diff --git a/go.mod b/go.mod index 2fc0db786e6..215bffcead9 100644 --- a/go.mod +++ b/go.mod @@ -1,8 +1,6 @@ module github.com/owncloud/ocis/v2 -go 1.24.0 - -toolchain go1.24.4 +go 1.24.6 require ( dario.cat/mergo v1.0.2 @@ -63,7 +61,7 @@ require ( github.com/onsi/ginkgo v1.16.5 github.com/onsi/ginkgo/v2 v2.26.0 github.com/onsi/gomega v1.38.2 - github.com/open-policy-agent/opa v1.6.0 + github.com/open-policy-agent/opa v1.10.0 github.com/orcaman/concurrent-map v1.0.0 github.com/owncloud/libre-graph-api-go v1.0.5-0.20250217093259-fa3804be6c27 github.com/owncloud/reva/v2 v2.0.0-20251017104024-82c22e954c1c @@ -75,9 +73,9 @@ require ( github.com/rs/cors v1.11.1 github.com/rs/zerolog v1.34.0 github.com/shamaton/msgpack/v2 v2.3.1 - github.com/sirupsen/logrus v1.9.3 + github.com/sirupsen/logrus v1.9.4-0.20230606125235-dd1b4c2e81af github.com/spf13/afero v1.15.0 - github.com/spf13/cobra v1.9.1 + github.com/spf13/cobra v1.10.1 github.com/stretchr/testify v1.11.1 github.com/test-go/testify v1.1.4 github.com/thejerf/suture/v4 v4.0.6 @@ -167,6 +165,7 @@ require ( github.com/cyphar/filepath-securejoin v0.2.5 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/deckarep/golang-set v1.8.0 // indirect + github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect github.com/desertbit/timer v1.0.1 // indirect github.com/dgraph-io/ristretto v0.2.0 // indirect github.com/dgryski/go-farm v0.0.0-20240924180020-3414d57e47da // indirect @@ -242,6 +241,14 @@ require ( github.com/klauspost/cpuid/v2 v2.2.11 // indirect github.com/kovidgoyal/go-parallel v1.0.1 // indirect github.com/leodido/go-urn v1.4.0 // indirect + github.com/lestrrat-go/blackmagic v1.0.4 // indirect + github.com/lestrrat-go/dsig v1.0.0 // indirect + github.com/lestrrat-go/dsig-secp256k1 v1.0.0 // indirect + github.com/lestrrat-go/httpcc v1.0.1 // indirect + github.com/lestrrat-go/httprc/v3 v3.0.1 // indirect + github.com/lestrrat-go/jwx/v3 v3.0.11 // indirect + github.com/lestrrat-go/option v1.0.1 // indirect + github.com/lestrrat-go/option/v2 v2.0.0 // indirect github.com/libregraph/oidc-go v1.1.0 // indirect github.com/longsleep/go-metrics v1.0.0 // indirect github.com/longsleep/rndm v1.2.0 // indirect @@ -292,6 +299,7 @@ require ( github.com/russellhaering/goxmldsig v1.5.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd // indirect + github.com/segmentio/asm v1.2.0 // indirect github.com/segmentio/kafka-go v0.4.49 // indirect github.com/segmentio/ksuid v1.0.4 // indirect github.com/sercand/kuberesolver/v5 v5.1.1 // indirect @@ -301,7 +309,7 @@ require ( github.com/shurcooL/vfsgen v0.0.0-20230704071429-0000e147ea92 // indirect github.com/skeema/knownhosts v1.3.0 // indirect github.com/spacewander/go-suffix-tree v0.0.0-20191010040751-0865e368c784 // indirect - github.com/spf13/pflag v1.0.6 // indirect + github.com/spf13/pflag v1.0.10 // indirect github.com/stretchr/objx v0.5.2 // indirect github.com/studio-b12/gowebdav v0.9.0 // indirect github.com/tchap/go-patricia/v2 v2.3.3 // indirect @@ -310,6 +318,7 @@ require ( github.com/tinylib/msgp v1.3.0 // indirect github.com/toorop/go-dkim v0.0.0-20201103131630-e1cd1a0a5208 // indirect github.com/trustelem/zxcvbn v1.0.1 // indirect + github.com/valyala/fastjson v1.6.4 // indirect github.com/vektah/gqlparser/v2 v2.5.30 // indirect github.com/wk8/go-ordered-map v1.0.0 // indirect github.com/xanzy/ssh-agent v0.3.3 // indirect @@ -323,7 +332,6 @@ require ( go.opencensus.io v0.24.0 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.37.0 // indirect go.opentelemetry.io/otel/metric v1.38.0 // indirect go.opentelemetry.io/proto/otlp v1.7.1 // indirect go.uber.org/automaxprocs v1.6.0 // indirect @@ -342,7 +350,7 @@ require ( gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - sigs.k8s.io/yaml v1.5.0 // indirect + sigs.k8s.io/yaml v1.6.0 // indirect ) replace github.com/studio-b12/gowebdav => github.com/kobergj/gowebdav v0.0.0-20250102091030-aa65266db202 diff --git a/go.sum b/go.sum index 0a6e5ab6097..08532d333ad 100644 --- a/go.sum +++ b/go.sum @@ -163,8 +163,8 @@ github.com/bombsimon/logrusr/v3 v3.1.0 h1:zORbLM943D+hDMGgyjMhSAz/iDz86ZV72qaak/ github.com/bombsimon/logrusr/v3 v3.1.0/go.mod h1:PksPPgSFEL2I52pla2glgCyyd2OqOHAnFF5E+g8Ixco= github.com/bufbuild/protocompile v0.14.1 h1:iA73zAf/fyljNjQKwYzUHD6AD4R8KMasmwa/FBatYVw= github.com/bufbuild/protocompile v0.14.1/go.mod h1:ppVdAIhbr2H8asPk6k4pY7t9zB1OU5DoEw9xY/FUi1c= -github.com/bytecodealliance/wasmtime-go/v3 v3.0.2 h1:3uZCA/BLTIu+DqCfguByNMJa2HVHpXvjfy0Dy7g6fuA= -github.com/bytecodealliance/wasmtime-go/v3 v3.0.2/go.mod h1:RnUjnIXxEJcL6BgCvNyzCCRzZcxCgsZCi+RNlvYor5Q= +github.com/bytecodealliance/wasmtime-go/v37 v37.0.0 h1:DPjdn2V3JhXHMoZ2ymRqGK+y1bDyr9wgpyYCvhjMky8= +github.com/bytecodealliance/wasmtime-go/v37 v37.0.0/go.mod h1:Pf1l2JCTUFMnOqDIwkjzx1qfVJ09xbaXETKgRVE4jZ0= github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM= @@ -212,11 +212,13 @@ github.com/davidbyttow/govips/v2 v2.16.0 h1:1nH/Rbx8qZP1hd+oYL9fYQjAnm1+KorX9s07 github.com/davidbyttow/govips/v2 v2.16.0/go.mod h1:clH5/IDVmG5eVyc23qYpyi7kmOT0B/1QNTKtci4RkyM= github.com/deckarep/golang-set v1.8.0 h1:sk9/l/KqpunDwP7pSjUg0keiOOLEnOBHzykLrsPppp4= github.com/deckarep/golang-set v1.8.0/go.mod h1:5nI87KwE7wgsBU1F4GKAw2Qod7p5kyS383rP6+o6qqo= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 h1:NMZiJj8QnKe1LgsbDayM4UoHwbvwDRwnI3hwNaAHRnc= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0/go.mod h1:ZXNYxsqcloTdSy/rNShjYzMhyjf0LaoftYK0p+A3h40= github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f/go.mod h1:xH/i4TFMt8koVQZ6WFms69WAsDWr2XsYL3Hkl7jkoLE= github.com/desertbit/timer v1.0.1 h1:yRpYNn5Vaaj6QXecdLMPMJsW81JLiI1eokUft5nBmeo= github.com/desertbit/timer v1.0.1/go.mod h1:htRrYeY5V/t4iu1xCJ5XsQvp4xve8QulXXctAzxqcwE= -github.com/dgraph-io/badger/v4 v4.7.0 h1:Q+J8HApYAY7UMpL8d9owqiB+odzEc0zn/aqOD9jhc6Y= -github.com/dgraph-io/badger/v4 v4.7.0/go.mod h1:He7TzG3YBy3j4f5baj5B7Zl2XyfNe5bl4Udl0aPemVA= +github.com/dgraph-io/badger/v4 v4.8.0 h1:JYph1ChBijCw8SLeybvPINizbDKWZ5n/GYbz2yhN/bs= +github.com/dgraph-io/badger/v4 v4.8.0/go.mod h1:U6on6e8k/RTbUWxqKR0MvugJuVmkxSNc79ap4917h4w= github.com/dgraph-io/ristretto v0.2.0 h1:XAfl+7cmoUDWW/2Lx8TGZQjjxIQ2Ley9DSf52dru4WE= github.com/dgraph-io/ristretto v0.2.0/go.mod h1:8uBHCU/PBV4Ag0CJrP47b9Ofby5dqWNh4FicAdoqFNU= github.com/dgraph-io/ristretto/v2 v2.2.0 h1:bkY3XzJcXoMuELV8F+vS8kzNgicwQFAaGINAEJdWGOM= @@ -605,6 +607,22 @@ github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= github.com/leonelquinteros/gotext v1.7.2 h1:bDPndU8nt+/kRo1m4l/1OXiiy2v7Z7dfPQ9+YP7G1Mc= github.com/leonelquinteros/gotext v1.7.2/go.mod h1:9/haCkm5P7Jay1sxKDGJ5WIg4zkz8oZKw4ekNpALob8= +github.com/lestrrat-go/blackmagic v1.0.4 h1:IwQibdnf8l2KoO+qC3uT4OaTWsW7tuRQXy9TRN9QanA= +github.com/lestrrat-go/blackmagic v1.0.4/go.mod h1:6AWFyKNNj0zEXQYfTMPfZrAXUWUfTIZ5ECEUEJaijtw= +github.com/lestrrat-go/dsig v1.0.0 h1:OE09s2r9Z81kxzJYRn07TFM9XA4akrUdoMwr0L8xj38= +github.com/lestrrat-go/dsig v1.0.0/go.mod h1:dEgoOYYEJvW6XGbLasr8TFcAxoWrKlbQvmJgCR0qkDo= +github.com/lestrrat-go/dsig-secp256k1 v1.0.0 h1:JpDe4Aybfl0soBvoVwjqDbp+9S1Y2OM7gcrVVMFPOzY= +github.com/lestrrat-go/dsig-secp256k1 v1.0.0/go.mod h1:CxUgAhssb8FToqbL8NjSPoGQlnO4w3LG1P0qPWQm/NU= +github.com/lestrrat-go/httpcc v1.0.1 h1:ydWCStUeJLkpYyjLDHihupbn2tYmZ7m22BGkcvZZrIE= +github.com/lestrrat-go/httpcc v1.0.1/go.mod h1:qiltp3Mt56+55GPVCbTdM9MlqhvzyuL6W/NMDA8vA5E= +github.com/lestrrat-go/httprc/v3 v3.0.1 h1:3n7Es68YYGZb2Jf+k//llA4FTZMl3yCwIjFIk4ubevI= +github.com/lestrrat-go/httprc/v3 v3.0.1/go.mod h1:2uAvmbXE4Xq8kAUjVrZOq1tZVYYYs5iP62Cmtru00xk= +github.com/lestrrat-go/jwx/v3 v3.0.11 h1:yEeUGNUuNjcez/Voxvr7XPTYNraSQTENJgtVTfwvG/w= +github.com/lestrrat-go/jwx/v3 v3.0.11/go.mod h1:XSOAh2SiXm0QgRe3DulLZLyt+wUuEdFo81zuKTLcvgQ= +github.com/lestrrat-go/option v1.0.1 h1:oAzP2fvZGQKWkvHa1/SAcFolBEca1oN+mQ7eooNBEYU= +github.com/lestrrat-go/option v1.0.1/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I= +github.com/lestrrat-go/option/v2 v2.0.0 h1:XxrcaJESE1fokHy3FpaQ/cXW8ZsIdWcdFzzLOcID3Ss= +github.com/lestrrat-go/option/v2 v2.0.0/go.mod h1:oSySsmzMoR0iRzCDCaUfsCzxQHUEuhOViQObyy7S6Vg= github.com/libregraph/idm v0.5.0 h1:tDMwKbAOZzdeDYMxVlY5PbSqRKO7dbAW9KT42A51WSk= github.com/libregraph/idm v0.5.0/go.mod h1:BGMwIQ/6orJSPVzJ1x6kgG2JyG9GY05YFmbsnaD80k0= github.com/libregraph/lico v0.66.0 h1:7T6fD1YF0Ep9n0g4KN6dvWHTlDC3awrQpgsP5GdYCF4= @@ -708,8 +726,8 @@ github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7J github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.38.2 h1:eZCjf2xjZAqe+LeWvKb5weQ+NcPwX84kqJ0cZNxok2A= github.com/onsi/gomega v1.38.2/go.mod h1:W2MJcYxRGV63b418Ai34Ud0hEdTVXq9NW9+Sx6uXf3k= -github.com/open-policy-agent/opa v1.6.0 h1:/S/cnNQJ2MUMNzizHPbisTWBHowmLkPrugY5jjkPlRQ= -github.com/open-policy-agent/opa v1.6.0/go.mod h1:zFmw4P+W62+CWGYRDDswfVYSCnPo6oYaktQnfIaRFC4= +github.com/open-policy-agent/opa v1.10.0 h1:CzWR/2OhZ5yHrqiyyB1Z37mqLMowifAiFSasjLxBBpk= +github.com/open-policy-agent/opa v1.10.0/go.mod h1:7uPI3iRpOalJ0BhK6s1JALWPU9HvaV1XeBSSMZnr/PM= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= @@ -810,6 +828,8 @@ github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd h1:CmH9+J6ZSsIjUK3dcGsnCnO41eRBOnY12zwkn5qVwgc= github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd/go.mod h1:hPqNNc0+uJM6H+SuU8sEs5K5IQeKccPqeSjfgcKGgPk= +github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys= +github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs= github.com/segmentio/kafka-go v0.4.49 h1:GJiNX1d/g+kG6ljyJEoi9++PUMdXGAxb7JGPiDCuNmk= github.com/segmentio/kafka-go v0.4.49/go.mod h1:Y1gn60kzLEEaW28YshXyk2+VCUKbJ3Qr6DrnT3i4+9E= github.com/segmentio/ksuid v1.0.4 h1:sBo2BdShXjmcugAMwjugoGUdUV0pcxY5mW4xKRn3v4c= @@ -832,18 +852,19 @@ github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPx github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= -github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/sirupsen/logrus v1.9.4-0.20230606125235-dd1b4c2e81af h1:Sp5TG9f7K39yfB+If0vjp97vuT74F72r8hfRpP8jLU0= +github.com/sirupsen/logrus v1.9.4-0.20230606125235-dd1b4c2e81af/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/skeema/knownhosts v1.3.0 h1:AM+y0rI04VksttfwjkSTNQorvGqmwATnvnAHpSgc0LY= github.com/skeema/knownhosts v1.3.0/go.mod h1:sPINvnADmT/qYH1kfv+ePMmOBTH6Tbl7b5LvTDjFK7M= github.com/spacewander/go-suffix-tree v0.0.0-20191010040751-0865e368c784 h1:0jjO3HdJfOn6gYHD/ZNZh0LLMxEAqkYX7xoDPQReEgs= github.com/spacewander/go-suffix-tree v0.0.0-20191010040751-0865e368c784/go.mod h1:ff/5myEGgtsAwf26goQCO905GrEm5ugEZSd6OWTsrhM= github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I= github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg= -github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo= -github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0= -github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= -github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/cobra v1.10.1 h1:lJeBwCfmrnXthfAupyUTzJ/J4Nc1RsHC/mSRU2dll/s= +github.com/spf13/cobra v1.10.1/go.mod h1:7SmJGaTHFVBY0jW4NXGluQoLvhqFQM+6XSKD+P4XaB0= +github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk= +github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= @@ -894,6 +915,8 @@ github.com/tus/tusd/v2 v2.8.0 h1:X2jGxQ05jAW4inDd2ogmOKqwnb4c/D0lw2yhgHayWyU= github.com/tus/tusd/v2 v2.8.0/go.mod h1:3/zEOVQQIwmJhvNam8phV4x/UQt68ZmZiTzeuJUNhVo= github.com/urfave/cli/v2 v2.27.7 h1:bH59vdhbjLv3LAvIu6gd0usJHgoTTPhCFib8qqOwXYU= github.com/urfave/cli/v2 v2.27.7/go.mod h1:CyNAG/xg+iAOg0N4MPGZqVmv2rCoP267496AOXUZjA4= +github.com/valyala/fastjson v1.6.4 h1:uAUNq9Z6ymTgGhcm0UynUAB6tlbakBrz6CQFax3BXVQ= +github.com/valyala/fastjson v1.6.4/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY= github.com/vektah/gqlparser/v2 v2.5.30 h1:EqLwGAFLIzt1wpx1IPpY67DwUujF1OfzgEyDsLrN6kE= github.com/vektah/gqlparser/v2 v2.5.30/go.mod h1:D1/VCZtV3LPnQrcPBeR/q5jkSQIPti0uYCP/RI0gIeo= github.com/wk8/go-ordered-map v1.0.0 h1:BV7z+2PaK8LTSd/mWgY12HyMAo5CEgkHqbkVq2thqr8= @@ -955,8 +978,8 @@ go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 h1:GqRJVj7UmLjCVyVJ3ZF go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0/go.mod h1:ri3aaHSmCTVYu2AWv44YMauwAQc0aqI9gHKIcSbI1pU= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0 h1:lwI4Dc5leUqENgGuQImwLo4WnuXFPetmPpkLi2IrX54= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0/go.mod h1:Kz/oCE7z5wuyhPxsXDuaPteSWqjSBD5YaSdbxZYGbGk= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.37.0 h1:bDMKF3RUSxshZ5OjOTi8rsHGaPKsAt76FaqgvIUySLc= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.37.0/go.mod h1:dDT67G/IkA46Mr2l9Uj7HsQVwsjASyV9SjGofsiUZDA= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 h1:aTL7F04bJHUlztTsNGJ2l+6he8c+y/b//eR0jjjemT4= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0/go.mod h1:kldtb7jDTeol0l3ewcmd8SDvx3EmIE7lyvqbasU3QC4= go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E= @@ -1407,7 +1430,7 @@ honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9 rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= -sigs.k8s.io/yaml v1.5.0 h1:M10b2U7aEUY6hRtU870n2VTPgR5RZiL/I6Lcc2F4NUQ= -sigs.k8s.io/yaml v1.5.0/go.mod h1:wZs27Rbxoai4C0f8/9urLZtZtF3avA3gKvGyPdDqTO4= +sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs= +sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4= stash.kopano.io/kgol/rndm v1.1.2 h1:vriNehb5NuglfGqZPkgeFr2Y5AjXtQCF4vEl4kqc6nc= stash.kopano.io/kgol/rndm v1.1.2/go.mod h1:CBvpAHlOwyu/XipxfLGk02UN3K3P6hQ8E2JoTbNWfJU= diff --git a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/LICENSE b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/LICENSE new file mode 100644 index 00000000000..fdf6d88225e --- /dev/null +++ b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/LICENSE @@ -0,0 +1,17 @@ +ISC License + +Copyright (c) 2013-2017 The btcsuite developers +Copyright (c) 2015-2024 The Decred developers +Copyright (c) 2017 The Lightning Network Developers + +Permission to use, copy, modify, and distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/README.md b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/README.md new file mode 100644 index 00000000000..b84bcdb77df --- /dev/null +++ b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/README.md @@ -0,0 +1,72 @@ +secp256k1 +========= + +[![Build Status](https://github.com/decred/dcrd/workflows/Build%20and%20Test/badge.svg)](https://github.com/decred/dcrd/actions) +[![ISC License](https://img.shields.io/badge/license-ISC-blue.svg)](http://copyfree.org) +[![Doc](https://img.shields.io/badge/doc-reference-blue.svg)](https://pkg.go.dev/github.com/decred/dcrd/dcrec/secp256k1/v4) + +Package secp256k1 implements optimized secp256k1 elliptic curve operations. + +This package provides an optimized pure Go implementation of elliptic curve +cryptography operations over the secp256k1 curve as well as data structures and +functions for working with public and private secp256k1 keys. See +https://www.secg.org/sec2-v2.pdf for details on the standard. + +In addition, sub packages are provided to produce, verify, parse, and serialize +ECDSA signatures and EC-Schnorr-DCRv0 (a custom Schnorr-based signature scheme +specific to Decred) signatures. See the README.md files in the relevant sub +packages for more details about those aspects. + +An overview of the features provided by this package are as follows: + +- Private key generation, serialization, and parsing +- Public key generation, serialization and parsing per ANSI X9.62-1998 + - Parses uncompressed, compressed, and hybrid public keys + - Serializes uncompressed and compressed public keys +- Specialized types for performing optimized and constant time field operations + - `FieldVal` type for working modulo the secp256k1 field prime + - `ModNScalar` type for working modulo the secp256k1 group order +- Elliptic curve operations in Jacobian projective coordinates + - Point addition + - Point doubling + - Scalar multiplication with an arbitrary point + - Scalar multiplication with the base point (group generator) +- Point decompression from a given x coordinate +- Nonce generation via RFC6979 with support for extra data and version + information that can be used to prevent nonce reuse between signing algorithms + +It also provides an implementation of the Go standard library `crypto/elliptic` +`Curve` interface via the `S256` function so that it may be used with other +packages in the standard library such as `crypto/tls`, `crypto/x509`, and +`crypto/ecdsa`. However, in the case of ECDSA, it is highly recommended to use +the `ecdsa` sub package of this package instead since it is optimized +specifically for secp256k1 and is significantly faster as a result. + +Although this package was primarily written for dcrd, it has intentionally been +designed so it can be used as a standalone package for any projects needing to +use optimized secp256k1 elliptic curve cryptography. + +Finally, a comprehensive suite of tests is provided to provide a high level of +quality assurance. + +## secp256k1 use in Decred + +At the time of this writing, the primary public key cryptography in widespread +use on the Decred network used to secure coins is based on elliptic curves +defined by the secp256k1 domain parameters. + +## Installation and Updating + +This package is part of the `github.com/decred/dcrd/dcrec/secp256k1/v4` module. +Use the standard go tooling for working with modules to incorporate it. + +## Examples + +* [Encryption](https://pkg.go.dev/github.com/decred/dcrd/dcrec/secp256k1/v4#example-package-EncryptDecryptMessage) + Demonstrates encrypting and decrypting a message using a shared key derived + through ECDHE. + +## License + +Package secp256k1 is licensed under the [copyfree](http://copyfree.org) ISC +License. diff --git a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/compressedbytepoints.go b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/compressedbytepoints.go new file mode 100644 index 00000000000..bb0b41fda18 --- /dev/null +++ b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/compressedbytepoints.go @@ -0,0 +1,18 @@ +// Copyright (c) 2015 The btcsuite developers +// Copyright (c) 2015-2022 The Decred developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package secp256k1 + +// Auto-generated file (see genprecomps.go) +// DO NOT EDIT + +var compressedBytePoints = "eJyk2wNCIAgAAMBs27Zt27a52bZt27Zt27Ztu+4RN/8YgP8pmqLC650yqn+RN9o5WamIzkLa9Agq2bEoRaoJ/oRJplKgCMS4iEExiT3u5gnfu//K8yz4XhSnQzTXYdtp6i45sAprIIyKo/AhtXelFMQPtnAcGf58V/JbVveLAN8Vcf0Q+bnIk0kWveCiUp9zy1Ko9e0uaYkPT0UfsCTgaZhyQTuNksSeqX9vTrQ5GH/G8fWiUIiM8Zvl31woXxiquMqOQMJCoQiZ/iXuDOqY7tTyHlv85rmSanWdJIe0JD1VkaEwqclvlvbtOy07cCk4KT/jXWxBk6kb7TMLkeWtCZli02fkxlspmDtHfMonSi0ScKI+ypNPlZVHgO1W4GkR4AkSbYSxX5oGlIctKHhCjRY9eR0GsIluyh4QFg9t4FU0TdkfLf4BSXR4MMmKV/aDCqtzxLvXaFGs0GVb7zLqgb0kn7nDXfGhpaDHAVIodPh3ummk9NZItmfr8juoNyszjGfELYp+OX5UK0lt7hcNU4NjciFV5Wd7rF4mtLxEEuUAmyUdQwDHGfahHiT9dk4+r7K6EPYYBbBaAQeWYegqF0z5jh/FwuFiOMV3oh7nteiCQCzGOJqamLDUBuox6qN4ZOLY4x+vIdtftTZM3+hI/xBsP5Zv0Yo1QQ8jcIP70VItBoA5MhNnb/AxAJzAPDvNTmrNgIqr66MA4MupfWmXLUa0gZu6/vA5lc2V6cKJC0xIayi9bT8kBWbiIVj/9oh5qCV/g53tVrxQ6XfhqsPWYFps2OYNc4vTaFEdPWT7BVQ8mWoNfwWqBHRV5KIyHgt1Mavq2Z7ogUtQRuRyipzfdg8hKVRf1r94lYx6hjntvVTgLiRvOtETLWBq/baEcWugzzIzxpLreLZWuSpPIj+yd7xLqrhNUu6uWQIESsLW8mIPQPS9tpxRI70BAQEYTY+gGvz8N5xgw3s1lCLjdaQA5ncTo18lEO1pjX0HkiKXSwBpVohq/1PSTUKwMXmdemLJmH0VfWx+xu+rIySuZYabbIJZRmoP7hx4qrjNR7ZLln4Fa96EAuW9C2RGaEjJXQ9XFGPJDi3O6PpdBHFKaPg0HXSqNaSf5HVB/npt+uEgjJWHh/bMHlB+Cq37JsrxklflGImfRY0WYdtecfotfzSaGGJXYGPdY6+Uk5OmyIgHXhgmAvG8kLXWetUZMxo5SuRCpdfdoNQ68uHArCZBkTJ2PTWfBs9MFazROg8x1CQdlvnwm3GSYWGuoJ6WsgBgGHZAxDltrlZDiYEpBMu2yV+sJ/M4cX1Vid9DJbwSWuMXdX22YqljiMvUf8gp5OUDO8mz8uD4izxRrDBa0k3sEsOdiPjVk/tGcJ9d47fkgYdy3jBfKSNrrG1Bvdn37xeqdSxFcEYdoggg3n8iy8Wo4FsHQJwB3QnexMLFrXO/4o5JCTJYUZFGBlT9yeU5rCdnGvJZeE68PVJVTlVxezDz3hnIMuy+EiH0QoasAI2GGlHvlsfDLcad8O7RfbwYd6nlG5phUmqOOQ6xgKFG309xCsbKvDumzmZ8WpVWGCvxYKExEGktwqkKfedH9PbOqcLSpzIDmoCD+/IQv2ZSKB3WzF+bZzAoxImoNSJPDDeCNkpeTbu58L3n8UQ6S3SHPhRoT9QneplWmOAhQoLTGNmzIqMZUflkPDNZJ1PUr7qnLP3OiPWWKfVm9HIXv7X2zdP0oFP5yC5cGCKG83zVSeBqd14przJKjmTOJTEFIJcZZt6LLnSPjxZkSMge3GLpx7KkCao7yMOxdxm7gKn4l5w4vrz1D/MuTgXvedy45y4n3YzmeUNNV12X5hUuCnC/RbBIfxXrE1JJffx1VpHc2Z88roux91yJK3zm9FHPcxWFL2eElsDqvYgoYlrrxIDCF8w0L9xVCJ/K1wBYV6z0Il1liZFnrh7oC7QnCoi/AZVC5wzuseezcZmsO1PXijTQ0Bz2N8iU9xr6H+hAMrmj5/kfZNGZwfRbQEYgFxnYiZ/RcnKxv6L/Ug2cGHP9l0pkpT1bcb6HfTZLVoy+UXd2qckfNk5rcKMh1Rl49vNssVRf7Hd8AfivO3ESlJUSz4MFkdDmiOzmO3GCXh864/drgFmZq6f1XiZsaz4r6NbjOTOQdQJf21TOmp1+bfXxGWCL5M810GZBhc6YLVGxcWFHwEhf/d8HuDXUa+i2WUcclqdokltn6q1nu2eLoI3aiyuYvyr08xBNo8h6o3/yX9fAyxP9Mmwwudd0GpruWyd+6Th6G7vUmuZ4LHgO1XTEVeMhK5PHoDx4J0JDDEVGv2kJdA/3hHRZXcjF/n6qveOFmgDS/K9c7qgLFfacIAS+VHxEk+Xm3UKLvhMgQXSU+GVKjei1uFONV4Ye67v33x7hbEEbT78HMWliBfVkEqbEOLiGV/81jLALoxKPMEAZaKMp2vBrwAHmcYqvhnZC1UE6Cr/JZW6k+69Bgxp+sGI3BfNvp5h/8spmJqg4myTAcqzYaW8Ami61S7cR5I5iErsXlk1oVtuqnyJi7rpaa89xob7p9udfTmT/ikUfL49GLZpxgYnjt7W/so79IqGHzZIGIIARcU7ktlYCMyhTUsBzf3Bt1fI3TPdf9q89J0+v8+lSdcIjcojNA6OKoSVmZl1IDJQ1FFUSB5nuRRnBQad6DQS/gHAZxefrebtPJA3qGzu4EsFsPJXaPKGq5gQaz1ERF1dpdRQmIeMWxLcyKaPK31zIUjilx0vGc0CupUPlgfzlAnni2l49rX6nxM8NF71OfhDKFLBIggWSfbBKORmOU1ZvFZIkfWIpDwOKy78HNLKSp/FNA7paMy9pcCxu0OvI9kcWld/GnM57qRnliEKgPUeQ9/Prs6koi6i8QAOov/xlN1Me38NfUgZIe5LJqw2p4hvWm0D7YuqCoZdYCnRVvwVDT/xcUc++4D7NeXYhKC1Ffqm8Jy7NWQE3v6koJY2q+T3yGH7+2c4V5HLboKAmLx7LSvsCRDjEhoUARsfKpiOSAxmJAf2Evbi5Z/+Ep1UFmFxGIrCPagCv/jUfTrQ+tB3CCp7L8Av2vR9x+42mKoeCso2te6hJ8+VZ3cq9beFbpyZUb/fOOwBjlS3NpWlKwU97IdO8Ey8Cr3w0TE9YOTY8Mu3LpY7j7PPBQtP/lrd9WaPQ7dJuSMp+mS/k8i4fIuuDBwMIzVouGhrn9t+nvTuXacu4D60+FYx+4+E27N0Q+QQY3rrMISc3dovqzKig1eMkIDQ8d5/Fwo7WflX2uHsYn16sKtRiQyMIagTwBBeTPEsm5U2YYkfBomnnO2pW3R9IdO2QghSgaQX50RveltU68Mck0D08wkYGWLA9TrrPfi7gzxJAyiup8DZsUrLsipVuEL47gpqdNtsaG7GV3ShLcCPfEKQEKzGRVs98mluYbdgEUagANpVz9XOstElchJ43RRkpMsmXYeoSzZatjSTDwGm6vHVgHrUrCk6dzTrrH2QZehW2xpjcc+JA4qp5zvuGSYgvC32BceJXaHvQMhwHs/5DXsxeioT3l4awYPOiJOVDihOyPZYb2iAWOUREfP3Seb2+3qyytoILxhIPf+0OYjWCTg8rb3mV3iAVpk5+PpwxDdwXI5GJ4Rz5BbmrY1ze7wcbSJvhEzIWONaUROb4ZEvIHHbMVBqyw0ITDtsv1S6dzgmZxZgRcrWSks18w49DFkEqrysIGd5HJcM5jpNWJvXax5ki9ggd6DDzzLWI6zBqgFht/NoOMiNfj8rkz61v0a8ynunoGYT2YB75l8dz80Vz+NvTEpN38PUdnv8dw12YmVQDvlXDXrrc7kdH5tigy4yLb/X8OIGY98t4PchBPxvtl/lZ7tCzOqU1fIFs5XqG0Xd5PpslyRkcpY0e81mcmxLPPE1dXm/j3t5BQpLKlKku137Y/Ln8HmU36BlrBS0Pr3Q36f5B+S8A48pP/Tb7BNB51Y8UI7Ub1vs6CueReJtn/crGW78BnfUiaJClNdGhaHdyveuLOsMjuUxQs8AUNi/miOuH1LE4s+v0UG8A4sXVdldX+FRkRgmcg5vk6xKFlGvIC1YIybgNrUgwUdE2P8iesBha81++nZ7KnL3l8E0ngcicmo3KpRbm+Wutc1c0NQhEnnjo0uiZ4xuVEFomiMtwkdD7ZlpBf/c5Awbf7wwUb4CxF+ha/zpWs/kLZIPRTaA2PHSQlGH+jSjRovkiI/Tn9Ba2mPNsW8v94k7CcHcrg6FtxVHjhd7Y6zPjOvYqeSstSHVAB9b7mLV4Q+TU1HM/g4eCcgHxQ+XIjelvMEVb4Bgp6VnQojLgPDC90zpna3WQMjvfaSoARO3vM1QioFr04Z+lg/UUre7tL3t6QYh3hPDuVC0p+y8DsZVAXs40fPjGFEUl2S4UuO5Q7+opHhQ1whzh6HySiEdJDcc/TMuk1oOVBLhEvgpzCJIngjYZ0Q8R/a5nBTNZdiEJwBlx7zjyI/BK36wsYgUW/NxePqrXlxQzmeY+o9uBGDJ4Au+WQePJ4SI/N43qkCHvnbHcCx0VTpsF/KP+ShrvwUvPlYho36mo/LA7HoywPU5iePgWgXCmA7QS9B+D+CwarAEkUtsJveNSkl5/aBqTQ7kWqA7ZP4DSR5WRPSsBSVrIH2EK1pPpQsgBCXs3o9KJROeFtFDeEEL/Yigqd5VvaQhL407jWgpFgNFlmaKcq2PTXWlpgyUwmPyUNmVHmza8saL+x7X4wxx5nBsM2UTqfafXxuR87Jv8+i1zpuNu4juOCM+QdGW9M7K7WnjUhtxq8I4p4xWzjT+/TGdcDfLZk4I45tl78NBJtR/H8mKcCaZ18eEcXf+J/nYUup7oMZu5+ed8KR48m7omvLKoDLOdVTkM+/6U5FcHDPGddnvoo6Fx9WCGkGYUPVE0y+qbFHOhIGEKpXSaJE/I2qLSYdKfIeJl0RzyqiGSVAiPE+3NWaBAGP39rkU6qmT0JixxcnRlbDrJx9ilvQNtiEZosu+M1K/8BXdvn9h3mIkrkPpKCEAPokV6J3ow1edX/3jttNgVdrLAdg9G7XkWZ1DrHb5smS2vgC5Tl4ez6YPKwROTT2y81Fo8ckE9gzWDkdLGFGM7ZTgvavoDCouXzQpgwx1wGEhYYegGbe89daiHrMIdyM1/BTu8xewC6uvpxt0NlJtgSwhZTh4/DPJKB5CD5wGrRFU9QdZpvRrh2zKhTrICkjaO60UKkjjw5S74vEMr9kYOcO9Xsugd8NXr3lToFFQPUda6LnnApS5MmCRth3sg+1/r96dEKGj6rAA+nDoQzJkZ4lnG7GWoZHyfdA+gV2Up7lpx74NOvChoWRCFwa1Ti4FfQfOCZUeiJwrdSekkNUgzkDcGXNciiAGpJaihg5PMtWVc+JL44g6fcH3wn/0hjiK0+XgkS4YXGusXaWowk1S5Mb88s1ZVfIHrVGrhKjIwXqrbjGlRsofTTW3L/1YMAfduSgZsTfE7x1pqDKJS5/QAL6/R8wkDP6znlJTOjJ3Q7mKRJSb7NxO5lqAum565vFUAEjG/F6ag+JXcliFEAtjB50aaVJq9Xdmr/41U1W3ohT37SFS+tO2QhxwCxYKLfZRZ5DTejhYjGjv9nJ+MPVs+reOkdiDN9B/umM3Dra5BYIR3e3Ma+sh7s7A3Vx8bChA637iqIcQHBRB/KC2jhIOJ6TloMJKwq7kb0E9XF9mJKmCg3hmo5d4RJzHqbNcjzYx7Yk5pW9u2bnVVTfNizvlXChMV4Jf5oYhhhryI6ltlUEoy0dcnVrxqGCr3oxeTTUf5UBKirSe1/gYybkHmnwPlavGS7xGvudqLruLswtEhy+WLGktsyMnJ8W9COKhKX+yT/JsbS4agPalAWAgq0Go9WOP3RF1RuzHL1/Twfhb1NYiWnyHTV97NVRg59dnhMnGmBgXkg61GiZUapX50LNQZxzNuqugyEHjxA5KJfat5xMGdWLkGemJFwfcuskXJeWXikIhyV4hgdXzZRgUxRslgMfjuxQLvmkV0Mo5xvsDp3TMwkg1PqkGEkXlV7AWFN3s01uhJ6yDjC2Uk+o6z0pfnoqwyJnVgeA3WjXxaVtR7egPbF8hfxxAfwKF0smjTHmboF0kgivS8DFJLv75/Ucq8fbYoMgadUoqnmcGJcHbqo0es+Dhi9Xl7vCUVADTnhnuyVi1432m6bM6IF6ay6xJCRKjLVmAyEooegmNImVU5uh5FGxvOAAyQ706a+NJGgUoH7knQYOL8ZyXPTJSWiqNEpr26wUb1hbclv6Q2iY+PTf2KneMpMOoIfJjCN562NYCeMp+soVRGxbyic3Kw5CfLkEZdmVFpFlp/gH3QYYfvp+catQcIPNavc4lWGp4i1Acl01RNbxphG4D/KBQ3D1souHPwVFKgaiC/gateFzhTrPRF19IEVRm4h1rGFjVw/0h0O8psDwOIUQVE6yWSmoOaMX56IjcaA3jEE/TStAQxNE3H5qejiTpfdUTzQdTRY2T0u2OiDdBC+f2dMXvjCGFtQItlBJQTQB+5X1HSQO3L/UBu2N2IH1WfCIaagjNUmrY+DpLuPswrx3pnRiwB+IZ/JH4x1YV5Frju6HvMEaEbV1VMA5+tyOcIbe18oGEX+GHKGb55evhOtLwWOEnIgwWtNtEu2k6sjlmeiYYIZe94CyD85JcA8jNtrGoOwPIzuOXQDjq2FyAZB4Y5oHWAFNbhuA7DjS3b/0r9FnVkB4st7jizbrNtR1TYyoGS7+lR4A7b7ya/FmVLMgKfAbohRbBjWWpfltG3mUVMQRTTI/F+Gsw0zwd0Y+OeqznaCusBQw2Lc8QWFJAylqaDK8ZRwDapfYycfqT1j2SxjIEL8FScDvLoaovVia3yBwMh2po02KhuyvIc1A3KVHZPpgD8RYU4+EhZCPky3ziajZKg3rOGHuBzw1A6g9gXNpN0pbWWS/gEyhMSGxg4AofPhtBYp1z5l/jmMREAJ0qnNpj3vXsXXaAKjNDjJel7acD0GUPaHRhsKq28WwZ/UuD+ILPjHDtblSZDMWR2a+tNY6kQm47emyolszCZo2fsc25fjpIzGXs0cetux4Dqzv03nH6XMdZwhuPqcrOixrdEEkqRPadaaRgfJymbY1HncC6myfR3zrPkEA3PLdw1x3ljW9+iZ1sPUeatW0c/nNggFNkllR4SxeOrOqgg18rwG8dPbaeun3WPVrvoIgd7oO/fUQJKSujMTWHZa8opUxebo6CahujaYmcGMC9h1ndg7r3k11sdoudFbd/0Ywwispr0E8h8XOUD2mVPlPesHFkAvglILLJ4WXRjSSnNcOdhwVilZTFgIlnDdimNm0JVz8Iz3WoP0LCp0+1sIDtpcuFVFUX6xd94DWvwsU0GstZp/Bd6TxbxfLluEDEZiy3YUJOsXSGBH8bcTJ1aZyu1woCqm4f4ogQG/otHbC0UKoYwwxNemdnuEdPF9Z0JMYKKo08Z53vle3XWrbODlTX+i9FAN5t6qe5RRgWuI6I68LMMB2ZBWGCwu8i2DinS1I9L4KgG0j0u7nA0vqcuJS/WCcLKXrgG20fgdRQWgYrhA0KHO5dqfeyNvSeU4h0pU754wmk58W07CK8z5cg/zzXGMuD8W+4PJtt+49U180vl5GWVWaUQZJ+MOOITDDV9UuA4tJ83c9vlnUzNeroPXVrPkt7kOA57ZNe2AkyfX4AR+q8paq/U8PwhABf1pXN79ERqG289WZdsb9waoaMeiyNYpvlwdD6gjoUZgOO3DdHKlYHSCeG87Wg9f0EMUkCS85KP9YETYylYArRn2Cy4CusH20VtLfLkP88l3VxQXV/PkPu0iwC3bFscgTVpUONTRqRoMCM2yI7MuLC9YPQTZsbFI4lMkpYCPKXaCra5lirPqucwJs1GqoCydQc+/2JuzNW3ZtuRYudz6zh1i3d9+alM6DMbSG08ao8AZwLW/KHbKBv5egSSHqsYB45H+aWJ96wANB3XanS5FvmKYQmO/mpndEk/N7geQJ6Eagc102vAM4FeOJRnmSoS58qGiPhsU5iDV4DwWJhZvFGSIslchcwjhuwOkvFRqlUfM8aQo3LWSXaXOS8oyPS86HHDIQtfeRAENPZ3OwnjkLG65FuhlIkOaCG4R3oThoPTsfTknjxf5z1JBhRBRCum8JRTWqHEYyOMHsnjicS/DH9zRCkEHdzRfkLOZoitOdpZsNaAYEprChcMLrLDZooVOj0vBgN2kEU4o569PY1x02SsaBWTffTVZvVnOc1j90s6YN5C754ZTMM04+J2B9V7j3BfM9YxQ+SSEcSO/QheRAjs1Fha1KUPNXg8lFuUJlOIQnWxvrupG1DPukFu0EYJLCUAhnBAL5/tXKdLHTKyRbm1BaDJSdDLcPSOngECoQH0C7UAOju6rz02WfgME7XNGRhmVdPLjfkdKle8Iw0cVwA7Zp2b5Qo4N99oOs61z6Y4GQy08B6xmWmlNccFSceTbSsTO+d6OfrK7pp/iqX4DE/RSSLhU/tvBcNlrUJXrr4tRK2L6hB8qn/JXI/jBPaO3TNKmVx4g4M4u27svPZfb/XozPSwBbi3qgsU3Q5+E1eZ3rKKolbViC+/LrGjZy1mm+Kvt7Ht9bd90kJ95+HJB2DhKY8jpzvUmXaCE8I6tnBvvao24ClQhwtFoKfsdVT1p80/vVBVyUNAb1sRPpTjjgvUr10ktSB1o0Kn7324E32nKDNkULKlBTRdNNAaAYDnQP/Eo7qukPuOjyR8oRJ2HU3f8ZvHTFXy9FYM+gxZj+wSDYkEch2ckTifXLHwDQaNSrIsGYKzaeJ2jAWsDHy1nStpusbz/O2FH46bUG94YJTVc9Wi7NkKNwt/PbmUJEds2/mP6wp3Z3sMRodI9NG7LZElsya61htUDAq8ucyuzD18z7n0wyJqKxSHJPOpvR9eAoSGrZJrhs9X0LKDrW/AuHAZ/cXQ1no/qjPeoZSJR33jTb8+4dUW8VX2Q7kBpO9ZrTTiYg3LXBPmKOGG6ODoKIeJ70obE3SBEB4AXJLHZ/4pmCvCAgABV+JB5v8dgAz+tjn/HSzi6oBGOCxqYVz7lg2JDM8d2LOQO7Z43ITYVfauEvbDjLM60S8t51edi33fD7bXGFKV/NmYy8yQTzsRnqx4vDblg4KV+/jxFSUE0x0M3RkOTy2FaedY7h1TIL/vViyJ2NO6eI92dcWLq3HQGio2RPh0MkEXRb2xtN7WkqE/MmGSlceDK5OEn5SnD11iI5y/VYbJfJj0jAIR6d4E5/oDAKKwJeufLHmIZZSKLSZ2VfCeHAEC5sktoU2na+vC1aAePQ9NeoQRegyDxHc60XsoW6iFXMkPu0FZ9Qfv3ZdKFHYHXn0G5pmYERvVgbctB4r7GJ6o4+eJxZDm+GkiC4Jw8wbZ5htmKiMAfhnWwGd9v/ihBblCIVp1nuFcnVQjJB915PyxvUE9wZC15lFUxk0Epa7YjhGUtVtjBdPIC4x3nIZJ8icVEUAAgwa7gBJ7alchWR04DXnJCyTVfaJWBNJz6q5oHv7qUMHd9VyfMdj6NTum63Nir/p7n3uLoJ0PwPwYbS83a1KNzAvyhdV9ypHLxGeDbP9LpOnmtUkC/TWOtdFKaZRR2dypMKeGE+0GZg/e5tjPvt6bhQeLl6KdYNIKCmMLx0rUp//YkkiGpJJtEPPNcLX6u7G2JYRRQPSzba9Xp+0S87BFdtHqHCvdxvkTvbOpg9xh5xQ4kBgwoXBCPlGlWplP0H+UQwB5D8lKIciWtdmVZLszP447LqeIrCKf/IoCUZei9vdI+bTHi1PthbG7xIDKO6+YJryCS0xA/4chsPnxVBRwjIJINQ9nuO41273xGQKmDdFEBs6vAVobitbvn1ZH23uZMESZX96o9XDuamK6Kf/KgpQfcj6tBtSX5QEV1CZkrzojQUO/+PHA6gUv2ZjqMOxyDZevUuOjUTo1gtGsY+w+kJvIUYSNg9w6lCqVcKA6tA1fNhvXf438haETgbYt4y07KqSsVXc8tKr3VTMQPJ1JLGuoa48AQJhRdy+BvR3rOvBSV++ZTsCkgDwb80VpzJAOSbqkCj5hu7EHLmfbvkbHZ4VSVluMY+LHxGZyowi3vqaabEBNDdXD3cGPO1m6mbdm0vxmwQhCgyHCcT1FaL//4wxyROIcOKe3YCpknT2YjYtcaX68pc+RC/MyEkAJoBr7uGkVxGJ3ZDGgecqQ2cjIqnH1ZUV0U5cEVx2L5jaTxw04k5xI0Ber8m+rJ7saZuPN+ygx6lHrMJenixAQmg/7N2VQuqmpHDxAMve+Anxp9hosyVm768h0LjWSUpdT29yGfMyfHKKWFjn4beQvUPYntPtGNp8G1nIJbzL8Fdp01C9GrnZjWCJZvK1sZB70onSsrWY585T8zSSyn6N6betbDnr88jIz0ssSwQ1UDROSfzqf1sV8+aKNFiMHkupDbFGZ7FZ1ndTgCHNaFIlU6Dwy8ZJO6J+QFNE5U+KfJfWA944DwusC/BEpsdDWiiFk0ECYn6t54z/BVFEeSrRsq4TAXYTfnXV6yA5URbVIzbIVyIAzZELWFWSTd57L3290vRBSCJSjkji0hpFHM3sCNZPpIrN6oK3YFycolTa4TCJrc801u+kuTZTVKS2Y/XmXvECwCMWnWsDhJwOahZi5cmlV5EcIpGq92gtZk+w8cmFm2I8RGs16IO63GvzA/RBiucWo5n9aBlcnZ2uKaIzEcrD7fMFvxQ00PGRkOCxASoZZxphcSWPfHFBgS9TEb2lNWwmxq6UQoIztgE30WGcJdoN04rJLKowps50xNxzhXkne/rIf7U5NAyy7ZSME/CH3/RvchIFNPQKqv0cxEPB8lDpN/NO1p0cjjqvqEa7xaZakbe50pY00WW6kK43s8cXUp3zYpFirE/K7944O11A1RbitQ+c9TCD8UUfB31YWkpgrelvnK/DhlQEfouj3IM8ouVMaC1DivFeY4XBJk7bVzOYwacQbil2pS2w+ij09l94qjEHXN6VpKFnOEao1GFXR76vaUak+CvKG3I2XjlkQPnwU1rs/y+6bIAUCQ27Ek6wcg5y1l55ay17DnSXh7FvItOONpLqpY5Sezkd+NaKM8tK8MaBqb/mmfCbkKtOLLoFs4x5Ndnjqomiz0iWzc7HMxdH7hZVWYyo/UXAovQOKSUtzk8GFe+HTMsI4mWgC190MpH8CEEXG0GI1MfREdtr+BaHQeR+Xv38xiiTFOUOyQLIiQ16eEGnISsTegDKImVYs0BtwslhG/taCz0lr3rTm/FAB6u0aw/e0gKi/RySn65kjWqtcqRzQT5LyKEdWGJI6Z7+OpOS9hUWruXezmdJbmVLng8yol9gTsm+cfK9PaCWQIFue3fB+NZn7cCkyWqUvTaJuyTc2ESuyn8rXB6k2RhDiDTZ3Q8YOnjuzTwOcThJYthMT+yS/9atI8q0QiJWu5Y3e4BhkZu/nOmri519zbCWxBbt0U2oHW+oMAmhowXCKbOt/tdM3Y1tgUUCflonBKpHvU6U3ZCdq7SwJ7jDPufsvbJPOTcGiLpTCjA7Ou4g0G1NtYus3jjworABGLURfulDRHiVblBdEaB4dX6N8+CmTZ/NhT79735JRrAzlBaHsxRQYIX2hCe51OqzlsNpBjPaDi/gL8le4JHoAdUS1XNNkmoMsNnYYrBquQebob3HpYiChA7uTe6SCWTyi9aLN1x28YiEAT7JZj7UU21eXn0IlvDbhy+0gh3tGGKOWvnOweVdwaxlBshDG8NAyvaQ6MSAZgjLoDaenXpyKC5quYWpJxKByw5Sb5cycLfU+wf5cHiF1dlDiFwt42l+k7G7zuxVOhHGNW87pg4j68HXzg+e4LUwKStit7LA0odvycHWXSW402BVqAsK5TW46hg2A2jT3kjzp6icPZP1xjUUmPxqAusg16PSiJTA56zccK8b1xHdvpj+pO6rvPsHjiT2lUD8DucY3fdiPxgotEjcBwVTeLDWKzp1K8s7m1hHVKtnrRqcRlgzy91296MNte85PlYV1iiFiATvAJsh7qLhI6DsnqBhsQJgmbdOHtgrBnpcRHXg2tgVxbKV7LE+ybuJB84LDlnZhQ+ZtbbAZlgU1VWjtG3HwrSrADO8v6JyE8EPdbMWYBfRQppTmmEXbGhbtx/h3UAWaTvtOjbazFqWbvk8qY1zmD6c/NeFCDeHxslrGlKc0SfvXUA7yHlUqVZ8x14WmG6NXiQLNfi/Wom23SGMkv92EQ8uG/bieilLbrEq6U3m2N9q3hyb+EBrfLmAfPHGK/2QbYa1R7tRuFn4XlI7Xz9PuO2TidNgpe2vfqEoP5T2XDsKg+XuQO+Gm4g4VX4sSFUzpduyVFWShH6AH3MvW7Gg+6EkZoMkr3zzuXLHw860t0RU7AaRdG/eoyrWgNkOmxvTANm9ClEx6BrHCfWvDnSkwB7euqrpJV8fLIaBSlCznaszkqy4244x7Yb9ysS/o9L6DEHRZVWfj737HblwDYCV8qzH5gU/kXI3i9+HnmmdcHPpHnb/fR3mF/be1ZHF317MXD0yZdB3Kuw0P9W27dsdXqlw1O7lVP+YlFMch/sn9mwLqOGLjdmT2AuXUo8Yqv2s6Q1T1suwnwjBE3NY8u82vqh5G2M++POyDG3X33xu0HmTrGKIWtr1OAD3VuFvfoUAqHwGwLYctVDYm/siP+7gDohJ+6faIE92xYZZp89KUfWftRoBkogf5NmSNZqF/l+9aXKrnepP4nDEs9PbP6cHQPg9I2/0EXIReLK32XKE67BT8MWt1CtVQXOx7/9wzaXzl2pd/t6TkN7bWcaOkg6AN0D3Ld8CtuLS/Gxv4Vo3RS1aorr1j0BF2OQLslpR42mJYOjHNd0S4Jd5mZYovju3fVlegfMAxEQAyt7bY379E0RRwnLeZUXgOCd1qdTqPr8lDhJ7PiFx/UttYlIythOYvoJoyUaPeezq0H/PPZCStqDXNbnga0eobIl1sNQ2K+pEKejL4h5MF9VZiC+QE5JLOoUbC+MZC0tFiLIpdNbjBbd4csPI3ht5jR9DVpbN2KlHlSiMf5oiY0e3CnqS0JZRgaHn+3MZBVPmd7yh7otO8nme5NYX0cKFzSVChjicW+FegIwGXBIQDqnuWr5zPbC33m0Gh6rZiZPF3ebb3Z1FbEtNNC1PmCkMYEUP29ybzDX5quuNfqL2H+hlgkIvNtYzGCv1hnPRhRCcjD+iMI5SXMYQq+9BB0jTURw12evhhSdrMuoidAsvl5a+T8Yr7rYDApt4T81l/cork/EbuGrznAXC903Zb/228hAYsjcB91mHRaOrd0edavZ99CNZdIyhcu8x+L9vXp+pqc7Yl24olI/61LymCfx7+OqCQwJ9GJ731kVt6X+K4GC5aiDyhRrXD2cJ0ygRICzZpd67TegiihiuWKOcY3JdQ/rlYjvs1yUjVbMgDfBndtWAzO2nTzLhqiJsRbo3OyVvfaoLdSgliLH/nnorb3pe3vwsgowu9MwbZ1HzEhu+njq/3TuEahhv9N5uMYBDrF3FasqnMyWaRSp9SO0dXU2ZiuLzAJtdMPi1dXYKRJGVP6AfXcGud94sD+qkkWN5dR5273gGJKc1Wk/KPd/NouhGRe8pL6u4G7xC1MvI0IID8xj5hfCWb9i8PlBfSd0I6qTfXKeP81glBC1pZVKb5ClKYCJpYff6nR7/v29ydsYYxqs5YOWYxLG05oifisQ7gyIumKjdUllSGpcF3hCSacTaVhFlF66dJ6seKWtnnogsRwEGy4loiNKzs4kJ0pqO0IPjDjUr5MTwvMugA0jHEJyowYOHCv1Ga4GmIPPmpl4lvyLcqt3ANXcTJ7ok6+2JQ92FiHKY+fOqb6u/y+KnNDUV6FvYtVxXSAGRTBjUhorqguaHUJq7kyndn/lpdao6K+HhE2qhYH9l+u//AWgmkbnjkENL7jymP4RRUOKRVPOs5O2ZdTkctUWDTOLncJHE4we7i6APEzfbQQs+ai0tRRMFz82YuZ09MkViJz3qW9E55L4Cild0sRnLA5sjddNollpJXaR+IylOW84+42K0YilrkLLQRIam11NYU8tKltkrKWdK6gCduHt/M3YFlYxRRjLSD2j1FqE8ApLKrqRrEksa7S9+3VNHbkn//3NsOL9JaxHnpkrtQQ9xFfBITwGQ0rQ1I+YZspVFuBHRk8kAlck2070qWuECNZff23TE4926Ky/nTzvemhoHBRhbFNO4ElF8bLWybKvPWLSCBGYqRngBOPjdWpMNQihKS8V6mOXX8THI5RYaFt2kOJdaeudP4gDdGmrR3NiY+H+K4HyRQDoi43sr7Va8HCfUCgc6slfMbbXn/igWx3KJPJjyBytreFPHhVm5UM6x/LwgqkQKLZGEMyLRpjILHoylLNtPsZ+xsk5qjuYdnTmG755KtPbQ923NYCy9R6eY4zfGaucmL4eMt68uZ5CqfvLjkAWr6/epBXwyBOZXxIkQWnZeVxmGF01tSBoj7jG42jkIggFp5BR/Qq1ltV5UA/ZQXYTL1BqNQgV2l5zTtZNOOOEVK2wedW1tsonQEQ4XiRzKr0fkZSqR3BOj7ACXfDMGmwS4X59kQystTaMInfuFWzia4uYSONvZcQtQOwOcPL3MwYWE7Ig+/MlmApvOZv4vZZmNEBxSnrMF2jP4UfP8w4SjcqOcZGMxEp5LT1Lfa15joK/jKMF0t3IZ8Iwd0DOFCZ3QxoxpdrHZyBbX1FfOcUdAQZgFqnuzDtlTsuw01FBWSNUD30qRKrmNpTLGhEBp36trunJZL2ahIl7zyL8WAxJmUN1/FF3qkFPf7dETEJX9f22kJOjKaP42cE3JPXxjmvlPZ9YzHCyeaDzp+NTdB2GefCCamNR4JV3HFVcFMXNqJ4Hh9yStLAczsX2YZ4JKJOQ5SLIUfrRcLrqmO/Wj3kTPDa3rfH/9NDmEeNnnJb/Wee/hBiCnyryAYZgu9ugc1qY26lQLewY+GMOkGbGz5HfdzfByxVgaCm4oAoZJUsvG8vI3pVZcFRULP6hgPzmfHt7zQ9+ck0/NFKGtgAx6wVaIuUTJOgEfgvCjikFSydff+GfCsogXsPmpiBAwEdp1UutKr5fQcjAWrhMthbQK18NuR7lwjVTpqhGrgRFxkQcNX8tSBHuW9BFOL2B8ks835oPih9Cxp7sKvD8YMERqlIs0BGiQCp65e5Yz49lITMSorlfy+KcUpVuAMYLdbpOp4msTYEPIf0l8TJVXGbc6Yr9AWoz8xxzxIylXl6VxF4WkhtH0U5Zj7Gba13dgtVRbX4vsphAV5RyzgRKW1wMjYeK9kkEQ+squ21bgz5HeRHQiP3159yYwokmAO3EGeAQWD+VYR87qlneZxaRdyoV38b94fr5vH+v0ZXrgC6RsWMslZaQGqN1xEzCKvcXrIFIQqciCV8d1OmTYJFw71kn3cBzZDA5l4rt7FVKxqrvYBFllfU9dIwCVZZ4YiRLYwSpZm7yjAVCN/ecaP5Zzy6CGDpGttWrsKmxB6g1AChFtFmKFBhkKIXdED7UmRXNJeCbp61zdqvf5APXIR2eWM+kEEK65AV34oD32e6gL7bFc2Ljsafj7B30aRYMdzy7IjfhiQVQBf2CTNQCd8PWx53uzQxnNPrl/VKkJM/L9z1bsMYcHwjN1bk+q/Wa4bq9siqjU0ZsKDSWU7i1nXL52l5JycaRTo7tvUai+2QFS2Dn4F9uIqGK3kUMCNYYBsPNemxBqEI5POVFr6ajMyS9F+4T9w9wXptBztb+lFPFaWQ4Ma/q6L12VVOh3h30B8h0AL3evKu809yU4b+U7i6Bscs/UREDWraoEs7UetLSffkTB3ZG9OH25gUtXU4dBp+CiM2QSBOBFAF9K+BvTgM/O74+7PheIZKsBWUY6emam1McPMdYLlLzIl6BdHAy5uLoXLE7NyZw9bSJKbrXUs+Akd+j1TMytjC9ke7YBcUb9+OuUVOxg8HXqHX6SdRef8ERFu/wNHXvglBeUAMMC7dYA6AJfFt7VzPxpv3tdvULTm+Px3UUjxp+JV5ubNUQO5+6chjYeIyWan4/T76SLU7tI2an6o1AR8iUzgapMAN65pJFScW7Mv0aBI2Bou7G2NxXbMkusrxWKi9umbLCjW4cZb9WzGUY8XcVwRlnqqmYKwY+Zfw1smlVfyBasNI4kxPIOC+kpurhAdujUKGGTHWmStRPCcG14SrwwUAst3FHyZKvsQGo59GHkS5jur4vPTQus9lWtHAtSwBbY2N2WbOeEL8T9x+FZdvQ1Lw/g/UzTWho1IE4PeZXlRp2Pm0j3dLSN91ao9YmpjtwRS1QwGzrhBkDk18PWvbkRBhwvW8YMXedJSISHnKvCzCAynoYZCT2uBdlAy0bRSUj/3DT7NZ28iRd6b0E7xWiqlO1JiFZg3eE9tQmfDhYaTQLTyJ7fb9AbO4O1XCgxIQVmB4KABTOgPxF1Hvk0wab16UoW8W6uLUXboJDtapCP6ZhGMpJgumHruxmrb+jMcLyx8/4u4f8Xe+oROFTCkahOkYe29VDRgnN8vVB9KTa1Sl5cazTY+ImVrZP7E2T461mGb6Nu7M6s/YLlVKXu16+nkzwQ2x6vYZ7VWLKaMux/yhkqLC6lOoz4srWBGT3DQUCiX16pyn2iXg6+3TbLj7k6fsvqP59ro6No0AuQZq55ksvot6+33KXo2M4/QQsCvAroHsimaeweOgc1C9xEd4tYMMKOEamF+khyICDXCLeh9G2p0lFmiuuGRr3nZziwzNC2Ei2Cg1VU78nob+rgLEXFa+V3pXgzuK2NbkWb6TkUePlYhAbfeaDze4ZjBG9gRKQrxhLa1mWWGjymxP7Kunke9O6i9QkbYRxbKZgDsz87Jtbz3EZeF2zs95mGm1/RRjy7E1o8/XyzB6rczulg2jqA6DpIDKVhKVFSRPB+OQHFGuv61WEuhVvOepHs1yiYWS/yTLv+exbRPi9UJdO1KazmfzECtNchfyJPJhdQpoSPrhBmSboZNkJaQpIzswCTgQrOo3Y6pjBWIRFbHFnpBpd3Vc8mFFh2EVyM++e2LNEOnH2IOjNQF0V2odyuJTX+csT49srzDDlOg5MaWqAPCD9LBecRjAj2VuoGzGOKTLs65v1WoD9eFF98K/8CLdryzpFuD1b3sX4KFM+MaITq3q36IEDdmfp2uSe2KFT3hPojt50ztGIPBFTtHHQ76AI6pLbiQg3JGt7BlNdPE2CkRuXl+GN0UWhvJ4DzMZe0KcveQlNwP4GOoUutW0fww9GxHd3SZBm+SnTHaKiIVLkNVGUfkcmopFvjMJS0FiSoiohe5PTXnCVJIre8F4oaG4ecNMiQF4tSjmUwRTDIIKWApBb4LE+xq9mtrT5aTyYcYKkGAQ7cRjyPSUDbQMYcgTRJkUFaV90ehHpvJR4c1Fah9AAqRqapZCakmCXxUVzkIIJbnXNWkqjcBOb/iSRhJHziVl058/KUjMNIVXOcdAjmiRq6dl58U7E3s2YLTurZ/0MzUypt/SJ9h+PaNqeYtd+1HDWKB/4ZaZvK4fHqLoJXnAf9ZHb9eFCN9piLm+Pehexkbg6eeAyuMF1GiPxXjnEMT6Y/eLuiaviYDYuNYm7A7LAQzLClp86B3TUmnhCIPJAKG3CS1xnDXT4Z7UShZBKCvTPZ8Mep5Lpz7zlaecFMSy8JXbADWHGfMa97EoND3A8oT6KEqqrEsxVWWd4PGza8HsfoY+kZZx0wSYOJjKtzBsU2JVMn/jamqK6Ee2R/dNxsT6JYPObjcEwycMGU+m+JLapmLo9I8Ugiz7a8p8pRZkx/Ct3hTzd5Nu8KOFpF+AugO/Ew3niJxELy3m5nDSihJS1vpay6KiNuXzr/RUho4R7HWJvp1sfaSaepbJXhZrvHATx7j50AIIZXywXZd6aoyojGg9X74p7ytRhxKzgMFwBC78gA0PLHLydMnKA2d8519etnZDxGTtPKABOxKgcn7KeSJKMmPdeCXiSumXxW56rmdxyrJJbP3PwThuTYodXd3RSGG5NZgNpQM/jIKmQl/5XOY5QW3U4Ib98S0HbN07YA8obDHSLlBuFdwOWlqqGM2OkvI1e7qnFPd5fenqJxRSr3Ob7vqaz2IbV/aGMcETUFTt+znfOS99QjnRo5NtqzM91I0Le/p6awFyWpohg3PAZf0hAO4HjouiVTiw2u01HykyfmCVs6wP+j/nhM5Rmo5t8T4y9lfYxl0/hgTHVXAisE34+dZsI2cMSi3F3OUzJ7srM7vy/NYTaIa3aeGd73LFk3lXr4LEQ7/qXzu/XqnyrSyqIBpKN6UYtQnkrDuiVBswefzgfEdOBebm+591Ri10PjLMWChEOIQF2s/ZfNXsl9LZAWzo68kIMG1yz2HHtnYn2dwEMC6k6nfRNUMrqAeGewxmzGEwj3nmk5q7GBxaKACSt+6XnCgQ1ZzQGnmU0gKhvyYXV0Zd3R6xUULhL8WKgr4TB1fiT1lSbV4+rVueupSKj29Pktx5gUu1bc4my3DemwZcIJuVPtjHS0SEziOq+21hub2eTp9nksjW2cMeJTznzaW/7JKDOJR3hnxclbori4J3Ci8y2k/oXOIBPaXiDtOE8TYeOoMG6DqmyksyqtLgSh05qD0+ATM6jNSzS9NJbO5dTnTfJYmgM0+bW1aDGWgIpe7P9rYyOJg9wrHk8h5Ev840HbNdGXSAp4SdMy7fwHIIknZNf9iw74gRbLP/GGVPWhHDGBPF0O0q9ca7jLqUCE/4iGpgvWx07Rr4os2rM46nR/5l5J0RIrbYnsXZ8atMOp67RFI2UOkE1YVImt+Nz8TtPmL8yS+9JMLn3NsF3UbiuVIUasG2bM/JeKNm8wzdUdngTII1A2guwY2xc/3oOhF5AMC5wHx1XvC41GOdUjc1/BRXpQb++MlDKll6GFfaxsk3LUgILXvXMFVg011a35XSP+zrCA8arwZrev42kOeRxQ9C5qIRb80Ck0j8SqmO+urRAMmmGdswc7CfaR+wFTIZU+MI09e0pPdB+xB3eaIsdisiWCP3/gNfXiEx3OTTlwaKSIZwIZdxbuHe76pGlaclDtLmRyhjzrLPRw25NxHdaVu4K7ugxAn8ZhMgaslx+j9DYTS3ML98h+cQFFTMhcAmC1Rvgaf9YnOTI5f3IBYFMAdVPIGl2A3GoIofQUfDeWPQDZ0EXhnXeOExBc0CZyLlXNpKyAp+H6wA+32NomAMFfRxDp9G7obRW/44s+bhNbxmSPSV8INiJu7eNufd3+4fIljPaDMmmt0b21ja/f11Y0cvvJTCtilv79jjKQyd/sw74KikH6viV+LjPStSZQtomYyldg3iA2PMRUEFMDU09ohawT6UDM4nsxwQKEz4+hdMrweuIrODJbf9asuUUWumkR90pqVwNMIQpMv4t69TXxenhhETEM0wf5UY2ezxeOydRAQM4ryh2+L7zTBkeqD/ZXRU+1YcJG610XeguBEJ7oKlE192z/bVbJsB6tPMpXjfUBbiLQ8hNxFil9jbiwz7Idgjpb6tfyKKVcNdTGEqWOsGst0eR4i1+6gIrwSl/OL7YQ7fhVVR9M3nc/YDwqV2Fs3l+Uti18niZ3iCqsXUPWecYJefeDOQukhSH9Ll+SbcJJht14I96KYoF4i4qrztbztBC40erk/jyM+hsDentEtVDOqLg/ecdLnrTJAEnWnxpZvdymEFZLk66S83CZzMnv2FS7IOFJAu8+7+UrEU7S/CUu+aZH+wCuHixWK6iq5Y0U3yr0V0CxiTkQWGPs91JkCxQlf01PuNAzXQDjzM17bCWK+LYsgkIEJYxpv+ohbyvT8DbXDSLNZGkxdHxYiC+ZITaGg5DCRnD3bcEBX6zbH3nqKnCOD2V3RedhErCxQt6vdXXLTFrvXNLgYvm65VmAf6pVH+gutSjEei6URst4JHEJUh+pMsMC6yHKbXO84dI2NXIm5hi93lcbwwAhYzgSic0rfLbG/svYhNTnUTxgiEidg59bmvvvCS1eUPI8YMUT9SEnhvXMl4nKzkH0jcOVP4ddckKrWXNDW9uJQuD8wOpOShNRJN/0G43JIhbGTf+alU5m7CJMfnDmsvWyHiUNL+is5PlMpTYGqg+cvYTiy8XeVKFL9xOZTu7/SLD1ZYO145fdjsWLKZnTBPZdIUs4+wcRd/cUKTaXa3URejWWfdvNG1T8JG+MhELsys4WVGndlQbp8ChxhrxpyDHm8d1sz6zTMqIN3EXYr/SZDGMwGIUywqimIPn/fOaJ27Welpq3cMW5i3g9vWc850Jah6wN/d6duqlJJU6BL6BvsLOjuZbxtOa5+B/DWZ19tXLmO7uB3nexcCYxHGmW33Zi4KDbEiIGWCIgNQcc0WVfzUjoLy8wIja0+52s4JJ1sYfBY3cfCtGIPvxnCkSUmhp2sAoNTGIM4WDO8atzF4x7tNhHrUwJkY42tT4kZrsx1YjTZoTU6UPwQQ3Am75yOZdDpd3AdAp1ppTskW+2nXsN2KSGKuhJHGeJfuVz9KS0igByrMCh+CXzgbMODtv9Afki9Y7hGEBpVhwsxHYmg6AszAmuIxg/llxfKG9VUHGRFB+K2+HsWZGAbnJXkbkvosgJrFRgDsS3rKZ5YQ7cs9ZD0/KjTvECcZZjoVKp2093IfjQEGjelaJWEVscqpAzZRRjnaBrBtQl5FqV3bZMP8J5Vu8DO8fXXhsfhHkf9lYUJDExFfwq75yzMLD+kG9kPdwLA9Rdi+arPyEXkXvAtipHNNgTMedvB+GthKAAhd5OZXYWI2Vj9wA0HKulx4wMO7mCLyYjxcw2WIIOvvUSkxQ7pTZfajgK/gdPn7OU042OYbFHDMYX8BC8LKM3GiL+KOLEIt7bgDxklmZ9Y4I5KzphsGiyp0GErOQx2bdkEYq/f60xwIteDGNxbPN419D9f/BcwkhrBLkLkzMm1qYlMzWyCdCvFtm4iaX/T4HLxoxgLmRokbzAy6vhEQbMkG34bj098rqc6KsK6+mkjdcEVQ5GcySlrQ1fHD3+S/aKcALXbkSoxsqTzfiBIivCP9mKWYm3VSij1eMjICKR4iTtn1iYRtBVx8qIBH88aFUVHkUphHGClQfjSMXVKgjtAk3f1355uSvWekMEtnJjOUYKNB6fuC1ElhOWVNQV3GwaljRjL/iCKC+r3eE5+B5Hd1AVdRbug7cU0Nz/DQ45J71QIc5BKGarQJwBCe6pXfuDfOaDLbi8SrG60u0p3w3uhBhnSFgIErUb95VJHJt0sskFT1LsCBS9flYgkya/CgxAmrU5gp+D0A25T+osY00jUnrwQYql/DlM2Bu1oY5Mre1TaAHvwcL2wDcFs4q5K0ByAHCwVlzM3EgUd0uS+r9n6aAzlR4Vp4XUz4p6Wx2lBUVHh0QDwbZ4HU3wV27YPclcJTMCv0NDrWDYqsw+Z8Ccom1cp97YZof1dFpvrRnONadgd+nEnY1ytib9lVIgSUKLSUf+yBoDy3L0FEsRc5zzwG6t/8ma8fRu4/vDTw33qm5RoSviozctV9EaJDb4OumsxIcbBBpcoF8G/U8stWyTTKn9Glmd8bhHR4E0yW+UnLOfEnnFeM8+v/oAeU3faTzg6W0ATLq0DpyPjuh9TX99ICVgFse0HnfUhqIvaZG0J4dssMg7gjmyC2FcJgJLVtm7TND+yyhAoEFiPOT++FYU3op+McXRGVNRFfDPQRGT95LgphZCJnsh1zZkGtgr9odAWpa+82RBd653N1UqjdwBOOGzUWRKT2JqIn5W4dNV+n9OZ22O9PfFd6Lh2fh28bM3S8eH/+/+RxaTUywKAKo1a0zLP0Z+N/b5/l4YbZhm6Vxn4rev+WVn0osaDGIr63/kKsyhP109KPAGU40IKHfBLasX7/Ue6PRiEggAAAM22bf5s27Zt27Zt27Zt27Zt1w1xgzzbafIr7vcXRhIlw2vQ8eiQX6SFhMBen9mqE7cxdYlRMPng2nGmsUCijTUAoV+j7bvt4oIXKpGRs63FUjuzgb8Pq2T/nYsVlJ3c01Rq29XGPtCWuZ1LdOzk78yrR7RGyNhJPYV2WQtk7sMAxPWEJykovzhI+d+r890INfzM1Uyn+VH2t56HUh9Imow0OU/9RwwRzMYS1++P4ELAjfeT7u7Bi5J5/pR4qiqTgspy6BPJ0D6vylIKaIMTQ2ODmeY3wBDDP68fLEMEYoskJ9s8ftsGAin0zBsFXoIa0Wu6eCvQjOzwY6wJL+WO8UHoL+R+C+U0t8BtK4fllGmAx4zxCTQNrfE9WKXohq365/GVYeXXSIpNjSIRlwiS4tV7nGlLlfwsmMlxTKtqT94BhCmoGG3+27W5EOaZjPUE5gknbBRfmMRcUNnjEIb1wdSOB77v48dxm7E5mhKnmAga8x4FLS09f4zZ1rjc5QDo95ZvL2GI+bGRUwdwCYfmczBAbpZSbDxxdnzzEEvbneFryhmtQ7NW4aDmaC6BVDGf0n89J9/oXORnDm5FPA9yHgVfyK0/EgN5XpJMuESPSfVOnAYYq//AuzZbf1yns5mHAbb+dBmkVdr77afy1VIghRLfgEJoEx7EWN0fQUyE3B2ENvd/98t4gKlX9Q1jb1EAx4V80WQvY1Dk5KRX1uc6Lsba/Y9lMvqwdhfPO0bhb7yCTFvuQRlnT61I1GxrA3c7pFTyjs+HslcXgCcNjnWRFj9viPB+Op8hGX9CCquKGIibgTBPZwOdmy8JqS3whB/SlG33ANpQYjwJk7KR0tWuqEDR1qn1AxemgfIORjf3srmQBP1ggpbrZ+Y4hxRX4MMp3ho1R0Ec7S8JwZfyH1VDWIdXLI+AZ2/WTtx63SjYO107Oix7lFC0Zj2+AMqrGluR0MG4i//C3zda7Bd1tr6d5n6dhaFtrNWCTOBZamPmMfe5QFnq6bXYXMzrPTn/XJLexZOiLu+cZ842qIKInMLxuPkA9As4yPY4ErPBEmRD64s58/ZDdx2qjHRzy+UVXuxefh2KWIzO8RxIWal8PSgUN3pAyderL0+qKfojrImsoN4qNv+RuCH7I1I8iASwMAhdSDqq3PtmplWOgxpjtbx9wn+yq/wqYJTheiPnqatfo6Rlrrf4yT+47VhM2BOAqQj2pHaksnercP4ZzXVL5ry0If/SZt4JQU/jTnjCbEzfHD6GhE9ucsLSBD2ZwnIGTNq6a4Oxc7DVPLelT5aeV3x9KnuhramvmqrjMw3U9oe/WMSSgfWKREnm7+90hTXpxGWtB8b6Q4X3uIX2yLynvKN1pz3yyacHBQ5pylV0sZVjPXe0gJrIEz4uNbQf8p3x+Plc/tVCwR0ECCYr03n+GebaOK9vH9vVIOwaB1sTAfPhm9osq9EW3aHLOG9wNEUH8GJB7MFm7Xt71dkj8LO/0CuV2OYaDphVlf4xXeRWSiwI6/m69qllFC4XZ97zjo1wl2dwqT5e4IsFKYGK13PWLjjN6YosUV5lsx+BEFCfRGQgeMVQAteMzk2ylElkDZNRHU1PJVshLnkPQh5msSb0/FQFQzvw25dhWFWT54yts4Z2Y5vSzae7O64F367D7OTvMQtXMHxgfduMtKj3OqKDTT4VdnowYzBFTyNi0lLLrbZ0+TSs1vbA/2yqYgpMDFZ3gfOJTy4x7eeDK9YWOhmAAr1Q9yUhVbqZ2G9X1o1HSJrgHuBCY87DVgMiagFkwlYnA269hrb5CQPWlGfrG1SyBgK54psQTVXAFyo7gpTzVIyx1jkYCGXhZ1IsWLSAgqR0QSqLjHV8XJopOqSGujAXJc6tFY/5yLUt0zaGCdGSIFnrmaAoUd2/OGwJUlsif+X4QjVx4OpDq2yALw6SRJXn2UQ+2yzurvexVROHBorWs2ft40uZw/z9iwqwRHF5Ll2sodcs1LehXOeFurDQ17wuuadF4LWi+TP7tgFyvL3ZRAZiqRGFov8dsvd05TzXbyF7406ZBC4U4Y8vceoMW6ZjhxexHRmJqwmGbNuLApgiX1ln/7KAiSn1Q/uuUg1piKjwJhRXpDidBN5th4T9mGy9VL8aaJaAXJPE+QjQId99yQxLT2GbRzb7hDtA0TN/mYCT2JvfITa2ZbB1Cefw9C0GIXbdW40FP7kzYR5AZ3wQOpdGuJ44OvwdNX7ivJ0UVKBfOGgm2ZkTJd+RW3L3v70CizA7dJVBs2ECjanjyKmI/EemGzUbdDKl4YMV1C3gCj0j/Ko5PNabMdfkoJOwx8pTcSx/i8izlwfFGyNS2F+AW2S/LbXm/NqxjX97NJ9gj70gCoA3KFaF0sWf6qDVhJgis/RTxYgzvkNcmiJMp2A9JeWG/vDFzXZR2kpxFBG4yKS3Rh6snQU/3+hiG8JGtYGjdfqmy/dPpD5eZaaK6zT+8gSSlhekuOiPuNB1kLRl73mZ6laN8brtuPcRLWp3TyMpgJmxGtjSNwP1KiGZvWrhJwFCdIUopPKiK1wEj4EtEjXieXcqeZoAGRE0V6dADyY4a14N4/BFVg1fo2C9b+l1U4hHF3F2ur9qZMzQ+qyzmTaikfAtZBiSguZE5On7CvM4fWuJsByBHveqZ7gu5YQw1u2bJpG80c1c1oGg9GXauG14F80Jsan45QHsG3/4G7uv7vfcZdt2xClQh0svSSiaBEDCm7gLT0cPR4flSab9EFaOFcKcs3I1nvT6qn6wRZjImTUPcrWN39Q/IhTXKZmgHLtJP3xJezOgwSLP6evlh+Pkl9Zl3n88stFXWQMFWPrV+seGzBEB/05vgEdpvIud0Ay6Y3KjvDJd95oh7SJwVZtieNbzsU0rYrQ4zleyHxj8r/SQhRVXMyXiIIAH2TG0eZnhef5z2yVFgke13BqxBDlQMS0Tz2XYC/reUSNH23SgnR+wSnNx6JAxWwCkjNjSmMi6773dvVfg+aPa20dIJGy32HzmZWp8GyiG4mhU3t5mbNfv4cnLbz22ySdjz5QmYh1x+peg4O+DoubJ1nE1KThHBRNekDa6UUm2F3e0NQgzSxFYo5M6DICpdmZJuOJ5q578XenJwOA3JPe2zjQz9SpPRCjDqzNFDWfHQd2ypGhilfeS0L1OsHHSMwKbfa8lDmiVOBXDbFoGRwYEE+Vw0bMbwFrft6s09eBJ9FnlPFHMBG5GQRQ+gyqFnuMEDEGsuIPCMZZTi56GeVi2XwoEkpsqaCkjIL+UPyG14rD9xL+MnJzgYCiJwJBb6HRbEzMlJZ6wHfgC7iq1CxLNKYhyltw9qYQFNHXJNxUtGVHfdrFv7wNxVMoZSnUqueq0duf4iYr0e7JtG72xikIwYZhJQ05Zy9r9gnoIOiCioeqz89AAwZPcO8ulMY1395MxZONqlSAMEFYuXOSr5rj9GXsC6K+afw7vy/VSnC9ozIkVcRQ2JDXU8R69FosfeFtP8P6L+C1GG7q3PFYGDCw+tc1abldPLZnpwQyz/UThcGZ+gM/6cbGKwG2aoqUvi2jBYkT1wcNkYrDPZ8xgJUhAkSkjgikEbQ+s/MEUXAd8Qapj+28Uul4yMDF7JQQ9w/vkFGG6w+pMiKaUqloNMWthDlx473wLlRmk1nwxGTuJipsP9iCOrlTmO71NQS3wRo6qZ7TH8my6TvMLWHnRyf+Jttx42vPfWOqFjx6zSDzzs6lcQ/CL7ymEz+o2UwihaziYsKeKyxCkOr8QHrvfUwVnQvLNjweg8dFisas2K22E2mKJ2+zgW7kAlMi+wg5gKw1Zw9yztr0D8DxTKCYBRJhuYZbGMFxisE2FlZVLnRUEnqv9R9R0YYQgT1uhpWlTpHhiZocVEvgRR5Ce74LOeGjXWr3hnYfNWYUr6x6oUtFqOZ7jrpW5emqzkVZLbnCzxavcB9SdPTEC2Xd+n0BqYlC6q7X5I8cac04SQ5P70hjpVhUAKrNjykPsJoqlab0lLeMbUi93XGKWnOod19sXkovyqDnS+Z3uW8l1MZrwND3mM47dq7Zk/nFbXlMlaIlEK3xyXwPiSHLlio122veWm/JaeUslWXzGT/JWrKuHhVgYykrX7DIvflkv+Ldvs5dv8eNm1KB0jaclikEuwY51ChcJ2/Ie87pjlNJuD3Wa5j1Dg/T8X2fzm9pmuNIsoLKNR5mPOUpsLK2+s4TKaec4qUi6qJvGcfcT71GX5roK07IFhAuF/x7nFmggmQESK4JgFGbyNZjjEUqgDqMct3DH7kR/iPhHseNSMZ4iYaQNItxFtIn0UCJBa16epzQlJWmnuSKRYClnd3xrGf1zic24shNFnxqyXoDYptQCDRma8VEkuRYTbpzfRAqax7mRpTZg1OH3DaICXTwCVkoy6MfO6yetcDjk6JCEOKlmUMX7voFBDjNRJm/8rfeo8dbTa4NRzif7yHRiOYvSYbDy6nEU8lMK4ZJvjzfsMuyCbsJfJLU0BzeaBo+ZBmL0UNK6ceTSc7WaBm67QuafmiUA8kqgAXdGxC53i7XW1Skmvad086jFqNfJe+HANhmABxgBlD6RxxVxd+ziIJln5+9n/18IdeV4rGS6sHxfYgtjwSP7utZINmlZrooE83OX+S6EZ4LYRGR4KVB1hp6uFxSmKsC9tVihqJ66v9y3nj9Q6B9Ywsx6hNy51Co83Y+EYFjQOA/LyjAPt3erc5EECn3zhXUoejsTE5JS8cJxugLm2KYkPbuUhgtQOD7Y2F2nW1XalyC0MlTLTl69AEQDv73GqKMNN1GaqRpfs7zxQKw7TLTZC2rn9fc6QwE9vUZ1+M75HKqcS6U423a75VzCSWPS7sE/kw0bMP+Sdr2WmV8U0Vw1NiuiZC1FSokOXK+4XigsnhFp4mn+Us+ji+FlPLgsS6DIiBz7hH3tUZSxTIacAQSnu9R/n+gn3mzRAIzCFJqeD+oLL/rvcLz8Ek5A4P5AfXvxsFkSm87xS8OCesDfOsx7+2dFXtbilC4kQXLeokIxKxvS34RcjxiCr5tTvjsGxpwB1qOvEKTHsWpIT1PYjBuHbR12FHm8egBZXkXB25XiguZq90R/G8dqAHeXpS52TPIohOapMqHvw1qrbBoq6XTGLsPqmQBfyo10oAnWcUgGDdviwWdGTEVi1Usi0J2inGe89VQ65GShzrX0VRJre1krPrxrUVmz3vlwI7cNxDDw0/WTUIEl/SyNPt8ezOELDzrQROnHrEYC+xbxfgaAeOcfL15M6dBvDbgymsYCE69szmDGvCmiEYpCucM8zAloBjVw0/cjseu3svAGMEYWeqZgPDGqztjwAszAeLF4F+dj1zg4iBYBA7Y/3cNBkY4EvmDKu+TamnMW/2p8/bREtVh4NubTgOJXnbnsjdPJR/qc6rMHy2Ub7Ew91Zoer38eIdlEOd1dEN7MJTSJuvdK+GMl2MTRdJsTJUaZ7nZvpa1Mndk7mnmWLpJIDlEIunXwh5hn+2f5g79q3mI4GLj9TqE5lTCk+4fy8cu8TKbR70mLJSP2JKxtzsj4+er0455kyIEqABzvI8WKKYPF5CwHL1n/IeJ4sKm3EVN7FepSvTXJ/+2Gu2K5u2qS0Yt8S3EiNJWY8rrvCXWid1AHGuZXdmuMCJYg1Nx28nY5EL8dn9bsKRB3YYZFOw8Svkta3M9mE2YMg8rs1kQEwwQttRJ8W/qfFosWj4IO+gn+zvfMFf7zq/lNIcPEo7Sa8WYnCY5CjPgMQ+m035VYujwOBQ4JA/PZtdFWOdObQmksvlsGx9GcZ4R084YqgAbamwOU8iXV7y6/yMRJ3Y1I8Ii0bBXL75eK11t3R+RhICx95L1QJW4YReId26IPVXYKh7/+TbwDlCGa3oPu3mJGqPMKlDe4NpTZKukP3uD9lx3EG7OuN3uOtb0l1lpzJdwMaXAb6IA3n+DfZm8770BIJ0xed/5FJI8xK4qODcY4dtHK0tUg52lgQi7l7AkNhJKR/hh3aTtPP6nk/J1XubAGmogfat+D/L3+KDyHZADU0V3ZlXNGN1vLa39xq7RATWDbsbGR+6Zbetc8BvXIjJ87PpCwTsY5/w9CDX6GonXWpzho97vRWxjeB4KPp8Ea9cDBBB2sA6vG8tTZ7wV1RalfhdHo+ofW5tRZhDn7fioQOWjAkn6HICMFyMLCS826dZviJp/OPN1UdDgOq/Pu6cvdeYDrktG6Duc5bLCSWilmn5zNHJq6CHvekWzv1IIqWDNvzmA0Ptvs1qJwhypvcDCkWNN8cBZ+D1T1TTXW36156XPNOgd76PmO9+Gm9yXV6QJ/lP5tAWUiB8b7QrkXnKRWUSDxB4tIoOPUozK8Ot5fpl7i6FwMCV054o+N/PITviMNK/+Ai7sUDleB1IDsYaJBagGNDGefG3qK1cmpHK/XUrNGCujoPCWHramFbTNSs/FIJKVqkO65yx1t+5vVB93j3kZqaQ9VPhf42LuxJApfZAWFrqrGQvfI+KvS3K+RNL+LVLP8I+OWrp+y2dJyOcCuO242tjz3GHkPQh+slq5QxcnZWoU0ism+PiGGF3dZaOvfb7yCuJSGV4OfydMt0nHE5DeDhIEyOkwu/rxKAcyeXbUeIX+6JYVXeTVqx0NnZB5Jy574+CXCq1dUzjybrSIUQbkQd2I00T93u9BCPCkiQgvuPseD/RwanN4vGhzpvfv87/upUvS3bdz5XIUZa8qUOrLRDEeO5HdaYM1aue49t0cqLNIqIeSPvfTcJ7IhE7R5fpCHaN/4/BRT/PHDMQ3IfG7KkcJ6EGj8NI+6HxDzXtbgdguUqXRDUZKJW/4d75OMBSfRn3F6oCBB1go3cDGMDM7WWkh5omChowUdDE1ntjby7hKqmRstYS47PHS+6X2bB/lvqSbZnIvubfLzYjmh6KTPLgzac2+z8796SQW7fyrIOCooM+oeCUuQo6PolCctT3zmkFwQWoDZhYYb9p89l5BLOO2TadHleeKaFBXy1HVKObxNPYWXPc7wquUW0OlGzY/qbHcv+fHhRKdlJsYn1BYxo506sYtUA+OsRsTVz8IliKjdPVNxLskOnWNUgKcmySCcImDOmiEtBh42+vTzOw9wz2UFEh4MexKUp63ENEpm8q5aip86Im7oAT8FBLWSN41DdmGe3SF69q+JCk+jrtl5cDgiZ8O4VX7vt460OepuqQqly9Vt3GsFYboMvhw+j73whFuW2QkZIDqK+V1amwP2n/V+hZhFQp2nL8F4EBmbgu6h/DAl13ycDv6VnEUEwbBuGTFFIWcJEQ9fwE/SpOuzDtNN1N3YaTfhO08/H8vyasYUqXqea8E35lwDmDvtJMpuwa0p1ggsCGp2piY31ZS0xpjbgwA+LP7YXZGrLjo0NC0ghArthpRh3LzP61fOvHDalyMSxa9n+CGfUQyaTVuBvryQTwFKaR7k4jnJghFCRuJ7PCvdebN1vmFyFi2dUcXIj12UOCT3v+hNa54HCUwbFM2g/HCkBZDsHag9em3WpYI9u5dpQs1MbK1UhXEDC5ODg3u73E2Za0fmKUl6a+3busXd+V0yMoPm4OWcLjdJu5NONdcwn3F16otq4rqSdn1Qk8crOxuLu4irkVt3caOnpwygg0N+3r3YxaY4Wvx8PpNXSGBC0UAY7isPSgAvWaaGm+kuokMOxMIZAVBACgVQDCCRIjGRnfVgP/gHJVJ3nUvyRCBtPjrcdgKlKznuX9d+2mpA8A6RpSvsGmmboNqD2aFI/RuFWIl1obx/SS1WIOJKm4x6gj1YdJKgDCYMC467ovFdfMnu/CKr3AebJE6YqPzslUFqRDMdiB4TJ5zAqd0fBzIhQYpPwCG3S3xsJmq/EbHSs6MqbyhxSj9XqaXlLy/HV32IzXqhv2qe6rHV/g9PvxiAgIMZkGvRJh+dJoyUGeAYL4m4O7QiL23D53vu65CwYuOXwEdRdi5RKedH7Yoj6dJVQOsNQPGLH9Zlu0uV7HOfim++Ru9JmYpzyiDaq5r2vqOBlmEgV8rlV+HNbPxl/FSVi3Iu07lVDvqOylbOfSYqZSLALixfVUl5pNjNDNkT8LywXAysZLVKIR5Ww1n0MOGdIkq7/ZWSboFJjmLgyxKZdvJUf211+9mEI4X2Xkiok7yIXW6U0/1QO8rkgteAfA6/PVOdpJpwhwRk3w+13rNWycD6ND4pjr2oBn0YPlDmx0PslCVEPF6soyetvGSD/vnWOHKnEySRq77ewbNaoB68oJHTMvIKIMmBgwsgi4I9XVJAPs0NwiaIOOMkjMBDKUCjzKLfd+DDpWgHdOLMKFqmuG/h73/F2vl1EOtlxI6reX/3W1yYIpvlfWKBLOkPKOnrKThYv4WCBY/SzTb3EGzpNQ5W39ayRBEkpsmS/YM9tAu1ToA3UHNTbhjN6buJK68ZVEIGyaTzYQap62b7VeqtjvNdEJBynRJi3YuVYOeN1553E077jlrgQbP7ZGyCLNIkXTQEWwPfigPcAX0/cf6V+rXWtN0fMW7tapp5XbAfkLw438pcsuoo+KlrWbTh7uG4bxLlcBwjUXdFcSulDl95ZwRQxu9nUSue+DgtcGfk/RcKB48RvVxWZpcYlA6ZWh3x3HYbXTZTU5x3frodv9qXQ1X77OBVy0ucGiu8nb2/xgEWafP9MMmbVZE2G6t7tPpq6aDK4iqqMfu3btRZAW6hj6JFF/Xs5p9I0Xdq6rEH1n3wLQGPOmdK+1HnQVD1c93Yx0MW0Wdgr7reCn30NqGdeKcTR4t4XTj8tOAuXrtNoX44ZnAYfCgkd9yCE7xBNgqvAqA9TTWKzSSTlppdrPk9YEEOZJekQDh2ioG2UqdjUT22oThNIjczBH5PgcL631X7vguYzGlOC4sMPZ1XcvU5dA510uWAAxkJphCXLlfg+Ccie1eyHNjwOZ6lz2k+7P3tYpTvRX8s0Q3WfOz6ltuiz9bgSm3okJ2Egr8iZoYGM5rydXmeJ8zT3yT8o7lzwBcj2e1Oo57+Nrda/jVdGdg3vdSrJLZYXlc1VGYakjsaHFMJdKQrxoCL4aC7ygxQXYooT1utyQKta7dz1eCZvjxtdQImb7FzbGxKpuWjpFj37hfoezNGnxvsWsedYBRtHzD9BiHWWfeXQ4dYnE3d4/5EHWG+O9q2WCgg7MUbniapTDmsQgq2JbkrlG/m2EzYnSeGSctg1e8YmqM3MdIxmjpLsKSlhL7WxHnYDzZ5dfWXUCvQtXsj6j3fb3oThHmBnW+7MWYasZsLz9mnWbiJeXUpWG+1W0qb5qz65cFGcl3Qsv/y2h9KjlBFG0vFblOisY2vRd4V1EHDgUGL1vbMjSNgG8lpSYM3V4lbp6Je5RAmwp4e5Z63bJ38taR8WQu0CUNtqCDgAJ4Rzt1C4kcajPimANDd+9eucw4LWgXJf1PxA2sQQY7TnGDbt6hs2HE9O7YIlZcIF+zP1x3Nb2Ksfom1Fp5d1au3l0fls5GKPau0/DZ5Kq50SNQ4TQLOCNQp1K1PL9+Ujf/F0jYbAN3hegwcAw0o4wA1VMqmPTB5J1r37lWeaNmFFEI73szCtcs2ur/xPmMcjLLg9gGyPHIOiT2jXTSDRIMsayiuVWXTYgOJeDT20169w5r+lF3a44i2aMHXQ61OjehVM8dUyyPfQUyWmGzV+8AXiqNQ0Ix6gvq23Je7dRKz9JMN3hrEyI2/2cczeaJtANIsd92BmIDs0OHH7eSsp6ObiS8V4K6xMXfsUudNv4GeQatNjkHgU8KcO0AjgNr4OHFavLzHOAmcgiYzKx3Vi8OqMihS5ehcBtHpjzzNP0ILwsEEhEwdWbIQP9GAsyhXY2vT2diKSvFbFo3LAePNJrhFOz3bqk2VHrwjp93pEeArfwoPV8ACe2tHNwkCYKKSwDPOWrZCr97t3ItateTpF5Cb6r+VuoFqXVEmT4aABk079MRSfodN0uu4ZhsUtS4dJwJspjRGPZzQ54BvIhN9CslAxsjWuqNhFuFNUtxMOJdhDE+QaSWAb12qhnH8fnIB8f1RGJm0d1O41yBrpJc4Wvc2xQaHOJuv/iTiq6UTANOfgrl78K4bw8c1wuShl5W0ij5grb6XU1BCygDAFL4JYdnoGKjpX9qeuTANvn80EVRhB/dVURUGxjbw58G7P68+FRePHqLYc62P/vt4gIQAUb4lzCz3+yzwImPVCQhBeibY2nvGp9X0wbDCWJk8mzxdOaQzW+PFGAhAfktTA/tru4RNfsRvAeADSH4tIc0GIL7Q4RTbyHa/IVKBsAS5p9jurT7d9nKv/000b0tMgHLKQuJeZ8QPmvaKLNztyJ2/53G+Y0WgDz+LCeXFhLac/odj0rRsT4imatageaDKUwI9Zix9dBXRrjTX4feKxJEpkO6j7eH8gW8MxxLokeJNhJPw7RyPulks7+KSRi6P54vdCa0SjkXYGwkjMk/JdKXo0qYm1aSzNwybaeDDJn5SYciaH0NmQpiuVkrzsUPNf88GWZe1zLL5Yj71Oy0mzFEIpXn1vuYVQX9lS6/J0vFhxNwaq03/LLXOJf1pEFXgRv5BuXt6ccK9oxVfiZZFkvf5rN8kF1kW2GfIgS5FoveQPtv41zVfPGzCY32JM88jEJVtgkEKPFD+8h7jSl9hNMWa4qxG1BuapBkkNxzkBV2ucUP1BAz5KCxIdcZs064pvFT+bUfSH/xKU5mNvSMW+37SCdUdVJRXdEGfPanazG+FarW5Y7B0L1LCh0TYb4VHrZjWefwNlW9M7zpc5qx/XNVn/QzToEpDdYjOlNQZeVOzbfZj4C5KT3HEklYRFgpeHmOAqsMLsG5o4ud0MdHHyjdWgZrYtfYX8BzeuhBQULUSnrKKA8brHYjqTcQxf49pXKNtI6Hp1QWMW4W7iESNB/5SOHzl8yBLSCjhkfrF33lZYHO8VEUqqjk5oSXQveWOMC21W6ZmzuihWCQYJOuDSaiLl513f63xWcGwveva3qZ3zMMUPD6wQp4MZWKNUBU2eosJoPNC2HxcX1cR7uER19By1pn0WkovRAboNLh+YNlE5YY9/bTt5/FDRYdpwIpQp4v6EapngXVaqvkFdhRXAADZ54yaJekOJjQsCuVNP5upcR2KYNGZpd6Gud5iurrKqndUT32nUU1YyMrW6OuCMh93BBAVgjWmezLv2Minl+Q1/8q6rWxX22+Z47fX5YqrTYb5gEZQjnPfS4D4/U9i9BX1uoAkGO5+17/t0ZXZ3TKFJuDOd0j9L8YAlt/kp3/bhzza5rY2aUxrhu7CvyUh54xdpfkb1AgFL1lUj2LDkoLaXTEp61n7i0ag2NqyAji8dJ2whLyRslWkxNWeSe/gpQpEHPtzDTe+WMgXlQqtkrGIC8P1nlUWpnNxWxxJyXLdSRWnkkwIGN6uB0Ac3Y8dHQ6X3bRDxy18u6OodB5i/ljNcJPjCqUp8JLvHS0a9vrryCTQoK4HeMQMEsg6t+DpPNAZSqsgiNG5p2xnTdn4Xm+7hvGXsi6HIHS4jwsh7fuvpVtNswhtsvLMkJ7h5Zi4gEWtV7NNWXkbXRkwN0Ywwu6hZNSkb/PVp+hYclvQVYQAHs5B4tYhTrBCQAhKVvpTdNfzYevu1y7NtPlQqe6xaya4LKDmFj5auNkgb/CFiJdZOzCqftv2Myqun2E/ZYP/MuYVR3BhAJlqTbMrj75FapnzLm4IsX9d4lM26Gwd7uymBRa7EXFgSbquCUHeip67qa/mkjRA/sFSZIvUfvrNVX0sZGGAMIXw9fa+4MViZ+8YP5jwlgpzamG+LpdAr4xYPQ3WNY+TJ90cw0A0lFFrkdZo7+JrE/00Xc/M63skDnX8d9ZQgcK+dvA101HCAHFY36zg7Quf9UQbCJvNpW78OLmpWKvTilNsZJ5d9srWlVj7H0PX0GuubjWs3vaJqwawHtl5nPZFitm1mB84WOWQqvjqWY8fstq2RWT3/cAdE6WW/CeZIsx3wMoZwZFtdpd+axyOag6zaKSMayd3F4Bt3L3OSJpperTnTHk7KH2iI1wh4D38IOBvlAsYe2OJmTY6iIhnhhn6CdgE0X6zDZlDMZB8tiSVHupPLAMjoSrnQZDNzBv0fNqtWeA1pb1aIbxyXNcQQtwe+94yS6B0TSUikmWTHz6YulqqDThH2jRm26KWV0YOg1MPIeU93dNvGfC9sllV2KlYUhuvhXSk0muGakm+UfdxTFPzKrvchcoKwAdLYb1YTf+lB40VJmaWUi4a5UgauV+hFe3XKrJwD9Mb6iW7SbaLJdpkBsBwcEMdwWBCZSCH2vgZstK0uc5gdCzF/Du9LQ3iOFRztdmvdZHuB1hiPXTC0hanSkocLBaoM2sxTECwano/CmsARyfsYGu4s1VmGx656FLfjersyDUqMYl28rhj2n3YEHa4BpeP/WtWmCs4OR+jWOsQ1TcFfJ+vECQKgYZZ4kiCDuTBKHlxCVcWLSi8cNlnZrVWpV5ocBgxX3GeM+EEpP57+S5t9bxwI0Sf79vMk7oLYP5Wcqk46kP5PEi1oZ1z8f7eARM7vt5DBLrm84t2cpajAKWei0mK1gy52mARWHJpZtD2tw6MFBUUtOL5BsIWmiIE6QIfqAs/GM1KCONq5qNvs+V9p6cT2KwKF0JXbksbDsMvHcwnugEFnG98ST4qg5rxNrUG+6n/48vgLxgxPQ5LZhpDCHEOuZEl2IHCqca5wOhaoxWwhAF8IgvH0qzNzR205N4y8RvweBnD/pljh+u1CRSeqctyHC3noh5sq2va+GYw1nrQyRrIM4/hWH5hgR+jpwRlhzjDAcBCd8ryTBscrWyih7VUuGZFE1ZV+yBVlEchKqzxkdwiBVhR5rK8EAEpIukwzu1paOCh5v0ItVtQ+u/qO1l/B5053Yngvz6NaHty3k+wu09qUKIOrXahVnWeX14X0UgRFwsUC7eshEdDmdQk/6V5ALhtmlkKgtHyoA/7HmzZdk/vOJWirDQL0kMr6K8dhijGvqZOVph7E2Sw6dba/QoSr9sSSoXbBJGDvTfyVkh06dg/an5ZdhWICM2mKbTuagaOAWVJuKi8swJCeqrJktFQddQbfy6iDD39e1fvcamXZB7OBbcl6EaKa2ZaFnrbfuNdBONQwUDAJ6+3e1+UXPmedRDccKlefkB+YAAf1/e+08VIDJ2o2Id6/FOtG692jX9oyOHiv+DIAbAWQXUNeIpv0ZDtrWlFvQEeO28j/gnukrq6avCnQAX7N9+Qs69pkn0JwMLFyyrMvD+XjnjTCogiK9h/0mRcoxzGWon9OjMPHSMgbimfWTBES5z+T5GOWuzwXidTZEL0YRYA9h2wF4gZchlzBKgGToso+zicT/xX7RnL8fZzigZEJ2i5BOHJ7NUv2oV0vBmK36ss4bww+QuMn5GgVJaUQcerEZ2WvqvumacDMnwDyTA0bZNAKOXT9hPAwQpLNWq8XGoSQqzJrvZCRQjES12sD9XM5e0ZzeXMg5CWPUXl6dZEjGghv85X8vwyZtMS0kyatDF/DBS6DY17DR9tsRaoukAnfLjYtEyYJGPyTQK+4ocef7ZrT9udtEh4eRbvX6f8Sa1DkdGjk3EeAthM9xhUJa2AvXRfDH4duZmzuVnKw+f7X6Lq7ghnxxWHhGYuDpHRgzh2plnob2hPXFx7TC7uf7JOQaGhSvO5MTY9T2HxMRptAuTO1tvweY6Geozj8ptoc3WFI3q/hCQBASfi09NQ5qMCkNkhGKNARmio7ulPU7Z8mvoGQtD9JK7oLfXU2bB1MhgpACFgHFu7JWOSlU07ycu3kL127Z11flT8V3UMGBwAEYn6pLMt+xP00QM+MA6QF6RJy/UTtCzUik2v0GybeFt4WoNKc0ZzazeQW+Amg3n1dc/qkPR54qAgs9O7JUm7Aiq+MuyImYq+DdzJhOvvNGFD422kZ6hLhzfb3RhPjGbSIYQM4zBh1GdYlSIb2HT5ivbJPXLIN1HlHSsHercI+jYRvMHaUjg8f2gfeQEcb956f6JcsBB4DeuDhngNhHQrPlRvAg0lGzSRdecvjVEwPOV+HEZxVlBK/vi5I2/NaQiD/s27iECy6euqpk9ySbNK9K7M4AJsNb/UyhsmEEJ6Ea01DqqFMhlp08L5hr9q1CkSv9QrzUW6TIUlUB/tT4yLGvj19Ya6Eeshks/QOt95aCEWQm/M8ECxK2pMRlASnzFkTbEV0hGmHylqe91pC9e4PGxQLrH12DMDIImx9qSV0aiIzpDV1JDoKiym587jnlf9Mx3tV3yJytLTjVysxKOFPdytUDdH/4zr0nIl7Uz277UwCGli+3nEilsj2ze88qYA5y9KsxHcw7XiQMmTO4dyNZdO/CVZ2yY3EWygQX6PYA53gny6Ymtd9vF712y2t9C46FMXe4R/e66kXAAj4hl4z814MnO3weRKafDXq9LNQxGgWC4kYfcEy6QXZBuvNkePJ+IR2JHn56ci4nWCHX6P1HEXDOVEkEujLrHuQup1BuuD44/AoIbjpYLVTw52YO4r3DVaZIKmsINcZTcwEQ/Vxnb8N4R1i9gfE1QldP00MJTJ5aVDXvNTYRwGGjuuYWpNuIN4cZ7AbcFdgr/141hi5P7iUpjYX30Sde1dTuJIgVoayVKlzlTmgvO0UJFrpc0pT6qIIaH1a9II5enLGarnTapkL2MzaZDXifazeCA8NOvuZ6VTpcdjlYhOaq3G9aP+tQ8AM4VnEL8DIO+9V4D2W1n9I3PLXtWHM/xso+0HiX0ShC8NpFE105k/hMGjUTg13EzncxDJtmO2L9xgifjxmXsZPArp8VDutHxK9kDv8FkbjDTjgeSw1k98YZuv3MqWsBf5FOlKfVY6Cj7CH1KE9S7OGfs3zyvtvYFNoE2mrczd3W4hADmiCLPlIVo17sy2/oh1ds3sNNo0UrkivyY6WgNrr5TPh+0rYlT4RIjLnGFiDXY5q85J11zsxCnnjF0BmcBqkzBaaRkW09W+mOBgX4H+791E1lKT+Ny+XL6zBOCgU4SDv7SRc2nbMh6fx9OEvDG0CtM7b9g7UhOXbBi80vya3REDBsryyImTxqcvnV3PDbtDWMGy/l2waT75qE6svfJM6aLMimqcWcZoc53+UwtEMg/B1wQR6KoE9riRXw8HvTQyKo4kFnAwd/3DaDCzgFVbG9ZGK7o5QlSdCeSFZgtzX++vNbTsREcMrmvvmK67m5sjKWVRkaE3HZLH2DRm7tK6HOLDfZw+tS/Jpguqe6u7pejmdfjBmn/5yJQ9FuLZAtNWwnbtZ7lh7IlCPlz3Xjke7aKb5nOXgFaAz/zjOLq/jzhH5afFLyCQKnMfHwGbsA4OmVrVKRRkD84TjQo1ljj+0nHK0CbuYqJ+gyzMJuTYQmgqx17rZtaFrJaL2sf1X0tsFDrmX0ToBI2nuwCjsF+pcmxgM6BJBcNujZ1syHqYwrQjj3fvetzxrWr5BSYkb/gXNfvQ+BCBwCVSlRFZD+xRzF+B9bXInoEL8izvye6ZcjXa3DJBPvinbMycanXEsZ1rWLg7X8w10wC1z6ExglrrwrUm4JxHDmyW9O3qj0UPLguGEcUIGy67m324Ie77rLrVMmyyW0LueiZo5xYZ574neEQfZvNxH5f1Px+XdDuMMJow8juEzCPbQljfrJlh7x0Io1jLny1nJqTfoJ/9jqp0do3FP0nbZfwJyeDJstBzxT1ZOFySCxEOyqNNLSbgR6etDeXcCld3YWlq2g8WXYv+We+RRYGnJlFDaRU7mh9On0vVJbVyWzjdEKQsUfTxAUEQ5QRyyFGYTAJGH2rnE3kCQBnu7YF07r0T9n/BsFj3APE1TAYn0hTYm7CQAmDf9e0XNYYqBBIm2fWkiPtaIo6NMPrKegeGZODfUQdn889Phc0QGs1NMxZdVxEZQ9Lzrdeawr7BC5lg3IeEF5GFz16HZZ7RaiqyVlOSsluNerBSmx6yo6yGHTlCWmbM8tuaN4qTVR83D9O1gIgwxFYriQFOMN8DEOd3OrrU60Si9YNL0Hxt2RsDNusjZXDtAEREYztw5z7RjtApwysgikBGaIh6LmB7KfJg6T35+0bB6Q8OlWpJQLDCSOU1u3t/E80Fla2IRTNbKi8v0QPArBve5Jw1qnhES2RTOQUT/OPTEmj+O5G5fMewqQwJAYuP3LuKbU6a2k2vX8qa9eKpngyY2580dDz9vMTibX2ozxl8vAMN0B7y20nnNqa3SYDQ6WMiFtglfz/ark9ObNP8+VCr7cmRHq1c4FHY5r/GfXqWSN9fsOGIRjNTSGuIOUyeudOMwn7LbAarn6oR2+vcPM99iGQzU1O5pxmHB14dD/h9d735qbsZEgUZdSQsMU/8+ZHqmhMGcwvxh1lUmP1DwXKihf4hgwE0jJEiS66YtHtZvVDkMlhV0usAU0VV3A7fbWM6o9PIfeImtqcsJtA67odzaE3q3ODjsa0GFWXcce1Jc5Ox++hOIyNfT7Py5xcFU6b9Kw37XtWkbk8DtGMyUSzFat0NnYxJgWt3ZWuddiX5EaAKB10IzsEGj5WXzX9lfGR+iodVsfefp6msUUg2yo8XaA4o+nYZxpxJsNxoI1zI0VB8577zqGhlbXf2SLfU7AEIAfgrpSKgQzarx6cMazWMHS9bQFQDDfpjJ5xG6PfWjRC5ElGiAZWI0a2WsYRfYhjXFQou5JWIKtjNt47WYGvoG+JmGGUt018SGatf+W0rhDTPKPcZ7Foq6P/8hOq97Ee9fDMkCGvF06sCr+A4Am9IhjUKBtSZgznrQ/0hUarM9dCNn2uwPOhFpwTAs3BmSZYAj0aynnxghq+WlHUZLsGfFqNKijS/VE5Y8OmxkniAKfRknic2wZfKOnHaDeHOgH0YJ7wwXUsRPuw1B5e6JSfVrIx3Nv+Al/lGyko8f3RaU3/O5m3xk5tJCxkTc8wHdjE4SlQWNdWf8dgSocW101wdjG3PHofj0zZQCFwst7Ql+lmSJxS/tl0UJhEGUsGUGKPrxV54lnS/yOC9qwwUtjUvzmmIoUoHn58OWtrzJq+6qtEU4rmIQ3gaDoJOMho9YzaIBqK4JAyboCJCCXFX2RbIg4uZQsDetH0vQV5QwKgcw9Y2Z00CXAj4wYJRQuqGn9EViHOLBO5h/4nIF/MGfg2xM4o3LxEjs0XqCW37DHssjU8si4BqwnCPmJ6wnbEZ9CbJbuN2y1Bi6UosYZkl0+DbKgdpzLvlWl/OyzM9Fok7lvvegCiQ97DKDBmbpFdg51QMlgDq/9Dw34qDHUPkW1OgUwgq8ZQghymZkNnI5ktc9pcTtCTgWRm62Eu5PlyM7pidL5c+x+PyTT6EzzI+FZnvJKMtX+3J+TBm+3ShTVF2TE65PCj8U+d4zZcggFFnTz5RtEuXgeLyCUhhP3vykST3EaT9NNPJdvPMjJnC0G+x/2Jhl/fzmwLLWVi3vxRjfk3ZAIcM1DL6tPHzZjS8GhHj3jQaXy/zIeZTfc1AgXlXxNxSQXYfizMM3me6iY93vT/7s56FoArmRh+GBy5PvOf10DSOsDqtSdQnB5oi08kTvadzX7G1TRzn68WVfnrmp35HjW1mfpy8F1gvFrkSSlCaI6kCeDLaWPZZCS4tGKvENFKDcSbFgdXwxAZk+wonTv4OZNe771YbJX86k7cR+ymYh+XEgdtp33VoqujQrCNQbgrvA8DA1V2Ly1nDE/5n1LiaCshe8LYa+1oPKjF1OJToAVDKmhdug90j4YCU9r53JrMCLEn1CUR3HwyZfQIokTcBpMIQ8BBRROAcP037pBFGYrD2/OM8FfhYh67G0mmVjgoMb+P0zey92YJW5EoW+EfyB4J9sEyMc+BvfdmMgzVZ4azf7TZ/3eDGrgrPCESGnf7aDxhrSAb3+vWQzU6isw6CTpAoH/5tbBleidzcIM/jMKhvvs3HxFpJXskM2rzW4V0z8gPGpaHb5xfP+fiDunjaM1e0r0ICsH8AYMkamn1F+O/964nVvoglrD6t6DfNx1KXep6eZdaH/n4YlgyVDeXPF8b1R//Cv0fOpnTom1O3LBl/PPgG7SOv8BLDZ3Rjc3uw7OfCp1LfkhvkdtBd+T0DRVAfysSiJB5fqoVDYILEjoSUhCrY6GVQQlQa7eHwQQoqwx2sXhL9FUpyOD0mSMQO/Nb+RhFCHHRax9pMuThfGmkjFzB7vyA+10QQvlPcYZXo28hfe7E04rFHL5/0vUAVc9kgGphR3rirR4iNeeLm2P75Qp5uWPaM2exJCFWG3v11rvD72M+qgk2Lng3AsL2+1i+h5ffgrwp/l4zT6vbnsm5fhPTxyaAtAfPDJ1JsPl25QfKUaJdnoDcTPVKpdSMC9oUIU3vzRzOJsBLSQFOisrjSKO+Hqbh4vjXYkV6vxk1g1Vjo8i+Q+R8VpSAD5rG5CeAOQ+hFC+z+ufgQTeddSpAZwXi24KUETMQNxkra4KC/GdH1RxImvNAGGe7ksl0Q2mEctuVF8tnKrjVgWchuwl7ujOQgmOth2Mpkn5HaYD1H8RdM6/vVadhpB9DH7cI8JMB9oaoZmvrBBKk5XETGURA3D0FmwXX2+uOXSf+blMc/YazcptOXpO3bC9kSqmHqilvomOpbHpECw1DdAd0HnS0IInuKQEq6N5FaDRIOtURRt7t1OL7FYkoeaF4wgyfl6tYAT6PFLFLyMPBWM4jq1WDp8Pt7oElWwT3tteMurCvZMFFE8Y0VrlYTRLGRhTGr+BYV0AKxg39QvokwCbDrAW4uGsWKKwNTuReOKI7hkIU1iqf59+LfPK8jJrtgFEr4QZh4l26rzEw7oINGe151R2gueQvCunXN6qjUTC3QHB1ti6pas/XIzC7SJx/ABxcaAS8A+79sIKoC2UsKTLr2ycH3936FO+5Jjgu4Xu1kt2AHlGYdYgq9nUUHHyP3AWFKYDIT2KnbMxPe1ZkktwimVLT3bA4usRdOlZbXVxRjQ/qJbeA031rjVywnEqGfHPYSHfI4ABYyT4IzBg+oRqjN4vu5aE3z8aM3ukYU1wwNbCCIEILL1cRf7UFdzDnhW7jO3m+MehfTu2L8WhJr7/SUjLdI2n5e/4Ll0qj0H6kfYKBncSTjNqSqgNMmBa585lmK5JLYhDhbg+24fygXyreD+58hzm1rcmlV50/EzmxHpMOuXWMwucR7mDAob+WPWbCD79ZfOlf6oebiC5prhI6n9IlqMHBVK87IZeKAat7nMeBOoY8Kgcbmm7M5NsxYgkijXC5og6sRT+4I7UhQGTRcGY3vRcWzEFq57m+AJXfl4Y6i76tA/6nmQWPZVV6qTtfNSP0z3lgj2gqMmySl4S6veKclbYzAkF7OXA+/xnFZmiZ7XJoOSPXH2ip39q+uEeLG5ZqpYpwoSTbSJ5tZo+hx6ZSTTkq+l8VfRdPShOdOx6Qhxql2ZpM/ZMI3Q7kG9xibIeSdON1478+uWyAYz5/1Rgx3G5sZEkoGRxte8aq/Tjwmtm5visLEnQp19HNOsSSdcCj3rG6VJBZwC27Wl2XJVL81mSLFUIDsUzclrgrJDl99BL1cxw9py1qI4/jW5/RzCQeDsoQDYrv86tblWZDr/xYlqXdurxaqG7lCPQhN+y5zsjBgswXOeomZBmuuq3OmS6yJeTcS1PVr1xQKEsf9iM63kald+x7ULse6tpuNkcPIMiXMFdE2vViu/cRpc0u/nHD7JJFEKWyFTlkQjBiRUuAVGOQWzJNEv4tUuqfzpMh8kVYQfbT0AkI2eSvMBfKcnDOMsGrj0VoQLuCbGO6/LbNjHD5yKX5SIr3BOIKo7KEHkz36gpSpmrd31woPW7hZKjtaE5ylvj9Mw1wG6zrbHUWSyKBW5XTPvJB9qo12Eq9hQiKIig3sb/6AFQYVT+aN3k3YYFqFFz7zyAJg54rVI4vMPjWzHjAYrKsTWPagv0JIxqvs0zezlLhZzUxyHfdVbCqyaMbk8lCCmBO7iaVJb23M3uQynAemptw/6nIKSCRfYrBt6eeQxnK8/ZKZZ3sf3F8CFgYu/sXzDRdfrZVcrqmpxaOdY9fm8e1n32Do4xgPv0Es/KNzRiNWzZc92r3GxqfGz3zN7OqcIzEYzfoMyIhW7GnGcyMwEgY0dSshfrZ6ySXmlxKK+vLVBQd4d5+kR4/YeZ1yGdfUxbmHPEK4DiHPwo+r4Q9ScaGjbgUzEaiSJlhDC9SoMyIAjPXYtU/ozjrAV/7sArUWiKxZoKR/okVfrZG4jfqVgn3Eac2SA1V5+kkp1/HXg6ra0cqf+ey8deZ1K4Ugibcg3DT0DI4UBtkyECYggEKcmnWNoVzye2Vj6n6p0SrA5wEFUYvLnMZYbf3UhrGcMajfS/OlRa/+fhNjznRuVkjyS2jNa4YsP2ttukxjvRnsCv/shdtbZPokfYayA9tVyhdLiaMoDvZjPozJawuMQmtjdW0CeTnfYdYZSQVETTC6lgxwPiq4sBhBcSqEutR5O4Y92f4hv5tuHEJ4+xKh7tx+jT9CYXlC2hQ2ITJjSIFgF7bnNi+bDsrDMREQqDiH+nuLcJb06snE4BdzkU8BdaGVMz1lqxWdmmbdCwFP2zTan1ZFFqMpLO0kXnf6sGVLryaJ9YaTybpu+oyYUr2GugfayCvR39vr/4Ftk127XB+P8vRh6K4dYu3rEKLON1aKkHuOplcgNwZi6MZp0Q2ndDecEIEePegnfJe7jiKw4zia/SKvKcNQp5Zf8G6V65WUq2xXnNLi1p9U1EGNPg+Q4nR7qhvKJmxrd7jjWxTB52gelnnNacOFL+78cgpCZw0VQNFV9HESCDi7yjXfY7m2taQa2AAmbhULV2YlPyPmsP1mNbMRfxJCSoIp2I0N6pAi4d99jpUmQtduhcsffyMN4DOfBeQtJoRXByLFgWuYulaLkGQ8Ixp3dFEM/e7EDW9ji1RyTu7liGuTiVSji5c5exPn8yDm51a8vDfshbg9ptuJLkxUY168mAsnai1eZE7wIMTQJYIHmJ0MsCYtKCFFf7Q64HKVqmMhnVfGG3epK7UMQe/+e2S50+Jdb6lhKl0RTHD3u5T3waLPVJVcDlSTUvRDth0f4g3Cbo7txm98bwNsupC48NYNrNgKDFTz6Se//TFYkBcOnFEFFlc/F+BqU56j+5Yn2pODpUVqF+zt/iZolXqwztt0Ahc4lVXh5DeQjt/5UdOjQSW3kvnCE684bDrQIEKwa7yWRBryN4GezIAFdTeyVBhewt59ZsIg9vqy+xwtXh+2UlN/kTbpo0KdQwN+lS+aPeMzJ0QnvpTwDbh+daoI7Eed7rnf88zDESXC5onKHXVOzUpDIfMn0eOAQTNOaOXqHJM15loxhGXIFaJ8eBuZ/3qAX3Q5k2uy+Gx01MRlenIGbLkefk0iqSOnFoent+C8fkwKpJwe3Is99Hnf+oWm2CedcY/u2UrK2fydvhbfzw8iunwcV9EeP/diIdqhLpWWeqYpI1vt03wWkP+3BtUFVnvX8KxtggU5OCe1SmwoiyNA7fXD+WZuWVnFt6isc905oyriYGb7L8JjrV8XupdOKgxcwIXmVFeKXK4RFjRPiDahWDIQPloFGf9Yv8yvs8wS+k0SUZj+fiF4aeFEXYhROGUmE0NkR/achop4/yJSqD/uB7NStT8xnbqDyU3f9EpTzbBRgdyktUu/XFcadExVAq76mQRH58aCSzhnmrfOucmzQ+MbOuKPNqe4EAEtgQ2t1zwDBcPZzRoXOUMWBQfH23L65UWQMnUckmhW+P/6f2N1X2IWMbz2+Fv31LW57VCr6p4edg4GL2bWj2ZV9H2njbyZlT4LoMPa1B1jscGMgpAOKA5kzssmdcpc3bw6k4h209UGwb1keOrHKOUJOhik5P3Wwn8Jj3fC3evRQsHisJgo9U2Cllf2EYXua5eZa9UkJ0T+Urihq3AmWWL/kW4PhoEYAAAAY9u2bdt2PrZt27Zt27Zt27bdITrIwcjUlXeLe61oCgG/sxUiz40kFngOiYH0ewNIaNS8oTjCIfCuHuHhkVCW7yhZd44oje6WcupQsjqOcotUG8UHrq++DQlfU7fHh+wG5A5vLBgbAHWGHa5QHd/IH6suUs6U4zbCWk9fD7ga7CMXMNOb3ptACowyF7JJn/t+pudfZMsaZj/nq+c0/2patXMAAzcTk3m9n0ON1KGAnLLE+8AO1S/LVTEaqopoI0QWFr+CgxGQ9MQ/4RvAqRJKvG8lY12dKbLhWzYs6ig2q8bpzU+3m3N9VMwZFliMJhj6lSSuQ2OwWegl29tsOgLDxTe89eZXY1aVo+u/PsRUhfJtl7RdZeoekbMhczaxL9jSF15GYujX2G55CwXh4PwDZhv1+jBwzIShEczLojQyHKvVKisigV9ALhKwQiJ/97kgLsbQA5WueOimdhguO4o4TJ1dynG501XRAD0BUDCGV+id4yiFmyKuz4FHRv7ccvJ86oR62i9MfEeodLejhpAy/Bsz8sIHdITdMvR76ipANppDn1ZgylIAbDEv3/kdZ+qfuWYHaXhX/xavw7cqq/XHKKXM747AdnYSsUIv4cZaiKqm9AtFk/noFC775tQZLkGUHe+uf7sHLl664Cj35HVf4jBe2JbpzBU8hOMw3U+AmPeBlLkKqIjaaV0FIhTXNNeVo3ariR48mxO6jR21F+O50u8yELzg1Lv2MwBopuQmXqbKAAxeBUghZHeJUy+1y9/UOgI7FRbUvrmFc9hMz++eU7yAA4Tncxf8+wuBjx5hBeokK19QJzdp+plvG4KNdQUhPZJMQ8BofWdi7JbK6QUqi1ee77MPbacZi4AK6StwI1rzkwLGytGjC3IK2jVoFjwD7IrYqua/SVlOqbUsoz/s0KbjafqLYVGq6mK6P2IpktHPK+1rrYuWQzVay9Zj65oVSogERbcClWu1Vf6N/IhLxvxCEe2yTHaBFRPrzWNvQ1UzCm9AMN6js/tMogjw9VJUMUQTmLMWMd7V1mt5PwXusR+kwmtyNL6ga+F1NYqIUxjYwopq6Yf3XjdnriVtTCzwQr0wjyZ7SXR9WHK1cPLE8NnST7Nl2Vxn5nsiTCfAbEgLBTwu1QrJ7m4KDujZPz5eD2kqEVs6kdwFoYcqnS1UOPthjbEO3RE9Vue49YruVAHZCS7Uesq+bpyMh/IYpiajU7UxbmhJ8wD15bvF+zc30UGmqrttC6R4tjjM99Gagx22WHAIV34lDyQvMx1fPh8NSnfclW51Ah/cuEj8eRy7Lkw7txTDON9XAMGVn9OvKpbm52TxCeWlPyENVxVagLCu+eYVaOziY3b5MjXcBKOaVCCM9HXov+0rWA4BNEP/YzLf8xLktvMFvao2sDwf2p8oiPJux727l7NgxslreQPMfXZTH5Lq1+PcC1c2nEHf7NMbRYrtoxxdlEzCmQoZXtPpcdlg/ghrRj7uQ7r8gnvVlTedC6V3K6a3MXA5GjZm4GXyZ2rchghmSGrYZZB3fqlXgnV5Lz0LDn99/NxloID40PJwjSiOb4cSuJmlJbEmyi8O97RxWDXuyBugN2eP0bE0uQkf+nykapObzy4FguYNhGMYeos5feZZ80YJjwvCRJte31Qgn+y3DmjncVcSTN+eJwehp2o73IsOq433HsnP7zJnRfCNBWkRXCMf16KATQ5zX78K6plYSXptCwXDOMGEEL95PWryxF6OSpL/FRw7lPPgfe0I1coiMXuNhmdddCAbcMVf+nmuk2kOeNAixlSN/swq5PzRbgQ7ncACr+l8BVSS7FuuNCeAMEDLge2vA2OCYrL5mwSJPfCKXpD9+Dkx6154CL31wcKpoaK4CylLbdCnUfn4VMwIpCestLJKjidazI4weYki9AWw4dHkMFBC75IItfMefOQP8Ekgow6w+OSeUtV1snrDxpQgiVK9Y1AlUSv5BihMuKyALfgPxJ0Q/pJnSn0pNKRefue0KD/sTnCLWOP4bNK73lhIGPBsZKqlW9pWQeqpToJ967z4SFrGOGA71mFDsGVHxBmq+2f/MmcKA87v9rHaQYSwC60rdgbmtTae9F/kHRL+DTvF3+zFJUrcTEDMXR8IPKsIXgRXfb3+i905NOpZBBZng8+/LmqwjDEAVaEkdc/ND2532JC1fc5Lc/k6mJatnbtmAKKHoUYcZArtX0C/hMuqF9yndQoGpHZaYApUgHRB+jeoDQ+GEzkoVyCCDw6Ca1FTloRNh+KTQKVyyEJh7mQd/jct3xlQIBDy/s7eOMHQ5z8+UMR1m69jbizlUd3hlYeKsQZrgnjq+OmfPco/i6IYJLOG5E1klh+CqTi3T8C53OybeGEEX8GFawG1KwPUQnXRY4Ol+PvTfDiolxBHnXnSuW/QLvEzMcvhLmpMSi2FK8GBQaT7GFdZt+TFCKq45IS3yaRR5EPHJOmwEbv+eujBR1S7wCLECJyKFqQpIHJPMknQLnnSKqtF6R07xqMmlVTKYoUeDq6ovGUe64XlxD5OulVQyhSDnRMRZiXriweUPuEsChi91jU1q7tFgtlX2Q5SDT7tf3Uxk5yOw4VSRQnxBm1EvYskWqkzlRkmBDv2BnkigwbdApAxv7YoccgyK/67w6n/wltb+EqDgmFvQkL11wzxv3HNF8K3R5X5z4jSmwCoAa61DlRmYpXIpNNeJp5FmkAhXrJlujd193IQtsMh0BQzU2jZtx0cvibw38l35QKtPs0amLlzA0bD5jdJP/jE+365CpCmjsH2a5VKfWUiQuzSxZnbqqMXCX9NV0/RP0Cu9V+qWiv0lHMmmmf2lqIxvR82UixEuGyQUCu9fB8o5RLQVQI1rieILP7tAt6zElYhzO8krab4mfJUvmcFjJR7ZCru5jAlCUBsI7H1JA2usfqu6BszAalmV379G6+hKFjm3jee1xd0wbSQbxRr1b7RBGVd/2QoidPed46iI3t5wMoTzJ2VGL6zwtYDytdg3h96/Dy25Ngh4m8pOJXxeyvAWrnUGBVpjFkToNJLrbA337Clu3JbyYTfH/yetiKlH8MJpbr8fSWYQAqh0SHVOq4X45iNdYLCsbd3AqeDIenDlBD3Y2sjDr+j7K1FjrFdkslZ25ZUEr7wYKOAXjma48U8J3Zg4K4v8XNswgiqlmQmBy4SgN+JOFHTMnDi0FdptNkMrxIf7vYsgx0HVhTzsTzqlc7+QFtWAZfOSN2etG16lYqsl1YjH1xfo2zJVNY8O4QrM/GLxnoHPgxZaSoxC1VxF5rKkGFS7ZObCcajVS2XLMLAAP7t1BFRB5cazZcSEXMKpyfOLRWF93Ax9warXvjTPdlhrp2MOi+/MbJYuDzyOMu5sepfV/x0zdKNMQnxfhoYiLXOgGlFtBvWMrr4IKlXM3BV7LkCFl1BJuk1a3fzrULVEBbB1YdvycmOMQUfLWTzFq2ahCmk3eDzVDx4/jfulA3j7eEVxKzcoYZaAn/tafybZMRsyoC0bFUy2sf/oeFjxQehWNulZ7AlmhOzQrVik6kw2xqwBKij+P5412NxlwGaXKe34KyUIXZhBZ0qdxGxYrZafJxdSG8YR9bUhd95uCd7iGMPEAoQlxwylyrjlN713gH9Zh9iWvi7RWObcWl+JNh2ZXSacr4Qi45QatoZOZzuXe90Q1yxg/oMIbFGCrJvxcscyR2F0M1D5nkJItDcWN1DmWh/Kj1sHwo+EsrdAokseuL0VHIohi2+1a9MbzV7AOQrst+xQxeQ9tX7rqOGVDVEBeAkNSvrZOzAlHDx0sa/DQGEafpmfICpuo8ETsJUBSo/yBKG01Y/GNCXSfuPFEgeqK2l7Y634TI08vIBtbgV5RjMVIVFtqK/Jh6c+/IGD14xWg8i+bRebx96HHEbeQti3tgKDQq+GJW2wGeofu1F889z5ve5vLfX/6BFZebMK+Z3GG3WXjLkesx8UfVPawUGMU9oqCHWsSN7meZM5EYdyfjjV6ktLEdoCuTV/e54Z88i5bYHuJw1ByC+LBrDuDlJn7/IDsmTP76Q3FZIGiUnAYRUjl/Nscknjeex2GoBIWL9XcHV9F6WgyaNOiZG6b2Kz14oA1dF5rWGa4P8drD4Isdb24QdWWI5pOfCC6/yB/VoUaKwnIzwjfyr1k1ZAJ76n7mIZXQRwTcEVznK3kEzFE55bXn8imb01iDEEK2zGXvLQL6b7Bt8VjEIPdazx61iHgL4EXID5i+Uoh3dmhGxYumYZT4ICU/S5E/iq5CxMW7hJy3dL2G/BrrDniXVMZA3HiiX2NsRk2+kK4FnMnrrXF0NWMjlIR4YO97H2jzUWz554FZQB/1dYdXBgh+EvlwBmsSpTud+zOg/0pYn5T00bWKax160L+N+2cPvDbMVsX3PgUHGH4W9gkVNRX0N2XC+ADvLHsMBbRHLu1cHxKTvhB29q0IjGAXjLvxPpsMJRgruPShcElsnbBDgl8L3gTZaEN7pkFFElRxeZQjlWhXmkauhGqUDKb1BOFYCzYEipJXRPLocExHDrGkLZ/CSaACSlhMbpe/JVsKe7OYK+Zx+Qp934wCoHGnWvOKg4q1VeV8t6ak0ZNzDlQPXTVnFblPy0UnPiFl8QTVwJyCjOBrw0PL2Ip9fUMPA1qcBWanqrJ4zUvODXyrAA8xd/Z2Jgf1v6utE8kHF4S2PA+1/aK8RZjlGUnV3NgqZ+iKgatqbHuZgyhshQvCLL9YyOxqDdgM2qDgwPvk3r8POYjzq3qJTvgIuEQuaNRG7RPz5ELLrUm2VfNwH5VmzLrEfKKi7HR4IvsU9JE5nClRsXZH2f1gXPJlmkIIjkgUii8sWq2J//REJtoXzv7+hlHDLYj/pmWWfg//8l3cnh0i/zS+Enb1GiHNVwnPKmtVhSWOmjhGghXaNdgu+7hjbB9ZQ0YvfDBK/xA3WaWi7i/gaZLtrBZ07ABrL05ua21JZ0YoJ65Wdp2uAhR9xqG94jQMypo7mah2S7XmEZuANola/nRs6SOthyQZsSNWI06ckHvrUEjQ1zqMCNPzq2Id1CZ2Mr1E1CsNOZT0AcJwCq91vXVcOsoUxWyby8VrCRykjva1csf37pI+SSfZNbbZFf9T2X49fluZajuXkDOmlHn8MITcFLF2iO5iTD311rrUkszMqGdQ1jFENOfr3HK9JBwInq6zVzxMOzTnsGgnDDjpP6jPJxDIAzjhyf+4LiBHzSkdnao4u1XPQOpAK1IFefQohl9u4ccTv8MTCr9AZNr3Hk/ZQ3NbED8IOgoKWYlLJJq2H1IVRpygliSqg1Falu8dBIZ2ICpUgXfw0P4d0XEvkt4qCrcrkyZi8oPTpUJ38mZetmo/k3qcLtCz7xCrfyBiXy0uoB4kA9xgX/jw99bHZkM9DaXicU7R6KR2C7YO1Jh30SEGoNT4aM7OD5kVRx+JwSLUcP/y8OByQz6PZOnKKrrbJMkQN1FHMp/DajiQWIWdqomzwuL/699n4EfDlu5YLcZg/FZYEbPLffw1ysZvuHgEc6r663ZrFew8KIuDRrzMHNI2fZWse/HtsnmyU2Z1kVtc4Dbwg7k8kf6kPH9b1crXHEkVmfBwdq1rDomjmTmBEWvfL7K0hGpAYWScVi5Tm7QFke6bspHuOO4bDEn/uyibF7YyC+12VPJb6bWnA8ZFj073uJByP8ED4ZGAh/P4WwEiK0muC9QH5Vrjj+RIcI3hwdR+BxfelzCfGhgtSerQ21VuojgGfZ/fHXddGVLjkKD4ml5i9Ai8F6+H5HrqKvKK+G+Ui0fWO/GM5s8wWMdjPWPbSqhr8l0jX+CfhxKX+XmfNzUlFWp1NaQ62cOp1/EK9JYTyo+WcHYTstuwHi79/E5b4l7VhNb3y5e4D7oBKbNZPR1XPhNIrLBAKyurKuDscmpYXfKWLzcXbHWbs4MbozlrRmM8cigQUW5cnd+6v7kK13Z43crblx3gF/YpSZjgvRiipMiPXud+LhSOxuur0WWb7/jZURr7u+r4n/VEb39gwKvOIGlJUR1hQ0V9J7gERaOiF5Y4eWRl1hKmXENHTVRZuWMnbCSmNXk5OluK33BWtNMaBmXUJwLv4Cxt56rBK1zEmtjHo1yCQhbvb2APwDXCCM46lrLeYi6yufEVaRE8ccBIo0eRsxVjA+0a3MMWVh/pdWNj0pAAsChOjG8ORGKinb890bbBBiqgdMYE9TFzjaEudHCDr7v23o+s28LQZJwHqFzn8m3WBm+YINVcg1Q9ZXgpgwhvdW9G6KAvLjKqt8pZSSbWPCZb9zeQOy8AVjMyYMXiJsBka1DZ1yaE+PUdP5+xbgnZ0YkvlmnoiO54spRQ1teVoDgs6WaLMed4bccr00CT8mE4g6jFGEqBag5H/EcOF9d1iA9z6mz0r6dC8fEMuhtEbeLXBNEpC9y0Q4uLi+G3T3pIwR7gKcTiZs+SJlUAYIrDkEXiCi6q7+zBb18+VWOOZxSzVS8k6+Em/ZIWSQ8Cfa8zwpPJ7hAIymRUPXQB0Nev1Y09GOFu0rhCtC/PjfMezlFrW1plk+oqFnpATWga2qsE+AOy7XGv43KzAxnx2g1RTxjZgc1ZVn8j2qRqktkl4PFfBOyBt1HjaOm3lT23nGIQp7fVzkmuknckxEQoBI7YRyxf4dMptj9xCDXxL3k5L9BarQoQHhiaRR7pt2oN5AHsxvs2s5OQfHwQNx5HTs3zDEdQVvYeT5aiiy6kDw1VUfuLA+nGFDnZTKPI+3eYNFfVVk+UGwMSLiWWrw+6R9Nvt06fHcVtOm+5earWOXfYXJl1AoAdZ8qlS+SGrcCqljqelylCJkpeRNwleDbEBYZ5zXm1Pdm+LkYvoDlKAUCdKsUAzLv8e6dNjtOUsRAjjfopx5JcHaE7m1Ea0eyc2S+qbbYcXTEMDN6d9fIU9FmJxjTXymPnk9vxYE44SUgAeg3kecF/IOwLTulx966emmSnundnlcRm1BTFhc4LuE3uahr+l3+Vd7HIVPPporjBCd5cAyrKvgbdepiAix+Fh5vcpBrcy3DsvAfDYXpEXRZjm5hEhJX3nQcKeiHoTh48DqjJebPQoAwKQ04Iqtx4QGkjf016u8nQwdjYU/IvgVoU5NNFT1IfVN9GK6ZHvRORR6PzjJ8VJraroF4GNtYjEkxsI/qrwPE4bFobskSOTv0GE7eNUGgPsOrxlkF7g1ear7OvEbArnK0bPZT+tSHciuTcZ3WaQ5SXSBEOzgelkjHBhzEUH0W+clvp3vbidl/HYb2bxuDEqZC8GV9n6bX7Jm79sncRW8i07909k2oB/4Np+eid0fMn7FFU5L/G8uX4bTPUeHNLV9VwPWi6a28pIW3KsSMA6aGyMJybrR4ks+HaCRAkas7l3SFrZafQU2QJ1GXkkIdsibBwXc7qVVikmRna1Uca4dvScvhJVs4TZIIwV2odwzrqqjvEdGninpW6dAL0bOeUXwzKsPZ1BU8IfPnG/J0Ax0StU/Vu/wtt44sMpyDyADIXVKAGOZlEcN8NULLU4q+ntW3/bFByhU0mPvJxr8Smoz0JjMXvPo/SUGsz42woudNXghe3cWH1bdqa36vLCE7FfR8z88F/B/JImnX5XFckhV7ZRuFa1xTEevj4nyCJJApGqifbyvHRDtDMxb/Ol9O4B9wha3ppyWvRTd30ZWaLvLyInAzxVx6jrxMB+aqIcnsNd98uT/fL7LmX6vqDUC1nSGuBqcJB2tdwwGpmn0OmMmZAC1DdY5oyjTd0/2i8nC+6ypLNBzoM0fkvIEt1Ecg5q7IT97JyIpciUTQJkN0/4gMdpvYrHc1y0gWTTUsAWC8YkHeDDytX2eT9M3rTOmcFc5Jk5DgVxtGjHikHugwg3SE7p4ViYDKkIq1B4azegV0xQ3Zf7WtdXkEU3sbevY7m9nI1jyRMYUn1wwTB1JKorvM4E9bgWU5akeaYvGQEHwym777EelXL3Pxahnhd3cNPkWQw0bmQ0wQVcfWoURzJUUt7ue/IKEsrCt6NMl4GOGpB5o4NeGe5NAw99zntLoSP4mR7qqx742v4PZy23n4U/PsLf8fjIY98Oe3FaYIFb/e2SZyX8iWEYny6anF+o9mhIGAMNuB/sIiLRtPjJ5vsn0GxuTYW4oRTbyOc2bhiIKZNqXqF0SI0LfzGM3kWnlmkJVZM9cuhYyIkCioqTy8QjcdN9AlRGHJ31YyLE30kfykIe3CQX8JeOXxUG6Bm56Ng1W9bTqIb6KD2lnzx2PCVUJFeQICE0EHym9Y/OpKGqjwPUvOikHLuyRFXHmvIsxTuzgjd4oYcqvAiEV2j4u5wj/tZGOjSXCAvmXn9MIhujkIyeUbh2rcsX3u1hPIzfgzOBIjFLk9rL5laa7VripH0PfTESKl1LYxs3wx7NWlEDxt22ZdjVLroFhQNcEsuhrIjHAldF4Y6qlwYwfEHdAjwwwNuO30fr17XBZ2psBbHXcBkwniVGvbXnrdWbx6gy2VKhGwQSOnbC72kC5rhIt8zZ9sujb78uOAEB3MPxE/JkrLW3iPk3stqkKvvO4ATq+mSRbZikIEwgrrY8rK8VGaL6NKUSDNHVte6Cv4yEY4jLr3PQ0CHdTolrLqWan6LTtEC/NJRZOUtQflmO65UJ89on5ZFhxOfQ7LzCIBpUUTeJ/hkemYmL2vjmjwW76Tb8YRqQ5OaEfArk1c5gSgQsytrA/H8iEfrAfPrAzJkwegU7NN6jQXQNC/EXP7fsgCDc2mC05x0JLz7oYNkgtU+Cr+3qkSd+n7FCFCVsP+hbrMu74GjZ3Ai1XqdMcRei0/nf3Prv+htRwtj67R+Qup4ywcWDJv86wKZNlwULrSjYo+aIl7j/qhGNvIm72jyXlM7+tPvzBPtsE8xWtBLy9eRM1pCBED9H+ZGl4BNWdv0j3JOGBA7QVrLGZhumpfBB6tSxXvezkHKkJu1X5ZIBKp1RbnWAPWodlrafKAeEWtcJEvVJx9gJjoPkD5Y32VLiRAa5HyCf7VuHvutPxxCciL1nc/0vRFwqpDBjhITqjEZMiC3SJ1QNv4/aD8m5cMPT5l4x7oBlZkqpapTno4Qi69kvTetua6KIPlGEqo54a7jgKaN+WZC33VYUnd8V7gctmJrUf9q2VtZhZXOYxu1foDS4xqkA75JSEwEG012IbLWW102pRg2eMXeXC5vp2zMHYD+uzkFaB0DPVUmnQK+cwZeCGBgP0Ywl8V/ozQeFplLcpaGJgIhuBGdnMTm1zR3OBZeEdCa8csCfJ5Eu2/Pk2thsRIaKJmM9e+fc7mU01jdHHLtZdPpqIE6mtTuBDoG5yvwQ7MeO08F+szKjDunH/y28UOT5Wj9pZ5+6ge1EsJ+0JLqSb/hWig8hgMS/fDJldjEKZMsISfl3eEQCVQT6aLWhuLnveCRcZjugf0Kx/Pj+MqHMSSAIks3tLuRboWEbB5w+23FjbvqOLTXdWBzRIsoyz8lQu0uWXGUN5rhMbvQEyxkqvdbGINIJN913BgbLoPAypZkEfmmYbh09t7nNW4dzjvJ+CTpRoIc57nb234h2JDjKYPaEVPGoL6Z4oUYVIpNhdjWHkEjpa+9aBgf1+/ZiAmUP9kWO4quIiwTZS5k7EignbdvaE08S2ZWyTnXO5S+SfRi79ctW9SZLWHSzpfZhlhjJr3zTnaebeNEaGYrT/JtbjKGcVADSGxmxBzfr3vD4p707tWF6t7783PuJCnj9SBTSOTOqwcpR67832nPQmTVcFlT5Moq9l122vIKRexDcIXuUasxNSadPonbc0uhr0G0zHNY7eaGL9ygzFner8iHkN41ZOKccYQAby8XOs/AutQwZ5UDGFyLBq+KjxUEDqMbz+febLrePzvzQv8nx6VHW5BGOQXSnSJy4PqWxUINXV6eseaD4ZfxvkORPIdwyE1F2TsE332rK0oXGeCzQLvXlm4HZM1sZPm55bPtYDQa7T3dycRQeqd6U18j6tLMq9/VZEnuOWLZWlXhICUX5vJRiCWrCVTAw+MJ0AnxdU5IHiXsW+e+dG+DLyRJaDJA1s61D4w3SYDRnEURT0CK4qpTqYy5wumDgIJr9G8RjOW2Mf7ASd3YOhrDoHDB4GbToakJnpu4W8UUa+dHbgGd3JciDlgCVEdJjQ+LAetH2Z0718yVGyshbtZnyJ86SxVzRu002LyZG4w1efSBIKup5EYHISNkHsn+mg/yQrBVuJTtCaxGIqdvMm1VSJxVQj12SX8HFIZoA/ZhGd06TvQrJRQYpM+AeseWL+bhUxzbBoqMkSia3M4hzk5+9H/jKSj9gvQT3IlJLcUyY+AI3HU4qz/iBEzN9qus0CT6E1nFKila/hdi4ZtZ0gPgKHq8441xQaUfbCrx2Ucdd2+9cs5BiErN4S7hWZPBlgBLbt5rJdj795DviM5/u4SCS7JYljBf3SPGuiSAZMZTuSoJ47IXKGHYb9KCbsB2h1NQ7oHs8LpcMLG279Gqh4aq9wL0mg8FGBczoY0sN2OKLs1PpaT+C4l23kYbrG5V+Y798YybYlMlf+CSSAO5sc769he6nm81Tu0BZuvGJM19C4VtSENA0zH97K0qRttKFbC5lZ8IzLw714J68g6n8zBX3NY2BqfWZDZSBG1PT/AG0UgkrxIUsrrBCAvlP99wekYPQ3PustNxSl9VNhfxCm8sRQEK5TT89O/IJl+hr7I8qw6mHadnwBlkoTM5XgdEa7+YXrXFLAAMY8SOCALzw921ei4q71TUiL9uWMHEpLmn/1gLo4btkiy15Tb5SGnR+UYtXEWDYlsiXF9CD9zAZtGYf3RXbuh4LjkRawvhvXZE//QtOtoKsgnykHTrwQEnlU9taRYV87oBG11t+uxrSEuKeNARIl+n4o/0vDk2xD7zZ0b3rQ9HliKL89WgF1jko5KMdB4dJ1zznbx2QBZVb5yAMGQctXRYFg3/Rh7JyowPVfFWhO9fKV+8oq8k3UWE6aBBDISAzs2yEoJ97tGPdrMVdcaya9FXlnNiKPDqmDUL2+w44Szx6R6TqnDDBxsz9bhHZ0vcQAFzLg2yt7UWhH2SMJbkvr+v8qMZ1DeEYnRi4jGSsui6QTtlBMQVGp+vXc1MtbIUEG7htaressttbty2sgZe5Xr7ey0BG7zTBWSVe1hrOgAnZ+V65gh77HRSiU/IttYYEHmwi9FCReFGv3NAlB1RL8Qi7tL1kfoggzebPDsD8H5lFGOu4iL3ziEp9IkBfnZf7LgDkT0+Z5O2hsFSYBVUKPu8XUX12rpKSfB9rPnWe0ZRyVxczgJqm+f52cDx3BcOtZOFmVA8mlyMkrMJSDnsOsxy/iFdbgt/lG85jdh3XM3hGpB9zijw779sW9FS3NgEje04tWxIyYh7C4aLjSOn5pUvVD1eV18S+Be/2TG0rGJY8GvwYR4Z5lXxvlcU/aTKU7nceDTi2O3x29/sXjcysnWTyHzfeN1WIgqkswUWpInhSwQxQ+5r02/ao2znXSvtPUWvxUCbKBuatSydKwudkpsZZGTKicBbdtikNu7mWxgvt2WkHnzEGk4niVcNYIvZwUCN+W961St6aw9Msf1vEFmhsz+Zm3kgPYFx3h4t34YvVYKeYypwS3AsPQ+vg9L6uarAdO7GbmEOgkctnsqZypohzHKxulS1UfZsDE+XFiP0Bvc8DyjNfS8Kry3NxUDm6LamVwQMGY5nSf6wqqCKZekaWLLiS5InhOuso7Yplz6jN1IENihvkmLkXODyAv/tPP/pRW5bqlHe1tEuB8pOFDSuxhR3O6xqN21k46Qd9cOZCYgnYTQzsu2XHnYSCyZ6kV2js39SNg5XrHX9hJqGqbKfT66GtgFKfHkfAjoO9VnpX0RDfWwQ70f7vvKl7BPUM2fpYwbghTQeVUIpKfHq4xNGx0m9ITbYo2QbaIvxed/wLliyuZR2dQb1hMocB/XVoq3yttrMaXt+f02UC0yynxrJ8iVnch3S18WE4Kg9tGg2c/yTqGXQvnb6EfxvoeEvmhTIWSWgZ4URJi+BOWCsxi7k/Nue2K2HOGYjeQlouSU59jRyowVeAIrPtMxYqKh4TaYMbILnhJIbmhznQlolGErP632HpeTwFP/Yti7WqKQX5Hsi3t7KlHe0OQ2Dfwz8VD8kEy6t8LUpZGRsu+GEQ2dlkhZj3/04HVJsFA8N3w7X7VZcoq6CRPPpaV9fQy03myrG3DrlNDLSfRkk5xpruXLLNZwtUi0mn4oMg4O8uLZ6g8+GkIDF3Xkz8tQ6lmcfoIkh3T2xysw+AUsEV35vw7vq/1dQ08ZDiPb7NmoMf5uvaCL/v7o0nGica9ZccXjDbTqdlxITLb5xyEPa+veRRJODjiOcSWXy/aV5HNrxVLUZGt4AyT9TaGgMHOvvPw0qouZvRfdhm0beYHV+Rx3/joQIZIK9xQRYsggvzw6YtHzHI+wZKTuZ3oVm3PCGw11JMYYYmwoHra/XutV/RApyuTZ8gX1BfUEq1Itz1JIznkCdaY/HkL59hcuyt4/JvnV+vwaZ3lbclraI3dbpILd9IjMjIyLfpb9C/NAD25bHxSS2X1I8KZM7+YO2RI17egp5knpS9xwY7vm3Mu0vdlfj4PA0SNk0b1csLi/kuT5cVUzYiP4E0/t7m8awRCzF86CpsADytdoYCYyutCxIrQyeToSmhFgTfl0x5VRGwspmzrJGCd/yYv18MOP3VsCremb/DRe30bBCcoKlxNbjNlvZ82GMUqwWXmdDdLaAIqcW8VPFE1LyRY4fnayP/2qbNR5xZZxDxkRMk42l699rKKtmTmytwhwr/HEqnenWy95JJnSRjf8QBT9ShbEyxQQAlbgKsUklctQVxqLMm9SGtxAyTlDPdIWsTW9Tlu7+ub1G8qU7ke+CH6nPhO6/thyzwE0hUHiffS2YUQ26AHQpRASLoRuBYvpBhiVrelOD3lSRLcqYWa97n4oZiiV3DJcdxepjEuN9R+URp7uEuA8RXIUoi7SOG/gE6dk4t3yKqDjORcK/gIufl0433AEgCLCHJXCeeiRPve9p4PzHw88Tuz0nfQoLmoet/5r2F2LG6Bn6f5S64AxIg/vhWjZTQQHAwDojF2psbW9DRsOwhMchGXWsQ/Yo6nJzzR8Qt0e1P7ZpUK4fMcUvUW1rzyufOF8V/mrKSjy2hlqDqi6vcbe3G2CBBaT4vZaOjNx3u1AASM9gHLFwmnO3/RDfJkKV5pIeVRMSzT79irY5qcggKSx9AoMQ2JVSyfCI9TJ+OsNhdnxQlsiF7Im9GmSx/rjZjDeOzwi+tW5O4UwUE6NfLptz/Ht2VvrxE8f9LcQuUe2dNLhYowRzX9x6x62S2jStt+okmZ1Q4lQ3r4WEmWxCx18S3k5fWscPIfliVJT+4G8jvEg0a+Y3yvdP+DpmtGFOmf59D/Jlirr2Jr+B81LZe8ngpxTzgrVmtSthpvJOD1aA6TKNpMvp4gmGWJEfKYn08GW1veSUZHhR/0GFkarc4AiupNRIHOdxLrNTLdfvVGlXwaFcDupmukWedN/gRaD03TBkPTA+QHTOv0igdogkycwnABfrW9JdykrwR4QU2lgRZaEqSmyX6TeLoOKsiJD4dHlcHWbuz31aYB5CyVe7qgkNMZoJqbWA1E/kR0s2R4J+dtbsiNF2MMwuS9+eDICwFsu/gI7IjV1BL5En7iKSfqxFfCnmTlh+rHeOeq7lVfULtlv5WrKFnlkf8ESU3qAkuCZvIO3coMDbVU5iHRl+GqgIIpAzDTSM5K44nbZZOANXzxL5PxvvEk0XAAqPYmEXpfC1WD9zCBgdrQpNfgbXbJXJNb51A6FyvFSsSQI4PxSPQsrd9nKNmbZo8Wkm/iLqVZIi5bJR5jn1BzNlexuVCVi63BwP0jRWlk2Uo0pM0wbQUeg6mtd68vPbNvZvD6jnQ27rRz4CoTXJpA+aBNh6ogNvBRq/ZVw5J2QCm1ngH4yH0rLEva9hK+aYAX0Hx0ea18Waxt4lkzcypHNzgoKVLunYKRfcrmTmT/nqOxvuKCSQ4NuQ0iLMNvWKYAL37491rKenk2xa8KgswxyXGxcq3fGRaOJZfZ8rt2gySwBdElyMKCFPmf1orqKpVvUlNjo7VLiXN/zu4GTOWbPvQ7eueSfiHmEGaEKG/TX2Jvz6Hu9rpBPc4IN8F3PF+nLgWfGfs6WquDjX/MkS/1zictsfzklfOdNvJXC1zBHRM3zB68Qcm1TGh2C75OdY9Qedpx1DZnEt4WILgoWYDMZsSwSKbeVI/8MvXNjxFuCsjwg0adU1tBfQMT232bRoyELy1/w8HS8tfwzfA71L3W+4gFV0grLhP4HRB1Wdk2w7YEVXuJgyMnUzFXihodOTjOR4RmFj18OFGAPPvusPdsYCWYJV9zYapI67gzXLNC4eZWzL0gWiHsjHEVbJNG/GxI3gLJaFSUI+ersdBEeQ2+UJgQPNrJsDkZ3lV7/GoH1MVfi6k07Np9jRkJ2u1xbmvJvaW/tWYWGfB0g8OCBkOCuziuRdtrKomT2UmpbnxE64f/HFm70cib1aniXQ+nbSltBiyqJ5RNZJoo0VYIgSPEP1jWcPjlpJgab4HNdrvpJWXy9C3Jv7V/8Js+5qei+qqfhOLPyhQksIgSFg+RZ+n2NLOjcIaWE40Nl3AI3a9zJ+KAJUSX85hBMF4TDDoWTIHzJTMphsyEpMTIgVxsROaVXeDd1kOmyGPsri7eUK1eJjID47XqXFFPSlMXw7XclL1EvEUR15symzyMs3ToCr18uOtCBEZAldIoDjgw9RLxVxOftX6isli8Lj0XSBtPTeR7FKrwUNjmB1/Gk78dszGqFKTRVzhxTJbjgQ8L1P/qLaWEXqyc64EGU1nIF/wSMW9OZbDRZjzo1n65mbBOJ0TwwVcqxjB8zsbMyZVZAM57fBMYrC2tzQpxlXCybTFES5O9SPk4DlFQrHB3xzr3R764hDB+BYQl5dFed+UIFxzr9fjbTk3MLzqsFym1pLpMELxB9KEfxn55graykfcSyKPNBn9+nEPSMv9iK3NFmZDqbLfs8wQulTrbYMaeskLnxptfyS9mumgv5H1MyRlxXVgaD0IDXBj5gnHdrVocI1r+nR53QLC+Ag6dQJm/dmE1wMEbaPJ5ZvJ7Ii1u5Zdglig7zMWDa/G7Kbu3SM2hZK4kuaB+HTW4p9XmGJSvUNWSuJR9ZYtfYfNXEJSt2ulinhjYSLvUajmZ7SDlzMmCA9nkHpRVvciYJkDUCHHWJE4ALOYh/2uS/gOELLtoAe15eTixvCv4QxLdQLrd+x+z0KL1o9J8kGgKC05obOQhXjHFpeyGkDc1J7qV74PxSY6uOJLKq8/gT9KgzG9UL1TLmdFAee9858QW0vWe35t8jaHfodKcgIQ3/HocTQoduf1Kr4MzyW44dl1+wXL31waIDp24cebRuChhBrEU4gkqM+Fs7wYBa7WUAcPp+XwP96UGcnBQp7aEgrkK1bwacylzhstBX3GO37Pww4J3Q8QKN+aJGfes1l/NAjxk/NoK6vKk4SNT4yvBUZcNHcpk5O5xD/Gbc1q085+QnEjUtRqxEwlW1dxw0Mz0Jdnsa+ok0fuIDAtvIlL4vA894WDJQIGMnrPptsAcGA7vfJNnK7mo2ZmGzoqvjvX97fTS6I3E+g5RT3Rd83VChSdTg6B35FtOW5kCiwVfv8ukwZe2rToCoLq2sGIXfgCE/Se/vkNMzFTQJky3TFNDNIpa41/2ZIBwcgjvpgKAalkd17vFKtqbsGVklcJ6BlJogJg5cQHLKIMz2MEU0GLC8vTlun8tPcJrROKeuPqwr1FtaIqg+5/rB+qfITsD/kz+SoZ7S4RUddCrQZ77FxkXA8lyPeGD/BRm9xrTE8HEJI2Ajd2KpbY1lqUs7tX6jAtekLDcaGPOaa4lZEAYQqZs/hXN5rcNQUWuVfcR9gAnb/yKVsVqhRMYKJ4IXUIv3GHpH4h9xg6C/6ZQBFFZ6KlUPjUwADmKmCU6+Rc1UDMDi6JTHu5xzIUD/UXw6HZLI33MIdSGuxnGEEv1U8zv1DIgnRXBEDTn2dlgewZb4WQS9zOXyHdYIvbgAvSiXVnyLoOIHAeM8txgKkcaz9zUyVfHjhNRn78hc92CAdTQadFvo/uWo5zg0rbcajMR/uZRb10J7RyJkJy5i7q0jo1yKXAZ2M4Z5kRVaGDNVRz1crwdy419dRFzlWmSdAhF2MxC1TASt5i+x5IkIOhgHmUVXPaYstrTAATs24U5xIKa/3XQlEDrmx/Bw7/PN+OlnlNK3kQqjbrzf18bcu+pFX83uC7c4V7ZDa5liN2hCjzkXmQtiQSJ6HEgeKR0Vba+Y+P3Yy9wGC8Tb7WZctp6AHwyuUTZDshdhKssI251M+ndXRYhlNp5ATBdVqUM+HTpYi4mp/PUFX09ID0StYEqmbfduX4vAVyKAzyip/nl1SI51gGgVrmAVlH9EniguFaw+nF0llN/WPl2oos7UZqC1HIIDnq2NAYFaDiai8/j/iAbIZVhBSHDpW6KfDJO4kBHaLaW6wMjfN04xF9gEaZ90o0F/EEGW1ELVBxXo5o6sFTQgYLbj2woKlWmtRV0Hk5xDC0KJkUpWNqCa+XzCXzYr7zGyqUnpikkcbpbLKOYS3L/Ap9ZqJVZ3X83bjMBR2UuhuMlVat52en2G5cN+PK3QB4BkzAZgmB4vPMrqDm4gJ9CTimG7IrOECLIw2qOjqCSPk7To+ZB7vozFWFLhLftYsdVUriiMxlipgk4K4ceYCnbVQa5iTMT4pNIhc6PeYY08FnuyWU8VPMzAZxejGTrA2CmwAIiMLpSVUrmgsJYLwq2SCuVnX49vFuWbgqY44PIydRruEJLT4xJEgMT1RB56XHqYYIRGhwxg9DS+VnIOwUx0lJT7i2fs19+hJAYlooXFu6BSRd1UZ9STyIyRl0ky5E82eXaUqRhXfWoG2Bu+9Qlzjn+iYK10pQ0ymoZEQmYrBOtVkVsTobSNuoRYuIZyhG4rpgBmjuo/6AzZcMMf0CgHgagd9/NVSX6X1gUnqE0Obq3WdXrrizJ+WW4a97sTnadWXV4VbwAYdG2D9Vcj1n8su4q1rSrZ8jo7UdqNQq4Wjp+a7w75iiUqDiEQlQcByo4aBU9XcRdYxsTveH8TibK2diHr/IIKhR9sOwCcuVfd+n4IQgL1eBjZDN4KQ7dgY6hUmLcM6mnDfzUgMykNA8HstEkavqioYFVjn2TuQq0DT3NmTPiiE58RwMHXlCfeNHv+I78DqLKKlj+e34x8B+nTwqf6bb+x+UmPI6kG70VQV6AueXw0vKEUAE/E6kmkYdZIrwsW3XWTKVgSkg4c/0otYiq+6yyMddiW7INwDB52EEV0hwWxhHJf8aeKQnVmOMEZFsyxUxe0cjDCNuBkvMvEIK9XDmBJLDlr5dWYtl3Duk6w06Xc6Q0q98xDjLB2GuFL9KXXoTkrk+36c/w0OlqBmn4yN0E7d6X9O5k/CjRFUmHJDgqXXwQiFj863Dk+MBtqYNCgQxeSW4IuY9bndjTIBvCZUNV/PhKQeo451qrNsLnMCEQVgni0JLoPQjGq3c0AkL7b1/ty0aGZ2G+U9YZh423GjH8yIkXdtvcXt5yRvzgaku6gl2BHeyijfpsFoxsGHGQOGbwiBtZ6/Sz6q2O1vx8NWjrVSQ5pOUZISmLWv9CPJP4D9kAC12HN6aTQrTsvCS234IqMcQzw0dga4Q6U+1p3wOWzLcEXTcZMYMF6i8dQ2kIPQpMlx+ax3nwp5cnsm6FIKsqiuJ4wK/CeDFXpQLbkyYxXLXn2n1iqJUW4h+TI6BPAtFwe/XC1H6pu48nrAIvND2lPtQE/TD5YkmVvKCaPsMx5qOfHA5/T/HRMQ4t/pM4EJaDWrKVc7KxfLPfX54Xi+a5m+geZXuUxIaKZpgv5khDr6p90UO63h+cNlWzt7UTEQQYm/5F9sOsx4WBIWIaNrt2Dp4b2vNJc8fUu1pJLkd5lttOxcGHyAERC/TdB/LpkWA7OFQZ8Otujmy1rhQ/Ci7OaHtrSgyxvqFucQB09i/VaHQ0yAozIo1GHtmrf9ZLczEJVQ0CkRpcP3L1MkP0DOF6pQrguFQvrBq5A6rqnc9s0M+mruGzJS8trtV+ZeASj0hoRjxFb2H+MTsPM/rGlbrX/rGeL15knOs5l/0eXEut2QTPSuIoHSP8ZjpJ6i1C5vhWqK07FNuL8qmFMsHxA7WGcSs712jDMSS9Sx2ETwoQHudneXRpeCDcx3AhEantxT9+AkjAfuX39PBAjWlv2SWVEPjk7IbdvNDq5JdeAn18HI2/H708FZ6+/uAhNHISGSAEIPiAEomIZlffw94zgUzvHFSUyHE+D3WEVy5f2Wylu1Heq5hOQJboqNzdiHMZxv/sDNvEX+CSvTvBwxnaJRt9fZXDdkb0inWTcBoLL8GnIFQAlxxISz5Oxw24GCW/my1upRh7djKBT72qVwsc/rE6nqsJnp1SOgVU+xBNsNkSaXExNQ2XxQJqtwQN8X7116zfsMdqr4SADs9VbqmoGNHmbn8Gtur9ntQFzif2bY46IkixPnv1RoevWkLmImIE+QyedxJJL+lKTJXuNOrEaLA9LVow3+duXiOrVHfUYNT6oQtPYivHP9b6eBC2ms1S5H0jn1fkMyi7ClbNI3VLQqrCMyDKSu5YJLv/MJbPPlY5KhumyIBBoJ4FM6wl2XOHwZbooSP34JuDFA41bXXQyl7PELyxp8Id7Ym5myuuU/NoTQb8JXUpRKdq07psiXPXeuqLrQObHoahRfJgK7Ks2Y4tTQF3/+Z2P0f7xwt4twYnsYaKTrLjXQ1VYEa8bCCcrCOgQELCGq/edjxa6EI7708hzDNVFYmQIBW4dir1mnwPJJaglENCepDTVwSjS/4+rqMtyXVqD0OIgxtUT12QQ+hRwGauedp8JWrOLn+0rXXbC4LohAVEFxTjPVOhtK7Rdcu5kuBDvh3p9ZEr1oEyShqLrxsjZZwGiwZtjaOvk75vwUUFoPJgaQdR+RclWdNZvDwJXIUW7Qb5REZk9iidIHsJRFhYtTCkb9MtSaFaUDUGcAUoQ/x2QUkCg12h194UeFMIXh9YU3KWAxq5S49lslo89RzxAw9suf7mgVeihKwsihTpm/SYFuID68CDQw9wRMS90nDGXIJ2ObYEiko6XCDhsbbc5uCwBMQYXqrEUOKQkBlT8T9i/ju1V5QsZswjJ1g08JDyk1iLqZh9+1qQN76kX7OPQg9E3kndQ92r4FZA1/JGqVoNQDlYU1kjxeDDI2jJxKId+CD573by+JYpFDbggyUJ++02Cr9Q3B5Br/Ldj2G6MzCXslEdjhxKDxS9qi+l9zFNHMHb3QHWJRN104/trvGpsW+4Hc/A3vltp9s+KzJXNuDoMbWfupam1ZffkfIkE70hVBRFksqhNityyQRFYV0lGMOyBbWqxXukBMjEWAcS6NYIIC5sm/uSvthvSB2qxgTKFAMzGx5Kk5QW2xKORjbBHQu4IMLptpuQQQCMbmOKTxp3E7b4ZUL51Wwv1UpdV8RH3GcMnPT4GnHQ1tK0r+Xmec+aDc5qLxf4CxjcavVpfEVpGJQaIv9ltIEteDXiiSHlx8k6JxC+nfHyEwcP7dFkxj7gCPd2yHgqPDi3e56IplLXH858FK9hhMrUyccNyIXOnbMeAD2HsVhJJKAMUSENB88RlZ1kycaFSbfmZ9A5FGXhe1CryFyTeMdoa2Rs/CJ6VqrGqHeWYToLA46SwDj0J6UcuiLoZ0gGTLXb2KcUInNMX16VNJLJSyfv+xB3euKjs5OmHH8vwg6JME8G7kW37Hj/FVH4akOHDF1Pg3gtoSDZLKDBmq2F6jkKFSHX/di6K5Eh/bSyxpU4+9HvVQU6Y8TQ1MmWfVl1JBo6YSw/AMGonGi0aXJIySHemM0vQWVLCtWu8V+M5Myb3p7/SKGsETnUaFntA6YN9Supxhl51O0atruHTzMU6mNE/kHtNr9jwTqmm2xHUSrIjfDJGVCJDwATSziv0dFEWjm7uIkoB6IoGUQVjMD2tbR58qjhEoDb2g8dX/pJZc4Rlifv13z60UzJyMTZAiueX3KeOIB4jbog7cDd8FnHijbj90YKqIS/jf8kVbSawR6tJuTtieZMf0qQVwSBdRsuO2C5k4EQxhqXiv+ROoz8THI7gFxn875mKvY5cAe5jIxfw4r19mQhg8tBP6HcawGt2ODaEA/QoHSi8BAeTi8HW5QazB7+bhxE31XHsopexQ50zvTf7v0TPMafSHbTJ5xRU8XjIw0ZXyRKOF2UQgOaVV26jofBr+yogie+v1RSrr8+64645KqzT8cUQXPm60yHUlaYJbnxINyfMrZO1myRXIYFZxB2PDfhxFe2mu1/CLdKKJhXtJ0Sl3Az6AaI6ife8qETRk+XTlL2FSEFhzX5qYj6T+jD02NLg2syMZlU9M1Mev6wYrVT0Lr7j3EVcSmJ2Rv1rbi6SqsG3Dcm1Ckl8PxIHv+RNxkuiW7eBiYV4RXxZSw9Ml+3aGFIve/zzrRmA7DvCdbCXX4Ozv3sPwo3YndjXRGjZju0X2qsZsRQSXEJUY0kXzzocBU7JFvszFbAvjan9OJoH9llcB2qcl/MW/qCY8caM5+OIeUfFygg79zk/DaQn0Het78DyRyD9sGJNy+3XfPYKTbRS0Ka+mP/QcQpKatXZw6zRatCXbI03FHGWyhirN/D81hRe6LJMMBVZudK2kp9nlLTIfbubFvYRKQsiyX0A40BNUiH0s075vX68zF2zVzulWW4Fvv9yOGqTJT+6CH3LdE/o8TJKTYnwzPKtjv+Yb2ylJXNlOL3Hud5jL5W/cQCeelzAbdHoTFUETIGxiFKfV+lo45S1yK5BD0cQUyGo8GxnRiuN1QjODi4XsD3gbbi1bOdnEGbTdtlkZu9HWN30ed9G6BeDypfO2QOlW+l6gNMANzOynMS8swp3l1IgkBXA26EbhvOi+n96LFuO9EMsGOGgwnq1nnJmBzqigcs/Zx64Pgm9puHobpNCLR72D0CK6sTj+h95CiOicBDhcCTZvvKbJx2oDEnXoSqxa+wh5R3XMJ3XUQdSvktc0+l0/l+eZUEONkmjwYS0k0Cc37XUd3OD/vKI44Oz1BVHIxCvwYM1q0CpNuCKbWXxDTAA98XWUoU/B6TSvIYjNNqQtoGZJGeLdOYChcWlDiAMjBuO54hW+KCZr46sQAG98UG4vkJoFsdPwUlHKHx6vV9xptRPQ2v0pO002QNwPSXXaifL9aPHAQOMJqXO13AEHmd3xrxZMp1nq8oPZ2YX5v2iVFqfvI01+m4c98UuQhZRHP/jNkOYsu0f9CSaF1m3WrBlxN/OFIh2wrfGB4qXrIvUZ/ygmxWczW8ekal4hWAoOeys0g1gDR85D2mqunv5OUnIIFCEfn4k/GaYESvrO4I+fmIrd7lu5+4hOx6i7z3a60oxV6D17B1IpWVbYNmOyodmuAUXRESlthIchptSVLJLIEiJKMaqymzB13wAc1D0AJ+pJUunKdcvMR0hIBZZ9xYY+/Af4ikijI3POR9XYtkHcQAItRITmRq6OnVbGe9SJM1tUUmXggTpEl3DkH43cAO5zitIyRHlGUjc5/X9RnKQzHruz+r/9PSUpNxxR21+blU7t5AYze2uc8YzhOiOINl9+7T3Zp66TzVaUIH2LcicrnsJTOXg3ONuE3HrdPCrlor3p3IXn8mbpFAf2DLdutO6Ip23Ha0F0DIrLiRBcfAyfXTIYef+F+JcSXl3P5AGrB5zPPCkyeg817fg0ge6OgJDptdB/3E4W6cHWZbaP3dY+zgP2ankPJY8iestlzrM3P1tmAX80ISSDMcHo9jkG5aN+7BcVSGZnvyBH0vMX6ixi/+o90ezAMxAAAABjbtu18bNu2bdu2bdu2bdu27Q7RQU4ABTIfuGalczGu8qV6Rx36E7pQcZ/nqLf2aw07+8ltPAqlCXHnYpj7eZNnqCRNVkguSCNATnH54Mw0KysC6CPwSWJ1KIYaNZRKc8CAbqJVD90dSAe/jXh44Jd7MDNnIGlvg4w6nq4elKcSiumzrAhWcTNMAsxOScL+IzmiOAMz9VScx0WNIMdqxtXAqIUkRth81AYdHOUPaXQYySBN1qXWQ9+9rh6LHlkw1+uff36qVlVFRKQW4E1bEsfz0VHIQptLGX8TguXH5Q1W6q2Z74U2Gtqxa+bj4nhyAgjcSdKHg3T5WS9/UwAVogWAqYQZ5KVgkNh2gMjRq2n+S4rFp4AtkC27L47SoxB1OTo6Cl/FHs+fwOyiJGUTSrdmdOrLKz8UrDekR4/i3dfAvUfb9PLRfgI2+K7USvHLxHm7yMfbBYySF2uhhqn5LYgwiuwVZ5WgdPvqB7+HXNRIj4DKopVd/nOgP15yZn65VuedHt74h36YA4NsTOvAlNGSkuayG0ocSBgMW5nhaS6IX6adwQp8UKgv/JZJn13UFzKM3B0/f0l4mr2RVfqO2tQNolpAgRNtEhtVREqUeFHq3qxhvpHFO6Wc7UNv8EI4try8K/2eDHqVGrSW5GT7Bag/xdDxROPZEA3mz92H/tS/bflkGTyT5yAIjmQPlbIXXfltNjMLSSXHBwp8R8P0q2xbxoAAYPBXwLUR99d61DvKS633qymg9D2Vij725XDAit2sn4ogTbqn+Yz9Xg+vqX4wp+YDtPf6bs7p2nSzfEZpWN8TgRdH58nH7vCpyxZ+ZPoCsx5slx/V0eTAeToDTS6EILlsD1qVhs4Mo1xDkTkFVYoKtHsDFDsPmrUOZmR4ZI7jSAvONxUN0V2x4gm4aN7PnpAMtcd1gbKzxRRiPqssWlDXSkjKkq+3GPy/pYCtM9hpgeKKhPJ0Ex6OctNHEf71AE0N8sdLgIzVqj3cxN8ZwG9K90KODVwVz4KWMI7XciBq4bWk9U+d+gMOgyuLUW8DLCmPgK7mASEw5sVSTvlafjzVVZECVC6EzLjp/GIeVfxO2i4FZpicwAaFc9rQL2Oh7zZVzVv1xuRAgjJ4F6jn4EnFZRRC5+33ZFC0UPMbNmGpnzOyjg5UceX3QC7nf5aW8aHamXAV3ZjgcFzpiUDSqhGfBRenF2SkoVSUXLzTxG9MKIBQxphNiiVx9hbccFocsHQvYxtC3fasvN8y1P29R/B+3/D3pxhSavNazG3ghRyRNVqHyyYS/A7oeK3DOKR8O97ickdMuJT58dJspru3GmiO+KHxdVDXklNOLxdYO4MscAxMFdZUl73ik3j95GxTVgTQtEKfuxQ+HPQ0sOOOBtXRfE/CjzwMDhdkFlsSATs017hNEKUwpdIFHl63wwgYtMyUt82y5+M8hwDCE1PGaRhcKnOLM3y6pxj5i1iy5k8T1tIhwIL7UsVPyC8hUA5DqUyFTOtknFnaqUUQYBrSBUZcSU8+ZHwyrb5PnhlzAXWXYpYgVk5PD0h1m2FOQ623He9KBj9LmcP7UC5ikIaMPzNd18y/PPq7L98LTq8mgt4VQtgVKurpI/Mzv+af69CVJfF4a0jK2gM+E1iEallSxpqHtMW0T3pc/FVA4pAFl0HMCm/UtMEsWEMsENCPS7Oq9tqYM9HBD4BG96VSl9C37pHWQnZUgkaVNz8w64qeEDP62eVEhe9Popgbfse0X02itstrU4GCuqYtByhloGgNGAn4CfYmljxdIJ90157Qctp6Qgyv4/UeTtL3leeF4YsDHSM6ZhKIB/HRERpNQP8iDgkkqa1Se6hq5p+qsURFZCSKWl+t3ea4P2dmz9ABVbV9/PW1qteSLR7GZWb9XYESlawld/E3g7g2PKmMCw1HtFONR1C3DcJD5s8k9gPV0kkU5OZ+TirImL5Vk35BsRszmrRsuver/Dmpg/C+f2Up75PXZSCqvZbwolX1wcdHGl5cxfcDY+NE6xgGAh+lQs7AYtFnxjq1lEn1QhsKasfWtx5PHAXrsBls90fPDeX5+nu2iWif6RN++TRdi6qYwnk1iv8IfnqTOJPdNuYPCgltSKu4T6gPomyolYfWP/GkKZX4Svl2Vgsjypejy3TkMwNo/D0JilgEw1YQTZ7SMlFzE2nYjphIShXNWUFjd7tvd/qFtLchMfSkOhH4XEz0YYUM6kkerYvjTagjcyM/Gq9cMCR8QCIkpE7sIk7ql/of9dKYfgRGQpFWcUUSxIbCSmBHbqQe7sSULx7QUqsxr+UGGvzOPg5kLvOGzuKStBSqb7gqp6srTpvj6FSX9ohgYb6UJg9Mbpg1kjoARBzl/DLM5mmggGhAxGDYt+0W38TztchrRpC+gvnDr/sEVUfoQgOhnGHlk+RGJNUQccU6H4LKDAAUdYm7HYGA2Ug/iDpmrFiHkSW8raWqJx039Xar83qzp2SYVMN71HcsGhZiiVlHJp2SDNi8TynKH/PnON91DXUAaOEXk9yFBHTomkfk8yFNK/cwNc2NMgd3gcAKn4/HY/uFnaB5WMy0rLOT7WVWJLO3hD7aYC3sChYwzMSoPldPMoFlYYf9l/boToKYCdMfyOXciU2iz9xk+5mT7bVIZ6vg+PKHLqqNP/FKPsw46wR8fl6cTrfqcDIAcY9crnjbF6izz3iday4PMaUKv4UNKEZdcG9NOAKBUHkgrrzoN6Aj10uJOH4SyjO28W0u3Yi5oHIYyX+h5Lgd8tyjXXvUW1Y6SBftm7IBOSHDKGCs6zJjsolZo1a14Ag0nfCheUVcROGJGKIuW0Ro3SGnDO1FQTfOkV8nbO6cyOTzDC8VWtCBllzf6/MqaTfFtfCxzQeBExncI3k6x57tUN5SiQ0Yd5N05+MOKGXmMYHG5AwJ1nIkB8agwyrpUdXjnHWbswls+k5LqM4VdT0003O4YVcrDcknRp+9noKGZvy1lyuXvMHrVkI6OFd75soklxlP78BgoCGQqlf9Bi9WxrqltFFFzc8ZD8yJLkP+rSsoxWEh4vtjdui3gS8JaZyr/ZnwI45oVwIpUdkYryJOf54IlSXvNdJAMMJidJ74kfesEJBx8k0Kecv0iU+ynlZG0BpUvcRZLo1T48NfiGwPa6K+5zUVI6fiw6kP2Lv41UcskVqI7JpNbri52z45wqEPTl1xwspPCh6KobyHwr5ne8Z40DerJ3qvZxs045hXCioTtUJmHXTzbJ3Uk3NphZjrphioUZGn11dCQT+VtpyZvtbwtZIO8+jCOFlLP1MP7DJzm4WAmMpwiPU6jM92Tz3tKNxL0APcFDbf2a1ypT+aHrofYFDHdwqBnKswxOVvFS75s9PsHsSYOU3zmqZQBXmvlNap/7hU0ib/LAwxLlvvR6cXhVn/0mKYNWSfowueI8mLgpFKFdUXEjPwo/KmXL39k9HHIPQ9PEn9zOTK7+1to6hfHvEEN05IUxgTIVIR5/SpOSbXNOBa9hJI7BKcQ/uLoixyl6V0hGo3yDdIqP+Ol/zqYb6apPNQPuTnqQYxq+HON5xti9s3frE8CutP4PwNASZNQ1NzirnW59wBmKoogcVfHKdz3Aj2i6gpW0XH4F56RkvUOXj+eyosnivinIWg0SQwpAnsWLaAx+5v0D7sS5NnTgIera586NTAyFCjb3Z+xp/EFT5Nf/rBsbye44ukOUomj2jtzHyCMZyuxKVYaPekEolOzSSAYXjrH6T1zDWWZH8gqQOczhzUFo8opGA6JA0+u8iPmRm/jNJuwFOMvBKcEYBABCXC/3Lq/UWHZ+wj0dOm6n15iHp4cNd4ZbmV4srfZnuycP1TNX+cNKnFtQpOR2aVCDHJN1YRtzDYRldUSeGH8oROcYNY7GaJdGSFEZCA8odXIOEutGm+i/ggN3ZlHAeeJlm74nHpHTxaTuOHEapBf5IK2KT+ne8QU57rMEhe/gX6Fr0RXIK0D0UhgMryzvlqxqggmYEr9cU4t5/3OyWBexEyc6Md59vHwgZi24MO+PLZOaG2sWBIneqHtNWdsFtEIBjOnCUf+EZb3w+05hMKmsLf8NyGwvtVR8CkKjXOLrdq0RpEg1TwqxDM1QvESIdV1ZZJVU99yrySFuD6U5MIj3scFSFX+NS8Ql/xEOYzTrEBeBUXR+zhfllrmhIjsYVvLAA7TuXJ5kNahBpHDGjfDd8+j1sYsVjsviAOPGMdbErUdDo+qlSgNadkmOQlqBsVwmLN1yZDsXr0UZkwNdEisCVqXtgv66l8hyrXL6YaHraMCOqVBZXQxlkcsqGtw95/WvABxOm9MW44/FhbaWlCCKyXrVj3zcNx4egviwcZnFpunrryNh9K/hpS38FVO16oo7NFvhCthHIvuToFhwIkjWvkJEuS1klOpJb2NNiKgLdSXX5/8T182L37lcYcFNVDjvp1/2i2JlLmpZp4YMKQUbvnOp1Wiq/effrTVJzLpphO8s9iaUotnphZTTNKQOen/1IJn3H1Fqigh0vDymQZ3phaq5288NDI5YoKQcZmu360Buh905jOxNhYFvYyGLMA4p+mBRtQ19vkwU7oVVdHtwiPM/Kt+/v6vA0l3rbEzOAf2/zscj7iUe3oVOaCZx7JzbcGiQmFgoJaxF+6XN/7V86xi3sZ3nXATRXvlXmxHJdurOCUnHPTsdSNAmAFuYJ5KX628ULhbENbQ6HkqLdHl08DQWy7SryKF9LgpU707TMv34kHCOcJC1+nfsV7iwOfOXWZuvm+/kwwRm0TKS3sYXiQpxiRqMX43IIHbX/jBXj3++yfJGUt7xVjIQlgHOeyhSD+eV2/KRB/U6W8Bkf/g7WCPG6/mFRSf1/az+IXSAUuaKi12u6BlNmxDgLFGLWFT0o75ZZMlHWWRSAHneS3AePU69a1DlqXQajzKqCyBQOkhzPfTtoLfSosrmGLYiF448Ut3k1N+hjVzk6xO40TCzb/i7xQKL/UGqV5C/cYGvvXrL3mfC6a8mBII9ySDROlZrmb2z2BSCx9gBmYrKFO7cgM4MuWpfJr0/yHJEpYhNoV68t2lkZo+n5GCBKdZBl+R6AylpLkj/W8Qr/1iiMgFoYNI9PS70Lci1Dn8dbF8OY0TgrvWPMEcOfCRF8ZqtWp7rnmIJ4mUf1Le7OxJPdW+152FMxPHJf0L95W/PVHc2ueVrXNUu9Tc1J9xJpDSJYLWnjlb9PDW5i6Z6iKb+52CDC4fHseWAjf0K/6WfChSo0NXo9t3O/lGH7K++m5CZTmha+rV5aCG3WXAQP+7ZeZG7D6dw5WFcrxy0CfwSp3cV96w0vXy8B7S6wxlHlcuQdhwixhklulxmwwmASX0nmHB0E6aXGdv+ZU+3Z5L8mt/ItTlsmB/nZ6X9okeBnVfavvKvcXRu4h6at/+urUlNEHYMN5wSm+D3GeUKldWPHFKpYdXvLF4RUW7NgNbDPZppnC1l1z27rKgamiidg3Jwa/3E3km+6XV22b27WqTFTNZrgnNtLC90QCjv1EodsWKsR34Dxdz78YFFxUlnLl5eaVjGi9UPCIgaPjESW7hu9wKX8tF9Vm97sxk9kcNPrkEOVbt/jg9FSIrqx0CWJS3z0c1tx+bsXjnfnkLnWa6izthoxwgQYsg8zdDnLdxPcSOeBS2htpjIJWUgDUK265WWXgyYhcQv9JPVGutuyoiohC605NMfFvdKWqgiymRQozcn44u+uDJKYKF4db5jGUB//HxhM9E4IA1CNVZKigKAHcyjzBeccn5g7bLdtZVoGMrCsgKs77YkZUdLsdE0dFknOkUljtPOaXf2NTiioR7CSXR1pek+BmqLLPSot0fuSnbeLDLhz4SPImjQWT4tOt3vO5HrsZTgT1XsNZ92R3Oq87nnKrmijJUPkOJDCUt7ht59xBZHbT7Q+71iDH3xZhy9TDaFL3YpFMm1huHi9xEBfJAgXYBM8VmTBQVHh62em66I5i5qjR0HPdV3uPa8PCvpEYukinod31IHUhafbHA9EnlJeRGWCyOEUT6q2g1bZ+W/BmSjsp6+IE5M2Yrmc0FzmpbNgqWH1yjyR2ON7sh4IF83L6nDW7FKEHKIvQHanUjz3gcpaPTKJy58YBkV0IIAWPYM0pRGDLfdJU0AAnOTyYhfV+E+rH6T3Pn5WA2utbkozTeXlSKWaWSyLFk8TMsZn47vrlsDAbyqsGkpDBvYihwiBUInNgSRJOkS/8bZE2qWtcbh4mdM2aHon+39nXs0wIx8KaJZVvWgHhbDl3SplzzSlBwjbdC9O/KETV+SNdq1AZ9zkgIBoO4XHQ0MSh23bqpYhwxEgAe6Pe9GPBwiThPuc/dK5D0J4/XWEmCkJsFmMnxpBElPgdHV21kxMO1rm3YPmn4q5/NTSZTED8Y11WHtuba4MjzcUQNQPH/zysh96BzzS/BYj7fFfXMXZFfpicKQSpiPRAQ+ZrrPmpSqoGCrVcoJePPu9wdwcrDx0NLwNpq5S6ehQJ/PNIxVNL4gVmQbhAeYpmIQCNCdN+g+R5jQoLEQqs+8fH54gyQBlXdbf2iIK4IoEwRCkn2pM2Ym7CqQUPz37H7OZNgP8p3ySL4le95kOOhXEqJKQt7y/MDQZRCmSmRgTEJ0s58Riu3yMUhtB6ahMC/C138XRzblIe3oyZ6knz2ak29TlOiuU9iJm26NY05sZmFLBD0rmDnfk+vUTwDQjIvFIJFohRH6nlKI5MIjL3I6n03d+0EO/7v56dDvWuB0o03Z4sQwLO4fgR7KPSytYdjj8W6NV1O+R5nzUWD/Bk2bKNxnUHZUAQLx+4/HTnFsUJ3MjqaO68lGatDFnrmh45e29eZBu7sGlE/3Z4zyRdpkQhJoxgDt6KuM88DqKnoxpTiTJ7u6O7vCSYehKBewbsPWJmyOnpsIqJ8uNRTFV7ufpJlnhv2Wcvw6NQ9v7aNGMNJpsXe8IWfCOhTaBd4eb/NOp2Ns/IMgzR5KdZRCKXQEsCxMASdR1T2WkZu/tm9FXwtOLPV4GV7Hx9Sr1B2UJ8YMUjZxmZeb4ZHMXwzuuPWBew4q8fPSH3uGMdRDhaFZFvxYaux14HMUucyicaSgKhfJqUAg9I7SLbO08NZee3KJ0bCH3zo5IwuKhRR0/9eaonmM5zTHVE+geeP3U6/FuCnivpnDTH+03jR67ZO+y6FE1ZUdKWIlPMZu09y6ET7O9Qkq0ZHeLgBe572/l3EzFbOat49mhFQFdaMnb+J2jt242GhGDnbXeCpRzdyhtIjppCxzyVMLhhZlo3iP902/MpLVlH6w+ejoCyuEeO/PmMpKpuF9ZERRbcKrOt5IBOazdAIwg+VegK6Ez2d/gtm6AMlXIMFF5ZJyeRPdiLR6ML50MhNZbKlnM3fNU/j5cY6m98UYmlcKMT8xRp7QleoLgmelMmOAohx1dKZysk7o+ssiQRT5yHeLYtNvA8wtvnt12Gcf0FIbo5BbMk73bW6VsX5BGMYpXOWey5o34Zat/W320ktSrjGeVv9qQAHh1aqib/Ojvawop1LdDkq1u/fl0ZTsfXSzduLsQ2rTNp8kp+Bb1KjgE+MpTgLDcgnjBSyVdtrzjTd9Yf2aY3Mjld5OhxOVLvHAiqgj8LbxYAPtlp63VCeU06U+MPvfmyKEccaRG2CaOtmYYTd2ErPAJRJG270CxhoNLcoyyjd7WK5LJ+KufplePwsmuvHAT8SJAgCdZQnCmMrU61IQAnuHnvOZj14IzHRDD6JPs7XK41TdU7txd0/NG40/PrLY4dyfRvlhigyg42TLgD6u9X4MkQhKIeQ3nlKRVeXs9rSouTxXFVXbPn9wChXVBv8BjoiN84IzgS/19co2yFlwdeEoSVK7kssMZLpU/8W7vp6Qry4J0RtgcLZ4gsOdAm2jTOoutaUmHPXyyNfSj5P3gkEWSwqJdNnXuCiFNLADjlEFPUnoUoujqnGCnmZRW6NL+M+UP7Rsji60nte4VwvR4/zvyhvVB49wmBFBEEmZ+/wmZfEB71xTMNtybpH/9J38uaQ+f2wIE+FTHUhGDoqezBm6HYj72PNVRwRVP50t/IgL10xOwWPMJZUusnZBs8c6HIerlLcMnEU30Nv9UAtFodsH1Fop2FzOpWNNXsNMEfifqSMyMBa7pBrDimx0Wnw3FgIufafKNWzmiT5RmhZnEJWFvdi1nbPFgGB2h1y4tTsFZ+WqxHw0hQG1k1XZ4Ahjs4/I8GMcsBDbkrzlX83y5QgfOhvYnsoPiYl9BBxUOid9Xp0ds4R2gG2MBvVANMBnR73nHD9NHSytBHYiOnpVF4K25MLf9/o3LfJmlBhQxHjBu64vl4KkdB57O+aYXHpx7HKTAub0zwqW6taDt8lkro9riIskUKqlnluU+lnIGeizL4MP2piFrGs9H8ZSI5k+DwwNDCWVKvnDOJBoEBTXcRG3foC6suEUowK2nw7fN1Q/LV61RL8QCWxeuYP8CtOqR108OCtQHTcL5apFkKRachaDHZGNUkLV6VL7xvwkg9yi3Sifnaaiuh1Q1WZb4+rU2lFUIkERN38Rv6B8LOaLRKlLdmPLHrWk1/i+mLPuYojWk0XsNGht2lLXG40GH97du/CYXofjBrdfxydmBi+0nqT0DqYZqGVs0NfM7MI8oUL//iVzn3mmxzAReKKWPpu4e4pCYGL4wW4P2I3y2j0eDSJKKTBuotwS2F2PlFk+wJyTMJCOVIGnUlVAKayBe/E3siWoYGqsaldeGKV/XuCQlJl+yJk8IVSKd8YeJ8DrkoiEasTx6R5/8O05fqGlzi0Y9maXTNOLNSkkT+jQlPggBR4X9hueYpJ2hOIjpqAomDcswaz76xCo2gk+W18hu5oe272e7MtkxeRobATDiGREsrERgsQUMihIo0wnLoKsQZOBtAYAzrOaImrBOI6+KwmkIqfzI0ppLKnIXE+xnrxNBMJKFyw8DW02/iOexgT9rLdE72Y1eQzXckyZ0FVzqb6NjPxIhVrtLX3tHwfuUhhq3LYKIfcjoTBT7xqG1fqKHh0oQIDAFoeM71T0KQLbB/n49ORwasQZbkbTI8inxqF2EB55v6lo/nahCvZ6drrpTqrQ1XTpkzlD9aF6dgaL8jo6DFPJnh9HWtbjDQHt4cNYSAZI3icc4vtEoQnTWij90XLmhynhVGZVKINyaV0LrPCYLWob1Ix2XEpNfwqByyp7ja7GCkF50p2T+yFfnr8Ex14zGK5VqERjEcUE4YUjpgWycGGmrc6nyYUrMMj3oTmsy2w6AG6AjnmE3yPNDR6aj13vv/OTnE48X4XoZiybeDKIvQM6xCcV4IoM5XcHOZGs1QdDIoH7OqzxYRyoWt8CsXgtX5CtScunQ51dT8c/+7J6WLM0L8nuLX1eXD9aRvfhZhZVyYVHOV8fuKBILROQhbQGhiyCFdfIznXATWzDVFz59pf7ohPMFxgQ07ZJpcYSfU5Io3DYgwv3tJRutP97S+Q/G4XOnmJfF9dgxHCYPJdjUFppfwksiuLud3nGk8MjuYeX2SqXTHuo+lVhnnjX7t7IFWV9DFPay7dYHvqrfD+BNPHZV4/8yyLOMpSygC/LGGVn7cKnyDcglCb9OTlde2WMBYGOwXrwhlOxukcDvtTeHEzis5UPv64hlFCC1ffF1mg91v+P0+4di5T5CVa8DPwATNwGw0ZMov3j1MjNLnirV1B5qDcNk++6c7/QH3SZ5Ahje5pwv8SH4lqJG1Y+1Psr8k9mmmX75K+Lvmv+hmLkHVVK8hY65/S2ieky0djtFKe5yMguWjEVRkIEW/fNIpq7I0Ef2cUaria2v+VbB+gXRyca3h1W1nJtwTf2HSREFE3F0fyKbC9DWH6TdyZ5FsXieWaKaEfF/dHHJC1PBxBnlCcKAnNJZ2fTnuRScE7FCfie1Dk//y/KDPlYHMJ5Voro6CXRtIL10J8wtmK6MA52SWS43GxkIbEY7n+nM9uB3CZOnQEMWdfpLD4Qr0EhUftiZq3ld/9HyQZccAHwbEFdSjQLBVgmno1XSm2wGS6NSH4zq+z0mSa2Vcx/APi2X8WF9vfmAVKrNzisGRanbKrSZVwASOi90/8ZDE/+yqYvEB3NFpHhgFor80048937Eu0sj7TN9lozXvPqQIgOaTJ1BkUiYkWAAZt2DoaQVyNcRJvJ0aaA5BMAeXzbzytGdSxx3nlFpMKsrxvZhgNz01vHnbTenQ0FifQHTpHt+JqZyKQv9TldrCT0EPYH/EFs7vI1Q9K9nxsKegOYdeXUgVDhcst3888klGNnO2rSwJ1LZ5iDbrIfWqFZPCdXLBzw0XQnGkrsDwlfMz+IEwg8HKtxL4DpBXtBEn9lEMz1svHOy8mEu/xD10gRrB1kmsGo0yBHgKD6WDRW4P66+FuP16NJqOmxzXwOiznKmATM2JbMCMDFcWyHRFTvO1+nKcni2H8+nUNLNK1t/IS8aKpQmovU2cQCK2lElzc+6zJe6QJrsSP3Ymrkh2zL5/v+GAUlPiAhHexWjefuw91DRxtJmnB9RvcwSjWv8CLILceAt4k277xoEo56qdIM/Umpgpqevw+b0dvM3/IB9U9WgjNn5S07R4zpeXhpsRSLLdMKsSC0SzyaBJuch3RxlmjT6dqVoLx36vRWwKATCedaTwMA92pwvf8/GTtGisLBq/OlkNMVFYI3N6saITXgwiKihiNmfceJqoDpLhpJ9x+5NAF3ba5Cd3mDU7MeRCLJX1GIPzApe7w17gdcPnVhugUFrigN6IhjaxzyOXynKUOt6lIQDl86JpfkiDJXIkxLIHT4EbQU+K45Z9fItcJMbKwNPeydfHpSWNEjXluPb35J4jHLHKtJl5bVyZio70nMsXs1/NEIFnpqeXqBqveDY2w27pDePrdxf4XhAkZqsG89uAG68cSXSZpAxhD9yXiuN1+eFS34Jn9DDV/ViymLHkMAyU6mfNAKjYFLOIZV2mJYw9N2tWODjeRU9A6eN8u1xzKCFA3dDaSZS7QQpEhFKPt5hAwdosCKw2KPhjngkwHX6HLP2+zGF6UoC42NzG0Dl1R4lXE4OAK9qsJVhos17E9BssTXKZiP7DgeblCionbTmSecM/u4CULv1MeHvDDP+fYTJnkGXBBm1p0LBPx9oumWtauHnh/nuSSeWsxziY84Y3kA6W7Hg60I3eZq2Tcsz1p6F25ipn9h6V4I3/AAuZimlPwHQQsXta30fOH2I9marehQmKe7WGnU1PH/t+7MVGuqOwHsyiGLXdcDly4mt2eCRM3q/LTPsy/yntMovH5kAzdckn86mi1OyXu3enImGk1K95ecUsaozPe8l9VGF9Iqvh90nyA6JiypztSO3E5B68I+uvQpPhRufOZaBnDP39ZwBrfPn8LYpiP33F907fhmQjjOm+1QX8qMvHurcMMmAXP1OMJnhH4n4VVr8ytiYRVWMA1EzQkoYA6qWD1XI8od4tA143p7PpsxRzay6Y9kX06MaF3mDuBmy2d2B1dilCBzeqsFKAX7iJeNRjyGCctD2N0V1XGhADeNl0KF/UlojRqeXKrmr5p7OD1lYWp/IBMEQKrCOJ1ZNy894ugVJKZjQuFSGWojHHCWnJukc413RocfWbEHdMF1wLy918jjhrHzbDVJo1+KQFBuQx/skDzB7VaKwiG0blk8Ttoz/Ozsk5BuJiNn1BJZ+KqE3EnxhWOvCkJWiBGIQmtzg//ctduIPr4/kpfivuEBTszGCfkQ1FsPLAbJ9vuCYcOZ1UmZb8Ae7VpLE7mvXj6jVCoKmvIIIeq9MIse5AWwJws3pXgSYf/mBLHZVohKGXc8vxp3g3YOhXcJLoEdshGWU9IG5o2V05cjSVtl4KiwkbTarTPGF0IQ9HKsBXiwk5fSBIau3tpvgTvTq4HGl9YCGZG0ajN7y2+U3lCsZAv9CR9y1K5Imm+2zDfFlIRfN8o1SFH1U1Y3JZvkHA4SDBNLAHexnpUc4torUJZbpl5bxG4bPKGd9J7/CpXF7wmNqVVURtZDasWmecOMWdXzj95C5eKqY9XgJx9lCIX909p8bcDPEfK6mTxSNE7yi2oQ8jLAJG8gDgxhZMvrp0MXPANediIaV6IGWth6AcFzInsZzv6DfRkpeW1RluGsClN4FzhPGO0QJc2Dfu7pzfvy/4daOF5F/zo3pqSTU3YB92LzrMfODLlU07d7FmZYIyiEK8OulcJ9xofNYhWHlkdFPqPHkDf8KbpkA0oGk21niJXu1r/bdPAKYwpX/nTHQNQKKPjopYSFcQMB0eAibQTFBaHy0d0v/+Gcobw5r4M6HQhRKpnhDrEXdmtS/mJKMPmrSjMHRljjKogbRaKBTiwobXkOvhwSqicEt7uDiwI5j52EkGKOlZyDbACCXDZA6i/upLl1kJS2B9sK+Ox0INxz1GjMcDp3dtE4ELPxfmxTB+ip7TYkx0BF55wXW3qchAXbB/IBfc78gW5aNDp1Qu6U+suvgTgVLwV8xEG+2OJ5ps1h/ptTtUWIhjpEwuBLG1tpDzqsNApH4qg4tSs0usSpBZFmetCBGUBe+RVJiwC/DrItNOSx+j/XB5lhy6Xmv2TSogqILBZyx+ltBdO47s+hr6MLPIovM7tqs9g2H1Z6RS3CySniK6NNjtQawlhxWxOIPTDyRNZ57eA3ON7ifERN9olXGZMDcWMQndVEKdBM5DNxPNh1fdTB6bG3tQahYUuK2dRlFyzTDyp+0M1LlKxasmTkN2UHscasWCV+NzKMzIImqcqnddfqlHQ2EAVzlTPQKPfMtKHroqs9s7pNBPhND66HGud2JBUuUCOoCbNkAiybcl54tw5YS6ajVQbpNPK+DrQNKG+eUYrUkkCENupztxea8Qib5xN7dtWab2ypUfNZCOotX5uA6Xnhg6aCYIzRbr+8IZdubAv7uGEE69dfDO8xxTYGLItHHfb1+w4yRnWgPoevOQsSMtw6yQUBkUrxowwVcrNixIFdueJeciLRvll8fusc1nq0z5fTQZNzguqok/v1/Yl/2jVH64IG81/GuZKk6ZeZbhqVXCVXwYpGiKMaMYLBMnFo+VTzKRVDwatvbVMp2Qo4aGrV43/kyWOAKSA5t/qlTpmzqMPBH3fKz/MlDW+pL58Lt2G0NolznUoceiNa539cTWZwoPXtk+NeLJqLZTu7mhI8yINY3A6hkC683nqn9Ircrc725d+AmskCtpFXXfYCCL1g2EJRm4fgf800jN6Vv1VE/eWu8zljoyCfB/Kk6fgGPUSZRMlSG8EjYnk+dt/gzveSA5CLWG5Y3lJYHpqmvKuE1K7hzhurkHkvUGMRMnA1YzAhCsygbBNkkBkDGm97dmTPzNWKZbc2d/ktIIIXHWt9OsVTfSuHAgIHqbHt4iSdkaB5NE1CV1G3TDEkPHrs6MalKIfW9B71ELYt+VuaCodQD8qE92ESjS593jWstxE2/boyDJKaiGCR6U2UcIBQZvRGeugiJws4q3+daKFnta8e+h19ecxVlOqtSu35xCbj/A4S0aoyfaSip7uRh8E0CfLk3IaImO8kPgpeMOCvUGu4XxHywo5Ehw5DJOioczU8a1TOgzJC+cOLFGLF2krI4nXwduKnSDWk8ZbKGzjw2ld2OGvhDHyDKUT7Ij3Z9rIwI8JjDBWUI4t777UoGJqkMV3TT7wMAph1lFJ6HApjP4xVIpQgKCs/FyXC3dOVPDtHpag0MxqsUOs82WMdhjN9oviYZ2PHvEbu57g989DiEtRhSZU5IQN+G1+a7gXaq/7TCgbX4OuEL1Ffeqx4KU/oVaNXeNLrXBKv6jA2nfTMuB0PMoo3vrtHb2ICaOESctjlFspxxlFEgVgT3jelLK5NKr7G07fwR91JdOluwFUzTamRN3oa2HnC8hq7/j3IcBo04nxVmugYH+nn+po+qN2t584F0WRs+V5vdu/P0GlCxlRqUNYaSFDAQSBS9Ccn8Ldq5WagDUrPtuyUXnkP1zO/JnhnU19aq/iyH6SCXdqjea8hcBpGWa53Cw4+A7qDmohC0lD3Xtmmq8IbOH/1hNYZeJWN5xD/C+1ugsmc2xtfeqd4qTW/JOj/fHW0stp/qiul4c6cTUOtXClMiu2FPT/ZB05Pm5Y/pHh4/OGco638/vPF2eIf3okfv31E0LKX7wlSgSupY5rpm7cvnK1+GNE7KFRLkbQu+qemG4X/0QLY6J6ZyUgjjY3E6EzMDdr2YSpLzWAeLwTyvH4/41M6pnxiGILyiS3Kd97YE3qJ6aEsjeULOa+d3htfI4yimr8YWHsowQ3d25hQENrNWAO3MlNoQKKX0i+BA9lc9lyZc/nibzwq30Ptoth/xvAAp59UfnaQKNh+HdT5ItKvDxOJUauMsInPi+7lb13fB+on0++s5yTVpAjIozv4ydC6ppr6mXHJYGmT/YT1mDGIzVPMonvMB6xQiliz4rMatHC/vkmhP50yDn8mjiuSmFWwn5wZpaRzKq8FKeXuIRXC4gCTYkiyIbxguf21Skf+3iY3Sh8gNWKiAFsYAQpYn7Azuw6bqH6WMd8weXaADv7mFhS6RO1BR1tAdd6kMgZ2tBII1tlJbXO55tpFbY4vcVEbmGych6bxg4irPBQoWY2z3S8vjT8w46rYQdAYCLCBUqKQBl8ZPGZOGnn8nusJING4/Uq8808V2lKmreYfG+Pk/XbaUOphHW9mxsh0JROC+zbLD/fS9+MXeb+tdMh7w+jH9UI8qsinHiuc3Vyhnp09+otqYuf/4ddRkyIRuoUPjzzZc2XH0BTgZDTlmDSAe6DD9erb/fAg32kCBQWlAbitqadR58JJuT2pfLdxYVvEc2D7Q+BGPe8yat+uoM2TaJcp6Gi1g7i4J3bC/vRRulUGw1IBimEy8s0dVNH2boh5sppehCx+eKIi51sVx+/p48oSszcXpMczbKIxLgIHB+mJanPgjMeFHKQVO0H43zbA44DB4mAUkI7fAtsVin3iiwvuaPvzDu2j+EFj4Yl+YMM/yKuFL2mSHyUCfeLwSZ/ixkAFZ4etELB/Dujj0b111pPaeZ0sHN4NTf3Djan3Gp37XdlZ0bBLRdQ9jbJXhP+fmvgl3Sx7mEJwKWCPujhcAhkeBCwG7FRCsVSX2GdLt4FS+EuiIG+Jk+d+mjXfMJfRsYO6lamLagHFpCZGPdWj3aPJ62KUtIICwa4vRQ0ytDVo9iNjPx2qzJ/pFkU33fFIWp/AcIPvLmpxNBdsQEBTK9/AtCUrN2j0bPWeLfDVD4I/KpJ1J4YEvak0/WF14Gujs0IRbSzbG6qQgTGDx3MK+w5Xptg648sxYjEsc72lyRRvcRZiDqAwGJmxXNhbMqnoCOtyJ1o2EJieYC2b3jQ+/Bl27SgoTdu2s4sHJHIRBTe9qGVsIo3+B4hWU4Gk1VGz5A/vVufnN5BLl3a4JWChWZw5285j/ksBT9+41z9TBwHOqwFliwrpzdoQUPQ5f69MgHXWcSYsEyAdMGSebJUSinQY65wDphOEi7OortshUHDrmJbXXYti6tvoNHu0OrDmH0hzmhGRRDtKSzjXzQ9aLdfPq0fAgjo9rk7WssxxtBmvPaeoPKkxJOZWb11Bnc8QwiMvkTdxDR++HIzYzcYG1WZGap1k35SWvjShTJyytDN4VnW3/33i5LkR3fR00NP3x+YR7afR7sjkPsIevxTYpL2hsI0lXAWOfpaxmx5OKP7wOz1oYYXZ50acjRYAGt5L+yRpqkD18etklPD+VXpyiLb/10fmNd31JaUnkaDAn5W6MGtZsj9Em9FaDnoNYfdEJbH1tulu1KPXD2w4R2w88GtaVhTynvGRZvMBoCzHwiBhctQ+VJNk7aeEnbufTUOxn13HNau0tr0Yx2v3oLdsMgI5lMbuv2hE8L1vcGz4ebShJfC5gL8m+qJ03AmWxYeJYJLaghzKF8iIdUCBOwx+VA/St3O7tvBpv2N6nfBs2XUsQH6VHhAhm5v0GKeDd9ZbVn+WPoiSi3DdLQ2pNdT5S0ejyJewW/bXSqz/Z1GsJ4SW14Vk11BcgCnWwaDF2wgQxL8ve5NuQgaq/AGMxYX4vV8X4RytElGzeGvuPfN16faavXy/GDa6IEvxySDWHOYJrb9RuaQHC6XM1EPWcReP/g+qckhX3UI24XHo0K6H7eYnIr/4uOXd6ZELi2urHNK0ncjzmCFe55nDbqKM92qu08oPoqizW8QSXFkEe9jS4MujbAe2Irg+PRLNkCLGSieFrKWus5eLVvaFLvsNSU5yr+td2pH1qH4uB0Htyv49++Snv+4fDk0BZ1J8kQ8zkNLOdW8QI1BzDBCJFdYOKARMg3wnfAUgXPxu+CF3ZFSeghcxXQ2VfVLwXNxkxDpSIMpTFTxNnIq3pT1a2SwtlzcwV3ujNFvN5XcnWh4UxqnxdkALc3rF/I220IKvCnhXH73u+lI68eO7D+uLW0AvyDwGK5skM3+S6srBSD8F8NSpbayIGuQY3k+O9DRmXSRoRCEIQGteMo5PMD8MkIAlD8Jp9pfFD5ykN8tWPpxmzooaOH2NLz4op3n+mudNvu4J1uzznyGQElW5+X2+ccGbkfUgYwnsWBAmwSj4Z+BhePqtkwhE/dh9EutBWWSSwXywihh2Ni8x619svRBafN7tm2D7r+iCt10MLdwOAYpHx8alsww/mLrA7bOkfqQ7tlyNof1B1n31k9Zk2EloQB5QX8mspI+CYRx7VACZccCFoilLKkLZNx7Bw00KACu72PX4pXKprBozxq1NdS7DpQWAeVDnDb1PijKxy2hxMYRWsIo1d5baVGb2moQ4EQi3GwmGVObbtCzlHnecDm29My8XXrXJuGh5gX6DnzeTllV7FQzQQpePnaXBb0IV2LFj8TMGpjW/fzrjdhGLYbgaiSVwV17fTfaaFZ/eW0+KtKTxvzksqrulO2jGsRn44j5KfLkTXATt0kqZ7ikZb+FEQNiMRIf2wuIERWHS091+mEF9CXHo9xaMdHyNWJmDAfjCOaIltczW0eBUgruKWsApWjozIzG80gP8aBb9Lxu0J92HmGcBHvHPLJcYjAw1QegXvuAs/lIcdZ5Fobt5ykdAmcOb2uDnS7j+GLPTXzk9gnHsJ/N0YBKaYhlk1Ddm2wIFQ7cBO7Nx+B9SOxROYtGAe8TTtdPkADNKir3xAd7bBVSaFS3lZW2+BP63kd3+aZHxWc60w3EjBb6jtWjDmfX7/xszd0Tmsi9yVemvcUZ2wor78NPcVkvSLVXYgIA5t2o2xtOI3bYor4RdaHS9AQUZlz1h4tjdst0bAjWgC9m9mOPVhRy+WzKMdRRC6sK1jRu/5xlu91ANDjuoxFYMYRB1JnIMONuX/ZVjY0ZROUtiM0AYwIddRHFfuStpTeFJ+yozMpz1L+Tlan7VqUQoPFMs9v65YvMh1qFhaBFHE3KpIh+UAwGFRwdyRNvB+Y7mYh7PL2GNOpbZdAEmmfzVtI83Dd0wWUuH0m0UUjOUBq5bn0FnOhdPsllZ15y/G5BmWpHr/JaPfzwrXaA2yel6Si8Gg6hg5cS64qBWZGwxizETULT3RvU2G04sPqQqweWlCVKnFu/W6oSyhF2KLU4mRq37vkMoreRyFNMEplE+esgpPU7BcWl3ZoBoXydbpN1QTtett+KWUMin3RZp71PBiLIdoZLiTkA1e8d6S/Bm4mVVQ7PQ8BvOcRORdoKtzmEonT63JheSDpaSUozUeCCbXhImimhsMacYChrry3RSJfzqK/xIkJ10m9YhCENcgX9E5jqVWkEsy2RZsz37WGGgI/PhXxLI0jHKMpjiUsE3AuaZdGm4mbBoeVOf1JDEAorXfbl13Lb3zB+//OpfO/iqxqTEKB3Q+YThMXDG7j/WvGGRdD5qoXxZkXagNIOCDpI3c5cdhj5AFbCkZyIFdyx0EAgLlJxxyB1VnS5GOtfZzA/RTBsPn/FR7iBYKBa10/hLqUK3rZL4mN/RY5+r3FW6gf5UQqQ4SOh3sZSGjGLv7oy18BAokSkCDM8AD9TL0NrKcE2FjjuDWwePVA/Oh50SQfJ8Wn5afIuoVn7kGzLbl/wBn4Vq8URed5T0NImN6uHUKcCXqjvSMdfjYS4J1+0oMODfOAuHP7AI/EqFf7uHQyVaM+KJ28wtVL5aZYy8wBYNFIir4NOXkLgtJnNyHVO5QCnCxKf3vU/3S9bqKSI1xz6CiBBythcYGftW7cW0YGG2cAohTt/abo1Up18bN5x5PrKNsOmEbvKzasqdeS45NkULEhE4basfyyQSehlnvdBiypaj54nlBo3pot16QsZF7DVLIYiKuTlVpfc006d6jVojSHMwc84wnmw5N/RrHSj2yRhRgnUPUsPtkTRz2EussTgivB0fK0Iod4ghTtpGQeMuhvFMkugo0GCjfa1cjtbbg1/VrI8u2CxxLlBkXDm3+9Bc/vN7V/htqzhspKriwy8GCV01NrOhqWp+q5spdU/POP8i66pz5lsrdUlzpuQjVq74lF8rt0AYgLtF7otwiuc/vODqUSN8wfJ9Io40RT+wFjThFwLEdv068B4gsXEtgmOmU1BQFRWRlQFclVIWv7OK+KuSU7i7cuW6aFp1m2GjHHt/ZuFiDw9F7wVDHoVyPxbTEcI6Be871r41uTG2TAb600ngWc0PDsgFwpJ5aV6aqghgAi2kCLCOKKXaiDBLRA6rXtf1wLkTJ0RoVOlgnuWJqPkJs3XteioWeZR962kyO6pb6Ps3gKE4WE6qIZQ91g0+ckFPaskMyhzMVnH41iEcOLnGqd6M9ZFxTrPRktjR+CRnO8NRYRh5IDtu9nk0lyPX9rdmlUIIFL5NB6k97jy9SN1fGanlZDZ8t2zhThOL/eQWQ9G77qDvTa3vn1WYDJlJ+RZRSsJEkuVDYKjvroZ+TOhntYdedDRDZ+LWs7VxXSuqs4nx23NrJfUwcU8EmLr5Ivsk9pP4/COOu2FTvMdiS4GQ9hFJ2Zo0PUIzUOXdpQz3qBXnqvgftHRvFSYUR5ZDosXcTh2dp99SJHBSt0T2KcOHIk1I5ZBulkGyQusBWLq9hTHd7pxZCmlBkvlW+9VJ1BSkfSshM+U2A9rj+FFiQa5syJL364tAAwZbZMKXNsmpyxQLor2SW3R8Dn1zeepeRjX44RuVFIXY9KzKP7fD3tVQMWIcxnKcoAlxe1eCoNbFYVoFAvnvkVn03Y8JuO78f87SAdfzqdZhy1DOiae0XO/COQhBhwmyZPbQlnpKY5uID6Plt6tOL2upIBvF4OpoVDKkEbsNceeRuV+4II7p/8FHOWG9FXMgAq0aHQ2moVBP1xk9Pdy4xgNFW5U0jCFv043shuo++zIc6pDwPUiWvZaPskbdbuX3digBn5hAlb42jOHJkFGrRNFsZEhi+q/93g6D5Iqjvj/cxke5wmx7cDhLluRqRd5Pfc/dW5KUOOmuI/5g1QnHPWPl8gvRdnCbzXRvw7m5qOqn2fX3MQ89Yh5oJacESH1cIqAMZNKSjA09e8RAFZP79MSPKpw7QQl6Ed1p2LJ6kEkebGV7FrVCZ69RJLEgNDiPABxFCWeN96qUman4PJvyjOTrROlUuE+aRe5uww8sp+sRqsbVh33gWWbbIhm1w9pZYVO7epwYFJaChNefVIxE9cFTHLLCrcfvSGq6ffaknfRr1KzkYbyJcrF9qBv7veMPjdh+ecJAZHKGBgbCanZ3mcs+7bpETH8uvtapeBEep8KbY2jL2S2dBCBr1CWiVbyr8AssFsH1qxOxhg8ET4T7QZT6tFVx1ec7Yqs7dJXYgWFX3fjyCqLwBQzzgSDHLu7i8ocYlIdoJJuJz52f47i695af0Q3wh09y7TLstW4e3jAN6q4LegzX01pNXtuQXxNKDCMALCFu11luURw8DfKu6GiwW64Nra3XIOAxd/ITQLw/L6GqY1uI5rqihpZiIqF/z0teWqGn0y4HuFhxABtfZ8HOILv8FAiYnM+ixlknPMgBFUYm2iLm1G8V5ZVlJHP0+pROu9MH52l2gerf4ods4TkbAnaTkn8ohr8NP2A3a8ia9hgMfPIqzAI1mE6K1+f2zEFF754izWPlNFAXfurXkAENpdjYrmq2jL+jBDxiuJ7xZLfvxGx1Y6fZKIQrFmYaG477MyBen1Uqmhr5NZtu6IdqqTReVRbTtPoUvalFrtKLJ7iIe5gU4LUt5q9vUhPwrAiBAOOyqNmt+S9kxYQpBxQkqyLuGxc1YaM0iHj0HbzPJBX1UVBb1Kc0KNNdXF5h0+XErFNqiiTypKo/IZDSyodm/ytAbBvmpYN2YXota9zIJpNm1iJDqqESfuQayg2NiGZrqKbG+p54xMD5Em0ihinqJwM8bGsKFsn9zcrIQ7w3PIi/wzl93d6+A+X0p5tlPrEPG29lPlQBpgl4FlwYZ8+FhIwHJ+8/q0VhrDhdn7ZIN2mOqoys2NDBZSaaPE/ZEW7+DIkWHJCaswX1G22qLFltCqxJj6M0N1k7zclpYGnSQHT6e8AMwQmqVp0es6Ll8XUIh+nwcH8OEoYXC6L1tyiDeBt0HQizkAWYCX1RJpZpKji7HDGYfQdENClNlFi1wX/StpeUw6zfyeI4qaNHsOkAvldwNW32ajpMmQCTQeYNundAvXDqTYlHBe+EDAFOBQDVxfDMSbmwW4NjoUX6ao7zopFpOtnorHUeez1JsMUOtNQ5FSINvy4pM5/e6xqdX2M0E5b+uQgGddsfj1tFdyhv2fZYDfFk6/OWhpxzVNwsrqOR1FBGQRB8urONBczMJBcQkhfMTftWSUFGHG7RBklNrpvUqTVomC5Ck4fQjPR3vvq+af2iyRSMNFgBEgHXZF/9jEd+ty20RzTx5OGGWKDSaocmPt6F3Wu66HBpm0UrB9rD4J8CLtPcmiBtj54HLDW3eYSjS5L/xeAlHfcXgTBqmKRs5SsHY/R0sSYWye6XwoERt0hk9Rl2ZjTvLkvH/ptTFVJ4Rzl+DzbSU3J8sQTKE09oBnw6HdM54jcDUibNjPHdOu8/fAaJIdJZoBsbiXHq7mAi5/q/90VmkSVCmS/bZVwJ4PlHo/3I0exKtFpPTd/PPzjbkeU9WWstFXh+9EBj8oMk1KjytUzytgN7I4fCp9r4jzNO/8DW7DHR6qxgraxzVbQwrUTHpipHF1QqS75BilZ5jIBCOH5sZ2ODwxowCKJs4xGDnLCCtO1V6miSboMamiYSKGZFG8nfUuHbDPMmjZhDCxg9prB/niU2Yvf3KrpB+FqzlHCL0r7esZzTjPSGa0DurIQjkmVQSX8mttx3Tf41GaDNpHzTAZPmrYW9NhxB60xKnBrjQPFPnqz0sdFINW7qSBAkYW4nI+7/25tmOxCbJVpBG0esu9GBeS306LDFjSSlMxQwTG4aJDuyGJaPfhUqFjVHu75S0qThOZUvUv/r8QBP17xBmYYfom7gf1OCBZiMY4vuqX2dvYEPzjRd18/avsGelumNhDhGYmtvEsWGArN+AKZOCPgJjibUHtvUSuuWpgR/od1DFegE8xF+PKM0IDbuZCLeBdcAx2EEKwkvvwXZ1cXZFnwn3RV74Du4+T4AB1h2lVseWm/+v/yw8D/2DSwOIdUf/Sz38ETFEZcfeF7fDAqJzqDWDBZJH90li0YtpxIKu+/Li1SFHDo8wyeeV3rFZn38YYEZ+nYSZHH88O/WqnpsLs/HVLbY3uenMrXXjMBgZ0Oy79XJUK3pbRTg4r7TClt0w2iqmY5QPOOU/MA4DzzQeg5n9HTlRricBHZmoOjcif/KDxjuHkOyniYk59A3OJCjLqOzk8Wi4TfhVgwPMcaqQTRYhr7PW/y7182JbfI8yfZkyD5T/tTvd2RW/ZFsHuujX+ncQKkUq2mVEKsk8hTudJ1oeSAPCEkTe19SZwSMTRi7+1xyUScOGcXCr6re24iP9Huj0g1KIgAADNftm2bdu2bdu2bdvm72bbtm1bs4hZyDGDJ0bv4JmKu4Grc649yb1WRYTQVDXa74VTuCQy/TxGxEKE/64kZSkDSnD9Fzmuw2Qr6U07NZxeR7A3loIh/CDYA55A7GIktXX81uxFY9qdP8lxviorDgN0nFtCjHunlo90cH28Yw1oc86UAAsaozU44vsvmUwbl1ONYRK8y6qJx7mUOp+/vnGEhyr6IcQC6kIKaO3MfrVRHkqZ6Lj6NhWpdZNnaoniljpDkKDHv8gkwdoQx7y5YZ2aGM7VxBoBHb1bms7nmJ1XHip3ozyYz7wU7tt7wjD4UPEINfcRaanxAJFNcvsAWuSr17zgIKk10M1nEs1djiPN60B4I+A047DPLJkbq/7SwaZCgDmvg3B5PZx+1uOFfBxC0ODNIv9t1/7LJAPAXrTtEY3xZzAQz9cIKAXvvehfz4JTjjz4S5HrefyCCKEJfZ/Gq6vwspBXEfZYEmy5jFbnX5tMhl18tQS3CQjWUxZC2ZUXRWxy/G3hj2IoQ3cAUx5cszW6gl1Oh7nnvHc8gPGTwPYbE6Z+7pp7tjgAETFkggpkXoNAXqa+ZSXMb8nfBZL2wXoqDzODBBAz3X2Hf3qkzfnhElf+wOXMpNa8GvoHDinsgET1srj4zbXw+f2ypasbXOGjQ6wonLf1PJ/cc5P6Q6lXxOLPqN20OUJuZ4MuwVLfETCLTSEFiIn/8paB3YMomXy0C9Q6On4PYQXfpwfMuFnM1Otql9lJHarrNw2Ay1edR/IR7smat5ZtkjfchLn/6a7OIJ34VayB2e1S79veYJ9nVO3xSf8GEqNujXW3hBzf5MvKXZcjFhpNoj4Tk0VGX+EgxHt3SWk7x5x2AGKLQMa9qiaY6102RdYV+pNqkVGBgG9IqhEc5dMQJJz04dl/Qa/rZd5lnxRTNodoTWfju6dqWWIaMB3/S3MByyq50dbj1la5j4pEruvcbaq0wJBW6ZgoDoug4zqxt0KZbNLTavpUIoPqJ34K3g3BkvKdntjmqPnORddoRTOglfg4NbXhxovtCBMJ2USphcz+dIGOlxbZqGVMQwXJqg9I+ajwquSdh2MpPrScLkm3kYNgKaQieHx6BpOjMVvdFWPy4L4ZLVErYin2xJBG5YVJy6PQzl1IfyGRn5ZQa/R90NtrmmFhxyObfgCaP7lgt5L9r2BBuSxS3Gj0aF37hukqpram8xUTeU/P2G6tAw7kIu/PACsQYLcoHRjhTJ2R7bYgG3L/q9WBIiija4JnmnRLiKNVP/TpVBYLK+bKNmi3gAa0Jq1qULT5/JAYSFnunIlBKAki7ohneWySgSGBOKouRvnCFFK8gK2cHj1nf6inUXPiKsvhnaUsacfIesm36iLbn5twt9LTuqmi74ZJT9+SV1G6vlxv2G/lCvZxmpzM8K0QF38C0xoY7wii7w5mPxapxO1KZbVFbf+u9mtkxRinf+GuMbFFwC2iUFLiqNPT3G3n/Ctw1ZiE8VCOwEAci4VZb6eqnQflc9+PcRN4HlBjvNQtd6Ah8/7yeAazyHDZ4V3jxNPWIWdtuh5XLMDsNwUPMxilMHShE+27+q24LeKDMRwz1+rI3IBwg84ZBwC1GQyQqXRyEalDoJnmtsH40IGF7CnosIvRJEMMBTa1Q99/koXMY1aWTeSAIzZCyf9ShXuYTdGPIqerQqt5xzS4q1JXYeIw1+Cj8KfvW/sdHpwaXazXnVCiH2RPUUjEM4Epv7diZCisu8ga/4jNxgYI5a3Xad/1b0TCvLn0esVNkmeJPEv/sUebjdv16iApF8jjEb3O8ydk/uFdLg5ptP8YltlZwjlG9vLNDerOgzXA9i4WLd4OkXnqgvyrz1bto+aNuQ9+rLl4Ifl1q+x5F65wTeCNff/Xz61HNfYfMMKB0ZZ5eWro51r5b5tlfW7hsDr3OCoTGVG279slkymUJ6BNDhCp33zR66lNlasKYW4zjfzyr0EmAyI2c7YhVsea4tJOncZYIuIfK/R3xftQDvU3lr41hJiOMzxg2qgO6XvNbT40qKuN12caX6chJNMmn9RmtG72z2XFovfolSoS4gcvH4Yg9CvDTIFRCk95rCIwDWQmlL2WK/lO5619oUBd3rKc8fDBhkrV5TaRBtEK8/nHF0LQJT6l+sGIzEeq211ppGufoTeD/CyyG4jFY3woi4PyUoChy63ccthwX7WuU20/ldJCrMBoa0KIp7c5lA0L04ZLNbZYLVfFSwe9B8cNqeYdwx5ffgnT4tSmngw+G/Jc5XdyWpnU2OKMEotFwROs0q+v8mJnY7ay9mFQMFpbQFKKLIW04CJIUntFb+YRSRwcZqKJ2pDw9PAsPdXmP8YxSPyHDvqSFT5KeHgxYCQDvRKH0H+LLkt13r8KaFrH0rBFdRkR4mpB+BNefJVWvP2+P2hd4m0pqimgnJSQgcjrlqAsSsPo1keIPWvhCW/e23dnknxFPSTIv5+5MRvh6XLSbCGlF/0ypXD/vP4sPlG6CVW+Sbqc0bhJCqCHQhW2Sq4boIN5hI5jVsFORwVAnWWLjlFaOxHOjHoewyqDYrtaDT7HuDurQymUa6l0NJXo6m7iP5GbgGUzqZOX0KDh1TWZtuP+dcVebWOiXDmBTOj5grwOxeppCiAg2t1kDmVRsLshkT7B/5MPL+dItnx14y0yFun+CQHOcy5Qw42305alumySpsFBy5eKn8wn4zh3XWBFUJw6NDSZNlEqxC3HpfCJ1blS91VSHUceQ6zIh/aD/bXboeozJmTk5/SZznNp86bifW9KK68Zypd9ERv3qGbQ4Edoz7zZJeXi0lYV2GmMc/zwa/5bNVOzs6Ws4tCI46grAPaqVfda2gA3sN94BiZV4JF9N96OJO0XnTYUGVVITjo0rNucKdSZ1cQOI0uCCWD/pC3hU6cGJ3b+MVHANtXGtCrUGN65odz83FkRNVHVmz5tfX/2EJjynzyridV9FiGVLzz9KMqWWP2jQanT4X6+g2qDPbdvtbwY1Zou1DMVAi206yOA7MWNIYM3TIADpNPxZAtSOcWIuoiiVLHXvGsBKBddoDvBmz+/X3jbW4jY00QCHRu3hvVmDX7ZB5BrwKyJJ4Ek5LW9opelysW6wikeJ1xYMvLYwDL3KiDxKRn56nQcweuMbddzoHHJDYOTwHnfPggIK9NC4a44b0cbK995/OvgBoWQh8l6KVDROwKG3QPPZVB5P98WNl1fI4Zb1OuyQDnTxzjlMGorWZ+1zTTjOHwv7tjJAgHFYAuhAOEfsdamD1RRHQlvzIS6zXkdcV049hHml2vmH2iywzvuLXaHx0NZp0JbPG0Cm3Qd1/igkN1jxZzrmbewJMwBENPxp8qcnGe+4UrWhWd1iSN+DVkyEXoo/FYp+IS86rayw0uVaZYsyLd8jWYUSkvrYClTvCC/nAuUy7RZuEr0f+JJEliNHjPAzbU3Uejf7wQ9uru79j8L/W7NPmWgzGDuej38mUMaqcs7Qw/LLzVQY5ZXmAU5dcufBLbzWJoiWSBVHih7ta4tZzoY8DiFgXShCKjlNjUfLQcSytZ7QvlDVZRjpPd6ILDkV5snlWGzUrHdOCcsds5ZTiHNTtOPBTY4sOjC7XVlV9K6ZFPK1nFHsMSQ1Op+j94DIJD3ZypVLk6pf5P2BGX9MJThWeqD+iUq26r1bNHbbRZzMTBK63C73hAzeJLfJCYgdf28+trQ0sfiyvaCk2XLmiLWeu1u7X4WKxB9F5KQfG4yIRb10e8TpV764IMTwA8a1DLeXtZVd3wnf6VizNl5SbNhk3ZwuZxZdvR21fohAYpq3/xc3WRs33scCI65uSrz9S6RNMFQMp6rc5YxEJGRK8qS5uwNpROpUAuIAepunXsU8fRoqXhf3A3ZBmo/4LB/l/9swvjUoVGcKPUZw5MDUKNsJJAM2U03lJyN1H6UNbcTXglDkfNLqyK2tdOkfa+KHwPVqMscendwOZROpsQkEHgzmMN+rOp2e0hfwQsTiHU5fJGusjgapLltr+vBpT6h/6m7YLyts2u1JUkDIOAUJoZKpegA91xmxVWDwz9v7gnxEAeCU9UF1tUL3YF7AYFbHVZ5uGZiiEcKPuHfEcid7FHHxV28hjeGD1gXszOVC7LPhfA+kp/NOGb2GGLkYaO60r/35evIT4qDrjAMfenoyF6D5VtuzhCHdyGgnyJU5SsaRZmnOUYcjRWngyGc1WC7YssQ0jzjo9JoNGHXxftfFuJ92Scm9YxDVPYaLcSeFkYPOp1g+Tt6jxeqS+7Un4foQlWYE0mMmgrS1xn4WrZtoopkiWG0dQeDze9YPADavS+iXgt/y0UCm30CxoTCEliX0d5GmxWR67NvF3FDjcDoLZCPkl5axLCXTnWFC9/3DHO/bmhrWqFdiqEef0WoM7CLsyO9jtjgSS9FDSNU30u9lA2Vfjq5FnYE+GjBJjYTV6TUuqE9jtl5NwVPafjw7ZB1D8ztVy04dMe+esNd6JpexuDM6NRDJrje2v6ToFW/ksFjNBRcIXzMAb1WCZuMM6tfJhorEA0+zq+1BbGHZJKh1n7x1r4d9484RL0395YwBiILx6LvdffVhGrPVbKj1uouogJ5u0KqUlDURWZtYyfdUW3xF2035XZwCbAaFllkVVXTMOwWYv6GnxKhGu59JWcVHJVWn4G37qIHNV9HF5HBwetUS7T0hG5IcoseOskMJbwOG3QNPKwSMlQpo2Wz+gtw5wDJvkpKMXDcuwyLNk0Gy+BOXGTqeAUzRBNGyAB0leEvclJIkLwXxyszJQuDEboScp4hWz3NvYK/1jR/GiYIkqVB3V9fDc0ZBcUTFcJHHP8E7saHtXdAzsBPbHeMtbQr6jp5fkGISw8iMxJUFS+h6Fc+iJw5h4ZCNDMr5RG3bv2VWj0q5o0usyu0lMGQFBvSV9dC5APZUf5/S9imGzI97tZA/AV5n8jme3EikM4sLBez7/iSc6jJoy9HU8+o6T7iaQLii3Yg5xhMJwnlcSGyr2xWzAJWhg8N93pnozkaS3GK5q0R5p3REIzSUEqOmijtmPtaJ8nwco4v06dX/FuGqT1Y2/FwlaRrJUpblSCBhf5OW45s9ZYotoOyJWdtCozYkO6uYNfqkFpYdELb6nmkm8ZzGnOvYFiLH4hUsKFT18jtN5kdyD8PSh0QvIepC6S9ZiThPG1K5DLMWLQINL9/1dVPugHEnWf2Mi1JRcMZCcAlk+D9iGchnGnx6tFIJPn2p0kY5uSavcT4kMeuBKhR2jbJ+BMQQONv4FpxxM+ZTol81eIh9nbAWbW7iu6WOlQR5HEORfKO9rQIBAmx/vXdAhx0J+erjphHeNotXncKfZCtWw4kesx8eFk2N3xgWtzugfKMfwzWd6H4c4zdZvGHFY0T5xptWbSjtWIdNAqy1DCPo/RaJqqleKz6wUu4aaRhtqGxGrPgYsyPCkQxcxGFKNagl32y/Jubmoi9UdRDTKMhsGPLzPUZzhAIGNO2ZEgg4tOLGFZ4Q9TsIPR5UgvSxNvuLuNBFYjhMKy4QkHw9x+1sZFC8gxBZSE6IFqxLLhd5skCTqISF7Fey9GT9oSiGePRMcDFjld+Zbie2NA760OUXDy+abyvnoWIvo8qmGbWp5CSEJZBHm9JLhcZKfY0LYkldpGr02uG4LSQAbwrn51EKJVjAJkDgvaKvEQPPn3k9OkUjtlUUiKdGCiACDS57pRMxgF+ZC5BdxvRp1zx3wUL0qomVoF6S4V9SgIf53jHQTVkqn9FCipeRuzRwSei95082SfEDU/vyxZwNF4dlNBgih7SHJZfxesoveo/eCtFXJ/Oj2aVUfhc/UN5GnwVWoLFNtOWpW5JOh6e8PJ+o6tb5wKURnyPy6gBYrV6HS4Q9qWR9wM88ttMPZWdhh896ykOaufFJpP1iPM6kKhfueXtUciUcZzK2KE47P1QKXpOZkxKvsgmlqOqQ9C2pmv/SYzITO1D1NP2tpq9Iz3EcB+YKU0AZzGFJyiZkpBF0dQeQu7rHjrgwongNR3OsvSpqQfgwogxBZlvtH6IIv16RXSAUMfn7TP8+gq24eW9JRKcXblvHobAk0fL36Ugc8aY/qR3pkOWq2OOBdXa2hLhwaKq6NSqB3M9NgiLQAjQ0tSz9RQjF0u0d3r/U1/ozsWwqzKOgjiLsZ0v9N1ZkHJzGb5eKPRHIrllNLS/pSewvDcad9ZCSB8O70NEwmVbDDCxWxtDOsATBrbFMmbGlMhgoxqmu7VoQy9Oi0QnByg0i61QPSadQ45LIclDRQ59T1/G1cJWq8ZWVkTTNf3xU8ZRKSRU4fuHUEzCN93vixeGITE60ZuDFSoBG9CRERDEsAQbblJbsqS9M1PP7Mk+J7X8dPueVGG7UKvpaeGLXkcxSwC5aM3Pl+SxlDVY4TBmTALrdBHObal5RUfrBb3k/bMzY4OhHQBa3q/rcKQPy7ueCmGCA9CdljFg5hEkTD5kaqRkNP3LiwAAZ2JymEJLLL6LixBHvMFqZk54Hm6QnBMBSToJbt9A+taF66BQ0ODSuArmvRopNYxu2FBXG3Vfs5ARTcUN1g6TMGThCWFN1U75KKV1a2eaGJU0TXgzJ7JU6T8BzoxIDWV/7z/uQREXk6RVJanQau5vpVPY1BZZHmW1QIS8a7kl7agzujxVTuSLf/AocoIsMtPxU7vq9dXbdq+YRlWvOpapnHmqpDJ75r+jLklc1VCSnaiEnJaiBzqtwhCEAGDzTK0jlAn3ODxRo/Seo3BB2Vg/JiMeC8/TXIdxQ6VN24jAdzwcDL54o/jCJdVORkb7RFUzz4EMZGfrnP05lvIizW1rv2LMtvGrM5pSd0iKNH5I2CmmjtN1fTJ1kWZmabd1ltwf+B1l7q2wZ9m2O/MiehF3CrpoWQ+kdE3FuSUI0onxnwCZFLvuOJNmgW+l4ZLbYVGaUhByVuvoNru0CbyYcqC6nqVekhtd6D9ig61vUjQ5wsfvb+UsDSLihYEZEMkurZpUtlvm/sL3ELfTPUT6PQg3mNhZ7wbPchWVkZqlZbNBrC+3HmULqIkTwXie0GupFeO+1iPogl15R4jqw66eglrLuj8oFRKe87zSXy6SatB+63+IjYK9yraX2iaxA7hqmQgJrGBve0140609YsTV/PA/Kxb0+/IHwYV6IGszcm/MYBbxz3rSN92STrw9LTU6S3aEildEacHg7iX9I5JEl3rrwAnWgjFej9fncQL02/ayumUy538jtBKdMPTakcYsW2M1fqIa+E6z4hJdoF0LoeM5SXihcKMophZB7+BgFb29jLPpLOtctonODVqOJrKcVkEH0nIjgBMZJrFuNElM+F7D+/pXu5Ti0DAXOSvBtGzKfmVCE/peCo/pX0f6Vx1IpOwh941Qx88X0i7wEjusDuHsrbz8onkQOOKaxbWGhh5R3HG9FP9iT8cis7uuLeq//TTW3B6dR+nKngyUwO1nhs/XDmEKR5JYlTo3qYrm6d1qeUzMgMddNxo/UAG5J+5YizqaofGCuiQHYvDR61N0euvNJ8bT36LjbgVxAYNh3pPCiZ3w4OrKAjanJZ3YiZNPymxcesFWJ3ji4IJji6BObh2GNCtBGZeqhn9/2OsxpG49bIAN4VlBFSqCcFLOkKSR5RrlDeFfFQ3df3QTPDq4FYVTD4Y8a2a1t1GwwvkYhiUM12CK5a59GJOWcXU++GK3SQZN5m5ZLoxRPtpJq5G3EvDHPxjX+Uba0V/Qrdo84vy6fisg8BbCf4C1Xbs5rvpQi4pN9k/2Qhz2gYszy2aYdr3cUWqeh8e114C241zHbVH6NVsk5Vp2IO8i37CyD5AH31Bt8NL96kIf8HN2uO46LZMCOUERgAEx7aZ9/TiGxY2B8ygwY8WHEGqtd9Twpflvp4zSZpyj9zT2S9saUTXvMkAwUFA52juIrBaLpHiHJ7rml/k6pL1B6wiTQeal/qHj7/BLTnVw1dSVOYqc7jUknB9OBNVZayd7ItdSfVFaazXhAW5bq/EyZpOuCKgmp0fwo3sQmkbopJ9Fqd3VeQObYONYsd+ve7iagq5Z2CAvgr5hDwwbZuRtOGyEgVynh5CwUNZsl3XRmJwKvsJ10f0H8jtHCf6OQRk8EV7k1gkvT/Kl2SLyu4jZpmFtTRO/w+KTTnN1wRV4M5X29wtorYQRW/D3jSVA/raYqa0P7Omn7OQfwcnThjncWUCLpBSv2Hhgu38tNKlHLO7+0wrzFZ9I7M49J+5jRMl7UZSyR3tQA/hhiVWFKs7EaMuhExCSS7TtG3z/fagzY+jQApGjQcN9/KTb8WmURTbI6qvkYtOfcXlXvA8YOcbxydWxPlY4y+uKlc9VY2lZAyW3OK/DR2S6iL+7lVr1dxdldI5NAfWkuQast08F1g1ZkGRiuhPqZg8GljmJrRaSybM3R2BzEViXTg+I4ltejFg9OWXsp5gl2WMSbxcOddqdjb1vveZrlqd9VHRfFDCSTmKvHVvLzBXNOSWPlX5mpCzlYN2i8cSat1X3IwKGGEjT+3zgEv9zU48gg2SpMIaeL/fM3qEqLWxIM+MKxh2+7q02a1x+hSdKzDCcoEUC/nXkXijQeYEMxO68RWka5F02IpwEA7eV+Ov58mfmitNxSkSMT6Q2cqD/J4bfM/zdisPPup4b0O4/mMckxkLWy4eq6s4DMbLcy634Jf7tSL3tcGWf6IlQR9A1aiwUENswfpEkEVWqmJ7ZOmy6PyRufhqgNheTMsBwa8mF8kNBOrQWXcNMyw10HIF7ezQLe7tqFEYtW/9YCT1xBa0STv1oH1Pyr5smWN7PPinV744ualmrJSo/9y+bNTfqNsVWwWolaVn93XVNvIfJgVCvVJmGv5iAC7gNGJtllMh7xJP5lypOskTe4fliqmy/k1B9FMZh1q938lFC+rgjLhhFN3V7jWqZkRbJoT0Ub7boB0WOV9yEjHb+ISrjTdwIu7h1UE5MJ6B8Dn1Z7DiYHyuK5D6GUZg7PYk0XDpjmys0/WYzBmZifPG/lHGV5k1ErquV+DvW7aVr/ikdTROT/Zz796bzfhtNKdfsrb9MvBLc24YoXwPn2mo/FhIu0DKIY/W8f2IqKym36FDrNiv4O85C8xBIH1oKqD/6+BmbSLCY/myt5H65Qi5QqKjE0w0zq5aB5MMeQJWIB2BkyXkLk//xgporo1jeufa/vhVl3w6XW5jQE4o1FTt2EQZhG+bm1p8TYA7RUKfsbmRJfVvilKeKAU9VRTGndQbA5I+WtDu3IxUPmqXptXxSsjBzsKowF703GttPFjodNCzXYi8CARuoc8+QelVx1qxLIPrIWSDQuJPfQWV/zoY+EMbRR28XG0btJU3SyAdUFA55fEqxBegSwBtCQ+UGa8IoD3lfTAIxHo+5N8Pasaz+Rtw1ry0ciWQYSGO70pYyjlo3RMOVxJIM8XfqaB+zC0JapFLD/3XS7ZOhd0fNe+QinMCvEicJv7KanS/JvCMenjRPW0QPezskK3G9s4BUvjk9sEVLl/r8bk2Ihl11caG176TLs7dDWzno6VafsMkPt7ED/XKdfonFYRlX1gPfAmkkw/pMX8DWNyL9dINASpl7xQavgOptQaJhJFm4yWbputYnFdBuW8L3DWzDURkLetnWz/QfSlZ2lNK+EV2MnSTtMD6VV0cISh7wk/bCpUHD8HZUOXaM4jIYn8WxJrtg/zgyFqOQGzG5ki/l7Ct5bnOgd9w9ISa1JftGkmJA4VzBLXgSjEX1PcFxJ5I1ym7qC8RFQyDA61Y68tbhO/z9+5VR7OawI9WYw06Ma9NV8WWbWSV5d6sOLkyq8FEAwswzdWMXRZJDraoNEDd/tooo8Ts0TWwaIXc9oG5AcMt4cJ1yzr+9tljTW8XvK7+COtwdGVP0svid9Uevv4M0PAtdQi3KxSMJjUpCBYulQABZUiEB/ju4yuN47c28rqlELCciGGAg6aMNwXOZEs7/WXNMM8JzVTqgq3iLjmltAMNf48VyX+B9JLELbtlqEZGe8806rvznPbyPlZXfgdPtRJIl24r6kw5WdYmSSo9j6bh/knad6ydWBn8QR7hrwR/hLWBKlbZLxLPozbQSPDpb1UIZWD/m/V1ocZ+5RKW+nNcN5SSk7fzF77EpJdOyZXtfPC0/3c+ssFZSo6Wz6DN3oOgfzD5s1lQ9ZTc+0Rtsaj3Q/RvvpLHVOIb1zrNPhe38BLeani3yX8kVUT6bl97NW7yjSsbx6RuxZcIzH/ojOdKZ5b67J5BBd0unmQXDOqJ7ia8dn6HFB4t6cmGeWBWwLhTnaEXQXWY1Lsae6ly003qMbmZTi975KzmabIxCVkgdIXuoV4xNUbT2hs08kKlOsNlM48FF2NHBYO7Jghp5csPJglf2plIu1wJLRVzRCq51i4Rwma+XVDpficotSEqUe3u3KpLRmxo9N3TG3R7h8GkgZOyKsgc398cKmg3GT1p/zsxAAUl1kC4HIA2ZCjQ21jV9SCwWSVcxAOrm/EnBdf4hhTJldgmkwOlVw4cVFqoEojrelphprrguOSTYl+etS3FTaSJ4YeTTRI2fz3ygYUuTqISoteHC+lu/EotUKGWa5wiUtYycCWeUZ+dUUq9pbpuga3hMptsUvmhZyaz+W8jjuycJ0e6gP5As8+YuF1FuftKH+VmwZmJhxXkHpD4P3vGlBlGlYCHTm6Co7K5+4LcCfCuxQSqAgvl8rT3UC0yPwi+rNnguXsJXcYBNOnYqjj7E6KdYpYbTal5I0ckSebS8x5WoS3/mGjr07YYwN71xB6E/bCrY/EuuqCVNnY9qwNAaOu4uxcc+yDNv1+mWxmxUaKENu6RigQn0nL75vSWx80U+Gt9k9F66rDxZf8DzYg+8EPydAVS0V+isH0tFcm8b5gq4EZ3Dlfjq26v7DZ3kj+IxfmnMbojxTRj7KRLM1VhVk1jH6x34FtJzWa9KjqocTimV3gFcupbFoOfI4PhdEC254dElookY9QPyQJoV/u7HKYxq7ViWo77EnWDGWjcvEzh4q6UJh1q8G7mvXIBY1QiwwA/9p5VCat0jbRyVxRi4s2sqLQMuKNb2GTunKkONJ0GNpWu9aWd/KpGDz4POjGkT6jkwiJ7re7r1Pq5V3QsV2/Wm5+ne17FK68cj3dIh5zMCA1mILzcHZNpTGqAs++aU9OsXOx+m9iIxUDPvFKOaxzpDiR7UKxr2gB6c3LFwbJHyUZZomMX86DH60F6uhxDyF56304Li1PchggmUIKZxONUJ7kN56r9le5K4ScGc4sh8Cu7pZOzQlhm5N0qFLHT0SCFSY+pXpFe2yW3VXhakVWUMb7kfiGMUveN2XQ/YZC+WZ3LbjqSDpzh5VR7UuqEDV8ifJycO7/wH57fwmYt2uLUQ6nj3nAXhw/0LwCNb6s+s4FMaiJj85JZjl4WAV5wb/SA0/OAeG43BhEISqh7Us1mClMfKefInIFvoZDbnRepEDNXAUiMsEzwtsH/ubPqvMSTkto98MCbqKgVyD0LUDlq7xpJFX9ZqandYDfo/y3e5IjIY3QpK2N/E/Ge8apBGF4l4h6xbUZqpJP4FNhkn4fFV8iXnE/xS0/8cXtE7Q/vd++5TGyqqmJ3JtYv77b9C8B3eI4WUU44CVnlSIZgmHn6rhzX7U9gK1qSrliPiIuxXV7htT9b2ao+1rs7bLcKO5uYL8j+1rcEZQriungMiefCtN+FAtqXcu2D4OHUlgoMJyiCBy1MPvmLCoNrTz94+ClUUAavw8nJyvbYBuJMWH/he/Z/NW/d8HvkUtK45CYnaNq3LfxSH7nLRQKnhdhSRvxle7jo5ysAHxOC1jDiJbT5ncHqNc7BWeByDiL8vEqiCW8iV/M0JAcWaARjg9UHjLPrPyI0DmwMdGd4nnR4ZIL9JYLaf6F/s6Gvk8JpJ4A5bCQTVEO7DKq+jl7scu1CnwP0mKn8ZSqni47pH2ZIGSJ8+m/BjQjENkpiZz4kk8oEzmzsGth5nRJIZ9M7T/StoIDSqf2UiH06Sog74HvOQigUyUk0BZQSZqcckTtHdq2BruYyBzP2cDGbLwPw9fw5LYKH/8ppGH8EFuBPR/hvf559OAGLxn9fqClwaEmNJkSa+lYXMd4CCoGb43r+2c25MwBA40yiLfZf6Jza6xF6NVKbXRGOOFeUpL9M5SWEhddnnC7TxwlsFOgU4TPlvDLzkkpMq4DVJ+2vJ5tQetm841CSyRUfDtXUFFWikQEnqEfuIUFt3NPK7VqubaWKHij9SnpKuwFrKUHDKr3DD/yRQLLaKmYINtzwGPvWJ5t8B3D/S9q8vB1suBIO1K/0lyM28vffGU8mPwdgANsi4ZqvwVyL+7qLeq43qbVk1+CjcSIKAVfgk6Rgbr9PxdjkX9vYyuWIpL3prqrATB2gk492X00rXEzD0Th2OqbRcH4pFP8M7qsLEvK5pbpgfDNoF8eXeUg/tvWc9AK3WfL/GSbZs56J4gjspESSeQ9mYegcKuDSHfYVdZDfdf/5X5xFXAelDituy/e0z0BluxxS7CWyeEX+PkXngu8uDilq0YqGmhVH4a/BjTWtTWbckpmPTRZCy3uSuUVxpu6Upk82/c/Yw60EhiEGTo1pvyJas3fpHRp8dlDBK8aoge+PhJbZXSyqgP7zOm6BhhtveH3sMUdyQFEeG7brw5BYd88hmeKOFTf6VBlZ/M5LSu0Us7vYgBhiML/nL8kYqgtlxg7qRadkPkGeUgWM5CkyEnDgyH9PZKuTeFDBiTXe4PT9EbEWPAUAS0gNZakQ04xp6kMIOHzkdKc1LSMv2nUMOYp/I1BiCZSa8Ejk3ME4oxVrTdS44W399eBBcvJXEWkUAJkabl6ejWwVooLAMR/pBjXSUrioC39EU/Zkpy/dbAXMfMz5B/3ahhmAWlKNOmYQw62MjYWwWMozRFy2zKzlDutbxk8OZfHQQQYLKLL0ZMvxdFWSI5nTaMC+T37+hy42/PoferUFZ7ZCVIdQ4OVSTiTrj1GnciMdKTAvNhgHFq5Drd8qG9K9PeyCu8U4OpPG9vVi5FDixv0qD1Lc8P/a8F6gxOT3KS17rkRSc2lPjIcaTuDGitwzv/xCDwDh0GL3EebxkVsrpmb9MqqDI6FpjacYIX9qeOF8fwNQqhM7WZHj2ufTQu3SPMUZLHiCx9YGZw9YhpiOcoe4OWw6u4YmiNGoWBH9fbiaPwbXKhugv3WbEe1CN/yjJeWbn9qancET0Meg1edIESPEz5Hyudj4G3A8whuNpFNzjyfwIDDtxWePduttKxC3QdOzLMum4xL5cudEQR506HEqkpDX2WRMRwbX3I4gmDcpObEZ64u4uiqqpGZVG+GscSFLvu6cE2E2II90pVEQxtylyHh3kXZA0z1h4V0QiwlJ7r+veZO7ZGvhQyi2qwKQfjow37ycbKtxlKm6Wk3SUi6yl19z0jp0oe/bGkO8cdB+uSmUXcwiLaNSpmDCfjKh0QTyuFweCiZl92m3OE4/q4tFEY6bLxGUq7qimQK5Nt/QyQRdfknWtEP4Uo7lm/3uddPLIb5E1redVeRC0SK70YWJQlKDT8qPidO5KTkcPvQ0QZLYxyr4pGol3NjGnfCiH2ZkyUqU0xj6MoYkXy2QS8mFm8xx8WCHH2rKc/RIOw9g/KD3Wc66GPgnH5AYs8rOlSbbOqOfAZkUxia5kv4TLx/Q238WiSyjtzYg0q445zQ9PZQ53iCR6sWU6c66VgYYKKKIQhcmY/Jdmizr0l7UoNUP65RSFppD2n4/i5CcZZ8XAzpqEcNcuBEqH2xwQv/RfGXMEjsjUnFaYwNI+vRtEGeCtvdKyxXhielEBoz7hJmZT0PWtfUBUVwXIYg3b5Qn5Qh2L6pjm4YSXW3ALVjPM5vUcSelWlPt9oTayfe4ULjoaiPVVypUk26pXVp6EWkuSubMrK2N4tsE7fhJib8aG7AFROvQcS/W/iJxpNVyVxFIEuqvL9hb4R/deTKRYzAAiFSgop7nFqqkefi8CZH2EQiYjybqJ/R5C1zltR6yzV6O18wPo+CcujeHd8c+cePPR+TCWStgnAgsTQdY1wlz2AYTuFIIFWz6o6CuNPHepfkFX2gGV2mi7ImxZonJTEhiGFdZKE8zW28hPFQ1mZxvpckhEgKGZWUxK2hb1XakkSyzu5Puc7TjuSn39Z7xSb5KA0Phtp0t6ntnoXG4lI7c6e+tfj2YFSTGpWTwxvQ5me5JGefKina6MdSCv/RNvVJMos3oDBfiwX8JMH3JlfFyf+OoWUnN7LY+QvmdhpWei1i8zpBH/8pojv605ayIQk0+LGgXxSU6vclH8ZotpcLxNxFVwNMkjmhExGZLgi8Zd0XG9D8dny4Nph7n+p8NfPrLSdfnI0UOMUF62/HJXJXbb1cm51nMR6D1OA3rvjA+jmDNOYYX7v03g7LER8dxHYsZCZDqDk6nWcHXxFOl7TyKELlXPybsv7tIfGNyozAKHsSck8QwFXfohsxGyNL3YniGOUi6bUNx3DJsZxbtNQzmPNcYGDQVcRmZ42chj8TumaUtPKy4vrO8RWt1v+wtJon39uJZhIVT3trtjEJXJPi4VuDPDO6ojCCGy3Oq11ylwyk5PJbt80hya5b/juQWL/eOTyapZ2/82CGs2M9Sw7CsEke3IH8QFaGxfPgshPZxSMLhKIYLYqf8w654G6ZG1wKv+Oh9SH/5wwB9cy339TzDC9d148OzqDDwwSFmkDUSgIxj+Uy/2KcswMbjWKOl/e+IGrDrY55W1BibtJ8B8XQqe5JaEX5CsrugJGCnrttwx1vQg5khD/4o9LzvZ8sypGXYeGafZd388rryEScdLm3PQCvH9vOF/pXVuDEHX5Hg1zERzU/oi4lVjIzRs2D8zMf2JlC88DF3GFnJ591MOLx6p6cdqPD+4W1p33/Aiznz54r2JfJ0wIPYOg7TKqf0hQucqkYLaxZqsdhKFFH4bhOMwiDVQ9U1zudHf+7Dfny9qB+8bwTrizOHXhby8T1locQSR9tj+dUu1Hsj26U6XpXAhOLMkAm2Wo7xO52oeH4U04qB2571Y8Wf3zbSviedp0MM5uHuRuU2gCtNpJKzGXdGrl8jU9il6NPEZ6FA4YmWi7TaDkZEEkrrsAIfL906ANFH3nr0wnfqNmUuyCs0B/htBDk4ljvC1G4yuZaAS/svXQ+qZBZJWKC8yrPeWoHRpzG+OYk7ncvNITzhh45dh7qHWSnK5f1skLVLViWX7Vwsxs29OZQxApyfjoTTaqvb/0OFfTvZbQD7ulgkZ8FprJ1vG5TCZ/pg73UsNbIPoTIyspDzNxKpvBIu9XUG4UxQO0B6iPUINnaxUS4srT2wUFAnrKzoZUsKpcYDCRrYYAp9uzNO80IYtlz1l/WacJCfRnCUhbmzEYxGX4Y+0khpc91LjY7DiMnbIcz+XXd8IMYCo+zEUX+yNth/EMnTMZ9kOlAWg3MV6FgCxbxj8Z/Gk6qWl8YCNPtgskBicc8eJGK+K4ZOD8wcWTywNX8VNWaqRrxdFQRTPVEaXRLEolUVCQAmObZolq2jD9lb2muNi5K78HVgnzUS1vO1HRO1cVNpLKASqK/hFWBPv2YtE3MoIZ9u9+8rsTORgH2+mCxprPQN71pXyReqe0YM7dRTuT50QhLTdfFYamwZjMiRhTfhaZBOcDDf9BYoOPTkw6RhhtI9543qWEtVrw32A5n2vwcSxLGnxaX1PQjqbrvRYmcIGEFsNmr57a9uQYLQUP4veNbmb3mrfow9SKxLdaK2ItE37QDGxzhgYKjGaHp5AT4LoUT5cYy1v/IS/KpNk9Zsdy2pegMFzVKUG533PElm6ZuccuMwzO9RiWlCE7xWLdSLY1PQYSw6SZxzTg7/3UxwdtLbezzWMGkHf5segxKlVQiKWGdNoX2HcZ0NcN8RNn14uZ+TIYRv2UjEi+n6UMTMknjePw7vtu7ljIh6tO+CGxZpQJ2BmwywMPjT918xjS+riKV+xNhRdgk3G6p/LSiG8fjBm0LQH7ydW+iKUhKDhJxTgmFT3PJZ1jnEZgiDmdAyQkSRS/uru5pWT+poTF/+1IwuGoBpKjBAgqvO4ubTm6I0H5Lsq88h6thWfzbO/+Dt40Ojn/aALt0+2y864K6GbSfDXnauhzNj+42e73Zgl0AHOvgjPgaX1LxrobsqHrLZqgG+/xRFulv2q010dIA4gRJSZHHh456SG6fCr5pfSdFAJKRsuPwHQX/dMMTpOyB3zQjMrrH2wvjDG0Pfu4xUkZN8h7w+gp3+VpUDHlfGFyXNiO6OLhq7d2bIYjaQxm3ddQ8h32O1a7vTlFNjdjwbJSAMBVGRzbCIzR3hhPCjJbHeAuyQIbF5rA7LjKuWX2GoV5IbZ9Hf3bbqUST9mrKy81EkciVcHCW8zqVLswuviz1ngEk/7U0nW3+T1WXNulHAA2XLJk/gGasNyGefKFnHt2QyNwP2pfaq8VTalsOKu/JcmL13oFJ2R5EPbvpisKCT/cbuuLC8VG3y5rtuNwTks2g7cT/cIvlmfnfBD3oEL86KviRLQ2oC+zDoE92jSubQShX+CfVvvyp80w/7o1WJmCZzYy3muzyvwSkscfsNgwKjfrxWhVuTB5sdi2/mK/UZ2xDoULgl/hsgRipttRiaI4YXnJuXOk/qcudXyjhQaC3shqpTeqgZs8jMWQPKalhnyKoWuKg00MrLWaOPMuadjkRHsjHtv++gHn9bgKE/BKxdRoGIcZ3/QXDeBRsYrD1le9tg2W8V82uBfpJ5vTUIgwbineTl1C1k/6fwDYfjdhJaQDjmo2nGbT5ouIzVlNSDnLvAZEEdf+Wn4L1xp74CRyo1aUSHFJbm4xWKCrNSE/gwQwjS5MbQPLkns01AfTrjuF4XBJEI9Sgj88G974PzLr1bXd76C8DHIfupErS6I/wwKkVqZktkkf1tPtOqxduw/+hRe8SemEogFfi/ae24WSbjizCOBTXnhmxJ7Q8uuXVHQSZkvtG0AEgAfVVkmgqQD7QsamQ8dbOBpi3HGTDoDXsncYru/4R72v6E97lDc7v+qxftXcr6QyVVRRrYL09QbCkoTOkb2YnpvuaRh/ho2Vj4MmUZRfaaWvUnhM54kMovEZHzQxFiJhQOwSv3eSFTouZLbWPPCSUKdMA9krCLQmvg2m7q14gxeFd5C8WDdpJL7T4cqvGauyWCuRrK2MUqfh17btZbxG+1N9Q6h/rFGVf12slm/OK0u9ym7diNcK8ozdez+lTwzfD8zrwUcq5ai2b9bQ2AtzzuIdJMvaVGSr5QIvXqMpTtH/4NFoRu1oqFQ5zgJXRIp7IK6PhrmPU6hrbmaoIEvko/jxBnJxlOwDL/Zl7NfbvHzraFFFgknALk/NYo4BhDZpboel6uCu+sFL3iszfqfwRZG9K1HY5RMQT38vslz97ubSM7O+AXEF78PTtszkGytetrlub1JT9SvHF73/UKNoThFKAkWz3z0mAjEDR/MZWrinxqsJJBuKYx8hUvL0XdfdMuS31jld9w/+hR5RrZUr9DQAi0AK8YOmiurjEKEdZkwmyBIJFo1hO7j3/py2x45KSwg4sqXAZG3Ql85EA2YxiN73buUp9tbvBP4xNZtbV8J8Ryt1QBiASO87Z+pFhs5Ly6rpLbJdQF7L1UV5R0k7+GClLpHtfFKA3FGFkStWoQaXdySW0xI3Nz7KOi5EwnC8ISstGeO/ScaA4+rZ1rz2gxhecDB0tmcMnNgxUWcXpo/K2llA6AdYmL2+/TSgSFjhRaTxIPIqM8hpp+8v8eFEBBeld9B6fktKVdWukn4lu0AnchLGy7ZF8kgsK7JnoHGE56X9Bky/kKRE2G/l1rrvMFHvQdC5pajX95gGdAj8J8ZMJpsktWFLEEiKXGIRnKPv8jFly0imD56+DQHJpZtMgvu9dansFjcZwDV8FqnGguEWpKzkMApQdJ/jgkyv+2/XXEs41u6VnrlEQ9PDfpvV5rPOuhB3HLLd3bHkmw/+JrO+fCxI9290pU41WdNuac8BJhB5QyEuk5vDtqcBo7/pngXkCPNtD7sqzSBNpYVM1jr+cChOVvlVwyoWECsXc9+thRxwbmSmtEpRsjVfSJmUPsfA4t5QjjGT+W02jubzEedZmSG1redqRdfKb2QT4z3OPYC97Ac2uauviGudnTQT17WuaNsRtAAPu1QxJ1tcuX6aZuDjBtsQ5QE8ZyPUJIYP0nydy4Q5Duk+0zZBZ1DiQv/OTLkJnaCLGjrw2O9REDXv7e1hhP6gqufbmeSRXwIqtEUK1ALOc2KcgWn/WQhJbwUNReUZ+jrz5vRdM/ElqAp0xv0if1sFuVDdAAaDoPp+Qobq5lcn4uZ59J/2hclKZoDN6N09cuAql/VQOGFIWk59blCNT1VJ/6DxGMdN/7kdTHKxStlUQLtHDsgroKXRnFwT4LWf8we+wrq0WqnIG55yndF/LXn75OOp+HM5++UHuHfOnEqLNfv6rVqPwe3/IxYP3UNuSqvfbzgUJApuXwI8X/eu0mP9iOk+ZuT5SIYqUDWWaoo2kFlG2vldQdCWXAnuzrphZr8vsmUB9B75JSM4L+uwPdeng8rrNttLDff9TrIkkYiRSzCPA1XPaP0NxBq2LRX+3H/RwGG54KZzpVlu44az6KlfB+YwkkWc6d5VccUDlh5PFY+qRrRoNAR8at/LBmhzfCIqTzQhCllwgbYVNJWDhY/0wcZ5HyNHCxYbo60zpVKLJypoE+ndW24eh4AStGJjw2jKxkuzvxEzqSo/xEhiW9EfAAe1XqXuReojsYCdh8Hoe4f59cfO53rvz0CBoDhBc4p2VG5uC4iMORNV15RWHesgAKS65PT2GUfOi+HFiT/qi8oNqs6ehv05xfAIk0lpQZuOamT53L4it7kpyPfxeU1+Witp18JZQ2QBnY08puo4Vlzw/RMzTTGAh9JNvupGRWjanTlu388udqDF9KEBinUv+avMdeAOZpzGCii6ckJZ2ePFL3LXng4PE5Q43lIeEzfYVbDRkoXKjUufxzrBy4flAsoJsdWaVgqnFZDHhltICqN+fTO65vNSNU2cvBwf7+81hRWZ+MT4vvMtQ0UMlc8D9fJeHMQNXYR9UNpKO1RsVnv40PyG1fQ7beKA6RQd8RWCWKfjSKM4OocWFgQqLSTIW9f7sI8A5JzQmIzTSclKJhf56GQWZtVXU3WZ/cEJwhVW2QV/sJXIsoEim2KvYjyVbnV2VgGKiUOm8hthVAq6en3vsu3NWMf9Yr+cLwjYOJsOLE5xgBpSmxCm+5n7lLjkuC80efZG/0nhYvelytxPaGjZ2OUYVZLnFGLomsgveivTsJfyuMOXlHiOh8Bi7vjGA0LggSe3Ki3BOkVl6nd5KeFKoTE+7S/YUNMhn+6FTaH3OOk19X7BtcDtxAj4taq869VVvw/OXWCA8yVndRTTZP8XlLVs9C/TlXs5lgeiUsNJrkSsIHv+T/YxCfP8MYZqSh05SZ5tJXkNZoUfZEEkz9L7j4LNw/MoX8K/zqaVMzlr6rymWd6d1iz9pfOxEOoiBzyzJ/TRplUuTzcZch7Nhs3RG8A+SuJxhaDEWac1tstqFoK13N5ub7g903hrfX6EyCt+hlBklq9sHBBxF8b4zKk8ZWpaCwTv8GxRGCfICyo/4lccWD32px4SkapTShzXkeHm/o8PU3R0fSsNDIObaIbkCCKj2Kk7D+lxfO3BAbjUNTjFlRsDixS8wDQVDsIiaHuUM2gJv1Jg59gMuQTFglv0cAHB9xMapi1oEQA6x0gK5KoXqZb+iVd6PYbThdoSHIOUiClYh2xiTXRSn386etbnqw87pa8Sq7y0f+FxHju024zX8x2XVyy8H2JM4mrLFSpNg2bvUX7Q0WPm1oMT8rY5PX5E6SUkRaFjydgJZ59yCvRQO46dqjkkE+SjWcFexAk454f+0JXyUu6eRmOrSWEQBOKS4iVVROvTttilWSOaG7AhGOWgJEpm/DHsgAFkgdlri/lJpWkd0w2j4O7xdFeNEwfot1P6jLBu3TAW6l8GSPltv/tP3dyopYMqw6WeIu3Dr076d6da9J/eFhEZaHEXnp5hyxnUOV30SKfOhJNvKcRsl3iiAtcepVV0RL3D5BJiyLqV/RB9p/JZEcAnRYNL+jWESWZ4eQvznhGfhqsyfFg6plwFzKaQetvp+Q0BAgcXDY61syL6tNeQBEBg9UAFvgW9kTH6f+iZOf211DuZAPsvd8WTeLLGYwiKxXSikCKR8QCre+9ZsVoHB0BfrWfT1nNPZ00ocjuhHAaEuQFfZJAOvRHc0pbqR8SfLATvMDvIJBIiFjOrO3AkQCBcqMgifodMAQNJthdlCR9nfIAzhqNg+oniKXK2zm6WWqeTOZXH2Oztk+jPrBSSWgU29U7keMmCB+NQrTKYOm84vuPCFv0fNbP46dY78DvH5S72aZNvq9g7sztMPGDOhdHNHOJj5jEckT616rYKAz/nPClSxSy6Pi7mcBJpbiUbM0BbrsHAMDNu2m9+1N2wi2KINHJAVtCR2LBWVTHcMGjYxthRMGs2AumLemtjgQNFNKQ4oTqQNVbW1t/kd+mIdXeOuqc3ZGwDChJ3MNeB53Oz1bhGb++qkKZzMPEeYTSrzmGZ8DTodo6owz1rgoxn0IO18OC1ieZQT2+hhxo71Y2lt2MHOWLwg08LvyYeWJwHWJ7VASvP2QGGPUvLMf/K6p5SBUnWYxKlsxl7By9NiaQr/RcvJCIBKL3NqPqPtYEEoxcYrXmpKy2whBbxT+IpmnpQj5WE40IhJnKNWLB2KyS8nHKu/TEQaYeKgXAh1LgOb+6YWqM5CZtH3OkF90MuQezecF4E/+ZPaiGVoQWYQSR+VUPEiM/Qa/rrKJTj5+Qy4+17poRfut50kPKaeIFWhKBBcw0NLZtR82qeZ9YNVYpYdufTq+RLWny0ZyD+a1rt4N4IOrU0QnT1wvPmlQmkTii9RKCCz9a1IpZ8xt98HgAm38Lvf2LsbK3pN1gI0Q8DfMUtTiuhkSyLR6Aj0RpuXYstUMn/GLsgAb7XyXjKcooEdBfFJ7YBJHEYEisIxWM6uJQtwyk9+fRXn73uYMBbGEL+cu6F1n+vzGXwjlcRD9RrwFt3oWIfCz5Tlq5ujBQqSj8d7qpETN2iZrrltlQHN7w8yfHbIG5kO+0hppm9TP+N42ad+pTArfqOcIIiYqrcGv8XD0xRSmSX6j610Y8azeObQLEplrblKuS7NQubXhFw0DIhvAEow7P1RZkXWZA/jTmATYcRzo2mH/SRP+Wl6i0v7BRoORyp+nxgLY2pziDzA+Zwutl779L3REoPFsHBinJRJCkBa1KxjP3kC0Q8zu06KcHsV018PrOh+fhuAcWQVORJcKyDLQyGTSg+SjtanEbh26l0s444MAg+Octp/Rfpwq3mi81CVw9MIYPpk3y7v+c3ISx4IASSyBjj8giKewiEkXG+/9f//+p2P+KR3xy788924Vd6IMcB4RMmE3Z4WHnXunFFHj7YRM6mkyScVXVTrsYQRxUHq1vyZxS5k3EwzkT5yegQIlkki5/a5Touu8JLPgLcgHFfkZCuSgaEr6sNdJLghmgKMlj+8VtEzUnVFLw0TQk8zXBpwmbIrdrG8rJTSkXxZj3/qZIzyvidYQzU0L1wY1b/F/VKIwg2uQUldMtPEvSpj4yr8bLzarv549WBrTY0KozmE/4Ev0b2Wy3t0yufkjY85U276GOHFr7IR2q1c79d4Fbw9oD9dLUJtM7aid+5xa1WQwrsk7yvoFJBLddX59AVgP/YczQOtlv/HqT4xwecwAe8q/nR0i9pnFJ6auxPKtay/OkrkzqiW8BoWsKE2L7Ajih8UMJ52r3m6eNdlFWxZQH3vWh2eptIkDsf6Tbg2EgBgAAwBgf27Zt27Zt27Zt27Zt27ZtdYgOcpGjX3kekvrL+AirgGBI4XDXVn58TFT4xFUMcZRZZTdETojgvIxisZ0nyxdFPrLQWDR6esJ9wV52jVJ0LPLRQ9j7qgHzsuHLrpVDSGJ7Yjzqw13w5BBSmOKw1vKVajR1rwTrTLnQOqB3Kq53MNr2d1V3jOOMQIZ6Uogkc4C6tkcqphhtCtenvNqnoHXpH7ybFvC9zPe7An8hW1O2FuWfAKhlTC6SecLz0jtzWdeEVr9eJVbzDGPW6lXcDX1FtNOj/fN6zBFLgKClRr9avdra02Gn0Awi5wEgoy3azNmZmNe5pM8h30r9oS0CGX5WBHh9Oljw1BGBPEMZuNMlThly/afZ8owlgIaA+8w2BIh4bwK/spVESZFCYmU4z4K5Kiy5lfirCRPPEPy8p0EO3BkRqmuqyxW+Z52UpNlLmbY9TDdDmZh1T2uzjrspip5AYDOBWt4FQJ6HPU/rjKYRQnLZtpnrgDdSLiHO0kv7qtVJC7KyBNvBfqi5a52nBaAomjRXUj4P319mRJSYBzWsr7IZN28tva1TYQZ1IFIIAASXACyqZUReBTbbS/aooBJh+Yn4GmNyborwwhEaBpY7310G3N7DBjm0vo1tMaXd+6ZLlDt9N9O9wu6alxHSklQRRqLmax7tVT8hYnJI39aWT7jLf8E/ezrgOH8PUNgjSaBbO556e9k+PF6ybwjsNYhMbPEf+Bcer6ViiM6UWS1mQCy23P5/fxH/ck6YmlRI2tRdcJJD77d581LK9l49eqBEJPkBLKPsk3+YSJycKKrH5po6ORp6TCWOuJN6rz5JS0Vi6+atdARVfeYFLxMdJVgE2uyQI8hlPeSqzG/RxdOccD6b72vK567ptJMLNnEM5icdMREaSvqsfMLPBTHJI1tWukoIYZWWqPTAfAcD1F40vTPorT36XQ0MJnApTMvYMxY9miNN9DrhMNdZH2btgCTcCByX33WF5aIVr21s57fYaWulNwuZH9sYFQK5k0oORrLA/6Fadkg/rM5J15R9zMDK7SP1wKPQhisctEi8HE9FwOPGLze+AKRVQhF+7oFbMD6D6GZ5Zp+vdqKF+fMucClUEIfGfusK32+WYusS9Pv8fdSxvUbdnfaeHYiBlFYGc4ev8Q/C358sxaN0hSBY+HqcA2p95xg+0d4unKnMbkwlAWWNwb7bke/ZI7AKN+pgYKGyztYPazRgBGkT08IIpJBor8ZCjdd9HERhvfjLQLoQcXYi0jsX7BMx2UhQXFsx+2y1ENkQwj/tE5FJYIkyGRdZgFEDYmoSQsuMkvJq8haprtO/xez7hDkVxf2DYe+cHg6XiIdQZ17E6tsW3P2EBCn2YL3M5RfY8KWRBIKQf3MWYhWK2spT+HBLZJkUZT3uYj2lcy8tRVFSYC1jZUP6jTrHjmbWr5BqFZTz9t+9kXb15v0LBZP7TYQA0UsrLBCLPNtuyuR7x4d7J5ZQnTapKmZ1kqNw2ooDxHZ1bBsTXnqnGf3eWKfGDuJKwOJ4154IaYqwAKW95YsCUA1rJskJypTgRhHQUHYHj5/C/U04HH3ugoDL4hZIm+N5HMk3k0YiHcKgAZusSLoXykCJqvpMdDdc6m+47EHsYkX4fRkVwFKPipf44VNXmiOr8SR7lOeXPdzo18B0I0z8xFSjjulLnfWR2KDNHX8c/OQo06wwCq3vX0JCQ7n5uL1218y0550oV8Jc1+6tBH6MyLQ/fjaokkszmDAWvfR02fVdMiT20j7vOGsWHBKiy8u/dmbRhbbNXP4Nsb1PbE9adUWrgqA+yZ8FVMwXrLtGKcdqdVXW2cw6sPkCDNLb7ADfebdEGv1VCGPP9BbKAh68/2ytSPs0MRZlRdU2fjcw2/wmhrcHkRcS+1yMql44cAr24wEEXmmVtGlCXDQCZJjiB7xUPN6vziCtPc1z7K0KqdzSJQvadhlEW8J6Bgdg8i4IMpOeV5X++q5rgxzkD0SDyxnHWIHbvDG2RvpHq33vvjPPAnwcr+qg0Sqmgu5ZZdaW8sfTRkSrsZadjh41Q8riJ852DGxjL20t6S9tIkKS7I4hn9NpQuxaTZ0Vhn0A8Ylk6ZRmGpbpeq2/FlZd0CbsafZety6RDEnMOHJtDfHCLkE5l0qT/9ZIDldkrhYBAdnOLuEdRlAzJYl0Zp1Cs/av96zZ+4serMApgd0x3RYxC9EqwZXMRge6IKewCpo5pxTMgo+BRdPAfkYUFIiIell9sCeLKy3bax9K9nlYeC9k5RVngJyTSF856OD9grlpEH6RemnIIhG/f9e5EQZfsdBGRPsYUJyXAYUT1TW7h+KW76qQMQXlOHmUxhC+EYyEBOfYg0N4NUNWwsx+K1R0e8Qx1x9ATEdLEF531mFBxc/Pjq4a5scgjRDkCp4L78AdRfIPMTE6bYZHNuyY6bEFdFtltOjR/1vtPePg/d7ND5gM9OmKWAV7+5KsOHIXC9shFcZYy2TmW5kdxk+xdaKkKQzmcAB39UbW1PStcfu6NYo47Rm0H1sD6Nvx3hw4+Q07Q2IkYpdUW52TVP+KrOStV0WZUaNrjTC9Kx70Y5fyXIZNXNgLTKRprP+0Ivk02snmDFBpjtSzIf1IG+9dtQRpl384abwbKex1R3FqOLOb06YrJ9TYNbqxUSH8TJR5a6N6SqZMeE6y403ML9/A1drw2cKCCp5OHKEXlvEOWTUm8BzIUfWmxo5b7s8Pmu5FEO7TuHkZxtvxuVPVFvyIDNxwi1PglWIUI470p/B43ncUaXclFvk2+JjgUv2kQ+t2NX1d7LUUpiHkNW3o70eIgkz88APThrjZ4hCm1l64nbmF1OLn0RPRpYgUZgEB32Ok8yokrrVE75Xn617cILo3nrSS+dP3Gr5h14vUnv7ZWGj5eXZXNYd5C11WUKBZUhxlKSnGc3PK2ezwbJA1aMC7H4VrJsq16CpRJ2QEQx6LmrVJzYFYzmxG3f4PRy+GE3XcY9gAwZqlOecDKXq3M5LPouLzfQSaNEBYCRib3w3uQWIWR5Pds6LuZHHJEvsXf5pzt9gDIc9qn3wn90LrqjQgtO7pDJ6FKQJZMPoRKumCX9RypYNI3tyZNEcBxun3ELUE+Khstb7QTHMLB8Obr1ZGKEi7tV7oZVkC8iV+iRUBhDu5UVMa/Yt3UAGV2ZfBsP3+xs55Bq5NYftqOwJB9qSMTlU21yfUqWxW564itqklSM5G7YdGbcc6fq9uciNYdhbk57nKLkP+C1dIejaliMsjYc2Di1B0ngT807RnTjJeZwpiVcXH4O3BessNSztpG/KDn4p9I+JXDqW/LdASYW4Umfn4vKJxgzpXn+k+WgbJECpw5KXjX8FDSjbSw4FBBWjRjCY4BeEbBR//bO5GO4PH5th4CAUtaIShbOjRDkvi67JWQ+HVP8vhlICJLax9pyKRto/a0lrQjVG5cU0CddaHxwyfLMjleWOnEW3RGXow+3UdOysVhsrxTRA++HyRAwlcAnlBbyw/YCqzRvo8sP12UzSp/gbCC7Dm2G+Qot0nQ2N7dPg1ZXFhTM48hGPvzOBN1Y1PZ7HMLIlZmSXWyXEf1ArI3p/HolLphmDK8/d4XYONKyE934Ii2eXjowuYYiPgHRCMC1PRDCw0onbe/mGxHNZXlHU3xs+U8q2vE65+UGu0qHq4yvgxoDPLr4a7tOl0GR541Dk/LBjsD2nSHCf2tumat3qrVDQQ1hqPSBqlvJaUVTg9503/lWt7d/FMPCev8HT+Ys1KImTT+RxH3tVLpPJQpfeIWF9tsM1eNb0MCEF0L/ruJsR030J0HgNmQYiwcJCWsw18xJOY7MuGHznJaLZjmneT+pYEwPz88brl6Z26rAZp58X+l+NxEL7tzTIbIPsgBc7odPnfjbej1g4Hd8c9U+MxAjMGYEng82suD3D2ROVCupxBhbgGyy4Abutw80P2QA2K1DoDU2Z3UqFNSZXi8T/+KFZrHvGvhkzNJrTPlrDooIPAgOU+JIhIjfyW5QYcMlL5FPFtoTftIIWj/Pif0RTHOjwPL2Tu+qFY63Qs4/yxAitBF3a1wBNFGAUl5FX9Rfo1aLPI41ykaLlqIYKSZLaM+Vt0os/4GTRF0hmvbJbWgjuriCl+Jtf9kg4+lNZhq8TLI6RLmpH5DoNCQ+awCIw5XZKLWnYtel4BoK2skD2F3+a9XuX+JPGywjaNd/BVg6dbC8Ff3hPKJgwBnj/uJP/69NqPdYwM+pCWC+ofN1wVPjwwLf/OC/z4v0oknQ94XQvvqiyuTINOiS2wL7LBCZCWPpu72Qqq4cZQh2Rbn+lBIVbUL6AKkM2His47waVSqOrSoH+mj6VBnokLya5JWETUBq/j/G8r61r+eYXw/aUmAHBiDsFZuKGThc0i1w4rEu9n7jv1eq144/lqL0z3K0ESH9ZHjRQTi4YSQzqjjmC0eN+DGxCgfuehEy4fuIwG2BMbi0kUlX94Bjed3N92dHv0Qmz4WlX02Kla8rhydN/VuwA7iF4kIAdEmnZ49+4IkglgVqjCNxIttCj/4F8A4383JXH/1Kq3D2fjRv+2Gzjhbt/UTeRmLnZxqPpjO1SIzS2NYMoFM/vlD9zutxJwOvO0FinOwCN0GzvJ0EbM6mlqTsT5F3/ecqmK+IFEfblvSfH7q5DnwJJQ1BrhKF6gV49l3SUt3DUJBd06cj+NbC3WvLf11wkA5hzurOfQUCDm4aTRx6qlNaS79+jSxXsxgokKWc2HpyuG0utEwzqV0+6daXo8hWvguUepEw7hf2azwCdDWNW9NluemZTjrRW2/PkYkAjSY7zYLn3GKDmhZB0FyJG7cRGZ0C55sYdvjvQmW5awk6aZoBREWKydr6Qv398mHipyMHTlNz+Mmd7/+e4U0s5wVLCS66pOCFOdS+wAcyndNygGub87dbDYOsabqswHuxj9pk/647uQb7mQCnkmd7ash8moeHlP7v8JyyWP6WuPC2FAO8HNBD2Tk5BytagaN7JPDyc474CVgQqgxbp2b9B4tU8cWUMNzF2OfM0urBPRnPy0BtX01s48GHo9n9uofO1JVtQ8wQZFCx3ToSXPwgaPbd8kAqTHe2HQAjz5X+NL2wjY2gNmAZkbcBDMefoMtURfHWQcjnJyBpcZFFid9B7mlGzOwXGshjZ4rqBz+tDDYf0Aaqsp40FUWGkICS3eBfbhd9nCrjoZZY9YuujRLrs7WXongoEN5xeMJAtaqxfrHFuQ6Y2hNehaLcSCc3ayXPv6BUt9IhLWkSSPrO3AvRDsK9/o0B4EmL3UxFcFmed2u1LspCw39dB92ESgJ64brfKUJa0mFu9/8x0osDeUxrtGKcmrYzHO1FSnBmVLRKrJCKyC81XHIdaZPJUQNpNy9AHEwlE5lrR75nfXwKmWKP+Mx/CBOf32r1odNVWRyQ2BXR2qA2SuX0X5PUK4N8RFuL2QAKZEnbhCvHMatf0V0D8C6jfNcZT5vJBQnaUFb63P1gzXiekf42PL9GRnjNzk098LvOC8ir95IV3jO8pEtPY+SqwlIZPmlVM8BynEThnVngypGnhFnQIwsuixVZEX9vpkEyPHGb/b9xlAtgPQaS42z1HdiVutWLAryPZF6Mr3awGgK+cG1jKWkNIz8ql2LdRtzzvgNkBzzCmdq3E153mPIHJUjwP23Cv+Y15ozB/Ff3xv8Bfp243n3zlIIJiP6siWA3+/ehVRSLvMUL7J3H9m4croh38jOX9ZHWHSv9sr5Xz0GnAyNEpaAwA/Ow/JyEVnbNG+SuTm6ywcSyGlxcuDjKyK+LCI9Jpr+fJa/4MzzfJ0Y4JmuVN6evrqr9vAwzl/ozNhcaMASTDFaWWG9cGuiGnvppN/USPnnkOIFbZzSNTczQJyaakQWwSw1DRYRREsdHBWi+C3bOH/HM/zXjwiR+RAWkFjEpukqgheac/zcGGpeu9yBshV+NkGrobDYDuhwgnnd/IDuMntjkukO7ooXU8TvIUouLk70h9qb43w3lwh7TI32YRkFMy3J79Q7S59uYihs4aucwQqyvd/IxaKKYvVkk/aC2FfTcfMc5/oo3IPZx/XprLkUJNv0hzKwIY7eKjscI+ybj2G+Enc3WWQ2gqNLRrGF6Tn4/gbsjcL5UOH4sdhZ/FbkQV/8QPoJ65OqIpb9r0DHfz0j0XpbDnj4bBdin4lgFYmbSq50RDN2LRu7/C3KFrrIJ28+N2iTSVZBIAP+/XnDb3EZsupDLNQovsBjskW9FegtmehGGLRKh/d/osTfYec4nt+WL3JTFVKDyW2WS2LyZeZI0efOoPUrxeciowwxBdTRpO0ksBzl+zpcmJNdzfEb1WOFknMnMg46FXNk/sdYzxacylvld9b6e/HdqeUTUtJQuFHq/wxRqA9RDbKPjxgiKWj1b8wDfxxGc1Jw2hNghr3J+d9FiSUD3nylKQQbKt+TOkClm0WSLtm24na4K2iKyQjwnj3jaxX0t8oEEuoLFOYgF81gSe9NiauE7au5SCkGR+56gAfyiPrUt45bUPSfjAZVRp72VImAeyuL8blHnXLLMWQHFiIDIIC3ORrbrEOuJBA37jAoWjpHU4JWlWKxWeG9MnJJfyp88d4ZHHOwb//luUuyfVVVB8BSKXWVDZJQNLLetNbEsULOXi6Z/Iwyk+F6fV9h1j5EJmsft/S2grauTj6rKuye9KmNxPW8Xa4txN1vqp7frpQpgfrtgmuIHsEKrXtRQGbnAZnx9MwXVM1y+XEKldK0IbEmqCScv27B8dOCxMbp0zwl4TbCYAtQN3dr6R1hW9AuQro1MrGmMMYN9fNZ7O7ZzmvSc3fE2J1Jcjg93Z3msSTZJ0GGRNRXIJ7GxGhzx85jfaFCPQhMo2jB+swncKwiASzqS1RbROAcMqBMUZeP99xnxj8M2FfVhGuXpgow3XtpZKFx7wRA4qwoLyS3Tnfzb+Sk86KrftlKiuJaK6mCMM4sS32NDDLiHN6MIem1XZqC4/n4W7bSRAQPjNb5koeNl7USLcL1DvqSz6+0tWKB+SK3xWfEVGptDzq1NwkD3ANuHxpFpdwm28kpxMJ7CsXyPjYTv7ZvdK3gFTDqtY+O+ByCnlK7siT7I5y8cnJ818ukIvNkRaNF/OdLX8jGp8gjHXRliDC3gfhadp7+M5rQ4yD7xMLkZJ7ZIm6PP8UEoBxnk2tbi3l6W9FULOgOV6qZHB0g45UWjmI0N7bMhgo5NAMtarxZ3MiuhSadFOGeCtGxh4lhAdjNdc9aKSTV56DnFkF/zuuUeIpb1VYbyWUXN67zNgkRkcnxM9vDLTswQ3pkfW4DU/JTMcbkVVqt9uBQ8rPbIz1jL/KU8iSfqcqdUYIkGMxwkHW9RJ+KrZcysUlJ+EAqmudgkFT5Y/DMBq2cGgzjAFz2xU38xEZQKIVDPnoP4ZtlEz4YPb/N3pviXs+Yqav06qMQ1RbprIKKPD79ie8D+kEMI+QpHGMqpgUGEo341WY5Ti/VGE0nLvR7mleqBPYNkEwnioJgqT5VCjjbsyGaA7zIj/feywPSnrHcoZWPOXycVQA97MB1KuDQ8W7EMVmeEybEgUkff6eeItUxTLqXA4q5BWURo+/vgCAgK6BsJSPRCD1huUexASjhr+wk2YUsp2mHdqj2FUPLwC/O6nzTFJ9hB0v1YqDfvhFDAY1LZVoGa8/iLaivIrkf6H4QJ7IfRdI2Sg019t3KeOLM6MGh0yhScH2UCFAeyA9y5Sv1+gckVg4pxEj8PzNM6WMA336W6ZktIcg74AFjC0czB/UwACRoo+lQ4ypWI4ZucbeFdqnOsTqX4cRe4OTFuqk3y9NEZE5cWRQjCWP1m9wrYFqkiT5WXGpPH78ylPbhCuReDkNHAOBdb/p1x6tCPVWY+GigRVMeLP1+bE46E2+E7xD70CJkr/bprizexo4zexIW+Ye/GSasuXnA9S1+SrH0MQr60sFbg9RSZj/KJKODJYHvxluopkTa+ERayLKCy/vDRrGKjCB4XoEINwUjmc84Q67PQlxaWNLI7c+1i/j2uta6t0miOBKLN7lP3kTHbR2clEMSvfrrz1bgtMYAbBzyj8i9An3wuKhQ9aHjoIsYEzcfqW2alN5uke51tO5vYmQp34RLy8q9F6YidN9eJfa3hbFBjN9VB3Q4f2SgmlvEJZVDGs7PMIrCWv9tp7zXC+cokeuQ5du5NO02E3l5VkUvtL2NuHW8+Evx4ic0G36AGM8vRPBrVt4fPbve8CgWoyIhsvtwTpFeSLMPtPTzrh/zrNBV9O5l52KjjMxyc55hjQqXUwCcS8aQyO8yroiI8VGra7ZWb54oqxAV+wAT+2TxkrMVlO/5aEPSNP0g/6wVdeq0B3fFrwUx6TDbWTNbSiOZrseO6EGTK3LdAWxFGLe8NVFg3gSQC+fvGqfyzdL2kE/ZGgTOAK/7rwtptBf8DNSt2hxN5ver7b8Qkiyo5x2zlEAycSdRuOf+CmkZF7Vh/tQA8P2LqhDVcmY/kIoYRDXTXQnbQoo1VrmnmdFS5RW9CjpgvvB55dYYJqceQltfZDppZCYVRF8Yy7h/NRVsaLvFPF4FDrKQ9DpJfe5aF5NSXuUv2L4amCwUyew+QodgchZcSW6/eK4l+UCczuk3O2AVKwTp8/mW77hwa4ZUa58v5UpY9opIPbdKKtbbWbMpW3qD8mVeA9g9oqnUkB0RBGSvt8TcXdVQkBTAuexIXdEymd9Vii7WebEU9WRmCAzd2UT9pBSikeyGLnvBnLZSOKqdFmjCyZNQ9u8tkfmQoDmlYL+wS+9fm+iz9MlNJxoVaHbREvcozS+URCPnSvTkGgcECrDmMP4nmylZ141om6xPbrCrAaIuYcHscT1kBpcp4bM9Z+khs18/z8iG+cwqfbN9wc85qu02wO6dBTeZ8awFrET3xZSVAd+mvZ4bfs0yg8rRwCqNZ8H4q5pZfRHtNf1sV6Gg4whnwj+HlNbS5tbQNnhDAXQ8cJElkvn4AwtAA5ioYGdUBQOiOmZ4HSM1QhvaLXnzJ6Ze4YU37B/M8yaEFTIiG3xbzbQvKGlI+nO7f8k774kwBl+MoMFQw2kZkWTf/6E8AxpBJAkBxoc8ovxhKGopRCVDpoGZHnfWwNE8AzySwrTGf3OKoXibGxOFdKIKh0FOitBWFTVHEXb2n7dZ98ztgwtiMx3psHttn8XXe9tKVD0qsE2AJTMF6YwHAwzY5RXzEpdJt6XiCWzpqE9v77IKzDz+y9thumJk1MdHPMSGDMKIzG5Hus87qgemGEYwv85DFYuBcq17RF9y7WtSFHA5zysnuFfYXMSA6OQnH5aHc6QR9q4IuWFgHmeJFbaeD2GQyTwlTXVu+H/09qdNjRCmjdGx0aErvFP3OJw6NVkcfBMtdudJDnzI1KnE6uMlgh3RydHp181dFG20TwDCFbbUSzIIHophU1vvvHVEioi5DIcuf9+WyWQcbRzWvR/wTh+01XSv97GSmVsViP3BhatQ5QWr1W9sbtd6xt0gIHCAdafeKcwit+Bmq4NHr1orxYR5ykTigZX/3zDKH9Tfj9HCe7OrocX9dW5jqpSiBi2vo+Vzg4ldNu8S7fjn/USZiwr80q4tmkttS2OOSY2Ac+knSWE69wkRAUMBhW9JkwZLByK2Ufx/Qf4eTGZo+plTHxpJ+Tr4JHeoFMO6HjXV/c0tAQTfhYidI5AfhRZqPdYTXQ57VoOCKz8LEaWnekZYxeiy7gqhY98VWGFLQUUn4XkJVbb1XTV+D2CMlWOg024T0B9GMtvnh/xGjgrrlG7bj4xKnuuRuOR66olSib2BPoiWTdyXsDREl6tEYsiQllzufSIuuxfGxQLncCFmvOg319D0usyLLt2SyzPX43KFmZt8SnruNHmB0ptumvffz+lEZ1vfWGzXC3zHO+FBac0/Oc36gsec+CFXgU6p80pazTbXOY1s5P/O8NRkW0UptZT0EdP4ihuyZcfebj6h3Z63HpJwN/0LSVcFOIylhJ80Gm1kRSGwFEJd0QKOw5wyglCgMhzo2apx7L3+GHe9GZPzYFStKnifDjo37bjP6pdB0/EV1g1vYBh4EmkuLU4pFFVjingfdbm4IMqOxBzfDpA4wFL3M6H4z6M12E+1B379uiFUW+255LE0Lzy+EWgR4u1XNC0Pr5CJjVxwWOC4Jjnc9r9FMUmF9sK+JIWSmMw8QFKBsEOyJkvW29RCO2EQ1rPRmhLB6l8F/rLmbpr6hBRoAOVB+WCK+Ma6jpQe4w/x5sBDG3G2LBc+JN/I17S62xPIHs9h5qdglyuHOeLwFAmFGwBsucz+NlhbIh/4pFjw2dG07lQraMCG3E+/lksviVR32IPv4oIXr4Ppq1Bw5nCKIQAGpwQ6pyA6LIBdoBlRaR+qScpz6lFbweNFPBBj/ew49g317/09hpJaDN1Cz3T669Vl6c7vkzSHu1m0ylmUAAZ7+DC74elfg+/PFM8SoJwktN2M0f+ImaTof2UIdxoZfwg1KwiJHy0Iv9kwwyIJD1uW4933uYshkMpaOv72SjIvNL0Sd6h7aa1Vx8mwSmvx0Q0b6T5I+Paewn5pHkBZamLzQw7AxHo0We7Mlk9R71tZuB1K8lB30JOJY7CcQo8nAczqzQDMT0NkI5Emb8Y2j2AyXrtty/MCJX04hqyYco2IsPdiUVaXxAMyuXqaMjDiAsqTpWbumxMXvBCfv/BlfwYZ4ILvN50YNy5MoQgE1cSzKqvui6SQSGjk6kauKReIV19HJU43oRbySC2kNN9Jlgb9jhLDkeqjyAaOZmuGQIBByLr4YevXLGNB7Xm7AUpLf/gp1XZcG6qa4nEmXspyHdIKIUeI29PYPBTlEeWbFZXh3J9y8mpWXax2ZCtCN3m2w440CDvZ4vGyazQtMbTEiHOPknbPNPEkwStW5SJ7PP+GPWNI2cJlU6rSd129wVppbdLqrXCLbJBsgDWmT13e5qopieOwibXNihXBVyDK13ASCaHvvjiduQxX6fHrwMIdhmVfpEJGf2jdjzej0YotdD2e/hy8PvanTij2gmq4ouEc2TgWt/MoVqucSHvXpz0SCxz1LOGzeZSocKBeLBqf12WiTEpPihp9W53+DXQLuBCnQd1CH1snV1uZVhftqeEIM7Cd5rPVv8JQvrvMi2UjkkLWGMEU+uO+dc/38WkYgrz73mPrqm5cfY668E0nnvWp7aWCfaoIIueOxqBQD1+tZmuCj4kwgbtBoPftrN5a8eJTK/79RBJpHZxwUk3fHiFaunHhZNRAe/dutmPGBJQ4ZO2+ahJSjuh9/2ed79qNydyIFQBhUlK2yEZ4IpBMHfaPukE6DkADNcVQskvR/Z0W/0xSUNHdlezS1q3mh9SMWrlGWD78sl7nikw7Yyz1cl06g59yvHfIzHAzTeW033NsaMDJze2tzlrr2mG31oLqiu8XYQNOO+JM9KAWAwmGes5jTgFerHaUNxkrmh+kPWfCAkEF255wMOpvWNO4bEKqSti8jOrRB1GBxVxQP1bhdTWg4CtHuOCIaw1OfEIgP+GXJusvPLACd3MHepHO/9invYXzsPefJGpo3zvafkM6XAKecHxOnFYD366ZzFxNBHmUx4Tez8h/sUo9uEbd9f0OmX00OXrR/oBoKU4QS4lW7XLmsJyZ6gkbpkXlcgh1MVBbS496Uhik73hber2oVS2rw+ElsXCySwxErbAnp15BvxA2jeV4ui9zi4IYPxfqkb5eRa3ZY7isdltgGt7YLWy4xJfgbfhZSP7GTWs0agMdSHC6KBuookBq+Z+YtuObEZOzaA5U9yHnFuUjlumL5ozSqEWMWQGT+fO9Vlcu3Ur7VNeJGI1rC2smBMS+dnkoNmKmXMIcAlBxW2Ixe2Vu567WFjBCybau9drVuRmcVYZK5Jv/eyhkKnz7jZKzlGottffbcg6W3H2E4NmbjJ6gVMVtPbuXGPlducaAK9vrGYAJ0vWDog3tgF0Ss25cx2lE2jFRDoQKeyUSdeBAvIqOPMj+dMtsGlI2c8alnqaDHRbvmTLPpssKl18375c5wPpANzXSU68EmIHIblh/B8xD4UJorzGRGFRoHxq6VOiqNJJrB+Ujz8e70OWKgS2rZ94twA6AAk1WIvDZNOfkj0o/5Gqb1iPWAb49mVbFoSCXvvz7kxEKQDw7F7UgqTi5YNO9f2GFFP+F+AQUolqLdk3QjjRSmW2/bU02sDqYgfTEe0gwPLYFytJk39COA16DXWsaCAvKiWTaU90ahtUiEsZUB7cFRvD6z3rLM7hCPbTq/S075wGRBV7Hlet3B7WIi6iiD9VgeZkPd8dtbEC1BrIzV0igUZcAT+TxU3CbZOD9i8JoJEKkrSoriP578fShKoeU5KMCFlsv2q92GG1WTmZwQX/MpcycSCY6Gw2XYqoWyat2W2JL8oix2AuN3P0FZAhjVsGIYxAiscsdaa6J7LI1gDAVqbDdl3f4j/dyoqfwVWhaG4RVEYyuDb+JhWQvHhZjDx47zg8YUjW62bPiqiJij25ctTzWlwgaALukJjlMWFNy+jFu4gm+Qp6+5USLyGWN2PwnN1loTaDaKB+eTRJxHIPj3rLa7qnBYReKmMuFg/DIEe9vTpIaRKMu1CLy7ueiPJV4XzHkTeE4xLGFCH4CUYjbqJHxOb6ILba8XrWOun77Ne8CUIqMamCHytLcqfewInC5QJlrAAuqpG1DWkELOvl97lmhbnBWzVQNzb19omLLgaMMFP2qDijXkQrd2f1qqyefFb1FipPnuXwB5Er6RhHWoT5tXThuzyyjbTinU6QCkzluUaee34SXJ11NNkFeKxEFh5FhPLANIqu3Gl2STAYviO2BycPt0RJhXF/jCgl+e5aVcYcZ3Hbaw5w4wqGvlsWSckFGhKzVsGW71PjEzkLMgfSZCkkDfpw6WoaTrfYDL3leTjQOgRnDOtQvalULP2+ZYTVFr5ZB8pb8lcxnCSRtUYfkVudrSere+6Tp99+p299WtZ9ABIwH2XD5YM+VF5XCwf4mG5GlQ6Ya2uRTp0j/a/kY9K+4izV+FgBlBUTuDX6bTEHoL2iJqQB2jnNMAyUKgIOe0Z/OfxZZ6tCmNHSn8QU6o1ulNH4LtysQUTEJElr4HeinKYPNPnWg20jGt7sq7lECXRuxjJon74P9omLLOWUq7c+SZzxki+IJStMJO2UZvgLaPxzq+ATNMfOwAgCYvS5as7J0ELuu8PnY+OtijRBXIIXg4s+1/maakxEtgJcjJK20FvXV635JIm9cR7jgkpLkSXSMOI5T/FcbvjhWqRbqJJbjFgyC3cG06bfrLZtDRDV7Lna4v58jOv1h+R3QtYmLvZD0JVQ9JnPfmZWjZBVUKgI2D335ch/51kShJPWzDPiqImGnCTeD4ZsRvsVoMEqKOSqzFRdjE88b7Kg5Ddy3nRdPaKS9zWJSAb6ZpsGyT5I8Vc6tg/QAbijL4ZQ0oeKg/PTTRwmYMDJh+s8tq/BfImGHllrHqAHCT6jxIWz34yIrc0PSsT2Yen5IJ4Qgl9/I2ArXzjFeveTI1JwY+JZs5WRxeDPjcxKD+vgLkl9O+nFF2ih0HT+cVxaZvHCctcGjlA7UUvbiB2q1wwaUD4VGl4ttfCpwy3IS4vMVnwEGjyXDmMi3UqEW1iDcpRf4dOQBK/MbK90h0c2ZevEQ68t/bLhIKWNpFP1PhBr59jkaX24lxIld7za7xRx9JhfVEjP1HiUDRv6z86xeUCKFtgY8mZqrfpQ2R3udklgS/+If9RYXLdEPRw9zqiJmXkXTkhJTh442idcr5MXJH2w2w06LShSh512peMeqHvfPh+9yHPsdMQrAl4wmI0w34R/RwrjQ8T7uwPwB/uKmQuH9JQkW2iYMdHoM8xFGKwlJy1BpmdqdwOYbVEFgv2bNdeOggjPS5vo9/3lupJ2k22zAIvETpZP+wtaerHkvpbb3J0Cczl0hMkQKRml6eZ74xx4cOTrixXRK3v4EHXMa2I/HMoZzBUz9iCXYsIb+QFc6rTKH70tScw7HAg1g/EPNvfXeUsBhI2IFgwv6niTQucuL0r4fa+tpIYnlC4mYkUGjfio76OA3lgGtbcv4McyInvVKOtuYEugikZPs1mRI+OChIQhJe4BCeKdTBfFOJT+HR7HFD4Do9qwQWxm2Ni9xAqtSBSlf/di6mjYyyRDWGOCatlF6iDt+X9yUaxlF+lthzvAcqwzff0mzZT4wXTiAbubYOvsnrsZjn4aufwbKok/+udL5TqEizyZ6tuIR0Obt8bo5O6PW8r09G30wT2147aOFykFFNNY4U+0NNChZK9F7qW114AAoyXSdBS4WdoJbeKV6317RFFCFcaN9r24I88Af1wiyjM21q+IdFKvcAUaZrbgVh58uCo3nKZcjcq5/hblaVqvMj5C+Zo4EKHvouctuvYMDteLg05l9j0qIBwVn4X66q8ABcqE0hKVGduxH+09JtpxVPKdhQM6N2+1YhJ2iV4+QMa7xtEzO8v/Xk1Bjm+qtv0rMOLads82LIOpqTnIeUgDMEGEPeG/M/kD/taVaSjgsuPy4NkJVqNbUsQhhN0Badh/ALWARyomIxZzSehSusjjn+9p+ItilOk/9u0D9ZBlmMhG93XTJVsSn24ZUk8Os+ILCOpODYJ7S9+9oMXhyByJT2bkSPjrjQjXggAG2fPAqjBTKsUHkklOM9qUODPu5nRO8xRSLKWylBSzYcgruAmVC1zQt1HnaejeX+Y620Id/4ok31I6Za7JKuPtexi6Om0C07cWasc7f9l/Sw5AWBS2eCaSYYnKJ1Jqm2HDK2WdcNArX+jddxW+yR/bFBvUeHb7GYjosW88pk6jxJPuv38OFHzPw+oTaUlUhIeCvHkctDm9yXpq+CxLhhAtDR0cRL6lgFgBn/yIlKP609yA3nO3bbziMIpKFhMvBU/QDuaeBky5AGKUxRach1GO2E7sRDOLVbR9hkqjrxTE2vUKtRKa+QaZz6OLyMIi4OuIlKR05i2pnzeMIskhrEg/nIxi6y4BFLcX8RVMuKEV/RpRQjij4XyBhl9N5UU5KIyCFJ4OAIn5CYjZrMqjaa1bJHwnTnc7lFDoA+D2LDEmtWUdik6vNXJCuTn5shWfYuJa2RdBekWCfqQOdPEv+SOB3HZnp+9+Rj5bIqq6qSdVxmj9FbN3C+7RCspMFLtAtvASHAqgT6VaTTYNtF24fDyvJDFuxjUxDenJiGczQRY2zhU164W6xzKwGpbLH/AptyEmNLy/rPL5LvNCYJz3hFAjI1Q15SmdDPdkdiahjsP8Ejeu0yOcgtPSEoMwKLb8hSG1zyjCPDKA+V/PG7fPsVImPnueyvgHXGNeujO9nldtPljC7us3ZysCzlcd+RnbL2gpQXuqtM37LRw4cKj/WqYk6/HvJZdYm7F6+9qSr5h0OawpTDMMlFgPHWwnjcmr3PEhNaEFtXnNcxCw+XVryZ8E32lkajCYxN4CiGR2hKXRqnqS50PK6Sdk0wkNHqXMt7O3IKtpbjQXw5wajXgryEAggvJt6pvJIqqjcaDtLJH0He4lsA9+wqMBoKp4pp7ze+/1O4mwHmWQwwKj4E+K/DsZI8+SRTHuILynuMcJtCe9wB5yQBuUpySrPLNab9YqrElNJq5pGccbUh2mn80dAY87G4XMRGQSrV7QBELCkv0K2dk3Kt1K3g1L19MaR/wd9G0y0KleN9iGU0vJMRRjEsrWSu+R+/n9aG9BHiVaImAEkRa9oj14Ck7oYHPuztqIjaL1RTdosSjzVcJmJT8VAPdXIcxGhVJInW41Iu+ReM8QorO1FuC3stT1+q1drgt/gZjks6QyFrbv+yw9sCG9fHVL0Fx95rynwHyJP6IQZCzRyIPnpxLEQs8sk2MgN0FlwmrqsNaVn/wT96T4JB3sQUuQOdoP9lsTi/S41Ibjfi1s2hF1D+ky/G1UxI/4rP7wGPpcthSznF82SB8FBbaVjpl8c9JHZ7hKLOsoYCjQ/rWvFEJtyVbgqriI+wHoTK8q7N3kvwz3ErOSY/NbEWpsrpIkR4iEOYgk0IGN+bld9I3P+RhuPQs8MOyoVKGfP4pBaCIHezX6nZUtkuokQKwU4ROdgI2HOhS1Hl8ewrQ75gbWXeQVCEhBUgnIhEEL0NZeXCrxlEwCTwAPdWDA0j6VjhWKxsc2gb60+s3mCBA92hSkypHGCGf1OnlXG18gtXi+2vJexEC2jjUQY8RzpPKL1+NZ4LdO5hqxKrB/6obB++L+QCXwEg1ml4K7OUwOWTyg8SDzoiUi33wBBx9A61EU7D+uLkRuPMvW6dEbHOz9RtgoV2o6suZpqDuzfXhcj5kDtlhOhV8B4VuQPZ9hvxrJq1rYmhZr+KrBs3YyfOsb9XVvGKKtuNruQVdBLajJFTpukwVl/KEff7WcldbccqFT2VB8rjZo7F3hoYgnyKUodid2mR6TjVHJK2TiWPEjCrTduAT4fVty+XsxwSTJUoRws8/UfX+FOfWLUtEcOqUJMvJ6/KswI//GYGPf5hv59qz1KxvQ4gxfRKfthxxhRHvcJ0XJh4IAGLvLtY+zP8f11NtrwtvvnAhjp7yhg0bYjqgI/kHBmLsErUq6VAkqJHU6F11zvBl5D3NUSyf30abSRylkPuuSsvZE8AyYP+e1xKuaZfw2tp+HmJZzz3tnIsSIAL4jRdCtX7Cpe/YUOGyQYKrsiPbozCJRfZzmQa2+pyqGBHK8yRdVXD0609tVyFSYTCipxHbJ6OvIcXPOzAhjz/xCcoBvid1y0iPvgMU4SoXRH1uqOKWtPH/sowG+PAZvFWpyQS4VQgiArCqXfdfcS4KN13j3p8/zwhe8MZ03qLcl/6nPtT5/PR2/EqCBQidj/RRRGJd5Tuthp2bCtiYPkHkjZKuyt5umh9zxRvZag8D3dA5xysg3CybUSfA/MJdB6P/5P/JqELfcvMmzLFKKCs0tME4q93ddn/PaKdkZfGvR97dRs0P6smNJ7jWwBl74UgZV7q8nVlCJlYfEWUv3XopsrpNUxAS2VnT+K1OLQmmuAtmSplElssbTImSYf3zw/JQL5Fy56C9UBb22pRieep9ilkqxtrgSdTjkB543a5t5sCdyZzwiew8wEmm/PNKrg0MZthZ4Tl5OgLvueGn8psRrlwhnL56ispmjd6MmGuUxippooU6qGE0VO5jhR7piDIroyfiTM8c+r3WfOjcs+rgiuYipZXv2hMO5hcDKKoPC894RF5vu2WldHMjFQTgTEQ0ypKOBGB78rlicP7jjXgMohUjRJZim/DN1V9FF2HjOL73QE9du9/KM6egHASZbDa6lyrIxqGFGUoDZ5Dl0fxVNVDTdIJvayy2dpUHh3DbVRxSHx/ftLnU0iXVbblGsfePiPKiEtVupiJ57TxJvZe6soWcnjDx78nx/QXR+kxaK9ekJnFm6N5xPOdcfmJYiIRYR16up+EoflsFGYQsvhMZyH5qpODJ4UxJczep+OHZ7HVb3f69v7VAL76Wzaxnyy6WFpvWxUTTsXW89iC4nC8w2XbOP+vEIzxnttKK8CDS6Gk+qa5puP5TQ0pTUeO9h1K3BgJxAoO/4ubkUoXb8WApizhN0ISJNd3y9DQC7qNQlZstWsuMrw8UJ2bC0OYn0h7u4bGyXzjDPRtslDZSIbPjA9uUrxoo+9Wc/JOTd2sQ3EdBn4WoIR8lUlbQqHa+HaT7boJSOco74fhC4/t3j5GnUyAn/0sORBT5IPRu7SHDIRKNOb3SfzhmwuihzRUi4qlotGpjfbczuzaCfxRlsfJ6Hwp9ThAdX/XOcpkp3WpMAlqIqrCBEi/qBY+pRwY9Bk6CDZgyMncegBS3yLIspPvXp+rPtBdYFb65+Xn7iDQ8Jh7ft/8kFOIUqzrQHG+j8V797eryB0mkcmfuWPduGQYdCfIbF06ZxjwU6fqBK1lzN4hG6cy/w4RomDnQEpdEtCy9meVA7HkEArzyJypJQ6+A1kozP4UOaDSrm6KxId8b7VaeCArdPeFv2WLHg4jpSfH62fuhTxihtCdVEt737yGZLYkPcJa9M1MOp0ILco3VrZ4FoLdoeDqy6JUV5li20Ta5LCh9FbFosZfYzRTpNbxHlTCATP33nbuESpCzWh3pjYTjjsUH8LwURdehZ89QAfUAcg62HU2nKZcRbj6A6gX4ArTGeTRtaAiOJFWHL0jCDqUk4t9RHwjqdfq9/NlYxBIjWYCkSVeXFs2KdAMBQy1nB6O16tAG89xh96MfLO0qUEq3bOcc1XKIKt4T56PhPpVnjzU4HFs8cVF5nt7M5MWjxZOK4d9g8xd5BrxkwPn6tu+SgufBd4bRel7gDCJCq9CtVYiqsX1oxCu51See91Vs5QLE2PAS4vDnLUyHykuAGI2+3G3y1c1utJePXi8gS6rvYp4cHOPqppW2v9FjoK2jlFlBSi8oTxh2IekgZp5mGgkgVTkInbWH8IITMXrB3xNm2MlWgOAydVpsTgej+PcP4CGcaW22G1I55npfH0asUdhvEFASB2wr6oCoUCE1W8u2X5Yq2G4Y8jG4/osi79BBxd8Dr35mpjygj+lR+92yAcosS5oyUay1UiS4w62PD+DbTw+IqmbBWKfdTXiG3ne8/1Q0A5gDYt2DzZS4eHgzO7DT3JWS2yBeN6jtk9E24ZHJ+cWs4UkKkiuE6EuXV/khh57CWdxag5obhJZW8tXNPmX1+tBaeCIcZSj7D+JqHsGi7gE8P03Otb3OCUjqT8g/CqeOn2/1LVGpExmKoS/PERV90zEkOJpjX8vfpeZ/rGiMjqTn1mVKK4OvsbEydfjn+k9HQRBy3a1IcN24bGCpbeW6Zq/u4EZ/54iWLglC7lhRJi6VFAJiXEaFKOutEVXpt6LaCpHtMOgjAnG4K0LG8pWTQiuK5TCf9jgPp9Ddt1vusgtTfa78Ktf7aLHEaVL4POGlplyeADLf1uHd01B3ScBv3KaVN6LYofYjGVdjlnfi7EQ05/xZ59kvKtJ0Fk0Y4ImDTBEVqUcB8hJUStuDMKzx5jKmVvg7AjQPfSEMCbdx0L9rOWVLy36LfyGV4uVe1uPRicZ6yV0fiE+B5glaN3l57sxMBBtuVkCsER7K78kVPN6Oa8OnFcLYxYumifE6UGC52rJOZ3Wz7gViNUBsR8hw9+L/fRQsAx4H7c3RhjAu7m3nfjjpmLdlSWic5oM2QTB/p86wpuUfM8BLmm3ypbfLVVxddBme5IB4iPcegk8XJ89KELkPIiaMhCc1tvAlH6Ihh1jmQtX9+LBTQGvQ2x2GAWRd7qlN0Ck1qpmhxyYubcCxAwJKXZzqgyZvmWUT9ABo7EqSj1qG8yGzyS+WXG+0d3xWFUMpzVAHgXJIWruuyYdRmd3FLCousj703bi6Y+sVevDRNI6entvsQWzRtDda0gLOoiLvLF7CzO3s2VZAhzratsIDCLWy97VpiLlmP61bSn2HXVXxiz3wE+QjCfrJKW5n4vlI8TKc/dE0QF/lAC90cEO0jwZwHQROTyktzRB3uDP1mLBYAo1NANFH4G3fR1GDqPePDew9KjYkW6T7oX52tNc2zsmbwJSxT5p2g4BiQ54VYQRQOpMIOvA7SgTHfg7kRrF8zpcyXG5zgh4i7oDrQtVEcZhOwS5pXuHwXkJVS1wS0WQ8SJS41DBEp8FMM9Z10feW/mLcDq22saaKf3pvPxjUaPhrB9AS8gG8ctSRhBjrp0oXoFdZiU1oxbNPzYzESj7e95L2QaeYcCLojxEMHi6fpiBwcp+nNHFzRTzsPAy4t8YuTVq0DvffVLOrD2GO6ugRSrDokZEok/KCeD8iOA3dYhmL1Q/TcDjg+V/blwoMBdkavKuFbFYlpiuJYOoyiEWJOXGQ6LzYyyTnzRm/QKHE3jcPl2OM1d/2DzNCd2W18b05Fqzfw3PXjRdaVD/5lVXKSD9o9OEGUpYHxthRYSGP6qi9/UQPHc5MusgRiQaqBhk2utsZ/mulYmseNC8aZWWyQl/VHm10WBcak4P+sAyVNBq+2JVmpN93Ea6oDewJSWcMTife0/g4AL6sB6rTApkOMTDIZhM9Vl/SycI90rXfkwHuHwRMl8OUSJRq8ZouSpz+RmfnY1PareqnAz6v5UQMZxFxQs2wXmErcTfpmutk2vvNudLA/bVvtK0lW7Tll1IEJGKHKcWuKKKJBX0b6D5Wua/w02dB4bafttnRZ9TP4JB52hg7iinoGVE3hcb1egqzW3yehbVK+QLch4tif64d9w8nmuPaCq9+eGDLMfq0d6uMqkoAJ6GUumUEXXzydCr7KR7xrxDwZPUwHL100dP0D0Pkmr8hQGbseN5/cdC9v5THN2U3A9oqwmwRPa04xo8BZCtXtD/ZEb1MvfWLPeqVQFHGFqoLw+uQ/UbmuCA2WBPAV098EK8ZeJSAIDp5x2LPmSIFfYQ6P07YBlWqO4AId42R/68nEC8mb2xLjzMLRxB13ivcTe2f5iY7ptPaRsobzJmbFo5bPeTrm7gIsQhiXwRThMDO1aTPBfalSjGz1guwpFqK1ZYc7PRQEReqJ2m6fdiJYJS5sJU7eKv4JDiGQ8CePOVdIRBJL8Sy9EuhdChtOcRt1SPyl/EGIhX7qj9hhzrhAzqYkkcvPXwt5D8C4fEDKmqXwxdM9wQctTG1jLxhZhlBVYZQAmefzY5TsWseF6hROBEfvjiUTqf7Yd2yA+Ic5LjrDMdHn2lj6n8XqeX6an8Dv+t49/3453Yo/l03wktyrOE2kePJ3mThNGo7KNqSXXz9E8KTaUrQDuK5YDWBtSnQsWOkr+RRk48Z9qqArY/7rrKfyL9E3GXOLHocWGfn6rEMXHrR11Hj1I6eF0mResNtrq/Bptb0lk+ZT9VQ7iGUFB2odKJUdkFOXs0Swi0tiulwSBi7tUBjazpuEGlHCBhpdqy5BmOsng1ITB5ntsx+8XcF3HgDMfMxgJfTPyJlfcf+moNEURWyRVJXd8eV3QrhRnjdxNnKKAuZmRMYAbU3qVPJkNUdZQRFC1gRGLBj/hLYoxMsE4PMIjjUgzfI0+v6rS1Uqt3n3y1CTKw6dEyrsCgrNgjQvCNVppVuM4mkoKzvm3XoFLuTDQHuSB2i6PBXOkRfCDO94mv/qFHEJC/sx6DyscdreaDKOvZvy5WNIdTYK3ANynpvV9fQ/vJzJzoRnj1leFRUSrY9HRF6EYNDPyjWhCcoSZmrMnZAYIlnCu+7EogFXkWYxaYT0M7UDjMnK6K+OCgEVFYdkfPJH1oa761BapNBDgLgQlt3fsc56XDSkSgYvo1K3a2tYWlNyZpaBS+oq+/zrIONsyKYMDiEnuLmYftwDAYr+6SFeaJVMaLSs5d6iTkIktE+kVd6/4Zf0XxXOYC4WABJGWr/8v/4fdxzujhW6Z0MZFa6mioXKKrGFxbU87lJCDI0rRwigD6P27oJNtYUZho5TQr2sqk8XUPTMzzAl38sMext7AHz2R+vskgXjXmp06rYSWPg7vis22PD1aj1eFabWX0dA7uOY8Yl26JX9FFTMLwLORLPtFzZjlJ4AowiSn77eXWy/p6t0O/yfysLjOdfcTpUZvAnD8B+UfDSIYocU2lS34m/Bh+9DubLPkNkQcGhQAWp1tzyoV8SWr/nbKRc28rHXkMiF+n0Ggm2trAkE0ndo+p6f9goAuXFeCEfC0ZeynsyWV7svOABl3S8CJozhnyuykb+pvO8xGA2aEFDPtZM6rRaN7a9VBd+loEgG1TZhtntxQGe0tfS5c6gq2/gyNB/Y6kST7wX6Gr9SumNrl0CTiACX6ob/Qx/o4EU9NLV7XIV4zxcRfsvkW0uW94lgMDnQmzQzktS3hFYuFXyUAa8btkfI8FheMs941IUQ+hhBO17WZNKGHTwB9sZVzH+k2wNCLQoCANBs27Zt62fbtm3b5su2bdu2brZds4hZyFF4ftiXpbMTQ189epD4zuxvIJoY2oHaW+w0DbQXo5MxFWFEcoH7UFIqbWdgTjJYuQ5IPIT2TCT96CZS6PTbGPiQpIGcYXy/fmz4AHQ2ZSS2sfYMKGwYTiMG88fhyA4WDgrzYUDMZMfTSZ3TPoTy7NkJTzd0Qvwc37MqzoAMOs2d2RKZj+zzw7eEDpw7q0eKeW+MH0BT1lH3caE1KQvfmZnyeyJ1Ulura1JohQQOGpKMFEQcY0OoOOsvl+FkEioQLtGnO+ds4AYuqm8bB1rAJF0n1ILNEfNrPac2a8zjZaPIahcwUm+ufa5swfOmbmtQkim+JAHbWTKNv3Q0FRYT6E5YVA78sOdBcfyuNY7jpLjgqyubnhUNeAy5igonifyiu3HqtE6k7lgjxh1Vnzb8/cGEemHhAJbrSFFdV1NgBEegZzrW6TMcxg9Q9P0nuFn31ft7PvxFVCvyttqMX9Yz2ey8fmFhp3gC/x0sv94cqU5zRXr8N/XijMNJIM/LcB8wxb8VmwiTmue4SWMtt5m8PD2OOPduKETaucGIF5/C7Qwfvs0V9oB1lKIW7rHf5SvtD+eOuBN0ZPkB/5uozWM6Mm4LpHKA2DpD5VxY0/yApUd02M86l7Fbz5+AbU+qXz+d0xKgnIZ8ZolEpVYRUobT3ZRjDeYWSZUAp21+O01JWLAeSYgjIYBWiJcLoE8BsU12k9h0lx9i/zxjH6xd6mTL9bwizK9IOJTc6jdFDaezpw9t2GiOvfp5CmNicXZzxD7z71x3HlcPIkA1QrP2iAWzgGNMaoB5toT/jJljS3Ty0+yKzN3WouIwF+lrxjq4ZlUFid41z6T8WGmKgKnKwGf0119caMqQ5A+5W4i94MX0CTkKcPXeOyKEsFe3YIYakw+itSxdg8OswZmzAmhapmyAUxzpTF5jMalBn9CL+XV9XgKtbEem+Tw9g2XbLZkkpmjrsckqVPWH9+XhokMS/hqcarwWXfK23AkDmx84Jv5mF4wQLs9PdsJI9orXsuawZMP7nbvgg3Rbfwzm3VsQdPeW+7VhfIbtM9QKoleqiupc2EWLTTmU5kJFf5wlLLRbAsVr+ld8VJg8bldq9PluLXbP55oVwTmfsK7x7vrk8gJzWTjkQ4+o++p6hthRhCZCKjP9i8a1NphfKalnt9B+sQ5bGJvGOK644uM7kfN4jmEIyfiw6wWJ19W4WK5MVZo54sAxbh/ogNHZ34nxzFuppezbDx+7dTWboOVScAT5lG+ryPa766DoumAu70ISI6TRLrMTGAYo7oA/76JkcAeeSAQsNUrpfZpIaD/0bO4ib96/cYapFrPHSCdUDKP2LjUhG1uLwGOrm9SAGa2vEzHQ9vBH0jBhJ4gliDMOUFEAtEAc58cY4iz+vUWEk0Vw76/6kgfxOVeKkwDOoVYRRVrUmSQNyvvB2C/npuL7uNJe52R62u+lukR9KjvCwuHBa0L6pRL8GyDTIGtWv0Yj3jTrK9sKb5VkwwLiDKN9CI+9/tm+qZ9+IdY8k4hfjr0034E2I7ktvFOZcxqk605nPlrhiSnD32IK/6OCZGU1i0Pv+eQxcwTTxyyjFHOkcnmC0aEPcsEcCnfGTwzJcZdSvj6OJBMzVu2ySMZJEnfB2rEd6/6qoBQIl3FJmMBmjAUbBvdllQyh1i8hCrxR2PpxBHzicl2lVXkXqoEfCOXEJRoZ/yVCff5EFh3qHJ30mAhGFeOPoW6P9gyyR7xT5trnrTPEJ3vVstmcNDuqGSO7iO+75PbP5JOvBaP4lidlWjQcSjF4z9w7TFUbXhjIrCx1LzsupJmACSesZg3E20lrvvH7w0rOwBRB6xrlXxkIrUvc7VZKRNdVnVv9LA9U4xUxYbysOONyBUDOrIkEUDTD2tw5nWc1cgMxRNDGFU7JCrzbZpsvgTtfSc9DdcvhKIZj6csdJgELFgmFG1CCMCuaez453O+wKJSLqaQAEZA629w1KTw7Lb2kEvhJTlC7MGvv53lTCmPogLdeFHMG0VV4TAicx1owqBg0T+tzYGJFYDZLMUEo+k4FTF39fngjyO9BK9ueigeoTiJsBFWr+YJ74SSIhWno5DlZ+WASUdt6OUYnKam8b0mzfYbsFs0rCTji8CiPxhDRhYBzoRSRTtU6b2rI389Fa/mTnVjA6sLOos3ffmfy+U9TYCM3cah57enWQHdmMVERYo/zrtUWqOd4iuNQwPjcIQHF1mnVlY1rS4L7oyvFunOmZUyCI5lt+Ciqk2qZnbaTnZNgoZ3eCN4opY74U9BhcdWANnuLLMyclxDoJmW1NsuxshFfeAv9t5fkbSyaKlcphV3JesdiC9G4843RhI1mUWjh2/zH+eiN9slWP9PVYehc+HgjZ8rsJoRAcgV/9lDb9DJXz/Kg8qyNvjbexoedAbT097Pi39AwnDdjbgVbfhGxETlBlrgMtVIgpyqxchgNbS7Cr7sIsiPototgQLGjsn/OHC1i/WGrgDGt0nAz6K97fBb1g8SSLVkBp/mKVYWGekIuh4TJgMD+jD/VBzG/Fi0bGqTGipyHbbJSxVOjmTtFjpjwvZYyM49GLNKNDnobgUilQKANDLWeM8J+M39iSAy+p0MyHPylnZJYDx4aid7lUkDkQHkk49AMC79zYnDZJJ1XsouSM5ISxbzbf//HOhrUb3RKLaIRDlsm4RcgdYR5hZ8HAl/pcjaxNPmmqPSVTmScKrzR/af+uMDQP/26I04M7qAhWrDQekR4WGf8O712++dvTWRKO1dV4fQiLiXVMxSUc2DsoiDWws/CEMwnmXlJ2YnHtYADgmizu0wAHQ2S6AbfJ8CxMSkobXCgsa9HDjVuhD+EL0zJ/Svg+3FhAYWyP90AoiYnNk0y85+Tr+Gupsi5QJtYtkhr25qcnpFEdGQK5p47UQAX5bKXxXk9iNDMpDDd75ig00iJJoJG1Bd+hfSY8EUT/2D7wg4dfaGMAjvTwu8w8jVigxogdDwgKxH7DOdko5QvCbwUn0ZD0PHirGRWYwYVImXvLYq2Yn5a91+iSntqpPeWyfq5IQX7gmF52RxmGiJycU99t8JWNhO0v/cpYtRm8C0NPo/bmmp8DxLIqqWIamymW7/B1GqlStvPMonAnZp4mlZyVzvCbS00fh01OZuMQc/Xjnap2c+71gf49o2Ah+lA/Ch2CUEpF2sZLMhTENXBqKCdMmG3sSej8kZuZCkEd4K1AIfGrYDELbgDpzHqmxcJBNTC/qIuHIJFHJHC6w2ma876vxDGrH0Q+ALMvrJevL6KZyqGZjpFHrOCOiaMHKFfy4zOEff7hRwVwJrCEonOykirr1b7VwO2sjHz2Sf/39A0Opv3GB+SdS9kvLYOPDguZ4RN32hZzZ+guVzCQWwSoSYF5n/dkO16tXQ9biVvZXGjjyeLIMvO/Sk1g8kKG9xJ9hAqELWdFmNK3DblV2Ks0xo46gHz/L1fa0fVymmnCMUwzHs9PoxKtoXX2d3TdcvOlbDLR2PKjYEZt6GZ7FsEb17c31a2YBCGKQbPdFGZRIUihfxe3avS5xbUuSkRXJTMqqIHc5RX77yayd33h7Nr6R6tkgHP4Ug5i42uiWuwGktRhiT2KuUC9/FydYe1l3WHQWd/uoI7Vt8gXmy/XZJMuiJ83yKzdjosC87cIjEjKTK61HOMk9kFe347sk+8z5hZuaNTKI2nNgH9qCfA+Zsv0xUjG5e7iigKCj9MXlK0PHkyLbY9V6OgdekNtGuFr3uPKo+WXfeGjAweGpL/yZYryKcd0SD9W0ZffS2Z+Z3PNFbif3zcVyzsmlAZsZxvBC5zTUK9s8wqj7sPzQxaUc44NUxmEJblwuMINHXz9u0a99RDrrqqT3CRvI+Rm1E1V39jZaUyQrQweHqy0JlygjeTNSGRa9EEIr/bpbiPqY2I26HGeZQytl4gfO4fIlbnfarOP9effNmEgEgK2wc6YPfjFnzg/8uX9El3Fnyi+y/LtvzX9cToFUNkSrQpP6CSFEfKPiw2lJWWefkIgAvzo6AitDhgbWdqfDPLZUAVXGPiJ17lfmPYzlFlv3QBOkXjtFRFDdwcSPVBrj4qOmU/oZJeTS1iE+3GRyN8uHlZ1LYuIZ3fPpi9I4HmuLeOzfFPKXaZlWjbrQuzbhUTZMIkObVidC3ReGf25Po1+Fycwe96qZEoy/9qy1LZKLAHJ5DQgZOK6qLNZKWJzIdeDN8SBozTUJx1HnhHcrJ3Og/pgCzL8MO8aQW/+D+rZ/1s2k6ome48bO/k5rPMyf4lbgPKLIhAkWI8JoVclXqWwmiHj93K2Ke9sTmRyRKqNIOgZb54HTYhGOjcxvQQn6hl6TaJ77EDyS1jgyg8Xf5LXOhKmRXKREt/YB2nsabhJCrRtfcFoAep85EUaglQ5CBWKIsStiFayuPAimxztrZwVibtc5oUo6igB7lxIapuHvNjluAEEPRpy6K13tz3DPHSzKR/6FcU5rYO4+W2N0LTX3GAXSc1RuB2fqVA9SRApA8TcdtGKfTAE/HAF4s3whtIVqTxsdD6GzXdeCDj3s0R5AxYLl1KecAIv5UmzKyTHhLI6oaGmDMn6VpaOtQ1wOGMVopLPe8Ow1Olz4zd5PAEDI2zQiYZS/5vI+am8jOJrMQRfbWvdowtJVe6ZQf+RhtQzQw8UJY2FHlMxbam+xIJnF6YajoBcgLlx+9AB0WZrQI6fMmYZi1iez4bFPsZSS9Ci3iVF49w9SeyQmaqZ2i8XYOKu+ONLMo8R0YqZryKdiEyonZNBDS2fpN/eNEHISvBBDL/XTs6/PDTT+CeGtLyuxrUKZDBNXfTl14D2P38V8dbHnDaBcKJZVdqE+uDq50jSUJbAkNdBRTqd16vCfSlNn2XoJ1KMSEi2rS86e+VG/PxrpeYktEZG6KHVO44WPcXLh4YS+9KAW2+HLfdYuLeNalvXRVFqSfEs9wKiEDuixu57d3rUAzhY1AmptSVaJPpxUAkYpeoQ0yTnXavzKDRKQT6VrkbGaJzojr+7UshD6hiHYLXpd/+b+5Y73kE9pSFgcq70uaMI5tyQTlyuGaLPXki0jAKuzE+j4O4jPOowEfHCabDUJgHmW9XhJ5UAImJErJJuQIW/5kqzewjoq90o650IOI0QxaQiQl6tBDC25crjnKnAUjzadgjxHDswaaplYyYbBZIDSqgbtih1MIBAp7i5xhNBogIIYlcUK4/sgqgtLosHrHzKpt94szBEqCM9NEyDiZFs9b2r7i81h7BccAlzQ2SZH4AgUE+YAMQ5K7v9gC7Jy6Q2VRuXB7+MNpkptDOGPs5Q3Q8Wulc/m6hT6R+C0aNrlU9PJC9aIQhjxQpjV+5aPn5Ic94ydrR9u6N3B2S49rWQlhSoQSuyBx/etTEX9ap2Sw9+fvRpKIdt10/HdbRvfQ9ScPMwuV5TNHbN/cic9FdvB9SaY7dX3Q6NDyXZnAcMlhF1+FfcCecCdztw00Gtv5oYb0gGtSxV8HbTSH8txv+/Bz4Ho6KWg0UfC1MOYWIelhnIVIYL5Q+hpURiFVDZk8cks4R6vJtmA8ezx17JUZo90O73OjGww+pHI1lAHwIV/avc8o981Y1NaFRvvKCmfEIUw0+bYrzkkrokCygTcM4QX2VmPq5D4cyNWU47GSlLo0bBaHWM4GZgB59uR2wEhci0QwimHBMmdmw8vOdyUwiv1dK8SaR7mmDRYeOjbIDGEkeJm+Ew2gp7bfhb8BoKCAYy8B/102WCMegmwOOV9pstPAxAVkZkkHTiFjrs0QMHqQo07GVtECHcKTAY//G4+Q9M+5aM+6/COtGx/DkY9QdyEAJOrUmkBI0gu6jyuVPu06cN4bHEaHQAJ/gLJPsIdA3TeM2YV32OFTNuHEG2U7Es0IHDJs2XqM1+twgu+exKZgxyYbXQgfkkaLo3EeOpJHIqE5+k3/4U0r2UWqYs/+BeVMlpze748BjqVpt2MBunMbnnGf9zqASS3j/ezq0/80V2eyBbE01uSNgYYS6EmqOZPN7oGiUCbQSyW+3MpltlGPHJSwBXu1Fxg0eV5GEX9mUrQQpgk6FXo62gU6PnWN1cFmweQiyvoRa3alKP29CT1N4CGU/x+D149HXllkPgY6+FHACEfy+MPuvHINSI2D/R6zfueVx/UJdOkKFFfRwcIS43CIDw4l8ZxFrJwlDieP6CWo0Gc2Rury8z+8mPTov2Ozxnnf5JJqrRcmzGA3+3WZP7ljO+XFrzR3jGRe3MmuBFSYpQ/qR+E/hsRbnxJrduK8hOaF412uMwdprsZtRF+On5UpNmctPRRF0ynQRwA8ykHiDjKdBw/s3xBYKPbxf+focuq5N+6z08VDyZC1o44P5y/XT58HTP2LlqrS/34hN02VfAV8Yw3orSVqZcaI85OfTxJ/TOb5DPt9CmnIcfXe2RDNcYrDKj1ipZJbS/+w4nWbk7sGvxljuh+NYICuO/Y8bl6lLiTzXpRf5nt9p4P6U4kMprHPHzaTO3V82W/XAb8q0U3lpkiAqLbkfnevqxv7eRHzKutirBlI+uiACsXsAaAp26dgsD14uUdxUC7IRyD824GhNdpKhjG7epsDW6lWqJRk++Kg0PbPwluS4H24P/PCWUYOQvB0FacZ01d8KN3ASaNiO8Ryxoy82kEHBH8eyEh9KMmkTBDv37Mb/1/ttFUtUW5DZxdy5gD5aJeDdAYwTqqVcRrOY5QYYZjKZUsJh/k14ySIkpapf5qkhAoOR6rjCDTP/WNN0s4o3MwVfGhdyWWX6bttQ9jDVzahes3M+LplkQVKed4UVi/lmf4x5PpKs1XvQP3RoX9YcjE7QngTLDZ9ALmMpCgH56IBFN1FuwwwvvqNI2p4jrKr7NTbbAhNqYDgKkTfgYPskSHO/0JnoopskLCzKFbILo0JOD403569P1nNhaU6bCiZG7a1kfGV3nnu7upQ4yHnYWkUxkkWce2Z3Q+JaRPOMftZJCAwtyZudtFU7fbOob9lRvT1OlKBOsx5KZsYbf0nmE7e612mFTg5iAPRDTKKWkdJgU9CGTYE+NVlNcVORtPa23CIF8+b5BO14JCtG8whA8zSNHbRSuf7DHd4bZm2QvmCd5A9CpJGStcu6nkLkUysX1QBMPxyiEchQjB4rSzTo9G9rQeW/dThw0DQo28KH0pJ+sPd0udCSCzobWrpvvu7mnq6JfPNZisFvdJrfqV8ZHE42sEun5Y9xMzhhloUo6vdcWj+o/2QFqRE0recff07G73iKGkxcmrmT6lieQjv2tZO5CEPId+btN+QVU8FlOGz//bRFI8EwH3FoH0hTywqudb9kSOgz7FAsSrHiyKuYWW4Co8EB7CsWpG3N9AUp2Ounqw6v1sapaZX+u+Xv+MjL+93XqxD6KidIQxR01gtS8NJModRw8uP1dveT3VG25poMpzleqRZA1PCpWrjCjoHLjhPyJYZq1+m4PG6OfqLbQ15n+UlKt3/EaA3Ey+PvLSVrA+GxFJ9OicDcckFc0My7KUZNYqgFkCj7wclW7eqO4cYr96UXpY2GZMjLMVqfSPSGolxrUtWdK9/kDW3vl8ypKMEHVrF0fmvNydA6CBeCvLUvKXdsEOeWWtXpNZJZ0RysGjx1QRWch2sA3Ylyzb5E3PA+Ap0Ih01U3UTGGAZwoP/42uiov3RJhORX1ip2ZttEdajs1SrbROA7hkUrFdrsKfHgu2F1XuQiZwP6RGA6W33Mw0smdXG0aTP5ZJzNmLgcrawKEwwjjGnkzTvfIaJGIqqqGfA60RCTa4JxTwPFVOL6UzBzQ5RKU+NMMluJbJQFjYE5fLmrDhLnoNhxc7qYmCPt/+4urQ15gGko4PzmcHjUyp3iTCpCq+T1I3Wd9HM6N+xB1/CjKGjJS9hIAcWJiSV3fusQ/UBZhVB1bTFl4biPSkTH8Qm6s7RPNSOhdcQhSeFG2tQZkneH6asBWkWcgi5X5+W+Y3C6I7LWERDP6jIuINZ/l052vFSsRzcOYzLBdzBKDKKb2D4Gfqx7UXn0YQlt0XsA5wlPo5gCfCYuLvFBdNl3UpJwAFDpnxcGzicW0xcKBytdm7HDtlFj9iGputBjXAs6r0wstzlykLVdkBcbLHErj97Ab1uN+sgl8D/N/CvG9esc0FFcU/uQL1uPX46s0F2Wj+PUEkT+qJfKiLoVIOA1GDlpjDZjss8jlGrBam49ImkqCj10I1jm+cd7us1ku6rUocW5q3iCGn7iDwW1iTUAn+Z6Dpy9a/T7EaZ+dvsvw0CSUQd0Z40B+p636O3LMqf7Xz8sDcrpQM/f3k/wLxve5GwCcYHlW8ycEvVAYmifMiDOMubZ9TSx3RnU8Nh4f07/2RA/gsu/ccIbUDqp1ttZzb1h5E7kyI9yZkZxW2cHz6VOAwzGuLaa/qOCf3XcWEc2uHPVt4vXRXgMhOwfUuTwxTZ27qonOLMH5VtmNDFNNbQJEILQzJiG7EL6G3HFkB4s86vM6iEjFyuNeLMBiNOqxkKNIxTPpX9ZgECq6yfNd+3L2uyRpesST000JklAQY95Uuxm9/uVSROheJ7L/qeRc2VtRw/swH+HiXM3xWe6tIgXD4s7iesg7BJmET0axyWRJdTKbK7rkigVMmWQ9s43xZQusTttEjMHiXX5/rd+FLpn4nHkV5f/jDGL8BLJcNxD8A0MiP1nDwear9TewfxfJr9bS1nR0yRPgS9NoEWtbiNVX0XD2d/oZ+8hxaCFcsauJy+NlXGy4arvYTcIwrRbQuOTqBTp6F8eRCsipwKtoS26psX+a5J37vnY5aIJ2Z0/ySqxsNGF5HGrsXyCzvOTaAPjk+I/3biokM4T7sW9XXlITLGtZo9g89HKyfOyMOWICpp4veZq8+8+lM3CjxL1N4ZAgp1UONUzMVGbfRwHK+oQbhWFF2dPcQzipKOrHxakkeyCbgUFbnEcfAh6u7xs51kZQ6kTr3z8up8Kuakj+cEZPfh4FEV2OSQH0Te3knWdqtYcqT3uGGgUXB7zZMfRcyqZYXPNCVSXROltPe3b42iNACNfRP8we22gcKO/rTdivZ3c6mWCm+Cl7C/H1wxM86CnbMSAN2V6ez1Uz2jXvWkBblCnJLGiUGdgoqF7C8tOsokeJV3Lx3GoUoGfpK2AS/FGqCAV5R/958kRbqgB0uWMqf9S3FwPhRr/avg/33HbmiClP+eXfhtdb91LYWdVh6I9qi2v25VpSOjXRKEQjy21CtpKsU8alZw5rNG264xz7mwXBKOuIsv7r7MX7rt5Bq5Z9pvU+NHwyBhsdrjOjXuoMee/zctwKo4P6GanFH/E/ZQU7oxp8mTse7MOd0+BnTtLnmD3rjNC9A45cn+7+tNabXHkRXMm4fmHFY3C30qmlSyvNvqxJpCmowA63Xc3SujVXh4vBGue8OJ+D21zB8dlcGJvJKQ4GVZxtbQrMisHJ79DMIR5AvwodchU9bLTUeSPXv6j7tWW/X+2kSNBonw7D4rW7M/fT0U+/FcVIfqdqeQDSzGNJpUwFGKQvwYj3TTpEqBGZYW6jOJ4mP77WKmkoivF7OdeqayGC965GZetazLrkxWh/kgnBhL6K7+XGnSzNQeLia3+MMw3xkR7vcp1L3OuKUDB8dpzoDudS6abvynYKJ3vqYc90VtsTWg/34we14N2uu7u/sz2mYq/U93LRLdbMyjByz/E0EMONrMSRPqD8OkdEDvFeoMyVcH8L1jCKCMFcaLiWVw27oKVWUgaZVlX4qxdZuaUvk5kRMwpY4aLVchrUjB0MimlIYJXy5AQvzNpg9PuO9szPq8XCU9NiQhR4QO4DxmoFTzX5wW2638Gzhp6asXejPaNHiyC3tC+g9l2lt1X+0WBWHUAyCNxM9OIVtD617H9rmw3CIctXpFI1nunQ5jeX3hezc5meeSmLN/N97LDDG/ybdPGeT9duWoYPoXDCW083W+5wKQ4btw14rSkc2JE+NHieKoCTQ2mWVqeobF0fW6xMNzcmLD5CCsgfIw4SktqzWkVWX0Goz1+wJWLyd03LJ6/wdk9TQJGSkvmWBHIpKJxJwxfPAPKjuAIM3PAcTJJLWfFmR5G3SgHiuBdcLsvb8PiOHBSt+oFBwtPwH+FA9Cpw35DU2pk4NHcYNXBzX+YwdRwJlaKp4SpFXoCZEfn8Jk2EBntZ263d7Wx3XUEU5/KBEeftV6TCyA7RYduydf3INZ31JLFAUtHY3c7VhkXyhAmwWBuVeEOQwgz88wGzUZMj7h5561Q/5ZgYFD98GXl3xS0l9ykr7wx7/v8b/Xnuyh2YYWltmh8lrz5ZQivp7DzFTR37nG4/314FM/zuO8M0yaEHYvbzWeLysBn2jAftzZ3oiTpNlaZsUQ2Y2X6ZMh70nXfwjT1ec4nSMmiAAl9paTH2sn4r0HiGQbBO1GEVsXTm1TwIsHgJ+Ya8w2HbJ7SnCfVKKEyWhxn4to00NtuptP+kYCy5+norLt7Ge0veUh4jdcglpw1Ni1Y/tCRA3N3H3LnxCAPkFnGmtlSk456ySzQZlYKpOAova4sZuuNUwyZEMG4h6CmGtIv6xinjOfYPx6LeOatsqIBcPjgY1vPfeJ1wEII9C+X28gNwBxc9aXc8adiUc25kkMxIZ+LBj2OeaFe9Ue1xkH6lMBHv6PyYzsFJKXRh0+7WdKL8g8WMLUm3g9X76HNrmoyF1J7eAJNOUUTsVxKDTOk7GJngBywrK+rEi/n0jNy7DuJ3wB/6enW60TrCidos1i/Nv64QQO6rVqwVOO7vVmS8H/7XMqn7gS9+iY4AJz703qhfg6yktrD3/FUzKbmmhVCvm6NSkO2eIg2dm3s7tHIGlcGINudtjJIZxEZNIj2xo3gKPyDNueWuEj9tjPU8+G0z3nJuj63/W/uzFl2PjuNRFAyhvRLz6jaGbAkNL4eDhqGS/d8GKEQXHav5RJhxklCYgDRzLwc2s7STwrRQFAsMjbyekGL3m4+RCsB4m943r0VTS+Qmt/5HS8N5uqOm8/9x6ECm6GVjbki9Bcckjikjsib5cE7WDCBv+l+A1YvUM6w8pNlVAdIiRlKpGKhZgS56jQPfy1VgZQD0ZJaxDP1JVXEECYM5hYbxXTxzxGCEeRL8hiQJ2mmPoZZxlb0HtLZIAysvVrmRG1yughL1Y4zMWToC9A1Hf2H7BJrUQQmR9ZrOk1qht7Dxjeed2cd046ERZsE95fLMcZtdrcfr596aQBb0Sp7UpcHcu7ht99QpujPS2IXpbGHkBP8CS1rvpGnnmF82I9cRPNiSs41pCfYg+DGSxQOblRtSrFtsCUap7C0BzPj2tgosKZ5mYi/cDUnnscgjNJzYaaEGBTlw3O9cth+r7HyukFUqefjjtCyPu9OyqlIIXOVKsyD56UXNwznFQIa+3SUuhUfWXDgIAgtq/4n90RTuVsgW/TCO0mfZu5WtUme2MnN6NaUjzspJVEZ/VHFN8/5q5wml1mHuX3agYQYE3t/WGAwnxpQg2PSILRuAmEhNfxPd+B3bTw00mHz2QsAtSwon/Qx9T8KvSZlPpy8STDie7Co6yAa/tOvCHfp9Z+jAgU0z6cdilUD8teeIFr68d4YMY/l0SGrq/t3HjxRxNt0fgXIMeLaNVJx0UsTiIFgUQkenzeoyrz/vok6jEcw3BqFcAos4qQrJjQ5HsIDk+gs2/WILNTBsucT1ZsE8MZag2bo1d9/vV5z6U2l8akvgaigFZ55tL8sDcqvpEb4gUEZ5/qTYBBOEsl/a0L80MNwCcRenC0T1xX3SSbj9RnC/xXaZZp2QSuUTaNcIHg1GdpXPHWwe/JsGu1cusR/WFT0u7iO3szHGafKZ/4wc0SaKGorMSBVnKVkt6quwACjFLaTTVWJLwCqR9zTL+7kVJ1qAh654hk+f0Ju+blMJPLlX0l88CbfJJq5OhW/lVITr4VYmXIj4x9NElwWmPyAU+bJ66lFdIKvUOi1JTll5QY2A42ycBxf6Bxqq472A67saaZGvADpATCS4HUc1SIRfI87HQ00YIWOvvmlb26XyFPLZLp0t1wQ/XmkQWiq3jdu3YO1GnWveF5iny/FHUOayO9fBPNKnQUGQatJ+/rj1QEHAqm/lM9VXfD3e9SUHh1ZS8GwjlWAHwnD4P9g1EI0vXG9z1H/cSKLJl7MDx96evgIZ8zq36YWYl4z/qIsutyTWFrWTDBkLYsh8nwcPfrIVTiqRzaiO8FKFNofm7495UesMVYCLExnzm0k1wJt/y1NQ4hIR9s3MarUZ8snA1xDtNHb+VkPl0BIC6xiWFqrri3He484cVX9lU03W+ZBwc/7Vzjrj/60lJfCC/37+QshSarteEF+VlDG7TNEqDjX+/+DUiQv73C4rQG5sqr4jOe7TKhej99AGI4woLt2f/CH++/sxGN4G+VRFM/pnQwXzbs3jw+v+HMVzeaEeetscmA1XIE+ZsPbVKNqBwurfBnUjgTXQlBRovds1Y5wRSHIWhQQNRQwZ0xq/d632b+WDWS7t0LtAFuGWL5pO1BA9ElbuFXBsK189cj7MrHLErBhKQR32V4t3Y24jSbnkXUXolAOzrnTYU+zmzH13wvMJ03uHlte1sV88IeVYOGNvgwbFJyKeLryqyJGA0u5GEqFi2/qssl/gkcFyu+O+K2WGvUQh4eP6ZDANZWMwDTc4X8tWhtbbGpRSbUskRrVbUpLCcCcBnm1xzfaPMmfBSFB1trJLfZ+DDu+s6HZCU9ylQO41CQKDBQhuLetOK1Fe0rmd5rTKhzBVw+J8FJXYH23E3ZiGErAeNVUHspwygJ1CzqugpDB2rjbYTPcH/ko7X8qIZdae4riYhtf7LLZGLFrfLVPvRyZEL2tlM6ykIuBJ2tbbkzTtVQu23YYL8ZahpEe3RfqlZBcj5xDlbH5Gp01FA+muWwHgiYXzwL/JeeQZzzndSrLcj8PpMPeKY67QIYFzJfm0zvcyQnMhvYwadcsEni3Up0Wn37nzNdkSXD7ItWdELbUa2NxKn+lhf6h1HXYKYpqHoMRx6MQ04r5fHU4tG4S8Fwu9mZ7vPhty/uFeTMX0k+LojW67cmXczFvQobZfm6esixLJ2L5HoGOkSPbCkONIxmwRzd0cNNoBZD9/N2y2/5at99uXRuPnXQbblihnjl5HBC0C9lNoO8meIxC7SvNUNLLjbjQIPqjEqe1BJVRETzVGdAvu/knriniMws3W6StmmhD/QZVFKj+a1VLdNa9zptqwHiYdCn3y+lSWMCql3Tmnww/AWtl9dCE6wG5bbyxeB/xPfAFC/juZE0iE0S0tQ8RLj8OW9H261HHmhlx93egpcQc0nb24VMbv1ztzKw3H867QMG7h7dijFNHkMLJhELcNLGMkdF+i0PlddC64e3z/Tk0y2qIgkuS97u7sET8tshWzIOtRtCSKVxQXiIyoWLk0Ffn6O0LdfZKHA9oPIIXzXmqnD9MFc83RLwvYg2OxcSNsYZesjiyJVnYYFeQb4vK144NYZTdcswsGYGPNtp/UTvLDcUgrT63Z/Qm+Cs25cj7sEIPYvme+IaflcdDEZUAww7OZucsIn0Zj8zkzy/jKS7YhflgXv8Ds7DE1E8c7NoiMUkEkcKxPnplql5sfhnq5S2EmqSwWUO6i05lvraYvBxv4qXbcUlr9nR7+ZHWvZzdfQzQyec2pTjKGv0DTcSz3nyIhh/FpmORJFbGXm+XeFWmdFuF412+VctDeo6pPFUvLIlcv3T02DJ+qSa8rzeEnwRsUgU3ucUNAJr0TGfjmT9Y6DvLaMN+9BJXKn3x8RQOo5EgAhMkXi/FSEaEIg2HyG3MjaLfDwJBo/hqTIk5YczMQmUTaabN51PglhiAe/TISkoVF/ye5b602uIB3PyfjDbU/yxXZbmnm1CFJn7WDQwpM7Um7LzBu2dY2RENZjVKMu1G3be4xAKs34IX87Ltg6rcuFEv+Wi8DeQuR8F4gzYiQxpKN7IQdVanIPwrxTJDroFAGNKNZgvT728PQmdvlzKhcj1c+DdOdy4XCGU9QIq+qg1ZD0ZvCABn8BKwIQRQWBpFQbOJFAmlFJ0mF53XbLSEapsTgZ/YjWlVqNrFQghTP0n167AkrBr6dtBxrmK/m4vgvcZXLs9Ilx6pwD2W+iwaiFH+A/evxKV/VP6TJbvAIsh+fW9XFo/OP+SyQ88PNwbW2JlJnyzf8eF3zlLR1F2vU4Q98/BqvZymYplTKGUzLQbrFkwfeEK031Mwtfdkftg+6wX9JP3SnmuKfDb4a4U59OSAE3a58/6NtV6my/6QCtjkmBPDexE/JwDlM8VVguhNPngJLdEAcawLQ5ISpmUiwTan4n3yVnp61XiYGPzlFXIUh1L/BbNOtV2E89YcCF5o9Ah0ga0XiGkl+FSbzwZzE04ehlA3F8QSkKVzOPFfYPWrmgm7sSuZgbEBwGKrYZYCjK4F+cXNFAwp05kg+c8PTcXWRe8k4VXrKEsbpsknaSjiDd+zZfX5nP+VUdW0H7WipyTaUpuXP5A9R40p25iPnJ4vVPCk9588YnSlppd84NKP8KyKj+RrYh76ovH4L3v7Jugw+QXXicBLeURIHMPAKxZuspfEHfqeoHMEOvddfWIpcDULw5+DtsiCCqTCbQXx5GTlA+EpWdjM+wYFz0hZWzVxyETPXT5jy9lozsHffmE2pVxzEUSm/l3zaMIeOMhy8QrcY94gGSEGvXRdFC9OFkgwWIw046MLIktOkZneQZ7sB0+6/BeKezoX1cvuR6KI2FKei29Scsi8bvWgNTCxtiJQe/CnhCWgiiHlIjd10TGNgpsJcTIN+PmxbJRej2foYwDLXReqA1VA0CdxICATscIF56vtcHIRSrxn2OtL+q23NoRlc7M91vftR8r9XwpdhDZYuBlzBxW3URYgaYcjqFCXWDIVek0e85/G9o/mw6lv9bNrVH5eetZ8Htddl5qI06DOKwq8Sz40xS+EYFyCT6Ixe1yyC1F28aSDsjJ5SUAoxSmhwG/L3yhGJiflQ0ZZ5W5ZNxowTHpO+p69RGj52mlLrXOFtaaoP7VEiHIUKljlehs1FQkykXftRNongN0upmDHQC2etp8CF0bhbElijLj3hAyXfAtIUrLPmIEhCePUgCmSdDxS4pC9lJsPwyzB4TTy+9B3ZVMpWwURBglxSnXx4zPi5iazkELV/V9aHzoB63A/XS+Srw7V5TPDECL8rSU3gXsGAMmAYuunPbb/E/nZA2pvR7566aHA4NCBzl6HlrEiQiUjzqRtEzw6kHugtoCiJaFyucxsp1IndjR97sH9gy48IcSDOIwjt7Tw4lOZ28oAzs+n7/73w4hrIJRIQx5fdRPjsMq+clHiNezML8SNC2XdPX72ahla3w5XEt/AtJiGti39o/tPuZJ7wZ3glr+L/t1FdaQHdVpfYxUk1kxD7iZv+VlyHKqSr/wZQM0GJXYBDI0dwgmGMQ5qbjkoWYoYAJBnn6Z8kkPFqB7G3yV8yy3I/40R/DOQkK6dMM/bCglAKazqqCXFVY+BwBKu8L61cjk2Dd8VayOHYN1Ti/h86g1v4J1wIEZ8RvCt9wV26UMVWieUaYjvSPcMrK+nWdrfNyO4pZKidWiuthfYiiFvQMd6cdmqfiU6OL2MuNdwblUmLPryLX/WwlREofRm2dGp9B7Bw7W66O68i3BsYjSxGNWHYeXKL9ZL3xf1eSiEA3e5P17NrpMZF7GJnxOpXzYtytcGJm7WqAOhFGU7Z+ESbHYNpqN58woLZi6Z0yz4ZX7uqIga/KFGRxIAmQ9dEX6PqiEFeiEha7AR4MFCDhsmlEQDoyhNRMb0hPHC/0kGaauPlOSkNrpqMsIPAvowyaPhm+jMvdRAV8V313tTnNul2NH4+vDBcGRaiu2OvLphTFdVzZO0qBJ2jLH3Xm4ACAbUGC+z2h/7XI0PI3ScOnL18BeD+XUUzk12sVhQ4+Fs2UCQy4DZEt2zfNOrjkC9bH8tjEgoWCzjgf/o775emYCcJRxmaZufeQSgA1U/7+dwZcZtYzkaAi/7VnSk+s0LFwOvsRWFA09pUkqQIroZLKaMiH2RoMzFLUyO+f6zkyDCSNoz2h+5LymlXn1byIUzX1/8T1HLOospU74aSwnRdd6BlG0Bie4J61/8ejpxw1XcOw3fGwedbgt+0vEpPTtd/PNq8B9nnhxeWTO+xeB0P3k2hUfBWqqmnPeSm8UwWYapssaxNgkkeFVWiA/noNiXZlayTQiNyB1Q1TBbCgTmv0GAdACATdZ1EVt9t35TMwOGaqpGauX0WB38iKjczSzemguBMSDIleQrcAAsah/tF5DuLqAPHc0BTNEaL8kczKLbs0cPQm4dyJ2hJybYlyTTkII2rQM69jpI4XJa1wMQtFX127X/evOSsOJWCqaon35uGzmfn+zhr15RjTZzai12G5fTYUefVeGq5DXV/Cc0h3q0mQ1EIvzDhPzUexPgUgVnPjkqeFBb4xSVKhDciuhHUt4WRN2eOIH/sqWdQqC75XIP+/KLyD57AB7FhB5a9PzSeMHtAcXwL2cV3pfOgvYOfCYf0Kbi1570r5tYd1mXI4VGoDuNH2w12623vrdgBpNqNseo1fUSpSfa4js12jyukLgtc6A83ZWgR705k7PypGJoH+WkS/MSEBItLm+704nebmRFCBv+qkSq8c3CzkzhlTGSmMh+lUvMBqWuCLyo/x8BCr+E8EELTWAzdkJALhL4UTDN5KQfhZN2MOShYCqbNbge/Lja8rPzmoBOPMA6FgbZ72u4BTlRczJ0kM1QbOoDSF4N9+DgOIa0X+KslTpOn1SDKsGjYz35X6Xt7yvXXjHn1YDT+SVEcwZCAXLlbzvNGitjypSFGIP6AqYGVnkTEK0UWW47HeAQHAY9VmwanqaAacoXZsYoiVYtbYis8Kca0S5uhp6LM8MpuNCQyO0CLeM/VUTTH7LBcZNHKflgkUXJ98uv78Xumy05/lpgioDO22I+YqpWM5JeTgeBNyC8yt06aGu/Ny+QYLOwxhTKoRurnk/GZ7OFOfTp7Lwk8esWz0PWtpw+jMeKzZGJhNzL7hBL1p+vjwTx6ttzej+QapyVntMsB+hU1zW4MNW/1+EuKlTlZVqvefYxPxmpyOb4GmMzhk9vmgSIUAc9l56/3+TCbmKvC3j+MCyXaNNnouvhuQo+sULpQHUn+OIy/lg4gs1xByzy2cs1rP563IAtXoXBCe2WBQwXXCyG3uMQsZM7k7Y/aH+/1aQk3MxnIjlPVjY1vihtU5CAVFWUCYl58TG1p492iD+/k1cBa+y/6h8fsY0aPWysr9GzHGyIwR3VXgAccQvkxPpzmgtYK/ykwrkSUzUTBSeF6YtDy8PbRGQgsHGX47BVb32EJZUJrEzTRw1yY6mZ44QdBTgKKag2FzYTFeKTTCpVXKSOJcdyq/zsii5jabcU+kAV0UZGYzcWKOUrLsinTTnclHZBDf8nxClH7HYW73SdJ3sSJi+ElSw3v/tJmY8Ge3sOPzWzylx/g7Wna1dZF6k2/lvwVceRcxWTbQFvEfsa/q4tEBbtDC97JtLpn663S9KFYFgh2Iile4J35IqRan1R9r2qDrdJmdqj4hkF2iPlscr3qTxhwGSXiMqjMqziCEg1XRgS8YCTYwQEtGDmGYDVyFDKPebFq8gHhW9qMnXSFZ+QqwECtN0bKFWnoUgwjFQc6GYNqGplhHXDeP1qViMiwfa/v1M4nRSmN4ZApEOKRisLWGipeksSONg+wPaY1c6M9Eq9iVaSD2mNard/Zn53TLF/hTTHJehxiqONXFnTxL0QySUY7jHpnWuWdsjHd/1r+pFcmnTOLqQ+ZnOvhrA8xs861ECc170JecpxSAeMt98ISHJDkjeyKfrTIiT5lo2tu13Zl056TvmYAGvL44JxiYTCF1HPXtGye1M2UHpOnXuv6Fyv1s+V/0So1CtJdpfoplUE+kmu/5zqCL6IJTGz9NzbS4NVHLGR9QwfTQO1q7dQnAVn/UZAEe3KVB2KJb2wMyzDduWq1AhZPwM+c6nkqw0AhDbgb0h5UtEkReni0oc3bhBiB790WSDecuhE8r0UmHNBR+6621J9DqfImfcDK0JLpWfeFTG4jpWH8cFZdvlLrts54Tz6sycpXhilpYOmey97pkAn22+7+3LhT1pN1zD23ybrWu5hZlkaMRHmpEGiZ5D2xGX5goiHTReQu9Y2VKG3mCSfuqCjr1X89/xgaiT8arqRf4CePbDOOezrLGc6ZkfzbFSbkcUi2197TsmywGFEbnz9sxpPsnSHT9Ga7gbrOg+0+eX5ozr1QwAW+VR2Op5bTKe048R9629jaB81b7dzPa3WkMoIZVdnBvMRPAzOQfmAWP78kv+4ix+Y3j4sdM3NFM2T9PPYAYrOcE77CjpGD+/2nNF1YvV2fN82SxtzqB8fit+X2AaGDL9Lvfr8uZ/okBhbtN4z/rkXfqnNSQqOp2hcA1lk+BgUgsFOOuJ+iAb/xrr3oaYPtS0GF+ZguKfhHOgoFixrPk3DXv5oecJ0WjKId5EbZBo4XhTLUEQQlTnX16N7gjLSmqFOZCCHDrm9QEFQ7UJrkdv1a53MDvfHSeNnKQI9+6uFtN71MjD3IB9CwKtmjDYl/+yYiKV9A3VFivZPxa3DGVZ0fsLcayOZnzS6HeKbFN0BjdF88IRzUim1gr64d77pZKtkAfIqcR9+3a/seHgR0Z+d70aB4NgNO3UfHA7A2yC5tzKSSq5wqRMjVIohqUO0D0GmKgeS8H6v6DXhlphkekmAYwiPpvba9ZlPfy69sBT6SPKi102a0HqOnLmiU2yuTIxpxEXDhr4LGA96MUCiJYZT+h3yK6njwZbJK/BzRHeHdGQEJFVxlV5djzx0hifakJ9HOW0Er8lQbKvrLE7JndW2onLPVjsPKpEvXD+KyLkjNu43VesJxvQlKXsuqSVjO7fPeK44EUmRerMTQrsJBmZtFBN1Ba7Lp6wX/gph8M25WviL9LLW3XbXeJ0rM45p3A0q6T+00Lnl7tnMGccTi6uv8Y2lWQltta4NA/qQN0TVnkiRVj5BewBoryeq8y+1ROdB6nmc+PNh0yqBxPI9yiBosWmYtX/0vygHvrdbdnz/XXIIWISZ3gZKG+nC+UZb8KEofpqMCQQO8WVetEACOiB3/oeoqSYyrJctjNPK/1yJi4lo+0OidjgUatzuk+l0Npl+t7Egwcxjj8l0ZQlRkdIkavztGnk7SgrrBJKazErT5S/dj+FcR5x7+XeVrJB3vgQI6QMe042OVKW5Lpk0+WwUA9BEZnF7Nw4U8sR6NeWjHbupKGrdLxd0NRyxOJRjGY1JdMTc25MoyuePDe6O4NxfYeRU0ab9qDALpcATHqFwq3nFaMIRTST3oa5CEcLQ6mtTil0QuBzDAjpmK0RM0Wck2ZRu5nDnm4vDoT0vymyF87nFQ2O3LkkPe7ED78CWIPRDVO1gEccFpUdF1SiXhefev+KdIofCrOK68NK2/uNjFf8jBfteEbFzn27hgIbgHqbSY79R51QQ+7kngxVgTRMvKMA+ZBFLLqZ+K683Wc74hvAhFNe+xWW5oAtBXwH9LBurHLK2eQ0b5gIhNVqjipBlBiEa1hD08USNOVsuzkXxJNH54KS8ueNe5dpCFdyhg36faP6LYZxKur//pcAwnwBSbdPF7uPGg+qy4D2ECth6cbNi72rf7SGkYwlA2L8Tf6o9ImsRAQHzsKqU1LzReo9xIfooDmNSejBzL/tPN9/2Hhay6JRzZSDP1zbqPczCxMo+Q2GtGUYf4xQnk9dkPWQSyp6+Z+XZ5za5vWIlcpiOTl1HaBmEoGwSR0oSjL7EwyEUQPH2ku1aWN/FeLH6iftfxfG+AikOcbMOwDx6lHa6SIMNhf9oMHzEO0bK+XyxACAXSe9y9rVkaVQ2BV8+et2R9mZc7N4agWyg7z5uFkLEC5zl+eHso/jfzXOZIC8JOTkWtmfQk+ulkOZfMut1zJXZrT5T30mrIKdEGJAimbZ+4UiF2PxDIkY17c+ZPPmm5OB18/qxyAUoZzZ7/x1Q9FaBrlOv/R+JMxMQjapfdncgaN+UrwqvWC3aMhJTo9ZbMU5lUPSE5hGV+wZvOVAFJ26rNqNJuRDBMwEaJVioOUb1xjZxuAGJ+rA6JmCI6Yuz8p85Zt6Vi7qvDqcQo7IYntfTjQbNkNZagOiSPhWX1tRmMA+Jyk3osWqKkMr8LN8PHFxdG14adF8NsV/z7vf9Gf/mJvF7yricm/r5Ff6u6zi9e4XAWJnPqHn7bLAIClwRKcpK9K/cbmIS9T6OpZ5W2pW4bRfkMcQluIqpNcTmKA51QHy4SmV7GnLodWYRJEoKUrZh/hXVUEKh6tJ2uCg72H/nKlz/WTYW5DHt3WGKIo1IUqHTz7rlIZaCZU2xELB/nNi7wF9bmcSCPMeUnq/Yxtzzt6Psfvv7xdUntiQeMmFvwc55XSYU35BXaCXnNurBZGN2YNR9U1wa7POuRLzur3uff1LmWQTxcKO4vhiZouJmnKZfJDnv5puGbB0cMI4viAHIKKTuMsn9HiGkGtA4ExMYtOHmrLOnaOBAr8x2S3grurO+61hE95yT/A1zYdWfvfQ+hJvRj8gq42o20fIfoTrL+880C59021jt4wkz0dL9RPfXizcob3i42x8/prhAVL2xQdM/KbPJxwPLklXzGG72082X6uNiNFC58yGUq6++p51iP6z4boMeKdNcAeT5PGJP1BOyNsQUQtMz5RSr5LgcTDsNcWxFJlo2EL0jdHE4KxqcF6iyx9r6iibDpVgh83byRNscduz+tw9xsnaA7FHOSYbQ/yhErYJMuc9PPNv2MtJN2NuQI1wk3lNT+ssgjTu7tQDvsYwe8ozxIi88QHu4jBGTkoWZBDx9V59LM0loNxbbCgj6qO465QPj89A7cqNXNAN23qaLfgI0d3NPyenYNe+rHMGqbZ3+Wk9I4CnzpaJG0oP4nyIEx/ZhL5DtVvE0Z1PPWRXtoo0OJKhqjXajiStiNlakY0XFJmY3wwyVwZF+l/MU4GW8wRzHIu+MrqCDrF8oL702+XPzIesZ1Oagi3vRHymoKeZZG5x1f6aYxtM2tfW0XVQSppoAfPVaCbZ8zJJCqN0r0o9dnf5E2PncEW2SCfYQpC5JyCcSN/qwMQ4PsduflUyyaAhYdOEXGAzk05AtYsxynIAD5DYHIWuJvLtBlQgJoyb8YqoucPaGB88d5p546Eej149Rrp05P6kDo4yiTpv1w90YzBI6Gs/9XvWu5p06bTSYqpROxv/X/1+WST0SKvV2nfVJH8uenhB7a/7MBfz3URXAq/lJTHTU3MfidaPT3cAzlh34nulVpQ1c1mn2IOivteKtAt6lvcnPs53b3NeZcTtkLFAKROJ1mcfqo+towN+isj04QzjZUMEpT29XdybvxOchd+ALbfBatTnxEQFiPmNU5+V2r9O7JeNcegHGKN3/HME83KH43xF1VTveKI115kvID48gAyS8Vh6+PL714bwhpU+zHSIfUkOL2e5Saiw/QKaC4cJuPRAlT6VGJP5ftz9Smr766LfV78+ferqAbz24fB5cYl34h7D+dFr0bTZ10xYxejsKlmBTEcsPRvMBbjDDzyxB1IRe5XfKtxn3xFFYWX9f6+GPkcCLVLqmEnnhxVzAhjSIFt4/ujPuHZUITIHQQW+cJLOTqchYYYN5ZxUvmN07q76hnSon4pXjLx1P65YsK+l6cFHKjykwgGESqkgEUMG7Fsr1WOK9x9ZCGvQoOIVNetHN1e8hW8UcuG1vI9o0hfSxluekELAvjkM+jLWf9yBRDogHdFFMHep0DwMykD0CfXqMFvcmiSJcTjgRakdhf2mrK91RKF2baOLk/0i3B4NQEAAAoNm2bdu2bdu2bds2f7Zt27btuiFukDf+++MmEHvi9GWAIpIy/poioR163frvAFJtTI3MFylSHDGJSHjlXLV9M7pl1fI18FQsL/rgJ5HpVFuFU3XQj59KulYBNOFJTroHP6Qr1+8GgOTaPLn0Dfp9nxE4Yt75Vve0KJyZ1cmamenWyRacejJvmlR80N+14+Z+sHuWVth2qEhVhKIY5XyFjvdxXn28Kx8o3mKfkG8T3W3wkY6PBG/6KndD07MhnXpq269hVGDc7nL1tJEbxMpCGjtRJC0AU9yxMYhmaVUXcg8eeT8SUvR73qYC1Zsz8WLMSULEArGGPFNns1Rq5q4yrnaF8MFNzkeB9ei9vrzJaIvCz0EPbbZmpj/K3bKXwtxcOhNVmZ3gg6VTAhyWvcdzw12PLKDBHWUWO8CK5G8xafuI3FXSEIGLyPYbyqXlHl89OZh4WJvd6keYS/9XHVKnbOcgsVRx59q3ySkKl1aDbOmiKcZ4ICKOvvSgn/viJdtam/rLAyjIdWq/XH0VR+lALlqdo+sMVf76tTaNkmwKBSF4GDg9r0Mv2a8kSP+PNUcHAycFsC8QQ/72BpuFuJnvilJd/1HY55YX+htPbB7WsDG1tW+yRflLoO5JIGw55EtRvxqQ7ibY3ksLba0vvRktqMJendX62MKxNUb1Z2K0NZM2+9OheGhB5OKqGZFhld47oRrR/zKCFbPBmVBpYHSo6riEVnhkDi03OXHP9vqZ7kSwdf1+opBdAI/YmHaTZVFeNj/pDG1hjJXsO3P6K2pJ5jzsdq9i/fiBy9+RcbczBWXxUiihMdu6IOcSiAzDDFYK2jd83ngXle7wCBjGNJoLqH8frycorO7WlZpBDbKYk8SdPIzeW0fueNavsEREdtMwCjiMTHT1LeWcfOWm8THShdXYR959SGCVF7wqmNFsCUp9H5+/IJ844I3vQ/7swBQPDwh1g28CYBdUUW3VGBMvBY6Dy7MLDlHZwiObNfbWrtVWBmIaRdI30V4IjcuceJU+++2oFHpBjiRyOkNIzfgl2MSvCOIHNd+a1WHi92bI+l4rkZubBJk2a/bqDabkYmKAjPYK+HPZ10CQrJgeMzRddFnByCN7RehXnoXpyKzOx/xnLAo3cgmlYOdL2Uai5Lzz+NK7kYVqNbd1iBITgD2ua+bdWelty3GmnivHCU/OOyTIgO4M/ytgcA1CrXB9O181VTGO8MyLDjfFQljQ5QhkMMn3UPngRGH64F/urh357AIVGkHERdvebH0WzLBroepmwBTAI85GUPfDhBcb7tt3YhEtskMyZeGmsVozxrFlQUHCcPTnwo0Y1fI4vL+TCdkuCAXWPvDM3qvGenhENOuz3VZDnsLyn5XFn71kU/u6Lvuj/PB6DaePUu2lnCzyt1MJXtuUbDqeMloRZA9z/JPdxpw8bAXik9GMVGpwXLtsEfNGCFPUsU/IX5A99wz07nx1MdtEZuAc1MVUXKky+jA/huMGBmGcn53PB7NgX20XwuKDxypUvRSWELq3Hsg4X2LRJXYcz4MYSN/p52Yoxcy7lax7PMOPUJfZnYs7RDvVG4/zAgylzljKY3ZOGA1mkYtWE+FHGHI305VMD2kSAJfW3kHA4AfzHYwTwpbGjGUcK67UPwgF9hNNFOexCJkAgc1Mr3TO8pmV6iAq+IfKjDsZClBv21mjcFDE+pJ4DG4MH6iqLRRAkjzmDoycyS/KSX90V4Hyf6IYi6ddMJvK01cdGF7tovg4yEY4iBTzY1mWz7sPxRahxyMwTxVQHh59UT0b4V6nzir2249IDubBjumYYAkg0t4r1Z5QXlWu7WmyQpvVSZIIbDFD8ZUg1MHcgXLaJBd2BfCMSSYLw9xXrdxxxedHD+3ZOdw7tlQ+MzYZX0fK0eZTsvtURUpJ4YJ/6oiKdoMTH7t4WuTWEhfGvRaEyeP3rkFEQZrauu1+8gTsGhFo/LB7lqrORvWpUty1IF8gP6NfQJgcTEUhn7iqoSY8aShqJSUHUGbUSOpsAxiTOQm+gJWdBqsIK1lEJKOqNwR6ODVtypSecsGOgFMKQu44zVWjMq4PYrLj8rZNGzI4z24/JopfIXMNsXz3Ne9qw3eyoMojRm//ZKkY+OmK+eKNus5EZxsbwlE9Wn+9dLCHRKY/qZqTFgHO+edrE8KQaSAR92Y+Xsa/W3EKw1kgIgv4L0lnoDrtQOdh99ItiQtwup6PYM7MJ9HPJYMvC/ksanhD4kYa8pbFz1AwWd0RpAEkUr8jXpJoUO2km2Bb0o0K7/ZFbwl2KBaCk5OLeaV7HMifC4jsFZ3cocgaKIzIALurs90xxIvBIePEFRPXcTZKJRxe6241eoxymm6IwBjwVmoHlfcAZUeSdwM17EAghiX7eP9SKOUT+qVdCslHUHNeWzCJu6ZZyWZH8sotkJsDvhveeGjRvo/a98VdUSUZ5sXAZxJs0hmyfBf6TZipfIU952UeWAT9j4kmd0Xp9M3x/3QPcK5Zc/+9LxAbAAEGl3XhGE2kp7MnmW9ksvjls8o5eZokm3gO7NimLzxLQlgTT5fIv9O/OQjU7ZN6UggU1s5cszGW2joLCQZM/cLbPpOa3bsW6eDNqiDK+PW0spAyN/eUT6+/cW29nR7iCmJEYuokqBuU3uY62TSkGwvBkg/927o/ODDfW5aPew/rU/zJ7yPYFj63Q2unmMCIv7MNXXWfVj6roFCbruFy331l1R20gKL/1QV2F3+lcXwgA4RDK0ccD5J4kyNWX/n3NuSkDfWwJVtVEiq6f0h26t8rNToBAvXXtEw+iv861D5EEIvS0sf+V9ZtVTZDSd5A/2PYJonGvtbr51SUF6+z7nQ44wr4aHw/uyVykYAPO+rdGoLoxPn+DQMB8a5RPZQ/1uvtimqWun6sArbYow72WVoxXcbwPMpNsSf0Clx4meXuBnvG+5BOR+/916I63uPx17IVqY/+9EPKv1BDEEtirVpqUN5jmFGbvWOUHwJPEGx76YQ8Kp7cbUdMA8dMaKIQDSNDOmszCjXdcvtNXMlhrPRdt/KG/KQtDL4zHpnHKTCBW8ZEAazB/xfbMR/wppFY0svKji3hojcwL9UQVa7rhpFr6JOyt8BJsTGn748jCQwBQxWJ0rd82vy5N27eylKLTQwrwnK1s1+ELHdS6PHnqDIW1jklTRvHkNrIe+UTE6HUUzUdTUg7nFh1OXltaPCsIJHstngDbBqKNS/gmuMChcIKXko3a1pvQqg9G1RsFV7dY2bCGkyK4SvvSkvi6yWVpPQVrSh4yJxKpkWrT0dejKUWnP52DYfh8+WYwm7PyYeKfshGRx4QG+er5v2MiGSTCLSP2mei8jNBA1DMItnuepa+QRoItlf56VHNH/OtAQ5nHebuZPTRlC+hTszXvWwDC8icHaekqX6NUeIuIve3Oa9dyGfUsXjZivTapDvNn6lv2am72ivXyCeYxnKgVlwkKdkdF8tpXwcpDEhs7s1JrROCUMd9CWMBSDySmyRN+PbkPPXLDpYMRl+IKcbAs4nV3WX/hiV600pP5XoY9PBU4OXW2ySn0JnkgjgZ60j9AtO5OHtj8/4bnVkPLJPaZ5hK1FhIf3v2nIEzk+tEPq2T463rtEwwPFng1guZlQorqf1eNm4htHGKtHQJIbvXNozh8nS2+a7P6AyxMi+i7JDb2biWT/uP0lWzPwc6dCz/455si2nExDL3RBXlQVnWFGn8rEUTVdcfkCGqfRo2eHj0ilsvazNowxSONyvocWkSBZjTZUZKHdVw8aVFAkfhO+NajpvQ68AgvjnUv7fAd0h3Rra3UfZMcsBsd4VCmXVOK+qd+3iiyxGavdB7FZYkdaN4dAZQ59sHNQqwlV1rjIiQiSsLenQayfzc+2Ox8vuoQrzfpR0T4IhUKHnUti7CDaI03jprT2mhB0CPeQGbcoyDhjy3/6ebo9USoZGIm3dw+RUTUBJMuGQtrmG3RXr5n63IfqvORa5DMCEB/fLKueXIBumkXrwsg18ReQ2oqYKqijmlbAAtQl9Q2yFAOZ0JnBHKA+dCqit3Hnz0VzZPYoHMtKLIT1KL2bBlLXnmDp+cIUXXN78OuzO4UkYFzXeMFpm3q1M+XbhmodnR0y1vb5NOzp/FCQh6c2Tk2Anidm71CriTuinT3drWv4PoISRxP9zl6MupplBUqoqLPvywvV93uhlvszQ+ef+CppZAR9kf44bNAK3y8qAqQDzEaOMmBh8MjMG6+tYlVWKdAcQ7N4rDU3WWX8/6zNvdweAOJGclDwHyNmYu5MOGohlVodiKxjkXWKI67OBPd+e1zuaGIMzg7RZ/9nnpIOtL2TlTOCAQceyCORbUdBGcMM11t1OslQC3C0GW3MI9muDalZOh3+2XO4EFgf6G4Z0aN5MFTfpdcMAimmkfShwNWsp74eWpmV21X/86MLcwk/IWxqjvzPcOo0cVpkFTyVpG6IyhGiSQlnl4+21iMl3Z7KnLv0RJw37/iiJ0zqaa2DA91UyiL8ue4iGxkmMAAqhqrXrQrYqJEIZSOVHYtMQsNJmaz2txzzlpMkR6SZkc/5EmvY15qAwxRCbQFZ+K8DgA4fX3yF61gjBIdrZ4gXLmYG50Gt1h+Om9hoWokh8c5/3F/MpY/BS/q1mJd2LXdQXJC2xJ5GLKwiyqA3xWZc4X4K/khW1tqX9ipt2oGwfZ0Uny7bA1AM3/etxK0o0bM8M6SrBdE3flKNQm0CckJzRlGJjek1RhzWh1sLsOkXmZGTQncJxi29PWmWadts8ogZq1uxpzdpTKPLfPKGFORgMiKZCJ0iRUA1iA71gxnYKic4nxbgl8GgXCuh3tAgvs87a6AIQOV7afxgo/cfE7Vn4trU1pejD/vZLlLDakLZAYTuh7AYHRQf1YynWJmsO5UDJ726y6mhF9y89paGsFbogPweel3bKhI6eOLmcfVLZZENqwnrNjwpFRmWd2/mg9HBEbqNTzFYmIv+fe1mjdGKnNESmN7Woi9eqtLjS9POlXNOHw0RkKlDjOdyO4EbPOynLfFTD1u5L1ix+V2PYT7EJwKg39DlB6N0Uln/SdbUYALwgiBrNDBYLRAG5d6JxzJXl1o71gRaawqTMtX4N+BaeogJI1Hkgn2IF3dZYf1JkN9CkECv/7MmJKks2XJFGa6xOBvIQQsV9E29F4J0zIJiOx7X96m+n4BWYIsl9hL5JidFm9tdzqjcDum5Dmt5JRFkNWetGCCb9pOv9JS8PMmLzg2Dy4Pl8tGm7JLTI6rLotk+/6Ybe+3AOInZhieMz4xuJ0378Pd7La58QVK4cz5FGaUz/YRWHTpR1pBgFVXFW7WB0rs0zU7bB/wDZggg1StBvwKRRk3wza1DIir11WgTccKqxZe8lauL0+v6ZRcKl9/mfaWcXgxsIxsK9nu5uVzzECSSn80Wl7UiMGoNsN5yRyW7QG4db1pho7kEkdjBuA4LkMJi67AwqbX68sQMVQcfh76anZtl6Gcrtxm+fCz+jdpQbzt2HJ15iE7Aoz4u1fPeuyzGddnUqoHWx/AnMBfxeDEYxofCWFfwWwkhUsxUllVrT5k0AhsFAnHi04vdOwTwH3SgVaXj5dMBEEK30ci1wOlKKEc0AatUV1ugH4QJ6bQeNBh0nUo9zRtr1fivYRoANpKQCeS9YqVcKLkSYh/6GDyJsvi3D/UFEfGyJIQz7OtuhEWBWC9P3NoqnjYXC7kp3uIJWfZ9OTewWVSuxKnnSZfA2zZuc/N6MoIu7VAwwk3bjtnOJEB5jNqkgAVEX69sWs9e0Fmoh+Ejid3ZL/nFziKq3aDlroynMNYutPl6hAIPX9AFuxnZCtBJDm5a2JGlwUv35889lNc33Q54zcUWwbDRU1vkdELCm91RgxeAHz/mWSxn4Bj2m6JtdSD8xSn7YYpFcx+pA8IpkIccir15d3QZj5MqYbHwtKA7cPGvtxr27hZjBqeyH/Of5WlpykSKnNJHUhQzFJ71fDJIkIljKU0TASO5rGZHDC7tqpvCL4Z7Fqmm4GyGs/+niojsq9fXihMGiHhVMIaZp//ibd1uPdJ+tlFxpjKXra56YCrPq2wKXN7LZeSZOfByyQQdBfyT5bqKTEmimeSHRAxmZpNORmXj42gURSmr7jqoyFS6SGq2pTgzQkSDHZsRcLfrZAOOlR3mja21pAUiL104mfRb6+HZvC8SKq6wpxu1x8Su8PrW7X1irDipORXue6yJOcQbLGZLjvLH9rQ0VTBr2E1XpnH99x2M5kDcYbBSAvkWwmkW/LOftaANnF8ruoKJT+rMkTg7Ox4s3uye6319atOM+Ml0R5F5HCqWmqeOgLc13AfvVn+qP0MYIPi3upLo/JIcpnCLNx0tYYELXpRkxTLJTiSf/CcBLvnOy2+Kdpaf054SIOZHY4jAdZUmONUTNHdx8JZOdUq9sKxcRpINJJo1vRcLOybz361ST/u4610/2u/IHvodrc2o2HKcIBHv2cHjKUlNukXnZML1Hh8fi8wl5hNbgfVxkpWXW0lRTv5Ehm4PkFwS/Tx3/e019V5jkoSiMN7Wn85pMqWlId5G/AsLeUF6hyqIBDvNie1/yyYqhscm3AHCU+sq4NieCOvs6TWJJ0FBaiIp1Ghh0d+U3PcNAn1tvA8HcArIVSoK4vsQP2m8rXEF258Br/IZ32sfGWbYKiwhASJBCDD4DcSi3QR/vqXKSlBleqmnT5beplWVsv2iU3VyIkXmuoHYB3IW848PmTTAfMu81tV8t68mzRz0SJDheC+2OvFV/5/F4SV4aiZf8e2eEUN4IKyDtjlyynCJ/MmGvZRJ2xcRlapuhi9WzF5OIDo4ZTHUgMmqF0b97LitA8AIFKDK5ile5OGzaepRI5uw1hnGMyQ8phENv4Y+ryRwCkWszPLTFLCf66QMPoEiTIt/QU2Ack3z7GS4vqsBvmX/MSgWuzV5H5yEy/b3JAjKlvyx4Rqj2V/rg7ql1bfOSGHsWmgRwTfsBsvFFk9Bfr/1D3CDWxKyK/5tADG5TWZZEBUcHywZE1+vkoGUG5pkOOJGKUK1rrZqG/WExs5cwOSjqSMrwpND75NrT6yjXnS7RVvRWF6Au02zONm5D+wAF8Ui6FccgP413OZeJzmFZGICydxKMtZpU566asxEQ7lX7s8Acs6XErKZtYJ5QQ5D1AKtBn8x5p/nxdcu6BUAZCEOW17wNXj9JfR6lHhcJ/8qQ9StSevQuLZSJo1QcYCBEjfxTyLRTt9zprEJZW/4HJCkKp9EYvzDsnRLDbL9Hu9ZP0cOt6LxF2uYF2604ytFjwRSoBPZNRDF0g+5puJoYQBfIOtUDtLodguv5TcrBj3/XKpHJlAmH3EsGOuOmRuW1ViSJCGbkA/nlP4eb6gS2kgyYT41aTfRQG0+EqOOc8kxVYlzlliNEAKqMExiiFQmEVBVXUGGe4qhQDUo1YtjVO9PX9DMcl7zy3nlbL92mPL4v+D/tQ2R3fw7HVgiywn2cJQlUPN7X/2tFYHYSbJiA7Pvvry3V/7TIQgG4mVNaq6bipYfwr0/kx93sj13HYrOKBK/Mkdox+CsaoJGkxFBzECHdP4uGZ+TQrA2UYfbldinlwfAYe+iK1yjpxBo9/3671yFcc4XHDKDQTfkT5ByfwkXx8sB7TUv/xEyTnQomYT+m3yQ2P4gS8liqHBH9BopHSrSvSQ92JsNfQXbeZn/BSAV/i6wEtNjuTvHTcZthKPUmZslfxh+x7xsPVGqMpzSEoTD1tmLbAFjVsoEKlJnqChUO/gR3T1Y34B5zzl87CrPF1VidWqNDTRiwtYCyXIiZE3EtSzia+q8M0gj+2Jt4O17o22cLDoeFbkpd9xtmhlJgLNBhwuTkI5yL0S+OzysMcTIJUsolVXJZu6LTaAnwGIhlW6zSFo2JepSeNejPp8VOGrNhfrzi8mkFEbO+VTpMF4xWto1St2rhDz4abqDpFAFJePUqk7PW+WnX3N1HhrKX1mUtSrpc6+qXtUB00k4OXBpFM2eZ3GThYwaGihZA8ydOlIVoeV/GLamWYUHtU//oji+SiVIPIsJ1LOfCkUcH9t7ss46sV1GZIaPB3yWvrfiYTPEGYa1r+zTxh5IGzvrp6JHv99lgefMpecb5PIpr2Yw6FoQKwxYsps6259TUHpOhY2zaLcrCNjicP1IUEPW239+3YhsgKiJghW06Y3rx8fNcuK78tRrijtBYHs+x79jiQKXAoF7o+VSt3d3lpRf+zyKjEvzbvBb/Pxm37e3DnHJ3uhml3GBjXLIKJjSVQRUu4dn8F9t+RUcnnVgaRzqJbwYdz7wOs6GCR8FA/ylvm14e8GY9STQl7XipH/zZAnoSkpoYE+qpqqlXpvTCg8JlNDGmFd3lM8f0D8ov3jfEQOWkOGbvUXvgYt40MRxi5Whrl8iaolJCKirAKbugMeiqe5kHb0sTaJRCKZMg9jSzC9j2S8si+NZAmpUBZMGd7Z+XKKOndzqbnp9HX4sbtphN5iVrZQ8AskQbFb7Q/rKlG88+JRcrl8d/hsEl0pxSsqbAMXHFOVPOtUd1dLhD8jfell/KqRYyJB5mC3B8WleZMI+Xl0xbgxa2yGR6inYY8qR9JhRcwO5ApO6xtv+kf9M4L+kNM2skdAWE9bSXExoo6KpQweH6KAs67gAxHSwMHWFgkzkaNTuzyuTxkrmX8yhv7FwnsPyuWKggLBEK6HnkGg6mA39r1Yxd7oAjIRsCTSu47LZMt6cXykhdK/kl0giHWuKk8schDMxCCLwYcc9rcfKPgrUrRfjX/NqsSHkOzCLvEvJiD7+xW4QYl8MwDLKoMWA8IPNiX3ZinT2OPVEXAv57wEn4iElgf2navXBHn47F/ULJoJ5h39hJ68LAO1IT89juaqGyp2iZ/uR1zZRhLFklgmdj/RhCfnzqMa2fP20hJRjRuVYRgpRKp6E9EhZMNBr9cKE4J4iTAsTLWkHdlFJuyoij4RBGEFoIuVlNQQYIW7Y+l9Kfc/k5Is4MVLlwBlextlsLX7TGEossGXJ1/0MiquEfbnxFeCcQMJ7oUOLqSQzaR7aOcC/42xBWlt7ZxiXryCklNc99GgFOs4ezpsgp/976Y+IAbYm3415ccJ04hCWewWZG8CR2GLi/NI7qCVaNhCsuRRlIWvIedFrI36GxAdf8d9ceqJs8htDKiIAfVgnCsLYIPwaBvJUB4wXYK1MjXTmRa6FNga89MUpQHI9g3PRFyXw1u8A9KpeGdB+hK9WYnFhlHiSNHP/0Bc226NC9IYSynyz2Q/XQUjiTV1PJyFsxpHyhVCRNEnIQGy/HPSIo5S08U3/pH4MUoGb42m+CJKTJmRXYrrR0AdLgwd2xDZFwm+p4Vz+HpRmS2gnQANwxhZN+6wGAT6RlnNEay8SunNAK921Jh9FOnbAiiYLBylYr7yC8yWGZ2SfWdXZiDHLE4qyCZEdaxQrLHQkAJ9lS67pEx4OfHoJx+TxCwn5krdlfZG3wE1IDVaiBgwj91eniOqjuphvgSu0+1lbjCJFs3+28VZpt2+3LLpCOv+SZunqPNvOjlkqw6vOmV6b6yQ5tHfTsfFVxmQpKdB+S5rFWll5Ju0DY0nZma4QviqbHW6xeGQo/VvoO/5RKljMlO46NDkgMsFpJWWUYPR0IWQMQfsZ/uRhlWhvP3cXemYeX3dLQUqHHXZLfrYTCBgLOqOwkcu0qPTG8dQjxResKXXm3brBRuzxKbTfuz244RzsP+RsNXoKQ0ikPuVWNJnRaISVuwuXr8nSgHmoeAYOMkPwc8lR5j4n+3GKqzdmgnf8qz4NHwCmvBc90OLjpSzDBA3TSjPvuigN1DJ2sHWbmlJ1FjaZ1RLcNro7h7dvkXBz76cUXfn45cGcli8IIQ0TuwStnR4ZZziLUa884njmwl+6tH9lho69owswkwuv72Wtef/ng5SRgPe2juA+GuOPefUQK0oYeYSc4T71qLRGrdweF0BhqW8+yZqGkPbGFpMtcyIkP+tIxrRTiG4iXkYCDByW51Z2b2JRDi0I64kyl1oikndHtrpp7VpeRBbEebxSWTx3TjF3hin2j3Pleg3bmiAPacUrUv9pVI6ZMpfhRRzhixzPnz/YViaBwljyT7zB9SvqoDZEpo0Z+skMLVf1fPgy8DCK++W+suVHQGbZ+49YvgwitJshDraF2pzCQ3WTDm+3Fw/YAfoT6409m9OflL3iWJjyVCWwKvDu58gswSeLwqMSEMqAuwU/ovqu65OzrFatfmy2GKvrSrfLNkiMU+BrqS8y+M4QyMYLbp30/DFfNVVF6hLJtW07DYESIe9H8D+qiTekIsw2PepfSvfCR4cTviRNE38i4Ct3ydGr+Cy5MZIr8I71afpNeJ0p8G2Q8g9uWkqZVm6oOv4lHI5D7P/8GzfjeUDoA1dMGJCEE7xVwdnWnEL7mc0yti9KP2iDBQUwMsCeKhIoehFkWE/IZeuR/YMWhR9TR+xY5aaaUUOWpeDixxmsMB7CuxkeEYJmXMldyd5nEjddY/835yZiZgOHnJOiUvnoosZBbSP0rdyntTUXD3p9TrY358w/8676vWucfqALwmchqevSl8LfXrgOyyaDWQv4ykc3blvzZcItyo9PET2Dq26OASLmK+31H9wMCmnctOEF5abdJKbzGgMAoJhEMBzBCQaeQ5WLMrqVyXXABmfH2jAeQo+DE0ek9aszJNN+pf8l2N7wgk8SeOPqUangt/5eORJcrlvO0M4X0KyRhEwXNoThv6WbCUPJmAYqocx4+i2kJqZbbOTkQ7Mm5ToU9eHR0+vdLyY2HRGL/OErAUmU+AemsL3S2zOt6JMmQSgqpXT0lVe0fem39dl8nEznO6XNSWHn2ercB2Ew/mVTLuDI9fjkrRpCp8lWchLGdTeevMsqnnhsKqs01DZnYfz6Xw/NN8lXcI92jK9TWMxkPaZVOyScjV6qDzTVBjbWLyyF6glW3eOjwGduKQ9UKARP4Fc4asNB3KITQ+WF4WzBTZUjLaLIGaE9Yeq+f4sdzxrR9fWwoas4uKlyYFVVB4hbN+MCO0EEBUcwg/jdqyDUq95UN09tT1VMWHFYj+ED+AGtsF5xq91+NXABqUZWlICEwqGaY47m2z2Bm0A96Na5isAaLI8o0GXunq1RsahTN7KYxdYo9EnoWrMNCo64CUxOoC0ik+qEy86wYZz0MeUhv0rmTp2REk2guk6IL40Lx0hsu/igD/sCSytMg9d51vpN86iIj4IFdTvbivEXxNII3szultXzIW01ooyGF72seHqpE5e+nPPeM1AjQkbeaurtUfqrp2rSebFa62y8dCcDGT5gVMt8lG7QvjmHgx1OOHpWgGyFPLj3Erxy3dZPwKEUx8CgD9RpK7Z874Qr7IfMlyAHLCP7i+nzcoLhrN6c0Em9CLWzH0SBZCDKfHpEXbGg6Tdu1iF9VIEozVw7LTkj8BKOQcs3yvZ5eRkuBQuNTdMkRnQPYzLQ1pud2ocEQKyZ16W9BBUq8nehb4PQ3cH2TSp56ziqw2dcEkcTKxlXUdgUtpaKz9oojIBVAyGw4YSfNYVFbivb5BLJbq6XA3lor9t4M/BHGHCzAJuo8589XmZLta94OF8sRpOBlstpA5bOZnuEBD4Kf0fjCIyp4WRbpBAfIrzPuXAdbAe6yvRWiLpJi17XYUSIiSxyD5pP3khCBAMzqY/MtN09xJFZohoFe7rbAfVVLpkwgWxEdxqhUOIvOKx1zD4FdPDwPUgTqf9wl2pNjy556SyrdC3voC/uOQvBOF4+dQFfrG2fppdWaIRqk+0YaOIrtiB3Rey8n/FOHuujnDJ5CwpD8RcW+/ArtuDiAOKSqP+NDBxgrqHKvUmohRUg5w7ICm1bP9BVvdAZ0yVibuiKpL1Q9fWC9n4daO1LWCfssM66kpvs7XK9QSJa20+JuTIixF8kELUQr7Vpnk8KE/5c5GzX3kR0ZT5E2E/tJcTaaacly3ISAlxug4F3dpI2CKTs59af8C3nq6JWOuW/loxEg70v7u9nT6xd6/YYk81KO/a0XwkI9aqSbn3Q6MiA9oscOexyBX/t6xcLt93Z4IHmDz/aJTu6S0jyq9FmBMQevoZawvvuD85KTOw9yYGpGtpHplkNRyeo21EYIZFiYYSIWbkFVLy6ShiBleuPJyxuiSL8aSMTWU7p4cGmv6vBscDoZxLfQXZi7y28OXkHi2PpJIZ5Vr5KjXHS6TuwxyGFl/zWRcYHfZxIkp/flu5sROwcvROJwsX71cOr3YFyfiGhxzfT3NrJQCkISOY5cABnya7xLQO34IrIBNh+TbC/EmSX0LJT3Ojjtt39l2QHt3ftNgnz+9g20cYNLyckeahnv4NivVkP3ERqKWRXtUsFg1HrbgAdo+vPmw2QY4BsavOxHfVuYQFskVJt/SyIlUWkmAz+QdIIZPIsyI1n4xHHkFhmWZrnZKD5Ima5SCzNgVugLWKHBLLILfoHXwZQAv1XEGfypNiBB7L/ApkkJmEtyF+PvnnV4j1VpzNd/D3cqer7+IvLtxjY8qR6/HVQYneXl5638rNTTU4PvtxMx+2Odj+mADuYTERnz6aCbTBtYEcM6uKrzg1wwth/UZu41pWBcPUmgm5292pkgQBZyHXuoFT/To7glsk4JsSkm01pYrSG718TwTvOJrvrN9+xOLueGfE84imtFOfoTl1kWlSWxqP1SlBHyMPajNq3tCvFWmyhnsuq5siMgjtH3eumZ6gNhpYJLekucQBgwbUwn0zTel0EzUJbtIHW9bZfslRYsd2ovui/3rBS1ArP3JtUeau4xbQkeill8Lesu1juDA5oqbTJ5lEwBKWz9PSH9ibQ8aoyMtMju1RAXKNAA27a8fqBsYvJ0ALVAAqTtVYh6kkpvQXzovjY1FnsQ4UwKW2V4t6B9fgWFgmpwhux8Oj8RTGzdzsBXrh7aKMU07M+fdnbT2cmUZHPAmIqh2wwZaUEQ6yOs1cHNmXiTFFHJsEFKYaizJpzaa1v4gxpfpKA+IHpp+jMf/lyc1KptTGgUiNonRN+AAT4OW7PcxThetmjO1pkgFA0Q0W6KLm398JssQcL5n3AQwj2MEDM9bnSCHNufmXPIz0WUZ9E4pvgzGRiw5rjo+uOd7F5MSTZ1Edag0Twi+nikfTEwCnVxwqCLkumzfw331BuX3lykLGAQx1r86wN9sdD9n6PKU1wgqiJ7tQL3sgRlIHglOpc9mH4CxJcuLDsmlBgHLzDcCR/WwmIy6SM6DUujaEvuQm1iX53h5CV7IwGlsL9fWvUBwjwhZv79GAyuZ/ANvBpyJBgTrEDps0zx/C+vMidVVofBMC+itEA0ZnkUuZMQ0B2/BMW8ZU/dQE1v87HIUCsvyLIBiwuQvbO2ZYXcvRbzm31ZnYYQztKT9MCJwXsoUwRtjiJhrKX/lAn//0Rk6gzhrX+snUq4F7JxXgE3m9mWVAwssTi54FwMnUdbRX+YJXcHKHulQ0zrQTo/DhK4KMgf6E7AZgPZB5wAA4IifLF2E5524vbYrknYhkLmUqdW00jM6v+rVRiuNeI3POuNGC3Eia3l3gH9MtNTHjnrDRk/YiKvwQcnjjtNg0cfjO2Q/wAo0yxjVTYngnD9kowuOspn8w19jZ38P/wdjpCZBzcNg8tCdOOP0S3HrvFrdCaPbQLwaGkimANu3bsEeTc1CBuA3nyeVO8ECSOlDFLqbcChjYmfedx7aZxs+jC3uF4M3+FoDC+3H5hLSmZAr1dedJO//KTiwSLh5tjCtLyp279HJihZik8yJP+RFC+YLM1Ew9QgK4kTW523hMsa1DPRDs7iBnZjtK55AtxfY9ZL+pV986FtsMApupWCODoIDnaFFDIGZEHJ5+wxWa4wpK1E9IG83HibmNAfzWrLD+aNopGQixn393G5/Kh8/xPazivO6QMgUVDYtcFRC1hK+/Cf4Vtrr4ar+3HVLSOmigWwXi1sgcDC3MEtgnSF68PmcIa3l5WKaPC7uweFRyFLNuAyPakP91qUyqCkDSpVkY283W1fRDmTCF+NtXM6KBsIP1z9wZwxkZ8TWo/WhSBF4Yh0SJQp+x8eiAVP7HgnQ8DIk3CvjiHR7IxZYbsTVCkaBejDCGFXvXik+XThSsiNk90NZu5ZDC+p5qu8+1oGIZTO6nX0eqNGlos2Sq2P3ecSO7wNubwW9zHwEXf7ThPNeIBNSrvvuX1lFJ1QgivRqNl8uyuqMSBRnzFm5eUJwTpgboQ2sEk/pI5XMt9J2xpd/C2SZmwcQdPdEdX/BwjeqVbUZDMRmxoc8/gREbyU8UWThxJO5B3Idx5JtKJ5AWQW8m8JpDAN6yPVLyJzfJElb4vTD+XEmc7cYY1QNUorgqsA+Dq5QMIfsO7LmOhSQX/dO5x+K+DAaqdkbPnD0feQSCfYv23wyrCABtMGJxc3e5vik73rvZS6xezlcBnfPb7QKgJi2wiOyW9mUjH6CUmTAIwcC/UG20JwlHiYZXFm0LMLn2DlBLmyTdGszjTUpzRXdVkGnGBPeKKpnCW6FN+S4YDssIDF2KTh2sbvhUWYLdekaZMUcg+h8NIyXZjyBAPBSGZ2U9GHwAnC3JkyMk+w7mhOXnhKnL1z9SlBBhPReYsgk+E76LLjcZplHbRGb0hQ7AgED7xJF7G9swP0j1SwssaUPkYauO2yrMIc8BvZSHEpuK2osknJWsTw1Cb9Bzi9yoEKIizQaG1N62xCawDZtBQsktHTOONV5CiABBXuqUPH21wbaKOFcv+KnEZYn8xcPKdl74XbM2Fjdnp/+N0OycfHJu5rzlTNB7js6ML+WuqM/BglXpGo+5PX+OOA1f4HlAhKx26pQrTvvbMYxtE3chhQ6NSnLsIzlxE7575odZLgIvx/oDflbCoL4tqpV0SuHusCe5g+GTmJA/cY/YeoNBio3kGM9SUt18i9sb1jZuqlKRWv02+i3JeORLnCC2vN1Hp01PDXP+N+kOZoQ0yrlcurOOkqYalX5Xh4Jy5RnaH54wgkDpaOK8LtGrQPF/vEoQHvrQwJCej7/V8PRdhFh7wg67pY9HxHJrI7NMKj+wU1smwimwFoc+wsYd7Eapqz9OUqgTfkke3AKQKTthrLAjAKJG7rlS0PkUWwAGC9Ri3S+/ar288NYqXdy0kuiT8CuI6P3VGCGYtwhaWEv5XoOVrmgJU5FO3d9EMR8MqG0RXdt76AhuoY9jTS5wMy6o3OjqseG8mlipELvp6pB4AmgLXN5/ZgToKXtgpRoaA7o/opeaMFXND4/LquMsCWZs20rPXBaR4oTcx98fknl2tPRW8k+eyboLMzqCdMRG5OUiNaLbQYLOIZgp1MDdNgGGqZsSB7kjqcb0KiODc+Uz7Cf/X5KRRDo3L31cP3mXElzeFUJ83IkR8DuNMIk6uLT3Ipw0q5k/2OIG8WtAGyBt8Rb0JM58oa2sg0Qu6pV/eq1Ax/hFShxnpJXhfQR5xDebExZdx7E+G/mZCtN0kjoOWEO6wg0uqRi+rWCku8HNWoY19iEn8qsjCQm0bv9qpjgzxLHjUhhymg32fg5Pzjq98DAwaJrDGQTsvS6eLo2V+6UV+jF8Fb4PJG2VpqjClG2c7kRvmlovqjJnUTYM1JkL+FoGxXgL8byEOJlzc8QZq3N4g8yF5l4XV+5uRHse+7GVSbbOnhKgWed4OM5D0x7wiH6q0BLSApAc2kg0REQ07Ut1+JD6NMoEJ1fwIhzOqlUcerrXEkz52Qx8T+tgoykzo2WsLQi86ixfs9stSmx9pnNVSSgbwHg/TTrU/wCfRhuFDlnLTwIRTnmjVIKbS+HP151BL04Tf+/Jl52FPVi49I3pLd+1YeiY9L1CtBHfNVadc/ItsnQ/XTc6va5tvb7iSg71YkPWoEZOtd6rhvE56iKWy5ZC6+VfC7f8/ndLD90C+OfnG3oyq5hguM/u+6cBUBy2gDlYe48w2fhDdCUCM2ndD/a4UyXfmhmCerorgfGze4amT8MKJHvEnc9wuUzuEAhxvQdb3LxS74irAjyHNclpPQwWkiSmx5w3i03/qox95LmmSDS2xaoagbj3vRgSKhlcBDBK96Sr+roV+rHxqChZn7BIwtFxlmfPV/EJvniibgKaVOB3wJ1A/S6kA4ZaWD5fnA/8uQo1/f4fXiMkzLGNW0CDEws+9QQD373VYsrtUonoB0exinRrcDMAUhZ29zJqrIRr9ugYy/pdThHcS3I3rPR7+1ddq8OZIBbHjfDbek+SkOy2tNyvNt4geeh5tqew+xqjJJ9oBejpw4hqEfY2dxxNh0nyMCvw212lWY6WIZRdwdDGvZ9kp2NgeiP/EB7x9+PON/2ilgbX4K3nbW8ykfYl3GDRSpJNzAYWW8oXt/y/FgbmjqnBO1+dSSywzX05eAijvyaxZpXFaz9xD7tfo8pfzNggMNq7ne2GY+DC6HL4RRwIezay03T6GCnv33SB7ejsUwGuLfQ+8ekPBstbstJmTSb/Wtpg8h1pJT5NB4auLcLaiBDqFR2OCGSbJyp6Who9oYPIM90hxD2s7YbZNZ4R4oi6iI4ShrZuSh94u92cTB22EAkd5s6FnZa0RGeHWwqqrgrqN+1em5+5gNjSs+RqYpjmSoWyPd/zcUFuDJ9I8RfJ0kVa1HvZAV3qu8cgeDlhpxNmBmcknW9wDTMOtuxuEPNrbiUgRkG5RG6AExo71Ou3UyGXpjvMHoHUAu+zcO0i4j2EH7ilW0+xjFfSzMxV9Brk24sLbyVfOnEjERlJmsua9WpO+tlsG7u9dn8aed8CwJzDi85CDs0MN0UqYA+wHQxqnQGbRKoGJD1+op80erKpYwhV/7xhfKqTgSOu6cKc6QCflYnRqfDbpkelokbaHLDhfB+Ll4CK/3pfH4APM0X+Lb35TG+zlgnkxOTMTiJ/CMQYt2KKF6y4DlDal+HfPyKSBkAd2IJrIN6Nafw4ycJ0e6uwjW6U+VZBLYiXwf/+lbaXrk7mtIUK7ggrRBUXvsr+roHvFz7ttK7I4yz1/PllUK5Q4egiPNbDHV8hJO/xrYdFxxBXD8i3RpmMl9QHQIT17w2hnDt/zCLmNWH62qX1s2UvuLb41PEwi/TPeFKeblZxCiBvWeA7eKc465XtWO0QOkC5wyIaD5xnG5RqjXVF4UCo7pRthlbzKJ4mTSqLRC3pJuFewrBswLGEmQgBsU2zz/6N0RqT/wglIFo4eMtPkKrtswO5X0EHoRQ9Dy+uR4uL7b3pA5iwQaZ+fhAhQCEqd7PTF1q/oXX4LSoOBVsAUMz5MMj80rJ7x4093p6i+FfaoTEvEysyXLwNiNtJKiibF3+okXljwS19s5U9Rn7Ul7OT3zQXj4GkULsuddqu/ObEhktcMxIZz6Pln7n6FV4tMDeYghDPuvZIMa7F64JH+BXdHEMdZyAVCUhmk8WMi/n8S9sHJDgoiTwZOICNyH8O8v3GVlAlZj3p9DA+zZwErLotnlrovJMGL8KfUtlRtWLxIDY1VbnlhIATg9L4jqjYMQBlJvN0Q853lgFum6fLEquJMKyzZEY/TxD2JDsw3GzRadoxZFaxra5HPvFEcE7peMLW84qYWNDA1VVZ7OUMbuRTQqRen0cK9oMhZTkGUO+fMoXo5QXSa7t0hb+mL8bZxRiskr8QE65WEmcmnjNJNd4OOfXshxL9eBKMjVfn6PE+mlJGjp1pmhBfAmg0PPmuW+wWGrLh9b+m5X2cViy00lVAJxWJUpehdYM0dGwXqjQIDwzUgSdqT6Sa3h1D2OIbk/x7l800R4YhttLH1twlh982vx3UrSVsewGv9TC53dUd1aVcGA1QWfjOrWkjNzLKZogjGEk4JOjZB69n9hb4IzNcpOOV7iWNIim8Lz6koC4uGt3+WYsOHs4oUGfSRUkK13LoUnf0SQBTSfFPwZUrTRflyIAdrKPLylFOTS45Zv9jVpVzzKZ/1zA+1zwdwKmWNnkMUuaJuMy/Jy6G4VJKVY2wYina4xFCy0yMKUuBnjCH2NNh6xlG9f0eoz8EqdnYOveAfHTYGNuRTXy1HI+zJFU5QefdHC+1iCmsQVS+AryyYVc8XYswAqiDipBdRXYyA8a+V2Cs6JMXi1NG1+MQKoQ0oGLtxjQpPgvXHB6l0kObc4O+Rqcfy5dLQK5zchwjHVS1V209WDVynx0I3YwDbtWWWbeqcuGhjbz5zY4BgITWLGyaZsCWEfL87BhhvsD2D+5IhpiY4YgUM8d398nhQsP8YCPXC+CQpTJXhL17RQOg3k/PaY1JQ0FD+ep5rYNbasDrR5lqnOURjO9NqwvqRFI3prfD+eH+0FAD9yN17wlDj9de7LsfaUlSStSQ0jAkSV0ANF7kTKLt0+mie0GJPp98yHCNAsDIpsxE26UYVdtctPtPuIuDUoQMYcPE76XlG9kHQxKD8KUktz97FHXXavgjBLubg99ubLWos7+lfgc7sbNMCnR34yDlyZQKmVCzj6X4VhFnlEw+wITGAHJpDMVZd0C3mbHLFI3R2tZHwDAjpJZwT5urTfdIYiqsj2QnJ+oTBh7q23fnWIg+zhP/w7b3oLBm/WCF7+jFY3V9IekRPkSFJOri0L0pIPYS7y5a12q2OTeTasN/F2fA9oDkjoDtIdvqtHy0QVs0571jZQCquwsaBFJ2UlLYyAwqARr3CtIP712Lbe2XdpbeyPafuzZdcvSPn4d0ycyua5pjnK5X77B83j6sJUN52Np9DBqirVRWADFgFNLcvnhrqBUUnzJfcokFByp554L0C0cSaas3FLqb5pi02UYQSVYMsw6s7JAB4UCgeLu9J9R1+ygauFvoM+VHWhkig2o2oTO8xsPfgkkKRgr43AYBWCC2LsInOA/NYmHrwzBkQIzXhc2RkufHRqeekshMXJgnvFXR3gzaR2G/lWB1RmUp41I8K3OWeRC+Cr0+xhLOYFXZVp3wAwgWXaQEgrOUI4vC3/abLth/NRzhm+o2/gWl5sg9vAWBeJOR4V7OWXtRxE6VHRZd/Ct7ZYLeFKAlQqqFnRaXQZti8+IpQ2ofd8qHK7Ol5K3EqXKraiZTv6X99UyudJefMd1UijpcHqRCBHOUizO+aliBtxLR09Me17eXfopHvFdZdtdAR4GFWtHr4YbjahzSv0dqX09P4FADoPmPHHiZbKbggLVy+XggcJF0poYv2zOBaWB67vI9RMSFq2P5lo2Zu7Y388HeashHrqmtYdrHsxa1WgLeuPXf2SuZF/1RDlXYT5ErKQ6yeQaSpDnGIamkD4LirRCDjDySvGInhXHfVVjS8amEFdqOZuy+ROZBynX5cueMjKPRPWGmFfbtcIq0j6OYh6IsmIezmLnfaBoqg6Eh5giYEUbnHkCatZ0Bvp/64Nmvbg3+7h4lm9Mo8w/ZEM9qpL3jghlC49vTBBB/2K93oByF/3mQo3hTXKRmR15Xrsc9oDxnhhm5PtclK9WXMlTj52l1PyJjHtTumOoh0sv6mbswBmZw/aXTEKqN4POFmya+xxN++c3r2UHX0laP9OugZZVbB2A4IZxK36GzcLsXaZoJnkHvV6atH0/7wYT+SNO24Ms7l1gmsqsdC5Jc18y3kyqVAq8JaW0kyzVC0CaGVbx8vSNCcRuPx0vyGldL1/GhJmi0ZroXhTeTGYbgUgLwrqjus66UjZ++pzx75xVrElkM4Tf5I9y6nxN/4UKtXR8nBoQIBRbO42G+Ol03EdrLaumx+N6CrIq/pSGgRWzox+VnmcpTWTZyVYia3F4nmZ5u8ILNgpbsDmrAEZ5BB6lQGcPJ5arrXWn9xMGqw4ECZ8K7yV1X9drFiswP1AMCrwAPyRvnkXsLI1IbpaBsvX8KUDIhhpNr66991gvW8y+vaPt9rAa9IzyXKtaP7C/zOHG48HAhqDGUEH1JXbfmp/JBBu7hAOSGDdx9uOS6JfxSQMVOr3WWDdv5gemWTOf4yqUVD9zjnHOwkt1kAT4zjvOinUad0UAcpM4mYl06Ndyq8q/i2geNyiQ0rM93Tf7HAalyw6UcbCbmJb6dSxLqTdcmhZpW46XPbiIIJg/2VPhJqwypHwqHascS7Q2lqIhOxroVvpybY7F8QhAPNn4DYC2+l+kWZR6wZLaU3Y+BntzoR4fT6aSXMwoM9ffIMOr2/tepNR7LxZGaugtBJDdGwlExuPFzU5sTlqGhjmok/Urvymj1UkrOdgmH1hUJxkAh0HBNZXLbYpOcFRXEIV/7Q0TzYxYJXJmmtd1oxWT7WfsE5hpNuDoWtUg62n539zOWxqazwsLvST3i40cfpVxoP2+6cPuIKakfivcMS6CNOsnChXtFdwqIj91ZFMHYQaROw9INNUPuKr3ucqBX2QG6SJm5DK5KQw3ZbHimkb6BPc2JCMTc5VSXFotKgZBb598V6dm88GReurFZtf/Rd+b9scAdx5eB1Vje9pmrc7pWYO4HvaTK4DI6ytRqgXlehFCnm8mtl4ct1OJ4IGLTqnmDsq0VquE051/t5b9ovvgwvbq4MxtmFxSoELGRq+T0cGEkEIwQOoSDbmObakdLL6VdUgxIg7hq8XTB8LUwYC7DExMEEZNGrUk/I7WlPdAy6JLXYgKWRjXQXWM7GuqWt3R3hycGVn94X3l3V8YTgwfRHz2aQ5vg2uS2x5vpbrG5OsQL6+0UweVJaalO3tc0fewNWwkf3M+Sg7qRPflkQzjUL1SpB59Ur/H7qc71GYFc3zzds2APB6NvTp4KjcjqvUOk55XiZL0G0f3hV1b+5isOvN1DLFFy43uqbfXxxcZcYkHpne0mee567ayiETJ7YB1MPukr6FK2a0/qMH6d9WFhmyx2AYjVCOWZ7wdiQUbCOp/aIbtQLyQ/JEk9Ha1ufDUJDO73FvDNq58nTZahzJSVC5RPaIc7j7qburIZ1JTeI4GZa3sIsgQmRYegxPi4QkL9rmuECgAV7Lo4IqB6iV97Ub+g/v3iSaloph/Z5IfB18ZMW2Csto2yc/Fv32XQ4+/zyKhzR1j5ypwx2lxgGM+IIJMWeozAnSs17NBEhex97Izz1IPwOG3L/AQzkpWvBSZmUGR0j/iF6wbe8s9wik6yTLGcXXBaj/WwS5Gv5K7GlgbanqbK+/MpqrnquipqiR8o1l/DcG7+EE9qY8x8f4t2TqgY65JaKHMcr/LsHBlW0K/hFD1sDUPmd2KoKOYxohXW4xE/xT3jc6KhOgg71pqrpLN7ZPZweSl2WJMVP6Bfy//f/3/HzXsbPrtbPrARCsIeka77s+XbUTQJgFDvApIkCgZhJ8kL/LvC0knRtTz8LbKvCfbWNuNfQcczRVNKh7g/WAmOGXQVrc+m02+x2Fe13VDFxHvlY7cKUezBvdSZR2j5PtdGbb2RZ0ZEVTHpzLnWEt3LqRuRwrS0U2I2hlZPdpYkcSY6M+juz4xRETbH+k+TUq92SzcXU38Vf5Igsqv52rghyYQ0eNrx8lZlCOnjMM5hnnM1hLrqK/omAGjs7B3F5I4FsUJCNV9/2sz25UmSPqWhgEgvmjAgZtGKEW+IXGACLaqe5Zn2khutY8HU1ak2/0NSNOZttit+b96fQOrEKU60upGz6dKV1Bo8tI8vVans8cmEY9zgsnhQD2Q2RvWGbhi3VsE7j70dNj85l4YYPC4ZZ90S9A8oKdWcUhGZh8G79kf536lhpTR0R2xmspVgQysa08DSPRS06sz/xUWkyxCVCNwi4Fx9AgRIKjOerK31Q2QV0A1ulwhfJCcau+yTptN/kBUaM1vCwryz8tyIfMbxMv8wkrjMw4aHTp6fuyJWz7M8SiLn74KWjHH3qZhTzUjN+LG7e/NQAOeyy0Yzax/YDDRwRfK+gwGuKQw/T38BCh0O3ptGbrBJHR3cJxGeAzlsNMO7mD6m2PtCkcPfj/jKlWTi+wd4f+Rbg8GoSAAAECzbdv1s23btm3btm3btm3btnlD3CAPWaa3z+sq7zV8V/sd+d88xL/TlOROpkrVsWvU69s5iC6WKAOH3s/343zwZs1bbViDT9jnGgH14Gie1/Fku9SxbL/zWaP7+Hjz9qCmT1CRIAVYqwQiM0SQzrHnTsmTr84aR3p64LtpaW6Mg3JtEpck/hcrr4LAdDC5059KleKMB5gTwSnEr1ukSmq51pVfGVip4mQTXqY0bn7ZRewhuySuub8GSNVfL7LB5TKxJ6cCzq7VAZnvD4Kcv59YZy1fWTtd7nHEmFlfznMjB00Z0R2TFCwz2wCTXyRrHZ1bmLZgJIpbxJ92axbsACs6twni1Ek4/SqgoEO/OJ7v1RY465Ev3umrurTadqdza32D8a5+0zn1MLAubFQAynqiy7juuIdt1235JFaib9MdpiSNXOJc5TdgYdOM5I6QpS9LBbDLwUCY6KKuiqfWB+hPudWMBhpHmBmvNF+tbUMyB4xqeooeIy2y71PxOSbt6q7RCbinF8T82g2xnL6ZVjyayozYxnMiXgOmxrvyWKx1juQj6hJnMneFsIkXNt6hnocwI9YBx9Dxz3TQtukdK7p3WGzhKKFNkIPEh+Nw03+50U2c94KKVr/INcshKjQHdbyBfl3HDef+l7mLjaf02ITUag+3KNGrOxTucLo076qHAqPw2Yncjl7QDr2Poz64SOZ+b6UMofEMpqugrVG1g0nX1M0q9NapZQowwZ90+LeoFp14UFcfaNxSvHIaXHH2o6d7W1hZWVyZ8zfYwVCkyEI7ogShGNwSSUAw9qarx4Ja1dobpcMXS45b8aV6iIAPBS2PUUPtPKAvGRxp2QmKbpcNvO0994HADdAUtPBORzXjsR5qFOp3jHHnPqJBFdlrAWFMoXjW8gz3Hl7l619s+PAvglNbEs0x+ArGhr89w2z0nOcbwC2oxTxy+U6Pk95SJN5h2Yrr/Ge9JWOLzNmKbRt+kcaskDUwdit6kw4pAdZtlTUoXC4ydufZxPm9nnpHZJp7vdsQIfSbusrVM39QwaZjsS5I7AU6VQjKMkePLqvwy+38MsF8dlKteQCJFrSmVuyJ9OIW8LtKnqJsH5BPl4N9Ufq2AT/vJMpNEf7uRGPIRUPUpTbKK8xKJUBevQpIGfDGOsXKRixeXwYtHYwYaWVcYXX6bgHiXuN1WKadEt26bM02JcoqwUKnpdk/BXCuSZISHTM9jC6TMLJSX7L+8jZZ88PrF1idyweGbNwqD0LKroFlrO7fmvK58UECZYRyeALrYWchq5JCB9mC0BI/yENIy4i4XX+74Fl5iVfJSLSJq9jddB6nBR/GgzpmAzaNshZgrks5shsJefTCIKMPsxpnFPhT0jErD+XuuA12NdgjRdYRqc/wQakY80qEiWyZhWmlbSQpdfwkjCKKYITN8lyUb6edLk5Q2q+YePOJwvnqR0W2EoviINL6OuIhfiTY6YqV7OyeWLEssiK37kq5mf8qE0LvU4S2jbdq1EkNJjss2SN6lWsOZhp9zCTfWYlaFoNjFWapXqJl9KvkT7QXHaqOryAYhGxClTbYOqjTVcxz4Vnq0lmYQfRGV47MS/PTpXj7jgJQWPp5Y+IhqU24uuLPJD6Y1aAiBvAK9ChZSY75O9QA0XxBFxk0Eew/vtDBvzfWlY6e53Blj11i5ExYQLF4qyO7MLnpSLl8Vnkg3pudwQQfLG/daY6M42R9BaS4OcZme6O5tZqUTyn69ux7fAN8Xuq5jwufqzYq5yRh5qZzy70G/dFonEX8Y0hggUcgL8YebxrELimmzesvl5tS+vzjJ2bvUNZ3r6cU3Pwdjx0ZmfcyKkjvaPNy1QjiTpWc/pLDrFDEWWOWlYSsNeYfy9UO3YgBfbvNwewqwFbWr4bsVlZSMiAg0DIX8GXjr6Y3FxHnRs5amu0WhGmzEFk/Um4yoztCJbAhernJIMR9UCtZSJcbqCDDuHHxgcwb867eMjawCRu8WAjjKvw1UhGZ92752/yQyrZPrNJ4/3nHqNlaseqLQSVitDsb3NkKt8E0BOhI2YU0yIVWD/PB3DU5TdOaSAvef2AJB9hYFS12x6ptjVw4PnpOPHesSRrZOJxVcv18E3BnhFZEzWiRDBPtvILbgkGYx0v5pe/6xXwTY3er9nlXwXtoWHTR5IAX8JRuOiDf6iw7ttxdVcwfKW8TEsUQ8ZfGhwf/A9ixMlI/ps/B13pmsFbqp9YzM4jqsi+byRrR0Y2BRYDD5XjKRTVhSvBT6jZQapzcXBPaSCfRM1vLSV2npaLJ5b2CiHmoc+nV1LKfUz6KH1cQ26K3w+yuIPewJQNZMDqc65UR20QHLxTGaFeU6hNrzZbwDPpARexD2Oi/E1hpN16Fs5oPryE2O0kW+SaBj7r/NRBwprcRY4ghAWdb8pVsCmtnyGedgFbLPO83Ocb5MsJrH3qQE7rwKwakcMg4bb2FPYWzHhWdaDH7Blzrq8wsIb9wbOQc8SJ8yYOOZPj3fhzEi9FyCFiSEphbbwvNjyomdyi/5MgPD8j7CW0/fL4XYA0XBRBDXlaOFqMMfyjP5htGDHEJDsyDcTE7bnBIzZzkRi/4YPK5p7hXd491mcLmfCg2rIDk0MZJN76dfNfnciLMXhg51yc2kTbCMdtip9FWipfvOruBuxQ1YHQ6TVYhJb0hAJDrvJ0Ds0xKkv+blf9NmNg6iGhPcNRbd/1L5TZO0X+L4YTYAWIhvdSbDDpU1uIx7i8pYh0FujU0Bmn82O2+1hS281MTvYAyt93yg/je0ZrkMCmJHFRx6c7tj5FEScq0BFEhR8htn3l56yDJ+wKQLr08s2LTnnYolT9i1m3a5Aj8BH/xEjXCqexalj3h1w7VdL6Ep7mAr33sbGFD/HDrWcVBERylYifOex4qVMieTYsQcSv10+kNH8hObGQRAgzejymB2E0aaQJYusp1T8g8auXN7zIL51ZMz9v5rtRK5jH8tu8Ot3MDFT7qyjtrEiYJgjrL5th9qEpTcjkl83ou6Mh7mmqfQHpmF1iaZBVLNO441DvjzP9FISh06Y7daB8RwqEKy6QrEZ5xRIYHbxReWcitj8WU9+/KCnzYRDcW8rBKvVhCWcFJSG1IUgORvJccid6YNjI8q5Vfp/IcJTA6Kv0ySUdF6iTbYIHVWzijlCSJW5YiSebkKJ+Z3uKgrB4JLys26x+kvhOYCZBbWeaZ+b+RJ0WrYERm2uZAt+J018kyg2tz1Ex85KEXu5lKYHizN0ZzspUNkn/YIavl+wq2dyFBEvCMI6iHldOeaSmMF8+JAxZjGtTQLV+aejrS+un+6rb56RHNnpUc/sKKrWUlp2a8/PStnT+DEI92fs4J07sHDoHW6SOQ+7cQakf4RhCDX/0L+VZLBAF5nGWbVm0gyOFGwiFTXO3wZa9CSYKc++gEiWvTObhTDmLotGwg3GuAlj3phPiQrFb/Ik9KcixiBdLpEVRuO/SMP1Uvb5a34Mlad9FfjmzaK5cANTrOMzqjzuDI4z9lqaY26+HWcaKpuB3x1ksljXDMV9LwPZEJwfyL/iyRatDFsYzuDGVgjpEQTX2NKt8AsutmC3GBjmdbcXZ/zJ4C3bTszjbA+8+ixj4OjEkcp1KanziO4wLiWq2F7spsX7BhNWh6T46X+PQTTqWpC70sy8qvBrdytiUYKPZ2C0XjYWN1jXGnBqnzIqbNOwRowt+pwYtuIiHryGrFacLEbae0QXtZp42nKXD3a4rmt3DFFWff5yXVznTMIxmMQtH+DbWXXg9wUCgMxttVaRzbbBrAyXdDo/QTgJXvP6Cavp3XVGPRQ05I8sz1sbalVPnYRZ9HaICDgQfeiQR0UNjodwuwLqYGgYSR6Ha/nzGmWptyqt0khOtrmyZGF2XaEpnR4HZGtTJhC5Q9c5cRuZbWLR1CGqNVjJwdEXBdYlBq8zSjNfvjrDEp5zQ9EijLioGpD5czAh6AS8O90tkQZiLB0TAuzlHKufIutwa8qOUnDuSXnQD/4QbAdEee6gLHskC1hwyLcaMp++6o4loOM8eGqmA7kXwiGbyxZ/UAHCDjoTolgnGFp8c8zTnTXKS7CKiBE33hKKYIBe3qYJKXmfaGZs0dq/HBlxVSZ6PG0DKf74L8zLTWwcYgMMRVIb5Ja5OCbbw+R3yTQplJqLytMMgkTwU+wz09LLFUt36UlCEPLnpjIWViOhou/dFltmq9EGfEGOMknlnuMaMtd7nvutg3XFwgBRWdf/eakKwJG+2eBp7LKjr2p3BbYVWVLZ0DAM1cZ7FeZPpZ/5klV4A7t53dGJyyMqTlGm2+CB0Z8Z+fpfF5Ba/Kpe7F6QiAOgqrqg8dKY6dNUHCrIdCOP0r1WrAdIBmNxkrNSUd1iDqSF2FcZDq8UpA66P7TaTEscnerme5kQOS5jW7SQRi9rh5yeBBapYOnx3Lk2mKF8XBB3QEC9CpvftoKBwGpHxNt0dpSMMyvslaeSeiowqHpHuSFiUkSEkNP/5YfJYO/QXPIOJg1N+nvysNijEeqOWALZ8o0EIY5j5gUmAedc4sKoP7Avv6i2jTZhVoCgs230z3YmrL2o8p+VGbPUy/C30l4epw2aQTNDh/U8JN7Cx0cZCCrrBecI4PJ0LAjys9pPGnVBxZL4/6LHLJRt3TkGkU7uh5q1uLYxUTCovoawRSJmw8M1nb63O0N9AlsTSnBq00Smf5Cb3k4GJ4pBAKrmR2wTqqFtljbfiZ+ha6E0/jSqbH6EMSa4JonPL4UF1XX9+TcBtJgz/ZXBxWMbl2xXcxl+PexjZm6+IEFNZ8UMBmSVUHcWvnCot3+bwBv8CaLyJ0Te00JdDnI3TIMlLS0UlwJYfUzZ0qDEodVEMs6Yr1mZziPMQG65swqKgPBXmpsBEr+hWDqFzjT8+Uh8EwG9HfcR50Hd7j/Trq0JmULbEWMZr2PCS9uozffzlE+lwymN2jWoA5DDCYoEQFYeRHclnjCCAEsTqEgHFi/uScC0sSSDmJYodo4IQO9ojINSskpGUubiIb155n/Vh1s9nKqKQw3tlK5OP4qVb41t4OWeAIq8nEqkhB/Ih/qKVHB5bRUcWwnWS1GLptcCxSNs4D66kkWDAgm8qOk7VnBY1ku6UXYWGB6diawxKTNzx0LoZBwpNA3A++KI3HBI+60vTv4qEPHM7359DsIShxNhn5l4nd1D8co9Z7X2JZiBP0HiF9RdIsTtABnVHNKUoL9KqrsJdZKeoNqMXuLyVj/WpALkZ6OIX5oaTxr4zUZJ1fFzKxVDAjc012pRlfh0R4ygpeYBvUJwR5djfY7sdR4vDOJqJ5bUu/Xw/B1sZQRAZ/bXg3g/tXacY1cElopoORMaopAR6PDP7mPmJC5m/GcFyk4UXMrQRO25xpZz4emjlbzNXLqlGUpBBwPma9MjFl8+nzHNjBBNqlVPmxDiivn5Bf9fgCd8laNtUPMbWN52DGY7xFbI7/KHxLOfSNmja9xJUtzoOhlrLwO5omCmxEsjI3qAa0bqFRpgyabtynU0lvi+eRgdJIbc2O8PbONdN+/q6OjlCw0NVq461ArAcLJqcuqKszRmNwiKdX9Y1mzWlYKq/Ah5XQeWksYngfIvxHCl72koNyru4yN8+ZIx5vtf5XeJn+FWFxvNeq9p6vnNi8H084LWrNFu0zUVOKIPiPMNBeRYtr9/HxYK3AfG9RDTlH2FuMHG3K/4rbNhLX00MpF+h7n9JcoGT1AaUPSWq5hU6Pv0bz+O/q9rqcgp/1ey4kfAitAgxKbwQ1UH9K4UxO7NeqoJPb2bYsiObBBf/q2EbqfsxAqFLdaotqsT+jmKUolo5UQhvvxwpEVX9BBGnJ8k7nEm+/vutZ98A8dc7U2clnnsiJS0r02dXQ+C8ts0pCCnAedzau2a2bwrGvUp2fDLVKkBcdHVclhP5uYlkn8uOGHgD/yQsbLSETWZOBwpeTh533aTLZOZYJSnFAVN1muMMwVqYwnrtQfEPScf+jh1S4g0CjER955YZzqLfZ8F/xcRoLTzz9Xtgfey5RU/fwOyAAxMUlLxKvB5goG8dChyw9h6mOmbSAh/uBl4yoC3id9nGYU2xgnZBOckXDBh/rHgVF5fSlao8+CIvIqIqrpBltdleU+5nScurLPA0n5BicEbUFI+07FhyqWXmq2Zj5VdvLt8assEzBecc9e+C92qYs52djkVgZEsidk6MxPwC9kZFd2YGZu+XFz8zxu+w5IJKoy4ZcuUwkKUoVv3MLC1zNqJJ+cnHHXwbCp87dcRU72HgQ3uyzsjY1u5N783uA09LDtE/HvLGbjD6HHNR1neYrzPxJm7DfevkUZpJAmTZSvyKsI9l3lNaK2paeRfrvJKhQGc0pPjB8k1516EhDPFNCRt+GW0fhfrmoouebbZGP7WDPGzGsgkQYQ+YwZguwypX7T+TIhFrmz4t22D9sn1oncYpjJyxXWMm/Th/oTnzwqKX1RtFHKYDC85WRhSMGlxnBMzUZPw3654Pb5uIQJcu2iI3vtjH/l/YnDmPZr5uVQTVLSbrRD/ioE7w6x2mjgS95HA8dewtfBFYpkM+u5Ja7uic5ZFU8Si8nsWZVZlXnyJFN6TN6dBtQYpL0pi3oqPdgVOI7ype+zyYsRZs+5warz6GiSg58ZxBTl6lyd4gBh5B+bigR7j/JAPBuApwpVkv6DMLbHW8g4IggSX8MjIkkR0GcWuXLo9/k0C9o7L76VO0tje9NuJLXbdiF9g/5xmiIZWH5UVEhtfza6Y4MU6QlLyq/ymJUF4Q6SVkxtorvnkyk1FVi3ebEWpHNuKGpsgU1AJWSEaNUGa2h7QAuEu5nFxZSvrE8E7zWLJnOaPITHfdVr/NnfDA8T4+wr4iOsxTj1gxzS3IB3iwWVroH/1tMx/F+hAHQPYv4N79taenpuhM0xIB7hGmoYxBYaC1XRVAxey3USjU1n5Qy76MCcgtXQAL3Em3RNcLUAvHFn1d5rXmNY+KRFUrdz2nqwNoRfJ0MrelFxo06T0Uy3d55hc2c36heCiJLC8WOOZMHfim0Bepj7dXiM4SzX7XX1JJ5Bta3O9VqVwH540zfnHwfhWKaSaezKCgSDc+IS3PPouq9mbmuSJPMtCTHzHmQDQb47pWqlmLh9pearkFz29UItQmcA2uVrFpZBPxpgxmRJoEBOqrVbyHBZPA/5n+LNQjllQCfikizvpTi/mgBJrZr9FzR6VRGnSZGozGrGJwnJevyugI8jijmpI8uEyIafcayzMt81OPLOKBxuWImiu4WWr2Bwjx16q6K6MyiSR+HRRFzDFHhbbnRizHj6kcPpagKoh11eKxpK17OLKMSr0N9Ic6TGBN3SfYgxtDkg6Gw9fL2uCKFPGXYCsfHki4n/q07jMu5QYFwu8wkZd325+R5Vi/LJF1+6tdd9sqrZDtUpRxqnTSAY39kXmREXV1AAFOyZXac2xrI99VdrU+BIcwTdboNl0imaH7UAcEBpVlhoCbEacxoBrjAEWzhTPlQvV421kuExYcn4LFHP5WziNQPKLqkDRMu/656scIrTylJn5/lez1VsKHEbGSbpHlMquP9SD1+HM4O/yWqrBaFeosONS5vYb1yIWuUMYKxvFl4iAJ2geRgT2eGR6o3rMh7fO4MRM196uEsCZOvYe36ejTWF3hVmM4rkQB+ZNj2BggNJIQuSk75Cp5tnxKBw3Rhy50mD5L8PiJCk1MUPbQC52MxU2IxxV6lRt2yThkMhIktBlqmJearN2KCg7NdwuaUSoQF8UQ6rFX+uSBgkinYdMS6GLTbuagCjbBW/Dx4wFPo7P3NW/eAAmB502Hz2SnFSPslrw4zIbBDoYFeoKz+krhmQov5WKOWuCDYUfk3eEh06Ibr5IrI0bPU1b6JfbGVdz8DNxs+rkvrgwdBC2jomv/N5kP9JkOEw66uyC5spfQ/XJs4fVYtnXnC72QgDXAja7jZuNkhrtas2424lvM/d0Jea7sJQ9QcQSU3snakpPWi9Agi0rcGs6eU67Ei383lz6YFVNiGYfOXmzcB33PfTT+kaAWiL9/XvX6qf4PWvQ4WqaFD80fFOVw+uexQFEt5ZdoQqY+Dy3KxNf0gfZrcVIUBbbyN0JlAZiM69Sk5TMAXL6PvS7xaGcNZwGic4U/+ZHyIi/OqF1Mytf8Kq4qgFJNyKQtBAUYyWkG7Ym2YQpzw4Zr6jG9O5u/qdIVsxgeKh/GGxJ1phMFfO3uxeAZC2swtrh41cJSjPdRaZ7l4hrrPN/LzLoIBSbK6IZjRo/478XXDDa4qO0UuthZ6xio1fZ9y6Dys8rXYGFc1WZ3gQeEgiUZgbzqasG8cM554ronaRp3LUI3399OBlAxOC8shj8G4XZ29VCFnp7hmqBoVvSk04G0udDlKbQIGb0jdEcdyhP1Sdvi6hr2CH1ET8cBT+w7yRC5mFp1/3DnVTZrFkfr+fMt9CaRN7YuSo/t3sH2sk2s6eTfVordh7W+WjA07SNruoh07LTOWK97DMBp7Jh9oG2zcp6qzz/TEbmO1iWpT0STXR9B9pS7o3DHXYNKkfHbArHHqWQt8hatuFDK9LrZuz1YrpOROO0zw1352LpGuL1EhU1kIDXXOIUQ9a2nsAFyGJL0tpsmVtTPTNnbZw2Xek1TLEDEdiIlF96FbhPlRnwK9BUh8SbzOpjxFmwfZHnz3vFAG0Y1BNqrxW8L1QqPQnLd/iB3glHr8BDwcUKGealRfoXsCrBn7aDGYtyz7g8chncjOXoOffJkHNz1AXvv3k0sX8MkSNxM1JcxNpbVxe/lbfAuTqQ2MRP/zW/Ol4SvA+SboEptJa2aTb4iHTHVpPBo5b1P41Eqar1JqILLTONF9FSmXuP6afQYGVa2PO0LndOrcYghXoGEgbV7rDyIZ/0TlLZVI9MngzfSpVJ8UHQuX5CEA3ZK38hgCjCJ5ZiQ7AzeytFEpDFysa5sj2x4BQeETtaeUrks+8/RlLNiYjYUOTGK8U+ODY/Abc66eyTnBYPK1Eyd9cFiCA9f3ciTdMFq7ExZyjLp9Ru+AicLVm8nrN8r4cf5nghjY6Husw39FmxV6y38yLMCsRkBqN4dK7dfPiRFe0KhuLYZzs6MLpjOb+pMpqn5Xu7zPfMrdc3XVNESPckOx80nlcA53mswVMP2dBIFQpqVI6dMI3WPrPgnbkTe/wweNyJ9KHAs9SkoovGQZ2lbpx1JkQzslW4lq2b+53PUYga1ncr1nJkCkPuPrEX41ErkjKp3Q3w3HJv0tHgdI/BbmJd9ir4d3KC+VC4vWOqei7WeomZ3IO0jC13o69b3KOKGQI/gluddqs2RxD8OIqJ800kRH1u+jxRb/OujuFDtfFEDTQSLjNfDSqgi1Vb9HtKAj0ODI7/BD6QPQHd0FCE6R+QCkIzC3RUhrgTIs7z95uHf9027R95uAzf7cYbgr7Xl7OYa30WmlENHaXzzABEPq7tSDpCZ4AoFqCCSWk9N+Ut88FMnTWmb1plRcfGoTpzOFWKcOPA+f7hBwm+c/gTclKEDUmvBift5Q8APEHs4yhaHC9Zu5ajOoT2Sxc0NDZ9n+0PB0gNKCKEqi9Orf92WoKCROdlUQ9lGV43BFnZRL0s7ZAX8DEYFAWyQIiQQIpnwKHcwNEq0RvOcDiHycZEkH3ayzaOfFHkjdRqgfJM4fJxs8Qw3oIlxtq+Ez99DBqquiu5tAX5fxkdoICEaUPWSNVxIFpt3CXsepQ3ONKOILXDMkJRpMw8SEh0dr9p4KwlOir/WtKOIQ4Bd5zeadlByXO+5x81ILl4q0kvnzqMTADk6d2M+guiOFJE3JniOJV9BsXCJzrlvb8GFGSWB/6kfL2SqY+YIQIkBSfrEmk3aRtK4RnxFMPpSJFfEPyVxcYgBrxnJ6TYGm/DVIOffMYi1Voc+cLsm4AE8qruCSr2gNmSCWSI7MW7aYRW/brzalapZ38o9k42J8VIYXPhjBQd7wsFPOvKOb8ihNTLU/XYzJEvqEHBqz2RYLYZTP8myCx4Q89VsdXfD3gghbNbMhovpKbQLDUxEIMVqmV40D7MDYCpjUHQdZEdT5BhUOqN0rDRkDum8c4JNazHaP7P6NA75VH5EaDX9FB9OZ8YdChLR0jUYd8XPffC5SI3tt0dN5afqc68MiR5UwrzDMzjqq7kPrMfPuGGp5bRqxDV3VjdJ1TqLK8qOmfjQ9yXMjUw7wgoE0NrZFJdvGwtEx0l4aHdpNk0xLhHy5eHlNsOvH4fMLj4lVmm93/1y3GS07RYq/Kdn6oEuX5Ykna34JXYYJ/GQ+8YfZcAoMbeZE+FCVQGLknR/qyTwsJchouT4LDksZCM/eq9Zq1f3ZEOKYIqaooojcInv2vjMG3eDEX3PXJoERwDv6p0+D5uiJPIgP1l7kcbpKXTOa8bkQlbAMGKCtlfa0nwocJvF0Vn9++YH2a8dGBsUhpZCJW85MFCP92kBOL+wtV3MXYm8uJMuh/bB5jJS0Pz59AHLqXq7iodIGZxUYt3tqIS/y77M7OSNyx3uiEk6lwei6vW/KcySN5jyhAafIL3gfqsRwYrbRiIemZI0SlObcS1nGUkoKviFKK8iBG6XsGrD097wVRgUvRzZkySHtpMQ/vLARUboueRtdnyAjWi945k+Rf15Q1tkjWwv5BktjEs/PESWK5cbdn11Zf1NoGvXlp11ps0ad/t8r+w3h0ifOlUoi6ZHKfEXx0f4JDYH/slFn9N9VwWFx9ZJeLQPgH5kY65ON1f1qiuL6B3CXEnFvJORwJRhjgCGoz73b7NsLniojKImjIAAGrY4r47Nfs1TcQTA53fO2cgz86buAXHYPXDCMttOjWZt4qnWN5QLIVt1h2yXbG8qWKeMg/Y/yIcUNSbemvRSeryiBziWHwRmhK4WaiZFE6xKFhxzIo6rr31HA78lcsZe7gOl4EQeZPezLBhRb0M+t+szGFdu/z6B2gggbp+BLw/kDsMfarMnq2SJiYSDWsWQKHS7/SXMWayHVNys7BrX3SadspFKjwXSasYajQd9uxcHtlRJNGN/tSMYjrFv76fBYMYee4Emz8EUirtpwqnqqGCW6GYUKK3q3CWryqmUsufx5jEE/qMmvsZPMmOFwBvknpfXTEnKSw37arcU/V4PTsZWJv+DOEvOqoJGy+OSj+3Dl1VL2qKSIZ7zJ2DBlmrB5sU4QrLkMHH/YQIz7OY+oQKIhIDuoV7Mm9kWeJ69wiwTBXf8dLeps+Bl7kU9eKBZ6spSTeC+ckVVTVW92uhF3Zu2YZoU7jOwB7qvdGAdAzGHQoFYU3vHyMAjlwns1ExOovO5bZarVTyzZVYELooZiXgNXlFLs7eR8eswPz3P556rMTS0XFYHOHG1Ot6VSX+F7se5RVrKq17DlozUrzTg5WLQoB/vmkvaE3DCpBGC+50UtwJOOANVJ1VTus0XYgVSXTmdoGzPvw1B7dXciqb1gxvQ6ogJZqu80IMhfZ9pRqtcI5ZveEMCyCKki8l2bv9Z+RbHKGA+ufOzKte9/FJbRxCi4XZUfGTr0i99bB7UiNKV7gLjbjphyBKhDwmCbo5z0VtHvTdxyQROXtRrEuOkto0UvqC/5QHdbsXNLoWP6aAwbePWqyWLx4AqSUZZMNSZOQ43u/piBLcIBc1ZhzqQRPPna11X1tAUsq1XIyVzlPQBrqW4mARCQxRTleA3msAmtijewPlqnd3DG5TMTK+yg8UFVIEpqmBFKSoFMHCFlT5wNqI8JTt5U6F2Q8jPEQHMP+DZfI8icl4xwWuzTZYod1cpWsfiuFcJfj0Rx2AJ0eytElQMlAYc9kq9yKlJg6UBR3INHyF5tKA2rV1ql0vj5nXy6zCnt1fexEph/KQHHdNuQe2yssDsP4bj/inrPqPEUPpA6tTBKpYuh9nLreDOnDKTkn/jEPwA7QSuNdIFt1tNNrvWriLge74RM6j6ltATq3DU23VrjJEDmq4xPVhEzU3vQT/UOpMo+7WALKZ6sdw1Czh8JX7KbM/dgd23S/8Y8o90zb+sZ5T3DgKXzMDyM3P+J+nA+NUMFRLasz1RjR7VaYH6w6VcaFKQTq4rf50COLlT/+2V11k6bpFssTI5cFxAG/CFdRK7OzVID/qIvO1UNjYbxcHlwhB5xd+CMJp7lsygNEFqvWR89REIF6nsAoidRHwTkjmVQH/ixpxOzV4UUQPOegZfyhKGMI22B8suqIvODCAXzFbyNQ4KpQxZ9WD35AhG1BNWmvyks9Ey8lkIxWGcCo1G1Cg7+R2r3uzMLmxmTDkPy2pKbKfyGWVjtuW3HLs1fEj1FStEfIiaeQ+IZLnu7dcSBPrCsjUZ9nWkGC9GIuTDHgJz8x/R+pBnIvFXUoAP9AIYXeQavK6+xt6jwE2fTFx6gC9Djxu9uJ1WRBn6TudzebKQp52isGnJEAFa28rDpA4W/erHBAZF0/RzCXXEpbMx9G0hnwybaKJb6c5F4VCXNu3x0B+spPgJZZmvjYGPRt0boI9F/jFvieSZlp3EDp8qXSoSPYeMrABQIVewCqp6N3EyCarxjrpwnf9/jtcU6oNVln1xoxbqgwZrT8gA8bSIaEz6kUbCYYJICRPOadOYacbCEWJYzAmbV8suu0wOWq6Om0e0T8CfJwHFeSdBeu1LSmt9GyRZPXVZmlfF1u5aHGg420selqLFLE42+GaeeVSxI2AFrSsPxq4FRJCttRTK5BG4vVfPcT7i9ViZlGPSFSqGs7h8TCkUXScXzfZ1TxJ9LWTHnKtbyXGKn5I7qtwMovZGvTHU0fE8NauaEXKafOEH1I5OTIZBo0w3++8CxOfYp3aR7kNc+14SNIhtinlBR9AmBBCMrMVsnR77OaTHhXmCqYOP9TTIqRXQlbluTlNkSZRhGmGqrzuVtTiJ6LTqTUBRt0gKM3Mh3XVZrHlEh0rniCLMIXYzgjQ5DC6F+8xTM7ucnKJzNqhdznhDgBcCSFVaGtJdzKrQ+pRxX8+C41FJfEBECsLsOxIIEVdoGLxuOvFvkQ+ExzDpnLaDXivS9zqEMqXHbSOACMxPcp55Fddhca+rOZuglVd4gdyV23jpAcMULvSd0MyIrU/v11lECAogcTK1jAqObw0H84jYxf8hfZl79ftS3iWoeO9gZOogzecN3g7eUjgXBwW+SGnaZK8FpCVSF0h0nLvJnA5kC4pTOXGDKVKg3bRh+m/SttwH1lll6lX4dRFkjvjgS6NQ1TtII+KbBrEO30eBiT3csAoSKsOdTB0Zgtc9JWygcNj7f43869aIxwVU4HIqqzV8AO8kkn+yf8L5LVfGIM6VZ1jT6euvc1V3T3XSSIYRyUXCsXkvmRAckhrCo9+WgXIoVxnuDfgu62vToF3kOayHPnXecvRkhE7YqAsbEWW6CbXCecDdsEK2j8Dap663cgYHT09hyVmJu9emQP5BuLnYQsSZeIdtOSYqGArJ+z+IXIUw6f9KJ46CLOI7BDOH/+YVHzrvQBgDg8PR64SOrWk/knb9pMpLYnoBhF+WCD8DKBH+Pr0fAKHPdemL1qWa0rNLFcNEQdS2wsgt8Fa+YfZ+/y6rD29cDZ0sNArNSvNmDuc0YdYz9zvqDOFO0IYwblxai9oNHW6f+4HGkM8fYvlagABgTdwCgTpFjQ+GDjHFde0qeNbaP2FSMZl39fvnhDiVd9PEBNoImy6RJ3eQXUSu48jzMsyb9M6kfKX+qpPg+yoDV2pVV23X7gISQGAO+KljyKDUN+0/u68/CrgqFB3Tiz9ySHRkeljukY6gr6F+TWop3r/lzeb7aodPMfM29tuPNmbWdQqwBrZsIXlSURne+YWVQNdejHavzXImYaDSZNaimwwnA90nxRGx1Gi25WYnh8Zb3/Pf9Gfu4hfia2ox9TJA3BUUNCOxfbeAfom9yP7l+dhanefpBmC9/yx3k2jooTyDVGpcNxFRIV0Bqop97KFggPh5n+Si91h3ZYB90uOXnvKr9hv525IJViMF9oU7eVRmEywL6fMjZU7Mw5Nqk9IjOKJuKCap9DQcFDMY/OhnYi+3vP+TCwfkFvUJIZe2NAaDOmHK6RA5zB/KSOO4teiYL9uOAYxpPan15vC6v26CSdYD0H37MFhLokSFQnccE/w3pRlY+lbM/XKMXg5pkbLNN6rmEcaay31Nu/pkgb/zmfFG/+bYg1q8yskj0a/c+iMWjyR+o1sGoUD3kIdNEnmUNyUloMYebpmHRMH1HtRS03/q1aFlyIW97Xi4xiraY/TACPvoGx3xas1yJVR/EhtUJwMtDXZlC4CEtu9Cw1eYq9ssmqEIvbjhWSBsd/7r3A4rIDLPlw2w84HMErspt9uZiyI6kMkww/K2e0L2KmCipJkI2b76lpatK/Dml5w9EmwphzI8xcARu1oEFsoD5TQT7sxRyj6V7BJHd1TKYWCtG+c5UJEamnnYyrC0XKBZdMettTooohwKx1ADOYXzOAxk4TKgcrL67AUpVn2tA9CMYTawgcyoPPq/JWRA0kAEfh0dCL5lpFuLMJyDcTHPETXyQM8nfZAxWjezcG7avlDFb7MKfbtZfD8yDwybhNGCKVuNKs/FhLYiKfM42FBM7geUSKU2GilhiYJKWeN4FQULHRI3uOwFhkXy/hNY54lqcDbmLsNBuB9EgfekdNvHvUKwYDgOoTLYTBJHg3AnMzZogb37mHX0jAm/ZIlgn5IRJSDABkBsfO5Yf5hr2guaoaYJHdFVTCI5m9CD3zUq+oaf4tOwq2R/Td7u/MekjzS41iw3Pr8jROQkRPersZETBsyjqDdxXnfxSHOkVmSZZh7dJ2cOyzx+10Hb5NBxVGHdYrLIe+jOclDl2mE2ML39AW9QQOrrSpgHLJHee1ctqBkq96HnP4Ilq1ikOdiwsmru+qH0YpujlBBkSIi5w6cAfuCecp2s+4vXI/CnRuK59IJXxC/1ox2AwdVm7RZOidpsq/tqSlSs/Z/UxxdciRUoScdmTjAz6Fk2Zu0OD0lwrTIhvmgjpe2h2E/WJ3oiNLXCExXc5DdfdY1Ys7Y1qD7F+HWc1RX0WYQviDlIBVTa4SpqLEdGfgNwX5vAohOVHm8k6hU62FDm1S+U/7KiVDEkbjT4hhKIMQhOa58His0wDlZPFU0aBVg1bafPsSjl7uJQQIWgXIglXed7L82+z+EwYD2VsvpfZAgiLyJGLfxrc7qTXlktAjxAgzthQmCqQEqzeQSP997NDCmR3viWfiYZ49IpsSU3XAYQoBrMWSH5uujgSB7coKG9Rk9kypvKvPsjsoBFfKDWgZ5iCQYBIZOqxJnw3K/e3OvrpSFUStMrYoRQR3pkzHwWFtvPe9W7fgmhQXFvtO1eTokDLaeECjShg2poNsOPkBqw8pdF5u4gWKTasQ7kukWKVqoXWkMLiatMplKkQdaTvcNrkYJBYE4FV7dSrjKw0IhVNxJhCzXDzjzZzav0ZqDD+STygyX4wO5qf7QEEqZBDzosUCxx6rXkDimOHyxWtddbYfKmc34eG54UwKV5fpxQSMMe9HiiGbujyKacTI94CCXonPh35h8Irr9v8qZ0KRUXaOaLjVLMFavD7FzXXvIYLtsgM8ni0DxtZ0RqE/OWADDhH71CoKlLZbXD99KLM9us6PAjr/czSoDLalpPtyFvM+TMoDcc5XAlxkrkKaApf20CC9vu5XYVzrDU/X6TCNKUDNHju1FJGerI/FFjkuhNuSDyC2n8qIwuWSGiW+66hEoMvUVwbj+Blyr6D2rDkYNWF7iGE+USxRaUpV6/UrRDte+Rs1TomiqW+C3uTq5Z1gp3T3b9X0gJMLDiLV3urRjeqD3LFEspRIo+qhry1slnBpe0e5OpeIbbkRh6pDWyqrdT2N0vqzfOcyO5U4HTUnMGpYrYabFlXWcIzvbaHhcdljfms6vKXujxMXrGOsaHAeUh1eO8Ptkrrz6v/sGXX2vyFHUtk/OzGyvs1yWlcLgyUhEEd77qZCLxtnTYaLxguGIA4tf96UzsWMr45BOrKCNEKyJz4ZkCmO7Q0Ctw9qzaKZhMAIXNzRWOcNiSsDmphlai1j2tncoyH5VCM3yaM+ORn599y7rp0onzlOYUkMDj8qgzX0yn86aBdueygXUEKA3qHBhM5bmBmx7hY8ZJX29WGzkHIaAHhJLWj/Q0Yx1Cse81LxDGHprSZMElVVgBBUU+0S5qLq6Fe3dUw/9xQONsJxyr59+KOY/T0Zm24BCtYukpIJCgZs5A+TqZMCcofcgD6B2ktKC0tE+mnuVVHvwFb1bSfluXTQi6LUEvYhelYSSsZAj9F01ZGy0CEGlyRFZOaPm0w/fTe7oafb0zrocxCcq0qWmP2mmqM5z2bmYGrfH1ir6ncW33N3bLVLy3Ly4eAG0foPdBsY5n8wrFqXliOJH2weUPJSRlgohSseGFU02FoY4G4svltKbDzTL4kThLRw8ri/EAph5oRsVRydPBLXXyrVlb3njj8PuEsKnJSqfvsc46jYtNm5YMjK6gfYwrsJe5cpn4P7x5y4qvu8nWbG4njDZKHVHlB9qrn/LMmYh/GRqHkX3WVQhm7jbAQFwVU2j3BngbFlPf+TqlTilaQNp2ZakeKHjkxNNvWVJqe3uCU1qVaPoZ0jQ6rcAAa5Y81mU/1BONc8N6LWtQgiBSJ6F0m8sLWW1jh/dqlYruxTEyW9A6aRFj2Da1Uz78UWpcK3bNeI8zIIr3zuIr1/z1+6IsqAkVjk8NeSQFoPVxaKHYea94BK49+kXU1LR5hCXlPUcPwg6gbOLDa7M4ChiUmzI7FYcOCRdZIJgZu/6hh+Vd2+4QP8Gs1xgBtNpkOu/dqwgIGE8T1NQ89ubocSuBvFuwtDtEJtxfJi++6+lBBLpkRilrkshdzZh1oPnv+5o5vRWd9QbQBqo2KUQlE2O6ff2IOaXOkdE0fpWFAJBeEZiRakMoxToLDoPKQLzYUo73Pb7HsocQzBejSlOP1p36+wxBl1i8O+baJKrh/YLSzLE4UIx7PgZN/kUUym2fDEq3mqE4NA+n84+HZA99FvNLwBwZGukTBXfpyF6HYBmg6Fwk0rJ098TiG9y7Jz2GKpXh0skrPqhh4T15mvittPpv0zldTb4M/Zca5WelHrNkHww7fu1JoNPOGogvBn7pX8s6Whhw2ab6zDPLqEb+hqHF8SEAozsoJz6ECuAJuqrXaxc5dOvF69kSj+RNhmSTinytIVjeD0EBm1CizY9tXGkqpYSMD9cYIclOCcIj4BbpJdztzKhq4fxYAkxxm4/f+bW+YkmDfJ0Xkv6l7HcPVa2iQnibx0Ro3MYVJ6UHqkY2lFj4cieXRBkMUpXwJY6oX3Armx87cBpJGR26t05kNfj6KwXPBpeudpcIpFnGKn7YW4NdkRoPYhCCt/Afzs+01hM2KVv6GrbVnFEy+leCGO4msuXjMXaGjf+AAw0P3M2RBEa2oiAoTNmY8robYOyhnEMQEr9tE3sAjW3dhqvtb1JHW+fm4yfD1k/6XgV6BhXNgu5VI9VVquIvS0vFWsCrVLoGxBuxbEuA1EbUPYEZH2J/peZ21XKytlFwYYQHFlBdvkwDDen6Fa2REtke0w16nF+AelH1HguONH9Y80I7O8YwzD1lwbgf06yss01ExA+pT0r53lM77jTRBENvL8+KdJaT8s/nsBZ0fmQBdMqJeJtTO60SIM0IFYT+i4Ku9KQ1muIg1l7IpAAUxyxQ3yGgc6UTT2QzmxZfczoNXUAdb+qp24TgI54pHdRxBohnYDSAmV8etQB0e9ba8m5Bi1GYfCvNnZ9D9fqh/mD6q5m+MMe/7ih8KT5uLtpQfSuNbkA2y8fqUr97RrnBVpED7gNNoBVIjkpx6BtWxg0zpqkAET4pZqoEuBf5Ll83RVpidNJfS25F9NhKZuNrr1h9wum+CQY/Ug2phFWGM1e0xfyvOuZpytXKu/E5iK1T9g9NWGRtXcHb3cAsoyO0QHHeL93VY1f6KO46xAPHEDmHCkp0tEV08/jeHLU+lH9BTHtqHPO7R83yuXNVR7pdHj/OoDhm9kjYKlFqIi5phxqNKuUu6rV63SjXJ4zWE3uwBAXPV181sYgJPEl3YRtUFZXK7B5SMvMQfgQSIxF7QDAluTsZSuAqKpJm0dSoAI6M9/Qwj9tu5Q1WC9CtdSYS6qO2iOLIKtlVqvPfBYkJ4u0NvfpAj6INYbCipa8DkCAzHEijKiTOUkpbhgMh1lnMCvjlBbCntKX87XJ84mC7XxakwwO7xllUAxKf+NuLZHIbkKg1fH8YqUQBzqeVEQeM6fU2sckSZQkCXIhj8MNrKrD7voaf6R+HXB6kalrwoKUBmeHr6nJVmEZwHPRAgIseh3axVs/KeDYlSF6WaxpglX78y8NIJL09L6NFT9S5bZE9qFSpFYiGMbW9FCW/ujMYwDlNobbRXe7gXeDZaMkm2L7JuAnNc0/wbwj81EPCWldiSO0BASbZHn3y8ZP4Em2BI93H5gkj6cN9xQrZCpAyQf+p38Yh5jlDC3iXyWI2HVS0tae+FvOjaMEmNqa9b4Ndol7E4cfPrYkZxLaNUbizfSHZ22iy/PIXVUpWxLliW+afwei5QiN659cuQAxqzpwb/K86CYIGLTfBSuCszNjH0Jszizk0qNLO0AR3WBcBcvgk3dm/Dpn6IeLQ4pF/JIng9rduuK7rlyXC0WlR4eSoUdUwi+3AxZwFHqoPU9oUiC7zFu3WXXwNwr42WaXsJMSOxQSpQe8q4FlrlGV9l3SSH+UD/RdpZurpzYRWNVyGl6378wBhoEHZAXBu+5n5ozeDURgeR1UpDINfMfgZIfhYRc/wBogtSYcVvX87+3tbRxVeD8VRi/vd4w+SuRvTooPytrWF1ORNwDj3a8HenhRD9LPiej5X4dotJJOmREOrOKSKs/Gdba3uA8lkXqKz4K+Tq718iuSVX+WKrT6nDgK0okqa3wBADokCTsF0hNtnBG0yxbJqEOFXm2FJrz88mya7pVfsZdXeNYGKwoTjZl29otRul5R/zmDeAAwvhcRFjYGbaZ94yZwo1KKdWkEZH/SSRo4L5ZOuO0BaLCYjxEpK9iSEmM3pMyoHPLTVzWPq9e7kIfTLgOObftqidftw05//Iv7V+sEKSVX41pDFbAxTknerO1P+4hw9Q/vSHqeDmfIPnrmvWWStshBWBxD6VAd5PiH7DuXWd+QOWjeFWi5cv9OZOJd4/GdCAzMpDx4++npzKOoM/0oxU64qzg6XjCRL1T+F76Tb6ksXSJQVLGa1w74Oni8+K1TVjxnu9qCw/g76b3d/847C8g8SEvNGummbxCx6b7YAQv0r8OkoZoU9CoBwtACa4HN4nDzyMW7/8Snd2fy3Ol91fVF3lGKdCA4mrvUkMCHQNgOuLOdZlV1s1eepjSdq/UCO+tBUk8B0MB97kdF+BDSdOm1+3+jj+w6ncuxGqzsbqI0ZFpjyuofCBvQNqOO4ZJUT9GlQ6+gK750tfDf+FSXnPo5ugGL1Up6v7WtXcpP57Av93cB/MuEN9SsWyPvIECdLDbZ9Uh1jstNeGfkUTjh1hdBRQRC24I2UkJqLYhqZXy91ngZVUGwAUM6O3qOSB0Qzl5Dd8JFbTIWOU8YYUx1nKuFE3oWihzwcxCW8vfPMEY4mnYy4kDh/IosxN7wLrUvoni0dlh4gF2lRH1kOQiquZqv6f1lGo9w/jQ6+SGSpTM1JDg82gjKiW/CyZ2wGVRkIxP4nc7CkWaHCtYg7Pxkndsx9y66DYtV1j4WD7+XDr71spmPMWI6W/7AQ9HNREZfifGGU4B4aPn1ECkLeSRkxGToU1Ljx1B6Q7dQFYLzbItrb/tgiGtETnCi1aIGw1O3l7JDtf8Ry/g0LGJUfVA1eubQpPB88Ash3fE7Y1yDcJPrwnSZL8INxWGUvsq4N8NPc9S3ozZcE5u8dMbT+ErxTphjt5qOV3kMw9ca05CPkx07KqZJjZ7pS0xvYtCXnAHZeqmd39bIpvXZR3Wx2Akao85iiK2IVrGtwPIrhLe0WQ7bmiES6avDfqo0pP/x4VLxTTtCKKbs2exaMiqDbURPTu00cJIQDbttdXySeNY31XGm26iEAAhOdczMK/QCOetdeP4i9sWaK+9lEp+tky8ct+Y1FbL4gEsnJwZEzp4BnufBoNv3yDpQi0Efohycxxe5vZogYmQtQmLmXZP+EoXtxC04v+f0ozj1C+NjpJJ8VBLT7Cpr2U2bVYIst9vRm458P0lkBwLUKMgFeX2h1l5Q8eWKhbeCzC2MX+Y7W8+TB7SioU+YQAgt/C7id+0Q7ri/YNauz0fBhYMDGq3XvUtfepCI4SyF9SWtt8vSxAySpxk0ye+/xDxqUx3XZxB+ZqugnyeWCOCwywqNp0iJI5JtQoPDBiGHr6vo9mLQYAhYtiFv/cLytJ9rULrp/09miyQ6SMIVDZgFjHfdSHk7rUd/wLD1qvZFOIyDo1u0+S2Mhhp8vFY7BYXXDjrAR2Zrt389uitZF+8MxMeT8Qm5OwBP9sw9+So1845FWqqkaSHr4odQHQYd0iCYye5JGQxaAlJlp+WOlH9jnK1EeAQfHZHhOBKMg3iu6wyHTVs6IhbSpF3hof5Mdkx+g+zy4NPm2bcXHYCJIZcUmN3vtoGl5/HYAeixuLB++HCJtKcZKyoz+oNlT4L1GbcwlW7W4JmXz6+mPuG5aFwyAGDUUPNnIVXRmR8gS8huKI8ML2Tj5764erIPN2JLe8taLOoKOX3lkLArXktiJ/XLoY/yFwcee/+eKgOSSs4GCG8YeAAYp81C6z/KQyELNiT3OhrzX02OoNkQ7rBM25gY2Xkqtp6vRL0frCRMDY6mqR1J2JVOxDN7rkUssx0+zOLpnGf6S+PiQtULqWL+TiuFE/xxB3xzrdwxEVqlamLkVFIh25S0Fkrc/Ih1EECma4KHStnyDip3dVZpBt0nlSZ+cqQzqA6PUMvb+L9XO2IaW/QDRljA4b9UqDZOFC47Qyt84NwqVbr7DWr6PrOIdXHXPeXpFtMCwIxrxxy2+aWC7XC5InItA+kriN1+hAG4kwlv0IzdEqETabYWGJXuLqICqchfinAvTCjxPPb1sQTqZLiTaQ82KKkvTv5I1zEtSROwdivm6RzVTdsgUqAXYJMq4wk/1f/w9JkaJ7ylYubOSYtwTn+UO78mHofFLjq12fu5kNtgFcPahKCMDDJ1hO3haJDMmZclvNQ3ZXXr7ON4IBl6Q1A4kvF9Fzy+awJL+5YFQv3RC56n1yMaKlfn9GjCBWCq+xkzvpobhC5IlvoS1VJw3C1SiGJx4ob8q+p42AVssIqFovwQvcjt9/cFIOynO/10jfWtsrgNqUwkMtEIBI4eLu3M6xwHlgtHfvJzgsZwquhhln6nMycv9TpRWTPzCr6g2a3DmVGwQyeTRSDsNhVV04NDyR3Gp+71Eo0qeYzSD9d4+YZji26I/XDmeJ5Kg+8wcRgS7QuBANqAtFMsS878qVno17atjfVvgsQbNKVxhUSUk08qDQgyzSBMTHyed+GqRWglwFjcl9iiRCDLp5CFFAWIy5Dqy9SqoUE4FJRYCTjz7vOzgSqUwB+8oh5v63X0hDLKUbVD4QfqkhklUbv9RRtpDmeMkYzmoLSa5GL1BleMNRCiV2LSJSEyguKzDdF3HbcsHf598wIf06FcxuODZ1pO4zmHddCp6NUi+R8na3x7Yo2OKxw7KuWnkvp/SbhU32i+TMiNcp2MOizoMb6FHKLx9++CRR/55t0cMd/ViM4AQ7Egt9u2wvPhKN+vE3KB9DM4h/RUcBH+jIFhAKde0KhNopyCx1vp/d0+TL7LW+v9wvx4Pym6aPO2nvb5cWwL6l8VoNjh9yyFz22PnYZKyhyaKONtqzei4acBdHWcGw9WKLErhfeCD2H+n2YBiIAQAAMLZt27Zt27Zt27Zt42Pbtm1bHaKD3MAa+Whtc42J8J4MiEOF04KrsYUFiPJouUvKlAcdsMrxmM8KwrcDCcqloAdEZnnlAELWjLmh6MUPZ/8UZquFg2XI5iV4iuTDP8jo1R37UoFzOlNSnIEaWZokCVNSinUcP35Xh5uLl9qgxm8S81Nqv8YlDPsjs4erB1M/92uEXesbZyIGKWEcMbhsl0mhbYW/qZJVkiIs8ngVkMuZSRxOSwAzxMs12dMNY7Yk9NLOLHwzDm1cv7V4fTToCuXyQs7rin28EByG9EM+2m515E/aCtoTXQ/4sJTMKl68AIRQ8faf2nuKwMtETd75OCBkY44GUdVNJ0ZmNQLrFqaxU5H6LswS6vRNVcFtngYWhNSg9hxpqDtXX/ygrpxJ1x3dqfby9TpvEOKHmgs0scoLIjDfALhlstvla6vZy/fTEsCp1pEH7qC/blmX5Cq1sox5GwnFpTEoEX4fhDan0aCg8Gy1HW5fy7IaYq6OFLljLA3UHxnQkPnaroaa5edXhsRs7xAWQ6NbUnr8kItoSj370Pnfp2vbRkjOBJOngqOmUDXRlkrwWlZR8qozReN1ckV8YJMQ5OIY6MNcSTsNmhczvnDFCwt3ZtSgQfYiucYPI/wKv0wlwd+dIPzJcb4PryDp7OI+HICIbwKq7TJYQVVMDBZ1x4G9clV566SaZfsdvMysaHW3TKMG6DXJ9rQuSNLX0yl9Y+ol+lYKk1qmMvnDUygPmLW+pAzXxVNcn/bJjohtYhrbagIKqW6lUWZUgg2zZbnu19v8ff731VBGTm8HcIUjMiY0KowhHmxwVCXF4F5zFOAx/gyMT4ggw6xIVc4l11OBvWFzd78LX3E79/wWTPXc8iBx2whBqVSy3aPpGIsKg7mzWYjQBFVHrAxR3uOn4AbOAPosEyE/glg+WRdYAogNJayWA62Hm/lD4xuL7RCPpAKp5lmiy15o3R8AZEMcE3+WqpWmmMwCHIptO2uqisKjsIvF8qPV2HJT4gUz26Tzc1PQ/ZYTAXkDmAf7Fp8yilb1ctRDQ3r473LPqQsu2M2hUi0u83HgWXZ2g55wCQOs0xLgdoCtPJbI3oJGUJRMAung3X5X7Yf0/RPC7tu2oF296cCukX/VR7R/aMFFVAehUxjgRoeCfDRptLpgTqkFjK+Wja1gdjGHNfvhqDdy9QKyrMiiPFu7sMfKS0wMpcKLNxl0w/JJcCJsQ+6gZ5cg6GOmk4mFBNTgonnsyCsHXTOfQV2DNhPk+UWLmqT4RU5rJytIY+ovLGlhbuajFFwbJY3hroa3kZkMkkC93UqfbXo5+j26PbJ2QZiSVwC42u0Kj1VG7VFfcVEMoCy3TRDS+Fob/0JXEtaae7Rss/dwR8vIMhyTVWMlaTkT7fH3XMzmIM8rUZWRQMWIh8IP0Va+7FSMOSV3yPsck7ZBVee39DTGBh17UBPTM1X3rWOZYK8XJuFsJD196xCR2oSa7XnatOpVTX/ENLpj7mePHsBab/fDfBX7qaZC5XTa7PTvmlgWBpcUAT/5sykRVrQZc44DiWtS93pHEYwmEgNk54KEcrrtN9CQc1m2Hd3Bh0g5FQ0UuBxcP7I5UuWOQbz4+mXimMkAFc4BjTf3vbL8GRDfKbs6al7G4Mb9PSj0GWKldEcSxH2DntoXWNUbThjMsr/zE6fx2bYD3stBWRl+EQqFgN/vOiIrpMXgUsXPCjU/0Phfhfq7ZwtdIZiWs0MPvUNPFSXRi+RstEbjRE/bzT4JssIeLhWPuUYPZs3lqPQFN1eTTlVOnVwnEMnfbxcSsNk+OrRjQFlm/whdC5Z4bAxMYjzFpirvgmY6Fq/TsM4gT2l5jnw3A3yaYCtGOQKn3N15h1J+cLZ7tMXHa5t8xbR4KoXLZK9PhBShCU9/8Gl7l6w94aUxS4afX8HL5mYQ90AsWoL2IR3x39RYbVFw9Sd357kysOk/rvge08zwc+ogpyr4S1u8D62h2v7e7Yc4lv4Cojued1pbosx5hQKr4rhu6MpeCvY15wQZJ4XWoygDTtEbvYTQ7TuI39ZOow84noGuxoKtEH3u+jzqzp37ciTjBu+TSnnRROhNFCyC2LBcdDo+DqrwnCTeH8wL11g9f0H0ZAcsMnsVHvw2NJElNkaDvG9dCB6NzAEIo5IxxNimBdNWpKXBGey3EMn6sh6/CQ1bhq6eIAKBddkcNg0axoxPqAagoAuEadEh0anSBbLSC85pfniUxtypVENJG09cCxWpYEptVPK3iOJJK+5HyBVFD0fXBTeMDODv2ZROkCuGcwALeR/HpS5mlE30O6gKlPKw72bMBDV9tmDryDXSQKj5Z8y3ebI0gQfP9NgG7eF3jE/UBEpogeRekIVHcgiMjToYVoFKx2aTDVXQNuO90rozJPgCoueup4QdpIIjpTGBtV4kDkqjstCdyhghXwnqD5SznsRMSB8n+HA1CQLg0u7J/lrzcPqlxD+UAYDDkR+aTo8gSL22+DHUvKvYRz5McjxEJwa5w1Hp09a3pk87l7d94BNPIrPtBi3LuEgpWP9pg+P7BCVdRl9s4l+r7Zfuo7sUx7+QqxAsGHpsDzQwQSH+M0fvmr/HzITqx6JMO5KHRMp+heJyXEeS+wkbc8/5XPe08oOw10vfJIdumE0g6X8mvPPsZpaxF+KPgiFmztr7SDilfLH7hTe7Y305Hq07iBApSG0RK/XgCgRt+BGONfZ5L3GEWkr3L2sL3BNDg17TFOikB+KnM5zEN6SqglNjdwUxnleBM5Y0StRSmHZ6TbHtxVqEU3bp34C+8+7Dnba0BK4MnC7ko+gX0tDXEBSvuiEEcDnWCuMtxOvtBp9WeHwYmtSq1sKmXr5gg0dM6GejYejgyF8MHNqazQpZvWZDFms64A+2m7I7xSuvZgmKqg/7zZVN19KsiaFfJw9HwD4RTfusoeqzpml9cVqIEKurvoxt9fE/mN6WPhpYNf81h99spMgp+2qV5Z8p/9yFQ7ulYZa9j0vk29opJ4JNcGzRtzXxeEqO6srymMV2BvvocN6Nqathnvmyw8NNpk22+X0+5c5plpyj/odN+dVtMAc86fU3Ld7t0F0+b0n6Nm5ZXX0KYQI6e7Mx4AEyGyUppiAOitJISCY19YhJdBAv9gu3c38gHmrIouRuaHNlpbhd/K1SvMKKgvIVBWUGtm9V9APK8nQbNnhkbf6QVwQQPQm4LYacjmb4JFkLPxxddDKqV9DBjHcBtLxrYfoR6p2fgMVONpdfDyyY1S0fNslFaMn7UNvPIVstNYBCNNTrQ0u2oJt1lixwwioeBWbVkapgeL0r87R6NNK90DEp3NdyY1vUMnqPLwzFnK7Y6dw+ltZESgtqZr+gfDBiCxqhEJvgQfb1KUJcWh7pqvj2YJ1DgNVJR9rWJ5wJi2OBuiK4HRT2Qiw3rEDY8A640yjNsoOxqHNdeJiHfnlIwGpahLhVoTHPXlyGUW9uOkyo9ZTj7hQag+M4ketw8MvrTbz6cE9rakKG0DbY1flEN/sCG8mm0J5MABWricVMhq4kQZEbjmiRLa8aHnhimLFbwYS+1Q9yXivtOwKkivu9cvu5nVaRSzTP5DTSp9RfoFazVlpVQQYLsPIKhGv8WVgLxUDFEfvrSkL5dl9FEXeSB+rkssDTvqhgKyAguIdCcvu0RPxECG9dAuLk+erNuTSGAVnSvacKTus2S1MMRwTeZUt/JaVRY0t2HcBnfC6hqCL4oYgWT2hZyqtRufIgo4YxYLtKx874TXK+TeXsKqkJKFbXAYfmPtxwHj3QodZRauNRMeizgCNd8UYX/P6Fd1FG0B68vdVYgfx+AMN0wR9s1E2OBypUToYQ0AAV4TfBKYAI34BsezZta2GdZA+hob+asjU6GoRFD45CCtPIQnmkOXJ/9pkrMleJmGawUVY2ncT3Z8KJpO5n9pYSbuvrM1WKnEdDnHNg/sBrh/3a1eP+b6vix0GKHwh7GKP/XUlGcvp7Qfa7zx8EYKIwduys7xfGZDMko0pvxlMIyPbEASIOiKrmsR3Fd+1B415O43gVead10KUUOmyR+y9ISCFa8Y0ChK1V4IboraLbaqCrr31TPd1oaJaEDUTPuPZWKFQb14ndld74u7gohEytHo3IVpIwWinGWPdLzE2fKvbbcG8y1h6dOGaedD1WJUvytf5qoggbwN30LHQJgrU4iAUCI1byw7yYv4bGUdzrlv8MJuBqMH2RMxNMTvzCL+8DCJzawTZav9y2DcubHo4mqb49zwPtSBxbNNouaWj2gH3TCsq6lhJLUTGkqZCF2OeowjZAt2r0B6b/ZmjBDuR+Uc+E/SWxIAXZ9cXj+xJesaWCGRvrz5rgiH2jdFotTbDpNrTpnb54YmHHk0trqmKyDrkEwEQcdxmZN5IHZ+ccaPAwYipA/To3Xa7fpIBz3J081OSUpzP775PNGKUyHm4eMJqvXLIVCm3t2vcQ8MbKZaNJjYjyLWnRAWSdBNwjd8PjYaglZA0DtlubefKCGqfiXyS5PBCeEsKaPP1haW3PI9btQ5ssZfPnLGai09Flp+Imgtv53kRLEFpnWu/X5/Tk47QJCE9Yg4x6xfwnoLAC6pxUkrQJIFF9V2aSHQXYOGTJWUzvEb0P9OqZLohRKUyAtSBKNg2tX+/SgNGQec3w+y8vieduaHr0fhfMTPVR8f7UBKx20pYPgwq1oE52JtAcRfO1B+idJDyJwwVdBnMCc8XreOe0JRXhyhclmbI3a+w3wWD7sL7SkiohZmqo4XdJKzGxbKcWSoI/hQYAKtDiNKkZQa/u6aUtET0QoYYI5I/nExB6UNSg7qva1k42BEUxXgaCV5SB2FPDUAuns6NvDbYk0snsDS3O2VCPtw1jvIuMGvZTs8uzlVkpFd6GLpX7oXOn4LJOy48yRV73wI7N4pjKCauISNPa3k0b/zYX0QHQIxlM5WURdawWiW1pMTrrvauECyOguFeJxPFDkY2+IsSbdAMRaaVVxn1Iye/WibhRMYS1O3lBNhzGHtqGrEzAgKhMkctjj0D8qlgTr0n92AcU5Ux/oUC5CCjYErGwYp5LEqvlqUjsBKCWEiQy/C2ZYAQBwUaT/HR7avJwU5yY589kHzy61msZuiP0zQYXvPV+616MuFCz+O+cRU8FygafJm9vKk77BYzC6WELI87wVOZU73CXvJboQyQ3e7vuqbAyxPwi0cBn/dQn0L7mwCeCnq3jBsCXde1tu+2CC7EcBhfw1HZo8yb59Eti4S+W2mqgeAXl2p1LUU6QDRoswHFGtuWEOpnPW4Sbs0yGzKNmCyKZRmeZNZcIEVJxD0a7XKHp/NHMX4kL+hOEvUmRAOXRT/ZYiYldcPYHMRWsAkveZE0JCTLoyvIkDeOC+fjO5iRfBXIJaQHFr+fpnv+AbphxokZ/hmNLnR1QENJzwEb5JzEu4AMP3qbnSWhW6I7WHq9PGeAy+PjJt0w6XMyBG/oz/ryhSf5QFnYTqEdVU8fzpNdRHGv4hCaKQbro0HS1jmTrmceIiy9WwTiHSe8IjFT5NGQhGUl4Hxx6T0KuGccrhiyrlBGr+5QatQxS/L9kvceGDz+LRK5cXQdXB/aMA7bbUdFTNE2Hn/NerWClr0I5jkA02rw3KtTRaEcDQPzLbIaVeWVtwvSts6fjOY7aNGEq+AFZiGamZJ5b6m9L2e5AxCtXmCRRjzSk6CRq6nCSiUqlh6KDRaqxTa2H/CUot/ewwRd9ixmo4c/c8EWI6C+35rLBKUg1/huV4qF+RNYSKl3sHQTYBVHIFRgN9xRHpLLF4H2KPWdl5nhyzczQeH8NEr7uiSdCu3JnGW+zaoUxfAetwT9egUpCgpaAqGP1bfbUGXOxWaAI4ZPZJiT8Ku1zsOm8IqlcaMMbaV64JYEz4gblEikcs4HH459ZpgzrXyuYJJNGwpcoeYsh557+XJ7+RItYazxNcRWEf5++VhxPBaQ+Na6CBvOPNRuUQEvMwjkn0gqE+lY+4q5AKhqq3nKopDAo99dw7cuoVYKNhtByQTcSAqz6OhxwU9EZ9XxJeEocg9VIK7zLwboBSfhjfBxCLv6LOgDrwCDJuXZhxeJJ955EBNOKVgicgQgBi7brpgdYaM2g2EfWnZWm9wuoX15oab5jWYaseskmKgFPcqdQliWRshd6B1XQyR+jQLLi0Y7QRgXAbZL9U4Ea0orNbp03nIbkIgvSzZ1BY1vaekbyAoEiEnaByFB5dSBHRmEX3uD8Q2sAzJReNzx1SO+XbyWw3i7kRf6zWzCY0iUBzX7NPHPIu1zeUMuu2Y/Hh8AgZTKidk8tVE8N3VGnYBooHzc/BvCdA+Ybg18mkVcD61x/J9/i9hnUxDsZNMrOfCYZHkHzmatbnKW7i+7HMHUBxculXEKX+/uG9PhS0IOS9NpNbRw/qmma+RMrlpvfR/qbnL2dNIkfVTTqsXSGmWYsu0XZ5MnzvqvVJ+b6ap80ChpId80oDXrLDqe1M8V1VKcMiEJigST89nf1LUROzeSx3XCdPNrGxjAl8pdC2eyzB7JyDIef0DBtfjwRXdRHDjLff5Qm5JDfUO1l8MhHYaWb3Zpox1B6fYwK+tBDv/vXiETD40rm6VKSLmKz086j28a6n0VzsTpzUmEFzW9j1M5k++/+G7gEaw8Rov/4OPOonuvQYrcR+HKHi2QR3wmCVnOMwughP1hs/oSIJ25oCyFoxW7rnwTfwuycNlQNO8xj72jzfRbCwQK8yG3/1utvEZgNwQHKsd0a7grEGmPsA8/K3ysqjX1WzPI9pdRF2UJOjXDWq5UOKEEzqgigG56K0wnMh05KlDqasreAgt9Z/kiKm35VApcbiKoqwgVRIPHFGm/oQNPs8TFX+hzYD0ggO14p8wTXN4rkdHgZMXzA/zRbG6g9abyJkdnl0W7pkP+yHe88fSq7NwcKdit1Jrl6a7IrxyypzpuG2JAfvRR/mPIh6itS+tOY5tsk7RSNgtbj+LZnnchc2Qr58siTBWPGwDFuVjBw5/HV+oedkS5oJ++nXHz72GGLhICZQrtMineWFHxfcOD2eaPsbCfbFNmY8tfMrpa+GZDCD3mMaLzpUUOSkrzNvMAbYvQPzZwnAdEMqKmAvM6FBFbeXypsNCZekgBjRnMI8Yw0oNE6SEMIQVO2kgPAiQ8G3DfIdj/46l2apEbpgNG+10LsNKJxCIpux5op1V5nEVsqTQB0Y5StikjacsfbV2fWqAQpZfsiJtlN7UQBAOZn4uM8gbwRflNZSSJB1yuoPZ7pPT3fOjA7tBsgNkHkIebFsA/FhqFd3tq9Ki8ePV/t3E6c7ehQbIt70umPKMKfZC5WVvzodJ18Z17G39LcCXqMYZ59wpvicceC3Jkq3SduohjDISX7DnQCMwbupoYFCw6S0ECAlPDwo4TNCqLSychNunzCLd7KZCHV/RZDwztL0EXYtIbupqbPWrzVxLqiPpI6Ndu2kRFFT816BiXRS6fVdUSgSHqt9952cNP9D+MhYGSDg8K9ZKiNpfxnjpLg3rx0o5+ZymlS3cN7EYQU4dpLGMV2VXPDn3QoDsrRaLzb5MyeNriI+K++R8PH4Fe+0FGz9cg2qaWEHnazhz8zBPJXhZq+aD0nTahG5SXycNcRFeOaiKxUDc+VFpm/r1Ar0Ww61Zz27XSWCaS217zhvj6e767RlO2bSLx+x53qVfM4QgQF6bfCCst1IEvM5Bfd0//gzAK/dB6NuLiLye0b05iluL/hAFDwfvPhQwI/BDdwAcF2yiF9oEUmi721IdVMIjGk2WvAKsgYp5LyUeUm3u5PWIbzQbMW/5RxtRend1M/wLnyEUu65WX3vIk+Yl+oHGoget1emDEBmCEVf8EyNkU0/ZJpaAAEpMg5Pn9LHgSTNS+958R3NALIFd94sk11oolI9LEbLF78LBa27GMdusB6XRXLZ2Gf0Q105++5jCD4el54SZ3m28V47/GkPHf/cbztM1QcmwjKZ5mHdkN5w/S7MpwIrYjROr1+tQNKh0w7mTdVVmEn/DhzJGBgEG8M1RuR5Ps5Zu/MczVqr/dsuNe8agFsqIPP2liv6EVLwz0F4k2aNkGGqDDDejP4KcaVk7wrvhuaIqvAN3LtvojXrEFgPjlADKJ8h7Bj4lFPRbR8yVLbYOLGrEztmIrVhpPpkSMIMtnvEm9/M2YGaIGiUPXpG95OElZE9ezHGLxEcO8obL2pOuZVbrSTmSk8va3vGBVpHTVIbWx//ES+wItfPxHqxcYvGWDpuleNr8NPbJBVNFWLlEZy0GB/B5QItrBlvezGsaXN7YdXwYhXkYrn5ZX6nQaXefkkDP5NI1OTJGRWgwKro3GAOYBtAv0uDfMYmsHbl3xSzGgm2QKS/GKhNJRi+c/T5o+v1DiB036S8iXniR4AmSy3W+D2tgBSpoA3UJNWupjs0JVk+9E1mh9vn85UrS/eH0LjAFsYCHtI2X3dt00uANONm9IrDGhg8L4EtCF4nvezTUiMob1iTumjXlRmwfcRjpQItUTIMfUhNHfUht6AlNPoJzj+qVBo1JflYlNb0VjQj38bAlwPz6aw3Z0q072218X4Y4Nnt9YcDN1igbPqz619p+uV5ViDh+dpLhiyD2m7LDjNQW+HcdrqV4GR1SpoCS66HM6FaQSeyqnkYrmo5cxtwIeXUwCy9uhrD4gVnHyLorA7kNsgbj1j/9aLGJE1RvQsS+IAlK/p5yE8XcZ26UxJ7x4psUoBqt7K4l8JPXV50FD4DeOwmEdpwW7uIAOVq33EYcQbK92tCF/IEkvZgsuTbtBOFOyo0898ucusi8WewtoKCajmHosmyUYqtD82O6spD1aNqYLm+VV0uDbn5X2rrbMspuQJZbumnRn2ot3vfLY2oRJ2uKy626D/0TjBnU9Ie6dYbvw5XB4zIUW3zNQn5DLQueJUjUmzlR9nysWDGyMsALw1ULvgq7hMMh/R4S1BfSHJabrlhlCzryk+wrBpgYO2+aT9Lj+WBEEa4qZF/eKYLa6EvwuEGPwxCUBig2wwga3fDtQH9q/B7vgg983aTe3lI7t/j+T5NCak1lO7ktb+1q+B8npG4yKaKxQKIjB4COXwgzpFKnlJWEKVBM8kMVm8EGpjZe/sQu9fmN0ZMBuK+Vhpxf27XvBqOkz41QteJR832BwyP2qyhXDk3sznqjKOpQoh4b3hq3H9sZE7htyLWzYiCvSTnJlXU5+c7eFZR8//MvR+DlP9qzIgM5aHIS9AMjGMvobz7HAotgAtPeODmXdqHL6VvetM+bhrDWIgPBtl4QPf9aUZfkgnlpux3loEcsE+sc6V0YKd+FZhQlxrcw6TK4N/2wJziilYpztGa1TmETQteI0mkRB/D9ooJAStf3XK4IFZD+bIblBnydHDVbJavCZX1wvvc5uza1s0sClEds5D5ogkWXmBtAV3+9t6TekYgcnK2q/WSP8bmWQmCJqioo76/o3MzsNtXKt8vJ3O7SL9+Xa8/uM0pNLQntSkDz2MEewmjNeQVXbHPQ3jyuh4oRqK88G5LO3smVfOYVZetB8ZgA4+YzQ9wc5VTnvxZB16xKm6E9zJhAp7V+FvOo3ZsGiQ+Nq19fZZ3u8kAMPTsZFEBuXJ/9s/HcQY1qgrRj/OsmAnX8I2NxSVKs2R0Y6azEljW/i0UsGSIVFSTQ9LEnCMBbd94i494Ja65tYH01GIEfvRRcaN8wvB7LYR63ffVQL2a4E6bcX6OEAwYXQYmyWG9lHLOV9VTjW2kkGBNBooKk3vm9AXzRzTYcVFE4Cp78gniajGTjrRKt/Qi4JfI/tjsXwN0h4YKwjawECKAG9jD/W29y5sqDN3Z0l1T5+3FO+nQRgy478X2RLb3EC+tOihAFEgaRVKalnakM73d+ZMAmbyzA5hMszuMzsee1t9kvZkiDA7fwk1LZEKek65YtTm5UDGF6+tZL8kdowDzxFjwJ/kE1diDWnlHhR2LfWhJXnO1+TuXsmhrc3tM7uX09dOv1WXJWJvEJvTFTTjVydhVLUw6X2NhdRKP5/RgjeGxjbyhIrMjrz8k2NuVN25NkWgVfrcqrgtMDuw4EnXEpyoxY/vlg7ZzjC/Ef6himrPggQFnMFc+Fz+lPMJyf285v2lcCrvNJPKDgIdzLl639mhOHpa+o4/SEcplvj5VXF+gwuN9sDoXHJkvHtyJrshYuFReHKQzXCwNcoQFn4oERXJmdUajlv2d+M7r5rvLzJ4FzAH8bvZy8HrX3NK/lm2LCEVidRcMrhMXAbxigyChBLPwkoOg3ka3lojZ8YBPuZmEMTT5kf8JjwBA9PAueSZswvP7GOchgjzk4iwhF+hk6bz+3FAOzyohUHsUA+hi2p8c58gWyNdOLm4ZAdR4x64C6008u7uQChjUy7IWxKOHzRlZ2oEoHwji+BQmEQ9Y9QaoCdBglafE9xXqC03gUv9ZnLd6nvH0MDZDWTvbSS8cvoHLL/0atGuTlM+glSWnKyRN7nMC4VdhGuYRvgdcwzGdiujO91VHZydSdRZh/Y3F9bXYbUW9mkBoyU9aZv+ER47TfDyXf1hwh7upv5BfVDby3eu9PqgGahICcZz2dYXNEmjgAXXxmV2xEqLnz9MxYarMAFtlpNeCP+zXpv/75pnEF2BWBWq5med9az0hkYCSb263dtkTDxptuNq/j63J+X+5PeR5eRRLEsXLMcqGtA9kWAEELF3urqis+AKTTw/ZzfBq8Rp7upCjd8shUDTs8CiHp3eF41FQpGRaALNEadJaeWXxrW8W/kAnrvSIQI8+oPXHV28ZViwbPVDoCuqByAvXGL7h/hemfnyW+YIsRgNRaDMMO+zS1YnfsH+3Z3pGab2ax0flOn59e0rF7L6zE2Hp15xiYdcvY+rLKBQ3Y+AxDhx01ootS+jSqKHORgtuIbj9a0BXDsisKyGzBnFxl9N2qUxzTJbFUb+VJHdJfGEd+HrH4QW/ge0CH8ItdjKZFlmrlc19BnXKcVT1PrjbWxqlGs9p0+NZthysCCILz6+BoHtb3EKQsLGe//Jju+oqxnVnm72/DOL/SpJMTv5Hs+oO8iQg1aFZjB5wyOCbT6VMOOo6HSAPKB6bEtP8U2dKyNOkpAbkoj9mMD7pMisMdgfxCSbayDZNZ7F7OMYaoojPP1pVUQYn3SCPapJVkeC/Zzr1Rb10xktGOAqaI5s6jOlFYUNc6XkAg8mkVYNcDtGYf0Velkx5V0mWdxVnEt9skIKo63cjY6Ce/4wneWKuuCpfFjz8gxXBgA9SafMoILG7l659AbwBBk4ph786Q2Z9boILLbXc/tmBfHGSBm8VWStD1ybk3ABhaVlJpTSNWtDMdpfpiXILNOp8qqDsTVdhLTlv8BHvNNWg0fqr8RoLbcEY5eJ8+qXUc49apnF2g/q7K7jvUk7d6dHad6qfmRR2nBiajQnXN92PtRCLjPQ3PN91r09CSwx6oJKSXM6HcU9VFbG9Mk0ZJwHjklFC4KNytt+ejuwSgLR7JrdGDNncmCSk1Y/zKqb1b/NJ3Qc4zB9Yacya9tddPG8u/i7Mf+vAbZLXUt6AThHgIABDl3ERMdqqGunIjAMdAyGs2ddF10+sDthbYOUBl1vOwyKHPv1x50jycC8DsbZxxpdcrOZOw2qr+Y57S2N/ppDIdU7lNvdJ3H9p2hGjUIuG2TRChk+48A8VYAJOG4TPGuSg9P2iT5ytBxskEj1LJcS3PrpcX6mRivzMt3MvnC/2jdGryHGYIxrkhqpKUl7nNS4N4G0xl1nB3Tw+UGieLtQSwt6sbwnQWCABqHhpjIXcDnwxP6ukoznYT4cGRchCrXwbOg+MGi2k4UVOIXEeM5eYnnI1j7AvpL0jjopafsAm0c0RVGLn2ILbXafxS+GeetohrmZbGmjuuCU9T9USpZA+dtbj/NhTyCoE4xHFguIhB/6+9FYK8hXh2mu94n38Ezdyj+1Iaa174lkKmLsYntpS3gEeLdVJR1zzyGNl1jFg39a2UPH7Fcn7oUlCaCcklBPOSFSpsOGV3aKORwVaQJCF99WWPJqngPQ3oWidYvFwmzB3xGEpNlJLAek9X6czywbPXJbpJi1nRGvd8AH5KIFEZKBTd2rgsvKiJDDcPJ/fjMVEigDL8SIhLF6c2OkavHY+lBgYDdugh3Hg4nglMMOPenOTiFuWttVFpVRb3o25Pqf8jO6No7LFD3cP55yptL303y1v72ANPsffnCRrR3dMdtrExHaz32nZpqw9peTzG1+z+pR8/UAYbZW2uVRRoYuEZwyw2Pgxz5EN4/k8ZKEniuCYhCAOksjwOzIxhRN8+o1yebJBrCM9bnvrWqa/cy7W3SEWz9u0J9HyRTVSEvBlO/lM4qfJkUbii9jyNr0P4gSZp7dHE8y8yZSdXsdpSERwcC+rJR5DheYvMxEltUDJh9X6fyGZNvzcS3mpHxLp/KCAg5o0ujun2exOdjuhyz0YFhvBbN8hKdGd/dxF0I/qfAIZSmhcpq0zusMZlYaOEOT9lFWZg6sQeo9kCBTm42axWGwsPJE6/9aIrdkghmneCS0cjtyVsECZ+6Wg8nr1RJ1YLilxFxswGtHzXSAp625v6iEZd/TBO9N3T07XBi/HdLq3EZ+RjxFxit0U9rsyUz4/MzGYfolVRwasGuZ21MvmUSibOGpH9o542Bfi20qqZ9qD4jRuBalK0Etr+zi5ij/GO9UuQUpSo/5ctEAvFPMxkhLhLBfwZTs9lT1qg+pXqEjSuJXQMIahDL2aB3mrA5RGlGv+6WBeBsJm6HmlPno08+Nd/G/3gHGJbI/FgYhcFysDNvuqV9EXw9mKRGSvnnIt1+34y5zt25RETxApy6rf6ldkPzJLDgGNpeQussnhGP8ak3ZxbmL9jstdpAnids+E1Dt6pLDzFTB7gr8edMcdE+YW1OI8pl85zk14ZMTO0J9CNLsnZ6jMwRj6RNrHQIa6VBJVPTP0EacR/vlxOHoq4a8XWx/BytwwyBNDBSkibLF8vdJad1jMeNiDBw5C5HgrvHqrS5b3CAWr8prdc/PkrKRO5+BIhfvMs9RWTgGWY/w3e36HkCh0cizQgIqWJShnTrwU8z0jFO2+u2yLKmLhwbtpQvgWsN9spAOChxQ8gnqIPVzULGOdwkdW3rjdCwX9L4XNZeH/sLAltMdzgL2ZTZjOFIxUHbdAxGeFo+NEyXL4c40Kbe7fHEck9DboiipM3bk31Xa2/fvsUPKTGhXW+fX4f7FmCbwsyfPOboGN7oy0or8U1aliNkkYbmI2ZnscxN+EUilDHqRFVZpY3FG79C75gxOKIeUub38TpIlL6wIglbqebMVKf0Z+PevTHe9z3g5j8+2pxEgreuW6uVG8FjEcCI8FU7Qe4+oXyrfl1PvCf4nMneIyhyKRfneFuN0XOVrag8TncUbMLCX7yvqs83AcO8eMOivA2ZF3rM8ALptciNcgp9PCRNMgekeV/cSZXCIBdgTDY3pO+3WTymK6eaAl3H9/BbZkVM8Jdj319oEF6aUIMLIb25c2jXAbxoksOrIBe932CbGBlP6s8DAZ07bZ/ObHL71pQWthzlfMDVjgsja20Hkc7wgu4yq0jPponTpote864ZIp9uGaq2UXr8+DC+KVDQ9XFlvyvl9i/kngSZXizV5Pjp+BFRpPn/LxTQkX/vf+D9Fypv7PFqhM5oohL4Ts49F9hpOYSKb2wvLGlIVmllnzn5BAlTP6qsVH+A02pkslksABCWrSacjN8B5N7VvHeLaP3J9S903p8WPSt33XszUmaPF3/Fsu7dtn0y8TURhv0wtDlD6bTw3DRTiGanlF022qnTGsoG3r6oU/5jh+FwHF9f2m6XBt8jDK+aeMRYNCCw5w01wJ3T/ch3UfVgEuc9NbwaZINcdaMIrB6qm/acYcEuYyJMAP9C7cCMXIwfum0GQkwipwvVqDL3Mtz8d4bRNk7sE9lrqxLIW2wDRVxwSsWckkgVnj39HLggXxKJxxUhMoRlBcBnLNb+SdO1gZg91PGK6uG4cqUkRGut0RNLmGjGLShtgcAL1oYHTQjepSGasbsla3ekPBzfsONrOxpD+NvE/NHW9+VivHHoVU6PpIwI7HJ5sK2stlAnpXyXstnL7N0MsweW/ndKeAq+x4XLY97t3vmJYOx0LY06TcTnISTd+ejNOgCxWOYKBAaYB4u+nbLh8O/EY3tAIrfn61MTF7HXA5q1hYb36AstI464FaSGZCRvsZcbeUh6fI/o2cPltFVWcakwrwiRjMTQoKR7LKv2VuNU99RmnWyze8WPJutSSPPhP75CGDZ7GST/OAZ5H2kd8OV3g5GUbXAO5MOXc983XHaFGDk/R9xlkWqaWCUfNRktzcRwGSjOPtybxV1nqWI2NqgXNcWFABqyXTL8gU6Q1lcbPJ8MvPMAMwpEAzEfmQbV0BSvoi6GQ0WnvgjqjbESdMLnZqP1SlgwRwQvfvN8OUJGvwfS/vUi9YgF602L2QYbP5esANWoPOLGnlt6pSl6bYypqXD1BAICS5V97kaIk2gRarb9DRitYRhhSNzx3vwab9Hc1D/56yRLr6vqQkeXxuZ2m4eZDaevudZSB/My/y5aUvY8/htB9dxntmAl/OAgeKdnItUVJLQILGrvP5W59PjO7QAYQZJrmLUgbBRJ5JzFzv9Jxgsod0K81DO+xNbOUDv5CecOU/4CBN6Ovb7282uwGPlHx5/7GEsg4ZaNITQ4tg9NZCq6uPoc/t6V7eXjMJtdj5XNwBG6pr7KUtTrF4EE1sO/9p+eLry7Q/CWJJ9wYVt0IZ+xabi1GTqiUlbMi7n/QbdKffmZ3VRKuZ21VZF0qIvEAVnMwHuLyWtiZPwh2qGou5WVrAimA74ao/IIsuWz43H75Fk2FUIz43B9ttWZeE4EHDoMHiIBV7X4yR5bE7yx7CucFRKbuF+oEG62OWStD49KcJ3EKv48eXM2JcHri6RoXtkZtIzW4U/dHFUqkMqmDLW4xA/ut7smZ2kS+xHuklzAA3fN7VaJNBRA9maeqVJUHev9kT1t3+aqE657GAsZ/fmZhZri4g2QJP3M5XBnGE0JNTvLlHW2kNKjsPMGfzYHYpQSJPRGAYfjJVbBqaTDEh5bLLprO5Oq6LCb9A7N6OYcjgFGbVRNUbQ7lfCOmVB0w0kGnUMdiSdjSvXOv+AwM7DLpRhbjcPPixEAMXfC6SWGyRROK0OoP+qusHAIyAujvpDRBYbjR/17gnzssmlIeumk43tVRj1JP0B1a4kov+g1ekKwUjvxNKxo9lb2+ru/7W6V98UAEgi+uGFquuGV4ZLyaKSnG9qdmY7qQyfV74YGzXeV1K2Hx0pRmZexMYg5c6HohKRO1VobY7RMvluTNK+xnP0fFcC2yFHSVGS+vEDRf1KUwaYVfSKp+HwNvT4n4AO6V3PLE5h3SisiSIVf4OvTt6x1g4hqK1y3mwzyUY5ZWy6r63kCWMBebhqvFCkktjdGRd2k9ZWFy4qDWWQ8eiYEhDp0ocUuHLe9xY/geSEbS4XwasvM/73KWGk2jN4WniiE70x4CM77pRlk+s+6D8GXo9+iFgu546Eiuvi2rWUDVBWmXIN0O3tsVA3Ar8+P+9sizVGTMJ7lQFQ7/zmc6cloFivcwc9uff8A9g8cxTmOgMRWfqV8F2ejt0g6wYXKFUv3/CMQjeE6uwAAOyC9gHibaBgr7jsan/VGzyFF4hEqTla4imTVNZriQUTKCEzt7PUT1juVuLlHjAezZaB1LXX0pcewrVtXuBWee4xhZ+gNvQfmLBumjuuZZM+FrQwieVMAhXnuxVWIlD0Zv+lNGpc8KFDpgSpDV16/Hc+wz5xjH3QhU6B29xNVvB4LT2SpECcxO3GkC4LDC9qnvyDu6vmzSFsHB0rem0k5+oW3yhQZy5LaqgfXWCkcz5tF5oxSKa924CLa21LeipjZx7byMR+hot/kTB7YTfy+RLwB+anUfDnP3YOhUeEZHfJfFz5yCcOXrOKQ97ikDMo8ABgYPsNoUVgyOnt/HJuOSqdKARQqd6p8/H5WtQ+lbpKkLNNlHvPnTRTi4IWltWiK7fZn0lwD9hGP8DNOSWBlotcvCv71algKYmO3suLyrax87Xr09jcYAUFgpTwRyrVH4SimI7EfzH91BRFNF5WQDbA6qU+uOeJ9fSyG/veDK61rRiwprprRc/vrWEZ6PMdF+AVxln9cGcTy6q7Z75pur59KvvKO0tuSGM9703YaKHehiX+8ejB26ZhHcXswdYITN0mDsX1KXUXhllu/v92i5301WnD2huokFc3ztNgiwc/tVxZcURUqluZchZTU9mTr6mPDUSrP0wGnWxg0LsU102p6RK8WWY7y9/9gaqwbecopR5tdxt343lQ06iMq+vQtNceFmZBuLAzxVbVDnvOqT/rI0MTO/2Z4xQwj+4UyAchDBLPanYb/psrZl7apMTp2BwYzagu39sXwPi8Snu18u7Da22m14P1Srg1RUvXPFdEaQq9lxS81TgkijshWcQsqYuHxK5DW+ylHDGUe/oHZ7BCvggRSG/DVr9Mdox9MiGRc8w3YQgkrs+SvEq/8AdhQx3ewPlXDmfy2o1rZUPr5lIOKpdDmW7g/4+DEAGonjMG8LQ5l4N+SwwBzB2ZHk5s6+Lta8Ar0BBpWclHEv2j9g0v+DodePukJbzvVFusqWPnPciJRUs62rSaS1u+13Pala8VoRjobdZ/QW9NN27utg+z4AiwZtPKIUy3DIVta6jzDGwUpFYyqOzbUH4wWOZwkh3fZ6n68oJOerJGXdDOTn48gO1ykIMjU2XXqlFkYrZrJWJndhjGSHht1Ufd1nEtyqKAoPfJOJ8OqUmwYG1mz0paFJM7W/CmsiTmgbtSvfEIH7shzJYgy0Ka1UreXvi4TdPyT1bB8FjKNHlidhCvta9YaIZGk6vUszya8SxYi70R/IbbCOnqY2b+2WP3uqAFKnYOzUwnEfvE28Omrglhm5jgvpv84YG7U7RI7P4tJ7TnJ7AZ6G8Bsubs7/Z9rqQxFT0d/B3l77bmOfwvJ6VdQz+6Qj18o0iOeBgbCx+s6H8mdjK6gnTffdqwLfBvfpRGvKh9PrbVk/3AfnS0KQGBdB7ljUdtrum5zs4cjSNAtzNoIEx2g5jriEwH2+LcLlBNUrTFP4ELxGUvRRtZPGf1RPxARUvvFUCgtQLH/fCCWL36qHTMvFmCWSjO/gsWC4FDGwtXoQFZ/jB+qrbLaNXIdYR0hxKOw/eG0N08D3W2OhWgln+IpsU99vpiZUVec2hxbDNtihXUzvie9HFva3sSSdm+INNwqq2qB/kW7MU9wjM+rA5gUqMkx4ErenK924MwSan9GDciIj+CGTfLIMAD8IOFZgnxdhJWiUD2oiEtjgO4iQa+mDqQEm0c5gdZ2it1oumeU2yG10xwIG4fIRDWBVj6opWPpFr5Pu179trNWVdYKfhbXrUOK9xiAALqN1evBoqMAQ0gFEbCcnz+KVik9qlBF1MPeGdYbv8K3SrKKKIxlOw4bYcZy5mctUAgOyTIFbFUdr2UDQBR2S/rKs6dJC+uIu53GB23NJNMsWLHFeKU1XYgk8tFj4+qmDeAZIpw6yYmDd7tob8mYR12Rncal2gBQWpJidplfJ/JB+BZlegIYooikDiToNOaJXUgyDtcByHS8KHh8c7u0XiOu7TjocEmzBvpEKbYdPtcyFem+GXcP15YForor1T3DgCpeXNQBsqzzXltMkRyfAfuaTmuBVj56b2dE5nZDp7FtgsK4WKojhkeWflaOQw350vKt+H6sq0sxWg8J7I5lcy7kecD6vr5HIH1I8DryS3y2KjaewZgb5RNCF2Ribn3qwunn3BuA+VQ4XLdVcN8T0n8Mn9YtGOzEK6zlanfD89MMCmAuAUsUtXUuqB5C+UQqfJGu5pLrgj9dG5G1EoxZAAol1rlPNbVcUHGwdGfAWsHvgrBFgPOl4cNS+WsVkb4URLjHcPF0gGyCfVpK9JTuWkznTLBYrpyjag+629YYf8hfIUg/+Yll7+kNlodL5WBel5PIgSo3wpx444iQ11WICQWSQk3M5l0YozAScQAENV6uv5AdcpehWps5K3VX2SzCJLFzKMW5Lf9On6SzWHY8H4KybuPGi3l5Ej+IKmIvZItEiNuoZiq0w1TG4O7r0lXWFA9+Ju88LUaKryzgW/SHntoakwfRhXSigIfOuY8nrsc0iQYuRPK34a6GmyMsVzvuJi3EmUHNj1MTXUu1LZ4MtAgc7y6LZYNvb9YNEEX3Z/kJiFX8QX7vV5ucXJo1PSA7H0c/MC7nNyZDCbHKFGYJCmzJ71UTAqVWpoa0IxoVE11OcXixjfiosANmhAk9o79LR+VQv8QNtxeM+3Ah7MESN9VrqnCI/wj+wtP67e77ayER1+GIAqyPMBfDQwZKxiV0OYDZJesdjtXdTGByKTH+zKW2MAXSHfC3BhzU/gWI2786b7OKPNdXCMCqNa4d/9OsX2RViBj8fXxf29DK30b1bFCk8IW9XBbDbm/hpR3Mxw+OivBYtAJh5YPIFOGo8VWRJh2Usan2ELnQbTx/MAo2CFsat7MfUDu64xJPb4q9LMRzBt5NUWvB6s1M/1mlHBYoP16n7pjplK/7T8VSiv7IuMJ9Z4EdyXsAMdMGvqZ7k/BZv7IcfTpYavh8GrcEnT4+4GSiXlFNvf0N0FY07WoU16hhwRZ+28vQs8aQlahRQg9hD92pzONJ6/7goPc0VmXx31LK9edoZclJOvPxQREgECtyqIwhWmcueQn3gayUMwY1hkHY0XbgpAHBrZghBfnY4EbUXJDQ+hTI4/uhbQ5oWPWIGHNpwO1z2f7QkVu41lTZ93NXEN4qhNwV2c0tP9ECEJm3wQL5q/Y8wgFi0913ZmFavJj0zLKbhSZ8iLZM78Y9/lWj9losYlYFPlT4eKJWM//b2UJW6+ud3AdmPjrpipLzJK2IOd52UW+7tNY1fa3SSYILZPE0xn5da1xh/LzctwJzciEs2P0g22pi9FNUg7YbRqoWWc3H5UBXU7IWSyC6icGTpcJVlAdGxEnmeUTaFGBZHKAkjwmchIr9Y22HRuQmOEmdz9514ghvdtClgj8W7DAHFhXBWhgHI4gIsOT3u0vg6P52VK1aunkDnAuYjcZ89vJR1quBzO2Y2YhQmFZovq7ag+0G1PUJeLnGa060y/o2AMS8HqgKMdsGM8rvSxQigP01IB92+n1z4TjHakVhWpa/KEkvGLOeFUgyXkkV7IyZC5H9ht422UbvmY1nK8s+mbi3HuGUdO6ixXT+QnCSU5Y5VAKcAi0VdB7evXEvJUNTFr64n7UsTdq3zzQjv+1d26r8VVvf5+tV0xm/DZcKXsnELcPwTEacSRa4FQu0rK4ApKd24CtoCZwk0B9hEcCzZFVO+Z1nAeB3JbyyWROYXIoISCnRLyGqVSwnGPD6Y8iihTN64cT6E1LqxBZqUvffeEkn2QZxSQj9eFeFPC/HrWPNY8pGdAX9dgu22lLkViRVmCwWs+kYBDCrN/jI0lcB9nZz7nZ2Md4nZ4w/WRkkpUETmVKSZfnh0MJU+n8k3Ou0UmvY3FmonG5OFJxu2ayWmcbJ+A3FUlJvc+gS8DuGC+qi/9BGyL/yhtJaCj3F2ah6FOrHJgRpby0jItcTJp1IRGojZ+BffDit0cxi52xkl8MN3iX0A7b8nyxEp0SUd6ivTHNO6OsZWK3bJFGDA0pUpzVpxKCvPh0ReH+OY3leupmn6tAYLWLMMT9jVWQtdjQhJ8bRiFFQwLe3Ch/rpaK48i/re7AfSUqXFcr9dnN5qW8fdabT8zqPnP8TFG12T0ArJiyjIHdhyeFIyI0qWTD/UHefXTEHwxWp0uRj7b0K2RXPLHJL+n5+3Os6jzYtwETbm8kN7jx/VGCqNZm4FNFW2r8EfTY3P9lDDskWN2kbjjos7HCkDFGwE4MKyiIaC/nYCcrHifSxOrDYpE2dtlWqoLbIof1SKZ/a5n1fCFnPoiwTozNxbNry8q7Uxy7WbhJDyxbFTczgWZhKRg4w1OVXVO+aW8mGPoEUIDjwzutnodfZpo2joU72D/H1D7V8Abj70gzBLmbC9X+R8EhaSsUOCZmxyihyd1aK14FBDf80irlE8b2wl2IsfgYR2vPs/qi5JmBOX38NNfgXVXJYQwzjvBhTuTuxJ3wgA2bNiT3j23nBKXOryR21wngLzPRYoHNDAAujCsRpnWfhCHRBWCSRY9zGjDmsL/sGpqLrtxJHf24hd/hJ+SfJUhgzPblgYCxBz+o/v/o4Nb7kcZonxbWr78YjEjepDsfK4kVDjat4pZMmcxTL1wgtecGfLe8v+BT3yyLpKTKA5bkj4umQM1TUNkkxt4AMDCUPMDOXR63NJ4PEe893hwV4cXaLmtQtqWx5MriEfrL2hYPW7x94tFmI6vHks2PuBnIuLF/F/74BOgFvWZ2wL8AeW4+HDPuqDqmbR1Y40S/35r0gJ5/bSimr430PsWvrAvSqhqAm854z1iLia2KswxbsSvsaC5vN1K62TEEO9MaK1qOSZQiodX25stUdhPBXAU+R9STYMXWkJAZikurUIUEWCJZwd16H45hB9qmkGCKsU78B9rnvyi5H6vhEz7NsQ2Q+ShiyJPkEnUshBifzg8XFbiZmCn5FGvjbrLyClLIDeoS7zvgKUgaQbTr543U2zOrJLxVvKCu1vf2ZwKovQsAVjA438nTPq4U1WgKP4u/10tKPbz4wzvhntLSYEhzbqnxwYzLfiBzcfS3Yv0c1voZ/UJ1vb1QjaIGb/8FWSUAIo8sAN9gk3IfbOtoFUWHC3fCwNjQ9DqLuObyiXfvo/8HRUd4pRN/tO6vfPdNztbxLp3S532qdTF7h/ldDamNlx4mjN3lWZ4RyO0jlnz9+cJAkrJepQy3VOV9YocqQAfaOsB1t9aMiHA53swJW1S0kePRwI/GViblVIujWlJOEOUoNfhGSvZVkslWuyumNfxEFqmfR2yHWEiHRl/5TT/4o9OKNmndNxc74WFSfgmND+r/8vdduLIy4IQRRC4SxRjC3GCJi9/ypf3kNqLEvnu+4QMhMo6yM4MxNomqBOrz+JWacRpkMof0HZeLqNPsA6aIobz9OdNrrj1uJWMSUI8z7DrrPnLjCeqPmKnR1x0t50kEizv1mg3UrS5yv94SJUGTMk8jTQxTBgeEGSeHTLnQwaZwWmYLadcnnhC+gbCHfQ24EblHPRHlpJXm2LutKYyVsdcKzI4ED6yacYttUULoL1iSHTft4jnZKU2h29On3//L0t34Vg1w4XrX1fvfhwu+cmOGIjLdC502BO5VsJF+nzKyjjTWtQry09IQQpaGaJiMsy0RLv/+3WKtqXAVXO7q6umpWXq4tOxFHZNk6ydfhFZTyKQmAH5J5tSszKimVizeB6mvhwHkr46uKr3SfJc3AVVrIxJYrrc4G6/rHGhOXZnbOE2TzK4MTo2NotKhdj7MbLGM60+5nZeLd2NYky21Q/DoHa9jT39izxyt/AfkmNlH03Xv+aTS1epjZMbUnmZ+6S7e0rlc4wIvI4jG+2fe/u2dL/mPOwk4ks26w2U204nUD4PWvgSeS6edYysrMjonzSSEZs6laQ+7yQ8lDVa5omHTQzjbNICJgY4GGtAZx7njoNMP25kDwurnz/RJDaQPs6O9fkUDnbrIb3DHRoEiOvto6/3rsyRI5Qq3uhLojwQCmhIoH+fdYhjKZDjJ/EKSSwHD/2BxbmBzTZx0IsDXVK5SpofjQE0BU1L2uiJtkpGSYvHKRZUExOVWt2/5306xgoaeUZ71OeQdncXQo6nx7aQ4VOC8/u+MEjy55bBdDRFpi9g5gNBtAOEEmdBOD9KQ3HzJnM/o90ezAMxAAAABjbtm3btm3btm07H9u2bdu27Q7RQe5NSfNo4eUGbWEU+4flgJo+7YuIzMsfP6x/OHNAFWof3urYApiI4E/VfqY/o1RqcGetZYlow2VqXNDTaQtkT5HhISP41WQKa9fKxeVw7pVc8QtNvDnqAH0Hf9UvmGs+K6l/kxVCPyOjUucrgG3m+YasR4UWa+SXpSXCUHjUoyRy/RWYgjSEn1uL5CV3H+F5UWCjK/Ex+wiLMF7W1ILbz+kZLa/NEGf1Si8enTspFI42FRJduYYQm7SkiBOiM6HLLRclrKZtAgjA1phRbHC34BswyuOpXRj9PdmI1fkoLPeP1Nwl9+DWzOBmXjh5Td5UcjqFTkdhqQ9Z/nXVDrjO9i6L2nO6py99+S7VEWbmXOwc2rLV/UzyITvdVmA6zApxt8GmemTy1n5ho3xdUqMwp/07UsaPVHBrA0E8o82+RrGIzXF/oFRg2MTbI2guz92jLIZid+gICvQ3jXI3hqOLYeFlLouLIN6NI7JXo8aRxcg2q6Wkkf4NMg7p8U8DILwpBPGPpFqNW5F/4CdPuPrPRYtQEOq6utKkLjojd7yH95iMhSh50+KJ6kNdhoOkka/rYT7VrJWMu78UMKA5yooXwx81YDCgs+KyWnodUwwk0HagVDPmN9czEa/L/gFE+uQtfXLW8UMdTKIxRsCr1Uosrmmi3aVZsdYTcPCg1KkKGwL5Y663nZoASmUwpk9P+dTkxA3PLrfInhFA6ff2qQ7IyeHY+OfptZVEha+s9lACHXnsUjEWKl1ocEyMAIRrKLk1VORRgxL0u2ejdzQ5olQkrwRQ658PCkXm7eoNhsv9YqcfNRZawL6QJFE/FQqbpDw1b549lIBIUHdIz7UbDvXwD+1AYY6Tfr4RtfjJWyoOTKowwO3C2JvoRmhbk+O5mIStpzBY8b58Ub19yWykutj9aU5wCasX5eh7mUjrpKa6o0EO5HZK7czRZYJPHw4o3OEwq26UlpGfGLt8KDWTcVBd9ae5GAOxYB2459vRcmddc1Q39L5wY2V3he9UBrdbDXd4YcHya3y8I2myETfC7IpZFV2NicB71T/UmNEUeh/sDcYmfRjnC3K+ufl+w/DN9Oga9hhHILE66qm2erPxT2A3bfE8Nmdt0QEeY3nGGzya81ZOd1wk3w83FPZS2S65Mrp9OWNEoUniNUsKqf2ra3F9DtpPEHw6xFrHVPX0v0eQXjijTQ3UX2CdioM1uqb1ssSBdDvYLfIAae7R/s06U+c3DAqBTL/SluJfWQKFnM5XfucHX63NeuS318s4rSVo38o8SyPwhS52KmYpHGc3EnchZ+IuHJt3sMAAJ4HBFq5zqkEWFTIjE4W7TuTxeYV8uGlvBPpmRMVv63kos+WBYeKZGxdjd44yGm1NTw28JoU7e5Z5RsXGnn1D79Eir9oTAopiQuJ2lizmW0Da2M0cmno+T/NVTzgDHRGIn9vq24zABikyCNoK4Nubi3BqiuAUlRVdmQ5ZozP2vOvprH1H3uBU7AHDoIGwLRQM1Y81WKMso072o2AQYGCj1+tlLVkqBMf2UMkIsuuGFEL3YVaS9hlnkVaWJhmw+nO4PhXbCW/J8+v7y84uxvQRo+Nb08fd5k1O7PQEunsMr7lWO/RsfE6NblrzJY7irNAuSDdXnZZDbuXkqGlb6HBsDMnz8kWKgh3PhKauHPKxzaPHWTalL/5xWt2rW7zRuLXm8+hOpR8blp4t9CHC0ty9Q92EDNQSem554Xv6LiCM8k523/i+2H242Nlr/EkB8PV741lYtDHNxbZcGBdC/vKwGPQKxS2PD4UkeFNPDTU241tsD7Ib2aqzDk9rnXywBWN6CVp/+KNkmgcrrQOQ27KySxxSBOdzT6T2jBhMtH/0e0IIVM4+A5M5LX2kNxVRTxxnCJGd5bkZSyjqGqIKQQJpWYcRUhFOPJSoYMzB4EJb2Z0d1FNQMmEGuJG9Flrc0FQMEERdApy+QI7VMocgHu85tNHbaDFtRTyWv5ipyWkmzHzTXYYXKwE1XDrpZKtJAOj4OSPeB0su7198XZMOZUm0Mt3cEMrPA0VKMn6ZSfeIKBTPPeRbhmtnn+AlEjzxJKYvjp59k3nnaNfwD/E/gWH05bSTw0kEpDXF2rDdcsZu9GzjLB0TCHDr1EUmBmCuDJv14zopYC0kAVi16geaF7rsRpsxmWvfsqiNw9G+N78xBwRc4G08Hykbq9lOEUChWY5vKo42WOBacyOEV3Wopis6XO0+ItEOujWn1SPjWWpEFu7VKZM7COBvhEqbeIPvE8jrUaqBverYU1LqIXbmLPjFTtk0edZtANABqZG5pz/kmKlNAipk2+pBEH55wqzy/txivkww1YuNFkgcXIeY0lhXlwMtROpL8WyX5lIxkP7VMVDG3F6LKcMbvgug5uCwDuN1WkTKwhSgXYQEFf+GvLe429zz2KiB/xn5hvTsufLT6gAwmfPDxQrF8L+/wTG8nRSrS9HGpqA7ca9CQQf4GI4Oi5VTfP74reN0mwStH0SMq/d+zjE7TxVDvkSFBamw+sCEhbS7Ivdolj6xqGiWX7OpxeByXMjftrQBZEcIN4+tT2RRBHkV8UmtwfEeZzZTCirCFukLsMyG85Bs2sUUu6chJiAXXERVryKYVMkmxQITKOM8Rh4kWc+hdalifzCQA1Dsk2nhuh5Sv9iDmsFqAwmIv3jtBR/npaCFNCVeOqTVBKCwPjgIO51o9+fnICoMnYnidFrCPX94JgVoWcDmyEXgqwFdZwOKwZIcNDhMSUnJgBqrJQPKyF4PgrMEjblz3yLbtHyJpHKRqnFymehpo9EdYlOxYnziuyLS9EYeH5+jT4vABw5GqB5XseNzKL3TGGGdZozG0T3gWDsIoBXQ7cdMiZHzKVx/eJDx4az36Gk3DKx9qAIgSNknAjLqMAxkrOTBHVcW36CxASpTxtxh9BRMBp/u8xWRjACV0eDnGk7qDjF/fchBdQfa26HOBWNo2fx4HCXlsjlxtj9dGJydDVygCPEqB+6a2G2GrSfieX4+hI6cvV7ela/phjGfuj9NkrGDFnV5yj5WMtwSaQ50aAzTH1ETdsi07MuCOiQZwhbyFG+3ntNVdOgWW22MgcOUUW/tqyCjWmn7njMydzlm+SaHNyr3UsTGR5KrjrKTPuvytvNQFhVGYLZT+TNtcpcbce71x/ULhDufM2CA6Gag84/PY3AC0U9Xb2NUfOi64TU60PvY1TJjjltW6494kAK3tb6bkTDBGtFxT1KFTErxZnl/w7hNLLar3RuKCB3icCcMhgrJBhWw2UvjN9To8jFsGcj/QLQ0ddg0sVjeBcvDrarVY5iDGBLf04dj/o2eafrl0ReLThuAVJeGK2+Ks1Ni0D0zaOWDJjDgU7blLzup//2KuJjoNJG00Mk50nzEBXWVjYuNHc98CzptoUohvjnKdtFb/b0mqDfb+Iimrrr9flTFe2CpBxGflfE4v6NhfH+oYUziIkhXhe5HxOWpU82BtC4SPcnZa2zWAOE1oC05+5GJ2rVkcPuro0GOm8+zacnHzvyGgzPLMvwRklZzBBqXR50YxhiuUWjq8TYa7eHcGDgT2JGVzYbeWKDb8yJtouLBbjp3mDRd/2g2EPxDddLWbUKchI83FCoUklcdGkrvjkGJNIo+KMREHWx0qUKs6BP3rNSKFFZCi0hIh6eyAoYAWIVPeBpj/5Dpm3/eQxe5TJ6slZCuZ5UspBXdj8Swzp0oxDRhYSFLxd33OzRfK6kegtFvJ+WjAXKSIv9Qea1MDkfzsUXs4AY+vUC3xUrMTEtGo8hpbP+T5QU12rxrny65b68CqnoUUJmIe9+MyATingxnYd5JnjIzlz5GeFU7ocgWO1eHW1W+vKqXqirnVbV83QhMlwkucK8DAnNDisX6FfGjuhIgwjQ+NdDhX1SMiXlyujy9KW2WPY01NQeBg3YKKWQRvTd2x8pJRmgcD1jKgfLwZSJTRW1ua7gsqaxz+2g25898mFNOH5E/b7WCE5bs2LpYWYTcJDfu/7nYlxcOXlMrzfh5mIh39MzSqaW/M83TimyzK4GzewDLGodDHQb7ZMq0B5n43hYIIpuVvkSowuvA9ALj7+Oc8Jrh+hHH5N3YMc9S95YZjL0KZViue4YCD7smWXK/UqBzfaS1JEo7hWo5u66/MfgXSlDDdW5BWgdGuiNh9wwRCl1pogAt8/er3r+M+ZdRBLhZJ2dWrhpCJOTtIU32V+RoJUlZtDK2f2ywBkXXlv45RHg7xmsNVT+tWMeQ94rykkpT4Z8DP2nBG/uv4JSVH1CYwlBhNcYTpnHuGumuS4kr4XhCrHgiLiijp0+xsSkGZZTr2+t6+Kw7IKUZDvNyPlz43I+a+CvcAbCc/i95Ofr2nYazadcV4SV5dVxKMyEs24GxxrOlmWbq7HNmrANRZTVlQSV1bb089DlzVCseUTds0WeRDo56Bu9eKCdns5Ev2JUxBc3KXyLrbbJVBD12oWAbUN56SaC/EJO+m1ghmN0U6cex5v7ElW0HbFsLKYA3cKq3tVs4ev0tR+SO83LLm4fFOQoc+x5DIdwIeHACtVB6P8vZVIi38rH2AjNM14n60SgeXsmrQFdBdk7qiA2gGwdC5hAyPseKGCegq8VHp0e0YIgF4GEA2OBJQRf1fDaewuCxHL+H+dO7XCKtU5ykEHcfeOuyMyVcpkCJflU8Q7ewQLnuTOPgUQ3Fr3pkw9AFV4FoMCjzfNppIQFiU3QHr5B+nk0o0A71/CaDXI2SdU+5b2L6aUNgfiqLn81W3Ir+CVlqGVYFF/8Fwp0bTuH+D1YMZdG+TnDrFIeIN4qIJr10dv5fjgnssFRz29U8h1P+u5LtqWyqSsw/jNQqrvIeAbld7VGlnYKRAvrHfakHlWOTtkRwLpe8oDJ4fLdNrMPb/kb4A0HABkN4it1EzhuEQkyliua+uiFsB8Gpt3ikZSwAGaGJw4aFB+k0LKzM061K8/AFSZ9D+UuopsViDx+2J/v2ZoWwyU7MyXJW6UO8bwZb9AXJy+uv6HNB8OsGPrYd0Jpdce7FobpwgDVl7IDsUqdYvmV0dMGOcoRNG+UJB8Zl5+8L0RP5n6reNT+CFbqqVxrQg8Omr5sUcEcKND7YoeiQBtw/rV3y/gbpmNFi8cV1d1lg/VqvPKzztLXE9K09l0X6F7HZTD8jPOxsXeCakux1aO+jZU/louq/+qZG+wrvSjw20KGwChk7fXnNi/vwWHHdCsIOHRbOO2aDmKUVUHwkfln3+I95ZoGXMOjtdrPpxMKYz1Wr18SHXTqA8tj4StiroQ4eZ9VYYEc0BWvN62Zd3bx65ijmM0pbohwUSkq7W6qpQ22zO7fWI4iPe901VnpluNjh5P5Xx+jiwhM1skf7zgcS8Cmj+hxlL/e5I9vmDYHas4hCel/O+byV0hCUxRknXzsKa3+VYsuw3+3UIlh5KRXqE5hiIv+wjHyZi7VFyBtALJpeFttkjy4GsmpbJi4/4t97yjzRi/zaMV06vuOYxWe0Kej9+/0xSWC1gl03N+6IRETtZldFfteto9UHmYeNkPq9fcuAyaclCvhHeVVNGeoLnaphszkZtqwWHEGbNVpqP/TDMydf+0xPWRL5itwn2NneU0/fZplSzJ5rU/8uDL6taD4+rAlyB5qL6NyZzlJDx7IkQzGZU0iibaRnuCY5arDsangcUdrlS9Ebyujziq8hZElpf1HwtuT3POxLjWlWRc9wxzF4oAZ4p5JeQ3eSFXaggRBDS3CWVoV8rUG8SWD8RMh7ZrcD4QosWTX6vRiyqOCOlH7ydf07zKgkWFgA46WQ4w/SbGzRTXU4Wlof/IdQ4KOFXCJuadtuokezmtQuXyfLcMhMJU+vKni3esIlAMl6A2txwtNNJGFKYTnxIkjz2ETTUehn/zg7OAO5vetLJorAVrwTvyfhKvOtLOPx0JdgaANHqh1sGbMM+5IbyhY0d6AQ9HwWuQaEhtxnVMaDyeDaqpRbN5A7eSQ7nwWtRY7j2OtPyHdSGGkJ7AIcslgP0s6uf/6CsCvqH0p8SOGB+dQ9et2Hit0bTAqVN0KyAEnvgklxYlH6tommzX8Gq9Wmz+I0f/O3HnmfROJsYX5X0PXZyp5Kbu8KHMrBqvjh9JcUfwcj29HwRsx0hvYzRGnzO+6lm9d9nCVqz8iG3qmRJ4ELSaFM4Bcb2NHIWCGpL+yOZow2WsDm7H0f+TP4lAw0Km2FpTHJcpkkHAfTD4o7rAUoFHlHoMwPLdWAbBYVoRO9ElD6yMQdu0M1sZiu/2ApPzq799oxIFhp9S2GamnTSGwWLUr4dYa1e1aiXl1IXsmjnvALgHRfEeLoaw1JFRuFuGzlpGSCMctLhLDv0+1k4Uch1qbXcXbhd8wqH04+3D3JEXe+J2rPhrPrWJeH2XUhdq6L+xghs4ZtCvEKdpPtYR5f+yAKdy3Na1SmA4I3z0BXf0eftVl5JcHGgNCm++HhzR2aYzsWC7qOP9jyjCkVpeShF/AZGQ7XnXPVpcIRP/+hQr0+fBWWDjXkk64xdjlnWHhbE8CvUaozFqG54AWbGuuFcohnnVQ5vENjcGK6amScSI8yjxvbcvuQvlpTT+DTkNocKS2WAei4JPmNldfNv51Dc2OcHCof6u+bCr/wMP5IvR0nxjLbQ4fcqiqskzdnO3efL3sNgofRupci3NRa3OupvJuhcxssf3p9eGTPIW9A6OZVNhMO7OcvGAy7y4BP1iADCZGy8ZYMRmCns7w+Tjg9eJKGE1aTlKZtCbtS3rg/Wcb5ZMGBn4g+JdUj2ocmn5kugewYOI0lxycAAbrPObPmEZqbHpOfUzApvaulEO35LXYcSYrk5l+IlaWXTndgHPvNOgjsdI0JX14V13zriHdjpUQdEzPYIUQXrwQVHsphT6ZKbYlx8POru03Ft6WJNqAz8Ikqml5sdJHOu6tfuHUd2f9ml2FgGm+bUGxTwwvgS3WmmOXBELnzNyYbmslScpSXoCN+fpsUZk4GGi/rpQ2zVcoIszX5cKODccgK/QjIicwPpnBqDmpKygY2hLbQV+fsp/fC85T0ShFFBAcBg6Tnqx7fO9izyCFbJaCij8hPjdD7doS2eg7d4xwzqTOgl1GU03mMJ6J632rkRtewW0Z7Fo+luGPULItwe+uySguejTZ8KF753AmD+7EM3NjsKNcmVVRQGhX01GTGA+tcmiViwf7GHUGOy2xs/3Wfdx2C+/0OcUrtwd2zH5UEkJnMOC7+cKK98KMFaj1nzjmESeJpqHV7VeD2D+tCdLgpSkBBU8vfwO4QRyAF2MBP71X4NzVTuYQT1pq4b2djpDIyzxRg0Hxp9dEDD4xOhonGxNoXhZzX30hXSA9KsbPUwU+EHQXNy8/UgO5xvvxwoRiuXGA8l6eR5ORpEPK6COirG/RkhJ4nyYzN4EAIxVl8JpuxetNHJkPo6VOPLufPvKx0stai+HDsGlQLzmGJPEHxcM+UzZj7Wylp60I841l+WAuBPJyI9gzL9XtmOFp5m7rWk+pLDkGs/eS39bIGCB9yvfztfNj1kDgbD8odjZIPvnB8iASkIKXJCIQfdk7Aj6yH14wyKRlKJ7Q9R0tRltqtdcqKcltwrpVUEQ9ac/7wuwvMbACBi5wTfwHS0LYKtJ1awFMYCvlPvvgfyreVlUoM1Yct77Mc1uu4yqlomlhniZyaVW9uNXRjvKj3LS8eQ4x5ARIosSMlqpy6Yi1iP/4iCLJvPC3sTxjT5FotUeqbGOxbZOlIkUtmKwX7vBY48eU6adHmuVT0/9TZPyu1Kzf3JWrofvtlCWKQl4NqDHhrZL2UUjOkbUrtbmN84qAEQO0NvmlFVxNecomC8sZe0H7YhoOerKpoz076bn78YietSXe77ybqZWDbyuq3nKj2EHFlWzMF5cWh54wnQO+wE7GaRVlvFJQh48VdNvj2uVy9ZvhEQuk6BgckJ+YTuV+/mdrE7SgW/ewHCI+sXZBvd/6scexN1VgLs9i6q1omkGdAq6tRlZPeJgUQD7dsEkaBUja1o+0l4hXBMWrc7Kugtsfa0a1vh6NMfnUFN4iBPgQfTfgt5at2/h7CPW2bjNSe8l/p4tr17JwUMOQwGRragmwuKaR/GVKo7bDbLIb9UNxQm31m/RuSuONAGBY6Mhzf3nNTN6/He9oa9N74fLrpxC3q6ysW4VD60CUybUc0H4cjz4e2Yn6m5IZxG8SL6n+U5LQzC1TPmuWgHfeSTn62kh0SYZXlbW8vAevcAEIr+k04ptPi84ksCSGIocitD5BqOq5aiW6USKPPewcAn5+d0oECzKndf/4FNFD8IGnSCGX9aCnjIniNrqJEIMXWOaqLZW+EIBNq3F7LCWFBbjJcTIjfZkZ2qP9M29+foJ+HF+3M7HDo0bMDLdiVLmA4TdBFvKpf6BqCQSXN1iaSr+/dogUGoeNxiqkEK4QitEL3TqPV3zCOJk4kwhbwxXMsE/oZuzULeho6Cq8CKMku29Rneulz6e+bs4OYJ8M/GJbyhNBDdavbh4XmPktmKtGjGwgsLBZFsoCqYcYTOHZZl6o4hTLjTHXCXtVN0f71eWkocNA6zxOwluIz23V1v0lsohywSzYOzzpgtzoijX49HN4O8urQuAw4v3YziIB74ekNk37g9svg5xDn6v/CzvsS3smmfdqaLjAGxCq9GD/l/gwBD5swBHAYzVF9WQZOJWUZFqMHzzkxU8fxgXZ96H44rMZ+NBIHP4d5BGqpRcudZcr59wygbRJltcRpzSAoC2DWT/U1i/Y6qITN6+RzNYgX7Bkac53lj2aiSa4zeiaBI2so/DgsDYTqKkvA74VvjXpofNnXId12syA07RwbIdZ5telXRUERYsVPh0HoB40CkkyR0xFx5CwPrUiUhm+vZ4Dkw/UZy+y0BHTcXziiMmiDqLjhM6hpCY6562rSKOTrZNVjY2PheFYxd4yjxJh/zwwjA8bwPjYTPTckuk/m5x9Zw9uvv77PCrZ4cXDd9rpAkXicZvH+NKgOcwXYCPNMdFwYkvKr4M4icLrIOah4TNiYX/yThGxKO1shtJVLX/PQQ8eXx07mwdPXuCjt3TC98gE9WLL5zVAusl/3x4bBhO337XCkhxHZYFLf1Gr7k9o4KfSLM3OPLMTKvSf+Vmkzbvguj0MlyJPuJ5udC0YqrjI7KVjqwuDVSRR8eSeE4w3dC0S6SjtfKxPvbWOkWXiA+BY1mFvwdVqN1ACegbAWX5gQFZjezr2VuIYjK6QRdSWCBF/BGXTg9sDFTMTqoTks8eGf7iJMvTpvtV6vK+piwHOyMCttHtLfdL0m/vo48uVyH17gGR+O1fsFCc2k+6t+wbHsbZmEmn9AJ5DmmfI4ZA/kLYb4HiQ/xFzp7CH8WBuxahtBPfoTy0/+pQV470eLYlMG+aQhmujB16sCNzU6qHDLI6O1K3NeKc9KelZ+W7FFeTgXlt73Em5YyliFavkjF8vz3U/xPH66zfMIvdXowSenGhN3g0Ct+WkngdasrUSh0l3mLb/OhdAwaEUyQKksFevnnXfBq423eH+cf4MCH3FpB5rXp4zIGYnzUPmVRJ3uCr+c6fIJFLyb+Qu+EobBBVuLoRyYGiy7veQM1Pymob5TUu7b8mQremFZF07J3IVjGm1Yn1fG/L7UJ1Gv2oJhAzU2p+Pwwg7pFgrdGumM2Z/vaRYLpOY7CXJZe9uSaSvmgc1jorsERSQfqUexX6x1nuHV/7G9LBV+zzJDCkbqL/B4XL1pPRhGfnV0Mq9UVgOS2rnPblC42kQZkuaPDrbWSnEcQo+RdLSZh1FG/qoO3d4UfDjNpLzvjd8P6Y0ErzBKhpMqKLg5PhntPFHGxHG/QBD3+CfFW1Lgd/EbdaJ+M+UZZeafvb4wwB0YiKN2/IyPQ2uEc8zWUTDRvzqWyDj81JuYuRhsiFIZzAduHXWd9TxiOcU2TkgppnJzidIY0TDiJc0q4kSKaUYfjOUkV+KvqaSAjKrl3iO5I5YcQ9W+jo4TLGqDRHMGCITBwjWVfWLBXESnKQM89E8bE3FcAQnZw97Yba8ojeCgtxxXIh1KobeOn+THgL6vX4Qps5heeOJaDzDzVcEyoyWxK8sg8v42DuHoQL7j70reF9shBRF6CVg2d3ea/vU6ReMNdTPws/HrTmFBXj7YW2gTJH7sLyt92LQ9abjsufUL7gBTL2U2ldbnJ8x16iIHzx8rsj6SVTD3lLKIsN+9lAPn+1+JsCIds78bYc81yxo4QOVGDHsVWM3xfKzv6Y1lzg0vj/X4HAJ+XOMf5/x4JodoOF3FWrVrLOLu18PwTYgy+OA/mDNcj4N5Bk5Pr8zqawH2QMDgdjQWImNJttgSpxQXqkIsasmMKU4wJA1C/m8zm1DBglID09Or8bWog97djMShUAV14v3W7YXJ2h56m3YrMLAY30DRPsKdJFcVHJv+iASTc7QbXnsfs+BqHpREXngXSc2cDkEmIbHSvGJlf6g3TDHUKfcSTCbgNsOrfIA2EfQTBORHIQx0/rgrOGJucKI9poLkpW2Y42zKIpx4Eo2azUf+ZxpMwPcNtmHDgG//xSPBlx1JGVueYjq5PxKX4HJo3sqxHNL0uHcWL/jkAzciMuU96GJbxMZ8iAe3XM3UR1LpMpn0mlq9hkfrRynopKIgXjkA+IH4JE/8ttzgZgLAYpo15CPA8t7LaGx71DsWs0CurOkOiH8JCe2eFkPM8NmxRAOl1gn6zi2JXmiyEA2cDfOpuqqadsVVEJRfKUBCwSS6flBRpaMO5Ngl3M2C87Gx1KCkJHZrZfi/WRkYTNdOtAGd5KuNDOu28KWhojSjlNh4N+qqS6WDxj1zulAdUMtbFJsopzupiTxtmtC4TrSHuo/gUHHooBstYbJCsuc1gf6wF4/n95cxcIzgJsQzo9yq7Tcuv7RvTUMJGX0lRE10iqQ9HQGBMwK9rrxdSTEm8h/l4UPBz2FUNcN6UCHKWcTwoGrWQju1AbWSnmAbUxX2uQYQ2sA4O7S5Ts0ivXzoZ2lsgBbHMmMAOUc7artTQHNnyc9914o3yR72AKSTUcE5h5qa9+w398xwJFtqqPAsDk/vEb8P5gMG7Ns2FstoLGEqhXySrGBZfHHWUFfhA2ar8zzUo6MPfZZy4loujryI3a6l51pMz8PX8HtjR2+YX2xeuG+mv1P6NOI5c5PPrDfke1TIdzUELH5JkfgoVh3Jg5bVyKi3g2+5ctUOYcHLdQDWvHWl3Fyf9PHJ8gAZAEX50go3f+RGzMyhvqMYRlF8Yvqrhbo4MiFftDkC0A57zXE+A48Dg19IMkad+/KAuIw8FQa8SqjuQFmLCWqkA9ZchOO00PWn2p8Xgha9cujQ8W3gHUi2ORpwi1lwZzEnI2YUgcgjP+RltlPC/fvpoXv0CDu/SLaT1fvEMnajP0SL1QVlV4AaXyPjj+DuZDDphuw7Q8tSqBLjPxB4LfrxQoUWCbSp4XoSN1U8mkDvd6k/a43d8mMIvxb1AyOOhHBoH4+McxG9zicubV71CqZSxBmypxxFjoLhjwHV2XkffIQcB1L2jTiPXu/z3MaLsRRcmSF3fM2Dk7zfZbJKW+RzeXZs8+E+mw1Y5mHE3W4wUgrvEgcvom93kVUg0LidNd62qkaRJgmDm5U72GcLdR7p4mzdgwouey3rYb+aeW+UuTH2FBvv3x3E0PAvP7xCXh7iQEKATcUSJLwlT52RwD29hfUBGIWsFpdtA41oYyN0u+nButjAhnBKvMMGoebDT8PehhwvW01nlI59Ud2oZssqxA2vyfF/YeFNlbA2tKzeumk7iYarqDdPE20URxS3qDnpF6qEIKym6St55AeEA60C+5/30d5HClpqwFINAI1mV9vDTFcf6jglwf74VyFgDH6ahhALvgjArhHmp0kWGGh33wlDbfBetFSsQhyFNAfBYnQpWsLaqqmlO1Jk3XpVBOL0V/kOt/O/ymBrsRrIlwJHt7/MMN3oXrPFDkbisfDmxtRnDuwW95kw65TdH92V74/zNvp/beoIpFHDheDpXY7/PlmolojzkWaSCmHeJ7ZCFRdDQ124oOixYVsG39mL0lGtChJ1o2mn/ibvejiZk4C0qZ/Ozk6+1zCNoY7tpYNmuvutUF7ELHo7lcAIWYgB1RGmy4QGpiinxrxSzH8uCkLFh5He9ruKhATlpv1HLjQy3D/a5SI9DGco7G/k/ZSiXcrUIGkfavuyx+vZWX4EQkokWA87ospkdyiS8GrxyI+6eJQg8Wh8n/VCYB1H8HooKIs3RSi6NYiPP9PYHdTngOsSrhtGUvdy58mAJgipWNndq/uS2YcVZQ1g6OfvGGN0wS2pUTdDbsICGd2e9MJ+AM5wdci+RGIRRCqGD3USLqh7gITeOZi32xH2spPZL/vOjq+1iuhCE0tnnj2SPX8TgX92tKgsuCDokXuPj4pn9OPheMuJxjpxxDckRJLz3zBqK1+k4+0xHwLv5gdD03S3A87UAp317+oQAOX3BlkUKRuZqBcSQGu0bC7XDjatC46qAVtvhTolDrH0bv9c9+vtMe4ga5HxjMTJXpUHh+p0NfezRfybGGA24oHtrPbZyGZUAVQrsOSylbtLVVFGVEiJENCS6KibqO3d8EKIE4xVAxJQWtBUawUDWQtVo1v1Y7SdQSCHuenDHQ+Qx6Fvj8GkDhXJAakmdlmUCJISqvv16dQDhgxz46qyqNgiK11zSeQZ46MMjFcaGHL1ZPQcbvaqg726f7GmC/uyfk9vB4LgXsKsmnt+6XJBlIlZuIqJYrCQa39PUHe0ELsdR3SqvLmg9Ki6QS8pAB6PKrPiMlx0uNLqwYaAkJSFvA/pmcvHeZ7+VqKHJEfWvPH+/TULMzcQtf+jClndCGh4ZCevBR95oSF2FIFgML+JF2Gkw9njihxN6A3lvRYnZwNWvIFNYLSoEnPrOGvZbVPYIEpQ3dIX+x4TbaHBD6IozgM/BZp2c1KSkyETAZXmuCvzanHAuOPQi7RC/5cScOZ8UJZcJNMghUlE6u8cy813tf9PMefFawn8I+aGeCo9brnH2XbyIsFiFZjDNBK6M6G8UPsCtLINZ4rhyJWwKg8wWerf/KpdQO8nhxBuDUXM060mgynULaetld9oEzFKHLjh0CrGe51oBYmyC0hmT67pyrlB3nPGnv3xa5nFWRN34sbQKXPc42J72MP5lb2MgvMXw23MuOTjBhGsqXgnx5vcc4+L6ANwnaRUqmeu1bYkaZPJ3rniIlu+7dKX03BP4/TZCtM/H63z8I4DpPQIMcGyEmKZLdzRgFFF6dLj88w6HaGjCu1Rmlz27MchyVueKDNLeaVghm+A6tVohuKRRjC/ySs+R4Z5Ax2JrMis5UsJf41MDYPk77EV02bPBR3/s7NyiR9SBxVPw2PV83U/ZR9aD8a9fuvp+qJvCbyxdbRN6eeIAmidTnZIns1ahBkTx1hPaUXZoyA94u+YQCTRMNA4iF8ICwtIcMzioOYJVU+m4ZUbn4fBLiH/+1OSg7xlmL9t4MG5qo1cKmgHpZn+FZm3CnErgXspkOEgfl3IiIKAYF7XYxE0272Ne7nOaAbzBvXUq23gAGngOgvB9QI4CjdgQwlrbnpiPCIQwcLrMjn9foHYWBJCAsy3NnF4FF6X/pjcv+XWQkp662yoCWCrZW2HKD0S0B2pe2ROW9oJQfThjro2Bs00w0MA97P1HyP2l52Qgy6wZjXwv0a8aKzbY9BjA0FLKPtJZsyjNTtRSpSnXiKA1lLeqwVMsHjUCEaCWqykjgOP2JakjBc6SwFbZKgXwhoeYSNhyUucA1NzkKEM9pTf4OA3Mfax9RYVJRjme3Q3To3woYLrfiWXIKaGHWwX4ybwqyQA9Oa/+9Ve1LyDnJ5hWyHbOzluL3AO5TeaufncoAe1gDB/TBzYfSyWVrsp+DuRHXDMsj6G43U2VS/CQzaxsMRavW9cIAgtv8tZ3CyE03kavul4pb/GQSao5X4wGiTc05GNmvfZ2e4CivIzpgadnMD7yxUL6qWDn1Kf/UwujqGzSFjC9dXdKb1rwtsL707L5lv/L2COnk6RRsj8tXKZhHrN7pqgUnaY0MX0zDB1/aXHlBwFTAF3UDriRYEP40KAcTEuKlV+2dQ1xLyTBSeJozRZSoDlzoAdEv248pzQFLIY/+D+ojYiBvxncoLo9kfW3GiDIOkR/XrN7swrThjZwGy4759DxVQzY2O7A77OmBRnBiEgPOO2woQpdnyJPRNDRfvMESLINgMIeRgNZ+kQ6+CBqmS+nl+pXXXg1vnwYhuwXROaYTjGmkLIcDICiBg0BnJ5OntJUpWtYOub191UfMdjG9q3ZmvTigvz2QHLnAIUWUk+igmJawPSNSNg5M3xib8vUgsUID/IkFF8VuEhqAXP54pG4MWzUs/wu1JEtBs4oNhof2ULWAJbgLtwgTqpMteGHyJimKET0DJpcLg11mYAQXkjC6i8A3UA7iQephW67lmov6WfsWS58Z/9sGfZNNyAEDFSh8AJu7SUorjdkD/Knen1mcaQDEOslHXm9Fzl16pzH81D+Syx46CXnQ4xU0TXW5ng2g140cw0LlgI5s0LfNiX1zu9jYOsWZN+7UeGtGZPZgo1Ypn2OgYji6S3GZJfekS2VUoIDe/gIRFueuBC4YxuEAt/TJt6NxIDwPEWQ88Vv9xrX6a7vOCW7/DGZKTw08yILzp/gKztGVw2k4po4pdh475nql8pSbWQVw73vZGMwN8uaVHns1NVgpHmR8gu8ug6a+2FSIdcvccT5tnWlu0qozn6hAMaVTN/jwH3fXrMb5HaKu8rVdVP+m8rbY4vs8qJ525RS9jFTTkGlzDt/d+1PBgUA7u2p8tBl5CYFE5F1NQaq9MUvDcBCP4ECtSGP0NyaHe7Jj1fC2jcvEdyA52KRhY7VXhLRjYuEAyCsEG39RYUCQeQPzBcnBPAjjIulucfGzrcyr/5bu9LzX9eTvVs7Nv42CmDIMzT384v/Ibdtb2meug4FKaWxABeJ9a0fKDL13AM6p5aSixyH2IVpXp4aEm7rENcw9T+NVt+VfHUVP61YefW00soghAUjW6Ghfxe/0Idc7BysqSR5O9QbueHy7VwEhc9inGdNREWriJzgUrYFkT9hX1iI3Zn4ynYYoDxcdmLfjz1pb8eXsPa8GWS7RKpnLQZ0bwBabSzZMRMgm4i49Lq2L+OES/0fNn5PWPNu0SwyyrSKi7utjS1m6qRl/ckKWCiQ0AKyG6RaXD//cPCqnLX0suRg9sgX06nH3LRoxgvu4gp83Mbry2RYwjW91whxg09mOZLgBfqyXkkmba7Eb2145kjXz3TfdpztR9N0cys2nhMWSGN/a1uRNpX9tXM8NNKF8M06tKNfauu0v+Gg1RKDvqnpAUrpHVot02Hm7ERGR0vSIpJiLSDeOvRfeFBOsMU+wifE/jzyOt2ObLMkVU6k8txQyeyUqeYW2R8JkQt9vscYx+mGAs+lOnDFZyiLlzRnrSCO9n0jmaI51cH178HRaW8AvWK9iMa9Jjtbleh5ZBp0afy5nSZr8+KyFni4sz928ig60FOsrSivTrysuqdgFp8MB4+GeC1BYwAZUU1yyKgBuaT2FERDo6wTv5Iwl3j7EHXH+haj3/P6SBHk0dQXA5K7Ug/FOLv2gW7CILWk4YjRTMNWZRsOJl0Dyo5e33KwWinj5t2k1Wjo/CADNCNZKm7OOozUItU9T6MeZ+D0D9nQkBY5kQrbfIF6GNhb85UDASF5kVXfuwafeobncLc+9BnvOJYtw2sW4RYtE6OFGZ9JClvExbMjaqiUF1PDgEQ6mGXJYHKtw98bCNqvJ1R0dKRsaurC+mwBNseoJxlagUIFN/hYchV2xf2MYNTokRUD7XQdYH1Gk3ocWS31sbCY6FSNfweSKkasDZLhSqGm8tYKFE0iNJ5nIK7gVb727yvU5B13jHuHroMhiODDJio4P3yuXrJe5+77BQI7h9SqE++q31YDkn9zMzdeZgL/j2adFztYbhxdXZpBH32xzcR4L9PN037A+oo8ZFLmyk4MvsNojRfOjBw9nQ1S2ib9a/uybkDoDtJR1t6NxmWbDogRUh328cLuW7XhkviG8Uf+ZrAmgz0CEzyPeGt7wBh5R+GzBHuJRrnR0WrzTJK0Ts+BAjaYITXm2qliDFuaTzwgcrQGuSbLhKF5FahYq7lILK85JLa/G87Wygpty3xU/nw27ADx5DsZhZP2QsMUawMMC0wRi5ZJsIHFPsvrZu+OztkoXS0WqGlbaf0aGuiXMW4ynBTz0ip/PSgP1esHNF5DrERzKLkuiGfF7Wt50hOXUMAqIQjUOT5WouLC9lVt19IAXei5FQDvogllkVfgnryH6+U+fAPq79e6x6t8rOY5Jz/2dMqVY5XX3lkY0fstowe0DzRNbRwtcC1yObJoZp8B9yz9nibg3dVpdRu5OMtVUQwFVYGgrIS+1FlvEP3KORSahKhBjS5ibUSg93uI4P6orLkmZi4NHbvvv0R7Mp1Gc/czm7/QhDBTvtRijO28WfrLXSZR2fHMXBgyZHGhpuOHjv7gR41miUEBxBL0stEprpd0pDSIi50la1JtvINkmbl5LwKihE47gILv2P4q/eJsgrY/aEzMdJUc7z0xXdSvMTkO/eydM4SeI0Ijp4vvucLIGu+8r+pVLB1gooC5c2ad7HBQD74OVBQn8k0vELELbjr2rWzkBs1R2ExdKO2SX0/gWLSxVriC0ETokf3x6teMFiQRuqHy3MbmR5kTBBf45w2L7WUGNo9m4wCfFSSl17H4En7YpONz5wJ5gFxuQqINJr0bSLaPwrKL9I94UVNml7gebuSDSKZP4eNso/YaCpNOEg/AScDp0dL45p/WBGMZGBFqOFM0QDcBJvaLMxgVWsZsBc3srAsvohlE0tqyKz/uC0WkhIXV+7GktDrh/KctTk35TArLpfjbNOimohvbOUzpX/mkcwPK7ykAQdDVZmULlJ/Szop+8SzvOf6mOtAFE8u89PE+g95/xKHrsV/FJsKuzpgkYPevMnVMtoIAUkdX181DyfCd8xKK/Hf4mZHTObsT/c4mZkPj67a7hrsx/sglhbRB7b3lAXZ9E6XpO2DzwX5g2o2EcZ9LN0BTuErt+mSV66oixODIhXwsiQoiWzu/802rJbHpdT9gkfP4D+AkH1UYa6SQWQLFNn0pUAvsgBsieZlYaqfAlSSRGHFEGhQp/vT4ny7pqZhLmlUDjfyLcQZbyoOJumU2WpCyGHXRb7oD8ev0kN+GM0ih/pipNkleSoYXiqZK/iU7xlCfRXt5nQPw87NhkYRfydj893a63UIqmonO81BjDdg6C1Gi2bSt56j2uPDXexG1oWQlmlRhAEQv90hIxyyUca4EL0d7B7J3O3k01u802CCemFHmmTXJuxTH2ZjMsNlU8lu0Lv+ug67n4C8W9ORSioJ4OxtTuboIkHmGRYXn7whFaXlFa4wmM0gCsd5EktN1d6M93k10AwMl/J3q5K/DghdEuutLEWUSLE7mCS7EMWkE/1jbYJq9n1cGYJZFj/RlQGJyoAUkdJZ7WnLMCEiUxaCn+diXAynnbudWRaKFQC/yUnyOWqog/iCW6oGMVugj6jM4DiOXyEmhDaOZtBaAuWBI+VsUMeGV/s2MrJWUC4Cv07CkpZQ8zOZNmcoAs9l4oHnM/WvH2vmPcURWFAHNFcSndLlpWCLUYkUa/UTtacK+pSx2ns08w+Ly0naYG2Gn3pDg9Mn++crfODdI+3zYbyEHITv+U61llR/Eo2zJiR6DBDSGhZR9xSVbrllYEEMTMA7MuBK6+wy4wqoXLLJ540JYKrIPuGuAe7AfJd+6iyzYRq3peaFTwfZmB/grCPHVsKzbtqf3/Ck7qCAn5CejW7kUyGXzzYjox9z2972J6e8AipysfGL5PHn/LDx0UEjK3agI435BRKHbpYZkCjtQULRr1cmsMVtKpayFEwNERbAD5/1AXAz1Oy+gUwx+jZPpmQyjuGTeCft2iPoUoMf0arHriTpD2bgibdyXyGaYBr8KkypnP9JQU60hgkghQIuYNmA6fi3dDK1M9pHtGbIbCSRvfQHVOKt4q+fimFsAP+m2eYbnoqsEblOcu1BK29nRaSl4H+hu5K+EbF67W4wj9Iae29tQgfhKtLNIbbsnqNDriDA0DB4Hb3dU3CbYibFA5xSIQKjXLqdyT0oPTE1EnskZiJ7AY3+V8aZ/7YefJWnVId5+by+QpF4H8dQHOXBG+V/dRMC/SXxLFsuSgEl4bTAYYtHIQvalsPMftWaXSnhIPVrj4YnmeotOa3mzEhsHqu3MX3vMYEIVR+leVscuyMXpZOUR5WPo08FeIL2pRhWoRRgbtijpBUxl3Y2CQ0cF1CroIvXLnybmFd39adcD3aYGJWy868YsGwMSIwhMERcILq88ERzZHMbsOhCjQFtg2mXnbb6XjL3K4SYI8IOPzXZtZRi2m7ArMkaZl6/ul8RLpmT3z4HHWfyTDvI/5Z7ubk96xHOhw0ubG9xrzP+U+1lgyjfpvI9qCqUL2wqOPGNZq+DgkZxsQK+iSF3ByKfSCGSOoXAlLyNu0cp/nxBmvuu8S8h1BHGTrNW14cwqAj5grydvEKADcXv0J2jFlhRVvQz+iZe+FFuqNmuPqMnm4NbPfanYTyqpfOySsgUsoxDfOjW1B/NP9tVqxmQZhKpv2bPq2WOVm+aVefyehbKYVjQaF+AuY9/1Sv+p2UGuPo82yGyRrzHwpva50t2lFKoE1epuiLqX4qEv4Hf4iI7rLoWXcqtHPa90IWeLDZe41vN3aPu/AOs3Ya7eyd6hGoCgT3WuGeqBWTbiOXyv2qa5l7p+/FHfSD9RcrS7IVqhTYDC/2dArlY201SH7sxfqKMlfyURz+C37baAWrzoHUAZ7Yo/rD9hhnOXrTt9dT5EL5ov8ndJiXBIX5k4PUKpSIC5xf4xtOVcjhJ2lTZD7IZ4RJpKkb+P9fiR+ip2oU7J36qfVZHqWfHDbF1J1VzSjqry9cwYoNTY/vJIvjy+3P9syDcSA92NxmkhP07I+mmyO5k2AsxLEYmr6INBaDM18UeViXnT1QD33hm/8WHhUeBBYFeNpgW11vSlX1+ZzMtPLNQHPKRJ3JHihylx1gP0i1By/kAWOl5QPgNPkS9uuqBncZF56SXkk3SztUry0Eqk9fEjTzywjwkNJCShxHE8u0/tmb3XQ842GznYY/uZA8kQ2L/NmIJDSxSbt47bvEqBpiHyboVz/aKLTZFmlW+0t5IZC9RWoGAVL/fAo7xEQ3LJ+XmPuEGg5w3QA/JuEBAZVR/x2mG0/aNHI36/A5CXDaoTlGii/c+71tMb2uI5ECGW7gTvGHOAQ93s/TGHCedNi9hVOwJ6D8IUDBQ6LzYobrZ7k9Gua0/PXnbP6OuFSkvYUqQevv4/l5jNSWLJ0VyxeiItynehKoI0LsoFPJGM6FP31G39Lqf433ZDMTCb4WVyY9eYEfDxpHB0Yore45K2yIOChnScYcCC7uelb4lSNHHLqD9lhMtdKH+FZKVkJ/BCpuFvmBNw3Y5PoSH3ww6bOchA7nmY1yAk9PiNEGsYJhpWbGcLW8VMGKUZDoCzMubLNltQlseAn3fzKUH5y8WO/37eUyrzFLXCImBGCqq5jrzhsntctqD3B5TepBNEu/lJlftMhdshqUq0qB1HSe2L9KroJH+a3QOXKc1XD+ndZp/kbQixRD8uVcVG9RIHNN4KscI8On7smNJFZmGfjKJCU3xpYxzGz8qxerim+YW36QBcfAAexvSYwXQveRYZPG9pc3Jti6vNgbtuhFycbWSUUl6JRNX5qne8Yjsv9AkedxPBwbegaGweCwJO7ody8FBuWlcQHdQIdfk+x7lIN8xn70y+i+gLRflBZAyl0EZ/S5U8Ad3VnNzhJ68Q3YBz4CgpuILBs28rCeJHJhAOMIud2xrIpobKG3p6NBrsOEV03CRj4b1KPXF5BIZvpwbP6PsEoJeWb8hKOe+TC0U0IdKIiVZWB4H+RetKGCk57JHi4AF5oOlCsFnEKXy5ywakZKHbPzy/mRy57DDNkedTLWQqKEssG2jB8HuU9mdUVXf1p/jumHp+ojEAD5GF5EBjGTBC24SA/PoGd3IWzV9IYSIoYvQ44qAfI5aXMPamqtql7zq1lp6VVA8k/a91GPqXV8V2LJlTHD1huNLbwQ/pQJupkQwFMYvIzeeGbofdv9Qnskd93H5zsSSZ17kUBuN7MPbbqFnV3EKdJvlbDdXzzezBqkSARcqqT29iwTubAf9+rYKuIwiZdqa/yW9eWvWXYm9wayCFUmYcZ5EIVeY4m+Rx8Ytqg30FSrINuiDbnONzq5NoOXcRmPPlGvweZ0e2ewqqDmiNPuFUPB6BpyPfvAskhYTa1BYtIg5WBZGObJg6mv8hEvqQTJPLciRJ2Z2vaK5ZNQZdNlG2Phml2kocORmlr8m4R2EQo8WoKavOdOxwTT9Gun9E1CAgQDlPOJ/GvBO8rW0o3oECfQvJ3gCMHk0g56d9zVPc9Y4A+w67vn7bKItty7k/eqGrw6zuxLGy+PutD1ocLTFNO3EUxiEI1/u8kPIBJE9TVMfXxEKze/Evnkirp7LJCL39osevQEUOpJr84g6y34rQzSdupMvOCg1ST8huRVwWB6VRY8tdj8WA72qjteBazt77Fc8BCXKW/yEjgy7fFoupCbEjFp9iCY9K0FFeNH+YusfH1RpuI0q0L7QjzpSF2mY+GHJytCa1b7RcucEqE5e75hF4MfMMVe76jvnpMRyLqmM+RTWZSZERKbFnE3C40XS9bPLA6cJu0j2R06TOxuKC2WCwTGmABkDr9nTBns07qMbx+7+FgAtiqBj9i+VYSiGTwdXuZNDy8GMgt+tbsWdEY8XT7Ka/IE7Df7Rj4awKk9XYmHQ/b/+P4cTs1xKXMLh8yYqB2fUgFCJJRJU1h8YYuo7c7waP2Nmp10eXkp2R11DHkT60eBUMEGZ7M3GZPy0108PePlbM5eOB5TJSHUdHkro23JlgqoYZomshC+U9V5Y78vbUgryGgD/PdHUxr6lZ/NQoJ1+oGpfooTHwdtMkZQlLDBijMlvAIU4ibJnuk2gq52/V7l9tezmeJJzRzkEvSNWOb5VtgmJ/XVbW8J+sGR25vg3PXqh3DUgQVbUfOGQYTbvG0iz9/ywUGauGDW8FvXLj49kp5jZERitICGShUAfs7Aqx+dUbCJ4FsZeF1umjpqa+5ZA0w7yFLhl0Mu5sR+vNYKNzMdGW/qdscyJBII2hwaTjMWRS4kwRlVU8xJvd50FGAJPbAoU2VGSbJm+kcXDeJb62ENwfi7IapDK6AY/px36a8bhHTSYZLRj8OyUUPyiGGst1uDo+hldSQY0IJhq5wFZ8jB1FE4LKkJtZuYcqxSuAIlYISWjxcj2PFa/WuyfNgHp98FFuZo5TM1xizmY6WQDlCgMw9hKJuIAyXat1rWY7Iy0GjVUqojqCGNbtbBmNql7kr/IQlZ1gTUlLbSRXhcIPk2ZSla1bqjzYON9UTQ6AFMhUnVdEgevtr42LKdZ1FjTYA/6QgcsDgkqsxauw0CKL7WutSKqsiPa3idMomNS+OWdYiOWeg1ifaZ7lMsx3TYKQfzGzAZQqbQvgIbbL3XNGg+AJwMCAP7SyYoU+D0uDc6nDQEyPMUYS6e9r9TBFdv6wiT41Fej1ELJzUYBVdSIoLo9P3WBdHhsUJXvRFqPH01q7TYjAtMe3J5UFJF5N4LZBNcQ2BO3H0wf6EV2dazCXmE64FMpN05bhmGVUdrTU67hSYTzKcS02ayt63wbN+STNO+ydFdMHdyCrgNjC6NaMLsjSPd/pNuDYSAGAADA2LZt27Zt27Zt27Zt27btj+10iA5ynP474yk1O6EwA/vqyXS2DZMngX6U9A1ODcpeLFg7JxG+ERmcxOjsuIh1KiEYLv+sBHHd7fuLkFEiPSoRTaTjcJ0Ph18eztKTBhCKOjEK2FpwafLMZkRUkw4E1njUlRze8MLJPRhQ54yI+/HoxYb7EwuAL615fR9eq8TzGmLBAo6C5u8bn98Yjyz1/polG3JnQDaHYVip1zgCoNxsC18ZhcJ3CLD7IQ1U0YC3qSCj/BlMAudJYN8gFo21rhbgrFKxVwatVs7r1re5AhoLkq1CP7er5GIU7KUMUVkAxJRMpTW64OCKcHs2OoFjZK4gANrEQLpOTHOVMZkHJX6NGFrIsaSF1wnbCnOvTzOMnp8M1NGhcRfp92MP9Clw48C6Ew8luaITV2a0CDkICSo1T7Ow7pusrCTAazeLtt5wH43EFJV6+I5kTC8y+5KJQ4sqWj+3TZe8hY5ze/Cai8s7qrpssBnnewIxsVBMJeikddlp9LaWElxuSemZz7B3juQD+n0a84e4rmf1d+EbIJJxE4rpXVBzyIXH6R6S+qUsLjjSK6ygONMX536KRwNbvs6C3XPtR0jCTvBIVOrnWCvg8iS7TZhJPv6NQxfmPdQDDAjsUime6nTFSdD3cXjFRdXhEnNjNoabdSi6EM7gCj24DxYkwwPt21BJntQuk2+r9T0dg7GrD42CWBFlgMZ3Y8JTwXSfx4vGiXoyQZt9hLdXSSIPF0sZAp6MCC599vX6ROgl0iytz4T5sFw0ImyDOqNidPBCA2zDTvHSLt6uUG7ADAIx9dvs74RHlF5IlzIZsJOVWqhve9fkx2wHQPkN/Stl735lkPKeuMCaQZ2edT3GJFQmoBakwlBk93hHZJR8hJnBEM6IFtq9DtsZm6xmaw6sLZhy0asutr4n9qNgUM+q+oITYit+jJwJZBkGyiLjeQ7F4KDMyGIjKc2bR4LE7ae1rri5cf+IRVRwzCmbG9ykWqyZEnciIXKwIEKI7m23MxD93G1HaeDc8ojwsdcOPiEeeKyKnh4lIWiyn8SuPHMqRJoroNuAw2FkUPgJBqoJoldJIWqcEikN5ZY6vrj2md5P/QawsQ33l7IHOZgBX1toYW7qolCCux7lzTNVumqSArBJB+MnA3VBUrAb2gY88qUm9b9hbQ0lU8HW0Qv8aiwu9UKTKp1Vj6cxWbollZNzrpkEZaGlWjUc5uDgKoGxujyoC9o8reDQPXz+VEFPKwBl3iyuElNz0eAFH2keFmn7i2mLF1ihqci6LNHOvDiEzR5Dh7DHC/+DDISixSs06ynpnDutTXSmJomlFaPFKQorIomj3QhB+VnWPXHYUhTNNNL2JB2OKdGLcsoCq3WoBHfHbofMRI4PIPiQfFNbPD55EmOlg0PsIrDh3v2NEXIkk8p5SO6oBvpQPJ1TQZndtG26YikMkmxXA8N2sWfzWGilaKqH0BJsEuwrGlrnGNyWtgS4c17XApUya6GNkwWel6Lxv2p2nJXNpcAwLM2DewlIXKPmcUj0eUBNGOq0GaEK4cJbijC32cJGvIV+iREWLvBmbuGog9TicVAW5jgV+jOPTKCGGWxodTeeEaZXmM1asoXHv3vEHfP4SXjF9vExBjQ8uLsVBgXNXLWZs1LHRsIG9j6WDBJy9djWPlW0H+D9J8MQ8zlYte4pi+692QFGh0kRRaqoeZtLtK1K2hzVWAZtgvrur7ItFujLbH0Z2A5adBR9be78Y+6jdGACnIIIJbYTuu+DzB+7UhRnhpE5pRv0o6IjIte2MZtuSg8PTzq5S01ifbUe8FI4Np9xMX7PkuLXWFcB9UyuqOc/gX82CTOJSlRZJw55kJZMW6S8uFUsvevvbHtpNX2EV3AU/vE30AKHZ7RPyJ8midaii1HBWmZZlrYQFdO/tqKnLlCVD0X4DMfmCPee/ttP/aZ8S0vvGiLVJvH4h0j5AAi62cmTbjVa/VVkSdrM6ABc1WLC5qa0kCsfQDkOCqzX/qADSPA4A0ypy/qG2PLOikw3kVbkZjPYcw9pnGB7PdF34/hogbHywfqcmMyUUs4vpee+HX4uEDbr43yXDKQyI2LsKk6I0pCmKehHAIjZWJMLyv/GShYHP6BwsOst5s4dEBy7rDrqEz+WB6CNxZD/pAs8OQyPxSMNtsSR5Br4LgV0LdKZjtIUTARRBkmChXEmMOB3wGC97oK+I2YSSXRt7/tvm5L69nBwin4C5iuKPLB+oyHSQBWV2juDWpk2ZuPnnWPcocOnUBy4IgTRdpPCpWbMwHZ31zCuQfkiQ+d6662GpGmwPEKOIzFwrNNpKWKCxTVJoeFS7ILJUX0HY4O30rv+W2aXfWbXCEN75md/lmRkMaI2DORSP1HKEydAhh58ZiAOLvyqPOh+YPyT+av6EMzQlOTD7rVtAGgAUBxVpiI6ZP4LNUnJdVUTm8t0lotJthPccfkaBFkN6ueXC0HL+1IBIHaH07JrRxheMXRkJvRA0C+HDt22SzAcGdEuVlvezFLgqQ+hyuJij43XUEpNCsi46lJHa94m7/s6D90BeC3rX0zrS9znUyo1erqe+ZaNjvTyAjCxP1ZFWCp+1c7yljhp4owTu0qQik3gyAsPysLGjl51amk8e55FZgkxd0EvvehA+Ojbhxa9c7SenBiUVtm2q6efXHU0RtP63F1SJ45qeBJBhh908Lgfw80V1/k072gd5oS3qivqwGqekbEY1zNDhTeW/8n9fkNXnR2KGcn+tlslCgwK5GsLzOmDBNHenjskRVqX+YU4krIJf3WvPQkkvGolQp8u1qTE9nxjQOstsQOq0NU7WxY8V1X/UsCJ7eHfDnyo2mTrwCM2grvYjEtChBDU6pHTmvOvKYp+AUioklSo+kfubiOfvBV4bSBmjqL+X4mXP7ip06QM4DIuI48+GZeglXCEfuS+2gdr3Ut0C7CbJGYslm45CNlPityopQwGx6RQOCEDoZ4atwP9yKd1NNb6b4KxmeMPKwf3s7OXea2Ui72P5PgWyCoOUiEjc9WaAr8jd7rmd3g7jmd2rgXlQPFQA3TUOUE1muhO7RDJfI2a+bbqFaKqxlPKbN8ZPibRGwdN6evTUr3jv4rvtQMgA95FbP39cbPRP2uzKPT6nQxY2UKjdBxg6qU/JCNpw+XcOzNQtBeZbn/HZKxFd2lx1fNqrTg0C9Z8y8kRzFzHnV0ELmSlNLrrLtOJfoP8C24Nc8gRarl1jeWvt0xkROcyvuTh8gKIuDH0CgjGPLtNCc2AhLKVWp12TebYXnwhCXBlRVueplFWSWqnkAyH8qBoCRPeQeFOsytDrINbZM+7nmlDI8WL8Nv8WWvjTK7hpu6jb3ZnKA6lLLOMEQ6Nb6YIEjcQTyn1B/l8EAMuh9WHIucrbNpDZvhfEcHzCR2+92F6hdIW7f4GxVmWqutz9pKg2JBRaiH1YEAUHj1uvZWrv/qaxHoirZeR/nHNuD3QpciJZPkxLTGTdg5qSBRbnqEr5YVbTqguMw8qGJpBbcTAmBR3fikCok2C91OapTVwMrwucexmV4Kp4iY2ExwyG1Gk0cXesMhHpBpJTl7F7M/MG1kOqxvBl2jslhk8UbHMWq6LGzttII0pTW22sH6Zp/BjAbBvRjl4oDH2W3sFo9vsVnNibYAzWUUzCbvCsi+5D/yKP32SnqtTNvD2OPSem6Rar5kgHqlazqgpNYVm3qULxQzdeBw7t5cYLLcbktMcgd/VgbhOoCq/lAiduBq3C0ngF3x/lelucpJ4Qx1bnVrHGTRUUom2VTUTaHcigMqGexHZIJp7qafmUk1Z9K9hc2ig6cHg38yBP4qRYLCDZK43omKXmoY8f+bgjtlIxyz0cdYaHf0WbN23hWhe84/Qc6TwH4y63nam6fdqYufEMSRFDkJgOr1Mz4Rfi/kE6lWJ9CRbzBNJG+FhqlOHxLXywGun8ayDsRxA4j1PTTlByhwsRL+5UJP+rog5EEp/OhS/2QIffaREHpTN0pl8oWr2GCtA3AAkZhBWq201qajnJYqb3COMwQ+bTl6Mi+Z+T/ukJroYE2mkuCTqTvCyWCb+EQjGq1RTt1t6L17M/V02IKbnzxzQIY8MW23q3Ylu8z6tD4W89+4OJHRX/XpsWvElHHxY8B1K9aEh7w4ejZkNOKWmnJahBXaaTZGwoA4YpazUgjtPB7j4teSA6ZJuSOveaQ2Z0j76E8fneMNnLKHXQe1p1XDkHZH+DrfFVad1H3SHEUlK2cTMP798puE6kf23hywzzdWn7O61OREB54IkVdwl+H/bsGDqUAWs8H48SjfERNDOXeKGXP2clV/NZd12RJNOlXyPWIYKs+8MMthqJR4VZzKCfHLXhmsZjy3qMKYLEhl/kGZ5QEK/QMDyX5ulQ/9yya4DRGKLpIBHxHPkRBGXF3cbtu/AXfMQf1koXDd7UXmWnjnQjpAEHXZSsFOSHVs7R9rqLncYoM/pDt5tUxZ9Tk2JfTyr5mDCh4BdTjgQxAIU2HkMraHD7glh1HGcnaF6nr0SL5geJrJosgJ6BhD1R7S5rT1nWvuZtLjYQBDcesJfQQcdfONPmlvmu4LvnKhCImZrVP9E/ezwcwtg9KL200NyjTfada99xhof8lN1FoW4ak832xgDXlwCo0GMVitQG9UJrZpkPTXC0Gcyu728ehNNdWrauzKZ9TiVPjXfaXXs9Eoy/yIu8ZcNsB9lwXd9ENj4NShR0Mu5gUXxBW/EzPh1vfLMNTOXLash7zbiz+DfzsTHRHJSsED+MWyRIJalpS4sNcRvHKzbnNHSMeiP0aLcWvITzsCzXYsMWIOPkWMYEPk5nE7+ZpvU6ylKrh/WwSxVcc665xaAYv1YD7HI2gD//ogYkKYwHt1W8+Sj3T1QZaj0IdT65Q/c1RagmGdUwfftXxgU7UhcyHnGuaKIo+EC42MyexUM/2otJnzglRbSrHbpajKCnIFGZmurnJ6fbSoacGzD0PiBHr8sg9/Q0yMvcZ225q6a30OgYaa52yrYt/KhPDqUEjv0I3NaBOlEHMxqZo8zxKMaVv1aC56Cl76xa9cVzk6W0BxJGV9JlAXF1hYyHNP7CQ1wJVDmX5t7rQz6ERZOJC+kDrkneCbzIofyIac9QVR5Pr7tyVsbhtjhiCLKfmZmP2l4D26IYjxjdw5W3/ZRMBEAaK6ldj8b1/YANGm7s7MMZXq/QWICmMRZlauwuOVLyPZvuIbTxpORBFl9yGpEzjjl8k45O+dcP2Do7X8Pjcn3RNcQT+G+VkssnUSBBfn1S3eG9JMpl5HIHp1T/GEQyqz+XGXC/dhwQ4a1rLBeiU0hDLREyZNCbhAJad5HQVA2aE3UWae3qs1MhxCUeL7sJzngCSJcB7yCKRM7zWn479oDhhlZx2t8s+ufTqmwIFjMU7VGnwsbA8430nCZvgULxM2dv6h6oInSi194lYt73p5goQ4y6bCmCpHfAnzBx4QPAbQAOlwWq5tWv5IEAWxDeIKhcSZplxh1+++2J59jn5LNGWrvxMW/hOL0amvJzE0SpODqmGD4t9QXGebsE4SJGCu8DtfBcfGLovjxN5oEqHrFnQs4ys1T+HnY6X8N4c7bxNwoxZ6ckQHy2pGGY6poZn+qLzFPgrklhtFNVdSmWZWfkq3K+w2Qt25iEUpcXNMIdSz3V+OmLMhLQu4dQGZ4vPmMb+6llKe1tjvo87jmUl36DSbymDoZ2r+EiYv7m9NhURg9RyHYYfeyLGyg1pwsyR64IdBGDMNeR4s285iDiXEOdi13j1VNoRZqL7+jevGZL9vDviw2riEDHkweFQXQ5wACfsGkpi2bzjINSYGKVadnA4TqDYM2k+QS0xS6CHVV5S4oeFg8W4KDuizYiYtSAZfhwG7o0o3e46C/CE//ZQt9yS0zvckV+omk6X7bVY3pfoOfH7SUtn/Ift8dLjya6pAeGuYWozEQeJffr5siZj52ogR3zegQMqcEIieeUxUMJ1GtjMa+pr9dWUFLePqJqzMgkk8FevS52iMRzfXZLCgjbGjZyGvejqMhu7u3kZ6tyKQTVodeECEacB0gI/52gTHpPWfBWxSdWHWr7lxA3m2NmAjPDajcEcb/9FdIu0FvdIukL3dYwnJwQP2lyWoPY73gxXca0vWoWKWueKKVFxLReuWIGubiNL/2hyxLDrNSsXpeoXNCwW3JIOOlstfY2eY966H0ms838fb+JDGz79AC3AiA3Q8aGP8hA+6y2gg2IGxFRMnNHCBIp4lpqnAazJl57uvfkO8S3CvrAnlRed7lSFkZFCuYSyt0msyjWp14nlELbHJsocJq60KLUus5YlRtejz+TLuh+Xs9+PQMKY4xiXaB6dxBi6NDrXkaMC+q/+A8EigtePtnJtmsxgEz2qeWbl4EvwnXVPwEFH1rG5lvTlC0puynpWAkRu/2CIgh45mmeYFvQSp63EJXrT5N2uyl1OH846hpNUxtTQADscJGi2cyDf1en1XNA3AXyHN85SIkugHAspJa99H/fd+FwPldGSV0/2dbMk35+aLDVBfgL/0aU/neb14G27wIlM1NC0ueSYGWW3Z+UX0oNcgDm1CwgZtNQElE9tk7JxRPf7Wpc/0vLFLc0kMAemra19ORJREkaXv7qe4fO3sK2zBlvm+K6TV8oH6jEDiw8hQdiHV1eZ1wI15PMrA61jGU7z8q67GaqQ2zPZ1+SY6M7GBd0LpNjVkfRusMaB83Qsi1iPU7bdJRDON5jKCkRsD+FofZvjBeyAjoadfjnozVeylkiY/sVhqzDQk77r7Uji+9AhfDAdNd7Fa7WtqJQwgtu7z++50IjALbhm+ZzDLb6oMATobZuohfgaosQBG09EipyI7nMiHAkGEjbaaQ2FruZWm7zThTm5v1e66zvgYOotGKOm6zFKR6a9/1rUHcklejwxHda1rmDGiqfkV+D/pjhMXYqcmN9OuiOsnkQF5hC4F5kJr61SyGc9Xe0Tq+CaBGBzYUZyaKoQU6VilmWt+e45Tgp8/XlvLuiX64FmdVrL+xEsiNSFDi1+jmHNqbwCUqOXWV4NsNl5h8pQGDQE4c8nWvXw7Q4pnL2O5s4g5mY8BZz5Z8K0QXSvVePgVzGZw5b+3E9b5V2tMNHVVj6LxoiKoIPX27Mlr1X+bZQO2Y4xnzKSiZraUBrsssT6BS/o4a5bi/SoddG5/q0Scj7SDTAinDuaEVQf8jyeXhOgpP4X+DMWKOf8Z3XdB3HjZrtvebb1xVyNFArJHrPUt8HENQupT3n3nqg7n1ewOqZvWLk9jMUlgXlvtyoQYL3cxdZTDLP/oiWCmsbm44Hc29A0lb1FZ4NFMKza1K5Ia6JI3Lv/oix2nZI9cy0tEzK9NCI4G194m5BdHpZnIeGVCS90GWf5gmeWGzvhVRbv9QBDdKn36o7IpZl2TdfNNNnclO5ORS0BE7pYW3FuIvIbZn+XsObrKcoqsjIrWIVpcDPazW1+XGM3L+mdsgUj3urUN5GaYv+M5XG5E9dxtwmzG27VQ/dKRGfgyVVBsDQtySMuxtnynKVKx4HWqJIYDnx+kAjPaTxLkFcGcEwA1Qx5xqyc+Do+AxP09PvGfUwKzmmMc/5HgF7oahLh/mucetaTQ1ABo/O71+SvXiAvcc1XnRY++2weXrNqGPpC6stjI7baXlOmCd68Yt4NVQZGErs3ZpGf2Fwzm0NamqG8j0wrMPLJMT01ZGyfgdm/hoKsBH+V+epWjz2lZiMrWElXzdJHCw5fcQfFRI1kDQzDHMPsbitUuHQnVkWOsMVUEbgAh2kPwELWEMVa8IWBVOxo9Wd8IF+tnt1lB56zSLG3NXPodZJ1ySI5DtLgEMVRqd2D7EkCkUzof+VrxeL4xn01hM9D/vL7swTNeGZO76ISjpDcoRVuPZO1UAXZnZdHkmc0ckVDED2HUEGFY9Mr41IHiyfEFaPaLlpPcq297P6JW7PCXrjKUIBNNWq8wVOK63xuMJB4yJLIL5J1hwswbzr2ansUV7EjA2EO3OJUTasOi4eUZrtyx3wUzuHudGeVLzn74wY1NsmTo3gxas6MuswAj3dhQIUVdP6v4DKAHVVExw0QSraG+9Athq/0h90Rc6jg67KVooUeTa3wMJzu0rv4D4WwXxl50rIulnqD+5IeuISRjqFsc8+Fzdwhw6PTs2cGW0yT3XBTA/Z0Bdb4wl2a+uUQKx7lkYe8wfeEtgwyKe8rPrnjs8Yiv8CKPRTLdM+XVYfevZJDTQcMXa5qlbpPH3Q72z4gAPEbkzJK4CsROPy5MYOq8kF8zVA5N4uZdJaLjR+TVuDjtzRciUDZVsuspZd4gPqU/8lQ5+AdQl3dguQRe/+kDNU6o6TogCuCkfaUuTVA2RXbSmtkhwM07M1TkYpp1yYXkGuO2RsEV+i9FX1vOZVlbVsqdp3MPR32JPNngt/1a6ereb3m7uT2BYmoFClUU8Kp1F1DkHsw1hNl9AYjYlWtzOE70yQvjI3VyufY++oRY7FCJ4mfRC6oYmD9ScV2fL315W0qcgAY0/nIiwwcmyxkIt+fYBeTTmOXHS7uWzYURCQ+Y0D5HETOE5kbDqav56eFBYymJI7S8Cw5gpcbEC82iAgZLAZ1oHO3cViK069lCKuFsQa4SUBLtZVBOeNbzIF2hnY//23zwByHSWbJTJX5pFhx6efAPQ6AnvNG41o6k6XL+gZYQOEKm3IaYbB0PGHNiSYEilvoI4zd3OAfR9CvILzIlZ6ctXnjjnQBggGfu3yhm9xR5ChqdC5HnKwrGSF9xknB8QkXUVuueD8SfY4Cc/E2ZjU1nBzVW0TxBrtOgkWwo7BkOec/IkCnfucFm4fWshsyzoATjLXnF3nPZZ4wth+ClxCU3bbrmsUmAPNs56lYlWUOI5gWGJTESOz0GHcsEjYvo8w1uRyvfyC/Xrdn6+G9nUL/IUAlwa7eHwhUb+Wu3ePPfifTb/8KaXmT8kY+AgTBjbYBSQNX+cYYbPjtDfFQ+A0AcZelJpM8KFm6TV5tVxFJWAJ3Dh216kPXCpKNlxu71NPJaCXASrEuttO1lOsvucSzu3RKIFGiPJW/eGTLwaFmbIw1BTo1MnKMOqxnGU/Hk+W6CIkSSXW92BvUuJxG4x/ogiXHQh9lpiFltdUBnxRCyu0I8TeOqS+KvmNo28CwxB3/ZeSpi/FljvAtJQUT670TGnxRb9M2bDdxiCNd/fXaOpIIMWXq0zyvP8aYxwPQvjbjB9EIwkSWOrGgSwTb8/i1BRDir2xZFKz/iN/yZoDGbnsUXXEbnQFHeY6e7y/FPg7SKOxBZNBj6P7oWLgWaIL8MgP552pHtghBgE/ZW8bEBIomaVz3s8lZwUdPA284E7f3V6X3wZecwLjzMCkvzAfRA2jXWbnCv4ofOl4uzyxCcFcC4nR3sM6sJR6rbDDREvpMoUQgPYrMLKQDbCezMeQXm1uM3axhsjC8sWs95mCPRPDxEuhlVOJxCfPh3fQuFCwMv4WqR9Z6tUiASeBAGoYvBFYiCYaOENj1yxNhsIpcH0Rl5NOgxrrMXggejA+kgOn/XjLbtpEokF30Mu9/HRoLNC8Sr0zIyRea6BkS1QtevAOd4k4YeU3Edk4I54xyya65Lc16hRZYRpxQ+JEFML3JaHnwXORpED+ExEwfwfty0l0o6o6vBfhr5rCwTPutsc+QIaJBSdLwsC1w2q9Hyt5S/uQ0X3801LXOayb8GBT1njgF89zDPOH3vBJwF/PmJVor21DfEH9ph9b0qHYkCCfPGK+oZqOFo7MFc2ZX2z2I+jGRd4tl0YOWY/kp0y7TC8Bravhj11/mHJ5vwpJXJPLoTd/mNUt5Fr/cNiwgX/rv+EBpVwfk7uz4vkc16kdhWyWrcAWFr1mggwYZKxeuUD5/kssOX6sEMlKz6zG3pNHStxMgiY+UbWnrrfM23OTQwVT1640BRqdT6JguBcJh4mr6W9vAy57wfE1Bpw1II7DdCWHbDF0h3ZBI76pInPyeJ3B8Dtml1oWSBYX3mwReRnDIt7sjQO3zLvb5tIUNALmjgQdL1GUu7ucPFocU3Xaxftr5TnID98MPcFsu11/3tjh3MVIhXTu2WshdDJ926xFyynZOerfHh0v8gFq27PVNP156KqXVW+60cBuC6lioQz48IKjjPuItjrQ3VBEmM+b4mDRPgwAVFAHd2wE0EgZOGYlrc+P1zI0PDvb5DzdS8w0WRoAg7sOurH9eu/NbMIztjsifkMXnR0TBxj9ftJc4094qPAYuzuuksBdt7JjAoZr9wR7oYF8VR/6T/oAGcNDBF8zImf+oTCDyV7F2ovaoPWUZHSUHx0+MI75FVkrm4ZJVrQFY9jR0PGDMxvaMIUFg3f1eivfHGsWjZdpUUV3u/MbXTK8qCbSyhG9yA1OALn91R32qOV0vfrm5p5DRBpxFTO9T7XtMYyd8naj6aMpd4xM/BMFRt0ED1AQAiN5j4L6HPh1eFU6+/QWw1lMgBMLoBV2r0+nPsmWGijtVZK44HrZe7P3qmin6smjT794cgdgpCEt+J0f0BWWpfOK5xeYp8webLeAZ2VKPNH8wWSgHVnq25obx8/SfQUhcFPILFN4pPbVNe9q2d5p7AhfixXmDr3xgXt6qqxjHvkVumK4zqnbSB+UXVShEObdsmQ21qbVtXjEoD+i+ENEXRpOJrinGViFdS3n2bxH+gV8BclqGrH9jGFTidsiRuI58sT5M9LKd4ryVncFtS2+2Ww4tMsO6Mus0AqmXUeBjso9VPyIJE0U3qcniqI6CYWYwxbKp0tlCLW4Ef7tfyCK+WPMxuMdXFXL+EHR1Xc51ag/nfXjyLqm9vr3VAToQEVEd/3PBukCAQltTMo02hFoKGIXYV3DFjAYQSh9drzhjpBRQknThm9inu2aWCLzViQes2a9KV2mjR9zXhiw/3tYuZGfbBY/XthEm828QsLSTjPWhw0be3mKJNpZe/1uuR1dp5UFvjE0uXm16DQpYpfe2LIWl8/l8bW1ONaE0huVc5hH1hV7DJkPAUCtBJcV8KS9YnGlVwsUFEZV15P133AqAkrqdXI8W1bss6RqBWI5jvWJqfZAJzoRkjIJIwAwLBtShGBtxsI4R9pASIq3dRfWUGvCGgR49RdJa6dfK1inACSy6olLOv+CCLJV91OgvaIxFmOuI2gA78+6O9IJbFgpTLyQVpfB4M9URqfYBc0yXLl2zlnF6vKUe3jnCQbm7XCT8jqi2+8Jw0OU4re1FGw77K4AefogeDI8p5clDo82ysQqLPY1pO7QxwkDO9+N3XabtZ3UF+/v0qrTcSZURR+OfbPezpgwvgIkX9SVMw/6ZR9FrYtMN2eOMtfUqXWVAnUiHutFEciyTFDnJ/QeD80uyxOlexoXaposGHVAo87Y4fMT5biC0eVoXnwh+VuBeaL4Eq9CxZVApMQvoWuzGJ5x/Vlj8aorQ+ixMWlsxQFBEy590F+7zbRAGw11eEaSV/2oCXiokjjHk8w0Pom2RX4cP0lxR97X8EV2ZK20pRy3oCKMNW1wtoVOG9EuQyZN0Hr+fjBxtc3V7gVQA037y5/05g1m0BJ1srsErc7TMA1cXhO2AZkjnwJPaCB6FQfdub3FNvXyhgqpvVump80Nq6KfFPBFKjIjsRCj+tgGsg2b4mktkK/Y7VPRQJAex2Or5gPx+OO9UOrWnRA2ZHQ7gO8bWwGA05oi4Zg55VYfZntCbQRihNti9SLWP/SWvDVJr7AmijHMwUi0QmGAnSOdiMTvHgSqLzr/Fa+fatlKNmdsUtJi6ELq13K6WuSOIT9VrSaxL+HNULTJPeFIjfttajY1KYpRs1PteoqRncBOc9k+G5YlBkZ8cnqxdthvGekt+qu69+m0p+LbsDT3tbGHtYl3otiwhCg3Y1JegH+gKW2kD/FfrCePcSo3szw2Qu5ViCZfx2HIPLhoek4FdgMBaWmLuE2E9aoWFb5VdisEBj7ppgA+x+PePwcHwabZg8oMT5fsujtkDzHy2P/OD5Tkfyw45XY/efot1cIDrfgIkUKGJ+zUDs80zlsyuI6ZnyHLK1S7Ubv4totXxisB23x+4Lh3PrhymSDOCsUEWOZIUPEZe5dS02oAT671Fs49Ulpv9A7TphL+QSeEFUmumMdXwNfdRDD0BnAgbQTdjTKA6qbXe3AUbL7TwBIv4ndyvFQpGHDDbTfoMgV5PCBp8n15jgJJj9LaSWQOhxPTVo3848lqUFv6FTQkdnPUcs3ml+c6a7tPxueuzmcM60ifYHfYPZRZ8YIMAxYUk6XiaYkln7z/yLIOpdsAf41LMwcml/QdDRq0uPNxFCtAcCUuk51HFoRimk0GBPUvBkzvDjLpstRHmUxnwfJe+fC1/YVS2nw1LpcreqstU8Grus4gwEYbD5dU4CveMcQ6Ampa2XIrPo8NqwnrQkXpDhq9qkLRIB03w7toM/Tn/Dln1hFPlWiO3u3MdWMjEaWtCcFNgg8I9iqHJEmDcZ9tdLPBg1moU5244bBhA/PZ5DRLe8BscMYvn+TYESiQO6k6CY7vuyKTRA4y/JKHMIiYWZ2bR338n7yKnMn04EWkArUSuc99N0H3rREtCbOzxuYF8Hiu70OMBxqwxQA62BQXFn+nH7YNYKydT8JYKXUHrEgBP313a1s79d/eL7fd0idIforLKdqRKrzoy28naqT63bfpITjNCqBZkajWkAgRNeDUGpw8WF9UhiNaqj9gsjrvleWtZyk/VLKrMxYzsejZkz7aSPJWycPA6nyDm/6UNgOXLoYVfdWelu5zwTeRSqVL/J1hMJ2Zz8w8/eyF/wS2sOGb8AqH9vuN9eHNKMFBwMK3iVTDpMT5yq/hp1fBpVmtRBEccWXvINOD5P76gTTD23/fBl6pjJ3MZuWCrTS+ASMqRkXiKW3zijiMgjaoe0e+Hi6YMOT/mlFhNm7QJsSipJPlEUHvQHb5/CzcYfeRLVzC/pwy9JakV2QblrEoXnvZmIresXTr1l8hEQaBmy7V49elyYtq2Qw9zRZPOOhrYZ8y+vLdUqV0omgJq7rsoe/wqgecVH7fo3Edq5UuTg/Y9lCU+zIh4e3SHGILQrUoyHOrj6wYLOwxd3Hzurdz/D1Bk8rXO3t2AzpBH5DvVheKLb6uRZLka7FxJKOJ9gMqDksGDATZejVLy266fSCYkG/La2Fzzohd+6fh7/Xzysn5CQ9JYzu6ChncM0DBIOUa6keE4MDyLSYQSzdS5GjZAXH9ILUFSfInVwQw2OEqeSCKJTqJL6I6kw9UKs/EoFcCBVahN1ALeomwiB9meEFrwD+5Z5LMEF+iVT9jGiRud75uFXX+LnIg24pfyHuborO+uIuPmehQ0QvQBr+Stx8vnx9OHEnNGivfPi/MjHUoWMsmf6U+n1vaiUIvHgCA/VaK8TukiHZN8qGCAYI3ahyMmgOM5c1LQEeomhNdEv5Mff6Q9kcWmjGOUctqT6cxPZscg0aiLwa159FfITjTJblEgZFvPl0dba/ieqtaM7FbnnCnCsTGyS8yhmc0Q8AueYkK06KXpvXl85PKNlNz0c+usgmCB9mWfz4CZ1+JCwtXcswmBOOF8rvZhoUYpfyqq0Ydq3H296JN4Q1uD3p5BC4MarEvsObF9KvWWJFTHg5ywqfwupBibyE4+JOkY9Q0McmP07tBUpTVBVnMRaM/qOMY2TB9fVzcu1OVbyELHAFyO/FPFe7Zi5v3CflLM4R4whfEFkAC7fEzSUn+lF/vcsgp5xIXJVa2HDowJarEU5RfHIVQ/d1kRVZ2dMb2+hRuXEkucJcvao/7ZbKJKEK4aFhRDH98QFi7bGGovr4vCFL6/VaXuTl8jDOx7lgwTiO5nWrkYLQZaDfXRLSTZGieVaglnYRckd0Sevpl48vwJFA1pEZlVU/qAzlMlrLdGf95/1tUoAIM2nVlvwgFQAUPY+7X5Y1+im23x5a9Hd+qGFtvCzqY/Rv4LmxcHehEh+N1Wl+1poBOXk/RVwjevMiVByKD+OPsLc/sJF1gPIigxUVdhf7AMx5+hMkD0ihG/0UJcdeuNPd5Z04aLdXEDk6A1S+hsM7EdMw3lXJGZPhO7svIIiF1vdN/3IDfQvAnoeZ1x6PH0LSiBWhURZ5S6NBTINqrLV4Ag2Z1wiZe21IC+iPJi5I6MrmF+7rmOcuA/biAZ7rfokVvnngaHpNjqESEaIUPSX1eOGyYa1WKDf5EBJxd28m8BhVZN4onwBfPBfkK69qzFqgcC0HHap/HdyhVB0qlmh68mnMDkcphsFaJoP5bnh0oyE7Drv9qDh6Xmg0wuhaqFjApT9wdQywMKvDmRfpmgZPFLfYmDlH89GEsVK+WKqJ9S8rABQrlTMHzqZpsdQbC6WnW+GAwfcdviY32zk+m4q02IT4itACwfbbxbgqrjPfWGIHR0g5clqADo58Xs2Vy1RoL1SCxCl/iDEEnjAFTrkKPD3Pvwezf/QcDGCzZtbomWQnGdyH1hJe27plkelAYMSCibSG4PyLFyjKxvuboFqTdQ4hWto7KFaDV6t5/u7cZas1PRBRdIt2Q3rG8HFes0N0N0+fr0uBSh1zjbdB9yD9axTeybehbmjpiFW5rMDINDYqzC18SMRySo6UjxnsFRQQ/gTUg5S8V0gc27Z1aiXB1UqIfevSa5I+Auku1sJSRzhYD5GeqYvsS90nXAlKbodU6nDwN9WDlZyGGNfRU7kc0NrHHeRX483dqFelzEcS2Sdtgk409Ealw5qwra27rD7ClXgGsBkwVd0TTbi/fAlvB9dPHCn2ZVQUJy1SokR1SUYs9U3BuY4oEV9h0DwHz7EKornch9ngcduSwPf9yqF7VJsybfcbIYIZ011jSDsLBlIQsd5PFPGk5nkBzDg8SzsLKb4FaX3LGwfrKj+p63loJ4bkIhmH83abqNrWxJtC/wZ2+ktE7hY0P88Az/pGRnQbP3q9E5kMwHFlGUQcJ0SyakA9yBj3ztNulPHwunf7nbCa5U2DiUmJILHDYtkkXlro7sZqlK4VK4xBRBRLt/Bmjzb9DPI57rIzmrFpS9Hvc+SQzRLor+wbU5oBlNe446643J59ffBMfP0aqulWp5tFDVpAGUxVpwcz7eQ2S5GcbfxEBg+3QHfpkEXRoAF4RUDRxEckcHuoWOdcSXM1FY9xVEuUfmdi8p/brPHN37e/i9lkTxpu0flLa2hmM5Sb3jIWnIZs4mda1JNHHwPAzROmoWpHxbhx2wW2aAQpCuj9SRSDHsIKB4AiE8UknGeprBomtw/SP+YVinMIVA57FVhmWh0klX2yyi8RB5QXOxJ9Wp9B98WpOnaAakWpJN+8uGsxeq5RZGPkbclCqF6Zh5dg3F1RxW9Qf/AM9Vs4mUNv7EoXa+jcaIezrSxenqvLvg4/DN/fTFMizAcDNA43Ed7toewtQqSJlnLfcyY0xE0/1GhBYPAzNpDKkBqdtqJX7ABbeewghl7bdWJYfud61QMvbFrHB0XIlZ/XfztgJCfjc5JBbSKH4hacsSxdBgbXFcy86HmN9gHXb6AA0izXG0vB6FbFG2t11ynxb8k10XyJlY3iAWvNSQmYXmYrmf0VVj0EGNA4aBpmD5XPwubT+c45cIpyyyKB7y/wMmwblBzoOn8zXlyMfyRNoS2SIzmvazOoBnEMZLrc2Zia0XSGCDj+wiBqoWP+DeJdQnH7pQh919buhWTqQic3C985NJSYnAqXF0scW6HzXojd+SJdVigqemN5d856w+TQSFoHFWSvYC30DAzV9VyDQnqF7gBL+Tg3ws3akET8loBmxRjEAqor3MtbzZ1c4g1cEtVqxcjBX6LyhFJG4wdx5lNxFJIcdpy2qk4HxTBx7lQY/VT5HSk1dv7bDoASSACKq6wnUgNHxnUTbpdJDSyyd8HB2Qk/5izBcQOtrkr3ed7oJq6BFesGMaoPL5q4IOLGP7Q0UUJoYf2vp+8tTUB5LHR3h1KayfqwVF8FSWC3q+d3IqAqjo43EXrIo6xrVmuZvJbHQD8G+lPrZiQlSYiorQmwGwG1SOtRGOw1hQ9GzaNoLhwlJ13OXSoO/0Bh7acmRisEt1iN8KmvztnFaDX1dp3sjxldWo1u3hKI1FDwNBYtbJSZY+56pEfOMlmt9a/8lLFbyV+dTjy/N5FPJe0TUUr6T6ejNqQ+LBGUMFoQ7+1EjvGh2l6Bx8HzhQW13a0U5W1kyb2vWOoX/Hez+ongk+rEaoBwwBMdUG9F6wqQyL+oYlLJOwQKinnIYvqi4duDvDEgfqY+fsqBBhlLqxTa4ebU+d5Xek3DxhrWRi5cWJqQnKQ+Womo62y7hc0lADjBnnIyyVHna6lvjp+eSB0k/HmKbxNFGW+UbD55lRSYVX7huLNTheAo1jCX05K2trhQx/9wTzsuG/L3u8hQ6sDwBcABRtnYH6hKLk/Lo1lSaUWhxs6p/qL2yOw5Hja7WVOxCy/gosg9X5tvtlkp7YunYTkushm9fqtnUMPx3CDW3g7MUW+ygt6vqF03H6jKGDMUEGOZ/F/L1vyBBpS5hEuk0BuKjxigaWYmvYVEd2YspThq3NsWvwBkgcWUAaTgeG/faemXjc3XhDEs0esKRxpJF6hKhqT6rgysiSjtLTx1frkwE3SImGEvcAauZhX4C2Bessh/2rB/SSa25oVJqOtfewezAvwPPj+MzxvbdqD66eSvpjCV8UojAe58JftqAxWuPPciTmtXbEe0P8Vn8xD3J5JkeXn+gNE5s0CYAXr8TfdWMWR1R+Teyerxq5cFsFxyIprF/JerpTjnoIDo+zfFhLp3Wp9dQRf5kvOddJH8EhdTna/haJ41+lyH6nnjDZwgLCMTtsoB2RRliWvUToaDZzo22wJac40aJW7wylG8DDRVi+jc8EL9eBuOuwwoGOWbfMleN3OccIWQFHu4buR4FzqcwI/iLk/kkKM2TUOlMnp4rxTRyEvQ14avn6bcHXdlbTEgwNzadjl4M6fZ2I9fjZTpEkCucM8nsCB2G0GgbvwzaQouj3AvUiWujDJvX+YkPYdWNisPBSYCJK51u7X6hJWGUKYmyeRxtl5Om+uAtgyO/9jN8NNhPFXzQNSdQwLrX+aJwvTjwxRgHUN1lE8+pTeAVRe6B2bsvzFN+vGe6InbaF1HtUZZexQuVxqz9tgn0TLmHDwOzBft0NaA9PeRYxs4UZ2ZjgpdKi7abcIK3Co4W1DQ4yj/hR92pSFojXeIYUZpQSrGZSfKUmJVvHfwi/0Ip6W3mYK+ClwGYLxzw35LEyyzHTdh7yMwPM2nztX8QvY1/q2lzj0O/Yr91pxp/0bWHz4ps0Efrsn+1QaTMY3THDyj543dpmD0EkAT1ictd6/qLrcC8kVFlkUIaSAdLD0w3Oem2qUNjXUuBcNFk2ok4P92Ivf2zEQEREYAplWaXKCBnzqCjBAV6+OcQjm4Z7ENhObWkNgK7506zIC55ImKL8DNZtUv0KUtyg1YSJBZRkrYHHjW3fwNcJEmHojJFlXZ1bs+lHgBXsLMZiDXvOQ+pZPDWVJd0AOEKfVZmC5A9/44AsPga3XckQgJMzj8jIeU1k/Z4hpkH7xDngaWrXLT6lmiuZcL1hj4kezopjFzqn0w1mdPAyAPqknHR/CAChvDEhrBC4pS9xy968fyZOu5illnM5YLLLxPQhkJzgRDxX3nQQjqZK8FenM5HOJQhORjEdwmsqkxArc/IZUNwOt0IkkDTjDjuFE6rVwvEvOrwCzSqm24IJ042zSn2qHm4P9SKsnUGTuBlZv9Be8gpx/GMurI/BpmyHgNwxhkm8oG9p7TipycjY1nnt4ccy7Ci0f0jJNZzXhNAaHDxR0PgTQeLt0w+RA86RzeKInsxbPM5dizO3FmxRtLl+iBH9bpzFhclF4rBrgrrwVQx0lxFNBc8cU9w1QjG9dYh2GWFfjMMdSsWP2QwJGjGYV1+nlQb0WmK+JD810sTcis2XLUar8xmejj+bL5FvNjPElMPyL2LJ34kKJZ9p0KaT72Z7HLJTvbiP56Ew/5ibZ+otIeXkVDoxIlgtHuFNVQajWMu9bn7cASQLc4sPmigeYE3L4OuIcj3jk3BQkec6unYaNpYNFHv9tshpxK8fzdFOPTqCXMHtEqUwQLlOGxVinSG5V7VYJP0pO5FJq/lx0reJCogYgZXO9xyusSrTm0jYMMdERgnfazzp884mHE6VCvVsok4Y+4oKYY1UePg/jtX0mwFK8Jt69oG6VX4nD5pY1zhXnfNzt50CWVhQNGTZx5jYLCkvZ3kteozto3Kxa2jFkHtbx7pSkFRXd74TDjtcg2lXpagCGZ0c3doq3yqMzXKX/l3XZlRv8DAHaaufcGn9uR1jOYP70k7251NucNpI3h8/IB7ty1eM3cQpYgNugh/BkvbqViAt40GMNxAX090MdC+eARjkRVy2hMxtf2xIySNMro8O5h/7dRPj0kClJcFkKDA/YIvQ9dMjdfkcUwFZASUPdaewCPb4jhIT7K2xTe70S4GmDceK3Uk15D8Tu7dOqRi95lPCiQM+TAgldlFa3gyJgl7+P8d2N4M3hOcP8aaDgBHiY1WZz9oJHdqA+c40N/V+QI3ZfNeGQCx7pKqFZuanZtkBmbm72/0sZnchxT69/T2b8d32mmGu+EICfhl62848YzH35J8ZDnyAIA1qOgWWfiaDkazyZJ1yldAb0wgWGDyf1Txz381xyfkaV0QWpvniyZaKmUTxo3DIR6K7htkn7jvV2mmomASk+1LtlojJjpygVRG3gnKW3HHR3d7eF9edL+w+8kLNo8T+RWUzM8p10bSH1gnCUtgF3h/yXBejTz9+Oo8OrCfsh9UqJkJnnVzXeix5EKapiwiXMW0VFCCjKAXDt4KrKYsJI9ozLokn3ZxY8XIb9cd1l/hY5zzjT9Hm/Yltysaf7MO3dZETNQ4Qa8o2DhyRYVgvkiRIqm+K9R3m5UdwgFj0hFpfRwhVPJ1BkRBtoN8tHBkreqogMxuocnQbsxcvIq0RGw2XJ6gXmzN5szK8qsKiZbSEoJLhMTz/Z2ZODPb+CXzygATWOaHRhf1/AEyaAjo3i71Ky7m8TkwiDT9LFIBuRn83L6903qbN/f5ZWiRaz2m06UAbasVQrIF9NhgZfKIK22wEXKQxvUiCgeIai2k/MtQ+VJrzvbUfLfw2gns0oSdMSVSTF1USgVY9EuXWwCXe6riWnUBLcYd2lnEjPOgf1qRHElq/UtyAfK9VgMxqzQ7BVCG7WZ9yTr+IG1UNyTitSa+SVAy9iwyT30YlyNu/nrCiJv8BWRaaOJYv7Q3KI3R2Y2jPZdyAfzH59PX8zbZPG5yBry2meFIGUMVGlwsPpBsfoStN/CJp7FgjmjkZ+KSAzL1tRqNVkwfZXjUSfUQ9bimKrj/qVR1+kagbxP7LTwgLbRN1o/O72TfBMhoBn3WQXtCSywpXheL5afid5lmbK3U3mfUGzmz7T+E90KGZ04rupjzTWqgrOgjaMGgmSstsAOWOztuIKF9sE7YQxCLqqV7pc3UzSUjpCb3aT/GoLEKeXnicbVeur7fBIe6JfSM8qY03gLlO6UArOmYlEDWgimunprxjLfLZ91eKciCnd1xZKex1XDyQJJQvvGxQ+/7+u2ECC8GtvaEzfOknXB+3pPfJaMPZNF2AFv+Hu07swhOLM8/sI/eos2j5xBkxxI+39mNaDnu2g9kmJjfLjgpMyIxI8lDSk8sw4+cNaTw5ppKfY4JIMYkgVUqMPkqI8/aOR7ev6axfL/us7mf9UX2i2c1L0DB8fVLCasvV0RUFDys+QsuuxgHaMcx1xr5/SCnx41Wh4ZkElK6yzDJTaS24Nmyc7lPj6jlcVQyR5xmOy7Vv7NLVaLLvsBm1PW+YreQcP/EtsAemAz0E3E0z9o/FNV3hO95dsraNWdF8F2QiupGWMEYMpwivvJRWdivO5+HZIdoQddzdIf2Pp4LrnC2SYHYfdlvscpiE0BzLtyI9TQfSmyhOhQF0twhNeWBFErs9XSSnF/xb2OrgZCFGZVfFSevi7pFcm/x6ymGwkVQRvluoMuir66fA0JWwUgkmWSNuK7zhnBjKEjpE7F9yVT8MWjaHHuE+pxOYdQdW+FT77y1fdP9dNilsrc7kRacRjoJigJ0MMjjTbIBW/JIeqOdPetR+UdYBCElbOpdBMxwg9dUs+9/6tzLFd+aPiyu6EsbVDIJDNK8DirkTSJTy7VP6JsMEjFQ13VpC2BYlLdqy/w1NrEBudKWH/H5o/lkmfUMH12jSr1Q+ATGfelG7l5ZD+bB4cYtW2+icUp+mB7NBIAFJK1Htso2ZqiIsIIWpzsgEXMkU+t51yBLCalN69xxEzglT7AxdzmwDb/U3c5M8Fl/FRd6lGz27tpUACfCW9ssjnwK1V/dHBldbO83L6Qq5KrgZWD6Spb3Eg3LLpoDLW0GBragw7lIEdt8AV6JROpwxERJPMIjAsFWuhQQgnfV0HOqcoO0gnTn1nQezU743cCDa8TGzAp47D0uDGx9UNX08Y6nokAPZHOMJo7JKf0OXTBAG7P57mH2010xqXgnBuyXgDSxOoZnZ7r9KS9CeNoad/Sjc1+JFCDZRb7eqmvnwxXkoyuyqmchYu7ZCYqtga2GX8WycpoXCVWFHTkUDmGCn/fwdcrvZOfUJwkMOL55Ss+WYhUCs/dNEPKY62uLTq2D2JMZ1S1d+nv8HmQVxwF4CQYNl2ZryBwRmAzgAJ+QrVpoEgpg7QQ0UV4Ju38SSHBMwTixqbcJV+n+qi6CPMZPG4SY86M2HrUDVeiHHFkWRuc2epTuRdDySABf0DYhcerznqLeW45rC/tNJM4B0q6AYUYNhzrBN2YthZHm057iyDrgzb0lvy//p9J6sb3VSdASGkHyCHBi6EhDamu01kk50ogNQN+KJZX1ySKTd2lDZ/+gWFgWOsaXx6TkBvGj5lCOM2JpD6t2ieEaZIZr8heEohimSwwAtYJ+I2aTyr2YBu/4ik4sCkxXXJ9lpyahSCn1VKLHqjtabuDLEqqt46zGtIYL73hMaH1mCAEejXT3KlWO96gk3HfRxKN3+Urt9Rm7mUSXYN+lW/5MZMlfW4wSFjCe8WtrOtzSCV8xDnlHCIzHIX/FMvLkekfJT03dwZ7qBTQazn8tTWO5aBh22GIdRweDpGSd3rqSYzwkFbabV8AWpqx1INosLY6Mq4rJCKOvbZfLn2dcsHvWVv/K1wzZ3cv8gLlacS/H6zWjSgdKCS87aXp1ohibVYs/cdeZoClJzJ74eNgTcPdX26bXO7LzPFRp+TtHATwXtKqsd4sazKBG2KXaca/eOM5NXuFT/yxmZHoOEoCpo+il7Ix7jIRFRu0J3qV54eEV9WM4O4RzKfNcyOGQmrFlfsDZXQX7ZPMpoiGDgg7mONu8YoKtg2FI0hYufelATbY5R0cbsfSTXrO2YDUoNa2AhTDzvC9DATeoaa62UQeknfvMi0uwH1uvcczghVGAMmvQ1lHUX/MxRvWuuJc9UgG/l3PuIIUmD8d+45n3tiEGxq3sDBcIPm65amtFalYoLNw4ApUbi73CBvNA4zTpQouPfXPneZJujIPTx8UM6OFjP0rKnFOE8MFg2/lje0c9VA+4MbWgzehrWfUKMnKfTvbSHqjwG7UzVXzoSzyCP/Xy1WKgbrns0M5qQxDY1ilJZmUSPrl0YKE2ArTJHKOZ7XL7hfRnzTZZcLm2sTwR+vcZ+oxedDhZvjr2q29Fksd47gtbipYoy1stG4gKD/3kui5+VLlkswrA14h+9o1JjbUVJZOEb8TxntsiVm6WSCp1GVv5Xf6u558sLH+RnrEtjHAidX9VNb7wHm80QRknK4UES2vlG723rEva3NV4BQaTIGWklac/0i3B4RaFAQAoNn2y7Zt27Zt27b1s93Ntm3btq1ZxCzkhLSKCy6cpHPPYplSe2dsMGZ15FtU4hyagh9U8WQgzFOFsylTd8+K47trQcmkV9l/ZFNny49orB0gQhi7ThkstU581c1deD7aKnAMNkaHF4VVV/0XIgw6zvi0RHynSE/O0S6Hp35p/vqzTIPRtrhyYp+ePIPjPZrcobx3AEtPvW7mQtTapnIxDL7CkAj8keOn6VvIqU7H1pnDKr5bxYq8quPwczZc9jnnEweenzCHUE6lCxrJKGtEQSIIa/tjPT9skgizROIJo4iLDb3enaol9zEg9W/mlMBOaW/r5Pdk+3YYjadiYTIyPmbJ5QdcNh2I7VoJmi6CEhzadZAbL2y5ZQViZjBSCjj5CgAxuQCvN+q81K96vsioAjR1kUue6L9QdoKP4UprPnRMXlwAHHWb+t3tSiFw25cDcO3TzSYy3Lb4KD5jtypv+MAgW1dMpiawxSdSvDIb0h/Imqx31vIv6dY3v6ur9HhJqFh92dRy4xsLPBlHoENwfNFUSFenIB3p80mvk/pyuqgMwsAYrJcOp/lLvW3SEoe+R2HUzluK1SKvwkoFsUXxa9kyKfsjEDN6dOLvy9T9Ny6go3LoN3m+2TBBged+kuaH/tUy1QiJnirVM+e5sRz3XFwGoZe0aFZeGnHX9V6brHdKUzNifD7ttogsA2Er9CGMO5N17GCUjj385kgSdHVF+uOUYGMAknsbXG4fOrltuw96RCwiP8hHrBNmZO8OeqI0NUohI+FtSeKNwkb5lSd9MWvaOuZZ/pyxyGNXtUruMx23JcJcxFV2xhwv3/lXQnsnALFRBmdRnW72zykYTFt0DL9Hgu2OeuB8zTK8WCvFqvmS+n0VcOx/sJKhlljzVhpQAl6IAq50fxeYSBG1vqwztf5bzjItGNqLW8z+yYH4x8eKxmDlJZBl2O2l6VrmVI5+gua4pbJJmGjqHveANReGReFsaDqrbo88vBPHv9M/kxVCt7idNN4jRbCl9LJJNOJC9+XNThP3Ida07h7zDKCuFTEUiUz8MsVsO1s0vlaVfAihyLOy32HMd8C6eQivptJ0MsmjFcRIKadmw1gaWxjM8a6aCNhc915n29VLfsWLQ06/1agDfBgIGpvpxM2fvLzGufILj+XR5voT2bv9PKKxcfdB3A95tv/uIxG/tGomrfjQb2H15MU1yRIA474O9st3ZS0EuWm0yTFUixBs5LaRippWD+9g/Pq/NtthHTjKz5deiaXFJswC0x7CCRk9g5X6BrzdmLnUVQOPMhAxO87HNL09R74tAsvzBjVMXjaseaFkw/MN9J5MQryq5rmwEl4DSRajxBX+964JkWHGZ52QUK7vHm2yFHEObfgfvYqPQMgElOztMC1tybrhgBDfwH0uduuQm4b4+WT59bD7V8IpxbBSEJWx2VZLshbRNbjvp4bSwD1jsQekc3d/7x4t6Sznnmpn6r4fCxqZHno+hn/1IlNIC79QNAU+KkL6LRgCL9QWizO+zUnKeKo/p1Emf3cz7pICA7PpbAcCoyxseA+n/xwfE/DvNEkoalUEQIX+RJoVy8U9L9rAxVlfs5wgxQNhlk1C5rKfJ4xgkUBYlcnKG/2+JyJVqOTIbZx1Y9cb7mVeNuZtSIGK7n3JaU7GNSw44oKjfBd6+YZ5cn1xOjN2UQVz+bjdMfJiV0z1xDvOsX+0/huvJA8MJf/OAA8UBKxUaJJDU2sRVnkzH9CcX+3XykS44IvXsV/HttUbv+WrJC1j/EygP6Z0o5HIhB24Emyd2rugrYg+uJjpqZUIZTB4DETNqHgK86HeFS2QAQqdMmkt2UXULMOX9TbPr6i5HVBdlMc+oTNyqBl6iYejqOEPMr8MVv0uCdpkLYXFwj1krAhJR0bXezPvEP0AQ90E+STlTCwsEGPA7+uKTV3UJjdoVovKbbBOcNdEg4evimKWje4dLYtmAE6fBLV09fW2AAq88ht3azMwBoXtJb+/r0xJfm7nGLNGct75vEy+rlOthalspjwqX7cItAprZDveFgMvCoFnSQa9KWZXccEceP2d/6tZYaKndqX0IcA8NpU2mMgEIvrFA4nd+fkbGNwzr8PW7jJhHI/uMI+HN7bgse1BkfegFbYvcfJInCHkDiMsrbExBXooFAhkdCNm2BtveAx9WWxCXOvD68QJ29sw84bHmE1oUkoDPMy2jrORMz0aiO+7E3Bj32aVeb3dE5Uni53Wnjn8wZD8b74BcZeFWdJHX5DXj8Y758t3jRhE25sjoWO6z45ViOpkcAw2+g5Ytzqkhd/JzPtUKS+SVp2nBZMuApFGEYPt2bEQ71lANNOKN90xJ4eEah5kC5oGUZzzVuwfmMvYlOHctdiEXHpm1WMUFB1lHUYnrrmbFSrhqvI81Yi3JqjkiBRlvKlwqgVDjey3AbOdqh3gothiiXg/KPCyGVPX/soT/Ja2vK0pJZPXDUSNIIHIkAqSjBgaWKGauKj7ko+ABrgQsFQQB3bEQPHMpEvfScqL1CxMqaCLiUVKqu3PawZNXApLhOtzRV69962+uYQCHsZAQPHTnlSd5tEEWHdhcNOXqK/CH6+7a5Zy56o8UVfgTfu6u+tk1Nli6JkypRUp1fLC9FbQjLqHwxvPF1uxhmXTZststXhsKTv3ZwQHog/ITNd7/k5eNWyqUzvz7ZxgpANDfJUqOiiKKaHx98Mm4QpFJE+kKdQr044Dl+7x7dEb4FHAwO5b/zfvJ93jMuSRz8YzqQ+1xy6GWezjzBGhF4irQVXyg3nEij3pzjYMFGDWxE0Quzh0SQZXVCLTebTc2e4uNe+ni9g3OHaColfDYcJxDXjyiB+zhECSi3yNzAw4jK3ZU0+2sgypfUfJi94J+4sqfL75BnJeSYijq0KxZJNF0kjfWmp/ybjc73gSlFKb7s45HpNFr9Kta/S+OyIocrMlQMS3FX6C04ihDTBRFxmdX9scfvva61Y3SaOoQfqIIJR5PtZ0YmDHewsw2jytgcmCwAlOymeGxQwlg0OjTKbs6yuVKqZr9KetI9zvwYU+apUh+uhazcgu8n9+JNvUuwPC88r29oLYMJ/akx1CWC9NVb9Cw6c2nnDU3tFrKL83lgh5bWm7AJNdgHWmbzw43JxS7eJD68kb1Eg+CXfRr7hO9/C9dFlcZak2wURefd9bkIGANP3gtODoD52wYJ5pcW3861Ue7+Sjdtn2NFcnOtj+KLCu/FTb/6BG/e91Myi46jV93JE4C3Fpa7ibiTv7BlFq6O1lm9YB5PZQdrwmk/NQFWF+2o1iauCsmAbpZpT4UkAwHwRNEkTxPFfHDS4sz4KJpLl2lVDo6WHK0cqQivoD0lLrvU7EXaOb+vafFFyU6X9fcSQ2e8S4LHe5QPLdIy4cDOwVKmy/2JQ4SaC/b28hoQk88m43avGjiVpEIwKwro3cRM1ChQ6h7+Z0aiJ70KXq0C+ujCU0EWnNKnB0RDNK+QSh0h25MVU6h11mSpFiRLWTlSww8ohZHcyFyZBd6oxJ+/DOmkAuFN80FG7iSlAyIGQGt8miVSOLBSUfx057JQJkTbhzlyNrv53MmqitI5tPCAnPgVvBjP+RXAq70RNSlKOB9yLC/Uu+PGY338A28oEHA5e8ATkTwmo/ZYWYWSpE4VQtOpvhYpfUUEh+grdCTwbsNjLaHEZm3O42OpPLDa8SR/j0mqywdk+uPIZwzBb2Oplo5gh9Rrk9j7skaGjk9K+DSRDFWm1is95C1MERGdhS8NYvEEW7Rz0HkCq12ejyD8XWChZP6wJqzT3E/uPTjj+DcTz71dgbJdSCMoehIBgCmbkE8+MBoiF29uuAAi1j59zE2xm185HzJnjQyWiPu8kh+fbLMaYZsljl7y17UkrBRAfZH5zAS24KtxQN+sRwr1O6a6zF48gLKvFiBNvkA3qANfHpuwxkV9+IxlCrmLtbcBy3+H032PF808zmO0oseRTAPElfJRyv/Rqh5fGz1jmvVmFn5O56fX45CC5mBdtZUz6rGOnJNaiprS1Vixlax3yRhITgy4At1dSvehu6hEfm+AI3YgHwfOBpo9PaeELl8DnYkLtY+zYDj8KcNX5cKVeEyCSWZ2Nyuxju48IjVSCRl569ZCoBEtWKi8SWtML/A8Ebtf2HSCIE3ziMoVQkh/lFRDxYJwmyo5lU1wZzxVi9vubvWphkyPy4xn1E8+VUuWiVRz9+4LUuliOah+uoaNKymjSmzcFpa09G4y1HNwKs/dnd5RYl+4oDBmDdcrx5en2q3ykGN9Im+geJKsXrzkwJCyJPzXExmL2FWokJOD9sRlmqqAAWh9I1QMEm2MqCUZ1RgIPO9LDLfMknNZLRTbnnxAP0bCmaEj02u/rfEvuAUPLGT6h6urPkXNKTMmHcnBNVO8uZGD4ESh0j4zqy21MO2U2ZDAliTLliLZ+HvKvV3E29m7zwHlnMLyOrYsxpxfD8G0W7Jrm7kYez1gqj2xvpwBYJjQ/cCGeftlK30DUdFxgA0ZeLCwsV5HOSJw2wonJIIAmR9wjtC7JMQ0YbTk+RVczIF7V3UugKd1OqBYo72P6HRDRWQfFOacbeZosXvKxclD2eO2x+wsqxqKHVTaKbZQjopFkN/UF8MI22WrP4a+LZP0y48fFyr8H0anfFU0lgIcd+8fYRqaRqbe1xw/nek67n02TH7ULX9JRYCHICx0+Evv7cjbUlIuMdK6bdw8pJegJOZS/PANOJkL0u/i6+lx+M2+k5SWb8KkIguXrK1uyO9LX/1D2/Em6OddxUZoelfJM9R1kkbnSFcweDta74NjveoGTQPl9WWApjsDhlYjyh5eSjKN482VlUuQm7FTr5bSLuWVKQ2/a0clks0DzVRmmylYdz2A8DdT7gxkvgw056gObHAu/QHYgHb4gOWIXeU/1qLnh3nxZjB3XrPGfVj8U9vdNhFmrLC3zFdU81w6VZFppUXKE5fOQgvbEhyRAllE2K3olJvGKkDQvuffAkYtTHW3qBfMTdwwxNDSE/xBfHfRuNIhiuYjzQlxbMH4JdsaX9CYSEK59zOFsY02cSAtfBNlEK6Fd6ssEkF3/yCTluczwrEeb/agEe5Awaoek57lipmuZ0dNqd87ICIqPrQYnpOjz5lyce4psgNF9DIrI2e+D5TnDcxbHW80h/WbUJqxaxkfwjcnpMhlr4RRpiAJ3T3WHUsXP8g2OyJdB48Fzi5VuLuZmEKp1FU13/I6pbvYZMcQQfzO7zcFHPkRuouZa9DvObXNODjABKzV5NDKMzBgqHLVsaf++QsGcrY8gp4WZzJHSYmhkZdmB1jd1TmFopjotT6WfGWtxy1Iqj8dTVy3XHfS/i8Y0XVfXu/VP/B3APwlfYaaB8EPas8EsZFjqi6ACGxpFyAdbRYnbft3F0865UXBJglb+a8rQXTxtpYyLhHgrY8T8hVlzMPyk6f4Y3oeLCdKDmNgpT611/j8b3RNImvKx/aRzbT5/U3NbUvCbm1LU7k0/JnyffNKKHsmhfNLeR+xGdXcf9J8D9TiyBLv1uQA1GtDGbhLyto7puyTTyYh1dCz0QLMCVG/3L9poMsxxBpTJKgixB3Kq/gO2kolKM9cXamxAFe6JxPIrHomiKkZU9qLZQHDx9A4epR1oRJ8eNxyfnGTb3I9e4CtRRBQXDywT2nPnpqL30OLsQ8Un0KLo52rQ4eI8mdNjH3pVXVLer6EpGwXb0c4QQgnFIYnZQfa+ZzDqZVhsPvc70M5WkKIzswMHDpakFD+fvlcC4CXm9QHIfsxGiQm8/obr7xQt9rQ1e+3AyQr88tcg3PVwkBwgBw06T2n2812hw0cD5y+coJHMyh0ztSjXOetTw73hBLZM2NDq+XeZxaObrfho7SGVSajLFg4BTxgaCZ7bP60zWUk2CMtvmW/ysEPjrr+garPzNVb1Q9u32/PGNcWdKBzLZS+AIuukZJUZF0Dk90Io8n25cldgqWIBKZNbdXSg3dQCqPalwam5utZZuBJI592qPdM1mxNXjLSzyhMRWVDBSDp+8NunV+jBl/TedKqqItMd9Ts2s9Z3FSppgrlAQbUX0CSydLFbQ2n2EatI3xAPXrg5W7dcan4jp+dufn21MlPHUE/DoZJTBogo0hNPgxOg3fU57UayxaeNp1LiDvkYPCT6X3ZUjpQc3vAGQy+Lo5x3livyqitlfmK7VLN+66CBx0sXhcWIzlo7pZz6y/swWqJGjEGeOePEI+8kVR5Vo6pg2+JtSbOwLeP9AYAaEFNGLaEnfRJXOEbzCFc4+xf/cy4XqO79xRwklpeHCwUj+2oaa3QRV6b+nAZ5DpiUG+SBXSVla3Ik6vGoqP1oS081cjsYaM2obC/y0wL74/9jaHUFRTdqOUBvH4iwEx0iVbMIooTrZguO95j9GQc3qQsGLwJYifhd8yuER+/WeIEPBb9RqQAoZdM8RSRHGVEmPTcjj6WX3SRFZdD2HjRTxsWa3m+h5lTxqjk6EXjm7GJNM0qItU74B36uKhbfYKP3yAy6KfSL51p4rlxs+cr58As2Ukx/838BIXw6sLafvM6TdFR8W+RKy12JP/lWOLrzNbQoj0cWmw7X3UiwW3U38i2nbzkAIOLOHq/kLOuuRpLOcteEub45Rt9d/UMxNAdxfgdgiT7IsuydRVgD0spweNHwR+IE0XSc4hlfkubOnEncYdUu7P5HfugetB0gPQPne9KFV7UwHF+PXR2DZ2q2oA8xBcXowMTcbKaspcSkEBjgxrUmhr+Mx2c0nCfcLZEKzoFe8PwiZ/zqXJAPzSO/oW5KUX94/fIwNC2HINEqYRWhmk6nv646AbNek6MpaakOo5NPy5Em4TMYJ8EVH7nq/CJIl/B8bUtkgWUgzhPFheEGxP9ppc6kDqcZhrlGZNiuBUbDv9Z+d0V61Q5kQ1YH8ojsjNUnJvURB/kNs0tOImQuvKEHJp1xSpZtZJK4bItpdNS149ihw9SFFMlIez8b04nenSKfqdUCArZo8TPB2O+VIStcxM54vCNDMk5KtB7vyC3FKmgn5FVhlcSc47YDLXY/WG6jCmQSfM9pKOe+JwNbM3jXWcHsqLfQwqxKLqb8ggWOuIcxMFRmqlo9ZehtwYHqhK9ssJ/ppMl8LeXXEY3ggyJx8yLONNoWCXCxWaqyiBFORhCdAGOLI25SAbc0TCT5+ZRJwY1j2EEc5q5IN9MlF3cfu+Xc/Ml0t5GFyYcBpP2zzQjOBKNFa/kqZ/p9C88j55p+wVafRmalI9MiHzjO0DTMQcXlUSlubFmFbuxvXegveI4akAoylkH/qiLipit3eTDOHpppi9M7XfMVgY6mN0Gq3SpDio20YdmKE7PnhYSAlEMeZsk6rY+mBEeOz0CV3lE1DricHGVhoWyo+939rffPxMx3EnHeBXRCc2Lc+2F9cpHgP193yXcnDvm98DIF3Ktq9a0NhHqTXm4KTuPjTjaiVAjewMM66wVVxAt61cOl7d8bX0XYbCeCy9olfLFIGCBjzEOJIy8zJt2PVuthbLc5kOXKQfxhfhZg638z7ES5C1fx2ghbNQuS1XjYs8q2k7MgPTtiEYQv/4rmQqx2UmkMhvSe9gh7PkTpnLsY7h0nZ/fFg4I/AssHehkdX5AH2ZGe/8k3kQiagO8lsIEQJdYd0OMimm5HIatyzYzuUZu7tgtO4Ty8Pvo3VoOkFd7t2DUTpaRwMxEiU1NMX31KKo3AGeISFoGlmYM13hxRrbTM1LFYzVoX5K/hZ8xbmtddgAp8y4L4zTGp0EJTcHMV1htNatSjpPlICdy19/xLCaGf9IkND6x46Usz9wU43J03QJSMB5EWWEdbPbapfEZa+5byyfx6rm4NgZxt6aU8kGmtOKxzH3qWNfV5wf6YX82J+vqyHZ+JQSkeOlwidDYvvxcZkliWhpW2OfrA/oUlxiCqmVU52rDlbejw5vLShUP5ouJrt+iiFYZdlHvDcL8aG3ptvLp6kmahVPFTLQ8m6GCsIUolPG//khVqz2OfYBInPrOKTA7k9SJXL3hcEXiv292nbKRHjQUgfTjQpNlvqI+pYyxxE/pWZvz4pAgOOety3J+pzalW/uDQuSapFSUyRomtWWb1AswO3jQKCyPkT8mrcd3VpjIF8CEn6Kd+fPn+/aqIzicuBHwIcmNUQMaK2WCV7D9ktjpfhyNQxaNBUv9dyoRyQLCaVObTACUpojhWqmDK3KCFyNVoslNHwO3xFTPcnBI5ohlqBwZHjK5q9h5tJ3nKSLh3uta+zTrwBjotsghcF/aHD8X5KzstYEU73YMCVJNMV8YRAAUmOZyP2DdjH3qdWy2RGU7fU/A2w7lwMFI8UGyzGPPwWklr/lbz9QGVxdHn2fiJZzuR5kzY6anKx6oIUjfJwE0mntzxdIH0xZPrYv2FKr1oUaX3LR+rhx7LddbzgiOHrUOUO8O5lqZEB4aaSbfzMyUaUS5hVML6jHfuvuRozCPmjvKBIdfRc1LYiHenRVy2XEysUATEpSYTU6OSld8YGQYWaPFCabPZb/DwVfC2ZQLF2ncgzd/Fv6vLKOH5y4UG/8Bkny/eXIrrN8EpwDHsTO8vYzioJklAi0+H+/Y5ji0MgdNNsaVlsaEMcaoNDF0i6zvkNfwr7sEtq78pvH5BY7tQkK1f5g1nj1DkhYQrq8x5/1BS+gIYoum8cA+10zdMCPypnsH0r1HgvaZXzTRh/EhdSR33b0uQJ3gv+vVYtJsgx4UIrlVvyKF4VdZemyhF0Jq8iCws6RaBpi5Fys6omV0gi65/lxnn1K5xyeRsvK5O13O2eRzXIoy3sU0fJoVQ5rD6e2QJqD23ubZufHnLz8LOyzk2I+OTCG0JMrePb0D1Me67en/iC+dz9T6rNfJpDGxR7O9XLbJd2+rXymZUdaQ17+rgc2AFoVgidfN+nVKTwKPrVuzQfgNpNGT9JBR33WCrs6cL0GCqz28NkzXW4FR2Q8kaLyQisjY5J7FonYDyZrIbLwEktcoDE48trx+zN3MSMnDInSWQ5rv+XHoeRzrtIjiY+sBiWMIvBagkBkSlakNKCpSEA5lbm2TPHdirO2wvmgk7NllPabrVn1Om7iVBc6Dohdf6Ydh8xQKhKIw669d5VmdE26cU/3000AeS/vkWVEH1KV2Ea4Fx7eEA4HDaKMdkPXmrec+eDXJTP6UUtIArvDZRQS3W+s00o2QMEW0tblqNvSFaPSdOdP+xp9sLRL/96VpobBaKX3PAI+DkOZOVooFlkiWuxHSvH/GpxMkIqiU61dI4OyNidIA/jTbzo5PIERcYy4oUIRbQNJjWe+wWXRCuTiKdB5BxeIEg3Qki7z1lOgZN/2szvloa43hxy0TJhUgIE5nudlEE3h8r4URnL+TTehyYEuDRchzHRNjBYZmOrmVegjNkoFBgzgYtXs4GOPeMGD1ItIqohEF9wW3TBEP2+rYQ+EzHftCYjH3dkHnm1k5qGcXBRL0ZgLU/UZTTI6tos2/BJo6haYf3yv1jWbTg7+pg4aeG0DZ/NId0ZDLQc3ESDczlXlP+KJzxald3KrDlp0qFh/OaQH38IdqNPTLfALEHCkH6YfnTFhORr5WAxt/5imByE9Oeeubo0PVEWJBfkm2x8EzClboryz0pv1WLKrFfyFuhRcQ4UJIqlbuSfsmd9x1VzjEDuwodljT42PdgnyAr7OWa8DzjrohyIIpQZrmEdvCpOcCwe/ZoGu8/B4RnbjL8vpHDKVfYCzDLFJ+xD4FATqviY6J4OtQxmCd32COlF09T8YQ/WNEC2vo2ljXLRWCS39yfzibK0myfC+Q8x/QDevPDK2GQtByPbO3IwAyb2xjDC75k8MeGU48FajRTUAwBp1FAHIgH4qNQT7EWUZzUxhu70lHIGtFKJOk6Ii68/rdtmIVf6rzVbksdYvmGxkymEUG97WHxCfVruBb60WDN2nrnrml5/Oa1EdMCKlAj4rPdywe112RyGRc0HH5labAwWC2hjrOxQxeJSab0ogaTX35Jq23zzCKr15734AOHOdncnx6sk+276KnhWzWRda5xIf1sG96MjuiLhupXESHuoXrssKHNCvVxY+/y3r2Q27r3Nf8kMLeM4bEEIOO6JgKwHKIzmBnImrVx8ebTNk+JcEqcEkStKXbX3vGsNmzKoELx08t62A+S3OltLUvvmkrhr+gKXSKu5OEcSGkho159sLsv2g2LsyrPr3i3ovU6/H3JxqEfAPguupEJcM6psGiOVDx3uq5qBPrV4iIMET8jPsy7pQd5VIccgSiDKSFhGgulrH+5fZElaSoELfTYmbfrFvZ8jcnqPPQSBvyMKzzifA9R5u6/bW1Q11vhFDtnT8Q00NFtby4MmUIOF8HP0GAjlWmLGDkyka5yHUIZlweE8CUr8o2Ve2FusiIsY24Tcot1SFAmHbcG6tzWhun7A8r/fB51i6lld9PJwk80EUKc1ei43NJQ8EeAkHZp71asSa6Az6QqpZoXPcW2HhuGSgBktHgRdtI3qI3+5PrwkkzdvKTjK0y4DYKMgUC5JWf5Mi3imJhv/Kxf4LuDObAZFMU4Otmu7IoCM4r/wOdB7AUWjw6LgsI9ekpF72Hl5aVqZbO2kuQJsrqfOPCpsLU0XMU/GS14rtr7zXVQBEVXwL2Uo5Ev+NnM0p1mV4EJ/e+txTNGB1cglR5ZMkwF0uvj4RDydMCka3cELIGswdeXIuySSnInPfu2WlBCL6V9RZfNSjIKvZWIQ1xtPnRcMEtZ//rLjSwGjsDnBlFMJeK6ZxsKaD80T8QXEIc9hLeX1/Vf50nZsSJZ6dn1sHojOGYQ9PhUs3VbJrHy4+exk8zgdWJ5P0Vp4AgK5h3RtTlPeOxL4qUxc+PL2iLsR2iwF5tK2/njPd4pa8EMvT5hGA71iV6xtIyMUZS4+4Mmd/M/v6Da7BHJm/dZ1YPv13ErGIHkNtGUQwWL/rFeJIOUpeKwQzeslCMZc6Cj0JjfOD2ppgJdypm21WBZ6l14nAVmjaIcoA1F1ss5vlDEtwi5wJo0XrLVRB+cIYBIPHP80zsbtsPrlF2Jl0NK5ym2rk96WHGKtcNbuDzBxMHCO4dQ911BXY8GIINLw4vJhSBjJAcNJDg5uIMyE2O2GS7aVhz1BhGteaUbaZEefmrZHu1XuD3wL/pEuG0PnuIuUvaPI5gfyPxiilnYacSn8S4YvmcUCAQbdIzP1Xa7cYXbYEGZqrlOJjpXqVvfkH9SDywXThjBcxyhZZNPHxPGPXV36YgDaF59Wd6kFTd5/a2Y1BR/9gcapy1g8BgFC5PDkgdIhmKy6/zk/xgSPQCbHDbjFY7SSrhpZHlRMbTivmyQc8C2JJgjGWCTCmaOTQiyZxOn3FxLpAUuywxsMDr+1oK27FJm8yP3LNC/WewThaUyrrUhVmd4PIFOcbx+1auUKdbZ3/HGiV8NQeGTZ3NY6ENoVEzxPWRREZjjyMvtvLuWtD1fD+JYTqhpvsG13sUyYaIPWJ3Z/ld7EW1/JTSlt5ICE/deOzaF5BLzfuLOORUz1bjSEYYzQdH5XbCY7VwTf1JySEdFCbVv5di4NhOV8qXu40Ljr4r7jvN4e4/R9+/zRa5Xxux0Z+gb+VXXLCDx+U673rq+hull8ktPERhtV0wUvvlIAIwco4nVRhZoWMRtmIzUgwYBwTiF8miN8dihskRg3PxDu8/vcxuP5AjNAW6Yt0MF43MmBL2/LaDUjdmggwfEitGLfP5sdiG+80wzlo2Oq41oRlSIhbi4Qn9jr+2BYj6uC9sQdbce1jeeVrTiP3E0jNLBw2XQ/nYEgSY/zRhqZJgPUbGZtwiOnPwpbTf36UrsRUsBkmzzC2KyokHBPWB+b68BPELfum3KyBYsCs9rL1WHMuSiWL0a371CvdPoe1SUseEC0FDH+kswlRFMAP6sFA5LlMM/7ypojDiM/+2TQvEycnu6MvRfyPRav0CHQQNy/0aDCVP76VU369Mcg3Uz5tWdhXwJBg1vNuD1dWvutBdphbbe//ki0j5VmQCvXAi8lWuiWqiLuc19ZkQlYhfGPKVhWMGU0M0dg61NBuE9moATSMacM9bBgHsYH4l8fjjgJaFt/K5xrmX/ihcFxIEEKHcjPeIS4/5jjefSYu7JzFLEIM8ii+YbfIFwYDRDCxAg0DEkYdOBke0XWrcGRIqMGxcZdNae3rJzfIF1ffRPj0X/z4hZdMuwu1yr38yKc9QOfWQ0Lt330BQvSWmHa6EOHIWeqMVjQJMOOzgoL13uMxFtu14wa8tyJ8YOdmpT+Burrkd0FENWWoEfN1TuDE0bXuStJ683gOrJYVKYEH61VlHC+uAIjaMnhNkYHDVzQlplpYNa75NMPLufic5poEqngKl4KkUwW9HZnlaxPThI5+7tw2ElAQlseHE1PEuGuQc5aAbCM4lt3lCQWqEH+w2SQew0soda6IhWQXsDNe2CcHQE1sz0Ens0/QrejVXBBClj8KyfgbwLbjOaAU9cGP20P7P9cygjsO/YqgO/PKpVedhtBeom3pMEYcr1csU+X2P++ec7Is7fzqlLxdSqQyA5xAqzA5K4jv3effQhGIMeXwdOKU/BZTdGLIWhQfzFSvLK6uJZ6wSFpDxBSQ1VxJxqAvvMougrEhE70QoMwhnNEeHIa10fkrV8RMUbhb/uZUk6GN5KPQ/bMB0GcMpqcWHZxcWJ23/P+8QerQ6AdUmvsfS1DLwcvTvHMnP9dG76DmY8Rix/S0L+J1YeS+xki6fg3alJXasm/TgCfYxBfGTkg4mTUV3T8vMEqa13jIWhEjPXn45SXLH//aZhbkYqGTqvNbNlj6WDxbX3y85miYti3faSl+DJqYp29r+EsYwmNy8MUDMvzWiJtPVflOFZ8MaRRmLfnnVaEb8UI/kcpGN7qY6YJXrZBr8I99ReHQFUuOD+1NfU0zr72s7CDeHohSxNzCxmt+cg8/UYPUeK5skARkuqYdHH0Q5bB7m8nbHntXcoa4G6Yu+Z008eHq4XaJoh2hQrzlQqtYDk3n+BhZeRE6UFr6MTOCUgLsU/AT26MJWQaG+pNrW/wJy0gnpvpkaAJZE7+wJT71sRL/IudVhj/xDvFhpyDT/a8cKvaffEo53hTCtUmDNeXMw0AEXKrySaYC8stSrfboutnAT+USOYebW/SQgiO8hqW+xcpCOpVxJFie8x7k/bLl7Jov5o6gRR91rLcKnFdcd0AiNwFIZU3yJ/0IFbwDltHchQJ2GjL2iCyVXbNmU8QB6tjZDSQOul8cOdQhSkhSE9ysO56lTn9fhe0YNfSzlOgj/Be66M8VPIwWRPmtBc53cTFFflBq66Eo+f5tFtAHVcdeHwjk2TeDDZVVf3pwpaj1FhXNVU+U2OP/9XSkA44dOzUC0T1uLEG6F2hgaOISwVKscfLOrZbkkGzDrFOHXwKwosv6UjwbvTTVhKN3lVaU65WDJ4stWbDm0LMM2k2d7mNQfniOaYamjpq2jrI8w1D6PZcaGIHVdEq/LfnlwGI9BCtirOOGRmvjibY43AtoAwfN4iV/+JZrMgik4Wo9C8uHK0sojJst4/7bvKDmZ5/eybRhDWU77LE41OIrIY100GyaRToHMO+56UOAnIWpElPXC+NGIm3suRp3RmE4qsQDGJJe9QDJg07/FE1LwR7UWA2+daxTnvJ0PsId63bs+NaPvxmjswBWK0C7hO9c/wAYGegAzKV7JqgVLlT1K+DaWkvC8Ob7Hz5p8CAv4GzZWqx8AXuujmqOsEw2ZPT/t0JbuR/pmuDdO18OiwXago2AENiQ/dWliyy2VaLXEw9ToyY4CuQgLLjVv5Ni+rsBr6wtBVgdJUbUyiw7fDuPrybzf5YjulyvFj8jXKPQRMCexSoCw3FzKvrJp96kkkWK/lGHsVato989ghR4or43OuLFQF/Xsdu33z18lAcy8k2Zm5qOdqZOsqNV4ODnzHkKuVGAtsEsEv6QWr/IfCnfwhqYYeucttEqHO8B9zPJIyh4zDL3alwWTF4JZa7LF6WsvSkLyA5AVcogkohG8U6mzP/FDbC8L3l2AwPfkAzW+sJdDLLuIAF1dHA0N5wUfK8bnTAYLDqYKFaD6U2C80QSdBdo5EoEOmeiTq9aGMc0v8MgsgZoa2k/JRVkZ2HYnNHHQThSYgcLC4AFLE/wZ+ekXemnFPPjVX1RTgS+A2KAiSrQEcMRugD2fglXf8pJg/DOqx8IGdADBwa3FeUd8M5YyFnIoJzwwkqdNZveFfLnNVmpxWbGQWj+ITGf9FEbHx3a5cEVVs7nhUiPAAwiR0oHPbbQyrUwTyDxvbnrdlqs7vsizV+rL5qrYy/7mJmdgHNDo0W2BsLSrRpEBQPpEwC5XzKLlD2s4FwB4eLegtcZd1AzqJ113IE1969lnu6oWivxO7E8hSOCU31qBnhkLMmlYQrpGzB1UeumJvvreZ083TAKl2clwe6sr25r4HpDEp3Hvp+MVix9Hi0CL6V+0H+URfoiFX6Fah6w0uxzOei6lOhesRut1l0KuYqaIVVWTvnPFv/kBo/mDTxNjl10jiUeyoVBeQXeKGieL/QM1i5DCsclyk3uX5rhpiO4vYqPbPjczrRY7ZUgdf4vpzJhUegHI5583trjG5+70VsoGnIo56AbrNPomKAui8pPNHyYZopTep1GgZQL32S6trRERIgk1AG0F2uwOTl/M1J6hvipOyPKhdRbvaUeFWtElavjedUyjkBtLDVPn+9537/HrHdENAacfjXrRSH/fINlYwsc3ywJb4yWZTbZ9lNoseKpxh2l3GFKGm+kfWlN599jUmH9BTliPPwERkfkNYpn6bry00TRoLNn+sMlg4ozK1Zm0Ar31wyf4WVD841mUU5inlKJblrNObaqo7HTh2pKKc6IFEeumI9vAL0/+vyoGln6F30eiY6TsETQl4v+US36zyX7UApeRek9CW5xe8E9Tpn1IcLSh+gbjwoceZGvD3v1xjKIWyW99oMqFju4OMrl0ynHg9XIz2ctuBUUt9MUN333uVQMFwbNvMmd1yavtxFOkVEvr+p6RuYBWPcARRlOpW3wl350bWDni7d7Rawz2g9BJnJhyLyfIG3iVE6OIHsW2plpc7hVySaf8rlDH8OvHu0OuNjssZv4s0IXrK/E16/6ot+4i1Io0D0FlOyOa9Ze/7s2ePa8mGmUcudiOaLR51C+PC/Q+2QwkrKJxNybtIZmQTJ7jMBKKIj/ZjiXm9ZKs2pbr+9FQltWh/1kU1E4OpJGrp6hUNbXj+B4ZDSle+2VT4GcC7yd8rgll8XVyZU7sMiDc42zpPrh9p7A3NktoCNLvwFhxb+fcxIsuKoJDhXWTswpL1f1/XgJ1F9e+EQRHb6+aeE4HdsoAhoaqJI/BsYyet0YABDJt0AOO+eloNTk9/8u4Spw+rKEqzsZ9MwwIHNRlyKw1Osf/P7LD/AIgvx04Usw0Y6Yy8kEYm/ctJXEPgPmT0nRkKWI4WpB3Z+Ysk8FULXNpRbLLzBUDk5wVbbIN7GdD6LMAK7MA1POrMI2+oVIVZnjEAD5ViYZZfNvolKQTJuEcOTMPzUQrJKCfdAbYIU8UiP4mmq33oWEJME89M80vxpjG3Ju9gM38bjcJDXAwe4HOACfWjCv9t4qLW6H8pwAUZij8Pz+G/9i6pfPXl/Ayd3XG1AqivE4MmPG6N1LJkQLxG4kNjCYoAYqDUoGCXa59TEuuP7ZlHhoBLaaZLRYrUm6uUdo1xHUnVCSqkcI75xUtJucPotWgIPqQFhnRBhyMtcRUbp+hhZlMoiY1+qrsqyepyfFO38LRV/SpDFE0BGHdhsKGyKvYdOAFxdCrujzJQe/N8zFz8v18a2NTJ3xiDq2iWUa+tNRZdUa1RrrisxhdGh4SxEo1tO881zRavl17NZGRQJLMpKlv2xpwCCFRxgtfz4cN/pLCODADXr8zGZvhybC6ilIz7+MlVjYmn5rILa2M2KEEOO0FUPvjkeQv52jLXgIufiraimklYUO6FPCSqTAbsnhwZSavbFR569CZVyHx10Z6eHklV33bZImbTDAsfzvxXEPYiIBpQuRpYW3X45tOZ4+OaCEQ2Sw7hKUyLQgtwwlndcnkf1P5VsJJY3s1JjFWYMwsTkrbinvS0Fa9FsLvMm/5LUBsuBFGcnbrF6ITREEp9ycTMuC2EsyRc+UjrIpzdeP7hnCUfDsFqTFNT6MCN9lpZHin9C45pRlMUs0nV0elbiS7+nvRyQn/BAuAqdGcRlYcvZ+IyAkeBSHF/x2rSRvJo/TLuKvtgf25lKCVrmGSs4nhbcwYgipaD/8B8XUIxzp2Zr+MYaaDb6OriYlwURNcEQjvkUlo+8pydMMgi/WQ5gHRha+LpPLvQ0g+zqOb0rV1FxZ2wQ0NNNLVlmVpa/fn8PWlzBpl0TrOSiuPle+eVkOl3K5Q6YhO8vqrdM/bheAhnwn6Uhxntx62WATi8gJHD+G9KjXsjf2glvhiN4N2MOfKJphd+8cfiv+iWt1xVJeA6mJSX8t8ItOoWB7bHBbrLJehRPOJm2Z3rDsDAFwOYmvybyOudHy9O64243nLQ5qDmVXLJzJNHhM5EoX2XOahOkePpDekKm8mgxQgHgdOawZJzEjf+r+eDDhZF84gBtdu6+20XidePxVLtpovK+VMl2Bu8oonjS6KyGSTt2pnG3YJ78fiBdyzULXzihTeSsG7VySciKva7GflVWDG1/4me/4iyIY2Kpcrw12LHkvwKiJfrPbpFCuZstJ2CSJAdDA7ZajexmbzvpMKeacUYMGn3w40omPPGvPgQhbI2nAMnMcljizX9/E3/mFNn5af7yzuqbUjic4weE5U9VsjhVet/41DWm6d3jkELuMy3kkNhaGrf7gyIcjhDYcIUqjpUviA/nWy/MK+njtvdTxPLyWR2g0Enrj/hFDQl0mJDV175IscIIZvOrGSVgJ2lLtZXtmuB/UkOZnaNKE+ih0ecT6m5k9JJ6L4Vo8Xo9pDtQBgYUiLwE/OI6JudO87oNys9WeHNn4wncon5/+ga99B+Z6UOmvqRPW9nx6q7G6QeEV6sqRYHYUJKSquMdC8JQYKqvVjlooRayzdWWUlKvYrcCMM9/AzYg8wDoU4lW3vh4OBiQ0hxnnCJ3bsE61+/+uBf55RnxDkZsU//HMvDwbh9Bo2SoMa+T7baUuv37n+3zq8n/LHf0eSEn7ZW7yIiAz59d1pS+hTMCni5amxOgtOIS1MxCvjDg8jU+KrpZaKXqEoPGZX/ixzqWvQSYU9vDHruwWbpWOphzC54W8BZXCOr8URSz/XufEak0sp7y6SWFR+ZGOvf0AhPVyEOqCXReSjqIAy9OQezvMM0r8czAdjDzJiAgSAai298G+oxRZ5hKECzXMSQkoQA2k6kGs47nr0XqiUq0sTuyCX0tKgNM6W+vkBeS1TFZGi8ZXtJbiQRetEuNCsO+5eunY72eIaPLJUjCIbr8QIt12cOzB8X09xxqTqsHXLaiKKjUR3UB3/dRLU68pSqzoi1YD7uvE7CtKQsISLYQD4K87MjJneILtHZPtMb8aWJXeP/SOdBDjVbnMJRafGG+3v1EvNrbH9RcGMvstMbNE7SR6POHQ8GxMiyDAjmZNGmzIzz087PFPBhCZ7gB0/izMSIUXiZcXJ9/P3LdyoIkh12tIyQbGvQu+xWns2VfxRp8cG07OyW0WlYMGiyECyyPHOuzhUEnxGkVz7WUeGXZozuvhSJyZRPwox+v2dAJV74MK5Sh9IdCwxYR3K3MMnUGA18InhRgncOfqYE2/9aIW0GS+/JvLjInmT4IvK8VJgswRiwPFn5oVRTMSujZLAGbxRMFvxCtzCFT1owI1k2jJ/qmDRkuciu2F4FSGef76PLo+uwt8CQ5MHNkXwF9YmyRNfvYGDmhJym/fVrxPN0sHhbS9J/MloUpp8JKl7NZ5k0Mc/QwfYNEuTuD838pAI3qD96vAGYM46oFYzkQEgRWg35SDiVlMne2kAd0EDg2CmrKqgbWiK7+vlC0EG9InRwQNSTMaU5lLzHVBzpb92AZW7HZT0nw77M3BuYsegWEav7R+PZd5tC6oXKrdEc7+a49RG2fgPJ5H9yxqrWAxvgiJ/erNg1tqF1GYwADZU0VZByI9gTt6dAD3vTpbcV4KrareN47o/tVsbV0vcpvCcBjvlzympNBIfrxMp0GWDMFWxukqUdsRONnDTFOBjub8DadxMbqB1jthf3ZlGoaBBIezz739fau2ZXNH7MQDNSDg34wNu0zqPmLgRBOa7jBMxKq3qosYwCLsCa/2hu6/uIxgWCw8WNEKt9Efd+B7TIMdIxYo7OHgkb1v/EMsDB9K8yTLyugp4lZp4q6x941cYhtOIvt9q2xh0UfupeAvOuAj5E+7x80iPcN0SJuxBE5quQB6BQMk0B0EnyUAs/7Ht6wD0Df2vbBE7OxLeR06Wsm6ShiQS6u9NPj9BYqcImKjElwyA8cDkWKPjRp4PrRheJvJ0NwIaZ3hJQKXzAvFwahV5tTOOAvET0S2fpLyVZM2hvGFZ0GH9xNdhE0augBT5LjKTwzfvxRbraxYxJE9S4ewVT67kHwWh6P+pFXmeh6Om0060zJI+EyWAkZVE8WxFw1dh+B4D8pF53uCirmR0ge1JerfSwlCTGHKjLb+dZttjmFLVcIVEQDVNHiwIVO7uap0M8N5bzCQmfQBMfKbjDipKBO2WYOriJnIqEzKIFZYESgVfphmugo8wkFMrqazhlpzqeDtoZW4E9tao28CLH8hSgYQxc0bfi5VuylQRxXTCpZa0C244pNdP1fU8oVj32clZq5JyIRWlAGxdFw+5iM6OTX13w09VA/NnFinOzmQ5hjrS+LPqa/hhtsHTn9AY1LmQOsCP+ooK/S7HXufO3xCC0KRUvNZygjuN0qenFoqKbgMJMAvumBz5bZW0kk0Lvl2bTYTI5FgXhg7CtbZGGOEwxolqEkUuUIEOVGYBSf8+5ZKdTyBGokOx3EgPuNZ0FgzZE6nbPdXkV9UI5F7RF0a3Eu7rYyyxA6UWXVd+OyXDBoHLPB6+g7zQ4XAr3IcMxNH5mQw0zaBtH5f7H4kPqi89rJEAkiQJjvRIFKGYgG8U7d6gIddVAbka2Dpt5nhmOa3a3ZSciU6dhIZitepOvlZ5nYuILyP49vE/8FkK1Parf74hjzbcr3Z4yZTtQlrm5yISjayOEO0XD63qp+xVvnq/L3Kz97VsFhCv1qrqKz1M+tqykppyuOt6UnJ5cURXBAVxB4AYA/CnEUu67MdN/PO5d5wsjEoksgVZ/VncJvhI5e+INRF8fCRodkoEi7SlGXptZMJrE0ZYaIL+KLU9dpVxo2mCV5L5gDj+As68MwTpNBYcxioql8Sez1c62VJy+r9m5IR97fZvDcZvt285ESyg2EOylFNHRkyWT33zsW1Xy081lZoFFwxuc4YCnpkS48W8x4lbguCQki2hyEU8ojmkTUjinuUSwZIK6kFwmOZCw5dwW1DfAaIoqUg11hkh6riuh2fhQin6CD5KATwhHl+VwYIQEPAlZz7W1haUzusrxCduN/GV+DeiNUQy8yGYPuHHy5+0OpF44RIibYcug7Pzgsd0MNQ6QIY1t7QY86zYbv9AZBKwJgm4imfO1XIZcN2o0qqTRpPVn5ODdEj8onDMUUutW/xiq9q3goC4oypOkzwKg39MbCNKuI2bTv87P+yS068RboPyzgYlmn8V3N2KR+fzfy8hbxTXXS6RpmTwtzZxzkCOViLIxEp3FJ+pBcjrjRkuEMCu1hnH3wA1g9M1q7Jpy/OLkek8KLyfnTFmUS2nRkhE+b/HIwJW1olHHE9UFm/574bIG6eKIe7tIsoLkU1HslfMB8ZUq3vUoWm6d1WtuRd2gxWn/y6LABZeLpV/o3EA7Cvw1Y+iRV91Va35ggtqgEnuiG7CwG+3xfpf59KNcpl2Y0mcJQuR4WaRUVUJXkGndah9uIqUPGvA/wGt8xnCOuWi02BsMR1tuqU1QYZS6rhQQvCet95sHQRwyFKLqdV0fg7JoiQyddyKTuJ0lkfGBcMkysLk2/MXz5S3Y47Ykcc+ylMjzseYxZ8yvTljBUDaBQ/pV8Q+6fk80cSxE7tVxzh/bbYfWnQN3U/7LtWog+JiI3iHb8HcaMmHZvYcnHHQpXoOBJqgyNJITgvYgdzMqyAJzQhzAniJhRA5q17ziSQQ4oNKOc78NoEXnDw9dMvEqt8wOFsh0DxGDQTKut07c3Y0LZCzkKQz0w1FRz/En3K5s9sAEofyu3f0xgJl5JPR5QG3j0OcpijlD/uXv12XlvczylTpP7bMP0ZEaZzBeP0CdFgzjFjpRXbpfmJFdiKHqoxSkP6l7eeV6onmPwldbEDsujLUyx4oOFYzGh4YHRG4/bs3A3WA5y+6F2fRh4RdwzXpZGULIjwTUz5NMlNRoYpBxPlIrjNecRlE6FPgcj9kdvkJkiDR5MKijXxNcbgV/Sv98aEvNN7ik21EDnk+UqZX7N4TCqWZENhqBKq3z44OkHjkTV7aV4taqWRuUhoy+N8VHfERADR/bqxUd8Uft8CtEB7rLWmv3HapkWhvtSPXRoly3Lk/o9oppZlfw75RkIdhafdsE0Ld5j07sODFbh8Hm3/2tZQ1rjK+BCJU2yJu3m03QNHsbhG2WWzYX/njrebwZDVmRxlDZtzt739IeVqWgsLR+FKx77YRHp+zbLARFdEO4tH8osOY+lEHyf7iHgCPUzSZm8hVA5jhNo7SPzQA4cWHd1NFyf1DJwb/X4/QJ6V5Tj3cst+X/9f6tYHsKROf34IpvgIEl3z4jT1FS6n5ewAu9jXtOuTeAdhG+EHcTTvt3B5h7GiTle03BTrZ3kkQ7DE+x9K7ZTp9jJ+vn9RjBv5PGSgwvwM3pKaxS4e6/XIDIZ/5MbKH8LgdzARVs4Pj9YdYO1xvrv7f0J9Lb4xv2LlNdKT7q2cdEGQeKlB/dQ2eHOKTwjlXmQBR9Kp82jaHSMSM6jF1NG5EVUL7sv+mYhQlqQyqLTVXoFEYfS70ka8an6z/d/d8g8XpWTFG9+3bF8IzaILkSd+zvV5r0KFcXAmBxl7pKI6Pqmz10s6p5faMsL/y2S2oLMg0XoCQXjTN7XEgiw8KrjMP+HWnIid/O3X2PvSFPDIqPcuQsq6pV0+jgKpf/lwGZMTDux6ieviXGO2jg5+I5nmKW8/DHiUTMB1h/bYB5bQQgsNk+Pw7s6AD5262omiTF7Jv/mxZeNnBGhknLZtDPQZyucBev6NBlPrIniQuw4vyhG3l0akZ2CYw1AZWdOiOhWnTbKxO8j4a3awRP0BV8X0+tBueE2+ZwgIxPxl+t/5hHvAh45gnr6OU5OY+B0Mv+qecCtcM4ppZ+Jf07QAp4mrJC0/HIKhAhfe9TvRFJHnjvTIpCIDw1Qmt23kxmlWr0l9Z1BWWQ13klnd3FRpVDEgYPMitOEBRvjza0lCKbDBg7Xu6SoLWmLWIqQAs3ZgscgR47JSlUQc/ZL8Nc52lnE3uEZQ3w4PabG3NUgmW1k1mUw9mxEWY2XxznD0afCa40923HieGvkezS8ynBTrP7HqoSBQ6M8SIJGtpciVr11uEmganAWvQ7GFuh6MgNoCCAHKr+6D1oRn9tql35fZp8ZuunWEldiswn4Ue1MRHpvPWzdzJa9cMWVJba3j37vMiJ402BHZoc72aNQBCPknEcfhvhIx+n2Cej75aEss5+MkgPFDlWvUO4udAu4xOQK4loQkeQ7M0Ubf0rALbyTeEiwRR886NgUXw6l3f1hzRtygswLkJ1AhA5zaHX6w/9mjsEUYsVotOdCf2NOPBep83KExu+fHhEgdTy76rcw1iw2MTJsgUBU1zYBuYtpZRdRFmdXXT74H+n2YBAKAgAANNu2bdu262fbtm3btm3btm2bN8QN8ti4qu07+d5RDPX61Au24eRRUb3TWXFOtYGu52g+a2WXLG8L6xdPMHgNdpNisT34+pOPTMFzOji/cyq2spfzZ/s3/6RZpcQrm78HfoY60yOApJVShlXzkrAvUXiCaS5DJvDWJF/FPfA5jRcj2Jto2/Xz7uK0/hiyvWwpCKd1tc4Nq8wRCbQCKjRE5Ssrjd/0VyP9xymg2wU8mFgqEePAiHHt8Ed9nUZKdjfhtSQthM+3oir+nltC52Gk8RPc6g+jtOC84txFKTUpZYLJrJAZCcS0ByvIsc+XWyeRKW50M052OoP+EtxkldcVv9s95sXdvSag110H+WHwBJMOvUzcfvVaMgU9GUPpTtUEYR1c1v3Qns0C8fhHJjJC3bLz9EkO7WMHAjXLjdmLSm+0y7JAzKiN7jpIlwN608gPa08wv2m0oJWNqZfnL08hgg4zdwBXRUb642IsyAhSBGr9TwMVlsWu0WhVSW5CPz7Zts7GQhEIdCqfIoMzfFaeLxMiHlEzeujNcxPQy8fwnBTCJ6EXSzNUUKoRmilMF/ewD9FI+bPoQ3h3z1tGZkZthXfDsB6axsxC34ri7e6838mA9DerxA8LldVjltqzy5PTshqOPYBLnx3aaKaDrzzV33Hvk82WcjfxNZOZwksCulnoGXq5BDxBDzSBovZnTpPvDmLsslajLaRewaivZ5ytGtMbH2gUov7GadPwja7wl0co7fPOuZzGNjrVYQIV9qm0+9HLye7hIROqCYwdccmHF0FQceugEoWo4al1eYrC2ncIUGzS9tOb76ZjjgfV3neURWcMJVUXzopLeVySxo7uSS4lp7u07o0CKARUxH5O1PIERg6sCOTc/QHj4XbNCg3JlQmE1TLKFk/S5+kZJDGAxCp+ezFA1vJmLZjEQa/IFT+vz/YMpAwLYZalBwAdx9LxrhH6CneV78E9FLPGTexgujlVs2Ridrfxg9+B8Gkw7hUjZR+E6fu1UwCr0L3z03lgTgD88uNEbFufYYQ4hbXerzozy6jzt5nVvAeu3npfGr8gFBf7Xj+4i8ZjPROAqIU5XCxH1W6Rup0oNs9SwPTNANHTt3a0xD1TbigZr212G9aDUevdbDgZD6fLgyUwDhD2j/YsGow23mkbSrzX2oh0N6jq3YquFL1RXQaabMGjjkHYmoa8zNX+mdDHrJv/GesKng9nz8QGYyeHRWCKukltmsDIINEMoy2UAZupZNOV4IZxDGZJwSixFrGVu7EOUkn62+Wxsf8wVMcJ94LWyWwjP8cSS9OwQXahOHv4dknHr7WQsc0SINuLq03uh9GlU3c9nA6n/oiWAZOclbDtRiFtv2aTY5g6dHR9JYD0PQStlfDyvXJOhfuQlOPw3KQDsvBsOn8zNdh4+TIu9APugZ8Z6cI5hEdnADkY5talgq9XNb4HT26/nZKPmXj1Ye4XKKw24PPojee2qBYGjzKcT4YhsnP2k92JCM8VwqWeKoKeJvHAHqKgyoNfR4uPRoL3lRdqnSW1i+9N1+pT3PhKVH35wSDlZOoM0TKX0XRWjvOIzELg2F7qjD9YCmSbeQr0CtDHfrErsfNU34Dy2NlTB0ZtEtEUI7X+UAkyoqMok2eslZZpOh/ByaGpgGmQ5HYXk8XUul3nK22KKJgTiJpvxkJGAjXn7G2OxaVpvBELynPRZnnj0YwrMbRi1aVmQm9PDhxS6I9W5PpTmPcax4wDClvMXsb3GUw8VJ0HTtZAUzkjpeVNjEsO9pcQf/HYOPrXw+wpQOzsgNpAoKxRA1B1T5SdMfu8bVavqGKXrDd21VIVe3R4vWh/LVib8UxhtOPeHxt0HsbSq+ZL2AR1aL8AuWNydN6ztQFw5BjP4rhHNwRtpPHs9uMREeewinam2RimINk8GzY7WatLEO1cDaHyK9SYRPNXgkHLBfcudKkeYR4cpGMf6LnXGpyMpJulMDokrQR07Yji2o2w+5TMTvDRE/EuNjBXZKYID2H5fR981zV4feRCmkPAxvwplSp6wpvaqhfNUbDdVOz+szlR6gF+Po6AiSyuZ8L4lxslhg0qg4ImfAnDvdzGSnDB6khZAOnUVWM/iBBLfMI6eBts4nxaY+rtDJX9q8iwV6srBd4PoNEgYouqHP9u/z4RtV9nIJRr6n7Awj9w6Yv1h3jV7hZQvCDiIQACTTx3OTF538c81soKouT5OVLycgwpG6RX00BYrf1mapT5UQgyxtm37/45pcS1KjqYcy6EjWXMj+2WNt/LWhIhPdAUwkltxft2xn3QZY1pD7EK61F8IX+VMF2uSaoFME84cFQrQb9d8y8g12bTPPZk2OtfB5QsL79A+kD47EQDbx428tzl0yN6tRpcGnugTaMO+KQuPviL59oqumnUi9uWRywluKx8cHUPTN3Yttl6xfuuzGJV7WtIyr0IKk+4cvEZKUW7PW5ErwJd3WZUIBVVKKfYvBm9WikXzDY3O1S0LiD/OhWJ84eeNykv2yvNkZSUqSw8WyOgnsrJ3GIdCklaNeSy35IaqV2U2UHgB7g/Ze7ZWc0Yz6UL5iJGgCEailU1JXo4TqnhpeFE0dbms6wc0yQ8KehURGsv00s10ETS5z1bECHKm/a0WDre+TCxOvobIURrscIJKioXQHg1gffOY6QcQxx5rEDlVOAJ4NiCZieBLhmf0mWtQFYMzZZ4gGSijN9llfyQzh1qKWAj3DAruFjBikbv5u39y1PFPIkGIDyyt504UxiTDdTaA5cE9yheOPST6+0Uh9lqglgiTPIvnHc5blp960UvD1XlNfgW/WlBjAPWPksTeXLQFoGgW1tobTp5OEHzbXNmrcIaIat+nq07Lh5wpGb25qx5KxPcooPqNDThE5hymC3ZFZAQx3RfvUvgiKMtxgTjOqHXrqLEX62OmU3g67RGyMNwYIMX3AfgtZy6O+pbHFGPY7SMQDtvKT7as7zcL8tk22EgazNVQXTB8MfAKOD5DGedpc8GzxOK+pCOdjPtKarbwkFmwyVbm3s3aihJthbfYfCwsXGxjBW/S1N13GwbkLPY8K5QB7zdYjoCmU3zlr+88Sj7Kf469E8ne0lCT+C+hsFlygSe2ZIqU+f6EDmgz7e9af/w/Y9CeX5Gf2M6xMJw+LhXbtRXB/xzXEgXRKOG4cL2aVWiGRmx9T4URyybTHKvaQF9GCmRjwKExWbhtJlk4yn7zfIPHs5BU8sqYa4Tiotv9ifnJVo8Xdx5X6HsCExc+ryfJI4kf+LFCZ0C6loQdzWmx1fAHs7q4gkeBnBHQkEWk/mLYuZ2UckpkX85q7ETf7hc02WfL1xh2I539lroO1g+a/62AWGFLU9+Gm2ytlNf/cnkmUR6YRaDhu8XzMoQLbSZV05Cw+xEPCmIplARC9qPVfbNoBDxv3ZFZ0kNKh0LfOXyfbzN3xMI890CxuR2MBHMdL7ZRyI/l0gXRVl+pJFoEDYdgGZcYGFoUgauQIol5nzuf0w87WcjwLgsUmv+lIJJbNS27AjgeVwnWg0F9L+4DT2D+s7ndNw+CUn5EQQbTo1UtaWYEZ7B2RtYxPdVCZjvVlupjDSPRrvsrpE0INYXvLSwsuyKWRZxp+HYQywbU4JE6eQLks1auWMQ2aX5pyTMUI4zNFSJTDuz7RN2P6GhjFm4pZjyXrSm2yhDo1sNRgAl8tQmPAcHL2ii56SjVBhwVIZ760maCjtjl3Z0H4Sm9PGNuWMaUkgC1CUiXTFCynAMOeIwcQXps0P7FklojES1KlrRZWr0zEF5OcRaAR8NoSKbHlrA+wJwHLoFNS1jwOGfL6Jr2Ibs1SHUmGn0VC+ft4AgA9NN5XQNBjvKoykqC3AztDTExVsv50rUc+ZIyVdgY2GEf2kbvXXq0WoSR3vi9YfSqLm1GiW2mpsAy5jl3z5a4qbu3FinND/4avwqVxkULSfsNpRV8NsmpP+0piDS3fmZZCRuAb7e4uuRMAoZXmIO0iyUtj7O4ntaxhyGjhUcz11ygpAlfqyKeno1pbz+6fD7w5jR9zLSxj+0a9k/VeYq3AMK1/8LkZ7hYduGORxIwIdlTg5q5UFmKNam7hKdf95zbPprYJt88+3PXGaVlVW5d3E0dadtCDBTjLM1uF58CrY4jaJXriaSmsEXKN/cjZBk7rruufwNG78GiZ4QyPeAZ+R0xcNuAp/wkAFylwGzOXbjdqPJe8TPoMh5xc4cmU8jig7nk34huImGSr5Wyu61trOB24DKld0rgmpDh6cz79c5Kr+SGdTQeCpduhcjnTuLAOlNUauEO2IRmQ6WvJqViDmSkRFUaQGrcrUT+jrys8hwfZdtz5Ont7pJZ9LGgrZlslk+Jq4BVxAeSQ9PHj2WNQDSexWUq9hYOKRdtg5JTAHXucHpx1uIfaXMM69svpYvNBa/SWBZe70vdjPu31fwy8hol6Vm5RnwMARIW9Z8OLUhoEuRutm/YIZLKo/73ZAXFNOe1XqIvtdh4QdlcNdTDiXPjiJPCd8u8BSpa8JLAy0O9cepUBJHcoI7k+IWoXXBlVQ1keg6PHqU6SeViX4zJZdxzAP6fWKP3iwqlHaj8WNOZpFPYn8IeD6gXA+GgYVPX/u1+sirJwSXgHJ/Zyfs6tS1ghHbs0nGFIt/Rp0N861zxk32UPLTbOONx//nut5rUjbno/h6MQ9Ngspg2+xNFZziU6EJVfwEm2Q8YITmJB+VG6kwvDb8IA0rFRnsRsbM8GtZR/PXESmef46nT7Y6sAUwcTik+T7BwkF3NEPx8XdgcTzeU78uFJDUH2BaWkqbAwn6mwPQ22/nDGMoEsCGMA0w4n6/yh1qGYuzYnC41Q85nD/gRLYohy21lpMf4Xhq0Khg6sS6NAF9aB+6l9ZNQjYFslur2lg4FiyxfvO8+K09Mm5jO1JPbNFmKMxkXbUDgn/ia8zRU66y/WklANgI9G7Py3995irHYhDTUIxKngzSIN1WMWHzI1Prxr0tVg9gg4kZMLRmfmKlaleWTyHrVmFTCV9jrNOcxhtXlkDqtLom5HgCDcu8Qr2CUAv1wKRiYzFtp+OWRr/QDfEHr4wNZU8EeSjPz14+ihpHTzyVkvRToSCFJVxxcocx46jM3YeoLY4RKbHF4RUEeNB3eMUZRxM0uLOQjZyP17co2Jdp2EBwzwZ6LtwWb6uX+4IX7IsFn/roH8tUAdtYzs/5+xYQAlKeUZTBM46XpKhoIu7400kuIh/YP2DswWzmV1mV9suNlqlvFUdE53uph5gIjrImz2m0Q+LCuQhQmOviGeu7K45ymc1WSunlejNdSNaEFWdx4RRGiTGcg8ttj5ZOuX9CzKLvWzjlWnZ1T39epZQaupv3chsSE3M5mer/IoXP5hnumP3SnhacCEAZZHHzs/B3VWvMhDy94hJuToMZFmLqOalNdGeqQNNZSg94+zqjKgokN5+Xrkr6M5aBplbl0DGBZ9MHrpo8dQLHWBGW6zAU0enDUvBa6gGPw0C21OQo3Wk1dH0efP5tnjjHnNW5fRV3330GQNPPRvTGifXSoiOYOQqyfqMTj53cEoOZSq2yvzopW5fed0Akhci4Vx7VN0mmW3ByPB4lC9csoRS+rjLqSfbYz+2LGIpemFgoqkCfYwtQdIPUpm53+VgqfricaNliqNIiN2kPoihcdKNA8zZUqpHueKU5lOg0k38tgG7L7m0MaGlto0j7GnAXJxtrQ3YwdBsdwhAt2Cv0T5gnNgdwKVlwCDNd4ea7p/B2DXUYGB7eI1hszLK38CmpoJa8ZsGeQgsgdSsJnDddR+6c9TasAp2ePSMxF8VyTJIwC4axQP/Exkf61yGtkvKdUjn/4tYqBjUqWYpQJQZW6Y6DjHVIAOSsgS6RbsH1SzpMa5jass4PhpDhGzzNgLyaAT+4sFarpj7by8sUUiO8cEDZOh9gq/i3FIrwqww8NO+y4btYi2agp3aGKS/3wJ3ekDkoMn721KMyGfk1I36bmhIPBdFZ2WBbAKGZbCrSL/JuuzAQGAkYJKqA6iWrAlovaFToGj/le5zTtspSUzhKAuP4PXDDL590x6NjkRedRhwHng/9WHeO/AXeyvJ6nv1iukgUIyfmKAUJtgywVbd0tFIjVoIMautxU1+ot/MgEsvEuPMZkh18SwToVEyfPKZkgCj7t+bVdAbdpUYP7WXpyH354jgmrfM8l7cJHp3fvLOu52JjCTTTSKHypQ9uUxfLOxbkyFDeHHrjMVlreJAn4EA7KVuES7vKWy9F2cdHfW42V+6Y83k/AjMEXDNO1FXw4oWPrwqw1rfXwpLLIuSeSIlin7xx35Ui6GsVFJeNRfhw1OuVJsSFU12WfZG4vfCRn97KUEmH8Q9itnMPFNdMR6ycCbWThHM4vGah0a1mpZWBEwP/eQi8tbWTaOSqxmWEEUgoQCjAi3OXND45q7KS43COSwJj4w0XMdDJKL/ndo2Q3Qqv9/bk5hbMfSvbamBwLhQJWWXMO+g7cfE65ZSjEZ9WgDKZcpIv/94pPDy6SQUWRQEa08yan5jAGJzRtSO3UwpCi3BHEdhqxhNt07+OIY4CxAYmWRpBfUuPfA4zpeCerzrB1b5vGOwANR22pYo8FnTOuZVUTwCZtNcghx6EtLus+4cVq9i4ihzMZsobbZJe1j/XcPM22JoEg/OXDCJPIanv0OVYKJu/ICd2xWQ+yp/WCMGopxWehPNqBueK91kBat8qAxaTLqaB7OsI1L99KVlEJU1npW6VXwFzWA5qqZjUs9IRqp0lqlpatw7LAusg9Dw3oSgmHnM/g4kjZ1y7f/V1065iv+TGYtX2q03iNzGv2m9bnr5Mwqgq2VJajTC/4/IBaWBlzWeyS0zC5Idp/YIJr17azxYp9EM+d0b2n3mNl8Hv0SWww30+RfzDUEIE32OBCyCo0qn+cBJfR0Wtui43nALFHm9bWRnUpBqcXW14an2lIcXI+INOQqJEjW51BH8Rd7sCcP2aMFqzVz+1D5odasUTaqUD6KU+RPGSf+JqqQY3Qp3Pk71f+R9bnyhTuLvuJJ/L1VJkAJZY28VvRvGlJH13PFNAB4k5469Gkn6dcs/xbJTwjUaqOc85XtHD9j84vv3gfKOrF4Ww5Io7JWdtuuMbxPNx7dqLw/WKn53RhGMfuxd4bRNVqAYp1NR9+ozlPnC1QRsCbwWvyfw3nyEdPRQMOqglBlcT0yzVaKfJZfB8zGNKV0smocP+2agwlwl3TWz+M01r6RxIP7FvTwAIlRn0AsHDfsHXa9pYOqTwa3CmX4ODY9OpKlPISwWhtw1G7pUAyCYqB/lZcg1IsFPQIeT4sg67tj4MJyYLCmlxLC9YRucoL1wCQXMMIhfwCBiO2NMujbBheRfVPotSs9ojr1sjiUYtTfSDmDSKPXrFKIEv9HQH9HwAgycWkjFOQRxJB6Gh7Y+5Gg7b1gng3A8tmldXWJ4tCCVVqGcPt6VbvldFHbyvxSMAvhuvVfNYEmHIyLa7rob5iIxyrEEh2PF09+IHgbcFKzBfelgeubDA3MXnKK7rulUJUw4G0DQoJenah8yVN62FtYA4UWZoVhNbL7r1NMWlPHUDCOy8kbqEN/fWMG+xxwZfexOxiXhPftj4gUUTlgSaKUtTiD7g0jLTQfnP3UTy4F4aksBTBe8bKCG8LhSLDcSAgcswdtoAd5Y/lLozpZUaTILHAktYeM/S2akJd0Gyio1IbtNQjqv+rfegeYX0eSSMlzIr1s6C2tPCDNVzJwRGiZPItFSqHFzWF4QZGHaqLoNmTP+2OQw8Qsyv/JIVjX/hE+gYI1aXhmpHZ83Vk3kvHH/xqDlwo1Z0Fy2lD6taPu2sKeAVzjxH3inKtjQUWNVg2AnvOY/KM68u4vorrVQGI5gieIATlfqnAMUqvlSKbeZoJm6EwMRC94jg/P6XH1erN8BxWc54Z6R7cxgpn4t/dxAxbOM75Zp7+AjnAtxbbRCkFUNBWe0q9Tk0zQNecTK7O4muTFlesWFQR/gOKDG9sFJ7XRlcUxtu4GH8txASmcihvu7zg2J/LTKF8d3/GtITcg5zATVfgZsPkDzzn7yQovWAeRaLJ3XU4HVSbC7s/R/9ZcGdVNlPbAPVY2FytcfV/cNbYPMMvvtKZ9Qm7b8JFV1dzKMZVGP5ddEL0Dfr9Gxtu8RkXIYpkI5oAlW0br1wKle308tmFzgnAs3c5G5aHvjH+a7z9wZNor7uWFkbbdz11tY0S2FNWbV3qHiNog0/LHR+7Cj71r5RnY3IbxjxNK1E2W4il8z0PTZYF3j+suuAK5yKwDJddin5vIgy5cE/QMMjWZ7h+Vtgzax2rzDpgggip6zTMf1BA6sZwF+I5p0v9B5RLjGMYLRKtlRisSKccKdAPYSE7ssvujvOD8Cnl1dFWzbrIdWy7WEBMMAJaQc2GZ3FX4IR68mVSBgH5rlJ0axt1fu3XksYHwW6iD3JBly409r9dKItFjkEzQY11tuWzNlG1spRSV8w2K6v32TtXL2vHFUe+NTnymDDAAeE6YCZdX+BbtkA1pWZrk3cGlCFEJDZlfisLDTNw55oafeMGaLKfbAsh4lf8mNQYEnRLR/qacaNwIQtoqfcRdzHYK7FWMgvFzlDR7/bDLNi6xvSwkAh4J/ac+LBE0XYIkAZoyaLjQiFKS3VoU/3gJTcpIwvt9yjrvhQPZShx2fJq+LP8VY2/A6nT8arKgcPRqJbeJpgwIxMfrUUWSmrsJk5NFyfpMJR79jKMmTescsJwXcF4o/PPx4ltmDsCHSpFpExSkaygfEifYcCpjXYW/h259UJSlg41Gl1QnOvuajunQk2tQLYDZ1fA7Wfa6OIdNuEoJ9Ei5ncznqCe+u1RdvPGNjObSDIxqiGWvNaXhFJ2dbREuvGrPMNBBKlQaEmVe101tiIaMq2fF0oY9B8SLgvTkv+yf8TZENmvUG97HcaZfwdfcLyM3RFK0PeNCmmE/46yKOXpGvSLKsD1UjpMQ/L5S8bCXvtSL5L37Iz7kVTVtvkLm3LHkSLwehDySUARe9cigMdA6k+A423xbzZm+NmNrqCgLqL8tcPb8ZFKKTivk39+BA0aVwU8rDYDlErNyo1P5L5nAtpY4FXIjz1On29RJSsRP7CqRKZxJyOABRVovyRTLu9VSWFlQ0vhC0yycvN13l5v9opNBHe4n/JmAR6S+bpuLpW1bGYMsjibXxS4UvygWMLPZgriC3oj4xQqT/G/DDkzewkWbc85VwbqDR2tQWOP2mgMvk10HA7J4BtxGjL31PiJntc2KmWTKNuPWKwIGD3RRE+66uAE3X23ZO5LtK+B71Km/Vkp61v0luuT//8CJrjJP34ok+iUtAUWXHCRPpdZprcF2QJXUSrUwasIo+WPp2ECB94UadAVibyxnrdKQaRRzTyZWlkfJnMtyy6z3Ac9fmeQDfBsE4Ud3rFp4Uv093EjWTgLndJ2rB0O0PPZms78bZZGtDm1ijFm4Xt6rDwB2xCqN7Zrlo+TCSzjpoLv/ytbJP2u6kGe57t/Nlg3Z1AwuM0xDu47XonJhAZ52+dnL+JaAe4/xDy9sjghiUYaUFfkuShQcvVpQ1YojI41v/eBplihE0l3Ro2ad9BtFfQAkhRlmzXXMe6x0tQZkrIry5iu81u+MLU4v4R9HGGa+Q8hQuNaXgn7pNo6wwHd6BiZyq9pOcY509eD/6bfahUVHMbJ047TV3OQOxbXrkjz8hYyzdqQj0ub92/LGTn3ZKvYPOQjoBM1JcDdcZMGaCwLgtlWqbNxs0D/zkJumiIbuMxIbeYThmAgIqRhdZQu0w6t5X8dvTZk1EsK+X3AxLLNNtCcHCezJFWVk8aaR24xIJ1PB49UTnR8FU0vqQS8NKIaoqMw8zXWMhj/InYQOTnjg2QNwckOmCUDFMRwrj1SkzjeIWSYSUX941pDKtimixGljjkJkxSiFNRpZ/Tit2QfDoC4LPgfAnGSZFrKSewBWb+aJunzV7ifPJDGOKeFyscQdjQV5QXwZLESN7MKrh2h1df+QILSOeiKPYvE3RPSby7lGnG0evJMEQZU5svWnZbcicQTcpaUCdvLMsdRWGZcWZNwDb4GHDnMG5qWyYroTvr4niIhV6zCgUHucQdVim6XO+b2O+4vgdiP2BNeSHqSwk18Y2B9PtRyIcIvbFaVQhKpTIrMFqn5axCjbvEANAHKzzQDQ5hA55tJ4ciKwJSiFCJXJfM4GGENcZpzJSlLaIf1GrwNFt0oHKNx7PU1xKoaiXK1W2anNnO8iNxdYle9e8nRfvn25mGQbK4xiQjrhcoiKrQDy2NN10VDxvjFp9zkl10cONdaBpfukfK8Y8AB2AnPXSExgeWs5iDUb4LsmZVVQKvXZdTZNPnsxMbDvnNaa277qnB3fqcl62tMDjhmL3c6AybY7lzIgFCUv6OSo4R4LNet/tpNrS7ZTZQAm3Bb4uCwCj8ditsIqrVWfKsaUbohZ/t/dMW5JQv/meunw4QmyeEtK+al0CSPH3Rs/RJ3lSZmkdHzg2u7UhvnNq9QI3zL7U6V+Z79s1VtWxxRk/Z0/SY69Xd09dE+EED8at8uU8RqVRTzh2L5e06AfDZW846rx28ZoSlFfrKhiHDGv3Dvwvt7AgYqkMgd5vKIESM0bCgnNzs9sEHz9QeJE4IPIkln+Rfy2Uzd+tbHNrtN469Z2fyy4Q5Mun6Ks9wMnUYArROD8YTefCoJYjgrEtInG22Sv7lm2UWrYauvKBuhVib1/i6Od48ahOu45jOBxyvCWATaD8tpj6nPTwxoHNldOTbypa4o5+r39Q7bJy26cz792zYq4ps40nyY9qRqdI6kSkmMznSaDLvE+Tj8pJZAducKiSuYlK6rAv46/Ipwy3+2PCyAHNfTEA7kDLJSTLHHfUC/a6JsQll7HZH6iHlAo64ff+I1qxBIaCd08WIAJocwrUnnWVYr8Su6flnzjnBaTodtKVuH7VCjd6EzQ1ol9g5bbq9dXVP6MhtTUcMf6RcAKuZ84T9AxmzHewyEvBm7e1F4wEgC04FunY3Xe5wfBJMpsnx5ICHgokEYl8E71GMomMwUykFjBlTRcL5ynq2bTtfJafUfPpfpPRYC5f82W2E+d7LSWHlDKouJBwiuojbnnCzjlcdA7OvZzwbkJil9OkUUB2cNYJxtULUHzEWcVLipumLGvBiK0UFO+e25INOXCVVBLiGz4Dpkf6nv3qVL7VMg5SULJ8ldc7jzcpcWaFRYrIho9czojkV5KEPpDG2LNow7dYw3T4AwdqIkI7KJFzT0jrWfR8gnKOZaMqQvAmyxnekhwPQMXacA2atLck6zPwFlzAwQSvQxyH8mKCmnnnzPBmm9kHo6mXAAqEqO70MUW0+JQ3MtnJeOJBMyTD3ZsNrmGaOMVlhsOQNh97eHcor5LqjAltR6L1Io/mgz9vS1FTkX4PMALzq8nqmrzkz0drxrAZyHsUejWPFiBAM0E1g3Te5Scawy1JEfTpKFe6YsU4fOKktatPgwXa+U5aOPfJZBcKpIhM2e8xBo7UEf3uczfR8zaLzRgYL+cdSCFxM8+vWZojsqeR6DwY9ve9YpjePow9V0PEdenCl5xaOjQtR1HjaNadWQndj+oU6t1oR4P3pDIOxhpWWd3fJRWeteHHLejquBjHFY83QgbJ2+UjUuixLs3dH5mHwdnJ16zF4450JCQ0F/PAlIe7COV5bjjVUq6+gUPuZ7mlu8vcMqFYtirupzf5Zg7S8qH5xcb1ND0HnblUdaJwQlbk0NBBpdl8jtmWtXNntz1bJI/xjKhrsr+U9yxR20HEybFU0R+tp2nc2B9I1CA22polzIolQYqKMloCGkJrGqmuvkTTCxl1sjOKCvuHn20jnhmL9mVaAXZqxzBrIVmBdsia2tiuX9hJCpHOlcEPTe56fPfw81WF1NODApamS85zmpRJrhIgIEQgKn4Xb17elU/cJO5RKc2bICtQ8ejbANZcxghSZHJTta/Dv3s8tjzsdk4Lf8LMJFcYUTC/BbCs/+erduMiND+R7ByZoC0/GC98Qm7FWKpS8n59i0znSzelgH4APc+NFxaWaewQpt1y70Rud14YYOpqC0zLtyEIO7phI01Y/9Ev3zhAyq1XNCE9hXkch9t+TZoCjCpcl6gOTbahXjzawmab0xqSKEtlHPIuEkGkfiy+O/7+wGrU47c3Wfnf2MsBZfSwlJBT/Cg8jRtV28ViB++BHB22MRNhUQqzxE7YBNDg+r2rfwFj+jozrIEwrc57Yu76mhENHkSq5IjEIpvNfECDhud1flqCLng9NF7q6vrbrjZoSNtyLZFvDIMPRl1wfCHBPp99475bGNHwqp/IeYpOUEdrxJK0qWMFgdVHESORVB6BdEGLCSF4HLYZYlHmzVNH2e3RCnGomakhgVI+hFQuzBREcMyNPPk3irt5nYA4/hrC/HW6dGDCf34pRPK7W784a3Asx3MKIyyhiSTCh/BqF0ZIijTJ4zod1v7z3C8CTu5NmVDD1xquBKDQDNo1Oe/11ApgUpM8pbSdARJlt6qxKrV2UyI2+nPX3r2i5s4pzsH0sdOQ00vdr53Q/PBS65WPpBlaXY6to7/GihXniuoKvOQFTtSiT5XA6IZMwhanWe4Nx3ejrtIelMdSgJ/HyvNfFlkOBnFSA36oriIQHsLjXtlOItBGoDoSNySEtk9hbc1RrcMvj1tEQ7G9YJQo0PID+Bk805OI30bs59zlJk5Cys71mAZzDbMmvwlSES8w74j4NXzKhvQ2Kwd+fCuy+MHmFnNF+Q/QjA0eT5GAnbpgAmVrzN+kE10cIk/cRwRSRQtVPve7vHXD6U1QgKpHowbysBAKq95/84IpF6IojWkACMi5YpIgnV4wN6ICwFV+/u671AkcJZxGpcaKLa2u5+Ma+x5wkXTDIoazllr2s8lvpKdu8a+9NOAV5tjhzuIm+h+5mIWu29anvg7/K4KfBT6zd9pwc6hyusC33o1+tL4SV5aTN/MBdmNbwvPoIpWoPANJs6Vmrl9EaA5afHBimJ36/Hi3dAO3i4gOVHB0w7HKnGLWgXf1o9VuxjNn09cEXqqyCIxJOJT9APSe4/tOF6UmmM7GNL2nVYlWAYHknKPmLCQTf49js3kGYgpY8CpqU5A2dVrJUntIVBtrKVpuPNZTAlD9+HJ/YXhdZPV1LBCWiKPqqlvwmiFfHxZtHOBuDWovcSkpzH1DHR45mC8s/uBY7UzhJvAeqpSIdDbn7YNSLEsIalel2jH31MCutrcKrbSRQ7ZgSyy2OJMHEUl83BdoYn6UQQdnRuhdv1U1dnQcHNUuiJ0GyJlvpiqZNvGPvx3fQFtEJjBDjQZry46IL0C9pBQ1XF40S6vDhjEUgonWqgqDnaLjpPB6qm3chI65I5I7bXaKM2p2i0N9RRq8hHHOcLsiNZV662N+qBn//yQK2n2AInvI6APFLegZuBvrC4U9cva+hU2epTu+vVr2N5WHryBBK2L+dwRZU/InEs5LbdJGCWeSZReAZOGkyCOVu3U3LuZseD+sdv3jFtVCBmIDeuMzd2cBOokVg0cZNWc8zxu4tjXzEnO5TsV4jgRHEkDWB8yqE/XpVgiYGb03QlKH712Zxb+pRMEuuQdyjaMuPDxU2u2cPZB+Fejt6ROLdvOB0O3LrJZ5/7vedvhx+BHSAj7E9gPY3asFzB1BvhcL+oHvsARidqH+LkAl2wbg03mkBn3R8ukuLsfItCi3bLcO4KDf0Psd6CfJM6NlAC6nY6DIa3uow0gJfX/y3vANlYi0QCMtAYwbiHz4zZ0Y4JIk9nH+R1jRwQ419bz28AWGsqDWT3qheV+KFutdeOW8orYc+jWbUmj0wdOHAuSPNGXQVGmIbKybz7dCW3YBvo3nItX7IIheB+nwTkTxRE/ChAuV2Zum9kTBi6X7VOXLT/Gw/hbQnDcC2TJmtH1N+OoeYr91k/AlnHJjoMuY8pAgyS9PyMkBlK+OUvj4VvBOcL921QwSO/P+2aDDT69JO10aNEeNHL7B1w2UHrpQWYNsgLRX9Q6iw3uEDlQUb28bGuVOlVAz9dOJumbrgnAQ87yuaaHSEqnraEKxgWnWqjHWOLzCadSVM9ZIc2Pc5EiUZhnwSBZFvzrEIXpxvqDivYJuAEfx+qJIZa0yQORb+CmJHpk9+2Zoezxf8ytu4TkPwel/w2m1J7Nzw+lWjdd6MHxnAoZEf2XTw9unG319jS82hI3ezEUuOnm6ThlNLuaB/oFh6WCdkUuCN+3ui84rqCdNcZrhqtU1Ocrp0A4EYzz+ZawPiPSv8mDbJZ/AQNwU9qnm/Vvo/8a5ok5Pi7EwitkzTmHA/Nec/EM3wufTFtPx6JZN1lA/EGQBw+1VWvjPOtwPzSwE86LOg7h9qb8nDElf29SdCcOtidCtO8Rra9Nunch2A6QpBfXpkfwvWIrXf2CgUGFuDR8VwudDux8WXoEr8O3W4IeyVNl2RqK2WgYHfVPF/vC/iE5A0zDmmq/YZW2akkNYEPfwaCd/BeJKW9uvjgDPEtOppJuhiBH3fEQSSCJGjmkV1mSDAqRveDMF7ENLwnuAhm4F1n3iQJaaZrKAQboNUp5wy1AsZjHDw+WB0Md2FhyFnOnYcAPbKaDs/2CGJ4clYALWy2AoVQt39WsBJnqI3gdnP2rMnA5Lhx1pRFdNTBVFVIAd9nu3WAGqft9xyo6HYhYNqvyWUailnSLOAHmRAlliLeoq1XeTSXKJWCLcw3tbgZzn6iRssHP+IgR2/zBaEw6N9vn/i1K2rXNvaNPJG7W5rFyGB3LdSzqyvh4HfErL3VC4MgLg7Hel2Fm7UAWCm9K0a7ff8sdWLeI6t/3Bao++FDcUC+BBOdtxhMUAC0mF90KyJhTaqy7bMcbDoQ2s0J6XjI5F5V2mcMbMuIfnYAXr2iBsb+/Nrf2DYWwn4WKcBoEXz1V334lLAQI92AZumJnW0jibCuRxmH+pnD3EsCRP98BilP2WwS0xPT8a8Hs7caXY4oCo7KhewDP45YUtg039TuXFgGlGH0Sv3xAa3fDXwHZ7Q5IO0DsimE9hc2bXbX7g51FiwLxeCIB1znQ+g0KHuhCms17vorW0Fd//+EZNWgUyWUAp3gftRVtsBqS3lOID/zp4Y90dlM1I4Q3wQCMZnGe9LJhhHlIcr7mSn4wCTjYkGIHNcjnaZjaL2Bhd2tRWT0pXcFqGaHAoCNEGKq9H6x3o0p5SQ85h7w6ieday7to8R+x6BO/Gb/TC60RAsIL6Y+O1Qh1fiXVvDs1Xiy7Jm39Lpe/3knX9VoweGXJ5yRWs1qD1HHPXsa+2jL1rSM+JOG4gb6VCsoJItryqWBgu9y6DHdovx4l6VoiC/2SWiLUhsWiwWskWE/eTT28wRq302GgVc4Qm5iOHqXJCsyUrWqLRGCjuhzMkuMXY/naAw5CVlM0CFCCh4OGx2PmbU/9Nykygon5DsMjU+O1Z8In7c7vnioLI7DNVcViht8bVU9DlgGovWeic1VdOZb/VJB3Gp2p03awQzf4qyDSbQxIIgA4s06f0pmxM0fiSS2BozbofyJzODzsYVMYfVIa7HdP8TDKB4b4a5isQ3KOAuA8eTGBxAj1d1bOocoIqc/xKOTpisV8C3SxlpuagZ0B7301wUglKXfMQ+2SdGGk1EYn23f1olzxYRLufIxNv8MnFH//yCts5V6xq/zv18rdOOv/LUkLmNj1VFmHx0g587xKVJ1CbXMkQL/aGaMQwdayEqvM8Yv0DQ3081MNTLNQZJOIvk1bnafoDEoG5LJCL5Rpugpbj2y3+AahsX0GddKo8PI4RRTW9ooisfNVpSufkrw0Wf86D7Bi9m1MGqiN1gFWr2ABPLUahyUSXNM5scebTZcfx4Bdp1RwS4TSW6t6POQGzU4ELO224iw464OoDTsgbZ2o0wZ3giCL5wyBhjI9hRJoudJx0xVW6MmXAvj5v2QXp0ps70aLjTdwWGYD46xc/33fHnrbot4B4ryjhsQaSvqds02zIoje5Wkl51X4/F3rrkWeul63iNKzD6lXSvPdQ0SggYUIh3PPVeyNIWl0ksM/MfwXVtZyVctgGhRHqZ9rMAsDXimRr3HJsN5mhTgFFz8YZ61yiTnrURFA4EWSrUk6vd9439t6nHoE0dY/n5M3TcN4WiVTHudTA6cJmhSZgxHXUnkKaKQgYHEnesL4rQLFeZ4G7T4W2gYw0GMzLPt9H+G+XkePIeYa97Ebhp2ibM8RuXFGoNEirkAMZL/bNqAhaD651uSpWiG4XiqCV46F2htg5Uj03yHOO/ljgi/GYDTz/07N5iUnlU9mZdweUhgrcKcIhHgBQYmk6K5nd2qQFyV9ocJU936b0hSw+83ilQwGikEWyVaUUMUMSewNU3eSLxJ43oG6v+C1lvprg8t3w2mWBCOfMIxM0oCVFgMeihbIfGh9R4JKz38MeusqPp7bbYW8x1CGnkhFKHk0c42CZwRTM9iao8Mj6MQVKgXhrYNzd4joNAAaMHsYFKyfz9yhaa3o1rZt5NIutUizx3STVB02gyXkxrUmpoOC3oJD01VcbRoj8JoSHYa3Cf6Tgvv9u5mleiOZ3m+ZS3ksr9BcB3AJ5hreqbDOiKvxQwZW94s/5JPZVt8gVHwJhKhstc0OO62Snr6RvHpY9fti+2pP2JOt0dOnLR/vIprAGlyC6F3VZCjFbYwdYYS6DrB4P4qwZo4d2SbMRnoQHjTwzdzFaFwtH+STV8XBkuAhUi5HcOOkK7qdoE7Kw5SS63ORggsO+JwmCdIm0lJsSKD3jTHuBi4IlBD/Yv/E6+ASj0+Yw0iWqfWXqE7jep1K98ZUCWVfKNqnpZ2AU2B8I0mCEcq2c5aDGz25IPMY+j+/UmgMqht/72y4W8Qg+y9tggG32AzPTflqtQz1CRFCY2pSktfrJLWir2HZK60pOHOWQ4hiAYP5dN6VhXw8Vj3jaGflctY59pHQqhsb/eOGnS3Loxyq9a5OoqCcdcc7jmIIvgP3Isq/UsXDjDkXAVYRATaPwboXyUW6QCgguz+tKh6G9elIXWt/RWgo/YwT1YMLTP+TDBX311itMYMx1Si7aQINryoMQQ/Bgxr9ZmxjcwFXM7E4VLnx63F6MkALaiaIedq2yxkQ01KrfCdNGLon/IBZgi7tVZVVz1g9JJDUcuQm5Ypaol10nejl5rIDY5DDZYisqrbs+957reqeZzpkgJc+eNNkoepgP9M/EZvsk+sVO0kZ5Wls+GNjbQPFBTKMU+4wsO4+jnops6k6eSPrelVhqTlyKuRqftUsFrbJ5BtOTHwPXTr3xtEyk4PbPDOIOLLyAGzQHs61cTP3LGn+rRBpuLh76TvjbNxAfr6EhKGwwExmP1cAnWe1gzT7RI9Yk1dOY3+AM28w0Go1gFxDhDShvySx+FVKn4YVIlyE/TmZtfyTrhgnE8oo5zfu26OCZ7Z57DmW6xZGxSZ1XoiGhSCcHMrlWHfqoSyy7cvh7pK2J9+s+2AsDUMGvOBqJUXHB6WoOVqelVBYC1AdYx0r3XP2zfFwc04zJB6w26VodRpAik8TtgWTOrz3WSJDyQR5cLB6J8L/suMdbszNlnV4uqi6nXYx7hlcMpHyHsqdGFYyok50Cvq9u+rWRIrtJOrbqGT93tBTtyQSeITvv/UHREa4zr9VdJoQ/9/VePGE/+Va0d5p3gFkTUBy7mHs77smd4OEQUU5i+ohIVIf8u7dyaSfKWohR0O2sjpCdb1sExRWRLgJNOrQ4Qt9xEYeaoIOfWrnESf98t0dXgUnwVAJAgx/DnHiGZ6F9Y970rDwarwMp2ZHxaleZo9rL/adx8aKEN5wtY2548NcgG+tEzsiSNPyhD3c4YHdnUfHeM72Z1FxXSCdTPf7VRwVZsyKKyZr1Lo/6BQ2hiF35iFPrti/LC3um6r4EHfAVOUnevLqYoq+gzylxaZjhM3ylrsn/q8BwnsTcuuRnbmTseHbtAATDCSHAkgqm01uUzeajnKDkfB3DaEm3M8IB+7cCXpQFW1ZDGgxIrSKZiIYE0m4T1jczVfU0VEuOisrYHPWtp2h9oKtAoDef29skgw5eNMqzw58pkjUcRutEUvOEqBCjv9WFV+awZrjeODTn0OEO5z603II+XvVm08YebHCA8l+EYjT+A2TwZHvK3O2ReRG5ldAks7/j0iE+mCZWUXBA2yZubstkCD8gLyffv+inO3qsMRPMkqt8yqzrTwaud7AQHUJoC0XsmZjbypwP0E2SPGja7B7eeNWkqhepB3UlP3KivjdD2dYAH8G/RJxXs4qApTzzW1Ofx1a7ztlOwGW62+xf3pZnv7j4MwjhCJvzwFRY5M+dUiQKAoiynnYu7hdt4pKNNZCahWW9ZjvKmK5SuySHiA9zeRJH4685eerBkfARO2KT3x+cH+NbLy6BZB5+q1xYJG+zJvYR85uiUck/cqoE4/cCKuuEzxCKrBG8awJeqT/e6aTLzmP9JQGF4L683pAeTqnc6hINW47kpUIi9c4vGd6un9kxEcfJJ7NfcMr79q9vgaZ62c5zttQx7H7poQpPj/nb4suknnKkhAY8wo+Lpv05qepCcnfgWSbqaMPrXcpbs0MiYngk/n/3bcZm7Hr07fnJ7Ozz0z6Fk8MaSAJHoQR9sk9hXA5FwkWXDMvMQxUebnGo5zYc0Sxqb4M/0qnaktqcWkblbEtMhFcVtHXxkfa9APm896ZJRfcXDD89BI+ttwnoxag/+E3M9JSRlZmcz1V85M2ywe4JJKlOClQ8gjDaBl88P01L+BwGMd+PP+6JW4ooevbytRhUIAAROujBSn8UrJ6q+VuU8VMviBK0PQHMibFEEiwRGpBmoLqbIb9avPutmRbS6UFyfHLyX2QSO9pP0K4fUorvuQTi4IEktWeR1YQw93SVOqRmvHrqovsyBimgZQy0/aibhO1XSJPDVmrPXGWQx6Ulp3t1QNPN2HRYQbLHNybYKETe9xM8lhNjJk83BlNz1k0hVf1YK1hKg3tVMEVxicPVgt8K58jN5QVU0LdTp1tS6RD8qLjqRdGdITRY7NX2A05HsdwNbH/plgLUVIFXYIsd0oJ/nsjQM7Civa4rqJ+x5hVxU6xEeM9FrPrn8CAYpp27Wg2CtfpZrusL6xRssaTKldxMJrsVkHPJ+RFPEoTYAeV3XUGkl8ZfZBqWdRM5HI1uUt9wArE15+RrjAFKXf/tUzSXtwl4FmCMXFL3Ji4dkLamBkkmIPW/ncWb+OyJpQANq/1YuDGiQcC+xbf617dd3oEeVBYcVgO87sByeup5EF9OwhekcENVurBK8HkBcJ+GZVf/PqyJ6b3sTyWtQpbbSmWtzMxAzPaSCm3IZrqwBUDB7rIjGNJWtHThO6Y/yhQWr7xKPKCKDLU+VjrWPrQoB/WJ18aRZN667BdU/ySR0dJq3yeU+EEyM05xHNIXUvGv6XXJixg81BIeDGSj7piOhtmGD9n27KDnJVQjBum02h77Mm0R1q9D2uJvm2t827zZMcCPN/0sA1UJzlPQdz73c/JYExGO7rJd+yOKSmIo/keusRuLm46hx0HXxp1zttAn7N/8S7gmU8mBoAKHfHVvyRfBkz858LbYRaHxY9VoNOdsMg3cJUTSFjMKSAvrLtADz2Qq9JnW4yOFGh40Xa8V9eK8tTUR2JyVbCBQuZHA4Gcq9FPaHcQd6LS4+OvMrf7SqhHrVokOFUuv68ezyRQ+HqWPUgpbcKZxaURbs26ObYPnaiXCGFbY1F25u/VstDcydUXxdS4yBZH6jyy1v0TyqPijQjlEB1OgahYQZh++bgyjyfSeIH8+t/PvQz9mNPSaz3JXdJS5EIOBTq8SeBr9SKCM/zz/x6MeQErY2uIiockH8LqXNYnabFzVBku3uoPlqLTSfHoESff2r1rkCNyI80Bash5cnzPoTJ55bxc7+iIgJRui8BfueQayxTH2KtZTlMLerdPk1K+KmrtI2iW//jeaa3BDVNKe8XC9HlXwFDHruyhZ9TrMtoQ0TfI+1FR3jV2fOEucG/WjFSWFTFxbui8gu1WrBiXXNf3dwXnTqgU2fFwR8dvdEHkZmJ+ewWREa8Sbf45EClJf1D2tR4M3ICX72BSTu6/C6sXBZiZLdCJHo1Z46pZC4ySQj/7YsDfsyzwuv4RLkHKv8sZuVCS2yDei5nTInttw7s7cmbSt0KIcdfrLBbfjqnxokqjPJsrqBD28Ka7SJ9rV0ZAsZYIt3v56P74MHtTmdn6SwTgP1kOL3v/sEY28pko4Q6ZUX1YPbQSe3XcWsMwOiX0jMZhyEuWL+GPv05X9ApnLdP/mzzAyynVWh/vfNWNfMpHD6H1WbftPxXBPdt06F2kf6yBDMDaS7dVz4egP3QakbsE9ED+uxPPezs7yD7iyDQi/Wd5dBVapT52qzITB3IlHbEU84Fdn9U0VCSaWIv1FPykWrYa5EJzGka1XAtOgfCLntqjFTYvCItFTHVwYO7sMCws+kkIY4+dl8IalMrXvhCxPEzgJQgekSQqBsCt8DyrIBZP8Q7tV0wyd+je8XLktuFmSqu7/0+TUBlZ8AKk+5+q2AA/SdOYvFAHNNZynaCw1yLT1mok/2AcTeWnAXGOmRxbWZ4kMaB9aaE9yiA8kSV1nUfTIWn8EaoLxr2D8axnlVuj+EawTtTjE/mX1lcJaVCkqffVOp6Avb+uQH2wTGT2LUV/v+r/+PBvjMwrh6YrxKRWUv1hQyHQOWp4eVwwVH+7KtJbg8zL0rdjT7LSEsqNhm4WJnm3Ae/Nz8DDiyVjlbLB41AxKUJpnrR7cpbLYr79L6MLI6uPvxpfSjRKJvOpfJrB+I3NS7+ovrAs82KE03d5DVuakgv0nJLih+R3k0/zTgTItUt2Jjoyq7AN95d573hJChiiFQKPU/vVWZuBz6UAO++knglXh0N7Nur1thQSMRtt+kClxn6EJYbfysG5bPvByhI+EFkPJRX+7oDrykvXEsoKQbRdtZ9Ru7/3fzAIyRkmyWU9gROdJmBjTlctqwjuI7hs3tMNScnMpfGCnh9hzslvdLJhKWZvNEhQf0mFKTSrtBAPvdcNTZ1m2d6l1V9VGDTJFK3qOuv4Bad3A3UQHurIbFDNYMq2noWukp0Y+NVGeuJBHHM8f43iadZSilg+3dAGlLQH9yRszuVhmSbrzk9o+p3+xhho+W84Qx4k5sI21Web0CztxNJSSc9Ix7V9ekQ1BLSpZrMGoqyD3KMrsyiBWYxBngnTrf0Ol0P0Dtta/QDMa+qgMHMFhTHv3MAXf3njpHkkFDpo+y98Y/Ku9ndcBV9tbHYnhqHnDs23XksN90VjL13T8SD7yxYvpJrmbcW9rketzQdqAYORALk6oPGJ7ucIgvIqPzQuiE+PxZboGtQlPPixYT6gIDaKjWbj3v/RcjnhFilJNFWxk2te5QplGqDNyeDWD457GJoegdiufUW3w25so+aRwXxsYdXFjKgtdHYc2l5Y0Ww4rMEuWEVKalUvInlDlgyAoymIxp7Q9AkIEF8JYbXq7k3wg6CYs+Ahg/pcuG6O1r8ZCoVbTxnq2AjSKnsyJzTvw81TXJ6YZE6LrXsHGB3jEklGBCtx69X3vP9xoKn7gx95N0+O9PbYC2+Oc309LRR4ymf3I1bVB8NHxYBgLZQyNiKuEli0WDRf3V8G9jlCikTtljwTsnS3ge/85lh0xJBW4qIdPjlIMfec4F0yv2Yyiwl+ThXtZQlwf1XBDaKvXXXnulUAJSH6BE2OW48ZJV19PNYZsk6i3bpBPkb0vMlU6O01GwKET89qQ5Tipq+nqMA7yWJGEy3aAqiy0hyg2lV7H8UKIpcDdwuXcdXx5N1Lqccd1MulhPdhwUqAYWzKAd2KFP6Qq8/8gG7n+k2wNCLQoCANBs27Zt2+5m27Zt27Zt42fb9bJtzCJmIQca9tpt4UNLv88LLW7Rmi4nHGkvW062Ne+Eeynccr4cQ5vh6z8DNncjvijOtQ6VD79l7IxCWhPY3hTfzRxy1o98jRr5AjV10YNAjZ0VQlycx7Ni29O8leACAaS5waqL+GU0fihFppjkwayA3W/DaQFhGrd4JsSKTFlJXCBrnIYerIXy5kERhJAjhOhU4nm6H2UxVDhdEhD0Mn2IR806vFLi6+pn5tjxbw1404w8AYkUJTC5uO8Tomzm9RGnwMbuCpssWFj2gibP/bbBKkJrADs3JzMGg3nl0gbi875AWhow6EuhYHb4AOcJkKGGxLzsuQSBccTUnVKxUlwrroLtEjj3jrsJU9BQhVop3GZxVgg/JPqikgAFpBkR1aGdf3Rifcgkj+ua5mjAmNS0dd92Q1wf5Guk0FmsalBvehty+9DuhAHK8djAKJt7mm4ubLPmwe/v0oJdWfZdraBaFEZUYa57jdjLgj7XinToC/WZR5rcX4NN3PXAQsWjaxNdwvhX32nKeftwSBTYRC1MuZ42SjYGMiqon+zIANr7HWvId+LIjWFpFBUoi+wXneChuiRm37uJmlaaYs6ymApjM1jpeKvg8qslatkaXhsJTHCa0o4cNli1xxz6bsaf5BCKtkfv/cUySEf2eRX2eKXbyc1l5/D1nIExrzvgZ2CmYxJ6finIvxLBMg8gA7WRspGUU/ViQBjh8DVqW4eT/4fQyFj+kZuzEVwJT4XX5f+sXjwQhvaixEQLqfXzQY3f86SpVYFasEm4h35mhFF1tHqTYJYZYF3Iud6QhrmvgSVCPAT61+KXLU1XIaUhwnstv6GE5VB64M/e650cVMU68ezSojKOPQYYJb2M8oo2K53k2HCvBwE2U1k3JaJwMQwf2wVb2e6hQqCTdDktTeQ5L2ivwhSiIP1HHamLa8TkXzaqbaeMb6PF04J5aDVz7L62yLMKxeDR5z46XHn+cKRR+b3QhMtkoqvvyXgz/5EDmxYcj2olcNDgMvamJhsZ9pHajtryq176loHwpxOLU02MEFJm7P18QBL0Ag7X+FjXx138ECOqG4mXa8HuO0mbkoX4lHgEu6U2ikr5G6T9trcCkTx2BMFHnuMjW73p3lUBpZDsDDW+6CzYY2VAS9y5ofrJqff3SSVfpVaHIDYwnDSBbuhdOz+whZWiUiU1QZimgnaOnrWj9qEqD6ZIYBWuhQqpweRmHzgct/kDozWt65oWQp9aB0QNvprl9+LYwP6bIVPIsdw5zRgU1rIRFfJYJw1Ip5bqI4NUTxtcBUGzUJp4DtHEAHSd4J32MZrh/dkbyeKbsc+PFI8tbalCNuL1CUqZAUiH1ZW4MSYuFUVE4Y0tc6nApiB4ZFre0zVyp871qJ2JY3B4N0Lb/8XWJs93EqPiKXDICCkiZnTa6TCxDzWm56fxV3DIYsVYdcwKVW2e+TwO7ECRIaVUjYcpkx4xipuWwx2sH9K/j75MfXaD2rwvwHMNtHsQRb0Q8bEfr/1jrNr010nykTk3wj7njQahsQvy+csCM4XiRs/hpclVZwR/msklzYUPJs0Vad2+njbvjnFGnpmDMva81KYY0q+d25pnS4GDfGDh/Gw/QPBxd8ZxWVNAXd3+dA/w3wZ4PjUzwOZo+S4G0YPytY0OweIiQKFy7t05DEYtHd6ibdHD9UidunZsr4jkk1zdk/N3P9+Zdzqm1eq5HfICk/fKAhZhjbYc7az4PHg9O5QkY0K1x4p8g0ciFe3g1ZV78e4DgFlp/Rjfwu8KHmdxUXxBaRiB0SzLUwWQuDdDrVlzavLd7otrMFvJwG9ye8lZTEeLhbkau3zS7Dy8EwCSt940HStA2ZW2EnSNITWxKgbf34zV1ENw8zYKeS0xpO3f+8TDXZoqsNdQz8/n3Cjx9BzJnCrRD6lYkwB9JUeDpTSu2reAXQlXzdAFPsCWs8SbRewFtQMlWATwRvnSq3Bupkioe2qErlbjrzbEZ7raAEFemjbIa6inCuW5uTR2YpnxBMgNLpJNm8gCPXWKGpEFGAxs1mfku9zgbdoOcLm9hgOgYhDkY7x3Qt9Mg2CLMbRfpNei2zwDs3El9rsyuPqD3BBmTIdQAXSFEm9h7Q6uihFZ5r+lEjlMagSD+AL+5j5ktkdYN07XJQPvXRc+KeRpX6t+2bzgvrzMczKXTCCF8xjvSjrrokiDJEEwr52nd4mUqGtVekX6z9T/2mSpQ8e4rrugT0/GHcxiRG/DzhGvjXCY5kAjDSNdh9X384tXrgRHy3wJQaDWi+FUwhNOZC9j8cKUeZW4sUsE3OyFVLPOyOn1BVWRJAf+CYp2j3d6mqlTshf4xwnwz16yv4JufKEP9pkMxvIcL/3GtovK1DM42RlQ9707iv+RdPnSWG7AcQeObL0XB6w2aaC98T91Aro5GJJY+gh4c9uv75oSKB4bNYEFhCObq2BZETcGcQHCtur8Ak4AGcf06OcpggC5bM8doyzAsuHXPBpzA7emjO2MmSLK0qJNhwiaGFtZXZWvkr8yJ37oLS3eIjuH+YQkBvBJfCqCiH2gxpywbnBN2xyTBBHd37Z+uQD8vYtDp1aMb4VUsOV81kjhxCiVUOrEdNt9DB9rIq5u+k8/NglMfsmpHV55t/QWPxcD7NeqAkCpMij2eXqO5totajK/J0RDMM8L08ixoRVGwCs6sivhy1YjdrEG0NbxjMbQvCGjhQtUkJF0VOU3eZ5cwVzIzt3cvO5drPBOUnfJdSD7nqZI968Althudp5lwjE3bTfOFW/TpET+MBSTWWAE3aEmJTG+jslt1v69tjD/bgSqE5nCQyfEyfXsN/k2HkJ0Weuw4dJcnXiGjfJssy1J6dvHfjvpemBos6dXR5LJScbx44f281Zk+5IsU7iMeLwoUl9w+YtYBQjpZLou3lmEfpwkFxh9w2cb7GZWqCzm6He9qiD46cuSUq7QvQQ0/Vi+z82iHMBxti9vMyT8IEl0CcJYoPO1fvEA5h8UqCZvekF6Ob8j4FMz3UaVNKA9DYRduQibGvEpOUryzgN0p5qfJNZX4L0KqYGhXJE9ppAJwJU6RKVqbPP0OhVw2FwT/HU2fFsM+rR7AMJyCT8aS2US1x3odvDxS4aS08gRpCXp1oW5JQgbLbhI/HlrFTyTlT+MJLcQdCTBNMPeBL6J0qzXNzmbXOHYiecCEhJ5ySUFdWR13TYv7w6Pq4YMXckd1kD0q/1iXUWXWMU2wDJ58DX/ysf87yfuECqvKgvvGdmBvOxA8SEE9R7r8Yal6ahLkoSimRo6lUWRykNeq1KYlf3nVqYPWxV1Qtj8oMYvRHCF6F+XcWgxYuivHNakzIwErTlJ9xDjjH3T9nO0Ej1UD9/QlmisRuARCpwSylCVc3R1e69eYow9Tcj2NvgP9oo3FXGEC8KRkdpA9o6YPsRN7V+aO5yOPQuJeelyiCBZYpc5c6hvCKUX1wtQtE0ATluKIgGDUI++XVTK6FeyssA6WmhgMgLO5mJp7gKf7XHEOr8L4jDhGgpkYwB0duxLfC/AL2j/mWFfql+KpeUrJGe2vBlZtAR5Ql6NRlhxmQxGXanZPGYkujs/IZO4adb22aEca/9MDe7Gnm3AJptXe9q6L9DqKBD1aBKLxyR8ThPa7X3+hHz1xu7KNfRc4WNxBU5+j6isrqCFZvcF2S7x2giA8E9zlBopjf6aaiC3XomHtp0c8dX+FH0DDK9ewQ3Z8Lf+7Yl3l/CyrobURjOpll7D8RXK8TW5XWvBInJUz08mWi1pG7K5oGXY21d9JDiFJIwHU/9umeny5b52ZJw2GooKI6+7b0DHedXhbkZvLEHAuZWzK9iOOBhmsftQoTeZUVRxvg6cqLY4d+CxB7I39Ml+kvw/PZukEe1DHK3iDkqyohgVYZLhLiBhJaibxZwczvj1tmMzl/x6DlkZzh6MCmyjhuGyKc/lJZwv55qs6vXNE9IbDdhvOuEei9Bs9jp5CjxiUjFoZHGX/EKCX7C2lPylg8OZTAyO0FmbAAO5QJfSemCTD5KnJ26blgYTud2xC30aCRe7nP5bV1cO2Y/DJWdFOFEVuvlP8Eo/yJiLj9c3sAAzjBwLvRSKzNol+AEbe/VY3ozvBxmPvDDK1Mss+dwNmGoasgzis9tD82U4PIYkzEiRhrCKO+IchIMob2WLdS4a/lO2TiWwkGJ8xtx2x7fwlOHT/zJCbUIl1EXOL7gSyebaBQlR9pUB6+fgIgn5SrnScplEoT9y63006crhUpYRpM5maR9U3t2vTtUPcU5Ic+MesL+/P0cd+p6WZBZB1Coy0mcLO31D2RUX1OeaIr6ksZ+tzPd8MT/hdzJk66Y1PBwHpUqaEKytgsdkYPeP09UGNJ3vLsJaOBI1qPa3sasC0e0iQW1Ty6T3ggt23kXmV/tJYa1xCI2nuAu9Rp3+m8P3PGe4AUZFmoHG8P8dYkkjq20JUJQIDTLFgVDg0Osh/NyiwnRW0KDk/GLYwkt+7hUjPsNilBq6m30mx4QRNqYXbKMoCPnYU0q5FFhlE+jpfPxnH5aWWUSuEbzQk2sBP3VWfVD9pXupgWBUcpLC3yXvunN/piqrEUHbm8Nyilv0QEbssRCMlRWAUhGpDQFoqT97bPd8NTk7So6ujTd+yczpcFxbW7sSQO2VsFYHZx9It661H19Tk2KzUb/TGOsiZqXI9kmyGke7GActbjO7G7VB+sj3rdDzFKBCL86JWa12/k40GX7vQ7zO2GLaWSprsb71TJXgeQOjTMPOnPRCcXgtFloay1xaOLl/jQ1pxoTDihVsjaTTmy4mU8vaSu/j/R4kMGFzqaeYCloVb0stTdhdMimExC3sJgTrkRLXSVUikOfwOYTg+2ENc0fbH0tuRfO8eF3FEvMyLE71XrjwZD8sWUpP1Ez/OyXESenfRZk7N8xU/ixVXsGmgKUGFPz9QEwNapNBhPW5WOgg6DdoOPM3MywFh9B/yZ03NmRE+dyg2OwyLllrnPM2IUu4p37oW8UAbf3m9mP9M937x2yiPVwd5iepCVmnS4UqN9n3/gFaRG5DpqvoSjSjAh6yQbQqe5pxjJo+zm/y4dB30VPMUYMhzYdupMX/jm81CfFr6E58nt47WhVxELb78QTwq9hn5CLRopGOg0pY40uV0f3+XtIGvNhUoorLMg81kmgiF52SWV1VwofAjqWeVUTH7AeESE0pZp7APaTZMtro/meRjik8z0XzR0coyfTWqI7LI/qha8/sLGdNMwID4u/3G8jKcz9uGR5pxba0eS1tCQdoGM2wUdoIf2NNoe/ccbxpQcDMWszhyzBx9nnN3PN4iVZAtfbsPayTY4yWwI1gVTeQD+ZqBsazFFXuD5g1NP6nvwhwpKoOkJNU7OKm1DUZd/cukKDS0SRT4XJ3DJ292EK84ug0C6I57oOMElDSvnNAG5iEwxU50y+DxkCvLkbCDL3cqQ0Nf17NB8uyYtTaBZpDQr+pJiBF84oa98ZLKVFV+v6MCk9N4yTROyn6l5mUedFSfnfIalySSIdUwVikBVRyE7z8iJOxmmjcPZIQ7iGbv+DpybxSP0Nbap70beBAhJCaAN49mymmdx0yFvY1rfvctK6LHp8rjPAnaj7uv1IYHi5XWfClTcMa/KxUbojMLYxHSlWBJ1i8WFwUiJhPOyW7emrFLvkfg68PJnIZGOjiWbCuX9EcbfzYmtFULwDZaZyLYtGoST/gXdlGLfZ5h4HpIox9EYio6F9XrC8lC27G9SL8hc3jcfm758GTPzqggK/LyZsroCuKys5s0Uk2qAV4+aWLI23xPx8sOIUuVYEE+uQbifLWaMAvSW3DOeJUkbwvN+ERBYTRKEZFxqrqRPK+njJ0HAkIOHINnDREQeR1PlldKXYt1ckCFx2K2DQVx9MqTzqlVx4eP0ivAuNhxerpXvnB3JeQa3EgHhfBk41zSXP3/XG9WTPbGQBZHTng14oNm9/xFYFDSCLjz08zWKkVmZlTprr8DyOhXdUeVELIr4SoIcJ6IsMQLMp1bYoRJXcVPXDjLQAGfx2s6zv1MaXTXaVJOhSKTXSTHtHOwleXqeaG8hDBCd9cIB/kJhA4Jz/ysFSWgMi+Rvo3o4GpX1+S/BCYkJlGheTiHAq75dFEI5cIZ/FuLqRpN3S1jPo4fmjJVk3z/qWeUCbv1m6Ax17E/i13v6HdWELO2/2WHtGIr0kKtv0To7vQmfZS+B2VDjVrdveOs5RttmwBVkdaPQXWttrG3xjKbwWuqbG0Unp0ZoR53mPXQLdgNUz1+KLzw2Jzohr60Fiq3mxGGn72l34+LPTr5OmUyHNhbSCWQhcCyQv0ppR55gGfFsh9VnmFMy2njWLuKG9kQZdvuyY1Zd/NXLwta8wZCsboip7NQST2l2Amk7nwSZZAwkgBiggCQQP43JiYtAu7cFUKNH3PkyOUGbCsdYBv+pmbsNE86suWHLwrnv0btanInmhXDGcHAuWtN9iBqNnjyBOE0z0egc+WuCJc49UTSak1EQ0ZCLWcWJYQIpVvx6RtzVT+ETlb393+h2xyzS2NGE63fSsfsoMOx5LPPQA/dxd2S40OGg9Un108Doq9pGyJH0IS+aNTfUHQg6rD1Q5Beod2VYLbfB5ph4jd173Rjy+9b69Vc7ngqU8+pktbzokIGqt8tGys+AK1qRqOuaRE4N3H8Ax2Pmw90qJ/VybRBrZBn4e/rDe6Xs5fhdoLm9Sap1lXmgZP1aGNywzJ03e3vFnE0z527YYTzQzdeF6XSThrVOqB+FzRFP1VEbzGKQin5qKIKxumYDJAw6tI+uItYMtQH04+njROPl+jvutqWSk1e2SQU5/Xnr1AeXX5G+2zHOXLdDI5EpeTS85nleN4W0dWsbpV8ojOQlddGUQN0gGRsJSL1fTarD+PzDx6cgjJo4P8QCx3hyTkWsTI3jGrYTOmZ5YLjQkH6EFLAM7E9ifC9IBi1f+e+jMANoQ5B2KahnEyY0g/fihMCy0zYoJh7W8U2OhnuixwQV1cApK5v9KMuse+bdRkWIXnl3mh6831ahhh6YHnik7CXtwoGhNcfN63tdQiloDfjaxqezsRfsNH/Yz+GKtFzcL39SgRic+m+LC9Rt9FBheljq7+fETIGyYDAUgLPBQAmLZtXjntZdhtFtgyH/r9Y6Pr+bLHENgaXQ7dpgMb2K+WvwnX/gLXuFKlcmQWaXf+m7oHMkV76k1v5s1+vG9KjuKdkYzCfJGRPnT9Z9EeKAEdiOWmaaFb0BGM2zOsrBuS7kJMt/wN7XT/g0JvHtm+1tYF2hB2fvoDAWuPv+mdCmDnAK+5A2LsTV1kQ68jKHZ/5A4ocoFiu7r1Zl7GkcNj8+OW27S4JR8pJ1J3DbMDe6MD6/0kD+hwrAkJoxisG8InF0ai5P+yV0P2LKQhRBRL3jSoCM7ROsu3QSmvmOGvkAzmY7yVX86QHcTvADe8AHY31DPaBo/6SfIs123LsnIEdmmYCiJ9Nak1+FvoStD3Nn2xTDN+6Ywp7AmjJQmS/i+af10iXJNE+4XChiikpvhGOWHkWO4IYWYJydkk4N+8Kjg12sswak30SkwblXlSqhN60tKTX9BbLkD5hPGwuzQ0eMSCDTq3Ih529mY4wbKoWIJFJw3vA905u8ddYLP/cNtI9YNQFXIimi83rMlGl0zummu5WHbYM+6f3PLcPGzctwA0tIC5yV7kdr2EVF6uLu3P52tYin0N8DAfEkz8AVGJ0GyVxX9PA2cbDCbfWko7cmS89120OIL7CpZ1dPp+C3YRrMNY96wDGDOcmkBDGxFYOqcGsCJqdXkfEEGD22xUM9XI2PJP+SHeNeKmh5/kCg4ZvTjGdzXqUzIBE0NvTIKr6o0VVx8V04eZQQ2WgaWUlqok4yDJgQ2jUDCkVNUBglNRMay25n0fgFcLkvuDZsisjE2FNAPqpgDRp3Zh7NAYCvj3GY1CbmnGJFAN4iQlJ3JnQuATm/1KK8u2/Gbp6kaRhNyEKcmGc8GXERw7oquz63sH0u+rj9URZl7PmgJX1ZUd7z+mdtXdo9Q4WFGCYyxqpyMM5c4OJUTFLlVmxUuFeQlMigCf4vAYz8FQVZFOHdnbQz4el+1uo+tbnMl9ORBlfOp/gxEv4oOlF7TM0/i+098FzvxBWFhgDh3KND2fVxLLKhtbOTz9QQVcRh+T6XyavBNEH5WDK7LrKa5DwNA2h8tNHRTPtv8YtSN0ZJay/eHbCrHQDik0btr+nRThv+azlT6jxRpXv+FQhcHIRIKKa4N0IW7560pUkq4iCPxD3bss1pJoNFAOX06+2FTPE5oXHSUPxTZOTsqehAB8i4vj24nWYz8vxZfLoQ9OX9p2qNERf7foEOJtk0kBn2yVzrihrj79Kwo/Hq7z4b36h21B+zngFsuYU7lNlhHLYYPkPn+//SoxXyGZ02aDSZBm8ZsiGjzcPnmbjgw2DXA/H9YU0pH4XOcb7WvBdf+I4mx1o2B1XdBHe0U8nVIqFkjhPpZ+c8o8F1kJrKA3SNCXgxBV8+3yMhpFTz0lhCf2BXfDmH1Lpk7ydc0N0vouvDfwK79hFbgSXRDOyGsNyjEjkShk78Lj0RcWWFh1+GiJQKUbGrpiKgZQFvlZKO5qSnPRCoy8zTfEsmcTrBi2TSE1xw2VpwRWT6044ohpRvOpWEuXgNU/lnoUxhBjyjcvfEciogkquGPWPLzSuK3vaTfei4i7h5A8Zi7TUlXxt9L5FsOa0Xr94VyUamGizGIFJ12qFG2fJHN2is7lAKDed+ehbfhLRB/Hy79aDLDCGkxGnZuUxhkmsKHtXU/OGniS3dDCYofJaTcfrZayKzzGs6LWIZKE+H8SyVuTukF3H4G2Oicb/P4zPR6XLGHrbAcL7HxLY861axwS67tWKga1BtG0wuJWFA2A5o18w6A7qv5Ysoyd+y2p+Dgz87xRPtTK0ybkMTeGX6qhRWlt0CYA430U/Yv5aJxcPf3PlvlJia1fqK10leSRGxP1Owz2iuMjNvRorINQsdzoltooo0VvQZEoL+/1ebNt0rMCpTqzjCsq6ILwnmzaKoDJHw77YAr14q/FvQbIrYT3ApY/dcQYb0MyXrhFTM3Bu+Dyg+arRjIlvdvk92hQIF4RKPCuSqLG5+6EQ71WDvp6/z9h14baR7r8AFG4qT2SN41zwxuwbSMt2TVJ7XNc/7WlT83AqUUYD8AnRRBsmCi8Oo15U/vhj+kJftWyg/3qPzMtFiL+mSODD7Owt/ztss2JM4a8eIsJQ7fmLSsulfMGCoIlj+Fl84zqlHP9WsrmaVqKuObL0Bw9StXcMDpQfdeSrgxqFNYYaD+aWQm5wK5ousPUolRfWFGBSK9VP07shzvD9cesyQVvQSJDd0dv1BMiUDmo7uqqG1COuLL2E1TDMZ+qZb8kmTq1MGLU5LdNc5LYq/Nzr8LEZa37BfSqmQr20zwetz3Z9PzUL+xxERxBQYknF/ZxcTiLgqowmE7eSY3Y0EHYNLoKdNg5Lm98SlsM91hRHiDYulEfpG4FVLoXKQSz+pDF8uhrtqVBOPdd9pNOkix+qjYSaTvfRT13LeVMq3QUymeSRhC1FWIwiZudfoe09IQgGWpQX0BNRhU5jhF3LuKiJ5TMbRRnFpDtsc+Ke+rWB94UlqHKps1rlENzKZvZo0VkzassUFNp3pYDhbjWhic1uc0NshXQBj0cZwGCPIrqeLzDPL1wve9uTYzXSR82xbIy3Z3POCeokPO6dzhzA/fUw+nkq6w4EP6xi1aAdKiU5UMskMjagdHqUhUs5ToME39J+vaqiYwIkRex+XMRJGlEIThCj28iTdiEYCPGtqY1IfNCloyC4BHPgYc6cPegFWNrEMDFkfMtmJ5Zhyj4/Fs8CwSAjHoIk6W6ynkbmeaXxu9WpjnzpkIJr3K552IBHu9QACAM1j/rX6Rwbl37VR12W2PixOO3S/QPGXmbTo6BsEE7KryzOsvH8BD9WG82cbjKfBf7yADNkCSqbsl4g7OWA9nKA34g4hg5hgoiDuTBvmKvV/VGBQ6j3j5hYhNCqN2pLlIoDGWQeMLSDbLctJRwXWB7XJVLo9XtrhILFTce0MtqPNr8ECUdUbWSZU2gVRjSxOSFrIYXMF3hxmBl5oBcPB/sZbUypu80N75BmrLX3uz+reqBS8Z1aL9lkwrPugyRDI8yTcDJU4EjJLtqv7mZ5NmriawDwuJBuuy4QxB9ub1VCfHcenyT14/F/1Yg0HtSUw0E4lFn8Cz6k2HOSvLtnnRBMOwQhm7NtmL65K8+oYR5qCiwBEKNymUhoLrW8XHMQLzjlNH0J3lQdfwR+AU9XQt53ohJ2dSrjqQdswyFA+zVyyNDcreWHRcQcdCIQvzB6g6D+ms6Yc4ZDguvD0h4l7JP/oejCVotR6bF/4Ac8q6+8Yh3LNpav6DAa680TB7Lhhws544AXvs4HhchLbrvTU8c7/ALfTU6xGOtHIt0ziyAJuPIlYUP8VqCaFytzsjejJKRikL6OjTTuwumUJYis+Xcsf5KNU+ZHaRqVyO7qLzm4ptORm4vVJamQjU/OmZjkD2ixt4s1ZmC4Ltvj8zhI++bPKVHe7Bs6wuOb7SPQJjqHW2KKHsZUFdcceSPimoVb8YA5wi0YnMF+Eokx9ybA4lVbwaMztHONdOKaCebiLkUnZs/+myOW5F/zLO23DZRrlLRhCd0cKXpfFTDDciXtgv6qQlO52YPcl8ZgVFN1rVj3HFyfRDFnfFs2uHZG7jb6VWIV6V8Qy/f6rTaRbEXAxGlpxCHk6blzo0LCJRliEuVDZKEn1IYWxNN9W430D5yw9IW9FGHjb1wKg64uMx68KETEGp8VGYn1x0FBxsqxG3SGNhhtYpLOcAWObDYnPwmo5q0PreTUM4DVoyzEJwfifKPJCJpDjYACuSZcK5PvcNsAorKweZ2FPJv+kV1ZdFzEoU+HFi0FSk1GevHThZnZJSyyVeeZYOeu6a+cmckStnixukdwsjhPha7t9nzJ/Qx4Hpf/oXPtCm3TXsy40qPqXd37jFabLS6/iizo6guY+QkVW5yQ+cihKZR93vZt+tToqNGz3AE0+9OVIqRkXETnGiCqVv98ihak1av+AmHmy954p2zjf1r6Md323A2oSKoBNznHsIBcSagSnjc1HaNwVCg/m3WyJt3wKjtvOoN829UIebwicpHwWHdTTLsLEAdqsOY1Yv1iteQUZR4WxAmgWdI7BLHdumRrb3bGUPh2jljF2k06BEITlcCxBHhUlXkpaPq3+NLbdoLI+44b+DAy3Bb5Kd1/qLbN3+Jd7cltwBH2J36l0L6wTt6XcRUOZA3fNGs/aZrmCjKoaBSfr/g2ZfLidWa/7r1z15JNtO8XEYst70daTjWqlOqP0ldRYEwzR1vpJi+56N3oP7bt1zxLl6YnMPHXHAAYenLDJwnUIBjjWdBG5IdgXBUECW5rrQJjZeDjysZkzMUMu6Tne52UenrshDDMzfkt+i+ygXbjWabXSPFpJWx8SkPDwnyrB9mvNWaekLtFhYzFt9/hQIiinJWjgbCe0sXkFCKrzYCFiSmq9SGMaXxh1HeIOmEeg9sePAtcrQEp95SmiHkDwcWAxqCbetXpsAq8Ls6WyZW+dcF65FqWa6ACW15MSifd4PkNwwbpgirNVpfOhGwND0i2+ejCZ3AmyBGRzLUip15QweOEMaKSFrK8fe0wS6K+9zwMnDDVpmyBP5f4fW/R8WyNKSzAY6ipGGxrcFZiCrr/mDyLIX4w7Tg5SprZKNidSKHZ+hUmsgQm93gc9qk+XUaZFQVFhMTdthEENFYKt7FziursUB1lz+Iu+z75dxNXq2PiNzOgudcB9Q65HYeuM8+oZ0yUevn8TtbauxnhW3nqfOLhGYQx7+iPkrjI7XPF6JjmYl7btbqpodilTiyA1KLJl1WRHLANA/IUXmQ7hDt8/ry0+7ReUXrJLAzlZjM/T7TJWT17BUNPz19/eDYVP5htKm7YEHdH8wr7kF6zUlXdtIRk3bQ8y2geNiHS7Lsac8EOdQP+Y5gEykKJB1CMX3oATsLPfb9hRhzj3gH/rXaGF+Oq/UB1dsB069BhDyRLc+YoKXQE7O7ldn7NynO9BDfQdY4bckFrZgL8tsbJFKgSu/RqYpyUzY3CaR7+xPeBtfzTzXvFiWEWArETIGilmJrO56V56MQougzxuFljnNBiXbjENwYN5zJq5TG1aJC3qDkXRG409nTnWXvfJowsGaQv7Lz1G24Ux6pcYQ331JEYuAm76oeCvzXo4EZwRYgZF5ZbjJdusRhnAHsW0yPKe8uXUDgfNEmNTlhOhmgI3Cfh8asTB94liF8vn4NKxwEnUNgD3E5yhoAxKgT8X7VJF4ShW3YKlHsUcNaC4j1r3YKoV4W9/8HkxtwI9VeOPHDyavSY1+irJFLcTiWnaZY5JLSKHO0RfUVFU0xpP+QMrAF6pqanUggeLUVUPudWnauWaMN8aKOsBXtSeyLpNbH1kNTR2ZPCGXb4T2N43+dQsNOSlzAPs4btSCR7Qo20nr7V4RJ/6dYduHfiSymZyVzUKOgPMawsx/UB8L0OxW9apkapK0VxQ+7QjA4NwmCTbooYAB0UGvgeaTDHd54yq5IIFt9HIi1sB6FtN9kJx+eheY1s2k8gGVT4hmlNhusBKqZeV81b6YmR+yGVWkpDml9gbb0D6Au1fu+0ihkqAdQf6P0xiVEujy/4LIv2NZXHaiCjVy2Wq69HYkNNlqoWhwL2FkngRxIC3oNpxdB79eDYnaK5U2GZGyRN5DKbE3n+3myeGZwVqMwJK1jgP32miZESPN8LUkos7FvElfwq+tteboux0gPaOCpChCwMGSc9NoLvTJ4iMNkJBy4J+6VPDB1P0kDK7CV9rBX6Lp19vV5OwozkDKa2q1zgY51PPRiJKti+u94qioLx4YlJzl36t73DZcnYTzL3Ex1FIOygfSfQQkJIV7H8CaHKs1TNRpxgVVp56XJrsfsybAPuVIMI19IMVmgnvHriebj1pohvOE+OKA7lSDm9L4JgFez11XWd9Ad9OdkD3mU27D8nqbEnl02Qvd0QgKEGRXhPIBkRrUqVMWywAV/21GkfcPt6ZgSdblLzE73OF6K2X1QUYikLP+Re8grdWstn/ALtlh/x+GfnH5yHYEiSdBXV0MdayhocHSFOi+SzjhfTbCJdcfXkJs0od3GdQ8qdQr6id6z1Odo8Fmu4/vAww5lijr4AjI8zr5/utwEhNnRddYDNSWK0S5vs1ObMdzOfMsYyigqhmn4en+CogQzdpFf4jE5KP6HnP5NefJqDHonA+mIlSqUC01kfqybjDtj1/wz+bebrSy75OiTsZASbzJNrqaBw2MdWF57cbC9tHM4l1GS5Xdegas9R+xcQlhHImO7B63PfmErRdDvV8JfpuKUmgmdaQzh1iFoytpNNBzgk+jN3W+bnGVoANuxd2f/lxRJd0dzfcaSw3myBhd2mzFLRIBbhCRout6qYhWVH4AX5ETu7EtiSZF1nuTytpZRydaYPsw7RqDA9AtFaHj5GUkRm5+NOuapJonahFK2VTYoL+5OK8UksJFJBQfOzENn6QoDWNIcqSoGA0XeONGk+dr+W8NEn2KDXKcROjJSaJdpdM2zzsIOHBOjkxwPzUDPqSur0d4b8BxnwiEKYJcW3y4q0cYXLL1069aWChBSHKBBcfoHbo1M5FPgbGwVZtSaiL6J61/js6MWIcXnmqsprMfJxF9z3GK3rWm9W3l21vYH9bKi5RskGz/8R8MpUu5BmzTlDV4+j/d7LRlvHvCMeWqGh6buF/5zOvIHNqRRg1YKSX9CWWtAtfp4hzjymty32ZTUhuHfpU8cRHxe5D0OhH+TlKL1biVBJe8i8h9WUjFa2MfSUn3hIq/GkxK9B1By2cUHhUpXVJK/m2KKavuBJb9nHALpmLkBPMv87doaSmBM4XeKMTFbhEg9wKcTGLHqOTVk+MoESFzBs73sKt2hIt1HJZ7WK9yLhvFuEDT2AQ9HbCKiCcMp5+EwAHw4aQz0hi4DwSHNjCHwpJlIdLtszNLfJc9rVXeG2LYhKAqtabWiPJ+ajZmewMr055fI4jBzGQODjcazryvlEbt31Y7JlLeqZKAlhR5xREeMwUBzu6Y/bbaI8nqbLwBbwqOSqQduI6wacT8oV9Hhldh2tty8cMY6l5mju1cEWRZibi9IfSM8zporFzKV81QYY1vrWOsLGKF74BkTEtXPxl+IPLQbXnJWOI2AktiOvwcAczqPlvldx1Sn9Q2dPSBWRR4Ho3hqWCEklkgSfeURHpXkrpvlt6K9voM3oP1jKRJJ3NjUaBTkXNQSE8FNYpBlob+9prznNXPrFh9+unSO6dx9hDC9T8VJGV2yVyi8IjvlkA/37HR3vaZsFaidk1cKgkPlg4ZqLeaEiGRaioNXXlzZhm2V6IC9Y/A4Fvb4eI+BwZDuI6Q5Q8s4/cnZHT5pqm2M7hmVXjoqKpWqSdZKpQdzoyBaAaVpeWzMH5y42FluhLyJiSFQuWMvfErF0Rd8iFAJtiWL48C3EHRgfEwlTxv7xbFakEoi7HFmE+Dv94e4njHlXgMiKtFQZtiEXb050Sd1yNkbpSQOCUvRsyxT0dCKO5HMdnlqzZzllzkImbqZI+L4ew7bGON6yF1sfRK3RhKkqQZJZg+sQ9s9KHyuh1LXbGGamM58gqC3udOVAwNrlxYQnjo3el4E9IPIe4cbSycQTqg8p8lK+cSOmRvFV1sK9LN2VJncQbVcbFHK+kdoKzKPcOCXMgknNrz0MekFUkXpmNdC7/r2EDxV515K0TTXjcmtVWrftesK0tG1mZ7S0Msrf0NYVGWB4tV4auxM79Zv7ayjORAO35sFsgF6aqJm7iFoqTVzc0F2zlwxeIPTnre2fGIMZgtX/UiazAJD39IKu2xbuy7xuCYxMN+oB5aCD09LugS6UYlvTCmjvhFGh4RheDUHcpHHqNq6EU6bRnYeFMbSL2xSjr//lZjfw/DpP7+T38g9xmOcoKmrKa4A5aMEowvQkV6SpK+/6eogs4aKV5CSg6rkBKYXX/PHu/XP/1sXbCoXJ1BXMUfZSYNhSJoj4YDSg+UW5qanUO5Fsen9D8iBDaf7NfeqsyXzHJ3fAranj18qn3CjsLy92WCdaJBjo3QsQCvokZ/Q6iWXRIP+OQDy7bf5C6hb5dILP3rJCDCLHnL1F8L49M2PtPu9FxqMePXx3Bl2WKxlF8j6AygkayczSizpTUOwlBGnnSoH0XKpCRzGwZ2er7fkDcbjlMmoewzHayd5G9v4tHFdEH2vX5quN72YCSrwg4TZsvOKWY3V0NXUH+LJ7EMK7tiynMk/F7a6sP4vVA2588vr24oDe+6bSjhFP0CskCQMeNt4Mic59B0sZPtbt9/fNL68AWXGM1PEcfvxEARrfQJsLX4CMRGFYWDb9Rq9do/bfKMNm/WKCLjdCR6+ZEpDI0Mw2o3t3lcNVz+iJ4VjY/GjxNw3H4l4rAtoCc4fRX/9oLH5ykQDrVTVd9h0K0x16upYf+rsUJ+mL/b9OX7noUek7H7fBWIWeNesrqxVz6RBdnGFdY+OeuYX2m+4tS5UtdUPZGO5Nq/Y+fqvJ+OK+CakzQb9iq7AaGNtnfEBnKQl9BocOL7Cw36ebaVTrXfXOE4vln/g7eMj8KHitht5GWZGVNTZxiM/UKQG+Eshxz+j+W6cIlTiU1JDBg0Wkk6h/yMXOjQ/6y0YRHaOEvob294guTF2B9Z2UnYfWYg1rz4fDzS5hUBbockZsP5sD/Xf9b7lkGpiZgIOpnInsyiagrpnsZhSW8j25fiPHh/J58VnhmgkDQ4IITyBGDP+g8HtHOu4j9nu0G3+9cAozCk9NKFG9OOFPAxHG/toKEz95BGrKV8D024J0D2X71vik/5m01njCyau+FRMjQMc52PCWtAcPPZmxOtPuPnOBZSyqQBHoREEX0p+FKkP1ikxnrcaIOiMo+zuvqCuQZBg+Nt6aSYVjPCC3x50DP1HPO2pxPpyrP/nxUqiRohXMiIlWhyXCjEC8XtLXpj8cfCy7DDI35BcJQ5F1axh/9tYAFcFiEKvqyYGc3DJ04WORCCI/D8MRX9lWJujSGGC77lVTXAmPLuJSaB5Mt/yQmUEV+jmAlQYfLi7bhVsJjOp8gnK/dF8yqoUlc75Ly+yvavGt658lDzHAzXoVNTts3DqKeKdeO8txDUUyUp4aSxCDYVHq9+vhhsT0KA5PfQHILWavYDY8vs9DqWEl244kj1iFTP4EYmVugJ29XKbl3fGpRs3YTntXSTw/7Ab/YEvy887JLTbUt2yhWKRyRYwY48ys/n1F0Kt9YkTp2j+blZMDqhWyWFtnLOvAS40ggPfHUyZONCXxt2W9xUE1tyJM4MR+WuqRjB5n5KF4xP2Qjl0D4tbfFfytzDrSmf11aDp8i+BrWlnJnxc0Y8eA/qjWk2Y53EMObOjTpf7E6OuaiQXGXW8Gp/fq0OQrOk8IqpkHDtW3oP+BtF2+slmVvgqnfS8koHufFi7NUcnKnQSvM7wLQbO/2KbsJsZnExNStsUXIm4zpWnG898VVX6mGxSnw0VvNNHeLj4sACPxdO/BtVlgyHEPSwpvM70rFAnG9BKDGBKvrT/1fNv42AG+Olt3EhoQfXlABOQj+YAl8T4gbI+Wbr8xd/v8wNcfL2inx4jiFP+CUGGQjhD3Vzc6Vr1xsKeMh3FBhdPk5pzun4mKvjitvUHSNOr3GGFuX4zg8L+WxLao7Mf7AWyHMlQu2ycttp3qNpK+8bTjKP1KsHS0yyHVKWI6n7gnSFz1FoY+CnvOIdg6mMbjbaBTCLQm8KO6BcSbg1rRfZmmY7dsTODUvpjjydKVL6fa/IpmiQXsYxcOf8kFXwnFhQFPNMG5S8OsNVzECmjmclPC86JlkBkIagKG4bYcx1jI6o7EYwF2Q0kdIRTjhQE0ZzUR9NI2oMDYQYrfkNUbl7N/UeM28758k+1Wvqpp+/PxTh7EJDs6R8Tpdpr9qwkFfrbHM+/RTeXhRwv3z23QjSK98jS9QiWNtYbFZdIJM2ve1iBzPzQmYLxjJYY1Js4VgX2Lr1KVU92hMMOYZFxJomQ8ugJishj5KArjCKw7izH7kR4e6iX18Gm9zZEioQbrgW0yHZSHpYX/22iRA2MU5y1hzI1NmDBZ+/oMdmoayf8x7+jqeJkFFbMdnjg2Bnbpezr9my5sYhX/QObAvH7zPASjzL6n9BIJuJx/ujSZMJFyaR3gYLV9qPEoJ/JDoJJHCLRMQZy7EssNbVLjAn7cd70hi+eNeWklNiijWvmJUeP4JcosWFw190gWMZALh13A8eeIIQKAgYL/jBh3Cvuii+FfRi3fs0JBb48DDrZ4R7eSKzfLVz0qDe1/wgy+jUx8NElSHqyyyXOUb7WGvsTUJYvouNVx3J6YRMSKKzRGXcmKNsupq4sRu9B/K6GfJredYDgUTckT4Qb4ZUawiZGD8JrfCy0CgSbxO9b3fClhKy13IzkDwuHyZJRU+EQlTBINceAMlewySsq9raQmUNFU2hBD47xn+BTPChFg5geIckLG4rUk6bc3wJ1kkmq5aXeE3m6MYkTR1aK9hEuLeVM5HPH2Cr+FvFMvhhsKYNZ6snIuzjJS6fGJPjrm6fP72D7yzmq2fZ/wTVW6VkjHXvXKegqxcbdpzyuB65oZrsiaOndqs73OWnNwJ/t6ExpR+kJ1K7rdhHxqX63DHTFtSvXWyJ3SFym31+U+DVbfXT8ufaxfzvx1Zz9vCMBqLjC4yH2evRKMPZz8xI2vSVCNyiXiNlVCApzdGMefA4Q1/szr83HPCseWcp0k4jMa4qT11hEnyYy8EM9Inp/5bOwRGomOC5SnVLQwYpUdbR4kuWsF99x6zpHhGfasrYNB9pmfsdV88rZq0Xxq+MYaRFPsJSCEe3eKqmMmBG/fVukyeD1QbN1RyOWE5WhcCoyLetNeCfowd9lPbL7s1ePPg4RgU5J/ori7Jr4a/4dipJvE98LGIrBFntm9JcaUREsQISU8QoOxBPndantyGFhx1nx7p6scy6falLuWjU1K0aAXaeyU1xvlAmnij/OA0bF5YgRNOoGUSn/lFZBFsj+hapeSQlr0eo+cwaGXU5V0MV/aGQRdGTe5GFgqsaQ+fRwUURcGWxN7XaXdPnYVEB2+dbFzQSYxHWGuHMK+IQdBv2CtpDOPcMFBvYZ6B62CUP/xl6VUCvBStYUHCus7vtvv15ALF3t04pR3VejRRGgNsV1Z7LsBWwtNZawk+nbZASoOJ5i2e6y0HtuJDar3wnWmVd6/auJqwYdWanxMGZlX4ffa14GKiBqC9IjxZ7srTgdA9klDDnCazgx8nB+O4H4faOUh9OWPbNoBtCr1CLxinQ5moZcuIqCOL8IiMQaS5iK9pbgu3uG2B0G96EUPD2LJFLDzssvnsQgKOV2tXmiVDLHrmNFFzdOgkLmzM3hkCArWrGMIgvZSMdTbZ7P/qgGnhQstIrNaRYZO/O2OxGNzFB4oLthmflXrohIWXH/OQEwldwJuvRaiYbCF/fz+egCPAQSf0H/oXMeX41ZcSOBE01JNM+f8Rh6EdBPO5/5FhbArSalaPBvoow2P/KbYO5IAZ2uz1qDJBFpU5o627hQXIUpB6xqJN/aGg2kkIlybVO+ZrFTSZR3+ovjjW2kRgKA6BT1M/yltiCe6zl0vUuyB/OcM+YUqxwTpTNxyDI3Oq7ulj7K7BVT0Rw1/01xsgKQB4xPfVcFBZ2deuXhRc6F4wuDOfGDWyHbnTM0l2CtOtDh3mfFh6onR4f1DDOA4JEG28caQZufGBI4ys+NIYE3xCxfA1MvcBxp3u9z0HmPL9Z7iEhHpUOUItfjtSzdM7kILyynKSO7QJI0zd2wsYM15lwPx5qRhBB4Foaj/APjx48M9xhNL0yKoHcefe8mKpAR6TWyWVweYcKS7shCngKsFbrsM98olHoPhxuESZtnqQfSKGmt8OKoaXJFgHL9tIM24mV8UcAGJdhOwCyTaa+JNOPXxNRqvyzP625NXAo1Me94sr3WK6qVrOgxnSB3Qum0fIm67dHxP5jiWk/dS8edjZ/d+nnIaRqXqxRgUho5y2DpX0tXTiUb/DlKxw6gTeqeWMeRfary2jb/LpdGWtzxjOmGyLpeS0ZJSCifEwHc9oVdWDd7KKcIIwGbELsFe6eHWVyK+ZewU6OJiHS3mqLTJyRcZVvvFPaqr/FSzyCUDOa9//qZ9OJfw11ohtSvDUW01/DUcVGlF5G0bPef+ZIAq5A80haHxJXzaVb7P2a+BPUd8u6K3V3eq/HQOycOCntraCHPEfIbu0qbv8Roc3SMOqwTy0yzMY0gZ9kwHkVQC0/M1RscXBTEXIA+uljWK/bHRqBqiUKCofeZURdAnHn7yQ8L5WMSFKIsz7crb68DRUs2WTZzYZcwBTz2P5qR55ZbF0eMdLlJyYhPOA1fZQ07KF5Gv+UYhkD7WNyKbL3xKjSDhMO+4vQlTh13Kpe8cOCSa52XPMURzpaFN1Lhnl+oJ0mzTQX5dCoIRhdOmv1tYgrLPHiYG7dbHrGwqO23n6FNIB+/e9BsB5Kg4Xq7xn6nEBi6T0Tjc0arL4TtPC9IJfBHaBv38x/c63a2Wi78XcAi8Ds1z0dXfZ1S9QgL/LeACJv3i4PNW3k/L+lD6LkwJGYlElqwZBvYAv+WIc9DkkfCi1mPOq/9w/rq5NXrQ5pyfDfaYMoO7/uwTXM8mIKOvVJ94H6XAsFK4ZcoissybedaxNBhzwox8ElY+9Yuie+g/QcNtJiDTUVuVi4kvbrwQeMUVS3T980UUIjbkWqzcklzCjRy/dpO/9R3O9cmJnSONrTK4CSmCLxU12Wbw5+XcZO5oLEol+1r1hVaDXAmcuyf0MbIQFa5d5zNlUPCjYKogs/GYFf5RGvEpM7IBQcnOHOlG6Qvp+SN3Mnrz4JHiPsfuHhtFHZ2uR9K7T5orBQSElEmQAKE3avsn2h5F59zQ2Orj2srmNrS9FUu/cgjLUNBgxk4JXF0q73sjkAcNzHilcCmLVReZH7G+18BVnReg/5voWO+d13PoOOqVnzC4LasPuALRjpWZnjRt3lFWIzmIypAn1n9PLG4y6KGhcSZ1QlK9xGg+LiPKTfDtgokZ4G1yVnLryTCjW4kZX6Hcnblqhy5IJXD+1HEXdSxmTJOLmL21LNRwDpo56pXHLxEqOL0i2DOPQtzn6sY6YuWCcThI/7E2r3Z76WxvsKi0P+QZN/lmEmTlPg0rCW2R3Um1890kMeUXiPybUffmlMkhm1/CstRJePYVPBUZLTZYy2qLbciglst+w86MdhERc4xMCFqtXniQEQ7L1xM0ZwMDanF9kln/bQbJfT8j2CpIGSk8TRWPcKtODg+U4lhN1vSH+iW4J2f1565k3zF/kvZEz6r2LysbSVFDmV8fEWI6r8hTA9iJ7/FSi0Yfp4Li3y/wFpBfBO/E84Qnf8kjMY5JupvvH7sD8TPBEXPONZQerE9XENGxJfYH6LqwdTGImhyzJoap3cN7gBI3s528nKcuo95CIdJ8diY/jwS/6//T7DsWnrlNWBN5h6qyyTEYDiPBXg6C5Sw4/qIyeWPDm6Z0xTQd0Nwh+/hJw639xPr9VzS/aYpw/488g14KRH+BctL1/94KgRpfjdcnQVsNmhtZGrWnRn715+G+r3LPTq6z7J8axXBL7KfkT4iseeW39sj0uP4PW9I2CS2G4NWexJwceH3MygVkMRUsZo8ihNC/YTqtihvqvVjHXXeLHFBfx6X0MMgdmHuNKaCl6kgNM1wBH1Ps2w8yvc5umGxEt6ouJmq5oetOoRxrhnlE+pqV8TR8B9E5uErnG9Pa1C3E1EMrYUJc0q3jKsw76vIOFOTW8rUbqp1FLAKO098bs3BPUlTUJIdc9KcvibjBldLZBU9hNeXCaFQMAmUUkhlDJcgoXKeufRW1Hxo030CMtCYeO0wOFAqDN7n4ITbg/Qp9xaszWXYrcsc9S2hym98xappy0qMkwr0YIPeMWyxQc35S8WyUbTUfi5iqN/th9IH4FahsjBQ/G3BJodDUL9Yv0lG/0EAYnHI4BJXj1Rbjj2O3uVncAB/ENtxqKGNXnN99MwItQ7/PFNEDCMTaJEC/ODb/3oDRfo5uSisaIVCktXsxYhhkrw39ym9LCT+mHA2ZyY8X3EMCJ+haFVNt2Y1Wos9LRBw1ZTaTny8ufuD3tdc/DijTnEaHmG/AyhRf+B8SJh585EQyKjmvilxEdxJv9ZYXa/eN6tb8TfHmEbyOZg5Gj+/MtHpMXqc9tFZrxIkdSiK66lKeJYJg9IEhhxst3ujvS+nUgZt1YU9LopS7VqCAEPnIJYqQRN6l5lXqruJKAr7zTnYcKiJ94q1DfcSQ5vKWr24H10wibKCSp5IJCAEzD0wddJONJNVtO5TgS97e2+YU5CWQZD9t+lQ95KMUnqCl1a5qmMhal7xs0SEzhlbbFHa2p/MFrB/ZynJSnzFH27qllvjXm8yLFdtn0vYat6L5s9CNUODmK2ObyCr4DdB+t5h766Ukd2mmvAOB/iQgrRX4G+3R5rEyps9r3JAhvT3XtAwE8e334Mr51fY3r/AqIcnMfKNyKR7MrfLPBxOcZOXNc60SYk6CagbGNOz2dWAXY6GDtgqoJh0VpImvM+zMUOC/EgpyFS+3px6QzhXjhG6nDMhhqMslppr3B0GscIJbW+Saoed+Bkn2djPgs+eJhEFOG0biVMtNS82lG6gE40z36C6iw8fdTzQ7d4T6W7zuHX8s1kP7aViKyu5AMP/Fnnm0Txv31GJx755WQQq0f9Huj0g1KIgAADNtm+2/bNt27Zt27Zt27b9sm0bs4hZyBE2RnN4w6UKW5YbDXwM+kcqefz0BexWH7qm/5H/AYhhgyaQODcFtcDnMwv7UVAmwUfGNzbmWriTx8UwLFu4BGmntBk/k5tUXJwMouVQt79y7tml0bnYmlPEfVwPj+O9CZ/hNeatK1pRFlQgaC5RnXlteAB3e1oe3j/ofsO8iMZmFzHtGNEaM8bqZgnKa0dGgjBzWI3eJtNHLgbuNC7qxkWbt99fpk8oPO837nX5x2/3qGAxOOCHpBFNigRWNQQ33Zum2jWrOnEMRpW2T+mimVwvtOC987eSWPSLX5rf64OCgkllmlO6K2YaTd4oBos6wKPWVCsONcuTvoOYI3BYuAu2arhh/BczdFtuffQKRyOgc5ZVWf6nsttVsAw/YImJJg+L93KWoY0VJaa2TuKIaHUlqsz29m1GZtpkxdmksT4u86YeuxwuwFoRYdUYQ00hnl8dJMDno8uIUc9uei3DaXN+gBhboiMsHaSOdFMt2G0lqwgPbYZz6NNuLqLWtdN8LqCYWW0zIzfmg4N8QV/rLcYNkDzRWwJGkHc2LFcZ3aliqE5wLfKibqDwrhbV4v44e9TlpaB9WcX8RNPnX+MKKUTqOHVbzmib787PWlYVIx0hjbjcZmL6WiN/Ieev0hiZet5IRkzmTRUc4heOaQlzhQiYX550b5xsqUjXMWm2SafTBS6O+Mod9sR2YYOWf6ANr0QLB2gFbAf3yc1PrnRQOen0ISPhkgPzZDyaYCrX458LvEOA4s1k2hzVNerbbkllEXHsRA45JFTsVYBQkieY3y6ncoLe6ptr/JGOYpU0h7nEy7P1rum0+3nUGORTQX97hm8gJAHkCpUE1wQSNVl6ScQlY4mpsSQpKjYb5g/rsGjOuavfBWkyC30vfQc8BfOJFRJv8SkpwDB0eKHXH3vWXn1jSfIQAEkJXD5Owbcp0YFqH/yO1x+DQ8h8E3OJZTW93DgLAdwenNUSxSGuvTMflY8Adc1h4a3+uGSSg/cg7dPSDdrhxoA/qkm/QvpB/ebo+hKw63ubEzw8UsqUSnITDQZYOkkii2RpmZM++zhiIsNd2oDrKXwLlGrOZW50lhPe2hprLo7Jbs6nzIgQQC5kTfj7zeyC/FZBwsTRYjiYhl5cC4HafVpjlEtmoXJpXc17H3hI2g7JZpwNgEiN8mtAzW/h95EmilvpOSEYSIQN1nTWclIw8hk7eWCVYJCnhT33T+PcISfX+LD+BUdhPv7HDAEAa+EY2BTHXpQHXTzzhTcExSlnyaAFeCY5N25cuGngovdJnAuGY/PlVYUw4xvqDATg5Vs2lpS4MB+FvZCBsFQxel6Iz88TMqfLIQ5oG8cRca9nXGOm5EAaNocCDRc1bpKqcKw2L7++EQo+6Nodr8x0SzNOt1uYO+/jjwkiVW+xMUQoYwdpFzqlcv8eknDP1jO4jLGCmHYbZdvn0aq7D49UEuzxBB6zhLpagPKK8ZK3tgNTTqLK5k57oHwLG4KPeS2oEv2nsh0A1VjXWrn9ZZT383t0IrWDTo604aTJBpS5ZjRoMHF8be92rP+MhQV76pNW8wD77SSwjgitPE/eCyJEnZbgVIZzLmDwOkaQUCeWQWEboYmQhSllqJ13pxReoS7nBalB7vPKJRBQKJd25PD8RHQNzKCV2ilLKh2rmK4GqcNIQKkSR6v4LTlwtAGPnRZKd0cE7l4v6S/jf+doKfkY54J1U/ajP2i0SLkL4NmFqgspxWzfV0q4XITB0ZOdEzV5a7us+aefI81ntY+4AunG4Z0P+9KGMJISEXYZstJDFwJwQrKxEdweIAhbsawR1Gu3iFcC+cqNHsiTQIiU8fl2ccPlPvOtb8TVEKJk4/sPdzSty1fTuFWwnH58qjdJgIUFm5OvPvK2N8VoYwhrnJF2uSgyamueIeajfP21IKCGHRzhzI4OQjFQhfa/eThi3Rx87X4r7U4ufrdg6QN5aSdKF6f7C6ESwby1h8MKfb9LSo0vnbxL3M6Kl2YmGUagUnhWSJGFO4Tofgt6Wa6Wt3uaeqqvCJGD+FHFL8pe8tTRCx0Li/0ZPyWr+0R0v9wvYzCskqUAUuQX98HRhfgeUS+xXqF4WeqmFNfLOyNKN00+yXscr2o75e9eORL/Ft5QvPEIX2SFnVqP1r+mxscM+ZCO/Qfx/EP6mzp+Bn0r3ZDKXTxNJotrbyUO+P1mI52pARYibBM6XYb16CDUVnhs/l4WwECLMZwEKxHTdKg1PbGbGMSgkbOUyaYdpqtclT/wE+qRnBRsH4pd2qLC0qQavTTI9iS1wSQQOTe4l5CuY2c1skZb05a+BLRzglNS3XfhstkzsfPN6Dkg3SV5tGE/f//uE+gV0ZsyQ03L8mW8qR/bU6G5rogjfsNjg+qhcC9DUlmjTSzxW16hlTHB6ijv13sTRbfkTKh92u257fm3qvd5R2tiIDYzjKVMlKZqJKyZIMv9Nm4qCmebIAZ65wONeVxmjUeAnGCXEKOEnbjxOH7Z0CXzXQKOUUHYo8UXqZmGc5NB0lbzuVGMUk3tXutf9p0S2j7wqm4csVBYbPRy+rRWZd4G4zH78SmRouOm16mRSdMst62Sww23E7sTosOh8Jwhw4AjwxZU2eR1yJUSTfZvqX2VEjvc8LpoR/EaXLvTHIeR4tMxnwG8/Hm3tF7k77vDI2gQmf+xK0rAP/m9sUyeMCHoAaDV8Bc31p40ta5MK3uCoW1n3l+laQhyLXm8staHD8atT84j00xnXHPq2mjFFZcEOGbBvmP5CyjmF4Ircfjrohc7UCLqTDHlzHs563vtNRumj/PzxvuXDx0nMHVYUs61DGUNHrkv9F2lWu57eNZokkI25kQyDutjfTkc6pkQL6OTy4/X1WclOzQ9/+u7JulEKnc/COEuYpp3zMJ6R9UHQZ5hB3aWLnvJB33VTAuVAeXqsFCs25iQd7Ih+KoGqjCMBR5hkVebahYwRAVYtujnkqD1tpoZno3pFFv8Qj1FyLrRI2MF8lcJ3SWd6u+6zwkzzUsDjTKT3WL1xMIYnd2VmBdN3hGBzpUoxhpWT7R8WOrtcfAK3WD7ZvG2PBeGsWFloMX1E5aHvwnCsbWmR0BuSmfqC740tJul9JX1gGUcJazj9GM1pitX2RJdTTVrrs0MrcP9eUu6UKvPQ6wbgoPmnDdo0wGbII32X5aM0uSDjNI299hBzXKL35y9TeQPNR9lZku4oBDSf6Be5js4lZzfunXNYsy1SP69wRub6MUjf/jx1sW3ismHDnmRw8IL6mKTDptBupgBKxW3P2IHkeT7Z0tdoQRxY64kRKycQGju3jXCYAdQfRKycY+evdwZHhKUcpXbYwZT9EZNuJmDsioLStLU6cmz6qK9iZFdOSneg5b8PVeu9y6vmOzWSKvqrIp5AZlr0yRf2LlXSTN8UQytZWFaY7zX1wV0aHY4PROwjm/pgWclqF4jXlm5QLkk2ew2C588nS+7YjFdWsiI3zuWj3ei4W6Jb0mfeNXdF4Vh5O8yNF4n3Y7fGxT2yQvr4SvORIEVhz2aykl8NrwbBhftStreqScJlun2Z4lqmEGudmQYY82qSVcwQl0AHti6jOqjEbo0tHi8kJsaI2wnegmSNE3oS5YBIxRwBBeDo90speCaMRKbZyfErNFRa9RckYwlyZ009ttTplbxyfMqABx0+lA/1c9qDIYP3dDLd01QfMd5Cl2SHcfPE4ek1dCd/ZRkeR3vm12jbqw6MPIJiJm0Z8Kqne+lRpysOWwRIdPpeDppmKDlCZ77W9LLTd/n+9XP0veJj8qYmyoz+BjfGS7lcJGm17AOgu+gYProftTmpa6OIAWgKbk6HvvxI9iNCQ0tWLMbXvpPlgxby77vn8QimlzEK59z9Z/T1CC+7/a8J+BM5JQiUrAOa7E9fT/j+ASCZ+tJ92lMFU4D4H+pYsyLHg4+7zt0xS0H/c7DSBTsAxz136kfNhl+LEqjMBjlCXhXbaVSh44F49LzUP0Ja+YG9/OFtkBa8aen42yoPUQbgzTm5MpXnlGke4xLvEGmvU8K29G2RN5sHB1GOefkOB+vwUlPsgW6A6drx12vDldCIJqBMoHCtF3/YpUHxGXI2VtcrFtTc5mtHmhBvwFn+UnOdAtLldeBA/wsehMsppgE5jWyo4LC/ieA4TeHqswZPF8KmxCmZbMXU41OkoSjda9WcEVPHmb1XbR9M02I2AcSLpeHzNBLbRFWbKMBGxNpMflcYB98zyzPDcA25EoYCd9p3TvQIyN10TO0d5sdtJmdQhD5N3teTz0FJuZz5KGEX9xTJJwGEJoLwcLyYSkHtZCt79QKoX3wOc92tQJVYPGW0tgW/P6mrmcuAlllBRvXURy4oye0/loGYuQA2m5rkNCg+ohTeMHxjz6IsdpvUR55XKgprWg4xaOD3wyF4N9ym9h86tmuiwPFdb6KJkIDDzDWKLtmrGVPDNsLOBq/P1mKb5WQ14zb/pP9r6uNO+lXKPhbRqiiUkuDvVz+7uLYxd+dVC0W1n3Fh2E7+RQrRqVHiOhsM4yNkvPk8ts7FZ4I22fNl3FoHK+KDThAjwlvDcwOsyJdKeWfHbZy1L2L7BBtikRnwxnKBGRDJ70lTNG+xcy5X3df1XNvWg4yWnepvDlcbGZoQEpa4roGXLc45CVL/7GacJdb1XL4On/XGFKOk2qntBNiv88/0VOUYYFbZMV/Z9hl3V8FW9Jvr4PdbJRhYY+0NBUxF0PH7U6T7bagBZjgWeWd6eXBLMFqBhQMExiSVpVnSA8JfRikXHKI6A4UMHRJ25VQ85nF0wP2Ox/tIPHkfJrcSJNBqzjveZOOr8XPBifcz9MMVk8kgUTS9Bk4PXhVwre3HQ/ibo1KGZxnlKyaEqn4uvNIn+PzDGutATLvcHqOsRCdMsEnZP9NIjyRyLO1E9/MD7iU3j1BW2aNvqeQpiEpznybAXZMzpE+cxSk397n8mZEdP1MaJjMEG6f2Uyd+H7rgpkUinPODs9KhttP7ziwIgJC2UgTcIRr4aAEdctNBEy/LX/RgofPFa0cyHSQtcx3bhkTEliKnhbbp7bIK3qqJtiufNUNIzPvwm/lhhK3o/9jVSkafLV39hRZQx4CUuyCJDEzrjncpBrcd+M5cUxaOMg8KxvLGdPt7rmehM/3/E9ErhHl66nVwCKsEmkycGQqDvFQmll+DzsQsxqlU/1Ylzfwv+NsXQQ2eUHoHy+/DggzBCkgWjvmS/YJtlmOOFaHL2900ex7nEIvk7RV63nTA0iTsypaqP/E6D6hY+jk4ImLrhDvVVQNT+pYpE8zUeBRRLesdysVEPULvM8yyEz+eI5ZS/xHXM4ty+5CFH6KCtwLDmbKbfeSIPPA12KO01wHlVid26jZO74hx9w3Z8fZOvhqnGmX+Auhgu1rSSywsqtbCzz4SIj9PuWqae2ANulw6Uv9p7z8453QySChexl7g9lSlj8LJVVeydBE3/mEVjEZl6FUC66CZXm8ztW0YkGNqsETqtYoZ1hAh/6bDdrfvfNGDSXz8qGcyUfSURjQvGxEXTlhS7aydhIU/nMpA3+NMltAHdbJJsTiKJm9MKGHIulmcU9N8/aqBBKMIru0fw3+8eYV6ohNWKQiSqject4tD7sGZzgyl0gyzq3npLQWSzBuiwQlguAcf2oBQlxYX/PVZ274N/DbF15IL1is8isFM1xiZQjbS9v8vr9rrP/4lMtO4r7BoXBEmIT7InsZsvC9H8ezx8BO6LqBkxeS1XYZeNKvCu6KvXOpkVZf7S/3x7CcYUDxgRGsY5Ik9ckxYFUu4VB6xvCY991z3Hy2k4qbTZVmTyO+AFnjRtVts1N8jJQIZSDUqGPPb5N0NZy3250pIDGCKX9qSVtHFGd/n2VJTA8357jYUzZBI7/CZ/hoPqNtqfGfyEpmIW9J7XRDBnjdiflrjmNlkMR5nsnHvuY+eu8+ttEOFnrchVTcmVFdoZXfJMrdjHLQlS0xzPBuRWgFAm8hbaB4UxwgeIlI8A9+1/RaxjpWNasBgmpBSiI8nOVwxrg/KR/3tPdI9TleRzSwyzr/8ZvH4U7bCGJRGR3G0iUg7Y19oEfLElt2kteYWtvYbrVYSqO/J4PJEjtxrfU+XftLK6hlsAcY8vRE3Uskz7UfY4O+rQsxp2UlzctvP+fBQOvOgvaTaZ5TC/f6rS1yCrRDwDkp+GIYiAsYyPSSn3vRDyLJYOCiVoDZufBRlKrDLICVn1J09fwlrDrjOxUTcMg1KwV81kIkriJqHYRz/wav/zh305a7YTXR3YrPxsrFtgrTOFiWLjD3BqmEMoecyT9IGAES5qKzc5kCZOzYslf07GUb3B45tkivKx6mP4maiq6/TVSDM6KAKHC6qelTOKfwo1NapKJit99EBcWUmhcHY1oq3fOh0hQIHkNXKq2CRuOdkgiVjPfQetRPJakokvYLG0rhAquzwSm3/V8z4yRepo1HboeKqFM0iSfMzckm65wXC7+LjiD8UbyMcg91t2B33SCzU+MFigctO29PCnnskKBZcehWHzvSo37l9c1F6u6QhW0CXU0w/tHjHsog6LANkKUEnskObx8otIaOH0O2DkKDKTO8SMdQV6myynBQf1oUhlmQ+YhkpJgkxGs2srw9hAuNASue63UAJXTvtqgZtj5lM8DcZq+1MXdtKW0xKCYCM8sYbkrT6HwI2VfIRQyL2rhlfRgEWVDcxF2J4O7cFHFYgoGqNjklfdBGtluFRgRNoJOxVSHjJHv1HgoV/w7wVg1WMcs6tG/9DazAVj0bjNz9ie7y15KB2JH8Xh/yAnjWsi8WIZcsS154LfIAiO1Lc+gsgFHVLL++qFBPgZ6NR5r6m1s/5HYAqPaOA3RWWTqxjSIvb95uxh40rorv4eFX++yb3srpqWT7zdbJFyCcDrKF5VwjCvRkFx/ScDmpbi1FUJ0MrsWylQxNBOHzA5+UKKg981vq+0g1py5tFAlKLtvVIwPgs7zqknrQAmAL82d5+k5zUjs57SWD/l5WzjYHqq8dlW+1PM26K/OVlXvUDvf5WQmGNjtypxQMMsrfeaJcdzgbRwiCXw5+eZ/oxodZKrfw/nETlxJmSI15ikJO0CiAErXnAedK3AWassZe/GN3is/KZgpqebEjS/TFH9Af+yz4DsWE1afbZiclF+CpHFEwyX2Ptl+mQ8Qk2p7G9fVD1wm+dPEbTd3KExiO6oNmxLFrgkqjE6+aUvmmL8Us0OO5kp8pCNm2fRV/iEQ4Z7r2fo+1K33ALjjKBagfMSIdHyLv8YaIsSMIxbB0Rpaw7Ww7yFlgwtMKYMaoiYXgNx2a0MJIRIZX3DQ+CmqQ4YqJTYFt85mwpbFwsH34OaboyyuSePVy3fZBvPxOhMjGONRUP7p7ta/aV97z4y4lREU5Co1reQbKN0leg+B1AYEkEq87YurToqkh0LbMEZWCcMTToZM/xcFLd9u1YQZ9QKN7C+oZCXtf9VrpAzad/TZNSrXmDyFMBb3y5M9GxbpuHhttkh4sPnKEXutBb26pEGY4wUbu/s7VvZ22yQ6isO5BdajBz+HXmiMY/Zsb3cqsjhVj1AS2XAV2SEfUR9AGU9Z4LfTRqa4cTGziLivxsEHqBpGzbdc4l2yeMulhHsRs5a/13hmhM+aY9qbtU50XZTDEjtlxjYrdPqUXjjYt8YXTmq6AjyqB0oRNFRaATpn+ZR2FYySsUn2ck0l5EmJYDpPPBmnmVP/SGsl8To5LOMsVQ97O6tFtQ3HckJqKa4etDRsVfZ/VHjJWAxoRdnqRFTZhGltgJLRO8ft/t9Ska8eBPB4RmRZRJC1ZFPkyQWNeOoeBoYSDwZ3wkLHjqCXVz4XgHlc3fE39MUC6yOvCVwWiGSpFYu840L04xyj9oV5I3imwO6IF3YEmR//BdMsS8OvXgbUo8wHxyg13AJVnk2VLzjWIDAkBKCwpCNFlRV2dnMjy23jknjXjcJ8eIaJk13OxUMShYnmEJDH4LJjJjVxaXU9EGBcguUl7H6t6AUDlz0Zo5NX4+1V+/6Fw4OofPMwjuA6Wv3kX9Vfk0hNdrDoTbIZjGaZIFmkxlXC9+Ago7cGuSNx29pLxiIERMGoRAoVEjRlOd7LWOPpvqH2Wv5f+jbYx/jci7AecytxJrCeEWawZe3w2KG4VGqhtVaKxwVsH0rwM6cRTyBbgYnYORh5qLICSoRa8A4mfrkxqhObMAVWc9qSLoIXKAbLBLwuKwvwKI3HHpe42XXLO7vRempRERWvih9XZtCZ/5Ummqis6TfFfETsTrsp2jGzyvjDs7SR8sTdiryaLZbBmKFBUOIfeWoP8e6YnfWvSx62NdfIn6bb/GFV2/uapVBQBRR5NlDa421eq5etAkIZbSGtzfJHCkRH16WFIKVjR3lo98fiMfWk7+nod4zT/vzk2GfY1pV/asBe4yOCjBH1O5TmxtEyYB9GVIYfC1F8NqLu6tY1nzlwM4p6seqJ3YgTZGo//rvqqYa/jNsfnR7J/YIOVjRCBGS+ORZReK+j/Vr5zAQ6PjFUWhmi1pd5C7DuovMOtW3GD93Cz0FUgPC4whm03elRsotndOWk4MnGC/zEwtcKPtJE4h3d/Su99dE4blmpjm/ySW94LPNzs59IVua89jCcM4pja1yr0pyJ5PmS7agSKlumqAFpAyE9Y97SlRXYFgTt5HUEJmEBWbfuuFpgFHeEt2dsnm4MSfLuLWwcVDQw1z+YICm9ykfcjC+iQR+bVV+UL8B5Jq4QUjeleS//TnIbaNtcffGC9NcdB6PTrc6GDmCtd7HlhvMmWXmcJKjCP5+T4caSSgwhMOk4bwFmb6yRLKv9XZmcXjWOi25rRSjYlhjfS2xp8kzXdE72TpbkbHlIZfSnRXt0Io+2gqoUrc6KKuyvn7QkzkkWVIvOlg2S/yfz9+3fRWuQ1Mb++Uc5bqF/Ggrifi+XlFTwdoQPLeW//NxN1y2P3J9rcscvJN87HovhK0kmvR1uiasZCVtHUyc0GLWhK1hDlfxZ2Yc3F4xstIsZOHq+s2qutdsujMfOmzmLhv7VAcco3Nqog+sBUt+dYAjOiJxedpk98nTClp73UL21VUY6I3gcmmKy3YBPpfDyEu6ei04kTXBLvAOIhUFoATCwlnTMr0lNtWKyFEj9zHIhrTofPzN8XfEAqTfkfxTDfFzG2ujk6sa5VvxZuVWyp8MB6NNEJ5k2+PjEQW81xbKSy1vV1UlG+Agr7O88pmHDA1hDVff/gC6/v/GX2Kq+8W0ozbyF5CrO45WfJN29c1HU5nouktEslEIvWhQ1VRtnJv1qI7/hRV1APwKcHpmALyyy5NwuCNwOdq316DSJFhye4tQgd6olZelzi/QzeWg2+yYWbFCuz7mJ78NgZ3OfYOCSxzcGMJQ5HgV+yv5Y+XU6g7MLyX74wL/P1rEW3DFDi0GqyXM+LZUcYzORbrcDovM/WlScNoS0Y9hHg0ZHmL4PSS6V6fEqSjmFs+3HUvWpbctnJ4JJzQ67KaXQN8QpYjq4ryHRqReXRkM6qZ6WJxLp2UkYCWA1vjuAIOQvg9wEwbm4KwuDR5ZpObwpsWxKbvreEFdg0To8/fPYAt81BosVdsPXGd1UnlbHN2RwNF0O6kBUPO4DYRRnwhz5FeuLjFDsNSN1HsrCUIR/0e4WuTvpnWW5zOqVs+FtpS1cA3AgcZplhmvssWNhA/USTUnU+dungm7ew+sRBZgbvGwy+qcSa7/MjSDnsUKWmeemIUYmRYIMQCAWjyJ8fTsvtMp6cn3OLF6+vyBnxIwtFV3Vfesrpfvw7tlhPVstGAvL0gWyebI5Z7zrGzxQKRsOOin2pfNiekkKn+TfGRTtnbywbqDcDCFwCCjc0c9+AqKLIhJNwxWSSHdU+Gvk0VELa6dXMS8Sxz/RCXFBxbeZpcpm8bjtZHvqPpK9LWsGQSgH/p+GVz73Efs6QQ/KBFLpsO+Ujcm3FH/Lbz/ptVlTXowUkW+KUT1cloJKAhNbm3xNDbFzMBpFewNUseStcJg1QiJLucuZGGMhGdKxyk6jG57drFIOYwXn2Wpno/UjwVMYSuYoWVYzoMyyyEATIS+k4gqbepTpdmaxhyeFHLJ7Cf9/L3EWs64eR3NkM6Pfh6hy6S8uJyjdibp1CYJEnod4pskgQVE2earDl7JUGFnSNKiwolVf47IEn4qGf3gzCcl+ijJGG+TNu+Mf8K+2+Yw1jeS16HXEid2522VfO6rzd8LbAA530mqYatiQ2sBfkaV4TwbDZC8AXd0PUSYmXlUwjSPHTwmIWIDtScUPzRvMyqhqBVFQ5zRV+qfZd1Cy8J070PTSaYzMGqG0wSXHBWa5VCi+US3oc1WAmt8HgEjBEnrW0Fv9BwNCLsybfHYHdb71EjmzTREjvjI4ffQ2q3YpyvldnALsVxtl+9rZBL0UULZFA2U4TAgi9Pl9BeQimTse7gzCKHtjtrSR34KbmYwAPLPaN2Dsnlgu+fIaM0gyY0F0eo5h2Q6bi4dnDEJJQtp32roKJQ7FpcywcAzvYnCxQ+MsHB+JVSt0C0MT4ryWij9RmjvFotsYJXnfgRQc97BBqTJw4XoR5niv5+KnZy5W/v660BkZon00J5a3N46wF0Z22TaVhQqx7R74+9tXmIKwZp6z4GKzGmfx0ZMc1sC8qyZcM+hk38VJDc1+PkYvRSd9M9bK+bCHxPmQhhEOsPaQHmkWdnEDCwSo2I2T6D09vh0hKyVucFnGQe6nrd7sH3w4waRmbb9VXOuDmpO/nfnDLEZI3n6R2CxVJJHXo5lhksaU1BmnHcF9NSw2Bstu3Sd2G6dxMpuG1KikBa7cseRN32rTa6iY2huvxp97ekT6hv7pepNSWM3/6NJsEJi+LZzpkBC3OoUoFt/e6cabGVWgHPXXaEj1+ShqdEii+hwaDPQ4i9xrxAoksSxlK0WerYc+wb22/SUsoFfaODr8MkJZjR/aUIjhohz1m1GPafg5GiQbqBRhOxGCzwvk9IS0sT06yzr07n7r3kJkIRJIz5dlWMrKr//g7QXZxCXGub2Hclu1vKBlgkB12rKbdhT8MvZsNWBFVFukKZyCvUHDf54e2rsrSEBEMWe/+8pCm5NRGNKSFWjFs+70ehGBLG5HGqTeZfk1qAns0NhCu4WHYqbY+Y7iHjthULjesOcNygiFOi17OKL4pnLM0nZcRpoJVlFnK6FoFfdVOPaGcIjfyuMPnPZLcTNCnmt0f3GXRZLE8XzE21dw+xBMWc8oi19+fRIk3eYpqmpwbhhobH628cujSWlRcgsit4my7mlvdNVBiec4Rd6cLVqcdQTx39ZOv8GRY/3GXtets1yx1w2pLumANVtCLuaTnwEGYYMesVqzGG0Re239aivWR7JZVIx3ak9kvRAoN8IR25J1aRyugPEOPyxspKoWdNCNdSVjcdzWPbNhfSn7aQo2pkUw2UrAqDfHzyKM84vRFf6k9In0s2xt/4fKrl0SY76XWPrxwKbQLBHiQEoUYI372gW1HQ/HU/2h9j/WEjYSo5zSj11ObaaMjDaCPzInYQ5ZHhbe9RY0LiJUuB2csSpsby0NWjxa/TChdxgjh3odGBgDjlQ0twZUnv9gxZYTKa2KAqoAMSTnWp8KFUMahpS6TOlE1bxuewlwF4fIHwCpPedByyxKlITQsTYKA3Jd+lSliku10ya+tF6Q93glLLbrIKjPJxyGGTwNnn9e7qwVugDvAtf9oA+2nGoulzCSvMlXYBS7luXJS9jdNcAXXmHslqSbTLMQykHsFOI7EGNrWYwHBa/gJRdD85xLAvCY9fLdmUJmmJqrfJqGsne6/Wqxv5kOiL0pRnV1RSTLomNDAd4XeZmurSS3MNoqnPqOWA932e9VTjGWvoiK6ISwwSqoOF/WUKINBlDACBafrXY193OVNbYasYv+V1XJxGU4Lqv6eh3zfuKVHBIYiEpVzEvavGLV3xrY7BECfMbqx7mnJyJgkxErGk1HR6PovYvdt4rRDXKGd8mwhsyISdYnJ827CTbKcG2BDSGsWXv+Eln8ijGxMYY9EHaFYon8bUBmRy361ZzAH9FohQtTSHHwO5R9KuG+AuSVu7rKd9Wds82hlbhPaKNqoIONYqWnucAPkRVdBH39wm+zohN4fsV+B8E8qQIC9uLnNd4eWJygqzjeS/sXD+LRxhmT44vtdGUgTt75N2zLTDGbYGU0K07yhKTg99rLiLMV2gbvQt8TbCxa1ZGZo/waJAGRR6L51eb35Pdm3JD8hNvgkMU91cpBFtVyzMplu7eS0dPq/uGXbN4Vr+jrd9sm/r0lQfYk6UIkvjqBNzjA+U7ztT4lVw+6vf9j45BtlO4bhEzKitJqj60nRDEsL5LtFY58CBJVJXL6Cv8WyJiADhGb2azGKA+YsEM/hvFi8J8SGzxvWw+SFv0V1HMPOElJqFofZLyj/vMBYyog98Dwi803x3ziMgLTGTT4ciAwDhvSInJyk2fWsOZqLvZb+tVR1zOd9DZpRVOcyXZfatI+qGE7UTkNz6rc0KoX0vJslxPfdg088QR/XFwlMinur8e8LndcU2ByCfUpzsNAbzOFOMXT56sAb8eh5BkSUE8RSYez7+PXRYH8CBnMSfeqYBjEwNgXyBeD9+G08TBWVEZtVUwuv2c9ObSI15kQbfHv1tRSVLfMUVVN4Jv6xkX9/ol5qa0/h1Thezxx00CNTxh//dr+W2AqBZP2I7KWOu5iqYzWv/0lsHI8bVVJ+tJjTqqxtRyeUJlxOp/vYWVnc2vbwAX61ksqyeoSHuzE+FpO0t6BL5/WF7kx1NWHOWA7exMqVZIHvXNepOiupQRUDvnTfsOKFCjob+vQFt/PJ+PbYeqpZJ4SVv3dh+LZcrQXFFufzSFUE+3JPLRgdj+LPIQQPwmwt6qdNIIuTePgxDv/VqEmEPylRECXK/MwFpRRPax043m+k/L1ok7Xj5mXV7D3/ysw4LtYrw44eXJ4N3nVWorI+WlPyE1OzKu0UyVCadHUznOMnFnrdjusA9hDefiDnaI7dB5gw8/gzZQo51A9b/5KztrO3VNUlWUBkwfY6FYeHfIwsUHYDSZI5oiFd6ZgcLusuZdm6BBQ1+xF/o1QZH56CVxXysfxeom3wb6Wm3Qt1t9R4L88EeN99GZmGJKqKYtNS433n2JrfYlUNvAyWa7A750lBMyQ4vOtODvl1hRcylAWx63IAF8jUnY1lPXg97WD1eLnQlwMcMUK1EkfKZyQyUE3jVkOdRJvKeh2GGJFEjIgXsZxpV7nqYw93UOCxMus7JWzqLjdt1P9FadbPOCIvShRgxu+UwH2wJ/Kgcbv9LJ0eki85kR2VpGk0cYwguJ+y7oZnoYDwwwxaSia6J3Yfr0ToTmnlK4fP+nensDKw2l/XcV5xyzQ7F2BjQq+luxZ+So3nnso2d4NP50HsCoqNA9XrEc+i2QUnpBa+uvDJL+Dn4LitjHOVAukLZQ7mb/HvAwc23uNSUFQTjHXblVrCSzEmDa0iL0WrilUBpJkHgPqXSZYAt6GLcdYuXl5OIkgfMLzyOsPu7+wF/PQ3MaGNESUxPI0QXVf5Mbg5RvcPHuLSEuYMYIKuLD5qExvQbwu8UAeYnYIc2IXi9RwioZwpxPGuH9YtpSm47BLzCj0G2sj5PxShPaP0sF8/o4Kbsc++C24XaAKfSPuOzRVpR3i/fuYBqnmg0KlhkVrognaciVjBWEn+gJFV9suZsHKNS44qS/OiwO3OiIE4jAxJMgLuAExIESbCxeNHutQtrzZJG3OkT8xSwg61f59bVu/Y+pc5GXyTMu/Mzamb+kM0y4Zbcj/kbIeBl4KZJk8Dkd7gDWwlUGQ3UmvyXZw8jwGSgphHoDb8KY12Sa1ZSEc81LGNtI0OFYI9jj3Mul1rovx9+pXamXxsmMIYOSnur5VxXGPmdMBiGtZ7B8I+UHAMXJv/Woc4c5+9MKxtOoEWonSz9Ir7L1LeDTda7Pl7izdwum88CeSkGof0coIlZT3lfwmKJwpMqQbakeZ/NH1N7s67Oi0IWDUipWY6tOp5iuU3Mh59JNyRyLJt7BBEIVnhpctUPrx7fit9k4MerRJHMcZZHvyHxt9lROJDCErtOeBzvBJeM6vjnQKVDnc7tueqim+V/xhISAQrlaS68uIUXm0goheGy/2VUbpzxdYRhi2J3tXQNebsjAfiTHCDJn+/L/CI5bcCcSjW4+trOPVvxKao+pCctUgoXccAMdIlAgOBrDINmb2GywLuFJdeeHYmAWKFe1+ELxEx+gnFnqrkapEysgh1fLxe2yyT+HW1VhgvluyqvnM0Fi5S3Vln2LFfpjOB1lAQlQrhTF2ZZaFo1KX0duEymeDQVspKY4ePBMW7WlnThWmgwHKVONVFMYfOYyedRQcFGUQ23AApWLWtTd82RJ0pR2SOCYXFudnc5zVi6FVSQwuDSiL4rLudmBSLzHyx2byda6aQjL2Wd/T/0LF0LbJIMuMgGhdIOd4mm952jbi1B4tXfzxcYtKkojtQOaL3VxctUMQXoJAqxD7VCKh6RBBI4BDctl+kMSo7JzAZEaueCszffo7oWgre1om3wtlT9NJVfvZ932Zhwyiv85/uCmO56WbH7S8XLWUko30EkcGqJhD47aracdWN0ltU6QVM2SV+iUoD6nqOr4JB/pxheYUK4APQnq0CfulWu8YKxASWmSrl8fYV8oSVM2xiPFW0kPvXm+UOGl4lq/cP8MUlJYEtFMvCe5Ly+EjY9664mh/zpBwHxK74gHzpuk61j5QWXvou4YF5pWVvxacffo4RNPvKDNt5c6BR8UWdgTOTvfb50l7pp8fYpdsCSzWoBdGYimDPb6No6QMXjM7iItHBNh6Ns3p1WwcZ+3hpG+tLfIOyAnlse9hDgJM+Vm35DBYq2fWshVNSv8efOvXOxuJ18bjXAzAPeyzQf6gb7MrM3yEST0SMCa/4k28loetrDDogfxNMI5puk2gANcu/4yW7efuRJSUHwxx6VKzmCVMG7Hstugmjz3xXBHrN5IRu/M/kmu3GZ9dO5WN5yZasJ4OUrNrM5C87JLZ8aEgD0EdOhQor8suirZmpPP5AYsPszm9Q1yUBDuKgtZIPCDc7RN8d+GR7HjOHitBAysN/WOGDQVuciInMFB6RHtJ6UvPxDItPpd/ijxPkDIDtVKxUZiJ1YZNUbVLcYAJo+X8rm8ZbAOq61oHac7qJ1TXcmrWE7tqHzjcUuJUEvQshqYq9uq1shqU/SyhNOIm1os36TfLLXnYW0BC8LqZVzwB8Jj4i7Qgn8K2EXT6WXGmt+X2dY3UGlh0Qs5NvQI1vVZ6h1vlbTIY6cxnwKA/V6ckKpHPi1cTQWts6gvMv0CkwNx4tjUSPe+mWtSgJ3ZYZ8iXB6I6nN167XrjWHyGDKf6N6X8bmCCXZbwUgoiDWRwu06nZakinYxaSYGwFXHBVPSV0jUF3tLBCyK9jmhpeTVwjnmy1RB235W80fkwGsct7830Yh3epejZ+o8zxIVv/2fE+5GI6VacZTTzM7JYMS1zapjhnlYtjEqWqwVlfdETdL8MrCoB1b7TMMEoVFrVxScJSddKaw/olYbBTV5YEbZXYjOvrEFQTyoXlqvSOlnVI+9QomMjB4hm/rqNeEVQpvYxkDAR4h47VQ3k9NCI0J+8K0u2GGlIluy2ZsG1AfiMtnxVHDCc+dmWu0TOFmqhHrYd45fxWl578ZZDSGkpq3l5JnSkEKYpkWOinFAhz5kSeibmQghLXaGlqvwhWlcj9C/TARvpNIuv6kEOKyhO/rYFtdJgtsN15MLO/nq8d96LgMs8ivdYQuDwSZ7VxVBeodl5g6Wnh16p/8u9XWFbFQjWZzPyduRvv5LBx3Yx+FZ21R1+XFHmTTgsls20j2Mzw/DXjTPoVB904Oi47eq9rf6DCQvKYrMaF+aRaZqSoMTOv2GfV4oV88lUKymGvIqiZmVBd4SjQ1WzYESNFu2XSmmudXAAkPIRKqcSQIcrGq4B9FPmZHKeRC7ZFHQFvgBmaDsm/fQkIx9fl04b2GsS83ukJjPlRlfHKUAihDxWsenCQMVAC7G2RunPqMU37gr7l4FLFdvhibqDM3ZzE8ftPXpgbfXtLU4YYSAq8AI2smHNcxa4JI+QVXMqFEZ1nB6lQtx8IKy7pEoZJap47pqIVlwAXXp/mgX7R/7A2DgI2lZ+5Hhuu30TqCyzoQv4RKTtdXEPQFh9XEYh/q+KJHC0WOhmUyNNMY8lWJ1K5IlOS2vp+elMrEEO012orgOFCXRfF2FtcussYVbPT6SDPsxWA+7tCr6JaqXHTswN/bPAfyI+AaOHY7J9jHGzphaW6VLutfJLDk5LdGSmQe3Uo/YH9gugDKySyX1JPXD4T5a++FdtgZxYujKEoBNsRSn9JmrsEP/MEKgLAKxK7XqZcOZgo1vbsExWG60ORsMDkHUyxP3cd1chj/n4/wU7mkZPFe65ONiwfKHZ4k577npBOfxh5x5ftWfb87esZjaannJM4hKhhOowKf0LuOU7ZEueHwMqXPpaMlyTGH+KR6dUR+Kkcts/zbvGxhJGcsEMfZvKvaF90wPx30hymx/jB6rfGXxHtyrmbSEiauHLDJKd6zKXIhzv58KZ+KvU+kEWICCWHw/rzPTwXj7v8/tMbsr1I70FkEY/9bkXsUTcfTp6pSmf7vh2vMLxS/lDOLZd/THeTl5MLFACTLXnjTF6mWsjC0D9kCIBerdVsJf2vhnRVbHw5hQ7NR1YylBk0nvoRMO+FSKSRcvTv3hpXRp/aKDjlnQMQ0pb6nIawZXB+RmHaOoREdzn7VqhWNik7ygdGd24/sR5jVeVEKFTtNubi+Mg2TxR+q6UGWA2c8a3RHm1EiG6n/BCGkj/P7NdznYTL8fBmik3hYRZ3me6Z4FLmZ/+ykLo0+rWQiD0cRY3xBMbyqytDjNLevH7InEMATgPopicrhV5K9PjHkN7QzCu8gToQhQ9aTIsUHiSH0vIoP9CRFPkRScjs2gUTzqatAuvfrSbHbhD9968ERKtqFAWNawZCxcEBi+Ii6vgGR0mEUQ2jgJjtQYd9YE1xXXT7Is3CoD3jLV8AYkjX557XmlElaz9LLAjxOYWkI8d+R8KBifmnBsN2MsEgi1kSNB9GnK2lZZLWtuN91iIR9IL67z+Sd0RKsSCp0EMD/kdnMd26nn7Tqoo09GmJGzUBkJssUp5iaNwX0HYeANVcoMnjkvzgoy424y2NECGjduVEXFjZrb+qKmfeCevZsv9x8z2gsy3R016mCkD6nW4+9iA9uVOcxu5VgyhJessZkfwTky3twfDrJ+HitRqOywXyO4CIRe4q0I1Mp+RJsHRhfIt4hD6NgYlJsXsnWWtBlEzNudgdnwHbyg4fCH4H9HfVjCBsUhsTFP4Nzn/LOtiZztIsS/f3bi2JUJvc+OtL847Q65W8BRZkJS1GJnxhD9yyuM9Yo7pZqYZOZSNOwV8I0E5Qo+gQU6kzwb5WHTBhvulut7YFL3rnb693SqiPIGRdpNhYASPMC2Vcc4HujihVUkIuBHyRkUDwkWdYLzAGyEgOkrAb/1j8dOgCzhWMXLm1mH3E7sL7oliYR416xogFygsp/+EUd7YNrVLE4mO+OM+tveufyI3U0AcBfaqAgZCmKR3IxJmY0GyOWNDhLbLBIlvcPuUo8b9iuOCTf90zVlE7Zj1Vv8/DkVBKahwxDn0ze42swIqkPxNXya3QJwdm/+2kKYQRgK8zMfvwJbgJ03m5ES3uXVz7zBMazjghZPlqw+smNe4/+JPD1qkBnnma3s3alRJ39aQuSxd3eJ8hEjxUEgOvRUBiY/OMD8wHF0HltBY4Q7/cDyljvXMylg00+lS1PYopk+kvtr74Q1y1THFySXQ+aMSGj7vl1Nv/7H3CZS+TtD240syJnu1qZsMl9ap9m4ftmpIGS5xbDP2tsyY0Uh1/XBr+wpRqyb0fRaXNvhSDzxhQ2r7ITDwlhPaWsKN49w2DwjYXmFdeuTiD0lMj7u/1ErcQ/YjHQ2JRRoaaUSIDTYkQddHso7AHbxLLu81jcXzRj/lW9WJfFZihyxVmpX454bkAhzTb0ysarkdp46ihqYJmhTdtXBzSoeGJuuTwsfOpuOgZH2RdqUKARyS7hwNFqS9N9sPXBz0tLNGGoZ0VRFF4p6hBa7iTbBNZkdc2/ve6hXst9kn6Gau7SYD/hyt57rkNAy/L7IPv2tNdYUaXszDBPJDTkzFPqb/vLz90o1GZ/mImxbWI2NHW6m2EwrPxUz7eQ0Hjyw06n4MEeK/OUIYbo3ecWQRB3qwsWRt2X3oVjl3jqzTUpPAckKcPOEN9EAm9zo+8nt9WbYz5W7hR9DYhHeTCIPpC3SCaLni/HttcfHNySp52jhySyBfD2yhheXslsDVHqsgJipCjaIOPwBkWFUNaCV4G8dyq1GUCMaSMDlxQl5wvZ8m+B7KhDP0gAY3j31DMl557njsndNykZY8Hz5QWsftSv/KpuiwuFwYIvJvO6yNe07WesE8E+SOBMGxO+6KQ5R4Lgcu2jf/EjCPVz1X/2IC63bbVZPDJkOSygdumL1mDDqw1hjGFmETFzFG5n0iG22Ix8yjnbxe58lf9ypuexbG5rIeMo30jspH3cqW7xPfZ7/Wf+UVomE86p5WvWOc77ChBUkbZ51OlbOHsschh0bBOxAo2Cj5VfH1HA0KblJy3/xLFe/nheP7BFtvDLZ8tJ+lSZR3vdv1nqGe0c3DhDp0NHNqlWDo/HmtbhYGD6EDqTZpGABGNsfC26nVfMzGfD73bHK3L69Lm9AeUQ/9xzSbtETpsIDVSiztVPeHwz5oFLiGfHffbxc+hQcTj0s8951jEZ7dYfBo5m+70NiX+uV0ucLlkvfGnTEV1FK+oS5wdYJ9umxXF85BNYmvJltTUJx31pSdutihKw6w2u30riYInn2Qg3CYVtaMstptwdB5DKotTjs95c3K/23uL1KjLXk+nsOV8jfmZUNi7VH6sMphuOwmYoCufMQ5shx5GNXmtL8wA8rHV9IZiQlv427TgKTgooLzyYxguFljhuDLyWmdrnJSo8TD/4QkKCy8Qs5GX3V6jndBgQEcjoGS0nEsK+5g6974JiNlrpJx5mvwMU/L0P1OFoKtFEQ1Boml+j/JpWmXn/Zedf0Hq+s2UeptPDAOJfrH/jYoxxia7P727crkT69VxYm8ShjLA8HzRlrMZlC2GA8HKr/Aaqnq3dP6cSv7i+GTgZgTnsYWIPDD2X37jY8OhPFYxJTOZ/xnNhsBypcElnDYO++GTsKUyxRWFOU54Ju1qq33sx2RcdNTXMVKftpL9/vDlGKNV8116UrXuycg5xtmWypqaJ4HYaMiG6ULftXFwMOnI04PDySxuZwvx5UOhaB2wm6vl5/+ITEFri8d2hw7fEPxWbd5MG4kqzXw+WJKe5lEbdVNJkCD20laloER47TVJL5oBdusRB0F+G5tsza/8Z44947cHHeSg+SHROdIymrF0CnYpA96juFcgtUv2Z/ViFAxHrcRKpHKGB+lJpK8oQi/2gruJ2npWyT26aiYj4a6NURf5dvvRgBHalzxpzTYr7BhdF3juN98QuV35nJ2+hkSMUBgVrlBEw9JVVI337RgoOd9d+uo/hl71yGuX1fmecCH6avQesmaGnl9isvzO6q7aCqaAuDQITjvQVsX9LXLC84QVDCnBbWagYcsI+zbkd6+cuKk59cG7XxolWrOVpe3jJs+++uxiFo6gtMXHpmmgQqke0R+YUvUYdklllzgtCNrw0ZS4+etahZvQt8Vur0gOUmGCgcdjR5HG7W/YZj0xeFtGlA3R7l2VMCjGCIw20IhkTWryzBrWtTMTjUZltANAt/Bv+dm7jioaTXCkMu/SkiYzNAEqgkYnhap9O0pIaoa8NTxahTW9WQhD75wtw2z3dRr7+8Qi3tfgYo6w/jakTsbVYcMZH6BN/wFEWOqjlaGhenf8HW3e2rkq46Y8z6XW5cuZDlxtE9bjGJhx5r1/I/lxOWjBfjQrcu6NsoX07a+Mi1GXg+lB4KG3LdKDUYLSMMGVL3o9zMNuvj6zOr4nd9HPWtCcAKh+duqj5TtrmBfYDRaaOwWCVzxE4XX7MeOYcaXzBWoLe4u44Y6qiTMCM7qNL8ftiOt//SP80UDQy8rbiSFLa6YMQKQt3Fp9tQZmiBkc79pNnquWZWFm3tu/unL8V5w90ltgWfOvICCjr4SB9w9AkcTbbCFRrnin7ZCaMFJGvnoJx9TSiNankl4fEFh0SzvbEhVt3T8vNuBga8iH2K2S4QY66eceXSUmPTPa666s3JbvBMlz1GXDoeGRNFww+jFdZq7rA14ocmHIWlNOrwahQ+qXqGseKLjSN80iauvb1KI9PTaq2VS2WBO1/I/tz+zcBSWQfVMcAn9lKY2biM1I+2pb8H9OgVv/GRHMqOr286Rzu0F7Qvkf5FoFY0XyrrZgq4FyUbfUSafyiI7Q58QzLGqGUtoe/cgPYf6//r8Y2NJ7b9ZBGLVL4gRPzVX4sTAIFP/HEn1nwLtn5MDAwdnhA/fL/PgFCgv6k2wFMRuTdettoBAbFQ4eGwwf06+Q4uAk58/zXvLpfEkwD/bPpYXTFEiGpXUdWQgU41G6tI4JlrxsAuwQ+hZHj+fbcw98T6KwLOvT+C2ktP82gku02S4YtRgK/QoZ3RqVMYgQRjZY08q81inUyByYAgg1APl7UDwwepv0EWywkK4JeHMYjLw+UetilCDLatrykx+92ncc5az0NUzqFkMjbjiSzk9ei7N2N+TrSz7TElMnp+5fnaSJIKSisXGz6Y10EBPexgkHfJyKNNwpe8iiRJUYulHKh1IldHpIKAHN4j5HycZBCy/btbZIor2/crlkxwKCdfl6JZc2VPVcfxiqW9Ghf8GrqjqGt4xRUWds1+0JsOvxYGmNLx7YbDFccIFy1UKG22xfM43ycjQh0YdKvo6mtr3fHmwUTKvAizbbDE+S+MYtTuZRosFLYJSExFY7Y1RjTkgKsK0e0/LvmYIAU2FuXiRXPD2ncN0XgZElkGlRcBVCsrkC862OqGyaAKsuq9yt/b/nEHbuKvUGL47bJYvw2s0h2G9wsJJmEl0IHXgh6zDX76YJXXsNCl1PHOGDX5GyLVCAqpiXDcuTKH/HtX9K2WQSu5BjOouuPLhGTSy2mHSo0B3xostqflMkTqdHiFU+9BAIq0URiFE3c8NzGD2IWaN3j3rIpFeTjKvFx8xwHUshJN8Zhb3jsGA7c9m+sOfmBF9G6MvXQUosoqpHFMceofqt041OIIN2iJr646jQlTBWK6r+2mveQ8ZH2tKIuVvMVZxPUO2NuSVYPcOJkAp6JqZO69vdnMxVJB3n1IwHLN0HxWPsdM/h9UYdCSqwVtJyUIGFsIq24vAjKw+0+tj+9M6y4xe0LVXN+2gXA0x3aUsrMygbIriYDpix1jp6x1rMmfmSsulJVLf2f51cUsdzgYM9fhKtH3DqCsDyrzlCiozmyiSYlFc6gejAbjuUaWo2fTu4O8NLTWdIbgLhKutfK0bCkTdCUGYxoyN+lqQmgrR/pfjiVnBND+9l/Fso1h9CDVEjuBlC1mytlLWn6zmrRKlyUK4sVmrFocjGLF8HPdF1QmlkSiTvFDwH6NBvLGCRyW8QcjYVRXfRoEgXKadn+kXhk88rD43kwHEGuLSBTp3bQ9QzzZqPOhecjwTR0SkRrA0zUIBRIq846mX9Y06WykeGVaySC42opRMAERf7zf3NA7r0v77RLlVYb9ft5nYdSYqE2tDmyLVONjH+XHAU89hDqJn/YJEZ/f+qvcb4+BvkVhAUvNgIi4MM63+mN4Sc/ke6PSDUoiAAAM22bdu2bdt62bZt18+2bZs327Y1i5iFHJIO7rrPPvTgKPksfHmpafsHJUUuZuVhoidbR2WC1GnUuMP9JgBHFR8ObdWz/wj66jmkaNYuJ2hllL3SfdenH2e9mNWqfqp7Jz/j+LufqYfHoB8wtS+sdI3d7q9xAMqGAevcP6VPLVIa7Pdv7yI0hLg9C4FRfWmHCoKYvOunAIvTCPDJNS6YanMMmvJh3XgMXihx+LfnyE4QX1+yv/I6TSdW6uS3s5g3Dmgai+zUn8ZbpYx6H+UjLkWfpiPyYG3rGCzZnWdReod+0UHbkFvMRu13/ONXAw4SW7VNfi2J+GFxYivGS3NKDUOBt9Y4Ut/adRGBz9n6upMImUQ107oZ2EL8bL3r/b2w5PcwmYERDt76oK0Uo9c7/1gW6+tGSjLlmYMGaZC16Lgkc47NLxl3aXwextyhcSMIHQbj95gprlf9iWyNBqCiAl9QlLP25Y61uc87LvyGEdgv+rGm2MEPYkteYJ1twWiEM5jDqN1LTv8fpu4mkdksoSpFystKxnm4k4uanNVh+ty8QYT08+usK+Yzb6kfrTFU/EfwKTpLljDVGzDLvplqcwF21smWhnfwmEyktk3BYY/RXyqaIevVssdqL+f3ktf7YQw7XKQ84hUfF7bOf2VmpOdnw1ynJjocDshJ6hH3VAB5um+dSJIBtB5QsnM+utnmrrC9vhoJ6aJM9+aQORVqCd0KTlmF/p+2oVt0zoZKFlSMu44DWLSNm8aKrFTwNDzq1XbtXJrcxOAH3eXcWt6SunMYFuez/EdTLR3HXGvs8VTXoCRfy2yTkC53bJKXUKDteF/ZjWHetuqR462XDNMyzna2Md2wapU2c33iVkYyQ4SKiCenLYhhrZ5NygMKBda+WvyGSSqbanyATqMuM/pLqzwEeLhUpiFWllt5FWenILH9ArvRGHlw6M/5ZnYBNTJ2gD7IYcUttctnhsaL85an1iRPN0oQr2s97FpuBYnj4IU1SvbfmZFkslyBQA+bC4QCwquZHvSaxtLAHjDj7ql3lt6qfeYHg5/wSG5qc9V7mR5bTtwPDWaKUXeUBXPBDtwe/+n0J0LtmUOSSFEqOWAMvIrOdYKDJmGohyIJDrlFSJAY2W5vfXWXVYGusWX3V+nn86bEg3jkTtHKl+ZpH13IoJyxZO7fPoPgbloixm8CCnKpuBK9c+p/bkRIt6KyN3REdb0pawiR3lHYSvro6Bben07z2Mu13qS1mYdts/+26zqpBTwxMDhL7pohcBkXmukVUjqK9t25+D+q6niaSiZSaBzK6sHsEQ+GhntPPTB1lSQ7cFQ3gUzo3kjGo/zpVhDeJ4U8nmXx0aVEDPj9UXRPJRx9aqmwGm7Kt4GVE3XdoGi2P5uDy3BiWAg+9CNzboXqbqHosnlHuYmcCcYn3kMcL4Vk6U/h7HLx3KIcUeGPjNL1cS95L+emlLTLBkNzoes7C6J/Z/jk3jyNfjxHqWHcwe8Y/Sg5ZkGG2zLQ2DkNaqw8Zveu/Nhymo6dDECZMwnG+3jCHzWKEyPuQatnpDlrtJO1vrMHyG6HYitLqETVc6dMPnzvsRMnvTrXXds4yrq9NAWRjQGQiPevktZwKreGYhzw7AenqXl6EerO0wbKK1AxSNG2UIRGsuzKK7/kiD2k0jBOlGARC4Ivz21c0blK3hMgAVGUj1vzGBgitiOENbjZC+xygVWmSc62uKTxv794ztbZuAk2cTcHufyaUb3z54kjn/4UB9FKwF8o7T6lWaRNRjTX08cOgol3rpCMThlCca/rYUggnYN2+ie1vdqKxIjxh5ZJEhP0KN2NuLinATOOCbfUZodTGUGIJPwNXg8/M+b9nJdGdEI26mYvOIxcQKU5gvshFhENSkx0+70rWRXiCWMtAX9vKSCqcS93uPGSyejPIMhV1y1S5U6plrHq9+gHk5KtAFPJ+52LLK1i9iXQPBrlQuWmuypBDwT25EDWFm0ssyUQ5IhRPTjLmWqLIopn2GD+k/SL2jILTfMThUZGQvAH82fMPzN+PfyP56gd7K+VI8dqwH1gL3rwypZCbN87qi9o588HmkDua9dSztytToKfv0mUSySZafaou7YBTCJMI7qygAlGHYxZPZ/hdvwO7bAPQAnVA639223aIJMWDavzc49XzGggJbLIK00LOxVAh+UmuVXki5h7T62E9zx8UfLkGub1xuo+UgKsFYYYZYOTdw5PH53wa5hRJ7R+BDPsqfJ+kM0gjQPZNcvHHOeL+zxm4Yqo2eEleXcA2tVVt6n656k/uarG2XXf2MNsH1KRcJvb4MFppLLv1PW9y08VINvSfgjRmzY9ZlPW1QCte24xuQ9GAZb8cgYW2573HTL4ETuwKuRCzp8hJWWcqHGoroqUedzEwkEhsSaJ8uLXMI36awfkaPq0AUKa4Z4tM+PnmTD1S+fGtsagzbDNzRsx9xscJ6NNXX2i+gRoMnz57VnhsC2QsmJ89ciWuk/29p+H3Qe7yJl8FEKOE0cf7OoTSqf7feboE04St0S/81SB5r14loJsyGvWSstPNUyILgMajpkJRyOsM0wORLgnyPcFIpZheG5lrK4OlROXFlNad0QlxvjIBSlReR2pJNWcLxVAoUt95JnpgjiGzifZgBJApFY9c1OsLvHczTDY1Skxv6lc7H4lw88CzcxR+Us9otM/ZOe1+JOiVcOyl3ZhOybFLcz8NyXyz9b9gU8UueeVC8PEbYu1ob3Nc2DF6DgTsje0KmCCfKD91B8Z0plcLI19u7zA/fF9g3BQc81ie9khQd1RXX4rQ3JqjJtMMXyqliU676UJTCDl0A5H0ewrt5xfLHZk2fnyfQRN2wPPPNbjdxCQmGU3JsWCHyi6m3Hh9D3Y5X7sFN3cYgE2MXN26/fr6GicVpD7CqfwGb9kxlSqBBXzF4IvjPBUjammGu8izejMS+IkUyHkcInHPy1krTuqLGXc2XGj+EBkD7bZCxn/AaGamGmGW0y3Zw4XUnUtSQKuafKtYmqZEQDL1v9a9SZApzbNmpRghpClYvCxX+envkN6A6C39vEEsDR4pYFTHp0Wxau8iApH1WmYwKoEc/TeEoPiTTrXN6CV5LJyhmXhYoLKwKH8wcJFFM72nTRtj0ixxSuJba/iGqRaNkIuSujZeRQtpz4vlT7tch7lcLSbCYxZyI4SkH099w5Z+eSjHq20S60fnDZ9LPEKlxHK8cyMU1uB9i/eZZg7hBxjT8mqJjxtoKrKVDl+H53lkLxB4FNQvShZX+47/EvHUtdnDg2hlgg5uwZWZ8rVh6ksI++QxrSMKtZMLd54gktMHZQSt2ZIwVP9k1YjRljNpWhvpe7f/PN4LST8Zt8jO3vlpiVcm5CAzz2oHzE6nQWNFekKMnn7jJAHTP8QvVlNULnjb3bCsB56cUL0cQIFCYGv82Csm3a2GQg9471X9kYd2ctJOrHPlzjDScBCK+/aocIonEZw1XIMQHleIt/WFFI+yYbEj+pjFBLhbId2m8lXMmxd0/NW1tuAyMvY9Ux4f2LQmLl+o+3xYWQ4JQxa/uO9gV8G8r7B5rgjClJaQT8w9hyMykCQ7S3TYaNWKQmeUlscaKtdoGybdCrvRRNrDzfZ43tv2TrMrNbGfF2B1Eho/cmHlQ9ToeL8Vl+Rx9kR+443YGht8eP59NqKYiRGQLaC5fYXfljhLOVl/2wW1EuB+LPXgzBbNbJ71it+9eb9pOEU7dtQy/DTlhOZNULLQtsFXTqOy3f6/OqTNBf2QEX/ESs5gMeEcJvXYTF5XSXbVtbZCyKM3OJTy4bSGxRFdOJMguhhSPijWTsLLjlRj7owU3LbFLWvCc5EmSTSGI5uAj0WGfJCcfY8oQ1LcEDBrDhG5Qayixq+QzyaVRYueSn3ZpyLTKkj8zm2psqn0W7pm8cuVBjSpBRyZdEJWgMooj9I2nYY0pcuxHVhHLRZ+SaIeflPmXY8oNYxCH/5u279Y7YDIReC15dKWOcDY+u1N16XHoR+EXZmLYQzzM/wzgsid3hOA83nGIHUc2Cg0P9M9RJE2RHQ0IoeDsjXnoovlHghTuvbnCOedOtevFMpzzX997EVxveBgMRzjCp+klFamQPToPrbkH2hv7TVjCt0aVnaRHyf2uDuZmnzrOMBMzKLPoDz3ykQ5bsQKHj905vDFuCCDxAKCPRznjnmbVu8cKA6WV4HSLiNjKLKPcGwKBNkuToBV9mnUQjKI2VzKeVwGok5vQX02FQOjoeDBrtqsbbOK491DOJgBqlCaRD+giLwcb7/I0KSYNfajSgl3JngJc1l4v/bdn9GZQtSwT94/sooDoorkptCghIQBuF/wAQe73XwJfahPuoNhxJkYmnF9/7iRnr86aDfanpTuRxJUdcVvqCFZ8rb9qjZpYjIapLTBOulYQqyFUapYlpR91czWe+6sOGo5XtdBnGvfZBYCFSjK1SSVnw9XWkA197Jtds2P6YbnQnvwdd34rxeOVlK7lFaCdZfJuW15N8EG42iihbg3ei1uPiZpBllLSeBUHyKLKW0ieeAidcJOu3WSBIaGQ6r+YtCh+gzvG1fI91qOaV1O/ONK9oHUbCvGR1PxD4NsZHoFvrmtk6sVF/KPK6emletm5e+VNo9Tmt+aWWMI7INUXEjEyPQhvFa5a88VPpRx0RTampnThwWJGomPbRhvrhnbERP331QXydXBFGAP4WVZLA6P/ro+cLIA/BTH9JWCGdB1nuI1lFYYCeH/fQMPEDqHg0RU/kAixSwecIPCZOVxyThG+w1tAfXEiYNBjBa2IJLPVdWdF9IMwJaldX3qV7Ui4RNh1lphTPg0L+lWR5qJXC00B+HU3PH+WcKGqVFJmMaDe3W9NxcyFB3f0EFQZdkWKc4/NStf6X2Z9w3FhDnHVwDsoijtW9EvCvuV19QmjOSfLVuXu0ls9mDPL6uvJbhOPIvQyDC4wrC7MzinKrmw6GJtLQYo80yujADShfgopG4xhw3i6SP3N/Sxj4S6O3emC0bSNu6BRPZPkzQd8Tb2LsUad308hd4GmIOv3pA1Eo5itGclm8X7GMq9ppnne88PIww8AcL1LTYxj0PrCyRd1eUJyaMrKOdh3i1i4PBqTskZ2H4XWCzV3atfKHHHQefasbnoPtFj3NtxASSzLO7kcWRyk4COrYpEg+ZkDcCXZNlmQ1BPlySmXwQhhGRpxcAf5w0u0+me2M1tEmFLQyj5OGi/Ff4B8AquUure0UIlcp6YMBcsXmBIO6g0A1ykvdMzR0H9gnsE6y+5ibM0NF8I91pQ4e09sZ2g+BUCaoEADR2uRx94HJX2yl5YaSpLBmJ9QBawAOJb/vDhKUoB7Hat1wF5QmCN3x53RM5ktVcpUB8b8StnHtPlz4QUB34IgE0Jqv13OuqUq+8l8y500+dL5we4AyDvGLh+vQYAi8uRNGu3+Rs/x/bcDsZSqa00+OdjvrCPMTJdLMIYYfdt81GImhLe1dKsjYC+JVeoCWqLI/D7FKWwauVAt9s4OTJQdMaiLKnYDMBsqmvJ+0od9KDbHxoYxzebl19xNJ8+7cy1vppjHyqUx/hgpfPYLmBXwgfBdmSgG2vyp5slInNSawx1az2f1Nb5lPKfwrss0QTn9UxgYCQhQIQ7Oe0o9TS0/pGk/xyh1g3itCZWHdOjSkoq6nAhvjhMKRP9qJzC3zu2y4zvz9JK1TLk2KsPK9kqBpGV92mm+op/x5MJCkJPE42F0q2qISdkDcFraeJ7CVS8rDlkCQtQ10pZS80RQf2E+TxJO3zA9TICxX34gK2+5mXX2Vj3AAi3bz78B3mZ7SeUW0uFAB/FbCh8Ade8gbWKwgr/GsIVTWa1CZZduHcCTI0Iyqu6Chyyzo9eP6zUSQcaPRhStKCzXlWVknuUcXRRpMjr2yunfFwXXLasW3wUqBO1ATVVI54UT/TIF4bip/wSKvfjyV8oLrnqgDsR/gD2AolGJjV10dqBc62R+4f1XXg0fQJlAeAP1I+MTimzXGmZfTmgrz3rQ/2pg0zhb0wFijGMzXosNJkORI2Sm1zuhDso6s3AZiWUON7R6gKNnuhAUEF5sREML/nrVSpxzWDOxzN6tQL6IQMiqG87SXjXrqzPtryYhAW1sXE4nrcZL/rfkLpK7yaRxosLP7ks9WweMXPYRlE/QNaDtP2PNn0hlOdLxedvrU6rq5HmMDC1K+L+DevqmRUj8qe1PG2Lb5S/voTisKWKjIH6Q75aN47WF0wliRw56TqKWnQaBYmOxKTBewkFyGJSFrC/3DUzyOdKxr4SNXaulsczb+edhP+Or2T7xZW6QgzJTrIdQvSvhSJ83ndTflBo9wFjKi117L89wPuXiqYf7HWlU5VEOPPHzL4ELFytnuL392x/64oo2BuklKfsLtjkmA2Dmf4MoFNECrvbEMYV4F71w/OdND9eMetjKIfnDmqE1u6L9kvDC8O4XXPbsA24CyoiVJLdKMih19Zk3tdN0Co77ihkZH+YOMnV/fko5pU4kBHQ8LavhB6Vob+E2GvEGei3uq1vumSwAsE+SNSSnVTLeUNI+/lDISE3ISA/SCf10Wx4zLNUeKFbHBzh8FfSKUgCzq5/6e1SfzHGqVZQ9EceE3WDJ4+2cEwxVUxbyv1gfGdG7m+DGwbZAp1MQrm7gG9NrSic/mZmclch52/77lYVC0jcXaq02vv0m2rWEmxTbFlxEsFaiTAFZL6Ivit/j0HObOrjGIkNhKv4KHzgLvD2RW8rbcvGD8gSzOSltZxnlwWJAJvah6MCW35ytOU07r4wuaz/CdLeO5gyMqMLMGRnZ0yYrG68kLg5WaZdSE2qkO2czvBW/jarVfo9Nnuwh/cM1L71NO56ef2NyXOVaBO9SQjcNUJI/l0zlIks3MZskNkK+CH6q+Jk5jpUJ3fKFCB3hkEV5kOyOT1YnhIFQO2LabT5Tb+9KPC4K7wIksq5PzDIwoI3yuRlO3zLqBzBqZohm85zBC6LmtP3bMm8tmZj/4yz1LLRMqGtezeYWD8YnSJq9bk/QGxJlfyKfJGlPuLYFQbAgt4VHShUXPRtKt0OsR6xY8jpad2kSNBZI0h6bNSd65dU5d6yGq6DGzKRVsVDMux9pE2ZM5Df9yltBJZ3imxJFHyUZBEWliNKHYUm6b8A6hyAe+GPcnVGfCOl/qxzFqMh1vXrLO7Nj47C8fkZvKe/B8xsbRHnadmKozM6EZ2+6dPYMR7tAhx//5Q3Z6ClwkG2hkLTbO05hD/OguE1uGiDHpB5z8qxyID/tvzfpQa9WvJb7SJX4/JBLG9oemzAnf98bVXxA9EBHJ9nP88ptIkidDfdY8ybg2BZtwiocVT6z+77qqRWdGvwjNBvCQtrqnlt1i12V7PlOuNyrrc/2wRDqB7xFjASl9disl8fR0G8e/Bo4if5g2SofgtwyxlhPpUcTT9N60VYXENSf9VQXVn8a5Ncq99H44PTLbSbQYAbWbNeolOzFMCBTXvqOKE3taYfuWdqzlmhY0uCa7YxXGvHkJ09UN05CdLMmozz58sOrh+BTEhR/JRwvWyvtTyUn5B1e3GlJ5CnIz9WfV94afE1ropqHyVch4Q7E80QIhgqDWRmFooMcOfR6eHPeAvxJBiiJukpJBmm1nv/Gxaf77/soe+nKpH5VeJNQYmUSUzSkKY3l4beCKZurqv2l3QHTXzcnfzb073q4t68M2P5+6ecvMx+LmP9LKikm3/uBNZp1AihWavXQF3oQtQiRkMaYbXF85moW2S7GanTzfPHULilVehpfqszr/nOBKDW+ZuQ/AwbP83wT0PdsbsHBJ8aLJNGpjPWBz1HLpFbvK27qZXq1Zmh8eyzfTCuPqWi1e3R+aQv6iMJvik3ZbN7thLL/alL+AfwCASXgoN5r6cWdvwbRq+V2uOXQDZP03YbdIcmRbRvE/BZGzvmUkzy9Sfsj40D0iUozQMFdEZE3FH1iakKYraJaZ60zpfkbkzUTtiOUeuXOnsbvpS9eNwFR3Mv1HQmL96thumcMcdAp1m4MfTfHhZWPutaEqrqxuWD8hH5Tcm4kLnJ+ddmKACtvyK4U85XE/F6HDRdxV8jgAitEv7b665XWAhbVzYnXNLCcJrxGJeysODEFd3R8d6s14PJqo1dIB2KASOiqEUBiPeNslA7iD3tayNhyj+BLWdg0XIhceqNvI/zrJqyi8pJ7I+rPp/7CX8bxMVQPSoMXi1nGAvRlgO2Ktu9m63WCZTVw7XQc8kZZ5q2sRsEneTdCphWipiVoXmp+y+C3yGehww62zMhGrGH3c5QS7YvdzpIA6hpmOmOPn0/7LDsl7bHbbSXewx6wmjPZ1Coc+pKHQq1Y0J1yqWdeYLBbHO92OkK/u/eFUyYNmPhBFWB9rHIpG5b3h5yqbfiFjwFepTWATZQgdVx5d3tUvkfNRzWKRwPBeEUv8F4LH9jfNkW9X/R3yhPPCC4GW0PIQ041E4uA+IiQ0MkA+lRUTHKMpr1LGKdrE6Dqox1Hw885pBFp236nMKtpL3vbl0XTE96NpOmNhhewjgXgCC7uKoJ9dMeVBykWI4iqGankjrUNDXlEWKuHv87XWUn3hX5/SrVlG40xlNyDolrIZSbIyIxyc+YIVPtO26g0Dqd9VH2XSsTQfl0ltRQwD//X2/em4y6P/ZwE9HUBoWm3mDUHXbPRQM8ayu47C/9khB9P0PWLunzjvnj3V7lB7ZW+RVvkQ+Qd4TrPBvKlaWo2aGCn+e+6E40B8yQDLwS+tY8W8f7MdaN+VJNfLoKvuL5eyR0NTAGmoh4nOLRASf72/+47gkNl75po0FDclNsBCvcj1JaS1EDuXel/o2s+DogOedu5eYT7mTT9Ty2Q7FWtmB1DwlfhOz/+PlE761t4zRexlCWA2WD/a6oY+phz9qWNC8vKD56rc3VcYif3vIOvuUBr5j9Va9h3By2pkxIzAgtSXoCGHQENNNeJni5RA24l/l95sPopSdHlVj9N2MRLS1XMgr8V121YtYysRONGH+X8LwyspSIRyBuQ+pgZkhzX8+gbtinRoGiDLnSmeivpjzIhcicrHiT4unXyYnmhpSpXczY8LtdcYWCaTSsqcGT+oUH5WHPfqJec4Cqf4GqfYNIXZvXgavQy1QW2AVXTE9HygObD631fJROjt56kLGtWWnlv24RluNODXomYpQfjPaH3P33tmeWO546g3Ivi5gnscfDUnRMV2go49QxdAjUEP3TzZY41fuIHj1VmEywHN2An5BmjohJzDe9ObWa5O73qQrznkIsafcTeA2OrzE6rWOWph2JagIvGm/CuF+/Ze1qhEv8S7/NTXjqrTA7WFHv8pD7XeyswXQKitXrJNgXoNIX0fXRbSawRCR/MM+7eXoy/lip8okE7+Mjfehes66oZOL26Ct2qvm70Z3aICThcb44zK/rDyjqsHMuVJf1D55GmM/IV5UnAeJq257Kcd6ATPG5RrMdaIBe2I9C578gHGNiSzqYLurLe+h5DS8Kku+w6+1KQY1xpze7v2AYRTQmNhcknMrnMdO6ez5+ths0glC29oVIfidGTmE61b9ljtWE9P6xac/lx9cnJ/2w0I6KY/ud0t5zno4IZtOIbOO2JHRXHtJetMS+XQBmOIqIUX9Q+PCduZXfzrX01TEqSxQ6mL+k1SThPmGCi3rzL3HIW5TnkHzrS2c4Rf9s8c2wmsVd2lRYpHEP4RWPkZIWe2vJLo/TRtkv7cnox2Ip8d3QU1sBNvMTKhEO1L67ZqGEq6ejPjRZNNL1oCfV6RVKZArVhNWENyGazi20inF/mJveZpP4IXOv2aHFeq+++C1V3A0C22yc5aEPE7x6GhXXtpdcsGqbA+zjksluCIoJjjuK5jLHvNuvdaxMkO4cGZcka7fIPTn0/QhwZ8XtLYBRF1VIeaU8uhX97w62nzrhi2ppwV6c2BVoFERy41SftIA/xEmlarCBodagS8vep2wlY0QjgC2DhnHbQ91pm7z4+C45vZaS61XqLPZlVqbeQ11xsUIflR3/+Nf5eXCd0uK1QqDPYfQmreXXn19JA/L2KVY5Db4dhhH1nd7l4AWDorYNuNODx1kakSZVUDm7cvr87Jf8g31BODdzM6i/FZhL4ANPUWAQ5kj6YG/F6doRwM1+CDt/OeTNQ+XMpC09q6EYmzOh09b/IcstkVGViTUPJtu6LGiWjQZEbiZIDRzdHxM2xFywnaNDaqz0b+GTI7TSx58+VKzG0+cwAI7qLEDNAjJ7OZVeN2LXW0hEr40syHQM3/fGR6Zto+2s3aZhchGRcbV/yb79LZEyuv3cf6VcLX2qsfCnUbh66LW8JTx/N+NrKOEdVHiOJHWr2782a2FhR1ATZP4PWkemdp15Mav0khkEi24f7Hk+DIt72eT5BaCX6hSbxgIf7fJIS+ZKkCsjsHk/L8A30SV3ukYSeLT8gKjVWPZOq6XEE0xDmYg7cnWpo5N1l/Fq8fDCt/f7T9bv5MKd+cipeBUgRqywEyv+Yjp3MUswaCswNQrW8GRLW/TGwY0GqRIjADSKfO2FYrInKLXvNVF4/l/zThWgyHCWAhntYLWY6yp0XXt93Zig4yASSI62ypXYlnQfaRUw8XHDyeYu0ED0iHxdRDS6oKDsucfwvD1tRcvo+gc+PdyTXEsYY5y/q/a9zepZSCqcq2G4OXL9S5DkulstVyeEcoeHPtmkGB+ZNuqc15zUnRjkTJxehgHaq4Ra/HPe7UIsOK2lGBYjVIHZqpGF0QU2RfH/zpWIcBnNSaP7w7lwUd46bIsztKD+K9MniqegUCU1ULARtPrcVbp9+XCWs6uJFZYDa14Jk0JBk8C2mQD1v5byKQyQbUd2x3kXjNRRaA28bEZABy2q5PD4YAkCcNZnaVDRCJPDFcoN0QUfVMNhQ+7k8DjIqJDev4FVJTwoRstYHVakZ6Xpckhs9Yqx4hXXd9lNKbGFSy5scxIpQjSeKLIutmzMlDSxIiHUV6HmPXK7M/4ivAvGMySh+/c0Yv78uMcmonFmGpFD8oNa7bSI0K/3HJNDpUDLxAmLUl3DhD6xsinnhBqCsKoOkJ9eqwUBwBHERyTJeBLTXZqVPl4zmFcmEcsjyqdJpXtesph/+kSCWOEKczTIrpFsB1i1v5eK8gO2DyBZ90Y512ZngVlLXULGPd1YyEI7l6jfhwTekP1IuPDlwURg+LgaejSW+87yX1M6jOjFaOJOYM7j+x7wQIhLoozeB3uhm3esaVKOog6w4JecXHk4MCSTvXSNCcXs2lyR2Gx//Ss2KSl5GYgYRzJX/POtlpPrynzuFSScjh912o+GqcmnUmtekXejvkOqqfz1OCs6nHTWz2F/hoZIb4YG8jSef1tquAHN0xWP1yU2Non5xdTLokLVbsBYHdAZeHedtGXLSdPygcVXBhXz7qRGgp83nKMZmnN8oRg7nJ1sCLg5Tw/xo8aMkDA088D3fdetaFsS6XUbi4pb4Klp8ki5f9Kj+fUe2BrEjvMPPqjiOFvzknzsuuFqaq/MPnMPhAqEafa+NCba5eGl7qTdza/taRst1EiQFvxUrlEUdGdwjPYdvigFyjM5MfqUePgqilvHVy18aMTLmAFN3QUTr+m0MFxm7Qlbku0aMk3lJx7BStoQtYgIC4g0wyNIE+5uPGnNcfILd5h0jNQqfP8aEf/LDf8ZY0ebmjV3v7zPdvZMkJI+wL71RvUpi/wh6QHW1QDMn6Oph5lf46bmFzudKuW3G3ECKgKE2Su/9fT/c8o1t88G0wnr4mMLTBf7vcw4duKPxyBiwVu0309aYoJXQtLgh5PdpiyndAwC0mgdZawD1b/1MQ1AZFL+HmGt4wN4WHP6Y/LTvVUIor+psDziQ4c8FP6ht48VO1jNzw4WUvO9B7ORJDYeySsuXvwLoIRBhNUzVREzzl47od2eN2anV3OQQhyVO2Zq4HuTU60l9klCGBLRFo4GH2qn4orNp6pxH/Cv0+eXoUQlm25LpikOjOVwPv6T2MNZrU4Qn9zbafEBU/8wxtmAjsVmp0DHLJ39dMgyrebEnrcMvoMUaJGGizM9gNiSTUHxsfunDroGVXEsz8JopwfLODh7fCLTGjbrHMW6PzLk5Tjc1GtsSaHtTd2PzQgwER4PnDxZ7pjaZ5jxMokDm4hgi3XUiN9vzir7HHsW5M1Ievs0B8164L4AJZ6Gq2OCGUBZlhRZWcMoVHgUK9vu4RpLI47Ba9HRePhAlI5qt1Soe0BxZEeksHZPyz8TeKgYql2BnSyoiEmXFqixq4Q+Crs1mdPnYyKrrAyzV7mtrH+IqKEfzsA6DdmotgG+Ak96W8PIX67mLxFnBbJfTgCCC94r6iswx76QLy49npKyMbKA6I2feqJVrJExCdv0aSQLJ8r9L2g/mgaVR/mcWIj7xJ2akHij8QLLSh0S9T7DzJn4j+JNiEgdkJNLmyhxpZscvZuivkSSk1Afp3C5Z4bbHsN7zVeTfxOtgk+lQQJLBZqLWiuewNsy0myDNyvAWCAR31HhzROOFzLfyUqJiDFfbOQHZwRXNuARObQYuEumUl3aIoKkd+WxjNz/L8gEFKjaQjZLTJb3CROkbfTiyDTHd0oOa0FQdJBP3YI9YSNact6AIMHmZ+uZENUaFTbBdU4AK6Abz78fmC8jDUQWbbfjH/SHzsYlCBbd66QhGI7AfbaSJqIrsmJbSDdrZDs3uH3ndlqSUAB2pkpR2PoamXkUN3nHw66uuODOj7KEI7aDfuq2gUOQsyp0VXinyXHtW8zyE/MZuxWWZU0TfkjHPGNPnrYJYoze0GpJhpz6zPFzGOyWyYyJ3iaZWA0bmgBbACtGuCij7DuC12L5NETaYc3KUDeibLtqKB7JUKwwlbz/FKGNMywNh+eGenlYCyY0zuNvlswYB8iG5djULdudjmI7u/A/Kx7ij6x3vAxU7E/iHwWP82y7pu0UB3jg60sNDFa/XHl3bnBcA2x60lKg7u6Mdlfj6IM65F3LAyvj8t9auhb0WMjBuG0kQ1StWkwa7DTqlvc9UeuW4PGLRdLwf65HX1v74EZnpCfuqLGuVrnGAMgIlHTfBOYsHBMseBOYm5ACcbTy6jf/2p33BYJAWzN2SXtdD9HHD5ehs/JgZhA6kpaPXLYVKA/hMMXLxM32xKlTX5oUfze+p9yZWMq1VkePxG9DGb124kq8tbioV11wK7iTsEvnhOvIQZ/cfWIsAAspM6Y/Hkwrr9/zwF3QqvfCcR6wTsWRYbc+qR6xbSWE6lckwDGHiMqu198d4sVBVFphoyJkxjHXXZ1BZIe4XBig+M1v3nHvDNRUMvDbqfcRh8gOY1QBJDpViTMqsdL86SHEgnUVn9EVjA2sxeyPm4nU1Fcv5z68LUc/AVQke1jOaX0fdHJ1rvVhjRAV8KoJVwsHX/d9UZuiz6JMpFXayuLM9il3iEeQYrh7MXsZ1ruMBvdSjiHU3eUgi//3VTaII5HVFjw1QcIrdF1BTCRwFD7a75/8YJCtJRG782M3EXj9Ds+jiYNTToZr7APA66nEMQJr5xNhDX67j/VbdAj5Lx9j72KeobSMlJXQLpe/ZlQzWgRp/UmnAmZeFCbqIRt+WYJrHVRDSwuV5qAUsNdudqNYgUP51TmDiQZwOw9g8pC1e2/e7jkfvlg2fCXTvjg6yQlaQ4dbdqCZ5OrJEcTxkJekzJiw4nfq7Ty1MX5ltw4zm0w8rR2wWXVNQCyOhikehsa2wkNgG4AqE1ZGeGw72+bvX2VUrXwVJui2fHJ17RQMblz9dVRXv1Du9mp+jxx5mR8rM2Icnlhj26Xaer+MhVRvm1ZIwrmFSr1XZMxu2+XF+4IW5/3u9P1Ic1NtiMxEEJ/P3p2ELtkYMDExvA+0KgexatfYZJth4jRWYadO1+nsJaVHyclQXmnTZx02V6AfAEGgOKc3WgnAcEDnNzX+yI36IOkPweuu09PXnzsa1qx+bO6ouXVeNWVtrjsxP/vZd7Je7VIUsPuNMdCUj09qIRtA8F38FvobzrWex0qCf822DYTBejqP/sBM8833qbrejzlSaU/1wp7kwvodDvtOWyqq4/JW2JgvduJrj7uf3Qmcx0xeTySVla40gA5bTCCt70f8QSRUGTGefaabl5w4QUP7zIk4+Ry8gvhwvi/bLS0ZBIUY5TYbfHNUrNGhXV37DNcHveoVe4pXZMUC2xB+u7+10UNYuE7Dc1Uf0W7k1eWQXgZgvYLAuCytRnzgk3vPJjGGHxedtzT9JJ3ckscKOUW6efaDm2fcOiIwmO2CT+QNXa2NE1eIGToKWu4QhYdkuZD3/X09LdQns/J8rIl4mQyolJyk1xV6H+rtf4XWkE8tQp+XiO8qnxDCBmP8FaxWCCywLzavw6FhPYZUjH5gOxmxfmw9bnsH0ZLGszmgkghKg105KmfIWem62HlnfOnM5FfM0XMSw3zLv9kF8Qv1XzliX0nn/h/oqIhSne6gS1Ud1Rj8C+UqjyxoFAowokBtE9YPiTz3s9FHSAKefLrJq8GEMLh/MJLZ2y53O5SDFTib4uDgaI7ikdnVBcq0ykP4yNA2WIFTiQdyo77cfdcNHycoZV92ThtMgpcgaXCQ5ixYrHgxPZ5/TnudUusDbxlaHGMd3ChQ2tO6b3IN94btaqDO0gjatn7s1pMId29NZoKkkU2B99NgmuCohgogDQi3TkX4tZ/c20U6I5YKeMDc4gcTJDntt9kQhuLoqEHXYhdc7/JGlBuVcp5U1AHwWCFn8DKaZiQfbXdldbQAM/eUs31kAQOBnY2fb07Y15+QWZ9KL0G32N9BBsc2Hz0qC1CxqoiE4nU92t8z4mXYcTtqNXELRQXUbxWXmBiVSy/OWG5S6iuN554ypaLjObKKLcXI/W/m1G429XzZVlCku4bJ2CPg51e9Zl5zK9mYm8k0wAz8zMFq0pOAgvLiM8FmTadQ200CAsolpTt8c+A5MOwqPuRiUfUuNJUGjfZ/1hefSlQRB5yDCPxNEfv0xQbO8oE7F09cRiYWb7oZ5sC/Z0e3o8uROl40znEV1WWkYgb2r6wiqfFQIzWTouZlGiBJPsUtt4jFIFiDnf+CY0jMCBkbWWPH5ny7N9Exb0RnucB7Gw9PrlF88JAzNroo+iXtsGqcv7TCcLEjkD+T11Q7C0AVVg2BteTrktbW2ctxh4rWyKWIfZA0chpH3igrC1suwnnaBBqMO9EcAsyGdw8dfCKjnfZpiefhVXi3eDhKcy/fHR848jL2YYarJ3hlhuml4ykzK31wMVbmE9lWWbtcElEsG5qx4fwBs8Wvi5OnmkWtZUj0EFzACzHV77yxo7u6bY75FdSlCyeYpr7/Nj2OMCkIDec9EDZKZpfBOJnTBNrKnPmC9S1h5D89x3E47ofW5JD8blVl7xco/84Q+GHb3n0mEIkX9m7tGibGXOPLyJiluwhxSlo2ql19P6q5/Qny4Ht2xeraq6UUf78aVcf1a9W+1giFw9hFa/xcDRBB+WrKbSJtPe6cAkFNOf5XoCC3j6rxGA7OWYg1jsG5lIh0HifAxfyj5TG86cWK68Blz38vxpN4ObUHI5ZA9RAKgqrHSvCfrazS3HwGrselyW7Om8VIg790GPDYKvtz15koJpLGhw4Sw6oNzGTj/KgfHedulcH0FI4rmzjTIAEgXB7ibfWDr8Oy2pVX42gZYzpYqbi1kwk68G5pRHJsBYRS25xlBHCZzIeF3UIWQss4gyiNMkyQ2a1YwiIoOZ1TIMo7SYzGFsLaKgfOzbDN16GUOFCldX40i59WcPo9OP38wQdKUQleWIs2S40czZRL3z4WdWqgb3dADDQOddqXoCoQLiUxn5vs7UuCVs9bNI20R5hvRgW8BbqSDWwNesruYl4sHKfW/Jof9x6kI8E/c7t2Tu8Z5d7l6l9W/c94cN/9064jTDf95w0/mya42ykPCyaVP8RR6SLO/TnDNYhvkwto0la/sfHI0Dt+jpZ9aFQT+xDupn0HXVcow4FtoP99RxFgczidMvkSUG3blUzIAnHz60KGF4asdsOo0baAWH9zjRK6BodH+xymtk1SoMHfMK9oEFg7zO/THvLRgQZ+VXLMwHgV+f0OOXFjsCGfWcN57u+Xx+oPL6atHkbhV6c0KvS71XJc+a99b64hZ+R//ihJwbvZOarqT5VrBfpiVhKb9BkChR8vIPd43akOHm+G6DfM9oJPPJ+pqk2kwGlbsouaDXn/kPlRzUgbhy46+c0SGCvPellxhGK7wtzHV8z9kV1+DTeWIv4xJee9KEHAre4RM5qUNfl14rRJXv8JHXyDsVpuhcMiTcML5ZuCTTlu7drKiFPQvzRHsCL/6KhOLXEChxqZiCNONQbxJPSdFtn8OqTJ8De6152Y+SNCKQ6r0ZIrdwQC5WIrz5PRCArFNt6yDp0Jt1PeKRwzN7/kDBIrvEGrW3oTt0xGoMSKdGSoEMTbHjTd1bmqX9B0r4FH0i0TYAWPDHcS8KZ/5UvXX23TmoD+YrZZLUqvCLPz9KpSkblh669qBULt1xUOQ0NHcZHsbwjLS1Oyns3BnY993HwTBrXtrdDdEWyU2Ge2aGBT4oOICrKiXGWbPsnBXDl45hFKQPrcNEtuGdqy2xF9R/BXeA0Zkfz25d8d08zRxuCS710iwzYnaodEit+ULhAXbADj30ApNi/3QSFr0WLq/HHjnn9fVXy/ekeca12X1BwYmXOXaziSrFx6zmyz6WmpHztuBADqeKlGO7XDokDMwr/qzbnkbNi+GAIZXemByW4TSRcu6f3BHqB/QZstB3K1OtXk1SG1HuJCF+p69MBF86GrCSp4mRcoRRu5OFAvFVzHV0GHs0IPsU9oSu5JIRhBXMMgISE1/0SmoHKrxLQXkberKhY7QjaiE/XvfvvWJe+MMdOuSOLgiJJM42xPclMWM3KTc8hJpWmJKiM3HLlgxZUHS5CGkg6GRaaTFxdHuXlrWXmbcAJxfKIQ3JCBVZlbj/MzGhw7nPR9tZW6RRnEsqWcATiKixu0CizGc4eklB+btBocp0ROZD1zXv45HLT5vY0ypPnvaBhcv13X9gS3yTZH6jcGsSEIaWV9pUgur0L53tc6Aut/mrzCCGaAK8KDo+e52UaUNVu7J6N90oLYEKwQs0TfkQQWaSl1k3eTc/tg6d43RuhXpLddWn0SZ1/nGcatRFRfGVNS8Wcdh3ALnWFZzUcG4TuJHrTs1J20CX4JM5xPy/txWUtAfrXGD3WcAz4z1kV8xyYCZmbupyVNX6wrA2NVNHp4BGP17f5BUrkDRI8BQhnolw7g32w0cNMSzv6HQZbaax5rpp7K40to9NXUIPQX6GsXx0B7QX+DLT7m51DeUpasxsZ2FTTF/fWti26OI84zlW5M+6ZsqCtDxi77hqTHtiXEwZfMjO0Ll56knbc4vhqemVqj0svdrOnA6qEVJd0GxGRTCJN6govd5bZEAoFdtOZC9+bkmP74PThaU6VcfTOzTVS+nakgcwKP8PU/cKfF8XYpqDITBKUm2UD/CG+u9jBmhR5wsabKH2M2hZB3K519hWUbz62svNeYnG93imHh4b/y52TMj7NF+HGlewy7qzXLPycpwinItgw5mX/TdulzeI2hoRAMvyuk5bw2gfNLApQ0ojKVfPGuu5lALb4qoM3nAAMnMUgwJlmPXVTW0TWBWLVguVaTn2IJsrtVEehMtPhxM9A4q2f098mm20XUk1G2E1UQc0Un4KZUbfHM6/eY5cxx3Z1JcH2i4SEsAwAcPEhl6tWMpNeTHAR/uNfn1JO9HYrg87Fv6lZvGoETvO3PIo6xfkDpJNK7vIkSdmRdq46KPtfMH2cbKNt2OtjMmHtKXoJ2xjHrhxa6dOxeV9OYyt6TY7LG1iGPQWtYwAXFvtFD+3F2BYnFpPWPfhbmfDdkYY1618tfNbhhHwiP2N+X5sZAmedY+Q38ZM8jcWunCbVf14jyOtTfj5FoSsKFhzTEPot0Fuun/d5dvhNvd1dMbsvglqddlj1ZJhdHSEpV7pIZnBxq8Jxt0WCXNf5gWSKyoVLFZWLkdpCpfV8UDYXLXiesnRgrEj6J6qujTySB5Eob8dPG8RX7zpulrS1983oY1VI6vLWtJ9/qZXzhaf6laejQdfYlLX/yUPxFa/4zwyehptrlE0uhdLeEgs0PDF0V+uw8d+56GVJMUyRvvxiMPip7bJXftVuDEL0Z2OnBGFEVkqB5vqchoNvcz3AzC0pItcLoN8OBKremL1+VqUSHdhUpvGcXptOe0ffeas2RRlTXcp++qTcnhjI9OPLAsGpk3gwlTdeUMI/fdD6sqo3OYIVPFNDEhFRoIKGc8y3Ezy9vI6YiIv8E7sm7JwJaSK7nf79VM2wYyOtCcfJRrjteGYyYL3PwjqfYRR1pmdNdkoVyG2Lud54c5Nt0rwWvdgKK3IgP0x+hWXTA5qgZzP9i6PJt3HLWVlfCZ9eDFKY3Tst6odYZCnHOQXf9V0UdwfjIzvv+wXJKwVDmbDXLzIlkQO/h/iFcQFE4vui2uwEjVsKAanPBXjElptE5kG83g2G98pcXbwkhWEQyt1UjWi597a0v5ttl6Qbwjg2b0X5C9wE3gIFe646xERvL8/lf7bVMDD+U7s9k737wrFiJ1//OGfRD2mZe4UPkYjhk104vq5PZHp5C7cx2TWE2a6TrAqmz3dS+g83s2kxyByF7rZ7Q4iuFzdOC9gl+5PkZKfele55/bBVlOG9yt4HG3NsZ9hFW6l6sxmVpd+ISD8Qr3tjDyH6WWavUJhSB406denG6RmqZm0FAyQB0KiJTCUGd7cRr004YlY3JqZIpV2d9o8ymgCnp2tv2qYj/ynlFpY+xL8KOVAbFTjRjU2RuhqjM76jzyXMyvg/X5OcME7SbgbOTocjb3tV8cLdt8v9+R0kXBWewP3XhW9ovsgjMbqgGexxhRn8riC9xVu78LLTBCqpGD0jMDnkAU9ljk3IBeZgxl1PLM64wGnyZOFwQPoNUKJ35xMQG0hrBwskQXOtrY9P70CBCmvhRPGjEcrk0g1GShlrG1tDfjykUOQpjgOHwIFlGiTAsVNcxal4UfS1ihYqJWafppzkbsPffoTZUffHuh7aHJ486u6ieS0kA8kfo8hod5W+3Wr+QCZNG/lApgQV1uUjsfyUP+hFSPmTOoBXhUbkjD6mfSzlbwnoWIRGn8ppXWczcg6PmvuotjSEn+NtfrTa+tt+Vcw3QILIkcRR6FxYG3HqHkWbAHPwjSO8ct6SdkEfNxonla35ZVjbcmUuu2ERoRgA6uI/W0VhFfFOq7ta9j446jwTYZDLRobyQvDnv+nDfuHvTQbm9HbKne5VfPAaHmVZRHbkOwM9UsLOjX9hgZiAwDM2kEuBbvr9i9DA9r6gHDHT4PQTSY0hEWHSRZY01XLj5ges68t7KzYphJYDusoyUm1MnVOISO8f0rDW73pK4sZTsGuZzL3JOFTuHs5vNgfUixMKf+8b14wi8ukMM43kWq+LElYjV1XEtT+wO7bM5i5IBy00D7tw7ejF8f4qpChvNCw4thfR1RyllB1VDNwKS4LxD463G9ibOLMSeW50D0EPpG1/ynT8AM6wnzSTIktTXvvVytgsUOUbMFJvu6TkaZ988xkVaU3Spr3mRcVoQz+aglUNts0It29Gh4Fs3gba4rlIQo6rGt6cyc1xrNbqpL+f1ul9mfOxxn8rqsJPrtP+amr3vV4vG+eqrCvzqfx7IczL7/aHiPUmD7B3L2zCD54kS+KThllRtR1Ztw0CF2nhV9fay1vt0Bhhb3vzsYa44x7jUXkEkwhY7j2z2Th1E5geGhZ7co4mb+UV0P+ByDEiMS/HE3r1+vxQOho696TMZtCxxwxksGi6IjB05UUSY8cdO78KjtBFgN+EgO9TTn5bsIkg2rcQA8rB17fxN2cukqByOkOuRz8ZD3bIblpIMlym/qsITm36ZB5TgHaJ2uTmL8TJOmvlXnvZOfudX3qjc8raRsyI0Iy9but2mVzw9AjWNTutJVfo7Mr6ICKF/vqDPKzODeqeptDVTlf9Fj5doBMDmYYLFfVXRKXl7QxmrNjOEslPXK9rs4J/1pFe00EkK3DOPPAM2MRzln0Z+LrZONyiAhVyLmTNHArCMWUNbN7aPtqHrKu6jzC0x/eJaYIXz3i4z15GC2NBA90wREzElzkyy7RJW2R34G6M9z+MedDS/7ejM7+OVdaXDpMJzjDjooeJ44HcbSnV912wOxqkwNwAfHyLqUiwSGxRtXYF6SPpox//yArpesLYBU7DxedcG+zMAf8CvNecavSnfpQbXW+4p2prNFsgxZYRukhqLiPRbsbO9BZtXEkrry+E3q3HTPdRGVYIwsQh+MxNx26ZxjZF9kUr+5mRzZ2FZoFqYz56LE5Ve2OQP1pSduKxtrzq8yT6XzHWM/4vS6YymkBjnddqlPE2ib3XQwVgqVzqiqq313687P/1/x2bqaA0aW5YV4hmrJoEEcZzf+McKecKO9LoMBqKlvagVGB7JVLghcdrk7mT7lRQDckzWvJpf7zKaJHHZwo/r2d2HIvgN7Gjc6qP09bRbUQfEtkCek26r6crqM9oo/XONsddemxHHhb5zutjtmmjQNTbo1kcLUjR7KOO0jioH99+EIlWf9DBi7Ancu6EaIsqAzp9PkhcOg+jl9iheWMHbP86TI/2E/t3KTbDtmgXwsVoSl6juFPHQOx9WqPV1khsUXnaeg/glmvgFqxCPi3uG46uUKEHVGWDSMIPi+FKhbayuqZMIHPOnda+mTErbVAvcrkWORuOrAdETyMEj3A3PYujYtlSpskzjFXCt/Uaz20PIGJ70dhi/3CYTpO+twtfC93etMOrNUrV8kLVyFRq7FOayucz/qNdyy2pHULEUDTzheCTIGO/y5Dl5gVv9sOLWoOFj9K6WhVe01Kg7XFmH087DMjpRAUNBRMltIBPwQtry5eZrvmUruwVZNmG1kUG0WpCPfxdSoq5x1HJWgOhoVQw0JjoxCwQpaqy3ufjJ+DOJPkvfgiRng9lGEDQH1LCO7zKhqF7tbvodk3XO8Zi2EHgZcF29FCrcf/TBZGXB9lz2MW48uSys9zl4dFP+R+S1KZ8/GHbfBNslMauq4uOF+WjKrn7+vyalMn5Rx9ZIcQ8sCwvzzrG+IeAPj5sWZKRPQRCyNEZ/B47JFAf4XWR7iGbwTUIb9hmT66n24XdT+yAnPDZT/I8MW4oBK8/aDJCiMlQ1liDva1nXRjtqt5usWHWktm0zjlHu181UfbkgArwgU45dzIHcqAuV6Qi2Y+H3Fqv6/ZLSA3NRe0yM4/SC27xfz6RbTsNiukgIMoNlFHmfdTuDfeH45aQnRZs5YdRLwYsH2+h42BIb33MEi3UCeOEAycc+1dIRY3Ns7zmvwSyuwvMdZlf7EZO2tFtg9GOpno4Ux1eoPwacj+c5Q+2eF3VwsrpLRdqWgrx9nIQtdPy83ZfMopbAMNtOW6wgDDkfxSr0aIX065SR2e2U3vLXy4lIykv0CdWnicYarmx+L/4tN+Y4f8KtELmkcqpUamoKP+pbXQR6/U69H8/eunGrkKTYJzrrNuksZtxd3pp+twsXNgz3Di7d1Fkmzj0aol5pQ+4QjXUtZBJC3wR++vtI6zqELeJ1OZq5KlJRfaYdaDjSxEvOXE7IYcgzdql5/JRXirciEFUZc0FGqAIK/eR5XoZpI5+tDS41VxiuuiGqdC2DAOcUmVk9tqNG4AZhrOI4ufOES/RxAibefyiNzsl9QOqibDvvpQ1ypMfCjE9jwb29G8XdwNM44E8CKLcY4unUiXp0Q0C61kYKr9bqHFtJq89CVDCnKiq+DiXxRdNzOva0L9naGaRx3ukzT4qCr1c2acYc0ct440OK7WQoTrz/0e6PSDUoiAAAM22bdu2bdu2bftl2zZvdj/btm3MImYhxyaB6jMoA0ojMlwL5+g/mHu5UVN4ydaHqJezm6rL5pOYxUGhMcp4U2Xfz6m4L7PqOcD4dV1jdqDJIOF/SgrYrSf37gQHXe2XEzt43ULk1vF/x5YxG/iAUmRdVgM/jFy/0yACAkP5sgj3gBErlzyX98sVOPX/xrg2xJcIZ1+L9oUKqR69Zsi+NnxwPI4qhUIKSArTG1Ekx2qT3XPplWde4LsUu5rcUM4aOOZz3kHqBBqC2Bs1QPZ96AmjNyjjfpqtW0fUYh90QvLsGkpRg+/tGryci9hUeQgclxsTYvBzVxkBokyN55wy91Op4YVGjg19m+4QSoYN/fmc8pVerCMOhE8oSoQt82nRgukqjaJzBlLxmeeOwSvOAjCutPKZ8+FV7lOTbYLlys4nc9LPVjJeGn5kv1UzHU9QhqJPDbrE/n92AJmttvsVTeZMhf22Gn+WJMN7fohIK7sQjrjxKPMPa5CIs+ddzi1hIHivj9b/YKyl1P820i3xND27TpiDEeHbinRZlZMiD0yweSNXxTGgaoAFqLiXB5DveCQj8AV/tOVxkhc+smw9odzlTn4IFzgwN/+mnJKaZTNDy9EtqDxFsIFoqSGaGSUbNTSuGnMDGaj9cyU9Jx3njvpWz+pUE9BXdL4N7Zy5uFpldFBpdvJ5bA/DOq9/b6BBxQl9UABoEtzNkFuNkwVYpea+iqRq6yTOYrkPhE3gz89CZ5cWR5T0VavNHQ7zCOllEB8qZGxT8A+qQqPhxk7oQVOixqiQKwRnotKk06rKFWH3Ewrt+343eI2g7pprb/zmL9Pt/wDZTIxQ4bmij8BdbcltKPV0qbiZe+TOjecrC2gmomGfn/irdqcakPm+ARn5YOgrcmMdEoUCE5b8FnwLJNbG85m85l040tG7E0WOT7TTF8j1kOos3IJsxsfA5o6NYUlQT/cTpPrR6h2xLg8nBqUpHkx0qG3MxjAsUQIX5C9cfztzUluQdim4bSNnzBbqYlfBbuGgz0MYEJjkk+ii9gJ9ntxn1jX/zgQH4kx+U5GWLGFBEmAUKHckTmUNiMPQNibv69h3FxE8SsOKlnG5UrvzeI8BrWq2nPgI8tHW/5hMnY7Mu5cgEu7Ys6uXdExmd18X7KZHRPL+SdCZ+ZHs5mMEMxjSugHsUBYKxDe/P5Ja3SDgrASulUe88+fwnfkdnlHQYkS4nbkvbIAumDx8+apZcKCQBl1GWRn+uMXgiu4TSlHMM3FGbgh+fThR6Ke5PBc/MOgbz2IRQ2e0yicaF2cMDkgaotW28xQYQYoJ5EWsB4qNGn0HrDtjBGVR36/1zFeChvdDUDzisNTKJM904u29bX/jEN2R7jxozzUwFh4yqEnyQOrFbN7mKxmZlbey5DaszGeMny81eIk8M9kHNXAP8U7gO6Ie+GAuUX9OIwgy/qMbLw/s5cS8/dwOUulujYunSNfGqkHi+u+SCpSWxoMTv5rnhKjMzH/H7oZBv4bM7g7cqRykIEnpn173CzHVuqz0gwwzwRB70UzjJ00UXt19AS5i5hen5OFRfNlyp5aNeljDbL0U0lAk+NCLlSXfX6MFzfP4wQJi6H9qEO9DGcs4sleogyy3y7g4tUQVfAi1dhVB/L3dmlMPaoItdAoQmhY7DAcJNjVLrbFe66Yj4lrx0GFbaLReqeSXgwzb9r89sFE8cvXhTXUwms7HY1CsEhE9v+uwqTy3oxNONYmGexW8LTfpFqA/xpvdf6YcM/JVNJ7GvGaYu7X42fB1uPcnELsUbdSBf72gMhKmT6iHlNB5G0KFwGTv+4nrEJQUs9hKeJFjKYz01qjaEyNyjgGRAeIe6x7SH2knjXscw2YTm0kI6HezjFxWck5ShngyYon42ehiUHpdZrXS1y1biIiJw7kzeV2/ZcIRsASYJb35HBeELtXarkkXTFYjic8mBhvv1BOS5M8xybJ+cxc1tbhO6QH2LASp+XSTofc6PUIrgmH+gsbK/dv4Tth4rVkjpvy82tmTsK2uQamL2qn8nvsH9prajrltJrsafNZZFI/7/GtU2x9shEkj9HesVaNhXY/T/+VUH5qLoCvUIQRMERrKUYb5VhGP8d2pxGr+vuhuqYohlPuQDrqGxI/+yzqgC0o/I5SKVZkNEVWN4dz15NTdRQSqrBLxGf1U4CiCLTeigBNzTmlR2xMWQv9KnLgkX097+Ra/S/XVCuTVtOgCCmnD2uKz/8HHtUckWSK8/vU9zQKkXKn6YF34QAXPBoBahLAhR7ptdoMtwkth10gpelEfZGsZVvdqnErBpvqTxbCekCd6WxEFDBltlXp6+VcWe8mgviD9eAFbrWLa0J+8J3odc5XaMnhUq4FsQIFJN1BKqnizcnyElRiFW2dHaLxKUYIADlomW3rj2uDzSa/MyIx+bXBiysy+qWYC2COJ8/0uVSjK7IlnxPu3GgMvLZyEyPyc7kQ3qRbee+4dFB7LFQeJINIKZ3iSnHKhxY3QMmCH2fPGDnS83q6tOYutByauzd6FCVty1KfBG/XcMX4MkIIVWIvKwjXCDl8CLK4ylp+lecsAhrl5H7nKLcaNqeWi3hKWzq4NgMO2ghAdENdpfYaxrZEicAqohjtrU76jJoiVLkmhIyVsOlDt6zVtenWY5Jn3XAfxK603pE+KuNU0BBrfmTpkZTcKB32EBuXQCu/zWEGL7iwW3AHGibjbGfuQIDITqb2+mz0Kuj/OwLJjoBo0766mfcpD6qXjFhDoFxG3H/wBIyPy0Gsm2AaranT+6gZELx3TDDhzUmZTaObbKvdREvboDA7cAMP/hDKDPm0WgAXQaAXe5dMs4bgzxr51LTn7gdomuVRw0nE4LWxSnSKeVeO/Wa760R0AMTT33jukA1MPEqciTVdcU2F7v+bST2Jr6KueOzPzIrifVLyRSDDpB6yuDC4IGHkeIzSvYirQRhz98qvDcBHZ5k8dG+WQdDRhEyl0ra29RIOH/zakAvRpOvItVXjuuGsyd07CUATCDw3awX//A6MYeRvySdLaSXPLwY570VJmnHk1Q90u6EMi/nnqg88cNFGkEyZUAh5OSRk/UIDBXLkuHkxppQvivjcu3CIxccDZjVva9mOumvmtyI7DmPVyr/rE0/WQ/KozI/zWdf1i3mCXwePDq/k+a5kzU4RZtVgZSLWLksDWStaWAFB+X71J3WwzyonbMnI0NvjbF6XKyWHveXClYk7XeZKVrGu7MmfykFUHWU4hyCWovenYhoK0zPPO537lxUsHkbb/R4OyZ2VtNhp6QRtlK5+RZf0e7hBEATVHLYQGzxPceMRQ/k/gsEa92p7EDw5A8hDPIo/9u1D8uwrbhYbuKEc0V3IoZ46f4y6YMpZeuULd2r+iEtWMURmikESb6WKuvGSADY9PN0st+gPbz5f7wzo3h1TNJavrBIKgoEIm5eprcDRJm82mqEoCWq0D3XMZ3aXLMaMCSjJx0uBm/HFQqPbID+ICZv3pNmPJo1LdVrvJkNLqnZG9NSEtWe42y/tpnP+7JKDQSdg5tVY+pRBDXrWb/xCWX0xFZh/AOkPOYi4jAJrGN602rozCGsmm4K25W/CohIS+/JGBXDQ8f+lksGXUFx2BbdLOTbhGaui30jdzmppIxOEqsP82BskGKU/bg9QbrQvqe2lFXo+J6Yz4gH4nspLp7DYxMQqCghYkVfRoqf5Wzmu4Li2dDIF641XoK8D/L6aJli5cr2D+yh8zTtEfOOaLXNLvVcfukt5AUeVXQbpVzJER7m4uCITQKuDc5N3cD4K6xImLNcSjJFokNlrwv2wVmUf7k2ouoJjhbWLtYD8nk5PJlcmzt52o7HVmbh3xrwAovDfXIzWBy0/4MSUDQIZVMHUd+mLqKT0TS++uCMsP7M2x8aQ5KYw2eF8goX1EVdxvgSvZBboqIJmji7vJ79brnAqcbCx2Q78js36X0lUwVbKTyQja8d6UL/819b8G2nQ7vNG3d+qlKsjgnHEEwGAz9cY57iYlSlYsklC5QLdx3z2/KZ/h57TEOs2VndkwFh+N5KtXLCbQvYGyUrw/u4/4HciHADAm+78ukLuwSUdr51LoyS0EkDV44RagUCj/9zx/Cti6JW8nquEgk9eFQja5gIU6aqAvyncaMhYYqIbLAeirQHLZeG79UMcphzJKBUamvL2OByJGXL6t97p0/b5T04fCIwp8hh992+0tPXQm5e19C1YeWEKlL/v/ivqmHG/O5NcwwNolPdeSPDsov2tUXupByoVD/cj0TpjVV8kJGZMCXtsZgGyM/rq5+3J3TUUVLaWFdKIwHI9CjY4QCSQe4Q1JGVlMWP9L0unotB7NmjVICdci9/2znUG9qbkxt+lvz816DS/mmLWWQTdGpuVbyAC4BPQHgJDWOhScVGBQOUO6j6I8syljcRZupLeOHU2eNdgVQ8REF276N/nqT2htHphm9RD5iYTB1dCCZWfGI54f2+1JWGRXUnXS4SPFPqfqIeyZTKPb3ociAvmIT+FWmzoUuOd09kPGqAfg9djQpyuJHuOZYtWco0HRFqNKo5NIT/UEakG6hFAd2uXbz+ivaoGyeV7jQULuPAJkpfftnUmNgjbciYn40FsmBCi225pJ4Q8N547fvJq11pHwDVI5TxKw6s3cvsowF9BIPRdb93Yr5ionztSRiAztjGCH1rGjgjDwmnlryHC/Fl6uYfw7DJEZ3FK9gJGEbZqed/MOIB9QE9uxJhE0VBwdo1Ik8CEv4eh3cEDqN51DAh5hxPLetIsWXghafagj9eB2dhuJvfe0DACq+YQz/3hGfo9sZC+em6CknLSmpFVO5IOkHH/d4gneY2r+PHpCxkr1Ozg8bhHf1vz2Pums5/1W6r5aaUHTykEuyMUe4UqlAytVWlYXvGTq3Mc7OCPb3mbVA5CTYWRg+s46r+xONXZi63+WW9fQKeKzjvE7Y0nRSFTmvRZ2hSD0dTvu5WphcI8ErH2MXNk9/AogLL2obsivSVSurK8r5wK4/FvJD0mJak5tcLgrRaPo/k0Dtc2r+J5wGyLsHhmbO4Wn9JGz61kBjXPDXZcrZwCNmOz1Ts4fAVcJB6tx4vL6hJ44w4quTsfYyStXMz5f7xCmp9Y8C/mnNMGLy0l06n/Z5rv0JQhYnyv0Mrahc8UGT2kw8zb7uEl8Ni4HjmnZMM9F4P8ZwHZOo7TDqCIxQU5kyHQSybyB+pZJEUfXgE3muwgprMX8p7EIIEtaWSLCrc2WlfcY4E+mP4A+w9pck3j5bFlkknQDzvx87W1MRkIg+FgJUoyoLOBgKYceK3vF6oxi0twV62eyP0ALyI42+5MFJ+ZIqIXmq+XEH27CfRP5patnIzYUknc1fjjQjoJRziKUlf5NLNAbxcAYjIQu9fwjBj5jUTtjJ0lj07p1J8DHrBR8YtFR4jt51zKc7iL6cbQjnNeqFQ7AcmmbjefJ3mFFJg9YEHJ87zMD31vTyRjmRmUaC/P2aHyB62xjw8HfZwdCnS7TBWa4sDDlsG2OWJ1wFNGh19CaxndlIc0futidqHFJk2XJFHd04ZmWfnU2fpWawJX4F9eNPQXjUCA2BB9DkC3MwFqcwSX2mNAIlwuB1xJ+2NcAc9zs1y3Ew1PkndyZorUWuOUCVJpuKcCSzN0DKb8cI7lH+60rNFhEGMi4mzfHP8F0ELyomDRLSfWpnGbToHO6Mdvu90cordhgUEiu+Mj9PZjI/CKaYja7zVrsXqPv/sawSa/NgZ7rEihdrBSQunf/JKXQG40toldxgDpqN3MBlXDHGwRgkpyzu5tsN2fcfVImHFaEPEXCXPC124ilCSlS/ZzlgWNR1FqDBIPmpjpBXWw2Yx/NHICs1R/2+bVKo15HvxByoICiZvxE8CXbM2fxWp/FslNH6IYZhxaYnjOuZasFkB6yxr768AT9xOVzqeP3tlqWceBcPbLjvXk5fuyrWLUbmV2odHum7Qlge8hHxNBwAW4hgDGJGVjKWbz15EGbkNvsXBH4DCXa/mu5kSUikM9ss8cFhvkeRelzJLzBrNtmdd30X0gSTRNJpdsfS7UR5PHr6AjEqd+REjCz+mbtvqVG32WROXn0GXdCIywrekIV34Pln7Fio6w4euBUyombSWJ/Sw/22eGZG3a+yExRe0VwWujCalMbJfrs0BSkMNDmf2l2rRBFb5PF6VmYaU59s+T0H5pAPbJtNaMnAJn6PlOjGdv4GSJm2FJjsVTkOhQZ97MhXRmjU2BRNgmZYOQtD7+FmKWM4RSFcVb7ps1sLrl9KaMlkrh7QuAJt0L4lTthBXAz7S6TW9as/0O16gMF/3p+u7LvtbroTxQPYoI7DCIe3EOPu/kmQx4jsH2V3TvKXLujCug7ZyoNznpCKJAaecAqkYvk7KwOn+5RvtqPxpQ9iJqB5ESGo65r0kjMY7PcW8sLhBi4Y8NjD+jUjgX55BDJPOymj8Q6bUD0Dwn1KA78skeVuoOxrdNBPXDO2wGBKmEaGhp1uzNOClOHz3ZgTeMgpDwgj2JGo6IHjSsuz5ivPnULrOWPy0YLgr4cWlR3465skxA3bClVwojG+eCkB2S9NZ4qUAQt/SycLdF0PwJosiZx7bOPoHeiVkL+Sts0lvOxpM1VoU9JENNj5H8FdYgV+JqlqsK9tLzHWfs6ERDd2E85NqzA4NpAR7FOvvoUEzaKTY3rzQKnba+O1iAVo0y8qLJmu+wmTnb4yEn46hU3zMZuNOGTKCvEOt9PdN/lVp1qS6GRi6OBR6VdqF0sQ7NB4M92FjxuHJXnagzRP2kCnn7mWDJqW5ysX767IP3KcIgOzg6vUOGyeB5acTvw7cN7fhQpbJaqnk7Vq/IsTaKKd5GEv+vhYwGbv6UynRQLhnNg5lXg1TFFm0quK2TnJUwNFgLPTK7aAzxydiOkO9kVOQeZ4P77Atvv2v+Af1ex25hDJ/lgxkrIvLKCimIXbnwQZYl9ocbrkEIQCx1OoZcbxhLjOsuiVuNCeCy3wDG0B2NvQ6vu+corXEK3iJwbuJC54KDstbMKfLPwyQe9dyFrACDthmDBu5c4ZMEgvVJlXdwDb13/bEkR+D7A0sy4Y/lLE5y/WUpkBHX+SWb0PKZcu4uCqfezam+FdWBVGltZ5E3oONSDfcDEBu4yICbny4pw0cPdoyQZQl4GD9xJHOPsALGGoPrEbEZFFCi8qHF3l+G4ESup1ukel3HyHJjgA5mV+2dXlKAmCWwcSZ0xQWPa4avM95m+yFYLnD89kPioIEV9BhC1GV4nnx5YPBEH9Ro0EondEki9itX8/h6y6Ijg4kl5D75ZAgmdT0hOX4HPclvGV9l0xk29r6q7tB5moGfyUwB1NFJoYm09aGk9GSBd+3J+EpLyr9Lq/wCl5D6uahnYTHzTZLBkj3FVC9FWtL9Z5SDcDngmxlvwg0LR056rR5fAKZEweoRg0/R6aiYSwqniD16K6L/5vcjdimsf8nN3iOtgPVu+k16nZZ5YfRyquBR7GGDS78mbD8do31oQGgVQdhc/MVWKeAK4jX3t3uPMx0SoYiXYioBCJE1Xb6yCOU7wp6wwYVHthX49MmHll5/Zf44SmTCzdl3lmqXRlf2HGFAeCeg2MrPa9UxKDf1COwgCURm1O9CBsDjWbNEw3DxqvgTbgAuSBCHkrC8GcafFiiCTZzcaOhbAU/k18RtBNg5RD1NHco4oj0nQ57zPrSgz1Aus478V91coFDZmye9mXsVBMLXeC+/3vdtWUkvJHd0zTzeDYCRRdwkRU0ZV/uGuNuMxNCUlCa6w81xb9tMIRE8iYzig2JUiHbVrTvl/y6CcLEJjlkn7XXoqIzCL4w6LKwOArMxZb+kuy+fZXG8fvJmqdqfx6dxQkPfWCAf0Cy3FlZ3ds2Rd7zhdIoyghWHTf/2bBav9UQQy4HBCqnzJim2C0ASUtsc2qnAcghfZH/WqSDG9LApduRxzGKzUs2dIEfaA7fiC52HxEACWUdJC2EX+gpp5fcZuSYsIbDW+Zxq4TnJJJE+rP/wWS3zZKKNoZottNfh4UlbUEYQwvpUJWan8XZZYjGz05eAR63XRIkA8aA9hcClSA70gJEU+QtG8IyoNXPrPRRMr2EdsElU/oGlpZZA+8rH09gg/x/u2P54c3meKmUJLMUCnXB7RouwnZWMzcZtwMyvlyo/d0yQiZaXteKr4cZ068BKkkbis4nClAz6YPGHVCN/Ub1QmS7N3tdsr8FpRHY8QHoYIPyaGf6LirD7FBJ9QYa7lFgwrbGBOFWkepRwMTNuAN5Nle5WXLEZhfW0qZCJCvBkbidHsf932ez9phXDCjn5n3ZVulojOcGEQpzcCeirkyuPOkG5v/WBf+Xp7Dv+1JPI+jXWYS9MQrE2qLHYe8UFzOi16pcmPCxdz2pfnHrJAjTXQdBd3Nt0xfdo72MQvQVDORvplpfce4hr8p5om2vAFlHG2mxTdnVR6GE7N5y9ht3UKT/JdB5U1tPqUmloNmhOWc/k2AxC2FY1LfcVwmCmgs5wSRYAQSQVr1oZdDQMjfXTo5Fh44MGD7TXmoQnJxL7bhjeN4+fp8pVE9cTt4KAfkheBn/uWUdd8LK/1YafUCaG6ZjEo7N3oVxmGqgjBBLJdw/DKDsglBR3DV3nTtfBwv/y0dDHzjpdmwMjB9i1h67v49yTsaepoQGU7EnFtidp8aRBxaBPVBEFmAl3xaToUC9r8xJ5sgAIulZjyJJz/97ABMX6zJqwgNnuWSgwg9Nl7eYnvo8jQAOup4BnOB1ojEoowGXKTchBKFSaYi98SiSlW9inTI2Xx7+KlL9U5MHEQtv+JVX0dJBVkwISMZqB3q89j8lzgXUOJ9CUjdAYIEAN9QtgkB0jmQ+I5c/YlgtkbepX3VBGgQyGuwpmMKrQXW525rhkEIH5/zQhPMNjfOvudYM5ecwTWiZqrgGetmYzZoej0/QXPuohs9x6fZQlRag84EG4R4F8FYcS93v1aNtMJGnnGV8aJCRN1Ij6F8nBAQJPc6vff9COfPQ2/Iq3PhwJHY6BULvy5ET2+edwUax/y3gKrZpdhNPrtl8Y2dEbre1qadParaHZw9Vl/REsHixoL6hR+wPEQeaki0HxRB8UONZjZ8m7ULNc0lL9rRVm9L/BrL4G6zd+nDDFp1HUZPMxHdeMA2amDhF6rh8hNZ8s0qh+GQOp6GcaK/ffm88TPvLA3mVb5j/ovegWSBUzWk031pbH9PTK8lordNiNLr3in6Q7WgUXPKV0/TNnyVrSUZkmRaFY57ItaWowlYiahGPgKnSxS2gG9uv3pkjxj+b9nv2e4qMS89KMyam42F757OoX3qUg9UVUAP2d/a5KgD0vLxTX2p7Up4ub298glKhSwSlJw37o2kGOoAh58d6bGPk1+LcQ7u47MR7JFDIIoQeN/OGm/vwzin8ExUXXXy7zRdrEOETTsGlZSSu3Lz9zF2kqSNa9pA7FmaB86qOzxK6o/lwZQ/xAW8FrhkQD0z1cFRWS1fDpYrKHz66CbSwI5JzcHXoUYhWD+iVzJAUbJG+tfPE9stdWNB8mLBKSfpYPIM1rex8o4m+44M5zM6kJxgvLbbHMi3aSQcXRluFD8KZ7SJKjSwvnmrA2C8iB3DiLOfARR0Q6BU1RTCObzIxs8/+k8xklm/nBEWoxFloB/NAan3MUZA02kkn8/bt988Zj9Svw8Vxl4g4yxeJIL+Gt/YU1vNA2B3HEdXAxDg8tFpKpUhx3UWCgd3T7N1nug0gJB2OevdZhWcnVz0Fg1a7sdVK3+Ja0CFNrijl8pqbhjUbsJNrbEO34Dv3g+rl9CCv+74VmuIF7vHxPTuzYKmabvaRiAGcMqLTCUP2Bv71qnggJJaYkjNRXNAVys7xFHhcwV/oi9/2GFmqXumbekg9l8jPm9/YNORcow5gyrBnbMj+/sSwJ92bqaFPL0DlEGN/DNNN2Suq+o6LW7r5nmqHmMBDhJ42W4gmfgMxr861PaK2zXxbTPoCbP0Av9Dpn40MVlAIr3Wn6DQQlnXs+SFkwwNagUbvf9Zf5KUh3/7vo7JlWoZseOEO3baR/DAYE/hEoSvmVfe+SFTQpRI/I9l4RPRO+tDJ/3OCacmoa4To32lyEmSwpCHuC8tegVSaYD1un8HJN0g8ZiNNpTMq/domFa0UpKwh+/oTjaozRL02z2wouXErZLKOfyyB75oRg0h1O6zKQwcex5DvopqxfQkYPiIt3TC0895CN5Uel2dyO9Q+n+I1/QoTQwFm88jJWL2ualcLmecVtsq5QotNKQrl+xq4wKj397aDwx3FCOnPo5zccNRQbGrR0FXPaGrv5m4oNWbU7URMG4gx34HtzBSAhwwXJLtL1bpQClnU+MTU8o2BQcRfgwtNjUsYww/IkKT/Q8K4E1+IiynHyHP339gny/nHjiTvEUu88maS8xlX46oAyELIMqPL/2Cos0Z3AJfEEMap/bLDcQevl7kmgNRdZMXj8N+awUgbqQJaTXvXFiN3cAz12UNUal5r4omPvI8K/tfQMgjv0Kc7vs8KyDDzbDHU9S6TNYDK0+2ERLI7nbJUpjsYvhfGZdhFYzpSpb0l2twKWzMf5DtQvzGq6TBt7tbHy/7nnypDiGFZBoaLfrCi5Nj0zOa4OIkHPM3HcVvsONa/ZN40ObGvS+GMy1MxXidCmgr3257IazVA6NE6xmGwmI52Jk8A52JVXLoiAJzuqjfyxR/9zNnYMpZ+rgn8a4IcnTwxzOUGrebuyCk2baq3VRWJ94VCgqXiRIOEJfZbgE18GRNbb3JkkBV4wdz83+VaKidKKwZSoRqSyeKVV8UdLLzLoSzgXmXZ3nd4lL60L9j+JVGmDg3biFo66yKA/52EJ2ITSJOx2se9V/hsn6JFVRDIyAQVIAJWqpJMZ3qJopyo1gFN8uptdRmjGLyY4ig0rGHvV7WcGdCtVpo2PEcC1RUT8fF6GutxkjFmH0hmdXcvKg7kaecrEOJ6pTqEvvjFJbG8HZbXXfPU8HQWs899iy1W4beJMUC+5+nu2U87eZ3uo+mr0ePDdd+UZqYNclDkO7LWesM8xxGNLk3dfYUWk2lhqwsLwQJGqN/17hmKXaOkOvUk4nhoQuuhoVFaReOkpJQguPZ5RPsAGO6EyUIaKHEA12lEep9SG1ZZJbYCvycCgTWMO+00iGDjnA6xnEf06DPdcF8qwbsJ3jJmAMn142LHXPrUGCNAnzT+8w3MaK/hPBleb1FMM3wNoNiQyh/KgbpxjjYtHg00AHBPqH2qRGukYDKFhklIjoj3DIjbXN1lkV+Hc3TMKma84C+CuuVh4TfMB9YEyMAceUTvzU9IJbWQu5Cj9pvYq1bdyXB4rIfTPTJBjSqRfIGqH60I+PhHrtVFyX2VyTa3X0KAgD2OPFHrrXkZrezzoU7d2+22CjfM5+ePT1MR3omeKJOa6/0+NXh2h3YafPrmLhhR4BId6gCOxvsGUXYVFUzCsZmuLYAGP0tez9tMq5YFmr03HJBOP+ecNIQ+HhpTxx6WuX+Orl/QQ1aZbMJDehfB6E0dRhI9ykUyNrnn477+8ihNTSt+FjAzrO5hCpnM7YGkjEFyDsX60wS7amZSx9iVRqRHfRqBAbGDwRaYfKQXihGZ1LI6VH/k8XwQoQOu+Dm6wRxBBRJwAacZTsOB8b8YZOMiJI8VKSH0C2SKOkEF+BqGAfwofZi7IJxWrJdLW5R2ofUZpXEbQdr4NW84IxADBka8vgCBMrn4B61sHgw1UFJSybxXbQ2FiLaYfJdRWj3rwMT24y/ml8oK7liZlYeWkgMz3zEgbx+ggOF8HRqQByyf75GGIHyIs0CbyCxKpkDBVV8iVsZWGEoDe8udBgAmRTJV4FKhqmqF2BMTgx2Hvkzbb05/RiNLbZLT+O8G+XDZ058MsF8KChGFWTYF6tdnXKQglhiZgUnIOVXi2LQ09ARjnViV5NBAdhGo7q8aD+gnc9NDMCVQA83vCBpNlftqPEv9vkrvOdSFOjKnzVTAgJIvY5KhfuKug3c00kPHJHSunxL93Mx466I0nRu7zvK8uo/D5DF15ZM/0iEPIwBr6gerOLeFc09y+xT9IpIqR/97DnRWeK29LhJr8C5EDaiUz2zNTp2ApkcGiU0s8a6lMWu9G5L+VXe+RNyBl8g+OBOASJ91GcS3X3DmRhctAsGwdAGtXXr1TLBfKvYmazpM9kMnNwWr2aF3mt3zRGnr1fjFdzr1zd9UcRBaVdcbknDDJdnBMpkeYrBOxJQy8ZAZ8EMrC8xeoCHrzqxSwkSDpg/q5mrAw3l08wWZo46swTupNiIReMGR1yBsP0YBXFmD5CmvQ+F1RwoeY+FRmS8RJav9pKmeIhf7ztnVO0JrxWja0BsMJbj+GSHo4/M0FWA9Bxk/USk8czoPhPwKuyq76PZT/3PB8C+dVeYj042LLc/IZ63RPjH0u3T7G6sgF9vCytPo36murl+kKYF6JyYTred6KhQs6IA5vCu3U6rGhadmubtMksGAEK04PcANk6vvR0rKYN7FhSQskDTman+6T+Fi71gorapNkbrJroRBqAtQ5QjxfGfcaEJk0Lg3RBREuGEDQP6nx4zaZE5cUUxBFxi3BoEngBRvSa3W4W3W5pMsVIZ3TusV9irIycEkLqqcC3hwIqXtVNLRoOOjmYBLTpcprxBVcwdsuxqgA1UK0akUDoDnpPvsbv+vbKA5qdmvPCfJSgnGhE9ua2l8onxnnuEeGnNx2iYY12AE8g5kB2HA0UFU8n9o291HVgiLodsLxcGpUU83NObWoR7uiQefXkgHZSywEPi9Uu7d/H4IUzQX7y1nzSkG5Ok2e9T4H3kFQ36unyMO4V+d+7rBkqfS2B+5+dQXxL2gPopJBvtl75cHcl4v4OJNfE+2j/vUt77udVFiBsyywchaHdrwNcv2RdAU7HWWa0yPvj38dAg5f11j/K+jCruZ/ujOizwhOqeI/zLM2bxpS3pSb4PHrJ96Ux0pINAVHE7ikqecT6NL1jtJAsxU1bxGrZg051j8/WLCoCohZP/UgfdE/10lp7srW0pAytyPessViTthQSTYEHOlMHzjszxAcnONLp1LDWDhBBh3yV/K11ORPI/5KcA0aX7qJ8+ROzSnaI7TH5UVs0FoQxgasoxJTQnAwHYUnuEAZO9zvFkaYghystFxBFxglTGmQp4DVLJ7/zPYT4PHGpmiq0YiPcGswsK/y370VkG3LYW7dmdQdhEtcQaX6Tf8RrfWtN60BNKg6LliJAZNuTbYMCM/XMeimcQ18Y5FBK/l5ZD4HRlJI7MDWKwZATDX8Df2Lp23Ij110G4/uu2PtRdswCLnEtdNUZKA+1J6hXItZpf2p2dK3WU/XiDyGDOqvUUbOL7HmJiaxUzE3tSwx0bBOmat8XCZl+GOsf5BV4oHuYubLKpTrulrm4DU8Mcdh2U8fXBpPDFRDVAfFybu22Vs0dQ3HA9uuAdcjC80tfUJb6ijVS2PV4MPtizL3qIOld4W8N0iMRBacTp2ZREx+xtNk9f9oWWvfj+aXQ/26IvU5O9/Heu5My+rfFNSJmcO6rC4m1DUIkCWdFityFoZPcCDMQxjsolv0329ovs9dTpkh/8rQz6UkYqPyhEin7qEWN7E8/CeoVtlXWrCWTLWQZdcFJ4YGJnnwkiNf/sgawe1Pq+Bg+a3CuUxdIuhnTaVOP9+QvSSV8lkoax3u1az+3CLZpvXKxIdAAp41zM7K3jIS9cVkrprc8VrCMMjw4RJYKvQI/g99gj3yqZQf1WsyK3vddocEO0P9JB9zuOkIgoJfDagD3bFonEGSFqF8NIz1HiJ6vP71i3KthQlMGna8fmPUa0Ps2T6fWylRNTe5vuseRvXgi/ZbkQ+I7x0d4lgwSQ5kDmRaykWaTv+WbVUbvK1ucfLoVqsUw0+aa2B1Z/prdKyVchJ/3nUC+i9mR7P8D1YzjHtAzCUKGS/31+KwHhnJVSiXZj+PG7dqyN4nWIw2/R7p7p0ETgg9LBllG3EMejGbx7Q35ZPgXeVuNKIuVLzBJuFPCEXaZmZdB8a0AEbGXMYPHZuROrtSa4TqetYmCR0tyh13ZO5bnpqnjsdCnNEPsW8fHbaQKDU8eW/afAKXSVXv4PIQR+fhMfZiJSBLR/LrAezilmN+NE+ZjnBspA86mF+hCnR/VcS+jEMSSyA6ndwfs027eq1UXPbqJfBrXUWMSO8fxR5QghZT/IB6ne5Y2l18IQiPubII3IStP4n41ZzSrHe3kEmUD80/dBRfINOPz513XjagVmH1AC/Z81DEJanYkd3oVxRzQu8UmCP0HSOMm5sDDlq2WBnCmuedhM2i1t5Gj8WGAgSDv0L0xEOsmB2gTJ5N8Aou23Zcx3ZoM1T84IK8WCSqTxrqKIT9TI5VSS5DQdXD/e2n8TYTj9IQ8kbiWCoEe/c2GGMLfN879Ky1xzeFKVRCojC3mVfl8xRCM2BJlxeAaqtkZ3A/czPsni8s2tYM5rqbF9Wwp3yoppbBopePYmBvyFfbF7mGPB5a1QxntCq34NHDqPATvFnz2wLogQpO/5pM38ahXrzCywh1ldFK2Wgdv/kYNW2kKw9u6PHtUuAYiby9Z3+dqWUv7Rp9wieLQH/ipmsDklTzYgW4X1mKyjt+IQvvCvl17q78/i2DfwpL789kpRA9g7xOidbOzaT8MIFcq1xlarmdI+BBsATFvNizBP4sUYJ9oYC5zL0wIULUg21X5+9cbs2XvC672UDjch0aG2HcyE5TdXkPMse14vpt/JgGdyw13BcTxtL3M99N1m0zX87XckyC8h50iWoKXMxXGiIWD0ce844NPeKZQEGozfvyoRtlycoaJYFKlrYUjkck4ZzvkotEXod8W6VkzNxYZW+/IFhCa89HYHopojFj5UQ/Z/OGtyG9xl6y/O9ZA5sQfMSrZ3KnO808Z6EOTONzvT6Nrc3tOYe43SB9vV6ysh8NWavcW5exhws57l/rIERp9G0BjbEmfqqn9KMyNMOwmTQBydrOwVNB+cUh6VOd7rLhBRuFvQ7pdwwFghDFFxJOTG9uLnPiOYe7VTxlEXabM5KuIilurZkPU3bKkEerRaN4ZtuBbTrcnICqPrNU7FTGytB99HGSHp7rKDjWfnqdGKudHKVTYlTZZ06wyoTnx7leIoaOMUgEzk6s4cZwIss4deH/R1kWgDL7nJDiW+DWmPUA6n0/QVUPwWEiTXUiMgmdBPd3ad1ijpVvLV9e+u4qs4L1fgXhuNbbhwMS8Msw3yaUkN4XxYVsatoKz90zD93Hkgb+EWuWhT8HHR3hVjYtQuUhO2bIp8J39S84FrEgVxiF4emk03kBUxsjHOm0FtT3xAQ1YE2Yg6cM7Mn/kTNTAbPKPLUmC6fOHiS2lQlp1TUSBcJoRF7AXfufLSN5Im5tCkwdP+wQ864Om8D8YcGOV1UhqBMhCr8BQfa7X8NXSqpu7/k5kZFwak8k0BFi0h8JpCndsNe8IjIXWLvvy9LNI0pxbf83XduNiwioQmbv6ghMn6F3gCqtwH9Ny33cBGdHjllFhhnW+7NiOFl38oCS4z8nhfD2du/LBwgt1llgMtEupBTsDpp819GK8z7VwMsj87U4F0tWYRymOHPs6mScnGiadkX7L5+PwS6LWOzIx1Y3o6xdtTNt8PAridxQFmLYWTwCzYREfRPlY4BfC06JkzdCMK2XC9YVuXsGclFHcxKN+5mkS0O6/iam+fvCdLXTV6c/Pkk6UXFO7EIQlszI+V0sQ0szTTUW/sKq7XPwzbGXkDt9XPohtAueLi2kHLdpIwqzPSujN8f98dpHVOn5xEmPZdaftdflw4cvQ5007bGE3VjjGHE4QCtmyg7SF5bmyIwO93OcxkvRqDo10ni2rkwwFj56WIxrqkKSjA1SciIeAT2P/pdCx5pGUb7Gx7WHnx5EBdM9hrrX2Iga3NHzNzRx832zFhpJ2nJpqMsFKMsO8Fo258n6P5T0dLcCv3wYQoJiBhu0uoirR+x5zq/AbAqwzUjioQnC4HmOXBXXBtQ9R8njo8aBBKuWtqnSetk3n0+WyyEEkSEju91Q+RIxndHiTzpU5pNIUBphZkA61oZuYwVwNLW0bU5nDkpQtJyTZiG+5WnRswEZmqm+4dAppHtpyuet92c7YL6fDk5zxFv3rUO0CBlO5GK0ZEcfgVe0CVmGZ9nUxUqlz+sdMje35d7Vl34aL6NpK8n0NP3UKqbUSYb2bp6iDWS8BS1l60YwWVtxMZkpRzB14ugIL7Vysxj33giDwRtphm2G5PQA8q+eaZzfvZ/lyVlbSdUX60lhdhTP9jMloq8Tk/KoOqiJYrzdqWdRvqbZV3BKD9LNumOcfaA2JWqDeZWOrJb6qa7aEX5Xq9gEIjKSCCecaFd0QVEJAXW2BRMADr6A2R1m4Ng97byvOHolfPfV9vi5jtdlBoZb9yIrssS1SU+5OYXCU3ItWWM5lTUA3L8Mg0C28ubof8pzHpwTZhitiRMPTNYTiHR4o75f09c9MygcPY1TEMc+ubwzX20VARlcebL61R0EWZxmjm17fTj2GnrsDUIMFH06ds3Pk3rgXDPYXYEH254bcDrfPImG9llRVFyXuq078PSEOmy2VnctgvOGi0jy4XteZ/01NYfm1oKWP80dn1GFrN1WbrF3WbPyjj9YbskCXp7lN13hXz8eyFdR/kH9wmkNHpzXZfjU29ezjNRp677Ssl7/wsmeB+3YkZlFlsmeGudhEImuYEgzrxCv48F+YGKNfYDGl+NNm25rKQRkN5FT+729JdUIjPkFB7U5PJNPWJWs+ihvc+L9twZuoaXsbTb5RCHPeXDXDp0+BHWiJEgVmTHY4VCIkB0ow/aTNnDh1F4OiEnOorCeZc77hUNrhqBJ6GA+j6+HTdyvf6DE7L/UmQ79I12lrj8zGDKee9dtFmqU2PZKIBYIgYSDOt2SdSjxwxWh+iBpWob9cn/cDfsBC8Hv9E7P/lJy3Wi1bWeQXBIniv2nM4ktAiOH5l5/k4qmD124fIyDQOqm93DiX6CTNDeJI2qbo478hqAWchjTv9Cf1GRBKAcYW5TYloSxiRhl13WEZN2q702ktQFUP0VIaPKR1/vwfvpEriWnajfnATSjz2UNr1SYFIJveevM3FeMVSknTs+EUmWu1MrizjjTSb1uef9VHmPWsrIr0HoXSlNU9mokJvhKUWmsrRBwLpg1SmuGiXwPfC1RQN+ZjNxBzbvjTLTZ6wCSVuHW6H4D1gU7j2ZU32yDBE+Hwa+NeDAApTIdJKRsRJwv5R4Oyb0RZMqToxeGHupTejUzdnoB8JXaluY5/Kg/Brh1Plv/11YDeawOcoG8MxwKYURCbZLFtW4aqxTYVAFwOiQGTxZfd6HNxSxFb01L3gV8QbkbsdfxxL11J+gjZcCyxcsWliNMftXQNwULkiXEYKF5vWWF7wTrMgp3Anje9zCTaFvDOnv+daBcmbO+6hvRNSDf/xkJ/Lupo3mwJz9P4o/58aFnduZXk6VJygatKafj2J9IKe9st+0RkxNwxjjU/glOj1K6Uppf8BNzxKQY3zJDZ2jaY7mqTNrmEKtWwiD94W1i4VfZd4056KFp4fYjKcAn4CbrC3qiJEbuOaC/OTPTA4Np2eB7bCkXFOAZ43lqlyicdZUZqMGx/CrR8j6rGfJyMGoPZ76Zx0H1Q3A4+YnYxw0pTilH5t+wuuZux1pgIHeYF8gRQf8DlKm4nqTt60LQ8nbWRyiiQgBMvD/dbNtHGd6svtcpfGWFHTnkRFU9KIevARGSM2WKlvJXylH0GeCA6P9zy7ijR0u17IFUNp7UoW18yonLyH0kM6DxhGDyeW6GDjA4mjeR0OSze2x1bRGDaOKgVUyaws3lkJhONEGmzOObEYsK6e5DvlsUeJ1L7Q3MmSrKgn3nZeR3EFy4gT6v2Tts0VBbu+lgYzLYF4hVovMDiS1hTMZcWgjuGSODTbQJtFvWYg+qsctBFVTYhwC+eTjK/vjv35Di7SbeP42mq9hKOCnk2/AChBhoFWjpDdid54njeOlI2WIMfTspxBU4il0S+tOTeosMgdS8ple3ZtlJnOHtW6uf+1Yg9cyy97JmWR9hEtMjwyNbA1FpNvbAWCqDgLMy+K/vo623MyaVetRYkd3iCtM0Czm7q11AnO8Wgg81glxpxyKNxMwZjLUyrYBiq+ZptIlJTfXhXJwLGaf2kw71CCfKX+J5QpFcaiSBh58zkt7VABW8Rp8KK8A6ZoB4EKTlC/8DzJubOmqDNVgXcPjm6yFc2jxSFOvYTWbZ1Q1+rrHl0Umpkgw9UQOk4GHm8l2KiWwXUl1ALKpHHhjDNS7vykq/CzNUiNo9ruxnJDUyP6bO+30E1lvKJ2/v+SqjbGeziiBEmXQhSaXz0ho1juyclcoikP//JI2/GYNo9IFUL0RiYUYmax6RsO8IW6X+jJSmz8P6CKDgQl92OjOK/0KJirsZ7JaxB8VlouW2bHUxb3Q/npECN858ab2rlTGFB6KKCU/XYq3uh0d+gr7r6vkzxA/AiL5s1dOFv4J5z8YgqnPdeRv0vDSJE3lT5/kKS8YOq/aZ0R0AXIXtUxNCgUdSgBwz8gzsyqMP+cIX43leJMttequKRxFMWlImC22/hbZ/3CKsiYBYCCGdu9Njro4dgLfIWCh8dLuWTL86pztjkFiy2dErUoZpJySeS+RVOL6GnErvEGJT9CkGCBAwVSX71HM4DoKFoxsNrx+gHzAHCuNAYiPu+mF51yrV+050UHHNJRO6NmW4y3ZXk5jHudqGOWDmySFoSaXfcf9A8dM20dIM4Hyl7yVvZ/5EZeGD8YHOhFbcxUyTtVKfmf4mWpm1gtcZClGTBAZRLiKcevx9eVEyYHK1hixbVnp6FvzZTO0rATqui+pn5uCi2uW5kjlMsiqfxYLiNSO5VCxS9oQLZsEWqCnMSmUidaWMNVUsrG0BiJuWh/p7dwqK6MGq4N04Y0YlLC/9z+lm8t3EPDu6U+PEkldoRtSpxYlDaAep+VNJcbuEO6jfYmxqYX4lIT/MRhke+1baFQWIPDV+T0UC5rZwt7NAM573E7CyM7H5d+Bj3kFXkODNu9J1VExgWOstK1zWtlLk690VrXSqp8fIpRzC/fGNQeR9PKMTv1wQ5o2WUv2EpfHnKUlUFhmERyotTorWtxnwuR0/Px0pV2xb0w7CvM+gjQTf4AW5IszvlAGkjI6q5wnsMpJDPdlyTePt9+gnjEW/j8lIAQmpP5HN8xBfpzuXYGUScb/8QFUHB0kK9SIhMuba1eZV3qdP+Ip6CK2yjTxxBt4PQ8QiZH5iEkDjf5arnKuJpAUnWRsFkTQX2k+0NNskZxEjuxMakHoTtZf2PqXEbM+z6NRrqFaRPx6psaE9YvNJUG08bL7xu6JTSgXf5i1lnD1MGQ3SOZeaIJ6a5vpYvi+Zzd8jJrAL83vXztw6cZJ3Hai1DspxagqMZCjfK3snAjLapHpajK5eujPiZf6hpWikBkc+UFyuH4zDg4jMie/IRXmpz5F6TSXdq8mR7sUTUjkpCct7VPln2P1B4u1s3isXbIOcv7msVprDGAE08HfxrKYLXyUFbx5u/g2pusd2+0GVyfLFLIC7L6vnmO4fSnLh+PmBkw4K5+97yF+5XgLIsKpGyUgPaGjCDeiK/mr+OFrtjDuHH4LlcX7z/1vetnJnd8da3wYzfSZ0c3yppzuxEbL+l2LLIdfHbi02RhD7GIC5Df6qEaT8U9iFlKge8IsLGNO4hxLfC8fiKEcRZrHq6jjwFLj4NnTcmyCjyVjM5C4+o2mF+l3/ydTSA5rfSbof0/K8wA3QU+dh4XYcVbAlmFkJGYkTjeMeulzNi2erWTdez7kuuI0fH5axmQGDZxLpQ6b8Wc3vmnC0yYdGuDmrQ5zku8cJAbcm85zhtAm5eYlD/qqVHcq3RQnhgb6S6ZGSkCmXwO/r+XgY7V/B2jw6EKF4iwzK5qg6mzxTj9btqmuyHnLaz3LoyO3V7Kv6HTy7nhUARXgcn+J+ZxzQdXhzAKyynP2ZY0YX45+gJ5SVgW6E++AhmcaSA/8pByS68Zwk46ICUd3V1XmV/nfsoVQ0QJHOJFqbbSEb7kQbftCtshfhb5jzpuAGKNePo1n6+xVU3tt9Prf6r1d28wAIcs1hie3qmbu0OeNrmNhCJnLxP0cPlUyTYN9WxLXRj25BGAbl6UZs583rZiZ6N7IqMXWNotKw0CnzWME8vcy8YZ39RJmvJ5PcFVXBP5prbFHdykVFMuWcs/uba0KUV2nB6jW9pJq8ChXnjPnntuRmeLGdq1tgcj40arXiWEtVSgIopl73nEwtqlmMzYEytl4aT+3/9/zjXqC1oc83BORVutZtgYnai35joHsV/tzxNSmS0/3X+ixZs80rDWVQNdE5kqO3v6QlhVrjzCpq7wDxj37DODhtW9wozmPEDdWNvobFOPqtONXPOuJTunDzeqW70kjCpwT3Fh8yItT8cni2fL8OnEVJ9Va1ws9E322W2x3oCd2RH7hwxpgwRNJZAKhYq0STa85mSyzmGWkVgZOtuYI00XolPzN+wU3Y68kcr1XrNeBoFF3QH8zJA8tM1TSjszkNSLpV84uKKKjGblukvAeDDXc+QPJCqfR9lGaW+W3emxtpRS01lxyOCUnNiI0hZ6grbOWP1SKdFfaRWEuweoCCoBnxArTgUOIM4v5UoTab8ZnM4Pz37d92jymzTN7aAgcMCCRURh9f3wmQXE/6gw8R7N4e/ro24IGCG9LUlUPjoCs4X2QIJsWIFx9P6eaHoJ0jBMEzd9ssI/z3ZF8lf4iBb/AkJz+DynFd/TqZHixZqwz7eQ1qFvp493VxcuaEi5Dl3Sm6jPrIsM86aCh8iZvie6nBGZeMZLMGaOL2Ym+6havIGTkJ3B4nks8HxuSFthlXBeDiJqzlhCsniidQuUskR0pYPDBCy1Qt3zh1btE6Ola28or04rX73vVlV4tglgv/JbMGGvfQdswfq+aX4wAq5d87OAEQXnBZ0w78V/lxr2ZHMyQfoT4H3AiF5HtLMt4ixK0nsiC+d7ujRGhm1YSPrc69iCi4XJ1C4+OCiFODn6pBXOMeE92DMIykkoeFRZccO3XlSGAESCf9t8ZPklwK186YUP9HigNDuOHAoYa+l0OHg1fEHqSGyaVYCT6r5y0/gwwwIB6C7ZVO1h1UnW/uzsQv97uTh0r0f557XFMhV1Ato1c+GDFBrS/8SBmW+XuvwsZUxkA1jqXbuN/aFM9MlygLV1bdJZPWHZJi0yT4f8HuiDbO6iorjdfKVqBAke7RIdEn0ggpkkn33gKkg2Qat9hMy3F1w4wbTbaLuPeG80TGrZ3ZziCBQGJt8GGiJ8DUSSgkgsEQAHErj6G/pAw3ColpcQXD/FaEaeeQoqC1Ut5ekT4kFu3zycqYrMv/iX4kLjtk0Igk/SSTaMLQQSG0EHQbomETyC1QKkPPx+a1w3thjrk25b92qWQZQ9stJbd5TXrxuiHmX9dv8VJhBz92O+ohmxjwz5Za7fzFnbYCHyVm1ssl0MQUN01NJh+wTQYd0NWiIr785Xr84VT9pmbAhkV474NGC0ZJJ0Li+Py5cKssZfitk2Hxzp62BvWdSExBcRa6nmZhLtesGH5qNm/plUHkurDEY8iQroXEyFJhHvQ7K/vZXcz0CAupdEsagsIaFrkBF4k1pGy0PvDkE1vT9swhFjz9pIYGo5LUuU1QYkWP2Q/e0vjA2wjC+qA+K7zuMoFSQwNHS/h23TbWqwA0DYaVoHUr4GIIjbaub0x0wBYZf8MzBlIWE53sbfph881kQlp2lbqhEkjdVsN69RqMcXmhOUMxzRin86yy1Jev7H+n2gFCLggAANNt2L9vGzbZt27Zt27Zt27bt+hmziFnIwSLqF5bXojb11rKACPJ14ZTaXwdKAayZUilkSRWIgpqDTmmIZKmcOzXVOgH9ZNktKIYo1pSWdrn35XKqqbStIL7mHgpQ0j6x5seXRG0fiUw/8k8UIXegpROrrPcKfo97yWD7/ujRbJkmHBJhm5UesqGg6/oL/0f3ornIPH2KCRRAD2zbpESoO0RudvrfDbcizxuPBnzWe6+yqrfVn/t0juJNiZwCU5U7hPLf2ejKI55ieMqZ81OeyPEa9l4SAvifjvMdoRC/MjztIMWdsnymCS45gXdYvLcYP6ry1e51m0MVkkCIz8qCzSQO0906IAZfR6aFkVdf0AqJwzbWPYgTDM6kmKhAOHvjP1UMDaZVV4vUrqCWGM2W7hvikrBAX1Yab5SjFjjIXmpPUpgEE7ipD9+Dhdv7S30rI9AO9s3eEh2iZFqtS4Md4D1Z+RGrjpDzNfk60D1HokM5P2padbdWB/oJ7hAdSg8dz4TMAkiVVsSplk2KnMeUARimXPApJdjCtGU2MDvxT0oWSSR4gvF/VH4M6R30NXqiNZbYkSKtkcBLbN9AN2AR3aiQoZ1uZLIZmzAVL4HmES8lhmCy088eEqCcGIn2Kor87uUnahI/YkEbsm4WGYl73+1DER9pIIp1HM3Ws9uoZlxWeMtq2mx/RuMuWU4Roq/Lv7R/oyuDOo3k400mvyH3L2FDCSqSF6bPtMS4/HzTLUeqhNBeJM9LzAEk0vysuZsTjMWLLPBbZ4V2OSB0NLACpbEkPOGPyznbTDOUVKXd6ns7IdAdGxaKRxw0VH7LjYzNSEHh1h8ZcCIogdp7akzh4Q1ezTj5MWnzHqh5AVfjnrEM57DckuwyBS9kxBJDnSzXxJm2WEHFT5dV3D4zpMkTZqAqiQIetGARH0tYft4/wlB2+ZxOzWRPfDrUd2glXGfM2jC2DhhJ87VIeTUnRa4brwsHOMd+Z8PXNcNCybPuNUcjGmzdzU5U/VjhruPMsT0WiGBG/cPHSjLir3mxJf/kd4UkMj+w8DiJsheDMDBEs8sw7oPyipGcoY7S8b0slrjTNvusaJ1iQ2tgmbtT1U6J0f8pi2w3dSPChltpYzguQlk0A4Hc7DAjQGoz+EEVFxQY0jPGnCGvdUSozX2Ub/6g2t1HOoLJRXELG/0DLTIHvan3QhiB4+/S1pR2hwwhJYqtYH0eU5oxL1xMbB29L/V5anyLot6vmDW8ux9z3H3U/qS61/+upQ26fPqiYeTEtWlsJoRzoRJW1vNHMGJvPrM2P4X8cBET02RbxlNenw/wv7m5L+goaTHYNWcgutQfuQN58uujWlfEXdzdOdOcbp5iMgdfZgucj6brHAc37Z4F17JdThe2mJIAYE+in6ZQVNGT6ArnDo6vG2X+foFODo/a29jxF2//yk7+hCSJI9RS7tbXDNuNJR0DVcvQpBu9EjNlaPAkLcpBcvfkM/k0MixcRLIjNVGRLDmDdv7ehGaj+xzsbaE1XSwbxoOBqMPgotKv01H5B5vgx2fi+5bKln0j3rn86ZA2tEyf0FwEPBqAUAm+d0H2GBoueJ3UUImwlbmK3Ufjj+IbiCSeuUS7FAxulFI+yH8WxvCLPCaJ/FCcxeo9QXWbNGgEfXQFf7RH7wfJb+r5cCimsUBMu6eo+F/pMmOMRKymsYenl1qhW0MZJec8WkNfXv1VbWHIKM4trqPrhoLluwr+kz7/PZ+YpgOAPGnT+SDT8F/2tfnJDJ6SqolCQsRH45NenXoQPXJkhcq1TPp9IhNz8qTt9/gomR3nxFgsczEdnPAVEXSPGwcopLo4eSihX63wz29AkH1HD5TTbaFiigU52e0R+k1XWbQ0cryuCGUsy2G2fyMd5koddgENtvaOiba6RbvpZmk+mdrBwfsAL0YZRvxWsKNJmPIgZd9tIW8B03ApMWnOP7J/b0Va/4V+HXHD9uP3Xr8SuQMLXFfv7z+EWzoPPjcLJYbMNutkjSVAeR4cVD17AjRhdLao2Ell72CoeP/hrSFLRjjgbhmFZumono6KKf20j3NEM30970kTStUS5ydvAM/Y9MAHMOU1JJraKcBFGUkOQGsiLEVZdwqVy6Gx6RuevDd7kqzubxm5zgVW746M0Vfl9p/gKDfTyqUdKYaIvGZpGE9TbnpUrbTKtB5C30nPaPgQUaX56WRyJvdBHhcEuBJCXldK/Z290hKkEK7vkwf0YO3qD9HoQ8+2R8UNk3i7+Vq4O16P/iw3a03dGkpywjUbiIrMC4UIul45sTuTMEK50vnXyvd4y2tVVcVONp98rvSGmi1s9e5sAP3SELhJd85jGmy/812+vkVTAnWQysqdKqLs5coLwXR1qfWRH9aWs4o64JV5E24cQ+btOBrJCep8dR0uiebYQUOpP8h3/rsYwesEkPI2H0GQh6lmvFcTmiE9oEsJEZ5fpe3gr7KPC/KifsCP3cfCFqGoN3WcrNl5vTj7Q6qaKd9RU0eO5RlTxhsFQJM1zIrI90b942Bn1YezjfFgcLR9JHdaNtpSMGjBABWKPqkuSAcL6Ar/M6RoV8us24dK++lERtOsoGNflq2X4y7bovPZmTJVfJPqxyRznMQtt3x3Hy42UB+mARmZra8BwCeJapF8gRfbe+j/R7wx6iWs7oiN81DMZLywKQALaXB/bl/+E4r7vEKIZADRe2LFi4JcPbsc0AhyCKaFXsDS8hKpKBO2554VQuP1KNADPsjGDgrOBmSHFWjWnoWNIMFZS7iArV/4iluXL1UqVeAQulpM1NMYiXKcCJgICLXh6FH/TnggPnUmJemI1AeKTmJn2AByBYpJlwjEdgJn+jVFLgvQHY1/XLDzhf0NZ+mEj+adsMSacUVfUZS1Dvx+fZbGFeY9MqMRed2w2fii4VmqpjnF0Xu3+Y/4AUXXfhuiEkMlAb1l8ywa1KoVcTJzMYeRv5YLRhaF6KCcN9bHsiJYdZczGYuqOmSAvIOB1UkM0vSo848Hywp5oWJea0w9z4LifAnawt3F5bTknZ1xrOjO4INNG3L7cK5g9SqloVgGG5LOqaqm0jeBmhOeLCPu27yJDYgVfGzvHDvDHeynyRojytNkSGMJK0qyDt/YWRBmizxAFs05Vfp1WYEr81Xm4smwFIp9YYXZntyVfjWf5UbL3sv5W6CHwoGwWNnB7FU85g2t8YFVi70BSMGMWTHrTVTheZC3xOUVbCqTXKOnLAjSrebPdxVyjbv1MJoSfLQvML3w6jjIgRg52cjrhhQhA593ifJB0mbHYhwtB3SwIZAJ4ghayTWvwX/xJevFd/YPIXPMewW9DU23rs+XkHXz6DQ3F9G/q/98fbK3+vtYtk7l5gtLEcRqpqWlJNJUTnXuV1WonDcCbKG3TXSqBc82hH32Pw6U2QZG90BC53qU5bGb5YL35CIFCl/Kix5m6ofPKJb7uWpJjAlbl+WUek9gTq5L0cb9oWrNq6Et3Limrwi3ZDBkVdfKDg8s4iLMJ5t8Saomi1SCcUG5F7jUD89MLqtWkxv/faQ7rKUmXYxahe/r8jjOk8mKLiGqsVC7kYwNFFd2mKkXu+PR1fWLtjdvYpe9Qv+ZUKOnO6HuWc7Wbw3QXYkFsI0GE/eR/fGIRAl7dB3tFPc6jVv45oPKVAJ+BgSPfodPyqmV3ACzHBrGJ6rG0uvhd0h5lkvGO1wFynnYZqxR61Ne0nVsvwQ3vO7umhngY2VP9BpziY12lMN4N95W74dUIx716McnUml6dEvb9lXF2YmMQUbECIlIKny9nn064ePnP9CZBlSQc5BX/g71HFG9YTEI715ujG2/TPB/M26O+f38sAR7gBcHhhLLxLdREtXen54DJV0mlZgWy2zySnN9rAmNnR6Q2hBJcIhul828uNxN41g0hJwpZXPF/DBcB9CCFX4QKX38kJvYxmle9h3sWryB4vJK0W5m3LkuO6Ow3/e/CTedjSiqY+swjvI8JtfDDp0EYl0nWDPjV0DCC0NGSTxWGAH0EjCdPvfYPZAnfINYpYeWpOBsLnlPPk6/0OMRG67+hG6u0mBlTBfRdr0ihNuNhuiJ423oPEOadCekd3JztOF/gL711NIxsz8ihJ/PMTs5TxxxoTw+MS/dLDg5rk9nQbNsKJCTXfu4L2bZD7h6MNuUqdOTBRK+DWmc5QI7WBrKXYktKPEo9yBDHqdfXfr61freCQlW5mPmIeZWH/0rZ8nTdHmxLKiytxJ7STU8Iii7unWytp647MGGyJpsNKjgf0DpFUlhZSUJGfyvA05iUUKhMXkeCXYqpuMMij3iUoQgD5/K/93wh4AOho10+uylpQlJuQ8DPZlMW3vBaMzGgJGdB/LBs+/15aSgFTbDlv85v6d0kQKGV+9q6sBK5r0r4cpvb0SQlWKcIOEEvbAGKb83nECDCQ7nFLsEmnY9xba8vL2AzqGFEOUoX7g/Y2Xy8ZSXUTTwzzeebsYzGeBCRDvDB+Ym+ugYG0Xh6xFmedApDbmg6acrKMaz+qOhJwXz7EHnHlpfnlsAfbOhcrcgS9KDo/9dBfETcbST7Q50YACHKlmd+hPbRz0yrjJ++8hqyy+Cv0gXDDzEk0ZkU0Ql3zFWJ+sPouiRSmmM8aO7l3kD6KnvTNeDKXrZaFmrOVRSdXf5D+NqzFVp/r2e/FcXeIZMC348qPOM/46QrxOOgFKybNGm1poZJgkGH0VCt41qrkvpF0v5Q+0Ck6RS4V7TvWnMOpJZCghZtFsrzIUw5fzZSNYNqcaRA7EuSpE2Wf7xLmKlYwk4tzCyYzxK3uXQsmL4Pl915U5nRpdE2b3qMN+41pJ4PgGffJMcYZWbUSbfvn8ZDWxSNLK0MJZ4fMoQL5jCOVDMx5juNJ153fbN2T/agfMbYVfOsWkFcjE6zLzFhmIzji+Vgy/B1ynsNivyVdcwIf+R+rIkIRmgd4vlbm8M7WysKA8DKNdgkhzV2axrl0G4Vw+x/PM0kuMwgWVwB7ak+ViqyU6E+hE/QVpGl2Y8HfELgsYXR554TCMURLtOiZXA4w8xctNFTF6ksnkDgbNLzDgM4PCV+xiDfw7Bi+FVk1ytVmnV4vIFkZ3pwohe18ycffSrRafDsuRd00uWRHqVyGY1WYXTOW+csVqGbtV0IvcEFGzFVONRzMbwGHn96vcYRz+EPA1CGhb9FNQbK9yMNxTAwrk8idQbrD+Qx6iWIFfwHlAuZ0iZ2DRoyTSP2MkiB/ZttZfqpeJkSSR/GG0eZ/s5AmTr+7Gup/p2U/u9pmLBs+5xBdLfH991p0sjSJRk73CcXWMevcSX5xDjiTunQQZgcM2H6a2RPpdQFmoudURsdvR1quBm1y4mkwddxnuB+lOK8Rv5ynDWGVHc+ngrCIkYFYR0hMcX8x7aJiJhzTgyv0TtGNAaNofS6mK6ONY1ul7nc1PxDHCQ3bjjzuiPf8gN/Omt5/w7idlg0w50IugRWyY6DavDhALbBS5Za2yhBfIf3GvKzhE9EM044HgD0cObcz6i5kgEG9Ypbi4X0A1XdlsdTLZxs64tNZvy/yESfl5cQWGIgSLVbSPTt+vMr2wkmzPHHIahpsLS9+rfp7lpTA16Wb0otJNKRZwnUlEzsSVqCBI8zgAv8g+sRVB2EH/2gb+1B03aFAzyMkx+OYYlgutHl5TYv+258MNnOKEQ4K/Ua+2zcs47D6pkJdyRs+P9VV6xku6L7Ehg9Aub2c/I/ToXhlxLmlsIS7lbDeDZrBRSYG7Ox/ko77YkqJB9LylRFW7XA3lJ6tWpfhMSt/s9VRS7fjSb7OngoI22nbHoEXq10TrLyZyUI4zjLzKSZZrQ2pLA268NEGzKJGF7Z/lx3V7Pjtsgzm/R2ebCUkjR7FvqX2iI0AQRBcBX+LdGxNgYTUX05ys/UylHA3RhcEd9kSnBwA1cq4ZJdf1ChUDtNJgmEVCki4GlcKAUyJDOkQyeElEx7oAbv2mWJ+KqcE1tuhDi2NBPSpu4JyWXp03YBbgowTJi527SswpBxTgMK1a1HLUCni2TGTYW2lq3lr0jIWUxXpSwfwnjKxJmt1jQIWB3Ze2itciS7qq9pZh4o4y+MTqDrlj3LelbyTkudIDaU1QefZOlncerCKpsM2iD7nwxd48d7l1cYZYxs1JUGprvl7blXXetHwJ0uEaT6WpFOfOR/lggd2Q8IsacXUCR3b8tq/YHLjgK7ihWXomGG9XGBI8idG7PCtcvDTsEprVrqXQ/tX8FtFpnn5ShSbXVaAMlpN12iupVXXCLSEfYfw7tu46rVR7vK4O6dL81n6gfsHh9dCEP3lpKvw9NclIz2pNNnolZSQsdVoZKSVXJMWKn1/uh3WYi7tuVgpuCC7qFQd0VgFgDOnvkBEg26CJcXlHjiePFqc986ErELiTFNtEL78uyaq2SkY9z2rU2RjDDsJ7X7ZIcfstQrcBuDYvPbdvh3gRVbzaXGUSu82WTuHWaIymLjBzsNIVwLh5cep29HPNdeSok1Ss3PZgveu7yDrDguCuJuqpOaWk/YeL7IRvdu53N7YbPcTCXWw0FkxwPRYcHvrCZXGq14PfaaMBLZ6MRrxYLvUklynHHMEB1W7jPuw/68exKTz/1S47GtL8FjozrZDDB1Sa3UsynZrUlZghppOrM0eDfgKfi5o40TkaaRhWLR3g5V6ymhcbzhp55PU12py2UBFcQP5hvpwqDZKN9/61P3nLTrKL204GtUU87pt2w1slwDihGTsAPAnyucwiAj/FTwJ5BoLXY4UVLPU4PvB33xLObFgTyt6hsyBSsa3RLD/n82Pxx5ah0BHc0j/OqCyr32xvDCRuk7KvJYCQYRHX/7pJ0cWlSM+ltcSAbFITSSo7k+l6edoI76xEAmdqT1gBoBi9QmwyGC/LQyuU9TmG7SvaA1aYX1aPjZ5q1NDRNy0s5xXr9tj0HmV6yT5SsYACuybvllcRwFOWeKLLFO8Fi0Ui8Y55mR3Rm287giYVD5TZXBwqNYrAMnHwB6Mg31XqElTXrYAaOanvKmL/5EWZNM9cdnGWZ4LavfRfqFx3pv041Xiqoom5nimUbMfF6PvE2yJJXgEW8J3OPeZLhR9Y6Z00rem45O689S4Npgli2r9quONNEf6drcOFZ1F1e2cFylZhvCrRN6P6zyyZnWaeWMZmtOY7BO2m2iP1aVuQe6WL1FnXKumswjpoki/Bmoch6ZIlSs571hf0jtlIhG4zuHbI8m58DflANuv7XfVaggDuflZIfWZ2UgxCWgrasLMqZL+4jQyaXP3VmaKkIP8PJrzAFQG4Yl/CgSdj5qaeIqzq2jc1GnunFPo1AWKjwT6EwSMAop2Bvhv2wm7T+1YVe3ZFwRsTSyjvzKjeVKibRfgsscvYFwMAkzjT9xxQ9YHGAIEZOAGu3iFMpQzZwyohIgAJ+OyoJaI4V/FL4KX0jSDo9Cw0wGI9t5dD0dIflttg9ojabz9t5knEF4ywRWOFBld2CtWIIe1Am5MMwzOHxaVen0ssT9YoNI75FbVCVFiR0zNxw7Qc0Syvqu3BauBog+wd/Ur9+Y0ATgvobfGVNu3iuaHxshGOdF0nJF5gXrROmX5Hvk9PKRfA+p8ClCb8OvD098ak8/pS5ZrMGJUOJDwKZI3raYa9W9ugWfdDuPpEj3TG+GwFO87wZnmVaa9aDuvTnoqpsrw6DzauCUHcx+Eq5ZN7/0xMPYUBlZHG//TSi8T5Y3WmK5bK9w+ZC5KnW9LszennUSmyioukx1xcwxKxq57i6EAZYWm/uKjwg8Yy9oZn8tw2sxd2HBe5YX2hGM9Mkx07ihqx8QHiVjE8GgKlM51diNnN3LGRAfiE8QumL7HVmFVOIxBoFAneSi+xt/TfBOr6AQIUycQfi1TD8dSd5qM8YHVDCiRy9Lq4oOYWdgAdo+g5PGbt/JQRRZH+YkqXx+4gR7T8jSZPxYHdPF6Er8gFA+DwdSyDbFbYP/3bWoVnflCg+8liGk3WKkwDXX+zL0kuvzJGKsuCw52F+UyKHGuEA+0R99dydoteE6mjbqP84jPhnk4uIbMtr3jOPphm36hMQyPpqrp7T0oupKahOafpY6lkgOQdb4Zcy+GjiR8y2vLXFe7KTm/yFCxfC88adxWzJtBn4Es5cymH/RysTfjYKQthqDRGA4Onys9YHuSW8Hp/0mPvdsQlZDAO6L5sg9xwQGMlyjIfcCeeJmfpuy3Pqmyvve2udbiwjGNdmy9pl0UPhUAdPywYu8Za80eSaIp7Mnnv/CkN8AJ2BdIS2bHFgN6KSew4ZjPNYOCmRKxwazuSwZuJy6UNtstfT8/1FuucCUKwLuki04GFFKw+e88mIBYPApjcEzHInuPhaqyNLrY2KLB+QfJw+X8Inx8hhycCWPT3LIY1PEk/nB1ddYZO5XX8x/Lb3EwgTIXZ0Oa9ePQuZGyykG8+gVOmvoBLGBBTYstTIz7/pBokQCVU4WM1OknDEQFo6k8rzNN7YT6Vshr2CHhwwinOvYfI5TrarmxdO1I6zI+G0mh5w4G7Fzzo9ozQdikUZ/EdJYQwJdXjT0+3F9gU8b2ISRAeOMYmenHB+zvbOMIELst6CWzTJADcp+HA/FsLO0h9Ta9QHMKf45BlSSOOoL0LG3SNEhINZipekuHipTVMzHYsiVeErA+KCghIv8rE3iiTxEVbjQHjPHc4z9ot+7WOC4JZ387luApmwMPHbxvpITHcL3MOm+RG1SJscfbGcWPNdoVK1sC5bmMTpzqswxRlsduEwSkE4Cd4iXJ88Skk7lDS10Oo3k8Q1WPz86/+UhHEs96/IJ/yWo3VW3dmtS3D2F6cID1SGp2EZZArFmBbo9I2xjIzzrOswyaRE+Cj9dHryJHv+9nh+FSKrRa6rR/rwbLy+ktfB0cr0fXNmBlGgNcls1SJxtD3s5K1DHtcwA/WWzV9qDxjKB81FO/WxWkbTvFRbq+OW6OdxIBD5kki95qItnPvzSlqxEa9G8BWj0v6yud6iC3EVHtd7fDjvt84dYKgbg4zW1kkecBDUuuyvA3UqOcQHOqNEK0lMbOZtaJUGNYQb9qnwFARl/KPmd8UryhK+SpOByGQlH2Yv6NrMgQiisi6E2ZlHS7KuhygxN3dTkMS1ldhOSniQF4lG8LdMUkaSOxu+KUkPNB1KcPbNRLPODxfMzbgJJP1YySuXy6Mz2UrU4aCUY89QvfN1+relDxGE7rFux0dcfWvwmdmpTWOyGdl8aqQ2musI7ujqPgCrU15MZ7i5j4oGcoXBi7NUPPnUewnZyKd46pAmzhtUlcIUqKV/2OfERtsytXbBmkjU4P2Tr5kBiepMniSmKP4fwH4yCOLcv+KhQFhM4VCQ8ZlPoRH059EwCzsYs7A3SuW0ITFxCZSNAEzgjP1H7DWWl1PRSSAWZMBOB2X4VxzOlzfU2VU7Oykv4ZyExrPG/OF7Oj1FjCjxVU3Zmn1+fxPI9sIMLfSm4FhUEAkXq6P+gAE0WHLI5eidQq3mEdm4vvAfjvtX6FpnIUYyTbn0vb4NQ5sF9cVhwIPCQ6pzzPD8kjdLgYYv2zfpx5zF2sAVTyQ+mHRbSEQmCmKauzSbZPBGi5MR2fJUGTu4TT2DweccCgT7p72UuWKZPu9s0w8v2FiO8wc/UssQvoiEIrSJg7t1DQGQDR03f96NQrommAQOmc+6M2wxknsKudsr4lBvk9rdlMBODaMW/b4XG33mLh9fHGkZ1RDdPXV8YWQpnecWlwv7h8U2evUDGBVI8Q+lPPDPEqvDz4/snOtSoCqVutPcf3BdGqGlHvGZXMtEFL5gTs5BHCgWnJVXCM/KPTQa92V8ePUTmaqcvYUO4n1d/N56wVUnjfxUMkB6NSyOYedcRGpsmX5XiTSCc4aymaQ1S6PfHcDlLI0Az6gtchMY1xtt7psuUqUswwxzbLImygIp978jpux7CcJIpA9AWdXz38Y7x4C93Q74JspNcMYjmPabknQoE+XRsUdpRBnen/XLb37pt8xGtNs+yc0dfVSxg7TaIctPdqyTRhuDPDCtUEGifsTf01PdEJrhgMDA9WIQWA+FMwokc4sSufWPahUklvKJRl95rZ7EKTLwcvun4to5/iQC3W/u0sSNtPDX5G1XOo0zxw5/gGPYZtQPzwPf11R8ERX3HlS7HmtW+exGCDcBeCd5qjtH/eVHV5+AvZ/PL90KQz2+Z0RihYOgPV1vZRzsvFs5X6mgss5whmCknKx+ucr4FcKuYEJt0dqOP18Vg11GG80ustt0tRiFgVPfgYyew35YWKsvd7KGD4SaNOujlcoJ1pk5KgfYHwev2XzpzVLzG+aC5GcvlJv663jNrIyfglaqPMw55tKG02h2uc/KNJCgAyoiuWG5k5plPe5IkJAIkNXof8SKIvq+pcj81UQrL73+ZEUG94p+R7MG0RwL+TamEwqm1YOn2UGCkHknhhp/A6Dr3/0SSnk3fE5+UfmBMMgddm9hAU+neV57myQ566sXoK4pE1Sleb186fPBNuF0SbNKPrR+HPqGKr3NQxZbuPFBSHmz4Vc/S8fmHMp2/4itv3syi5xlYKLBmWHm+bblQhok21Gj+6hy71LIh+9MmDKqg7p9fH4dFQTTX2JrXK9Y4rfGJHE92WF8LS0qnRUSGbS/Awwat1H/5ZKGFFRlGKK0+0S761UIIkbgh2nWaEandd0pgW1hMfD+jKaCCNKQGBrilpdz1tmaqI9hXPLQdB2PCVgsr2PdVDAnkoaBcGdgGP0y398jIhgqLMRrbymdn6jEbCi3k0mJV3XeoGn65nIuZsQS3aIOOzO7Z82ebtxjE9TisAi1Z1+pn4ocR7Tk/AQzhcaW/BfRAVD06u7BOJT8b1MdWTVlEGu3Sj2JPA/w8AO1TFx//oDnc1kncSMBqJx3v6UjCg3RW7GDuYzzpD1GEAotr3tOtr9eLedfzDxBMm5l0C62nt1hezEnDgRUCdqhC/8o01pG4w55OWwVcMh2YiEpaYyg1VdYx4dhiLTxshFlORCU20p8mJHfovGnwJVkLO4WOt4H4/xLOyiarIF7FCGeUQrtVv5bBClF5fxCylhau23LtH4eXnQDtIOtojBtRMgG6oHAbqvOYFi3ZkxE96WNPStjE3vOVpt/jZsc7CGWmdaoq7EK7La5vCAYF50QbnI8oqmThdgEf6yz2ojc/q0LTgs/SITzl4CgBBo919BWYSp0YchCb0yLomLx2CcEpqeZFdqM2MYT882CCXheI1npYb9Wj8oF47l0qijb8dc1lngCeZxDeLGkI6GTQ3sAoFzUvHvB5zDPBA7P4cKKqSCEkZLlj2AbaUkEAcfn5b4DFHV3zoP4RAc4zZQs8VCDnHgKqQYVaz8rzHt9Inqyhyg1ECCIaCEOmFZG85jqLPIYVufXysXkArX1Yio9itWmmwaYkzguVqZ2ranLuZPdrG47sDhI7E/7XnIVwCFmTESdAkppZnJvB1OOxOGvdoZNWOkIYHskry3bLoKVMoSdi/wcLXvzfvBHaDn+2hvEPQl6gjzP61sNSFrbXn2RuSRl98juh4/eEH1Mbd4nnLpFgqSnVHJQVn0v0Bgo0a+hClJRAhnZB1hiDyRUF2Ms0gyM+aX7cj6mOypGLfkLnJp5GbMKnWRiumocryUcQiUCgqa8NGmXzPi4AVeGjAq/MvxCsaB4XR63vosCsg09mAjCWEBWGFxS+9DrRphxW4Ol3BXn3jIwVDYu319QE80iR4yFsG4+ihUViXGMPnl2s0yCYU0Ek/p/ye5/rxIhJIx1KKVTafM5wsqZw2EjD+n0YWzu/xVKbZRWyvwew0ANzL/1b+0zGyYfO1jgaFwvSQud8gHh81zBNizipV3PC8U0bDsvHg8b3hTlPKcFZdnXWrbR4KWjx62UTp6lxGVmZCPp8pKNKDcRSuAn234DbSsl2JgeQnXcfPd7vbaSd5d+iOwc/2LMywXz7GVNGWLNTiKKhzAu1UfFXPpyQZ5R4DAuOHVb5Fiq/dlkHJNzFd3VcsyIrlfJ3txwvUCNfqaUx/Xgo2ODzxeoE6eUHpltYvS42zs43I6y9erYoMHZMsvTnwkF7RQMw82lw93gObMVecRY4rJcTXYXDavOqR0Cf9QXtBfMigcMKWIkXgvAEf7HtkHqx5bO5Hxy6CO4IkZI/YN+TxfyPs/RfiXgz0Fk1VAPqOyfZ8b06mmCyIi/ZQCdjixA6eUBBPBEWD3snek6Si3Lr9OYAvPS2ct7Q6PjnYqjPf95Bz1pFlgq4ayCyU0Y3uY+ObVTUpikzBPK9GtqZIY4C6WELx2cTCaRCCyZ5BjLtWrM7BJRRCX80KZpIFqk+zKy9gvuN8Vm2S4SLTKSvalcPwZU9Dab9ylzh7SDFuEJVXvj5mKtcWtMnKN71hq/P6zmIFE0rIw8TevNbGsleyxBNTsnSg3FGcSdLSp1WlTHR84qxaFfyvSjn0fCU+Vn17Hr+6o2NbZk1n+ZQ+FIaDLrDod6GZm62/11Vxx4sdOoJo2dQO4ck6BfODchph7lH/n+5EeBDSCn58XJE9ud4uVdPv9j5/UzJfUIzJUnejLDA4Ug12B94E07nMkLpt387R4RXoHedrVnSwnMofYgiz8zqXtCNrx5DVm9jUOusa4lNNQa1sMN8Zs3I7q8UceIGc6vTexo+i9b6RT15Z8IU9SxeqNI+OnfwUwNaxIePALVy7nFhjmdw9yHIXENq6NnUfJIHhxbYV6CS4fmR6aTjZgIrv9UGJTMwQ+/ps9VO0tzx+TTJgSJdAXpY8nf+M39IAVHErKgwvBvhPJtPh/5W08+wL5KoQvB6mjjLz1JGmw3zaOlah6w0Mr7frmysX/V+bUpavmzlawSUxd9uiACzBxH/WWG1Bs8L2zy2C4+B/nJ8NUs72Z+NHKVC313OVKzpfugM60kGaS3hJPu6OsjbyVmlTo2w4MFYtjmw+I66f5Q+jlEYnmL498O2XNuqGV3o4dnpFLx3zPzdLIgQpojO6a36M+hrE3HNVrg4VGB6OnPkWj5pdZo1g0bRi6fJajkqVnicTHdhBD3lXMKBlCfGze6oWqjASAj9lHLPTK+IMFrBnQy9zH1vaL1rVSZtl1VOOCqfAzSpsFJnKmO4SrlTdpXH6wIUxaStMXZzui4SHOuITNQyakKmYAd8igk3hvcrY4UhkK7Je2mbeNBz80kftVyfri/92c3b/pa+/P9Fjlqnt2iNKmpWf6w+01OGS2xBRy5kbRQUOo3dqNcHyvgemb0yCTySNy2JEzNId9ELQFdATBtFNzSs5xMmGa9Ggkn7rhZgjEoKpk37Z9RAf2iOvPsyYx80BY3EY3xOET7Ipcoze5seKt1Cfq5ozKYkWapWaJzFrnM1ra9JBvLqVM2O7swjlMUTQz5MeyvxLFNn15WyVJQF78YneVmQWsk0k4Bmaya9KkUtj7/X/qaQbrhXfe7JJjxlVnD/WdJIaWr/iXn4osKiirCbOMG2UGr9jO9wRSIX4lrUbh3JcselHrtu9joJpd3fDDru9N6uYrECS+mk5RTcLQL4c3GClNSufyo5rn6pOgqAjikjLhq1vCgP8epVGUUCu11+39r4vX6fketZPbnuSzfocf/Wl64JafgZTHFOn38TM4eCdwJ1+W/3F/vqMX8r41EMaCqBhdTQI8YguJAy0pzqqIJIKWU+PFchDvW8Rve6mTi/vEg7s3AJQrqoDtfgFbDfRdvTu6yEcnpV1IBeh6oOsT8SUJ98vBZce5EPRb9GVUIPv4RXML9OPZ1X2OxApWLDivcVTIbXZ6MoMTqX1aXLuj8kN7fw38LSiyTK+zIrb6UVQppeJ+X70C4aGVsf1cOB9+OAhqhUx346rAf/f/FdzECZvwC5baraUglXuNYmTVM+CJH2KMuV4anIKnoZXKEtbkuqJViAWRd17/Xk4luF8Q2Ro1KEzo71GrioymCcNbkr5Ux5IkBbzxM3R5pbt0dgvpvCkl0PvwaWctdrXUos9rfarrr5PXRvm7g30H25hVH2VUWCEOs/Q7SXLR1fxLgJ99+7urZDNRt4GMX5t4nSU/ugOkW7FzJK8wtHwLm+Yx1zpo3K0SmMKP+UqFqSJTkTfB51vCNllYRI1BA5Ze94+BNsLok7DcYEDsRDR0AF+MWxJ7caZbUxXWmb/zKxTUdx9o2hZ49ejbTM9yuvsSIjgkQmKsXlDhBV6nB2EejHU5o9SKGXVaC9M1ngfP0EKGY08/msNYBzB3fWZWjyZVz3AyCUXdsKBPU4Bu008sYsMFYDl47qqIYpgmCyq32yoKFSHwo+qnBFYiiSBA5xG0Y4nmwucjqJsOkOcbTrS8jH7EoR8yZUTf6LenLjkqywG2YUQhhhk9Dtio3qgywH/+ksTxGLcH9/TAdERj4WYO2Acuxp9TYkI8U0slhox3S8yutZpUwn2cxyWrM60n3BafhbTgAn3m/IFaVvzaclQx7bCb85Z6ZRwBtTPM/eFsPDSXJRbmLiS2+Qs3pe4HFo2mr+3ksa+kLIVrRjrZPyS/+/sdV1PaU0Fd/ixCOxgWkM87Qe0uEaTBIZh5spZiALk2pT7rZ+XrfEfiPUUy00GgD72oiQahf12RbVGUDZpoQpZflnCNUvztCZkF8ZTsZsypIxRrrlWsOvxCLbJplKpjNwqh9pfH5HFwocbmqelIxLBCPOLIs2yMY7kBUp1rW34wpqpcYQdk0DE8z7/3BDmODhLuBtk2KQg4cT0qdHXcN6p8+xYn015uywYvwz09HekddWeNmckQj265XhFgqWxaWAxQ1OFgLRfnPxplXlbWKKmCodq0oa1/SvCH+YbETYr5l6FS0pS6BAySBjawCs51AxTaJbhIkl3moeYAwXIFFSwn5DlomvPNIcoHuzXHifOa+Ym7yA8gjkVpm5ijihbxXiUa1uyiMVLnIPvklRvHDN/FIu9SG4/s3GOdaPrJu48Ax0bgtdMXj0CmjiTn7Nma8l9sOXQRd060eG4JxdO8aBkVPhr7FLajZK26lviAlkfU2aOpNOkSUiBj1nW5G7uiNBCfFx9eE7uYfKsQK/DNw60sNvjUBOCxr4/quFnV8xhTbwIh9je6lkgrnwM10glMLrfhupAS2oHh+NLA3w9/NpgL68Ol3ItOjNidcC3hswO4urbG3LpMtFtD4HivGpI8H/tje7VQTiH9eIIC+GTU1ojicYCFTQ+WSQ+l2kOQvUozPKsu3UlITWXWRr/sWv56GourDoNrAZRY568811FbO3woLXWMmhf/9zApa6A4IGBJKx2XYigr5WAVByCEcJa/cd51/PX/L+wGXJIJ/3j/wNUscZQ3b++yNsI9YnWfG2i+W8ZaXkHEHVXMqT4sKkUiTMVKfOx+UrCbswY6+2PY7j3cM43Bp+dHpCDpjyURcTcJ4Lnzg1qIDubbRAuUjv27buxnxOr2fH5cViemw9XJ4OosaL+A8LR7vxH3uGS9cPgW8phQab46ErWF2gssMOYtA8FRkSyJkLibc3mV60wKMooOK0HIxSeADnXMSTCqVOjZzyLTMSlGtDVzNXcewp6kCx4g10ooJgySGut3RbrjQe+cDieAgs/TL+AV4lLOJcrl+JknoS2A1Qp62KVB1D+YxtflF6hhd56jNSvORyHFel4jpwiDgjod6hLhnhmt1kqsvACOCtWTVwlQj449+st2rU12IQ0gLt+6U8Z4NEx4c3xoOR+Rk14WvCq8oxJniWXDsgYruQCp6+RTixFH7zSbpLfidlG4H3Zsav6ufMANV1i+prj/pJCA1r1C1HeNtT+fB2Y9ha8uhcGrABwNqRE0b/0eklUVc9FtDOwVN4ADy+Snk58EXydp2c1FQpvqwnor4UW5CsHuUyLDHjDiZtlOZQ1bUGUmer1kqXSUEzO0suLfBolCRci4LtcFIjNWSUU6ZQgUqKf7ra1AO60cn5GjY8ZicbIeothpFLj9IUX0eJNQIFTIlRWl6xOMrVE6wXRf+yXf+TgzkcY8RD7SF6T1iY5aR42auUj5FZRgUV965aSnKiu6Wsgf6YId/4o9Boi2mdTNrJX6iXhxX6Wxi7/Dtb6dSc8fNyIO4796U5j8s80aJjzYZ2H0/3QLDv/Mjcf88XguJRG8QlYtbEcta1Lrz9ophA4iJPUm7FDrWMoz1qRLdnVAkHZqTl29WLordJke3/UsJAuYmCiHnuDuS6JW75s6uCzylrrixNup0LPgUWXOc4dbQlbHs9lbuz4X4UGheFdZnFyLOhaoxtYlS+3Ik03RvBcI/GTQudlTuMWzzlUGXXQhFv86XHdMt76PI1ckgxaBE/IJ71aGUyur4BY34cM9o11Q8J6oWFO6GmD2SySQOAJ1/SwZenVjANysKgwObpw1Q6JX376LtgbK20JnR3H8j1Ilhq6wJGOJSAlNNOCstJqfGv3Jr8RYay3oQY0Wd69CQHCZtcuSR+wKPyWSn8z+pXOxW/iaz1rL1CKxz2YS22bOJaZVivYIXi+wWg4bUBx6BKov6ktg9r3Vuiqu38Rz9Wwy87ymAgXX+1EEoMKeEvs/zTSXap6ZFnA0ZdeIC4YB6v/ZQR5EQbZcRkgqlQ+TSP8f9IlhXaAknZKC/uUC5juv0pZS/vhwM7Ac6tiEPoe6uh0TeFg9SHihqAqXNwWO1FCjOTeOH8KUdhKqg6Xm3EUXBh5SsBW0wOfKRFrR+byxQBxA5WltTmqeP9OJ2ofcdTeHrUOeqacWwhaclD9qd6pLk+YX9HjCIN1xUodAuzIzbVJK6ejBXC26KD1dbKmHN5ziMebQvoJ1/sBzXM3E5nX77B0HNXwBtFnlFxwnfQfm3Os6XvqcywzYpow8946x2jO0+yozyXgFpGy2slOMLINGB3oMCN9xwpTkNuJaY6u9buVCbTr7jKZIvykfM9ddQUTfgbNXs//7rQYdDZefzdkJhZWsR3IxetNylUIfVHSR+clhwq+fbPhXlGcRekyfw+uQVCH/UCdvnyHy445opnOyKVTkvaC82La9u5eFbKC/Ev2j5NCiDWABJU9y9HF4kmxo8b/i1aUstseveD8QEK2Xv0Rk2QhGMqAIUU6FuPh86mbwuUji5PcRV75mRVS03gTtZlrJrr6Y2VrMppvmXl8BSzwATfI+UKR8ZB4yufkJ1U8OqplQWO+RBqYeYUfGL38v82atnNWtouorGx5N6CY55qc+dS5Vu1QscHhkO8EgdnYxM7otuDr/SZnbJMzBbFsO9i4NSJM4XAjtfwZWdfRzWtU/5FnH11/Byu76Kf+qJE6rZR+5pBOkwR+4C+X6X2LthfmV5KZCtZg66Qel5K6couNtS1oDAnOuKvbV+rBEaCZbrtmfeBbTv6weTYyR6ZHiHNK1vCEiCDELWVT62HXxNVEZXsCV5/h5/bPpoNxUivw1hj0RG3nLZxZX2O9qvB5HnAfuGCkkUPzkVsNSaire/TAKKnKJqS+vtebupAMjPnDvoaOu826X7vCzoLotirOTu7ZdPmgTfA5p9c3axfIs1NZ31BFA9ehCkWCXVwzhEyIopUbLgSPnlSV3/pcapjUa0V3Lm9sJMcxjFZZ9FyfKtsP3QRSZ2r/xz/ZzXTetCJ+8wJOYysw0vzAtFvErpKv8tsnhjTFrGFhHxuU7w7qgVeU3Wdlfjotsa63NqEu0UX4BVpXmJEOlac3MfFcx2MnJsZhKQHKwDJtlwfyU1xJ+qctjyBZdQHucoxR/r0WSeOanEcin0n5ZsPx0FL8V3Fy6zB+r+wGE7leZ8abPBCYlqQEH9JUOGiJKqo9Fa2rvUi+gMl/OWHhqG92jYPUClP5PTEnMofOKKKBlk/XcLqxgMSmZpxaQd7Wdj34dWE1Z+4FVgmUWIrCEsgAFN9apYIqHtyn7VYrZ8Q2i3JqBezCb6dwoTvs9GfgW9yzNChJGtK7aDCG9Fq8L5/K0NpcyFJZ05r1YORrr8t+v1jixq5o3MfJNcSU+K+LsBcHABRiRMZmdbaow8UQXvy9/HIQ85dsW+YQDmq0czjEbicJr3/oqE0ItusPZwJZRSa24BBVFiZaER7G29wxuFqVJArUtPxSZtiqZKQ72oZsX5LpcQ5WCjvXjXhX1P+a7xRzG6bJ7VaeMfZRtF/7Tp+iai1S3XkeBSePF9NxBds6K+Wa/ZLscBJPRS1RMu0DIcXAPpryVA3hC5AXPkX+ZieaZet5671utbLiw/+XSEyb/kE++gVgRnDvjqrsb4Ccbn9Av99lqt+LEccKLMUfGp0fHAZevApU1OEx7HZ3izJkP0RMp9L3y5pHc5rKmk4ZRnW42Wp6Yq+wRA0Srp0IoMF1Jv9doiPUiCkpbH2IxcKIF40M/sezlA+UThVYLK03YtWjIvRIn1x7Hous8w0RdC+R/chMcXtZaol9HPHFOcsAcnBOwEb5OfQ3Bv2a6ue+yC4ePBaP3Hm9PpyQodnG3xj4RHALhrNb6ta2Zu99KOM1qEbt/XVDrIQCpCaUmnf1poc2YzQsgEn6/i9YxaYskWLnZtD/bx7WyPHobwahGkik1M7zBxv5lQAbisNM59CwK9ahin/RpMlfeqwqgRUza/o7eorecQiFjrvwKCGaXBaVB1dYcX7VfOnbfWZBStrbTOrWGjRlWHmECxJF0nlp/fOOM8ne1mO+j/Trf8lIRzOtVSpWauuq6sc5krUk7UkfHlmsGjc6LXvoptFtAvvjuNA1yWz4BdbnNYoKhT5spGh/8eYIVaE4QmkPQNp5fXhAqCtyI8ObRt+ENBA/d/qwQ/h8p5xCEENB/DIjuRhIBL2rQynHHds5PLfoE/peFoy1Zt+RUgmsgQRESRpRHCf4MEjN0mrgEI5cYs2iB5tnotdnn63LTy2Jmoh3gK3F5pkrM4xJ1FbGpAb56rC2GVTIedmcpcWC8JMNvr2Tif7iXRHc1bZkrDi8YyVHaer+tPfnsuHnr0gMVjKtfqgsfcxjxfbNewUrnEWegsuF9rUFOt5WHwH8tT2wmUBNi66yisOqhHrfk7QwmO8hADbqeKBVtXC3N3lFwUbTYyWTbSxfNBzmCoTtzuCCUk8mtsOVnqnXt+oTkPP9W2j08IaChr56fltYT9vP7z8sZRNGQ30xSSacoZeUfLLLeDqLZmoG82taeGX2d9VbVvtZbdr93Zbu2GPlSPAMsRd0mIMJoKPgb1tsOh63XKFuWC6dRgoFnx1+vlzIgzs2O4cqr5kjaJUanO25BKzsT3ZZW2KFauXuXvxX6tSljrr05fZ9Hu81nJlunUtiLMPMc/+XPNYNz3olnzS1a6Ohmc+GQdcsI7Kd45jZ8U+MFokA4l5D80ki55qMbUXb2xcyzzDLLozRGo7J9CgLaKMCxtx/3jH5r0YG6S0sAmfP5rn18jbiBFI+xBUKRmvHYgOQzfyul4kQaXL6iw7qCKG9hh5DQsbN/X2g06COOvGIMxypvqztPOEmHMtrwJNNSz4571VIiW5YvuMq/S6t1mybgXx7+FrF3ZIKxntwaJxeQz60py5mAtbtZFc9KvI2sj+WY3gGkEfpgy/RMeRgrsn2SlNw/L41/V1lMv4rm+Lsnv+ylRQaqLEJRdBEHXBgt+TNfK8yFaLUa6nuOeUMsq5L6xp0N7DU4vM1/JgwrhCmWROi5IfBnRzaiWYsoovxl6kgRIE3HulcOf21LpOWItNvhAEvLxGh2+KcPMOnT5G4yKV4W1K2oGltQ4uHF8i6KN8W5/HzZBFvRXsSbIjQKKmvb5Dp7Ku6qVLthRBCIumDR6/ArOx06p4L15r0FsGJDXw3d1hRXt5PIr1YeEn/o1blWz8o2Xr3AjyNe4miUp+V8tFaSIhLMAr33oEyW7+MN3E+Bm5dTMHqkHEq0NZxx4IAJo9JZKiqOxcJSg+RQIyC5Afqu5Xz1NYMaiQjvLCHpMXTYMgFX7nqPzDv0PAnfBfwdM8mYC4jQZDquTVorgyD2jmb6mJMLBCthCXc40STdIjtbItO/PWiE/Ew6N2t3bVyj7AP9IdacZr+2iq0M36Z3w0vQL7AG+oncSwilxsPlFdRKzH2d6TdddE+ytwAEhnF8559gd84f3hYFMrYLz82jrzqaKWR5UL3lYoG9yP9GxR50GCB5ZcAo9fHgdwfdcl/s2FRlB1O49TWjF0Lbm2HXXGUCm36pk6UNIR4JNDH9eqhMPLy3DDxR4XGV65WUjRjcRaJViwLXEjXr224jQYA2gmfEzAsv67sOcy4UDnYRRBIow2YfPVX3vyQHEjICpnTdLTRqyye5/DWeY49cW/aOZHLw1xOgMGahcyrOCBGZTjx/e7DY1Ab10twCqnNUXT/HBQdaPx2oy4H9UVaT9f/3/b7kcoM89GhfpibPW0MKqdNwO0NQnDO7GLORHKfBF0WYHbrGdDYtK5fPqsjfTVp+MYq1pnc7v7e6AD2h/4u20v00RnGAUCvjDQgDdULiYRehWRzjd42CUiN/0SSNMVzsB9OXl/UZ/YtcXuqFEoyYSQD9xuPzKXkb/IUB/8HP317nRRw8zI/9WENtselNgZT4/eZtkegNJN+lu4Fz2RaSrDVCmkMM8X/rw+ow8SgYdi2M7bTNJhHzqkR1pHviUtbtQbVrGnXn58E/+Lr+StoQraiP1bshXyzKidy2wrOI9Yvsv0Cr6TtCIUnihqIA9Ttp35KQgJJcPpfFGuIC7ghtz7UP6iu8bpLLGYfd2k0C9VBIo1XwioV1ckb/ppUO7Ll29G3pFAN37i5BOCOlkFCn5RBGMdsj3LrlX8dLlMSXbp3J2ULuqZy1b54rfmzyWVuiQ+hOB+KmNDYWrBpSWOYoafGyUpduTE7xQ9quxGpqwavqmPPHcOxqF1FY4s5a7UOXl8/m6Ri9vgdJj7lWwSKNRsW3L2p0KJ7ZohyR+9cgkrd8shRCU+4pZa4TREE1Xo4OIUpOArqUcYtl09883SkLsolirLyigJtva87f3smjAMP2I8kmFQcD9ifmIKPsLkSYOlu+gQmAYDR2PFF8X9fM3HEp0DcM+J4vXFxNi5xbfhxTMeOp668zn7XAOL9F/KAViSsNFjILBDGsdrDM3VYwEVw8DE783h/MdcchPOjHte1izxuPuW7KDK6S5qCbNWFfikCJ7dl4QqjnM139OFLT2cxbUfaXXurqBoxtxc3++gMbhFQxUmAsMjfRTSHKBt9vQBrq/YMa+wmvC2gmcrGdh2OIplKIrj88cHFFnjVW6TaGic0fFpy09YSLiWo/uct/V/6HFQVTv76Q7OQERh6+4hBIwwVTcKtf+Hquc/PyX/saHNFqXNWlxRyjWfSvIBfGP/ClYP2Pme8GN+Bos2wmWfJxtbP5XKCJRK8y0KZxIj/Loz7Nk+yBPmNUuY7x2k65VTx/fMDr94/kZuWyjokww3jSXifi/wvod85jK9pOyhe71RgUaiPKzN7Z461mwc6ItJ1V9egV7U26M4BBPJJarD+d377p01lCpqLaQBQ2EigJeUaq2ITqQzAMobl9TFd4WjjGbB+7wd/u7/v5BHDSQyFwdof/Y/Om8AHQbTiOhNrvvqFHWvBhC/n/L01lzwIWSWq9xTH3D2Uu7la0n8kB6/FOu8Tz3LdebHwvop16l04ovN4K9qtJHqELrB/8Y2Pza3c4EUV/d5xGQitThNTMtltFFDj3bDYSplAaoRTB797gm4fdj7+RS59UdzNYhAh+W9ahZllpt/zG3NLrSYQPXAOvmt3Y/wIf2KR70Has8HnY4qHHmVSxJLA9UwZj4LJ1JAWkkB+vsYaGKrZtFW07Y18ZmrmTCNB27oH6pEPZBDdELehPsNuabXE2MXIhZeEYAQY3Y3hzY6O4VvXV4FbSSkehE3sqzdgI6l8vc3t++b/vh9cZtQe9RrswcGdLVkMrYQzfEnjDnmXX4eCmPmvZX+W4j1Cs0ObnIIc/NGl/8DBHp3rhzBmbvV4lT5f9Huj0YBmIAAACMbdu2bdu2bdu2bdu2bds2PlaH6CCHXswpaXHZyJ8qVKuW0fM3giMRTNSt0rmICOtVWj3SYFgChTE22QPGmaoNHgJfF9HabVlm6CDzr9DymEapl45f2dDEnrtMrcPebz4JwS+NONGpG19AqPdxedRgRxdSzusjHM1HEHh0Ri1g5ZtFiFi6K7hhY0RTZzMLyuWwln/mwHZgPotM4roKVo/vcq7AgaAo7vroSu4O0reqhS4pFy9phJDxmFMi95pOxOXy3PtO1j6+v+j6IdZEvChzcMt9eiSlDN5RZtSLW7h1o1DTGtIGTWVQMAzinRpUj+I32/nt2tLnnYYhY+puIPdsFpdBfo38SwAR2495wkRomIUaYAQynUB4SkGh3kyGxkf/beMb0ysbjfLsGHe09Ny+YdOvPe0NMdTV8r0X+McqkCAoRHeEgnQGdT4lVDvqyNXffA0wnRmxEpwWxpS2R1pLN/1DvlTOPAXuvejteW5q5Oy2RxmNH6wvR+BAf7zVqtp1hwYiuzAk+GeP20aozsznHZLCsyZlLL788iJy/2rYrHRTn+Lfsu6ezNVTRW9DoWYQsvsurtmU/UTZV5gmL0uRQAniQhV0TCfSd0OyMTlmKi4BjCNwC+u2Rp6a1bz+CaY1PgY4GqlypwWK/0JAShFwLhQ7dQGeXdbKyb5aVQb749DdITL74Yto4w6IKS3sGCW3/aDlsDYT/J2xeEG/cNfh7K88sw0sCURFYT8yVcWQaNSf3XdDFzoJ9nJyXa93A1YQr3x5oaev7EtjEsJiR6Kf0VDME8ReHBsApnHbIBxCLXkiqx5sIRPrW0CkoELzqxwETYqdsQR+ztUEmAfhNCgM3/s0euvUDtisPRejF0/QPc0SbNgcllmdD4uSBckxNr2m1pnI/cs2TewSCTlfadPrZbJoC1lGgyBqHhYxrLlPLiJTrCBOcbaO70+lhCWlxXtjTscvcGs4b/VSPz+ZBUtoRqilx3H+3hMWifDFMwi0rFPgDqM17hJ0xKmF8W7aIsZV36hDVd7JugNdXz0Msr/Xl8BJRfV6fbSgDSHh8xbkOoAl2ZoU5sko6CeOQ5QyXJ7SOPdd+ORGoOEEAoCuuhENZZ0lzkdmBRdieGl2hATi4UdF+mea2k63LQcF32w5jy0rX5RGyWO2OG/ngL+tjNCPTto9N+8e3W0IufPRYoNrnjYjwGKIEXx6riVmiu1i8tDqdNGV28nt1RCZ4e1OGQWmiLGrfiKgra8YH23tTyrAeFjlAGbdOE7JP79A7pw9lw9Y6mcTp4cUGl5MlO38Tf3njIC2fbQ6Pw+t9RjhvAw/yFUkRie5EXaeTzmS3oUsr77HIVF+5KAHXBf7iNfaY8gj7Au3j+kIEVJU9ZZyKnGu+gnlQGslEfogRea5fWrhGyRYNTerhs2zNZTOFd6hEG/UgFaUzhcFA87gKAwcUUz3nNaxY+vOJBlaP8IX18ahBEKqxnJSCZ9TpDPi4/FqSMXqUQZ+8B8y8pNmhn1/mInBNHvcFjgx7v2+yFeLgcXcwaaoklzh96/RwQoiFcorou0vg7eZij/iPGnblYVW0C9v2YcgFDWD5swqzjgTApXPkfHLAVGJPNWf7BGAUrmp3FRsgerPIAjkSoRAC3zdkVtlAzLhVr8XZe9BmNfnRECNmFb25FWo026r0gZQDCttmLV8hhBcNsZyq6HgK9Tq6vJZrzwLRg3A3V5IKXITzjDKKIAfC1+3XyPGhi47UQW7ybXgHyfqVFsRL9ETEaJd1yhzPI0fMZ1ginz3IvH3IM7FYP1WAOpHY8t9Li+1L/vrzxy3hIV39zVjGXPOUx7qekY/Q0BWqr140JHdB8OqT19MC/oDoM2Pyqp088EmaJZKqBEt24aMgOzOFVMQCAC1juER6sTkr2rradEvIiQSf6pfy5GPC32GgLVgpEQtKOaAUpKe8ol5ZROpvzM8vZT05hnWf3VrtpZe9q0xL6YEVNO9Xmw6mDt0kXtyB2DvV7dZxtjaAtvRbxbac07gORA1vBVZyDM5x23K8zPUn9HSyeiwwT4e1IN82m5r1WSGsqtzlK03w+wOSY0OALvRsYUBE/i9oNl8x7HTKRoDiSeZh1iIhw++qoI0Att9ySWqowhwXLsxsU8GgRPpzrcJX3lIiCnrSeRP04QDLqerbgTkt9GOnjmu5AgG2ayOLOpdGN1pcFfr9pb0/cjsCvcVJS24UO74BmlYUQONWNmjbiBYAKNKuLuAviPxd/5auT8DQKpZzBpExEubz6jqyTf2YiHStkMP7OTnXmVfszpWf5awyyDWsCh/JtrzS9QKFXoNFIJaDekrsFUOimj4FDC/k36PwipBmvdUNThI0mIedCCWPRTVIgn2/hcdRkKYl6lPKAsKvzVgTo53Rp8n4ScSxwoR0lrrYbqoot3giUoMvMIDg8CL/rm5u7SqiFVZJx5KNwtx6rWhuZV9pH9OxlXZ8q9y/QRzCpaYIvSgkDgDHnexoXTpGVItEeu0hk53rn62/5D43uZTiG5zL9P/7dCW8YUxPWmUksW3rWBMrogmDkR93ed7qtypSWKr72t7joOAxNLUaeozGze/mnzovDNBP7nZQgkpd7LZeefrx+0mOarMCaqg6ryOU3PP/JuWG7zLibuuZkVVO3w3fDBCZFmNqQtvn4PpYuZnYgAm+Rpgj1RPax08EbE602y4CrK+uA8aRoW2sltmqAFvT8M5lG1X9W4nXHlx6YHDW2daS9w2l+2I8yjfujLQbm+L+agXkIItrrcWhnBAEhnUGrDpiV8PsW0QiHK5/mo6IgIrjQReJVK8+ivTpkZ3exw7dMZCj047/nkhoq4rXdG0rREGhd6yvfkK8mv7faaIybT6wGRgfFPrfZR+M1YrTDHcULjTBH/aCGGiCNw0DBxOu1i5KAS0PGXeDi8ZfuA9rKOsuhE3JHxp6PqGh+cbH5BSKcduMYdU/4cq9RVUdU8VQaSAQGTCq/xQC3UDDun0D7FbFdRdGM5Brl8Q3zqhoUzHSr53FdSLcmlIlKlLKsc9OTavnUDL3SPrOtNw7C14UFshL8DA9yg2kL/IlIxksO8VOfjm0OFg1vZW9wo1eab9zjLs9vHEY6vB4Mr9wSFQn0qcWKCagSGcmu/Naixi96IhwNfMgj/xt6yxDXyRuijAaLCgjzHWTNSW4LUU/V/K+gr3+QHTlbFocF9DE7BuLBb4WzyBI/JNLU48ifzXiapevcEpdGbS3Uegmq/rCITF6wjE2NosEEN9ZtA7FGDu0CIPWDsqdbswqdrLjTUb85030R/8r4I0k1U14+TRwZCHfw3FbGQcoo5y8/1EEctRxJaQ3ESXEdv7VPCVDjqs7S9s6xTwVosDnLSYZg1kpbXiw9143GVy77pBQXhd5lz4lh3BNsjTsKWMnCyfoMZd4/NwY3FXjwtdZxSXMjvLo6WbXixy61SdnKuyGEl1JqXFkkh2j99u0iDIDB8RknOetO0q4UhJ6x3XNGsGUrOOSEuMOsegPY7MM2M3xaRzuyExpUaaqydL7KcUK0r+05CshD0dTVzaEFSRoXBUzCCjy57FrS/BKKiVakJtW5mm+p47Dyi7Kx+YMepJFnyli6BlcAU6TaSpwDAVz8xa+sXRJzUEE+TrfGWzuJ+A+7wnqc+OcXJ43ZOhpb6LAN5f/37SgfePRqE989ebcP3IFZ7C8cf10Z/lomwkFRHU5jXpIqkXq7R3eybk+WeWkWA18kBqcMm4gpuKtMHS9v5XkV9cCre2M88qNiGBTIB+vl2i2ucYnInVU+Wp+M/xZBK3luF1PNE3MbkO17JUoaQW5jyw/Eg09xFmr0lw6onRfD67tG1YU2seHTba2OzJSx/FMTVYoVaL2XBLn0U1Bqb4feLiJD88DgxUojK1PRPW08u5jm8EGiDGEGWyoaYM152sBLdbzjbffXMZ5dijV+wVGvBLm9ZcVkuCFS14cQhj8KNu+JJ0HdJMM0ldVL42CHXZvep+5ERbY8Bwy9sLkWCONDssvo1lYewRc18bzi7kHentW10X1adY633jdWdZ+MLzdiwM/iAxFaqGmEn0IQu27FWy9iKMlnm7VpvJLWpScEdpjh7aeghuJ1G72hT2QUvSo1Otgt2vqdQRaBKrh5NkZFQWlFDeEmJ0kmjnv+QotnTPlJxqmZlA+Y4igp9L/txIBWK1gc6PV+T7OdQ7UxOs6AYk4nfXMUhVWTcmsHNhvuQ1mIhZrzJ/z2Eitz5y/S2ruVBpCzb1isP5Jg3XIy4Z6PbfgVXdcPe2DoFJ7jijeNFFjrr2C9MOE3iI7TrJo7quGrpPu7aFOcnpxx3ubwQYbpzd3ryXNJJYnVKMc6hBxQmLoIKbyDOx2XyjSuPY3HnyYm9lkyi/UCNCJ1PktSyqMD6R4QhQ9aV7LcfpKt30ZV/y2zbWNXTCwNFJ7msYsdKI4dMdVHsZ6JEGhFd49OJS0GNV5g0XSTmraAq89uAiYaMN4aQW/7Sl/GqF76ItJAZ1Yt7wCNpjsXMg1o4NAq33YfHlxyt/EJaPVDFhawGhSeOq2FLkkeIh1rshv2av70s26A0H/na4gKbJf88CJf0U4bUWqK3GYKm8Y7NrVSAYGpN1U7YygH7cF3ICQ83v5VCy61VHAWn+OGYQHkwWmPcDcZwjE/86RZQMGW9i3n9I12GFHKAPHJJ8OMnLj5eM+mqzbfaHimXLjaSA23TUrUjsYRFE74vO7yMwEfTjrv39bxHCCt4WHwMzKa1t2npYnvizARl/BAB6gSgSNBAcbm+LIGJioo6EbE4WgEIT9FIvykIOfmFozXvNNl5YOo1LCdxFonRo6Tsuz0zlm07n5qHCguuBR1MAhgmp0ItW1rGNC5T4rK4PDbU6OW3uCOx8vxv3cdgrG7ibQE+eZUiLR0ZZwmkwHg31RismW/osID+t6kf7o/iKc+c7eTmQ24NClzgP/miOEeCfMcuoWDvF1LTmJJjyNyhE8ivBLIUf8Fbxk+Siyd5yJgmdRTrEPYaxa9AnMauDgttloRgfLOdt4QF2FCPboXDWHjtXZat8sC840OJdRpmtMYWkwE8xKazggsd47x/2a4KYuuDsqt9T+RsFCeJur9nfKeAGIuYZ/CboaD/fHVkWnPDSZ1cTte55o20AjPkuc50IahngTMdY9/9k3CwH3HHBtkO40UuczPlYEH3LBkJPVmTJ9TX6Am6WcSFg6rjm8SRIJVATxRyEEilv/mWgWHf+w1BXxAUCl0Qj7weRGAhTmdKwulaoO6rZ/IOTdCamzJezuQdCn/EQzWKFTy4H2jIWdxY2+MuCZNYZ2ndh73wimKVES9D+EDI6G38Ulkz3b2KWSSFxn7M2xOzdgMia90ORoNg7Si3ylKTWtNnQgYPSqU1LWNQhAwfLE+UV+dQgrzdYz+TbT/NYdqkX4M1eU2Kgq2VwnLXqnLhypYFnEu51vWeQMBh113EIrqj177adVANsDbzKmOjOL9Nzt2iOcicYdpyvLUrjz0AlxFQGIiJExsfrooaweU0QZCAZ6zubf54Axv6Seoes9aAA0suUBqB/gL5f+Vq8i+dPgWgvqhq4n0VCuPFR+YmWLc6QlQOl3ZrvduhoeQf4LA9pXSKMvfzlgvdLstESd2USkmIqwyR7P945aBy6aPYrqYdp9+nRd6Sby4GFiTUW8JbXgiE8mpF+6PCbvnvRZ66nVkQjIYmcF2l1l0TKf40ifHwcek+lqnWBtZoGeH5dqcd+Zgh+Unyjlag/lyQmTKbsr69uyEF+QMoPAWn/W8Wfk3LPEm6lP4i2bWH6xy/J9YiBPa1Jx1+RIVFxm+WVtMbdQLAeTQu39Yne/6gIDmVwTtZ6PedDxPsJzUwkU1hQUNaw1ymEMZSBCzMtEhKJ/zH8xBevHIuUQutO4Lx6XQj3gLB3OfX5xKT7xyCmP+h73+x6Y2sSv1O3o49v1Kh3ykwyRbbToJUx2+QhMiqR0pFDhd1wARQ18aSNG3hhiSoPLIetzDWCYe9VaMQ7rDDahIJUnySifwNmWYSHcNNX7Z1vPq0OhxdxhdOX3+wakSHDqnEbvaEapN338zKT/uEuSpm8ALpXgYKXj3OjKtBQuVw9lF4fPDnVOKy+M8cBqlFRvtX89WdTJulsJVwX4DaPNAmUNLc7TpiV3BTqaZDsArL+yH21xu1IN6KgqXJ7f6N4YVrBYommUwEOI12SH+ccz9g8qxq75XQur6nIWvn7kYyxW9LjZJGFc/yJ3w13niSG+1CGvw1/Jal2ieqslB9tgpQl1vXt8hwX6XaPj546LCoe4v1pAr41FyM69EK7rltLlXxJD81f9lSCsRh0adSqS3KRoUScAOxlf+W5hfqdtQenkESi7s2Ynoz83WrrJ0ekCnd5FmByu5Uf++SbVLuCjvJyFwGsmdg20nOsMdblmaWc1EFf8KOBiwtL0Q8GbJlfRsAzk+JJPkmrzdIlVRmud0T21TrqK9MamZZgJczrdX0HVTzxqDa1CZtqvX9d9p5Qn8SJ3clnjt7fJtzYy56XSikQnmQPCfdJwsrQDW7Fh4bFJSOjzDpXepl3TeymzSKy2eN9BrhlvpbYM0K/wnUqDJdD1MP9vkDglqNEUmD+EPAw12E1MQxDbFP4mM1DQ+Y0vTVtECiFvueywtSKX8om00XzkRdlH9mYGeJSChHf2Es7eOS2Q7T4Pa9QpmL7KKufhslwJedmpOOkp2zQS4+qYUNo5TsUmyEZ8gfjs2HIq23/hvu12W/EOd2t1QDJbyLDvHUo7SupBRLnd6ZmWexowyWIzBAoLYtswuOuHGyvUNGWunMs61InMtBMn41lqJhz8yMRR5P7rh8SeeonezDZ+9YTsFoDwqwFdrCauY7CbgpIK356cqQ4v5qqVVm3adpX4SJjEm+qjXK7D4x+/XSH9KysPYWrDIbpAj6f1hafRxz1oCRYnjcJqFfirHfK7Vss7b8h7ozDnECvPpTcGLhNmbNJaKjPAH+AoJSwThqzyT2m+ydUzDJzE6OYK65jb/F8Oo3OLJK1eSZv+40+25Mgvzom32v5LMmWZShOawDd4PtPTgONHWDfWUywQU1GpiWMU5qtBrCUXJLKQT+kvu6Q2cz41GwthiMfwWph6ueBbK7RxWpjwWGLlDjDX3BQ8Wnk9tKBTVBR9ZkbqRCaV/XMzlyn4xuDqjEV33slvU5ZeislN86wSBaYXzWbyOPntgf4jjHVGdrdSXRj47Uf/ahIUjzxpE/jRmDCwC1ERCr3q7ZVLE+wrWVoJj1PsX/Cap2E8pxwfFw6xvoG8Y+2h8N3RYP+saWgeG46CSOe+RWKsgXmIGd9Q5ikqjMMdyWKKhBjTzPUxEq1G1WpHF1JihXsUxIMJry0RQgJcp1r3XWEv4gpTeI0nOsLucZglDzxNg80jf0fwndd7qxQuqUb/bR+ah7g+rccyRrTq4mNWqIBxwG6MIulf7kvFhGjVoiS57xZ8QVD9UcUMPE8RAW/YYW+VEULWQvN6VLAvrUuaq9F6naNxwhgW0uMzMHbo4EK5Jbgv59tJ4hwHaXa6jznWF1K2zGD/u9z+IDewsguFN5BHSEvvvL84NBNVRZ9Gd7bJvOjwdRTRVQySMndktnrIEqZhYOJWyVooHgXNYl0wsJ+xF9UdivXvOrmvheIg2uVd/9rScc0bt6N0XOc/uZOZ9XLynUmr8HUYQBQcvehris5nE6l8kKy7HpdiQn8iIYG22J84GaXEcyvmQSVjdVRymyixa9qgULQObLUevJ14NjGvibm9UrnCGFCqtmOSuZZGGo1PeY/p2U1xc3iHpBhy3MbDM8MecDhHrq9qjj7JLfDU9wZ2cHPe/pYvp3PSZ2fZJB6vWu8/FWxbLzIhuLMNtxtbmdca5zux2WVkvLlnDU+YE2B+3Twn/LVKvX2Rrs7jrzoDrm05YSFhPmXwT47wr4EwD7LTfmmt+cUYqy6S/nglVRFU3miWbUsXOqaV6xUfiA8sH4HZts1VlPe4ncXeN0DdQMs4UPFJ6gr6N0uY0KHKgMkOmV7yPSw9PQksyVUOXxrbKbmTbro2VNkv9wZYMDQw1jzx1DdJPnMJdGxzZmofZ/Yl5kB14Y3C5dhJi13ILYyMRoVz3eTCUtDcShKDj4rhANUNQxkfTJOTyiyqhv7MIXL2WCE7byvAbiA/MdjrtyR01RgFCSP9mMULDbXdS1vO3fTVeTfCQOw5Y5nr/fe15M7MNIet76rihw0TZiAStsRWOOoLBFP7Id13DtxZTDBXL4KMQ9mAX/j8IjlmZZ0txCLeaVaA00PF34+qutMRI6yrxOr9b/FL0TnfMgP8R8ITKvAGPEbbbz5G/muRDFDFBAWQpXtqZQGznk1Ho7uIKgPv3Z7WMBfa0ePGWyzhTPrnhoPSoqVDeGjiYRDb/vrD9TmpQTgPQ4xWE0ZstKPZIsESW0NnX3IayM95lYx+OSSKD657RJTQpu4YfjkcSPJ6CeA3sPOyOqiMViqRhy1PpuGpFV98HtUpw1hIZNCAh5oal7Qwok5BcKpkH7HCNCgfL0A2kzS5A3MHbytFgn+3xbkFQ6KOGFkRsh6gYT9GOTuokSW82NpBVQZhWv8LCKTCPMV8FxCASitRBUjxmtVumqu2Bsfj1ELLu9fYNF32phtys5ZTbahQJBacLWOYyCTbRNDgDdeitKsPKE86Su27n0Kp/NAItz1WMQigfCyB92pgQ9S3zw8xbHHGaE3YVCuFaaEou1wugCL/LqiYha1Rp6Al9FYMeFRkPw0/Fxx1cBA+RucdG2bQmAbjr3T7nivVKSNGPTZVuzbB26oKggG4wPT8zRG9e1b5JxKU0dY0LZ6GffA4XiZX5hScUknPgTUjI1k975kiZX8LZe8611Lw1R93ShPStUzceKi2xf7/m5xoAhcsK0KGi1iOhoMus8u9wO51WJZ/ZAX1sUa7Qv3m4DR53+ZhK3DrwOd2QzkdyrpufMEkk8r6yT3QCyXv9s4dC2sEO4KyqQfR4FBFqBEUa8qwKwWda5Xv/pdL96nJqGgHV5nAR8l1Uygg7bRDoCTR4jDWF6BcnG6+OUFHBK+e/KGwNmHnbPOK4JHXens+rnZmXD9pO8qeIZh1u6r4jL1i+w9znFVOnBvbh289GFsff/g8j3dhAt0DCgfY35Fp89xhzGJozU3pEPoJmg6ItYt+uSdqCDv4qxTY6QueAjTtOOtatAcTpA8M6Zqevp/CsPnQmW0yexue8Lu2Jk92/SXeffAjBBBww3GDhN9v9dXRnDdSTWixMixkDVHRuAK1c9Fh1MeBKTqbUQKPKb1YX0cc+iD01/c7pJ7gaWviDCPq4cgF32eL8BDIO0vdKUZ6vOcUXmaxPZv2KiufApWWDtqFwzQFbuubC3UN0D1vZOIJlobem6sB+R2AdCvA83z863cKSRZ4Z1M8jGDu6xlf/AM6lVXXsAsfZEm/pjH8omNul3k7lG4mwaTvBXUAlGcds2gA1XfXPThpvECTNrDCawb9WO4271VaFXR/10kylErUKBQjoo7IZvFJ02mp+wN5JG0yii0n/klWChjMH3igi+mgxMPxvXqmd2wUfSRAqF9vpbQzPzzsjyaJVRsHzBF2RyTBn29ZmiENR05FdBKdpYD8zEw85qN59qjV5m2weBaCd7cSG+Y1ZWxYetZyk4u23F72KWvGzl7Jxc4ISf/Cjw7F31d6tOYfXtfSFx4qLHEJtrKQ98YCSBpLs6hv176Q/ODS5e/+0jCmRNBjh9dEOUIpXDbcrAzb5/9NdRllhCSwiwFfjokPqyppwaetEsQv1Y2am5uHuDNRUtl14JMF814J2mQZZrLQTAiT7RwvbV2btoMb0k4p0fhBfl+bxfdPpUM2fOcQwqxxCH+hwRu8gneE6GctuAUnHe1BpCQ3vkmYUZNSxw9NPyqzrchAZRgwVF6AL7a9q3cFXYFWA1UM/81GP4T//QKd2hPgImxWWAYo8xiZ+5nYB6mhR9z5Cmld8pII561uKGDUt/ng3F5Por8HcRXTF+Sgmqq8bYgLEmahC/9soOyY0l+ms+QupBn5pead8+TDsQjRISgZKpZ6oz6c1LoKBVShn9PmiAypoJMb8wE4Ovor3DpgxNRsVxiUxQqgpCqPfs3oiPdCb48ARU8v05JuCWuEcsJ0/p2b3cP6+4x1qvCQt76g0FyfTbh9psUkFSSt5YA1aUX7rqG0ME8mHas7XlNsPGCMrNsV6TN+LAbGwfO8S/wiUdyh0XD4xA1gnM8fCY3MlCsaylmUdw6qWhb9y85LTs4mwXbjSyW3HC97+xtTrukIJKa8VZpLGQ3tCw4a6yiPu3Jd9xtSsH+HTQVZZgJyYG1stXUDq3ymuEsCTPghaT9ee9BPSU+KrVIhQvcBJoJa0q22b5X/xHTmSVDxSCZ5AgERWRq/8gSlIjkNZQngPO1BzGrOx26eaLSEcZL3hjoWCWI3EwrDecmB18IDADwS2fuMyj2kNtWRhA/zqL5GiAgnTZ3X8X86PyOQpOyAl49urCo36dN3Au8uPlCQukC3UJgXhY62g8c0RaY5N2RuEz59XBoN2lOYTfelCg34xyd8CxZgpvMTYgBwXfv0ZP/vh0UR000DG9dg/G+nj9hs268GnqfTtjoXl1RMuC+sYuDIn54KXL/sPrTLYgFeorXeUs8Q8PncfFmnImGEYKQkm5z7cAWLAJzHdvuVXHcGvPzunHdI3umHnDR2RLcD00tr8x7kS9V+ZvAqsjumsle640aa83lUPe1uMPpPCFscRVlaSpcOWglD46TA4bsvM9Q+O53A/cRJuABrbBLKdVgIwsjm3Xuswn1faldXqZux1t7h0wvVHQ1ZvrzA0NtbT5rH2SiWDZ0rpmoy78i09zn8LpVVTj8gfGdE24R4/7fxZxGHSj1XJxhobCsUPO8ErlCoHCEBoCDSrwUecoFS7OYdJ8Z1he6kjE05tdybJfskNkxxF3+tIt2DRiYE/s1MOGBjg9B8OvKNGesi9DJmVxpCWzjrdvqHk7hA/Lr+zX1mvOkz0egWEP+oRKw9DbaXVqqJBDOnDYCpZnauA1+pq4SEpWbxUtKBQrzYopxa2NKGMSEpsguyUUf2yg+I549HEbddiDOVLuv/MBcF1nw3o2BL/f84GKwHT2zObE4ooFJ42KlAgj+2iYKxhdc2JKZhIPfkW4JW6JR8UGl5R9EtGSuRwEcV6hsSACXazmjL9ptrTCfApjZOO7MFi6GHxAgYhkY7/E/n76hbYZvjXpJt01bQ9JST5GyyfRJ5Pyy/aI317VNkZJsVka3GxbM6q9t8B+cPQqqlqeneuNcmE/pUBScjUTYJWtlc22THRoDJH9ZGy7nPzNWHWG3ekV52WXeA3y4ghN49xESPo4zbzW+S7IdEkgNM9h3K0zvoymt5mPlmSoHrJ57rsjnKGFojjFIyC1rfNGR9IDm4wy8hik2ZN0dre3xN6GSy+PzwNVhClnVgKn68miv6ZbvKAWB87ZvbZ8F2Om5T3M0eH1EhQ9lOXAcM/WmAdKURsrEec9YeXOXHdMq8RdBxS1RRwPmwnbguUHZxHSdSTJU6AwYr2afP0eXERRVXOzxnYDDzCTw5gQAuW1LRwwSH5kvpQqjH4RJaE4uMZsQIxg7VhiBubJwPVML2nIp+poWtbHbTAr2s3dqvikYemn59xEQs/mmFXE43zDiZhtWjV72iIvQFwoluegVmRMgGH+hJ3dUJvv62VB3HFThVqGak/LjQx74pIhEry89hd0DueyOB5fEaJ9DfDi0gJtJpvMthXSKWdxYfFxmrlfMhXF51mFO9p1qIZiSdLxcdEVRmzGzenye9YqygqJHZ7EZsD6/LCl7e1KYSdPt1MjMm0B/bF1NzkaJHmTezzGOI9BMisBTRfGn/mhoN/VTaE+vDLc3F/pL4KfslIJrB1Cmqa1tDtLMaKRm7FcuUVzd6aQJDNiGHKEv3BrnbM1tMcvbBUtZClCuG40tpD0IY1WwfHYi10qGjJHl5BGi069WdID2jIq/NewB4q7lzMHKW4cqwjFYe18j5Vyhrt/U0XgG5gFOm0+Yuw9b+sTbNbUEkaY6i7BvOasrW1yy2hWsfbk7ra5B5KRglsEkGcGhZ3ezGugqO7i3blZonczOuXf4dgRh+mu+0PcWNBtzvOCcfG0COMFXnGYjbXK3Avl7pcbEH1w7gjToMtvbYm0HGUyfb4PwZDyFVFF93poCW+gmta5/GrxUWdOtKit7l15NulZcKHr9X7V2yjl3FOyyhvMLdr4qsz21GgPmAGkaHWs4lHK2G5qhhxG3jlXJcP/GDJNSQ0lFppbDqMYoBHTXci/D90+PlDrbdB44e7j8RITThyW4xN1yq/J+IiPb9C9yvXqGEzQURY7jVT6qP1rW29XhD9cWVBKQ8ZMdcTXAdmUOYHhOT8QadE/Sk3nukI6gDu1Lnzu7kxqqE/MtF8HSukV9TCY4wSvVCMhOxKXbXKTMQAyDRR2ECR/6arUwmykmmkFShrUs6WmRIShON56xeLJYccmkdjlZSMsmQnEAiqpNiWSDfRunInXpd1CDL06RFQ6yFYwkmaey5Q6U1rOxK1Rgrho9iex3PkdZ+jCfN34jwhVT51YQzc7biKa9zdCWKiVafKOannVxtEhD2fPWf+VjSSrMreq1Q9Z7um+Y4YM76kgYQMgcBhcyrh51gcC72CX5fYo7053vZxXYqUhuim68krXevoiSsJlnopcn7iIckSnTMNWUNyTOh9C0A1TNyHTx13ip3kSRtcL7pe2qYHLZwCU7UXVlqyyVM5F1Nxzkz1VdmFsdQrbWKxFtZCuBKc0ertJGoK1mBwNVXeQh2QgX8EY5NYz7EeufWkG73SuOvxoiDqkLYerIxkaW7kdj/j5v+cnLoz3SLAla+Mxu8FD66SOehTTyqFvWKgyJIZp8qkQpM6AVhj9MTtig4QQ7YGaN4Zc8dHvIT9QHECSOK/1tz24imDfELJ+JDJRSBJpJRHkp6Zmaujsa4Khz2SQ8XMgG94Npjqd2sngvO8ZVl/vS5orrQdEqee1QYw3ZyCHrvT7rHXOuGcuVpcSQw4JNMKaHUgbn1kUy1tZE2mXWy7sbx2/E4P8aSLvp/3JI8C31dMeK19W5FmmCBN9saXvxzlW/kUIGrUX1q7J4ejHx4Vi7yBfezOF0lr+Ju/2RCsYNSuN+PZbYLTuld1CRNq149H68Kvi1HZzbHVCyj8ELvG/D/CL0GQG5htP/UUsRZNt+//AZERAFPbfHuUJcvHDLwnaki1IQF985OmjKqIRsITzrKeSoAGHE3BQztA5GGkW/bYAUTlN8/yYoyzy/huI1kY5Nq1CMi/EZKtzaq5XXNlXIZMBsiUueM1VCVkOHoBXOl2twHaiVt2T2tE3WIwUvXkBnHZ+4glTs3lltoFe9BF1G+jwMhNdzbhjjzSZ9mXYi6/YmQ2m/Q06PjUBnTGAqdfD/lhYB/elN6lZagtXziUuA6PIY7S94OQi3kXWSMrWIWHReXjhBWSps5EtvqP42FZoG4WH4pGMOKRX1AZ7V+9q5icMVr51DKUcJZ9pZwL9DCJp/OToJ8JJGhle9D9CsgGdBtO56Bu05xDxHhCyufZmF0/qMi4+rv7x8fES1rqb5incHmWpSXktzAvpTBcLxYWlG7lUZg6DiUWEMB3LxYNvlmZS3vIKFOPcrvCPAECnVG8GprLCEeX0rlemTZpKP+l6QrmCNNcw3kOnhDYheCVtDz/WF1f2Z/qI48FEyi5Yqt4U5IsU+dEuenASDCRwPGc3uk5zui+qQ7Yyfr2hbCDzEAvXKshaSEgkPjdwOUj+3JwSyF6XbMSFO2iQAAn1h4w9I3DhXrFAfPXGn742ranTcJtCVsHDR1bzArJZHeTgSltIhmitb8BQmAvUpt4KmfhpB+5YP6CbN0OcbVaDV0BuvuuKs/gxEP3V8UV2bj+nrPeId7n383XpcBSsmyeE8Rlcv70DV4BvNe6qW0H1LscS6qxUx/fb4N6yU02fl4yRHQth3ZtsrouZa+oKkjg4YvfDShSskYJCFDQH1+hoqOup8CibiabpYIfpXD0yVKn6IrSoXKmQNOk1NG9/HyVqxx97wDyYlGUPI4VQNHKWtAm/bKNsm/ajn4Gipw8hCW5UgPSHofrSqzBlg0T2+kSM0F4l3RGORm263Uae+j8FqWqzr92qGObS8RGZ3Hp1S8AY0ILLBTs+z3mNRX/zYq2CVicJXVjkuKHk7+6EOY9CpVTV5JgZApECLFby4fZS1JE0Xw6JM7hoWWRyEF8/4MgDsb3/OQ8JPtvloBNUGl02dOSRE3+1PtPAdt9ArR71wqEsjryYTQ7jptQu6bF56SOK3oYhdkNcTVgBc7CrVw2oI27Hnv04IpEMRtRJi429+vSx0Hbi7aHD2RtkO6FxfT8OU/pN5nLmNv5ltNy95ATadSKle0MMblZZxs8JanrSTeJ05+9e84qr/GNojXowTUd50Cb6WYggZ4JhLg5Wl1cnUsDgGSFFZgUoau89mvO8p9wBR0nL6ok0EBIT8W/8Y1Q6uIyAhqrvsfwpi5I5rrH6qqTEEqvwguUudjnIdHq/wgOgH5fqQ7JTGcZ7VWmqyYcOkav/1dRiV8ljrqNdpBBAa/Xz8QcHLQWtWA+0GYpjet8GMgf/0DHEqLqmQh4PVzCdVxagVAnncPIWEMelUNC+buzcWwjiNxGlh7ut2W8D/g4drqlWhBW5e+hDjKsjSmwbKO6K7KNsZUmxtVj/PW2uGiKdpAqWOtsOq+wRUNNwCjPMoRaFROtWbeLk81Kc9eEYo/29PJUPfRgBKO/g58arMsDKZZPT6+XdmQfwEfflKflUBAb4Usr0Ay9QCXu2E4We4+PJo9Id5/NQLTLJNwkgrcSAocZOGgLQbinNjdAhyC40qc6IcpTqlTt3jKW5R6gLsClLkgZR6Sp1TtNvyL2PEqB0XOPUdTc0TmCkG24F6Emlkt7KghauhNmjggGsAA7cvcv/Nmlg1o6Wb3Q1rChbNd3u85tRQpStel4aq1mgaaGhFCcm4F/rAZ6SKmkCgAck/FIEGbSTgytlNMDmLmvnFk4Gqgh6r/b3MKZnEzrYul+9EQ4mvvAeYYczpqeSHTakOPmZV4dJ2twSQSwLR3wwLcGsZGIIpegaRq1lvqAU9W60nBLBxNEmco2mJKOAAdc5yaixdQzqNT9iWGTtUQDFlNuxy6C+mzInAJICF74By2oMl200MCozNo1Fr5lQ9bjocFBkJ7l/KKMBAuWcnC02s2GDMPyKO6yk2yHq20ZQ/PputDAZJTH2fD+DnaUBiQgILNel1vaebJP7zBXvgBbjWYiluYzyqjaVCzoJaR3pnp2uRYHqRGya2gn6VtNQ9qwP23uOC6XvPTYJH10CnTZoGE0weUABlmLDma3rT1zrWR2NBaORLoYSpjSV9tG1N4OQJtutRU8ROvo0q/duY5KPgmcNYpppsguTNEpwazRrgUGMxFELWNjzM7VVszhTLatV7zzPVjd0e/sF5j8sSKy3tAIeLnEtBxDHLo0aphJUb+CN99QQB5wWuHr2qzWv8VgvdrnG7x4uZUnANSq4f7VMvHCGJZ5P5jE6kGaktlFJE3JvsupwlYzDwqlR1oXKLwCIg/Dt0grGJdLwuk7Tr9a+2XvpFlTzHtHr1RhjlrocxtaIl+v2Xzb+ETP/uxfrI0AO8lQ0fK8oL8Ppqpv6c8H8cIsXohNGmAabpuh4jmO2JZOEvkdyFSiaa2NtZDy4iwlEk2Gan7BFDaUiqlqixyH+KQdojdBPrtlbGensUsXFN7SYburb0FFuezPvBesiApxtFKtbH1isYkMAgvoCiPgOD7tmKnI1fYQfZa0ZdY4e0ZqzuEO+VsqIM3Bz2IciCn6oU5vpw3c5LaJPaHfkEiIwDukfdlcS2jTi2yN7gMgqyBkfLN1c0F+FSFemSkqLpAffIBYbS1jyIjgqAPAtZ/17/DuDJrkH6hW2GHrf2iiRXiLbAZREGD2lXeCmhl0xRWJrE80Dq1rA+7E+bjdjRDXC+FRR+/aaXWKWcOg8nCgKGcRnHr4gJT/16flmReFLJg/7k/va8ro/bdiUgjeaJrqQorpLpHOdpylGzWmlms9DmmNOwhm/I/WJM7S8cKhtKXJQ53qG3pf7M/84u5gRcpx86T2fvRPV7d8eYphhc4Kn43eAlgEu5pYoWzcX+mZGj815moGPndMGd8oPCzq9BLpzBpa00dVOq+OhEP8GcKTUybeyZt9bdFqTZn5nxE0NkPwND4pxoMzKUhoTulLhVBG3XZjioBWZFi7oAH1R0FtDno1UolMxIMwViolmpx0WDg5se62LWPdoaVa57aoThdyg9jmcSkyKgDOyFjib9MlYF8F45xDStwCYAskJPfi+5I6eay9b7DZl5D7DI55LxTGavXbYErf2e66lA5XzJf9YgoW1zieG1ZE5zbnG11h2Isn3ELqBxMxClT7R4aBdabUybciTca3R31aqbD7hPE6luwyLGO1Lrwh7ZKpOktvIX6j+D1SApKHP8+zgooSMKkF+ArMdYqfan38Q/v3s+a0JS5+Ta/ro4AXorh1YRGX0bVR7Dirge/m6r093rRtBwdwkrg+EmHv+24/UepDqqXsLLvCphvz7Fqgzc6H6jXGh7oxdvmvrdyRx6T5bPeiKBc4KiasnnAJ+B4Z4cTF7CKQfyjwuk1abcUR3d5wSBYbezqSyArKAJ2Q3VYDEi3GPEufNk9uur5wvGI+IQtqwUI0wR2uQ8uUA2/W4DOXIVCI+rb+F7p4uRElrmNdQfkLIHeEy2f8eoK+Q8mCf1ugqNujGn6895Pvqlq/K5olwIhYOkYENnNBGIJVn0mLvEZqknKmGcTsv/arGm6pG7P2TXx+dizZEJ4gE54RXpUer9qQBEGy3Ljm9LOSc7pYbu25O0r49A879dZnYpdsblx06+zczQY9QPgjfrFtes0lC5whUX36li6v+uqmTo1HbXpagoLBm53x2hXx0vJTA5ZN3Glg/79UkxqhMqOTXh8qxsl+ar46FJOWIH04llG88POS2gDjcxWK8bBUdXRg9avA0RMLhJSggAkO8B11aZv/5a4XzHXhlCJsnFs4/7UdJmmYB/RnusNK+d4xmFLzVmIMWtx5GU609fro+LCig82+DtPFAZ+2GFGLXLjzo0Uuz8d3hsVqRtTqHF7i9aVkZ5xxIvumAnZjTxEA6tx/R+1UAQw9S3T4t2puosORqeqvuvtqI1w7nVuprGBsnCpgjSC7zJKx8WP1y+SFAB6pJAswr1xpyh9gFR6JqNr6d59FOLHMNo/AI44ppqoX7zpmcbY9gMMKlilspWOSWxklrTSp5iE/Asfkz7eKbsS8S4adgjFQD/MnbhFrypn8RWPXXj0BVBBZNulC5/85rhT3iocoljHum6U4mPuCwrK5QwHlMzMzvJlIhqUDyou36aSq5ngjjGPfxK+XasD5hW6xp18OFv4V1sAAt3FuJLZRAYTHFak5aCWlniMUn7+EF2S4G5h/Po2xvPUAE23bLVh5QggrnbayCjRo6E+EItaBiTShbDOd8D1P+5FPSZie0462W+CKImQ3JKq3/lYJCt7VQ0Yy9POuNJo1JyWzUHaEgT1Q64fj2QgR7hLiURN/+FXVKMGZRFkTK/1kr9GyBlUk3QpFxVdM29AANJMC6RlY1qjC062Sp0EnlFijB8oV4Llrn6Jg9Lnb8hQ6dLIkAfOs2ZqX22dNxGd5hC81JXTGQIif7nQJcN1d4s7kOO/l8GCRFfr4N87NB4RWj7H/qYeqrVJu1W1NvAlFBlBZlBp2Uilzgr84DlS3FFBlJcSe1VmWwOJYkTy64RLHtB0qOXEaPzx1DqKsN8pjYR8xsH/8xU5lXjuVm4w42ytFugyGQnnMCDIAAEd8TrkvnWgMTs2Kcnwk/ZNnRhiOGjHTuJflJj+QBJoKwwmOnXNmT68EioQ1TCSvC+/Gb9SssBrLL/NBQN36Vph/qQot9+mMsVPbAgMrZo0BUUpMoyV1Fz+foTmmdsw9FILTfNQPcuAoM7cCaSD1hmKgpI/FJDNiHzs2rUTA2CVUC5xe+Yy+WZZQzeYYOCPCfdH66Ch4EBcokfVHS3cpjzmjI5OkjIA+sO6qYwGaJ7EhSXlDavl+YnNsp4WxwxZ/Np1dUK43mnbBJ5BAO7qVvfA13ntTnBKVUt4p7lxqmQMXeGk9FL6oAhHbT0GYXrLbrCYeeydXAYl+vwpR35RxIwYM2OSU0BhFn9YnTUtAW0VhosCNzMHCaaMlB043m0oIzFxctgUshgkNy6XwNGJtu31k4pPgWVeLaIEDik+r2qhRhz+D4fHfGYEG1c4we3Fuy33DUubWU8svNw04MwgNwp09lIHD2LQGK3M8utpEw8bkIh2K7Q3ACq+cKBAXAqjiFpPM8UdDP8NHAX6EdJoSTnL1RICLfki//tyFzi5SKKCH2f6c07dqOhPeftwd7J6LlpJLxMmo/O5zhLFVwO9oqxAdrg5zc+j025xqbTOGREfPxmwo6zuqgPaNtChi8hqY2v67r9kPdbMV3HbZ9myETomyUz2aEBZM1pZUbFpxZjDS6IYjbBGpbZU/wLvVacNpcS4jlDEknQSF20jBqYU0Dx5kvJcRBj3i7vRpBACg6DG5FqZetqNm6qGdivqrWJfVeykOWrDGx/3MkVZZ+DCZ+694Zd00ijZfHB/FSTxzArA0+rGqYrYAEls1qaM4oWxQP01TFqTbnvbKPoxOIqy46NOKoVgzSKvEkfdAi49OTGeqbt8IvNW7g1dbfSGGK128ysC/FwEcm3/i1lFFX94ciZwIXHe1jy/qTT0/mA81nAL9ngJRWo7pZ4Vnwp77vge2KlXqP2NbBW8/E4GRSzJmkki3gJu6d1tllGa15z/Nl+RkPC4BZQ18UjznOY93eYN6Gk5HvP+5mndVLXS/hMZcTPuw5YZI/wve/BhDuT956d9LO5bDuV+YgXBPxuLQPzy2ahcasXoM3Klh9/6qCvWY2B5d90h3+iMN6cDqbcgWgdToZtcbVOWPO2knHdVS9Z3glJDWdnFn0UJvg7+ODX+WoPsn2ohqqTLD2DI2jb2OaLzP5+WlzupSZEQhPKKAnZvRkV0ZVjhTJeZm3T1q5ZHwS5R0CMlaMxPZzjAmLXFE/YezVgu2ADuhsUq4mmCs95uhKLtMvto9QdE0elvIhi3/edWHWPmnOlBqXlE2Ivz7aRHK/6vlQKbPIjjIlCNX2TPUagdL0wmMzQ1YAWavefpaJRsYnIZK5SahiAyCAXhFqnIDpAeXGd2KEdkHWMlISTcGmccre/BY39zZ+QZwv8qGjZaTZcwLi/mrp727eUaeQDbMCAVRULZEmZh26fW7WbBExGuIFtVKcC73KIFaH2fOvbikF7v0fVXQokSz7J6mOXj+IcV86PScN4drtCzSrinlI9vbGhwvKy3MWoXVqdHpGKeZJw8qBvnMqz2IYWcOec6oTPnv39iTTb3PJqwQCsKy1oYAnzgVs2KVDtvMTr2gRtj2jtVdtIBzqmuXUpQhlIr6ZOjqIzC9TYJHdXxSSdLwdth1S/qsNhABxsjBPxQWRsydMqmoYaguiq685UWaoLTtRlixb2py1S3p3FKJt19tcGVOo5QDNCP1mJJIZD44j6B/glH7/P8AOBbczNoYeb7MMv49CD3F8FLRkszgVzjxMwJv3KCTZrty0xUJ+zyJZY+/HVzrmYemgpIaByyM5IRN/fGL9xIsJW5uygLbZV1TCT9PYhQHzMOC62Qjpnd1R9RMM1q/OuQkygGqBDiYOWsESJErMZnLSjAvvvTDE5xhLTdC+dVpMAn6OpMkQbh4V63eszj26cjQd4yRixMMr2WAcXJwqbEi83hYg1UqxZaq91kOF+zd683tm6ZMmaoHfudzjG7dZKrsw8gUuopqRXzSNs6z5H18n+tULLWLlOigx1O0vZSPBiCLrJtydWSBA01H7Sl/UwZWaunhxY5sFwMchUOJLiNtz4b1NJVJ5FcH3UCIwl2gLw7Lefs98tjVts8jN4WJ4RccQE57OcvPT84EaX/xQK0kznXL47vzgMQf6ckUGR+pC8zmbQ3vYV9IMEuPa0fulqeMo2tkiq3RUk8osoe4dMauSuwGlpUkIC05SZoHofMFaoXMV+HJdEoFdwmxeO3TWQRFGVIXtbUWLGv3/An9fnsA17zTekayKsYoamEcuG2H73Z1J4p//X/xPyeDnqrK4oayx0f+zAHBCBNELvHhW/hArUWkIsqKarSNvWQmudGCk4INeCkWgXJnRLKLw8W/nd7j8NubK0aDzh6KkEMrVk+ZvV5d8GE0vAwWJ1uhjR+TxEJkfqwU3418h/v8IH+4vFU3dqfuLKUC0X79Vck/0yyajqevPqD63cd8y9HrryFjCkih2kdSovOtXxF9/KYFbyKdMGIOaB7swwUEcZlM1k91vJSrmcLPVm7rv6D1tZWyAzoBTMz9iqK4iR24IBjZrF7r1eCiF0j8/hJ+Bg/q5OOhzBTxeuKOP2wMH7k6zIuHZIURKFq8PeZkpG1379HfZk1oczQKaFdRwBfzGfe7Y4hx5QQe/RdetLOuB7W+tvp7eE9v4esnM3Yz1bbSqpxP1S4MGgYVV3q1OPafm4jbgJrBzL9Fn6EurkcamjMSTr4AOt/YSL0EAQGMzqeVLh2Cf1wsjdAlrYvsCGHnI4t2Y+0yva8z+dOhTsHlS943V7YCEuoUZTXGiaZ0uj+yxC3vAhGj7ae8vCe7E5+rANhmq3D5S2ol7vZkm18E2aXZYefZr+VLw6JRtZS9ixH6k+uuCrRtXunxhrtb3dX1nclJcNycuZXhPiMCYaWygc1Ox4bGQaotwjK9ED4FZ1iIflavCgbKECgxc7ZqGfIKfmN4eEOw5SCOY794ig6oUDK4EVeYENFXBQdnbOug5RCWqIl+S82It9UTbgEJdop5nIfeUkEZ6jqy7W0djRFqHjhkvJzG8hoWdaI2yGfcxD74sXP2qT6DiyDXHxcTyZ4VdUyj7l90YL3hMNJe7YcQwd4NgZviCWjBK3nHpivLZ82/xQtz5V5jgPimx7Baadig4DJsNaQIk4kcgb1Fy7sJT/npjahH3h87MuAXjDmB1YscDFGKXq+enYb3Fq9vSnnwbFYWsR5274qy85Pq046FmF8coT6E/3xiGdlugO9DUXsHt2+SbNHlVRm7/H+0EOqWOBR3HE7Y+IVCy+pgCxlMUpsBO3zB93r1GYS+xPpTeVCKF6qbwEFDLfEekDNmcEFTw0WA6Pi0hpYEIHm0R3/crrD7Ulmxnm5fekx/f6MQ5sqKLi5KB3k9hXSwF8mSiBF/5dxZ8iSkcZB4NxeyAOk5bAYAqJoqqb57keNYNUJx7CgBA2/PioWCII+wiLlKZS+OleYQLk5rLWi3Gbp5+qYCfEwfOKcphiVzpgYmw6gL9BC37SiCLwz9su0V1Xky9k2xrp3YhZ69mz+iQG+khntXZPJWv4KbY6XpjrCSwvIsj5kFN5/WuWi+1OVioVzAo/Co5xqB2j2X2Y4eKG+FrlQXfJcbPJhcY4tF/It723wFaGTkPpf9tlPmhOwUDfqTpjA9fN3IuZLYMUaAejaqfJGBlJsQH7OLW0GNzw4fo8dw0QGGo1hzLUciwfccInkBy45I/jwyTbjh/JHnDUdGYHmxViij0pNCYexXuPgPYz7/q4w1EOQsNOMD3cRu3d+dtkRfqQC/SUjpfMIrSJji0gtg5brqh6RQGCv70ZuN354MlrLBVLRQFtQcalaPL8VojaJ4/VurvxLbXzxD48yT4IYqpvuBirrRU7DHiQSsjDC4afr2nX9o6Tqf7CmZMUJbKiKWuuIe4b3UPAsfmSDvTzskaEsi57PvWRHQ0d8lvL1VC3qxVsaa3nQ+T4j3R7MAzEAAAAGNu2beNj27Zt27Zt27Zt27atDtFBrr/8j4cXFDMwRwpy/chS54vtWtwuQiLf5Zmam4CYlRA2QRDlr5qenx1r4fuiyWPsp0CxOL/waefM6Gcz8jqAaxonElVUgIZMFuyPrZJrCzrosGTe+p+mQshcCfwpA02LGmuywZPLznBQqdUoassHQ1WPJOhYLYw3c1dANdvBe3wXbeaYMcJHlbFjmHnE33PRJON4PgNQoQGy5Hi/NflHHVUY42Q1DEeizvw6Oj1fG+MH0p/ByLo002+ecMRXQL3bD6SKHeQcw37ALKcU06vgS5AOvjf3/bZigEML8eAPYDbC4dvdbrkrMCbMR6GKv37uZHjpzqtJkBcNp44XDHmpRtRsjGhuXHMKgQDP2C6gAP883qyfOAzZZo7+8DTMSLuwnM6+J0mFPxHaF20wiSm36nUOlB8CqI5zwq8cDHKm9O97NbCawFoulyERoTO1JVWUw+zGxL7BNvWxDuh5tnpDIFIEdOvlB6sd8JHnT4pjgmQbVprnOysst1z+FxuELolEmj5+AkOI3wCrbrvjqy6ySWAsoXrVi4rYOfrJAoW86gnj3DXWP7SuU4/0LAFcOdakGMGgYgo7yCTytVsO2HJ7Ct73zL9StAJfLG90eadPlCjlWxLigGzp8GDyGWZKdImKHb6e9wz9/ITC0Li25kckJi0PFFNx5ZvfQW8cDnMX/DQzPWFsrt/lXZvg4ez5gVX6LThhrSityI3DARwXDMfYXOfLod33JWob2VHYH9VcIL3ZBTHTyG9bF7/ewZ3oQXrlHpHnPXWXjwb7dKYcrnFdEScI2ZehLF3GjvYdH/am2Ai65LGSc/Txv0ocnBcLjz8/0gAtlygbyCeStBeF0AI4sIYA9zpFu/CQSkROTvjQEgTLg0HlTqoKy6UHANOtuz6WfaJ+SSqpMbjhLVC75gCkRrxvA/Xp6PO2J2o8CsXDZkGvhfrOz23RAv8trRZmgL9sgetXjR2ipoh49Hqy1PA4skiyPFkOnewsxEdN7Luw+MNAPFtvW2wZoVqazZYmlvsuEY8gNtaoz+MT7P4PpkYkgMyrzXWUKmqKsnPyJjOUewIOX8hi7OdpG28/zP430Av2ZSZ7QT9Va5V84VYbCiHG4TLBck6mYC+YAXKQ1HeDK67dE/54o9rmYKShiO7wi+4GtXXWkDrYH3HzFKYjf+EORK/ImVkuw6lzVK0vAF7IlTEIRtOP3eT9PuEctA86CM03Ie1YPpr7K85KRlGP8uGQoVGxn8UU6S/Xf8ZXywuIZ34SglC126Qba4zd145+m3Wssg8Gt8w/aT37WQcILl4AZ09ITMso9Bl65kbiy+f0gQE3ZgBftTFAvKYzcMcTFXdL3m7zKsQS48AzgU5CsvDF5blGL7Tv/t1ENNXjzdMQ7WuVWKLeIiHMk+pBtgEDiaPtR6cjlyldkgzYHYEfltl96Wi2MuQ+OQVq7KJNJPBg2GLZhIUVj4bugkgfw3TaqO6HTVBKaH/1RCAXwSEP2vI21os53nyZGpdSn/Um7utWRo+6zkdwnpepy/L9sjzxy88n75uyhUeIKu/MyGgvh+Sw/n7kG+QMu72wB3DvJMW8uVbT4eZqlzOVXYaep5e2q5ZF+OY24Sz9sWJahCx2ej93HcFwpmTFWD1sNIkV0H+afdaRH+Y7IhZfJITurms64fRvodikRV2cirFA76GES2CjWsD1S0UrB2I5iQxf8LI6QOt54NnXPyJfuf26ySb/1uTX8m/3wuj34EeCbqF9+UZVeYXk2hBUOk6/pOBpc9OmGfk2zD/WKR08IrtnPYESxrsy+SfP76bV5/JZYTNfFVbd/xRKcDx5zYuz3fVNW43pEJEzi4D9gVHqLX9k0uCCUAp2c+yBtLy6njtGFpFwz4ocrepX4a/ukzNMKHFUXCRwbXTkK/fTCopM4PZ7EF9IoCGz9s90a7wQ3br+5ufbS9PbN9sr7P1J3djPXPvwx2N0zWLiOEbggDtJPVztAt0x49SkZjTBR4io0d7JRMkqs8Pd0B2mBpqmDBvBD2WvUBW1aqQM1nwDq7uGQm/OIqjyxrdfkj1SfV5UNOUdZc35pxbMkv6xuP8aWpYrg4i2aXglgmXSJRv1sBCuwaNYYVJJcQFIgIeog0Tan94iMlxEGZ016UfQkHbWGtvylNsI+S+I6sbGwT6E7tV1g8xt6EPYha70+KuaqaRlM60I5HQn2xgVgcBO29nYzIjDz4hLGnrSqwLx2Am+7HN8V0r2Nd3HURfR5aviTiNaoDkHUI9MMMuD7Sflqvc2p4CjyP3r8fPzWN+y+g6jalhL+COe5pvXOxxbp5zMu9moTnr+FRq2l8tMLf5EzvmmR0UHEpdlQJgQ0XY5lqG+qCUpIeYGR7+odIG5pQw2PiFs+kvFnM+vJD6CBb+m5qamhbuqsQfbTfw33jWNddwBZLHpGwk/YRNuOCGSiv4wF5voOwxiHJV5W+laOgUHTDbXbrusg3RL3CDbH0K/hct7zj7wblaZ0NcFsJc0jYvuPaAABE5ZZb1Ss5IyP2V8uTG06FI6y8GHmsT/+YIYO7iY1VFKW1XWcU28ztNKRbf7YHBzohWYF6941LGLlw4ZbEsO0360n6Di01YeDcesyaeYzQ8zuLsF4s8J4j+KMIlB4fXkbG0JB678HKXBO5fPVDncBhnoZzo9BTS3CVE/Nuw02HM9aT10JhO7cAyh8LL+jf+X4tP7Tu15Qg/y28TF+ll08eQQLZdB4Wlra+Xe9k2O9EtL1K9cU+Az6wP820N7ukbcinidFl94GsRX/E5iYe5CgSwMMbG646Z1U9S0Mtj+yS7pI+d1Bgy6glBxw5uwbqF10yghjF6FwY01v9yninnZ7XtLuiKC3AEhs130CIeRzEEUj6i58rjtOGjWGazFbbnL+fFg5/nm/w9BWQNyqRfVHr1iJ8lh3pJ4Fmi5VZ0rRbP/tVBq/p9t6WQ38DfloRcaGqWkayS9a7NRHdIICLQ6mTHH6R1Sq5mSHOSwAKbcjSmxMcB9B8cuxzHEgGiA1/7rHzHTpSTfyZyyNwxyhuuiXHpnBw6IpAci2vW6mM/83+U9mlD6xgmVUTzqZl4HIUzOqwq/1WdkZALP5hvtJytAxAhI0xgeMqpj6wQh/+Ktwfm/8/5cxjVLsRmU878o9JLG1dnsqt5caEGPtEEZ7Z5cmbb49KiUzPWJLIY+Qa33Q5rVm550Kp3ieUocDtW42qsxm6fH+pMOnPml1sUnAjewIW2htoq8NKqr+RQ72dlPDK/DmTHyVOp75ujTgSE2lIhoveUDN/swwE2o9eVwqwE+zkwqdRsAmKjCK27D1lwGhLYttKIzpwSrEVcpTPYsqsKRbjj7PTO4tX8/XWPE0WGIhNzc23tdvUCqfZXLDlJ88rfQKhnV6rGxwt8GphDCzkDgawv24f74u1jjqxYC/psmFNR6puQeibnMPAor3T9nXh9KXddlyFAC0xotvGIwMLNuGJYc1hSGckBrQlzBhQ87zBywcP68cMvXkGGQfiSsvjactXtt7zg37kd7iqEPMFlAi4S2A/ljv/zDUE8Keq/69y1cca29PBtI741jxU6LvBKLgLL3f0+nB1bbeYDJxcvJwZ7RfDyIY41IlDjEXyphU0DPaEEo9uPOz887STo+OvgrUL8nsVBmIWc8u2hQdTXyYpF6Ml6qzSMBsz7DCUFI7rnVDGcGuiCwlQsmBFJUeg3t3mavwm+28XrL5c+OsUZEfnAUjC99CS1B5XVkrAW+eg707cyrcabCOiD3mrttLaFz7rpwKOFvSwbpq5FTuvYO+idgYiG2PNhuh8QIwpMeVxOpdMVwHQARo9k18pF4drLUk/V+g/2tbY+a9EpzMY/Huy0svPWeJmZFvxSzHXr3HVJ2lRPEDD6WKusqNKdP2Uq4unU7SsjvgCQ0hHvgTaWqoxjWZAJJpa+/qlfXzNtWLD0JmBqX1n/WtUeYAfsAaWIQVoDftdZLwJbiVkuVlrO9iuE9vbZnvUoo3FlXbm5hRHkqxTkEbjbUtAS3lUAxfg+rJN054NIFaXjpnj6lK/bKSC05QX1Bu4lig9aTpTKW0+WZ2BZbWK8ft+/wRz6FhGwZwo57gBqT1UpD8I+/0CxcAh3UWboji1RjwIZuLDV1PVShoIhtw8KhGiXfFAei2kHQXWQ0bMW0uwR3kjstyxKzBtqwFms6FjkGxRJ3yff67Ci7VMngRLPOxCzjxGyADaxYEETE4lK5B9RkVIQFMWSBVYCDCbc4v1xSuXRJX2aVEEo6TbRZZ/yPOUAyGepp+SHygBRClngCvZxCIU924SeMg10vvZ3+IrBvCeMaMij8XP54fIEIm1tiQ0t/gJGeQaY2DV+ZKuM708AnFkId6eh/2ofBPZm13Jvv0je/do3SG5CqJQoQo/jru0Hp0gz2H2dli6+Lw+81OW4GuPjKqwV/2gvQX33jIl6xBTXmq4LCMljm3QS8DpFeiSXUkzSVwOzJoAOiOwLKHFF3xLjH4KiDK3hmS9Vog7D0zjLgb+CqV/s7MKBf+ZW2dbcXse/grqoOILS8IOUgAvBMVLgHcTmJ4a8+xseiJv2c6GG/0ChoVQji//RJ6xrhojG5uoqFKYxHwpYedX0z38ElmgwqvLSoBs0oxXwuwxcR9EFLQo5gZegFMiXvlakx1fdOqQGd2wFSBvo/rbfFJKLCIO7f73ny0r+4TcLg7aYUVd7UxMxGMn5fnjqrUVhY0OVirCdXJO1QnpFguLzHCE8yuTp8KdtUUdkpJkgIN/b0piTkcGt6ZKfYkD41HSWEfD4FYFX331qPPfDNnZ+YLYUkl1gJ+c8gUnI0oTmuiZpLfDPFnOV2SUfjvDTDhp11Uz3tOHCxp7O1O/i2hM4dIXoEj7AS0/b16w8EMoBN8K8G7w5wslgWys2LJDD8gFdeXik6CKHDI4cfWuhd+FGV8fI40OhScywznt/XU5TkaRyfhXuTmZ4dNO3Iwie1YR0xVlTek5EeMrp46zZY+NwNaP0A6/UN9wbJ/bSfbVma4RMUu87IsVjpiRmAmlawM+IluYHolN6G1bwJ0CSUhT9//NMURlAwxcB9ulLQBkbI5lpn1e482mDNaFJkCVaL7Rmc0RU+rDw+/aXKOrZQ/bxZgFE4wcjIRbIjk3evXbQBeyYqpsW0jkpwtNYE9iUxjC1uArvSO8VeDu20oQTVoBiyNACPZvLe9qkyTAw0soCc8KV0XnYv2hsVSfxXo9l47Ev2+FVVmY8zMBj/FCQguWXIMAXdDbnpP6xj6RHhc/e4kIcYMkC91B5ymhVGC6sBKurEFogNEfW7kRJFhyF1cqYXhShNr19UGWrnhvZ9abo3gsdd2hBr8AzF0MalYMIFXiAPfAFlaJIhy/VHI5uWEyMoZQs/KIH1yjpowRay6nPJzj4dQ1zgepCaTOkPHDAZ9qWQ1sW5cURalQm5r+yuuzLA5MEbXgCYWq6I5Kopz96gNXS+rNS+Cpp8y3Pm1v7RrtEppzsV58BV7vU284BxMxJL2sTBsEx035yap9IcbntEF64zMtXp3k3Er+uLE9gXEfD1GGjqDVCbQmpq2rBkpkMBc/3aDD+X6uQcPdWmplmGtO4NtyLvHKkN4rBilLxoexUuUrpq0LoycWmGiFoQZ9w7wMhJKAqES6b+1EsSxU5m5AYB1z75XcMU99SkPGx0uzTlD99pxIOnsSGtxhcloRAcpp59JW/jDfq5bBLoJ6D4vEjmsAtcywISxCK/9v6le1/U+ucg6e+Fb+EGsmjTS9Y66mgfIat7SRqBAekdBu2R2WCJ0jKMijKrSrkAyfB/V+w+vbD2xYfasC3t7rfqQEaLuJp/ILsf03T1PI2cgKLVsu2spM+8WfHM6jKMdp0jQ6Ns8LWmJR5LfUDOB/WBCCngG1lGvD11OVRbNAKWacpTsm+IMTdk0IqOBDAKui2l7xNF7jBcHBBcNhiz9TIMKteaAJo6Rl0ipu/iN/hFmeyxK8Z339xLYIJy22mp7Zl/CUxXTszPkhh3wLgnTpO/OEMdz5EQdX7sJgZigEvpo2ilzkDHf1v9s+ZEsYAz7kibi8rxa/S0O+EnV4kMkJ1JYaVAw6MX15Mjb5oxXAJS60vUICnrZzCey77RRIhlsO5GPLol2yxQTGSuatP4bdHE/avvNYy+R0mUU2wAYAjDGSefRsk1YKfJs1ylwqRutzuIHR1T0d6wccvgCbFvL9rlZemJEdbfpILj6IAN8iDq5Ds1Y8xyef1zl+OPlUMZXT1jyNjn+jW3W5vJTqTLgYlLeCnxLIY1hC4GX7ctMYsyGZctfxQ4rNyxeRRUNNIMRZseDKbkPhXoh4aSgPVQQ1mn0hVczUoiCO866oW4UOFzx2VuSrbnaOlXMmERvI4xamEyWiPCDU5zfDLNjlm18hgxMQzk2pF4LfnnOYQHkgm+WMsGmMaPVaYs14aXjJYOKqs03pwB+OcPB1VzJ4WPCbf9zG09tQH7S00GacBvQb+wY8srJyOQj4dhvQZZRphTUO4pv6n2naaUJMFwxhRKuo9+6umEvqyIlJ/TwdhPwzYD9aPJKJQpWMOIePnGdI45G7lRuNj9pTrYderSRIjyzZPprUH1eUBCJjWqnO5+TEd7wfevUid3W0mfcokps7/vt458eYf/Rf6E592jsGRgI2lTqocCFhd/4Mn/0u1CV75bktb9Hp8JelVE+BTN8uix5hTFREup/gTXOeIjSfisNZZfR7QPNRZab/3xBKzBLY9HCqgcCs4YN40D9ncQBE+WVuvK30zwEd/eUomAfyqaBk8faX6+BTPcXcIUhnRIcRfhHtTRtvNLxKGqnMBhNbC+YBhWANypAYBP3WJiG3Gsr98khLcZJYbByQMTvIJisn0cJQ58phU7sp8iyPhGjG5eH/inOMwm/PtnuUmWaQXbbhrxVa9gPP/mBd/YLPsh38K2gkE+wx2HDV0gh6xJMIhdRWdMDY98tUPF2j1L0n85bwldwK54X9K3kXurPTqb9J+w+MbBwuhMYJpmZ4qQYccfB0hiQq36DAckZ5PgQwVhI0Z2wvbdfufEnINPyEIRMlF80fqTmULH3BFPHG3bspJKjtaRqJcCLK5lf0XizVhSNlek2lbeIMnfjn/RturmdYGKLcPrP8Eb0w4f6wlPy/noaNwjpHfKRh7uAYPLCkehyYeAlM8sahs6jIla4xR7cLxCqNggJnMLcYfh8jvG1kvlrlRS/JpqaMuE4TGuDyFnI1Ssdks97CHjxRfKLE77PwuMqIdqdg+aCfikBmBeTPWKP5R6vIliF25AkfRlpJgRbV6gQDmpN/pESqp8fnVPGKUU6bCznW6dhQyo14RYm1Z6vAvlq+hh8LGlmhNIoHVwGWmpXRIiIfiknGEmD/FmmIkunJUc3IQHuNHATKiVrDNchGBZ1NgW/rbHGSNtz9QkbTyZcOMfZg0pQJ5w3EV1xF6sll/mbuR35uFvDorK4VHW8ZNMkcK0GSRYSNQmulQ86Tc7tofTwL+J6An4IFK8NlA3+wEVLJ/VYMPSQhJQHC2z+vIjIepyJhF/Eksu9uJqvnJUQ/ZNhmW+UMHEPTWcK5Rg3ATsicIW7GsRX7X3O4SP5DRV0NtUUyJ79xtsQMOICAcXeswfQqYSdTGWc6zGSP+RuT8g9T9r2LSMQBYxNy2XDoyAfduuNepiineSaO1HFNlczMnUohZ7qfs0sKhdY/4GfJ5wouYosW43MLsesLBHMUQP+xLpBEoHqZB0UEFSTfDSZzUvZi4W/685s3L9cNqV6ABbD2oORK2wk1I+BsQ/MfXjDaUwrursIWVyEMilTCXgNO41pQ/GurDy7DNnRS/TlEBsJf9rCNJzNnHPItOgT445TZohmKIiY16kVqaWQus19+CDuIuA3T29xjY/STU/G5Nq/0r9TCQ78SJpioUhiyRqOepL/C1SWvTH7UqSYsVTOUAm0+yl7mizdeVPf8jLK4LPAxks2wGeGQ4gceMrUDzUjovBOLc9cHX2/OkUkKqi4sw7svKYDGW+ssVyF0Polbc76xQQvs2xN5FZqNIYd5w1M6VwoL9dg3ge0w25EWKjr6oZJUORGL3k7zuQu0OW7gPCwQqA17a1FsVt5NlFWrk5En0tBvprw7lD5yDauy2SEaWgipK/Ug2qoA+41BrDsUEQ6iDOkyLJ5tYqMl9Vc7mxPm93OkbGSpSwSdQvzfHI4OSrfOeaUHZUzMUMrPGxgKbrTj08UaD5mrelGWyHPSt1vZrU0iI7UiA2NxxqNAu6zLQtp0FpmJmy9zt0/Cn4hqksxpPWMPtksnGgZP1iANBpH5bSEKBX4z+uTtOFa1RhBvBHoaHXD9cEfsZhPFgJA2Yn/qzl0oBHOGmPJLnBXYJ0RWQ2xvyUhyTvm1SD7+o0RHecA4vQe3jBqVcr+TCZtFgRz0+o6E0sJqv8o5TGjATIA9Fka6mhAuAutoca6ROTDoLK5o9SkTzdFpCuOEr+CbRp1lRAcQ3Xnuj+S2F7R3p5npUNytkApLYllPCtVYRjGHtAubXiwvt9W1Ql+r7QKoEbFbXf1ri86M6BWXHBmjcERFdlVylar9Dd575kf+8B9LLEzWhFmvF1/a9tbH2/ZNAzcaBMvENknz60Sc3lFSbd3XNVP7BGEtgDz+ECV+z2PaCiHTtD7Jg3B2PONVASPvkToGG9DaLk72HrJsTIUKE6gAUjqdXkvf7b9l7a5ZUgURt8WH2h/DX3i4PEg41EuH3x7eGkn/sNRBwrQAsxSFPhnqco8IstsHK0QxlS4YpPzzWGVWVrSP5FocSwDOUx3w5DMMLyZKXU9oeiyK7Spwc9hKa4EmOwDLZOKIT8Kqkwr33IvrPlfn1PDUi0ayTb3zBFDv9XfQ7iWDo/OYsg2S1M7Qwl98K/TTPhv0H5fUcYbdoNJWiI2qrcexj7u/29qdmh1No7555eqs7qZRC1RHDZgOPxFDu7ivhLC6DSe86q8LlYZO92Y6v83cQxWDdj71VEryD6dhdNI5XQeHel6GsxfhWhETpz7VxrlzQDu96bNtjnX252nbVFMUpqJAiFHV5e9bmP7MgCcB5gj86NdLupmG24kxkK/aPfFK30CuKyKO6qKyC+2HowPg/5mVN1zrRRoWbNJFeN+xSptCQApxCbQ3tABNpZlJWKqU/uMSoDFnvbWR8ib7mcHMqPED8EJr8w6yQTUpVP/3zl1CgxpCTYCQakW6uYASCjG66IMsPGZZDLJkV+svoMC1JdzLQOFyV5+98en9/svA2NDgJmQPplbEOAzTEpJCH+SDT7Y6T8YDbXsYK5EVDgIP3fzhl/fX5bDQTeIS5xFjaUomY6WWhnpahqDeE7Nqltl7BuRRdOBHDBD/bvQQOgmc7lecdiu0QlvMVyJLKQQLGy0MIT6ku1sfTx/TgkxpVdn2CcdQGVsbgc3BWbEF1Q+d4euPx0V1mNh6nXMI2uhwPbZBiAKpu70bEawUXREO6K8noECGuKhn4HP3SWAgKIeIK7xgqCK8EATr7twlIN2eV2LbHfDk/TJMR9ovX6LYdFE7QW9HdiwWk8BMNk499S+SWoQfOLdqKH3w1tk2Od6mq1Db55u1wzMoJCSlcAku0x0R8nesIsy8FrzaFfvzkzvQkSNoyHqomt6kK7eldq2qmetbHV1KXPGTqsYvaOx+g1ae/6zWafdE5FFjVltGeJbOmKPJQ5yfX13Ob6QuoSpKuaG7nKovHN/XXWi/OHlck29tFvIn/wRGKbMPWPNuFXaGbG2fiMjd3G6SUMxvMpAbrVp62b9M1BB1w9q+WuiYZM1qF4lV9guTFFOtwXfHrZqjSWRBZcROfrhMjCtr+UWkcUkOhAqu9QE8d7rXcoph8WA0SDGJDeAt0s9YAb5QA0i268mamTbHDV6AvsVQuDX5YnHW2P4bR1UmfIx7TDD8jYvsn0tkDZXHXlc0uwaQ4Pe73R0hRLTtOXABugrj05bgoIzivZGjtaSHzAQ/MWqpXUYJWD49ZmFil8Zh0D9yaHgCvjYpXf1GIkeyLNJNjpQAbVgGGlIOyqvHimkKZ/RyduoM9Orrpjb8Hdwu220iOSpGte8xdJArUBHGfvK1dNO+rM1uB9CeG3pT8je5N/4NJezNeWXDxJEFtbR4PrHF7y+IkfW67XZSnu+xymUaXORHbU7dqG6LPjbnOAxobxwqd0OQOKM33SNNcwFK+nGm0DgHsj01o71dOLRmpnTFpNsXzZ1WpP5OK5ECJuvGe/+8ERqzjOf3JzQ9gfhogtHcOEqLzI9kRq9Nz5sexTZ1yHq5XpbpiihtwdDh76hhY+nUV0+Lyp9cAUtZ/JS6ASnEcPcKFAaRYO90vXSYeIa6xfhZ6r/RbYlI7DflGj6dAeCEWVF3qhBtzEku34NWHjxoqgdg+cDLjhYgi1g4A2GlYi4SpA25PcBDY9mTbph9ZytvjryOR6vZ8aO+LQElDSa/Py2pdm7LP6sQU5mazgK7HsijLeQ8bw8cAg9cmfcmIsLUcl6DQ9izdR+u0Ys2mvOQB+rVgd7kNJKCbn4jB9Wj58cBH3NH+KYp2WWZ2O1w8KODQgz/UEaiYO3MhMpCBcahjQnBn9fXZgyG54HE2SiPVMQNCPJ+o9sbk6KG/VFp51R9R39u64LQo2l04eaIS2NneSTCAV8bFzkEGvXi9nH8JsOPjoIm/EdjJ135Xf6VlHOhYU7+MYnrXXOwLDS8CN31k55LiU1vj9J2RKHm8kNwqYNXALYaAGYxVpvD6f7Zjc/+QgFHIu1m5i7IiIG3CANjTAzphA9Ot7hVR9isSIqxhyylEDoGQOg4ghpKBsfPQudjw5GZHQxDfwI852Znbl8R6r+UYysGx4h+YSJXIUcbXVKVuCnQhMATz4Hwr/EMjYY79Z6ptP7K4kTZtj3E7570kyaVJa04wnysPA/Zd5Jv1SYSiCbhgxlh2K1hQBUWiyITUbbmtXQ0n7TjOBJXPTsStH2MzMkP6iFqVz3oHnqHmwPfcnvF9nzyKEkTW6Bl6xGsOvCU1jWK3Xgko8ZMztrk2sbesn4Mk52QanHx2pYQf0Q0GVDtTNEEfL+Ab57zL2seudZtJLPttnJO4jbbappFTlHX+6b4WEx5tKRZ3kiB31PoRKhodKPCMr+RH4iGB4xLwbSFu2Dcqg448B3R8qeVQ5G3ndZxhRNv6mYyj30eAFv4YfvmjIvAXrjt3MgMS4GlvUHryljrOH6IwaU/JQuxE/at68yFv2w5DJT+iLLQ6DPiwh78vjdj3hLAppRCVM5ShpHzLbyI9VYMR2Yw7mmI7HjTuBKSzvpmBq9XJuKHvYNfLaYcohOih6aeNBItoj2Mkk49UcdMFEQB2mRCD3ROe0YZ5IdPQ+3ZkF95UAtWnWnfbm0j+rjB5ieIi/SAzkw/7wFY4R/eMRt0KzNSMn+dbbblMLy85y1SEBvsxpiPSeSH4hnK76SaIOiETbF350A7X/CDYBcczTYoA6qaIknHESNn4PQxHyoLES4b5roUuvZsUKi1gCOpogpj7xUDaQwWUfyNTmVwRTy7cyGdqJzVCLQBWrOAHYBbi9Oc65QyCCeFY/lKKpCgQHdNtQGYyPf5C3gmDlLYgOS5jBdETnBPHE+up3UY1aE0hKHRY2AX+TkLAXr0rJedA0UzrqF+jCCBuSShAOqCgpCuq3440XZU3qRGe0CGWDkMH0bjEhWzDaW7JGvxEbGBAHoezIHywiEF018yHH5HHKra++xefpj59nc7ChFwTT9RkKyA8xC4LLzFftGnXvqhU7QCLNQFbZ7bYHqbHEM4w3esk5nkZ8LvJ6379I9iNSOFj5lArxvjPLyy2QXpUfE5L2OFHloaT6A6tZUxhxqGhBZVZM3D/EzPc+TGHkexyF4fMsM+wcRLIO8oGBoV7356oEyqDesIIGu/vAeTtmqKFhnkY2rTKqtYdWOiisgQEtrRU70nXH9Ao98hAzVIy8OIHmWug3nrKMkUUdagb8SUrYq5dAiQe1uRfFitYKQ6j4R/6erubJ+MipxSjYTaBlJGVnmPQpwSi+2mPi3mLtlbV4rKBYyjfbK3M1h01ltoUEnMLOKQ6nrx2qHc1mheUBRpxmefyl8zUW8AOhsoXcY9rCLTq4NnNScTbRqa2mxpTx6moEJYis8+fd2Fnr5Mz5Z3u+waG/UbzrRg97CapMaPwBx7U+CZjOe4A+u6Vk6owJqHQkHi6BIvUbB6tZzZGIhNyWKZmTRnPeCgcP/Q5lbqzffNkHN9sEHdT4EueL2MNHhU4A3o6C5iKsbpYR2yjoyHXKy6TtpcuTJDiCEPh9v0UzG6bxC8jbgo+A+p8FnRDIa3c2svB0AgGyny67MnaS/wQTg7NwQ18t4RQRNchd9jgcL6Lbe2w7clSxFe3evL/fXuigIXP0HEK9ld6yGVcImOSqeRCxW2FzRfYsmEOmPQOSwqL+tbkglWcv/8NiascNfl88oaso+9QvAu2vc271XwSPeM+gTulpPGeQFRSfTyq94Qj5uxQlmsdYG8igkCJJ1IrPzBOJUU1PycSa64EcpqFNR11mljkoWAqu3INUwaIWCnzdBjh6M5G61N0dT9HwiKca1nzVt7MGaGOr/HmmnZcN8KJ9n7KoWy+/pxKKVXscbfIWbVPMyjNzUapJ3jwLeLYTRcPvQwNA6zKdUFSpN87f1wHc4Vqp/5vgwjiMPZibWzGfZO/CstTUupTsHWEpnQ/dhlCQk4DCMMus6oYlIjtQKuujB7kixyZpI0t0/kZpcEKCv1ujSQ9pvtHZvDFUAI4KGyLZB//dTLdCf2NcRw9rs5TjXP+itp3rN/Ed4JIDtr2NMYbDgZQkoNHWYRNogsGmWHAtdLIbWlwJqi7ei7UqstQeFjGsgzHFykNCSfbgiH4Goe4WzbMbE4M1vmJOq8zGbsIOAdlf4dXPUCZpRyuganf06R6l1dZXyVd1RVQzIx6UOfg40narwTf7FnTbZA66fvpA+UgsB/Y3ZXswRBeTUUuMqmGlxZ37QJlCb0VIK0X57UUSpkcXmU4tQPfEFJ++Epn9NZpnXYD7egTCyMugPvd9gX/VUh56rqIwP0RR9igmvx8P/roajGg60QZhEkHYSVOpQiY7P0EbBbXPEnRMwjJZldKqlVhkzBDS7fPjnJQBeAeyxfhX3nFrfxj6ojo9lBuWqkdxBiDPMRT/NWrq2ptZidirj6Krgkv+pFjmitZOK6Gg0VI1CjzNnu3CknNXsyohUuhGD87QqFziEqcdwJ8WpRwlHUYHW2BOAdvonAHr7OIMU6kiLX3XYAQxxjrSPU0+LbO4Xrshb7wrTC+8grJqUiPU8YP3ce9AjCUEx+biyJUmOuskq07Q+qmeI/1WPA3GfV/r00YngkYw/urC5Lc0fWw5YgdJE5dxHtQ22WHGe98dCWA3DYFt8aXG0UKeE8cbDQhgib/9DywUVo74T0NTN46h43zvUvrfR2NpLQpibegpyLQIxABwpk7eFOWmCCCHy9VWKkWBis7lLpV8ZcgHF8dszJm3snYSPfBrT8FGPeHQt6Jqmu49YTAQaP5ywOOiDg+oKsCRDDIJ3FJ9XlFRGoNDKhXyFsBcu3qR2Ch/EYm9OY4nbE4z5PeBrvh1UG1t6oWoryKMgzH2ZT6sD+xeDg0bI/IGoZIuB7cJhbgChTt0G0k0KqbjppkX+gADMeeLvKtVSnoqfJ1HcU1FuAuwOcEcr/anGP6yFwTcs7yuRC++Moy5sEXfNg+l57Pi9y4FGUmONY/xjEQ6gYz02DX05O5ddhRlKAldAY30Or24LjPUfJkj37zboRJS4AS22b5EIu357ZsmjJJZxYZLAYg6C2tTzLVv6CmIHO32xJecnmBsRuWRmkB0fzzX7QPAsBmqF4EbfY7aNbUFrJpg3UhEbn/lQ+5X6BiFOMKCrLzLubenjYICktjSmqW8sw3VFXmtcL8ciSlfc+e2Eq/+VciyLN+hkhFOpSc1HyK8n0Oov8IxhBtNeZRO7/wDq5gPNhjLWuNpRWhiwCiGpgHHInm7pQ6jRS5dMg8RohSAoMNINglf7hjT9OAeVAowD5dxYq3EIfri2fSX8N1u0OxMzYPwObkpn6LdptgJhs4kF141qOIXIC4cVwize16hPKOzrKxVhbI1/nDPL3AilXLmpsEnjv8NsnN7Scsq7S2XqM946nOhtXd36wRcFZkpXVJbVwsSUfT92V9Cr192pFfi7zxaKm+3PbLCcCj1b7IBRTN0THJqWP+4uEJGeFhDJhJOu4UeaZm+Lhw62P33w3gFocfa9kvphc2OWDIDLFJY5rmSeGcrBL+Ygn1Ntin8d22NetBlQAt5PF2NuZgXo86qj31pP2RbSv4nNZYvxZiK5LErzDWftiO/liOEypvsiMXGkj7F2+GreWsSA1QGAxXXEO9hNPfLasVkYHc7RKFWRjkxKroQHnbo5cBwymz/Ywl4duDiT5PReKGwBani+GOvqwLpXDcKKBA/fzP4XNCaOE+wDJxeoEANJE2+hkzfbMXjM6SNcwGj401TY3L9aUS0UyHfQNEDK1E6jE/IQy4/LSCZmHCqykjsX1JUBVtqFWFPOkIncDTI8EPsP9ILrHL8GsBJfnoYRoq6Co8SI7EQ/1Vbq6KLrZuwZphi/rB5/zY6UZQpbvaX3gLEIJZGQ8BZsfmX/SWXp3JCOrBdmiPE7+G3pwPCHgPxWVafFolAL9TR9K8MI1iJlQjkvJOOGnjKUw36ezWLPaHpTL272vk0FUmY3NO8VYBrE+C4enq8UY/Ry65hv9y2NfEGU5Iscw+xJQDPFvTUo6y/6KfZq/pVq09QeTm2unHZjPp7vAw1ZLiGzrZZvzPURmwTyI3WWQvp3SkA7bkC1sHoy3OsBGfSHiogKa5lM7+t4h4CHOanVRPF1lCATasiwvBLsB47G52CAzXeZXV3k14vzYNiMSRZ1Rbx5ErrEVVcM+BM81XP6qCh+qGpbltiOaL6NpMUYK8ItplLBS8d4ilZpWtAiyY2hil+EzM5eTAjsalrM1bz61I/IUZl2ZreCtacaBG2aSnVFzpv4hlpJnO8o/OoutOAGlX0wjxecpvh4eZNLKhUckhY+MuwN/B6i6hg/3yrK2k8+HODTwb39fgl3z3JK7f4JGC9MEf6mcwwGt1iTFlHiuFPEkxdCdCsavWfvR6Jb8QkAq9L9KVJRpHtOJMeDTTt94hIkvZPbLdFyBbFI/uAtxvUsS4hEx+efbKaeaDxpSWLYjlw21KTeJTU2APg9Lv+jChTh55uYaGuJJ/5pdv+aVcryft+wtdXuN4nF2M1MWwaaw4RU35H/wK+7wmoOnyGYZpv+G70aieeD9eIcVUQbdVpmIpKvj9Tv4zvzaRLHeN9Uo7PkXQz74c1bM8FRAHsC4Wo+2h4WBRBY//9ArLkD884CCoY1FJf9ysIypqkhlh1B1l45xHa8LKUuvzzP0KujQwT0gyR6SQYF4WOOdzJ5iaPu3gCNIbo8FMaxJLKtZdjllmg55jp0Tu8EqllVyelj1ujdlA0GwXtj2CNuwjdUzvP1UoUEZuwx4ddSSz5KWWzXh3is95ykNidKfu9QZg8b03s/vD9CLgAwcmeWlKabeL+X7oSxXvy5DRamlbUYKGeyCvbFQavG3u7CUsgNLcdN0s3mQXxYwCIC4jPrU0265Xw0N3bDnlOQxuDkanwW0E4v5CDJJOadYyqRMX8uERqkIgF24xMXX/FVliZ7/ioHvfIUc2jmvgWIEGSkfyOPKwbcpHf1YgqaR98IvR5tH0hfknVJ38pK9DXrQI71ivQPJqACyJYugQrTBLfTlqM1upqQrCKlK9PbhNvPSvrOT3J1ANX7GU9lZi1GalXxEZFpH/3T+AMmRLQB2wQkCD8x/J4LDTwzpse7vG68sO+XrZIaIzjwvoySs54E6M8HQEiQCBorSfRPTmE+X/ZGMpePl171ljauhp4EKKeciLQX9w/rSPorYGIDSIkKdKTrh1ykKVlm31hOOhgdgZYWXju/jZSwBM/EKRSwG/oiDOoncbLP2LZJNoqod0FRA/0I+GslmMC8emwATOuffzdqj/LYJAMFnMtZMl1d4+Ta8Xc6QI/Cci1a2Q4xU45hw9slsaTSi51TcrsZYHkkxYbtYmwljW5rmLbOJpb9ojWZ+5HpOvRyQxSDIbq8CvgrE2s4A2REs6U6lax+jFB9IGEwPs0yHsOlkbMwvWFfJVp17QLjdWsIGH7we4hdxCAhOO/G/+CbB3LaFjeMRcmKfyCz6GCyLjqt3T5FLl57WLOc3RZ2Lcf/zpGd3wt5tXcZ+xPRSo2mrvoJ9Tcu0AAEkpGwXqTvPsXWM2z+345m/TcYweuQbh6AcLBGqn+kiw/VjysAXPGUrWoZuiBOWtRpP/loqsfKbgkdIpO3SJvB1KADSyjp2W60fAM9pJrxAlCsrSgOwdGFC/dqAg40S2LG5ZVPKDyIdGmL79i6CPiRaz5IgBcq69HBE6rSf7xH99BHRNDKUh7vgg2hqmpOwZ2Woo7pG3WNyH8Gsjw+cbEpAxhaaqA2mE7IG70KPjOxgfKojgug1HnCYzkLXIn2X0x+MVamYNMF15mYnA4ZZTIZiaoVwD0jLy3PXZVAPQLOHYIfaygC8Vi3h5/tzn3BnyZ2PK4ZUT21FUOd2aCJfb+aq/OhZqf39H/lm7AG4VZ+N40CdqTnhOuj62pSmCfaHUqmucXlzXV7rDyQHweR2+kcNMrMPoQ/MTLQCXVmKNArJw7GimYtNSFJ9SsHIMHmA02h+JTjhGHwIQHvmMoQ0nY6tyuAhTruTCSz8vZlyQdl7yA+eKnp4zgHRiluNPk5dd8NWHNN9FgyJp+hAyJzY9L8TXUUC8v8HFE+EvU0hID72TKcG7p5B3dx2ikwiHsb8b3XEV2KNLaiPq1gjKkrIvf5KSO+KgZMaHnSBr2j/OjR3UwgIO1wJgH0eseWrxy2e0l3NbsUEEMPzJNExLCMXBO6g6MTgGr/tQ3hoGh7mlmWbmHc19XSmLMhCv54ZmoOBfEu7zYIdOmEApHsvyjvV3om4cLrdp5Q93z6J2Ooqih62bbl9AVIqYlwqqpmau6csYnhi95neOg8yGAj5XRrqsSO5ectwM/gqC+zUZtFTpeSNnSNIdLwirLe+2LHJt8K/hJm/T8Wtf+9uRiwBy4Tp3kxuQK2seRx96U+NvCpHbmkhsCq2vYgXkgU/uDZ6bdtb5re4lV/whO2Ac0X7itWCw67J/EL0I5264lRB4P+lwHwkSMyoiizu5o/VWDp9645JpTKFUo3Qh5mBixAVYCXYR04V8eRREpg2zCrnNfi30qaHsJ7ppyH2STtoxz62uL++Jj2GRU6MrexmYrHbawbDZ34AlIa/GSc5fiEQ0mBlRjTN42H86ljkZNLU7Cfu+RjBV8kq0/JPBLERp7BQu8REv/RW6KO0P1Ee8FeEDluhfPJghaaAo/ReS/urUUurVsYt55QQ2tQMYXflZcLZSMexAN3tjVSc4R4bOCY7WZy04r46Z3GlFDh8KYY6J9SpL/hdBwNxYbYL1W8MVvfLV2a3WNruQLvaiCKQ+zGG50J1vTDN2Ka2NZ8xTZC3qeDLo/Fz+zLbn2huCptWdAoRrDYG+NvIxreAyjpZxLhcHm+0RW3N86RuBETSMkcPenH8QW7MMrJR3tZt5+ympMoRNpl81YKEh7IG5Est/JOHxsSjWwW1zngYFZb2+vx25AQ+Pg1A4NDCOiQb++P5zWrzFsC/TWOmXrxTckmywIcw3nVPR+R5ohzOLWukhSjeGtO1k2REOKB5QxwNE2/Hv3AMmB3pbm0su0n6iY8DP/jDWZbhcQOuK+1ls2/XUiSOp7B+qoVySMhomWtFoq70aF9l/x5uXkCXKHFrZQvGlsW9CjWm9logKSa9dt9SHgn030V1v+J/MGGsKzMy+oz0DIeVjreX/JldY3Q9hJTShjA/7lBCFNtzHC03aJL88rIKtf2Z9JFPAQKFpi2aKmJqbxBHRTDIvZd6zwikJRupVVgACowvBAPcotHN3awJru+LvFPLriavW6bgsycT3lrd1rVYqKrWptRk0HxIyVmsxlu+mlvIBMMI5JPUImRNlQzZdYLEuQ7Mx5NUMPpDmuqU6BkWm9PL4YnF9JbMpshNwDg9Oqp87LGh6SD7cuvfO3WHFj3EHjkcZ2Rk2KFgbQ42OudLUJqcrBlsHXFa8EYJuDq8bNywNenIK494nTY0aKg96o1/OZIePF1ik2Hzn/7cMvJitBQJaaqt8JbGMhX/RBNqoTr4NAhij5iCa6TSBsDqfjyMaOxVlCQCD9alkmGlW59Cxhj/ldpcld/RJhUwlw+ALVBbxfSIMj07KLREwinm2SMg9b1IJKV96znRriL/ajFxn9AsRg3MHllGCRVBmNy+lh3ey9IezY155HxWlccD4ZKCeAmOkl3P0WZLpJlm76FR1lCydKj4x2gheXg9CJfICgK/87IAOD4G6wgldehQrwNBc/+FoamCay84DrtygoTwKQbxVkVY6IsQ1/LFcwvVWhXz+/tCtJNMgrl4mBUnHjzGzkb7bWzDd6WQ0CCNA88dsoMXAfOfC0pZ69rmBdOiK2x/QIra4ptGWt84QGUhP/WbfiM7iqA0RxGVzzxvGp/7FXtRVlL1JP8MZWnsZ6KCudQF6WUP46ACuG1a7WZQiBF0EsHHlaj5pcah9U4TcmQ3BLqIr0wb7mnKqueYn/rPsdf4dvfAKzpmQmWouFlHVAG3SxzbiOCAQyG9FhqchszQ9A9W963bjnJrajjsZHWQ6jdUap/VxQpg3ohdoj0y9lcBuVoZW11wI6yBIOd7un37NHOhAk6DVKe5xmaRyP6QloeQ1EfXZE0K1g00kl+SrU96hP9y4/zr10SzB9G7athe3cljqG8OlJy4FMntGIZEVUO4nGbWhHUDeuZlpkYWVC0h9NrTuhzAUFCZf4OsLiJYkNtZvmUe4ixJUhJwLY9meXC7UZI+9dNsdGV/O5jbVIokfsq+bt3VhH1OcSAzL0tYmrADCAtnduUolR46E9fD7W6vmv50yntE3KreXcOvaHTS9xHVkS+EKiqn98NxHmRpjEAjlm/qVPgrmHzCcKXS1cHcPHJPu8UCLeTpTrLHvdLm7Ngc5GRI0OQ18t4xfaYWW1NbhRfgd713ptccZYZsK5JNZ3dzBm+U0TzSy6RdTNvyHxivasOlCjemE8Ipcx1BQWIAITIAk7BFSkuwZ9MifrGZ3Sq7okStz/or/eK7lN8DpbrH8PylQRBKXT7Pz0OxtnjmW7RPZip5ndhUrNiCCtbnrXt8jtTgFckMvUhmj8kcYuWei0vKCEqO+I66MkB+3G3HUUyr+lZ/yNHIpIHzkvN53N/J92jx6iEK5Hd4HPhe3js4jgMaB3hZaejlsiOfmvHV885RNZtrr/v/60+DzFqTmhhHysFyEZ6TkvnyyeDSRDQp2NPCtB+M34Bb6u8kfcAd0MF20CIGUD1MhSXaZSlkbKEWFwcr9y7EvNtxJjhaqjCaTFaRuQYA1sDROGbMGmSMdbwV/o2exJNhVmRpgPldrV1czM+vHd0i/8aY+wDP2TlkL1cgQJg5TQJpt0/jb4LHFvcqkDJcY6JEs5ZEwUbYE1e7IQN52H6GzLK7Z4Dk0wOuXX+tc3BNdhol9fY856wEMe248RU9e1mUuDMoIiEjbrfKv7xTdUjzeKmBUNXtZ9kq2XPgYDFg7CtKsgyraFNpcCUh1vvEaFeOasCFKOc9iu7kCztf0p8anvhyd4CYO/r54pBPtL/ucC3BpVRiniQmuvWMroljCkN9oIxpeEgjf6poudhlIS59jHxu/fJ4RtVcUrdtmYyfRc3Q7SQJsEHRyqK+gilRR60kXKljF8twWUHJUXRP4soptlGH1/PHosrWIkScrjUF5qnlvI/F1sjofZtpNHko0lq4gAhURzyPCKJFn8p+KXsn9hdQbPiJWpu1sOGG5CvGGf40bS1hdvkbqPpCJwekkSkaTdx2NOQ0e4kZnDZ9B21yW/qDtBwhcrnzb/6lWg2mFUUyTWPxfCoze876MOGM3HkcvMHNdMM1+TOKNSUbhtsEsimA/eVcAGYRVDCey8H5ktJfWnCn4/WYzDOikm8B485rHTiP6v/z8B9tmvG1hf5gkSF5DqEwAG4R1/cenbFqJUmo4hYP+kFXFQkqpMXmr5+IiB/MqA3unR0wK+FsdH2D/ZDsZ10dos2YctNvtRTn6Gtn5bXMXmHaoi9Pagot2KNhofy+VhuYOMO3k50Q9REUQn+83oE1rU0t/+9YAEqG5XGZml99ySzomw/PeXyjx7EiLUOaeYUNtyoJIUfpPyyhEZaYvu6+ayk1BxzCfRB518YXzjKJ/oc54x43uYQcp1N2fzrxPUNKEiGfXl7h81PyvmcxdO1tewjeQPnbCbGtWpk4P+WgeSYuD8qXRtwLtUx+EDPMnra2tEJlqNBrzMjlORW7XUzaBxEHn7rQMae+L8FZQaU+DzjGp4u+0FsJi13i7ILjcVUxJIhi+Z7X5FLEYXb6mhh31wat1m8y2TpYDVuPJBLOxHD8BcNC1tO8beh1+sMSM5cfAelbN6vLpaMGqKH150vOxSZQ0AXFnAsgDmjjb2CvY6IlEGrscSvTl5PWQql4ed24DmMVUllU2DedqqKW5cZuwqJC0xsVTMFxYJYaO1iGG/YMbGP2/QP1C8Km3cbX2OHMnk/a0UBO/1rQ/Q6b04D7LsFjvZvFy5hW+f2J399A/Wd2kXWHs9GGTq9WGTVktleHSm8xMWyuly1aVtxJp7dVpcwmVKo6npcmXRwu9aIAAE2sTBf8dkBeNXGrWtca+D2PCysWtEO5Jnpk3iARS6IXUGAtLvcYAq2M2Qj+grYxwrHrTENYGtFHY3so5sFkOW1JD/OhUUJl/FuRbOjkfvv7cYxCfaIn6sK3kpoIoDNU4WmqLxHIn7HhXm442v/cXWaCYOgo00FndtT8u1zGIEnwDCfk/0o13r9hDC55/RLd/3BGmrbsY+MC7ZZqkeGsdarso5wDUSWH7V6xpQgD4SwwZkj/z/BPvilT34FHTYYqCztAH8s/zwz6KxlzW/wt+ydiKE6KxQ24o1T7GpNcKj3+d+3tH3ifoEyo2AwsfZdhV/JpCK+D83qPOSNnBFCmJanugFT4SvEk/NTgkKkJtHqSy/C+OeqiheeBQDjjqluI0mn/Pelfc/cEYd3vCJYNAFdN2dSuC8rO5GHjA8ryFTsynHmXZOd5YUl8sE9twlxL4xqWqoS/Lh7kd5rA3idd9ucj8EFry2WQjMug/Zij9k1AeeNa6x2bPTnxuxuoLNgfHbHTxvglpNlGiOgjJsF4vt4X7vCyAfOviZgvwLe9J14SELXtqV9TIZ77x9Nn+gGoBpY9ej6Bng+SSVQXSid0NCfJz2jRzrnwvBa14u43Xj0B2az863FkZLR9pIQy2hjr/PSD3jI5y7D6J/kQq9Gms0xaPXxCXdwhDE7RvtWT5kbxl3SERhbOqWxVEx9Qu1hmSJ5r4qLO1C0T5pdYWlm2/rJtjrkD5F1OEvWCRDJzqWWLuTyr5UEsJxlitGHyphOP9xa8gy2UwcMkJOOIiuqpEHKNNY2FUukJOdzuhJFRhz63gj7KNPadleXteoubCezEIC062qTJQhvVjYpJBeHxp37nTZ8lXF5uZOIDXI0l4OCaPyuG3sGBHpKSFDADhkxcZp5pbJGIyIZrPov3m/PE3Aypcii6XkpslpoPJNPR7R2zTK/xAMobtxr9A4Wb2yOthhaIAZ9RSWLVX0TCQk0O4jA7dvhqD0w1VMNUi7Yt0ewRJLYqhXhzQimMfrtB26/ya+lX7L/KIJ9acZlKkA2KhW4Ci1RmPpHzGOZohFEB9ZxrrNTD2gLDZ6OwNe/Ee6PRgGYgAAAIxt287Htm3btm3btm3btm3bdofoIHfl5AKsrWpi92ZUHihF1eh8d0DNyMWZZDgPuKhfx9P7tNTDQXkIxk/X0MuYeqGFeXi4+EwVFjMnFSSQG8A/TGt1iDYUxHsLPrHJSQPIRDbNcHEBBcsvoVVUBAqSzTA5vQ/22Vngjv/VWQIYCvo1fpSQL+mcfQ3LF+3zD66lxjBr0s8IhCzyyZlxSMP/qpiwg4u1nfhbECOWTsS6cPjd32pWug6JUdgKnBl0u8qLe7ufxGfeo2aslOx9zqGs2FheWYYQv9WYP08JSDqmZ8C2tuJyth6ghDyFkQpCow9hDjQhQh9CVz66uqYyCjZ7OvP3Tt8HYVsE0JfSKS1p6iBa7s3dfaeHr7bJKdYYnHKmTkQr6tA43ydY92TccdEhIWsYbO0Hpla1n4vkYr76zBWZ4auSjd1OqVF+WaiskwwBnt0JBuZvb5/GnGIrct1aPuRtK1aVhoh0HFIcNfq7SficyeHcN7lPa5rbU1jrBr0Q5AcutvZYgLYvj6nJYzZ9B+8q8zdhSfdYDuK9gLL9+LOHG1E6G+3N/TYQOEOK60OwXvhsvHaoif+x4aufuaywncYGFSqF043X2tMxfR6EqBKikfZMQ7yMI8wuryNDmKGMyk9rzqSqgQ/tXUX1wRNh7JgCA/k7GuIzwnl2jcPSaRwMO+vpOR66bqI4QzxWYvdA+ZlfuL3EerZ2RXMn+rDG4DpVPIO9NC8M4V2FVx+zWBbuqF98By+YA0SrXq5i2kKQYokY9v1mTxNd3PLM+WEqXqnQGLyo+YkCRa3XjlPtu5ClKvTTXiNi7gfbC4xYCSpFktqwpPX75Bcv88uWZHuhuFek7W/dssl7Qbwj2QJyqBhrygu3rNwXGEetvxbCd5r9Vnh0zTtA5O4HWQeuGlm6EMQqLjumh16uho8bRLdvS3b0hvsXsvaYd/GPV8IItteDJUtQpA+B67EBPaMa8zW17RHZ9cARjMCHEDJ8FxI83JnZxsXdWAcox5xRrXyRMWOsl9U15xYXO3NUjQaqKAW0E5+5ldN9jXV+iCdXXp11kEPeXWCtST2n0vUpbDSdXptkwIrx4cu22aDGMjydL/0b7aJMVFt4XMKsLHPGP7rQjKTmR2Y6I8KD1W15GC0Qa9QRhmWb98w8z9APkmuzRqZQPFOMDL+iSsRBBUH2425rJynuCa3GkoWEPgQc5wXwabX0hrsyxW9E3heqy0E0qPOLvE0c0PBPd/qKNNFz1+01KSvMUoQju9BeuIZInlNWYLPaUbiWqoom59KhG35Mn73m+HthKxeZ1gZMNpk+OtoaDC+N5I+AoOUlrXHc69wkmKzd5Wgv6aiygwD9ZgDlTfJqqu31eoAaZxqMbt/vOntwSnVj3mQiJ4ZnNnW0e02xV4wbdpiaKJpdclUnuCfAQAFJkpt1yIwPr4QkDoVe/UN2r2YbaSOowuRoSi/XoHATPhB1k4q8tO/2yeJKwe1VrOtS1TaSkGob5WTgCBHWCm3jGY29YrleiKy5Md1gVmjxNIxC2bdn9f7W41d2uVHatMt8jA59kL6veKjwkUdlD0gmopjzCIbFw1W1ii5tvLw7mW4U/vEABT4zjccXOsrNIlBZDdIf9APDNi1XCDRpxef9frPtJ50LWD16Nlq6CpiK6VihNQS8TJy6xv7Lrpvt4YRDmM1ybKjvZ/FblaHvcQtXbC+LONmfIp4be0bKRku/EUHRZt4VB9TMkPHwHDfU5opu9Pd5kgS2TqBBbIYF2xFCSXYPiCisKTKWrFPaDbwmq6RaP3plK4AiGJT2S8Oo0qxmk/7nSzUDJuxrvKhOaCFxeA9avOhO30D7mVmcLdV3CW3Sarxiri/K3lbR1deg7bmhpQluysmgboUkcUoOMhMB8CrWvfJgAQW30/tgq9PvfHQOlDZo36bF3jtwyJSbuKvJkoiN2HRnPT4ItXIOkjoMlpZtGA7wuev9vczlsAzUsFzcW/WyZzUYn3zM5COvAQHT7nZVRTou69qGEo/D4xS9IriHP4PgMkEnGy4EO3mlX6V/xwwSYCW55+0PYKlYuyTyjY5lV1i99df3U96WcwiSBi3qRc9CMOyW2Pa81qkNWzgTGpplE7sc052lFu8Paf+YC1d7RkRTcWQ16U8LKNGFT00Q+SKie5LAVRs1+K7DxfqLTPBy4vGneXqNB5d8VB2adeiFtKulwHqDORgW4CONaHHLnGLbNckw8220UhrPEs4y45g0DuymFQivD1m7vUiUVYfi+PAZOLQsFrVw1Khfq5RYFqBINCIhpD6urFHGjTOlZiBqqzIgfJMxxpKJ4SJGzxGHfSnzZ45cDRl9J0ThUoH6Y5q4vsuyd6K9X7ag0GaW1YJzlAodNCenGBWerAbECJQbHQWcwj5tEahPsyRMu7jbKN+P/PKVV4lmWO2DaB1A5hCiX+t86O7fAoh2aBpkhp4Lv9CC0mXmn0o6zLfjtZglQMfdDEQ/tj2wIyz9b0beNQzZ3w+uZmlkIXDVxCi46smQPivS10+FJCl7KrNjWdx5eJdLGRPpfi0GLVfyFRQWRj/zMK4bGlMxj9U4p2bYy/hg2Sg5qJXRZ3bQ7omAKbhmuJ2M+0PKe+E817TYyRgXwf6/XEVAbFXZu8CiQ4+Pf0rbmGjdOV0VHL6D9HBUZ/6jIdBqfNzZLpr8vncX7TD1EldiIm21mJ3rRgPROaAxJ42l4V5GQqDPzXfz7tEA/5pA8NLW3zPp6lX8ilfRuwc1Q+4Cq8KHZ2fkSS7Dk+aGCu4GDZJIerHCujeCzlNSdHz53chiOaPSEL1RCaqw/8hcihMfmsby2iBqhs4iTNq7j5eQlcx7hMNghRwQJ7r8n/FQj4niClc3Hs0d7SGfhb8NTMj36n3zUtcfTF1BeLjRz80j7Gs/ltDgOMfZgn4vTemrU9m6wynsXoxnWn0RNQravoqVZ8nEDHEy6QlKNNixnrGT5Q47OzYMr72V7hq1j/EfilWVK/JEN7wPYVA4IOMjFaN3mq5POXrSWM3//np7blkypco4IYwFnrUM9yV6xsUvEpRNd2uLQBkvb+EYOs7nZ2VlejKntMx6/7Huh0gQy7DHrKVom2DmYx6XviyP9ZW8Lm5UTN7Qu55EBhjeQwVJrH1c1Zrd9DtSWqFwLpOQ+GEs3wv3YiidwjeY+qgA8uODGMNGWSZqH+v9HSOFx4nWmVeiTaf4i+JEqmMo3X2Cc40y66Zpxvf0Yk362Xmu2rtCZQfl1p9ilGaYL2WeCINJazjDsZ7DbpOAi9SDU2+3imgPENWpqMIYVllhsSXiMYaiEH0dJEbeL2i90rK0QpF0pX0dQI3z9YcAH1ZhsX8qg/jIxltQiPr0yRffhT3i8Cjpec33A8W3L6WN0Sqzd+LcmXoGzSW/Hs4nRJ7ruTYTzZQlcQNQHg6cICh6L5HkCW8BY73WCCgHcYjCp9hkxYPTYhnqMiY5ZwFbRwvFkkXvOLbtzcl+gR/XEy8/glNEB4fXYK+hWLsOrOXsJaXDw101hYUbZotMMXYEnM4jk0ZojxS15YqPLcqnaN9yRyx1tV+5Z+Ly8/BWUxkGVfS6rxCMP6lZZy/n13SDBWrM8IMzkZ8tjN6Yt4rfryoMZAPdvlFHR4Zrit5A29EbRK66h8Q74V9iBiUi5nhuNeO/JEe6g4xroYuZgR3v9RVvU1yWj+fIGw0nw72MLuIgVxqCPQzvTOR7T3rNWPVwKYO5SaD7QOtqwZZXUcKy3R/EJ1kZp2Z+JjPxByEtTSdfkMDfSltL2w/JLJPBavS1g3OjREXpmtsZPFuwK+E+8reXJheePg9JW7FQ+EwHLOhVTPUULpcQT17xDQD3EgXQGa6NC+PGoqiv86YucHbv+G2pr8TQFKKxL4SWm9uYJGMfVs0jQnDrIDywjqEBX5fyDQQOcnch/GPogo9NPuKoxn+su9GRqiwBEJ74nNAcvR09BOm+q7+vNKDCmTCqwHlGN+t8BagmBx2SMH/OkSlZA5ws5ISPXGPk7HtG5qGZvLLsJIT+6FoIBNIL9wYyn0xYd0HRoxPgxFIEfbXqCzFuniyN3OZ9TRAp+niIcME/DMZQkkM8us5Tkj5bG3nk8xa60IQEFgy7GfH63W9wy3dg/ZmnQ6LCxrWRcKaliaJjodbXwXn1fzHUyGRSQIqOvVAwKAq7h0KPyUIPPBedC9AFhm5q0lkLZeVQxA6Zs7Z/HYM2lkUMWUijFxiS/rioqIFiQuH+3KdXYR/gnKOJ0CjKdbX8ThnROv0qXUZ33j2cFwMoZO6/1Yvi6fLA26bXSQ/jWZC29U/rIdoZVWEUdQh/uTIt4+1IjZyox58Ppx3VjMvT1Kz/uqY53O4Ln860bwv3Lsk8acSba+kAZk8/5akipUJ3MEx5GzUxWVPyPz/RsNiCA5rj+J42RCmTCquWdx+YPkrdgo73/bP2U+u9OGnTiRSQos9DtihY9z1yLoHzdAr9M4E4cL9rCXQTUCrmDECJJ5kuvitFsT1kSHQEUgxiU3J1NI0DrWkZnpuVMKBD9pHpKApW/b3m9YmBNB0AZS6dLI5MsU49ZY1zcobO7UROU9F+ExKcPBPxTGEHr1EuLpKRzzh05aCMIu+rm7MrXdutM3E9vV+aqeYtbkJesL8zEwzjvDtt6pvXk2tox1uwfkuSzwq6+aLGgwKnesmGQe4FpcUV/Z2Su0pPlgczaEhOu+OSwifbascEj2v/zA5YwcHi5qhbOCikPG5zDvIgruRzhOvP48xHXzmd8KUAPkwyGK6lDZ2bbuZa3cFzaN7vP+td8CE8dRbGuydzL9/wG/w6w+mEpPPLi7MUu74RK7pFoMJvgr5O2HPjry4+JjBj95udb+5P//xHgcIExneq61pDhV/rx9Rw7f/8eo1cpPmpHrxnf7w1VEo2KoxECVfM/esRyubAJbQanSfUn2YBdxC9Uu0W5oMHT9yj4XlbZeUwM+cu/sVT0eMee0sydwfwFKOYZ3C0ZhVH5hFeoVawifbzwdy69E0WuNduKZJ9Rb97CX984Ta7R7vfqIDSnTAuzpG6Szd8v5dRrAeF8Rolprz8FrApq9GcvufZhxYtQSSwrGgXfR/dC884hnRsQhoAgAh9l/YNEte2XjMERv43KzGeZyTBlqxYgEqO1sxGpYL6OI9ysGaXd4YE4JlIHewIVtWSEqM5G4CHUm77XTattJOYX3sszT7pls1s1Q5A9B1ELsr7zdJG3Xmh465Wi60Tupg+4pEpqqGDtxCOGxAZ5hdKn8va/1I8PTooe7PugfLQqhY5uz4jCT6d5khe0mOFxAFLR8ENurAwgLOPkbgsRUbcBHsBjcFsqLZmBCucVUBRZ4ZpLgNI2RiBZDr9Q01pgBZFQjdHCTSvQRnkYfigcvRz2X4X6/Fg42Vxmb5+5D+rAspQ4pEUKEFPFcedA0QNeqipmJPr7YsuUymz9pP26KQuAgXjvjL6NSoy4CNx1q0VUDTpb421tx00supBxNZ08HpF9aGGH3Wu4jpPjuO8C4yW7GNHIfAYmOu71xlhEnDdWiQgzu8qECpkCtl/FeL+zlgzf3lR4JpyIlOg+wjWzM1335LWlEqIiGC7aCiUPZqnKaHrsv85ofciHRvuKggXvRMSTykgrBc+89iJDpTuVFg8W7vvfs8QFq0y/Ox+AdDID6y9H6+9EXiqsYQC256jlUSoZ81HyeWSh0ol3UHLkHMyTx0IrzPXTXtWwvPzdmd9qKHNKBGsLPZ4eJoNFLW0U0IljL2OFZggihcsDHa4tK9Vyan39acEw9Dpl98iqSs8B2vT0//su3jtIBpMadrRPXrWPOUhdtU8qA6wPyjt9pn0CZkjY7zvDdpiZoaSwMP9ZFJimq9d1TzFQgeVVYAUkDaZhVAzk367kfTYB7NecwbCvo4H0aNotmbwFe+zmc1WH3sP0UW+zEdy+u9TVebvyTlQcwhpQ6QZsHpcdJCtLBUIl4MpeFoBkslYTUL3bnLJkik4wTPOToCkzH92tvrisg5AATG9KJlOceRoQGIl6fzWiUS9uXtEsUX3a58QpEcUoHYhXQHixpjCIDFWn4jLAb+DdB8ZWoMn7qVfB12k3sVrZEK5E7nWD9RW2nKE+Aedb+ig410HoLxqO1Hm9z1d1ubmrULgZvBvWwhoN3SWTVOlYwLlghjsJCX6queZIRuaqdMyo/BOsbLj0k2vlgp/PzxtWf0a6ptdyE2xJ8MEdk4OiAmLEHMMs6vdTME+1oZPzB41zJGq58fT8HN1QMGYQQZn39mpAOHBmlIkfAnb4pBkhHLDeQVAi7Hl3t6avaTF2m+rtl5i9aO8Ib8Rs81NtYRSkcM9kMFaqBMyIt2UHPE7SW9TbNaZryqxBt/ae3BRBv9PmpJqG4epLsgD5vOPKdkjJa3iKzEIehB0x2ZI08QQha8+39EUe3a/VezpITUSZvj6dZ3XlMZJN0cmMqeV+8hyHoe3opOYQ+3p7YfzRitsk3scdeZaOKDPepIrAYowG11xsipKFa4vJIDYF3nOQn6fSt20EWkjs5Itze2+VPYVi986wEnoWE9PozF/DIpikakPOyvsCd+muOG5le7fAk40Nwd9KGdyCBtQp6o+w7tW6RNa47NLvud5Xy2HlD+DnL0QX6kKtVmmkYyOEcGgQl0CDXlnq0hF9fEaCGdeRX9p/FzxAlAIjfFE1ZdDpitz4TwEotMcmebWv+f1C2v89Ga3R3R3CB2bGDM2yX8xzBBRbMxECGKAT4VLR8GxLH8zlXykP4rxu0fQbejTtCru4dsdW3KqG/iMrZeaUoY6M3rAH6J3cR2MlUawl/8C7HHuM4zqAqLbJxxlvyFEGfJog3dY39LItkz8UQ0hD6tWYTFNv6Q/DCkDSJ5DoLl90+KQhgBKwV1qtXqzFYC1cOEiypcfSJ3umjV7AJIzo4BjA4bTZmQUZbZpJMceBWfAiVqGxj+hYGWpFI7aGRAfOLYxZzr+aECjVNVTo6PtAhtjcOWnO4Ma7RxUPLWhn+Yw+61OAxk6XkW/IG4oSzZnuVSqMgWlQI3bws6PZ66nYK5zqZBb8kTJsb3ibotuJB/mssB/m1nuXHEhsHEfAFzT3uJONiLALa+lVB5dEIRiyf6NoZmdxlXB73HqEIRYfsmyBEl8ZfQCLzKIqIG/uk6XnUBlnhlndmWD3PdN7V5p93Ru4nmTP8w6OqX3Iw56w/pQmA2siZG91N+9N78QTkMVuRKqkjBISq4re59EYYR88VdrM5cxS+fwvOoEOciNPTstNjeKRVibE1nU9MAhQnyDNQlq+kOpiKfveRocHqS4Kso4XjK4CeIm+nMYZnGno/MDlBxDPZs8mr75UVYXfk2JzU0Ynx5gYUzuvAsihQGm//3b8fWUfybPPFAJAIuzKQYTefPJw2EosavZFYqID0vksC2FLSY1Q8TpBGf8B5/8e9MutoS1O3swxBEayC+5GGN8rkPq0IYY8yWZr6On3QHm1FNHDVWus2tutynuknJG7b9yG58Lr5qtJzFt6bdz4U2wobqTwt4FOGB6HwZByNhGpLT2NrUSTuPIiL8sgUusHvzGahZ+vUTzeoeDkaUyllL7l9UXmZGZ+FGltbv/Irhv3xI60Sb2YYk+cLdrS2msJHacngg5pmCDKeYGO7POnfH4Z0Z08TX1CNd6aQEMtKRgXZ2j8UX+GHD1Q376Sd/pJcG+QikxYRMHZFfVMU8Lo4Zmd0j1MMLZK3YgY2N+DJRGrJlaEsFNHWQ84Ckl9NvYT+wziX+dyVe1kH3q/pWuF3SubS2+AHyadsnBok2jUqWhPHng/oapj1+belDQ4pcHVAV31O6zu20d9uipCBJIgrjCWSYAFLQ/Xl0JxrvS+BRffdD72tArufW8tYm9SXi7HRrbHOxY5FrmKn2XNjBur3C+Fnf7TEamBhPBneQ31QNYVAmwIig8NNfLuXjnf1eNxlCea5bJFsuEa+waxp7GYEdNp8/0JuDV8YkoSvNKnU4IscIk5pJFxztPUot9eWsCTVE/aWjls8kdjk/swxVtF9BxRcqpzMnSccT49Ghu0Cf/419D+9Te94FpfFU28xVcJNSuFk6KIU0hNxv/AiL3XpbQ6M6+k1643g49M+Yy0Fv08kdK4t4u6wBYrj2tA14KhAwE7yzLxQqpOW2m/QYS6yHE6Mv4eBxfn90ht4bBz1jN8uBDE8kq7OuupucTLNPQJRJd1IZWf/xmwCQKr2+kUJbas8t/DXOTPrd0any5V0ZOKJWGIhNrt8onSZG7DZ1JkhAPgLgu4WDGUcBh2ot+37hzmcTZBpDXTXGApf1YZpnKB6TsKk/3Yp3evQDM8g6g3lHlIuzM3CpITpRvvZ+egWUB/eoWfVyZ9s998eMfXUMbISFBgCOweuun1Vhd9NTJkxqVNTjTB4WEKBIAAImTmH0jYjtHpVHDaxZVmWyPb5QVTQrtX92Jsm7HRVaqe6GCanqaolj1ON99wAHvkkBauAowTDVk70kBgT62EJ/+99UOAV2E9YL9I4z99CTo+V3Rx3OlPg1QHdkfoac543XuZaaZQ382JHzgRLgLjqn1MYKac438XvR2kAjnjO85TuhTo0fYBMeNJEX611FVS/bBMAK+FmQxPtDYu7Guiu5oANCTxNkHnJVmBtIh+9RA5WbD4/MmGN25LNYPIjHQZR+vqjN28VGy2SMxJ/rGrNJGi8SB/yVHTp6xoihPuimzK63WDd37dT97CRVPAvaRegdB2iVqNAOzFUjS1GS8du6oZIvY+RAveSL3jkqRboLyv0ZQjdTGxSVxsgYwxyjz9hj9qXmSKupj0uKeMDoHNBfd0i/NTGavugFPn1l+D6D1NFL1m9PvXKUlU8U5wfRwl7l9k8MJJHx1d7VzKjbhOqlUq9VVIDqszfHgYUyNlSyjKSuvLJv+Q6dgElRBuGB77G2MadfyCE4iQujiX3DMimX8iBFdxCwzz8WpcZK9ODmzrVrJsoqnP6odnxWLIyASBAgyISP+9ol9F9OMujqlCCcMqGF7HR5lCBtcDpl+st8/hgSgGUH53n8AbST1RIYboFLUjriWkMCJTt9032mH0BKu4ICj7SMQccUv0iNzLeOIS2s3IkdX1QDZgLlwYhb031Mb+fxpkn2E8EhtuFJjDaUEKhn1WI4uX/zHcR9NfkC1yR1igJeb9N9bYXo27pDwWcjH1SNYcztVerEXlrLyMaGoX6c8wUtpQG8ITcpLyrnxnumuGpHf2ru0xtUMI9ZGAmP0sGL+Xc3/zgIRF87q2PssXg8ucKVueATsr5T6FKff886Vezq6iLFfr0LF2gbCFYoud+fzeepGeGpSJwGRSo7x6oiHaq2dacL2nPfy3y2cJn4DzROyskmFazr3oNpUXxyKr3uhwIoJ66sao7ggJIZKIxPDrdrM4SfO38OAn4J66btaSR6ZUwjiqbhW0PiWwtIXFLfexq5sDXzp1hjOnz+XDGTOaXcSZtv6/CYZ7Laf/MLy6UeMM1cUJd1ylhbslp0rE+RAlUzYDDtWTnByT5npxvtheGnMZUCXUo0W4K/Bk7TC3UgobLYBR6n9yk/F3hNK/0B6Z6Vqg3qSu3VKogpLiKpx7yePULdTd4PBHpdlZxbbulzZTaxO2aeoMs63EB6vCZ8aMM9Re9RsijhPWP6sqaahz2zt4HBbiRbHSIn3gJZG8S2im5tdtjuqIWfaFhadQJwfB4TV4uauMC+tf4T7Kji3oQ10cnDLZv1jwudLTgATZaxdB73VetQ3kcpUvKMQxUV48t+1EMWOr0aA7A3gGwt9lNfdXqC/4W6brnI1z2depShcmTOrht60s3NSilgYUeZnYIWQuIFM6mM8PW4RIUNmRINd7OwyRtHM9AqN+Z2Yg44NCsRvei6E2k38AnkFeMosj+DW9fGZJVQAg0xZunyrwQx/f8lRBm1sCsq0iNXRgrte0tTfZwv10qDqeBvTmC3O9tcwql1dhBh/TfeXKTauT67BHvQLxN6D/8QWzD2q5GLUwsj0VRmamu+lapt3UaWEhoeu1TPvMLFQR7jNsKwes300gWpEqkOZGmSZ3vN2gKo4iEZL7VkFmQluunDTIq0N8v41HE1FB5oEagnp5J6iaU9l4F38KJqoJU5N8hsN5+mEUqNSTZS62HfPBZESum3ToPuN/r3S8W1jDAgmmdL0ReRdD9elNeBW/wtthDy0AathavM0mJdegviA7mpODawr0OxXuC0cb5ZAZI8pLljAZnydQGWGkEu01RKhGmKL5FdeKgXaTSoquo1Pn6j/nX5uHyoEtEgYdzrG23HQ64CfgEtbZ+qjahgimtor27/8yNppXOyLBojGFhHKW9mbzkGz+bRHbfEadYUIwT2fsgmBBAsXzQ2ACLt9SjxBc1iQ88WYcvRMGKnzu1xFmpmU8ERW6cPKc9ZGhQKRBehFlJp0xF87ZwtTlvOXIdCpEkulA30g9VP2gVefX7b6Oxe6jRDPxh9DFwRH1fgXZxDlXWgW32w+wZzjN4C/mwm3ewqfVIQYuDgExGC0ie1OzEd6H3Vl2/K16bxWrSloLD9qySjRejb2hIQI3LNmq1ClG2lQj8OeydLFZ0Fxxh9uZ4ZMiJ8Hrzx6BSipk39xa+AHZzw31jbE6ATWnHblySa+YP2VywWlvO4C8xlQWbCI3DHgpy7TyFrewx1NiDs/0Xwmg6JZzudcP6uqRYfL78tUF4abOw3AAa0txacTM2TeUcwDDQewNIg0/OxcB7ToE2QHJfeE0o3s8yeh9dFRkz/GmY0hD/cMlkOeqDxeBfjKN7naR0O2aSH+4LAgEh5Ft43bKBa4BAMxnyn68G4O9VX5+2KyXg7GH4Op+8QSemIkk6wOjkCsx49MMo2z4GRlmmRDR2EAQl6UJ80xbVfzT+Gnp1GQ6wxOck/1/MPoJs6IQN7mSt3EmozvYvYtV7aWQqetN94c+99bvNWBz+ao61ClEJB0yz/vffKas+keF1u3bBCGMHxh+IVq2yTW4DpQUqiEB2zEXOCbyvgboJfPBg6MF4cEzwa8CoUN+zbsNOEAb4cDjMGSsrgFKxusOOU/FHVFTqiu5Xc7zugA+fT5zfZ9KEnBbxLn1GsywPVS+B/B5Wf17ofJzfIGDwcATuNVFXiEyQNgjtiqh6CQdhSZfme6yO85L1zBtRVv1T9hbXHfixS9jEOMs829m+TNNVBZXui0ziRi9i2LG1Aru8g9lZouPLOalruCH0nCW18KfrQXqhS9G5dBdychTt6f4k6Tp38rbfhPu1qeomHmVu20T+eAM2HyWUS6h3xcos4xjcMJ/WNmeBuR0MvlVaAnyMcc9IeRVVhAJtu3UEM8VDlsZr8qZysSyADxZBmT0QxJnfxDNhJRPNXYtt1McBrwbo5IwiJU2L9Vp/xkM82mbiUg/I6XqUE4IhTYTMz1wW67sNT0wksVsIpjdrwWWZjFXxhXlnp2I6J3603csxs0AxDhr8Udv2OdCQJZ0tQZeVG9S9QYcInH1SU9jNZGNEqvBsna2aYkyozg62u6EmkpdAK52Ud+bS6caWInxxrfa08CcxyLHR68v8U7GVa43qG2EsKuBtprhehe3EdKFJId7Kn2W9Lzy+Gg3KvPq7eiNFfqeucuaEFbSbDtQ03ADcHuUpK73dIOE1sa+ufH6N3SstXw+AjqDIv5C87AyzbDg7nrfkgnASr+1z24Z/VOGdvg79yzLkF2H/BspaUUXN5jl2xOAF0X7LwE/DSFXKrRBK6OqJ8Y8TXm+NhgoEdv45VgkBTmVF2fjA87uTXmjZPxN6mlS5w7Jn4aDOjb0GWuQbwpDSlaMJH5KQXKodeiKFD46LZdGG9ZyUCFnAASbBoJmrxuUjIpVNlFjHgWtVVwBo1Ls46dpPfflbur9cFfkC0yMNcIDe4YkqY75LkigrVjYS1Tsp2ShXvjcsqbsUdWyF3zFox2U1miynoo4I8kllEXn1P4eUDT8KznvGdeTXgn65EjqK4y1hL4Pbx8leveV6PlzAQgtyQPe8n3+lbImK/XVYwKrt47ybD6dO8wDfhebx440SHhJM4vnlYZYIpfDGYvhnpqVtbvM2IhcUzHaK9oTWTtCn+Y4g8iXFQJeGDjr5MsroE9AaoJttSvF9Z9L+9hwHjbI8UR84AJxBrizVWso8lEtEjsKZaIqBtL6GPwoP1mzyfB+dDKVqZ0RGwKFb1Psa+8NYrjSNx5mcJaRXwVr97O9P3mSminEUlO7i8Ta/imGO0VS6AICSxa7LYEI/0J/Ac2YWRBshJoGmcWSietf+M+VSjXnJZEtVv6FqOAVSbbNHJtqyfwsXl37oaTXs5kqL6SvJCXMlUOtIaDO1TxrLMg6I8O9Y5PEFj2ZFRMh0phnNOnzw78C3LNB1F/k74a4bia/CbYLq0CYIhrbi1Kw8EJXo1vEmihew0QS36P7r3tyrrK6cXkqynfy+0K56FJzWOSEMKVAGweldbrJ3qmXhELAHdJoqolECtuTpMz2XXoQiL96eq9RS1hYZvetfx2dlmtzS34U00X+rYMa8YayjJJR9EBNTF765OygE/+7pe/U/CxW6WxTCcm9JmcG/dV+1ev8Ep48PkvnrptHl1uTOgnS1AF0qr7vC+YYvNteSRo6IDp5Zba8CTwHcT8k5TmSBnydCjjRRS9SQLPQ0/J8L0pXwBXKvsh+MAlPmUZteXXL0DRHzYmR/W+uLtxmp1bXs0mAqPC84eMzexQ3BY+vWY6pPb5IuqAefvV+wravBM7rq36FnIwp6kQIRXqR4JFb0hmojEklJj+tjStpf1RuV+sBpmkK6vO0R1CKDb1XcsgiOd9UsfF2ugnx5dnwJZy2L1qZwlFYwBkpr3uWT8AorKesJQX0FHfOY5TvhXBGw5lHB2rKPPfH4uAOVUcxxutiKRNGzfY+C1E/7Kijo7vUxhxkFjwz+Rqx2m0S6p38ekGdxZfc1HiZhIg1i2Kjw4CMM/sLhH+OGZHK5gis3ilIkaXUi+R3028oDXRM1uGND2RJGRpvEFIksRSK5wmStHxP9GJMtVR5o4udk6us8TBHW1fLLPxyu1gvG44V9fEtBEY8Bhzk6a8p6TDMbG6I701S+hWKJiZwUQ0IGYjdfY5remFqikNel/GZ66RJURtnDNkt8Icpf/RvQEw3rw0IvRhX810TV1DxqOxs+rHPQvxHQjq2UnL8BI4fETgOeUyL7r7wNIm/KOwfbx+UHSOjdKnmjFIS+9/0PLEs2230YqpDnpon2u0SjzvGtm9DYn/hRuvje/kP6x0KaZd2qGdkJDLduo9PE7VmmcIP/TMHLw8oRBeIis+hol2GrHkQ2MSyD3kaOD75PPt6dm7foQ1Uiif0Mura9zqtPxgdJQzpdw3FvRqMqPufItzOJmfujtKhqLmy+DiAC3Y4+3kJW4AigA4f5wmKNs+Hwm5DumKhr+8XkBxrjQexSACNjNQP+oIKk4QIsOibN1HxN+s8p68S7h57qBZQw1vFOTNJKEz/XIesvdnizD/NM1nJpNWPze3CuPhVYk7BBjX2GGJfuV4UN+UC5ysj/R/MvS/Ir3jwo3i9c42z3wsjMudZ6IK/wy3Y6TjPwmUujri1qfiY/ctOcKARA+CEZA/MZnQG5bNplAFdcl6yjKJfeSiWKZXFNGCaM4u6/gKfBncTDNo8XRVHbCrla87S3ZMB8zajlO0oLXFS1Jywoi3kOlOSdYuEUilV9ASscCWLjPaS4x3DcI1Zf0lIfD9iJR8RxU9D5/BNyFnY+xZKuMfWYVxJ7De/eZ+rSgyvB2mvfFBJtYVk0uTVt2azgZqXMyohOk64z++AhoxBx91cpt9ffemGZDz6PnhkRqE0EgeVDJ4hDy8w5/0Z22un7dsM1swjEG+cZf2fNW0zt9TXjQFX3xXDpqDNRHlZurk1EsIaxG1X+wobUMcj2HhutV3LHjZmHWhiJG1TkD03xEg88OYXKW5Rd2iFqKHFSUcmOWYC8AdItsIkPkXAx8GTml3sFyHADeY1YeqRgdWuG5AxdzgAysGiEqARJc+3uOlJQd7ivqWJXFFuWtV3Zr6dsynV2ZJjE/683ECutimS/gL0+bu0vTbU8ADpOPNsExBF9bUmoDCdZfU1Vpo2qfXLUcGtETBt/+zqkCP6ucje7U6A6s8A8sZg08W0rsgjGgOnhSIfFXob113iblVnd2d4q6kH6ZZgCLlxTIQY+kIwzAZqGaduCf7AvektN8zzhqntJ17hrKsfxIY+ctO748K7sfR1gN9A9WJd6CKlAsXB8Fu46ISFL7HRNSS404NUQ94/HrGtMYKgqMtHqRM0rqrGxLAhgLVzojlsLPc8sfnEwFrtsGe2ge+FK0RoMthrQGIqRw5qa8c+20RCaGJmEqDj2DojaattgKEV/SSzpEEww55ee+1TVWO083OCDW1O2MrHLA9dK5WzED+5U7NPbGjTNKxLLxM5VXlKloM515BR9BoqO0kgV8a4UT57UpvIAfsYyBuUmR7ZCg02V9rBrO2ThIx73qkNwaUeWo2CdPVgOm9+ogNnTGdlonY7Cj0sr6Lk2zVxTsZ3To5E+SUR3nRuUDy6kXJ1XSN4GJtnQpk2RusVswC/lGjbLb0u+0vqTHq0rT6h8vxBSkpEnGNZ03fAQftHUczIc23hoVCAz7dDH3ev01FwKqkkaXJBwCdwYm/TRCpnSX5eRZqeyMagiOeemYc2GekxM+W4m/yySMPG84dvOfCLijotsrS8/ekTUQPGUqgTt6UY4PvyY/NC2VfL126vmhK9wn4dESn8UA4hoylOI6hsxUby0dEDL2+rU8KwyI1Q80PMAwB5wZr8Qc1s0oToMrUqwsaWRDjEVY3nMrRhGUCpPdT0CvJYk7UNWuXMW4NG1YikewbAJUJHXk2TCA6wGVtrgvre/QaburPwnCv7gXSNroebBJzXr+jZHcn4XDKT+KWXMaxZZDNSfTnFNRr2GPOyOETxImV7Es7ZKBlO4uOrKFeR+lj//ZSqXfIggm7MoCuH79xloocYferzLJkxlv/RDw/2AT2mjyPk84IkLLwnNZD4+naVZjmzD9oEU3Djp1ifmRf+wQaqGNDbHUR2iuYkwkh5BMUwzH5vgcWEYCAFGrdh2u3zZgKiwd20kv8C2YYU4ffOZ3qTs2QAiH6mJ3jLhgaMvLKfL1azTZYn2I66QA4+7zH2iLmWwu1H53n2yVmeb8eYoX+mw+7FZOJJ+lIeKMi+czCYRU/ZahIP/yKuyJaqCG7Ux3yQKzZlV0aIbm7cc45Vh3oXprkd4KSvvKuWcGdE3Yky9Wk4ZPkf192MlLPO4jJTzqeK4hkrESCveKdETmCnAsBf4hFQHggJepKbyk4IaSRSHwPgKiZUR/Usn9X4OOV9uXae1iSyLoGGZSSrsoiS9ZCHDqq+HE+CqG4R6Cz02lz5XGl0aEwZOHm7bv18QfahwpMZv/9BSMzMP686a3pEDvY351/z0BmCmApKhivxR5lr/aYBJK7ekScKyh4eZnMwj3c9OL+ULtSpTsI0NJC5/jM2AndJFM+KyRcckYi4vh6s0niYGe0sXHaElc1+o4wEdxKXG7lfNjMr102j0c9fsM/oPTPdtfHsZLsTF/HX+aL2eM2M3GjHR/IvexvcCLxX7WzHj0NkDt0n+MMfHpfAka9O4oB7fiATVBLVorLBuXHoz1O0usxw55G6FNKC03r+wPpDCAuTK+0bDe9AEsqHZFwAWCvb+JEQDKFGZ7IInOjrPPL4D8zVUxiAPT3zcz61xCQg8GqEPo3rO+Px2DYhikrWVTLbGiAwOravwmfoFxobgP4Ds403Iw8Qzxn/pjdjxNaGZnm+d8tf3Z6ms+JCOggLVgzkCXRHSFv21iLwQvlQZCbiIIqC8DIakBFILbbF15t5SXUBd2ASZMNXwXEdeCW8mcQ7qovJ9Hkvy0r0Q917xYXmWFTQqK80MFRpeTuJwZzAcygvuyfT9ujL00aM7E57Pj2xGAXz9JEeYWw7QDQgrQ4xFUrP5nsJzwiifStpP6BiaJNjOF10Y8d5LWYi83ydzD3E/Sonr8z4g8dFSXdN1YD89mAIUoTyaM/71VGChVDg60tCm8N2IHwsNrGqajh2X5nmHOQTuy6MkpUqTLGwxdiTha4kKyB8RrrAsizRdxeMLTzOLejZBeuXCRAUyK394qwDaeUpqNZ8dkVYDr38pFftU+mdW8kXH1H8I/9Tu0QBCqqcFmY4Z9MAMQpwIeNV1xUD74Uz0cnBV2izHVMeBU7cwJuAi1i0M5JRzOHLdiK05W8/WxdOQiP/gH5klGaa7TWPOjcL2ND3l49pP3suIemE2cyCMTmc7P+YmcyYU3XHLUizx//uwQ7AG0R2mxl5k6MZ1vEzX+YyBVfwCSoSy3gBVyrd9h2oqCcTAPBYXoy86udjEdlGIGS1HIJY9Do/It6U2WNybNfZQJ6Pa3nW0Dpcpbmsb/wEl23LTm2dQga7VmZse3ZC6KhGTKFCpW/jJfMzPxZA4zgvOqR82fe6X7ql1SSgImCMTsQwo01BrM88eZy3kAWRWK7k8J2cC6EYZU04F7UfIJouKj/AGfBxuCz4ss+K5vZyqS325TdT50+Xf0/MVCNm/eMDgGm0BJVjlq9+5BBnDROwBEWiUcie/VhcwpsXTXI3N4tlD22G1HraLomwAjPnqbKTUCNfrGpwkyshRG8xnux8aSNH1bKxmczPFsOZ5E+Vja5cPAAhXzQehBVwImum+yknEs6SC09WsgCH+Nart3BgidLuRLrmjFsMHLZMgbdAFQV4H40sYrMQJwHohCi6BT9UG+v8yGjEphaAmFGs2PLMlYjMEiSKG7nFemF/9jG1pc8H47YJU33qnhxf4Xi9cNJRC07B0XPMwcJ4CySXVRQnmS4ynDJeNVqZbdUTG1OhurlYeQA6SCQ//IaWwuK9B7yPGs1Fe4QbrKzRZJ9yKi/zWNo6/xM2tDLA+5Ie3cKvgFifcH6CH6FdgfK+79/610WxBy1hm+HhDeCzNZ/a1usLcxXNWxeeQgqYb0e+rM/UfxT6DnlQUjg26ioN6SkwLjLjpR6iMZJ+hd7D/4w3xwcg8VNTNAh2gr21tkJdCsaAO0hYNdldS1o2Gd7YowflZwIhg3c555He9rI0DC2D0V2yz2CtIbJ3qfM/Y5SATr1WKnnzU/zNNylaEoPS9vxVNtXZZVBzJTwcPbwe5AgGp2RhD23rHHU38BeGPnkPduBIC0LMAQNLGesyL8NFUMOLAmTq+o1RDhcilaJ3NgB8BiE153kcSWSGazRk8jPqe7lDa1bO6tmQ3pZdaK3ZoyY41t1yNHDJcoPGUFiB7RDHOtlZ6S8vjrvDnAKyiROHXC3jLc8qSU421lbQjX612rMTZou4YyL1Gd3RGhskmQAU8l0zHFHn79of+2ezYhn0hRx2q8Qvz9A9DSJq/UohjySBXhewQkdmAKzyj9cZvZcTRZkTKBv0ksz+FfI3l/rNT3zni4aF7zOGvEmijKZpcO47NRhPuLTD0cg1jUikCyiUMzZQGribFNG+Gzr/G4QXXGYgCdJO1MdmzKKVBtf2+jQ7n/pyWzUpO2kH414XPo2p/Kd/Mu0lzHs42r/kDN4iS046PCwhxRy01uYH6xMbLbyXTk/ew4VP5MGfcS5oSIoJPm0grzeGvniDYqgHRzj3J250wyzFK7lvQ0Nk9jLCdvVKcrMnDO1LM46Z1DlvsXagJmCZwzt13IXHwzDosK8LEXDp7AaFhM5KYBbL0X/OcOHdSXuq5CdYDG62SpeO/cLVF46YZTdVuALkUamJRaWJksD9rW5m6FdaGs7aVJq9WNCH72QaqyzrbaJyH4FYctpEMHNzI8JFVYxb2R3GI4FTKqwvHmBRZV/qMBVW/3A9nZemdtL5OPA8wzrc4KobeU7zrKP5f5eZFPYVkBSWt7AVEqfSHlpOQvFavLuqfDdDC4aEDXTBwZTtCz9FcaFGheVO+/8jAYdpAP6JAzuIS8ce06kWZDHUYASaXRpr6dTu20CulI2zAHqqsNNb3vugiSifpeDnfnrwrGk4D7eaLf7sMtTZZh1QSqA1DgyaK12OzzRPjXvbsNvdb1Yvk2aa+xgwAanK6gwVHfEBMhyS9oShaEVNeyT3e+F/ANfF5ffBpeVOWnVzKIJ5HS64akL6rWTdVhvj1B39J+X0R+X6/WWLUngsmAuJvrgO2G5fbUyiluf0NXScEQIUgrHbvv3re7iYVvrOM2KRXUCZCWswqjcci2E6tVJTRQraYokv89qDesZyDMouax7Ipi2z5vOUMe2UCoeVaFhx0JU/EnxzPX4JJA+gDK3BsVZzmQhPmfpbLk10W1+A7rUlzu65n+cBOGxVQBGslFW3Z68m+GmHj0tMV055tRWs+zQtj0KCt8L/2W2CmQ7PGH+2e8or2zE+inuKkrsHZfNWtuGOKZi5lTdc/lhh8zxjWAiR7GK5i3DROs2/EnhUqiJxtrYFzMSnBIbOP5xrDo5SZlJYLWH3kga12JPG0H/FCy/TsgxueLv4ZX094jsxtzJQU6cNbCvsuoRoGqQ8zD4B1JCOtoTCQ0lt9bvbrMbZgmE9k4btz2QfOwCEHBV4BZzTyFxKkItRPWJI6ZKukRecwO23uLsTEMHf9D1478AVSqC4TDNJDGaUrv0ZIKDMgZTMM+JCMHF+RPiD2/nNEbJEHDm4DKI20BWr/mjPsu+S5QrVLNbUWwwRwRnMUvtLoDjQ98OrhacaNJ9/7dfcsJmRKi1wk7VURxy/BVGhv1L8TCD+8TrmX2VYZjYNu/ZMkoD3pGd+pwVPlISI8MIkUsPX52iWjHCWHlcvQexSMtxdAfH1OH5zZZ/ahEQWRuTFHuGdrPUiRKz2ilBtMMeyXS0iRYHtsb6QZPObkfFB3hv9no4VVqX4/HYybU3SgRyB9v4UWU4OHKp/VETzeizBgSLbRlnXIJDluSKOmDsrlchoMIGXflUxd4Z0CwWe6ltxZlFaW+CNmh/CGsIXc268Vh8x6uUspCPwllczufHL8XGgp/GQ1qWGR5m7YV3NrmSpwqjmWT/LoMxqK5CnW7aUabodjHDRstsMXOfgH9oavVAnYl+vJFXnWZuC54tTRdLLYaX7Q6OZtAy7iJEAIF/ZOBOIlW9/KYWme5EkGMnYpxcvvdpDk07pEpqDgP2kj7n3xX5OERlvZskovmsNLlohYUI309RYEmv27GvOWvtvYcHSra1qo7YpLrwhaVN3+E6W4Sgm5EPQhFZfZNABideWJ5BvcYxKgNAHvF9xf/+hsQh/PrgDZ6bdMoZGiD+1Sj+wem/iobD4Fm66QPEF/Xy9MrP7sNpWE7n5vtxXE4UOjAiWN5SEBZ/Rk2Vehev6xPuL1NLi4jhjmmUtafH7N8R1w4n/iy7ZfETBRh7nUIC8qUhMl6k3ceKdj4mWjtD3XenvpezeJUCNWtwmY8NUHostgr1lhS8z4uUPMMkELkKnd9pn7AngqC20KIkdUHdT5irc9WQ52hLd3lDbt9CS0tyGGG+Jof/cwmqCvzqxOF8NhxubJVtGBZGtEsD8G+kj3IqByryCe7ZvmFAypfYB4nk/Gan+/xjtneMlt/alNmlv54hbcUntPwcGdC1UIhZ0Bpl/pL0S+L8+dxqhxt8+7phZpLT7PX2NNYZ54UgH7xk5ox/SRgYGvsjv5y6Ti8zZXw2O8d3N6FRejmWYUaYMavlBqa1g5nDL0ccLbIqq1mlLGcN/vC8klp3I48eWbz99m+6S2xPnpQiNUglMOGK7MrZOIXswff37YjWeHQ7zv3HsHPLWO7AIn9faD8HWH5yQlBVLoDmZiU2SpCCwP79/V7p+yJgWR8w3apoN+WfQTOZyz7mxd9GlGRiJHuNrgOAT8yS6GByAOyz6C2BuFRsvJdR5gD4iPI7vq4LrlKvnJtaMw538JwZGvHNN0D9l3BCJWjlN6/0+DDgxUJhGU/g3xiasNFXbJ678xwk0QblscukDryOh8PUNkufssiJyI2AQ5EZJezyTLmS2sn13ASBtmjSmNdZb6z8ccgoLtBccuCPkWGfxi7xlT19QGF/KAjM//X/kOJ9/lmY4cVWYBMPCcnIDfCJZKPwpuGMfxsadfrjVFBKJYYhNlOmottWziMLQwLRNjJ/EBPei73LU37h6+MnEWQp//zYaDVYYbWPRw0T7lvv0AaY8AJ1FThs60V8owCgXpAvpdUBSsMNuyN4aMyDiXZ7OeJMeMwYonn48UHv7DUzRBq/jgKpu1uGOGwIVN8ljJEEb00OKxUdA3/12ser/XjvbgKl4Clo9H2a5b4o7l4o6DyJbzdnPlM3hAosaovqR2nVT7+JR3p6H3ujkPEfhV4IMU0cV+svHoDUI1yR5VKF0gJ9RBoKzKJ5zMyUUPBHur9CWIyccHgDyX2XF6Q/fKkYpK0I1O1PifUCiRzAV34R8oUhFLsOXm9wPY5Sc1k4UYuroZ80yauxRHnFrCqx85EjlSu3yNT7BjXIDk6c9c1gfBC14ZqNfOrN3f65Tej0cS2675IGMMRyVUqkJ37PGUuWO3thktYLexaTtItFPoiIu+sEpWSexii9LjVRuP/ua2iUALQBf9NIRNnVcVpZJ2DLCYDt+PF9RBw+5160S5gC258642uXp30IIQXCjlPZJwBs90f/kpDxlxoRholxWiI46yvCXWs7owUxZjqYEtW34wATQIDvprGGvvtDY0R3VZ0s92cSakSzMFplZb9IIpLQwjrHzPKUAq61suKTE5LkXjFwsBHRnR+gwYjSa+nl+Kwbcvve8F1xwWQlUo82OB0QPuwjwq3EpFBV/XR1Yh3BlWH1zp/BSKVwGMKmEZfhKsJmZj1tVkxhLJxDF3px03kVZ8l0J3omi/hmTVAtzpGekD1nIZDj1Yrf1zo0d6aBUVdBmyD22Y8ZQFsHFYZg4HNMyx2PvWG8oF01svvbpoX7HMO7QG6kJKg5CvP5joM+XTeI/dMUfX9CxTNNmhPc9enqUGPjm0A6XkjIH+DkFl/SGx3AMzBPYSlKCS3HfmLHPtgCv/NU6KGN0ryqVo5RJUI4h1POLNjYysbspKln9ZyCA62BOB3ro4eFDQYErEYL+pD2dza93rYwT/zbNd5aXhxDpkhdXH0PS1qla5klUofTzfbbNgsh0kxI7nut0gx4TQ+7FmFkw5UNOCF+dSDfCtQsZjpZd1y9YGYgl2S6gawhW/MxF3G6y0DibAXvL1ov2Zkt+DanOsvELEquHaMoMUAT036hybF9/tLzfbPhpi6Lnm63tlxZMPzuJzDfwsxYlCep0JAB3vS0OoauQRh+xFd7T1U3dMERssi6U84OUy+RStyuDjTupXh7ILt0zPnNN9Sf9RPFABySA/Pev6dwKn+oP5b5tnChmr5ex3yKWz/vpimntitpcSi7j5dws8R7u15MJPZXGEgfKJdNaWyuRT96HE7581JDxJ/JVsxz0oV7XvXAaCUVFJs2gpIoiRjVnoQ9bk61H8csaUOY+n6wNiqZgu7wsbKJGxe4ScUSaF++Q/0e0g1ctZnYa3mbmBt8aWRmiA09K8j9KgjC72mKa8G4gsdD8N0F/jH/k/yW5cNpPyI+RIei9F9W8h1fr1ipUxfeDR/2x4Ixgq7tbd45BahkeXKi1oVx3z91gh4GID3KFog0J5HO/TfErPQENmqKP8LsSNJAGgjp6q31snEAfhrp0SG9/Ch9Ajy2gX4sO9T6Sp7T4GWf9+ie244aJTAlDmqPmS06yqIFrpH2mkTcF10c0FiNJbTzI75yW2U11XLsiMkPK/NEAUKA8uROnJLzISl9bMxqEFpTcSzJE7uvJjSvrpg+QRqeEJuFkbtK6+bTJ9Kj7NP9g6RB81wEms/n6Tc6+2P0npLGGQIakPdl2k0iTYW/lYOw+sdUmt4Ftzr9V8b5tZnkRPwf6faAUAmDAAA427ZtTrZt27bNyfbLrpdtu/5s28Zk7SH2IB9OCmZzxxj5zb0bY6vjYuO7Zc4JPussRUKmcPDFY8ZxNJuwhwQW5GGDXf7T5DycgHWbEMJNyix+RVtREZK9N7S9UGAhAAJaZI1AtcP3dzEO7sO5U/aTcvKMfCd2BUgmSBIuzKwbmHgfHIAfimSMuTnjmSHR3DxhOAfJmNMDprbo5AJ6w3yGstz+lccaLH+d9fIKO1BdIQFR+6o2W+byhztkjn748k/Dxd/Jp7CB+UHQ7zaLlG+xkli9pR6pH05UISV+iwsH2IVFcxdqMx73mlP2kYlJYxkEeVgh6xk/wncVXgmiH8ElxlavuG8CRiYVgfyPZSnghx/oMMwd53FqvIVF2pNlGINZPR82IADRxu1tYavub8sT/UOSJdlrn1Nrxpog5OEF+XkNWPp/zJnFVNNYFX9X/50Ve7g0JtI0bQl9pa6te8sg5DMHJY/n4SY1XHDVk0V2fuH4RcrOGCeYoxlV8MCH4+s7pZznNc7DnAt4wb14rt0H15XmgaJbUyI2FaZtaYm+q+tr/MZspowPdC1s+gCU9TgZ/9OPVeLmCyTRGRaQvm//hx+btivIml4QlMlCFK9mLP2dKKqStkR6Dtu2xuALHLJhNIQqjUN8MxE8L4pjk/yabcW0ZeXw1T5U4E+Pin2tpru8xd2y8RPDK/JTJ12i9XpOXuT1yRhe/jfSK90T112tKDGdPUUp2wx8XhSU04AD5PKK8DpHs4jq6VTddrRdC509ymXSgOlZGBymjrcQKZDFbnAE6RX4ViKVvozzPMQCLxlF8nJQtw8Ey1pZLyOXxx4SWjf/rm9KSdfiue1OCOecK+GhY53qq2RULQZCW7o7CUj5M2qnxapZ6lsmadupWbDejfekNRSSsI+slJP4hDiNL+w4U8hXyu3Fh/rsaM3nABzErWISkvb5iAap3a+BPDFWRmusuMUMVOsB/4VW3BB+XGlTjKaP5y6CdJSbDeRjam9j47d/4XIKvv0u1IanyRl6wIP2e4npWTV3mmQxfQz7HM3V1EfpZNVemSFU/R3F0LdK8yOPuk9fGD2EQnD0ICu3fn7tQtHoiVpSm/eDNKWvINMIvb+v6W1t7A7kburv2yQRClkxi/q055XTK8xPJGHUFQZBdv2pApcgaZEr1UgK9anclJju90qU1pHsVYyaPXg62sTKumtMqPgm8W3/8RY4I8w9qrz7MazFWMuxrjMPJCBUDEo/p/jFzpv30EOUzIS1TZllqAkCilQ9CbaY5yepaHhwgwOaZtUbl30L/9K0bK2jotnK4ZD5QFQI3Jrx/YZBrgkOYrDV13dny+yAh/0k5WT03tIKK5kZyEsjHruByrfCmyxAU2FTU+6IsPbbXnQrnjCNRz1e298Jke8qEcot6+m2q5hL7zzrynOliIWlnWgWj86HBqSiPQ4DLOkYEnriDDEc9NvsjL6zNTWEvbYBOhdLEjAvGy7CKNJ2FULPz5ZiE4x2+SyXpNlQfu1vk461sKgvkliU2zgvcu1j9JYa1HhO10uz4yGzjopEoeftAvUVOGdJzybuJ4aqnSzXWqjtXuJO/7Xm5MsLrl3m2SRYPsjQ5In+sak2uB6qKYFOGE1TNNQWsPCg4Z7lJwWQzOxG0e/GGMCMvPGW7uxl7cXGHnbSssKB5eXsirxNaUy71ZVaKemM2BNv8jdgimYdLy4G1z/DDvl7aEECErYg71xo101tgZJLwnZNFMtzgIYGGi/P8CkMjq039JD8VZ54r5xSEN8Yq/wBK112BZt/2gTit5evFMuWSRpTp7+CWrjChLg7Ndkns4tj+ZITlIpMf71yEl9UzK//GRL7DInc9jJv4KrHmzc175GIwIHaTW6MTkJO2L3es7OdNfu4a6eEHKWwppxuK/yj++d8uUJYOFt0Z00cydafRYoTaGr42U0L5FEoruWQGR+V0H6NaCwJ1hvBYoHnpOfW3bygTiw6mtICUWoNluRG13jiAB09fCwK7sS3uWRhOVRUvgZEvs10tYGOXC3ILNgA/f/jLMQj25eSToUIEfOuajO1E6+YvNfqAJ04DtC3Yu5lykZLdxZAEPBaD2DDHzrzAOlyFsYAPaYZeW7iOJ77Kvp0ouvNgEThNt+n7v5z9mi8SkiP6hrgASXJ9kSnUXRekwrkbLgKGrH5qffrG5ykXBFoQv+QNXj8rmEljVygpoEI3RsWgIzmemTnE+AecZJGzOfV64YvtRBBtwRzmaWIhNMF302xpbb/tXJXi6wMd3da6vdXsuYXWa+3rXEKr3Vf8zIax9lqBiyqCHHEbZpMnto5F+ijESXfMcmU63jvvVjVRsxCZ5Mrv47KlRennE8sVyzw3A3u94wjcQb6zhvaLPlCBkKgbxh8504J9kkur6bA+qKnNRGfiamTHrHYVmRSEbW07m8/W7R8ZgbLLXoHSciM13i9l5PShntVyXLvZ6I87vjgsgHnS/erqw0zvXz6gu0FF3j12sghPoYo3OJsmcZ8NBtUTRmPMugOxtMpv7HsOlgoVMQNSyhM3sd0VzPFpPNVyAfXEjsELnXdyn5zfPNRYZfblJCjIniIWYWxFQzTP7KsiY2HrvhDZN6IHFIDETnkeZEpUqu8pNbR+6VaycYwefLuLkD0SO/8MzpJZpe0lNDTKXBpeDEVvFNNlzqsY7P3+7uGrZYUQV6TPxZEsWvAMZN4NvDqdn5jYt4VKSMMI2hWlh+CHVSZvNyZp5g4y4WjbSfyh3kRQiR3sxN6sgbpNnMKEnnatW3H8mPkSMw7IGxX+OD2fLXw0tQJUfaRZzhAaOT2HPr1WjXhxL/nUSzzoDrI7nn5JLBXHqtfyVzdNZ16LsPRPtF6H1Rae+kDU0xGKp8aFa788mZ5Ga0NrKIYjlb27b+46k9VYqg2Rt+lEmZL4nD87f4Q6JQc0BbHWhgQjnZr5fb/lT8M/ZVGmvB1W09L27q0cBzo31KWQcWivK33kv4YA1e5UsOjCqBORwtqvYaYk/bLwcXGelzvZ1FmqKBQBUQkgdscsYrKlsewxdRslUTeb7bzIE/lqpwzwQ5eUPMcq5yHAK8WvtuHXOXY6TOL43ddMGRhrHITyGvn9/qadA13Wtv9LMKKof1EvTDULhAOYlQxkdBUNoWpIoAM+FdqcirSGDl3TYuBYvunWmdKFk494XFJ26+3Xn2zTbdtOX/YxanJeARfTGCEprmimxbMy6OwTFyssu1vDJ0T50RDxn65PqCn/TYTM+Lbni7lafq+tCcn3CAHJ1IiRiQMmTlBFhd5Avk512cK9++FHy4hM2vi5FIh4diWLw83vkkMnBcw2mMi9piLJ3HmRw8sAvKm+ImpborkBrlsGGSZAo0kw2c/sTqN6Knj9s6YZS2CyA2jUt6Q5mkHCgOEp1ktcagKmF/JXI+TFu9MWJOBBNSbcSEOVP8JbPubNb4FXQuGeofPgaaufO/0iMg0U8+TrYy6nJ4y6K25j/bXrMEXrIeeE4VdGqx1Kz20d/wn8GHDZ2Rq2zAg8byvVKAvSuH0iB58M6RbVtcgLfHlwSYoMNHPuzb68Fg665BA52J5di2XEQeTcjEteHSrQBSIgrwtdS+tzMpoDx+8cbkFD6xj6NNhuFnMcbHNk1bNbItag+LIlhkjplttKlCuEDbz8yl5fulFAXEaQHGdyYMndjeatbVxwMxlynvX1Bh5axLk8b/ywga/VHsvL85f8H2N2TGPSDK6kAHPtTsEcJVT97XMyZoP5L0KwdPdgt1PsOJIQ4o5zUTnBYiH3vyB77EQovZD+DsmkE78Aa/pt1xAuMZ/930OMZDK3qG3pKtJq/UMOyy6z3odqsdVmYnzvOBOf6v77sbMAA/8ovmcaULrNm2uLn4zGmAgVZYHwQm4VclAMYLInU5az8A3emicTjXVPlYfh3Ia1voJCnIHkm/Wnn/hdlDne1KXVPyOeYZqvlsMKizXbJlO2xSNy86U3gQA6tnBi+z8GNpd+jZAE1CjeXfHPSN2aHYIKHPQnHKdVFVOJJhQEvALlwmNGlkWFn3yb3FUr8BTZ7CQ7G6hasFrGG5UDT156IjY9jjbryvHXIADX0Yt1o22SalR4awf+gcZprzrBSxGXsj8Nbk1WKhq0DDXQaoBNeurnUrmU/TAtUFQ5VryRo89PnrKnEsIbS+wGdM2R7bMQc7B0r1aV476DkqJjhQc7pUqIY4MUhs4XGO+Cixr/mUd9GUeSYKsZliFaVxMWV9X2rC1BzSk9T+viUgpAfpAotm9lf/qtSQFJjbj6d67Di6FUst2dHnFyPgUywpxuNFW3Ax1rwxDyGlKtTmteOe5R9n4wdE8GkstDVgqT6wVNWmoJf6lmkwHvZerh0b55TrsTs+/2TSfOGZ31LB32pDUGAjazTlgNimFRq7nYF+jCIyQ9CB0KrxsNvKug6kR+1zAOiqTdPytZoF2EKZ5spX2ss26d132UgVyHi/indMCmJZz7RcOmgNm+vnlGbKmpuzoA8EYwGSsr0zAIkfTfR31aJWAHcZElCzqqGEu4a5tLRFQQHgwbt98t6ro8kTAQ45I30kC/gCkikrOCcwQp/K08XMnt8ofVQldLQ1SbfsLC7TEaGLMHW8UZ3RLSZsOAG5XhzeOSa4TXEk5JebWeOXLROa71Zwuvurr1TNxsq2V6r1rfS+YMrfmFdxUojN3x9yV++Uu6E/mHdbip1cfTrFPBgX40QjSZs53Z0hz5wEq667PDnLgpGQO3tfoOuf541ndkTPWhGTyApT32WN7DK7YxJweuAHkiR1hq/TdxPjMf0n9lE/Vnm6NhkC6H1H2QYy+M54qSxXDC/oQ1eO6o3jN2KASM+/LlNwqf1NlSKr+MpQxg70NaWWsf07waYN4pqfC0hQWRZyfmgESKja+LH6RFq31g+g4y/wGl9mpPzU+SB9P12+GcgHfBgFChyYX7nZw02abrbJFQvriiGqaKI96JAZu0qNALMR1wfnbVj3oxRb+cp/xVuaTNW6M3jmnqkY5rgbfrdhNgc1vkpQ7AkQFGJfFczQxMm5r9hobC4KdnXE5zT6YCUUeUo76k+7Ww/fkprPkwrF87cDSq+6pRSFYUdLc29TfVNN0Houd9Zoh2Rk7hK2A+RjR9yqFBwHTDAIObhxR750NNQIP00IuY7GyRUG13yL5wOVWtbtNbNRIEaSSghVwvODWOd3xDUcwV+pjDlZ7ovd/bXZ0KtWw87aOt3eDxjgOybiXCj4koZoQojoMXU4CpKSj45P5nkskdDwIOCiH48LTKrJDGIWeNjz2PhrJdKFZBp6RNZd8bofihwfBjFbb8sLk+lkXaxcc//D5RXhzr+P2OHBkKIY9g24YlxO+JLbzKx0lP5KXPpZzCQhzniJi+8Qb/aeCXyHr/9FaI9NCMcaCbKJkjQMHgtNXskbQN9P40+CbsdyGVijm5XpsfNSZj3lduIEL+lFCXz8r/Tp/1ZuMWMkToC1Iil1sBzlCmvu8AkSKS6M3/3RzgUJJ1mZ8IHFOjWVPJg9bgMkRe/mT3jKuuJFc9CQf9Amv1LKwlol4u7aHdRzm9xFkQdlqXKVppImI1cqLhRqpd0VXtGQ3jRgh+Bu/v2QZ084Acc721SQ7sd1ry7RKSum5PhPEDZMH1fn6vdzMrk6uTYExTt7l1S+3d68twSRv7HjZEjHC/imgnQ8wetHqknTtlXMyBM7Ejg725XLj+tfoilyazGD45M4BUohsKvrRr4+Vy5IOCjSw580NlTnmF4yeAzW2KlZj7sjsVW4YtsBZQPo+/xVJM96J3T/tpc6C74EWn2iGtUpwaPoFKaIapKm0MBkQ3EuJsDiFvIOEbXyWc76fsnICQ9WCh4CiPtlBv7u6q1KA3Ot5jY2o7povV5tyFUxPVjXITvKY6/6jhaAW28WrpPQMn/VoYp8rgCENlCyqk9RKZ5viwfJrwCssU3gFGcI5s8DJ1sCTttEjUZzYTv3onhDzj0pkp0AZVKPOelNgjuqoWgtYptNgs4X0Gfm6t1lstfE78dD9ldRNai/QAwwpkFGZNT9aUPQi/Puw+iqb4s01MQdJs4lFhmdE4HXQhd1NvQKL30vHwhE+2H3hTLfccmhm+d7OYpDIbTscDrKqpHcpu1L7jUauRgrLJUSp0soUc0Vq/j+93fOO/X1ZwtvqMo0S0dg3H8xMV/ART2ZziSksK++afy+RTCd/wQL2OmMmz7xKGXHmKN0Uk4Te1IvQEnGbxNIggxTcn4lA5+TFBwk73rKe9gK9BxePSNgAfA1wzlhdJq1P48XGlpeSCPdEuCDHu9m+NHvehIoDmsE6yJLaLvwxyT+PXGaRO207VrKcEw1n4joPMvnltujI2P8hNnonPVKnlfjolYHWOcHF7/sP3BlaOA3iY7+Sr06IGaCuTPhzPq0a95iUeg1cWGx9pjm30/pjMTU4lN8iamwaifBfZqbJ8Xo1Y9U17f/xsRzTLgv2r3Ixngvg7UCD9F6zKOfp9DrArviFA7HUJtIZ+9JfvGeMQ26qsGXvdpIw5ZAIfSilypYcikW6XMoQsBcn3yYPkltS6sKqY7APFBFUv9Nki9MJTa4nLYMoGH+jpxKkG3/nmY5I09dB1W8rzJLnwh7DWa+kjvkGaf0T0UpLRfhT0Oz3GINDfMsqMrqJA3Zy6KyfrRUkp1CuDPaeFTdrTe4BH6i3THKk2YIvtvvdKwnD3zrlfVWOXcJ9uHyjtnpY0mTTuQF4A3YkhHt7ctO6IDhLQefupnyvt9DitWgsu1ElErTmGPjrnQNPRHiv2IsAFyaSSg1aBTfD7XnJ3V9RlISTZF4eWxym2M/PrK6iXgiVLK0BiNwBBZXK4kfuloTJ/6YdtU7/kpMfqzWKlmLnEUI0nZ9CJ9Kqvp8E7uMssCmHXv9yAhhaBnU58QAIbodzKIaWqMbgBVUdeQbI+NA3DURUeHkT/lADDJzn3f5t1VoA+bj2AijPgQQHt7AR63nRdbpegd3ViaJE9DvmEReai0vmOf4Gxd1Fw20F71MF97zJV9x/6WtBRcgedSvoXCCXELWayW4ww33QsxFThNGFS0FIVO2XT1yuVA34gbHeIVWAZJP5OmNdthxVMMSIUGysLXQt40Fu0Xh9mFaMP3mkpNvnpDBeavWEMKHRZW0PqDZChYZzZ80tK71PrXKDivpqdJyPo1KsQcHwa/MNEavH8a9hf3ZgRN9/HYs8kbIynZ7oe+XeisSZD12nDmZOY3h7hXUxUOQ6inJGc2hBu/HxSkDF2SJWTB2y3O4OKl51Wgt7WVEKmSK+A8ObKqjlZUGmoaVGkSn3riwQ75YwSzLQo24jpZjz3DYOgGjFwRNWFwx7mpd5vxoK4PLQnmppUJ1tjfM9kWmSbFpFjL/3wjFhMxm6XDguuDACYABsACpJRXZsdHeMsM3nULP03jPKRUWcXvMEDocSP+zZcThjOEE3zrgKuBCX3aoqpxpa8UKOq+vOKntBtV0F6fIc3OIFOxsWKDrjlALwTA4nDLvOD0GJDUxnJAEx+lq0kzgE9i1nS/nKoFBhLZG32ohTQg0NTRypkohRgmUrPsx1eY54vcOZCGMPKvCFiuYE/uRUe2/lCuCTWRotajSEFXkLmzX5mCKXulQEcwGuWKksaateXA6LQS2HlRwqiOg8eTd5f9GSd00NI6GBtIu4jJJFQIVGX6o2zMghFsLtqZfV2quyI7GRlMH5qpq7BueYh1KMYZRDChvK6MvpjB1NMRaV4yVsNoQAdjwT9dNzrF/KAT+0qQ7TdP0O6RKQduqLOQitKzLyhwZxLZAY8Fo9HUzpH2jK6WxDzjXTnItHpSDKZ6wPNooQsCVi47Aq/hilzlg+BWU2gMTIYYdvSiQ0j8N1HLSHLU7Yc29fYXv0X5rs1lToazTyroAbb9wH67vP2bVQ8i7sRiWeMIx3kw//1UuNq5qW/xn0x9VMad2FAvRsfqM5gD77bBYNHQMCk4+p1+RQSmqZgTGAz+fBRGyLNNAz1JBZzoDGQ2xdEsxKb2yGLtZVdvANFDajyI7n9R1C5dtxg3sl643gL5nReIH/1JwydxYBROfef7HDURgNvbAaFosscvF4VRM05wIlL9WU7LTIXw/G398q3RsYN4HpVe9ACOdZWtK5f2AwwG1ssnaJ9VQ8f0nFKBDfISoiHTWbxrODJR4FolpYqpH0xeZqGuVc1hhsb9piDV5iUD7VaWV9O+VBmEnKZqxo/qnJ2q2JDf5Hbw60yC/OQurqagvujoxCxlYLF2SZfS6Hy3ULxgTKHKVKA4vtJIhQcLUpNLTGYKpWmZcwrSrKmCGmzgVFw4raj+eI02OhFzMUaR5fgE/LJAs0KF0WhGbC1rT7qGSM87zS/U6Ky7JO75tS+8q8vX4iSZZKlfhv2A+wmRSC/dDM2yHGP4GaE7HMVtIj+JzU/oBU/KfAgZ/c7R0lM5XkKdvHv+iiV+EXoLhcKSQOfyjmUS2eslkMbXqrf+zPL1QZjZBbcFM+1JrQbwIxB9e/6DfZBYLOCZtk/Gcf0YnFPY9Jt/8POrV2Ef4jCs8Eu/ayWc3mFLE5t3OKudB3sgZ5pFRCDAd1L6KSJLVgnb4nRhTipTmla2C8YU9/VM6erOjgbKW8pRJ+1Z/vt8RIw5btbnNs0MPa1lHYbvyEpaWq4XNpK/03ys/qrA85UC1ZiTx0L/S22vRgvQePNQsP3WGVXzW9DUrwtdWS/hqJTPaZd+Q1AnYZ9+fRjQPr2rGhRu2TW2eYNmzvmiTwu2fZqjO+U9m578W/hKjegU0qB/kJoQsVUevsofqeFZ5+4mniDMsV+sBZI4MkcSPmSkeSIVmme5JBM5XCf/q4UpIEv6X8kkV1+9+KhS1HbWGj+iBg6AO0sprvIAhsJX1GInpkOKPgWQHOrNBVcoY/irYYo1xJVBdDuxusmXbsGTboW15UYl8Rg9AHr6H/Zd85VsIQ5x3hWopmVzUY4jwDdXemTyyrpN9Y3+4hHQ7Kjd4A7jYqE0z1Tfo2pzJwUI+grIKMPBWKRn9DmVl2zm9R2gH81uWeOePaov3PCdthltdridHKt7JN5+g6G8gA0g8BBgmTPrk37D/MZ2FdE9vHs69CBlIiRV6eft5utSsp8L8NG9ZGCdGOqr8SLbFIejVN8geqy9/AKmTnq9whAK7LZTb6BqG9To3bfN3M6SPi5rbqa+JeQ2tkfOvmm9Xc5yLj2/mJ+aJua3l66fe0aoPcLlNAD1YPy1XoWWIMC0m7PflL+0y6uP4PYbogdwF8b5m1ocjbHfFFPjp3DwtBaZ13P/8q76tSeArTUJbnF0nCbiC3PvOVTBs2s2HV1+a5eSSkTad5kIEL0L4W2+ZPXmaDzwBRwXqJeCTDXVwbOdFjVSLqI5rEX7ztg9zR9y7yyaSLBhk1pB/nqmP8rgRMyENh65njna+x2KStr7Nhzh3I76GZWGPqEU2sMxoT2Xj8IVPFI8l8fuZFCGhL1cEAi70boybaksS/wDjIO/5hoHH/hrdPaq1T5N5OiDf/UeQ8WmzsQkJCpai+TNCO7IKKY8ufk6T+qf/K6nnnObz6JTHf/mNsMheSqva/DxGPZpYoh+cek58WDwWAXazG99Y4Sjoh41eFZILyTir0Y7NyLtSIAPniTvtnekYqx67t/qLF6xvvro34feHm+kd0RKxsYsmI+f3gl8BcnrCNJwd72wekKrj6/Q7Xf1BV5Qns3QT/du4d0IKIzY2/o/l/WXxjsB4OwdPrW+aALjVZwJsiFWHZKWGT7CpcfBoTfUG2Jbqc/tH+3OesuwuUkmj4lTL57wK9lkir55OFT3Z9+YaSbkddIEUAtjFoHtsBSik2PpfbUmttjyRE+L6iqjPjHBYSQ0FOrxpA2OHmPV8k4E0KHliRFHqk+UFRSAdG1QHxxMi5khm5yIBxhOkfBZJo8AJQfDOH+VMX9W76OXpaTPzcL1cCJ70nyCss3GCnSRhSp1MgMaEdxYyYAeougcK5V7SpZSQOc9r/tA0fk2rswd7FXzh5pj3IMNyz9UxoOzFqRBq8J/bcQe5DXZL2OC4A6wzxs/iie2OUkDh0EM/bt4Aot7a1HeQgQqD8RZSzwShSKnbUWe1znRbtPNLuUCgOp5yCOGzTJiHQFqgEmhTuyAf1kuEchZyOvdwrOBiXOnFl/WJ0+2skdvgNp66RCR6n1Go06J+wDpeql64idsVOqrW+mGErV03wqguENIyoIoNIsW4hYlSBeDsSYLkbBP4j6bJsbfbFhJxBeFYv34SlLWq9+SsdgfxNEUMgmxluGN7et+ZjeA8/XZX1PGU4bb45O/+GYGKXqn0GaDiAWP1VTuHCizTiUHTh6Q6xiVFyh4I5+wVNDXQ9aio+PoC3YY0GHN5BSYN40Vs7GDBEvrf8808CbO9xBQktQAx5NNmTxGzK/1O0Ge374hlKKcZEBUHu/4upxR/6L5771QGVmOAtFFZmif9+5DwgacacHRKExSIv1FRumwCk8aid0w4yXi4JCTXT/pzqxCtjkSAFvx4hfdMcvbioXTaBUMzMCZfGTcGRJvQX+rtzQhIrbJ9W9eRBGFawKws4WGBLJpWFv4JSjC71XMXrQe353dtoG3/o5cwtwdC9raOE19MmYiKWRONJkZ6hMKe56frNVSAEHJnvaSsf9gsf74t/EDVP4KnYZyXBCPSEPKpqFD4d/K9GBByKA2GEGBupnnFhw40zCuGBw0y5i8jADIilZwXfZ4YXZ78X8I6nvha3GHhAoVGDjbPZsPjxwL0bkQ+Cds1g9jeJRO3zNc3mSQcwSoXvvsksO41cJ6u17OWhAZlsSptl0QQWe0wTLwtlcdwssu+I3pHQexRz/mUmvhLA32yn5/c7nUVD8TfYwYhmc5OtJcBXE17BlWZMVqVxX6UOJlrZuPL+CI/YPrLvE4Y8nm1d3KxAA029NJksk3TcM8ilRiAkZk7o3S3bU7dN88JzUJD8SCMoZu2ytPKfE64FkGZwbpv4dL5r+fyvHZ7FdYkfDPkHqHKPaZK+R+Gu2d8S5uJvxP8GLFrpXF1JEF6NHhFi2xb+gS7xkN41D2JcoK6/1VEJGsBYFD2Vjt9Qqr163h8Cg532sMfLSBaRWIs0JBysDr6FKtwzqDIPM9nmef9DY8NELJCclT13OQ7RPCiAYonELZ11Guwofn79l3VbonrP/h8zpj7RZ+gLMuwPBRXUhkrzJYecx7/xM2YnphzEfNkokHwDYfPM7/4McS1p+ebVuZy4snhypcqHMjmmh8JgwT0PELr39NkHVCacX1FBFxVltJw2whw0E5ZcsEFo5lSfZO8lPPhInf8KE4Pm2zy+AtFbCZmuxQcd4iR0mokn01DRr+4Ui5mImICUHV6brHnrtK/PXKxhY/9Bmrgf42a5JkT+iA1qw/70P551VDW96/bwCToKxImJ4zb4nL1MbduFh+SERdQhUElRhXj+fCJecYDRMLjRDSo5JFnw7WkeEPU9iICUR9prG1GavVLhh+LKdbTHpPuTboV5gTJsdfYoMUDykEsLShbXW7WEFRbOaJl3DTRg3w2D768w1WnkcuhQBH0pa8ptLFC9/VRnTuMom7ii1fe0jtOcQmfkMWirSHIwdILLgMuK67yhtoG6FJdYHu1rait30nJfBZT52TeVbmseVdCbC22jdrVq+UuEBVrbtv2pXnQUWXcQeZCe/NpcN6yrkgG2MnJl9wfdkPOw0GsXfQOMMhkQ3Y//sKYAsoPgM65O4TBf1ZoNP0TNaSSCQGzanXP9T0SfSzxk2RulrdlMLI++7tqb5F/rkeMPE9SG9ugX9poGaHJQWMnzCtMS0PJJ+mOV2p0HXnRi9Z7k94L/M1rbyF8o41Nx7R42ZjrrvnSoeVOHfCi5mhw1gCl3sY6lAeJN63T+WHb0UWqnLEPQWlk2h6a6/S6D5+V/Il5bghXT736DvGy9jjVIYUFmrLSAmgeqxtudASh/kAoizifSRewum+yMvhhMP5AdSrhV1xsRQLg8G7Rm2AvrwL0yUKem/fqLws7EMcBMDxicGKzy0/4Saz6l05lXUxk5uqtZcasnqeTFTTPknoxriTxSZHOkxy+yHNoa1yCK5Sq9DZ/kD/uunXxVdYEDBgJCRk6TFB/MXRZ932snIJ2hW+gcWNHYVUstK/jQYmQTV6v/695dMID9xKr2+wPyIr5e/0b0GO6jGk8wgKIeVZLivJA148JgW8FXCHJ9Xz3tuuXrvESPHT3rBy5qqYzxxMjRcWU/M3mDJPGhyBVOQRClUEgvsQuniQwP912/KXdrUVEI8mc7bqL27TjWOSgEP8eewhueW1m5G8sNXty/HwvvLrLmYV59qvMNSgS9gqXoyDewtQ8iPoQ2W//Kzfo6UN4GnWKjBIl87kmJj69S+xTXfs9VKTvGQ5rFgx3F3yuDTqd8SOjWNP926hNdUq6WBdRCdhVHo6vR4Ct7lUw1vau+zi7LBCJFRsdJLLKIkwlxPEt4X6LsP7sqxSTts54Ehi+ki8WG4jim2oBuJNP3U0zxsyGTY1CKjpKkX9lPhSS+LZXR1NZN2Io7qxRe5sHMsZH3nR5GTHMLtHk3YXNjkbjW71xLJQXqTPKwq6SQ58OEMG2xUhF7shUE0FPC3oFtuwtEH/NlwuE6kdLcOO37aH7JyNDTIxGr23dSjG/xL6KSwM2y1vsUVvlTu7/CeTSPBIKaht+B2M9B6r7QTZjd3u9AvunfsoKIsdhfelnLdL/mp1H+pEDEEeJcN1TtWtU1370ai4YHx0ZWnULTYlSoFSWstP/claBuqSJUUe/z87QjZA/1ir6W7SyhB/apGif/ueFRjEWtpNy3XOcRxjndTndNC6dHVyEWlaR7YgHLOSIVboJAEMGYKtN4glSSTa/hhDWv9Xto0F9Y7wON7JetNIZWjVjlN1NnDwu/S63iykZVz2CGzxw8e+Jh/TRLaVXvS7BIOdn+uowWvMWot+IlgfhpwpVKz76/BKE4msCXjh2mDXIwxRzXz0UEJsZP9Cr141qaj51AKmxOvZfyyA+snPdWky9wtcKMjQbfIQ2Louhal4EazJr55RtApmcz1yY43EKIePY/7PwA5tyHcbJPMc0YZhWG7wLx8XzOq1tQOFnW/fx5zbEeaUBLUkjSkoHLgJan/8IjfxW/rjA6voKeySuOemlB42gVawBCzwW50ezvinxQlvlkW+ZVdrzCqx0LX+tlFapGsBS1Gkg+vIp98v1ajE36ZMZF9rQESJAkULGUweV4BqWVwtseff/G462Tpxgncf9oiJQZSySw/Pd8/53ap5ZzB6JiGEvzrUuBia4JrGE7UftMU41sOjzea+D47KBnHyuW+fWRg76qU/PRPb4i6+h1fPaxEA+Tp3Muu331XSulAF3YGeryatv0mDPsEVaD39sPLzTvMpTGq/AjTEA0sNnx7/J8GTyJj61Wta4PkgPdck5IrSe8AUV94/k3o/3fYC0FezuCSUrrv2Hr/A0cBKfqJ2A0BDTNeiEFr2+h7r3o8ZicdyGAy+9GTLCsOvMLbrHZap4FLUj/y5sAohEw9n1IQbLwRjDxkyrA4osahxO0eppMJCLwtKrimKnfTv70lpJ9HmjePgReo87GNLMy1XZAUkBc656h+zOsnfsw9GBuGl5KtkyezrquYUX+SM9vusxcYB6P8TiWX86KS3uhhX+oVDdr2FA+kXZ3qOl5df/wo/tEZtZiSlKVjR4a85THon/K9E+BsFROGsjhKOv4FP1yAXjfRLKXcsrStgjIMQxFpKiLMLdF43p7wVzVFPCiosPDZtpZ7dSm1+YZsiHkqh7jxVAI+HZlpeyC4ZznTjntGVlrPNHwP9lP927+8RwSi+p5ys1n+f3S5FcTxvV+7z/gxdb4WQldij7/nHAsT0hcbmPIqVCxjPyhDC5DgaUgiQotLifUtxDP3n9NHoXk+2m7O2feTpGvK3JJnMIvI0LeM6IIqRijQuNrebhO2i1zvwrfw79qAePL/rPACgCLTOf49Eq0iYC4yOAm1pb+Hgt+brdO6KJ9x486zhJqbopFlC5qIAeyQ5BKyTBL2KM1WwjmbfRWTGRKEdQtJRzTrMMJu2LiSeMt4vk9tuw6ZF8WWY1n1m3usPYe/Serq/1Cv0ac70gxTiOHh4QOXnWsdO5F1KEWNIISQjwAMfMupKKkq9O1YyNveptDDBSlLQ5jsNnFhH8MlbJkLh32z1wN3TQkCHGaYuZbBFEV+rlsK7RI3fy0jiHZrp0jlupEI7f5twzlN3mARY76eCgHmvQxe0z0jpp7SfDt7VFLhGLYzvmi7kQhfWHDeU3n2l3IOwrQo4shNsmPg0K1crJ61Utqa5xOVu6bzZPQYVzUeGXIDLVxer6IR4EIb6KB0TZbASEyvBcz7Zyxt3NP8Q+4hd4z4rKpUqVJJ9KAuvg03TalsHrCzvRJs4SwwOckA25I4uTcE8uzoBJDjCgsvCRy2PAablpdFbBd4jX6u/DJnMhLxJidVn2wC16koJgd68Vg2sq23gpHGMEXIbUYZZB1X6LwV0y/g5B/cDIF1taI32tdcjjkjdKOo4qpjjBra3P3Imv9AX1OIqLRWtWxubSlx/83UTlTDO/c+KcBWbIV9Jec4suDyAf6oT5NoYw/vRypYKI6dPh9RYmSps3Quq1ROkfA50XjgYO6ZXXRggGm9KTvYAT0W+d28hcEnsu98ytWn2XvhFAY5yhFUMyWpqJ+DxJmL86KKIqGy4LtIhyC5SMwjQSNSJg1pYgMNl+zScphB0+YyoxFgEeQqxKGHtKDa6ivnOrsnhLCSNqt5K+khabKvxScF34kyhcOIHuhS11KbFAIYPFuQZSeloFGRZSJt/IkCdLm2jCGZzoHqDefHvgnkSQWwt7uZyGRKl45AHoXZ7CxRoUqhmUIoQeCzG+/qAt3EFW0LHNKsPRZ73epO/0VIh/t+mcrYyoLqoS1/yhJSTs5MQrZXeQO7rVLF3v9jp/sBaZJEO0S7u4Rq/yJIh2pM1EHFOXKwWCZgzrj4kgN8QnV/ENYDLFiuPEBnylH92cS5dD2GzavuOrQvbaBOYpuN0jxS8kMDisl7XHKKussmIS5JtqcYhvTL2CTxjmsc0lQKjMD7Wms2oyItp4o4+nZ92A3w9mVzOMgX8+1Vhz/LbdCepDZngDSo905iEuHf1ySoip04eOJ3Pl1hJFF2K1IRTYS1rF+3H41PKG+64fIQ10ltUkMf9dIiZ2qnZ0/6ZX3yO9Kbt9zq+MG6fUx8yhOxEM58EL8NLrY4INNYPEsYJR4jkd3O2ugOAMUX4WxkvO/kahIWGkWoF5YNzfpY2DabSb8lGAMWbkDrLq9aNJ+ipCxH4sidIw7Vac5//f1ls64cYEtdFw4j5QAVDj/eFkw3rtr0AspJmYS6KlZ76mv5qC4ct3rPJLhlRsZkakiVZXwOOz8vwCILrNraULlMCHTIzG0QwJFCYlYsxVmY3dkUO6S2p82g0RSI0KvFIswFnUFdDWh0wJcWKZHyYlWw9noKvcRYIQT08ss+z6zA95AVmjwlPwPRana6Gdl56kFu1P/obvH5+jz37qeytXPvxllnB9YfYOScEu1mgPL2pnGqmFw3ze01BgxlnhsU8J9Tg/HANXBO7QMIgKovdJUIv+cyQ2OKD7oQSMRnA2aR1h6wtCPnbHFPJ8saAfpLWlWH5VlseHJMk8rseFSQ/o8Se9wW5LJaI6IJKHy81GLtVoQ0jr2LnV7izY8Ppl+zXdY81by31Fuzrnnxp8kiFo1mF5ZexGILt8XavVBdne+NX5seWHOYNXWalH9/c8jhZCH+B/qRyjTzlaTMl7hOLMCmcbt3RK6Cuv7SN+H1KVqnMhrrZnVkkFNmyEKH1Hy0rVGnigrDbLpG7Rg5VHFpGxT/hn9Go1BDy855aAqNVc8FwuZUWUnGBGfkhhqjTrNzci4Wc662UfJHWUPna22GbW0RdpghHpfmRfy6ZJdR50aFINp4X1NqixoAxR48vWciH00AgX4U1imkkNp9H66e10iESU+4Dvz/QjFYcOGjAr+230lKtSSNces7m/lBxSuHVcgkf2Vck6FMv8nGyxdUktqtcjXFtd8t6+m6YXHDJuS1wAjiywb+qWPPUZrWBTPTPxuaQDyt58WuXx6/l6xIlFO3QOaP2SVr00p4JJvNeod5EmV6++l3rVIj/pmCUJgZgpv9e9uvYHhDn/yVwc0ot3HCFhc5TR47S+i3Xxd3Y1i1iOmfz68og8DYFpl4l/d7jQQUEdZzh6U+UXla584DWVH6vy4yc2EoQumsdsGAnJ11VdKvPMH7Q/+0ABpjsFoO0hNEbI/GFuBlY2gn7bgo+92cLwnO5Qh+8Dj463oDGZe7G4heCNETSwbYjBWo0iPbbsN8GajvZbigllLrMpGHfVZQbEriIQO+ibAMhU1VNQLW3R3DocJGYqEsjWOjsuroEpJrYLx7iU0OGptk4+bU4m9/9KZF6qwWVEhHt1XSh4tgH68Wr7lnVBGz5q2pi8XJrtXgBEq+Mg+VYZEc6f4+3p+lEaxe7s1H1iUMkwS2IBpcrIEKpCfymU2D2WZnAooIO4qjSHBiYOh3+VsZJcvZTJrAW1WYcs3VJHK2CedNIlMV3jrt/HvaY68ACiahQER109woRCYdzSDpfYluIDpxs0YmRdz2rPfN5oLcG1FLczYUTU/WPcFX2emRGTcq5GIX5GbCsBYk9RpagIOYw8a7o6dV1/uH0978l9170RkMj0Hqk1UM3czc7cp13IwBuhJ+xckwiKm1vk4m7ypnZo47pi/DK+uEnfTgnQX9rXmQ2d+hQM9UOfPMk7FbCtio89Wgjh685qGIkE3x5U3Wwv/2fnRE3g2Fs5FBKgwKuVOwZKWRjYRhoT3nHBzXHB+kTj0fD1heA9aYVfgISGsfqN/ed/sBzOz9dxEUwRxs0FRL1tmuUCYXP22P2BlDTnAGkWk9QhOMBvXa+KU2tvMVUf0006iXkj7b6PuAEU+EyY092Vx0/J+bMjVbYE8ECQPxWZyP9I+RQag/5HyAUOgM9aelUCeUdd0UoUYz8WLT9cU6MAAZH9XxOjTWN2Whv/2DjSuXk2MvDJR2CKuoXEON7RpgZ2XIru0HmrmoKvgt2WAySuCh9Fpc9aHbqj81X473p1W7aPMprZdKcRWSssEUkE/FDGVaYAtvJ+II6UWTOXjevF47VJrBpxKfWw9U1Vskzo3FpOTfCaJ+I+Yuge4eCdPlR+TteWEsChoMaDtZxzyv5PENLG0C1hLQaD2C0gD9h8yPN5oj5hBZjDi+aHXJnbBx+Qx6yMMVK5PpywGrUjyJMMnVjpGcxFkkzc35W9hGG8Esyq0K4b0vHTAnFCYGbDQAiKoP3nNHvzT/foZzGDQ7zjOCUY7tRxb5T2nDryeOGqeOrFF8sDxL/ZaTjnuQKLLLp0rnyiefqJ95DheH/a3yP/Gpwc7phADrFx9PoZNXxbv1fpXD2cCKsxCTSbkj53Xim5d9Jk1O49dKMwbYVIooQpn9rpLnyU5HOq5CFEkNgXSmX4ziizuX346MaGSU/elBMmlIW0roaZptNNMZk+NFEbkiRpvvFfPAsPq7X35qACO6Hf6/Zedd3bzsNKM7czhBTxDN+NWMfIvE6nyFZxLJA+SMgsFmNrhVshvssKcf7I5DJDUAhFjka5BYLlft+CmfaA+SheuAjmPO04v6SepfZWk2qtIUWgbOdGwl9XvW+uaT763ObHd3bIOFS3DP6siJ40gzM0XS7M5cgqvT0Gj/K8ZrN4+cyuSern5wC5DsCK1uX+Q50f3fW9XTpoQieEilo8u2dLanPI0zZrOSsI4b0SPc3HWl5CUGtlp/BkT9LWuHzArVQqyAxfxIdDe6RzGNLvKeIffjCbypBJltCKwzo4kN+v2PBicxRk+u/5ZlPRcqAHNOAI1zzfcpk9KkBt//Oy5i/oBUsekXJg0SJfoDiWBzjDIlocEfE5s+UMNh9ieRw6nFJesFoakV6geF08DTFyCRbriZ828OQ05zQ/Jn2ZX6mfKvYds25NWcNaLWTeuuujwTZzN25jHFUIgubJsUQFhEeIEYiQyoPSjRM0KWYXERDd7/vST4vqvZ5pfp0N94WEB7u4E0mh/Ovb2pk5/lOSerc4lboXXA6ompIQgYnG7DMO2XmRDnWukXrsqUNTyT+a7I6Q5W4/MizJmQKs04D+FFsGXtQksUZ8AnORj+RaAO5O+3VP+Mip6bd7WDxVkOxgwVfSpHJW0KIIjd3FSIw7jpRYe2ksk0YJDFI2eAAtMhC8igPuNI4krTuE1rro0HfthTYtD8c1rfYxUXdM3PEZDvIgovXySq54RGdfojEVxyKwL4NGshwWjFh44Fa12FG3r9hBEl+xtiUrc6AEtv2MuSHTpXTCKuz5Q9leT1PHAZWPkYiLnuky177OZNSAvyqIy5XZXKAPcvILsyS4D1FoqqZGMxRwoR8HlsPztfUT7kCvEYKfWZNKXgdD+js1MFcr9hXWUVtd3ZIIHzn2ZsyaEAykHK3QtCHsD2XYL+d/XzAy47BhqeNYRuk0EVI/JOLHkmAUsgg+bgckXe6ACZteOEo2QnLsO/WUYrzSOtVxEKwy4yWsTNKRNhOXfYSsJfbJ9efD+hiKJqwThw95TZK+o0fSSSsponSy+cgVeVbh5m/+M2WGQkBzDN8zHRU1ta4q8EjFM5CfebUlDvmMVg5s77SG6mG5Ub5x/OZKdwHgYHzbH167YeKcl+EkLBihXX9Hlap17OupGM9LWfwDi/E867M4akmR9TXMB21RegLoR/y3S+5twG7V5JfBKWpOLSEfkua2Xycg7KRbM7h/rBXgOcmrCtKLE1pVJT6XJzdYk0Tw3/+0Wt1k4O7M2bsanUQWdYQq5GIrrWaEI+lYwmW7rFaYV0bhcM2/L+XmXoxOUg9Th5SwUGZYSn1Yc7gNNBHsHXgjtW+Fm0KVtqu6ildp0JQAnMnvYNFg4WSj3+Ct6otos3vRksZY7VZabu5SL5LH93GvbwmhIHgbymEIF6/6xSIbbEO2AoqVdOKhnif4ZhfKb/QGLwsnlb/6BKpR6pkLn2R9NAx82W87cJmWBye9sems5+F1zo/2lwV+hT3CZWgV6Pmgtr+qHPccpdsO55mmaUgd10shCqEi8ruvrIf6T1ZE6OZdCVA4K5age5CiGEyZun2MfmPXchXO9gNkkdbPzVkkQPBYp+PcQHcJ/22FFsrogLtJHV5qo88IYyMvbkhymmslmKaj8DPCyr6exkJ8b4OxR+NNtwsqPgAnvpvyAZjCYHjFOO4pEsc/wXINeD4X4G4IdKye0aH0zyU4ycyXo2EMvn3SuExY/kgq3+9qBXJUqJFiWaHGV162Te51N26+wSikIKJuNwxuRQ2DOH2AHqkGwHTjEsHcFKn4Lltt9c4Ecr7ky+43l+eY30wW0bfAFtc65upm6xA9MUwJ8rnOiqB4Wlc/p1EBilU2XdLtQ8RCn3XssVsniMr58JEmwdQ8WWf/+KWq1rXJvecvjv+7WjTlo5wd9LiEbZzr9XnsLpfGaKDuOImPei/qN3bOoh0vf9BgE+Ul3hQGDGcTPqMwngXyDbCEnEZUuzcZurh5sMFPuq6liPbop7sYTvVeRlxjXJZm/uy0JKZGFQUabJFuA22MDmt54eb5aq2jpDaHNT8zyE8RUx2FW5ihP7DGQUpod5fub/NVunivD5uf0XCxvK/Xpu7hNv1Gqo96Q7lMzgNPUMFV8nc+W5SYtbzgMYdyVi/m6K8uGaakyaHYQKfW2zwkHWHcQ38QuDGp6c+N0jPwkivMYZdxX0N17FEPaOYsHPTQK+idZjSUTnv0aZ8eNKTvPcUBBWwwvKbEb3CfHhnb17frLAcwOB+sWpsCAM60vKFUnp4pxDlSnNelKkbIRl7sqUyG7p5t106YdkaCvmoysc8UknOe2SQLZHRSRXRBZotDyuTqu+QKEGN8ENSMcfu9deQMB+eY+1v/r/9nJlkEp+BUpQ4sx/FEUHP97dV8w20I2VENv3z8TnT/t1TyDzrywVHzub8DtUdh8b6eBfBEsjuR9oXgqvrCnaSqMpyIBU57trUNDesKHmEBYQZTfmbjcmqP9snFgG6g9Nr264Wtx0fvHtUTsxDh8+6eLUPZT0dUqlnd9v7ITmUoKwbur/glUH7LLgDSjeSwItAcenTbX0W2YpXpj6REyuwVQK7e9tQU1UF8/Fb5/EwrDlGzGdBuPpgKwJiTH+dnP/EbjHvB0rOsDzgpbFz2nzfMlLKciQjPmxiabmwtiYp2yx+Q1MHZTo+usTvocLgxvY8NKUjJOu4PRQM6004z7eUM6OT+iFskeLQ/Bh2fJ0FbjkTvn/HnjJZkSTz2w/4aqOfUhimFJA/Nzc0pff5LqLFD2YEu37NMdvYWIveFoA1vZxR5wXbHbQQ+tCJXGjyldJGdsT+PWdu6pHYZiZymbUfPZAO39RyNQaH7mjyZVTwiuFK1T40mlV4v4OrWv0ggzQ3mgk9eUZ1uK+QYr85AMPr0cdyOt53JhKrWdcHRrfIsv7MNuSk4Xslx4Vx8tW8U8Plf+h9e9hw2Qd7BKZbiWmFpOTagH7fxfLuZZ06VHjC1q58z2Gg090hAWbgOmqneCr6UBb6k2x9m/5GOteYBMTWTQYaHFkXJMqKJvvKv2Pn8mdTc8RCaEsI2mmIXpkoAEjs49UiL4JBrM4RvhB43MAIKgsNWxtlp9gZmFAXORb2OD6o8VhGKSwSScT3YWI2q6LmcN3X85pIBsZ3VomGpr9lDLuhfl23UCPZZNosj1SiB5u2e46F/UQVcFguwPxAeB/Gbjhvl+tEVfpeJtNNm1GZLybV0RDZF07/wc87w+aF2j/jGzVpVWQcOz/TO9XMgdtlPZp8pyoQKrCofZskPQfh1x5sfbJM/jnLngsy1fD1lAZxQ1AZgpasp7lx3lXW4TpWMNW9k78aIhUCt1AGeKMb5uDXdHTdnFs0qYIJb3pPq5Zhgk0mEcex7wKWqPLEjktYHpiOvME8mX18euXuYCqggoghKlbKU15sxf1quRED/7z24gviCRNSkAyKNFZxYmd56WsRJv2MIz46CWMlBLCceF2cGDaMHoxn2QsJ+cuX/g6f420vXB5Pc3Ua92MjeaAtnb/hEh4Scehrd3bXq8rADQDG5VrY/HzsnEnP92RHUvK2rTM/uftVio3ZRnMc0ZFrr0haldAW6/+tbnUO5oltrUDT0BXugAVjv5hDxwhLUU9ptHuOz9pLJkMz3hmbNjyeqvFUMA4377Jv2CF2K0pba1O75Q9qs5e6YroftiCEd1mL80fo6eWNOVmTtEzofp0MlZEPbXKG2i+MQRrJIPOHp5olYVT59XQC77rK+TrUIp5OTV4AlwiWYk3lMr69Dvz5aitADi3fs35HeSb14qRVQstAAnQRYtHneWGwNcMw39xI0psVdW7RpZw7ahaq7Ttd3eCwx1QyPDX5y1rG1PYhQPLevBCE1OJHCCi7oukldpirQEb901xfWb1DzxooanVm2o/k4VDRVQIcllwEIQ/shQcr0LganP1bmYm0e1rHeT8QWzEqTBgpvFJriDvdHE9WZTglDHylSUVC1TIOeNljDU5fIHMxwm1v4Gncd/vk+pSLaUbvITftMyRrRtjh1pUoUtKu773Ky/pLPU3fD0Tgydz4uVEhtMm1C6xn96fLDYQsKuKaoCwPzfXO2Rn579zHm1/DvrLPPcsHLI4x2ilogUwoK+p089rpYwj3v3M/87be/4bXKeIHFdrN8B+cdoHvBtlI5M0oYyYOeZllet+mUik7mo3geHzlIoI0RUTGgcZU714hcYMDIAxSQkzSyG9Qo8S+tCT9qj3DC/DPDzaLZQ5n8uAsz23iLUFge9G959BVqmzMstuCKCnwwkGl/8aGeyCXJuh0dO/I90e0CoRUEAAJpt27ZtGz/btm3btm3b7mXXzbaNWcQs5IyGJvMYWVgjBJaS+NpTAAg5oGl22Y+HuzHn2v2DGARkqKutQ5Az7cdqRAnCyB7IDr6qlD5/CE5Ay/Wtw8RruSFQO0n3PJFyN2xko+zSbq0Onwh/hDYVMkcXobHk02J8J6W6ur4iZDS+UW5lzstkTg8VZy7eOpvCgGx8/uURJEL7yF0oi3DZ6ESOK7hkX9w5uVcvjvRUobEQZ1dVv9goYWxr6gRhAGbqkK1kMXbj8toutSlz5+WhcfG9dx1R+ifM2kR7wFZ9Ey7QGsx5H7zE+u2yAyvjG0/bShgH0keHJmkVXAiPk4gYYY9reb5vhVOSzwTtG9OAgdb6w7iYAp3P5bFfcKiTGgNY/tC6yTqy0SvrtzMRNSRQcenqId1i7c7RLOIvfxncBOkgUkLr8IIF06iiprdxT7xsLb1tDLkvc3dCI6tVYQCQziCNqQUpzNVgoaCbi0D6C1GA4gBqxiXs/c3zD8q0wLgUzH0a/zX1ruKXS+1g2ZPAaGTjr7NQ0oUkKJ8JG2L6fS5KoQUNZ8XZDuaX8SuQgKX0EdkCCclsK2F8jZGJS+u9StYPwmak7B+miUS6I9J6WbR+uBRqKkIfGzZro0z+imPcTegm5O4rXwx1/Q3X96FoH1dbdZ6wOhKm4pcZuYEHbi9Cq55K0pvUCHqoveAeYWkK7ZYYCHMwtRv8Sxx4cH0/5blIOdSOCnoWfxY1rkaIsFsXYhW5eRtXxPxBjqFwFPTJckLeqEuJPQa79KyYxF5CzG/yVSfdxtwY+m0JmiMAy6qoGszRkscAgAqwjhdgP39u7z53UlgJAWD33+t8rWYCQ/lZYFhADJ33aiOgmcDXpPTLOsYjUrPHGIUF7xvRYUcUHFN+fsI9qXPDwe6CSaH2/u/DmSgmFnEzFN59r3z/yfbFX4mRSkeEEbYoBzkNyIYegAz+epr04s6c5uFziaqBZgd7ZSpn1nDe5u22JpSTLYvRmYYc15RxUT/8Q67mAdxXEiR+KopMaMLCGPavR7dOBfsqF+ReJ70hokWQmupvdliofGW4BdLYflZKSuP4wkwPat2Y7So1RfFyf+ZjmM6Z36bsGots0mR0KhEXrBPT/AJBo3FAtzg5vuYmC3x+tYQa3YyI1jSFxRlfgCh+QEHjIX1YSHslnKE8EDm72QKEG7Xfi/4aryGlinrlpkRDRWbmfb0Gwa7wYUBayBCohE1Hh1LfmP5hNFXiuz+dsfKUbgobi+Gas8gAgNfQOhhmcG6rxgZcEbvTkiqZyYyL9+z3Zll7dMZU8qvuiJHAgD2tej2V0fRo1dqMqJAcUo/+8/dkNMvnPO+tX7eR7LnHu23KnvkzKqNNpaFjvM8PmVyuvoWZfwzuhAwXfj4/8BO1UGKdPdabrFHxDvhFLq4WsRF36iK/cxUUxZPhQO8ZvUaCHvIHirNm/44VIi7MuMHfCsszOX01CWf4jdGFWyraS4H7XZ6au7U1YSswF1rEYdlhHFEhadSioP6npzEJ43oiMbchC7ldOa+CbcyTR/fWHpuPX/iLsYs5PPwdwUJNp0cl+YWQfibX25Z1UmRGvUHP+EKhbev/ZLFO+rs1Hy6iafTqq1MMstsAZnWEHenNw4PCyK1h3eqP1fvwJyR6aMHGX2LBc/FXjRMDGqgP44VQbHJcGmQ/VBVZklwNRFQsZG/J5+qvWn59lV4Iru9jzzMu7m7wOUAMPvBjzjMIPsSeJrHGGnGBjatyihzcr17lYyW4r7niusRvF3LuNscdDvlOjs1SVxclJRenZFT+F48MoQVkixLcdFBL+0r/wuIqQHim71NJ1KEBI866gnY9SKvLPyycUBDHX0th7bPQABlreV4Uq1k7sm2ekUM1fEXucDt4dauITyeUjq+oN4IvV67Df6gQn3Wd+wM1b5norayW4yW/iy0ZtcAo/B5D6JvYiOS5rpXtWHSVS4qkda4uwtlYQocFDBPk5P+smEtV+gRo7Nfos1xKJMzmV0u9wAmF3wbCbd3slhPGxKK8F359Yrl8astn8HB4N8KRTWl/vrwZisQbFMP7EiptjvsqhOs6QR0d9XigEWEpPELlHzDfjlyJqi2Dcq3lcv34e9gYspRyh9QUQuMfjWDMtSQ/b/+5d+YJ6U4Eqja7IIUqGrTqNAacpyIHpEDps8MHmF98ypdMbDogzcPAxeUsxA4+CnekKjpeUdb3GOova5JBWreYrZeJBZv33Vi7oujo7f+KDamBC/jmk8DxYDFz1SMoKXGUykzrkgqZlDi3icO+2Gh2jBrH1Vb1op33msiv56HmxXcUr6BK6AooEe8QgdMeZRDZqBK9vuSszFEv+HBvtbS2/Lc2PZkbxU99fS3s+28YZ7nSm0H1aaYhxae4vpEhypw+IrDvTn/DbcUOwn8EPJy7hOeBzlRZOnJeAluXuOVCC/PecNcj6sLTLZtmlf3khNXQMy8H4pQc0+VDyu+WE6gIdv8e/dvOCwmuM2JUER3gMHGKr1PS5xhLpgcQVETdq0TgIsla0VqD0rflTD+yhVx7pNTR/UtNyyt2/sFDcb2jNIAAFavtG3eI4dwPUELVFtF++I6BP0QswkABYSTUI1JuN3lKGSicofovCjZrckdqtL3puF4nWHC6LjWtKxjzU6b1/cIQ0nfrI0VPPDauIMnPZNYajGSxNcYl8mbuwQucuGgpzgEHawTZ72eRYiBX9MzaZUdB/Y9p5Yg5fg3d5Rcox/K8fCdU2HQU8EXy31li47Rxaix9lPn4ia1mu3BcqpzwLIRdxBcaISSWVV2nv2EDpQmImDfC8/irzuYzqJVl/tKmjSGcR47g+ujtceBt8AUrHYIAGz7X3uJVDYXTAAkuUVQKGMHaIJ6EwORMf/e3TvjiGUpulcux7hQydLz1Ax3edGyCG6ZR+8KbeykqjAmvC/I3wBumHWEXOjpzCQt0r4ahHbWcW07wNgv4JwWlGC8iTwGXbLU4q5MIBt3e7EBShkhtspiDjfRY3nbE9Q4SU9UWFfkCMh9II9MfvVzSXirmnnTxPmV7+NWVcavJ7+vjb7ndbGsmy6LPFpNTKi+SOoPqX0nCXrOzaPxbA505pcxvst6y7yrr5/7MEu2NBDSwcmtePN7QQCjqIqrjqOB+kVd85GfA1OX2euf927016h8NKCsFJE/CuGjQLVf2oi2HVKSY7zgGOKXgbERAm4FVfsQwz2X5Ttr+BCwTV8TrliNdXc4tEmWm1+IvXW2mTfho+x418I1URH+j2nOVNnDQEBnuO2Rhao1RYBvQrQzUXsM7YTGb4qSzxB6MMMQa4ch4c5HC/NUl/7w/F0ROQvWYOwxsNK5vvI8+iaVBqs9jDtm5BTOu7Yzi7IPzYFs4eVXxU/48GaKw6kpNF0gZdf+MCd1koDGO038VqlpYnaTZGNzKTck9Wco2WsTLWi7wCcr/WdwSmR6FtXjDIkeViG6TfGGVtQf5lo9RVeET6t5GdDxBEaARYb1X33iBwEtef00uTWBCk573n7e7RrMoHO7FH2g7RU0Ctpab34HUC4xjm8mB+DGqhSHEhkKLZZYi+alSeKW+vfcNsmM8KKQH0cWKsxunsDLwILqlJ6RhATvyFupXUOJqflrNDM6uxF365z7Cba0nPxhWu3QjRVt89jYJdDTxnThYbo9dBLlL4cJSxmsaxjaSpajrAIvhN7tyX9pFEVF8SqLbVH4YJhdPZclZchwsDDaIdNOMnTgXr45/Q2fg6V1uciaHtTMrl0OdctWNQkB0LTZpRzwkKSxcaNk6h+Ru35f1C0Tw7VFp/7VAO81d+ve9vtLXhKo5Nru5YN1BFrkKiebFQHjqECF8MN+BJbNounilpKpVCoMZRj+37v0ofSm/UwOYh4fRPs+ln4YwkRGtr2ZrPLjhEokFsbEM0CimMVL0NJgiJYzUVoCcwA8S+pg1ys01Qm03YEqcud7vIwq95NZR7wlZOVkOpKEy5jvJ4CCbZgNV3kDmy+/nl9yKJxqU2vjhUnvSlUxGWZ8f5xf5swLhS+OGdXQIRAuXkxeclXnLzSy/Qo5tX+SCU5chtb2YH6AIFU7ZUmFNKFYkRhVzPFRAa5sg1tsJmysLkU6ZYehwa7J2yVIMkQnhe/rpqmMAY5UsFO6sDXkkfNQFeEy8I6KHI7n+Xz7WcJG8wwNpnOLKapFpxP5NP2Db1MqBt4lnA6zfwWtF4WSaHLSF4ldvbpFh16CHn2s5c13ilrxb/KZmyWtOn03bB7agIDld4SbeXAaFRHyD+B0TaRA4RbRuCmTljnlSJUez1oneRQYT3QXSw/uKhIY0pFoiUMMa8CJ5uNCM5Z4mtYxAmGA/Suj3N0w3LyusY5d0B0ohvEW6+J1lx0vPMRngl8iqVbUcEH6y/xm1mC/0vA1qqg+ZbQElYEvGLBzya4Am4IUMWMVBsPB2+E7dBNOsDRCX8xDdeZH0+hIFEGuJ8TqQembSpAH2ov/aR6Aam40N/1mlT92uUHxaIorshSj3RxVNs2G6lQoC0806YAZaAtE53GL3u3/uou93TG0CgT2SRNJHnwaH4lAcjKkK1UnvuIWwI2lrMO1zJHjQ/gmBESAS45yUlvN84Hfj9/A/fhhJNTWHRxQvJFvWvYDL6Lp8hM8un5ZRlVZps7kVLGpRqaBGv/e7jCHaoS5yZ3/AkczNNLzFGr0eyeWlWIw+48zmslNfbKR6RVW64jv2zk/oBioWUnwnRS0uPAFDgooIttlpt0gt4ou/7Q63VsAo8Pt8VfSmpz+/8IXjjp1iONZ97waYDpDbTKMzCATZOgbXX/WgMKpFUkSHq8uhuAfUboHCW7AXsvXxOYxbapqso2vA655VWzqiZi8KuV2UnFFfIwiGeRbDQ+EYOpjfQGyvlNerSIsggLyCt9tbIC/g9rSHlNiNS8DeaJv1z/URrKQpgLMxi0NsWX0dRRXKx6phOEhBgT5eHTrXO3TH5zkWjrD7/YSC8UqpiiH7dM7qpSrHwz6oUAJe53pv4Pe1t/RcUvE57zCcVl8sdC4WVmcIYWrs/gC0yyJjY+20F5GrhdUdMzTIGhDKTs/arK4LMoCCWbzKTJrSNC36L0J8XdcuEajsyPOsc4+dlW2ngbDUb0bxbvG6dXvxSlkkKs8tQPOPLqmhwYxpWaXsL2CAfS7AtFQ7yu/d3gU/GXiYdEgV3H9yG/omXkB3+AFf25/wMUPbknaRP/LQr3beCpGSSovT9AXX1DuOviq2RNgpGziNXwGooQAnXFoXyPSAdaogaZU+ACiscpx0Q/UDQ8UigKsSZm38guGX7vO7fiEjNDaZAng82xbOXPKfPGVXCYpaz0PVAnlEQB0Ycf2AlMkjm9UQMLuT34zi5VZiI3e1F9I8hMzkVGbbdw+oL8lAfvJVmeGGNJBtPIUrzD/IpUCybSDw9FVgRexy8XnygpVZsx8xjOgiMWrKXVWa1JzSvyyjhoSyDKpxGjy4ut6IHRLDPnfYu0gsgM8IPl1bfoQtwfzahjiz+8GnNNMQe3zQ128OnP0locbD0ZVkdUJh/Qd+9ena5MNo2TcLkHQ/3Gt47JiC4L+lF9YGcxHBnL7WQNoOOl3paIoz4TclO2QZpkZ9LH6btLTkOt9I9iSwV3UQIDUvhR36n/meYx7/ISbhynPxKgdUhTbNy77Esixsv9rjH/ra0SLf88DqR17pvxAreab1JIsqfvD6T+bBIdVBRsuk0KE/NjkL2AOBFjD6E8xHQiOym+fodp6uevCCfNi7oQ26C22y2oMhqvG0LryCmX2YIeoeIXifGCc8vN1C2CwCK/rISTjbWdVQgJl80NSj5A2PkHx7OjGfBwMKrPR9nLqRicCjhem7ZQO/k5pHs2WKSdToYZ4TZJeuu+6XN4KOneA4YfiUlxFG2lad8wRiuXtzzmGGeJXlNZtRABgt9F7MgggIlm0FVa1QJfVDPY0HPnQbtYphmp9LZuvfub28rJPi6kjp8kQBLcfkoFwBSYH5PzNwSTx0lHdw+YA0XQO0pASgSUwymZBTNkHBi5YymnlBblIqUigq/DOjVxDzr2Aq8dvJmCPGBIAMRGcX/+fmiNuaTLzt4EA8Lry6sjWsnjnsZoKFjXQ+MUdOL8/9NzQrnLCrSC7DcXidVkgI3FYmOy67PVRtUtL0NCAziT/O3H3uFctTwaRxhgcC/n0s+QWxVRFFPSRoCl6gVY3AcCBPwUA/cS8+Cld3MaGQRrO/Dk5K6mhkpBNHlx6MOqpezwQWs1uI4WQZAcE6f9wSlmvhGOyxBKLBDI6MWKPiNh7X2Gv0c3N/PyHMOmyNo/9ECDbAQiEBXB6xiKlnqXU0q4eoll0RVfUC1m3YglibPonpIWuz5GdCmgl7/sNUumHabhqLYCLfXiU3a9059tUYdZ9ssACF4mVaD3reonuIXjJIlrbpbA3ZE4mh6aECDKjGXshbDaRD+SPjfpKQYh3xGiwFJbHft2uyUH1rtz8fDOP7SScwzu2GsMUhZeDLROfxERaj3mAX+79PHnxQY+OgXduUKf8NiisL4N8JtzIUUSq6tafjsFeCKcrbNex8HMdZKETN3LMVdou3Uu5t7vsEszo2kKXkAvUhLsCm1zNQTCPfu/5CpCMS8UuFxtPtZAGoY9K1ZGAa+0sQmvNCD1RP11onPdFA9Jrvm6uYWOXjcNDAZw5vKzy0JFOWn2L4Br5bsfYDttwSd12ON8tkmI40OmVAYMFRCeNbMkS7J+o/04JUE1TeWplpTuMM/TQFhJdK9454WW09soJZWmTbJOs0pdtg9gIvtP2cLNUzmu+G4dbf64upui6N2MtIGF2OQ73c/CRdtpAHpPEyYczV+O9U1+jWmhr3gxBfK0vTMK6xh/eFPVdSWi70UlR4lcanZ/gzvMp/GoQBbMgjujDUY8VRpKzoQMs1fIuScbn5T3Swc1ZPseOGdiLH9Lpi1H2nuaLrTsOZgtpzYyI/OVEurYPIrfGZBK5HtQfhSRSqYJbNZi2NBD4HsD8XshUWRccAR/FwG5gnQZ/WkVlOkFEV0mxBFgW+VSvC6q1/PCObO1rxOhQk1dvEtKqNV2CWcQZycQxy/5Sy+YF4mWLVuJsBGDDiM2cEvxw/ieCTlB8Oe3kihBKJnOJhgdH7NvlQMfrUcJju5tyRL6tooxtCYs5qeHTfh4faD0EMWOA96I0uxDNY6kQn7DX/bLJDHNVk+WoZn78BzZiRcY8HYtRl9kHDBQmCGPhS4S6HZ5UiKcNxtZZlRXxSYVpdqLuYKxB82PWF99db48JmWxb4OhD4ys+P1IWNIVMc+3Kf4d4F8X99XQ1bB5QtoXECBoYE+pouYd/dvl5Jj91pRovVURt+gWCULK/RJ/gc8YcfGmIV5FaW5T4p4LW52WkJuBjpE/HXzDkIO3w2NiIKAUTj3mawQUE388e2t4UCU++32o/DkadYfibSRrZpagrkaS5szFePpE+LK+/aQVUbeeRDMuwnbNp/XUOWQFDouNUSFQ7d/stSa6FTdXbWvOggvaCC9hlPVgu26UNAl9vQ93lc9ENcwg72hoPoVjoSBavDh4AfJluqWQb8puA31FJQF6g7t7Z3RyqKmPZ3X5L8fQ77l61blsKlFG4qUTnCZGh6UoT/fOeIjyrCSE3WI8RVAZ/xIBaljeDI71+gvn1fq+iOndVaE+lzL2p4X+Ig3luHrUuvxjzFcvtWwOEhG7c9/Uw8bkJVnsfUJ1TcIxVEYwYJ4M63HcJyXnAk/JrrI4hz9LClIF6TUjtgtCW3ybnUSEcUNzeGynn5TaWZP+sH35HlffAceerw1o/LKkJMa9PidEYbr4JYU5PuGeBfFBWH/3EK/2i8KuOSht+87oWtvEQpqjZbHV5texjzoMZJT0v2w9G7wYgLf2iiHYJopPe/JJdVNwYg978JQutdtRoLsQTKXuGzRt6D+suVbd6GmNaDnbqiFPwdD7EMAJUMAPctxAwx6C1tWi6Urv4n0LPt6XaBWdxNmIVRcdXnC3J+wkMyaychqUbPwMBGjf1cgeqyzT2LRltQzFZBJx5D7JfZqOCa2+oqRXebFFu9Wq2NeNtKUlYXyTiym+Xm/lUtWsp/VqjpmZa/5ThTMwP+mVCf7kzZ3h9h1yVSzzVwWTWyrJXhj/ef1+Ssle3E56ji417KJ3WYCETxNLb5KrWxs9vszvvktQphU7S2/7+9uMTgyrC9SPTrBMHg45a5T4cIz+5scsnvyIggxRHoO40x6nPeBbgRe9kzvl0mIKkhSeekk5gMlYeea/fAGe9JB2CFBCWFCNrXwVWLIJUi+6+CwkiGUJkNaK66kBiwGFCRHWuvrzjAyqWspSCaxC5oD6b/Vd3ys6vqDyCmW47vJ//t+gS6r4Zy/1lY836Ab/jrETn2iidKG+qL0h6l8rQUO0u7uQn3lmE7/KUn9MXyhfjS/J/zN1JQ6ZZyJtvgom2gt6dF5+9U3hQfb/4SVkTVNGaKqHMeb9VhqmQmTRDwEhXXW0Xu9+XCDwh0aFVHhGZc2OnjfGMORDQd+CX92pgRUw/cvt1kLON0gYKorjUOqVDQ23iQ6977byJL4HDymM+DVwEOR2E/BpPr1GkA9hPhQxExR1oZnTJLntMYqjFgfx/kyrRFUa+V//wEJhwhuKhFNpO+ud+UC6Ix1f+gAJbaF/NwrYs4eWaQcuNcCE12bQXhrx//kDKbVpft5f1mLylFEeITXQAE7cZ3tzvPnNFCsmXzQFRitumDh/VdpMhk9i+JAJgCCsBKPbVGX9jcKLf+3yErRbYKVkGQFtqrPdVQYYnks9EGfgCdWqg++xX/SJa4pqz+Z5xTMTrLKqf3YMZBs0fTvBPKiL63bNBS7iARUBKSNGlGczDuZiH1amgRnVcKFc/HTm7/IiFE6Bl/yFc/hc9bu+0BF0DAfB4+ueZR4mO0U/Fh3uMtbSRmeas9Txx82+QJLcZNvm1IN5Z0Ey6efagYDXC4wsUHyV4v3v9KiFSNg0euFTrvSlulukH1Hwn75I6D+KHBerfkgAe9UiN68Whp7Ab3bCMQpfPbGqaCp9bxvWcgnBJPxrTsNbMAd2WTZmjXFn1veIyd0ATRiFSKEH9OI30Jclm64Umv8u9C8jBwE24qx2Z0EbpzQdwhLjaBdEG0RDxP4rJqJqISFzO6zLu1Sj5mljRw9Dm9UFXVzVm3RAoC7ehRw6KYXaBUsgfNHO24QuyoZOrUIPdgcxBU1L/Oggpn2a0EGAcqsmL7jY+kqqJwuR3wthhkC5lBS1HqWdw1TAM5taU1tqR4oFbHAmdhxh49Y8Nad6vupfPXBIiGcFD2sGT+PO1TgyGb9/3FXyv+5oqAaL4b+QKM/4TheRi3idGX6UOVpk6gdauUHss+0GkQbXUjE0ncpbkt9xC1+HlwcNyPvkpxJ/5zq+FpVbeXgr2dscdvp/BH/ZuMTR5AnUHnrDdYwl3FiohmdHl/D7knfswfSwIJ/iVu91AwaGQXQcUUKqZxVTNXkktZ69kT5et3797pZTqwzf7IrEM5Zh9aF9KLOgq9nTHyRzF+cuRxQ5Sfdh0EJUNnJtDaEU9hyt+tvYKh8fl3p/4ZH65ZjrujSpw/IFcyLYdYW2mRgIOjza/qeT98r7llA4UkSY8tKb9Ilw5UYGyaA7ogxK/TTUQARBzUFFQopkYq2EiP5vUVgBzkdKy9rtVThIgwCkY6sJXwbiKuH8gT0/DcnUtLmJH2lYO7UD+ecOcB18jrgWEngJrgczpwr7rHxCfQoervnF/z3N3NZX+nuFX1uatb70FY0h+AGiI6tAz3KkzFJfESekiUPvSfoHPHUF7Yuujcf4Li/9VHdTDXu8rJmy86wRfKW46lxisrJyH888XcsjbdTGf3hiFNgKVsFuB4dgRejFJ73CGQSEwe3oCp1juvj7UKW2H8YUNbXl9feXN1I42b0uQl60QZU6e4MhTb6DYdPyK+mUiyuygUMezxd7yx5Oe2RCtSdm7krCusU+N2n2QEhLt9NBFVydrD50/u3k9934w07MTJmZNkeuJwN1YTuj9aIANvC+/YkHiQu1w/eGLTFSThl9BTJ+VM7dlilzc4vKmDAT6OtwW8qhOzHuJ3QPJ4kDbKBUI7hXDHTDq/RaXpna8Q8HiRsbXY5gju8mcit05Bb6g7/dc1Vnvu2lpEcrFQ8WyOrXhn8W2Zc3z3Qw85rn+iTd3YmYpq09yceKjComVgnA/OMPndsKQgFDjAWRgMB4P0kaT6XB/ZjGdYu/7qs9kMtzlAXi6gFstzpEXerU//Aotw16faQ+ppqsW784SEgOQSOZP+tEJuqX60bXFO814V+OhPPcW+4z8PbnaHG8s6ESiXtCaTA5BKaY8i5STbB6xHFGcRliZ2U7tzUC2Oky3OIlmX150RUkt7F6Tycv9ACZxyRWAgKFRAUgQSywg7+d9UBUASJWlx1QAIIIUTGnMEPLWvvEbRXYM75DmQ2eMu8mygwui7SCEzkdnW675yL+ezDnX+YD5v300VqNBxPzUMDGEq82nMpLPJl7w6teVpgiBZU5bpLy1fVEE35yrpAzwMGtAMZZYh4RrL00sT3eDiWHmz9u4trQXxZwIH5xMCIHYWUXtntJO1MfSJjbl4b8xRmJrNMt7ZU3m6CnntDvtj0ck8h/CkQKn/xQ3jR42bC3Ww8m4zKLVsnm6BBfJMMJIJNndtha/uEJ4Po0BthlV1kf0IQ2cmPy1AXmmOQshmiY6NXdTFaB8lZBZYTk4oSqYbCCIdd4gEAbwzHOmoLAKsmafCOhDs4URarPd+D8QLHR+0xlbdGbzhnLv+JHYfiztGUYw7zue8l1P216AEtA0wM3203U8aSIjEK7/Twe3SA7+ViLcozrrfsjS6PczRhGI9UKUnnMlVXUbbth74QUuNIxG1zGtHW7JPjgZbi1tlvyFuX6SIpt0JSeFdM/oZveEX+1gY8djiiOhhftZb9Nk2bSTPj7rx/Vgt8nuQR1H5o6k+iah9fkb0Fl9nE1ygl/r1tWw54mLUd9GKMJV9VPAjmh3G2VyqqMKKbcp+UwdFb06caKcotqAgW2G1PI1Ix0PfxpVaHkQTYFi9Q6YmE/cpLrmf8YVC9Yt+k5yRelje4fmQUN4uN4dTvg/NPrH0fF19zveai32di3Nd9wVjaws/yjXJW1dhoeWx34jwbrU/yBFte0lxZ/9rfBuphFmequ+VmFh7UMsrwBn/YFzSAdkCsmlchGF4+5djFZxUPMM7+RhLLkpngkJkPQSwkaM5H3rPCRhWRHamSEOfgy01Z+e17I9c8JR/CEhxH/KYuiBZEewdtL/h5DGr7N4A4qJHsMzdFB1aLyWPWAcauU4iP9aRLcBIMwqT1sPMSyaRUUHZpoEfV2y7Syt7rqLdt1cpHUCNB4y71ERY4HxBfZ/GwXd6LANRl8fF9/73H7k685haUzxZHI0qUNHwuZpAvMfcsmD/gyyMSeW90HP9XRnr9SycDn+64cf2bq+cP5k1TASa4nwEmYShIGOtlHePIo7EXJ0MBNPH/L6Iu/sRbYWakyoITEOxDzXAzn8EdER6ESHTs/Eg1Wy/hGBRrH9hypLufNgci8R5hBlqhho/BsU/MpAqdxvRWFDc/xAfewCBfsUNQYKCo6eTUq8ygczpOJbQwxgvqFj+NcimnRoNDsvDVn1oOyxfO26sKJSn6+c+MoMFfv4uA8kJ3TwclY1Kr91Loi6mHCbit4a9Kraz44FJU1gQIUpkt0qRPaMaIfheGew89e6L6IdkV4rKMob0ZuaDXOKew+do72oCdl52hvXJ6zGkBa6GadhNfJ1wiakO19mP0t5aW408pvM/f/sT5CSaWoaBLlDt5T3lPBCIJu7BA/Qaux2dB1pr34Gx66leMwJfUKlk2tkBGlJAAmncQzo9xgjcqIjIKDLQ3POeEYg+HGxQjciHWqeJrOm1R9LFkAToYkRh1TWmrh1HktM1KF+iJhBY/VvnPUxc/e6Lxf0VcZ7ADootXpbYe540hMVtm99kD3q3FI+wPR2mVM/8e3kxJrpW/ECZ57ETR/jj0J1B5vmJz8PhvG/zcuYnmn4wAuou0kuN0++cNTk6FwQeiGoxlJ9Qt4zseXzW2O+ha3QCG6EmvC+5Zini+Vf2oqwjiTuZIeHWVl4LtGdUwBQ19p2XrDISpfwLENw0pmLvF8C7ASojWXS7UHzziHCjdKBUqBrAOn9OfQYDJUNvte8yPDi7j/h1ziAgXlfhaincz+vcGXkcoCZwqX4rpMGyllg2TgpjEjaNMeUfjLqX6Mqz2T14FH02hI3VchCHkCW7eoeo3Oz0MYr412syw9qJYzi2UJM9KkLja5LJhd1S3uhJuN8pXrILkTXC1rqYIi+8trQZYWq8uQ+SEb1P6aBH1memNHoZrQVULyyExWChdcP/knYGCwsKJAzP/OaC4y2mMJvhqHW91go9qjI0ZwxqLzrUtJ1r1z7Yj9/BN3o1fL1gyuqQkHiyI0wuEf1fiC7QGwkEu3qRRmykVU0Usw1Qy/GZPmOJCpx/F/2by7s9rVqyLvyorX7H5xtvt3d3fs8vByeH3tPl1K+Fb0nMo+StGpdC5IcKnU99dSkSzK4adr0tp5FWXLw6l8YMpsMNUGfP6cEKWLvaSMjBtOXsXWmCuecg94jeoug6A/wnX3t+pXqIoqnyxxINjjPJ5aX3fmnWL1/d6xSk5qobPTo3iEM6padj6cbr/a3IoIhLeApjUy2xzX/dnJd1XP7DMGeJBLfxbJLnEMi6jLLQWtBChB/hArDMASkrsFoaTyyDFS/J4gD88gQIkqug1SzPV11iWe5/lsodmGjq0yy41O6Nfr2NqbBg4ZBkjvanjXuWdoZc+NlclS1Bgq3FOxJtMoJm+ionYdMp8znhMjn9UVRHvdO0IpIcblwTWMl6os9jMfy7/viBL8PtoiAfgjvsbIsIMTJ5h0e+Eys/sg1yWCIUgP2a2/rp7LCezTU6YaxjTGg5LQlDDyhqoIS/qGNFrTvdkYZHhmSnx9JBhE4OMug1VjbDL/kjPOGE1OFda9EUJL5Dw1Eqw3xnJiPe8LD70N3ibsnuOZ/xcGsMYwSQF/a/L8HiESYnt9XSoO+Y9qykeqqBtU04quNa3YHr0LeuM5K8fy3GBJu9jhYiVQ8Oh3v/DZz0BYfaLLdfSkUW/QsUlSRy4X/xdBo6PkaeKtNPity+W+4TAXyNtI9oifa8jnTJxQVdEmmfwYppKjEntQtrQHZHYCisYvnJZEgv60JfAG0TuX4hQ7jLAcxf+KPUYdb03XY518CPjat/Aigj64YNo8E7hy/h99x2Ai1YaJJ7RTGuZ/nIkMnUFEmrMd+UqKzukymPlmz+2SbNZMx37GGxrtdis135EuHNmo7yzpyYbLX7sR0MS+MQB/izrfgIHhiIo7HvTjpCEUoPyyYdRHkTeZ6xFPKCVzOo36974VBC7wjHXz0ZjzrJEC+zdzBsjfuHHeQ0Wly/ty6UKL3HdqPG953TfsPndsJhouwxUnSaC4h5LCRlcHUVDu85fOswkpkcg6xcRRvr/wmRwVh9M0xyrGHmbgboz6Ldc+GlMLH3Vm5Z5kBsV7PPlgmKsJsOl3xx95DuDZhfl+eAWw+f4G2v5Ilt+D2xvENm1SiGcc8QNVj0dAhsFnjn3CG608idHLpOSm6zLBKL56hvt3pYpEj1nbTPelZiqygnWNBJbUEZ4VUrpotmty0BwWxYdFj7oFL22stU4GuvJqcKdFLRpXN5xgNRA2PalovJOSghyTj6zXfD4WSH71BXQjc4BQyonkkuokwV1KFeuJ8/HzDtCLjyaND1toF3oETk3vm93Qy1Qzqzj7YlRRzJ7WTYOS/Brs/9XFheHykkXt2LQTrzsMJ/U66gR6G6Hmi9XflMCzb0YMGN+WblFL6uHvzygWKtWIQwsixfx+YzCLBHRDlxfJe8m5Pe4t/ghOeDa7k0Hnqf6wFNDG7eBhzDCR20DjNQBULgAu960jOVi5BcjOF7KUINw6RIm3LOde8nOo12i+Im5ub+QR3c6DRux461qUXuJ97gGGBzhdM82ehu4jmcw8QU88AFKSiYqOcUpLZ7d7hJq4qcMCq5mejbdtqMibuSqlBMKrtWtJ4GXf9CxHevM+KnZh8vsrmZNRzgdSLY+gHw4r6urvSN1bARF/6Vnb2aEvjHtdf83YXuSAaCkPMVHf+AmTaOdBiRgd5Z28NtIv2bl+OJPq3niGQAX9iRme81DHD9FnBVfpgWPyMB/wlQIDGbb5wkZTyvQuPcwypvy+Fvao8UVL1Tg5/0K8luFjGU1DNMn7QsN3JH/AowWkzlXVlNFBpxluzr9nN/NKrEfGvps503eBQCOcQ3tHsYJl39Jz31H/zIO2FJqDeHKtYJU6lk1gJ2JfOKhboQ/Et4QXdyHgc0SPB/c5nOz7zRPsKL+L2GqCzvvXjjWTmSdJWPTDbM2QhwmPlrOT4tpwRrBCo28+cjeRO31IYM66ivvuLsOxBB3SmtZKuVw2jKjQC6rbNQkLmv//TJ+czJtgq9Jo+HEbNpG2ajUgLc+fJWNO0g/dop0R4EOMO1OF0Ib1ltno1QgzAnrILJ+vQ6Kw/lj1rzB3inlUK0/aQrXI2P4OooNvhKyHUS1bWAzhPcLpl3Xcy3OQlftDEb3ni9bUFib7iBZqBCzN1cjGwjY0OjkliCxVr9JHGZxEFc0DHhenC/nKRIdaSQdpKP9EFleGqkt+fGdjk8G8RcmpFY5rZHakeGC2DE+1xgkk4VBwLohQy4xVeHXY4ptAgWKopwp+IZmVT3OGZEfOIqCZLe5Q/jWCdSC4prdDQyTkm4CLhnhpACGkrZv7Ojebl88gEE6/QLdLbJWogLsmhYECznS+VA3xQkj/B782bzrAHwzyOa+TWNsVMJKVvv4lnfnpgvSDBy1ju5sn1cpUxz9IVrpz0fSNltfJDnYuz3JhPcUMEBEOtNXUy6m3uKcfoHTzxVehBfj1iSna/nmECC6k8c/+APoAur+bjIUcWJ7jmlUosU0T3HKllhz+OgPeZ0kwRlo6Wl1hnS5ZGTXqbjh5sKeZfEVCKSLpupwuAq0erJmuJRbvkPxztGuD5UDoPfTbBWqQbaSrSvTqnETuBlv1Frylb+rvfPNjXvRPuwzSTHWWzlfbuqc6Qq6wqTD/iG1uuNr2PU11xdYoLtiOERN0h28R4kOifWywstnws197t69AyiZL+24y6kGIuyWY817oYvy/NvOSoRu+9gVhRfukdCf4Z4xgc7BwqZy1d5+iSp3eQuy/SXGtqDzf6ZYWXzk7Pq/rN7Phaliayk+cqYC/5WgTQa3Kp6sNuN1tbnXI9D4MNDJdFklMdS1LoVfEvDirZ7FUJTnCmNru9ip1qR44kvsIuoMWbqalz0v5OECq9eJnEpwRyEpPh5xtO+KTsFwvRYJKaWQZEXx7bg0KjWQf3Mja+X2k8GoUl1LM5qfEx2/Y2nRAwFaRogywOAZpqxfT0xGrD2ApKmRWztSZynLen3MkHrJH0+y8eZMzPiArZR85tGj9UTvlhln8ndqYTjfXgC6XvMxHPKG8GvaPmVvH29p1TgxsZwZtZZAmF0cKs9SxYR4qXpewq+KNxtjzuk0MNaDXru+HgkQSZ5VYPYGRaW/zSwEmzJfOPtMLai+6KMKErsSinqw7PPNjIm60+APG7Zq1gfR9gzwKdAq6rV82SADEZDJrfT9w/h3SUTevo71g7Pt/A9DhzIySzuvG7ppzblz0ux/3VO3nxOCUCjVepWm7o97xUmOzrcuFYQDLi5VDvD5QbarhUBmXJbfmeWH1iu3Q3N2452VnJQLMD0UpcamcWSwYMoK07Neub2LGzLalGhcGbS49SxTOGgmbn/RT6xAaekRhnUcQK2IXCaOGg6gAO8/IIkQ131E2dvPw0OD0SiFh5aGxOGJ9Du4jXdmNOg23r5tm35wHLgz9oiiT2253qnCVds6gmxf6HcxJsrH+OFcBKm0QOupE2n5GuBP03kF66UXcUFOOC8/wjGBrnyOM43nB9E4p4+LGpQqzgo7CzU1f1P5OILpjdz6Whlr48eL64EjX28ohK7tCM64xkZ2mYBOkCxwLv8PpYlsqnjqCqv6e8p/J9tn9CA2MqVbrarfaQsQPG3aM0+H7jcQifcL4qGWrKFbaJdHhHWI7qp2YhxlZaI16mmEiM1HRdzdP3WULCxPUJty4XhfIAziTkBqsb6JyGcIYLN9UipVI1QRIfSRW6rIO5fUmx6BCPf3dCXKZqSwNkmIewUr/mPxG8KF8YHbcMnm+iNAQPXq8efSeW/ydylte3Dq/jauRt9bZSWAQk2eeXVRm9Oor9vxUsbfLMW9wDK54Ugn3BBW6UO2RjknhNImEqL4udSI6xCtDiOFeH6hI/z5rVmUM4lwVnFlCiAexJqOqq6sVBHmjtJFPbSJIGvxQ9ogJCZ8g2PmLyenumN3ylaGS1kd0KlLb9I2u6MDjXn78T1kgSHzZePotT9U1EJibduMUg2tuJpn4ikIM82mRYu7pJs8GK8PVoOv7YTJqdScuMFrMl/Txdb4PQdC8aFvWTT6I3zaG9Aw4vDBHZV45cEAq/khx/9KRfNDW8vwJ3EM4lXnb5P1+mZmIbvQYTvhVbPgwF7VPL81/DeSMmzQ3U8TAGMGqCYk9k2aaasaptvXASl9BhCr0KrguBIzrDTdZhL8vH7AxwvyEhB9gj2NMyb8B/YvP6kMZ4iDMNspmsaoVqkjzmLWMzFY51b0KLlxDcizcmORjaJx98b4LS8xjE1j1COticKdfdMYdb7m0G37XA5N7gj+0PYBlfSOvj+sX4wj5P6Yn8q3snMZ3sFuMlGPvZaleVbYCMf03+Iijhvf5ab2SNPVQGS0MU5oSK5v/eYY3mF6XWJja62FltrGi/UcotbKKkaMXLH09raKigVRebfA56lKB5oZjSHTb0Ojil0y4VXDK3SvjfBdX8hukXOR3DHtZmJN1xKpCfRwNtBCa5R+wJq6W2LFfEfG7P3nbXpSMdij/5qVUa1jSYb17ThMwk7xtlD7eZnq64S8CrganYEd0Pb1kZ23P9oxphTIIGq5VZdxLLO9PwaDxd6dOO0Pj3PQQsQbbkysibm8LP+8u6FfmjV8w+pD6gPHlTaukzgcfFqw1aXO8qHMJvguA1fPALbAFYcCqpQGCEInOi5NNIqgQP4drfdhJSDpA0CaLOhA7Ic15oqEzM2NosRrGNxwuLszEi7ABucxIkwYt8jVze4mYd+MiJycvK1PHRuGKW6rfkPBDlI5/In6CLaCqI/tTkTDvIjG04p6vUlgtcIDDXDFdXPiySGs0PpCi2FMzVPCLx3qoTmwSNm6FsLMHOI7MMCXaAdJvmxXy69bBZjbd7tkJvSgqT/9GsJhQ1wwdqH129jiByq3ibBaLe3Pc3QNGLE52BVmZg09v7KSR+P1OaIYZ7twqdETXaxrDQGUBvGXCtfvKhHwjTLdCISHANWt3bg2dunbHxDmWRSrRBpSyEV6mWOn1WeCcKFXmbMy3EJKvBEyitHsjCrguv9SLcqniX4hLYpB1TC5y2gFHg6Dk6uD0iuEvom6QaIVhs2zn+Z5DN7Nvt0tWgnnIwlFFnUZOgx1KthAwoPUm+ByBw0upNyipA222r1Jzx7MrOEtU8aE95Xe4LMOyKupwEUzjbLDSP/yWPJJMq5xIeQQXJKok0lh9Sy42gQpcmnV/peOC/z0BOuBb3+gm7SisO+vGwqFY+MREuJcxKPkQETO2lvEwOXNbGeOeVWyw8kTn+orlsaTAwUtwOXWLFX/NYtC5wUcyxAKaVvPiYZa9dDK9IetGEG0j/VJlj5PvE19JIsBXpMPhSUy/dLv1ts46ntUvz7iLY7gRgHwVxsdRlFiTBrVXCqujR6xeQsa+mk3i8WM50f3+7wTzGFoM6/s2XnGeohrMYvFmSSPd6868Rsw75rkcRjt6PCyfEyHld/EXhM1H3X6nWTxAWKpos93sS3fUvG6UZJNuIbeioQ+iEv5Nyonl+FuP3sGYM+ML9OB1fdQHheTvhgHr1l+GQyS3RejAZCdo41KGWmpeSdmH/jpgZy4oGlQ60pK26Mixg6PlGMVFy/weiOXWxcfhyu9WqjPEcd0hKb4OhCunvK8egiRIz0Aynr2BQ7B57PJ02vuMAfCZFVdM9zEDX4Z1159a8IAUEeOoK+FBfgudIspzP+e4pNSMB+BuygnEkEclPBmk3CWrQjG502c8TobBzb/VpgLzpt6VVraCPPfPNJoUR9nBVasUkgWa2HegzQRtQCTbSWXMPLZxuXFWTtEOE+3mVR7JG4YEYy+y+AAy3GHcFuxamLnaYybfO+CFufPEO7yMlioNUDgu7u+kL5nd1bs1X3oQ3eEy4scxHe40nhsyVbbBWwQxCLsvh7s0FU86xgE5SPt2Q3MX1OQYbsG5aBhOD2C01AuUgW6RCYUAgFyWM5VJ1SHADijs8bADpwhummePexUDI+jnAYj0l3OkOjCVvc4CejGtPU+dLiQGTR6qZjYrHnMVaEYJmeBJG5b01N0ax3n+YlvlpexqBiyMNDDnNNnFQPF/ZQ/yPY2hKbkaz+BD60Ib5OTyg0lFe4CppM5xrMSj+0S+wZzjmX+zBHVVHl7E8mU8keES8e+VUZGNEPfvNbIftHFg29g4rm6QRjnE3XRIKq5IdLoiDYt4XSGKxnlnaFFClCr7alH5YodIk+12uSrYqHK1G4IK/oP/Od9zonF4jYuYXhDp/dISRqsxyIytxiLwvbLF6+siyOrAwREpn/UHbKks9dkgZTqj1Zl5dkDfkrUw08u0o+G//r+AljjsRPr5jg9lyHohcX5DWQYgO72IuCQFIRqppJSY17TBt9IiztqJ85siAk8LJNz5QwSWGNyYWUpt3Ly0wDuuZXSjDCmndM9oa/DPp+80YZjODZEWUG7m6TArczYXwOJp9deUpP1YeD8RnGQa+BUNnCIG9PPYy5FNjGxVpnF/FiNhwrvR0sb1dYu5eLSramtLAVaWbe5ZufNUnacPnvnWBrRWEA3OHm7L88y7bgLBXu7WXtsswhgzNdG/C6OHwc/7SaDIFVbyv3mZdnDLPG55bBOcQ127bul/DndLJ6EXMZYfR6KdlArtWch+6sMO4q64UOaTflhPlVkfCs9S2lkr9rmUV0tR82RfZftOPeksE1/79VQDTpOXqyGkMYDLNPg35H8kQ4NHRnwB2vqIoxJ6Qwsky+rp4PMQ1fks0mAWQAHrOwPdx9OTtk/QHzT2xCxP5IrRAoXrBJtmh+z/gLhd7Hy0ANGCwLa7Yk1fyniU84K97DbfPpe7WYEf1U3AH8LUwoSonLOp7r78uCJWQd4ueDRyoctgJ3yWGd05VPklvf1zqCOPriQt+K1JcTd1+9MH/sMciEh1SKpns1iE1Vx6PrFYZhrS7RIjlna6mhljYFd/vhGp8cFZr7y6F19qkAh0pWLIiS0GjsczIpDuI5gG6oDdbk7EidJQjVZJxaqw/hG0C94gB1e18fJ0k+YfZPBAfJJG9UQjnHHS2iBUoA/2lHp+QYPjHFsXAG//Hy3RtmXyJsKJGLkzwrK5mGSeSUD+TzcXedysDegZk6Jj6kjAFVJMP0tKIN9yimy6D0hnqYddjLlVQrTfK4xg4Oe30ydY5hhdVXmxjGIHPD/fXC8dGy6ZPqNhu3GeUKBLmN9l3Uljc6ThMKYUZUBinA8EJ+ZT9Yjt3yEM0UU5VtO22NtuNEvocwXLOetC1UFnOhb3QUIO2wndEfGMDXrkpSJda1zWWlZt9HIcLKzvgHgLJ9y2YapYiDqRLMsQTSNXWuBDceLASvbrrHmNL103C0T2qR1xvR+dCLoqHCdOnIjVH33JuykFhQ3JapJoez0k8mwTeEjkvho3q2vP1//T+X/g3b0L8/4tOFoPCoTtxdp4rnh5CMUyuYUAL0rFEuYyreq5HzS9IXC+Bd7IurZw0bJoVrovCd2EHxhBNVBlWV11cSKP4G1UAw9X5UeQOLRclJCpH+b7zDnZBiR8/HYF/cfwpBfmc8iA10GugtFnNnpxrTrlIsuK+LOkRtRNVFINglaE8ZE+Bn+iiXRtzzoerC28khuFxr7Gh9TNbth5sttrUbL1sTVABSabP3iBeqljIQfHwysH711f9uyWeqG1i/KE6wEtL4D/scZ/j4CYfV/iWNzPnFOnDkRbFAO2nvtD8dUAUhoZTIa55LVGAvYFphLM0wd3bUqEpvT/Nqdls+aQrdyKZVbpWo7WSamL46YxOxR4IVAe3c+oVFXKHcgwVawG3ZkMA+CEOmx10W6W1sdbuRqP5Xz+WMnrx62E8ynx/2twN/jhVwUQlxWFV9gve3UPcNii4Ey/nfGeemSRmJqeAtE5b3YWoc7InlC7iqo61FUPAULWYeWObEUnbwFlFwgQZwGZsV1hf+WCyhwpwKufgODh9FNv/kcejuOemLnMicT0JnIH6+xkCXjo0G9QAg6tZTphn7hDIcAU+a8cqaOCqJRAu5C5We6mW8153vsmMxlhMCIWZx/UZs283QM5ZgK0Y+03eqNoey051dq4njkyM9N/TnLh/ZRFeEJD4B4YHyFdmKVDv2G7gnAhjC/6OwtwWGQmcCi8U/FZUljUQC5wTloSoRxnrpUmrMiFIk/vw4E5doK5xbzLp0+mOCCYc+/Vbl1IWGAVrzv01428PVEp/3V9biewhlu77MtFPAci131/TlcTv148bolBPBAAHCHTxkhq35DsTXow6Hc47DrimkV5jt7YcwBe7jM/tzVRB55nSPSddT4uzhVPOiIkfXllFygtiJ/edd4rrBhraPbewWlKN07m1zlCzBxXFrG4ynWWLQiWQSdwzxZm0GXTVNiY+lObP0HkQu4Utpe2VsrlYxk0dyCTyt1fmnM/k5thHKfFIOaI01uj54irhbxWJOMafSEV6YeYE4o2PMYN5vfcBJ1VfrJPr23Cv/R+pah8Mbaw5a+dmuXS3Lp4C8MDLqmaMv8k+n1KLwJt1s3Gzllv5/bbD2hAg9gQWX7jcNTBgOAtrAqgCMyJXvbdSFISYv7PzdMx52Wbgcq4gwtkKBWhku6kV+kzm8IdDReMcDaoeeh1rIkkfOOP3lQeKn6T/hGutJKqEbT1qU21zT79tjt9aBzt3LFcNTpEi+SY4mgyOyq7wo0RjhtVBjGqCIXyULiI/NTtDrhyQTX5dSYf5PLETAu4yW5NfUOMRN+MjnSIVv4Hi8IZNWt1XnYQmC+OiKfymAUZcKCWTDMtGQJ5TYkE/RIALaw3ajALZf4J1O33fjle3Ay6pLT4uGbHUxgaIudqRPpMgTgb66UeGuLJ1wUcT5IwjsmWACcgunO4ddVXyySCrM/Ql6TRlD6NlAQzT2kXR3/5fZNg6eZNmWqiW6sNyjh7cVsFY/rl15zarBvCM0Bsg7lPuhDMn63b3cVsugA60seJvct0OoXhIAFvRSzast2XJfjdS2kKZU0WfZDCjyq+mQtdmZXEWiaZmyllL7b2T7m6xvb7Sh6NQXSe5lfizHIWyBzZXIg+w9SU2x3ni1w0wuKyIVbyC2hqMmDZwRV5T0Eb781fUcH4JuAjj9O//qWNlGrcd3gZS8cwpuR1XlNuSu9VAvwDioRCAu4Y6qfloiYcL4aL5Sg1yTGkMEZYCnd8wP1bc28F9h9Y4PcUXf2ktuqLJY9qicbI/bdc7qsAY9T76cpvUb8oeQDRRCHZhGhCjuLXfdCmm0B1jD8LqBovFE+u1MAL/PgXDVGhRdFdPOq6xKb9RK53l5NTSaEDhpA1+OZqh5BdaKQTKRjlKq13qi46pOI1hDH8n3hHrt2itrnamSfeVmPiVJN3YPaFvYgC6yPTKdxC9g3btor5h4TgxY7kJr98GGG+U84TlmReGtwOCGnr1vacdzN8EdnIXHAoSH7n+k2wNCLQoCANBs29bNL9vmz7Zt27Zt27Zt27Y9i5iFnM83ndQfU0L8YtvnI5ZUczF9WlRdUeQIFXS9mRvXD9XTwNLWcZqJBgzfYfakaORGh843XD4MNhPV81kXlZBTjOMKK5CelBMmc7K5XjVwb0uRSj1LB7QzNwbiE+vEfyE2ESr9w13V+NXeOOfgC4jYHhzyKnqeO5dN1R3pey6DifjIJFFtjCxuTTwUne8YVmBjX0e0T/wPq/kRILLsmRGBP0/FQZ7B3b8prwy2QaXMjsJGAeMNpVSd/s5S8Xl0pCXqsbxxxOiLahL3nTP10LOQds3n4WqI9K9vSTdBLq+eDE99S+1C9yyhrsQ6w/AJKpEYQlCnfIN4Kk02ryQh7FVw3nQQUzxkpB7uSXwkuNZzATbtg1XooeJTMqO3KGlsL11tnUDkyqIqgRU/kkOazETDoceFNDgN9aKIJGrNECw+UHafxRudF8qnq0tYU9qzCDV96uMHMFA3p/uycW6V93fpO5llvsAozXaq8WFBjLdlKM7nRV8foIHTiCSORfvKjb//GXs76TvLDnWolqD5B16dDLK9GZBfHqUWE3Nfepf8jX0gEykk5noIRuRsjBTTP3li8FViLHGCmKmXEiGmJppTBs2i3IundNPJB6WuPtFTUmGXOyNJqzRr88DVoteG3l6S0wji4W2zDQZLADg3MUVPyo43MbVzSJyl/dbosC+SJuydQD4Mq2Bm1fPuL2ISkVXQHN+oSFmmPOVuOboX8y4/Mc+c8+/gBgdbcwVaqQsSkc+FNICXWypaJFxeyTn/SC0jcgGhRchCw6yugCoMH+7+CSHUw9sgAEaDZWPwQ70w3Ee3UvXGmtQQot5flfnI1sGe1FzUmLocsOkeZIsg/djPsJxfq/YVPW92J3+f8UFwCdvEEHfr4h9kSmHl4QHFHEtJfqnWP89nLBhLKJVRZvmyHHglRMk1XbLKvicbz/Kfhq2TTprwDjEV4G5xNRnZXZFWXe5BtQjkxN0UWJpH90+itaHLK9DKjpLPSTiRm/TzjgekzoQ/LWkGoVSjPruUg6xQ9hCQwqaV+Wfeb4HvgJ2wuUpqTWNnh2nHHQXdsNU1Njr3itUQEp7w7Sp+Kd9ZyKR8xRVRKf7BTX3o56e+nYT5DE/wyRPOiodzITp13faAHKGwj8PumWwg8HmwEpc0YjTUhldWHgY33ojxG0A+jaPTD77CpoEYjrY5O8HxzBukHgK7qu6Sagt7+ZPR+8DHB946O6wEkDz80sdOV5E35VSCLSxrCmpII3/a4dRhhZSbugNPxPwsBcOOP8pYaNZTOcci8lte40hDh1ftenTJdwsJEB2apb3sq2ckPMF6GdU4IxJGMifX05t/w2wtF8Qk1KX0tosy9bmo8YvQYFRwGgiGkznZDNoQGdWlb0KtiaZX2aYhR/0n1Q4JrP3hdztfjLPPpxGC/TFFdBUxn+y3cOd2aS2TF7qcUUkXcO69IUfXpWG6Vz/kiRxb8blDR/JvqHJaxD7ZGdKuFsp/i/remgqfMQNZXiTgzUBjYM6g0u8gMtcEZt48hs49jm7SNnx1DblvY+MD1zDxPbPOKP4TXDyIuQi+mEdBk0MeZRPBhdG3l1l65p9dgjCfQ8HWjpFgq4utulX2MpxyqFEuEwMDPrqu1fE0MiqN/YsxQT9uefvrZjQp9U8KeKDjo3DCoU/Uo1FdkSlnSJj/fn5V6SX/BTb87P31PcL7s5/lGdCfa+RRMOS7wLHSwJmxZ8MtBLe6Yy/UVNTcmg4fzuz/6nLBsRkgKgwt0P++UVLp1vC5ET6N9fCZkA+efXhY+n2T3+hkkQRiMXWgoLCymxy60m3uiZb0/yAFKdePa2sHWTWMHRXFjXQtaN696NBen5bvF+q50AS8QYkS8xv+TN1fh2/TbzPpXhPE4sDE9sQnRnX1XBfiz6BKwt+nQlGjJTiMe2f+9WsVHS5Ijr0NpNIssFw9gTkJ0C5RWsPzTp1mUtsbEx/4mgTPHCXmYRcn07W3oBbGSeZKpMDs59ayQW3vGM4JTwouGDaNyrezy4Zkl74xNJaRxwqZGa2Q3bicL+Idgm1fagYe2ZN+4pkgJmJtFRFmto418RUXm5+Qg8klScVZfbUuVo20bwMY3DsFU9yZSqoiq1yODiT434REwM19VnFb+V8w8SrJgTJFTDK+rrOSJEh4e5hexKdQlHMlWkCE4Ycuc5Jh7in6eq5f/516vdLkBV3Dknga+UZxfGhniwpn7tGSt5Zg58Y7riudZeAbsEaDca27NmvHW7ENCP9HFYRrzghy9SsUPqc71hgGcwr+n9bwDwraeKsTpC8qqNtmTbitIEF8AQZtQ15pfJB/39alNq/8L7Dj+hEW2EV+GKXs+SCVXBiu7UD3/QfBeV7EjkBZo64oIAH/a7x2KjogBSQrJQzYfGsbqWtpVYhE6L0cBh/Yr+1E5rWAkpr2YhwghybJUSG+a3y5pLwjhOehjjyZDr5IaO1Kg8z+0BlOtYat+cslB91L4HKcH4q0Kpa+6nMHdM3a5hkR6+DODCljz6UPPfefAOG2G1V3vEYj8t2FBKcELWFgd/BAhFK/SgbN03BCs2ll1EusZw8XyM8MEYgRVlJ8ooszY8ui7ciWjbADIKpaAoa5Snh7K5DogNpi5K1EaXO5DdZ37tRX9avpMbMXjYMsC2/opViN+pGqKR75Z0s9KtdPIy22jLuJxH/CbNFK3jC2t3UVG9/ANoyJuZZ9UmbosTqcQCObNpYXoD3Tf9sn5pYHqxScaSB/E08kYcEvqlGz88NMKFAlo+mRf4IWucB2aUOox+kfOEbCimlvPtJEP0XOr1DjDt1mB2OZ3+gP6kmMGIUPL3pmPAPnk/hcJvI+W7Kv1Mn7UEh1G1UiZ8pngOTveJ/NAA/PMwj4+5gLUlYkL85ldmQQCXcSKV+deqrEoWMPAT47M1nGAcPYDh9rJMhUvQ0eFYcGJT0MbPzlO45DpIiFuFB6j/dIAzzBKTdPpTQFdh8GYmkrhA1CBoOquZO6md/Uh4ROGkG8yEBbFmcG9/qWr6WVpcVhVUoyqSRECt2kbDVN8qD5GtwvitHDF1Fp3WobxUnMeQ/1MWJOAA0du8x9jMySGJ9OFkyqR5jjSGj7HtXwNye42bdFiM5BCXOBR15VCdnhn0IvVEK6lJIAcXwx2j5XXOdIQVjjPonLOUZsX+5l4QIsMqWNaBO9KqMxhlu6bowZsTCjEkdslwb/3f3+F5D6HtNt8/qibz2V26HHviLX+uxS1CZBuo0IqqoZd7ho8M8E27USDslWHWVWMB/4n8BTnrh3XrioLJnuUpbjiMRnTlm2s8jLn/qlOvPeBPO/SQC9G/rWn042M+DBCSu9+s3O6oCV4ABBnCMecq9ptQfGX7b5cUVFiERi4gO270/lFJ8hWnWbViIMq9dlju3x1hPNmcIbIzH+EzzZgo74dq0EokulmbUT68DIBYR1k+aQLScSJZyvUG26FDfTU0C4tQmuedu3lBzeSIajrzctCOPppaQImks+h+BxM0k3+OVblIoeIq7hyU83+TJG8K1sbE6NQy6yt/QhS4ZGgXKEe+q/k3H8LDrVsClrYg3Vt0mFWOUT+Zvs/PcWEzyls2gXr6397VeLQS1lrZUDUltGBgWBu4bxdb5lHtptt2TPn8S9n2q69E+1cw5+s3EJZfeL+3CPcmWQgaErPrkoLgzRnhpgDmISAQ/As6vi5hpetx+Q6IriVlXFwsm51uzKZ9XT/hCp8DAISn43s/EdhBYUqN/fff/y3Hl2Zm1azlG+s242HfNGU+qCbjI6kWnhQ8zmouRPSTjXC4AwwSM19QvlukFiY6S6wWQe8Rv/Z5sqUfIksmbwTsQpSR5dY4n5MXMM9GL4OMk5PVtk6zXQdzeMLjXQVW4uq7rd8csEXtTRmWdSGlvlI+gbuMPPdULuFtq1e4l+8sqGrYlUSLH30hGmcj8bEkjOi6WHZxLiyKAizQMrh6Ap76a6syLsVKh4kt6ASNrbiRXsCmy/RsN/0PCZYjfnDA77548AG3BQ53iXH7mRU3nnAfZnzI1j47WAOH1j/GSSPEhfYvRbn72dtQDyntc9ibACFa6Q5a0N0mA83ZcPOv8r1NCAegz76pGfIj1+CLNuh/bmCB341jwchRBAxrcq/sNMjWuwquOC/ayWHek6FJCiLKlt4ARokooxATIyE3aloHYtyO56j8Mywe/qhWDvbCsIQppHv57Sxrc+WYVP8EwcqXmtuFjql4PLfm+P+eebmNMgOI6uENXdJbC8K1BS6RcSReysJXtkKMFmRChuc4fAPwscLp+Mp2jE1JpX36MlXzNYssfoYySFAqSbakB5rt7cIKxlytUlG9Ol/vlzeI9jHhgi9F2PzWTqhj39bDC+G+twov/D7bnhBN+NWfRSZdFi3mNV/wcNy1IipjYmsnbjdHvO7LLJl5/eYchYStGNKnKwubHNdh51uni2Bhf4E4nhXd6BH63ZWt+xg4FYWA+VeM4YeOxm+gxy1ELyhamuzhraJ5NnfGIN7OB27nmwfqit8U9VtMDhtpjXyBkWUljlHYeyEVxOed95eN5XrTrMc8D5BG2GbUhjOfZI8rYLywy7X4CADhLsuCHRW1IYLWNKfN5D73F8jk33LS5hn772XxRqkg8DyHbJmEzXK9v4KOovH32Ci/mNYjtQTinalgUqPMpKuIZCXo39wTFMG+nkbxfeDt7n49gavQ9/RfjRF5bWacBgcvil2ob/9f1wBt9kb9E12n02H8QdSQTNS6vpG6m75n82iXTyT++O/hrG3xe0V6d3m2Vt0Cdnhom8kfeNyzKHdivL3OPmXmw/b3toiExltd8+sJkBa4bO/IsQxulh7HVeYQY79gmBI6Vmn2RFsRSVVfLJIEq7fY/63lTk0WnM0lh2Dnw6lSTHnjrJ9oHoakblzvghM4/3z6KdWxkvxGGtgJABAtdacISb1D4p1UKCm6O3uUTtt5cVTsCTTFDJX0LOs7INFyTEWtOiUWFCioLvW3KUkzRmLg5C7AOd8lWpxt5fFFmkU5h070CmcovjABelFs9ibUSAEhwbj6Ibr/EROxitk2RQe47yok+z0q0UKT59o4cnIOgc1ATM8GBt05VrNZ55F240I7+X5lbJElXc7R2WQ+zTaLmJFTri6S3wJh5e8mNIrFiuCBIc8j367lEyzufDtsxK38DVI+FjZyYdCmOXedGY5C/NBj5zNgPgaTyo4tCYbvHT/FKhHbWzbAzZ7gk1GLXJ1MvAPsVJ82e1q5scPjdcJ2H5QBrT+iUPwJnKa4SMXPoKOOEdMFmkzzCusm4VbCwX2khonAOamUTdDHMTULwCMLzfWAvuu0KB5prJmQGjiv6twyCvzv8am9lhXfwYe5vb8CGHWLXCe7H8VyImXlSdvZqb2Mcg8CpcFUlZx0kFXd04eKs5X2ZUlgrCn40iNyNnfWD2Cj/HQZ5mx2w8zfgHQeizm2oXTSqDWrwRQjVMRvgfHi+7oe0kTadoU2heBtqvnXWrQQJfM1R9yhF4gtKQG6q6tbt4CWIxOIrlXDVr21oW5gxgcA75xubee9Ad9jQUw+bnHlntr402v8rh3wHAN8ag5Os6I9ea39LUxAer9TKPJq0X8FsUMXQ+/10JQOoE56vznzeAqKqu8aFSBTMrb8AzjhmxEX6/2nSBNUdoIIIJsqtCdNzDa/72P51TqIZpbtOz6zFEwVuHGC2AXP7A1e098yUfgRbAAsrCUrMbh5T/qqbmOJjeJEdUO/Bgvw9wqtg0lP0piANt6uLW/i8nRbqvHMbK9Cm/kTmfXs8t61uVsJJcAKSfPMMJSAjOtk2W+z5V/Owzae0MoHgUyDZ5SsxhWp/KxpjMsadC3E+ROk8vnRywNRV51f2KRA5sqv0lnEcYUQi1Y+csTHxqxTwVXGlT2mRFFbH3vBo/D49fFPyItdIJgFIERdPHHDDeuigeDDFfycjBuRf3KYSor+ehPAO5crzaWrdChp37G3CrsSlk6vXocsogrqO2GsdFa2ItwRuzuARlBYDX/dd90nCEIkpLEmcyM/IW8DwGuCzbPQZdQiCT8JGya66tO2y38lAcgJTSKo+SCA78u1m1F+0cLaHK5gycM10AMmZkrHrPyn78xy7pLpgR/0GCNrN6UXtvYMCvxSVMhJYWEiQNqoAu7uecPvPW/Dh/UOVvhIJQyN0SXC1i4M+KP6bmtlbJYLt5hSgf+374mDHWgNyhF6QwWLr2REUDDCOcCasJ/x2GzcfPihno/hIx1o7f+8IZr8/FLVXVcYNNbyQbc8JLcbof6HQ5646h8TZZfVTTA53HluLSBb40Ul85ZU7sayIQZNejRIM6P+/u/uWfngdn3pC7AbANDyEpAZLzzhg263sIw3hDs3xrUxdotB7GGTDWEjsdgUq1NHeXnIvbNqkbb6fnxmZ8j5OqbrRt9DB9/YUVfOkR6D0YX0fQpUy/ysX8XU3OEXHGuwgLDGGKrG542TzSULO6mT6lKhIQcPEd13EXxU8yn0XVg4AcVEds0fZwQ61ubAzEmlCqH1vxSID2jAUI2Y/gLcx0Or2i0KMyoW6JRPw+UaM7kTA/qCAXBbJLOtsjFVL30YxAJNfroy40RsglZEawVrhIA5vbNqyoJj9Gu9ZPSqbebEHGyXmJ90ol/N7ve/7+xpiL1Y1hUo00O75Gu28Leuj0xAblDn3oHGpI1waNc+VC8QUc4HONlwBccBtqgxq0aOp9ONgX/QE3/VYobJPAkEfGOqkjmrlafrw5CqEO4jJXGZ1FIvRjfkuOT7HLuVS17j13gsaMMhn0yEHLZ3W7GNaiB+xjeOHLoGnQYBTERrBSR7FKgUkPvJZTYJW4IW+oyLNH9s9a/KOvCUSyVCjZPydrtzOYRQzCJB2EKM+4BETBYz9Z2BUWWCzPIZgk60JMhxtlI4ag1wUqU41n8VyNJGdcs3Rjjys0wJUDuUyzovceWNUILENKohNCZ4qeoZWwzTvJx28SpEtfhrafhznZ9UQ64Y2nJw9KQeEsU8yOMfG5NHl4qSo306cUzQCgEJC3wJtW6KtjztQH4v3yzWeMG5RZMT5FBYIOHVZCgIXH8/lxuap9KOTYiGb3J1G3jddnWi5CpyAoLtnhv05phOxPhd9wZA3h69GLvnxSivjmoBb0mXyqscUlCr9aL/eJ7+Nxix1yiWeUiiCw7ItPoQ8wn3nZjeSHQ1xEpDkEK3svVX2qt2pX6LgnDVtKMJYQrH7z+jA449/B3Gp5jFfWxpXo9Smulcfd6Ucc/b7Gz5L3n8f2A1xSmLpkvCPKKzclhAQdzyVFr8yAc7lI64b3VhUM0BkP0DLyn7ArH6JxXlHlYBOOlB5ZTYshwd6seAi1imTyz3tcqqyCsbt+VV9EbE3rpuSoepgiRDqDMlY8GXtJtajgCtw6vhdpi/Iavlpcr7FMmifkh5m0kgBiv8IzhKzz8AhIGWZFoWkQpcCiSiz6qaJVkTf9Xw56HbvIItRDRFDuNkqNdUY3rUtad6J525NDDxTPltHxqMOa4YaYGNXl8zGcOuYqqG6imyq72NK+xMEIehV+eM81HUnjJCyrhfsKWaZQB2RTWoA/rXRZCjcfeWQEIkFfZfxzV2DeOis6pEnxdlpGUu8Egq2/9ma0vewVtKhkBQU3iMSGuYWOpQdY+1L7LeoHmEPMpeZx/f2jC28ugnw/65L4iDgOSbakDfE89RDgUjVTnBu8r4FQhr3vHyPkylKbIx8KBVHtBEmHPFqSAhH/l+Li4sRB6iWL82IyXrlyt4/NhqJZCb/lgdZNWGtjlWOxluOGyjR6krYyrd1qPVad+I2dL/UAmf2OxtszIu+SwvirKBrah6hAyQpVw2N98thFldWo0SRy/ARY/8BTvIRoT5gAu7Phy+3s+JW9Rx8y/ad0c79Ox/GtEqbGGrfcNzfvETEaG/gQHPEDs/UAommRc2q3Tq68QUD4uYobFt5mUV6e547tjBxQY3Pm5NJ+wCYonyrKlSyvMiIzXIUqS0JV3FyiX+mYmZrHZ/WpfVJAGeiHvT8bm+jDk+8BTC4zy4HkUSmutk+LQ8plz8afWlytJOwT1k35fDYPh6DFZeZFEW/hjgkI1XGa4R1P77hyNI8ZofbRp9NdjfWj5jrgNhe25DvYwh6KyOmKnGw3guTuH5J7Y/j8jywS1pADGp1eZKiBNzkCUOvQCjFcsYntuFzYfK1QU8MwbPfq15fqCJxDjGa9XtLwYorvxT47cWUDiRHcqGm5YsVBBisb7SDD6foFmdN/z12HIaoP4v/Kuo1CXbFjFiFGyqd+VtvdEyZaEP85xWACo09OI6hXCEaoiY66X3aVHC2GPA2VHSeOulIijsbREKCGHZQW9xlmiCd0NO/0OhnM1HfMkIajf9z4gDYJAJgXB0gkUaZb1eTbi//7ZzWvpVQ+akNQyjgcdDwZ3LhksOlk7VXFu2TZhqWDH+tmioloIgt4WaHERxqaUkeo/L40UIBLg8kA0ONSD6CThUXEarHDIhSVgUCMV8UNVX+oTIAyRPNbu5xm2V64X7T3Qhlqb9mfD49f5dP2tWsnEkhctgoFnb3fBYCPeyuxRh1UsGSxyZMSoEuYn4ndMbFXl6Z+DpbA1fI3uKtxGPwz+V1kH/18IEUeaux1mUSM49hTYHW6NYGqSfh83o06HGLWGAIB4uML/k9C+G2sadOg5hxZ2iZOPcw3yBba6+TdzCO2kDSS54vB4b9/c/UWx5HMwqzV1fnGLwc7VqdyVtC42Jb8GYeT+YT2HQ/SmMSOTgzO2YNKqzixFWtSPZHaQCWeXotCMDD84o0Bc1VXKS9WUV9mHcThuMeSo6dma1YVe/8BLdgt2hYd4Nhi7GuLQEoN4EpsCITMV+RBue3g2bn+wFdLt0AbH4WtQmiFFS4zHtTokqfe15Fh1owecPyLtnP164uCCOwbH3L7KEly1QTiTvzaiyV0JtfKGCEcXSrrMFcF1mdSOdCYlarXNrpIFDaKJ6jB5smtkmOODcKS+2p0NDwaHyCMKJ6S/qyTpEzv1GWx7lRxO45wprEzR16BJUqjJn2deikgjidl1MWPjkXWWHCczrroiHQ/K6YM6LSQRNQsPtHO5gJB9b9tUDGPEyhTHaUXTYBi14qf1RFfxvwmdkjXeV2o65IJT+Oy9+UKUi1NaKC5rIiXKR1GKCCj8zdEmQyjGlEv2fK2mbJJx8z7jVJuSQ8WVChsoj6FExdJ3mzjugSR5zvji5+2wwx5T3t52Nc+IB4eNR7W7r7T9g321TevVaiAluQDFL4MWpWSkLcrtJ/rwVObBV8LrMCdDxlDzI1ZhmxFNxE6fTWRTH9el0gOhxTy+Yr9CuE6qhIOC+LJHFXz0AuG2tJygovZG0izPLKhLquIfB7iubPgd45jOK1VHFiaC7wGNwzXmfJRVWp/LAzEv7HMJkKPeFJVFL0q1qIpIhHrxeNqlhKYp/3Xt06e3mKShjzBFh5yYEVBWk0n1vEw2LmV57WMQ7TCMz71XxYdWe1nEvc8SP2lz2kNaU6yIwcxLnfKJywTGCxZJ6A4eO39nuSq6QlUEnq9aiDTojWeL1zLnAhb3KGCSmybFFKUc6cXkD3Cq1DJo7fPom+RmG0/8k/RSCe/CyKpbxl+/89bETQ/aeyuzAgLcQI7HtpgEaHBMRk9zIMlpMPjENd/pBuo7oFJOnq++71AdyR+RDkH+UljyMx3izf3r5ufOCggH3oCaVv4fhPerwC4RWQIVSSxFQD6IBndWmYeImrdnZvS2kJSt3Phx6/o4Cs2LrQtqXek1uzpsPfshxR4D39mTMwdYHVoxFY/7uZ4y0R+JdXWin/PbeoDviJ8K/HFQotMxIRdU8g6HEzkAsz8du32Eu8dMagn1yiWJC7v9nnGDsG8Q+jSlG1p/J9p1IbAZ7R8d/dGiE2UhDom5B2KjuabGCdeiychJTo7cGI3zRUUQ+NjV3FV3Myszuo3fz5risNFq5Zv1Fs6osmfXD1ma0M4wOvXNWWlq7dzG3QsDzTeYaYHEJhZAyuztOQJHU4D8mEibiejDNXhCLVP4HWCPRLfR4wKLsLH7QU/tfgiC600WBJjy0lYWgWZXC8c2PhdBa05pJvTLp+SpXhv6hes0mPIDg4mL7dNQEVMfnAJloeoaj/fQ7Q/+31HWxRpua3jV/6D0ZKwTutuMkDKJTGii+7uDjXZ1e0RPotfrzsu3t5U1j3triNr8eLDOgRWCq83boU+NMARNTKaDRo44HQc/BjBipu40C5i78ebWxH7vOEBtvRScWwkYw+RRsSYoG0pJl3VY0Bhzs6s4v+AnGU/L4SC2sCCF+5xgywRdUi/jSM2VnzOiuZk1zZmoV4SoBNvuGhfd2+S5iCwjk0ioI+X+J9G/YoYJ3tD1Hfby06AvYzQ1bm9LCDc5/50vqPdTk04d5rSTVG2whAOtbzXRayAJcjdrVJiNYObiTKUkwPcp/CFralVI3vO5u/i0oKU+NL58/YRf5NH2ZABySV6prBCl7VAfPcMxPr8+IS7WhVPEF5urUE24NlGrIxi2U+k5C8jtD4hgGoSELo9qu1xhzNt+bAAXPCxoTH2rd7nm6a37isVdg9uPum/5UrNixcLQ0MFRT3ynwIAXmSWJgobD7BzxNRFU5L2n5Yepnh+nZrHSqwUdO8JlaslR0hMVfn+q/2IBzFDSS7UVI9Q5QYPKlqCiMtbWlL03vxBhZ2jpVItObJpMGcBJxQjnSBhymFjyVlmc7rL5NzoGJfgb+beV6e00osSpTvxd0F9SJb1lx28/JapZsIZ008DCId7ose7W09W7Aij5/RmTxYmCkyWx0SBzJQgHUzTN4Ptir5ycx/lGVyGYwsUH29rnpAyV8vY2Vj2bJ/M2xuL5dL+qSKwTuH13zSt95l+v2Wc9OrNUmWBP3X9sy24YOQm+5ka1bltcWOSKfYEg5qZ7BAbRg4tcSw6qD+b9uowSMz+XIF7go5WZAlERSDLrko/mayaATkjUFfvFC1qhLEugkQeDSgvL0JrJa8sahRiUhzLdNtu/ZjXX/wIh56vpoKjE/F6nY2Dsk89YYV30oIUBYqQaIxprbTplkRFP5BW8NFf0QcKNySD8mSn06pU+8nuiM2nRUZSKoljYSD/DNDvSJrB3F0x5NW71vxr9MYAr7csbhv4tK6G73pKV/XQC//4QQMoh+l/6ssEa/ttdRHRwr54IPnfzsvMkLDtkmcJk2xrwCrSVAnKZY8xKJmIBpu+C/y3dDg1s0nEuKbDwgWScVwfXsSHbaVopIQZLaOiaVR7MmT4CDK4BG1C6DZ+imFpKUg34sXNPkbSoL0Bq0erVnI3La5pxol2aL1IQndHwLq6IY+BwAsez8SR68hTA1BeZpO//KUpUiYts95EbGoKAmEntDN1M9BxNSOxhPZScv4UEmS5U2OBO6JqMPeQGjFx6FDhgIAyAEFrT+OzQiTrIm1mO5ExjjwmEYO22rueLTmRsiQMXpCp5rzSW0YoLWoUYX6RsS1FYNGV4EJPMjXVxZsuMQ0Lo7gDss6r8wWv66bRmSLoE/E7RbXtG84UiRiQIEEiDy+E5HeuAUSWOWWZ16el0xexGUWFymyMYFZOAWw58ju8GC3nz7tTGoZ4I6HCkjzP7XfBzdOg36UPQNIRmYmuOVAsSr/NGThQdqOERBrzGzhzl4aD0o0bSzryVCjOcNl8C2JaWYTD6jXubmMy7SdxbLeHV16IN2vKOiP0+2Y7dLUeqQmPyT2aRlOFUp4Ld/iVUYlM7/AeM5HEAXpyLSODUte+TS4RVad35Jfg/aafTOy67D8H8Ad79vtTmP/4tEQOCY9yg0l+YEX8Vyl7aLoREiGWHrkFoLPnMjsHL3kJwrHFhf4RjVKcs5UFISC8JaUQxte+me0S9+8sqjEtNFHZa/NDaFayJAtHy26AMVwCyLKkJc3JMgeGqPdj11lyxljN8WE8ox34CzImH6qViUcyOwjDiOrcM9CXjcdgnLIk7L5hq9A/khH1+asWy81n0/ej0ntuNWJvNjYhOng+7fWUMpgGQIOyp5DTlV0HUY4b/o7pynAGX+C75FMzRhLoUPoKmEUEfF4Kb4V3cJAVcDaMeS0ckxSXMh54/vDMWDFFAFtAIqyPhyg4/1llbYWpu6kFRiQJhNokouKzfwImjmYGcjqoXuUA09v452fztChsfqPT/7ipEUTG0ThD9L03jgnNNEXg3wEGPDHucOFJL2ueMpOzXS5Bup0SJQKBU4KNC4foIXl4kxYkkRrILQ5mkl4Fja68j5BPcwsrMQrxVwkZc4HPOXTQlC+P+m/0+Q/uT2KgSs0YCTCzUzDXla98Yab/bXE2KAPq/uMypRhdN0m84qe6syDH2vnjrz3K07+DdPw+IGumZHvX0qkz8si2ywRa5yHSS+BphiiASt7YLASZ7q34gYJ2w9ZOGSNje8uExOXqal8T9ww45ca9lRWv8Z75Xh96CtzNChrM9ZBv1K6P2EjOJDhlKc9xZQMPoICCtAD4Q6Ha8Ezb6JQJgN4x2UqiGlNUuamHQhcaWAhcOjX2AduRmdCLB/g7KyTp+I2pAcMsCIyaaky0lDyj9m9jFPitrZEl5bod4yrvzHs9mtusnT6w/jo2pxkYmlidj44dipKp1qUevqYxSgmHg8/vBS1yO9dqlWcB7RamH2XieRsAG1eJCJJhKXZH4xS907DtkfuDO5mHvkBJkGF3VHzDi79sCLMmGmcBjYs8WNB8f4KKIAyMQB6C7ymAKlD20kpXnmHCoI7SclI4eqh5gL/9mt4BiAiM3yppsBNLCVXFm97EUTm00FRf07UN/TSzEWCUMdd5RVcVrjDOgwdcX5O2ikt9k4B5KZk9rXV6w06YrKJwPQ8GYFmemeU2QLJtc4OEUqlyYeoaFxsdq4abUXi/1LuwLf3rDEyAf8ZppOECOCqRmWtk3NL2m3yz5SVkaIZdUc/0PblMkkteUg9+j9YdxLjHrswLFppZSWWB/HjGpqCpZMdjzr/aG47If9a1WAA5JpeHXaYtroK4Z5qRUJAJ+t/wOMla6v2+hCEz1+jf4snAy7zYOviTV8AKKWwfLQGGLKkBmpRrpWe1xSz+Exv0AT0G51pVUqW+IyaGROo+ypjwmTXsEIJHRGfVAjMiAz+ULv2cIy9OFBxZiYulw/l5RHlXwgNs2WLBSY3r39+5egF1yWX28s7fDsAMvgCfGVFfGAHabZPIfwDWjMZTnneT4f/KwRmoF6AifoaCS/PUnT26HIxf/rNNUQ6BjPkqhZIu+mjgKdW+8OWEnjdQ6s6kBLxZukkLNZNsZ7+Ib5g8NYWeAxn0xugJyZfJ89ugVPreLVb8RVUPTIM+g/BJIuX3ax1MT7/y0axEI5hbkPV1t/TuX8NFmtt/IfO1bkCRaK4XZxW9xklsmI5aQZ1VT5CPHgWqbjmzJg9pBR8x+jdrrkUU0DDCZnE7ee5OiKlmiqwUl0i93IL9IAiKtnLIOXwd9dR2iZ8VCAzGpHgR7WejIQsTxLPjYBLnmwcVNqItojgKohwNga03u4kgvHR5SgXfRLv/fANCkX54q3EoY4zxpo9VbMx2FU8f9td1jeRB0xwH4HyBAJ83P4PBIQINQGqWrTgVbU146DErVLj1zU6+It1IGITFBucuKY8Wm561PHPAAhdInxEoroN7uBs4KcfzYjIJUrDiqye/Z6n7B3Xbhc7QCVfqiFmHgDPFQGL0y8+MzbsIDagkbHYyrQ7mA8Mgq9WMQIMdpdxBwRHdqJE0E5JZVqqPlPWle4UOOrCUaDKhVz87NOSMyrtD3HodgtYOc6avnyWHIx/+44UiMYxDFlU/jr2zW16h/sESwQ2yYARwk1JjVn8dQOSjzqPx9zhJCpprJYQpmdFqmEKL77lAUFPvAeAJMqPvmdmSTOY2aTWHNBmoCjbvA0Tkaz0k5DkC0n2WqM3qGiKHPfyFzwC7E3vqYdvwkzL3fnrJZ+yJmj6KKHUcWQY45ADdSmLqh46coQlreEYvsUBmNRneIXl5O0Fs+mbW1nUu89Do60vVbx2FlYZOevi/YeA3RvVJThi0IgaKgG5nPdK3k3NwfPXNj3Hj8c1+cGAcn3TD8XUjFWCeJxzrd5Xo5ZDFv1GK0Jovs/izys6iqp0bTKZt7I8Z4QfBdgX0vnl2AjAw5a0K6/JfYNAhbJHjCV/VBnl2ac2g/qgoV7i4v7fon5pqBN8sM6Owagm09Xpx9Y81IobOb9Q/Zni8+2Z4gefb9Ku61fwFyOEbYNsJR2ris1LaQ+bHQz9SNJz57YN/GvgL1SiTVZFDQnusUMPtkNjoGv3GscYw5ZXAcpUbbLt25oTVBvlalqViTu9Kt9sZ05xFvkbXVP7ovBeo/WJsvZlDj2XH/F6IRnfSWZDCs5MbewFypmIDQHZIuCLhUw04JJRkoXDs0/CshJj/CDLKJDK47X4jGVnJVEmzhbK1jiRcaiSeWmipqycfT9GiTYWTTOUEj3zR2YZmfz57BRRdYq+CdJBqZlyVJwCzncb/ur/ZCAVCRxwiv9USqxoldXgZrp34ZBz9gu1eujCtWRlZU3Zh+3nS6YJ7x0AfgTuBKq+FxXOtX2dtXvYWHiZPXy33zdnDkRxPB8/4YJj/0WYPCX9+DNxFUxpQfHHryYnt/lO56TMgZhndj9tAqLPxKLGHqNUAi2cmGHX0fW2Td74ghrvv/yEW5+qa6U4If5WEgU4wVQ9TFgqERuRhTX3rp8jZkdgOrwxLuu74RFZlmbSu4jevmYV1zgaeytW1+rJt5yLubSqNmfeAaWoGndNqp7UprVQlnTdFqkrkJCF6fcFxJcbS9qJdEocUC2gFwnw7PQYa4PdpTUNppx+8ZPvrfRbFIDpkSCJpRiY41ZZjEK4S7ocijCmjfTZNf5a6Qpk3EEDi5p6ubB7D4my4eC4bLJ8892sCXCXIumDdThO+qYCZ0dP+6H4SLi4bYf1gG52X9KrUt/1otjFGIJtgNYDwk30kfFnVvxwZhgyR6fBKAZzk22qoxGpRZPyZjS951frO13xyLbn5o7P/KFppcczUTzqst7XLid5mDZlOqKZDZthcm/1S5rgi5MxL/MSR8yeAC5x3+8EabIWoBMQbdNvG3fLMwnrqfh9CarURT7ziqhjBqq2ZU7rEkUBiG1cd2m1L9mUtgJNFmXh1L4wcGomEipIiWdO25e6AWJmUnFTC81K+Mop7HDzAvMNwHz3wc0IcIqnqhEfBQqjRFfLsODPlWHIfid5TiVrxwdchjGYOopy2VbYxnOzEuhUTSRVaBRKxRQRdrVFgVYSq+JHsu+fMWavckEGRXhtwdZfsGsnThQYOFw9ENibCxkPNyH8F1N8cCS/v9YWYJAz8KAhFv2SUn8v5xTp54Su0MKsZrZlFsHDnmg4D1jY+wg6W5s/GFYCNUjFIsV50weGpIUAq9E3jqoniMELeGOpXnXAWKEfcYjcjsXhrpS21S0DSHN8cUan0oY2jLGKZgOHNaPVEnUoVR8diiqkVtNIxtA6+oZZ1jFf2Eiv0Uw4F7bS8B0yCiym7WjgqNQ5aGvHmPiXZ3G/+JsSYoCy9rLI4AGHW3pORob/Do5zCDP+Kps3684MwwvpVL2tH33TK/etPI+xvrDpLSKVGXI4b4lIv5cnUp/sokRZeDBIDyftzyiPlgmTPTuitstJnSGLzvtr4v0MAvUUkqgGBp2RA5LC4EPH45a6EjZj0Qx1A+rMo6jO34N4CG4UWCJkIFUBZ/O32umMf3/9ax0fTj3KlQDVKKRTGyVxWmZherW2a3b1acVarWnRM2dWr4qdLCizxyp7FR+6kLjnna2uPMlJuNARL5orrbpdaZkM9osoqD3ertQsZjnf4eWaYNFi4fOSiUPVgzsSv84eqmIIX1nkshg4RCz481lg6raAxSl69t3r0haKHPSoFs5gTHal4g4CR14cWuITf+Dswh37udBVeA1tAp+jUipxG3BKqjzYgYjxoPsoRhbiQJ10KLkWg4vzi0II5fP2vYZAOagtNs0SO+nvOODmEw/9lmrIOBiBipQg2GkUpXiI4OqHLdmcuWvdPRGh60m7/ynx8AgYzXfgJ3TpopBmzPOOnMisvLTdSWlXxqy5S0GAlcmy8j+OIWaZLhvoJgKK2NsGwx6ZjQihb4mt36T4hex1r9KGp9w8OyI4buUzzWsPHVCJ+VWkHiYZ/cVYwNlLW0klQzg3wuE+eg3kk/wsFjqqWEPZeKQIkFhEM93vbyypSVdvxrDgwgZQ9R9LIQuDLsEpbFPn1AL0nZ1TaeBdFYktLAZk6Q3Ktqc+SsUX3S16alyGiHNnU+0p7Ul4AD0FjchhZn5i8xyELT5+McPKXAolU0BEsHzKFKJWd4jQsftyUWHxkTW8Tq8NXyCeuJ6HMvvug3sdErjyoyaEwlsqcNhzqKj3SReFBUBFDRcV/1HyE4bQqVkXQ976Q8asM7dwwhj/eW3wyW41fzI4AKdvxuYZ7GOgYO5qL/SzATkwgQ0ZZyO1PPGtcvKNGyOaO2uzsTkSTbdFJZLRsNnKPqLTWdJVJ6JGsb9KKL20MCXllBTe2Qh6xMCQvl/5FP7M+2OWqDZgvNyLVNxIfjmZnvnrwyLcXzECgF6MQQxoR5ZNsWsCGM1ZtIxdzt28LikGL5X6kx2qp2YQvBSGwV5maFFeshxf58rM+MIbAL2xM2JsK3W/odmzTaQkdeGx1BD6hMiaj7DnNgDFvlGOe+3Bk9gDDQZMD81aMDbPNBPStlfQuIHJiOZg5//4cbkw2U+Ul+jVZsASTpeK24fqPl5zlwdujxiZcI2aNspqKENiIHDox/dBQRrQnZONlCp5M0E4o5KUoNIjEnRomB+jkq8WZz6LOBtYxFJY+oHetUnuYAkyZRMLEiY8erSB0k8ffKz9/tVuNXI4++C8c7AwzezAiI757z4f4cLmTWQfss5R0i+5w3TVT5NIOSxuVrQXoNvz3ng4TEFM+F5tD9VT/Gfhpb/4H0fsft7Ws4HmYRvHkvWTihwGN06wVOHAIFwf25Tsb2hbH0m+PdmuDm2JCdGiU9JpZEVvt0ZISuwKNXOEdrduWh22nDN6utYcpmsy7ivsDvujHZM0m64yFfrbHVIo45EScMpA063y1OBtEDncVv/dv5/LUqgn5oPVTgXailJcBIWj4K6KOj5SlE6hbAzXktZyJNXXfstKqzMdmPdnrMF3ZzHorX+AYW8ML0SNHMLsLEfPCP8CSLocquf1ogqSYve8FehPBIHFl2zaX5nL6D0aSLuz3Xbl+0jPPIqmfaqrGrRLS/dU9236e/MRbXO39zFNpZc1nbu8+iZ0Uu5plaebxS3Su2iQuumVp6+2U9RFvj7ybWDuALnFKg4Lg3/b7VZrsuInaTxf7qj/V+TXJeY+ACqJbtRjXx4tGTesRRA0Jbz1VHMXVnDmFe9LPv+++Epiis9O15qPxHf+50qTUbEnmbqnK9k+Vw2Ie60rxo7VCRyhh7Yed/QdSXUOjTQKAjBfgVsSL0+WTDdtwNMPfcpxTIWZNf5qxt4IjPwzk+uu/QqCU3npuUMd3OV6MmtWl4q09pP2pFjwYF7dpp6rsSzfMGbpZRqFmMBIQRZrn+izkTAygTEzLMyWBynFT2f2WwarUTzWUP3JeoGZV3uKVYeq/WUbRGDpOMSBJGve+BpCz67w5h7TGdOnJ6AJb4ypEzItD8Npik02XePNiTG3dCQw6Zhm1pT73TIvzfK6YBgzlxB4q+BlKF+/VhHOqQ+yw1Ssr5fPdR1lK0uiVvSZL3vl77bo+gXEsofCUHOWen1eOQyii98azIkSA/BixKjsBHzn1NAu0YVAPL3yOt4pKILLlksZcbUlBuFsRlxZMdPFByMX+1mxJUmp/l3wkePZ9VYvD+OyxnpUCEM+UGaau/EBdsZ7EhOeIBkSh8usGA5UQcl7AObH0iT9WVo64y5yKjiB4708Cl+zguDA4jqZE3xbWWqryP84t9nIMXur9Oq/ejiQZ76g2B4+JSHBCSNVxUp9HTYq0iN79uY7EGoy6DDoUd/g9rtwoxm/tJQlbJxgitl/tNTQ7JMfbEFo3A8JNUV7xDZRAOyVF9lYceFBfSQxddx/YOuZUUWIhZd1sHLsOjp/7Ol6n98FdkvzYhUaZLygtTDjpEerzT+U7xI0Ux6CLOqE7m8OZreC8FiDxhGtMgv5PDLKbYvaksJO8iABSA5ZCBmd9ouoIJt/5T+/D+H3LgMXem7LGj1IYYBuljhqZzArTq/1a0Xui/6aMoqdMM6hV79ZKLkPw48S8blwNnYtsC8PildrLgYUhYQs24lzkSvFXXd0ef8RGdE06DiFzSaen3bYV5brjki0tpt1uaGpdlPc9R2WpX+K1D/VZVSR6+G6yO2jp9i5STojhrieCzmILbFrJxp6YSJPjrHkvAvKvn8dfiN1tSAPDzzaG7OqeeKU0lvV7krq2tqaRW8dUUR4iN/fN7fr0ObbUrgcNQLoXFlYrdZ+LrLXu0/FXI39IU1gxkOZ8uvlg7YkUFlhDmoAmcuzuXCuVX9XyrUXOGpJ64hLTeXIykbIIQiOD1DrZXpCBmCBUfuCLnaPp5nYHJESYDyf8lH2DYLf4YP+oHAcGjXeAoFoHFnKCYJlUivMaW8W+2YTy4rgV9OfWLNpRzS0PtXXM3PmeeEvGSAuzffvv5onTwUYUCW66VfWbmxoBay4wJstcXwgbxsAAaKMhdaOodVZEBPYqygepajVFd4LoEReCHWeFMlKs2mVOGSOkDpOC9gVeTzo6Vzn8kZaYloXSbDzPvlekK0F8VQ7dYIGRwDiIr4Yog7ssUipLAV09BAIJ9HRwofZraLvOMT/cxHfjHx6UlOewIltbYKbXrjaoLwqcP+rmVIfu4gA4+Wjl4gTRsT8c8v17omB2+nfmlSbqVyP8+BpvY1F3zSSwiOEqDfUXc9atzBvfBpLRcKyKp4Zg8OGMMDf4lHxg1JIc6Wmo3a/CDatKB1rUKQ2Vs2yPVu3GVt7Ez1601/GlvXoDJezRzbAwuccRdK5sB8TbJT6l1MnNbvacE1t21yrGOZvrkzdlA09xavQluAX8Ct0J6Ww9hYgj7XMxzFdqFbM3rKO8SlubqxQ/+ktGHUPFcJ4m5LF7Nk0hCcR2SLZ/2jKGksocovck2cYeYfDK93gYLxe1C0AUqNvYtkz1HlepKdWtQSGIEAJdxHVfH6RjsYpz8vM/9Udc2zNz5vUgL09X1z7q99k6o1CZeOgUbDdHH8GBuPe04UkZidK3q+3JQOSeGdoof/HzvXJCdL9zmIYECaEuAjWL9+JwQtYz9az5v2NnVaQJT00h+j+8xZlCKxHs3lEsEMnFnQx2UmX8VPOkDNk4jL4StHp51ENrzSyXK4vlYNfUpTQd2s48LnCXZPbeRjNKF7J640urI7R1UF4auNAVU17cmLhDm68z8WY0mgW1uGvFkUX0qTZfTAhYwsm3lBIWxgF2oDCzN8lyv7LVamyh9HcMXOBcm8os5hRlMr7F7abPH4+dYFhUnhTdEWjE1vqYAp/UEGb3/RvY7pqHiWhP8A2gJLOXB6OZn/ocMvr9QnQ/0SS9Kt37g7Jj+J2HgIF1bvRCK8+0ool3cVSdxLhdce9UyXtawvz/wjEnkSlgHzo/M/ydyRI+k8f0q8wIdNAUNerYVgUOL9r/5E3IRgxB+RkF8ODXoDjNUlduBLkbMp80NOWMXQV6dnZevjNenRCXcbajAx6KOu5OnwZYDi9wcBA8ynfgyZESRjl1J8vX7PoQfgcqHY/LY3zDHR7fd9fU/l//rxQvXwnLLLNTug+UpPtIrHANNf/WhQyRp6asPY3D3tav1R823+2PZBM+cT05CM+Dh5qREXAgwmKRMwVtBULpMA5c4lKXIyjmwvORgG2EkaFDbXtWWYMYUqM2g0jIUexdwcjxMBXZCD80rfKteNAVmt7TwaOTJ+tbajayR+92NdNmxk72Q9bthJXaZjFtK54V4Uz/omagF2nmUC30K1EIjnA8F6gWYSlFRMQS2J8ZbmXTa1X9I8ySPdgBlykJgc9r/3K/L+xKvMw56fAy0GagsrpUihO0NAhnewS9pnKErqpllSdn2KsJTvNKHIEB/4aEU9Jn0Me3dgxjFsxYt0M/HShselfsuCfDmKsRaURoYFq+z/XCFEaBZzr1ehwUuGvUR++zAd17uDZLf6jkiwpifvnEDaeoWWljBTJaDHXgQTaToV32ZB/Qvh2vKc5sCH2TZ/XfBTgFvOUvy5w+YUVZgMdGvsaFipIaV8uRbDhYYihX13SIamarnGISYZdM3TWhuNeakqFHQhVhWq+Khalnmd7CPd0F5ISi7gM45R/Eh0F8ENtj01anEfTKjbFzMgfl6izitDYBQmlK0YIjWNUm0Gvcf3aw1rC2mWplTzZpcMVH4lMTxGIkrkJTZwEbL2x0zGJ5KTrUnwYOKYwjQvJ4zOYSc4k6wl2xdYwSPnBhn2T88r6JXjuVKwN1RYK5EVjbiaBQ1azP96xkzA1K6Ko1gjd7Z84KquVRSCoA/z2l8tdSeic0B7k6N609YbVQX2M6ta9BJCeODp++sH1MNAJBMiMMG5OXnLjv5oFgLhw+XVOsvCwoDSztZLTmVDgcO84GfD8eeX78qelHhBXZfBLGcX1SlalQHwDedHKzYsPNEi+Qj1q87LoRLPBcKTiKmXNoPPHgQ6Smw8H7i1bINXqlt7o6lbn6DF5Sgviwyz+ZCHUa8GTYsbvAck2TARaAIGODpTMRzzzK8b9v1PV1neAE1qV4JY+QK/kqAwaX+rHKVnPPByojqol40oR5OmeFVBKVRVjTQK0s3hJrYNbEKmtKHbLa7M4Lnl6QaJvaQgyYXT+Mgq/8dqz9LP47LtfOKLUKvzYyHvinsxmaDREhc4kRQ0yM29j1lpOJRZ2Sijdc/tfi7afI1OC5K5pRZkhg40V22Regs3tluwekSIp24ZPWP0NIFVSE0+WdDf+T7ubvUI30VxAwnvseENpWpCyGjQ+FqXgx1AY8Li5vAEQ9SQYEvNY9WxvEwP0cdjhOnHG1vNcle6XqYtsODr/r6wssznscaqzXDOySRlCZQ/akm/FkvJlHCxcYV1bU5N2HxjPXur44UpsbLDVvcVMyKJIQXIWCqMd5LL34j3nTJRKYb7A+O3WDvd5/2W//QS0IPQWzRhl3Q6TSTlzA5uHZjfljcCjKbQ2MOXk5veTh3/am8BhF8Y4BC2qOKcgRsOVefpSlOyeHQ2MI/4oF+5uOTuT4TTziqQX4qU9mm3iMtmnBCHleddMsYKjUyhB8VtsmwVjBGYx295fWFtfphFvWFrsS8smrW9kPdXEeiinPK+f6WSb9geC0s09cb5WydqbP8fL3UGODm1f9WSgNqX4Ytwk+LPpG4CbK82MOvTDBIEstk9fNxg0Zjc4plk33xdnj4T8E+RbbuyvsZ/+O+bJTIm9LkVCSXAYmYZO7skS7RuE9Wj8H7NTBRFqPDzUz4kdY+gtWnpjgFwrnxk7Vpyp6lqeK5+WsNxZJXNNATXpDt8PGjoOuTtUZnsp6c0PuE6A2VeW/QWIRoabnzdpzVA8EoZUd0g45bL7d2WqyOqCVL9bvNbQRdmWE6zCltJ2qvWnK38P5OiOSC+hiirLOIPm4nO+WSwm/5L1tMn1WA6t9qgWw0pG5GauJZqRi7N3FHBhCPYrEOW2T5ffkemeyWRGR1h3CwnW8EyIWFTyAMThPJbs1KMb31we8OXLdMxDOGuSSf2i6/rNHGVMRrc7ptJty3oYgd4wJg3uxJZzssLLFR3S/pOw4jVPw9ucRK+oO0aZ2id2ixoh6I8dLiJik2zNfGA6KcJ/rGkBrR33wqQf90XHGsGuWsqW+7tkzddgBNV+q4TQsV6zYYRGc5Oz7H+n2gBiHggAANLZt27Zt27atxrZt2/b8qJnYaGzb3EPsQZ7s5dBIAV2yX3sUVbjlAvk6TA9lOpRFOG+BbkbRpRysc8Kq+/pXJ5etKidMx18PWSJX7mfGq5aJluAaoBPJ6o3S826/4hM14qo3sKhqRW6bXlAfDC/qCbdinvaMGytBlLtmJSHa+zXQP7Yni+TDCxhgQHHHKN0z4Yj+ETvERKc+4OP+HFb8gJI23H030I9Ew4JXDvaMry44EILsJlU4Brwmjtg8deC3sJR2WkK1Pjon20R0cxPjZaA11gtACMhcOBOAjd9pIqDm3nsu5vv2hl76u1zZ9LfEbsJp3ECxMra7LHH8IlomRoh65I6BRqGq4pQbyc89fDKrZx4+4L9lakLYcjaZa6cvAOgquM19KNAh8MCMn0qOSmO5/+VlWjJYC9epp3vJFViAdozwGYjPwG+2g36IkHEU4u2MWYVb+Z9s2nvRZQB2KxjPd8vNOZ3vbfxswyD7DzrfBt7L3wJwHItLAYb6c7fFG7uIA5ehOcv4+rKEPLU7T5WeQ8hhjPFQK3EMcPfSNoI+z3eBlk3qqCyV6hDmI4kwFhtw+3b2Nv1aXCO3ghGVR9wcW5VdfoB+giB4zKn3YnDcvTC4akUsaIQF3FDUu5QIF0WCWn+tpcltf3SeC/0Y+PRUggfOxgnRFAinmCeObobaSnOx4ZF+Muo8VxBHQ8gs9hAavFXj00ZboFpsEVMh/pqB2X+xQV25jocAu35MjlwISNyDIeG/8oiFhyUNoIq2qyr6rpyhzn28AHuDAva/F+blSyYbNFLtAMsRpKMGyRcGYY/APTX4QfwD+clXEEGcfQxjWT8ldbzxu5P8erep8OKqBmG6AS0jBSeqgj9SfrLNql+cFx84YzkVGvfzhUWWURoKdH0+bB/485KfefhMOnh9JzWhY0r12RH4itTVjfwz78BMtyssINVQij1P+zJsbnH7ghD8Ob1Zfa+xFzcDJ4hOst+Ss1ao7KukM+i+NYWSIfdjB3OLpnpgfGDeh57LBnG8HFDGRf+A1b6XkSm60YyrCWyJWE4MO6XnpOsmYd3ye+jAmhPqoOGfP/ARD7m6PkAIizEzCo6D2cVWN6y0xujpB5hvo7bUqDCp/gcsWIdMpANPrSUUWyrCJmecl8nXzQ2r0x83bGrL2DHPrmy+BnETd2hxbO+ITqzVoZV+W8zgyOlqJFPw51GOhJ5hj0HVdcSPxyuVOII9kUhM+Fr2qvxs5R1J+d2fWHCAVle0bgEfldr8be+RDz2C89rH83Ug7Lgc8xTtZzJ5/fcLI/US70HtrV4e88CLhTqlcWcvLK9Cf8zzREDlPX2ztQIhORPF/0+pSHWkv5XfRDk6ZUPPVqpYehEpgWSgM6WB1IvKjJii4Twx5wdmGRfxp7O3+hoiAlizVlxdQ32+lgq509VnCWbFfzgFwBs2gf3C5KZ/dIAR0epg5JXB2t29mNFKJKuMGw4PgOIHuzLtO2BFtd2t2+M/aPj9vjxy6sJnt7K28t3wbPPVlgRh5BWzA3cPyH0eii46+lN4xjUYtpo5QTuj2NJojIE3JCqwAYqm+w+35jzNo37N/lolCUEXUhn4HHQKdKg9gYIT6ncyWR2rW3QXp2drAk1WJphXv0zR/vgN+OSRK4MyG65ao7DSEsBxPtcvuNmDFHKH5wWZio5SvBDmaeMwWK0SsDNvttvHNwQ/69vrbH32OqD4Rdb/Hi3Tdfqr9HUWb/qpnnc1gArWRtauttlK7VFH9S4S6SFpM0HFhCM/PaPCqQfsuJd0uuXkbx9SCqK9QK7ozTaCaHVC/jlmpaLpxPKDFrX7oP7Ub6f6DjPyPe9VSLKyc3joxZNE+IBLAMIyMAlT6WlX0gGkYlakFIIjXtsusElBfAX12z1Pnm/HWxlB/T2w3VLwXKCZmKab3B+VdMjsvJqYg09gRzd6Vf+vDD3l0CQCQnwSe+AEhrvSx4/XIJ/n9actPjjg9ywqF4KoQd4vPaRlL39nUbHXNWEFgpHrUyrxl22vUchDbfwu8mfzOjoZZ7oByq71T2BBNp55X03Upst9u02py/j6pXVYzjcKr6IynlJMjS+LLv8XN96lEJMDukc3MPPGoOrbz85EMO8hQjH0cmX2a2/eFVUkPPNv0l7gH7VLjrZ+4dPzntpsGay7VtHaLGIqjAhWpRxU0JGVwAOruj7Tg9nID+M//o+HbBhHUqXGKquRql7U1flxyp1h62qr8gLdgbnB/eTGFmd32cYHJE+mJGtB9nz2MGG/aRdHh8gkdEsIuFypNc3ElA4p7bpNulv63PFy9PkpEao5ttXJLTcnevWROWk+ClqYcgKOIqjUV1mcfZDKagO/F98pg6aqK7mFceHzH/Qb04nr7MDou05o3Hs1VbGSwVZv7Bjr8MXbtzzhBTSaLflSMKUBEWNuUwoZQQ8lXoEqKc0zc6PKR/ESuhN9PHyGBKafp6IGTyovfqcmn6vvMKOJ47asEW9KvpIe/MrXLDAqXK/5r/iqu+g44Zu8EMMfhOw5UHVlGoxgZ2JmfknAjM+/spkVKh6x+10x9e7od72u8EJZZPW/hsEvWWCHJ44v0iVCkOGycIPzWEgwbf6Q95jN4ZduIjSOLgbCgou4Ngsae+gW0ZcI8ILnh602Vn2rw7sQ90/FQ93sHJ5ZHYHzFNx2HB+ZXr62A2I39qNKVSwJlBr4c5SXl4BtMuBd4w9DOhV0eeyTKVbe5ahiwfCfQ6wi5SzpPM3nkOZq8prlge8tu/sm1IKpOzlCG0ibo9/LdbGp7I0PIk3bvzsIAvax1ZnZvDrSoOQF5qv+hecAfuRK6lH3XXHzPvd3reIjByLbqX8fLL4FzYCi01kFIfZfvpj0+i/nxrycY4mNVdRvnL3VGq0/cWFp28uafO3OnDZzH055M8lpdwd5ooIxfpG0mAhu/D52K2a2uRMqikAJ+0TPSeeAmMBnbJgha3MkDx50GCcyljwBL8RiabJrlJQa3IM/thuNSgR51nzeeIPJPtT4VIbt1NqIclz9Fb7jlHDUcIYi45p6//FYBnUri0SeXrWU9Hw+kFUOjGPaLhNIP9cuZE+2fgoYoQwy74bClqvHDQkNsFxQ3QeCRxrfq8IQntvomkNtm6MoQT1q2OP2wVKR73v5TqIWyLq9Jwrq4cdOnzrb86ow5bahtitAOUZDWgRGwbiCBrLWeDfy0cyDFI92P7Xxu7gjAEgQ6SNG+6GWVQdr4FqXLMk14l75GPpgEA+hBTIQ9RoN/VQCSvJkg6qCJIjjQOPSmwfFUqjBSwC26Ywq10hfGLv69XhBLJNKCXy8YNyKN41kk8IZBt18i9DEgWRaL/uwwLX+yjXCiVYJjD4ubFTLTuUZ5RwscAaoN6hXWh6aVXOQY3FSH8/BmoQmdzluuG82SVQ+f0DJ63F+WhcNIvyUU0hsxLGh2i8xo8Rv4LVFhJYxTrPtVpoEGgmMzyeiREI+ZRTFKk3XMcK8DeZHgbWkkipD9XwrS03F+nUEfqFtkcHzFg/eH6l9xwuFEhVE897ubJ2EXdynrZAgGGPvuFRlKNlvXzV4EIbHD4foDNmIsMUyHrpGRYM+pwpPcySRovMZzaZWK3G6qNzw/4y3fYHQhp2Tk13OqvQg3N5bRE0ggtOvC4YnxH5gJGtjX8ZyT4iKKW6Vy3xF8C2Mf/5zvlGUq/iN+YNjD3+XTIit+J9ZQ1pP9+E/ApiEfackI0NQLaeyFUVH+9Urx7QpmHqqoRxUL5s5nFVAVl9wnMCHsyb2898mbgWVf9/3s6hXKWcGiII0UW/G/wXm31m4Q+42t7IpQ9JtgHJ5Vn3x6u5Y8M+3dBMy6T9K3TI0/ERp0rXvT5O+RHPx7rib2YQw2VzbWratrT3T6YFocdxhjOgDc/CGfhvCUyQpJNLnVpJJU9ygtMfarxsNmcHsoeCnPmGXdVTb1/fK0pg6I+ZZWC+lQMhJjBZqpJ3lg50I74bn2Lz1nUyRQO0TSjzgqBB69fhVwi+I9iM+35whTFWbOd9wjrVE4EBPck3yWfFZjhLsAYp0Vqh7BcTTlqk+ZvM6bok4CeH2IT3x6CfUnE9JRG1YihWFZa5RbvrKdRdOp3TZhsSEwgkJIouS56zhzMToRpFkLFiHsw8/0Q70XYJ4eSa0RUM32bT0XZ8d9sXJPZpN9ondJEKBVpTbTUDMShl3lhdcF7rF2V9PRibOHCswdjWeGrXxIp/ctIEEtq6oqUyVQxWrDMnpWyO68lp9mktPwRkV+zYX0ELFDPFLDMPXTU2s/UzZ7Ni4uzN80rpO+EkaoWUcKObH99mC5b6KnDTYP6M/ItAgoiXZxv5Ph+iOO0OiCIwY1Bu1RCyE9tkRzf688mybbebRYtIzdtIojeVbTJFBhSu7NFoWeEfuUDQWVfudOHF+LHlUbiGnNaVNV9ppxqkOjuKrVscpiMyLbD625DrkkHabtismP6shLLT6fTro6/OqcD/4v1VrDPGPKROPkVnl1KDJM9t3PxGNiUwjO8mFG7+9qK5tvCuFW4ZYt+e7vS1Msa/W+DnQrxNQjHhpOiuVy4fU/gqia3cPuv+OSZTkgTNNELnwnR/0tb/5HCeK3nPTZLu2RaKQTsXRveZH2VB7inPJ7ZNxGz/NCXrtprystwwUsYbwB+gzMgGsgh7Qx4xP7lQTvmO7yBZeU6WtQsgl7oz3BIPCteVbFTlC8YzC+iqeXNi3Re5TVKcD0J59/EJBoslCO0k53lOBlDoilLxYJwUNjhZj4VzT2oFEa1xWaeP/UigwSJoX9RU21GB3YdFcwJtDeU2rOQJZOfxrT223PoE2mZ6uSuTfkcIF7QvNtZmS41LI52fDtx/HDwnlP4i6iv9k0ihZsTmok0SSoRMnlBjJM9KjdhTa8tDmSubHq5hpVrMWlRZN0/hiwSKsJRGYMhcCYx+flsb689+q8huQsEfRCyDzRk5sSK/F3cG458OolcUY8yCJvs+4VD5dcYxpXi+r9Cp5q8gLj+OUbFjpVdw/17FtBDqhuccrhzTxrIZrkk0aB0YXTYZOJPhlealVjti2ddJi0frgcp6u/TEvH6vAy4keI7xrStqyEy69otXYPPP6HuTGN9eSEcPJFaGgmJDdY9qjTVA4MiHXTgatayusyYfpl6o7/fYiSpUr1X7qjHVU+aabZB0Chs3td0Vkz2sr3+6qMgzNOJrttTqBMIh2OmkFgqwJQpfT4DIMmvUPaL+S9ploJxFmU5EnYOZwrLQMpkGxOhCgc4LVe3/YhMlmBMBfZsHBA9UYDHf11dyhSlFUVx490SfOTN/B6u6n2x9ZlqIpQLr3bAXJFIOlub/RdP81+hWoxSWTNsUjbXWfk/h3mn5wlqnX71QEKZUzLJGJwFPxbfjwLpYhnYLF60RLTCCwZMRVS4SBoRbZxSgUQqXdjQh5FZ7YGLSRfLI1v2ddDryBZRoBWggaPlTSuKMaGZmqNtEMhsmB4vQlcPP6KMygpMHqelTXXFaOUexiufkgFOUF/ei4/rkW59saYoTgsX7srgVTnWxCtxYNA7kt7MCf7hum9KH5dMnPt8ml6pxx8fIRFs/TbusvVXVtDs+vMVUrLWhQGnIPM7Vv0mNFCHGKCjS0W6262uvxblS9R2xrqT16xwaaoD2d0SH8iFm3hj8aQjQWBCCVJDOm8UlF7w3/CXPF5IR1Q+LV8LYJ8U6PDRvzFat7X7xk22cyYYacVSNonrKmZt1BoElfN92yVeiV1HpwYvs9odIrPu7PZWeBooTo/k2sVsGcfBV4ii4QBdOng6H7rxivOo14F7c9ZNHDqqlpSmyMKPaDXHvnO5FtobKamAyMl+uQGwNNNBi/cpqihPWyMrddBdBosJ9R/vcDEMuPrfqnuoHtuoA0Y/GcDS5f1qghD1FswL9wGLBCwxkmrWyW2VdUabFUCqXCcNB8KkijFsoPd/Rj5/CMjNRV7Rr5qUbpmY0XXxgZ9+z0R1Qi1QDdaGneh9VsoMFQYl+n4+86u7seTfvR2ueyXyrVhvRWUUCWiTfZaMYsawWBDBVxh+sot2On6seFghefpi1iXcce4n/z6+WZCw4SXjdeATXzC0u2ChFOx10NiCMHibiexZb+n6Sf9Vm3OY+gwKlY4AgazupkVHLr2Si0huzqdEKZ0jXYWao+CbVRWaC/WRpX6ar1Zg3QgH/ez3Z5i/N7KaFeeheuqCrijLcx2WOyeEmhZVTGgcXeGqVQNsOV0nZ+8u+idU+X1n24+IQd6g3luJ6/KVEC65R448PMjlXaCe89zI7CcDEH77oElYRXdOCBP/EKbXCU4XtxAMf1T2Rwv0yCcZn7I7SVZj5tOm4FsUszHqTEXTES7EBDaveimz1sKAqOChqj7KBegjMJ/4G1kNFMgihfnz6ay42n6Ptw90EyfmsF6sukwOBGxl+rPZz+cn0knc9ZbNr71gMxc5Gsxivo6bqzMGco2aThYBnhF5YxdLt44AUXYSL3tMWO5cokt6dUpsaFFy/POR4v5HB29m3kbgs/+GtJe2ZhOYe0nJGxXHFYCwEWzQx0i+AIItwJB2I9VWz1p+JyfHKrCZroMWJ5qhcaAiEfZjD9vKmD14lALoZbC96t09R/+n74s8fDd6x3lU8xMP6IW/oYqeVBZVnMMIaYM9dFWDI4MOqrMwsg7WSMW/pwlCPbjicbPHgwm4E/f6Nw+hOcG2kmld+caNS60G88XnXmwDhCdEOmgGewkQqmFy6SdzvJQaKbkiGU3ddbKOmdv1tYwE6/sOoHxq2u1gxEZoq73S2Rlfk8MOucgzL/2j3Xfh2/FRCzrdG9vZekBr7sZNEvuE11qMQjoR1RWq/WbfJrvFYBQltUXUmOeDNPi+N3r8/LEaPZ+wAopF0qNGqVkwE3UxyzOluaSFrG1nlzBrOhsHRBHo/wpnTAbeNEXf1aYwemPDsr4I9RP9ef+9RX5BG7MeR3dMQllaMLULVgYQbhwRTZLgAh8/GRrvufcZ1IRSJohArSLD3VTMLfgkcoLmLUAIsdH2IbEdrOYlu+riVpA9jORi2RuoUW3l7DqzbkIFEBsWbHK4n7RJh6EtnN8vw5f0nVQl7LJ5JeIZyyOT9JA94N5nUlE4ETF9A3eu9yh44G4P0Ytfwa/KpMnWWTdeMM6DeoWUEZ5BrX8cj56OMUeCmfHAal9DJv7ZztGRC9S1R6NmK7pvvXbQHd8desH7nxP7c3Kd89fo5YYUUXwDrWZ5z7lw2Lcgi04n00XG1TcjwtX4D/lnSgPGbq4GafUwI8+2OxejM9xnOxOieKAvhd2gFdXBJKIXIAPX/KxXs513rwT9BCnEbFaCUZb4vIjSZ0D3kkZVSp1J5wfHSEInypEXXKe18zotKgjg9QDrm0L+L4CY6g9m2ThnfiJGGlgJclNf8Km/uuljH362rc2XtuOj9TYS+9x4RXup1mM1pkOuvWBLfSluLcWyFn7LkNEJ0w0gPJi9w7hJcntOKvGAz0qi/FItEnmbyAUmHAeO08Ht5Ri3pQBrWVcRkibG1TNYBjMi11eD0O0JJ0Xd94ljn0qE4AK9iH7vmJwDIUAqf+pkUFdB6L6hX8U3tlSh2YapT7CtRrG77PM586p21U11nlDABK2x7M5y+9tdUmY4alcZqRCl2ivQWoTybrEEMoq/m/zbXzCxY4sgeLlhlqnSrWkurTg5XE9xR8/HO3SKx8ogIpQtvOZKtsEwZ/EGyVfS6gyb2OlhHf7Wi03TBjiVfRNf4VePmTkM8afzP6xC0ULgSaUA7ZB0+WfXTdonS29E6fYe5o3KjPHFI1T9uZN0AaHPuiHWWLMqdUrRiGqwexBIFTkdCjm2tVywbxzxpMaX0giuSphnJdfHXgVN/jWDhyos22RBMH7OfLomgvr7gxNgkLYEcRtAcbj+AjHHn1zZmW75DZbPBi+JQH10kpHDfyzM1GzimSd39aNHp3KVORmxmDE/xvFBFKOS1uXRrEv5YzAVgfLSV5Cbm1HQsfa4JOEL8pv2rJKdPelDSX54YHebdh1LnqTQs9QtWo8pn2doZX3eyHCYepHa/secRm+BzaGwEmB0trznQ22XHtS3gjPfKHYwDR/bdHRkpSY1eirMZQ9kO8vpyOpYlZ65TN2RbWLwsm6llSbDK78nvoH3AdY4/HltpKwblVcB2ryu9G4xo2jU7Hix0Zmz0t3XVwr6Z0S+pSM4F4W2e9eYntJqbh86d92FfTqaG6KsuT135wQskYrHswLHpnvhD2M5W+a9YNgtoHTWkUAycE85JXQRj1rnl/YluEzzogrReMrxzUPY9GdxahcQDv14MmrEcJAoNc5yntF2pcjtVJPcDTVug/iPqfvT6Hq78fIhg0xl8cfk2LNU6ith4ed6ramPJSAn9JES5cF7AEd7TzcSF4KfumjojwG5hoxP3WexHfqE7ZMO41vted8EpEV7iGvOxZqpZz5yc4RXr9CfZkSjMYJmt5GEyFnQUo7AI2uvMJX/DS6xMBFj1oI7Kr93jgLbVH72Jxu43UrnPgDs9oQ5w4Jeua9aT+7F8Y8UvpZYGJKUDpI9rMx8CSl2Pw6k4odFfi6PhwpBySLzoDBAfy/EVXqTOx9HclQ0KLdWjdrHnVFzwpb+LkMzctX4eWs9p8OkAhMOfUkKCG9wiu+s/oxS8PgmUx8K8w7OJvJFmWXfQ7SEWiI6d/gPgVs5aOiPzGWG+UMCi2V5uGPmHgAQpdvXbT9H8LlTy/aCUMdXMCmxt+7ldjwyMDcz4FR7rJrtNwj4W/cmHMhPPAj9P9YWqBgRb1ShlD7kzNUfLg4fwgvovjAKk994zG5q10xd6HTroiBKNYiwa701Us58RIXA6LDLt73djbFdjm3LSmVIykcGstkJxBGSz8fjx4/tHqU0G40Gs7evGZ91ZndJ+XDB93IYVsDcP7OQ5w5eN57WB41sFtnaoKZjqjkpUOXy5F3HhmYTEVcfp1A8lcYWQhnwqhJ57EzXq2RubYwUt3yGvW7U6ecIo5bRLejHsyDKQ4gmR2QhLoTV9TYdGpytHNVJ3RSjaJqiD9clf+5ForGvYhFRxi5XKItVL337m3+UhbCEEsJDc2v5zVBF9AZTq0tJYrp68wazsefdrTFfN3KnlPa0VnbUu9AAhTc3AU/oCy3nHQ+qWAnwF1WfEUyDKlr+1XVQUOc9xUhyycDcQoLYSdW25QuYp6h6JakbAK2uJlm82ccb905pCizpGcVaD92IeNM/jDaZweBH756ULkoAqvefHswLNezhiLGflPDvDNPQ89MefEf1vbxy76vtGNk4xuVAtWBIwyVuPNSlnD9QG83DOMp5C85bV8BrupvMg33VXx4kSE5b9pkHz7qNRGugkeDsw2y00CKogMc9qsQkehDIUZM2EeOHsw/dHZQITRboOVqTkjLL+w5TBQUt3OGxDeR7LPLdcZAFN5Ick6rlpKyX8LoTZ6qhML9BPrGNu97BSsnUL7Q1JtwhqJbqfd6egNxHwEmuq97BxXmsT36WLZ1hXMiyl/oidS0Z5VwdmaiqnElfsJPJkchtsDPvtRx/xzwpXITYLTSeX4E+ucjrH7szfKAi+H3grnYI7KYGhVRj9CKIZzal6KL82aXesj7Y4mJN8DrsDDVM7EDIW/79+ihlSNPKQdw34YgpJxnrXHqyIlAXKVouis4dfYk2yckMjFNRlQRKbBBZn52+yK63d1wT51J2Q3kBBd2FZaKqZzPmUg7i2oFuukoC/csT1KtEm6k3xCkSiMN/wSchGidJX5/dKnOh/ChnrTe9o291730M4HOSoPZ3JEPs7TISgZf+GvaxRb1QVTkRnAxAvgdJ4agfIQIvCJrqrk/L1dYjYkyIJIFM8ourIOMyk/Br+CE//NBbMBGgc1A7dr34vrEAcO0tCsjg3yXMRaPct4IOfrrwIhypv/EXLEJTcEAH7OwBKX6u2BG8COe4Zo6h1ZZB2SUI7u5/vnafVTMSG8bsRd0Z+scV13YS8E9J1jXrE7bbPT7xSl+lJ0p+/zXzq7TLWhTrfnoTdhwZfp/dcxnu4ZqSODFxt8mveGEJnYy7oQwqMne8zM27moyrvG1rsgB+QmOfjY+JWK5OCJVFaWFz8RTPEmldAkAZGeV8qiqIgbAczlFn7ZIF6g7Q95zFPGctnd1oXIA/g29+XCVHVuZmKX87j1TuZ6ZY0+mPD8gYZLWwVs47YCtxE8XO2PXt3LJ3TlUi+txpfVvGAkIdJpRzSc5SnC8Kz9t5jShudw2sW6dayxaM8epYQfAfKSrYBrqjeYouslpR47gWS0FR2Wx8RNuLmQpQB9qDS+6a/vmxG4Z7l+bpLYiO+h8kFfFfudNBBjuoByM03+Lq4jNknKskBSAd0Vd3VFIczbeJdboPZ4oJwJ8+3Qz2Ub84cnHz0bDKwXslY28uDHX/aIgFWDvkiq+wZHpO2AovfcASY9Dqw/uY+h/qWDRWIUqpmqxTvG5KiUaK0WzQYJZUsf2OCL+sAkQjqB+MV1mePYZXYLSu4nDhV0Oj0WHlyVRbRv9d9bEpeIeTG3TuOByHGkBaRIbhXGEye/5YaMTMyZNc+pQlOiuh1I/FEeMedG6iDAhdp0dPFRdXrqzqsg8mw16OZFrTxBVGMjyFpm8zbnu/yTtL5Hfy0Jpajimjh6w9MPIrPEZg4yzgmbKi8kRp6vm3iQZGBociOTTkKiBLIHMxxpr81PoDSCPiRPO6NTprNQFGFD798NvQTgKzcdNbc1K8sMwf+AhVAvL3FgOL01JcYRscl81ik+I+uSVO7qHve+ZC39MZOkDX3RVIMIox/OyyLCUitrjubHWuB0MZ7Fr/hLn/UP0hMtT8eFl5WUNhHyeEhprsJFWVJHNaXyRoBmvXJjFHa9XOtbaWlUoWbtiEosF/bt1IeN4236VaSwmT7ZwTi1djtfntPQ4QejzvQRVUoSVC3Zr2vQ72zNbmkxD4hfwTIHJ6NqjK+07ZUt5doVnwCkUqe310srCy0iZ7cktv4myS87lwoVcizL+kbWctPZqndBV0J09XudHHvvnPSX/qH5K3AUNDckDhzrN56hBH+iZc9h/sNKfE4wfWzrCkNx0F8M3y3kUIg6KnO14KSqPuI17dhsQ48VFKLuF/RszqSXFItZ1MKRWLwhH1kAxt8oFhbtoLo9WoTtWSEPeTK4Xqc5hRDo/w/MR4mfcGWrU5EYfT1oC5UCc2ZNavVDAlPDPtHHSE11z5pNXwcTyoBciKPoGKCWkAXUEig1O7rxyRg3fkmd+Qz1VMAPvLlEGQ09eo7EI6GtCyv2gzMjy6u4MmLOQvOqtloyKBrS/JCR+znL+7Gk7x1KKCNPZT2Trkik5Xiw1bAnRZZyIm9s08WT0qQ2sQU7JM/QJZtMrdXZH3ahAFQWggijBInjCtJrFwAgW5k3mLTeo2TRgkFcOMeyyUhV9uqXMJM2ArB1dY8HlfeVpB59rSooFUTH2HTn6GmjxoPXJRl5ZvbDQ+jZAMJ2EWwrRDszA+YGoXVUK0AQKRMqSg5kEVzBSDaxOXQXIS8cOKXZNYWLur3Xf/zNPOBKRpb5pgJWFRwJmYwYt2UUYLKxitrSvWsHDX1fzBQ/gxGVYGNpQVsLcWzgPoijMfJKlrYOweUD7DaaR7u2Ham8Gco0l2kv4G4PVU48bvegKXsv+yQb2FBCBh27U92imnB8FXqAb4K0q7tS1wck5n4bKKmkz45w0vvVEf2JrEppa3iBLdcbn/C/4aISB7pw5l3SNlKvv+X07dSWuVu4brZmcVJYtUCbzpeCkTJBp9V/plKic5aOqtYXpESHMtOAgd4XXiPMKqyZG7ZAjsVwsRjz58HqZM9gQanV34bevs2gjUDNjkdHqU/IlUiH1u4qc8tIVU8yb8sOCYyFWM7kQv3tsedzOjSTdc2thgNL2W5+36WW9JsCCs5b8EzDkxOQMA4ojxHPEDH/oh97W3kdkrM/oqgh6JI1DMjYtvnf/7w44qdI/YTO9sA21xbNlSoXSzZpOUMFiblLsVqViZ/iyuyHICYoJ3qpz37j0klDTeomhXJs8t+5guc79pan/1NUqEaFTwBxq+TpATGAMiqIkh9b7PmgtuLjfEPBHxGCbayT9T/HT4LtJrOsCOcJr2Bkw4PnoeMnlPLjmsXXH1V7cXLFhHnDdBifwPIHsBaq5ZP0xONpiFZ8W5Asi9mb5bSZtKrfHBjPAEzsNhXyRr1U9qv8gloMJdiso/GcqgOECpSSQ/Fy2FMyRK8T3G30jCgUhn/usfcfAVLJEZCBvycMp17R092eTqRc843boIqgMi+zYQUyJnFhRObkL6ZVeVMCLahqPdkxidWa8DrLURh+WMNtSWghqI1pplftrHobS3zAc+hfziMYlzHMQUdEgg3l5TbGgbYz79FlKkMnbOX2jGfCCBRgPMkB+qb8nPRD0uqozOJoQ1tTuIs3DVNsi5o5eU71aCA0kO4kH0mX01Ye4JOsR429oKd8BGXlNKmotp4y1Sa9drhKeh96rgtI6JiKuI7KGb19CkcBcXYtJs4MjQrPQh+tbdN68aWngAqry3BD3KuOC7nz4mqsTf8YdZlFiBE6SJLfAXFtlO8UD3MgZT0XtTLYx83edZhtV+vJgzO9cmmPOVJS+phgUZnncGH5VTePkfnX/Xn8b0tgEVZKCVlf2j0KdMX2C/wvKdjkUgXERvmzQMHRfBU3Ji+6LYtmMp4Vktk9uw+rCTz9Dvj0LCNevrumRv/sUWEiNRse5ulfdBHiix9Inb8WvACter6UN8MpMsbleVSM/Qw/DmM/qmOpFPpKe+0CurwYHFxq9ms7QmvqpreWt+1HGDGQngfVSRY5Du3R2+EMxCjZ/sP2gu4rRoQkfKQtsvhfEsWExAK+Aa7VH7n89kK/V5ghxNZrCKeApfHPa1BX0wxluNtgSq5WUuhtwQ4QjxlYbtWp90cF8yw5xMUxIyO6+3QdXsXUi06pWARvmGQjJJCWrwRImynhfNf1NI8rc5nvEq/+V+PMWILjuGmSlxL0ITKLslNvucbH7VjrFoGIvft5OASUNabSAQt9ra9c7A1JykFsIWqvHT5iJ6vGROEuqBRpfFbqwmNQOUsX1xImW4sRHHIyveyQt84HkAG7xymFF5KvjLNXMpnfcov3fJzymSj8XseXS2KGWOGDbhJ1xQWB1UCT54bgL+jMzDOytwmUG/0llYScNn9/DPc5tgESvqJ+b9kkfw3XeZu6JKllLdnT74eUGh4XLmbXopcDnGy+ovg9DpXzb5UjbqAErxAK3Y7dl2IBxkEUtjX0f+dNP/s66U1lWg6f/BwiXHciGQPoe0v6QXzZ5L7tUvsL/XBg/gPmqwkcBMPfJICojbZfVcCQ0IqbOy2GX0/2E1YByGC7zoxumV4T7A4+538PVzGUp1aCv9ljcrngtCH1cjQi8JsDDGzN9nbXY0S5kGOEI/cZ7pxeuDbzU6QhpmwhcO7TFo1GP+HBmkL3/A8/Vq1YCY+HUlUWUjWm3T/CB3oflRMOqjmvVqUPDQbRd2Mq3wn+WodGfENzMuUpjwqNCMLbg8hjTJW64oXGW62tvtQJhqXbTRrVEa0k64z8hE7xE9RN7CI2uAGrEvWQnddl4bEYc6bH/u4w/K8+CJsoNvOAkoLPMWWk8EbJvyU8eErPR0SXWHHxG5LAbqt5bw3CSpP3Hv25P/jg0e+ZRZe5RtcI/nnnHsez0nkFknnPiapkc/49A7rtbUeWlZmilT5vyK61lf8OFtZVVsSWL6zC0EPUBIFtc2QFRPMhmlmkHk56dK5Nv1HNPiUo/ku0CN33XO3NNCfo0ZOcMkzeppxHHM2SKO/g8kTnapgcAcZBkXx9P1KiJx1r/t+uHiVmJGSSKqRVg07QQAtxFP13jhUsxNMRmbCQf7w7RIHJDZoL7Yphu83aViJfpP85TSBdBoZmEBIgZhi2WPddHxvkqjRD8YpNi5hSljtbS0lrGOrH0wUdjACmU4XAoB123m4mQR6H9q4MqX31dnjBK0NR+7axVlHjZqV1vEPDz74isKfqzU2Zld052r+fv/vaKY6z5CoUYyVg5yea1uhtR3O0QahGNKVaYOrflJaMHvFRHILP9cSvscmC4xJ2qAMxyS3lzxkhcZW1TMJUtcpu81V8TiRUtXlFBpbe0zqc4M12HGhutNBFHpRuQGONB/YE/2BR+1VxQ6gUt/sBpZursbaxBqonR7wtMv4OZqoMi9qhdcG//JTVPpqJgLz+lvWGXq8wnPvsw9Og+7bUXtRWejPTjoroWRiYDfUwTKcuJE4fMkBcGflhSaMot6T6STfntO6G9gu0YzwpZu49A4GmB9ynaMwfBa2zW1L0hqVhcrAsf4boZpton3ylGlFQd0VRRgVQ5ONWr+7TomPteqUXZBU13ouNm6eNYVIiR+OEsr/8I4KdhTnpAJF97KefJMA0XWv7YaMt0m7O29otrBQBCqpPQmWaNlmkbDO8lHZ0ertaOAI/qf9gcour/kEyUtYRYcQqP+sYnOdiXFetKFdIhEicxGgqh5xmBvjJIiPBUOXG308LtyBvRnFsurx1Wv8L4KDhZ+Y93kDjNHlREGmypElpi0TcskQ1jqEErTtJH2AYZssY1Mo5SSW4audR8yLEZppBY1902Qrs1igKsGncpQKhDGOhkvEEBYfLx8v15bd0VVZLLtq0akc9zaxBz+GEzAg9Xa7STxtO+gcIxXXBBJgdcDqCHDBr+/9yRyjR63s/GfV3ICrP1d5B/Md8yco2k1l8iPJ3KWVJVkrfb0biQSjXS8TZfg3e2q6haSis5RPvQk2ysk8qokE1aKi2hOT3eYro42OLQgkd5Iblpvgq7FYzjlnMYQtEoubwrcnWrk47PULJkXMZ0MYBmrQEm1Bjm3Ieyx5oCXJeVdtyp+Xxg/ZYK7fvOn3lJlbOAKnnjPJAMJuw8iNJc+6vLWexXuz4F4LlSfZcXM75HROn+L+mwcnOYo2BFyISbuEd0iQ/NbFta9XEuuGpNkicPrkGgIQy1tILQj2Yes+qzwbQZr3LaDA2uqEVCIcdI2FGsrg60s3iDJXM1nKHTr6ePdbaX9Ol72JjsLyZccJS2i/0Au/2xJEwAshesS6HIzv0smjYJdLeDK2WjHMyTpIDMC3iZdz3wJtsqwOb8chZD5VV9/3OkBX/VKMpwCHw5CJc7CPq6aJMEXNO1ny6D+ffie86SRan0q9t19u3ZYwl+g8W2trXDFExN71wxwjToTYdoeET3PF0w8xjn4ByebZVpa5nfnX/7ZSUPJROhsXzEm08MElm+YbOwMCYTVT+5y4+TcMHnxiA4utsl6koqvtoyM/ZX/Z13knUjONK2PkmwzPTrHlXwvBFFW7xh+fx/pXjasQGG4CygyS8ET7T5ZbFxouUCZqUhPBZSIpRajXt6Q5DCPAs7Uksg66oZqVEsjBaanCWKTQPVek5Y8UGocpwBUWS42wfzJQagU7gJbxanS8deMCsXJMs+J2qsmdWxNQ8/N7Kjjdmub4dV4UIR1EWLtpyjKwNuFxvwV9Uo75qRTONHuOIrPXKqLBl+siXgK8IkYGtHZFGCvwE8JnaS0eVjUnO8pyZ0Wnk4vwzurkdu9/GMAVleepD9qx+U80xugnlIvi0Bwf9Z1aiMHCYjZYq3r3HDFVlV8er/pOqb1bRZCGF202ZBjeCHuhwrGGShG6qqwJLhy6fPuKykFbVqJPYYDIMc29wM8x8EhDRk3YC49RLI9zg2wMO5zhaITawwjMGajckbh8EwMWW2JSs6ojHO9yRHqWc7JnI8JPaOY8LtSGY+Iyt0fcdp3BQs0j56SZoKRucX5eFhciMb3hGkBCEYmCfPh7R+OXgaEhoK/pd4/NgdMjG2VG3k0bBR9bWFF2N232ojJFQ2KAvMlAv43R6j1AMb5/WlbUk0tfUYUSXJ2sQ0hPd57ae6yAsY/do4LenKcCrywbXh20ry+2s0sh3iQ4AZSlwBItaNTYz4ZlyLcw2i96qaO2etOfjrZgey4int5vLXvZAV1iKqvPY2631gZgt3WYzF85QIF+MUqmIVx16/U4eUhdDyO45Cr8fuWedmJToE6HJDOFNhxjmvgBFP4uoXh9fxLrXjelUnSEuBi/7LtTK+RMiTgdlFJYaD94tRbtQ9agm8VXB3HrjLCYcgIutS1mgjngj9HKK+0nm00aQJSAq+k0Vf4ubFxum5w/GFX6P5ad+jXjEcbCE+/n8U3lPUqO/ZdwzHq43n6wBMkWxdsdgzKR2Rr77t66pEsqWjCo1aB4HPkdNQVt3vUDXUS4belMipu7iZu7p7Jg/fuyfyD/IN9qDS7Zii8rVaKSfR/GgcnTxM/2BVjREiRsYN6gTtIEsa3hW2AVuH98eS1YTTgZusj9eCG8ZrM66Vt5UfSwxr+4Y7eqnN8uqa04x6dF+npFhYqpsn7ZsYeiIWQgoBgIpLNgNlbOFvDgRAfzDDUu0Ineh/tc+7pAqudW77256/nW0PFiMDmVASiMoJpVyLMXLtW7BpziJhGWcFlH/FJAneIGVQr6o1YKbYmktNRsJUnmzvCx6eSMk8zlhYWywRVPOPuvaez5dqlSURYjfvzHv7mtilw3g0SE4kYDH3n8qFGhrPxe4hZFq38nNcEJ/rXG/XFD+m+f4NaVznEYK8wZPLIHeiH2MaRYjqajHyq4iz2miqsCdJEtrd7PQw9xYM2rHl6BaWbbajxH0yenzwuLtwO/Dy3M6/pjVxB3X3leHnfDJNdwR9IWYUeKvXw7Efp9mw3Kyn4RAlXJ09ulw2gnWBawqLK7tp/ahbap9q1TmgMo0UOVF1Etu3TzHxKL6oNUsAkgrAzKxR6IqtxefMhOdfL2d0flSobOQQSyDrhWgI8kXTJ1FAFz+5r1P3XUzIqSwwXT0+qdIk1GW5SNKW04Zrcn2CvECFC2niNjEWeENAItLAgdjNRXdyhUW5ygegy5O24eBor7E69OfgxOBSz7uAu4liym6A4U3X2X1xZkZ5Qn17fc60VrH0aVZdbzHk4jkr/pBH6y/tHx3a74YZROoheTHCMdOlxM5SaWix7ROxE5bRpYn5gDc8M23V5Tqnl0+jj/Xa7x4avdf5nJTtqz9ftwVv6xnicbMk/sQENKfoMK24d/ntJwpXYLIl6OtLFTVbd7hi/lUyo778li/1yF8Raw6aGtCTNyAtAJNmleeL1RZapjbzwCPz6Co2P+YuZ89ZmCzl82ndI2nGQm/W+lYF3qsoBK6F9fGXVTqB35LGN7/Szq07kAFNGIzRcsv+WuUWzfBXVOXmFtMX4HIas9uejuezl8/RlHOKQDgeRvKCN0L59opKOXBXFIfyWhiMFszu+2T/C48jElC9yzV8Ia/iZAywUR8F7uM1+dQfqDDyGmzxgQZSIavWbsuDF29ohe8j5uMYisJS1yjrgKPFc1CzCzuZJtKIUXfhQ3kq+5D4qdM7ryLTlQp5zU1lZlMdwsBo0VnUCjFDSiIfgjnmVeOiDSBTraz8hmn47ukpnySmFXEvvLID5CdX659HymzJ+DGGmBYThw7wV3FPQ2W5JslNm2/Hj+vbY9+NALF5JAjgvSbX1OEM7ED9ZtbpLyS3Lcrjw48ftHHFDzuRhztIJSnD1pyP+tE2wfHy5a5ycXlmQG9feOOMoANCL1fKsJ7GKLPoQrse7Oy3BRdGcPHnAyCGvGTZNC/1+nYxHedJe3rOjmcDIBteZcp8QQRtRQpV1ywtlQGu9qYJ4nEFdvOGxwUp+ajjT75PFayibD9ZGwjZiKIEVf9KosCNNMqCad/emjzVhFZNuiI2dRzkKB33XTTlR1/IHAivRbUXDZwfODA59ekaRwGwMfxbwPNb9/DfY5vRBULLTg4hvWfC5h3+pibDgE8nl1RLPaP33KejxnByYQpBTe/Bz5lemW3CRMZz24y5QjlC5bdFLkIEJJ3hlB33JFarK3CZucqjrAnhumHUod0KgP9KMPG/7LeVoFo941ZQVD4I7hBHEhDevNFcCelgx/GSzJAy4sFRfulAZG76azIYqafWGscotv9I3VQTGtq4za1ZjOnm+T6xeaDeg7Sv6YmFSB7bf+NC7a5Xm2TW+D0n960OMuxHBClXThdMmCmyN12UcK/RZ47dtwvsF958axiJjVKPM2tU+vPQfKlQSEXLoMFQkDm/zg0KGcYffw3jjgJ2/Myf40XT9bBdqBjaX/HtdwwYdQpBTDVDiHaPRPwDiRgVr2uHndAt8D3Xbv8aBQn8LzXz0XzNWecqslvVgNwJQ+2tzlN7HpUwVei2AYOc7kSR3SmBDk3uo6q5sUurO9MBw7HGPQIPKE+SxA0AtG0oXL2faXzpq61lSRpxXHl3+WRunJ27CW8hptFz1PYfZICeSflC9gFQlvMpLsH8t0RMGb7wEeTpvqF4WOlS1kc9j7f5L+DJj4PFABqmqyC2VS+XZfWViviB88dJ+SFR+1lDgIyL5eLLjTQLZUhj1CkibLujsB+Pksv+E67QRC94tpVhA0uOQGd3+a8w/fQqcefQp7wzz36ms3JY+iCcsjzYuv0mxYLHrGtNECDNCUtXfP7QUXDJTqbeYyOLvyXQMo5hFTXjoFVsmtFiiXKR2e3Q9Vu/gR6D3U7+fwnrWndvMmJ+/qaCVw1XLZRrXZk5VUvnUkVKJNRIYrOPDZ2zE/SpRnv558ovNPEPsmEb9evsLMAUCzN4mrlKTfysXb4eKMTAyzcKbpk/YTpecaQkJIsr5j/tP3Nees/1u4H9sfEZ8+5/iW2mwtPxEt2Tv45NHrcwAcrfZlQLquSF6HUNolx/wooqGJVZj1YPeZX5mppeJF6dcnF+2AKkZ8FFSd0uiPtUHsXuNclkcvOlnt55wTQ2qqvggnjgqGXSepX/9CRR0cNU4C9ieo9U2gUUcsqYBBLWQXz4J4BuNMO+hSrYFLqEHnKdl++kzlYKxzri+P1+I+xFAbxj1lvNNxTcnJeKALXg3CnxwgpTOk894DNH+0gr5tcMNToPI9RFTm+cMfeTXxFNm3eSWqSUs+S/WAPH+zWYJmyJUUpr8CTMGyZFsIfIWy230ZoPZL9U4/oidsAuYznwO/o9u2GKn1iuTvWaHL0lF4TVMAMDC9Bvd2vKNk/xAAx0UuR99HlPdmnCT6bho26gMuN/O5XwUqcGLFK88bfi2lp0QOvVWcYTYAVhcnYVlKNshg8ZFEYrOvKR6q3Z+0C1sVQ6Z7UUx33SO3WvpQMVOb2KQ79oBxQofjbKYC/aEoKZtL9S9RVpx6Li4UAW7g0dDYJ9bCOuOOi649ulZRxMEhq+KGPLSyN5yElbyLq4K1qq5DjnEtWWLZ0Zt8YgNyxhKhAcyAAB6qeA94b+heFaL9fci32nLUeTrz0DQzOdoQxBXQRLsZS+2sl91rIEN0TS29InIxRJ5zEPoW8TKG0FOweuikkf5NkRrbaZWhpVbciA4EXr+LtgNny2N/UluOzORU1LeAWqCaC4FzqenWKIn78t/cEoQEtDfWBp9usawgAY13Qpn9Hv9DbSOMhitgTW5iLjbn6QSuusoHGfdAR79zjDns1qf/OJBd3XVLlqKYqqzdsjDtmmL9RKp52pu7QPETelZ1mu5ILoaL/jy6pJb1QB8bb3hhlACEKF1KLidenKS4CmW3ScPTwbtDKFW1x0jUmM3xtM8DhqSiptjj82cLMQU6+VC0QeByXrExtVBscgOxKdTOMpSghb0R7oistIImiw/oFFuDMsllubSw2Nmnw//r/nwuHRqkVfXW4/8KKMPjXrgzeWq3KCe2eGY1sEpLTbR2PA+wdsrb2e5udlNCGhGYMsglitKdFJRhZNXeGcGBBohVB4M3w/kXtj7GZNhW07vtiEAH32lhLouDKIeBuPOlh7BD1k3D2FjWnHEM1Qzfcpqf+PN/jTtDyCblFEMuwMFyohLfj1z+pxHFE+tUyPJcwGo328kw2U2lBp5n2yeyuRHHUmOMRZiOymuZW/tWkpZY27Hw2sUl5NnHyPQ9KkUaKcX12AZIIFhuu1lKRYri60qxqF4sIEeN7v+WYfUsb6NxeionqZ2xFIy5qanPoT+onPEgYgoxwCf15s8h1WzIUQ1LGGBaCElu5UP8UJl5IcKX5i0DrFfAIhzYfymbq16Yw7q8+Xw0sP0sfV69CFq+kFOnZEZhNDNkGo7yiZM4OtCEuL1xAqq1LI+czljGUX4iHoqmjor3rHvmnCJnh6JAhXDPt1p1uhayevcfhNVy8u/2pd+bJkZmIg2/dOkAm9angVqXYHSg7UbiwjMEFa7S9ZH5GcC/6j0LijYPaFRRNdAPxNTJlpon85pH6ez5WJ8T1b82NSppEcRn6IyVOt7Df5nJpV5tZkf+ietdiaMd/hMUYUu2hhONGXqomMs0m4r9hurYsPOlYGWiM2jXcZa9EtJMoCzCcEM48nKW8QVc/kT//2YJ+aEv0ls7lzsxIXJZp6Ug66YzHzoi0VlwByVgBjcScOwbRZO7/oUnhqwf/l5+MuFbEX3E84ZeGHMZiuUjD02yIrmRgWB7kX57xgNWeo5gs5wvpJwjiNchxl4yec/9oBd5yqygEIwnBOEgnd1hN7z4HtopFUh3He9C8dD6ag8yQILDOSCgeQl0q0Sl+31dmCGHnCMEpq1AvD44S0uon/y9vmdI0+Eb0yWVuqADEi9xp+TD4DzfcYubIkkLASW4sgyXSe33nSgFC7zhmrOW/ZhdWfTheQ2JiPgFYR+HTkg0sGEPUB1SzFhyX8+Ee6rzQMZ0+KZgqB6reiPD8ShcbHv+L9zDzVShp3qbzVbdMf1viDdgiA6c/SZISCEvj7VeEjMc4OHxBpwlk3mo0xSctObU1z4wa2mfy6l8/niYKYeFqhN5wswiXpGE/VZMU1Z8lWdoFj37JMamDywyJwXEbifvUSdGQT07POz6ZLDydmnSR3C8E5UiC2lfvnyG+hDy/wM+MASy+604OqyckSAao4/X/3GumCmO8Cfrb9F8h9E6trRQw1lGrt/vVQBQLuEKp9buxnlxjde85cNQv4D6HkFA3rWsIUyDyt9qsB+VPfoECP9eWf4IjwnbYP7LiAFcOLXn1tZwyWGL9ok/mr1dZwcc7Ew1jMK8iJYGF1Qd+NoOEWddjbPM2B6gFBC+9UApNUAdfs6tGKqrZdJYi3ibHD0LdSMdvaJd0u6NwIMUm9g7tLd07MmNteqUGiYt8owo32mTSLyx5B4+1hwi60P8lZyz34CZQ4mH3cQQ8T3GWXrXc/8mqzNulDn87rBjqk7F4NwnWRUdkEYYeVzy/jKle4xVqb806N0hBNb4ex1c+/+Yf0Rj1bD4nC98wYLCDgjD6XlpIQ5w3rVdjYsPvhdTLGxtIklL+YJcnzh6j4gh3suvwMgPzKopg2LpmtMF0Nc8qS0yrGvgr0hFA/ncuf4nIIh3os8Vz5zxvxX7sb1D5zIlef/6fVfiyoy7me/qBOwOUESytr7jFWyw1RQnuPVQkklf4EOokdtYoyFlhp0lKyCyDk4RxOlnk/RyoNEvUDU9WWYCXgxhlwwBE6Ogkf87XltzVG/jaOA7Je/DlXmtWVK1N/HbDLZAsL6etcuD4PJU5fVEPWr5pijyUqOcAIg4HzbwzaCgcuf3BqVIlacxk/854liCfi9hFFf+mtmCRZmWoeghMV5TymGbjQhCcY66pXWvL9InvwfR05VoDyIFSPusER863Ir+zn9Zs3Pwh9VyUyaoSVny7CfqX+apLlEesLmnAlXjYtlVdROz7i1DE65NW5M6i8e33yIe+N2ngzUzxPg/GDs2JaGb7ceAQvNNr9kYC++FjPaH06kj6V4Zq+0A5EsnkoDTROZWxie46oI9gi+E/hxhEbcmk22kbPu0IFYdWu4J5uBcerebAhrJagIIrgr9F/IfIrJuHbuXHAQ3XBSE8TkN5Hk4loUcI9WvAzakrosFjzf9ItweEWhQEAKDZtm3btm3btm3bP9t2L5s327aNWcQs5PR5JkzN37RlkC99V3t7ivORY1MUvmyuVWmWGe1ffiXq55Urroyp6tqNcJAilM9G9Mm1HYl+vz6Q49mk+/M58WwKvzDFt6mHnMbhpy0u++zepcpIPb2GF07EUtbq3Evshwvo6imouzRAxlWrE89rFRlJMyisa1O8Jdfrjoro3UeVYI9vt/yAILpRQ1gsiK3uSBMS2LJVAUR50LPA0ycrolMKI39P1L1jveO+PLXkbcSLIaHUBkVXalk34VM+mAa43bQN6XNOMzWEbVMw1qbA8v3kP8PNw4sNTNPhKie4TLbSCdazZStngL1etzPvthxQgwYjsWtmySrjIkEzxZQO3Dl+FGzokggUhLWd7S91a7HHs7CLPXM1xWGBSi4mApUwebCfQKlS/kvjdQxUW8wV7wtqMqTiZlev1ubNqAzS+dKa9nzIp57hjS5L2uCnD3J4Q9mNNMNWW6nzJBm8i5TvnuUwLLrT8oOD+2wAWneO7Stgn7nUCTU4mgkhPBOexBhWQ4hRjmYI3P7RPuei/g9uOKywYEDV0Ogf0jtrQjtpOlOkIVXlBSmjirvUR+u8WNLExDFCRbjA5w79my9WrhrYVG3FkjA8S0x35dseLDLnTcJRmMLQndf44P2/YE2bRNqxzM8NyR8T0x4qYRxKcaKXlZDXQNBkNGo2ru+cOr+QmrlXCf/XYFC2HsqaW9C6+dTwXaOFCrngIboajQWwpRDsGxfcZEeslEgEviWSAtFT8Kz8MVtgkDdxjuJL+0fPH/q9DSVN4P8cM8WNjd/D4+obp+wNJMUUI1kUaSMhDt9Vb5qRh7o9tJatSyTsyBO7ifC/fOGC3kYdmQswPa5ShrJQiE/defu/EYfwD5OJX44huyEvsN0IcgRxD7eKT9Sa3QzbuNCbt2toAkAP8bBnLFUFU0Fz1IHw12cHQKuE5Ig2MuMwTig37g3+A2NqaNN3UCJq2i9u9+3smU/oMVLcaiUB8nG3cfk9j/Oh1CpjSdsMt4VAycP2OsSkHU+nS2lUMedVGX0UjgdZF9KNYQRjSLcvsrP771kw1pXPTANhlLL7e/aV7hpQJESTZTeEY4tmzPHL3h/zyg6ncMcylzGrj57b2qmsqaq/uozwx5uyL4IdOkp+fKbAUORCPoaKU8YOlEYjvUa2ykYPK6anXM0rN3Dy1J4mpWRSQG3VhGmUaNE+8qsMCHbcwJv5cFglRjovTIM7Ar3H8uCpYyak8KGngPaxaRIzq33zJgPzfEG97E0cmYxjgNDTPnqvWRrI896Lr6sleyKwe5O5Ms9ktYmzjH9rQluQXDSEXDKD3KIhCnF5P1MhPf8l88lSIZr+VUHH9pqMRzNyc4w/jMhYZHd+YrUlEwuMUeuw8a/rXPXnUuQTo1x5/29SMPSz518QrOdAPCatMzoLURCiGNFHUtL5f7TlA+6kZX7OxApceIJaMPO3/+LcCrocCmpRSE/4vXaFwsoZUVkshgprS/4Rgl3ClEcvBHDKuQOD2TjvPpDSmdT1Gmeug5G6INdLd4gs9VrPgHsy+sNNkNF5EtAzfI1qZ+AQ0atmiR9q1shJ5JR4QQO2ZbHJNi3gQIEyTfDi4h20AIqSU0v1+5Y4XhnqbhLT/+YqTFgKI0LaCBY9thlUSlXtLA7JdkG2d3WJT8lxckxcG4yJ+wcrMBrTRZVFhgmUuJYvJUQ3hhmXXeJR3bYq8YrufTQcaB02ftm3ndeMEzCoesl7fZSpuWYh31L4r95jax7MbqJOEiBWyq37XAg15dArBw7oyjiT6iAHXsx9fGcskP0HvFBK4DmaMCGFyV4vJFY2UkGEydrL0xJtuZOepSCeJ+WBg7T4vm9KlsLNS7t1DMethIE9pw+Ui/J/FszRe2PEeFjHBuNaX5YsL7qDIFe5UDPSiCTCQzY5GAnTJnG2BvL57YTxu4Op/tOZTqUzp8fi/RoLGJliX+csYLK9RRDyhyKx8f8Nr0UEcLRQsIewJW0g/G6I/RFK7RFiwfpBlbQxixR67cy7FZDXjxc9JmQ6eiNQxHFUtDXO2tQf7adoSlxy3591Jf2UexGipxoOSrhAW4xb1cqEi8HCxNm8CDEaIod98AR+B29gLYcM6cUkN0HXKyzkrUM0OTorioFPqMU5uSOrKCEy2SgrGWbQsv1odFsM6FBJP9oWWW6TEUQf3+j5VOIfhPa4U+a3MQnGb+95VIm/IcB6Vz4AzTBrX2YnaK0biNvFodWlko0fhlgOI0UijtzOV7WGKipo1w2zvmhSXPuVjJles6e7e12IOZ/2GzfGLRbL2fG2n2RXcbVyh0mzMBELTlXd3fqPsjGWG2aBqYu8oSczubcNQm1TJHh/WmIkV8HmvVEQcwRV0Ddo35FlqUn9GbJz0tQ40NztxbKe+NF/L6dq5TOspV53zG3+1ZRtf1aw6TlgI5KZGlrxU2Be5beFJHygrL8paydf9OK9yHfPOf5j0WSIbnWUAT6PH4iRCBuaiOe7VByoG2xb+8dCqiHKhKTCr/qj0X6JLBfNpjq8ZHLtSqKPhoD85Tyw1GR99YrRMT6z8NcpfLa5plWs/8LHf1g0VdCIsdAMRqL7Z7wOd2gbG3Et050g2V1JRULm/VSKTb15T+M9F8JBBb9Wlgwn+eSoMz8O37DLTAgsxxqVwX8zqF1hotTdi1jah59oH7puHnQGp0ZxhTX59xxuawyicCqOnwksZquO5jF8fWWLfY2BrjPL7Dv0DxnKDPmNuCR5QuY/cvayvUH0H7dobGFwIJzWdvrsT4T08p0uE8gaks8sO0jjh0fdkFGNqcz+ML85PKytjkr0dTuHzw5Vmcw8fjDiOik22y2DkXmbZ1euL+OSHUHDp4axu7RY0F8adxmXj0Ma9juGDKqApNYlVURwkF8W32KXdMae/duJ968XxbxQDAzJinFZA2xhJx61+tb3Bsvjs/CRwwZuvgDplZmHT4+XvqjCzLR36Ab2xyOkeqRVCYQIsO8vqgE0aK/nr13Ck36SLixUL4oO5nN2aZi9RJ56rYgucpVP0t1lmkfVbxXFRnKFM5cXBH07jHUpazL1CfXlf+iXBfk5asjbn2YMkEuo2K/ueeCHHbgX6VQOsaiF/hd8F7yuezgculoYDmdyGJGu4YS8X0NGzlX7zfh2Qpz1BfUcJzIZHus+pW21LE8Oka7ZRA4MbI7cLts9mo2kcMp9JNtLCuKl6YBQVMDfSLBS7u1pIub6n/CQNqJc+IOKlZFS5E1ld+sh1qYRFDdhVXIG/tx0KmdTh1ZfaR0wkb0ugHJ/S/i/LWw8bNfZ4tXepse1hdiFnGR7bDqvNDrgoytbiDEGuEPECo5B2uX1d7vbKMeFsdv1UXsgc9fv2nhT+rcQ6qHHiANxhWMogb/SQcq2Oh841T3dE23b5VLqSIaG9Qe1rPJFyU5XNCQNq3KOyeer6F7ixVyVd/QxJjXCZY6mP1IzQAI/Pg/WJG1eZdEBmvbao5OKya/ZDtKOM3XMaALWhU6Yz4iD6TaOsTAfRlMv0Sh2b0t33RQSm3Zjkslu/ODUrBdvn5QyouFMEfCZ6XKF9W/qH4+X7JxKM9Q5TtyKuOozHFV8LBLXQtKdHcfm0yFHrGOGq7IAx7NgpJSO+unBgxRLWuTbEKiEoeUSoQSR5kFsXm7JbLUpab5f5v3l7GvxqeMweD7IPiFkuvy9f90P+0cBTIcut5ZobeTI1FmsNlhp/w9gMGu/y3haXP+8rX1kdGjFnYkvmL1t0UuJB32RExdcGUiX1HaQwde7RCND/Psoru30s371iDpXuDJjU2/laj29kfeW/yRwJgl1nAhbdAExcA80LXXLyESw2w3Zi6cC7TaqG+5eppnk6mbJ8p9BAl+Z4qmfG41YQ2V/1Q/nGZdL3xGm6+Ucg9Ix0a+HyLBcGx2pYCxPy1AFTxMbcBbcTGi/nfkn1oOyfxhMEe5I1UekikYo5LuIX30nDgMBs4Ptig1+TYJr5+jYW9lMsZZ8Spleh+jaAu0Mx0LIkOc5XwLVM+odZJOsIVxHsSvesi7I9j7B8ICXhPC1/rf5F3vs8fKtUxYB3q0ecoSnBIU0xFJgN4LUWea29RPeah3JTKqfC9md3/nWNZRlKDxrdz1hBe3dUMkWzTU/9Q8Jq4oyCKmaH0NzFaHhDKYAQTB1Asae/JoM9jahyZJbG86As3yWs46IgOv0o3dD6+YU51T4EBoZ/jWWCG0f+TLDwEa55wBO4mmB4r/iUGzyIa2NUzFOlpEOuszasxreneiOC9DpTGFkgNXydgEMuYiddZHCt3H8VqrIxMagoOxoVz6xHnG2Pg66tKRKwDNdoap14veEGi9XnYmUntw/YDqPar8ZA2TXSWKKCBUOORWgyZGy6cBySQctC2LdhvP48rXfn/Wj3TzEJJb3hOlY68rkVsxLc98y2nqtFISOB+CelAOlbdxJ4+EA11msjlL/JjJYbQ/PMeLHRNQL5CPDky57ePs8grsMZY60Kxtc37uq72xzMH/WwsnqAHK7PyuLNGfhS4GmSCJXiRu/cNAmpRSXlVvvehsHBo9++UhWHUohaZSOh/IlMGmxoTbiS0YLdMg9vQ9NKLr2Ytf2C4A26RXZnJmhRy9OG5X55hXQjx4KqqNKi6DDh6pPCFDdgsPsLSW2PlMcCqVldCh3ysB/fObuNFmf5z8dxW9jMPJGu1YGGF09kH5DV2SKaHkoTiofxug2H9ePN3Shl3DiDCTtivIb+F7dcVSjqECviPrQJ/hFmgYaDk/dS58WJ2osB9T/7DhYjpIGntcssbuPZH2r7Z4jFkAdiLM69hSQ+R2pYlGpTI4MQ5KK9CHPOstNDz5x2h1lWCDX2dw6vHl0Mk8mqimqnNKbG8oIfBMPbft/OkvXQ6UjINkcpHQ43ACtZbqc893CDLRtLL/PeljfeLvhl5hx+extOfSyduZdIMJHfkrpnXc6En7iGancq0DULkH1cbcyMUEu2KK0lp6gsgPzNt9GWZJZbVDCyjtDKoGm4j/L8SL2X+d4ZQbDr87wLPQyu6+vT8fDzIaTRyvSpOZmP4znGHq2SCCILI0J4Ed3tZvuxemutT/JXckUDnjIMVXVpje8IEaLLbqgcD7qyBOWucZOnaVPEZ/7/ZUprtrgCzlde83iZnMWIrmubBefUP/B3TBk3QxZomQjLjRH1BVMMPlKc+QQhv04s0BI5nqp8k4neSMyAYzmfd9X+2yhCrYEOfw3Ddodesogma6+MRa2rX6Is4KeDFlpH3ot/6vLqaDQoDZdQjGghtH/I9Afj/WgdS9TNXF2Sx5a7a1cOfbausp8fWnHSjAsvGKZVsk3E7IUiKmMUHUd4O95yFwYBDeiz5Yf3MEm7Wlo+NQuohFmwgnZgk0+xDntu5zD4hlsb43DFqaZr5LO3S/jF8ak0By17qOJsmTcKrKDHfmDtZMpfKilXJDYiOyqin1C9AQBTyWcS9Xu0BYzS1sk3qZUaRY6BuHuNCi3spKRZlp0X+nB4Esz35MZFa5gNn4eK1Tq33RBAvk4Of0ABbTPQzVLYKP0V6sP//GY2QnbHnR1TI7sktZgpEH9fYkhYQSQrn//yyfsAC0SL98v/6Y2Mm6BjtLY1lmCWf2HVCBhECi0iD2uWN3AABPpZnIY26RMVUKbk5crVUIlnuoTE/r5tnfyqp0qe0tN6xYugUYV3+e4haQTJ6HL5dzss7nrVDPgdNOoKg7wI0F1WtcMYW/Db/GxS4EgncHC9332zvCURWWauLJ2HSHKJjdqoE7aLZ04fKgw5Gl5AaU+pH1NvIii5ZWfjObYWxf6Z/MSVWNvvCsFLZvf1s87ZdRMf3yb3W/TWo0tgTjv5Y3Mt8CexkJD7fJZZO1FcgV95mydNv4KziI3frKKFbodVpWy8QwufKkIVmW0YTyLsOfi/WQUHcdxw6gpWI1GfqWlU4oraPhi7sMgdOM0iG11zLNHonH/p1Yy00A/B/mi+VATq8P3QoJ6nKqr0Nn/cprqGSGeGOq9Tnjq4Rgi8t6ahlKBlusklm3vmIyzw7VjrzWNIpBUidJ15TTxkyIjaK/LZ+ATXI+XarDtVjd7hLuwaxi1pwU/lxi7beu3rwjifmhl+OadrRFNyJjyxiWqXaunvwb7sPyoCIQK3PWKuTGWa8oOX5cTB0gxN6gE5iBotKVEHVPvet2oLI762ph6t9VVQNq601C8dVEtLnfY39tLUzXhvsJ5GQuWA5QxYCyk+7DZS0m130En+NR0rXi9KMNvYbHb+rzwszgfX2Ndtc1vfqhqrCU3wkOZKna5dPY8/rmW9DUeMQ+uCjg7RhzncyaMNopDxiDQ3nSovzzCxN2IQyQAzBK/feC/w/AmfsPT/DaeETyN52tZenLXQOW1jrI5HSo1vPGFgjcVJP9L0GoSLo+ZiD3qEALXffTm9C5ZJYax7TUgwKOEiAPemPGOHp5cLLd/tWayaDAc0xtYD6CFQlfgGkAN89FhDBvy2IaKdRzMyX1Kqixl/UwN3Hx06AkKdezDTcrV4O7X4bc9SXqDoUOmzX1+ldc/6l8g1VH13DMpBA7PZrRPcsScdrONaLoxSAtwyALChFgjHyv26w+lNtNrIvIj3/TGGqa2uTbWnwvCgzDMbwdQGC+E/GJsOK3M5HMXXwk1anHjWS78dfon5s6VnevqBSMyLHkcn51VABrVOOamlLRyrit6GSIJs9QSJr7hmur+yGD7dTyMHWKiYvucgq+SP2aiEg91kfB3inwXr7mQAGs4M3hMsj5G9Bh3KpJopp8zmB/RzpipvQr5jDYlOtxYzFGLX0FisKOk2lZcQpXa33QJJGsMo5tkqaU9Sq4Vr1rKPruh75bRBpP1CQuwAEOB+9duXuZ/S5y88KqjuF2hcn4cOSlTVbRO4xxlGgRtEIYE5Ilsyj76h9/NfbaAcLYBX7E4sYe0fq5/6QpAuoOiCwiTINnDbxeqtpRxUAuECI6uYoRLSPgswiISmA2wwcfKM2BstgGn6bSH3evIuiHFOOCV7E5ZrcnP6r8irvxuAYMnSL1wAyflyfEoglj+AUpvG/YP0wUj/4HXluE1Dep3nflZqqjtZGlEKMnEjmJ/5o4rdggXZSdaLICdkPngEYttwdLfYV6miY7qu/maAOIWisZcM54Qzg53tXMiU8LruGORmBNwQiOJy0bekMEl8hu+EziBo9ViSKyC/xsSLKGeq9Y6pAxxYKBqTp4rjOttzTIrKDKRz1TaacCK97wpb+VjpwAnatkclL8I1atX7bI5ONilN+3pSjBYQ7qY1vaLHrFL4OEpuIlxs3ulCA2+YR6k0lWFcitBfElD9gf/lVwkV8SULwrV4eIwmWiXdKKfx6JJKky2Kd+YqjAuc8jERZk339psTOu98knxjBKw1Y0YX7B26GdQml/ZJ3eXQiG7gBalsYwNQUAk81SBqC5FArfVrFb/Q15CytsyNoZ5PCnzd0eqVk+IgmTiCl7JOK8eQrL5lIAor956bXkomA2o1UE1hQH0PDF3aUB1FM5VWx7KEITCGtxkketr90eeit8Hh3s8QtQNZ002qLzR8FeHMtRyI2cjtffLuMOeffI3zH7C3bfN8e2qR4O+GWI48hxnD0WXYLk4X3OJfmheNDiQgQ9SCCmyvWkPd0NR4NxVeer5QHUTYdDol2FMV6gu+t+/ia/N9QXpE/RCj48JSO0RE4zNbqOtAZxIS4D3KHPO4bfOn+L8z05nvJ6Y5oI9CO6chQDX/MsSxtz93lWci1LTiWM8loCeeUEGw6e3Lgawbw8NS4c4fAvRxQSGOTYT4ySJEzBep/5Gw3ggBSggMoJZZwSSzNqT+tQTAQSpWLyYGbJ33E+cVw+cn9ZPQwNTzG6X/m5GSDvGl9SlJj6zhQmJDhBR4xE9cH9BUhB8/Eq/l6+Wc68ypFLB0iPz2+0KVee+1+LVoHO6og6zrnaCaf60OF+jFhKXnER7Q/fXNlAZlP4KhC8tjGd7sEBHsOIjL1SXFtqFSuuqfHklH48vDq5vjPPw+Kwzbvc/Vzi3HfW9URDudhp67BA8UOc9ZJwgEMmP6sjYdgBD4AgUgasG8HrQpU/sF9iRe9EcYZfGpRr0YVcba11BmWPgeT/1D3Qua774u5Vph1VRMD5MhxlP5WA10WE71EMNojhF4D/us9U7ZkpEP2pyjNZaioQFl2nUq6TJk0HI125Nm8ha91JmVRADm4i6rfSeighGZGb3MniXqTQEzZarzXblII/G0Pf5elu4M7yHR68BicAgaJ8KH1wBbrloYpwmyUPHWyTlZbCxzejuMtXgTXVmeqSe1h6RYcEUvlPlA5bUxC38EBL3zq6m5m3PBze58l4ElAm89xzNQxL6e/s6MkgHc/uoUrF6m5l9+Mw/7JxxBtaHq7oc/3g/pVN+EIDy5YYH4fgC3SatUJO066EuJBZX5Rovq1Q9tK7lWokc523ArgvF1LRBriZbxL3tT8qR9OWLa/1poV6UooWDzSj1nNAb4zLRtx2E9LLrKPrbdr4BUrqyQ4WIYLqlOQz6uwYWI4Ef1tKJVNfPVNqlBIgMTuL0ABMJhZNww8fXmrDEr73gjb86BIpdNCJ+GsaNaq9eJMXNFehXjoJMQQ+Jr8rZfn0HTBXAPzzQynMM60QlzRL2O0DorQB1JdPJkPJXQf0IJVskDMhPNW0rlm3n9+l5+hfYgjhXMe/OzgjIQ3s8T7xRlZdvcgNjjnrrD5VXaKr4wr6TbGMMfEP77vKlVDhogJPGgVsxZlQgSdOccg+4Ip7Xdlygi5n9iiKhz2I+R3hDqQ5fAbkTJiUXAr+cjkEVAF4z3WMXsnq48GHNKLvulKFPw3uRsmB53E+eXOrSzOztKzo+Vk2h7FEbnutv/7tHWaxpVQgpOWaD+vY6QRtR7V42oEI/RNq6IqOOIFsUjZ8p5Vs282k/5nrZ9ekioYIIrX3LDOftzNRk4Q9oo3B/+yCswWwiXox41nCuNLj+EDrkuViU24B2tR1qfnWZRJI1PHlnrKSxuAoo4FkYWu1D24juuGINyOyrb9nuNgIM1QLv4RPThE3iPGsGZSPcM2B8o/m9TPVw28QVgrLKBT5ZPUxWIdmv/COj+GAPyoIWOHT/dLI6TVywu3Ipui+fh7DycaAL5WAzMHoRX+CZ9LPKCgyr64cN0qoWDoHl9ZpEGwmzwDce9gPFHY+IRBqx49XTLUjj/JqrQLQwSOchdXFm36ojn3nVk73fNWooYsTrsvG0e+IbVOSEPbEzQAV535QryMsz9hqv3U77fn2yDfdsfrA1zXyvKpMmuM0XUIOVDR5/mrx3PDAGmuj6lqKjk29XQJ5YXOmBnk82trh4NP1xvqrVccS9pk04Sg8yBI0MrrfFHbvnZh6a4tQotsr25bb2eXw/k7iVrWzNzWW9hrAnwuWjCgx16BamtmA6LG0//emYAp8OYBxiYnHfFqOsDx0ulS79QrEogLCWqNsncG9GBGesV9VwnhVfkjOUpkf2J/4vEjFG8KMLyz8dKyuMgeNotzt7HetiHr+Z8Lf0lAjv6ITkagdZO6IkwO7Bd8rOeJx/QOFc0grASTeEErOrfe3AxWQCL9VsVYokpAyEURQb+oGAOplqQ8ZsJkKgNFBWzujO7YhYNfLxvF1Hi3Cta/uKL+mQQMSVeGjBbZNqlix5CdV+cebc0hnnPwJBin6tMPQlavqzfom8Xy1w5ECPfZnfJZq8D/GCNEpYrHJ7Ld+n2LvkrjV61XfykiCH21Uv6n8IV26XR9eY4Sc86OeEzJUS4tBD2hIMzjlUQBuD8TL85SMTd0mDIjz2BOQR3GdOmW4TrRxN1RGvd2A59wJVS2kQvji7siWOsmWjJxXmhy9ywsad9RmNFaDgxhpHy+0CFjP4aHxgrZ2+0v38hG7EyJuPxqyAYJUE7B+mWFMobV19FzSs1Jf1BozyumVGmHrnL7SOoa8ypnBxkR/XxffKITreJ5QduUqWsdi1J2B7TfSOuEHF/NcMrEewWnKQwxDmddjQSUEW9bVPYyzlYwYM3Ql2etlB/S+FQYQfjGUdseU363BsIw+RXj6QUD5vd+RgOPY0wxl/UyH+fEZ2W26qHjTdZ+x5QGCiIDwgdVce84vy5yn4jCDRBqkiiYxC4+ysp86FNVdrbfbQEUhJW8jSzEDzaSLyjKERDfIKbocWaR5yPDWG/sImXBZZmyBVuW5NIFXV7u/UY7Ab3dkgxP5NhQE8C5pIvwqZ5CB86Y+lKKYpYa8T5QCafgpf9rdOFA+LaV4WYycnY7M20WYkJlm/snziDal5klB7+V7BJLbvfZZyC/trjzL4mY9GseYvD/siesz+vr1kH06sVG7Tq6pvdms2u5vemTM2WZJ+iGDuGDvgqPHzRiLLLmWi9fxMz8r3wyFUarf2GAawft1tekkz5HjLgpR53kW57jwMEitYxu+9ToP8L6MFIr9pS6fmc48PVeI4e8C1aq0YcENgtbWMqqtV0/onBGJddYy5t8uBmK0lHZ7Yr/KD1W6Xx/8MGzX1F9pNKq/T73MyzRbwuwq610Brsb34WEirrRvITq4JJnb2I+R3DQghT+wNOEQ3dTbEQbjxYAjit3aZ5lgfap7FmWHI9xdzCwn1EuhsnEhctJZp58t1pK7MCPUVOjdn/mNcLmaW5D++BbLkYMUkcJFfH86FNDFrQ9kEms+tG9UaE1UpG8wL1qehWeoInEEG+wd8MyfRr1LY93oGa7JWhM9SCGm2HjTSQo7IAJwSe6PtbPbsOAFFWnlWVMLQQt34qxMj+kwah9MCzI2qzZfRHhCgjIkfFw1lDNFbkz1uihA0bfyxXazwnxwGAg82q4AStABB0G08aZV6rG9tzKD4eH7kzwTwKwjb3+ttSpyEpS7kpkSSQUx11ov3efcJMOCkCoPO8xu8SH897lkdAMw1yfmOowAO669ed9XwopXZY2v3361qmp+8yewqh4jpGMPK9Lgnv+mfWAzEBT/UVoARfj7TUQj0kIJESCCu2g2HQz7dQzf7EunDXYwT/sgOzuofhLba+OoIq2lulvLboA4nsqKh0AHefsnLLIuLRDZNmlbyCULDpEq3dFsnk0tsZJXSo96xMn0t5Meko6CQhi+kl26zXEOsGuYOy/tEXDsSixMm4f7JGVTSC8hlnNdXFzzh2aEWOPmpHdrdvbay+13wbogMjY6iQR6PdpRXT75gZFtsdhdRd6zzYmMs+BMvh+W1V1nl7jbCWNIxlzFS2zlk72XyVuH8h3q2GaltuYi4r5ol6v5Cq+msLzUERFvQfz7E2JnTZdcsmGTmLlOrJACqd1l875hs9kcahTyhKukhJj14MlVxP4qqQVb8iXqDOvHwoNFQU83SLrffcDdTOwscxIY+aVRTKVzg+rxZ2rJbT/0QhMswbsFfSCDpptYdq6MthR1lzb7hx1oVRCuhvlmzVr0d0audIBs2zFohokYuHsfaUXvCnGcqUconsKVAJEQcT2mD2D9ZY7SG9viaCmfa/A4heEod8cMal5lfk1dBo4hXSSAY4ucVoJ5BFAyYf0eoE+FjQ+1KjB8iUPAJilZovT58IEOQbtXRQxTwcTroCPnZxuZp9ZbGPceUk5Xj5LZvPaQoZCMug7U2q1Wa496s7nFuTYJT+LnOWXO4DmYO+7YNOGCTed7PfPY3k5QKnAvdZHmRx71wYO5IS32DhwFxbh3DAc+pf4M2UoZVVMF6P3s+okFVBIxNXPdaCLGKtuZq33I4hfIWSa7GtP8AlbTqe+3CdT+CzRbO5+JIXe/m3eXZ3icUzNLGnNzav79OQvipB36zBbylvpCYnUtJ6sCO9e2rxHVJ692ONQgPfm+df/FwSplY/UJGqmQtpVGga3eGC+fnYdYejbKHwliUmMuDOq6tAo0IGHmhY8ChFsXGbdtdjv07eI1XDb7ZBow2SAoyAPf9xvIEcff/sHBSNRVIHMM/KbWZWK3haEYKZeeXHNMedxFnG6JzgClF99PdaAmTWi5KRK/lEUxGHCBgfbLnz8ijpeirFK1LxEYqlbpf1aYLuFufpIHqqYMP0kBAD5v9VGsN6kt6OTNLrXvRyqqaMxv4cmJ8XeX2rZ4krzXGA26POTz2HVMbsXS1Cbc/zA7EP0YoQ7rT6Vf+WLbuY6TCwzVltFaYFymPlEHsoC/HcPiPa48v/xEFRjz1cfn97qq3PsXs7vvWecG04dafrXN6c3Ibv1iVM9RNJVAcjKHW9Ul/GoNXz73tYU0riDEQuKZmnIPNl5bHYgc9rSlhNi77w8bqYHdwRuh0jb8EASznsYzY7aDv3TWGFF7XhgvRquxNNNos+is6rV0SkUcaXJgQEPFnsw8/R4QR03ylVnKF2e2DWuaaSd5EGLIEjytH+75w3Nw8zeg09gtTkcUNCngpzJhtZUO0ZUbAFAwfx42tpW8SAxeiF0mfIbGX4Yl10Qc4hb9naofgKv8AmlRx/qU4/5bHtMe5G9OOwyt1eP+6oznNhljJz7HqsTVYz1uRJ/FF3aMT5wuBIrVaSMznFF4lRD1lBQH/YrvL9oIwBdetkXvgR43YxUg6n+t/C0XW6QfC8A/FEg1poSnNZKy/O6apfCsG9m7rvHHwtrYj6wK8qpCNs40rTsQEbS+pzyENgZIKmmar1EL/ylHjd2CLFGmGXFLRARDMoz3/kE7M74P3mEt+vpyekM9dxQ2CD2cfmta33rEfBApzCOJwTshDFy4m3ZZwxKzk9wWuOLnUFukuwFlrAiKnhKeEQBiWKhNuQTdpfPo16Ar/a60zJvhTVZni9uqsovkj4aqbO8HXnxs6LJLtI+goCtbWWngg5SL5sSimVV9XBxfcE4lrdtATCm0SmRiFh4wMkXKEjeoTSGaMNBIrIzAAAEXrYuU612h6pyH9oCP7ocFKf0vIRR7DdaTbmW0ujZ+td5X6OizYd/TjOB0EZ3oSOmWIRrAhvK3ys/bmU5Z6yUm7cHi/5IG9UgJ73su5LiGd0bEaELozBsy7Jqr5EC+BysSUR8co5ajkhSpfAJKerkPe2uJ2dE7RlGpswAmA6o9ylAWGbgC2YfamX0lxi1ryybkW3CLb6FO51SOogOHVNLa9FID4/lUCIZV8D6RigolgF9s6O0hRwXF1bEM7/OGa5VnxkkC2VJfudqvg01Mr7qOoOx8/SvEo12xMMhOW26ZW9rcgnZELPLwzBeUC1pmpF2T4vELHC5f1EWdIr6Wy6gcl7Vjvb6FLzsMwEH+yLmSGzBRLm+V/Vg7DiGBGB/mRdQPR8j04R1fa80nXfSOByD0NuJpcUBBbpOAnruyuvrKmx2N65Y6ojJQTJk+SFBc+XqgTVayZ4Ln9JSUgGJkpQ2Y5Q/L8IVJP9ThINxL3eDg15tVq7HLoBnuwZ/JsEc4G1iI3aCkTCX4RUG0oCAAtMXdJ1i+vwP2AvrmUVkBjGeu86xAUoxfUyqrnGgmfA1ka/IuaWrCzoyO+9KJCRsug5ngo0W6gJiniTkkqE6R5FdtA+LRmPUPN/TpvZbFDOQNoo3vHC6OhCUTw9gaTuXEAAdi3bpXBG8wgpMOdcUJMBsjpiPlUjJYwOsANe5HwT6F6Y/5DXYX5HDYgR5rc3jy+nYuxBwmq+ic1WJUHMMt0omcwCz7IDy1WVeuwo801O5kW8NQShrdcDrwpkdnrRTheF/6g825xuAnnyNPUZiosd9eXOf32k2MWF8AIh9Y9xjyy3Yx4yNyDQMEBbI11h4KIKpBqYeSkeQCfJeUcUncTCHVTQ0893cyCyqDaZWtoICflrnmtk/9QGvyKO4/tI6d4tFnUAyNOWBKVNHN7bvPk1gYxd2xiCPVHxRAdfzGpcauI0FlDyX/txqhaANKHerky+7GLr8o3+bakF59KGfk0tHpI5/7XnnsZv3M6u4XR9GYb15IesoXnTQ7ke81HCFUAB3jSihMTfKxawV4OcUj8pknrlctOAPus8fEjB4q+JJ8fteaJmfroTvu9wmlJ3Lx4pzVGl/wqGPCrBdYULGAmMnybINZRgNGg95tv/oBlfrtzcXFuWlw4vE30VipF//tgkZam0SBJVlG2AX5cAwtK/YoWOA4rbuO4EbB61DsW8FKXQjYrB41S9XHadmYXz523fFvo8pZQgeliZZHhqgj7dinqJ96Ci6HqE/GlMmavRfhm0MmmDMHAs/t3IMV/+frRkj6BeQWcQjVb1lCrpUmtWwStvfedEUMxlVLe9Zelu6jNjdcUCp6bwTbJ0BBBPMk7b4wrTX+Mei4+2JvHf6E5kchYBYhB94GJdMDQZ96zQE78L3l+oZGImu1LaEULqDXC5c0TZv4z3egMWL45VsRW255yT+POIrZhjavD3h6JMOuwr/a/htfwiSruYaer2u8Rbre26FICZgrkb1JulyLSc+DBxDi9bX3SyL/TS/y2HDSpCWtU2Zjr+XkU28z7t1EuoqORhfFVzXjnh9JvUMq9UVGXKF/vcCKy0Bbro0Zxd9GHO9SVJ5HzVH1+lONG2Q5ERaWHvoKzROCOoO+6oktsLgjkHW+gxyW3gjGY5KZA0qwCzDOycenQHSWAsYGpR07vGZp0LhtAoAtXc5Zm7nVyw4H6AnpI84be+6Ees2tfb7fcla3YkL+iBkNuW4n09CqOUPU9xr/m6/JGV6Tr8RD3V/mfFHl5GnL6VFdZGeNUtl1upOH+VqgXd3MyZc1VpXXWRY959bSNEoZR3bsM0ScLIP18YnWfCUiz2ghn1RqBXbpfcYnX1rwQqz9WJ2FqMBqhOyKWyQZo7P3zEyn7tJmAuNtrITHbTxTFSKXOocqmUzO9EFh3pDN0qq5NSaS9cIgclvYLLplXhrgXjdIm4ems9GAtjx7/RrAAK9/a59pft2Ji7pGDfLOo5dBic8T66Ilwwi9Ggyab7JfPc4ArEIhP0PrG/o4DmUeeUWv8B9ZhAUEtLo2sWV3Stkdr6qHpZhHnMQEKNWzI01HbLeSesG4n7d1hKhOCBNxxfXKRCvNcHCVpWQX1C0iqThJDsDqBaUNlua5et0jPlFC5LDEu/2qyYCuKFwvEhr+siUHcvgQkDkK74pK/zvUfe5cVLV2QPdyt6aTwVqX8D40HKvFuW6rwnHbpCbQjmmLaQ7vwq57L986BB2e+8CaVmgyXtu8Ahkuu2RwfNdUwGQltvDXUQA8FG8+Hikw0H/dBsxV0WjUrXOZIPMf31hUXe3YVDjO8a1XGsOfHyqY+YIDMHlKs4vL7/LVZQdypP0vrrCdwrT4v/Z3TYPjcrOkJwFEFCzEXFhgRX8udI/DaQmvs2CzkBnRiv5v8LB8wbupVk9dJkzAmAnVMi4o18jFcQqPyw/NOwuNglik2SbZpPp1Cn53sIxmVOjRynAx7ws6+ELRAcxnnXXSW3XSjHoD9TkOtLoPXHce31pC9QPPa0sOa+HOBuvqgb8+wptYM2VCZpIqANhgzx7xoTKl61KCWZgv9MHAJUTFfDgO3UGbODf0IasKIbWyt+H3qgkzOfYGqSnfG4l1Hoj07Xro/VfBxVol7dFuXPeEP9Ygblu8VvVH8wwRtKVqwW9U8I0wxty7qkQGRunnyhVCZWMmF4ro3Rd6qvOqoxOnTQOQxb/KSaLwaVIfiSlYo0HK7BO3JP/YL86pNRZWfPZzED3LDrwpZIoEEtPpvGO9wgnV5yqhFPk8MtEIcHR6HffFDJpPpqZ1PPaBT8wbnPyuNSPRcZXBJMEJYRpAuFcKtE43AWFdnU8eNCloXRrJGARTPvXNvUnJrccSOU5KVBQJvpYvyPaRdET16tUIsWLrWi+B0PiSrivNF8rQx0A0bXNLZ9jeHzTsuyXQVHU06BBEZOKTpFHH5H/bf71yvlU1ekKxR53F2rTRIcV+JLVVz5u2GG6L43PvRS8ZNisvXE13jfDifknFwoqydppZn3S4AjSFhbicZgPy9/Gxnl66Q1yyc5vjF2bGuH0pem3C0pYqB5SlICHW947p4RCD7T//JL3YDvs97BTcpZymEjjWSFq1FWmQGdBngt2x6CEr5gxI0mDVhDr8PQsZWp/P+kUGvyqOl8cYa6eCboJ//dWp+xiUgbFG35PAEpt5++EYZhnRgorGqgbkBEUETW0tteOVt9OUBpfGkFMoc5piNo/K5Oc+5iFHsLP3WbvPEt9kP3yAkolqXxZgUBc3mV53uTPA6dtrVZpJcGhO1JqrjjwQaPJg33njKgjruLxPMofyGphJ09j5zVPJOFyOAQjHtLdXK/CzB2itOilHfIN3sPt4JDrXtAcIo1mA9pxmPxGx2puuDbqb4Pkdz7inUvSHIQqv7im5IsFEgDSUVJHLzFvVXcQFMaIxHesW2gmgiwNo9v+JmJvZsleNOnQi2PrvURXzpAM0xF71kk04HuzvK8cz6CUstNbnXy+teGPkTOegwFpqtOkk7hyuiCKwWhQyM5zrCxA1Fa7RovmJfBuaLvuUagy65n19bHhzClFdJaB/UYvzujTs3TH5XKZxyGXVu0VE32JtCXxSAF1PR3BNfwSvh3/2Yjn2huvg5c3S1y88mIzwlRi6Kq3G7IdYHz4V6J4h7o6+PgHMK81jf+bAnTMUII8R7M47a39ugsMMvnRY+QRHoJ9EhqKjsQdAtbn4eMhwAiu1eT4DQfF7Gr5FqCPFvGmpiGHZjLNLxPOd4hhpMJj1u0CNqIOhchVVJ7su4JO5WVmiuBF3T+tD916WnJNVQgrh9RYgNP9GpIGvMfsPZW/7cCGJ7eW+l5jZ84SjIMwK9+sat1+MKwikFVPyICbPICTgOY6XuKidp/q8CJYrGroMyUQ67fFgEeHVWjxlPt+a8SECkcw6bSQ07UFs/qLOcq0yblxdc6gC/ppOWvniW9s4IJGweMwfvg1gdYflgGdf3tyG7lDeHZ/PHsyHIbevvQchOp8oO34sfYUbQbLnw184l/CG6Ok5Fqo+536Hpn9wrumEwjJUgEYw9SJLrcwmwrZsm5eMKQdtuSpQLt8HF3qrd4f6LnNyu7FkA+Ta9TWqWDqyAlBdwveZtZ7EEiXGseYIIrd/RucTflgQRn61f5I5HRzbFr9gFZmELnJ1fJ4PzDFFQf0/tZp+D9I533pHvcm6P7Zn6v+8kqPoV7Js5wWyye4wRtgorPt1xlMN6vH9q1sa71Hcq/wj1F/ss4JuMZ9dbcuigTHjVC/H1EhMAZ4T+52ljcu1/r5x/6bMEZ6jLns4/x7wV4IDQcktIHXumFxleW6yvVXBTce9x1HCzysELoaM6zgcHoqbkO9jQyFwhD39vOn8q+DkO9FUxKY4gBiDnm7ybuIsW4wig2UeAiMHweyyVB53AcdKz9fVFQ/sv0rPHTJtV2+EbEBGh9lAQa95kSD+WHl3kek4G+2a0QPGp2Y9jBL/3i6WdGrvKH3ikb+DtQQy49bnWPUlsd7rUzM6YsYCxTVOQAKHCVS4OHrprK1RUABHJ0M4zUkCu9MMakr0jqBCytnsN+dNNIRohwFfaXM/LyUyffDhv+Ff2taGwdXR6WnQXwHvW5eyXbUzzPZZPzao4AQ/wGDJnY+PrTCYx6unK3VrD5BPmBYAi87DYkykSgFfUkOzdnDqHh5OKR6xqHtWRcWzTek4g3tYM77BX2Ci0vc3Qkh/Hk+SOu7ez2V8VEi6Ku23hyrw9nSaN9rXrRliMFmaMy4zFydHwSczxTOk9OTEXyze5xSwSM9pP1cR5ZwOxMZ5xXHsELj3yipUqAR4qlY4EP3HOcbgRR9F02TSRvE7RfNGQv3lRxheKkODET1G8R2DhW/GZAieTlBr+87BPLebnd+BfHu2KBlT9iubNyCu08lYzYZqMvaSgdeFo9QRSLoDwAFBe5SrpTTpBpWGesSKvF0Z008MWFpesanP/xY5EmoWg9omQpVVYpc9COlIUeKRdIfY25/78aFAtDvGCJfBAOurnNZKSipKXxfiQKZaLBnZg4TYrtaFH//05FwoGasNUOKtHszSs7ppQzgYTwENvflGUTkqRbwRoRKo4kSkoRJytyywE8BK8TA/XB0m8S1AxPE6BruB7JmJDHmtXJm/DTCVXsUZEgCdGaZAtHhbSiiahnl/JrDK7yNbn0zIytxmQ5kcCb/2a6IE/kX1cS1j3TjH5GGN16QatyAbGTAX0a0vNzXvpE1kL40wJDilYmGTyX+diX44upzSnezUV575csp6DsxsukwwoRbVXOUclo4421dmJpYNRLhv4BbA9+u7c6zOM9ZSmJvFMGkqIqfVDnd9dhkSZ8doKSv9I3J8koKTMt1qfBPDX8YreMYVi40aGlsEcjNLgoSLr/M6Rphkw0EQrLuIN09K1jeMn79cGorsG4TrlQ+yiAvzqYzCLCJXdwcRvnbquoQ7RYoyzNye1UAMKwLZ2YTeem+g7DQNkqRQFPun6PG6iawYbockQJg9r5r0T8LgRNZeIxhwTkMbVFYHQ47nKzUrgqn0eKu3TLKAaDRvJWeeIuPTz9WFynTLAfrPPynXjh6HyG6uUs4SbSMMyflWXNh9sSu2z8kw5QduzC5MIIHux5FvriJUd0lbVMSfNKde4synDZCi5TIeo5F5XeI+H/igvMR+mYbGIVgJGqssJ5jmN/GMobOaV4PpjkYMMoSYAWG70Yt0DNsWc91C0jz7uj9ZwwGRJ+FwPnOzDVnv243sFYLxcrIh6hFpR2ez/ddwn+O+KnnsTbssCXYL3g4M6idzxG11qtXK0ReH6H40gbjxTs7kc6h/0prhgklK+OJOXy5ueObZJixb6auHnrucwyoRlvYMK37T2aLwXKJ1SUh+8FtzW4bwS5YHFXno6tx+nQBWC/pFZGyMR8LoifRb1TFNkmLgJc732/FNip/14vt/QpsBU6h0e1TMFG9W1KDRA/8TK79Pn7Gxx65eTlLUo0PL/KVYCJ6Lc3dQSpBmf+Y2DZCQ/WhERwqOviCO/pLkkDjaDxmJ89t5mvGV7qD9xjBaorXdXiBJ8aLfV90WIX4XQ3c5jbkywJWNuCTPZL19ComuPlogYSfrkKqUtFtHwjRTj8E98csKBzm7MA69JPFNvHnKk9UvMoC+8fXujuJBcDmBNK4wEifTDwPy+GBJailszEbuzElnw8jrEbdsJYkKT4zlLgszjfWrPr2XLRy3dyR4TkEz5jRyl+TsWICqzSEjRULpOWGtsVa3ZL2gKRrgCDjegUdGQG7q4xlAsk1fKr0naEPcuWzL/cl8DZoRGzw4wVoMYkRIob5tyzjhPhI9A2LEwl2A59KcsrPBPOt1ZtXH96pcBqQrtFa07GbK1IVSGpJbjaHVDHVw2xP16l9qviUTmU1UoEgHorSoayL/lFrPrCSHM3ZwajPlpRCGz5/sARLjAD4wiOEFKHQpzE23yhNICne6HRq1t2LsGwUMmIkbn5lkUo/utr6eG13/lqmLd9UY8zWp4Lo7w8NKd0LACbfVuN7erQhx5BLlIvGaLp0uw+ULT1Xztja+P5tGkmtCqQgQ8BpuLBRuoGk3ir7mRZrUAfMO7fpYKCK5Gz387p6Us/LSGIEXvysD9L1iygT/c1gd4cK3aaMQQJJyctiPL1dCsQV7uRTsnG6nsnfzzn7CBE6E2HBn988JFbTpa/7V5OQMgxPtdhYXD3tcmhRxbnQ5dXYEQ3wj7G4LWYs4sq8rgWIz+X/+PhCi2ae3gbEmZvFCY67srXoCCXpzLB9p/txaqy10a3zi7ccCcUgjryTDxxAQHDWHR8SeD9aecXovYp7dKO6YDHQcd/TjXNu5cKaz/RysnnL2+MfFB6g8FJQtOpUgg/wbxJd8HpihKxPa3iEnXtZ1hZ7Rr+4JujlztajNaou/ymYV0gcCgfFs3eROecDG3NhWf4g6SIKHDcJrXVcSW3oveOhbDCRq0si8ir1k5hlFH6C5XFm0K0mMTxXZ1Cq1VTR7/lYjOZ0BhCTZSGuzGYjJAnqcSzt2b3ovbdMrHui3Z/2NX7PPf6L4JFsYn8kZr76wq/i5qdK0aBSo0jPjOhnRj+psIo8imGgaXuHsXrLOs/2yJZ8kMOD8rFv3SN5PgmYq1kB0jDisqtCAg7my765U9M7ClmPO5JGsfKwshEvM4d6W9SceqHG2mrMkv9wyI8WNY3kRZa0wnzw3RpGbCBw8m6POUAW11tp2gTIFE4M6cYzkvB6UFigHjtn0WGEl4DgaUPq4ODHOZ788lMkc9ZGW356bzzHkJ75nGnNci46UC03BckDeUOa5KxreZ5dOY7j9OnzDbn7y2k/15zp7knv+0ac4kWQXX9JXddeAm7yuonMLMC+m0PDkrOjs/cWNlm01yHht+gcUh4ZDlRjhAg+TIgydCPaodcDJyCuIzcKwlXlcJpn/wu2IcymLO+BWazudde8YmMp7wyFuO5HKH09qQxPFeD5lis4fLxfxhm8JycrmakiAkWjlE6FXLnYFBxoEost1wO1s9DzMaYnF/O27aZT4Yre92Vu4sZdjb7MxQj7l3JS8afTcmy87YqzXIEwR8mvzQJ63dLI4FzP1DrFhmdXOg0kZ/Nd2pQi/Ui5OXaOKQqlg/lr9k/3urXbO4YA9nrcgKHSHCTRwmTPY3TFccJjYvP+nrCdqp+xLA0x826oZizxAoZdG4nIL4wkQJvSTx8dE7O8ltLxKumCqDSWk0WX7VPRCXVj6Z7J85yPgYiMlYEArpMtvVbiqCKQX0NKuCWMivS28pLh7pbkyouHbWl2uTPr35QCYWWIuBr2InvL3WKRNhYj56sxSJxZ3sgGnNf/PztOAmOMydSTs+6RPUps31+PqCzA8TjxWek4UP5Qu7uSR88cAA2uFhLZ6QU9nuf/kfRU15ZVi6CQbe5BePnCTNi//r2ueYxnCHXVQ+Vk4OQeZJ9VzoNA1h3rDIQq4AoWV+CdKFORzZHyjvGJ5ka4kv6tycrOewgJKwe2wrHKOqJvSjyBGzAvU8OaUZobNBPADFPTQZv8HFnyTxkQEbwKwIjBcze2oJp4uZPT1h+6H/z8k4JVpIyMC2vRTTPFNV5zFlRzgf78a7VBHrMU2jEP6seio5SntsL6Uzd4hkngSUKMDIeWiGZDcYuiEVBL8KMh+9lx4tL3JXrMj7zeaYK/YJZZfjPzYX9txz2p1X1ynY6ehQNS1KjYTZNfbjQXoF81MeFzDpBKPqfCWqZBmNZ3oUnWryrm0Zdo3yZE5cZ2svGd2QxXBeVDgJEfYnFEyd4MxiTyyqJgyRHKX9FM6tfBaTs7+rjDucyUdHLzl2ZlSpgGR2W/WQnLW6W6NgBHzEu6u8GK3bNyaCxqaD2cHu6gXINXp+WlVhp0SvzE1KjoNSOHz2dwia4KgfN02hqcihbIkatGSwtDfcu52QsJJjbiXmnqkv0axgEY3wwfFuxEyTAmo5Id+rxVXG66vNV/0wuf9I3nEPEqDL7yHiI73OSMAWxpkK40B1Et7hserNofzVbmjGKB7AibnOwKiQHSUqnPQ0QTf18R5SJwXFTJCUeH2OLpNlHWQlt+9mM0HUGP16Bd41lLBmA+sm+RQvhEHdBU/b3eYIV1M1sClTBamrS55iJw1THTniAt2q13ItRVCeGmijCP1PsMJ3/2X99yQq/ZOUTiYOi4N0VnKdi2NKslqRC/H2303rGXh6Dt6V9inMQv6aIDSJ6bncAglXwmYIB66YoSZ/u8SMySfsyyg+6w9lO3O05VXT7eWte+uTiISLWlol6UnzsTSbtkvzLiXGiNYP5qQIhZ4ovluPai5/mVJCWP2vLUy/hbhPwp9X1GEvtPcKtIUiQ74/3sgKfu/SG0RyGygn4M7WXRU8OMRY7f6f69b5QJoG23H/9odZCuYDmQdzoWS1Amg2Svtt9SE2XAuxfN6ezS+JIdCsvC8xqsfKMi9SSxnFTfV0+Pp4aH96XMGC4fZ6XzYMTCUzuQFRyaeu6Cv6xaX8xkg5G5j/e+QM9/TI/0i3B8NADAAAgLFt27Zt27aNj23btm3btm3b6hAd5KIYa4m2ktL6vhshvyOUtE9Ls/b1WHtMi/+kCXFOjlJCn3J+cyY4Vh/JpUuJVTJHN54nasunZzRCod5Na6all288m1K2p4WSjNFapqnSeRqheSwBEMpFAWrprMcuPnd/t7QLfmW/VWj0Sz2SyvrzuSCaZozmAwRLaguCmPMeKrA9YrR15o0lR7d7jiyf0kxSrhvgwseQ/AQ1H3DsgMd5bnUwLVT/lFhTbrEzdFywXWp+sN8d6f4QF2i9ms9Okh6RbRvAXN5DjiQ8lDavfVVLdJE9NPtfPS15WtVvVc4U06Qw2C+q6M7Fj8/Kv2gYH931UoS2KjoeiZpY0cQtWOl88XUR37E4EILFUuMoR26dZ9xzFewz/2be6kF7B7tafZ47+Ilk/CMuOz50Z+ApGyeAIq1GdpPX1YMPfdkqdILUSj0Tr8EojfbqT17LiuFu44d8H1gkUQ0yezQMO3oB8JdMSEZ/8bjLuH3AHPd4YSFMjrypvM3BXcQ0GWBsLczO+/hMe/0OV81FCLRG3L5Hz5xoP0NRt3XfC7nQJY51zdElk/xgIp7aHgeyXaATF31yN5cNxeNPQYM7d3MZYkKPk9dclQz4UHRmm2dR/8LyyKag5TvH1iHIOaq7CkyrRATYa3YxiTDutbaZIRC0jnW5RtRrmUV+iQg0cB3DEqJINp3cphzXOmmvZmta1aX9sQHOOjwx4Geinr3r9q53vV2wvSCYfbsTj0pZWhrGbSUfBLG0lEceQuJS45LefVRP1DuG0UFCHWHy4Znd7xcU+NjvLKNhMocF5wavc9z9ve0EZS0XyGqEbC0nLOM2Zi/9kWAnbCvjgAymc0qoIOS9X12Zzup+H6Gi/BOg1etjg4DceGeLJHKWuH/veiEW3LkZQ+7a//58/41Bhi8QBziLn8cq8/evQrnTIm1yoLFbxlVFU4tEDZFYVxtPSlWZy+kgl8aFvGm3Yon9YnzQ94xgdxPMr62kDvKq96/AB+I5nLgEzVDR3DTTIc/yTeah0DzdOr6Q+QUlUzv2pWaISW8gT6uVUFplk/NO+9kMMtz0XOEiV/f5dBHx3D6gKKyM7LfpElyJ9OaIbP9RqAuiI31ruHIHJXG6yJp5uqPEFz05S16uFRqmxpI4zjr5AhVmn9kbe9/qkFS6t4DsB2rS4j5gRBAQq6Th1lBrKr6npC8vH+jrol0CosXrbf0e1H1xYmLG1Ycvp2ppE9/nSHd1gnwtUSdSwEAFSCG/JAeGJ8XIb2d3dV0zsgkpiKSzqHq3ym80EqzPBkSoCe8LafFp3qy73cglsst/Z3B+oUorTmRQPCQHI8wUGuaD7BnaASjHuc5HKWDuFMTWwGZXbaWMQM5n9ffAUVk9Rr1ye7tJLiSsQ9nUJ649L0HWVdjuZUo4Yt5kLXUzhjOyUCvIqBUS3KnByvcBrSFKZemZpUVJnFC0pRg1wyIslzKHcGIXoSp3ilGIgSD4gCN8xSaIq8y3eUj70dbXWT+IWTLEK1kUUcP0y1q+UBHVfYdk7XcKNKhp4K4wVOvstwSIL5HQzrvJ8ReTMEu8ZCZJxCMp7PivMrUu6nRpXHdciMju8meZIvyBw0lve/GEUyi5j7accohiu2HHniD6Vf/rQYYvCkyFY+VluSDnZ4jq1qySZu0CHGkjY1b8WlRmfgmCGiCEGbps2z5VJ85nfbRWEiAKCZGhQBt5rdtz12uVkCok51dE4zLt0+lAAbrceUmCk97Tu0zEsGBPUt68eeUpu3obPhoLubbS6tVC3bXcMkxJtO104TRUTyWuvQOKCTICRaXvOzJamdsYY3cQ8ZcWL4oglwblxEwV4KTOmO9dOFPmyvznYNDQ299ooo2qnUjwXnmvVFpF40gHmRfHbD14K6/PKS79bkkpAaglMwdwlqHAMO7ctuSatjtiFO9i6328d189B56k3AbCd88+2BVsVGpOruYHyflx3GTibqtNWwzX/LKN3EuCi0WFmKefT57h3m/qRpppF0st0apPxkRWPFUy6tzpuRjwiM5Bo8eCcMugXG7nTIqlYWmRXvtW6b3lhruNHJDmIlZROGHafJZcwQTA4oTUB75sNeBl0Ekrurwl0KjuZZLxzioU6ADW3/9yuEdVwS8XMTdhkBvrW0kDDsTJMHry1aDJNZ8kx94G8AbzQYtrhxnGWUmJZXzb6hDdNyDuHZFu0+fx1RwAI3Ifl7cQTXSN8Zat/AfRTeEHV1571Y9eGs+Z3n83+TlDriBccP1L3e3HLN8zVH0uoC+95tocfkn5bfLQC5D1XEXs8pFJnuGEZK44d6svSo2wAbfPfjpchjHRmQzP3Br9kpuol/XhcYaoEzWTaG2cj6BVksyU4Dr/7Pqgpzw9K6/aL+vSNrrMAccUMcWiXeZgpq/hzMSTaV9r0wuLnwiLfBLazjivq/v9p9WNQLxJlgA1C571SrM9U3VBMVAlMssxA4aIrOl4EzBrY783cqW9MZRh71a87YuP4UnD3B/GcW9A1YxMZGTAa2G4DRZgQqMNd/skfs8QPawxtKLpZoWsOqbIXrUlnzM6xMM/fTEjApuse+iXhvLhidiCBNGS1qqPAornAVYn5CQthxd6SjBDJe129OfGF8dxE4QUSTUeMySMSHaO8Xo2HkbR39hOYgkprAbWKxeWYiBl2ix4uFfRIh6NGT1sP5Pt7unsfNf18zoGjvOi2iT+HSY5HDP4z17gvXp+N4QmZR6BPG+9i8pyT2nWjUJOHsLT7+y5gn0KbHgyXsYhY8r8vfssg/bmPVirvwj+X6TVEZi1ZZicbxcqnVDpQSwX58cq2WG+oIZCNIfdOIpzNtf6xr4A1NLXao3JPwEcGuDoK+8zdZIuEubSdGyk6Jzl9byAFpIGJXXstuLI+f0bnBpzi4Hju6o1Lx8GkmVzg8X7d8NlG119cjk91TItGOuFodTHSjPbR996IV4nWIk+90kxBQoWDPlPaW/1cvODjX/ua487zJ62wE1TVw9Zwp6INAuiqnW9UrIOrX/ugYqD9/AJ94AEX62KxEHOURi3D4FZW4xw6DQCpXS1oLAKJWy7JIuMa6WC0/Uj2mlnWM8LjPVRTgAj3XEkOsxOsWjjeSIelNMy1NjMtwY3UQKGDpAL1QXfJ0psDalEl0DaEPUreCFIH76WNgSr9AdeaHCRiMoYcYqA96N8apY0++uDvvYX+7eJSC0nLPsKI975MiKqxm1aB8oFb3RI/C133vedAATqjeIFOrv6d8fvXYbF8EZis2AuGt14bAK8fdQb5CKoa4HRBvntrymsfsAIwt5q/EHIxjWN6JZ3eEBJ8qbAJq1CQd6CURS8eTmcBaSm7NyBohhYiYYYHKXnhkr3IqkwbXX+x+ocnXUkiT8aU3oe04hHk7h9pvjkGaxI7vgKRosTF1Jqqq0qR6+OfXzko54z4WWC0PI1p8OVfonq8ice97TT+cijec6/h8E+RMI7AuWzUOy5kmkjo4vQuv8KZ7cY79lwaLFs8OSXSqUUs6hw/i3SKkHqg0YDVINd1pIFS6CnIp9ihiM2JKYNDUCu8BxYk1souELKihF9v5fbi4fidCqQH+8O7PwQLRCf5PsLlX3A7XYLP562QZgep3QMh+YfFlMUZywt1xv9eQ8+pWWJnqfPZ8WfwSbyntDvWdH0pWwHK5KAY9L3hTnUQSj9MeKVKrbbAvuKQozq3Vg0CYck/COcfzL0DpkSs8GNJl3Ds0eTJ2pw6Nm9Z9qAvbIxwJQczgB4QB94no3UItq1VqtDyrEibaQkgJITkxzyAP9RY7xuD18ulimsQB9kTCpm+GcsW7MaVb2GATUgl9WtiwfDifhIQBuPn1UqKVZvCt5ut3IBDMA3oCaYLuj0+hJuQHYXDLnM4dlvjhbCP+kyFH5qftiZzePiFK7z5h5NoiJNTFZBBr6fB/ddysNLLbrymfBQC/F36ArqxjWt3AlUpHYkkI/YkXaqnoepD/kpswhyhMupIZcBLllzyTDAe8p5MW9X9bU7Fv47EvRs7bNkro7uZ8rvN20vuCtJKRGJtAiYRdIrPXrpoOhCuSVj7vsGaziUkyJXsuggi45p6bHW/Of7Yl48SYm7EIDknSWuF/cTEP5JdPkMU8FaOSWdKamOytMOK39ePzCaypvJiiJY8cIany7tfpcRMVdDopLvwpczrpSUGlSW/rtryf9Ri/e5G70TA/0WnC3ErqAGZhr51q2FhI5IZA65dzHYOWtcYf5RjsiK1LZexng1BHe2RoN7lljYVEX3ddAHbLo9rxFZ4/xNT0f6FP8F80Jea+rvAAo1I0xckzjOxVemc5I1df6TFpI/jV/CbmSKqm49WHnfKKbseHtWZTNLOKyetPRPKeyn4Y7Gci0JhyIDEebkNrLl4dtZFKkHmqhwJxOmMzDTekzfOTX6Y7H9+u7JRtq+/kYLbccWqDri0EUshnUg7xxyiwToNBQe7UHv3P+g29CP83NM5kRqdl1NTfccMwFGOaLv9nFJWyc/ZgpIXgZn20pZyFiM2SpiBNkPcrmlc/8YiHxH55NvuvUNqkCD9CLhfrY8ND65b958uo7JcunUpPQjV+IiGgsuF3InAd0ebyo1PZXfT99QmeEXp0yHQ6vQa2xcIudqsSVUIivYuI5sCz0POc6qR1PYBfLbmMZz8X2fex2GPk7vmxoj8s2W31NRx/geumLEE/4aLWHIQTSoOjZajv1sZeyaUqz3AqZ4yUeaRdRUhihDJAysY8c1M7G5Nv/OFiaUfuTi+qIdvKgUjNJ0cEJDwfBWnSZM9UcFoKfY8J1hvoXN3djUjCWZ9IFz3fiG3vSurcb+qjT8r4ADaDni0DNhIBsvVCt4wu8xH8vYMrHyOUGv1iY2alJWAHV9N2CMV6dlLjlMN9vgemN+yAN5CpDuJYgzasaocF+HrY6FcDJMU6teezJSmC/wTbpwP3S4oVpEZAQZuqCR7lVLR0wgoWeh4L3SA8DSuV4uuXIvwfI962adUyBuxuiQ8D37Xm3LoS+5l3jbZY3rj3kh/3EC5lqdtf4BO/ikVLamw+WwaMxq6jWW0ISxJTH2GazaDTgFcuFggZDiBEmbH2PBj0XFy9lU7UUzgRcboYWM8F+nFpG/xN2RU2DNAOiY9ZsIF87uK0dIcFvN9fcxbhYxkcDegw+GhZHWJjB0v0NRBGKDRppNIUp7NmfeTFPlXIaH/XzKgPeEu61HcyYWqa5O7gkCx5IRHOJQ6wQ1GB0YbdZeN23xrp7qDOgAQhf06/ugdLClZZ5yso2ixtwvqLS7T9VchswnVZCz2VJJKX8vtGksXbSl31M3kC2qIoAWC20BiwG0AC7PMxvbZq/WtW4xNYdIvLgq1pV1BrXfEVmPPuX9uCs/IURsvJxgPFQt0uGB0qTsZ75ym9hnRsjN5WHNsklAQptBSHjZgb/m4o6u6hNc3sbcFyvsidmoohAbMXiD0PVdnCjFL3nYFTySGCVxt7K4Q6Dc2sythKLca3gqG0L8KW7Pwp8keIUimyViEQyQvMDS2K12c9nS5/RE85wv1b0dik2W0/wf0e/3dx1f3NcAcK6piUz0+toiXceT+sDIahSebOzWqlKkDs8b7tiprcyH8GYMCMt+7KYVqJZDoFDP5w/g3hpDkPifvm5Tv2FUfTG5wTa/n7HF7u4zEi7lP/VjrfTpc6dwqdTHB+XxSSOroChuRUB7xIdzf46jG1QHxRRFzml3WPQdPbt/zk0QSH9/e376AjTZYCOq71rvPd1WZTAF/nmiIg9I1Uz9i7n9+b8BBkbyuFNCkUtj+SuS4n0f1lpBNUCU0hU7r1yFc5SUKmWbgMPe4bWigr+eXFLpTtKDf2cOjKBDWiWWt/ucFwPOOW3ZyMtJTAzTYYTtZmQcMxEutXab8iCHX/gwyI/hIsherXgnQDiQVS9YOcQ303o5eJNfelgLNNFawjHbZrTF8yeryeUbzPQjSZ9bNUh77SlHAG1UNhMzBDFm7bEPdonSYrVgSvw08X8aPbBIAFnkGZxvrWVX0mxOxh50ZVxQSLW7nVcGsuUqofPsCBGJbaFYzXIb/a+3TAOpVgZUmQRs8Zp8oaMu7PoI9VUQGJKGz+US/IJsFczTFI7V5M7zfigm9VKkBkhxLrCxpLHV6qhwCPb0WOtWct85ReKqbyhb/EdjFW9oJE5mxRB1oetphO44w463pW8i9dIJ0C8Gm4qd3uMG45sgqc/pq5Wrwl0sPbJ8tRSVTCJpYIs570/c7dI16UjffJcCz6Tv/BuLPmY7wtAmqHEn2IL5/phNgP17UObXAsWT/gi6kzmn+dp8Pw9LhgpTj/GEg83sonJFxVpLz6amQN+csUebuoG8yA0E8pQMSXNS9jtChuGxKqdsK6OVnyLVf/vEF3Lzo1j5siAzyoxAdqT5NelfUOBEWoXSGuhzK4bLYD9lQKfAP6E0VlsdSbHp+6Ly5voyrQ7wO3k5HYWN6f5S0Vb9EvLned00DNt3gnPt/FzJk4MQGGieGJ4OBtxGNFzc4tMWsb5BOuGhU3kTG1CfXb7Hf2LjKh7MO4XiaCOJmW4ETX/AxjtOxgc1QUOkZOatPtxOgwMyKff+UjsEb+W+JRHGX9Y+LX/qp6hVUnlIeAQmrBQEi9kviqlc+vO68MFWnSqKJkFZ+39ybKfQZ4WZDMEgA09qFkO/pWVpO/hFNQa09y2LuILY9rDyqLOX2Tk/Ef5IqHwMysuEMKEZFwJCMAlG0xnWFCPC7d0YNHl8VUyQV3SeRgSaA6UJQ/Rt72zzT3rSyGMJh9fWho3fIe7q46szZkGb4DDHpftptgJ3iY/K8gX9CNYT2ntuheuZgV2RbrM0udH5y/kGj0p4/lPl/ZJm+q5PGv2usjseOIx3Mv9+Dr7EWElNXpTTsVGgOed4sxmsxngwC6Mdi56c6LFjLBXko2Ys2ks6DWYxa0Nws9+84vMtwsrHHQOqcgS6ZL2yylKDAr8x7A4fUDHWBPtxmd0xRoobtHLdE6H82PXZtfv3++oFIwhY7F+Co+8W0fuej9kZFCkUunJQeJc0YHx9zyNbTjFSI9Bz9B5rxYY9+1baGmxmwRCgVTgzikXQX3BEO/yMWRG5VQ4hsrYE3gWt/y61IuEWzdpEwtJ/FpYtUWBV9Kmplj0uXsK44GdV6I7nvKbld4H7/CJHuaImNZiDxEGrkYpH211SHNR2/Czse0jOygKzupJjA9Q9pZsO3p7K038nxIEIFVjRmJlDfZ5A7MmqBxClW6bv+FwiBmko/xSZrBtgaPKoUyiOiJXxA639pRmNtQMvZ4kdqumHSD3mSZN1Nlt0/EpAv6OgZzfB27xzRzkJaTgKf8DcnIqpeebABSkouMraZSqrSa4juWywchJlAmxsOeekmGaUPRTkE0Fi71M7UrvJG2ep4SvChwQ+oZEEXy0De7evR7OWJM0kIbqOdq0sRGcbDlQlH964K17DpkQ4Pbwcpw1cB89UanETS7/AJatEW9X8LbRc1mGtPAUDIdlX/QeXHIka4zod7od6kICuXj+NCZx5VU9Ys2lhItOdJ8kWZlu4UFcPAwmkMl2QpvfvS27hCHbZNv7Z5qQL29J0z4gMiOGlLbLWp9o6yO/4jPSa13OWbgvepvsX8mxk4Hwtxg/LoaWrOqe0q6PzTLfBNggPLOgNiSalqW+mhs0QYo7p+asyLcdI6Kx8GWiQGKySqQb9Uo4Ahmi+HJW48PH2WAfZDEiusP+dfYzutypWJMx0WxjDQ2fsZKrppKqlE2jqj3ppQuuP6lhw9kTPc+86oAUa3BNH0p5KBp2hX3JMasLxKRt1lNSalGfE8t4LcUrQUfLkyJU67b9YUt+EnwDaApOawBkA0KXv5+Y4M/RboKWy1KAF/NxHF6Z1/9Vyq6hhZXqlcJadz2101ntPU885cuity9FwS9fbz0hayp4BMzQPoTAuKz1dnBjd7O1TAk6fRDu3Zm+358JLfsUW6EgCMYPjbomNABDQKSu5KHRxCWNMYrBJw/errmwAAFVJ6oW7OerEmc3zuPYYU29N5/NFiGi/FMVDaGCmCKqj19ytpKgDbp9+1NNmG/dQFDVRMuUkCFlfFMN5si6J7bS6kPleWwSlX2jo17iwroSLupYwrQ0ajk6d39Y05iCKB27MUGqYtjzKCjqZTZh4SwkgSDM9CTOc8z08R6Xz8KzfLc/LjCrKlanlEe8cr9GE4AbRVuT8nvJcTDIF5143596QWNpupJNDYJKKBEDVWZRBAAAQwM0BRY5dfUFMbgdeI5Ai+6UpKzGjDZbh8e0cpToVJixbX2If+R2N/W1Y3beaDB97kEuWLZndYgIfxLEHWpE3RuCDIvChNDveYSmLUcJPeEForL1Sz+ziDzlHpHi5IS4d4cbQ1pQQtCh5xroFqbqCEaATC3aqfbfzXWvH9U+jakyNxl+spupZC8UuFKOQysEwtV7ujpJXKCONwVBphGag3SqmbA/XYY5WuIgMlFuIlY+24dU33zQ/qik8MufUxa/bvgw1rPuKwSM7XnOjOt1K+wZoltNS2tyIc/JmxzXbxdykE+clhfhD6tfGkgqqD1XTQaM1JSw3wXAsj0i3yRDeziy8tJN9Md3Pt+XAj9poTovKUOdiFNZ4cBDOnClGcSX1DaUYXfj4gLh2+g1uaNIf9jXBz/UWP81WDsA03kMZ7DRoqqb5Do1mv+lrqvkWzhDlq/lUOPUxDIaIsQ/VDrlp6gfoWBi+in+R4fEcbxfDQ9CqANiKQeLePhyxKgLRfoopvJBzMzJE+rlumdOhZMc2FfpNLHn7GlUNJuk0/E00ctd9ZSgd53ityKMfXTN/yYT1OZIvmxwLX8cBcwVaGLFxZ6eqvpYJYWiAr5c/wOLe0Hu/kTfg2i3KWNEk//bUmXUYbR3B46v7mvKBo8HGXBs89ypCmWukJIZOAwhmItIqaLOFj+XDtCVcb/8rUXc/LI1KWWtHzO/j1USspqoZ/0WleeQ41A2Okunv1mPJewhh/BJdIMMuSYA6e9odEOmAOPtFqyAkgWZn6VTZQ/D83BotCLS34t4D7LQtU7h/LYE5wXQepsyhavOQPjM8DFH/poRcCayclH24cN+f0CpfbQkbYaiUwRH/QQhD4YNN/bKZSrJgv4SIV9CPHxTcz91uQBA9g01CL3bdNwA9GGPZK9nqeH5IRfsalaVgXJ2Xh5GN5gBQJPSSz5PatL3unK8OFCpXbaq7xWTVZIx/+FZyDm6qClDq/sFsQcmBFoMfRTV/ZmnYYtiOobdsQRBtJtvJy5T4fsrLTbaOR6Pt3qCv72peQoA5Rt8diRNLuYliEAZ7xL9FfM/Q0G/yrYjX0fx3tc9s04V5Ht6Dc9TDlUnfycEsHu9GEFQ0QdvfibXbSXdWeA517WRSdqjlq8ZREVAGCsJjQS3hcmdZr1S88RVeCAaxZPdmudvPcHvqIs4dZUMlLGMQ2PnsVaStx0nNskb6khDiOV3rCMT3MhQhZxp7It6Eq8g08DASpciCUMQK3NUsjcrLs4Rdt9qVvBk4PrLtkrtGJ1uQnbI5NSwUfm1uRM3Q8Zpxys+hzxYXqjmtZxtH4DD1uMzxJRdsj7nWxVgE9eWIpzwJEzGZcdUNJ3chUT/RKfzwNq8Ll5kHKJpkfocsmwK062hHI8KUnn6iSBSkm1kuE9AivtkEmW7TcTXBfP7Ptds5TFO3xFSld2CatymTe9UylrB8c+IAy4xSv5uOF2qgFp4YWX0atvJti4gi0KEv6z6oQvSah2TF0cnJg4wAfvWp0Kvlx1cVhrlzj++w6Ixto8sO+LLIkjHayWTA5MaRvJ0fvfm3hwB72/G0+3tMatieg7RVz7QLcmCOSwdRdvaosW9mIYVrZLM5lNPEfQ8sfpWcgDnznMYm8T636GgmE1ICFrxX3BRjXB7ucJMetzrVlFwATzs458CLt6X1nNzm9lD3WOZTU41euqKJLbzYvcA4mzCt/z2b0RcuhXoAk2yDcf+uhfXDHh4iw0RrDgWafifBOt6gQYUdQZgcMergfdqHtDUCQ1L6IXR6dC6oKpEm/0lA9TjR8PDu0BCmuQn8z4qdRwR7PsOym7RUqQGKRDFOEGbzn0c/zq3ZKDF+zU1zZ6GapwYGXpcC4Bddr3v8Y+w6CxqWAoz9IjWgZ9cH+Z/It227ip15bAs1TsjyGYQHyspmBMUe6VnssXT4mms4ekytOxLc+ogpTVSKsPUmf5nehxEgvvdFP/OyyVSaMWE1HtHagpQb3N+1AMKfAZVzoUn/eZH7MhREYTSOM06LL16uox4CKRI5dLuo3b9GvuKldObWjjY5EGRzFQL4NIRfsPnIu250GxI1nHzBLmVi+WbAAaYoxQq4grKsv4VDb5BGhmGyraDFla8ZI/TBOO3G86+Zgj+mkIYzqZif7dHdYEgJgREBemKs3J0VytxEpYI708wDhB32FkGjEROnLtgeFvTMkFbMhBKAG6k5Hh/wjiU2TvzdyUHosn0DO3Mvo8U9gdOyVhPAN1jTJjtubUDaSkTT/K7lrdeXDAgpbinFC0MVdZ0orhXgVGbShciVfYo5GEAedblE/+GnXI6sYGfMkhMLnv63o2TpLN6cMXTALmt1ZXmLNoPN9k0kzVMeaqOCdE79RdKcyL1bR1JGDi7bYvEIsDAZAFtLq0Ksgdom3xtWcrFU6pBCnNCOXxYDYTawzONZO65A1pJjHokast5MvOqY6Zfgynf48RDLlKrjeBZrG3N2osT46q1b4sGv1mjyIe0DJx5+WGHwS6gsa+7XYyjPVpOQrVuX7CGXgEa/dqIMZI1VVenUzUS7OfoP/OEGux9V4j95cnJRCL2o6dfNnf03ZMh4IlD4SEChGjw2n9o7Ulepw/T73CK7VGb/Jbuss6XRy6C0gmjnm0vvmwmsB/U/Nb6KOhaOJcCUiNy3CpAdT6nqJj4Wxb4pFNRttg8YWsZy8MSgKs63vyDAhOkNfZ5NH+TSPz2kFGvbFjWA2LPNDn3HY8nn8j/LyMA2+I7B8ryDLShbEBMzqP6dWf0i5y7NNKEEp1YAwNxC/zyhdBNPL1kF8frDsTNG+QnooVmAXTSwsfErE+oHbvOYye4m6Fyeu1Z32XuOAh1YdbVEHZ3kBSb84smXAWh+2u7IW4BfrVKhY5IdzJGghUQ8Fl5EdP2VTg/xGKpk3OqcuEBSSEjLlkpUqDyNnkva9fccauAHTM742zdSXa2iA2OhZr+NgHC4orTOuV1o77en3lY6iWhl9vDu6y++h1Jhp7w/N0J2iBTnXHSPeUWpYw20jyQU12tRpeY1Ni31v8cHf2/WDvbLuyu0/hyWeSi3qm81SEkh6elSM0F3XL4hamUP1eyVSilo9iZq9NmXRr2XB+tnEH7yWM/5d7bRGaJeRpvKFZFsiGWBf49bFZRhMpb0kRyZuGzg/mdYVh0TefsCyGAKXSqdj/NOKs2jGmaQqrp1nDtnaHpYNnY0GNahkv9S28tOOsZtFVst62UeEqOHqOkCa2/sZ9Ej9FMCme1NTLbwS02d+2DJT+Mv3SXaGHRWRha3kw8EtUlleYXd75YL+htldiGLXMdQa6U9Up9N1FFaoxBWU/oEaFK55fKKnUSFlKn0Upub5SZ/ia6vCe2OBfoo17Hup0Q8BCFWsBbBLbzeqRENTZyOBkWJIY1INm8WcW/P+ciPkVXFjdMZ+7uXlxJJIB5dnQ6a1qIynAM3h5gdsOkwkdb/Jd8T5jqZ255DXWXfT+f7m0WvoQDBQqllDe84P7L9UOvReODrp5iG+0xQWj7y3EJKRSIUlhVuX5g23+DWRu8AFZ8fEB/pnJCWjKCzr2bavPSvfKKRnP5ImeDktJyj93XXYQT/gJUiiUU8cjqjK8ooMh0jLlviaiWsNCT5GT/6bK1JkSFJwRKw7nafc1EJWBsNyNV1NN18ovIkHSOX33Too+ImyQXSUF13AhlUTSKsueSPJySTSKZ8APln9BYWaQtWypzMqOrU3qH0VosiKkXM0MLNBkNnGIPhLRuXYXTcXYlrK4cZ4/nXEQhwckW1+/0KmSqah5BETgiMSpXBOSrSdQ2yhGjaQNnmlGyGz83Q8oE/j1bFliT0zuhFSXc4fpRBMjfmF2ZRl5mQML3sl67SvcBVmBOfhSjW2HiN/5xUp6WaQtUSP6OSVJnNBqIr1v6a6ZLwrkjWmUR0Apav1cnCQJrvogTzw5YRGuUDXwjsR213ehsJ3cg4Tv6jRdX/PMOH68uJ9kF7IZZfjenlig3pSRFUUXAZdf+jd4rlAq/gXzJSs7Itqwc3KXX54+nHmXBA8dFN4qeoEsS1EVLVRBesWpISeGrhJwhFKP+1d1mYDYrWsHkv07bPbVdxIaO3uPTC5M22FdJ8vqECeQE6LYKjuiBawpm/LFgAlegkLGXNMo98oHQqv1BG3t1KuGrtnt58q+IdUW7h/SWIYSBjZYF/7p5Pv79liG/gshIm6jGWuc84T9YwpOedNBq66jMiCEeomFNlfD7en5aryasK8a6YmlOlrIaoR5L57gkgLibkrV9FBCvd2F2QeIdBn/UXvHw9w40nlxJwDxht4pe/FbFqwKCI9EA0DribZ9E/bMItU/FGdzKsBgsCzevZaYQnoArifJAsxVkQp/IbOAnBxxIjUaSgtllzdLTkSuf15qNnH6Kx7Xfd50ecm0TPLtfPTSP7kLIilTdnFyqe96E9JJsXArNRKioEJgpwd7CEELu4soijs9lqkVaO8BjWBoxRGpIqNxzwCJMvIPUwPpTQn/LjvxppBnQg+aDv8rPp5iknnKAm5VI3zRCzT2fd8rcwtB00cbzovL5jrSYpnTXpLwYEKNqYmAqmC+8orY4E50ZhDLZKq9RtcbCDYLQcH+1gdi/8TKjnJaoLHDm02TwijfjNAcSSFJxM9dr+PazodqUd35ZIXO+RqhYQ2Kidbbzctcfn4bTQaWX71Nf+53cKf1WFPZuoL9G1OLBCb7kkiMrR91Gw18KJcLC0IS9p3pCVbxLHn7ju1Q4YDcElIxKN12nPWrIAfxzqwF3lwpZR1CQb/6a3k//GYSSRCjAs4Fs+XucbYSjBt7poEOQDOvpmFOaopdxDBqYeeB+6ShNYR5nwYkGfXcSej1UoDHqYw4D1ro52VQOODtd1AZe3kgXJSVN3PuFI0X48RIQk3cN2XA3bH++XAyp3+C+lUkEAEFA8M9Tk881CxQccWxnprYM+zR2VOSrswXhXPhdiXnmUA92hq2mYnSZ9YwSbtyExYyGvsI5uR6XQXiofDWVBvghkqmRFfjjt0m0g+ycMe5SNL1EtJ9Kx4S5Im2LBGb3t9roPRbFjiR5KIHQonf2IAgpBzdNwTCDMA6o5XWlgXuUYP0wQ8uI0zoq6Em3Om8iIi1qzSWVkjGTCOiPidyu3S0wR04M6WBEZm8mMD7oSZZigRCAaX7muUXhG0m64IQCjTyhvmaLvNcFruQ/I+wsx2mv5veHrkkr5qWCna022k00DcqfbWxg0bYQbuIRf7C8CCvRAOzcPUVZXke+g20kkZzLadVsQdZKAWxsp3sK7OHc+fycD1bIVvx4oRcplykdeAM4WbBfqqaWZnBKvmkYU7S4snviQrxOIQI5NiLUSHiUxmCM1bEJBtCQMmuiyggCUp7apKRhm0N2+JcaURXwNufMqrbTT0xdEof4tg5i6Bmv0+Q5cMOv0/ia2EuLw4WzHpt/wNfbi7F8xowFx3Q+RHF9d/MaoWr/MBI6wxYXhNDdcfRzcssdVB8fccUqr2K6iyYpMESOZH5wbasIDQ9RvHyWNOmgoWlFA19TYtnhB5+AmltURvhkgGENM/3gRTQ8LLNBVGnre1sih/GERxOWTewc+NJ+xnNHgy2agUfXYv3Gligrc1rSBBe6Ko2Zsfz/mGIh2ud+atyWvCWoS4OYykr2GFX5HLv4Hmj1VvZpOXnNHSNTrEZeT1q8wtsUCxQh/tt+/yQXAOBSk+13ZRXsRFyFgQFnW+S+SgqKpG3BPgRAVbuQ0PDdQYrYDrDDwfy8PkzkTaNSYqlEWRJvFJLpAqIjmNMhYGjnR0ked2Clomje08Aw7rmE3Z9uVVZ6YlQhqEfbs4+nOC/niYkqDngiF15Xbf11i4XO/yrDb3dcgqlIcIMRnRFLD1ZtG1PVyAdgPpxDahtXD6NurcXkHiQkce7UDwkFnaGUyYyB8UBPCauhEzpXWLCQcua2AFtZEethvxZoc3bX4OLIkoodv88+pA14lgn+4OFTBxO/oiIYgp5f86Ltb8irUaCWqnVjc6UkvvvPIg60bEZpBP8eKFYM2hmRVjOp2GARYNenLA7M1+RXRQH8JhkcKh3/+K2UGvsuSwvCkfvmwffyG8EDxwurHRoQqtcoeBE/ayskGqvVaujClmSqN0nyy71/KAXU8x0NAfdNm6YLfJZFp2VM66hKSrFqnd3E5HIq03NTNei0mj8jMF3yQ7vMcYxeooCkocfSzakbmMHxkTUmqZA/Op9XnOB/n5aNIk14N4ClRk5Bnbl6fvezvOnwZb3DN3a9l+JyF4zHVFjTisgqi/Yi502WanY5aMGWWmIlC/oAD8qOTwVyuNqSb/jzU2LSAtN44H2E28Xb5C14qWqVHg4Qh3xN++T+gIUrd/P6/x3tc31hbPrmr3UlywrGIjKNeDGTKK4ZpP2yrmOVrM9tziRjj8BAj+e+AFHDr62qGWBsbvHYKJUjsPZPdvEZ8E0CIlr7IuALz5xac+LWPU+slWEIYJegXkHkb0BhAtk9lDs+PZG8EgYu8FFf5slCHrwSR244zVk/1hxChME6UwFUHYL/1dYwhFwwuSmd9NLTSKiDFa1LvP8S1m+tkxUx9gxbXyEEIh0Q4z2UcVxG7pls6EaQOxbTAgOkOPXryArA7BJMqzPP8DxImmz40s2wJ565cu8Do9SkHJ/x3kUWdY2kFvHLZe8zNI60jC9acduXU1ymIsi/0rVRtDThrNt29HNtBGVqvGis+BQGHs0WUtEqBctWyU7O9sq4F8Puh0mmWxT2odm9bXVAMhjfBviXQYRctPxTwvWMjcFlfBJPF1gEtzYWVuiWNxcGBkl6Ib/gaTtSkoZKzBQbbWluSy1cksnNZUnkiljKXYObKkw93eYEuhwZinH0oiUfjnfi0Xrsst+9qSloGbh+ZM58K9fRDDG49hOf/8n8x1FEshSau1vf03T/7XZxYR9hzDftERHQbDHthqCrLOtPlZexJITSwG28OOcZDVMphMk9e+gmdsm1Tblt4GjPySMruSOW3px6FDdtGBzAabA0SAfcTmfylIBLtU8a1g/bE8zYosKbNPDJX8R58rk5b3EbO5OUNkI3b2Z8IAyiGZrPE2Xs/Tam68oJGARhgecWmTbeE2XVF8T+dCTRQCUKAHZ4HMjBR2j2s1+D04WeIhJPJMxf5waPjc2A4Jyma2Ma5DXP/MWUgzYFGmIm6YlA7IH7xvn1FJxJ0dpWp0j4XUaLujnubtsgu/tAickrvHnLNKsJRdiOO8agpFSqqwHa2ROY6OQr9Lvrp7efcyaQRne+2amB/pKm2Eg12m96xdc+SInUxAMyDHXt8VE4pxdyEmvtULO6+TPqYBlnZ2In+tnKJcp1lzEh/sddMp89S0UAUuSXQyRPq+8xphk+VFbbv+kmoFEiBDoJLaOUnuB+ZjYGa05IbJ4iQT8n1q+RIMOoJudCX9pFSqBFWft7l5bXfm1oFJxi+faEbmJVu0Mivqiz/WUICaXACnRQhIOUc+XrHsUW/XT+M/K4WVmMg7dTHgoEW+2jWaqJF6SQy/IXjdjkrLDDZ4OWMm7mtIK7qvHwnRGRE2YgTAW6N9cESPE2UXZ0cARZemUJqUlJrVoCX3O9AIQckpLqG63JngayDmslXN0cQUT38GjnucqEGLolu9coVOqa/6PWU5CD4r01KiZWygnQH/XpTV+9dqAK1jm2Ub1kES4Os1AlTG39GT7GrRZlarTUeFO/WgGzSbN6O2PTU+6i5lXDpa7IeZkINnXPAokWUxABX4L5RveLJ1XQcuGEWIn7K6xfiZkhnjs/zjiRExjqqMUEvK6WY3psKjx35FrGuNvRgXpyWz9ymOs/GvekqeOza4VIFK2sTUlSk0OwOWXC45y821QKW4ZeWm9z8s8dSnzc16wt4bjCmxHx2u6tsfqc8zNmUJjfySsXpO7oiPPAu9Yd9yh5cE3tlRVgf0Qozh9OwALJ7+MNFJz2L4A702g7BB96v3r9WkomkOG8QmYcImMVbHeTNgIg8gCxCnNfONj00by1EiejTDFqLU19mZoENg/NAS2LX7SMrr76Pdpsd9BtNZm+Sm11TMb/3LIAzGVwhukPBOFEqN6U+cM7SW7+gxzW441S/I6KPTBcXSfhnPrMtluFNY7DsVhbgxAOse91EfO711fO1vg3cbh81qtvxM7My4joEmkHmH72GfeQRE5N4zsOzeU8AzY9922RBXskMveD6MuKwj6KtiUs8b5Fmq5o5gSWEz6/neKsyiPGD65Ar18H1F+sd/MW0KapB4hUCWEDH0P6YW8nPBo7GcZNylR84cHvzM+o0XDIs2hIOB4jltaMDVDEn5ojCs5HkB4RJsHZY8XbIExHO3Fs0Fwaqzh+0q5LleAXQnZ9J1vOOPTwDS3TLFplHoc+T+P667bPKCMpEmN5bvZME9Nonoy9dUMEAlVOI/fCOlfXb2TSagU7JIZ0C6r53ih8EzdQXD9IF7LR+SCMUsJU+vDDlbKVM3l1m929495xzlAl+nedlwNfBw40rq/zN+WsM04zIcfAOqRGlp3TNj4ISwzUchQmEhkTM0f2iPsz3+G9Ggtoe3RJVidMU16LdKR7uCE9cZfQMYCpRP/6BQWfJPuJ8aAD3o2RaawpjkM/W74IO8xacRWg500LMu8jJofiZuNSMF+RggMhTeUz14a33Gxa+AZXRFNTwAx1mhNuQXnvA3Ze9SJKgaQHrAzzO5wLzJdvkO/pRj2Cn1x/JsbC+orK+Z4Vvmz4LI/B7HKTY/y1ze5GvOn5pGLDdPva3corFThC4DKdhDBKj9W88pksjByxh24SaphzQHDVS3cBPxWo3lYHcccAlQZt8Ox2EqPuKF9J+0/Ky7LvyPNdIa+ws/ssReuK6iue5wkcDIvxQc/E9/JHr+HQPIRKlqNiSlP0jXz0XL/OtdWTG+YgAyz8N3a2lwXBbDN+S0YZ8CjwlQVO+AL7j/nToTiidKkuTl16EtF/duk1ggSrfwQOSdclgPdMmowJdosWFKjUGyWt1OdSpWTexf6mXA7WOmKzj5sN/QqenEeHVo6mC0YrAlL5VS+NRCAOR3/QaYJsYHF4UITQZWe8r2woCOWEO0zIgsheioF0Ijqg+L/rzOlMZ7ZrLn1Rh41FmzoIlniTef/aq1hbVlhcd078wOIMYzvPtthDatMTENmzYysNJN0NhiZQofcO9yTjYkHqoKGqI5NnP/Msf3PjvRZttUKoSfJUrzMoSIvu8AnseSYBspYeJEpzwczbkb4gMMyE4Si8hWkr5MaGc0cNaacVKhyPq6pR0LXre1woo/ib4siDeL+nNoL9E0Gqqwf4Kl2OeBGNPxMWGPC2icNyoZA4yoydH2XaEQX+Ai13j+vGl9VldnWSsqs1IbWqsB8optbek3MXIipqOgUgtV5vyPLbaXRsZ2nz6bjutXCrDaQ8cfB5aiiiOmvkz9PFJPVzg4tBrMLKQ5M1WWtmdTrphKVyaR1bpywEcNEU+tASZUNzVEVMAar82VLugoYYO3HoCCBPttyMV/3ZJ/vukaT4WTq0nfoe8j86JTHF0sBHyZG1uiezNOQQFB0TJ5eZGHV/5wpI0kEC6p0u1Yo9fldkcs50k9bhQ6lDBxARF8Kur3fFbB74be7bmDcwLWKOqEzSTHxXFn0pGFfupLIANVVnqqbRV0zzLDToE42UWj29DvsDBcbFw5oHEKurUduP6WtOzgyvrpMXPphRNfR2wFO6AtKOG6vwhGyY4kZjPjpfEe6DalwJQUNqaDliuWySZgDWo1YiwNtkrDAjjGH0+QbCTDbCvsLhr4wEHKZ9LQ42+WQenSDj/Fzfdch89ENajus0yKZkpBUKZfFX+FL4P3MVNHg3vlITbMzFK7XGBWpbYVZ8Ze6jfoAzVRRig9yI9Lw3/cWPjIh4t/RHPuotrz8WSG+PjzNzipBBaEU3X0HZdb1BeRzGKr73oiqthRtDBWZr3I+8BMhR87k6BnFgR7dL8GQlfyBdyGfyjTkewLczb/m1oP8A7C/yT2m/MTBr8NRkejBBe2bYWu/CRjxIRfo3EDE1VEKy3B9Tjz5DwROeMzgg2QQPH329yJcN/p7BOSwfe0uAuPGtWa6xPNNs9aZZHyYTN8KU7ITzj8ZHo1fzeSGtw2P4kswGd7aqlROBPXioDJeOOh3a60OsH9dPSJ3psLYowFOfaMm1VtQjuYgTHBZzPhzLfxWRaE79v9mKo0/TE0nGiSrGHm73u6O59deY65IeH05jtdhxCSHwkvPw3jEZruJp0SKNQ6q4fE9PRN57ty9BIsGDnMTNzUYmVWnpIM7v3iTZhsCijYMdO8OH1BKa4HdOIwO2O+VbJdJKxuk+vGUP5Lk5bfDCz6pWrKkX3q7oUWEHBOAzHvNQlJ7A6lahjFrR+2DY7QbFpkoj/PfCWwy527QtMIlgjbAwTUHmN/dY4eyxImb+ldnSz0pndX1dsnxLmpoZ5iB6vaEZ89eB1PPkgr313K6+X9ftAJnbycwQ9lWLvGkrjc6b3HY4pc5hDBOAUy6b60ehVJFLgbsQ44hoYjjDG7GAY/dIC17vxwiaYzaJv+CDGi41w9vTYQA+jVz0rL/LYtKNCbCd2vocYkagYZnRxfa6Cy79EAzRBXgUjDRvBGHRuKG0b6ZWLmzZKFE93oBWGjjc3ESI3YT0rXQtOsmPdEC3BoxMmQv3X9vvgXIttYQPpOAINJMTmEMVWkoulEKEjMJmR9vlmmT2BBwl7Ax3ONUql0uDgOSMF7bqorAOre/CW7rcvIH7VR3ibvPE4S51wBUBawlFSG9W1u3UzeRPpghKRgSlN49jz5/on4pPUry2frgAxWVmQsqTfMso5XBxJovNCTSM+/PnHxCWVlahjmrRv9Qbf1rv9EoVkxd35M673hCyIodC2hracYGxKDKQaf0K+tOIxODzzHrrkNU/pm/3ExXzmWo7yK+vAZxmyqQQE4yXUdcSLiWH8J74vAqL3ZoiO5E0B9Q7Nu1RdzXp0VLuzQu4hh2JADWi15vfMK+ayMvhpb3xFZIZ/wez2Ejsm2KZuwcvRdbuTrxaCXXzFBUr2DPRIFEUBsEwSuh4IRvS4cmTTP/P71qeNdsUencK5dwDQ3962qpM1oUVnjEBNR7Yv3c524w1AAaQR25WZykCkE/L9NXxnuEjyRdsUIJEmH0hMq2W4gGcBJpCCuMZ/rwJR7I0YpCNY/jg4MCXzfGnVFEZFOo1TG2dJ5jHQPg7MLm6FmrYuE5IhgOIhxrNqHy5eskmrHrLkIAC8YPAhegQH4zH0q8ECZynjRnbkAibk46BDq+b/+n8nns7Sk60MW+s3x37oFYmxNoCtv9L+M68pQ9REJabvzdRz8xZNneH0CkJkl/BAWTsyg3xTdg9JCcBtsJzcpjx99buyUGEvF1kWXp9hdeeiUVoSKGHwdElw/KWgVZh8hpU1pC3oheYQjAg28gmKXeBriyxbqpOLNKl6z2Yhl3r6XNvd7Cf0ysllgFFyJiQM/Cl1LSJpy3lCZFLz/Vx/Y56GhPCvszLwY1ydjLvQgk6zcv9Gv825kNwn9R3JSvNZaxYy6R5hK4puocI93+wVIpsOBH91XyYvQCq/ujE3GA3ZlXVv+wq5/aTm5TedQxnmXiIrxEBhR6+YmFMk8iQ3kCpECfsympWWmXPk4S6/WPF2BQgteEfUB1IiwUzFGErmpxGjA2LMF+sd4eNoic7r8Yc8o422oDl44rbM5TKsyS945bR5k/tvywIiGsJXOrgJhwuB+Mh2zK7PWVnoNSuREzGfiDR5uiUWoGngt1H7coVQ/E39pnaVB+8ZD2eAH7zspk8SD0uX8uQ6+VaTP/I2K2Vgc2fXr9MHIpCrlWQivYw3iqO1GBGLOAbAa6VzX58YMymtraf+FNfCdfZ8ULSryqu/ChlTkh6Bxa7NcR1QI7aynLKoUfyVnusc6kfrdWkSjvMWAvyNxA8j/x8PwhRQwFwuX10eg/yjLOrBw/Gth1DDZ3rOqc2iFf17YyzN239NQSQJ9rlvxIkGkhP7o8v09eCZVZdbu8ihnEGyFWzz5DElUVlf/N3hVEAMv0RpDDRq8Z18wXTalf7UOxSJxm1Q5affAgNwLK1kxn/6Yo8RHf6h4xGP8i/fiWd02EkOYoz1bv3s7Sf/2vR85D6SW5BjLzgrTopwbZh8DDvVinJDR1hqF42Oli9zRITLPJgBGo/fqpzZ3aN5Y/ByPGEQI9M85WZ1+6JFJMthOgk5kYu+HdTwhWjnJtsnONl7bh6aeMfk06iiWr5zEHB+zafLcTqQDbmvxbaGd5JdipFM78PbVl9Hn9mZ5jqX+PU5+JwhSTKBE1GnOXKkYFFZxPcUdtIJFLcf8EeWCVL7HFvCPyiLBmRnQpNq5VcNXrtustSitnorECZBR3wxfn3dXSyubDfG78udC2uVF2pdAylih7tAKO7PW1vMV/7ki65MgoXXTPaaX3stmTVlRZry071TzLO9sVW8ZeA+zYeWQdj6hUjNpW47Cv0SE8ZzHC+A2BUKfGFebvCh+fAOEcIcxUk+Rq/cA5IQc/JhEYyv+e5f5nejRUlQW5GgKgWyQwtcKvOy1KvpGkhv+4qXk3r70jv1b8eRBpdaIMVTkdgrMIMylfkm4XzWPnUzo4vS4O4fLW99Nx/cIXIyj2eGyhDfkHZ+5DcPdiMyrgIMlL6mvgq/dxf8N7t4HyZ2IW+BATCshuS5jVTE2GVc88gOX+tdVLGnYAWMd+MHBzXoDgBlJoxYLOYT1DCE2kLcxved6g+yMvxFkpOdmapM0N0Vm0PUyzKqL/UIhi5MADOH9nXZiy83juCFQFSNirY0zBIk+txXwdZIACeb5Nkeb5H/QQjVBmDVI3zTxiIuxYIOru8zC6WyIAxSVX7sGSqOyRvmFANfSaEfh0aIyQxWEXPBlAN3z8TzOmhf3wDORu72J/cUo48C9TVQMQ1C62NFL02dgKuH2PZdb9eAwjp4prvJQ2WcBqJeEgIFyvplMokJZgVI14lAwoEqlaBzVikKTk7QpddJWZZfV4Mk9UDciYm+LGokPW9PyKpT5le0LbTbHPcGI/gYH9xgucFyAaEtfH8Wvvx5kYL6JhjK+ijMxVyO5R1FGucPhdy6m+C9MPYkOY8AzX+Vyb/pawYchh7abwXo8wCoCyS33Lqe1aLiqQrJGaW3JG+sADPpdfm2dbqkdOdEedfFXbxgkK7TGdV+qwr+O/Sq1WMGhwoIu1zhl/C7SFn2B7kVyMfJ/f1F2+VkFCAW2wniE10t9fiogce+FpQqjh0pf8innuiqgvvndybtskvFlIo+gw4h/pWLdaRhDuKAZGYe6dGtzjAiDW+BHLJ5PuFhp/56gO6SDSIsbT2dLRj/WUstNKkAPaX3D17mjWGDOungZFeuWSW9cCIj04RHfwulbAbPfNmo8OS4htlulritWNv6McWCadMVs+Vov2txAeHRjks/rwGrishz4woftxqusio6EP8+Fed1iagOead1sDmvy4dGPCIItn5sfFAEuZ07aDn0j9XZJVjxr/NbS93cG7sWEKiI6Nmb334xkyQDMw/Y/lBAnuj2Nx/cYckSWQdhxVDf/aQIoQYgTJ/zn7peo8opOmRpHyQne0AWeFWtpihl+3Ooz6IysZwmosr6wpRoRVgIl809ZkFv8n+k24NBKAgAANBs27ZdP9u2bdu2bdu2bdu2bd4QN8gbsiZ5gbJcJ89QAVZSswHhmD24ujBV87+rwRUJ/9cCL+glPfdWbOHkFZS7wrUZu870pxkowQXbrM21KIqvPgd19hd751dmFzy0cfZX7RBlGcTrfJSOjYqufio5URrykM2FgXfTvT0kVpUIvOkErggBQOMcN8QYh0avszS0i7VL1cLkgMxjcwdcG1yKt0RWEPIOj9Vw+yMaPQWFeQwAVLMYxtQlQL6PSx8KFsZ8rSZVq5FLTkel73fL4mN/zt//l+B2VSK96tHHapPfljFi64q3SaHiHe4x3c0g+Su5VnfEgSO5Vlbh9VOKo884gCGhN3wp1R9nZrrq2nsBIbaY9pNk+cJFHHt7HMerVwaZoDt9L4LAtJWUDZBUfYThI8E34lrtGF15Pm0TvJYfUQKlAoLYNoRcsEgGTREMj+QyXZ5LsnHGRLcM/CtKkag1lv4QBD4FPfLJOkFr4K7WaDGTpZDd5GnIUJmpOXR752YMH9baKNEvHzV1qxiGikpRqFd1wnnF3PPVmAy8LQnmkZQ5+eYy7SCwNl+38Fwv/+rHXRqhPRc6HpzRySi8FgWzAgapLlJihXiDDSka47deXZzwBPZNCPtqOnZCrJpOuJh5hBNjoLbaKzcb2T3KPNG89uV6dDo/18anporjJt2xHZk62eLhwFUrRAZhynBYhJ1N+sn714SIPHULlTNZOBYFtMwc+eMQhCKR5S/FSJ0jkSHTx/HqIcnfkpiyYyx4dYqSNNu2Q0fGH2TeCUbzs+Q2StgfkplNGhlttwYMwZCmRtyIt9GoLIO9caOKFwVRAPENmA6QsV28xCESZjh7SY2R4wXlKnkJFA5zCF9z+9rUAvlckKkM7Upa3YjoyZIWi7UVo4zOOLwBgxF1Tq01zFeRgyYD6msm9/QYlm5PG1zN0BrLwzSLZ0Zm1S8yW039DrdbXmQtfPpy5wTAW99TFWvdHWOFZA6e3LwWm9j1lWIrwRjSTKRmH1uDMlZOpkqLIDFhulX1bK5uTJ98oCkK2rkLXC3YVHf4qmzlhIRnrlmfKnHCKYBmzaCQ4oaWEpc0SDst1kpclsN1/wSsP+oFGd3Dm5X+c64HR+6iQ2o9RHLOSII3BODvCrm39Jxg3MChabcqZp60W6A82QSelAzkLZHkUYT3jjb9ZA/yUblCB5wM8rMwaysr/i/cNNikymWE46serAAzJVIkV2VC18jWQxPAehTnTHq0QBdBLijIBK7hflGUmSXh3i7+db2rGuj6qLHxcuztBu34xvS3/GPrYqPpqrhGumzDUXGVISBUtf6yvX8RKHFA1VcUJpbpuL4dh8SATRjdEZ9B8gOaLgVdawBqNCywEmIbheyqmlkL+ygBZ3nqSfVkc70kLyhCCxowGEg51xklCzr8xxNst8T5hCObCycqV30vx/SVF8SxHSR0z8bGQv4n2vKWBqR1ciWYMg2bSpSSGo68CeiVx8RBBzm++94ODw4i5mQdjcAJJ97kgJ52N7ox8lK1GNhD1WPnt6B9uoTa9zVe8ixL9XIR8pTE2e7Yffemokaw7DsltWEXdNXxUpvnSXcXMQjZTG8Vms9N76TkvLSHGygP21mUsczMhSgd/WSk9Gf1yhwmVc4lp0UOFF1ryhuIDMmKVXPeVayljySIrOPrbhUTxEBU0aYU5eMNT8gzlEDQdVme7a8dyc7WHMWpJC8pPO3z/unV/a/L+/oKOsGqgPdyiN6i/bc1YzHtL4wIfm47Li3Qyah7SHUg4CDZjVXzT4v3zLz1XLClDPjl4Zlq2YG5RZEkx1jZqi8WpUwQlRHzyLUlfojai60H4x/a7b/eBrgK/5IwSs6yEO6AdO6OKXt+T+AfFVXnwcZFbg+TmaaXY6/fx/nm4RE1Th8cp2Xnh56cTSETbmrKz2Mo9euitL3H62LrpVDH3RRF90jKbdgbEDXykBdnlktjguYRA7PuTUePRPsVUVY4IUQge5bAG5KznzIJN+fVhoztz+NHAtwjoW1wTr0Qn79R6vXcI7c1giE+TVa8fftkcxGPz3iIzKcaeCs29Fu4H7ZBpG0yRVPekv5PrDjL+p6LXqzozqI70/dZn2kPAMXP7Nz0n5g255GVyZZoaDB74U0dnE3HVKS6/Nn5gB7B6vlwRczr9R44O5eDtrlLcGUQMg8pPpJ4mfSIptdYWT2zeC72MP9kbFSUhkdOICn8QXkhPELEvUF9N8cwN1svI6ohuPRNQ7qgzvOHlxWOM+DasVwdMgU7+3Sob1eyiDF9wOfKAamUrctZnDbQRf2JeUaLyC9DzT0CjI+Kw/uL9Cah23bSMmYAP61TItjiOIh/Ymxlzl8HoJ1H6ZRthzfPPxM+w2fEW2KyD+eRMxZTDO8krmDDARe/w7NwiknwRS2f0B1E/Q66SryB08kQy8TvZU9YAgIiUm0HSf0ezKCVpDs8yCKDnzwx/8bNwwyVjiJYZpTUeNg3HXB8qYrBmUmhvkr5Gr0PB7nDjHc+K5E5tyr/wdfXEndJjAy7I2uD0DHX90lupvGZKfMCER/7btaMBIu2ABuL8U9x0UdJX2752DwYf5tyP5sSeFh+TWkXCWEr5vmz9wqcIwkqw/Vgx2Ola42KiOliwlxJ+1FqdzMdPMZT2YXbbZKBzy91ww8tozmRoLsj4m9tBrMhEkWODcZCWTxPFNZdqvd8BLAGDa6je1tss8JkIWXtJULSnWZv18J++4myKHSUMiegc/1o0BRY9acpJBKeIIx0ksfBgjmm1ShoGkMYPclw+uwjGo/qm1t8Ru80T9lMP8uS4hpL12jSXGazoTe/4e+VWXsFnI95V5NBjlh2sohpDT62VN0GlcWzflPO3Kwevanlfix69BMMay4mRjlO0nNhzEcRbidooLQ3fBs8vvLnfrcIimRjU+NS1XhGtz9I9Edr8xDq19+9XxyihQxVSD8RPeQ0I86D68HoZhkisqmeU64Anj0BHK59DZdAqOUxnREE1lnD9UkAmfhc0S6ihkd3DRFJpTOc/DmvXdLLholNTWRqQ97VxPhgywjaZCMd3HXMgNaMck0fQDBuKEWLZT/M693tQDQKx9gL0u2KSMNNiTCs12Wd1aNK4/+KORCLyjIJlxUuj9bkLTKXJ7CnudIrkkD9ANZ0XnFvmxj26Argx67aGV1BS9LWpS/kuVfQ1ITZxFomAWLK8lheNd7klPpsd/twkl3I62UftFOB7PSHqrx1KgiPd5so8Hc5hnMK4O4b+MT1FeM2CTNDCP4JiZr3REEq2l8/JJEINaBlT22Qizjr1HDNm7Q9p53bvDmqfeytNr8AzxIN44uzNUGLb8+4vt/DwSnWUTgXcH8Eh50hMLuyiSz3SL6UQI0iuYDnvvYWwIKhZL2CzESY8imRJ7+znAzwp6xNcshAXhMkAwUvbBbbw6ViwzmDN7qpIpNYWG+7qeLBcSvG1k5AwRQXrSVS2jLwtR6cbkoCMGblaY2jtPE+HFOvgwffXOAVaq1+b1FQStMQLLw8LtD/6yOmSlpBWvBvctfxknlgvmzOq15cuq6lg96zm4O7cx0G/amjMA2zo5jBSqxENoULRbP+DCXzKAy6LMxrpOvstEE6OeC3B8CBVhv6EwvlWb2ZX9W4iD+HnNC6C66I+tD/kiV6/6unqyB+fnNo+tUjzYqporofnZSOi2a0oEazXP9GrEcyN4kFtm7N9Irf6isEgYexGu6Tn0Qi+xcUqweZeYFUzo5JJOfgoNBahRCYLKJKqDcw8+58l9DCFaGIG223NaY/4MOJE1AMDrlJcVV0FSfWu0yUWDDuHI+kQ0mMyuHOAFrBbfsEN9/9KoqRWmc7nSQ0/7gN9feWZk2nNXd0kzRpf7VJtS0w5rcWDNl/kaZ9KyVGTysEojDE9XiQZ92qWF9NtppDmXnPaF2WhR/8wHzchal34oJIxleK3i4eN+gs3tKw5KVt1zhmn+nowikyYZuo2/+AvjdHhOi5tXiKp4z+s4Gtv96yLkj7ixzPCYdUke//sbyiLpnBve55yAZGbWKC2ECurhGvIbqq3g7Z537hiywHq9dj7M+EgMVFdqNaLSVApJMEKYZBkMOwGIse0R8jMPqwsxrut5DGCnvRUxmXmTQz1CrD8PX1bQlnpOcFKewUYZj+PTV9b0t+L7HkYfHVutBYTLoLkEirgMXmy89JAvzeXpAwQybq3y/spSvSgNnVQoFUQQuN+wDW5CCJxbnFCHQlevAY7/uhvNauzQA9XtuHe24p6ZVih5WVNeoCtTnHR9HRTj4g5CHHwIDmCgJwFzV9QMyKjhBL/kAJ01eXbz9roJEVLiZ9cPkG+GYihhuUXUYpU2IPC5UjuTHk88svQezNhT83Q5037alC0j6vuA3lBBlO5Iet+ahQmYl9CbSr8nliCUIf5Zw7Xuf5a/WRWXGXh3xYHNEdNOXLlck96MQayEq5OO6kvRLjmAvpl/p4jjJ9kqyS472heosG12XA0yYXUaeZJQbUz6NSr9ovdWxvY64moJp531Gp4uSh6xxZrtsxCVns1VFLJ9vQ2vd562qRnO2FXbTUnNwPgnNFMqx1E1pIocz/7uZN/coRERnbf6xSKR/B9nWIE1COaOCtS+Bfw6JRLG17gZ+jUZwHrZ0xeoAekrEJpGCMTzY01HhSQUp7pc0/p80VFr+8R+A0r0gIsQY3tclP4KRCpKAAdwuCYtA73WItDWj4UkrG9NxY2M0XgaKNuwwDu551hHFO4rvnIu5/j5wMD9rrUBAA0PzeRhFRsKW81D36Lcw4jj/MJDLosoOOLMsMGHKW7rNY8kYYHbJMEZtuecGzHv72KCLYeoFhvrsW6cs7s4IX6Ufm7T6Wf2U35VUkfm/sQDf9tvDaASzFdNtgvkdLDyExXI0VPIaYlLxea2dM2MYhkas+3vI32HUZ431ZD3g8fbLlmG/ZRUQLZ+4FLw0RlRpSIO8pNobMIlmoLU14o90p6iaubHFDDCzfcNIbTWjqvWg+ghLNcUqZqQzQ4zrlER1dN8b0EjWkocKBINUd10T0LzljoL77JGCptoO0K5Ctyq5DPcLNBHVOv/rDbgqJiuni9pGaB6OlD4P8chRpFYKFR4OjWAxtd9U/CNKARt/BNkG6hLGwWbEenGYWqZh8uZtQr3+ActVkraPNpHapuRg4dXFKVq1W2O2ASIS4KeQK1zs1yrAXuiLizpSSnW/n0yBsx940p4frpBDIbit2ceyfkbsdvCjaSkI1uw8x8K0S0AyVyGpl6hUjEfYBF3sLk6D17bAcyECi72cBWBAtxwo9QnjLEoICIgxna91jB8JhTn+5WTmjPF+24YiQL/e1DnN8YkZCa9agbFaXWy0T8TM9muuB2D5epan082T101WJwkVqEphNBmolhYhzyKTKbjySo8olBWRXcvgn60WnwmzBnhlvOH1Fyim2xYPbDyx7RC5pngEkabCyx2wygPFRjuH8q8HNjfyNo3V0qLbPC68yLYASxb5i+V1vuHMu9l91B79gxQTNtkyY0s1g3vKI0bUJj5kzuIJUBBO3FAI9vtuhI/fY8jZPr2sKeNDt2htNdDBxBoIDFfgZRUp2o6zaI5diJbpEgLRcF31J968K7g2QH8JXWeMVDxaeDOYOAkFT1kIDSSq8IPdQ1hdTybeKfh5SILjMtXZk2fQ4LN/8Jb0wDBfArpdoqhhj1TAKbT7pIRNVeIALzFqZd1PsuMR9hoQiOQMDAmhCISgj/7Zwmcf0vzRmjNVIu4NH25hh9gqY+GU8xXVl7DHGHI3mzQdYyEYYx5D2ePva1MvlbYletNeCIuhBgeaLqIEYIHLpnJyw7T6AKzuS8cHxwvU4MaLk44HhMtMp2Ciw1g5LM2w/7BlsOFNZWPzAuDyIkyEvMyAEGT0XjOTqI5kXWXzT72X/yDamQX7z4Zgs++J5YFVy0A+9IhXnzdjxy8tDE2oKpNNr6GX7ExEUo32e4ZiVDRRKiArcOeaHm8V33S0ZwrnxVDy+5XkLv9gyvW25npkvhzZzR6trQ7LqgK7C0T+peg3dWdKiSPudwmw6zEpWJeCyHgW5PyGFPgY3GK0H51V2UjuszFUmI0K+X3Oe6JIpwci6v/7GTM5zfoCVa+tFr1XfHhW3bNezyXRTzk1efcN8IaNWpVHRjXl+IAeJYciAyOPhDH54flYEYKVCQJL1MswHJPuF0JJSIHuU353XiDX1bIacL2PRPZv8HF4tf8yPFiZ0ArOilfUV7G+G7bop1vWS3+ww4i32Tj9LcaS1XnLhPJJvGn2JLfWSx8qIzV9VwR+gHr2yxt+cdD8c8sqZzvucWk/CIc45MZ6blJZes2juV+GnzacpEFX+DAhzdkuIrvCL07frCQ0giKKWCPsMFYg9efDwG46ps9Gnzsko9m1m7iZeGnwUzgtqS2M9rLac4EE5hk+97Or7rAs8sRee8eculxaUNT17n2gNBkgRTWsOtjcPxbmmAYeFjW6QG+H3LzYXuo97OWbplpvoYQr+SP8Xa0/MoDS6EOCkjJg69EX8OqWMDiZ5Ty1y8wPcQ9Ns8oNOSJFljxrlXIU0nekN3jPG0xxtWpXZp1COZK6QKOKLFrEUN0vFxkIid0a+R3ZnxsCKVlECysFVTVsJ8Bk1o1/QZGfixUyA1RriUlXiyOfS4z1who+q/HME3ZeS8uZRGz0aEBcREWmWv7o5XOJOgvAgcO5ldCeWVRNmVC6r+koOUc7rz6S4BAcTTpIdYMfxCQruQOtW+Q906Ic4WUG9LaxuR4RgItPrRvX29bgkq9uOScPO1zhxdRLbQ/kBtevEg655SkFbPPJiTmsLPH7lEJeBr28hclZrVT70jsjtHQf1EqMlzCkLPyBX70y1424G+G/a2guxo+xFsjrigq6a+WSiyuHjQs7JyddV+UJ3a8Sz58zvlVvTBQA9zcFlwPUWz6n2bu7g0Dw+SCo7pFI5TX+n6s4g6XYTkaf6FS6Lw1Tb38aIg54vZFhP076a66ZGT1Uq85JizUSyn/Vo+dABvXFVM16+Xn9K5P7kugGdAc87Y742qiCWmcWsBjaklGTdoGNNzcRvvQZeoB3oN6p003fWGjQvWKZcfjDLBGNZ7lvBhnVjzhJoX2iPNka2uMCjLX9s7eAtEDbn8AX/p6sbr2278PoyX8k803VQgVtc1l4VDvLVvEowQfCtF2fl8irYbqiWAlaYN1+Fub0zpr8vwaGHZQIlVeTXZOFmzraGNhsqvbS6/MuiUszywSxDUNj5xc7PlVD3iGMjPIwI7LLWVEezY4chKHitGYP9jiFL7Oaqt9qwVD0mRcKjDix6HO6qcCtr7AeN7TNF+YTjCzLOGq1c09ASUzw2Y01SobFr/whpKBt54856ahPBiQ/lsNgwKzIUBat6oAPNKvdB8t/Xm9yofwWkC3LErLJJgefMl3kPfQYILs8q294hzyTjMwfXc/3TIUyi4LLsMZCQEdUyoQTw8p0ADDmYlG2v9zLNNUVyIBptMiCw9ByZJyKCgPS3oJtUE+SUEsBCqtC6wXN8unlC/GtYZ3nD2xLAV7UyWRyXss6Bf3cxQLVUFP76w1+jozMCubVVhyJEO0Hw918LlubH5oPAzI8K9Lxo2ZPzoqc5f4rjqH2Y/C3SKgKrBKTnYDHsrHJqCTvkLOWZ7y8aBMkeXff+ZK5oi3VdY2c+ksqzNK0hk3a6sDMeqH8fO7wQS3TzIhoh8fiCfgJMrdWUdd+bFSK9dqGDj8o+gz5VRyBpU3NKUpJXatBwCLr4n8Xq76PCdZaZY/V94ZvIOlD8LdgZAHGOGlbC+pu++YLPJSSDNrYgsLbOQ4tDapOWw95nA0eKpY3XDqxzI2bWDEISeSBp2UfuKlZQNzG9FQRSa1sdoGBHdKcTP5WyRJmf8GPJVfgpct88SBT3CdDOwtODJBj7kuKfhNUHft9W39LRA29ARjGDGYfwHL7iFEZ9GmqLu6aCdMQtqKmt/EgpzhRRjMQ9sbcy+CRqydC7LFpi7UT4jt3W+i0Q4v3JOLu5zTHIgMP7AZhE+DfhB61GgeToK5cIYQDmW8O5nhc110Frqz2Dj8fus3rE+fAJbeJubVYYO25hcS6iIFepeHQ+Xayp5Lr5oSV4AjzUiegp9xwHioYGcGG+QaHoFbdwgOcaMuz1VbMn/utUtaiBaffU3/pWeysOlL7eR0/BYyTvzmeezgCeJKL3revxWuSyINSSst083N9syjH/eB73Bscy2t+T7eXYDX/ak7Gb/bOujc66++WWNWFRHMvydeUO8xpeuHnMNg5vsdO9OnQtxTozzqN51Y3PX/lJz63DqBBuM8NFg3eP2lsRlxWelA3fMetms+avn/WtgKd5aLmc6BzWxKztOHQgqk98RnGF7IyqRYlXnn6UphV6dg1AlDZaES2F7ZSFezaxepGFmRFsPqz3bW7jxwwcwcNzvV6wB96hhuEKCAXrirk4pP7R8Mh2xAaQBBrrI7FCzpwcE3EENEl4nvEwqGm6TuisGblO0liaV4RXoxXBZVngTb0yzCthfDQUWtgjjFQT62Y+u5SPnQjkMS97YSzx3TZRXmUUP0vPXUndFGOqOW5wXjWDnhfjU/MvHF2b0Dja3v4mfNAK/Yqs2PnRXw25mlg1jsPju7KhOBeEVRwsZ36fzKLWimMSE5eEu4kch7dkGIIbK2n1IOGyWHLks8gqfkr36gmuEeO8ZeDCM1YiN8oulF0TU5k0irVrCpNvoe/Om3yPklqVeAWhhPrBV5teF4iwwioydnaiPJdQn5NgebBdKBrhoavy0NlHo350GLk3HHd0m+tDj44SFsba9UdFDpnP+4tA2+RdUMGCUl4B/Ms7rW29iErlfKaVsZlk+Uyjz+brq+66u6QTtCCYyxAuoM4meizEgcfmuAvTrrY4BNEjF/C4Nie8eBqGrGBekhYSmLZ3EDihf6dCnwfFgHzCxi9STWGcDNbVwYuELCsc3qDr6gchvMZ6Z1p/Qmz7rCzEq7EZqnjxD0R3ZdS3c9ihnxlPPOXEwDR/w6DV2lW/V4nXzcGjW9oVyGtZ4InBMi09G5I9Q2dYDESCawNPrLvkKKOLpwq43Deh4wHlO8+lasW/76T/zGon/zCupOzjOgbk760bS5FgJ9qyHhyEKoHnFsgLORJCyCX4ValYK2lRNbnyCvQZ8F1aOMGAYLPtp89QwEqaAF+IxAU4f7ahe9r22Z/jKcsWcIRFTEGE5mCWdxsAy9TcGXh5OSvT1iX8tUjSyMMxqC8QE/fkM+IYgPU/bfIIMRKbfN1aEgGgmuEj1sBsWHbNfIAdidl3qFtY92Xdrzu0NJ7oOOyuEtgZ/A4U6rCdwYeulCmiSmP3U1JQENOwRQI4dkUkt7eU+xYJVQ80KDJc8MPGi1nWUTtE/5H7t/C46Q7ZqJyhTqvnvW+jdNbg0T5cXcW6gw/FE85C1yPHjJ3R2hOyfPhW09O7yI6np83jbWhW4QqDWsO64Jrvb/x110x1HlIclAF9mL3eAlqU0Rn3eouTVUiTnyXWAK6DZ4kzl8Mmld8cIRcNbwZriYapbpDaUjoMVBze9ytj6lBr8UNb4Eg4OhM6sHlmVPDLKOB+lK/9j1civ/hf9zKNZdvAGInkKvUxmn84q+JfEVukLXHwZz/0RFXKFkZ6yzRMFG3sPrnO9F51IfX0Itt6Z+cH1LuXHvV+3R5HSerFKInsM6B3ZFCu9NuWcsnBK70PSpA0Tz/L9wwh/LavMmqVmDmAPP54aYgAbervhX5sCBB+S/MM3RfnR7NJtl3+QSzV2Qczo9avEZc/wA3vF6Gh/yM8DhXZbx+a8Mi32Q1pCqdBTmCvvdnhBgpyvJhZY6Aabsi3UpTo6Br3hK5KGOfiHemdp8OlcEmnsXASofXxbKzLwqFtUjiNYTXoAZs8X2EfK0TBqPTQOLQTgaS7Xil1knIoRRghpyaxXc9T/kLp8VLKWS54BanHiQYkYIBH8t0ALGH/s2WuSCyhqPhSqPrk4GwwFjJwKyb+7L1+wSgdNAJxMmNESttsCNsAGcRFmUH+mha5zy9eK2pzmHUIqI+UODJu5zqBhGP83+NFxrtBDApmUdnWX769mtcXM8tSyEof0PZO1JSPCZJyu0mlbgf5nqKhHZp0oFh+rvAq5K20LAjeWg2g2/fnSVtFyJaeEaKwJ6sBQaWQ67TQ6W7ma4HWYxF9Qn+K3/EwkneqaCpdgN5r9jtS0DrMr5Y1Yo8xUWWNsNMxW1fMgqzSZdywFV/EgEUAKTXTJn4LgbQ4eShRDwNEmHIr2dHrYLnEkfW1ZYPhZj5gNjcKBKpSmPfF7U6b0RNmuVOvxZAsSGZSBeFGBwn5u9uiXVZO2l5ULG82JxSKx7oCo608FaUTp7QgjMlMDkdlvr9vVYOdNJ+CpTpnQGY/FbnYlEMaSFgq7btisiL0bQ845VdT7kNFmsDxCk3h7l8sZHYLRWly8CiTZmtaHRmYlPlit7JIcOTGKg8P87OhhKwrFJcoCeCE3uOHE4G7sot7f2Pde7BQmaKShw7nb9fUQI4PWbOKbA40f79LI1w0QFqWqQF7zP3EYSnZZIQVtMIJasMABjEngo9Z0JWr+OeDX/en8EKS3iJaJabVi/Z9BiKXsTx0MbOm1+DhvCrWeldcSqemuXttO59kTfISjSWvaoy1d6DW7pn8TOt6Zg6Xr6oir7/NUOLv5th1of/DiyrspdTj1RBSyTe+13q94dTagzNcTHYp7vaZDVgoTnLyd8oyRtqxcQx6CrxMLbywAPI92QShxfxZmUtr2+D3kIAdctWY+daq5pTcBCILT45crBb6OjKJR65PWCNV9tTTDME4SlJFV8uUpGqPzL5wGTqP1lblczJ0ATWaSjVxZBq77KgZAiOJY0nduEfneb6h52HAAb9Xd3ZVAX5EYcrkCLwhZcdphGSeAxLyTHWpSYs5rz1L0IPosQsZ/NnJd89ymv7zKW9TDuPOU1jpM8Q/mn1hZon3RIuLDrhnihhc4QAhfssj+jIbVlYgPmSmaNHbV01o0RJ5D8nbGxQLb0al4/sJLxs+dSG+H7Bcop0NcULfU7hrVYhzcmQ4YhfjSSuofVob7xmbOY0ULlkvWe+tMNDxSRU6I/DZdFmoBiVGH55zFg3NAc9ujpTsqcknfZtZoV1jHMEjrMt2nHiLaxDuH0wr0opg5AWyJRZXFUVhyF2Iqa2WDwbSoFOcax+7Wl13w77316vVpScxDc2Oqv3x+f4+g5r2VlYmr3AbXLwyTrmX75tJL+yjM4zYp74qBPZg9oOQTB+l8wwDkqGUSUEa0NVGbO67McuB0+8MT1D6zox50C+MuX+xHMerNufcrhwurGjAVIpxAN1B3q6hPnI1RLoX4nqJH7ZX8ftKIeaQYkAdhrS4+IURIkRXh0/gUrI0G6/Kh1O/95UGJgmD7j6vIFula0KRbh3czl+b7BHfgVjCJRWvEkKgnWKMPPUZ2xU5tQQS1xXfgfCD0DepIgIYT53oBB0oU1YIiGzKSlu8/F14tEGvzsBbd7C2RH8jaB2bYZmxJybniq7zOtAnSEbbOKVacR26couyswBnqhQoqs6tVK5ciS6w6dCJ/pBWurFHDxOr857BMGQNYQOO71mGOJxRiuPDDoEt+zzOnjpyyWG1QEmwoCPZKtA9NLnTtRLycDwBGz8JmH3Cd/oPDMnmqB1hZxEIi1hoTZme8pU8cJoUsBgT1MtmrmUz1APz7bDlZlL4jwGXxOtbzH5CYWI9e0mRZRKgd5hGs/rxyO3PIVeCVEq+hwW7yA7AcfiFHZpvWVQy401q0qAkI+DqZkPdPSi438zxVcH08NbwosNM3hOHt2UWFql2GOh+CZTIJsAbhZAv3ElPswsm4PE4c4KELN1s3rbF23Y6ZRoUa3iKYivbVlbWstATyHp28gef34125HBgEKuPYwtQaKHh+2dqu23fuJeZycXywfhEIO9Ccv+42T8CCK1X2d4/znpc7FIrjfZsk+THO4/Weg7LD7ahRyRyddNd3YFPtsNZ6T10Q5Z0SyCcgu2KFKIM5PQujXADwaS/7cezeoFLQ85x2slHEwtpUjbB/V70xgLt9PevTGXK8jDNbkMv8R5LPGztvdO3HSta0E/qbV5/GCSNMY/4gVw0Yk7Og5eZcYSfRqnkYldAhUPnsFkM7wjF/bpkUK3v5EsQC66MiDCbBhTWbfv41DHgpJwMqsg1ePjvKAF88ek9+gvbrvcN2kFodfN0OMnaby/9OvOheoCvi9TCtv5IVVa7EE88S9xQTWHCFuPbtHtBu5toLzWQOOJ6/TJfUBo+0u3w+v6JxCJiewJ4+FIXu08JbVxeJ/cA1a43I9JvPLaaO5oi6/+WdYC9chVAssLpfWMTQ8Zb+f0Q1CKcXFOhNoi28ZCjojXzBIQ1nhf24qYFNgWcHBkAhe7+OgXx9AG3sdKfY0UHuuFf95ravQL9Fsu+LyhTUrhJlgDJI9lYLXa7FS1wmuI3ZOph+dfTq/Fw9WayjCv8GqH/YsQA5OFqO1fZDoRYijA/S4HBPnA8CNkZl3oOyx8hU8+WFkjN0++7jsHfFh0UFOJNYCXwMkCcVpwHtO8gEWj2v/cjsjXJcWuBfVwDZguAJnKAqnfFdiFjtfM93A2j3MpPIg9LOArHaWm9Itdp29E2haxcAly+2uINwS+nm3UuUAdVQgYZDIaNV6N+Gl/WFK0a2Vc5IJa4mEZY5ImmEdc/hoh4U7PUG0hp5dDlLkgWZYoc+1BGJztTZ7dwDneSF2fJfI1AE2hL8GLTNIuDl5luldXrOgXHC2lNuLEYBhMz0wbljeQz1qaqQWR13G0hBp9Kc0qBP8lQwa1XT/CQztYQ/+EIe9Rz1qGYQPQ4RPIs6Y+SyiX7RCXd2RS9ByAPmCzUQoe7mbrx1gS/lRVLDw+vuem1lVBFZdYEpcKJp4xLeKEc5cdCJVwDsdY3TR7EXvePiASpbs/PesCn+GTf3aQCXU6+Nrq+y5q5gyhrQQbcKLW67SyBg0hGF37ICm4XF7PXTQKd6uxFsoCuw33ANeZFmhT+rIu/RA7sOPh+OBTPYzCKOSvgf5B9IIt8jDrMwOTaBXHawCwkmHlJzqfOxjU0HtJtgK51YQq6Afaqams0tgvKK/uS0cXAWprd6zeYJYL9RtICCq0ScsXzu65eaMAlZnLWlFfIAywhO5S9MW1jRV5koWiUMSCTQm1uOCJfLhnlqnurFGfuHrYuED6sLLQeDBBUhIhV916s9FtBGJGcFt0QLtJzoNo91TWAZaBfzVPnujeAImRFMFwPEccXC6NeZu7Bd6HlLHECdn0xojNK6j4JjOgb/qUXX20nXI2BsQs95SDJAfjbVMRnSqsVYIawqbHh+uTKNgzFm16XageM7wFr+ZdcYKMhKCbBkFVTLHHHl8bv2CQwar16OtmbcJ29P3uA/qRj5zZmQzkjMHrYE6LzikDT3aPtWeWtoDPu+ZX4Mdf0umGeXO6zgYr0r08uMhAgaeAdF4hqzVXOdFwRKibS7AJuMX9hID/dnkE/gOd+uoxxqvBqgPKyU4D7mNmoI8qosqdNsyyU/nMWyRyjt3EvyFjJnQL+pQV7eAO54/uzOxl0se2SsjqPM4yKPy7knaXluS/HreZxVgfZC1anJwaSZbffHEn3kqYfqOJ7blnvJKhfVtGhXu/PbSUG0+igt49a3uq3LWNtcGi/A4rERrtnEJRW4h4OloFZst4S3kTHDUnuP2IoGEfiJeMBiichPfkb3tWiooiPeEigxbobUZpbiY11JueZXDi+A4U2H9ggJEcIudy62WMsCXFjcKvgCOSyzCnK+y6CsTUvGut9vnXUXsFSt/xqa2lNWuivg7aC0r5BT9o6pPap5dQRso1eH/mDXMGNtrHzLpukpYGbB78H3k55pzDNqBIhZEi+TYwix/PraPzss2mSF2mqRDRPKHvYODPUaRl3VvyTM5kfSMBBxfb/bV5GeVGA6VhfAnFOw8RvMzmTFBSndJLYcFHIJxMPM81uFnh/YutqaCwP1tetuRkQiTEp6lj9y2z9OmvMRd1sbgQUTo+jp52cp93DUOXYCLCEawVOonLvJuymYulPV6sXTI7wPNRttrFaJ3cNDGeltNXa7gQqAD2xnHrdLa8pO3IW0poVMI0fJHR5ltvzOUKfujgpr3cInaOLJmxjooSjBkZAcbYj6b0CXiMpdWhDvvzuKxNo9s70dXqudoiwxDAgb6xiFekliiEc4ey8RDXCNDGUCghWhY607wlxZB+khyoOy0JhtjNtz+dpLffQGtgyRg2fhDLuhku4ItytNonH0oPNL5e9iw/r0ecLRV6w7+17pJwYwhdPLwuoVai1gEi+pQvYzISkZ8/6ImXWuWHKcxYD3DRTEq/miUr9wdaXFbJJf7o0E3+9DnxBBaoeVPFClNT655+XaztD0Qz4Dtt4l0ned3Xo/30i+7hdSquMFJIuOAoWFSxsSBffLVrZ93IvVFDqGtFiQkpgArpWG/CkMe808JS5ccFPS+g39wwDu21NGbVzNIhXHA18fQQVlnUVn/RelqCp0212HDRN0M6PatVgoMnDftMMq3J1jA+/02qYW45PYXr9qhE8p/eb83AmMqrLyxl1JyUmh8BTq3NM83BHvHVbfsKxDZhSt8NptoSAsY5VpQadS9dxvZMjY8XaeeysIiEZEj47DY41IA6/+Qys06eyx42eyomcCTCmseEuvbsuDymDLWcCWUHPwLG7mSU3HpDAIrnsGU3gJOjEAhf6Wtgqb2OIKRmUbVkvpjXTZRAz7PlqQl8nBNSN13v1x0RNiyVD9jyRX5VPzAiRJ59f1M3b5+tXjPljidYJX7U01buZLaYi+LLJCt1MNXA5Xi349f4AYwMUtEuCgrxHokCg1H/AKxzbctlRU7g16ooTGbHTDxk3kOlDgCiOmah2Hi8nwKTQXrtvcx6YZ6Fte403eYuVjnBT+nvHSz7pscr8+xiKlRIy0WppLDY+YzzNTTBxh8AS3xLJQNgER751Ud7iREFJEn0qekFfLlQLqiwFi5RGQrF+dZvRDNxZivIUkpWkRBauwp2IVTyrfzT/vSy3irOsxnzNCwAi1m+EyoQZKH+PqGbSwIkhSQB7ljNLGaPrjZGcGQlukPPsBwhcQ4IKdnaeEsw+/JLe+NpCVBEYa8isW2mZH0NgSTIKproqHk6VM6ALV3zQsLzmtuZpMH9gfRVKauizFxtjJ50nJ5/iLEZmHYjsXy63dv0mzYM+2wjT1ZTd13Y2CgqnwDP/4aE0mUgsbj0D6sKEpFYTIyXXAddldIPuDZW1IRe8yLgRScgUFnVkVtEJRjTPu2NV64xopBO7blcFhBr5cgFU+y/dnrn+WPrhEIpc5RPnugGwDJTqXHMAR05YP1cC5S4ylNZ0zm+n9uRD219A9klI3zQV0vtLVrOIgvWmBi3eRe1E2JFxfrs2OXERLZMLualxG7yV1K0MD0ZQXM8z3z8wOMbWa/n8kuBr1ap+uMtJnu28NaS8x77MYQm4J2Fx6FJAx97MemlV5ED7bX4TJpKnWZZ8+h7e+F+/q3xEVS+7BwoL16EUSL3xI1/ohw96Ok28NUiryELPfGgNWKVU2pST4KEwGfu/lJgoIPHbPNTFy7I3yhIEQcB79xxjjOzXTrBaTmmG/cYojnT3fJGlNmIQ+RltqQ4C5x/6PyQKus0IQcHqGf+kwWsLyMLdQjbZ6FFd9VfI+CW+htiWg5S6CthsfkRulgmnjwyrYqBeIoHH56GiRdFMaakKw6QCRyYxA71KwQ9t0l6c64ZPpw1JhrZq1jwzZwOThrTk1XAelLOQqu+TPebk5dtEVtZ3oBpPdGTnLw5b7ddvsxyLvOt9MBDOsCJpgkOYMhvZ4nJcO6IzGO49ksmg+r4isOIv9mQIaMppQh5QapI+oj8HOwVIRrP9hm0viKnOxNcNqZfp2TqALIDRuETWB8NpE6maCB5yaO8gX7oZIuR/nTXgjckkOo5i0IO3opprBMKlpk4VI2J79Uy1JfB49BaU1hHtHlgAwr6csXEGHG3wW3k40dcjfAGO+IJZb0ykTOtuFGkdzvvw3xvFVjmcRtMMOO4cM3s97VH3n5FRg7DZ38akKZvhVEaPYfmDRKq/d5T1aLKcN+WlnCD+wrsSdlbImGopHEFVBoAaUL8r2dd6X2i0fc+qmaK9xnZLvlHBoB5q5nw3C08koB8rFQSGoccquHDe+P0vKYDddI4dmew36w71CLKZu6fpCRjz3ZF51ZMIGnDwgWlLkz+y8Y8wQEp5c1iuuIQv5IVbDcA0bmicmx7T5JNAm0+hxk09mVEP3r9A4b1yTHYVLGjpt42Unu2I+nnGi9jfs4MwLbB2ixBT15QSBt2fR1j0kxPCpJUqACtJ3T8M4GmibUAK+flN0QMKaT7lV7vdOaaC9Sm3n+fVAbI8pYsnsx59a/cGwH5YKAqatuqe0cUZh5VzEXkuoKwnz2LnpqWsNzQR99b5EBh5jFfh81CGzPBxHLp9J+oLrupHFEufQZjDUJvQXJKnSRKsv4w5dKvtHtMjaU412c8oPfWjtNFt2/HwC865ySMNAAKVSALY++dM3Cls+y2BqXm1K0qMO7yZE3ADG1vhuDQzAK99IrC1qJs2SHo8tZL28NyioZ6Awm7wMcp6NhKJCNf2NFXcQNB0sH1plJNb16zK6dHbXzttoxlwP5TvRGZo5rx4zXh+28PfN63dlidLGMLji3pFGziyH1E63bzKg+T1QM/qySHwz1yojato4CE48gvHC1EE8T6HKxA9cpLIn4JJWfZWFdO5At8b+6QVcKxBCoxZ2hNkdUnOpW92euM+3i8/yqjKtUKvU+Fu3POSzLOU62frrCXQy2GByo9ktGtOFRUS47T522ESAT8jNvGE/pIyNnDA77ii6Dj6NxxZRCD5flefLRsvTKTZwPlQ57yAED1jy97kXdC5juBhcsquot3tj3/ve040hzrOCOXFRYEMvTtUToICaJS5j7WlBS0izfegLl8ZGLu9i/9GIluQp2ZOo5/fAv8QP59Gz12qQe07TjB/68JkIv0ZTKtPzhtekRqttnwpRQ/tMJNMepRvgmyY+A1O/b11ZxMdafn7KWi+Cv4YZH0gH2O8zAR1SpZij7F73E74VstA5M32ekKzKjbC3lg7kDGWxNxb4cHv+r74XUeXybDloFcPv5gxuQNSvfvjLbtTC0yYB8mMwjgfsGLJ3kQ+1aqakpaPrgY8cSvPQvYd4lHAS89bczkgLTrB34pFMmmd+P4+5ATquj3ZcvzKWSq4Z8rJzQ07KEn9mxBeSteP8x23KV/vy+FTsYPJMNgzR1UcWhjlRPn5aXaVnhItOSg4SC67IOZ5kr4fU+PVEqepNpFwSeOtkuNje9Tbx+SyeYUgGfWuFXc0ReRGJtmcreYyE+BMWyG20Ooq5u6uZlm2y9mzcXeCoZwx4HtOSC8LaP2jWvld5zq/3OOPw26w0zdX0xm/Hg79CJZhTO+ODz4oZmqKyRms3eJyKZrOgRzi9B0GYL91l9JEmJhuB8HX3vzW2tCMVDsj3Ql6OFBvozA493HFTGUPxUNZsJefYWLsj8RSKyGbsoYBgsgDRoIYhb06BR1uKEiiquiu5tgdCu7jYkGMA8zN9dKOeafAOjK4ixufQDJlapw0+LC8jX+2p2/h/v29CGpzL7k1Jt26N0WkOuPAU9+S45l0tC7gFebtdbH8OjoR56WwZ0uq4kLup4LCWUYqATxTONFkKwRCljTisnCNUIapgFLH4VK/L6hUAwdKQXECRjGHWhk6QfwpsFuPp8lrPp+/akVKBnzW8rhR2VLY8pZug7MY5Jr8wq0p1aPZKETCI8Lz53bAcpZxUVuTowZnfdOktRxoMHeMPLa/yYIAOOGmT/Fdh2D5defQlXbkcdX1T1205hQanoz9gP5RVsHjzyvWGbaeO1+0STsgU1fCuErElhaSdHj5M8OWAogICLrHZcwQhRDF8OR1pvyE5wrF+v7FCCe2TfefaBNRFhprCOkAPWj2XnAsaqGpZY2p4wJ7N2h4EhRvPi2Zk+Z9BT0weQyM1kkPsGdORDY5ZT3FsE/25xTR+25ma0lSD2CzKlJZxLuArMVlT8hvvjzsESfKhefwcdsDqgy/dEfLriNUKH8AZ1nz/G0OXatbKH+BfJv6iF34DoiMzYU2hX9miVHIuvaOUP+iLpyFlGtnsKmfbZNProNuPsk4uJkY1BhJejHkO9ekKeWyaYMRCHhYamMJS7/K+DQ9jm4eUUnRxYInT+jrlY7Q5na56p7kB2Kl9NMTBzl381Vo+yPtocTIblsL+Gp6L6S3QWLI7W69x+DXCyB4/AMFgQIF0qYeRqRPm1A6DCXmk/FDodse87U8r1rUZBgWO+8hwD/K96RtVahiXMOlwG3W9ZSx5JXWKnOE8ddj/kWCxZoGV2wjb/9IT8/0WpwqAGnBVCFd+Wu9Yhl6HrH+eUYYUHdGdd0gJrUbwOiPfBC4gHX5FQyFQ381gOjyS130jG7mbu9HGglDfK+3kvzCnaqOuFj1HSwL4vB5vV2rYkG6Euy7RT6AwZM09Q9CO1MzB/IGcjSH3rZMVOmMW+m1vkRvGSci5f4RwBHGdq44KR0Q6SfkaH8QhZkHOAqRdgvbeW/xycMA/qhoZQPXTh/TqCfNMaHOkI4BvRvhjRGHjo7vBMl2PETNTq1Vc6MZYCl6Tx8pTeIlF4GlVykjtLfCrRaSsMjOe7krBO1kd1910+gYDL3kFbab4NUkHraT8OpVc62hkdrcfQiS6AXRKabwxwUTyqqOGz8XA95uyG3pskhdL8umTSPZCJHwuAMaEZLvkQaOZPqEu3Flb4uD/GESMImiACHYV2VfwIrmxCE3y7qoH2+YHj9eCkWZx+3miwR/QcAG7+ghFQzVUXzWs0g02AUnve35Oqg6HjAddGdv902mQoO3bXjDwwwzSRYNG10ZDmdx9JybK4BUJjbE8Lq9hKaNPWu7fLYjTPg9c4z3UApzkwr97kUeOZWBcVNWu9gSVyqbkjsWCV88Zlf6oyDunrP4iQqwaaSszc7FA0LBD3GuRlU/k/Q/FfhNzglQd0/V1JvyIQHbBrcnWr7PvD11sWkoyty3s9n1CKbq7bzI4mfXNOENgjwz9UBwGLSC1IJ66BlEAs49KINI/PE/+5iW4KZJS+BFR0dXsz/tUkPlSQ6DkbFx/F4tWmAk4IWh2cq+d3qF+9nWxZcxv/nA6d9M4NjFbNnmO+APETa8ImyNtSqVm/ZDGSunfHdjA6wiLHydlZZRxCX305leBbS9mxr5Ucup+nMVly7Hsw2okshrpZ4Bhvw9zw865G1LBb5sJ6yqiC4NfrwojcfZh1WHltH2eJ5HKR/Qr5zwJAC1Ubympiii9ALNIovAY10/yFux/+Fvp6+u1VQgAXPQAeZ4UIoQCVtUpWp+to7X7at86/FhiBhvbzVojxwwCRtc+sf1f/0/G0/8slg9THbGbDVoKxndvpIwjq+KCv2volVNXNCfKD/IoVPNtxMRYQqXsFLaExujSEd5PARm7pQhALcf123OhTR2uulNpm+Wyj+n0QkuoD5owy9Aur2WnEUHKu26xBGBgbfEJYLeSHi/7jalWdXT7FHFy7Vj3oYax+Gnn9G4fQJhRn6x+JG/xs7gYv5++WRBuw/N1stJkH9SEUhoryc646n1A4KnSqbvvxlBfqqCv2ullpRtuZV08owbwrVbR8RNxRAcbp1BDdSKmfTc4P4tskzMN91YFA+s++OP0b2VTwv8F69Iv3fdHu19QatJBk2HBIBnarYLd/EN1Eoy943KHblEvzGh1uXeSIZCKx2EEDlVXj5iUGG3UHsX4jr22MTlP/T3F5NItAjofnxAkNmozP1vExJfCjjXb8XIIxDBN7UnHPDnanpkNW2JkvsrARyL5ojkrg3YS1K8LQepzPcXlR1+607xYc24WhbIRonSsYB2HbI6z+aMscOdAmz8gY7w8jGvK8CzVDF0OxanYqAMNjO6J/h62s8uO84QfeBY9seo0kJZSVzDtG5OIJVOvBIjsv1MFLeRNb97dFpvlCmQweUgowKL0f0tnLK8WPSq43a2sOFQIoLAHdFLW5oe/EucKb1BpNT0pfM81xSCA/pi51gP0eXZb2wVQrMpnzaiqZ5HW3/BKghpRswxLwFJgKSNmx2EgxpTRPC2dZuus1i9iGCPH5CZLCiExhyfLluRsU9LEz7x3FbaAlISNcp55btGb8W9PN8mHl9CIxX6EPERnM9ABiY3uZyNp4lJ7q3/zFtXd+6sz4lHUQkX4xk4JhUXM+zp2xcQEHQlZDaZ5ofEAzGr943HdpNhw2KykfN9ACVfsb2RjqlE/7YfGtmANVgkjjwSgRXNi5j7rtb+bfDTiFY7QOfxB4NFcgpIJdW8szEm5T0dF91k3g+l3C/oWOErRMYtlW38Ce5i3bBh33YbrO5Wcc1BtFXA5Yh+y94BWoOkQz/atkX7BZ7pFpsWvUzZrzvDXBO8+1QiRDMTxZbHMkLBnzr/QHO13PKmJ053WhkZOw4wj3Yw9bFH2l7Ecw758CPIaQ8FWEj2XrL1W7CMPAFm5urhSNcyeHimbxXyKxRzXLpoe4ERJBfJrp5Hxj3O4ZnimF2G1Ol+xhsmyiO1McCcXd2Gi9uwcrqdmW7BCSmqVzP/w5bXDzIO53Wlp4SS3/hRsDyFsSI3SP6jwebt50gwWgNb0U7ccHdLlLhI+E0DwgThhpbrmkS7LHpAIDH0iJLSQ9N5GuyNNhRuaRMxChc6Lgso0JrBtnjLVNn7eYeRrIGyM1+CaG76WgvgrN8E+ThiUzYwvFVtursf1Vv+YUP7CRrMkjhjNF4qzzF1Cmw1zA4ejVxstYhv58F1vfRSBqlGruFGJULN20+pTdFpkYmiggU3Qff2gAvVfzMKjwShoS3uj7R16qf7sfVBBjBgvc+IL5CGgqvGpzCAeC7M3/e71dylAH2RiYwoZqgj0c3+M3Blm3tw2Zy1WuICUkR9TMM/O8nJzk5+ro2lmKeA449YOIBgHtGlgH4Gqo4wGj/L2O4O3xCIjg3vz087aZ74fPI+VaU6NXQ4kUjgFPMQs5HYvFWPwcq2MbeXuQgnWCRO4/DjyWk4w8j5CaSCsHeARdGZKZyp7xt5VFWv4jHdjZlS0V0nz1R0eaKZE+yzrUTCz1nWOr5XvupkZ/UEhErNh9hicO++NifhUt8BwEEVscjETcLmMZRfiPCYnbSU5EboiXpfF0yLfKP3H1os8ZXbJKff/UWJfTtN8WsvkAS/r2nwJr+UUCIVU0AZeAY3sM9/dxVDKevAeqZ25c9gFHTvD4KvOJ2IwqC4CtCwSTF228V6PXs1B4FGM12IHrqAHpsGingL+vf6GaHXFprW4ntd4w1MVSr6TkRf+fvvlLuOwvQrBSpjqAiXAfkNY6L/YJ7jZ5RXsZaDKQk8JCzkV58yX5qrme36zU4J0BZZZjhtf4+Stsas+qpL8WjPQTDy8Lzdq7eRvo91Y+VeX1hiK7chT4+gd8bUfgwPTkE/D6HfR9c43Ah2Sizr6+opQcftR+RDlQENEMDkSpYEQikP1G3mLKWcSNwzWCH5PXq9iMzPQo+ayEivnbN+OSvw5rNExpAlhuvW7qaXGTXZviEy9cOdsJcMRrUGLtaHGX59U9JBMOQXJmZyX9h+6bJvzBZdJr9mo+uBBl5sNOADsy1zRhyg4GQTtFNVRqrQgMeySD9dAiLUurU7lxLsbTH3MuOkfRFABd3CHLE+F9nIJFlYHpTFu6Q77CKrR7D+d5xqkGNa0BGHFW3uy9hBg2S9gh9OZnt44eyEpxh4z9lfdz4HBAicNZitKRRy/I9nGn/ZkQqIxHg6VL0bdbMmieFQORm2cPoiMdxGxtuinT4vyFsm2PtB7uI/0u0BoRYFAQBotm3btm3b7mXbtm3b/Nl2N9u2XbOIWcgx8g6s0BaTmXRL4i1vxz76PR6s4JXwd78YJS+DY/NR8eJicoORqLxSz5408OvrvFVuv4CgPNHNSSZz+TFkaOfZGqjC8AHZiK2IbstcVq3SMsc6Kc64fO93UnJZlCmCSQgwQ+scL+rzMAAEDCSG3FFBZsty65HqQ9tr/A7JiIF22KIoyuLgDCzYoF2e9EkiNH2uXD1uebS5zrlUMNwB7Fdv4PSOD1iSnGIPfP0n+IyRnBrMboV9s7y7BSmcJNWP+0hwCsZ7SMV7+/nrAnT8ywOlN7jJ3fk3m0w/Pu0LfZ4Z1dokIGpnQZ3JcvyqGeq6OuWq8X//02FAkX/tbC62Hm12ZbABx9nf8F95K/TfubRHKg/6b9v6eNiUcAf5RRXNKbwMSTj0NsuazYmk1GiWoUsHeUGmutSPYZf8EvVT+Bb4GVYGXg4K1SE/TAaOLWp2hlGJk1YItLYhqpgHpJe1xpf1b1Iou43H02lB0pZ5kJPSdVuFeCHo0OsihoBIt5c6emFssjks6uH0EP/eQoxX2o/+w1dp0v3GSEnsonGlIM01WrKJ7uqw1KBGIpPuYoqZk90GYPnv8ZA+ErEaKohiM9dzElzR+GzGuGrE/APRhxHrXEbT9ZFFoYMSwc4G7oKcOxD/J4Kw5gZvKqIRgiOUiT685vNlCLokhczmuI8fR12rTLywFGVEGnH942fe8ZPFP/783sUqJu04+Dq7WMTL4EDQiQ6rEObc3z8izDbmz17QLsv6QDMDwU2xuxL2VoRw9ux53UMc22RaHK0YJM/324poxH1ao/qoIOEFc2+IlefBwrfQkb6JVRbDQtRCIQ4pqNNmZo/0QM7j36aExMw30CiXbxtNa/dWBQkk/KTo0ZIcGUxNTLRzeZdLUMLR46Iusa1E43AUsZK9j5X4ONqZbMzAB2ZwAA1YzTECL2Jb3BXubi24ONbw+BSbazsy819ZJKW+HiIM3Dv0DQHvKAlwqfKORuhVCTb9Xonp73Swo/VHgkvvX1DM83FaVRDG9MPiJNfEZE3lBR14DJak9vhVOYvYmHo8GhvVt+TMZ57VAr+icehL1eRscdKAU3VB3FqDTszjLfzmVxL3ze9+AiLox9wQ0fj1+kVdKAFlur2G6JpVGh+3oH+jIDGkNw5DPozRf2veyngbNGiqoH/ABB1oj+DNv5z1olCni/dg4n+woR8buY5d3/uanpKi6VV1E2vHgkxMuuqfSOl2bpZfHS0IqFc0kNFKpPcf4fzQ++7MomcwTovT1h7styNpwagKiRi4dEu3NdbJcF26wVMTFN42Mb+6VR2aN0Y83mludh++RevFhPXHjTv6dad4EC5ps3adEYcdxMrq8yyYXN+M9KPig66m4CWfbQ8BWHZggc8bueEe16yRuNdQ4CWNV8u8c2cUqLR40rwqgjpilib/SGC0yEyojKKN+F9vmiZxEhuNHJuMrJznTrrKIDb6MYDfEFf9ySq/5ZdhHWmwEucEooW28Wt1UYBuk/0djRGnEboru5Y3/pDTO3Yupt4y+Ej4mSRS55pvnXe68EE1eysyHdPjkB3DS8jpNSeXZ/iiutBZiWsNrBype72T/9gZYa37Vge03uL5xSxJ1emZDguLy4JftFB2Gm8/N3/OWwB+q2oyRxAhtZKb5yKizeN8znhjNjj01JTDsuG06k2ky1wPOtVlG8F0mC03XBKpl+jwIMlxdpXGv2ra7iI58Bs9+JyAYt5qcY1PRsNTDvKNDTraxRTp09oDzaxS05kgn0+KnlHRu/192Kk8UiLsqHM1E8TJpr9Bmd+cunEGl/QZR1Nba/AiKA5F6OVgjqeWVGOeLs56a2mxYDhzk5wDdGbQjqKWv33/AaYR6PkrQVTJHOSxnFBqnrrVuwjxxESXJSuQiHoGyQ+HC4rVwrb5DbwI5uAmnDPUthS1Be1ilSL6KE5+GA+d+c3/iFpLs2NUQ59JvsK2LSPHCtpyjRkTofgFTnMrHRJhqtuVGFEDpGcXMhMU+pu7+0or2xV+5LeFs7n4zKsK97e3c0OP2j8wUDjUZjFfyP7zmTSqNv7PrvQxovZWT+zgpZtk9BeWGue0PYfc1s/GZRgCMVzlUJAWGyxOtMlZI+2o99v7+QrQr60IzNsBbwd3jWTKuOmWN5n5+uwW63EwFpP+AYkuluXbytcxeJSoKVWTs6eqtLjPp9npxz/NGonQ5p26GoWlDp0CXHy7WU2hugtWUVojNjOZfzcoCUm/kx4XYl2E8Jx69kxW2a4FN30wEL5YylzaOHpslFe6DBucrix603T0dT/c3xNz2ckH0W93z9lvGyWnbxnU/2vvtE51j2YdOU7OggDJCL4uKyH7WK4QPpWKt73XGAZ/55pgBXcXKnYXdx8hrixe6faQiBot3QyIX2A77Igjy20pVrsLi/EDAJIlutg2ZFRx7L+OVRAbDoKaWpon1Ra/7DO/P7jvBiNBGa24o4IeclleTnSZCLWvMHpHM2tOVsV+rVWALwWIjkz8x5qslhnsUlgjjEqQIZAgAEkttcZ1n/HJwFmCa9xbm6TYI/Cv3tYlcc6F5GZTvXUcdDf9Dgf26qUnmfgUWNJoyvo2kaxagn6eY74W3qvPNB9Lz5ValUXeT//kXvMWxCxV/0An3P0JcIdz0BflgrIuyie7rmT7cSvDFEz9tiiNYC4Py8gOSa61spQppUW1pFwnJr4IzQv5L/dhGnzM4F73zJxi/xSX1disJ9RzdF1GEn9OZ4eVWiuB7S7Pi97xxdALZQc9eYgCU/bMI2LEysjVU6Lx/5DdhCZeb/1e6fnonphbwlJQ0SmHM8HGNiIkVb46fRnbEa1Ed38ISfc0C57dDHdnaBiVnVPkkzqtURIXw93lvKZEAt8G5muEmsf331x/LQeeFfUwE0posjvm/q6Gp8ZLEbj9xe5NXIaPg+Y8dRJ+WEJlhVWTP9ybibf2JkY+rxtRR+ROU1ua9ARDHj7PT1jUNOzBVeaW208nIOcmamag2y4Q8qc1vxlAxq4Zm/hzWZrDOwwYGKKC9jZq0JUcM4p4oEkNrEalzyjfLJ+xH04rVPlkKPHn83qBehKlSwoEW707XVyFpqhqTmB6Dn5TpT5+ghPFWdGN/dvaGV5xr6jFGgKHIBch56K+Ei/tqmnG9FCNlPg4Ruu8QlgTRemOu2WG1kEy5+G/R1xWETbzJ59yI/u9CH+1CkT3ESClt9APNVBWu3t/TpDJo6QmD/2VsSTiPJsVRKEVYyMIKmhEp7d3/MQ6/j2Y1lbhjaTuf2TiZsM6Vsvnp79S5dzdrvW2iVTrS4lBg1GJ8v0lMrkqSuTAsONo0YA09lw/I8DEdPDCukcwCkyQJfrpMKlQU4TE+hbkNL9MtKNj85lhB9PrLmx+yBAlf+4wMAUXBq3h+l7F0uVKKxLGzz68daGZH7Ql8qpMP3buYpnodp6QA8WXAzbZo5AhrIimg18mh9e8mCoe7qajwz+kM8xbEsrit2/+eXB2XEhvgz9iw7Ln5QMGqsLlOWN2iHdTHbripPSMZh/va/HsnClxZgz0nW1AaC0Xf678lBIKjXh1Yqqx96Y4PrAEUFGkwfooXDYxEoT8JIjkTqOMRqLupuXuGmBRibTZA/50cXZ57LTIzeO8KTEfoiEh4mnFL1UKGdK5lfDagCs30kw67/cC7kSJWgVXSSade9SJejq8KCXozGCorvCP4M97lfcGV2EIlXN67X+i1GVPdP/xOFXBiMSY6QGeVsm+6jzuR98ggWgM3XoccNIppnhP9JSaexoFkAUsj/BXKee4XnAIbmw8fETRFZsyZkSosdJmUD/S2IqwvPnNF6UgrO4XBvpbaWkKcEyT1/3x6eylHMrABdHMsuqJp3yXwMy5lJ23qw9mmstnHUzQUfofSSsiuE6PpOoW/ThWSunhGp2fZQ/rhCGBY6XVC6xCkdNVmW7aFZ8e2lQYRK/NpnO2OX/YCZAvtGZtTyy+I7/CZfgP6q4ECjI4xMqT8sRVp71Az9+Bn0MKbabSikn6J/oH7fJOwckIL6WjjQLbTNGcA7pziT0o7uMFo4W0lXB5GkHG5NnO4ZmWpuJefOMEnZhiyCGBz5CzQwJLruLh1UWC7pfowmzU/nuXN/1Rx55YJMZlEwoL1nzod8yokSj3vQ+2m7Zbr6qqc0of5OOQkNHr/BKuXm+cEeHN+iwOGl0pn7OvC9e5SvfMVGFCWQvTtW9C4fH1U4qv8eZXfxqN5EHCV2bmHqOaGBLdyssWeVyVtVaNZ2VOKVetmp+5kqJ4bYGZcv9ZI59dCx8lN5K1rOGCAXqS5YQ2uMglXOGKAr2jTF9qyp2/mbo81csCyhOGXp93M9IU7+uS1tC1lp7TCOmVsl/0ZZR34rdmmW9HIQsigmVDJiO21LbSpilWtNO+cbvQj6viYYOaCNkVw2ff4/Kfl6B43niyLpB1NxFRchT0jY6W7pR/jvW26zsA6gVFr33a6nJY95gQxMk2rfbLXpUOFSQITJP1BIsgCU84ikyid9/rWnVvPfMCPtHe0Q45voB64E3EyWExtMoaI9wOXO3EAKy2Id80ss2Q1/5r8vBVVIUBAqxQSkoL/omZOz1ZhJvMt0hfBcavjRbrwOrl+nXtYkw87b78FLP7qg87RIzGDO06Yw9Xx6RTJdbaIpq2B7LmMsRhbLsaz5h0dVwZ5Ws3Katq4+d9/ytCf6K9SoKX8FK6nbrKKEJWFUG2I15pxGk9KMfWI5OscHyN2i8nxxOh+zmssAjeIBNPXuo6Hi2/GGodnsWVyCZoH7sc+GYBnC9GgaanNnNJmosMv0WWgOyG7h3afSjfOWCx154s13aCQUx7EohhCwSTtvkljIULJ8vtrvOArUPM5w3GeN8bISmYYFx1oY+Sg8QlCi8fJjJ4u7ACKuUnxERXs9nRWI5zavmhFXA9ISf3wYg8nSc9L8nj7mqFMPbPvvZtPxebBTPM1Y4m8Ma0pzJPMSTPRrFlYHzpRumdf5N7Y8ico5ZNbJzNKJiPm7h7qfs/fqjMvbxm/q6s4RRUr3lSYEdEEeoI3+QoE4BmVgjNVidFqQLJce/tDYsihr6kRtL8Mj5Y7XTSx7X5Q3ru3WmgiQavmzsgTBNhDzGdBzdZwtUME4t5O/zTA3/2CK8Qp3vq/wFSSBwSSmAQE01e1kaw8y4Za7vMeFJBDdwyN2ywCiRte5qy6LO56ubzcG0vbCPA48m0xNEK9yQdA9dcCSQBhkt6gdml9JM94kJDJUAjKesbxswxLygRgtqTNLx+kw8ZPsDyDV0lu8LUjsAEWNFb0H6kGTQsE6nV1zFuPuAmrrSsCBWZ/O6XTwzSkzquhkVS3vtsnfAmdoHDFlZa+oID5XxWRO8PNoU+yYs5qFEvluAH2bE/6ouBGPKZI0FjoSSI9GcIXAbNtEOW+ZEvUR2omqjlawM/hpXwtyBWOS5mHFZu+/8tnkFrRjc3Lp+5MDFbeck47iqp+gNcBYgrJpeRbg8Wt7ktLSJ5ruKnOGEHMlG9oQJt/Bhv5/QfoqDLyrbgq68PacZR6sFuVaUkUxzW2Q0LXv5mamwr4nI/EJ2vmZefpJ9H3BRFCjvlkFZ8g0hx9pdkmHvDYTOvOoVW4/WusFu08gQObnzzjasRQv0FNKlLmsRuDvK7a3OA5lhsyYPHrP3oEO2dbFDew4T1TJzxCZ/kE+l/FO5ZtZ/pkGie/e0lZYrNOrBKFPx3GE269cZIzbY3+z+agn6GNJV4Wm1/A209Pxf0OhwOaeTQleizaeYpgu6BUkrD1n6okPdt8sPTUuB1pq2zGkuMG2D7wXlsw7PAbJMTT0DZ2pW1JFwQD4YOIMcjBrqvUJF0OHvjLLm11Tik1YiRvhlsHh75T/s9cr/XzbbGW42gZwFMNviz8IfD5k9A9hr6+cQ+MIa3MUBOIRwajnUDqwForb+T1tDbDhemPAZ0LyzeudZDLTTrqT28oWzC6mr5x9uORwvnqNQCuiqH5rZ6JGtyCKIlA0zl7dStDzbCciEhEFIXbOmNB853WbpMzvBDItcmIYETms0aNgMgXihuN3Ku3r21RIKR0hxuuKxJtWfju/HOqL6qPwsz8chyGRwVNzXGemWaamyPzIbE9jDYMk3bIvVn4FvzwA92eIz5Pgt3S5WM2kKFOIzDr9cXLkWD7BLYQHPnzp8wsflRHxyf5C+B/GCsfjMSWXCMQqDUR9BR2U5fbGaNRnBQAWfQEJTJ5e6UIQhKhf2tLteJaUxMXsnBwN+ZG2x2bm5uQCjz4/9iI1d+k0IPRTDhkiXvKFl6ez4qEdTRz6FqoZZ3SD3OxnF1DAXlHCZdem41dBeNyvQqKNAB1ZVsIf6VGG03ZDq6ykf1qNaYpt0OQCEUC6dvc2YHdprGcSjKRE610iuo/6mV0I/tqP23MTZi0GYjKAwzA425Nd5zMmfSYKod7AxuuihqJrWoghAkcLTphQ8sG1RfmhU+rLZ+p2JFSoaIPuWbnUcKq/tllxUga4WXP4Cyuut3fNkO50i9jYzgCpt/7tPnWeUvRKLSkupEIIKZ0dn4hpDkuZvQ3GT4lC3lxF5sarN9qdnNg3Y3TP1SaDP3GfDbAK1TYmxZtF9nJh7Cljxa8se8xnYFh/ELKDTKomQu6rp8RArKT5R7bC0MK7zcb7yktnsg71SHr9waD4rmXS+SGM2P5AugXTSy5Zo5o6/BQ+9aNKHECYYuWCgmkgbpKnAxh+n5fL5Imnq+G/o0k8GsDmGarpDYAEQ8KKAnjW8Fo/EvSZI8PyZ/CybxwwXAEVwDDCuZhEfHUmvjwA2N7XUBW84M8/pu/7kjJsEh7SWsVQ24LC2OWUwFkOb1YmnSGF/7xgRdHR4WYs5XZwtM4poenNoIu1hkOOCWrvMoYGDgEDrQuw9lEV8J8qPoIXdC8OMMuReDB8q2nEnJOteDhRy3jGL+R6mpA5ztdNIcm8rg+C6jssYmFU0x7hTSiEo5zolmfiATlrXEB0lmeJxXYiAeoUQJDbzE1zDh947y7wyetnE3mIqyZHDO4T+i5JzxaxCJx5+NbuhanRdKcX14lpuDf0sis9myEabCwqLslT9HfKV72Avj4u5d9DL/FUM0VeguXE7di2t5FZ0/CgSpRdanCBTGAFO2xN84mCraOzS01fzJzDilepepUSBbGc1XEbqrvdQTx1+zsSfYBuL9wHJCchpCd4uLI1TUlG7d2ua4WH89dDb8h8oSq9+9ig4Bbxz05l0rnellULEOzXlcc4tqi6alK9S81S24NIE4MYYrPouvfe7iH6SGfzfmWi53UfCTKWghDm/c4t70SqHzZiODJmzGPbuWkcb+sfeiS5UfFLUucKIVHb6jWmR25s2vjz9U7EhGIMEg2/eUvvivzMz7PGtMRkwrc3/ogikfx9/6nlbwArpJP+XRIl/ln6bNr/A11w/bPqm+LMjz0QiSfThwuzXFFEZYACHvGMIyqmB8E7w0ziazIfeA6g+wfAe+/cR6PVSvvglkRLdybyDzjL64Xy9XGOA4fQmsWwUo1doFJoYDljonms7x1YTnKWD2mzX9NNn4NzsC8iPtF8ykYs6vm9ZZNdTWWgrBAzdR5uB8Y2nz4W9xWi6ye3E3U1x2AjNNQu2+rL1Dx+1Fwuab5cUh5XD/aUBqaKVdQpBBQ2RKzqIjX2s7eE2cJoHPyt09YPJevzjy+FsmRKHYXE4/uQbfpjMs9Lt5z0zQtqIj+HvXX4rUHK5Z9ljZcuyS0P3vQLogtN4ACAy8EE53rpI2UEJVUmwZ5qDGehjM7b5fC8Aq9eyiEY8VuAgGNE+7H/+rSDTeSwtCbQSk8egVxX2LpPh2raldQakpLqmhkrx+d2Dm/Cg5HDB0xh6byJAMWAaotAZmYAEXW2peisHPjtkGZZsXsuSfoIQleQhcAU8XOZ1d1oow+fxum9+vkrjyqX4aO5/GZfLR5ST0aKUKStVBVKpMhoIesBczrZ0s7DEUonyQuRPRO7xx0K08wd5j+wd57QVe2IWfN0DXgSxdpGzrHmnv005xVVROAWW1kJV0wlT5fWJKA9Z6jH1JT0OhaM0+r0F8/C33vVCDXtdg93sUQwwMaWQ43NodtzeTCojb+HotFaqo/wZf3gOtzvA7gIfXdDjUHd3ajOneXqu9Pa4tfTmLiwY0caJaipRRd6M6UHPopXQam8Y83yZKXULhP62J3bCfYRHpc62G0MuXbwIjRcK/X+T8MJk3DnKSnOaMgNnmYn4bDqpz8VtzVWaRRvt9OUUz5cpiH0R91v0DGtQRp8+DGl3x6mGlTvdbhjdycLHJaJJ1KM5lfzv5rhV4RojqCJHQyLsCKDN97V+twFwBL4xm9JURTVvpEUokbDL0IqNnKjXcHhn6G7hlu+Y9vmqUF/fH2cuwdSpc5qegu5I2iLI+QeQqhbKWRbPIh+dibZdtRuR+ptDd0aj0U4DHCRccWM7pqZ+W5p1gRdJZAchXhfrsxaa3VN3m5obbo872jx0qxXCBMES1SqFnN3pVM1QIyuEgvEDmlJRoY0shbKMxvbVnVZOYNbod6UcD0PCHRpcndNnGgI+Wv9QTKwpl4dQZ1PCmIXZzt+OZPJ5ap+AwqZXnjeO5LWGaWPSny+Fpc93lkFQxmnZldLrQgtzdBeHb1zxM+SBhjKjMaqE9gh48xjXqe0WVYFgA+MfJby9Msz48hVEGCi/yHKyhaPMiuUvabiMMYeSlMlbkJBEWsuWGM5Kqgj1yIhJkItvZ/ke19qdo2OsxFye0L8Y2yJ1GP+ZQRjrdbDNOuxAHkm0CAxnLkIC1U+4qp7Ncdo6UzaTJxNtcmSO4pwkHBl5tOtY9M/niW0FugBDA32VnYek2mZI6dpvD78oCv9liG68j/9FMb5nUwBARlIUIedd3kARm73fQWHTbRvIZ5TSxua8GlgczAwIhfMaxzyL0bH9X1SIcQ61L/KEIcyVOQAwQMDdlcwAiXCJ7hO6zncnuh74nDIfnn4YpoaJpxzEGybCVCGUorBOUqgOMx+VFb2XGW/Qy/Pv7aU5wA3hk1ykPIJI5ZbnHZetL57n1/qbp5ptMxtjttREJkVQ9G+LKIGe/Clm50RFyjYRAXT/ynVpmNphxrA8+YuDle9Oj+snJ+QQa9bavZzbohkXEOB22kVb3DQ3pMX86KR8za19f7xPYQsCsBhO6DEbyJpIysV9VTdjj/K2S2o3y78NSZZNocihrUen2CP+8e58ZsPyw3SBX1gpaqmd55UkNAOXp3ONt53/8SyB3GExjPldqaLdj695FHKFwx+E4kvyMAjQMUM6swW+MkxjWLfhqSZQBULerbgDPhNIb1Kn9ESyiL5x1ULap9FlYfa1NzW4SNr+KU3TDinQ3qgtqPMOpXyiWP/kTZZZtK6Qkg6aLu4OiXBnIkai7k6c/WsWPQSHNtvNBQAJhKxb4541fR1Xce0Qh6PfUv+I1iyynyvHm0UwM5M6x1XKMXVNn/6L7KhL7STyJ/oPzzb8Z8o5KffVWYagbEVxbQrBUIzB9H/k5XmgHHEfIJ1C/BDjj51MSKyN+zwJchjQ571xdQ4EPgxuM9oj5BnS+xQ0r5god+Uwz/1uYUgub9aLMpYijA8WzxL+S/wixKBhcfD7EWVvtcYoZw/pFB77Mccnuz/v7TzBfeDr5mRZEvdhlOgggkv1VDI2RVWhrpRjkBh5fRoot2QBkRH3aXQD7XxEYM2c7NSHSJQgrw1825RFCLtE3BuFoEyXFgC8z6D0Hd3l1b4UeRvWAVbxIKG6+Rp06DwTsQg8g8znxzGlM2nFEYJOhPkzEJuk/tPw66EjGyJucy0hFeoaUVaZUadC1YoFm9+lHaNWS8R7NMWfRgViRrzLa4qDwcerNPkMfZnxO9sTDpSmWgZt6GZgOXp2CzcL47UbaVLVLdp5MJ6Pg4UHR7tqlXsrBbgZBpp3bJeXSUrM+4MQKWJZtqNPoB6TLZRLqEVqUexf2bd0gMs4z4GWfoeHq+/5grIa0OHS9Q2j4XqRgCJdnP+oytXzUaNQwI8SIQZCiWGtFKx/UvjDlrfjLeYenLMSsveb2679ZFr/MTRcc1buRnRsPh8jpDfb7X6ggWy4eqdacD4y/J9aHasr82OKyz2rhvJCoB4Tg26EbbzCdGKzSBh+jHlFJ3LO66EOFQJNuF8MKSuP3deuCye2UA0nF3CkNjU+w7xBi1EiO7KWcpd/GVfiv24e1cXDNM9LNiJYEUw6oGX+SAa+DCukFT//HNCNaxjYL+4JTEN5Eg2+kwZ7XnNt3uUQqMu7AWhEGR+GE5tc48PkdSl4SUDYqxA0FXNI4AfFqhvP54eJ/4hKkwgmYH8xClJrtEhJUfwHDRyx1OluVsznYoVmvnqPV8WLEk7VbOoXtcj7Ih7uS8TYKW4YB9pa4vBfRyEaS8MXqE7sHk0T+UgLaFbhZT2+xW+EaySyn2MBS3M/h3b8iJbhcZVpDSJDoCrtT/fWam0AHPcvX00/rGuCPlGLq1xQD/dA2k3hFORkEwiYDDIw98lcxvxS0ke/v+ZrC/7mgFBwrnrFJMPUI2fBvyUtLh/x3jsY+Cwp9WfRWxUiBeIZ57pMKVpDgZYENKpCcah7+S2egMMooZ/U9LKTmv89fGvylHuWnjmEtR0k7GllNcfLpd+zq7OJYq+WzVok3qTdYtuOrNJqmFcU3TXFxIEcEGabdH7UOwTUHH8GgXcsjcxqu33qMZ/jsXp995ros1XPvUDnhGaIjX9QQ66JOmYRn7V2Xl9IMfqfa3Iowu5yKSSE9vUx19O+OjOHwYkf2lseIBQyRTYH/z5sbhYPTHJhwThNCuY1iNt0XSFQrMC6yVk/9lkhotdKLv5dGcG52dZN8KQPGFVeeAZUp9GOq/RRBF2n9CNTXuDznBzrYnAYZopCidP9+J0/eY5iwDwMqFieLxI/IITlrIxbl5fydcwsmGn6639cFxsXUvHGVfD1dyTV9vr7wzcj4jvL8SSCVuVaA2zouS6YgcfHM2MyhTdW2fj1rI0D88ebETeH3j0giYrqFRPzBG3bnqjY3loqQNF0Jf8aNqhX0PE0p6zviOy9A12X8WXDnFAfG4+3LimbFDVbxv6kNHChcDra8YrK1fa3BU0NWS+673mb11bVmY2WgZn2IsythY/p9KqcWtk53E7IxXCJH9AOfVTSWo1XRgkOjwhko2vLuU6ubNA5rNFLOilJ402Ws0nz6GjPFZL9xzltLscbNPMt7l2l+Z91noZuegVYJug76UkOOZ4n6J3247CndJ9R2tnLWrru2c4+n8i4/sPVbngHog12e79JdPw+MCDhQ/lifU14JID62roPr2OA1Es8rFS6GjPsJl9gwV3XTNoZ0GvCe8LlAkd3kFNIEjeH0SLqK6TZtcTXuKhzCtwHKh9aygm5c7lY5UMfE7d+JlpdWhT8gMBWt+HgLXVVrWfDepXgd2xChjWRcmQWU6IXkdaO8FvlU3HgZTvx2vAQEUPQV/KY7OEQLMISL/NhlXhVPIOsJ4RdYQxA3KxT+oNszv+IHUUcMJ2VTL1sMGB0T2ZH7i8sHkKeZdcWiybDJEBsbwDuu8ZYr20wNuY3nj3Vc/Z48oomLAKF7IF1xWcJtlhWno23fUa0J8JiGQhj3ZgxTssrX4xyLcAwpiNyzc4pna9E7fZsag3ye35SoggLOZMorfYTtSi7VQyfGD5HhFzj+jqmQf5cHU1mylCIb1wT0OT0NtMGpg9kzUgxuB1fGZYd5557KPgnJaJNOV3dM02xILzlNKLf5j7rTwGTMObGbx9bIdO/rITUc4eXi2Nf2WJMbIq+luo0ssJcn7BuWnqP/HJCNw3SdjRn+Lezkcnh9hUd+D5tX5C2lG4x6RX36cQdjvzGarbu/rDu/BCz3TCgpXlnThc8o9Uay0+XLaqX0Lam1jHRhB66X/saGKp5R/Yhc1i3+H64Lf/IONuhCLDJCyXOeb/5j1xiGSHXWUMMGB2UCMu/uKho/Mu4/onolqsTqO93oK31KNpuun8rEibE3zOlDbkIMSywcYPkbOi8YWgplaQ8QdjeLzPsuWVYFbWKIPrVtRAnYKG+dqXVRwdjuAzWTIfnEsxMPglp/zFiss/y53QZkmJPKc1QohzOrlt4qOBaobVuApjheRJhhBXlBlYuw0FweVwRZwmBtMDT4dCWfUjVdzGW/Gj3ImDp2z03GmkIRdDNCrHeOHDoktdTbDD1X5OOxPJJZ4WCqKg0PoriekBjWVK3oJBqCfUthM5xink9xuqllBXEBaZxkLWVaYL5R1DDVg7rj0VgFBUTW15qHTstGEC3OWsRssnyTgme6SK3eSzJxxWRObZE4sgSrczArcuf90NWCNrMdcGsN0IvZoTwryBqOZYbTxyQjvYWkI5BfzTsjH4EOyGwyiFPQVfzL00qgEmhUDSBUoZHDnnAhTtNXNX9lYl5XlajHTlqKg8ucRydylXaqklC9LNpJA8nnbQKJif9X1pVcgXuxjWInZ0koNe8tNyKY4ueSObpvnwkpqzNeFuEsC2Zm/eWdmsTIzIJotukr2ndjkRrmiq+UkKCuGFD1Cdh/gajibEDEMrkMgXOuKTMF8W9jRr2mF7gByUAfczYNP8bkrp8tqFCkuazb/IykxqN+ydzAGmRqPOM7KsyDZDNTrAMn+UQU/URk3bJPVBxlRiuRAxnxdzeFxu3fUZM8Rk4fAN3HZfM8wUmREgsNpfuGwzupl3QQUPG5g92dX/pI4SdJe78QnJj4/POs4+X4G557JM6/IBR1T+I9xUR//nwAQmb9U2KN7PGaQLwNefV/sWWtNpC/FpZoJEymaRHRuINvv7Lahnerx2wmIT0PTreS7V40ZlNlMuhkKUzr+W9LIG0+Sx3QlHbMA7fLQq3veoCwht52TOperPJxiUWlgyISO4p4uoDudPwOpSqqiUEW2SlaePWxaX7b47u49iHQ2/zZ5ao7ixs6u2XnSqp/yhAZAA40oJqpclIx3bCemSj2HyfPBXk+2WauQDzhopQ7ifzUV2XMjWpjIT+MmpFYQW4vJeM44WnJ1om8FIfEZoQWaBza9Pf1NxQPpyhAfOV9fHQ8nVzrvWwTV/s80OFnlMt5wkpXixCDJ28HcMBn8Wj6wwfReM5pUUE0k+JNT3xYA2ieabii9D62/SYslibbizUu2cExpE+/nxSszLsRx6bfs4c49DIVtdozAfxquryho4sNx8pq2QluxTQLA3qevTjkAYWnaFaTcAVbOdSGgsqQzq/136a+sjFWmgcFfRmrJL+vMNzROVYtYf4HKSiA1hoJJ2FA/Engg1dV3b0SiZMHb/Wuc6+h1n+RZK1wZtmSrnpIDrkwwQfKbdNIIvJ97l96DwWoyj88vk9JUolXVySlnmxvQ+Hi7XArk0J8xwI0plMaZbdhvILk52SMvssJ/hf4T3Wl2NctnU5p6XqMFj5581HZryuljQVzLcTBLiNkIKSNDU+x9Z1R24qAAmVVVMrq0xDhrJoHt0qqNxfuyZcJhG9/Wx3Ey55rEX/aTDVR3KoxnHGg6hWWUvZmjK72s2BHIQnLENt8aJ0o5XdnHxmC/6qvLeyTE9kgfP9kQZSAY8o+e+weC+XPksUvMTObyZaP9PsH8eURBWd79DaUfrpKMOPtwxxzjkxLFsg1fK1el9iMUmBVP87ASUg5Moy2loItv6Ui5ZYtmhAK30zuF0jYPEd8Uf8RdNRmLbiKP+e45YtPIZB53cRzf+EpyveHl8sKhwRIGiL5NKSSAKvp+RiHBkMKzKhi890aEEHDB0Xp0OPsjCHYyZ9V13R1u0kvKotwkYfz/ISM/2Iseo1n2jy8l9V5zgye7izXqpuFUPCKb5od277/w7XeXHVBwzDW3d7C2G76FFFrhZila4t6tWj1S78fQmerwl3I4MYQCP7QdollmZ+3JhtXkZ3S8RS69f25luZ0ODQ/SI/lslj2u93xWyUOtWbLsPaQMoGCthYq0CDwho8FgEoXxpD/iNX/Qh0xZUhPMRnFS91hY5YwImKEPIuK1lCxelaAQQkaora/ycTiI3Lxe3zKpnrWiN9XTtuZV237n6nNMw5dI1p4Ul/vSOXTsIBNPEgV9EZuX6zl2umyWZVv1w16W2rH18cEeWeUHWNpSL7/F9JWXfkU51pZNZOr1AfnQjzZGIS3ko4CwOz/Bnehw6EJ1Yzk6Wz8W64cnklH4UDsujSq9aCOJbWxtri6zXTC34eTuH7IfKIs5xZ3VIPG0C3v1BPhOHzUNBIIJ7ZcCYOdTwa3ZjIXYBe7+KNb6sLjOECoQkmN49Lg/SUkksMbU20gkkik+69NT1F7J5r0Lhy4xGIgKcZnzfAYNNHrBeTQ1mm2Vhy8HPG+q69FL4ZB+8hnEzdUH4E59cqA86ixCJYTjahKGiOc6qxYNmPLwQ0O03QagRBbjBA8pyPlZKX3zwt14DE/NTMRR/3pt88xxsGVdM8YUFxizCYrg2Mex3Oc7w0eP2Fw9gai2Mm1XeY7nko0gonMxctyzYlyIqHLQAp+Uq6ZmSYrhdvxM5dP/EAM6eioXLe4PaBsHPqHL4JTLsxn1cA4xj+v/bhoDQszdQlSwQlqUdEo7f7vpj3uRCDG+xmyelFKb9pmbG2n4HSRWLiLKz3iUcHkuXJNVi0PR893S9Zbe9AoPXaw3gyhlPxg3xLa2PAQ7njq/jkmvsGjYxfabfc0gt13L+B94XrDrb2CA4i1DPxUK8cAOaFBwRoW43QQXRhl6yg5j2ntNmxcEl99JXXA1wVt2Ni0m8HjyIG9JoQCPnwdry+0yVm5PgQ252FPWG3ARvY7KDvn0t943BNl87r9RmkWcFAsdAE6H2QXMeWSrFh05JGQkEIPdmTXLIy4n7KnN+fo76HEvDdUokVunZsywN6sQ63MCJTNXU6msW51M9KSHQ/q6YcPmlm6m7rCFHSSVIX5tstwd15QQWXU6M36e1d57R+THglyidYGb766mc0jm5SACsr2D0PzY/QDZ0zmsXIKF6yuBHGrDsogriL+B06IPm/MGAguGEjzaH1VezWxOCvq7oc6XDPiKd+QM/PhV7uCT5rpsfFPZuioy+oQkt7mJAuRMhgWRgtfNze8ki/mH8baFigrYra0g6nRbDeAdPpb2i9BqQTf+FaopNi4EGXWS7PXEINCeQOylQLCBI/OFkUCVNnHq+hJDj/5bH4H+Fg/XHoeufJw+Uwuh8PEHu9qWi/VXwazgakGdfGl1yqi79R4K4/EEzUp/soXM6rccd85zfh2vqutA/y27tGkTjRPj1CWoEfJa1c1z/YuaZa4FkJQPRSkiQJEUK3sp2uWE+x5kYzHHIKGl8dRrzv+2rlT/m9izdD/+KXp2cnqZVL5X5h+e/T3HMmFJwGGsZ5Dxz+sla4v54yxLBFQoQZTHCqxnAE6itWbBDj7SGrD9UbcZ57/bAhIK2afY8G3R0Msa7fyhH+afZqsWjhXZFdtEKYQcK8T1sFN5lK4tJjRL0JCvXo92Uec2VlMm5xSUlV+bdG4qq8Qu9aUwdaMqvb9fhz/nXDoCCuTxwReP0gPj2Q1DixkerIDHlBzs0sASej7xk9UxTS992HmYl+oZKRKqh7DTopnQ32pXZzR9TxrqVaZk8MKbVg4FQ51YamfUzFEV6as6nWF+XcmkwN+YuaL830OMvAG6f9gC7UuihYDMrg+wDIl4Hb5Ad10jZbCZHL0ojo2A3GMMSYOjrAkuxKb5OEDcioHovR/kr7K2qSHybDuvLQkJoqsJxmXSvCtvVLhaOTc7YXsPX5ZcXfkaradu6DPhU5n+ghQUt4C/CjXMnwqCH1SmNcsbBZiGaNwBX91KB6GRJoC/sHWEwcLB19bLa9pX11d0HoCcoSGeT2QLzYIAcb4ZEmqRfwcA1SlPcnnWBSt72+jybiHU/2JYdUSKisx0pXHnG2zm9ylae0aye2Q9FE1SC7D+dxqYFj1gPO7/6LifLK+0Fb36M9S6GPosC04UPpaMjDMy0Wze9jEB1wIQfksFeICv/fxoqRtPeJT07WR5G/fmKFHlJaia+5Db2RAqcpjA3/2VWPd8gr+o74Zr45NxDpL31JDb9knTOsPky+1UNA/ZMCLlwJ+JfAaZapKHxkyW3DE2C408+l7PgwnowzZrslNxqKfNVtJNt2TOI/WP5epJ7ULqrYcLQQK8rPqUpoHliP4oiN5uizkBUcSTZYThUsq6RVYRSrhzz+81iJv6sjJPlSJuQVZfXgSsGfB8bqiGIf3rjTas8Y3GKJtznMzzG5GYuzK9BIF8ecAfJvp6DjtkU3csUci3Tw9FqCDczNYBJVrb7Pdn05wUKe1Ozk4SBO63qmehaNV/u7YSrDpdouX/Z6yhRUgTSo0ko6Xrlo8nasYgwIQJKgv/vkGb4TAgVIFOnjQtP83zmub0p9ZgGzO4xe2DozksG1VvhYToKU1L5oUD/6yZiTZ5bwdFq6RDJ2FTaxPnIWfv2NszL3klaAgnDDZ1XM8/jCPXD0colB/KikyD6PiarQvX4UrNVYxT/if2piG58CZvi++s/mF+fyXIBgw1MU/BqOv+D7+YgWilkNgkWdEKknI1hrRQ2KWuiu83KNUvRnnTio/6Fpktm5MFnd0Wq4Oa8qM4LnM+wE9EIUFYqyBdclhIvQ/D4KzM+trUr3qnXOdkQKB6dMEJAAdSMeHkNYXPXi6lR3oz2vNO/82yse4+I/k1a0IS1lPSl2UIDjWKgsHUn2AwuQFPOtBEs92KmbtWM0fxVz5jqoveSurhaMlLAkuejNK9+npE2vK/sA4Uo4kMSbDi+x9nB+ScKYK5RJSYiTLltPXHY/CD9a8Hkzu1tFAYT03TImuSBzGV6TlIb2rIhXYQ1SHTTS1Fz7SJVk/RZnSqvZ/GMad198/6IL2iSQr5Vg8H7lr+NvyF7uO63cVwW4BfYyo2uvahZZhkyxKfhSflwewxkJOwqKqCtaTOivJKLQzmyD7AWa4xWZFwx5DsUeVcSSWnmzzCBoZP39a4hBcrmVLl359hmtR3hnek3sxkLejWqxGCQD9Io/yh4kzkGy/78a/nNn0USHl1cVdsAiYVLD6klxdyqsg355DeMYR+lTRsIOjp/LrubsVbmx6gq9VTTrwv0zXqXwMLozjUPs5AAa7U/IZLn5dH08uABzG2Fdw2BBpzN/vgTOYYkW7LhAmu5d6xSgzfAifyvf6DgnD3nttVyNGoJ/Sf6Ys45lLSQuMg8BaYh5yoOm2nvp7WGRON/894vt3lsOu7XjgRkHuPuOucoPhXSTQ7xfXXUc2m1o6mHzRVqQLD+9nI4oAq0iHz6JY1u6WvwTPmAg1ftStBtGWn+yc5uKZt9ar62BFqfafMtOehJXQW0vfKhJrWLKBzWzFXpbif3SHYbgVTR5SUsCJde1eqX1LlV96I85OpoG9jGV7pZDSuonF+3idKNnFYs9KNG8sKaudJd0VaKhy6sahiVLo1KkyKq3WmLWiODXm+iKaWS3yArw/MsgzrdDfP9FxxN6M/HFkm9Wlk2pAuS5VmrpET6/lB6RFpWxZHYvA5EfGWYgKKMV+TIJr5MUsNy8okjt0VIlQlDWdQgx51CYrUptZ810y7DIWRrNWh3ufsGQJNPvuTx4kc/LjLTzq/whRfLCTez/o65T+QekIPERovG6dI1Mt75bhutMCLyVFEBR0GR8cqVd0ek+p/qr4vS+ijrIRmMaFmjjd5maUxWqPgwmsrL4+HqNTRHDF+vTFGv7zL+TbfCnuB1JhvUHcn5ZurgyWNgAJZ/ELeZoR5DrYuT8Ltft68AhpOju7e+Q1j3N4fWHpNGtRr1mD3y2p4K8+LCw1RSATIjDBLZUG4GpGChNCaXKYsgqfCYfjn6WjCQf0SHUGowqaU0o42sNY4oYslxhMeUggIDYPc0lfrQ2thyh4RpfGW/Ga8j6mK4uZ4/wtjtLNpUCXHWAAgO6ObL0laiakIPvediBnBwt1d7hV6CCVXktGLCgqfgBYXDTkt6UDF6p2HgpwXJGHfBNgLHxrDjiZDfLMFf5KhuPnSfyX9X7NJjpDEeXm29BBVlAAsdP/ZAQLSMgIJo0yNXUhmhK4xgMpVadfv5Tb92HcFKdBhJkIYCvm1QokTq0LZYPnjrGF7ngkihITOcMrunaY7kPqYUvs/hKGTFPSuPJfBYMhZpoF8mQlYNAPIKg3ZzReiWFIpvWpqQ0Nbr2m/N1ZnGDzy+0n4a7/ZWtjcuK1cEr8E73GNTRV7sO7kwPaUfa2mLpZuy0e/Udgr49sa1354maEPUtC6c8+9cJt1ZsFoo3jXMws11cBnIpZAHK5kOEd0cHywAb3uLgv853lCxRkDfnbY42OHbA5QV+bPZ40RIAqydNa40prG39ew5eOlIGvPCxz+H6nyn2Ivb3fE0LP3yile34Y8NN2+IO/RWyLRC98FyGb+NWvLbEcUHEpZMVBJOdMcuBcFtfi5B5mWJsZBz4Qr1c6B5eIT0GaZ+SCEt6i4gaIRSzrKQ1HumPFKzTJsbluouKLhNAI++cuM1zr3S6ktVXGt7F9qzY7RLAdZnQfZDbzV4wRGCKktIX11k/mkr29N+8Z7SD+Tc1Vg2rxAFGxKyHyZ6ekbhURP1WFb620b3SBiK4mwYJzZyqkvflRznUQ3W2HSQp8mXkKOnhLZgC7KpC/Fz4W0yNyhTOq+AfeQWhBMWJMyx0hwMsTE8iiQb4V144hqm5W6XdhL+JkQ8VveckZLNhbmDv0KJhMMy7e6sikHHzDwuqg3ftLjB6PwUvZmiIgcKiUc76xU4OTY9aZtgsLM1n2w+9DokhReciZkXPdRV+frn8zgFu9Li9c3y+IxAdQYq2TMAgq4XhDC1AobktdO5p6KqKDgRyGZNY+vyoJSwENmHID7NmrQSarZ2yt39e70+7N/qXcuQbEJ7I+x+b2NtQaZCNcgeN71CR0hc6NuOVy92Jnj5boIHZlcongU/eXxbczq21J9Yc17D1Gam5JkGc3yzpiLu1I/Ydu53nMs1o3YJPU3xR9x5i9DOd+wQF1HCS4O9ZovC3ccy1dNZw53bg/hmMbtqyGTIbpgjawhpjH6ImkV/70BlYlyK3d1Vws3mxTJCi6D+BDiFP3DkIJy9Hgix6IVT1xkpZHC6wha94UG5Y7b0vDoSSDyk6b1Q+pupRFY1hZwGclBMFsCRu23Oi0kjNRciYLDv1SNxji9F7a0C5l0PFmYLmhFBMSmlfSVmuH07mQ8ESsKs9+J2Iso0Uaj5nRfeJa4oh0esScf2VMSTYXSwK7E/SkCiaZcIK2s9Ep4dyIapTY4uWTzWlF/fPUNROZUE9NmrW9xyl0VdMnne/4Hf2eaHCEYFAFRMu32lNRHH8KcfpJV6+6yH9hsX+89vUTEGg272c0c4Z7t5f9v/4/OJiCBWUMeuOSxl4Ak/6Qa304t2alFq8IQuJQcOUFHQr5vRI6THPv2CBY45ypHWbOZBW1ltEHs28J177h9dC2QULVsTmiouApUSfMO/cDawVma/LfxoH2QrI9HdAdW7E8+wlzS8i/geDShpjNn9uhQa146Gb0JW+k4vcvohauiOdgk3nGe69cOfhspvfaqthC6MCkpJLxg9Dvb7jOE/+4z5CftENopHwFi99DhtEWRTbN9htWWrQRT/b59/WvWk5rMsKrjkO+Xo9Vs6IEizoToepr+9kJ1MbIlU7g5sMwVEJlVs+Nv9T3pdURol7UTPz3WaUfxF64toaallMHSiUQO+xgvRj8wp0VjCDwZrmL3AjfUtxlHxfZ1ESV4xgQmy0Hk1RmRHi5iAQWEOOZ1JcC26uL25nY16Xytj3H0JHc7xwM1crSODpSuzH4JRxaS8xA6cyRvpqhyI1F38FHX0cTOFAuamj2hgDvy88sSYVPRzxgmjepvaVtFdvic3xmXZZZB5R1W2QjbDTR0Rf7saGs/L2yeDYDdLZTpRtoFf7gYDk9xbdnmZb+wgjt1KcfE04rbrxkYSi1Ht0wr2EpiCu2BX3cLYUi50+v7+MZ6pD1941v5piwZ9Jd+JtpU4icZDAnKtFgSy/OfAYv2c5UrmIKDa8rgqz0UXsfR1YIi7cOZlAinliHbJhqfTQKSoxinr5X8fntbUTtU1BIu22QLXEOal5EWNVd/Y1Ojhn3RUNhCJR/dlfko1QGy9pO42GC7wWhkjKSLEOpTQfYpyWmZObKoOrMWcTeHdPinWLmmk2ST6upJgakKBD3Cjd0w3DDpdElyJ8BmMAIqEDbt2FUVCYxpfY0U1f8oMJBEwRvrFIWB9d5PDeCJ91yF57MTDvHtv7T+callhl3t2h5gSOb919mPJ/jEJ24lsp0odJEBLc9EUTL+cdfNqbPfEaZ9SxGbZyCaku/0lEn04qSy7TlZ/g1s+DMR8nQZdLwaxP+FeW4TxoouUopKH+OzKfWifPAFqBDKxVgyRcX6DYNxk7+0dIwWpSSOzFvbo/AV45YT/elaP55bRQvWzVRY9/S0InuBuAszyMboV6WLwHxsnwdrF/mf7aDSPmge1BZ0t02KttXz0Mo1XwDS6J3vaabCf9auYTHGjRwfnOhZd0Rf/htYKj/rtdyRAXoE21fOl14JDrVLuS5RpGzaw5iKsFJ78aY6DbHiiDwhpZMFcUVdlpt1m/mxk6ld0jCNlxoLGKbNykNqRipimyDadWZysXtYb+wWbegMA3QC5xjwnWcP3LHxr5D7fY7uVh/SEhuXL5P2pRP/uNeUrKHz+fzuiq9yygjfCM0qG1L09khY9Oz/3T4vfhdTbubLFFx08LGGkbZILEs6MNNEMklNWfIPbFRizntZUDosuYObNVSOd98VuJmt7K+nfQHxbnGWuUV0UrH/KFNEBhfyoDjD9ncWD8UJ9WSkxCjVkUarlW6UTObvMcD2YBr86viaEbgj0A2o9qqM9df70VwAh8f3ACxHKl5uL6qi29QAfKLGSKnJshgkWUBdo016pKkF2dNfsoZs2B6pMJrT2zv2AmWZt6RWkwqWh0IYwk+XX2+5zh9qASpzYZZr1Tpo07hoboLZatUfJKt8POCnM+SVfkHhc4SM1Ojd60ZjIdc0m49Ydzq3293HXrxMebd1vzIcCecgLtNAFTdAu1T/PrWWVGw0yBdL/Ngix1puc4+Fuu8Tm/sf8DPtVwSsr4ck3iw3M0AqDSGSnmvbzYearaogN9W3/6CCxnyMgq8KG+FLYbZeLrXBdqA8wsJFkPblXAHRKBPHvPBYP9HnFGtqQSjO6ASjkE+3GSJMYAEYkjq7h2FmUYlVB31xF9vJIVldkLS2v2RIIOFgRP1kTr4tpQJS6MRitwuCshOcMfviYfHIWvVI3zr16czYuWVmXv58lY0dg9dbaIgerjskYAtFVs1TA3DK0XLd0MQK1zHPMdzQ2VoFpm0PiZUfYLphIsNjqboGO5oKPo9P7n38osMfjKItdhzUxyLAeu/ghHkZJMPpJzYrILOCYpgwHlXIN4Ui5nPEil5V9RokV6im710ha3R6qe25sQRpITYzRlyFJHHNZ5HnTrpXYzjo4IyAitZdahzGNlh2dk1LE7tQ3Ae+fMmEaITUParWZObbQcNDosjgH0TXoBrg0BW+CmkR03r10EbZrrVUG/lh7OwXleEWv25T03cf6IhyPkgszyAjguaELhuN0FmrZwf31Z+wjxEU4+YKPudzLTwldkASjpK5IYbkl+MlaMqE1Y6Dg9L1SlGlqJl/Mhj133DPkmWqGSTwYLXaCKlVW331KCXirvHZW8dsvnpwAFL5j8d+dO1pNabfrTTEc1XrxvvmDt9Tph3krureCoCcfEVwjzdqfpTUtYUYh0GHjem8yNL5j30GLqZ/NzRmZCpWCs8e7x37IDAuZPklr1op8s3npXrt4HDeeV8wH+RLEzx7vxvnlwso8lRIBOmLIOfkYnimYxOOHyT1u5/pNuDYSAGAADA2LZt27Zt2zY+tm3btm3btm11iA5yWYrSchvJo7vIgW+3J5yDjCMdC5VBFWYHiQJkVI2QTKUAJ4BYvZak9CDGF1UGVdFfuZMoHvfnDbwmJiIXRQK3vqBOZhqo6xHQ2BwkhiF6NstPNyYQj51plliIAiEaUthBQlyA/MB/TGslf93jB5yjhAw/vy2jm0jYsx4guWLd4qsdWPvwBwcbDgXoed6dr01jTrCxQ0ryALkLxHa2USqRLIKAeJoejTpfPpeQhHwBWP8C/jVoFYKqR0c/KbsfQZZew7W5qDWea37jrMOcPT8CGoamSsMImDvAZPJtu7cWoaUcbho7HjeIuhEt097u4tZTt+GgRvBsOdjZV9M3nsyZX9PeV6XFNEVXNBZGvysdf9gBWoRH7oXLU0ufJIczMxZqsStPsMZtAApA0/IhJzPShjPQM8N6L+jfqIU8E+rX9V1oVa355Le1xX+x0KvM6kC1ZAAlaS5nvnZznm1LGgAYTozm68bek4vss4Glit7qatN2H2sSozoWQknBYETxgeivJNIV7ZM4UPhznM1b6nraRLt31+xt+7kfzVoZ4TjVxUBlPx0rRK5+EH6WZih7MZeFGgHpk5mejb41P/l0sJl1kEKgam3IBCrajt9E995xYr7xKAgrgf3dspvwIDTByHnvKS3DDLh+OWX28BoTJPNkoKLBYXq/aIGWUvH8mTjkRjNe2A+ZKHs5xE3dTxUTk0LiikWDV4RhLZcXR5ClfdD+dYDrWgBmePcEUoBSTBSxqQlUdxSYJ24LITCvkqQ3e9XwM9XGMGv91mRFxmouZpJPBEHi0D1YTwN5cc5axVbYjdn86v00Mznq33x0NdjDmu68ylx0IaMUJwxx/+52TomD3GERT0DlK6dGoYKRY2+v7PC4KnOK3WyqBS2klvYih+bDDXrzBLA4lpCENxgqw1GoOJqjDynXbgPIuWcOwDfHSo7vITAikN+EHT5n188mYNqbFtiTVxtJb3c60vFZPvj1EmPtjq0/3mTcAthYgu0J8a/KleItPAIPU2Cw/H5Shti8lizCzbxBy5N7FmIlf6qfaIrLstIqFZsVaKE8k9HtnrdOU/RqJfMWwa55OMaRASj7lrLRbpdEfYTv79vtHp25SnIIFDhvET+qhXomeKLNEuBwaElaNFPSgz69/rsa22jGjj8CsavwYuGjGJJqP/cmg8pCK/Lp4vihV8SpE+18X4jl8ypdC4NEFVVVPaepgKWfhhPsQffcvMbXVVcRrNbZKWYmLLVaerh1CPSDMwNm3GaoC9/i2j78ABhiDg2nnAXocZLkO353XqSyOVVN5BY0edOjC873a97i7RwKV7Ly917UF630mKQdTwP+4GJdUwtA9Rc5+Yz3EMS0OxBy31bVp75IrhWOl50YD6KPKrpMMtQHAxfvE68sgxYLTchvVZNrFqx2wYaa4ApmgU2VDiy2PUUjC7Ro4NznXNARB6Oc2k7sEZlnDpte0Mapg54sADvbcqtrP0LIGToEYmGSN839i990ZfQmfKt+RorSvNumv1Hid2Z9DaYOsjJte38YAUFCc37PF+tzWrnfwzzEZqH1G72o7Pc685rd3LxhSrdzCHEiPRGu41KaOCltAZi7NxNFoYks35E6QqOVdLN3u6ogFsI92WLyd/7Ia8//9M5rVjLz1oLNb1g/9K3cav5SjfaogXkdt7NShla87hlDKxjpaGqNrQy6VmJGJviBoDdLvLavI5Wyu8XBu2d0+LJwfQusQtBMtDFsJKAvYwMpsIl2u+iegQVrilIQeZmTKobap2uIx9HAsbud/rxXXNWS5Ode8vvwjp+33aMacaDXn1WaoTCf2h7J1OQLkLGIxHBxEhmCMH3iVCYu4tVJXgetpMCIaLrPdOpd6ZSRZOc9pawnDEDjQp/2owH4alRVw286936DnDlIPWGcm6+VJztxHVWyfdvwFR8XzTO/0wEjjGSSbOkTjOyR5ewaFjhsBzgKGKNDlIKU971taiKD5VkdexHTPYe2FJ6yRBAOGBALb173B/Lqsxq1g7sRQpMm2u2Njpy3ztckvf7ZBD9zY/ockh+lvhjovwX415JxnHAnERYNmRDjN+rqRrMx7orspNFwPseTXwa/RknDH94Lic407TL4mclBYG8kTEHGN1nxp/CQNwO2tYi+0gG2X45EytipQo+GZJzerwNkwdB9nJHoPhcuCNXUuNtf/shVttSxGB4GaUkneifOXpZYsqr1QX0SZyyu3NDCdixSznw1jnmDTc04Plj/41n6Kblb4ZPo61Yknr+25k+OczIvfvsk0nSE2ufGDofz5x/SxyepEX5daF9q8bk/rCjQh/SxNlXL0OCFY840ZrQ0rnt42H6vRHcwsZwxDFlmAo2duTAhX/Rg6H9I/96uASJxZMm5DWt8woWgY/9ceqrl0XhX475Jvy0oo3TmBkt+vCG02q07zc4dJl/vGDWWssQfDJgEL1EHKfw90h7Nu6bMYTtwuoQ4DssgHaBP31TPT59WvGkMhcwppT7zJDWxsspDbmogxPp9xzyV2Umhhh9cvO1heCqhRtyKfL4Xowi5TEFzVR4DuCsQJivQJw9rM5FmiUBkK2xVtFU9ZiXCymU3AEEpUl05AQvbmG9aN5nZ12mjlO92UrPLk9sP7hES2IWpyUPr6moRp7U0Pi2T5gXr0z9ppzifZe7tNdfvRx4LI6yodprOdNEOSY8E2kgJ1Suu25svwTFNV545lC2GlR5wnCBcMIMnCdcWA9zq7e6yR9HxrsidGd1FbDSSHDOnG5BOBBkBMtZhBIsDzy3TEqQvG4vNXYJv2KCAFx9Fl5kWdKjc+o+lkhki3Vm07QKVxpfwTnE6A88DP6huuPLIm4HZcDOVD/md6EN3X38TEddKtBq/AxQi3surezXMTXLPjJ6bj1yQgfb1LRgtUAosNQFHPLbuqwNWYusPTFPp3gEgInVzUqaiAHGZEOJiHnFmqSdArc5Gr9T+cOchg+7eLGuZ5/G43glFbts4GcHhhmmPLo+IhS/5h3lqgOhPIBquOzWXM2M1STd1+tkM/9lACofk+8YeT2U4dH6diop3XhrcteP2GiAuFklE7JUdMlY6kn3Tfz9U3kF+5tWNLMA+wluHI/slyQiPOzSFUCg6CfVjO0tr/jJQM/Ha3BWbzN6O8qZJptczX/qIffT2FLk/ssjvYOKg/Ywq+TiVCxBlMb+g1DucWktF77X0eM/GM2D4hktlg7ELxMfmsFF6cCCuPFq/CVNAm0cie+MYcoiskCJgWxjsaVtWrq4rZ/oRDHMPxFFd9Wsm7JDBnc1vEqpPrXjAD/vZ5Vo0tPH2WyAEte3hYeZJsHEkI+lhUdw7NxAz4gi2BlKAvrft4RqOsxlqAtmAXSVufQmxXKU8YINbs5ih1Pww9l9v7J+vwMxxTsS0uyuFdJ01j3sALiSf+EfPoFAohwaUzR+lvFa+anW5fF/T8frYzZTOS5dEmV13goSZCQDQ4eVC8alFaOF7omAT7poTMCuwaBhzFSau/4xq1xh67eRrwGnyM7IEAJdbP1S1+xknFhZfE78ElyxfU4tTGS9q9ttbVgqkYxuO2ZORygJ70MidebtsKe6MzDNTZTjFLRZf6NAEqoCJp8BI6uJ2/Q8JNpVXfSEi2LqYrz3AzB3x6bV3FDadUiyT38n1BKphpxSIvfiG9UOIshOzJnVBPbC9zJyRzHYI3r+5TFkdlgrchSH2JR+li2GjcuHPmJBlXg+vax51XhrLmUCg0TNWS5h4kh3WtZ74SSKkULOVlkEj4q3BTygfgy/ChsJs5a8ayYdhhPDEP9jfaMGw91UZsMH5+JpiC6y6kyYwV1g29CQCBsAmeaseKKx8kDHGaoy+aTQPFyFQlTR/e0ECzLHGYrBvK0DlagWZBS7CCOeD7iTRJKC5jF99OdRYBFTcHBX5Ol413cdF3149O0BEgX5cMwCSLmc3n9gtNzs5pXmivrktfJyl3Z+NAsU8SYuUirB8EM4CgPtb+G+BUelN2sd4he3RgUbkFyJQiRkRDErERqamtgV2PiSKf4RqVxvU8a2UK/k0EZIY3yvDbFoJFOZbqCbQ67Po/0BcNvPZ7XFwBdTwOnGIVq8NSfxSaJEtTkpC36mxn8fgQSFQPpHO0nmOp0JphQFrycE/AVWmCNtGgzXwFO/P9LXGk33cblOFOKffvWP+NT3BmOUWVAgpIrNXZVOeCgUqS9HZf8UIVlGhYyudSBJmAdHyrPcPp6ai+OI4jjTHpkmugTqPREsFXuGRhj0MWCMr/dSj8Dkem1YwSCUMsZy/fMKQIz88Bkq3Rnuy6PG3ocuK44bx2wyJcbQU2x89iu0WaItzU8k65SyiouwlzwRVWG8a65GRe3FG8EKBnK/8CwyX/OmTQDWCcZ6zL6PB9ywFJH+nSZjqd+hl+Iq00+cJGRlhEuWdZKdElCx9WohEalral0Cf1nDIgETU4IXmH9zcOIJ9KeCocu+jphPgreFwjvK+m6TWaL0oW6BSGLqSi6ImxGG/HiGSKAZRNip9gtIM2Ld6ZToevx7cK0w+tCHrFBItYDmnhIDNlP/pxfmghgdz6grej5htC6F4L7oAF5lAoJiWQH3NMX/9gaL27qEYCLpU34foYy16yysnSRF8/VwU5qzrSLN9SkNyabGh+Kh2lwizyBt/tykFoUbsFYACNZg5NHR2Yyw2rqfPTnInwIn3Y1vpaPIjV7CLkI5ju8ok91SyMuIudvROjmJDihHd4SgYJeuAYU2sjWalQtOekySeakcKYiu5Jo91PdRI0+z3XboAu9y7Kj9b6Y2dRwfdVjqRab/tPZhP0dqrfc/DChJIVTa7cFK/BDBpAxrYk48w+BSBEGvBUICwsGGEJtrBY1G6K/YM0SoKOcRFjCFDAtxZ2ib9gqyO5F1Cd6sbtwSbeJbH2T52nmRYA0ehcLLXHBxvSm+kp2oZmjwHLpKp0oAUz/KWDcKPjYYd/6l9mGl6vZW5bMrFzxLdTkOAAoz/nByZMn/gfQsRCpS9VyQrFjLZciebm7zryk1OnFK5EjHDHH9+2tJSL6Jy9rhRKCPNLGpw/BW2RL2pCs8mNj2xrO90tKV/+LebLVg6Ni/Sd+havSYve23oogpZ0xtJPG4hJRV6ZhZqE+ckkmaeRJaywJ0ACCWKeonnOhcNTE5KK1NQXamBUKeMOArpSQKatPk4flGz1Z3Ah1ZDuHeMIRomKik/fuE6XxX3AR6dh0UXCKDtpJAZeBGnEvA133IR8NGUeIlfOc9ZE5u4cxouEuKBKUkXQ0Oj6kb2rS8kTRyykEDtgNYyx/VC9i4jcGrWlqqhSodaA/HcAAgksjkLXN+7/6o3UeYQ5Kv5IYnCeMYtNpKT86ok0RV8OwxyfbZ41FYTKdrE87qRFKB4YSvI0PTae0SQkDRNUMV3LUV9Qrvl1jfNVck9B8hlm9SeW7vjfiIITwVl2qckEmcrdwTvPNyfN+e5zJ5Cd63WpEf/kXsUkQBbL2+J7vozGyWmE5lTXdnVcMc8WyjektTqRG5nHXOKbGERv+OBkrfIJ6HMP8uhoCR4O0iX8sOLv6Zz81cI1t+QCmg3vvubKFn7YHca/O5NBpJM2DNLJYuRihacwnD/AcQvlo1s0rY4dN4Gh4kKu6d4XwWWAsokz2PU2R/Hw6AVl0d4yLJD76fZxLx/qM0UQo+/bSEe2VPhhnEEeQsDfbsAQ1tDGGsQoJFDTSSZpCos4HSBmM/ews4uvBmpBirUmkKpRs9/L0tf4Du5spWCiI7gsX09UXvm9hS1A+0emXPPzI7PfvH0jihj2iJH0IURl5YzsP0cWjebYks2N+DdI3RMpcvagEnUleCmxeI9y9hQBJc08Ym1XSskLbAWow9Qi+2Ep/IhYNZaULieq/2HQfrALgX/E4yWZjWFD4GKMwFiEuKdwO/VcIkpjXICL8mkMKudr9vhc8aZpnFwBHQ4eYhKrc45nDOujkJ3A2O5xugW8lnHXFd5BALaUVUuyuLwanzK4SQiiXv2sliP6C1bk00+d/jcVjK1pKWZiOYNw4OsIVDem+DO14ArwaAPc+AdoJVnHcdsPiKg2ruExq1fTFgToRpo36Qv5OvRM7tnOilksKuuspLgETnDD5zQMPKi02jOT9IxyRoqBhtcvdoicDQDtyoRLj3I1jb2puHh1d7gwzNCGso1AiJjGFVE6Odsb+EKSxCROSFBzFrRnrKMYTart2oQ+GsDbcS9ubG/VnyJG5bIy+JOL9rjlaKu8IMUVLRUbbuJbOimqyTEIlQj3AykGEMsZT0Ps7u6YbOK5tZbgLtQ4okm89UoEauiquujSrwzXgKiMpwrFbp+eRYpRZUoViecJ4cofq7WAllyCmlP7aosj/1PqTrXLE8tOo5H3+voQHdXbrv4CuShp8Yi+/sHjquYV54XtbUYBtkUZWMe+KK4lZOkP/YoGTI4t8UikDoWxYFat7D4K/1cs/Wzbb5ItkW4/+3ebllUeYWfkZmuJ3XtA7MjE4oJuYbFwJqsfVCIwIGtPttTTpXbU6JaUakEpUFqXlrvNVbeQleafoJviGtjR3sYzEW+hqlc9x/am+56iuAJOvggQ39h4gl6PiAsrhDoFbuIzKUNFi/nQq576L4aQrvGhAEAKWSw262o0B100Nk/jYX9RTw6VsYl80W15pKhY2zrzZ2aZCxsjAmb8MKKg24a53pcJ4wndjKvbMddIq53l4919goUG2ybT94d1nRQoLSHUg61LkfB+TrEmVE5ohed+uIio+AV+k+YlJFKEFQJRTpTjcfBHvOtGeFslG9+HmXWhYSPN8nAW0cu7MJZ7eRrAqZc8t8UTeeM4Z7AEhp0xByX8giLQS2wTqunG8ymmhh/Ui8aeSZBwHp2qkHcIOIpnsvuGejvhdMQU2cY/HUuPoAODz57MXMJZ6RB6FknZ/9XL8n9z3oDlaasfBM+ePN2X+McbCSO7Ct/QqBahBaZPF+HniCdl3U5qW98xhKzJLsgr/gsmWwPhR1hcpF89yOMzZPOLbuzE1L/zH/enrNIRTEaL6a7sj/r1WlSRaeSgStqp8t0vYsRzPWPydrArJqOnva7rQEeDpCyFr0o2vqDNe42q2iLS3Kb/xRmeZbo+IAxbjsd43V0IVbRaGqi9txG9u1pWFytNJWBX+NBk0104E4ozTe048+GDIE+rfD9e6Kal8IQqYZnaBZsx/8p2VHqHAsVmpmzehcGNz9vcogiyj22qRMG/Sa3L7uaFhctS0GW69AbOckLEU8hZIPnHC+1sEFbCXKgwePe8sc6QUPQwggvomIdPn7guRY/xsVNYZd6gYauZBggThakLVIlzImxqRjVrvgLh53U0j2FXVNo16vIAMD2AyYD1COjSu/UMpTgHMhorx232ssasM64gCNRV7OlfKmRoeel8ZyjQ0oAkLMdr+z+unSKzbcNK32MSnIjaTbSkY/yCay9i/4dVSTeZBz406FY/DypyfjZ9CJnFMCbfH1L/IsBB/p+f4joqdPtyHVt/aK6Aa237S20Ek/UOdUyrya/d4oS96rdQZ6kGj4nCToGu+adDZ7CxmkanTirt7ee7c3ygtkR9Z0QnHAcj8xYxK38S5D8DFxy38koLhNx/jeNnXJ+jERBOf5yPIPLbpfXd6/nxSZmBDOt6MyGtvf9+J7xPeWB3FBG5EUyrdysgRmiSVUB7ohM8UUFiivpVMhIXoG85xKTDQ5+OhxBAnKSVG+bRXQD2Y9eo+rwLxLoFxF8rMb4Mlpi5GZSc9qc6Ur9Da0VJh1J4SxqhTb1zcdwRDSySvv1CopOI1bxlg4ySzGo4OYY61Ru1KCn8Q5bSBg2GMsYaul0hqJGjyIxBWQsDpKmh8O6DkI6CKRotMYl9DcjEoCneZ4gbnvCEgrxKzPQZrblZP42+6S6x65P+wYrLrNwkMU0SGJ6mpsbEUEKpA3LzNDo/hF7feUl7HInLHzVBXb2gwrxhr7/IHBXA3FqHAKuZ/I6/2vXxI6h30RtFTXoTm5nHnBF/0UkGEhxfXUOm7/gFyWyHDZfhE5EKhw5P/pQu6j8i1HISQv44DiMCUKzWgMGWl85T6o3Q8jFO2CWaIVLuxqA0r5TD2fF+sVF/mMxFKDzp9oB8dde0eelEV/rQJ3NB7RpKPZCrG5gwmgCKlr5m38OnNivnu8RDuYKuikhPeSHbe7mLJEsiti9IXVrHz+gu3b+hepdl+M+cRTewocJAnvfdAa8+DwralLtWmGeiwvejbcTPG2em9a1CFEX1KBsHrkzp8k8zKubxlQmkFzZ1UZ5My7XR9CRG3LBkyoDjAk1RUcKlx8HvKFYQPPOnYHI9aXChwMuvouB83NsFFtTSsp2wmtsvL3GU7e3u2P7zym+NVLvTU6tSm9nH3t2zVUpA7EezRjPKZnv442z/1kd9wJmS0hcqLqxL86iLGbVdrESmc0ki7rbKtJNkYIxFoyXR7499NuA8WIajRM5JD0niz44G8l1FrnDOEYddD46LgIddGukd/l3tLFwIeqMG0EO/N1Or5EL1ImO/h++CcFkwqVAV4px4L/Xh0vkJW3Vp2FZKcxHD3u3oey/s37Wt3vim8m29SZ2VYzOVaFHYgM2GuLdVeMZ8y1Ewj1mvjNLVWsw8QBxxzaVN1JO3h3E/GNRAuHdLKM/lLA2sS9cZvd65zUMhmSVEHVMkMH3QkZl4ULYSyuzAZK6Nos6psGUiFZkfULdpzprXqEbMcbl/f3rVurLACYax1PVsVevlbzR4s7IzbeMkZDD94ETQ1b/e/9getowgQCQuvAD/Sji2GURVx5yJEY6LBuromNxKninWAX+gcJgv65Moq5krsw/22UXEsa8fmdoQ6MalMw/17XgP9PxF2KPgMoll8vZQbVVep5flSeoybN511OY95ZBm6H+bh4tecVEVu5sUTbfy9PgsFRz7o2faNn1rYmbkGNgllCbtKVUAA3HkqwffNbwyYCfbrKb7rYBraGe8268bVy8oiGt2dT42t6ejC+mXDbRvLu91cZ4GwliGd4WgfKEXCOZSQadzldDvejtSI2nihO6tFuCpzsI8KRZBC3ggoelxewA9SarsJljKWLeUf+cDyEVAoCVG6eJznbqKChXV/TsDeNoKGQsO/5J56PJovmqK9b9OqCkFLzrQG5XcJMw4scpxd3cjvaZWseYlLzhuFlh3THSSXCPM52gchaM8yP6tdWaFKEYnWyNw+NZON33AO0y7hDrtUg/nEglHTwhyIGGBaRj7u3uGktYaH+FJYnuinFc7LUdAOplfKPjzY9VAEtnm2rT61CD9CjZP0FmWHxuDPWQs2ld60Webxa38N2XjH32Cyt5khn/K1etcMhXs4TW4oVBQRcg+hF3FC+S54tcFohR4yPKmlfMfkfyEElGeKYktK0K0sJ5ycmzGNMPw2WQP+DWkv17AvJDpuZ96V7+K6vkN6PFlPWSKwcPs38ax33+I5zsAEP2YPmA6S4Y0VVZJmZDBmDLl4bPK5+rK80SZtLcuqoHMf3w1aQAkKCqI9mblApSBFC1jTloHDWf3P5EQIutUbIr6Gz/1m4hJjTkKR60p3Dbq74blhXOExlLlEFm2Uy91wE5O0FLrIQAO5ITMqv47ERBbvVWOzQKoGFthzoMbJw60fOJ2i7Lo/eDCeO3441u7T30/B8qduD6WSyartmdfS+klL7E0Fyr3Vr80mLz0sQce4mM9oKeANRmNJ+WRaR3zQJkBRupE0P+7JZeofaeaqszFjnlcueKc20RoIRJ9krv0Xilq1KqMSOltb+xNhVmc2yMoYCj+5XFN/kpW6AbIkb8auDEZC6r31UYDrzkYiwXDsnTZWIrDsgkGWJxxvBOhhQ9BsZTclZ3jc+DVkVQOCvoTNKQZfdVXfFYjUjHfnKO7S3hsCcJMmI4hX2lfjtrfTzOmOKsc1jPirRv1nQBMoRiEK1qBi/tV4HjmSrQOUYgX8UbHPaYMYRjZ403z0ZjD9j/HLXXvI9c2F3UEqxzMJhwiFsQJ6Ojh7csfr3M68NE2xWRJdL8TR1aPTEALWKQiT5sWU7ZbG3I2a+DylJkH4dv6WeWrfqGVErhD0hILVfmTBnyREpAsmFpvgeBcUYp44Svrt1aJ89dIZ2Xm+533JBtIv/Rd4jPsYcR/9vM86Hlq4dY75zfcIevHXVRwyUL+qgNO1SHpY1DErnTctzwvV93GAeU6QR55zd5LOBvzJTVAplUMnuMeLUKJBA647u8D2Hhs8wN9qhjn0lENaZqteX1q1wd1oVG+YqYGjuw9+3M1x2MDeqB4Nv3+lyJokZ9ovTWYy2mAM3r4axCtcWXHJX9+4iPK9DrURpuZ8DfQcEjE0addecXZwZ5exqSrB9pZtJRpiF97Mtyc9gUBJd8mT7CkXijwtvMNNH8mExL6vG02h8AWPN4MhHtiqpUWNeUPozbv8SjRWNIIwV+n2uBbqq4S4D/6JrgN+k9tk1qqmDyKfcH5z8RfYVgt+xDFMUn8ozLPxrpw0crwJpBWvhqC9r7iRwit5yh8UA6MjN09FGO2W/eUE1Ii2DcBcFW2Icj0mkPXVUiRo+jw4jMC2SzCt9CmHGF1KVybjSOa2tX572Sqg2WnmPX2fgIoUKgZlnPR4rKaNPEtGHkCKJdtpWTN5NEZ9mqsJuYeJ8BjDvHfpNu4l14N/Jz3Z+P3fJcyHPywmgkO29s2IfpX2Hu3Q5uaWj7hKlbKZleSN2aIm+7ueak5Rymd8dblNCrCX1fxJeKdXeYfjrCPdjyjQ05iXnBhF7bCxthDLXoi8Fw42fNYH5wbl4qhea0C9KiETRW3Q72heFhLDVIaQGcx7hjuWHVe5ffC3T5PPGBlF8ji4GqhHvXIAJEO/H6ahss1ZLPGzcUW73EBmk5FtAfJ0MKtFBC8QUD558lX4Lgq7HKGEPeR9r8BNRRmiXVhHdqMOKXCKJZt9LMBqIreyYNIRNpv1kJSrQvf7xMud5EVXc6kjqVkT3Sr9DgvtuMiPYT1W5ac3Hx9xMNqWAWE17UBuK9eSzET3Yt11lzXyO07LMdZh5MRd/rSV55RXZr3zISFSB8t0MYwN3Kp80rUhelcbu6Bxumx42Vd8V9p/vdz1CiYbWkXPgxU0F8ucB2LxFvbnoNUFkuNVOC0hEPjpST90FznWC+Xe31Omi5E8krtyqTFpIScQL8Qbv82jI/AoRaChu/JbZO5iQAvLCBZvjT7+PedYwzav5GYH88lKrErkXvwmSeIQ7wIX3ia4DH3GT3xGgSWLCV6qdvY23CPItEAK9utd9sveu6x2pEd2qN71HTm2fDrYfnSEzxWtk8h88mdWum7w8k02YLNzY76LW79eh8kMv+ZvXEpDD1xkBQC0tq9QGn7G8V6DM1XHttGAGuGlD6dCkc4voinMwFgz1wcXrAAXvPhZfl7Munq11rPIy4G0rbUSSXe0MmXvuju7RUUhM/79MN66snP/o1jx04hg49RoDnFcngBbkOeHa6+6f8DqGUTc/AMoIs3CXqbaHG7tptrgRKOeyyoUDtU0Vl2HtkJtLkmOjPwmOWOCCHtxCRaeCveepfMScMFd3mVPxME9JoS4Sxo5xRkWLAafzEyHPyir+0FlkU4taEWXXgX033AfN1Lr33Bvzeard2OWmLyLG9cm5Gy8HJ9SLkq+hqoWUDWjqun/qP2+o0CziDC374o10PSVrMIgiy60G68bybnK9x7m5Xlxdpb1t9pzXGCZyHaNU+Q+1rXlS8nvPnHDPwjkxO3/9s8u1vhzo8s3eNO9G/0rgJfweW9s6Augp2PRLVsWpeiRwyvNi46tDyWyJvyvSq8D6R4YFE22PGQxd2l7gZ85oA4j688n7NwyQh0Kjtnp1mnLDvIT4uZ4ebzdRchEObAGr53mvI5sWAfIrYCRR0qyubvst7J521Bcf24lxX4cfTFZwWQ75DabFpw5vsFYkEI5/5ZHlAX8AwyxgfKoJcfP7C/I2hEIBttd6LDMKdPbOFIgdBZERNeDHqEsk7PQf3NMeJa85jEO0i1FQXieKPZ3vEZNkC5oA7R9db+PB2f6PK5Gpm75g4Xt4tn/WBRxcA9Q9G2sfyZJHAx8NxZIk7ETOIc+kq/nEM9c0xMBc1+hwdKcFXIanmfDZTKAiHIJAtJAThY9CWwTBBzfooKCY1+RWukYpENm0hBCsM3eZDzqyTeOrh41L9yvHpIEyILboybH906CURNiMyaUDmTr5O1MNQLo+E9zsQixHTOhiNpVIEg4Zo/c0VaRn73juUl6b/miDmgTihxX3Ueaxiv6hBFV9F5h+nU7XZdgEfBjQhikzz/Y6ShhX7KNxvY8eVWqjALoN+nRHhTC0drNTa7uofbomRMg936WGqJ2H49tbj7jw5QSzdEkWS/4uYr5IOspKmv88K8IQXe05Liw/XoCteYJIbpHJkyFDdm+Y3kyA/R9Wj0wbl1t0xHjjG9B3BbS2DKU1ONm7EB4QqwUzPM4ic0y1EJWd3lcQUC9jFEhe4TcfGUIzxr/rd9NkSb/vKHE42+8ve2oWOSxgMvEF+Y6llnHYsLpyUgR62nrQU+RCf6FhJDxXUR23+vWmaJI/9tA1GJRsAyAhWGuvKwa5kmRGGWCOWMa/3jxieqoackEUc/qdPs3Tj96ANv6D6wigZAFuFOJzZZRdw2bsZBSF3fDneLJDTR4bHBQv6PN9DjbvOuCiXPYXQ1ZgopxuD4+hCmZXe0/tUucd41WCUAWSEmuhBJMC+1XFMUtxYHLHdXx6+N46AATi0asdnUrLWG0G0uKmQq3Ck2OpGsQNNuJuQv4xcwDd1Xu0ZY41koLmZdfnr60Zk6/v8NIoEvPbid9697R0WA0yDLfbWgDy6Nvtr7w7Mlwf5SoTz3YpImDOWqDjdx59K6S9BNcX5CuQ7NuM7mWXkbGN1cJjT52s/gz3ePJ75nDbOD3WweUcXPKtYl9QBnz4uRyXMuNWA1TnchrFxAb/v3279i4RCilRcpXS5FBWanAGnyZNSG4de8BaIATqQwQvH7USexU6YNJg1WzEp+TxhrlzQatL1C5nPbQtJaGau3M0HDK8uXA54vxf+YmI/bRSAU2rVOwtIQJOpoIbGjkkmQnyGy2JCuxldfAW7dcEXPjf59RUOoPh3VKM+SlSWn0a8OWib42y1qwhSRbqwkjyVlHXJ7OS5IlhXwNvxxo5G/QJiWYclp/tlSD/w+ltRVicHCk42J1LIful3NuE29OJlXxiMIt6XyrFK3EQityNvTzfT5oGzgAqCfiYVSZ3kta+a3SWZ05g0faRngMz8Z6wCZuf3gvFzYZZoY9w1836P8SET2RW+P7XrQqSfm/pWrCBpXrxRevVxbStBgDA3mf7SmKxvJHqdQzHjK7BCBlFrzm+u40e55u5K4DlwLnhKoCIvp3aVDXegKwRiQVcfyc8yX44cB7IIUUjmVxKIAZwg4PRivmqGki43CRbd3TTb+qqAB4zDZcdDSh9VwFrw+b5nLdsO+cV5C5m3kJZuKCh5WfIOWXWCgcaUJdJW/0JWdmzLodsgqWCKo6oIFJH5dIe/f1+JPXdfS7hCkT0u0XzojEwNVloIh+ttS7vPob1CTjGKC+Uc1O5xjQhFju+nLAshk5ijlc83n3HvSNbbNiI1imEWOobT3/Adn+xzyam+qOVf743/NnGAqna+YCDy9RYiPTmElRd8MXnrai7Hxv1H3PyFaifh+ZUdddrn4u8PG8MvjrmKDs1HSTUbkCafL1/jvRlBCTjUapMY2QydNpTN1gwH49Nx7ZiR7vCyHlgVtC4vAk2F/2pazyy6qd61hVs0h/m48oR0ydBXKow2rrp5L9B2r1D6jz3kn3BlEVP9Y4D9LZ+weSOYg3DINk92nFeWahmf7F1w4YRoKwQlWtJMBvcrdPhgryqHZLomm9IG3JAj+j5S0A822WRreb9fyIeBSdS28MC+iuIdINng0RsdtzgSNMenfuXAFySb78OrHLY96OWrsYnO8pK5rYhUU+Knt2eU3YuVeM78BSbLgNCXutxMDMUgGc/pY1/JOVtPrON0KjEgODR3JiGr+9AAlHAJcgGwNI6GvAs+42m7Qh82Myz11LcIgYLmZJsPko9QtG9SoDrUv+UzX4YS46LdYqrA9kYBP/Zyj/kVC0TH9DjwX9TQIxBuQmiGMxpq8KE7Bm3jeZzuluNCDHj5TZUkHYszBqaECRU2hSAJfkZ4pM/rvmezTjYWx7Rq8DNbxdgVfWPSFS4wIt2CFY+N3MMG3teM54zp64xK6Szxt6fPZQrJLCTTqNOiSjTustRAVpKMuFpP3axZn/RoFIbDILPGjyeu3IwlsQ8A+VVgLffnOEM8B7GxsE+xmiUQvKD4AuqqTpwXJulJoa5bfZUl5GcRcYywS9R2fAu8yE73VlGNOvsSOsxYv7pSW9ZwKEG/I/RIXQU/0Qpi+dANCMYbmJrR7yaSYgZeZQVJkrr15kwtlV+ZqH/1ynu+uuJUlk5r7ccKqwlpKsWh6RXiqS11L3ZMhwZyFxRyBeMV+WXab71cOkAQL7SOLV/GAsoCeDEQL0ur3cIXCmWRsoWOW+syo9eQ+ELqnho1OuI34HB29BCCaMcZhYaO8D0IhP6+LRnuSoyA3Zwsj03ujVDB6VmJQ2HR+8bEcGSgTbg9/yp2VBKw/vwKPOvPjgkuD215dmYS4VZb+DgVHvjuz8JIDVLVQ1ElpgVC/X1/HNWIGiKGWet+3UHMy7gv6JsipIKFjjtzoNEdop4P9XSN+MQkRQHaEsniIMeFcdL9jYl3OlQAaM5EXF4yIG72p3HkGs1/smXkAaPetVe/oNMVPxdnUcEfW9pwj1rucUkcDh5qibrIO4MOi+ZTnU4XV9W7CmC0tyUpiXU82R1yU1DyjJMCXyZ0peKv3k/eLKxW3t85y5dvGofertU6YjqQCd+k9U0Tf4nOV0PxLNLlU7ee1KynsyPBKz4G++4E1dgxMFKkmB7WV8U9KP3YFQrZjdYnnR92yGgk5OgDo0pcw+dlvMq5H36NZtaFRigH9MXQ48lJ0jsGDn6MM1pIRC/jGp9lTdcHHX2k6cZxFaj6jNCGLEK2C7MQq7cFwcvGa3/gHy+9Q8jfcCa+vUd6dVDuJUwqfPk0aYDOoZ4DkBHOPr8bNCtEFEuQ+KeuutO5gtjozT6oRFwVCTOS9L9b2TWRozRjonFPrImMdtKX1rexqbRXDsZRD3xdgziiMzEsx7qmAwM2XVNVOmAoJiejr6E2yGfHVqJtY4oJSHySfRh1aa4DKF5nWt0uiZuuvdTsOh2EPLFFL8H5FFN9wHdEaKJOtajTa08swy9QXj6TCXNJuQUzMA9eep3+xInL+O47VsfMUyVUm5QorNP09Uh2yii5dUDE0xMPUxnXfXrjaTEvLKje97yzfpDf5AEnAgJOql6Krr9lZQCTEzSAREi6Y/NTY5kLyGvuR1M4dMhk1awBNLkPt6te1ZbpVckLSpveo79Z1MHlTfcXZ1VsdoGcomN5QFh08nGI5oSREI/2QTgZHhbCDb25aGLJ++Eu7yCK62MjFJj4p0scmhPybbVTiqjUfmGxA59FzaMyxJ5KvYSPrpzjFnqXB/x0XglIQ6rryXVJdnXYnL72UitdJeXuNynh9ZEaNU9RyhQYX6RiQJI6vYK4iVPDeRjosKGQaTo/VvBtE8Q7p2VPbGat8ScQTioE8Yb8+2jmftbMvm7dUv/2bQ02EB1ixeNz5EiqWfTGds1K8BEMvYRxKpL6o8Y9r5dJ2+5Tv3lDbm8lInQJLy4m8yx/2hSTpnAwMPgo249KACb22cwcm0gVNUIOlBTJvFRrhr9rJHb9Poqh4Fwwg44l9mG7Bn7HLpfg58PLCNYdfUufW4eI5eazx+9cb+/Pu+EzYdjCuiyNfA72HL9YCPdJqY54UTcZOAsBhK+ZXS4JDQ1XONpGay8QIm7S5x7DeLH+2XpiSk4kuSZX/Y0YCDheD/+oDfYDhomi9j8R4rVegt/5rMKITLYG6vppaLKEivwagQRB/HplrZfKioFetQsxdwk5Kbtvl6ZrIx6lrCjBJS4VGcCoEZvk8MWTWaELJOqnqGiC3ucjOgopoZ98UrDjDnsEbFIJF3S7dFZtSPd1W+pUw2/kR4JQ2e/wIBANeJG+u9AVEJNYa716he5GND+uxYdRyZKIDN9m0IBjUtHZc16CvcpHogL/JeU8JcaiRjjpa8Drz4OVVeGHz5LeAH8LQEC99j/1gLrW1vA+T0tQb9spXN47oKP1cc1lM3HelOMVQK+K0bqn2HTZcrmO1f1col6Ex5j6QY4+ikdmFM97cdVNCL1+tLw6kBk8CYyqhgpUpas36kZaGtKqL88xbSw85KG4zzIVKFgfbHZ0vHQSi1t6TGD0jhvwxrtuPEjcgG0Suk0LfFwhD80bMN9GQYkZXhP9djPV957JUe4aK50/0lBQsvqk9SYlALZpdP8lJDytH38emYXor+LqTGY/bBszOpDp4l0PxDEP5wkJ9EbXiChh6Cs54Q9mFOwvGjjQ2uEbEVbGKEjCly3KlS+qt1P4h9LvNoBDMRyVJOsnRsJZNokJ8J6HDJTAiLKSgDbsTI9HhSF0bo4MfrgoRgG2QMt9jnyvHSsZ7q5Bta3tsM/uaerzAljwCcYeWXhsmI5cg8cMGsOeFND24Oxcbz0wMp75gUVVn9bxrEYxNLjycE+jtvyyrHvrt2QDnTJclIRSb89ioQhPWE/fgyST027cZAw2z2+fjbyJrwF0RwxTphwqoqC1UvPNLj3xNSY78GZqD4cAo27pWEktAKJEGz3sh9SBX/YL4CcL+Gq4XSh5gXVDGS6lgqIT/c6dmR0F7JHMNrTenBmcsLgeQG/0aGEH+N6lxPdm9D1Bwb+i09Yp28G+gJ8wuTIxtNbnYQ/32XHRmE7Ea+2gCQ5/C7MVRHvQ/uZIK+Eqa4SCYfIuK0OC+5Mg942baBHYwdSd6bgayAs0h+2+UiVOE1pUZN+5m8d5hXSnNyVr2N7DqBRRFqXLgTy+Gt9qW1ptz0alopIHi8Bd0Eorj5elbW2y9gUXNLCf+Blc3WK4hr54a7kZQnPu3aGzP/rtO4dUAZRMnVe72bkvjd3ZVH0dY21SpDhoUX7MPqJaEciPHsq8jxjCxiibdq6Btg15wpJuAkWhJA78JGKhBMTX7IY9Do9J/uD133dQfIx6Un7U/CI7NJoRioAkW2+eqz4eqX1IvuUOVcLXCOMq4s8WC9ZZolFDTkGypuGnC41awGLUv1CQy9C1CNGJM6rBlRvVTItgWnTpc2n3zaGxW55OYQklBFI2Nh9CeAYFWzidLbTNlmD34+L/U+sszinPm86reftyZRjOl8H3x6Qu6JwzEZqosJFK/F674rxENi/HeMw4aebPWDrAI30A1VlGoPpjtZyTak17eYIdkqV6oTdVHy7+Tsb9GUVk0g6UfVPWy0wSJDt2wfYnC20m3ef9cAyljeuSjOn+5nexAQ8lWRWl8lyfLZY8TkzPGu7iF5kf6auNx9YowvUlh/6gnDRwarKTHfxlqpk90i3N0NbGNSBSpmyN7ZWZvrw/Udq5NdZs+zFEmJMHJo8zJzEQ5UiYURwA3gDuIdbRRBcmqf0QANkS4aOtJVCr/7c5mYpV5xTW/anzcKtW8ZahrHwwgfPDsfw9iZkgh7WzSNfTczgUnMrkrxYjmVOC/psIEdcr/WoI3sYTWUdGKwDKLbUV/pBF56BLjvlpIKskZePtJQ40xgjrxxXkgKMa9KCrkM/kxSMk5TYrjHxHRxYSsIBJWmwweLL0Pcsi4u2Nwa82peYTyKIV16ObR31XVmZSQFnCki7uMiuYBYnEO6tuPcoR9I5ijv7iCZLSXEn9UOcNY9u15NHASRsRRGdiulNSikkuOOs6T08Ciu/JqNKb69pBH3FZAqnBtyV643/kP7htf+tPLnmYOPIuN72STFo+z/SEW1b7Q/wEDQIUQfhlxj0saK8wTSvHbk49LMCbnAE/ucX3kpvXqndhCOqb3nP4bd0T2wZ7mqBoSLgNMLuEAu7MYE+eUfU7Sf2JqesZuDmlDJ/cXeljpXpPZ0sepzHY4wCbJDjvhYo4zg3TGCXwD3z1KErgwhBeYQQho55TLy0nGdZKU8mMQit4NYDF0O9gSuUe2CsnFVU/Pw2WwuwVL76u7yD4RiM5vfpXi9+nr53cST0EvtcloKlTQod1/pfWfoesjbSwUvfhNoC5U352/xs0Q6DM/aw4vRINfYcj/TcZCaUA4XdPlU3EzLp41atZrgzaPscmnoSb1LkZ5F9erle8QuEu9rP4Nne6Bt4lz3PcE7acXBSKkKgOL4L2lDUzpLYMeJAptwjPlljz0I3uy3Ulto02cpzm4oK9XiPQxct4ReeSsfWGd8x+Jmcs8AxyY//5XsVuy6ioXfSnQhaV/MX69qBcCfHCnEMiUfEfXPUAgNDAQuiReOWxGPsAdhQDSsFrljUzk1/nuH0qFPN7ycUJYhCKvQhpvEawhREUmqXmCwrotzCMR0kBOF1EjzWCLG62BkcdzvICq2+sfZZDMDtqn7O1FjkaP5Fl7EU05x9g+Q6Goxzh3E+NhibyVP1mc4DXjZ2GcxmzLY80FXum6uxg2F5VphPF/QpzkVRKHZciELZqF5MQZQwCltkVG03a5XAUkJ8m3S12Lcrrk6AQlQ5jPcnX8kQmuEUjuN3OrhxwoKh/1zRw6+PgyT3NrKW5BiV3b+hBssKfvuzlys1eLy/Lteh1RwpVo6FH0VtMt9kJHMrNh6kqYYu9w1efDRXyLmrfkPw+ocBwHoLAw8i6HsGuIcSCCfqigT5U6irwPgavFNiIWNWEnwa1VfrDwhPQqLEfTk9YQMCfA9A9OD6HWbfaml+vspEgFd1zu4+TTFjQvd9Ask/9ia9O8M1PXvSqVvpiA9z8sKOqizTQVYUyxp8UzsSyQS56VndjQlzXdwgjZg/6ZDcUFAzXK0/gU9PYsRXFs+4txy8HVI0BMrHoeiJWBP2bMPJ1d3hGIhpDhWsXhvAawb2W/jA90R+ww6XLHyXRcCpheFVUXMLYI8d0pVtB9uZayai3b+ALp8R5oNob5rr7RBARJQBa4bhCANZU3TkSS0s3OiP9Xo74Z38OiP4iadN7H3UlirJ44Ju8adnTxrRDA+eQ2AcYO9i2VktZIdO/oLsblITMmDSyvTM+MG/5BlLqGR9zlsRkUJAb+5lkDSBSgKgsgL2Ol6biSMYPxa5Yl6H6sTISokxEvSbiyi5zjFvo7xUnLp0nWmi8g/aUoOTyc41tsMimKlLkTH9hnb7hqf/r/z17zXw/truqVfONUmbDoMGBsr63aGcpNjQfA7TR3tHTJbg23cmKhk11i7++4RAhyn/QmyVKQ1Qws8Xn474QlttHQfySBW98bBlEBexS+v+t67jHSkff8ZRVVUN26DjknmAdWPyW8g5xFo0EY4rZXN6+vTKZMpnNHxCbMFYozJ1QfTBEAiZqDCFIssiHvOcoUbYwjosG2WfUhwI+IHfvs31wxHnDG9Oeo8AfsZ9SsT+pmQJUZLAMEmPbdPy4BrefOh0nbT0MwPo/aeBJgiRBo4BM2yDHw+27Brt8JledD88gK95k8OUvq7apCR1CxpagSGyY1zL39fwKzF14b4s7ZxDRR+3KYoETJKk2l5FC6ShSnEcF92wbZrZNla9YNgrcHa9XE5GxnRytLm9V7JRODJO9hZNjV8FaCGyX+3CVVhut/n14r7jq3RYTiHKhsCqxLgW+itOHWBRE0YN6oRhQuqrVIrl7VX+1Ejz1pgL6iY4Y7PrfvyrGHefzhMGw1bs+pun03JvY6TZfFqU/mT5eesHxCmb5AjMcZV9Q79xMDn90W11NCnSSahoUocfYhmKpbJUjz7cj/5y1lECQUUA4mWzSA54c6Eyy4tY9BfO3wfPQQ2HvgJ7UhUeae8g9HUBRAerIlpcJKmdIUvJCUCHTIjcPHiKvdmq7obds0rTZ9FyAVC8HH96PvSpD1qBH5qlm9uynpabJqJ+hDOkjwn6TT/dOM0cQ1pdt/JhwQDq6cRte1KyHF7Prx8KDTpNRjcpns+cLy+aKP40bsYr/88Y6rdVlEVrOwhQebFMqjaUSPxQfi+DqFFLB7CYvah07TSqUsbT3lKFbdy/Q5Ok94QZ2tlhzlzp716gQxNN7JrF2GNWqVpNMhz4Z8EjoukaP0M2HmNoIzme6stbDBBLeUVtrazJlp2043PtYLWfAdZmYUB7FnkdEXZE4U8NGHYoDkHUWY7b49yyYSgCpPVL/7OBQd65V8ST/M466v1beKsp+4L2O6kkcrbtRbqtkDYqN/AxGTP4Y5jy44UoRNbawCDrkEqpY7/o1aginMbN7sxeHKaBVDlUfTxcTDhXhGoh0ZTpTJ86FBbaphF+BT9kypbQFfBMgmbeXG6HnmP1jcuoHvhTLRFbpbWweIXl6nEWCZXBOfDw5+DrcIheiGH8vclzWtGwiJuQ56MWf0j2qL7AMXMCvvZYoK+8jfJmqJaZ1BKn/jMh4kmzPE/KWK1LT/X7oCwGngUfhVG7jVBoUTDdIMW17dylQR72eulQyArKd91porXEKP5vUkps7woBY2U04yJfWWIRs2e6ldTEsd55LZXsN9Xak4JxxkpKY05HH8uLJjoCUGoEnssgPffBEM2tpaEG4+3Mps2XurlBM8HsOfjlHeJWeXuvZ4RZmdvyZL0UrxSKEWAWWbKxocZFWf7lYwVs7u/CcL5XS/zrXkPGaq3blrgaoDtPsRxxDDRS6JZUBn//USbFQhPlyNqc6WCgiWzY9wDawDdPbwXBxmA7CGsGKG7C+3+1sdVjwgkmnFwWGq0Etl1+WViy8mHSn8yciL+l5bzV3tXZuS+7iamrIwaFtE3Ke1c+erJvUJAzBrYUTiowF+AqjQJZm3OIwrnLSn+Ulc4A5YUdfpE4ArZpF77NSck+rFF/3Jg38dOzY6EyIk4bUSbbdADdgpFuKXwAVLGNuaJQc6LhhaS4KFH6byLzNxUrdJyWzg6Qmn/TJTHPEzICbuQzk+I7gGMACdUfaq7nChNcMrizxwrKSjUGas8mHL4XNTefYAJxt3sMbNReQES2Erz9RiGAqopP604EDg0dPwuiC4+TILZ2xM8Voz3jxTR3/YIu42dOK9rrlS6SLh+LCwNLkTcSIukXg6LUwYx5AX4gga82xgA3EAAiqGZZAckzVvnf38ke5nb25Izc5zQ+0i2BBqbtu2ipqyay9suOPgetw/R1OJiHEXWatTO1j/us0zCrIy7wc2Z+dYNgZBWnBhCqcY9SWDArUU94IdDprobgL5vcoZbFUJb6f45QRALgdfmQtlUOUFrv4Nacx0pcoQZ4F2bwaU0VYUW92sxlExsMbvJ/idGg5CbP2IsqO4gxo7/3IUrmri1WGvVvY8Mffv0sV7on0dyLFNJs2xQJkFjbT0qqwovEM03M3fgyZ1s9/0FjVLhCup1MT4AgjE8m/AtSEiOjRgIVf7hyo4wQA935Cec/86NREF9SoE1RjsnkjT31U3kce64BMX9/bpkSvDoci/Yra75thK8J7G0ZZmjMr5WOTfr5cUF3u+74GwB80yPBUV0ZWJXBCFN+Lo6p6Zb7WRhzpUPZpb7KyzRNozahsW3rFIjuUafYB8uFp4ZNgJd7YEiAAjecY9QxCGiKQxj2LkwJKO2+RRy/JfTQ+LIs0BqYbQBc5R7E21ZAXj3i9cfHzGFB/WtRy7kN0tkWIWWwwy2Sz7TasSTYR+FMNh2AXirdnOJLPCcYPB2cSaEsNoZfLQbcAbfnNiAX8boIz90eoLruf6IpcnJNpEQlQ3U7XwQxZgzPGufPJbCAV5G7EUQm98kcS0znshf4U/mVFov26bRkCMp5JMLe7CqGMSm2pzDbob9yKYzq1aHn6HwAhON7HtOAiz0LCvUpwiz9RJvFqJK2LM7pI0EI7bv1eY0gQDYqC0wGZ10+1oi1HtuBU4vN4ztrP/LiZBKYdddDb1AcUPmWVA42dCuPVw7PW3snpg4BlH3YMw2TtgZYFs/8fJBBquRaX/6b9neYnwHfj0v5UEITOEzALC+wRRvla5X8NC9alucOY8YaAb10nVhUG5FV0M6LPFQCeSYrnre6dY9AbI5Yb5opaAo8mAdDoDUaMNEujMdYRuWw1i2Ay6LTaBUf8Eb68R1Ea3nMIs8piZflAB3nAdjKcdRRrxv8YIvXR8w55YFvbAZmBcYuYbQ8H6DTLDZ3rg2D/t/Yd+YI0XvJ6dHkCly0t5PjSBoGnjZPslv4jwmv66E+xTbQ7AeHpBWuMSeA5LPoziq8vC1bFY+Pl5npdX+/jOI+F2QyJnaIPAZj5dtRYZCosk63uejR6XkaB+btbEPS9iqUe39bj9Q59o6xi0U2rQVC/SXQC/cRaIV4Q3LAcNUlZsQz+Mcfp2H/zPYD8Br2MxbAQmAiKGVDu0NsBqhMpZ6tHIjX1ZCSDsl6vtpmjDm4YTN+oisFsfYC//Tji4fxwWCHqac1f3xaR//fVBXAMUdhgzloJbuY36+072dcmgSbHaha3RbwxilGrBIDGCtAEDyfa3ltLBsQI5WssUOn1a5uLQl5VXC+GMItvHDgwPxzFww8m5mutf+cvcKZe7Uy+cCTrGqAfVkML1XqR3i9rtnsRE58OISAwQb8IDqz1mjPZnNnxkpFBuwtNC+ue9sAx7tMd4056EAn4clFVsDFYICqdPpqaLoMSSniZepN1rWFnrVSqdMY0jMVNNEzF3JSH2EcEnV6rsPoDyPsNDj+p7KhyaQlVng15JpBGvcWeoQxwzisC1JnsIk3H9/6NHrG8s0MrHbWDP/XyIm2cteZc7kMFWMGO06PIbOGvB7FY8kTNDeITSsfB03HP+/rk20CAGiVy5THFc82ptbTVKOzZtpa1TJB6ntBFRHp5u0COw5to31BLtR9Fm8P/ye7PQSUxNuX5mWbyGIH9ZW68Q0VAXFINvAY0ZbUhQJkzXQRYVzMtW55UFRRzFiKvjWDBgBZdlxph4GtwqbODR2XbK6lygC1F/S3surjQmKjCodHzR2HGzyYYeafKvwb7aASTcKS19DQS6iX1FOjs2tBSZhFeSn7LE4cjGAj4tFljdY8/Qa/W7UKLMIGwUS/WKlTD86+7W2dktlMFKhKUnJr4sLA9RBEiWfkDs9EA45UNmA/d6cfoVwHBa67ckCNXF72OncMB2a3Ja+GIOzYvEjvQqYaSiseZclF6tcJGJCIDd/Iwk27ojLvXPfkw1kcC74gdgR4OFJji8cE+sfw0XXSVjvQqeIa2QAoIJm6bobN4lslTMNlwd8u+jrPHZxxg1m7KM12WRTB9tEFlbvTmW0v8V5snRSvrwZvYcKoRGOXD1QEjtXp6BxBZL1eQdLh1oDpJajo7+Ow0SYoveAWghmjy2smRzEzkuepEiH5cfAvOWMgAdKudTbrrKFMbdzn1MODe3Js7L42tTaHzLewlMd+etfvrBZjk/RoRfbpwOjw3KXV3dMxvO+HV8XdK76jwLlC8ZEBCMOemfo/eeb1VmprDnQczfdySaKDrpFp6QYdtFRtCPqxAM7VQvSjBfEcBNEY7PZ9mJiH7G0vo+74lIBJaIWzfydrj3ry6SFDGkNRbXtQw14wpbDVDEUMG3YYi18Yi4nyXCh3jHLN3sBr3MH4rIu/aMkkangKUM5yj2nYffTbPyIFMGynKcxkhAl/2lX7VIDJwgKn6TBZmL8E0+tzHBIhG1GreADC4P9Ga3IfN8W+AQkTkbioJIy1K/ztZl2uY+sFDKKLRoySWtJmY8kfO2r2bgiA/fhPSBvzfTjPZKmxTwm5czibWV5lixOMd9k/cuPpjnO5EHIMx/Uei5f80R74kUAynpSSZcQZ8HVBrJaUgi2dL/UyuTZHrVVAQqkIsyCQJ1QeWkPN0PQD9rvvK91QnLchFY7A1K3oUMRr1XSRTFazifGU2nhX3FR1B0ctHRmDvNfXypBtkP6XkYFdfT6m3liIypcMvkIMYoER2vOdN5tX5jcAndAwrv/Bbaq/l/Y0QP4J+SIlKK9NGARdb6h+hekGxFVJaPn2/DY1aT3zlxvxzpvTyFlEkF8n2tCYAyksoLLmG+F0PFwmXnYtEoJwHy4bXwSRJe8hvCCEgQRm4h1PBW9amk7A/zdu0XVrGvnSrXw70SwvpR1p+S0BFVi8DNpj6yhVAy8m/liz0dkwe9AlO5LZ0K3YcSbRtO5QD0RorQZ7arPkxv72cMqJkVYUINivF/JkCXsYrA04CdjXKctfoQywzjsU80SIgvAHEhoXiT33IxgKndGmY5DUJG2SWCUidYT0dXlkPeObXTs/AYdVwSLrZ528wLFucYQElfpOnilt9j+DPKP8diCI1DHeKyKMOV9Ks/E1fuMGSESTsEcd9NW4ELa0VThEW7afMaSRPKVFmtU49NBkEoad1TjI58yVXDNu/Sofe7opmt/KzNHnUaPvBpQdDv1bMGAZz+4blvaMPs80O0wTqSaAj7jPQGXppXQxdmAk8U2aDEIRDuUjRVTWEonEzP3+9BDxNZqkXBu3svwf2iUwE8plOe12ro0+8+fBVUg1NuMSf1gKC0yrfylVbBEA9uVgan+PmvRBxoelq/1eFnILVcPAzCABmHRyVL5/iaUaR2bnoWcngu6OU529AwKpYN5o8tqWiKDmT6QxBZwAq9JION/W/I8FULRbqtwsQUer4MoI8/ExvHc26/YHjeRjm+HTvi1yzhm/DMANzetkooLpTkuTFIvxUgR4veE3Dfv5mgx2fGGtIPQVqAzgmrnPYj3MphcTMsfMro19LTMR/3PBKpus7lS0yxnz3fi4XRG4gQYCrIfuAkIlROLSkp5f4boCIiweSZMS0v81/46e3uStsQ586Wzq80pGJv3tU14H/A9cib28OB4Tq2p+SmZ7pxDjUfqosgGjxhFGX4wccdLBjxeHfnXCmuYds5UTJhWH0vk9yVELm0rc32ckagyFyTOCWP1XrLa/YTWzNX4YreF3DnUqxVyInIO+dohe4xFzyuiQXcOa0SirGCDq2c7rLXLfKVUt5W0FucCwcmAu3uHx4uOlJujIDBI4G2EFzhnq1MkvkCg0OZDbaFnVP+YsqrhcM+F7dXMI8Ueh6SXyoFdXc4PirUlVPhJ7YmV3mTF80znFD766cjbwUEwZh6M7AMMia0ME8ZsDReikFzccGq3OZqGjAC+iDCZXR5E8UIN07kNNEH7ZvaGHISjX5WcSVo75UQOz5Zl5uukVyDeZSo0BgDHNW7+JNIov+bqIEPneRxRu3KQeYwrZHaDDaEv4CKH6ed3qj+6HDVbF6ci02L4RhT7rjjadtzUQGIZiNALz3mvJdWynAlNsqIxRtADr9QZQ+eqjyyU4Z2dgp7LSxf4T0LYwemI1pPfSh+2WQMoZf9RVMPx1y0lOgHfxGLiHzNqiXHfrT2hXWke+k+d3BToa+Hr+vPEI6ldn1swVHVO+hUKw5zSlVL+NgJXNi397O9AU7RfmKP9gx6yt0mpOw5vNc+0DIzVqmZ6FVgbwv7e1Jj9nGJ3OED89OnkWcBSzrv7t+nf1rByxPu41Hbje5PFxHiEDMJkeYMOEDcHTqqHaqQWz1mv1Iu8Kiz7SdOpUyTlQ8SXZtuyTRNOdFzMqijJm/J0kGu2aybc+Y340v7VDYhCSadEsRUurL5eONzIh5gNo4uJdYSmX6Bs7dLJJPl8usWZaWUWqPZXdCdSeNDXQgqI3wrES9ZMe64Hw/45fFszALI72s2aBfuftzEIwKmdVn+6my91qzYgfhVX9r8lXxM3/wWdv0b4yUdZuiEnfDN4T0FkX3tE9sWWpYzpLmZhkavj7FNK1EF1+8MA9Ops5kgwmgQs5zmnkZeYzYXiFsSjB/bi3fe7z+EU6Afv41Tbn5X+cOflVb2RFJULs9PZhwWMiu7JPknIj8hWUudUYDtCa8DZDzQISRxHC06xPxmTmfTsnxOtqVEDxFNzBeaR506aSo3WR+cRqV5zy2LcYBjP2HuOE4F7RO4U3mY79LyAg0HzJpSeIaanXCVwd4QZva9XM96WI7vvG/kOwNfHRO00ZZ8BDm5jhjcWEnDs0x4U+H9i44qXQ7S8KZ6eD+lTqO2qkp/mBDyd1ohE5TAT6vpE7nN3dUtPoOis7QbUFnosWcykzaGGnAbrrftkiFUAFaiFIsMOk+hk5mnYIiS5Z8MCC4+o0eTjULbLzFN6SLV4QRY6LjW8a7GwWyEwo3wo53HGy0vomzl7RUyLWeWU/swTtZ3yGGiHTMLLWnnE0H1WoZjew1jrTmajMbdsEot1fN2SrLlI3K31mQ4EiqOHTUar751wGFj5XegEHSpoKMmeImJRnkkaQlN/bll9XSijIksbwl35FU770u8dLLuiyuU0fVfofAHifYTaLb0zMKfwWlhhSh7Nur3PzNOeVia6r2gSN5kOmZGnMEIGpk72hkSCO+ikIOdoWeWeVODl7JXuKh7O55YkFEUMdsFonHtI+CAuw3+yJM9awL+hVwMoqKPXx3qxALYQ7E/7R2DVwfwTPvb2sSUHoFHwSsV2CvpbKduDQ3SXyDw5x25W0HD7kGvO1ECZ3i0OIiV18i5HSWgt5G7qyYB9o0Gil+6EZTpVdEn/iyeuaUk/2oZvin7XlbkjuXIjUUCHg0lktUsVsWBkTZFUhaFpdyJbiEe7DdCFE37EfK7wr7sgViBUSOFlLEjoEn/GA553wVwjeLfn0VoN4pMxGorzhOeUkw5j2B0+HvZs2rFtHP2hsFTaX3CGNTqAxE/qJNbQft4c7eyzJkjEk6996vmRXwN3kG8eOrgj1lgcwo08wwrWtIPkvHnOLJ3YvFSZPpR+uN94e0QpQ9P3tSfq+LN4oi2CcnjYnF6b6PlQiuPCrUYpA1hjCvs02wTu3gpOtJ/Z9RBGn0/lQOSwZkQQ8hbLvJDZeu1iry5gYRDMkZbmON96kQW7w02xT5NwaJHV1kBsv8124XTEgTJKbIkSsWJNhHgHMoYM4cePy/7+CLKymCPbkT9kk5dboP9IR2EGhlHPm22pA+CRREjGzZ1MqJaHj1KCvkyMwG4qQEB4V13h01y8YwjMW0NduEohYFp9OmFy1lEcaL9mOdSchwSBjQPOC473qoqiqvQ8a05OvxgjrGYuBS+id11eHwIB8d7XM86A2pVaiiaQLJVjPmKphRkkdLWvIH2m33tP1fxhzU9UNaK9K6331IWk2Ljbn8zj4e+OAgHkV4xUZzvB3F6h2E3y5uXoTN/yQSDKGGSJYawTS819bzWRm/bc1XEOaC8h0dIBx8KVJcxTOcfZeOO3SJNebVfzAAKnmxbVRRZ2JeFdlEElSUUGTPGhwzu9O0n4lmxQkhceaZ7yWN+rgcBFzVbrMLaUY+cjT1E3tzuEF3Q0gAus6/xoX8N7vp7+QHDT8OgOV0RW2Pj6ZOBEsuty6iLrU/4e/jpEOTOsp/jLDjy2bX1ylsvJHpC5wISF0Bs5UBJTqmW1OkywKJ4upfQE+h0Pzy7J3mdbYSE25c5w0nHCFBfJ0riqqsE4WZ0HF5QO3Xf1C8taPKsukHNzCWZ/JkFGKlQHDz1RkhLTnBl6YpR1L4VIYggxE5vxw51l8ZTRkREP0ukSKr1jerY++R5bTIDx2FJlm0GG7BnpziauS9tvNrFPv1StFlTz7lyebBwuIvvhXAr4zMV4DAc1+E2+mnkLre6CRcBsfKNzMcs2mACoVbq61c1gyItDCmn1Ohp6OCiRVJZHmb5D0G130x2gbtO6ziPF4XZS4XTINftyv1PuMGs0BqJokCIbTO91APiOV6b1cSiMz/3Npeinofh7+XvRe+CEiV0PzhetXjNShuMRCR3Zhg6OIO4TRzwRVfX2ljXjlHBOqnQAlFIkbPqbNm22Vvh9HwT//R8EeIwGgwhx7Fpk/u5oW9gPCxKG2DdDBJ9//HHXRL2b7W9C3Gool046G50wZx+ADl1GOJEDx++ue8FhhfwaZ/hnCdAdK2bt/v3v0SYrykxwMvmUcL70Q0wf0E0wG+ibMcBELT5qwkiDkotFqTQHgYZ9QjLsLb3wlBRoXpextZVL1G9zAXQTbVfxzutIdEPcUyGFe6c6vuGIDJrTL7sH4ftSpojZ1v5tsN+Q7NTJSDID9jbuAJJtyiDAls82Nnvwt/HJdQ4or+mawLJOOpDCcObbgVVIRzzPIZ6l1rVHAcHBTeW1V+tCqNE/OrvNCK/8wqXmsEm41jTLlZV+g9QLD3OvRUTMz2sfSwjTwHsn+42MKWKkAHZtEfx1fTg+QlB3IxDbNMHnnziIBDsXvL6RSQx/BPisy3JbTQ5+9SHByBkpf/COdN8L2ahZc5vqmzfi+A/V3BXna917h0D3So+6qx9oPbj0XeJlQ6VJC8picIcjaRJGmgtEj6d5aBKNnJLuEBDzN61HF+/xXbXtPASbNBHgMV6qRZO35mC+2gIOnMIDkc74U3RXaFOw8iuJJdXYHFhFu4NMIeLRFKXtsyDMmAZSfR2vG7uWqP7cb56OrUIervLHII5Aky0xwiL49vDvhvfJjTozNerVvNMqvdlCif5NMJGqgkv18wMvWJIVbjnM09eRW54doubayebybpYRGNFLhGLhZhO7muwfHrnsf6c1/E/NCrfHsA8CSpcoCH90XdqkJYPRGa4CR7I0IYDGr1ud1KZgDXzRTZ3XZNRyYh7huu8rsEzXRh83GRSrMmcQRaFV2YMeqHk9d81ZWSxDQPhsvBg0e1jsC6I4uWvsDL3dyuCqRCVC7uH/UMmG6ms5hHs8wJL/a8gt1z5RYdugiEo28ggNaC/8J0v2L8qPnrCq34Ko1zPOXyjDoESxysVKm0v3GfAt+uk6C65ziXMB54YQT0d5fw7gea2x3xhgB0NWolqjggam1xayw+Z0U9KHaYuteystaNwkEqr+O+XExfN+Dsxfn2pEaYmvBMTiXrqsR57ByMHrdPDBZbSpQ1k8wzkJbWatWI1rEwsWaV5b2V7FV6k+q1ZG+ltfza0tO8MGybbBVJSpCrRU5l5eyeO5jpYR9dwggW7JPkR+yD8EZ7GDAu5iD35l3jMYdMnccr/YYWup2mtV5GMRUOYvtA0OjCp8pYBKOdWBhqUOSXE5Ymd44lsGdN/GBA/iRWgs34Hu4ZOjrzVe9sw3TOFDhGkwb+f4lX9IkoMSpVdl0ENfZWo1S5ySaE7YvVF0Bzc/1dTgdeMoCHheql+YDCRfbwOJeCkK+nC2vYhViX+YtqpIW5YGXVN72Z9l9dPiksLggZpSg5HJlGJNeEhp1+bqZ/sYBBAk7cB9ynwOpzldh4UlPehIM8z/2zHcgfnDK7hKU+wXddD62uAKJr7MXqGBnTP4dv9FlhqDwZ4WuJzpgocfWFE/j7FSvOB4yUB1RKwTJpLuGRCgJDmViuBIdxUTQuqWxLazWkn1Hz4DGRaeubhdVAR5VTml5o+h+9WDwGTSRitnXxlKPdtN1bpnz7gHgkvT/yXp0WZ/qJ5wIOjgvst5yqAPV0rcgm1rg3EW+on6HQ1uGTqq9aVkJCXYQpBUXylKB1OpFbZExJT0viGaGncBbc2DhDGuoAAc3IrnpvxohyZXjZcChXpUIkKpaSg6XzObp/B142uir5Jc4w12ftblX0sDGIDVYsE5rkahEz8fnSPyXvug9t2Hv33a9Wil+54KO/2nMXYjcAmV5VXIqr0mP9I4gzoSGIuKX/vrSAug4+bsSBqJkUcqWYqAMNpthsa8fy9RROpUnSghHqWPqnDr9MHmZcH+m1IEtdb4SCLDB+S0pxQHN67CP8Y7ZbNfhqEAJtvS2GTmv5C4nVO9xySmhbuMEkGbv1uP/qUOwIQiqaewmxApRx42cr2YfH44O6GqoTLXX3UV8aZSywhu5F1XBIwT/rR4X2xBkWNlq7K10JGS9fLb6v7CCPAg8SVwoYTbrcPlhZWZcE8UNR0Ah++knSRbMomEmJ1cr5RQ80v8DtFulrWPqZE233taehJqYRLh4LoBrRoPifBV3TwcflM2k4rTLElLMZniWZtCCYJTWykM9FMlrwtKge+mtBSlg+6wlSCpgf3zKEHWBjpYb6R1pyRgTaA7xbkqLg0uCjas/kxzpVFHQogQc4Z/WcBlnoGQT5ocdUNpjmJWLWdEwWnOejbeAajWFUNP875AM/egZpbD0J99FnHLz1XNcAU1ZVZHB3RWdpok5dnRFiOiNsVT9mGdiYMgmMVd8Ww+j4toGEkQZ6c8wvGl6VuzmaaXHTdgJpR/ib3i8oKzOBCSi+Te0RKsTXDiDVOfI/NmgJCFvuv8cRgTE3damcmu19i6OLFhOEx0YBKGWd2pRAQzfbFHTmfx1wUvOYoOcO0gXF6U1ucxsGxvUc2ABlpYEo91Wvrm+uOO1tLsQwagoR/dIrDX1fpJIp0xZpNuRkGlOUj9R2w5+Kmf2XTl7AdWS1MV2L+ZRxvKDvL2bSQksbGr5OuBZCJ7CFyaqUVuoTST/VY+Bv1Rz1aUx4/IqTBG0iiXtANhvNFUMB/0t+08FwxF5E1EXSrirjiUfXsif30CEmPG8pyhm5EQwxW0Pd9HL7sWSR6QAtzLGvUM4DNlgep7+7spDBkaL1B6Qc9WQ4QhcOkU+uqyfCxXn3JurRIWhZX+G+mSUhKbblazOR96sUEM0eDvPc3KvS/aIk1fZgIL3Tg6h16LRtxakZJfF9Px9e6vtOKx85vsWblhiPjD7sGQ3z0REmOnXZMooch5uauOm3XUoXxd6ebzqiFoq4mBba39a2ofJjT88A7IQDeBAl7WiQxISXQnBr1D7eb9zvCfL20KBE5lSu9iQTb1A9RZw+iYRYWKR6kSnN0k7yX24nHiMd/V9fjSqvMPxtr+g1/soVdek/Zn9p0NlwGLqyGSt1MkWZ0pRq8qhze7aL4v8X8lLOvTae5po1tK8lHjPxp0bJxXeBMzRNkpn8qiCwk46Kz/JUS7QChLjF+5QGBmAlfdEbOqnI7WGNJO3/IwbTIPHQMBDjOn0gV/Oztg8d1ia5ciAZlUGoA1NbCdxvAyi8btoze16pN5E8zxCV9Gv7OJ/bfORChq4/EDogdOF1STQKRoMa/rd3Bfwl9RaFt8Hcs87Bt+5/MN7XndIKDtH0zBjLz8+kEDYf2PCPMT2Yqc3QJt1D85BI8lqIR/T8r60YldemM8b+08NemZURk1i/TmJs55qIjApUzkCLSPpKy4nNfZSHuS0vESkon6la8RAycE6D0Fcze4XMrLtis0kFogh+aiVVMKOdLo12OSnfn72NnkZQknX0sSXW1F1/vpo7h4p6+HKigAZhrF9RC0xP6Zx3WmBuLYhiF5E5/9ph3IYcAZ5VzSh26yon2EvvaKLHrTMkHWrcMbTngwA2teVxr5FP4BTJ+Btm/0cq2yAmMuNxBmdm6IQsS/1nxGwqviIaF20OLnhu9V6+KYh+oLHK4GsKhHo/6m5nGq+K39/ljKL3aBBcgIKy5En84lKuQ0EC7d4JWOxLGdkXpqKOa3LaGDSv8OZQ8ElQOils8o49EkjHZXIR0gKRzheY9JB0PxvIUoWOMtfv4jFfvHZxCZpI4Q7Py4H2RIDhk5PpDrk1K6qmPhRKfvHcZBhxfewE6M6vubPpoTbcf/Z+hAKVtJnfs7ITPkuhE/LkwOEh5c8hdBGMi216S0j21TTOXHlCLAhqY0YFArgnzmKjJmg8e3Mq80B38zEIoOZ52e6mqBz15wfI8wUNXfsphCmVIVIXxNE8U1vjYLkv0IVZ7ipxPgAS9q9cAd+PFjkEutHHz9JKROBH4ZtvWvuBx8ovaQgKUHZomgEJGfQnJcK3iaM7b7jVWRtGb4/GPbUPHA8caQE/mWiHuCRNLN7EF6/qj6PsyZsM+J7xQScYGX7xftCHbwLCT7sQrkbfBRt52hS2wwSrzdBSAei9WYpShPx5BnPnxfcCIG3A6G1cQacMHp/b6gFganpsnN0kn9/PrLmVhAAe3Sirurd7UQTpjo47NdQyKvSQjHMSsM+/42n3p7PNt9RJS8KCNwDP1lIYij6pjR9gFFadEgOuDBKKwApBCXYJsWOGvef4V7kI6pXl7rvvgrg/jXnsS4ZadaKnCQj0g6/p+WIx0dHCkUdTSKwNzlGvit2/K2YcimxjKGVeuWZRJSAH2MXqMb5K0ZbejOITH2dJ5nwCm4X1KgNOr9CWg2slIIGGgOJqyPPfvNtxdJcA4Z2NQWso7u+2A7fVFTdzIi8Se3b/JNe4QZ62mX3ujRelSwBW++tHGw/FNNQq7MRZDiJox9Fnl1cmbi0WP8g9mQDjrhl0VmygbMUW1H4PsWWmdKPavPyhXnIvDjRQ9FiJKuq+fkUxUQEWIX8Hv00HMA3pfkh0+B9TNCCnLusL1qSepcIYuYzJkL9yV8O1iOdbSgOpwBB+HWOOewomH5lxkKBJsfTu/Gcy505rDHm1N3Wfq/PpoGC9cL0knusoov6iWR7jVTE9mXIc9pk//tHj4wGZP/PtJYgCB16oztOX4kaw6lWKETwwvqYPxHdUYMeQH/CwU9Jcor3u6Y8aS+XRlqi+Z9QIFZGcXxPHzITBZtVeYD62dQB3rNehfBjxWjaZbbBou/VJkkMYm10Bf4/bdrqx0A2w28A6ZaKzH4gZbEcROW1V/aVMSfGaqXMY2Nph+oWE5HsISUUHfPAyVbUphJmMdKjNRawBKJ1YM6e+tHRP9TawGyV75MV2e+qT6lekkVBQwow56/027L4ZjpD+caU1c4IqbpSzD3NK+wop85BRVZvjJbTW1t6GggkLbsCYh6VY2trgxYDBITFqje1CkzxdKhujnFoXkAAHOMngxAuNzf1UaHVLZAVUAVfgF6p6sihCeZlaNOL51N5zlvwYuA+bi5/dJw9mYfecpMgb0lcwiROielLZIivHdoOPc/V2pNBHEiqbGEsF7DKtUbA/bPSlsJVD/r5fkeNTH2bAN12oMz/qgr0fEmCrXvzo/kxnzIcEuKYKDe+jqZpymfLpw/vDla+wSsB4Ql74oXk8wDC91GA5/u0XiB0eCGLbNH+M85W3T8S83E6UC3TjrB8bE/uvTrW9+P6Tl6O4vFG/onGD/0rDSpZuuCIQlwB4CnlDNuf/UXrXn6tlcd4u2SvMBIIJ9lBv5MD/UsC7IF1lSp3FM+T36oVVqs2Xd6xcrSm5fdTe/MxT7n6iBBGbKImxl28KJWvF799Cmi+2JC8aQ6LZuSW7Sks6JruOD0XrWWCW9iiFzlX/e+KR3ZZxcVnhBrd77rU5INuCohinvacV57p064MXQW/o/WVt8vlZg8/yUr/mp7Deq2B+uFONHalUBwwU+PLMsn1vEJ9tCNA8yWppuow07sB7vPVm1I4z2mWTw1nWkjuzmPf9RHPhb+HChHW3QN0JgHXmwOhkkRPcOjilgivQbGc+IbQfMMTv18SRCfAMEs3BLFFWg1/lDJ0yBaO81iZFzrplSHcI6+tlLZ8ZtY+kWIy09bNfTtoTbQiopsvDBGvGpFC6wkeJ+hcRWkyXOe11+PIc5EH3LguQ5u8CGuf0aA6Im7EwYZ4sD5WjYM61c8cGAxOYYq/WF/qbnzKLpscMQESXpmNQWRRwSntpUzFWnXKXRbqh8c3L8tNZyOzChFkXt/+lGL3ExOgS5Ch9j4l7KxtHSm7+GnhvzlU0fW2aAsSJJ+v7hsE1mxyvEwo8AmfRHOY0Szn5nUPMOGDqf2GjU1JNHJh/bs7JLwhtVlq2h4cMsSaJ/x4xx0RI+VAtVAyn1asJ6onoOIn6S80LJ/fuxXUvT6B7GxkWDzuhDObbSFnYJcS6L70SgDp7toIvZeCnqTtrcd9bBcga6NplRdIYHbjZg/fcs3XvWGbUfGexvzHIz4Ve90N7cmVqSblnFatoeKeeePB85WgMXWZzBRtJNb2Jf+qCS3fcIIrE+ULqK1KozvBuldBmWkBz2cQZYfZo/baEZKtAcKsresa9PN9QsR+Tmad/f+q+ghPsveJkYWw/YTWS/IZwPa1mxAdHzJ0BLLGhO4FIMJxt5+wl1pRdZXFGudWZS4/rERFcpWB1O+KhL8bebK8stIlWXbk2FWuVFOG7XoMDfg+i1GkxdpTRWxbFSPwg7JhpHtaDgjCoW3YukvpPG8HaQPCC45pmVTrJ+dY/ViRCK7wKvNYafsaAJIB6Te8BYE7TjhROQsjsgsmXmMzzphC+hw54M4x/cTNIvTTIID70A381AnVx107l4PuSp6izOgd4M0GlSSFEzFS8xAqURzaTYGQ3eKiRqiI0pJiJahk+0Iiito/K6CeI9Qag8yh0Mr6zHbJpEqNb61A1y/z18lUnMC32VDebzdgAuC0wadYjufpDQzd1q3CJvGr4I6ui4a9wsjbSUcrbDIZ0ModSKhs7De3qvlLRB7z6Cdi8uXNqgoz6f6yNsXv3p2osQq2WFAkBjPcZLnhwIbHoPq1FcsVbSIYH3LB5NllmxUN2MsXDPky3IWyOXRSlAckm2EwizdYA72OBw21chxC7aL/R6Tv3HiO5zuMcv3407DedlPuBTT13WtlUWV0TFLqIRpWePoL3TiaP1koUwGtYnCa5R64rz2v6AUnvC+FO1NgPRIoBxDscbYJn9fNeePMNz1j3vGWiUU0MjArI0fa5k3SBjuiPXlJPtc3LSO4s3NaOzF416Xb3fsZyBeMecsFwIaspAtoP84G0+erqCbaRdhn26mpOtUZO/dtY/UWx6+/NwaAdCLR5hjnlyZJbWlSwdDOk8Yxhcm+LsTHAEspULrJKisByAGgqoHbKz5LMRnyU7XLaW5lhOV2s8aIksVdVkWnk6isZpgKiE8vRHyyILQQ+ID/juMQiEHcK0pagGtBEnULuN+ZfpNQmPfw9LfkjoBeaSJZtMM6E4lFa/D3Mwbd5B3kuvMYOYt+vB6D3j+sw4w1ilYU84YnhJ3YK1s9/rhZOEiogjVRCZbuvjUQqxRYqquGDamSquekSdp7zOT85VoGBX1vjnDFAuRVBDBISh6O5fjf9IjCdRVLSCOHn4rP6IQJFfPFRSEV1JIIPplpPjTXraTCFfAAyrMCkot5CIjPu2ol2EsQlp0irNnl52Yczw4ofocLn3GzAfbLWCprnp2qqSb0Pdz6AX6VjdYx7IYfuCnpOJQNJXzaGyTUYIrBU04RPFyTB502cj4Rj6jfsHa8gSlEoiswSkYmDv3TwC07roHGwWUvf7u8YgRAfLLEWRPOir9/CBF4ZkZFSkj82ehdnwRzO2uz7cFbPHeBC+UILqzlnk8DDkL3nS0u9/xaoOuCamnUXKW7vW91IOvHsQBp/oPXbi3WnrbGxWWJAdfPY7ylIRfOU3hLQUeYpQPmlFCGxVJvOKx3lstHTvYzPhdOT0/L4v21+9rF1Q/g3PFc/ROHziYNdiby8YGLO02yC34O4+uhZzUUOwzVDiYbf76EMV/6pvMUhoJWbLYC790sZDcpxLRAywAH1eFaI9iQW8K5O1R7IXY2zotxWuLHmMGWwmLuuLuZiuGmiIiezZXzFbPbkatH6xxRSpjJDH/z8yPx8MGMW51YF1ZECpaJoRQDTuZHy4/PIi5MiVUcDWvJa9m4EVB/1xUdUqPce5UC5tIcoRz4xT3KaxTCLBpODYJkOK/rRJdeg2ljQHcY1gS3fZNmcmurng8eX180gTse3UPczzhdSkSdw4GgAgDL28pKDQOKEZQvgQKjAYrdCu8AnOAdizvTrmGYPTE36oGor5FPVAgvJmgwuYKvjiEV91D/vse1iDGy5qIdtnLhSBgmvOt0mzSCgp82KlBETHOhfRBAAmSI+g47S65j0ZoU7SrUPaxAwzh2HQq86OQSa0PnPgDG9yGODbtRU2UyRmUlbqIXZuLgZ/JrbbFfVTJyu5wDqbGrjLxPoewJ9hRTTWTny5okrGZIhVFlpQYiDNtw1Y+O426lC/vWjxoBZpt7F1iQRS/HpGqwrnaVo1qvrJXDVVka4rfEhx22/eo0HWoi0JiIXlgNZZPCOo6pXXY9fLXyl2G4ZbtZyhrHVcWQB3K6b2XN4vUqiXwy9KilmVryPAYbM9Fxa7hYwJun9b+AXw48Gpb5vwSVCSzcc4nCOe/RJFpHldkoayyUPJV3WHEPZTMxnDQ9Y9Jrj+hW5ZiPlQw2grWxispPmUfLTrCZZ44tZulhXuDz+PzESXzvFvGoMgb2Qh37VkHMIsJgMRc7cNKcjUOpdQL8nWF9LGsHtjPg8VW1zr4SyaPXvmtUeTXjeOnUMLcibHmJtQ1BYZ5mZMuXbM689gF8xDUs8mbnrsZ931Bwd7gGM8NNP1BkWFAA+lFoSFuQjzVo75BcX1laD/nqd6K5bS4/s7WnyaotV7u+8wudLdfv9Y4Hq8pZX/bE3P7uleAAe+pLDSx84yJ+cC2BbqVgypf8H8xGKnfA16frYXrbHv+QrAvAcqZzuo79//bqTxHUNQ4E21gPoWKOlxEDDjsy63cHSlCEU4u3dR0DQmM7R8NhsDR8XhOR/8EEIwdkEnfazZYqmSQ707xrB5Nv9kKwEJ++ai9FSX0hkQTvRbhdJ7hhFGacwoy4iZR9SYveIe3KvjYuYVcfAUqNBRv0g/7ZYvqS59p4Ngl6+wW6MPOK1JqHNtVnu3C15+Sa69E+4TqTUS89Q/uUdfOsw4uf0YwNnWNqbnpq2mcEc74uM29RS98XKbdnaep76GazAqJdYVUts7IWYxF058OB1u3qOcU6IXgH6r1Z1SEGFJcVgJXvpW9tS2wtThN+/Bb+p1HLXribf5LhRzsqRseulQmMYDaMrYww7mX0FDuXUI+uvZqbbn1ezGAyQKHVnnekktp2Ep7N1UlIN5gCcfknwgOpMIaKt4tL1giDDCnywVvxMCYrTA2mdCmsHfXHMO/TIiFIL0zlVTzAD7+GygCw1DVTP5Hv1C+YvlJDT1R2mOV79JOgJGcx9DynD8/pIxv/1Q77L1DNSbYmte6SHawsiwsooDGgoYvNCyFkfHa9RcOB7/ZzK+n19hngYVdsbF9fON2WBYHbrpxY8ufuggrtlNI93jbDlleK5mt/shvh3LlYuK+1PiDgpN4RODiXVMpmVHjq8cz3ofzDqJHazmbSVdQnIj3fQGRr6L/XLexT9bY59ZaqrEZPKXvfUsjHJTDsVOJpfYxHp2v97tnsQPpiA70v/Y3rK7FmuE0waQc/ugcXCzVGscntOd1lVLXKeB7JQMd8VZhgV4MKCFompJjW9ffMilqn8OIR6QUqEVSGNCc2n8B6L/CtQmP8eHZ8U+0aiEPrabJA/7w+3tKHdHZrGCgNhgAt6AAlzEUHYH8j4CE03xudUIAaz7htA1g3+U2KlsTL9F93A9KDKrZrSCZJRMbE4nv+70oYVQC6zHywILPZTH9aL79U8v1yZKGIi9GT+SGVrEBtYf9WjrouotLEtvXp2sbnIuTK3jH3p7lEqcolb5rnL76bi88TMzkRclrnyyB4neK1Y7hhJ9RPfceMu/DiW7igmDHO7gFR64idbpJcjd5TIdTy0AiajehpYbQs2Ctde5z+rrGeUc2EyCIKo+eDPuXRuzPfOkYQuSenUH41KPiGs5GlSJsDTzyTEr0jlJWIKEwYM4st0/dyOn7zQdu7yp8crDON9UPCCad/AdLWBVQVHpPfTqi7XHJ3SJHpi3wYnNusLrd6p42Ei0r6GQavLAFzEpFS+vJlvbCt8UqwyHqkwr6Zmwvgoypn6zFd+D/pDtPO8FSdtkUW5vK8r6+3kmOAo2AQerp8Rez40KjYZrQ3iROmEOER1ZtTXvtrcKZSWqzV0JgCaNfI1yxQb4Nmc0QrjqMThAgkWmApNpdAaxeatMwc07w15BmMcTyOQQmsu3XkfzqjZeuJMrrsruk7/mcdD3MrHMr4x4bYUNNZnuPrZYgED5rVJHrUhnR2gd1Q84Lfxsl4KeA/eoU7JB3T2uqfoNEFi1Ii4lAIDm1hMb8bDCIcFh9nEb2YLh4q2XILHEdZ+ZxY+kDI2KJ93byLCX7ijr8FzLyuEtOldvaR65aCFJklLJGSayW8mT9Eu+coKNLBo+EtvYkmuPX38nKoZ/zIVHsmJmL5MYTp6KrJxQWkKuFmBxDTTRt9eDGLzuJboNpeHP60/qEyvDzTw+Jv9Lc9U/BdddnrsPlBoTzukpL9faD0M0bx8tsxAe7LwymR8cYpzDPcYcufQ0qU/og783+YYJr3GwbDwYcVjJDBhV13Ci0ilYoR77BuItvYAu95bLHSkynpC2vhpTGK0CoHoUoJ7jmTSiCFVn87ccWQJzIurha5nTyYAowB6AFaMGnzgXQgWwfuEvxNweY8caVMvrrGoaymdIflBPzOz7fQ7JXAEWAtw21faCxgiWeCe7MaeDTilCLyJwvkZ7RWIhcNWAIRNSYkJBcebNXMiYJxFcGzmtRTTE/PN183MFt53b+w7WJLBFy0wVhEndvBvY/TOqMlRV9MvTaVK3nSruBuBWtH7OyY9gtbGknFLz/h9Kb1e6fCP+UKec4uOU7lo6ZAWwFlwd4LhT0U1NZ1YL8QWkQs+6odxRlGpy0rxTHismGYeOXI9I01WU3BT0BQPCGcPGIzivCi214NwBBIPqhGxq29+wPPx+QLHROQlvS3WaMH9YXzGMOTmcENThVVuWTZXE1hF02+7aTH3KwjLHtlU8ePOP/ZGL5vOYZiYY4SZNQETu8mxCoeNNdpwdA3GlaVZ64jbe35iRpwIk/wWYfoESSUM0qV1WLno1GEwwSUUnu2Y/hJJYPgDwrRNQ6AN/K72qCucfPgL6yM9vZ333wJ2CuqeCiy+IGIAPFHMMARoKQQzDk3ufz3NELAeWAvxlxsE1MrSl2IYi8SdYeVChXPUinThxlWxxhCQkFaCoNVVjtctzLm8BjmGPFzwNpaGeWD083hHP6/d/tU+oUUia1EEa/Fug5vBMHlEefK7d8KlvHQd7rca0A4yKL8euZ0fyoZEI9HBvpMURCOs40Ue0p4Puawq8hHLboSmAd9Zk8QZhZ//XfBKfBDfsWTDQl9ccaP515kgOPEGUiT3K7nR2QKm0TA3tHx9VCYdVpxzMKW5Q6vdSg1/L7HzXqOtxB9CIEmhIlF5YbUpdKN6HF6Ud1Wb3H8QF9Hv3VCaGcY+VmOt2ZnS+VuzsBX4BE9fy9zyHKJtbDT7gZeCkgXHt9Kny2ZBjBV7ESyrjB4IbQToE3RKZVst+NX4Ozzcb6owiMHTrqFFTjodX7NVEdZ+Y/plUtt0C0irptIwwheZ5lpmR6XL/Hie8BhLyO7RXfo2vKKNhZs5gjQ96pGTDNRjIqEZfcdM7GIqWZXV6eHaZJ2X2J5IaBF6Rlo6T4oY3lehQNNrPyrzQaIbUkywRDfzke1zERoTzB1N0NsWk0ZcIkBIDYlV6FkvJ0R65IW+PazKv6sODKe1ltqRjX8BB9U1J0yUloO6qzML/5XEBx/Z8bkCgzDGIeiqtYahfAg0+VRBaPzfceGr3P2PttOuQQR918oGXb+O13uZJDmYMAXNcuFtb5lqUxbTaWa7vRrrIa0i67IqEPAwNBfG2WT4zdffCsphSxDcFNElrEYGWSFKwaF5ACP1PEz1WgpjueIMEVHvqXEhWzlaVYqhUbEmNjqkJD0nWTIKNWIwVppO6jVdnavZTtf0WQcB5TZNRj4nY9iF+Vj8Zs3SKADwpIcZfQqC43e0n4Cvh8iXsGW/76zbDl0P1986MRqU3gYrJrgMYfvJdQi3mZJnHvfKf93FMQ8AWCrISElLncQasIZ2VF+EIF5qKgCP74UWBg38ug0vOvINlpIBkattzI8OkEHbr8ar0Ecw+1+KtueCDKh5hf39EnwFZ8b1PsG7Y+wxWOWXxAv+dHyDzd/JEGQZF2A8Etrz2YYu8rJf4d4omu0k7SkeDsZwhwOlvVZ/Mu0DaoQ7pDwkT4mo+GxwjCXw4U2OLfdW7xOd8+1RbtfFBO9j2tOSLmbN+1hkPD/rLPrG+MuhsWoZuPIxEoRNyrCvAXShrWtfduOdst0klBDqx/medMWcuD0tDtX/FUPadwPpzGFX7xjJxjzWGT2DYxu+oAk+CWiULowz1XN/15Dg2wguNFUqpxau917fah+KEN/4Y2R4y7/xcTpfwNpIE3BKCPyCLV6gxot2jJy6/uUfl6BkeCtaOIWrWE5E3o55WYoBMGgqUHAzdfYC1BZmS6Gbf8m6tCxydHRjpx0IlrIvbaNVPgT2sBi0+myPOefzEdMXYpDQ4PGcpz8XcU2Zd6Iv+AATaTMXS8OIp069Z0bhOv4O711mWAyOI9M0ZMNC3ACAJwFdxH2/54FonyMlQcBBBWCsacggROjlkG5UaAEn/5KeIVjw18DV8mw3ke/vp5WXZU56KyRk9Sse5sE0d2nvVwcS/N0bkFPwkAOjSB+ndi6f/XyO81o4UJ4vvyYpAINzIiE7ePPc+9/rdswXMcG6MYsrDDLwgeIG9QYY+n6vWqPdgbaU7DpgutKiA9ju3IY/5Hat1c9zkXQNhuXIcYowURduJpiaQ8nP66QCnCAlOMKBcuVm48T85zIoV/O+Mn1m7YzJ0Esp64d9JwtIeNxDwZrv0x9O7gnue0eDTB+kscOHWKn9Iy8P6aevyEVqQNV7xG4qWG03ZBwtbHe8rJOPk1zGeKMaO1NsDAqyyUqOiebiLjaTCaw8TnhjrCoGj3hmddRu/qN3Hm5oq7iaE610fs8Ykjk9/E8bcAR4jFA3TaiYUjkKmVB2ef0Lhv0rOaho1+/CIVE0bho8pHJlhqa+2Gm0fHJJQ50jpfPCjbF+YNqGGkg5OaET4tkD4FR7smv7Gpz2zXx62Sr9N+Q8DWIwxkNZDZjlTlZ4CwiCTfGXjqKAmiDGfWSQD/tpjEyCX21fIxD7BFHIaTRbcxn2RWBXIZ6ZSYDZkX4it2sGGSf6BBQ9CWzMVJY+al6/pfP44obBVlSDQmiEPnLDAOl9UYj8ou0ERZ4JykNRR1pixLyK3lMbM6M2K8BzgBnPHIOMaSU8xt3MOWduLqFpOU0giUgedRs4kDpD9/EU7UUAtOrHCD/e/s4c8pxjUo1WNEb5csGAQDbtyTGmCuiJNT93/VPeSicIsmtvXacq0zlBGdr0CPkBAAD//5VYk3s=" + +// Set accessor to a real function. +func init() { + compressedBytePointsFn = func() string { + return compressedBytePoints + } +} diff --git a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/curve.go b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/curve.go new file mode 100644 index 00000000000..6d6d669f198 --- /dev/null +++ b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/curve.go @@ -0,0 +1,1310 @@ +// Copyright (c) 2015-2024 The Decred developers +// Copyright 2013-2014 The btcsuite developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package secp256k1 + +import ( + "encoding/hex" + "math/bits" +) + +// References: +// [SECG]: Recommended Elliptic Curve Domain Parameters +// https://www.secg.org/sec2-v2.pdf +// +// [GECC]: Guide to Elliptic Curve Cryptography (Hankerson, Menezes, Vanstone) +// +// [BRID]: On Binary Representations of Integers with Digits -1, 0, 1 +// (Prodinger, Helmut) +// +// [STWS]: Secure-TWS: Authenticating Node to Multi-user Communication in +// Shared Sensor Networks (Oliveira, Leonardo B. et al) + +// All group operations are performed using Jacobian coordinates. For a given +// (x, y) position on the curve, the Jacobian coordinates are (x1, y1, z1) +// where x = x1/z1^2 and y = y1/z1^3. + +// hexToFieldVal converts the passed hex string into a FieldVal and will panic +// if there is an error. This is only provided for the hard-coded constants so +// errors in the source code can be detected. It will only (and must only) be +// called with hard-coded values. +func hexToFieldVal(s string) *FieldVal { + b, err := hex.DecodeString(s) + if err != nil { + panic("invalid hex in source file: " + s) + } + var f FieldVal + if overflow := f.SetByteSlice(b); overflow { + panic("hex in source file overflows mod P: " + s) + } + return &f +} + +// hexToModNScalar converts the passed hex string into a ModNScalar and will +// panic if there is an error. This is only provided for the hard-coded +// constants so errors in the source code can be detected. It will only (and +// must only) be called with hard-coded values. +func hexToModNScalar(s string) *ModNScalar { + var isNegative bool + if len(s) > 0 && s[0] == '-' { + isNegative = true + s = s[1:] + } + if len(s)%2 != 0 { + s = "0" + s + } + b, err := hex.DecodeString(s) + if err != nil { + panic("invalid hex in source file: " + s) + } + var scalar ModNScalar + if overflow := scalar.SetByteSlice(b); overflow { + panic("hex in source file overflows mod N scalar: " + s) + } + if isNegative { + scalar.Negate() + } + return &scalar +} + +var ( + // The following constants are used to accelerate scalar point + // multiplication through the use of the endomorphism: + // + // φ(Q) ⟼ λ*Q = (β*Q.x mod p, Q.y) + // + // See the code in the deriveEndomorphismParams function in genprecomps.go + // for details on their derivation. + // + // Additionally, see the scalar multiplication function in this file for + // details on how they are used. + endoNegLambda = hexToModNScalar("-5363ad4cc05c30e0a5261c028812645a122e22ea20816678df02967c1b23bd72") + endoBeta = hexToFieldVal("7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee") + endoNegB1 = hexToModNScalar("e4437ed6010e88286f547fa90abfe4c3") + endoNegB2 = hexToModNScalar("-3086d221a7d46bcde86c90e49284eb15") + endoZ1 = hexToModNScalar("3086d221a7d46bcde86c90e49284eb153daa8a1471e8ca7f") + endoZ2 = hexToModNScalar("e4437ed6010e88286f547fa90abfe4c4221208ac9df506c6") + + // Alternatively, the following parameters are valid as well, however, + // benchmarks show them to be about 2% slower in practice. + // endoNegLambda = hexToModNScalar("-ac9c52b33fa3cf1f5ad9e3fd77ed9ba4a880b9fc8ec739c2e0cfc810b51283ce") + // endoBeta = hexToFieldVal("851695d49a83f8ef919bb86153cbcb16630fb68aed0a766a3ec693d68e6afa40") + // endoNegB1 = hexToModNScalar("3086d221a7d46bcde86c90e49284eb15") + // endoNegB2 = hexToModNScalar("-114ca50f7a8e2f3f657c1108d9d44cfd8") + // endoZ1 = hexToModNScalar("114ca50f7a8e2f3f657c1108d9d44cfd95fbc92c10fddd145") + // endoZ2 = hexToModNScalar("3086d221a7d46bcde86c90e49284eb153daa8a1471e8ca7f") +) + +// JacobianPoint is an element of the group formed by the secp256k1 curve in +// Jacobian projective coordinates and thus represents a point on the curve. +type JacobianPoint struct { + // The X coordinate in Jacobian projective coordinates. The affine point is + // X/z^2. + X FieldVal + + // The Y coordinate in Jacobian projective coordinates. The affine point is + // Y/z^3. + Y FieldVal + + // The Z coordinate in Jacobian projective coordinates. + Z FieldVal +} + +// MakeJacobianPoint returns a Jacobian point with the provided X, Y, and Z +// coordinates. +func MakeJacobianPoint(x, y, z *FieldVal) JacobianPoint { + var p JacobianPoint + p.X.Set(x) + p.Y.Set(y) + p.Z.Set(z) + return p +} + +// Set sets the Jacobian point to the provided point. +func (p *JacobianPoint) Set(other *JacobianPoint) { + p.X.Set(&other.X) + p.Y.Set(&other.Y) + p.Z.Set(&other.Z) +} + +// ToAffine reduces the Z value of the existing point to 1 effectively +// making it an affine coordinate in constant time. The point will be +// normalized. +func (p *JacobianPoint) ToAffine() { + // Inversions are expensive and both point addition and point doubling + // are faster when working with points that have a z value of one. So, + // if the point needs to be converted to affine, go ahead and normalize + // the point itself at the same time as the calculation is the same. + var zInv, tempZ FieldVal + zInv.Set(&p.Z).Inverse() // zInv = Z^-1 + tempZ.SquareVal(&zInv) // tempZ = Z^-2 + p.X.Mul(&tempZ) // X = X/Z^2 (mag: 1) + p.Y.Mul(tempZ.Mul(&zInv)) // Y = Y/Z^3 (mag: 1) + p.Z.SetInt(1) // Z = 1 (mag: 1) + + // Normalize the x and y values. + p.X.Normalize() + p.Y.Normalize() +} + +// EquivalentNonConst returns whether or not two Jacobian points represent the +// same affine point in *non-constant* time. +func (p *JacobianPoint) EquivalentNonConst(other *JacobianPoint) bool { + // Since the point at infinity is the identity element for the group, note + // that P = P + ∞ trivially implies that P - P = ∞. + // + // Use that fact to determine if the points represent the same affine point. + var result JacobianPoint + result.Set(p) + result.Y.Normalize().Negate(1).Normalize() + AddNonConst(&result, other, &result) + return (result.X.IsZero() && result.Y.IsZero()) || result.Z.IsZero() +} + +// addZ1AndZ2EqualsOne adds two Jacobian points that are already known to have +// z values of 1 and stores the result in the provided result param. That is to +// say result = p1 + p2. It performs faster addition than the generic add +// routine since less arithmetic is needed due to the ability to avoid the z +// value multiplications. +// +// NOTE: The points must be normalized for this function to return the correct +// result. The resulting point will be normalized. +func addZ1AndZ2EqualsOne(p1, p2, result *JacobianPoint) { + // To compute the point addition efficiently, this implementation splits + // the equation into intermediate elements which are used to minimize + // the number of field multiplications using the method shown at: + // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-mmadd-2007-bl + // + // In particular it performs the calculations using the following: + // H = X2-X1, HH = H^2, I = 4*HH, J = H*I, r = 2*(Y2-Y1), V = X1*I + // X3 = r^2-J-2*V, Y3 = r*(V-X3)-2*Y1*J, Z3 = 2*H + // + // This results in a cost of 4 field multiplications, 2 field squarings, + // 6 field additions, and 5 integer multiplications. + x1, y1 := &p1.X, &p1.Y + x2, y2 := &p2.X, &p2.Y + x3, y3, z3 := &result.X, &result.Y, &result.Z + + // When the x coordinates are the same for two points on the curve, the + // y coordinates either must be the same, in which case it is point + // doubling, or they are opposite and the result is the point at + // infinity per the group law for elliptic curve cryptography. + if x1.Equals(x2) { + if y1.Equals(y2) { + // Since x1 == x2 and y1 == y2, point doubling must be + // done, otherwise the addition would end up dividing + // by zero. + DoubleNonConst(p1, result) + return + } + + // Since x1 == x2 and y1 == -y2, the sum is the point at + // infinity per the group law. + x3.SetInt(0) + y3.SetInt(0) + z3.SetInt(0) + return + } + + // Calculate X3, Y3, and Z3 according to the intermediate elements + // breakdown above. + var h, i, j, r, v FieldVal + var negJ, neg2V, negX3 FieldVal + h.Set(x1).Negate(1).Add(x2) // H = X2-X1 (mag: 3) + i.SquareVal(&h).MulInt(4) // I = 4*H^2 (mag: 4) + j.Mul2(&h, &i) // J = H*I (mag: 1) + r.Set(y1).Negate(1).Add(y2).MulInt(2) // r = 2*(Y2-Y1) (mag: 6) + v.Mul2(x1, &i) // V = X1*I (mag: 1) + negJ.Set(&j).Negate(1) // negJ = -J (mag: 2) + neg2V.Set(&v).MulInt(2).Negate(2) // neg2V = -(2*V) (mag: 3) + x3.Set(&r).Square().Add(&negJ).Add(&neg2V) // X3 = r^2-J-2*V (mag: 6) + negX3.Set(x3).Negate(6) // negX3 = -X3 (mag: 7) + j.Mul(y1).MulInt(2).Negate(2) // J = -(2*Y1*J) (mag: 3) + y3.Set(&v).Add(&negX3).Mul(&r).Add(&j) // Y3 = r*(V-X3)-2*Y1*J (mag: 4) + z3.Set(&h).MulInt(2) // Z3 = 2*H (mag: 6) + + // Normalize the resulting field values as needed. + x3.Normalize() + y3.Normalize() + z3.Normalize() +} + +// addZ1EqualsZ2 adds two Jacobian points that are already known to have the +// same z value and stores the result in the provided result param. That is to +// say result = p1 + p2. It performs faster addition than the generic add +// routine since less arithmetic is needed due to the known equivalence. +// +// NOTE: The points must be normalized for this function to return the correct +// result. The resulting point will be normalized. +func addZ1EqualsZ2(p1, p2, result *JacobianPoint) { + // To compute the point addition efficiently, this implementation splits + // the equation into intermediate elements which are used to minimize + // the number of field multiplications using a slightly modified version + // of the method shown at: + // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-zadd-2007-m + // + // In particular it performs the calculations using the following: + // A = X2-X1, B = A^2, C=Y2-Y1, D = C^2, E = X1*B, F = X2*B + // X3 = D-E-F, Y3 = C*(E-X3)-Y1*(F-E), Z3 = Z1*A + // + // This results in a cost of 5 field multiplications, 2 field squarings, + // 9 field additions, and 0 integer multiplications. + x1, y1, z1 := &p1.X, &p1.Y, &p1.Z + x2, y2 := &p2.X, &p2.Y + x3, y3, z3 := &result.X, &result.Y, &result.Z + + // When the x coordinates are the same for two points on the curve, the + // y coordinates either must be the same, in which case it is point + // doubling, or they are opposite and the result is the point at + // infinity per the group law for elliptic curve cryptography. + if x1.Equals(x2) { + if y1.Equals(y2) { + // Since x1 == x2 and y1 == y2, point doubling must be + // done, otherwise the addition would end up dividing + // by zero. + DoubleNonConst(p1, result) + return + } + + // Since x1 == x2 and y1 == -y2, the sum is the point at + // infinity per the group law. + x3.SetInt(0) + y3.SetInt(0) + z3.SetInt(0) + return + } + + // Calculate X3, Y3, and Z3 according to the intermediate elements + // breakdown above. + var a, b, c, d, e, f FieldVal + var negX1, negY1, negE, negX3 FieldVal + negX1.Set(x1).Negate(1) // negX1 = -X1 (mag: 2) + negY1.Set(y1).Negate(1) // negY1 = -Y1 (mag: 2) + a.Set(&negX1).Add(x2) // A = X2-X1 (mag: 3) + b.SquareVal(&a) // B = A^2 (mag: 1) + c.Set(&negY1).Add(y2) // C = Y2-Y1 (mag: 3) + d.SquareVal(&c) // D = C^2 (mag: 1) + e.Mul2(x1, &b) // E = X1*B (mag: 1) + negE.Set(&e).Negate(1) // negE = -E (mag: 2) + f.Mul2(x2, &b) // F = X2*B (mag: 1) + x3.Add2(&e, &f).Negate(2).Add(&d) // X3 = D-E-F (mag: 4) + negX3.Set(x3).Negate(4) // negX3 = -X3 (mag: 5) + y3.Set(y1).Mul(f.Add(&negE)).Negate(1) // Y3 = -(Y1*(F-E)) (mag: 2) + y3.Add(e.Add(&negX3).Mul(&c)) // Y3 = C*(E-X3)+Y3 (mag: 3) + z3.Mul2(z1, &a) // Z3 = Z1*A (mag: 1) + + // Normalize the resulting field values as needed. + x3.Normalize() + y3.Normalize() + z3.Normalize() +} + +// addZ2EqualsOne adds two Jacobian points when the second point is already +// known to have a z value of 1 (and the z value for the first point is not 1) +// and stores the result in the provided result param. That is to say result = +// p1 + p2. It performs faster addition than the generic add routine since +// less arithmetic is needed due to the ability to avoid multiplications by the +// second point's z value. +// +// NOTE: The points must be normalized for this function to return the correct +// result. The resulting point will be normalized. +func addZ2EqualsOne(p1, p2, result *JacobianPoint) { + // To compute the point addition efficiently, this implementation splits + // the equation into intermediate elements which are used to minimize + // the number of field multiplications using the method shown at: + // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-madd-2007-bl + // + // In particular it performs the calculations using the following: + // Z1Z1 = Z1^2, U2 = X2*Z1Z1, S2 = Y2*Z1*Z1Z1, H = U2-X1, HH = H^2, + // I = 4*HH, J = H*I, r = 2*(S2-Y1), V = X1*I + // X3 = r^2-J-2*V, Y3 = r*(V-X3)-2*Y1*J, Z3 = (Z1+H)^2-Z1Z1-HH + // + // This results in a cost of 7 field multiplications, 4 field squarings, + // 9 field additions, and 4 integer multiplications. + x1, y1, z1 := &p1.X, &p1.Y, &p1.Z + x2, y2 := &p2.X, &p2.Y + x3, y3, z3 := &result.X, &result.Y, &result.Z + + // When the x coordinates are the same for two points on the curve, the + // y coordinates either must be the same, in which case it is point + // doubling, or they are opposite and the result is the point at + // infinity per the group law for elliptic curve cryptography. Since + // any number of Jacobian coordinates can represent the same affine + // point, the x and y values need to be converted to like terms. Due to + // the assumption made for this function that the second point has a z + // value of 1 (z2=1), the first point is already "converted". + var z1z1, u2, s2 FieldVal + z1z1.SquareVal(z1) // Z1Z1 = Z1^2 (mag: 1) + u2.Set(x2).Mul(&z1z1).Normalize() // U2 = X2*Z1Z1 (mag: 1) + s2.Set(y2).Mul(&z1z1).Mul(z1).Normalize() // S2 = Y2*Z1*Z1Z1 (mag: 1) + if x1.Equals(&u2) { + if y1.Equals(&s2) { + // Since x1 == x2 and y1 == y2, point doubling must be + // done, otherwise the addition would end up dividing + // by zero. + DoubleNonConst(p1, result) + return + } + + // Since x1 == x2 and y1 == -y2, the sum is the point at + // infinity per the group law. + x3.SetInt(0) + y3.SetInt(0) + z3.SetInt(0) + return + } + + // Calculate X3, Y3, and Z3 according to the intermediate elements + // breakdown above. + var h, hh, i, j, r, rr, v FieldVal + var negX1, negY1, negX3 FieldVal + negX1.Set(x1).Negate(1) // negX1 = -X1 (mag: 2) + h.Add2(&u2, &negX1) // H = U2-X1 (mag: 3) + hh.SquareVal(&h) // HH = H^2 (mag: 1) + i.Set(&hh).MulInt(4) // I = 4 * HH (mag: 4) + j.Mul2(&h, &i) // J = H*I (mag: 1) + negY1.Set(y1).Negate(1) // negY1 = -Y1 (mag: 2) + r.Set(&s2).Add(&negY1).MulInt(2) // r = 2*(S2-Y1) (mag: 6) + rr.SquareVal(&r) // rr = r^2 (mag: 1) + v.Mul2(x1, &i) // V = X1*I (mag: 1) + x3.Set(&v).MulInt(2).Add(&j).Negate(3) // X3 = -(J+2*V) (mag: 4) + x3.Add(&rr) // X3 = r^2+X3 (mag: 5) + negX3.Set(x3).Negate(5) // negX3 = -X3 (mag: 6) + y3.Set(y1).Mul(&j).MulInt(2).Negate(2) // Y3 = -(2*Y1*J) (mag: 3) + y3.Add(v.Add(&negX3).Mul(&r)) // Y3 = r*(V-X3)+Y3 (mag: 4) + z3.Add2(z1, &h).Square() // Z3 = (Z1+H)^2 (mag: 1) + z3.Add(z1z1.Add(&hh).Negate(2)) // Z3 = Z3-(Z1Z1+HH) (mag: 4) + + // Normalize the resulting field values as needed. + x3.Normalize() + y3.Normalize() + z3.Normalize() +} + +// addGeneric adds two Jacobian points without any assumptions about the z +// values of the two points and stores the result in the provided result param. +// That is to say result = p1 + p2. It is the slowest of the add routines due +// to requiring the most arithmetic. +// +// NOTE: The points must be normalized for this function to return the correct +// result. The resulting point will be normalized. +func addGeneric(p1, p2, result *JacobianPoint) { + // To compute the point addition efficiently, this implementation splits + // the equation into intermediate elements which are used to minimize + // the number of field multiplications using the method shown at: + // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-add-2007-bl + // + // In particular it performs the calculations using the following: + // Z1Z1 = Z1^2, Z2Z2 = Z2^2, U1 = X1*Z2Z2, U2 = X2*Z1Z1, S1 = Y1*Z2*Z2Z2 + // S2 = Y2*Z1*Z1Z1, H = U2-U1, I = (2*H)^2, J = H*I, r = 2*(S2-S1) + // V = U1*I + // X3 = r^2-J-2*V, Y3 = r*(V-X3)-2*S1*J, Z3 = ((Z1+Z2)^2-Z1Z1-Z2Z2)*H + // + // This results in a cost of 11 field multiplications, 5 field squarings, + // 9 field additions, and 4 integer multiplications. + x1, y1, z1 := &p1.X, &p1.Y, &p1.Z + x2, y2, z2 := &p2.X, &p2.Y, &p2.Z + x3, y3, z3 := &result.X, &result.Y, &result.Z + + // When the x coordinates are the same for two points on the curve, the + // y coordinates either must be the same, in which case it is point + // doubling, or they are opposite and the result is the point at + // infinity. Since any number of Jacobian coordinates can represent the + // same affine point, the x and y values need to be converted to like + // terms. + var z1z1, z2z2, u1, u2, s1, s2 FieldVal + z1z1.SquareVal(z1) // Z1Z1 = Z1^2 (mag: 1) + z2z2.SquareVal(z2) // Z2Z2 = Z2^2 (mag: 1) + u1.Set(x1).Mul(&z2z2).Normalize() // U1 = X1*Z2Z2 (mag: 1) + u2.Set(x2).Mul(&z1z1).Normalize() // U2 = X2*Z1Z1 (mag: 1) + s1.Set(y1).Mul(&z2z2).Mul(z2).Normalize() // S1 = Y1*Z2*Z2Z2 (mag: 1) + s2.Set(y2).Mul(&z1z1).Mul(z1).Normalize() // S2 = Y2*Z1*Z1Z1 (mag: 1) + if u1.Equals(&u2) { + if s1.Equals(&s2) { + // Since x1 == x2 and y1 == y2, point doubling must be + // done, otherwise the addition would end up dividing + // by zero. + DoubleNonConst(p1, result) + return + } + + // Since x1 == x2 and y1 == -y2, the sum is the point at + // infinity per the group law. + x3.SetInt(0) + y3.SetInt(0) + z3.SetInt(0) + return + } + + // Calculate X3, Y3, and Z3 according to the intermediate elements + // breakdown above. + var h, i, j, r, rr, v FieldVal + var negU1, negS1, negX3 FieldVal + negU1.Set(&u1).Negate(1) // negU1 = -U1 (mag: 2) + h.Add2(&u2, &negU1) // H = U2-U1 (mag: 3) + i.Set(&h).MulInt(2).Square() // I = (2*H)^2 (mag: 1) + j.Mul2(&h, &i) // J = H*I (mag: 1) + negS1.Set(&s1).Negate(1) // negS1 = -S1 (mag: 2) + r.Set(&s2).Add(&negS1).MulInt(2) // r = 2*(S2-S1) (mag: 6) + rr.SquareVal(&r) // rr = r^2 (mag: 1) + v.Mul2(&u1, &i) // V = U1*I (mag: 1) + x3.Set(&v).MulInt(2).Add(&j).Negate(3) // X3 = -(J+2*V) (mag: 4) + x3.Add(&rr) // X3 = r^2+X3 (mag: 5) + negX3.Set(x3).Negate(5) // negX3 = -X3 (mag: 6) + y3.Mul2(&s1, &j).MulInt(2).Negate(2) // Y3 = -(2*S1*J) (mag: 3) + y3.Add(v.Add(&negX3).Mul(&r)) // Y3 = r*(V-X3)+Y3 (mag: 4) + z3.Add2(z1, z2).Square() // Z3 = (Z1+Z2)^2 (mag: 1) + z3.Add(z1z1.Add(&z2z2).Negate(2)) // Z3 = Z3-(Z1Z1+Z2Z2) (mag: 4) + z3.Mul(&h) // Z3 = Z3*H (mag: 1) + + // Normalize the resulting field values as needed. + x3.Normalize() + y3.Normalize() + z3.Normalize() +} + +// AddNonConst adds the passed Jacobian points together and stores the result in +// the provided result param in *non-constant* time. +// +// NOTE: The points must be normalized for this function to return the correct +// result. The resulting point will be normalized. +func AddNonConst(p1, p2, result *JacobianPoint) { + // The point at infinity is the identity according to the group law for + // elliptic curve cryptography. Thus, ∞ + P = P and P + ∞ = P. + if (p1.X.IsZero() && p1.Y.IsZero()) || p1.Z.IsZero() { + result.Set(p2) + return + } + if (p2.X.IsZero() && p2.Y.IsZero()) || p2.Z.IsZero() { + result.Set(p1) + return + } + + // Faster point addition can be achieved when certain assumptions are + // met. For example, when both points have the same z value, arithmetic + // on the z values can be avoided. This section thus checks for these + // conditions and calls an appropriate add function which is accelerated + // by using those assumptions. + isZ1One := p1.Z.IsOne() + isZ2One := p2.Z.IsOne() + switch { + case isZ1One && isZ2One: + addZ1AndZ2EqualsOne(p1, p2, result) + return + case p1.Z.Equals(&p2.Z): + addZ1EqualsZ2(p1, p2, result) + return + case isZ2One: + addZ2EqualsOne(p1, p2, result) + return + } + + // None of the above assumptions are true, so fall back to generic + // point addition. + addGeneric(p1, p2, result) +} + +// doubleZ1EqualsOne performs point doubling on the passed Jacobian point when +// the point is already known to have a z value of 1 and stores the result in +// the provided result param. That is to say result = 2*p. It performs faster +// point doubling than the generic routine since less arithmetic is needed due +// to the ability to avoid multiplication by the z value. +// +// NOTE: The resulting point will be normalized. +func doubleZ1EqualsOne(p, result *JacobianPoint) { + // This function uses the assumptions that z1 is 1, thus the point + // doubling formulas reduce to: + // + // X3 = (3*X1^2)^2 - 8*X1*Y1^2 + // Y3 = (3*X1^2)*(4*X1*Y1^2 - X3) - 8*Y1^4 + // Z3 = 2*Y1 + // + // To compute the above efficiently, this implementation splits the + // equation into intermediate elements which are used to minimize the + // number of field multiplications in favor of field squarings which + // are roughly 35% faster than field multiplications with the current + // implementation at the time this was written. + // + // This uses a slightly modified version of the method shown at: + // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-mdbl-2007-bl + // + // In particular it performs the calculations using the following: + // A = X1^2, B = Y1^2, C = B^2, D = 2*((X1+B)^2-A-C) + // E = 3*A, F = E^2, X3 = F-2*D, Y3 = E*(D-X3)-8*C + // Z3 = 2*Y1 + // + // This results in a cost of 1 field multiplication, 5 field squarings, + // 6 field additions, and 5 integer multiplications. + x1, y1 := &p.X, &p.Y + x3, y3, z3 := &result.X, &result.Y, &result.Z + var a, b, c, d, e, f FieldVal + z3.Set(y1).MulInt(2) // Z3 = 2*Y1 (mag: 2) + a.SquareVal(x1) // A = X1^2 (mag: 1) + b.SquareVal(y1) // B = Y1^2 (mag: 1) + c.SquareVal(&b) // C = B^2 (mag: 1) + b.Add(x1).Square() // B = (X1+B)^2 (mag: 1) + d.Set(&a).Add(&c).Negate(2) // D = -(A+C) (mag: 3) + d.Add(&b).MulInt(2) // D = 2*(B+D)(mag: 8) + e.Set(&a).MulInt(3) // E = 3*A (mag: 3) + f.SquareVal(&e) // F = E^2 (mag: 1) + x3.Set(&d).MulInt(2).Negate(16) // X3 = -(2*D) (mag: 17) + x3.Add(&f) // X3 = F+X3 (mag: 18) + f.Set(x3).Negate(18).Add(&d).Normalize() // F = D-X3 (mag: 1) + y3.Set(&c).MulInt(8).Negate(8) // Y3 = -(8*C) (mag: 9) + y3.Add(f.Mul(&e)) // Y3 = E*F+Y3 (mag: 10) + + // Normalize the resulting field values as needed. + x3.Normalize() + y3.Normalize() + z3.Normalize() +} + +// doubleGeneric performs point doubling on the passed Jacobian point without +// any assumptions about the z value and stores the result in the provided +// result param. That is to say result = 2*p. It is the slowest of the point +// doubling routines due to requiring the most arithmetic. +// +// NOTE: The resulting point will be normalized. +func doubleGeneric(p, result *JacobianPoint) { + // Point doubling formula for Jacobian coordinates for the secp256k1 + // curve: + // + // X3 = (3*X1^2)^2 - 8*X1*Y1^2 + // Y3 = (3*X1^2)*(4*X1*Y1^2 - X3) - 8*Y1^4 + // Z3 = 2*Y1*Z1 + // + // To compute the above efficiently, this implementation splits the + // equation into intermediate elements which are used to minimize the + // number of field multiplications in favor of field squarings which + // are roughly 35% faster than field multiplications with the current + // implementation at the time this was written. + // + // This uses a slightly modified version of the method shown at: + // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-dbl-2009-l + // + // In particular it performs the calculations using the following: + // A = X1^2, B = Y1^2, C = B^2, D = 2*((X1+B)^2-A-C) + // E = 3*A, F = E^2, X3 = F-2*D, Y3 = E*(D-X3)-8*C + // Z3 = 2*Y1*Z1 + // + // This results in a cost of 1 field multiplication, 5 field squarings, + // 6 field additions, and 5 integer multiplications. + x1, y1, z1 := &p.X, &p.Y, &p.Z + x3, y3, z3 := &result.X, &result.Y, &result.Z + var a, b, c, d, e, f FieldVal + z3.Mul2(y1, z1).MulInt(2) // Z3 = 2*Y1*Z1 (mag: 2) + a.SquareVal(x1) // A = X1^2 (mag: 1) + b.SquareVal(y1) // B = Y1^2 (mag: 1) + c.SquareVal(&b) // C = B^2 (mag: 1) + b.Add(x1).Square() // B = (X1+B)^2 (mag: 1) + d.Set(&a).Add(&c).Negate(2) // D = -(A+C) (mag: 3) + d.Add(&b).MulInt(2) // D = 2*(B+D)(mag: 8) + e.Set(&a).MulInt(3) // E = 3*A (mag: 3) + f.SquareVal(&e) // F = E^2 (mag: 1) + x3.Set(&d).MulInt(2).Negate(16) // X3 = -(2*D) (mag: 17) + x3.Add(&f) // X3 = F+X3 (mag: 18) + f.Set(x3).Negate(18).Add(&d).Normalize() // F = D-X3 (mag: 1) + y3.Set(&c).MulInt(8).Negate(8) // Y3 = -(8*C) (mag: 9) + y3.Add(f.Mul(&e)) // Y3 = E*F+Y3 (mag: 10) + + // Normalize the resulting field values as needed. + x3.Normalize() + y3.Normalize() + z3.Normalize() +} + +// DoubleNonConst doubles the passed Jacobian point and stores the result in the +// provided result parameter in *non-constant* time. +// +// NOTE: The point must be normalized for this function to return the correct +// result. The resulting point will be normalized. +func DoubleNonConst(p, result *JacobianPoint) { + // Doubling the point at infinity is still infinity. + if p.Y.IsZero() || p.Z.IsZero() { + result.X.SetInt(0) + result.Y.SetInt(0) + result.Z.SetInt(0) + return + } + + // Slightly faster point doubling can be achieved when the z value is 1 + // by avoiding the multiplication on the z value. This section calls + // a point doubling function which is accelerated by using that + // assumption when possible. + if p.Z.IsOne() { + doubleZ1EqualsOne(p, result) + return + } + + // Fall back to generic point doubling which works with arbitrary z + // values. + doubleGeneric(p, result) +} + +// mulAdd64 multiplies the two passed base 2^64 digits together, adds the given +// value to the result, and returns the 128-bit result via a (hi, lo) tuple +// where the upper half of the bits are returned in hi and the lower half in lo. +func mulAdd64(digit1, digit2, m uint64) (hi, lo uint64) { + // Note the carry on the final add is safe to discard because the maximum + // possible value is: + // (2^64 - 1)(2^64 - 1) + (2^64 - 1) = 2^128 - 2^64 + // and: + // 2^128 - 2^64 < 2^128. + var c uint64 + hi, lo = bits.Mul64(digit1, digit2) + lo, c = bits.Add64(lo, m, 0) + hi, _ = bits.Add64(hi, 0, c) + return hi, lo +} + +// mulAdd64Carry multiplies the two passed base 2^64 digits together, adds both +// the given value and carry to the result, and returns the 128-bit result via a +// (hi, lo) tuple where the upper half of the bits are returned in hi and the +// lower half in lo. +func mulAdd64Carry(digit1, digit2, m, c uint64) (hi, lo uint64) { + // Note the carry on the high order add is safe to discard because the + // maximum possible value is: + // (2^64 - 1)(2^64 - 1) + 2*(2^64 - 1) = 2^128 - 1 + // and: + // 2^128 - 1 < 2^128. + var c2 uint64 + hi, lo = mulAdd64(digit1, digit2, m) + lo, c2 = bits.Add64(lo, c, 0) + hi, _ = bits.Add64(hi, 0, c2) + return hi, lo +} + +// mul512Rsh320Round computes the full 512-bit product of the two given scalars, +// right shifts the result by 320 bits, rounds to the nearest integer, and +// returns the result in constant time. +// +// Note that despite the inputs and output being mod n scalars, the 512-bit +// product is NOT reduced mod N prior to the right shift. This is intentional +// because it is used for replacing division with multiplication and thus the +// intermediate results must be done via a field extension to a larger field. +func mul512Rsh320Round(n1, n2 *ModNScalar) ModNScalar { + // Convert n1 and n2 to base 2^64 digits. + n1Digit0 := uint64(n1.n[0]) | uint64(n1.n[1])<<32 + n1Digit1 := uint64(n1.n[2]) | uint64(n1.n[3])<<32 + n1Digit2 := uint64(n1.n[4]) | uint64(n1.n[5])<<32 + n1Digit3 := uint64(n1.n[6]) | uint64(n1.n[7])<<32 + n2Digit0 := uint64(n2.n[0]) | uint64(n2.n[1])<<32 + n2Digit1 := uint64(n2.n[2]) | uint64(n2.n[3])<<32 + n2Digit2 := uint64(n2.n[4]) | uint64(n2.n[5])<<32 + n2Digit3 := uint64(n2.n[6]) | uint64(n2.n[7])<<32 + + // Compute the full 512-bit product n1*n2. + var r0, r1, r2, r3, r4, r5, r6, r7, c uint64 + + // Terms resulting from the product of the first digit of the second number + // by all digits of the first number. + // + // Note that r0 is ignored because it is not needed to compute the higher + // terms and it is shifted out below anyway. + c, _ = bits.Mul64(n2Digit0, n1Digit0) + c, r1 = mulAdd64(n2Digit0, n1Digit1, c) + c, r2 = mulAdd64(n2Digit0, n1Digit2, c) + r4, r3 = mulAdd64(n2Digit0, n1Digit3, c) + + // Terms resulting from the product of the second digit of the second number + // by all digits of the first number. + // + // Note that r1 is ignored because it is no longer needed to compute the + // higher terms and it is shifted out below anyway. + c, _ = mulAdd64(n2Digit1, n1Digit0, r1) + c, r2 = mulAdd64Carry(n2Digit1, n1Digit1, r2, c) + c, r3 = mulAdd64Carry(n2Digit1, n1Digit2, r3, c) + r5, r4 = mulAdd64Carry(n2Digit1, n1Digit3, r4, c) + + // Terms resulting from the product of the third digit of the second number + // by all digits of the first number. + // + // Note that r2 is ignored because it is no longer needed to compute the + // higher terms and it is shifted out below anyway. + c, _ = mulAdd64(n2Digit2, n1Digit0, r2) + c, r3 = mulAdd64Carry(n2Digit2, n1Digit1, r3, c) + c, r4 = mulAdd64Carry(n2Digit2, n1Digit2, r4, c) + r6, r5 = mulAdd64Carry(n2Digit2, n1Digit3, r5, c) + + // Terms resulting from the product of the fourth digit of the second number + // by all digits of the first number. + // + // Note that r3 is ignored because it is no longer needed to compute the + // higher terms and it is shifted out below anyway. + c, _ = mulAdd64(n2Digit3, n1Digit0, r3) + c, r4 = mulAdd64Carry(n2Digit3, n1Digit1, r4, c) + c, r5 = mulAdd64Carry(n2Digit3, n1Digit2, r5, c) + r7, r6 = mulAdd64Carry(n2Digit3, n1Digit3, r6, c) + + // At this point the upper 256 bits of the full 512-bit product n1*n2 are in + // r4..r7 (recall the low order results were discarded as noted above). + // + // Right shift the result 320 bits. Note that the MSB of r4 determines + // whether or not to round because it is the final bit that is shifted out. + // + // Also, notice that r3..r7 would also ordinarily be set to 0 as well for + // the full shift, but that is skipped since they are no longer used as + // their values are known to be zero. + roundBit := r4 >> 63 + r2, r1, r0 = r7, r6, r5 + + // Conditionally add 1 depending on the round bit in constant time. + r0, c = bits.Add64(r0, roundBit, 0) + r1, c = bits.Add64(r1, 0, c) + r2, r3 = bits.Add64(r2, 0, c) + + // Finally, convert the result to a mod n scalar. + // + // No modular reduction is needed because the result is guaranteed to be + // less than the group order given the group order is > 2^255 and the + // maximum possible value of the result is 2^192. + var result ModNScalar + result.n[0] = uint32(r0) + result.n[1] = uint32(r0 >> 32) + result.n[2] = uint32(r1) + result.n[3] = uint32(r1 >> 32) + result.n[4] = uint32(r2) + result.n[5] = uint32(r2 >> 32) + result.n[6] = uint32(r3) + result.n[7] = uint32(r3 >> 32) + return result +} + +// splitK returns two scalars (k1 and k2) that are a balanced length-two +// representation of the provided scalar such that k ≡ k1 + k2*λ (mod N), where +// N is the secp256k1 group order. +func splitK(k *ModNScalar) (ModNScalar, ModNScalar) { + // The ultimate goal is to decompose k into two scalars that are around + // half the bit length of k such that the following equation is satisfied: + // + // k1 + k2*λ ≡ k (mod n) + // + // The strategy used here is based on algorithm 3.74 from [GECC] with a few + // modifications to make use of the more efficient mod n scalar type, avoid + // some costly long divisions, and minimize the number of calculations. + // + // Start by defining a function that takes a vector v = ∈ ℤ⨯ℤ: + // + // f(v) = a + bλ (mod n) + // + // Then, find two vectors, v1 = , and v2 = in ℤ⨯ℤ such that: + // 1) v1 and v2 are linearly independent + // 2) f(v1) = f(v2) = 0 + // 3) v1 and v2 have small Euclidean norm + // + // The vectors that satisfy these properties are found via the Euclidean + // algorithm and are precomputed since both n and λ are fixed values for the + // secp256k1 curve. See genprecomps.go for derivation details. + // + // Next, consider k as a vector in ℚ⨯ℚ and by linear algebra write: + // + // = g1*v1 + g2*v2, where g1, g2 ∈ ℚ + // + // Note that, per above, the components of vector v1 are a1 and b1 while the + // components of vector v2 are a2 and b2. Given the vectors v1 and v2 were + // generated such that a1*b2 - a2*b1 = n, solving the equation for g1 and g2 + // yields: + // + // g1 = b2*k / n + // g2 = -b1*k / n + // + // Observe: + // = g1*v1 + g2*v2 + // = (b2*k/n)* + (-b1*k/n)* | substitute + // = + <-a2*b1*k/n, -b2*b1*k/n> | scalar mul + // = | vector add + // = <[a1*b2*k - a2*b1*k]/n, 0> | simplify + // = | factor out k + // = | substitute + // = | simplify + // + // Now, consider an integer-valued vector v: + // + // v = c1*v1 + c2*v2, where c1, c2 ∈ ℤ (mod n) + // + // Since vectors v1 and v2 are linearly independent and were generated such + // that f(v1) = f(v2) = 0, all possible scalars c1 and c2 also produce a + // vector v such that f(v) = 0. + // + // In other words, c1 and c2 can be any integers and the resulting + // decomposition will still satisfy the required equation. However, since + // the goal is to produce a balanced decomposition that provides a + // performance advantage by minimizing max(k1, k2), c1 and c2 need to be + // integers close to g1 and g2, respectively, so the resulting vector v is + // an integer-valued vector that is close to . + // + // Finally, consider the vector u: + // + // u = - v + // + // It follows that f(u) = k and thus the two components of vector u satisfy + // the required equation: + // + // k1 + k2*λ ≡ k (mod n) + // + // Choosing c1 and c2: + // ------------------- + // + // As mentioned above, c1 and c2 need to be integers close to g1 and g2, + // respectively. The algorithm in [GECC] chooses the following values: + // + // c1 = round(g1) = round(b2*k / n) + // c2 = round(g2) = round(-b1*k / n) + // + // However, as section 3.4.2 of [STWS] notes, the aforementioned approach + // requires costly long divisions that can be avoided by precomputing + // rounded estimates as follows: + // + // t = bitlen(n) + 1 + // z1 = round(2^t * b2 / n) + // z2 = round(2^t * -b1 / n) + // + // Then, use those precomputed estimates to perform a multiplication by k + // along with a floored division by 2^t, which is a simple right shift by t: + // + // c1 = floor(k * z1 / 2^t) = (k * z1) >> t + // c2 = floor(k * z2 / 2^t) = (k * z2) >> t + // + // Finally, round up if last bit discarded in the right shift by t is set by + // adding 1. + // + // As a further optimization, rather than setting t = bitlen(n) + 1 = 257 as + // stated by [STWS], this implementation uses a higher precision estimate of + // t = bitlen(n) + 64 = 320 because it allows simplification of the shifts + // in the internal calculations that are done via uint64s and also allows + // the use of floor in the precomputations. + // + // Thus, the calculations this implementation uses are: + // + // z1 = floor(b2<<320 / n) | precomputed + // z2 = floor((-b1)<<320) / n) | precomputed + // c1 = ((k * z1) >> 320) + (((k * z1) >> 319) & 1) + // c2 = ((k * z2) >> 320) + (((k * z2) >> 319) & 1) + // + // Putting it all together: + // ------------------------ + // + // Calculate the following vectors using the values discussed above: + // + // v = c1*v1 + c2*v2 + // u = - v + // + // The two components of the resulting vector v are: + // va = c1*a1 + c2*a2 + // vb = c1*b1 + c2*b2 + // + // Thus, the two components of the resulting vector u are: + // k1 = k - va + // k2 = 0 - vb = -vb + // + // As some final optimizations: + // + // 1) Note that k1 + k2*λ ≡ k (mod n) means that k1 ≡ k - k2*λ (mod n). + // Therefore, the computation of va can be avoided to save two + // field multiplications and a field addition. + // + // 2) Since k1 ≡ k - k2*λ ≡ k + k2*(-λ), an additional field negation is + // saved by storing and using the negative version of λ. + // + // 3) Since k2 ≡ -vb ≡ -(c1*b1 + c2*b2) ≡ c1*(-b1) + c2*(-b2), one more + // field negation is saved by storing and using the negative versions of + // b1 and b2. + // + // k2 = c1*(-b1) + c2*(-b2) + // k1 = k + k2*(-λ) + var k1, k2 ModNScalar + c1 := mul512Rsh320Round(k, endoZ1) + c2 := mul512Rsh320Round(k, endoZ2) + k2.Add2(c1.Mul(endoNegB1), c2.Mul(endoNegB2)) + k1.Mul2(&k2, endoNegLambda).Add(k) + return k1, k2 +} + +// nafScalar represents a positive integer up to a maximum value of 2^256 - 1 +// encoded in non-adjacent form. +// +// NAF is a signed-digit representation where each digit can be +1, 0, or -1. +// +// In order to efficiently encode that information, this type uses two arrays, a +// "positive" array where set bits represent the +1 signed digits and a +// "negative" array where set bits represent the -1 signed digits. 0 is +// represented by neither array having a bit set in that position. +// +// The Pos and Neg methods return the aforementioned positive and negative +// arrays, respectively. +type nafScalar struct { + // pos houses the positive portion of the representation. An additional + // byte is required for the positive portion because the NAF encoding can be + // up to 1 bit longer than the normal binary encoding of the value. + // + // neg houses the negative portion of the representation. Even though the + // additional byte is not required for the negative portion, since it can + // never exceed the length of the normal binary encoding of the value, + // keeping the same length for positive and negative portions simplifies + // working with the representation and allows extra conditional branches to + // be avoided. + // + // start and end specify the starting and ending index to use within the pos + // and neg arrays, respectively. This allows fixed size arrays to be used + // versus needing to dynamically allocate space on the heap. + // + // NOTE: The fields are defined in the order that they are to minimize the + // padding on 32-bit and 64-bit platforms. + pos [33]byte + start, end uint8 + neg [33]byte +} + +// Pos returns the bytes of the encoded value with bits set in the positions +// that represent a signed digit of +1. +func (s *nafScalar) Pos() []byte { + return s.pos[s.start:s.end] +} + +// Neg returns the bytes of the encoded value with bits set in the positions +// that represent a signed digit of -1. +func (s *nafScalar) Neg() []byte { + return s.neg[s.start:s.end] +} + +// naf takes a positive integer up to a maximum value of 2^256 - 1 and returns +// its non-adjacent form (NAF), which is a unique signed-digit representation +// such that no two consecutive digits are nonzero. See the documentation for +// the returned type for details on how the representation is encoded +// efficiently and how to interpret it +// +// NAF is useful in that it has the fewest nonzero digits of any signed digit +// representation, only 1/3rd of its digits are nonzero on average, and at least +// half of the digits will be 0. +// +// The aforementioned properties are particularly beneficial for optimizing +// elliptic curve point multiplication because they effectively minimize the +// number of required point additions in exchange for needing to perform a mix +// of fewer point additions and subtractions and possibly one additional point +// doubling. This is an excellent tradeoff because subtraction of points has +// the same computational complexity as addition of points and point doubling is +// faster than both. +func naf(k []byte) nafScalar { + // Strip leading zero bytes. + for len(k) > 0 && k[0] == 0x00 { + k = k[1:] + } + + // The non-adjacent form (NAF) of a positive integer k is an expression + // k = ∑_(i=0, l-1) k_i * 2^i where k_i ∈ {0,±1}, k_(l-1) != 0, and no two + // consecutive digits k_i are nonzero. + // + // The traditional method of computing the NAF of a positive integer is + // given by algorithm 3.30 in [GECC]. It consists of repeatedly dividing k + // by 2 and choosing the remainder so that the quotient (k−r)/2 is even + // which ensures the next NAF digit is 0. This requires log_2(k) steps. + // + // However, in [BRID], Prodinger notes that a closed form expression for the + // NAF representation is the bitwise difference 3k/2 - k/2. This is more + // efficient as it can be computed in O(1) versus the O(log(n)) of the + // traditional approach. + // + // The following code makes use of that formula to compute the NAF more + // efficiently. + // + // To understand the logic here, observe that the only way the NAF has a + // nonzero digit at a given bit is when either 3k/2 or k/2 has a bit set in + // that position, but not both. In other words, the result of a bitwise + // xor. This can be seen simply by considering that when the bits are the + // same, the subtraction is either 0-0 or 1-1, both of which are 0. + // + // Further, observe that the "+1" digits in the result are contributed by + // 3k/2 while the "-1" digits are from k/2. So, they can be determined by + // taking the bitwise and of each respective value with the result of the + // xor which identifies which bits are nonzero. + // + // Using that information, this loops backwards from the least significant + // byte to the most significant byte while performing the aforementioned + // calculations by propagating the potential carry and high order bit from + // the next word during the right shift. + kLen := len(k) + var result nafScalar + var carry uint8 + for byteNum := kLen - 1; byteNum >= 0; byteNum-- { + // Calculate k/2. Notice the carry from the previous word is added and + // the low order bit from the next word is shifted in accordingly. + kc := uint16(k[byteNum]) + uint16(carry) + var nextWord uint8 + if byteNum > 0 { + nextWord = k[byteNum-1] + } + halfK := kc>>1 | uint16(nextWord<<7) + + // Calculate 3k/2 and determine the non-zero digits in the result. + threeHalfK := kc + halfK + nonZeroResultDigits := threeHalfK ^ halfK + + // Determine the signed digits {0, ±1}. + result.pos[byteNum+1] = uint8(threeHalfK & nonZeroResultDigits) + result.neg[byteNum+1] = uint8(halfK & nonZeroResultDigits) + + // Propagate the potential carry from the 3k/2 calculation. + carry = uint8(threeHalfK >> 8) + } + result.pos[0] = carry + + // Set the starting and ending positions within the fixed size arrays to + // identify the bytes that are actually used. This is important since the + // encoding is big endian and thus trailing zero bytes changes its value. + result.start = 1 - carry + result.end = uint8(kLen + 1) + return result +} + +// ScalarMultNonConst multiplies k*P where k is a scalar modulo the curve order +// and P is a point in Jacobian projective coordinates and stores the result in +// the provided Jacobian point. +// +// NOTE: The point must be normalized for this function to return the correct +// result. The resulting point will be normalized. +func ScalarMultNonConst(k *ModNScalar, point, result *JacobianPoint) { + // ------------------------------------------------------------------------- + // This makes use of the following efficiently-computable endomorphism to + // accelerate the computation: + // + // φ(P) ⟼ λ*P = (β*P.x mod p, P.y) + // + // In other words, there is a special scalar λ that every point on the + // elliptic curve can be multiplied by that will result in the same point as + // performing a single field multiplication of the point's X coordinate by + // the special value β. + // + // This is useful because scalar point multiplication is significantly more + // expensive than a single field multiplication given the former involves a + // series of point doublings and additions which themselves consist of a + // combination of several field multiplications, squarings, and additions. + // + // So, the idea behind making use of the endomorphism is thus to decompose + // the scalar into two scalars that are each about half the bit length of + // the original scalar such that: + // + // k ≡ k1 + k2*λ (mod n) + // + // This in turn allows the scalar point multiplication to be performed as a + // sum of two smaller half-length multiplications as follows: + // + // k*P = (k1 + k2*λ)*P + // = k1*P + k2*λ*P + // = k1*P + k2*φ(P) + // + // Thus, a speedup is achieved so long as it's faster to decompose the + // scalar, compute φ(P), and perform a simultaneous multiply of the + // half-length point multiplications than it is to compute a full width + // point multiplication. + // + // In practice, benchmarks show the current implementation provides a + // speedup of around 30-35% versus not using the endomorphism. + // + // See section 3.5 in [GECC] for a more rigorous treatment. + // ------------------------------------------------------------------------- + + // Per above, the main equation here to remember is: + // k*P = k1*P + k2*φ(P) + // + // p1 below is P in the equation while p2 is φ(P) in the equation. + // + // NOTE: φ(x,y) = (β*x,y). The Jacobian z coordinates are the same, so this + // math goes through. + // + // Also, calculate -p1 and -p2 for use in the NAF optimization. + p1, p1Neg := new(JacobianPoint), new(JacobianPoint) + p1.Set(point) + p1Neg.Set(p1) + p1Neg.Y.Negate(1).Normalize() + p2, p2Neg := new(JacobianPoint), new(JacobianPoint) + p2.Set(p1) + p2.X.Mul(endoBeta).Normalize() + p2Neg.Set(p2) + p2Neg.Y.Negate(1).Normalize() + + // Decompose k into k1 and k2 such that k = k1 + k2*λ (mod n) where k1 and + // k2 are around half the bit length of k in order to halve the number of EC + // operations. + // + // Notice that this also flips the sign of the scalars and points as needed + // to minimize the bit lengths of the scalars k1 and k2. + // + // This is done because the scalars are operating modulo the group order + // which means that when they would otherwise be a small negative magnitude + // they will instead be a large positive magnitude. Since the goal is for + // the scalars to have a small magnitude to achieve a performance boost, use + // their negation when they are greater than the half order of the group and + // flip the positive and negative values of the corresponding point that + // will be multiplied by to compensate. + // + // In other words, transform the calc when k1 is over the half order to: + // k1*P = -k1*-P + // + // Similarly, transform the calc when k2 is over the half order to: + // k2*φ(P) = -k2*-φ(P) + k1, k2 := splitK(k) + if k1.IsOverHalfOrder() { + k1.Negate() + p1, p1Neg = p1Neg, p1 + } + if k2.IsOverHalfOrder() { + k2.Negate() + p2, p2Neg = p2Neg, p2 + } + + // Convert k1 and k2 into their NAF representations since NAF has a lot more + // zeros overall on average which minimizes the number of required point + // additions in exchange for a mix of fewer point additions and subtractions + // at the cost of one additional point doubling. + // + // This is an excellent tradeoff because subtraction of points has the same + // computational complexity as addition of points and point doubling is + // faster than both. + // + // Concretely, on average, 1/2 of all bits will be non-zero with the normal + // binary representation whereas only 1/3rd of the bits will be non-zero + // with NAF. + // + // The Pos version of the bytes contain the +1s and the Neg versions contain + // the -1s. + k1Bytes, k2Bytes := k1.Bytes(), k2.Bytes() + k1NAF, k2NAF := naf(k1Bytes[:]), naf(k2Bytes[:]) + k1PosNAF, k1NegNAF := k1NAF.Pos(), k1NAF.Neg() + k2PosNAF, k2NegNAF := k2NAF.Pos(), k2NAF.Neg() + k1Len, k2Len := len(k1PosNAF), len(k2PosNAF) + + // Add left-to-right using the NAF optimization. See algorithm 3.77 from + // [GECC]. + // + // Point Q = ∞ (point at infinity). + var q JacobianPoint + m := k1Len + if m < k2Len { + m = k2Len + } + for i := 0; i < m; i++ { + // Since k1 and k2 are potentially different lengths and the calculation + // is being done left to right, pad the front of the shorter one with + // 0s. + var k1BytePos, k1ByteNeg, k2BytePos, k2ByteNeg byte + if i >= m-k1Len { + k1BytePos, k1ByteNeg = k1PosNAF[i-(m-k1Len)], k1NegNAF[i-(m-k1Len)] + } + if i >= m-k2Len { + k2BytePos, k2ByteNeg = k2PosNAF[i-(m-k2Len)], k2NegNAF[i-(m-k2Len)] + } + + for mask := uint8(1 << 7); mask > 0; mask >>= 1 { + // Q = 2 * Q + DoubleNonConst(&q, &q) + + // Add or subtract the first point based on the signed digit of the + // NAF representation of k1 at this bit position. + // + // +1: Q = Q + p1 + // -1: Q = Q - p1 + // 0: Q = Q (no change) + if k1BytePos&mask == mask { + AddNonConst(&q, p1, &q) + } else if k1ByteNeg&mask == mask { + AddNonConst(&q, p1Neg, &q) + } + + // Add or subtract the second point based on the signed digit of the + // NAF representation of k2 at this bit position. + // + // +1: Q = Q + p2 + // -1: Q = Q - p2 + // 0: Q = Q (no change) + if k2BytePos&mask == mask { + AddNonConst(&q, p2, &q) + } else if k2ByteNeg&mask == mask { + AddNonConst(&q, p2Neg, &q) + } + } + } + + result.Set(&q) +} + +// ScalarBaseMultNonConst multiplies k*G where k is a scalar modulo the curve +// order and G is the base point of the group and stores the result in the +// provided Jacobian point. +// +// NOTE: The resulting point will be normalized. +func ScalarBaseMultNonConst(k *ModNScalar, result *JacobianPoint) { + scalarBaseMultNonConst(k, result) +} + +// jacobianG is the secp256k1 base point converted to Jacobian coordinates and +// is defined here to avoid repeatedly converting it. +var jacobianG = func() JacobianPoint { + var G JacobianPoint + bigAffineToJacobian(curveParams.Gx, curveParams.Gy, &G) + return G +}() + +// scalarBaseMultNonConstSlow computes k*G through ScalarMultNonConst. +func scalarBaseMultNonConstSlow(k *ModNScalar, result *JacobianPoint) { + ScalarMultNonConst(k, &jacobianG, result) +} + +// scalarBaseMultNonConstFast computes k*G through the precomputed lookup +// tables. +func scalarBaseMultNonConstFast(k *ModNScalar, result *JacobianPoint) { + bytePoints := s256BytePoints() + + // Start with the point at infinity. + result.X.Zero() + result.Y.Zero() + result.Z.Zero() + + // bytePoints has all 256 byte points for each 8-bit window. The strategy + // is to add up the byte points. This is best understood by expressing k in + // base-256 which it already sort of is. Each "digit" in the 8-bit window + // can be looked up using bytePoints and added together. + kb := k.Bytes() + for i := 0; i < len(kb); i++ { + pt := &bytePoints[i][kb[i]] + AddNonConst(result, pt, result) + } +} + +// isOnCurve returns whether or not the affine point (x,y) is on the curve. +func isOnCurve(fx, fy *FieldVal) bool { + // Elliptic curve equation for secp256k1 is: y^2 = x^3 + 7 + y2 := new(FieldVal).SquareVal(fy).Normalize() + result := new(FieldVal).SquareVal(fx).Mul(fx).AddInt(7).Normalize() + return y2.Equals(result) +} + +// DecompressY attempts to calculate the Y coordinate for the given X coordinate +// such that the result pair is a point on the secp256k1 curve. It adjusts Y +// based on the desired oddness and returns whether or not it was successful +// since not all X coordinates are valid. +// +// The magnitude of the provided X coordinate field value must be a max of 8 for +// a correct result. The resulting Y field value will have a magnitude of 1. +// +// Preconditions: +// - The input field value MUST have a max magnitude of 8 +// Output Normalized: Yes if the func returns true, no otherwise +// Output Max Magnitude: 1 +func DecompressY(x *FieldVal, odd bool, resultY *FieldVal) bool { + // The curve equation for secp256k1 is: y^2 = x^3 + 7. Thus + // y = +-sqrt(x^3 + 7). + // + // The x coordinate must be invalid if there is no square root for the + // calculated rhs because it means the X coordinate is not for a point on + // the curve. + x3PlusB := new(FieldVal).SquareVal(x).Mul(x).AddInt(7) + if hasSqrt := resultY.SquareRootVal(x3PlusB); !hasSqrt { + return false + } + if resultY.Normalize().IsOdd() != odd { + resultY.Negate(1).Normalize() + } + return true +} diff --git a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/curve_embedded.go b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/curve_embedded.go new file mode 100644 index 00000000000..16288318c1e --- /dev/null +++ b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/curve_embedded.go @@ -0,0 +1,14 @@ +// Copyright (c) 2024 The Decred developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +//go:build tinygo + +package secp256k1 + +// This file contains the variants suitable for +// memory or storage constrained environments. + +func scalarBaseMultNonConst(k *ModNScalar, result *JacobianPoint) { + scalarBaseMultNonConstSlow(k, result) +} diff --git a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/curve_precompute.go b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/curve_precompute.go new file mode 100644 index 00000000000..cf84f770edd --- /dev/null +++ b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/curve_precompute.go @@ -0,0 +1,14 @@ +// Copyright (c) 2024 The Decred developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +//go:build !tinygo + +package secp256k1 + +// This file contains the variants that don't fit in +// memory or storage constrained environments. + +func scalarBaseMultNonConst(k *ModNScalar, result *JacobianPoint) { + scalarBaseMultNonConstFast(k, result) +} diff --git a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/doc.go b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/doc.go new file mode 100644 index 00000000000..ac01e2343ca --- /dev/null +++ b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/doc.go @@ -0,0 +1,59 @@ +// Copyright (c) 2013-2014 The btcsuite developers +// Copyright (c) 2015-2022 The Decred developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +/* +Package secp256k1 implements optimized secp256k1 elliptic curve operations in +pure Go. + +This package provides an optimized pure Go implementation of elliptic curve +cryptography operations over the secp256k1 curve as well as data structures and +functions for working with public and private secp256k1 keys. See +https://www.secg.org/sec2-v2.pdf for details on the standard. + +In addition, sub packages are provided to produce, verify, parse, and serialize +ECDSA signatures and EC-Schnorr-DCRv0 (a custom Schnorr-based signature scheme +specific to Decred) signatures. See the README.md files in the relevant sub +packages for more details about those aspects. + +An overview of the features provided by this package are as follows: + + - Private key generation, serialization, and parsing + - Public key generation, serialization and parsing per ANSI X9.62-1998 + - Parses uncompressed, compressed, and hybrid public keys + - Serializes uncompressed and compressed public keys + - Specialized types for performing optimized and constant time field operations + - FieldVal type for working modulo the secp256k1 field prime + - ModNScalar type for working modulo the secp256k1 group order + - Elliptic curve operations in Jacobian projective coordinates + - Point addition + - Point doubling + - Scalar multiplication with an arbitrary point + - Scalar multiplication with the base point (group generator) + - Point decompression from a given x coordinate + - Nonce generation via RFC6979 with support for extra data and version + information that can be used to prevent nonce reuse between signing + algorithms + +It also provides an implementation of the Go standard library crypto/elliptic +Curve interface via the S256 function so that it may be used with other packages +in the standard library such as crypto/tls, crypto/x509, and crypto/ecdsa. +However, in the case of ECDSA, it is highly recommended to use the ecdsa sub +package of this package instead since it is optimized specifically for secp256k1 +and is significantly faster as a result. + +Although this package was primarily written for dcrd, it has intentionally been +designed so it can be used as a standalone package for any projects needing to +use optimized secp256k1 elliptic curve cryptography. + +Finally, a comprehensive suite of tests is provided to provide a high level of +quality assurance. + +# Use of secp256k1 in Decred + +At the time of this writing, the primary public key cryptography in widespread +use on the Decred network used to secure coins is based on elliptic curves +defined by the secp256k1 domain parameters. +*/ +package secp256k1 diff --git a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/ecdh.go b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/ecdh.go new file mode 100644 index 00000000000..96869a3cd90 --- /dev/null +++ b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/ecdh.go @@ -0,0 +1,21 @@ +// Copyright (c) 2015 The btcsuite developers +// Copyright (c) 2015-2023 The Decred developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package secp256k1 + +// GenerateSharedSecret generates a shared secret based on a private key and a +// public key using Diffie-Hellman key exchange (ECDH) (RFC 5903). +// RFC5903 Section 9 states we should only return x. +// +// It is recommended to securely hash the result before using as a cryptographic +// key. +func GenerateSharedSecret(privkey *PrivateKey, pubkey *PublicKey) []byte { + var point, result JacobianPoint + pubkey.AsJacobian(&point) + ScalarMultNonConst(&privkey.Key, &point, &result) + result.ToAffine() + xBytes := result.X.Bytes() + return xBytes[:] +} diff --git a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/ellipticadaptor.go b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/ellipticadaptor.go new file mode 100644 index 00000000000..a3a45af3178 --- /dev/null +++ b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/ellipticadaptor.go @@ -0,0 +1,255 @@ +// Copyright 2020-2022 The Decred developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package secp256k1 + +// References: +// [SECG]: Recommended Elliptic Curve Domain Parameters +// https://www.secg.org/sec2-v2.pdf +// +// [GECC]: Guide to Elliptic Curve Cryptography (Hankerson, Menezes, Vanstone) + +import ( + "crypto/ecdsa" + "crypto/elliptic" + "math/big" +) + +// CurveParams contains the parameters for the secp256k1 curve. +type CurveParams struct { + // P is the prime used in the secp256k1 field. + P *big.Int + + // N is the order of the secp256k1 curve group generated by the base point. + N *big.Int + + // Gx and Gy are the x and y coordinate of the base point, respectively. + Gx, Gy *big.Int + + // BitSize is the size of the underlying secp256k1 field in bits. + BitSize int + + // H is the cofactor of the secp256k1 curve. + H int + + // ByteSize is simply the bit size / 8 and is provided for convenience + // since it is calculated repeatedly. + ByteSize int +} + +// Curve parameters taken from [SECG] section 2.4.1. +var curveParams = CurveParams{ + P: fromHex("fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f"), + N: fromHex("fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141"), + Gx: fromHex("79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798"), + Gy: fromHex("483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8"), + BitSize: 256, + H: 1, + ByteSize: 256 / 8, +} + +// Params returns the secp256k1 curve parameters for convenience. +func Params() *CurveParams { + return &curveParams +} + +// KoblitzCurve provides an implementation for secp256k1 that fits the ECC Curve +// interface from crypto/elliptic. +type KoblitzCurve struct { + *elliptic.CurveParams +} + +// bigAffineToJacobian takes an affine point (x, y) as big integers and converts +// it to Jacobian point with Z=1. +func bigAffineToJacobian(x, y *big.Int, result *JacobianPoint) { + result.X.SetByteSlice(x.Bytes()) + result.Y.SetByteSlice(y.Bytes()) + result.Z.SetInt(1) +} + +// jacobianToBigAffine takes a Jacobian point (x, y, z) as field values and +// converts it to an affine point as big integers. +func jacobianToBigAffine(point *JacobianPoint) (*big.Int, *big.Int) { + point.ToAffine() + + // Convert the field values for the now affine point to big.Ints. + x3, y3 := new(big.Int), new(big.Int) + x3.SetBytes(point.X.Bytes()[:]) + y3.SetBytes(point.Y.Bytes()[:]) + return x3, y3 +} + +// Params returns the parameters for the curve. +// +// This is part of the elliptic.Curve interface implementation. +func (curve *KoblitzCurve) Params() *elliptic.CurveParams { + return curve.CurveParams +} + +// IsOnCurve returns whether or not the affine point (x,y) is on the curve. +// +// This is part of the elliptic.Curve interface implementation. This function +// differs from the crypto/elliptic algorithm since a = 0 not -3. +func (curve *KoblitzCurve) IsOnCurve(x, y *big.Int) bool { + // Convert big ints to a Jacobian point for faster arithmetic. + var point JacobianPoint + bigAffineToJacobian(x, y, &point) + return isOnCurve(&point.X, &point.Y) +} + +// Add returns the sum of (x1,y1) and (x2,y2). +// +// This is part of the elliptic.Curve interface implementation. +func (curve *KoblitzCurve) Add(x1, y1, x2, y2 *big.Int) (*big.Int, *big.Int) { + // The point at infinity is the identity according to the group law for + // elliptic curve cryptography. Thus, ∞ + P = P and P + ∞ = P. + if x1.Sign() == 0 && y1.Sign() == 0 { + return x2, y2 + } + if x2.Sign() == 0 && y2.Sign() == 0 { + return x1, y1 + } + + // Convert the affine coordinates from big integers to Jacobian points, + // do the point addition in Jacobian projective space, and convert the + // Jacobian point back to affine big.Ints. + var p1, p2, result JacobianPoint + bigAffineToJacobian(x1, y1, &p1) + bigAffineToJacobian(x2, y2, &p2) + AddNonConst(&p1, &p2, &result) + return jacobianToBigAffine(&result) +} + +// Double returns 2*(x1,y1). +// +// This is part of the elliptic.Curve interface implementation. +func (curve *KoblitzCurve) Double(x1, y1 *big.Int) (*big.Int, *big.Int) { + if y1.Sign() == 0 { + return new(big.Int), new(big.Int) + } + + // Convert the affine coordinates from big integers to Jacobian points, + // do the point doubling in Jacobian projective space, and convert the + // Jacobian point back to affine big.Ints. + var point, result JacobianPoint + bigAffineToJacobian(x1, y1, &point) + DoubleNonConst(&point, &result) + return jacobianToBigAffine(&result) +} + +// moduloReduce reduces k from more than 32 bytes to 32 bytes and under. This +// is done by doing a simple modulo curve.N. We can do this since G^N = 1 and +// thus any other valid point on the elliptic curve has the same order. +func moduloReduce(k []byte) []byte { + // Since the order of G is curve.N, we can use a much smaller number by + // doing modulo curve.N + if len(k) > curveParams.ByteSize { + tmpK := new(big.Int).SetBytes(k) + tmpK.Mod(tmpK, curveParams.N) + return tmpK.Bytes() + } + + return k +} + +// ScalarMult returns k*(bx, by) where k is a big endian integer. +// +// This is part of the elliptic.Curve interface implementation. +func (curve *KoblitzCurve) ScalarMult(bx, by *big.Int, k []byte) (*big.Int, *big.Int) { + // Convert the affine coordinates from big integers to Jacobian points, + // do the multiplication in Jacobian projective space, and convert the + // Jacobian point back to affine big.Ints. + var kModN ModNScalar + kModN.SetByteSlice(moduloReduce(k)) + var point, result JacobianPoint + bigAffineToJacobian(bx, by, &point) + ScalarMultNonConst(&kModN, &point, &result) + return jacobianToBigAffine(&result) +} + +// ScalarBaseMult returns k*G where G is the base point of the group and k is a +// big endian integer. +// +// This is part of the elliptic.Curve interface implementation. +func (curve *KoblitzCurve) ScalarBaseMult(k []byte) (*big.Int, *big.Int) { + // Perform the multiplication and convert the Jacobian point back to affine + // big.Ints. + var kModN ModNScalar + kModN.SetByteSlice(moduloReduce(k)) + var result JacobianPoint + ScalarBaseMultNonConst(&kModN, &result) + return jacobianToBigAffine(&result) +} + +// X returns the x coordinate of the public key. +func (p *PublicKey) X() *big.Int { + return new(big.Int).SetBytes(p.x.Bytes()[:]) +} + +// Y returns the y coordinate of the public key. +func (p *PublicKey) Y() *big.Int { + return new(big.Int).SetBytes(p.y.Bytes()[:]) +} + +// ToECDSA returns the public key as a *ecdsa.PublicKey. +func (p *PublicKey) ToECDSA() *ecdsa.PublicKey { + return &ecdsa.PublicKey{ + Curve: S256(), + X: p.X(), + Y: p.Y(), + } +} + +// ToECDSA returns the private key as a *ecdsa.PrivateKey. +func (p *PrivateKey) ToECDSA() *ecdsa.PrivateKey { + var privKeyBytes [PrivKeyBytesLen]byte + p.Key.PutBytes(&privKeyBytes) + var result JacobianPoint + ScalarBaseMultNonConst(&p.Key, &result) + x, y := jacobianToBigAffine(&result) + newPrivKey := &ecdsa.PrivateKey{ + PublicKey: ecdsa.PublicKey{ + Curve: S256(), + X: x, + Y: y, + }, + D: new(big.Int).SetBytes(privKeyBytes[:]), + } + zeroArray32(&privKeyBytes) + return newPrivKey +} + +// fromHex converts the passed hex string into a big integer pointer and will +// panic is there is an error. This is only provided for the hard-coded +// constants so errors in the source code can bet detected. It will only (and +// must only) be called for initialization purposes. +func fromHex(s string) *big.Int { + if s == "" { + return big.NewInt(0) + } + r, ok := new(big.Int).SetString(s, 16) + if !ok { + panic("invalid hex in source file: " + s) + } + return r +} + +// secp256k1 is a global instance of the KoblitzCurve implementation which in +// turn embeds and implements elliptic.CurveParams. +var secp256k1 = &KoblitzCurve{ + CurveParams: &elliptic.CurveParams{ + P: curveParams.P, + N: curveParams.N, + B: fromHex("0000000000000000000000000000000000000000000000000000000000000007"), + Gx: curveParams.Gx, + Gy: curveParams.Gy, + BitSize: curveParams.BitSize, + Name: "secp256k1", + }, +} + +// S256 returns an elliptic.Curve which implements secp256k1. +func S256() *KoblitzCurve { + return secp256k1 +} diff --git a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/error.go b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/error.go new file mode 100644 index 00000000000..ac8c45127e4 --- /dev/null +++ b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/error.go @@ -0,0 +1,67 @@ +// Copyright (c) 2020 The Decred developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package secp256k1 + +// ErrorKind identifies a kind of error. It has full support for errors.Is and +// errors.As, so the caller can directly check against an error kind when +// determining the reason for an error. +type ErrorKind string + +// These constants are used to identify a specific RuleError. +const ( + // ErrPubKeyInvalidLen indicates that the length of a serialized public + // key is not one of the allowed lengths. + ErrPubKeyInvalidLen = ErrorKind("ErrPubKeyInvalidLen") + + // ErrPubKeyInvalidFormat indicates an attempt was made to parse a public + // key that does not specify one of the supported formats. + ErrPubKeyInvalidFormat = ErrorKind("ErrPubKeyInvalidFormat") + + // ErrPubKeyXTooBig indicates that the x coordinate for a public key + // is greater than or equal to the prime of the field underlying the group. + ErrPubKeyXTooBig = ErrorKind("ErrPubKeyXTooBig") + + // ErrPubKeyYTooBig indicates that the y coordinate for a public key is + // greater than or equal to the prime of the field underlying the group. + ErrPubKeyYTooBig = ErrorKind("ErrPubKeyYTooBig") + + // ErrPubKeyNotOnCurve indicates that a public key is not a point on the + // secp256k1 curve. + ErrPubKeyNotOnCurve = ErrorKind("ErrPubKeyNotOnCurve") + + // ErrPubKeyMismatchedOddness indicates that a hybrid public key specified + // an oddness of the y coordinate that does not match the actual oddness of + // the provided y coordinate. + ErrPubKeyMismatchedOddness = ErrorKind("ErrPubKeyMismatchedOddness") +) + +// Error satisfies the error interface and prints human-readable errors. +func (e ErrorKind) Error() string { + return string(e) +} + +// Error identifies an error related to public key cryptography using a +// sec256k1 curve. It has full support for errors.Is and errors.As, so the +// caller can ascertain the specific reason for the error by checking +// the underlying error. +type Error struct { + Err error + Description string +} + +// Error satisfies the error interface and prints human-readable errors. +func (e Error) Error() string { + return e.Description +} + +// Unwrap returns the underlying wrapped error. +func (e Error) Unwrap() error { + return e.Err +} + +// makeError creates an Error given a set of arguments. +func makeError(kind ErrorKind, desc string) Error { + return Error{Err: kind, Description: desc} +} diff --git a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/field.go b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/field.go new file mode 100644 index 00000000000..f979bb2efe1 --- /dev/null +++ b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/field.go @@ -0,0 +1,1696 @@ +// Copyright (c) 2013-2014 The btcsuite developers +// Copyright (c) 2015-2024 The Decred developers +// Copyright (c) 2013-2024 Dave Collins +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package secp256k1 + +// References: +// [HAC]: Handbook of Applied Cryptography Menezes, van Oorschot, Vanstone. +// http://cacr.uwaterloo.ca/hac/ + +// All elliptic curve operations for secp256k1 are done in a finite field +// characterized by a 256-bit prime. Given this precision is larger than the +// biggest available native type, obviously some form of bignum math is needed. +// This package implements specialized fixed-precision field arithmetic rather +// than relying on an arbitrary-precision arithmetic package such as math/big +// for dealing with the field math since the size is known. As a result, rather +// large performance gains are achieved by taking advantage of many +// optimizations not available to arbitrary-precision arithmetic and generic +// modular arithmetic algorithms. +// +// There are various ways to internally represent each finite field element. +// For example, the most obvious representation would be to use an array of 4 +// uint64s (64 bits * 4 = 256 bits). However, that representation suffers from +// a couple of issues. First, there is no native Go type large enough to handle +// the intermediate results while adding or multiplying two 64-bit numbers, and +// second there is no space left for overflows when performing the intermediate +// arithmetic between each array element which would lead to expensive carry +// propagation. +// +// Given the above, this implementation represents the field elements as +// 10 uint32s with each word (array entry) treated as base 2^26. This was +// chosen for the following reasons: +// 1) Most systems at the current time are 64-bit (or at least have 64-bit +// registers available for specialized purposes such as MMX) so the +// intermediate results can typically be done using a native register (and +// using uint64s to avoid the need for additional half-word arithmetic) +// 2) In order to allow addition of the internal words without having to +// propagate the carry, the max normalized value for each register must +// be less than the number of bits available in the register +// 3) Since we're dealing with 32-bit values, 64-bits of overflow is a +// reasonable choice for #2 +// 4) Given the need for 256-bits of precision and the properties stated in #1, +// #2, and #3, the representation which best accommodates this is 10 uint32s +// with base 2^26 (26 bits * 10 = 260 bits, so the final word only needs 22 +// bits) which leaves the desired 64 bits (32 * 10 = 320, 320 - 256 = 64) for +// overflow +// +// Since it is so important that the field arithmetic is extremely fast for high +// performance crypto, this type does not perform any validation where it +// ordinarily would. See the documentation for FieldVal for more details. + +import ( + "encoding/hex" +) + +// Constants used to make the code more readable. +const ( + twoBitsMask = 0x3 + fourBitsMask = 0xf + sixBitsMask = 0x3f + eightBitsMask = 0xff +) + +// Constants related to the field representation. +const ( + // fieldWords is the number of words used to internally represent the + // 256-bit value. + fieldWords = 10 + + // fieldBase is the exponent used to form the numeric base of each word. + // 2^(fieldBase*i) where i is the word position. + fieldBase = 26 + + // fieldBaseMask is the mask for the bits in each word needed to + // represent the numeric base of each word (except the most significant + // word). + fieldBaseMask = (1 << fieldBase) - 1 + + // fieldMSBBits is the number of bits in the most significant word used + // to represent the value. + fieldMSBBits = 256 - (fieldBase * (fieldWords - 1)) + + // fieldMSBMask is the mask for the bits in the most significant word + // needed to represent the value. + fieldMSBMask = (1 << fieldMSBBits) - 1 + + // These fields provide convenient access to each of the words of the + // secp256k1 prime in the internal field representation to improve code + // readability. + fieldPrimeWordZero = 0x03fffc2f + fieldPrimeWordOne = 0x03ffffbf + fieldPrimeWordTwo = 0x03ffffff + fieldPrimeWordThree = 0x03ffffff + fieldPrimeWordFour = 0x03ffffff + fieldPrimeWordFive = 0x03ffffff + fieldPrimeWordSix = 0x03ffffff + fieldPrimeWordSeven = 0x03ffffff + fieldPrimeWordEight = 0x03ffffff + fieldPrimeWordNine = 0x003fffff +) + +// FieldVal implements optimized fixed-precision arithmetic over the +// secp256k1 finite field. This means all arithmetic is performed modulo +// +// 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f. +// +// WARNING: Since it is so important for the field arithmetic to be extremely +// fast for high performance crypto, this type does not perform any validation +// of documented preconditions where it ordinarily would. As a result, it is +// IMPERATIVE for callers to understand some key concepts that are described +// below and ensure the methods are called with the necessary preconditions that +// each method is documented with. For example, some methods only give the +// correct result if the field value is normalized and others require the field +// values involved to have a maximum magnitude and THERE ARE NO EXPLICIT CHECKS +// TO ENSURE THOSE PRECONDITIONS ARE SATISFIED. This does, unfortunately, make +// the type more difficult to use correctly and while I typically prefer to +// ensure all state and input is valid for most code, this is a bit of an +// exception because those extra checks really add up in what ends up being +// critical hot paths. +// +// The first key concept when working with this type is normalization. In order +// to avoid the need to propagate a ton of carries, the internal representation +// provides additional overflow bits for each word of the overall 256-bit value. +// This means that there are multiple internal representations for the same +// value and, as a result, any methods that rely on comparison of the value, +// such as equality and oddness determination, require the caller to provide a +// normalized value. +// +// The second key concept when working with this type is magnitude. As +// previously mentioned, the internal representation provides additional +// overflow bits which means that the more math operations that are performed on +// the field value between normalizations, the more those overflow bits +// accumulate. The magnitude is effectively that maximum possible number of +// those overflow bits that could possibly be required as a result of a given +// operation. Since there are only a limited number of overflow bits available, +// this implies that the max possible magnitude MUST be tracked by the caller +// and the caller MUST normalize the field value if a given operation would +// cause the magnitude of the result to exceed the max allowed value. +// +// IMPORTANT: The max allowed magnitude of a field value is 32. +type FieldVal struct { + // Each 256-bit value is represented as 10 32-bit integers in base 2^26. + // This provides 6 bits of overflow in each word (10 bits in the most + // significant word) for a total of 64 bits of overflow (9*6 + 10 = 64). It + // only implements the arithmetic needed for elliptic curve operations. + // + // The following depicts the internal representation: + // ----------------------------------------------------------------- + // | n[9] | n[8] | ... | n[0] | + // | 32 bits available | 32 bits available | ... | 32 bits available | + // | 22 bits for value | 26 bits for value | ... | 26 bits for value | + // | 10 bits overflow | 6 bits overflow | ... | 6 bits overflow | + // | Mult: 2^(26*9) | Mult: 2^(26*8) | ... | Mult: 2^(26*0) | + // ----------------------------------------------------------------- + // + // For example, consider the number 2^49 + 1. It would be represented as: + // n[0] = 1 + // n[1] = 2^23 + // n[2..9] = 0 + // + // The full 256-bit value is then calculated by looping i from 9..0 and + // doing sum(n[i] * 2^(26i)) like so: + // n[9] * 2^(26*9) = 0 * 2^234 = 0 + // n[8] * 2^(26*8) = 0 * 2^208 = 0 + // ... + // n[1] * 2^(26*1) = 2^23 * 2^26 = 2^49 + // n[0] * 2^(26*0) = 1 * 2^0 = 1 + // Sum: 0 + 0 + ... + 2^49 + 1 = 2^49 + 1 + n [10]uint32 +} + +// String returns the field value as a normalized human-readable hex string. +// +// Preconditions: None +// Output Normalized: Field is not modified -- same as input value +// Output Max Magnitude: Field is not modified -- same as input value +func (f FieldVal) String() string { + // f is a copy, so it's safe to normalize it without mutating the original. + f.Normalize() + return hex.EncodeToString(f.Bytes()[:]) +} + +// Zero sets the field value to zero in constant time. A newly created field +// value is already set to zero. This function can be useful to clear an +// existing field value for reuse. +// +// Preconditions: None +// Output Normalized: Yes +// Output Max Magnitude: 1 +func (f *FieldVal) Zero() { + f.n[0] = 0 + f.n[1] = 0 + f.n[2] = 0 + f.n[3] = 0 + f.n[4] = 0 + f.n[5] = 0 + f.n[6] = 0 + f.n[7] = 0 + f.n[8] = 0 + f.n[9] = 0 +} + +// Set sets the field value equal to the passed value in constant time. The +// normalization and magnitude of the two fields will be identical. +// +// The field value is returned to support chaining. This enables syntax like: +// f := new(FieldVal).Set(f2).Add(1) so that f = f2 + 1 where f2 is not +// modified. +// +// Preconditions: None +// Output Normalized: Same as input value +// Output Max Magnitude: Same as input value +func (f *FieldVal) Set(val *FieldVal) *FieldVal { + *f = *val + return f +} + +// SetInt sets the field value to the passed integer in constant time. This is +// a convenience function since it is fairly common to perform some arithmetic +// with small native integers. +// +// The field value is returned to support chaining. This enables syntax such +// as f := new(FieldVal).SetInt(2).Mul(f2) so that f = 2 * f2. +// +// Preconditions: None +// Output Normalized: Yes +// Output Max Magnitude: 1 +func (f *FieldVal) SetInt(ui uint16) *FieldVal { + f.Zero() + f.n[0] = uint32(ui) + return f +} + +// SetBytes packs the passed 32-byte big-endian value into the internal field +// value representation in constant time. SetBytes interprets the provided +// array as a 256-bit big-endian unsigned integer, packs it into the internal +// field value representation, and returns either 1 if it is greater than or +// equal to the field prime (aka it overflowed) or 0 otherwise in constant time. +// +// Note that a bool is not used here because it is not possible in Go to convert +// from a bool to numeric value in constant time and many constant-time +// operations require a numeric value. +// +// Preconditions: None +// Output Normalized: Yes if no overflow, no otherwise +// Output Max Magnitude: 1 +func (f *FieldVal) SetBytes(b *[32]byte) uint32 { + // Pack the 256 total bits across the 10 uint32 words with a max of + // 26-bits per word. This could be done with a couple of for loops, + // but this unrolled version is significantly faster. Benchmarks show + // this is about 34 times faster than the variant which uses loops. + f.n[0] = uint32(b[31]) | uint32(b[30])<<8 | uint32(b[29])<<16 | + (uint32(b[28])&twoBitsMask)<<24 + f.n[1] = uint32(b[28])>>2 | uint32(b[27])<<6 | uint32(b[26])<<14 | + (uint32(b[25])&fourBitsMask)<<22 + f.n[2] = uint32(b[25])>>4 | uint32(b[24])<<4 | uint32(b[23])<<12 | + (uint32(b[22])&sixBitsMask)<<20 + f.n[3] = uint32(b[22])>>6 | uint32(b[21])<<2 | uint32(b[20])<<10 | + uint32(b[19])<<18 + f.n[4] = uint32(b[18]) | uint32(b[17])<<8 | uint32(b[16])<<16 | + (uint32(b[15])&twoBitsMask)<<24 + f.n[5] = uint32(b[15])>>2 | uint32(b[14])<<6 | uint32(b[13])<<14 | + (uint32(b[12])&fourBitsMask)<<22 + f.n[6] = uint32(b[12])>>4 | uint32(b[11])<<4 | uint32(b[10])<<12 | + (uint32(b[9])&sixBitsMask)<<20 + f.n[7] = uint32(b[9])>>6 | uint32(b[8])<<2 | uint32(b[7])<<10 | + uint32(b[6])<<18 + f.n[8] = uint32(b[5]) | uint32(b[4])<<8 | uint32(b[3])<<16 | + (uint32(b[2])&twoBitsMask)<<24 + f.n[9] = uint32(b[2])>>2 | uint32(b[1])<<6 | uint32(b[0])<<14 + + // The intuition here is that the field value is greater than the prime if + // one of the higher individual words is greater than corresponding word of + // the prime and all higher words in the field value are equal to their + // corresponding word of the prime. Since this type is modulo the prime, + // being equal is also an overflow back to 0. + // + // Note that because the input is 32 bytes and it was just packed into the + // field representation, the only words that can possibly be greater are + // zero and one, because ceil(log_2(2^256 - 1 - P)) = 33 bits max and the + // internal field representation encodes 26 bits with each word. + // + // Thus, there is no need to test if the upper words of the field value + // exceeds them, hence, only equality is checked for them. + highWordsEq := constantTimeEq(f.n[9], fieldPrimeWordNine) + highWordsEq &= constantTimeEq(f.n[8], fieldPrimeWordEight) + highWordsEq &= constantTimeEq(f.n[7], fieldPrimeWordSeven) + highWordsEq &= constantTimeEq(f.n[6], fieldPrimeWordSix) + highWordsEq &= constantTimeEq(f.n[5], fieldPrimeWordFive) + highWordsEq &= constantTimeEq(f.n[4], fieldPrimeWordFour) + highWordsEq &= constantTimeEq(f.n[3], fieldPrimeWordThree) + highWordsEq &= constantTimeEq(f.n[2], fieldPrimeWordTwo) + overflow := highWordsEq & constantTimeGreater(f.n[1], fieldPrimeWordOne) + highWordsEq &= constantTimeEq(f.n[1], fieldPrimeWordOne) + overflow |= highWordsEq & constantTimeGreaterOrEq(f.n[0], fieldPrimeWordZero) + + return overflow +} + +// SetByteSlice interprets the provided slice as a 256-bit big-endian unsigned +// integer (meaning it is truncated to the first 32 bytes), packs it into the +// internal field value representation, and returns whether or not the resulting +// truncated 256-bit integer is greater than or equal to the field prime (aka it +// overflowed) in constant time. +// +// Note that since passing a slice with more than 32 bytes is truncated, it is +// possible that the truncated value is less than the field prime and hence it +// will not be reported as having overflowed in that case. It is up to the +// caller to decide whether it needs to provide numbers of the appropriate size +// or it if is acceptable to use this function with the described truncation and +// overflow behavior. +// +// Preconditions: None +// Output Normalized: Yes if no overflow, no otherwise +// Output Max Magnitude: 1 +func (f *FieldVal) SetByteSlice(b []byte) bool { + var b32 [32]byte + b = b[:constantTimeMin(uint32(len(b)), 32)] + copy(b32[:], b32[:32-len(b)]) + copy(b32[32-len(b):], b) + result := f.SetBytes(&b32) + zeroArray32(&b32) + return result != 0 +} + +// Normalize normalizes the internal field words into the desired range and +// performs fast modular reduction over the secp256k1 prime by making use of the +// special form of the prime in constant time. +// +// Preconditions: None +// Output Normalized: Yes +// Output Max Magnitude: 1 +func (f *FieldVal) Normalize() *FieldVal { + // The field representation leaves 6 bits of overflow in each word so + // intermediate calculations can be performed without needing to + // propagate the carry to each higher word during the calculations. In + // order to normalize, we need to "compact" the full 256-bit value to + // the right while propagating any carries through to the high order + // word. + // + // Since this field is doing arithmetic modulo the secp256k1 prime, we + // also need to perform modular reduction over the prime. + // + // Per [HAC] section 14.3.4: Reduction method of moduli of special form, + // when the modulus is of the special form m = b^t - c, highly efficient + // reduction can be achieved. + // + // The secp256k1 prime is equivalent to 2^256 - 4294968273, so it fits + // this criteria. + // + // 4294968273 in field representation (base 2^26) is: + // n[0] = 977 + // n[1] = 64 + // That is to say (2^26 * 64) + 977 = 4294968273 + // + // The algorithm presented in the referenced section typically repeats + // until the quotient is zero. However, due to our field representation + // we already know to within one reduction how many times we would need + // to repeat as it's the uppermost bits of the high order word. Thus we + // can simply multiply the magnitude by the field representation of the + // prime and do a single iteration. After this step there might be an + // additional carry to bit 256 (bit 22 of the high order word). + t9 := f.n[9] + m := t9 >> fieldMSBBits + t9 &= fieldMSBMask + t0 := f.n[0] + m*977 + t1 := (t0 >> fieldBase) + f.n[1] + (m << 6) + t0 &= fieldBaseMask + t2 := (t1 >> fieldBase) + f.n[2] + t1 &= fieldBaseMask + t3 := (t2 >> fieldBase) + f.n[3] + t2 &= fieldBaseMask + t4 := (t3 >> fieldBase) + f.n[4] + t3 &= fieldBaseMask + t5 := (t4 >> fieldBase) + f.n[5] + t4 &= fieldBaseMask + t6 := (t5 >> fieldBase) + f.n[6] + t5 &= fieldBaseMask + t7 := (t6 >> fieldBase) + f.n[7] + t6 &= fieldBaseMask + t8 := (t7 >> fieldBase) + f.n[8] + t7 &= fieldBaseMask + t9 = (t8 >> fieldBase) + t9 + t8 &= fieldBaseMask + + // At this point, the magnitude is guaranteed to be one, however, the + // value could still be greater than the prime if there was either a + // carry through to bit 256 (bit 22 of the higher order word) or the + // value is greater than or equal to the field characteristic. The + // following determines if either or these conditions are true and does + // the final reduction in constant time. + // + // Also note that 'm' will be zero when neither of the aforementioned + // conditions are true and the value will not be changed when 'm' is zero. + m = constantTimeEq(t9, fieldMSBMask) + m &= constantTimeEq(t8&t7&t6&t5&t4&t3&t2, fieldBaseMask) + m &= constantTimeGreater(t1+64+((t0+977)>>fieldBase), fieldBaseMask) + m |= t9 >> fieldMSBBits + t0 += m * 977 + t1 = (t0 >> fieldBase) + t1 + (m << 6) + t0 &= fieldBaseMask + t2 = (t1 >> fieldBase) + t2 + t1 &= fieldBaseMask + t3 = (t2 >> fieldBase) + t3 + t2 &= fieldBaseMask + t4 = (t3 >> fieldBase) + t4 + t3 &= fieldBaseMask + t5 = (t4 >> fieldBase) + t5 + t4 &= fieldBaseMask + t6 = (t5 >> fieldBase) + t6 + t5 &= fieldBaseMask + t7 = (t6 >> fieldBase) + t7 + t6 &= fieldBaseMask + t8 = (t7 >> fieldBase) + t8 + t7 &= fieldBaseMask + t9 = (t8 >> fieldBase) + t9 + t8 &= fieldBaseMask + t9 &= fieldMSBMask // Remove potential multiple of 2^256. + + // Finally, set the normalized and reduced words. + f.n[0] = t0 + f.n[1] = t1 + f.n[2] = t2 + f.n[3] = t3 + f.n[4] = t4 + f.n[5] = t5 + f.n[6] = t6 + f.n[7] = t7 + f.n[8] = t8 + f.n[9] = t9 + return f +} + +// PutBytesUnchecked unpacks the field value to a 32-byte big-endian value +// directly into the passed byte slice in constant time. The target slice must +// have at least 32 bytes available or it will panic. +// +// There is a similar function, PutBytes, which unpacks the field value into a +// 32-byte array directly. This version is provided since it can be useful +// to write directly into part of a larger buffer without needing a separate +// allocation. +// +// Preconditions: +// - The field value MUST be normalized +// - The target slice MUST have at least 32 bytes available +func (f *FieldVal) PutBytesUnchecked(b []byte) { + // Unpack the 256 total bits from the 10 uint32 words with a max of + // 26-bits per word. This could be done with a couple of for loops, + // but this unrolled version is a bit faster. Benchmarks show this is + // about 10 times faster than the variant which uses loops. + b[31] = byte(f.n[0] & eightBitsMask) + b[30] = byte((f.n[0] >> 8) & eightBitsMask) + b[29] = byte((f.n[0] >> 16) & eightBitsMask) + b[28] = byte((f.n[0]>>24)&twoBitsMask | (f.n[1]&sixBitsMask)<<2) + b[27] = byte((f.n[1] >> 6) & eightBitsMask) + b[26] = byte((f.n[1] >> 14) & eightBitsMask) + b[25] = byte((f.n[1]>>22)&fourBitsMask | (f.n[2]&fourBitsMask)<<4) + b[24] = byte((f.n[2] >> 4) & eightBitsMask) + b[23] = byte((f.n[2] >> 12) & eightBitsMask) + b[22] = byte((f.n[2]>>20)&sixBitsMask | (f.n[3]&twoBitsMask)<<6) + b[21] = byte((f.n[3] >> 2) & eightBitsMask) + b[20] = byte((f.n[3] >> 10) & eightBitsMask) + b[19] = byte((f.n[3] >> 18) & eightBitsMask) + b[18] = byte(f.n[4] & eightBitsMask) + b[17] = byte((f.n[4] >> 8) & eightBitsMask) + b[16] = byte((f.n[4] >> 16) & eightBitsMask) + b[15] = byte((f.n[4]>>24)&twoBitsMask | (f.n[5]&sixBitsMask)<<2) + b[14] = byte((f.n[5] >> 6) & eightBitsMask) + b[13] = byte((f.n[5] >> 14) & eightBitsMask) + b[12] = byte((f.n[5]>>22)&fourBitsMask | (f.n[6]&fourBitsMask)<<4) + b[11] = byte((f.n[6] >> 4) & eightBitsMask) + b[10] = byte((f.n[6] >> 12) & eightBitsMask) + b[9] = byte((f.n[6]>>20)&sixBitsMask | (f.n[7]&twoBitsMask)<<6) + b[8] = byte((f.n[7] >> 2) & eightBitsMask) + b[7] = byte((f.n[7] >> 10) & eightBitsMask) + b[6] = byte((f.n[7] >> 18) & eightBitsMask) + b[5] = byte(f.n[8] & eightBitsMask) + b[4] = byte((f.n[8] >> 8) & eightBitsMask) + b[3] = byte((f.n[8] >> 16) & eightBitsMask) + b[2] = byte((f.n[8]>>24)&twoBitsMask | (f.n[9]&sixBitsMask)<<2) + b[1] = byte((f.n[9] >> 6) & eightBitsMask) + b[0] = byte((f.n[9] >> 14) & eightBitsMask) +} + +// PutBytes unpacks the field value to a 32-byte big-endian value using the +// passed byte array in constant time. +// +// There is a similar function, PutBytesUnchecked, which unpacks the field value +// into a slice that must have at least 32 bytes available. This version is +// provided since it can be useful to write directly into an array that is type +// checked. +// +// Alternatively, there is also Bytes, which unpacks the field value into a new +// array and returns that which can sometimes be more ergonomic in applications +// that aren't concerned about an additional copy. +// +// Preconditions: +// - The field value MUST be normalized +func (f *FieldVal) PutBytes(b *[32]byte) { + f.PutBytesUnchecked(b[:]) +} + +// Bytes unpacks the field value to a 32-byte big-endian value in constant time. +// +// See PutBytes and PutBytesUnchecked for variants that allow an array or slice +// to be passed which can be useful to cut down on the number of allocations by +// allowing the caller to reuse a buffer or write directly into part of a larger +// buffer. +// +// Preconditions: +// - The field value MUST be normalized +func (f *FieldVal) Bytes() *[32]byte { + b := new([32]byte) + f.PutBytesUnchecked(b[:]) + return b +} + +// IsZeroBit returns 1 when the field value is equal to zero or 0 otherwise in +// constant time. +// +// Note that a bool is not used here because it is not possible in Go to convert +// from a bool to numeric value in constant time and many constant-time +// operations require a numeric value. See IsZero for the version that returns +// a bool. +// +// Preconditions: +// - The field value MUST be normalized +func (f *FieldVal) IsZeroBit() uint32 { + // The value can only be zero if no bits are set in any of the words. + // This is a constant time implementation. + bits := f.n[0] | f.n[1] | f.n[2] | f.n[3] | f.n[4] | + f.n[5] | f.n[6] | f.n[7] | f.n[8] | f.n[9] + + return constantTimeEq(bits, 0) +} + +// IsZero returns whether or not the field value is equal to zero in constant +// time. +// +// Preconditions: +// - The field value MUST be normalized +func (f *FieldVal) IsZero() bool { + // The value can only be zero if no bits are set in any of the words. + // This is a constant time implementation. + bits := f.n[0] | f.n[1] | f.n[2] | f.n[3] | f.n[4] | + f.n[5] | f.n[6] | f.n[7] | f.n[8] | f.n[9] + + return bits == 0 +} + +// IsOneBit returns 1 when the field value is equal to one or 0 otherwise in +// constant time. +// +// Note that a bool is not used here because it is not possible in Go to convert +// from a bool to numeric value in constant time and many constant-time +// operations require a numeric value. See IsOne for the version that returns a +// bool. +// +// Preconditions: +// - The field value MUST be normalized +func (f *FieldVal) IsOneBit() uint32 { + // The value can only be one if the single lowest significant bit is set in + // the first word and no other bits are set in any of the other words. + // This is a constant time implementation. + bits := (f.n[0] ^ 1) | f.n[1] | f.n[2] | f.n[3] | f.n[4] | f.n[5] | + f.n[6] | f.n[7] | f.n[8] | f.n[9] + + return constantTimeEq(bits, 0) +} + +// IsOne returns whether or not the field value is equal to one in constant +// time. +// +// Preconditions: +// - The field value MUST be normalized +func (f *FieldVal) IsOne() bool { + // The value can only be one if the single lowest significant bit is set in + // the first word and no other bits are set in any of the other words. + // This is a constant time implementation. + bits := (f.n[0] ^ 1) | f.n[1] | f.n[2] | f.n[3] | f.n[4] | f.n[5] | + f.n[6] | f.n[7] | f.n[8] | f.n[9] + + return bits == 0 +} + +// IsOddBit returns 1 when the field value is an odd number or 0 otherwise in +// constant time. +// +// Note that a bool is not used here because it is not possible in Go to convert +// from a bool to numeric value in constant time and many constant-time +// operations require a numeric value. See IsOdd for the version that returns a +// bool. +// +// Preconditions: +// - The field value MUST be normalized +func (f *FieldVal) IsOddBit() uint32 { + // Only odd numbers have the bottom bit set. + return f.n[0] & 1 +} + +// IsOdd returns whether or not the field value is an odd number in constant +// time. +// +// Preconditions: +// - The field value MUST be normalized +func (f *FieldVal) IsOdd() bool { + // Only odd numbers have the bottom bit set. + return f.n[0]&1 == 1 +} + +// Equals returns whether or not the two field values are the same in constant +// time. +// +// Preconditions: +// - Both field values being compared MUST be normalized +func (f *FieldVal) Equals(val *FieldVal) bool { + // Xor only sets bits when they are different, so the two field values + // can only be the same if no bits are set after xoring each word. + // This is a constant time implementation. + bits := (f.n[0] ^ val.n[0]) | (f.n[1] ^ val.n[1]) | (f.n[2] ^ val.n[2]) | + (f.n[3] ^ val.n[3]) | (f.n[4] ^ val.n[4]) | (f.n[5] ^ val.n[5]) | + (f.n[6] ^ val.n[6]) | (f.n[7] ^ val.n[7]) | (f.n[8] ^ val.n[8]) | + (f.n[9] ^ val.n[9]) + + return bits == 0 +} + +// NegateVal negates the passed value and stores the result in f in constant +// time. The caller must provide the maximum magnitude of the passed value for +// a correct result. +// +// The field value is returned to support chaining. This enables syntax like: +// f.NegateVal(f2).AddInt(1) so that f = -f2 + 1. +// +// Preconditions: +// - The max magnitude MUST be 31 +// Output Normalized: No +// Output Max Magnitude: Input magnitude + 1 +func (f *FieldVal) NegateVal(val *FieldVal, magnitude uint32) *FieldVal { + // Negation in the field is just the prime minus the value. However, + // in order to allow negation against a field value without having to + // normalize/reduce it first, multiply by the magnitude (that is how + // "far" away it is from the normalized value) to adjust. Also, since + // negating a value pushes it one more order of magnitude away from the + // normalized range, add 1 to compensate. + // + // For some intuition here, imagine you're performing mod 12 arithmetic + // (picture a clock) and you are negating the number 7. So you start at + // 12 (which is of course 0 under mod 12) and count backwards (left on + // the clock) 7 times to arrive at 5. Notice this is just 12-7 = 5. + // Now, assume you're starting with 19, which is a number that is + // already larger than the modulus and congruent to 7 (mod 12). When a + // value is already in the desired range, its magnitude is 1. Since 19 + // is an additional "step", its magnitude (mod 12) is 2. Since any + // multiple of the modulus is congruent to zero (mod m), the answer can + // be shortcut by simply multiplying the magnitude by the modulus and + // subtracting. Keeping with the example, this would be (2*12)-19 = 5. + f.n[0] = (magnitude+1)*fieldPrimeWordZero - val.n[0] + f.n[1] = (magnitude+1)*fieldPrimeWordOne - val.n[1] + f.n[2] = (magnitude+1)*fieldBaseMask - val.n[2] + f.n[3] = (magnitude+1)*fieldBaseMask - val.n[3] + f.n[4] = (magnitude+1)*fieldBaseMask - val.n[4] + f.n[5] = (magnitude+1)*fieldBaseMask - val.n[5] + f.n[6] = (magnitude+1)*fieldBaseMask - val.n[6] + f.n[7] = (magnitude+1)*fieldBaseMask - val.n[7] + f.n[8] = (magnitude+1)*fieldBaseMask - val.n[8] + f.n[9] = (magnitude+1)*fieldMSBMask - val.n[9] + + return f +} + +// Negate negates the field value in constant time. The existing field value is +// modified. The caller must provide the maximum magnitude of the field value +// for a correct result. +// +// The field value is returned to support chaining. This enables syntax like: +// f.Negate().AddInt(1) so that f = -f + 1. +// +// Preconditions: +// - The max magnitude MUST be 31 +// Output Normalized: No +// Output Max Magnitude: Input magnitude + 1 +func (f *FieldVal) Negate(magnitude uint32) *FieldVal { + return f.NegateVal(f, magnitude) +} + +// AddInt adds the passed integer to the existing field value and stores the +// result in f in constant time. This is a convenience function since it is +// fairly common to perform some arithmetic with small native integers. +// +// The field value is returned to support chaining. This enables syntax like: +// f.AddInt(1).Add(f2) so that f = f + 1 + f2. +// +// Preconditions: +// - The field value MUST have a max magnitude of 31 +// - The integer MUST be a max of 32767 +// Output Normalized: No +// Output Max Magnitude: Existing field magnitude + 1 +func (f *FieldVal) AddInt(ui uint16) *FieldVal { + // Since the field representation intentionally provides overflow bits, + // it's ok to use carryless addition as the carry bit is safely part of + // the word and will be normalized out. + f.n[0] += uint32(ui) + + return f +} + +// Add adds the passed value to the existing field value and stores the result +// in f in constant time. +// +// The field value is returned to support chaining. This enables syntax like: +// f.Add(f2).AddInt(1) so that f = f + f2 + 1. +// +// Preconditions: +// - The sum of the magnitudes of the two field values MUST be a max of 32 +// Output Normalized: No +// Output Max Magnitude: Sum of the magnitude of the two individual field values +func (f *FieldVal) Add(val *FieldVal) *FieldVal { + // Since the field representation intentionally provides overflow bits, + // it's ok to use carryless addition as the carry bit is safely part of + // each word and will be normalized out. This could obviously be done + // in a loop, but the unrolled version is faster. + f.n[0] += val.n[0] + f.n[1] += val.n[1] + f.n[2] += val.n[2] + f.n[3] += val.n[3] + f.n[4] += val.n[4] + f.n[5] += val.n[5] + f.n[6] += val.n[6] + f.n[7] += val.n[7] + f.n[8] += val.n[8] + f.n[9] += val.n[9] + + return f +} + +// Add2 adds the passed two field values together and stores the result in f in +// constant time. +// +// The field value is returned to support chaining. This enables syntax like: +// f3.Add2(f, f2).AddInt(1) so that f3 = f + f2 + 1. +// +// Preconditions: +// - The sum of the magnitudes of the two field values MUST be a max of 32 +// Output Normalized: No +// Output Max Magnitude: Sum of the magnitude of the two field values +func (f *FieldVal) Add2(val *FieldVal, val2 *FieldVal) *FieldVal { + // Since the field representation intentionally provides overflow bits, + // it's ok to use carryless addition as the carry bit is safely part of + // each word and will be normalized out. This could obviously be done + // in a loop, but the unrolled version is faster. + f.n[0] = val.n[0] + val2.n[0] + f.n[1] = val.n[1] + val2.n[1] + f.n[2] = val.n[2] + val2.n[2] + f.n[3] = val.n[3] + val2.n[3] + f.n[4] = val.n[4] + val2.n[4] + f.n[5] = val.n[5] + val2.n[5] + f.n[6] = val.n[6] + val2.n[6] + f.n[7] = val.n[7] + val2.n[7] + f.n[8] = val.n[8] + val2.n[8] + f.n[9] = val.n[9] + val2.n[9] + + return f +} + +// MulInt multiplies the field value by the passed int and stores the result in +// f in constant time. Note that this function can overflow if multiplying the +// value by any of the individual words exceeds a max uint32. Therefore it is +// important that the caller ensures no overflows will occur before using this +// function. +// +// The field value is returned to support chaining. This enables syntax like: +// f.MulInt(2).Add(f2) so that f = 2 * f + f2. +// +// Preconditions: +// - The field value magnitude multiplied by given val MUST be a max of 32 +// Output Normalized: No +// Output Max Magnitude: Existing field magnitude times the provided integer val +func (f *FieldVal) MulInt(val uint8) *FieldVal { + // Since each word of the field representation can hold up to + // 32 - fieldBase extra bits which will be normalized out, it's safe + // to multiply each word without using a larger type or carry + // propagation so long as the values won't overflow a uint32. This + // could obviously be done in a loop, but the unrolled version is + // faster. + ui := uint32(val) + f.n[0] *= ui + f.n[1] *= ui + f.n[2] *= ui + f.n[3] *= ui + f.n[4] *= ui + f.n[5] *= ui + f.n[6] *= ui + f.n[7] *= ui + f.n[8] *= ui + f.n[9] *= ui + + return f +} + +// Mul multiplies the passed value to the existing field value and stores the +// result in f in constant time. Note that this function can overflow if +// multiplying any of the individual words exceeds a max uint32. In practice, +// this means the magnitude of either value involved in the multiplication must +// be a max of 8. +// +// The field value is returned to support chaining. This enables syntax like: +// f.Mul(f2).AddInt(1) so that f = (f * f2) + 1. +// +// Preconditions: +// - Both field values MUST have a max magnitude of 8 +// Output Normalized: No +// Output Max Magnitude: 1 +func (f *FieldVal) Mul(val *FieldVal) *FieldVal { + return f.Mul2(f, val) +} + +// Mul2 multiplies the passed two field values together and stores the result in +// f in constant time. Note that this function can overflow if multiplying any +// of the individual words exceeds a max uint32. In practice, this means the +// magnitude of either value involved in the multiplication must be a max of 8. +// +// The field value is returned to support chaining. This enables syntax like: +// f3.Mul2(f, f2).AddInt(1) so that f3 = (f * f2) + 1. +// +// Preconditions: +// - Both input field values MUST have a max magnitude of 8 +// Output Normalized: No +// Output Max Magnitude: 1 +func (f *FieldVal) Mul2(val *FieldVal, val2 *FieldVal) *FieldVal { + // This could be done with a couple of for loops and an array to store + // the intermediate terms, but this unrolled version is significantly + // faster. + + // Terms for 2^(fieldBase*0). + m := uint64(val.n[0]) * uint64(val2.n[0]) + t0 := m & fieldBaseMask + + // Terms for 2^(fieldBase*1). + m = (m >> fieldBase) + + uint64(val.n[0])*uint64(val2.n[1]) + + uint64(val.n[1])*uint64(val2.n[0]) + t1 := m & fieldBaseMask + + // Terms for 2^(fieldBase*2). + m = (m >> fieldBase) + + uint64(val.n[0])*uint64(val2.n[2]) + + uint64(val.n[1])*uint64(val2.n[1]) + + uint64(val.n[2])*uint64(val2.n[0]) + t2 := m & fieldBaseMask + + // Terms for 2^(fieldBase*3). + m = (m >> fieldBase) + + uint64(val.n[0])*uint64(val2.n[3]) + + uint64(val.n[1])*uint64(val2.n[2]) + + uint64(val.n[2])*uint64(val2.n[1]) + + uint64(val.n[3])*uint64(val2.n[0]) + t3 := m & fieldBaseMask + + // Terms for 2^(fieldBase*4). + m = (m >> fieldBase) + + uint64(val.n[0])*uint64(val2.n[4]) + + uint64(val.n[1])*uint64(val2.n[3]) + + uint64(val.n[2])*uint64(val2.n[2]) + + uint64(val.n[3])*uint64(val2.n[1]) + + uint64(val.n[4])*uint64(val2.n[0]) + t4 := m & fieldBaseMask + + // Terms for 2^(fieldBase*5). + m = (m >> fieldBase) + + uint64(val.n[0])*uint64(val2.n[5]) + + uint64(val.n[1])*uint64(val2.n[4]) + + uint64(val.n[2])*uint64(val2.n[3]) + + uint64(val.n[3])*uint64(val2.n[2]) + + uint64(val.n[4])*uint64(val2.n[1]) + + uint64(val.n[5])*uint64(val2.n[0]) + t5 := m & fieldBaseMask + + // Terms for 2^(fieldBase*6). + m = (m >> fieldBase) + + uint64(val.n[0])*uint64(val2.n[6]) + + uint64(val.n[1])*uint64(val2.n[5]) + + uint64(val.n[2])*uint64(val2.n[4]) + + uint64(val.n[3])*uint64(val2.n[3]) + + uint64(val.n[4])*uint64(val2.n[2]) + + uint64(val.n[5])*uint64(val2.n[1]) + + uint64(val.n[6])*uint64(val2.n[0]) + t6 := m & fieldBaseMask + + // Terms for 2^(fieldBase*7). + m = (m >> fieldBase) + + uint64(val.n[0])*uint64(val2.n[7]) + + uint64(val.n[1])*uint64(val2.n[6]) + + uint64(val.n[2])*uint64(val2.n[5]) + + uint64(val.n[3])*uint64(val2.n[4]) + + uint64(val.n[4])*uint64(val2.n[3]) + + uint64(val.n[5])*uint64(val2.n[2]) + + uint64(val.n[6])*uint64(val2.n[1]) + + uint64(val.n[7])*uint64(val2.n[0]) + t7 := m & fieldBaseMask + + // Terms for 2^(fieldBase*8). + m = (m >> fieldBase) + + uint64(val.n[0])*uint64(val2.n[8]) + + uint64(val.n[1])*uint64(val2.n[7]) + + uint64(val.n[2])*uint64(val2.n[6]) + + uint64(val.n[3])*uint64(val2.n[5]) + + uint64(val.n[4])*uint64(val2.n[4]) + + uint64(val.n[5])*uint64(val2.n[3]) + + uint64(val.n[6])*uint64(val2.n[2]) + + uint64(val.n[7])*uint64(val2.n[1]) + + uint64(val.n[8])*uint64(val2.n[0]) + t8 := m & fieldBaseMask + + // Terms for 2^(fieldBase*9). + m = (m >> fieldBase) + + uint64(val.n[0])*uint64(val2.n[9]) + + uint64(val.n[1])*uint64(val2.n[8]) + + uint64(val.n[2])*uint64(val2.n[7]) + + uint64(val.n[3])*uint64(val2.n[6]) + + uint64(val.n[4])*uint64(val2.n[5]) + + uint64(val.n[5])*uint64(val2.n[4]) + + uint64(val.n[6])*uint64(val2.n[3]) + + uint64(val.n[7])*uint64(val2.n[2]) + + uint64(val.n[8])*uint64(val2.n[1]) + + uint64(val.n[9])*uint64(val2.n[0]) + t9 := m & fieldBaseMask + + // Terms for 2^(fieldBase*10). + m = (m >> fieldBase) + + uint64(val.n[1])*uint64(val2.n[9]) + + uint64(val.n[2])*uint64(val2.n[8]) + + uint64(val.n[3])*uint64(val2.n[7]) + + uint64(val.n[4])*uint64(val2.n[6]) + + uint64(val.n[5])*uint64(val2.n[5]) + + uint64(val.n[6])*uint64(val2.n[4]) + + uint64(val.n[7])*uint64(val2.n[3]) + + uint64(val.n[8])*uint64(val2.n[2]) + + uint64(val.n[9])*uint64(val2.n[1]) + t10 := m & fieldBaseMask + + // Terms for 2^(fieldBase*11). + m = (m >> fieldBase) + + uint64(val.n[2])*uint64(val2.n[9]) + + uint64(val.n[3])*uint64(val2.n[8]) + + uint64(val.n[4])*uint64(val2.n[7]) + + uint64(val.n[5])*uint64(val2.n[6]) + + uint64(val.n[6])*uint64(val2.n[5]) + + uint64(val.n[7])*uint64(val2.n[4]) + + uint64(val.n[8])*uint64(val2.n[3]) + + uint64(val.n[9])*uint64(val2.n[2]) + t11 := m & fieldBaseMask + + // Terms for 2^(fieldBase*12). + m = (m >> fieldBase) + + uint64(val.n[3])*uint64(val2.n[9]) + + uint64(val.n[4])*uint64(val2.n[8]) + + uint64(val.n[5])*uint64(val2.n[7]) + + uint64(val.n[6])*uint64(val2.n[6]) + + uint64(val.n[7])*uint64(val2.n[5]) + + uint64(val.n[8])*uint64(val2.n[4]) + + uint64(val.n[9])*uint64(val2.n[3]) + t12 := m & fieldBaseMask + + // Terms for 2^(fieldBase*13). + m = (m >> fieldBase) + + uint64(val.n[4])*uint64(val2.n[9]) + + uint64(val.n[5])*uint64(val2.n[8]) + + uint64(val.n[6])*uint64(val2.n[7]) + + uint64(val.n[7])*uint64(val2.n[6]) + + uint64(val.n[8])*uint64(val2.n[5]) + + uint64(val.n[9])*uint64(val2.n[4]) + t13 := m & fieldBaseMask + + // Terms for 2^(fieldBase*14). + m = (m >> fieldBase) + + uint64(val.n[5])*uint64(val2.n[9]) + + uint64(val.n[6])*uint64(val2.n[8]) + + uint64(val.n[7])*uint64(val2.n[7]) + + uint64(val.n[8])*uint64(val2.n[6]) + + uint64(val.n[9])*uint64(val2.n[5]) + t14 := m & fieldBaseMask + + // Terms for 2^(fieldBase*15). + m = (m >> fieldBase) + + uint64(val.n[6])*uint64(val2.n[9]) + + uint64(val.n[7])*uint64(val2.n[8]) + + uint64(val.n[8])*uint64(val2.n[7]) + + uint64(val.n[9])*uint64(val2.n[6]) + t15 := m & fieldBaseMask + + // Terms for 2^(fieldBase*16). + m = (m >> fieldBase) + + uint64(val.n[7])*uint64(val2.n[9]) + + uint64(val.n[8])*uint64(val2.n[8]) + + uint64(val.n[9])*uint64(val2.n[7]) + t16 := m & fieldBaseMask + + // Terms for 2^(fieldBase*17). + m = (m >> fieldBase) + + uint64(val.n[8])*uint64(val2.n[9]) + + uint64(val.n[9])*uint64(val2.n[8]) + t17 := m & fieldBaseMask + + // Terms for 2^(fieldBase*18). + m = (m >> fieldBase) + uint64(val.n[9])*uint64(val2.n[9]) + t18 := m & fieldBaseMask + + // What's left is for 2^(fieldBase*19). + t19 := m >> fieldBase + + // At this point, all of the terms are grouped into their respective + // base. + // + // Per [HAC] section 14.3.4: Reduction method of moduli of special form, + // when the modulus is of the special form m = b^t - c, highly efficient + // reduction can be achieved per the provided algorithm. + // + // The secp256k1 prime is equivalent to 2^256 - 4294968273, so it fits + // this criteria. + // + // 4294968273 in field representation (base 2^26) is: + // n[0] = 977 + // n[1] = 64 + // That is to say (2^26 * 64) + 977 = 4294968273 + // + // Since each word is in base 26, the upper terms (t10 and up) start + // at 260 bits (versus the final desired range of 256 bits), so the + // field representation of 'c' from above needs to be adjusted for the + // extra 4 bits by multiplying it by 2^4 = 16. 4294968273 * 16 = + // 68719492368. Thus, the adjusted field representation of 'c' is: + // n[0] = 977 * 16 = 15632 + // n[1] = 64 * 16 = 1024 + // That is to say (2^26 * 1024) + 15632 = 68719492368 + // + // To reduce the final term, t19, the entire 'c' value is needed instead + // of only n[0] because there are no more terms left to handle n[1]. + // This means there might be some magnitude left in the upper bits that + // is handled below. + m = t0 + t10*15632 + t0 = m & fieldBaseMask + m = (m >> fieldBase) + t1 + t10*1024 + t11*15632 + t1 = m & fieldBaseMask + m = (m >> fieldBase) + t2 + t11*1024 + t12*15632 + t2 = m & fieldBaseMask + m = (m >> fieldBase) + t3 + t12*1024 + t13*15632 + t3 = m & fieldBaseMask + m = (m >> fieldBase) + t4 + t13*1024 + t14*15632 + t4 = m & fieldBaseMask + m = (m >> fieldBase) + t5 + t14*1024 + t15*15632 + t5 = m & fieldBaseMask + m = (m >> fieldBase) + t6 + t15*1024 + t16*15632 + t6 = m & fieldBaseMask + m = (m >> fieldBase) + t7 + t16*1024 + t17*15632 + t7 = m & fieldBaseMask + m = (m >> fieldBase) + t8 + t17*1024 + t18*15632 + t8 = m & fieldBaseMask + m = (m >> fieldBase) + t9 + t18*1024 + t19*68719492368 + t9 = m & fieldMSBMask + m >>= fieldMSBBits + + // At this point, if the magnitude is greater than 0, the overall value + // is greater than the max possible 256-bit value. In particular, it is + // "how many times larger" than the max value it is. + // + // The algorithm presented in [HAC] section 14.3.4 repeats until the + // quotient is zero. However, due to the above, we already know at + // least how many times we would need to repeat as it's the value + // currently in m. Thus we can simply multiply the magnitude by the + // field representation of the prime and do a single iteration. Notice + // that nothing will be changed when the magnitude is zero, so we could + // skip this in that case, however always running regardless allows it + // to run in constant time. The final result will be in the range + // 0 <= result <= prime + (2^64 - c), so it is guaranteed to have a + // magnitude of 1, but it is denormalized. + d := t0 + m*977 + f.n[0] = uint32(d & fieldBaseMask) + d = (d >> fieldBase) + t1 + m*64 + f.n[1] = uint32(d & fieldBaseMask) + f.n[2] = uint32((d >> fieldBase) + t2) + f.n[3] = uint32(t3) + f.n[4] = uint32(t4) + f.n[5] = uint32(t5) + f.n[6] = uint32(t6) + f.n[7] = uint32(t7) + f.n[8] = uint32(t8) + f.n[9] = uint32(t9) + + return f +} + +// SquareRootVal either calculates the square root of the passed value when it +// exists or the square root of the negation of the value when it does not exist +// and stores the result in f in constant time. The return flag is true when +// the calculated square root is for the passed value itself and false when it +// is for its negation. +// +// Note that this function can overflow if multiplying any of the individual +// words exceeds a max uint32. In practice, this means the magnitude of the +// field must be a max of 8 to prevent overflow. The magnitude of the result +// will be 1. +// +// Preconditions: +// - The input field value MUST have a max magnitude of 8 +// Output Normalized: No +// Output Max Magnitude: 1 +func (f *FieldVal) SquareRootVal(val *FieldVal) bool { + // This uses the Tonelli-Shanks method for calculating the square root of + // the value when it exists. The key principles of the method follow. + // + // Fermat's little theorem states that for a nonzero number 'a' and prime + // 'p', a^(p-1) ≡ 1 (mod p). + // + // Further, Euler's criterion states that an integer 'a' has a square root + // (aka is a quadratic residue) modulo a prime if a^((p-1)/2) ≡ 1 (mod p) + // and, conversely, when it does NOT have a square root (aka 'a' is a + // non-residue) a^((p-1)/2) ≡ -1 (mod p). + // + // This can be seen by considering that Fermat's little theorem can be + // written as (a^((p-1)/2) - 1)(a^((p-1)/2) + 1) ≡ 0 (mod p). Therefore, + // one of the two factors must be 0. Then, when a ≡ x^2 (aka 'a' is a + // quadratic residue), (x^2)^((p-1)/2) ≡ x^(p-1) ≡ 1 (mod p) which implies + // the first factor must be zero. Finally, per Lagrange's theorem, the + // non-residues are the only remaining possible solutions and thus must make + // the second factor zero to satisfy Fermat's little theorem implying that + // a^((p-1)/2) ≡ -1 (mod p) for that case. + // + // The Tonelli-Shanks method uses these facts along with factoring out + // powers of two to solve a congruence that results in either the solution + // when the square root exists or the square root of the negation of the + // value when it does not. In the case of primes that are ≡ 3 (mod 4), the + // possible solutions are r = ±a^((p+1)/4) (mod p). Therefore, either r^2 ≡ + // a (mod p) is true in which case ±r are the two solutions, or r^2 ≡ -a + // (mod p) in which case 'a' is a non-residue and there are no solutions. + // + // The secp256k1 prime is ≡ 3 (mod 4), so this result applies. + // + // In other words, calculate a^((p+1)/4) and then square it and check it + // against the original value to determine if it is actually the square + // root. + // + // In order to efficiently compute a^((p+1)/4), (p+1)/4 needs to be split + // into a sequence of squares and multiplications that minimizes the number + // of multiplications needed (since they are more costly than squarings). + // + // The secp256k1 prime + 1 / 4 is 2^254 - 2^30 - 244. In binary, that is: + // + // 00111111 11111111 11111111 11111111 + // 11111111 11111111 11111111 11111111 + // 11111111 11111111 11111111 11111111 + // 11111111 11111111 11111111 11111111 + // 11111111 11111111 11111111 11111111 + // 11111111 11111111 11111111 11111111 + // 11111111 11111111 11111111 11111111 + // 10111111 11111111 11111111 00001100 + // + // Notice that can be broken up into three windows of consecutive 1s (in + // order of least to most significant) as: + // + // 6-bit window with two bits set (bits 4, 5, 6, 7 unset) + // 23-bit window with 22 bits set (bit 30 unset) + // 223-bit window with all 223 bits set + // + // Thus, the groups of 1 bits in each window forms the set: + // S = {2, 22, 223}. + // + // The strategy is to calculate a^(2^n - 1) for each grouping via an + // addition chain with a sliding window. + // + // The addition chain used is (credits to Peter Dettman): + // (0,0),(1,0),(2,2),(3,2),(4,1),(5,5),(6,6),(7,7),(8,8),(9,7),(10,2) + // => 2^1 2^[2] 2^3 2^6 2^9 2^11 2^[22] 2^44 2^88 2^176 2^220 2^[223] + // + // This has a cost of 254 field squarings and 13 field multiplications. + var a, a2, a3, a6, a9, a11, a22, a44, a88, a176, a220, a223 FieldVal + a.Set(val) + a2.SquareVal(&a).Mul(&a) // a2 = a^(2^2 - 1) + a3.SquareVal(&a2).Mul(&a) // a3 = a^(2^3 - 1) + a6.SquareVal(&a3).Square().Square() // a6 = a^(2^6 - 2^3) + a6.Mul(&a3) // a6 = a^(2^6 - 1) + a9.SquareVal(&a6).Square().Square() // a9 = a^(2^9 - 2^3) + a9.Mul(&a3) // a9 = a^(2^9 - 1) + a11.SquareVal(&a9).Square() // a11 = a^(2^11 - 2^2) + a11.Mul(&a2) // a11 = a^(2^11 - 1) + a22.SquareVal(&a11).Square().Square().Square().Square() // a22 = a^(2^16 - 2^5) + a22.Square().Square().Square().Square().Square() // a22 = a^(2^21 - 2^10) + a22.Square() // a22 = a^(2^22 - 2^11) + a22.Mul(&a11) // a22 = a^(2^22 - 1) + a44.SquareVal(&a22).Square().Square().Square().Square() // a44 = a^(2^27 - 2^5) + a44.Square().Square().Square().Square().Square() // a44 = a^(2^32 - 2^10) + a44.Square().Square().Square().Square().Square() // a44 = a^(2^37 - 2^15) + a44.Square().Square().Square().Square().Square() // a44 = a^(2^42 - 2^20) + a44.Square().Square() // a44 = a^(2^44 - 2^22) + a44.Mul(&a22) // a44 = a^(2^44 - 1) + a88.SquareVal(&a44).Square().Square().Square().Square() // a88 = a^(2^49 - 2^5) + a88.Square().Square().Square().Square().Square() // a88 = a^(2^54 - 2^10) + a88.Square().Square().Square().Square().Square() // a88 = a^(2^59 - 2^15) + a88.Square().Square().Square().Square().Square() // a88 = a^(2^64 - 2^20) + a88.Square().Square().Square().Square().Square() // a88 = a^(2^69 - 2^25) + a88.Square().Square().Square().Square().Square() // a88 = a^(2^74 - 2^30) + a88.Square().Square().Square().Square().Square() // a88 = a^(2^79 - 2^35) + a88.Square().Square().Square().Square().Square() // a88 = a^(2^84 - 2^40) + a88.Square().Square().Square().Square() // a88 = a^(2^88 - 2^44) + a88.Mul(&a44) // a88 = a^(2^88 - 1) + a176.SquareVal(&a88).Square().Square().Square().Square() // a176 = a^(2^93 - 2^5) + a176.Square().Square().Square().Square().Square() // a176 = a^(2^98 - 2^10) + a176.Square().Square().Square().Square().Square() // a176 = a^(2^103 - 2^15) + a176.Square().Square().Square().Square().Square() // a176 = a^(2^108 - 2^20) + a176.Square().Square().Square().Square().Square() // a176 = a^(2^113 - 2^25) + a176.Square().Square().Square().Square().Square() // a176 = a^(2^118 - 2^30) + a176.Square().Square().Square().Square().Square() // a176 = a^(2^123 - 2^35) + a176.Square().Square().Square().Square().Square() // a176 = a^(2^128 - 2^40) + a176.Square().Square().Square().Square().Square() // a176 = a^(2^133 - 2^45) + a176.Square().Square().Square().Square().Square() // a176 = a^(2^138 - 2^50) + a176.Square().Square().Square().Square().Square() // a176 = a^(2^143 - 2^55) + a176.Square().Square().Square().Square().Square() // a176 = a^(2^148 - 2^60) + a176.Square().Square().Square().Square().Square() // a176 = a^(2^153 - 2^65) + a176.Square().Square().Square().Square().Square() // a176 = a^(2^158 - 2^70) + a176.Square().Square().Square().Square().Square() // a176 = a^(2^163 - 2^75) + a176.Square().Square().Square().Square().Square() // a176 = a^(2^168 - 2^80) + a176.Square().Square().Square().Square().Square() // a176 = a^(2^173 - 2^85) + a176.Square().Square().Square() // a176 = a^(2^176 - 2^88) + a176.Mul(&a88) // a176 = a^(2^176 - 1) + a220.SquareVal(&a176).Square().Square().Square().Square() // a220 = a^(2^181 - 2^5) + a220.Square().Square().Square().Square().Square() // a220 = a^(2^186 - 2^10) + a220.Square().Square().Square().Square().Square() // a220 = a^(2^191 - 2^15) + a220.Square().Square().Square().Square().Square() // a220 = a^(2^196 - 2^20) + a220.Square().Square().Square().Square().Square() // a220 = a^(2^201 - 2^25) + a220.Square().Square().Square().Square().Square() // a220 = a^(2^206 - 2^30) + a220.Square().Square().Square().Square().Square() // a220 = a^(2^211 - 2^35) + a220.Square().Square().Square().Square().Square() // a220 = a^(2^216 - 2^40) + a220.Square().Square().Square().Square() // a220 = a^(2^220 - 2^44) + a220.Mul(&a44) // a220 = a^(2^220 - 1) + a223.SquareVal(&a220).Square().Square() // a223 = a^(2^223 - 2^3) + a223.Mul(&a3) // a223 = a^(2^223 - 1) + + f.SquareVal(&a223).Square().Square().Square().Square() // f = a^(2^228 - 2^5) + f.Square().Square().Square().Square().Square() // f = a^(2^233 - 2^10) + f.Square().Square().Square().Square().Square() // f = a^(2^238 - 2^15) + f.Square().Square().Square().Square().Square() // f = a^(2^243 - 2^20) + f.Square().Square().Square() // f = a^(2^246 - 2^23) + f.Mul(&a22) // f = a^(2^246 - 2^22 - 1) + f.Square().Square().Square().Square().Square() // f = a^(2^251 - 2^27 - 2^5) + f.Square() // f = a^(2^252 - 2^28 - 2^6) + f.Mul(&a2) // f = a^(2^252 - 2^28 - 2^6 - 2^1 - 1) + f.Square().Square() // f = a^(2^254 - 2^30 - 2^8 - 2^3 - 2^2) + // // = a^(2^254 - 2^30 - 244) + // // = a^((p+1)/4) + + // Ensure the calculated result is actually the square root by squaring it + // and checking against the original value. + var sqr FieldVal + return sqr.SquareVal(f).Normalize().Equals(val.Normalize()) +} + +// Square squares the field value in constant time. The existing field value is +// modified. Note that this function can overflow if multiplying any of the +// individual words exceeds a max uint32. In practice, this means the magnitude +// of the field must be a max of 8 to prevent overflow. +// +// The field value is returned to support chaining. This enables syntax like: +// f.Square().Mul(f2) so that f = f^2 * f2. +// +// Preconditions: +// - The field value MUST have a max magnitude of 8 +// Output Normalized: No +// Output Max Magnitude: 1 +func (f *FieldVal) Square() *FieldVal { + return f.SquareVal(f) +} + +// SquareVal squares the passed value and stores the result in f in constant +// time. Note that this function can overflow if multiplying any of the +// individual words exceeds a max uint32. In practice, this means the magnitude +// of the field being squared must be a max of 8 to prevent overflow. +// +// The field value is returned to support chaining. This enables syntax like: +// f3.SquareVal(f).Mul(f) so that f3 = f^2 * f = f^3. +// +// Preconditions: +// - The input field value MUST have a max magnitude of 8 +// Output Normalized: No +// Output Max Magnitude: 1 +func (f *FieldVal) SquareVal(val *FieldVal) *FieldVal { + // This could be done with a couple of for loops and an array to store + // the intermediate terms, but this unrolled version is significantly + // faster. + + // Terms for 2^(fieldBase*0). + m := uint64(val.n[0]) * uint64(val.n[0]) + t0 := m & fieldBaseMask + + // Terms for 2^(fieldBase*1). + m = (m >> fieldBase) + 2*uint64(val.n[0])*uint64(val.n[1]) + t1 := m & fieldBaseMask + + // Terms for 2^(fieldBase*2). + m = (m >> fieldBase) + + 2*uint64(val.n[0])*uint64(val.n[2]) + + uint64(val.n[1])*uint64(val.n[1]) + t2 := m & fieldBaseMask + + // Terms for 2^(fieldBase*3). + m = (m >> fieldBase) + + 2*uint64(val.n[0])*uint64(val.n[3]) + + 2*uint64(val.n[1])*uint64(val.n[2]) + t3 := m & fieldBaseMask + + // Terms for 2^(fieldBase*4). + m = (m >> fieldBase) + + 2*uint64(val.n[0])*uint64(val.n[4]) + + 2*uint64(val.n[1])*uint64(val.n[3]) + + uint64(val.n[2])*uint64(val.n[2]) + t4 := m & fieldBaseMask + + // Terms for 2^(fieldBase*5). + m = (m >> fieldBase) + + 2*uint64(val.n[0])*uint64(val.n[5]) + + 2*uint64(val.n[1])*uint64(val.n[4]) + + 2*uint64(val.n[2])*uint64(val.n[3]) + t5 := m & fieldBaseMask + + // Terms for 2^(fieldBase*6). + m = (m >> fieldBase) + + 2*uint64(val.n[0])*uint64(val.n[6]) + + 2*uint64(val.n[1])*uint64(val.n[5]) + + 2*uint64(val.n[2])*uint64(val.n[4]) + + uint64(val.n[3])*uint64(val.n[3]) + t6 := m & fieldBaseMask + + // Terms for 2^(fieldBase*7). + m = (m >> fieldBase) + + 2*uint64(val.n[0])*uint64(val.n[7]) + + 2*uint64(val.n[1])*uint64(val.n[6]) + + 2*uint64(val.n[2])*uint64(val.n[5]) + + 2*uint64(val.n[3])*uint64(val.n[4]) + t7 := m & fieldBaseMask + + // Terms for 2^(fieldBase*8). + m = (m >> fieldBase) + + 2*uint64(val.n[0])*uint64(val.n[8]) + + 2*uint64(val.n[1])*uint64(val.n[7]) + + 2*uint64(val.n[2])*uint64(val.n[6]) + + 2*uint64(val.n[3])*uint64(val.n[5]) + + uint64(val.n[4])*uint64(val.n[4]) + t8 := m & fieldBaseMask + + // Terms for 2^(fieldBase*9). + m = (m >> fieldBase) + + 2*uint64(val.n[0])*uint64(val.n[9]) + + 2*uint64(val.n[1])*uint64(val.n[8]) + + 2*uint64(val.n[2])*uint64(val.n[7]) + + 2*uint64(val.n[3])*uint64(val.n[6]) + + 2*uint64(val.n[4])*uint64(val.n[5]) + t9 := m & fieldBaseMask + + // Terms for 2^(fieldBase*10). + m = (m >> fieldBase) + + 2*uint64(val.n[1])*uint64(val.n[9]) + + 2*uint64(val.n[2])*uint64(val.n[8]) + + 2*uint64(val.n[3])*uint64(val.n[7]) + + 2*uint64(val.n[4])*uint64(val.n[6]) + + uint64(val.n[5])*uint64(val.n[5]) + t10 := m & fieldBaseMask + + // Terms for 2^(fieldBase*11). + m = (m >> fieldBase) + + 2*uint64(val.n[2])*uint64(val.n[9]) + + 2*uint64(val.n[3])*uint64(val.n[8]) + + 2*uint64(val.n[4])*uint64(val.n[7]) + + 2*uint64(val.n[5])*uint64(val.n[6]) + t11 := m & fieldBaseMask + + // Terms for 2^(fieldBase*12). + m = (m >> fieldBase) + + 2*uint64(val.n[3])*uint64(val.n[9]) + + 2*uint64(val.n[4])*uint64(val.n[8]) + + 2*uint64(val.n[5])*uint64(val.n[7]) + + uint64(val.n[6])*uint64(val.n[6]) + t12 := m & fieldBaseMask + + // Terms for 2^(fieldBase*13). + m = (m >> fieldBase) + + 2*uint64(val.n[4])*uint64(val.n[9]) + + 2*uint64(val.n[5])*uint64(val.n[8]) + + 2*uint64(val.n[6])*uint64(val.n[7]) + t13 := m & fieldBaseMask + + // Terms for 2^(fieldBase*14). + m = (m >> fieldBase) + + 2*uint64(val.n[5])*uint64(val.n[9]) + + 2*uint64(val.n[6])*uint64(val.n[8]) + + uint64(val.n[7])*uint64(val.n[7]) + t14 := m & fieldBaseMask + + // Terms for 2^(fieldBase*15). + m = (m >> fieldBase) + + 2*uint64(val.n[6])*uint64(val.n[9]) + + 2*uint64(val.n[7])*uint64(val.n[8]) + t15 := m & fieldBaseMask + + // Terms for 2^(fieldBase*16). + m = (m >> fieldBase) + + 2*uint64(val.n[7])*uint64(val.n[9]) + + uint64(val.n[8])*uint64(val.n[8]) + t16 := m & fieldBaseMask + + // Terms for 2^(fieldBase*17). + m = (m >> fieldBase) + 2*uint64(val.n[8])*uint64(val.n[9]) + t17 := m & fieldBaseMask + + // Terms for 2^(fieldBase*18). + m = (m >> fieldBase) + uint64(val.n[9])*uint64(val.n[9]) + t18 := m & fieldBaseMask + + // What's left is for 2^(fieldBase*19). + t19 := m >> fieldBase + + // At this point, all of the terms are grouped into their respective + // base. + // + // Per [HAC] section 14.3.4: Reduction method of moduli of special form, + // when the modulus is of the special form m = b^t - c, highly efficient + // reduction can be achieved per the provided algorithm. + // + // The secp256k1 prime is equivalent to 2^256 - 4294968273, so it fits + // this criteria. + // + // 4294968273 in field representation (base 2^26) is: + // n[0] = 977 + // n[1] = 64 + // That is to say (2^26 * 64) + 977 = 4294968273 + // + // Since each word is in base 26, the upper terms (t10 and up) start + // at 260 bits (versus the final desired range of 256 bits), so the + // field representation of 'c' from above needs to be adjusted for the + // extra 4 bits by multiplying it by 2^4 = 16. 4294968273 * 16 = + // 68719492368. Thus, the adjusted field representation of 'c' is: + // n[0] = 977 * 16 = 15632 + // n[1] = 64 * 16 = 1024 + // That is to say (2^26 * 1024) + 15632 = 68719492368 + // + // To reduce the final term, t19, the entire 'c' value is needed instead + // of only n[0] because there are no more terms left to handle n[1]. + // This means there might be some magnitude left in the upper bits that + // is handled below. + m = t0 + t10*15632 + t0 = m & fieldBaseMask + m = (m >> fieldBase) + t1 + t10*1024 + t11*15632 + t1 = m & fieldBaseMask + m = (m >> fieldBase) + t2 + t11*1024 + t12*15632 + t2 = m & fieldBaseMask + m = (m >> fieldBase) + t3 + t12*1024 + t13*15632 + t3 = m & fieldBaseMask + m = (m >> fieldBase) + t4 + t13*1024 + t14*15632 + t4 = m & fieldBaseMask + m = (m >> fieldBase) + t5 + t14*1024 + t15*15632 + t5 = m & fieldBaseMask + m = (m >> fieldBase) + t6 + t15*1024 + t16*15632 + t6 = m & fieldBaseMask + m = (m >> fieldBase) + t7 + t16*1024 + t17*15632 + t7 = m & fieldBaseMask + m = (m >> fieldBase) + t8 + t17*1024 + t18*15632 + t8 = m & fieldBaseMask + m = (m >> fieldBase) + t9 + t18*1024 + t19*68719492368 + t9 = m & fieldMSBMask + m >>= fieldMSBBits + + // At this point, if the magnitude is greater than 0, the overall value + // is greater than the max possible 256-bit value. In particular, it is + // "how many times larger" than the max value it is. + // + // The algorithm presented in [HAC] section 14.3.4 repeats until the + // quotient is zero. However, due to the above, we already know at + // least how many times we would need to repeat as it's the value + // currently in m. Thus we can simply multiply the magnitude by the + // field representation of the prime and do a single iteration. Notice + // that nothing will be changed when the magnitude is zero, so we could + // skip this in that case, however always running regardless allows it + // to run in constant time. The final result will be in the range + // 0 <= result <= prime + (2^64 - c), so it is guaranteed to have a + // magnitude of 1, but it is denormalized. + n := t0 + m*977 + f.n[0] = uint32(n & fieldBaseMask) + n = (n >> fieldBase) + t1 + m*64 + f.n[1] = uint32(n & fieldBaseMask) + f.n[2] = uint32((n >> fieldBase) + t2) + f.n[3] = uint32(t3) + f.n[4] = uint32(t4) + f.n[5] = uint32(t5) + f.n[6] = uint32(t6) + f.n[7] = uint32(t7) + f.n[8] = uint32(t8) + f.n[9] = uint32(t9) + + return f +} + +// Inverse finds the modular multiplicative inverse of the field value in +// constant time. The existing field value is modified. +// +// The field value is returned to support chaining. This enables syntax like: +// f.Inverse().Mul(f2) so that f = f^-1 * f2. +// +// Preconditions: +// - The field value MUST have a max magnitude of 8 +// Output Normalized: No +// Output Max Magnitude: 1 +func (f *FieldVal) Inverse() *FieldVal { + // Fermat's little theorem states that for a nonzero number 'a' and prime + // 'p', a^(p-1) ≡ 1 (mod p). Multiplying both sides of the equation by the + // multiplicative inverse a^-1 yields a^(p-2) ≡ a^-1 (mod p). Thus, a^(p-2) + // is the multiplicative inverse. + // + // In order to efficiently compute a^(p-2), p-2 needs to be split into a + // sequence of squares and multiplications that minimizes the number of + // multiplications needed (since they are more costly than squarings). + // Intermediate results are saved and reused as well. + // + // The secp256k1 prime - 2 is 2^256 - 4294968275. In binary, that is: + // + // 11111111 11111111 11111111 11111111 + // 11111111 11111111 11111111 11111111 + // 11111111 11111111 11111111 11111111 + // 11111111 11111111 11111111 11111111 + // 11111111 11111111 11111111 11111111 + // 11111111 11111111 11111111 11111111 + // 11111111 11111111 11111111 11111110 + // 11111111 11111111 11111100 00101101 + // + // Notice that can be broken up into five windows of consecutive 1s (in + // order of least to most significant) as: + // + // 2-bit window with 1 bit set (bit 1 unset) + // 3-bit window with 2 bits set (bit 4 unset) + // 5-bit window with 1 bit set (bits 6, 7, 8, 9 unset) + // 23-bit window with 22 bits set (bit 32 unset) + // 223-bit window with all 223 bits set + // + // Thus, the groups of 1 bits in each window forms the set: + // S = {1, 2, 22, 223}. + // + // The strategy is to calculate a^(2^n - 1) for each grouping via an + // addition chain with a sliding window. + // + // The addition chain used is (credits to Peter Dettman): + // (0,0),(1,0),(2,2),(3,2),(4,1),(5,5),(6,6),(7,7),(8,8),(9,7),(10,2) + // => 2^[1] 2^[2] 2^3 2^6 2^9 2^11 2^[22] 2^44 2^88 2^176 2^220 2^[223] + // + // This has a cost of 255 field squarings and 15 field multiplications. + var a, a2, a3, a6, a9, a11, a22, a44, a88, a176, a220, a223 FieldVal + a.Set(f) + a2.SquareVal(&a).Mul(&a) // a2 = a^(2^2 - 1) + a3.SquareVal(&a2).Mul(&a) // a3 = a^(2^3 - 1) + a6.SquareVal(&a3).Square().Square() // a6 = a^(2^6 - 2^3) + a6.Mul(&a3) // a6 = a^(2^6 - 1) + a9.SquareVal(&a6).Square().Square() // a9 = a^(2^9 - 2^3) + a9.Mul(&a3) // a9 = a^(2^9 - 1) + a11.SquareVal(&a9).Square() // a11 = a^(2^11 - 2^2) + a11.Mul(&a2) // a11 = a^(2^11 - 1) + a22.SquareVal(&a11).Square().Square().Square().Square() // a22 = a^(2^16 - 2^5) + a22.Square().Square().Square().Square().Square() // a22 = a^(2^21 - 2^10) + a22.Square() // a22 = a^(2^22 - 2^11) + a22.Mul(&a11) // a22 = a^(2^22 - 1) + a44.SquareVal(&a22).Square().Square().Square().Square() // a44 = a^(2^27 - 2^5) + a44.Square().Square().Square().Square().Square() // a44 = a^(2^32 - 2^10) + a44.Square().Square().Square().Square().Square() // a44 = a^(2^37 - 2^15) + a44.Square().Square().Square().Square().Square() // a44 = a^(2^42 - 2^20) + a44.Square().Square() // a44 = a^(2^44 - 2^22) + a44.Mul(&a22) // a44 = a^(2^44 - 1) + a88.SquareVal(&a44).Square().Square().Square().Square() // a88 = a^(2^49 - 2^5) + a88.Square().Square().Square().Square().Square() // a88 = a^(2^54 - 2^10) + a88.Square().Square().Square().Square().Square() // a88 = a^(2^59 - 2^15) + a88.Square().Square().Square().Square().Square() // a88 = a^(2^64 - 2^20) + a88.Square().Square().Square().Square().Square() // a88 = a^(2^69 - 2^25) + a88.Square().Square().Square().Square().Square() // a88 = a^(2^74 - 2^30) + a88.Square().Square().Square().Square().Square() // a88 = a^(2^79 - 2^35) + a88.Square().Square().Square().Square().Square() // a88 = a^(2^84 - 2^40) + a88.Square().Square().Square().Square() // a88 = a^(2^88 - 2^44) + a88.Mul(&a44) // a88 = a^(2^88 - 1) + a176.SquareVal(&a88).Square().Square().Square().Square() // a176 = a^(2^93 - 2^5) + a176.Square().Square().Square().Square().Square() // a176 = a^(2^98 - 2^10) + a176.Square().Square().Square().Square().Square() // a176 = a^(2^103 - 2^15) + a176.Square().Square().Square().Square().Square() // a176 = a^(2^108 - 2^20) + a176.Square().Square().Square().Square().Square() // a176 = a^(2^113 - 2^25) + a176.Square().Square().Square().Square().Square() // a176 = a^(2^118 - 2^30) + a176.Square().Square().Square().Square().Square() // a176 = a^(2^123 - 2^35) + a176.Square().Square().Square().Square().Square() // a176 = a^(2^128 - 2^40) + a176.Square().Square().Square().Square().Square() // a176 = a^(2^133 - 2^45) + a176.Square().Square().Square().Square().Square() // a176 = a^(2^138 - 2^50) + a176.Square().Square().Square().Square().Square() // a176 = a^(2^143 - 2^55) + a176.Square().Square().Square().Square().Square() // a176 = a^(2^148 - 2^60) + a176.Square().Square().Square().Square().Square() // a176 = a^(2^153 - 2^65) + a176.Square().Square().Square().Square().Square() // a176 = a^(2^158 - 2^70) + a176.Square().Square().Square().Square().Square() // a176 = a^(2^163 - 2^75) + a176.Square().Square().Square().Square().Square() // a176 = a^(2^168 - 2^80) + a176.Square().Square().Square().Square().Square() // a176 = a^(2^173 - 2^85) + a176.Square().Square().Square() // a176 = a^(2^176 - 2^88) + a176.Mul(&a88) // a176 = a^(2^176 - 1) + a220.SquareVal(&a176).Square().Square().Square().Square() // a220 = a^(2^181 - 2^5) + a220.Square().Square().Square().Square().Square() // a220 = a^(2^186 - 2^10) + a220.Square().Square().Square().Square().Square() // a220 = a^(2^191 - 2^15) + a220.Square().Square().Square().Square().Square() // a220 = a^(2^196 - 2^20) + a220.Square().Square().Square().Square().Square() // a220 = a^(2^201 - 2^25) + a220.Square().Square().Square().Square().Square() // a220 = a^(2^206 - 2^30) + a220.Square().Square().Square().Square().Square() // a220 = a^(2^211 - 2^35) + a220.Square().Square().Square().Square().Square() // a220 = a^(2^216 - 2^40) + a220.Square().Square().Square().Square() // a220 = a^(2^220 - 2^44) + a220.Mul(&a44) // a220 = a^(2^220 - 1) + a223.SquareVal(&a220).Square().Square() // a223 = a^(2^223 - 2^3) + a223.Mul(&a3) // a223 = a^(2^223 - 1) + + f.SquareVal(&a223).Square().Square().Square().Square() // f = a^(2^228 - 2^5) + f.Square().Square().Square().Square().Square() // f = a^(2^233 - 2^10) + f.Square().Square().Square().Square().Square() // f = a^(2^238 - 2^15) + f.Square().Square().Square().Square().Square() // f = a^(2^243 - 2^20) + f.Square().Square().Square() // f = a^(2^246 - 2^23) + f.Mul(&a22) // f = a^(2^246 - 4194305) + f.Square().Square().Square().Square().Square() // f = a^(2^251 - 134217760) + f.Mul(&a) // f = a^(2^251 - 134217759) + f.Square().Square().Square() // f = a^(2^254 - 1073742072) + f.Mul(&a2) // f = a^(2^254 - 1073742069) + f.Square().Square() // f = a^(2^256 - 4294968276) + return f.Mul(&a) // f = a^(2^256 - 4294968275) = a^(p-2) +} + +// IsGtOrEqPrimeMinusOrder returns whether or not the field value is greater +// than or equal to the field prime minus the secp256k1 group order in constant +// time. +// +// Preconditions: +// - The field value MUST be normalized +func (f *FieldVal) IsGtOrEqPrimeMinusOrder() bool { + // The secp256k1 prime is equivalent to 2^256 - 4294968273 and the group + // order is 2^256 - 432420386565659656852420866394968145599. Thus, + // the prime minus the group order is: + // 432420386565659656852420866390673177326 + // + // In hex that is: + // 0x00000000 00000000 00000000 00000001 45512319 50b75fc4 402da172 2fc9baee + // + // Converting that to field representation (base 2^26) is: + // + // n[0] = 0x03c9baee + // n[1] = 0x03685c8b + // n[2] = 0x01fc4402 + // n[3] = 0x006542dd + // n[4] = 0x01455123 + // + // This can be verified with the following test code: + // pMinusN := new(big.Int).Sub(curveParams.P, curveParams.N) + // var fv FieldVal + // fv.SetByteSlice(pMinusN.Bytes()) + // t.Logf("%x", fv.n) + // + // Outputs: [3c9baee 3685c8b 1fc4402 6542dd 1455123 0 0 0 0 0] + const ( + pMinusNWordZero = 0x03c9baee + pMinusNWordOne = 0x03685c8b + pMinusNWordTwo = 0x01fc4402 + pMinusNWordThree = 0x006542dd + pMinusNWordFour = 0x01455123 + pMinusNWordFive = 0x00000000 + pMinusNWordSix = 0x00000000 + pMinusNWordSeven = 0x00000000 + pMinusNWordEight = 0x00000000 + pMinusNWordNine = 0x00000000 + ) + + // The intuition here is that the value is greater than field prime minus + // the group order if one of the higher individual words is greater than the + // corresponding word and all higher words in the value are equal. + result := constantTimeGreater(f.n[9], pMinusNWordNine) + highWordsEqual := constantTimeEq(f.n[9], pMinusNWordNine) + result |= highWordsEqual & constantTimeGreater(f.n[8], pMinusNWordEight) + highWordsEqual &= constantTimeEq(f.n[8], pMinusNWordEight) + result |= highWordsEqual & constantTimeGreater(f.n[7], pMinusNWordSeven) + highWordsEqual &= constantTimeEq(f.n[7], pMinusNWordSeven) + result |= highWordsEqual & constantTimeGreater(f.n[6], pMinusNWordSix) + highWordsEqual &= constantTimeEq(f.n[6], pMinusNWordSix) + result |= highWordsEqual & constantTimeGreater(f.n[5], pMinusNWordFive) + highWordsEqual &= constantTimeEq(f.n[5], pMinusNWordFive) + result |= highWordsEqual & constantTimeGreater(f.n[4], pMinusNWordFour) + highWordsEqual &= constantTimeEq(f.n[4], pMinusNWordFour) + result |= highWordsEqual & constantTimeGreater(f.n[3], pMinusNWordThree) + highWordsEqual &= constantTimeEq(f.n[3], pMinusNWordThree) + result |= highWordsEqual & constantTimeGreater(f.n[2], pMinusNWordTwo) + highWordsEqual &= constantTimeEq(f.n[2], pMinusNWordTwo) + result |= highWordsEqual & constantTimeGreater(f.n[1], pMinusNWordOne) + highWordsEqual &= constantTimeEq(f.n[1], pMinusNWordOne) + result |= highWordsEqual & constantTimeGreaterOrEq(f.n[0], pMinusNWordZero) + + return result != 0 +} diff --git a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/loadprecomputed.go b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/loadprecomputed.go new file mode 100644 index 00000000000..91c3d377693 --- /dev/null +++ b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/loadprecomputed.go @@ -0,0 +1,91 @@ +// Copyright 2015 The btcsuite developers +// Copyright (c) 2015-2022 The Decred developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package secp256k1 + +import ( + "compress/zlib" + "encoding/base64" + "io" + "strings" + "sync" +) + +//go:generate go run genprecomps.go + +// bytePointTable describes a table used to house pre-computed values for +// accelerating scalar base multiplication. +type bytePointTable [32][256]JacobianPoint + +// compressedBytePointsFn is set to a real function by the code generation to +// return the compressed pre-computed values for accelerating scalar base +// multiplication. +var compressedBytePointsFn func() string + +// s256BytePoints houses pre-computed values used to accelerate scalar base +// multiplication such that they are only loaded on first use. +var s256BytePoints = func() func() *bytePointTable { + // mustLoadBytePoints decompresses and deserializes the pre-computed byte + // points used to accelerate scalar base multiplication for the secp256k1 + // curve. + // + // This approach is used since it allows the compile to use significantly + // less ram and be performed much faster than it is with hard-coding the + // final in-memory data structure. At the same time, it is quite fast to + // generate the in-memory data structure on first use with this approach + // versus computing the table. + // + // It will panic on any errors because the data is hard coded and thus any + // errors means something is wrong in the source code. + var data *bytePointTable + mustLoadBytePoints := func() { + // There will be no byte points to load when generating them. + if compressedBytePointsFn == nil { + return + } + bp := compressedBytePointsFn() + + // Decompress the pre-computed table used to accelerate scalar base + // multiplication. + decoder := base64.NewDecoder(base64.StdEncoding, strings.NewReader(bp)) + r, err := zlib.NewReader(decoder) + if err != nil { + panic(err) + } + serialized, err := io.ReadAll(r) + if err != nil { + panic(err) + } + + // Deserialize the precomputed byte points and set the memory table to + // them. + offset := 0 + var bytePoints bytePointTable + for byteNum := 0; byteNum < len(bytePoints); byteNum++ { + // All points in this window. + for i := 0; i < len(bytePoints[byteNum]); i++ { + p := &bytePoints[byteNum][i] + p.X.SetByteSlice(serialized[offset:]) + offset += 32 + p.Y.SetByteSlice(serialized[offset:]) + offset += 32 + p.Z.SetInt(1) + } + } + data = &bytePoints + } + + // Return a closure that initializes the data on first access. This is done + // because the table takes a non-trivial amount of memory and initializing + // it unconditionally would cause anything that imports the package, either + // directly, or indirectly via transitive deps, to use that memory even if + // the caller never accesses any parts of the package that actually needs + // access to it. + var loadBytePointsOnce sync.Once + return func() *bytePointTable { + loadBytePointsOnce.Do(mustLoadBytePoints) + return data + } +}() diff --git a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/modnscalar.go b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/modnscalar.go new file mode 100644 index 00000000000..225016d8de9 --- /dev/null +++ b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/modnscalar.go @@ -0,0 +1,1105 @@ +// Copyright (c) 2020-2024 The Decred developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package secp256k1 + +import ( + "encoding/hex" + "math/big" +) + +// References: +// [SECG]: Recommended Elliptic Curve Domain Parameters +// https://www.secg.org/sec2-v2.pdf +// +// [HAC]: Handbook of Applied Cryptography Menezes, van Oorschot, Vanstone. +// http://cacr.uwaterloo.ca/hac/ + +// Many elliptic curve operations require working with scalars in a finite field +// characterized by the order of the group underlying the secp256k1 curve. +// Given this precision is larger than the biggest available native type, +// obviously some form of bignum math is needed. This code implements +// specialized fixed-precision field arithmetic rather than relying on an +// arbitrary-precision arithmetic package such as math/big for dealing with the +// math modulo the group order since the size is known. As a result, rather +// large performance gains are achieved by taking advantage of many +// optimizations not available to arbitrary-precision arithmetic and generic +// modular arithmetic algorithms. +// +// There are various ways to internally represent each element. For example, +// the most obvious representation would be to use an array of 4 uint64s (64 +// bits * 4 = 256 bits). However, that representation suffers from the fact +// that there is no native Go type large enough to handle the intermediate +// results while adding or multiplying two 64-bit numbers. +// +// Given the above, this implementation represents the field elements as 8 +// uint32s with each word (array entry) treated as base 2^32. This was chosen +// because most systems at the current time are 64-bit (or at least have 64-bit +// registers available for specialized purposes such as MMX) so the intermediate +// results can typically be done using a native register (and using uint64s to +// avoid the need for additional half-word arithmetic) + +const ( + // These fields provide convenient access to each of the words of the + // secp256k1 curve group order N to improve code readability. + // + // The group order of the curve per [SECG] is: + // 0xffffffff ffffffff ffffffff fffffffe baaedce6 af48a03b bfd25e8c d0364141 + // + // nolint: dupword + orderWordZero uint32 = 0xd0364141 + orderWordOne uint32 = 0xbfd25e8c + orderWordTwo uint32 = 0xaf48a03b + orderWordThree uint32 = 0xbaaedce6 + orderWordFour uint32 = 0xfffffffe + orderWordFive uint32 = 0xffffffff + orderWordSix uint32 = 0xffffffff + orderWordSeven uint32 = 0xffffffff + + // These fields provide convenient access to each of the words of the two's + // complement of the secp256k1 curve group order N to improve code + // readability. + // + // The two's complement of the group order is: + // 0x00000000 00000000 00000000 00000001 45512319 50b75fc4 402da173 2fc9bebf + orderComplementWordZero uint32 = (^orderWordZero) + 1 + orderComplementWordOne uint32 = ^orderWordOne + orderComplementWordTwo uint32 = ^orderWordTwo + orderComplementWordThree uint32 = ^orderWordThree + // orderComplementWordFour uint32 = ^orderWordFour // unused + // orderComplementWordFive uint32 = ^orderWordFive // unused + // orderComplementWordSix uint32 = ^orderWordSix // unused + // orderComplementWordSeven uint32 = ^orderWordSeven // unused + + // These fields provide convenient access to each of the words of the + // secp256k1 curve group order N / 2 to improve code readability and avoid + // the need to recalculate them. + // + // The half order of the secp256k1 curve group is: + // 0x7fffffff ffffffff ffffffff ffffffff 5d576e73 57a4501d dfe92f46 681b20a0 + // + // nolint: dupword + halfOrderWordZero uint32 = 0x681b20a0 + halfOrderWordOne uint32 = 0xdfe92f46 + halfOrderWordTwo uint32 = 0x57a4501d + halfOrderWordThree uint32 = 0x5d576e73 + halfOrderWordFour uint32 = 0xffffffff + halfOrderWordFive uint32 = 0xffffffff + halfOrderWordSix uint32 = 0xffffffff + halfOrderWordSeven uint32 = 0x7fffffff + + // uint32Mask is simply a mask with all bits set for a uint32 and is used to + // improve the readability of the code. + uint32Mask = 0xffffffff +) + +var ( + // zero32 is an array of 32 bytes used for the purposes of zeroing and is + // defined here to avoid extra allocations. + zero32 = [32]byte{} +) + +// ModNScalar implements optimized 256-bit constant-time fixed-precision +// arithmetic over the secp256k1 group order. This means all arithmetic is +// performed modulo: +// +// 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141 +// +// It only implements the arithmetic needed for elliptic curve operations, +// however, the operations that are not implemented can typically be worked +// around if absolutely needed. For example, subtraction can be performed by +// adding the negation. +// +// Should it be absolutely necessary, conversion to the standard library +// math/big.Int can be accomplished by using the Bytes method, slicing the +// resulting fixed-size array, and feeding it to big.Int.SetBytes. However, +// that should typically be avoided when possible as conversion to big.Ints +// requires allocations, is not constant time, and is slower when working modulo +// the group order. +type ModNScalar struct { + // The scalar is represented as 8 32-bit integers in base 2^32. + // + // The following depicts the internal representation: + // --------------------------------------------------------- + // | n[7] | n[6] | ... | n[0] | + // | 32 bits | 32 bits | ... | 32 bits | + // | Mult: 2^(32*7) | Mult: 2^(32*6) | ... | Mult: 2^(32*0) | + // --------------------------------------------------------- + // + // For example, consider the number 2^87 + 2^42 + 1. It would be + // represented as: + // n[0] = 1 + // n[1] = 2^10 + // n[2] = 2^23 + // n[3..7] = 0 + // + // The full 256-bit value is then calculated by looping i from 7..0 and + // doing sum(n[i] * 2^(32i)) like so: + // n[7] * 2^(32*7) = 0 * 2^224 = 0 + // n[6] * 2^(32*6) = 0 * 2^192 = 0 + // ... + // n[2] * 2^(32*2) = 2^23 * 2^64 = 2^87 + // n[1] * 2^(32*1) = 2^10 * 2^32 = 2^42 + // n[0] * 2^(32*0) = 1 * 2^0 = 1 + // Sum: 0 + 0 + ... + 2^87 + 2^42 + 1 = 2^87 + 2^42 + 1 + n [8]uint32 +} + +// String returns the scalar as a human-readable hex string. +// +// This is NOT constant time. +func (s ModNScalar) String() string { + b := s.Bytes() + return hex.EncodeToString(b[:]) +} + +// Set sets the scalar equal to a copy of the passed one in constant time. +// +// The scalar is returned to support chaining. This enables syntax like: +// s := new(ModNScalar).Set(s2).Add(1) so that s = s2 + 1 where s2 is not +// modified. +func (s *ModNScalar) Set(val *ModNScalar) *ModNScalar { + *s = *val + return s +} + +// Zero sets the scalar to zero in constant time. A newly created scalar is +// already set to zero. This function can be useful to clear an existing scalar +// for reuse. +func (s *ModNScalar) Zero() { + s.n[0] = 0 + s.n[1] = 0 + s.n[2] = 0 + s.n[3] = 0 + s.n[4] = 0 + s.n[5] = 0 + s.n[6] = 0 + s.n[7] = 0 +} + +// IsZeroBit returns 1 when the scalar is equal to zero or 0 otherwise in +// constant time. +// +// Note that a bool is not used here because it is not possible in Go to convert +// from a bool to numeric value in constant time and many constant-time +// operations require a numeric value. See IsZero for the version that returns +// a bool. +func (s *ModNScalar) IsZeroBit() uint32 { + // The scalar can only be zero if no bits are set in any of the words. + bits := s.n[0] | s.n[1] | s.n[2] | s.n[3] | s.n[4] | s.n[5] | s.n[6] | s.n[7] + return constantTimeEq(bits, 0) +} + +// IsZero returns whether or not the scalar is equal to zero in constant time. +func (s *ModNScalar) IsZero() bool { + // The scalar can only be zero if no bits are set in any of the words. + bits := s.n[0] | s.n[1] | s.n[2] | s.n[3] | s.n[4] | s.n[5] | s.n[6] | s.n[7] + return bits == 0 +} + +// SetInt sets the scalar to the passed integer in constant time. This is a +// convenience function since it is fairly common to perform some arithmetic +// with small native integers. +// +// The scalar is returned to support chaining. This enables syntax like: +// s := new(ModNScalar).SetInt(2).Mul(s2) so that s = 2 * s2. +func (s *ModNScalar) SetInt(ui uint32) *ModNScalar { + s.Zero() + s.n[0] = ui + return s +} + +// constantTimeEq returns 1 if a == b or 0 otherwise in constant time. +func constantTimeEq(a, b uint32) uint32 { + return uint32((uint64(a^b) - 1) >> 63) +} + +// constantTimeNotEq returns 1 if a != b or 0 otherwise in constant time. +func constantTimeNotEq(a, b uint32) uint32 { + return ^uint32((uint64(a^b)-1)>>63) & 1 +} + +// constantTimeLess returns 1 if a < b or 0 otherwise in constant time. +func constantTimeLess(a, b uint32) uint32 { + return uint32((uint64(a) - uint64(b)) >> 63) +} + +// constantTimeLessOrEq returns 1 if a <= b or 0 otherwise in constant time. +func constantTimeLessOrEq(a, b uint32) uint32 { + return uint32((uint64(a) - uint64(b) - 1) >> 63) +} + +// constantTimeGreater returns 1 if a > b or 0 otherwise in constant time. +func constantTimeGreater(a, b uint32) uint32 { + return constantTimeLess(b, a) +} + +// constantTimeGreaterOrEq returns 1 if a >= b or 0 otherwise in constant time. +func constantTimeGreaterOrEq(a, b uint32) uint32 { + return constantTimeLessOrEq(b, a) +} + +// constantTimeMin returns min(a,b) in constant time. +func constantTimeMin(a, b uint32) uint32 { + return b ^ ((a ^ b) & -constantTimeLess(a, b)) +} + +// overflows determines if the current scalar is greater than or equal to the +// group order in constant time and returns 1 if it is or 0 otherwise. +func (s *ModNScalar) overflows() uint32 { + // The intuition here is that the scalar is greater than the group order if + // one of the higher individual words is greater than corresponding word of + // the group order and all higher words in the scalar are equal to their + // corresponding word of the group order. Since this type is modulo the + // group order, being equal is also an overflow back to 0. + // + // Note that the words 5, 6, and 7 are all the max uint32 value, so there is + // no need to test if those individual words of the scalar exceeds them, + // hence, only equality is checked for them. + highWordsEqual := constantTimeEq(s.n[7], orderWordSeven) + highWordsEqual &= constantTimeEq(s.n[6], orderWordSix) + highWordsEqual &= constantTimeEq(s.n[5], orderWordFive) + overflow := highWordsEqual & constantTimeGreater(s.n[4], orderWordFour) + highWordsEqual &= constantTimeEq(s.n[4], orderWordFour) + overflow |= highWordsEqual & constantTimeGreater(s.n[3], orderWordThree) + highWordsEqual &= constantTimeEq(s.n[3], orderWordThree) + overflow |= highWordsEqual & constantTimeGreater(s.n[2], orderWordTwo) + highWordsEqual &= constantTimeEq(s.n[2], orderWordTwo) + overflow |= highWordsEqual & constantTimeGreater(s.n[1], orderWordOne) + highWordsEqual &= constantTimeEq(s.n[1], orderWordOne) + overflow |= highWordsEqual & constantTimeGreaterOrEq(s.n[0], orderWordZero) + + return overflow +} + +// reduce256 reduces the current scalar modulo the group order in accordance +// with the overflows parameter in constant time. The overflows parameter +// specifies whether or not the scalar is known to be greater than the group +// order and MUST either be 1 in the case it is or 0 in the case it is not for a +// correct result. +func (s *ModNScalar) reduce256(overflows uint32) { + // Notice that since s < 2^256 < 2N (where N is the group order), the max + // possible number of reductions required is one. Therefore, in the case a + // reduction is needed, it can be performed with a single subtraction of N. + // Also, recall that subtraction is equivalent to addition by the two's + // complement while ignoring the carry. + // + // When s >= N, the overflows parameter will be 1. Conversely, it will be 0 + // when s < N. Thus multiplying by the overflows parameter will either + // result in 0 or the multiplicand itself. + // + // Combining the above along with the fact that s + 0 = s, the following is + // a constant time implementation that works by either adding 0 or the two's + // complement of N as needed. + // + // The final result will be in the range 0 <= s < N as expected. + overflows64 := uint64(overflows) + c := uint64(s.n[0]) + overflows64*uint64(orderComplementWordZero) + s.n[0] = uint32(c & uint32Mask) + c = (c >> 32) + uint64(s.n[1]) + overflows64*uint64(orderComplementWordOne) + s.n[1] = uint32(c & uint32Mask) + c = (c >> 32) + uint64(s.n[2]) + overflows64*uint64(orderComplementWordTwo) + s.n[2] = uint32(c & uint32Mask) + c = (c >> 32) + uint64(s.n[3]) + overflows64*uint64(orderComplementWordThree) + s.n[3] = uint32(c & uint32Mask) + c = (c >> 32) + uint64(s.n[4]) + overflows64 // * 1 + s.n[4] = uint32(c & uint32Mask) + c = (c >> 32) + uint64(s.n[5]) // + overflows64 * 0 + s.n[5] = uint32(c & uint32Mask) + c = (c >> 32) + uint64(s.n[6]) // + overflows64 * 0 + s.n[6] = uint32(c & uint32Mask) + c = (c >> 32) + uint64(s.n[7]) // + overflows64 * 0 + s.n[7] = uint32(c & uint32Mask) +} + +// SetBytes interprets the provided array as a 256-bit big-endian unsigned +// integer, reduces it modulo the group order, sets the scalar to the result, +// and returns either 1 if it was reduced (aka it overflowed) or 0 otherwise in +// constant time. +// +// Note that a bool is not used here because it is not possible in Go to convert +// from a bool to numeric value in constant time and many constant-time +// operations require a numeric value. +func (s *ModNScalar) SetBytes(b *[32]byte) uint32 { + // Pack the 256 total bits across the 8 uint32 words. This could be done + // with a for loop, but benchmarks show this unrolled version is about 2 + // times faster than the variant that uses a loop. + s.n[0] = uint32(b[31]) | uint32(b[30])<<8 | uint32(b[29])<<16 | uint32(b[28])<<24 + s.n[1] = uint32(b[27]) | uint32(b[26])<<8 | uint32(b[25])<<16 | uint32(b[24])<<24 + s.n[2] = uint32(b[23]) | uint32(b[22])<<8 | uint32(b[21])<<16 | uint32(b[20])<<24 + s.n[3] = uint32(b[19]) | uint32(b[18])<<8 | uint32(b[17])<<16 | uint32(b[16])<<24 + s.n[4] = uint32(b[15]) | uint32(b[14])<<8 | uint32(b[13])<<16 | uint32(b[12])<<24 + s.n[5] = uint32(b[11]) | uint32(b[10])<<8 | uint32(b[9])<<16 | uint32(b[8])<<24 + s.n[6] = uint32(b[7]) | uint32(b[6])<<8 | uint32(b[5])<<16 | uint32(b[4])<<24 + s.n[7] = uint32(b[3]) | uint32(b[2])<<8 | uint32(b[1])<<16 | uint32(b[0])<<24 + + // The value might be >= N, so reduce it as required and return whether or + // not it was reduced. + needsReduce := s.overflows() + s.reduce256(needsReduce) + return needsReduce +} + +// zeroArray32 zeroes the provided 32-byte buffer. +func zeroArray32(b *[32]byte) { + copy(b[:], zero32[:]) +} + +// SetByteSlice interprets the provided slice as a 256-bit big-endian unsigned +// integer (meaning it is truncated to the first 32 bytes), reduces it modulo +// the group order, sets the scalar to the result, and returns whether or not +// the resulting truncated 256-bit integer overflowed in constant time. +// +// Note that since passing a slice with more than 32 bytes is truncated, it is +// possible that the truncated value is less than the order of the curve and +// hence it will not be reported as having overflowed in that case. It is up to +// the caller to decide whether it needs to provide numbers of the appropriate +// size or it is acceptable to use this function with the described truncation +// and overflow behavior. +func (s *ModNScalar) SetByteSlice(b []byte) bool { + var b32 [32]byte + b = b[:constantTimeMin(uint32(len(b)), 32)] + copy(b32[:], b32[:32-len(b)]) + copy(b32[32-len(b):], b) + result := s.SetBytes(&b32) + zeroArray32(&b32) + return result != 0 +} + +// PutBytesUnchecked unpacks the scalar to a 32-byte big-endian value directly +// into the passed byte slice in constant time. The target slice must have at +// least 32 bytes available or it will panic. +// +// There is a similar function, PutBytes, which unpacks the scalar into a +// 32-byte array directly. This version is provided since it can be useful to +// write directly into part of a larger buffer without needing a separate +// allocation. +// +// Preconditions: +// - The target slice MUST have at least 32 bytes available +func (s *ModNScalar) PutBytesUnchecked(b []byte) { + // Unpack the 256 total bits from the 8 uint32 words. This could be done + // with a for loop, but benchmarks show this unrolled version is about 2 + // times faster than the variant which uses a loop. + b[31] = byte(s.n[0]) + b[30] = byte(s.n[0] >> 8) + b[29] = byte(s.n[0] >> 16) + b[28] = byte(s.n[0] >> 24) + b[27] = byte(s.n[1]) + b[26] = byte(s.n[1] >> 8) + b[25] = byte(s.n[1] >> 16) + b[24] = byte(s.n[1] >> 24) + b[23] = byte(s.n[2]) + b[22] = byte(s.n[2] >> 8) + b[21] = byte(s.n[2] >> 16) + b[20] = byte(s.n[2] >> 24) + b[19] = byte(s.n[3]) + b[18] = byte(s.n[3] >> 8) + b[17] = byte(s.n[3] >> 16) + b[16] = byte(s.n[3] >> 24) + b[15] = byte(s.n[4]) + b[14] = byte(s.n[4] >> 8) + b[13] = byte(s.n[4] >> 16) + b[12] = byte(s.n[4] >> 24) + b[11] = byte(s.n[5]) + b[10] = byte(s.n[5] >> 8) + b[9] = byte(s.n[5] >> 16) + b[8] = byte(s.n[5] >> 24) + b[7] = byte(s.n[6]) + b[6] = byte(s.n[6] >> 8) + b[5] = byte(s.n[6] >> 16) + b[4] = byte(s.n[6] >> 24) + b[3] = byte(s.n[7]) + b[2] = byte(s.n[7] >> 8) + b[1] = byte(s.n[7] >> 16) + b[0] = byte(s.n[7] >> 24) +} + +// PutBytes unpacks the scalar to a 32-byte big-endian value using the passed +// byte array in constant time. +// +// There is a similar function, PutBytesUnchecked, which unpacks the scalar into +// a slice that must have at least 32 bytes available. This version is provided +// since it can be useful to write directly into an array that is type checked. +// +// Alternatively, there is also Bytes, which unpacks the scalar into a new array +// and returns that which can sometimes be more ergonomic in applications that +// aren't concerned about an additional copy. +func (s *ModNScalar) PutBytes(b *[32]byte) { + s.PutBytesUnchecked(b[:]) +} + +// Bytes unpacks the scalar to a 32-byte big-endian value in constant time. +// +// See PutBytes and PutBytesUnchecked for variants that allow an array or slice +// to be passed which can be useful to cut down on the number of allocations +// by allowing the caller to reuse a buffer or write directly into part of a +// larger buffer. +func (s *ModNScalar) Bytes() [32]byte { + var b [32]byte + s.PutBytesUnchecked(b[:]) + return b +} + +// IsOdd returns whether or not the scalar is an odd number in constant time. +func (s *ModNScalar) IsOdd() bool { + // Only odd numbers have the bottom bit set. + return s.n[0]&1 == 1 +} + +// Equals returns whether or not the two scalars are the same in constant time. +func (s *ModNScalar) Equals(val *ModNScalar) bool { + // Xor only sets bits when they are different, so the two scalars can only + // be the same if no bits are set after xoring each word. + bits := (s.n[0] ^ val.n[0]) | (s.n[1] ^ val.n[1]) | (s.n[2] ^ val.n[2]) | + (s.n[3] ^ val.n[3]) | (s.n[4] ^ val.n[4]) | (s.n[5] ^ val.n[5]) | + (s.n[6] ^ val.n[6]) | (s.n[7] ^ val.n[7]) + + return bits == 0 +} + +// Add2 adds the passed two scalars together modulo the group order in constant +// time and stores the result in s. +// +// The scalar is returned to support chaining. This enables syntax like: +// s3.Add2(s, s2).AddInt(1) so that s3 = s + s2 + 1. +func (s *ModNScalar) Add2(val1, val2 *ModNScalar) *ModNScalar { + c := uint64(val1.n[0]) + uint64(val2.n[0]) + s.n[0] = uint32(c & uint32Mask) + c = (c >> 32) + uint64(val1.n[1]) + uint64(val2.n[1]) + s.n[1] = uint32(c & uint32Mask) + c = (c >> 32) + uint64(val1.n[2]) + uint64(val2.n[2]) + s.n[2] = uint32(c & uint32Mask) + c = (c >> 32) + uint64(val1.n[3]) + uint64(val2.n[3]) + s.n[3] = uint32(c & uint32Mask) + c = (c >> 32) + uint64(val1.n[4]) + uint64(val2.n[4]) + s.n[4] = uint32(c & uint32Mask) + c = (c >> 32) + uint64(val1.n[5]) + uint64(val2.n[5]) + s.n[5] = uint32(c & uint32Mask) + c = (c >> 32) + uint64(val1.n[6]) + uint64(val2.n[6]) + s.n[6] = uint32(c & uint32Mask) + c = (c >> 32) + uint64(val1.n[7]) + uint64(val2.n[7]) + s.n[7] = uint32(c & uint32Mask) + + // The result is now 256 bits, but it might still be >= N, so use the + // existing normal reduce method for 256-bit values. + s.reduce256(uint32(c>>32) + s.overflows()) + return s +} + +// Add adds the passed scalar to the existing one modulo the group order in +// constant time and stores the result in s. +// +// The scalar is returned to support chaining. This enables syntax like: +// s.Add(s2).AddInt(1) so that s = s + s2 + 1. +func (s *ModNScalar) Add(val *ModNScalar) *ModNScalar { + return s.Add2(s, val) +} + +// accumulator96 provides a 96-bit accumulator for use in the intermediate +// calculations requiring more than 64-bits. +type accumulator96 struct { + n [3]uint32 +} + +// Add adds the passed unsigned 64-bit value to the accumulator. +func (a *accumulator96) Add(v uint64) { + low := uint32(v & uint32Mask) + hi := uint32(v >> 32) + a.n[0] += low + hi += constantTimeLess(a.n[0], low) // Carry if overflow in n[0]. + a.n[1] += hi + a.n[2] += constantTimeLess(a.n[1], hi) // Carry if overflow in n[1]. +} + +// Rsh32 right shifts the accumulator by 32 bits. +func (a *accumulator96) Rsh32() { + a.n[0] = a.n[1] + a.n[1] = a.n[2] + a.n[2] = 0 +} + +// reduce385 reduces the 385-bit intermediate result in the passed terms modulo +// the group order in constant time and stores the result in s. +func (s *ModNScalar) reduce385(t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12 uint64) { + // At this point, the intermediate result in the passed terms has been + // reduced to fit within 385 bits, so reduce it again using the same method + // described in reduce512. As before, the intermediate result will end up + // being reduced by another 127 bits to 258 bits, thus 9 32-bit terms are + // needed for this iteration. The reduced terms are assigned back to t0 + // through t8. + // + // Note that several of the intermediate calculations require adding 64-bit + // products together which would overflow a uint64, so a 96-bit accumulator + // is used instead until the value is reduced enough to use native uint64s. + + // Terms for 2^(32*0). + var acc accumulator96 + acc.n[0] = uint32(t0) // == acc.Add(t0) because acc is guaranteed to be 0. + acc.Add(t8 * uint64(orderComplementWordZero)) + t0 = uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*1). + acc.Add(t1) + acc.Add(t8 * uint64(orderComplementWordOne)) + acc.Add(t9 * uint64(orderComplementWordZero)) + t1 = uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*2). + acc.Add(t2) + acc.Add(t8 * uint64(orderComplementWordTwo)) + acc.Add(t9 * uint64(orderComplementWordOne)) + acc.Add(t10 * uint64(orderComplementWordZero)) + t2 = uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*3). + acc.Add(t3) + acc.Add(t8 * uint64(orderComplementWordThree)) + acc.Add(t9 * uint64(orderComplementWordTwo)) + acc.Add(t10 * uint64(orderComplementWordOne)) + acc.Add(t11 * uint64(orderComplementWordZero)) + t3 = uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*4). + acc.Add(t4) + acc.Add(t8) // * uint64(orderComplementWordFour) // * 1 + acc.Add(t9 * uint64(orderComplementWordThree)) + acc.Add(t10 * uint64(orderComplementWordTwo)) + acc.Add(t11 * uint64(orderComplementWordOne)) + acc.Add(t12 * uint64(orderComplementWordZero)) + t4 = uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*5). + acc.Add(t5) + // acc.Add(t8 * uint64(orderComplementWordFive)) // 0 + acc.Add(t9) // * uint64(orderComplementWordFour) // * 1 + acc.Add(t10 * uint64(orderComplementWordThree)) + acc.Add(t11 * uint64(orderComplementWordTwo)) + acc.Add(t12 * uint64(orderComplementWordOne)) + t5 = uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*6). + acc.Add(t6) + // acc.Add(t8 * uint64(orderComplementWordSix)) // 0 + // acc.Add(t9 * uint64(orderComplementWordFive)) // 0 + acc.Add(t10) // * uint64(orderComplementWordFour) // * 1 + acc.Add(t11 * uint64(orderComplementWordThree)) + acc.Add(t12 * uint64(orderComplementWordTwo)) + t6 = uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*7). + acc.Add(t7) + // acc.Add(t8 * uint64(orderComplementWordSeven)) // 0 + // acc.Add(t9 * uint64(orderComplementWordSix)) // 0 + // acc.Add(t10 * uint64(orderComplementWordFive)) // 0 + acc.Add(t11) // * uint64(orderComplementWordFour) // * 1 + acc.Add(t12 * uint64(orderComplementWordThree)) + t7 = uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*8). + // acc.Add(t9 * uint64(orderComplementWordSeven)) // 0 + // acc.Add(t10 * uint64(orderComplementWordSix)) // 0 + // acc.Add(t11 * uint64(orderComplementWordFive)) // 0 + acc.Add(t12) // * uint64(orderComplementWordFour) // * 1 + t8 = uint64(acc.n[0]) + // acc.Rsh32() // No need since not used after this. Guaranteed to be 0. + + // NOTE: All of the remaining multiplications for this iteration result in 0 + // as they all involve multiplying by combinations of the fifth, sixth, and + // seventh words of the two's complement of N, which are 0, so skip them. + + // At this point, the result is reduced to fit within 258 bits, so reduce it + // again using a slightly modified version of the same method. The maximum + // value in t8 is 2 at this point and therefore multiplying it by each word + // of the two's complement of N and adding it to a 32-bit term will result + // in a maximum requirement of 33 bits, so it is safe to use native uint64s + // here for the intermediate term carry propagation. + // + // Also, since the maximum value in t8 is 2, this ends up reducing by + // another 2 bits to 256 bits. + c := t0 + t8*uint64(orderComplementWordZero) + s.n[0] = uint32(c & uint32Mask) + c = (c >> 32) + t1 + t8*uint64(orderComplementWordOne) + s.n[1] = uint32(c & uint32Mask) + c = (c >> 32) + t2 + t8*uint64(orderComplementWordTwo) + s.n[2] = uint32(c & uint32Mask) + c = (c >> 32) + t3 + t8*uint64(orderComplementWordThree) + s.n[3] = uint32(c & uint32Mask) + c = (c >> 32) + t4 + t8 // * uint64(orderComplementWordFour) == * 1 + s.n[4] = uint32(c & uint32Mask) + c = (c >> 32) + t5 // + t8*uint64(orderComplementWordFive) == 0 + s.n[5] = uint32(c & uint32Mask) + c = (c >> 32) + t6 // + t8*uint64(orderComplementWordSix) == 0 + s.n[6] = uint32(c & uint32Mask) + c = (c >> 32) + t7 // + t8*uint64(orderComplementWordSeven) == 0 + s.n[7] = uint32(c & uint32Mask) + + // The result is now 256 bits, but it might still be >= N, so use the + // existing normal reduce method for 256-bit values. + s.reduce256(uint32(c>>32) + s.overflows()) +} + +// reduce512 reduces the 512-bit intermediate result in the passed terms modulo +// the group order down to 385 bits in constant time and stores the result in s. +func (s *ModNScalar) reduce512(t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15 uint64) { + // At this point, the intermediate result in the passed terms is grouped + // into the respective bases. + // + // Per [HAC] section 14.3.4: Reduction method of moduli of special form, + // when the modulus is of the special form m = b^t - c, where log_2(c) < t, + // highly efficient reduction can be achieved per the provided algorithm. + // + // The secp256k1 group order fits this criteria since it is: + // 2^256 - 432420386565659656852420866394968145599 + // + // Technically the max possible value here is (N-1)^2 since the two scalars + // being multiplied are always mod N. Nevertheless, it is safer to consider + // it to be (2^256-1)^2 = 2^512 - 2^257 + 1 since it is the product of two + // 256-bit values. + // + // The algorithm is to reduce the result modulo the prime by subtracting + // multiples of the group order N. However, in order simplify carry + // propagation, this adds with the two's complement of N to achieve the same + // result. + // + // Since the two's complement of N has 127 leading zero bits, this will end + // up reducing the intermediate result from 512 bits to 385 bits, resulting + // in 13 32-bit terms. The reduced terms are assigned back to t0 through + // t12. + // + // Note that several of the intermediate calculations require adding 64-bit + // products together which would overflow a uint64, so a 96-bit accumulator + // is used instead. + + // Terms for 2^(32*0). + var acc accumulator96 + acc.n[0] = uint32(t0) // == acc.Add(t0) because acc is guaranteed to be 0. + acc.Add(t8 * uint64(orderComplementWordZero)) + t0 = uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*1). + acc.Add(t1) + acc.Add(t8 * uint64(orderComplementWordOne)) + acc.Add(t9 * uint64(orderComplementWordZero)) + t1 = uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*2). + acc.Add(t2) + acc.Add(t8 * uint64(orderComplementWordTwo)) + acc.Add(t9 * uint64(orderComplementWordOne)) + acc.Add(t10 * uint64(orderComplementWordZero)) + t2 = uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*3). + acc.Add(t3) + acc.Add(t8 * uint64(orderComplementWordThree)) + acc.Add(t9 * uint64(orderComplementWordTwo)) + acc.Add(t10 * uint64(orderComplementWordOne)) + acc.Add(t11 * uint64(orderComplementWordZero)) + t3 = uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*4). + acc.Add(t4) + acc.Add(t8) // * uint64(orderComplementWordFour) // * 1 + acc.Add(t9 * uint64(orderComplementWordThree)) + acc.Add(t10 * uint64(orderComplementWordTwo)) + acc.Add(t11 * uint64(orderComplementWordOne)) + acc.Add(t12 * uint64(orderComplementWordZero)) + t4 = uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*5). + acc.Add(t5) + // acc.Add(t8 * uint64(orderComplementWordFive)) // 0 + acc.Add(t9) // * uint64(orderComplementWordFour) // * 1 + acc.Add(t10 * uint64(orderComplementWordThree)) + acc.Add(t11 * uint64(orderComplementWordTwo)) + acc.Add(t12 * uint64(orderComplementWordOne)) + acc.Add(t13 * uint64(orderComplementWordZero)) + t5 = uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*6). + acc.Add(t6) + // acc.Add(t8 * uint64(orderComplementWordSix)) // 0 + // acc.Add(t9 * uint64(orderComplementWordFive)) // 0 + acc.Add(t10) // * uint64(orderComplementWordFour)) // * 1 + acc.Add(t11 * uint64(orderComplementWordThree)) + acc.Add(t12 * uint64(orderComplementWordTwo)) + acc.Add(t13 * uint64(orderComplementWordOne)) + acc.Add(t14 * uint64(orderComplementWordZero)) + t6 = uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*7). + acc.Add(t7) + // acc.Add(t8 * uint64(orderComplementWordSeven)) // 0 + // acc.Add(t9 * uint64(orderComplementWordSix)) // 0 + // acc.Add(t10 * uint64(orderComplementWordFive)) // 0 + acc.Add(t11) // * uint64(orderComplementWordFour) // * 1 + acc.Add(t12 * uint64(orderComplementWordThree)) + acc.Add(t13 * uint64(orderComplementWordTwo)) + acc.Add(t14 * uint64(orderComplementWordOne)) + acc.Add(t15 * uint64(orderComplementWordZero)) + t7 = uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*8). + // acc.Add(t9 * uint64(orderComplementWordSeven)) // 0 + // acc.Add(t10 * uint64(orderComplementWordSix)) // 0 + // acc.Add(t11 * uint64(orderComplementWordFive)) // 0 + acc.Add(t12) // * uint64(orderComplementWordFour) // * 1 + acc.Add(t13 * uint64(orderComplementWordThree)) + acc.Add(t14 * uint64(orderComplementWordTwo)) + acc.Add(t15 * uint64(orderComplementWordOne)) + t8 = uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*9). + // acc.Add(t10 * uint64(orderComplementWordSeven)) // 0 + // acc.Add(t11 * uint64(orderComplementWordSix)) // 0 + // acc.Add(t12 * uint64(orderComplementWordFive)) // 0 + acc.Add(t13) // * uint64(orderComplementWordFour) // * 1 + acc.Add(t14 * uint64(orderComplementWordThree)) + acc.Add(t15 * uint64(orderComplementWordTwo)) + t9 = uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*10). + // acc.Add(t11 * uint64(orderComplementWordSeven)) // 0 + // acc.Add(t12 * uint64(orderComplementWordSix)) // 0 + // acc.Add(t13 * uint64(orderComplementWordFive)) // 0 + acc.Add(t14) // * uint64(orderComplementWordFour) // * 1 + acc.Add(t15 * uint64(orderComplementWordThree)) + t10 = uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*11). + // acc.Add(t12 * uint64(orderComplementWordSeven)) // 0 + // acc.Add(t13 * uint64(orderComplementWordSix)) // 0 + // acc.Add(t14 * uint64(orderComplementWordFive)) // 0 + acc.Add(t15) // * uint64(orderComplementWordFour) // * 1 + t11 = uint64(acc.n[0]) + acc.Rsh32() + + // NOTE: All of the remaining multiplications for this iteration result in 0 + // as they all involve multiplying by combinations of the fifth, sixth, and + // seventh words of the two's complement of N, which are 0, so skip them. + + // Terms for 2^(32*12). + t12 = uint64(acc.n[0]) + // acc.Rsh32() // No need since not used after this. Guaranteed to be 0. + + // At this point, the result is reduced to fit within 385 bits, so reduce it + // again using the same method accordingly. + s.reduce385(t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12) +} + +// Mul2 multiplies the passed two scalars together modulo the group order in +// constant time and stores the result in s. +// +// The scalar is returned to support chaining. This enables syntax like: +// s3.Mul2(s, s2).AddInt(1) so that s3 = (s * s2) + 1. +func (s *ModNScalar) Mul2(val, val2 *ModNScalar) *ModNScalar { + // This could be done with for loops and an array to store the intermediate + // terms, but this unrolled version is significantly faster. + + // The overall strategy employed here is: + // 1) Calculate the 512-bit product of the two scalars using the standard + // pencil-and-paper method. + // 2) Reduce the result modulo the prime by effectively subtracting + // multiples of the group order N (actually performed by adding multiples + // of the two's complement of N to avoid implementing subtraction). + // 3) Repeat step 2 noting that each iteration reduces the required number + // of bits by 127 because the two's complement of N has 127 leading zero + // bits. + // 4) Once reduced to 256 bits, call the existing reduce method to perform + // a final reduction as needed. + // + // Note that several of the intermediate calculations require adding 64-bit + // products together which would overflow a uint64, so a 96-bit accumulator + // is used instead. + + // Terms for 2^(32*0). + var acc accumulator96 + acc.Add(uint64(val.n[0]) * uint64(val2.n[0])) + t0 := uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*1). + acc.Add(uint64(val.n[0]) * uint64(val2.n[1])) + acc.Add(uint64(val.n[1]) * uint64(val2.n[0])) + t1 := uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*2). + acc.Add(uint64(val.n[0]) * uint64(val2.n[2])) + acc.Add(uint64(val.n[1]) * uint64(val2.n[1])) + acc.Add(uint64(val.n[2]) * uint64(val2.n[0])) + t2 := uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*3). + acc.Add(uint64(val.n[0]) * uint64(val2.n[3])) + acc.Add(uint64(val.n[1]) * uint64(val2.n[2])) + acc.Add(uint64(val.n[2]) * uint64(val2.n[1])) + acc.Add(uint64(val.n[3]) * uint64(val2.n[0])) + t3 := uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*4). + acc.Add(uint64(val.n[0]) * uint64(val2.n[4])) + acc.Add(uint64(val.n[1]) * uint64(val2.n[3])) + acc.Add(uint64(val.n[2]) * uint64(val2.n[2])) + acc.Add(uint64(val.n[3]) * uint64(val2.n[1])) + acc.Add(uint64(val.n[4]) * uint64(val2.n[0])) + t4 := uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*5). + acc.Add(uint64(val.n[0]) * uint64(val2.n[5])) + acc.Add(uint64(val.n[1]) * uint64(val2.n[4])) + acc.Add(uint64(val.n[2]) * uint64(val2.n[3])) + acc.Add(uint64(val.n[3]) * uint64(val2.n[2])) + acc.Add(uint64(val.n[4]) * uint64(val2.n[1])) + acc.Add(uint64(val.n[5]) * uint64(val2.n[0])) + t5 := uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*6). + acc.Add(uint64(val.n[0]) * uint64(val2.n[6])) + acc.Add(uint64(val.n[1]) * uint64(val2.n[5])) + acc.Add(uint64(val.n[2]) * uint64(val2.n[4])) + acc.Add(uint64(val.n[3]) * uint64(val2.n[3])) + acc.Add(uint64(val.n[4]) * uint64(val2.n[2])) + acc.Add(uint64(val.n[5]) * uint64(val2.n[1])) + acc.Add(uint64(val.n[6]) * uint64(val2.n[0])) + t6 := uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*7). + acc.Add(uint64(val.n[0]) * uint64(val2.n[7])) + acc.Add(uint64(val.n[1]) * uint64(val2.n[6])) + acc.Add(uint64(val.n[2]) * uint64(val2.n[5])) + acc.Add(uint64(val.n[3]) * uint64(val2.n[4])) + acc.Add(uint64(val.n[4]) * uint64(val2.n[3])) + acc.Add(uint64(val.n[5]) * uint64(val2.n[2])) + acc.Add(uint64(val.n[6]) * uint64(val2.n[1])) + acc.Add(uint64(val.n[7]) * uint64(val2.n[0])) + t7 := uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*8). + acc.Add(uint64(val.n[1]) * uint64(val2.n[7])) + acc.Add(uint64(val.n[2]) * uint64(val2.n[6])) + acc.Add(uint64(val.n[3]) * uint64(val2.n[5])) + acc.Add(uint64(val.n[4]) * uint64(val2.n[4])) + acc.Add(uint64(val.n[5]) * uint64(val2.n[3])) + acc.Add(uint64(val.n[6]) * uint64(val2.n[2])) + acc.Add(uint64(val.n[7]) * uint64(val2.n[1])) + t8 := uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*9). + acc.Add(uint64(val.n[2]) * uint64(val2.n[7])) + acc.Add(uint64(val.n[3]) * uint64(val2.n[6])) + acc.Add(uint64(val.n[4]) * uint64(val2.n[5])) + acc.Add(uint64(val.n[5]) * uint64(val2.n[4])) + acc.Add(uint64(val.n[6]) * uint64(val2.n[3])) + acc.Add(uint64(val.n[7]) * uint64(val2.n[2])) + t9 := uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*10). + acc.Add(uint64(val.n[3]) * uint64(val2.n[7])) + acc.Add(uint64(val.n[4]) * uint64(val2.n[6])) + acc.Add(uint64(val.n[5]) * uint64(val2.n[5])) + acc.Add(uint64(val.n[6]) * uint64(val2.n[4])) + acc.Add(uint64(val.n[7]) * uint64(val2.n[3])) + t10 := uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*11). + acc.Add(uint64(val.n[4]) * uint64(val2.n[7])) + acc.Add(uint64(val.n[5]) * uint64(val2.n[6])) + acc.Add(uint64(val.n[6]) * uint64(val2.n[5])) + acc.Add(uint64(val.n[7]) * uint64(val2.n[4])) + t11 := uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*12). + acc.Add(uint64(val.n[5]) * uint64(val2.n[7])) + acc.Add(uint64(val.n[6]) * uint64(val2.n[6])) + acc.Add(uint64(val.n[7]) * uint64(val2.n[5])) + t12 := uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*13). + acc.Add(uint64(val.n[6]) * uint64(val2.n[7])) + acc.Add(uint64(val.n[7]) * uint64(val2.n[6])) + t13 := uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*14). + acc.Add(uint64(val.n[7]) * uint64(val2.n[7])) + t14 := uint64(acc.n[0]) + acc.Rsh32() + + // What's left is for 2^(32*15). + t15 := uint64(acc.n[0]) + // acc.Rsh32() // No need since not used after this. Guaranteed to be 0. + + // At this point, all of the terms are grouped into their respective base + // and occupy up to 512 bits. Reduce the result accordingly. + s.reduce512(t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, + t15) + return s +} + +// Mul multiplies the passed scalar with the existing one modulo the group order +// in constant time and stores the result in s. +// +// The scalar is returned to support chaining. This enables syntax like: +// s.Mul(s2).AddInt(1) so that s = (s * s2) + 1. +func (s *ModNScalar) Mul(val *ModNScalar) *ModNScalar { + return s.Mul2(s, val) +} + +// SquareVal squares the passed scalar modulo the group order in constant time +// and stores the result in s. +// +// The scalar is returned to support chaining. This enables syntax like: +// s3.SquareVal(s).Mul(s) so that s3 = s^2 * s = s^3. +func (s *ModNScalar) SquareVal(val *ModNScalar) *ModNScalar { + // This could technically be optimized slightly to take advantage of the + // fact that many of the intermediate calculations in squaring are just + // doubling, however, benchmarking has shown that due to the need to use a + // 96-bit accumulator, any savings are essentially offset by that and + // consequently there is no real difference in performance over just + // multiplying the value by itself to justify the extra code for now. This + // can be revisited in the future if it becomes a bottleneck in practice. + + return s.Mul2(val, val) +} + +// Square squares the scalar modulo the group order in constant time. The +// existing scalar is modified. +// +// The scalar is returned to support chaining. This enables syntax like: +// s.Square().Mul(s2) so that s = s^2 * s2. +func (s *ModNScalar) Square() *ModNScalar { + return s.SquareVal(s) +} + +// NegateVal negates the passed scalar modulo the group order and stores the +// result in s in constant time. +// +// The scalar is returned to support chaining. This enables syntax like: +// s.NegateVal(s2).AddInt(1) so that s = -s2 + 1. +func (s *ModNScalar) NegateVal(val *ModNScalar) *ModNScalar { + // Since the scalar is already in the range 0 <= val < N, where N is the + // group order, negation modulo the group order is just the group order + // minus the value. This implies that the result will always be in the + // desired range with the sole exception of 0 because N - 0 = N itself. + // + // Therefore, in order to avoid the need to reduce the result for every + // other case in order to achieve constant time, this creates a mask that is + // all 0s in the case of the scalar being negated is 0 and all 1s otherwise + // and bitwise ands that mask with each word. + // + // Finally, to simplify the carry propagation, this adds the two's + // complement of the scalar to N in order to achieve the same result. + bits := val.n[0] | val.n[1] | val.n[2] | val.n[3] | val.n[4] | val.n[5] | + val.n[6] | val.n[7] + mask := uint64(uint32Mask * constantTimeNotEq(bits, 0)) + c := uint64(orderWordZero) + (uint64(^val.n[0]) + 1) + s.n[0] = uint32(c & mask) + c = (c >> 32) + uint64(orderWordOne) + uint64(^val.n[1]) + s.n[1] = uint32(c & mask) + c = (c >> 32) + uint64(orderWordTwo) + uint64(^val.n[2]) + s.n[2] = uint32(c & mask) + c = (c >> 32) + uint64(orderWordThree) + uint64(^val.n[3]) + s.n[3] = uint32(c & mask) + c = (c >> 32) + uint64(orderWordFour) + uint64(^val.n[4]) + s.n[4] = uint32(c & mask) + c = (c >> 32) + uint64(orderWordFive) + uint64(^val.n[5]) + s.n[5] = uint32(c & mask) + c = (c >> 32) + uint64(orderWordSix) + uint64(^val.n[6]) + s.n[6] = uint32(c & mask) + c = (c >> 32) + uint64(orderWordSeven) + uint64(^val.n[7]) + s.n[7] = uint32(c & mask) + return s +} + +// Negate negates the scalar modulo the group order in constant time. The +// existing scalar is modified. +// +// The scalar is returned to support chaining. This enables syntax like: +// s.Negate().AddInt(1) so that s = -s + 1. +func (s *ModNScalar) Negate() *ModNScalar { + return s.NegateVal(s) +} + +// InverseValNonConst finds the modular multiplicative inverse of the passed +// scalar and stores result in s in *non-constant* time. +// +// The scalar is returned to support chaining. This enables syntax like: +// s3.InverseVal(s1).Mul(s2) so that s3 = s1^-1 * s2. +func (s *ModNScalar) InverseValNonConst(val *ModNScalar) *ModNScalar { + // This is making use of big integers for now. Ideally it will be replaced + // with an implementation that does not depend on big integers. + valBytes := val.Bytes() + bigVal := new(big.Int).SetBytes(valBytes[:]) + bigVal.ModInverse(bigVal, curveParams.N) + s.SetByteSlice(bigVal.Bytes()) + return s +} + +// InverseNonConst finds the modular multiplicative inverse of the scalar in +// *non-constant* time. The existing scalar is modified. +// +// The scalar is returned to support chaining. This enables syntax like: +// s.Inverse().Mul(s2) so that s = s^-1 * s2. +func (s *ModNScalar) InverseNonConst() *ModNScalar { + return s.InverseValNonConst(s) +} + +// IsOverHalfOrder returns whether or not the scalar exceeds the group order +// divided by 2 in constant time. +func (s *ModNScalar) IsOverHalfOrder() bool { + // The intuition here is that the scalar is greater than half of the group + // order if one of the higher individual words is greater than the + // corresponding word of the half group order and all higher words in the + // scalar are equal to their corresponding word of the half group order. + // + // Note that the words 4, 5, and 6 are all the max uint32 value, so there is + // no need to test if those individual words of the scalar exceeds them, + // hence, only equality is checked for them. + result := constantTimeGreater(s.n[7], halfOrderWordSeven) + highWordsEqual := constantTimeEq(s.n[7], halfOrderWordSeven) + highWordsEqual &= constantTimeEq(s.n[6], halfOrderWordSix) + highWordsEqual &= constantTimeEq(s.n[5], halfOrderWordFive) + highWordsEqual &= constantTimeEq(s.n[4], halfOrderWordFour) + result |= highWordsEqual & constantTimeGreater(s.n[3], halfOrderWordThree) + highWordsEqual &= constantTimeEq(s.n[3], halfOrderWordThree) + result |= highWordsEqual & constantTimeGreater(s.n[2], halfOrderWordTwo) + highWordsEqual &= constantTimeEq(s.n[2], halfOrderWordTwo) + result |= highWordsEqual & constantTimeGreater(s.n[1], halfOrderWordOne) + highWordsEqual &= constantTimeEq(s.n[1], halfOrderWordOne) + result |= highWordsEqual & constantTimeGreater(s.n[0], halfOrderWordZero) + + return result != 0 +} diff --git a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/nonce.go b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/nonce.go new file mode 100644 index 00000000000..70a75bb81c6 --- /dev/null +++ b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/nonce.go @@ -0,0 +1,263 @@ +// Copyright (c) 2013-2014 The btcsuite developers +// Copyright (c) 2015-2024 The Decred developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package secp256k1 + +import ( + "bytes" + "crypto/sha256" + "hash" +) + +// References: +// [GECC]: Guide to Elliptic Curve Cryptography (Hankerson, Menezes, Vanstone) +// +// [ISO/IEC 8825-1]: Information technology — ASN.1 encoding rules: +// Specification of Basic Encoding Rules (BER), Canonical Encoding Rules +// (CER) and Distinguished Encoding Rules (DER) +// +// [SEC1]: Elliptic Curve Cryptography (May 31, 2009, Version 2.0) +// https://www.secg.org/sec1-v2.pdf + +var ( + // singleZero is used during RFC6979 nonce generation. It is provided + // here to avoid the need to create it multiple times. + singleZero = []byte{0x00} + + // zeroInitializer is used during RFC6979 nonce generation. It is provided + // here to avoid the need to create it multiple times. + zeroInitializer = bytes.Repeat([]byte{0x00}, sha256.BlockSize) + + // singleOne is used during RFC6979 nonce generation. It is provided + // here to avoid the need to create it multiple times. + singleOne = []byte{0x01} + + // oneInitializer is used during RFC6979 nonce generation. It is provided + // here to avoid the need to create it multiple times. + oneInitializer = bytes.Repeat([]byte{0x01}, sha256.Size) +) + +// hmacsha256 implements a resettable version of HMAC-SHA256. +type hmacsha256 struct { + inner, outer hash.Hash + ipad, opad [sha256.BlockSize]byte +} + +// Write adds data to the running hash. +func (h *hmacsha256) Write(p []byte) { + h.inner.Write(p) +} + +// initKey initializes the HMAC-SHA256 instance to the provided key. +func (h *hmacsha256) initKey(key []byte) { + // Hash the key if it is too large. + if len(key) > sha256.BlockSize { + h.outer.Write(key) + key = h.outer.Sum(nil) + } + copy(h.ipad[:], key) + copy(h.opad[:], key) + for i := range h.ipad { + h.ipad[i] ^= 0x36 + } + for i := range h.opad { + h.opad[i] ^= 0x5c + } + h.inner.Write(h.ipad[:]) +} + +// ResetKey resets the HMAC-SHA256 to its initial state and then initializes it +// with the provided key. It is equivalent to creating a new instance with the +// provided key without allocating more memory. +func (h *hmacsha256) ResetKey(key []byte) { + h.inner.Reset() + h.outer.Reset() + copy(h.ipad[:], zeroInitializer) + copy(h.opad[:], zeroInitializer) + h.initKey(key) +} + +// Resets the HMAC-SHA256 to its initial state using the current key. +func (h *hmacsha256) Reset() { + h.inner.Reset() + h.inner.Write(h.ipad[:]) +} + +// Sum returns the hash of the written data. +func (h *hmacsha256) Sum() []byte { + h.outer.Reset() + h.outer.Write(h.opad[:]) + h.outer.Write(h.inner.Sum(nil)) + return h.outer.Sum(nil) +} + +// newHMACSHA256 returns a new HMAC-SHA256 hasher using the provided key. +func newHMACSHA256(key []byte) *hmacsha256 { + h := new(hmacsha256) + h.inner = sha256.New() + h.outer = sha256.New() + h.initKey(key) + return h +} + +// NonceRFC6979 generates a nonce deterministically according to RFC 6979 using +// HMAC-SHA256 for the hashing function. It takes a 32-byte hash as an input +// and returns a 32-byte nonce to be used for deterministic signing. The extra +// and version arguments are optional, but allow additional data to be added to +// the input of the HMAC. When provided, the extra data must be 32-bytes and +// version must be 16 bytes or they will be ignored. +// +// Finally, the extraIterations parameter provides a method to produce a stream +// of deterministic nonces to ensure the signing code is able to produce a nonce +// that results in a valid signature in the extremely unlikely event the +// original nonce produced results in an invalid signature (e.g. R == 0). +// Signing code should start with 0 and increment it if necessary. +func NonceRFC6979(privKey []byte, hash []byte, extra []byte, version []byte, extraIterations uint32) *ModNScalar { + // Input to HMAC is the 32-byte private key and the 32-byte hash. In + // addition, it may include the optional 32-byte extra data and 16-byte + // version. Create a fixed-size array to avoid extra allocs and slice it + // properly. + const ( + privKeyLen = 32 + hashLen = 32 + extraLen = 32 + versionLen = 16 + ) + var keyBuf [privKeyLen + hashLen + extraLen + versionLen]byte + + // Truncate rightmost bytes of private key and hash if they are too long and + // leave left padding of zeros when they're too short. + if len(privKey) > privKeyLen { + privKey = privKey[:privKeyLen] + } + if len(hash) > hashLen { + hash = hash[:hashLen] + } + offset := privKeyLen - len(privKey) // Zero left padding if needed. + offset += copy(keyBuf[offset:], privKey) + offset += hashLen - len(hash) // Zero left padding if needed. + offset += copy(keyBuf[offset:], hash) + if len(extra) == extraLen { + offset += copy(keyBuf[offset:], extra) + if len(version) == versionLen { + offset += copy(keyBuf[offset:], version) + } + } else if len(version) == versionLen { + // When the version was specified, but not the extra data, leave the + // extra data portion all zero. + offset += privKeyLen + offset += copy(keyBuf[offset:], version) + } + key := keyBuf[:offset] + + // Step B. + // + // V = 0x01 0x01 0x01 ... 0x01 such that the length of V, in bits, is + // equal to 8*ceil(hashLen/8). + // + // Note that since the hash length is a multiple of 8 for the chosen hash + // function in this optimized implementation, the result is just the hash + // length, so avoid the extra calculations. Also, since it isn't modified, + // start with a global value. + v := oneInitializer + + // Step C (Go zeroes all allocated memory). + // + // K = 0x00 0x00 0x00 ... 0x00 such that the length of K, in bits, is + // equal to 8*ceil(hashLen/8). + // + // As above, since the hash length is a multiple of 8 for the chosen hash + // function in this optimized implementation, the result is just the hash + // length, so avoid the extra calculations. + k := zeroInitializer[:hashLen] + + // Step D. + // + // K = HMAC_K(V || 0x00 || int2octets(x) || bits2octets(h1)) + // + // Note that key is the "int2octets(x) || bits2octets(h1)" portion along + // with potential additional data as described by section 3.6 of the RFC. + hasher := newHMACSHA256(k) + hasher.Write(oneInitializer) + hasher.Write(singleZero) + hasher.Write(key) + k = hasher.Sum() + + // Step E. + // + // V = HMAC_K(V) + hasher.ResetKey(k) + hasher.Write(v) + v = hasher.Sum() + + // Step F. + // + // K = HMAC_K(V || 0x01 || int2octets(x) || bits2octets(h1)) + // + // Note that key is the "int2octets(x) || bits2octets(h1)" portion along + // with potential additional data as described by section 3.6 of the RFC. + hasher.Reset() + hasher.Write(v) + hasher.Write(singleOne) + hasher.Write(key) + k = hasher.Sum() + + // Step G. + // + // V = HMAC_K(V) + hasher.ResetKey(k) + hasher.Write(v) + v = hasher.Sum() + + // Step H. + // + // Repeat until the value is nonzero and less than the curve order. + var generated uint32 + for { + // Step H1 and H2. + // + // Set T to the empty sequence. The length of T (in bits) is denoted + // tlen; thus, at that point, tlen = 0. + // + // While tlen < qlen, do the following: + // V = HMAC_K(V) + // T = T || V + // + // Note that because the hash function output is the same length as the + // private key in this optimized implementation, there is no need to + // loop or create an intermediate T. + hasher.Reset() + hasher.Write(v) + v = hasher.Sum() + + // Step H3. + // + // k = bits2int(T) + // If k is within the range [1,q-1], return it. + // + // Otherwise, compute: + // K = HMAC_K(V || 0x00) + // V = HMAC_K(V) + var secret ModNScalar + overflow := secret.SetByteSlice(v) + if !overflow && !secret.IsZero() { + generated++ + if generated > extraIterations { + return &secret + } + } + + // K = HMAC_K(V || 0x00) + hasher.Reset() + hasher.Write(v) + hasher.Write(singleZero) + k = hasher.Sum() + + // V = HMAC_K(V) + hasher.ResetKey(k) + hasher.Write(v) + v = hasher.Sum() + } +} diff --git a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/privkey.go b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/privkey.go new file mode 100644 index 00000000000..e6b7be35063 --- /dev/null +++ b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/privkey.go @@ -0,0 +1,111 @@ +// Copyright (c) 2013-2014 The btcsuite developers +// Copyright (c) 2015-2024 The Decred developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package secp256k1 + +import ( + cryptorand "crypto/rand" + "io" +) + +// PrivateKey provides facilities for working with secp256k1 private keys within +// this package and includes functionality such as serializing and parsing them +// as well as computing their associated public key. +type PrivateKey struct { + Key ModNScalar +} + +// NewPrivateKey instantiates a new private key from a scalar encoded as a +// big integer. +func NewPrivateKey(key *ModNScalar) *PrivateKey { + return &PrivateKey{Key: *key} +} + +// PrivKeyFromBytes returns a private based on the provided byte slice which is +// interpreted as an unsigned 256-bit big-endian integer in the range [0, N-1], +// where N is the order of the curve. +// +// WARNING: This means passing a slice with more than 32 bytes is truncated and +// that truncated value is reduced modulo N. Further, 0 is not a valid private +// key. It is up to the caller to provide a value in the appropriate range of +// [1, N-1]. Failure to do so will either result in an invalid private key or +// potentially weak private keys that have bias that could be exploited. +// +// This function primarily exists to provide a mechanism for converting +// serialized private keys that are already known to be good. +// +// Typically callers should make use of GeneratePrivateKey or +// GeneratePrivateKeyFromRand when creating private keys since they properly +// handle generation of appropriate values. +func PrivKeyFromBytes(privKeyBytes []byte) *PrivateKey { + var privKey PrivateKey + privKey.Key.SetByteSlice(privKeyBytes) + return &privKey +} + +// generatePrivateKey generates and returns a new private key that is suitable +// for use with secp256k1 using the provided reader as a source of entropy. The +// provided reader must be a source of cryptographically secure randomness to +// avoid weak private keys. +func generatePrivateKey(rand io.Reader) (*PrivateKey, error) { + // The group order is close enough to 2^256 that there is only roughly a 1 + // in 2^128 chance of generating an invalid private key, so this loop will + // virtually never run more than a single iteration in practice. + var key PrivateKey + var b32 [32]byte + for valid := false; !valid; { + if _, err := io.ReadFull(rand, b32[:]); err != nil { + return nil, err + } + + // The private key is only valid when it is in the range [1, N-1], where + // N is the order of the curve. + overflow := key.Key.SetBytes(&b32) + valid = (key.Key.IsZeroBit() | overflow) == 0 + } + zeroArray32(&b32) + + return &key, nil +} + +// GeneratePrivateKey generates and returns a new cryptographically secure +// private key that is suitable for use with secp256k1. +func GeneratePrivateKey() (*PrivateKey, error) { + return generatePrivateKey(cryptorand.Reader) +} + +// GeneratePrivateKeyFromRand generates a private key that is suitable for use +// with secp256k1 using the provided reader as a source of entropy. The +// provided reader must be a source of cryptographically secure randomness, such +// as [crypto/rand.Reader], to avoid weak private keys. +func GeneratePrivateKeyFromRand(rand io.Reader) (*PrivateKey, error) { + return generatePrivateKey(rand) +} + +// PubKey computes and returns the public key corresponding to this private key. +func (p *PrivateKey) PubKey() *PublicKey { + var result JacobianPoint + ScalarBaseMultNonConst(&p.Key, &result) + result.ToAffine() + return NewPublicKey(&result.X, &result.Y) +} + +// Zero manually clears the memory associated with the private key. This can be +// used to explicitly clear key material from memory for enhanced security +// against memory scraping. +func (p *PrivateKey) Zero() { + p.Key.Zero() +} + +// PrivKeyBytesLen defines the length in bytes of a serialized private key. +const PrivKeyBytesLen = 32 + +// Serialize returns the private key as a 256-bit big-endian binary-encoded +// number, padded to a length of 32 bytes. +func (p PrivateKey) Serialize() []byte { + var privKeyBytes [PrivKeyBytesLen]byte + p.Key.PutBytes(&privKeyBytes) + return privKeyBytes[:] +} diff --git a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/pubkey.go b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/pubkey.go new file mode 100644 index 00000000000..2f8815bedf3 --- /dev/null +++ b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/pubkey.go @@ -0,0 +1,236 @@ +// Copyright (c) 2013-2014 The btcsuite developers +// Copyright (c) 2015-2024 The Decred developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package secp256k1 + +// References: +// [SEC1] Elliptic Curve Cryptography +// https://www.secg.org/sec1-v2.pdf +// +// [SEC2] Recommended Elliptic Curve Domain Parameters +// https://www.secg.org/sec2-v2.pdf +// +// [ANSI X9.62-1998] Public Key Cryptography For The Financial Services +// Industry: The Elliptic Curve Digital Signature Algorithm (ECDSA) + +import ( + "fmt" +) + +const ( + // PubKeyBytesLenCompressed is the number of bytes of a serialized + // compressed public key. + PubKeyBytesLenCompressed = 33 + + // PubKeyBytesLenUncompressed is the number of bytes of a serialized + // uncompressed public key. + PubKeyBytesLenUncompressed = 65 + + // PubKeyFormatCompressedEven is the identifier prefix byte for a public key + // whose Y coordinate is even when serialized in the compressed format per + // section 2.3.4 of [SEC1](https://secg.org/sec1-v2.pdf#subsubsection.2.3.4). + PubKeyFormatCompressedEven byte = 0x02 + + // PubKeyFormatCompressedOdd is the identifier prefix byte for a public key + // whose Y coordinate is odd when serialized in the compressed format per + // section 2.3.4 of [SEC1](https://secg.org/sec1-v2.pdf#subsubsection.2.3.4). + PubKeyFormatCompressedOdd byte = 0x03 + + // PubKeyFormatUncompressed is the identifier prefix byte for a public key + // when serialized according in the uncompressed format per section 2.3.3 of + // [SEC1](https://secg.org/sec1-v2.pdf#subsubsection.2.3.3). + PubKeyFormatUncompressed byte = 0x04 + + // PubKeyFormatHybridEven is the identifier prefix byte for a public key + // whose Y coordinate is even when serialized according to the hybrid format + // per section 4.3.6 of [ANSI X9.62-1998]. + // + // NOTE: This format makes little sense in practice an therefore this + // package will not produce public keys serialized in this format. However, + // it will parse them since they exist in the wild. + PubKeyFormatHybridEven byte = 0x06 + + // PubKeyFormatHybridOdd is the identifier prefix byte for a public key + // whose Y coordingate is odd when serialized according to the hybrid format + // per section 4.3.6 of [ANSI X9.62-1998]. + // + // NOTE: This format makes little sense in practice an therefore this + // package will not produce public keys serialized in this format. However, + // it will parse them since they exist in the wild. + PubKeyFormatHybridOdd byte = 0x07 +) + +// PublicKey provides facilities for efficiently working with secp256k1 public +// keys within this package and includes functions to serialize in both +// uncompressed and compressed SEC (Standards for Efficient Cryptography) +// formats. +type PublicKey struct { + x FieldVal + y FieldVal +} + +// NewPublicKey instantiates a new public key with the given x and y +// coordinates. +// +// It should be noted that, unlike ParsePubKey, since this accepts arbitrary x +// and y coordinates, it allows creation of public keys that are not valid +// points on the secp256k1 curve. The IsOnCurve method of the returned instance +// can be used to determine validity. +func NewPublicKey(x, y *FieldVal) *PublicKey { + var pubKey PublicKey + pubKey.x.Set(x) + pubKey.y.Set(y) + return &pubKey +} + +// ParsePubKey parses a secp256k1 public key encoded according to the format +// specified by ANSI X9.62-1998, which means it is also compatible with the +// SEC (Standards for Efficient Cryptography) specification which is a subset of +// the former. In other words, it supports the uncompressed, compressed, and +// hybrid formats as follows: +// +// Compressed: +// +// <32-byte X coordinate> +// +// Uncompressed: +// +// <32-byte X coordinate><32-byte Y coordinate> +// +// Hybrid: +// +// <32-byte X coordinate><32-byte Y coordinate> +// +// NOTE: The hybrid format makes little sense in practice an therefore this +// package will not produce public keys serialized in this format. However, +// this function will properly parse them since they exist in the wild. +func ParsePubKey(serialized []byte) (key *PublicKey, err error) { + var x, y FieldVal + switch len(serialized) { + case PubKeyBytesLenUncompressed: + // Reject unsupported public key formats for the given length. + format := serialized[0] + switch format { + case PubKeyFormatUncompressed: + case PubKeyFormatHybridEven, PubKeyFormatHybridOdd: + default: + str := fmt.Sprintf("invalid public key: unsupported format: %x", + format) + return nil, makeError(ErrPubKeyInvalidFormat, str) + } + + // Parse the x and y coordinates while ensuring that they are in the + // allowed range. + if overflow := x.SetByteSlice(serialized[1:33]); overflow { + str := "invalid public key: x >= field prime" + return nil, makeError(ErrPubKeyXTooBig, str) + } + if overflow := y.SetByteSlice(serialized[33:]); overflow { + str := "invalid public key: y >= field prime" + return nil, makeError(ErrPubKeyYTooBig, str) + } + + // Ensure the oddness of the y coordinate matches the specified format + // for hybrid public keys. + if format == PubKeyFormatHybridEven || format == PubKeyFormatHybridOdd { + wantOddY := format == PubKeyFormatHybridOdd + if y.IsOdd() != wantOddY { + str := fmt.Sprintf("invalid public key: y oddness does not "+ + "match specified value of %v", wantOddY) + return nil, makeError(ErrPubKeyMismatchedOddness, str) + } + } + + // Reject public keys that are not on the secp256k1 curve. + if !isOnCurve(&x, &y) { + str := fmt.Sprintf("invalid public key: [%v,%v] not on secp256k1 "+ + "curve", x, y) + return nil, makeError(ErrPubKeyNotOnCurve, str) + } + + case PubKeyBytesLenCompressed: + // Reject unsupported public key formats for the given length. + format := serialized[0] + switch format { + case PubKeyFormatCompressedEven, PubKeyFormatCompressedOdd: + default: + str := fmt.Sprintf("invalid public key: unsupported format: %x", + format) + return nil, makeError(ErrPubKeyInvalidFormat, str) + } + + // Parse the x coordinate while ensuring that it is in the allowed + // range. + if overflow := x.SetByteSlice(serialized[1:33]); overflow { + str := "invalid public key: x >= field prime" + return nil, makeError(ErrPubKeyXTooBig, str) + } + + // Attempt to calculate the y coordinate for the given x coordinate such + // that the result pair is a point on the secp256k1 curve and the + // solution with desired oddness is chosen. + wantOddY := format == PubKeyFormatCompressedOdd + if !DecompressY(&x, wantOddY, &y) { + str := fmt.Sprintf("invalid public key: x coordinate %v is not on "+ + "the secp256k1 curve", x) + return nil, makeError(ErrPubKeyNotOnCurve, str) + } + + default: + str := fmt.Sprintf("malformed public key: invalid length: %d", + len(serialized)) + return nil, makeError(ErrPubKeyInvalidLen, str) + } + + return NewPublicKey(&x, &y), nil +} + +// SerializeUncompressed serializes a public key in the 65-byte uncompressed +// format. +func (p PublicKey) SerializeUncompressed() []byte { + // 0x04 || 32-byte x coordinate || 32-byte y coordinate + var b [PubKeyBytesLenUncompressed]byte + b[0] = PubKeyFormatUncompressed + p.x.PutBytesUnchecked(b[1:33]) + p.y.PutBytesUnchecked(b[33:65]) + return b[:] +} + +// SerializeCompressed serializes a public key in the 33-byte compressed format. +func (p PublicKey) SerializeCompressed() []byte { + // Choose the format byte depending on the oddness of the Y coordinate. + format := PubKeyFormatCompressedEven + if p.y.IsOdd() { + format = PubKeyFormatCompressedOdd + } + + // 0x02 or 0x03 || 32-byte x coordinate + var b [PubKeyBytesLenCompressed]byte + b[0] = format + p.x.PutBytesUnchecked(b[1:33]) + return b[:] +} + +// IsEqual compares this public key instance to the one passed, returning true +// if both public keys are equivalent. A public key is equivalent to another, +// if they both have the same X and Y coordinates. +func (p *PublicKey) IsEqual(otherPubKey *PublicKey) bool { + return p.x.Equals(&otherPubKey.x) && p.y.Equals(&otherPubKey.y) +} + +// AsJacobian converts the public key into a Jacobian point with Z=1 and stores +// the result in the provided result param. This allows the public key to be +// treated a Jacobian point in the secp256k1 group in calculations. +func (p *PublicKey) AsJacobian(result *JacobianPoint) { + result.X.Set(&p.x) + result.Y.Set(&p.y) + result.Z.SetInt(1) +} + +// IsOnCurve returns whether or not the public key represents a point on the +// secp256k1 curve. +func (p *PublicKey) IsOnCurve() bool { + return isOnCurve(&p.x, &p.y) +} diff --git a/vendor/github.com/lestrrat-go/blackmagic/.gitignore b/vendor/github.com/lestrrat-go/blackmagic/.gitignore new file mode 100644 index 00000000000..66fd13c903c --- /dev/null +++ b/vendor/github.com/lestrrat-go/blackmagic/.gitignore @@ -0,0 +1,15 @@ +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, built with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Dependency directories (remove the comment below to include it) +# vendor/ diff --git a/vendor/github.com/lestrrat-go/blackmagic/LICENSE b/vendor/github.com/lestrrat-go/blackmagic/LICENSE new file mode 100644 index 00000000000..188ea7685c6 --- /dev/null +++ b/vendor/github.com/lestrrat-go/blackmagic/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 lestrrat-go + +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/lestrrat-go/blackmagic/README.md b/vendor/github.com/lestrrat-go/blackmagic/README.md new file mode 100644 index 00000000000..0356f8a72b1 --- /dev/null +++ b/vendor/github.com/lestrrat-go/blackmagic/README.md @@ -0,0 +1,3 @@ +# blackmagic + +Reflect-based black magic. YMMV, and use with caution diff --git a/vendor/github.com/lestrrat-go/blackmagic/blackmagic.go b/vendor/github.com/lestrrat-go/blackmagic/blackmagic.go new file mode 100644 index 00000000000..9c98ac84835 --- /dev/null +++ b/vendor/github.com/lestrrat-go/blackmagic/blackmagic.go @@ -0,0 +1,125 @@ +package blackmagic + +import ( + "fmt" + "reflect" +) + +type errInvalidValue struct{} + +func (*errInvalidValue) Error() string { + return "invalid value (probably an untyped nil)" +} + +// InvalidValueError is a sentinel error that can be used to +// indicate that a value is invalid. This can happen when the +// source value is an untyped nil, and we have no further information +// about the type of the value, obstructing the assignment. +func InvalidValueError() error { + return &errInvalidValue{} +} + +// AssignField is a convenience function to assign a value to +// an optional struct field. In Go, an optional struct field is +// usually denoted by a pointer to T instead of T: +// +// type Object struct { +// Optional *T +// } +// +// This gets a bit cumbersome when you want to assign literals +// or you do not want to worry about taking the address of a +// variable. +// +// Object.Optional = &"foo" // doesn't compile! +// +// Instead you can use this function to do it in one line: +// +// blackmagic.AssignOptionalField(&Object.Optionl, "foo") +func AssignOptionalField(dst, src interface{}) error { + dstRV := reflect.ValueOf(dst) + srcRV := reflect.ValueOf(src) + if dstRV.Kind() != reflect.Pointer || dstRV.Elem().Kind() != reflect.Pointer { + return fmt.Errorf(`dst must be a pointer to a field that is turn a pointer of src (%T)`, src) + } + + if !dstRV.Elem().CanSet() { + return fmt.Errorf(`dst (%T) is not assignable`, dstRV.Elem().Interface()) + } + if !reflect.PointerTo(srcRV.Type()).AssignableTo(dstRV.Elem().Type()) { + return fmt.Errorf(`cannot assign src (%T) to dst (%T)`, src, dst) + } + + ptr := reflect.New(srcRV.Type()) + ptr.Elem().Set(srcRV) + dstRV.Elem().Set(ptr) + return nil +} + +// AssignIfCompatible is a convenience function to safely +// assign arbitrary values. dst must be a pointer to an +// empty interface, or it must be a pointer to a compatible +// variable type that can hold src. +func AssignIfCompatible(dst, src interface{}) error { + orv := reflect.ValueOf(src) // save this value for error reporting + result := orv + + // src can be a pointer or a slice, and the code will slightly change + // depending on this + var srcIsPtr bool + var srcIsSlice bool + switch result.Kind() { + case reflect.Ptr: + srcIsPtr = true + case reflect.Slice: + srcIsSlice = true + } + + rv := reflect.ValueOf(dst) + if rv.Kind() != reflect.Ptr { + return fmt.Errorf(`destination argument to AssignIfCompatible() must be a pointer: %T`, dst) + } + + actualDst := rv + for { + if !actualDst.IsValid() { + return fmt.Errorf(`could not find a valid destination for AssignIfCompatible() (%T)`, dst) + } + if actualDst.CanSet() { + break + } + actualDst = actualDst.Elem() + } + + switch actualDst.Kind() { + case reflect.Interface: + // If it's an interface, we can just assign the pointer to the interface{} + default: + // If it's a pointer to the struct we're looking for, we need to set + // the de-referenced struct + if !srcIsSlice && srcIsPtr { + result = result.Elem() + } + } + + if !result.IsValid() { + // At this point there's nothing we can do. return an error + return fmt.Errorf(`source value is invalid (%T): %w`, src, InvalidValueError()) + } + + if actualDst.Kind() == reflect.Ptr { + actualDst.Set(result.Addr()) + return nil + } + + if !result.Type().AssignableTo(actualDst.Type()) { + return fmt.Errorf(`argument to AssignIfCompatible() must be compatible with %T (was %T)`, orv.Interface(), dst) + } + + if !actualDst.CanSet() { + return fmt.Errorf(`argument to AssignIfCompatible() must be settable`) + } + actualDst.Set(result) + + return nil +} diff --git a/vendor/github.com/lestrrat-go/dsig-secp256k1/.gitignore b/vendor/github.com/lestrrat-go/dsig-secp256k1/.gitignore new file mode 100644 index 00000000000..aaadf736e57 --- /dev/null +++ b/vendor/github.com/lestrrat-go/dsig-secp256k1/.gitignore @@ -0,0 +1,32 @@ +# If you prefer the allow list template instead of the deny list, see community template: +# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore +# +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, built with `go test -c` +*.test + +# Code coverage profiles and other test artifacts +*.out +coverage.* +*.coverprofile +profile.cov + +# Dependency directories (remove the comment below to include it) +# vendor/ + +# Go workspace file +go.work +go.work.sum + +# env file +.env + +# Editor/IDE +# .idea/ +# .vscode/ diff --git a/vendor/github.com/lestrrat-go/dsig-secp256k1/Changes b/vendor/github.com/lestrrat-go/dsig-secp256k1/Changes new file mode 100644 index 00000000000..4dd588a0067 --- /dev/null +++ b/vendor/github.com/lestrrat-go/dsig-secp256k1/Changes @@ -0,0 +1,5 @@ +Changes +======= + +v1.0.0 18 Aug 2025 +* Initial release \ No newline at end of file diff --git a/vendor/github.com/lestrrat-go/dsig-secp256k1/LICENSE b/vendor/github.com/lestrrat-go/dsig-secp256k1/LICENSE new file mode 100644 index 00000000000..1e1f5d199e8 --- /dev/null +++ b/vendor/github.com/lestrrat-go/dsig-secp256k1/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 lestrrat-go + +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/lestrrat-go/dsig-secp256k1/secp256k1.go b/vendor/github.com/lestrrat-go/dsig-secp256k1/secp256k1.go new file mode 100644 index 00000000000..85650efa1cb --- /dev/null +++ b/vendor/github.com/lestrrat-go/dsig-secp256k1/secp256k1.go @@ -0,0 +1,29 @@ +package dsigsecp256k1 + +import ( + "crypto" + + "github.com/decred/dcrd/dcrec/secp256k1/v4" + "github.com/lestrrat-go/dsig" +) + +const ECDSAWithSecp256k1AndSHA256 = "ECDSA_WITH_SECP256K1_AND_SHA256" + +// init adds secp256k1 support when the dsig_secp256k1 build tag is used. +func init() { + // Register ES256K (secp256k1 + SHA256) support using the new API + err := dsig.RegisterAlgorithm(ECDSAWithSecp256k1AndSHA256, dsig.AlgorithmInfo{ + Family: dsig.ECDSA, + Meta: dsig.ECDSAFamilyMeta{ + Hash: crypto.SHA256, + }, + }) + if err != nil { + panic("failed to register secp256k1 algorithm: " + err.Error()) + } +} + +// secp256k1Curve returns the secp256k1 curve. +func Curve() *secp256k1.KoblitzCurve { + return secp256k1.S256() +} diff --git a/vendor/github.com/lestrrat-go/dsig/.gitignore b/vendor/github.com/lestrrat-go/dsig/.gitignore new file mode 100644 index 00000000000..aaadf736e57 --- /dev/null +++ b/vendor/github.com/lestrrat-go/dsig/.gitignore @@ -0,0 +1,32 @@ +# If you prefer the allow list template instead of the deny list, see community template: +# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore +# +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, built with `go test -c` +*.test + +# Code coverage profiles and other test artifacts +*.out +coverage.* +*.coverprofile +profile.cov + +# Dependency directories (remove the comment below to include it) +# vendor/ + +# Go workspace file +go.work +go.work.sum + +# env file +.env + +# Editor/IDE +# .idea/ +# .vscode/ diff --git a/vendor/github.com/lestrrat-go/dsig/Changes b/vendor/github.com/lestrrat-go/dsig/Changes new file mode 100644 index 00000000000..bccce97613e --- /dev/null +++ b/vendor/github.com/lestrrat-go/dsig/Changes @@ -0,0 +1,5 @@ +Changes +======= + +v1.0.0 - 18 Aug 2025 +* Initial release \ No newline at end of file diff --git a/vendor/github.com/lestrrat-go/dsig/LICENSE b/vendor/github.com/lestrrat-go/dsig/LICENSE new file mode 100644 index 00000000000..1e1f5d199e8 --- /dev/null +++ b/vendor/github.com/lestrrat-go/dsig/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 lestrrat-go + +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/lestrrat-go/dsig/README.md b/vendor/github.com/lestrrat-go/dsig/README.md new file mode 100644 index 00000000000..37c194579eb --- /dev/null +++ b/vendor/github.com/lestrrat-go/dsig/README.md @@ -0,0 +1,163 @@ +# github.com/lestrrat-go/dsig [![CI](https://github.com/lestrrat-go/dsig/actions/workflows/ci.yml/badge.svg)](https://github.com/lestrrat-go/dsig/actions/workflows/ci.yml) [![Go Reference](https://pkg.go.dev/badge/github.com/lestrrat-go/dsig.svg)](https://pkg.go.dev/github.com/lestrrat-go/dsig) [![codecov.io](https://codecov.io/github/lestrrat-go/dsig/coverage.svg?branch=v1)](https://codecov.io/github/lestrrat-go/dsig?branch=v1) + +Go module providing low-level digital signature operations. + +While there are many standards for generating and verifying digital signatures, the core operations are virtually the same. This module implements the core functionality of digital signature generation / verifications in a framework agnostic way. + +# Features + +* RSA signatures (PKCS1v15 and PSS) +* ECDSA signatures (P-256, P-384, P-521) +* EdDSA signatures (Ed25519, Ed448) +* HMAC signatures (SHA-256, SHA-384, SHA-512) +* Support for crypto.Signer interface +* Allows for dynamic additions of algorithms in limited cases. + +# SYNOPSIS + + +```go +package examples_test + +import ( + "crypto/ecdsa" + "crypto/ed25519" + "crypto/elliptic" + "crypto/rand" + "crypto/rsa" + "fmt" + + "github.com/lestrrat-go/dsig" +) + +func Example() { + payload := []byte("hello world") + + // RSA signing and verification + { + privKey, err := rsa.GenerateKey(rand.Reader, 2048) + if err != nil { + fmt.Printf("failed to generate RSA key: %s\n", err) + return + } + + // Sign with RSA-PSS SHA256 + signature, err := dsig.Sign(privKey, dsig.RSAPSSWithSHA256, payload, nil) + if err != nil { + fmt.Printf("failed to sign with RSA: %s\n", err) + return + } + + // Verify with RSA-PSS SHA256 + err = dsig.Verify(&privKey.PublicKey, dsig.RSAPSSWithSHA256, payload, signature) + if err != nil { + fmt.Printf("failed to verify RSA signature: %s\n", err) + return + } + } + + // ECDSA signing and verification + { + privKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + if err != nil { + fmt.Printf("failed to generate ECDSA key: %s\n", err) + return + } + + // Sign with ECDSA P-256 SHA256 + signature, err := dsig.Sign(privKey, dsig.ECDSAWithP256AndSHA256, payload, nil) + if err != nil { + fmt.Printf("failed to sign with ECDSA: %s\n", err) + return + } + + // Verify with ECDSA P-256 SHA256 + err = dsig.Verify(&privKey.PublicKey, dsig.ECDSAWithP256AndSHA256, payload, signature) + if err != nil { + fmt.Printf("failed to verify ECDSA signature: %s\n", err) + return + } + } + + // EdDSA signing and verification + { + pubKey, privKey, err := ed25519.GenerateKey(rand.Reader) + if err != nil { + fmt.Printf("failed to generate Ed25519 key: %s\n", err) + return + } + + // Sign with EdDSA + signature, err := dsig.Sign(privKey, dsig.EdDSA, payload, nil) + if err != nil { + fmt.Printf("failed to sign with EdDSA: %s\n", err) + return + } + + // Verify with EdDSA + err = dsig.Verify(pubKey, dsig.EdDSA, payload, signature) + if err != nil { + fmt.Printf("failed to verify EdDSA signature: %s\n", err) + return + } + } + + // HMAC signing and verification + { + key := []byte("secret-key") + + // Sign with HMAC SHA256 + signature, err := dsig.Sign(key, dsig.HMACWithSHA256, payload, nil) + if err != nil { + fmt.Printf("failed to sign with HMAC: %s\n", err) + return + } + + // Verify with HMAC SHA256 + err = dsig.Verify(key, dsig.HMACWithSHA256, payload, signature) + if err != nil { + fmt.Printf("failed to verify HMAC signature: %s\n", err) + return + } + } + // OUTPUT: +} +``` +source: [examples/dsig_readme_example_test.go](https://github.com/lestrrat-go/dsig/blob/v1/examples/dsig_readme_example_test.go) + + +# Supported Algorithms + +| Constant | Algorithm | Key Type | +|----------|-----------|----------| +| `HMACWithSHA256` | HMAC using SHA-256 | []byte | +| `HMACWithSHA384` | HMAC using SHA-384 | []byte | +| `HMACWithSHA512` | HMAC using SHA-512 | []byte | +| `RSAPKCS1v15WithSHA256` | RSA PKCS#1 v1.5 using SHA-256 | *rsa.PrivateKey / *rsa.PublicKey | +| `RSAPKCS1v15WithSHA384` | RSA PKCS#1 v1.5 using SHA-384 | *rsa.PrivateKey / *rsa.PublicKey | +| `RSAPKCS1v15WithSHA512` | RSA PKCS#1 v1.5 using SHA-512 | *rsa.PrivateKey / *rsa.PublicKey | +| `RSAPSSWithSHA256` | RSA PSS using SHA-256 | *rsa.PrivateKey / *rsa.PublicKey | +| `RSAPSSWithSHA384` | RSA PSS using SHA-384 | *rsa.PrivateKey / *rsa.PublicKey | +| `RSAPSSWithSHA512` | RSA PSS using SHA-512 | *rsa.PrivateKey / *rsa.PublicKey | +| `ECDSAWithP256AndSHA256` | ECDSA using P-256 and SHA-256 | *ecdsa.PrivateKey / *ecdsa.PublicKey | +| `ECDSAWithP384AndSHA384` | ECDSA using P-384 and SHA-384 | *ecdsa.PrivateKey / *ecdsa.PublicKey | +| `ECDSAWithP521AndSHA512` | ECDSA using P-521 and SHA-512 | *ecdsa.PrivateKey / *ecdsa.PublicKey | +| `EdDSA` | EdDSA using Ed25519 or Ed448 | ed25519.PrivateKey / ed25519.PublicKey | + +# Description + +This library provides low-level digital signature operations. It does minimal parameter validation for performance, uses strongly typed APIs, and has minimal dependencies. + +# Contributions + +## Issues + +For bug reports and feature requests, please include failing tests when possible. + +## Pull Requests + +Please include tests that exercise your changes. + +# Related Libraries + +* [github.com/lestrrat-go/jwx](https://github.com/lestrrat-go/jwx) - JOSE (JWA/JWE/JWK/JWS/JWT) implementation \ No newline at end of file diff --git a/vendor/github.com/lestrrat-go/dsig/algorithms.go b/vendor/github.com/lestrrat-go/dsig/algorithms.go new file mode 100644 index 00000000000..0895c64764c --- /dev/null +++ b/vendor/github.com/lestrrat-go/dsig/algorithms.go @@ -0,0 +1,37 @@ +package dsig + +// This file defines verbose algorithm name constants that can be mapped to by +// different standards (RFC7518, FIDO, etc.) for interoperability. +// +// The algorithm names are intentionally verbose to avoid any ambiguity about +// the exact cryptographic operations being performed. + +const ( + // HMAC signature algorithms + // These use Hash-based Message Authentication Code with specified hash functions + HMACWithSHA256 = "HMAC_WITH_SHA256" + HMACWithSHA384 = "HMAC_WITH_SHA384" + HMACWithSHA512 = "HMAC_WITH_SHA512" + + // RSA signature algorithms with PKCS#1 v1.5 padding + // These use RSA signatures with PKCS#1 v1.5 padding and specified hash functions + RSAPKCS1v15WithSHA256 = "RSA_PKCS1v15_WITH_SHA256" + RSAPKCS1v15WithSHA384 = "RSA_PKCS1v15_WITH_SHA384" + RSAPKCS1v15WithSHA512 = "RSA_PKCS1v15_WITH_SHA512" + + // RSA signature algorithms with PSS padding + // These use RSA signatures with Probabilistic Signature Scheme (PSS) padding + RSAPSSWithSHA256 = "RSA_PSS_WITH_SHA256" + RSAPSSWithSHA384 = "RSA_PSS_WITH_SHA384" + RSAPSSWithSHA512 = "RSA_PSS_WITH_SHA512" + + // ECDSA signature algorithms + // These use Elliptic Curve Digital Signature Algorithm with specified curves and hash functions + ECDSAWithP256AndSHA256 = "ECDSA_WITH_P256_AND_SHA256" + ECDSAWithP384AndSHA384 = "ECDSA_WITH_P384_AND_SHA384" + ECDSAWithP521AndSHA512 = "ECDSA_WITH_P521_AND_SHA512" + + // EdDSA signature algorithms + // These use Edwards-curve Digital Signature Algorithm (supports Ed25519 and Ed448) + EdDSA = "EDDSA" +) \ No newline at end of file diff --git a/vendor/github.com/lestrrat-go/dsig/crypto_signer.go b/vendor/github.com/lestrrat-go/dsig/crypto_signer.go new file mode 100644 index 00000000000..f81666708b0 --- /dev/null +++ b/vendor/github.com/lestrrat-go/dsig/crypto_signer.go @@ -0,0 +1,45 @@ +package dsig + +import ( + "crypto" + "crypto/rand" + "fmt" + "io" +) + +// cryptosign is a low-level function that signs a payload using a crypto.Signer. +// If hash is crypto.Hash(0), the payload is signed directly without hashing. +// Otherwise, the payload is hashed using the specified hash function before signing. +// +// rr is an io.Reader that provides randomness for signing. If rr is nil, it defaults to rand.Reader. +func cryptosign(signer crypto.Signer, payload []byte, hash crypto.Hash, opts crypto.SignerOpts, rr io.Reader) ([]byte, error) { + if rr == nil { + rr = rand.Reader + } + + var digest []byte + if hash == crypto.Hash(0) { + digest = payload + } else { + h := hash.New() + if _, err := h.Write(payload); err != nil { + return nil, fmt.Errorf(`failed to write payload to hash: %w`, err) + } + digest = h.Sum(nil) + } + return signer.Sign(rr, digest, opts) +} + +// SignCryptoSigner generates a signature using a crypto.Signer interface. +// This function can be used for hardware security modules, smart cards, +// and other implementations of the crypto.Signer interface. +// +// rr is an io.Reader that provides randomness for signing. If rr is nil, it defaults to rand.Reader. +// +// Returns the signature bytes or an error if signing fails. +func SignCryptoSigner(signer crypto.Signer, raw []byte, h crypto.Hash, opts crypto.SignerOpts, rr io.Reader) ([]byte, error) { + if signer == nil { + return nil, fmt.Errorf("dsig.SignCryptoSigner: signer is nil") + } + return cryptosign(signer, raw, h, opts, rr) +} diff --git a/vendor/github.com/lestrrat-go/dsig/dsig.go b/vendor/github.com/lestrrat-go/dsig/dsig.go new file mode 100644 index 00000000000..de6cbdec45a --- /dev/null +++ b/vendor/github.com/lestrrat-go/dsig/dsig.go @@ -0,0 +1,224 @@ +// Package dsig provides digital signature operations for Go. +// It contains low-level signature generation and verification tools that +// can be used by other signing libraries +// +// The package follows these design principles: +// 1. Does minimal checking of input parameters (for performance); callers need to ensure that the parameters are valid. +// 2. All exported functions are strongly typed (i.e. they do not take `any` types unless they absolutely have to). +// 3. Does not rely on other high-level packages (standalone, except for internal packages). +package dsig + +import ( + "crypto" + "crypto/sha256" + "crypto/sha512" + "fmt" + "hash" + "sync" +) + +// Family represents the cryptographic algorithm family +type Family int + +const ( + InvalidFamily Family = iota + HMAC + RSA + ECDSA + EdDSAFamily + maxFamily +) + +// String returns the string representation of the Family +func (f Family) String() string { + switch f { + case HMAC: + return "HMAC" + case RSA: + return "RSA" + case ECDSA: + return "ECDSA" + case EdDSAFamily: + return "EdDSA" + default: + return "InvalidFamily" + } +} + +// AlgorithmInfo contains metadata about a digital signature algorithm +type AlgorithmInfo struct { + Family Family // The cryptographic family (HMAC, RSA, ECDSA, EdDSA) + Meta any // Family-specific metadata +} + +// HMACFamilyMeta contains metadata specific to HMAC algorithms +type HMACFamilyMeta struct { + HashFunc func() hash.Hash // Hash function constructor +} + +// RSAFamilyMeta contains metadata specific to RSA algorithms +type RSAFamilyMeta struct { + Hash crypto.Hash // Hash algorithm + PSS bool // Whether to use PSS padding (false = PKCS#1 v1.5) +} + +// ECDSAFamilyMeta contains metadata specific to ECDSA algorithms +type ECDSAFamilyMeta struct { + Hash crypto.Hash // Hash algorithm +} + +// EdDSAFamilyMeta contains metadata specific to EdDSA algorithms +// Currently EdDSA doesn't need specific metadata, but this provides extensibility +type EdDSAFamilyMeta struct { + // Reserved for future use +} + +var algorithms = make(map[string]AlgorithmInfo) +var muAlgorithms sync.RWMutex + +// RegisterAlgorithm registers a new digital signature algorithm with the specified family and metadata. +// +// info.Meta should contain extra metadata for some algorithms. Currently HMAC, RSA, +// and ECDSA family of algorithms need their respective metadata (HMACFamilyMeta, +// RSAFamilyMeta, and ECDSAFamilyMeta). Metadata for other families are ignored. +func RegisterAlgorithm(name string, info AlgorithmInfo) error { + muAlgorithms.Lock() + defer muAlgorithms.Unlock() + + // Validate the metadata matches the family + switch info.Family { + case HMAC: + if _, ok := info.Meta.(HMACFamilyMeta); !ok { + return fmt.Errorf("invalid HMAC metadata for algorithm %s", name) + } + case RSA: + if _, ok := info.Meta.(RSAFamilyMeta); !ok { + return fmt.Errorf("invalid RSA metadata for algorithm %s", name) + } + case ECDSA: + if _, ok := info.Meta.(ECDSAFamilyMeta); !ok { + return fmt.Errorf("invalid ECDSA metadata for algorithm %s", name) + } + case EdDSAFamily: + // EdDSA metadata is optional for now + default: + return fmt.Errorf("unsupported algorithm family %s for algorithm %s", info.Family, name) + } + + algorithms[name] = info + return nil +} + +// GetAlgorithmInfo retrieves the algorithm information for a given algorithm name. +// Returns the info and true if found, zero value and false if not found. +func GetAlgorithmInfo(name string) (AlgorithmInfo, bool) { + muAlgorithms.RLock() + defer muAlgorithms.RUnlock() + + info, ok := algorithms[name] + return info, ok +} + +func init() { + // Register all standard algorithms with their metadata + toRegister := map[string]AlgorithmInfo{ + // HMAC algorithms + HMACWithSHA256: { + Family: HMAC, + Meta: HMACFamilyMeta{ + HashFunc: sha256.New, + }, + }, + HMACWithSHA384: { + Family: HMAC, + Meta: HMACFamilyMeta{ + HashFunc: sha512.New384, + }, + }, + HMACWithSHA512: { + Family: HMAC, + Meta: HMACFamilyMeta{ + HashFunc: sha512.New, + }, + }, + + // RSA PKCS#1 v1.5 algorithms + RSAPKCS1v15WithSHA256: { + Family: RSA, + Meta: RSAFamilyMeta{ + Hash: crypto.SHA256, + PSS: false, + }, + }, + RSAPKCS1v15WithSHA384: { + Family: RSA, + Meta: RSAFamilyMeta{ + Hash: crypto.SHA384, + PSS: false, + }, + }, + RSAPKCS1v15WithSHA512: { + Family: RSA, + Meta: RSAFamilyMeta{ + Hash: crypto.SHA512, + PSS: false, + }, + }, + + // RSA PSS algorithms + RSAPSSWithSHA256: { + Family: RSA, + Meta: RSAFamilyMeta{ + Hash: crypto.SHA256, + PSS: true, + }, + }, + RSAPSSWithSHA384: { + Family: RSA, + Meta: RSAFamilyMeta{ + Hash: crypto.SHA384, + PSS: true, + }, + }, + RSAPSSWithSHA512: { + Family: RSA, + Meta: RSAFamilyMeta{ + Hash: crypto.SHA512, + PSS: true, + }, + }, + + // ECDSA algorithms + ECDSAWithP256AndSHA256: { + Family: ECDSA, + Meta: ECDSAFamilyMeta{ + Hash: crypto.SHA256, + }, + }, + ECDSAWithP384AndSHA384: { + Family: ECDSA, + Meta: ECDSAFamilyMeta{ + Hash: crypto.SHA384, + }, + }, + ECDSAWithP521AndSHA512: { + Family: ECDSA, + Meta: ECDSAFamilyMeta{ + Hash: crypto.SHA512, + }, + }, + + // EdDSA algorithm + EdDSA: { + Family: EdDSAFamily, + Meta: EdDSAFamilyMeta{}, + }, + } + + for name, info := range toRegister { + if err := RegisterAlgorithm(name, info); err != nil { + panic(fmt.Sprintf("failed to register algorithm %s: %v", name, err)) + } + } +} + diff --git a/vendor/github.com/lestrrat-go/dsig/ecdsa.go b/vendor/github.com/lestrrat-go/dsig/ecdsa.go new file mode 100644 index 00000000000..a04a266919a --- /dev/null +++ b/vendor/github.com/lestrrat-go/dsig/ecdsa.go @@ -0,0 +1,200 @@ +package dsig + +import ( + "crypto" + "crypto/ecdsa" + "crypto/rand" + "encoding/asn1" + "fmt" + "io" + "math/big" + + "github.com/lestrrat-go/dsig/internal/ecutil" +) + + +func ecdsaGetSignerKey(key any) (*ecdsa.PrivateKey, crypto.Signer, bool, error) { + cs, isCryptoSigner := key.(crypto.Signer) + if isCryptoSigner { + if !isValidECDSAKey(key) { + return nil, nil, false, fmt.Errorf(`invalid key type %T for ECDSA algorithm`, key) + } + + switch key.(type) { + case ecdsa.PrivateKey, *ecdsa.PrivateKey: + // if it's ecdsa.PrivateKey, it's more efficient to + // go through the non-crypto.Signer route. Set isCryptoSigner to false + isCryptoSigner = false + } + } + + if isCryptoSigner { + return nil, cs, true, nil + } + + privkey, ok := key.(*ecdsa.PrivateKey) + if !ok { + return nil, nil, false, fmt.Errorf(`invalid key type %T. *ecdsa.PrivateKey is required`, key) + } + return privkey, nil, false, nil +} + +// UnpackASN1ECDSASignature unpacks an ASN.1 encoded ECDSA signature into r and s values. +// This is typically used when working with crypto.Signer interfaces that return ASN.1 encoded signatures. +func UnpackASN1ECDSASignature(signed []byte, r, s *big.Int) error { + // Okay, this is silly, but hear me out. When we use the + // crypto.Signer interface, the PrivateKey is hidden. + // But we need some information about the key (its bit size). + // + // So while silly, we're going to have to make another call + // here and fetch the Public key. + // (This probably means that this information should be cached somewhere) + var p struct { + R *big.Int // TODO: get this from a pool? + S *big.Int + } + if _, err := asn1.Unmarshal(signed, &p); err != nil { + return fmt.Errorf(`failed to unmarshal ASN1 encoded signature: %w`, err) + } + + r.Set(p.R) + s.Set(p.S) + return nil +} + +// UnpackECDSASignature unpacks a JWS-format ECDSA signature into r and s values. +// The signature should be in the format specified by RFC 7515 (r||s as fixed-length byte arrays). +func UnpackECDSASignature(signature []byte, pubkey *ecdsa.PublicKey, r, s *big.Int) error { + keySize := ecutil.CalculateKeySize(pubkey.Curve) + if len(signature) != keySize*2 { + return fmt.Errorf(`invalid signature length for curve %q`, pubkey.Curve.Params().Name) + } + + r.SetBytes(signature[:keySize]) + s.SetBytes(signature[keySize:]) + + return nil +} + +// PackECDSASignature packs the r and s values from an ECDSA signature into a JWS-format byte slice. +// The output format follows RFC 7515: r||s as fixed-length byte arrays. +func PackECDSASignature(r *big.Int, sbig *big.Int, curveBits int) ([]byte, error) { + keyBytes := curveBits / 8 + if curveBits%8 > 0 { + keyBytes++ + } + + // Serialize r and s into fixed-length bytes + rBytes := r.Bytes() + rBytesPadded := make([]byte, keyBytes) + copy(rBytesPadded[keyBytes-len(rBytes):], rBytes) + + sBytes := sbig.Bytes() + sBytesPadded := make([]byte, keyBytes) + copy(sBytesPadded[keyBytes-len(sBytes):], sBytes) + + // Output as r||s + return append(rBytesPadded, sBytesPadded...), nil +} + +// SignECDSA generates an ECDSA signature for the given payload using the specified private key and hash. +// The raw parameter should be the pre-computed signing input (typically header.payload). +// +// rr is an io.Reader that provides randomness for signing. if rr is nil, it defaults to rand.Reader. +func SignECDSA(key *ecdsa.PrivateKey, payload []byte, h crypto.Hash, rr io.Reader) ([]byte, error) { + if !isValidECDSAKey(key) { + return nil, fmt.Errorf(`invalid key type %T for ECDSA algorithm`, key) + } + hh := h.New() + if _, err := hh.Write(payload); err != nil { + return nil, fmt.Errorf(`failed to write payload using ecdsa: %w`, err) + } + digest := hh.Sum(nil) + + if rr == nil { + rr = rand.Reader + } + + // Sign and get r, s values + r, s, err := ecdsa.Sign(rr, key, digest) + if err != nil { + return nil, fmt.Errorf(`failed to sign payload using ecdsa: %w`, err) + } + + return PackECDSASignature(r, s, key.Curve.Params().BitSize) +} + +// SignECDSACryptoSigner generates an ECDSA signature using a crypto.Signer interface. +// This function works with hardware security modules and other crypto.Signer implementations. +// The signature is converted from ASN.1 format to JWS format (r||s). +// +// rr is an io.Reader that provides randomness for signing. If rr is nil, it defaults to rand.Reader. +func SignECDSACryptoSigner(signer crypto.Signer, raw []byte, h crypto.Hash, rr io.Reader) ([]byte, error) { + signed, err := SignCryptoSigner(signer, raw, h, h, rr) + if err != nil { + return nil, fmt.Errorf(`failed to sign payload using crypto.Signer: %w`, err) + } + + return signECDSACryptoSigner(signer, signed) +} + +func signECDSACryptoSigner(signer crypto.Signer, signed []byte) ([]byte, error) { + cpub := signer.Public() + pubkey, ok := cpub.(*ecdsa.PublicKey) + if !ok { + return nil, fmt.Errorf(`expected *ecdsa.PublicKey, got %T`, pubkey) + } + curveBits := pubkey.Curve.Params().BitSize + + var r, s big.Int + if err := UnpackASN1ECDSASignature(signed, &r, &s); err != nil { + return nil, fmt.Errorf(`failed to unpack ASN1 encoded signature: %w`, err) + } + + return PackECDSASignature(&r, &s, curveBits) +} + +func ecdsaVerify(key *ecdsa.PublicKey, buf []byte, h crypto.Hash, r, s *big.Int) error { + hasher := h.New() + hasher.Write(buf) + digest := hasher.Sum(nil) + if !ecdsa.Verify(key, digest, r, s) { + return NewVerificationError("invalid ECDSA signature") + } + return nil +} + +// VerifyECDSA verifies an ECDSA signature for the given payload. +// This function verifies the signature using the specified public key and hash algorithm. +// The payload parameter should be the pre-computed signing input (typically header.payload). +func VerifyECDSA(key *ecdsa.PublicKey, payload, signature []byte, h crypto.Hash) error { + var r, s big.Int + if err := UnpackECDSASignature(signature, key, &r, &s); err != nil { + return fmt.Errorf("dsig.VerifyECDSA: failed to unpack ECDSA signature: %w", err) + } + + return ecdsaVerify(key, payload, h, &r, &s) +} + +// VerifyECDSACryptoSigner verifies an ECDSA signature for crypto.Signer implementations. +// This function is useful for verifying signatures created by hardware security modules +// or other implementations of the crypto.Signer interface. +// The payload parameter should be the pre-computed signing input (typically header.payload). +func VerifyECDSACryptoSigner(signer crypto.Signer, payload, signature []byte, h crypto.Hash) error { + var pubkey *ecdsa.PublicKey + switch cpub := signer.Public(); cpub := cpub.(type) { + case ecdsa.PublicKey: + pubkey = &cpub + case *ecdsa.PublicKey: + pubkey = cpub + default: + return fmt.Errorf(`dsig.VerifyECDSACryptoSigner: expected *ecdsa.PublicKey, got %T`, cpub) + } + + var r, s big.Int + if err := UnpackECDSASignature(signature, pubkey, &r, &s); err != nil { + return fmt.Errorf("dsig.VerifyECDSACryptoSigner: failed to unpack ASN.1 encoded ECDSA signature: %w", err) + } + + return ecdsaVerify(pubkey, payload, h, &r, &s) +} diff --git a/vendor/github.com/lestrrat-go/dsig/eddsa.go b/vendor/github.com/lestrrat-go/dsig/eddsa.go new file mode 100644 index 00000000000..6562da37b8d --- /dev/null +++ b/vendor/github.com/lestrrat-go/dsig/eddsa.go @@ -0,0 +1,44 @@ +package dsig + +import ( + "crypto" + "crypto/ed25519" + "fmt" +) + +func eddsaGetSigner(key any) (crypto.Signer, error) { + // The ed25519.PrivateKey object implements crypto.Signer, so we should + // simply accept a crypto.Signer here. + signer, ok := key.(crypto.Signer) + if ok { + if !isValidEDDSAKey(key) { + return nil, fmt.Errorf(`invalid key type %T for EdDSA algorithm`, key) + } + return signer, nil + } + + // This fallback exists for cases when users give us a pointer instead of non-pointer, etc. + privkey, ok := key.(ed25519.PrivateKey) + if !ok { + return nil, fmt.Errorf(`failed to retrieve ed25519.PrivateKey out of %T`, key) + } + return privkey, nil +} + +// SignEdDSA generates an EdDSA (Ed25519) signature for the given payload. +// The raw parameter should be the pre-computed signing input (typically header.payload). +// EdDSA is deterministic and doesn't require additional hashing of the input. +func SignEdDSA(key ed25519.PrivateKey, payload []byte) ([]byte, error) { + return ed25519.Sign(key, payload), nil +} + +// VerifyEdDSA verifies an EdDSA (Ed25519) signature for the given payload. +// This function verifies the signature using Ed25519 verification algorithm. +// The payload parameter should be the pre-computed signing input (typically header.payload). +// EdDSA is deterministic and provides strong security guarantees without requiring hash function selection. +func VerifyEdDSA(key ed25519.PublicKey, payload, signature []byte) error { + if !ed25519.Verify(key, payload, signature) { + return fmt.Errorf("invalid EdDSA signature") + } + return nil +} diff --git a/vendor/github.com/lestrrat-go/dsig/hmac.go b/vendor/github.com/lestrrat-go/dsig/hmac.go new file mode 100644 index 00000000000..8b2612279d4 --- /dev/null +++ b/vendor/github.com/lestrrat-go/dsig/hmac.go @@ -0,0 +1,45 @@ +package dsig + +import ( + "crypto/hmac" + "fmt" + "hash" +) + +func toHMACKey(dst *[]byte, key any) error { + keyBytes, ok := key.([]byte) + if !ok { + return fmt.Errorf(`dsig.toHMACKey: invalid key type %T. []byte is required`, key) + } + + if len(keyBytes) == 0 { + return fmt.Errorf(`dsig.toHMACKey: missing key while signing payload`) + } + + *dst = keyBytes + return nil +} + +// SignHMAC generates an HMAC signature for the given payload using the specified hash function and key. +// The raw parameter should be the pre-computed signing input (typically header.payload). +func SignHMAC(key, payload []byte, hfunc func() hash.Hash) ([]byte, error) { + h := hmac.New(hfunc, key) + if _, err := h.Write(payload); err != nil { + return nil, fmt.Errorf(`failed to write payload using hmac: %w`, err) + } + return h.Sum(nil), nil +} + +// VerifyHMAC verifies an HMAC signature for the given payload. +// This function verifies the signature using the specified key and hash function. +// The payload parameter should be the pre-computed signing input (typically header.payload). +func VerifyHMAC(key, payload, signature []byte, hfunc func() hash.Hash) error { + expected, err := SignHMAC(key, payload, hfunc) + if err != nil { + return fmt.Errorf("failed to sign payload for verification: %w", err) + } + if !hmac.Equal(signature, expected) { + return NewVerificationError("invalid HMAC signature") + } + return nil +} diff --git a/vendor/github.com/lestrrat-go/dsig/internal/ecutil/ecutil.go b/vendor/github.com/lestrrat-go/dsig/internal/ecutil/ecutil.go new file mode 100644 index 00000000000..cf0bd4ac484 --- /dev/null +++ b/vendor/github.com/lestrrat-go/dsig/internal/ecutil/ecutil.go @@ -0,0 +1,76 @@ +// Package ecutil defines tools that help with elliptic curve related +// computation +package ecutil + +import ( + "crypto/elliptic" + "math/big" + "sync" +) + +const ( + // size of buffer that needs to be allocated for EC521 curve + ec521BufferSize = 66 // (521 / 8) + 1 +) + +var ecpointBufferPool = sync.Pool{ + New: func() any { + // In most cases the curve bit size will be less than this length + // so allocate the maximum, and keep reusing + buf := make([]byte, 0, ec521BufferSize) + return &buf + }, +} + +func getCrvFixedBuffer(size int) []byte { + //nolint:forcetypeassert + buf := *(ecpointBufferPool.Get().(*[]byte)) + if size > ec521BufferSize && cap(buf) < size { + buf = append(buf, make([]byte, size-cap(buf))...) + } + return buf[:size] +} + +// ReleaseECPointBuffer releases the []byte buffer allocated. +func ReleaseECPointBuffer(buf []byte) { + buf = buf[:cap(buf)] + buf[0] = 0x0 + for i := 1; i < len(buf); i *= 2 { + copy(buf[i:], buf[:i]) + } + buf = buf[:0] + ecpointBufferPool.Put(&buf) +} + +func CalculateKeySize(crv elliptic.Curve) int { + // We need to create a buffer that fits the entire curve. + // If the curve size is 66, that fits in 9 bytes. If the curve + // size is 64, it fits in 8 bytes. + bits := crv.Params().BitSize + + // For most common cases we know before hand what the byte length + // is going to be. optimize + var inBytes int + switch bits { + case 224, 256, 384: // TODO: use constant? + inBytes = bits / 8 + case 521: + inBytes = ec521BufferSize + default: + inBytes = bits / 8 + if (bits % 8) != 0 { + inBytes++ + } + } + + return inBytes +} + +// AllocECPointBuffer allocates a buffer for the given point in the given +// curve. This buffer should be released using the ReleaseECPointBuffer +// function. +func AllocECPointBuffer(v *big.Int, crv elliptic.Curve) []byte { + buf := getCrvFixedBuffer(CalculateKeySize(crv)) + v.FillBytes(buf) + return buf +} diff --git a/vendor/github.com/lestrrat-go/dsig/rsa.go b/vendor/github.com/lestrrat-go/dsig/rsa.go new file mode 100644 index 00000000000..a339fe5b782 --- /dev/null +++ b/vendor/github.com/lestrrat-go/dsig/rsa.go @@ -0,0 +1,63 @@ +package dsig + +import ( + "crypto" + "crypto/rsa" + "fmt" + "io" +) + +func rsaGetSignerCryptoSignerKey(key any) (crypto.Signer, bool, error) { + if !isValidRSAKey(key) { + return nil, false, fmt.Errorf(`invalid key type %T for RSA algorithm`, key) + } + cs, isCryptoSigner := key.(crypto.Signer) + if isCryptoSigner { + return cs, true, nil + } + return nil, false, nil +} + +// rsaPSSOptions returns the PSS options for RSA-PSS signatures with the specified hash. +// The salt length is set to equal the hash length as per RFC 7518. +func rsaPSSOptions(h crypto.Hash) rsa.PSSOptions { + return rsa.PSSOptions{ + Hash: h, + SaltLength: rsa.PSSSaltLengthEqualsHash, + } +} + +// SignRSA generates an RSA signature for the given payload using the specified private key and options. +// The raw parameter should be the pre-computed signing input (typically header.payload). +// If pss is true, RSA-PSS is used; otherwise, PKCS#1 v1.5 is used. +// +// The rr parameter is an optional io.Reader that can be used to provide randomness for signing. +// If rr is nil, it defaults to rand.Reader. +func SignRSA(key *rsa.PrivateKey, payload []byte, h crypto.Hash, pss bool, rr io.Reader) ([]byte, error) { + if !isValidRSAKey(key) { + return nil, fmt.Errorf(`invalid key type %T for RSA algorithm`, key) + } + var opts crypto.SignerOpts = h + if pss { + rsaopts := rsaPSSOptions(h) + opts = &rsaopts + } + return cryptosign(key, payload, h, opts, rr) +} + +// VerifyRSA verifies an RSA signature for the given payload and header. +// This function constructs the signing input by encoding the header and payload according to JWS specification, +// then verifies the signature using the specified public key and hash algorithm. +// If pss is true, RSA-PSS verification is used; otherwise, PKCS#1 v1.5 verification is used. +func VerifyRSA(key *rsa.PublicKey, payload, signature []byte, h crypto.Hash, pss bool) error { + if !isValidRSAKey(key) { + return fmt.Errorf(`invalid key type %T for RSA algorithm`, key) + } + hasher := h.New() + hasher.Write(payload) + digest := hasher.Sum(nil) + if pss { + return rsa.VerifyPSS(key, h, digest, signature, &rsa.PSSOptions{Hash: h, SaltLength: rsa.PSSSaltLengthEqualsHash}) + } + return rsa.VerifyPKCS1v15(key, h, digest, signature) +} diff --git a/vendor/github.com/lestrrat-go/dsig/sign.go b/vendor/github.com/lestrrat-go/dsig/sign.go new file mode 100644 index 00000000000..e2a6bde2905 --- /dev/null +++ b/vendor/github.com/lestrrat-go/dsig/sign.go @@ -0,0 +1,100 @@ +package dsig + +import ( + "crypto" + "crypto/rsa" + "fmt" + "io" +) + +// Sign generates a digital signature using the specified key and algorithm. +// +// This function loads the signer registered in the dsig package _ONLY_. +// It does not support custom signers that the user might have registered. +// +// rr is an io.Reader that provides randomness for signing. If rr is nil, it defaults to rand.Reader. +// Not all algorithms require this parameter, but it is included for consistency. +// 99% of the time, you can pass nil for rr, and it will work fine. +func Sign(key any, alg string, payload []byte, rr io.Reader) ([]byte, error) { + info, ok := GetAlgorithmInfo(alg) + if !ok { + return nil, fmt.Errorf(`dsig.Sign: unsupported signature algorithm %q`, alg) + } + + switch info.Family { + case HMAC: + return dispatchHMACSign(key, info, payload) + case RSA: + return dispatchRSASign(key, info, payload, rr) + case ECDSA: + return dispatchECDSASign(key, info, payload, rr) + case EdDSAFamily: + return dispatchEdDSASign(key, info, payload, rr) + default: + return nil, fmt.Errorf(`dsig.Sign: unsupported signature family %q`, info.Family) + } +} + +func dispatchHMACSign(key any, info AlgorithmInfo, payload []byte) ([]byte, error) { + meta, ok := info.Meta.(HMACFamilyMeta) + if !ok { + return nil, fmt.Errorf(`dsig.Sign: invalid HMAC metadata`) + } + + var hmackey []byte + if err := toHMACKey(&hmackey, key); err != nil { + return nil, fmt.Errorf(`dsig.Sign: %w`, err) + } + return SignHMAC(hmackey, payload, meta.HashFunc) +} + +func dispatchRSASign(key any, info AlgorithmInfo, payload []byte, rr io.Reader) ([]byte, error) { + meta, ok := info.Meta.(RSAFamilyMeta) + if !ok { + return nil, fmt.Errorf(`dsig.Sign: invalid RSA metadata`) + } + + cs, isCryptoSigner, err := rsaGetSignerCryptoSignerKey(key) + if err != nil { + return nil, fmt.Errorf(`dsig.Sign: %w`, err) + } + if isCryptoSigner { + var options crypto.SignerOpts = meta.Hash + if meta.PSS { + rsaopts := rsaPSSOptions(meta.Hash) + options = &rsaopts + } + return SignCryptoSigner(cs, payload, meta.Hash, options, rr) + } + + privkey, ok := key.(*rsa.PrivateKey) + if !ok { + return nil, fmt.Errorf(`dsig.Sign: invalid key type %T. *rsa.PrivateKey is required`, key) + } + return SignRSA(privkey, payload, meta.Hash, meta.PSS, rr) +} + +func dispatchEdDSASign(key any, _ AlgorithmInfo, payload []byte, rr io.Reader) ([]byte, error) { + signer, err := eddsaGetSigner(key) + if err != nil { + return nil, fmt.Errorf(`dsig.Sign: %w`, err) + } + + return SignCryptoSigner(signer, payload, crypto.Hash(0), crypto.Hash(0), rr) +} + +func dispatchECDSASign(key any, info AlgorithmInfo, payload []byte, rr io.Reader) ([]byte, error) { + meta, ok := info.Meta.(ECDSAFamilyMeta) + if !ok { + return nil, fmt.Errorf(`dsig.Sign: invalid ECDSA metadata`) + } + + privkey, cs, isCryptoSigner, err := ecdsaGetSignerKey(key) + if err != nil { + return nil, fmt.Errorf(`dsig.Sign: %w`, err) + } + if isCryptoSigner { + return SignECDSACryptoSigner(cs, payload, meta.Hash, rr) + } + return SignECDSA(privkey, payload, meta.Hash, rr) +} diff --git a/vendor/github.com/lestrrat-go/dsig/validation.go b/vendor/github.com/lestrrat-go/dsig/validation.go new file mode 100644 index 00000000000..17682d85384 --- /dev/null +++ b/vendor/github.com/lestrrat-go/dsig/validation.go @@ -0,0 +1,66 @@ +package dsig + +import ( + "crypto/ecdsa" + "crypto/ed25519" + "crypto/rsa" +) + +// isValidRSAKey validates that the provided key type is appropriate for RSA algorithms. +// It returns false if the key is clearly incompatible (e.g., ECDSA or EdDSA keys). +func isValidRSAKey(key any) bool { + switch key.(type) { + case + ecdsa.PrivateKey, *ecdsa.PrivateKey, + ed25519.PrivateKey: + // these are NOT ok for RSA algorithms + return false + } + return true +} + +// isValidECDSAKey validates that the provided key type is appropriate for ECDSA algorithms. +// It returns false if the key is clearly incompatible (e.g., RSA or EdDSA keys). +func isValidECDSAKey(key any) bool { + switch key.(type) { + case + ed25519.PrivateKey, + rsa.PrivateKey, *rsa.PrivateKey: + // these are NOT ok for ECDSA algorithms + return false + } + return true +} + +// isValidEDDSAKey validates that the provided key type is appropriate for EdDSA algorithms. +// It returns false if the key is clearly incompatible (e.g., RSA or ECDSA keys). +func isValidEDDSAKey(key any) bool { + switch key.(type) { + case + ecdsa.PrivateKey, *ecdsa.PrivateKey, + rsa.PrivateKey, *rsa.PrivateKey: + // these are NOT ok for EdDSA algorithms + return false + } + return true +} + +// VerificationError represents an error that occurred during signature verification. +type VerificationError struct { + message string +} + +func (e *VerificationError) Error() string { + return e.message +} + +// NewVerificationError creates a new verification error with the given message. +func NewVerificationError(message string) error { + return &VerificationError{message: message} +} + +// IsVerificationError checks if the given error is a verification error. +func IsVerificationError(err error) bool { + _, ok := err.(*VerificationError) + return ok +} diff --git a/vendor/github.com/lestrrat-go/dsig/verify.go b/vendor/github.com/lestrrat-go/dsig/verify.go new file mode 100644 index 00000000000..86085b0a379 --- /dev/null +++ b/vendor/github.com/lestrrat-go/dsig/verify.go @@ -0,0 +1,134 @@ +package dsig + +import ( + "crypto" + "crypto/ecdsa" + "crypto/ed25519" + "crypto/rsa" + "fmt" +) + +// Verify verifies a digital signature using the specified key and algorithm. +// +// This function loads the verifier registered in the dsig package _ONLY_. +// It does not support custom verifiers that the user might have registered. +func Verify(key any, alg string, payload, signature []byte) error { + info, ok := GetAlgorithmInfo(alg) + if !ok { + return fmt.Errorf(`dsig.Verify: unsupported signature algorithm %q`, alg) + } + + switch info.Family { + case HMAC: + return dispatchHMACVerify(key, info, payload, signature) + case RSA: + return dispatchRSAVerify(key, info, payload, signature) + case ECDSA: + return dispatchECDSAVerify(key, info, payload, signature) + case EdDSAFamily: + return dispatchEdDSAVerify(key, info, payload, signature) + default: + return fmt.Errorf(`dsig.Verify: unsupported signature family %q`, info.Family) + } +} + +func dispatchHMACVerify(key any, info AlgorithmInfo, payload, signature []byte) error { + meta, ok := info.Meta.(HMACFamilyMeta) + if !ok { + return fmt.Errorf(`dsig.Verify: invalid HMAC metadata`) + } + + var hmackey []byte + if err := toHMACKey(&hmackey, key); err != nil { + return fmt.Errorf(`dsig.Verify: %w`, err) + } + return VerifyHMAC(hmackey, payload, signature, meta.HashFunc) +} + +func dispatchRSAVerify(key any, info AlgorithmInfo, payload, signature []byte) error { + meta, ok := info.Meta.(RSAFamilyMeta) + if !ok { + return fmt.Errorf(`dsig.Verify: invalid RSA metadata`) + } + + var pubkey *rsa.PublicKey + + if cs, ok := key.(crypto.Signer); ok { + cpub := cs.Public() + switch cpub := cpub.(type) { + case rsa.PublicKey: + pubkey = &cpub + case *rsa.PublicKey: + pubkey = cpub + default: + return fmt.Errorf(`dsig.Verify: failed to retrieve rsa.PublicKey out of crypto.Signer %T`, key) + } + } else { + var ok bool + pubkey, ok = key.(*rsa.PublicKey) + if !ok { + return fmt.Errorf(`dsig.Verify: failed to retrieve *rsa.PublicKey out of %T`, key) + } + } + + return VerifyRSA(pubkey, payload, signature, meta.Hash, meta.PSS) +} + +func dispatchECDSAVerify(key any, info AlgorithmInfo, payload, signature []byte) error { + meta, ok := info.Meta.(ECDSAFamilyMeta) + if !ok { + return fmt.Errorf(`dsig.Verify: invalid ECDSA metadata`) + } + + pubkey, cs, isCryptoSigner, err := ecdsaGetVerifierKey(key) + if err != nil { + return fmt.Errorf(`dsig.Verify: %w`, err) + } + if isCryptoSigner { + return VerifyECDSACryptoSigner(cs, payload, signature, meta.Hash) + } + return VerifyECDSA(pubkey, payload, signature, meta.Hash) +} + +func dispatchEdDSAVerify(key any, _ AlgorithmInfo, payload, signature []byte) error { + var pubkey ed25519.PublicKey + signer, ok := key.(crypto.Signer) + if ok { + v := signer.Public() + pubkey, ok = v.(ed25519.PublicKey) + if !ok { + return fmt.Errorf(`dsig.Verify: expected crypto.Signer.Public() to return ed25519.PublicKey, but got %T`, v) + } + } else { + var ok bool + pubkey, ok = key.(ed25519.PublicKey) + if !ok { + return fmt.Errorf(`dsig.Verify: failed to retrieve ed25519.PublicKey out of %T`, key) + } + } + + return VerifyEdDSA(pubkey, payload, signature) +} + +func ecdsaGetVerifierKey(key any) (*ecdsa.PublicKey, crypto.Signer, bool, error) { + cs, isCryptoSigner := key.(crypto.Signer) + if isCryptoSigner { + switch key.(type) { + case ecdsa.PublicKey, *ecdsa.PublicKey: + // if it's ecdsa.PublicKey, it's more efficient to + // go through the non-crypto.Signer route. Set isCryptoSigner to false + isCryptoSigner = false + } + } + + if isCryptoSigner { + return nil, cs, true, nil + } + + pubkey, ok := key.(*ecdsa.PublicKey) + if !ok { + return nil, nil, false, fmt.Errorf(`invalid key type %T. *ecdsa.PublicKey is required`, key) + } + + return pubkey, nil, false, nil +} diff --git a/vendor/github.com/lestrrat-go/httpcc/.gitignore b/vendor/github.com/lestrrat-go/httpcc/.gitignore new file mode 100644 index 00000000000..66fd13c903c --- /dev/null +++ b/vendor/github.com/lestrrat-go/httpcc/.gitignore @@ -0,0 +1,15 @@ +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, built with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Dependency directories (remove the comment below to include it) +# vendor/ diff --git a/vendor/github.com/lestrrat-go/httpcc/LICENSE b/vendor/github.com/lestrrat-go/httpcc/LICENSE new file mode 100644 index 00000000000..963209bfba5 --- /dev/null +++ b/vendor/github.com/lestrrat-go/httpcc/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 lestrrat-go + +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/lestrrat-go/httpcc/README.md b/vendor/github.com/lestrrat-go/httpcc/README.md new file mode 100644 index 00000000000..cf2dcb327c7 --- /dev/null +++ b/vendor/github.com/lestrrat-go/httpcc/README.md @@ -0,0 +1,35 @@ +httpcc +====== + +Parses HTTP/1.1 Cache-Control header, and returns a struct that is convenient +for the end-user to do what they will with. + +# Parsing the HTTP Request + +```go +dir, err := httpcc.ParseRequest(req.Header.Get(`Cache-Control`)) +// dir.MaxAge() uint64, bool +// dir.MaxStale() uint64, bool +// dir.MinFresh() uint64, bool +// dir.NoCache() bool +// dir.NoStore() bool +// dir.NoTransform() bool +// dir.OnlyIfCached() bool +// dir.Extensions() map[string]string +``` + +# Parsing the HTTP Response + +```go +directives, err := httpcc.ParseResponse(res.Header.Get(`Cache-Control`)) +// dir.MaxAge() uint64, bool +// dir.MustRevalidate() bool +// dir.NoCache() []string +// dir.NoStore() bool +// dir.NoTransform() bool +// dir.Public() bool +// dir.Private() bool +// dir.SMaxAge() uint64, bool +// dir.Extensions() map[string]string +``` + diff --git a/vendor/github.com/lestrrat-go/httpcc/directives.go b/vendor/github.com/lestrrat-go/httpcc/directives.go new file mode 100644 index 00000000000..86cbbf0b9a9 --- /dev/null +++ b/vendor/github.com/lestrrat-go/httpcc/directives.go @@ -0,0 +1,117 @@ +package httpcc + +type RequestDirective struct { + maxAge *uint64 + maxStale *uint64 + minFresh *uint64 + noCache bool + noStore bool + noTransform bool + onlyIfCached bool + extensions map[string]string +} + +func (d *RequestDirective) MaxAge() (uint64, bool) { + if v := d.maxAge; v != nil { + return *v, true + } + return 0, false +} + +func (d *RequestDirective) MaxStale() (uint64, bool) { + if v := d.maxStale; v != nil { + return *v, true + } + return 0, false +} + +func (d *RequestDirective) MinFresh() (uint64, bool) { + if v := d.minFresh; v != nil { + return *v, true + } + return 0, false +} + +func (d *RequestDirective) NoCache() bool { + return d.noCache +} + +func (d *RequestDirective) NoStore() bool { + return d.noStore +} + +func (d *RequestDirective) NoTransform() bool { + return d.noTransform +} + +func (d *RequestDirective) OnlyIfCached() bool { + return d.onlyIfCached +} + +func (d *RequestDirective) Extensions() map[string]string { + return d.extensions +} + +func (d *RequestDirective) Extension(s string) string { + return d.extensions[s] +} + +type ResponseDirective struct { + maxAge *uint64 + noCache []string + noStore bool + noTransform bool + public bool + private []string + proxyRevalidate bool + sMaxAge *uint64 + extensions map[string]string +} + +func (d *ResponseDirective) MaxAge() (uint64, bool) { + if v := d.maxAge; v != nil { + return *v, true + } + return 0, false +} + +func (d *ResponseDirective) NoCache() []string { + return d.noCache +} + +func (d *ResponseDirective) NoStore() bool { + return d.noStore +} + +func (d *ResponseDirective) NoTransform() bool { + return d.noTransform +} + +func (d *ResponseDirective) Public() bool { + return d.public +} + +func (d *ResponseDirective) Private() []string { + return d.private +} + +func (d *ResponseDirective) ProxyRevalidate() bool { + return d.proxyRevalidate +} + +func (d *ResponseDirective) SMaxAge() (uint64, bool) { + if v := d.sMaxAge; v != nil { + return *v, true + } + return 0, false +} + +func (d *ResponseDirective) Extensions() map[string]string { + return d.extensions +} + +func (d *ResponseDirective) Extension(s string) string { + return d.extensions[s] +} + + diff --git a/vendor/github.com/lestrrat-go/httpcc/httpcc.go b/vendor/github.com/lestrrat-go/httpcc/httpcc.go new file mode 100644 index 00000000000..14679f9b1c3 --- /dev/null +++ b/vendor/github.com/lestrrat-go/httpcc/httpcc.go @@ -0,0 +1,310 @@ +package httpcc + +import ( + "bufio" + "fmt" + "strconv" + "strings" + "unicode/utf8" +) + +const ( + // Request Cache-Control directives + MaxAge = "max-age" // used in response as well + MaxStale = "max-stale" + MinFresh = "min-fresh" + NoCache = "no-cache" // used in response as well + NoStore = "no-store" // used in response as well + NoTransform = "no-transform" // used in response as well + OnlyIfCached = "only-if-cached" + + // Response Cache-Control directive + MustRevalidate = "must-revalidate" + Public = "public" + Private = "private" + ProxyRevalidate = "proxy-revalidate" + SMaxAge = "s-maxage" +) + +type TokenPair struct { + Name string + Value string +} + +type TokenValuePolicy int + +const ( + NoArgument TokenValuePolicy = iota + TokenOnly + QuotedStringOnly + AnyTokenValue +) + +type directiveValidator interface { + Validate(string) TokenValuePolicy +} +type directiveValidatorFn func(string) TokenValuePolicy + +func (fn directiveValidatorFn) Validate(ccd string) TokenValuePolicy { + return fn(ccd) +} + +func responseDirectiveValidator(s string) TokenValuePolicy { + switch s { + case MustRevalidate, NoStore, NoTransform, Public, ProxyRevalidate: + return NoArgument + case NoCache, Private: + return QuotedStringOnly + case MaxAge, SMaxAge: + return TokenOnly + default: + return AnyTokenValue + } +} + +func requestDirectiveValidator(s string) TokenValuePolicy { + switch s { + case MaxAge, MaxStale, MinFresh: + return TokenOnly + case NoCache, NoStore, NoTransform, OnlyIfCached: + return NoArgument + default: + return AnyTokenValue + } +} + +// ParseRequestDirective parses a single token. +func ParseRequestDirective(s string) (*TokenPair, error) { + return parseDirective(s, directiveValidatorFn(requestDirectiveValidator)) +} + +func ParseResponseDirective(s string) (*TokenPair, error) { + return parseDirective(s, directiveValidatorFn(responseDirectiveValidator)) +} + +func parseDirective(s string, ccd directiveValidator) (*TokenPair, error) { + s = strings.TrimSpace(s) + + i := strings.IndexByte(s, '=') + if i == -1 { + return &TokenPair{Name: s}, nil + } + + pair := &TokenPair{Name: strings.TrimSpace(s[:i])} + + if len(s) <= i { + // `key=` feels like it's a parse error, but it's HTTP... + // for now, return as if nothing happened. + return pair, nil + } + + v := strings.TrimSpace(s[i+1:]) + switch ccd.Validate(pair.Name) { + case TokenOnly: + if v[0] == '"' { + return nil, fmt.Errorf(`invalid value for %s (quoted string not allowed)`, pair.Name) + } + case QuotedStringOnly: // quoted-string only + if v[0] != '"' { + return nil, fmt.Errorf(`invalid value for %s (bare token not allowed)`, pair.Name) + } + tmp, err := strconv.Unquote(v) + if err != nil { + return nil, fmt.Errorf(`malformed quoted string in token`) + } + v = tmp + case AnyTokenValue: + if v[0] == '"' { + tmp, err := strconv.Unquote(v) + if err != nil { + return nil, fmt.Errorf(`malformed quoted string in token`) + } + v = tmp + } + case NoArgument: + if len(v) > 0 { + return nil, fmt.Errorf(`received argument to directive %s`, pair.Name) + } + } + + pair.Value = v + return pair, nil +} + +func ParseResponseDirectives(s string) ([]*TokenPair, error) { + return parseDirectives(s, ParseResponseDirective) +} + +func ParseRequestDirectives(s string) ([]*TokenPair, error) { + return parseDirectives(s, ParseRequestDirective) +} + +func parseDirectives(s string, p func(string) (*TokenPair, error)) ([]*TokenPair, error) { + scanner := bufio.NewScanner(strings.NewReader(s)) + scanner.Split(scanCommaSeparatedWords) + + var tokens []*TokenPair + for scanner.Scan() { + tok, err := p(scanner.Text()) + if err != nil { + return nil, fmt.Errorf(`failed to parse token #%d: %w`, len(tokens)+1, err) + } + tokens = append(tokens, tok) + } + return tokens, nil +} + +// isSpace reports whether the character is a Unicode white space character. +// We avoid dependency on the unicode package, but check validity of the implementation +// in the tests. +func isSpace(r rune) bool { + if r <= '\u00FF' { + // Obvious ASCII ones: \t through \r plus space. Plus two Latin-1 oddballs. + switch r { + case ' ', '\t', '\n', '\v', '\f', '\r': + return true + case '\u0085', '\u00A0': + return true + } + return false + } + // High-valued ones. + if '\u2000' <= r && r <= '\u200a' { + return true + } + switch r { + case '\u1680', '\u2028', '\u2029', '\u202f', '\u205f', '\u3000': + return true + } + return false +} + +func scanCommaSeparatedWords(data []byte, atEOF bool) (advance int, token []byte, err error) { + // Skip leading spaces. + start := 0 + for width := 0; start < len(data); start += width { + var r rune + r, width = utf8.DecodeRune(data[start:]) + if !isSpace(r) { + break + } + } + // Scan until we find a comma. Keep track of consecutive whitespaces + // so we remove them from the end result + var ws int + for width, i := 0, start; i < len(data); i += width { + var r rune + r, width = utf8.DecodeRune(data[i:]) + switch { + case isSpace(r): + ws++ + case r == ',': + return i + width, data[start : i-ws], nil + default: + ws = 0 + } + } + + // If we're at EOF, we have a final, non-empty, non-terminated word. Return it. + if atEOF && len(data) > start { + return len(data), data[start : len(data)-ws], nil + } + + // Request more data. + return start, nil, nil +} + +// ParseRequest parses the content of `Cache-Control` header of an HTTP Request. +func ParseRequest(v string) (*RequestDirective, error) { + var dir RequestDirective + tokens, err := ParseRequestDirectives(v) + if err != nil { + return nil, fmt.Errorf(`failed to parse tokens: %w`, err) + } + + for _, token := range tokens { + name := strings.ToLower(token.Name) + switch name { + case MaxAge: + iv, err := strconv.ParseUint(token.Value, 10, 64) + if err != nil { + return nil, fmt.Errorf(`failed to parse max-age: %w`, err) + } + dir.maxAge = &iv + case MaxStale: + iv, err := strconv.ParseUint(token.Value, 10, 64) + if err != nil { + return nil, fmt.Errorf(`failed to parse max-stale: %w`, err) + } + dir.maxStale = &iv + case MinFresh: + iv, err := strconv.ParseUint(token.Value, 10, 64) + if err != nil { + return nil, fmt.Errorf(`failed to parse min-fresh: %w`, err) + } + dir.minFresh = &iv + case NoCache: + dir.noCache = true + case NoStore: + dir.noStore = true + case NoTransform: + dir.noTransform = true + case OnlyIfCached: + dir.onlyIfCached = true + default: + dir.extensions[token.Name] = token.Value + } + } + return &dir, nil +} + +// ParseResponse parses the content of `Cache-Control` header of an HTTP Response. +func ParseResponse(v string) (*ResponseDirective, error) { + tokens, err := ParseResponseDirectives(v) + if err != nil { + return nil, fmt.Errorf(`failed to parse tokens: %w`, err) + } + + var dir ResponseDirective + dir.extensions = make(map[string]string) + for _, token := range tokens { + name := strings.ToLower(token.Name) + switch name { + case MaxAge: + iv, err := strconv.ParseUint(token.Value, 10, 64) + if err != nil { + return nil, fmt.Errorf(`failed to parse max-age: %w`, err) + } + dir.maxAge = &iv + case NoCache: + scanner := bufio.NewScanner(strings.NewReader(token.Value)) + scanner.Split(scanCommaSeparatedWords) + for scanner.Scan() { + dir.noCache = append(dir.noCache, scanner.Text()) + } + case NoStore: + dir.noStore = true + case NoTransform: + dir.noTransform = true + case Public: + dir.public = true + case Private: + scanner := bufio.NewScanner(strings.NewReader(token.Value)) + scanner.Split(scanCommaSeparatedWords) + for scanner.Scan() { + dir.private = append(dir.private, scanner.Text()) + } + case ProxyRevalidate: + dir.proxyRevalidate = true + case SMaxAge: + iv, err := strconv.ParseUint(token.Value, 10, 64) + if err != nil { + return nil, fmt.Errorf(`failed to parse s-maxage: %w`, err) + } + dir.sMaxAge = &iv + default: + dir.extensions[token.Name] = token.Value + } + } + return &dir, nil +} diff --git a/vendor/github.com/lestrrat-go/httprc/v3/.gitignore b/vendor/github.com/lestrrat-go/httprc/v3/.gitignore new file mode 100644 index 00000000000..66fd13c903c --- /dev/null +++ b/vendor/github.com/lestrrat-go/httprc/v3/.gitignore @@ -0,0 +1,15 @@ +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, built with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Dependency directories (remove the comment below to include it) +# vendor/ diff --git a/vendor/github.com/lestrrat-go/httprc/v3/.golangci.yml b/vendor/github.com/lestrrat-go/httprc/v3/.golangci.yml new file mode 100644 index 00000000000..b3af8cfe123 --- /dev/null +++ b/vendor/github.com/lestrrat-go/httprc/v3/.golangci.yml @@ -0,0 +1,95 @@ +version: "2" +linters: + default: all + disable: + - cyclop + - depguard + - dupl + - errorlint + - exhaustive + - forbidigo + - funcorder + - funlen + - gochecknoglobals + - gochecknoinits + - gocognit + - gocritic + - gocyclo + - godot + - godox + - gosec + - gosmopolitan + - govet + - inamedparam + - ireturn + - lll + - maintidx + - makezero + - mnd + - nakedret + - nestif + - nlreturn + - noinlineerr + - nonamedreturns + - paralleltest + - tagliatelle + - testpackage + - thelper + - varnamelen + - wrapcheck + - wsl + - wsl_v5 + settings: + govet: + disable: + - shadow + - fieldalignment + enable-all: true + exclusions: + generated: lax + presets: + - comments + - common-false-positives + - legacy + - std-error-handling + rules: + - linters: + - staticcheck + path: /*.go + text: 'ST1003: should not use underscores in package names' + - linters: + - revive + path: /*.go + text: don't use an underscore in package name + - linters: + - contextcheck + - exhaustruct + path: /*.go + - linters: + - errcheck + path: /main.go + - linters: + - errcheck + - errchkjson + - forcetypeassert + path: /*_test.go + - linters: + - forbidigo + path: /*_example_test.go + paths: + - third_party$ + - builtin$ + - examples$ +issues: + max-issues-per-linter: 0 + max-same-issues: 0 +formatters: + enable: + - gofmt + - goimports + exclusions: + generated: lax + paths: + - third_party$ + - builtin$ + - examples$ diff --git a/vendor/github.com/lestrrat-go/httprc/v3/Changes b/vendor/github.com/lestrrat-go/httprc/v3/Changes new file mode 100644 index 00000000000..4dc6f9f4b10 --- /dev/null +++ b/vendor/github.com/lestrrat-go/httprc/v3/Changes @@ -0,0 +1,30 @@ +Changes +======= + +v3.0.1 18 Aug 2025 +* Refresh() no longer requires the resource to be ready. + +v3.0.0 5 Jun 2025 +[Breaking Changes] + * The entire API has been re-imagined for Go versions that allow typed parameters + +v2.0.0 19 Feb 2024 +[Breaking Changes] + * `Fetcher` type is no longer available. You probably want to provide + a customg HTTP client instead via httprc.WithHTTPClient()). + * + +v1.0.4 19 Jul 2022 + * Fix sloppy API breakage + +v1.0.3 19 Jul 2022 + * Fix queue insertion in the middle of the queue (#7) + +v1.0.2 13 Jun 2022 + * Properly release a lock when the fetch fails (#5) + +v1.0.1 29 Mar 2022 + * Bump dependency for github.com/lestrrat-go/httpcc to v1.0.1 + +v1.0.0 29 Mar 2022 + * Initial release, refactored out of github.com/lestrrat-go/jwx diff --git a/vendor/github.com/lestrrat-go/httprc/v3/LICENSE b/vendor/github.com/lestrrat-go/httprc/v3/LICENSE new file mode 100644 index 00000000000..3e196892cab --- /dev/null +++ b/vendor/github.com/lestrrat-go/httprc/v3/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022 lestrrat + +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/lestrrat-go/httprc/v3/README.md b/vendor/github.com/lestrrat-go/httprc/v3/README.md new file mode 100644 index 00000000000..68239669a20 --- /dev/null +++ b/vendor/github.com/lestrrat-go/httprc/v3/README.md @@ -0,0 +1,172 @@ +# github.com/lestrrat-go/httprc/v3 ![](https://github.com/lestrrat-go/httprc/v3/workflows/CI/badge.svg) [![Go Reference](https://pkg.go.dev/badge/github.com/lestrrat-go/httprc/v3.svg)](https://pkg.go.dev/github.com/lestrrat-go/httprc/v3) + +`httprc` is a HTTP "Refresh" Cache. Its aim is to cache a remote resource that +can be fetched via HTTP, but keep the cached content up-to-date based on periodic +refreshing. + +# Client + +A `httprc.Client` object is comprised of 3 parts: The user-facing controller API, +the main controller loop, and set of workers that perform the actual fetching. + +The user-facing controller API is the object returned when you call `(httprc.Client).Start`. + +```go +ctrl, _ := client.Start(ctx) +``` + +# Controller API + +The controller API gives you access to the controller backend that runs asynchronously. +All methods take a `context.Context` object because they potentially block. You should +be careful to use `context.WithTimeout` to properly set a timeout if you cannot tolerate +a blocking operation. + +# Main Controller Loop + +The main controller loop is run asynchronously to the controller API. It is single threaded, +and it has two reponsibilities. + +The first is to receive commands from the controller API, +and appropriately modify the state of the goroutine, i.e. modify the list of resources +it is watching, performing forced refreshes, etc. + +The other is to periodically wake up and go through the list of resources and re-fetch +ones that are past their TTL (in reality, each resource carry a "next-check" time, not +a TTL). The main controller loop itself does nothing more: it just kicks these checks periodically. + +The interval between fetches is changed dynamically based on either the metadata carried +with the HTTP responses, such as `Cache-Control` and `Expires` headers, or a constant +interval set by the user for a given resource. Between these values, the main controller loop +will pick the shortest interval (but no less than 1 second) and checks if resources +need updating based on that value. + +For example, if a resource A has an expiry of 10 minutes and if resource has an expiry of 5 +minutes, the main controller loop will attempt to wake up roughly every 5 minutes to check +on the resources. + +When the controller loop detects that a resource needs to be checked for freshness, +it will send the resource to the worker pool to be synced. + +# Interval calculation + +After the resource is synced, the next fetch is scheduled. The interval to the next +fetch is calculated either by using constant intervals, or by heuristics using values +from the `http.Response` object. + +If the constant interval is specified, no extra calculation is performed. If you specify +a constant interval of 15 minutes, the resource will be checked every 15 minutes. This is +predictable and reliable, but not necessarily efficient. + +If you do not specify a constant interval, the HTTP response is analyzed for +values in `Cache-Control` and `Expires` headers. These values will be compared against +a maximum and minimum interval values, which default to 30 days and 15 minutes, respectively. +If the values obtained from the headers fall within that range, the value from the header is +used. If the value is larger than the maximum, the maximum is used. If the value is lower +than the minimum, the minimum is used. + +# SYNOPSIS + + +```go +package httprc_test + +import ( + "context" + "encoding/json" + "fmt" + "net/http" + "net/http/httptest" + "time" + + "github.com/lestrrat-go/httprc/v3" +) + +func ExampleClient() { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + type HelloWorld struct { + Hello string `json:"hello"` + } + + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + json.NewEncoder(w).Encode(map[string]string{"hello": "world"}) + })) + + options := []httprc.NewClientOption{ + // By default the client will allow all URLs (which is what the option + // below is explicitly specifying). If you want to restrict what URLs + // are allowed, you can specify another whitelist. + // + // httprc.WithWhitelist(httprc.NewInsecureWhitelist()), + } + // If you would like to handle errors from asynchronous workers, you can specify a error sink. + // This is disabled in this example because the trace logs are dynamic + // and thus would interfere with the runnable example test. + // options = append(options, httprc.WithErrorSink(errsink.NewSlog(slog.New(slog.NewJSONHandler(os.Stdout, nil))))) + + // If you would like to see the trace logs, you can specify a trace sink. + // This is disabled in this example because the trace logs are dynamic + // and thus would interfere with the runnable example test. + // options = append(options, httprc.WithTraceSink(tracesink.NewSlog(slog.New(slog.NewJSONHandler(os.Stdout, nil))))) + + // Create a new client + cl := httprc.NewClient(options...) + + // Start the client, and obtain a Controller object + ctrl, err := cl.Start(ctx) + if err != nil { + fmt.Println(err.Error()) + return + } + // The following is required if you want to make sure that there are no + // dangling goroutines hanging around when you exit. For example, if you + // are running tests to check for goroutine leaks, you should call this + // function before the end of your test. + defer ctrl.Shutdown(time.Second) + + // Create a new resource that is synchronized every so often + // + // By default the client will attempt to fetch the resource once + // as soon as it can, and then if no other metadata is provided, + // it will fetch the resource every 15 minutes. + // + // If the resource responds with a Cache-Control/Expires header, + // the client will attempt to respect that, and will try to fetch + // the resource again based on the values obatained from the headers. + r, err := httprc.NewResource[HelloWorld](srv.URL, httprc.JSONTransformer[HelloWorld]()) + if err != nil { + fmt.Println(err.Error()) + return + } + + // Add the resource to the controller, so that it starts fetching. + // By default, a call to `Add()` will block until the first fetch + // succeeds, via an implicit call to `r.Ready()` + // You can change this behavior if you specify the `WithWaitReady(false)` + // option. + ctrl.Add(ctx, r) + + // if you specified `httprc.WithWaitReady(false)` option, the fetch will happen + // "soon", but you're not guaranteed that it will happen before the next + // call to `Lookup()`. If you want to make sure that the resource is ready, + // you can call `Ready()` like so: + /* + { + tctx, tcancel := context.WithTimeout(ctx, time.Second) + defer tcancel() + if err := r.Ready(tctx); err != nil { + fmt.Println(err.Error()) + return + } + } + */ + m := r.Resource() + fmt.Println(m.Hello) + // OUTPUT: + // world +} +``` +source: [client_example_test.go](https://github.com/lestrrat-go/httprc/blob/refs/heads/v3/client_example_test.go) + diff --git a/vendor/github.com/lestrrat-go/httprc/v3/backend.go b/vendor/github.com/lestrrat-go/httprc/v3/backend.go new file mode 100644 index 00000000000..31f9fc07d31 --- /dev/null +++ b/vendor/github.com/lestrrat-go/httprc/v3/backend.go @@ -0,0 +1,235 @@ +package httprc + +import ( + "context" + "fmt" + "sync" + "time" +) + +func (c *ctrlBackend) adjustInterval(ctx context.Context, req adjustIntervalRequest) { + interval := roundupToSeconds(time.Until(req.resource.Next())) + c.traceSink.Put(ctx, fmt.Sprintf("httprc controller: got adjust request (current tick interval=%s, next for %q=%s)", c.tickInterval, req.resource.URL(), interval)) + + if interval < time.Second { + interval = time.Second + } + + if c.tickInterval < interval { + c.traceSink.Put(ctx, fmt.Sprintf("httprc controller: no adjusting required (time to next check %s > current tick interval %s)", interval, c.tickInterval)) + } else { + c.traceSink.Put(ctx, fmt.Sprintf("httprc controller: adjusting tick interval to %s", interval)) + c.tickInterval = interval + c.check.Reset(interval) + } +} + +func (c *ctrlBackend) addResource(ctx context.Context, req addRequest) { + r := req.resource + if _, ok := c.items[r.URL()]; ok { + // Already exists + sendReply(ctx, req.reply, struct{}{}, errResourceAlreadyExists) + return + } + c.items[r.URL()] = r + + if r.MaxInterval() == 0 { + r.SetMaxInterval(c.defaultMaxInterval) + } + + if r.MinInterval() == 0 { + c.traceSink.Put(ctx, fmt.Sprintf("httprc controller: set minimum interval to %s", c.defaultMinInterval)) + r.SetMinInterval(c.defaultMinInterval) + } + + c.traceSink.Put(ctx, fmt.Sprintf("httprc controller: added resource %q", r.URL())) + sendReply(ctx, req.reply, struct{}{}, nil) + c.SetTickInterval(time.Nanosecond) +} + +func (c *ctrlBackend) rmResource(ctx context.Context, req rmRequest) { + u := req.u + if _, ok := c.items[u]; !ok { + sendReply(ctx, req.reply, struct{}{}, errResourceNotFound) + return + } + + delete(c.items, u) + + minInterval := oneDay + for _, item := range c.items { + if d := item.MinInterval(); d < minInterval { + minInterval = d + } + } + + close(req.reply) + c.check.Reset(minInterval) +} + +func (c *ctrlBackend) refreshResource(ctx context.Context, req refreshRequest) { + c.traceSink.Put(ctx, fmt.Sprintf("httprc controller: [refresh] START %q", req.u)) + defer c.traceSink.Put(ctx, fmt.Sprintf("httprc controller: [refresh] END %q", req.u)) + u := req.u + + r, ok := c.items[u] + if !ok { + c.traceSink.Put(ctx, fmt.Sprintf("httprc controller: [refresh] %s is not registered", req.u)) + sendReply(ctx, req.reply, struct{}{}, errResourceNotFound) + return + } + + // Note: We don't wait for r.Ready() here because refresh should work + // regardless of whether the resource has been fetched before. This allows + // refresh to work with resources registered using WithWaitReady(false). + + r.SetNext(time.Unix(0, 0)) + sendWorkerSynchronous(ctx, c.syncoutgoing, synchronousRequest{ + resource: r, + reply: req.reply, + }) + c.traceSink.Put(ctx, fmt.Sprintf("httprc controller: [refresh] sync request for %s sent to worker pool", req.u)) +} + +func (c *ctrlBackend) lookupResource(ctx context.Context, req lookupRequest) { + u := req.u + r, ok := c.items[u] + if !ok { + sendReply(ctx, req.reply, nil, errResourceNotFound) + return + } + sendReply(ctx, req.reply, r, nil) +} + +func (c *ctrlBackend) handleRequest(ctx context.Context, req any) { + switch req := req.(type) { + case adjustIntervalRequest: + c.adjustInterval(ctx, req) + case addRequest: + c.addResource(ctx, req) + case rmRequest: + c.rmResource(ctx, req) + case refreshRequest: + c.refreshResource(ctx, req) + case lookupRequest: + c.lookupResource(ctx, req) + default: + c.traceSink.Put(ctx, fmt.Sprintf("httprc controller: unknown request type %T", req)) + } +} + +func sendWorker(ctx context.Context, ch chan Resource, r Resource) { + r.SetBusy(true) + select { + case <-ctx.Done(): + case ch <- r: + } +} + +func sendWorkerSynchronous(ctx context.Context, ch chan synchronousRequest, r synchronousRequest) { + r.resource.SetBusy(true) + select { + case <-ctx.Done(): + case ch <- r: + } +} + +func sendReply[T any](ctx context.Context, ch chan backendResponse[T], v T, err error) { + defer close(ch) + select { + case <-ctx.Done(): + case ch <- backendResponse[T]{payload: v, err: err}: + } +} + +type ctrlBackend struct { + items map[string]Resource + outgoing chan Resource + syncoutgoing chan synchronousRequest + incoming chan any // incoming requests to the controller + traceSink TraceSink + tickInterval time.Duration + check *time.Ticker + defaultMaxInterval time.Duration + defaultMinInterval time.Duration +} + +func (c *ctrlBackend) loop(ctx context.Context, readywg, donewg *sync.WaitGroup) { + c.traceSink.Put(ctx, "httprc controller: starting main controller loop") + readywg.Done() + defer c.traceSink.Put(ctx, "httprc controller: stopping main controller loop") + defer donewg.Done() + for { + c.traceSink.Put(ctx, fmt.Sprintf("httprc controller: waiting for request or tick (tick interval=%s)", c.tickInterval)) + select { + case req := <-c.incoming: + c.traceSink.Put(ctx, fmt.Sprintf("httprc controller: got request %T", req)) + c.handleRequest(ctx, req) + case t := <-c.check.C: + c.periodicCheck(ctx, t) + case <-ctx.Done(): + return + } + } +} + +func (c *ctrlBackend) periodicCheck(ctx context.Context, t time.Time) { + c.traceSink.Put(ctx, "httprc controller: START periodic check") + defer c.traceSink.Put(ctx, "httprc controller: END periodic check") + var minNext time.Time + var dispatched int + minInterval := -1 * time.Second + for _, item := range c.items { + c.traceSink.Put(ctx, fmt.Sprintf("httprc controller: checking resource %q", item.URL())) + + next := item.Next() + if minNext.IsZero() || next.Before(minNext) { + minNext = next + } + + if interval := item.MinInterval(); minInterval < 0 || interval < minInterval { + minInterval = interval + } + + c.traceSink.Put(ctx, fmt.Sprintf("httprc controller: resource %q isBusy=%t, next(%s).After(%s)=%t", item.URL(), item.IsBusy(), next, t, next.After(t))) + if item.IsBusy() || next.After(t) { + c.traceSink.Put(ctx, fmt.Sprintf("httprc controller: resource %q is busy or not ready yet, skipping", item.URL())) + continue + } + c.traceSink.Put(ctx, fmt.Sprintf("httprc controller: resource %q is ready, dispatching to worker pool", item.URL())) + + dispatched++ + c.traceSink.Put(ctx, fmt.Sprintf("httprc controller: dispatching resource %q to worker pool", item.URL())) + sendWorker(ctx, c.outgoing, item) + } + + c.traceSink.Put(ctx, fmt.Sprintf("httprc controller: dispatched %d resources", dispatched)) + + // Next check is always at the earliest next check + 1 second. + // The extra second makes sure that we are _past_ the actual next check time + // so we can send the resource to the worker pool + if interval := time.Until(minNext); interval > 0 { + c.SetTickInterval(roundupToSeconds(interval) + time.Second) + c.traceSink.Put(ctx, fmt.Sprintf("httprc controller: resetting check intervanl to %s", c.tickInterval)) + } else { + // if we got here, either we have no resources, or all resources are busy. + // In this state, it's possible that the interval is less than 1 second, + // because we previously set it to a small value for an immediate refresh. + // in this case, we want to reset it to a sane value + if c.tickInterval < time.Second { + c.SetTickInterval(minInterval) + c.traceSink.Put(ctx, fmt.Sprintf("httprc controller: resetting check intervanl to %s after forced refresh", c.tickInterval)) + } + } + + c.traceSink.Put(ctx, fmt.Sprintf("httprc controller: next check in %s", c.tickInterval)) +} + +func (c *ctrlBackend) SetTickInterval(d time.Duration) { + // TODO synchronize + if d <= 0 { + d = time.Second // ensure positive interval + } + c.tickInterval = d + c.check.Reset(d) +} diff --git a/vendor/github.com/lestrrat-go/httprc/v3/client.go b/vendor/github.com/lestrrat-go/httprc/v3/client.go new file mode 100644 index 00000000000..75ac3fc188c --- /dev/null +++ b/vendor/github.com/lestrrat-go/httprc/v3/client.go @@ -0,0 +1,183 @@ +package httprc + +import ( + "context" + "net/http" + "sync" + "time" + + "github.com/lestrrat-go/httprc/v3/errsink" + "github.com/lestrrat-go/httprc/v3/proxysink" + "github.com/lestrrat-go/httprc/v3/tracesink" +) + +// setupSink creates and starts a proxy for the given sink if it's not a Nop sink +// Returns the sink to use and a cancel function that should be chained with the original cancel +func setupSink[T any, S proxysink.Backend[T], NopType any](ctx context.Context, sink S, wg *sync.WaitGroup) (S, context.CancelFunc) { + if _, ok := any(sink).(NopType); ok { + return sink, func() {} + } + + proxy := proxysink.New[T](sink) + wg.Add(1) + go func(ctx context.Context, wg *sync.WaitGroup, proxy *proxysink.Proxy[T]) { + defer wg.Done() + proxy.Run(ctx) + }(ctx, wg, proxy) + + // proxy can be converted to one of the sink subtypes + s, ok := any(proxy).(S) + if !ok { + panic("type assertion failed: proxy cannot be converted to type S") + } + return s, proxy.Close +} + +// Client is the main entry point for the httprc package. +type Client struct { + mu sync.Mutex + httpcl HTTPClient + numWorkers int + running bool + errSink ErrorSink + traceSink TraceSink + wl Whitelist + defaultMaxInterval time.Duration + defaultMinInterval time.Duration +} + +// NewClient creates a new `httprc.Client` object. +// +// By default ALL urls are allowed. This may not be suitable for you if +// are using this in a production environment. You are encouraged to specify +// a whitelist using the `WithWhitelist` option. +func NewClient(options ...NewClientOption) *Client { + //nolint:staticcheck + var errSink ErrorSink = errsink.NewNop() + //nolint:staticcheck + var traceSink TraceSink = tracesink.NewNop() + var wl Whitelist = InsecureWhitelist{} + var httpcl HTTPClient = http.DefaultClient + + defaultMinInterval := DefaultMinInterval + defaultMaxInterval := DefaultMaxInterval + + numWorkers := DefaultWorkers + //nolint:forcetypeassert + for _, option := range options { + switch option.Ident() { + case identHTTPClient{}: + httpcl = option.Value().(HTTPClient) + case identWorkers{}: + numWorkers = option.Value().(int) + case identErrorSink{}: + errSink = option.Value().(ErrorSink) + case identTraceSink{}: + traceSink = option.Value().(TraceSink) + case identWhitelist{}: + wl = option.Value().(Whitelist) + } + } + + if numWorkers <= 0 { + numWorkers = 1 + } + return &Client{ + httpcl: httpcl, + numWorkers: numWorkers, + errSink: errSink, + traceSink: traceSink, + wl: wl, + + defaultMinInterval: defaultMinInterval, + defaultMaxInterval: defaultMaxInterval, + } +} + +// Start sets the client into motion. It will start a number of worker goroutines, +// and return a Controller object that you can use to control the execution of +// the client. +// +// If you attempt to call Start more than once, it will return an error. +func (c *Client) Start(octx context.Context) (Controller, error) { + c.mu.Lock() + if c.running { + c.mu.Unlock() + return nil, errAlreadyRunning + } + c.running = true + c.mu.Unlock() + + // DON'T CANCEL THIS IN THIS METHOD! It's the responsibility of the + // controller to cancel this context. + ctx, cancel := context.WithCancel(octx) + + var donewg sync.WaitGroup + + // start proxy goroutines that will accept sink requests + // and forward them to the appropriate sink + errSink, errCancel := setupSink[error, ErrorSink, errsink.Nop](ctx, c.errSink, &donewg) + traceSink, traceCancel := setupSink[string, TraceSink, tracesink.Nop](ctx, c.traceSink, &donewg) + + // Chain the cancel functions + ocancel := cancel + cancel = func() { + ocancel() + errCancel() + traceCancel() + } + + chbuf := c.numWorkers + 1 + incoming := make(chan any, chbuf) + outgoing := make(chan Resource, chbuf) + syncoutgoing := make(chan synchronousRequest, chbuf) + + var readywg sync.WaitGroup + readywg.Add(c.numWorkers) + donewg.Add(c.numWorkers) + for range c.numWorkers { + wrk := worker{ + incoming: incoming, + next: outgoing, + nextsync: syncoutgoing, + errSink: errSink, + traceSink: traceSink, + httpcl: c.httpcl, + } + go wrk.Run(ctx, &readywg, &donewg) + } + + tickInterval := oneDay + ctrl := &controller{ + cancel: cancel, + incoming: incoming, + shutdown: make(chan struct{}), + traceSink: traceSink, + wl: c.wl, + } + + backend := &ctrlBackend{ + items: make(map[string]Resource), + outgoing: outgoing, + syncoutgoing: syncoutgoing, + incoming: incoming, + traceSink: traceSink, + tickInterval: tickInterval, + check: time.NewTicker(tickInterval), + + defaultMinInterval: c.defaultMinInterval, + defaultMaxInterval: c.defaultMaxInterval, + } + donewg.Add(1) + readywg.Add(1) + go backend.loop(ctx, &readywg, &donewg) + + go func(wg *sync.WaitGroup, ch chan struct{}) { + wg.Wait() + close(ch) + }(&donewg, ctrl.shutdown) + + readywg.Wait() + + return ctrl, nil +} diff --git a/vendor/github.com/lestrrat-go/httprc/v3/controller.go b/vendor/github.com/lestrrat-go/httprc/v3/controller.go new file mode 100644 index 00000000000..ae2eb218e42 --- /dev/null +++ b/vendor/github.com/lestrrat-go/httprc/v3/controller.go @@ -0,0 +1,186 @@ +package httprc + +import ( + "context" + "fmt" + "time" +) + +type Controller interface { + // Add adds a new `http.Resource` to the controller. If the resource already exists, + // it will return an error. + Add(context.Context, Resource, ...AddOption) error + + // Lookup a `httprc.Resource` by its URL. If the resource does not exist, it + // will return an error. + Lookup(context.Context, string) (Resource, error) + + // Remove a `httprc.Resource` from the controller by its URL. If the resource does + // not exist, it will return an error. + Remove(context.Context, string) error + + // Refresh forces a resource to be refreshed immediately. If the resource does + // not exist, or if the refresh fails, it will return an error. + Refresh(context.Context, string) error + + ShutdownContext(context.Context) error + Shutdown(time.Duration) error +} + +type controller struct { + cancel context.CancelFunc + incoming chan any // incoming requests to the controller + shutdown chan struct{} + traceSink TraceSink + wl Whitelist +} + +// Shutdown is a convenience function that calls ShutdownContext with a +// context that has a timeout of `timeout`. +func (c *controller) Shutdown(timeout time.Duration) error { + ctx, cancel := context.WithTimeout(context.Background(), timeout) + defer cancel() + return c.ShutdownContext(ctx) +} + +// ShutdownContext stops the client and all associated goroutines, and waits for them +// to finish. If the context is canceled, the function will return immediately: +// there fore you should not use the context you used to start the client (because +// presumably it's already canceled). +// +// Waiting for the client shutdown will also ensure that all sinks are properly +// flushed. +func (c *controller) ShutdownContext(ctx context.Context) error { + c.cancel() + + select { + case <-ctx.Done(): + return ctx.Err() + case <-c.shutdown: + return nil + } +} + +type ctrlRequest[T any] struct { + reply chan T + resource Resource + u string +} +type addRequest ctrlRequest[backendResponse[struct{}]] +type rmRequest ctrlRequest[backendResponse[struct{}]] +type refreshRequest ctrlRequest[backendResponse[struct{}]] +type lookupRequest ctrlRequest[backendResponse[Resource]] +type synchronousRequest ctrlRequest[backendResponse[struct{}]] +type adjustIntervalRequest struct { + resource Resource +} + +type backendResponse[T any] struct { + payload T + err error +} + +func sendBackend[TReq any, TB any](ctx context.Context, backendCh chan any, v TReq, replyCh chan backendResponse[TB]) (TB, error) { + select { + case <-ctx.Done(): + case backendCh <- v: + } + + select { + case <-ctx.Done(): + var zero TB + return zero, ctx.Err() + case res := <-replyCh: + return res.payload, res.err + } +} + +// Lookup returns a resource by its URL. If the resource does not exist, it +// will return an error. +// +// Unfortunately, due to the way typed parameters are handled in Go, we can only +// return a Resource object (and not a ResourceBase[T] object). This means that +// you will either need to use the `Resource.Get()` method or use a type +// assertion to obtain a `ResourceBase[T]` to get to the actual object you are +// looking for +func (c *controller) Lookup(ctx context.Context, u string) (Resource, error) { + reply := make(chan backendResponse[Resource], 1) + req := lookupRequest{ + reply: reply, + u: u, + } + return sendBackend[lookupRequest, Resource](ctx, c.incoming, req, reply) +} + +// Add adds a new resource to the controller. If the resource already +// exists, it will return an error. +// +// By default this function will automatically wait for the resource to be +// fetched once (by calling `r.Ready()`). Note that the `r.Ready()` call will NOT +// timeout unless you configure your context object with `context.WithTimeout`. +// To disable waiting, you can specify the `WithWaitReady(false)` option. +func (c *controller) Add(ctx context.Context, r Resource, options ...AddOption) error { + c.traceSink.Put(ctx, fmt.Sprintf("httprc controller: START Add(%q)", r.URL())) + defer c.traceSink.Put(ctx, fmt.Sprintf("httprc controller: END Add(%q)", r.URL())) + waitReady := true + //nolint:forcetypeassert + for _, option := range options { + switch option.Ident() { + case identWaitReady{}: + waitReady = option.(addOption).Value().(bool) + } + } + + if !c.wl.IsAllowed(r.URL()) { + return fmt.Errorf(`httprc.Controller.AddResource: cannot add %q: %w`, r.URL(), errBlockedByWhitelist) + } + + reply := make(chan backendResponse[struct{}], 1) + req := addRequest{ + reply: reply, + resource: r, + } + c.traceSink.Put(ctx, fmt.Sprintf("httprc controller: sending add request for %q to backend", r.URL())) + if _, err := sendBackend[addRequest, struct{}](ctx, c.incoming, req, reply); err != nil { + return err + } + + if waitReady { + c.traceSink.Put(ctx, fmt.Sprintf("httprc controller: waiting for resource %q to be ready", r.URL())) + if err := r.Ready(ctx); err != nil { + return err + } + } + return nil +} + +// Remove removes a resource from the controller. If the resource does +// not exist, it will return an error. +func (c *controller) Remove(ctx context.Context, u string) error { + reply := make(chan backendResponse[struct{}], 1) + req := rmRequest{ + reply: reply, + u: u, + } + if _, err := sendBackend[rmRequest, struct{}](ctx, c.incoming, req, reply); err != nil { + return err + } + return nil +} + +// Refresh forces a resource to be refreshed immediately. If the resource does +// not exist, or if the refresh fails, it will return an error. +// +// This function is synchronous, and will block until the resource has been refreshed. +func (c *controller) Refresh(ctx context.Context, u string) error { + reply := make(chan backendResponse[struct{}], 1) + req := refreshRequest{ + reply: reply, + u: u, + } + + if _, err := sendBackend[refreshRequest, struct{}](ctx, c.incoming, req, reply); err != nil { + return err + } + return nil +} diff --git a/vendor/github.com/lestrrat-go/httprc/v3/errors.go b/vendor/github.com/lestrrat-go/httprc/v3/errors.go new file mode 100644 index 00000000000..1152ba947fc --- /dev/null +++ b/vendor/github.com/lestrrat-go/httprc/v3/errors.go @@ -0,0 +1,57 @@ +package httprc + +import "errors" + +var errResourceAlreadyExists = errors.New(`resource already exists`) + +func ErrResourceAlreadyExists() error { + return errResourceAlreadyExists +} + +var errAlreadyRunning = errors.New(`client is already running`) + +func ErrAlreadyRunning() error { + return errAlreadyRunning +} + +var errResourceNotFound = errors.New(`resource not found`) + +func ErrResourceNotFound() error { + return errResourceNotFound +} + +var errTransformerRequired = errors.New(`transformer is required`) + +func ErrTransformerRequired() error { + return errTransformerRequired +} + +var errURLCannotBeEmpty = errors.New(`URL cannot be empty`) + +func ErrURLCannotBeEmpty() error { + return errURLCannotBeEmpty +} + +var errUnexpectedStatusCode = errors.New(`unexpected status code`) + +func ErrUnexpectedStatusCode() error { + return errUnexpectedStatusCode +} + +var errTransformerFailed = errors.New(`failed to transform response body`) + +func ErrTransformerFailed() error { + return errTransformerFailed +} + +var errRecoveredFromPanic = errors.New(`recovered from panic`) + +func ErrRecoveredFromPanic() error { + return errRecoveredFromPanic +} + +var errBlockedByWhitelist = errors.New(`blocked by whitelist`) + +func ErrBlockedByWhitelist() error { + return errBlockedByWhitelist +} diff --git a/vendor/github.com/lestrrat-go/httprc/v3/errsink/errsink.go b/vendor/github.com/lestrrat-go/httprc/v3/errsink/errsink.go new file mode 100644 index 00000000000..03d128ffcd5 --- /dev/null +++ b/vendor/github.com/lestrrat-go/httprc/v3/errsink/errsink.go @@ -0,0 +1,59 @@ +package errsink + +import ( + "context" + "log/slog" +) + +type Interface interface { + Put(context.Context, error) +} + +// Nop is an ErrorSink that does nothing. It does not require +// any initialization, so the zero value can be used. +type Nop struct{} + +// NewNop returns a new NopErrorSink object. The constructor +// is provided for consistency. +func NewNop() Interface { + return Nop{} +} + +// Put for NopErrorSink does nothing. +func (Nop) Put(context.Context, error) {} + +type SlogLogger interface { + Log(context.Context, slog.Level, string, ...any) +} + +type slogSink struct { + logger SlogLogger +} + +// NewSlog returns a new ErrorSink that logs errors using the provided slog.Logger +func NewSlog(l SlogLogger) Interface { + return &slogSink{ + logger: l, + } +} + +func (s *slogSink) Put(ctx context.Context, v error) { + s.logger.Log(ctx, slog.LevelError, v.Error()) +} + +// FuncSink is an ErrorSink that calls a function with the error. +type FuncSink struct { + fn func(context.Context, error) +} + +// NewFunc returns a new FuncSink that calls the provided function with errors. +func NewFunc(fn func(context.Context, error)) Interface { + return &FuncSink{fn: fn} +} + +// Put calls the function with the error. +func (f *FuncSink) Put(ctx context.Context, err error) { + if f.fn != nil { + f.fn(ctx, err) + } +} diff --git a/vendor/github.com/lestrrat-go/httprc/v3/httprc.go b/vendor/github.com/lestrrat-go/httprc/v3/httprc.go new file mode 100644 index 00000000000..fc324b771fd --- /dev/null +++ b/vendor/github.com/lestrrat-go/httprc/v3/httprc.go @@ -0,0 +1,90 @@ +package httprc + +import ( + "context" + "net/http" + "time" + + "github.com/lestrrat-go/httprc/v3/errsink" + "github.com/lestrrat-go/httprc/v3/tracesink" +) + +// Buffer size constants +const ( + // ReadBufferSize is the default buffer size for reading HTTP responses (10MB) + ReadBufferSize = 1024 * 1024 * 10 + // MaxBufferSize is the maximum allowed buffer size (1GB) + MaxBufferSize = 1024 * 1024 * 1000 +) + +// Client worker constants +const ( + // DefaultWorkers is the default number of worker goroutines + DefaultWorkers = 5 +) + +// Interval constants +const ( + // DefaultMaxInterval is the default maximum interval between fetches (30 days) + DefaultMaxInterval = 24 * time.Hour * 30 + // DefaultMinInterval is the default minimum interval between fetches (15 minutes) + DefaultMinInterval = 15 * time.Minute + // oneDay is used internally for time calculations + oneDay = 24 * time.Hour +) + +// utility to round up intervals to the nearest second +func roundupToSeconds(d time.Duration) time.Duration { + if diff := d % time.Second; diff > 0 { + return d + time.Second - diff + } + return d +} + +// ErrorSink is an interface that abstracts a sink for errors. +type ErrorSink = errsink.Interface + +type TraceSink = tracesink.Interface + +// HTTPClient is an interface that abstracts a "net/http".Client, so that +// users can provide their own implementation of the HTTP client, if need be. +type HTTPClient interface { + Do(*http.Request) (*http.Response, error) +} + +// Transformer is used to convert the body of an HTTP response into an appropriate +// object of type T. +type Transformer[T any] interface { + Transform(context.Context, *http.Response) (T, error) +} + +// TransformFunc is a function type that implements the Transformer interface. +type TransformFunc[T any] func(context.Context, *http.Response) (T, error) + +func (f TransformFunc[T]) Transform(ctx context.Context, res *http.Response) (T, error) { + return f(ctx, res) +} + +// Resource is a single resource that can be retrieved via HTTP, and (possibly) transformed +// into an arbitrary object type. +// +// Realistically, there is no need for third-parties to implement this interface. This exists +// to provide a way to aggregate `httprc.ResourceBase` objects with different specialized types +// into a single collection. +// +// See ResourceBase for details +type Resource interface { //nolint:interfacebloat + Get(any) error + Next() time.Time + SetNext(time.Time) + URL() string + Sync(context.Context) error + ConstantInterval() time.Duration + MaxInterval() time.Duration + SetMaxInterval(time.Duration) + MinInterval() time.Duration + SetMinInterval(time.Duration) + IsBusy() bool + SetBusy(bool) + Ready(context.Context) error +} diff --git a/vendor/github.com/lestrrat-go/httprc/v3/options.go b/vendor/github.com/lestrrat-go/httprc/v3/options.go new file mode 100644 index 00000000000..3f07b5671ca --- /dev/null +++ b/vendor/github.com/lestrrat-go/httprc/v3/options.go @@ -0,0 +1,144 @@ +package httprc + +import ( + "time" + + "github.com/lestrrat-go/option" +) + +type NewClientOption interface { + option.Interface + newClientOption() +} + +type newClientOption struct { + option.Interface +} + +func (newClientOption) newClientOption() {} + +type identWorkers struct{} + +// WithWorkers specifies the number of concurrent workers to use for the client. +// If n is less than or equal to 0, the client will use a single worker. +func WithWorkers(n int) NewClientOption { + return newClientOption{option.New(identWorkers{}, n)} +} + +type identErrorSink struct{} + +// WithErrorSink specifies the error sink to use for the client. +// If not specified, the client will use a NopErrorSink. +func WithErrorSink(sink ErrorSink) NewClientOption { + return newClientOption{option.New(identErrorSink{}, sink)} +} + +type identTraceSink struct{} + +// WithTraceSink specifies the trace sink to use for the client. +// If not specified, the client will use a NopTraceSink. +func WithTraceSink(sink TraceSink) NewClientOption { + return newClientOption{option.New(identTraceSink{}, sink)} +} + +type identWhitelist struct{} + +// WithWhitelist specifies the whitelist to use for the client. +// If not specified, the client will use a BlockAllWhitelist. +func WithWhitelist(wl Whitelist) NewClientOption { + return newClientOption{option.New(identWhitelist{}, wl)} +} + +type NewResourceOption interface { + option.Interface + newResourceOption() +} + +type newResourceOption struct { + option.Interface +} + +func (newResourceOption) newResourceOption() {} + +type NewClientResourceOption interface { + option.Interface + newResourceOption() + newClientOption() +} + +type newClientResourceOption struct { + option.Interface +} + +func (newClientResourceOption) newResourceOption() {} +func (newClientResourceOption) newClientOption() {} + +type identHTTPClient struct{} + +// WithHTTPClient specifies the HTTP client to use for the client. +// If not specified, the client will use http.DefaultClient. +// +// This option can be passed to NewClient or NewResource. +func WithHTTPClient(cl HTTPClient) NewClientResourceOption { + return newClientResourceOption{option.New(identHTTPClient{}, cl)} +} + +type identMinimumInterval struct{} + +// WithMinInterval specifies the minimum interval between fetches. +// +// This option affects the dynamic calculation of the interval between fetches. +// If the value calculated from the http.Response is less than the this value, +// the client will use this value instead. +func WithMinInterval(d time.Duration) NewResourceOption { + return newResourceOption{option.New(identMinimumInterval{}, d)} +} + +type identMaximumInterval struct{} + +// WithMaxInterval specifies the maximum interval between fetches. +// +// This option affects the dynamic calculation of the interval between fetches. +// If the value calculated from the http.Response is greater than the this value, +// the client will use this value instead. +func WithMaxInterval(d time.Duration) NewResourceOption { + return newResourceOption{option.New(identMaximumInterval{}, d)} +} + +type identConstantInterval struct{} + +// WithConstantInterval specifies the interval between fetches. When you +// specify this option, the client will fetch the resource at the specified +// intervals, regardless of the response's Cache-Control or Expires headers. +// +// By default this option is disabled. +func WithConstantInterval(d time.Duration) NewResourceOption { + return newResourceOption{option.New(identConstantInterval{}, d)} +} + +type AddOption interface { + option.Interface + newAddOption() +} + +type addOption struct { + option.Interface +} + +func (addOption) newAddOption() {} + +type identWaitReady struct{} + +// WithWaitReady specifies whether the client should wait for the resource to be +// ready before returning from the Add method. +// +// By default, the client will wait for the resource to be ready before returning. +// If you specify this option with a value of false, the client will not wait for +// the resource to be fully registered, which is usually not what you want. +// This option exists to accommodate for cases where you for some reason want to +// add a resource to the controller, but want to do something else before +// you wait for it. Make sure to call `r.Ready()` later on to ensure that +// the resource is ready before you try to access it. +func WithWaitReady(b bool) AddOption { + return addOption{option.New(identWaitReady{}, b)} +} diff --git a/vendor/github.com/lestrrat-go/httprc/v3/proxysink/proxysink.go b/vendor/github.com/lestrrat-go/httprc/v3/proxysink/proxysink.go new file mode 100644 index 00000000000..f290422d6ce --- /dev/null +++ b/vendor/github.com/lestrrat-go/httprc/v3/proxysink/proxysink.go @@ -0,0 +1,135 @@ +package proxysink + +import ( + "context" + "sync" +) + +type Backend[T any] interface { + Put(context.Context, T) +} + +// Proxy is used to send values through a channel. This is used to +// serialize calls to underlying sinks. +type Proxy[T any] struct { + mu *sync.Mutex + cancel context.CancelFunc + ch chan T + cond *sync.Cond + pending []T + backend Backend[T] + closed bool +} + +func New[T any](b Backend[T]) *Proxy[T] { + mu := &sync.Mutex{} + return &Proxy[T]{ + ch: make(chan T, 1), + mu: mu, + cond: sync.NewCond(mu), + backend: b, + cancel: func() {}, + } +} + +func (p *Proxy[T]) Run(ctx context.Context) { + defer p.cond.Broadcast() + + p.mu.Lock() + ctx, cancel := context.WithCancel(ctx) + p.cancel = cancel + p.mu.Unlock() + + go p.controlloop(ctx) + go p.flushloop(ctx) + + <-ctx.Done() +} + +func (p *Proxy[T]) controlloop(ctx context.Context) { + defer p.cond.Broadcast() + for { + select { + case <-ctx.Done(): + return + case r := <-p.ch: + p.mu.Lock() + p.pending = append(p.pending, r) + p.mu.Unlock() + } + p.cond.Broadcast() + } +} + +func (p *Proxy[T]) flushloop(ctx context.Context) { + const defaultPendingSize = 10 + pending := make([]T, defaultPendingSize) + for { + select { + case <-ctx.Done(): + p.mu.Lock() + if len(p.pending) <= 0 { + p.mu.Unlock() + return + } + default: + } + + p.mu.Lock() + for len(p.pending) <= 0 { + select { + case <-ctx.Done(): + p.mu.Unlock() + return + default: + p.cond.Wait() + } + } + + // extract all pending values, and clear the shared slice + if cap(pending) < len(p.pending) { + pending = make([]T, len(p.pending)) + } else { + pending = pending[:len(p.pending)] + } + copy(pending, p.pending) + if cap(p.pending) > defaultPendingSize { + p.pending = make([]T, 0, defaultPendingSize) + } else { + p.pending = p.pending[:0] + } + p.mu.Unlock() + + for _, v := range pending { + // send to sink serially + p.backend.Put(ctx, v) + } + } +} + +func (p *Proxy[T]) Put(ctx context.Context, v T) { + p.mu.Lock() + if p.closed { + p.mu.Unlock() + return + } + p.mu.Unlock() + + select { + case <-ctx.Done(): + return + case p.ch <- v: + return + } +} + +func (p *Proxy[T]) Close() { + p.mu.Lock() + defer p.mu.Unlock() + + if !p.closed { + p.closed = true + } + p.cancel() + p.cond.Broadcast() +} diff --git a/vendor/github.com/lestrrat-go/httprc/v3/resource.go b/vendor/github.com/lestrrat-go/httprc/v3/resource.go new file mode 100644 index 00000000000..e637f791fcc --- /dev/null +++ b/vendor/github.com/lestrrat-go/httprc/v3/resource.go @@ -0,0 +1,359 @@ +package httprc + +import ( + "context" + "fmt" + "io" + "net/http" + "net/url" + "sync" + "sync/atomic" + "time" + + "github.com/lestrrat-go/blackmagic" + "github.com/lestrrat-go/httpcc" + "github.com/lestrrat-go/httprc/v3/tracesink" +) + +// ResourceBase is a generic Resource type +type ResourceBase[T any] struct { + u string + ready chan struct{} // closed when the resource is ready (i.e. after first successful fetch) + once sync.Once + httpcl HTTPClient + t Transformer[T] + r atomic.Value + next atomic.Value + interval time.Duration + minInterval atomic.Int64 + maxInterval atomic.Int64 + busy atomic.Bool +} + +// NewResource creates a new Resource object which after fetching the +// resource from the URL, will transform the response body using the +// provided Transformer to an object of type T. +// +// This function will return an error if the URL is not a valid URL +// (i.e. it cannot be parsed by url.Parse), or if the transformer is nil. +func NewResource[T any](s string, transformer Transformer[T], options ...NewResourceOption) (*ResourceBase[T], error) { + var httpcl HTTPClient + var interval time.Duration + minInterval := DefaultMinInterval + maxInterval := DefaultMaxInterval + //nolint:forcetypeassert + for _, option := range options { + switch option.Ident() { + case identHTTPClient{}: + httpcl = option.Value().(HTTPClient) + case identMinimumInterval{}: + minInterval = option.Value().(time.Duration) + case identMaximumInterval{}: + maxInterval = option.Value().(time.Duration) + case identConstantInterval{}: + interval = option.Value().(time.Duration) + } + } + if transformer == nil { + return nil, fmt.Errorf(`httprc.NewResource: %w`, errTransformerRequired) + } + + if s == "" { + return nil, fmt.Errorf(`httprc.NewResource: %w`, errURLCannotBeEmpty) + } + + if _, err := url.Parse(s); err != nil { + return nil, fmt.Errorf(`httprc.NewResource: %w`, err) + } + r := &ResourceBase[T]{ + u: s, + httpcl: httpcl, + t: transformer, + interval: interval, + ready: make(chan struct{}), + } + if httpcl != nil { + r.httpcl = httpcl + } + r.minInterval.Store(int64(minInterval)) + r.maxInterval.Store(int64(maxInterval)) + r.SetNext(time.Unix(0, 0)) // initially, it should be fetched immediately + return r, nil +} + +// URL returns the URL of the resource. +func (r *ResourceBase[T]) URL() string { + return r.u +} + +// Ready returns an empty error when the resource is ready. If the context +// is canceled before the resource is ready, it will return the error from +// the context. +func (r *ResourceBase[T]) Ready(ctx context.Context) error { + select { + case <-ctx.Done(): + return ctx.Err() + case <-r.ready: + return nil + } +} + +// Get assigns the value of the resource to the provided pointer. +// If using the `httprc.ResourceBase[T]` type directly, you can use the `Resource()` +// method to get the resource directly. +// +// This method exists because parametric types cannot be assigned to a single object type +// that return different return values of the specialized type. i.e. for resources +// `ResourceBase[A]` and `ResourceBase[B]`, we cannot have a single interface that can +// be assigned to the same interface type `X` that expects a `Resource()` method that +// returns `A` or `B` depending on the type of the resource. When accessing the +// resource through the `httprc.Resource` interface, use this method to obtain the +// stored value. +func (r *ResourceBase[T]) Get(dst interface{}) error { + return blackmagic.AssignIfCompatible(dst, r.Resource()) +} + +// Resource returns the last fetched resource. If the resource has not been +// fetched yet, this will return the zero value of type T. +// +// If you would rather wait until the resource is fetched, you can use the +// `Ready()` method to wait until the resource is ready (i.e. fetched at least once). +func (r *ResourceBase[T]) Resource() T { + v := r.r.Load() + switch v := v.(type) { + case T: + return v + default: + var zero T + return zero + } +} + +func (r *ResourceBase[T]) Next() time.Time { + //nolint:forcetypeassert + return r.next.Load().(time.Time) +} + +func (r *ResourceBase[T]) SetNext(v time.Time) { + r.next.Store(v) +} + +func (r *ResourceBase[T]) ConstantInterval() time.Duration { + return r.interval +} + +func (r *ResourceBase[T]) MaxInterval() time.Duration { + return time.Duration(r.maxInterval.Load()) +} + +func (r *ResourceBase[T]) MinInterval() time.Duration { + return time.Duration(r.minInterval.Load()) +} + +func (r *ResourceBase[T]) SetMaxInterval(v time.Duration) { + r.maxInterval.Store(int64(v)) +} + +func (r *ResourceBase[T]) SetMinInterval(v time.Duration) { + r.minInterval.Store(int64(v)) +} + +func (r *ResourceBase[T]) SetBusy(v bool) { + r.busy.Store(v) +} + +func (r *ResourceBase[T]) IsBusy() bool { + return r.busy.Load() +} + +// limitedBody is a wrapper around an io.Reader that will only read up to +// MaxBufferSize bytes. This is provided to prevent the user from accidentally +// reading a huge response body into memory +type limitedBody struct { + rdr io.Reader + close func() error +} + +func (l *limitedBody) Read(p []byte) (n int, err error) { + return l.rdr.Read(p) +} + +func (l *limitedBody) Close() error { + return l.close() +} + +type traceSinkKey struct{} + +func withTraceSink(ctx context.Context, sink TraceSink) context.Context { + return context.WithValue(ctx, traceSinkKey{}, sink) +} + +func traceSinkFromContext(ctx context.Context) TraceSink { + if v := ctx.Value(traceSinkKey{}); v != nil { + //nolint:forcetypeassert + return v.(TraceSink) + } + return tracesink.Nop{} +} + +type httpClientKey struct{} + +func withHTTPClient(ctx context.Context, cl HTTPClient) context.Context { + return context.WithValue(ctx, httpClientKey{}, cl) +} + +func httpClientFromContext(ctx context.Context) HTTPClient { + if v := ctx.Value(httpClientKey{}); v != nil { + //nolint:forcetypeassert + return v.(HTTPClient) + } + return http.DefaultClient +} + +func (r *ResourceBase[T]) Sync(ctx context.Context) error { + traceSink := traceSinkFromContext(ctx) + httpcl := r.httpcl + if httpcl == nil { + httpcl = httpClientFromContext(ctx) + } + + req, err := http.NewRequestWithContext(ctx, http.MethodGet, r.u, nil) + if err != nil { + return fmt.Errorf(`httprc.Resource.Sync: failed to create request: %w`, err) + } + + traceSink.Put(ctx, fmt.Sprintf("httprc.Resource.Sync: fetching %q", r.u)) + res, err := httpcl.Do(req) + if err != nil { + return fmt.Errorf(`httprc.Resource.Sync: failed to execute HTTP request: %w`, err) + } + defer res.Body.Close() + + next := r.calculateNextRefreshTime(ctx, res) + traceSink.Put(ctx, fmt.Sprintf("httprc.Resource.Sync: next refresh time for %q is %v", r.u, next)) + r.SetNext(next) + + if res.StatusCode != http.StatusOK { + return fmt.Errorf(`httprc.Resource.Sync: %w (status code=%d, url=%q)`, errUnexpectedStatusCode, res.StatusCode, r.u) + } + + // replace the body of the response with a limited reader that + // will only read up to MaxBufferSize bytes + res.Body = &limitedBody{ + rdr: &io.LimitedReader{R: res.Body, N: MaxBufferSize}, + close: res.Body.Close, + } + traceSink.Put(ctx, fmt.Sprintf("httprc.Resource.Sync: transforming %q", r.u)) + v, err := r.transform(ctx, res) + if err != nil { + return fmt.Errorf(`httprc.Resource.Sync: %w: %w`, errTransformerFailed, err) + } + + traceSink.Put(ctx, fmt.Sprintf("httprc.Resource.Sync: storing new value for %q", r.u)) + r.r.Store(v) + r.once.Do(func() { close(r.ready) }) + traceSink.Put(ctx, fmt.Sprintf("httprc.Resource.Sync: stored value for %q", r.u)) + return nil +} + +func (r *ResourceBase[T]) transform(ctx context.Context, res *http.Response) (ret T, gerr error) { + // Protect the call to Transform with a defer/recover block, so that even + // if the Transform method panics, we can recover from it and return an error + defer func() { + if recovered := recover(); recovered != nil { + gerr = fmt.Errorf(`httprc.Resource.transform: %w: %v`, errRecoveredFromPanic, recovered) + } + }() + return r.t.Transform(ctx, res) +} + +func (r *ResourceBase[T]) determineNextFetchInterval(ctx context.Context, name string, fromHeader, minValue, maxValue time.Duration) time.Duration { + traceSink := traceSinkFromContext(ctx) + + if fromHeader > maxValue { + traceSink.Put(ctx, fmt.Sprintf("httprc.Resource.Sync: %s %s > maximum interval, using maximum interval %s", r.URL(), name, maxValue)) + return maxValue + } + + if fromHeader < minValue { + traceSink.Put(ctx, fmt.Sprintf("httprc.Resource.Sync: %s %s < minimum interval, using minimum interval %s", r.URL(), name, minValue)) + return minValue + } + + traceSink.Put(ctx, fmt.Sprintf("httprc.Resource.Sync: %s Using %s (%s)", r.URL(), name, fromHeader)) + return fromHeader +} + +func (r *ResourceBase[T]) calculateNextRefreshTime(ctx context.Context, res *http.Response) time.Time { + traceSink := traceSinkFromContext(ctx) + now := time.Now() + + // If constant interval is set, use that regardless of what the + // response headers say. + if interval := r.ConstantInterval(); interval > 0 { + traceSink.Put(ctx, fmt.Sprintf("httprc.Resource.Sync: %s Explicit interval set, using value %s", r.URL(), interval)) + return now.Add(interval) + } + + if interval := r.extractCacheControlMaxAge(ctx, res); interval > 0 { + return now.Add(interval) + } + + if interval := r.extractExpiresInterval(ctx, res); interval > 0 { + return now.Add(interval) + } + + traceSink.Put(ctx, fmt.Sprintf("httprc.Resource.Sync: %s No cache-control/expires headers found, using minimum interval", r.URL())) + return now.Add(r.MinInterval()) +} + +func (r *ResourceBase[T]) extractCacheControlMaxAge(ctx context.Context, res *http.Response) time.Duration { + traceSink := traceSinkFromContext(ctx) + + v := res.Header.Get(`Cache-Control`) + if v == "" { + return 0 + } + + dir, err := httpcc.ParseResponse(v) + if err != nil { + return 0 + } + + maxAge, ok := dir.MaxAge() + if !ok { + return 0 + } + + traceSink.Put(ctx, fmt.Sprintf("httprc.Resource.Sync: %s Cache-Control=max-age directive set (%d)", r.URL(), maxAge)) + return r.determineNextFetchInterval( + ctx, + "max-age", + time.Duration(maxAge)*time.Second, + r.MinInterval(), + r.MaxInterval(), + ) +} + +func (r *ResourceBase[T]) extractExpiresInterval(ctx context.Context, res *http.Response) time.Duration { + traceSink := traceSinkFromContext(ctx) + + v := res.Header.Get(`Expires`) + if v == "" { + return 0 + } + + expires, err := http.ParseTime(v) + if err != nil { + return 0 + } + + traceSink.Put(ctx, fmt.Sprintf("httprc.Resource.Sync: %s Expires header set (%s)", r.URL(), expires)) + return r.determineNextFetchInterval( + ctx, + "expires", + time.Until(expires), + r.MinInterval(), + r.MaxInterval(), + ) +} diff --git a/vendor/github.com/lestrrat-go/httprc/v3/tracesink/tracesink.go b/vendor/github.com/lestrrat-go/httprc/v3/tracesink/tracesink.go new file mode 100644 index 00000000000..b8400a94aee --- /dev/null +++ b/vendor/github.com/lestrrat-go/httprc/v3/tracesink/tracesink.go @@ -0,0 +1,52 @@ +package tracesink + +import ( + "context" + "log/slog" +) + +type Interface interface { + Put(context.Context, string) +} + +// Nop is an ErrorSink that does nothing. It does not require +// any initialization, so the zero value can be used. +type Nop struct{} + +// NewNop returns a new NopTraceSink object. The constructor +// is provided for consistency. +func NewNop() Interface { + return Nop{} +} + +// Put for NopTraceSink does nothing. +func (Nop) Put(context.Context, string) {} + +type slogSink struct { + level slog.Level + logger SlogLogger +} + +type SlogLogger interface { + Log(context.Context, slog.Level, string, ...any) +} + +// NewSlog returns a new ErrorSink that logs errors using the provided slog.Logger +func NewSlog(l SlogLogger) Interface { + return &slogSink{ + level: slog.LevelInfo, + logger: l, + } +} + +func (s *slogSink) Put(ctx context.Context, v string) { + s.logger.Log(ctx, s.level, v) +} + +// Func is a TraceSink that calls a function with the trace message. +type Func func(context.Context, string) + +// Put calls the function with the trace message. +func (f Func) Put(ctx context.Context, msg string) { + f(ctx, msg) +} diff --git a/vendor/github.com/lestrrat-go/httprc/v3/transformer.go b/vendor/github.com/lestrrat-go/httprc/v3/transformer.go new file mode 100644 index 00000000000..2bd0635a2ce --- /dev/null +++ b/vendor/github.com/lestrrat-go/httprc/v3/transformer.go @@ -0,0 +1,37 @@ +package httprc + +import ( + "context" + "encoding/json" + "io" + "net/http" +) + +type bytesTransformer struct{} + +// BytesTransformer returns a Transformer that reads the entire response body +// as a byte slice. This is the default Transformer used by httprc.Client +func BytesTransformer() Transformer[[]byte] { + return bytesTransformer{} +} + +func (bytesTransformer) Transform(_ context.Context, res *http.Response) ([]byte, error) { + return io.ReadAll(res.Body) +} + +type jsonTransformer[T any] struct{} + +// JSONTransformer returns a Transformer that decodes the response body as JSON +// into the provided type T. +func JSONTransformer[T any]() Transformer[T] { + return jsonTransformer[T]{} +} + +func (jsonTransformer[T]) Transform(_ context.Context, res *http.Response) (T, error) { + var v T + if err := json.NewDecoder(res.Body).Decode(&v); err != nil { + var zero T + return zero, err + } + return v, nil +} diff --git a/vendor/github.com/lestrrat-go/httprc/v3/whitelist.go b/vendor/github.com/lestrrat-go/httprc/v3/whitelist.go new file mode 100644 index 00000000000..74ef2a1be64 --- /dev/null +++ b/vendor/github.com/lestrrat-go/httprc/v3/whitelist.go @@ -0,0 +1,113 @@ +package httprc + +import ( + "regexp" + "sync" +) + +// Whitelist is an interface that allows you to determine if a given URL is allowed +// or not. Implementations of this interface can be used to restrict the URLs that +// the client can access. +// +// By default all URLs are allowed, but this may not be ideal in production environments +// for security reasons. +// +// This exists because you might use this module to store resources provided by +// user of your application, in which case you cannot necessarily trust that the +// URLs are safe. +// +// You will HAVE to provide some sort of whitelist. +type Whitelist interface { + IsAllowed(string) bool +} + +// WhitelistFunc is a function type that implements the Whitelist interface. +type WhitelistFunc func(string) bool + +func (f WhitelistFunc) IsAllowed(u string) bool { return f(u) } + +// BlockAllWhitelist is a Whitelist implementation that blocks all URLs. +type BlockAllWhitelist struct{} + +// NewBlockAllWhitelist creates a new BlockAllWhitelist instance. It is safe to +// use the zero value of this type; this constructor is provided for consistency. +func NewBlockAllWhitelist() BlockAllWhitelist { return BlockAllWhitelist{} } + +func (BlockAllWhitelist) IsAllowed(_ string) bool { return false } + +// InsecureWhitelist is a Whitelist implementation that allows all URLs. Be careful +// when using this in your production code: make sure you do not blindly register +// URLs from untrusted sources. +type InsecureWhitelist struct{} + +// NewInsecureWhitelist creates a new InsecureWhitelist instance. It is safe to +// use the zero value of this type; this constructor is provided for consistency. +func NewInsecureWhitelist() InsecureWhitelist { return InsecureWhitelist{} } + +func (InsecureWhitelist) IsAllowed(_ string) bool { return true } + +// RegexpWhitelist is a jwk.Whitelist object comprised of a list of *regexp.Regexp +// objects. All entries in the list are tried until one matches. If none of the +// *regexp.Regexp objects match, then the URL is deemed unallowed. +type RegexpWhitelist struct { + mu sync.RWMutex + patterns []*regexp.Regexp +} + +// NewRegexpWhitelist creates a new RegexpWhitelist instance. It is safe to use the +// zero value of this type; this constructor is provided for consistency. +func NewRegexpWhitelist() *RegexpWhitelist { + return &RegexpWhitelist{} +} + +// Add adds a new regular expression to the list of expressions to match against. +func (w *RegexpWhitelist) Add(pat *regexp.Regexp) *RegexpWhitelist { + w.mu.Lock() + defer w.mu.Unlock() + w.patterns = append(w.patterns, pat) + return w +} + +// IsAllowed returns true if any of the patterns in the whitelist +// returns true. +func (w *RegexpWhitelist) IsAllowed(u string) bool { + w.mu.RLock() + patterns := w.patterns + w.mu.RUnlock() + for _, pat := range patterns { + if pat.MatchString(u) { + return true + } + } + return false +} + +// MapWhitelist is a jwk.Whitelist object comprised of a map of strings. +// If the URL exists in the map, then the URL is allowed to be fetched. +type MapWhitelist interface { + Whitelist + Add(string) MapWhitelist +} + +type mapWhitelist struct { + mu sync.RWMutex + store map[string]struct{} +} + +func NewMapWhitelist() MapWhitelist { + return &mapWhitelist{store: make(map[string]struct{})} +} + +func (w *mapWhitelist) Add(pat string) MapWhitelist { + w.mu.Lock() + defer w.mu.Unlock() + w.store[pat] = struct{}{} + return w +} + +func (w *mapWhitelist) IsAllowed(u string) bool { + w.mu.RLock() + _, b := w.store[u] + w.mu.RUnlock() + return b +} diff --git a/vendor/github.com/lestrrat-go/httprc/v3/worker.go b/vendor/github.com/lestrrat-go/httprc/v3/worker.go new file mode 100644 index 00000000000..d11477dadcb --- /dev/null +++ b/vendor/github.com/lestrrat-go/httprc/v3/worker.go @@ -0,0 +1,62 @@ +package httprc + +import ( + "context" + "fmt" + "sync" +) + +type worker struct { + httpcl HTTPClient + incoming chan any + next <-chan Resource + nextsync <-chan synchronousRequest + errSink ErrorSink + traceSink TraceSink +} + +func (w worker) Run(ctx context.Context, readywg *sync.WaitGroup, donewg *sync.WaitGroup) { + w.traceSink.Put(ctx, "httprc worker: START worker loop") + defer w.traceSink.Put(ctx, "httprc worker: END worker loop") + defer donewg.Done() + ctx = withTraceSink(ctx, w.traceSink) + ctx = withHTTPClient(ctx, w.httpcl) + + readywg.Done() + for { + select { + case <-ctx.Done(): + w.traceSink.Put(ctx, "httprc worker: stopping worker loop") + return + case r := <-w.next: + w.traceSink.Put(ctx, fmt.Sprintf("httprc worker: syncing %q (async)", r.URL())) + if err := r.Sync(ctx); err != nil { + w.errSink.Put(ctx, err) + } + r.SetBusy(false) + + w.sendAdjustIntervalRequest(ctx, r) + case sr := <-w.nextsync: + w.traceSink.Put(ctx, fmt.Sprintf("httprc worker: syncing %q (synchronous)", sr.resource.URL())) + if err := sr.resource.Sync(ctx); err != nil { + w.traceSink.Put(ctx, fmt.Sprintf("httprc worker: FAILED to sync %q (synchronous): %s", sr.resource.URL(), err)) + sendReply(ctx, sr.reply, struct{}{}, err) + sr.resource.SetBusy(false) + return + } + w.traceSink.Put(ctx, fmt.Sprintf("httprc worker: SUCCESS syncing %q (synchronous)", sr.resource.URL())) + sr.resource.SetBusy(false) + sendReply(ctx, sr.reply, struct{}{}, nil) + w.sendAdjustIntervalRequest(ctx, sr.resource) + } + } +} + +func (w worker) sendAdjustIntervalRequest(ctx context.Context, r Resource) { + w.traceSink.Put(ctx, "httprc worker: Sending interval adjustment request for "+r.URL()) + select { + case <-ctx.Done(): + case w.incoming <- adjustIntervalRequest{resource: r}: + } + w.traceSink.Put(ctx, "httprc worker: Sent interval adjustment request for "+r.URL()) +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/.bazelignore b/vendor/github.com/lestrrat-go/jwx/v3/.bazelignore new file mode 100644 index 00000000000..50347e8777e --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/.bazelignore @@ -0,0 +1,4 @@ +cmd +bench +examples +tools diff --git a/vendor/github.com/lestrrat-go/jwx/v3/.bazelrc b/vendor/github.com/lestrrat-go/jwx/v3/.bazelrc new file mode 100644 index 00000000000..b47648db7b4 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/.bazelrc @@ -0,0 +1 @@ +import %workspace%/.aspect/bazelrc/bazel7.bazelrc diff --git a/vendor/github.com/lestrrat-go/jwx/v3/.bazelversion b/vendor/github.com/lestrrat-go/jwx/v3/.bazelversion new file mode 100644 index 00000000000..56b6be4ebb2 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/.bazelversion @@ -0,0 +1 @@ +8.3.1 diff --git a/vendor/github.com/lestrrat-go/jwx/v3/.gitignore b/vendor/github.com/lestrrat-go/jwx/v3/.gitignore new file mode 100644 index 00000000000..c4c0ebff32b --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/.gitignore @@ -0,0 +1,39 @@ +# 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 + +# IDE +.idea +.vscode +.DS_Store +*~ + +coverage.out + +# I redirect my test output to files named "out" way too often +out + +cmd/jwx/jwx + +bazel-* diff --git a/vendor/github.com/lestrrat-go/jwx/v3/.golangci.yml b/vendor/github.com/lestrrat-go/jwx/v3/.golangci.yml new file mode 100644 index 00000000000..214a9edaa83 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/.golangci.yml @@ -0,0 +1,125 @@ +version: "2" +linters: + default: all + disable: + - cyclop + - depguard + - dupl + - err113 + - errorlint + - exhaustive + - funcorder + - funlen + - gochecknoglobals + - gochecknoinits + - gocognit + - gocritic + - gocyclo + - godot + - godox + - gosec + - gosmopolitan + - govet + - inamedparam + - ireturn + - lll + - maintidx + - makezero + - mnd + - nakedret + - nestif + - nlreturn + - noinlineerr + - nonamedreturns + - paralleltest + - perfsprint + - staticcheck + - recvcheck + - tagliatelle + - testifylint + - testpackage + - thelper + - varnamelen + - wrapcheck + - wsl + - wsl_v5 + settings: + govet: + disable: + - shadow + - fieldalignment + enable-all: true + exclusions: + generated: lax + presets: + - comments + - common-false-positives + - legacy + - std-error-handling + rules: + - linters: + - staticcheck + path: /*.go + text: 'ST1003: should not use underscores in package names' + - linters: + - revive + path: /*.go + text: don't use an underscore in package name + - linters: + - staticcheck + text: SA1019 + - linters: + - contextcheck + - exhaustruct + path: /*.go + - linters: + - errcheck + path: /main.go + - linters: + - errcheck + path: internal/codegen/codegen.go + - linters: + - errcheck + - errchkjson + - forcetypeassert + path: internal/jwxtest/jwxtest.go + - linters: + - errcheck + - errchkjson + - forcetypeassert + path: /*_test.go + - linters: + - forbidigo + path: /*_example_test.go + - linters: + - forbidigo + path: cmd/jwx/jwx.go + - linters: + - revive + path: /*_test.go + text: 'var-naming: ' + - linters: + - revive + path: internal/tokens/jwe_tokens.go + text: "don't use ALL_CAPS in Go names" + - linters: + - revive + path: jwt/internal/types/ + text: "var-naming: avoid meaningless package names" + paths: + - third_party$ + - builtin$ + - examples$ +issues: + max-issues-per-linter: 0 + max-same-issues: 0 +formatters: + enable: + - gofmt + - goimports + exclusions: + generated: lax + paths: + - third_party$ + - builtin$ + - examples$ diff --git a/vendor/github.com/lestrrat-go/jwx/v3/BUILD b/vendor/github.com/lestrrat-go/jwx/v3/BUILD new file mode 100644 index 00000000000..2759408882d --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/BUILD @@ -0,0 +1,47 @@ +load("@rules_go//go:def.bzl", "go_library", "go_test") +load("@gazelle//:def.bzl", "gazelle") + +# gazelle:prefix github.com/lestrrat-go/jwx/v3 +# gazelle:go_naming_convention import_alias + +gazelle(name = "gazelle") + +go_library( + name = "jwx", + srcs = [ + "format.go", + "formatkind_string_gen.go", + "jwx.go", + "options.go", + ], + importpath = "github.com/lestrrat-go/jwx/v3", + visibility = ["//visibility:public"], + deps = [ + "//internal/json", + "//internal/tokens", + "@com_github_lestrrat_go_option_v2//:option", + ], +) + +go_test( + name = "jwx_test", + srcs = ["jwx_test.go"], + deps = [ + ":jwx", + "//internal/jose", + "//internal/json", + "//internal/jwxtest", + "//jwa", + "//jwe", + "//jwk", + "//jwk/ecdsa", + "//jws", + "@com_github_stretchr_testify//require", + ], +) + +alias( + name = "go_default_library", + actual = ":jwx", + visibility = ["//visibility:public"], +) diff --git a/vendor/github.com/lestrrat-go/jwx/v3/Changes b/vendor/github.com/lestrrat-go/jwx/v3/Changes new file mode 100644 index 00000000000..29910bf35cb --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/Changes @@ -0,0 +1,222 @@ +Changes +======= + +v3 has many incompatibilities with v2. To see the full list of differences between +v2 and v3, please read the Changes-v3.md file (https://github.com/lestrrat-go/jwx/blob/develop/v3/Changes-v3.md) + +v3.0.11 14 Sep 2025 + * [jwk] Add `(jwk.Cache).Shutdown()` method that delegates to the httprc controller + object, to shutdown the cache. + * [jwk] Change timing of `res.Body.Close()` call + * [jwe] Previously, ecdh.PrivateKey/ecdh.PublicKey were not properly handled + when used for encryption, which has been fixed. + * [jws/jwsbb] (EXPERIMENTAL/BREAKS COMPATIBILITY) Convert most functions into + thin wrappers around functions from github.com/lestrrat-go/dsig package. + As a related change, HAMCHashFuncFor/RSAHashFuncFor/ECDSAHashFuncFor/RSAPSSOptions + have been removed or unexported. + Users of this module should be using jwsbb.Sign() and jwsbb.Verify() instead of + algorithm specific jwsbb.SignRSA()/jwsbb.VerifyRSA() and such. If you feel the + need to use these functions, you should use github.com/lestrrat-go/dsig directly. + +v3.0.10 04 Aug 2025 + * [jws/jwsbb] Add `jwsbb.ErrHeaderNotFound()` to return the same error type as when + a non-existent header is requested. via `HeaderGetXXX()` functions. Previously, this + function was called `jwsbb.ErrFieldNotFound()`, but it was a misnomer. + * [jws/jwsbb] Fix a bug where error return values from `HeaderGetXXX()` functions + could not be matched against `jwsbb.ErrHeaderNotFound()` using `errors.Is()`. + +v3.0.9 31 Jul 2025 + * [jws/jwsbb] `HeaderGetXXX()` functions now return errors when + the requested header is not found, or if the value cannot be + converted to the requested type. + + * [jwt] `(jwt.Token).Get` methods now return specific types of errors depending + on if a) the specified claim was not present, or b) the specified claim could + not be assigned to the destination variable. + + You can distinguish these by using `errors.Is` against `jwt.ClaimNotFoundError()` + or `jwt.ClaimAssignmentFailedError()` + +v3.0.8 27 Jun 2025 + * [jwe/jwebb] (EXPERIMENTAL) Add low-level functions for JWE operations. + * [jws/jwsbb] (EXPERIMENTAL/BREAKS COMPATIBILITY) Add io.Reader parameter + so your choice of source of randomness can be passed. Defaults to crypto/rand.Reader. + Function signatures around jwsbb.Sign() now accept an addition `rr io.Reader`, + which can be nil for 99% of use cases. + * [jws/jwsbb] Add HeaderParse([]byte), where it is expected that the header + is already in its base64 decoded format. + * misc: replace `interface{}` with `any` + +v3.0.7 16 Jun 2025 + * [jws/jwsbb] (EXPERIMENTAL) Add low-level fast access to JWS headers in compact + serialization form. + * [jws] Fix error reporting when no key matched for a signature. + * [jws] Refactor jws signer setup. + * Known algorithms are now implemented completely in the jws/jwsbb package. + * VerifierFor and SignerFor now always succeed, and will also return a Signer2 + or Verifier2 that wraps the legacy Signer or Verifier if one is registered. + +v3.0.6 13 Jun 2025 + * This release contains various performance improvements all over the code. + No, this time for real. In particular, the most common case for signing + a JWT with a key is approx 70% more efficient based on the number of allocations. + + Please read the entry for the (retracted) v3.0.4 for what else I have to + say about performance improvements + + * [jwt] Added fast-path for token signing and verification. The fast path + is triggered if you only pass `jwt.Sign()` and `jwt.Parse()` one options each + (`jwt.WithKey()`), with no suboptions. + + * [jws] Major refactoring around basic operations: + + * How to work with Signer/Verifier have completely changed. Please take + a look at examples/jws_custom_signer_verifier_example_test.go for how + to do it the new way. The old way still works, but it WILL be removed + when v4 arrives. + * Related to the above, old code has been moved to `jws/legacy`. + + * A new package `jws/jwsbb` has been added. `bb` stands for building blocks. + This package separates out the low-level JWS operations into its own + package. So if you are looking for just the signing of a payload with + a key, this is it. + + `jws/jwsbb` is currently considered to be EXPERIMENTAL. + +v3.0.5 11 Jun 2025 + * Retract v3.0.4 + * Code for v3.0.3 is the same as v3.0.3 + +v3.0.4 09 Jun 2025 + * This release contains various performance improvements all over the code. + + Because of the direction that this library is taking, we have always been + more focused on correctness and usability/flexibility over performance. + + It just so happens that I had a moment of inspiration and decided to see + just how good our AI-based coding agents are in this sort of analysis-heavy tasks. + + Long story short, the AI was fairly good at identifying suspicious code with + an okay accuracy, but completely failed to make any meaningful changes to the + code in a way that both did not break the code _and_ improved performance. + I am sure that they will get better in the near future, but for now, + I had to do the changes myself. I should clarify to their defence that + the AI was very helpful in writing cumbersome benchmark code for me. + + The end result is that we have anywhere from 10 to 30% performance improvements + in various parts of the code that we touched, based on number of allocations. + We believe that this would be a significant improvement for many users. + + For further improvements, we can see that there would be a clear benefit to + writing optimized code path that is designed to serve the most common cases. + For example, for the case of signing JWTs with a single key, we could provide + a path that skips a lot of extra processing (we kind of did that in this change, + but we _could_ go ever harder in this direction). However, it is a trade-off between + maintainability and performance, and as I am currently the sole maintainer of + this library for the time being, I only plan to pursue such a route where it + requires minimal effort on my part. + + If you are interested in helping out in this area, I hereby thank you in advance. + However, please be perfectly clear that unlike other types of changes, for performance + related changes, the balance between the performance gains and maintainability is + top priority. If you have good ideas and code, they will always be welcome, but + please be prepared to justify your changes. + + Finally, thank you for using this library! + +v3.0.3 06 Jun 2025 + * Update some dependencies + * [jwe] Change some error messages to contain more context information + +v3.0.2 03 Jun 2025 + * [transform] (EXPERIMENTAL) Add utility function `transform.AsMap` to convert a + Mappable object to a map[string]interface{}. This is useful for converting + objects such as `jws.Header`, `jwk.Key`, `jwt.Token`, etc. to a map that can + be used with other libraries that expect a map. + * [jwt] (EXPERIMENTAL) Added token filtering functionality through the TokenFilter interface. + * [jwt/openid] (EXPERIMENTAL) Added StandardClaimsFilter() for filtering standard OpenID claims. + * [jws] (EXPERIMENTAL) Added header filtering functionality through the HeaderFilter interface. + * [jwe] (EXPERIMENTAL) Added header filtering functionality through the HeaderFilter interface. + * [jwk] (EXPERIMENTAL) Added key filtering functionality through the KeyFilter interface. + * [jwk] `jwk.Export` previously did not recognize third-party objects that implemented `jwk.Key`, + as it was detecting what to do by checking if the object was one of our own unexported + types. This caused some problems for consumers of this library that wanted to extend the + features of the keys. + + Now `jwk.Export` checks types against interface types such as `jwk.RSAPrivateKey`, `jwk.ECDSAPrivateKey`, etc. + It also uses some reflect blackmagic to detect if the given object implements the `jwk.Key` interface + via embedding, so you should be able to embed a `jwk.Key` to another object to act as if it + is a legitimate `jwk.Key`, as far as `jwk.Export` is concerned. + +v3.0.1 29 Apr 2025 + * [jwe] Fixed a long standing bug that could lead to degraded encryption or failure to + decrypt JWE messages when a very specific combination of inputs were used for + JWE operations. + + This problem only manifested itself when the following conditions in content encryption or decryption + were met: + - Content encryption was specified to use DIRECT mode. + - Contentn encryption algorithm is specified as A256CBC_HS512 + - The key was erronously constructed with a 32-byte content encryption key (CEK) + + In this case, the user would be passing a mis-constructed key of 32-bytes instead + of the intended 64-bytes. In all other cases, this construction would cause + an error because `crypto/aes.NewCipher` would return an error when a key with length + not matching 16, 24, and 32 bytes is used. However, due to use using a the provided + 32-bytes as half CEK and half the hash, the `crypto/aes.NewCipher` was passed + a 16-byte key, which is fine for AES-128. So internally `crypto/aes.NewCipher` would + choose to use AES-128 instead of AES-256, and happily continue. Note that no other + key lengths such as 48 and 128 would have worked. It had to be exactly 32. + + This does indeed result in a downgraded encryption, but we believe it is unlikely that this would cause a problem in the real world, + as you would have to very specifically choose to use DIRECT mode, choose + the specific content encryption algorithm, AND also use the wrong key size of + exactly 32 bytes. + + However, in abandunce of caution, we recommend that you upgrade to v3.0.1 or later, + or v2.1.6 or later if you are still on v2 series. + + * [jws] Improve performance of jws.SplitCompact and jws.SplitCompactString + * [jwe] Improve performance of jwe.Parse + +v3.0.0 1 Apr 2025 + * Release initial v3.0.0 series. Code is identical to v3.0.0-beta2, except + for minor documentation changes. + + Please note that v1 will no longer be maintained. + + Going forward v2 will receive security updates but will no longer receive + feature updates. Users are encouraged to migrate to v3. There is no hard-set + guarantee as to how long v2 will be supported, but if/when v4 comes out, + v2 support will be terminated then. + +v3.0.0-beta2 30 Mar 2025 + * [jwk] Fix a bug where `jwk.Set`'s `Keys()` method did not return the proper + non-standard fields. (#1322) + * [jws][jwt] Implement `WithBase64Encoder()` options to pass base64 encoders + to use during signing/verifying signatures. This useful when the token + provider generates JWTs that don't follow the specification and uses base64 + encoding other than raw url encoding (no padding), such as, apparently, + AWS ALB. (#1324, #1328) + +v3.0.0-beta1 15 Mar 2025 + * [jwt] Token validation no longer truncates time based fields by default. + To restore old behavior, you can either change the global settings by + calling `jwt.Settings(jwt.WithTruncation(time.Second))`, or you can + change it by each invocation by using `jwt.Validate(..., jwt.WithTruncation(time.Second))` + +v3.0.0-alpha3 13 Mar 2025 + * [jwk] Importing/Exporting from jwk.Key with P256/P386/P521 curves to + ecdh.PrivateKey/ecdh.PublicKey should now work. Previously these keys were not properly + recognized by the exporter/importer. Note that keys that use X25519 and P256/P384/P521 + behave differently: X25519 keys can only be exported to/imported from OKP keys, + while P256/P384/P521 can be exported to either ecdsa or ecdh keys. + +v3.0.0-alpha2 25 Feb 2025 + * Update to work with go1.24 + * Update tests to work with latest latchset/jose + * Fix build pipeline to work with latest golangci-lint + * Require go1.23 + +v3.0.0-alpha1 01 Nov 2024 + * Initial release of v3 line. diff --git a/vendor/github.com/lestrrat-go/jwx/v3/Changes-v2.md b/vendor/github.com/lestrrat-go/jwx/v3/Changes-v2.md new file mode 100644 index 00000000000..af146ed33ad --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/Changes-v2.md @@ -0,0 +1,390 @@ +# Incompatible Changes from v1 to v2 + +These are changes that are incompatible with the v1.x.x version. + +* [tl;dr](#tldr) - If you don't feel like reading the details -- but you will read the details, right? +* [Detailed List of Changes](#detailed-list-of-changes) - A comprehensive list of changes from v1 to v2 + +# tl;dr + +## JWT + +```go +// most basic +jwt.Parse(serialized, jwt.WithKey(alg, key)) // NOTE: verification and validation are ENABLED by default! +jwt.Sign(token, jwt.WithKey(alg,key)) + +// with a jwk.Set +jwt.Parse(serialized, jwt.WithKeySet(set)) + +// UseDefault/InferAlgorithm with JWKS +jwt.Parse(serialized, jwt.WithKeySet(set, + jws.WithUseDefault(true), jws.WithInferAlgorithm(true)) + +// Use `jku` +jwt.Parse(serialized, jwt.WithVerifyAuto(...)) + +// Any other custom key provisioning (using functions in this +// example, but can be anything that fulfills jws.KeyProvider) +jwt.Parse(serialized, jwt.WithKeyProvider(jws.KeyProviderFunc(...))) +``` + +## JWK + +```go +// jwk.New() was confusing. Renamed to fit the actual implementation +key, err := jwk.FromRaw(rawKey) + +// Algorithm() now returns jwa.KeyAlgorithm type. `jws.Sign()` +// and other function that receive JWK algorithm names accept +// this new type, so you can use the same key and do the following +// (previously you needed to type assert) +jws.Sign(payload, jws.WithKey(key.Algorithm(), key)) + +// If you need the specific type, type assert +key.Algorithm().(jwa.SignatureAlgorithm) + +// jwk.AutoRefresh is no more. Use jwk.Cache +cache := jwk.NewCache(ctx, options...) + +// Certificate chains are no longer jwk.CertificateChain type, but +// *(github.com/lestrrat-go/jwx/cert).Chain +cc := key.X509CertChain() // this is *cert.Chain now +``` + +## JWS + +```go +// basic +jws.Sign(payload, jws.WithKey(alg, key)) +jws.Sign(payload, jws.WithKey(alg, key), jws.WithKey(alg, key), jws.WithJSON(true)) +jws.Verify(signed, jws.WithKey(alg, key)) + +// other ways to pass the key +jws.Sign(payload, jws.WithKeySet(jwks)) +jws.Sign(payload, jws.WithKeyProvider(kp)) + +// retrieve the key that succeeded in verifying +var keyUsed interface{} +jws.Verify(signed, jws.WithKeySet(jwks), jws.WithKeyUsed(&keyUsed)) +``` + +## JWE + +```go +// basic +jwe.Encrypt(payload, jwe.WithKey(alg, key)) // other defaults are inferred +jwe.Encrypt(payload, jwe.WithKey(alg, key), jwe.WithKey(alg, key), jwe.WithJSON(true)) +jwe.Decrypt(encrypted, jwe.WithKey(alg, key)) + +// other ways to pass the key +jwe.Encrypt(payload, jwe.WithKeySet(jwks)) +jwe.Encrypt(payload, jwe.WithKeyProvider(kp)) + +// retrieve the key that succeeded in decrypting +var keyUsed interface{} +jwe.Verify(signed, jwe.WithKeySet(jwks), jwe.WithKeyUsed(&keyUsed)) +``` + +# Detailed List of Changes + +## Module + +* Module now requires go 1.16 + +* Use of github.com/pkg/errors is no more. If you were relying on behavior + that depends on the errors being an instance of github.com/pkg/errors + then you need to change your code + +* File-generation tools have been moved out of internal/ directories. + These files pre-dates Go modules, and they were in internal/ in order + to avoid being listed in the `go doc` -- however, now that we can + make them separate modules this is no longer necessary. + +* New package `cert` has been added to handle `x5c` certificate + chains, and to work with certificates + * cert.Chain to store base64 encoded ASN.1 DER format certificates + * cert.EncodeBase64 to encode ASN.1 DER format certificate using base64 + * cert.Create to create a base64 encoded ASN.1 DER format certificates + * cert.Parse to parse base64 encoded ASN.1 DER format certificates + +## JWE + +* `jwe.Compact()`'s signature has changed to + `jwe.Compact(*jwe.Message, ...jwe.CompactOption)` + +* `jwe.JSON()` has been removed. You can generate JSON serialization + using `jwe.Encrypt(jwe.WitJSON())` or `json.Marshal(jwe.Message)` + +* `(jwe.Message).Decrypt()` has been removed. Since formatting of the + original serialized message matters (including whitespace), using a parsed + object was inherently confusing. + +* `jwe.Encrypt()` can now generate JWE messages in either compact or JSON + forms. By default, the compact form is used. JSON format can be + enabled by using the `jwe.WithJSON` option. + +* `jwe.Encrypt()` can now accept multiple keys by passing multiple + `jwe.WithKey()` options. This can be used with `jwe.WithJSON` to + create JWE messages with multiple recipients. + +* `jwe.DecryptEncryptOption()` has been renamed to `jwe.EncryptDecryptOption()`. + This is so that it is more uniform with `jws` equivalent of `jws.SignVerifyOption()` + where the producer (`Sign`) comes before the consumer (`Verify`) in the naming + +* `jwe.WithCompact` and `jwe.WithJSON` options have been added + to control the serialization format. + +* jwe.Decrypt()'s method signature has been changed to `jwt.Decrypt([]byte, ...jwe.DecryptOption) ([]byte, error)`. + These options can be stacked. Therefore, you could configure the + verification process to attempt a static key pair, a JWKS, and only + try other forms if the first two fails, for example. + + - For static key pair, use `jwe.WithKey()` + - For static JWKS, use `jwe.WithKeySet()` (NOTE: InferAlgorithmFromKey like in `jws` package is NOT supported) + - For custom, possibly dynamic key provisioning, use `jwe.WithKeyProvider()` + +* jwe.Decrypter has been unexported. Users did not need this. + +* jwe.WithKeyProvider() has been added to specify arbitrary + code to specify which keys to try. + +* jwe.KeyProvider interface has been added + +* jwe.KeyProviderFunc has been added + +* `WithPostParser()` has been removed. You can achieve the same effect + by using `jwe.WithKeyProvider()`. Because this was the only consumer for + `jwe.DecryptCtx`, this type has been removed as well. + +* `x5c` field type has been changed to `*cert.Chain` instead of `[]string` + +* Method signature for `jwe.Parse()` has been changed to include options, + but options are currently not used + +* `jwe.ReadFile` now supports the option `jwe.WithFS` which allows you to + read data from arbitrary `fs.FS` objects + +* jwe.WithKeyUsed has been added to allow users to retrieve + the key used for decryption. This is useful in cases you provided + multiple keys and you want to know which one was successful + +## JWK + +* `jwk.New()` has been renamed to `jwk.FromRaw()`, which hopefully will + make it easier for the users what the input should be. + +* `jwk.Set` has many interface changes: + * Changed methods to match jwk.Key and its semantics: + * Field is now Get() (returns values for arbitrary fields other than keys). Fetching a key is done via Key() + * Remove() now removes arbitrary fields, not keys. to remove keys, use RemoveKey() + * Iterate has been added to iterate through all non-key fields. + * Add is now AddKey(Key) string, and returns an error when the same key is added + * Get is now Key(int) (Key, bool) + * Remove is now RemoveKey(Key) error + * Iterate is now Keys(context.Context) KeyIterator + * Clear is now Clear() error + +* `jwk.CachedSet` has been added. You can create a `jwk.Set` that is backed by + `jwk.Cache` so you can do this: + +```go +cache := jkw.NewCache(ctx) +cachedSet := jwk.NewCachedSet(cache, jwksURI) + +// cachedSet is always the refreshed, cached version from jwk.Cache +jws.Verify(signed, jws.WithKeySet(cachedSet)) +``` + +* `jwk.NewRSAPRivateKey()`, `jwk.NewECDSAPrivateKey()`, etc have been removed. + There is no longer any way to create concrete types of `jwk.Key` + +* `jwk.Key` type no longer supports direct unmarshaling via `json.Unmarshal()`, + because you can no longer instantiate concrete `jwk.Key` types. You will need to + use `jwk.ParseKey()`. See the documentation for ways to parse JWKs. + +* `(jwk.Key).Algorithm()` is now of `jwk.KeyAlgorithm` type. This field used + to be `string` and therefore could not be passed directly to `jwt.Sign()` + `jws.Sign()`, `jwe.Encrypt()`, et al. This is no longer the case, and + now you can pass it directly. See + https://github.com/lestrrat-go/jwx/blob/v2/docs/99-faq.md#why-is-jwkkeyalgorithm-and-jwakeyalgorithm-so-confusing + for more details + +* `jwk.Fetcher` and `jwk.FetchFunc` has been added. + They represent something that can fetch a `jwk.Set` + +* `jwk.CertificateChain` has been removed, use `*cert.Chain` +* `x5c` field type has been changed to `*cert.Chain` instead of `[]*x509.Certificate` + +* `jwk.ReadFile` now supports the option `jwk.WithFS` which allows you to + read data from arbitrary `fs.FS` objects + +* Added `jwk.PostFetcher`, `jwk.PostFetchFunc`, and `jwk.WithPostFetch` to + allow users to get at the `jwk.Set` that was fetched in `jwk.Cache`. + This will make it possible for users to supply extra information and edit + `jwk.Set` after it has been fetched and parsed, but before it is cached. + You could, for example, modify the `alg` field so that it's easier to + work with when you use it in `jws.Verify` later. + +* Reworked `jwk.AutoRefresh` in terms of `github.com/lestrrat-go/httprc` + and renamed it `jwk.Cache`. + + Major difference between `jwk.AutoRefresh` and `jwk.Cache` is that while + former used one `time.Timer` per resource, the latter uses a static timer + (based on `jwk.WithRefreshWindow()` value, default 15 minutes) that periodically + refreshes all resources that were due to be refreshed within that time frame. + + This method may cause your updates to happen slightly later, but uses significantly + less resources and is less prone to clogging. + +* Reimplemented `jwk.Fetch` in terms of `github.com/lestrrat-go/httprc`. + +* Previously `jwk.Fetch` and `jwk.AutoRefresh` respected backoff options, + but this has been removed. This is to avoid unwanted clogging of the fetch workers + which is the default processing mode in `github.com/lestrrat-go/httprc`. + + If you are using backoffs, you need to control your inputs more carefully so as + not to clog your fetch queue, and therefore you should be writing custom code that + suits your needs + +## JWS + +* `jws.Sign()` can now generate JWS messages in either compact or JSON + forms. By default, the compact form is used. JSON format can be + enabled by using the `jws.WithJSON` option. + +* `jws.Sign()` can now accept multiple keys by passing multiple + `jws.WithKey()` options. This can be used with `jws.WithJSON` to + create JWS messages with multiple signatures. + +* `jws.WithCompact` and `jws.WithJSON` options have been added + to control the serialization format. + +* jws.Verify()'s method signature has been changed to `jwt.Verify([]byte, ...jws.VerifyOption) ([]byte, error)`. + These options can be stacked. Therefore, you could configure the + verification process to attempt a static key pair, a JWKS, and only + try other forms if the first two fails, for example. + + - For static key pair, use `jws.WithKey()` + - For static JWKS, use `jws.WithKeySet()` + - For enabling verification using `jku`, use `jws.WithVerifyAuto()` + - For custom, possibly dynamic key provisioning, use `jws.WithKeyProvider()` + +* jws.WithVerify() has been removed. + +* jws.WithKey() has been added to specify an algorithm + key to + verify the payload with. + +* jws.WithKeySet() has been added to specify a JWKS to be used for + verification. By default `kid` AND `alg` must match between the signature + and the key. + + The option can take further suboptions: + +```go +jws.Parse(serialized, + jws.WithKeySet(set, + // by default `kid` is required. set false to disable. + jws.WithRequireKid(false), + // optionally skip matching kid if there's exactly one key in set + jws.WithUseDefault(true), + // infer algorithm name from key type + jws.WithInferAlgorithm(true), + ), +) +``` + +* `jws.VerifuAuto` has been removed in favor of using + `jws.WithVerifyAuto` option with `jws.Verify()` + +* `jws.WithVerifyAuto` has been added to enable verification + using `jku`. + + The first argument must be a jwk.Fetcher object, but can be + set to `nil` to use the default implementation which is `jwk.Fetch` + + The rest of the arguments are treated as options passed to the + `(jwk.Fetcher).Fetch()` function. + +* Remove `jws.WithPayloadSigner()`. This should be completely replaceable + using `jws.WithKey()` + +* jws.WithKeyProvider() has been added to specify arbitrary + code to specify which keys to try. + +* jws.KeyProvider interface has been added + +* jws.KeyProviderFunc has been added + +* jws.WithKeyUsed has been added to allow users to retrieve + the key used for verification. This is useful in cases you provided + multiple keys and you want to know which one was successful + +* `x5c` field type has been changed to `*cert.Chain` instead of `[]string` + +* `jws.ReadFile` now supports the option `jws.WithFS` which allows you to + read data from arbitrary `fs.FS` objects + +## JWT + +* `jwt.Parse` now verifies the signature and validates the token + by default. You must disable it explicitly using `jwt.WithValidate(false)` + and/or `jwt.WithVerify(false)` if you only want to parse the JWT message. + + If you don't want either, a convenience function `jwt.ParseInsecure` + has been added. + +* `jwt.Parse` can only parse raw JWT (JSON) or JWS (JSON or Compact). + It no longer accepts JWE messages. + +* `jwt.WithDecrypt` has been removed + +* `jwt.WithJweHeaders` has been removed + +* `jwt.WithVerify()` has been renamed to `jwt.WithKey()`. The option can + be used for signing, encryption, and parsing. + +* `jwt.Validator` has been changed to return `jwt.ValidationError`. + If you provide a custom validator, you should wrap the error with + `jwt.NewValidationError()` + +* `jwt.UseDefault()` has been removed. You should use `jws.WithUseDefault()` + as a suboption in the `jwt.WithKeySet()` option. + +```go +jwt.Parse(serialized, jwt.WithKeySet(set, jws.WithUseDefault(true))) +``` + +* `jwt.InferAlgorithmFromKey()` has been removed. You should use + `jws.WithInferAlgorithmFromKey()` as a suboption in the `jwt.WithKeySet()` option. + +```go +jwt.Parse(serialized, jwt.WithKeySet(set, jws.WithInferAlgorithmFromKey(true))) +``` + +* jwt.WithKeySetProvider has been removed. Use `jwt.WithKeyProvider()` + instead. If jwt.WithKeyProvider seems a bit complicated, use a combination of + JWS parse, no-verify/validate JWT parse, and an extra JWS verify: + +```go +msg, _ := jws.Parse(signed) +token, _ := jwt.Parse(msg.Payload(), jwt.WithVerify(false), jwt.WithValidate(false)) +// Get information out of token, for example, `iss` +switch token.Issuer() { +case ...: + jws.Verify(signed, jwt.WithKey(...)) +} +``` + +* `jwt.WithHeaders` and `jwt.WithJwsHeaders` have been removed. + You should be able to use the new `jwt.WithKey` option to pass headers + +* `jwt.WithSignOption` and `jwt.WithEncryptOption` have been added as + escape hatches for options that are declared in `jws` and `jwe` packages + but not in `jwt` + +* `jwt.ReadFile` now supports the option `jwt.WithFS` which allows you to + read data from arbitrary `fs.FS` objects + +* `jwt.Sign()` has been changed so that it works more like the new `jws.Sign()` + diff --git a/vendor/github.com/lestrrat-go/jwx/v3/Changes-v3.md b/vendor/github.com/lestrrat-go/jwx/v3/Changes-v3.md new file mode 100644 index 00000000000..c2fa8747b9e --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/Changes-v3.md @@ -0,0 +1,140 @@ +# Incompatible Changes from v2 to v3 + +These are changes that are incompatible with the v2.x.x version. + +# Detailed list of changes + +## Module + +* This module now requires Go 1.23 + +* All `xxx.Get()` methods have been changed from `Get(string) (interface{}, error)` to + `Get(string, interface{}) error`, where the second argument should be a pointer + to the storage destination of the field. + +* All convenience accessors (e.g. `(jwt.Token).Subject`) now return `(T, bool)` instead of + `T`. If you want an accessor that returns a single value, consider using `Get()` + +* Most major errors can now be differentiated using `errors.Is` + +## JWA + +* All string constants have been renamed to equivalent functions that return a struct. + You should rewrite `jwa.RS256` as `jwa.RS256()` and so forth. + +* By default, only known algorithm names are accepted. For example, in our JWK tests, + there are tests that deal with "ECMR" algorithm, but this will now fail by default. + If you want this algorithm to succeed parsing, you need to call `jwa.RegisterXXXX` + functions before using them. + +* Previously, unmarshaling unquoted strings used to work (e.g. `var s = "RS256"`), + but now they must conform to the JSON standard and be quoted (e.g. `var s = strconv.Quote("RS256")`) + +## JWT + +* All convenience accessors (e.g. `Subject`) now return `(T, bool)` instead of + just `T`. If you want a single return value accessor, use `Get(dst) error` instead. + +* Validation used to work for `iat`, `nbf`, `exp` fields where these fields were + set to the explicit time.Time{} zero value, but now the _presence_ of these fields matter. + +* Validation of fields related to time used to be truncated to one second accuracy, + but no longer does so. To restore old behavior, you can either change the global settings by + calling `jwt.Settings(jwt.WithTruncation(time.Second))`, or you can + change it by each invocation by using `jwt.Validate(..., jwt.WithTruncation(time.Second))` + +* Error names have been renamed. For example `jwt.ErrInvalidJWT` has been renamed to + `jwt.UnknownPayloadTypeError` to better reflect what the error means. For other errors, + `func ErrXXXX()` have generally been renamed to `func XXXError()` + +* Validation errors are now wrapped. While `Validate()` returns a `ValidateError()` type, + it can also be matched against more specific error types such as `TokenExpierdError()` + using `errors.Is` + +* `jwt.ErrMissingRequiredClaim` has been removed + +## JWS + +* Iterators have been completely removed. +* As a side effect of removing iterators, some methods such as `Copy()` lost the + `context.Context` argument + +* All convenience accessors (e.g. `Algorithm`) now return `(T, bool)` instead of + just `T`. If you want a single return value accessor, use `Get(dst) error` instead. + +* Errors from `jws.Sign` and `jws.Verify`, as well as `jws.Parse` (and friends) + can now be differentiated by using `errors.Is`. All `jws.IsXXXXError` functions + have been removed. + +## JWE + +* Iterators have been completely removed. +* As a side effect of removing iterators, some methods such as `Copy()` lost the + `context.Context` argument + +* All convenience accessors (e.g. `Algorithm`) now return `(T, bool)` instead of + just `T`. If you want a single return value accessor, use `Get(dst) error` instead. + +* Errors from `jwe.Decrypt` and `jwe.Encrypt`, as well as `jwe.Parse` (and friends) + can now be differentiated by using `errors.Is`. All `jwe.IsXXXXrror` functions + have been removed. + +## JWK + +* All convenience accessors (e.g. `Algorithm`, `Crv`) now return `(T, bool)` instead + of just `T`, except `KeyType`, which _always_ returns a valid value. If you want a + single return value accessor, use `Get(dst) error` instead. + +* `jwk.KeyUsageType` can now be configured so that it's possible to assign values + other than "sig" and "enc" via `jwk.RegisterKeyUsage()`. Furthermore, strict + checks can be turned on/off against these registered values + +* `jwk.Cache` has been completely re-worked based on github.com/lestrrat-go/httprc/v3. + In particular, the default whitelist mode has changed from "block everything" to + "allow everything". + +* Experimental secp256k1 encoding/decoding for PEM encoded ASN.1 DER Format + has been removed. Instead, `jwk.PEMDecoder` and `jwk.PEMEncoder` have been + added to support those who want to perform non-standard PEM encoding/decoding + +* Iterators have been completely removed. + +* `jwk/x25519` has been removed. To use X25519 keys, use `(crypto/ecdh).PrivateKey` and + `(crypto/ecdh).PublicKey`. Similarly, internals have been reworked to use `crypto/ecdh` + +* Parsing has completely been reworked. It is now possible to add your own `jwk.KeyParser` + to generate a custom `jwk.Key` that this library may not natively support. Also see + `jwk.RegisterKeyParser()` + +* `jwk.KeyProbe` has been added to aid probing the JSON message. This is used to + guess the type of key described in the JSON message before deciding which concrete + type to instantiate, and aids implementing your own `jwk.KeyParser`. Also see + `jwk.RegisterKeyProbe()` + +* Conversion between raw keys and `jwk.Key` can be customized using `jwk.KeyImporter` and `jwk.KeyExporter`. + Also see `jwk.RegisterKeyImporter()` and `jwk.RegisterKeyExporter()` + +* Added `jwk/ecdsa` to keep track of which curves are available for ECDSA keys. + +* `(jwk.Key).Raw()` has been deprecated. Use `jwk.Export()` instead to convert `jwk.Key` + objects into their "raw" versions (e.g. `*rsa.PrivateKey`, `*ecdsa.PrivateKey`, etc). + This is to allow third parties to register custom key types that this library does not + natively support: Whereas a method must be bound to an object, and thus does not necessarily + have a way to hook into a global settings (i.e. custom exporter/importer) for arbitrary + key types, if the entrypoint is a function it's much easier and cleaner to for third-parties + to take advantage and hook into the mechanisms. + +* `jwk.FromRaw()` has been derepcated. Use `jwk.Import()` instead to convert "raw" + keys (e.g. `*rsa.PrivateKEy`, `*Ecdsa.PrivateKey`, etc) int `jwk.Key`s. + +* `(jwk.Key).FromRaw()` has been deprecated. The method `(jwk.Key).Import()` still exist for + built-in types, but it is no longer part of any public API (`interface{}`). + +* `jwk.Fetch` is marked as a simple wrapper around `net/http` and `jwk.Parse`. + +* `jwk.SetGlobalFetcher` has been deprecated. + +* `jwk.Fetcher` has been clearly marked as something that has limited + usage for `jws.WithVerifyAuto` + +* `jwk.Key` with P256/P386/P521 curves can be exporrted to `ecdh.PrivateKey`/`ecdh.PublicKey` \ No newline at end of file diff --git a/vendor/github.com/open-policy-agent/opa/internal/jwx/LICENSE b/vendor/github.com/lestrrat-go/jwx/v3/LICENSE similarity index 99% rename from vendor/github.com/open-policy-agent/opa/internal/jwx/LICENSE rename to vendor/github.com/lestrrat-go/jwx/v3/LICENSE index 6369f4fcc40..205e33a7f14 100644 --- a/vendor/github.com/open-policy-agent/opa/internal/jwx/LICENSE +++ b/vendor/github.com/lestrrat-go/jwx/v3/LICENSE @@ -19,3 +19,4 @@ 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/lestrrat-go/jwx/v3/MODULE.bazel b/vendor/github.com/lestrrat-go/jwx/v3/MODULE.bazel new file mode 100644 index 00000000000..167e9b5c89d --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/MODULE.bazel @@ -0,0 +1,34 @@ +module( + name = "com_github_lestrrat_go_jwx_v3", + version = "3.0.0", + repo_name = "com_github_lestrrat_go_jwx_v2", +) + +bazel_dep(name = "bazel_skylib", version = "1.7.1") +bazel_dep(name = "rules_go", version = "0.55.1") +bazel_dep(name = "gazelle", version = "0.44.0") +bazel_dep(name = "aspect_bazel_lib", version = "2.11.0") + +# Go SDK setup - using Go 1.24.4 to match the toolchain in go.mod +go_sdk = use_extension("@rules_go//go:extensions.bzl", "go_sdk") +go_sdk.download(version = "1.24.4") + +# Go dependencies from go.mod +go_deps = use_extension("@gazelle//:extensions.bzl", "go_deps") +go_deps.from_file(go_mod = "//:go.mod") + +# Use repositories for external Go dependencies +use_repo( + go_deps, + "com_github_decred_dcrd_dcrec_secp256k1_v4", + "com_github_goccy_go_json", + "com_github_lestrrat_go_blackmagic", + "com_github_lestrrat_go_dsig", + "com_github_lestrrat_go_dsig_secp256k1", + "com_github_lestrrat_go_httprc_v3", + "com_github_lestrrat_go_option_v2", + "com_github_segmentio_asm", + "com_github_stretchr_testify", + "com_github_valyala_fastjson", + "org_golang_x_crypto", +) diff --git a/vendor/github.com/lestrrat-go/jwx/v3/MODULE.bazel.lock b/vendor/github.com/lestrrat-go/jwx/v3/MODULE.bazel.lock new file mode 100644 index 00000000000..2848e8716d4 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/MODULE.bazel.lock @@ -0,0 +1,230 @@ +{ + "lockFileVersion": 18, + "registryFileHashes": { + "https://bcr.bazel.build/bazel_registry.json": "8a28e4aff06ee60aed2a8c281907fb8bcbf3b753c91fb5a5c57da3215d5b3497", + "https://bcr.bazel.build/modules/abseil-cpp/20210324.2/MODULE.bazel": "7cd0312e064fde87c8d1cd79ba06c876bd23630c83466e9500321be55c96ace2", + "https://bcr.bazel.build/modules/abseil-cpp/20211102.0/MODULE.bazel": "70390338f7a5106231d20620712f7cccb659cd0e9d073d1991c038eb9fc57589", + "https://bcr.bazel.build/modules/abseil-cpp/20230125.1/MODULE.bazel": "89047429cb0207707b2dface14ba7f8df85273d484c2572755be4bab7ce9c3a0", + "https://bcr.bazel.build/modules/abseil-cpp/20230802.0.bcr.1/MODULE.bazel": "1c8cec495288dccd14fdae6e3f95f772c1c91857047a098fad772034264cc8cb", + "https://bcr.bazel.build/modules/abseil-cpp/20230802.0/MODULE.bazel": "d253ae36a8bd9ee3c5955384096ccb6baf16a1b1e93e858370da0a3b94f77c16", + "https://bcr.bazel.build/modules/abseil-cpp/20230802.1/MODULE.bazel": "fa92e2eb41a04df73cdabeec37107316f7e5272650f81d6cc096418fe647b915", + "https://bcr.bazel.build/modules/abseil-cpp/20240116.1/MODULE.bazel": "37bcdb4440fbb61df6a1c296ae01b327f19e9bb521f9b8e26ec854b6f97309ed", + "https://bcr.bazel.build/modules/abseil-cpp/20240116.1/source.json": "9be551b8d4e3ef76875c0d744b5d6a504a27e3ae67bc6b28f46415fd2d2957da", + "https://bcr.bazel.build/modules/aspect_bazel_lib/2.11.0/MODULE.bazel": "cb1ba9f9999ed0bc08600c221f532c1ddd8d217686b32ba7d45b0713b5131452", + "https://bcr.bazel.build/modules/aspect_bazel_lib/2.11.0/source.json": "92494d5aa43b96665397dd13ee16023097470fa85e276b93674d62a244de47ee", + "https://bcr.bazel.build/modules/bazel_features/1.1.0/MODULE.bazel": "cfd42ff3b815a5f39554d97182657f8c4b9719568eb7fded2b9135f084bf760b", + "https://bcr.bazel.build/modules/bazel_features/1.1.1/MODULE.bazel": "27b8c79ef57efe08efccbd9dd6ef70d61b4798320b8d3c134fd571f78963dbcd", + "https://bcr.bazel.build/modules/bazel_features/1.11.0/MODULE.bazel": "f9382337dd5a474c3b7d334c2f83e50b6eaedc284253334cf823044a26de03e8", + "https://bcr.bazel.build/modules/bazel_features/1.15.0/MODULE.bazel": "d38ff6e517149dc509406aca0db3ad1efdd890a85e049585b7234d04238e2a4d", + "https://bcr.bazel.build/modules/bazel_features/1.17.0/MODULE.bazel": "039de32d21b816b47bd42c778e0454217e9c9caac4a3cf8e15c7231ee3ddee4d", + "https://bcr.bazel.build/modules/bazel_features/1.18.0/MODULE.bazel": "1be0ae2557ab3a72a57aeb31b29be347bcdc5d2b1eb1e70f39e3851a7e97041a", + "https://bcr.bazel.build/modules/bazel_features/1.19.0/MODULE.bazel": "59adcdf28230d220f0067b1f435b8537dd033bfff8db21335ef9217919c7fb58", + "https://bcr.bazel.build/modules/bazel_features/1.30.0/MODULE.bazel": "a14b62d05969a293b80257e72e597c2da7f717e1e69fa8b339703ed6731bec87", + "https://bcr.bazel.build/modules/bazel_features/1.30.0/source.json": "b07e17f067fe4f69f90b03b36ef1e08fe0d1f3cac254c1241a1818773e3423bc", + "https://bcr.bazel.build/modules/bazel_features/1.4.1/MODULE.bazel": "e45b6bb2350aff3e442ae1111c555e27eac1d915e77775f6fdc4b351b758b5d7", + "https://bcr.bazel.build/modules/bazel_features/1.9.0/MODULE.bazel": "885151d58d90d8d9c811eb75e3288c11f850e1d6b481a8c9f766adee4712358b", + "https://bcr.bazel.build/modules/bazel_features/1.9.1/MODULE.bazel": "8f679097876a9b609ad1f60249c49d68bfab783dd9be012faf9d82547b14815a", + "https://bcr.bazel.build/modules/bazel_skylib/1.0.3/MODULE.bazel": "bcb0fd896384802d1ad283b4e4eb4d718eebd8cb820b0a2c3a347fb971afd9d8", + "https://bcr.bazel.build/modules/bazel_skylib/1.1.1/MODULE.bazel": "1add3e7d93ff2e6998f9e118022c84d163917d912f5afafb3058e3d2f1545b5e", + "https://bcr.bazel.build/modules/bazel_skylib/1.2.0/MODULE.bazel": "44fe84260e454ed94ad326352a698422dbe372b21a1ac9f3eab76eb531223686", + "https://bcr.bazel.build/modules/bazel_skylib/1.2.1/MODULE.bazel": "f35baf9da0efe45fa3da1696ae906eea3d615ad41e2e3def4aeb4e8bc0ef9a7a", + "https://bcr.bazel.build/modules/bazel_skylib/1.3.0/MODULE.bazel": "20228b92868bf5cfc41bda7afc8a8ba2a543201851de39d990ec957b513579c5", + "https://bcr.bazel.build/modules/bazel_skylib/1.4.1/MODULE.bazel": "a0dcb779424be33100dcae821e9e27e4f2901d9dfd5333efe5ac6a8d7ab75e1d", + "https://bcr.bazel.build/modules/bazel_skylib/1.4.2/MODULE.bazel": "3bd40978e7a1fac911d5989e6b09d8f64921865a45822d8b09e815eaa726a651", + "https://bcr.bazel.build/modules/bazel_skylib/1.5.0/MODULE.bazel": "32880f5e2945ce6a03d1fbd588e9198c0a959bb42297b2cfaf1685b7bc32e138", + "https://bcr.bazel.build/modules/bazel_skylib/1.6.1/MODULE.bazel": "8fdee2dbaace6c252131c00e1de4b165dc65af02ea278476187765e1a617b917", + "https://bcr.bazel.build/modules/bazel_skylib/1.7.0/MODULE.bazel": "0db596f4563de7938de764cc8deeabec291f55e8ec15299718b93c4423e9796d", + "https://bcr.bazel.build/modules/bazel_skylib/1.7.1/MODULE.bazel": "3120d80c5861aa616222ec015332e5f8d3171e062e3e804a2a0253e1be26e59b", + "https://bcr.bazel.build/modules/bazel_skylib/1.7.1/source.json": "f121b43eeefc7c29efbd51b83d08631e2347297c95aac9764a701f2a6a2bb953", + "https://bcr.bazel.build/modules/buildozer/7.1.2/MODULE.bazel": "2e8dd40ede9c454042645fd8d8d0cd1527966aa5c919de86661e62953cd73d84", + "https://bcr.bazel.build/modules/buildozer/7.1.2/source.json": "c9028a501d2db85793a6996205c8de120944f50a0d570438fcae0457a5f9d1f8", + "https://bcr.bazel.build/modules/gazelle/0.32.0/MODULE.bazel": "b499f58a5d0d3537f3cf5b76d8ada18242f64ec474d8391247438bf04f58c7b8", + "https://bcr.bazel.build/modules/gazelle/0.33.0/MODULE.bazel": "a13a0f279b462b784fb8dd52a4074526c4a2afe70e114c7d09066097a46b3350", + "https://bcr.bazel.build/modules/gazelle/0.34.0/MODULE.bazel": "abdd8ce4d70978933209db92e436deb3a8b737859e9354fb5fd11fb5c2004c8a", + "https://bcr.bazel.build/modules/gazelle/0.36.0/MODULE.bazel": "e375d5d6e9a6ca59b0cb38b0540bc9a05b6aa926d322f2de268ad267a2ee74c0", + "https://bcr.bazel.build/modules/gazelle/0.44.0/MODULE.bazel": "fd3177ca0938da57a1e416cad3f39b9c4334defbc717e89aba9d9ddbbb0341da", + "https://bcr.bazel.build/modules/gazelle/0.44.0/source.json": "7fb65ef9c1ce470d099ca27fd478673d9d64c844af28d0d472b0874c7d590cb6", + "https://bcr.bazel.build/modules/google_benchmark/1.8.2/MODULE.bazel": "a70cf1bba851000ba93b58ae2f6d76490a9feb74192e57ab8e8ff13c34ec50cb", + "https://bcr.bazel.build/modules/googletest/1.11.0/MODULE.bazel": "3a83f095183f66345ca86aa13c58b59f9f94a2f81999c093d4eeaa2d262d12f4", + "https://bcr.bazel.build/modules/googletest/1.14.0.bcr.1/MODULE.bazel": "22c31a561553727960057361aa33bf20fb2e98584bc4fec007906e27053f80c6", + "https://bcr.bazel.build/modules/googletest/1.14.0.bcr.1/source.json": "41e9e129f80d8c8bf103a7acc337b76e54fad1214ac0a7084bf24f4cd924b8b4", + "https://bcr.bazel.build/modules/googletest/1.14.0/MODULE.bazel": "cfbcbf3e6eac06ef9d85900f64424708cc08687d1b527f0ef65aa7517af8118f", + "https://bcr.bazel.build/modules/jsoncpp/1.9.5/MODULE.bazel": "31271aedc59e815656f5736f282bb7509a97c7ecb43e927ac1a37966e0578075", + "https://bcr.bazel.build/modules/jsoncpp/1.9.5/source.json": "4108ee5085dd2885a341c7fab149429db457b3169b86eb081fa245eadf69169d", + "https://bcr.bazel.build/modules/libpfm/4.11.0/MODULE.bazel": "45061ff025b301940f1e30d2c16bea596c25b176c8b6b3087e92615adbd52902", + "https://bcr.bazel.build/modules/package_metadata/0.0.2/MODULE.bazel": "fb8d25550742674d63d7b250063d4580ca530499f045d70748b1b142081ebb92", + "https://bcr.bazel.build/modules/package_metadata/0.0.2/source.json": "e53a759a72488d2c0576f57491ef2da0cf4aab05ac0997314012495935531b73", + "https://bcr.bazel.build/modules/platforms/0.0.10/MODULE.bazel": "8cb8efaf200bdeb2150d93e162c40f388529a25852b332cec879373771e48ed5", + "https://bcr.bazel.build/modules/platforms/0.0.11/MODULE.bazel": "0daefc49732e227caa8bfa834d65dc52e8cc18a2faf80df25e8caea151a9413f", + "https://bcr.bazel.build/modules/platforms/0.0.11/source.json": "f7e188b79ebedebfe75e9e1d098b8845226c7992b307e28e1496f23112e8fc29", + "https://bcr.bazel.build/modules/platforms/0.0.4/MODULE.bazel": "9b328e31ee156f53f3c416a64f8491f7eb731742655a47c9eec4703a71644aee", + "https://bcr.bazel.build/modules/platforms/0.0.5/MODULE.bazel": "5733b54ea419d5eaf7997054bb55f6a1d0b5ff8aedf0176fef9eea44f3acda37", + "https://bcr.bazel.build/modules/platforms/0.0.6/MODULE.bazel": "ad6eeef431dc52aefd2d77ed20a4b353f8ebf0f4ecdd26a807d2da5aa8cd0615", + "https://bcr.bazel.build/modules/platforms/0.0.7/MODULE.bazel": "72fd4a0ede9ee5c021f6a8dd92b503e089f46c227ba2813ff183b71616034814", + "https://bcr.bazel.build/modules/platforms/0.0.8/MODULE.bazel": "9f142c03e348f6d263719f5074b21ef3adf0b139ee4c5133e2aa35664da9eb2d", + "https://bcr.bazel.build/modules/protobuf/21.7/MODULE.bazel": "a5a29bb89544f9b97edce05642fac225a808b5b7be74038ea3640fae2f8e66a7", + "https://bcr.bazel.build/modules/protobuf/27.0/MODULE.bazel": "7873b60be88844a0a1d8f80b9d5d20cfbd8495a689b8763e76c6372998d3f64c", + "https://bcr.bazel.build/modules/protobuf/27.1/MODULE.bazel": "703a7b614728bb06647f965264967a8ef1c39e09e8f167b3ca0bb1fd80449c0d", + "https://bcr.bazel.build/modules/protobuf/29.0-rc2.bcr.1/MODULE.bazel": "52f4126f63a2f0bbf36b99c2a87648f08467a4eaf92ba726bc7d6a500bbf770c", + "https://bcr.bazel.build/modules/protobuf/29.0-rc2/MODULE.bazel": "6241d35983510143049943fc0d57937937122baf1b287862f9dc8590fc4c37df", + "https://bcr.bazel.build/modules/protobuf/29.0/MODULE.bazel": "319dc8bf4c679ff87e71b1ccfb5a6e90a6dbc4693501d471f48662ac46d04e4e", + "https://bcr.bazel.build/modules/protobuf/29.0/source.json": "b857f93c796750eef95f0d61ee378f3420d00ee1dd38627b27193aa482f4f981", + "https://bcr.bazel.build/modules/protobuf/3.19.0/MODULE.bazel": "6b5fbb433f760a99a22b18b6850ed5784ef0e9928a72668b66e4d7ccd47db9b0", + "https://bcr.bazel.build/modules/protobuf/3.19.2/MODULE.bazel": "532ffe5f2186b69fdde039efe6df13ba726ff338c6bc82275ad433013fa10573", + "https://bcr.bazel.build/modules/protobuf/3.19.6/MODULE.bazel": "9233edc5e1f2ee276a60de3eaa47ac4132302ef9643238f23128fea53ea12858", + "https://bcr.bazel.build/modules/pybind11_bazel/2.11.1/MODULE.bazel": "88af1c246226d87e65be78ed49ecd1e6f5e98648558c14ce99176da041dc378e", + "https://bcr.bazel.build/modules/pybind11_bazel/2.11.1/source.json": "be4789e951dd5301282729fe3d4938995dc4c1a81c2ff150afc9f1b0504c6022", + "https://bcr.bazel.build/modules/re2/2023-09-01/MODULE.bazel": "cb3d511531b16cfc78a225a9e2136007a48cf8a677e4264baeab57fe78a80206", + "https://bcr.bazel.build/modules/re2/2023-09-01/source.json": "e044ce89c2883cd957a2969a43e79f7752f9656f6b20050b62f90ede21ec6eb4", + "https://bcr.bazel.build/modules/rules_android/0.1.1/MODULE.bazel": "48809ab0091b07ad0182defb787c4c5328bd3a278938415c00a7b69b50c4d3a8", + "https://bcr.bazel.build/modules/rules_android/0.1.1/source.json": "e6986b41626ee10bdc864937ffb6d6bf275bb5b9c65120e6137d56e6331f089e", + "https://bcr.bazel.build/modules/rules_cc/0.0.1/MODULE.bazel": "cb2aa0747f84c6c3a78dad4e2049c154f08ab9d166b1273835a8174940365647", + "https://bcr.bazel.build/modules/rules_cc/0.0.10/MODULE.bazel": "ec1705118f7eaedd6e118508d3d26deba2a4e76476ada7e0e3965211be012002", + "https://bcr.bazel.build/modules/rules_cc/0.0.13/MODULE.bazel": "0e8529ed7b323dad0775ff924d2ae5af7640b23553dfcd4d34344c7e7a867191", + "https://bcr.bazel.build/modules/rules_cc/0.0.14/MODULE.bazel": "5e343a3aac88b8d7af3b1b6d2093b55c347b8eefc2e7d1442f7a02dc8fea48ac", + "https://bcr.bazel.build/modules/rules_cc/0.0.15/MODULE.bazel": "6704c35f7b4a72502ee81f61bf88706b54f06b3cbe5558ac17e2e14666cd5dcc", + "https://bcr.bazel.build/modules/rules_cc/0.0.16/MODULE.bazel": "7661303b8fc1b4d7f532e54e9d6565771fea666fbdf839e0a86affcd02defe87", + "https://bcr.bazel.build/modules/rules_cc/0.0.2/MODULE.bazel": "6915987c90970493ab97393024c156ea8fb9f3bea953b2f3ec05c34f19b5695c", + "https://bcr.bazel.build/modules/rules_cc/0.0.6/MODULE.bazel": "abf360251023dfe3efcef65ab9d56beefa8394d4176dd29529750e1c57eaa33f", + "https://bcr.bazel.build/modules/rules_cc/0.0.8/MODULE.bazel": "964c85c82cfeb6f3855e6a07054fdb159aced38e99a5eecf7bce9d53990afa3e", + "https://bcr.bazel.build/modules/rules_cc/0.0.9/MODULE.bazel": "836e76439f354b89afe6a911a7adf59a6b2518fafb174483ad78a2a2fde7b1c5", + "https://bcr.bazel.build/modules/rules_cc/0.1.1/MODULE.bazel": "2f0222a6f229f0bf44cd711dc13c858dad98c62d52bd51d8fc3a764a83125513", + "https://bcr.bazel.build/modules/rules_cc/0.1.1/source.json": "d61627377bd7dd1da4652063e368d9366fc9a73920bfa396798ad92172cf645c", + "https://bcr.bazel.build/modules/rules_foreign_cc/0.9.0/MODULE.bazel": "c9e8c682bf75b0e7c704166d79b599f93b72cfca5ad7477df596947891feeef6", + "https://bcr.bazel.build/modules/rules_fuzzing/0.5.2/MODULE.bazel": "40c97d1144356f52905566c55811f13b299453a14ac7769dfba2ac38192337a8", + "https://bcr.bazel.build/modules/rules_fuzzing/0.5.2/source.json": "c8b1e2c717646f1702290959a3302a178fb639d987ab61d548105019f11e527e", + "https://bcr.bazel.build/modules/rules_go/0.41.0/MODULE.bazel": "55861d8e8bb0e62cbd2896f60ff303f62ffcb0eddb74ecb0e5c0cbe36fc292c8", + "https://bcr.bazel.build/modules/rules_go/0.42.0/MODULE.bazel": "8cfa875b9aa8c6fce2b2e5925e73c1388173ea3c32a0db4d2b4804b453c14270", + "https://bcr.bazel.build/modules/rules_go/0.46.0/MODULE.bazel": "3477df8bdcc49e698b9d25f734c4f3a9f5931ff34ee48a2c662be168f5f2d3fd", + "https://bcr.bazel.build/modules/rules_go/0.51.0/MODULE.bazel": "b6920f505935bfd69381651c942496d99b16e2a12f3dd5263b90ded16f3b4d0f", + "https://bcr.bazel.build/modules/rules_go/0.55.1/MODULE.bazel": "a57a6fc59a74326c0b440d07cca209edf13c7d1a641e48cfbeab56e79f873609", + "https://bcr.bazel.build/modules/rules_go/0.55.1/source.json": "827a740c8959c9d20616889e7746cde4dcc6ee80d25146943627ccea0736328f", + "https://bcr.bazel.build/modules/rules_java/4.0.0/MODULE.bazel": "5a78a7ae82cd1a33cef56dc578c7d2a46ed0dca12643ee45edbb8417899e6f74", + "https://bcr.bazel.build/modules/rules_java/5.3.5/MODULE.bazel": "a4ec4f2db570171e3e5eb753276ee4b389bae16b96207e9d3230895c99644b86", + "https://bcr.bazel.build/modules/rules_java/6.0.0/MODULE.bazel": "8a43b7df601a7ec1af61d79345c17b31ea1fedc6711fd4abfd013ea612978e39", + "https://bcr.bazel.build/modules/rules_java/6.3.0/MODULE.bazel": "a97c7678c19f236a956ad260d59c86e10a463badb7eb2eda787490f4c969b963", + "https://bcr.bazel.build/modules/rules_java/6.4.0/MODULE.bazel": "e986a9fe25aeaa84ac17ca093ef13a4637f6107375f64667a15999f77db6c8f6", + "https://bcr.bazel.build/modules/rules_java/6.5.2/MODULE.bazel": "1d440d262d0e08453fa0c4d8f699ba81609ed0e9a9a0f02cd10b3e7942e61e31", + "https://bcr.bazel.build/modules/rules_java/7.10.0/MODULE.bazel": "530c3beb3067e870561739f1144329a21c851ff771cd752a49e06e3dc9c2e71a", + "https://bcr.bazel.build/modules/rules_java/7.12.2/MODULE.bazel": "579c505165ee757a4280ef83cda0150eea193eed3bef50b1004ba88b99da6de6", + "https://bcr.bazel.build/modules/rules_java/7.2.0/MODULE.bazel": "06c0334c9be61e6cef2c8c84a7800cef502063269a5af25ceb100b192453d4ab", + "https://bcr.bazel.build/modules/rules_java/7.3.2/MODULE.bazel": "50dece891cfdf1741ea230d001aa9c14398062f2b7c066470accace78e412bc2", + "https://bcr.bazel.build/modules/rules_java/7.6.1/MODULE.bazel": "2f14b7e8a1aa2f67ae92bc69d1ec0fa8d9f827c4e17ff5e5f02e91caa3b2d0fe", + "https://bcr.bazel.build/modules/rules_java/8.12.0/MODULE.bazel": "8e6590b961f2defdfc2811c089c75716cb2f06c8a4edeb9a8d85eaa64ee2a761", + "https://bcr.bazel.build/modules/rules_java/8.12.0/source.json": "cbd5d55d9d38d4008a7d00bee5b5a5a4b6031fcd4a56515c9accbcd42c7be2ba", + "https://bcr.bazel.build/modules/rules_jvm_external/4.4.2/MODULE.bazel": "a56b85e418c83eb1839819f0b515c431010160383306d13ec21959ac412d2fe7", + "https://bcr.bazel.build/modules/rules_jvm_external/5.1/MODULE.bazel": "33f6f999e03183f7d088c9be518a63467dfd0be94a11d0055fe2d210f89aa909", + "https://bcr.bazel.build/modules/rules_jvm_external/5.2/MODULE.bazel": "d9351ba35217ad0de03816ef3ed63f89d411349353077348a45348b096615036", + "https://bcr.bazel.build/modules/rules_jvm_external/5.3/MODULE.bazel": "bf93870767689637164657731849fb887ad086739bd5d360d90007a581d5527d", + "https://bcr.bazel.build/modules/rules_jvm_external/6.1/MODULE.bazel": "75b5fec090dbd46cf9b7d8ea08cf84a0472d92ba3585b476f44c326eda8059c4", + "https://bcr.bazel.build/modules/rules_jvm_external/6.3/MODULE.bazel": "c998e060b85f71e00de5ec552019347c8bca255062c990ac02d051bb80a38df0", + "https://bcr.bazel.build/modules/rules_jvm_external/6.3/source.json": "6f5f5a5a4419ae4e37c35a5bb0a6ae657ed40b7abc5a5189111b47fcebe43197", + "https://bcr.bazel.build/modules/rules_kotlin/1.9.0/MODULE.bazel": "ef85697305025e5a61f395d4eaede272a5393cee479ace6686dba707de804d59", + "https://bcr.bazel.build/modules/rules_kotlin/1.9.6/MODULE.bazel": "d269a01a18ee74d0335450b10f62c9ed81f2321d7958a2934e44272fe82dcef3", + "https://bcr.bazel.build/modules/rules_kotlin/1.9.6/source.json": "2faa4794364282db7c06600b7e5e34867a564ae91bda7cae7c29c64e9466b7d5", + "https://bcr.bazel.build/modules/rules_license/0.0.3/MODULE.bazel": "627e9ab0247f7d1e05736b59dbb1b6871373de5ad31c3011880b4133cafd4bd0", + "https://bcr.bazel.build/modules/rules_license/0.0.7/MODULE.bazel": "088fbeb0b6a419005b89cf93fe62d9517c0a2b8bb56af3244af65ecfe37e7d5d", + "https://bcr.bazel.build/modules/rules_license/1.0.0/MODULE.bazel": "a7fda60eefdf3d8c827262ba499957e4df06f659330bbe6cdbdb975b768bb65c", + "https://bcr.bazel.build/modules/rules_license/1.0.0/source.json": "a52c89e54cc311196e478f8382df91c15f7a2bfdf4c6cd0e2675cc2ff0b56efb", + "https://bcr.bazel.build/modules/rules_pkg/0.7.0/MODULE.bazel": "df99f03fc7934a4737122518bb87e667e62d780b610910f0447665a7e2be62dc", + "https://bcr.bazel.build/modules/rules_pkg/1.0.1/MODULE.bazel": "5b1df97dbc29623bccdf2b0dcd0f5cb08e2f2c9050aab1092fd39a41e82686ff", + "https://bcr.bazel.build/modules/rules_pkg/1.0.1/source.json": "bd82e5d7b9ce2d31e380dd9f50c111d678c3bdaca190cb76b0e1c71b05e1ba8a", + "https://bcr.bazel.build/modules/rules_proto/4.0.0/MODULE.bazel": "a7a7b6ce9bee418c1a760b3d84f83a299ad6952f9903c67f19e4edd964894e06", + "https://bcr.bazel.build/modules/rules_proto/5.3.0-21.7/MODULE.bazel": "e8dff86b0971688790ae75528fe1813f71809b5afd57facb44dad9e8eca631b7", + "https://bcr.bazel.build/modules/rules_proto/6.0.0/MODULE.bazel": "b531d7f09f58dce456cd61b4579ce8c86b38544da75184eadaf0a7cb7966453f", + "https://bcr.bazel.build/modules/rules_proto/6.0.2/MODULE.bazel": "ce916b775a62b90b61888052a416ccdda405212b6aaeb39522f7dc53431a5e73", + "https://bcr.bazel.build/modules/rules_proto/7.0.2/MODULE.bazel": "bf81793bd6d2ad89a37a40693e56c61b0ee30f7a7fdbaf3eabbf5f39de47dea2", + "https://bcr.bazel.build/modules/rules_proto/7.0.2/source.json": "1e5e7260ae32ef4f2b52fd1d0de8d03b606a44c91b694d2f1afb1d3b28a48ce1", + "https://bcr.bazel.build/modules/rules_python/0.10.2/MODULE.bazel": "cc82bc96f2997baa545ab3ce73f196d040ffb8756fd2d66125a530031cd90e5f", + "https://bcr.bazel.build/modules/rules_python/0.23.1/MODULE.bazel": "49ffccf0511cb8414de28321f5fcf2a31312b47c40cc21577144b7447f2bf300", + "https://bcr.bazel.build/modules/rules_python/0.25.0/MODULE.bazel": "72f1506841c920a1afec76975b35312410eea3aa7b63267436bfb1dd91d2d382", + "https://bcr.bazel.build/modules/rules_python/0.28.0/MODULE.bazel": "cba2573d870babc976664a912539b320cbaa7114cd3e8f053c720171cde331ed", + "https://bcr.bazel.build/modules/rules_python/0.31.0/MODULE.bazel": "93a43dc47ee570e6ec9f5779b2e64c1476a6ce921c48cc9a1678a91dd5f8fd58", + "https://bcr.bazel.build/modules/rules_python/0.4.0/MODULE.bazel": "9208ee05fd48bf09ac60ed269791cf17fb343db56c8226a720fbb1cdf467166c", + "https://bcr.bazel.build/modules/rules_python/0.40.0/MODULE.bazel": "9d1a3cd88ed7d8e39583d9ffe56ae8a244f67783ae89b60caafc9f5cf318ada7", + "https://bcr.bazel.build/modules/rules_python/0.40.0/source.json": "939d4bd2e3110f27bfb360292986bb79fd8dcefb874358ccd6cdaa7bda029320", + "https://bcr.bazel.build/modules/rules_shell/0.2.0/MODULE.bazel": "fda8a652ab3c7d8fee214de05e7a9916d8b28082234e8d2c0094505c5268ed3c", + "https://bcr.bazel.build/modules/rules_shell/0.3.0/MODULE.bazel": "de4402cd12f4cc8fda2354fce179fdb068c0b9ca1ec2d2b17b3e21b24c1a937b", + "https://bcr.bazel.build/modules/rules_shell/0.3.0/source.json": "c55ed591aa5009401ddf80ded9762ac32c358d2517ee7820be981e2de9756cf3", + "https://bcr.bazel.build/modules/stardoc/0.5.1/MODULE.bazel": "1a05d92974d0c122f5ccf09291442580317cdd859f07a8655f1db9a60374f9f8", + "https://bcr.bazel.build/modules/stardoc/0.5.3/MODULE.bazel": "c7f6948dae6999bf0db32c1858ae345f112cacf98f174c7a8bb707e41b974f1c", + "https://bcr.bazel.build/modules/stardoc/0.5.6/MODULE.bazel": "c43dabc564990eeab55e25ed61c07a1aadafe9ece96a4efabb3f8bf9063b71ef", + "https://bcr.bazel.build/modules/stardoc/0.6.2/MODULE.bazel": "7060193196395f5dd668eda046ccbeacebfd98efc77fed418dbe2b82ffaa39fd", + "https://bcr.bazel.build/modules/stardoc/0.7.0/MODULE.bazel": "05e3d6d30c099b6770e97da986c53bd31844d7f13d41412480ea265ac9e8079c", + "https://bcr.bazel.build/modules/stardoc/0.7.1/MODULE.bazel": "3548faea4ee5dda5580f9af150e79d0f6aea934fc60c1cc50f4efdd9420759e7", + "https://bcr.bazel.build/modules/stardoc/0.7.1/source.json": "b6500ffcd7b48cd72c29bb67bcac781e12701cc0d6d55d266a652583cfcdab01", + "https://bcr.bazel.build/modules/upb/0.0.0-20220923-a547704/MODULE.bazel": "7298990c00040a0e2f121f6c32544bab27d4452f80d9ce51349b1a28f3005c43", + "https://bcr.bazel.build/modules/zlib/1.2.11/MODULE.bazel": "07b389abc85fdbca459b69e2ec656ae5622873af3f845e1c9d80fe179f3effa0", + "https://bcr.bazel.build/modules/zlib/1.2.12/MODULE.bazel": "3b1a8834ada2a883674be8cbd36ede1b6ec481477ada359cd2d3ddc562340b27", + "https://bcr.bazel.build/modules/zlib/1.3.1.bcr.5/MODULE.bazel": "eec517b5bbe5492629466e11dae908d043364302283de25581e3eb944326c4ca", + "https://bcr.bazel.build/modules/zlib/1.3.1.bcr.5/source.json": "22bc55c47af97246cfc093d0acf683a7869377de362b5d1c552c2c2e16b7a806", + "https://bcr.bazel.build/modules/zlib/1.3.1/MODULE.bazel": "751c9940dcfe869f5f7274e1295422a34623555916eb98c174c1e945594bf198" + }, + "selectedYankedVersions": {}, + "moduleExtensions": { + "@@rules_kotlin+//src/main/starlark/core/repositories:bzlmod_setup.bzl%rules_kotlin_extensions": { + "general": { + "bzlTransitiveDigest": "hUTp2w+RUVdL7ma5esCXZJAFnX7vLbVfLd7FwnQI6bU=", + "usagesDigest": "QI2z8ZUR+mqtbwsf2fLqYdJAkPOHdOV+tF2yVAUgRzw=", + "recordedFileInputs": {}, + "recordedDirentsInputs": {}, + "envVariables": {}, + "generatedRepoSpecs": { + "com_github_jetbrains_kotlin_git": { + "repoRuleId": "@@rules_kotlin+//src/main/starlark/core/repositories:compiler.bzl%kotlin_compiler_git_repository", + "attributes": { + "urls": [ + "https://github.com/JetBrains/kotlin/releases/download/v1.9.23/kotlin-compiler-1.9.23.zip" + ], + "sha256": "93137d3aab9afa9b27cb06a824c2324195c6b6f6179d8a8653f440f5bd58be88" + } + }, + "com_github_jetbrains_kotlin": { + "repoRuleId": "@@rules_kotlin+//src/main/starlark/core/repositories:compiler.bzl%kotlin_capabilities_repository", + "attributes": { + "git_repository_name": "com_github_jetbrains_kotlin_git", + "compiler_version": "1.9.23" + } + }, + "com_github_google_ksp": { + "repoRuleId": "@@rules_kotlin+//src/main/starlark/core/repositories:ksp.bzl%ksp_compiler_plugin_repository", + "attributes": { + "urls": [ + "https://github.com/google/ksp/releases/download/1.9.23-1.0.20/artifacts.zip" + ], + "sha256": "ee0618755913ef7fd6511288a232e8fad24838b9af6ea73972a76e81053c8c2d", + "strip_version": "1.9.23-1.0.20" + } + }, + "com_github_pinterest_ktlint": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_file", + "attributes": { + "sha256": "01b2e0ef893383a50dbeb13970fe7fa3be36ca3e83259e01649945b09d736985", + "urls": [ + "https://github.com/pinterest/ktlint/releases/download/1.3.0/ktlint" + ], + "executable": true + } + }, + "rules_android": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "sha256": "cd06d15dd8bb59926e4d65f9003bfc20f9da4b2519985c27e190cddc8b7a7806", + "strip_prefix": "rules_android-0.1.1", + "urls": [ + "https://github.com/bazelbuild/rules_android/archive/v0.1.1.zip" + ] + } + } + }, + "recordedRepoMappingEntries": [ + [ + "rules_kotlin+", + "bazel_tools", + "bazel_tools" + ] + ] + } + } + } +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/Makefile b/vendor/github.com/lestrrat-go/jwx/v3/Makefile new file mode 100644 index 00000000000..672c007b298 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/Makefile @@ -0,0 +1,98 @@ +.PHONY: generate realclean cover viewcover test lint check_diffs imports tidy jwx +generate: + @go generate + @$(MAKE) generate-jwa generate-jwe generate-jwk generate-jws generate-jwt + @./tools/cmd/gofmt.sh + +generate-%: + @go generate $(shell pwd -P)/$(patsubst generate-%,%,$@) + +realclean: + rm coverage.out + +test-cmd: + env TESTOPTS="$(TESTOPTS)" ./tools/test.sh + +test: + $(MAKE) test-stdlib TESTOPTS= + +test-stdlib: + $(MAKE) test-cmd TESTOPTS= + +test-goccy: + $(MAKE) test-cmd TESTOPTS="-tags jwx_goccy" + +test-es256k: + $(MAKE) test-cmd TESTOPTS="-tags jwx_es256k" + +test-secp256k1-pem: + $(MAKE) test-cmd TESTOPTS="-tags jwx_es256k,jwx_secp256k1_pem" + +test-asmbase64: + $(MAKE) test-cmd TESTOPTS="-tags jwx_asmbase64" + +test-alltags: + $(MAKE) test-cmd TESTOPTS="-tags jwx_asmbase64,jwx_goccy,jwx_es256k,jwx_secp256k1_pem" + +cover-cmd: + env MODE=cover ./tools/test.sh + +cover: + $(MAKE) cover-stdlib + +cover-stdlib: + $(MAKE) cover-cmd TESTOPTS= + +cover-goccy: + $(MAKE) cover-cmd TESTOPTS="-tags jwx_goccy" + +cover-es256k: + $(MAKE) cover-cmd TESTOPTS="-tags jwx_es256k" + +cover-secp256k1-pem: + $(MAKE) cover-cmd TESTOPTS="-tags jwx_es256k,jwx_secp256k1" + +cover-asmbase64: + $(MAKE) cover-cmd TESTOPTS="-tags jwx_asmbase64" + +cover-alltags: + $(MAKE) cover-cmd TESTOPTS="-tags jwx_asmbase64,jwx_goccy,jwx_es256k,jwx_secp256k1_pem" + +smoke-cmd: + env MODE=short ./tools/test.sh + +smoke: + $(MAKE) smoke-stdlib + +smoke-stdlib: + $(MAKE) smoke-cmd TESTOPTS= + +smoke-goccy: + $(MAKE) smoke-cmd TESTOPTS="-tags jwx_goccy" + +smoke-es256k: + $(MAKE) smoke-cmd TESTOPTS="-tags jwx_es256k" + +smoke-secp256k1-pem: + $(MAKE) smoke-cmd TESTOPTS="-tags jwx_es256k,jwx_secp256k1_pem" + +smoke-alltags: + $(MAKE) smoke-cmd TESTOPTS="-tags jwx_goccy,jwx_es256k,jwx_secp256k1_pem" + +viewcover: + go tool cover -html=coverage.out + +lint: + golangci-lint run ./... + +check_diffs: + ./scripts/check-diff.sh + +imports: + goimports -w ./ + +tidy: + ./scripts/tidy.sh + +jwx: + @./tools/cmd/install-jwx.sh diff --git a/vendor/github.com/lestrrat-go/jwx/v3/README.md b/vendor/github.com/lestrrat-go/jwx/v3/README.md new file mode 100644 index 00000000000..632033f3cb0 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/README.md @@ -0,0 +1,263 @@ +# github.com/lestrrat-go/jwx/v3 [![CI](https://github.com/lestrrat-go/jwx/actions/workflows/ci.yml/badge.svg)](https://github.com/lestrrat-go/jwx/actions/workflows/ci.yml) [![Go Reference](https://pkg.go.dev/badge/github.com/lestrrat-go/jwx/v3.svg)](https://pkg.go.dev/github.com/lestrrat-go/jwx/v3) [![codecov.io](https://codecov.io/github/lestrrat-go/jwx/coverage.svg?branch=v3)](https://codecov.io/github/lestrrat-go/jwx?branch=v3) + +Go module implementing various JWx (JWA/JWE/JWK/JWS/JWT, otherwise known as JOSE) technologies. + +If you are using this module in your product or your company, please add your product and/or company name in the [Wiki](https://github.com/lestrrat-go/jwx/wiki/Users)! It really helps keeping up our motivation. + +# Features + +* Complete coverage of JWA/JWE/JWK/JWS/JWT, not just JWT+minimum tool set. + * Supports JWS messages with multiple signatures, both compact and JSON serialization + * Supports JWS with detached payload + * Supports JWS with unencoded payload (RFC7797) + * Supports JWE messages with multiple recipients, both compact and JSON serialization + * Most operations work with either JWK or raw keys e.g. *rsa.PrivateKey, *ecdsa.PrivateKey, etc). +* Opinionated, but very uniform API. Everything is symmetric, and follows a standard convention + * jws.Parse/Verify/Sign + * jwe.Parse/Encrypt/Decrypt + * Arguments are organized as explicit required parameters and optional WithXXXX() style options. +* Extra utilities + * `jwk.Cache` to always keep a JWKS up-to-date + * [bazel](https://bazel.build)-ready + +Some more in-depth discussion on why you might want to use this library over others +can be found in the [Description section](#description) + +If you are using v0 or v1, you are strongly encouraged to migrate to using v3 +(the version that comes with the README you are reading). + +# SYNOPSIS + + +```go +package examples_test + +import ( + "bytes" + "fmt" + "net/http" + "time" + + "github.com/lestrrat-go/jwx/v3/jwa" + "github.com/lestrrat-go/jwx/v3/jwe" + "github.com/lestrrat-go/jwx/v3/jwk" + "github.com/lestrrat-go/jwx/v3/jws" + "github.com/lestrrat-go/jwx/v3/jwt" +) + +func Example() { + // Parse, serialize, slice and dice JWKs! + privkey, err := jwk.ParseKey(jsonRSAPrivateKey) + if err != nil { + fmt.Printf("failed to parse JWK: %s\n", err) + return + } + + pubkey, err := jwk.PublicKeyOf(privkey) + if err != nil { + fmt.Printf("failed to get public key: %s\n", err) + return + } + + // Work with JWTs! + { + // Build a JWT! + tok, err := jwt.NewBuilder(). + Issuer(`github.com/lestrrat-go/jwx`). + IssuedAt(time.Now()). + Build() + if err != nil { + fmt.Printf("failed to build token: %s\n", err) + return + } + + // Sign a JWT! + signed, err := jwt.Sign(tok, jwt.WithKey(jwa.RS256(), privkey)) + if err != nil { + fmt.Printf("failed to sign token: %s\n", err) + return + } + + // Verify a JWT! + { + verifiedToken, err := jwt.Parse(signed, jwt.WithKey(jwa.RS256(), pubkey)) + if err != nil { + fmt.Printf("failed to verify JWS: %s\n", err) + return + } + _ = verifiedToken + } + + // Work with *http.Request! + { + req, err := http.NewRequest(http.MethodGet, `https://github.com/lestrrat-go/jwx`, nil) + req.Header.Set(`Authorization`, fmt.Sprintf(`Bearer %s`, signed)) + + verifiedToken, err := jwt.ParseRequest(req, jwt.WithKey(jwa.RS256(), pubkey)) + if err != nil { + fmt.Printf("failed to verify token from HTTP request: %s\n", err) + return + } + _ = verifiedToken + } + } + + // Encrypt and Decrypt arbitrary payload with JWE! + { + encrypted, err := jwe.Encrypt(payloadLoremIpsum, jwe.WithKey(jwa.RSA_OAEP(), jwkRSAPublicKey)) + if err != nil { + fmt.Printf("failed to encrypt payload: %s\n", err) + return + } + + decrypted, err := jwe.Decrypt(encrypted, jwe.WithKey(jwa.RSA_OAEP(), jwkRSAPrivateKey)) + if err != nil { + fmt.Printf("failed to decrypt payload: %s\n", err) + return + } + + if !bytes.Equal(decrypted, payloadLoremIpsum) { + fmt.Printf("verified payload did not match\n") + return + } + } + + // Sign and Verify arbitrary payload with JWS! + { + signed, err := jws.Sign(payloadLoremIpsum, jws.WithKey(jwa.RS256(), jwkRSAPrivateKey)) + if err != nil { + fmt.Printf("failed to sign payload: %s\n", err) + return + } + + verified, err := jws.Verify(signed, jws.WithKey(jwa.RS256(), jwkRSAPublicKey)) + if err != nil { + fmt.Printf("failed to verify payload: %s\n", err) + return + } + + if !bytes.Equal(verified, payloadLoremIpsum) { + fmt.Printf("verified payload did not match\n") + return + } + } + // OUTPUT: +} +``` +source: [examples/jwx_readme_example_test.go](https://github.com/lestrrat-go/jwx/blob/v3/examples/jwx_readme_example_test.go) + + +# How-to Documentation + +* [API documentation](https://pkg.go.dev/github.com/lestrrat-go/jwx/v3) +* [How-to style documentation](./docs) +* [Runnable Examples](./examples) + +# Description + +This Go module implements JWA, JWE, JWK, JWS, and JWT. Please see the following table for the list of +available packages: + +| Package name | Notes | +|-----------------------------------------------------------|-------------------------------------------------| +| [jwt](https://github.com/lestrrat-go/jwx/tree/v3/jwt) | [RFC 7519](https://tools.ietf.org/html/rfc7519) | +| [jwk](https://github.com/lestrrat-go/jwx/tree/v3/jwk) | [RFC 7517](https://tools.ietf.org/html/rfc7517) + [RFC 7638](https://tools.ietf.org/html/rfc7638) | +| [jwa](https://github.com/lestrrat-go/jwx/tree/v3/jwa) | [RFC 7518](https://tools.ietf.org/html/rfc7518) | +| [jws](https://github.com/lestrrat-go/jwx/tree/v3/jws) | [RFC 7515](https://tools.ietf.org/html/rfc7515) + [RFC 7797](https://tools.ietf.org/html/rfc7797) | +| [jwe](https://github.com/lestrrat-go/jwx/tree/v3/jwe) | [RFC 7516](https://tools.ietf.org/html/rfc7516) | +## History + +My goal was to write a server that heavily uses JWK and JWT. At first glance +the libraries that already exist seemed sufficient, but soon I realized that + +1. To completely implement the protocols, I needed the entire JWT, JWK, JWS, JWE (and JWA, by necessity). +2. Most of the libraries that existed only deal with a subset of the various JWx specifications that were necessary to implement their specific needs + +For example, a certain library looks like it had most of JWS, JWE, JWK covered, but then it lacked the ability to include private claims in its JWT responses. Another library had support of all the private claims, but completely lacked in its flexibility to generate various different response formats. + +Because I was writing the server side (and the client side for testing), I needed the *entire* JOSE toolset to properly implement my server, **and** they needed to be *flexible* enough to fulfill the entire spec that I was writing. + +So here's `github.com/lestrrat-go/jwx/v3`. This library is extensible, customizable, and hopefully well organized to the point that it is easy for you to slice and dice it. + +## Why would I use this library? + +There are several other major Go modules that handle JWT and related data formats, +so why should you use this library? + +From a purely functional perspective, the only major difference is this: +Whereas most other projects only deal with what they seem necessary to handle +JWTs, this module handles the **_entire_** spectrum of JWS, JWE, JWK, and JWT. + +That is, if you need to not only parse JWTs, but also to control JWKs, or +if you need to handle payloads that are NOT JWTs, you should probably consider +using this module. You should also note that JWT is built _on top_ of those +other technologies. You simply cannot have a complete JWT package without +implementing the entirety of JWS/JWE/JWK, which this library does. + +Next, from an implementation perspective, this module differs significantly +from others in that it tries very hard to expose only the APIs, and not the +internal data. For example, individual JWT claims are not accessible through +struct field lookups. You need to use one of the getter methods. + +This is because this library takes the stance that the end user is fully capable +and even willing to shoot themselves on the foot when presented with a lax +API. By making sure that users do not have access to open structs, we can protect +users from doing silly things like creating _incomplete_ structs, or access the +structs concurrently without any protection. This structure also allows +us to put extra smarts in the structs, such as doing the right thing when +you want to parse / write custom fields (this module does not require the user +to specify alternate structs to parse objects with custom fields) + +In the end I think it comes down to your usage pattern, and priorities. +Some general guidelines that come to mind are: + +* If you want a single library to handle everything JWx, such as using JWE, JWK, JWS, handling [auto-refreshing JWKs](https://github.com/lestrrat-go/jwx/blob/v3/docs/04-jwk.md#auto-refreshing-remote-keys), use this module. +* If you want to honor all possible custom fields transparently, use this module. +* If you want a standardized clean API, use this module. + +Otherwise, feel free to choose something else. + +# Contributions + +## Issues + +For bug reports and feature requests, please try to follow the issue templates as much as possible. +For either bug reports or feature requests, failing tests are even better. + +## Pull Requests + +Please make sure to include tests that exercise the changes you made. + +If you are editing auto-generated files (those files with the `_gen.go` suffix, please make sure that you do the following: + +1. Edit the generator, not the generated files (e.g. internal/cmd/genreadfile/main.go) +2. Run `make generate` (or `go generate`) to generate the new code +3. Commit _both_ the generator _and_ the generated files + +## Discussions / Usage + +Please try [discussions](https://github.com/lestrrat-go/jwx/tree/v3/discussions) first. + +# Related Modules + +* [github.com/lestrrat-go/echo-middleware-jwx](https://github.com/lestrrat-go/echo-middleware-jwx) - Sample Echo middleware +* [github.com/jwx-go/crypto-signer/gcp](https://github.com/jwx-go/crypto-signer/tree/main/gcp) - GCP KMS wrapper that implements [`crypto.Signer`](https://pkg.go.dev/crypto#Signer) +* [github.com/jwx-go/crypto-signer/aws](https://github.com/jwx-go/crypto-signer/tree/main/aws) - AWS KMS wrapper that implements [`crypto.Signer`](https://pkg.go.dev/crypto#Signer) + +# Credits + +* Initial work on this library was generously sponsored by HDE Inc (https://www.hde.co.jp) +* Lots of code, especially JWE was initially taken from go-jose library (https://github.com/square/go-jose) +* Lots of individual contributors have helped this project over the years. Thank each and everyone of you very much. + +# Quid pro quo + +If you use this software to build products in a for-profit organization, we ask you to _consider_ +contributing back to FOSS in the following manner: + +* For every 100 employees (direct hires) of your organization, please consider contributing minimum of $1 every year to either this project, **or** another FOSS projects that this project uses. For example, for 100 employees, we ask you contribute $100 yearly; for 10,000 employees, we ask you contribute $10,000 yearly. +* If possible, please make this information public. You do not need to disclose the amount you are contributing, but please make the information that you are contributing to particular FOSS projects public. For this project, please consider writing your name on the [Wiki](https://github.com/lestrrat-go/jwx/wiki/Users) + +This is _NOT_ a licensing term: you are still free to use this software according to the license it +comes with. This clause is only a plea for people to acknowledge the work from FOSS developers whose +work you rely on each and everyday. diff --git a/vendor/github.com/lestrrat-go/jwx/v3/SECURITY.md b/vendor/github.com/lestrrat-go/jwx/v3/SECURITY.md new file mode 100644 index 00000000000..601dced5cd4 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/SECURITY.md @@ -0,0 +1,18 @@ +# Security Policy + +## Supported Versions + +Most recent two major versions will receive security updates + +| Version | Supported | +| -------- | ------------------ | +| v3.x.x | :white_check_mark: | +| v2.x.x | :white_check_mark: | +| < v2.0.0 | :x: | + +## Reporting a Vulnerability + +If you think you found a vulnerability, please report it via [GitHub Security Advisory](https://github.com/lestrrat-go/jwx/security/advisories/new). +Please include explicit steps to reproduce the security issue. + +We will do our best to respond in a timely manner, but please also be aware that this project is maintained by a very limited number of people. Please help us with test code and such. diff --git a/vendor/github.com/lestrrat-go/jwx/v3/WORKSPACE b/vendor/github.com/lestrrat-go/jwx/v3/WORKSPACE new file mode 100644 index 00000000000..c8578d8b0a4 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/WORKSPACE @@ -0,0 +1,2 @@ +# Empty WORKSPACE file for bzlmod compatibility +# All dependencies are now managed in MODULE.bazel \ No newline at end of file diff --git a/vendor/github.com/lestrrat-go/jwx/v3/cert/BUILD.bazel b/vendor/github.com/lestrrat-go/jwx/v3/cert/BUILD.bazel new file mode 100644 index 00000000000..f308530bcff --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/cert/BUILD.bazel @@ -0,0 +1,34 @@ +load("@rules_go//go:def.bzl", "go_library", "go_test") + +go_library( + name = "cert", + srcs = [ + "cert.go", + "chain.go", + ], + importpath = "github.com/lestrrat-go/jwx/v3/cert", + visibility = ["//visibility:public"], + deps = [ + "//internal/base64", + "//internal/tokens", + ], +) + +go_test( + name = "cert_test", + srcs = [ + "cert_test.go", + "chain_test.go", + ], + deps = [ + ":cert", + "//internal/jwxtest", + "@com_github_stretchr_testify//require", + ], +) + +alias( + name = "go_default_library", + actual = ":cert", + visibility = ["//visibility:public"], +) diff --git a/vendor/github.com/lestrrat-go/jwx/v3/cert/cert.go b/vendor/github.com/lestrrat-go/jwx/v3/cert/cert.go new file mode 100644 index 00000000000..efefbcb417c --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/cert/cert.go @@ -0,0 +1,48 @@ +package cert + +import ( + "crypto/x509" + stdlibb64 "encoding/base64" + "fmt" + "io" + + "github.com/lestrrat-go/jwx/v3/internal/base64" +) + +// Create is a wrapper around x509.CreateCertificate, but it additionally +// encodes it in base64 so that it can be easily added to `x5c` fields +func Create(rand io.Reader, template, parent *x509.Certificate, pub, priv any) ([]byte, error) { + der, err := x509.CreateCertificate(rand, template, parent, pub, priv) + if err != nil { + return nil, fmt.Errorf(`failed to create x509 certificate: %w`, err) + } + return EncodeBase64(der) +} + +// EncodeBase64 is a utility function to encode ASN.1 DER certificates +// using base64 encoding. This operation is normally done by `pem.Encode` +// but since PEM would include the markers (`-----BEGIN`, and the like) +// while `x5c` fields do not need this, this function can be used to +// shave off a few lines +func EncodeBase64(der []byte) ([]byte, error) { + enc := stdlibb64.StdEncoding + dst := make([]byte, enc.EncodedLen(len(der))) + enc.Encode(dst, der) + return dst, nil +} + +// Parse is a utility function to decode a base64 encoded +// ASN.1 DER format certificate, and to parse the byte sequence. +// The certificate must be in PKIX format, and it must not contain PEM markers +func Parse(src []byte) (*x509.Certificate, error) { + dst, err := base64.Decode(src) + if err != nil { + return nil, fmt.Errorf(`failed to base64 decode the certificate: %w`, err) + } + + cert, err := x509.ParseCertificate(dst) + if err != nil { + return nil, fmt.Errorf(`failed to parse x509 certificate: %w`, err) + } + return cert, nil +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/cert/chain.go b/vendor/github.com/lestrrat-go/jwx/v3/cert/chain.go new file mode 100644 index 00000000000..112274669af --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/cert/chain.go @@ -0,0 +1,80 @@ +package cert + +import ( + "bytes" + "encoding/json" + "fmt" + + "github.com/lestrrat-go/jwx/v3/internal/tokens" +) + +// Chain represents a certificate chain as used in the `x5c` field of +// various objects within JOSE. +// +// It stores the certificates as a list of base64 encoded []byte +// sequence. By definition these values must PKIX encoded. +type Chain struct { + certificates [][]byte +} + +func (cc Chain) MarshalJSON() ([]byte, error) { + var buf bytes.Buffer + buf.WriteByte(tokens.OpenSquareBracket) + for i, cert := range cc.certificates { + if i > 0 { + buf.WriteByte(tokens.Comma) + } + buf.WriteByte('"') + buf.Write(cert) + buf.WriteByte('"') + } + buf.WriteByte(tokens.CloseSquareBracket) + return buf.Bytes(), nil +} + +func (cc *Chain) UnmarshalJSON(data []byte) error { + var tmp []string + if err := json.Unmarshal(data, &tmp); err != nil { + return fmt.Errorf(`failed to unmarshal certificate chain: %w`, err) + } + + certs := make([][]byte, len(tmp)) + for i, cert := range tmp { + certs[i] = []byte(cert) + } + cc.certificates = certs + return nil +} + +// Get returns the n-th ASN.1 DER + base64 encoded certificate +// stored. `false` will be returned in the second argument if +// the corresponding index is out of range. +func (cc *Chain) Get(index int) ([]byte, bool) { + if index < 0 || index >= len(cc.certificates) { + return nil, false + } + + return cc.certificates[index], true +} + +// Len returns the number of certificates stored in this Chain +func (cc *Chain) Len() int { + return len(cc.certificates) +} + +var pemStart = []byte("----- BEGIN CERTIFICATE -----") +var pemEnd = []byte("----- END CERTIFICATE -----") + +func (cc *Chain) AddString(der string) error { + return cc.Add([]byte(der)) +} + +func (cc *Chain) Add(der []byte) error { + // We're going to be nice and remove marker lines if they + // give it to us + der = bytes.TrimPrefix(der, pemStart) + der = bytes.TrimSuffix(der, pemEnd) + der = bytes.TrimSpace(der) + cc.certificates = append(cc.certificates, der) + return nil +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/codecov.yml b/vendor/github.com/lestrrat-go/jwx/v3/codecov.yml new file mode 100644 index 00000000000..130effd7a60 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/codecov.yml @@ -0,0 +1,2 @@ +codecov: + allow_coverage_offsets: true diff --git a/vendor/github.com/lestrrat-go/jwx/v3/format.go b/vendor/github.com/lestrrat-go/jwx/v3/format.go new file mode 100644 index 00000000000..6cb6efe7eb7 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/format.go @@ -0,0 +1,104 @@ +package jwx + +import ( + "bytes" + "encoding/json" + + "github.com/lestrrat-go/jwx/v3/internal/tokens" +) + +type FormatKind int + +// These constants describe the result from guessing the format +// of the incoming buffer. +const ( + // InvalidFormat is returned when the format of the incoming buffer + // has been deemed conclusively invalid + InvalidFormat FormatKind = iota + // UnknownFormat is returned when GuessFormat was not able to conclusively + // determine the format of the + UnknownFormat + JWE + JWS + JWK + JWKS + JWT +) + +type formatHint struct { + Payload json.RawMessage `json:"payload"` // Only in JWS + Signatures json.RawMessage `json:"signatures"` // Only in JWS + Ciphertext json.RawMessage `json:"ciphertext"` // Only in JWE + KeyType json.RawMessage `json:"kty"` // Only in JWK + Keys json.RawMessage `json:"keys"` // Only in JWKS + Audience json.RawMessage `json:"aud"` // Only in JWT +} + +// GuessFormat is used to guess the format the given payload is in +// using heuristics. See the type FormatKind for a full list of +// possible types. +// +// This may be useful in determining your next action when you may +// encounter a payload that could either be a JWE, JWS, or a plain JWT. +// +// Because JWTs are almost always JWS signed, you may be thrown off +// if you pass what you think is a JWT payload to this function. +// If the function is in the "Compact" format, it means it's a JWS +// signed message, and its payload is the JWT. Therefore this function +// will return JWS, not JWT. +// +// This function requires an extra parsing of the payload, and therefore +// may be inefficient if you call it every time before parsing. +func GuessFormat(payload []byte) FormatKind { + // The check against kty, keys, and aud are something this library + // made up. for the distinctions between JWE and JWS, we used + // https://datatracker.ietf.org/doc/html/rfc7516#section-9. + // + // The above RFC described several ways to distinguish between + // a JWE and JWS JSON, but we're only using one of them + + payload = bytes.TrimSpace(payload) + if len(payload) <= 0 { + return UnknownFormat + } + + if payload[0] != tokens.OpenCurlyBracket { + // Compact format. It's probably a JWS or JWE + sep := []byte{tokens.Period} // I want to const this :/ + + // Note: this counts the number of occurrences of the + // separator, but the RFC talks about the number of segments. + // number of tokens.Period == segments - 1, so that's why we have 2 and 4 here + switch count := bytes.Count(payload, sep); count { + case 2: + return JWS + case 4: + return JWE + default: + return InvalidFormat + } + } + + // If we got here, we probably have JSON. + var h formatHint + if err := json.Unmarshal(payload, &h); err != nil { + return UnknownFormat + } + + if h.Audience != nil { + return JWT + } + if h.KeyType != nil { + return JWK + } + if h.Keys != nil { + return JWKS + } + if h.Ciphertext != nil { + return JWE + } + if h.Signatures != nil && h.Payload != nil { + return JWS + } + return UnknownFormat +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/formatkind_string_gen.go b/vendor/github.com/lestrrat-go/jwx/v3/formatkind_string_gen.go new file mode 100644 index 00000000000..38abd1bc475 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/formatkind_string_gen.go @@ -0,0 +1,29 @@ +// Code generated by "stringer -type=FormatKind"; DO NOT EDIT. + +package jwx + +import "strconv" + +func _() { + // An "invalid array index" compiler error signifies that the constant values have changed. + // Re-run the stringer command to generate them again. + var x [1]struct{} + _ = x[InvalidFormat-0] + _ = x[UnknownFormat-1] + _ = x[JWE-2] + _ = x[JWS-3] + _ = x[JWK-4] + _ = x[JWKS-5] + _ = x[JWT-6] +} + +const _FormatKind_name = "InvalidFormatUnknownFormatJWEJWSJWKJWKSJWT" + +var _FormatKind_index = [...]uint8{0, 13, 26, 29, 32, 35, 39, 42} + +func (i FormatKind) String() string { + if i < 0 || i >= FormatKind(len(_FormatKind_index)-1) { + return "FormatKind(" + strconv.FormatInt(int64(i), 10) + ")" + } + return _FormatKind_name[_FormatKind_index[i]:_FormatKind_index[i+1]] +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/internal/base64/BUILD.bazel b/vendor/github.com/lestrrat-go/jwx/v3/internal/base64/BUILD.bazel new file mode 100644 index 00000000000..57da5179f3a --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/internal/base64/BUILD.bazel @@ -0,0 +1,21 @@ +load("@rules_go//go:def.bzl", "go_library", "go_test") + +go_library( + name = "base64", + srcs = ["base64.go"], + importpath = "github.com/lestrrat-go/jwx/v3/internal/base64", + visibility = ["//:__subpackages__"], +) + +go_test( + name = "base64_test", + srcs = ["base64_test.go"], + embed = [":base64"], + deps = ["@com_github_stretchr_testify//require"], +) + +alias( + name = "go_default_library", + actual = ":base64", + visibility = ["//:__subpackages__"], +) diff --git a/vendor/github.com/lestrrat-go/jwx/v3/internal/base64/asmbase64.go b/vendor/github.com/lestrrat-go/jwx/v3/internal/base64/asmbase64.go new file mode 100644 index 00000000000..6e83ecc4a53 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/internal/base64/asmbase64.go @@ -0,0 +1,51 @@ +//go:build jwx_asmbase64 + +package base64 + +import ( + "fmt" + "slices" + + asmbase64 "github.com/segmentio/asm/base64" +) + +func init() { + SetEncoder(asmEncoder{asmbase64.RawURLEncoding}) + SetDecoder(asmDecoder{}) +} + +type asmEncoder struct { + *asmbase64.Encoding +} + +func (e asmEncoder) AppendEncode(dst, src []byte) []byte { + n := e.Encoding.EncodedLen(len(src)) + dst = slices.Grow(dst, n) + e.Encoding.Encode(dst[len(dst):][:n], src) + return dst[:len(dst)+n] +} + +type asmDecoder struct{} + +func (d asmDecoder) Decode(src []byte) ([]byte, error) { + var enc *asmbase64.Encoding + switch Guess(src) { + case Std: + enc = asmbase64.StdEncoding + case RawStd: + enc = asmbase64.RawStdEncoding + case URL: + enc = asmbase64.URLEncoding + case RawURL: + enc = asmbase64.RawURLEncoding + default: + return nil, fmt.Errorf(`invalid encoding`) + } + + dst := make([]byte, enc.DecodedLen(len(src))) + n, err := enc.Decode(dst, src) + if err != nil { + return nil, fmt.Errorf(`failed to decode source: %w`, err) + } + return dst[:n], nil +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/internal/base64/base64.go b/vendor/github.com/lestrrat-go/jwx/v3/internal/base64/base64.go new file mode 100644 index 00000000000..5ed8e35006a --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/internal/base64/base64.go @@ -0,0 +1,139 @@ +package base64 + +import ( + "bytes" + "encoding/base64" + "encoding/binary" + "fmt" + "sync" +) + +type Decoder interface { + Decode([]byte) ([]byte, error) +} + +type Encoder interface { + Encode([]byte, []byte) + EncodedLen(int) int + EncodeToString([]byte) string + AppendEncode([]byte, []byte) []byte +} + +var muEncoder sync.RWMutex +var encoder Encoder = base64.RawURLEncoding +var muDecoder sync.RWMutex +var decoder Decoder = defaultDecoder{} + +func SetEncoder(enc Encoder) { + muEncoder.Lock() + defer muEncoder.Unlock() + encoder = enc +} + +func getEncoder() Encoder { + muEncoder.RLock() + defer muEncoder.RUnlock() + return encoder +} + +func DefaultEncoder() Encoder { + return getEncoder() +} + +func SetDecoder(dec Decoder) { + muDecoder.Lock() + defer muDecoder.Unlock() + decoder = dec +} + +func getDecoder() Decoder { + muDecoder.RLock() + defer muDecoder.RUnlock() + return decoder +} + +func Encode(src []byte) []byte { + encoder := getEncoder() + dst := make([]byte, encoder.EncodedLen(len(src))) + encoder.Encode(dst, src) + return dst +} + +func EncodeToString(src []byte) string { + return getEncoder().EncodeToString(src) +} + +func EncodeUint64ToString(v uint64) string { + data := make([]byte, 8) + binary.BigEndian.PutUint64(data, v) + + i := 0 + for ; i < len(data); i++ { + if data[i] != 0x0 { + break + } + } + + return EncodeToString(data[i:]) +} + +const ( + InvalidEncoding = iota + Std + URL + RawStd + RawURL +) + +func Guess(src []byte) int { + var isRaw = !bytes.HasSuffix(src, []byte{'='}) + var isURL = !bytes.ContainsAny(src, "+/") + switch { + case isRaw && isURL: + return RawURL + case isURL: + return URL + case isRaw: + return RawStd + default: + return Std + } +} + +// defaultDecoder is a Decoder that detects the encoding of the source and +// decodes it accordingly. This shouldn't really be required per the spec, but +// it exist because we have seen in the wild JWTs that are encoded using +// various versions of the base64 encoding. +type defaultDecoder struct{} + +func (defaultDecoder) Decode(src []byte) ([]byte, error) { + var enc *base64.Encoding + + switch Guess(src) { + case RawURL: + enc = base64.RawURLEncoding + case URL: + enc = base64.URLEncoding + case RawStd: + enc = base64.RawStdEncoding + case Std: + enc = base64.StdEncoding + default: + return nil, fmt.Errorf(`invalid encoding`) + } + + dst := make([]byte, enc.DecodedLen(len(src))) + n, err := enc.Decode(dst, src) + if err != nil { + return nil, fmt.Errorf(`failed to decode source: %w`, err) + } + return dst[:n], nil +} + +func Decode(src []byte) ([]byte, error) { + return getDecoder().Decode(src) +} + +func DecodeString(src string) ([]byte, error) { + return getDecoder().Decode([]byte(src)) +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/internal/ecutil/BUILD.bazel b/vendor/github.com/lestrrat-go/jwx/v3/internal/ecutil/BUILD.bazel new file mode 100644 index 00000000000..3ccdcf372a7 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/internal/ecutil/BUILD.bazel @@ -0,0 +1,14 @@ +load("@rules_go//go:def.bzl", "go_library") + +go_library( + name = "ecutil", + srcs = ["ecutil.go"], + importpath = "github.com/lestrrat-go/jwx/v3/internal/ecutil", + visibility = ["//:__subpackages__"], +) + +alias( + name = "go_default_library", + actual = ":ecutil", + visibility = ["//:__subpackages__"], +) diff --git a/vendor/github.com/lestrrat-go/jwx/v3/internal/ecutil/ecutil.go b/vendor/github.com/lestrrat-go/jwx/v3/internal/ecutil/ecutil.go new file mode 100644 index 00000000000..cf0bd4ac484 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/internal/ecutil/ecutil.go @@ -0,0 +1,76 @@ +// Package ecutil defines tools that help with elliptic curve related +// computation +package ecutil + +import ( + "crypto/elliptic" + "math/big" + "sync" +) + +const ( + // size of buffer that needs to be allocated for EC521 curve + ec521BufferSize = 66 // (521 / 8) + 1 +) + +var ecpointBufferPool = sync.Pool{ + New: func() any { + // In most cases the curve bit size will be less than this length + // so allocate the maximum, and keep reusing + buf := make([]byte, 0, ec521BufferSize) + return &buf + }, +} + +func getCrvFixedBuffer(size int) []byte { + //nolint:forcetypeassert + buf := *(ecpointBufferPool.Get().(*[]byte)) + if size > ec521BufferSize && cap(buf) < size { + buf = append(buf, make([]byte, size-cap(buf))...) + } + return buf[:size] +} + +// ReleaseECPointBuffer releases the []byte buffer allocated. +func ReleaseECPointBuffer(buf []byte) { + buf = buf[:cap(buf)] + buf[0] = 0x0 + for i := 1; i < len(buf); i *= 2 { + copy(buf[i:], buf[:i]) + } + buf = buf[:0] + ecpointBufferPool.Put(&buf) +} + +func CalculateKeySize(crv elliptic.Curve) int { + // We need to create a buffer that fits the entire curve. + // If the curve size is 66, that fits in 9 bytes. If the curve + // size is 64, it fits in 8 bytes. + bits := crv.Params().BitSize + + // For most common cases we know before hand what the byte length + // is going to be. optimize + var inBytes int + switch bits { + case 224, 256, 384: // TODO: use constant? + inBytes = bits / 8 + case 521: + inBytes = ec521BufferSize + default: + inBytes = bits / 8 + if (bits % 8) != 0 { + inBytes++ + } + } + + return inBytes +} + +// AllocECPointBuffer allocates a buffer for the given point in the given +// curve. This buffer should be released using the ReleaseECPointBuffer +// function. +func AllocECPointBuffer(v *big.Int, crv elliptic.Curve) []byte { + buf := getCrvFixedBuffer(CalculateKeySize(crv)) + v.FillBytes(buf) + return buf +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/internal/json/BUILD.bazel b/vendor/github.com/lestrrat-go/jwx/v3/internal/json/BUILD.bazel new file mode 100644 index 00000000000..4e2dbe12b73 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/internal/json/BUILD.bazel @@ -0,0 +1,19 @@ +load("@rules_go//go:def.bzl", "go_library") + +go_library( + name = "json", + srcs = [ + "json.go", + "registry.go", + "stdlib.go", + ], + importpath = "github.com/lestrrat-go/jwx/v3/internal/json", + visibility = ["//:__subpackages__"], + deps = ["//internal/base64"], +) + +alias( + name = "go_default_library", + actual = ":json", + visibility = ["//:__subpackages__"], +) diff --git a/vendor/github.com/lestrrat-go/jwx/v3/internal/json/goccy.go b/vendor/github.com/lestrrat-go/jwx/v3/internal/json/goccy.go new file mode 100644 index 00000000000..e70a3c1edc2 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/internal/json/goccy.go @@ -0,0 +1,49 @@ +//go:build jwx_goccy +// +build jwx_goccy + +package json + +import ( + "io" + + "github.com/goccy/go-json" +) + +type Decoder = json.Decoder +type Delim = json.Delim +type Encoder = json.Encoder +type Marshaler = json.Marshaler +type Number = json.Number +type RawMessage = json.RawMessage +type Unmarshaler = json.Unmarshaler + +func Engine() string { + return "github.com/goccy/go-json" +} + +// NewDecoder respects the values specified in DecoderSettings, +// and creates a Decoder that has certain features turned on/off +func NewDecoder(r io.Reader) *json.Decoder { + dec := json.NewDecoder(r) + + if UseNumber() { + dec.UseNumber() + } + + return dec +} + +// NewEncoder is just a proxy for "encoding/json".NewEncoder +func NewEncoder(w io.Writer) *json.Encoder { + return json.NewEncoder(w) +} + +// Marshal is just a proxy for "encoding/json".Marshal +func Marshal(v any) ([]byte, error) { + return json.Marshal(v) +} + +// MarshalIndent is just a proxy for "encoding/json".MarshalIndent +func MarshalIndent(v any, prefix, indent string) ([]byte, error) { + return json.MarshalIndent(v, prefix, indent) +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/internal/json/json.go b/vendor/github.com/lestrrat-go/jwx/v3/internal/json/json.go new file mode 100644 index 00000000000..c1917ef27ab --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/internal/json/json.go @@ -0,0 +1,127 @@ +package json + +import ( + "bytes" + "fmt" + "os" + "sync/atomic" + + "github.com/lestrrat-go/jwx/v3/internal/base64" +) + +var useNumber uint32 // TODO: at some point, change to atomic.Bool + +func UseNumber() bool { + return atomic.LoadUint32(&useNumber) == 1 +} + +// Sets the global configuration for json decoding +func DecoderSettings(inUseNumber bool) { + var val uint32 + if inUseNumber { + val = 1 + } + atomic.StoreUint32(&useNumber, val) +} + +// Unmarshal respects the values specified in DecoderSettings, +// and uses a Decoder that has certain features turned on/off +func Unmarshal(b []byte, v any) error { + dec := NewDecoder(bytes.NewReader(b)) + return dec.Decode(v) +} + +func AssignNextBytesToken(dst *[]byte, dec *Decoder) error { + var val string + if err := dec.Decode(&val); err != nil { + return fmt.Errorf(`error reading next value: %w`, err) + } + + buf, err := base64.DecodeString(val) + if err != nil { + return fmt.Errorf(`expected base64 encoded []byte (%T)`, val) + } + *dst = buf + return nil +} + +func ReadNextStringToken(dec *Decoder) (string, error) { + var val string + if err := dec.Decode(&val); err != nil { + return "", fmt.Errorf(`error reading next value: %w`, err) + } + return val, nil +} + +func AssignNextStringToken(dst **string, dec *Decoder) error { + val, err := ReadNextStringToken(dec) + if err != nil { + return err + } + *dst = &val + return nil +} + +// FlattenAudience is a flag to specify if we should flatten the "aud" +// entry to a string when there's only one entry. +// In jwx < 1.1.8 we just dumped everything as an array of strings, +// but apparently AWS Cognito doesn't handle this well. +// +// So now we have the ability to dump "aud" as a string if there's +// only one entry, but we need to retain the old behavior so that +// we don't accidentally break somebody else's code. (e.g. messing +// up how signatures are calculated) +var FlattenAudience uint32 + +func MarshalAudience(aud []string, flatten bool) ([]byte, error) { + var val any + if len(aud) == 1 && flatten { + val = aud[0] + } else { + val = aud + } + return Marshal(val) +} + +func EncodeAudience(enc *Encoder, aud []string, flatten bool) error { + var val any + if len(aud) == 1 && flatten { + val = aud[0] + } else { + val = aud + } + return enc.Encode(val) +} + +// DecodeCtx is an interface for objects that needs that extra something +// when decoding JSON into an object. +type DecodeCtx interface { + Registry() *Registry +} + +// DecodeCtxContainer is used to differentiate objects that can carry extra +// decoding hints and those who can't. +type DecodeCtxContainer interface { + DecodeCtx() DecodeCtx + SetDecodeCtx(DecodeCtx) +} + +// stock decodeCtx. should cover 80% of the cases +type decodeCtx struct { + registry *Registry +} + +func NewDecodeCtx(r *Registry) DecodeCtx { + return &decodeCtx{registry: r} +} + +func (dc *decodeCtx) Registry() *Registry { + return dc.registry +} + +func Dump(v any) { + enc := NewEncoder(os.Stdout) + enc.SetIndent("", " ") + //nolint:errchkjson + _ = enc.Encode(v) +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/internal/json/registry.go b/vendor/github.com/lestrrat-go/jwx/v3/internal/json/registry.go new file mode 100644 index 00000000000..04a6a4c4a50 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/internal/json/registry.go @@ -0,0 +1,90 @@ +package json + +import ( + "fmt" + "reflect" + "sync" +) + +// CustomDecoder is the interface we expect from RegisterCustomField in jws, jwe, jwk, and jwt packages. +type CustomDecoder interface { + // Decode takes a JSON encoded byte slice and returns the desired + // decoded value,which will be used as the value for that field + // registered through RegisterCustomField + Decode([]byte) (any, error) +} + +// CustomDecodeFunc is a stateless, function-based implementation of CustomDecoder +type CustomDecodeFunc func([]byte) (any, error) + +func (fn CustomDecodeFunc) Decode(data []byte) (any, error) { + return fn(data) +} + +type objectTypeDecoder struct { + typ reflect.Type + name string +} + +func (dec *objectTypeDecoder) Decode(data []byte) (any, error) { + ptr := reflect.New(dec.typ).Interface() + if err := Unmarshal(data, ptr); err != nil { + return nil, fmt.Errorf(`failed to decode field %s: %w`, dec.name, err) + } + return reflect.ValueOf(ptr).Elem().Interface(), nil +} + +type Registry struct { + mu *sync.RWMutex + ctrs map[string]CustomDecoder +} + +func NewRegistry() *Registry { + return &Registry{ + mu: &sync.RWMutex{}, + ctrs: make(map[string]CustomDecoder), + } +} + +func (r *Registry) Register(name string, object any) { + if object == nil { + r.mu.Lock() + defer r.mu.Unlock() + delete(r.ctrs, name) + return + } + + r.mu.Lock() + defer r.mu.Unlock() + if ctr, ok := object.(CustomDecoder); ok { + r.ctrs[name] = ctr + } else { + r.ctrs[name] = &objectTypeDecoder{ + typ: reflect.TypeOf(object), + name: name, + } + } +} + +func (r *Registry) Decode(dec *Decoder, name string) (any, error) { + r.mu.RLock() + defer r.mu.RUnlock() + + if ctr, ok := r.ctrs[name]; ok { + var raw RawMessage + if err := dec.Decode(&raw); err != nil { + return nil, fmt.Errorf(`failed to decode field %s: %w`, name, err) + } + v, err := ctr.Decode([]byte(raw)) + if err != nil { + return nil, fmt.Errorf(`failed to decode field %s: %w`, name, err) + } + return v, nil + } + + var decoded any + if err := dec.Decode(&decoded); err != nil { + return nil, fmt.Errorf(`failed to decode field %s: %w`, name, err) + } + return decoded, nil +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/internal/json/stdlib.go b/vendor/github.com/lestrrat-go/jwx/v3/internal/json/stdlib.go new file mode 100644 index 00000000000..6f416ec89a9 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/internal/json/stdlib.go @@ -0,0 +1,47 @@ +//go:build !jwx_goccy +// +build !jwx_goccy + +package json + +import ( + "encoding/json" + "io" +) + +type Decoder = json.Decoder +type Delim = json.Delim +type Encoder = json.Encoder +type Marshaler = json.Marshaler +type Number = json.Number +type RawMessage = json.RawMessage +type Unmarshaler = json.Unmarshaler + +func Engine() string { + return "encoding/json" +} + +// NewDecoder respects the values specified in DecoderSettings, +// and creates a Decoder that has certain features turned on/off +func NewDecoder(r io.Reader) *json.Decoder { + dec := json.NewDecoder(r) + + if UseNumber() { + dec.UseNumber() + } + + return dec +} + +func NewEncoder(w io.Writer) *json.Encoder { + return json.NewEncoder(w) +} + +// Marshal is just a proxy for "encoding/json".Marshal +func Marshal(v any) ([]byte, error) { + return json.Marshal(v) +} + +// MarshalIndent is just a proxy for "encoding/json".MarshalIndent +func MarshalIndent(v any, prefix, indent string) ([]byte, error) { + return json.MarshalIndent(v, prefix, indent) +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/internal/jwxio/BUILD.bazel b/vendor/github.com/lestrrat-go/jwx/v3/internal/jwxio/BUILD.bazel new file mode 100644 index 00000000000..c70c4d28717 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/internal/jwxio/BUILD.bazel @@ -0,0 +1,8 @@ +load("@rules_go//go:def.bzl", "go_library") + +go_library( + name = "jwxio", + srcs = ["jwxio.go"], + importpath = "github.com/lestrrat-go/jwx/v3/internal/jwxio", + visibility = ["//:__subpackages__"], +) diff --git a/vendor/github.com/lestrrat-go/jwx/v3/internal/jwxio/jwxio.go b/vendor/github.com/lestrrat-go/jwx/v3/internal/jwxio/jwxio.go new file mode 100644 index 00000000000..8396417a9d2 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/internal/jwxio/jwxio.go @@ -0,0 +1,29 @@ +package jwxio + +import ( + "bytes" + "errors" + "io" + "strings" +) + +var errNonFiniteSource = errors.New(`cannot read from non-finite source`) + +func NonFiniteSourceError() error { + return errNonFiniteSource +} + +// ReadAllFromFiniteSource reads all data from a io.Reader _if_ it comes from a +// finite source. +func ReadAllFromFiniteSource(rdr io.Reader) ([]byte, error) { + switch rdr.(type) { + case *bytes.Reader, *bytes.Buffer, *strings.Reader: + data, err := io.ReadAll(rdr) + if err != nil { + return nil, err + } + return data, nil + default: + return nil, errNonFiniteSource + } +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/internal/keyconv/BUILD.bazel b/vendor/github.com/lestrrat-go/jwx/v3/internal/keyconv/BUILD.bazel new file mode 100644 index 00000000000..d46d2f38140 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/internal/keyconv/BUILD.bazel @@ -0,0 +1,31 @@ +load("@rules_go//go:def.bzl", "go_library", "go_test") + +go_library( + name = "keyconv", + srcs = ["keyconv.go"], + importpath = "github.com/lestrrat-go/jwx/v3/internal/keyconv", + visibility = ["//:__subpackages__"], + deps = [ + "//jwk", + "@com_github_lestrrat_go_blackmagic//:blackmagic", + "@org_golang_x_crypto//ed25519", + ], +) + +go_test( + name = "keyconv_test", + srcs = ["keyconv_test.go"], + deps = [ + ":keyconv", + "//internal/jwxtest", + "//jwa", + "//jwk", + "@com_github_stretchr_testify//require", + ], +) + +alias( + name = "go_default_library", + actual = ":keyconv", + visibility = ["//:__subpackages__"], +) diff --git a/vendor/github.com/lestrrat-go/jwx/v3/internal/keyconv/keyconv.go b/vendor/github.com/lestrrat-go/jwx/v3/internal/keyconv/keyconv.go new file mode 100644 index 00000000000..751fd8f05a4 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/internal/keyconv/keyconv.go @@ -0,0 +1,354 @@ +package keyconv + +import ( + "crypto" + "crypto/ecdh" + "crypto/ecdsa" + "crypto/ed25519" + "crypto/elliptic" + "crypto/rsa" + "fmt" + "math/big" + + "github.com/lestrrat-go/blackmagic" + "github.com/lestrrat-go/jwx/v3/jwk" +) + +// RSAPrivateKey assigns src to dst. +// `dst` should be a pointer to a rsa.PrivateKey. +// `src` may be rsa.PrivateKey, *rsa.PrivateKey, or a jwk.Key +func RSAPrivateKey(dst, src any) error { + if jwkKey, ok := src.(jwk.Key); ok { + var raw rsa.PrivateKey + if err := jwk.Export(jwkKey, &raw); err != nil { + return fmt.Errorf(`failed to produce rsa.PrivateKey from %T: %w`, src, err) + } + src = &raw + } + + var ptr *rsa.PrivateKey + switch src := src.(type) { + case rsa.PrivateKey: + ptr = &src + case *rsa.PrivateKey: + ptr = src + default: + return fmt.Errorf(`keyconv: expected rsa.PrivateKey or *rsa.PrivateKey, got %T`, src) + } + + return blackmagic.AssignIfCompatible(dst, ptr) +} + +// RSAPublicKey assigns src to dst +// `dst` should be a pointer to a non-zero rsa.PublicKey. +// `src` may be rsa.PublicKey, *rsa.PublicKey, or a jwk.Key +func RSAPublicKey(dst, src any) error { + if jwkKey, ok := src.(jwk.Key); ok { + pk, err := jwk.PublicRawKeyOf(jwkKey) + if err != nil { + return fmt.Errorf(`keyconv: failed to produce public key from %T: %w`, src, err) + } + src = pk + } + + var ptr *rsa.PublicKey + switch src := src.(type) { + case rsa.PrivateKey: + ptr = &src.PublicKey + case *rsa.PrivateKey: + ptr = &src.PublicKey + case rsa.PublicKey: + ptr = &src + case *rsa.PublicKey: + ptr = src + default: + return fmt.Errorf(`keyconv: expected rsa.PublicKey/rsa.PrivateKey or *rsa.PublicKey/*rsa.PrivateKey, got %T`, src) + } + + return blackmagic.AssignIfCompatible(dst, ptr) +} + +// ECDSAPrivateKey assigns src to dst, converting its type from a +// non-pointer to a pointer +func ECDSAPrivateKey(dst, src any) error { + if jwkKey, ok := src.(jwk.Key); ok { + var raw ecdsa.PrivateKey + if err := jwk.Export(jwkKey, &raw); err != nil { + return fmt.Errorf(`keyconv: failed to produce ecdsa.PrivateKey from %T: %w`, src, err) + } + src = &raw + } + + var ptr *ecdsa.PrivateKey + switch src := src.(type) { + case ecdsa.PrivateKey: + ptr = &src + case *ecdsa.PrivateKey: + ptr = src + default: + return fmt.Errorf(`keyconv: expected ecdsa.PrivateKey or *ecdsa.PrivateKey, got %T`, src) + } + return blackmagic.AssignIfCompatible(dst, ptr) +} + +// ECDSAPublicKey assigns src to dst, converting its type from a +// non-pointer to a pointer +func ECDSAPublicKey(dst, src any) error { + if jwkKey, ok := src.(jwk.Key); ok { + pk, err := jwk.PublicRawKeyOf(jwkKey) + if err != nil { + return fmt.Errorf(`keyconv: failed to produce public key from %T: %w`, src, err) + } + src = pk + } + + var ptr *ecdsa.PublicKey + switch src := src.(type) { + case ecdsa.PrivateKey: + ptr = &src.PublicKey + case *ecdsa.PrivateKey: + ptr = &src.PublicKey + case ecdsa.PublicKey: + ptr = &src + case *ecdsa.PublicKey: + ptr = src + default: + return fmt.Errorf(`keyconv: expected ecdsa.PublicKey/ecdsa.PrivateKey or *ecdsa.PublicKey/*ecdsa.PrivateKey, got %T`, src) + } + return blackmagic.AssignIfCompatible(dst, ptr) +} + +func ByteSliceKey(dst, src any) error { + if jwkKey, ok := src.(jwk.Key); ok { + var raw []byte + if err := jwk.Export(jwkKey, &raw); err != nil { + return fmt.Errorf(`keyconv: failed to produce []byte from %T: %w`, src, err) + } + src = raw + } + + if _, ok := src.([]byte); !ok { + return fmt.Errorf(`keyconv: expected []byte, got %T`, src) + } + return blackmagic.AssignIfCompatible(dst, src) +} + +func Ed25519PrivateKey(dst, src any) error { + if jwkKey, ok := src.(jwk.Key); ok { + var raw ed25519.PrivateKey + if err := jwk.Export(jwkKey, &raw); err != nil { + return fmt.Errorf(`failed to produce ed25519.PrivateKey from %T: %w`, src, err) + } + src = &raw + } + + var ptr *ed25519.PrivateKey + switch src := src.(type) { + case ed25519.PrivateKey: + ptr = &src + case *ed25519.PrivateKey: + ptr = src + default: + return fmt.Errorf(`expected ed25519.PrivateKey or *ed25519.PrivateKey, got %T`, src) + } + return blackmagic.AssignIfCompatible(dst, ptr) +} + +func Ed25519PublicKey(dst, src any) error { + if jwkKey, ok := src.(jwk.Key); ok { + pk, err := jwk.PublicRawKeyOf(jwkKey) + if err != nil { + return fmt.Errorf(`keyconv: failed to produce public key from %T: %w`, src, err) + } + src = pk + } + + switch key := src.(type) { + case ed25519.PrivateKey: + src = key.Public() + case *ed25519.PrivateKey: + src = key.Public() + } + + var ptr *ed25519.PublicKey + switch src := src.(type) { + case ed25519.PublicKey: + ptr = &src + case *ed25519.PublicKey: + ptr = src + case *crypto.PublicKey: + tmp, ok := (*src).(ed25519.PublicKey) + if !ok { + return fmt.Errorf(`failed to retrieve ed25519.PublicKey out of *crypto.PublicKey`) + } + ptr = &tmp + case crypto.PublicKey: + tmp, ok := src.(ed25519.PublicKey) + if !ok { + return fmt.Errorf(`failed to retrieve ed25519.PublicKey out of crypto.PublicKey`) + } + ptr = &tmp + default: + return fmt.Errorf(`expected ed25519.PublicKey or *ed25519.PublicKey, got %T`, src) + } + return blackmagic.AssignIfCompatible(dst, ptr) +} + +type privECDHer interface { + ECDH() (*ecdh.PrivateKey, error) +} + +func ECDHPrivateKey(dst, src any) error { + var privECDH *ecdh.PrivateKey + if jwkKey, ok := src.(jwk.Key); ok { + var rawECDH ecdh.PrivateKey + if err := jwk.Export(jwkKey, &rawECDH); err == nil { + privECDH = &rawECDH + } else { + // If we cannot export the key as an ecdh.PrivateKey, we try to export it as an ecdsa.PrivateKey + var rawECDSA ecdsa.PrivateKey + if err := jwk.Export(jwkKey, &rawECDSA); err != nil { + return fmt.Errorf(`keyconv: failed to produce ecdh.PrivateKey or ecdsa.PrivateKey from %T: %w`, src, err) + } + src = &rawECDSA + } + } + + switch src := src.(type) { + case ecdh.PrivateKey: + privECDH = &src + case *ecdh.PrivateKey: + privECDH = src + case privECDHer: + priv, err := src.ECDH() + if err != nil { + return fmt.Errorf(`keyconv: failed to convert ecdsa.PrivateKey to ecdh.PrivateKey: %w`, err) + } + privECDH = priv + } + + return blackmagic.AssignIfCompatible(dst, privECDH) +} + +type pubECDHer interface { + ECDH() (*ecdh.PublicKey, error) +} + +func ECDHPublicKey(dst, src any) error { + var pubECDH *ecdh.PublicKey + if jwkKey, ok := src.(jwk.Key); ok { + var rawECDH ecdh.PublicKey + if err := jwk.Export(jwkKey, &rawECDH); err == nil { + pubECDH = &rawECDH + } else { + // If we cannot export the key as an ecdh.PublicKey, we try to export it as an ecdsa.PublicKey + var rawECDSA ecdsa.PublicKey + if err := jwk.Export(jwkKey, &rawECDSA); err != nil { + return fmt.Errorf(`keyconv: failed to produce ecdh.PublicKey or ecdsa.PublicKey from %T: %w`, src, err) + } + src = &rawECDSA + } + } + + switch src := src.(type) { + case ecdh.PublicKey: + pubECDH = &src + case *ecdh.PublicKey: + pubECDH = src + case pubECDHer: + pub, err := src.ECDH() + if err != nil { + return fmt.Errorf(`keyconv: failed to convert ecdsa.PublicKey to ecdh.PublicKey: %w`, err) + } + pubECDH = pub + } + + return blackmagic.AssignIfCompatible(dst, pubECDH) +} + +// ecdhCurveToElliptic maps ECDH curves to elliptic curves +func ecdhCurveToElliptic(ecdhCurve ecdh.Curve) (elliptic.Curve, error) { + switch ecdhCurve { + case ecdh.P256(): + return elliptic.P256(), nil + case ecdh.P384(): + return elliptic.P384(), nil + case ecdh.P521(): + return elliptic.P521(), nil + default: + return nil, fmt.Errorf(`keyconv: unsupported ECDH curve: %v`, ecdhCurve) + } +} + +// ecdhPublicKeyToECDSA converts an ECDH public key to an ECDSA public key +func ecdhPublicKeyToECDSA(ecdhPubKey *ecdh.PublicKey) (*ecdsa.PublicKey, error) { + curve, err := ecdhCurveToElliptic(ecdhPubKey.Curve()) + if err != nil { + return nil, err + } + + pubBytes := ecdhPubKey.Bytes() + + // Parse the uncompressed point format (0x04 prefix + X + Y coordinates) + if len(pubBytes) == 0 || pubBytes[0] != 0x04 { + return nil, fmt.Errorf(`keyconv: invalid ECDH public key format`) + } + + keyLen := (len(pubBytes) - 1) / 2 + if len(pubBytes) != 1+2*keyLen { + return nil, fmt.Errorf(`keyconv: invalid ECDH public key length`) + } + + x := new(big.Int).SetBytes(pubBytes[1 : 1+keyLen]) + y := new(big.Int).SetBytes(pubBytes[1+keyLen:]) + + return &ecdsa.PublicKey{ + Curve: curve, + X: x, + Y: y, + }, nil +} + +func ECDHToECDSA(dst, src any) error { + // convert ecdh.PublicKey to ecdsa.PublicKey, ecdh.PrivateKey to ecdsa.PrivateKey + + // First, handle value types by converting to pointers + switch s := src.(type) { + case ecdh.PrivateKey: + src = &s + case ecdh.PublicKey: + src = &s + } + + var privBytes []byte + var pubkey *ecdh.PublicKey + // Now handle the actual conversion with pointer types + switch src := src.(type) { + case *ecdh.PrivateKey: + pubkey = src.PublicKey() + privBytes = src.Bytes() + case *ecdh.PublicKey: + pubkey = src + default: + return fmt.Errorf(`keyconv: expected ecdh.PrivateKey, *ecdh.PrivateKey, ecdh.PublicKey, or *ecdh.PublicKey, got %T`, src) + } + + // convert the public key + ecdsaPubKey, err := ecdhPublicKeyToECDSA(pubkey) + if err != nil { + return fmt.Errorf(`keyconv.ECDHToECDSA: failed to convert ECDH public key to ECDSA public key: %w`, err) + } + + // return if we were being asked to convert *ecdh.PublicKey + if privBytes == nil { + return blackmagic.AssignIfCompatible(dst, ecdsaPubKey) + } + + // Then create the private key with the public key embedded + ecdsaPrivKey := &ecdsa.PrivateKey{ + D: new(big.Int).SetBytes(privBytes), + PublicKey: *ecdsaPubKey, + } + + return blackmagic.AssignIfCompatible(dst, ecdsaPrivKey) +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/internal/pool/BUILD.bazel b/vendor/github.com/lestrrat-go/jwx/v3/internal/pool/BUILD.bazel new file mode 100644 index 00000000000..cebc269330e --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/internal/pool/BUILD.bazel @@ -0,0 +1,32 @@ +load("@rules_go//go:def.bzl", "go_library", "go_test") + +go_library( + name = "pool", + srcs = [ + "big_int.go", + "byte_slice.go", + "bytes_buffer.go", + "error_slice.go", + "key_to_error_map.go", + "pool.go", + ], + importpath = "github.com/lestrrat-go/jwx/v3/internal/pool", + visibility = ["//:__subpackages__"], +) + +alias( + name = "go_default_library", + actual = ":pool", + visibility = ["//:__subpackages__"], +) + +go_test( + name = "pool_test", + srcs = [ + "byte_slice_test.go", + ], + deps = [ + ":pool", + "@com_github_stretchr_testify//require", + ], +) \ No newline at end of file diff --git a/vendor/github.com/lestrrat-go/jwx/v3/internal/pool/big_int.go b/vendor/github.com/lestrrat-go/jwx/v3/internal/pool/big_int.go new file mode 100644 index 00000000000..57c446d4d2e --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/internal/pool/big_int.go @@ -0,0 +1,19 @@ +package pool + +import "math/big" + +var bigIntPool = New[*big.Int](allocBigInt, freeBigInt) + +func allocBigInt() *big.Int { + return &big.Int{} +} + +func freeBigInt(b *big.Int) *big.Int { + b.SetInt64(0) // Reset the value to zero + return b +} + +// BigInt returns a pool of *big.Int instances. +func BigInt() *Pool[*big.Int] { + return bigIntPool +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/internal/pool/byte_slice.go b/vendor/github.com/lestrrat-go/jwx/v3/internal/pool/byte_slice.go new file mode 100644 index 00000000000..46f1028343c --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/internal/pool/byte_slice.go @@ -0,0 +1,19 @@ +package pool + +var byteSlicePool = SlicePool[byte]{ + pool: New[[]byte](allocByteSlice, freeByteSlice), +} + +func allocByteSlice() []byte { + return make([]byte, 0, 64) // Default capacity of 64 bytes +} + +func freeByteSlice(b []byte) []byte { + clear(b) + b = b[:0] // Reset the slice to zero length + return b +} + +func ByteSlice() SlicePool[byte] { + return byteSlicePool +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/internal/pool/bytes_buffer.go b/vendor/github.com/lestrrat-go/jwx/v3/internal/pool/bytes_buffer.go new file mode 100644 index 00000000000..a877f73ff8d --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/internal/pool/bytes_buffer.go @@ -0,0 +1,18 @@ +package pool + +import "bytes" + +var bytesBufferPool = New[*bytes.Buffer](allocBytesBuffer, freeBytesBuffer) + +func allocBytesBuffer() *bytes.Buffer { + return &bytes.Buffer{} +} + +func freeBytesBuffer(b *bytes.Buffer) *bytes.Buffer { + b.Reset() + return b +} + +func BytesBuffer() *Pool[*bytes.Buffer] { + return bytesBufferPool +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/internal/pool/error_slice.go b/vendor/github.com/lestrrat-go/jwx/v3/internal/pool/error_slice.go new file mode 100644 index 00000000000..4f1675c1c08 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/internal/pool/error_slice.go @@ -0,0 +1,16 @@ +package pool + +var errorSlicePool = New[[]error](allocErrorSlice, freeErrorSlice) + +func allocErrorSlice() []error { + return make([]error, 0, 1) +} + +func freeErrorSlice(s []error) []error { + // Reset the slice to its zero value + return s[:0] +} + +func ErrorSlice() *Pool[[]error] { + return errorSlicePool +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/internal/pool/key_to_error_map.go b/vendor/github.com/lestrrat-go/jwx/v3/internal/pool/key_to_error_map.go new file mode 100644 index 00000000000..9fae012644c --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/internal/pool/key_to_error_map.go @@ -0,0 +1,19 @@ +package pool + +var keyToErrorMapPool = New[map[string]error](allocKeyToErrorMap, freeKeyToErrorMap) + +func allocKeyToErrorMap() map[string]error { + return make(map[string]error) +} + +func freeKeyToErrorMap(m map[string]error) map[string]error { + for k := range m { + delete(m, k) // Clear the map + } + return m +} + +// KeyToErrorMap returns a pool of map[string]error instances. +func KeyToErrorMap() *Pool[map[string]error] { + return keyToErrorMapPool +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/internal/pool/pool.go b/vendor/github.com/lestrrat-go/jwx/v3/internal/pool/pool.go new file mode 100644 index 00000000000..008b1cdb8ba --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/internal/pool/pool.go @@ -0,0 +1,70 @@ +package pool + +import ( + "sync" +) + +type Pool[T any] struct { + pool sync.Pool + destructor func(T) T +} + +// New creates a new Pool instance for the type T. +// The allocator function is used to create new instances of T when the pool is empty. +// The destructor function is used to clean up instances of T before they are returned to the pool. +// The destructor should reset the state of T to a clean state, so it can be reused, and +// return the modified instance of T. This is required for cases when you reset operations +// can modify the underlying data structure, such as slices or maps. +func New[T any](allocator func() T, destructor func(T) T) *Pool[T] { + return &Pool[T]{ + pool: sync.Pool{ + New: func() any { + return allocator() + }, + }, + destructor: destructor, + } +} + +// Get retrieves an item of type T from the pool. +func (p *Pool[T]) Get() T { + //nolint:forcetypeassert + return p.pool.Get().(T) +} + +// Put returns an item of type T to the pool. +// The item is first processed by the destructor function to ensure it is in a clean state. +func (p *Pool[T]) Put(item T) { + p.pool.Put(p.destructor(item)) +} + +// SlicePool is a specialized pool for slices of type T. It is identical to Pool[T] but +// provides additional functionality to get slices with a specific capacity. +type SlicePool[T any] struct { + pool *Pool[[]T] +} + +func NewSlicePool[T any](allocator func() []T, destructor func([]T) []T) SlicePool[T] { + return SlicePool[T]{ + pool: New(allocator, destructor), + } +} + +func (p SlicePool[T]) Get() []T { + return p.pool.Get() +} + +func (p SlicePool[T]) GetCapacity(capacity int) []T { + if capacity <= 0 { + return p.Get() + } + s := p.Get() + if cap(s) < capacity { + s = make([]T, 0, capacity) + } + return s +} + +func (p SlicePool[T]) Put(s []T) { + p.pool.Put(s) +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/internal/tokens/BUILD.bazel b/vendor/github.com/lestrrat-go/jwx/v3/internal/tokens/BUILD.bazel new file mode 100644 index 00000000000..6a331efb346 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/internal/tokens/BUILD.bazel @@ -0,0 +1,17 @@ +load("@rules_go//go:def.bzl", "go_library") + +go_library( + name = "tokens", + srcs = [ + "jwe_tokens.go", + "tokens.go", + ], + importpath = "github.com/lestrrat-go/jwx/v3/internal/tokens", + visibility = ["//:__subpackages__"], +) + +alias( + name = "go_default_library", + actual = ":tokens", + visibility = ["//:__subpackages__"], +) diff --git a/vendor/github.com/lestrrat-go/jwx/v3/internal/tokens/jwe_tokens.go b/vendor/github.com/lestrrat-go/jwx/v3/internal/tokens/jwe_tokens.go new file mode 100644 index 00000000000..9001cbbbc78 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/internal/tokens/jwe_tokens.go @@ -0,0 +1,48 @@ +package tokens + +// JWE Key Encryption Algorithms +const ( + // RSA algorithms + RSA1_5 = "RSA1_5" + RSA_OAEP = "RSA-OAEP" + RSA_OAEP_256 = "RSA-OAEP-256" + RSA_OAEP_384 = "RSA-OAEP-384" + RSA_OAEP_512 = "RSA-OAEP-512" + + // AES Key Wrap algorithms + A128KW = "A128KW" + A192KW = "A192KW" + A256KW = "A256KW" + + // AES GCM Key Wrap algorithms + A128GCMKW = "A128GCMKW" + A192GCMKW = "A192GCMKW" + A256GCMKW = "A256GCMKW" + + // ECDH-ES algorithms + ECDH_ES = "ECDH-ES" + ECDH_ES_A128KW = "ECDH-ES+A128KW" + ECDH_ES_A192KW = "ECDH-ES+A192KW" + ECDH_ES_A256KW = "ECDH-ES+A256KW" + + // PBES2 algorithms + PBES2_HS256_A128KW = "PBES2-HS256+A128KW" + PBES2_HS384_A192KW = "PBES2-HS384+A192KW" + PBES2_HS512_A256KW = "PBES2-HS512+A256KW" + + // Direct key agreement + DIRECT = "dir" +) + +// JWE Content Encryption Algorithms +const ( + // AES GCM algorithms + A128GCM = "A128GCM" + A192GCM = "A192GCM" + A256GCM = "A256GCM" + + // AES CBC + HMAC algorithms + A128CBC_HS256 = "A128CBC-HS256" + A192CBC_HS384 = "A192CBC-HS384" + A256CBC_HS512 = "A256CBC-HS512" +) diff --git a/vendor/github.com/lestrrat-go/jwx/v3/internal/tokens/tokens.go b/vendor/github.com/lestrrat-go/jwx/v3/internal/tokens/tokens.go new file mode 100644 index 00000000000..2af3b88de16 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/internal/tokens/tokens.go @@ -0,0 +1,51 @@ +package tokens + +const ( + CloseCurlyBracket = '}' + CloseSquareBracket = ']' + Colon = ':' + Comma = ',' + DoubleQuote = '"' + OpenCurlyBracket = '{' + OpenSquareBracket = '[' + Period = '.' +) + +// Cryptographic key sizes +const ( + KeySize16 = 16 + KeySize24 = 24 + KeySize32 = 32 + KeySize48 = 48 // A192CBC_HS384 key size + KeySize64 = 64 // A256CBC_HS512 key size +) + +// Bit/byte conversion factors +const ( + BitsPerByte = 8 + BytesPerBit = 1.0 / 8 +) + +// Key wrapping constants +const ( + KeywrapChunkLen = 8 + KeywrapRounds = 6 // RFC 3394 key wrap rounds + KeywrapBlockSize = 8 // Key wrap block size in bytes +) + +// AES-GCM constants +const ( + GCMIVSize = 12 // GCM IV size in bytes (96 bits) + GCMTagSize = 16 // GCM tag size in bytes (128 bits) +) + +// PBES2 constants +const ( + PBES2DefaultIterations = 10000 // Default PBKDF2 iteration count + PBES2NullByteSeparator = 0 // Null byte separator for PBES2 +) + +// RSA key generation constants +const ( + RSAKeyGenMultiplier = 2 // RSA key generation size multiplier +) diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwa/BUILD.bazel b/vendor/github.com/lestrrat-go/jwx/v3/jwa/BUILD.bazel new file mode 100644 index 00000000000..cfb7af02a00 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwa/BUILD.bazel @@ -0,0 +1,45 @@ +load("@rules_go//go:def.bzl", "go_library", "go_test") + +go_library( + name = "jwa", + srcs = [ + "compression_gen.go", + "content_encryption_gen.go", + "elliptic_gen.go", + "jwa.go", + "key_encryption_gen.go", + "key_type_gen.go", + "options_gen.go", + "signature_gen.go", + ], + importpath = "github.com/lestrrat-go/jwx/v3/jwa", + visibility = ["//visibility:public"], + deps = [ + "//internal/tokens", + "@com_github_lestrrat_go_option_v2//:option", + ], +) + +go_test( + name = "jwa_test", + srcs = [ + "compression_gen_test.go", + "content_encryption_gen_test.go", + "elliptic_gen_test.go", + "jwa_test.go", + "key_encryption_gen_test.go", + "key_type_gen_test.go", + "signature_gen_test.go", + ], + deps = [ + ":jwa", + "@com_github_stretchr_testify//require", + "@com_github_lestrrat_go_option_v2//:option", + ], +) + +alias( + name = "go_default_library", + actual = ":jwa", + visibility = ["//visibility:public"], +) diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwa/README.md b/vendor/github.com/lestrrat-go/jwx/v3/jwa/README.md new file mode 100644 index 00000000000..270e60c6724 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwa/README.md @@ -0,0 +1,3 @@ +# JWA [![Go Reference](https://pkg.go.dev/badge/github.com/lestrrat-go/jwx/v3/jwa.svg)](https://pkg.go.dev/github.com/lestrrat-go/jwx/v3/jwa) + +Package [github.com/lestrrat-go/jwx/v3/jwa](./jwa) defines the various algorithm described in [RFC7518](https://tools.ietf.org/html/rfc7518) diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwa/compression_gen.go b/vendor/github.com/lestrrat-go/jwx/v3/jwa/compression_gen.go new file mode 100644 index 00000000000..a7a2451afa8 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwa/compression_gen.go @@ -0,0 +1,153 @@ +// Code generated by tools/cmd/genjwa/main.go. DO NOT EDIT. + +package jwa + +import ( + "encoding/json" + "fmt" + "sort" + "sync" +) + +var muAllCompressionAlgorithm sync.RWMutex +var allCompressionAlgorithm = map[string]CompressionAlgorithm{} +var muListCompressionAlgorithm sync.RWMutex +var listCompressionAlgorithm []CompressionAlgorithm +var builtinCompressionAlgorithm = map[string]struct{}{} + +func init() { + // builtin values for CompressionAlgorithm + algorithms := make([]CompressionAlgorithm, 2) + algorithms[0] = NewCompressionAlgorithm("DEF") + algorithms[1] = NewCompressionAlgorithm("") + + RegisterCompressionAlgorithm(algorithms...) +} + +// Deflate returns an object representing the "DEF" content compression algorithm value. Using this value specifies that the content should be compressed using DEFLATE (RFC 1951). +func Deflate() CompressionAlgorithm { + return lookupBuiltinCompressionAlgorithm("DEF") +} + +// NoCompress returns an object representing an empty compression algorithm value. Using this value specifies that the content should not be compressed. +func NoCompress() CompressionAlgorithm { + return lookupBuiltinCompressionAlgorithm("") +} + +func lookupBuiltinCompressionAlgorithm(name string) CompressionAlgorithm { + muAllCompressionAlgorithm.RLock() + v, ok := allCompressionAlgorithm[name] + muAllCompressionAlgorithm.RUnlock() + if !ok { + panic(fmt.Sprintf(`jwa: CompressionAlgorithm %q not registered`, name)) + } + return v +} + +// CompressionAlgorithm represents the compression algorithms as described in https://tools.ietf.org/html/rfc7518#section-7.3 +type CompressionAlgorithm struct { + name string + deprecated bool +} + +func (s CompressionAlgorithm) String() string { + return s.name +} + +// IsDeprecated returns true if the CompressionAlgorithm object is deprecated. +func (s CompressionAlgorithm) IsDeprecated() bool { + return s.deprecated +} + +// EmptyCompressionAlgorithm returns an empty CompressionAlgorithm object, used as a zero value. +func EmptyCompressionAlgorithm() CompressionAlgorithm { + return CompressionAlgorithm{} +} + +// NewCompressionAlgorithm creates a new CompressionAlgorithm object with the given name. +func NewCompressionAlgorithm(name string, options ...NewAlgorithmOption) CompressionAlgorithm { + var deprecated bool + for _, option := range options { + switch option.Ident() { + case identDeprecated{}: + if err := option.Value(&deprecated); err != nil { + panic("jwa.NewCompressionAlgorithm: WithDeprecated option must be a boolean") + } + } + } + return CompressionAlgorithm{name: name, deprecated: deprecated} +} + +// LookupCompressionAlgorithm returns the CompressionAlgorithm object for the given name. +func LookupCompressionAlgorithm(name string) (CompressionAlgorithm, bool) { + muAllCompressionAlgorithm.RLock() + v, ok := allCompressionAlgorithm[name] + muAllCompressionAlgorithm.RUnlock() + return v, ok +} + +// RegisterCompressionAlgorithm registers a new CompressionAlgorithm. The signature value must be immutable +// and safe to be used by multiple goroutines, as it is going to be shared with all other users of this library. +func RegisterCompressionAlgorithm(algorithms ...CompressionAlgorithm) { + muAllCompressionAlgorithm.Lock() + for _, alg := range algorithms { + allCompressionAlgorithm[alg.String()] = alg + } + muAllCompressionAlgorithm.Unlock() + rebuildCompressionAlgorithm() +} + +// UnregisterCompressionAlgorithm unregisters a CompressionAlgorithm from its known database. +// Non-existent entries, as well as built-in algorithms will silently be ignored. +func UnregisterCompressionAlgorithm(algorithms ...CompressionAlgorithm) { + muAllCompressionAlgorithm.Lock() + for _, alg := range algorithms { + if _, ok := builtinCompressionAlgorithm[alg.String()]; ok { + continue + } + delete(allCompressionAlgorithm, alg.String()) + } + muAllCompressionAlgorithm.Unlock() + rebuildCompressionAlgorithm() +} + +func rebuildCompressionAlgorithm() { + list := make([]CompressionAlgorithm, 0, len(allCompressionAlgorithm)) + muAllCompressionAlgorithm.RLock() + for _, v := range allCompressionAlgorithm { + list = append(list, v) + } + muAllCompressionAlgorithm.RUnlock() + sort.Slice(list, func(i, j int) bool { + return list[i].String() < list[j].String() + }) + muListCompressionAlgorithm.Lock() + listCompressionAlgorithm = list + muListCompressionAlgorithm.Unlock() +} + +// CompressionAlgorithms returns a list of all available values for CompressionAlgorithm. +func CompressionAlgorithms() []CompressionAlgorithm { + muListCompressionAlgorithm.RLock() + defer muListCompressionAlgorithm.RUnlock() + return listCompressionAlgorithm +} + +// MarshalJSON serializes the CompressionAlgorithm object to a JSON string. +func (s CompressionAlgorithm) MarshalJSON() ([]byte, error) { + return json.Marshal(s.String()) +} + +// UnmarshalJSON deserializes the JSON string to a CompressionAlgorithm object. +func (s *CompressionAlgorithm) UnmarshalJSON(data []byte) error { + var name string + if err := json.Unmarshal(data, &name); err != nil { + return fmt.Errorf(`failed to unmarshal CompressionAlgorithm: %w`, err) + } + v, ok := LookupCompressionAlgorithm(name) + if !ok { + return fmt.Errorf(`unknown CompressionAlgorithm: %q`, name) + } + *s = v + return nil +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwa/content_encryption_gen.go b/vendor/github.com/lestrrat-go/jwx/v3/jwa/content_encryption_gen.go new file mode 100644 index 00000000000..8ccc47e462f --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwa/content_encryption_gen.go @@ -0,0 +1,179 @@ +// Code generated by tools/cmd/genjwa/main.go. DO NOT EDIT. + +package jwa + +import ( + "encoding/json" + "fmt" + "sort" + "sync" + + "github.com/lestrrat-go/jwx/v3/internal/tokens" +) + +var muAllContentEncryptionAlgorithm sync.RWMutex +var allContentEncryptionAlgorithm = map[string]ContentEncryptionAlgorithm{} +var muListContentEncryptionAlgorithm sync.RWMutex +var listContentEncryptionAlgorithm []ContentEncryptionAlgorithm +var builtinContentEncryptionAlgorithm = map[string]struct{}{} + +func init() { + // builtin values for ContentEncryptionAlgorithm + algorithms := make([]ContentEncryptionAlgorithm, 6) + algorithms[0] = NewContentEncryptionAlgorithm(tokens.A128CBC_HS256) + algorithms[1] = NewContentEncryptionAlgorithm(tokens.A128GCM) + algorithms[2] = NewContentEncryptionAlgorithm(tokens.A192CBC_HS384) + algorithms[3] = NewContentEncryptionAlgorithm(tokens.A192GCM) + algorithms[4] = NewContentEncryptionAlgorithm(tokens.A256CBC_HS512) + algorithms[5] = NewContentEncryptionAlgorithm(tokens.A256GCM) + + RegisterContentEncryptionAlgorithm(algorithms...) +} + +// A128CBC_HS256 returns an object representing A128CBC-HS256. Using this value specifies that the content should be encrypted using AES-CBC + HMAC-SHA256 (128). +func A128CBC_HS256() ContentEncryptionAlgorithm { + return lookupBuiltinContentEncryptionAlgorithm(tokens.A128CBC_HS256) +} + +// A128GCM returns an object representing A128GCM. Using this value specifies that the content should be encrypted using AES-GCM (128). +func A128GCM() ContentEncryptionAlgorithm { + return lookupBuiltinContentEncryptionAlgorithm(tokens.A128GCM) +} + +// A192CBC_HS384 returns an object representing A192CBC-HS384. Using this value specifies that the content should be encrypted using AES-CBC + HMAC-SHA384 (192). +func A192CBC_HS384() ContentEncryptionAlgorithm { + return lookupBuiltinContentEncryptionAlgorithm(tokens.A192CBC_HS384) +} + +// A192GCM returns an object representing A192GCM. Using this value specifies that the content should be encrypted using AES-GCM (192). +func A192GCM() ContentEncryptionAlgorithm { + return lookupBuiltinContentEncryptionAlgorithm(tokens.A192GCM) +} + +// A256CBC_HS512 returns an object representing A256CBC-HS512. Using this value specifies that the content should be encrypted using AES-CBC + HMAC-SHA512 (256). +func A256CBC_HS512() ContentEncryptionAlgorithm { + return lookupBuiltinContentEncryptionAlgorithm(tokens.A256CBC_HS512) +} + +// A256GCM returns an object representing A256GCM. Using this value specifies that the content should be encrypted using AES-GCM (256). +func A256GCM() ContentEncryptionAlgorithm { + return lookupBuiltinContentEncryptionAlgorithm(tokens.A256GCM) +} + +func lookupBuiltinContentEncryptionAlgorithm(name string) ContentEncryptionAlgorithm { + muAllContentEncryptionAlgorithm.RLock() + v, ok := allContentEncryptionAlgorithm[name] + muAllContentEncryptionAlgorithm.RUnlock() + if !ok { + panic(fmt.Sprintf(`jwa: ContentEncryptionAlgorithm %q not registered`, name)) + } + return v +} + +// ContentEncryptionAlgorithm represents the various encryption algorithms as described in https://tools.ietf.org/html/rfc7518#section-5 +type ContentEncryptionAlgorithm struct { + name string + deprecated bool +} + +func (s ContentEncryptionAlgorithm) String() string { + return s.name +} + +// IsDeprecated returns true if the ContentEncryptionAlgorithm object is deprecated. +func (s ContentEncryptionAlgorithm) IsDeprecated() bool { + return s.deprecated +} + +// EmptyContentEncryptionAlgorithm returns an empty ContentEncryptionAlgorithm object, used as a zero value. +func EmptyContentEncryptionAlgorithm() ContentEncryptionAlgorithm { + return ContentEncryptionAlgorithm{} +} + +// NewContentEncryptionAlgorithm creates a new ContentEncryptionAlgorithm object with the given name. +func NewContentEncryptionAlgorithm(name string, options ...NewAlgorithmOption) ContentEncryptionAlgorithm { + var deprecated bool + for _, option := range options { + switch option.Ident() { + case identDeprecated{}: + if err := option.Value(&deprecated); err != nil { + panic("jwa.NewContentEncryptionAlgorithm: WithDeprecated option must be a boolean") + } + } + } + return ContentEncryptionAlgorithm{name: name, deprecated: deprecated} +} + +// LookupContentEncryptionAlgorithm returns the ContentEncryptionAlgorithm object for the given name. +func LookupContentEncryptionAlgorithm(name string) (ContentEncryptionAlgorithm, bool) { + muAllContentEncryptionAlgorithm.RLock() + v, ok := allContentEncryptionAlgorithm[name] + muAllContentEncryptionAlgorithm.RUnlock() + return v, ok +} + +// RegisterContentEncryptionAlgorithm registers a new ContentEncryptionAlgorithm. The signature value must be immutable +// and safe to be used by multiple goroutines, as it is going to be shared with all other users of this library. +func RegisterContentEncryptionAlgorithm(algorithms ...ContentEncryptionAlgorithm) { + muAllContentEncryptionAlgorithm.Lock() + for _, alg := range algorithms { + allContentEncryptionAlgorithm[alg.String()] = alg + } + muAllContentEncryptionAlgorithm.Unlock() + rebuildContentEncryptionAlgorithm() +} + +// UnregisterContentEncryptionAlgorithm unregisters a ContentEncryptionAlgorithm from its known database. +// Non-existent entries, as well as built-in algorithms will silently be ignored. +func UnregisterContentEncryptionAlgorithm(algorithms ...ContentEncryptionAlgorithm) { + muAllContentEncryptionAlgorithm.Lock() + for _, alg := range algorithms { + if _, ok := builtinContentEncryptionAlgorithm[alg.String()]; ok { + continue + } + delete(allContentEncryptionAlgorithm, alg.String()) + } + muAllContentEncryptionAlgorithm.Unlock() + rebuildContentEncryptionAlgorithm() +} + +func rebuildContentEncryptionAlgorithm() { + list := make([]ContentEncryptionAlgorithm, 0, len(allContentEncryptionAlgorithm)) + muAllContentEncryptionAlgorithm.RLock() + for _, v := range allContentEncryptionAlgorithm { + list = append(list, v) + } + muAllContentEncryptionAlgorithm.RUnlock() + sort.Slice(list, func(i, j int) bool { + return list[i].String() < list[j].String() + }) + muListContentEncryptionAlgorithm.Lock() + listContentEncryptionAlgorithm = list + muListContentEncryptionAlgorithm.Unlock() +} + +// ContentEncryptionAlgorithms returns a list of all available values for ContentEncryptionAlgorithm. +func ContentEncryptionAlgorithms() []ContentEncryptionAlgorithm { + muListContentEncryptionAlgorithm.RLock() + defer muListContentEncryptionAlgorithm.RUnlock() + return listContentEncryptionAlgorithm +} + +// MarshalJSON serializes the ContentEncryptionAlgorithm object to a JSON string. +func (s ContentEncryptionAlgorithm) MarshalJSON() ([]byte, error) { + return json.Marshal(s.String()) +} + +// UnmarshalJSON deserializes the JSON string to a ContentEncryptionAlgorithm object. +func (s *ContentEncryptionAlgorithm) UnmarshalJSON(data []byte) error { + var name string + if err := json.Unmarshal(data, &name); err != nil { + return fmt.Errorf(`failed to unmarshal ContentEncryptionAlgorithm: %w`, err) + } + v, ok := LookupContentEncryptionAlgorithm(name) + if !ok { + return fmt.Errorf(`unknown ContentEncryptionAlgorithm: %q`, name) + } + *s = v + return nil +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwa/elliptic_gen.go b/vendor/github.com/lestrrat-go/jwx/v3/jwa/elliptic_gen.go new file mode 100644 index 00000000000..2418efde08f --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwa/elliptic_gen.go @@ -0,0 +1,190 @@ +// Code generated by tools/cmd/genjwa/main.go. DO NOT EDIT. + +package jwa + +import ( + "encoding/json" + "fmt" + "sort" + "sync" +) + +var muAllEllipticCurveAlgorithm sync.RWMutex +var allEllipticCurveAlgorithm = map[string]EllipticCurveAlgorithm{} +var muListEllipticCurveAlgorithm sync.RWMutex +var listEllipticCurveAlgorithm []EllipticCurveAlgorithm +var builtinEllipticCurveAlgorithm = map[string]struct{}{} + +func init() { + // builtin values for EllipticCurveAlgorithm + algorithms := make([]EllipticCurveAlgorithm, 7) + algorithms[0] = NewEllipticCurveAlgorithm("Ed25519") + algorithms[1] = NewEllipticCurveAlgorithm("Ed448") + algorithms[2] = NewEllipticCurveAlgorithm("P-256") + algorithms[3] = NewEllipticCurveAlgorithm("P-384") + algorithms[4] = NewEllipticCurveAlgorithm("P-521") + algorithms[5] = NewEllipticCurveAlgorithm("X25519") + algorithms[6] = NewEllipticCurveAlgorithm("X448") + + RegisterEllipticCurveAlgorithm(algorithms...) +} + +// Ed25519 returns an object representing Ed25519 algorithm for EdDSA operations. +func Ed25519() EllipticCurveAlgorithm { + return lookupBuiltinEllipticCurveAlgorithm("Ed25519") +} + +// Ed448 returns an object representing Ed448 algorithm for EdDSA operations. +func Ed448() EllipticCurveAlgorithm { + return lookupBuiltinEllipticCurveAlgorithm("Ed448") +} + +var invalidEllipticCurve = NewEllipticCurveAlgorithm("P-invalid") + +// InvalidEllipticCurve returns an object representing an invalid elliptic curve. +func InvalidEllipticCurve() EllipticCurveAlgorithm { + return invalidEllipticCurve +} + +// P256 returns an object representing P-256 algorithm for ECDSA operations. +func P256() EllipticCurveAlgorithm { + return lookupBuiltinEllipticCurveAlgorithm("P-256") +} + +// P384 returns an object representing P-384 algorithm for ECDSA operations. +func P384() EllipticCurveAlgorithm { + return lookupBuiltinEllipticCurveAlgorithm("P-384") +} + +// P521 returns an object representing P-521 algorithm for ECDSA operations. +func P521() EllipticCurveAlgorithm { + return lookupBuiltinEllipticCurveAlgorithm("P-521") +} + +// X25519 returns an object representing X25519 algorithm for ECDH operations. +func X25519() EllipticCurveAlgorithm { + return lookupBuiltinEllipticCurveAlgorithm("X25519") +} + +// X448 returns an object representing X448 algorithm for ECDH operations. +func X448() EllipticCurveAlgorithm { + return lookupBuiltinEllipticCurveAlgorithm("X448") +} + +func lookupBuiltinEllipticCurveAlgorithm(name string) EllipticCurveAlgorithm { + muAllEllipticCurveAlgorithm.RLock() + v, ok := allEllipticCurveAlgorithm[name] + muAllEllipticCurveAlgorithm.RUnlock() + if !ok { + panic(fmt.Sprintf(`jwa: EllipticCurveAlgorithm %q not registered`, name)) + } + return v +} + +// EllipticCurveAlgorithm represents the algorithms used for EC keys +type EllipticCurveAlgorithm struct { + name string + deprecated bool +} + +func (s EllipticCurveAlgorithm) String() string { + return s.name +} + +// IsDeprecated returns true if the EllipticCurveAlgorithm object is deprecated. +func (s EllipticCurveAlgorithm) IsDeprecated() bool { + return s.deprecated +} + +// EmptyEllipticCurveAlgorithm returns an empty EllipticCurveAlgorithm object, used as a zero value. +func EmptyEllipticCurveAlgorithm() EllipticCurveAlgorithm { + return EllipticCurveAlgorithm{} +} + +// NewEllipticCurveAlgorithm creates a new EllipticCurveAlgorithm object with the given name. +func NewEllipticCurveAlgorithm(name string, options ...NewAlgorithmOption) EllipticCurveAlgorithm { + var deprecated bool + for _, option := range options { + switch option.Ident() { + case identDeprecated{}: + if err := option.Value(&deprecated); err != nil { + panic("jwa.NewEllipticCurveAlgorithm: WithDeprecated option must be a boolean") + } + } + } + return EllipticCurveAlgorithm{name: name, deprecated: deprecated} +} + +// LookupEllipticCurveAlgorithm returns the EllipticCurveAlgorithm object for the given name. +func LookupEllipticCurveAlgorithm(name string) (EllipticCurveAlgorithm, bool) { + muAllEllipticCurveAlgorithm.RLock() + v, ok := allEllipticCurveAlgorithm[name] + muAllEllipticCurveAlgorithm.RUnlock() + return v, ok +} + +// RegisterEllipticCurveAlgorithm registers a new EllipticCurveAlgorithm. The signature value must be immutable +// and safe to be used by multiple goroutines, as it is going to be shared with all other users of this library. +func RegisterEllipticCurveAlgorithm(algorithms ...EllipticCurveAlgorithm) { + muAllEllipticCurveAlgorithm.Lock() + for _, alg := range algorithms { + allEllipticCurveAlgorithm[alg.String()] = alg + } + muAllEllipticCurveAlgorithm.Unlock() + rebuildEllipticCurveAlgorithm() +} + +// UnregisterEllipticCurveAlgorithm unregisters a EllipticCurveAlgorithm from its known database. +// Non-existent entries, as well as built-in algorithms will silently be ignored. +func UnregisterEllipticCurveAlgorithm(algorithms ...EllipticCurveAlgorithm) { + muAllEllipticCurveAlgorithm.Lock() + for _, alg := range algorithms { + if _, ok := builtinEllipticCurveAlgorithm[alg.String()]; ok { + continue + } + delete(allEllipticCurveAlgorithm, alg.String()) + } + muAllEllipticCurveAlgorithm.Unlock() + rebuildEllipticCurveAlgorithm() +} + +func rebuildEllipticCurveAlgorithm() { + list := make([]EllipticCurveAlgorithm, 0, len(allEllipticCurveAlgorithm)) + muAllEllipticCurveAlgorithm.RLock() + for _, v := range allEllipticCurveAlgorithm { + list = append(list, v) + } + muAllEllipticCurveAlgorithm.RUnlock() + sort.Slice(list, func(i, j int) bool { + return list[i].String() < list[j].String() + }) + muListEllipticCurveAlgorithm.Lock() + listEllipticCurveAlgorithm = list + muListEllipticCurveAlgorithm.Unlock() +} + +// EllipticCurveAlgorithms returns a list of all available values for EllipticCurveAlgorithm. +func EllipticCurveAlgorithms() []EllipticCurveAlgorithm { + muListEllipticCurveAlgorithm.RLock() + defer muListEllipticCurveAlgorithm.RUnlock() + return listEllipticCurveAlgorithm +} + +// MarshalJSON serializes the EllipticCurveAlgorithm object to a JSON string. +func (s EllipticCurveAlgorithm) MarshalJSON() ([]byte, error) { + return json.Marshal(s.String()) +} + +// UnmarshalJSON deserializes the JSON string to a EllipticCurveAlgorithm object. +func (s *EllipticCurveAlgorithm) UnmarshalJSON(data []byte) error { + var name string + if err := json.Unmarshal(data, &name); err != nil { + return fmt.Errorf(`failed to unmarshal EllipticCurveAlgorithm: %w`, err) + } + v, ok := LookupEllipticCurveAlgorithm(name) + if !ok { + return fmt.Errorf(`unknown EllipticCurveAlgorithm: %q`, name) + } + *s = v + return nil +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwa/jwa.go b/vendor/github.com/lestrrat-go/jwx/v3/jwa/jwa.go new file mode 100644 index 00000000000..29ac1dfe764 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwa/jwa.go @@ -0,0 +1,68 @@ +//go:generate ../tools/cmd/genjwa.sh + +// Package jwa defines the various algorithm described in https://tools.ietf.org/html/rfc7518 +package jwa + +import ( + "errors" + "fmt" +) + +// KeyAlgorithm is a workaround for jwk.Key being able to contain different +// types of algorithms in its `alg` field. +// +// Previously the storage for the `alg` field was represented as a string, +// but this caused some users to wonder why the field was not typed appropriately +// like other fields. +// +// Ideally we would like to keep track of Signature Algorithms and +// Key Encryption Algorithms separately, and force the APIs to +// type-check at compile time, but this allows users to pass a value from a +// jwk.Key directly +type KeyAlgorithm interface { + String() string + IsDeprecated() bool +} + +var errInvalidKeyAlgorithm = errors.New(`invalid key algorithm`) + +func ErrInvalidKeyAlgorithm() error { + return errInvalidKeyAlgorithm +} + +// KeyAlgorithmFrom takes either a string, `jwa.SignatureAlgorithm`, +// `jwa.KeyEncryptionAlgorithm`, or `jwa.ContentEncryptionAlgorithm`. +// and returns a `jwa.KeyAlgorithm`. +// +// If the value cannot be handled, it returns an `jwa.InvalidKeyAlgorithm` +// object instead of returning an error. This design choice was made to allow +// users to directly pass the return value to functions such as `jws.Sign()` +func KeyAlgorithmFrom(v any) (KeyAlgorithm, error) { + switch v := v.(type) { + case SignatureAlgorithm: + return v, nil + case KeyEncryptionAlgorithm: + return v, nil + case ContentEncryptionAlgorithm: + return v, nil + case string: + salg, ok := LookupSignatureAlgorithm(v) + if ok { + return salg, nil + } + + kalg, ok := LookupKeyEncryptionAlgorithm(v) + if ok { + return kalg, nil + } + + calg, ok := LookupContentEncryptionAlgorithm(v) + if ok { + return calg, nil + } + + return nil, fmt.Errorf(`invalid key value: %q: %w`, v, errInvalidKeyAlgorithm) + default: + return nil, fmt.Errorf(`invalid key type: %T: %w`, v, errInvalidKeyAlgorithm) + } +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwa/key_encryption_gen.go b/vendor/github.com/lestrrat-go/jwx/v3/jwa/key_encryption_gen.go new file mode 100644 index 00000000000..716c43cd047 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwa/key_encryption_gen.go @@ -0,0 +1,268 @@ +// Code generated by tools/cmd/genjwa/main.go. DO NOT EDIT. + +package jwa + +import ( + "encoding/json" + "fmt" + "sort" + "sync" + + "github.com/lestrrat-go/jwx/v3/internal/tokens" +) + +var muAllKeyEncryptionAlgorithm sync.RWMutex +var allKeyEncryptionAlgorithm = map[string]KeyEncryptionAlgorithm{} +var muListKeyEncryptionAlgorithm sync.RWMutex +var listKeyEncryptionAlgorithm []KeyEncryptionAlgorithm +var builtinKeyEncryptionAlgorithm = map[string]struct{}{} + +func init() { + // builtin values for KeyEncryptionAlgorithm + algorithms := make([]KeyEncryptionAlgorithm, 19) + algorithms[0] = NewKeyEncryptionAlgorithm(tokens.A128GCMKW, WithIsSymmetric(true)) + algorithms[1] = NewKeyEncryptionAlgorithm(tokens.A128KW, WithIsSymmetric(true)) + algorithms[2] = NewKeyEncryptionAlgorithm(tokens.A192GCMKW, WithIsSymmetric(true)) + algorithms[3] = NewKeyEncryptionAlgorithm(tokens.A192KW, WithIsSymmetric(true)) + algorithms[4] = NewKeyEncryptionAlgorithm(tokens.A256GCMKW, WithIsSymmetric(true)) + algorithms[5] = NewKeyEncryptionAlgorithm(tokens.A256KW, WithIsSymmetric(true)) + algorithms[6] = NewKeyEncryptionAlgorithm(tokens.DIRECT, WithIsSymmetric(true)) + algorithms[7] = NewKeyEncryptionAlgorithm(tokens.ECDH_ES) + algorithms[8] = NewKeyEncryptionAlgorithm(tokens.ECDH_ES_A128KW) + algorithms[9] = NewKeyEncryptionAlgorithm(tokens.ECDH_ES_A192KW) + algorithms[10] = NewKeyEncryptionAlgorithm(tokens.ECDH_ES_A256KW) + algorithms[11] = NewKeyEncryptionAlgorithm(tokens.PBES2_HS256_A128KW, WithIsSymmetric(true)) + algorithms[12] = NewKeyEncryptionAlgorithm(tokens.PBES2_HS384_A192KW, WithIsSymmetric(true)) + algorithms[13] = NewKeyEncryptionAlgorithm(tokens.PBES2_HS512_A256KW, WithIsSymmetric(true)) + algorithms[14] = NewKeyEncryptionAlgorithm(tokens.RSA1_5, WithDeprecated(true)) + algorithms[15] = NewKeyEncryptionAlgorithm(tokens.RSA_OAEP) + algorithms[16] = NewKeyEncryptionAlgorithm(tokens.RSA_OAEP_256) + algorithms[17] = NewKeyEncryptionAlgorithm(tokens.RSA_OAEP_384) + algorithms[18] = NewKeyEncryptionAlgorithm(tokens.RSA_OAEP_512) + + RegisterKeyEncryptionAlgorithm(algorithms...) +} + +// A128GCMKW returns an object representing AES-GCM key wrap (128) key encryption algorithm. +func A128GCMKW() KeyEncryptionAlgorithm { + return lookupBuiltinKeyEncryptionAlgorithm(tokens.A128GCMKW) +} + +// A128KW returns an object representing AES key wrap (128) key encryption algorithm. +func A128KW() KeyEncryptionAlgorithm { + return lookupBuiltinKeyEncryptionAlgorithm(tokens.A128KW) +} + +// A192GCMKW returns an object representing AES-GCM key wrap (192) key encryption algorithm. +func A192GCMKW() KeyEncryptionAlgorithm { + return lookupBuiltinKeyEncryptionAlgorithm(tokens.A192GCMKW) +} + +// A192KW returns an object representing AES key wrap (192) key encryption algorithm. +func A192KW() KeyEncryptionAlgorithm { + return lookupBuiltinKeyEncryptionAlgorithm(tokens.A192KW) +} + +// A256GCMKW returns an object representing AES-GCM key wrap (256) key encryption algorithm. +func A256GCMKW() KeyEncryptionAlgorithm { + return lookupBuiltinKeyEncryptionAlgorithm(tokens.A256GCMKW) +} + +// A256KW returns an object representing AES key wrap (256) key encryption algorithm. +func A256KW() KeyEncryptionAlgorithm { + return lookupBuiltinKeyEncryptionAlgorithm(tokens.A256KW) +} + +// DIRECT returns an object representing Direct key encryption algorithm. +func DIRECT() KeyEncryptionAlgorithm { + return lookupBuiltinKeyEncryptionAlgorithm(tokens.DIRECT) +} + +// ECDH_ES returns an object representing ECDH-ES key encryption algorithm. +func ECDH_ES() KeyEncryptionAlgorithm { + return lookupBuiltinKeyEncryptionAlgorithm(tokens.ECDH_ES) +} + +// ECDH_ES_A128KW returns an object representing ECDH-ES + AES key wrap (128) key encryption algorithm. +func ECDH_ES_A128KW() KeyEncryptionAlgorithm { + return lookupBuiltinKeyEncryptionAlgorithm(tokens.ECDH_ES_A128KW) +} + +// ECDH_ES_A192KW returns an object representing ECDH-ES + AES key wrap (192) key encryption algorithm. +func ECDH_ES_A192KW() KeyEncryptionAlgorithm { + return lookupBuiltinKeyEncryptionAlgorithm(tokens.ECDH_ES_A192KW) +} + +// ECDH_ES_A256KW returns an object representing ECDH-ES + AES key wrap (256) key encryption algorithm. +func ECDH_ES_A256KW() KeyEncryptionAlgorithm { + return lookupBuiltinKeyEncryptionAlgorithm(tokens.ECDH_ES_A256KW) +} + +// PBES2_HS256_A128KW returns an object representing PBES2 + HMAC-SHA256 + AES key wrap (128) key encryption algorithm. +func PBES2_HS256_A128KW() KeyEncryptionAlgorithm { + return lookupBuiltinKeyEncryptionAlgorithm(tokens.PBES2_HS256_A128KW) +} + +// PBES2_HS384_A192KW returns an object representing PBES2 + HMAC-SHA384 + AES key wrap (192) key encryption algorithm. +func PBES2_HS384_A192KW() KeyEncryptionAlgorithm { + return lookupBuiltinKeyEncryptionAlgorithm(tokens.PBES2_HS384_A192KW) +} + +// PBES2_HS512_A256KW returns an object representing PBES2 + HMAC-SHA512 + AES key wrap (256) key encryption algorithm. +func PBES2_HS512_A256KW() KeyEncryptionAlgorithm { + return lookupBuiltinKeyEncryptionAlgorithm(tokens.PBES2_HS512_A256KW) +} + +// RSA1_5 returns an object representing RSA-PKCS1v1.5 key encryption algorithm. +func RSA1_5() KeyEncryptionAlgorithm { + return lookupBuiltinKeyEncryptionAlgorithm(tokens.RSA1_5) +} + +// RSA_OAEP returns an object representing RSA-OAEP-SHA1 key encryption algorithm. +func RSA_OAEP() KeyEncryptionAlgorithm { + return lookupBuiltinKeyEncryptionAlgorithm(tokens.RSA_OAEP) +} + +// RSA_OAEP_256 returns an object representing RSA-OAEP-SHA256 key encryption algorithm. +func RSA_OAEP_256() KeyEncryptionAlgorithm { + return lookupBuiltinKeyEncryptionAlgorithm(tokens.RSA_OAEP_256) +} + +// RSA_OAEP_384 returns an object representing RSA-OAEP-SHA384 key encryption algorithm. +func RSA_OAEP_384() KeyEncryptionAlgorithm { + return lookupBuiltinKeyEncryptionAlgorithm(tokens.RSA_OAEP_384) +} + +// RSA_OAEP_512 returns an object representing RSA-OAEP-SHA512 key encryption algorithm. +func RSA_OAEP_512() KeyEncryptionAlgorithm { + return lookupBuiltinKeyEncryptionAlgorithm(tokens.RSA_OAEP_512) +} + +func lookupBuiltinKeyEncryptionAlgorithm(name string) KeyEncryptionAlgorithm { + muAllKeyEncryptionAlgorithm.RLock() + v, ok := allKeyEncryptionAlgorithm[name] + muAllKeyEncryptionAlgorithm.RUnlock() + if !ok { + panic(fmt.Sprintf(`jwa: KeyEncryptionAlgorithm %q not registered`, name)) + } + return v +} + +// KeyEncryptionAlgorithm represents the various encryption algorithms as described in https://tools.ietf.org/html/rfc7518#section-4.1 +type KeyEncryptionAlgorithm struct { + name string + deprecated bool + isSymmetric bool +} + +func (s KeyEncryptionAlgorithm) String() string { + return s.name +} + +// IsDeprecated returns true if the KeyEncryptionAlgorithm object is deprecated. +func (s KeyEncryptionAlgorithm) IsDeprecated() bool { + return s.deprecated +} + +// IsSymmetric returns true if the KeyEncryptionAlgorithm object is symmetric. Symmetric algorithms use the same key for both encryption and decryption. +func (s KeyEncryptionAlgorithm) IsSymmetric() bool { + return s.isSymmetric +} + +// EmptyKeyEncryptionAlgorithm returns an empty KeyEncryptionAlgorithm object, used as a zero value. +func EmptyKeyEncryptionAlgorithm() KeyEncryptionAlgorithm { + return KeyEncryptionAlgorithm{} +} + +// NewKeyEncryptionAlgorithm creates a new KeyEncryptionAlgorithm object with the given name. +func NewKeyEncryptionAlgorithm(name string, options ...NewKeyEncryptionAlgorithmOption) KeyEncryptionAlgorithm { + var deprecated bool + var isSymmetric bool + for _, option := range options { + switch option.Ident() { + case identIsSymmetric{}: + if err := option.Value(&isSymmetric); err != nil { + panic("jwa.NewKeyEncryptionAlgorithm: WithIsSymmetric option must be a boolean") + } + case identDeprecated{}: + if err := option.Value(&deprecated); err != nil { + panic("jwa.NewKeyEncryptionAlgorithm: WithDeprecated option must be a boolean") + } + } + } + return KeyEncryptionAlgorithm{name: name, deprecated: deprecated, isSymmetric: isSymmetric} +} + +// LookupKeyEncryptionAlgorithm returns the KeyEncryptionAlgorithm object for the given name. +func LookupKeyEncryptionAlgorithm(name string) (KeyEncryptionAlgorithm, bool) { + muAllKeyEncryptionAlgorithm.RLock() + v, ok := allKeyEncryptionAlgorithm[name] + muAllKeyEncryptionAlgorithm.RUnlock() + return v, ok +} + +// RegisterKeyEncryptionAlgorithm registers a new KeyEncryptionAlgorithm. The signature value must be immutable +// and safe to be used by multiple goroutines, as it is going to be shared with all other users of this library. +func RegisterKeyEncryptionAlgorithm(algorithms ...KeyEncryptionAlgorithm) { + muAllKeyEncryptionAlgorithm.Lock() + for _, alg := range algorithms { + allKeyEncryptionAlgorithm[alg.String()] = alg + } + muAllKeyEncryptionAlgorithm.Unlock() + rebuildKeyEncryptionAlgorithm() +} + +// UnregisterKeyEncryptionAlgorithm unregisters a KeyEncryptionAlgorithm from its known database. +// Non-existent entries, as well as built-in algorithms will silently be ignored. +func UnregisterKeyEncryptionAlgorithm(algorithms ...KeyEncryptionAlgorithm) { + muAllKeyEncryptionAlgorithm.Lock() + for _, alg := range algorithms { + if _, ok := builtinKeyEncryptionAlgorithm[alg.String()]; ok { + continue + } + delete(allKeyEncryptionAlgorithm, alg.String()) + } + muAllKeyEncryptionAlgorithm.Unlock() + rebuildKeyEncryptionAlgorithm() +} + +func rebuildKeyEncryptionAlgorithm() { + list := make([]KeyEncryptionAlgorithm, 0, len(allKeyEncryptionAlgorithm)) + muAllKeyEncryptionAlgorithm.RLock() + for _, v := range allKeyEncryptionAlgorithm { + list = append(list, v) + } + muAllKeyEncryptionAlgorithm.RUnlock() + sort.Slice(list, func(i, j int) bool { + return list[i].String() < list[j].String() + }) + muListKeyEncryptionAlgorithm.Lock() + listKeyEncryptionAlgorithm = list + muListKeyEncryptionAlgorithm.Unlock() +} + +// KeyEncryptionAlgorithms returns a list of all available values for KeyEncryptionAlgorithm. +func KeyEncryptionAlgorithms() []KeyEncryptionAlgorithm { + muListKeyEncryptionAlgorithm.RLock() + defer muListKeyEncryptionAlgorithm.RUnlock() + return listKeyEncryptionAlgorithm +} + +// MarshalJSON serializes the KeyEncryptionAlgorithm object to a JSON string. +func (s KeyEncryptionAlgorithm) MarshalJSON() ([]byte, error) { + return json.Marshal(s.String()) +} + +// UnmarshalJSON deserializes the JSON string to a KeyEncryptionAlgorithm object. +func (s *KeyEncryptionAlgorithm) UnmarshalJSON(data []byte) error { + var name string + if err := json.Unmarshal(data, &name); err != nil { + return fmt.Errorf(`failed to unmarshal KeyEncryptionAlgorithm: %w`, err) + } + v, ok := LookupKeyEncryptionAlgorithm(name) + if !ok { + return fmt.Errorf(`unknown KeyEncryptionAlgorithm: %q`, name) + } + *s = v + return nil +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwa/key_type_gen.go b/vendor/github.com/lestrrat-go/jwx/v3/jwa/key_type_gen.go new file mode 100644 index 00000000000..8bc5ebb5f0e --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwa/key_type_gen.go @@ -0,0 +1,172 @@ +// Code generated by tools/cmd/genjwa/main.go. DO NOT EDIT. + +package jwa + +import ( + "encoding/json" + "fmt" + "sort" + "sync" +) + +var muAllKeyType sync.RWMutex +var allKeyType = map[string]KeyType{} +var muListKeyType sync.RWMutex +var listKeyType []KeyType +var builtinKeyType = map[string]struct{}{} + +func init() { + // builtin values for KeyType + algorithms := make([]KeyType, 4) + algorithms[0] = NewKeyType("EC") + algorithms[1] = NewKeyType("OKP") + algorithms[2] = NewKeyType("oct") + algorithms[3] = NewKeyType("RSA") + + RegisterKeyType(algorithms...) +} + +// EC returns an object representing EC. Elliptic Curve +func EC() KeyType { + return lookupBuiltinKeyType("EC") +} + +var invalidKeyType = NewKeyType("") + +// InvalidKeyType returns an object representing invalid key type. Invalid KeyType +func InvalidKeyType() KeyType { + return invalidKeyType +} + +// OKP returns an object representing OKP. Octet string key pairs +func OKP() KeyType { + return lookupBuiltinKeyType("OKP") +} + +// OctetSeq returns an object representing oct. Octet sequence (used to represent symmetric keys) +func OctetSeq() KeyType { + return lookupBuiltinKeyType("oct") +} + +// RSA returns an object representing RSA. RSA +func RSA() KeyType { + return lookupBuiltinKeyType("RSA") +} + +func lookupBuiltinKeyType(name string) KeyType { + muAllKeyType.RLock() + v, ok := allKeyType[name] + muAllKeyType.RUnlock() + if !ok { + panic(fmt.Sprintf(`jwa: KeyType %q not registered`, name)) + } + return v +} + +// KeyType represents the key type ("kty") that are supported +type KeyType struct { + name string + deprecated bool +} + +func (s KeyType) String() string { + return s.name +} + +// IsDeprecated returns true if the KeyType object is deprecated. +func (s KeyType) IsDeprecated() bool { + return s.deprecated +} + +// EmptyKeyType returns an empty KeyType object, used as a zero value. +func EmptyKeyType() KeyType { + return KeyType{} +} + +// NewKeyType creates a new KeyType object with the given name. +func NewKeyType(name string, options ...NewAlgorithmOption) KeyType { + var deprecated bool + for _, option := range options { + switch option.Ident() { + case identDeprecated{}: + if err := option.Value(&deprecated); err != nil { + panic("jwa.NewKeyType: WithDeprecated option must be a boolean") + } + } + } + return KeyType{name: name, deprecated: deprecated} +} + +// LookupKeyType returns the KeyType object for the given name. +func LookupKeyType(name string) (KeyType, bool) { + muAllKeyType.RLock() + v, ok := allKeyType[name] + muAllKeyType.RUnlock() + return v, ok +} + +// RegisterKeyType registers a new KeyType. The signature value must be immutable +// and safe to be used by multiple goroutines, as it is going to be shared with all other users of this library. +func RegisterKeyType(algorithms ...KeyType) { + muAllKeyType.Lock() + for _, alg := range algorithms { + allKeyType[alg.String()] = alg + } + muAllKeyType.Unlock() + rebuildKeyType() +} + +// UnregisterKeyType unregisters a KeyType from its known database. +// Non-existent entries, as well as built-in algorithms will silently be ignored. +func UnregisterKeyType(algorithms ...KeyType) { + muAllKeyType.Lock() + for _, alg := range algorithms { + if _, ok := builtinKeyType[alg.String()]; ok { + continue + } + delete(allKeyType, alg.String()) + } + muAllKeyType.Unlock() + rebuildKeyType() +} + +func rebuildKeyType() { + list := make([]KeyType, 0, len(allKeyType)) + muAllKeyType.RLock() + for _, v := range allKeyType { + list = append(list, v) + } + muAllKeyType.RUnlock() + sort.Slice(list, func(i, j int) bool { + return list[i].String() < list[j].String() + }) + muListKeyType.Lock() + listKeyType = list + muListKeyType.Unlock() +} + +// KeyTypes returns a list of all available values for KeyType. +func KeyTypes() []KeyType { + muListKeyType.RLock() + defer muListKeyType.RUnlock() + return listKeyType +} + +// MarshalJSON serializes the KeyType object to a JSON string. +func (s KeyType) MarshalJSON() ([]byte, error) { + return json.Marshal(s.String()) +} + +// UnmarshalJSON deserializes the JSON string to a KeyType object. +func (s *KeyType) UnmarshalJSON(data []byte) error { + var name string + if err := json.Unmarshal(data, &name); err != nil { + return fmt.Errorf(`failed to unmarshal KeyType: %w`, err) + } + v, ok := LookupKeyType(name) + if !ok { + return fmt.Errorf(`unknown KeyType: %q`, name) + } + *s = v + return nil +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwa/options.yaml b/vendor/github.com/lestrrat-go/jwx/v3/jwa/options.yaml new file mode 100644 index 00000000000..dd498c680e2 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwa/options.yaml @@ -0,0 +1,41 @@ +package_name: jwa +output: jwa/options_gen.go +interfaces: + - name: NewAlgorithmOption + methods: + - newSignatureAlgorithmOption + - newKeyEncryptionAlgorithmOption + - newSignatureKeyEncryptionAlgorithmOption + comment: | + NewAlgorithmOption represents an option that can be passed to any of the constructor functions + - name: NewSignatureAlgorithmOption + methods: + - newSignatureAlgorithmOption + comment: | + NewSignatureAlgorithmOption represents an option that can be passed to the NewSignatureAlgorithm + - name: NewKeyEncryptionAlgorithmOption + methods: + - newKeyEncryptionAlgorithmOption + comment: | + NewKeyEncryptionAlgorithmOption represents an option that can be passed to the NewKeyEncryptionAlgorithm + - name: NewSignatureKeyEncryptionAlgorithmOption + comment: | + NewSignatureKeyEncryptionAlgorithmOption represents an option that can be passed to both + NewSignatureAlgorithm and NewKeyEncryptionAlgorithm + methods: + - newSignatureAlgorithmOption + - newKeyEncryptionAlgorithmOption +options: + - ident: IsSymmetric + interface: NewSignatureKeyEncryptionAlgorithmOption + argument_type: bool + comment: | + IsSymmetric specifies that the algorithm is symmetric + - ident: Deprecated + interface: NewAlgorithmOption + argument_type: bool + comment: | + WithDeprecated specifies that the algorithm is deprecated. In order to + un-deprecate an algorithm, you will have to create a new algorithm + with the same values but with the Deprecated option set to false, and + then call RegisterXXXXAlgorithm with the new algorithm. \ No newline at end of file diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwa/options_gen.go b/vendor/github.com/lestrrat-go/jwx/v3/jwa/options_gen.go new file mode 100644 index 00000000000..9394ac587ac --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwa/options_gen.go @@ -0,0 +1,91 @@ +// Code generated by tools/cmd/genoptions/main.go. DO NOT EDIT. + +package jwa + +import ( + "github.com/lestrrat-go/option/v2" +) + +type Option = option.Interface + +// NewAlgorithmOption represents an option that can be passed to any of the constructor functions +type NewAlgorithmOption interface { + Option + newSignatureAlgorithmOption() + newKeyEncryptionAlgorithmOption() + newSignatureKeyEncryptionAlgorithmOption() +} + +type newAlgorithmOption struct { + Option +} + +func (*newAlgorithmOption) newSignatureAlgorithmOption() {} + +func (*newAlgorithmOption) newKeyEncryptionAlgorithmOption() {} + +func (*newAlgorithmOption) newSignatureKeyEncryptionAlgorithmOption() {} + +// NewKeyEncryptionAlgorithmOption represents an option that can be passed to the NewKeyEncryptionAlgorithm +type NewKeyEncryptionAlgorithmOption interface { + Option + newKeyEncryptionAlgorithmOption() +} + +type newKeyEncryptionAlgorithmOption struct { + Option +} + +func (*newKeyEncryptionAlgorithmOption) newKeyEncryptionAlgorithmOption() {} + +// NewSignatureAlgorithmOption represents an option that can be passed to the NewSignatureAlgorithm +type NewSignatureAlgorithmOption interface { + Option + newSignatureAlgorithmOption() +} + +type newSignatureAlgorithmOption struct { + Option +} + +func (*newSignatureAlgorithmOption) newSignatureAlgorithmOption() {} + +// NewSignatureKeyEncryptionAlgorithmOption represents an option that can be passed to both +// NewSignatureAlgorithm and NewKeyEncryptionAlgorithm +type NewSignatureKeyEncryptionAlgorithmOption interface { + Option + newSignatureAlgorithmOption() + newKeyEncryptionAlgorithmOption() +} + +type newSignatureKeyEncryptionAlgorithmOption struct { + Option +} + +func (*newSignatureKeyEncryptionAlgorithmOption) newSignatureAlgorithmOption() {} + +func (*newSignatureKeyEncryptionAlgorithmOption) newKeyEncryptionAlgorithmOption() {} + +type identDeprecated struct{} +type identIsSymmetric struct{} + +func (identDeprecated) String() string { + return "WithDeprecated" +} + +func (identIsSymmetric) String() string { + return "WithIsSymmetric" +} + +// WithDeprecated specifies that the algorithm is deprecated. In order to +// un-deprecate an algorithm, you will have to create a new algorithm +// with the same values but with the Deprecated option set to false, and +// then call RegisterXXXXAlgorithm with the new algorithm. +func WithDeprecated(v bool) NewAlgorithmOption { + return &newAlgorithmOption{option.New(identDeprecated{}, v)} +} + +// IsSymmetric specifies that the algorithm is symmetric +func WithIsSymmetric(v bool) NewSignatureKeyEncryptionAlgorithmOption { + return &newSignatureKeyEncryptionAlgorithmOption{option.New(identIsSymmetric{}, v)} +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwa/secp2561k.go b/vendor/github.com/lestrrat-go/jwx/v3/jwa/secp2561k.go new file mode 100644 index 00000000000..e7a6be754dd --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwa/secp2561k.go @@ -0,0 +1,15 @@ +//go:build jwx_es256k +// +build jwx_es256k + +package jwa + +var secp256k1Algorithm = NewEllipticCurveAlgorithm("secp256k1") + +// This constant is only available if compiled with jwx_es256k build tag +func Secp256k1() EllipticCurveAlgorithm { + return secp256k1Algorithm +} + +func init() { + RegisterEllipticCurveAlgorithm(secp256k1Algorithm) +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwa/signature_gen.go b/vendor/github.com/lestrrat-go/jwx/v3/jwa/signature_gen.go new file mode 100644 index 00000000000..653d7d56af4 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwa/signature_gen.go @@ -0,0 +1,242 @@ +// Code generated by tools/cmd/genjwa/main.go. DO NOT EDIT. + +package jwa + +import ( + "encoding/json" + "fmt" + "sort" + "sync" +) + +var muAllSignatureAlgorithm sync.RWMutex +var allSignatureAlgorithm = map[string]SignatureAlgorithm{} +var muListSignatureAlgorithm sync.RWMutex +var listSignatureAlgorithm []SignatureAlgorithm +var builtinSignatureAlgorithm = map[string]struct{}{} + +func init() { + // builtin values for SignatureAlgorithm + algorithms := make([]SignatureAlgorithm, 15) + algorithms[0] = NewSignatureAlgorithm("ES256") + algorithms[1] = NewSignatureAlgorithm("ES256K") + algorithms[2] = NewSignatureAlgorithm("ES384") + algorithms[3] = NewSignatureAlgorithm("ES512") + algorithms[4] = NewSignatureAlgorithm("EdDSA") + algorithms[5] = NewSignatureAlgorithm("HS256", WithIsSymmetric(true)) + algorithms[6] = NewSignatureAlgorithm("HS384", WithIsSymmetric(true)) + algorithms[7] = NewSignatureAlgorithm("HS512", WithIsSymmetric(true)) + algorithms[8] = NewSignatureAlgorithm("none") + algorithms[9] = NewSignatureAlgorithm("PS256") + algorithms[10] = NewSignatureAlgorithm("PS384") + algorithms[11] = NewSignatureAlgorithm("PS512") + algorithms[12] = NewSignatureAlgorithm("RS256") + algorithms[13] = NewSignatureAlgorithm("RS384") + algorithms[14] = NewSignatureAlgorithm("RS512") + + RegisterSignatureAlgorithm(algorithms...) +} + +// ES256 returns an object representing ECDSA signature algorithm using P-256 curve and SHA-256. +func ES256() SignatureAlgorithm { + return lookupBuiltinSignatureAlgorithm("ES256") +} + +// ES256K returns an object representing ECDSA signature algorithm using secp256k1 curve and SHA-256. +func ES256K() SignatureAlgorithm { + return lookupBuiltinSignatureAlgorithm("ES256K") +} + +// ES384 returns an object representing ECDSA signature algorithm using P-384 curve and SHA-384. +func ES384() SignatureAlgorithm { + return lookupBuiltinSignatureAlgorithm("ES384") +} + +// ES512 returns an object representing ECDSA signature algorithm using P-521 curve and SHA-512. +func ES512() SignatureAlgorithm { + return lookupBuiltinSignatureAlgorithm("ES512") +} + +// EdDSA returns an object representing EdDSA signature algorithms. +func EdDSA() SignatureAlgorithm { + return lookupBuiltinSignatureAlgorithm("EdDSA") +} + +// HS256 returns an object representing HMAC signature algorithm using SHA-256. +func HS256() SignatureAlgorithm { + return lookupBuiltinSignatureAlgorithm("HS256") +} + +// HS384 returns an object representing HMAC signature algorithm using SHA-384. +func HS384() SignatureAlgorithm { + return lookupBuiltinSignatureAlgorithm("HS384") +} + +// HS512 returns an object representing HMAC signature algorithm using SHA-512. +func HS512() SignatureAlgorithm { + return lookupBuiltinSignatureAlgorithm("HS512") +} + +// NoSignature returns an object representing the lack of a signature algorithm. Using this value specifies that the content should not be signed, which you should avoid doing. +func NoSignature() SignatureAlgorithm { + return lookupBuiltinSignatureAlgorithm("none") +} + +// PS256 returns an object representing RSASSA-PSS signature algorithm using SHA-256 and MGF1-SHA256. +func PS256() SignatureAlgorithm { + return lookupBuiltinSignatureAlgorithm("PS256") +} + +// PS384 returns an object representing RSASSA-PSS signature algorithm using SHA-384 and MGF1-SHA384. +func PS384() SignatureAlgorithm { + return lookupBuiltinSignatureAlgorithm("PS384") +} + +// PS512 returns an object representing RSASSA-PSS signature algorithm using SHA-512 and MGF1-SHA512. +func PS512() SignatureAlgorithm { + return lookupBuiltinSignatureAlgorithm("PS512") +} + +// RS256 returns an object representing RSASSA-PKCS-v1.5 signature algorithm using SHA-256. +func RS256() SignatureAlgorithm { + return lookupBuiltinSignatureAlgorithm("RS256") +} + +// RS384 returns an object representing RSASSA-PKCS-v1.5 signature algorithm using SHA-384. +func RS384() SignatureAlgorithm { + return lookupBuiltinSignatureAlgorithm("RS384") +} + +// RS512 returns an object representing RSASSA-PKCS-v1.5 signature algorithm using SHA-512. +func RS512() SignatureAlgorithm { + return lookupBuiltinSignatureAlgorithm("RS512") +} + +func lookupBuiltinSignatureAlgorithm(name string) SignatureAlgorithm { + muAllSignatureAlgorithm.RLock() + v, ok := allSignatureAlgorithm[name] + muAllSignatureAlgorithm.RUnlock() + if !ok { + panic(fmt.Sprintf(`jwa: SignatureAlgorithm %q not registered`, name)) + } + return v +} + +// SignatureAlgorithm represents the various signature algorithms as described in https://tools.ietf.org/html/rfc7518#section-3.1 +type SignatureAlgorithm struct { + name string + deprecated bool + isSymmetric bool +} + +func (s SignatureAlgorithm) String() string { + return s.name +} + +// IsDeprecated returns true if the SignatureAlgorithm object is deprecated. +func (s SignatureAlgorithm) IsDeprecated() bool { + return s.deprecated +} + +// IsSymmetric returns true if the SignatureAlgorithm object is symmetric. Symmetric algorithms use the same key for both encryption and decryption. +func (s SignatureAlgorithm) IsSymmetric() bool { + return s.isSymmetric +} + +// EmptySignatureAlgorithm returns an empty SignatureAlgorithm object, used as a zero value. +func EmptySignatureAlgorithm() SignatureAlgorithm { + return SignatureAlgorithm{} +} + +// NewSignatureAlgorithm creates a new SignatureAlgorithm object with the given name. +func NewSignatureAlgorithm(name string, options ...NewSignatureAlgorithmOption) SignatureAlgorithm { + var deprecated bool + var isSymmetric bool + for _, option := range options { + switch option.Ident() { + case identIsSymmetric{}: + if err := option.Value(&isSymmetric); err != nil { + panic("jwa.NewSignatureAlgorithm: WithIsSymmetric option must be a boolean") + } + case identDeprecated{}: + if err := option.Value(&deprecated); err != nil { + panic("jwa.NewSignatureAlgorithm: WithDeprecated option must be a boolean") + } + } + } + return SignatureAlgorithm{name: name, deprecated: deprecated, isSymmetric: isSymmetric} +} + +// LookupSignatureAlgorithm returns the SignatureAlgorithm object for the given name. +func LookupSignatureAlgorithm(name string) (SignatureAlgorithm, bool) { + muAllSignatureAlgorithm.RLock() + v, ok := allSignatureAlgorithm[name] + muAllSignatureAlgorithm.RUnlock() + return v, ok +} + +// RegisterSignatureAlgorithm registers a new SignatureAlgorithm. The signature value must be immutable +// and safe to be used by multiple goroutines, as it is going to be shared with all other users of this library. +func RegisterSignatureAlgorithm(algorithms ...SignatureAlgorithm) { + muAllSignatureAlgorithm.Lock() + for _, alg := range algorithms { + allSignatureAlgorithm[alg.String()] = alg + } + muAllSignatureAlgorithm.Unlock() + rebuildSignatureAlgorithm() +} + +// UnregisterSignatureAlgorithm unregisters a SignatureAlgorithm from its known database. +// Non-existent entries, as well as built-in algorithms will silently be ignored. +func UnregisterSignatureAlgorithm(algorithms ...SignatureAlgorithm) { + muAllSignatureAlgorithm.Lock() + for _, alg := range algorithms { + if _, ok := builtinSignatureAlgorithm[alg.String()]; ok { + continue + } + delete(allSignatureAlgorithm, alg.String()) + } + muAllSignatureAlgorithm.Unlock() + rebuildSignatureAlgorithm() +} + +func rebuildSignatureAlgorithm() { + list := make([]SignatureAlgorithm, 0, len(allSignatureAlgorithm)) + muAllSignatureAlgorithm.RLock() + for _, v := range allSignatureAlgorithm { + list = append(list, v) + } + muAllSignatureAlgorithm.RUnlock() + sort.Slice(list, func(i, j int) bool { + return list[i].String() < list[j].String() + }) + muListSignatureAlgorithm.Lock() + listSignatureAlgorithm = list + muListSignatureAlgorithm.Unlock() +} + +// SignatureAlgorithms returns a list of all available values for SignatureAlgorithm. +func SignatureAlgorithms() []SignatureAlgorithm { + muListSignatureAlgorithm.RLock() + defer muListSignatureAlgorithm.RUnlock() + return listSignatureAlgorithm +} + +// MarshalJSON serializes the SignatureAlgorithm object to a JSON string. +func (s SignatureAlgorithm) MarshalJSON() ([]byte, error) { + return json.Marshal(s.String()) +} + +// UnmarshalJSON deserializes the JSON string to a SignatureAlgorithm object. +func (s *SignatureAlgorithm) UnmarshalJSON(data []byte) error { + var name string + if err := json.Unmarshal(data, &name); err != nil { + return fmt.Errorf(`failed to unmarshal SignatureAlgorithm: %w`, err) + } + v, ok := LookupSignatureAlgorithm(name) + if !ok { + return fmt.Errorf(`unknown SignatureAlgorithm: %q`, name) + } + *s = v + return nil +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwe/BUILD.bazel b/vendor/github.com/lestrrat-go/jwx/v3/jwe/BUILD.bazel new file mode 100644 index 00000000000..0719efd2dc9 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwe/BUILD.bazel @@ -0,0 +1,70 @@ +load("@rules_go//go:def.bzl", "go_library", "go_test") + +go_library( + name = "jwe", + srcs = [ + "compress.go", + "decrypt.go", + "encrypt.go", + "errors.go", + "filter.go", + "headers.go", + "headers_gen.go", + "interface.go", + "io.go", + "jwe.go", + "key_provider.go", + "message.go", + "options.go", + "options_gen.go", + ], + importpath = "github.com/lestrrat-go/jwx/v3/jwe", + visibility = ["//visibility:public"], + deps = [ + "//cert", + "//internal/base64", + "//transform", + "//internal/json", + "//internal/tokens", + "//internal/keyconv", + "//internal/pool", + "//jwa", + "//jwe/internal/aescbc", + "//jwe/internal/cipher", + "//jwe/internal/content_crypt", + "//jwe/internal/keygen", + "//jwe/jwebb", + "//jwk", + "@com_github_lestrrat_go_blackmagic//:blackmagic", + "@com_github_lestrrat_go_option_v2//:option", + "@org_golang_x_crypto//pbkdf2", + ], +) + +go_test( + name = "jwe_test", + srcs = [ + "filter_test.go", + "gh402_test.go", + "headers_test.go", + "jwe_test.go", + "message_test.go", + "options_gen_test.go", + "speed_test.go", + ], + embed = [":jwe"], + deps = [ + "//cert", + "//internal/json", + "//internal/jwxtest", + "//jwa", + "//jwk", + "@com_github_stretchr_testify//require", + ], +) + +alias( + name = "go_default_library", + actual = ":jwe", + visibility = ["//visibility:public"], +) diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwe/README.md b/vendor/github.com/lestrrat-go/jwx/v3/jwe/README.md new file mode 100644 index 00000000000..c85d05bbbe4 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwe/README.md @@ -0,0 +1,94 @@ +# JWE [![Go Reference](https://pkg.go.dev/badge/github.com/lestrrat-go/jwx/v3/jwe.svg)](https://pkg.go.dev/github.com/lestrrat-go/jwx/v3/jwe) + +Package jwe implements JWE as described in [RFC7516](https://tools.ietf.org/html/rfc7516) + +* Encrypt and Decrypt arbitrary data +* Content compression and decompression +* Add arbitrary fields in the JWE header object + +How-to style documentation can be found in the [docs directory](../docs). + +Examples are located in the examples directory ([jwe_example_test.go](../examples/jwe_example_test.go)) + +Supported key encryption algorithm: + +| Algorithm | Supported? | Constant in [jwa](../jwa) | +|:-----------------------------------------|:-----------|:-------------------------| +| RSA-PKCS1v1.5 | YES | jwa.RSA1_5 | +| RSA-OAEP-SHA1 | YES | jwa.RSA_OAEP | +| RSA-OAEP-SHA256 | YES | jwa.RSA_OAEP_256 | +| AES key wrap (128) | YES | jwa.A128KW | +| AES key wrap (192) | YES | jwa.A192KW | +| AES key wrap (256) | YES | jwa.A256KW | +| Direct encryption | YES (1) | jwa.DIRECT | +| ECDH-ES | YES (1) | jwa.ECDH_ES | +| ECDH-ES + AES key wrap (128) | YES | jwa.ECDH_ES_A128KW | +| ECDH-ES + AES key wrap (192) | YES | jwa.ECDH_ES_A192KW | +| ECDH-ES + AES key wrap (256) | YES | jwa.ECDH_ES_A256KW | +| AES-GCM key wrap (128) | YES | jwa.A128GCMKW | +| AES-GCM key wrap (192) | YES | jwa.A192GCMKW | +| AES-GCM key wrap (256) | YES | jwa.A256GCMKW | +| PBES2 + HMAC-SHA256 + AES key wrap (128) | YES | jwa.PBES2_HS256_A128KW | +| PBES2 + HMAC-SHA384 + AES key wrap (192) | YES | jwa.PBES2_HS384_A192KW | +| PBES2 + HMAC-SHA512 + AES key wrap (256) | YES | jwa.PBES2_HS512_A256KW | + +* Note 1: Single-recipient only + +Supported content encryption algorithm: + +| Algorithm | Supported? | Constant in [jwa](../jwa) | +|:----------------------------|:-----------|:--------------------------| +| AES-CBC + HMAC-SHA256 (128) | YES | jwa.A128CBC_HS256 | +| AES-CBC + HMAC-SHA384 (192) | YES | jwa.A192CBC_HS384 | +| AES-CBC + HMAC-SHA512 (256) | YES | jwa.A256CBC_HS512 | +| AES-GCM (128) | YES | jwa.A128GCM | +| AES-GCM (192) | YES | jwa.A192GCM | +| AES-GCM (256) | YES | jwa.A256GCM | + +# SYNOPSIS + +## Encrypt data + +```go +func ExampleEncrypt() { + privkey, err := rsa.GenerateKey(rand.Reader, 2048) + if err != nil { + log.Printf("failed to generate private key: %s", err) + return + } + + payload := []byte("Lorem Ipsum") + + encrypted, err := jwe.Encrypt(payload, jwe.WithKey(jwa.RSA1_5, &privkey.PublicKey), jwe.WithContentEncryption(jwa.A128CBC_HS256)) + if err != nil { + log.Printf("failed to encrypt payload: %s", err) + return + } + _ = encrypted + // OUTPUT: +} +``` + +## Decrypt data + +```go +func ExampleDecrypt() { + privkey, encrypted, err := exampleGenPayload() + if err != nil { + log.Printf("failed to generate encrypted payload: %s", err) + return + } + + decrypted, err := jwe.Decrypt(encrypted, jwe.WithKey(jwa.RSA1_5, privkey)) + if err != nil { + log.Printf("failed to decrypt: %s", err) + return + } + + if string(decrypted) != "Lorem Ipsum" { + log.Printf("WHAT?!") + return + } + // OUTPUT: +} +``` diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwe/compress.go b/vendor/github.com/lestrrat-go/jwx/v3/jwe/compress.go new file mode 100644 index 00000000000..a1ed158fb04 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwe/compress.go @@ -0,0 +1,62 @@ +package jwe + +import ( + "bytes" + "compress/flate" + "fmt" + "io" + + "github.com/lestrrat-go/jwx/v3/internal/pool" +) + +func uncompress(src []byte, maxBufferSize int64) ([]byte, error) { + var dst bytes.Buffer + r := flate.NewReader(bytes.NewReader(src)) + defer r.Close() + var buf [16384]byte + var sofar int64 + for { + n, readErr := r.Read(buf[:]) + sofar += int64(n) + if sofar > maxBufferSize { + return nil, fmt.Errorf(`compressed payload exceeds maximum allowed size`) + } + if readErr != nil { + // if we have a read error, and it's not EOF, then we need to stop + if readErr != io.EOF { + return nil, fmt.Errorf(`failed to read inflated data: %w`, readErr) + } + } + + if _, err := dst.Write(buf[:n]); err != nil { + return nil, fmt.Errorf(`failed to write inflated data: %w`, err) + } + + if readErr != nil { + // if it got here, then readErr == io.EOF, we're done + return dst.Bytes(), nil + } + } +} + +func compress(plaintext []byte) ([]byte, error) { + buf := pool.BytesBuffer().Get() + defer pool.BytesBuffer().Put(buf) + + w, _ := flate.NewWriter(buf, 1) + in := plaintext + for len(in) > 0 { + n, err := w.Write(in) + if err != nil { + return nil, fmt.Errorf(`failed to write to compression writer: %w`, err) + } + in = in[n:] + } + if err := w.Close(); err != nil { + return nil, fmt.Errorf(`failed to close compression writer: %w`, err) + } + + ret := make([]byte, buf.Len()) + copy(ret, buf.Bytes()) + return ret, nil +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwe/decrypt.go b/vendor/github.com/lestrrat-go/jwx/v3/jwe/decrypt.go new file mode 100644 index 00000000000..9429d84b1b2 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwe/decrypt.go @@ -0,0 +1,227 @@ +package jwe + +import ( + "fmt" + + "github.com/lestrrat-go/jwx/v3/internal/tokens" + "github.com/lestrrat-go/jwx/v3/jwa" + "github.com/lestrrat-go/jwx/v3/jwe/internal/content_crypt" + "github.com/lestrrat-go/jwx/v3/jwe/jwebb" +) + +// decrypter is responsible for taking various components to decrypt a message. +// its operation is not concurrency safe. You must provide locking yourself +// +//nolint:govet +type decrypter struct { + aad []byte + apu []byte + apv []byte + cek *[]byte + computedAad []byte + iv []byte + keyiv []byte + keysalt []byte + keytag []byte + tag []byte + privkey any + pubkey any + ctalg jwa.ContentEncryptionAlgorithm + keyalg jwa.KeyEncryptionAlgorithm + cipher content_crypt.Cipher + keycount int +} + +// newDecrypter Creates a new Decrypter instance. You must supply the +// rest of parameters via their respective setter methods before +// calling Decrypt(). +// +// privkey must be a private key in its "raw" format (i.e. something like +// *rsa.PrivateKey, instead of jwk.Key) +// +// You should consider this object immutable once you assign values to it. +func newDecrypter(keyalg jwa.KeyEncryptionAlgorithm, ctalg jwa.ContentEncryptionAlgorithm, privkey any) *decrypter { + return &decrypter{ + ctalg: ctalg, + keyalg: keyalg, + privkey: privkey, + } +} + +func (d *decrypter) AgreementPartyUInfo(apu []byte) *decrypter { + d.apu = apu + return d +} + +func (d *decrypter) AgreementPartyVInfo(apv []byte) *decrypter { + d.apv = apv + return d +} + +func (d *decrypter) AuthenticatedData(aad []byte) *decrypter { + d.aad = aad + return d +} + +func (d *decrypter) ComputedAuthenticatedData(aad []byte) *decrypter { + d.computedAad = aad + return d +} + +func (d *decrypter) ContentEncryptionAlgorithm(ctalg jwa.ContentEncryptionAlgorithm) *decrypter { + d.ctalg = ctalg + return d +} + +func (d *decrypter) InitializationVector(iv []byte) *decrypter { + d.iv = iv + return d +} + +func (d *decrypter) KeyCount(keycount int) *decrypter { + d.keycount = keycount + return d +} + +func (d *decrypter) KeyInitializationVector(keyiv []byte) *decrypter { + d.keyiv = keyiv + return d +} + +func (d *decrypter) KeySalt(keysalt []byte) *decrypter { + d.keysalt = keysalt + return d +} + +func (d *decrypter) KeyTag(keytag []byte) *decrypter { + d.keytag = keytag + return d +} + +// PublicKey sets the public key to be used in decoding EC based encryptions. +// The key must be in its "raw" format (i.e. *ecdsa.PublicKey, instead of jwk.Key) +func (d *decrypter) PublicKey(pubkey any) *decrypter { + d.pubkey = pubkey + return d +} + +func (d *decrypter) Tag(tag []byte) *decrypter { + d.tag = tag + return d +} + +func (d *decrypter) CEK(ptr *[]byte) *decrypter { + d.cek = ptr + return d +} + +func (d *decrypter) ContentCipher() (content_crypt.Cipher, error) { + if d.cipher == nil { + cipher, err := jwebb.CreateContentCipher(d.ctalg.String()) + if err != nil { + return nil, err + } + d.cipher = cipher + } + + return d.cipher, nil +} + +func (d *decrypter) Decrypt(recipient Recipient, ciphertext []byte, msg *Message) (plaintext []byte, err error) { + cek, keyerr := d.DecryptKey(recipient, msg) + if keyerr != nil { + err = fmt.Errorf(`failed to decrypt key: %w`, keyerr) + return + } + + cipher, ciphererr := d.ContentCipher() + if ciphererr != nil { + err = fmt.Errorf(`failed to fetch content crypt cipher: %w`, ciphererr) + return + } + + computedAad := d.computedAad + if d.aad != nil { + computedAad = append(append(computedAad, tokens.Period), d.aad...) + } + + plaintext, err = cipher.Decrypt(cek, d.iv, ciphertext, d.tag, computedAad) + if err != nil { + err = fmt.Errorf(`failed to decrypt payload: %w`, err) + return + } + + if d.cek != nil { + *d.cek = cek + } + return plaintext, nil +} + +func (d *decrypter) DecryptKey(recipient Recipient, msg *Message) (cek []byte, err error) { + recipientKey := recipient.EncryptedKey() + if kd, ok := d.privkey.(KeyDecrypter); ok { + return kd.DecryptKey(d.keyalg, recipientKey, recipient, msg) + } + + if jwebb.IsDirect(d.keyalg.String()) { + cek, ok := d.privkey.([]byte) + if !ok { + return nil, fmt.Errorf("decrypt key: []byte is required as the key for %s (got %T)", d.keyalg, d.privkey) + } + return jwebb.KeyDecryptDirect(recipientKey, recipientKey, d.keyalg.String(), cek) + } + + if jwebb.IsPBES2(d.keyalg.String()) { + password, ok := d.privkey.([]byte) + if !ok { + return nil, fmt.Errorf("decrypt key: []byte is required as the password for %s (got %T)", d.keyalg, d.privkey) + } + salt := []byte(d.keyalg.String()) + salt = append(salt, byte(0)) + salt = append(salt, d.keysalt...) + return jwebb.KeyDecryptPBES2(recipientKey, recipientKey, d.keyalg.String(), password, salt, d.keycount) + } + + if jwebb.IsAESGCMKW(d.keyalg.String()) { + sharedkey, ok := d.privkey.([]byte) + if !ok { + return nil, fmt.Errorf("decrypt key: []byte is required as the key for %s (got %T)", d.keyalg, d.privkey) + } + return jwebb.KeyDecryptAESGCMKW(recipientKey, recipientKey, d.keyalg.String(), sharedkey, d.keyiv, d.keytag) + } + + if jwebb.IsECDHES(d.keyalg.String()) { + alg, keysize, keywrap, err := jwebb.KeyEncryptionECDHESKeySize(d.keyalg.String(), d.ctalg.String()) + if err != nil { + return nil, fmt.Errorf(`failed to determine ECDH-ES key size: %w`, err) + } + + if !keywrap { + return jwebb.KeyDecryptECDHES(recipientKey, cek, alg, d.apu, d.apv, d.privkey, d.pubkey, keysize) + } + return jwebb.KeyDecryptECDHESKeyWrap(recipientKey, recipientKey, d.keyalg.String(), d.apu, d.apv, d.privkey, d.pubkey, keysize) + } + + if jwebb.IsRSA15(d.keyalg.String()) { + cipher, err := d.ContentCipher() + if err != nil { + return nil, fmt.Errorf(`failed to fetch content crypt cipher: %w`, err) + } + keysize := cipher.KeySize() / 2 + return jwebb.KeyDecryptRSA15(recipientKey, recipientKey, d.privkey, keysize) + } + + if jwebb.IsRSAOAEP(d.keyalg.String()) { + return jwebb.KeyDecryptRSAOAEP(recipientKey, recipientKey, d.keyalg.String(), d.privkey) + } + + if jwebb.IsAESKW(d.keyalg.String()) { + sharedkey, ok := d.privkey.([]byte) + if !ok { + return nil, fmt.Errorf("[]byte is required as the key to decrypt %s", d.keyalg.String()) + } + return jwebb.KeyDecryptAESKW(recipientKey, recipientKey, d.keyalg.String(), sharedkey) + } + + return nil, fmt.Errorf(`unsupported algorithm for key decryption (%s)`, d.keyalg) +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwe/encrypt.go b/vendor/github.com/lestrrat-go/jwx/v3/jwe/encrypt.go new file mode 100644 index 00000000000..e75f342a3d8 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwe/encrypt.go @@ -0,0 +1,193 @@ +package jwe + +import ( + "crypto/ecdh" + "crypto/ecdsa" + "crypto/rsa" + "fmt" + + "github.com/lestrrat-go/jwx/v3/internal/keyconv" + "github.com/lestrrat-go/jwx/v3/jwa" + "github.com/lestrrat-go/jwx/v3/jwe/internal/content_crypt" + "github.com/lestrrat-go/jwx/v3/jwe/internal/keygen" + "github.com/lestrrat-go/jwx/v3/jwe/jwebb" +) + +// encrypter is responsible for taking various components to encrypt a key. +// its operation is not concurrency safe. You must provide locking yourself +// +//nolint:govet +type encrypter struct { + apu []byte + apv []byte + ctalg jwa.ContentEncryptionAlgorithm + keyalg jwa.KeyEncryptionAlgorithm + pubkey any + rawKey any + cipher content_crypt.Cipher +} + +// newEncrypter creates a new Encrypter instance with all required parameters. +// The content cipher is built internally during construction. +// +// pubkey must be a public key in its "raw" format (i.e. something like +// *rsa.PublicKey, instead of jwk.Key) +// +// You should consider this object immutable once created. +func newEncrypter(keyalg jwa.KeyEncryptionAlgorithm, ctalg jwa.ContentEncryptionAlgorithm, pubkey any, rawKey any, apu, apv []byte) (*encrypter, error) { + cipher, err := jwebb.CreateContentCipher(ctalg.String()) + if err != nil { + return nil, fmt.Errorf(`failed to create content cipher: %w`, err) + } + + return &encrypter{ + apu: apu, + apv: apv, + ctalg: ctalg, + keyalg: keyalg, + pubkey: pubkey, + rawKey: rawKey, + cipher: cipher, + }, nil +} + +func (e *encrypter) EncryptKey(cek []byte) (keygen.ByteSource, error) { + if ke, ok := e.pubkey.(KeyEncrypter); ok { + encrypted, err := ke.EncryptKey(cek) + if err != nil { + return nil, err + } + return keygen.ByteKey(encrypted), nil + } + + if jwebb.IsDirect(e.keyalg.String()) { + sharedkey, ok := e.rawKey.([]byte) + if !ok { + return nil, fmt.Errorf("encrypt key: []byte is required as the key for %s (got %T)", e.keyalg, e.rawKey) + } + return jwebb.KeyEncryptDirect(cek, e.keyalg.String(), sharedkey) + } + + if jwebb.IsPBES2(e.keyalg.String()) { + password, ok := e.rawKey.([]byte) + if !ok { + return nil, fmt.Errorf("encrypt key: []byte is required as the password for %s (got %T)", e.keyalg, e.rawKey) + } + return jwebb.KeyEncryptPBES2(cek, e.keyalg.String(), password) + } + + if jwebb.IsAESGCMKW(e.keyalg.String()) { + sharedkey, ok := e.rawKey.([]byte) + if !ok { + return nil, fmt.Errorf("encrypt key: []byte is required as the key for %s (got %T)", e.keyalg, e.rawKey) + } + return jwebb.KeyEncryptAESGCMKW(cek, e.keyalg.String(), sharedkey) + } + + if jwebb.IsECDHES(e.keyalg.String()) { + _, keysize, keywrap, err := jwebb.KeyEncryptionECDHESKeySize(e.keyalg.String(), e.ctalg.String()) + if err != nil { + return nil, fmt.Errorf(`failed to determine ECDH-ES key size: %w`, err) + } + + // Use rawKey for ECDH-ES operations - it should contain the actual key material + keyToUse := e.rawKey + if keyToUse == nil { + keyToUse = e.pubkey + } + + switch key := keyToUse.(type) { + case *ecdsa.PublicKey: + // no op + case ecdsa.PublicKey: + keyToUse = &key + case *ecdsa.PrivateKey: + keyToUse = &key.PublicKey + case ecdsa.PrivateKey: + keyToUse = &key.PublicKey + case *ecdh.PublicKey: + // no op + case ecdh.PublicKey: + keyToUse = &key + case ecdh.PrivateKey: + keyToUse = key.PublicKey() + case *ecdh.PrivateKey: + keyToUse = key.PublicKey() + } + + // Determine key type and call appropriate function + switch key := keyToUse.(type) { + case *ecdh.PublicKey: + if key.Curve() == ecdh.X25519() { + if !keywrap { + return jwebb.KeyEncryptECDHESX25519(cek, e.keyalg.String(), e.apu, e.apv, key, keysize, e.ctalg.String()) + } + return jwebb.KeyEncryptECDHESKeyWrapX25519(cek, e.keyalg.String(), e.apu, e.apv, key, keysize, e.ctalg.String()) + } + + var ecdsaKey *ecdsa.PublicKey + if err := keyconv.ECDHToECDSA(&ecdsaKey, key); err != nil { + return nil, fmt.Errorf(`encrypt: failed to convert ECDH public key to ECDSA: %w`, err) + } + keyToUse = ecdsaKey + } + + switch key := keyToUse.(type) { + case *ecdsa.PublicKey: + if !keywrap { + return jwebb.KeyEncryptECDHESECDSA(cek, e.keyalg.String(), e.apu, e.apv, key, keysize, e.ctalg.String()) + } + return jwebb.KeyEncryptECDHESKeyWrapECDSA(cek, e.keyalg.String(), e.apu, e.apv, key, keysize, e.ctalg.String()) + default: + return nil, fmt.Errorf(`encrypt: unsupported key type for ECDH-ES: %T`, keyToUse) + } + } + + if jwebb.IsRSA15(e.keyalg.String()) { + keyToUse := e.rawKey + if keyToUse == nil { + keyToUse = e.pubkey + } + + // Handle rsa.PublicKey by value - convert to pointer + if pk, ok := keyToUse.(rsa.PublicKey); ok { + keyToUse = &pk + } + + var pubkey *rsa.PublicKey + if err := keyconv.RSAPublicKey(&pubkey, keyToUse); err != nil { + return nil, fmt.Errorf(`encrypt: failed to convert to RSA public key: %w`, err) + } + + return jwebb.KeyEncryptRSA15(cek, e.keyalg.String(), pubkey) + } + + if jwebb.IsRSAOAEP(e.keyalg.String()) { + keyToUse := e.rawKey + if keyToUse == nil { + keyToUse = e.pubkey + } + + // Handle rsa.PublicKey by value - convert to pointer + if pk, ok := keyToUse.(rsa.PublicKey); ok { + keyToUse = &pk + } + + var pubkey *rsa.PublicKey + if err := keyconv.RSAPublicKey(&pubkey, keyToUse); err != nil { + return nil, fmt.Errorf(`encrypt: failed to convert to RSA public key: %w`, err) + } + + return jwebb.KeyEncryptRSAOAEP(cek, e.keyalg.String(), pubkey) + } + + if jwebb.IsAESKW(e.keyalg.String()) { + sharedkey, ok := e.rawKey.([]byte) + if !ok { + return nil, fmt.Errorf("[]byte is required as the key to encrypt %s", e.keyalg.String()) + } + return jwebb.KeyEncryptAESKW(cek, e.keyalg.String(), sharedkey) + } + + return nil, fmt.Errorf(`unsupported algorithm for key encryption (%s)`, e.keyalg) +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwe/errors.go b/vendor/github.com/lestrrat-go/jwx/v3/jwe/errors.go new file mode 100644 index 00000000000..89d276fc440 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwe/errors.go @@ -0,0 +1,90 @@ +package jwe + +import "errors" + +type encryptError struct { + error +} + +func (e encryptError) Unwrap() error { + return e.error +} + +func (encryptError) Is(err error) bool { + _, ok := err.(encryptError) + return ok +} + +var errDefaultEncryptError = encryptError{errors.New(`encrypt error`)} + +// EncryptError returns an error that can be passed to `errors.Is` to check if the error is an error returned by `jwe.Encrypt`. +func EncryptError() error { + return errDefaultEncryptError +} + +type decryptError struct { + error +} + +func (e decryptError) Unwrap() error { + return e.error +} + +func (decryptError) Is(err error) bool { + _, ok := err.(decryptError) + return ok +} + +var errDefaultDecryptError = decryptError{errors.New(`decrypt error`)} + +// DecryptError returns an error that can be passed to `errors.Is` to check if the error is an error returned by `jwe.Decrypt`. +func DecryptError() error { + return errDefaultDecryptError +} + +type recipientError struct { + error +} + +func (e recipientError) Unwrap() error { + return e.error +} + +func (recipientError) Is(err error) bool { + _, ok := err.(recipientError) + return ok +} + +var errDefaultRecipientError = recipientError{errors.New(`recipient error`)} + +// RecipientError returns an error that can be passed to `errors.Is` to check if the error is +// an error that occurred while attempting to decrypt a JWE message for a particular recipient. +// +// For example, if the JWE message failed to parse during `jwe.Decrypt`, it will be a +// `jwe.DecryptError`, but NOT `jwe.RecipientError`. However, if the JWE message could not +// be decrypted for any of the recipients, then it will be a `jwe.RecipientError` +// (actually, it will be _multiple_ `jwe.RecipientError` errors, one for each recipient) +func RecipientError() error { + return errDefaultRecipientError +} + +type parseError struct { + error +} + +func (e parseError) Unwrap() error { + return e.error +} + +func (parseError) Is(err error) bool { + _, ok := err.(parseError) + return ok +} + +var errDefaultParseError = parseError{errors.New(`parse error`)} + +// ParseError returns an error that can be passed to `errors.Is` to check if the error +// is an error returned by `jwe.Parse` and related functions. +func ParseError() error { + return errDefaultParseError +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwe/filter.go b/vendor/github.com/lestrrat-go/jwx/v3/jwe/filter.go new file mode 100644 index 00000000000..14941604bf0 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwe/filter.go @@ -0,0 +1,36 @@ +package jwe + +import ( + "github.com/lestrrat-go/jwx/v3/transform" +) + +// HeaderFilter is an interface that allows users to filter JWE header fields. +// It provides two methods: Filter and Reject; Filter returns a new header with only +// the fields that match the filter criteria, while Reject returns a new header with +// only the fields that DO NOT match the filter. +// +// EXPERIMENTAL: This API is experimental and its interface and behavior is +// subject to change in future releases. This API is not subject to semver +// compatibility guarantees. +type HeaderFilter interface { + Filter(header Headers) (Headers, error) + Reject(header Headers) (Headers, error) +} + +// StandardHeadersFilter returns a HeaderFilter that filters out standard JWE header fields. +// +// You can use this filter to create headers that either only have standard fields +// or only custom fields. +// +// If you need to configure the filter more precisely, consider +// using the HeaderNameFilter directly. +func StandardHeadersFilter() HeaderFilter { + return stdHeadersFilter +} + +var stdHeadersFilter = NewHeaderNameFilter(stdHeaderNames...) + +// NewHeaderNameFilter creates a new HeaderNameFilter with the specified field names. +func NewHeaderNameFilter(names ...string) HeaderFilter { + return transform.NewNameBasedFilter[Headers](names...) +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwe/headers.go b/vendor/github.com/lestrrat-go/jwx/v3/jwe/headers.go new file mode 100644 index 00000000000..6e13afde764 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwe/headers.go @@ -0,0 +1,95 @@ +package jwe + +import ( + "fmt" + + "github.com/lestrrat-go/jwx/v3/internal/base64" + "github.com/lestrrat-go/jwx/v3/internal/json" +) + +type isZeroer interface { + isZero() bool +} + +func (h *stdHeaders) isZero() bool { + return h.agreementPartyUInfo == nil && + h.agreementPartyVInfo == nil && + h.algorithm == nil && + h.compression == nil && + h.contentEncryption == nil && + h.contentType == nil && + h.critical == nil && + h.ephemeralPublicKey == nil && + h.jwk == nil && + h.jwkSetURL == nil && + h.keyID == nil && + h.typ == nil && + h.x509CertChain == nil && + h.x509CertThumbprint == nil && + h.x509CertThumbprintS256 == nil && + h.x509URL == nil && + len(h.privateParams) == 0 +} + +func (h *stdHeaders) Clone() (Headers, error) { + dst := NewHeaders() + if err := h.Copy(dst); err != nil { + return nil, fmt.Errorf(`failed to copy header contents to new object: %w`, err) + } + return dst, nil +} + +func (h *stdHeaders) Copy(dst Headers) error { + for _, key := range h.Keys() { + var v any + if err := h.Get(key, &v); err != nil { + return fmt.Errorf(`jwe.Headers: Copy: failed to get header %q: %w`, key, err) + } + + if err := dst.Set(key, v); err != nil { + return fmt.Errorf(`jwe.Headers: Copy: failed to set header %q: %w`, key, err) + } + } + return nil +} + +func (h *stdHeaders) Merge(h2 Headers) (Headers, error) { + h3 := NewHeaders() + + if h != nil { + if err := h.Copy(h3); err != nil { + return nil, fmt.Errorf(`failed to copy headers from receiver: %w`, err) + } + } + + if h2 != nil { + if err := h2.Copy(h3); err != nil { + return nil, fmt.Errorf(`failed to copy headers from argument: %w`, err) + } + } + + return h3, nil +} + +func (h *stdHeaders) Encode() ([]byte, error) { + buf, err := json.Marshal(h) + if err != nil { + return nil, fmt.Errorf(`failed to marshal headers to JSON prior to encoding: %w`, err) + } + + return base64.Encode(buf), nil +} + +func (h *stdHeaders) Decode(buf []byte) error { + // base64 json string -> json object representation of header + decoded, err := base64.Decode(buf) + if err != nil { + return fmt.Errorf(`failed to unmarshal base64 encoded buffer: %w`, err) + } + + if err := json.Unmarshal(decoded, h); err != nil { + return fmt.Errorf(`failed to unmarshal buffer: %w`, err) + } + + return nil +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwe/headers_gen.go b/vendor/github.com/lestrrat-go/jwx/v3/jwe/headers_gen.go new file mode 100644 index 00000000000..7773a5d8125 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwe/headers_gen.go @@ -0,0 +1,899 @@ +// Code generated by tools/cmd/genjwe/main.go. DO NOT EDIT. + +package jwe + +import ( + "bytes" + "fmt" + "sort" + "sync" + + "github.com/lestrrat-go/blackmagic" + "github.com/lestrrat-go/jwx/v3/cert" + "github.com/lestrrat-go/jwx/v3/internal/base64" + "github.com/lestrrat-go/jwx/v3/internal/json" + "github.com/lestrrat-go/jwx/v3/internal/pool" + "github.com/lestrrat-go/jwx/v3/internal/tokens" + "github.com/lestrrat-go/jwx/v3/jwa" + "github.com/lestrrat-go/jwx/v3/jwk" +) + +const ( + AgreementPartyUInfoKey = "apu" + AgreementPartyVInfoKey = "apv" + AlgorithmKey = "alg" + CompressionKey = "zip" + ContentEncryptionKey = "enc" + ContentTypeKey = "cty" + CriticalKey = "crit" + EphemeralPublicKeyKey = "epk" + JWKKey = "jwk" + JWKSetURLKey = "jku" + KeyIDKey = "kid" + TypeKey = "typ" + X509CertChainKey = "x5c" + X509CertThumbprintKey = "x5t" + X509CertThumbprintS256Key = "x5t#S256" + X509URLKey = "x5u" +) + +// Headers describe a standard JWE Header set. It is part of the JWE message +// and is used to represent both Protected and Unprotected headers, +// which in turn can be found in each Recipient object. +// If you are not sure how this works, it is strongly recommended that +// you read RFC7516, especially the section +// that describes the full JSON serialization format of JWE messages. +// +// In most cases, you likely want to use the protected headers, as this is the part of the encrypted content +type Headers interface { + AgreementPartyUInfo() ([]byte, bool) + AgreementPartyVInfo() ([]byte, bool) + Algorithm() (jwa.KeyEncryptionAlgorithm, bool) + Compression() (jwa.CompressionAlgorithm, bool) + ContentEncryption() (jwa.ContentEncryptionAlgorithm, bool) + ContentType() (string, bool) + Critical() ([]string, bool) + EphemeralPublicKey() (jwk.Key, bool) + JWK() (jwk.Key, bool) + JWKSetURL() (string, bool) + KeyID() (string, bool) + Type() (string, bool) + X509CertChain() (*cert.Chain, bool) + X509CertThumbprint() (string, bool) + X509CertThumbprintS256() (string, bool) + X509URL() (string, bool) + + // Get is used to extract the value of any field, including non-standard fields, out of the header. + // + // The first argument is the name of the field. The second argument is a pointer + // to a variable that will receive the value of the field. The method returns + // an error if the field does not exist, or if the value cannot be assigned to + // the destination variable. Note that a field is considered to "exist" even if + // the value is empty-ish (e.g. 0, false, ""), as long as it is explicitly set. + Get(string, any) error + Set(string, any) error + Remove(string) error + // Has returns true if the specified header has a value, even if + // the value is empty-ish (e.g. 0, false, "") as long as it has been + // explicitly set. + Has(string) bool + Encode() ([]byte, error) + Decode([]byte) error + Clone() (Headers, error) + Copy(Headers) error + Merge(Headers) (Headers, error) + + // Keys returns a list of the keys contained in this header. + Keys() []string +} + +// stdHeaderNames is a list of all standard header names defined in the JWE specification. +var stdHeaderNames = []string{AgreementPartyUInfoKey, AgreementPartyVInfoKey, AlgorithmKey, CompressionKey, ContentEncryptionKey, ContentTypeKey, CriticalKey, EphemeralPublicKeyKey, JWKKey, JWKSetURLKey, KeyIDKey, TypeKey, X509CertChainKey, X509CertThumbprintKey, X509CertThumbprintS256Key, X509URLKey} + +type stdHeaders struct { + agreementPartyUInfo []byte + agreementPartyVInfo []byte + algorithm *jwa.KeyEncryptionAlgorithm + compression *jwa.CompressionAlgorithm + contentEncryption *jwa.ContentEncryptionAlgorithm + contentType *string + critical []string + ephemeralPublicKey jwk.Key + jwk jwk.Key + jwkSetURL *string + keyID *string + typ *string + x509CertChain *cert.Chain + x509CertThumbprint *string + x509CertThumbprintS256 *string + x509URL *string + privateParams map[string]any + mu *sync.RWMutex +} + +func NewHeaders() Headers { + return &stdHeaders{ + mu: &sync.RWMutex{}, + privateParams: map[string]any{}, + } +} + +func (h *stdHeaders) AgreementPartyUInfo() ([]byte, bool) { + h.mu.RLock() + defer h.mu.RUnlock() + return h.agreementPartyUInfo, h.agreementPartyUInfo != nil +} + +func (h *stdHeaders) AgreementPartyVInfo() ([]byte, bool) { + h.mu.RLock() + defer h.mu.RUnlock() + return h.agreementPartyVInfo, h.agreementPartyVInfo != nil +} + +func (h *stdHeaders) Algorithm() (jwa.KeyEncryptionAlgorithm, bool) { + h.mu.RLock() + defer h.mu.RUnlock() + if h.algorithm == nil { + return jwa.EmptyKeyEncryptionAlgorithm(), false + } + return *(h.algorithm), true +} + +func (h *stdHeaders) Compression() (jwa.CompressionAlgorithm, bool) { + h.mu.RLock() + defer h.mu.RUnlock() + if h.compression == nil { + return jwa.NoCompress(), false + } + return *(h.compression), true +} + +func (h *stdHeaders) ContentEncryption() (jwa.ContentEncryptionAlgorithm, bool) { + h.mu.RLock() + defer h.mu.RUnlock() + if h.contentEncryption == nil { + return jwa.EmptyContentEncryptionAlgorithm(), false + } + return *(h.contentEncryption), true +} + +func (h *stdHeaders) ContentType() (string, bool) { + h.mu.RLock() + defer h.mu.RUnlock() + if h.contentType == nil { + return "", false + } + return *(h.contentType), true +} + +func (h *stdHeaders) Critical() ([]string, bool) { + h.mu.RLock() + defer h.mu.RUnlock() + return h.critical, h.critical != nil +} + +func (h *stdHeaders) EphemeralPublicKey() (jwk.Key, bool) { + h.mu.RLock() + defer h.mu.RUnlock() + return h.ephemeralPublicKey, h.ephemeralPublicKey != nil +} + +func (h *stdHeaders) JWK() (jwk.Key, bool) { + h.mu.RLock() + defer h.mu.RUnlock() + return h.jwk, h.jwk != nil +} + +func (h *stdHeaders) JWKSetURL() (string, bool) { + h.mu.RLock() + defer h.mu.RUnlock() + if h.jwkSetURL == nil { + return "", false + } + return *(h.jwkSetURL), true +} + +func (h *stdHeaders) KeyID() (string, bool) { + h.mu.RLock() + defer h.mu.RUnlock() + if h.keyID == nil { + return "", false + } + return *(h.keyID), true +} + +func (h *stdHeaders) Type() (string, bool) { + h.mu.RLock() + defer h.mu.RUnlock() + if h.typ == nil { + return "", false + } + return *(h.typ), true +} + +func (h *stdHeaders) X509CertChain() (*cert.Chain, bool) { + h.mu.RLock() + defer h.mu.RUnlock() + return h.x509CertChain, h.x509CertChain != nil +} + +func (h *stdHeaders) X509CertThumbprint() (string, bool) { + h.mu.RLock() + defer h.mu.RUnlock() + if h.x509CertThumbprint == nil { + return "", false + } + return *(h.x509CertThumbprint), true +} + +func (h *stdHeaders) X509CertThumbprintS256() (string, bool) { + h.mu.RLock() + defer h.mu.RUnlock() + if h.x509CertThumbprintS256 == nil { + return "", false + } + return *(h.x509CertThumbprintS256), true +} + +func (h *stdHeaders) X509URL() (string, bool) { + h.mu.RLock() + defer h.mu.RUnlock() + if h.x509URL == nil { + return "", false + } + return *(h.x509URL), true +} + +func (h *stdHeaders) PrivateParams() map[string]any { + h.mu.RLock() + defer h.mu.RUnlock() + return h.privateParams +} + +func (h *stdHeaders) Has(name string) bool { + h.mu.RLock() + defer h.mu.RUnlock() + switch name { + case AgreementPartyUInfoKey: + return h.agreementPartyUInfo != nil + case AgreementPartyVInfoKey: + return h.agreementPartyVInfo != nil + case AlgorithmKey: + return h.algorithm != nil + case CompressionKey: + return h.compression != nil + case ContentEncryptionKey: + return h.contentEncryption != nil + case ContentTypeKey: + return h.contentType != nil + case CriticalKey: + return h.critical != nil + case EphemeralPublicKeyKey: + return h.ephemeralPublicKey != nil + case JWKKey: + return h.jwk != nil + case JWKSetURLKey: + return h.jwkSetURL != nil + case KeyIDKey: + return h.keyID != nil + case TypeKey: + return h.typ != nil + case X509CertChainKey: + return h.x509CertChain != nil + case X509CertThumbprintKey: + return h.x509CertThumbprint != nil + case X509CertThumbprintS256Key: + return h.x509CertThumbprintS256 != nil + case X509URLKey: + return h.x509URL != nil + default: + _, ok := h.privateParams[name] + return ok + } +} + +func (h *stdHeaders) Get(name string, dst any) error { + h.mu.RLock() + defer h.mu.RUnlock() + switch name { + case AgreementPartyUInfoKey: + if h.agreementPartyUInfo == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, h.agreementPartyUInfo); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + case AgreementPartyVInfoKey: + if h.agreementPartyVInfo == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, h.agreementPartyVInfo); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + case AlgorithmKey: + if h.algorithm == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.algorithm)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + case CompressionKey: + if h.compression == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.compression)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + case ContentEncryptionKey: + if h.contentEncryption == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.contentEncryption)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + case ContentTypeKey: + if h.contentType == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.contentType)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + case CriticalKey: + if h.critical == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, h.critical); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + case EphemeralPublicKeyKey: + if h.ephemeralPublicKey == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, h.ephemeralPublicKey); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + case JWKKey: + if h.jwk == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, h.jwk); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + case JWKSetURLKey: + if h.jwkSetURL == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.jwkSetURL)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + case KeyIDKey: + if h.keyID == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.keyID)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + case TypeKey: + if h.typ == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.typ)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + case X509CertChainKey: + if h.x509CertChain == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, h.x509CertChain); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + case X509CertThumbprintKey: + if h.x509CertThumbprint == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.x509CertThumbprint)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + case X509CertThumbprintS256Key: + if h.x509CertThumbprintS256 == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.x509CertThumbprintS256)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + case X509URLKey: + if h.x509URL == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.x509URL)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + default: + v, ok := h.privateParams[name] + if !ok { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, v); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + } + return nil +} + +func (h *stdHeaders) Set(name string, value any) error { + h.mu.Lock() + defer h.mu.Unlock() + return h.setNoLock(name, value) +} + +func (h *stdHeaders) setNoLock(name string, value any) error { + switch name { + case AgreementPartyUInfoKey: + if v, ok := value.([]byte); ok { + h.agreementPartyUInfo = v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, AgreementPartyUInfoKey, value) + case AgreementPartyVInfoKey: + if v, ok := value.([]byte); ok { + h.agreementPartyVInfo = v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, AgreementPartyVInfoKey, value) + case AlgorithmKey: + if v, ok := value.(jwa.KeyEncryptionAlgorithm); ok { + h.algorithm = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, AlgorithmKey, value) + case CompressionKey: + if v, ok := value.(jwa.CompressionAlgorithm); ok { + h.compression = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, CompressionKey, value) + case ContentEncryptionKey: + if v, ok := value.(jwa.ContentEncryptionAlgorithm); ok { + if v == jwa.EmptyContentEncryptionAlgorithm() { + return fmt.Errorf(`"enc" field cannot be an empty string`) + } + h.contentEncryption = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, ContentEncryptionKey, value) + case ContentTypeKey: + if v, ok := value.(string); ok { + h.contentType = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, ContentTypeKey, value) + case CriticalKey: + if v, ok := value.([]string); ok { + h.critical = v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, CriticalKey, value) + case EphemeralPublicKeyKey: + if v, ok := value.(jwk.Key); ok { + h.ephemeralPublicKey = v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, EphemeralPublicKeyKey, value) + case JWKKey: + if v, ok := value.(jwk.Key); ok { + h.jwk = v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, JWKKey, value) + case JWKSetURLKey: + if v, ok := value.(string); ok { + h.jwkSetURL = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, JWKSetURLKey, value) + case KeyIDKey: + if v, ok := value.(string); ok { + h.keyID = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, KeyIDKey, value) + case TypeKey: + if v, ok := value.(string); ok { + h.typ = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, TypeKey, value) + case X509CertChainKey: + if v, ok := value.(*cert.Chain); ok { + h.x509CertChain = v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, X509CertChainKey, value) + case X509CertThumbprintKey: + if v, ok := value.(string); ok { + h.x509CertThumbprint = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, X509CertThumbprintKey, value) + case X509CertThumbprintS256Key: + if v, ok := value.(string); ok { + h.x509CertThumbprintS256 = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, X509CertThumbprintS256Key, value) + case X509URLKey: + if v, ok := value.(string); ok { + h.x509URL = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, X509URLKey, value) + default: + if h.privateParams == nil { + h.privateParams = map[string]any{} + } + h.privateParams[name] = value + } + return nil +} + +func (h *stdHeaders) Remove(key string) error { + h.mu.Lock() + defer h.mu.Unlock() + switch key { + case AgreementPartyUInfoKey: + h.agreementPartyUInfo = nil + case AgreementPartyVInfoKey: + h.agreementPartyVInfo = nil + case AlgorithmKey: + h.algorithm = nil + case CompressionKey: + h.compression = nil + case ContentEncryptionKey: + h.contentEncryption = nil + case ContentTypeKey: + h.contentType = nil + case CriticalKey: + h.critical = nil + case EphemeralPublicKeyKey: + h.ephemeralPublicKey = nil + case JWKKey: + h.jwk = nil + case JWKSetURLKey: + h.jwkSetURL = nil + case KeyIDKey: + h.keyID = nil + case TypeKey: + h.typ = nil + case X509CertChainKey: + h.x509CertChain = nil + case X509CertThumbprintKey: + h.x509CertThumbprint = nil + case X509CertThumbprintS256Key: + h.x509CertThumbprintS256 = nil + case X509URLKey: + h.x509URL = nil + default: + delete(h.privateParams, key) + } + return nil +} + +func (h *stdHeaders) UnmarshalJSON(buf []byte) error { + h.agreementPartyUInfo = nil + h.agreementPartyVInfo = nil + h.algorithm = nil + h.compression = nil + h.contentEncryption = nil + h.contentType = nil + h.critical = nil + h.ephemeralPublicKey = nil + h.jwk = nil + h.jwkSetURL = nil + h.keyID = nil + h.typ = nil + h.x509CertChain = nil + h.x509CertThumbprint = nil + h.x509CertThumbprintS256 = nil + h.x509URL = nil + dec := json.NewDecoder(bytes.NewReader(buf)) +LOOP: + for { + tok, err := dec.Token() + if err != nil { + return fmt.Errorf(`error reading token: %w`, err) + } + switch tok := tok.(type) { + case json.Delim: + // Assuming we're doing everything correctly, we should ONLY + // get either tokens.OpenCurlyBracket or tokens.CloseCurlyBracket here. + if tok == tokens.CloseCurlyBracket { // End of object + break LOOP + } else if tok != tokens.OpenCurlyBracket { + return fmt.Errorf(`expected '%c' but got '%c'`, tokens.OpenCurlyBracket, tok) + } + case string: // Objects can only have string keys + switch tok { + case AgreementPartyUInfoKey: + if err := json.AssignNextBytesToken(&h.agreementPartyUInfo, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, AgreementPartyUInfoKey, err) + } + case AgreementPartyVInfoKey: + if err := json.AssignNextBytesToken(&h.agreementPartyVInfo, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, AgreementPartyVInfoKey, err) + } + case AlgorithmKey: + var decoded jwa.KeyEncryptionAlgorithm + if err := dec.Decode(&decoded); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, AlgorithmKey, err) + } + h.algorithm = &decoded + case CompressionKey: + var decoded jwa.CompressionAlgorithm + if err := dec.Decode(&decoded); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, CompressionKey, err) + } + h.compression = &decoded + case ContentEncryptionKey: + var decoded jwa.ContentEncryptionAlgorithm + if err := dec.Decode(&decoded); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, ContentEncryptionKey, err) + } + h.contentEncryption = &decoded + case ContentTypeKey: + if err := json.AssignNextStringToken(&h.contentType, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, ContentTypeKey, err) + } + case CriticalKey: + var decoded []string + if err := dec.Decode(&decoded); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, CriticalKey, err) + } + h.critical = decoded + case EphemeralPublicKeyKey: + var buf json.RawMessage + if err := dec.Decode(&buf); err != nil { + return fmt.Errorf(`failed to decode value for key %s:%w`, EphemeralPublicKeyKey, err) + } + key, err := jwk.ParseKey(buf) + if err != nil { + return fmt.Errorf(`failed to parse JWK for key %s: %w`, EphemeralPublicKeyKey, err) + } + h.ephemeralPublicKey = key + case JWKKey: + var buf json.RawMessage + if err := dec.Decode(&buf); err != nil { + return fmt.Errorf(`failed to decode value for key %s:%w`, JWKKey, err) + } + key, err := jwk.ParseKey(buf) + if err != nil { + return fmt.Errorf(`failed to parse JWK for key %s: %w`, JWKKey, err) + } + h.jwk = key + case JWKSetURLKey: + if err := json.AssignNextStringToken(&h.jwkSetURL, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, JWKSetURLKey, err) + } + case KeyIDKey: + if err := json.AssignNextStringToken(&h.keyID, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, KeyIDKey, err) + } + case TypeKey: + if err := json.AssignNextStringToken(&h.typ, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, TypeKey, err) + } + case X509CertChainKey: + var decoded cert.Chain + if err := dec.Decode(&decoded); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, X509CertChainKey, err) + } + h.x509CertChain = &decoded + case X509CertThumbprintKey: + if err := json.AssignNextStringToken(&h.x509CertThumbprint, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, X509CertThumbprintKey, err) + } + case X509CertThumbprintS256Key: + if err := json.AssignNextStringToken(&h.x509CertThumbprintS256, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, X509CertThumbprintS256Key, err) + } + case X509URLKey: + if err := json.AssignNextStringToken(&h.x509URL, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, X509URLKey, err) + } + default: + decoded, err := registry.Decode(dec, tok) + if err != nil { + return err + } + h.setNoLock(tok, decoded) + } + default: + return fmt.Errorf(`invalid token %T`, tok) + } + } + return nil +} + +func (h *stdHeaders) Keys() []string { + h.mu.RLock() + defer h.mu.RUnlock() + keys := make([]string, 0, 16+len(h.privateParams)) + if h.agreementPartyUInfo != nil { + keys = append(keys, AgreementPartyUInfoKey) + } + if h.agreementPartyVInfo != nil { + keys = append(keys, AgreementPartyVInfoKey) + } + if h.algorithm != nil { + keys = append(keys, AlgorithmKey) + } + if h.compression != nil { + keys = append(keys, CompressionKey) + } + if h.contentEncryption != nil { + keys = append(keys, ContentEncryptionKey) + } + if h.contentType != nil { + keys = append(keys, ContentTypeKey) + } + if h.critical != nil { + keys = append(keys, CriticalKey) + } + if h.ephemeralPublicKey != nil { + keys = append(keys, EphemeralPublicKeyKey) + } + if h.jwk != nil { + keys = append(keys, JWKKey) + } + if h.jwkSetURL != nil { + keys = append(keys, JWKSetURLKey) + } + if h.keyID != nil { + keys = append(keys, KeyIDKey) + } + if h.typ != nil { + keys = append(keys, TypeKey) + } + if h.x509CertChain != nil { + keys = append(keys, X509CertChainKey) + } + if h.x509CertThumbprint != nil { + keys = append(keys, X509CertThumbprintKey) + } + if h.x509CertThumbprintS256 != nil { + keys = append(keys, X509CertThumbprintS256Key) + } + if h.x509URL != nil { + keys = append(keys, X509URLKey) + } + for k := range h.privateParams { + keys = append(keys, k) + } + return keys +} + +func (h stdHeaders) MarshalJSON() ([]byte, error) { + data := make(map[string]any) + keys := make([]string, 0, 16+len(h.privateParams)) + h.mu.RLock() + if h.agreementPartyUInfo != nil { + data[AgreementPartyUInfoKey] = h.agreementPartyUInfo + keys = append(keys, AgreementPartyUInfoKey) + } + if h.agreementPartyVInfo != nil { + data[AgreementPartyVInfoKey] = h.agreementPartyVInfo + keys = append(keys, AgreementPartyVInfoKey) + } + if h.algorithm != nil { + data[AlgorithmKey] = *(h.algorithm) + keys = append(keys, AlgorithmKey) + } + if h.compression != nil { + data[CompressionKey] = *(h.compression) + keys = append(keys, CompressionKey) + } + if h.contentEncryption != nil { + data[ContentEncryptionKey] = *(h.contentEncryption) + keys = append(keys, ContentEncryptionKey) + } + if h.contentType != nil { + data[ContentTypeKey] = *(h.contentType) + keys = append(keys, ContentTypeKey) + } + if h.critical != nil { + data[CriticalKey] = h.critical + keys = append(keys, CriticalKey) + } + if h.ephemeralPublicKey != nil { + data[EphemeralPublicKeyKey] = h.ephemeralPublicKey + keys = append(keys, EphemeralPublicKeyKey) + } + if h.jwk != nil { + data[JWKKey] = h.jwk + keys = append(keys, JWKKey) + } + if h.jwkSetURL != nil { + data[JWKSetURLKey] = *(h.jwkSetURL) + keys = append(keys, JWKSetURLKey) + } + if h.keyID != nil { + data[KeyIDKey] = *(h.keyID) + keys = append(keys, KeyIDKey) + } + if h.typ != nil { + data[TypeKey] = *(h.typ) + keys = append(keys, TypeKey) + } + if h.x509CertChain != nil { + data[X509CertChainKey] = h.x509CertChain + keys = append(keys, X509CertChainKey) + } + if h.x509CertThumbprint != nil { + data[X509CertThumbprintKey] = *(h.x509CertThumbprint) + keys = append(keys, X509CertThumbprintKey) + } + if h.x509CertThumbprintS256 != nil { + data[X509CertThumbprintS256Key] = *(h.x509CertThumbprintS256) + keys = append(keys, X509CertThumbprintS256Key) + } + if h.x509URL != nil { + data[X509URLKey] = *(h.x509URL) + keys = append(keys, X509URLKey) + } + for k, v := range h.privateParams { + data[k] = v + keys = append(keys, k) + } + h.mu.RUnlock() + + sort.Strings(keys) + buf := pool.BytesBuffer().Get() + defer pool.BytesBuffer().Put(buf) + enc := json.NewEncoder(buf) + buf.WriteByte(tokens.OpenCurlyBracket) + for i, k := range keys { + if i > 0 { + buf.WriteRune(tokens.Comma) + } + buf.WriteRune(tokens.DoubleQuote) + buf.WriteString(k) + buf.WriteString(`":`) + v := data[k] + switch v := v.(type) { + case []byte: + buf.WriteRune(tokens.DoubleQuote) + buf.WriteString(base64.EncodeToString(v)) + buf.WriteRune(tokens.DoubleQuote) + default: + if err := enc.Encode(v); err != nil { + return nil, fmt.Errorf(`failed to encode value for field %s`, k) + } + buf.Truncate(buf.Len() - 1) + } + } + buf.WriteByte(tokens.CloseCurlyBracket) + ret := make([]byte, buf.Len()) + copy(ret, buf.Bytes()) + return ret, nil +} + +func (h *stdHeaders) clear() { + h.mu.Lock() + h.agreementPartyUInfo = nil + h.agreementPartyVInfo = nil + h.algorithm = nil + h.compression = nil + h.contentEncryption = nil + h.contentType = nil + h.critical = nil + h.ephemeralPublicKey = nil + h.jwk = nil + h.jwkSetURL = nil + h.keyID = nil + h.typ = nil + h.x509CertChain = nil + h.x509CertThumbprint = nil + h.x509CertThumbprintS256 = nil + h.x509URL = nil + h.privateParams = map[string]any{} + h.mu.Unlock() +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwe/interface.go b/vendor/github.com/lestrrat-go/jwx/v3/jwe/interface.go new file mode 100644 index 00000000000..91ad8cb809b --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwe/interface.go @@ -0,0 +1,207 @@ +package jwe + +import ( + "github.com/lestrrat-go/jwx/v3/jwa" + "github.com/lestrrat-go/jwx/v3/jwe/internal/keygen" +) + +// KeyEncrypter is an interface for object that can encrypt a +// content encryption key. +// +// You can use this in place of a regular key (i.e. in jwe.WithKey()) +// to encrypt the content encryption key in a JWE message without +// having to expose the secret key in memory, for example, when you +// want to use hardware security modules (HSMs) to encrypt the key. +// +// This API is experimental and may change without notice, even +// in minor releases. +type KeyEncrypter interface { + // Algorithm returns the algorithm used to encrypt the key. + Algorithm() jwa.KeyEncryptionAlgorithm + + // EncryptKey encrypts the given content encryption key. + EncryptKey([]byte) ([]byte, error) +} + +// KeyIDer is an interface for things that can return a key ID. +// +// As of this writing, this is solely used to identify KeyEncrypter +// objects that also carry a key ID on its own. +type KeyIDer interface { + KeyID() (string, bool) +} + +// KeyDecrypter is an interface for objects that can decrypt a content +// encryption key. +// +// You can use this in place of a regular key (i.e. in jwe.WithKey()) +// to decrypt the encrypted key in a JWE message without having to +// expose the secret key in memory, for example, when you want to use +// hardware security modules (HSMs) to decrypt the key. +// +// This API is experimental and may change without notice, even +// in minor releases. +type KeyDecrypter interface { + // Decrypt decrypts the encrypted key of a JWE message. + // + // Make sure you understand how JWE messages are structured. + // + // For example, while in most circumstances a JWE message will only have one recipient, + // a JWE message may contain multiple recipients, each with their own + // encrypted key. This method will be called for each recipient, instead of + // just once for a message. + // + // Also, header values could be found in either protected/unprotected headers + // of a JWE message, as well as in protected/unprotected headers for each recipient. + // When checking a header value, you can decide to use either one, or both, but you + // must be aware that there are multiple places to look for. + DecryptKey(alg jwa.KeyEncryptionAlgorithm, encryptedKey []byte, recipient Recipient, message *Message) ([]byte, error) +} + +// Recipient holds the encrypted key and hints to decrypt the key +type Recipient interface { + Headers() Headers + EncryptedKey() []byte + SetHeaders(Headers) error + SetEncryptedKey([]byte) error +} + +type stdRecipient struct { + // Comments on each field are taken from https://datatracker.ietf.org/doc/html/rfc7516 + // + // header + // The "header" member MUST be present and contain the value JWE Per- + // Recipient Unprotected Header when the JWE Per-Recipient + // Unprotected Header value is non-empty; otherwise, it MUST be + // absent. This value is represented as an unencoded JSON object, + // rather than as a string. These Header Parameter values are not + // integrity protected. + // + // At least one of the "header", "protected", and "unprotected" members + // MUST be present so that "alg" and "enc" Header Parameter values are + // conveyed for each recipient computation. + // + // JWX note: see Message.unprotectedHeaders + headers Headers + + // encrypted_key + // The "encrypted_key" member MUST be present and contain the value + // BASE64URL(JWE Encrypted Key) when the JWE Encrypted Key value is + // non-empty; otherwise, it MUST be absent. + encryptedKey []byte +} + +// Message contains the entire encrypted JWE message. You should not +// expect to use Message for anything other than inspecting the +// state of an encrypted message. This is because encryption is +// highly context-sensitive, and once we parse the original payload +// into an object, we may not always be able to recreate the exact +// context in which the encryption happened. +// +// For example, it is totally valid for if the protected header's +// integrity was calculated using a non-standard line breaks: +// +// {"a dummy": +// "protected header"} +// +// Once parsed, though, we can only serialize the protected header as: +// +// {"a dummy":"protected header"} +// +// which would obviously result in a contradicting integrity value +// if we tried to re-calculate it from a parsed message. +// +//nolint:govet +type Message struct { + // Comments on each field are taken from https://datatracker.ietf.org/doc/html/rfc7516 + // + // protected + // The "protected" member MUST be present and contain the value + // BASE64URL(UTF8(JWE Protected Header)) when the JWE Protected + // Header value is non-empty; otherwise, it MUST be absent. These + // Header Parameter values are integrity protected. + protectedHeaders Headers + + // unprotected + // The "unprotected" member MUST be present and contain the value JWE + // Shared Unprotected Header when the JWE Shared Unprotected Header + // value is non-empty; otherwise, it MUST be absent. This value is + // represented as an unencoded JSON object, rather than as a string. + // These Header Parameter values are not integrity protected. + // + // JWX note: This field is NOT mutually exclusive with per-recipient + // headers within the implementation because... it's too much work. + // It is _never_ populated (we don't provide a way to do this) upon encryption. + // When decrypting, if present its values are always merged with + // per-recipient header. + unprotectedHeaders Headers + + // iv + // The "iv" member MUST be present and contain the value + // BASE64URL(JWE Initialization Vector) when the JWE Initialization + // Vector value is non-empty; otherwise, it MUST be absent. + initializationVector []byte + + // aad + // The "aad" member MUST be present and contain the value + // BASE64URL(JWE AAD)) when the JWE AAD value is non-empty; + // otherwise, it MUST be absent. A JWE AAD value can be included to + // supply a base64url-encoded value to be integrity protected but not + // encrypted. + authenticatedData []byte + + // ciphertext + // The "ciphertext" member MUST be present and contain the value + // BASE64URL(JWE Ciphertext). + cipherText []byte + + // tag + // The "tag" member MUST be present and contain the value + // BASE64URL(JWE Authentication Tag) when the JWE Authentication Tag + // value is non-empty; otherwise, it MUST be absent. + tag []byte + + // recipients + // The "recipients" member value MUST be an array of JSON objects. + // Each object contains information specific to a single recipient. + // This member MUST be present with exactly one array element per + // recipient, even if some or all of the array element values are the + // empty JSON object "{}" (which can happen when all Header Parameter + // values are shared between all recipients and when no encrypted key + // is used, such as when doing Direct Encryption). + // + // Some Header Parameters, including the "alg" parameter, can be shared + // among all recipient computations. Header Parameters in the JWE + // Protected Header and JWE Shared Unprotected Header values are shared + // among all recipients. + // + // The Header Parameter values used when creating or validating per- + // recipient ciphertext and Authentication Tag values are the union of + // the three sets of Header Parameter values that may be present: (1) + // the JWE Protected Header represented in the "protected" member, (2) + // the JWE Shared Unprotected Header represented in the "unprotected" + // member, and (3) the JWE Per-Recipient Unprotected Header represented + // in the "header" member of the recipient's array element. The union + // of these sets of Header Parameters comprises the JOSE Header. The + // Header Parameter names in the three locations MUST be disjoint. + recipients []Recipient + + // TODO: Additional members can be present in both the JSON objects defined + // above; if not understood by implementations encountering them, they + // MUST be ignored. + // privateParams map[string]any + + // These two fields below are not available for the public consumers of this object. + // rawProtectedHeaders stores the original protected header buffer + rawProtectedHeaders []byte + // storeProtectedHeaders is a hint to be used in UnmarshalJSON(). + // When this flag is true, UnmarshalJSON() will populate the + // rawProtectedHeaders field + storeProtectedHeaders bool +} + +// populater is an interface for things that may modify the +// JWE header. e.g. ByteWithECPrivateKey +type populater interface { + Populate(keygen.Setter) error +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwe/internal/aescbc/BUILD.bazel b/vendor/github.com/lestrrat-go/jwx/v3/jwe/internal/aescbc/BUILD.bazel new file mode 100644 index 00000000000..4ed4c53fa3f --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwe/internal/aescbc/BUILD.bazel @@ -0,0 +1,22 @@ +load("@rules_go//go:def.bzl", "go_library", "go_test") + +go_library( + name = "aescbc", + srcs = ["aescbc.go"], + importpath = "github.com/lestrrat-go/jwx/v3/jwe/internal/aescbc", + visibility = ["//:__subpackages__"], + deps = ["//internal/pool"], +) + +go_test( + name = "aescbc_test", + srcs = ["aescbc_test.go"], + embed = [":aescbc"], + deps = ["@com_github_stretchr_testify//require"] +) + +alias( + name = "go_default_library", + actual = ":aescbc", + visibility = ["//jwe:__subpackages__"], +) diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwe/internal/aescbc/aescbc.go b/vendor/github.com/lestrrat-go/jwx/v3/jwe/internal/aescbc/aescbc.go new file mode 100644 index 00000000000..b572674e2dd --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwe/internal/aescbc/aescbc.go @@ -0,0 +1,270 @@ +package aescbc + +import ( + "crypto/cipher" + "crypto/hmac" + "crypto/sha256" + "crypto/sha512" + "crypto/subtle" + "encoding/binary" + "errors" + "fmt" + "hash" + "sync/atomic" + + "github.com/lestrrat-go/jwx/v3/internal/pool" +) + +const ( + NonceSize = 16 +) + +const defaultBufSize int64 = 256 * 1024 * 1024 + +var maxBufSize atomic.Int64 + +func init() { + SetMaxBufferSize(defaultBufSize) +} + +func SetMaxBufferSize(siz int64) { + if siz <= 0 { + siz = defaultBufSize + } + maxBufSize.Store(siz) +} + +func pad(buf []byte, n int) []byte { + rem := n - len(buf)%n + if rem == 0 { + return buf + } + + bufsiz := len(buf) + rem + mbs := maxBufSize.Load() + if int64(bufsiz) > mbs { + panic(fmt.Errorf("failed to allocate buffer")) + } + newbuf := make([]byte, bufsiz) + copy(newbuf, buf) + + for i := len(buf); i < len(newbuf); i++ { + newbuf[i] = byte(rem) + } + return newbuf +} + +// ref. https://github.com/golang/go/blob/c3db64c0f45e8f2d75c5b59401e0fc925701b6f4/src/crypto/tls/conn.go#L279-L324 +// +// extractPadding returns, in constant time, the length of the padding to remove +// from the end of payload. It also returns a byte which is equal to 255 if the +// padding was valid and 0 otherwise. See RFC 2246, Section 6.2.3.2. +func extractPadding(payload []byte) (toRemove int, good byte) { + if len(payload) < 1 { + return 0, 0 + } + + paddingLen := payload[len(payload)-1] + t := uint(len(payload)) - uint(paddingLen) + // if len(payload) > paddingLen then the MSB of t is zero + good = byte(int32(^t) >> 31) + + // The maximum possible padding length plus the actual length field + toCheck := 256 + // The length of the padded data is public, so we can use an if here + if toCheck > len(payload) { + toCheck = len(payload) + } + + for i := 1; i <= toCheck; i++ { + t := uint(paddingLen) - uint(i) + // if i <= paddingLen then the MSB of t is zero + mask := byte(int32(^t) >> 31) + b := payload[len(payload)-i] + good &^= mask&paddingLen ^ mask&b + } + + // We AND together the bits of good and replicate the result across + // all the bits. + good &= good << 4 + good &= good << 2 + good &= good << 1 + good = uint8(int8(good) >> 7) + + // Zero the padding length on error. This ensures any unchecked bytes + // are included in the MAC. Otherwise, an attacker that could + // distinguish MAC failures from padding failures could mount an attack + // similar to POODLE in SSL 3.0: given a good ciphertext that uses a + // full block's worth of padding, replace the final block with another + // block. If the MAC check passed but the padding check failed, the + // last byte of that block decrypted to the block size. + // + // See also macAndPaddingGood logic below. + paddingLen &= good + + toRemove = int(paddingLen) + return +} + +type Hmac struct { + blockCipher cipher.Block + hash func() hash.Hash + keysize int + tagsize int + integrityKey []byte +} + +type BlockCipherFunc func([]byte) (cipher.Block, error) + +func New(key []byte, f BlockCipherFunc) (hmac *Hmac, err error) { + keysize := len(key) / 2 + ikey := key[:keysize] + ekey := key[keysize:] + + bc, ciphererr := f(ekey) + if ciphererr != nil { + err = fmt.Errorf(`failed to execute block cipher function: %w`, ciphererr) + return + } + + var hfunc func() hash.Hash + switch keysize { + case 16: + hfunc = sha256.New + case 24: + hfunc = sha512.New384 + case 32: + hfunc = sha512.New + default: + return nil, fmt.Errorf("unsupported key size %d", keysize) + } + + return &Hmac{ + blockCipher: bc, + hash: hfunc, + integrityKey: ikey, + keysize: keysize, + tagsize: keysize, // NonceSize, + // While investigating GH #207, I stumbled upon another problem where + // the computed tags don't match on decrypt. After poking through the + // code using a bunch of debug statements, I've finally found out that + // tagsize = keysize makes the whole thing work. + }, nil +} + +// NonceSize fulfills the crypto.AEAD interface +func (c Hmac) NonceSize() int { + return NonceSize +} + +// Overhead fulfills the crypto.AEAD interface +func (c Hmac) Overhead() int { + return c.blockCipher.BlockSize() + c.tagsize +} + +func (c Hmac) ComputeAuthTag(aad, nonce, ciphertext []byte) ([]byte, error) { + var buf [8]byte + binary.BigEndian.PutUint64(buf[:], uint64(len(aad)*8)) + + h := hmac.New(c.hash, c.integrityKey) + + // compute the tag + // no need to check errors because Write never returns an error: https://pkg.go.dev/hash#Hash + // + // > Write (via the embedded io.Writer interface) adds more data to the running hash. + // > It never returns an error. + h.Write(aad) + h.Write(nonce) + h.Write(ciphertext) + h.Write(buf[:]) + s := h.Sum(nil) + return s[:c.tagsize], nil +} + +func ensureSize(dst []byte, n int) []byte { + // if the dst buffer has enough length just copy the relevant parts to it. + // Otherwise create a new slice that's big enough, and operate on that + // Note: I think go-jose has a bug in that it checks for cap(), but not len(). + ret := dst + if diff := n - len(dst); diff > 0 { + // dst is not big enough + ret = make([]byte, n) + copy(ret, dst) + } + return ret +} + +// Seal fulfills the crypto.AEAD interface +func (c Hmac) Seal(dst, nonce, plaintext, data []byte) []byte { + ctlen := len(plaintext) + bufsiz := ctlen + c.Overhead() + mbs := maxBufSize.Load() + + if int64(bufsiz) > mbs { + panic(fmt.Errorf("failed to allocate buffer")) + } + ciphertext := make([]byte, bufsiz)[:ctlen] + copy(ciphertext, plaintext) + ciphertext = pad(ciphertext, c.blockCipher.BlockSize()) + + cbc := cipher.NewCBCEncrypter(c.blockCipher, nonce) + cbc.CryptBlocks(ciphertext, ciphertext) + + authtag, err := c.ComputeAuthTag(data, nonce, ciphertext) + if err != nil { + // Hmac implements cipher.AEAD interface. Seal can't return error. + // But currently it never reach here because of Hmac.ComputeAuthTag doesn't return error. + panic(fmt.Errorf("failed to seal on hmac: %v", err)) + } + + retlen := len(dst) + len(ciphertext) + len(authtag) + + ret := ensureSize(dst, retlen) + out := ret[len(dst):] + n := copy(out, ciphertext) + copy(out[n:], authtag) + + return ret +} + +// Open fulfills the crypto.AEAD interface +func (c Hmac) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) { + if len(ciphertext) < c.keysize { + return nil, fmt.Errorf(`invalid ciphertext (too short)`) + } + + tagOffset := len(ciphertext) - c.tagsize + if tagOffset%c.blockCipher.BlockSize() != 0 { + return nil, fmt.Errorf( + "invalid ciphertext (invalid length: %d %% %d != 0)", + tagOffset, + c.blockCipher.BlockSize(), + ) + } + tag := ciphertext[tagOffset:] + ciphertext = ciphertext[:tagOffset] + + expectedTag, err := c.ComputeAuthTag(data, nonce, ciphertext[:tagOffset]) + if err != nil { + return nil, fmt.Errorf(`failed to compute auth tag: %w`, err) + } + + cbc := cipher.NewCBCDecrypter(c.blockCipher, nonce) + buf := pool.ByteSlice().GetCapacity(tagOffset) + defer pool.ByteSlice().Put(buf) + buf = buf[:tagOffset] + + cbc.CryptBlocks(buf, ciphertext) + + toRemove, good := extractPadding(buf) + cmp := subtle.ConstantTimeCompare(expectedTag, tag) & int(good) + if cmp != 1 { + return nil, errors.New(`invalid ciphertext`) + } + + plaintext := buf[:len(buf)-toRemove] + ret := ensureSize(dst, len(plaintext)) + out := ret[len(dst):] + copy(out, plaintext) + return ret, nil +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwe/internal/cipher/BUILD.bazel b/vendor/github.com/lestrrat-go/jwx/v3/jwe/internal/cipher/BUILD.bazel new file mode 100644 index 00000000000..cf642c744de --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwe/internal/cipher/BUILD.bazel @@ -0,0 +1,34 @@ +load("@rules_go//go:def.bzl", "go_library", "go_test") + +go_library( + name = "cipher", + srcs = [ + "cipher.go", + "interface.go", + ], + importpath = "github.com/lestrrat-go/jwx/v3/jwe/internal/cipher", + visibility = ["//:__subpackages__"], + deps = [ + "//jwa", + "//jwe/internal/aescbc", + "//jwe/internal/keygen", + "//internal/tokens", + ], +) + +go_test( + name = "cipher_test", + srcs = ["cipher_test.go"], + deps = [ + ":cipher", + "//jwa", + "//internal/tokens", + "@com_github_stretchr_testify//require", + ], +) + +alias( + name = "go_default_library", + actual = ":cipher", + visibility = ["//jwe:__subpackages__"], +) diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwe/internal/cipher/cipher.go b/vendor/github.com/lestrrat-go/jwx/v3/jwe/internal/cipher/cipher.go new file mode 100644 index 00000000000..9b9a40d00d1 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwe/internal/cipher/cipher.go @@ -0,0 +1,169 @@ +package cipher + +import ( + "crypto/aes" + "crypto/cipher" + "fmt" + + "github.com/lestrrat-go/jwx/v3/internal/tokens" + "github.com/lestrrat-go/jwx/v3/jwe/internal/aescbc" + "github.com/lestrrat-go/jwx/v3/jwe/internal/keygen" +) + +var gcm = &gcmFetcher{} +var cbc = &cbcFetcher{} + +func (f gcmFetcher) Fetch(key []byte, size int) (cipher.AEAD, error) { + if len(key) != size { + return nil, fmt.Errorf(`key size (%d) does not match expected key size (%d)`, len(key), size) + } + aescipher, err := aes.NewCipher(key) + if err != nil { + return nil, fmt.Errorf(`cipher: failed to create AES cipher for GCM: %w`, err) + } + + aead, err := cipher.NewGCM(aescipher) + if err != nil { + return nil, fmt.Errorf(`failed to create GCM for cipher: %w`, err) + } + return aead, nil +} + +func (f cbcFetcher) Fetch(key []byte, size int) (cipher.AEAD, error) { + if len(key) != size { + return nil, fmt.Errorf(`key size (%d) does not match expected key size (%d)`, len(key), size) + } + aead, err := aescbc.New(key, aes.NewCipher) + if err != nil { + return nil, fmt.Errorf(`cipher: failed to create AES cipher for CBC: %w`, err) + } + return aead, nil +} + +func (c AesContentCipher) KeySize() int { + return c.keysize +} + +func (c AesContentCipher) TagSize() int { + return c.tagsize +} + +func NewAES(alg string) (*AesContentCipher, error) { + var keysize int + var tagsize int + var fetcher Fetcher + switch alg { + case tokens.A128GCM: + keysize = 16 + tagsize = 16 + fetcher = gcm + case tokens.A192GCM: + keysize = 24 + tagsize = 16 + fetcher = gcm + case tokens.A256GCM: + keysize = 32 + tagsize = 16 + fetcher = gcm + case tokens.A128CBC_HS256: + tagsize = 16 + keysize = tagsize * 2 + fetcher = cbc + case tokens.A192CBC_HS384: + tagsize = 24 + keysize = tagsize * 2 + fetcher = cbc + case tokens.A256CBC_HS512: + tagsize = 32 + keysize = tagsize * 2 + fetcher = cbc + default: + return nil, fmt.Errorf("failed to create AES content cipher: invalid algorithm (%s)", alg) + } + + return &AesContentCipher{ + keysize: keysize, + tagsize: tagsize, + fetch: fetcher, + }, nil +} + +func (c AesContentCipher) Encrypt(cek, plaintext, aad []byte) (iv, ciphertxt, tag []byte, err error) { + var aead cipher.AEAD + aead, err = c.fetch.Fetch(cek, c.keysize) + if err != nil { + return nil, nil, nil, fmt.Errorf(`failed to fetch AEAD: %w`, err) + } + + // Seal may panic (argh!), so protect ourselves from that + defer func() { + if e := recover(); e != nil { + switch e := e.(type) { + case error: + err = e + default: + err = fmt.Errorf("%s", e) + } + err = fmt.Errorf(`failed to encrypt: %w`, err) + } + }() + + if c.NonceGenerator != nil { + iv, err = c.NonceGenerator(aead.NonceSize()) + if err != nil { + return nil, nil, nil, fmt.Errorf(`failed to generate nonce: %w`, err) + } + } else { + bs, err := keygen.Random(aead.NonceSize()) + if err != nil { + return nil, nil, nil, fmt.Errorf(`failed to generate random nonce: %w`, err) + } + iv = bs.Bytes() + } + + combined := aead.Seal(nil, iv, plaintext, aad) + tagoffset := len(combined) - c.TagSize() + + if tagoffset < 0 { + panic(fmt.Sprintf("tag offset is less than 0 (combined len = %d, tagsize = %d)", len(combined), c.TagSize())) + } + + tag = combined[tagoffset:] + ciphertxt = make([]byte, tagoffset) + copy(ciphertxt, combined[:tagoffset]) + + return +} + +func (c AesContentCipher) Decrypt(cek, iv, ciphertxt, tag, aad []byte) (plaintext []byte, err error) { + aead, err := c.fetch.Fetch(cek, c.keysize) + if err != nil { + return nil, fmt.Errorf(`failed to fetch AEAD data: %w`, err) + } + + // Open may panic (argh!), so protect ourselves from that + defer func() { + if e := recover(); e != nil { + switch e := e.(type) { + case error: + err = e + default: + err = fmt.Errorf(`%s`, e) + } + err = fmt.Errorf(`failed to decrypt: %w`, err) + return + } + }() + + combined := make([]byte, len(ciphertxt)+len(tag)) + copy(combined, ciphertxt) + copy(combined[len(ciphertxt):], tag) + + buf, aeaderr := aead.Open(nil, iv, combined, aad) + if aeaderr != nil { + err = fmt.Errorf(`aead.Open failed: %w`, aeaderr) + return + } + plaintext = buf + return +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwe/internal/cipher/interface.go b/vendor/github.com/lestrrat-go/jwx/v3/jwe/internal/cipher/interface.go new file mode 100644 index 00000000000..a03e15b1598 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwe/internal/cipher/interface.go @@ -0,0 +1,32 @@ +package cipher + +import ( + "crypto/cipher" +) + +const ( + TagSize = 16 +) + +// ContentCipher knows how to encrypt/decrypt the content given a content +// encryption key and other data +type ContentCipher interface { + KeySize() int + Encrypt(cek, aad, plaintext []byte) ([]byte, []byte, []byte, error) + Decrypt(cek, iv, aad, ciphertext, tag []byte) ([]byte, error) +} + +type Fetcher interface { + Fetch([]byte, int) (cipher.AEAD, error) +} + +type gcmFetcher struct{} +type cbcFetcher struct{} + +// AesContentCipher represents a cipher based on AES +type AesContentCipher struct { + NonceGenerator func(int) ([]byte, error) + fetch Fetcher + keysize int + tagsize int +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwe/internal/concatkdf/BUILD.bazel b/vendor/github.com/lestrrat-go/jwx/v3/jwe/internal/concatkdf/BUILD.bazel new file mode 100644 index 00000000000..59aeb2cd27d --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwe/internal/concatkdf/BUILD.bazel @@ -0,0 +1,24 @@ +load("@rules_go//go:def.bzl", "go_library", "go_test") + +go_library( + name = "concatkdf", + srcs = ["concatkdf.go"], + importpath = "github.com/lestrrat-go/jwx/v3/jwe/internal/concatkdf", + visibility = ["//:__subpackages__"], +) + +go_test( + name = "concatkdf_test", + srcs = ["concatkdf_test.go"], + embed = [":concatkdf"], + deps = [ + "//jwa", + "@com_github_stretchr_testify//require", + ], +) + +alias( + name = "go_default_library", + actual = ":concatkdf", + visibility = ["//jwe:__subpackages__"], +) diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwe/internal/concatkdf/concatkdf.go b/vendor/github.com/lestrrat-go/jwx/v3/jwe/internal/concatkdf/concatkdf.go new file mode 100644 index 00000000000..3691830a636 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwe/internal/concatkdf/concatkdf.go @@ -0,0 +1,66 @@ +package concatkdf + +import ( + "crypto" + "encoding/binary" + "fmt" +) + +type KDF struct { + buf []byte + otherinfo []byte + z []byte + hash crypto.Hash +} + +func ndata(src []byte) []byte { + buf := make([]byte, 4+len(src)) + binary.BigEndian.PutUint32(buf, uint32(len(src))) + copy(buf[4:], src) + return buf +} + +func New(hash crypto.Hash, alg, Z, apu, apv, pubinfo, privinfo []byte) *KDF { + algbuf := ndata(alg) + apubuf := ndata(apu) + apvbuf := ndata(apv) + + concat := make([]byte, len(algbuf)+len(apubuf)+len(apvbuf)+len(pubinfo)+len(privinfo)) + n := copy(concat, algbuf) + n += copy(concat[n:], apubuf) + n += copy(concat[n:], apvbuf) + n += copy(concat[n:], pubinfo) + copy(concat[n:], privinfo) + + return &KDF{ + hash: hash, + otherinfo: concat, + z: Z, + } +} + +func (k *KDF) Read(out []byte) (int, error) { + var round uint32 = 1 + h := k.hash.New() + + for len(out) > len(k.buf) { + h.Reset() + + if err := binary.Write(h, binary.BigEndian, round); err != nil { + return 0, fmt.Errorf(`failed to write round using kdf: %w`, err) + } + if _, err := h.Write(k.z); err != nil { + return 0, fmt.Errorf(`failed to write z using kdf: %w`, err) + } + if _, err := h.Write(k.otherinfo); err != nil { + return 0, fmt.Errorf(`failed to write other info using kdf: %w`, err) + } + + k.buf = append(k.buf, h.Sum(nil)...) + round++ + } + + n := copy(out, k.buf[:len(out)]) + k.buf = k.buf[len(out):] + return n, nil +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwe/internal/content_crypt/BUILD.bazel b/vendor/github.com/lestrrat-go/jwx/v3/jwe/internal/content_crypt/BUILD.bazel new file mode 100644 index 00000000000..bb395200f8f --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwe/internal/content_crypt/BUILD.bazel @@ -0,0 +1,21 @@ +load("@rules_go//go:def.bzl", "go_library") + +go_library( + name = "content_crypt", + srcs = [ + "content_crypt.go", + "interface.go", + ], + importpath = "github.com/lestrrat-go/jwx/v3/jwe/internal/content_crypt", + visibility = ["//:__subpackages__"], + deps = [ + "//jwa", + "//jwe/internal/cipher", + ], +) + +alias( + name = "go_default_library", + actual = ":content_crypt", + visibility = ["//jwe:__subpackages__"], +) diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwe/internal/content_crypt/content_crypt.go b/vendor/github.com/lestrrat-go/jwx/v3/jwe/internal/content_crypt/content_crypt.go new file mode 100644 index 00000000000..0ef45ed953a --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwe/internal/content_crypt/content_crypt.go @@ -0,0 +1,43 @@ +package content_crypt //nolint:golint + +import ( + "fmt" + + "github.com/lestrrat-go/jwx/v3/jwa" + "github.com/lestrrat-go/jwx/v3/jwe/internal/cipher" +) + +func (c Generic) Algorithm() jwa.ContentEncryptionAlgorithm { + return c.alg +} + +func (c Generic) Encrypt(cek, plaintext, aad []byte) ([]byte, []byte, []byte, error) { + iv, encrypted, tag, err := c.cipher.Encrypt(cek, plaintext, aad) + if err != nil { + return nil, nil, nil, fmt.Errorf(`failed to crypt content: %w`, err) + } + + return iv, encrypted, tag, nil +} + +func (c Generic) Decrypt(cek, iv, ciphertext, tag, aad []byte) ([]byte, error) { + return c.cipher.Decrypt(cek, iv, ciphertext, tag, aad) +} + +func NewGeneric(alg jwa.ContentEncryptionAlgorithm) (*Generic, error) { + c, err := cipher.NewAES(alg.String()) + if err != nil { + return nil, fmt.Errorf(`aes crypt: failed to create content cipher: %w`, err) + } + + return &Generic{ + alg: alg, + cipher: c, + keysize: c.KeySize(), + tagsize: 16, + }, nil +} + +func (c Generic) KeySize() int { + return c.keysize +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwe/internal/content_crypt/interface.go b/vendor/github.com/lestrrat-go/jwx/v3/jwe/internal/content_crypt/interface.go new file mode 100644 index 00000000000..84b42fe07d5 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwe/internal/content_crypt/interface.go @@ -0,0 +1,20 @@ +package content_crypt //nolint:golint + +import ( + "github.com/lestrrat-go/jwx/v3/jwa" + "github.com/lestrrat-go/jwx/v3/jwe/internal/cipher" +) + +// Generic encrypts a message by applying all the necessary +// modifications to the keys and the contents +type Generic struct { + alg jwa.ContentEncryptionAlgorithm + keysize int + tagsize int + cipher cipher.ContentCipher +} + +type Cipher interface { + Decrypt([]byte, []byte, []byte, []byte, []byte) ([]byte, error) + KeySize() int +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwe/internal/keygen/BUILD.bazel b/vendor/github.com/lestrrat-go/jwx/v3/jwe/internal/keygen/BUILD.bazel new file mode 100644 index 00000000000..bde8eb68f74 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwe/internal/keygen/BUILD.bazel @@ -0,0 +1,24 @@ +load("@rules_go//go:def.bzl", "go_library") + +go_library( + name = "keygen", + srcs = [ + "interface.go", + "keygen.go", + ], + importpath = "github.com/lestrrat-go/jwx/v3/jwe/internal/keygen", + visibility = ["//:__subpackages__"], + deps = [ + "//internal/ecutil", + "//jwa", + "//jwe/internal/concatkdf", + "//internal/tokens", + "//jwk", + ], +) + +alias( + name = "go_default_library", + actual = ":keygen", + visibility = ["//jwe:__subpackages__"], +) diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwe/internal/keygen/interface.go b/vendor/github.com/lestrrat-go/jwx/v3/jwe/internal/keygen/interface.go new file mode 100644 index 00000000000..7f8fb961a29 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwe/internal/keygen/interface.go @@ -0,0 +1,40 @@ +package keygen + +// ByteKey is a generated key that only has the key's byte buffer +// as its instance data. If a key needs to do more, such as providing +// values to be set in a JWE header, that key type wraps a ByteKey +type ByteKey []byte + +// ByteWithECPublicKey holds the EC private key that generated +// the key along with the key itself. This is required to set the +// proper values in the JWE headers +type ByteWithECPublicKey struct { + ByteKey + + PublicKey any +} + +type ByteWithIVAndTag struct { + ByteKey + + IV []byte + Tag []byte +} + +type ByteWithSaltAndCount struct { + ByteKey + + Salt []byte + Count int +} + +// ByteSource is an interface for things that return a byte sequence. +// This is used for KeyGenerator so that the result of computations can +// carry more than just the generate byte sequence. +type ByteSource interface { + Bytes() []byte +} + +type Setter interface { + Set(string, any) error +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwe/internal/keygen/keygen.go b/vendor/github.com/lestrrat-go/jwx/v3/jwe/internal/keygen/keygen.go new file mode 100644 index 00000000000..daa7599d9f0 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwe/internal/keygen/keygen.go @@ -0,0 +1,139 @@ +package keygen + +import ( + "crypto" + "crypto/ecdh" + "crypto/ecdsa" + "crypto/rand" + "encoding/binary" + "fmt" + "io" + + "github.com/lestrrat-go/jwx/v3/internal/ecutil" + "github.com/lestrrat-go/jwx/v3/internal/tokens" + "github.com/lestrrat-go/jwx/v3/jwe/internal/concatkdf" + "github.com/lestrrat-go/jwx/v3/jwk" +) + +// Bytes returns the byte from this ByteKey +func (k ByteKey) Bytes() []byte { + return []byte(k) +} + +func Random(n int) (ByteSource, error) { + buf := make([]byte, n) + if _, err := io.ReadFull(rand.Reader, buf); err != nil { + return nil, fmt.Errorf(`failed to read from rand.Reader: %w`, err) + } + return ByteKey(buf), nil +} + +// Ecdhes generates a new key using ECDH-ES +func Ecdhes(alg string, enc string, keysize int, pubkey *ecdsa.PublicKey, apu, apv []byte) (ByteSource, error) { + priv, err := ecdsa.GenerateKey(pubkey.Curve, rand.Reader) + if err != nil { + return nil, fmt.Errorf(`failed to generate key for ECDH-ES: %w`, err) + } + + var algorithm string + if alg == tokens.ECDH_ES { + algorithm = enc + } else { + algorithm = alg + } + + pubinfo := make([]byte, 4) + binary.BigEndian.PutUint32(pubinfo, uint32(keysize)*8) + + if !priv.PublicKey.Curve.IsOnCurve(pubkey.X, pubkey.Y) { + return nil, fmt.Errorf(`public key used does not contain a point (X,Y) on the curve`) + } + z, _ := priv.PublicKey.Curve.ScalarMult(pubkey.X, pubkey.Y, priv.D.Bytes()) + zBytes := ecutil.AllocECPointBuffer(z, priv.PublicKey.Curve) + defer ecutil.ReleaseECPointBuffer(zBytes) + kdf := concatkdf.New(crypto.SHA256, []byte(algorithm), zBytes, apu, apv, pubinfo, []byte{}) + kek := make([]byte, keysize) + if _, err := kdf.Read(kek); err != nil { + return nil, fmt.Errorf(`failed to read kdf: %w`, err) + } + + return ByteWithECPublicKey{ + PublicKey: &priv.PublicKey, + ByteKey: ByteKey(kek), + }, nil +} + +// X25519 generates a new key using ECDH-ES with X25519 +func X25519(alg string, enc string, keysize int, pubkey *ecdh.PublicKey) (ByteSource, error) { + priv, err := ecdh.X25519().GenerateKey(rand.Reader) + if err != nil { + return nil, fmt.Errorf(`failed to generate key for X25519: %w`, err) + } + + var algorithm string + if alg == tokens.ECDH_ES { + algorithm = enc + } else { + algorithm = alg + } + + pubinfo := make([]byte, 4) + binary.BigEndian.PutUint32(pubinfo, uint32(keysize)*8) + + zBytes, err := priv.ECDH(pubkey) + if err != nil { + return nil, fmt.Errorf(`failed to compute Z: %w`, err) + } + kdf := concatkdf.New(crypto.SHA256, []byte(algorithm), zBytes, []byte{}, []byte{}, pubinfo, []byte{}) + kek := make([]byte, keysize) + if _, err := kdf.Read(kek); err != nil { + return nil, fmt.Errorf(`failed to read kdf: %w`, err) + } + + return ByteWithECPublicKey{ + PublicKey: priv.PublicKey(), + ByteKey: ByteKey(kek), + }, nil +} + +// HeaderPopulate populates the header with the required EC-DSA public key +// information ('epk' key) +func (k ByteWithECPublicKey) Populate(h Setter) error { + key, err := jwk.Import(k.PublicKey) + if err != nil { + return fmt.Errorf(`failed to create JWK: %w`, err) + } + + if err := h.Set("epk", key); err != nil { + return fmt.Errorf(`failed to write header: %w`, err) + } + return nil +} + +// HeaderPopulate populates the header with the required AES GCM +// parameters ('iv' and 'tag') +func (k ByteWithIVAndTag) Populate(h Setter) error { + if err := h.Set("iv", k.IV); err != nil { + return fmt.Errorf(`failed to write header: %w`, err) + } + + if err := h.Set("tag", k.Tag); err != nil { + return fmt.Errorf(`failed to write header: %w`, err) + } + + return nil +} + +// HeaderPopulate populates the header with the required PBES2 +// parameters ('p2s' and 'p2c') +func (k ByteWithSaltAndCount) Populate(h Setter) error { + if err := h.Set("p2c", k.Count); err != nil { + return fmt.Errorf(`failed to write header: %w`, err) + } + + if err := h.Set("p2s", k.Salt); err != nil { + return fmt.Errorf(`failed to write header: %w`, err) + } + + return nil +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwe/io.go b/vendor/github.com/lestrrat-go/jwx/v3/jwe/io.go new file mode 100644 index 00000000000..a5d6aca8a3f --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwe/io.go @@ -0,0 +1,36 @@ +// Code generated by tools/cmd/genreadfile/main.go. DO NOT EDIT. + +package jwe + +import ( + "fmt" + "io/fs" + "os" +) + +type sysFS struct{} + +func (sysFS) Open(path string) (fs.File, error) { + return os.Open(path) +} + +func ReadFile(path string, options ...ReadFileOption) (*Message, error) { + + var srcFS fs.FS = sysFS{} + for _, option := range options { + switch option.Ident() { + case identFS{}: + if err := option.Value(&srcFS); err != nil { + return nil, fmt.Errorf("failed to set fs.FS: %w", err) + } + } + } + + f, err := srcFS.Open(path) + if err != nil { + return nil, err + } + + defer f.Close() + return ParseReader(f) +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwe/jwe.go b/vendor/github.com/lestrrat-go/jwx/v3/jwe/jwe.go new file mode 100644 index 00000000000..5728021ec7d --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwe/jwe.go @@ -0,0 +1,1036 @@ +//go:generate ../tools/cmd/genjwe.sh + +// Package jwe implements JWE as described in https://tools.ietf.org/html/rfc7516 +package jwe + +// #region imports +import ( + "bytes" + "context" + "crypto/ecdsa" + "errors" + "fmt" + "io" + "sync" + + "github.com/lestrrat-go/blackmagic" + "github.com/lestrrat-go/jwx/v3/internal/base64" + "github.com/lestrrat-go/jwx/v3/internal/json" + "github.com/lestrrat-go/jwx/v3/internal/pool" + "github.com/lestrrat-go/jwx/v3/internal/tokens" + "github.com/lestrrat-go/jwx/v3/jwk" + + "github.com/lestrrat-go/jwx/v3/jwa" + "github.com/lestrrat-go/jwx/v3/jwe/internal/aescbc" + "github.com/lestrrat-go/jwx/v3/jwe/internal/content_crypt" + "github.com/lestrrat-go/jwx/v3/jwe/internal/keygen" +) + +// #region globals + +var muSettings sync.RWMutex +var maxPBES2Count = 10000 +var maxDecompressBufferSize int64 = 10 * 1024 * 1024 // 10MB + +func Settings(options ...GlobalOption) { + muSettings.Lock() + defer muSettings.Unlock() + for _, option := range options { + switch option.Ident() { + case identMaxPBES2Count{}: + if err := option.Value(&maxPBES2Count); err != nil { + panic(fmt.Sprintf("jwe.Settings: value for option WithMaxPBES2Count must be an int: %s", err)) + } + case identMaxDecompressBufferSize{}: + if err := option.Value(&maxDecompressBufferSize); err != nil { + panic(fmt.Sprintf("jwe.Settings: value for option WithMaxDecompressBufferSize must be an int64: %s", err)) + } + case identCBCBufferSize{}: + var v int64 + if err := option.Value(&v); err != nil { + panic(fmt.Sprintf("jwe.Settings: value for option WithCBCBufferSize must be an int64: %s", err)) + } + aescbc.SetMaxBufferSize(v) + } + } +} + +const ( + fmtInvalid = iota + fmtCompact + fmtJSON + fmtJSONPretty + fmtMax +) + +var _ = fmtInvalid +var _ = fmtMax + +var registry = json.NewRegistry() + +type recipientBuilder struct { + alg jwa.KeyEncryptionAlgorithm + key any + headers Headers +} + +func (b *recipientBuilder) Build(r Recipient, cek []byte, calg jwa.ContentEncryptionAlgorithm, _ *content_crypt.Generic) ([]byte, error) { + // we need the raw key for later use + rawKey := b.key + + var keyID string + if ke, ok := b.key.(KeyEncrypter); ok { + if kider, ok := ke.(KeyIDer); ok { + if v, ok := kider.KeyID(); ok { + keyID = v + } + } + } else if jwkKey, ok := b.key.(jwk.Key); ok { + // Meanwhile, grab the kid as well + if v, ok := jwkKey.KeyID(); ok { + keyID = v + } + + var raw any + if err := jwk.Export(jwkKey, &raw); err != nil { + return nil, fmt.Errorf(`jwe.Encrypt: recipientBuilder: failed to retrieve raw key out of %T: %w`, b.key, err) + } + + rawKey = raw + } + + // Extract ECDH-ES specific parameters if needed + var apu, apv []byte + if b.headers != nil { + if val, ok := b.headers.AgreementPartyUInfo(); ok { + apu = val + } + if val, ok := b.headers.AgreementPartyVInfo(); ok { + apv = val + } + } + + // Create the encrypter using the new jwebb pattern + enc, err := newEncrypter(b.alg, calg, b.key, rawKey, apu, apv) + if err != nil { + return nil, fmt.Errorf(`jwe.Encrypt: recipientBuilder: failed to create encrypter: %w`, err) + } + + if hdrs := b.headers; hdrs != nil { + _ = r.SetHeaders(hdrs) + } + + if err := r.Headers().Set(AlgorithmKey, b.alg); err != nil { + return nil, fmt.Errorf(`failed to set header: %w`, err) + } + + if keyID != "" { + if err := r.Headers().Set(KeyIDKey, keyID); err != nil { + return nil, fmt.Errorf(`failed to set header: %w`, err) + } + } + + var rawCEK []byte + enckey, err := enc.EncryptKey(cek) + if err != nil { + return nil, fmt.Errorf(`failed to encrypt key: %w`, err) + } + if b.alg == jwa.ECDH_ES() || b.alg == jwa.DIRECT() { + rawCEK = enckey.Bytes() + } else { + if err := r.SetEncryptedKey(enckey.Bytes()); err != nil { + return nil, fmt.Errorf(`failed to set encrypted key: %w`, err) + } + } + + if hp, ok := enckey.(populater); ok { + if err := hp.Populate(r.Headers()); err != nil { + return nil, fmt.Errorf(`failed to populate: %w`, err) + } + } + + return rawCEK, nil +} + +// Encrypt generates a JWE message for the given payload and returns +// it in serialized form, which can be in either compact or +// JSON format. Default is compact. +// +// You must pass at least one key to `jwe.Encrypt()` by using `jwe.WithKey()` +// option. +// +// jwe.Encrypt(payload, jwe.WithKey(alg, key)) +// jwe.Encrypt(payload, jws.WithJSON(), jws.WithKey(alg1, key1), jws.WithKey(alg2, key2)) +// +// Note that in the second example the `jws.WithJSON()` option is +// specified as well. This is because the compact serialization +// format does not support multiple recipients, and users must +// specifically ask for the JSON serialization format. +// +// Read the documentation for `jwe.WithKey()` to learn more about the +// possible values that can be used for `alg` and `key`. +// +// Look for options that return `jwe.EncryptOption` or `jws.EncryptDecryptOption` +// for a complete list of options that can be passed to this function. +func Encrypt(payload []byte, options ...EncryptOption) ([]byte, error) { + ec := encryptContextPool.Get() + defer encryptContextPool.Put(ec) + if err := ec.ProcessOptions(options); err != nil { + return nil, encryptError{fmt.Errorf(`jwe.Encrypt: failed to process options: %w`, err)} + } + ret, err := ec.EncryptMessage(payload, nil) + if err != nil { + return nil, encryptError{fmt.Errorf(`jwe.Encrypt: %w`, err)} + } + return ret, nil +} + +// EncryptStatic is exactly like Encrypt, except it accepts a static +// content encryption key (CEK). It is separated out from the main +// Encrypt function such that the latter does not accidentally use a static +// CEK. +// +// DO NOT attempt to use this function unless you completely understand the +// security implications to using static CEKs. You have been warned. +// +// This function is currently considered EXPERIMENTAL, and is subject to +// future changes across minor/micro versions. +func EncryptStatic(payload, cek []byte, options ...EncryptOption) ([]byte, error) { + if len(cek) <= 0 { + return nil, encryptError{fmt.Errorf(`jwe.EncryptStatic: empty CEK`)} + } + ec := encryptContextPool.Get() + defer encryptContextPool.Put(ec) + if err := ec.ProcessOptions(options); err != nil { + return nil, encryptError{fmt.Errorf(`jwe.EncryptStatic: failed to process options: %w`, err)} + } + ret, err := ec.EncryptMessage(payload, cek) + if err != nil { + return nil, encryptError{fmt.Errorf(`jwe.EncryptStatic: %w`, err)} + } + return ret, nil +} + +// decryptContext holds the state during JWE decryption, similar to JWS verifyContext +type decryptContext struct { + keyProviders []KeyProvider + keyUsed any + cek *[]byte + dst *Message + maxDecompressBufferSize int64 + //nolint:containedctx + ctx context.Context +} + +var decryptContextPool = pool.New(allocDecryptContext, freeDecryptContext) + +func allocDecryptContext() *decryptContext { + return &decryptContext{ + ctx: context.Background(), + } +} + +func freeDecryptContext(dc *decryptContext) *decryptContext { + dc.keyProviders = dc.keyProviders[:0] + dc.keyUsed = nil + dc.cek = nil + dc.dst = nil + dc.maxDecompressBufferSize = 0 + dc.ctx = context.Background() + return dc +} + +func (dc *decryptContext) ProcessOptions(options []DecryptOption) error { + // Set default max decompress buffer size + muSettings.RLock() + dc.maxDecompressBufferSize = maxDecompressBufferSize + muSettings.RUnlock() + + for _, option := range options { + switch option.Ident() { + case identMessage{}: + if err := option.Value(&dc.dst); err != nil { + return fmt.Errorf("jwe.decrypt: WithMessage must be a *jwe.Message: %w", err) + } + case identKeyProvider{}: + var kp KeyProvider + if err := option.Value(&kp); err != nil { + return fmt.Errorf("jwe.decrypt: WithKeyProvider must be a KeyProvider: %w", err) + } + dc.keyProviders = append(dc.keyProviders, kp) + case identKeyUsed{}: + if err := option.Value(&dc.keyUsed); err != nil { + return fmt.Errorf("jwe.decrypt: WithKeyUsed must be an any: %w", err) + } + case identKey{}: + var pair *withKey + if err := option.Value(&pair); err != nil { + return fmt.Errorf("jwe.decrypt: WithKey must be a *withKey: %w", err) + } + alg, ok := pair.alg.(jwa.KeyEncryptionAlgorithm) + if !ok { + return fmt.Errorf("jwe.decrypt: WithKey() option must be specified using jwa.KeyEncryptionAlgorithm (got %T)", pair.alg) + } + dc.keyProviders = append(dc.keyProviders, &staticKeyProvider{alg: alg, key: pair.key}) + case identCEK{}: + if err := option.Value(&dc.cek); err != nil { + return fmt.Errorf("jwe.decrypt: WithCEK must be a *[]byte: %w", err) + } + case identMaxDecompressBufferSize{}: + if err := option.Value(&dc.maxDecompressBufferSize); err != nil { + return fmt.Errorf("jwe.decrypt: WithMaxDecompressBufferSize must be int64: %w", err) + } + case identContext{}: + if err := option.Value(&dc.ctx); err != nil { + return fmt.Errorf("jwe.decrypt: WithContext must be a context.Context: %w", err) + } + } + } + + if len(dc.keyProviders) < 1 { + return fmt.Errorf(`jwe.Decrypt: no key providers have been provided (see jwe.WithKey(), jwe.WithKeySet(), and jwe.WithKeyProvider()`) + } + + return nil +} + +func (dc *decryptContext) DecryptMessage(buf []byte) ([]byte, error) { + msg, err := parseJSONOrCompact(buf, true) + if err != nil { + return nil, fmt.Errorf(`failed to parse buffer for Decrypt: %w`, err) + } + + // Process things that are common to the message + h, err := msg.protectedHeaders.Clone() + if err != nil { + return nil, fmt.Errorf(`failed to copy protected headers: %w`, err) + } + h, err = h.Merge(msg.unprotectedHeaders) + if err != nil { + return nil, fmt.Errorf(`failed to merge headers for message decryption: %w`, err) + } + + var aad []byte + if aadContainer := msg.authenticatedData; aadContainer != nil { + aad = base64.Encode(aadContainer) + } + + var computedAad []byte + if len(msg.rawProtectedHeaders) > 0 { + computedAad = msg.rawProtectedHeaders + } else { + // this is probably not required once msg.Decrypt is deprecated + var err error + computedAad, err = msg.protectedHeaders.Encode() + if err != nil { + return nil, fmt.Errorf(`failed to encode protected headers: %w`, err) + } + } + + // for each recipient, attempt to match the key providers + // if we have no recipients, pretend like we only have one + recipients := msg.recipients + if len(recipients) == 0 { + r := NewRecipient() + if err := r.SetHeaders(msg.protectedHeaders); err != nil { + return nil, fmt.Errorf(`failed to set headers to recipient: %w`, err) + } + recipients = append(recipients, r) + } + + errs := make([]error, 0, len(recipients)) + for _, recipient := range recipients { + decrypted, err := dc.tryRecipient(msg, recipient, h, aad, computedAad) + if err != nil { + errs = append(errs, recipientError{err}) + continue + } + if dc.dst != nil { + *dc.dst = *msg + dc.dst.rawProtectedHeaders = nil + dc.dst.storeProtectedHeaders = false + } + return decrypted, nil + } + return nil, fmt.Errorf(`failed to decrypt any of the recipients: %w`, errors.Join(errs...)) +} + +func (dc *decryptContext) tryRecipient(msg *Message, recipient Recipient, protectedHeaders Headers, aad, computedAad []byte) ([]byte, error) { + var tried int + var lastError error + for i, kp := range dc.keyProviders { + var sink algKeySink + if err := kp.FetchKeys(dc.ctx, &sink, recipient, msg); err != nil { + return nil, fmt.Errorf(`key provider %d failed: %w`, i, err) + } + + for _, pair := range sink.list { + tried++ + // alg is converted here because pair.alg is of type jwa.KeyAlgorithm. + // this may seem ugly, but we're trying to avoid declaring separate + // structs for `alg jwa.KeyEncryptionAlgorithm` and `alg jwa.SignatureAlgorithm` + //nolint:forcetypeassert + alg := pair.alg.(jwa.KeyEncryptionAlgorithm) + key := pair.key + + decrypted, err := dc.decryptContent(msg, alg, key, recipient, protectedHeaders, aad, computedAad) + if err != nil { + lastError = err + continue + } + + if dc.keyUsed != nil { + if err := blackmagic.AssignIfCompatible(dc.keyUsed, key); err != nil { + return nil, fmt.Errorf(`failed to assign used key (%T) to %T: %w`, key, dc.keyUsed, err) + } + } + return decrypted, nil + } + } + return nil, fmt.Errorf(`jwe.Decrypt: tried %d keys, but failed to match any of the keys with recipient (last error = %s)`, tried, lastError) +} + +func (dc *decryptContext) decryptContent(msg *Message, alg jwa.KeyEncryptionAlgorithm, key any, recipient Recipient, protectedHeaders Headers, aad, computedAad []byte) ([]byte, error) { + if jwkKey, ok := key.(jwk.Key); ok { + var raw any + if err := jwk.Export(jwkKey, &raw); err != nil { + return nil, fmt.Errorf(`failed to retrieve raw key from %T: %w`, key, err) + } + key = raw + } + + ce, ok := msg.protectedHeaders.ContentEncryption() + if !ok { + return nil, fmt.Errorf(`jwe.Decrypt: failed to retrieve content encryption algorithm from protected headers`) + } + dec := newDecrypter(alg, ce, key). + AuthenticatedData(aad). + ComputedAuthenticatedData(computedAad). + InitializationVector(msg.initializationVector). + Tag(msg.tag). + CEK(dc.cek) + + if v, ok := recipient.Headers().Algorithm(); !ok || v != alg { + // algorithms don't match + return nil, fmt.Errorf(`jwe.Decrypt: key (%q) and recipient (%q) algorithms do not match`, alg, v) + } + + h2, err := protectedHeaders.Clone() + if err != nil { + return nil, fmt.Errorf(`jwe.Decrypt: failed to copy headers (1): %w`, err) + } + + h2, err = h2.Merge(recipient.Headers()) + if err != nil { + return nil, fmt.Errorf(`failed to copy headers (2): %w`, err) + } + + switch alg { + case jwa.ECDH_ES(), jwa.ECDH_ES_A128KW(), jwa.ECDH_ES_A192KW(), jwa.ECDH_ES_A256KW(): + var epk any + if err := h2.Get(EphemeralPublicKeyKey, &epk); err != nil { + return nil, fmt.Errorf(`failed to get 'epk' field: %w`, err) + } + switch epk := epk.(type) { + case jwk.ECDSAPublicKey: + var pubkey ecdsa.PublicKey + if err := jwk.Export(epk, &pubkey); err != nil { + return nil, fmt.Errorf(`failed to get public key: %w`, err) + } + dec.PublicKey(&pubkey) + case jwk.OKPPublicKey: + var pubkey any + if err := jwk.Export(epk, &pubkey); err != nil { + return nil, fmt.Errorf(`failed to get public key: %w`, err) + } + dec.PublicKey(pubkey) + default: + return nil, fmt.Errorf("unexpected 'epk' type %T for alg %s", epk, alg) + } + + if apu, ok := h2.AgreementPartyUInfo(); ok && len(apu) > 0 { + dec.AgreementPartyUInfo(apu) + } + if apv, ok := h2.AgreementPartyVInfo(); ok && len(apv) > 0 { + dec.AgreementPartyVInfo(apv) + } + case jwa.A128GCMKW(), jwa.A192GCMKW(), jwa.A256GCMKW(): + var ivB64 string + if err := h2.Get(InitializationVectorKey, &ivB64); err == nil { + iv, err := base64.DecodeString(ivB64) + if err != nil { + return nil, fmt.Errorf(`failed to b64-decode 'iv': %w`, err) + } + dec.KeyInitializationVector(iv) + } + var tagB64 string + if err := h2.Get(TagKey, &tagB64); err == nil { + tag, err := base64.DecodeString(tagB64) + if err != nil { + return nil, fmt.Errorf(`failed to b64-decode 'tag': %w`, err) + } + dec.KeyTag(tag) + } + case jwa.PBES2_HS256_A128KW(), jwa.PBES2_HS384_A192KW(), jwa.PBES2_HS512_A256KW(): + var saltB64 string + if err := h2.Get(SaltKey, &saltB64); err != nil { + return nil, fmt.Errorf(`failed to get %q field`, SaltKey) + } + + // check if WithUseNumber is effective, because it will change the + // type of the underlying value (#1140) + var countFlt float64 + if json.UseNumber() { + var count json.Number + if err := h2.Get(CountKey, &count); err != nil { + return nil, fmt.Errorf(`failed to get %q field`, CountKey) + } + v, err := count.Float64() + if err != nil { + return nil, fmt.Errorf("failed to convert 'p2c' to float64: %w", err) + } + countFlt = v + } else { + var count float64 + if err := h2.Get(CountKey, &count); err != nil { + return nil, fmt.Errorf(`failed to get %q field`, CountKey) + } + countFlt = count + } + + muSettings.RLock() + maxCount := maxPBES2Count + muSettings.RUnlock() + if countFlt > float64(maxCount) { + return nil, fmt.Errorf("invalid 'p2c' value") + } + salt, err := base64.DecodeString(saltB64) + if err != nil { + return nil, fmt.Errorf(`failed to b64-decode 'salt': %w`, err) + } + dec.KeySalt(salt) + dec.KeyCount(int(countFlt)) + } + + plaintext, err := dec.Decrypt(recipient, msg.cipherText, msg) + if err != nil { + return nil, fmt.Errorf(`jwe.Decrypt: decryption failed: %w`, err) + } + + if v, ok := h2.Compression(); ok && v == jwa.Deflate() { + buf, err := uncompress(plaintext, dc.maxDecompressBufferSize) + if err != nil { + return nil, fmt.Errorf(`jwe.Derypt: failed to uncompress payload: %w`, err) + } + plaintext = buf + } + + if plaintext == nil { + return nil, fmt.Errorf(`failed to find matching recipient`) + } + + return plaintext, nil +} + +// encryptContext holds the state during JWE encryption, similar to JWS signContext +type encryptContext struct { + calg jwa.ContentEncryptionAlgorithm + compression jwa.CompressionAlgorithm + format int + builders []*recipientBuilder + protected Headers +} + +var encryptContextPool = pool.New(allocEncryptContext, freeEncryptContext) + +func allocEncryptContext() *encryptContext { + return &encryptContext{ + calg: jwa.A256GCM(), + compression: jwa.NoCompress(), + format: fmtCompact, + } +} + +func freeEncryptContext(ec *encryptContext) *encryptContext { + ec.calg = jwa.A256GCM() + ec.compression = jwa.NoCompress() + ec.format = fmtCompact + ec.builders = ec.builders[:0] + ec.protected = nil + return ec +} + +func (ec *encryptContext) ProcessOptions(options []EncryptOption) error { + var mergeProtected bool + var useRawCEK bool + for _, option := range options { + switch option.Ident() { + case identKey{}: + var wk *withKey + if err := option.Value(&wk); err != nil { + return fmt.Errorf("jwe.encrypt: WithKey must be a *withKey: %w", err) + } + v, ok := wk.alg.(jwa.KeyEncryptionAlgorithm) + if !ok { + return fmt.Errorf("jwe.encrypt: WithKey() option must be specified using jwa.KeyEncryptionAlgorithm (got %T)", wk.alg) + } + if v == jwa.DIRECT() || v == jwa.ECDH_ES() { + useRawCEK = true + } + ec.builders = append(ec.builders, &recipientBuilder{alg: v, key: wk.key, headers: wk.headers}) + case identContentEncryptionAlgorithm{}: + var c jwa.ContentEncryptionAlgorithm + if err := option.Value(&c); err != nil { + return err + } + ec.calg = c + case identCompress{}: + var comp jwa.CompressionAlgorithm + if err := option.Value(&comp); err != nil { + return err + } + ec.compression = comp + case identMergeProtectedHeaders{}: + var mp bool + if err := option.Value(&mp); err != nil { + return err + } + mergeProtected = mp + case identProtectedHeaders{}: + var hdrs Headers + if err := option.Value(&hdrs); err != nil { + return err + } + if !mergeProtected || ec.protected == nil { + ec.protected = hdrs + } else { + merged, err := ec.protected.Merge(hdrs) + if err != nil { + return fmt.Errorf(`failed to merge headers: %w`, err) + } + ec.protected = merged + } + case identSerialization{}: + var fmtOpt int + if err := option.Value(&fmtOpt); err != nil { + return err + } + ec.format = fmtOpt + } + } + + // We need to have at least one builder + switch l := len(ec.builders); { + case l == 0: + return fmt.Errorf(`missing key encryption builders: use jwe.WithKey() to specify one`) + case l > 1: + if ec.format == fmtCompact { + return fmt.Errorf(`cannot use compact serialization when multiple recipients exist (check the number of WithKey() argument, or use WithJSON())`) + } + } + + if useRawCEK { + if len(ec.builders) != 1 { + return fmt.Errorf(`multiple recipients for ECDH-ES/DIRECT mode supported`) + } + } + + return nil +} + +var msgPool = pool.New(allocMessage, freeMessage) + +func allocMessage() *Message { + return &Message{ + recipients: make([]Recipient, 0, 1), + } +} + +func freeMessage(msg *Message) *Message { + msg.cipherText = nil + msg.initializationVector = nil + if hdr := msg.protectedHeaders; hdr != nil { + headerPool.Put(hdr) + } + msg.protectedHeaders = nil + msg.unprotectedHeaders = nil + msg.recipients = nil // reuse should be done elsewhere + msg.authenticatedData = nil + msg.tag = nil + msg.rawProtectedHeaders = nil + msg.storeProtectedHeaders = false + return msg +} + +var headerPool = pool.New(NewHeaders, freeHeaders) + +func freeHeaders(h Headers) Headers { + if c, ok := h.(interface{ clear() }); ok { + c.clear() + } + return h +} + +var recipientPool = pool.New(NewRecipient, freeRecipient) + +func freeRecipient(r Recipient) Recipient { + if h := r.Headers(); h != nil { + if c, ok := h.(interface{ clear() }); ok { + c.clear() + } + } + + if sr, ok := r.(*stdRecipient); ok { + sr.encryptedKey = nil + } + return r +} + +var recipientSlicePool = pool.NewSlicePool(allocRecipientSlice, freeRecipientSlice) + +func allocRecipientSlice() []Recipient { + return make([]Recipient, 0, 1) +} + +func freeRecipientSlice(rs []Recipient) []Recipient { + for _, r := range rs { + recipientPool.Put(r) + } + return rs[:0] +} + +func (ec *encryptContext) EncryptMessage(payload []byte, cek []byte) ([]byte, error) { + // Get protected headers from pool and copy contents from context + protected := headerPool.Get() + if userSupplied := ec.protected; userSupplied != nil { + ec.protected = nil // Clear from context + if err := userSupplied.Copy(protected); err != nil { + return nil, fmt.Errorf(`failed to copy protected headers: %w`, err) + } + } + + // There is exactly one content encrypter. + contentcrypt, err := content_crypt.NewGeneric(ec.calg) + if err != nil { + return nil, fmt.Errorf(`failed to create AES encrypter: %w`, err) + } + + // Generate CEK if not provided + if len(cek) <= 0 { + bk, err := keygen.Random(contentcrypt.KeySize()) + if err != nil { + return nil, fmt.Errorf(`failed to generate key: %w`, err) + } + cek = bk.Bytes() + } + + var useRawCEK bool + for _, builder := range ec.builders { + if builder.alg == jwa.DIRECT() || builder.alg == jwa.ECDH_ES() { + useRawCEK = true + break + } + } + + recipients := recipientSlicePool.GetCapacity(len(ec.builders)) + defer recipientSlicePool.Put(recipients) + + for i, builder := range ec.builders { + r := recipientPool.Get() + defer recipientPool.Put(r) + + // some builders require hint from the contentcrypt object + rawCEK, err := builder.Build(r, cek, ec.calg, contentcrypt) + if err != nil { + return nil, fmt.Errorf(`failed to create recipient #%d: %w`, i, err) + } + recipients = append(recipients, r) + + // Kinda feels weird, but if useRawCEK == true, we asserted earlier + // that len(builders) == 1, so this is OK + if useRawCEK { + cek = rawCEK + } + } + + if err := protected.Set(ContentEncryptionKey, ec.calg); err != nil { + return nil, fmt.Errorf(`failed to set "enc" in protected header: %w`, err) + } + + if ec.compression != jwa.NoCompress() { + payload, err = compress(payload) + if err != nil { + return nil, fmt.Errorf(`failed to compress payload before encryption: %w`, err) + } + if err := protected.Set(CompressionKey, ec.compression); err != nil { + return nil, fmt.Errorf(`failed to set "zip" in protected header: %w`, err) + } + } + + // If there's only one recipient, you want to include that in the + // protected header + if len(recipients) == 1 { + h, err := protected.Merge(recipients[0].Headers()) + if err != nil { + return nil, fmt.Errorf(`failed to merge protected headers: %w`, err) + } + protected = h + } + + aad, err := protected.Encode() + if err != nil { + return nil, fmt.Errorf(`failed to base64 encode protected headers: %w`, err) + } + + iv, ciphertext, tag, err := contentcrypt.Encrypt(cek, payload, aad) + if err != nil { + return nil, fmt.Errorf(`failed to encrypt payload: %w`, err) + } + + msg := msgPool.Get() + defer msgPool.Put(msg) + + if err := msg.Set(CipherTextKey, ciphertext); err != nil { + return nil, fmt.Errorf(`failed to set %s: %w`, CipherTextKey, err) + } + if err := msg.Set(InitializationVectorKey, iv); err != nil { + return nil, fmt.Errorf(`failed to set %s: %w`, InitializationVectorKey, err) + } + if err := msg.Set(ProtectedHeadersKey, protected); err != nil { + return nil, fmt.Errorf(`failed to set %s: %w`, ProtectedHeadersKey, err) + } + if err := msg.Set(RecipientsKey, recipients); err != nil { + return nil, fmt.Errorf(`failed to set %s: %w`, RecipientsKey, err) + } + if err := msg.Set(TagKey, tag); err != nil { + return nil, fmt.Errorf(`failed to set %s: %w`, TagKey, err) + } + + switch ec.format { + case fmtCompact: + return Compact(msg) + case fmtJSON: + return json.Marshal(msg) + case fmtJSONPretty: + return json.MarshalIndent(msg, "", " ") + default: + return nil, fmt.Errorf(`invalid serialization`) + } +} + +// Decrypt takes encrypted payload, and information required to decrypt the +// payload (e.g. the key encryption algorithm and the corresponding +// key to decrypt the JWE message) in its optional arguments. See +// the examples and list of options that return a DecryptOption for possible +// values. Upon successful decryptiond returns the decrypted payload. +// +// The JWE message can be either compact or full JSON format. +// +// When using `jwe.WithKeyEncryptionAlgorithm()`, you can pass a `jwa.KeyAlgorithm` +// for convenience: this is mainly to allow you to directly pass the result of `(jwk.Key).Algorithm()`. +// However, do note that while `(jwk.Key).Algorithm()` could very well contain key encryption +// algorithms, it could also contain other types of values, such as _signature algorithms_. +// In order for `jwe.Decrypt` to work properly, the `alg` parameter must be of type +// `jwa.KeyEncryptionAlgorithm` or otherwise it will cause an error. +// +// When using `jwe.WithKey()`, the value must be a private key. +// It can be either in its raw format (e.g. *rsa.PrivateKey) or a jwk.Key +// +// When the encrypted message is also compressed, the decompressed payload must be +// smaller than the size specified by the `jwe.WithMaxDecompressBufferSize` setting, +// which defaults to 10MB. If the decompressed payload is larger than this size, +// an error is returned. +// +// You can opt to change the MaxDecompressBufferSize setting globally, or on a +// per-call basis by passing the `jwe.WithMaxDecompressBufferSize` option to +// either `jwe.Settings()` or `jwe.Decrypt()`: +// +// jwe.Settings(jwe.WithMaxDecompressBufferSize(10*1024*1024)) // changes value globally +// jwe.Decrypt(..., jwe.WithMaxDecompressBufferSize(250*1024)) // changes just for this call +func Decrypt(buf []byte, options ...DecryptOption) ([]byte, error) { + dc := decryptContextPool.Get() + defer decryptContextPool.Put(dc) + + if err := dc.ProcessOptions(options); err != nil { + return nil, decryptError{fmt.Errorf(`jwe.Decrypt: failed to process options: %w`, err)} + } + + ret, err := dc.DecryptMessage(buf) + if err != nil { + return nil, decryptError{fmt.Errorf(`jwe.Decrypt: %w`, err)} + } + return ret, nil +} + +// Parse parses the JWE message into a Message object. The JWE message +// can be either compact or full JSON format. +// +// Parse() currently does not take any options, but the API accepts it +// in anticipation of future addition. +func Parse(buf []byte, _ ...ParseOption) (*Message, error) { + return parseJSONOrCompact(buf, false) +} + +// errors are wrapped within this function, because we call it directly +// from Decrypt as well. +func parseJSONOrCompact(buf []byte, storeProtectedHeaders bool) (*Message, error) { + buf = bytes.TrimSpace(buf) + if len(buf) == 0 { + return nil, parseError{fmt.Errorf(`jwe.Parse: empty buffer`)} + } + + var msg *Message + var err error + if buf[0] == tokens.OpenCurlyBracket { + msg, err = parseJSON(buf, storeProtectedHeaders) + } else { + msg, err = parseCompact(buf, storeProtectedHeaders) + } + + if err != nil { + return nil, parseError{fmt.Errorf(`jwe.Parse: %w`, err)} + } + return msg, nil +} + +// ParseString is the same as Parse, but takes a string. +func ParseString(s string) (*Message, error) { + msg, err := Parse([]byte(s)) + if err != nil { + return nil, parseError{fmt.Errorf(`jwe.ParseString: %w`, err)} + } + return msg, nil +} + +// ParseReader is the same as Parse, but takes an io.Reader. +func ParseReader(src io.Reader) (*Message, error) { + buf, err := io.ReadAll(src) + if err != nil { + return nil, parseError{fmt.Errorf(`jwe.ParseReader: failed to read from io.Reader: %w`, err)} + } + msg, err := Parse(buf) + if err != nil { + return nil, parseError{fmt.Errorf(`jwe.ParseReader: %w`, err)} + } + return msg, nil +} + +func parseJSON(buf []byte, storeProtectedHeaders bool) (*Message, error) { + m := NewMessage() + m.storeProtectedHeaders = storeProtectedHeaders + if err := json.Unmarshal(buf, &m); err != nil { + return nil, fmt.Errorf(`failed to parse JSON: %w`, err) + } + return m, nil +} + +func parseCompact(buf []byte, storeProtectedHeaders bool) (*Message, error) { + var parts [5][]byte + var ok bool + + for i := range 4 { + parts[i], buf, ok = bytes.Cut(buf, []byte{tokens.Period}) + if !ok { + return nil, fmt.Errorf(`compact JWE format must have five parts (%d)`, i+1) + } + } + // Validate that the last part does not contain more dots + if bytes.ContainsRune(buf, tokens.Period) { + return nil, errors.New(`compact JWE format must have five parts, not more`) + } + parts[4] = buf + + hdrbuf, err := base64.Decode(parts[0]) + if err != nil { + return nil, fmt.Errorf(`failed to parse first part of compact form: %w`, err) + } + + protected := NewHeaders() + if err := json.Unmarshal(hdrbuf, protected); err != nil { + return nil, fmt.Errorf(`failed to parse header JSON: %w`, err) + } + + ivbuf, err := base64.Decode(parts[2]) + if err != nil { + return nil, fmt.Errorf(`failed to base64 decode iv: %w`, err) + } + + ctbuf, err := base64.Decode(parts[3]) + if err != nil { + return nil, fmt.Errorf(`failed to base64 decode content: %w`, err) + } + + tagbuf, err := base64.Decode(parts[4]) + if err != nil { + return nil, fmt.Errorf(`failed to base64 decode tag: %w`, err) + } + + m := NewMessage() + if err := m.Set(CipherTextKey, ctbuf); err != nil { + return nil, fmt.Errorf(`failed to set %s: %w`, CipherTextKey, err) + } + if err := m.Set(InitializationVectorKey, ivbuf); err != nil { + return nil, fmt.Errorf(`failed to set %s: %w`, InitializationVectorKey, err) + } + if err := m.Set(ProtectedHeadersKey, protected); err != nil { + return nil, fmt.Errorf(`failed to set %s: %w`, ProtectedHeadersKey, err) + } + + if err := m.makeDummyRecipient(string(parts[1]), protected); err != nil { + return nil, fmt.Errorf(`failed to setup recipient: %w`, err) + } + + if err := m.Set(TagKey, tagbuf); err != nil { + return nil, fmt.Errorf(`failed to set %s: %w`, TagKey, err) + } + + if storeProtectedHeaders { + // This is later used for decryption. + m.rawProtectedHeaders = parts[0] + } + + return m, nil +} + +type CustomDecoder = json.CustomDecoder +type CustomDecodeFunc = json.CustomDecodeFunc + +// RegisterCustomField allows users to specify that a private field +// be decoded as an instance of the specified type. This option has +// a global effect. +// +// For example, suppose you have a custom field `x-birthday`, which +// you want to represent as a string formatted in RFC3339 in JSON, +// but want it back as `time.Time`. +// +// In such case you would register a custom field as follows +// +// jws.RegisterCustomField(`x-birthday`, time.Time{}) +// +// Then you can use a `time.Time` variable to extract the value +// of `x-birthday` field, instead of having to use `any` +// and later convert it to `time.Time` +// +// var bday time.Time +// _ = hdr.Get(`x-birthday`, &bday) +// +// If you need a more fine-tuned control over the decoding process, +// you can register a `CustomDecoder`. For example, below shows +// how to register a decoder that can parse RFC1123 format string: +// +// jwe.RegisterCustomField(`x-birthday`, jwe.CustomDecodeFunc(func(data []byte) (any, error) { +// return time.Parse(time.RFC1123, string(data)) +// })) +// +// Please note that use of custom fields can be problematic if you +// are using a library that does not implement MarshalJSON/UnmarshalJSON +// and you try to roundtrip from an object to JSON, and then back to an object. +// For example, in the above example, you can _parse_ time values formatted +// in the format specified in RFC822, but when you convert an object into +// JSON, it will be formatted in RFC3339, because that's what `time.Time` +// likes to do. To avoid this, it's always better to use a custom type +// that wraps your desired type (in this case `time.Time`) and implement +// MarshalJSON and UnmashalJSON. +func RegisterCustomField(name string, object any) { + registry.Register(name, object) +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwe/jwebb/BUILD.bazel b/vendor/github.com/lestrrat-go/jwx/v3/jwe/jwebb/BUILD.bazel new file mode 100644 index 00000000000..c410a05cdf7 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwe/jwebb/BUILD.bazel @@ -0,0 +1,43 @@ +load("@rules_go//go:def.bzl", "go_library", "go_test") + +go_library( + name = "jwebb", + srcs = [ + "content_cipher.go", + "key_decrypt_asymmetric.go", + "key_decrypt_symmetric.go", + "key_encrypt_asymmetric.go", + "key_encrypt_symmetric.go", + "key_encryption.go", + "keywrap.go", + ], + importpath = "github.com/lestrrat-go/jwx/v3/jwe/jwebb", + visibility = ["//jwe:__subpackages__"], + deps = [ + "//internal/keyconv", + "//internal/pool", + "//jwe/internal/cipher", + "//jwe/internal/concatkdf", + "//jwe/internal/content_crypt", + "//jwe/internal/keygen", + "//internal/tokens", + "@org_golang_x_crypto//pbkdf2", + ], +) + +go_test( + name = "jwebb_test", + srcs = [ + "decrypt_test.go", + "jwebb_test.go", + "keywrap_test.go", + ], + embed = [":jwebb"], + deps = [ + "//internal/jwxtest", + "//jwa", + "//jwe/internal/keygen", + "//internal/tokens", + "@com_github_stretchr_testify//require", + ], +) \ No newline at end of file diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwe/jwebb/content_cipher.go b/vendor/github.com/lestrrat-go/jwx/v3/jwe/jwebb/content_cipher.go new file mode 100644 index 00000000000..9078789d8d1 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwe/jwebb/content_cipher.go @@ -0,0 +1,34 @@ +package jwebb + +import ( + "fmt" + + "github.com/lestrrat-go/jwx/v3/internal/tokens" + "github.com/lestrrat-go/jwx/v3/jwe/internal/cipher" + "github.com/lestrrat-go/jwx/v3/jwe/internal/content_crypt" +) + +// ContentEncryptionIsSupported checks if the content encryption algorithm is supported +func ContentEncryptionIsSupported(alg string) bool { + switch alg { + case tokens.A128GCM, tokens.A192GCM, tokens.A256GCM, + tokens.A128CBC_HS256, tokens.A192CBC_HS384, tokens.A256CBC_HS512: + return true + default: + return false + } +} + +// CreateContentCipher creates a content encryption cipher for the given algorithm string +func CreateContentCipher(alg string) (content_crypt.Cipher, error) { + if !ContentEncryptionIsSupported(alg) { + return nil, fmt.Errorf(`invalid content cipher algorithm (%s)`, alg) + } + + cipher, err := cipher.NewAES(alg) + if err != nil { + return nil, fmt.Errorf(`failed to build content cipher for %s: %w`, alg, err) + } + + return cipher, nil +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwe/jwebb/jwebb.go b/vendor/github.com/lestrrat-go/jwx/v3/jwe/jwebb/jwebb.go new file mode 100644 index 00000000000..3768acef8b2 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwe/jwebb/jwebb.go @@ -0,0 +1,15 @@ +// Package jwebb provides the building blocks (hence the name "bb") for JWE operations. +// It should be thought of as a low-level API, almost akin to internal packages +// that should not be used directly by users of the jwx package. However, these exist +// to provide a more efficient way to perform JWE operations without the overhead of +// the higher-level jwe package to power-users who know what they are doing. +// +// This package is currently considered EXPERIMENTAL, and the API may change +// without notice. It is not recommended to use this package unless you are +// fully aware of the implications of using it. +// +// All bb packages in jwx follow the same design principles: +// 1. Does minimal checking of input parameters (for performance); callers need to ensure that the parameters are valid. +// 2. All exported functions are stringly typed (i.e. they do not take any parameters unless they absolutely have to). +// 3. Does not rely on other public jwx packages (they are standalone, except for internal packages). +package jwebb diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwe/jwebb/key_decrypt_asymmetric.go b/vendor/github.com/lestrrat-go/jwx/v3/jwe/jwebb/key_decrypt_asymmetric.go new file mode 100644 index 00000000000..ac079931769 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwe/jwebb/key_decrypt_asymmetric.go @@ -0,0 +1,177 @@ +package jwebb + +import ( + "crypto" + "crypto/aes" + "crypto/ecdh" + "crypto/rand" + "crypto/rsa" + "crypto/sha1" + "crypto/sha256" + "crypto/sha512" + "encoding/binary" + "fmt" + "hash" + + "github.com/lestrrat-go/jwx/v3/internal/keyconv" + "github.com/lestrrat-go/jwx/v3/internal/tokens" + "github.com/lestrrat-go/jwx/v3/jwe/internal/concatkdf" + "github.com/lestrrat-go/jwx/v3/jwe/internal/keygen" +) + +func contentEncryptionKeySize(ctalg string) (uint32, error) { + switch ctalg { + case tokens.A128GCM: + return tokens.KeySize16, nil + case tokens.A192GCM: + return tokens.KeySize24, nil + case tokens.A256GCM: + return tokens.KeySize32, nil + case tokens.A128CBC_HS256: + return tokens.KeySize32, nil + case tokens.A192CBC_HS384: + return tokens.KeySize48, nil + case tokens.A256CBC_HS512: + return tokens.KeySize64, nil + default: + return 0, fmt.Errorf(`unsupported content encryption algorithm %s`, ctalg) + } +} + +func KeyEncryptionECDHESKeySize(alg, ctalg string) (string, uint32, bool, error) { + switch alg { + case tokens.ECDH_ES: + keysize, err := contentEncryptionKeySize(ctalg) + if err != nil { + return "", 0, false, err + } + return ctalg, keysize, false, nil + case tokens.ECDH_ES_A128KW: + return alg, tokens.KeySize16, true, nil + case tokens.ECDH_ES_A192KW: + return alg, tokens.KeySize24, true, nil + case tokens.ECDH_ES_A256KW: + return alg, tokens.KeySize32, true, nil + default: + return "", 0, false, fmt.Errorf(`unsupported key encryption algorithm %s`, alg) + } +} + +func DeriveECDHES(alg string, apu, apv []byte, privkeyif, pubkeyif any, keysize uint32) ([]byte, error) { + pubinfo := make([]byte, 4) + binary.BigEndian.PutUint32(pubinfo, keysize*tokens.BitsPerByte) + + var privkey *ecdh.PrivateKey + var pubkey *ecdh.PublicKey + if err := keyconv.ECDHPrivateKey(&privkey, privkeyif); err != nil { + return nil, fmt.Errorf(`jwebb.DeriveECDHES: %w`, err) + } + if err := keyconv.ECDHPublicKey(&pubkey, pubkeyif); err != nil { + return nil, fmt.Errorf(`jwebb.DeriveECDHES: %w`, err) + } + + zBytes, err := privkey.ECDH(pubkey) + if err != nil { + return nil, fmt.Errorf(`jwebb.DeriveECDHES: unable to determine Z: %w`, err) + } + kdf := concatkdf.New(crypto.SHA256, []byte(alg), zBytes, apu, apv, pubinfo, []byte{}) + key := make([]byte, keysize) + if _, err := kdf.Read(key); err != nil { + return nil, fmt.Errorf(`jwebb.DeriveECDHES: failed to read kdf: %w`, err) + } + + return key, nil +} + +func KeyDecryptECDHESKeyWrap(_, enckey []byte, alg string, apu, apv []byte, privkey, pubkey any, keysize uint32) ([]byte, error) { + key, err := DeriveECDHES(alg, apu, apv, privkey, pubkey, keysize) + if err != nil { + return nil, fmt.Errorf(`failed to derive ECDHES encryption key: %w`, err) + } + + block, err := aes.NewCipher(key) + if err != nil { + return nil, fmt.Errorf(`failed to create cipher for ECDH-ES key wrap: %w`, err) + } + + return Unwrap(block, enckey) +} + +func KeyDecryptECDHES(_, _ []byte, alg string, apu, apv []byte, privkey, pubkey any, keysize uint32) ([]byte, error) { + key, err := DeriveECDHES(alg, apu, apv, privkey, pubkey, keysize) + if err != nil { + return nil, fmt.Errorf(`failed to derive ECDHES encryption key: %w`, err) + } + return key, nil +} + +// RSA key decryption functions + +func KeyDecryptRSA15(_, enckey []byte, privkeyif any, keysize int) ([]byte, error) { + var privkey *rsa.PrivateKey + if err := keyconv.RSAPrivateKey(&privkey, privkeyif); err != nil { + return nil, fmt.Errorf(`jwebb.KeyDecryptRSA15: %w`, err) + } + + // Perform some input validation. + expectedlen := privkey.PublicKey.N.BitLen() / tokens.BitsPerByte + if expectedlen != len(enckey) { + // Input size is incorrect, the encrypted payload should always match + // the size of the public modulus (e.g. using a 2048 bit key will + // produce 256 bytes of output). Reject this since it's invalid input. + return nil, fmt.Errorf( + "input size for key decrypt is incorrect (expected %d, got %d)", + expectedlen, + len(enckey), + ) + } + + // Generate a random CEK of the required size + bk, err := keygen.Random(keysize * tokens.RSAKeyGenMultiplier) + if err != nil { + return nil, fmt.Errorf(`failed to generate key`) + } + cek := bk.Bytes() + + // Use a defer/recover pattern to handle potential panics from DecryptPKCS1v15SessionKey + defer func() { + // DecryptPKCS1v15SessionKey sometimes panics on an invalid payload + // because of an index out of bounds error, which we want to ignore. + // This has been fixed in Go 1.3.1 (released 2014/08/13), the recover() + // only exists for preventing crashes with unpatched versions. + // See: https://groups.google.com/forum/#!topic/golang-dev/7ihX6Y6kx9k + // See: https://code.google.com/p/go/source/detail?r=58ee390ff31602edb66af41ed10901ec95904d33 + _ = recover() + }() + + // When decrypting an RSA-PKCS1v1.5 payload, we must take precautions to + // prevent chosen-ciphertext attacks as described in RFC 3218, "Preventing + // the Million Message Attack on Cryptographic Message Syntax". We are + // therefore deliberately ignoring errors here. + _ = rsa.DecryptPKCS1v15SessionKey(rand.Reader, privkey, enckey, cek) + + return cek, nil +} + +func KeyDecryptRSAOAEP(_, enckey []byte, alg string, privkeyif any) ([]byte, error) { + var privkey *rsa.PrivateKey + if err := keyconv.RSAPrivateKey(&privkey, privkeyif); err != nil { + return nil, fmt.Errorf(`jwebb.KeyDecryptRSAOAEP: %w`, err) + } + + var hash hash.Hash + switch alg { + case tokens.RSA_OAEP: + hash = sha1.New() + case tokens.RSA_OAEP_256: + hash = sha256.New() + case tokens.RSA_OAEP_384: + hash = sha512.New384() + case tokens.RSA_OAEP_512: + hash = sha512.New() + default: + return nil, fmt.Errorf(`failed to generate key encrypter for RSA-OAEP: RSA_OAEP/RSA_OAEP_256/RSA_OAEP_384/RSA_OAEP_512 required`) + } + + return rsa.DecryptOAEP(hash, rand.Reader, privkey, enckey, []byte{}) +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwe/jwebb/key_decrypt_symmetric.go b/vendor/github.com/lestrrat-go/jwx/v3/jwe/jwebb/key_decrypt_symmetric.go new file mode 100644 index 00000000000..c09e30a34ef --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwe/jwebb/key_decrypt_symmetric.go @@ -0,0 +1,91 @@ +package jwebb + +import ( + "crypto/aes" + cryptocipher "crypto/cipher" + "crypto/sha256" + "crypto/sha512" + "fmt" + "hash" + + "golang.org/x/crypto/pbkdf2" + + "github.com/lestrrat-go/jwx/v3/internal/tokens" +) + +// AES key wrap decryption functions + +// Use constants from tokens package +// No need to redefine them here + +func KeyDecryptAESKW(_, enckey []byte, _ string, sharedkey []byte) ([]byte, error) { + block, err := aes.NewCipher(sharedkey) + if err != nil { + return nil, fmt.Errorf(`failed to create cipher from shared key: %w`, err) + } + + cek, err := Unwrap(block, enckey) + if err != nil { + return nil, fmt.Errorf(`failed to unwrap data: %w`, err) + } + return cek, nil +} + +func KeyDecryptDirect(_, _ []byte, _ string, cek []byte) ([]byte, error) { + return cek, nil +} + +func KeyDecryptPBES2(_, enckey []byte, alg string, password []byte, salt []byte, count int) ([]byte, error) { + var hashFunc func() hash.Hash + var keylen int + + switch alg { + case tokens.PBES2_HS256_A128KW: + hashFunc = sha256.New + keylen = tokens.KeySize16 + case tokens.PBES2_HS384_A192KW: + hashFunc = sha512.New384 + keylen = tokens.KeySize24 + case tokens.PBES2_HS512_A256KW: + hashFunc = sha512.New + keylen = tokens.KeySize32 + default: + return nil, fmt.Errorf(`unsupported PBES2 algorithm: %s`, alg) + } + + // Derive key using PBKDF2 + derivedKey := pbkdf2.Key(password, salt, count, keylen, hashFunc) + + // Use the derived key for AES key wrap + return KeyDecryptAESKW(nil, enckey, alg, derivedKey) +} + +func KeyDecryptAESGCMKW(recipientKey, _ []byte, _ string, sharedkey []byte, iv []byte, tag []byte) ([]byte, error) { + if len(iv) != tokens.GCMIVSize { + return nil, fmt.Errorf("GCM requires 96-bit iv, got %d", len(iv)*tokens.BitsPerByte) + } + if len(tag) != tokens.GCMTagSize { + return nil, fmt.Errorf("GCM requires 128-bit tag, got %d", len(tag)*tokens.BitsPerByte) + } + + block, err := aes.NewCipher(sharedkey) + if err != nil { + return nil, fmt.Errorf(`failed to create new AES cipher: %w`, err) + } + + aesgcm, err := cryptocipher.NewGCM(block) + if err != nil { + return nil, fmt.Errorf(`failed to create new GCM wrap: %w`, err) + } + + // Combine recipient key and tag for GCM decryption + ciphertext := recipientKey[:] + ciphertext = append(ciphertext, tag...) + + jek, err := aesgcm.Open(nil, iv, ciphertext, nil) + if err != nil { + return nil, fmt.Errorf(`failed to decode key: %w`, err) + } + + return jek, nil +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwe/jwebb/key_encrypt_asymmetric.go b/vendor/github.com/lestrrat-go/jwx/v3/jwe/jwebb/key_encrypt_asymmetric.go new file mode 100644 index 00000000000..6f008173c8a --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwe/jwebb/key_encrypt_asymmetric.go @@ -0,0 +1,147 @@ +package jwebb + +import ( + "crypto/aes" + "crypto/ecdh" + "crypto/ecdsa" + "crypto/rand" + "crypto/rsa" + "crypto/sha1" + "crypto/sha256" + "crypto/sha512" + "fmt" + "hash" + + "github.com/lestrrat-go/jwx/v3/internal/tokens" + "github.com/lestrrat-go/jwx/v3/jwe/internal/keygen" +) + +// KeyEncryptRSA15 encrypts the CEK using RSA PKCS#1 v1.5 +func KeyEncryptRSA15(cek []byte, _ string, pubkey *rsa.PublicKey) (keygen.ByteSource, error) { + encrypted, err := rsa.EncryptPKCS1v15(rand.Reader, pubkey, cek) + if err != nil { + return nil, fmt.Errorf(`failed to encrypt using PKCS1v15: %w`, err) + } + return keygen.ByteKey(encrypted), nil +} + +// KeyEncryptRSAOAEP encrypts the CEK using RSA OAEP +func KeyEncryptRSAOAEP(cek []byte, alg string, pubkey *rsa.PublicKey) (keygen.ByteSource, error) { + var hash hash.Hash + switch alg { + case tokens.RSA_OAEP: + hash = sha1.New() + case tokens.RSA_OAEP_256: + hash = sha256.New() + case tokens.RSA_OAEP_384: + hash = sha512.New384() + case tokens.RSA_OAEP_512: + hash = sha512.New() + default: + return nil, fmt.Errorf(`failed to generate key encrypter for RSA-OAEP: RSA_OAEP/RSA_OAEP_256/RSA_OAEP_384/RSA_OAEP_512 required`) + } + + encrypted, err := rsa.EncryptOAEP(hash, rand.Reader, pubkey, cek, []byte{}) + if err != nil { + return nil, fmt.Errorf(`failed to OAEP encrypt: %w`, err) + } + return keygen.ByteKey(encrypted), nil +} + +// generateECDHESKeyECDSA generates the key material for ECDSA keys using ECDH-ES +func generateECDHESKeyECDSA(alg string, calg string, keysize uint32, pubkey *ecdsa.PublicKey, apu, apv []byte) (keygen.ByteWithECPublicKey, error) { + // Generate the key directly + kg, err := keygen.Ecdhes(alg, calg, int(keysize), pubkey, apu, apv) + if err != nil { + return keygen.ByteWithECPublicKey{}, fmt.Errorf(`failed to generate ECDSA key: %w`, err) + } + + bwpk, ok := kg.(keygen.ByteWithECPublicKey) + if !ok { + return keygen.ByteWithECPublicKey{}, fmt.Errorf(`key generator generated invalid key (expected ByteWithECPublicKey)`) + } + + return bwpk, nil +} + +// generateECDHESKeyX25519 generates the key material for X25519 keys using ECDH-ES +func generateECDHESKeyX25519(alg string, calg string, keysize uint32, pubkey *ecdh.PublicKey) (keygen.ByteWithECPublicKey, error) { + // Generate the key directly + kg, err := keygen.X25519(alg, calg, int(keysize), pubkey) + if err != nil { + return keygen.ByteWithECPublicKey{}, fmt.Errorf(`failed to generate X25519 key: %w`, err) + } + + bwpk, ok := kg.(keygen.ByteWithECPublicKey) + if !ok { + return keygen.ByteWithECPublicKey{}, fmt.Errorf(`key generator generated invalid key (expected ByteWithECPublicKey)`) + } + + return bwpk, nil +} + +// KeyEncryptECDHESKeyWrapECDSA encrypts the CEK using ECDH-ES with key wrapping for ECDSA keys +func KeyEncryptECDHESKeyWrapECDSA(cek []byte, alg string, apu, apv []byte, pubkey *ecdsa.PublicKey, keysize uint32, calg string) (keygen.ByteSource, error) { + bwpk, err := generateECDHESKeyECDSA(alg, calg, keysize, pubkey, apu, apv) + if err != nil { + return nil, err + } + + // For key wrapping algorithms, wrap the CEK with the generated key + block, err := aes.NewCipher(bwpk.Bytes()) + if err != nil { + return nil, fmt.Errorf(`failed to generate cipher from generated key: %w`, err) + } + + jek, err := Wrap(block, cek) + if err != nil { + return nil, fmt.Errorf(`failed to wrap data: %w`, err) + } + + bwpk.ByteKey = keygen.ByteKey(jek) + return bwpk, nil +} + +// KeyEncryptECDHESKeyWrapX25519 encrypts the CEK using ECDH-ES with key wrapping for X25519 keys +func KeyEncryptECDHESKeyWrapX25519(cek []byte, alg string, _ []byte, _ []byte, pubkey *ecdh.PublicKey, keysize uint32, calg string) (keygen.ByteSource, error) { + bwpk, err := generateECDHESKeyX25519(alg, calg, keysize, pubkey) + if err != nil { + return nil, err + } + + // For key wrapping algorithms, wrap the CEK with the generated key + block, err := aes.NewCipher(bwpk.Bytes()) + if err != nil { + return nil, fmt.Errorf(`failed to generate cipher from generated key: %w`, err) + } + + jek, err := Wrap(block, cek) + if err != nil { + return nil, fmt.Errorf(`failed to wrap data: %w`, err) + } + + bwpk.ByteKey = keygen.ByteKey(jek) + return bwpk, nil +} + +// KeyEncryptECDHESECDSA encrypts using ECDH-ES direct (no key wrapping) for ECDSA keys +func KeyEncryptECDHESECDSA(_ []byte, alg string, apu, apv []byte, pubkey *ecdsa.PublicKey, keysize uint32, calg string) (keygen.ByteSource, error) { + bwpk, err := generateECDHESKeyECDSA(alg, calg, keysize, pubkey, apu, apv) + if err != nil { + return nil, err + } + + // For direct ECDH-ES, return the generated key directly + return bwpk, nil +} + +// KeyEncryptECDHESX25519 encrypts using ECDH-ES direct (no key wrapping) for X25519 keys +func KeyEncryptECDHESX25519(_ []byte, alg string, _, _ []byte, pubkey *ecdh.PublicKey, keysize uint32, calg string) (keygen.ByteSource, error) { + bwpk, err := generateECDHESKeyX25519(alg, calg, keysize, pubkey) + if err != nil { + return nil, err + } + + // For direct ECDH-ES, return the generated key directly + return bwpk, nil +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwe/jwebb/key_encrypt_symmetric.go b/vendor/github.com/lestrrat-go/jwx/v3/jwe/jwebb/key_encrypt_symmetric.go new file mode 100644 index 00000000000..d489aaba284 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwe/jwebb/key_encrypt_symmetric.go @@ -0,0 +1,115 @@ +package jwebb + +import ( + "crypto/aes" + cryptocipher "crypto/cipher" + "crypto/rand" + "crypto/sha256" + "crypto/sha512" + "fmt" + "hash" + "io" + + "golang.org/x/crypto/pbkdf2" + + "github.com/lestrrat-go/jwx/v3/internal/tokens" + "github.com/lestrrat-go/jwx/v3/jwe/internal/keygen" +) + +// KeyEncryptAESKW encrypts the CEK using AES key wrap +func KeyEncryptAESKW(cek []byte, _ string, sharedkey []byte) (keygen.ByteSource, error) { + block, err := aes.NewCipher(sharedkey) + if err != nil { + return nil, fmt.Errorf(`failed to create cipher from shared key: %w`, err) + } + + encrypted, err := Wrap(block, cek) + if err != nil { + return nil, fmt.Errorf(`failed to wrap data: %w`, err) + } + return keygen.ByteKey(encrypted), nil +} + +// KeyEncryptDirect returns the CEK directly for DIRECT algorithm +func KeyEncryptDirect(_ []byte, _ string, sharedkey []byte) (keygen.ByteSource, error) { + return keygen.ByteKey(sharedkey), nil +} + +// KeyEncryptPBES2 encrypts the CEK using PBES2 password-based encryption +func KeyEncryptPBES2(cek []byte, alg string, password []byte) (keygen.ByteSource, error) { + var hashFunc func() hash.Hash + var keylen int + + switch alg { + case tokens.PBES2_HS256_A128KW: + hashFunc = sha256.New + keylen = tokens.KeySize16 + case tokens.PBES2_HS384_A192KW: + hashFunc = sha512.New384 + keylen = tokens.KeySize24 + case tokens.PBES2_HS512_A256KW: + hashFunc = sha512.New + keylen = tokens.KeySize32 + default: + return nil, fmt.Errorf(`unsupported PBES2 algorithm: %s`, alg) + } + + count := tokens.PBES2DefaultIterations + salt := make([]byte, keylen) + _, err := io.ReadFull(rand.Reader, salt) + if err != nil { + return nil, fmt.Errorf(`failed to get random salt: %w`, err) + } + + fullsalt := []byte(alg) + fullsalt = append(fullsalt, byte(tokens.PBES2NullByteSeparator)) + fullsalt = append(fullsalt, salt...) + + // Derive key using PBKDF2 + derivedKey := pbkdf2.Key(password, fullsalt, count, keylen, hashFunc) + + // Use the derived key for AES key wrap + block, err := aes.NewCipher(derivedKey) + if err != nil { + return nil, fmt.Errorf(`failed to create cipher from derived key: %w`, err) + } + encrypted, err := Wrap(block, cek) + if err != nil { + return nil, fmt.Errorf(`failed to wrap data: %w`, err) + } + + return keygen.ByteWithSaltAndCount{ + ByteKey: encrypted, + Salt: salt, + Count: count, + }, nil +} + +// KeyEncryptAESGCMKW encrypts the CEK using AES GCM key wrap +func KeyEncryptAESGCMKW(cek []byte, _ string, sharedkey []byte) (keygen.ByteSource, error) { + block, err := aes.NewCipher(sharedkey) + if err != nil { + return nil, fmt.Errorf(`failed to create new AES cipher: %w`, err) + } + + aesgcm, err := cryptocipher.NewGCM(block) + if err != nil { + return nil, fmt.Errorf(`failed to create new GCM wrap: %w`, err) + } + + iv := make([]byte, aesgcm.NonceSize()) + _, err = io.ReadFull(rand.Reader, iv) + if err != nil { + return nil, fmt.Errorf(`failed to get random iv: %w`, err) + } + + encrypted := aesgcm.Seal(nil, iv, cek, nil) + tag := encrypted[len(encrypted)-aesgcm.Overhead():] + ciphertext := encrypted[:len(encrypted)-aesgcm.Overhead()] + + return keygen.ByteWithIVAndTag{ + ByteKey: ciphertext, + IV: iv, + Tag: tag, + }, nil +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwe/jwebb/key_encryption.go b/vendor/github.com/lestrrat-go/jwx/v3/jwe/jwebb/key_encryption.go new file mode 100644 index 00000000000..ce39352fc5d --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwe/jwebb/key_encryption.go @@ -0,0 +1,70 @@ +package jwebb + +import ( + "github.com/lestrrat-go/jwx/v3/internal/tokens" +) + +// IsECDHES checks if the algorithm is an ECDH-ES based algorithm +func IsECDHES(alg string) bool { + switch alg { + case tokens.ECDH_ES, tokens.ECDH_ES_A128KW, tokens.ECDH_ES_A192KW, tokens.ECDH_ES_A256KW: + return true + default: + return false + } +} + +// IsRSA15 checks if the algorithm is RSA1_5 +func IsRSA15(alg string) bool { + return alg == tokens.RSA1_5 +} + +// IsRSAOAEP checks if the algorithm is an RSA-OAEP based algorithm +func IsRSAOAEP(alg string) bool { + switch alg { + case tokens.RSA_OAEP, tokens.RSA_OAEP_256, tokens.RSA_OAEP_384, tokens.RSA_OAEP_512: + return true + default: + return false + } +} + +// IsAESKW checks if the algorithm is an AES key wrap algorithm +func IsAESKW(alg string) bool { + switch alg { + case tokens.A128KW, tokens.A192KW, tokens.A256KW: + return true + default: + return false + } +} + +// IsAESGCMKW checks if the algorithm is an AES-GCM key wrap algorithm +func IsAESGCMKW(alg string) bool { + switch alg { + case tokens.A128GCMKW, tokens.A192GCMKW, tokens.A256GCMKW: + return true + default: + return false + } +} + +// IsPBES2 checks if the algorithm is a PBES2 based algorithm +func IsPBES2(alg string) bool { + switch alg { + case tokens.PBES2_HS256_A128KW, tokens.PBES2_HS384_A192KW, tokens.PBES2_HS512_A256KW: + return true + default: + return false + } +} + +// IsDirect checks if the algorithm is direct encryption +func IsDirect(alg string) bool { + return alg == tokens.DIRECT +} + +// IsSymmetric checks if the algorithm is a symmetric key encryption algorithm +func IsSymmetric(alg string) bool { + return IsAESKW(alg) || IsAESGCMKW(alg) || IsPBES2(alg) || IsDirect(alg) +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwe/jwebb/keywrap.go b/vendor/github.com/lestrrat-go/jwx/v3/jwe/jwebb/keywrap.go new file mode 100644 index 00000000000..0792d6cb8e3 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwe/jwebb/keywrap.go @@ -0,0 +1,110 @@ +package jwebb + +import ( + "crypto/cipher" + "crypto/subtle" + "encoding/binary" + "fmt" + + "github.com/lestrrat-go/jwx/v3/internal/pool" + "github.com/lestrrat-go/jwx/v3/internal/tokens" +) + +var keywrapDefaultIV = []byte{0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6} + +func Wrap(kek cipher.Block, cek []byte) ([]byte, error) { + if len(cek)%tokens.KeywrapBlockSize != 0 { + return nil, fmt.Errorf(`keywrap input must be %d byte blocks`, tokens.KeywrapBlockSize) + } + + n := len(cek) / tokens.KeywrapChunkLen + r := make([][]byte, n) + + for i := range n { + r[i] = make([]byte, tokens.KeywrapChunkLen) + copy(r[i], cek[i*tokens.KeywrapChunkLen:]) + } + + buffer := pool.ByteSlice().GetCapacity(tokens.KeywrapChunkLen * 2) + defer pool.ByteSlice().Put(buffer) + // the byte slice has the capacity, but len is 0 + buffer = buffer[:tokens.KeywrapChunkLen*2] + + tBytes := pool.ByteSlice().GetCapacity(tokens.KeywrapChunkLen) + defer pool.ByteSlice().Put(tBytes) + // the byte slice has the capacity, but len is 0 + tBytes = tBytes[:tokens.KeywrapChunkLen] + + copy(buffer, keywrapDefaultIV) + + for t := range tokens.KeywrapRounds * n { + copy(buffer[tokens.KeywrapChunkLen:], r[t%n]) + + kek.Encrypt(buffer, buffer) + + binary.BigEndian.PutUint64(tBytes, uint64(t+1)) + + for i := range tokens.KeywrapChunkLen { + buffer[i] = buffer[i] ^ tBytes[i] + } + copy(r[t%n], buffer[tokens.KeywrapChunkLen:]) + } + + out := make([]byte, (n+1)*tokens.KeywrapChunkLen) + copy(out, buffer[:tokens.KeywrapChunkLen]) + for i := range r { + copy(out[(i+1)*tokens.KeywrapBlockSize:], r[i]) + } + + return out, nil +} + +func Unwrap(block cipher.Block, ciphertxt []byte) ([]byte, error) { + if len(ciphertxt)%tokens.KeywrapChunkLen != 0 { + return nil, fmt.Errorf(`keyunwrap input must be %d byte blocks`, tokens.KeywrapChunkLen) + } + + n := (len(ciphertxt) / tokens.KeywrapChunkLen) - 1 + r := make([][]byte, n) + + for i := range r { + r[i] = make([]byte, tokens.KeywrapChunkLen) + copy(r[i], ciphertxt[(i+1)*tokens.KeywrapChunkLen:]) + } + + buffer := pool.ByteSlice().GetCapacity(tokens.KeywrapChunkLen * 2) + defer pool.ByteSlice().Put(buffer) + // the byte slice has the capacity, but len is 0 + buffer = buffer[:tokens.KeywrapChunkLen*2] + + tBytes := pool.ByteSlice().GetCapacity(tokens.KeywrapChunkLen) + defer pool.ByteSlice().Put(tBytes) + // the byte slice has the capacity, but len is 0 + tBytes = tBytes[:tokens.KeywrapChunkLen] + + copy(buffer[:tokens.KeywrapChunkLen], ciphertxt[:tokens.KeywrapChunkLen]) + + for t := tokens.KeywrapRounds*n - 1; t >= 0; t-- { + binary.BigEndian.PutUint64(tBytes, uint64(t+1)) + + for i := range tokens.KeywrapChunkLen { + buffer[i] = buffer[i] ^ tBytes[i] + } + copy(buffer[tokens.KeywrapChunkLen:], r[t%n]) + + block.Decrypt(buffer, buffer) + + copy(r[t%n], buffer[tokens.KeywrapChunkLen:]) + } + + if subtle.ConstantTimeCompare(buffer[:tokens.KeywrapChunkLen], keywrapDefaultIV) == 0 { + return nil, fmt.Errorf(`key unwrap: failed to unwrap key`) + } + + out := make([]byte, n*tokens.KeywrapChunkLen) + for i := range r { + copy(out[i*tokens.KeywrapChunkLen:], r[i]) + } + + return out, nil +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwe/key_provider.go b/vendor/github.com/lestrrat-go/jwx/v3/jwe/key_provider.go new file mode 100644 index 00000000000..05adc045178 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwe/key_provider.go @@ -0,0 +1,163 @@ +package jwe + +import ( + "context" + "fmt" + "sync" + + "github.com/lestrrat-go/jwx/v3/jwa" + "github.com/lestrrat-go/jwx/v3/jwk" +) + +// KeyProvider is responsible for providing key(s) to encrypt or decrypt a payload. +// Multiple `jwe.KeyProvider`s can be passed to `jwe.Encrypt()` or `jwe.Decrypt()` +// +// `jwe.Encrypt()` can only accept static key providers via `jwe.WithKey()`, +// while `jwe.Decrypt()` can accept `jwe.WithKey()`, `jwe.WithKeySet()`, +// and `jwe.WithKeyProvider()`. +// +// Understanding how this works is crucial to learn how this package works. +// Here we will use `jwe.Decrypt()` as an example to show how the `KeyProvider` +// works. +// +// `jwe.Encrypt()` is straightforward: the content encryption key is encrypted +// using the provided keys, and JWS recipient objects are created for each. +// +// `jwe.Decrypt()` is a bit more involved, because there are cases you +// will want to compute/deduce/guess the keys that you would like to +// use for decryption. +// +// The first thing that `jwe.Decrypt()` needs to do is to collect the +// KeyProviders from the option list that the user provided (presented in pseudocode): +// +// keyProviders := filterKeyProviders(options) +// +// Then, remember that a JWE message may contain multiple recipients in the +// message. For each recipient, we call on the KeyProviders to give us +// the key(s) to use on this CEK: +// +// for r in msg.Recipients { +// for kp in keyProviders { +// kp.FetchKeys(ctx, sink, r, msg) +// ... +// } +// } +// +// The `sink` argument passed to the KeyProvider is a temporary storage +// for the keys (either a jwk.Key or a "raw" key). The `KeyProvider` +// is responsible for sending keys into the `sink`. +// +// When called, the `KeyProvider` created by `jwe.WithKey()` sends the same key, +// `jwe.WithKeySet()` sends keys that matches a particular `kid` and `alg`, +// and finally `jwe.WithKeyProvider()` allows you to execute arbitrary +// logic to provide keys. If you are providing a custom `KeyProvider`, +// you should execute the necessary checks or retrieval of keys, and +// then send the key(s) to the sink: +// +// sink.Key(alg, key) +// +// These keys are then retrieved and tried for each recipient, until +// a match is found: +// +// keys := sink.Keys() +// for key in keys { +// if decryptJWEKey(recipient.EncryptedKey(), key) { +// return OK +// } +// } +type KeyProvider interface { + FetchKeys(context.Context, KeySink, Recipient, *Message) error +} + +// KeySink is a data storage where `jwe.KeyProvider` objects should +// send their keys to. +type KeySink interface { + Key(jwa.KeyEncryptionAlgorithm, any) +} + +type algKeyPair struct { + alg jwa.KeyAlgorithm + key any +} + +type algKeySink struct { + mu sync.Mutex + list []algKeyPair +} + +func (s *algKeySink) Key(alg jwa.KeyEncryptionAlgorithm, key any) { + s.mu.Lock() + s.list = append(s.list, algKeyPair{alg, key}) + s.mu.Unlock() +} + +type staticKeyProvider struct { + alg jwa.KeyEncryptionAlgorithm + key any +} + +func (kp *staticKeyProvider) FetchKeys(_ context.Context, sink KeySink, _ Recipient, _ *Message) error { + sink.Key(kp.alg, kp.key) + return nil +} + +type keySetProvider struct { + set jwk.Set + requireKid bool +} + +func (kp *keySetProvider) selectKey(sink KeySink, key jwk.Key, _ Recipient, _ *Message) error { + if usage, ok := key.KeyUsage(); ok { + if usage != "" && usage != jwk.ForEncryption.String() { + return nil + } + } + + if v, ok := key.Algorithm(); ok { + kalg, ok := jwa.LookupKeyEncryptionAlgorithm(v.String()) + if !ok { + return fmt.Errorf(`invalid key encryption algorithm %s`, v) + } + + sink.Key(kalg, key) + return nil + } + + return nil +} + +func (kp *keySetProvider) FetchKeys(_ context.Context, sink KeySink, r Recipient, msg *Message) error { + if kp.requireKid { + var key jwk.Key + + wantedKid, ok := r.Headers().KeyID() + if !ok || wantedKid == "" { + return fmt.Errorf(`failed to find matching key: no key ID ("kid") specified in token but multiple keys available in key set`) + } + // Otherwise we better be able to look up the key, baby. + v, ok := kp.set.LookupKeyID(wantedKid) + if !ok { + return fmt.Errorf(`failed to find key with key ID %q in key set`, wantedKid) + } + key = v + + return kp.selectKey(sink, key, r, msg) + } + + for i := range kp.set.Len() { + key, _ := kp.set.Key(i) + if err := kp.selectKey(sink, key, r, msg); err != nil { + continue + } + } + return nil +} + +// KeyProviderFunc is a type of KeyProvider that is implemented by +// a single function. You can use this to create ad-hoc `KeyProvider` +// instances. +type KeyProviderFunc func(context.Context, KeySink, Recipient, *Message) error + +func (kp KeyProviderFunc) FetchKeys(ctx context.Context, sink KeySink, r Recipient, msg *Message) error { + return kp(ctx, sink, r, msg) +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwe/message.go b/vendor/github.com/lestrrat-go/jwx/v3/jwe/message.go new file mode 100644 index 00000000000..13cf3dec830 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwe/message.go @@ -0,0 +1,546 @@ +package jwe + +import ( + "fmt" + "sort" + "strings" + + "github.com/lestrrat-go/jwx/v3/internal/base64" + "github.com/lestrrat-go/jwx/v3/internal/json" + "github.com/lestrrat-go/jwx/v3/internal/pool" + "github.com/lestrrat-go/jwx/v3/internal/tokens" +) + +// NewRecipient creates a Recipient object +func NewRecipient() Recipient { + return &stdRecipient{ + headers: NewHeaders(), + } +} + +func (r *stdRecipient) SetHeaders(h Headers) error { + r.headers = h + return nil +} + +func (r *stdRecipient) SetEncryptedKey(v []byte) error { + r.encryptedKey = v + return nil +} + +func (r *stdRecipient) Headers() Headers { + return r.headers +} + +func (r *stdRecipient) EncryptedKey() []byte { + return r.encryptedKey +} + +type recipientMarshalProxy struct { + Headers Headers `json:"header"` + EncryptedKey string `json:"encrypted_key"` +} + +func (r *stdRecipient) UnmarshalJSON(buf []byte) error { + var proxy recipientMarshalProxy + proxy.Headers = NewHeaders() + if err := json.Unmarshal(buf, &proxy); err != nil { + return fmt.Errorf(`failed to unmarshal json into recipient: %w`, err) + } + + r.headers = proxy.Headers + decoded, err := base64.DecodeString(proxy.EncryptedKey) + if err != nil { + return fmt.Errorf(`failed to decode "encrypted_key": %w`, err) + } + r.encryptedKey = decoded + return nil +} + +func (r *stdRecipient) MarshalJSON() ([]byte, error) { + buf := pool.BytesBuffer().Get() + defer pool.BytesBuffer().Put(buf) + + buf.WriteString(`{"header":`) + hdrbuf, err := json.Marshal(r.headers) + if err != nil { + return nil, fmt.Errorf(`failed to marshal recipient header: %w`, err) + } + buf.Write(hdrbuf) + buf.WriteString(`,"encrypted_key":"`) + buf.WriteString(base64.EncodeToString(r.encryptedKey)) + buf.WriteString(`"}`) + + ret := make([]byte, buf.Len()) + copy(ret, buf.Bytes()) + return ret, nil +} + +// NewMessage creates a new message +func NewMessage() *Message { + return &Message{} +} + +func (m *Message) AuthenticatedData() []byte { + return m.authenticatedData +} + +func (m *Message) CipherText() []byte { + return m.cipherText +} + +func (m *Message) InitializationVector() []byte { + return m.initializationVector +} + +func (m *Message) Tag() []byte { + return m.tag +} + +func (m *Message) ProtectedHeaders() Headers { + return m.protectedHeaders +} + +func (m *Message) Recipients() []Recipient { + return m.recipients +} + +func (m *Message) UnprotectedHeaders() Headers { + return m.unprotectedHeaders +} + +const ( + AuthenticatedDataKey = "aad" + CipherTextKey = "ciphertext" + CountKey = "p2c" + InitializationVectorKey = "iv" + ProtectedHeadersKey = "protected" + RecipientsKey = "recipients" + SaltKey = "p2s" + TagKey = "tag" + UnprotectedHeadersKey = "unprotected" + HeadersKey = "header" + EncryptedKeyKey = "encrypted_key" +) + +func (m *Message) Set(k string, v any) error { + switch k { + case AuthenticatedDataKey: + buf, ok := v.([]byte) + if !ok { + return fmt.Errorf(`invalid value %T for %s key`, v, AuthenticatedDataKey) + } + m.authenticatedData = buf + case CipherTextKey: + buf, ok := v.([]byte) + if !ok { + return fmt.Errorf(`invalid value %T for %s key`, v, CipherTextKey) + } + m.cipherText = buf + case InitializationVectorKey: + buf, ok := v.([]byte) + if !ok { + return fmt.Errorf(`invalid value %T for %s key`, v, InitializationVectorKey) + } + m.initializationVector = buf + case ProtectedHeadersKey: + cv, ok := v.(Headers) + if !ok { + return fmt.Errorf(`invalid value %T for %s key`, v, ProtectedHeadersKey) + } + m.protectedHeaders = cv + case RecipientsKey: + cv, ok := v.([]Recipient) + if !ok { + return fmt.Errorf(`invalid value %T for %s key`, v, RecipientsKey) + } + m.recipients = cv + case TagKey: + buf, ok := v.([]byte) + if !ok { + return fmt.Errorf(`invalid value %T for %s key`, v, TagKey) + } + m.tag = buf + case UnprotectedHeadersKey: + cv, ok := v.(Headers) + if !ok { + return fmt.Errorf(`invalid value %T for %s key`, v, UnprotectedHeadersKey) + } + m.unprotectedHeaders = cv + default: + if m.unprotectedHeaders == nil { + m.unprotectedHeaders = NewHeaders() + } + return m.unprotectedHeaders.Set(k, v) + } + return nil +} + +type messageMarshalProxy struct { + AuthenticatedData string `json:"aad,omitempty"` + CipherText string `json:"ciphertext"` + InitializationVector string `json:"iv,omitempty"` + ProtectedHeaders json.RawMessage `json:"protected"` + Recipients []json.RawMessage `json:"recipients,omitempty"` + Tag string `json:"tag,omitempty"` + UnprotectedHeaders Headers `json:"unprotected,omitempty"` + + // For flattened structure. Headers is NOT a Headers type, + // so that we can detect its presence by checking proxy.Headers != nil + Headers json.RawMessage `json:"header,omitempty"` + EncryptedKey string `json:"encrypted_key,omitempty"` +} + +type jsonKV struct { + Key string + Value string +} + +func (m *Message) MarshalJSON() ([]byte, error) { + // This is slightly convoluted, but we need to encode the + // protected headers, so we do it by hand + buf := pool.BytesBuffer().Get() + defer pool.BytesBuffer().Put(buf) + enc := json.NewEncoder(buf) + + var fields []jsonKV + + if cipherText := m.CipherText(); len(cipherText) > 0 { + buf.Reset() + if err := enc.Encode(base64.EncodeToString(cipherText)); err != nil { + return nil, fmt.Errorf(`failed to encode %s field: %w`, CipherTextKey, err) + } + fields = append(fields, jsonKV{ + Key: CipherTextKey, + Value: strings.TrimSpace(buf.String()), + }) + } + + if iv := m.InitializationVector(); len(iv) > 0 { + buf.Reset() + if err := enc.Encode(base64.EncodeToString(iv)); err != nil { + return nil, fmt.Errorf(`failed to encode %s field: %w`, InitializationVectorKey, err) + } + fields = append(fields, jsonKV{ + Key: InitializationVectorKey, + Value: strings.TrimSpace(buf.String()), + }) + } + + var encodedProtectedHeaders []byte + if h := m.ProtectedHeaders(); h != nil { + v, err := h.Encode() + if err != nil { + return nil, fmt.Errorf(`failed to encode protected headers: %w`, err) + } + + encodedProtectedHeaders = v + if len(encodedProtectedHeaders) <= 2 { // '{}' + encodedProtectedHeaders = nil + } else { + fields = append(fields, jsonKV{ + Key: ProtectedHeadersKey, + Value: fmt.Sprintf("%q", encodedProtectedHeaders), + }) + } + } + + if aad := m.AuthenticatedData(); len(aad) > 0 { + aad = base64.Encode(aad) + if encodedProtectedHeaders != nil { + tmp := append(encodedProtectedHeaders, tokens.Period) + aad = append(tmp, aad...) + } + + buf.Reset() + if err := enc.Encode(aad); err != nil { + return nil, fmt.Errorf(`failed to encode %s field: %w`, AuthenticatedDataKey, err) + } + fields = append(fields, jsonKV{ + Key: AuthenticatedDataKey, + Value: strings.TrimSpace(buf.String()), + }) + } + + if recipients := m.Recipients(); len(recipients) > 0 { + if len(recipients) == 1 { // Use flattened format + if hdrs := recipients[0].Headers(); hdrs != nil { + buf.Reset() + if err := enc.Encode(hdrs); err != nil { + return nil, fmt.Errorf(`failed to encode %s field: %w`, HeadersKey, err) + } + fields = append(fields, jsonKV{ + Key: HeadersKey, + Value: strings.TrimSpace(buf.String()), + }) + } + + if ek := recipients[0].EncryptedKey(); len(ek) > 0 { + buf.Reset() + if err := enc.Encode(base64.EncodeToString(ek)); err != nil { + return nil, fmt.Errorf(`failed to encode %s field: %w`, EncryptedKeyKey, err) + } + fields = append(fields, jsonKV{ + Key: EncryptedKeyKey, + Value: strings.TrimSpace(buf.String()), + }) + } + } else { + buf.Reset() + if err := enc.Encode(recipients); err != nil { + return nil, fmt.Errorf(`failed to encode %s field: %w`, RecipientsKey, err) + } + fields = append(fields, jsonKV{ + Key: RecipientsKey, + Value: strings.TrimSpace(buf.String()), + }) + } + } + + if tag := m.Tag(); len(tag) > 0 { + buf.Reset() + if err := enc.Encode(base64.EncodeToString(tag)); err != nil { + return nil, fmt.Errorf(`failed to encode %s field: %w`, TagKey, err) + } + fields = append(fields, jsonKV{ + Key: TagKey, + Value: strings.TrimSpace(buf.String()), + }) + } + + if h := m.UnprotectedHeaders(); h != nil { + unprotected, err := json.Marshal(h) + if err != nil { + return nil, fmt.Errorf(`failed to encode unprotected headers: %w`, err) + } + + if len(unprotected) > 2 { + fields = append(fields, jsonKV{ + Key: UnprotectedHeadersKey, + Value: fmt.Sprintf("%q", unprotected), + }) + } + } + + sort.Slice(fields, func(i, j int) bool { + return fields[i].Key < fields[j].Key + }) + buf.Reset() + fmt.Fprintf(buf, `{`) + for i, kv := range fields { + if i > 0 { + fmt.Fprintf(buf, `,`) + } + fmt.Fprintf(buf, `%q:%s`, kv.Key, kv.Value) + } + fmt.Fprintf(buf, `}`) + + ret := make([]byte, buf.Len()) + copy(ret, buf.Bytes()) + return ret, nil +} + +func (m *Message) UnmarshalJSON(buf []byte) error { + var proxy messageMarshalProxy + proxy.UnprotectedHeaders = NewHeaders() + + if err := json.Unmarshal(buf, &proxy); err != nil { + return fmt.Errorf(`failed to unmashal JSON into message: %w`, err) + } + + // Get the string value + var protectedHeadersStr string + if err := json.Unmarshal(proxy.ProtectedHeaders, &protectedHeadersStr); err != nil { + return fmt.Errorf(`failed to decode protected headers (1): %w`, err) + } + + // It's now in _quoted_ base64 string. Decode it + protectedHeadersRaw, err := base64.DecodeString(protectedHeadersStr) + if err != nil { + return fmt.Errorf(`failed to base64 decoded protected headers buffer: %w`, err) + } + + h := NewHeaders() + if err := json.Unmarshal(protectedHeadersRaw, h); err != nil { + return fmt.Errorf(`failed to decode protected headers (2): %w`, err) + } + + // if this were a flattened message, we would see a "header" and "ciphertext" + // field. TODO: do both of these conditions need to meet, or just one? + if proxy.Headers != nil || len(proxy.EncryptedKey) > 0 { + recipient := NewRecipient() + hdrs := NewHeaders() + if err := json.Unmarshal(proxy.Headers, hdrs); err != nil { + return fmt.Errorf(`failed to decode headers field: %w`, err) + } + + if err := recipient.SetHeaders(hdrs); err != nil { + return fmt.Errorf(`failed to set new headers: %w`, err) + } + + if v := proxy.EncryptedKey; len(v) > 0 { + buf, err := base64.DecodeString(v) + if err != nil { + return fmt.Errorf(`failed to decode encrypted key: %w`, err) + } + if err := recipient.SetEncryptedKey(buf); err != nil { + return fmt.Errorf(`failed to set encrypted key: %w`, err) + } + } + + m.recipients = append(m.recipients, recipient) + } else { + for i, recipientbuf := range proxy.Recipients { + recipient := NewRecipient() + if err := json.Unmarshal(recipientbuf, recipient); err != nil { + return fmt.Errorf(`failed to decode recipient at index %d: %w`, i, err) + } + + m.recipients = append(m.recipients, recipient) + } + } + + if src := proxy.AuthenticatedData; len(src) > 0 { + v, err := base64.DecodeString(src) + if err != nil { + return fmt.Errorf(`failed to decode "aad": %w`, err) + } + m.authenticatedData = v + } + + if src := proxy.CipherText; len(src) > 0 { + v, err := base64.DecodeString(src) + if err != nil { + return fmt.Errorf(`failed to decode "ciphertext": %w`, err) + } + m.cipherText = v + } + + if src := proxy.InitializationVector; len(src) > 0 { + v, err := base64.DecodeString(src) + if err != nil { + return fmt.Errorf(`failed to decode "iv": %w`, err) + } + m.initializationVector = v + } + + if src := proxy.Tag; len(src) > 0 { + v, err := base64.DecodeString(src) + if err != nil { + return fmt.Errorf(`failed to decode "tag": %w`, err) + } + m.tag = v + } + + m.protectedHeaders = h + if m.storeProtectedHeaders { + // this is later used for decryption + m.rawProtectedHeaders = base64.Encode(protectedHeadersRaw) + } + + if iz, ok := proxy.UnprotectedHeaders.(isZeroer); ok { + if !iz.isZero() { + m.unprotectedHeaders = proxy.UnprotectedHeaders + } + } + + if len(m.recipients) == 0 { + if err := m.makeDummyRecipient(proxy.EncryptedKey, m.protectedHeaders); err != nil { + return fmt.Errorf(`failed to setup recipient: %w`, err) + } + } + + return nil +} + +func (m *Message) makeDummyRecipient(enckeybuf string, protected Headers) error { + // Recipients in this case should not contain the content encryption key, + // so move that out + hdrs, err := protected.Clone() + if err != nil { + return fmt.Errorf(`failed to clone headers: %w`, err) + } + + if err := hdrs.Remove(ContentEncryptionKey); err != nil { + return fmt.Errorf(`failed to remove %#v from public header: %w`, ContentEncryptionKey, err) + } + + enckey, err := base64.DecodeString(enckeybuf) + if err != nil { + return fmt.Errorf(`failed to decode encrypted key: %w`, err) + } + + if err := m.Set(RecipientsKey, []Recipient{ + &stdRecipient{ + headers: hdrs, + encryptedKey: enckey, + }, + }); err != nil { + return fmt.Errorf(`failed to set %s: %w`, RecipientsKey, err) + } + return nil +} + +// Compact generates a JWE message in compact serialization format from a +// `*jwe.Message` object. The object contain exactly one recipient, or +// an error is returned. +// +// This function currently does not take any options, but the function +// signature contains `options` for possible future expansion of the API +func Compact(m *Message, _ ...CompactOption) ([]byte, error) { + if len(m.recipients) != 1 { + return nil, fmt.Errorf(`wrong number of recipients for compact serialization`) + } + + recipient := m.recipients[0] + + // The protected header must be a merge between the message-wide + // protected header AND the recipient header + + // There's something wrong if m.protectedHeaders is nil, but + // it could happen + if m.protectedHeaders == nil { + return nil, fmt.Errorf(`invalid protected header`) + } + + hcopy, err := m.protectedHeaders.Clone() + if err != nil { + return nil, fmt.Errorf(`failed to copy protected header: %w`, err) + } + hcopy, err = hcopy.Merge(m.unprotectedHeaders) + if err != nil { + return nil, fmt.Errorf(`failed to merge unprotected header: %w`, err) + } + hcopy, err = hcopy.Merge(recipient.Headers()) + if err != nil { + return nil, fmt.Errorf(`failed to merge recipient header: %w`, err) + } + + protected, err := hcopy.Encode() + if err != nil { + return nil, fmt.Errorf(`failed to encode header: %w`, err) + } + + encryptedKey := base64.Encode(recipient.EncryptedKey()) + iv := base64.Encode(m.initializationVector) + cipher := base64.Encode(m.cipherText) + tag := base64.Encode(m.tag) + + buf := pool.BytesBuffer().Get() + defer pool.BytesBuffer().Put(buf) + + buf.Grow(len(protected) + len(encryptedKey) + len(iv) + len(cipher) + len(tag) + 4) + buf.Write(protected) + buf.WriteByte(tokens.Period) + buf.Write(encryptedKey) + buf.WriteByte(tokens.Period) + buf.Write(iv) + buf.WriteByte(tokens.Period) + buf.Write(cipher) + buf.WriteByte(tokens.Period) + buf.Write(tag) + + result := make([]byte, buf.Len()) + copy(result, buf.Bytes()) + return result, nil +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwe/options.go b/vendor/github.com/lestrrat-go/jwx/v3/jwe/options.go new file mode 100644 index 00000000000..c9137eecf4a --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwe/options.go @@ -0,0 +1,108 @@ +package jwe + +import ( + "github.com/lestrrat-go/jwx/v3/jwa" + "github.com/lestrrat-go/jwx/v3/jwk" + "github.com/lestrrat-go/option/v2" +) + +// Specify contents of the protected header. Some fields such as +// "enc" and "zip" will be overwritten when encryption is performed. +// +// There is no equivalent for unprotected headers in this implementation +func WithProtectedHeaders(h Headers) EncryptOption { + cloned, _ := h.Clone() + return &encryptOption{option.New(identProtectedHeaders{}, cloned)} +} + +type withKey struct { + alg jwa.KeyAlgorithm + key any + headers Headers +} + +type WithKeySuboption interface { + Option + withKeySuboption() +} + +type withKeySuboption struct { + Option +} + +func (*withKeySuboption) withKeySuboption() {} + +// WithPerRecipientHeaders is used to pass header values for each recipient. +// Note that these headers are by definition _unprotected_. +func WithPerRecipientHeaders(hdr Headers) WithKeySuboption { + return &withKeySuboption{option.New(identPerRecipientHeaders{}, hdr)} +} + +// WithKey is used to pass a static algorithm/key pair to either `jwe.Encrypt()` or `jwe.Decrypt()`. +// either a raw key or `jwk.Key` may be passed as `key`. +// +// The `alg` parameter is the identifier for the key encryption algorithm that should be used. +// It is of type `jwa.KeyAlgorithm` but in reality you can only pass `jwa.KeyEncryptionAlgorithm` +// types. It is this way so that the value in `(jwk.Key).Algorithm()` can be directly +// passed to the option. If you specify other algorithm types such as `jwa.SignatureAlgorithm`, +// then you will get an error when `jwe.Encrypt()` or `jwe.Decrypt()` is executed. +// +// Unlike `jwe.WithKeySet()`, the `kid` field does not need to match for the key +// to be tried. +func WithKey(alg jwa.KeyAlgorithm, key any, options ...WithKeySuboption) EncryptDecryptOption { + var hdr Headers + for _, option := range options { + switch option.Ident() { + case identPerRecipientHeaders{}: + if err := option.Value(&hdr); err != nil { + panic(`jwe.WithKey() requires Headers value for WithPerRecipientHeaders option`) + } + } + } + + return &encryptDecryptOption{option.New(identKey{}, &withKey{ + alg: alg, + key: key, + headers: hdr, + })} +} + +func WithKeySet(set jwk.Set, options ...WithKeySetSuboption) DecryptOption { + requireKid := true + for _, option := range options { + switch option.Ident() { + case identRequireKid{}: + if err := option.Value(&requireKid); err != nil { + panic(`jwe.WithKeySet() requires bool value for WithRequireKid option`) + } + } + } + + return WithKeyProvider(&keySetProvider{ + set: set, + requireKid: requireKid, + }) +} + +// WithJSON specifies that the result of `jwe.Encrypt()` is serialized in +// JSON format. +// +// If you pass multiple keys to `jwe.Encrypt()`, it will fail unless +// you also pass this option. +func WithJSON(options ...WithJSONSuboption) EncryptOption { + var pretty bool + for _, option := range options { + switch option.Ident() { + case identPretty{}: + if err := option.Value(&pretty); err != nil { + panic(`jwe.WithJSON() requires bool value for WithPretty option`) + } + } + } + + format := fmtJSON + if pretty { + format = fmtJSONPretty + } + return &encryptOption{option.New(identSerialization{}, format)} +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwe/options.yaml b/vendor/github.com/lestrrat-go/jwx/v3/jwe/options.yaml new file mode 100644 index 00000000000..b7fb0262deb --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwe/options.yaml @@ -0,0 +1,172 @@ +package_name: jwe +output: jwe/options_gen.go +interfaces: + - name: GlobalOption + comment: | + GlobalOption describes options that changes global settings for this package + - name: GlobalDecryptOption + comment: | + GlobalDecryptOption describes options that changes global settings and for each call of the `jwe.Decrypt` function + methods: + - globalOption + - decryptOption + - name: CompactOption + comment: | + CompactOption describes options that can be passed to `jwe.Compact` + - name: DecryptOption + comment: | + DecryptOption describes options that can be passed to `jwe.Decrypt` + - name: EncryptOption + comment: | + EncryptOption describes options that can be passed to `jwe.Encrypt` + - name: EncryptDecryptOption + methods: + - encryptOption + - decryptOption + comment: | + EncryptDecryptOption describes options that can be passed to either `jwe.Encrypt` or `jwe.Decrypt` + - name: WithJSONSuboption + concrete_type: withJSONSuboption + comment: | + JSONSuboption describes suboptions that can be passed to `jwe.WithJSON()` option + - name: WithKeySetSuboption + comment: | + WithKeySetSuboption is a suboption passed to the WithKeySet() option + - name: ParseOption + methods: + - readFileOption + comment: | + ReadFileOption is a type of `Option` that can be passed to `jwe.Parse` + - name: ReadFileOption + comment: | + ReadFileOption is a type of `Option` that can be passed to `jwe.ReadFile` +options: + - ident: Key + skip_option: true + - ident: Pretty + skip_option: true + - ident: ProtectedHeaders + skip_option: true + - ident: PerRecipientHeaders + skip_option: true + - ident: KeyProvider + interface: DecryptOption + argument_type: KeyProvider + - ident: Context + interface: DecryptOption + argument_type: context.Context + comment: | + WithContext specifies the context.Context object to use when decrypting a JWE message. + If not provided, context.Background() will be used. + - ident: Serialization + option_name: WithCompact + interface: EncryptOption + constant_value: fmtCompact + comment: | + WithCompact specifies that the result of `jwe.Encrypt()` is serialized in + compact format. + + By default `jwe.Encrypt()` will opt to use compact format, so you usually + do not need to specify this option other than to be explicit about it + - ident: Compress + interface: EncryptOption + argument_type: jwa.CompressionAlgorithm + comment: | + WithCompress specifies the compression algorithm to use when encrypting + a payload using `jwe.Encrypt` (Yes, we know it can only be "" or "DEF", + but the way the specification is written it could allow for more options, + and therefore this option takes an argument) + - ident: ContentEncryptionAlgorithm + interface: EncryptOption + option_name: WithContentEncryption + argument_type: jwa.ContentEncryptionAlgorithm + comment: | + WithContentEncryptionAlgorithm specifies the algorithm to encrypt the + JWE message content with. If not provided, `jwa.A256GCM` is used. + - ident: Message + interface: DecryptOption + argument_type: '*Message' + comment: | + WithMessage provides a message object to be populated by `jwe.Decrypt` + Using this option allows you to decrypt AND obtain the `jwe.Message` + in one go. + - ident: RequireKid + interface: WithKeySetSuboption + argument_type: bool + comment: | + WithRequiredKid specifies whether the keys in the jwk.Set should + only be matched if the target JWE message's Key ID and the Key ID + in the given key matches. + - ident: Pretty + interface: WithJSONSuboption + argument_type: bool + comment: | + WithPretty specifies whether the JSON output should be formatted and + indented + - ident: MergeProtectedHeaders + interface: EncryptOption + argument_type: bool + comment: | + WithMergeProtectedHeaders specify that when given multiple headers + as options to `jwe.Encrypt`, these headers should be merged instead + of overwritten + - ident: FS + interface: ReadFileOption + argument_type: fs.FS + comment: | + WithFS specifies the source `fs.FS` object to read the file from. + - ident: KeyUsed + interface: DecryptOption + argument_type: 'any' + comment: | + WithKeyUsed allows you to specify the `jwe.Decrypt()` function to + return the key used for decryption. This may be useful when + you specify multiple key sources or if you pass a `jwk.Set` + and you want to know which key was successful at decrypting the + CEK. + + `v` must be a pointer to an empty `any`. Do not use + `jwk.Key` here unless you are 100% sure that all keys that you + have provided are instances of `jwk.Key` (remember that the + jwx API allows users to specify a raw key such as *rsa.PublicKey) + - ident: CEK + interface: DecryptOption + argument_type: '*[]byte' + comment: | + WithCEK allows users to specify a variable to store the CEK used in the + message upon successful decryption. The variable must be a pointer to + a byte slice, and it will only be populated if the decryption is successful. + + This option is currently considered EXPERIMENTAL, and is subject to + future changes across minor/micro versions. + - ident: MaxPBES2Count + interface: GlobalOption + argument_type: int + comment: | + WithMaxPBES2Count specifies the maximum number of PBES2 iterations + to use when decrypting a message. If not specified, the default + value of 10,000 is used. + + This option has a global effect. + - ident: MaxDecompressBufferSize + interface: GlobalDecryptOption + argument_type: int64 + comment: | + WithMaxDecompressBufferSize specifies the maximum buffer size for used when + decompressing the payload of a JWE message. If a compressed JWE payload + exceeds this amount when decompressed, jwe.Decrypt will return an error. + The default value is 10MB. + + This option can be used for `jwe.Settings()`, which changes the behavior + globally, or for `jwe.Decrypt()`, which changes the behavior for that + specific call. + - ident: CBCBufferSize + interface: GlobalOption + argument_type: int64 + comment: | + WithCBCBufferSize specifies the maximum buffer size for internal + calculations, such as when AES-CBC is performed. The default value is 256MB. + If set to an invalid value, the default value is used. + In v2, this option was called MaxBufferSize. + + This option has a global effect. \ No newline at end of file diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwe/options_gen.go b/vendor/github.com/lestrrat-go/jwx/v3/jwe/options_gen.go new file mode 100644 index 00000000000..2a15c141b42 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwe/options_gen.go @@ -0,0 +1,350 @@ +// Code generated by tools/cmd/genoptions/main.go. DO NOT EDIT. + +package jwe + +import ( + "context" + "io/fs" + + "github.com/lestrrat-go/jwx/v3/jwa" + "github.com/lestrrat-go/option/v2" +) + +type Option = option.Interface + +// CompactOption describes options that can be passed to `jwe.Compact` +type CompactOption interface { + Option + compactOption() +} + +type compactOption struct { + Option +} + +func (*compactOption) compactOption() {} + +// DecryptOption describes options that can be passed to `jwe.Decrypt` +type DecryptOption interface { + Option + decryptOption() +} + +type decryptOption struct { + Option +} + +func (*decryptOption) decryptOption() {} + +// EncryptDecryptOption describes options that can be passed to either `jwe.Encrypt` or `jwe.Decrypt` +type EncryptDecryptOption interface { + Option + encryptOption() + decryptOption() +} + +type encryptDecryptOption struct { + Option +} + +func (*encryptDecryptOption) encryptOption() {} + +func (*encryptDecryptOption) decryptOption() {} + +// EncryptOption describes options that can be passed to `jwe.Encrypt` +type EncryptOption interface { + Option + encryptOption() +} + +type encryptOption struct { + Option +} + +func (*encryptOption) encryptOption() {} + +// GlobalDecryptOption describes options that changes global settings and for each call of the `jwe.Decrypt` function +type GlobalDecryptOption interface { + Option + globalOption() + decryptOption() +} + +type globalDecryptOption struct { + Option +} + +func (*globalDecryptOption) globalOption() {} + +func (*globalDecryptOption) decryptOption() {} + +// GlobalOption describes options that changes global settings for this package +type GlobalOption interface { + Option + globalOption() +} + +type globalOption struct { + Option +} + +func (*globalOption) globalOption() {} + +// ReadFileOption is a type of `Option` that can be passed to `jwe.Parse` +type ParseOption interface { + Option + readFileOption() +} + +type parseOption struct { + Option +} + +func (*parseOption) readFileOption() {} + +// ReadFileOption is a type of `Option` that can be passed to `jwe.ReadFile` +type ReadFileOption interface { + Option + readFileOption() +} + +type readFileOption struct { + Option +} + +func (*readFileOption) readFileOption() {} + +// JSONSuboption describes suboptions that can be passed to `jwe.WithJSON()` option +type WithJSONSuboption interface { + Option + withJSONSuboption() +} + +type withJSONSuboption struct { + Option +} + +func (*withJSONSuboption) withJSONSuboption() {} + +// WithKeySetSuboption is a suboption passed to the WithKeySet() option +type WithKeySetSuboption interface { + Option + withKeySetSuboption() +} + +type withKeySetSuboption struct { + Option +} + +func (*withKeySetSuboption) withKeySetSuboption() {} + +type identCBCBufferSize struct{} +type identCEK struct{} +type identCompress struct{} +type identContentEncryptionAlgorithm struct{} +type identContext struct{} +type identFS struct{} +type identKey struct{} +type identKeyProvider struct{} +type identKeyUsed struct{} +type identMaxDecompressBufferSize struct{} +type identMaxPBES2Count struct{} +type identMergeProtectedHeaders struct{} +type identMessage struct{} +type identPerRecipientHeaders struct{} +type identPretty struct{} +type identProtectedHeaders struct{} +type identRequireKid struct{} +type identSerialization struct{} + +func (identCBCBufferSize) String() string { + return "WithCBCBufferSize" +} + +func (identCEK) String() string { + return "WithCEK" +} + +func (identCompress) String() string { + return "WithCompress" +} + +func (identContentEncryptionAlgorithm) String() string { + return "WithContentEncryption" +} + +func (identContext) String() string { + return "WithContext" +} + +func (identFS) String() string { + return "WithFS" +} + +func (identKey) String() string { + return "WithKey" +} + +func (identKeyProvider) String() string { + return "WithKeyProvider" +} + +func (identKeyUsed) String() string { + return "WithKeyUsed" +} + +func (identMaxDecompressBufferSize) String() string { + return "WithMaxDecompressBufferSize" +} + +func (identMaxPBES2Count) String() string { + return "WithMaxPBES2Count" +} + +func (identMergeProtectedHeaders) String() string { + return "WithMergeProtectedHeaders" +} + +func (identMessage) String() string { + return "WithMessage" +} + +func (identPerRecipientHeaders) String() string { + return "WithPerRecipientHeaders" +} + +func (identPretty) String() string { + return "WithPretty" +} + +func (identProtectedHeaders) String() string { + return "WithProtectedHeaders" +} + +func (identRequireKid) String() string { + return "WithRequireKid" +} + +func (identSerialization) String() string { + return "WithSerialization" +} + +// WithCBCBufferSize specifies the maximum buffer size for internal +// calculations, such as when AES-CBC is performed. The default value is 256MB. +// If set to an invalid value, the default value is used. +// In v2, this option was called MaxBufferSize. +// +// This option has a global effect. +func WithCBCBufferSize(v int64) GlobalOption { + return &globalOption{option.New(identCBCBufferSize{}, v)} +} + +// WithCEK allows users to specify a variable to store the CEK used in the +// message upon successful decryption. The variable must be a pointer to +// a byte slice, and it will only be populated if the decryption is successful. +// +// This option is currently considered EXPERIMENTAL, and is subject to +// future changes across minor/micro versions. +func WithCEK(v *[]byte) DecryptOption { + return &decryptOption{option.New(identCEK{}, v)} +} + +// WithCompress specifies the compression algorithm to use when encrypting +// a payload using `jwe.Encrypt` (Yes, we know it can only be "" or "DEF", +// but the way the specification is written it could allow for more options, +// and therefore this option takes an argument) +func WithCompress(v jwa.CompressionAlgorithm) EncryptOption { + return &encryptOption{option.New(identCompress{}, v)} +} + +// WithContentEncryptionAlgorithm specifies the algorithm to encrypt the +// JWE message content with. If not provided, `jwa.A256GCM` is used. +func WithContentEncryption(v jwa.ContentEncryptionAlgorithm) EncryptOption { + return &encryptOption{option.New(identContentEncryptionAlgorithm{}, v)} +} + +// WithContext specifies the context.Context object to use when decrypting a JWE message. +// If not provided, context.Background() will be used. +func WithContext(v context.Context) DecryptOption { + return &decryptOption{option.New(identContext{}, v)} +} + +// WithFS specifies the source `fs.FS` object to read the file from. +func WithFS(v fs.FS) ReadFileOption { + return &readFileOption{option.New(identFS{}, v)} +} + +func WithKeyProvider(v KeyProvider) DecryptOption { + return &decryptOption{option.New(identKeyProvider{}, v)} +} + +// WithKeyUsed allows you to specify the `jwe.Decrypt()` function to +// return the key used for decryption. This may be useful when +// you specify multiple key sources or if you pass a `jwk.Set` +// and you want to know which key was successful at decrypting the +// CEK. +// +// `v` must be a pointer to an empty `any`. Do not use +// `jwk.Key` here unless you are 100% sure that all keys that you +// have provided are instances of `jwk.Key` (remember that the +// jwx API allows users to specify a raw key such as *rsa.PublicKey) +func WithKeyUsed(v any) DecryptOption { + return &decryptOption{option.New(identKeyUsed{}, v)} +} + +// WithMaxDecompressBufferSize specifies the maximum buffer size for used when +// decompressing the payload of a JWE message. If a compressed JWE payload +// exceeds this amount when decompressed, jwe.Decrypt will return an error. +// The default value is 10MB. +// +// This option can be used for `jwe.Settings()`, which changes the behavior +// globally, or for `jwe.Decrypt()`, which changes the behavior for that +// specific call. +func WithMaxDecompressBufferSize(v int64) GlobalDecryptOption { + return &globalDecryptOption{option.New(identMaxDecompressBufferSize{}, v)} +} + +// WithMaxPBES2Count specifies the maximum number of PBES2 iterations +// to use when decrypting a message. If not specified, the default +// value of 10,000 is used. +// +// This option has a global effect. +func WithMaxPBES2Count(v int) GlobalOption { + return &globalOption{option.New(identMaxPBES2Count{}, v)} +} + +// WithMergeProtectedHeaders specify that when given multiple headers +// as options to `jwe.Encrypt`, these headers should be merged instead +// of overwritten +func WithMergeProtectedHeaders(v bool) EncryptOption { + return &encryptOption{option.New(identMergeProtectedHeaders{}, v)} +} + +// WithMessage provides a message object to be populated by `jwe.Decrypt` +// Using this option allows you to decrypt AND obtain the `jwe.Message` +// in one go. +func WithMessage(v *Message) DecryptOption { + return &decryptOption{option.New(identMessage{}, v)} +} + +// WithPretty specifies whether the JSON output should be formatted and +// indented +func WithPretty(v bool) WithJSONSuboption { + return &withJSONSuboption{option.New(identPretty{}, v)} +} + +// WithRequiredKid specifies whether the keys in the jwk.Set should +// only be matched if the target JWE message's Key ID and the Key ID +// in the given key matches. +func WithRequireKid(v bool) WithKeySetSuboption { + return &withKeySetSuboption{option.New(identRequireKid{}, v)} +} + +// WithCompact specifies that the result of `jwe.Encrypt()` is serialized in +// compact format. +// +// By default `jwe.Encrypt()` will opt to use compact format, so you usually +// do not need to specify this option other than to be explicit about it +func WithCompact() EncryptOption { + return &encryptOption{option.New(identSerialization{}, fmtCompact)} +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwk/BUILD.bazel b/vendor/github.com/lestrrat-go/jwx/v3/jwk/BUILD.bazel new file mode 100644 index 00000000000..8e82e1f0096 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwk/BUILD.bazel @@ -0,0 +1,87 @@ +load("@rules_go//go:def.bzl", "go_library", "go_test") + +go_library( + name = "jwk", + srcs = [ + "cache.go", + "convert.go", + "ecdsa.go", + "ecdsa_gen.go", + "errors.go", + "fetch.go", + "filter.go", + "interface.go", + "interface_gen.go", + "io.go", + "jwk.go", + "key_ops.go", + "okp.go", + "okp_gen.go", + "options.go", + "options_gen.go", + "parser.go", + "rsa.go", + "rsa_gen.go", + "set.go", + "symmetric.go", + "symmetric_gen.go", + "usage.go", + "whitelist.go", + "x509.go", + ], + importpath = "github.com/lestrrat-go/jwx/v3/jwk", + visibility = ["//visibility:public"], + deps = [ + "//cert", + "//internal/base64", + "//internal/ecutil", + "//transform", + "//internal/json", + "//internal/pool", + "//internal/tokens", + "//jwa", + "//jwk/ecdsa", + "//jwk/jwkbb", + "@com_github_lestrrat_go_blackmagic//:blackmagic", + "@com_github_lestrrat_go_httprc_v3//:httprc", + "@com_github_lestrrat_go_option_v2//:option", + ], +) + +go_test( + name = "jwk_test", + srcs = [ + "filter_test.go", + "headers_test.go", + "jwk_internal_test.go", + "jwk_test.go", + "options_gen_test.go", + "refresh_test.go", + "set_test.go", + "x5c_test.go", + ], + data = glob(["testdata/**"]), + embed = [":jwk"], + deps = [ + "//cert", + "//internal/base64", + "//internal/jose", + "//internal/json", + "//internal/jwxtest", + "//internal/tokens", + "//jwa", + "//jwk/ecdsa", + "//jws", + "@com_github_lestrrat_go_blackmagic//:blackmagic", + "@com_github_lestrrat_go_httprc_v3//:httprc", + "@com_github_lestrrat_go_httprc_v3//tracesink", + "@com_github_stretchr_testify//assert", + "@com_github_stretchr_testify//require", + ], +) + +alias( + name = "go_default_library", + actual = ":jwk", + visibility = ["//visibility:public"], +) diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwk/README.md b/vendor/github.com/lestrrat-go/jwx/v3/jwk/README.md new file mode 100644 index 00000000000..741dd4647d6 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwk/README.md @@ -0,0 +1,215 @@ +# JWK [![Go Reference](https://pkg.go.dev/badge/github.com/lestrrat-go/jwx/v3/jwk.svg)](https://pkg.go.dev/github.com/lestrrat-go/jwx/v3/jwk) + +Package jwk implements JWK as described in [RFC7517](https://tools.ietf.org/html/rfc7517). +If you are looking to use JWT wit JWKs, look no further than [github.com/lestrrat-go/jwx](../jwt). + +* Parse and work with RSA/EC/Symmetric/OKP JWK types + * Convert to and from JSON + * Convert to and from raw key types (e.g. *rsa.PrivateKey) +* Ability to keep a JWKS fresh using *jwk.AutoRefresh + +## Supported key types: + +| kty | Curve | Go Key Type | +|:----|:------------------------|:----------------------------------------------| +| RSA | N/A | rsa.PrivateKey / rsa.PublicKey (2) | +| EC | P-256
P-384
P-521
secp256k1 (1) | ecdsa.PrivateKey / ecdsa.PublicKey (2) | +| oct | N/A | []byte | +| OKP | Ed25519 (1) | ed25519.PrivateKey / ed25519.PublicKey (2) | +| | X25519 (1) | (jwx/)x25519.PrivateKey / x25519.PublicKey (2)| + +* Note 1: Experimental +* Note 2: Either value or pointers accepted (e.g. rsa.PrivateKey or *rsa.PrivateKey) + +# Documentation + +Please read the [API reference](https://pkg.go.dev/github.com/lestrrat-go/jwx/v3/jwk), or +the how-to style documentation on how to use JWK can be found in the [docs directory](../docs/04-jwk.md). + +# Auto-Refresh a key during a long-running process + + +```go +package examples_test + +import ( + "context" + "fmt" + "time" + + "github.com/lestrrat-go/httprc/v3" + "github.com/lestrrat-go/jwx/v3/jwk" +) + +func Example_jwk_cache() { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + const googleCerts = `https://www.googleapis.com/oauth2/v3/certs` + + // First, set up the `jwk.Cache` object. You need to pass it a + // `context.Context` object to control the lifecycle of the background fetching goroutine. + c, err := jwk.NewCache(ctx, httprc.NewClient()) + if err != nil { + fmt.Printf("failed to create cache: %s\n", err) + return + } + + // Tell *jwk.Cache that we only want to refresh this JWKS periodically. + if err := c.Register(ctx, googleCerts); err != nil { + fmt.Printf("failed to register google JWKS: %s\n", err) + return + } + + // Pretend that this is your program's main loop +MAIN: + for { + select { + case <-ctx.Done(): + break MAIN + default: + } + keyset, err := c.Lookup(ctx, googleCerts) + if err != nil { + fmt.Printf("failed to fetch google JWKS: %s\n", err) + return + } + _ = keyset + // The returned `keyset` will always be "reasonably" new. + // + // By "reasonably" we mean that we cannot guarantee that the keys will be refreshed + // immediately after it has been rotated in the remote source. But it should be close\ + // enough, and should you need to forcefully refresh the token using the `(jwk.Cache).Refresh()` method. + // + // If refetching the keyset fails, a cached version will be returned from the previous + // successful sync + + // Do interesting stuff with the keyset... but here, we just + // sleep for a bit + time.Sleep(time.Second) + + // Because we're a dummy program, we just cancel the loop now. + // If this were a real program, you presumably loop forever + cancel() + } + // OUTPUT: +} +``` +source: [examples/jwk_cache_example_test.go](https://github.com/lestrrat-go/jwx/blob/v3/examples/jwk_cache_example_test.go) + + +Parse and use a JWK key: + + +```go +package examples_test + +import ( + "context" + "fmt" + "log" + + "github.com/lestrrat-go/jwx/v3/internal/json" + "github.com/lestrrat-go/jwx/v3/jwk" +) + +func Example_jwk_usage() { + // Use jwk.Cache if you intend to keep reuse the JWKS over and over + set, err := jwk.Fetch(context.Background(), "https://www.googleapis.com/oauth2/v3/certs") + if err != nil { + log.Printf("failed to parse JWK: %s", err) + return + } + + // Key sets can be serialized back to JSON + { + jsonbuf, err := json.Marshal(set) + if err != nil { + log.Printf("failed to marshal key set into JSON: %s", err) + return + } + log.Printf("%s", jsonbuf) + } + + for i := 0; i < set.Len(); i++ { + var rawkey any // This is where we would like to store the raw key, like *rsa.PrivateKey or *ecdsa.PrivateKey + key, ok := set.Key(i) // This retrieves the corresponding jwk.Key + if !ok { + log.Printf("failed to get key at index %d", i) + return + } + + // jws and jwe operations can be performed using jwk.Key, but you could also + // covert it to their "raw" forms, such as *rsa.PrivateKey or *ecdsa.PrivateKey + if err := jwk.Export(key, &rawkey); err != nil { + log.Printf("failed to create public key: %s", err) + return + } + _ = rawkey + + // You can create jwk.Key from a raw key, too + fromRawKey, err := jwk.Import(rawkey) + if err != nil { + log.Printf("failed to acquire raw key from jwk.Key: %s", err) + return + } + + // Keys can be serialized back to JSON + jsonbuf, err := json.Marshal(key) + if err != nil { + log.Printf("failed to marshal key into JSON: %s", err) + return + } + + fromJSONKey, err := jwk.Parse(jsonbuf) + if err != nil { + log.Printf("failed to parse json: %s", err) + return + } + _ = fromJSONKey + _ = fromRawKey + } + // OUTPUT: +} + +//nolint:govet +func Example_jwk_marshal_json() { + // JWKs that inherently involve randomness such as RSA and EC keys are + // not used in this example, because they may produce different results + // depending on the environment. + // + // (In fact, even if you use a static source of randomness, tests may fail + // because of internal changes in the Go runtime). + + raw := []byte("01234567890123456789012345678901234567890123456789ABCDEF") + + // This would create a symmetric key + key, err := jwk.Import(raw) + if err != nil { + fmt.Printf("failed to create symmetric key: %s\n", err) + return + } + if _, ok := key.(jwk.SymmetricKey); !ok { + fmt.Printf("expected jwk.SymmetricKey, got %T\n", key) + return + } + + key.Set(jwk.KeyIDKey, "mykey") + + buf, err := json.MarshalIndent(key, "", " ") + if err != nil { + fmt.Printf("failed to marshal key into JSON: %s\n", err) + return + } + fmt.Printf("%s\n", buf) + + // OUTPUT: + // { + // "k": "MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODlBQkNERUY", + // "kid": "mykey", + // "kty": "oct" + // } +} +``` +source: [examples/jwk_example_test.go](https://github.com/lestrrat-go/jwx/blob/v3/examples/jwk_example_test.go) + diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwk/cache.go b/vendor/github.com/lestrrat-go/jwx/v3/jwk/cache.go new file mode 100644 index 00000000000..b83b56c7908 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwk/cache.go @@ -0,0 +1,362 @@ +package jwk + +import ( + "context" + "fmt" + "io" + "net/http" + + "github.com/lestrrat-go/httprc/v3" +) + +type HTTPClient = httprc.HTTPClient +type ErrorSink = httprc.ErrorSink +type TraceSink = httprc.TraceSink + +// Cache is a container built on top of github.com/lestrrat-go/httprc/v3 +// that keeps track of Set object by their source URLs. +// The Set objects are stored in memory, and are refreshed automatically +// behind the scenes. +// +// Before retrieving the Set objects, the user must pre-register the +// URLs they intend to use by calling `Register()` +// +// c := jwk.NewCache(ctx, httprc.NewClient()) +// c.Register(ctx, url, options...) +// +// Once registered, you can call `Get()` to retrieve the Set object. +// +// All JWKS objects that are retrieved via this mechanism should be +// treated read-only, as they are shared among all consumers, as well +// as the `jwk.Cache` object. +// +// There are cases where `jwk.Cache` and `jwk.CachedSet` should and +// should not be used. +// +// First and foremost, do NOT use a cache for those JWKS objects that +// need constant checking. For example, unreliable or user-provided JWKS (i.e. those +// JWKS that are not from a well-known provider) should not be fetched +// through a `jwk.Cache` or `jwk.CachedSet`. +// +// For example, if you have a flaky JWKS server for development +// that can go down often, you should consider alternatives such as +// providing `http.Client` with a caching `http.RoundTripper` configured +// (see `jwk.WithHTTPClient`), setting up a reverse proxy, etc. +// These techniques allow you to set up a more robust way to both cache +// and report precise causes of the problems than using `jwk.Cache` or +// `jwk.CachedSet`. If you handle the caching at the HTTP level like this, +// you will be able to use a simple `jwk.Fetch` call and not worry about the cache. +// +// User-provided JWKS objects may also be problematic, as it may go down +// unexpectedly (and frequently!), and it will be hard to detect when +// the URLs or its contents are swapped. +// +// A good use-case for `jwk.Cache` and `jwk.CachedSet` are for "stable" +// JWKS objects. +// +// When we say "stable", we are thinking of JWKS that should mostly be +// ALWAYS available. A good example are those JWKS objects provided by +// major cloud providers such as Google Cloud, AWS, or Azure. +// Stable JWKS may still experience intermittent network connectivity problems, +// but you can expect that they will eventually recover in relatively +// short period of time. They rarely change URLs, and the contents are +// expected to be valid or otherwise it would cause havoc to those providers +// +// We also know that these stable JWKS objects are rotated periodically, +// which is a perfect use for `jwk.Cache` and `jwk.CachedSet`. The caches +// can be configured to periodically refresh the JWKS thereby keeping them +// fresh without extra intervention from the developer. +// +// Notice that for these recommended use-cases the requirement to check +// the validity or the availability of the JWKS objects are non-existent, +// as it is expected that they will be available and will be valid. The +// caching mechanism can hide intermittent connectivity problems as well +// as keep the objects mostly fresh. +type Cache struct { + ctrl httprc.Controller +} + +// Transformer is a specialized version of `httprc.Transformer` that implements +// conversion from a `http.Response` object to a `jwk.Set` object. Use this in +// conjection with `httprc.NewResource` to create a `httprc.Resource` object +// to auto-update `jwk.Set` objects. +type Transformer struct { + parseOptions []ParseOption +} + +func (t Transformer) Transform(_ context.Context, res *http.Response) (Set, error) { + buf, err := io.ReadAll(res.Body) + if err != nil { + return nil, fmt.Errorf(`failed to read response body status: %w`, err) + } + + set, err := Parse(buf, t.parseOptions...) + if err != nil { + return nil, fmt.Errorf(`failed to parse JWK set at %q: %w`, res.Request.URL.String(), err) + } + + return set, nil +} + +// NewCache creates a new `jwk.Cache` object. +// +// Under the hood, `jwk.Cache` uses `httprc.Client` manage the +// fetching and caching of JWKS objects, and thus spawns multiple goroutines +// per `jwk.Cache` object. +// +// The provided `httprc.Client` object must NOT be started prior to +// passing it to `jwk.NewCache`. The `jwk.Cache` object will start +// the `httprc.Client` object on its own. +func NewCache(ctx context.Context, client *httprc.Client) (*Cache, error) { + ctrl, err := client.Start(ctx) + if err != nil { + return nil, fmt.Errorf(`failed to start httprc.Client: %w`, err) + } + + return &Cache{ + ctrl: ctrl, + }, nil +} + +// Register registers a URL to be managed by the cache. URLs must +// be registered before issuing `Get` +// +// The `Register` method is a thin wrapper around `(httprc.Controller).Add` +func (c *Cache) Register(ctx context.Context, u string, options ...RegisterOption) error { + var parseOptions []ParseOption + var resourceOptions []httprc.NewResourceOption + waitReady := true + for _, option := range options { + switch option := option.(type) { + case ParseOption: + parseOptions = append(parseOptions, option) + case ResourceOption: + var v httprc.NewResourceOption + if err := option.Value(&v); err != nil { + return fmt.Errorf(`failed to retrieve NewResourceOption option value: %w`, err) + } + resourceOptions = append(resourceOptions, v) + default: + switch option.Ident() { + case identHTTPClient{}: + var cli HTTPClient + if err := option.Value(&cli); err != nil { + return fmt.Errorf(`failed to retrieve HTTPClient option value: %w`, err) + } + resourceOptions = append(resourceOptions, httprc.WithHTTPClient(cli)) + case identWaitReady{}: + if err := option.Value(&waitReady); err != nil { + return fmt.Errorf(`failed to retrieve WaitReady option value: %w`, err) + } + } + } + } + + r, err := httprc.NewResource[Set](u, &Transformer{ + parseOptions: parseOptions, + }, resourceOptions...) + if err != nil { + return fmt.Errorf(`failed to create httprc.Resource: %w`, err) + } + if err := c.ctrl.Add(ctx, r, httprc.WithWaitReady(waitReady)); err != nil { + return fmt.Errorf(`failed to add resource to httprc.Client: %w`, err) + } + + return nil +} + +// LookupResource returns the `httprc.Resource` object associated with the +// given URL `u`. If the URL has not been registered, an error is returned. +func (c *Cache) LookupResource(ctx context.Context, u string) (*httprc.ResourceBase[Set], error) { + r, err := c.ctrl.Lookup(ctx, u) + if err != nil { + return nil, fmt.Errorf(`failed to lookup resource %q: %w`, u, err) + } + //nolint:forcetypeassert + return r.(*httprc.ResourceBase[Set]), nil +} + +func (c *Cache) Lookup(ctx context.Context, u string) (Set, error) { + r, err := c.LookupResource(ctx, u) + if err != nil { + return nil, fmt.Errorf(`failed to lookup resource %q: %w`, u, err) + } + set := r.Resource() + if set == nil { + return nil, fmt.Errorf(`resource %q is not ready`, u) + } + return set, nil +} + +func (c *Cache) Ready(ctx context.Context, u string) bool { + r, err := c.LookupResource(ctx, u) + if err != nil { + return false + } + if err := r.Ready(ctx); err != nil { + return false + } + return true +} + +// Refresh is identical to Get(), except it always fetches the +// specified resource anew, and updates the cached content +// +// Please refer to the documentation for `(httprc.Cache).Refresh` for +// more details +func (c *Cache) Refresh(ctx context.Context, u string) (Set, error) { + if err := c.ctrl.Refresh(ctx, u); err != nil { + return nil, fmt.Errorf(`failed to refresh resource %q: %w`, u, err) + } + return c.Lookup(ctx, u) +} + +// IsRegistered returns true if the given URL `u` has already been registered +// in the cache. +func (c *Cache) IsRegistered(ctx context.Context, u string) bool { + _, err := c.LookupResource(ctx, u) + return err == nil +} + +// Unregister removes the given URL `u` from the cache. +func (c *Cache) Unregister(ctx context.Context, u string) error { + return c.ctrl.Remove(ctx, u) +} + +func (c *Cache) Shutdown(ctx context.Context) error { + return c.ctrl.ShutdownContext(ctx) +} + +// CachedSet is a thin shim over jwk.Cache that allows the user to cloak +// jwk.Cache as if it's a `jwk.Set`. Behind the scenes, the `jwk.Set` is +// retrieved from the `jwk.Cache` for every operation. +// +// Since `jwk.CachedSet` always deals with a cached version of the `jwk.Set`, +// all operations that mutate the object (such as AddKey(), RemoveKey(), et. al) +// are no-ops and return an error. +// +// Note that since this is a utility shim over `jwk.Cache`, you _will_ lose +// the ability to control the finer details (such as controlling how long to +// wait for in case of a fetch failure using `context.Context`) +// +// Make sure that you read the documentation for `jwk.Cache` as well. +type CachedSet interface { + Set + cached() (Set, error) // used as a marker +} + +type cachedSet struct { + r *httprc.ResourceBase[Set] +} + +func (c *Cache) CachedSet(u string) (CachedSet, error) { + r, err := c.LookupResource(context.Background(), u) + if err != nil { + return nil, fmt.Errorf(`failed to lookup resource %q: %w`, u, err) + } + return NewCachedSet(r), nil +} + +func NewCachedSet(r *httprc.ResourceBase[Set]) CachedSet { + return &cachedSet{ + r: r, + } +} + +func (cs *cachedSet) cached() (Set, error) { + if err := cs.r.Ready(context.Background()); err != nil { + return nil, fmt.Errorf(`failed to fetch resource: %w`, err) + } + return cs.r.Resource(), nil +} + +// Add is a no-op for `jwk.CachedSet`, as the `jwk.Set` should be treated read-only +func (*cachedSet) AddKey(_ Key) error { + return fmt.Errorf(`(jwk.Cachedset).AddKey: jwk.CachedSet is immutable`) +} + +// Clear is a no-op for `jwk.CachedSet`, as the `jwk.Set` should be treated read-only +func (*cachedSet) Clear() error { + return fmt.Errorf(`(jwk.cachedSet).Clear: jwk.CachedSet is immutable`) +} + +// Set is a no-op for `jwk.CachedSet`, as the `jwk.Set` should be treated read-only +func (*cachedSet) Set(_ string, _ any) error { + return fmt.Errorf(`(jwk.cachedSet).Set: jwk.CachedSet is immutable`) +} + +// Remove is a no-op for `jwk.CachedSet`, as the `jwk.Set` should be treated read-only +func (*cachedSet) Remove(_ string) error { + // TODO: Remove() should be renamed to Remove(string) error + return fmt.Errorf(`(jwk.cachedSet).Remove: jwk.CachedSet is immutable`) +} + +// RemoveKey is a no-op for `jwk.CachedSet`, as the `jwk.Set` should be treated read-only +func (*cachedSet) RemoveKey(_ Key) error { + return fmt.Errorf(`(jwk.cachedSet).RemoveKey: jwk.CachedSet is immutable`) +} + +func (cs *cachedSet) Clone() (Set, error) { + set, err := cs.cached() + if err != nil { + return nil, fmt.Errorf(`failed to get cached jwk.Set: %w`, err) + } + + return set.Clone() +} + +// Get returns the value of non-Key field stored in the jwk.Set +func (cs *cachedSet) Get(name string, dst any) error { + set, err := cs.cached() + if err != nil { + return err + } + + return set.Get(name, dst) +} + +// Key returns the Key at the specified index +func (cs *cachedSet) Key(idx int) (Key, bool) { + set, err := cs.cached() + if err != nil { + return nil, false + } + + return set.Key(idx) +} + +func (cs *cachedSet) Index(key Key) int { + set, err := cs.cached() + if err != nil { + return -1 + } + + return set.Index(key) +} + +func (cs *cachedSet) Keys() []string { + set, err := cs.cached() + if err != nil { + return nil + } + + return set.Keys() +} + +func (cs *cachedSet) Len() int { + set, err := cs.cached() + if err != nil { + return -1 + } + + return set.Len() +} + +func (cs *cachedSet) LookupKeyID(kid string) (Key, bool) { + set, err := cs.cached() + if err != nil { + return nil, false + } + + return set.LookupKeyID(kid) +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwk/convert.go b/vendor/github.com/lestrrat-go/jwx/v3/jwk/convert.go new file mode 100644 index 00000000000..057f4b02a00 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwk/convert.go @@ -0,0 +1,399 @@ +package jwk + +import ( + "crypto/ecdh" + "crypto/ecdsa" + "crypto/ed25519" + "crypto/elliptic" + "crypto/rsa" + "errors" + "fmt" + "math/big" + "reflect" + "sync" + + "github.com/lestrrat-go/blackmagic" + "github.com/lestrrat-go/jwx/v3/internal/ecutil" + "github.com/lestrrat-go/jwx/v3/jwa" +) + +// # Converting between Raw Keys and `jwk.Key`s +// +// A converter that converts from a raw key to a `jwk.Key` is called a KeyImporter. +// A converter that converts from a `jwk.Key` to a raw key is called a KeyExporter. + +var keyImporters = make(map[reflect.Type]KeyImporter) +var keyExporters = make(map[jwa.KeyType][]KeyExporter) + +var muKeyImporters sync.RWMutex +var muKeyExporters sync.RWMutex + +// RegisterKeyImporter registers a KeyImporter for the given raw key. When `jwk.Import()` is called, +// the library will look up the appropriate KeyImporter for the given raw key type (via `reflect`) +// and execute the KeyImporters in succession until either one of them succeeds, or all of them fail. +func RegisterKeyImporter(from any, conv KeyImporter) { + muKeyImporters.Lock() + defer muKeyImporters.Unlock() + keyImporters[reflect.TypeOf(from)] = conv +} + +// RegisterKeyExporter registers a KeyExporter for the given key type. When `key.Raw()` is called, +// the library will look up the appropriate KeyExporter for the given key type and execute the +// KeyExporters in succession until either one of them succeeds, or all of them fail. +func RegisterKeyExporter(kty jwa.KeyType, conv KeyExporter) { + muKeyExporters.Lock() + defer muKeyExporters.Unlock() + convs, ok := keyExporters[kty] + if !ok { + convs = []KeyExporter{conv} + } else { + convs = append([]KeyExporter{conv}, convs...) + } + keyExporters[kty] = convs +} + +// KeyImporter is used to convert from a raw key to a `jwk.Key`. mneumonic: from the PoV of the `jwk.Key`, +// we're _importing_ a raw key. +type KeyImporter interface { + // Import takes the raw key to be converted, and returns a `jwk.Key` or an error if the conversion fails. + Import(any) (Key, error) +} + +// KeyImportFunc is a convenience type to implement KeyImporter as a function. +type KeyImportFunc func(any) (Key, error) + +func (f KeyImportFunc) Import(raw any) (Key, error) { + return f(raw) +} + +// KeyExporter is used to convert from a `jwk.Key` to a raw key. mneumonic: from the PoV of the `jwk.Key`, +// we're _exporting_ it to a raw key. +type KeyExporter interface { + // Export takes the `jwk.Key` to be converted, and a hint (the raw key to be converted to). + // The hint is the object that the user requested the result to be assigned to. + // The method should return the converted raw key, or an error if the conversion fails. + // + // Third party modules MUST NOT modifiy the hint object. + // + // When the user calls `key.Export(dst)`, the `dst` object is a _pointer_ to the + // object that the user wants the result to be assigned to, but the converter + // receives the _value_ that this pointer points to, to make it easier to + // detect the type of the result. + // + // Note that the second argument may be an `any` (which means that the + // user has delegated the type detection to the converter). + // + // Export must NOT modify the hint object, and should return jwk.ContinueError + // if the hint object is not compatible with the converter. + Export(Key, any) (any, error) +} + +// KeyExportFunc is a convenience type to implement KeyExporter as a function. +type KeyExportFunc func(Key, any) (any, error) + +func (f KeyExportFunc) Export(key Key, hint any) (any, error) { + return f(key, hint) +} + +func init() { + { + f := KeyImportFunc(rsaPrivateKeyToJWK) + k := rsa.PrivateKey{} + RegisterKeyImporter(k, f) + RegisterKeyImporter(&k, f) + } + { + f := KeyImportFunc(rsaPublicKeyToJWK) + k := rsa.PublicKey{} + RegisterKeyImporter(k, f) + RegisterKeyImporter(&k, f) + } + { + f := KeyImportFunc(ecdsaPrivateKeyToJWK) + k := ecdsa.PrivateKey{} + RegisterKeyImporter(k, f) + RegisterKeyImporter(&k, f) + } + { + f := KeyImportFunc(ecdsaPublicKeyToJWK) + k := ecdsa.PublicKey{} + RegisterKeyImporter(k, f) + RegisterKeyImporter(&k, f) + } + { + f := KeyImportFunc(okpPrivateKeyToJWK) + for _, k := range []any{ed25519.PrivateKey(nil)} { + RegisterKeyImporter(k, f) + } + } + { + f := KeyImportFunc(ecdhPrivateKeyToJWK) + for _, k := range []any{ecdh.PrivateKey{}, &ecdh.PrivateKey{}} { + RegisterKeyImporter(k, f) + } + } + { + f := KeyImportFunc(okpPublicKeyToJWK) + for _, k := range []any{ed25519.PublicKey(nil)} { + RegisterKeyImporter(k, f) + } + } + { + f := KeyImportFunc(ecdhPublicKeyToJWK) + for _, k := range []any{ecdh.PublicKey{}, &ecdh.PublicKey{}} { + RegisterKeyImporter(k, f) + } + } + RegisterKeyImporter([]byte(nil), KeyImportFunc(bytesToKey)) +} + +func ecdhPrivateKeyToJWK(src any) (Key, error) { + var raw *ecdh.PrivateKey + switch src := src.(type) { + case *ecdh.PrivateKey: + raw = src + case ecdh.PrivateKey: + raw = &src + default: + return nil, fmt.Errorf(`cannot convert key type '%T' to ECDH jwk.Key`, src) + } + + switch raw.Curve() { + case ecdh.X25519(): + return okpPrivateKeyToJWK(raw) + case ecdh.P256(): + return ecdhPrivateKeyToECJWK(raw, elliptic.P256()) + case ecdh.P384(): + return ecdhPrivateKeyToECJWK(raw, elliptic.P384()) + case ecdh.P521(): + return ecdhPrivateKeyToECJWK(raw, elliptic.P521()) + default: + return nil, fmt.Errorf(`unsupported curve %s`, raw.Curve()) + } +} + +func ecdhPrivateKeyToECJWK(raw *ecdh.PrivateKey, crv elliptic.Curve) (Key, error) { + pub := raw.PublicKey() + rawpub := pub.Bytes() + + size := ecutil.CalculateKeySize(crv) + var x, y, d big.Int + x.SetBytes(rawpub[1 : 1+size]) + y.SetBytes(rawpub[1+size:]) + d.SetBytes(raw.Bytes()) + + var ecdsaPriv ecdsa.PrivateKey + ecdsaPriv.Curve = crv + ecdsaPriv.D = &d + ecdsaPriv.X = &x + ecdsaPriv.Y = &y + return ecdsaPrivateKeyToJWK(&ecdsaPriv) +} + +func ecdhPublicKeyToJWK(src any) (Key, error) { + var raw *ecdh.PublicKey + switch src := src.(type) { + case *ecdh.PublicKey: + raw = src + case ecdh.PublicKey: + raw = &src + default: + return nil, fmt.Errorf(`cannot convert key type '%T' to ECDH jwk.Key`, src) + } + + switch raw.Curve() { + case ecdh.X25519(): + return okpPublicKeyToJWK(raw) + case ecdh.P256(): + return ecdhPublicKeyToECJWK(raw, elliptic.P256()) + case ecdh.P384(): + return ecdhPublicKeyToECJWK(raw, elliptic.P384()) + case ecdh.P521(): + return ecdhPublicKeyToECJWK(raw, elliptic.P521()) + default: + return nil, fmt.Errorf(`unsupported curve %s`, raw.Curve()) + } +} + +func ecdhPublicKeyToECJWK(raw *ecdh.PublicKey, crv elliptic.Curve) (Key, error) { + rawbytes := raw.Bytes() + size := ecutil.CalculateKeySize(crv) + var x, y big.Int + + x.SetBytes(rawbytes[1 : 1+size]) + y.SetBytes(rawbytes[1+size:]) + var ecdsaPriv ecdsa.PublicKey + ecdsaPriv.Curve = crv + ecdsaPriv.X = &x + ecdsaPriv.Y = &y + return ecdsaPublicKeyToJWK(&ecdsaPriv) +} + +// These may seem a bit repetitive and redandunt, but the problem is that +// each key type has its own Import method -- for example, Import(*ecdsa.PrivateKey) +// vs Import(*rsa.PrivateKey), and therefore they can't just be bundled into +// a single function. +func rsaPrivateKeyToJWK(src any) (Key, error) { + var raw *rsa.PrivateKey + switch src := src.(type) { + case *rsa.PrivateKey: + raw = src + case rsa.PrivateKey: + raw = &src + default: + return nil, fmt.Errorf(`cannot convert key type '%T' to RSA jwk.Key`, src) + } + k := newRSAPrivateKey() + if err := k.Import(raw); err != nil { + return nil, fmt.Errorf(`failed to initialize %T from %T: %w`, k, raw, err) + } + return k, nil +} + +func rsaPublicKeyToJWK(src any) (Key, error) { + var raw *rsa.PublicKey + switch src := src.(type) { + case *rsa.PublicKey: + raw = src + case rsa.PublicKey: + raw = &src + default: + return nil, fmt.Errorf(`cannot convert key type '%T' to RSA jwk.Key`, src) + } + k := newRSAPublicKey() + if err := k.Import(raw); err != nil { + return nil, fmt.Errorf(`failed to initialize %T from %T: %w`, k, raw, err) + } + return k, nil +} + +func ecdsaPrivateKeyToJWK(src any) (Key, error) { + var raw *ecdsa.PrivateKey + switch src := src.(type) { + case *ecdsa.PrivateKey: + raw = src + case ecdsa.PrivateKey: + raw = &src + default: + return nil, fmt.Errorf(`cannot convert key type '%T' to ECDSA jwk.Key`, src) + } + k := newECDSAPrivateKey() + if err := k.Import(raw); err != nil { + return nil, fmt.Errorf(`failed to initialize %T from %T: %w`, k, raw, err) + } + return k, nil +} + +func ecdsaPublicKeyToJWK(src any) (Key, error) { + var raw *ecdsa.PublicKey + switch src := src.(type) { + case *ecdsa.PublicKey: + raw = src + case ecdsa.PublicKey: + raw = &src + default: + return nil, fmt.Errorf(`cannot convert key type '%T' to ECDSA jwk.Key`, src) + } + k := newECDSAPublicKey() + if err := k.Import(raw); err != nil { + return nil, fmt.Errorf(`failed to initialize %T from %T: %w`, k, raw, err) + } + return k, nil +} + +func okpPrivateKeyToJWK(src any) (Key, error) { + var raw any + switch src.(type) { + case ed25519.PrivateKey, *ecdh.PrivateKey: + raw = src + case ecdh.PrivateKey: + raw = &src + default: + return nil, fmt.Errorf(`cannot convert key type '%T' to OKP jwk.Key`, src) + } + k := newOKPPrivateKey() + if err := k.Import(raw); err != nil { + return nil, fmt.Errorf(`failed to initialize %T from %T: %w`, k, raw, err) + } + return k, nil +} + +func okpPublicKeyToJWK(src any) (Key, error) { + var raw any + switch src.(type) { + case ed25519.PublicKey, *ecdh.PublicKey: + raw = src + case ecdh.PublicKey: + raw = &src + default: + return nil, fmt.Errorf(`jwk: convert raw to OKP jwk.Key: cannot convert key type '%T' to OKP jwk.Key`, src) + } + k := newOKPPublicKey() + if err := k.Import(raw); err != nil { + return nil, fmt.Errorf(`failed to initialize %T from %T: %w`, k, raw, err) + } + return k, nil +} + +func bytesToKey(src any) (Key, error) { + var raw []byte + switch src := src.(type) { + case []byte: + raw = src + default: + return nil, fmt.Errorf(`cannot convert key type '%T' to symmetric jwk.Key`, src) + } + + k := newSymmetricKey() + if err := k.Import(raw); err != nil { + return nil, fmt.Errorf(`failed to initialize %T from %T: %w`, k, raw, err) + } + return k, nil +} + +// Export converts a `jwk.Key` to a Export key. The dst argument must be a pointer to the +// object that the user wants the result to be assigned to. +// +// Normally you would pass a pointer to the zero value of the raw key type +// such as &(*rsa.PrivateKey) or &(*ecdsa.PublicKey), which gets assigned +// the converted key. +// +// If you do not know the exact type of a jwk.Key before attempting +// to obtain the raw key, you can simply pass a pointer to an +// empty interface as the second argument +// +// If you already know the exact type, it is recommended that you +// pass a pointer to the zero value of the actual key type for efficiency. +// +// Be careful when/if you are using a third party key type that implements +// the `jwk.Key` interface, as the first argument. This function tries hard +// to Do The Right Thing, but it is not guaranteed to work in all cases, +// especially when the object implements the `jwk.Key` interface via +// embedding. +func Export(key Key, dst any) error { + // dst better be a pointer + rv := reflect.ValueOf(dst) + if rv.Kind() != reflect.Ptr { + return fmt.Errorf(`jwk.Export: destination object must be a pointer`) + } + muKeyExporters.RLock() + exporters, ok := keyExporters[key.KeyType()] + muKeyExporters.RUnlock() + if !ok { + return fmt.Errorf(`jwk.Export: no exporters registered for key type '%T'`, key) + } + for _, conv := range exporters { + v, err := conv.Export(key, dst) + if err != nil { + if errors.Is(err, ContinueError()) { + continue + } + return fmt.Errorf(`jwk.Export: failed to export jwk.Key to raw format: %w`, err) + } + if err := blackmagic.AssignIfCompatible(dst, v); err != nil { + return fmt.Errorf(`jwk.Export: failed to assign key: %w`, err) + } + return nil + } + return fmt.Errorf(`jwk.Export: no suitable exporter found for key type '%T'`, key) +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwk/doc.go b/vendor/github.com/lestrrat-go/jwx/v3/jwk/doc.go new file mode 100644 index 00000000000..7df707521b1 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwk/doc.go @@ -0,0 +1,294 @@ +// Package jwk implements JWK as described in https://tools.ietf.org/html/rfc7517 +// +// This package implements jwk.Key to represent a single JWK, and jwk.Set to represent +// a set of JWKs. +// +// The `jwk.Key` type is an interface, which hides the underlying implementation for +// each key type. Each key type can further be converted to interfaces for known +// types, such as `jwk.ECDSAPrivateKey`, `jwk.RSAPublicKey`, etc. This may not necessarily +// work for third party key types (see section on "Registering a key type" below). +// +// Users can create a JWK in two ways. One is to unmarshal a JSON representation of a +// key. The second one is to use `jwk.Import()` to import a raw key and convert it to +// a jwk.Key. +// +// # Simple Usage +// +// You can parse a JWK from a JSON payload: +// +// jwk.ParseKey([]byte(`{"kty":"EC",...}`)) +// +// You can go back and forth between raw key types and JWKs: +// +// jwkKey, _ := jwk.Import(rsaPrivateKey) +// var rawKey *rsa.PRrivateKey +// jwkKey.Raw(&rawKey) +// +// You can use them to sign/verify/encrypt/decrypt: +// +// jws.Sign([]byte(`...`), jws.WithKey(jwa.RS256, jwkKey)) +// jwe.Encrypt([]byte(`...`), jwe.WithKey(jwa.RSA_OAEP, jwkKey)) +// +// See examples/jwk_parse_example_test.go and other files in the exmaples/ directory for more. +// +// # Advanced Usage: Registering a custom key type and conversion routines +// +// Caveat Emptor: Functionality around registering keys +// (KeyProbe/KeyParser/KeyImporter/KeyExporter) should be considered experimental. +// While we expect that the functionality itself will remain, the API may +// change in backward incompatible ways, even during minor version +// releases. +// +// ## tl;dr +// +// * KeyProbe: Used for parsing JWKs in JSON format. Probes hint fields to be used for later parsing by KeyParser +// * KeyParser: Used for parsing JWKs in JSON format. Parses the JSON payload into a jwk.Key using the KeyProbe as hint +// * KeyImporter: Used for converting raw key into jwk.Key. +// * KeyExporter: Used for converting jwk.Key into raw key. +// +// ## Overview +// +// You can add the ability to use a JWK type that this library does not +// implement out of the box. You can do this by registering your own +// KeyParser, KeyImporter, and KeyExporter instances. +// +// func init() { +// jwk.RegiserProbeField(reflect.StructField{Name: "SomeHint", Type: reflect.TypeOf(""), Tag: `json:"some_hint"`}) +// jwk.RegisterKeyParser(&MyKeyParser{}) +// jwk.RegisterKeyImporter(&MyKeyImporter{}) +// jwk.RegisterKeyExporter(&MyKeyExporter{}) +// } +// +// The KeyParser is used to parse JSON payloads and conver them into a jwk.Key. +// The KeyImporter is used to convert a raw key (e.g. *rsa.PrivateKey, *ecdsa.PrivateKey, etc) into a jwk.Key. +// The KeyExporter is used to convert a jwk.Key into a raw key. +// +// Although we believe the mechanism has been streamline quite a lot, it is also true +// that the entire process of parsing and converting keys are much more convoluted than you might +// think. Please know before hand that if you intend to add support for a new key type, +// it _WILL_ require you to learn this module pretty much in-and-out. +// +// Read on for more explanation. +// +// ## Registering a KeyParser +// +// In order to understand how parsing works, we need to explain how the `jwk.ParseKey()` works. +// +// The first thing that occurs when parsing a key is a partial +// unmarshaling of the payload into a hint / probe object. +// +// Because the `json.Unmarshal` works by calling the `UnmarshalJSON` +// method on a concrete object, we need to create a concrete object first. +// In order/ to create the appropriate Go object, we need to know which concrete +// object to create from the JSON payload, meaning we need to peek into the +// payload and figure out what type of key it is. +// +// In order to do this, we effectively need to parse the JSON payload twice. +// First, we "probe" the payload to figure out what kind of key it is, then +// we parse it again to create the actual key object. +// +// For probing, we create a new "probe" object (KeyProbe, which is not +// directly available to end users) to populate the object with hints from the payload. +// For example, a JWK representing an RSA key would look like: +// +// { "kty": "RSA", "n": ..., "e": ..., ... } +// +// The default KeyProbe is constructed to unmarshal "kty" and "d" fields, +// because that is enough information to determine what kind of key to +// construct. +// +// For example, if the payload contains "kty" field with the value "RSA", +// we know that it's an RSA key. If it contains "EC", we know that it's +// an EC key. Furthermore, if the payload contains some value in the "d" field, we can +// also tell that this is a private key, as only private keys need +// this field. +// +// For most cases, the default KeyProbe implementation should be sufficient. +// However, there may be cases in the future where there are new key types +// that require further information. Perhaps you are embedding another hint +// in your JWK to further specify what kind of key it is. In that case, you +// would need to probe more. +// +// Normally you can only change how an object is unmarshaled by specifying +// JSON tags when defining a struct, but we use `reflect` package capabilities +// to create an object dynamically, which is shared among all parsing operations. +// +// To add a new field to be probed, you need to register a new `reflect.StructField` +// object that has all of the information. For example, the code below would +// register a field named "MyHint" that is of type string, and has a JSON tag +// of "my_hint". +// +// jwk.RegisterProbeField(reflect.StructField{Name: "MyHint", Type: reflect.TypeOf(""), Tag: `json:"my_hint"`}) +// +// The value of this field can be retrieved by calling `Get()` method on the +// KeyProbe object (from the `KeyParser`'s `ParseKey()` method discussed later) +// +// var myhint string +// _ = probe.Get("MyHint", &myhint) +// +// var kty string +// _ = probe.Get("Kty", &kty) +// +// This mechanism allows you to be flexible when trying to determine the key type +// to instantiate. +// +// ## Parse via the KeyParser +// +// When `jwk.Parse` / `jwk.ParseKey` is called, the library will first probe +// the payload as discussed above. +// +// Once the probe is done, the library will iterate over the registered parsers +// and attempt to parse the key by calling their `ParseKey()` methods. +// +// The parsers will be called in reverse order that they were registered. +// This means that it will try all parsers that were registered by third +// parties, and once those are exhausted, the default parser will be used. +// +// Each parser's `ParseKey()“ method will receive three arguments: the probe object, a +// KeyUnmarshaler, and the raw payload. The probe object can be used +// as a hint to determine what kind of key to instantiate. An example +// pseudocode may look like this: +// +// var kty string +// _ = probe.Get("Kty", &kty) +// switch kty { +// case "RSA": +// // create an RSA key +// case "EC": +// // create an EC key +// ... +// } +// +// The `KeyUnmarshaler` is a thin wrapper around `json.Unmarshal`. It works almost +// identical to `json.Unmarshal`, but it allows us to add extra magic that is +// specific to this library (which users do not need to be aware of) before calling +// the actual `json.Unmarshal`. Please use the `KeyUnmarshaler` to unmarshal JWKs instead of `json.Unmarshal`. +// +// Putting it all together, the boiler plate for registering a new parser may look like this: +// +// func init() { +// jwk.RegisterFieldProbe(reflect.StructField{Name: "MyHint", Type: reflect.TypeOf(""), Tag: `json:"my_hint"`}) +// jwk.RegisterParser(&MyKeyParser{}) +// } +// +// type MyKeyParser struct { ... } +// func(*MyKeyParser) ParseKey(rawProbe *KeyProbe, unmarshaler KeyUnmarshaler, data []byte) (jwk.Key, error) { +// // Create concrete type +// var hint string +// if err := probe.Get("MyHint", &hint); err != nil { +// // if it doesn't have the `my_hint` field, it probably means +// // it's not for us, so we return ContinueParseError so that +// // the next parser can pick it up +// return nil, jwk.ContinueParseError() +// } +// +// // Use hint to determine concrete key type +// var key jwk.Key +// switch hint { +// case ...: +// key = = myNewAwesomeJWK() +// ... +// } +// +// return unmarshaler.Unmarshal(data, key) +// } +// +// ## Registering KeyImporter/KeyExporter +// +// If you are going to do anything with the key that was parsed by your KeyParser, +// you will need to tell the library how to convert back and forth between +// raw keys and JWKs. Conversion from raw keys to jwk.Keys are done by KeyImporters, +// and conversion from jwk.Keys to raw keys are done by KeyExporters. +// +// ## Using jwk.Import() using KeyImporter +// +// Each KeyImporter is hooked to run against a specific raw key type. +// +// When `jwk.Import()` is called, the library will iterate over all registered +// KeyImporters for the specified raw key type, and attempt to convert the raw +// key to a JWK by calling the `Import()` method on each KeyImporter. +// +// The KeyImporter's `Import()` method will receive the raw key to be converted, +// and should return a JWK or an error if the conversion fails, or the return +// `jwk.ContinueError()` if the specified raw key cannot be handled by ths/ KeyImporter. +// +// Once a KeyImporter is available, you will be able to pass the raw key to `jwk.Import()`. +// The following example shows how you might register a KeyImporter for a hypotheical +// mypkg.SuperSecretKey: +// +// jwk.RegisterKeyImporter(&mypkg.SuperSecretKey{}, jwk.KeyImportFunc(imnportSuperSecretKey)) +// +// func importSuperSecretKey(key any) (jwk.Key, error) { +// mykey, ok := key.(*mypkg.SuperSecretKey) +// if !ok { +// // You must return jwk.ContinueError here, or otherwise +// // processing will stop with an error +// return nil, fmt.Errorf("invalid key type %T for importer: %w", key, jwk.ContinueError()) +// } +// +// return mypkg.SuperSecretJWK{ .... }, nil // You could reuse existing JWK types if you can +// } +// +// ## Registering a KeyExporter +// +// KeyExporters are the opposite of KeyImporters: they convert a JWK to a raw key when `key.Raw(...)` is +// called. If you intend to use `key.Raw(...)` for a JWK created using one of your KeyImporters, +// you will also +// +// KeyExporters are registered by key type. For example, if you want to register a KeyExporter for +// RSA keys, you would do: +// +// jwk.RegisterKeyExporter(jwa.RSA, jwk.KeyExportFunc(exportRSAKey)) +// +// For a given JWK, it will be passed a "destination" object to store the exported raw key. For example, +// an RSA-based private JWK can be exported to a `*rsa.PrivateKey` or to a `*any`, but not +// to a `*ecdsa.PrivateKey`: +// +// var dst *rsa.PrivateKey +// key.Raw(&dst) // OK +// +// var dst any +// key.Raw(&dst) // OK +// +// var dst *ecdsa.PrivateKey +// key.Raw(&dst) // Error, if key is an RSA key +// +// You will need to handle this distinction yourself in your KeyImporter. For example, certain +// elliptic curve keys can be expressed in JWK in the same format, minus the "kty". In that case +// you will need to check for the type of the destination object and return an error if it is +// not compatible with your key. +// +// var raw mypkg.PrivateKey // assume a hypothetical private key type using a different curve than standard ones lie P-256 +// key, _ := jwk.Import(raw) +// // key could be jwk.ECDSAPrivateKey, with different curve than P-256 +// +// var dst *ecdsa.PrivateKey +// key.Raw(&dst) // your KeyImporter will be called with *ecdsa.PrivateKey, which is not compatible with your key +// +// To implement this your code should look like the following: +// +// jwk.RegisterKeyExporter(jwk.EC, jwk.KeyExportFunc(exportMyKey)) +// +// func exportMyKey(key jwk.Key, hint any) (any, error) { +// // check if the type of object in hint is compatible with your key +// switch hint.(type) { +// case *mypkg.PrivateKey, *any: +// // OK, we can proceed +// default: +// // Not compatible, return jwk.ContinueError +// return nil, jwk.ContinueError() +// } +// +// // key is a jwk.ECDSAPrivateKey or jwk.ECDSAPublicKey +// switch key := key.(type) { +// case jwk.ECDSAPrivateKey: +// // convert key to mypkg.PrivateKey +// case jwk.ECDSAPublicKey: +// // convert key to mypkg.PublicKey +// default: +// // Not compatible, return jwk.ContinueError +// return nil, jwk.ContinueError() +// } +// return ..., nil +// } +package jwk diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwk/ecdsa.go b/vendor/github.com/lestrrat-go/jwx/v3/jwk/ecdsa.go new file mode 100644 index 00000000000..3dcd33bb1f4 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwk/ecdsa.go @@ -0,0 +1,402 @@ +package jwk + +import ( + "crypto" + "crypto/ecdh" + "crypto/ecdsa" + "crypto/elliptic" + "fmt" + "math/big" + "reflect" + + "github.com/lestrrat-go/jwx/v3/internal/base64" + "github.com/lestrrat-go/jwx/v3/internal/ecutil" + "github.com/lestrrat-go/jwx/v3/jwa" + ourecdsa "github.com/lestrrat-go/jwx/v3/jwk/ecdsa" +) + +func init() { + ourecdsa.RegisterCurve(jwa.P256(), elliptic.P256()) + ourecdsa.RegisterCurve(jwa.P384(), elliptic.P384()) + ourecdsa.RegisterCurve(jwa.P521(), elliptic.P521()) + + RegisterKeyExporter(jwa.EC(), KeyExportFunc(ecdsaJWKToRaw)) +} + +func (k *ecdsaPublicKey) Import(rawKey *ecdsa.PublicKey) error { + k.mu.Lock() + defer k.mu.Unlock() + + if rawKey.X == nil { + return fmt.Errorf(`invalid ecdsa.PublicKey`) + } + + if rawKey.Y == nil { + return fmt.Errorf(`invalid ecdsa.PublicKey`) + } + + xbuf := ecutil.AllocECPointBuffer(rawKey.X, rawKey.Curve) + ybuf := ecutil.AllocECPointBuffer(rawKey.Y, rawKey.Curve) + defer ecutil.ReleaseECPointBuffer(xbuf) + defer ecutil.ReleaseECPointBuffer(ybuf) + + k.x = make([]byte, len(xbuf)) + copy(k.x, xbuf) + k.y = make([]byte, len(ybuf)) + copy(k.y, ybuf) + + alg, err := ourecdsa.AlgorithmFromCurve(rawKey.Curve) + if err != nil { + return fmt.Errorf(`jwk: failed to get algorithm for converting ECDSA public key to JWK: %w`, err) + } + k.crv = &alg + + return nil +} + +func (k *ecdsaPrivateKey) Import(rawKey *ecdsa.PrivateKey) error { + k.mu.Lock() + defer k.mu.Unlock() + + if rawKey.PublicKey.X == nil { + return fmt.Errorf(`invalid ecdsa.PrivateKey`) + } + if rawKey.PublicKey.Y == nil { + return fmt.Errorf(`invalid ecdsa.PrivateKey`) + } + if rawKey.D == nil { + return fmt.Errorf(`invalid ecdsa.PrivateKey`) + } + + xbuf := ecutil.AllocECPointBuffer(rawKey.PublicKey.X, rawKey.Curve) + ybuf := ecutil.AllocECPointBuffer(rawKey.PublicKey.Y, rawKey.Curve) + dbuf := ecutil.AllocECPointBuffer(rawKey.D, rawKey.Curve) + defer ecutil.ReleaseECPointBuffer(xbuf) + defer ecutil.ReleaseECPointBuffer(ybuf) + defer ecutil.ReleaseECPointBuffer(dbuf) + + k.x = make([]byte, len(xbuf)) + copy(k.x, xbuf) + k.y = make([]byte, len(ybuf)) + copy(k.y, ybuf) + k.d = make([]byte, len(dbuf)) + copy(k.d, dbuf) + + alg, err := ourecdsa.AlgorithmFromCurve(rawKey.Curve) + if err != nil { + return fmt.Errorf(`jwk: failed to get algorithm for converting ECDSA private key to JWK: %w`, err) + } + k.crv = &alg + + return nil +} + +func buildECDSAPublicKey(alg jwa.EllipticCurveAlgorithm, xbuf, ybuf []byte) (*ecdsa.PublicKey, error) { + crv, err := ourecdsa.CurveFromAlgorithm(alg) + if err != nil { + return nil, fmt.Errorf(`jwk: failed to get algorithm for ECDSA public key: %w`, err) + } + + var x, y big.Int + x.SetBytes(xbuf) + y.SetBytes(ybuf) + + return &ecdsa.PublicKey{Curve: crv, X: &x, Y: &y}, nil +} + +func buildECDHPublicKey(alg jwa.EllipticCurveAlgorithm, xbuf, ybuf []byte) (*ecdh.PublicKey, error) { + var ecdhcrv ecdh.Curve + switch alg { + case jwa.X25519(): + ecdhcrv = ecdh.X25519() + case jwa.P256(): + ecdhcrv = ecdh.P256() + case jwa.P384(): + ecdhcrv = ecdh.P384() + case jwa.P521(): + ecdhcrv = ecdh.P521() + default: + return nil, fmt.Errorf(`jwk: unsupported ECDH curve %s`, alg) + } + + return ecdhcrv.NewPublicKey(append([]byte{0x04}, append(xbuf, ybuf...)...)) +} + +func buildECDHPrivateKey(alg jwa.EllipticCurveAlgorithm, dbuf []byte) (*ecdh.PrivateKey, error) { + var ecdhcrv ecdh.Curve + switch alg { + case jwa.X25519(): + ecdhcrv = ecdh.X25519() + case jwa.P256(): + ecdhcrv = ecdh.P256() + case jwa.P384(): + ecdhcrv = ecdh.P384() + case jwa.P521(): + ecdhcrv = ecdh.P521() + default: + return nil, fmt.Errorf(`jwk: unsupported ECDH curve %s`, alg) + } + + return ecdhcrv.NewPrivateKey(dbuf) +} + +var ecdsaConvertibleTypes = []reflect.Type{ + reflect.TypeOf((*ECDSAPrivateKey)(nil)).Elem(), + reflect.TypeOf((*ECDSAPublicKey)(nil)).Elem(), +} + +func ecdsaJWKToRaw(keyif Key, hint any) (any, error) { + var isECDH bool + + extracted, err := extractEmbeddedKey(keyif, ecdsaConvertibleTypes) + if err != nil { + return nil, fmt.Errorf(`jwk: failed to extract embedded key: %w`, err) + } + + switch k := extracted.(type) { + case ECDSAPrivateKey: + switch hint.(type) { + case ecdsa.PrivateKey, *ecdsa.PrivateKey: + case ecdh.PrivateKey, *ecdh.PrivateKey: + isECDH = true + default: + rv := reflect.ValueOf(hint) + //nolint:revive + if rv.Kind() == reflect.Ptr && rv.Elem().Kind() == reflect.Interface { + // pointer to an interface value, presumably they want us to dynamically + // create an object of the right type + } else { + return nil, fmt.Errorf(`invalid destination object type %T: %w`, hint, ContinueError()) + } + } + + locker, ok := k.(rlocker) + if ok { + locker.rlock() + defer locker.runlock() + } + + crv, ok := k.Crv() + if !ok { + return nil, fmt.Errorf(`missing "crv" field`) + } + + if isECDH { + d, ok := k.D() + if !ok { + return nil, fmt.Errorf(`missing "d" field`) + } + return buildECDHPrivateKey(crv, d) + } + + x, ok := k.X() + if !ok { + return nil, fmt.Errorf(`missing "x" field`) + } + y, ok := k.Y() + if !ok { + return nil, fmt.Errorf(`missing "y" field`) + } + pubk, err := buildECDSAPublicKey(crv, x, y) + if err != nil { + return nil, fmt.Errorf(`failed to build public key: %w`, err) + } + + var key ecdsa.PrivateKey + var d big.Int + + origD, ok := k.D() + if !ok { + return nil, fmt.Errorf(`missing "d" field`) + } + + d.SetBytes(origD) + key.D = &d + key.PublicKey = *pubk + + return &key, nil + case ECDSAPublicKey: + switch hint.(type) { + case ecdsa.PublicKey, *ecdsa.PublicKey: + case ecdh.PublicKey, *ecdh.PublicKey: + isECDH = true + default: + rv := reflect.ValueOf(hint) + //nolint:revive + if rv.Kind() == reflect.Ptr && rv.Elem().Kind() == reflect.Interface { + // pointer to an interface value, presumably they want us to dynamically + // create an object of the right type + } else { + return nil, fmt.Errorf(`invalid destination object type %T: %w`, hint, ContinueError()) + } + } + + locker, ok := k.(rlocker) + if ok { + locker.rlock() + defer locker.runlock() + } + + crv, ok := k.Crv() + if !ok { + return nil, fmt.Errorf(`missing "crv" field`) + } + + x, ok := k.X() + if !ok { + return nil, fmt.Errorf(`missing "x" field`) + } + + y, ok := k.Y() + if !ok { + return nil, fmt.Errorf(`missing "y" field`) + } + if isECDH { + return buildECDHPublicKey(crv, x, y) + } + return buildECDSAPublicKey(crv, x, y) + default: + return nil, ContinueError() + } +} + +func makeECDSAPublicKey(src Key) (Key, error) { + newKey := newECDSAPublicKey() + + // Iterate and copy everything except for the bits that should not be in the public key + for _, k := range src.Keys() { + switch k { + case ECDSADKey: + continue + default: + var v any + if err := src.Get(k, &v); err != nil { + return nil, fmt.Errorf(`ecdsa: makeECDSAPublicKey: failed to get field %q: %w`, k, err) + } + + if err := newKey.Set(k, v); err != nil { + return nil, fmt.Errorf(`ecdsa: makeECDSAPublicKey: failed to set field %q: %w`, k, err) + } + } + } + + return newKey, nil +} + +func (k *ecdsaPrivateKey) PublicKey() (Key, error) { + return makeECDSAPublicKey(k) +} + +func (k *ecdsaPublicKey) PublicKey() (Key, error) { + return makeECDSAPublicKey(k) +} + +func ecdsaThumbprint(hash crypto.Hash, crv, x, y string) []byte { + h := hash.New() + fmt.Fprint(h, `{"crv":"`) + fmt.Fprint(h, crv) + fmt.Fprint(h, `","kty":"EC","x":"`) + fmt.Fprint(h, x) + fmt.Fprint(h, `","y":"`) + fmt.Fprint(h, y) + fmt.Fprint(h, `"}`) + return h.Sum(nil) +} + +// Thumbprint returns the JWK thumbprint using the indicated +// hashing algorithm, according to RFC 7638 +func (k ecdsaPublicKey) Thumbprint(hash crypto.Hash) ([]byte, error) { + k.mu.RLock() + defer k.mu.RUnlock() + + var key ecdsa.PublicKey + if err := Export(&k, &key); err != nil { + return nil, fmt.Errorf(`failed to export ecdsa.PublicKey for thumbprint generation: %w`, err) + } + + xbuf := ecutil.AllocECPointBuffer(key.X, key.Curve) + ybuf := ecutil.AllocECPointBuffer(key.Y, key.Curve) + defer ecutil.ReleaseECPointBuffer(xbuf) + defer ecutil.ReleaseECPointBuffer(ybuf) + + return ecdsaThumbprint( + hash, + key.Curve.Params().Name, + base64.EncodeToString(xbuf), + base64.EncodeToString(ybuf), + ), nil +} + +// Thumbprint returns the JWK thumbprint using the indicated +// hashing algorithm, according to RFC 7638 +func (k ecdsaPrivateKey) Thumbprint(hash crypto.Hash) ([]byte, error) { + k.mu.RLock() + defer k.mu.RUnlock() + + var key ecdsa.PrivateKey + if err := Export(&k, &key); err != nil { + return nil, fmt.Errorf(`failed to export ecdsa.PrivateKey for thumbprint generation: %w`, err) + } + + xbuf := ecutil.AllocECPointBuffer(key.X, key.Curve) + ybuf := ecutil.AllocECPointBuffer(key.Y, key.Curve) + defer ecutil.ReleaseECPointBuffer(xbuf) + defer ecutil.ReleaseECPointBuffer(ybuf) + + return ecdsaThumbprint( + hash, + key.Curve.Params().Name, + base64.EncodeToString(xbuf), + base64.EncodeToString(ybuf), + ), nil +} + +func ecdsaValidateKey(k interface { + Crv() (jwa.EllipticCurveAlgorithm, bool) + X() ([]byte, bool) + Y() ([]byte, bool) +}, checkPrivate bool) error { + crvtyp, ok := k.Crv() + if !ok { + return fmt.Errorf(`missing "crv" field`) + } + + crv, err := ourecdsa.CurveFromAlgorithm(crvtyp) + if err != nil { + return fmt.Errorf(`invalid curve algorithm %q: %w`, crvtyp, err) + } + + keySize := ecutil.CalculateKeySize(crv) + if x, ok := k.X(); !ok || len(x) != keySize { + return fmt.Errorf(`invalid "x" length (%d) for curve %q`, len(x), crv.Params().Name) + } + + if y, ok := k.Y(); !ok || len(y) != keySize { + return fmt.Errorf(`invalid "y" length (%d) for curve %q`, len(y), crv.Params().Name) + } + + if checkPrivate { + if priv, ok := k.(keyWithD); ok { + if d, ok := priv.D(); !ok || len(d) != keySize { + return fmt.Errorf(`invalid "d" length (%d) for curve %q`, len(d), crv.Params().Name) + } + } else { + return fmt.Errorf(`missing "d" value`) + } + } + return nil +} + +func (k *ecdsaPrivateKey) Validate() error { + if err := ecdsaValidateKey(k, true); err != nil { + return NewKeyValidationError(fmt.Errorf(`jwk.ECDSAPrivateKey: %w`, err)) + } + return nil +} + +func (k *ecdsaPublicKey) Validate() error { + if err := ecdsaValidateKey(k, false); err != nil { + return NewKeyValidationError(fmt.Errorf(`jwk.ECDSAPublicKey: %w`, err)) + } + return nil +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwk/ecdsa/BUILD.bazel b/vendor/github.com/lestrrat-go/jwx/v3/jwk/ecdsa/BUILD.bazel new file mode 100644 index 00000000000..bf058aa649a --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwk/ecdsa/BUILD.bazel @@ -0,0 +1,15 @@ +load("@rules_go//go:def.bzl", "go_library") + +go_library( + name = "ecdsa", + srcs = ["ecdsa.go"], + importpath = "github.com/lestrrat-go/jwx/v3/jwk/ecdsa", + visibility = ["//visibility:public"], + deps = ["//jwa"], +) + +alias( + name = "go_default_library", + actual = ":ecdsa", + visibility = ["//visibility:public"], +) diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwk/ecdsa/ecdsa.go b/vendor/github.com/lestrrat-go/jwx/v3/jwk/ecdsa/ecdsa.go new file mode 100644 index 00000000000..3392483218e --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwk/ecdsa/ecdsa.go @@ -0,0 +1,76 @@ +package ecdsa + +import ( + "crypto/elliptic" + "fmt" + "sync" + + "github.com/lestrrat-go/jwx/v3/jwa" +) + +var muCurves sync.RWMutex +var algToCurveMap map[jwa.EllipticCurveAlgorithm]elliptic.Curve +var curveToAlgMap map[elliptic.Curve]jwa.EllipticCurveAlgorithm +var algList []jwa.EllipticCurveAlgorithm + +func init() { + muCurves.Lock() + algToCurveMap = make(map[jwa.EllipticCurveAlgorithm]elliptic.Curve) + curveToAlgMap = make(map[elliptic.Curve]jwa.EllipticCurveAlgorithm) + muCurves.Unlock() +} + +// RegisterCurve registers a jwa.EllipticCurveAlgorithm constant and its +// corresponding elliptic.Curve object. Users do not need to call this unless +// they are registering a new ECDSA key type +func RegisterCurve(alg jwa.EllipticCurveAlgorithm, crv elliptic.Curve) { + muCurves.Lock() + defer muCurves.Unlock() + + algToCurveMap[alg] = crv + curveToAlgMap[crv] = alg + rebuildCurves() +} + +func rebuildCurves() { + l := len(algToCurveMap) + if cap(algList) < l { + algList = make([]jwa.EllipticCurveAlgorithm, 0, l) + } else { + algList = algList[:0] + } + + for alg := range algToCurveMap { + algList = append(algList, alg) + } +} + +// Algorithms returns the list of registered jwa.EllipticCurveAlgorithms +// that ca be used for ECDSA keys. +func Algorithms() []jwa.EllipticCurveAlgorithm { + muCurves.RLock() + defer muCurves.RUnlock() + + return algList +} + +func AlgorithmFromCurve(crv elliptic.Curve) (jwa.EllipticCurveAlgorithm, error) { + alg, ok := curveToAlgMap[crv] + if !ok { + return jwa.InvalidEllipticCurve(), fmt.Errorf(`unknown elliptic curve: %q`, crv) + } + return alg, nil +} + +func CurveFromAlgorithm(alg jwa.EllipticCurveAlgorithm) (elliptic.Curve, error) { + crv, ok := algToCurveMap[alg] + if !ok { + return nil, fmt.Errorf(`unknown elliptic curve algorithm: %q`, alg) + } + return crv, nil +} + +func IsCurveAvailable(alg jwa.EllipticCurveAlgorithm) bool { + _, ok := algToCurveMap[alg] + return ok +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwk/ecdsa_gen.go b/vendor/github.com/lestrrat-go/jwx/v3/jwk/ecdsa_gen.go new file mode 100644 index 00000000000..39536de3d8f --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwk/ecdsa_gen.go @@ -0,0 +1,1432 @@ +// Code generated by tools/cmd/genjwk/main.go. DO NOT EDIT. + +package jwk + +import ( + "bytes" + "fmt" + "sort" + "sync" + + "github.com/lestrrat-go/blackmagic" + "github.com/lestrrat-go/jwx/v3/cert" + "github.com/lestrrat-go/jwx/v3/internal/base64" + "github.com/lestrrat-go/jwx/v3/internal/json" + "github.com/lestrrat-go/jwx/v3/internal/pool" + "github.com/lestrrat-go/jwx/v3/internal/tokens" + "github.com/lestrrat-go/jwx/v3/jwa" +) + +const ( + ECDSACrvKey = "crv" + ECDSADKey = "d" + ECDSAXKey = "x" + ECDSAYKey = "y" +) + +type ECDSAPublicKey interface { + Key + Crv() (jwa.EllipticCurveAlgorithm, bool) + X() ([]byte, bool) + Y() ([]byte, bool) +} + +type ecdsaPublicKey struct { + algorithm *jwa.KeyAlgorithm // https://tools.ietf.org/html/rfc7517#section-4.4 + crv *jwa.EllipticCurveAlgorithm + keyID *string // https://tools.ietf.org/html/rfc7515#section-4.1.4 + keyOps *KeyOperationList // https://tools.ietf.org/html/rfc7517#section-4.3 + keyUsage *string // https://tools.ietf.org/html/rfc7517#section-4.2 + x []byte + x509CertChain *cert.Chain // https://tools.ietf.org/html/rfc7515#section-4.1.6 + x509CertThumbprint *string // https://tools.ietf.org/html/rfc7515#section-4.1.7 + x509CertThumbprintS256 *string // https://tools.ietf.org/html/rfc7515#section-4.1.8 + x509URL *string // https://tools.ietf.org/html/rfc7515#section-4.1.5 + y []byte + privateParams map[string]any + mu *sync.RWMutex + dc json.DecodeCtx +} + +var _ ECDSAPublicKey = &ecdsaPublicKey{} +var _ Key = &ecdsaPublicKey{} + +func newECDSAPublicKey() *ecdsaPublicKey { + return &ecdsaPublicKey{ + mu: &sync.RWMutex{}, + privateParams: make(map[string]any), + } +} + +func (h ecdsaPublicKey) KeyType() jwa.KeyType { + return jwa.EC() +} + +func (h ecdsaPublicKey) rlock() { + h.mu.RLock() +} + +func (h ecdsaPublicKey) runlock() { + h.mu.RUnlock() +} + +func (h ecdsaPublicKey) IsPrivate() bool { + return false +} + +func (h *ecdsaPublicKey) Algorithm() (jwa.KeyAlgorithm, bool) { + if h.algorithm != nil { + return *(h.algorithm), true + } + return nil, false +} + +func (h *ecdsaPublicKey) Crv() (jwa.EllipticCurveAlgorithm, bool) { + if h.crv != nil { + return *(h.crv), true + } + return jwa.InvalidEllipticCurve(), false +} + +func (h *ecdsaPublicKey) KeyID() (string, bool) { + if h.keyID != nil { + return *(h.keyID), true + } + return "", false +} + +func (h *ecdsaPublicKey) KeyOps() (KeyOperationList, bool) { + if h.keyOps != nil { + return *(h.keyOps), true + } + return nil, false +} + +func (h *ecdsaPublicKey) KeyUsage() (string, bool) { + if h.keyUsage != nil { + return *(h.keyUsage), true + } + return "", false +} + +func (h *ecdsaPublicKey) X() ([]byte, bool) { + if h.x != nil { + return h.x, true + } + return nil, false +} + +func (h *ecdsaPublicKey) X509CertChain() (*cert.Chain, bool) { + return h.x509CertChain, true +} + +func (h *ecdsaPublicKey) X509CertThumbprint() (string, bool) { + if h.x509CertThumbprint != nil { + return *(h.x509CertThumbprint), true + } + return "", false +} + +func (h *ecdsaPublicKey) X509CertThumbprintS256() (string, bool) { + if h.x509CertThumbprintS256 != nil { + return *(h.x509CertThumbprintS256), true + } + return "", false +} + +func (h *ecdsaPublicKey) X509URL() (string, bool) { + if h.x509URL != nil { + return *(h.x509URL), true + } + return "", false +} + +func (h *ecdsaPublicKey) Y() ([]byte, bool) { + if h.y != nil { + return h.y, true + } + return nil, false +} + +func (h *ecdsaPublicKey) Has(name string) bool { + h.mu.RLock() + defer h.mu.RUnlock() + switch name { + case KeyTypeKey: + return true + case AlgorithmKey: + return h.algorithm != nil + case ECDSACrvKey: + return h.crv != nil + case KeyIDKey: + return h.keyID != nil + case KeyOpsKey: + return h.keyOps != nil + case KeyUsageKey: + return h.keyUsage != nil + case ECDSAXKey: + return h.x != nil + case X509CertChainKey: + return h.x509CertChain != nil + case X509CertThumbprintKey: + return h.x509CertThumbprint != nil + case X509CertThumbprintS256Key: + return h.x509CertThumbprintS256 != nil + case X509URLKey: + return h.x509URL != nil + case ECDSAYKey: + return h.y != nil + default: + _, ok := h.privateParams[name] + return ok + } +} + +func (h *ecdsaPublicKey) Get(name string, dst any) error { + h.mu.RLock() + defer h.mu.RUnlock() + switch name { + case KeyTypeKey: + if err := blackmagic.AssignIfCompatible(dst, h.KeyType()); err != nil { + return fmt.Errorf(`ecdsaPublicKey.Get: failed to assign value for field %q to destination object: %w`, name, err) + } + case AlgorithmKey: + if h.algorithm == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.algorithm)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case ECDSACrvKey: + if h.crv == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.crv)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case KeyIDKey: + if h.keyID == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.keyID)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case KeyOpsKey: + if h.keyOps == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.keyOps)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case KeyUsageKey: + if h.keyUsage == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.keyUsage)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case ECDSAXKey: + if h.x == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, h.x); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case X509CertChainKey: + if h.x509CertChain == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, h.x509CertChain); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case X509CertThumbprintKey: + if h.x509CertThumbprint == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.x509CertThumbprint)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case X509CertThumbprintS256Key: + if h.x509CertThumbprintS256 == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.x509CertThumbprintS256)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case X509URLKey: + if h.x509URL == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.x509URL)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case ECDSAYKey: + if h.y == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, h.y); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + default: + v, ok := h.privateParams[name] + if !ok { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, v); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + } + return nil +} + +func (h *ecdsaPublicKey) Set(name string, value any) error { + h.mu.Lock() + defer h.mu.Unlock() + return h.setNoLock(name, value) +} + +func (h *ecdsaPublicKey) setNoLock(name string, value any) error { + switch name { + case "kty": + return nil + case AlgorithmKey: + switch v := value.(type) { + case string, jwa.SignatureAlgorithm, jwa.KeyEncryptionAlgorithm, jwa.ContentEncryptionAlgorithm: + tmp, err := jwa.KeyAlgorithmFrom(v) + if err != nil { + return fmt.Errorf(`invalid algorithm for %q key: %w`, AlgorithmKey, err) + } + h.algorithm = &tmp + default: + return fmt.Errorf(`invalid type for %q key: %T`, AlgorithmKey, value) + } + return nil + case ECDSACrvKey: + if v, ok := value.(jwa.EllipticCurveAlgorithm); ok { + h.crv = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, ECDSACrvKey, value) + case KeyIDKey: + if v, ok := value.(string); ok { + h.keyID = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, KeyIDKey, value) + case KeyOpsKey: + var acceptor KeyOperationList + if err := acceptor.Accept(value); err != nil { + return fmt.Errorf(`invalid value for %s key: %w`, KeyOpsKey, err) + } + h.keyOps = &acceptor + return nil + case KeyUsageKey: + switch v := value.(type) { + case KeyUsageType: + switch v { + case ForSignature, ForEncryption: + tmp := v.String() + h.keyUsage = &tmp + default: + return fmt.Errorf(`invalid key usage type %s`, v) + } + case string: + h.keyUsage = &v + default: + return fmt.Errorf(`invalid key usage type %s`, v) + } + case ECDSAXKey: + if v, ok := value.([]byte); ok { + h.x = v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, ECDSAXKey, value) + case X509CertChainKey: + if v, ok := value.(*cert.Chain); ok { + h.x509CertChain = v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, X509CertChainKey, value) + case X509CertThumbprintKey: + if v, ok := value.(string); ok { + h.x509CertThumbprint = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, X509CertThumbprintKey, value) + case X509CertThumbprintS256Key: + if v, ok := value.(string); ok { + h.x509CertThumbprintS256 = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, X509CertThumbprintS256Key, value) + case X509URLKey: + if v, ok := value.(string); ok { + h.x509URL = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, X509URLKey, value) + case ECDSAYKey: + if v, ok := value.([]byte); ok { + h.y = v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, ECDSAYKey, value) + default: + if h.privateParams == nil { + h.privateParams = map[string]any{} + } + h.privateParams[name] = value + } + return nil +} + +func (k *ecdsaPublicKey) Remove(key string) error { + k.mu.Lock() + defer k.mu.Unlock() + switch key { + case AlgorithmKey: + k.algorithm = nil + case ECDSACrvKey: + k.crv = nil + case KeyIDKey: + k.keyID = nil + case KeyOpsKey: + k.keyOps = nil + case KeyUsageKey: + k.keyUsage = nil + case ECDSAXKey: + k.x = nil + case X509CertChainKey: + k.x509CertChain = nil + case X509CertThumbprintKey: + k.x509CertThumbprint = nil + case X509CertThumbprintS256Key: + k.x509CertThumbprintS256 = nil + case X509URLKey: + k.x509URL = nil + case ECDSAYKey: + k.y = nil + default: + delete(k.privateParams, key) + } + return nil +} + +func (k *ecdsaPublicKey) Clone() (Key, error) { + key, err := cloneKey(k) + if err != nil { + return nil, fmt.Errorf(`ecdsaPublicKey.Clone: %w`, err) + } + return key, nil +} + +func (k *ecdsaPublicKey) DecodeCtx() json.DecodeCtx { + k.mu.RLock() + defer k.mu.RUnlock() + return k.dc +} + +func (k *ecdsaPublicKey) SetDecodeCtx(dc json.DecodeCtx) { + k.mu.Lock() + defer k.mu.Unlock() + k.dc = dc +} + +func (h *ecdsaPublicKey) UnmarshalJSON(buf []byte) error { + h.mu.Lock() + defer h.mu.Unlock() + h.algorithm = nil + h.crv = nil + h.keyID = nil + h.keyOps = nil + h.keyUsage = nil + h.x = nil + h.x509CertChain = nil + h.x509CertThumbprint = nil + h.x509CertThumbprintS256 = nil + h.x509URL = nil + h.y = nil + dec := json.NewDecoder(bytes.NewReader(buf)) +LOOP: + for { + tok, err := dec.Token() + if err != nil { + return fmt.Errorf(`error reading token: %w`, err) + } + switch tok := tok.(type) { + case json.Delim: + // Assuming we're doing everything correctly, we should ONLY + // get either tokens.OpenCurlyBracket or tokens.CloseCurlyBracket here. + if tok == tokens.CloseCurlyBracket { // End of object + break LOOP + } else if tok != tokens.OpenCurlyBracket { + return fmt.Errorf(`expected '%c' but got '%c'`, tokens.OpenCurlyBracket, tok) + } + case string: // Objects can only have string keys + switch tok { + case KeyTypeKey: + val, err := json.ReadNextStringToken(dec) + if err != nil { + return fmt.Errorf(`error reading token: %w`, err) + } + if val != jwa.EC().String() { + return fmt.Errorf(`invalid kty value for RSAPublicKey (%s)`, val) + } + case AlgorithmKey: + var s string + if err := dec.Decode(&s); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, AlgorithmKey, err) + } + alg, err := jwa.KeyAlgorithmFrom(s) + if err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, AlgorithmKey, err) + } + h.algorithm = &alg + case ECDSACrvKey: + var decoded jwa.EllipticCurveAlgorithm + if err := dec.Decode(&decoded); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, ECDSACrvKey, err) + } + h.crv = &decoded + case KeyIDKey: + if err := json.AssignNextStringToken(&h.keyID, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, KeyIDKey, err) + } + case KeyOpsKey: + var decoded KeyOperationList + if err := dec.Decode(&decoded); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, KeyOpsKey, err) + } + h.keyOps = &decoded + case KeyUsageKey: + if err := json.AssignNextStringToken(&h.keyUsage, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, KeyUsageKey, err) + } + case ECDSAXKey: + if err := json.AssignNextBytesToken(&h.x, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, ECDSAXKey, err) + } + case X509CertChainKey: + var decoded cert.Chain + if err := dec.Decode(&decoded); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, X509CertChainKey, err) + } + h.x509CertChain = &decoded + case X509CertThumbprintKey: + if err := json.AssignNextStringToken(&h.x509CertThumbprint, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, X509CertThumbprintKey, err) + } + case X509CertThumbprintS256Key: + if err := json.AssignNextStringToken(&h.x509CertThumbprintS256, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, X509CertThumbprintS256Key, err) + } + case X509URLKey: + if err := json.AssignNextStringToken(&h.x509URL, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, X509URLKey, err) + } + case ECDSAYKey: + if err := json.AssignNextBytesToken(&h.y, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, ECDSAYKey, err) + } + default: + if dc := h.dc; dc != nil { + if localReg := dc.Registry(); localReg != nil { + decoded, err := localReg.Decode(dec, tok) + if err == nil { + h.setNoLock(tok, decoded) + continue + } + } + } + decoded, err := registry.Decode(dec, tok) + if err == nil { + h.setNoLock(tok, decoded) + continue + } + return fmt.Errorf(`could not decode field %s: %w`, tok, err) + } + default: + return fmt.Errorf(`invalid token %T`, tok) + } + } + if h.crv == nil { + return fmt.Errorf(`required field crv is missing`) + } + if h.x == nil { + return fmt.Errorf(`required field x is missing`) + } + if h.y == nil { + return fmt.Errorf(`required field y is missing`) + } + return nil +} + +func (h ecdsaPublicKey) MarshalJSON() ([]byte, error) { + data := make(map[string]any) + fields := make([]string, 0, 11) + data[KeyTypeKey] = jwa.EC() + fields = append(fields, KeyTypeKey) + if h.algorithm != nil { + data[AlgorithmKey] = *(h.algorithm) + fields = append(fields, AlgorithmKey) + } + if h.crv != nil { + data[ECDSACrvKey] = *(h.crv) + fields = append(fields, ECDSACrvKey) + } + if h.keyID != nil { + data[KeyIDKey] = *(h.keyID) + fields = append(fields, KeyIDKey) + } + if h.keyOps != nil { + data[KeyOpsKey] = *(h.keyOps) + fields = append(fields, KeyOpsKey) + } + if h.keyUsage != nil { + data[KeyUsageKey] = *(h.keyUsage) + fields = append(fields, KeyUsageKey) + } + if h.x != nil { + data[ECDSAXKey] = h.x + fields = append(fields, ECDSAXKey) + } + if h.x509CertChain != nil { + data[X509CertChainKey] = h.x509CertChain + fields = append(fields, X509CertChainKey) + } + if h.x509CertThumbprint != nil { + data[X509CertThumbprintKey] = *(h.x509CertThumbprint) + fields = append(fields, X509CertThumbprintKey) + } + if h.x509CertThumbprintS256 != nil { + data[X509CertThumbprintS256Key] = *(h.x509CertThumbprintS256) + fields = append(fields, X509CertThumbprintS256Key) + } + if h.x509URL != nil { + data[X509URLKey] = *(h.x509URL) + fields = append(fields, X509URLKey) + } + if h.y != nil { + data[ECDSAYKey] = h.y + fields = append(fields, ECDSAYKey) + } + for k, v := range h.privateParams { + data[k] = v + fields = append(fields, k) + } + + sort.Strings(fields) + buf := pool.BytesBuffer().Get() + defer pool.BytesBuffer().Put(buf) + buf.WriteByte(tokens.OpenCurlyBracket) + enc := json.NewEncoder(buf) + for i, f := range fields { + if i > 0 { + buf.WriteRune(tokens.Comma) + } + buf.WriteRune(tokens.DoubleQuote) + buf.WriteString(f) + buf.WriteString(`":`) + v := data[f] + switch v := v.(type) { + case []byte: + buf.WriteRune(tokens.DoubleQuote) + buf.WriteString(base64.EncodeToString(v)) + buf.WriteRune(tokens.DoubleQuote) + default: + if err := enc.Encode(v); err != nil { + return nil, fmt.Errorf(`failed to encode value for field %s: %w`, f, err) + } + buf.Truncate(buf.Len() - 1) + } + } + buf.WriteByte(tokens.CloseCurlyBracket) + ret := make([]byte, buf.Len()) + copy(ret, buf.Bytes()) + return ret, nil +} + +func (h *ecdsaPublicKey) Keys() []string { + h.mu.RLock() + defer h.mu.RUnlock() + keys := make([]string, 0, 11+len(h.privateParams)) + keys = append(keys, KeyTypeKey) + if h.algorithm != nil { + keys = append(keys, AlgorithmKey) + } + if h.crv != nil { + keys = append(keys, ECDSACrvKey) + } + if h.keyID != nil { + keys = append(keys, KeyIDKey) + } + if h.keyOps != nil { + keys = append(keys, KeyOpsKey) + } + if h.keyUsage != nil { + keys = append(keys, KeyUsageKey) + } + if h.x != nil { + keys = append(keys, ECDSAXKey) + } + if h.x509CertChain != nil { + keys = append(keys, X509CertChainKey) + } + if h.x509CertThumbprint != nil { + keys = append(keys, X509CertThumbprintKey) + } + if h.x509CertThumbprintS256 != nil { + keys = append(keys, X509CertThumbprintS256Key) + } + if h.x509URL != nil { + keys = append(keys, X509URLKey) + } + if h.y != nil { + keys = append(keys, ECDSAYKey) + } + for k := range h.privateParams { + keys = append(keys, k) + } + return keys +} + +type ECDSAPrivateKey interface { + Key + Crv() (jwa.EllipticCurveAlgorithm, bool) + D() ([]byte, bool) + X() ([]byte, bool) + Y() ([]byte, bool) +} + +type ecdsaPrivateKey struct { + algorithm *jwa.KeyAlgorithm // https://tools.ietf.org/html/rfc7517#section-4.4 + crv *jwa.EllipticCurveAlgorithm + d []byte + keyID *string // https://tools.ietf.org/html/rfc7515#section-4.1.4 + keyOps *KeyOperationList // https://tools.ietf.org/html/rfc7517#section-4.3 + keyUsage *string // https://tools.ietf.org/html/rfc7517#section-4.2 + x []byte + x509CertChain *cert.Chain // https://tools.ietf.org/html/rfc7515#section-4.1.6 + x509CertThumbprint *string // https://tools.ietf.org/html/rfc7515#section-4.1.7 + x509CertThumbprintS256 *string // https://tools.ietf.org/html/rfc7515#section-4.1.8 + x509URL *string // https://tools.ietf.org/html/rfc7515#section-4.1.5 + y []byte + privateParams map[string]any + mu *sync.RWMutex + dc json.DecodeCtx +} + +var _ ECDSAPrivateKey = &ecdsaPrivateKey{} +var _ Key = &ecdsaPrivateKey{} + +func newECDSAPrivateKey() *ecdsaPrivateKey { + return &ecdsaPrivateKey{ + mu: &sync.RWMutex{}, + privateParams: make(map[string]any), + } +} + +func (h ecdsaPrivateKey) KeyType() jwa.KeyType { + return jwa.EC() +} + +func (h ecdsaPrivateKey) rlock() { + h.mu.RLock() +} + +func (h ecdsaPrivateKey) runlock() { + h.mu.RUnlock() +} + +func (h ecdsaPrivateKey) IsPrivate() bool { + return true +} + +func (h *ecdsaPrivateKey) Algorithm() (jwa.KeyAlgorithm, bool) { + if h.algorithm != nil { + return *(h.algorithm), true + } + return nil, false +} + +func (h *ecdsaPrivateKey) Crv() (jwa.EllipticCurveAlgorithm, bool) { + if h.crv != nil { + return *(h.crv), true + } + return jwa.InvalidEllipticCurve(), false +} + +func (h *ecdsaPrivateKey) D() ([]byte, bool) { + if h.d != nil { + return h.d, true + } + return nil, false +} + +func (h *ecdsaPrivateKey) KeyID() (string, bool) { + if h.keyID != nil { + return *(h.keyID), true + } + return "", false +} + +func (h *ecdsaPrivateKey) KeyOps() (KeyOperationList, bool) { + if h.keyOps != nil { + return *(h.keyOps), true + } + return nil, false +} + +func (h *ecdsaPrivateKey) KeyUsage() (string, bool) { + if h.keyUsage != nil { + return *(h.keyUsage), true + } + return "", false +} + +func (h *ecdsaPrivateKey) X() ([]byte, bool) { + if h.x != nil { + return h.x, true + } + return nil, false +} + +func (h *ecdsaPrivateKey) X509CertChain() (*cert.Chain, bool) { + return h.x509CertChain, true +} + +func (h *ecdsaPrivateKey) X509CertThumbprint() (string, bool) { + if h.x509CertThumbprint != nil { + return *(h.x509CertThumbprint), true + } + return "", false +} + +func (h *ecdsaPrivateKey) X509CertThumbprintS256() (string, bool) { + if h.x509CertThumbprintS256 != nil { + return *(h.x509CertThumbprintS256), true + } + return "", false +} + +func (h *ecdsaPrivateKey) X509URL() (string, bool) { + if h.x509URL != nil { + return *(h.x509URL), true + } + return "", false +} + +func (h *ecdsaPrivateKey) Y() ([]byte, bool) { + if h.y != nil { + return h.y, true + } + return nil, false +} + +func (h *ecdsaPrivateKey) Has(name string) bool { + h.mu.RLock() + defer h.mu.RUnlock() + switch name { + case KeyTypeKey: + return true + case AlgorithmKey: + return h.algorithm != nil + case ECDSACrvKey: + return h.crv != nil + case ECDSADKey: + return h.d != nil + case KeyIDKey: + return h.keyID != nil + case KeyOpsKey: + return h.keyOps != nil + case KeyUsageKey: + return h.keyUsage != nil + case ECDSAXKey: + return h.x != nil + case X509CertChainKey: + return h.x509CertChain != nil + case X509CertThumbprintKey: + return h.x509CertThumbprint != nil + case X509CertThumbprintS256Key: + return h.x509CertThumbprintS256 != nil + case X509URLKey: + return h.x509URL != nil + case ECDSAYKey: + return h.y != nil + default: + _, ok := h.privateParams[name] + return ok + } +} + +func (h *ecdsaPrivateKey) Get(name string, dst any) error { + h.mu.RLock() + defer h.mu.RUnlock() + switch name { + case KeyTypeKey: + if err := blackmagic.AssignIfCompatible(dst, h.KeyType()); err != nil { + return fmt.Errorf(`ecdsaPrivateKey.Get: failed to assign value for field %q to destination object: %w`, name, err) + } + case AlgorithmKey: + if h.algorithm == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.algorithm)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case ECDSACrvKey: + if h.crv == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.crv)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case ECDSADKey: + if h.d == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, h.d); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case KeyIDKey: + if h.keyID == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.keyID)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case KeyOpsKey: + if h.keyOps == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.keyOps)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case KeyUsageKey: + if h.keyUsage == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.keyUsage)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case ECDSAXKey: + if h.x == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, h.x); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case X509CertChainKey: + if h.x509CertChain == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, h.x509CertChain); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case X509CertThumbprintKey: + if h.x509CertThumbprint == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.x509CertThumbprint)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case X509CertThumbprintS256Key: + if h.x509CertThumbprintS256 == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.x509CertThumbprintS256)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case X509URLKey: + if h.x509URL == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.x509URL)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case ECDSAYKey: + if h.y == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, h.y); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + default: + v, ok := h.privateParams[name] + if !ok { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, v); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + } + return nil +} + +func (h *ecdsaPrivateKey) Set(name string, value any) error { + h.mu.Lock() + defer h.mu.Unlock() + return h.setNoLock(name, value) +} + +func (h *ecdsaPrivateKey) setNoLock(name string, value any) error { + switch name { + case "kty": + return nil + case AlgorithmKey: + switch v := value.(type) { + case string, jwa.SignatureAlgorithm, jwa.KeyEncryptionAlgorithm, jwa.ContentEncryptionAlgorithm: + tmp, err := jwa.KeyAlgorithmFrom(v) + if err != nil { + return fmt.Errorf(`invalid algorithm for %q key: %w`, AlgorithmKey, err) + } + h.algorithm = &tmp + default: + return fmt.Errorf(`invalid type for %q key: %T`, AlgorithmKey, value) + } + return nil + case ECDSACrvKey: + if v, ok := value.(jwa.EllipticCurveAlgorithm); ok { + h.crv = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, ECDSACrvKey, value) + case ECDSADKey: + if v, ok := value.([]byte); ok { + h.d = v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, ECDSADKey, value) + case KeyIDKey: + if v, ok := value.(string); ok { + h.keyID = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, KeyIDKey, value) + case KeyOpsKey: + var acceptor KeyOperationList + if err := acceptor.Accept(value); err != nil { + return fmt.Errorf(`invalid value for %s key: %w`, KeyOpsKey, err) + } + h.keyOps = &acceptor + return nil + case KeyUsageKey: + switch v := value.(type) { + case KeyUsageType: + switch v { + case ForSignature, ForEncryption: + tmp := v.String() + h.keyUsage = &tmp + default: + return fmt.Errorf(`invalid key usage type %s`, v) + } + case string: + h.keyUsage = &v + default: + return fmt.Errorf(`invalid key usage type %s`, v) + } + case ECDSAXKey: + if v, ok := value.([]byte); ok { + h.x = v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, ECDSAXKey, value) + case X509CertChainKey: + if v, ok := value.(*cert.Chain); ok { + h.x509CertChain = v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, X509CertChainKey, value) + case X509CertThumbprintKey: + if v, ok := value.(string); ok { + h.x509CertThumbprint = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, X509CertThumbprintKey, value) + case X509CertThumbprintS256Key: + if v, ok := value.(string); ok { + h.x509CertThumbprintS256 = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, X509CertThumbprintS256Key, value) + case X509URLKey: + if v, ok := value.(string); ok { + h.x509URL = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, X509URLKey, value) + case ECDSAYKey: + if v, ok := value.([]byte); ok { + h.y = v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, ECDSAYKey, value) + default: + if h.privateParams == nil { + h.privateParams = map[string]any{} + } + h.privateParams[name] = value + } + return nil +} + +func (k *ecdsaPrivateKey) Remove(key string) error { + k.mu.Lock() + defer k.mu.Unlock() + switch key { + case AlgorithmKey: + k.algorithm = nil + case ECDSACrvKey: + k.crv = nil + case ECDSADKey: + k.d = nil + case KeyIDKey: + k.keyID = nil + case KeyOpsKey: + k.keyOps = nil + case KeyUsageKey: + k.keyUsage = nil + case ECDSAXKey: + k.x = nil + case X509CertChainKey: + k.x509CertChain = nil + case X509CertThumbprintKey: + k.x509CertThumbprint = nil + case X509CertThumbprintS256Key: + k.x509CertThumbprintS256 = nil + case X509URLKey: + k.x509URL = nil + case ECDSAYKey: + k.y = nil + default: + delete(k.privateParams, key) + } + return nil +} + +func (k *ecdsaPrivateKey) Clone() (Key, error) { + key, err := cloneKey(k) + if err != nil { + return nil, fmt.Errorf(`ecdsaPrivateKey.Clone: %w`, err) + } + return key, nil +} + +func (k *ecdsaPrivateKey) DecodeCtx() json.DecodeCtx { + k.mu.RLock() + defer k.mu.RUnlock() + return k.dc +} + +func (k *ecdsaPrivateKey) SetDecodeCtx(dc json.DecodeCtx) { + k.mu.Lock() + defer k.mu.Unlock() + k.dc = dc +} + +func (h *ecdsaPrivateKey) UnmarshalJSON(buf []byte) error { + h.mu.Lock() + defer h.mu.Unlock() + h.algorithm = nil + h.crv = nil + h.d = nil + h.keyID = nil + h.keyOps = nil + h.keyUsage = nil + h.x = nil + h.x509CertChain = nil + h.x509CertThumbprint = nil + h.x509CertThumbprintS256 = nil + h.x509URL = nil + h.y = nil + dec := json.NewDecoder(bytes.NewReader(buf)) +LOOP: + for { + tok, err := dec.Token() + if err != nil { + return fmt.Errorf(`error reading token: %w`, err) + } + switch tok := tok.(type) { + case json.Delim: + // Assuming we're doing everything correctly, we should ONLY + // get either tokens.OpenCurlyBracket or tokens.CloseCurlyBracket here. + if tok == tokens.CloseCurlyBracket { // End of object + break LOOP + } else if tok != tokens.OpenCurlyBracket { + return fmt.Errorf(`expected '%c' but got '%c'`, tokens.OpenCurlyBracket, tok) + } + case string: // Objects can only have string keys + switch tok { + case KeyTypeKey: + val, err := json.ReadNextStringToken(dec) + if err != nil { + return fmt.Errorf(`error reading token: %w`, err) + } + if val != jwa.EC().String() { + return fmt.Errorf(`invalid kty value for RSAPublicKey (%s)`, val) + } + case AlgorithmKey: + var s string + if err := dec.Decode(&s); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, AlgorithmKey, err) + } + alg, err := jwa.KeyAlgorithmFrom(s) + if err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, AlgorithmKey, err) + } + h.algorithm = &alg + case ECDSACrvKey: + var decoded jwa.EllipticCurveAlgorithm + if err := dec.Decode(&decoded); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, ECDSACrvKey, err) + } + h.crv = &decoded + case ECDSADKey: + if err := json.AssignNextBytesToken(&h.d, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, ECDSADKey, err) + } + case KeyIDKey: + if err := json.AssignNextStringToken(&h.keyID, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, KeyIDKey, err) + } + case KeyOpsKey: + var decoded KeyOperationList + if err := dec.Decode(&decoded); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, KeyOpsKey, err) + } + h.keyOps = &decoded + case KeyUsageKey: + if err := json.AssignNextStringToken(&h.keyUsage, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, KeyUsageKey, err) + } + case ECDSAXKey: + if err := json.AssignNextBytesToken(&h.x, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, ECDSAXKey, err) + } + case X509CertChainKey: + var decoded cert.Chain + if err := dec.Decode(&decoded); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, X509CertChainKey, err) + } + h.x509CertChain = &decoded + case X509CertThumbprintKey: + if err := json.AssignNextStringToken(&h.x509CertThumbprint, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, X509CertThumbprintKey, err) + } + case X509CertThumbprintS256Key: + if err := json.AssignNextStringToken(&h.x509CertThumbprintS256, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, X509CertThumbprintS256Key, err) + } + case X509URLKey: + if err := json.AssignNextStringToken(&h.x509URL, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, X509URLKey, err) + } + case ECDSAYKey: + if err := json.AssignNextBytesToken(&h.y, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, ECDSAYKey, err) + } + default: + if dc := h.dc; dc != nil { + if localReg := dc.Registry(); localReg != nil { + decoded, err := localReg.Decode(dec, tok) + if err == nil { + h.setNoLock(tok, decoded) + continue + } + } + } + decoded, err := registry.Decode(dec, tok) + if err == nil { + h.setNoLock(tok, decoded) + continue + } + return fmt.Errorf(`could not decode field %s: %w`, tok, err) + } + default: + return fmt.Errorf(`invalid token %T`, tok) + } + } + if h.crv == nil { + return fmt.Errorf(`required field crv is missing`) + } + if h.d == nil { + return fmt.Errorf(`required field d is missing`) + } + if h.x == nil { + return fmt.Errorf(`required field x is missing`) + } + if h.y == nil { + return fmt.Errorf(`required field y is missing`) + } + return nil +} + +func (h ecdsaPrivateKey) MarshalJSON() ([]byte, error) { + data := make(map[string]any) + fields := make([]string, 0, 12) + data[KeyTypeKey] = jwa.EC() + fields = append(fields, KeyTypeKey) + if h.algorithm != nil { + data[AlgorithmKey] = *(h.algorithm) + fields = append(fields, AlgorithmKey) + } + if h.crv != nil { + data[ECDSACrvKey] = *(h.crv) + fields = append(fields, ECDSACrvKey) + } + if h.d != nil { + data[ECDSADKey] = h.d + fields = append(fields, ECDSADKey) + } + if h.keyID != nil { + data[KeyIDKey] = *(h.keyID) + fields = append(fields, KeyIDKey) + } + if h.keyOps != nil { + data[KeyOpsKey] = *(h.keyOps) + fields = append(fields, KeyOpsKey) + } + if h.keyUsage != nil { + data[KeyUsageKey] = *(h.keyUsage) + fields = append(fields, KeyUsageKey) + } + if h.x != nil { + data[ECDSAXKey] = h.x + fields = append(fields, ECDSAXKey) + } + if h.x509CertChain != nil { + data[X509CertChainKey] = h.x509CertChain + fields = append(fields, X509CertChainKey) + } + if h.x509CertThumbprint != nil { + data[X509CertThumbprintKey] = *(h.x509CertThumbprint) + fields = append(fields, X509CertThumbprintKey) + } + if h.x509CertThumbprintS256 != nil { + data[X509CertThumbprintS256Key] = *(h.x509CertThumbprintS256) + fields = append(fields, X509CertThumbprintS256Key) + } + if h.x509URL != nil { + data[X509URLKey] = *(h.x509URL) + fields = append(fields, X509URLKey) + } + if h.y != nil { + data[ECDSAYKey] = h.y + fields = append(fields, ECDSAYKey) + } + for k, v := range h.privateParams { + data[k] = v + fields = append(fields, k) + } + + sort.Strings(fields) + buf := pool.BytesBuffer().Get() + defer pool.BytesBuffer().Put(buf) + buf.WriteByte(tokens.OpenCurlyBracket) + enc := json.NewEncoder(buf) + for i, f := range fields { + if i > 0 { + buf.WriteRune(tokens.Comma) + } + buf.WriteRune(tokens.DoubleQuote) + buf.WriteString(f) + buf.WriteString(`":`) + v := data[f] + switch v := v.(type) { + case []byte: + buf.WriteRune(tokens.DoubleQuote) + buf.WriteString(base64.EncodeToString(v)) + buf.WriteRune(tokens.DoubleQuote) + default: + if err := enc.Encode(v); err != nil { + return nil, fmt.Errorf(`failed to encode value for field %s: %w`, f, err) + } + buf.Truncate(buf.Len() - 1) + } + } + buf.WriteByte(tokens.CloseCurlyBracket) + ret := make([]byte, buf.Len()) + copy(ret, buf.Bytes()) + return ret, nil +} + +func (h *ecdsaPrivateKey) Keys() []string { + h.mu.RLock() + defer h.mu.RUnlock() + keys := make([]string, 0, 12+len(h.privateParams)) + keys = append(keys, KeyTypeKey) + if h.algorithm != nil { + keys = append(keys, AlgorithmKey) + } + if h.crv != nil { + keys = append(keys, ECDSACrvKey) + } + if h.d != nil { + keys = append(keys, ECDSADKey) + } + if h.keyID != nil { + keys = append(keys, KeyIDKey) + } + if h.keyOps != nil { + keys = append(keys, KeyOpsKey) + } + if h.keyUsage != nil { + keys = append(keys, KeyUsageKey) + } + if h.x != nil { + keys = append(keys, ECDSAXKey) + } + if h.x509CertChain != nil { + keys = append(keys, X509CertChainKey) + } + if h.x509CertThumbprint != nil { + keys = append(keys, X509CertThumbprintKey) + } + if h.x509CertThumbprintS256 != nil { + keys = append(keys, X509CertThumbprintS256Key) + } + if h.x509URL != nil { + keys = append(keys, X509URLKey) + } + if h.y != nil { + keys = append(keys, ECDSAYKey) + } + for k := range h.privateParams { + keys = append(keys, k) + } + return keys +} + +var ecdsaStandardFields KeyFilter + +func init() { + ecdsaStandardFields = NewFieldNameFilter(KeyTypeKey, KeyUsageKey, KeyOpsKey, AlgorithmKey, KeyIDKey, X509URLKey, X509CertChainKey, X509CertThumbprintKey, X509CertThumbprintS256Key, ECDSACrvKey, ECDSAXKey, ECDSAYKey, ECDSADKey) +} + +// ECDSAStandardFieldsFilter returns a KeyFilter that filters out standard ECDSA fields. +func ECDSAStandardFieldsFilter() KeyFilter { + return ecdsaStandardFields +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwk/errors.go b/vendor/github.com/lestrrat-go/jwx/v3/jwk/errors.go new file mode 100644 index 00000000000..af7e00d952f --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwk/errors.go @@ -0,0 +1,79 @@ +package jwk + +import ( + "errors" + "fmt" +) + +var cpe = &continueError{} + +// ContinueError returns an opaque error that can be returned +// when a `KeyParser`, `KeyImporter`, or `KeyExporter` cannot handle the given payload, +// but would like the process to continue with the next handler. +func ContinueError() error { + return cpe +} + +type continueError struct{} + +func (e *continueError) Error() string { + return "continue parsing" +} + +type importError struct { + error +} + +func (e importError) Unwrap() error { + return e.error +} + +func (importError) Is(err error) bool { + _, ok := err.(importError) + return ok +} + +func importerr(f string, args ...any) error { + return importError{fmt.Errorf(`jwk.Import: `+f, args...)} +} + +var errDefaultImportError = importError{errors.New(`import error`)} + +func ImportError() error { + return errDefaultImportError +} + +type parseError struct { + error +} + +func (e parseError) Unwrap() error { + return e.error +} + +func (parseError) Is(err error) bool { + _, ok := err.(parseError) + return ok +} + +func bparseerr(prefix string, f string, args ...any) error { + return parseError{fmt.Errorf(prefix+`: `+f, args...)} +} + +func parseerr(f string, args ...any) error { + return bparseerr(`jwk.Parse`, f, args...) +} + +func rparseerr(f string, args ...any) error { + return bparseerr(`jwk.ParseReader`, f, args...) +} + +func sparseerr(f string, args ...any) error { + return bparseerr(`jwk.ParseString`, f, args...) +} + +var errDefaultParseError = parseError{errors.New(`parse error`)} + +func ParseError() error { + return errDefaultParseError +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwk/es256k.go b/vendor/github.com/lestrrat-go/jwx/v3/jwk/es256k.go new file mode 100644 index 00000000000..48114bbaeeb --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwk/es256k.go @@ -0,0 +1,14 @@ +//go:build jwx_es256k +// +build jwx_es256k + +package jwk + +import ( + "github.com/decred/dcrd/dcrec/secp256k1/v4" + "github.com/lestrrat-go/jwx/v3/jwa" + ourecdsa "github.com/lestrrat-go/jwx/v3/jwk/ecdsa" +) + +func init() { + ourecdsa.RegisterCurve(jwa.Secp256k1(), secp256k1.S256()) +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwk/fetch.go b/vendor/github.com/lestrrat-go/jwx/v3/jwk/fetch.go new file mode 100644 index 00000000000..910a2101d49 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwk/fetch.go @@ -0,0 +1,117 @@ +package jwk + +import ( + "context" + "fmt" + "io" + "net/http" +) + +// Fetcher is an interface that represents an object that fetches a JWKS. +// Currently this is only used in the `jws.WithVerifyAuto` option. +// +// Particularly, do not confuse this as the backend to `jwk.Fetch()` function. +// If you need to control how `jwk.Fetch()` implements HTTP requests look into +// providing a custom `http.Client` object via `jwk.WithHTTPClient` option +type Fetcher interface { + Fetch(context.Context, string, ...FetchOption) (Set, error) +} + +// FetchFunc describes a type of Fetcher that is represented as a function. +// +// You can use this to wrap functions (e.g. `jwk.Fetch“) as a Fetcher object. +type FetchFunc func(context.Context, string, ...FetchOption) (Set, error) + +func (ff FetchFunc) Fetch(ctx context.Context, u string, options ...FetchOption) (Set, error) { + return ff(ctx, u, options...) +} + +// CachedFetcher wraps `jwk.Cache` so that it can be used as a `jwk.Fetcher`. +// +// One notable diffence from a general use fetcher is that `jwk.CachedFetcher` +// can only be used with JWKS URLs that have been registered with the cache. +// Please read the documentation fo `(jwk.CachedFetcher).Fetch` for more details. +// +// This object is intended to be used with `jws.WithVerifyAuto` option, specifically +// for a scenario where there is a very small number of JWKS URLs that are trusted +// and used to verify JWS messages. It is NOT meant to be used as a general purpose +// caching fetcher object. +type CachedFetcher struct { + cache *Cache +} + +// Creates a new `jwk.CachedFetcher` object. +func NewCachedFetcher(cache *Cache) *CachedFetcher { + return &CachedFetcher{cache} +} + +// Fetch fetches a JWKS from the cache. If the JWKS URL has not been registered with +// the cache, an error is returned. +func (f *CachedFetcher) Fetch(ctx context.Context, u string, _ ...FetchOption) (Set, error) { + if !f.cache.IsRegistered(ctx, u) { + return nil, fmt.Errorf(`jwk.CachedFetcher: url %q has not been registered`, u) + } + return f.cache.Lookup(ctx, u) +} + +// Fetch fetches a JWK resource specified by a URL. The url must be +// pointing to a resource that is supported by `net/http`. +// +// This function is just a wrapper around `net/http` and `jwk.Parse`. +// There is nothing special here, so you are safe to use your own +// mechanism to fetch the JWKS. +// +// If you are using the same `jwk.Set` for long periods of time during +// the lifecycle of your program, and would like to periodically refresh the +// contents of the object with the data at the remote resource, +// consider using `jwk.Cache`, which automatically refreshes +// jwk.Set objects asynchronously. +func Fetch(ctx context.Context, u string, options ...FetchOption) (Set, error) { + var parseOptions []ParseOption + //nolint:revive // I want to keep the type of `wl` as `Whitelist` instead of `InsecureWhitelist` + var wl Whitelist = InsecureWhitelist{} + var client HTTPClient = http.DefaultClient + for _, option := range options { + if parseOpt, ok := option.(ParseOption); ok { + parseOptions = append(parseOptions, parseOpt) + continue + } + + switch option.Ident() { + case identHTTPClient{}: + if err := option.Value(&client); err != nil { + return nil, fmt.Errorf(`failed to retrieve HTTPClient option value: %w`, err) + } + case identFetchWhitelist{}: + if err := option.Value(&wl); err != nil { + return nil, fmt.Errorf(`failed to retrieve fetch whitelist option value: %w`, err) + } + } + } + + if !wl.IsAllowed(u) { + return nil, fmt.Errorf(`jwk.Fetch: url %q has been rejected by whitelist`, u) + } + + req, err := http.NewRequestWithContext(ctx, http.MethodGet, u, nil) + if err != nil { + return nil, fmt.Errorf(`jwk.Fetch: failed to create new request: %w`, err) + } + + res, err := client.Do(req) + if err != nil { + return nil, fmt.Errorf(`jwk.Fetch: request failed: %w`, err) + } + defer res.Body.Close() + + if res.StatusCode != http.StatusOK { + return nil, fmt.Errorf(`jwk.Fetch: request returned status %d, expected 200`, res.StatusCode) + } + + buf, err := io.ReadAll(res.Body) + if err != nil { + return nil, fmt.Errorf(`jwk.Fetch: failed to read response body for %q: %w`, u, err) + } + + return Parse(buf, parseOptions...) +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwk/filter.go b/vendor/github.com/lestrrat-go/jwx/v3/jwk/filter.go new file mode 100644 index 00000000000..e73b0757dac --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwk/filter.go @@ -0,0 +1,28 @@ +package jwk + +import ( + "github.com/lestrrat-go/jwx/v3/transform" +) + +// KeyFilter is an interface that allows users to filter JWK key fields. +// It provides two methods: Filter and Reject; Filter returns a new key with only +// the fields that match the filter criteria, while Reject returns a new key with +// only the fields that DO NOT match the filter. +// +// EXPERIMENTAL: This API is experimental and its interface and behavior is +// subject to change in future releases. This API is not subject to semver +// compatibility guarantees. +type KeyFilter interface { + Filter(key Key) (Key, error) + Reject(key Key) (Key, error) +} + +// NewFieldNameFilter creates a new FieldNameFilter with the specified field names. +// +// Note that because some JWK fields are associated with the type instead of +// stored as data, this filter will not be able to remove them. An example would +// be the `kty` field: it's associated with the underlying JWK key type, and will +// always be present even if you attempt to remove it. +func NewFieldNameFilter(names ...string) KeyFilter { + return transform.NewNameBasedFilter[Key](names...) +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwk/interface.go b/vendor/github.com/lestrrat-go/jwx/v3/jwk/interface.go new file mode 100644 index 00000000000..c157c2362cb --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwk/interface.go @@ -0,0 +1,143 @@ +package jwk + +import ( + "sync" + + "github.com/lestrrat-go/jwx/v3/internal/json" +) + +// AsymmetricKey describes a Key that represents a key in an asymmetric key pair, +// which in turn can be either a private or a public key. This interface +// allows those keys to be queried if they are one or the other. +type AsymmetricKey interface { + IsPrivate() bool +} + +// KeyUsageType is used to denote what this key should be used for +type KeyUsageType string + +const ( + // ForSignature is the value used in the headers to indicate that + // this key should be used for signatures + ForSignature KeyUsageType = "sig" + // ForEncryption is the value used in the headers to indicate that + // this key should be used for encrypting + ForEncryption KeyUsageType = "enc" +) + +type KeyOperation string +type KeyOperationList []KeyOperation + +const ( + KeyOpSign KeyOperation = "sign" // (compute digital signature or MAC) + KeyOpVerify KeyOperation = "verify" // (verify digital signature or MAC) + KeyOpEncrypt KeyOperation = "encrypt" // (encrypt content) + KeyOpDecrypt KeyOperation = "decrypt" // (decrypt content and validate decryption, if applicable) + KeyOpWrapKey KeyOperation = "wrapKey" // (encrypt key) + KeyOpUnwrapKey KeyOperation = "unwrapKey" // (decrypt key and validate decryption, if applicable) + KeyOpDeriveKey KeyOperation = "deriveKey" // (derive key) + KeyOpDeriveBits KeyOperation = "deriveBits" // (derive bits not to be used as a key) +) + +// Set represents JWKS object, a collection of jwk.Key objects. +// +// Sets can be safely converted to and from JSON using the standard +// `"encoding/json".Marshal` and `"encoding/json".Unmarshal`. However, +// if you do not know if the payload contains a single JWK or a JWK set, +// consider using `jwk.Parse()` to always get a `jwk.Set` out of it. +// +// Since v1.2.12, JWK sets with private parameters can be parsed as well. +// Such private parameters can be accessed via the `Field()` method. +// If a resource contains a single JWK instead of a JWK set, private parameters +// are stored in _both_ the resulting `jwk.Set` object and the `jwk.Key` object . +// +//nolint:interfacebloat +type Set interface { + // AddKey adds the specified key. If the key already exists in the set, + // an error is returned. + AddKey(Key) error + + // Clear resets the list of keys associated with this set, emptying the + // internal list of `jwk.Key`s, as well as clearing any other non-key + // fields + Clear() error + + // Get returns the key at index `idx`. If the index is out of range, + // then the second return value is false. + Key(int) (Key, bool) + + // Get returns the value of a private field in the key set. + // + // For the purposes of a key set, any field other than the "keys" field is + // considered to be a private field. In other words, you cannot use this + // method to directly access the list of keys in the set + Get(string, any) error + + // Set sets the value of a single field. + // + // This method, which takes an `any`, exists because + // these objects can contain extra _arbitrary_ fields that users can + // specify, and there is no way of knowing what type they could be. + Set(string, any) error + + // Remove removes the specified non-key field from the set. + // Keys may not be removed using this method. See RemoveKey for + // removing keys. + Remove(string) error + + // Index returns the index where the given key exists, -1 otherwise + Index(Key) int + + // Len returns the number of keys in the set + Len() int + + // LookupKeyID returns the first key matching the given key id. + // The second return value is false if there are no keys matching the key id. + // The set *may* contain multiple keys with the same key id. If you + // need all of them, use `Iterate()` + LookupKeyID(string) (Key, bool) + + // RemoveKey removes the key from the set. + // RemoveKey returns an error when the specified key does not exist + // in set. + RemoveKey(Key) error + + // Keys returns the list of keys present in the Set, except for `keys`. + // e.g. if you had `{"keys": ["a", "b"], "c": .., "d": ...}`, this method would + // return `["c", "d"]`. Note that the order of the keys is not guaranteed. + // + // TODO: name is confusing between this and Key() + Keys() []string + + // Clone create a new set with identical keys. Keys themselves are not cloned. + Clone() (Set, error) +} + +type set struct { + keys []Key + mu sync.RWMutex + dc DecodeCtx + privateParams map[string]any +} + +type PublicKeyer interface { + // PublicKey creates the corresponding PublicKey type for this object. + // All fields are copied onto the new public key, except for those that are not allowed. + // Returned value must not be the receiver itself. + PublicKey() (Key, error) +} + +type DecodeCtx interface { + json.DecodeCtx + IgnoreParseError() bool +} +type KeyWithDecodeCtx interface { + SetDecodeCtx(DecodeCtx) + DecodeCtx() DecodeCtx +} + +// Used internally: It's used to lock a key +type rlocker interface { + rlock() + runlock() +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwk/interface_gen.go b/vendor/github.com/lestrrat-go/jwx/v3/jwk/interface_gen.go new file mode 100644 index 00000000000..4f23d96cb0d --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwk/interface_gen.go @@ -0,0 +1,109 @@ +// Code generated by tools/cmd/genjwk/main.go. DO NOT EDIT. + +package jwk + +import ( + "crypto" + + "github.com/lestrrat-go/jwx/v3/cert" + "github.com/lestrrat-go/jwx/v3/jwa" +) + +const ( + KeyTypeKey = "kty" + KeyUsageKey = "use" + KeyOpsKey = "key_ops" + AlgorithmKey = "alg" + KeyIDKey = "kid" + X509URLKey = "x5u" + X509CertChainKey = "x5c" + X509CertThumbprintKey = "x5t" + X509CertThumbprintS256Key = "x5t#S256" +) + +// Key defines the minimal interface for each of the +// key types. Their use and implementation differ significantly +// between each key type, so you should use type assertions +// to perform more specific tasks with each key +type Key interface { + + // Has returns true if the specified field has a value, even if + // the value is empty-ish (e.g. 0, false, "") as long as it has been + // explicitly set. + Has(string) bool + + // Get is used to extract the value of any field, including non-standard fields, out of the key. + // + // The first argument is the name of the field. The second argument is a pointer + // to a variable that will receive the value of the field. The method returns + // an error if the field does not exist, or if the value cannot be assigned to + // the destination variable. Note that a field is considered to "exist" even if + // the value is empty-ish (e.g. 0, false, ""), as long as it is explicitly set. + Get(string, any) error + + // Set sets the value of a single field. Note that certain fields, + // notably "kty", cannot be altered, but will not return an error + // + // This method, which takes an `any`, exists because + // these objects can contain extra _arbitrary_ fields that users can + // specify, and there is no way of knowing what type they could be + Set(string, any) error + + // Remove removes the field associated with the specified key. + // There is no way to remove the `kty` (key type). You will ALWAYS be left with one field in a jwk.Key. + Remove(string) error + // Validate performs _minimal_ checks if the data stored in the key are valid. + // By minimal, we mean that it does not check if the key is valid for use in + // cryptographic operations. For example, it does not check if an RSA key's + // `e` field is a valid exponent, or if the `n` field is a valid modulus. + // Instead, it checks for things such as the _presence_ of some required fields, + // or if certain keys' values are of particular length. + // + // Note that depending on th underlying key type, use of this method requires + // that multiple fields in the key are properly populated. For example, an EC + // key's "x", "y" fields cannot be validated unless the "crv" field is populated first. + // + // Validate is never called by `UnmarshalJSON()` or `Set`. It must explicitly be + // called by the user + Validate() error + + // Thumbprint returns the JWK thumbprint using the indicated + // hashing algorithm, according to RFC 7638 + Thumbprint(crypto.Hash) ([]byte, error) + + // Keys returns a list of the keys contained in this jwk.Key. + Keys() []string + + // Clone creates a new instance of the same type + Clone() (Key, error) + + // PublicKey creates the corresponding PublicKey type for this object. + // All fields are copied onto the new public key, except for those that are not allowed. + // + // If the key is already a public key, it returns a new copy minus the disallowed fields as above. + PublicKey() (Key, error) + + // KeyType returns the `kty` of a JWK + KeyType() jwa.KeyType + // KeyUsage returns `use` of a JWK + KeyUsage() (string, bool) + // KeyOps returns `key_ops` of a JWK + KeyOps() (KeyOperationList, bool) + // Algorithm returns `alg` of a JWK + + // Algorithm returns the value of the `alg` field. + // + // This field may contain either `jwk.SignatureAlgorithm`, `jwk.KeyEncryptionAlgorithm`, or `jwk.ContentEncryptionAlgorithm`. + // This is why there exists a `jwa.KeyAlgorithm` type that encompasses both types. + Algorithm() (jwa.KeyAlgorithm, bool) + // KeyID returns `kid` of a JWK + KeyID() (string, bool) + // X509URL returns `x5u` of a JWK + X509URL() (string, bool) + // X509CertChain returns `x5c` of a JWK + X509CertChain() (*cert.Chain, bool) + // X509CertThumbprint returns `x5t` of a JWK + X509CertThumbprint() (string, bool) + // X509CertThumbprintS256 returns `x5t#S256` of a JWK + X509CertThumbprintS256() (string, bool) +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwk/io.go b/vendor/github.com/lestrrat-go/jwx/v3/jwk/io.go new file mode 100644 index 00000000000..29b30274ccb --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwk/io.go @@ -0,0 +1,42 @@ +// Code generated by tools/cmd/genreadfile/main.go. DO NOT EDIT. + +package jwk + +import ( + "fmt" + "io/fs" + "os" +) + +type sysFS struct{} + +func (sysFS) Open(path string) (fs.File, error) { + return os.Open(path) +} + +func ReadFile(path string, options ...ReadFileOption) (Set, error) { + var parseOptions []ParseOption + for _, option := range options { + if po, ok := option.(ParseOption); ok { + parseOptions = append(parseOptions, po) + } + } + + var srcFS fs.FS = sysFS{} + for _, option := range options { + switch option.Ident() { + case identFS{}: + if err := option.Value(&srcFS); err != nil { + return nil, fmt.Errorf("failed to set fs.FS: %w", err) + } + } + } + + f, err := srcFS.Open(path) + if err != nil { + return nil, err + } + + defer f.Close() + return ParseReader(f, parseOptions...) +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwk/jwk.go b/vendor/github.com/lestrrat-go/jwx/v3/jwk/jwk.go new file mode 100644 index 00000000000..785feaf94c1 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwk/jwk.go @@ -0,0 +1,709 @@ +//go:generate ../tools/cmd/genjwk.sh + +package jwk + +import ( + "bytes" + "crypto" + "crypto/ecdsa" + "crypto/x509" + "encoding/pem" + "errors" + "fmt" + "io" + "math/big" + "reflect" + + "github.com/lestrrat-go/jwx/v3/internal/base64" + "github.com/lestrrat-go/jwx/v3/internal/json" +) + +var registry = json.NewRegistry() + +func bigIntToBytes(n *big.Int) ([]byte, error) { + if n == nil { + return nil, fmt.Errorf(`invalid *big.Int value`) + } + return n.Bytes(), nil +} + +func init() { + if err := RegisterProbeField(reflect.StructField{ + Name: "Kty", + Type: reflect.TypeOf(""), + Tag: `json:"kty"`, + }); err != nil { + panic(fmt.Errorf("failed to register mandatory probe for 'kty' field: %w", err)) + } + if err := RegisterProbeField(reflect.StructField{ + Name: "D", + Type: reflect.TypeOf(json.RawMessage(nil)), + Tag: `json:"d,omitempty"`, + }); err != nil { + panic(fmt.Errorf("failed to register mandatory probe for 'kty' field: %w", err)) + } +} + +// Import creates a jwk.Key from the given key (RSA/ECDSA/symmetric keys). +// +// The constructor auto-detects the type of key to be instantiated +// based on the input type: +// +// - "crypto/rsa".PrivateKey and "crypto/rsa".PublicKey creates an RSA based key +// - "crypto/ecdsa".PrivateKey and "crypto/ecdsa".PublicKey creates an EC based key +// - "crypto/ed25519".PrivateKey and "crypto/ed25519".PublicKey creates an OKP based key +// - "crypto/ecdh".PrivateKey and "crypto/ecdh".PublicKey creates an OKP based key +// - []byte creates a symmetric key +func Import(raw any) (Key, error) { + if raw == nil { + return nil, importerr(`a non-nil key is required`) + } + + muKeyImporters.RLock() + conv, ok := keyImporters[reflect.TypeOf(raw)] + muKeyImporters.RUnlock() + if !ok { + return nil, importerr(`failed to convert %T to jwk.Key: no converters were able to convert`, raw) + } + + return conv.Import(raw) +} + +// PublicSetOf returns a new jwk.Set consisting of +// public keys of the keys contained in the set. +// +// This is useful when you are generating a set of private keys, and +// you want to generate the corresponding public versions for the +// users to verify with. +// +// Be aware that all fields will be copied onto the new public key. It is the caller's +// responsibility to remove any fields, if necessary. +func PublicSetOf(v Set) (Set, error) { + newSet := NewSet() + + n := v.Len() + for i := range n { + k, ok := v.Key(i) + if !ok { + return nil, fmt.Errorf(`key not found`) + } + pubKey, err := PublicKeyOf(k) + if err != nil { + return nil, fmt.Errorf(`failed to get public key of %T: %w`, k, err) + } + if err := newSet.AddKey(pubKey); err != nil { + return nil, fmt.Errorf(`failed to add key to public key set: %w`, err) + } + } + + return newSet, nil +} + +// PublicKeyOf returns the corresponding public version of the jwk.Key. +// If `v` is a SymmetricKey, then the same value is returned. +// If `v` is already a public key, the key itself is returned. +// +// If `v` is a private key type that has a `PublicKey()` method, be aware +// that all fields will be copied onto the new public key. It is the caller's +// responsibility to remove any fields, if necessary +// +// If `v` is a raw key, the key is first converted to a `jwk.Key` +func PublicKeyOf(v any) (Key, error) { + // This should catch all jwk.Key instances + if pk, ok := v.(PublicKeyer); ok { + return pk.PublicKey() + } + + jk, err := Import(v) + if err != nil { + return nil, fmt.Errorf(`jwk.PublicKeyOf: failed to convert key into JWK: %w`, err) + } + + return jk.PublicKey() +} + +// PublicRawKeyOf returns the corresponding public key of the given +// value `v` (e.g. given *rsa.PrivateKey, *rsa.PublicKey is returned) +// If `v` is already a public key, the key itself is returned. +// +// The returned value will always be a pointer to the public key, +// except when a []byte (e.g. symmetric key, ed25519 key) is passed to `v`. +// In this case, the same []byte value is returned. +// +// This function must go through converting the object once to a jwk.Key, +// then back to a raw key, so it's not exactly efficient. +func PublicRawKeyOf(v any) (any, error) { + pk, ok := v.(PublicKeyer) + if !ok { + k, err := Import(v) + if err != nil { + return nil, fmt.Errorf(`jwk.PublicRawKeyOf: failed to convert key to jwk.Key: %w`, err) + } + + pk, ok = k.(PublicKeyer) + if !ok { + return nil, fmt.Errorf(`jwk.PublicRawKeyOf: failed to convert key to jwk.PublicKeyer: %w`, err) + } + } + + pubk, err := pk.PublicKey() + if err != nil { + return nil, fmt.Errorf(`jwk.PublicRawKeyOf: failed to obtain public key from %T: %w`, v, err) + } + + var raw any + if err := Export(pubk, &raw); err != nil { + return nil, fmt.Errorf(`jwk.PublicRawKeyOf: failed to obtain raw key from %T: %w`, pubk, err) + } + return raw, nil +} + +// ParseRawKey is a combination of ParseKey and Raw. It parses a single JWK key, +// and assigns the "raw" key to the given parameter. The key must either be +// a pointer to an empty interface, or a pointer to the actual raw key type +// such as *rsa.PrivateKey, *ecdsa.PublicKey, *[]byte, etc. +func ParseRawKey(data []byte, rawkey any) error { + key, err := ParseKey(data) + if err != nil { + return fmt.Errorf(`failed to parse key: %w`, err) + } + + if err := Export(key, rawkey); err != nil { + return fmt.Errorf(`failed to assign to raw key variable: %w`, err) + } + + return nil +} + +type setDecodeCtx struct { + json.DecodeCtx + + ignoreParseError bool +} + +func (ctx *setDecodeCtx) IgnoreParseError() bool { + return ctx.ignoreParseError +} + +// ParseKey parses a single key JWK. Unlike `jwk.Parse` this method will +// report failure if you attempt to pass a JWK set. Only use this function +// when you know that the data is a single JWK. +// +// Given a WithPEM(true) option, this function assumes that the given input +// is PEM encoded ASN.1 DER format key. +// +// Note that a successful parsing of any type of key does NOT necessarily +// guarantee a valid key. For example, no checks against expiration dates +// are performed for certificate expiration, no checks against missing +// parameters are performed, etc. +func ParseKey(data []byte, options ...ParseOption) (Key, error) { + var parsePEM bool + var localReg *json.Registry + var pemDecoder PEMDecoder + for _, option := range options { + switch option.Ident() { + case identPEM{}: + if err := option.Value(&parsePEM); err != nil { + return nil, fmt.Errorf(`failed to retrieve PEM option value: %w`, err) + } + case identPEMDecoder{}: + if err := option.Value(&pemDecoder); err != nil { + return nil, fmt.Errorf(`failed to retrieve PEMDecoder option value: %w`, err) + } + case identLocalRegistry{}: + if err := option.Value(&localReg); err != nil { + return nil, fmt.Errorf(`failed to retrieve local registry option value: %w`, err) + } + case identTypedField{}: + var pair typedFieldPair // temporary var needed for typed field + if err := option.Value(&pair); err != nil { + return nil, fmt.Errorf(`failed to retrieve typed field option value: %w`, err) + } + if localReg == nil { + localReg = json.NewRegistry() + } + localReg.Register(pair.Name, pair.Value) + case identIgnoreParseError{}: + return nil, fmt.Errorf(`jwk.WithIgnoreParseError() cannot be used for ParseKey()`) + } + } + + if parsePEM { + var raw any + + // PEMDecoder should probably be deprecated, because of being a misnomer. + if pemDecoder != nil { + if err := decodeX509WithPEMDEcoder(&raw, data, pemDecoder); err != nil { + return nil, fmt.Errorf(`failed to decode PEM encoded key: %w`, err) + } + } else { + // This version takes into account the various X509 decoders that are + // pre-registered. + if err := decodeX509(&raw, data); err != nil { + return nil, fmt.Errorf(`failed to decode X.509 encoded key: %w`, err) + } + } + return Import(raw) + } + + probe, err := keyProbe.Probe(data) + if err != nil { + return nil, fmt.Errorf(`jwk.Parse: failed to probe data: %w`, err) + } + + unmarshaler := keyUnmarshaler{localReg: localReg} + + muKeyParser.RLock() + parsers := make([]KeyParser, len(keyParsers)) + copy(parsers, keyParsers) + muKeyParser.RUnlock() + + for i := len(parsers) - 1; i >= 0; i-- { + parser := parsers[i] + key, err := parser.ParseKey(probe, &unmarshaler, data) + if err == nil { + return key, nil + } + + if errors.Is(err, ContinueError()) { + continue + } + + return nil, err + } + return nil, fmt.Errorf(`jwk.Parse: no parser was able to parse the key`) +} + +// Parse parses JWK from the incoming []byte. +// +// For JWK sets, this is a convenience function. You could just as well +// call `json.Unmarshal` against an empty set created by `jwk.NewSet()` +// to parse a JSON buffer into a `jwk.Set`. +// +// This function exists because many times the user does not know before hand +// if a JWK(s) resource at a remote location contains a single JWK key or +// a JWK set, and `jwk.Parse()` can handle either case, returning a JWK Set +// even if the data only contains a single JWK key +// +// If you are looking for more information on how JWKs are parsed, or if +// you know for sure that you have a single key, please see the documentation +// for `jwk.ParseKey()`. +func Parse(src []byte, options ...ParseOption) (Set, error) { + var parsePEM bool + var parseX509 bool + var localReg *json.Registry + var ignoreParseError bool + var pemDecoder PEMDecoder + for _, option := range options { + switch option.Ident() { + case identPEM{}: + if err := option.Value(&parsePEM); err != nil { + return nil, parseerr(`failed to retrieve PEM option value: %w`, err) + } + case identX509{}: + if err := option.Value(&parseX509); err != nil { + return nil, parseerr(`failed to retrieve X509 option value: %w`, err) + } + case identPEMDecoder{}: + if err := option.Value(&pemDecoder); err != nil { + return nil, parseerr(`failed to retrieve PEMDecoder option value: %w`, err) + } + case identIgnoreParseError{}: + if err := option.Value(&ignoreParseError); err != nil { + return nil, parseerr(`failed to retrieve IgnoreParseError option value: %w`, err) + } + case identTypedField{}: + var pair typedFieldPair // temporary var needed for typed field + if err := option.Value(&pair); err != nil { + return nil, parseerr(`failed to retrieve typed field option value: %w`, err) + } + if localReg == nil { + localReg = json.NewRegistry() + } + localReg.Register(pair.Name, pair.Value) + } + } + + s := NewSet() + + if parsePEM || parseX509 { + if pemDecoder == nil { + pemDecoder = NewPEMDecoder() + } + src = bytes.TrimSpace(src) + for len(src) > 0 { + raw, rest, err := pemDecoder.Decode(src) + if err != nil { + return nil, parseerr(`failed to parse PEM encoded key: %w`, err) + } + key, err := Import(raw) + if err != nil { + return nil, parseerr(`failed to create jwk.Key from %T: %w`, raw, err) + } + if err := s.AddKey(key); err != nil { + return nil, parseerr(`failed to add jwk.Key to set: %w`, err) + } + src = bytes.TrimSpace(rest) + } + return s, nil + } + + if localReg != nil || ignoreParseError { + dcKs, ok := s.(KeyWithDecodeCtx) + if !ok { + return nil, parseerr(`typed field was requested, but the key set (%T) does not support DecodeCtx`, s) + } + dc := &setDecodeCtx{ + DecodeCtx: json.NewDecodeCtx(localReg), + ignoreParseError: ignoreParseError, + } + dcKs.SetDecodeCtx(dc) + defer func() { dcKs.SetDecodeCtx(nil) }() + } + + if err := json.Unmarshal(src, s); err != nil { + return nil, parseerr(`failed to unmarshal JWK set: %w`, err) + } + + return s, nil +} + +// ParseReader parses a JWK set from the incoming byte buffer. +func ParseReader(src io.Reader, options ...ParseOption) (Set, error) { + // meh, there's no way to tell if a stream has "ended" a single + // JWKs except when we encounter an EOF, so just... ReadAll + buf, err := io.ReadAll(src) + if err != nil { + return nil, rparseerr(`failed to read from io.Reader: %w`, err) + } + + set, err := Parse(buf, options...) + if err != nil { + return nil, rparseerr(`failed to parse reader: %w`, err) + } + return set, nil +} + +// ParseString parses a JWK set from the incoming string. +func ParseString(s string, options ...ParseOption) (Set, error) { + set, err := Parse([]byte(s), options...) + if err != nil { + return nil, sparseerr(`failed to parse string: %w`, err) + } + return set, nil +} + +// AssignKeyID is a convenience function to automatically assign the "kid" +// section of the key, if it already doesn't have one. It uses Key.Thumbprint +// method with crypto.SHA256 as the default hashing algorithm +func AssignKeyID(key Key, options ...AssignKeyIDOption) error { + if key.Has(KeyIDKey) { + return nil + } + + hash := crypto.SHA256 + for _, option := range options { + switch option.Ident() { + case identThumbprintHash{}: + if err := option.Value(&hash); err != nil { + return fmt.Errorf(`failed to retrieve thumbprint hash option value: %w`, err) + } + } + } + + h, err := key.Thumbprint(hash) + if err != nil { + return fmt.Errorf(`failed to generate thumbprint: %w`, err) + } + + if err := key.Set(KeyIDKey, base64.EncodeToString(h)); err != nil { + return fmt.Errorf(`failed to set "kid": %w`, err) + } + + return nil +} + +// NOTE: may need to remove this to allow pluggale key types +func cloneKey(src Key) (Key, error) { + var dst Key + switch src.(type) { + case RSAPrivateKey: + dst = newRSAPrivateKey() + case RSAPublicKey: + dst = newRSAPublicKey() + case ECDSAPrivateKey: + dst = newECDSAPrivateKey() + case ECDSAPublicKey: + dst = newECDSAPublicKey() + case OKPPrivateKey: + dst = newOKPPrivateKey() + case OKPPublicKey: + dst = newOKPPublicKey() + case SymmetricKey: + dst = newSymmetricKey() + default: + return nil, fmt.Errorf(`jwk.cloneKey: unknown key type %T`, src) + } + + for _, k := range src.Keys() { + // It's absolutely + var v any + if err := src.Get(k, &v); err != nil { + return nil, fmt.Errorf(`jwk.cloneKey: failed to get %q: %w`, k, err) + } + if err := dst.Set(k, v); err != nil { + return nil, fmt.Errorf(`jwk.cloneKey: failed to set %q: %w`, k, err) + } + } + return dst, nil +} + +// Pem serializes the given jwk.Key in PEM encoded ASN.1 DER format, +// using either PKCS8 for private keys and PKIX for public keys. +// If you need to encode using PKCS1 or SEC1, you must do it yourself. +// +// # Argument must be of type jwk.Key or jwk.Set +// +// Currently only EC (including Ed25519) and RSA keys (and jwk.Set +// comprised of these key types) are supported. +func Pem(v any) ([]byte, error) { + var set Set + switch v := v.(type) { + case Key: + set = NewSet() + if err := set.AddKey(v); err != nil { + return nil, fmt.Errorf(`failed to add key to set: %w`, err) + } + case Set: + set = v + default: + return nil, fmt.Errorf(`argument to Pem must be either jwk.Key or jwk.Set: %T`, v) + } + + var ret []byte + for i := range set.Len() { + key, _ := set.Key(i) + typ, buf, err := asnEncode(key) + if err != nil { + return nil, fmt.Errorf(`failed to encode content for key #%d: %w`, i, err) + } + + var block pem.Block + block.Type = typ + block.Bytes = buf + ret = append(ret, pem.EncodeToMemory(&block)...) + } + return ret, nil +} + +func asnEncode(key Key) (string, []byte, error) { + switch key := key.(type) { + case ECDSAPrivateKey: + var rawkey ecdsa.PrivateKey + if err := Export(key, &rawkey); err != nil { + return "", nil, fmt.Errorf(`failed to get raw key from jwk.Key: %w`, err) + } + buf, err := x509.MarshalECPrivateKey(&rawkey) + if err != nil { + return "", nil, fmt.Errorf(`failed to marshal PKCS8: %w`, err) + } + return pmECPrivateKey, buf, nil + case RSAPrivateKey, OKPPrivateKey: + var rawkey any + if err := Export(key, &rawkey); err != nil { + return "", nil, fmt.Errorf(`failed to get raw key from jwk.Key: %w`, err) + } + buf, err := x509.MarshalPKCS8PrivateKey(rawkey) + if err != nil { + return "", nil, fmt.Errorf(`failed to marshal PKCS8: %w`, err) + } + return pmPrivateKey, buf, nil + case RSAPublicKey, ECDSAPublicKey, OKPPublicKey: + var rawkey any + if err := Export(key, &rawkey); err != nil { + return "", nil, fmt.Errorf(`failed to get raw key from jwk.Key: %w`, err) + } + buf, err := x509.MarshalPKIXPublicKey(rawkey) + if err != nil { + return "", nil, fmt.Errorf(`failed to marshal PKIX: %w`, err) + } + return pmPublicKey, buf, nil + default: + return "", nil, fmt.Errorf(`unsupported key type %T`, key) + } +} + +type CustomDecoder = json.CustomDecoder +type CustomDecodeFunc = json.CustomDecodeFunc + +// RegisterCustomField allows users to specify that a private field +// be decoded as an instance of the specified type. This option has +// a global effect. +// +// For example, suppose you have a custom field `x-birthday`, which +// you want to represent as a string formatted in RFC3339 in JSON, +// but want it back as `time.Time`. +// +// In such case you would register a custom field as follows +// +// jwk.RegisterCustomField(`x-birthday`, time.Time{}) +// +// Then you can use a `time.Time` variable to extract the value +// of `x-birthday` field, instead of having to use `any` +// and later convert it to `time.Time` +// +// var bday time.Time +// _ = key.Get(`x-birthday`, &bday) +// +// If you need a more fine-tuned control over the decoding process, +// you can register a `CustomDecoder`. For example, below shows +// how to register a decoder that can parse RFC1123 format string: +// +// jwk.RegisterCustomField(`x-birthday`, jwk.CustomDecodeFunc(func(data []byte) (any, error) { +// return time.Parse(time.RFC1123, string(data)) +// })) +// +// Please note that use of custom fields can be problematic if you +// are using a library that does not implement MarshalJSON/UnmarshalJSON +// and you try to roundtrip from an object to JSON, and then back to an object. +// For example, in the above example, you can _parse_ time values formatted +// in the format specified in RFC822, but when you convert an object into +// JSON, it will be formatted in RFC3339, because that's what `time.Time` +// likes to do. To avoid this, it's always better to use a custom type +// that wraps your desired type (in this case `time.Time`) and implement +// MarshalJSON and UnmashalJSON. +func RegisterCustomField(name string, object any) { + registry.Register(name, object) +} + +// Equal compares two keys and returns true if they are equal. The comparison +// is solely done against the thumbprints of k1 and k2. It is possible for keys +// that have, for example, different key IDs, key usage, etc, to be considered equal. +func Equal(k1, k2 Key) bool { + h := crypto.SHA256 + tp1, err := k1.Thumbprint(h) + if err != nil { + return false // can't report error + } + tp2, err := k2.Thumbprint(h) + if err != nil { + return false // can't report error + } + + return bytes.Equal(tp1, tp2) +} + +// IsPrivateKey returns true if the supplied key is a private key of an +// asymmetric key pair. The argument `k` must implement the `AsymmetricKey` +// interface. +// +// An error is returned if the supplied key is not an `AsymmetricKey`. +func IsPrivateKey(k Key) (bool, error) { + asymmetric, ok := k.(AsymmetricKey) + if ok { + return asymmetric.IsPrivate(), nil + } + return false, fmt.Errorf("jwk.IsPrivateKey: %T is not an asymmetric key", k) +} + +type keyValidationError struct { + err error +} + +func (e *keyValidationError) Error() string { + return fmt.Sprintf(`key validation failed: %s`, e.err) +} + +func (e *keyValidationError) Unwrap() error { + return e.err +} + +func (e *keyValidationError) Is(target error) bool { + _, ok := target.(*keyValidationError) + return ok +} + +// NewKeyValidationError wraps the given error with an error that denotes +// `key.Validate()` has failed. This error type should ONLY be used as +// return value from the `Validate()` method. +func NewKeyValidationError(err error) error { + return &keyValidationError{err: err} +} + +func IsKeyValidationError(err error) bool { + var kve keyValidationError + return errors.Is(err, &kve) +} + +// Configure is used to configure global behavior of the jwk package. +func Configure(options ...GlobalOption) { + var strictKeyUsagePtr *bool + for _, option := range options { + switch option.Ident() { + case identStrictKeyUsage{}: + var v bool + if err := option.Value(&v); err != nil { + continue + } + strictKeyUsagePtr = &v + } + } + + if strictKeyUsagePtr != nil { + strictKeyUsage.Store(*strictKeyUsagePtr) + } +} + +// These are used when validating keys. +type keyWithD interface { + D() ([]byte, bool) +} + +var _ keyWithD = &okpPrivateKey{} + +func extractEmbeddedKey(keyif Key, concretTypes []reflect.Type) (Key, error) { + rv := reflect.ValueOf(keyif) + + // If the value can be converted to one of the concrete types, then we're done + for _, t := range concretTypes { + if rv.Type().ConvertibleTo(t) { + return keyif, nil + } + } + + // When a struct implements the Key interface via embedding, you unfortunately + // cannot use a type switch to determine the concrete type, because + if rv.Kind() == reflect.Ptr { + if rv.IsNil() { + return nil, fmt.Errorf(`invalid key value (0): %w`, ContinueError()) + } + rv = rv.Elem() + } + + if rv.Kind() != reflect.Struct { + return nil, fmt.Errorf(`invalid key value type %T (1): %w`, keyif, ContinueError()) + } + if rv.NumField() == 0 { + return nil, fmt.Errorf(`invalid key value type %T (2): %w`, keyif, ContinueError()) + } + // Iterate through the fields of the struct to find the first field that + // implements the Key interface + rt := rv.Type() + for i := range rv.NumField() { + field := rv.Field(i) + ft := rt.Field(i) + if !ft.Anonymous { + // We can only salvage this object if the object implements jwk.Key + // via embedding, so we skip fields that are not anonymous + continue + } + + if field.CanInterface() { + if k, ok := field.Interface().(Key); ok { + return extractEmbeddedKey(k, concretTypes) + } + } + } + + return nil, fmt.Errorf(`invalid key value type %T (3): %w`, keyif, ContinueError()) +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwk/jwkbb/BUILD.bazel b/vendor/github.com/lestrrat-go/jwx/v3/jwk/jwkbb/BUILD.bazel new file mode 100644 index 00000000000..68a4ccdc19a --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwk/jwkbb/BUILD.bazel @@ -0,0 +1,17 @@ +load("@rules_go//go:def.bzl", "go_library") + +go_library( + name = "jwkbb", + srcs = ["x509.go"], + importpath = "github.com/lestrrat-go/jwx/v3/jwk/jwkbb", + visibility = ["//visibility:public"], + deps = [ + "@com_github_lestrrat_go_blackmagic//:blackmagic", + ], +) + +alias( + name = "go_default_library", + actual = ":jwkbb", + visibility = ["//visibility:public"], +) \ No newline at end of file diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwk/jwkbb/x509.go b/vendor/github.com/lestrrat-go/jwx/v3/jwk/jwkbb/x509.go new file mode 100644 index 00000000000..3c827cfa6ff --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwk/jwkbb/x509.go @@ -0,0 +1,111 @@ +package jwkbb + +import ( + "crypto/ecdsa" + "crypto/ed25519" + "crypto/rsa" + "crypto/x509" + "encoding/pem" + "fmt" + + "github.com/lestrrat-go/blackmagic" +) + +const ( + PrivateKeyBlockType = `PRIVATE KEY` + PublicKeyBlockType = `PUBLIC KEY` + ECPrivateKeyBlockType = `EC PRIVATE KEY` + RSAPublicKeyBlockType = `RSA PUBLIC KEY` + RSAPrivateKeyBlockType = `RSA PRIVATE KEY` + CertificateBlockType = `CERTIFICATE` +) + +// EncodeX509 encodes the given value into ASN.1 DER format, and returns +// the encoded bytes. The value must be one of the following types: +// *rsa.PrivateKey, *ecdsa.PrivateKey, ed25519.PrivateKey, +// *rsa.PublicKey, *ecdsa.PublicKey, ed25519.PublicKey. +// +// Users can pass a pre-allocated byte slice (but make sure its length is +// changed so that the encoded buffer is appended to the correct location) +// as `dst` to avoid allocations. +func EncodeX509(dst []byte, v any) ([]byte, error) { + var block pem.Block + // Try to convert it into a certificate + switch v := v.(type) { + case *rsa.PrivateKey: + block.Type = RSAPrivateKeyBlockType + block.Bytes = x509.MarshalPKCS1PrivateKey(v) + case *ecdsa.PrivateKey: + marshaled, err := x509.MarshalECPrivateKey(v) + if err != nil { + return nil, err + } + block.Type = ECPrivateKeyBlockType + block.Bytes = marshaled + case ed25519.PrivateKey: + marshaled, err := x509.MarshalPKCS8PrivateKey(v) + if err != nil { + return nil, err + } + block.Type = PrivateKeyBlockType + block.Bytes = marshaled + case *rsa.PublicKey, *ecdsa.PublicKey, ed25519.PublicKey: + marshaled, err := x509.MarshalPKIXPublicKey(v) + if err != nil { + return nil, err + } + block.Type = PublicKeyBlockType + block.Bytes = marshaled + default: + return nil, fmt.Errorf(`unsupported type %T for ASN.1 DER encoding`, v) + } + + encoded := pem.EncodeToMemory(&block) + dst = append(dst, encoded...) + return dst, nil +} + +func DecodeX509(dst any, block *pem.Block) error { + switch block.Type { + // Handle the semi-obvious cases + case RSAPrivateKeyBlockType: + key, err := x509.ParsePKCS1PrivateKey(block.Bytes) + if err != nil { + return fmt.Errorf(`failed to parse PKCS1 private key: %w`, err) + } + return blackmagic.AssignIfCompatible(dst, key) + case RSAPublicKeyBlockType: + key, err := x509.ParsePKCS1PublicKey(block.Bytes) + if err != nil { + return fmt.Errorf(`failed to parse PKCS1 public key: %w`, err) + } + return blackmagic.AssignIfCompatible(dst, key) + case ECPrivateKeyBlockType: + key, err := x509.ParseECPrivateKey(block.Bytes) + if err != nil { + return fmt.Errorf(`failed to parse EC private key: %w`, err) + } + return blackmagic.AssignIfCompatible(dst, key) + case PublicKeyBlockType: + // XXX *could* return dsa.PublicKey + key, err := x509.ParsePKIXPublicKey(block.Bytes) + if err != nil { + return fmt.Errorf(`failed to parse PKIX public key: %w`, err) + } + return blackmagic.AssignIfCompatible(dst, key) + case PrivateKeyBlockType: + key, err := x509.ParsePKCS8PrivateKey(block.Bytes) + if err != nil { + return fmt.Errorf(`failed to parse PKCS8 private key: %w`, err) + } + return blackmagic.AssignIfCompatible(dst, key) + case CertificateBlockType: + cert, err := x509.ParseCertificate(block.Bytes) + if err != nil { + return fmt.Errorf(`failed to parse certificate: %w`, err) + } + return blackmagic.AssignIfCompatible(dst, cert.PublicKey) + default: + return fmt.Errorf(`invalid PEM block type %s`, block.Type) + } +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwk/key_ops.go b/vendor/github.com/lestrrat-go/jwx/v3/jwk/key_ops.go new file mode 100644 index 00000000000..b8c229b3afc --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwk/key_ops.go @@ -0,0 +1,58 @@ +package jwk + +import "fmt" + +func (ops *KeyOperationList) Get() KeyOperationList { + if ops == nil { + return nil + } + return *ops +} + +func (ops *KeyOperationList) Accept(v any) error { + switch x := v.(type) { + case string: + return ops.Accept([]string{x}) + case []any: + l := make([]string, len(x)) + for i, e := range x { + if es, ok := e.(string); ok { + l[i] = es + } else { + return fmt.Errorf(`invalid list element type: expected string, got %T`, v) + } + } + return ops.Accept(l) + case []string: + list := make(KeyOperationList, len(x)) + for i, e := range x { + switch e := KeyOperation(e); e { + case KeyOpSign, KeyOpVerify, KeyOpEncrypt, KeyOpDecrypt, KeyOpWrapKey, KeyOpUnwrapKey, KeyOpDeriveKey, KeyOpDeriveBits: + list[i] = e + default: + return fmt.Errorf(`invalid keyoperation %v`, e) + } + } + + *ops = list + return nil + case []KeyOperation: + list := make(KeyOperationList, len(x)) + for i, e := range x { + switch e { + case KeyOpSign, KeyOpVerify, KeyOpEncrypt, KeyOpDecrypt, KeyOpWrapKey, KeyOpUnwrapKey, KeyOpDeriveKey, KeyOpDeriveBits: + list[i] = e + default: + return fmt.Errorf(`invalid keyoperation %v`, e) + } + } + + *ops = list + return nil + case KeyOperationList: + *ops = x + return nil + default: + return fmt.Errorf(`invalid value %T`, v) + } +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwk/okp.go b/vendor/github.com/lestrrat-go/jwx/v3/jwk/okp.go new file mode 100644 index 00000000000..773734b660d --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwk/okp.go @@ -0,0 +1,321 @@ +package jwk + +import ( + "bytes" + "crypto" + "crypto/ecdh" + "crypto/ed25519" + "fmt" + "reflect" + + "github.com/lestrrat-go/blackmagic" + "github.com/lestrrat-go/jwx/v3/internal/base64" + "github.com/lestrrat-go/jwx/v3/jwa" +) + +func init() { + RegisterKeyExporter(jwa.OKP(), KeyExportFunc(okpJWKToRaw)) +} + +// Mental note: +// +// Curve25519 refers to a particular curve, and is represented in its Montgomery form. +// +// Ed25519 refers to the biratinally equivalent curve of Curve25519, except it's in Edwards form. +// Ed25519 is the name of the curve and the also the signature scheme using that curve. +// The full name of the scheme is Edwards Curve Digital Signature Algorithm, and thus it is +// also referred to as EdDSA. +// +// X25519 refers to the Diffie-Hellman key exchange protocol that uses Cruve25519. +// Because this is an elliptic curve based Diffie Hellman protocol, it is also referred to +// as ECDH. +// +// OKP keys are used to represent private/public pairs of thse elliptic curve +// keys. But note that the name just means Octet Key Pair. + +func (k *okpPublicKey) Import(rawKeyIf any) error { + k.mu.Lock() + defer k.mu.Unlock() + + var crv jwa.EllipticCurveAlgorithm + switch rawKey := rawKeyIf.(type) { + case ed25519.PublicKey: + k.x = rawKey + crv = jwa.Ed25519() + k.crv = &crv + case *ecdh.PublicKey: + k.x = rawKey.Bytes() + crv = jwa.X25519() + k.crv = &crv + default: + return fmt.Errorf(`unknown key type %T`, rawKeyIf) + } + + return nil +} + +func (k *okpPrivateKey) Import(rawKeyIf any) error { + k.mu.Lock() + defer k.mu.Unlock() + + var crv jwa.EllipticCurveAlgorithm + switch rawKey := rawKeyIf.(type) { + case ed25519.PrivateKey: + k.d = rawKey.Seed() + k.x = rawKey.Public().(ed25519.PublicKey) //nolint:forcetypeassert + crv = jwa.Ed25519() + k.crv = &crv + case *ecdh.PrivateKey: + // k.d = rawKey.Seed() + k.d = rawKey.Bytes() + k.x = rawKey.PublicKey().Bytes() + crv = jwa.X25519() + k.crv = &crv + default: + return fmt.Errorf(`unknown key type %T`, rawKeyIf) + } + + return nil +} + +func buildOKPPublicKey(alg jwa.EllipticCurveAlgorithm, xbuf []byte) (any, error) { + switch alg { + case jwa.Ed25519(): + return ed25519.PublicKey(xbuf), nil + case jwa.X25519(): + ret, err := ecdh.X25519().NewPublicKey(xbuf) + if err != nil { + return nil, fmt.Errorf(`failed to parse x25519 public key %x (size %d): %w`, xbuf, len(xbuf), err) + } + return ret, nil + default: + return nil, fmt.Errorf(`invalid curve algorithm %s`, alg) + } +} + +// Raw returns the EC-DSA public key represented by this JWK +func (k *okpPublicKey) Raw(v any) error { + k.mu.RLock() + defer k.mu.RUnlock() + + crv, ok := k.Crv() + if !ok { + return fmt.Errorf(`missing "crv" field`) + } + + pubk, err := buildOKPPublicKey(crv, k.x) + if err != nil { + return fmt.Errorf(`jwk.OKPPublicKey: failed to build public key: %w`, err) + } + + if err := blackmagic.AssignIfCompatible(v, pubk); err != nil { + return fmt.Errorf(`jwk.OKPPublicKey: failed to assign to destination variable: %w`, err) + } + return nil +} + +func buildOKPPrivateKey(alg jwa.EllipticCurveAlgorithm, xbuf []byte, dbuf []byte) (any, error) { + if len(dbuf) == 0 { + return nil, fmt.Errorf(`cannot use empty seed`) + } + switch alg { + case jwa.Ed25519(): + if len(dbuf) != ed25519.SeedSize { + return nil, fmt.Errorf(`ed25519: wrong private key size`) + } + ret := ed25519.NewKeyFromSeed(dbuf) + //nolint:forcetypeassert + if !bytes.Equal(xbuf, ret.Public().(ed25519.PublicKey)) { + return nil, fmt.Errorf(`ed25519: invalid x value given d value`) + } + return ret, nil + case jwa.X25519(): + ret, err := ecdh.X25519().NewPrivateKey(dbuf) + if err != nil { + return nil, fmt.Errorf(`x25519: unable to construct x25519 private key from seed: %w`, err) + } + return ret, nil + default: + return nil, fmt.Errorf(`invalid curve algorithm %s`, alg) + } +} + +var okpConvertibleKeys = []reflect.Type{ + reflect.TypeOf((*OKPPrivateKey)(nil)).Elem(), + reflect.TypeOf((*OKPPublicKey)(nil)).Elem(), +} + +// This is half baked. I think it will blow up if we used ecdh.* keys and/or x25519 keys +func okpJWKToRaw(key Key, _ any /* this is unused because this is half baked */) (any, error) { + extracted, err := extractEmbeddedKey(key, okpConvertibleKeys) + if err != nil { + return nil, fmt.Errorf(`jwk.OKP: failed to extract embedded key: %w`, err) + } + + switch key := extracted.(type) { + case OKPPrivateKey: + locker, ok := key.(rlocker) + if ok { + locker.rlock() + defer locker.runlock() + } + + crv, ok := key.Crv() + if !ok { + return nil, fmt.Errorf(`missing "crv" field`) + } + + x, ok := key.X() + if !ok { + return nil, fmt.Errorf(`missing "x" field`) + } + + d, ok := key.D() + if !ok { + return nil, fmt.Errorf(`missing "d" field`) + } + + privk, err := buildOKPPrivateKey(crv, x, d) + if err != nil { + return nil, fmt.Errorf(`jwk.OKPPrivateKey: failed to build private key: %w`, err) + } + return privk, nil + case OKPPublicKey: + locker, ok := key.(rlocker) + if ok { + locker.rlock() + defer locker.runlock() + } + + crv, ok := key.Crv() + if !ok { + return nil, fmt.Errorf(`missing "crv" field`) + } + + x, ok := key.X() + if !ok { + return nil, fmt.Errorf(`missing "x" field`) + } + pubk, err := buildOKPPublicKey(crv, x) + if err != nil { + return nil, fmt.Errorf(`jwk.OKPPublicKey: failed to build public key: %w`, err) + } + return pubk, nil + default: + return nil, ContinueError() + } +} + +func makeOKPPublicKey(src Key) (Key, error) { + newKey := newOKPPublicKey() + + // Iterate and copy everything except for the bits that should not be in the public key + for _, k := range src.Keys() { + switch k { + case OKPDKey: + continue + default: + var v any + if err := src.Get(k, &v); err != nil { + return nil, fmt.Errorf(`failed to get field %q: %w`, k, err) + } + + if err := newKey.Set(k, v); err != nil { + return nil, fmt.Errorf(`failed to set field %q: %w`, k, err) + } + } + } + + return newKey, nil +} + +func (k *okpPrivateKey) PublicKey() (Key, error) { + return makeOKPPublicKey(k) +} + +func (k *okpPublicKey) PublicKey() (Key, error) { + return makeOKPPublicKey(k) +} + +func okpThumbprint(hash crypto.Hash, crv, x string) []byte { + h := hash.New() + fmt.Fprint(h, `{"crv":"`) + fmt.Fprint(h, crv) + fmt.Fprint(h, `","kty":"OKP","x":"`) + fmt.Fprint(h, x) + fmt.Fprint(h, `"}`) + return h.Sum(nil) +} + +// Thumbprint returns the JWK thumbprint using the indicated +// hashing algorithm, according to RFC 7638 / 8037 +func (k okpPublicKey) Thumbprint(hash crypto.Hash) ([]byte, error) { + k.mu.RLock() + defer k.mu.RUnlock() + + crv, ok := k.Crv() + if !ok { + return nil, fmt.Errorf(`missing "crv" field`) + } + return okpThumbprint( + hash, + crv.String(), + base64.EncodeToString(k.x), + ), nil +} + +// Thumbprint returns the JWK thumbprint using the indicated +// hashing algorithm, according to RFC 7638 / 8037 +func (k okpPrivateKey) Thumbprint(hash crypto.Hash) ([]byte, error) { + k.mu.RLock() + defer k.mu.RUnlock() + + crv, ok := k.Crv() + if !ok { + return nil, fmt.Errorf(`missing "crv" field`) + } + + return okpThumbprint( + hash, + crv.String(), + base64.EncodeToString(k.x), + ), nil +} + +func validateOKPKey(key interface { + Crv() (jwa.EllipticCurveAlgorithm, bool) + X() ([]byte, bool) +}) error { + if v, ok := key.Crv(); !ok || v == jwa.InvalidEllipticCurve() { + return fmt.Errorf(`invalid curve algorithm`) + } + + if v, ok := key.X(); !ok || len(v) == 0 { + return fmt.Errorf(`missing "x" field`) + } + + if priv, ok := key.(keyWithD); ok { + if d, ok := priv.D(); !ok || len(d) == 0 { + return fmt.Errorf(`missing "d" field`) + } + } + return nil +} + +func (k *okpPublicKey) Validate() error { + k.mu.RLock() + defer k.mu.RUnlock() + if err := validateOKPKey(k); err != nil { + return NewKeyValidationError(fmt.Errorf(`jwk.OKPPublicKey: %w`, err)) + } + return nil +} + +func (k *okpPrivateKey) Validate() error { + k.mu.RLock() + defer k.mu.RUnlock() + if err := validateOKPKey(k); err != nil { + return NewKeyValidationError(fmt.Errorf(`jwk.OKPPrivateKey: %w`, err)) + } + return nil +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwk/okp_gen.go b/vendor/github.com/lestrrat-go/jwx/v3/jwk/okp_gen.go new file mode 100644 index 00000000000..0bde9861473 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwk/okp_gen.go @@ -0,0 +1,1347 @@ +// Code generated by tools/cmd/genjwk/main.go. DO NOT EDIT. + +package jwk + +import ( + "bytes" + "fmt" + "sort" + "sync" + + "github.com/lestrrat-go/blackmagic" + "github.com/lestrrat-go/jwx/v3/cert" + "github.com/lestrrat-go/jwx/v3/internal/base64" + "github.com/lestrrat-go/jwx/v3/internal/json" + "github.com/lestrrat-go/jwx/v3/internal/pool" + "github.com/lestrrat-go/jwx/v3/internal/tokens" + "github.com/lestrrat-go/jwx/v3/jwa" +) + +const ( + OKPCrvKey = "crv" + OKPDKey = "d" + OKPXKey = "x" +) + +type OKPPublicKey interface { + Key + Crv() (jwa.EllipticCurveAlgorithm, bool) + X() ([]byte, bool) +} + +type okpPublicKey struct { + algorithm *jwa.KeyAlgorithm // https://tools.ietf.org/html/rfc7517#section-4.4 + crv *jwa.EllipticCurveAlgorithm + keyID *string // https://tools.ietf.org/html/rfc7515#section-4.1.4 + keyOps *KeyOperationList // https://tools.ietf.org/html/rfc7517#section-4.3 + keyUsage *string // https://tools.ietf.org/html/rfc7517#section-4.2 + x []byte + x509CertChain *cert.Chain // https://tools.ietf.org/html/rfc7515#section-4.1.6 + x509CertThumbprint *string // https://tools.ietf.org/html/rfc7515#section-4.1.7 + x509CertThumbprintS256 *string // https://tools.ietf.org/html/rfc7515#section-4.1.8 + x509URL *string // https://tools.ietf.org/html/rfc7515#section-4.1.5 + privateParams map[string]any + mu *sync.RWMutex + dc json.DecodeCtx +} + +var _ OKPPublicKey = &okpPublicKey{} +var _ Key = &okpPublicKey{} + +func newOKPPublicKey() *okpPublicKey { + return &okpPublicKey{ + mu: &sync.RWMutex{}, + privateParams: make(map[string]any), + } +} + +func (h okpPublicKey) KeyType() jwa.KeyType { + return jwa.OKP() +} + +func (h okpPublicKey) rlock() { + h.mu.RLock() +} + +func (h okpPublicKey) runlock() { + h.mu.RUnlock() +} + +func (h okpPublicKey) IsPrivate() bool { + return false +} + +func (h *okpPublicKey) Algorithm() (jwa.KeyAlgorithm, bool) { + if h.algorithm != nil { + return *(h.algorithm), true + } + return nil, false +} + +func (h *okpPublicKey) Crv() (jwa.EllipticCurveAlgorithm, bool) { + if h.crv != nil { + return *(h.crv), true + } + return jwa.InvalidEllipticCurve(), false +} + +func (h *okpPublicKey) KeyID() (string, bool) { + if h.keyID != nil { + return *(h.keyID), true + } + return "", false +} + +func (h *okpPublicKey) KeyOps() (KeyOperationList, bool) { + if h.keyOps != nil { + return *(h.keyOps), true + } + return nil, false +} + +func (h *okpPublicKey) KeyUsage() (string, bool) { + if h.keyUsage != nil { + return *(h.keyUsage), true + } + return "", false +} + +func (h *okpPublicKey) X() ([]byte, bool) { + if h.x != nil { + return h.x, true + } + return nil, false +} + +func (h *okpPublicKey) X509CertChain() (*cert.Chain, bool) { + return h.x509CertChain, true +} + +func (h *okpPublicKey) X509CertThumbprint() (string, bool) { + if h.x509CertThumbprint != nil { + return *(h.x509CertThumbprint), true + } + return "", false +} + +func (h *okpPublicKey) X509CertThumbprintS256() (string, bool) { + if h.x509CertThumbprintS256 != nil { + return *(h.x509CertThumbprintS256), true + } + return "", false +} + +func (h *okpPublicKey) X509URL() (string, bool) { + if h.x509URL != nil { + return *(h.x509URL), true + } + return "", false +} + +func (h *okpPublicKey) Has(name string) bool { + h.mu.RLock() + defer h.mu.RUnlock() + switch name { + case KeyTypeKey: + return true + case AlgorithmKey: + return h.algorithm != nil + case OKPCrvKey: + return h.crv != nil + case KeyIDKey: + return h.keyID != nil + case KeyOpsKey: + return h.keyOps != nil + case KeyUsageKey: + return h.keyUsage != nil + case OKPXKey: + return h.x != nil + case X509CertChainKey: + return h.x509CertChain != nil + case X509CertThumbprintKey: + return h.x509CertThumbprint != nil + case X509CertThumbprintS256Key: + return h.x509CertThumbprintS256 != nil + case X509URLKey: + return h.x509URL != nil + default: + _, ok := h.privateParams[name] + return ok + } +} + +func (h *okpPublicKey) Get(name string, dst any) error { + h.mu.RLock() + defer h.mu.RUnlock() + switch name { + case KeyTypeKey: + if err := blackmagic.AssignIfCompatible(dst, h.KeyType()); err != nil { + return fmt.Errorf(`okpPublicKey.Get: failed to assign value for field %q to destination object: %w`, name, err) + } + case AlgorithmKey: + if h.algorithm == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.algorithm)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case OKPCrvKey: + if h.crv == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.crv)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case KeyIDKey: + if h.keyID == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.keyID)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case KeyOpsKey: + if h.keyOps == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.keyOps)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case KeyUsageKey: + if h.keyUsage == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.keyUsage)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case OKPXKey: + if h.x == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, h.x); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case X509CertChainKey: + if h.x509CertChain == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, h.x509CertChain); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case X509CertThumbprintKey: + if h.x509CertThumbprint == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.x509CertThumbprint)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case X509CertThumbprintS256Key: + if h.x509CertThumbprintS256 == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.x509CertThumbprintS256)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case X509URLKey: + if h.x509URL == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.x509URL)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + default: + v, ok := h.privateParams[name] + if !ok { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, v); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + } + return nil +} + +func (h *okpPublicKey) Set(name string, value any) error { + h.mu.Lock() + defer h.mu.Unlock() + return h.setNoLock(name, value) +} + +func (h *okpPublicKey) setNoLock(name string, value any) error { + switch name { + case "kty": + return nil + case AlgorithmKey: + switch v := value.(type) { + case string, jwa.SignatureAlgorithm, jwa.KeyEncryptionAlgorithm, jwa.ContentEncryptionAlgorithm: + tmp, err := jwa.KeyAlgorithmFrom(v) + if err != nil { + return fmt.Errorf(`invalid algorithm for %q key: %w`, AlgorithmKey, err) + } + h.algorithm = &tmp + default: + return fmt.Errorf(`invalid type for %q key: %T`, AlgorithmKey, value) + } + return nil + case OKPCrvKey: + if v, ok := value.(jwa.EllipticCurveAlgorithm); ok { + h.crv = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, OKPCrvKey, value) + case KeyIDKey: + if v, ok := value.(string); ok { + h.keyID = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, KeyIDKey, value) + case KeyOpsKey: + var acceptor KeyOperationList + if err := acceptor.Accept(value); err != nil { + return fmt.Errorf(`invalid value for %s key: %w`, KeyOpsKey, err) + } + h.keyOps = &acceptor + return nil + case KeyUsageKey: + switch v := value.(type) { + case KeyUsageType: + switch v { + case ForSignature, ForEncryption: + tmp := v.String() + h.keyUsage = &tmp + default: + return fmt.Errorf(`invalid key usage type %s`, v) + } + case string: + h.keyUsage = &v + default: + return fmt.Errorf(`invalid key usage type %s`, v) + } + case OKPXKey: + if v, ok := value.([]byte); ok { + h.x = v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, OKPXKey, value) + case X509CertChainKey: + if v, ok := value.(*cert.Chain); ok { + h.x509CertChain = v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, X509CertChainKey, value) + case X509CertThumbprintKey: + if v, ok := value.(string); ok { + h.x509CertThumbprint = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, X509CertThumbprintKey, value) + case X509CertThumbprintS256Key: + if v, ok := value.(string); ok { + h.x509CertThumbprintS256 = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, X509CertThumbprintS256Key, value) + case X509URLKey: + if v, ok := value.(string); ok { + h.x509URL = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, X509URLKey, value) + default: + if h.privateParams == nil { + h.privateParams = map[string]any{} + } + h.privateParams[name] = value + } + return nil +} + +func (k *okpPublicKey) Remove(key string) error { + k.mu.Lock() + defer k.mu.Unlock() + switch key { + case AlgorithmKey: + k.algorithm = nil + case OKPCrvKey: + k.crv = nil + case KeyIDKey: + k.keyID = nil + case KeyOpsKey: + k.keyOps = nil + case KeyUsageKey: + k.keyUsage = nil + case OKPXKey: + k.x = nil + case X509CertChainKey: + k.x509CertChain = nil + case X509CertThumbprintKey: + k.x509CertThumbprint = nil + case X509CertThumbprintS256Key: + k.x509CertThumbprintS256 = nil + case X509URLKey: + k.x509URL = nil + default: + delete(k.privateParams, key) + } + return nil +} + +func (k *okpPublicKey) Clone() (Key, error) { + key, err := cloneKey(k) + if err != nil { + return nil, fmt.Errorf(`okpPublicKey.Clone: %w`, err) + } + return key, nil +} + +func (k *okpPublicKey) DecodeCtx() json.DecodeCtx { + k.mu.RLock() + defer k.mu.RUnlock() + return k.dc +} + +func (k *okpPublicKey) SetDecodeCtx(dc json.DecodeCtx) { + k.mu.Lock() + defer k.mu.Unlock() + k.dc = dc +} + +func (h *okpPublicKey) UnmarshalJSON(buf []byte) error { + h.mu.Lock() + defer h.mu.Unlock() + h.algorithm = nil + h.crv = nil + h.keyID = nil + h.keyOps = nil + h.keyUsage = nil + h.x = nil + h.x509CertChain = nil + h.x509CertThumbprint = nil + h.x509CertThumbprintS256 = nil + h.x509URL = nil + dec := json.NewDecoder(bytes.NewReader(buf)) +LOOP: + for { + tok, err := dec.Token() + if err != nil { + return fmt.Errorf(`error reading token: %w`, err) + } + switch tok := tok.(type) { + case json.Delim: + // Assuming we're doing everything correctly, we should ONLY + // get either tokens.OpenCurlyBracket or tokens.CloseCurlyBracket here. + if tok == tokens.CloseCurlyBracket { // End of object + break LOOP + } else if tok != tokens.OpenCurlyBracket { + return fmt.Errorf(`expected '%c' but got '%c'`, tokens.OpenCurlyBracket, tok) + } + case string: // Objects can only have string keys + switch tok { + case KeyTypeKey: + val, err := json.ReadNextStringToken(dec) + if err != nil { + return fmt.Errorf(`error reading token: %w`, err) + } + if val != jwa.OKP().String() { + return fmt.Errorf(`invalid kty value for RSAPublicKey (%s)`, val) + } + case AlgorithmKey: + var s string + if err := dec.Decode(&s); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, AlgorithmKey, err) + } + alg, err := jwa.KeyAlgorithmFrom(s) + if err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, AlgorithmKey, err) + } + h.algorithm = &alg + case OKPCrvKey: + var decoded jwa.EllipticCurveAlgorithm + if err := dec.Decode(&decoded); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, OKPCrvKey, err) + } + h.crv = &decoded + case KeyIDKey: + if err := json.AssignNextStringToken(&h.keyID, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, KeyIDKey, err) + } + case KeyOpsKey: + var decoded KeyOperationList + if err := dec.Decode(&decoded); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, KeyOpsKey, err) + } + h.keyOps = &decoded + case KeyUsageKey: + if err := json.AssignNextStringToken(&h.keyUsage, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, KeyUsageKey, err) + } + case OKPXKey: + if err := json.AssignNextBytesToken(&h.x, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, OKPXKey, err) + } + case X509CertChainKey: + var decoded cert.Chain + if err := dec.Decode(&decoded); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, X509CertChainKey, err) + } + h.x509CertChain = &decoded + case X509CertThumbprintKey: + if err := json.AssignNextStringToken(&h.x509CertThumbprint, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, X509CertThumbprintKey, err) + } + case X509CertThumbprintS256Key: + if err := json.AssignNextStringToken(&h.x509CertThumbprintS256, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, X509CertThumbprintS256Key, err) + } + case X509URLKey: + if err := json.AssignNextStringToken(&h.x509URL, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, X509URLKey, err) + } + default: + if dc := h.dc; dc != nil { + if localReg := dc.Registry(); localReg != nil { + decoded, err := localReg.Decode(dec, tok) + if err == nil { + h.setNoLock(tok, decoded) + continue + } + } + } + decoded, err := registry.Decode(dec, tok) + if err == nil { + h.setNoLock(tok, decoded) + continue + } + return fmt.Errorf(`could not decode field %s: %w`, tok, err) + } + default: + return fmt.Errorf(`invalid token %T`, tok) + } + } + if h.crv == nil { + return fmt.Errorf(`required field crv is missing`) + } + if h.x == nil { + return fmt.Errorf(`required field x is missing`) + } + return nil +} + +func (h okpPublicKey) MarshalJSON() ([]byte, error) { + data := make(map[string]any) + fields := make([]string, 0, 10) + data[KeyTypeKey] = jwa.OKP() + fields = append(fields, KeyTypeKey) + if h.algorithm != nil { + data[AlgorithmKey] = *(h.algorithm) + fields = append(fields, AlgorithmKey) + } + if h.crv != nil { + data[OKPCrvKey] = *(h.crv) + fields = append(fields, OKPCrvKey) + } + if h.keyID != nil { + data[KeyIDKey] = *(h.keyID) + fields = append(fields, KeyIDKey) + } + if h.keyOps != nil { + data[KeyOpsKey] = *(h.keyOps) + fields = append(fields, KeyOpsKey) + } + if h.keyUsage != nil { + data[KeyUsageKey] = *(h.keyUsage) + fields = append(fields, KeyUsageKey) + } + if h.x != nil { + data[OKPXKey] = h.x + fields = append(fields, OKPXKey) + } + if h.x509CertChain != nil { + data[X509CertChainKey] = h.x509CertChain + fields = append(fields, X509CertChainKey) + } + if h.x509CertThumbprint != nil { + data[X509CertThumbprintKey] = *(h.x509CertThumbprint) + fields = append(fields, X509CertThumbprintKey) + } + if h.x509CertThumbprintS256 != nil { + data[X509CertThumbprintS256Key] = *(h.x509CertThumbprintS256) + fields = append(fields, X509CertThumbprintS256Key) + } + if h.x509URL != nil { + data[X509URLKey] = *(h.x509URL) + fields = append(fields, X509URLKey) + } + for k, v := range h.privateParams { + data[k] = v + fields = append(fields, k) + } + + sort.Strings(fields) + buf := pool.BytesBuffer().Get() + defer pool.BytesBuffer().Put(buf) + buf.WriteByte(tokens.OpenCurlyBracket) + enc := json.NewEncoder(buf) + for i, f := range fields { + if i > 0 { + buf.WriteRune(tokens.Comma) + } + buf.WriteRune(tokens.DoubleQuote) + buf.WriteString(f) + buf.WriteString(`":`) + v := data[f] + switch v := v.(type) { + case []byte: + buf.WriteRune(tokens.DoubleQuote) + buf.WriteString(base64.EncodeToString(v)) + buf.WriteRune(tokens.DoubleQuote) + default: + if err := enc.Encode(v); err != nil { + return nil, fmt.Errorf(`failed to encode value for field %s: %w`, f, err) + } + buf.Truncate(buf.Len() - 1) + } + } + buf.WriteByte(tokens.CloseCurlyBracket) + ret := make([]byte, buf.Len()) + copy(ret, buf.Bytes()) + return ret, nil +} + +func (h *okpPublicKey) Keys() []string { + h.mu.RLock() + defer h.mu.RUnlock() + keys := make([]string, 0, 10+len(h.privateParams)) + keys = append(keys, KeyTypeKey) + if h.algorithm != nil { + keys = append(keys, AlgorithmKey) + } + if h.crv != nil { + keys = append(keys, OKPCrvKey) + } + if h.keyID != nil { + keys = append(keys, KeyIDKey) + } + if h.keyOps != nil { + keys = append(keys, KeyOpsKey) + } + if h.keyUsage != nil { + keys = append(keys, KeyUsageKey) + } + if h.x != nil { + keys = append(keys, OKPXKey) + } + if h.x509CertChain != nil { + keys = append(keys, X509CertChainKey) + } + if h.x509CertThumbprint != nil { + keys = append(keys, X509CertThumbprintKey) + } + if h.x509CertThumbprintS256 != nil { + keys = append(keys, X509CertThumbprintS256Key) + } + if h.x509URL != nil { + keys = append(keys, X509URLKey) + } + for k := range h.privateParams { + keys = append(keys, k) + } + return keys +} + +type OKPPrivateKey interface { + Key + Crv() (jwa.EllipticCurveAlgorithm, bool) + D() ([]byte, bool) + X() ([]byte, bool) +} + +type okpPrivateKey struct { + algorithm *jwa.KeyAlgorithm // https://tools.ietf.org/html/rfc7517#section-4.4 + crv *jwa.EllipticCurveAlgorithm + d []byte + keyID *string // https://tools.ietf.org/html/rfc7515#section-4.1.4 + keyOps *KeyOperationList // https://tools.ietf.org/html/rfc7517#section-4.3 + keyUsage *string // https://tools.ietf.org/html/rfc7517#section-4.2 + x []byte + x509CertChain *cert.Chain // https://tools.ietf.org/html/rfc7515#section-4.1.6 + x509CertThumbprint *string // https://tools.ietf.org/html/rfc7515#section-4.1.7 + x509CertThumbprintS256 *string // https://tools.ietf.org/html/rfc7515#section-4.1.8 + x509URL *string // https://tools.ietf.org/html/rfc7515#section-4.1.5 + privateParams map[string]any + mu *sync.RWMutex + dc json.DecodeCtx +} + +var _ OKPPrivateKey = &okpPrivateKey{} +var _ Key = &okpPrivateKey{} + +func newOKPPrivateKey() *okpPrivateKey { + return &okpPrivateKey{ + mu: &sync.RWMutex{}, + privateParams: make(map[string]any), + } +} + +func (h okpPrivateKey) KeyType() jwa.KeyType { + return jwa.OKP() +} + +func (h okpPrivateKey) rlock() { + h.mu.RLock() +} + +func (h okpPrivateKey) runlock() { + h.mu.RUnlock() +} + +func (h okpPrivateKey) IsPrivate() bool { + return true +} + +func (h *okpPrivateKey) Algorithm() (jwa.KeyAlgorithm, bool) { + if h.algorithm != nil { + return *(h.algorithm), true + } + return nil, false +} + +func (h *okpPrivateKey) Crv() (jwa.EllipticCurveAlgorithm, bool) { + if h.crv != nil { + return *(h.crv), true + } + return jwa.InvalidEllipticCurve(), false +} + +func (h *okpPrivateKey) D() ([]byte, bool) { + if h.d != nil { + return h.d, true + } + return nil, false +} + +func (h *okpPrivateKey) KeyID() (string, bool) { + if h.keyID != nil { + return *(h.keyID), true + } + return "", false +} + +func (h *okpPrivateKey) KeyOps() (KeyOperationList, bool) { + if h.keyOps != nil { + return *(h.keyOps), true + } + return nil, false +} + +func (h *okpPrivateKey) KeyUsage() (string, bool) { + if h.keyUsage != nil { + return *(h.keyUsage), true + } + return "", false +} + +func (h *okpPrivateKey) X() ([]byte, bool) { + if h.x != nil { + return h.x, true + } + return nil, false +} + +func (h *okpPrivateKey) X509CertChain() (*cert.Chain, bool) { + return h.x509CertChain, true +} + +func (h *okpPrivateKey) X509CertThumbprint() (string, bool) { + if h.x509CertThumbprint != nil { + return *(h.x509CertThumbprint), true + } + return "", false +} + +func (h *okpPrivateKey) X509CertThumbprintS256() (string, bool) { + if h.x509CertThumbprintS256 != nil { + return *(h.x509CertThumbprintS256), true + } + return "", false +} + +func (h *okpPrivateKey) X509URL() (string, bool) { + if h.x509URL != nil { + return *(h.x509URL), true + } + return "", false +} + +func (h *okpPrivateKey) Has(name string) bool { + h.mu.RLock() + defer h.mu.RUnlock() + switch name { + case KeyTypeKey: + return true + case AlgorithmKey: + return h.algorithm != nil + case OKPCrvKey: + return h.crv != nil + case OKPDKey: + return h.d != nil + case KeyIDKey: + return h.keyID != nil + case KeyOpsKey: + return h.keyOps != nil + case KeyUsageKey: + return h.keyUsage != nil + case OKPXKey: + return h.x != nil + case X509CertChainKey: + return h.x509CertChain != nil + case X509CertThumbprintKey: + return h.x509CertThumbprint != nil + case X509CertThumbprintS256Key: + return h.x509CertThumbprintS256 != nil + case X509URLKey: + return h.x509URL != nil + default: + _, ok := h.privateParams[name] + return ok + } +} + +func (h *okpPrivateKey) Get(name string, dst any) error { + h.mu.RLock() + defer h.mu.RUnlock() + switch name { + case KeyTypeKey: + if err := blackmagic.AssignIfCompatible(dst, h.KeyType()); err != nil { + return fmt.Errorf(`okpPrivateKey.Get: failed to assign value for field %q to destination object: %w`, name, err) + } + case AlgorithmKey: + if h.algorithm == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.algorithm)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case OKPCrvKey: + if h.crv == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.crv)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case OKPDKey: + if h.d == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, h.d); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case KeyIDKey: + if h.keyID == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.keyID)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case KeyOpsKey: + if h.keyOps == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.keyOps)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case KeyUsageKey: + if h.keyUsage == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.keyUsage)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case OKPXKey: + if h.x == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, h.x); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case X509CertChainKey: + if h.x509CertChain == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, h.x509CertChain); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case X509CertThumbprintKey: + if h.x509CertThumbprint == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.x509CertThumbprint)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case X509CertThumbprintS256Key: + if h.x509CertThumbprintS256 == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.x509CertThumbprintS256)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case X509URLKey: + if h.x509URL == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.x509URL)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + default: + v, ok := h.privateParams[name] + if !ok { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, v); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + } + return nil +} + +func (h *okpPrivateKey) Set(name string, value any) error { + h.mu.Lock() + defer h.mu.Unlock() + return h.setNoLock(name, value) +} + +func (h *okpPrivateKey) setNoLock(name string, value any) error { + switch name { + case "kty": + return nil + case AlgorithmKey: + switch v := value.(type) { + case string, jwa.SignatureAlgorithm, jwa.KeyEncryptionAlgorithm, jwa.ContentEncryptionAlgorithm: + tmp, err := jwa.KeyAlgorithmFrom(v) + if err != nil { + return fmt.Errorf(`invalid algorithm for %q key: %w`, AlgorithmKey, err) + } + h.algorithm = &tmp + default: + return fmt.Errorf(`invalid type for %q key: %T`, AlgorithmKey, value) + } + return nil + case OKPCrvKey: + if v, ok := value.(jwa.EllipticCurveAlgorithm); ok { + h.crv = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, OKPCrvKey, value) + case OKPDKey: + if v, ok := value.([]byte); ok { + h.d = v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, OKPDKey, value) + case KeyIDKey: + if v, ok := value.(string); ok { + h.keyID = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, KeyIDKey, value) + case KeyOpsKey: + var acceptor KeyOperationList + if err := acceptor.Accept(value); err != nil { + return fmt.Errorf(`invalid value for %s key: %w`, KeyOpsKey, err) + } + h.keyOps = &acceptor + return nil + case KeyUsageKey: + switch v := value.(type) { + case KeyUsageType: + switch v { + case ForSignature, ForEncryption: + tmp := v.String() + h.keyUsage = &tmp + default: + return fmt.Errorf(`invalid key usage type %s`, v) + } + case string: + h.keyUsage = &v + default: + return fmt.Errorf(`invalid key usage type %s`, v) + } + case OKPXKey: + if v, ok := value.([]byte); ok { + h.x = v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, OKPXKey, value) + case X509CertChainKey: + if v, ok := value.(*cert.Chain); ok { + h.x509CertChain = v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, X509CertChainKey, value) + case X509CertThumbprintKey: + if v, ok := value.(string); ok { + h.x509CertThumbprint = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, X509CertThumbprintKey, value) + case X509CertThumbprintS256Key: + if v, ok := value.(string); ok { + h.x509CertThumbprintS256 = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, X509CertThumbprintS256Key, value) + case X509URLKey: + if v, ok := value.(string); ok { + h.x509URL = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, X509URLKey, value) + default: + if h.privateParams == nil { + h.privateParams = map[string]any{} + } + h.privateParams[name] = value + } + return nil +} + +func (k *okpPrivateKey) Remove(key string) error { + k.mu.Lock() + defer k.mu.Unlock() + switch key { + case AlgorithmKey: + k.algorithm = nil + case OKPCrvKey: + k.crv = nil + case OKPDKey: + k.d = nil + case KeyIDKey: + k.keyID = nil + case KeyOpsKey: + k.keyOps = nil + case KeyUsageKey: + k.keyUsage = nil + case OKPXKey: + k.x = nil + case X509CertChainKey: + k.x509CertChain = nil + case X509CertThumbprintKey: + k.x509CertThumbprint = nil + case X509CertThumbprintS256Key: + k.x509CertThumbprintS256 = nil + case X509URLKey: + k.x509URL = nil + default: + delete(k.privateParams, key) + } + return nil +} + +func (k *okpPrivateKey) Clone() (Key, error) { + key, err := cloneKey(k) + if err != nil { + return nil, fmt.Errorf(`okpPrivateKey.Clone: %w`, err) + } + return key, nil +} + +func (k *okpPrivateKey) DecodeCtx() json.DecodeCtx { + k.mu.RLock() + defer k.mu.RUnlock() + return k.dc +} + +func (k *okpPrivateKey) SetDecodeCtx(dc json.DecodeCtx) { + k.mu.Lock() + defer k.mu.Unlock() + k.dc = dc +} + +func (h *okpPrivateKey) UnmarshalJSON(buf []byte) error { + h.mu.Lock() + defer h.mu.Unlock() + h.algorithm = nil + h.crv = nil + h.d = nil + h.keyID = nil + h.keyOps = nil + h.keyUsage = nil + h.x = nil + h.x509CertChain = nil + h.x509CertThumbprint = nil + h.x509CertThumbprintS256 = nil + h.x509URL = nil + dec := json.NewDecoder(bytes.NewReader(buf)) +LOOP: + for { + tok, err := dec.Token() + if err != nil { + return fmt.Errorf(`error reading token: %w`, err) + } + switch tok := tok.(type) { + case json.Delim: + // Assuming we're doing everything correctly, we should ONLY + // get either tokens.OpenCurlyBracket or tokens.CloseCurlyBracket here. + if tok == tokens.CloseCurlyBracket { // End of object + break LOOP + } else if tok != tokens.OpenCurlyBracket { + return fmt.Errorf(`expected '%c' but got '%c'`, tokens.OpenCurlyBracket, tok) + } + case string: // Objects can only have string keys + switch tok { + case KeyTypeKey: + val, err := json.ReadNextStringToken(dec) + if err != nil { + return fmt.Errorf(`error reading token: %w`, err) + } + if val != jwa.OKP().String() { + return fmt.Errorf(`invalid kty value for RSAPublicKey (%s)`, val) + } + case AlgorithmKey: + var s string + if err := dec.Decode(&s); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, AlgorithmKey, err) + } + alg, err := jwa.KeyAlgorithmFrom(s) + if err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, AlgorithmKey, err) + } + h.algorithm = &alg + case OKPCrvKey: + var decoded jwa.EllipticCurveAlgorithm + if err := dec.Decode(&decoded); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, OKPCrvKey, err) + } + h.crv = &decoded + case OKPDKey: + if err := json.AssignNextBytesToken(&h.d, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, OKPDKey, err) + } + case KeyIDKey: + if err := json.AssignNextStringToken(&h.keyID, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, KeyIDKey, err) + } + case KeyOpsKey: + var decoded KeyOperationList + if err := dec.Decode(&decoded); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, KeyOpsKey, err) + } + h.keyOps = &decoded + case KeyUsageKey: + if err := json.AssignNextStringToken(&h.keyUsage, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, KeyUsageKey, err) + } + case OKPXKey: + if err := json.AssignNextBytesToken(&h.x, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, OKPXKey, err) + } + case X509CertChainKey: + var decoded cert.Chain + if err := dec.Decode(&decoded); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, X509CertChainKey, err) + } + h.x509CertChain = &decoded + case X509CertThumbprintKey: + if err := json.AssignNextStringToken(&h.x509CertThumbprint, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, X509CertThumbprintKey, err) + } + case X509CertThumbprintS256Key: + if err := json.AssignNextStringToken(&h.x509CertThumbprintS256, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, X509CertThumbprintS256Key, err) + } + case X509URLKey: + if err := json.AssignNextStringToken(&h.x509URL, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, X509URLKey, err) + } + default: + if dc := h.dc; dc != nil { + if localReg := dc.Registry(); localReg != nil { + decoded, err := localReg.Decode(dec, tok) + if err == nil { + h.setNoLock(tok, decoded) + continue + } + } + } + decoded, err := registry.Decode(dec, tok) + if err == nil { + h.setNoLock(tok, decoded) + continue + } + return fmt.Errorf(`could not decode field %s: %w`, tok, err) + } + default: + return fmt.Errorf(`invalid token %T`, tok) + } + } + if h.crv == nil { + return fmt.Errorf(`required field crv is missing`) + } + if h.d == nil { + return fmt.Errorf(`required field d is missing`) + } + if h.x == nil { + return fmt.Errorf(`required field x is missing`) + } + return nil +} + +func (h okpPrivateKey) MarshalJSON() ([]byte, error) { + data := make(map[string]any) + fields := make([]string, 0, 11) + data[KeyTypeKey] = jwa.OKP() + fields = append(fields, KeyTypeKey) + if h.algorithm != nil { + data[AlgorithmKey] = *(h.algorithm) + fields = append(fields, AlgorithmKey) + } + if h.crv != nil { + data[OKPCrvKey] = *(h.crv) + fields = append(fields, OKPCrvKey) + } + if h.d != nil { + data[OKPDKey] = h.d + fields = append(fields, OKPDKey) + } + if h.keyID != nil { + data[KeyIDKey] = *(h.keyID) + fields = append(fields, KeyIDKey) + } + if h.keyOps != nil { + data[KeyOpsKey] = *(h.keyOps) + fields = append(fields, KeyOpsKey) + } + if h.keyUsage != nil { + data[KeyUsageKey] = *(h.keyUsage) + fields = append(fields, KeyUsageKey) + } + if h.x != nil { + data[OKPXKey] = h.x + fields = append(fields, OKPXKey) + } + if h.x509CertChain != nil { + data[X509CertChainKey] = h.x509CertChain + fields = append(fields, X509CertChainKey) + } + if h.x509CertThumbprint != nil { + data[X509CertThumbprintKey] = *(h.x509CertThumbprint) + fields = append(fields, X509CertThumbprintKey) + } + if h.x509CertThumbprintS256 != nil { + data[X509CertThumbprintS256Key] = *(h.x509CertThumbprintS256) + fields = append(fields, X509CertThumbprintS256Key) + } + if h.x509URL != nil { + data[X509URLKey] = *(h.x509URL) + fields = append(fields, X509URLKey) + } + for k, v := range h.privateParams { + data[k] = v + fields = append(fields, k) + } + + sort.Strings(fields) + buf := pool.BytesBuffer().Get() + defer pool.BytesBuffer().Put(buf) + buf.WriteByte(tokens.OpenCurlyBracket) + enc := json.NewEncoder(buf) + for i, f := range fields { + if i > 0 { + buf.WriteRune(tokens.Comma) + } + buf.WriteRune(tokens.DoubleQuote) + buf.WriteString(f) + buf.WriteString(`":`) + v := data[f] + switch v := v.(type) { + case []byte: + buf.WriteRune(tokens.DoubleQuote) + buf.WriteString(base64.EncodeToString(v)) + buf.WriteRune(tokens.DoubleQuote) + default: + if err := enc.Encode(v); err != nil { + return nil, fmt.Errorf(`failed to encode value for field %s: %w`, f, err) + } + buf.Truncate(buf.Len() - 1) + } + } + buf.WriteByte(tokens.CloseCurlyBracket) + ret := make([]byte, buf.Len()) + copy(ret, buf.Bytes()) + return ret, nil +} + +func (h *okpPrivateKey) Keys() []string { + h.mu.RLock() + defer h.mu.RUnlock() + keys := make([]string, 0, 11+len(h.privateParams)) + keys = append(keys, KeyTypeKey) + if h.algorithm != nil { + keys = append(keys, AlgorithmKey) + } + if h.crv != nil { + keys = append(keys, OKPCrvKey) + } + if h.d != nil { + keys = append(keys, OKPDKey) + } + if h.keyID != nil { + keys = append(keys, KeyIDKey) + } + if h.keyOps != nil { + keys = append(keys, KeyOpsKey) + } + if h.keyUsage != nil { + keys = append(keys, KeyUsageKey) + } + if h.x != nil { + keys = append(keys, OKPXKey) + } + if h.x509CertChain != nil { + keys = append(keys, X509CertChainKey) + } + if h.x509CertThumbprint != nil { + keys = append(keys, X509CertThumbprintKey) + } + if h.x509CertThumbprintS256 != nil { + keys = append(keys, X509CertThumbprintS256Key) + } + if h.x509URL != nil { + keys = append(keys, X509URLKey) + } + for k := range h.privateParams { + keys = append(keys, k) + } + return keys +} + +var okpStandardFields KeyFilter + +func init() { + okpStandardFields = NewFieldNameFilter(KeyTypeKey, KeyUsageKey, KeyOpsKey, AlgorithmKey, KeyIDKey, X509URLKey, X509CertChainKey, X509CertThumbprintKey, X509CertThumbprintS256Key, OKPCrvKey, OKPXKey, OKPDKey) +} + +// OKPStandardFieldsFilter returns a KeyFilter that filters out standard OKP fields. +func OKPStandardFieldsFilter() KeyFilter { + return okpStandardFields +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwk/options.go b/vendor/github.com/lestrrat-go/jwx/v3/jwk/options.go new file mode 100644 index 00000000000..56cc52625f7 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwk/options.go @@ -0,0 +1,76 @@ +package jwk + +import ( + "time" + + "github.com/lestrrat-go/httprc/v3" + "github.com/lestrrat-go/option/v2" +) + +type identTypedField struct{} + +type typedFieldPair struct { + Name string + Value any +} + +// WithTypedField allows a private field to be parsed into the object type of +// your choice. It works much like the RegisterCustomField, but the effect +// is only applicable to the jwt.Parse function call which receives this option. +// +// While this can be extremely useful, this option should be used with caution: +// There are many caveats that your entire team/user-base needs to be aware of, +// and therefore in general its use is discouraged. Only use it when you know +// what you are doing, and you document its use clearly for others. +// +// First and foremost, this is a "per-object" option. Meaning that given the same +// serialized format, it is possible to generate two objects whose internal +// representations may differ. That is, if you parse one _WITH_ the option, +// and the other _WITHOUT_, their internal representation may completely differ. +// This could potentially lead to problems. +// +// Second, specifying this option will slightly slow down the decoding process +// as it needs to consult multiple definitions sources (global and local), so +// be careful if you are decoding a large number of tokens, as the effects will stack up. +func WithTypedField(name string, object any) ParseOption { + return &parseOption{ + option.New(identTypedField{}, + typedFieldPair{Name: name, Value: object}, + ), + } +} + +type registerResourceOption struct { + option.Interface +} + +func (registerResourceOption) registerOption() {} +func (registerResourceOption) resourceOption() {} + +type identNewResourceOption struct{} + +// WithHttprcResourceOption can be used to pass arbitrary `httprc.NewResourceOption` +// to `(httprc.Client).Add` by way of `(jwk.Cache).Register`. +func WithHttprcResourceOption(o httprc.NewResourceOption) RegisterOption { + return ®isterResourceOption{ + option.New(identNewResourceOption{}, o), + } +} + +// WithConstantInterval can be used to pass `httprc.WithConstantInterval` option to +// `(httprc.Client).Add` by way of `(jwk.Cache).Register`. +func WithConstantInterval(d time.Duration) RegisterOption { + return WithHttprcResourceOption(httprc.WithConstantInterval(d)) +} + +// WithMinInterval can be used to pass `httprc.WithMinInterval` option to +// `(httprc.Client).Add` by way of `(jwk.Cache).Register`. +func WithMinInterval(d time.Duration) RegisterOption { + return WithHttprcResourceOption(httprc.WithMinInterval(d)) +} + +// WithMaxInterval can be used to pass `httprc.WithMaxInterval` option to +// `(httprc.Client).Add` by way of `(jwk.Cache).Register`. +func WithMaxInterval(d time.Duration) RegisterOption { + return WithHttprcResourceOption(httprc.WithMaxInterval(d)) +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwk/options.yaml b/vendor/github.com/lestrrat-go/jwx/v3/jwk/options.yaml new file mode 100644 index 00000000000..879dcba158b --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwk/options.yaml @@ -0,0 +1,143 @@ +package_name: jwk +output: jwk/options_gen.go +interfaces: + - name: CacheOption + comment: | + CacheOption is a type of Option that can be passed to the + the `jwk.NewCache()` function. + - name: ResourceOption + comment: | + ResourceOption is a type of Option that can be passed to the `httprc.NewResource` function + by way of RegisterOption. + - name: AssignKeyIDOption + - name: FetchOption + methods: + - fetchOption + - parseOption + - registerOption + comment: | + FetchOption is a type of Option that can be passed to `jwk.Fetch()` + FetchOption also implements the `RegisterOption`, and thus can + safely be passed to `(*jwk.Cache).Register()` + - name: ParseOption + methods: + - fetchOption + - registerOption + - readFileOption + comment: | + ParseOption is a type of Option that can be passed to `jwk.Parse()` + ParseOption also implements the `ReadFileOption` and `NewCacheOption`, + and thus safely be passed to `jwk.ReadFile` and `(*jwk.Cache).Configure()` + - name: ReadFileOption + comment: | + ReadFileOption is a type of `Option` that can be passed to `jwk.ReadFile` + - name: RegisterOption + comment: | + RegisterOption describes options that can be passed to `(jwk.Cache).Register()` + - name: RegisterFetchOption + methods: + - fetchOption + - registerOption + - parseOption + comment: | + RegisterFetchOption describes options that can be passed to `(jwk.Cache).Register()` and `jwk.Fetch()` + - name: GlobalOption + comment: | + GlobalOption is a type of Option that can be passed to the `jwk.Configure()` to + change the global configuration of the jwk package. +options: + - ident: HTTPClient + interface: RegisterFetchOption + argument_type: HTTPClient + comment: | + WithHTTPClient allows users to specify the "net/http".Client object that + is used when fetching jwk.Set objects. + - ident: ThumbprintHash + interface: AssignKeyIDOption + argument_type: crypto.Hash + - ident: LocalRegistry + option_name: withLocalRegistry + interface: ParseOption + argument_type: '*json.Registry' + comment: This option is only available for internal code. Users don't get to play with it + - ident: PEM + interface: ParseOption + argument_type: bool + comment: | + WithPEM specifies that the input to `Parse()` is a PEM encoded key. + + This option is planned to be deprecated in the future. The plan is to + replace it with `jwk.WithX509(true)` + - ident: X509 + interface: ParseOption + argument_type: bool + comment: | + WithX509 specifies that the input to `Parse()` is an X.509 encoded key + - ident: PEMDecoder + interface: ParseOption + argument_type: PEMDecoder + comment: | + WithPEMDecoder specifies the PEMDecoder object to use when decoding + PEM encoded keys. This option can be passed to `jwk.Parse()` + + This option is planned to be deprecated in the future. The plan is to + use `jwk.RegisterX509Decoder()` to register a custom X.509 decoder globally. + - ident: FetchWhitelist + interface: FetchOption + argument_type: Whitelist + comment: | + WithFetchWhitelist specifies the Whitelist object to use when + fetching JWKs from a remote source. This option can be passed + to both `jwk.Fetch()` + - ident: IgnoreParseError + interface: ParseOption + argument_type: bool + comment: | + WithIgnoreParseError is only applicable when used with `jwk.Parse()` + (i.e. to parse JWK sets). If passed to `jwk.ParseKey()`, the function + will return an error no matter what the input is. + + DO NOT USE WITHOUT EXHAUSTING ALL OTHER ROUTES FIRST. + + The option specifies that errors found during parsing of individual + keys are ignored. For example, if you had keys A, B, C where B is + invalid (e.g. it does not contain the required fields), then the + resulting JWKS will contain keys A and C only. + + This options exists as an escape hatch for those times when a + key in a JWKS that is irrelevant for your use case is causing + your JWKS parsing to fail, and you want to get to the rest of the + keys in the JWKS. + + Again, DO NOT USE unless you have exhausted all other routes. + When you use this option, you will not be able to tell if you are + using a faulty JWKS, except for when there are JSON syntax errors. + - ident: FS + interface: ReadFileOption + argument_type: fs.FS + comment: | + WithFS specifies the source `fs.FS` object to read the file from. + - ident: WaitReady + interface: RegisterOption + argument_type: bool + comment: | + WithWaitReady specifies that the `jwk.Cache` should wait until the + first fetch is done before returning from the `Register()` call. + + This option is by default true. Specify a false value if you would + like to return immediately from the `Register()` call. + + This options is exactly the same as `httprc.WithWaitReady()` + - ident: StrictKeyUsage + interface: GlobalOption + argument_type: bool + comment: | + WithStrictKeyUsage specifies if during JWK parsing, the "use" field + should be confined to the values that have been registered via + `jwk.RegisterKeyType()`. By default this option is true, and the + initial allowed values are "use" and "enc" only. + + If this option is set to false, then the "use" field can be any + value. If this options is set to true, then the "use" field must + be one of the registered values, and otherwise an error will be + reported during parsing / assignment to `jwk.KeyUsageType` \ No newline at end of file diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwk/options_gen.go b/vendor/github.com/lestrrat-go/jwx/v3/jwk/options_gen.go new file mode 100644 index 00000000000..99e66c3e7ed --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwk/options_gen.go @@ -0,0 +1,297 @@ +// Code generated by tools/cmd/genoptions/main.go. DO NOT EDIT. + +package jwk + +import ( + "crypto" + "io/fs" + + "github.com/lestrrat-go/jwx/v3/internal/json" + "github.com/lestrrat-go/option/v2" +) + +type Option = option.Interface + +type AssignKeyIDOption interface { + Option + assignKeyIDOption() +} + +type assignKeyIDOption struct { + Option +} + +func (*assignKeyIDOption) assignKeyIDOption() {} + +// CacheOption is a type of Option that can be passed to the +// the `jwk.NewCache()` function. +type CacheOption interface { + Option + cacheOption() +} + +type cacheOption struct { + Option +} + +func (*cacheOption) cacheOption() {} + +// FetchOption is a type of Option that can be passed to `jwk.Fetch()` +// FetchOption also implements the `RegisterOption`, and thus can +// safely be passed to `(*jwk.Cache).Register()` +type FetchOption interface { + Option + fetchOption() + parseOption() + registerOption() +} + +type fetchOption struct { + Option +} + +func (*fetchOption) fetchOption() {} + +func (*fetchOption) parseOption() {} + +func (*fetchOption) registerOption() {} + +// GlobalOption is a type of Option that can be passed to the `jwk.Configure()` to +// change the global configuration of the jwk package. +type GlobalOption interface { + Option + globalOption() +} + +type globalOption struct { + Option +} + +func (*globalOption) globalOption() {} + +// ParseOption is a type of Option that can be passed to `jwk.Parse()` +// ParseOption also implements the `ReadFileOption` and `NewCacheOption`, +// and thus safely be passed to `jwk.ReadFile` and `(*jwk.Cache).Configure()` +type ParseOption interface { + Option + fetchOption() + registerOption() + readFileOption() +} + +type parseOption struct { + Option +} + +func (*parseOption) fetchOption() {} + +func (*parseOption) registerOption() {} + +func (*parseOption) readFileOption() {} + +// ReadFileOption is a type of `Option` that can be passed to `jwk.ReadFile` +type ReadFileOption interface { + Option + readFileOption() +} + +type readFileOption struct { + Option +} + +func (*readFileOption) readFileOption() {} + +// RegisterFetchOption describes options that can be passed to `(jwk.Cache).Register()` and `jwk.Fetch()` +type RegisterFetchOption interface { + Option + fetchOption() + registerOption() + parseOption() +} + +type registerFetchOption struct { + Option +} + +func (*registerFetchOption) fetchOption() {} + +func (*registerFetchOption) registerOption() {} + +func (*registerFetchOption) parseOption() {} + +// RegisterOption describes options that can be passed to `(jwk.Cache).Register()` +type RegisterOption interface { + Option + registerOption() +} + +type registerOption struct { + Option +} + +func (*registerOption) registerOption() {} + +// ResourceOption is a type of Option that can be passed to the `httprc.NewResource` function +// by way of RegisterOption. +type ResourceOption interface { + Option + resourceOption() +} + +type resourceOption struct { + Option +} + +func (*resourceOption) resourceOption() {} + +type identFS struct{} +type identFetchWhitelist struct{} +type identHTTPClient struct{} +type identIgnoreParseError struct{} +type identLocalRegistry struct{} +type identPEM struct{} +type identPEMDecoder struct{} +type identStrictKeyUsage struct{} +type identThumbprintHash struct{} +type identWaitReady struct{} +type identX509 struct{} + +func (identFS) String() string { + return "WithFS" +} + +func (identFetchWhitelist) String() string { + return "WithFetchWhitelist" +} + +func (identHTTPClient) String() string { + return "WithHTTPClient" +} + +func (identIgnoreParseError) String() string { + return "WithIgnoreParseError" +} + +func (identLocalRegistry) String() string { + return "withLocalRegistry" +} + +func (identPEM) String() string { + return "WithPEM" +} + +func (identPEMDecoder) String() string { + return "WithPEMDecoder" +} + +func (identStrictKeyUsage) String() string { + return "WithStrictKeyUsage" +} + +func (identThumbprintHash) String() string { + return "WithThumbprintHash" +} + +func (identWaitReady) String() string { + return "WithWaitReady" +} + +func (identX509) String() string { + return "WithX509" +} + +// WithFS specifies the source `fs.FS` object to read the file from. +func WithFS(v fs.FS) ReadFileOption { + return &readFileOption{option.New(identFS{}, v)} +} + +// WithFetchWhitelist specifies the Whitelist object to use when +// fetching JWKs from a remote source. This option can be passed +// to both `jwk.Fetch()` +func WithFetchWhitelist(v Whitelist) FetchOption { + return &fetchOption{option.New(identFetchWhitelist{}, v)} +} + +// WithHTTPClient allows users to specify the "net/http".Client object that +// is used when fetching jwk.Set objects. +func WithHTTPClient(v HTTPClient) RegisterFetchOption { + return ®isterFetchOption{option.New(identHTTPClient{}, v)} +} + +// WithIgnoreParseError is only applicable when used with `jwk.Parse()` +// (i.e. to parse JWK sets). If passed to `jwk.ParseKey()`, the function +// will return an error no matter what the input is. +// +// DO NOT USE WITHOUT EXHAUSTING ALL OTHER ROUTES FIRST. +// +// The option specifies that errors found during parsing of individual +// keys are ignored. For example, if you had keys A, B, C where B is +// invalid (e.g. it does not contain the required fields), then the +// resulting JWKS will contain keys A and C only. +// +// This options exists as an escape hatch for those times when a +// key in a JWKS that is irrelevant for your use case is causing +// your JWKS parsing to fail, and you want to get to the rest of the +// keys in the JWKS. +// +// Again, DO NOT USE unless you have exhausted all other routes. +// When you use this option, you will not be able to tell if you are +// using a faulty JWKS, except for when there are JSON syntax errors. +func WithIgnoreParseError(v bool) ParseOption { + return &parseOption{option.New(identIgnoreParseError{}, v)} +} + +// This option is only available for internal code. Users don't get to play with it +func withLocalRegistry(v *json.Registry) ParseOption { + return &parseOption{option.New(identLocalRegistry{}, v)} +} + +// WithPEM specifies that the input to `Parse()` is a PEM encoded key. +// +// This option is planned to be deprecated in the future. The plan is to +// replace it with `jwk.WithX509(true)` +func WithPEM(v bool) ParseOption { + return &parseOption{option.New(identPEM{}, v)} +} + +// WithPEMDecoder specifies the PEMDecoder object to use when decoding +// PEM encoded keys. This option can be passed to `jwk.Parse()` +// +// This option is planned to be deprecated in the future. The plan is to +// use `jwk.RegisterX509Decoder()` to register a custom X.509 decoder globally. +func WithPEMDecoder(v PEMDecoder) ParseOption { + return &parseOption{option.New(identPEMDecoder{}, v)} +} + +// WithStrictKeyUsage specifies if during JWK parsing, the "use" field +// should be confined to the values that have been registered via +// `jwk.RegisterKeyType()`. By default this option is true, and the +// initial allowed values are "use" and "enc" only. +// +// If this option is set to false, then the "use" field can be any +// value. If this options is set to true, then the "use" field must +// be one of the registered values, and otherwise an error will be +// reported during parsing / assignment to `jwk.KeyUsageType` +func WithStrictKeyUsage(v bool) GlobalOption { + return &globalOption{option.New(identStrictKeyUsage{}, v)} +} + +func WithThumbprintHash(v crypto.Hash) AssignKeyIDOption { + return &assignKeyIDOption{option.New(identThumbprintHash{}, v)} +} + +// WithWaitReady specifies that the `jwk.Cache` should wait until the +// first fetch is done before returning from the `Register()` call. +// +// This option is by default true. Specify a false value if you would +// like to return immediately from the `Register()` call. +// +// This options is exactly the same as `httprc.WithWaitReady()` +func WithWaitReady(v bool) RegisterOption { + return ®isterOption{option.New(identWaitReady{}, v)} +} + +// WithX509 specifies that the input to `Parse()` is an X.509 encoded key +func WithX509(v bool) ParseOption { + return &parseOption{option.New(identX509{}, v)} +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwk/parser.go b/vendor/github.com/lestrrat-go/jwx/v3/jwk/parser.go new file mode 100644 index 00000000000..fa8764ef72a --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwk/parser.go @@ -0,0 +1,244 @@ +package jwk + +import ( + "fmt" + "reflect" + "sync" + + "github.com/lestrrat-go/blackmagic" + "github.com/lestrrat-go/jwx/v3/internal/json" + "github.com/lestrrat-go/jwx/v3/jwa" +) + +// KeyParser represents a type that can parse a JSON representation of a JWK into +// a jwk.Key. +// See KeyConvertor for a type that can convert a raw key into a jwk.Key +type KeyParser interface { + // ParseKey parses a JSON payload to a `jwk.Key` object. The first + // argument is an object that contains some hints as to what kind of + // key the JSON payload contains. + // + // If your KeyParser decides that the payload is not something + // you can parse, and you would like to continue parsing with + // the remaining KeyParser instances that are registered, + // return a `jwk.ContinueParseError`. Any other errors will immediately + // halt the parsing process. + // + // When unmarshaling JSON, use the unmarshaler object supplied as + // the second argument. This will ensure that the JSON is unmarshaled + // in a way that is compatible with the rest of the library. + ParseKey(probe *KeyProbe, unmarshaler KeyUnmarshaler, payload []byte) (Key, error) +} + +// KeyParseFunc is a type of KeyParser that is based on a function/closure +type KeyParseFunc func(probe *KeyProbe, unmarshaler KeyUnmarshaler, payload []byte) (Key, error) + +func (f KeyParseFunc) ParseKey(probe *KeyProbe, unmarshaler KeyUnmarshaler, payload []byte) (Key, error) { + return f(probe, unmarshaler, payload) +} + +// protects keyParsers +var muKeyParser sync.RWMutex + +// list of parsers +var keyParsers = []KeyParser{KeyParseFunc(defaultParseKey)} + +// RegisterKeyParser adds a new KeyParser. Parsers are called in FILO order. +// That is, the last parser to be registered is called first. There is no +// check for duplicate entries. +func RegisterKeyParser(kp KeyParser) { + muKeyParser.Lock() + defer muKeyParser.Unlock() + keyParsers = append(keyParsers, kp) +} + +func defaultParseKey(probe *KeyProbe, unmarshaler KeyUnmarshaler, data []byte) (Key, error) { + var key Key + var kty string + var d json.RawMessage + if err := probe.Get("Kty", &kty); err != nil { + return nil, fmt.Errorf(`jwk.Parse: failed to get "kty" hint: %w`, err) + } + // We ignore errors from this field, as it's optional + _ = probe.Get("D", &d) + switch v, _ := jwa.LookupKeyType(kty); v { + case jwa.RSA(): + if d != nil { + key = newRSAPrivateKey() + } else { + key = newRSAPublicKey() + } + case jwa.EC(): + if d != nil { + key = newECDSAPrivateKey() + } else { + key = newECDSAPublicKey() + } + case jwa.OctetSeq(): + key = newSymmetricKey() + case jwa.OKP(): + if d != nil { + key = newOKPPrivateKey() + } else { + key = newOKPPublicKey() + } + default: + return nil, fmt.Errorf(`invalid key type from JSON (%s)`, kty) + } + + if err := unmarshaler.UnmarshalKey(data, key); err != nil { + return nil, fmt.Errorf(`failed to unmarshal JSON into key (%T): %w`, key, err) + } + return key, nil +} + +type keyUnmarshaler struct { + localReg *json.Registry +} + +func (ku *keyUnmarshaler) UnmarshalKey(data []byte, key any) error { + if ku.localReg != nil { + dcKey, ok := key.(json.DecodeCtxContainer) + if !ok { + return fmt.Errorf(`typed field was requested, but the key (%T) does not support DecodeCtx`, key) + } + dc := json.NewDecodeCtx(ku.localReg) + dcKey.SetDecodeCtx(dc) + defer func() { dcKey.SetDecodeCtx(nil) }() + } + + if err := json.Unmarshal(data, key); err != nil { + return fmt.Errorf(`failed to unmarshal JSON into key (%T): %w`, key, err) + } + + return nil +} + +// keyProber is the object that starts the probing. When Probe() is called, +// it creates (possibly from a cached value) an object that is used to +// hold hint values. +type keyProber struct { + mu sync.RWMutex + pool *sync.Pool + fields map[string]reflect.StructField + typ reflect.Type +} + +func (kp *keyProber) AddField(field reflect.StructField) error { + kp.mu.Lock() + defer kp.mu.Unlock() + + if _, ok := kp.fields[field.Name]; ok { + return fmt.Errorf(`field name %s is already registered`, field.Name) + } + kp.fields[field.Name] = field + kp.makeStructType() + + // Update pool (note: the logic is the same, but we need to recreate it + // so that we don't accidentally use old stored values) + kp.pool = &sync.Pool{ + New: kp.makeStruct, + } + return nil +} + +func (kp *keyProber) makeStructType() { + // DOES NOT LOCK + fields := make([]reflect.StructField, 0, len(kp.fields)) + for _, f := range kp.fields { + fields = append(fields, f) + } + kp.typ = reflect.StructOf(fields) +} + +func (kp *keyProber) makeStruct() any { + return reflect.New(kp.typ) +} + +func (kp *keyProber) Probe(data []byte) (*KeyProbe, error) { + kp.mu.RLock() + defer kp.mu.RUnlock() + + // if the field list unchanged, so is the pool object, so effectively + // we should be using the cached version + v := kp.pool.Get() + if v == nil { + return nil, fmt.Errorf(`probe: failed to get object from pool`) + } + rv, ok := v.(reflect.Value) + if !ok { + return nil, fmt.Errorf(`probe: value returned from pool as of type %T, expected reflect.Value`, v) + } + + if err := json.Unmarshal(data, rv.Interface()); err != nil { + return nil, fmt.Errorf(`probe: failed to unmarshal data: %w`, err) + } + + return &KeyProbe{data: rv}, nil +} + +// KeyProbe is the object that carries the hints when parsing a key. +// The exact list of fields can vary depending on the types of key +// that are registered. +// +// Use `Get()` to access the value of a field. +// +// The underlying data stored in a KeyProbe is recycled each +// time a value is parsed, therefore you are not allowed to hold +// onto this object after ParseKey() is done. +type KeyProbe struct { + data reflect.Value +} + +// Get returns the value of the field with the given `name“. +// `dst` must be a pointer to a value that can hold the type of +// the value of the field, which is determined by the +// field type registered through `jwk.RegisterProbeField()` +func (kp *KeyProbe) Get(name string, dst any) error { + f := kp.data.Elem().FieldByName(name) + if !f.IsValid() { + return fmt.Errorf(`field %s not found`, name) + } + + if err := blackmagic.AssignIfCompatible(dst, f.Addr().Interface()); err != nil { + return fmt.Errorf(`failed to assign value of field %q to %T: %w`, name, dst, err) + } + return nil +} + +// We don't really need the object, we need to know its type +var keyProbe = &keyProber{ + fields: make(map[string]reflect.StructField), +} + +// RegisterProbeField adds a new field to be probed during the initial +// phase of parsing. This is done by partially parsing the JSON payload, +// and we do this by calling `json.Unmarshal` using a dynamic type that +// can possibly be modified during runtime. This function is used to +// add a new field to this dynamic type. +// +// Note that the `Name` field for the given `reflect.StructField` must start +// with an upper case alphabet, such that it is treated as an exported field. +// So for example, if you want to probe the "my_hint" field, you should specify +// the field name as "MyHint" or similar. +// +// Also the field name must be unique. If you believe that your field name may +// collide with other packages that may want to add their own probes, +// it is the responsibility of the caller +// to ensure that the field name is unique (possibly by prefixing the field +// name with a unique string). It is important to note that the field name +// need not be the same as the JSON field name. For example, your field name +// could be "MyPkg_MyHint", while the actual JSON field name could be "my_hint". +// +// If the field name is not unique, an error is returned. +func RegisterProbeField(p reflect.StructField) error { + // locking is done inside keyProbe + return keyProbe.AddField(p) +} + +// KeyUnmarshaler is a thin wrapper around json.Unmarshal. It behaves almost +// exactly like json.Unmarshal, but it allows us to add extra magic that +// is specific to this library before calling the actual json.Unmarshal. +type KeyUnmarshaler interface { + UnmarshalKey(data []byte, key any) error +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwk/rsa.go b/vendor/github.com/lestrrat-go/jwx/v3/jwk/rsa.go new file mode 100644 index 00000000000..bcd7d05c026 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwk/rsa.go @@ -0,0 +1,360 @@ +package jwk + +import ( + "crypto" + "crypto/rsa" + "encoding/binary" + "fmt" + "math/big" + "reflect" + + "github.com/lestrrat-go/jwx/v3/internal/base64" + "github.com/lestrrat-go/jwx/v3/internal/pool" + "github.com/lestrrat-go/jwx/v3/jwa" +) + +func init() { + RegisterKeyExporter(jwa.RSA(), KeyExportFunc(rsaJWKToRaw)) +} + +func (k *rsaPrivateKey) Import(rawKey *rsa.PrivateKey) error { + k.mu.Lock() + defer k.mu.Unlock() + + d, err := bigIntToBytes(rawKey.D) + if err != nil { + return fmt.Errorf(`invalid rsa.PrivateKey: %w`, err) + } + k.d = d + + l := len(rawKey.Primes) + + if l < 0 /* I know, I'm being paranoid */ || l > 2 { + return fmt.Errorf(`invalid number of primes in rsa.PrivateKey: need 0 to 2, but got %d`, len(rawKey.Primes)) + } + + if l > 0 { + p, err := bigIntToBytes(rawKey.Primes[0]) + if err != nil { + return fmt.Errorf(`invalid rsa.PrivateKey: %w`, err) + } + k.p = p + } + + if l > 1 { + q, err := bigIntToBytes(rawKey.Primes[1]) + if err != nil { + return fmt.Errorf(`invalid rsa.PrivateKey: %w`, err) + } + k.q = q + } + + // dp, dq, qi are optional values + if v, err := bigIntToBytes(rawKey.Precomputed.Dp); err == nil { + k.dp = v + } + if v, err := bigIntToBytes(rawKey.Precomputed.Dq); err == nil { + k.dq = v + } + if v, err := bigIntToBytes(rawKey.Precomputed.Qinv); err == nil { + k.qi = v + } + + // public key part + n, e, err := importRsaPublicKeyByteValues(&rawKey.PublicKey) + if err != nil { + return fmt.Errorf(`invalid rsa.PrivateKey: %w`, err) + } + k.n = n + k.e = e + + return nil +} + +func importRsaPublicKeyByteValues(rawKey *rsa.PublicKey) ([]byte, []byte, error) { + n, err := bigIntToBytes(rawKey.N) + if err != nil { + return nil, nil, fmt.Errorf(`invalid rsa.PublicKey: %w`, err) + } + + data := make([]byte, 8) + binary.BigEndian.PutUint64(data, uint64(rawKey.E)) + i := 0 + for ; i < len(data); i++ { + if data[i] != 0x0 { + break + } + } + return n, data[i:], nil +} + +func (k *rsaPublicKey) Import(rawKey *rsa.PublicKey) error { + k.mu.Lock() + defer k.mu.Unlock() + + n, e, err := importRsaPublicKeyByteValues(rawKey) + if err != nil { + return fmt.Errorf(`invalid rsa.PrivateKey: %w`, err) + } + k.n = n + k.e = e + + return nil +} + +func buildRSAPublicKey(key *rsa.PublicKey, n, e []byte) { + bin := pool.BigInt().Get() + bie := pool.BigInt().Get() + defer pool.BigInt().Put(bie) + + bin.SetBytes(n) + bie.SetBytes(e) + + key.N = bin + key.E = int(bie.Int64()) +} + +var rsaConvertibleKeys = []reflect.Type{ + reflect.TypeOf((*RSAPrivateKey)(nil)).Elem(), + reflect.TypeOf((*RSAPublicKey)(nil)).Elem(), +} + +func rsaJWKToRaw(key Key, hint any) (any, error) { + extracted, err := extractEmbeddedKey(key, rsaConvertibleKeys) + if err != nil { + return nil, fmt.Errorf(`failed to extract embedded key: %w`, err) + } + switch key := extracted.(type) { + case RSAPrivateKey: + switch hint.(type) { + case *rsa.PrivateKey, *any: + default: + return nil, fmt.Errorf(`invalid destination object type %T for private RSA JWK: %w`, hint, ContinueError()) + } + + locker, ok := key.(rlocker) + if !ok { + locker.rlock() + defer locker.runlock() + } + + od, ok := key.D() + if !ok { + return nil, fmt.Errorf(`missing "d" value`) + } + + oq, ok := key.Q() + if !ok { + return nil, fmt.Errorf(`missing "q" value`) + } + + op, ok := key.P() + if !ok { + return nil, fmt.Errorf(`missing "p" value`) + } + + var d, q, p big.Int // note: do not use from sync.Pool + + d.SetBytes(od) + q.SetBytes(oq) + p.SetBytes(op) + + // optional fields + var dp, dq, qi *big.Int + + if odp, ok := key.DP(); ok { + dp = &big.Int{} // note: do not use from sync.Pool + dp.SetBytes(odp) + } + + if odq, ok := key.DQ(); ok { + dq = &big.Int{} // note: do not use from sync.Pool + dq.SetBytes(odq) + } + + if oqi, ok := key.QI(); ok { + qi = &big.Int{} // note: do not use from sync.Pool + qi.SetBytes(oqi) + } + + n, ok := key.N() + if !ok { + return nil, fmt.Errorf(`missing "n" value`) + } + + e, ok := key.E() + if !ok { + return nil, fmt.Errorf(`missing "e" value`) + } + + var privkey rsa.PrivateKey + buildRSAPublicKey(&privkey.PublicKey, n, e) + privkey.D = &d + privkey.Primes = []*big.Int{&p, &q} + + if dp != nil { + privkey.Precomputed.Dp = dp + } + if dq != nil { + privkey.Precomputed.Dq = dq + } + if qi != nil { + privkey.Precomputed.Qinv = qi + } + // This may look like a no-op, but it's required if we want to + // compare it against a key generated by rsa.GenerateKey + privkey.Precomputed.CRTValues = []rsa.CRTValue{} + return &privkey, nil + case RSAPublicKey: + switch hint.(type) { + case *rsa.PublicKey, *any: + default: + return nil, fmt.Errorf(`invalid destination object type %T for public RSA JWK: %w`, hint, ContinueError()) + } + + locker, ok := key.(rlocker) + if !ok { + locker.rlock() + defer locker.runlock() + } + + n, ok := key.N() + if !ok { + return nil, fmt.Errorf(`missing "n" value`) + } + + e, ok := key.E() + if !ok { + return nil, fmt.Errorf(`missing "e" value`) + } + + var pubkey rsa.PublicKey + buildRSAPublicKey(&pubkey, n, e) + + return &pubkey, nil + + default: + return nil, ContinueError() + } +} + +func makeRSAPublicKey(src Key) (Key, error) { + newKey := newRSAPublicKey() + + // Iterate and copy everything except for the bits that should not be in the public key + for _, k := range src.Keys() { + switch k { + case RSADKey, RSADPKey, RSADQKey, RSAPKey, RSAQKey, RSAQIKey: + continue + default: + var v any + if err := src.Get(k, &v); err != nil { + return nil, fmt.Errorf(`rsa: makeRSAPublicKey: failed to get field %q: %w`, k, err) + } + if err := newKey.Set(k, v); err != nil { + return nil, fmt.Errorf(`rsa: makeRSAPublicKey: failed to set field %q: %w`, k, err) + } + } + } + + return newKey, nil +} + +func (k *rsaPrivateKey) PublicKey() (Key, error) { + return makeRSAPublicKey(k) +} + +func (k *rsaPublicKey) PublicKey() (Key, error) { + return makeRSAPublicKey(k) +} + +// Thumbprint returns the JWK thumbprint using the indicated +// hashing algorithm, according to RFC 7638 +func (k rsaPrivateKey) Thumbprint(hash crypto.Hash) ([]byte, error) { + k.mu.RLock() + defer k.mu.RUnlock() + + var key rsa.PrivateKey + if err := Export(&k, &key); err != nil { + return nil, fmt.Errorf(`failed to export RSA private key: %w`, err) + } + return rsaThumbprint(hash, &key.PublicKey) +} + +func (k rsaPublicKey) Thumbprint(hash crypto.Hash) ([]byte, error) { + k.mu.RLock() + defer k.mu.RUnlock() + + var key rsa.PublicKey + if err := Export(&k, &key); err != nil { + return nil, fmt.Errorf(`failed to export RSA public key: %w`, err) + } + return rsaThumbprint(hash, &key) +} + +func rsaThumbprint(hash crypto.Hash, key *rsa.PublicKey) ([]byte, error) { + buf := pool.BytesBuffer().Get() + defer pool.BytesBuffer().Put(buf) + + buf.WriteString(`{"e":"`) + buf.WriteString(base64.EncodeUint64ToString(uint64(key.E))) + buf.WriteString(`","kty":"RSA","n":"`) + buf.WriteString(base64.EncodeToString(key.N.Bytes())) + buf.WriteString(`"}`) + + h := hash.New() + if _, err := buf.WriteTo(h); err != nil { + return nil, fmt.Errorf(`failed to write rsaThumbprint: %w`, err) + } + return h.Sum(nil), nil +} + +func validateRSAKey(key interface { + N() ([]byte, bool) + E() ([]byte, bool) +}, checkPrivate bool) error { + n, ok := key.N() + if !ok { + return fmt.Errorf(`missing "n" value`) + } + + e, ok := key.E() + if !ok { + return fmt.Errorf(`missing "e" value`) + } + + if len(n) == 0 { + // Ideally we would like to check for the actual length, but unlike + // EC keys, we have nothing in the key itself that will tell us + // how many bits this key should have. + return fmt.Errorf(`missing "n" value`) + } + if len(e) == 0 { + return fmt.Errorf(`missing "e" value`) + } + if checkPrivate { + if priv, ok := key.(keyWithD); ok { + if d, ok := priv.D(); !ok || len(d) == 0 { + return fmt.Errorf(`missing "d" value`) + } + } else { + return fmt.Errorf(`missing "d" value`) + } + } + + return nil +} + +func (k *rsaPrivateKey) Validate() error { + if err := validateRSAKey(k, true); err != nil { + return NewKeyValidationError(fmt.Errorf(`jwk.RSAPrivateKey: %w`, err)) + } + return nil +} + +func (k *rsaPublicKey) Validate() error { + if err := validateRSAKey(k, false); err != nil { + return NewKeyValidationError(fmt.Errorf(`jwk.RSAPublicKey: %w`, err)) + } + return nil +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwk/rsa_gen.go b/vendor/github.com/lestrrat-go/jwx/v3/jwk/rsa_gen.go new file mode 100644 index 00000000000..8e2a4f085b4 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwk/rsa_gen.go @@ -0,0 +1,1543 @@ +// Code generated by tools/cmd/genjwk/main.go. DO NOT EDIT. + +package jwk + +import ( + "bytes" + "fmt" + "sort" + "sync" + + "github.com/lestrrat-go/blackmagic" + "github.com/lestrrat-go/jwx/v3/cert" + "github.com/lestrrat-go/jwx/v3/internal/base64" + "github.com/lestrrat-go/jwx/v3/internal/json" + "github.com/lestrrat-go/jwx/v3/internal/pool" + "github.com/lestrrat-go/jwx/v3/internal/tokens" + "github.com/lestrrat-go/jwx/v3/jwa" +) + +const ( + RSADKey = "d" + RSADPKey = "dp" + RSADQKey = "dq" + RSAEKey = "e" + RSANKey = "n" + RSAPKey = "p" + RSAQIKey = "qi" + RSAQKey = "q" +) + +type RSAPublicKey interface { + Key + E() ([]byte, bool) + N() ([]byte, bool) +} + +type rsaPublicKey struct { + algorithm *jwa.KeyAlgorithm // https://tools.ietf.org/html/rfc7517#section-4.4 + e []byte + keyID *string // https://tools.ietf.org/html/rfc7515#section-4.1.4 + keyOps *KeyOperationList // https://tools.ietf.org/html/rfc7517#section-4.3 + keyUsage *string // https://tools.ietf.org/html/rfc7517#section-4.2 + n []byte + x509CertChain *cert.Chain // https://tools.ietf.org/html/rfc7515#section-4.1.6 + x509CertThumbprint *string // https://tools.ietf.org/html/rfc7515#section-4.1.7 + x509CertThumbprintS256 *string // https://tools.ietf.org/html/rfc7515#section-4.1.8 + x509URL *string // https://tools.ietf.org/html/rfc7515#section-4.1.5 + privateParams map[string]any + mu *sync.RWMutex + dc json.DecodeCtx +} + +var _ RSAPublicKey = &rsaPublicKey{} +var _ Key = &rsaPublicKey{} + +func newRSAPublicKey() *rsaPublicKey { + return &rsaPublicKey{ + mu: &sync.RWMutex{}, + privateParams: make(map[string]any), + } +} + +func (h rsaPublicKey) KeyType() jwa.KeyType { + return jwa.RSA() +} + +func (h rsaPublicKey) rlock() { + h.mu.RLock() +} + +func (h rsaPublicKey) runlock() { + h.mu.RUnlock() +} + +func (h rsaPublicKey) IsPrivate() bool { + return false +} + +func (h *rsaPublicKey) Algorithm() (jwa.KeyAlgorithm, bool) { + if h.algorithm != nil { + return *(h.algorithm), true + } + return nil, false +} + +func (h *rsaPublicKey) E() ([]byte, bool) { + if h.e != nil { + return h.e, true + } + return nil, false +} + +func (h *rsaPublicKey) KeyID() (string, bool) { + if h.keyID != nil { + return *(h.keyID), true + } + return "", false +} + +func (h *rsaPublicKey) KeyOps() (KeyOperationList, bool) { + if h.keyOps != nil { + return *(h.keyOps), true + } + return nil, false +} + +func (h *rsaPublicKey) KeyUsage() (string, bool) { + if h.keyUsage != nil { + return *(h.keyUsage), true + } + return "", false +} + +func (h *rsaPublicKey) N() ([]byte, bool) { + if h.n != nil { + return h.n, true + } + return nil, false +} + +func (h *rsaPublicKey) X509CertChain() (*cert.Chain, bool) { + return h.x509CertChain, true +} + +func (h *rsaPublicKey) X509CertThumbprint() (string, bool) { + if h.x509CertThumbprint != nil { + return *(h.x509CertThumbprint), true + } + return "", false +} + +func (h *rsaPublicKey) X509CertThumbprintS256() (string, bool) { + if h.x509CertThumbprintS256 != nil { + return *(h.x509CertThumbprintS256), true + } + return "", false +} + +func (h *rsaPublicKey) X509URL() (string, bool) { + if h.x509URL != nil { + return *(h.x509URL), true + } + return "", false +} + +func (h *rsaPublicKey) Has(name string) bool { + h.mu.RLock() + defer h.mu.RUnlock() + switch name { + case KeyTypeKey: + return true + case AlgorithmKey: + return h.algorithm != nil + case RSAEKey: + return h.e != nil + case KeyIDKey: + return h.keyID != nil + case KeyOpsKey: + return h.keyOps != nil + case KeyUsageKey: + return h.keyUsage != nil + case RSANKey: + return h.n != nil + case X509CertChainKey: + return h.x509CertChain != nil + case X509CertThumbprintKey: + return h.x509CertThumbprint != nil + case X509CertThumbprintS256Key: + return h.x509CertThumbprintS256 != nil + case X509URLKey: + return h.x509URL != nil + default: + _, ok := h.privateParams[name] + return ok + } +} + +func (h *rsaPublicKey) Get(name string, dst any) error { + h.mu.RLock() + defer h.mu.RUnlock() + switch name { + case KeyTypeKey: + if err := blackmagic.AssignIfCompatible(dst, h.KeyType()); err != nil { + return fmt.Errorf(`rsaPublicKey.Get: failed to assign value for field %q to destination object: %w`, name, err) + } + case AlgorithmKey: + if h.algorithm == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.algorithm)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case RSAEKey: + if h.e == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, h.e); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case KeyIDKey: + if h.keyID == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.keyID)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case KeyOpsKey: + if h.keyOps == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.keyOps)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case KeyUsageKey: + if h.keyUsage == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.keyUsage)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case RSANKey: + if h.n == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, h.n); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case X509CertChainKey: + if h.x509CertChain == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, h.x509CertChain); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case X509CertThumbprintKey: + if h.x509CertThumbprint == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.x509CertThumbprint)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case X509CertThumbprintS256Key: + if h.x509CertThumbprintS256 == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.x509CertThumbprintS256)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case X509URLKey: + if h.x509URL == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.x509URL)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + default: + v, ok := h.privateParams[name] + if !ok { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, v); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + } + return nil +} + +func (h *rsaPublicKey) Set(name string, value any) error { + h.mu.Lock() + defer h.mu.Unlock() + return h.setNoLock(name, value) +} + +func (h *rsaPublicKey) setNoLock(name string, value any) error { + switch name { + case "kty": + return nil + case AlgorithmKey: + switch v := value.(type) { + case string, jwa.SignatureAlgorithm, jwa.KeyEncryptionAlgorithm, jwa.ContentEncryptionAlgorithm: + tmp, err := jwa.KeyAlgorithmFrom(v) + if err != nil { + return fmt.Errorf(`invalid algorithm for %q key: %w`, AlgorithmKey, err) + } + h.algorithm = &tmp + default: + return fmt.Errorf(`invalid type for %q key: %T`, AlgorithmKey, value) + } + return nil + case RSAEKey: + if v, ok := value.([]byte); ok { + h.e = v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, RSAEKey, value) + case KeyIDKey: + if v, ok := value.(string); ok { + h.keyID = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, KeyIDKey, value) + case KeyOpsKey: + var acceptor KeyOperationList + if err := acceptor.Accept(value); err != nil { + return fmt.Errorf(`invalid value for %s key: %w`, KeyOpsKey, err) + } + h.keyOps = &acceptor + return nil + case KeyUsageKey: + switch v := value.(type) { + case KeyUsageType: + switch v { + case ForSignature, ForEncryption: + tmp := v.String() + h.keyUsage = &tmp + default: + return fmt.Errorf(`invalid key usage type %s`, v) + } + case string: + h.keyUsage = &v + default: + return fmt.Errorf(`invalid key usage type %s`, v) + } + case RSANKey: + if v, ok := value.([]byte); ok { + h.n = v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, RSANKey, value) + case X509CertChainKey: + if v, ok := value.(*cert.Chain); ok { + h.x509CertChain = v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, X509CertChainKey, value) + case X509CertThumbprintKey: + if v, ok := value.(string); ok { + h.x509CertThumbprint = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, X509CertThumbprintKey, value) + case X509CertThumbprintS256Key: + if v, ok := value.(string); ok { + h.x509CertThumbprintS256 = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, X509CertThumbprintS256Key, value) + case X509URLKey: + if v, ok := value.(string); ok { + h.x509URL = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, X509URLKey, value) + default: + if h.privateParams == nil { + h.privateParams = map[string]any{} + } + h.privateParams[name] = value + } + return nil +} + +func (k *rsaPublicKey) Remove(key string) error { + k.mu.Lock() + defer k.mu.Unlock() + switch key { + case AlgorithmKey: + k.algorithm = nil + case RSAEKey: + k.e = nil + case KeyIDKey: + k.keyID = nil + case KeyOpsKey: + k.keyOps = nil + case KeyUsageKey: + k.keyUsage = nil + case RSANKey: + k.n = nil + case X509CertChainKey: + k.x509CertChain = nil + case X509CertThumbprintKey: + k.x509CertThumbprint = nil + case X509CertThumbprintS256Key: + k.x509CertThumbprintS256 = nil + case X509URLKey: + k.x509URL = nil + default: + delete(k.privateParams, key) + } + return nil +} + +func (k *rsaPublicKey) Clone() (Key, error) { + key, err := cloneKey(k) + if err != nil { + return nil, fmt.Errorf(`rsaPublicKey.Clone: %w`, err) + } + return key, nil +} + +func (k *rsaPublicKey) DecodeCtx() json.DecodeCtx { + k.mu.RLock() + defer k.mu.RUnlock() + return k.dc +} + +func (k *rsaPublicKey) SetDecodeCtx(dc json.DecodeCtx) { + k.mu.Lock() + defer k.mu.Unlock() + k.dc = dc +} + +func (h *rsaPublicKey) UnmarshalJSON(buf []byte) error { + h.mu.Lock() + defer h.mu.Unlock() + h.algorithm = nil + h.e = nil + h.keyID = nil + h.keyOps = nil + h.keyUsage = nil + h.n = nil + h.x509CertChain = nil + h.x509CertThumbprint = nil + h.x509CertThumbprintS256 = nil + h.x509URL = nil + dec := json.NewDecoder(bytes.NewReader(buf)) +LOOP: + for { + tok, err := dec.Token() + if err != nil { + return fmt.Errorf(`error reading token: %w`, err) + } + switch tok := tok.(type) { + case json.Delim: + // Assuming we're doing everything correctly, we should ONLY + // get either tokens.OpenCurlyBracket or tokens.CloseCurlyBracket here. + if tok == tokens.CloseCurlyBracket { // End of object + break LOOP + } else if tok != tokens.OpenCurlyBracket { + return fmt.Errorf(`expected '%c' but got '%c'`, tokens.OpenCurlyBracket, tok) + } + case string: // Objects can only have string keys + switch tok { + case KeyTypeKey: + val, err := json.ReadNextStringToken(dec) + if err != nil { + return fmt.Errorf(`error reading token: %w`, err) + } + if val != jwa.RSA().String() { + return fmt.Errorf(`invalid kty value for RSAPublicKey (%s)`, val) + } + case AlgorithmKey: + var s string + if err := dec.Decode(&s); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, AlgorithmKey, err) + } + alg, err := jwa.KeyAlgorithmFrom(s) + if err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, AlgorithmKey, err) + } + h.algorithm = &alg + case RSAEKey: + if err := json.AssignNextBytesToken(&h.e, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, RSAEKey, err) + } + case KeyIDKey: + if err := json.AssignNextStringToken(&h.keyID, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, KeyIDKey, err) + } + case KeyOpsKey: + var decoded KeyOperationList + if err := dec.Decode(&decoded); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, KeyOpsKey, err) + } + h.keyOps = &decoded + case KeyUsageKey: + if err := json.AssignNextStringToken(&h.keyUsage, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, KeyUsageKey, err) + } + case RSANKey: + if err := json.AssignNextBytesToken(&h.n, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, RSANKey, err) + } + case X509CertChainKey: + var decoded cert.Chain + if err := dec.Decode(&decoded); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, X509CertChainKey, err) + } + h.x509CertChain = &decoded + case X509CertThumbprintKey: + if err := json.AssignNextStringToken(&h.x509CertThumbprint, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, X509CertThumbprintKey, err) + } + case X509CertThumbprintS256Key: + if err := json.AssignNextStringToken(&h.x509CertThumbprintS256, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, X509CertThumbprintS256Key, err) + } + case X509URLKey: + if err := json.AssignNextStringToken(&h.x509URL, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, X509URLKey, err) + } + default: + if dc := h.dc; dc != nil { + if localReg := dc.Registry(); localReg != nil { + decoded, err := localReg.Decode(dec, tok) + if err == nil { + h.setNoLock(tok, decoded) + continue + } + } + } + decoded, err := registry.Decode(dec, tok) + if err == nil { + h.setNoLock(tok, decoded) + continue + } + return fmt.Errorf(`could not decode field %s: %w`, tok, err) + } + default: + return fmt.Errorf(`invalid token %T`, tok) + } + } + if h.e == nil { + return fmt.Errorf(`required field e is missing`) + } + if h.n == nil { + return fmt.Errorf(`required field n is missing`) + } + return nil +} + +func (h rsaPublicKey) MarshalJSON() ([]byte, error) { + data := make(map[string]any) + fields := make([]string, 0, 10) + data[KeyTypeKey] = jwa.RSA() + fields = append(fields, KeyTypeKey) + if h.algorithm != nil { + data[AlgorithmKey] = *(h.algorithm) + fields = append(fields, AlgorithmKey) + } + if h.e != nil { + data[RSAEKey] = h.e + fields = append(fields, RSAEKey) + } + if h.keyID != nil { + data[KeyIDKey] = *(h.keyID) + fields = append(fields, KeyIDKey) + } + if h.keyOps != nil { + data[KeyOpsKey] = *(h.keyOps) + fields = append(fields, KeyOpsKey) + } + if h.keyUsage != nil { + data[KeyUsageKey] = *(h.keyUsage) + fields = append(fields, KeyUsageKey) + } + if h.n != nil { + data[RSANKey] = h.n + fields = append(fields, RSANKey) + } + if h.x509CertChain != nil { + data[X509CertChainKey] = h.x509CertChain + fields = append(fields, X509CertChainKey) + } + if h.x509CertThumbprint != nil { + data[X509CertThumbprintKey] = *(h.x509CertThumbprint) + fields = append(fields, X509CertThumbprintKey) + } + if h.x509CertThumbprintS256 != nil { + data[X509CertThumbprintS256Key] = *(h.x509CertThumbprintS256) + fields = append(fields, X509CertThumbprintS256Key) + } + if h.x509URL != nil { + data[X509URLKey] = *(h.x509URL) + fields = append(fields, X509URLKey) + } + for k, v := range h.privateParams { + data[k] = v + fields = append(fields, k) + } + + sort.Strings(fields) + buf := pool.BytesBuffer().Get() + defer pool.BytesBuffer().Put(buf) + buf.WriteByte(tokens.OpenCurlyBracket) + enc := json.NewEncoder(buf) + for i, f := range fields { + if i > 0 { + buf.WriteRune(tokens.Comma) + } + buf.WriteRune(tokens.DoubleQuote) + buf.WriteString(f) + buf.WriteString(`":`) + v := data[f] + switch v := v.(type) { + case []byte: + buf.WriteRune(tokens.DoubleQuote) + buf.WriteString(base64.EncodeToString(v)) + buf.WriteRune(tokens.DoubleQuote) + default: + if err := enc.Encode(v); err != nil { + return nil, fmt.Errorf(`failed to encode value for field %s: %w`, f, err) + } + buf.Truncate(buf.Len() - 1) + } + } + buf.WriteByte(tokens.CloseCurlyBracket) + ret := make([]byte, buf.Len()) + copy(ret, buf.Bytes()) + return ret, nil +} + +func (h *rsaPublicKey) Keys() []string { + h.mu.RLock() + defer h.mu.RUnlock() + keys := make([]string, 0, 10+len(h.privateParams)) + keys = append(keys, KeyTypeKey) + if h.algorithm != nil { + keys = append(keys, AlgorithmKey) + } + if h.e != nil { + keys = append(keys, RSAEKey) + } + if h.keyID != nil { + keys = append(keys, KeyIDKey) + } + if h.keyOps != nil { + keys = append(keys, KeyOpsKey) + } + if h.keyUsage != nil { + keys = append(keys, KeyUsageKey) + } + if h.n != nil { + keys = append(keys, RSANKey) + } + if h.x509CertChain != nil { + keys = append(keys, X509CertChainKey) + } + if h.x509CertThumbprint != nil { + keys = append(keys, X509CertThumbprintKey) + } + if h.x509CertThumbprintS256 != nil { + keys = append(keys, X509CertThumbprintS256Key) + } + if h.x509URL != nil { + keys = append(keys, X509URLKey) + } + for k := range h.privateParams { + keys = append(keys, k) + } + return keys +} + +type RSAPrivateKey interface { + Key + D() ([]byte, bool) + DP() ([]byte, bool) + DQ() ([]byte, bool) + E() ([]byte, bool) + N() ([]byte, bool) + P() ([]byte, bool) + Q() ([]byte, bool) + QI() ([]byte, bool) +} + +type rsaPrivateKey struct { + algorithm *jwa.KeyAlgorithm // https://tools.ietf.org/html/rfc7517#section-4.4 + d []byte + dp []byte + dq []byte + e []byte + keyID *string // https://tools.ietf.org/html/rfc7515#section-4.1.4 + keyOps *KeyOperationList // https://tools.ietf.org/html/rfc7517#section-4.3 + keyUsage *string // https://tools.ietf.org/html/rfc7517#section-4.2 + n []byte + p []byte + q []byte + qi []byte + x509CertChain *cert.Chain // https://tools.ietf.org/html/rfc7515#section-4.1.6 + x509CertThumbprint *string // https://tools.ietf.org/html/rfc7515#section-4.1.7 + x509CertThumbprintS256 *string // https://tools.ietf.org/html/rfc7515#section-4.1.8 + x509URL *string // https://tools.ietf.org/html/rfc7515#section-4.1.5 + privateParams map[string]any + mu *sync.RWMutex + dc json.DecodeCtx +} + +var _ RSAPrivateKey = &rsaPrivateKey{} +var _ Key = &rsaPrivateKey{} + +func newRSAPrivateKey() *rsaPrivateKey { + return &rsaPrivateKey{ + mu: &sync.RWMutex{}, + privateParams: make(map[string]any), + } +} + +func (h rsaPrivateKey) KeyType() jwa.KeyType { + return jwa.RSA() +} + +func (h rsaPrivateKey) rlock() { + h.mu.RLock() +} + +func (h rsaPrivateKey) runlock() { + h.mu.RUnlock() +} + +func (h rsaPrivateKey) IsPrivate() bool { + return true +} + +func (h *rsaPrivateKey) Algorithm() (jwa.KeyAlgorithm, bool) { + if h.algorithm != nil { + return *(h.algorithm), true + } + return nil, false +} + +func (h *rsaPrivateKey) D() ([]byte, bool) { + if h.d != nil { + return h.d, true + } + return nil, false +} + +func (h *rsaPrivateKey) DP() ([]byte, bool) { + if h.dp != nil { + return h.dp, true + } + return nil, false +} + +func (h *rsaPrivateKey) DQ() ([]byte, bool) { + if h.dq != nil { + return h.dq, true + } + return nil, false +} + +func (h *rsaPrivateKey) E() ([]byte, bool) { + if h.e != nil { + return h.e, true + } + return nil, false +} + +func (h *rsaPrivateKey) KeyID() (string, bool) { + if h.keyID != nil { + return *(h.keyID), true + } + return "", false +} + +func (h *rsaPrivateKey) KeyOps() (KeyOperationList, bool) { + if h.keyOps != nil { + return *(h.keyOps), true + } + return nil, false +} + +func (h *rsaPrivateKey) KeyUsage() (string, bool) { + if h.keyUsage != nil { + return *(h.keyUsage), true + } + return "", false +} + +func (h *rsaPrivateKey) N() ([]byte, bool) { + if h.n != nil { + return h.n, true + } + return nil, false +} + +func (h *rsaPrivateKey) P() ([]byte, bool) { + if h.p != nil { + return h.p, true + } + return nil, false +} + +func (h *rsaPrivateKey) Q() ([]byte, bool) { + if h.q != nil { + return h.q, true + } + return nil, false +} + +func (h *rsaPrivateKey) QI() ([]byte, bool) { + if h.qi != nil { + return h.qi, true + } + return nil, false +} + +func (h *rsaPrivateKey) X509CertChain() (*cert.Chain, bool) { + return h.x509CertChain, true +} + +func (h *rsaPrivateKey) X509CertThumbprint() (string, bool) { + if h.x509CertThumbprint != nil { + return *(h.x509CertThumbprint), true + } + return "", false +} + +func (h *rsaPrivateKey) X509CertThumbprintS256() (string, bool) { + if h.x509CertThumbprintS256 != nil { + return *(h.x509CertThumbprintS256), true + } + return "", false +} + +func (h *rsaPrivateKey) X509URL() (string, bool) { + if h.x509URL != nil { + return *(h.x509URL), true + } + return "", false +} + +func (h *rsaPrivateKey) Has(name string) bool { + h.mu.RLock() + defer h.mu.RUnlock() + switch name { + case KeyTypeKey: + return true + case AlgorithmKey: + return h.algorithm != nil + case RSADKey: + return h.d != nil + case RSADPKey: + return h.dp != nil + case RSADQKey: + return h.dq != nil + case RSAEKey: + return h.e != nil + case KeyIDKey: + return h.keyID != nil + case KeyOpsKey: + return h.keyOps != nil + case KeyUsageKey: + return h.keyUsage != nil + case RSANKey: + return h.n != nil + case RSAPKey: + return h.p != nil + case RSAQKey: + return h.q != nil + case RSAQIKey: + return h.qi != nil + case X509CertChainKey: + return h.x509CertChain != nil + case X509CertThumbprintKey: + return h.x509CertThumbprint != nil + case X509CertThumbprintS256Key: + return h.x509CertThumbprintS256 != nil + case X509URLKey: + return h.x509URL != nil + default: + _, ok := h.privateParams[name] + return ok + } +} + +func (h *rsaPrivateKey) Get(name string, dst any) error { + h.mu.RLock() + defer h.mu.RUnlock() + switch name { + case KeyTypeKey: + if err := blackmagic.AssignIfCompatible(dst, h.KeyType()); err != nil { + return fmt.Errorf(`rsaPrivateKey.Get: failed to assign value for field %q to destination object: %w`, name, err) + } + case AlgorithmKey: + if h.algorithm == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.algorithm)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case RSADKey: + if h.d == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, h.d); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case RSADPKey: + if h.dp == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, h.dp); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case RSADQKey: + if h.dq == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, h.dq); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case RSAEKey: + if h.e == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, h.e); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case KeyIDKey: + if h.keyID == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.keyID)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case KeyOpsKey: + if h.keyOps == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.keyOps)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case KeyUsageKey: + if h.keyUsage == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.keyUsage)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case RSANKey: + if h.n == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, h.n); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case RSAPKey: + if h.p == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, h.p); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case RSAQKey: + if h.q == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, h.q); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case RSAQIKey: + if h.qi == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, h.qi); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case X509CertChainKey: + if h.x509CertChain == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, h.x509CertChain); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case X509CertThumbprintKey: + if h.x509CertThumbprint == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.x509CertThumbprint)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case X509CertThumbprintS256Key: + if h.x509CertThumbprintS256 == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.x509CertThumbprintS256)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case X509URLKey: + if h.x509URL == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.x509URL)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + default: + v, ok := h.privateParams[name] + if !ok { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, v); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + } + return nil +} + +func (h *rsaPrivateKey) Set(name string, value any) error { + h.mu.Lock() + defer h.mu.Unlock() + return h.setNoLock(name, value) +} + +func (h *rsaPrivateKey) setNoLock(name string, value any) error { + switch name { + case "kty": + return nil + case AlgorithmKey: + switch v := value.(type) { + case string, jwa.SignatureAlgorithm, jwa.KeyEncryptionAlgorithm, jwa.ContentEncryptionAlgorithm: + tmp, err := jwa.KeyAlgorithmFrom(v) + if err != nil { + return fmt.Errorf(`invalid algorithm for %q key: %w`, AlgorithmKey, err) + } + h.algorithm = &tmp + default: + return fmt.Errorf(`invalid type for %q key: %T`, AlgorithmKey, value) + } + return nil + case RSADKey: + if v, ok := value.([]byte); ok { + h.d = v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, RSADKey, value) + case RSADPKey: + if v, ok := value.([]byte); ok { + h.dp = v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, RSADPKey, value) + case RSADQKey: + if v, ok := value.([]byte); ok { + h.dq = v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, RSADQKey, value) + case RSAEKey: + if v, ok := value.([]byte); ok { + h.e = v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, RSAEKey, value) + case KeyIDKey: + if v, ok := value.(string); ok { + h.keyID = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, KeyIDKey, value) + case KeyOpsKey: + var acceptor KeyOperationList + if err := acceptor.Accept(value); err != nil { + return fmt.Errorf(`invalid value for %s key: %w`, KeyOpsKey, err) + } + h.keyOps = &acceptor + return nil + case KeyUsageKey: + switch v := value.(type) { + case KeyUsageType: + switch v { + case ForSignature, ForEncryption: + tmp := v.String() + h.keyUsage = &tmp + default: + return fmt.Errorf(`invalid key usage type %s`, v) + } + case string: + h.keyUsage = &v + default: + return fmt.Errorf(`invalid key usage type %s`, v) + } + case RSANKey: + if v, ok := value.([]byte); ok { + h.n = v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, RSANKey, value) + case RSAPKey: + if v, ok := value.([]byte); ok { + h.p = v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, RSAPKey, value) + case RSAQKey: + if v, ok := value.([]byte); ok { + h.q = v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, RSAQKey, value) + case RSAQIKey: + if v, ok := value.([]byte); ok { + h.qi = v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, RSAQIKey, value) + case X509CertChainKey: + if v, ok := value.(*cert.Chain); ok { + h.x509CertChain = v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, X509CertChainKey, value) + case X509CertThumbprintKey: + if v, ok := value.(string); ok { + h.x509CertThumbprint = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, X509CertThumbprintKey, value) + case X509CertThumbprintS256Key: + if v, ok := value.(string); ok { + h.x509CertThumbprintS256 = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, X509CertThumbprintS256Key, value) + case X509URLKey: + if v, ok := value.(string); ok { + h.x509URL = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, X509URLKey, value) + default: + if h.privateParams == nil { + h.privateParams = map[string]any{} + } + h.privateParams[name] = value + } + return nil +} + +func (k *rsaPrivateKey) Remove(key string) error { + k.mu.Lock() + defer k.mu.Unlock() + switch key { + case AlgorithmKey: + k.algorithm = nil + case RSADKey: + k.d = nil + case RSADPKey: + k.dp = nil + case RSADQKey: + k.dq = nil + case RSAEKey: + k.e = nil + case KeyIDKey: + k.keyID = nil + case KeyOpsKey: + k.keyOps = nil + case KeyUsageKey: + k.keyUsage = nil + case RSANKey: + k.n = nil + case RSAPKey: + k.p = nil + case RSAQKey: + k.q = nil + case RSAQIKey: + k.qi = nil + case X509CertChainKey: + k.x509CertChain = nil + case X509CertThumbprintKey: + k.x509CertThumbprint = nil + case X509CertThumbprintS256Key: + k.x509CertThumbprintS256 = nil + case X509URLKey: + k.x509URL = nil + default: + delete(k.privateParams, key) + } + return nil +} + +func (k *rsaPrivateKey) Clone() (Key, error) { + key, err := cloneKey(k) + if err != nil { + return nil, fmt.Errorf(`rsaPrivateKey.Clone: %w`, err) + } + return key, nil +} + +func (k *rsaPrivateKey) DecodeCtx() json.DecodeCtx { + k.mu.RLock() + defer k.mu.RUnlock() + return k.dc +} + +func (k *rsaPrivateKey) SetDecodeCtx(dc json.DecodeCtx) { + k.mu.Lock() + defer k.mu.Unlock() + k.dc = dc +} + +func (h *rsaPrivateKey) UnmarshalJSON(buf []byte) error { + h.mu.Lock() + defer h.mu.Unlock() + h.algorithm = nil + h.d = nil + h.dp = nil + h.dq = nil + h.e = nil + h.keyID = nil + h.keyOps = nil + h.keyUsage = nil + h.n = nil + h.p = nil + h.q = nil + h.qi = nil + h.x509CertChain = nil + h.x509CertThumbprint = nil + h.x509CertThumbprintS256 = nil + h.x509URL = nil + dec := json.NewDecoder(bytes.NewReader(buf)) +LOOP: + for { + tok, err := dec.Token() + if err != nil { + return fmt.Errorf(`error reading token: %w`, err) + } + switch tok := tok.(type) { + case json.Delim: + // Assuming we're doing everything correctly, we should ONLY + // get either tokens.OpenCurlyBracket or tokens.CloseCurlyBracket here. + if tok == tokens.CloseCurlyBracket { // End of object + break LOOP + } else if tok != tokens.OpenCurlyBracket { + return fmt.Errorf(`expected '%c' but got '%c'`, tokens.OpenCurlyBracket, tok) + } + case string: // Objects can only have string keys + switch tok { + case KeyTypeKey: + val, err := json.ReadNextStringToken(dec) + if err != nil { + return fmt.Errorf(`error reading token: %w`, err) + } + if val != jwa.RSA().String() { + return fmt.Errorf(`invalid kty value for RSAPublicKey (%s)`, val) + } + case AlgorithmKey: + var s string + if err := dec.Decode(&s); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, AlgorithmKey, err) + } + alg, err := jwa.KeyAlgorithmFrom(s) + if err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, AlgorithmKey, err) + } + h.algorithm = &alg + case RSADKey: + if err := json.AssignNextBytesToken(&h.d, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, RSADKey, err) + } + case RSADPKey: + if err := json.AssignNextBytesToken(&h.dp, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, RSADPKey, err) + } + case RSADQKey: + if err := json.AssignNextBytesToken(&h.dq, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, RSADQKey, err) + } + case RSAEKey: + if err := json.AssignNextBytesToken(&h.e, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, RSAEKey, err) + } + case KeyIDKey: + if err := json.AssignNextStringToken(&h.keyID, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, KeyIDKey, err) + } + case KeyOpsKey: + var decoded KeyOperationList + if err := dec.Decode(&decoded); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, KeyOpsKey, err) + } + h.keyOps = &decoded + case KeyUsageKey: + if err := json.AssignNextStringToken(&h.keyUsage, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, KeyUsageKey, err) + } + case RSANKey: + if err := json.AssignNextBytesToken(&h.n, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, RSANKey, err) + } + case RSAPKey: + if err := json.AssignNextBytesToken(&h.p, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, RSAPKey, err) + } + case RSAQKey: + if err := json.AssignNextBytesToken(&h.q, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, RSAQKey, err) + } + case RSAQIKey: + if err := json.AssignNextBytesToken(&h.qi, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, RSAQIKey, err) + } + case X509CertChainKey: + var decoded cert.Chain + if err := dec.Decode(&decoded); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, X509CertChainKey, err) + } + h.x509CertChain = &decoded + case X509CertThumbprintKey: + if err := json.AssignNextStringToken(&h.x509CertThumbprint, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, X509CertThumbprintKey, err) + } + case X509CertThumbprintS256Key: + if err := json.AssignNextStringToken(&h.x509CertThumbprintS256, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, X509CertThumbprintS256Key, err) + } + case X509URLKey: + if err := json.AssignNextStringToken(&h.x509URL, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, X509URLKey, err) + } + default: + if dc := h.dc; dc != nil { + if localReg := dc.Registry(); localReg != nil { + decoded, err := localReg.Decode(dec, tok) + if err == nil { + h.setNoLock(tok, decoded) + continue + } + } + } + decoded, err := registry.Decode(dec, tok) + if err == nil { + h.setNoLock(tok, decoded) + continue + } + return fmt.Errorf(`could not decode field %s: %w`, tok, err) + } + default: + return fmt.Errorf(`invalid token %T`, tok) + } + } + if h.d == nil { + return fmt.Errorf(`required field d is missing`) + } + if h.e == nil { + return fmt.Errorf(`required field e is missing`) + } + if h.n == nil { + return fmt.Errorf(`required field n is missing`) + } + return nil +} + +func (h rsaPrivateKey) MarshalJSON() ([]byte, error) { + data := make(map[string]any) + fields := make([]string, 0, 16) + data[KeyTypeKey] = jwa.RSA() + fields = append(fields, KeyTypeKey) + if h.algorithm != nil { + data[AlgorithmKey] = *(h.algorithm) + fields = append(fields, AlgorithmKey) + } + if h.d != nil { + data[RSADKey] = h.d + fields = append(fields, RSADKey) + } + if h.dp != nil { + data[RSADPKey] = h.dp + fields = append(fields, RSADPKey) + } + if h.dq != nil { + data[RSADQKey] = h.dq + fields = append(fields, RSADQKey) + } + if h.e != nil { + data[RSAEKey] = h.e + fields = append(fields, RSAEKey) + } + if h.keyID != nil { + data[KeyIDKey] = *(h.keyID) + fields = append(fields, KeyIDKey) + } + if h.keyOps != nil { + data[KeyOpsKey] = *(h.keyOps) + fields = append(fields, KeyOpsKey) + } + if h.keyUsage != nil { + data[KeyUsageKey] = *(h.keyUsage) + fields = append(fields, KeyUsageKey) + } + if h.n != nil { + data[RSANKey] = h.n + fields = append(fields, RSANKey) + } + if h.p != nil { + data[RSAPKey] = h.p + fields = append(fields, RSAPKey) + } + if h.q != nil { + data[RSAQKey] = h.q + fields = append(fields, RSAQKey) + } + if h.qi != nil { + data[RSAQIKey] = h.qi + fields = append(fields, RSAQIKey) + } + if h.x509CertChain != nil { + data[X509CertChainKey] = h.x509CertChain + fields = append(fields, X509CertChainKey) + } + if h.x509CertThumbprint != nil { + data[X509CertThumbprintKey] = *(h.x509CertThumbprint) + fields = append(fields, X509CertThumbprintKey) + } + if h.x509CertThumbprintS256 != nil { + data[X509CertThumbprintS256Key] = *(h.x509CertThumbprintS256) + fields = append(fields, X509CertThumbprintS256Key) + } + if h.x509URL != nil { + data[X509URLKey] = *(h.x509URL) + fields = append(fields, X509URLKey) + } + for k, v := range h.privateParams { + data[k] = v + fields = append(fields, k) + } + + sort.Strings(fields) + buf := pool.BytesBuffer().Get() + defer pool.BytesBuffer().Put(buf) + buf.WriteByte(tokens.OpenCurlyBracket) + enc := json.NewEncoder(buf) + for i, f := range fields { + if i > 0 { + buf.WriteRune(tokens.Comma) + } + buf.WriteRune(tokens.DoubleQuote) + buf.WriteString(f) + buf.WriteString(`":`) + v := data[f] + switch v := v.(type) { + case []byte: + buf.WriteRune(tokens.DoubleQuote) + buf.WriteString(base64.EncodeToString(v)) + buf.WriteRune(tokens.DoubleQuote) + default: + if err := enc.Encode(v); err != nil { + return nil, fmt.Errorf(`failed to encode value for field %s: %w`, f, err) + } + buf.Truncate(buf.Len() - 1) + } + } + buf.WriteByte(tokens.CloseCurlyBracket) + ret := make([]byte, buf.Len()) + copy(ret, buf.Bytes()) + return ret, nil +} + +func (h *rsaPrivateKey) Keys() []string { + h.mu.RLock() + defer h.mu.RUnlock() + keys := make([]string, 0, 16+len(h.privateParams)) + keys = append(keys, KeyTypeKey) + if h.algorithm != nil { + keys = append(keys, AlgorithmKey) + } + if h.d != nil { + keys = append(keys, RSADKey) + } + if h.dp != nil { + keys = append(keys, RSADPKey) + } + if h.dq != nil { + keys = append(keys, RSADQKey) + } + if h.e != nil { + keys = append(keys, RSAEKey) + } + if h.keyID != nil { + keys = append(keys, KeyIDKey) + } + if h.keyOps != nil { + keys = append(keys, KeyOpsKey) + } + if h.keyUsage != nil { + keys = append(keys, KeyUsageKey) + } + if h.n != nil { + keys = append(keys, RSANKey) + } + if h.p != nil { + keys = append(keys, RSAPKey) + } + if h.q != nil { + keys = append(keys, RSAQKey) + } + if h.qi != nil { + keys = append(keys, RSAQIKey) + } + if h.x509CertChain != nil { + keys = append(keys, X509CertChainKey) + } + if h.x509CertThumbprint != nil { + keys = append(keys, X509CertThumbprintKey) + } + if h.x509CertThumbprintS256 != nil { + keys = append(keys, X509CertThumbprintS256Key) + } + if h.x509URL != nil { + keys = append(keys, X509URLKey) + } + for k := range h.privateParams { + keys = append(keys, k) + } + return keys +} + +var rsaStandardFields KeyFilter + +func init() { + rsaStandardFields = NewFieldNameFilter(KeyTypeKey, KeyUsageKey, KeyOpsKey, AlgorithmKey, KeyIDKey, X509URLKey, X509CertChainKey, X509CertThumbprintKey, X509CertThumbprintS256Key, RSAEKey, RSANKey, RSADKey, RSADPKey, RSADQKey, RSAPKey, RSAQKey, RSAQIKey) +} + +// RSAStandardFieldsFilter returns a KeyFilter that filters out standard RSA fields. +func RSAStandardFieldsFilter() KeyFilter { + return rsaStandardFields +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwk/set.go b/vendor/github.com/lestrrat-go/jwx/v3/jwk/set.go new file mode 100644 index 00000000000..89d8646874a --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwk/set.go @@ -0,0 +1,311 @@ +package jwk + +import ( + "bytes" + "fmt" + "reflect" + "sort" + + "github.com/lestrrat-go/blackmagic" + "github.com/lestrrat-go/jwx/v3/internal/json" + "github.com/lestrrat-go/jwx/v3/internal/pool" + "github.com/lestrrat-go/jwx/v3/internal/tokens" +) + +const keysKey = `keys` // appease linter + +// NewSet creates and empty `jwk.Set` object +func NewSet() Set { + return &set{ + privateParams: make(map[string]any), + } +} + +func (s *set) Set(n string, v any) error { + s.mu.RLock() + defer s.mu.RUnlock() + + if n == keysKey { + vl, ok := v.([]Key) + if !ok { + return fmt.Errorf(`value for field "keys" must be []jwk.Key`) + } + s.keys = vl + return nil + } + + s.privateParams[n] = v + return nil +} + +func (s *set) Get(name string, dst any) error { + s.mu.RLock() + defer s.mu.RUnlock() + + v, ok := s.privateParams[name] + if !ok { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, v); err != nil { + return fmt.Errorf(`failed to assign value to dst: %w`, err) + } + return nil +} + +func (s *set) Key(idx int) (Key, bool) { + s.mu.RLock() + defer s.mu.RUnlock() + + if idx >= 0 && idx < len(s.keys) { + return s.keys[idx], true + } + return nil, false +} + +func (s *set) Len() int { + s.mu.RLock() + defer s.mu.RUnlock() + + return len(s.keys) +} + +// indexNL is Index(), but without the locking +func (s *set) indexNL(key Key) int { + for i, k := range s.keys { + if k == key { + return i + } + } + return -1 +} + +func (s *set) Index(key Key) int { + s.mu.RLock() + defer s.mu.RUnlock() + + return s.indexNL(key) +} + +func (s *set) AddKey(key Key) error { + s.mu.Lock() + defer s.mu.Unlock() + + if reflect.ValueOf(key).IsNil() { + panic("nil key") + } + + if i := s.indexNL(key); i > -1 { + return fmt.Errorf(`(jwk.Set).AddKey: key already exists`) + } + s.keys = append(s.keys, key) + return nil +} + +func (s *set) Remove(name string) error { + s.mu.Lock() + defer s.mu.Unlock() + + delete(s.privateParams, name) + return nil +} + +func (s *set) RemoveKey(key Key) error { + s.mu.Lock() + defer s.mu.Unlock() + + for i, k := range s.keys { + if k == key { + switch i { + case 0: + s.keys = s.keys[1:] + case len(s.keys) - 1: + s.keys = s.keys[:i] + default: + s.keys = append(s.keys[:i], s.keys[i+1:]...) + } + return nil + } + } + return fmt.Errorf(`(jwk.Set).RemoveKey: specified key does not exist in set`) +} + +func (s *set) Clear() error { + s.mu.Lock() + defer s.mu.Unlock() + + s.keys = nil + s.privateParams = make(map[string]any) + return nil +} + +func (s *set) Keys() []string { + ret := make([]string, len(s.privateParams)) + var i int + for k := range s.privateParams { + ret[i] = k + i++ + } + return ret +} + +func (s *set) MarshalJSON() ([]byte, error) { + s.mu.RLock() + defer s.mu.RUnlock() + + buf := pool.BytesBuffer().Get() + defer pool.BytesBuffer().Put(buf) + enc := json.NewEncoder(buf) + + fields := []string{keysKey} + for k := range s.privateParams { + fields = append(fields, k) + } + sort.Strings(fields) + + buf.WriteByte(tokens.OpenCurlyBracket) + for i, field := range fields { + if i > 0 { + buf.WriteByte(tokens.Comma) + } + fmt.Fprintf(buf, `%q:`, field) + if field != keysKey { + if err := enc.Encode(s.privateParams[field]); err != nil { + return nil, fmt.Errorf(`failed to marshal field %q: %w`, field, err) + } + } else { + buf.WriteByte(tokens.OpenSquareBracket) + for j, k := range s.keys { + if j > 0 { + buf.WriteByte(tokens.Comma) + } + if err := enc.Encode(k); err != nil { + return nil, fmt.Errorf(`failed to marshal key #%d: %w`, i, err) + } + } + buf.WriteByte(tokens.CloseSquareBracket) + } + } + buf.WriteByte(tokens.CloseCurlyBracket) + + ret := make([]byte, buf.Len()) + copy(ret, buf.Bytes()) + return ret, nil +} + +func (s *set) UnmarshalJSON(data []byte) error { + s.mu.Lock() + defer s.mu.Unlock() + + s.privateParams = make(map[string]any) + s.keys = nil + + var options []ParseOption + var ignoreParseError bool + if dc := s.dc; dc != nil { + if localReg := dc.Registry(); localReg != nil { + options = append(options, withLocalRegistry(localReg)) + } + ignoreParseError = dc.IgnoreParseError() + } + + var sawKeysField bool + dec := json.NewDecoder(bytes.NewReader(data)) +LOOP: + for { + tok, err := dec.Token() + if err != nil { + return fmt.Errorf(`error reading token: %w`, err) + } + + switch tok := tok.(type) { + case json.Delim: + // Assuming we're doing everything correctly, we should ONLY + // get either tokens.OpenCurlyBracket or tokens.CloseCurlyBracket here. + if tok == tokens.CloseCurlyBracket { // End of object + break LOOP + } else if tok != tokens.OpenCurlyBracket { + return fmt.Errorf(`expected '%c' but got '%c'`, tokens.OpenCurlyBracket, tok) + } + case string: + switch tok { + case "keys": + sawKeysField = true + var list []json.RawMessage + if err := dec.Decode(&list); err != nil { + return fmt.Errorf(`failed to decode "keys": %w`, err) + } + + for i, keysrc := range list { + key, err := ParseKey(keysrc, options...) + if err != nil { + if !ignoreParseError { + return fmt.Errorf(`failed to decode key #%d in "keys": %w`, i, err) + } + continue + } + s.keys = append(s.keys, key) + } + default: + var v any + if err := dec.Decode(&v); err != nil { + return fmt.Errorf(`failed to decode value for key %q: %w`, tok, err) + } + s.privateParams[tok] = v + } + } + } + + // This is really silly, but we can only detect the + // lack of the "keys" field after going through the + // entire object once + // Not checking for len(s.keys) == 0, because it could be + // an empty key set + if !sawKeysField { + key, err := ParseKey(data, options...) + if err != nil { + return fmt.Errorf(`failed to parse sole key in key set`) + } + s.keys = append(s.keys, key) + } + return nil +} + +func (s *set) LookupKeyID(kid string) (Key, bool) { + s.mu.RLock() + defer s.mu.RUnlock() + + for i := range s.Len() { + key, ok := s.Key(i) + if !ok { + return nil, false + } + gotkid, ok := key.KeyID() + if ok && gotkid == kid { + return key, true + } + } + return nil, false +} + +func (s *set) DecodeCtx() DecodeCtx { + s.mu.RLock() + defer s.mu.RUnlock() + return s.dc +} + +func (s *set) SetDecodeCtx(dc DecodeCtx) { + s.mu.Lock() + defer s.mu.Unlock() + s.dc = dc +} + +func (s *set) Clone() (Set, error) { + s2 := &set{} + + s.mu.RLock() + defer s.mu.RUnlock() + + s2.keys = make([]Key, len(s.keys)) + copy(s2.keys, s.keys) + return s2, nil +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwk/symmetric.go b/vendor/github.com/lestrrat-go/jwx/v3/jwk/symmetric.go new file mode 100644 index 00000000000..16427ff86f1 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwk/symmetric.go @@ -0,0 +1,105 @@ +package jwk + +import ( + "crypto" + "fmt" + "reflect" + + "github.com/lestrrat-go/jwx/v3/internal/base64" + "github.com/lestrrat-go/jwx/v3/jwa" +) + +func init() { + RegisterKeyExporter(jwa.OctetSeq(), KeyExportFunc(octetSeqToRaw)) +} + +func (k *symmetricKey) Import(rawKey []byte) error { + k.mu.Lock() + defer k.mu.Unlock() + + if len(rawKey) == 0 { + return fmt.Errorf(`non-empty []byte key required`) + } + + k.octets = rawKey + + return nil +} + +var symmetricConvertibleKeys = []reflect.Type{ + reflect.TypeOf((*SymmetricKey)(nil)).Elem(), +} + +func octetSeqToRaw(key Key, hint any) (any, error) { + extracted, err := extractEmbeddedKey(key, symmetricConvertibleKeys) + if err != nil { + return nil, fmt.Errorf(`failed to extract embedded key: %w`, err) + } + + switch key := extracted.(type) { + case SymmetricKey: + switch hint.(type) { + case *[]byte, *any: + default: + return nil, fmt.Errorf(`invalid destination object type %T for symmetric key: %w`, hint, ContinueError()) + } + + locker, ok := key.(rlocker) + if ok { + locker.rlock() + defer locker.runlock() + } + + ooctets, ok := key.Octets() + if !ok { + return nil, fmt.Errorf(`jwk.SymmetricKey: missing "k" field`) + } + + octets := make([]byte, len(ooctets)) + copy(octets, ooctets) + return octets, nil + default: + return nil, ContinueError() + } +} + +// Thumbprint returns the JWK thumbprint using the indicated +// hashing algorithm, according to RFC 7638 +func (k *symmetricKey) Thumbprint(hash crypto.Hash) ([]byte, error) { + k.mu.RLock() + defer k.mu.RUnlock() + var octets []byte + if err := Export(k, &octets); err != nil { + return nil, fmt.Errorf(`failed to export symmetric key: %w`, err) + } + + h := hash.New() + fmt.Fprint(h, `{"k":"`) + fmt.Fprint(h, base64.EncodeToString(octets)) + fmt.Fprint(h, `","kty":"oct"}`) + return h.Sum(nil), nil +} + +func (k *symmetricKey) PublicKey() (Key, error) { + newKey := newSymmetricKey() + + for _, key := range k.Keys() { + var v any + if err := k.Get(key, &v); err != nil { + return nil, fmt.Errorf(`failed to get field %q: %w`, key, err) + } + + if err := newKey.Set(key, v); err != nil { + return nil, fmt.Errorf(`failed to set field %q: %w`, key, err) + } + } + return newKey, nil +} + +func (k *symmetricKey) Validate() error { + octets, ok := k.Octets() + if !ok || len(octets) == 0 { + return NewKeyValidationError(fmt.Errorf(`jwk.SymmetricKey: missing "k" field`)) + } + return nil +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwk/symmetric_gen.go b/vendor/github.com/lestrrat-go/jwx/v3/jwk/symmetric_gen.go new file mode 100644 index 00000000000..bfd2f8497d4 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwk/symmetric_gen.go @@ -0,0 +1,620 @@ +// Code generated by tools/cmd/genjwk/main.go. DO NOT EDIT. + +package jwk + +import ( + "bytes" + "fmt" + "sort" + "sync" + + "github.com/lestrrat-go/blackmagic" + "github.com/lestrrat-go/jwx/v3/cert" + "github.com/lestrrat-go/jwx/v3/internal/base64" + "github.com/lestrrat-go/jwx/v3/internal/json" + "github.com/lestrrat-go/jwx/v3/internal/pool" + "github.com/lestrrat-go/jwx/v3/internal/tokens" + "github.com/lestrrat-go/jwx/v3/jwa" +) + +const ( + SymmetricOctetsKey = "k" +) + +type SymmetricKey interface { + Key + Octets() ([]byte, bool) +} + +type symmetricKey struct { + algorithm *jwa.KeyAlgorithm // https://tools.ietf.org/html/rfc7517#section-4.4 + keyID *string // https://tools.ietf.org/html/rfc7515#section-4.1.4 + keyOps *KeyOperationList // https://tools.ietf.org/html/rfc7517#section-4.3 + keyUsage *string // https://tools.ietf.org/html/rfc7517#section-4.2 + octets []byte + x509CertChain *cert.Chain // https://tools.ietf.org/html/rfc7515#section-4.1.6 + x509CertThumbprint *string // https://tools.ietf.org/html/rfc7515#section-4.1.7 + x509CertThumbprintS256 *string // https://tools.ietf.org/html/rfc7515#section-4.1.8 + x509URL *string // https://tools.ietf.org/html/rfc7515#section-4.1.5 + privateParams map[string]any + mu *sync.RWMutex + dc json.DecodeCtx +} + +var _ SymmetricKey = &symmetricKey{} +var _ Key = &symmetricKey{} + +func newSymmetricKey() *symmetricKey { + return &symmetricKey{ + mu: &sync.RWMutex{}, + privateParams: make(map[string]any), + } +} + +func (h symmetricKey) KeyType() jwa.KeyType { + return jwa.OctetSeq() +} + +func (h symmetricKey) rlock() { + h.mu.RLock() +} + +func (h symmetricKey) runlock() { + h.mu.RUnlock() +} + +func (h *symmetricKey) Algorithm() (jwa.KeyAlgorithm, bool) { + if h.algorithm != nil { + return *(h.algorithm), true + } + return nil, false +} + +func (h *symmetricKey) KeyID() (string, bool) { + if h.keyID != nil { + return *(h.keyID), true + } + return "", false +} + +func (h *symmetricKey) KeyOps() (KeyOperationList, bool) { + if h.keyOps != nil { + return *(h.keyOps), true + } + return nil, false +} + +func (h *symmetricKey) KeyUsage() (string, bool) { + if h.keyUsage != nil { + return *(h.keyUsage), true + } + return "", false +} + +func (h *symmetricKey) Octets() ([]byte, bool) { + if h.octets != nil { + return h.octets, true + } + return nil, false +} + +func (h *symmetricKey) X509CertChain() (*cert.Chain, bool) { + return h.x509CertChain, true +} + +func (h *symmetricKey) X509CertThumbprint() (string, bool) { + if h.x509CertThumbprint != nil { + return *(h.x509CertThumbprint), true + } + return "", false +} + +func (h *symmetricKey) X509CertThumbprintS256() (string, bool) { + if h.x509CertThumbprintS256 != nil { + return *(h.x509CertThumbprintS256), true + } + return "", false +} + +func (h *symmetricKey) X509URL() (string, bool) { + if h.x509URL != nil { + return *(h.x509URL), true + } + return "", false +} + +func (h *symmetricKey) Has(name string) bool { + h.mu.RLock() + defer h.mu.RUnlock() + switch name { + case KeyTypeKey: + return true + case AlgorithmKey: + return h.algorithm != nil + case KeyIDKey: + return h.keyID != nil + case KeyOpsKey: + return h.keyOps != nil + case KeyUsageKey: + return h.keyUsage != nil + case SymmetricOctetsKey: + return h.octets != nil + case X509CertChainKey: + return h.x509CertChain != nil + case X509CertThumbprintKey: + return h.x509CertThumbprint != nil + case X509CertThumbprintS256Key: + return h.x509CertThumbprintS256 != nil + case X509URLKey: + return h.x509URL != nil + default: + _, ok := h.privateParams[name] + return ok + } +} + +func (h *symmetricKey) Get(name string, dst any) error { + h.mu.RLock() + defer h.mu.RUnlock() + switch name { + case KeyTypeKey: + if err := blackmagic.AssignIfCompatible(dst, h.KeyType()); err != nil { + return fmt.Errorf(`symmetricKey.Get: failed to assign value for field %q to destination object: %w`, name, err) + } + case AlgorithmKey: + if h.algorithm == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.algorithm)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case KeyIDKey: + if h.keyID == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.keyID)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case KeyOpsKey: + if h.keyOps == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.keyOps)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case KeyUsageKey: + if h.keyUsage == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.keyUsage)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case SymmetricOctetsKey: + if h.octets == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, h.octets); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case X509CertChainKey: + if h.x509CertChain == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, h.x509CertChain); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case X509CertThumbprintKey: + if h.x509CertThumbprint == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.x509CertThumbprint)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case X509CertThumbprintS256Key: + if h.x509CertThumbprintS256 == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.x509CertThumbprintS256)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case X509URLKey: + if h.x509URL == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.x509URL)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + default: + v, ok := h.privateParams[name] + if !ok { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, v); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + } + return nil +} + +func (h *symmetricKey) Set(name string, value any) error { + h.mu.Lock() + defer h.mu.Unlock() + return h.setNoLock(name, value) +} + +func (h *symmetricKey) setNoLock(name string, value any) error { + switch name { + case "kty": + return nil + case AlgorithmKey: + switch v := value.(type) { + case string, jwa.SignatureAlgorithm, jwa.KeyEncryptionAlgorithm, jwa.ContentEncryptionAlgorithm: + tmp, err := jwa.KeyAlgorithmFrom(v) + if err != nil { + return fmt.Errorf(`invalid algorithm for %q key: %w`, AlgorithmKey, err) + } + h.algorithm = &tmp + default: + return fmt.Errorf(`invalid type for %q key: %T`, AlgorithmKey, value) + } + return nil + case KeyIDKey: + if v, ok := value.(string); ok { + h.keyID = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, KeyIDKey, value) + case KeyOpsKey: + var acceptor KeyOperationList + if err := acceptor.Accept(value); err != nil { + return fmt.Errorf(`invalid value for %s key: %w`, KeyOpsKey, err) + } + h.keyOps = &acceptor + return nil + case KeyUsageKey: + switch v := value.(type) { + case KeyUsageType: + switch v { + case ForSignature, ForEncryption: + tmp := v.String() + h.keyUsage = &tmp + default: + return fmt.Errorf(`invalid key usage type %s`, v) + } + case string: + h.keyUsage = &v + default: + return fmt.Errorf(`invalid key usage type %s`, v) + } + case SymmetricOctetsKey: + if v, ok := value.([]byte); ok { + h.octets = v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, SymmetricOctetsKey, value) + case X509CertChainKey: + if v, ok := value.(*cert.Chain); ok { + h.x509CertChain = v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, X509CertChainKey, value) + case X509CertThumbprintKey: + if v, ok := value.(string); ok { + h.x509CertThumbprint = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, X509CertThumbprintKey, value) + case X509CertThumbprintS256Key: + if v, ok := value.(string); ok { + h.x509CertThumbprintS256 = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, X509CertThumbprintS256Key, value) + case X509URLKey: + if v, ok := value.(string); ok { + h.x509URL = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, X509URLKey, value) + default: + if h.privateParams == nil { + h.privateParams = map[string]any{} + } + h.privateParams[name] = value + } + return nil +} + +func (k *symmetricKey) Remove(key string) error { + k.mu.Lock() + defer k.mu.Unlock() + switch key { + case AlgorithmKey: + k.algorithm = nil + case KeyIDKey: + k.keyID = nil + case KeyOpsKey: + k.keyOps = nil + case KeyUsageKey: + k.keyUsage = nil + case SymmetricOctetsKey: + k.octets = nil + case X509CertChainKey: + k.x509CertChain = nil + case X509CertThumbprintKey: + k.x509CertThumbprint = nil + case X509CertThumbprintS256Key: + k.x509CertThumbprintS256 = nil + case X509URLKey: + k.x509URL = nil + default: + delete(k.privateParams, key) + } + return nil +} + +func (k *symmetricKey) Clone() (Key, error) { + key, err := cloneKey(k) + if err != nil { + return nil, fmt.Errorf(`symmetricKey.Clone: %w`, err) + } + return key, nil +} + +func (k *symmetricKey) DecodeCtx() json.DecodeCtx { + k.mu.RLock() + defer k.mu.RUnlock() + return k.dc +} + +func (k *symmetricKey) SetDecodeCtx(dc json.DecodeCtx) { + k.mu.Lock() + defer k.mu.Unlock() + k.dc = dc +} + +func (h *symmetricKey) UnmarshalJSON(buf []byte) error { + h.mu.Lock() + defer h.mu.Unlock() + h.algorithm = nil + h.keyID = nil + h.keyOps = nil + h.keyUsage = nil + h.octets = nil + h.x509CertChain = nil + h.x509CertThumbprint = nil + h.x509CertThumbprintS256 = nil + h.x509URL = nil + dec := json.NewDecoder(bytes.NewReader(buf)) +LOOP: + for { + tok, err := dec.Token() + if err != nil { + return fmt.Errorf(`error reading token: %w`, err) + } + switch tok := tok.(type) { + case json.Delim: + // Assuming we're doing everything correctly, we should ONLY + // get either tokens.OpenCurlyBracket or tokens.CloseCurlyBracket here. + if tok == tokens.CloseCurlyBracket { // End of object + break LOOP + } else if tok != tokens.OpenCurlyBracket { + return fmt.Errorf(`expected '%c' but got '%c'`, tokens.OpenCurlyBracket, tok) + } + case string: // Objects can only have string keys + switch tok { + case KeyTypeKey: + val, err := json.ReadNextStringToken(dec) + if err != nil { + return fmt.Errorf(`error reading token: %w`, err) + } + if val != jwa.OctetSeq().String() { + return fmt.Errorf(`invalid kty value for RSAPublicKey (%s)`, val) + } + case AlgorithmKey: + var s string + if err := dec.Decode(&s); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, AlgorithmKey, err) + } + alg, err := jwa.KeyAlgorithmFrom(s) + if err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, AlgorithmKey, err) + } + h.algorithm = &alg + case KeyIDKey: + if err := json.AssignNextStringToken(&h.keyID, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, KeyIDKey, err) + } + case KeyOpsKey: + var decoded KeyOperationList + if err := dec.Decode(&decoded); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, KeyOpsKey, err) + } + h.keyOps = &decoded + case KeyUsageKey: + if err := json.AssignNextStringToken(&h.keyUsage, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, KeyUsageKey, err) + } + case SymmetricOctetsKey: + if err := json.AssignNextBytesToken(&h.octets, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, SymmetricOctetsKey, err) + } + case X509CertChainKey: + var decoded cert.Chain + if err := dec.Decode(&decoded); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, X509CertChainKey, err) + } + h.x509CertChain = &decoded + case X509CertThumbprintKey: + if err := json.AssignNextStringToken(&h.x509CertThumbprint, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, X509CertThumbprintKey, err) + } + case X509CertThumbprintS256Key: + if err := json.AssignNextStringToken(&h.x509CertThumbprintS256, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, X509CertThumbprintS256Key, err) + } + case X509URLKey: + if err := json.AssignNextStringToken(&h.x509URL, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, X509URLKey, err) + } + default: + if dc := h.dc; dc != nil { + if localReg := dc.Registry(); localReg != nil { + decoded, err := localReg.Decode(dec, tok) + if err == nil { + h.setNoLock(tok, decoded) + continue + } + } + } + decoded, err := registry.Decode(dec, tok) + if err == nil { + h.setNoLock(tok, decoded) + continue + } + return fmt.Errorf(`could not decode field %s: %w`, tok, err) + } + default: + return fmt.Errorf(`invalid token %T`, tok) + } + } + if h.octets == nil { + return fmt.Errorf(`required field k is missing`) + } + return nil +} + +func (h symmetricKey) MarshalJSON() ([]byte, error) { + data := make(map[string]any) + fields := make([]string, 0, 9) + data[KeyTypeKey] = jwa.OctetSeq() + fields = append(fields, KeyTypeKey) + if h.algorithm != nil { + data[AlgorithmKey] = *(h.algorithm) + fields = append(fields, AlgorithmKey) + } + if h.keyID != nil { + data[KeyIDKey] = *(h.keyID) + fields = append(fields, KeyIDKey) + } + if h.keyOps != nil { + data[KeyOpsKey] = *(h.keyOps) + fields = append(fields, KeyOpsKey) + } + if h.keyUsage != nil { + data[KeyUsageKey] = *(h.keyUsage) + fields = append(fields, KeyUsageKey) + } + if h.octets != nil { + data[SymmetricOctetsKey] = h.octets + fields = append(fields, SymmetricOctetsKey) + } + if h.x509CertChain != nil { + data[X509CertChainKey] = h.x509CertChain + fields = append(fields, X509CertChainKey) + } + if h.x509CertThumbprint != nil { + data[X509CertThumbprintKey] = *(h.x509CertThumbprint) + fields = append(fields, X509CertThumbprintKey) + } + if h.x509CertThumbprintS256 != nil { + data[X509CertThumbprintS256Key] = *(h.x509CertThumbprintS256) + fields = append(fields, X509CertThumbprintS256Key) + } + if h.x509URL != nil { + data[X509URLKey] = *(h.x509URL) + fields = append(fields, X509URLKey) + } + for k, v := range h.privateParams { + data[k] = v + fields = append(fields, k) + } + + sort.Strings(fields) + buf := pool.BytesBuffer().Get() + defer pool.BytesBuffer().Put(buf) + buf.WriteByte(tokens.OpenCurlyBracket) + enc := json.NewEncoder(buf) + for i, f := range fields { + if i > 0 { + buf.WriteRune(tokens.Comma) + } + buf.WriteRune(tokens.DoubleQuote) + buf.WriteString(f) + buf.WriteString(`":`) + v := data[f] + switch v := v.(type) { + case []byte: + buf.WriteRune(tokens.DoubleQuote) + buf.WriteString(base64.EncodeToString(v)) + buf.WriteRune(tokens.DoubleQuote) + default: + if err := enc.Encode(v); err != nil { + return nil, fmt.Errorf(`failed to encode value for field %s: %w`, f, err) + } + buf.Truncate(buf.Len() - 1) + } + } + buf.WriteByte(tokens.CloseCurlyBracket) + ret := make([]byte, buf.Len()) + copy(ret, buf.Bytes()) + return ret, nil +} + +func (h *symmetricKey) Keys() []string { + h.mu.RLock() + defer h.mu.RUnlock() + keys := make([]string, 0, 9+len(h.privateParams)) + keys = append(keys, KeyTypeKey) + if h.algorithm != nil { + keys = append(keys, AlgorithmKey) + } + if h.keyID != nil { + keys = append(keys, KeyIDKey) + } + if h.keyOps != nil { + keys = append(keys, KeyOpsKey) + } + if h.keyUsage != nil { + keys = append(keys, KeyUsageKey) + } + if h.octets != nil { + keys = append(keys, SymmetricOctetsKey) + } + if h.x509CertChain != nil { + keys = append(keys, X509CertChainKey) + } + if h.x509CertThumbprint != nil { + keys = append(keys, X509CertThumbprintKey) + } + if h.x509CertThumbprintS256 != nil { + keys = append(keys, X509CertThumbprintS256Key) + } + if h.x509URL != nil { + keys = append(keys, X509URLKey) + } + for k := range h.privateParams { + keys = append(keys, k) + } + return keys +} + +var symmetricStandardFields KeyFilter + +func init() { + symmetricStandardFields = NewFieldNameFilter(KeyTypeKey, KeyUsageKey, KeyOpsKey, AlgorithmKey, KeyIDKey, X509URLKey, X509CertChainKey, X509CertThumbprintKey, X509CertThumbprintS256Key, SymmetricOctetsKey) +} + +// SymmetricStandardFieldsFilter returns a KeyFilter that filters out standard Symmetric fields. +func SymmetricStandardFieldsFilter() KeyFilter { + return symmetricStandardFields +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwk/usage.go b/vendor/github.com/lestrrat-go/jwx/v3/jwk/usage.go new file mode 100644 index 00000000000..ed724153b80 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwk/usage.go @@ -0,0 +1,74 @@ +package jwk + +import ( + "fmt" + "sync" + "sync/atomic" +) + +var strictKeyUsage = atomic.Bool{} +var keyUsageNames = map[string]struct{}{} +var muKeyUsageName sync.RWMutex + +// RegisterKeyUsage registers a possible value that can be used for KeyUsageType. +// Normally, key usage (or the "use" field in a JWK) is either "sig" or "enc", +// but other values may be used. +// +// While this module only works with "sig" and "enc", it is possible that +// systems choose to use other values. This function allows users to register +// new values to be accepted as valid key usage types. Values are case sensitive. +// +// Furthermore, the check against registered values can be completely turned off +// by setting the global option `jwk.WithStrictKeyUsage(false)`. +func RegisterKeyUsage(v string) { + muKeyUsageName.Lock() + defer muKeyUsageName.Unlock() + keyUsageNames[v] = struct{}{} +} + +func UnregisterKeyUsage(v string) { + muKeyUsageName.Lock() + defer muKeyUsageName.Unlock() + delete(keyUsageNames, v) +} + +func init() { + strictKeyUsage.Store(true) + RegisterKeyUsage("sig") + RegisterKeyUsage("enc") +} + +func isValidUsage(v string) bool { + // This function can return true if strictKeyUsage is false + if !strictKeyUsage.Load() { + return true + } + + muKeyUsageName.RLock() + defer muKeyUsageName.RUnlock() + _, ok := keyUsageNames[v] + return ok +} + +func (k KeyUsageType) String() string { + return string(k) +} + +func (k *KeyUsageType) Accept(v any) error { + switch v := v.(type) { + case KeyUsageType: + if !isValidUsage(v.String()) { + return fmt.Errorf("invalid key usage type: %q", v) + } + *k = v + return nil + case string: + if !isValidUsage(v) { + return fmt.Errorf("invalid key usage type: %q", v) + } + *k = KeyUsageType(v) + return nil + } + + return fmt.Errorf("invalid Go type for key usage type: %T", v) +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwk/whitelist.go b/vendor/github.com/lestrrat-go/jwx/v3/jwk/whitelist.go new file mode 100644 index 00000000000..0b0df701aeb --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwk/whitelist.go @@ -0,0 +1,38 @@ +package jwk + +import "github.com/lestrrat-go/httprc/v3" + +type Whitelist = httprc.Whitelist +type WhitelistFunc = httprc.WhitelistFunc + +// InsecureWhitelist is an alias to httprc.InsecureWhitelist. Use +// functions in the `httprc` package to interact with this type. +type InsecureWhitelist = httprc.InsecureWhitelist + +func NewInsecureWhitelist() InsecureWhitelist { + return httprc.NewInsecureWhitelist() +} + +// BlockAllWhitelist is an alias to httprc.BlockAllWhitelist. Use +// functions in the `httprc` package to interact with this type. +type BlockAllWhitelist = httprc.BlockAllWhitelist + +func NewBlockAllWhitelist() BlockAllWhitelist { + return httprc.NewBlockAllWhitelist() +} + +// RegexpWhitelist is an alias to httprc.RegexpWhitelist. Use +// functions in the `httprc` package to interact with this type. +type RegexpWhitelist = httprc.RegexpWhitelist + +func NewRegexpWhitelist() *RegexpWhitelist { + return httprc.NewRegexpWhitelist() +} + +// MapWhitelist is an alias to httprc.MapWhitelist. Use +// functions in the `httprc` package to interact with this type. +type MapWhitelist = httprc.MapWhitelist + +func NewMapWhitelist() MapWhitelist { + return httprc.NewMapWhitelist() +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwk/x509.go b/vendor/github.com/lestrrat-go/jwx/v3/jwk/x509.go new file mode 100644 index 00000000000..c0a7c4c4d94 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwk/x509.go @@ -0,0 +1,249 @@ +package jwk + +import ( + "crypto/ecdsa" + "crypto/ed25519" + "crypto/rsa" + "crypto/x509" + "encoding/pem" + "errors" + "fmt" + "sync" + + "github.com/lestrrat-go/blackmagic" + "github.com/lestrrat-go/jwx/v3/jwk/jwkbb" +) + +// PEMDecoder is an interface to describe an object that can decode +// a key from PEM encoded ASN.1 DER format. +// +// A PEMDecoder can be specified as an option to `jwk.Parse()` or `jwk.ParseKey()` +// along with the `jwk.WithPEM()` option. +type PEMDecoder interface { + Decode([]byte) (any, []byte, error) +} + +// PEMEncoder is an interface to describe an object that can encode +// a key into PEM encoded ASN.1 DER format. +// +// `jwk.Key` instances do not implement a way to encode themselves into +// PEM format. Normally you can just use `jwk.EncodePEM()` to do this, but +// this interface allows you to generalize the encoding process by +// abstracting the `jwk.EncodePEM()` function using `jwk.PEMEncodeFunc` +// along with alternate implementations, should you need them. +type PEMEncoder interface { + Encode(any) (string, []byte, error) +} + +type PEMEncodeFunc func(any) (string, []byte, error) + +func (f PEMEncodeFunc) Encode(v any) (string, []byte, error) { + return f(v) +} + +func encodeX509(v any) (string, []byte, error) { + // we can't import jwk, so just use the interface + if key, ok := v.(Key); ok { + var raw any + if err := Export(key, &raw); err != nil { + return "", nil, fmt.Errorf(`failed to get raw key out of %T: %w`, key, err) + } + + v = raw + } + + // Try to convert it into a certificate + switch v := v.(type) { + case *rsa.PrivateKey: + return pmRSAPrivateKey, x509.MarshalPKCS1PrivateKey(v), nil + case *ecdsa.PrivateKey: + marshaled, err := x509.MarshalECPrivateKey(v) + if err != nil { + return "", nil, err + } + return pmECPrivateKey, marshaled, nil + case ed25519.PrivateKey: + marshaled, err := x509.MarshalPKCS8PrivateKey(v) + if err != nil { + return "", nil, err + } + return pmPrivateKey, marshaled, nil + case *rsa.PublicKey, *ecdsa.PublicKey, ed25519.PublicKey: + marshaled, err := x509.MarshalPKIXPublicKey(v) + if err != nil { + return "", nil, err + } + return pmPublicKey, marshaled, nil + default: + return "", nil, fmt.Errorf(`unsupported type %T for ASN.1 DER encoding`, v) + } +} + +// EncodePEM encodes the key into a PEM encoded ASN.1 DER format. +// The key can be a jwk.Key or a raw key instance, but it must be one of +// the types supported by `x509` package. +// +// Internally, it uses the same routine as `jwk.EncodeX509()`, and therefore +// the same caveats apply +func EncodePEM(v any) ([]byte, error) { + typ, marshaled, err := encodeX509(v) + if err != nil { + return nil, fmt.Errorf(`failed to encode key in x509: %w`, err) + } + + block := &pem.Block{ + Type: typ, + Bytes: marshaled, + } + return pem.EncodeToMemory(block), nil +} + +const ( + pmPrivateKey = `PRIVATE KEY` + pmPublicKey = `PUBLIC KEY` + pmECPrivateKey = `EC PRIVATE KEY` + pmRSAPublicKey = `RSA PUBLIC KEY` + pmRSAPrivateKey = `RSA PRIVATE KEY` +) + +// NewPEMDecoder returns a PEMDecoder that decodes keys in PEM encoded ASN.1 DER format. +// You can use it as argument to `jwk.WithPEMDecoder()` option. +// +// The use of this function is planned to be deprecated. The plan is to replace the +// `jwk.WithPEMDecoder()` option with globally available custom X509 decoders which +// can be registered via `jwk.RegisterX509Decoder()` function. +func NewPEMDecoder() PEMDecoder { + return pemDecoder{} +} + +type pemDecoder struct{} + +// DecodePEM decodes a key in PEM encoded ASN.1 DER format. +// and returns a raw key. +func (pemDecoder) Decode(src []byte) (any, []byte, error) { + block, rest := pem.Decode(src) + if block == nil { + return nil, rest, fmt.Errorf(`failed to decode PEM data`) + } + var ret any + if err := jwkbb.DecodeX509(&ret, block); err != nil { + return nil, rest, err + } + return ret, rest, nil +} + +// X509Decoder is an interface that describes an object that can decode +// a PEM encoded ASN.1 DER format into a specific type of key. +// +// This interface is experimental, and may change in the future. +type X509Decoder interface { + // DecodeX509 decodes the given PEM block into the destination object. + // The destination object must be a pointer to a type that can hold the + // decoded key, such as *rsa.PrivateKey, *ecdsa.PrivateKey, etc. + DecodeX509(dst any, block *pem.Block) error +} + +// X509DecodeFunc is a function type that implements the X509Decoder interface. +// It allows you to create a custom X509Decoder by providing a function +// that takes a destination and a PEM block, and returns an error if the decoding fails. +// +// This interface is experimental, and may change in the future. +type X509DecodeFunc func(dst any, block *pem.Block) error + +func (f X509DecodeFunc) DecodeX509(dst any, block *pem.Block) error { + return f(dst, block) +} + +var muX509Decoders sync.Mutex +var x509Decoders = map[any]int{} +var x509DecoderList = []X509Decoder{} + +type identDefaultX509Decoder struct{} + +func init() { + RegisterX509Decoder(identDefaultX509Decoder{}, X509DecodeFunc(jwkbb.DecodeX509)) +} + +// RegisterX509Decoder registers a new X509Decoder that can decode PEM encoded ASN.1 DER format. +// Because the decoder could be non-comparable, you must provide an identifier that can be used +// as a map key to identify the decoder. +// +// This function is experimental, and may change in the future. +func RegisterX509Decoder(ident any, decoder X509Decoder) { + if decoder == nil { + panic(`jwk.RegisterX509Decoder: decoder cannot be nil`) + } + + muX509Decoders.Lock() + defer muX509Decoders.Unlock() + if _, ok := x509Decoders[ident]; ok { + return // already registered + } + + x509Decoders[ident] = len(x509DecoderList) + x509DecoderList = append(x509DecoderList, decoder) +} + +// UnregisterX509Decoder unregisters the X509Decoder identified by the given identifier. +// If the identifier is not registered, it does nothing. +// +// This function is experimental, and may change in the future. +func UnregisterX509Decoder(ident any) { + muX509Decoders.Lock() + defer muX509Decoders.Unlock() + idx, ok := x509Decoders[ident] + if !ok { + return // not registered + } + + delete(x509Decoders, ident) + + l := len(x509DecoderList) + switch idx { + case l - 1: + // if the last element, just truncate the slice + x509DecoderList = x509DecoderList[:l-1] + case 0: + // if the first element, just shift the slice + x509DecoderList = x509DecoderList[1:] + default: + // if the element is in the middle, remove it by slicing + // and appending the two slices together + x509DecoderList = append(x509DecoderList[:idx], x509DecoderList[idx+1:]...) + } +} + +// decodeX509 decodes a PEM encoded ASN.1 DER format into the given destination. +// It tries all registered X509 decoders until one of them succeeds. +// If no decoder can handle the PEM block, it returns an error. +func decodeX509(dst any, src []byte) error { + block, _ := pem.Decode(src) + if block == nil { + return fmt.Errorf(`failed to decode PEM data`) + } + + var errs []error + for _, d := range x509DecoderList { + if err := d.DecodeX509(dst, block); err != nil { + errs = append(errs, err) + continue + } + // successfully decoded + return nil + } + + return fmt.Errorf(`failed to decode X509 data using any of the decoders: %w`, errors.Join(errs...)) +} + +func decodeX509WithPEMDEcoder(dst any, src []byte, decoder PEMDecoder) error { + ret, _, err := decoder.Decode(src) + if err != nil { + return fmt.Errorf(`failed to decode PEM data: %w`, err) + } + + if err := blackmagic.AssignIfCompatible(dst, ret); err != nil { + return fmt.Errorf(`failed to assign decoded key to destination: %w`, err) + } + + return nil +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jws/BUILD.bazel b/vendor/github.com/lestrrat-go/jwx/v3/jws/BUILD.bazel new file mode 100644 index 00000000000..920d3f87b11 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jws/BUILD.bazel @@ -0,0 +1,76 @@ +load("@rules_go//go:def.bzl", "go_library", "go_test") + +go_library( + name = "jws", + srcs = [ + "errors.go", + "filter.go", + "headers.go", + "headers_gen.go", + "interface.go", + "io.go", + "jws.go", + "key_provider.go", + "legacy.go", + "message.go", + "options.go", + "options_gen.go", + "signer.go", + "sign_context.go", + "signature_builder.go", + "verifier.go", + "verify_context.go", + ], + importpath = "github.com/lestrrat-go/jwx/v3/jws", + visibility = ["//visibility:public"], + deps = [ + "//cert", + "//internal/base64", + "//internal/ecutil", + "//internal/json", + "//internal/jwxio", + "//internal/tokens", + "//internal/keyconv", + "//internal/pool", + "//jwa", + "//jwk", + "//jws/internal/keytype", + "//jws/jwsbb", + "//jws/legacy", + "//transform", + "@com_github_lestrrat_go_blackmagic//:blackmagic", + "@com_github_lestrrat_go_option_v2//:option", + ], +) + +go_test( + name = "jws_test", + srcs = [ + "es256k_test.go", + "filter_test.go", + "headers_test.go", + "jws_test.go", + "message_test.go", + "options_gen_test.go", + "signer_test.go", + ], + embed = [":jws"], + deps = [ + "//cert", + "//internal/base64", + "//internal/ecutil", + "//internal/json", + "//internal/jwxtest", + "//jwa", + "//jwk", + "//jwt", + "@com_github_lestrrat_go_httprc_v3//:httprc", + "@com_github_stretchr_testify//require", + ], +) + +alias( + name = "go_default_library", + actual = ":jws", + visibility = ["//visibility:public"], +) diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jws/README.md b/vendor/github.com/lestrrat-go/jwx/v3/jws/README.md new file mode 100644 index 00000000000..29ca7218e48 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jws/README.md @@ -0,0 +1,111 @@ +# JWS [![Go Reference](https://pkg.go.dev/badge/github.com/lestrrat-go/jwx/v3/jws.svg)](https://pkg.go.dev/github.com/lestrrat-go/jwx/v3/jws) + +Package jws implements JWS as described in [RFC7515](https://tools.ietf.org/html/rfc7515) and [RFC7797](https://tools.ietf.org/html/rfc7797) + +* Parse and generate compact or JSON serializations +* Sign and verify arbitrary payload +* Use any of the keys supported in [github.com/lestrrat-go/jwx/v3/jwk](../jwk) +* Add arbitrary fields in the JWS object +* Ability to add/replace existing signature methods +* Respect "b64" settings for RFC7797 + +How-to style documentation can be found in the [docs directory](../docs). + +Examples are located in the examples directory ([jws_example_test.go](../examples/jws_example_test.go)) + +Supported signature algorithms: + +| Algorithm | Supported? | Constant in [jwa](../jwa) | +|:----------------------------------------|:-----------|:-------------------------| +| HMAC using SHA-256 | YES | jwa.HS256 | +| HMAC using SHA-384 | YES | jwa.HS384 | +| HMAC using SHA-512 | YES | jwa.HS512 | +| RSASSA-PKCS-v1.5 using SHA-256 | YES | jwa.RS256 | +| RSASSA-PKCS-v1.5 using SHA-384 | YES | jwa.RS384 | +| RSASSA-PKCS-v1.5 using SHA-512 | YES | jwa.RS512 | +| ECDSA using P-256 and SHA-256 | YES | jwa.ES256 | +| ECDSA using P-384 and SHA-384 | YES | jwa.ES384 | +| ECDSA using P-521 and SHA-512 | YES | jwa.ES512 | +| ECDSA using secp256k1 and SHA-256 (2) | YES | jwa.ES256K | +| RSASSA-PSS using SHA256 and MGF1-SHA256 | YES | jwa.PS256 | +| RSASSA-PSS using SHA384 and MGF1-SHA384 | YES | jwa.PS384 | +| RSASSA-PSS using SHA512 and MGF1-SHA512 | YES | jwa.PS512 | +| EdDSA (1) | YES | jwa.EdDSA | + +* Note 1: Experimental +* Note 2: Experimental, and must be toggled using `-tags jwx_es256k` build tag + +# SYNOPSIS + +## Sign and verify arbitrary data + +```go +import( + "crypto/rand" + "crypto/rsa" + "log" + + "github.com/lestrrat-go/jwx/v3/jwa" + "github.com/lestrrat-go/jwx/v3/jws" +) + +func main() { + privkey, err := rsa.GenerateKey(rand.Reader, 2048) + if err != nil { + log.Printf("failed to generate private key: %s", err) + return + } + + buf, err := jws.Sign([]byte("Lorem ipsum"), jws.WithKey(jwa.RS256, privkey)) + if err != nil { + log.Printf("failed to created JWS message: %s", err) + return + } + + // When you receive a JWS message, you can verify the signature + // and grab the payload sent in the message in one go: + verified, err := jws.Verify(buf, jws.WithKey(jwa.RS256, &privkey.PublicKey)) + if err != nil { + log.Printf("failed to verify message: %s", err) + return + } + + log.Printf("signed message verified! -> %s", verified) +} +``` + +## Programmatically manipulate `jws.Message` + +```go +func ExampleMessage() { + // initialization for the following variables have been omitted. + // please see jws_example_test.go for details + var decodedPayload, decodedSig1, decodedSig2 []byte + var public1, protected1, public2, protected2 jws.Header + + // Construct a message. DO NOT use values that are base64 encoded + m := jws.NewMessage(). + SetPayload(decodedPayload). + AppendSignature( + jws.NewSignature(). + SetSignature(decodedSig1). + SetProtectedHeaders(public1). + SetPublicHeaders(protected1), + ). + AppendSignature( + jws.NewSignature(). + SetSignature(decodedSig2). + SetProtectedHeaders(public2). + SetPublicHeaders(protected2), + ) + + buf, err := json.MarshalIndent(m, "", " ") + if err != nil { + fmt.Printf("%s\n", err) + return + } + + _ = buf +} +``` + diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jws/errors.go b/vendor/github.com/lestrrat-go/jwx/v3/jws/errors.go new file mode 100644 index 00000000000..d5e1762a6a7 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jws/errors.go @@ -0,0 +1,112 @@ +package jws + +import ( + "fmt" +) + +type signError struct { + error +} + +var errDefaultSignError = signerr(`unknown error`) + +// SignError returns an error that can be passed to `errors.Is` to check if the error is a sign error. +func SignError() error { + return errDefaultSignError +} + +func (e signError) Unwrap() error { + return e.error +} + +func (signError) Is(err error) bool { + _, ok := err.(signError) + return ok +} + +func signerr(f string, args ...any) error { + return signError{fmt.Errorf(`jws.Sign: `+f, args...)} +} + +// This error is returned when jws.Verify fails, but note that there's another type of +// message that can be returned by jws.Verify, which is `errVerification`. +type verifyError struct { + error +} + +var errDefaultVerifyError = verifyerr(`unknown error`) + +// VerifyError returns an error that can be passed to `errors.Is` to check if the error is a verify error. +func VerifyError() error { + return errDefaultVerifyError +} + +func (e verifyError) Unwrap() error { + return e.error +} + +func (verifyError) Is(err error) bool { + _, ok := err.(verifyError) + return ok +} + +func verifyerr(f string, args ...any) error { + return verifyError{fmt.Errorf(`jws.Verify: `+f, args...)} +} + +// verificationError is returned when the actual _verification_ of the key/payload fails. +type verificationError struct { + error +} + +var errDefaultVerificationError = verificationError{fmt.Errorf(`unknown verification error`)} + +// VerificationError returns an error that can be passed to `errors.Is` to check if the error is a verification error. +func VerificationError() error { + return errDefaultVerificationError +} + +func (e verificationError) Unwrap() error { + return e.error +} + +func (verificationError) Is(err error) bool { + _, ok := err.(verificationError) + return ok +} + +type parseError struct { + error +} + +var errDefaultParseError = parseerr(`unknown error`) + +// ParseError returns an error that can be passed to `errors.Is` to check if the error is a parse error. +func ParseError() error { + return errDefaultParseError +} + +func (e parseError) Unwrap() error { + return e.error +} + +func (parseError) Is(err error) bool { + _, ok := err.(parseError) + return ok +} + +func bparseerr(prefix string, f string, args ...any) error { + return parseError{fmt.Errorf(prefix+": "+f, args...)} +} + +func parseerr(f string, args ...any) error { + return bparseerr(`jws.Parse`, f, args...) +} + +func sparseerr(f string, args ...any) error { + return bparseerr(`jws.ParseString`, f, args...) +} + +func rparseerr(f string, args ...any) error { + return bparseerr(`jws.ParseReader`, f, args...) +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jws/es256k.go b/vendor/github.com/lestrrat-go/jwx/v3/jws/es256k.go new file mode 100644 index 00000000000..3b68c461440 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jws/es256k.go @@ -0,0 +1,13 @@ +//go:build jwx_es256k +// +build jwx_es256k + +package jws + +import ( + "github.com/lestrrat-go/jwx/v3/jwa" +) + +func init() { + // Register ES256K to EC algorithm family + addAlgorithmForKeyType(jwa.EC(), jwa.ES256K()) +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jws/filter.go b/vendor/github.com/lestrrat-go/jwx/v3/jws/filter.go new file mode 100644 index 00000000000..9351ab870bd --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jws/filter.go @@ -0,0 +1,36 @@ +package jws + +import ( + "github.com/lestrrat-go/jwx/v3/transform" +) + +// HeaderFilter is an interface that allows users to filter JWS header fields. +// It provides two methods: Filter and Reject; Filter returns a new header with only +// the fields that match the filter criteria, while Reject returns a new header with +// only the fields that DO NOT match the filter. +// +// EXPERIMENTAL: This API is experimental and its interface and behavior is +// subject to change in future releases. This API is not subject to semver +// compatibility guarantees. +type HeaderFilter interface { + Filter(header Headers) (Headers, error) + Reject(header Headers) (Headers, error) +} + +// StandardHeadersFilter returns a HeaderFilter that filters out standard JWS header fields. +// +// You can use this filter to create headers that either only have standard fields +// or only custom fields. +// +// If you need to configure the filter more precisely, consider +// using the HeaderNameFilter directly. +func StandardHeadersFilter() HeaderFilter { + return stdHeadersFilter +} + +var stdHeadersFilter = NewHeaderNameFilter(stdHeaderNames...) + +// NewHeaderNameFilter creates a new HeaderNameFilter with the specified field names. +func NewHeaderNameFilter(names ...string) HeaderFilter { + return transform.NewNameBasedFilter[Headers](names...) +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jws/headers.go b/vendor/github.com/lestrrat-go/jwx/v3/jws/headers.go new file mode 100644 index 00000000000..45f8e8959e7 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jws/headers.go @@ -0,0 +1,52 @@ +package jws + +import ( + "fmt" +) + +func (h *stdHeaders) Copy(dst Headers) error { + for _, k := range h.Keys() { + var v any + if err := h.Get(k, &v); err != nil { + return fmt.Errorf(`failed to get header %q: %w`, k, err) + } + if err := dst.Set(k, v); err != nil { + return fmt.Errorf(`failed to set header %q: %w`, k, err) + } + } + return nil +} + +// mergeHeaders merges two headers, and works even if the first Header +// object is nil. This is not exported because ATM it felt like this +// function is not frequently used, and MergeHeaders seemed a clunky name +func mergeHeaders(h1, h2 Headers) (Headers, error) { + h3 := NewHeaders() + + if h1 != nil { + if err := h1.Copy(h3); err != nil { + return nil, fmt.Errorf(`failed to copy headers from first Header: %w`, err) + } + } + + if h2 != nil { + if err := h2.Copy(h3); err != nil { + return nil, fmt.Errorf(`failed to copy headers from second Header: %w`, err) + } + } + + return h3, nil +} + +func (h *stdHeaders) Merge(h2 Headers) (Headers, error) { + return mergeHeaders(h, h2) +} + +// Clone creates a deep copy of the header +func (h *stdHeaders) Clone() (Headers, error) { + dst := NewHeaders() + if err := h.Copy(dst); err != nil { + return nil, fmt.Errorf(`failed to copy header: %w`, err) + } + return dst, nil +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jws/headers_gen.go b/vendor/github.com/lestrrat-go/jwx/v3/jws/headers_gen.go new file mode 100644 index 00000000000..8465eda2b14 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jws/headers_gen.go @@ -0,0 +1,704 @@ +// Code generated by tools/cmd/genjws/main.go. DO NOT EDIT. + +package jws + +import ( + "bytes" + "fmt" + "sort" + "sync" + + "github.com/lestrrat-go/blackmagic" + "github.com/lestrrat-go/jwx/v3/cert" + "github.com/lestrrat-go/jwx/v3/internal/base64" + "github.com/lestrrat-go/jwx/v3/internal/json" + "github.com/lestrrat-go/jwx/v3/internal/pool" + "github.com/lestrrat-go/jwx/v3/internal/tokens" + "github.com/lestrrat-go/jwx/v3/jwa" + "github.com/lestrrat-go/jwx/v3/jwk" +) + +const ( + AlgorithmKey = "alg" + ContentTypeKey = "cty" + CriticalKey = "crit" + JWKKey = "jwk" + JWKSetURLKey = "jku" + KeyIDKey = "kid" + TypeKey = "typ" + X509CertChainKey = "x5c" + X509CertThumbprintKey = "x5t" + X509CertThumbprintS256Key = "x5t#S256" + X509URLKey = "x5u" +) + +// Headers describe a standard JWS Header set. It is part of the JWS message +// and is used to represet both Public or Protected headers, which in turn +// can be found in each Signature object. If you are not sure how this works, +// it is strongly recommended that you read RFC7515, especially the section +// that describes the full JSON serialization format of JWS messages. +// +// In most cases, you likely want to use the protected headers, as this is part of the signed content. +type Headers interface { + Algorithm() (jwa.SignatureAlgorithm, bool) + ContentType() (string, bool) + Critical() ([]string, bool) + JWK() (jwk.Key, bool) + JWKSetURL() (string, bool) + KeyID() (string, bool) + Type() (string, bool) + X509CertChain() (*cert.Chain, bool) + X509CertThumbprint() (string, bool) + X509CertThumbprintS256() (string, bool) + X509URL() (string, bool) + Copy(Headers) error + Merge(Headers) (Headers, error) + Clone() (Headers, error) + // Get is used to extract the value of any field, including non-standard fields, out of the header. + // + // The first argument is the name of the field. The second argument is a pointer + // to a variable that will receive the value of the field. The method returns + // an error if the field does not exist, or if the value cannot be assigned to + // the destination variable. Note that a field is considered to "exist" even if + // the value is empty-ish (e.g. 0, false, ""), as long as it is explicitly set. + Get(string, any) error + Set(string, any) error + Remove(string) error + // Has returns true if the specified header has a value, even if + // the value is empty-ish (e.g. 0, false, "") as long as it has been + // explicitly set. + Has(string) bool + Keys() []string +} + +// stdHeaderNames is a list of all standard header names defined in the JWS specification. +var stdHeaderNames = []string{AlgorithmKey, ContentTypeKey, CriticalKey, JWKKey, JWKSetURLKey, KeyIDKey, TypeKey, X509CertChainKey, X509CertThumbprintKey, X509CertThumbprintS256Key, X509URLKey} + +type stdHeaders struct { + algorithm *jwa.SignatureAlgorithm // https://tools.ietf.org/html/rfc7515#section-4.1.1 + contentType *string // https://tools.ietf.org/html/rfc7515#section-4.1.10 + critical []string // https://tools.ietf.org/html/rfc7515#section-4.1.11 + jwk jwk.Key // https://tools.ietf.org/html/rfc7515#section-4.1.3 + jwkSetURL *string // https://tools.ietf.org/html/rfc7515#section-4.1.2 + keyID *string // https://tools.ietf.org/html/rfc7515#section-4.1.4 + typ *string // https://tools.ietf.org/html/rfc7515#section-4.1.9 + x509CertChain *cert.Chain // https://tools.ietf.org/html/rfc7515#section-4.1.6 + x509CertThumbprint *string // https://tools.ietf.org/html/rfc7515#section-4.1.7 + x509CertThumbprintS256 *string // https://tools.ietf.org/html/rfc7515#section-4.1.8 + x509URL *string // https://tools.ietf.org/html/rfc7515#section-4.1.5 + privateParams map[string]any + mu *sync.RWMutex + dc DecodeCtx + raw []byte // stores the raw version of the header so it can be used later +} + +func NewHeaders() Headers { + return &stdHeaders{ + mu: &sync.RWMutex{}, + } +} + +func (h *stdHeaders) Algorithm() (jwa.SignatureAlgorithm, bool) { + h.mu.RLock() + defer h.mu.RUnlock() + if h.algorithm == nil { + return jwa.EmptySignatureAlgorithm(), false + } + return *(h.algorithm), true +} + +func (h *stdHeaders) ContentType() (string, bool) { + h.mu.RLock() + defer h.mu.RUnlock() + if h.contentType == nil { + return "", false + } + return *(h.contentType), true +} + +func (h *stdHeaders) Critical() ([]string, bool) { + h.mu.RLock() + defer h.mu.RUnlock() + return h.critical, true +} + +func (h *stdHeaders) JWK() (jwk.Key, bool) { + h.mu.RLock() + defer h.mu.RUnlock() + return h.jwk, true +} + +func (h *stdHeaders) JWKSetURL() (string, bool) { + h.mu.RLock() + defer h.mu.RUnlock() + if h.jwkSetURL == nil { + return "", false + } + return *(h.jwkSetURL), true +} + +func (h *stdHeaders) KeyID() (string, bool) { + h.mu.RLock() + defer h.mu.RUnlock() + if h.keyID == nil { + return "", false + } + return *(h.keyID), true +} + +func (h *stdHeaders) Type() (string, bool) { + h.mu.RLock() + defer h.mu.RUnlock() + if h.typ == nil { + return "", false + } + return *(h.typ), true +} + +func (h *stdHeaders) X509CertChain() (*cert.Chain, bool) { + h.mu.RLock() + defer h.mu.RUnlock() + return h.x509CertChain, true +} + +func (h *stdHeaders) X509CertThumbprint() (string, bool) { + h.mu.RLock() + defer h.mu.RUnlock() + if h.x509CertThumbprint == nil { + return "", false + } + return *(h.x509CertThumbprint), true +} + +func (h *stdHeaders) X509CertThumbprintS256() (string, bool) { + h.mu.RLock() + defer h.mu.RUnlock() + if h.x509CertThumbprintS256 == nil { + return "", false + } + return *(h.x509CertThumbprintS256), true +} + +func (h *stdHeaders) X509URL() (string, bool) { + h.mu.RLock() + defer h.mu.RUnlock() + if h.x509URL == nil { + return "", false + } + return *(h.x509URL), true +} + +func (h *stdHeaders) clear() { + h.algorithm = nil + h.contentType = nil + h.critical = nil + h.jwk = nil + h.jwkSetURL = nil + h.keyID = nil + h.typ = nil + h.x509CertChain = nil + h.x509CertThumbprint = nil + h.x509CertThumbprintS256 = nil + h.x509URL = nil + h.privateParams = nil + h.raw = nil +} + +func (h *stdHeaders) DecodeCtx() DecodeCtx { + h.mu.RLock() + defer h.mu.RUnlock() + return h.dc +} + +func (h *stdHeaders) SetDecodeCtx(dc DecodeCtx) { + h.mu.Lock() + defer h.mu.Unlock() + h.dc = dc +} + +func (h *stdHeaders) rawBuffer() []byte { + return h.raw +} + +func (h *stdHeaders) PrivateParams() map[string]any { + h.mu.RLock() + defer h.mu.RUnlock() + return h.privateParams +} + +func (h *stdHeaders) Has(name string) bool { + h.mu.RLock() + defer h.mu.RUnlock() + switch name { + case AlgorithmKey: + return h.algorithm != nil + case ContentTypeKey: + return h.contentType != nil + case CriticalKey: + return h.critical != nil + case JWKKey: + return h.jwk != nil + case JWKSetURLKey: + return h.jwkSetURL != nil + case KeyIDKey: + return h.keyID != nil + case TypeKey: + return h.typ != nil + case X509CertChainKey: + return h.x509CertChain != nil + case X509CertThumbprintKey: + return h.x509CertThumbprint != nil + case X509CertThumbprintS256Key: + return h.x509CertThumbprintS256 != nil + case X509URLKey: + return h.x509URL != nil + default: + _, ok := h.privateParams[name] + return ok + } +} + +func (h *stdHeaders) Get(name string, dst any) error { + h.mu.RLock() + defer h.mu.RUnlock() + switch name { + case AlgorithmKey: + if h.algorithm == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.algorithm)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case ContentTypeKey: + if h.contentType == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.contentType)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case CriticalKey: + if h.critical == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, + h.critical); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case JWKKey: + if h.jwk == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, + h.jwk); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case JWKSetURLKey: + if h.jwkSetURL == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.jwkSetURL)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case KeyIDKey: + if h.keyID == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.keyID)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case TypeKey: + if h.typ == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.typ)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case X509CertChainKey: + if h.x509CertChain == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, + h.x509CertChain); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case X509CertThumbprintKey: + if h.x509CertThumbprint == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.x509CertThumbprint)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case X509CertThumbprintS256Key: + if h.x509CertThumbprintS256 == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.x509CertThumbprintS256)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case X509URLKey: + if h.x509URL == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.x509URL)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + default: + v, ok := h.privateParams[name] + if !ok { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, v); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + } + return nil +} + +func (h *stdHeaders) Set(name string, value any) error { + h.mu.Lock() + defer h.mu.Unlock() + return h.setNoLock(name, value) +} + +func (h *stdHeaders) setNoLock(name string, value any) error { + switch name { + case AlgorithmKey: + alg, err := jwa.KeyAlgorithmFrom(value) + if err != nil { + return fmt.Errorf("invalid value for %s key: %w", AlgorithmKey, err) + } + if salg, ok := alg.(jwa.SignatureAlgorithm); ok { + h.algorithm = &salg + return nil + } + return fmt.Errorf("expecte jwa.SignatureAlgorithm, received %T", alg) + case ContentTypeKey: + if v, ok := value.(string); ok { + h.contentType = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, ContentTypeKey, value) + case CriticalKey: + if v, ok := value.([]string); ok { + h.critical = v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, CriticalKey, value) + case JWKKey: + if v, ok := value.(jwk.Key); ok { + h.jwk = v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, JWKKey, value) + case JWKSetURLKey: + if v, ok := value.(string); ok { + h.jwkSetURL = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, JWKSetURLKey, value) + case KeyIDKey: + if v, ok := value.(string); ok { + h.keyID = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, KeyIDKey, value) + case TypeKey: + if v, ok := value.(string); ok { + h.typ = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, TypeKey, value) + case X509CertChainKey: + if v, ok := value.(*cert.Chain); ok { + h.x509CertChain = v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, X509CertChainKey, value) + case X509CertThumbprintKey: + if v, ok := value.(string); ok { + h.x509CertThumbprint = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, X509CertThumbprintKey, value) + case X509CertThumbprintS256Key: + if v, ok := value.(string); ok { + h.x509CertThumbprintS256 = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, X509CertThumbprintS256Key, value) + case X509URLKey: + if v, ok := value.(string); ok { + h.x509URL = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, X509URLKey, value) + default: + if h.privateParams == nil { + h.privateParams = map[string]any{} + } + h.privateParams[name] = value + } + return nil +} + +func (h *stdHeaders) Remove(key string) error { + h.mu.Lock() + defer h.mu.Unlock() + switch key { + case AlgorithmKey: + h.algorithm = nil + case ContentTypeKey: + h.contentType = nil + case CriticalKey: + h.critical = nil + case JWKKey: + h.jwk = nil + case JWKSetURLKey: + h.jwkSetURL = nil + case KeyIDKey: + h.keyID = nil + case TypeKey: + h.typ = nil + case X509CertChainKey: + h.x509CertChain = nil + case X509CertThumbprintKey: + h.x509CertThumbprint = nil + case X509CertThumbprintS256Key: + h.x509CertThumbprintS256 = nil + case X509URLKey: + h.x509URL = nil + default: + delete(h.privateParams, key) + } + return nil +} + +func (h *stdHeaders) UnmarshalJSON(buf []byte) error { + h.mu.Lock() + defer h.mu.Unlock() + h.clear() + dec := json.NewDecoder(bytes.NewReader(buf)) +LOOP: + for { + tok, err := dec.Token() + if err != nil { + return fmt.Errorf(`error reading token: %w`, err) + } + switch tok := tok.(type) { + case json.Delim: + // Assuming we're doing everything correctly, we should ONLY + // get either tokens.OpenCurlyBracket or tokens.CloseCurlyBracket here. + if tok == tokens.CloseCurlyBracket { // End of object + break LOOP + } else if tok != tokens.OpenCurlyBracket { + return fmt.Errorf(`expected '%c' but got '%c'`, tokens.OpenCurlyBracket, tok) + } + case string: // Objects can only have string keys + switch tok { + case AlgorithmKey: + var decoded jwa.SignatureAlgorithm + if err := dec.Decode(&decoded); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, AlgorithmKey, err) + } + h.algorithm = &decoded + case ContentTypeKey: + if err := json.AssignNextStringToken(&h.contentType, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, ContentTypeKey, err) + } + case CriticalKey: + var decoded []string + if err := dec.Decode(&decoded); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, CriticalKey, err) + } + h.critical = decoded + case JWKKey: + var buf json.RawMessage + if err := dec.Decode(&buf); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, JWKKey, err) + } + key, err := jwk.ParseKey(buf) + if err != nil { + return fmt.Errorf(`failed to parse JWK for key %s: %w`, JWKKey, err) + } + h.jwk = key + case JWKSetURLKey: + if err := json.AssignNextStringToken(&h.jwkSetURL, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, JWKSetURLKey, err) + } + case KeyIDKey: + if err := json.AssignNextStringToken(&h.keyID, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, KeyIDKey, err) + } + case TypeKey: + if err := json.AssignNextStringToken(&h.typ, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, TypeKey, err) + } + case X509CertChainKey: + var decoded cert.Chain + if err := dec.Decode(&decoded); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, X509CertChainKey, err) + } + h.x509CertChain = &decoded + case X509CertThumbprintKey: + if err := json.AssignNextStringToken(&h.x509CertThumbprint, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, X509CertThumbprintKey, err) + } + case X509CertThumbprintS256Key: + if err := json.AssignNextStringToken(&h.x509CertThumbprintS256, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, X509CertThumbprintS256Key, err) + } + case X509URLKey: + if err := json.AssignNextStringToken(&h.x509URL, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, X509URLKey, err) + } + default: + decoded, err := registry.Decode(dec, tok) + if err != nil { + return err + } + h.setNoLock(tok, decoded) + } + default: + return fmt.Errorf(`invalid token %T`, tok) + } + } + h.raw = buf + return nil +} + +func (h *stdHeaders) Keys() []string { + h.mu.RLock() + defer h.mu.RUnlock() + keys := make([]string, 0, 11+len(h.privateParams)) + if h.algorithm != nil { + keys = append(keys, AlgorithmKey) + } + if h.contentType != nil { + keys = append(keys, ContentTypeKey) + } + if h.critical != nil { + keys = append(keys, CriticalKey) + } + if h.jwk != nil { + keys = append(keys, JWKKey) + } + if h.jwkSetURL != nil { + keys = append(keys, JWKSetURLKey) + } + if h.keyID != nil { + keys = append(keys, KeyIDKey) + } + if h.typ != nil { + keys = append(keys, TypeKey) + } + if h.x509CertChain != nil { + keys = append(keys, X509CertChainKey) + } + if h.x509CertThumbprint != nil { + keys = append(keys, X509CertThumbprintKey) + } + if h.x509CertThumbprintS256 != nil { + keys = append(keys, X509CertThumbprintS256Key) + } + if h.x509URL != nil { + keys = append(keys, X509URLKey) + } + for k := range h.privateParams { + keys = append(keys, k) + } + return keys +} + +func (h stdHeaders) MarshalJSON() ([]byte, error) { + h.mu.RLock() + data := make(map[string]any) + keys := make([]string, 0, 11+len(h.privateParams)) + if h.algorithm != nil { + data[AlgorithmKey] = *(h.algorithm) + keys = append(keys, AlgorithmKey) + } + if h.contentType != nil { + data[ContentTypeKey] = *(h.contentType) + keys = append(keys, ContentTypeKey) + } + if h.critical != nil { + data[CriticalKey] = h.critical + keys = append(keys, CriticalKey) + } + if h.jwk != nil { + data[JWKKey] = h.jwk + keys = append(keys, JWKKey) + } + if h.jwkSetURL != nil { + data[JWKSetURLKey] = *(h.jwkSetURL) + keys = append(keys, JWKSetURLKey) + } + if h.keyID != nil { + data[KeyIDKey] = *(h.keyID) + keys = append(keys, KeyIDKey) + } + if h.typ != nil { + data[TypeKey] = *(h.typ) + keys = append(keys, TypeKey) + } + if h.x509CertChain != nil { + data[X509CertChainKey] = h.x509CertChain + keys = append(keys, X509CertChainKey) + } + if h.x509CertThumbprint != nil { + data[X509CertThumbprintKey] = *(h.x509CertThumbprint) + keys = append(keys, X509CertThumbprintKey) + } + if h.x509CertThumbprintS256 != nil { + data[X509CertThumbprintS256Key] = *(h.x509CertThumbprintS256) + keys = append(keys, X509CertThumbprintS256Key) + } + if h.x509URL != nil { + data[X509URLKey] = *(h.x509URL) + keys = append(keys, X509URLKey) + } + for k, v := range h.privateParams { + data[k] = v + keys = append(keys, k) + } + h.mu.RUnlock() + sort.Strings(keys) + buf := pool.BytesBuffer().Get() + defer pool.BytesBuffer().Put(buf) + enc := json.NewEncoder(buf) + buf.WriteByte(tokens.OpenCurlyBracket) + for i, k := range keys { + if i > 0 { + buf.WriteRune(tokens.Comma) + } + buf.WriteRune(tokens.DoubleQuote) + buf.WriteString(k) + buf.WriteString(`":`) + switch v := data[k].(type) { + case []byte: + buf.WriteRune(tokens.DoubleQuote) + buf.WriteString(base64.EncodeToString(v)) + buf.WriteRune(tokens.DoubleQuote) + default: + if err := enc.Encode(v); err != nil { + return nil, fmt.Errorf(`failed to encode value for field %s: %w`, k, err) + } + buf.Truncate(buf.Len() - 1) + } + } + buf.WriteByte(tokens.CloseCurlyBracket) + ret := make([]byte, buf.Len()) + copy(ret, buf.Bytes()) + return ret, nil +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jws/interface.go b/vendor/github.com/lestrrat-go/jwx/v3/jws/interface.go new file mode 100644 index 00000000000..e3ad2968443 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jws/interface.go @@ -0,0 +1,80 @@ +package jws + +import ( + "github.com/lestrrat-go/jwx/v3/internal/base64" + "github.com/lestrrat-go/jwx/v3/jws/legacy" +) + +type Signer = legacy.Signer +type Verifier = legacy.Verifier +type HMACSigner = legacy.HMACSigner +type HMACVerifier = legacy.HMACVerifier + +// Base64Encoder is an interface that can be used when encoding JWS message +// components to base64. This is useful when you want to use a non-standard +// base64 encoder while generating or verifying signatures. By default JWS +// uses raw url base64 encoding (without padding), but there are apparently +// some cases where you may want to use a base64 encoders that uses padding. +// +// For example, apparently AWS ALB User Claims is provided in JWT format, +// but it uses a base64 encoding with padding. +type Base64Encoder = base64.Encoder + +type DecodeCtx interface { + CollectRaw() bool +} + +// Message represents a full JWS encoded message. Flattened serialization +// is not supported as a struct, but rather it's represented as a +// Message struct with only one `signature` element. +// +// Do not expect to use the Message object to verify or construct a +// signed payload with. You should only use this when you want to actually +// programmatically view the contents of the full JWS payload. +// +// As of this version, there is one big incompatibility when using Message +// objects to convert between compact and JSON representations. +// The protected header is sometimes encoded differently from the original +// message and the JSON serialization that we use in Go. +// +// For example, the protected header `eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9` +// decodes to +// +// {"typ":"JWT", +// "alg":"HS256"} +// +// However, when we parse this into a message, we create a jws.Header object, +// which, when we marshal into a JSON object again, becomes +// +// {"typ":"JWT","alg":"HS256"} +// +// Notice that serialization lacks a line break and a space between `"JWT",` +// and `"alg"`. This causes a problem when verifying the signatures AFTER +// a compact JWS message has been unmarshaled into a jws.Message. +// +// jws.Verify() doesn't go through this step, and therefore this does not +// manifest itself. However, you may see this discrepancy when you manually +// go through these conversions, and/or use the `jwx` tool like so: +// +// jwx jws parse message.jws | jwx jws verify --key somekey.jwk --stdin +// +// In this scenario, the first `jwx jws parse` outputs a parsed jws.Message +// which is marshaled into JSON. At this point the message's protected +// headers and the signatures don't match. +// +// To sign and verify, use the appropriate `Sign()` and `Verify()` functions. +type Message struct { + dc DecodeCtx + payload []byte + signatures []*Signature + b64 bool // true if payload should be base64 encoded +} + +type Signature struct { + encoder Base64Encoder + dc DecodeCtx + headers Headers // Unprotected Headers + protected Headers // Protected Headers + signature []byte // Signature + detached bool +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jws/internal/keytype/BUILD.bazel b/vendor/github.com/lestrrat-go/jwx/v3/jws/internal/keytype/BUILD.bazel new file mode 100644 index 00000000000..eb8bd94acbe --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jws/internal/keytype/BUILD.bazel @@ -0,0 +1,11 @@ +load("@rules_go//go:def.bzl", "go_library") + +go_library( + name = "keytype", + srcs = ["keytype.go"], + importpath = "github.com/lestrrat-go/jwx/v3/jws/internal/keytype", + visibility = ["//jws:__subpackages__"], + deps = [ + "//jwk", + ], +) diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jws/internal/keytype/keytype.go b/vendor/github.com/lestrrat-go/jwx/v3/jws/internal/keytype/keytype.go new file mode 100644 index 00000000000..6b57ed10d8e --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jws/internal/keytype/keytype.go @@ -0,0 +1,57 @@ +package keytype + +import ( + "crypto/ecdsa" + "crypto/ed25519" + "crypto/rsa" + + "github.com/lestrrat-go/jwx/v3/jwk" +) + +// Because the keys defined in github.com/lestrrat-go/jwx/jwk may also implement +// crypto.Signer, it would be possible for to mix up key types when signing/verifying +// for example, when we specify jws.WithKey(jwa.RSA256, cryptoSigner), the cryptoSigner +// can be for RSA, or any other type that implements crypto.Signer... even if it's for the +// wrong algorithm. +// +// These functions are there to differentiate between the valid KNOWN key types. +// For any other key type that is outside of the Go std library and our own code, +// we must rely on the user to be vigilant. +// +// Notes: symmetric keys are obviously not part of this. for v2 OKP keys, +// x25519 does not implement Sign() +func IsValidRSAKey(key any) bool { + switch key.(type) { + case + ecdsa.PrivateKey, *ecdsa.PrivateKey, + ed25519.PrivateKey, + jwk.ECDSAPrivateKey, jwk.OKPPrivateKey: + // these are NOT ok + return false + } + return true +} + +func IsValidECDSAKey(key any) bool { + switch key.(type) { + case + ed25519.PrivateKey, + rsa.PrivateKey, *rsa.PrivateKey, + jwk.RSAPrivateKey, jwk.OKPPrivateKey: + // these are NOT ok + return false + } + return true +} + +func IsValidEDDSAKey(key any) bool { + switch key.(type) { + case + ecdsa.PrivateKey, *ecdsa.PrivateKey, + rsa.PrivateKey, *rsa.PrivateKey, + jwk.RSAPrivateKey, jwk.ECDSAPrivateKey: + // these are NOT ok + return false + } + return true +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jws/io.go b/vendor/github.com/lestrrat-go/jwx/v3/jws/io.go new file mode 100644 index 00000000000..77a084cfda4 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jws/io.go @@ -0,0 +1,36 @@ +// Code generated by tools/cmd/genreadfile/main.go. DO NOT EDIT. + +package jws + +import ( + "fmt" + "io/fs" + "os" +) + +type sysFS struct{} + +func (sysFS) Open(path string) (fs.File, error) { + return os.Open(path) +} + +func ReadFile(path string, options ...ReadFileOption) (*Message, error) { + + var srcFS fs.FS = sysFS{} + for _, option := range options { + switch option.Ident() { + case identFS{}: + if err := option.Value(&srcFS); err != nil { + return nil, fmt.Errorf("failed to set fs.FS: %w", err) + } + } + } + + f, err := srcFS.Open(path) + if err != nil { + return nil, err + } + + defer f.Close() + return ParseReader(f) +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jws/jws.go b/vendor/github.com/lestrrat-go/jwx/v3/jws/jws.go new file mode 100644 index 00000000000..1fa77438b9a --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jws/jws.go @@ -0,0 +1,662 @@ +//go:generate ../tools/cmd/genjws.sh + +// Package jws implements the digital signature on JSON based data +// structures as described in https://tools.ietf.org/html/rfc7515 +// +// If you do not care about the details, the only things that you +// would need to use are the following functions: +// +// jws.Sign(payload, jws.WithKey(algorithm, key)) +// jws.Verify(serialized, jws.WithKey(algorithm, key)) +// +// To sign, simply use `jws.Sign`. `payload` is a []byte buffer that +// contains whatever data you want to sign. `alg` is one of the +// jwa.SignatureAlgorithm constants from package jwa. For RSA and +// ECDSA family of algorithms, you will need to prepare a private key. +// For HMAC family, you just need a []byte value. The `jws.Sign` +// function will return the encoded JWS message on success. +// +// To verify, use `jws.Verify`. It will parse the `encodedjws` buffer +// and verify the result using `algorithm` and `key`. Upon successful +// verification, the original payload is returned, so you can work on it. +// +// As a sidenote, consider using github.com/lestrrat-go/htmsig if you +// looking for HTTP Message Signatures (RFC9421) -- it uses the same +// underlying signing/verification mechanisms as this module. +package jws + +import ( + "bufio" + "crypto/ecdh" + "crypto/ecdsa" + "crypto/ed25519" + "crypto/rsa" + "errors" + "fmt" + "io" + "reflect" + "sync" + "unicode" + "unicode/utf8" + + "github.com/lestrrat-go/jwx/v3/internal/base64" + "github.com/lestrrat-go/jwx/v3/internal/json" + "github.com/lestrrat-go/jwx/v3/internal/jwxio" + "github.com/lestrrat-go/jwx/v3/internal/pool" + "github.com/lestrrat-go/jwx/v3/internal/tokens" + "github.com/lestrrat-go/jwx/v3/jwa" + "github.com/lestrrat-go/jwx/v3/jwk" + "github.com/lestrrat-go/jwx/v3/jws/jwsbb" +) + +var registry = json.NewRegistry() + +var signers = make(map[jwa.SignatureAlgorithm]Signer) +var muSigner = &sync.Mutex{} + +func removeSigner(alg jwa.SignatureAlgorithm) { + muSigner.Lock() + defer muSigner.Unlock() + delete(signers, alg) +} + +type defaultSigner struct { + alg jwa.SignatureAlgorithm +} + +func (s defaultSigner) Algorithm() jwa.SignatureAlgorithm { + return s.alg +} + +func (s defaultSigner) Sign(key any, payload []byte) ([]byte, error) { + return jwsbb.Sign(key, s.alg.String(), payload, nil) +} + +type signerAdapter struct { + signer Signer +} + +func (s signerAdapter) Algorithm() jwa.SignatureAlgorithm { + return s.signer.Algorithm() +} + +func (s signerAdapter) Sign(key any, payload []byte) ([]byte, error) { + return s.signer.Sign(payload, key) +} + +const ( + fmtInvalid = 1 << iota + fmtCompact + fmtJSON + fmtJSONPretty + fmtMax +) + +// silence linters +var _ = fmtInvalid +var _ = fmtMax + +func validateKeyBeforeUse(key any) error { + jwkKey, ok := key.(jwk.Key) + if !ok { + converted, err := jwk.Import(key) + if err != nil { + return fmt.Errorf(`could not convert key of type %T to jwk.Key for validation: %w`, key, err) + } + jwkKey = converted + } + return jwkKey.Validate() +} + +// Sign generates a JWS message for the given payload and returns +// it in serialized form, which can be in either compact or +// JSON format. Default is compact. +// +// You must pass at least one key to `jws.Sign()` by using `jws.WithKey()` +// option. +// +// jws.Sign(payload, jws.WithKey(alg, key)) +// jws.Sign(payload, jws.WithJSON(), jws.WithKey(alg1, key1), jws.WithKey(alg2, key2)) +// +// Note that in the second example the `jws.WithJSON()` option is +// specified as well. This is because the compact serialization +// format does not support multiple signatures, and users must +// specifically ask for the JSON serialization format. +// +// Read the documentation for `jws.WithKey()` to learn more about the +// possible values that can be used for `alg` and `key`. +// +// You may create JWS messages with the "none" (jwa.NoSignature) algorithm +// if you use the `jws.WithInsecureNoSignature()` option. This option +// can be combined with one or more signature keys, as well as the +// `jws.WithJSON()` option to generate multiple signatures (though +// the usefulness of such constructs is highly debatable) +// +// Note that this library does not allow you to successfully call `jws.Verify()` on +// signatures with the "none" algorithm. To parse these, use `jws.Parse()` instead. +// +// If you want to use a detached payload, use `jws.WithDetachedPayload()` as +// one of the options. When you use this option, you must always set the +// first parameter (`payload`) to `nil`, or the function will return an error +// +// You may also want to look at how to pass protected headers to the +// signing process, as you will likely be required to set the `b64` field +// when using detached payload. +// +// Look for options that return `jws.SignOption` or `jws.SignVerifyOption` +// for a complete list of options that can be passed to this function. +// +// You can use `errors.Is` with `jws.SignError()` to check if an error is from this function. +func Sign(payload []byte, options ...SignOption) ([]byte, error) { + sc := signContextPool.Get() + defer signContextPool.Put(sc) + + sc.payload = payload + + if err := sc.ProcessOptions(options); err != nil { + return nil, signerr(`failed to process options: %w`, err) + } + + lsigner := len(sc.sigbuilders) + if lsigner == 0 { + return nil, signerr(`no signers available. Specify an algorithm and a key using jws.WithKey()`) + } + + // Design note: while we could have easily set format = fmtJSON when + // lsigner > 1, I believe the decision to change serialization formats + // must be explicitly stated by the caller. Otherwise, I'm pretty sure + // there would be people filing issues saying "I get JSON when I expected + // compact serialization". + // + // Therefore, instead of making implicit format conversions, we force the + // user to spell it out as `jws.Sign(..., jws.WithJSON(), jws.WithKey(...), jws.WithKey(...))` + if sc.format == fmtCompact && lsigner != 1 { + return nil, signerr(`cannot have multiple signers (keys) specified for compact serialization. Use only one jws.WithKey()`) + } + + // Create a Message object with all the bits and bobs, and we'll + // serialize it in the end + var result Message + + if err := sc.PopulateMessage(&result); err != nil { + return nil, signerr(`failed to populate message: %w`, err) + } + switch sc.format { + case fmtJSON: + return json.Marshal(result) + case fmtJSONPretty: + return json.MarshalIndent(result, "", " ") + case fmtCompact: + // Take the only signature object, and convert it into a Compact + // serialization format + var compactOpts []CompactOption + if sc.detached { + compactOpts = append(compactOpts, WithDetached(true)) + } + for _, option := range options { + if copt, ok := option.(CompactOption); ok { + compactOpts = append(compactOpts, copt) + } + } + return Compact(&result, compactOpts...) + default: + return nil, signerr(`invalid serialization format`) + } +} + +var allowNoneWhitelist = jwk.WhitelistFunc(func(string) bool { + return false +}) + +// Verify checks if the given JWS message is verifiable using `alg` and `key`. +// `key` may be a "raw" key (e.g. rsa.PublicKey) or a jwk.Key +// +// If the verification is successful, `err` is nil, and the content of the +// payload that was signed is returned. If you need more fine-grained +// control of the verification process, manually generate a +// `Verifier` in `verify` subpackage, and call `Verify` method on it. +// If you need to access signatures and JOSE headers in a JWS message, +// use `Parse` function to get `Message` object. +// +// Because the use of "none" (jwa.NoSignature) algorithm is strongly discouraged, +// this function DOES NOT consider it a success when `{"alg":"none"}` is +// encountered in the message (it would also be counterintuitive when the code says +// it _verified_ something when in fact it did no such thing). If you want to +// accept messages with "none" signature algorithm, use `jws.Parse` to get the +// raw JWS message. +// +// The error returned by this function is of type can be checked against +// `jws.VerifyError()` and `jws.VerificationError()`. The latter is returned +// when the verification process itself fails (e.g. invalid signature, wrong key), +// while the former is returned when any other part of the `jws.Verify()` +// function fails. +func Verify(buf []byte, options ...VerifyOption) ([]byte, error) { + vc := verifyContextPool.Get() + defer verifyContextPool.Put(vc) + + if err := vc.ProcessOptions(options); err != nil { + return nil, verifyerr(`failed to process options: %w`, err) + } + + return vc.VerifyMessage(buf) +} + +// get the value of b64 header field. +// If the field does not exist, returns true (default) +// Otherwise return the value specified by the header field. +func getB64Value(hdr Headers) bool { + var b64 bool + if err := hdr.Get("b64", &b64); err != nil { + return true // default + } + + return b64 +} + +// Parse parses contents from the given source and creates a jws.Message +// struct. By default the input can be in either compact or full JSON serialization. +// +// You may pass `jws.WithJSON()` and/or `jws.WithCompact()` to specify +// explicitly which format to use. If neither or both is specified, the function +// will attempt to autodetect the format. If one or the other is specified, +// only the specified format will be attempted. +// +// On error, returns a jws.ParseError. +func Parse(src []byte, options ...ParseOption) (*Message, error) { + var formats int + for _, option := range options { + switch option.Ident() { + case identSerialization{}: + var v int + if err := option.Value(&v); err != nil { + return nil, parseerr(`failed to retrieve serialization option value: %w`, err) + } + switch v { + case fmtJSON: + formats |= fmtJSON + case fmtCompact: + formats |= fmtCompact + } + } + } + + // if format is 0 or both JSON/Compact, auto detect + if v := formats & (fmtJSON | fmtCompact); v == 0 || v == fmtJSON|fmtCompact { + CHECKLOOP: + for i := range src { + r := rune(src[i]) + if r >= utf8.RuneSelf { + r, _ = utf8.DecodeRune(src) + } + if !unicode.IsSpace(r) { + if r == tokens.OpenCurlyBracket { + formats = fmtJSON + } else { + formats = fmtCompact + } + break CHECKLOOP + } + } + } + + if formats&fmtCompact == fmtCompact { + msg, err := parseCompact(src) + if err != nil { + return nil, parseerr(`failed to parse compact format: %w`, err) + } + return msg, nil + } else if formats&fmtJSON == fmtJSON { + msg, err := parseJSON(src) + if err != nil { + return nil, parseerr(`failed to parse JSON format: %w`, err) + } + return msg, nil + } + + return nil, parseerr(`invalid byte sequence`) +} + +// ParseString parses contents from the given source and creates a jws.Message +// struct. The input can be in either compact or full JSON serialization. +// +// On error, returns a jws.ParseError. +func ParseString(src string) (*Message, error) { + msg, err := Parse([]byte(src)) + if err != nil { + return nil, sparseerr(`failed to parse string: %w`, err) + } + return msg, nil +} + +// ParseReader parses contents from the given source and creates a jws.Message +// struct. The input can be in either compact or full JSON serialization. +// +// On error, returns a jws.ParseError. +func ParseReader(src io.Reader) (*Message, error) { + data, err := jwxio.ReadAllFromFiniteSource(src) + if err == nil { + return Parse(data) + } + + if !errors.Is(err, jwxio.NonFiniteSourceError()) { + return nil, rparseerr(`failed to read from finite source: %w`, err) + } + + rdr := bufio.NewReader(src) + var first rune + for { + r, _, err := rdr.ReadRune() + if err != nil { + return nil, rparseerr(`failed to read rune: %w`, err) + } + if !unicode.IsSpace(r) { + first = r + if err := rdr.UnreadRune(); err != nil { + return nil, rparseerr(`failed to unread rune: %w`, err) + } + + break + } + } + + var parser func(io.Reader) (*Message, error) + if first == tokens.OpenCurlyBracket { + parser = parseJSONReader + } else { + parser = parseCompactReader + } + + m, err := parser(rdr) + if err != nil { + return nil, rparseerr(`failed to parse reader: %w`, err) + } + + return m, nil +} + +func parseJSONReader(src io.Reader) (result *Message, err error) { + var m Message + if err := json.NewDecoder(src).Decode(&m); err != nil { + return nil, fmt.Errorf(`failed to unmarshal jws message: %w`, err) + } + return &m, nil +} + +func parseJSON(data []byte) (result *Message, err error) { + var m Message + if err := json.Unmarshal(data, &m); err != nil { + return nil, fmt.Errorf(`failed to unmarshal jws message: %w`, err) + } + return &m, nil +} + +// SplitCompact splits a JWS in compact format and returns its three parts +// separately: protected headers, payload and signature. +// On error, returns a jws.ParseError. +// +// This function will be deprecated in v4. It is a low-level API, and +// thus will be available in the `jwsbb` package. +func SplitCompact(src []byte) ([]byte, []byte, []byte, error) { + hdr, payload, signature, err := jwsbb.SplitCompact(src) + if err != nil { + return nil, nil, nil, parseerr(`%w`, err) + } + return hdr, payload, signature, nil +} + +// SplitCompactString splits a JWT and returns its three parts +// separately: protected headers, payload and signature. +// On error, returns a jws.ParseError. +// +// This function will be deprecated in v4. It is a low-level API, and +// thus will be available in the `jwsbb` package. +func SplitCompactString(src string) ([]byte, []byte, []byte, error) { + hdr, payload, signature, err := jwsbb.SplitCompactString(src) + if err != nil { + return nil, nil, nil, parseerr(`%w`, err) + } + return hdr, payload, signature, nil +} + +// SplitCompactReader splits a JWT and returns its three parts +// separately: protected headers, payload and signature. +// On error, returns a jws.ParseError. +// +// This function will be deprecated in v4. It is a low-level API, and +// thus will be available in the `jwsbb` package. +func SplitCompactReader(rdr io.Reader) ([]byte, []byte, []byte, error) { + hdr, payload, signature, err := jwsbb.SplitCompactReader(rdr) + if err != nil { + return nil, nil, nil, parseerr(`%w`, err) + } + return hdr, payload, signature, nil +} + +// parseCompactReader parses a JWS value serialized via compact serialization. +func parseCompactReader(rdr io.Reader) (m *Message, err error) { + protected, payload, signature, err := SplitCompactReader(rdr) + if err != nil { + return nil, fmt.Errorf(`invalid compact serialization format: %w`, err) + } + return parse(protected, payload, signature) +} + +func parseCompact(data []byte) (m *Message, err error) { + protected, payload, signature, err := SplitCompact(data) + if err != nil { + return nil, fmt.Errorf(`invalid compact serialization format: %w`, err) + } + return parse(protected, payload, signature) +} + +func parse(protected, payload, signature []byte) (*Message, error) { + decodedHeader, err := base64.Decode(protected) + if err != nil { + return nil, fmt.Errorf(`failed to decode protected headers: %w`, err) + } + + hdr := NewHeaders() + if err := json.Unmarshal(decodedHeader, hdr); err != nil { + return nil, fmt.Errorf(`failed to parse JOSE headers: %w`, err) + } + + var decodedPayload []byte + b64 := getB64Value(hdr) + if !b64 { + decodedPayload = payload + } else { + v, err := base64.Decode(payload) + if err != nil { + return nil, fmt.Errorf(`failed to decode payload: %w`, err) + } + decodedPayload = v + } + + decodedSignature, err := base64.Decode(signature) + if err != nil { + return nil, fmt.Errorf(`failed to decode signature: %w`, err) + } + + var msg Message + msg.payload = decodedPayload + msg.signatures = append(msg.signatures, &Signature{ + protected: hdr, + signature: decodedSignature, + }) + msg.b64 = b64 + return &msg, nil +} + +type CustomDecoder = json.CustomDecoder +type CustomDecodeFunc = json.CustomDecodeFunc + +// RegisterCustomField allows users to specify that a private field +// be decoded as an instance of the specified type. This option has +// a global effect. +// +// For example, suppose you have a custom field `x-birthday`, which +// you want to represent as a string formatted in RFC3339 in JSON, +// but want it back as `time.Time`. +// +// In such case you would register a custom field as follows +// +// jws.RegisterCustomField(`x-birthday`, time.Time{}) +// +// Then you can use a `time.Time` variable to extract the value +// of `x-birthday` field, instead of having to use `any` +// and later convert it to `time.Time` +// +// var bday time.Time +// _ = hdr.Get(`x-birthday`, &bday) +// +// If you need a more fine-tuned control over the decoding process, +// you can register a `CustomDecoder`. For example, below shows +// how to register a decoder that can parse RFC1123 format string: +// +// jws.RegisterCustomField(`x-birthday`, jws.CustomDecodeFunc(func(data []byte) (any, error) { +// return time.Parse(time.RFC1123, string(data)) +// })) +// +// Please note that use of custom fields can be problematic if you +// are using a library that does not implement MarshalJSON/UnmarshalJSON +// and you try to roundtrip from an object to JSON, and then back to an object. +// For example, in the above example, you can _parse_ time values formatted +// in the format specified in RFC822, but when you convert an object into +// JSON, it will be formatted in RFC3339, because that's what `time.Time` +// likes to do. To avoid this, it's always better to use a custom type +// that wraps your desired type (in this case `time.Time`) and implement +// MarshalJSON and UnmashalJSON. +func RegisterCustomField(name string, object any) { + registry.Register(name, object) +} + +// Helpers for signature verification +var rawKeyToKeyType = make(map[reflect.Type]jwa.KeyType) +var keyTypeToAlgorithms = make(map[jwa.KeyType][]jwa.SignatureAlgorithm) + +func init() { + rawKeyToKeyType[reflect.TypeOf([]byte(nil))] = jwa.OctetSeq() + rawKeyToKeyType[reflect.TypeOf(ed25519.PublicKey(nil))] = jwa.OKP() + rawKeyToKeyType[reflect.TypeOf(rsa.PublicKey{})] = jwa.RSA() + rawKeyToKeyType[reflect.TypeOf((*rsa.PublicKey)(nil))] = jwa.RSA() + rawKeyToKeyType[reflect.TypeOf(ecdsa.PublicKey{})] = jwa.EC() + rawKeyToKeyType[reflect.TypeOf((*ecdsa.PublicKey)(nil))] = jwa.EC() + + addAlgorithmForKeyType(jwa.OKP(), jwa.EdDSA()) + for _, alg := range []jwa.SignatureAlgorithm{jwa.HS256(), jwa.HS384(), jwa.HS512()} { + addAlgorithmForKeyType(jwa.OctetSeq(), alg) + } + for _, alg := range []jwa.SignatureAlgorithm{jwa.RS256(), jwa.RS384(), jwa.RS512(), jwa.PS256(), jwa.PS384(), jwa.PS512()} { + addAlgorithmForKeyType(jwa.RSA(), alg) + } + for _, alg := range []jwa.SignatureAlgorithm{jwa.ES256(), jwa.ES384(), jwa.ES512()} { + addAlgorithmForKeyType(jwa.EC(), alg) + } +} + +func addAlgorithmForKeyType(kty jwa.KeyType, alg jwa.SignatureAlgorithm) { + keyTypeToAlgorithms[kty] = append(keyTypeToAlgorithms[kty], alg) +} + +// AlgorithmsForKey returns the possible signature algorithms that can +// be used for a given key. It only takes in consideration keys/algorithms +// for verification purposes, as this is the only usage where one may need +// dynamically figure out which method to use. +func AlgorithmsForKey(key any) ([]jwa.SignatureAlgorithm, error) { + var kty jwa.KeyType + switch key := key.(type) { + case jwk.Key: + kty = key.KeyType() + case rsa.PublicKey, *rsa.PublicKey, rsa.PrivateKey, *rsa.PrivateKey: + kty = jwa.RSA() + case ecdsa.PublicKey, *ecdsa.PublicKey, ecdsa.PrivateKey, *ecdsa.PrivateKey: + kty = jwa.EC() + case ed25519.PublicKey, ed25519.PrivateKey, *ecdh.PublicKey, ecdh.PublicKey, *ecdh.PrivateKey, ecdh.PrivateKey: + kty = jwa.OKP() + case []byte: + kty = jwa.OctetSeq() + default: + return nil, fmt.Errorf(`unknown key type %T`, key) + } + + algs, ok := keyTypeToAlgorithms[kty] + if !ok { + return nil, fmt.Errorf(`unregistered key type %q`, kty) + } + return algs, nil +} + +func Settings(options ...GlobalOption) { + for _, option := range options { + switch option.Ident() { + case identLegacySigners{}: + enableLegacySigners() + } + } +} + +// VerifyCompactFast is a fast path verification function for JWS messages +// in compact serialization format. +// +// This function is considered experimental, and may change or be removed +// in the future. +// +// VerifyCompactFast performs signature verification on a JWS compact +// serialization without fully parsing the message into a jws.Message object. +// This makes it more efficient for cases where you only need to verify +// the signature and extract the payload, without needing access to headers +// or other JWS metadata. +// +// Returns the original payload that was signed if verification succeeds. +// +// Unlike jws.Verify(), this function requires you to specify the +// algorithm explicitly rather than extracting it from the JWS headers. +// This can be useful for performance-critical applications where the +// algorithm is known in advance. +// +// Since this function avoids doing many checks that jws.Verify would perform, +// you must ensure to perform the necessary checks including ensuring that algorithm is safe to use for your payload yourself. +func VerifyCompactFast(key any, compact []byte, alg jwa.SignatureAlgorithm) ([]byte, error) { + algstr := alg.String() + + // Split the serialized JWT into its components + hdr, payload, encodedSig, err := jwsbb.SplitCompact(compact) + if err != nil { + return nil, fmt.Errorf("jwt.verifyFast: failed to split compact: %w", err) + } + + signature, err := base64.Decode(encodedSig) + if err != nil { + return nil, fmt.Errorf("jwt.verifyFast: failed to decode signature: %w", err) + } + + // Instead of appending, copy the data from hdr/payload + lvb := len(hdr) + 1 + len(payload) + verifyBuf := pool.ByteSlice().GetCapacity(lvb) + verifyBuf = verifyBuf[:lvb] + copy(verifyBuf, hdr) + verifyBuf[len(hdr)] = tokens.Period + copy(verifyBuf[len(hdr)+1:], payload) + defer pool.ByteSlice().Put(verifyBuf) + + // Verify the signature + if verifier2, err := VerifierFor(alg); err == nil { + if err := verifier2.Verify(key, verifyBuf, signature); err != nil { + return nil, verifyError{verificationError{fmt.Errorf("jwt.VerifyCompact: signature verification failed for %s: %w", algstr, err)}} + } + } else { + legacyVerifier, err := NewVerifier(alg) + if err != nil { + return nil, verifyerr("jwt.VerifyCompact: failed to create verifier for %s: %w", algstr, err) + } + if err := legacyVerifier.Verify(verifyBuf, signature, key); err != nil { + return nil, verifyError{verificationError{fmt.Errorf("jwt.VerifyCompact: signature verification failed for %s: %w", algstr, err)}} + } + } + + decoded, err := base64.Decode(payload) + if err != nil { + return nil, verifyerr("jwt.VerifyCompact: failed to decode payload: %w", err) + } + return decoded, nil +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jws/jwsbb/BUILD.bazel b/vendor/github.com/lestrrat-go/jwx/v3/jws/jwsbb/BUILD.bazel new file mode 100644 index 00000000000..0799e811103 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jws/jwsbb/BUILD.bazel @@ -0,0 +1,38 @@ +load("@rules_go//go:def.bzl", "go_library", "go_test") + +go_library( + name = "jwsbb", + srcs = [ + "crypto_signer.go", + "ecdsa.go", + "eddsa.go", + "format.go", + "hmac.go", + "jwsbb.go", + "rsa.go", + "sign.go", + "verify.go", + ], + importpath = "github.com/lestrrat-go/jwx/v3/jws/jwsbb", + visibility = ["//visibility:public"], + deps = [ + "//internal/base64", + "//internal/ecutil", + "//internal/jwxio", + "//internal/keyconv", + "//internal/pool", + "//internal/tokens", + "//jws/internal/keytype", + "@com_github_lestrrat_go_dsig//:dsig", + ], +) + +go_test( + name = "jwsbb_test", + srcs = ["jwsbb_test.go"], + embed = [":jwsbb"], + deps = [ + "//internal/base64", + "@com_github_stretchr_testify//require", + ], +) diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jws/jwsbb/crypto_signer.go b/vendor/github.com/lestrrat-go/jwx/v3/jws/jwsbb/crypto_signer.go new file mode 100644 index 00000000000..bd6132a4c58 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jws/jwsbb/crypto_signer.go @@ -0,0 +1,45 @@ +package jwsbb + +import ( + "crypto" + "crypto/rand" + "fmt" + "io" +) + +// cryptosign is a low-level function that signs a payload using a crypto.Signer. +// If hash is crypto.Hash(0), the payload is signed directly without hashing. +// Otherwise, the payload is hashed using the specified hash function before signing. +// +// rr is an io.Reader that provides randomness for signing. If rr is nil, it defaults to rand.Reader. +func cryptosign(signer crypto.Signer, payload []byte, hash crypto.Hash, opts crypto.SignerOpts, rr io.Reader) ([]byte, error) { + if rr == nil { + rr = rand.Reader + } + + var digest []byte + if hash == crypto.Hash(0) { + digest = payload + } else { + h := hash.New() + if _, err := h.Write(payload); err != nil { + return nil, fmt.Errorf(`failed to write payload to hash: %w`, err) + } + digest = h.Sum(nil) + } + return signer.Sign(rr, digest, opts) +} + +// SignCryptoSigner generates a signature using a crypto.Signer interface. +// This function can be used for hardware security modules, smart cards, +// and other implementations of the crypto.Signer interface. +// +// rr is an io.Reader that provides randomness for signing. If rr is nil, it defaults to rand.Reader. +// +// Returns the signature bytes or an error if signing fails. +func SignCryptoSigner(signer crypto.Signer, raw []byte, h crypto.Hash, opts crypto.SignerOpts, rr io.Reader) ([]byte, error) { + if signer == nil { + return nil, fmt.Errorf("jwsbb.SignCryptoSignerRaw: signer is nil") + } + return cryptosign(signer, raw, h, opts, rr) +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jws/jwsbb/ecdsa.go b/vendor/github.com/lestrrat-go/jwx/v3/jws/jwsbb/ecdsa.go new file mode 100644 index 00000000000..1eb492ee7b6 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jws/jwsbb/ecdsa.go @@ -0,0 +1,179 @@ +package jwsbb + +import ( + "crypto" + "crypto/ecdsa" + "encoding/asn1" + "fmt" + "io" + "math/big" + + "github.com/lestrrat-go/dsig" + "github.com/lestrrat-go/jwx/v3/internal/ecutil" +) + +// ecdsaHashToDsigAlgorithm maps ECDSA hash functions to dsig algorithm constants +func ecdsaHashToDsigAlgorithm(h crypto.Hash) (string, error) { + switch h { + case crypto.SHA256: + return dsig.ECDSAWithP256AndSHA256, nil + case crypto.SHA384: + return dsig.ECDSAWithP384AndSHA384, nil + case crypto.SHA512: + return dsig.ECDSAWithP521AndSHA512, nil + default: + return "", fmt.Errorf("unsupported ECDSA hash function: %v", h) + } +} + +// UnpackASN1ECDSASignature unpacks an ASN.1 encoded ECDSA signature into r and s values. +// This is typically used when working with crypto.Signer interfaces that return ASN.1 encoded signatures. +func UnpackASN1ECDSASignature(signed []byte, r, s *big.Int) error { + // Okay, this is silly, but hear me out. When we use the + // crypto.Signer interface, the PrivateKey is hidden. + // But we need some information about the key (its bit size). + // + // So while silly, we're going to have to make another call + // here and fetch the Public key. + // (This probably means that this information should be cached somewhere) + var p struct { + R *big.Int // TODO: get this from a pool? + S *big.Int + } + if _, err := asn1.Unmarshal(signed, &p); err != nil { + return fmt.Errorf(`failed to unmarshal ASN1 encoded signature: %w`, err) + } + + r.Set(p.R) + s.Set(p.S) + return nil +} + +// UnpackECDSASignature unpacks a JWS-format ECDSA signature into r and s values. +// The signature should be in the format specified by RFC 7515 (r||s as fixed-length byte arrays). +func UnpackECDSASignature(signature []byte, pubkey *ecdsa.PublicKey, r, s *big.Int) error { + keySize := ecutil.CalculateKeySize(pubkey.Curve) + if len(signature) != keySize*2 { + return fmt.Errorf(`invalid signature length for curve %q`, pubkey.Curve.Params().Name) + } + + r.SetBytes(signature[:keySize]) + s.SetBytes(signature[keySize:]) + + return nil +} + +// PackECDSASignature packs the r and s values from an ECDSA signature into a JWS-format byte slice. +// The output format follows RFC 7515: r||s as fixed-length byte arrays. +func PackECDSASignature(r *big.Int, sbig *big.Int, curveBits int) ([]byte, error) { + keyBytes := curveBits / 8 + if curveBits%8 > 0 { + keyBytes++ + } + + // Serialize r and s into fixed-length bytes + rBytes := r.Bytes() + rBytesPadded := make([]byte, keyBytes) + copy(rBytesPadded[keyBytes-len(rBytes):], rBytes) + + sBytes := sbig.Bytes() + sBytesPadded := make([]byte, keyBytes) + copy(sBytesPadded[keyBytes-len(sBytes):], sBytes) + + // Output as r||s + return append(rBytesPadded, sBytesPadded...), nil +} + +// SignECDSA generates an ECDSA signature for the given payload using the specified private key and hash. +// The raw parameter should be the pre-computed signing input (typically header.payload). +// +// rr is an io.Reader that provides randomness for signing. if rr is nil, it defaults to rand.Reader. +// +// This function is now a thin wrapper around dsig.SignECDSA. For new projects, you should +// consider using dsig instead of this function. +func SignECDSA(key *ecdsa.PrivateKey, payload []byte, h crypto.Hash, rr io.Reader) ([]byte, error) { + dsigAlg, err := ecdsaHashToDsigAlgorithm(h) + if err != nil { + return nil, fmt.Errorf("jwsbb.SignECDSA: %w", err) + } + + return dsig.Sign(key, dsigAlg, payload, rr) +} + +// SignECDSACryptoSigner generates an ECDSA signature using a crypto.Signer interface. +// This function works with hardware security modules and other crypto.Signer implementations. +// The signature is converted from ASN.1 format to JWS format (r||s). +// +// rr is an io.Reader that provides randomness for signing. If rr is nil, it defaults to rand.Reader. +func SignECDSACryptoSigner(signer crypto.Signer, raw []byte, h crypto.Hash, rr io.Reader) ([]byte, error) { + signed, err := SignCryptoSigner(signer, raw, h, h, rr) + if err != nil { + return nil, fmt.Errorf(`failed to sign payload using crypto.Signer: %w`, err) + } + + return signECDSACryptoSigner(signer, signed) +} + +func signECDSACryptoSigner(signer crypto.Signer, signed []byte) ([]byte, error) { + cpub := signer.Public() + pubkey, ok := cpub.(*ecdsa.PublicKey) + if !ok { + return nil, fmt.Errorf(`expected *ecdsa.PublicKey, got %T`, pubkey) + } + curveBits := pubkey.Curve.Params().BitSize + + var r, s big.Int + if err := UnpackASN1ECDSASignature(signed, &r, &s); err != nil { + return nil, fmt.Errorf(`failed to unpack ASN1 encoded signature: %w`, err) + } + + return PackECDSASignature(&r, &s, curveBits) +} + +func ecdsaVerify(key *ecdsa.PublicKey, buf []byte, h crypto.Hash, r, s *big.Int) error { + hasher := h.New() + hasher.Write(buf) + digest := hasher.Sum(nil) + if !ecdsa.Verify(key, digest, r, s) { + return fmt.Errorf("jwsbb.ECDSAVerifier: invalid ECDSA signature") + } + return nil +} + +// VerifyECDSA verifies an ECDSA signature for the given payload. +// This function verifies the signature using the specified public key and hash algorithm. +// The payload parameter should be the pre-computed signing input (typically header.payload). +// +// This function is now a thin wrapper around dsig.VerifyECDSA. For new projects, you should +// consider using dsig instead of this function. +func VerifyECDSA(key *ecdsa.PublicKey, payload, signature []byte, h crypto.Hash) error { + dsigAlg, err := ecdsaHashToDsigAlgorithm(h) + if err != nil { + return fmt.Errorf("jwsbb.VerifyECDSA: %w", err) + } + + return dsig.Verify(key, dsigAlg, payload, signature) +} + +// VerifyECDSACryptoSigner verifies an ECDSA signature for crypto.Signer implementations. +// This function is useful for verifying signatures created by hardware security modules +// or other implementations of the crypto.Signer interface. +// The payload parameter should be the pre-computed signing input (typically header.payload). +func VerifyECDSACryptoSigner(signer crypto.Signer, payload, signature []byte, h crypto.Hash) error { + var pubkey *ecdsa.PublicKey + switch cpub := signer.Public(); cpub := cpub.(type) { + case ecdsa.PublicKey: + pubkey = &cpub + case *ecdsa.PublicKey: + pubkey = cpub + default: + return fmt.Errorf(`jwsbb.VerifyECDSACryptoSigner: expected *ecdsa.PublicKey, got %T`, cpub) + } + + var r, s big.Int + if err := UnpackECDSASignature(signature, pubkey, &r, &s); err != nil { + return fmt.Errorf("jwsbb.ECDSAVerifier: failed to unpack ASN.1 encoded ECDSA signature: %w", err) + } + + return ecdsaVerify(pubkey, payload, h, &r, &s) +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jws/jwsbb/eddsa.go b/vendor/github.com/lestrrat-go/jwx/v3/jws/jwsbb/eddsa.go new file mode 100644 index 00000000000..960cf97dde6 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jws/jwsbb/eddsa.go @@ -0,0 +1,30 @@ +package jwsbb + +import ( + "crypto/ed25519" + + "github.com/lestrrat-go/dsig" +) + +// SignEdDSA generates an EdDSA (Ed25519) signature for the given payload. +// The raw parameter should be the pre-computed signing input (typically header.payload). +// EdDSA is deterministic and doesn't require additional hashing of the input. +// +// This function is now a thin wrapper around dsig.SignEdDSA. For new projects, you should +// consider using dsig instead of this function. +func SignEdDSA(key ed25519.PrivateKey, payload []byte) ([]byte, error) { + // Use dsig.Sign with EdDSA algorithm constant + return dsig.Sign(key, dsig.EdDSA, payload, nil) +} + +// VerifyEdDSA verifies an EdDSA (Ed25519) signature for the given payload. +// This function verifies the signature using Ed25519 verification algorithm. +// The payload parameter should be the pre-computed signing input (typically header.payload). +// EdDSA is deterministic and provides strong security guarantees without requiring hash function selection. +// +// This function is now a thin wrapper around dsig.VerifyEdDSA. For new projects, you should +// consider using dsig instead of this function. +func VerifyEdDSA(key ed25519.PublicKey, payload, signature []byte) error { + // Use dsig.Verify with EdDSA algorithm constant + return dsig.Verify(key, dsig.EdDSA, payload, signature) +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jws/jwsbb/es256k.go b/vendor/github.com/lestrrat-go/jwx/v3/jws/jwsbb/es256k.go new file mode 100644 index 00000000000..a8761ee0fca --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jws/jwsbb/es256k.go @@ -0,0 +1,14 @@ +//go:build jwx_es256k + +package jwsbb + +import ( + dsigsecp256k1 "github.com/lestrrat-go/dsig-secp256k1" +) + +const es256k = "ES256K" + +func init() { + // Add ES256K mapping when this build tag is enabled + jwsToDsigAlgorithm[es256k] = dsigsecp256k1.ECDSAWithSecp256k1AndSHA256 +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jws/jwsbb/format.go b/vendor/github.com/lestrrat-go/jwx/v3/jws/jwsbb/format.go new file mode 100644 index 00000000000..430bf625aca --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jws/jwsbb/format.go @@ -0,0 +1,235 @@ +package jwsbb + +import ( + "bytes" + "errors" + "io" + + "github.com/lestrrat-go/jwx/v3/internal/base64" + "github.com/lestrrat-go/jwx/v3/internal/jwxio" + "github.com/lestrrat-go/jwx/v3/internal/tokens" +) + +// SignBuffer combines the base64-encoded header and payload into a single byte slice +// for signing purposes. This creates the signing input according to JWS specification (RFC 7515). +// The result should be passed to signature generation functions. +// +// Parameters: +// - buf: Reusable buffer (can be nil for automatic allocation) +// - hdr: Raw header bytes (will be base64-encoded) +// - payload: Raw payload bytes (encoded based on encodePayload flag) +// - encoder: Base64 encoder to use for encoding components +// - encodePayload: If true, payload is base64-encoded; if false, payload is used as-is +// +// Returns the constructed signing input in the format: base64(header).base64(payload) or base64(header).payload +func SignBuffer(buf, hdr, payload []byte, encoder base64.Encoder, encodePayload bool) []byte { + l := encoder.EncodedLen(len(hdr)+len(payload)) + 1 + if cap(buf) < l { + buf = make([]byte, 0, l) + } + buf = buf[:0] + buf = encoder.AppendEncode(buf, hdr) + buf = append(buf, tokens.Period) + if encodePayload { + buf = encoder.AppendEncode(buf, payload) + } else { + buf = append(buf, payload...) + } + + return buf +} + +// AppendSignature appends a base64-encoded signature to a JWS signing input buffer. +// This completes the compact JWS serialization by adding the final signature component. +// The input buffer should contain the signing input (header.payload), and this function +// adds the period separator and base64-encoded signature. +// +// Parameters: +// - buf: Buffer containing the signing input (typically from SignBuffer) +// - signature: Raw signature bytes (will be base64-encoded) +// - encoder: Base64 encoder to use for encoding the signature +// +// Returns the complete compact JWS in the format: base64(header).base64(payload).base64(signature) +func AppendSignature(buf, signature []byte, encoder base64.Encoder) []byte { + l := len(buf) + len(signature) + 1 + if cap(buf) < l { + buf = make([]byte, 0, l) + } + buf = append(buf, tokens.Period) + buf = encoder.AppendEncode(buf, signature) + + return buf +} + +// JoinCompact creates a complete compact JWS serialization from individual components. +// This is a one-step function that combines header, payload, and signature into the final JWS format. +// It includes safety checks to prevent excessive memory allocation. +// +// Parameters: +// - buf: Reusable buffer (can be nil for automatic allocation) +// - hdr: Raw header bytes (will be base64-encoded) +// - payload: Raw payload bytes (encoded based on encodePayload flag) +// - signature: Raw signature bytes (will be base64-encoded) +// - encoder: Base64 encoder to use for encoding all components +// - encodePayload: If true, payload is base64-encoded; if false, payload is used as-is +// +// Returns the complete compact JWS or an error if the total size exceeds safety limits (1GB). +func JoinCompact(buf, hdr, payload, signature []byte, encoder base64.Encoder, encodePayload bool) ([]byte, error) { + const MaxBufferSize = 1 << 30 // 1 GB + totalSize := len(hdr) + len(payload) + len(signature) + 2 + if totalSize > MaxBufferSize { + return nil, errors.New("input sizes exceed maximum allowable buffer size") + } + if cap(buf) < totalSize { + buf = make([]byte, 0, totalSize) + } + buf = buf[:0] + buf = encoder.AppendEncode(buf, hdr) + buf = append(buf, tokens.Period) + if encodePayload { + buf = encoder.AppendEncode(buf, payload) + } else { + buf = append(buf, payload...) + } + buf = append(buf, tokens.Period) + buf = encoder.AppendEncode(buf, signature) + + return buf, nil +} + +var compactDelim = []byte{tokens.Period} + +var errInvalidNumberOfSegments = errors.New(`jwsbb: invalid number of segments`) + +// InvalidNumberOfSegmentsError returns the standard error for invalid JWS segment count. +// A valid compact JWS must have exactly 3 segments separated by periods: header.payload.signature +func InvalidNumberOfSegmentsError() error { + return errInvalidNumberOfSegments +} + +// SplitCompact parses a compact JWS serialization into its three components. +// This function validates that the input has exactly 3 segments separated by periods +// and returns the base64-encoded components without decoding them. +// +// Parameters: +// - src: Complete compact JWS string as bytes +// +// Returns: +// - protected: Base64-encoded protected header +// - payload: Base64-encoded payload (or raw payload if b64=false was used) +// - signature: Base64-encoded signature +// - err: Error if the format is invalid or segment count is wrong +func SplitCompact(src []byte) (protected, payload, signature []byte, err error) { + var s []byte + var ok bool + + protected, s, ok = bytes.Cut(src, compactDelim) + if !ok { // no period found + return nil, nil, nil, InvalidNumberOfSegmentsError() + } + payload, s, ok = bytes.Cut(s, compactDelim) + if !ok { // only one period found + return nil, nil, nil, InvalidNumberOfSegmentsError() + } + signature, _, ok = bytes.Cut(s, compactDelim) + if ok { // three periods found + return nil, nil, nil, InvalidNumberOfSegmentsError() + } + return protected, payload, signature, nil +} + +// SplitCompactString is a convenience wrapper around SplitCompact for string inputs. +// It converts the string to bytes and parses the compact JWS serialization. +// +// Parameters: +// - src: Complete compact JWS as a string +// +// Returns the same components as SplitCompact: protected header, payload, signature, and error. +func SplitCompactString(src string) (protected, payload, signature []byte, err error) { + return SplitCompact([]byte(src)) +} + +// SplitCompactReader parses a compact JWS serialization from an io.Reader. +// This function handles both finite and streaming sources efficiently. +// For finite sources, it reads all data at once. For streaming sources, +// it uses a buffer-based approach to find segment boundaries. +// +// Parameters: +// - rdr: Reader containing the compact JWS data +// +// Returns: +// - protected: Base64-encoded protected header +// - payload: Base64-encoded payload (or raw payload if b64=false was used) +// - signature: Base64-encoded signature +// - err: Error if reading fails or the format is invalid +// +// The function validates that exactly 3 segments are present, separated by periods. +func SplitCompactReader(rdr io.Reader) (protected, payload, signature []byte, err error) { + data, err := jwxio.ReadAllFromFiniteSource(rdr) + if err == nil { + return SplitCompact(data) + } + + if !errors.Is(err, jwxio.NonFiniteSourceError()) { + return nil, nil, nil, err + } + + var periods int + var state int + + buf := make([]byte, 4096) + var sofar []byte + + for { + // read next bytes + n, err := rdr.Read(buf) + // return on unexpected read error + if err != nil && err != io.EOF { + return nil, nil, nil, io.ErrUnexpectedEOF + } + + // append to current buffer + sofar = append(sofar, buf[:n]...) + // loop to capture multiple tokens.Period in current buffer + for loop := true; loop; { + var i = bytes.IndexByte(sofar, tokens.Period) + if i == -1 && err != io.EOF { + // no tokens.Period found -> exit and read next bytes (outer loop) + loop = false + continue + } else if i == -1 && err == io.EOF { + // no tokens.Period found -> process rest and exit + i = len(sofar) + loop = false + } else { + // tokens.Period found + periods++ + } + + // Reaching this point means we have found a tokens.Period or EOF and process the rest of the buffer + switch state { + case 0: + protected = sofar[:i] + state++ + case 1: + payload = sofar[:i] + state++ + case 2: + signature = sofar[:i] + } + // Shorten current buffer + if len(sofar) > i { + sofar = sofar[i+1:] + } + } + // Exit on EOF + if err == io.EOF { + break + } + } + if periods != 2 { + return nil, nil, nil, InvalidNumberOfSegmentsError() + } + + return protected, payload, signature, nil +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jws/jwsbb/header.go b/vendor/github.com/lestrrat-go/jwx/v3/jws/jwsbb/header.go new file mode 100644 index 00000000000..d50c38eeb13 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jws/jwsbb/header.go @@ -0,0 +1,222 @@ +package jwsbb + +import ( + "fmt" + + "github.com/lestrrat-go/jwx/v3/internal/base64" + "github.com/valyala/fastjson" +) + +type headerNotFoundError struct { + key string +} + +func (e headerNotFoundError) Error() string { + return fmt.Sprintf(`jwsbb: header "%s" not found`, e.key) +} + +func (e headerNotFoundError) Is(target error) bool { + switch target.(type) { + case headerNotFoundError, *headerNotFoundError: + // If the target is a headerNotFoundError or a pointer to it, we + // consider it a match + return true + default: + return false + } +} + +// ErrHeaderdNotFound returns an error that can be passed to `errors.Is` to check if the error is +// the result of the field not being found +func ErrHeaderNotFound() error { + return headerNotFoundError{} +} + +// ErrFieldNotFound is an alias for ErrHeaderNotFound, and is deprecated. It was a misnomer. +// It will be removed in a future release. +func ErrFieldNotFound() error { + return ErrHeaderNotFound() +} + +// Header is an object that allows you to access the JWS header in a quick and +// dirty way. It does not verify anything, it does not know anything about what +// each header field means, and it does not care about the JWS specification. +// But when you need to access the JWS header for that one field that you +// need, this is the object you want to use. +// +// As of this writing, HeaderParser cannot be used from concurrent goroutines. +// You will need to create a new instance for each goroutine that needs to parse a JWS header. +// Also, in general values obtained from this object should only be used +// while the Header object is still in scope. +// +// This type is experimental and may change or be removed in the future. +type Header interface { + // I'm hiding this behind an interface so that users won't accidentally + // rely on the underlying json handler implementation, nor the concrete + // type name that jwsbb provides, as we may choose a different one in the future. + jwsbbHeader() +} + +type header struct { + v *fastjson.Value + err error +} + +func (h *header) jwsbbHeader() {} + +// HeaderParseCompact parses a JWS header from a compact serialization format. +// You will need to call HeaderGet* functions to extract the values from the header. +// +// This function is experimental and may change or be removed in the future. +func HeaderParseCompact(buf []byte) Header { + decoded, err := base64.Decode(buf) + if err != nil { + return &header{err: err} + } + return HeaderParse(decoded) +} + +// HeaderParse parses a JWS header from a byte slice containing the decoded JSON. +// You will need to call HeaderGet* functions to extract the values from the header. +// +// Unlike HeaderParseCompact, this function does not perform any base64 decoding. +// This function is experimental and may change or be removed in the future. +func HeaderParse(decoded []byte) Header { + var p fastjson.Parser + v, err := p.ParseBytes(decoded) + if err != nil { + return &header{err: err} + } + return &header{ + v: v, + } +} + +func headerGet(h Header, key string) (*fastjson.Value, error) { + //nolint:forcetypeassert + hh := h.(*header) // we _know_ this can't be another type + if hh.err != nil { + return nil, hh.err + } + + v := hh.v.Get(key) + if v == nil { + return nil, headerNotFoundError{key: key} + } + return v, nil +} + +// HeaderGetString returns the string value for the given key from the JWS header. +// An error is returned if the JSON was not valid, if the key does not exist, +// or if the value is not a string. +// +// This function is experimental and may change or be removed in the future. +func HeaderGetString(h Header, key string) (string, error) { + v, err := headerGet(h, key) + if err != nil { + return "", err + } + + sb, err := v.StringBytes() + if err != nil { + return "", err + } + + return string(sb), nil +} + +// HeaderGetBool returns the boolean value for the given key from the JWS header. +// An error is returned if the JSON was not valid, if the key does not exist, +// or if the value is not a boolean. +// +// This function is experimental and may change or be removed in the future. +func HeaderGetBool(h Header, key string) (bool, error) { + v, err := headerGet(h, key) + if err != nil { + return false, err + } + return v.Bool() +} + +// HeaderGetFloat64 returns the float64 value for the given key from the JWS header. +// An error is returned if the JSON was not valid, if the key does not exist, +// or if the value is not a float64. +// +// This function is experimental and may change or be removed in the future. +func HeaderGetFloat64(h Header, key string) (float64, error) { + v, err := headerGet(h, key) + if err != nil { + return 0, err + } + return v.Float64() +} + +// HeaderGetInt returns the int value for the given key from the JWS header. +// An error is returned if the JSON was not valid, if the key does not exist, +// or if the value is not an int. +// +// This function is experimental and may change or be removed in the future. +func HeaderGetInt(h Header, key string) (int, error) { + v, err := headerGet(h, key) + if err != nil { + return 0, err + } + return v.Int() +} + +// HeaderGetInt64 returns the int64 value for the given key from the JWS header. +// An error is returned if the JSON was not valid, if the key does not exist, +// or if the value is not an int64. +// +// This function is experimental and may change or be removed in the future. +func HeaderGetInt64(h Header, key string) (int64, error) { + v, err := headerGet(h, key) + if err != nil { + return 0, err + } + return v.Int64() +} + +// HeaderGetStringBytes returns the byte slice value for the given key from the JWS header. +// An error is returned if the JSON was not valid, if the key does not exist, +// or if the value is not a byte slice. +// +// Because of limitations of the underlying library, you cannot use the return value +// of this function after the parser is garbage collected. +// +// This function is experimental and may change or be removed in the future. +func HeaderGetStringBytes(h Header, key string) ([]byte, error) { + v, err := headerGet(h, key) + if err != nil { + return nil, err + } + + return v.StringBytes() +} + +// HeaderGetUint returns the uint value for the given key from the JWS header. +// An error is returned if the JSON was not valid, if the key does not exist, +// or if the value is not a uint. +// +// This function is experimental and may change or be removed in the future. +func HeaderGetUint(h Header, key string) (uint, error) { + v, err := headerGet(h, key) + if err != nil { + return 0, err + } + return v.Uint() +} + +// HeaderGetUint64 returns the uint64 value for the given key from the JWS header. +// An error is returned if the JSON was not valid, if the key does not exist, +// or if the value is not a uint64. +// +// This function is experimental and may change or be removed in the future. +func HeaderGetUint64(h Header, key string) (uint64, error) { + v, err := headerGet(h, key) + if err != nil { + return 0, err + } + + return v.Uint64() +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jws/jwsbb/hmac.go b/vendor/github.com/lestrrat-go/jwx/v3/jws/jwsbb/hmac.go new file mode 100644 index 00000000000..8e70eb667de --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jws/jwsbb/hmac.go @@ -0,0 +1,52 @@ +package jwsbb + +import ( + "fmt" + "hash" + + "github.com/lestrrat-go/dsig" +) + +// hmacHashToDsigAlgorithm maps HMAC hash function sizes to dsig algorithm constants +func hmacHashToDsigAlgorithm(hfunc func() hash.Hash) (string, error) { + h := hfunc() + switch h.Size() { + case 32: // SHA256 + return dsig.HMACWithSHA256, nil + case 48: // SHA384 + return dsig.HMACWithSHA384, nil + case 64: // SHA512 + return dsig.HMACWithSHA512, nil + default: + return "", fmt.Errorf("unsupported HMAC hash function: size=%d", h.Size()) + } +} + +// SignHMAC generates an HMAC signature for the given payload using the specified hash function and key. +// The raw parameter should be the pre-computed signing input (typically header.payload). +// +// This function is now a thin wrapper around dsig.SignHMAC. For new projects, you should +// consider using dsig instead of this function. +func SignHMAC(key, payload []byte, hfunc func() hash.Hash) ([]byte, error) { + dsigAlg, err := hmacHashToDsigAlgorithm(hfunc) + if err != nil { + return nil, fmt.Errorf("jwsbb.SignHMAC: %w", err) + } + + return dsig.Sign(key, dsigAlg, payload, nil) +} + +// VerifyHMAC verifies an HMAC signature for the given payload. +// This function verifies the signature using the specified key and hash function. +// The payload parameter should be the pre-computed signing input (typically header.payload). +// +// This function is now a thin wrapper around dsig.VerifyHMAC. For new projects, you should +// consider using dsig instead of this function. +func VerifyHMAC(key, payload, signature []byte, hfunc func() hash.Hash) error { + dsigAlg, err := hmacHashToDsigAlgorithm(hfunc) + if err != nil { + return fmt.Errorf("jwsbb.VerifyHMAC: %w", err) + } + + return dsig.Verify(key, dsigAlg, payload, signature) +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jws/jwsbb/jwsbb.go b/vendor/github.com/lestrrat-go/jwx/v3/jws/jwsbb/jwsbb.go new file mode 100644 index 00000000000..6a67ee8f86e --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jws/jwsbb/jwsbb.go @@ -0,0 +1,94 @@ +// Package jwsbb provides the building blocks (hence the name "bb") for JWS operations. +// It should be thought of as a low-level API, almost akin to internal packages +// that should not be used directly by users of the jwx package. However, these exist +// to provide a more efficient way to perform JWS operations without the overhead of +// the higher-level jws package to power-users who know what they are doing. +// +// This package is currently considered EXPERIMENTAL, and the API may change +// without notice. It is not recommended to use this package unless you are +// fully aware of the implications of using it. +// +// All bb packages in jwx follow the same design principles: +// 1. Does minimal checking of input parameters (for performance); callers need to ensure that the parameters are valid. +// 2. All exported functions are strongly typed (i.e. they do not take `any` types unless they absolutely have to). +// 3. Does not rely on other public jwx packages (they are standalone, except for internal packages). +// +// This implementation uses github.com/lestrrat-go/dsig as the underlying signature provider. +package jwsbb + +import ( + "github.com/lestrrat-go/dsig" +) + +// JWS algorithm name constants +const ( + // HMAC algorithms + hs256 = "HS256" + hs384 = "HS384" + hs512 = "HS512" + + // RSA PKCS#1 v1.5 algorithms + rs256 = "RS256" + rs384 = "RS384" + rs512 = "RS512" + + // RSA PSS algorithms + ps256 = "PS256" + ps384 = "PS384" + ps512 = "PS512" + + // ECDSA algorithms + es256 = "ES256" + es384 = "ES384" + es512 = "ES512" + + // EdDSA algorithm + edDSA = "EdDSA" +) + +// Signer is a generic interface that defines the method for signing payloads. +// The type parameter K represents the key type (e.g., []byte for HMAC keys, +// *rsa.PrivateKey for RSA keys, *ecdsa.PrivateKey for ECDSA keys). +type Signer[K any] interface { + Sign(key K, payload []byte) ([]byte, error) +} + +// Verifier is a generic interface that defines the method for verifying signatures. +// The type parameter K represents the key type (e.g., []byte for HMAC keys, +// *rsa.PublicKey for RSA keys, *ecdsa.PublicKey for ECDSA keys). +type Verifier[K any] interface { + Verify(key K, buf []byte, signature []byte) error +} + +// JWS to dsig algorithm mapping +var jwsToDsigAlgorithm = map[string]string{ + // HMAC algorithms + hs256: dsig.HMACWithSHA256, + hs384: dsig.HMACWithSHA384, + hs512: dsig.HMACWithSHA512, + + // RSA PKCS#1 v1.5 algorithms + rs256: dsig.RSAPKCS1v15WithSHA256, + rs384: dsig.RSAPKCS1v15WithSHA384, + rs512: dsig.RSAPKCS1v15WithSHA512, + + // RSA PSS algorithms + ps256: dsig.RSAPSSWithSHA256, + ps384: dsig.RSAPSSWithSHA384, + ps512: dsig.RSAPSSWithSHA512, + + // ECDSA algorithms + es256: dsig.ECDSAWithP256AndSHA256, + es384: dsig.ECDSAWithP384AndSHA384, + es512: dsig.ECDSAWithP521AndSHA512, + // Note: ES256K requires external dependency and is handled separately + + // EdDSA algorithm + edDSA: dsig.EdDSA, +} + +// getDsigAlgorithm returns the dsig algorithm name for a JWS algorithm +func getDsigAlgorithm(jwsAlg string) (string, bool) { + dsigAlg, ok := jwsToDsigAlgorithm[jwsAlg] + return dsigAlg, ok +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jws/jwsbb/rsa.go b/vendor/github.com/lestrrat-go/jwx/v3/jws/jwsbb/rsa.go new file mode 100644 index 00000000000..36997cef7c0 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jws/jwsbb/rsa.go @@ -0,0 +1,71 @@ +package jwsbb + +import ( + "crypto" + "crypto/rsa" + "fmt" + "io" + + "github.com/lestrrat-go/dsig" +) + +// rsaHashToDsigAlgorithm maps RSA hash functions to dsig algorithm constants +func rsaHashToDsigAlgorithm(h crypto.Hash, pss bool) (string, error) { + if pss { + switch h { + case crypto.SHA256: + return dsig.RSAPSSWithSHA256, nil + case crypto.SHA384: + return dsig.RSAPSSWithSHA384, nil + case crypto.SHA512: + return dsig.RSAPSSWithSHA512, nil + default: + return "", fmt.Errorf("unsupported hash algorithm for RSA-PSS: %v", h) + } + } else { + switch h { + case crypto.SHA256: + return dsig.RSAPKCS1v15WithSHA256, nil + case crypto.SHA384: + return dsig.RSAPKCS1v15WithSHA384, nil + case crypto.SHA512: + return dsig.RSAPKCS1v15WithSHA512, nil + default: + return "", fmt.Errorf("unsupported hash algorithm for RSA PKCS#1 v1.5: %v", h) + } + } +} + +// SignRSA generates an RSA signature for the given payload using the specified private key and options. +// The raw parameter should be the pre-computed signing input (typically header.payload). +// If pss is true, RSA-PSS is used; otherwise, PKCS#1 v1.5 is used. +// +// The rr parameter is an optional io.Reader that can be used to provide randomness for signing. +// If rr is nil, it defaults to rand.Reader. +// +// This function is now a thin wrapper around dsig.SignRSA. For new projects, you should +// consider using dsig instead of this function. +func SignRSA(key *rsa.PrivateKey, payload []byte, h crypto.Hash, pss bool, rr io.Reader) ([]byte, error) { + dsigAlg, err := rsaHashToDsigAlgorithm(h, pss) + if err != nil { + return nil, fmt.Errorf("jwsbb.SignRSA: %w", err) + } + + return dsig.Sign(key, dsigAlg, payload, rr) +} + +// VerifyRSA verifies an RSA signature for the given payload and header. +// This function constructs the signing input by encoding the header and payload according to JWS specification, +// then verifies the signature using the specified public key and hash algorithm. +// If pss is true, RSA-PSS verification is used; otherwise, PKCS#1 v1.5 verification is used. +// +// This function is now a thin wrapper around dsig.VerifyRSA. For new projects, you should +// consider using dsig instead of this function. +func VerifyRSA(key *rsa.PublicKey, payload, signature []byte, h crypto.Hash, pss bool) error { + dsigAlg, err := rsaHashToDsigAlgorithm(h, pss) + if err != nil { + return fmt.Errorf("jwsbb.VerifyRSA: %w", err) + } + + return dsig.Verify(key, dsigAlg, payload, signature) +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jws/jwsbb/sign.go b/vendor/github.com/lestrrat-go/jwx/v3/jws/jwsbb/sign.go new file mode 100644 index 00000000000..6f36ab05541 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jws/jwsbb/sign.go @@ -0,0 +1,110 @@ +package jwsbb + +import ( + "crypto" + "crypto/ecdsa" + "crypto/ed25519" + "crypto/rsa" + "fmt" + "io" + + "github.com/lestrrat-go/dsig" + "github.com/lestrrat-go/jwx/v3/internal/keyconv" +) + +// Sign generates a JWS signature using the specified key and algorithm. +// +// This function loads the signer registered in the jwsbb package _ONLY_. +// It does not support custom signers that the user might have registered. +// +// rr is an io.Reader that provides randomness for signing. If rr is nil, it defaults to rand.Reader. +// Not all algorithms require this parameter, but it is included for consistency. +// 99% of the time, you can pass nil for rr, and it will work fine. +func Sign(key any, alg string, payload []byte, rr io.Reader) ([]byte, error) { + dsigAlg, ok := getDsigAlgorithm(alg) + if !ok { + return nil, fmt.Errorf(`jwsbb.Sign: unsupported signature algorithm %q`, alg) + } + + // Get dsig algorithm info to determine key conversion strategy + dsigInfo, ok := dsig.GetAlgorithmInfo(dsigAlg) + if !ok { + return nil, fmt.Errorf(`jwsbb.Sign: dsig algorithm %q not registered`, dsigAlg) + } + + switch dsigInfo.Family { + case dsig.HMAC: + return dispatchHMACSign(key, dsigAlg, payload) + case dsig.RSA: + return dispatchRSASign(key, dsigAlg, payload, rr) + case dsig.ECDSA: + return dispatchECDSASign(key, dsigAlg, payload, rr) + case dsig.EdDSAFamily: + return dispatchEdDSASign(key, dsigAlg, payload, rr) + default: + return nil, fmt.Errorf(`jwsbb.Sign: unsupported dsig algorithm family %q`, dsigInfo.Family) + } +} + +func dispatchHMACSign(key any, dsigAlg string, payload []byte) ([]byte, error) { + var hmackey []byte + if err := keyconv.ByteSliceKey(&hmackey, key); err != nil { + return nil, fmt.Errorf(`jwsbb.Sign: invalid key type %T. []byte is required: %w`, key, err) + } + + return dsig.Sign(hmackey, dsigAlg, payload, nil) +} + +func dispatchRSASign(key any, dsigAlg string, payload []byte, rr io.Reader) ([]byte, error) { + // Try crypto.Signer first (dsig can handle it directly) + if signer, ok := key.(crypto.Signer); ok { + // Verify it's an RSA key + if _, ok := signer.Public().(*rsa.PublicKey); ok { + return dsig.Sign(signer, dsigAlg, payload, rr) + } + } + + // Fall back to concrete key types + var privkey *rsa.PrivateKey + if err := keyconv.RSAPrivateKey(&privkey, key); err != nil { + return nil, fmt.Errorf(`jwsbb.Sign: invalid key type %T. *rsa.PrivateKey is required: %w`, key, err) + } + + return dsig.Sign(privkey, dsigAlg, payload, rr) +} + +func dispatchECDSASign(key any, dsigAlg string, payload []byte, rr io.Reader) ([]byte, error) { + // Try crypto.Signer first (dsig can handle it directly) + if signer, ok := key.(crypto.Signer); ok { + // Verify it's an ECDSA key + if _, ok := signer.Public().(*ecdsa.PublicKey); ok { + return dsig.Sign(signer, dsigAlg, payload, rr) + } + } + + // Fall back to concrete key types + var privkey *ecdsa.PrivateKey + if err := keyconv.ECDSAPrivateKey(&privkey, key); err != nil { + return nil, fmt.Errorf(`jwsbb.Sign: invalid key type %T. *ecdsa.PrivateKey is required: %w`, key, err) + } + + return dsig.Sign(privkey, dsigAlg, payload, rr) +} + +func dispatchEdDSASign(key any, dsigAlg string, payload []byte, rr io.Reader) ([]byte, error) { + // Try crypto.Signer first (dsig can handle it directly) + if signer, ok := key.(crypto.Signer); ok { + // Verify it's an EdDSA key + if _, ok := signer.Public().(ed25519.PublicKey); ok { + return dsig.Sign(signer, dsigAlg, payload, rr) + } + } + + // Fall back to concrete key types + var privkey ed25519.PrivateKey + if err := keyconv.Ed25519PrivateKey(&privkey, key); err != nil { + return nil, fmt.Errorf(`jwsbb.Sign: invalid key type %T. ed25519.PrivateKey is required: %w`, key, err) + } + + return dsig.Sign(privkey, dsigAlg, payload, rr) +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jws/jwsbb/verify.go b/vendor/github.com/lestrrat-go/jwx/v3/jws/jwsbb/verify.go new file mode 100644 index 00000000000..bac3ff487e6 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jws/jwsbb/verify.go @@ -0,0 +1,105 @@ +package jwsbb + +import ( + "crypto" + "crypto/ecdsa" + "crypto/ed25519" + "crypto/rsa" + "fmt" + + "github.com/lestrrat-go/dsig" + "github.com/lestrrat-go/jwx/v3/internal/keyconv" +) + +// Verify verifies a JWS signature using the specified key and algorithm. +// +// This function loads the verifier registered in the jwsbb package _ONLY_. +// It does not support custom verifiers that the user might have registered. +func Verify(key any, alg string, payload, signature []byte) error { + dsigAlg, ok := getDsigAlgorithm(alg) + if !ok { + return fmt.Errorf(`jwsbb.Verify: unsupported signature algorithm %q`, alg) + } + + // Get dsig algorithm info to determine key conversion strategy + dsigInfo, ok := dsig.GetAlgorithmInfo(dsigAlg) + if !ok { + return fmt.Errorf(`jwsbb.Verify: dsig algorithm %q not registered`, dsigAlg) + } + + switch dsigInfo.Family { + case dsig.HMAC: + return dispatchHMACVerify(key, dsigAlg, payload, signature) + case dsig.RSA: + return dispatchRSAVerify(key, dsigAlg, payload, signature) + case dsig.ECDSA: + return dispatchECDSAVerify(key, dsigAlg, payload, signature) + case dsig.EdDSAFamily: + return dispatchEdDSAVerify(key, dsigAlg, payload, signature) + default: + return fmt.Errorf(`jwsbb.Verify: unsupported dsig algorithm family %q`, dsigInfo.Family) + } +} + +func dispatchHMACVerify(key any, dsigAlg string, payload, signature []byte) error { + var hmackey []byte + if err := keyconv.ByteSliceKey(&hmackey, key); err != nil { + return fmt.Errorf(`jwsbb.Verify: invalid key type %T. []byte is required: %w`, key, err) + } + + return dsig.Verify(hmackey, dsigAlg, payload, signature) +} + +func dispatchRSAVerify(key any, dsigAlg string, payload, signature []byte) error { + // Try crypto.Signer first (dsig can handle it directly) + if signer, ok := key.(crypto.Signer); ok { + // Verify it's an RSA key + if _, ok := signer.Public().(*rsa.PublicKey); ok { + return dsig.Verify(signer, dsigAlg, payload, signature) + } + } + + // Fall back to concrete key types + var pubkey *rsa.PublicKey + if err := keyconv.RSAPublicKey(&pubkey, key); err != nil { + return fmt.Errorf(`jwsbb.Verify: invalid key type %T. *rsa.PublicKey is required: %w`, key, err) + } + + return dsig.Verify(pubkey, dsigAlg, payload, signature) +} + +func dispatchECDSAVerify(key any, dsigAlg string, payload, signature []byte) error { + // Try crypto.Signer first (dsig can handle it directly) + if signer, ok := key.(crypto.Signer); ok { + // Verify it's an ECDSA key + if _, ok := signer.Public().(*ecdsa.PublicKey); ok { + return dsig.Verify(signer, dsigAlg, payload, signature) + } + } + + // Fall back to concrete key types + var pubkey *ecdsa.PublicKey + if err := keyconv.ECDSAPublicKey(&pubkey, key); err != nil { + return fmt.Errorf(`jwsbb.Verify: invalid key type %T. *ecdsa.PublicKey is required: %w`, key, err) + } + + return dsig.Verify(pubkey, dsigAlg, payload, signature) +} + +func dispatchEdDSAVerify(key any, dsigAlg string, payload, signature []byte) error { + // Try crypto.Signer first (dsig can handle it directly) + if signer, ok := key.(crypto.Signer); ok { + // Verify it's an EdDSA key + if _, ok := signer.Public().(ed25519.PublicKey); ok { + return dsig.Verify(signer, dsigAlg, payload, signature) + } + } + + // Fall back to concrete key types + var pubkey ed25519.PublicKey + if err := keyconv.Ed25519PublicKey(&pubkey, key); err != nil { + return fmt.Errorf(`jwsbb.Verify: invalid key type %T. ed25519.PublicKey is required: %w`, key, err) + } + + return dsig.Verify(pubkey, dsigAlg, payload, signature) +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jws/key_provider.go b/vendor/github.com/lestrrat-go/jwx/v3/jws/key_provider.go new file mode 100644 index 00000000000..84529a1a87a --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jws/key_provider.go @@ -0,0 +1,291 @@ +package jws + +import ( + "context" + "fmt" + "net/url" + "sync" + + "github.com/lestrrat-go/jwx/v3/jwa" + "github.com/lestrrat-go/jwx/v3/jwk" +) + +// KeyProvider is responsible for providing key(s) to sign or verify a payload. +// Multiple `jws.KeyProvider`s can be passed to `jws.Verify()` or `jws.Sign()` +// +// `jws.Sign()` can only accept static key providers via `jws.WithKey()`, +// while `jws.Verify()` can accept `jws.WithKey()`, `jws.WithKeySet()`, +// `jws.WithVerifyAuto()`, and `jws.WithKeyProvider()`. +// +// Understanding how this works is crucial to learn how this package works. +// +// `jws.Sign()` is straightforward: signatures are created for each +// provided key. +// +// `jws.Verify()` is a bit more involved, because there are cases you +// will want to compute/deduce/guess the keys that you would like to +// use for verification. +// +// The first thing that `jws.Verify()` does is to collect the +// KeyProviders from the option list that the user provided (presented in pseudocode): +// +// keyProviders := filterKeyProviders(options) +// +// Then, remember that a JWS message may contain multiple signatures in the +// message. For each signature, we call on the KeyProviders to give us +// the key(s) to use on this signature: +// +// for sig in msg.Signatures { +// for kp in keyProviders { +// kp.FetchKeys(ctx, sink, sig, msg) +// ... +// } +// } +// +// The `sink` argument passed to the KeyProvider is a temporary storage +// for the keys (either a jwk.Key or a "raw" key). The `KeyProvider` +// is responsible for sending keys into the `sink`. +// +// When called, the `KeyProvider` created by `jws.WithKey()` sends the same key, +// `jws.WithKeySet()` sends keys that matches a particular `kid` and `alg`, +// `jws.WithVerifyAuto()` fetches a JWK from the `jku` URL, +// and finally `jws.WithKeyProvider()` allows you to execute arbitrary +// logic to provide keys. If you are providing a custom `KeyProvider`, +// you should execute the necessary checks or retrieval of keys, and +// then send the key(s) to the sink: +// +// sink.Key(alg, key) +// +// These keys are then retrieved and tried for each signature, until +// a match is found: +// +// keys := sink.Keys() +// for key in keys { +// if givenSignature == makeSignature(key, payload, ...)) { +// return OK +// } +// } +type KeyProvider interface { + FetchKeys(context.Context, KeySink, *Signature, *Message) error +} + +// KeySink is a data storage where `jws.KeyProvider` objects should +// send their keys to. +type KeySink interface { + Key(jwa.SignatureAlgorithm, any) +} + +type algKeyPair struct { + alg jwa.KeyAlgorithm + key any +} + +type algKeySink struct { + mu sync.Mutex + list []algKeyPair +} + +func (s *algKeySink) Key(alg jwa.SignatureAlgorithm, key any) { + s.mu.Lock() + s.list = append(s.list, algKeyPair{alg, key}) + s.mu.Unlock() +} + +type staticKeyProvider struct { + alg jwa.SignatureAlgorithm + key any +} + +func (kp *staticKeyProvider) FetchKeys(_ context.Context, sink KeySink, _ *Signature, _ *Message) error { + sink.Key(kp.alg, kp.key) + return nil +} + +type keySetProvider struct { + set jwk.Set + requireKid bool // true if `kid` must be specified + useDefault bool // true if the first key should be used iff there's exactly one key in set + inferAlgorithm bool // true if the algorithm should be inferred from key type + multipleKeysPerKeyID bool // true if we should attempt to match multiple keys per key ID. if false we assume that only one key exists for a given key ID +} + +func (kp *keySetProvider) selectKey(sink KeySink, key jwk.Key, sig *Signature, _ *Message) error { + if usage, ok := key.KeyUsage(); ok { + // it's okay if use: "". we'll assume it's "sig" + if usage != "" && usage != jwk.ForSignature.String() { + return nil + } + } + + if v, ok := key.Algorithm(); ok { + salg, ok := jwa.LookupSignatureAlgorithm(v.String()) + if !ok { + return fmt.Errorf(`invalid signature algorithm %q`, v) + } + + sink.Key(salg, key) + return nil + } + + if kp.inferAlgorithm { + algs, err := AlgorithmsForKey(key) + if err != nil { + return fmt.Errorf(`failed to get a list of signature methods for key type %s: %w`, key.KeyType(), err) + } + + // bail out if the JWT has a `alg` field, and it doesn't match + if tokAlg, ok := sig.ProtectedHeaders().Algorithm(); ok { + for _, alg := range algs { + if tokAlg == alg { + sink.Key(alg, key) + return nil + } + } + return fmt.Errorf(`algorithm in the message does not match any of the inferred algorithms`) + } + + // Yes, you get to try them all!!!!!!! + for _, alg := range algs { + sink.Key(alg, key) + } + return nil + } + return nil +} + +func (kp *keySetProvider) FetchKeys(_ context.Context, sink KeySink, sig *Signature, msg *Message) error { + if kp.requireKid { + wantedKid, ok := sig.ProtectedHeaders().KeyID() + if !ok { + // If the kid is NOT specified... kp.useDefault needs to be true, and the + // JWKs must have exactly one key in it + if !kp.useDefault { + return fmt.Errorf(`failed to find matching key: no key ID ("kid") specified in token`) + } else if kp.useDefault && kp.set.Len() > 1 { + return fmt.Errorf(`failed to find matching key: no key ID ("kid") specified in token but multiple keys available in key set`) + } + + // if we got here, then useDefault == true AND there is exactly + // one key in the set. + key, ok := kp.set.Key(0) + if !ok { + return fmt.Errorf(`failed to get key at index 0 (empty JWKS?)`) + } + return kp.selectKey(sink, key, sig, msg) + } + + // Otherwise we better be able to look up the key. + // <= v2.0.3 backwards compatible case: only match a single key + // whose key ID matches `wantedKid` + if !kp.multipleKeysPerKeyID { + key, ok := kp.set.LookupKeyID(wantedKid) + if !ok { + return fmt.Errorf(`failed to find key with key ID %q in key set`, wantedKid) + } + return kp.selectKey(sink, key, sig, msg) + } + + // if multipleKeysPerKeyID is true, we attempt all keys whose key ID matches + // the wantedKey + ok = false + for i := range kp.set.Len() { + key, _ := kp.set.Key(i) + if kid, ok := key.KeyID(); !ok || kid != wantedKid { + continue + } + + if err := kp.selectKey(sink, key, sig, msg); err != nil { + continue + } + ok = true + // continue processing so that we try all keys with the same key ID + } + if !ok { + return fmt.Errorf(`failed to find key with key ID %q in key set`, wantedKid) + } + return nil + } + + // Otherwise just try all keys + for i := range kp.set.Len() { + key, ok := kp.set.Key(i) + if !ok { + return fmt.Errorf(`failed to get key at index %d`, i) + } + if err := kp.selectKey(sink, key, sig, msg); err != nil { + continue + } + } + return nil +} + +type jkuProvider struct { + fetcher jwk.Fetcher + options []jwk.FetchOption +} + +func (kp jkuProvider) FetchKeys(ctx context.Context, sink KeySink, sig *Signature, _ *Message) error { + if kp.fetcher == nil { + kp.fetcher = jwk.FetchFunc(jwk.Fetch) + } + + kid, ok := sig.ProtectedHeaders().KeyID() + if !ok { + return fmt.Errorf(`use of "jku" requires that the payload contain a "kid" field in the protected header`) + } + + // errors here can't be reliably passed to the consumers. + // it's unfortunate, but if you need this control, you are + // going to have to write your own fetcher + u, ok := sig.ProtectedHeaders().JWKSetURL() + if !ok || u == "" { + return fmt.Errorf(`use of "jku" field specified, but the field is empty`) + } + uo, err := url.Parse(u) + if err != nil { + return fmt.Errorf(`failed to parse "jku": %w`, err) + } + if uo.Scheme != "https" { + return fmt.Errorf(`url in "jku" must be HTTPS`) + } + + set, err := kp.fetcher.Fetch(ctx, u, kp.options...) + if err != nil { + return fmt.Errorf(`failed to fetch %q: %w`, u, err) + } + + key, ok := set.LookupKeyID(kid) + if !ok { + // It is not an error if the key with the kid doesn't exist + return nil + } + + algs, err := AlgorithmsForKey(key) + if err != nil { + return fmt.Errorf(`failed to get a list of signature methods for key type %s: %w`, key.KeyType(), err) + } + + hdrAlg, ok := sig.ProtectedHeaders().Algorithm() + if ok { + for _, alg := range algs { + // if we have an "alg" field in the JWS, we can only proceed if + // the inferred algorithm matches + if hdrAlg != alg { + continue + } + + sink.Key(alg, key) + break + } + } + return nil +} + +// KeyProviderFunc is a type of KeyProvider that is implemented by +// a single function. You can use this to create ad-hoc `KeyProvider` +// instances. +type KeyProviderFunc func(context.Context, KeySink, *Signature, *Message) error + +func (kp KeyProviderFunc) FetchKeys(ctx context.Context, sink KeySink, sig *Signature, msg *Message) error { + return kp(ctx, sink, sig, msg) +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jws/legacy.go b/vendor/github.com/lestrrat-go/jwx/v3/jws/legacy.go new file mode 100644 index 00000000000..a6687d68cb3 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jws/legacy.go @@ -0,0 +1,88 @@ +package jws + +import ( + "fmt" + + "github.com/lestrrat-go/jwx/v3/jwa" + "github.com/lestrrat-go/jwx/v3/jws/legacy" +) + +func enableLegacySigners() { + for _, alg := range []jwa.SignatureAlgorithm{jwa.HS256(), jwa.HS384(), jwa.HS512()} { + if err := RegisterSigner(alg, func(alg jwa.SignatureAlgorithm) SignerFactory { + return SignerFactoryFn(func() (Signer, error) { + return legacy.NewHMACSigner(alg), nil + }) + }(alg)); err != nil { + panic(fmt.Sprintf("RegisterSigner failed: %v", err)) + } + if err := RegisterVerifier(alg, func(alg jwa.SignatureAlgorithm) VerifierFactory { + return VerifierFactoryFn(func() (Verifier, error) { + return legacy.NewHMACVerifier(alg), nil + }) + }(alg)); err != nil { + panic(fmt.Sprintf("RegisterVerifier failed: %v", err)) + } + } + + for _, alg := range []jwa.SignatureAlgorithm{jwa.RS256(), jwa.RS384(), jwa.RS512(), jwa.PS256(), jwa.PS384(), jwa.PS512()} { + if err := RegisterSigner(alg, func(alg jwa.SignatureAlgorithm) SignerFactory { + return SignerFactoryFn(func() (Signer, error) { + return legacy.NewRSASigner(alg), nil + }) + }(alg)); err != nil { + panic(fmt.Sprintf("RegisterSigner failed: %v", err)) + } + if err := RegisterVerifier(alg, func(alg jwa.SignatureAlgorithm) VerifierFactory { + return VerifierFactoryFn(func() (Verifier, error) { + return legacy.NewRSAVerifier(alg), nil + }) + }(alg)); err != nil { + panic(fmt.Sprintf("RegisterVerifier failed: %v", err)) + } + } + for _, alg := range []jwa.SignatureAlgorithm{jwa.ES256(), jwa.ES384(), jwa.ES512(), jwa.ES256K()} { + if err := RegisterSigner(alg, func(alg jwa.SignatureAlgorithm) SignerFactory { + return SignerFactoryFn(func() (Signer, error) { + return legacy.NewECDSASigner(alg), nil + }) + }(alg)); err != nil { + panic(fmt.Sprintf("RegisterSigner failed: %v", err)) + } + if err := RegisterVerifier(alg, func(alg jwa.SignatureAlgorithm) VerifierFactory { + return VerifierFactoryFn(func() (Verifier, error) { + return legacy.NewECDSAVerifier(alg), nil + }) + }(alg)); err != nil { + panic(fmt.Sprintf("RegisterVerifier failed: %v", err)) + } + } + + if err := RegisterSigner(jwa.EdDSA(), SignerFactoryFn(func() (Signer, error) { + return legacy.NewEdDSASigner(), nil + })); err != nil { + panic(fmt.Sprintf("RegisterSigner failed: %v", err)) + } + if err := RegisterVerifier(jwa.EdDSA(), VerifierFactoryFn(func() (Verifier, error) { + return legacy.NewEdDSAVerifier(), nil + })); err != nil { + panic(fmt.Sprintf("RegisterVerifier failed: %v", err)) + } +} + +func legacySignerFor(alg jwa.SignatureAlgorithm) (Signer, error) { + muSigner.Lock() + s, ok := signers[alg] + if !ok { + v, err := NewSigner(alg) + if err != nil { + muSigner.Unlock() + return nil, fmt.Errorf(`failed to create payload signer: %w`, err) + } + signers[alg] = v + s = v + } + muSigner.Unlock() + + return s, nil +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jws/legacy/BUILD.bazel b/vendor/github.com/lestrrat-go/jwx/v3/jws/legacy/BUILD.bazel new file mode 100644 index 00000000000..8e77cece469 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jws/legacy/BUILD.bazel @@ -0,0 +1,21 @@ +load("@rules_go//go:def.bzl", "go_library") + +go_library( + name = "legacy", + srcs = [ + "ecdsa.go", + "eddsa.go", + "hmac.go", + "legacy.go", + "rsa.go", + ], + importpath = "github.com/lestrrat-go/jwx/v3/jws/legacy", + visibility = ["//visibility:public"], + deps = [ + "//internal/ecutil", + "//internal/keyconv", + "//internal/pool", + "//jwa", + "//jws/internal/keytype", + ], +) diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jws/legacy/ecdsa.go b/vendor/github.com/lestrrat-go/jwx/v3/jws/legacy/ecdsa.go new file mode 100644 index 00000000000..0b714a44b84 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jws/legacy/ecdsa.go @@ -0,0 +1,204 @@ +package legacy + +import ( + "crypto" + "crypto/ecdsa" + "crypto/rand" + "encoding/asn1" + "fmt" + "math/big" + + "github.com/lestrrat-go/jwx/v3/internal/ecutil" + "github.com/lestrrat-go/jwx/v3/internal/keyconv" + "github.com/lestrrat-go/jwx/v3/internal/pool" + "github.com/lestrrat-go/jwx/v3/jwa" + "github.com/lestrrat-go/jwx/v3/jws/internal/keytype" +) + +var ecdsaSigners = make(map[jwa.SignatureAlgorithm]*ecdsaSigner) +var ecdsaVerifiers = make(map[jwa.SignatureAlgorithm]*ecdsaVerifier) + +func init() { + algs := map[jwa.SignatureAlgorithm]crypto.Hash{ + jwa.ES256(): crypto.SHA256, + jwa.ES384(): crypto.SHA384, + jwa.ES512(): crypto.SHA512, + jwa.ES256K(): crypto.SHA256, + } + for alg, hash := range algs { + ecdsaSigners[alg] = &ecdsaSigner{ + alg: alg, + hash: hash, + } + ecdsaVerifiers[alg] = &ecdsaVerifier{ + alg: alg, + hash: hash, + } + } +} + +func NewECDSASigner(alg jwa.SignatureAlgorithm) Signer { + return ecdsaSigners[alg] +} + +// ecdsaSigners are immutable. +type ecdsaSigner struct { + alg jwa.SignatureAlgorithm + hash crypto.Hash +} + +func (es ecdsaSigner) Algorithm() jwa.SignatureAlgorithm { + return es.alg +} + +func (es *ecdsaSigner) Sign(payload []byte, key any) ([]byte, error) { + if key == nil { + return nil, fmt.Errorf(`missing private key while signing payload`) + } + + h := es.hash.New() + if _, err := h.Write(payload); err != nil { + return nil, fmt.Errorf(`failed to write payload using ecdsa: %w`, err) + } + + signer, ok := key.(crypto.Signer) + if ok { + if !keytype.IsValidECDSAKey(key) { + return nil, fmt.Errorf(`cannot use key of type %T to generate ECDSA based signatures`, key) + } + switch key.(type) { + case ecdsa.PrivateKey, *ecdsa.PrivateKey: + // if it's a ecdsa.PrivateKey, it's more efficient to + // go through the non-crypto.Signer route. Set ok to false + ok = false + } + } + + var r, s *big.Int + var curveBits int + if ok { + signed, err := signer.Sign(rand.Reader, h.Sum(nil), es.hash) + if err != nil { + return nil, err + } + + var p struct { + R *big.Int + S *big.Int + } + if _, err := asn1.Unmarshal(signed, &p); err != nil { + return nil, fmt.Errorf(`failed to unmarshal ASN1 encoded signature: %w`, err) + } + + // Okay, this is silly, but hear me out. When we use the + // crypto.Signer interface, the PrivateKey is hidden. + // But we need some information about the key (its bit size). + // + // So while silly, we're going to have to make another call + // here and fetch the Public key. + // This probably means that this should be cached some where. + cpub := signer.Public() + pubkey, ok := cpub.(*ecdsa.PublicKey) + if !ok { + return nil, fmt.Errorf(`expected *ecdsa.PublicKey, got %T`, pubkey) + } + curveBits = pubkey.Curve.Params().BitSize + + r = p.R + s = p.S + } else { + var privkey ecdsa.PrivateKey + if err := keyconv.ECDSAPrivateKey(&privkey, key); err != nil { + return nil, fmt.Errorf(`failed to retrieve ecdsa.PrivateKey out of %T: %w`, key, err) + } + curveBits = privkey.Curve.Params().BitSize + rtmp, stmp, err := ecdsa.Sign(rand.Reader, &privkey, h.Sum(nil)) + if err != nil { + return nil, fmt.Errorf(`failed to sign payload using ecdsa: %w`, err) + } + r = rtmp + s = stmp + } + + keyBytes := curveBits / 8 + // Curve bits do not need to be a multiple of 8. + if curveBits%8 > 0 { + keyBytes++ + } + + rBytes := r.Bytes() + rBytesPadded := make([]byte, keyBytes) + copy(rBytesPadded[keyBytes-len(rBytes):], rBytes) + + sBytes := s.Bytes() + sBytesPadded := make([]byte, keyBytes) + copy(sBytesPadded[keyBytes-len(sBytes):], sBytes) + + out := append(rBytesPadded, sBytesPadded...) + + return out, nil +} + +// ecdsaVerifiers are immutable. +type ecdsaVerifier struct { + alg jwa.SignatureAlgorithm + hash crypto.Hash +} + +func NewECDSAVerifier(alg jwa.SignatureAlgorithm) Verifier { + return ecdsaVerifiers[alg] +} + +func (v ecdsaVerifier) Algorithm() jwa.SignatureAlgorithm { + return v.alg +} + +func (v *ecdsaVerifier) Verify(payload []byte, signature []byte, key any) error { + if key == nil { + return fmt.Errorf(`missing public key while verifying payload`) + } + + var pubkey ecdsa.PublicKey + if cs, ok := key.(crypto.Signer); ok { + cpub := cs.Public() + switch cpub := cpub.(type) { + case ecdsa.PublicKey: + pubkey = cpub + case *ecdsa.PublicKey: + pubkey = *cpub + default: + return fmt.Errorf(`failed to retrieve ecdsa.PublicKey out of crypto.Signer %T`, key) + } + } else { + if err := keyconv.ECDSAPublicKey(&pubkey, key); err != nil { + return fmt.Errorf(`failed to retrieve ecdsa.PublicKey out of %T: %w`, key, err) + } + } + + if !pubkey.Curve.IsOnCurve(pubkey.X, pubkey.Y) { + return fmt.Errorf(`public key used does not contain a point (X,Y) on the curve`) + } + + r := pool.BigInt().Get() + s := pool.BigInt().Get() + defer pool.BigInt().Put(r) + defer pool.BigInt().Put(s) + + keySize := ecutil.CalculateKeySize(pubkey.Curve) + if len(signature) != keySize*2 { + return fmt.Errorf(`invalid signature length for curve %q`, pubkey.Curve.Params().Name) + } + + r.SetBytes(signature[:keySize]) + s.SetBytes(signature[keySize:]) + + h := v.hash.New() + if _, err := h.Write(payload); err != nil { + return fmt.Errorf(`failed to write payload using ecdsa: %w`, err) + } + + if !ecdsa.Verify(&pubkey, h.Sum(nil), r, s) { + return fmt.Errorf(`failed to verify signature using ecdsa`) + } + return nil +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jws/legacy/eddsa.go b/vendor/github.com/lestrrat-go/jwx/v3/jws/legacy/eddsa.go new file mode 100644 index 00000000000..289e48e3b30 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jws/legacy/eddsa.go @@ -0,0 +1,79 @@ +package legacy + +import ( + "crypto" + "crypto/ed25519" + "crypto/rand" + "fmt" + + "github.com/lestrrat-go/jwx/v3/internal/keyconv" + "github.com/lestrrat-go/jwx/v3/jwa" + "github.com/lestrrat-go/jwx/v3/jws/internal/keytype" +) + +type eddsaSigner struct{} + +func NewEdDSASigner() Signer { + return &eddsaSigner{} +} + +func (s eddsaSigner) Algorithm() jwa.SignatureAlgorithm { + return jwa.EdDSA() +} + +func (s eddsaSigner) Sign(payload []byte, key any) ([]byte, error) { + if key == nil { + return nil, fmt.Errorf(`missing private key while signing payload`) + } + + // The ed25519.PrivateKey object implements crypto.Signer, so we should + // simply accept a crypto.Signer here. + signer, ok := key.(crypto.Signer) + if ok { + if !keytype.IsValidEDDSAKey(key) { + return nil, fmt.Errorf(`cannot use key of type %T to generate EdDSA based signatures`, key) + } + } else { + // This fallback exists for cases when jwk.Key was passed, or + // users gave us a pointer instead of non-pointer, etc. + var privkey ed25519.PrivateKey + if err := keyconv.Ed25519PrivateKey(&privkey, key); err != nil { + return nil, fmt.Errorf(`failed to retrieve ed25519.PrivateKey out of %T: %w`, key, err) + } + signer = privkey + } + + return signer.Sign(rand.Reader, payload, crypto.Hash(0)) +} + +type eddsaVerifier struct{} + +func NewEdDSAVerifier() Verifier { + return &eddsaVerifier{} +} + +func (v eddsaVerifier) Verify(payload, signature []byte, key any) (err error) { + if key == nil { + return fmt.Errorf(`missing public key while verifying payload`) + } + + var pubkey ed25519.PublicKey + signer, ok := key.(crypto.Signer) + if ok { + v := signer.Public() + pubkey, ok = v.(ed25519.PublicKey) + if !ok { + return fmt.Errorf(`expected crypto.Signer.Public() to return ed25519.PublicKey, but got %T`, v) + } + } else { + if err := keyconv.Ed25519PublicKey(&pubkey, key); err != nil { + return fmt.Errorf(`failed to retrieve ed25519.PublicKey out of %T: %w`, key, err) + } + } + + if !ed25519.Verify(pubkey, payload, signature) { + return fmt.Errorf(`failed to match EdDSA signature`) + } + + return nil +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jws/legacy/hmac.go b/vendor/github.com/lestrrat-go/jwx/v3/jws/legacy/hmac.go new file mode 100644 index 00000000000..7a3c9d1896b --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jws/legacy/hmac.go @@ -0,0 +1,90 @@ +package legacy + +import ( + "crypto/hmac" + "crypto/sha256" + "crypto/sha512" + "fmt" + "hash" + + "github.com/lestrrat-go/jwx/v3/internal/keyconv" + "github.com/lestrrat-go/jwx/v3/jwa" +) + +func init() { + algs := map[jwa.SignatureAlgorithm]func() hash.Hash{ + jwa.HS256(): sha256.New, + jwa.HS384(): sha512.New384, + jwa.HS512(): sha512.New, + } + + for alg, h := range algs { + hmacSignFuncs[alg] = makeHMACSignFunc(h) + } +} + +// HMACSigner uses crypto/hmac to sign the payloads. +// This is for legacy support only. +type HMACSigner struct { + alg jwa.SignatureAlgorithm + sign hmacSignFunc +} + +type HMACVerifier struct { + signer Signer +} + +type hmacSignFunc func(payload []byte, key []byte) ([]byte, error) + +var hmacSignFuncs = make(map[jwa.SignatureAlgorithm]hmacSignFunc) + +func NewHMACSigner(alg jwa.SignatureAlgorithm) Signer { + return &HMACSigner{ + alg: alg, + sign: hmacSignFuncs[alg], // we know this will succeed + } +} + +func makeHMACSignFunc(hfunc func() hash.Hash) hmacSignFunc { + return func(payload []byte, key []byte) ([]byte, error) { + h := hmac.New(hfunc, key) + if _, err := h.Write(payload); err != nil { + return nil, fmt.Errorf(`failed to write payload using hmac: %w`, err) + } + return h.Sum(nil), nil + } +} + +func (s HMACSigner) Algorithm() jwa.SignatureAlgorithm { + return s.alg +} + +func (s HMACSigner) Sign(payload []byte, key any) ([]byte, error) { + var hmackey []byte + if err := keyconv.ByteSliceKey(&hmackey, key); err != nil { + return nil, fmt.Errorf(`invalid key type %T. []byte is required: %w`, key, err) + } + + if len(hmackey) == 0 { + return nil, fmt.Errorf(`missing key while signing payload`) + } + + return s.sign(payload, hmackey) +} + +func NewHMACVerifier(alg jwa.SignatureAlgorithm) Verifier { + s := NewHMACSigner(alg) + return &HMACVerifier{signer: s} +} + +func (v HMACVerifier) Verify(payload, signature []byte, key any) (err error) { + expected, err := v.signer.Sign(payload, key) + if err != nil { + return fmt.Errorf(`failed to generated signature: %w`, err) + } + + if !hmac.Equal(signature, expected) { + return fmt.Errorf(`failed to match hmac signature`) + } + return nil +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jws/legacy/legacy.go b/vendor/github.com/lestrrat-go/jwx/v3/jws/legacy/legacy.go new file mode 100644 index 00000000000..84a25274281 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jws/legacy/legacy.go @@ -0,0 +1,36 @@ +// Package legacy provides support for legacy implementation of JWS signing and verification. +// Types, functions, and variables in this package are exported only for legacy support, +// and should not be relied upon for new code. +// +// This package will be available until v3 is sunset, but it will be removed in v4 +package legacy + +import ( + "github.com/lestrrat-go/jwx/v3/jwa" +) + +// Signer generates the signature for a given payload. +// This is for legacy support only. +type Signer interface { + // Sign creates a signature for the given payload. + // The second argument is the key used for signing the payload, and is usually + // the private key type associated with the signature method. For example, + // for `jwa.RSXXX` and `jwa.PSXXX` types, you need to pass the + // `*"crypto/rsa".PrivateKey` type. + // Check the documentation for each signer for details + Sign([]byte, any) ([]byte, error) + + Algorithm() jwa.SignatureAlgorithm +} + +// This is for legacy support only. +type Verifier interface { + // Verify checks whether the payload and signature are valid for + // the given key. + // `key` is the key used for verifying the payload, and is usually + // the public key associated with the signature method. For example, + // for `jwa.RSXXX` and `jwa.PSXXX` types, you need to pass the + // `*"crypto/rsa".PublicKey` type. + // Check the documentation for each verifier for details + Verify(payload []byte, signature []byte, key any) error +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jws/legacy/rsa.go b/vendor/github.com/lestrrat-go/jwx/v3/jws/legacy/rsa.go new file mode 100644 index 00000000000..aef110a5cfc --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jws/legacy/rsa.go @@ -0,0 +1,145 @@ +package legacy + +import ( + "crypto" + "crypto/rand" + "crypto/rsa" + "fmt" + + "github.com/lestrrat-go/jwx/v3/internal/keyconv" + "github.com/lestrrat-go/jwx/v3/jwa" + "github.com/lestrrat-go/jwx/v3/jws/internal/keytype" +) + +var rsaSigners = make(map[jwa.SignatureAlgorithm]*rsaSigner) +var rsaVerifiers = make(map[jwa.SignatureAlgorithm]*rsaVerifier) + +func init() { + data := map[jwa.SignatureAlgorithm]struct { + Hash crypto.Hash + PSS bool + }{ + jwa.RS256(): { + Hash: crypto.SHA256, + }, + jwa.RS384(): { + Hash: crypto.SHA384, + }, + jwa.RS512(): { + Hash: crypto.SHA512, + }, + jwa.PS256(): { + Hash: crypto.SHA256, + PSS: true, + }, + jwa.PS384(): { + Hash: crypto.SHA384, + PSS: true, + }, + jwa.PS512(): { + Hash: crypto.SHA512, + PSS: true, + }, + } + + for alg, item := range data { + rsaSigners[alg] = &rsaSigner{ + alg: alg, + hash: item.Hash, + pss: item.PSS, + } + rsaVerifiers[alg] = &rsaVerifier{ + alg: alg, + hash: item.Hash, + pss: item.PSS, + } + } +} + +type rsaSigner struct { + alg jwa.SignatureAlgorithm + hash crypto.Hash + pss bool +} + +func NewRSASigner(alg jwa.SignatureAlgorithm) Signer { + return rsaSigners[alg] +} + +func (rs *rsaSigner) Algorithm() jwa.SignatureAlgorithm { + return rs.alg +} + +func (rs *rsaSigner) Sign(payload []byte, key any) ([]byte, error) { + if key == nil { + return nil, fmt.Errorf(`missing private key while signing payload`) + } + + signer, ok := key.(crypto.Signer) + if ok { + if !keytype.IsValidRSAKey(key) { + return nil, fmt.Errorf(`cannot use key of type %T to generate RSA based signatures`, key) + } + } else { + var privkey rsa.PrivateKey + if err := keyconv.RSAPrivateKey(&privkey, key); err != nil { + return nil, fmt.Errorf(`failed to retrieve rsa.PrivateKey out of %T: %w`, key, err) + } + signer = &privkey + } + + h := rs.hash.New() + if _, err := h.Write(payload); err != nil { + return nil, fmt.Errorf(`failed to write payload to hash: %w`, err) + } + if rs.pss { + return signer.Sign(rand.Reader, h.Sum(nil), &rsa.PSSOptions{ + Hash: rs.hash, + SaltLength: rsa.PSSSaltLengthEqualsHash, + }) + } + return signer.Sign(rand.Reader, h.Sum(nil), rs.hash) +} + +type rsaVerifier struct { + alg jwa.SignatureAlgorithm + hash crypto.Hash + pss bool +} + +func NewRSAVerifier(alg jwa.SignatureAlgorithm) Verifier { + return rsaVerifiers[alg] +} + +func (rv *rsaVerifier) Verify(payload, signature []byte, key any) error { + if key == nil { + return fmt.Errorf(`missing public key while verifying payload`) + } + + var pubkey rsa.PublicKey + if cs, ok := key.(crypto.Signer); ok { + cpub := cs.Public() + switch cpub := cpub.(type) { + case rsa.PublicKey: + pubkey = cpub + case *rsa.PublicKey: + pubkey = *cpub + default: + return fmt.Errorf(`failed to retrieve rsa.PublicKey out of crypto.Signer %T`, key) + } + } else { + if err := keyconv.RSAPublicKey(&pubkey, key); err != nil { + return fmt.Errorf(`failed to retrieve rsa.PublicKey out of %T: %w`, key, err) + } + } + + h := rv.hash.New() + if _, err := h.Write(payload); err != nil { + return fmt.Errorf(`failed to write payload to hash: %w`, err) + } + + if rv.pss { + return rsa.VerifyPSS(&pubkey, rv.hash, h.Sum(nil), signature, nil) + } + return rsa.VerifyPKCS1v15(&pubkey, rv.hash, h.Sum(nil), signature) +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jws/message.go b/vendor/github.com/lestrrat-go/jwx/v3/jws/message.go new file mode 100644 index 00000000000..e113d1438cd --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jws/message.go @@ -0,0 +1,550 @@ +package jws + +import ( + "bytes" + "fmt" + + "github.com/lestrrat-go/jwx/v3/internal/base64" + "github.com/lestrrat-go/jwx/v3/internal/json" + "github.com/lestrrat-go/jwx/v3/internal/pool" + "github.com/lestrrat-go/jwx/v3/internal/tokens" + "github.com/lestrrat-go/jwx/v3/jwa" +) + +func NewSignature() *Signature { + return &Signature{} +} + +func (s *Signature) DecodeCtx() DecodeCtx { + return s.dc +} + +func (s *Signature) SetDecodeCtx(dc DecodeCtx) { + s.dc = dc +} + +func (s Signature) PublicHeaders() Headers { + return s.headers +} + +func (s *Signature) SetPublicHeaders(v Headers) *Signature { + s.headers = v + return s +} + +func (s Signature) ProtectedHeaders() Headers { + return s.protected +} + +func (s *Signature) SetProtectedHeaders(v Headers) *Signature { + s.protected = v + return s +} + +func (s Signature) Signature() []byte { + return s.signature +} + +func (s *Signature) SetSignature(v []byte) *Signature { + s.signature = v + return s +} + +type signatureUnmarshalProbe struct { + Header Headers `json:"header,omitempty"` + Protected *string `json:"protected,omitempty"` + Signature *string `json:"signature,omitempty"` +} + +func (s *Signature) UnmarshalJSON(data []byte) error { + var sup signatureUnmarshalProbe + sup.Header = NewHeaders() + if err := json.Unmarshal(data, &sup); err != nil { + return fmt.Errorf(`failed to unmarshal signature into temporary struct: %w`, err) + } + + s.headers = sup.Header + if buf := sup.Protected; buf != nil { + src := []byte(*buf) + if !bytes.HasPrefix(src, []byte{tokens.OpenCurlyBracket}) { + decoded, err := base64.Decode(src) + if err != nil { + return fmt.Errorf(`failed to base64 decode protected headers: %w`, err) + } + src = decoded + } + + prt := NewHeaders() + //nolint:forcetypeassert + prt.(*stdHeaders).SetDecodeCtx(s.DecodeCtx()) + if err := json.Unmarshal(src, prt); err != nil { + return fmt.Errorf(`failed to unmarshal protected headers: %w`, err) + } + //nolint:forcetypeassert + prt.(*stdHeaders).SetDecodeCtx(nil) + s.protected = prt + } + + if sup.Signature != nil { + decoded, err := base64.DecodeString(*sup.Signature) + if err != nil { + return fmt.Errorf(`failed to base decode signature: %w`, err) + } + s.signature = decoded + } + return nil +} + +// Sign populates the signature field, with a signature generated by +// given the signer object and payload. +// +// The first return value is the raw signature in binary format. +// The second return value s the full three-segment signature +// (e.g. "eyXXXX.XXXXX.XXXX") +// +// This method is deprecated, and will be remove in a future release. +// Signature objects in the future will only be used as containers, +// and signing will be done using the `jws.Sign` function, or alternatively +// you could use jwsbb package to craft the signature manually. +func (s *Signature) Sign(payload []byte, signer Signer, key any) ([]byte, []byte, error) { + return s.sign2(payload, signer, key) +} + +func (s *Signature) sign2(payload []byte, signer interface{ Algorithm() jwa.SignatureAlgorithm }, key any) ([]byte, []byte, error) { + // Create a signatureBuilder to use the shared signing logic + sb := signatureBuilderPool.Get() + defer signatureBuilderPool.Put(sb) + + sb.alg = signer.Algorithm() + sb.key = key + sb.protected = s.protected + sb.public = s.headers + + // Set up the appropriate signer interface + switch typedSigner := signer.(type) { + case Signer2: + sb.signer2 = typedSigner + case Signer: + sb.signer = typedSigner + default: + return nil, nil, fmt.Errorf(`invalid signer type: %T`, signer) + } + + // Create a minimal sign context + sc := signContextPool.Get() + defer signContextPool.Put(sc) + + sc.detached = s.detached + + encoder := s.encoder + if encoder == nil { + encoder = base64.DefaultEncoder() + } + sc.encoder = encoder + + // Build the signature using signatureBuilder + sig, err := sb.Build(sc, payload) + if err != nil { + return nil, nil, fmt.Errorf(`failed to build signature: %w`, err) + } + + // Copy the signature result back to this signature instance + s.signature = sig.signature + s.protected = sig.protected + s.headers = sig.headers + + // Build the complete JWS token for the return value + buf := pool.BytesBuffer().Get() + defer pool.BytesBuffer().Put(buf) + + // Marshal the merged headers for the final output + hdrs, err := mergeHeaders(s.headers, s.protected) + if err != nil { + return nil, nil, fmt.Errorf(`failed to merge headers: %w`, err) + } + + hdrbuf, err := json.Marshal(hdrs) + if err != nil { + return nil, nil, fmt.Errorf(`failed to marshal headers: %w`, err) + } + + buf.WriteString(encoder.EncodeToString(hdrbuf)) + buf.WriteByte(tokens.Period) + + var plen int + b64 := getB64Value(hdrs) + if b64 { + encoded := encoder.EncodeToString(payload) + plen = len(encoded) + buf.WriteString(encoded) + } else { + if !s.detached { + if bytes.Contains(payload, []byte{tokens.Period}) { + return nil, nil, fmt.Errorf(`payload must not contain a "."`) + } + } + plen = len(payload) + buf.Write(payload) + } + + // Handle detached payload + if s.detached { + buf.Truncate(buf.Len() - plen) + } + + buf.WriteByte(tokens.Period) + buf.WriteString(encoder.EncodeToString(s.signature)) + ret := make([]byte, buf.Len()) + copy(ret, buf.Bytes()) + + return s.signature, ret, nil +} + +func NewMessage() *Message { + return &Message{} +} + +// Clears the internal raw buffer that was accumulated during +// the verify phase +func (m *Message) clearRaw() { + for _, sig := range m.signatures { + if protected := sig.protected; protected != nil { + if cr, ok := protected.(*stdHeaders); ok { + cr.raw = nil + } + } + } +} + +func (m *Message) SetDecodeCtx(dc DecodeCtx) { + m.dc = dc +} + +func (m *Message) DecodeCtx() DecodeCtx { + return m.dc +} + +// Payload returns the decoded payload +func (m Message) Payload() []byte { + return m.payload +} + +func (m *Message) SetPayload(v []byte) *Message { + m.payload = v + return m +} + +func (m Message) Signatures() []*Signature { + return m.signatures +} + +func (m *Message) AppendSignature(v *Signature) *Message { + m.signatures = append(m.signatures, v) + return m +} + +func (m *Message) ClearSignatures() *Message { + m.signatures = nil + return m +} + +// LookupSignature looks up a particular signature entry using +// the `kid` value +func (m Message) LookupSignature(kid string) []*Signature { + var sigs []*Signature + for _, sig := range m.signatures { + if hdr := sig.PublicHeaders(); hdr != nil { + hdrKeyID, ok := hdr.KeyID() + if ok && hdrKeyID == kid { + sigs = append(sigs, sig) + continue + } + } + + if hdr := sig.ProtectedHeaders(); hdr != nil { + hdrKeyID, ok := hdr.KeyID() + if ok && hdrKeyID == kid { + sigs = append(sigs, sig) + continue + } + } + } + return sigs +} + +// This struct is used to first probe for the structure of the +// incoming JSON object. We then decide how to parse it +// from the fields that are populated. +type messageUnmarshalProbe struct { + Payload *string `json:"payload"` + Signatures []json.RawMessage `json:"signatures,omitempty"` + Header Headers `json:"header,omitempty"` + Protected *string `json:"protected,omitempty"` + Signature *string `json:"signature,omitempty"` +} + +func (m *Message) UnmarshalJSON(buf []byte) error { + m.payload = nil + m.signatures = nil + m.b64 = true + + var mup messageUnmarshalProbe + mup.Header = NewHeaders() + if err := json.Unmarshal(buf, &mup); err != nil { + return fmt.Errorf(`failed to unmarshal into temporary structure: %w`, err) + } + + b64 := true + if mup.Signature == nil { // flattened signature is NOT present + if len(mup.Signatures) == 0 { + return fmt.Errorf(`required field "signatures" not present`) + } + + m.signatures = make([]*Signature, 0, len(mup.Signatures)) + for i, rawsig := range mup.Signatures { + var sig Signature + sig.SetDecodeCtx(m.DecodeCtx()) + if err := json.Unmarshal(rawsig, &sig); err != nil { + return fmt.Errorf(`failed to unmarshal signature #%d: %w`, i+1, err) + } + sig.SetDecodeCtx(nil) + + if sig.protected == nil { + // Instead of barfing on a nil protected header, use an empty header + sig.protected = NewHeaders() + } + + if i == 0 { + if !getB64Value(sig.protected) { + b64 = false + } + } else { + if b64 != getB64Value(sig.protected) { + return fmt.Errorf(`b64 value must be the same for all signatures`) + } + } + + m.signatures = append(m.signatures, &sig) + } + } else { // .signature is present, it's a flattened structure + if len(mup.Signatures) != 0 { + return fmt.Errorf(`invalid format ("signatures" and "signature" keys cannot both be present)`) + } + + var sig Signature + sig.headers = mup.Header + if src := mup.Protected; src != nil { + decoded, err := base64.DecodeString(*src) + if err != nil { + return fmt.Errorf(`failed to base64 decode flattened protected headers: %w`, err) + } + prt := NewHeaders() + //nolint:forcetypeassert + prt.(*stdHeaders).SetDecodeCtx(m.DecodeCtx()) + if err := json.Unmarshal(decoded, prt); err != nil { + return fmt.Errorf(`failed to unmarshal flattened protected headers: %w`, err) + } + //nolint:forcetypeassert + prt.(*stdHeaders).SetDecodeCtx(nil) + sig.protected = prt + } + + if sig.protected == nil { + // Instead of barfing on a nil protected header, use an empty header + sig.protected = NewHeaders() + } + + decoded, err := base64.DecodeString(*mup.Signature) + if err != nil { + return fmt.Errorf(`failed to base64 decode flattened signature: %w`, err) + } + sig.signature = decoded + + m.signatures = []*Signature{&sig} + b64 = getB64Value(sig.protected) + } + + if mup.Payload != nil { + if !b64 { // NOT base64 encoded + m.payload = []byte(*mup.Payload) + } else { + decoded, err := base64.DecodeString(*mup.Payload) + if err != nil { + return fmt.Errorf(`failed to base64 decode payload: %w`, err) + } + m.payload = decoded + } + } + m.b64 = b64 + return nil +} + +func (m Message) MarshalJSON() ([]byte, error) { + if len(m.signatures) == 1 { + return m.marshalFlattened() + } + return m.marshalFull() +} + +func (m Message) marshalFlattened() ([]byte, error) { + buf := pool.BytesBuffer().Get() + defer pool.BytesBuffer().Put(buf) + + sig := m.signatures[0] + + buf.WriteRune(tokens.OpenCurlyBracket) + var wrote bool + + if hdr := sig.headers; hdr != nil { + hdrjs, err := json.Marshal(hdr) + if err != nil { + return nil, fmt.Errorf(`failed to marshal "header" (flattened format): %w`, err) + } + buf.WriteString(`"header":`) + buf.Write(hdrjs) + wrote = true + } + + if wrote { + buf.WriteRune(tokens.Comma) + } + buf.WriteString(`"payload":"`) + buf.WriteString(base64.EncodeToString(m.payload)) + buf.WriteRune('"') + + if protected := sig.protected; protected != nil { + protectedbuf, err := json.Marshal(protected) + if err != nil { + return nil, fmt.Errorf(`failed to marshal "protected" (flattened format): %w`, err) + } + buf.WriteString(`,"protected":"`) + buf.WriteString(base64.EncodeToString(protectedbuf)) + buf.WriteRune('"') + } + + buf.WriteString(`,"signature":"`) + buf.WriteString(base64.EncodeToString(sig.signature)) + buf.WriteRune('"') + buf.WriteRune(tokens.CloseCurlyBracket) + + ret := make([]byte, buf.Len()) + copy(ret, buf.Bytes()) + return ret, nil +} + +func (m Message) marshalFull() ([]byte, error) { + buf := pool.BytesBuffer().Get() + defer pool.BytesBuffer().Put(buf) + + buf.WriteString(`{"payload":"`) + buf.WriteString(base64.EncodeToString(m.payload)) + buf.WriteString(`","signatures":[`) + for i, sig := range m.signatures { + if i > 0 { + buf.WriteRune(tokens.Comma) + } + + buf.WriteRune(tokens.OpenCurlyBracket) + var wrote bool + if hdr := sig.headers; hdr != nil { + hdrbuf, err := json.Marshal(hdr) + if err != nil { + return nil, fmt.Errorf(`failed to marshal "header" for signature #%d: %w`, i+1, err) + } + buf.WriteString(`"header":`) + buf.Write(hdrbuf) + wrote = true + } + + if protected := sig.protected; protected != nil { + protectedbuf, err := json.Marshal(protected) + if err != nil { + return nil, fmt.Errorf(`failed to marshal "protected" for signature #%d: %w`, i+1, err) + } + if wrote { + buf.WriteRune(tokens.Comma) + } + buf.WriteString(`"protected":"`) + buf.WriteString(base64.EncodeToString(protectedbuf)) + buf.WriteRune('"') + wrote = true + } + + if len(sig.signature) > 0 { + // If InsecureNoSignature is enabled, signature may not exist + if wrote { + buf.WriteRune(tokens.Comma) + } + buf.WriteString(`"signature":"`) + buf.WriteString(base64.EncodeToString(sig.signature)) + buf.WriteString(`"`) + } + buf.WriteString(`}`) + } + buf.WriteString(`]}`) + + ret := make([]byte, buf.Len()) + copy(ret, buf.Bytes()) + return ret, nil +} + +// Compact generates a JWS message in compact serialization format from +// `*jws.Message` object. The object contain exactly one signature, or +// an error is returned. +// +// If using a detached payload, the payload must already be stored in +// the `*jws.Message` object, and the `jws.WithDetached()` option +// must be passed to the function. +func Compact(msg *Message, options ...CompactOption) ([]byte, error) { + if l := len(msg.signatures); l != 1 { + return nil, fmt.Errorf(`jws.Compact: cannot serialize message with %d signatures (must be one)`, l) + } + + var detached bool + var encoder Base64Encoder = base64.DefaultEncoder() + for _, option := range options { + switch option.Ident() { + case identDetached{}: + if err := option.Value(&detached); err != nil { + return nil, fmt.Errorf(`jws.Compact: failed to retrieve detached option value: %w`, err) + } + case identBase64Encoder{}: + if err := option.Value(&encoder); err != nil { + return nil, fmt.Errorf(`jws.Compact: failed to retrieve base64 encoder option value: %w`, err) + } + } + } + + s := msg.signatures[0] + // XXX check if this is correct + hdrs := s.ProtectedHeaders() + + hdrbuf, err := json.Marshal(hdrs) + if err != nil { + return nil, fmt.Errorf(`jws.Compress: failed to marshal headers: %w`, err) + } + + buf := pool.BytesBuffer().Get() + defer pool.BytesBuffer().Put(buf) + + buf.WriteString(encoder.EncodeToString(hdrbuf)) + buf.WriteByte(tokens.Period) + + if !detached { + if getB64Value(hdrs) { + encoded := encoder.EncodeToString(msg.payload) + buf.WriteString(encoded) + } else { + if bytes.Contains(msg.payload, []byte{tokens.Period}) { + return nil, fmt.Errorf(`jws.Compress: payload must not contain a "."`) + } + buf.Write(msg.payload) + } + } + + buf.WriteByte(tokens.Period) + buf.WriteString(encoder.EncodeToString(s.signature)) + ret := make([]byte, buf.Len()) + copy(ret, buf.Bytes()) + return ret, nil +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jws/options.go b/vendor/github.com/lestrrat-go/jwx/v3/jws/options.go new file mode 100644 index 00000000000..729e561936b --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jws/options.go @@ -0,0 +1,259 @@ +package jws + +import ( + "github.com/lestrrat-go/jwx/v3/jwa" + "github.com/lestrrat-go/jwx/v3/jwk" + "github.com/lestrrat-go/option/v2" +) + +type identInsecureNoSignature struct{} + +// WithJSON specifies that the result of `jws.Sign()` is serialized in +// JSON format. +// +// If you pass multiple keys to `jws.Sign()`, it will fail unless +// you also pass this option. +func WithJSON(options ...WithJSONSuboption) SignVerifyParseOption { + var pretty bool + for _, option := range options { + switch option.Ident() { + case identPretty{}: + if err := option.Value(&pretty); err != nil { + panic(`jws.WithJSON() option must be of type bool`) + } + } + } + + format := fmtJSON + if pretty { + format = fmtJSONPretty + } + return &signVerifyParseOption{option.New(identSerialization{}, format)} +} + +type withKey struct { + alg jwa.KeyAlgorithm + key any + protected Headers + public Headers +} + +// This exists as an escape hatch to modify the header values after the fact +func (w *withKey) Protected(v Headers) Headers { + if w.protected == nil && v != nil { + w.protected = v + } + return w.protected +} + +// WithKey is used to pass a static algorithm/key pair to either `jws.Sign()` or `jws.Verify()`. +// +// The `alg` parameter is the identifier for the signature algorithm that should be used. +// It is of type `jwa.KeyAlgorithm` but in reality you can only pass `jwa.SignatureAlgorithm` +// types. It is this way so that the value in `(jwk.Key).Algorithm()` can be directly +// passed to the option. If you specify other algorithm types such as `jwa.KeyEncryptionAlgorithm`, +// then you will get an error when `jws.Sign()` or `jws.Verify()` is executed. +// +// The `alg` parameter cannot be "none" (jwa.NoSignature) for security reasons. +// You will have to use a separate, more explicit option to allow the use of "none" +// algorithm (WithInsecureNoSignature). +// +// The algorithm specified in the `alg` parameter MUST be able to support +// the type of key you provided, otherwise an error is returned. +// +// Any of the following is accepted for the `key` parameter: +// * A "raw" key (e.g. rsa.PrivateKey, ecdsa.PrivateKey, etc) +// * A crypto.Signer +// * A jwk.Key +// +// Note that due to technical reasons, this library is NOT able to differentiate +// between a valid/invalid key for given algorithm if the key implements crypto.Signer +// and the key is from an external library. For example, while we can tell that it is +// invalid to use `jwk.WithKey(jwa.RSA256, ecdsaPrivateKey)` because the key is +// presumably from `crypto/ecdsa` or this library, if you use a KMS wrapper +// that implements crypto.Signer that is outside of the go standard library or this +// library, we will not be able to properly catch the misuse of such keys -- +// the output will happily generate an ECDSA signature even in the presence of +// `jwa.RSA256` +// +// A `crypto.Signer` is used when the private part of a key is +// kept in an inaccessible location, such as hardware. +// `crypto.Signer` is currently supported for RSA, ECDSA, and EdDSA +// family of algorithms. You may consider using `github.com/jwx-go/crypto-signer` +// if you would like to use keys stored in GCP/AWS KMS services. +// +// If the key is a jwk.Key and the key contains a key ID (`kid` field), +// then it is added to the protected header generated by the signature. +// +// `jws.WithKey()` can further accept suboptions to change signing behavior +// when used with `jws.Sign()`. `jws.WithProtected()` and `jws.WithPublic()` +// can be passed to specify JWS headers that should be used whe signing. +// +// If the protected headers contain "b64" field, then the boolean value for the field +// is respected when serializing. That is, if you specify a header with +// `{"b64": false}`, then the payload is not base64 encoded. +// +// These suboptions are ignored when the `jws.WithKey()` option is used with `jws.Verify()`. +func WithKey(alg jwa.KeyAlgorithm, key any, options ...WithKeySuboption) SignVerifyOption { + // Implementation note: this option is shared between Sign() and + // Verify(). As such we don't create a KeyProvider here because + // if used in Sign() we would be doing something else. + var protected, public Headers + for _, option := range options { + switch option.Ident() { + case identProtectedHeaders{}: + if err := option.Value(&protected); err != nil { + panic(`jws.WithKey() option must be of type Headers`) + } + case identPublicHeaders{}: + if err := option.Value(&public); err != nil { + panic(`jws.WithKey() option must be of type Headers`) + } + } + } + + return &signVerifyOption{ + option.New(identKey{}, &withKey{ + alg: alg, + key: key, + protected: protected, + public: public, + }), + } +} + +// WithKeySet specifies a JWKS (jwk.Set) to use for verification. +// +// Because a JWKS can contain multiple keys and this library cannot tell +// which one of the keys should be used for verification, we by default +// require that both `alg` and `kid` fields in the JWS _and_ the +// key match before a key is considered to be used. +// +// There are ways to override this behavior, but they must be explicitly +// specified by the caller. +// +// To work with keys/JWS messages not having a `kid` field, you may specify +// the suboption `WithKeySetRequired` via `jws.WithKey(key, jws.WithRequireKid(false))`. +// This will allow the library to proceed without having to match the `kid` field. +// +// However, it will still check if the `alg` fields in the JWS message and the key(s) +// match. If you must work with JWS messages that do not have an `alg` field, +// you will need to use `jws.WithKeySet(key, jws.WithInferAlgorithm(true))`. +// +// See the documentation for `WithInferAlgorithm()` for more details. +func WithKeySet(set jwk.Set, options ...WithKeySetSuboption) VerifyOption { + requireKid := true + var useDefault, inferAlgorithm, multipleKeysPerKeyID bool + for _, option := range options { + switch option.Ident() { + case identRequireKid{}: + if err := option.Value(&requireKid); err != nil { + panic(`jws.WithKeySet() option must be of type bool`) + } + case identUseDefault{}: + if err := option.Value(&useDefault); err != nil { + panic(`jws.WithKeySet() option must be of type bool`) + } + case identMultipleKeysPerKeyID{}: + if err := option.Value(&multipleKeysPerKeyID); err != nil { + panic(`jws.WithKeySet() option must be of type bool`) + } + case identInferAlgorithmFromKey{}: + if err := option.Value(&inferAlgorithm); err != nil { + panic(`jws.WithKeySet() option must be of type bool`) + } + } + } + + return WithKeyProvider(&keySetProvider{ + set: set, + requireKid: requireKid, + useDefault: useDefault, + multipleKeysPerKeyID: multipleKeysPerKeyID, + inferAlgorithm: inferAlgorithm, + }) +} + +// WithVerifyAuto enables automatic verification of the signature using the JWKS specified in +// the `jku` header. Note that by default this option will _reject_ any jku +// provided by the JWS message. Read on for details. +// +// The JWKS is retrieved by the `jwk.Fetcher` specified in the first argument. +// If the fetcher object is nil, the default fetcher, which is the `jwk.Fetch()` +// function (wrapped in the `jwk.FetchFunc` type) is used. +// +// The remaining arguments are passed to the `(jwk.Fetcher).Fetch` method +// when the JWKS is retrieved. +// +// jws.WithVerifyAuto(nil) // uses jwk.Fetch +// jws.WithVerifyAuto(jwk.NewCachedFetcher(...)) // uses cached fetcher +// jws.WithVerifyAuto(myFetcher) // use your custom fetcher +// +// By default a whitelist that disallows all URLs is added to the options +// passed to the fetcher. You must explicitly specify a whitelist that allows +// the URLs you trust. This default behavior is provided because by design +// of the JWS specification it is the/ caller's responsibility to verify if +// the URL specified in the `jku` header can be trusted -- thus by default +// we trust nothing. +// +// Users are free to specify an open whitelist if they so choose, but this must +// be explicitly done: +// +// jws.WithVerifyAuto(nil, jwk.WithFetchWhitelist(jwk.InsecureWhitelist())) +// +// You can also use `jwk.CachedFetcher` to use cached JWKS objects, but do note +// that this object is not really designed to accommodate a large set of +// arbitrary URLs. Use `jwk.CachedFetcher` as the first argument if you only +// have a small set of URLs that you trust. For anything more complex, you should +// implement your own `jwk.Fetcher` object. +func WithVerifyAuto(f jwk.Fetcher, options ...jwk.FetchOption) VerifyOption { + // the option MUST start with a "disallow no whitelist" to force + // users provide a whitelist + options = append(append([]jwk.FetchOption(nil), jwk.WithFetchWhitelist(allowNoneWhitelist)), options...) + + return WithKeyProvider(jkuProvider{ + fetcher: f, + options: options, + }) +} + +type withInsecureNoSignature struct { + protected Headers +} + +// This exists as an escape hatch to modify the header values after the fact +func (w *withInsecureNoSignature) Protected(v Headers) Headers { + if w.protected == nil && v != nil { + w.protected = v + } + return w.protected +} + +// WithInsecureNoSignature creates an option that allows the user to use the +// "none" signature algorithm. +// +// Please note that this is insecure, and should never be used in production +// (this is exactly why specifying "none"/jwa.NoSignature to `jws.WithKey()` +// results in an error when `jws.Sign()` is called -- we do not allow using +// "none" by accident) +// +// TODO: create specific suboption set for this option +func WithInsecureNoSignature(options ...WithKeySuboption) SignOption { + var protected Headers + for _, option := range options { + switch option.Ident() { + case identProtectedHeaders{}: + if err := option.Value(&protected); err != nil { + panic(`jws.WithInsecureNoSignature() option must be of type Headers`) + } + } + } + + return &signOption{ + option.New(identInsecureNoSignature{}, + &withInsecureNoSignature{ + protected: protected, + }, + ), + } +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jws/options.yaml b/vendor/github.com/lestrrat-go/jwx/v3/jws/options.yaml new file mode 100644 index 00000000000..303ab3a32e9 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jws/options.yaml @@ -0,0 +1,234 @@ +package_name: jws +output: jws/options_gen.go +interfaces: + - name: CompactOption + comment: | + CompactOption describes options that can be passed to `jws.Compact` + - name: VerifyOption + comment: | + VerifyOption describes options that can be passed to `jws.Verify` + methods: + - verifyOption + - parseOption + - name: SignOption + comment: | + SignOption describes options that can be passed to `jws.Sign` + - name: SignVerifyOption + methods: + - signOption + - verifyOption + - parseOption + comment: | + SignVerifyOption describes options that can be passed to either `jws.Verify` or `jws.Sign` + - name: SignVerifyCompactOption + methods: + - signOption + - verifyOption + - compactOption + - parseOption + comment: | + SignVerifyCompactOption describes options that can be passed to either `jws.Verify`, + `jws.Sign`, or `jws.Compact` + - name: WithJSONSuboption + concrete_type: withJSONSuboption + comment: | + JSONSuboption describes suboptions that can be passed to the `jws.WithJSON()` option. + - name: WithKeySuboption + comment: | + WithKeySuboption describes option types that can be passed to the `jws.WithKey()` + option. + - name: WithKeySetSuboption + comment: | + WithKeySetSuboption is a suboption passed to the `jws.WithKeySet()` option + - name: ParseOption + methods: + - readFileOption + comment: | + ReadFileOption is a type of `Option` that can be passed to `jwe.Parse` + - name: ReadFileOption + comment: | + ReadFileOption is a type of `Option` that can be passed to `jws.ReadFile` + - name: SignVerifyParseOption + methods: + - signOption + - verifyOption + - parseOption + - readFileOption + - name: GlobalOption + comment: | + GlobalOption can be passed to `jws.Settings()` to set global options for the JWS package. +options: + - ident: Key + skip_option: true + - ident: Serialization + skip_option: true + - ident: Serialization + option_name: WithCompact + interface: SignVerifyParseOption + constant_value: fmtCompact + comment: | + WithCompact specifies that the result of `jws.Sign()` is serialized in + compact format. + + By default `jws.Sign()` will opt to use compact format, so you usually + do not need to specify this option other than to be explicit about it + - ident: Detached + interface: CompactOption + argument_type: bool + comment: | + WithDetached specifies that the `jws.Message` should be serialized in + JWS compact serialization with detached payload. The resulting octet + sequence will not contain the payload section. + + - ident: DetachedPayload + interface: SignVerifyOption + argument_type: '[]byte' + comment: | + WithDetachedPayload can be used to both sign or verify a JWS message with a + detached payload. + Note that this option does NOT populate the `b64` header, which is sometimes + required by other JWS implementations. + + + When this option is used for `jws.Sign()`, the first parameter (normally the payload) + must be set to `nil`. + + If you have to verify using this option, you should know exactly how and why this works. + - ident: Base64Encoder + interface: SignVerifyCompactOption + argument_type: Base64Encoder + comment: | + WithBase64Encoder specifies the base64 encoder to be used while signing or + verifying the JWS message. By default, the raw URL base64 encoding (no padding) + is used. + - ident: Message + interface: VerifyOption + argument_type: '*Message' + comment: | + WithMessage can be passed to Verify() to obtain the jws.Message upon + a successful verification. + - ident: KeyUsed + interface: VerifyOption + argument_type: 'any' + comment: | + WithKeyUsed allows you to specify the `jws.Verify()` function to + return the key used for verification. This may be useful when + you specify multiple key sources or if you pass a `jwk.Set` + and you want to know which key was successful at verifying the + signature. + + `v` must be a pointer to an empty `any`. Do not use + `jwk.Key` here unless you are 100% sure that all keys that you + have provided are instances of `jwk.Key` (remember that the + jwx API allows users to specify a raw key such as *rsa.PublicKey) + - ident: ValidateKey + interface: SignVerifyOption + argument_type: bool + comment: | + WithValidateKey specifies whether the key used for signing or verification + should be validated before using. Note that this means calling + `key.Validate()` on the key, which in turn means that your key + must be a `jwk.Key` instance, or a key that can be converted to + a `jwk.Key` by calling `jwk.Import()`. This means that your + custom hardware-backed keys will probably not work. + + You can directly call `key.Validate()` yourself if you need to + mix keys that cannot be converted to `jwk.Key`. + + Please also note that use of this option will also result in + one extra conversion of raw keys to a `jwk.Key` instance. If you + care about shaving off as much as possible, consider using a + pre-validated key instead of using this option to validate + the key on-demand each time. + + By default, the key is not validated. + - ident: InferAlgorithmFromKey + interface: WithKeySetSuboption + argument_type: bool + comment: | + WithInferAlgorithmFromKey specifies whether the JWS signing algorithm name + should be inferred by looking at the provided key, in case the JWS + message or the key does not have a proper `alg` header. + + When this option is set to true, a list of algorithm(s) that is compatible + with the key type will be enumerated, and _ALL_ of them will be tried + against the key/message pair. If any of them succeeds, the verification + will be considered successful. + + Compared to providing explicit `alg` from the key this is slower, and + verification may fail to verify if somehow our heuristics are wrong + or outdated. + + Also, automatic detection of signature verification methods are always + more vulnerable for potential attack vectors. + + It is highly recommended that you fix your key to contain a proper `alg` + header field instead of resorting to using this option, but sometimes + it just needs to happen. + - ident: UseDefault + interface: WithKeySetSuboption + argument_type: bool + comment: | + WithUseDefault specifies that if and only if a jwk.Key contains + exactly one jwk.Key, that key should be used. + - ident: RequireKid + interface: WithKeySetSuboption + argument_type: bool + comment: | + WithRequiredKid specifies whether the keys in the jwk.Set should + only be matched if the target JWS message's Key ID and the Key ID + in the given key matches. + - ident: MultipleKeysPerKeyID + interface: WithKeySetSuboption + argument_type: bool + comment: | + WithMultipleKeysPerKeyID specifies if we should expect multiple keys + to match against a key ID. By default it is assumed that key IDs are + unique, i.e. for a given key ID, the key set only contains a single + key that has the matching ID. When this option is set to true, + multiple keys that match the same key ID in the set can be tried. + - ident: Pretty + interface: WithJSONSuboption + argument_type: bool + comment: | + WithPretty specifies whether the JSON output should be formatted and + indented + - ident: KeyProvider + interface: VerifyOption + argument_type: KeyProvider + - ident: Context + interface: VerifyOption + argument_type: context.Context + - ident: ProtectedHeaders + interface: WithKeySuboption + argument_type: Headers + comment: | + WithProtected is used with `jws.WithKey()` option when used with `jws.Sign()` + to specify a protected header to be attached to the JWS signature. + + It has no effect if used when `jws.WithKey()` is passed to `jws.Verify()` + - ident: PublicHeaders + interface: WithKeySuboption + argument_type: Headers + comment: | + WithPublic is used with `jws.WithKey()` option when used with `jws.Sign()` + to specify a public header to be attached to the JWS signature. + + It has no effect if used when `jws.WithKey()` is passed to `jws.Verify()` + + `jws.Sign()` will result in an error if `jws.WithPublic()` is used + and the serialization format is compact serialization. + - ident: FS + interface: ReadFileOption + argument_type: fs.FS + comment: | + WithFS specifies the source `fs.FS` object to read the file from. + - ident: LegacySigners + interface: GlobalOption + constant_value: true + comment: | + WithLegacySigners specifies whether the JWS package should use legacy + signers for signing JWS messages. + + Usually there's no need to use this option, as the new signers and + verifiers are loaded by default. diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jws/options_gen.go b/vendor/github.com/lestrrat-go/jwx/v3/jws/options_gen.go new file mode 100644 index 00000000000..b97cf7e8dd9 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jws/options_gen.go @@ -0,0 +1,449 @@ +// Code generated by tools/cmd/genoptions/main.go. DO NOT EDIT. + +package jws + +import ( + "context" + "io/fs" + + "github.com/lestrrat-go/option/v2" +) + +type Option = option.Interface + +// CompactOption describes options that can be passed to `jws.Compact` +type CompactOption interface { + Option + compactOption() +} + +type compactOption struct { + Option +} + +func (*compactOption) compactOption() {} + +// GlobalOption can be passed to `jws.Settings()` to set global options for the JWS package. +type GlobalOption interface { + Option + globalOption() +} + +type globalOption struct { + Option +} + +func (*globalOption) globalOption() {} + +// ReadFileOption is a type of `Option` that can be passed to `jwe.Parse` +type ParseOption interface { + Option + readFileOption() +} + +type parseOption struct { + Option +} + +func (*parseOption) readFileOption() {} + +// ReadFileOption is a type of `Option` that can be passed to `jws.ReadFile` +type ReadFileOption interface { + Option + readFileOption() +} + +type readFileOption struct { + Option +} + +func (*readFileOption) readFileOption() {} + +// SignOption describes options that can be passed to `jws.Sign` +type SignOption interface { + Option + signOption() +} + +type signOption struct { + Option +} + +func (*signOption) signOption() {} + +// SignVerifyCompactOption describes options that can be passed to either `jws.Verify`, +// `jws.Sign`, or `jws.Compact` +type SignVerifyCompactOption interface { + Option + signOption() + verifyOption() + compactOption() + parseOption() +} + +type signVerifyCompactOption struct { + Option +} + +func (*signVerifyCompactOption) signOption() {} + +func (*signVerifyCompactOption) verifyOption() {} + +func (*signVerifyCompactOption) compactOption() {} + +func (*signVerifyCompactOption) parseOption() {} + +// SignVerifyOption describes options that can be passed to either `jws.Verify` or `jws.Sign` +type SignVerifyOption interface { + Option + signOption() + verifyOption() + parseOption() +} + +type signVerifyOption struct { + Option +} + +func (*signVerifyOption) signOption() {} + +func (*signVerifyOption) verifyOption() {} + +func (*signVerifyOption) parseOption() {} + +type SignVerifyParseOption interface { + Option + signOption() + verifyOption() + parseOption() + readFileOption() +} + +type signVerifyParseOption struct { + Option +} + +func (*signVerifyParseOption) signOption() {} + +func (*signVerifyParseOption) verifyOption() {} + +func (*signVerifyParseOption) parseOption() {} + +func (*signVerifyParseOption) readFileOption() {} + +// VerifyOption describes options that can be passed to `jws.Verify` +type VerifyOption interface { + Option + verifyOption() + parseOption() +} + +type verifyOption struct { + Option +} + +func (*verifyOption) verifyOption() {} + +func (*verifyOption) parseOption() {} + +// JSONSuboption describes suboptions that can be passed to the `jws.WithJSON()` option. +type WithJSONSuboption interface { + Option + withJSONSuboption() +} + +type withJSONSuboption struct { + Option +} + +func (*withJSONSuboption) withJSONSuboption() {} + +// WithKeySetSuboption is a suboption passed to the `jws.WithKeySet()` option +type WithKeySetSuboption interface { + Option + withKeySetSuboption() +} + +type withKeySetSuboption struct { + Option +} + +func (*withKeySetSuboption) withKeySetSuboption() {} + +// WithKeySuboption describes option types that can be passed to the `jws.WithKey()` +// option. +type WithKeySuboption interface { + Option + withKeySuboption() +} + +type withKeySuboption struct { + Option +} + +func (*withKeySuboption) withKeySuboption() {} + +type identBase64Encoder struct{} +type identContext struct{} +type identDetached struct{} +type identDetachedPayload struct{} +type identFS struct{} +type identInferAlgorithmFromKey struct{} +type identKey struct{} +type identKeyProvider struct{} +type identKeyUsed struct{} +type identLegacySigners struct{} +type identMessage struct{} +type identMultipleKeysPerKeyID struct{} +type identPretty struct{} +type identProtectedHeaders struct{} +type identPublicHeaders struct{} +type identRequireKid struct{} +type identSerialization struct{} +type identUseDefault struct{} +type identValidateKey struct{} + +func (identBase64Encoder) String() string { + return "WithBase64Encoder" +} + +func (identContext) String() string { + return "WithContext" +} + +func (identDetached) String() string { + return "WithDetached" +} + +func (identDetachedPayload) String() string { + return "WithDetachedPayload" +} + +func (identFS) String() string { + return "WithFS" +} + +func (identInferAlgorithmFromKey) String() string { + return "WithInferAlgorithmFromKey" +} + +func (identKey) String() string { + return "WithKey" +} + +func (identKeyProvider) String() string { + return "WithKeyProvider" +} + +func (identKeyUsed) String() string { + return "WithKeyUsed" +} + +func (identLegacySigners) String() string { + return "WithLegacySigners" +} + +func (identMessage) String() string { + return "WithMessage" +} + +func (identMultipleKeysPerKeyID) String() string { + return "WithMultipleKeysPerKeyID" +} + +func (identPretty) String() string { + return "WithPretty" +} + +func (identProtectedHeaders) String() string { + return "WithProtectedHeaders" +} + +func (identPublicHeaders) String() string { + return "WithPublicHeaders" +} + +func (identRequireKid) String() string { + return "WithRequireKid" +} + +func (identSerialization) String() string { + return "WithSerialization" +} + +func (identUseDefault) String() string { + return "WithUseDefault" +} + +func (identValidateKey) String() string { + return "WithValidateKey" +} + +// WithBase64Encoder specifies the base64 encoder to be used while signing or +// verifying the JWS message. By default, the raw URL base64 encoding (no padding) +// is used. +func WithBase64Encoder(v Base64Encoder) SignVerifyCompactOption { + return &signVerifyCompactOption{option.New(identBase64Encoder{}, v)} +} + +func WithContext(v context.Context) VerifyOption { + return &verifyOption{option.New(identContext{}, v)} +} + +// WithDetached specifies that the `jws.Message` should be serialized in +// JWS compact serialization with detached payload. The resulting octet +// sequence will not contain the payload section. +func WithDetached(v bool) CompactOption { + return &compactOption{option.New(identDetached{}, v)} +} + +// WithDetachedPayload can be used to both sign or verify a JWS message with a +// detached payload. +// Note that this option does NOT populate the `b64` header, which is sometimes +// required by other JWS implementations. +// +// When this option is used for `jws.Sign()`, the first parameter (normally the payload) +// must be set to `nil`. +// +// If you have to verify using this option, you should know exactly how and why this works. +func WithDetachedPayload(v []byte) SignVerifyOption { + return &signVerifyOption{option.New(identDetachedPayload{}, v)} +} + +// WithFS specifies the source `fs.FS` object to read the file from. +func WithFS(v fs.FS) ReadFileOption { + return &readFileOption{option.New(identFS{}, v)} +} + +// WithInferAlgorithmFromKey specifies whether the JWS signing algorithm name +// should be inferred by looking at the provided key, in case the JWS +// message or the key does not have a proper `alg` header. +// +// When this option is set to true, a list of algorithm(s) that is compatible +// with the key type will be enumerated, and _ALL_ of them will be tried +// against the key/message pair. If any of them succeeds, the verification +// will be considered successful. +// +// Compared to providing explicit `alg` from the key this is slower, and +// verification may fail to verify if somehow our heuristics are wrong +// or outdated. +// +// Also, automatic detection of signature verification methods are always +// more vulnerable for potential attack vectors. +// +// It is highly recommended that you fix your key to contain a proper `alg` +// header field instead of resorting to using this option, but sometimes +// it just needs to happen. +func WithInferAlgorithmFromKey(v bool) WithKeySetSuboption { + return &withKeySetSuboption{option.New(identInferAlgorithmFromKey{}, v)} +} + +func WithKeyProvider(v KeyProvider) VerifyOption { + return &verifyOption{option.New(identKeyProvider{}, v)} +} + +// WithKeyUsed allows you to specify the `jws.Verify()` function to +// return the key used for verification. This may be useful when +// you specify multiple key sources or if you pass a `jwk.Set` +// and you want to know which key was successful at verifying the +// signature. +// +// `v` must be a pointer to an empty `any`. Do not use +// `jwk.Key` here unless you are 100% sure that all keys that you +// have provided are instances of `jwk.Key` (remember that the +// jwx API allows users to specify a raw key such as *rsa.PublicKey) +func WithKeyUsed(v any) VerifyOption { + return &verifyOption{option.New(identKeyUsed{}, v)} +} + +// WithLegacySigners specifies whether the JWS package should use legacy +// signers for signing JWS messages. +// +// Usually there's no need to use this option, as the new signers and +// verifiers are loaded by default. +func WithLegacySigners() GlobalOption { + return &globalOption{option.New(identLegacySigners{}, true)} +} + +// WithMessage can be passed to Verify() to obtain the jws.Message upon +// a successful verification. +func WithMessage(v *Message) VerifyOption { + return &verifyOption{option.New(identMessage{}, v)} +} + +// WithMultipleKeysPerKeyID specifies if we should expect multiple keys +// to match against a key ID. By default it is assumed that key IDs are +// unique, i.e. for a given key ID, the key set only contains a single +// key that has the matching ID. When this option is set to true, +// multiple keys that match the same key ID in the set can be tried. +func WithMultipleKeysPerKeyID(v bool) WithKeySetSuboption { + return &withKeySetSuboption{option.New(identMultipleKeysPerKeyID{}, v)} +} + +// WithPretty specifies whether the JSON output should be formatted and +// indented +func WithPretty(v bool) WithJSONSuboption { + return &withJSONSuboption{option.New(identPretty{}, v)} +} + +// WithProtected is used with `jws.WithKey()` option when used with `jws.Sign()` +// to specify a protected header to be attached to the JWS signature. +// +// It has no effect if used when `jws.WithKey()` is passed to `jws.Verify()` +func WithProtectedHeaders(v Headers) WithKeySuboption { + return &withKeySuboption{option.New(identProtectedHeaders{}, v)} +} + +// WithPublic is used with `jws.WithKey()` option when used with `jws.Sign()` +// to specify a public header to be attached to the JWS signature. +// +// It has no effect if used when `jws.WithKey()` is passed to `jws.Verify()` +// +// `jws.Sign()` will result in an error if `jws.WithPublic()` is used +// and the serialization format is compact serialization. +func WithPublicHeaders(v Headers) WithKeySuboption { + return &withKeySuboption{option.New(identPublicHeaders{}, v)} +} + +// WithRequiredKid specifies whether the keys in the jwk.Set should +// only be matched if the target JWS message's Key ID and the Key ID +// in the given key matches. +func WithRequireKid(v bool) WithKeySetSuboption { + return &withKeySetSuboption{option.New(identRequireKid{}, v)} +} + +// WithCompact specifies that the result of `jws.Sign()` is serialized in +// compact format. +// +// By default `jws.Sign()` will opt to use compact format, so you usually +// do not need to specify this option other than to be explicit about it +func WithCompact() SignVerifyParseOption { + return &signVerifyParseOption{option.New(identSerialization{}, fmtCompact)} +} + +// WithUseDefault specifies that if and only if a jwk.Key contains +// exactly one jwk.Key, that key should be used. +func WithUseDefault(v bool) WithKeySetSuboption { + return &withKeySetSuboption{option.New(identUseDefault{}, v)} +} + +// WithValidateKey specifies whether the key used for signing or verification +// should be validated before using. Note that this means calling +// `key.Validate()` on the key, which in turn means that your key +// must be a `jwk.Key` instance, or a key that can be converted to +// a `jwk.Key` by calling `jwk.Import()`. This means that your +// custom hardware-backed keys will probably not work. +// +// You can directly call `key.Validate()` yourself if you need to +// mix keys that cannot be converted to `jwk.Key`. +// +// Please also note that use of this option will also result in +// one extra conversion of raw keys to a `jwk.Key` instance. If you +// care about shaving off as much as possible, consider using a +// pre-validated key instead of using this option to validate +// the key on-demand each time. +// +// By default, the key is not validated. +func WithValidateKey(v bool) SignVerifyOption { + return &signVerifyOption{option.New(identValidateKey{}, v)} +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jws/sign_context.go b/vendor/github.com/lestrrat-go/jwx/v3/jws/sign_context.go new file mode 100644 index 00000000000..49abe0abca6 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jws/sign_context.go @@ -0,0 +1,141 @@ +package jws + +import ( + "fmt" + + "github.com/lestrrat-go/jwx/v3/internal/base64" + "github.com/lestrrat-go/jwx/v3/internal/pool" + "github.com/lestrrat-go/jwx/v3/jwa" +) + +type signContext struct { + format int + detached bool + validateKey bool + payload []byte + encoder Base64Encoder + none *signatureBuilder // special signature builder + sigbuilders []*signatureBuilder +} + +var signContextPool = pool.New[*signContext](allocSignContext, freeSignContext) + +func allocSignContext() *signContext { + return &signContext{ + format: fmtCompact, + sigbuilders: make([]*signatureBuilder, 0, 1), + encoder: base64.DefaultEncoder(), + } +} + +func freeSignContext(ctx *signContext) *signContext { + ctx.format = fmtCompact + for _, sb := range ctx.sigbuilders { + signatureBuilderPool.Put(sb) + } + ctx.sigbuilders = ctx.sigbuilders[:0] + ctx.detached = false + ctx.validateKey = false + ctx.encoder = base64.DefaultEncoder() + ctx.none = nil + ctx.payload = nil + + return ctx +} + +func (sc *signContext) ProcessOptions(options []SignOption) error { + for _, option := range options { + switch option.Ident() { + case identSerialization{}: + if err := option.Value(&sc.format); err != nil { + return signerr(`failed to retrieve serialization option value: %w`, err) + } + case identInsecureNoSignature{}: + var data withInsecureNoSignature + if err := option.Value(&data); err != nil { + return signerr(`failed to retrieve insecure-no-signature option value: %w`, err) + } + sb := signatureBuilderPool.Get() + sb.alg = jwa.NoSignature() + sb.protected = data.protected + sb.signer = noneSigner{} + sc.none = sb + sc.sigbuilders = append(sc.sigbuilders, sb) + case identKey{}: + var data *withKey + if err := option.Value(&data); err != nil { + return signerr(`jws.Sign: invalid value for WithKey option: %w`, err) + } + + alg, ok := data.alg.(jwa.SignatureAlgorithm) + if !ok { + return signerr(`expected algorithm to be of type jwa.SignatureAlgorithm but got (%[1]q, %[1]T)`, data.alg) + } + + // No, we don't accept "none" here. + if alg == jwa.NoSignature() { + return signerr(`"none" (jwa.NoSignature) cannot be used with jws.WithKey`) + } + + sb := signatureBuilderPool.Get() + sb.alg = alg + sb.protected = data.protected + sb.key = data.key + sb.public = data.public + + s2, err := SignerFor(alg) + if err == nil { + sb.signer2 = s2 + } else { + s1, err := legacySignerFor(alg) + if err != nil { + sb.signer2 = defaultSigner{alg: alg} + } else { + sb.signer = s1 + } + } + + sc.sigbuilders = append(sc.sigbuilders, sb) + case identDetachedPayload{}: + if sc.payload != nil { + return signerr(`payload must be nil when jws.WithDetachedPayload() is specified`) + } + if err := option.Value(&sc.payload); err != nil { + return signerr(`failed to retrieve detached payload option value: %w`, err) + } + sc.detached = true + case identValidateKey{}: + if err := option.Value(&sc.validateKey); err != nil { + return signerr(`failed to retrieve validate-key option value: %w`, err) + } + case identBase64Encoder{}: + if err := option.Value(&sc.encoder); err != nil { + return signerr(`failed to retrieve base64-encoder option value: %w`, err) + } + } + } + return nil +} + +func (sc *signContext) PopulateMessage(m *Message) error { + m.payload = sc.payload + m.signatures = make([]*Signature, 0, len(sc.sigbuilders)) + + for i, sb := range sc.sigbuilders { + // Create signature for each builders + if sc.validateKey { + if err := validateKeyBeforeUse(sb.key); err != nil { + return fmt.Errorf(`failed to validate key for signature %d: %w`, i, err) + } + } + + sig, err := sb.Build(sc, m.payload) + if err != nil { + return fmt.Errorf(`failed to build signature %d: %w`, i, err) + } + + m.signatures = append(m.signatures, sig) + } + + return nil +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jws/signature_builder.go b/vendor/github.com/lestrrat-go/jwx/v3/jws/signature_builder.go new file mode 100644 index 00000000000..fc09a693670 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jws/signature_builder.go @@ -0,0 +1,118 @@ +package jws + +import ( + "bytes" + "fmt" + + "github.com/lestrrat-go/jwx/v3/internal/json" + "github.com/lestrrat-go/jwx/v3/internal/pool" + "github.com/lestrrat-go/jwx/v3/internal/tokens" + "github.com/lestrrat-go/jwx/v3/jwa" + "github.com/lestrrat-go/jwx/v3/jwk" + "github.com/lestrrat-go/jwx/v3/jws/jwsbb" +) + +var signatureBuilderPool = pool.New[*signatureBuilder](allocSignatureBuilder, freeSignatureBuilder) + +// signatureBuilder is a transient object that is used to build +// a single JWS signature. +// +// In a multi-signature JWS message, each message is paired with +// the following: +// - a signer (the object that takes a buffer and key and generates a signature) +// - a key (the key that is used to sign the payload) +// - protected headers (the headers that are protected by the signature) +// - public headers (the headers that are not protected by the signature) +// +// This object stores all of this information in one place. +// +// This object does NOT take care of any synchronization, because it is +// meant to be used in a single-threaded context. +type signatureBuilder struct { + alg jwa.SignatureAlgorithm + signer Signer + signer2 Signer2 + key any + protected Headers + public Headers +} + +func allocSignatureBuilder() *signatureBuilder { + return &signatureBuilder{} +} + +func freeSignatureBuilder(sb *signatureBuilder) *signatureBuilder { + sb.alg = jwa.EmptySignatureAlgorithm() + sb.signer = nil + sb.signer2 = nil + sb.key = nil + sb.protected = nil + sb.public = nil + return sb +} + +func (sb *signatureBuilder) Build(sc *signContext, payload []byte) (*Signature, error) { + protected := sb.protected + if protected == nil { + protected = NewHeaders() + } + + if err := protected.Set(AlgorithmKey, sb.alg); err != nil { + return nil, signerr(`failed to set "alg" header: %w`, err) + } + + if key, ok := sb.key.(jwk.Key); ok { + if kid, ok := key.KeyID(); ok && kid != "" { + if err := protected.Set(KeyIDKey, kid); err != nil { + return nil, signerr(`failed to set "kid" header: %w`, err) + } + } + } + + hdrs, err := mergeHeaders(sb.public, protected) + if err != nil { + return nil, signerr(`failed to merge headers: %w`, err) + } + + // raw, json format headers + hdrbuf, err := json.Marshal(hdrs) + if err != nil { + return nil, fmt.Errorf(`failed to marshal headers: %w`, err) + } + + // check if we need to base64 encode the payload + b64 := getB64Value(hdrs) + if !b64 && !sc.detached { + if bytes.IndexByte(payload, tokens.Period) != -1 { + return nil, fmt.Errorf(`payload must not contain a "."`) + } + } + + combined := jwsbb.SignBuffer(nil, hdrbuf, payload, sc.encoder, b64) + + var sig Signature + sig.protected = protected + sig.headers = sb.public + + if sb.signer2 != nil { + signature, err := sb.signer2.Sign(sb.key, combined) + if err != nil { + return nil, fmt.Errorf(`failed to sign payload: %w`, err) + } + sig.signature = signature + return &sig, nil + } + + if sb.signer == nil { + panic("can't get here") + } + + signature, err := sb.signer.Sign(combined, sb.key) + if err != nil { + return nil, fmt.Errorf(`failed to sign payload: %w`, err) + } + + sig.signature = signature + + return &sig, nil +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jws/signer.go b/vendor/github.com/lestrrat-go/jwx/v3/jws/signer.go new file mode 100644 index 00000000000..340666931f5 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jws/signer.go @@ -0,0 +1,158 @@ +package jws + +import ( + "fmt" + "sync" + + "github.com/lestrrat-go/jwx/v3/jwa" +) + +// Signer2 is an interface that represents a per-signature algorithm signing +// operation. +type Signer2 interface { + Algorithm() jwa.SignatureAlgorithm + + // Sign takes a key and a payload, and returns the signature for the payload. + // The key type is restricted by the signature algorithm that this + // signer is associated with. + // + // (Note to users of legacy Signer interface: the method signature + // is different from the legacy Signer interface) + Sign(key any, payload []byte) ([]byte, error) +} + +var muSigner2DB sync.RWMutex +var signer2DB = make(map[jwa.SignatureAlgorithm]Signer2) + +type SignerFactory interface { + Create() (Signer, error) +} +type SignerFactoryFn func() (Signer, error) + +func (fn SignerFactoryFn) Create() (Signer, error) { + return fn() +} + +// SignerFor returns a Signer2 for the given signature algorithm. +// +// Currently, this function will never fail. It will always return a +// valid Signer2 object. The heuristic is as follows: +// 1. If a Signer2 is registered for the given algorithm, it will return that. +// 2. If a legacy Signer(Factory) is registered for the given algorithm, it will +// return a Signer2 that wraps the legacy Signer. +// 3. If no Signer2 or legacy Signer(Factory) is registered, it will return a +// default signer that uses jwsbb.Sign. +// +// jwsbb.Sign knows how to handle a static set of algorithms, so if the +// algorithm is not supported, it will return an error when you call +// `Sign` on the default signer. +func SignerFor(alg jwa.SignatureAlgorithm) (Signer2, error) { + muSigner2DB.RLock() + defer muSigner2DB.RUnlock() + + signer, ok := signer2DB[alg] + if ok { + return signer, nil + } + + s1, err := legacySignerFor(alg) + if err == nil { + return signerAdapter{signer: s1}, nil + } + + return defaultSigner{alg: alg}, nil +} + +var muSignerDB sync.RWMutex +var signerDB = make(map[jwa.SignatureAlgorithm]SignerFactory) + +// RegisterSigner is used to register a signer for the given +// algorithm. +// +// Please note that this function is intended to be passed a +// signer object as its second argument, but due to historical +// reasons the function signature is defined as taking `any` type. +// +// You should create a signer object that implements the `Signer2` +// interface to register a signer, unless you have legacy code that +// plugged into the `SignerFactory` interface. +// +// Unlike the `UnregisterSigner` function, this function automatically +// calls `jwa.RegisterSignatureAlgorithm` to register the algorithm +// in this module's algorithm database. +func RegisterSigner(alg jwa.SignatureAlgorithm, f any) error { + jwa.RegisterSignatureAlgorithm(alg) + switch s := f.(type) { + case Signer2: + muSigner2DB.Lock() + signer2DB[alg] = s + muSigner2DB.Unlock() + + // delete the other signer, if there was one + muSignerDB.Lock() + delete(signerDB, alg) + muSignerDB.Unlock() + case SignerFactory: + muSignerDB.Lock() + signerDB[alg] = s + muSignerDB.Unlock() + + // Remove previous signer, if there was one + removeSigner(alg) + + muSigner2DB.Lock() + delete(signer2DB, alg) + muSigner2DB.Unlock() + default: + return fmt.Errorf(`jws.RegisterSigner: unsupported type %T for algorithm %q`, f, alg) + } + return nil +} + +// UnregisterSigner removes the signer factory associated with +// the given algorithm, as well as the signer instance created +// by the factory. +// +// Note that when you call this function, the algorithm itself is +// not automatically unregistered from this module's algorithm database. +// This is because the algorithm may still be required for verification or +// some other operation (however unlikely, it is still possible). +// Therefore, in order to completely remove the algorithm, you must +// call `jwa.UnregisterSignatureAlgorithm` yourself. +func UnregisterSigner(alg jwa.SignatureAlgorithm) { + muSigner2DB.Lock() + delete(signer2DB, alg) + muSigner2DB.Unlock() + + muSignerDB.Lock() + delete(signerDB, alg) + muSignerDB.Unlock() + // Remove previous signer + removeSigner(alg) +} + +// NewSigner creates a signer that signs payloads using the given signature algorithm. +// This function is deprecated. You should use `SignerFor()` instead. +// +// This function only exists for backwards compatibility, but will not work +// unless you enable the legacy support mode by calling jws.Settings(jws.WithLegacySigners(true)). +func NewSigner(alg jwa.SignatureAlgorithm) (Signer, error) { + muSignerDB.RLock() + f, ok := signerDB[alg] + muSignerDB.RUnlock() + + if ok { + return f.Create() + } + return nil, fmt.Errorf(`jws.NewSigner: unsupported signature algorithm "%s"`, alg) +} + +type noneSigner struct{} + +func (noneSigner) Algorithm() jwa.SignatureAlgorithm { + return jwa.NoSignature() +} + +func (noneSigner) Sign([]byte, any) ([]byte, error) { + return nil, nil +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jws/verifier.go b/vendor/github.com/lestrrat-go/jwx/v3/jws/verifier.go new file mode 100644 index 00000000000..70b91c29382 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jws/verifier.go @@ -0,0 +1,154 @@ +package jws + +import ( + "fmt" + "sync" + + "github.com/lestrrat-go/jwx/v3/jwa" + "github.com/lestrrat-go/jwx/v3/jws/jwsbb" +) + +type defaultVerifier struct { + alg jwa.SignatureAlgorithm +} + +func (v defaultVerifier) Algorithm() jwa.SignatureAlgorithm { + return v.alg +} + +func (v defaultVerifier) Verify(key any, payload, signature []byte) error { + if err := jwsbb.Verify(key, v.alg.String(), payload, signature); err != nil { + return verifyError{verificationError{err}} + } + return nil +} + +type Verifier2 interface { + Verify(key any, payload, signature []byte) error +} + +var muVerifier2DB sync.RWMutex +var verifier2DB = make(map[jwa.SignatureAlgorithm]Verifier2) + +type verifierAdapter struct { + v Verifier +} + +func (v verifierAdapter) Verify(key any, payload, signature []byte) error { + if err := v.v.Verify(payload, signature, key); err != nil { + return verifyError{verificationError{err}} + } + return nil +} + +// VerifierFor returns a Verifier2 for the given signature algorithm. +// +// Currently, this function will never fail. It will always return a +// valid Verifier2 object. The heuristic is as follows: +// 1. If a Verifier2 is registered for the given algorithm, it will return that. +// 2. If a legacy Verifier(Factory) is registered for the given algorithm, it will +// return a Verifier2 that wraps the legacy Verifier. +// 3. If no Verifier2 or legacy Verifier(Factory) is registered, it will return a +// default verifier that uses jwsbb.Verify. +// +// jwsbb.Verify knows how to handle a static set of algorithms, so if the +// algorithm is not supported, it will return an error when you call +// `Verify` on the default verifier. +func VerifierFor(alg jwa.SignatureAlgorithm) (Verifier2, error) { + muVerifier2DB.RLock() + defer muVerifier2DB.RUnlock() + + v2, ok := verifier2DB[alg] + if ok { + return v2, nil + } + + v1, err := NewVerifier(alg) + if err == nil { + return verifierAdapter{v: v1}, nil + } + + return defaultVerifier{alg: alg}, nil +} + +type VerifierFactory interface { + Create() (Verifier, error) +} +type VerifierFactoryFn func() (Verifier, error) + +func (fn VerifierFactoryFn) Create() (Verifier, error) { + return fn() +} + +var muVerifierDB sync.RWMutex +var verifierDB = make(map[jwa.SignatureAlgorithm]VerifierFactory) + +// RegisterVerifier is used to register a verifier for the given +// algorithm. +// +// Please note that this function is intended to be passed a +// verifier object as its second argument, but due to historical +// reasons the function signature is defined as taking `any` type. +// +// You should create a signer object that implements the `Verifier2` +// interface to register a signer, unless you have legacy code that +// plugged into the `SignerFactory` interface. +// +// Unlike the `UnregisterVerifier` function, this function automatically +// calls `jwa.RegisterSignatureAlgorithm` to register the algorithm +// in this module's algorithm database. +func RegisterVerifier(alg jwa.SignatureAlgorithm, f any) error { + jwa.RegisterSignatureAlgorithm(alg) + switch v := f.(type) { + case Verifier2: + muVerifier2DB.Lock() + verifier2DB[alg] = v + muVerifier2DB.Unlock() + + muVerifierDB.Lock() + delete(verifierDB, alg) + muVerifierDB.Unlock() + case VerifierFactory: + muVerifierDB.Lock() + verifierDB[alg] = v + muVerifierDB.Unlock() + + muVerifier2DB.Lock() + delete(verifier2DB, alg) + muVerifier2DB.Unlock() + default: + return fmt.Errorf(`jws.RegisterVerifier: unsupported type %T for algorithm %q`, f, alg) + } + return nil +} + +// UnregisterVerifier removes the signer factory associated with +// the given algorithm. +// +// Note that when you call this function, the algorithm itself is +// not automatically unregistered from this module's algorithm database. +// This is because the algorithm may still be required for signing or +// some other operation (however unlikely, it is still possible). +// Therefore, in order to completely remove the algorithm, you must +// call `jwa.UnregisterSignatureAlgorithm` yourself. +func UnregisterVerifier(alg jwa.SignatureAlgorithm) { + muVerifier2DB.Lock() + delete(verifier2DB, alg) + muVerifier2DB.Unlock() + + muVerifierDB.Lock() + delete(verifierDB, alg) + muVerifierDB.Unlock() +} + +// NewVerifier creates a verifier that signs payloads using the given signature algorithm. +func NewVerifier(alg jwa.SignatureAlgorithm) (Verifier, error) { + muVerifierDB.RLock() + f, ok := verifierDB[alg] + muVerifierDB.RUnlock() + + if ok { + return f.Create() + } + return nil, fmt.Errorf(`jws.NewVerifier: unsupported signature algorithm "%s"`, alg) +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jws/verify_context.go b/vendor/github.com/lestrrat-go/jwx/v3/jws/verify_context.go new file mode 100644 index 00000000000..b4807d569c8 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jws/verify_context.go @@ -0,0 +1,211 @@ +package jws + +import ( + "context" + "errors" + "fmt" + "strings" + + "github.com/lestrrat-go/blackmagic" + "github.com/lestrrat-go/jwx/v3/internal/base64" + "github.com/lestrrat-go/jwx/v3/internal/json" + "github.com/lestrrat-go/jwx/v3/internal/pool" + "github.com/lestrrat-go/jwx/v3/jwa" + "github.com/lestrrat-go/jwx/v3/jws/jwsbb" +) + +// verifyContext holds the state during JWS verification +type verifyContext struct { + parseOptions []ParseOption + dst *Message + detachedPayload []byte + keyProviders []KeyProvider + keyUsed any + validateKey bool + encoder Base64Encoder + //nolint:containedctx + ctx context.Context +} + +var verifyContextPool = pool.New[*verifyContext](allocVerifyContext, freeVerifyContext) + +func allocVerifyContext() *verifyContext { + return &verifyContext{ + encoder: base64.DefaultEncoder(), + ctx: context.Background(), + } +} + +func freeVerifyContext(vc *verifyContext) *verifyContext { + vc.parseOptions = vc.parseOptions[:0] + vc.dst = nil + vc.detachedPayload = nil + vc.keyProviders = vc.keyProviders[:0] + vc.keyUsed = nil + vc.validateKey = false + vc.encoder = base64.DefaultEncoder() + vc.ctx = context.Background() + return vc +} + +func (vc *verifyContext) ProcessOptions(options []VerifyOption) error { + //nolint:forcetypeassert + for _, option := range options { + switch option.Ident() { + case identMessage{}: + if err := option.Value(&vc.dst); err != nil { + return verifyerr(`invalid value for option WithMessage: %w`, err) + } + case identDetachedPayload{}: + if err := option.Value(&vc.detachedPayload); err != nil { + return verifyerr(`invalid value for option WithDetachedPayload: %w`, err) + } + case identKey{}: + var pair *withKey + if err := option.Value(&pair); err != nil { + return verifyerr(`invalid value for option WithKey: %w`, err) + } + vc.keyProviders = append(vc.keyProviders, &staticKeyProvider{ + alg: pair.alg.(jwa.SignatureAlgorithm), + key: pair.key, + }) + case identKeyProvider{}: + var kp KeyProvider + if err := option.Value(&kp); err != nil { + return verifyerr(`failed to retrieve key-provider option value: %w`, err) + } + vc.keyProviders = append(vc.keyProviders, kp) + case identKeyUsed{}: + if err := option.Value(&vc.keyUsed); err != nil { + return verifyerr(`failed to retrieve key-used option value: %w`, err) + } + case identContext{}: + if err := option.Value(&vc.ctx); err != nil { + return verifyerr(`failed to retrieve context option value: %w`, err) + } + case identValidateKey{}: + if err := option.Value(&vc.validateKey); err != nil { + return verifyerr(`failed to retrieve validate-key option value: %w`, err) + } + case identSerialization{}: + vc.parseOptions = append(vc.parseOptions, option.(ParseOption)) + case identBase64Encoder{}: + if err := option.Value(&vc.encoder); err != nil { + return verifyerr(`failed to retrieve base64-encoder option value: %w`, err) + } + default: + return verifyerr(`invalid jws.VerifyOption %q passed`, `With`+strings.TrimPrefix(fmt.Sprintf(`%T`, option.Ident()), `jws.ident`)) + } + } + + if len(vc.keyProviders) < 1 { + return verifyerr(`no key providers have been provided (see jws.WithKey(), jws.WithKeySet(), jws.WithVerifyAuto(), and jws.WithKeyProvider()`) + } + + return nil +} + +func (vc *verifyContext) VerifyMessage(buf []byte) ([]byte, error) { + msg, err := Parse(buf, vc.parseOptions...) + if err != nil { + return nil, verifyerr(`failed to parse jws: %w`, err) + } + defer msg.clearRaw() + + if vc.detachedPayload != nil { + if len(msg.payload) != 0 { + return nil, verifyerr(`can't specify detached payload for JWS with payload`) + } + + msg.payload = vc.detachedPayload + } + + verifyBuf := pool.ByteSlice().Get() + + // Because deferred functions bind to the current value of the variable, + // we can't just use `defer pool.ByteSlice().Put(verifyBuf)` here. + // Instead, we use a closure to reference the _variable_. + // it would be better if we could call it directly, but there are + // too many place we may return from this function + defer func() { + pool.ByteSlice().Put(verifyBuf) + }() + + errs := pool.ErrorSlice().Get() + defer func() { + pool.ErrorSlice().Put(errs) + }() + for idx, sig := range msg.signatures { + var rawHeaders []byte + if rbp, ok := sig.protected.(interface{ rawBuffer() []byte }); ok { + if raw := rbp.rawBuffer(); raw != nil { + rawHeaders = raw + } + } + + if rawHeaders == nil { + protected, err := json.Marshal(sig.protected) + if err != nil { + return nil, verifyerr(`failed to marshal "protected" for signature #%d: %w`, idx+1, err) + } + rawHeaders = protected + } + + verifyBuf = verifyBuf[:0] + verifyBuf = jwsbb.SignBuffer(verifyBuf, rawHeaders, msg.payload, vc.encoder, msg.b64) + for i, kp := range vc.keyProviders { + var sink algKeySink + if err := kp.FetchKeys(vc.ctx, &sink, sig, msg); err != nil { + return nil, verifyerr(`key provider %d failed: %w`, i, err) + } + + for _, pair := range sink.list { + // alg is converted here because pair.alg is of type jwa.KeyAlgorithm. + // this may seem ugly, but we're trying to avoid declaring separate + // structs for `alg jwa.KeyEncryptionAlgorithm` and `alg jwa.SignatureAlgorithm` + //nolint:forcetypeassert + alg := pair.alg.(jwa.SignatureAlgorithm) + key := pair.key + + if err := vc.tryKey(verifyBuf, alg, key, msg, sig); err != nil { + errs = append(errs, verifyerr(`failed to verify signature #%d with key %T: %w`, idx+1, key, err)) + continue + } + + return msg.payload, nil + } + } + errs = append(errs, verifyerr(`signature #%d could not be verified with any of the keys`, idx+1)) + } + return nil, verifyerr(`could not verify message using any of the signatures or keys: %w`, errors.Join(errs...)) +} + +func (vc *verifyContext) tryKey(verifyBuf []byte, alg jwa.SignatureAlgorithm, key any, msg *Message, sig *Signature) error { + if vc.validateKey { + if err := validateKeyBeforeUse(key); err != nil { + return fmt.Errorf(`failed to validate key before signing: %w`, err) + } + } + + verifier, err := VerifierFor(alg) + if err != nil { + return fmt.Errorf(`failed to get verifier for algorithm %q: %w`, alg, err) + } + + if err := verifier.Verify(key, verifyBuf, sig.signature); err != nil { + return verificationError{err} + } + + // Verification succeeded + if vc.keyUsed != nil { + if err := blackmagic.AssignIfCompatible(vc.keyUsed, key); err != nil { + return fmt.Errorf(`failed to assign used key (%T) to %T: %w`, key, vc.keyUsed, err) + } + } + + if vc.dst != nil { + *(vc.dst) = *msg + } + + return nil +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwt/BUILD.bazel b/vendor/github.com/lestrrat-go/jwx/v3/jwt/BUILD.bazel new file mode 100644 index 00000000000..86197d348aa --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwt/BUILD.bazel @@ -0,0 +1,72 @@ +load("@rules_go//go:def.bzl", "go_library", "go_test") + +go_library( + name = "jwt", + srcs = [ + "builder_gen.go", + "errors.go", + "filter.go", + "fastpath.go", + "http.go", + "interface.go", + "io.go", + "jwt.go", + "options.go", + "options_gen.go", + "serialize.go", + "token_gen.go", + "token_options.go", + "token_options_gen.go", + "validate.go", + ], + importpath = "github.com/lestrrat-go/jwx/v3/jwt", + visibility = ["//visibility:public"], + deps = [ + "//:jwx", + "//internal/base64", + "//transform", + "//internal/json", + "//internal/tokens", + "//internal/pool", + "//jwa", + "//jwe", + "//jwk", + "//jws", + "//jws/jwsbb", + "//jwt/internal/types", + "//jwt/internal/errors", + "@com_github_lestrrat_go_blackmagic//:blackmagic", + "@com_github_lestrrat_go_option_v2//:option", + ], +) + +go_test( + name = "jwt_test", + srcs = [ + "jwt_test.go", + "options_gen_test.go", + "token_options_test.go", + "token_test.go", + "validate_test.go", + "verify_test.go", + ], + embed = [":jwt"], + deps = [ + "//internal/json", + "//internal/jwxtest", + "//jwa", + "//jwe", + "//jwk", + "//jwk/ecdsa", + "//jws", + "//jwt/internal/types", + "@com_github_lestrrat_go_httprc_v3//:httprc", + "@com_github_stretchr_testify//require", + ], +) + +alias( + name = "go_default_library", + actual = ":jwt", + visibility = ["//visibility:public"], +) diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwt/README.md b/vendor/github.com/lestrrat-go/jwx/v3/jwt/README.md new file mode 100644 index 00000000000..a6b5664c942 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwt/README.md @@ -0,0 +1,224 @@ +# JWT [![Go Reference](https://pkg.go.dev/badge/github.com/lestrrat-go/jwx/v3/jwt.svg)](https://pkg.go.dev/github.com/lestrrat-go/jwx/v3/jwt) + +Package jwt implements JSON Web Tokens as described in [RFC7519](https://tools.ietf.org/html/rfc7519). + +* Convenience methods for oft-used keys ("aud", "sub", "iss", etc) +* Convenience functions to extract/parse from http.Request, http.Header, url.Values +* Ability to Get/Set arbitrary keys +* Conversion to and from JSON +* Generate signed tokens +* Verify signed tokens +* Extra support for OpenID tokens via [github.com/lestrrat-go/jwx/v3/jwt/openid](./jwt/openid) + +How-to style documentation can be found in the [docs directory](../docs). + +More examples are located in the examples directory ([jwt_example_test.go](../examples/jwt_example_test.go)) + +# SYNOPSIS + +## Verify a signed JWT + +```go + token, err := jwt.Parse(payload, jwt.WithKey(alg, key)) + if err != nil { + fmt.Printf("failed to parse payload: %s\n", err) + } +``` + +## Token Usage + +```go +func ExampleJWT() { + const aLongLongTimeAgo = 233431200 + + t := jwt.New() + t.Set(jwt.SubjectKey, `https://github.com/lestrrat-go/jwx/v3/jwt`) + t.Set(jwt.AudienceKey, `Golang Users`) + t.Set(jwt.IssuedAtKey, time.Unix(aLongLongTimeAgo, 0)) + t.Set(`privateClaimKey`, `Hello, World!`) + + buf, err := json.MarshalIndent(t, "", " ") + if err != nil { + fmt.Printf("failed to generate JSON: %s\n", err) + return + } + + fmt.Printf("%s\n", buf) + fmt.Printf("aud -> '%s'\n", t.Audience()) + fmt.Printf("iat -> '%s'\n", t.IssuedAt().Format(time.RFC3339)) + if v, ok := t.Get(`privateClaimKey`); ok { + fmt.Printf("privateClaimKey -> '%s'\n", v) + } + fmt.Printf("sub -> '%s'\n", t.Subject()) + + key, err := rsa.GenerateKey(rand.Reader, 2048) + if err != nil { + log.Printf("failed to generate private key: %s", err) + return + } + + { + // Signing a token (using raw rsa.PrivateKey) + signed, err := jwt.Sign(t, jwt.WithKey(jwa.RS256, key)) + if err != nil { + log.Printf("failed to sign token: %s", err) + return + } + _ = signed + } + + { + // Signing a token (using JWK) + jwkKey, err := jwk.New(key) + if err != nil { + log.Printf("failed to create JWK key: %s", err) + return + } + + signed, err := jwt.Sign(t, jwt.WithKey(jwa.RS256, jwkKey)) + if err != nil { + log.Printf("failed to sign token: %s", err) + return + } + _ = signed + } +} +``` + +## OpenID Claims + +`jwt` package can work with token types other than the default one. +For OpenID claims, use the token created by `openid.New()`, or +use the `jwt.WithToken(openid.New())`. If you need to use other specialized +claims, use `jwt.WithToken()` to specify the exact token type + +```go +func Example_openid() { + const aLongLongTimeAgo = 233431200 + + t := openid.New() + t.Set(jwt.SubjectKey, `https://github.com/lestrrat-go/jwx/v3/jwt`) + t.Set(jwt.AudienceKey, `Golang Users`) + t.Set(jwt.IssuedAtKey, time.Unix(aLongLongTimeAgo, 0)) + t.Set(`privateClaimKey`, `Hello, World!`) + + addr := openid.NewAddress() + addr.Set(openid.AddressPostalCodeKey, `105-0011`) + addr.Set(openid.AddressCountryKey, `日本`) + addr.Set(openid.AddressRegionKey, `東京都`) + addr.Set(openid.AddressLocalityKey, `港区`) + addr.Set(openid.AddressStreetAddressKey, `芝公園 4-2-8`) + t.Set(openid.AddressKey, addr) + + buf, err := json.MarshalIndent(t, "", " ") + if err != nil { + fmt.Printf("failed to generate JSON: %s\n", err) + return + } + fmt.Printf("%s\n", buf) + + t2, err := jwt.Parse(buf, jwt.WithToken(openid.New())) + if err != nil { + fmt.Printf("failed to parse JSON: %s\n", err) + return + } + if _, ok := t2.(openid.Token); !ok { + fmt.Printf("using jwt.WithToken(openid.New()) creates an openid.Token instance") + return + } +} +``` + +# FAQ + +## Why is `jwt.Token` an interface? + +In this package, `jwt.Token` is an interface. This is not an arbitrary choice: there are actual reason for the type being an interface. + +We understand that if you are migrating from another library this may be a deal breaker, but we hope you can at least appreciate the fact that this was not done arbitrarily, and that there were real technical trade offs that were evaluated. + +### No uninitialized tokens + +First and foremost, by making it an interface, you cannot use an uninitialized token: + +```go +var token1 jwt.Token // this is nil, you can't just start using this +if err := json.Unmarshal(data, &token1); err != nil { // so you can't do this + ... +} + +// But you _can_ do this, and we _want_ you to do this so the object is properly initialized +token2 = jwt.New() +if err := json.Unmarshal(data, &token2); err != nil { // actually, in practice you should use jwt.Parse() + .... +} +``` + +### But why does it need to be initialized? + +There are several reasons, but one of the reasons is that I'm using a sync.Mutex to avoid races. We want this to be properly initialized. + +The other reason is that we support custom claims out of the box. The `map[string]interface{}` container is initialized during new. This is important when checking for equality using reflect-y methods (akin to `reflect.DeepEqual`), because if you allowed zero values, you could end up with "empty" tokens, that actually differ. Consider the following: + +```go +// assume jwt.Token was s struct, not an interface +token1 := jwt.Token{ privateClaims: make(map[string]interface{}) } +token2 := jwt.Token{ privateClaims: nil } +``` + +These are semantically equivalent, but users would need to be aware of this difference when comparing values. By forcing the user to use a constructor, we can force a uniform empty state. + +### Standard way to store values + +Unlike some other libraries, this library allows you to store standard claims and non-standard claims in the same token. + +You _want_ to store standard claims in a properly typed field, which we do for fields like "iss", "nbf", etc. +But for non-standard claims, there is just no way of doing this, so we _have_ to use a container like `map[string]interface{}` + +This means that if you allow direct access to these fields via a struct, you will have two different ways to access the claims, which is confusing: + +```go +tok.Issuer = ... +tok.PrivateClaims["foo"] = ... +``` + +So we want to hide where this data is stored, and use a standard method like `Set()` and `Get()` to store all the values. +At this point you are effectively going to hide the implementation detail from the user, so you end up with a struct like below, which is fundamentally not so different from providing just an interface{}: + +```go +type Token struct { + // unexported fields +} + +func (tok *Token) Set(...) { ... } +``` + +### Use of pointers to store values + +We wanted to differentiate the state between a claim being uninitialized, and a claim being initialized to empty. + +So we use pointers to store values: + +```go +type stdToken struct { + .... + issuer *string // if nil, uninitialized. if &(""), initialized to empty +} +``` + +This is fine for us, but we doubt that this would be something users would want to do. +This is a subtle difference, but cluttering up the API with slight variations of the same type (i.e. pointers vs non-pointers) seemed like a bad idea to us. + +```go +token.Issuer = &issuer // want to avoid this + +token.Set(jwt.IssuerKey, "foobar") // so this is what we picked +``` + +This way users no longer need to care how the data is internally stored. + +### Allow more than one type of token through the same interface + +`dgrijalva/jwt-go` does this in a different way, but we felt that it would be more intuitive for all tokens to follow a single interface so there is fewer type conversions required. + +See the `openid` token for an example. diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwt/builder_gen.go b/vendor/github.com/lestrrat-go/jwx/v3/jwt/builder_gen.go new file mode 100644 index 00000000000..48d0375a28d --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwt/builder_gen.go @@ -0,0 +1,88 @@ +// Code generated by tools/cmd/genjwt/main.go. DO NOT EDIT. + +package jwt + +import ( + "fmt" + "sync" + "time" +) + +// Builder is a convenience wrapper around the New() constructor +// and the Set() methods to assign values to Token claims. +// Users can successively call Claim() on the Builder, and have it +// construct the Token when Build() is called. This alleviates the +// need for the user to check for the return value of every single +// Set() method call. +// Note that each call to Claim() overwrites the value set from the +// previous call. +type Builder struct { + mu sync.Mutex + claims map[string]any +} + +func NewBuilder() *Builder { + return &Builder{} +} + +func (b *Builder) init() { + if b.claims == nil { + b.claims = make(map[string]any) + } +} + +func (b *Builder) Claim(name string, value any) *Builder { + b.mu.Lock() + defer b.mu.Unlock() + b.init() + b.claims[name] = value + return b +} + +func (b *Builder) Audience(v []string) *Builder { + return b.Claim(AudienceKey, v) +} + +func (b *Builder) Expiration(v time.Time) *Builder { + return b.Claim(ExpirationKey, v) +} + +func (b *Builder) IssuedAt(v time.Time) *Builder { + return b.Claim(IssuedAtKey, v) +} + +func (b *Builder) Issuer(v string) *Builder { + return b.Claim(IssuerKey, v) +} + +func (b *Builder) JwtID(v string) *Builder { + return b.Claim(JwtIDKey, v) +} + +func (b *Builder) NotBefore(v time.Time) *Builder { + return b.Claim(NotBeforeKey, v) +} + +func (b *Builder) Subject(v string) *Builder { + return b.Claim(SubjectKey, v) +} + +// Build creates a new token based on the claims that the builder has received +// so far. If a claim cannot be set, then the method returns a nil Token with +// a en error as a second return value +// +// Once `Build()` is called, all claims are cleared from the Builder, and the +// Builder can be reused to build another token +func (b *Builder) Build() (Token, error) { + b.mu.Lock() + claims := b.claims + b.claims = nil + b.mu.Unlock() + tok := New() + for k, v := range claims { + if err := tok.Set(k, v); err != nil { + return nil, fmt.Errorf(`failed to set claim %q: %w`, k, err) + } + } + return tok, nil +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwt/errors.go b/vendor/github.com/lestrrat-go/jwx/v3/jwt/errors.go new file mode 100644 index 00000000000..c5b529c1ae5 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwt/errors.go @@ -0,0 +1,95 @@ +package jwt + +import ( + jwterrs "github.com/lestrrat-go/jwx/v3/jwt/internal/errors" +) + +// ClaimNotFoundError returns the opaque error value that is returned when +// `jwt.Get` fails to find the requested claim. +// +// This value should only be used for comparison using `errors.Is()`. +func ClaimNotFoundError() error { + return jwterrs.ErrClaimNotFound +} + +// ClaimAssignmentFailedError returns the opaque error value that is returned +// when `jwt.Get` fails to assign the value to the destination. For example, +// this can happen when the value is a string, but you passed a &int as the +// destination. +// +// This value should only be used for comparison using `errors.Is()`. +func ClaimAssignmentFailedError() error { + return jwterrs.ErrClaimAssignmentFailed +} + +// UnknownPayloadTypeError returns the opaque error value that is returned when +// `jwt.Parse` fails due to not being able to deduce the format of +// the incoming buffer. +// +// This value should only be used for comparison using `errors.Is()`. +func UnknownPayloadTypeError() error { + return jwterrs.ErrUnknownPayloadType +} + +// ParseError returns the opaque error that is returned from jwt.Parse when +// the input is not a valid JWT. +// +// This value should only be used for comparison using `errors.Is()`. +func ParseError() error { + return jwterrs.ErrParse +} + +// ValidateError returns the immutable error used for validation errors +// +// This value should only be used for comparison using `errors.Is()`. +func ValidateError() error { + return jwterrs.ErrValidateDefault +} + +// InvalidIssuerError returns the immutable error used when `iss` claim +// is not satisfied +// +// This value should only be used for comparison using `errors.Is()`. +func InvalidIssuerError() error { + return jwterrs.ErrInvalidIssuerDefault +} + +// TokenExpiredError returns the immutable error used when `exp` claim +// is not satisfied. +// +// This value should only be used for comparison using `errors.Is()`. +func TokenExpiredError() error { + return jwterrs.ErrTokenExpiredDefault +} + +// InvalidIssuedAtError returns the immutable error used when `iat` claim +// is not satisfied +// +// This value should only be used for comparison using `errors.Is()`. +func InvalidIssuedAtError() error { + return jwterrs.ErrInvalidIssuedAtDefault +} + +// TokenNotYetValidError returns the immutable error used when `nbf` claim +// is not satisfied +// +// This value should only be used for comparison using `errors.Is()`. +func TokenNotYetValidError() error { + return jwterrs.ErrTokenNotYetValidDefault +} + +// InvalidAudienceError returns the immutable error used when `aud` claim +// is not satisfied +// +// This value should only be used for comparison using `errors.Is()`. +func InvalidAudienceError() error { + return jwterrs.ErrInvalidAudienceDefault +} + +// MissingRequiredClaimError returns the immutable error used when the claim +// specified by `jwt.IsRequired()` is not present. +// +// This value should only be used for comparison using `errors.Is()`. +func MissingRequiredClaimError() error { + return jwterrs.ErrMissingRequiredClaimDefault +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwt/fastpath.go b/vendor/github.com/lestrrat-go/jwx/v3/jwt/fastpath.go new file mode 100644 index 00000000000..43f7c966da4 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwt/fastpath.go @@ -0,0 +1,71 @@ +package jwt + +import ( + "fmt" + + "github.com/lestrrat-go/jwx/v3/internal/base64" + "github.com/lestrrat-go/jwx/v3/internal/json" + "github.com/lestrrat-go/jwx/v3/internal/pool" + "github.com/lestrrat-go/jwx/v3/jwa" + "github.com/lestrrat-go/jwx/v3/jwk" + "github.com/lestrrat-go/jwx/v3/jws" + "github.com/lestrrat-go/jwx/v3/jws/jwsbb" +) + +// signFast reinvents the wheel a bit to avoid the overhead of +// going through the entire jws.Sign() machinery. +func signFast(t Token, alg jwa.SignatureAlgorithm, key any) ([]byte, error) { + algstr := alg.String() + + var kid string + if jwkKey, ok := key.(jwk.Key); ok { + if v, ok := jwkKey.KeyID(); ok && v != "" { + kid = v + } + } + + // Setup headers + // {"alg":"","typ":"JWT"} + // 1234567890123456789012 + want := len(algstr) + 22 + // also, if kid != "", we need to add "kid":"$kid" + if kid != "" { + // "kid":"" + // 12345689 + want += len(kid) + 9 + } + hdr := pool.ByteSlice().GetCapacity(want) + hdr = append(hdr, '{', '"', 'a', 'l', 'g', '"', ':', '"') + hdr = append(hdr, algstr...) + hdr = append(hdr, '"') + if kid != "" { + hdr = append(hdr, ',', '"', 'k', 'i', 'd', '"', ':', '"') + hdr = append(hdr, kid...) + hdr = append(hdr, '"') + } + hdr = append(hdr, ',', '"', 't', 'y', 'p', '"', ':', '"', 'J', 'W', 'T', '"', '}') + defer pool.ByteSlice().Put(hdr) + + // setup the buffer to sign with + payload, err := json.Marshal(t) + if err != nil { + return nil, fmt.Errorf(`jwt.signFast: failed to marshal token payload: %w`, err) + } + + combined := jwsbb.SignBuffer(nil, hdr, payload, base64.DefaultEncoder(), true) + signer, err := jws.SignerFor(alg) + if err != nil { + return nil, fmt.Errorf(`jwt.signFast: failed to get signer for %s: %w`, alg, err) + } + + signature, err := signer.Sign(key, combined) + if err != nil { + return nil, fmt.Errorf(`jwt.signFast: failed to sign payload with %s: %w`, alg, err) + } + + serialized, err := jwsbb.JoinCompact(nil, hdr, payload, signature, base64.DefaultEncoder(), true) + if err != nil { + return nil, fmt.Errorf("jwt.signFast: failed to join compact: %w", err) + } + return serialized, nil +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwt/filter.go b/vendor/github.com/lestrrat-go/jwx/v3/jwt/filter.go new file mode 100644 index 00000000000..31471dbdfbb --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwt/filter.go @@ -0,0 +1,34 @@ +package jwt + +import ( + "github.com/lestrrat-go/jwx/v3/transform" +) + +// TokenFilter is an interface that allows users to filter JWT claims. +// It provides two methods: Filter and Reject; Filter returns a new token with only +// the claims that match the filter criteria, while Reject returns a new token with +// only the claims that DO NOT match the filter. +// +// EXPERIMENTAL: This API is experimental and its interface and behavior is +// subject to change in future releases. This API is not subject to semver +// compatibility guarantees. +type TokenFilter interface { + Filter(token Token) (Token, error) + Reject(token Token) (Token, error) +} + +// StandardClaimsFilter returns a TokenFilter that filters out standard JWT claims. +// +// You can use this filter to create tokens that either only has standard claims +// or only custom claims. If you need to configure the filter more precisely, consider +// using the ClaimNameFilter directly. +func StandardClaimsFilter() TokenFilter { + return stdClaimsFilter +} + +var stdClaimsFilter = NewClaimNameFilter(stdClaimNames...) + +// NewClaimNameFilter creates a new ClaimNameFilter with the specified claim names. +func NewClaimNameFilter(names ...string) TokenFilter { + return transform.NewNameBasedFilter[Token](names...) +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwt/http.go b/vendor/github.com/lestrrat-go/jwx/v3/jwt/http.go new file mode 100644 index 00000000000..691c5a0df46 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwt/http.go @@ -0,0 +1,295 @@ +package jwt + +import ( + "fmt" + "net/http" + "net/url" + "strconv" + "strings" + + "github.com/lestrrat-go/jwx/v3/internal/pool" + "github.com/lestrrat-go/jwx/v3/internal/tokens" +) + +// ParseCookie parses a JWT stored in a http.Cookie with the given name. +// If the specified cookie is not found, http.ErrNoCookie is returned. +func ParseCookie(req *http.Request, name string, options ...ParseOption) (Token, error) { + var dst **http.Cookie + for _, option := range options { + switch option.Ident() { + case identCookie{}: + if err := option.Value(&dst); err != nil { + return nil, fmt.Errorf(`jws.ParseCookie: value to option WithCookie must be **http.Cookie: %w`, err) + } + } + } + + cookie, err := req.Cookie(name) + if err != nil { + return nil, err + } + tok, err := ParseString(cookie.Value, options...) + if err != nil { + return nil, fmt.Errorf(`jws.ParseCookie: failed to parse token stored in cookie: %w`, err) + } + + if dst != nil { + *dst = cookie + } + return tok, nil +} + +// ParseHeader parses a JWT stored in a http.Header. +// +// For the header "Authorization", it will strip the prefix "Bearer " and will +// treat the remaining value as a JWT. +func ParseHeader(hdr http.Header, name string, options ...ParseOption) (Token, error) { + key := http.CanonicalHeaderKey(name) + v := strings.TrimSpace(hdr.Get(key)) + if v == "" { + return nil, fmt.Errorf(`empty header (%s)`, key) + } + + if key == "Authorization" { + // Authorization header is an exception. We strip the "Bearer " from + // the prefix + v = strings.TrimSpace(strings.TrimPrefix(v, "Bearer")) + } + + tok, err := ParseString(v, options...) + if err != nil { + return nil, fmt.Errorf(`failed to parse token stored in header (%s): %w`, key, err) + } + return tok, nil +} + +// ParseForm parses a JWT stored in a url.Value. +func ParseForm(values url.Values, name string, options ...ParseOption) (Token, error) { + v := strings.TrimSpace(values.Get(name)) + if v == "" { + return nil, fmt.Errorf(`empty value (%s)`, name) + } + + return ParseString(v, options...) +} + +// ParseRequest searches a http.Request object for a JWT token. +// +// Specifying WithHeaderKey() will tell it to search under a specific +// header key. Specifying WithFormKey() will tell it to search under +// a specific form field. +// +// If none of jwt.WithHeaderKey()/jwt.WithCookieKey()/jwt.WithFormKey() is +// used, "Authorization" header will be searched. If any of these options +// are specified, you must explicitly re-enable searching for "Authorization" header +// if you also want to search for it. +// +// # searches for "Authorization" +// jwt.ParseRequest(req) +// +// # searches for "x-my-token" ONLY. +// jwt.ParseRequest(req, jwt.WithHeaderKey("x-my-token")) +// +// # searches for "Authorization" AND "x-my-token" +// jwt.ParseRequest(req, jwt.WithHeaderKey("Authorization"), jwt.WithHeaderKey("x-my-token")) +// +// Cookies are searched using (http.Request).Cookie(). If you have multiple +// cookies with the same name, and you want to search for a specific one that +// (http.Request).Cookie() would not return, you will need to implement your +// own logic to extract the cookie and use jwt.ParseString(). +func ParseRequest(req *http.Request, options ...ParseOption) (Token, error) { + var hdrkeys []string + var formkeys []string + var cookiekeys []string + var parseOptions []ParseOption + for _, option := range options { + switch option.Ident() { + case identHeaderKey{}: + var v string + if err := option.Value(&v); err != nil { + return nil, fmt.Errorf(`jws.ParseRequest: value to option WithHeaderKey must be string: %w`, err) + } + hdrkeys = append(hdrkeys, v) + case identFormKey{}: + var v string + if err := option.Value(&v); err != nil { + return nil, fmt.Errorf(`jws.ParseRequest: value to option WithFormKey must be string: %w`, err) + } + formkeys = append(formkeys, v) + case identCookieKey{}: + var v string + if err := option.Value(&v); err != nil { + return nil, fmt.Errorf(`jws.ParseRequest: value to option WithCookieKey must be string: %w`, err) + } + cookiekeys = append(cookiekeys, v) + default: + parseOptions = append(parseOptions, option) + } + } + + if len(hdrkeys) == 0 && len(formkeys) == 0 && len(cookiekeys) == 0 { + hdrkeys = append(hdrkeys, "Authorization") + } + + mhdrs := pool.KeyToErrorMap().Get() + defer pool.KeyToErrorMap().Put(mhdrs) + mfrms := pool.KeyToErrorMap().Get() + defer pool.KeyToErrorMap().Put(mfrms) + mcookies := pool.KeyToErrorMap().Get() + defer pool.KeyToErrorMap().Put(mcookies) + + for _, hdrkey := range hdrkeys { + // Check presence via a direct map lookup + if _, ok := req.Header[http.CanonicalHeaderKey(hdrkey)]; !ok { + // if non-existent, not error + continue + } + + tok, err := ParseHeader(req.Header, hdrkey, parseOptions...) + if err != nil { + mhdrs[hdrkey] = err + continue + } + return tok, nil + } + + for _, name := range cookiekeys { + tok, err := ParseCookie(req, name, parseOptions...) + if err != nil { + if err == http.ErrNoCookie { + // not fatal + mcookies[name] = err + } + continue + } + return tok, nil + } + + if cl := req.ContentLength; cl > 0 { + if err := req.ParseForm(); err != nil { + return nil, fmt.Errorf(`failed to parse form: %w`, err) + } + } + + for _, formkey := range formkeys { + // Check presence via a direct map lookup + if _, ok := req.Form[formkey]; !ok { + // if non-existent, not error + continue + } + + tok, err := ParseForm(req.Form, formkey, parseOptions...) + if err != nil { + mfrms[formkey] = err + continue + } + return tok, nil + } + + // Everything below is a prelude to error reporting. + var triedHdrs strings.Builder + for i, hdrkey := range hdrkeys { + if i > 0 { + triedHdrs.WriteString(", ") + } + triedHdrs.WriteString(strconv.Quote(hdrkey)) + } + + var triedForms strings.Builder + for i, formkey := range formkeys { + if i > 0 { + triedForms.WriteString(", ") + } + triedForms.WriteString(strconv.Quote(formkey)) + } + + var triedCookies strings.Builder + for i, cookiekey := range cookiekeys { + if i > 0 { + triedCookies.WriteString(", ") + } + triedCookies.WriteString(strconv.Quote(cookiekey)) + } + + var b strings.Builder + b.WriteString(`failed to find a valid token in any location of the request (tried: `) + olen := b.Len() + if triedHdrs.Len() > 0 { + b.WriteString(`header keys: [`) + b.WriteString(triedHdrs.String()) + b.WriteByte(tokens.CloseSquareBracket) + } + if triedForms.Len() > 0 { + if b.Len() > olen { + b.WriteString(", ") + } + b.WriteString("form keys: [") + b.WriteString(triedForms.String()) + b.WriteByte(tokens.CloseSquareBracket) + } + + if triedCookies.Len() > 0 { + if b.Len() > olen { + b.WriteString(", ") + } + b.WriteString("cookie keys: [") + b.WriteString(triedCookies.String()) + b.WriteByte(tokens.CloseSquareBracket) + } + b.WriteByte(')') + + lmhdrs := len(mhdrs) + lmfrms := len(mfrms) + lmcookies := len(mcookies) + var errors []any + if lmhdrs > 0 || lmfrms > 0 || lmcookies > 0 { + b.WriteString(". Additionally, errors were encountered during attempts to verify using:") + + if lmhdrs > 0 { + b.WriteString(" headers: (") + count := 0 + for hdrkey, err := range mhdrs { + if count > 0 { + b.WriteString(", ") + } + b.WriteString("[header key: ") + b.WriteString(strconv.Quote(hdrkey)) + b.WriteString(", error: %w]") + errors = append(errors, err) + count++ + } + b.WriteString(")") + } + + if lmcookies > 0 { + count := 0 + b.WriteString(" cookies: (") + for cookiekey, err := range mcookies { + if count > 0 { + b.WriteString(", ") + } + b.WriteString("[cookie key: ") + b.WriteString(strconv.Quote(cookiekey)) + b.WriteString(", error: %w]") + errors = append(errors, err) + count++ + } + } + + if lmfrms > 0 { + count := 0 + b.WriteString(" forms: (") + for formkey, err := range mfrms { + if count > 0 { + b.WriteString(", ") + } + b.WriteString("[form key: ") + b.WriteString(strconv.Quote(formkey)) + b.WriteString(", error: %w]") + errors = append(errors, err) + count++ + } + } + } + return nil, fmt.Errorf(b.String(), errors...) +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwt/interface.go b/vendor/github.com/lestrrat-go/jwx/v3/jwt/interface.go new file mode 100644 index 00000000000..f9a9d971ef7 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwt/interface.go @@ -0,0 +1,8 @@ +package jwt + +import ( + "github.com/lestrrat-go/jwx/v3/internal/json" +) + +type DecodeCtx = json.DecodeCtx +type TokenWithDecodeCtx = json.DecodeCtxContainer diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwt/internal/errors/BUILD.bazel b/vendor/github.com/lestrrat-go/jwx/v3/jwt/internal/errors/BUILD.bazel new file mode 100644 index 00000000000..a053e8c0aae --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwt/internal/errors/BUILD.bazel @@ -0,0 +1,16 @@ +load("@rules_go//go:def.bzl", "go_library") + +go_library( + name = "errors", + srcs = [ + "errors.go", + ], + importpath = "github.com/lestrrat-go/jwx/v3/jwt/internal/errors", + visibility = ["//jwt:__subpackages__"], +) + +alias( + name = "go_default_library", + actual = ":errors", + visibility = ["//jwt:__subpackages__"], +) \ No newline at end of file diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwt/internal/errors/errors.go b/vendor/github.com/lestrrat-go/jwx/v3/jwt/internal/errors/errors.go new file mode 100644 index 00000000000..a1dca0d5a3b --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwt/internal/errors/errors.go @@ -0,0 +1,183 @@ +// Package errors exist to store errors for jwt and openid packages. +// +// It's internal because we don't want to expose _anything_ about these errors +// so users absolutely cannot do anything other than use them as opaque errors. +package errors + +import ( + "errors" + "fmt" +) + +var ( + ErrClaimNotFound = ClaimNotFoundError{} + ErrClaimAssignmentFailed = ClaimAssignmentFailedError{Err: errors.New(`claim assignment failed`)} + ErrUnknownPayloadType = errors.New(`unknown payload type (payload is not JWT?)`) + ErrParse = ParseError{error: errors.New(`jwt.Parse: unknown error`)} + ErrValidateDefault = ValidationError{errors.New(`unknown error`)} + ErrInvalidIssuerDefault = InvalidIssuerError{errors.New(`"iss" not satisfied`)} + ErrTokenExpiredDefault = TokenExpiredError{errors.New(`"exp" not satisfied: token is expired`)} + ErrInvalidIssuedAtDefault = InvalidIssuedAtError{errors.New(`"iat" not satisfied`)} + ErrTokenNotYetValidDefault = TokenNotYetValidError{errors.New(`"nbf" not satisfied: token is not yet valid`)} + ErrInvalidAudienceDefault = InvalidAudienceError{errors.New(`"aud" not satisfied`)} + ErrMissingRequiredClaimDefault = &MissingRequiredClaimError{error: errors.New(`required claim is missing`)} +) + +type ClaimNotFoundError struct { + Name string +} + +func (e ClaimNotFoundError) Error() string { + // This error message uses "field" instead of "claim" for backwards compatibility, + // but it shuold really be "claim" since it refers to a JWT claim. + return fmt.Sprintf(`field "%s" not found`, e.Name) +} + +func (e ClaimNotFoundError) Is(target error) bool { + _, ok := target.(ClaimNotFoundError) + return ok +} + +type ClaimAssignmentFailedError struct { + Err error +} + +func (e ClaimAssignmentFailedError) Error() string { + // This error message probably should be tweaked, but it is this way + // for backwards compatibility. + return fmt.Sprintf(`failed to assign value to dst: %s`, e.Err.Error()) +} + +func (e ClaimAssignmentFailedError) Unwrap() error { + return e.Err +} + +func (e ClaimAssignmentFailedError) Is(target error) bool { + _, ok := target.(ClaimAssignmentFailedError) + return ok +} + +type ParseError struct { + error +} + +func (e ParseError) Unwrap() error { + return e.error +} + +func (ParseError) Is(err error) bool { + _, ok := err.(ParseError) + return ok +} + +func ParseErrorf(prefix, f string, args ...any) error { + return ParseError{fmt.Errorf(prefix+": "+f, args...)} +} + +type ValidationError struct { + error +} + +func (ValidationError) Is(err error) bool { + _, ok := err.(ValidationError) + return ok +} + +func (err ValidationError) Unwrap() error { + return err.error +} + +func ValidateErrorf(f string, args ...any) error { + return ValidationError{fmt.Errorf(`jwt.Validate: `+f, args...)} +} + +type InvalidIssuerError struct { + error +} + +func (err InvalidIssuerError) Is(target error) bool { + _, ok := target.(InvalidIssuerError) + return ok +} + +func (err InvalidIssuerError) Unwrap() error { + return err.error +} + +func IssuerErrorf(f string, args ...any) error { + return InvalidIssuerError{fmt.Errorf(`"iss" not satisfied: `+f, args...)} +} + +type TokenExpiredError struct { + error +} + +func (err TokenExpiredError) Is(target error) bool { + _, ok := target.(TokenExpiredError) + return ok +} + +func (err TokenExpiredError) Unwrap() error { + return err.error +} + +type InvalidIssuedAtError struct { + error +} + +func (err InvalidIssuedAtError) Is(target error) bool { + _, ok := target.(InvalidIssuedAtError) + return ok +} + +func (err InvalidIssuedAtError) Unwrap() error { + return err.error +} + +type TokenNotYetValidError struct { + error +} + +func (err TokenNotYetValidError) Is(target error) bool { + _, ok := target.(TokenNotYetValidError) + return ok +} + +func (err TokenNotYetValidError) Unwrap() error { + return err.error +} + +type InvalidAudienceError struct { + error +} + +func (err InvalidAudienceError) Is(target error) bool { + _, ok := target.(InvalidAudienceError) + return ok +} + +func (err InvalidAudienceError) Unwrap() error { + return err.error +} + +func AudienceErrorf(f string, args ...any) error { + return InvalidAudienceError{fmt.Errorf(`"aud" not satisfied: `+f, args...)} +} + +type MissingRequiredClaimError struct { + error + + claim string +} + +func (err *MissingRequiredClaimError) Is(target error) bool { + err1, ok := target.(*MissingRequiredClaimError) + if !ok { + return false + } + return err1 == ErrMissingRequiredClaimDefault || err1.claim == err.claim +} + +func MissingRequiredClaimErrorf(name string) error { + return &MissingRequiredClaimError{claim: name, error: fmt.Errorf(`required claim "%s" is missing`, name)} +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwt/internal/types/BUILD.bazel b/vendor/github.com/lestrrat-go/jwx/v3/jwt/internal/types/BUILD.bazel new file mode 100644 index 00000000000..1d046a3eccb --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwt/internal/types/BUILD.bazel @@ -0,0 +1,35 @@ +load("@rules_go//go:def.bzl", "go_library", "go_test") + +go_library( + name = "types", + srcs = [ + "date.go", + "string.go", + ], + importpath = "github.com/lestrrat-go/jwx/v3/jwt/internal/types", + visibility = ["//jwt:__subpackages__"], + deps = [ + "//internal/json", + "//internal/tokens", + ], +) + +go_test( + name = "types_test", + srcs = [ + "date_test.go", + "string_test.go", + ], + deps = [ + ":types", + "//internal/json", + "//jwt", + "@com_github_stretchr_testify//require", + ], +) + +alias( + name = "go_default_library", + actual = ":types", + visibility = ["//jwt:__subpackages__"], +) diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwt/internal/types/date.go b/vendor/github.com/lestrrat-go/jwx/v3/jwt/internal/types/date.go new file mode 100644 index 00000000000..3d40a9ed97a --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwt/internal/types/date.go @@ -0,0 +1,192 @@ +package types + +import ( + "fmt" + "strconv" + "strings" + "time" + + "github.com/lestrrat-go/jwx/v3/internal/json" + "github.com/lestrrat-go/jwx/v3/internal/tokens" +) + +const ( + DefaultPrecision uint32 = 0 // second level + MaxPrecision uint32 = 9 // nanosecond level +) + +var Pedantic uint32 +var ParsePrecision = DefaultPrecision +var FormatPrecision = DefaultPrecision + +// NumericDate represents the date format used in the 'nbf' claim +type NumericDate struct { + time.Time +} + +func (n *NumericDate) Get() time.Time { + if n == nil { + return (time.Time{}).UTC() + } + return n.Time +} + +func intToTime(v any, t *time.Time) bool { + var n int64 + switch x := v.(type) { + case int64: + n = x + case int32: + n = int64(x) + case int16: + n = int64(x) + case int8: + n = int64(x) + case int: + n = int64(x) + default: + return false + } + + *t = time.Unix(n, 0) + return true +} + +func parseNumericString(x string) (time.Time, error) { + var t time.Time // empty time for empty return value + + // Only check for the escape hatch if it's the pedantic + // flag is off + if Pedantic != 1 { + // This is an escape hatch for non-conformant providers + // that gives us RFC3339 instead of epoch time + for _, r := range x { + // 0x30 = '0', 0x39 = '9', 0x2E = tokens.Period + if (r >= 0x30 && r <= 0x39) || r == 0x2E { + continue + } + + // if it got here, then it probably isn't epoch time + tv, err := time.Parse(time.RFC3339, x) + if err != nil { + return t, fmt.Errorf(`value is not number of seconds since the epoch, and attempt to parse it as RFC3339 timestamp failed: %w`, err) + } + return tv, nil + } + } + + var fractional string + whole := x + if i := strings.IndexRune(x, tokens.Period); i > 0 { + if ParsePrecision > 0 && len(x) > i+1 { + fractional = x[i+1:] // everything after the tokens.Period + if int(ParsePrecision) < len(fractional) { + // Remove insignificant digits + fractional = fractional[:int(ParsePrecision)] + } + // Replace missing fractional diits with zeros + for len(fractional) < int(MaxPrecision) { + fractional = fractional + "0" + } + } + whole = x[:i] + } + n, err := strconv.ParseInt(whole, 10, 64) + if err != nil { + return t, fmt.Errorf(`failed to parse whole value %q: %w`, whole, err) + } + var nsecs int64 + if fractional != "" { + v, err := strconv.ParseInt(fractional, 10, 64) + if err != nil { + return t, fmt.Errorf(`failed to parse fractional value %q: %w`, fractional, err) + } + nsecs = v + } + + return time.Unix(n, nsecs).UTC(), nil +} + +func (n *NumericDate) Accept(v any) error { + var t time.Time + switch x := v.(type) { + case float32: + tv, err := parseNumericString(fmt.Sprintf(`%.9f`, x)) + if err != nil { + return fmt.Errorf(`failed to accept float32 %.9f: %w`, x, err) + } + t = tv + case float64: + tv, err := parseNumericString(fmt.Sprintf(`%.9f`, x)) + if err != nil { + return fmt.Errorf(`failed to accept float32 %.9f: %w`, x, err) + } + t = tv + case json.Number: + tv, err := parseNumericString(x.String()) + if err != nil { + return fmt.Errorf(`failed to accept json.Number %q: %w`, x.String(), err) + } + t = tv + case string: + tv, err := parseNumericString(x) + if err != nil { + return fmt.Errorf(`failed to accept string %q: %w`, x, err) + } + t = tv + case time.Time: + t = x + default: + if !intToTime(v, &t) { + return fmt.Errorf(`invalid type %T`, v) + } + } + n.Time = t.UTC() + return nil +} + +func (n NumericDate) String() string { + if FormatPrecision == 0 { + return strconv.FormatInt(n.Unix(), 10) + } + + // This is cheating, but it's better (easier) than doing floating point math + // We basically munge with strings after formatting an integer value + // for nanoseconds since epoch + s := strconv.FormatInt(n.UnixNano(), 10) + for len(s) < int(MaxPrecision) { + s = "0" + s + } + + slwhole := len(s) - int(MaxPrecision) + s = s[:slwhole] + "." + s[slwhole:slwhole+int(FormatPrecision)] + if s[0] == tokens.Period { + s = "0" + s + } + + return s +} + +// MarshalJSON translates from internal representation to JSON NumericDate +// See https://tools.ietf.org/html/rfc7519#page-6 +func (n *NumericDate) MarshalJSON() ([]byte, error) { + if n.IsZero() { + return json.Marshal(nil) + } + + return json.Marshal(n.String()) +} + +func (n *NumericDate) UnmarshalJSON(data []byte) error { + var v any + if err := json.Unmarshal(data, &v); err != nil { + return fmt.Errorf(`failed to unmarshal date: %w`, err) + } + + var n2 NumericDate + if err := n2.Accept(v); err != nil { + return fmt.Errorf(`invalid value for NumericDate: %w`, err) + } + *n = n2 + return nil +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwt/internal/types/string.go b/vendor/github.com/lestrrat-go/jwx/v3/jwt/internal/types/string.go new file mode 100644 index 00000000000..8117bea3589 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwt/internal/types/string.go @@ -0,0 +1,43 @@ +package types + +import ( + "fmt" + + "github.com/lestrrat-go/jwx/v3/internal/json" +) + +type StringList []string + +func (l StringList) Get() []string { + return []string(l) +} + +func (l *StringList) Accept(v any) error { + switch x := v.(type) { + case string: + *l = StringList([]string{x}) + case []string: + *l = StringList(x) + case []any: + list := make(StringList, len(x)) + for i, e := range x { + if s, ok := e.(string); ok { + list[i] = s + continue + } + return fmt.Errorf(`invalid list element type %T`, e) + } + *l = list + default: + return fmt.Errorf(`invalid type: %T`, v) + } + return nil +} + +func (l *StringList) UnmarshalJSON(data []byte) error { + var v any + if err := json.Unmarshal(data, &v); err != nil { + return fmt.Errorf(`failed to unmarshal data: %w`, err) + } + return l.Accept(v) +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwt/io.go b/vendor/github.com/lestrrat-go/jwx/v3/jwt/io.go new file mode 100644 index 00000000000..812cda775e8 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwt/io.go @@ -0,0 +1,42 @@ +// Code generated by tools/cmd/genreadfile/main.go. DO NOT EDIT. + +package jwt + +import ( + "fmt" + "io/fs" + "os" +) + +type sysFS struct{} + +func (sysFS) Open(path string) (fs.File, error) { + return os.Open(path) +} + +func ReadFile(path string, options ...ReadFileOption) (Token, error) { + var parseOptions []ParseOption + for _, option := range options { + if po, ok := option.(ParseOption); ok { + parseOptions = append(parseOptions, po) + } + } + + var srcFS fs.FS = sysFS{} + for _, option := range options { + switch option.Ident() { + case identFS{}: + if err := option.Value(&srcFS); err != nil { + return nil, fmt.Errorf("failed to set fs.FS: %w", err) + } + } + } + + f, err := srcFS.Open(path) + if err != nil { + return nil, err + } + + defer f.Close() + return ParseReader(f, parseOptions...) +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwt/jwt.go b/vendor/github.com/lestrrat-go/jwx/v3/jwt/jwt.go new file mode 100644 index 00000000000..43e382987aa --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwt/jwt.go @@ -0,0 +1,592 @@ +//go:generate ../tools/cmd/genjwt.sh +//go:generate stringer -type=TokenOption -output=token_options_gen.go + +// Package jwt implements JSON Web Tokens as described in https://tools.ietf.org/html/rfc7519 +package jwt + +import ( + "bytes" + "fmt" + "io" + "sync/atomic" + "time" + + "github.com/lestrrat-go/jwx/v3" + "github.com/lestrrat-go/jwx/v3/internal/json" + "github.com/lestrrat-go/jwx/v3/jwa" + "github.com/lestrrat-go/jwx/v3/jws" + jwterrs "github.com/lestrrat-go/jwx/v3/jwt/internal/errors" + "github.com/lestrrat-go/jwx/v3/jwt/internal/types" +) + +var defaultTruncation atomic.Int64 + +// Settings controls global settings that are specific to JWTs. +func Settings(options ...GlobalOption) { + var flattenAudience bool + var parsePedantic bool + var parsePrecision = types.MaxPrecision + 1 // illegal value, so we can detect nothing was set + var formatPrecision = types.MaxPrecision + 1 // illegal value, so we can detect nothing was set + truncation := time.Duration(-1) + for _, option := range options { + switch option.Ident() { + case identTruncation{}: + if err := option.Value(&truncation); err != nil { + panic(fmt.Sprintf("jwt.Settings: value for WithTruncation must be time.Duration: %s", err)) + } + case identFlattenAudience{}: + if err := option.Value(&flattenAudience); err != nil { + panic(fmt.Sprintf("jwt.Settings: value for WithFlattenAudience must be bool: %s", err)) + } + case identNumericDateParsePedantic{}: + if err := option.Value(&parsePedantic); err != nil { + panic(fmt.Sprintf("jwt.Settings: value for WithNumericDateParsePedantic must be bool: %s", err)) + } + case identNumericDateParsePrecision{}: + var v int + if err := option.Value(&v); err != nil { + panic(fmt.Sprintf("jwt.Settings: value for WithNumericDateParsePrecision must be int: %s", err)) + } + // only accept this value if it's in our desired range + if v >= 0 && v <= int(types.MaxPrecision) { + parsePrecision = uint32(v) + } + case identNumericDateFormatPrecision{}: + var v int + if err := option.Value(&v); err != nil { + panic(fmt.Sprintf("jwt.Settings: value for WithNumericDateFormatPrecision must be int: %s", err)) + } + // only accept this value if it's in our desired range + if v >= 0 && v <= int(types.MaxPrecision) { + formatPrecision = uint32(v) + } + } + } + + if parsePrecision <= types.MaxPrecision { // remember we set default to max + 1 + v := atomic.LoadUint32(&types.ParsePrecision) + if v != parsePrecision { + atomic.CompareAndSwapUint32(&types.ParsePrecision, v, parsePrecision) + } + } + + if formatPrecision <= types.MaxPrecision { // remember we set default to max + 1 + v := atomic.LoadUint32(&types.FormatPrecision) + if v != formatPrecision { + atomic.CompareAndSwapUint32(&types.FormatPrecision, v, formatPrecision) + } + } + + { + v := atomic.LoadUint32(&types.Pedantic) + if (v == 1) != parsePedantic { + var newVal uint32 + if parsePedantic { + newVal = 1 + } + atomic.CompareAndSwapUint32(&types.Pedantic, v, newVal) + } + } + + { + defaultOptionsMu.Lock() + if flattenAudience { + defaultOptions.Enable(FlattenAudience) + } else { + defaultOptions.Disable(FlattenAudience) + } + defaultOptionsMu.Unlock() + } + + if truncation >= 0 { + defaultTruncation.Store(int64(truncation)) + } +} + +var registry = json.NewRegistry() + +// ParseString calls Parse against a string +func ParseString(s string, options ...ParseOption) (Token, error) { + tok, err := parseBytes([]byte(s), options...) + if err != nil { + return nil, jwterrs.ParseErrorf(`jwt.ParseString`, `failed to parse string: %w`, err) + } + return tok, nil +} + +// Parse parses the JWT token payload and creates a new `jwt.Token` object. +// The token must be encoded in JWS compact format, or a raw JSON form of JWT +// without any signatures. +// +// If you need JWE support on top of JWS, you will need to rollout your +// own workaround. +// +// If the token is signed, and you want to verify the payload matches the signature, +// you must pass the jwt.WithKey(alg, key) or jwt.WithKeySet(jwk.Set) option. +// If you do not specify these parameters, no verification will be performed. +// +// During verification, if the JWS headers specify a key ID (`kid`), the +// key used for verification must match the specified ID. If you are somehow +// using a key without a `kid` (which is highly unlikely if you are working +// with a JWT from a well-know provider), you can work around this by modifying +// the `jwk.Key` and setting the `kid` header. +// +// If you also want to assert the validity of the JWT itself (i.e. expiration +// and such), use the `Validate()` function on the returned token, or pass the +// `WithValidate(true)` option. Validate options can also be passed to +// `Parse` +// +// This function takes both ParseOption and ValidateOption types: +// ParseOptions control the parsing behavior, and ValidateOptions are +// passed to `Validate()` when `jwt.WithValidate` is specified. +func Parse(s []byte, options ...ParseOption) (Token, error) { + tok, err := parseBytes(s, options...) + if err != nil { + return nil, jwterrs.ParseErrorf(`jwt.Parse`, `failed to parse token: %w`, err) + } + return tok, nil +} + +// ParseInsecure is exactly the same as Parse(), but it disables +// signature verification and token validation. +// +// You cannot override `jwt.WithVerify()` or `jwt.WithValidate()` +// using this function. Providing these options would result in +// an error +func ParseInsecure(s []byte, options ...ParseOption) (Token, error) { + for _, option := range options { + switch option.Ident() { + case identVerify{}, identValidate{}: + return nil, jwterrs.ParseErrorf(`jwt.ParseInsecure`, `jwt.WithVerify() and jwt.WithValidate() may not be specified`) + } + } + + options = append(options, WithVerify(false), WithValidate(false)) + tok, err := Parse(s, options...) + if err != nil { + return nil, jwterrs.ParseErrorf(`jwt.ParseInsecure`, `failed to parse token: %w`, err) + } + return tok, nil +} + +// ParseReader calls Parse against an io.Reader +func ParseReader(src io.Reader, options ...ParseOption) (Token, error) { + // We're going to need the raw bytes regardless. Read it. + data, err := io.ReadAll(src) + if err != nil { + return nil, jwterrs.ParseErrorf(`jwt.ParseReader`, `failed to read from token data source: %w`, err) + } + tok, err := parseBytes(data, options...) + if err != nil { + return nil, jwterrs.ParseErrorf(`jwt.ParseReader`, `failed to parse token: %w`, err) + } + return tok, nil +} + +type parseCtx struct { + token Token + validateOpts []ValidateOption + verifyOpts []jws.VerifyOption + localReg *json.Registry + pedantic bool + skipVerification bool + validate bool + withKeyCount int + withKey *withKey // this is used to detect if we have a WithKey option +} + +func parseBytes(data []byte, options ...ParseOption) (Token, error) { + var ctx parseCtx + + // Validation is turned on by default. You need to specify + // jwt.WithValidate(false) if you want to disable it + ctx.validate = true + + // Verification is required (i.e., it is assumed that the incoming + // data is in JWS format) unless the user explicitly asks for + // it to be skipped. + verification := true + + var verifyOpts []Option + for _, o := range options { + if v, ok := o.(ValidateOption); ok { + ctx.validateOpts = append(ctx.validateOpts, v) + continue + } + + switch o.Ident() { + case identKey{}: + // it would be nice to be able to detect if ctx.verifyOpts[0] + // is a WithKey option, but unfortunately at that point we have + // already converted the options to a jws option, which means + // we can no longer compare its Ident() to jwt.identKey{}. + // So let's just count this here + ctx.withKeyCount++ + if ctx.withKeyCount == 1 { + if err := o.Value(&ctx.withKey); err != nil { + return nil, fmt.Errorf("jws.parseBytes: value for WithKey option must be a *jwt.withKey: %w", err) + } + } + verifyOpts = append(verifyOpts, o) + case identKeySet{}, identVerifyAuto{}, identKeyProvider{}, identBase64Encoder{}: + verifyOpts = append(verifyOpts, o) + case identToken{}: + var token Token + if err := o.Value(&token); err != nil { + return nil, fmt.Errorf("jws.parseBytes: value for WithToken option must be a jwt.Token: %w", err) + } + ctx.token = token + case identPedantic{}: + if err := o.Value(&ctx.pedantic); err != nil { + return nil, fmt.Errorf("jws.parseBytes: value for WithPedantic option must be a bool: %w", err) + } + case identValidate{}: + if err := o.Value(&ctx.validate); err != nil { + return nil, fmt.Errorf("jws.parseBytes: value for WithValidate option must be a bool: %w", err) + } + case identVerify{}: + if err := o.Value(&verification); err != nil { + return nil, fmt.Errorf("jws.parseBytes: value for WithVerify option must be a bool: %w", err) + } + case identTypedClaim{}: + var pair claimPair + if err := o.Value(&pair); err != nil { + return nil, fmt.Errorf("jws.parseBytes: value for WithTypedClaim option must be claimPair: %w", err) + } + if ctx.localReg == nil { + ctx.localReg = json.NewRegistry() + } + ctx.localReg.Register(pair.Name, pair.Value) + } + } + + if !verification { + ctx.skipVerification = true + } + + lvo := len(verifyOpts) + if lvo == 0 && verification { + return nil, fmt.Errorf(`jwt.Parse: no keys for verification are provided (use jwt.WithVerify(false) to explicitly skip)`) + } + + if lvo > 0 { + converted, err := toVerifyOptions(verifyOpts...) + if err != nil { + return nil, fmt.Errorf(`jwt.Parse: failed to convert options into jws.VerifyOption: %w`, err) + } + ctx.verifyOpts = converted + } + + data = bytes.TrimSpace(data) + return parse(&ctx, data) +} + +const ( + _JwsVerifyInvalid = iota + _JwsVerifyDone + _JwsVerifyExpectNested + _JwsVerifySkipped +) + +var _ = _JwsVerifyInvalid + +func verifyJWS(ctx *parseCtx, payload []byte) ([]byte, int, error) { + lvo := len(ctx.verifyOpts) + if lvo == 0 { + return nil, _JwsVerifySkipped, nil + } + + if lvo == 1 && ctx.withKeyCount == 1 { + wk := ctx.withKey + alg, ok := wk.alg.(jwa.SignatureAlgorithm) + if ok && len(wk.options) == 0 { + verified, err := jws.VerifyCompactFast(wk.key, payload, alg) + if err != nil { + return nil, _JwsVerifyDone, err + } + return verified, _JwsVerifyDone, nil + } + } + + verifyOpts := append(ctx.verifyOpts, jws.WithCompact()) + verified, err := jws.Verify(payload, verifyOpts...) + return verified, _JwsVerifyDone, err +} + +// verify parameter exists to make sure that we don't accidentally skip +// over verification just because alg == "" or key == nil or something. +func parse(ctx *parseCtx, data []byte) (Token, error) { + payload := data + const maxDecodeLevels = 2 + + // If cty = `JWT`, we expect this to be a nested structure + var expectNested bool + +OUTER: + for i := range maxDecodeLevels { + switch kind := jwx.GuessFormat(payload); kind { + case jwx.JWT: + if ctx.pedantic { + if expectNested { + return nil, fmt.Errorf(`expected nested encrypted/signed payload, got raw JWT`) + } + } + + if i == 0 { + // We were NOT enveloped in other formats + if !ctx.skipVerification { + if _, _, err := verifyJWS(ctx, payload); err != nil { + return nil, err + } + } + } + + break OUTER + case jwx.InvalidFormat: + return nil, UnknownPayloadTypeError() + case jwx.UnknownFormat: + // "Unknown" may include invalid JWTs, for example, those who lack "aud" + // claim. We could be pedantic and reject these + if ctx.pedantic { + return nil, fmt.Errorf(`unknown JWT format (pedantic)`) + } + + if i == 0 { + // We were NOT enveloped in other formats + if !ctx.skipVerification { + if _, _, err := verifyJWS(ctx, payload); err != nil { + return nil, err + } + } + } + break OUTER + case jwx.JWS: + // Food for thought: This is going to break if you have multiple layers of + // JWS enveloping using different keys. It is highly unlikely use case, + // but it might happen. + + // skipVerification should only be set to true by us. It's used + // when we just want to parse the JWT out of a payload + if !ctx.skipVerification { + // nested return value means: + // false (next envelope _may_ need to be processed) + // true (next envelope MUST be processed) + v, state, err := verifyJWS(ctx, payload) + if err != nil { + return nil, err + } + + if state != _JwsVerifySkipped { + payload = v + + // We only check for cty and typ if the pedantic flag is enabled + if !ctx.pedantic { + continue + } + + if state == _JwsVerifyExpectNested { + expectNested = true + continue OUTER + } + + // if we're not nested, we found our target. bail out of this loop + break OUTER + } + } + + // No verification. + m, err := jws.Parse(data, jws.WithCompact()) + if err != nil { + return nil, fmt.Errorf(`invalid jws message: %w`, err) + } + payload = m.Payload() + default: + return nil, fmt.Errorf(`unsupported format (layer: #%d)`, i+1) + } + expectNested = false + } + + if ctx.token == nil { + ctx.token = New() + } + + if ctx.localReg != nil { + dcToken, ok := ctx.token.(TokenWithDecodeCtx) + if !ok { + return nil, fmt.Errorf(`typed claim was requested, but the token (%T) does not support DecodeCtx`, ctx.token) + } + dc := json.NewDecodeCtx(ctx.localReg) + dcToken.SetDecodeCtx(dc) + defer func() { dcToken.SetDecodeCtx(nil) }() + } + + if err := json.Unmarshal(payload, ctx.token); err != nil { + return nil, fmt.Errorf(`failed to parse token: %w`, err) + } + + if ctx.validate { + if err := Validate(ctx.token, ctx.validateOpts...); err != nil { + return nil, err + } + } + return ctx.token, nil +} + +// Sign is a convenience function to create a signed JWT token serialized in +// compact form. +// +// It accepts either a raw key (e.g. rsa.PrivateKey, ecdsa.PrivateKey, etc) +// or a jwk.Key, and the name of the algorithm that should be used to sign +// the token. +// +// For well-known algorithms with no special considerations (e.g. detached +// payloads, extra protected heders, etc), this function will automatically +// take the fast path and bypass the jws.Sign() machinery, which improves +// performance significantly. +// +// If the key is a jwk.Key and the key contains a key ID (`kid` field), +// then it is added to the protected header generated by the signature +// +// The algorithm specified in the `alg` parameter must be able to support +// the type of key you provided, otherwise an error is returned. +// For convenience `alg` is of type jwa.KeyAlgorithm so you can pass +// the return value of `(jwk.Key).Algorithm()` directly, but in practice +// it must be an instance of jwa.SignatureAlgorithm, otherwise an error +// is returned. +// +// The protected header will also automatically have the `typ` field set +// to the literal value `JWT`, unless you provide a custom value for it +// by jws.WithProtectedHeaders option, that can be passed to `jwt.WithKey“. +func Sign(t Token, options ...SignOption) ([]byte, error) { + // fast path; can only happen if there is exactly one option + if len(options) == 1 && (options[0].Ident() == identKey{}) { + // The option must be a withKey option. + var wk *withKey + if err := options[0].Value(&wk); err == nil { + alg, ok := wk.alg.(jwa.SignatureAlgorithm) + if !ok { + return nil, fmt.Errorf(`jwt.Sign: invalid algorithm type %T. jwa.SignatureAlgorithm is required`, wk.alg) + } + + // Check if option contains anything other than alg/key + if len(wk.options) == 0 { + // yay, we have something we can put in the FAST PATH! + return signFast(t, alg, wk.key) + } + // fallthrough + } + // fallthrough + } + + var soptions []jws.SignOption + if l := len(options); l > 0 { + // we need to from SignOption to Option because ... reasons + // (todo: when go1.18 prevails, use type parameters + rawoptions := make([]Option, l) + for i, option := range options { + rawoptions[i] = option + } + + converted, err := toSignOptions(rawoptions...) + if err != nil { + return nil, fmt.Errorf(`jwt.Sign: failed to convert options into jws.SignOption: %w`, err) + } + soptions = converted + } + return NewSerializer().sign(soptions...).Serialize(t) +} + +// Equal compares two JWT tokens. Do not use `reflect.Equal` or the like +// to compare tokens as they will also compare extra detail such as +// sync.Mutex objects used to control concurrent access. +// +// The comparison for values is currently done using a simple equality ("=="), +// except for time.Time, which uses time.Equal after dropping the monotonic +// clock and truncating the values to 1 second accuracy. +// +// if both t1 and t2 are nil, returns true +func Equal(t1, t2 Token) bool { + if t1 == nil && t2 == nil { + return true + } + + // we already checked for t1 == t2 == nil, so safe to do this + if t1 == nil || t2 == nil { + return false + } + + j1, err := json.Marshal(t1) + if err != nil { + return false + } + + j2, err := json.Marshal(t2) + if err != nil { + return false + } + + return bytes.Equal(j1, j2) +} + +func (t *stdToken) Clone() (Token, error) { + dst := New() + + dst.Options().Set(*(t.Options())) + for _, k := range t.Keys() { + var v any + if err := t.Get(k, &v); err != nil { + return nil, fmt.Errorf(`jwt.Clone: failed to get %s: %w`, k, err) + } + if err := dst.Set(k, v); err != nil { + return nil, fmt.Errorf(`jwt.Clone failed to set %s: %w`, k, err) + } + } + return dst, nil +} + +type CustomDecoder = json.CustomDecoder +type CustomDecodeFunc = json.CustomDecodeFunc + +// RegisterCustomField allows users to specify that a private field +// be decoded as an instance of the specified type. This option has +// a global effect. +// +// For example, suppose you have a custom field `x-birthday`, which +// you want to represent as a string formatted in RFC3339 in JSON, +// but want it back as `time.Time`. +// +// In such case you would register a custom field as follows +// +// jwt.RegisterCustomField(`x-birthday`, time.Time{}) +// +// Then you can use a `time.Time` variable to extract the value +// of `x-birthday` field, instead of having to use `any` +// and later convert it to `time.Time` +// +// var bday time.Time +// _ = token.Get(`x-birthday`, &bday) +// +// If you need a more fine-tuned control over the decoding process, +// you can register a `CustomDecoder`. For example, below shows +// how to register a decoder that can parse RFC822 format string: +// +// jwt.RegisterCustomField(`x-birthday`, jwt.CustomDecodeFunc(func(data []byte) (any, error) { +// return time.Parse(time.RFC822, string(data)) +// })) +// +// Please note that use of custom fields can be problematic if you +// are using a library that does not implement MarshalJSON/UnmarshalJSON +// and you try to roundtrip from an object to JSON, and then back to an object. +// For example, in the above example, you can _parse_ time values formatted +// in the format specified in RFC822, but when you convert an object into +// JSON, it will be formatted in RFC3339, because that's what `time.Time` +// likes to do. To avoid this, it's always better to use a custom type +// that wraps your desired type (in this case `time.Time`) and implement +// MarshalJSON and UnmashalJSON. +func RegisterCustomField(name string, object any) { + registry.Register(name, object) +} + +func getDefaultTruncation() time.Duration { + return time.Duration(defaultTruncation.Load()) +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwt/options.go b/vendor/github.com/lestrrat-go/jwx/v3/jwt/options.go new file mode 100644 index 00000000000..cadf163b151 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwt/options.go @@ -0,0 +1,322 @@ +package jwt + +import ( + "fmt" + "time" + + "github.com/lestrrat-go/jwx/v3/jwa" + "github.com/lestrrat-go/jwx/v3/jwe" + "github.com/lestrrat-go/jwx/v3/jwk" + "github.com/lestrrat-go/jwx/v3/jws" + "github.com/lestrrat-go/option/v2" +) + +type identInsecureNoSignature struct{} +type identKey struct{} +type identKeySet struct{} +type identTypedClaim struct{} +type identVerifyAuto struct{} + +func toSignOptions(options ...Option) ([]jws.SignOption, error) { + soptions := make([]jws.SignOption, 0, len(options)) + for _, option := range options { + switch option.Ident() { + case identInsecureNoSignature{}: + soptions = append(soptions, jws.WithInsecureNoSignature()) + case identKey{}: + var wk withKey + if err := option.Value(&wk); err != nil { + return nil, fmt.Errorf(`toSignOtpions: failed to convert option value to withKey: %w`, err) + } + var wksoptions []jws.WithKeySuboption + for _, subopt := range wk.options { + wksopt, ok := subopt.(jws.WithKeySuboption) + if !ok { + return nil, fmt.Errorf(`expected optional arguments in jwt.WithKey to be jws.WithKeySuboption, but got %T`, subopt) + } + wksoptions = append(wksoptions, wksopt) + } + + soptions = append(soptions, jws.WithKey(wk.alg, wk.key, wksoptions...)) + case identSignOption{}: + var sigOpt jws.SignOption + if err := option.Value(&sigOpt); err != nil { + return nil, fmt.Errorf(`failed to decode SignOption: %w`, err) + } + soptions = append(soptions, sigOpt) + case identBase64Encoder{}: + var enc jws.Base64Encoder + if err := option.Value(&enc); err != nil { + return nil, fmt.Errorf(`failed to decode Base64Encoder: %w`, err) + } + soptions = append(soptions, jws.WithBase64Encoder(enc)) + } + } + return soptions, nil +} + +func toEncryptOptions(options ...Option) ([]jwe.EncryptOption, error) { + soptions := make([]jwe.EncryptOption, 0, len(options)) + for _, option := range options { + switch option.Ident() { + case identKey{}: + var wk withKey + if err := option.Value(&wk); err != nil { + return nil, fmt.Errorf(`toEncryptOptions: failed to convert option value to withKey: %w`, err) + } + var wksoptions []jwe.WithKeySuboption + for _, subopt := range wk.options { + wksopt, ok := subopt.(jwe.WithKeySuboption) + if !ok { + return nil, fmt.Errorf(`expected optional arguments in jwt.WithKey to be jwe.WithKeySuboption, but got %T`, subopt) + } + wksoptions = append(wksoptions, wksopt) + } + + soptions = append(soptions, jwe.WithKey(wk.alg, wk.key, wksoptions...)) + case identEncryptOption{}: + var encOpt jwe.EncryptOption + if err := option.Value(&encOpt); err != nil { + return nil, fmt.Errorf(`failed to decode EncryptOption: %w`, err) + } + soptions = append(soptions, encOpt) + } + } + return soptions, nil +} + +func toVerifyOptions(options ...Option) ([]jws.VerifyOption, error) { + voptions := make([]jws.VerifyOption, 0, len(options)) + for _, option := range options { + switch option.Ident() { + case identKey{}: + var wk withKey + if err := option.Value(&wk); err != nil { + return nil, fmt.Errorf(`toVerifyOptions: failed to convert option value to withKey: %w`, err) + } + var wksoptions []jws.WithKeySuboption + for _, subopt := range wk.options { + wksopt, ok := subopt.(jws.WithKeySuboption) + if !ok { + return nil, fmt.Errorf(`expected optional arguments in jwt.WithKey to be jws.WithKeySuboption, but got %T`, subopt) + } + wksoptions = append(wksoptions, wksopt) + } + + voptions = append(voptions, jws.WithKey(wk.alg, wk.key, wksoptions...)) + case identKeySet{}: + var wks withKeySet + if err := option.Value(&wks); err != nil { + return nil, fmt.Errorf(`failed to convert option value to withKeySet: %w`, err) + } + var wkssoptions []jws.WithKeySetSuboption + for _, subopt := range wks.options { + wkssopt, ok := subopt.(jws.WithKeySetSuboption) + if !ok { + return nil, fmt.Errorf(`expected optional arguments in jwt.WithKey to be jws.WithKeySetSuboption, but got %T`, subopt) + } + wkssoptions = append(wkssoptions, wkssopt) + } + + voptions = append(voptions, jws.WithKeySet(wks.set, wkssoptions...)) + case identVerifyAuto{}: + var vo jws.VerifyOption + if err := option.Value(&vo); err != nil { + return nil, fmt.Errorf(`failed to decode VerifyOption: %w`, err) + } + voptions = append(voptions, vo) + case identKeyProvider{}: + var kp jws.KeyProvider + if err := option.Value(&kp); err != nil { + return nil, fmt.Errorf(`failed to decode KeyProvider: %w`, err) + } + voptions = append(voptions, jws.WithKeyProvider(kp)) + case identBase64Encoder{}: + var enc jws.Base64Encoder + if err := option.Value(&enc); err != nil { + return nil, fmt.Errorf(`failed to decode Base64Encoder: %w`, err) + } + voptions = append(voptions, jws.WithBase64Encoder(enc)) + } + } + return voptions, nil +} + +type withKey struct { + alg jwa.KeyAlgorithm + key any + options []Option +} + +// WithKey is a multipurpose option. It can be used for either jwt.Sign, jwt.Parse (and +// its siblings), and jwt.Serializer methods. For signatures, please see the documentation +// for `jws.WithKey` for more details. For encryption, please see the documentation +// for `jwe.WithKey`. +// +// It is the caller's responsibility to match the suboptions to the operation that they +// are performing. For example, you are not allowed to do this, because the operation +// is to generate a signature, and yet you are passing options for jwe: +// +// jwt.Sign(token, jwt.WithKey(alg, key, jweOptions...)) +// +// In the above example, the creation of the option via `jwt.WithKey()` will work, but +// when `jwt.Sign()` is called, the fact that you passed JWE suboptions will be +// detected, and an error will occur. +func WithKey(alg jwa.KeyAlgorithm, key any, suboptions ...Option) SignEncryptParseOption { + return &signEncryptParseOption{option.New(identKey{}, &withKey{ + alg: alg, + key: key, + options: suboptions, + })} +} + +type withKeySet struct { + set jwk.Set + options []any +} + +// WithKeySet forces the Parse method to verify the JWT message +// using one of the keys in the given key set. +// +// Key IDs (`kid`) in the JWS message and the JWK in the given `jwk.Set` +// must match in order for the key to be a candidate to be used for +// verification. +// +// This is for security reasons. If you must disable it, you can do so by +// specifying `jws.WithRequireKid(false)` in the suboptions. But we don't +// recommend it unless you know exactly what the security implications are +// +// When using this option, keys MUST have a proper 'alg' field +// set. This is because we need to know the exact algorithm that +// you (the user) wants to use to verify the token. We do NOT +// trust the token's headers, because they can easily be tampered with. +// +// However, there _is_ a workaround if you do understand the risks +// of allowing a library to automatically choose a signature verification strategy, +// and you do not mind the verification process having to possibly +// attempt using multiple times before succeeding to verify. See +// `jws.InferAlgorithmFromKey` option +// +// If you have only one key in the set, and are sure you want to +// use that key, you can use the `jwt.WithDefaultKey` option. +func WithKeySet(set jwk.Set, options ...any) ParseOption { + return &parseOption{option.New(identKeySet{}, &withKeySet{ + set: set, + options: options, + })} +} + +// WithIssuer specifies that expected issuer value. If not specified, +// the value of issuer is not verified at all. +func WithIssuer(s string) ValidateOption { + return WithValidator(issuerClaimValueIs(s)) +} + +// WithSubject specifies that expected subject value. If not specified, +// the value of subject is not verified at all. +func WithSubject(s string) ValidateOption { + return WithValidator(ClaimValueIs(SubjectKey, s)) +} + +// WithJwtID specifies that expected jti value. If not specified, +// the value of jti is not verified at all. +func WithJwtID(s string) ValidateOption { + return WithValidator(ClaimValueIs(JwtIDKey, s)) +} + +// WithAudience specifies that expected audience value. +// `Validate()` will return true if one of the values in the `aud` element +// matches this value. If not specified, the value of `aud` is not +// verified at all. +func WithAudience(s string) ValidateOption { + return WithValidator(audienceClaimContainsString(s)) +} + +// WithClaimValue specifies the expected value for a given claim +func WithClaimValue(name string, v any) ValidateOption { + return WithValidator(ClaimValueIs(name, v)) +} + +// WithTypedClaim allows a private claim to be parsed into the object type of +// your choice. It works much like the RegisterCustomField, but the effect +// is only applicable to the jwt.Parse function call which receives this option. +// +// While this can be extremely useful, this option should be used with caution: +// There are many caveats that your entire team/user-base needs to be aware of, +// and therefore in general its use is discouraged. Only use it when you know +// what you are doing, and you document its use clearly for others. +// +// First and foremost, this is a "per-object" option. Meaning that given the same +// serialized format, it is possible to generate two objects whose internal +// representations may differ. That is, if you parse one _WITH_ the option, +// and the other _WITHOUT_, their internal representation may completely differ. +// This could potentially lead to problems. +// +// Second, specifying this option will slightly slow down the decoding process +// as it needs to consult multiple definitions sources (global and local), so +// be careful if you are decoding a large number of tokens, as the effects will stack up. +// +// Finally, this option will also NOT work unless the tokens themselves support such +// parsing mechanism. For example, while tokens obtained from `jwt.New()` and +// `openid.New()` will respect this option, if you provide your own custom +// token type, it will need to implement the TokenWithDecodeCtx interface. +func WithTypedClaim(name string, object any) ParseOption { + return &parseOption{option.New(identTypedClaim{}, claimPair{Name: name, Value: object})} +} + +// WithRequiredClaim specifies that the claim identified the given name +// must exist in the token. Only the existence of the claim is checked: +// the actual value associated with that field is not checked. +func WithRequiredClaim(name string) ValidateOption { + return WithValidator(IsRequired(name)) +} + +// WithMaxDelta specifies that given two claims `c1` and `c2` that represent time, the difference in +// time.Duration must be less than equal to the value specified by `d`. If `c1` or `c2` is the +// empty string, the current time (as computed by `time.Now` or the object passed via +// `WithClock()`) is used for the comparison. +// +// `c1` and `c2` are also assumed to be required, therefore not providing either claim in the +// token will result in an error. +// +// Because there is no way of reliably knowing how to parse private claims, we currently only +// support `iat`, `exp`, and `nbf` claims. +// +// If the empty string is passed to c1 or c2, then the current time (as calculated by time.Now() or +// the clock object provided via WithClock()) is used. +// +// For example, in order to specify that `exp` - `iat` should be less than 10*time.Second, you would write +// +// jwt.Validate(token, jwt.WithMaxDelta(10*time.Second, jwt.ExpirationKey, jwt.IssuedAtKey)) +// +// If AcceptableSkew of 2 second is specified, the above will return valid for any value of +// `exp` - `iat` between 8 (10-2) and 12 (10+2). +func WithMaxDelta(dur time.Duration, c1, c2 string) ValidateOption { + return WithValidator(MaxDeltaIs(c1, c2, dur)) +} + +// WithMinDelta is almost exactly the same as WithMaxDelta, but force validation to fail if +// the difference between time claims are less than dur. +// +// For example, in order to specify that `exp` - `iat` should be greater than 10*time.Second, you would write +// +// jwt.Validate(token, jwt.WithMinDelta(10*time.Second, jwt.ExpirationKey, jwt.IssuedAtKey)) +// +// The validation would fail if the difference is less than 10 seconds. +func WithMinDelta(dur time.Duration, c1, c2 string) ValidateOption { + return WithValidator(MinDeltaIs(c1, c2, dur)) +} + +// WithVerifyAuto specifies that the JWS verification should be attempted +// by using the data available in the JWS message. Currently only verification +// method available is to use the keys available in the JWKS URL pointed +// in the `jku` field. +// +// Please read the documentation for `jws.VerifyAuto` for more details. +func WithVerifyAuto(f jwk.Fetcher, options ...jwk.FetchOption) ParseOption { + return &parseOption{option.New(identVerifyAuto{}, jws.WithVerifyAuto(f, options...))} +} + +func WithInsecureNoSignature() SignOption { + return &signEncryptParseOption{option.New(identInsecureNoSignature{}, (any)(nil))} +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwt/options.yaml b/vendor/github.com/lestrrat-go/jwx/v3/jwt/options.yaml new file mode 100644 index 00000000000..bfcadfac25c --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwt/options.yaml @@ -0,0 +1,274 @@ +package_name: jwt +output: jwt/options_gen.go +interfaces: + - name: GlobalOption + comment: | + GlobalOption describes an Option that can be passed to `Settings()`. + - name: EncryptOption + comment: | + EncryptOption describes an Option that can be passed to (jwt.Serializer).Encrypt + - name: ParseOption + methods: + - parseOption + - readFileOption + comment: | + ParseOption describes an Option that can be passed to `jwt.Parse()`. + ParseOption also implements ReadFileOption, therefore it may be + safely pass them to `jwt.ReadFile()` + - name: SignOption + comment: | + SignOption describes an Option that can be passed to `jwt.Sign()` or + (jwt.Serializer).Sign + - name: SignParseOption + methods: + - signOption + - parseOption + - readFileOption + comment: | + SignParseOption describes an Option that can be passed to both `jwt.Sign()` or + `jwt.Parse()` + - name: SignEncryptParseOption + methods: + - parseOption + - encryptOption + - readFileOption + - signOption + comment: | + SignEncryptParseOption describes an Option that can be passed to both `jwt.Sign()` or + `jwt.Parse()` + - name: ValidateOption + methods: + - parseOption + - readFileOption + - validateOption + comment: | + ValidateOption describes an Option that can be passed to Validate(). + ValidateOption also implements ParseOption, therefore it may be + safely passed to `Parse()` (and thus `jwt.ReadFile()`) + - name: ReadFileOption + comment: | + ReadFileOption is a type of `Option` that can be passed to `jws.ReadFile` + - name: GlobalValidateOption + methods: + - globalOption + - parseOption + - readFileOption + - validateOption + comment: | + GlobalValidateOption describes an Option that can be passed to `jwt.Settings()` and `jwt.Validate()` +options: + - ident: AcceptableSkew + interface: ValidateOption + argument_type: time.Duration + comment: | + WithAcceptableSkew specifies the duration in which exp, iat and nbf + claims may differ by. This value should be positive + - ident: Truncation + interface: GlobalValidateOption + argument_type: time.Duration + comment: | + WithTruncation specifies the amount that should be used when + truncating time values used during time-based validation routines, + and by default this is disabled. + + In v2 of this library, time values were truncated down to second accuracy, i.e. + 1.0000001 seconds is truncated to 1 second. To restore this behavior, set + this value to `time.Second` + + Since v3, this option can be passed to `jwt.Settings()` to set the truncation + value globally, as well as per invocation of `jwt.Validate()` + - ident: Clock + interface: ValidateOption + argument_type: Clock + comment: | + WithClock specifies the `Clock` to be used when verifying + exp, iat and nbf claims. + - ident: Context + interface: ValidateOption + argument_type: context.Context + comment: | + WithContext allows you to specify a context.Context object to be used + with `jwt.Validate()` option. + + Please be aware that in the next major release of this library, + `jwt.Validate()`'s signature will change to include an explicit + `context.Context` object. + - ident: ResetValidators + interface: ValidateOption + argument_type: bool + comment: | + WithResetValidators specifies that the default validators should be + reset before applying the custom validators. By default `jwt.Validate()` + checks for the validity of JWT by checking `exp`, `nbf`, and `iat`, even + when you specify more validators through other options. + + You SHOULD NOT use this option unless you know exactly what you are doing, + as this will pose significant security issues when used incorrectly. + + Using this option with the value `true` will remove all default checks, + and will expect you to specify validators as options. This is useful when you + want to skip the default validators and only use specific validators, such as + for https://openid.net/specs/openid-connect-rpinitiated-1_0.html, where + the token could be accepted even if the token is expired. + + If you set this option to true and you do not specify any validators, + `jwt.Validate()` will return an error. + + The default value is `false` (`iat`, `exp`, and `nbf` are automatically checked). + - ident: FlattenAudience + interface: GlobalOption + argument_type: bool + comment: | + WithFlattenAudience specifies the the `jwt.FlattenAudience` option on + every token defaults to enabled. You can still disable this on a per-object + basis using the `jwt.Options().Disable(jwt.FlattenAudience)` method call. + + See the documentation for `jwt.TokenOptionSet`, `(jwt.Token).Options`, and + `jwt.FlattenAudience` for more details + - ident: FormKey + interface: ParseOption + argument_type: string + comment: | + WithFormKey is used to specify header keys to search for tokens. + + While the type system allows this option to be passed to jwt.Parse() directly, + doing so will have no effect. Only use it for HTTP request parsing functions + - ident: HeaderKey + interface: ParseOption + argument_type: string + comment: | + WithHeaderKey is used to specify header keys to search for tokens. + + While the type system allows this option to be passed to `jwt.Parse()` directly, + doing so will have no effect. Only use it for HTTP request parsing functions + - ident: Cookie + interface: ParseOption + argument_type: '**http.Cookie' + comment: | + WithCookie is used to specify a variable to store the cookie used when `jwt.ParseCookie()` + is called. This allows you to inspect the cookie for additional information after a successful + parsing of the JWT token stored in the cookie. + + While the type system allows this option to be passed to `jwt.Parse()` directly, + doing so will have no effect. Only use it for HTTP request parsing functions + - ident: CookieKey + interface: ParseOption + argument_type: string + comment: | + WithCookieKey is used to specify cookie keys to search for tokens. + + While the type system allows this option to be passed to `jwt.Parse()` directly, + doing so will have no effect. Only use it for HTTP request parsing functions + - ident: Token + interface: ParseOption + argument_type: Token + comment: | + WithToken specifies the token instance in which the resulting JWT is stored + when parsing JWT tokens + - ident: Validate + interface: ParseOption + argument_type: bool + comment: | + WithValidate is passed to `Parse()` method to denote that the + validation of the JWT token should be performed (or not) after + a successful parsing of the incoming payload. + + This option is enabled by default. + + If you would like disable validation, + you must use `jwt.WithValidate(false)` or use `jwt.ParseInsecure()` + - ident: Verify + interface: ParseOption + argument_type: bool + comment: | + WithVerify is passed to `Parse()` method to denote that the + signature verification should be performed after a successful + deserialization of the incoming payload. + + This option is enabled by default. + + If you do not provide any verification key sources, `jwt.Parse()` + would return an error. + + If you would like to only parse the JWT payload and not verify it, + you must use `jwt.WithVerify(false)` or use `jwt.ParseInsecure()` + - ident: KeyProvider + interface: ParseOption + argument_type: jws.KeyProvider + comment: | + WithKeyProvider allows users to specify an object to provide keys to + sign/verify tokens using arbitrary code. Please read the documentation + for `jws.KeyProvider` in the `jws` package for details on how this works. + - ident: Pedantic + interface: ParseOption + argument_type: bool + comment: | + WithPedantic enables pedantic mode for parsing JWTs. Currently this only + applies to checking for the correct `typ` and/or `cty` when necessary. + - ident: EncryptOption + interface: EncryptOption + argument_type: jwe.EncryptOption + comment: | + WithEncryptOption provides an escape hatch for cases where extra options to + `(jws.Serializer).Encrypt()` must be specified when using `jwt.Sign()`. Normally you do not + need to use this. + - ident: SignOption + interface: SignOption + argument_type: jws.SignOption + comment: | + WithSignOption provides an escape hatch for cases where extra options to + `jws.Sign()` must be specified when using `jwt.Sign()`. Normally you do not + need to use this. + - ident: Validator + interface: ValidateOption + argument_type: Validator + comment: | + WithValidator validates the token with the given Validator. + + For example, in order to validate tokens that are only valid during August, you would write + + validator := jwt.ValidatorFunc(func(_ context.Context, t jwt.Token) error { + if time.Now().Month() != 8 { + return fmt.Errorf(`tokens are only valid during August!`) + } + return nil + }) + err := jwt.Validate(token, jwt.WithValidator(validator)) + - ident: FS + interface: ReadFileOption + argument_type: fs.FS + comment: | + WithFS specifies the source `fs.FS` object to read the file from. + - ident: NumericDateParsePrecision + interface: GlobalOption + argument_type: int + comment: | + WithNumericDateParsePrecision sets the precision up to which the + library uses to parse fractional dates found in the numeric date + fields. Default is 0 (second, no fractions), max is 9 (nanosecond) + - ident: NumericDateFormatPrecision + interface: GlobalOption + argument_type: int + comment: | + WithNumericDateFormatPrecision sets the precision up to which the + library uses to format fractional dates found in the numeric date + fields. Default is 0 (second, no fractions), max is 9 (nanosecond) + - ident: NumericDateParsePedantic + interface: GlobalOption + argument_type: bool + comment: | + WithNumericDateParsePedantic specifies if the parser should behave + in a pedantic manner when parsing numeric dates. Normally this library + attempts to interpret timestamps as a numeric value representing + number of seconds (with an optional fractional part), but if that fails + it tries to parse using a RFC3339 parser. This allows us to parse + payloads from non-conforming servers. + + However, when you set WithNumericDateParePedantic to `true`, the + RFC3339 parser is not tried, and we expect a numeric value strictly + - ident: Base64Encoder + interface: SignParseOption + argument_type: jws.Base64Encoder + comment: | + WithBase64Encoder specifies the base64 encoder to use for signing + tokens and verifying JWS signatures. \ No newline at end of file diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwt/options_gen.go b/vendor/github.com/lestrrat-go/jwx/v3/jwt/options_gen.go new file mode 100644 index 00000000000..3a644a6e4ca --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwt/options_gen.go @@ -0,0 +1,495 @@ +// Code generated by tools/cmd/genoptions/main.go. DO NOT EDIT. + +package jwt + +import ( + "context" + "io/fs" + "net/http" + "time" + + "github.com/lestrrat-go/jwx/v3/jwe" + "github.com/lestrrat-go/jwx/v3/jws" + "github.com/lestrrat-go/option/v2" +) + +type Option = option.Interface + +// EncryptOption describes an Option that can be passed to (jwt.Serializer).Encrypt +type EncryptOption interface { + Option + encryptOption() +} + +type encryptOption struct { + Option +} + +func (*encryptOption) encryptOption() {} + +// GlobalOption describes an Option that can be passed to `Settings()`. +type GlobalOption interface { + Option + globalOption() +} + +type globalOption struct { + Option +} + +func (*globalOption) globalOption() {} + +// GlobalValidateOption describes an Option that can be passed to `jwt.Settings()` and `jwt.Validate()` +type GlobalValidateOption interface { + Option + globalOption() + parseOption() + readFileOption() + validateOption() +} + +type globalValidateOption struct { + Option +} + +func (*globalValidateOption) globalOption() {} + +func (*globalValidateOption) parseOption() {} + +func (*globalValidateOption) readFileOption() {} + +func (*globalValidateOption) validateOption() {} + +// ParseOption describes an Option that can be passed to `jwt.Parse()`. +// ParseOption also implements ReadFileOption, therefore it may be +// safely pass them to `jwt.ReadFile()` +type ParseOption interface { + Option + parseOption() + readFileOption() +} + +type parseOption struct { + Option +} + +func (*parseOption) parseOption() {} + +func (*parseOption) readFileOption() {} + +// ReadFileOption is a type of `Option` that can be passed to `jws.ReadFile` +type ReadFileOption interface { + Option + readFileOption() +} + +type readFileOption struct { + Option +} + +func (*readFileOption) readFileOption() {} + +// SignEncryptParseOption describes an Option that can be passed to both `jwt.Sign()` or +// `jwt.Parse()` +type SignEncryptParseOption interface { + Option + parseOption() + encryptOption() + readFileOption() + signOption() +} + +type signEncryptParseOption struct { + Option +} + +func (*signEncryptParseOption) parseOption() {} + +func (*signEncryptParseOption) encryptOption() {} + +func (*signEncryptParseOption) readFileOption() {} + +func (*signEncryptParseOption) signOption() {} + +// SignOption describes an Option that can be passed to `jwt.Sign()` or +// (jwt.Serializer).Sign +type SignOption interface { + Option + signOption() +} + +type signOption struct { + Option +} + +func (*signOption) signOption() {} + +// SignParseOption describes an Option that can be passed to both `jwt.Sign()` or +// `jwt.Parse()` +type SignParseOption interface { + Option + signOption() + parseOption() + readFileOption() +} + +type signParseOption struct { + Option +} + +func (*signParseOption) signOption() {} + +func (*signParseOption) parseOption() {} + +func (*signParseOption) readFileOption() {} + +// ValidateOption describes an Option that can be passed to Validate(). +// ValidateOption also implements ParseOption, therefore it may be +// safely passed to `Parse()` (and thus `jwt.ReadFile()`) +type ValidateOption interface { + Option + parseOption() + readFileOption() + validateOption() +} + +type validateOption struct { + Option +} + +func (*validateOption) parseOption() {} + +func (*validateOption) readFileOption() {} + +func (*validateOption) validateOption() {} + +type identAcceptableSkew struct{} +type identBase64Encoder struct{} +type identClock struct{} +type identContext struct{} +type identCookie struct{} +type identCookieKey struct{} +type identEncryptOption struct{} +type identFS struct{} +type identFlattenAudience struct{} +type identFormKey struct{} +type identHeaderKey struct{} +type identKeyProvider struct{} +type identNumericDateFormatPrecision struct{} +type identNumericDateParsePedantic struct{} +type identNumericDateParsePrecision struct{} +type identPedantic struct{} +type identResetValidators struct{} +type identSignOption struct{} +type identToken struct{} +type identTruncation struct{} +type identValidate struct{} +type identValidator struct{} +type identVerify struct{} + +func (identAcceptableSkew) String() string { + return "WithAcceptableSkew" +} + +func (identBase64Encoder) String() string { + return "WithBase64Encoder" +} + +func (identClock) String() string { + return "WithClock" +} + +func (identContext) String() string { + return "WithContext" +} + +func (identCookie) String() string { + return "WithCookie" +} + +func (identCookieKey) String() string { + return "WithCookieKey" +} + +func (identEncryptOption) String() string { + return "WithEncryptOption" +} + +func (identFS) String() string { + return "WithFS" +} + +func (identFlattenAudience) String() string { + return "WithFlattenAudience" +} + +func (identFormKey) String() string { + return "WithFormKey" +} + +func (identHeaderKey) String() string { + return "WithHeaderKey" +} + +func (identKeyProvider) String() string { + return "WithKeyProvider" +} + +func (identNumericDateFormatPrecision) String() string { + return "WithNumericDateFormatPrecision" +} + +func (identNumericDateParsePedantic) String() string { + return "WithNumericDateParsePedantic" +} + +func (identNumericDateParsePrecision) String() string { + return "WithNumericDateParsePrecision" +} + +func (identPedantic) String() string { + return "WithPedantic" +} + +func (identResetValidators) String() string { + return "WithResetValidators" +} + +func (identSignOption) String() string { + return "WithSignOption" +} + +func (identToken) String() string { + return "WithToken" +} + +func (identTruncation) String() string { + return "WithTruncation" +} + +func (identValidate) String() string { + return "WithValidate" +} + +func (identValidator) String() string { + return "WithValidator" +} + +func (identVerify) String() string { + return "WithVerify" +} + +// WithAcceptableSkew specifies the duration in which exp, iat and nbf +// claims may differ by. This value should be positive +func WithAcceptableSkew(v time.Duration) ValidateOption { + return &validateOption{option.New(identAcceptableSkew{}, v)} +} + +// WithBase64Encoder specifies the base64 encoder to use for signing +// tokens and verifying JWS signatures. +func WithBase64Encoder(v jws.Base64Encoder) SignParseOption { + return &signParseOption{option.New(identBase64Encoder{}, v)} +} + +// WithClock specifies the `Clock` to be used when verifying +// exp, iat and nbf claims. +func WithClock(v Clock) ValidateOption { + return &validateOption{option.New(identClock{}, v)} +} + +// WithContext allows you to specify a context.Context object to be used +// with `jwt.Validate()` option. +// +// Please be aware that in the next major release of this library, +// `jwt.Validate()`'s signature will change to include an explicit +// `context.Context` object. +func WithContext(v context.Context) ValidateOption { + return &validateOption{option.New(identContext{}, v)} +} + +// WithCookie is used to specify a variable to store the cookie used when `jwt.ParseCookie()` +// is called. This allows you to inspect the cookie for additional information after a successful +// parsing of the JWT token stored in the cookie. +// +// While the type system allows this option to be passed to `jwt.Parse()` directly, +// doing so will have no effect. Only use it for HTTP request parsing functions +func WithCookie(v **http.Cookie) ParseOption { + return &parseOption{option.New(identCookie{}, v)} +} + +// WithCookieKey is used to specify cookie keys to search for tokens. +// +// While the type system allows this option to be passed to `jwt.Parse()` directly, +// doing so will have no effect. Only use it for HTTP request parsing functions +func WithCookieKey(v string) ParseOption { + return &parseOption{option.New(identCookieKey{}, v)} +} + +// WithEncryptOption provides an escape hatch for cases where extra options to +// `(jws.Serializer).Encrypt()` must be specified when using `jwt.Sign()`. Normally you do not +// need to use this. +func WithEncryptOption(v jwe.EncryptOption) EncryptOption { + return &encryptOption{option.New(identEncryptOption{}, v)} +} + +// WithFS specifies the source `fs.FS` object to read the file from. +func WithFS(v fs.FS) ReadFileOption { + return &readFileOption{option.New(identFS{}, v)} +} + +// WithFlattenAudience specifies the the `jwt.FlattenAudience` option on +// every token defaults to enabled. You can still disable this on a per-object +// basis using the `jwt.Options().Disable(jwt.FlattenAudience)` method call. +// +// See the documentation for `jwt.TokenOptionSet`, `(jwt.Token).Options`, and +// `jwt.FlattenAudience` for more details +func WithFlattenAudience(v bool) GlobalOption { + return &globalOption{option.New(identFlattenAudience{}, v)} +} + +// WithFormKey is used to specify header keys to search for tokens. +// +// While the type system allows this option to be passed to jwt.Parse() directly, +// doing so will have no effect. Only use it for HTTP request parsing functions +func WithFormKey(v string) ParseOption { + return &parseOption{option.New(identFormKey{}, v)} +} + +// WithHeaderKey is used to specify header keys to search for tokens. +// +// While the type system allows this option to be passed to `jwt.Parse()` directly, +// doing so will have no effect. Only use it for HTTP request parsing functions +func WithHeaderKey(v string) ParseOption { + return &parseOption{option.New(identHeaderKey{}, v)} +} + +// WithKeyProvider allows users to specify an object to provide keys to +// sign/verify tokens using arbitrary code. Please read the documentation +// for `jws.KeyProvider` in the `jws` package for details on how this works. +func WithKeyProvider(v jws.KeyProvider) ParseOption { + return &parseOption{option.New(identKeyProvider{}, v)} +} + +// WithNumericDateFormatPrecision sets the precision up to which the +// library uses to format fractional dates found in the numeric date +// fields. Default is 0 (second, no fractions), max is 9 (nanosecond) +func WithNumericDateFormatPrecision(v int) GlobalOption { + return &globalOption{option.New(identNumericDateFormatPrecision{}, v)} +} + +// WithNumericDateParsePedantic specifies if the parser should behave +// in a pedantic manner when parsing numeric dates. Normally this library +// attempts to interpret timestamps as a numeric value representing +// number of seconds (with an optional fractional part), but if that fails +// it tries to parse using a RFC3339 parser. This allows us to parse +// payloads from non-conforming servers. +// +// However, when you set WithNumericDateParePedantic to `true`, the +// RFC3339 parser is not tried, and we expect a numeric value strictly +func WithNumericDateParsePedantic(v bool) GlobalOption { + return &globalOption{option.New(identNumericDateParsePedantic{}, v)} +} + +// WithNumericDateParsePrecision sets the precision up to which the +// library uses to parse fractional dates found in the numeric date +// fields. Default is 0 (second, no fractions), max is 9 (nanosecond) +func WithNumericDateParsePrecision(v int) GlobalOption { + return &globalOption{option.New(identNumericDateParsePrecision{}, v)} +} + +// WithPedantic enables pedantic mode for parsing JWTs. Currently this only +// applies to checking for the correct `typ` and/or `cty` when necessary. +func WithPedantic(v bool) ParseOption { + return &parseOption{option.New(identPedantic{}, v)} +} + +// WithResetValidators specifies that the default validators should be +// reset before applying the custom validators. By default `jwt.Validate()` +// checks for the validity of JWT by checking `exp`, `nbf`, and `iat`, even +// when you specify more validators through other options. +// +// You SHOULD NOT use this option unless you know exactly what you are doing, +// as this will pose significant security issues when used incorrectly. +// +// Using this option with the value `true` will remove all default checks, +// and will expect you to specify validators as options. This is useful when you +// want to skip the default validators and only use specific validators, such as +// for https://openid.net/specs/openid-connect-rpinitiated-1_0.html, where +// the token could be accepted even if the token is expired. +// +// If you set this option to true and you do not specify any validators, +// `jwt.Validate()` will return an error. +// +// The default value is `false` (`iat`, `exp`, and `nbf` are automatically checked). +func WithResetValidators(v bool) ValidateOption { + return &validateOption{option.New(identResetValidators{}, v)} +} + +// WithSignOption provides an escape hatch for cases where extra options to +// `jws.Sign()` must be specified when using `jwt.Sign()`. Normally you do not +// need to use this. +func WithSignOption(v jws.SignOption) SignOption { + return &signOption{option.New(identSignOption{}, v)} +} + +// WithToken specifies the token instance in which the resulting JWT is stored +// when parsing JWT tokens +func WithToken(v Token) ParseOption { + return &parseOption{option.New(identToken{}, v)} +} + +// WithTruncation specifies the amount that should be used when +// truncating time values used during time-based validation routines, +// and by default this is disabled. +// +// In v2 of this library, time values were truncated down to second accuracy, i.e. +// 1.0000001 seconds is truncated to 1 second. To restore this behavior, set +// this value to `time.Second` +// +// Since v3, this option can be passed to `jwt.Settings()` to set the truncation +// value globally, as well as per invocation of `jwt.Validate()` +func WithTruncation(v time.Duration) GlobalValidateOption { + return &globalValidateOption{option.New(identTruncation{}, v)} +} + +// WithValidate is passed to `Parse()` method to denote that the +// validation of the JWT token should be performed (or not) after +// a successful parsing of the incoming payload. +// +// This option is enabled by default. +// +// If you would like disable validation, +// you must use `jwt.WithValidate(false)` or use `jwt.ParseInsecure()` +func WithValidate(v bool) ParseOption { + return &parseOption{option.New(identValidate{}, v)} +} + +// WithValidator validates the token with the given Validator. +// +// For example, in order to validate tokens that are only valid during August, you would write +// +// validator := jwt.ValidatorFunc(func(_ context.Context, t jwt.Token) error { +// if time.Now().Month() != 8 { +// return fmt.Errorf(`tokens are only valid during August!`) +// } +// return nil +// }) +// err := jwt.Validate(token, jwt.WithValidator(validator)) +func WithValidator(v Validator) ValidateOption { + return &validateOption{option.New(identValidator{}, v)} +} + +// WithVerify is passed to `Parse()` method to denote that the +// signature verification should be performed after a successful +// deserialization of the incoming payload. +// +// This option is enabled by default. +// +// If you do not provide any verification key sources, `jwt.Parse()` +// would return an error. +// +// If you would like to only parse the JWT payload and not verify it, +// you must use `jwt.WithVerify(false)` or use `jwt.ParseInsecure()` +func WithVerify(v bool) ParseOption { + return &parseOption{option.New(identVerify{}, v)} +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwt/serialize.go b/vendor/github.com/lestrrat-go/jwx/v3/jwt/serialize.go new file mode 100644 index 00000000000..9d3bdac94ad --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwt/serialize.go @@ -0,0 +1,264 @@ +package jwt + +import ( + "fmt" + + "github.com/lestrrat-go/jwx/v3/internal/json" + "github.com/lestrrat-go/jwx/v3/jwe" + "github.com/lestrrat-go/jwx/v3/jws" +) + +type SerializeCtx interface { + Step() int + Nested() bool +} + +type serializeCtx struct { + step int + nested bool +} + +func (ctx *serializeCtx) Step() int { + return ctx.step +} + +func (ctx *serializeCtx) Nested() bool { + return ctx.nested +} + +type SerializeStep interface { + Serialize(SerializeCtx, any) (any, error) +} + +// errStep is always an error. used to indicate that a method like +// serializer.Sign or Encrypt already errored out on configuration +type errStep struct { + err error +} + +func (e errStep) Serialize(_ SerializeCtx, _ any) (any, error) { + return nil, e.err +} + +// Serializer is a generic serializer for JWTs. Whereas other convenience +// functions can only do one thing (such as generate a JWS signed JWT), +// Using this construct you can serialize the token however you want. +// +// By default, the serializer only marshals the token into a JSON payload. +// You must set up the rest of the steps that should be taken by the +// serializer. +// +// For example, to marshal the token into JSON, then apply JWS and JWE +// in that order, you would do: +// +// serialized, err := jwt.NewSerializer(). +// Sign(jwa.RS256, key). +// Encrypt(jwe.WithEncryptOption(jwe.WithKey(jwa.RSA_OAEP(), publicKey))). +// Serialize(token) +// +// The `jwt.Sign()` function is equivalent to +// +// serialized, err := jwt.NewSerializer(). +// Sign(...args...). +// Serialize(token) +type Serializer struct { + steps []SerializeStep +} + +// NewSerializer creates a new empty serializer. +func NewSerializer() *Serializer { + return &Serializer{} +} + +// Reset clears all of the registered steps. +func (s *Serializer) Reset() *Serializer { + s.steps = nil + return s +} + +// Step adds a new Step to the serialization process +func (s *Serializer) Step(step SerializeStep) *Serializer { + s.steps = append(s.steps, step) + return s +} + +type jsonSerializer struct{} + +func (jsonSerializer) Serialize(_ SerializeCtx, v any) (any, error) { + token, ok := v.(Token) + if !ok { + return nil, fmt.Errorf(`invalid input: expected jwt.Token`) + } + + buf, err := json.Marshal(token) + if err != nil { + return nil, fmt.Errorf(`failed to serialize as JSON: %w`, err) + } + return buf, nil +} + +type genericHeader interface { + Get(string, any) error + Set(string, any) error + Has(string) bool +} + +func setTypeOrCty(ctx SerializeCtx, hdrs genericHeader) error { + // cty and typ are common between JWE/JWS, so we don't use + // the constants in jws/jwe package here + const typKey = `typ` + const ctyKey = `cty` + + if ctx.Step() == 1 { + // We are executed immediately after json marshaling + if !hdrs.Has(typKey) { + if err := hdrs.Set(typKey, `JWT`); err != nil { + return fmt.Errorf(`failed to set %s key to "JWT": %w`, typKey, err) + } + } + } else { + if ctx.Nested() { + // If this is part of a nested sequence, we should set cty = 'JWT' + // https://datatracker.ietf.org/doc/html/rfc7519#section-5.2 + if err := hdrs.Set(ctyKey, `JWT`); err != nil { + return fmt.Errorf(`failed to set %s key to "JWT": %w`, ctyKey, err) + } + } + } + return nil +} + +type jwsSerializer struct { + options []jws.SignOption +} + +func (s *jwsSerializer) Serialize(ctx SerializeCtx, v any) (any, error) { + payload, ok := v.([]byte) + if !ok { + return nil, fmt.Errorf(`expected []byte as input`) + } + + for _, option := range s.options { + var pc interface{ Protected(jws.Headers) jws.Headers } + if err := option.Value(&pc); err != nil { + continue + } + hdrs := pc.Protected(jws.NewHeaders()) + if err := setTypeOrCty(ctx, hdrs); err != nil { + return nil, err // this is already wrapped + } + + // JWTs MUST NOT use b64 = false + // https://datatracker.ietf.org/doc/html/rfc7797#section-7 + var b64 bool + if err := hdrs.Get("b64", &b64); err == nil { + if !b64 { // b64 = false + return nil, fmt.Errorf(`b64 cannot be false for JWTs`) + } + } + } + return jws.Sign(payload, s.options...) +} + +func (s *Serializer) Sign(options ...SignOption) *Serializer { + var soptions []jws.SignOption + if l := len(options); l > 0 { + // we need to from SignOption to Option because ... reasons + // (todo: when go1.18 prevails, use type parameters + rawoptions := make([]Option, l) + for i, option := range options { + rawoptions[i] = option + } + + converted, err := toSignOptions(rawoptions...) + if err != nil { + return s.Step(errStep{fmt.Errorf(`(jwt.Serializer).Sign: failed to convert options into jws.SignOption: %w`, err)}) + } + soptions = converted + } + return s.sign(soptions...) +} + +func (s *Serializer) sign(options ...jws.SignOption) *Serializer { + return s.Step(&jwsSerializer{ + options: options, + }) +} + +type jweSerializer struct { + options []jwe.EncryptOption +} + +func (s *jweSerializer) Serialize(ctx SerializeCtx, v any) (any, error) { + payload, ok := v.([]byte) + if !ok { + return nil, fmt.Errorf(`expected []byte as input`) + } + + hdrs := jwe.NewHeaders() + if err := setTypeOrCty(ctx, hdrs); err != nil { + return nil, err // this is already wrapped + } + + options := append([]jwe.EncryptOption{jwe.WithMergeProtectedHeaders(true), jwe.WithProtectedHeaders(hdrs)}, s.options...) + return jwe.Encrypt(payload, options...) +} + +// Encrypt specifies the JWT to be serialized as an encrypted payload. +// +// One notable difference between this method and `jwe.Encrypt()` is that +// while `jwe.Encrypt()` OVERWRITES the previous headers when `jwe.WithProtectedHeaders()` +// is provided, this method MERGES them. This is due to the fact that we +// MUST add some extra headers to construct a proper JWE message. +// Be careful when you pass multiple `jwe.EncryptOption`s. +func (s *Serializer) Encrypt(options ...EncryptOption) *Serializer { + var eoptions []jwe.EncryptOption + if l := len(options); l > 0 { + // we need to from SignOption to Option because ... reasons + // (todo: when go1.18 prevails, use type parameters + rawoptions := make([]Option, l) + for i, option := range options { + rawoptions[i] = option + } + + converted, err := toEncryptOptions(rawoptions...) + if err != nil { + return s.Step(errStep{fmt.Errorf(`(jwt.Serializer).Encrypt: failed to convert options into jwe.EncryptOption: %w`, err)}) + } + eoptions = converted + } + return s.encrypt(eoptions...) +} + +func (s *Serializer) encrypt(options ...jwe.EncryptOption) *Serializer { + return s.Step(&jweSerializer{ + options: options, + }) +} + +func (s *Serializer) Serialize(t Token) ([]byte, error) { + steps := make([]SerializeStep, len(s.steps)+1) + steps[0] = jsonSerializer{} + for i, step := range s.steps { + steps[i+1] = step + } + + var ctx serializeCtx + ctx.nested = len(s.steps) > 1 + var payload any = t + for i, step := range steps { + ctx.step = i + v, err := step.Serialize(&ctx, payload) + if err != nil { + return nil, fmt.Errorf(`failed to serialize token at step #%d: %w`, i+1, err) + } + payload = v + } + + res, ok := payload.([]byte) + if !ok { + return nil, fmt.Errorf(`invalid serialization produced`) + } + + return res, nil +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwt/token_gen.go b/vendor/github.com/lestrrat-go/jwx/v3/jwt/token_gen.go new file mode 100644 index 00000000000..2361ff56218 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwt/token_gen.go @@ -0,0 +1,635 @@ +// Code generated by tools/cmd/genjwt/main.go. DO NOT EDIT. + +package jwt + +import ( + "bytes" + "fmt" + "sort" + "sync" + "time" + + "github.com/lestrrat-go/blackmagic" + "github.com/lestrrat-go/jwx/v3/internal/json" + "github.com/lestrrat-go/jwx/v3/internal/pool" + "github.com/lestrrat-go/jwx/v3/internal/tokens" + jwterrs "github.com/lestrrat-go/jwx/v3/jwt/internal/errors" + "github.com/lestrrat-go/jwx/v3/jwt/internal/types" +) + +const ( + AudienceKey = "aud" + ExpirationKey = "exp" + IssuedAtKey = "iat" + IssuerKey = "iss" + JwtIDKey = "jti" + NotBeforeKey = "nbf" + SubjectKey = "sub" +) + +// stdClaimNames is a list of all standard claim names defined in the JWT specification. +var stdClaimNames = []string{AudienceKey, ExpirationKey, IssuedAtKey, IssuerKey, JwtIDKey, NotBeforeKey, SubjectKey} + +// Token represents a generic JWT token. +// which are type-aware (to an extent). Other claims may be accessed via the `Get`/`Set` +// methods but their types are not taken into consideration at all. If you have non-standard +// claims that you must frequently access, consider creating accessors functions +// like the following +// +// func SetFoo(tok jwt.Token) error +// func GetFoo(tok jwt.Token) (*Customtyp, error) +// +// Embedding jwt.Token into another struct is not recommended, because +// jwt.Token needs to handle private claims, and this really does not +// work well when it is embedded in other structure +type Token interface { + // Audience returns the value for "aud" field of the token + Audience() ([]string, bool) + + // Expiration returns the value for "exp" field of the token + Expiration() (time.Time, bool) + + // IssuedAt returns the value for "iat" field of the token + IssuedAt() (time.Time, bool) + + // Issuer returns the value for "iss" field of the token + Issuer() (string, bool) + + // JwtID returns the value for "jti" field of the token + JwtID() (string, bool) + + // NotBefore returns the value for "nbf" field of the token + NotBefore() (time.Time, bool) + + // Subject returns the value for "sub" field of the token + Subject() (string, bool) + + // Get is used to extract the value of any claim, including non-standard claims, out of the token. + // + // The first argument is the name of the claim. The second argument is a pointer + // to a variable that will receive the value of the claim. The method returns + // an error if the claim does not exist, or if the value cannot be assigned to + // the destination variable. Note that a field is considered to "exist" even if + // the value is empty-ish (e.g. 0, false, ""), as long as it is explicitly set. + // + // For standard claims, you can use the corresponding getter method, such as + // `Issuer()`, `Subject()`, `Audience()`, `IssuedAt()`, `NotBefore()`, `ExpiresAt()` + // + // Note that fields of JWS/JWE are NOT accessible through this method. You need + // to use `jws.Parse` and `jwe.Parse` to obtain the JWS/JWE message (and NOT + // the payload, which presumably is the JWT), and then use their `Get` methods in their respective packages + Get(string, any) error + + // Set assigns a value to the corresponding field in the token. Some + // pre-defined fields such as `nbf`, `iat`, `iss` need their values to + // be of a specific type. See the other getter methods in this interface + // for the types of each of these fields + Set(string, any) error + + // Has returns true if the specified claim has a value, even if + // the value is empty-ish (e.g. 0, false, "") as long as it has been + // explicitly set. + Has(string) bool + Remove(string) error + + // Options returns the per-token options associated with this token. + // The options set value will be copied when the token is cloned via `Clone()` + // but it will not survive when the token goes through marshaling/unmarshaling + // such as `json.Marshal` and `json.Unmarshal` + Options() *TokenOptionSet + Clone() (Token, error) + Keys() []string +} +type stdToken struct { + mu *sync.RWMutex + dc DecodeCtx // per-object context for decoding + options TokenOptionSet // per-object option + audience types.StringList // https://tools.ietf.org/html/rfc7519#section-4.1.3 + expiration *types.NumericDate // https://tools.ietf.org/html/rfc7519#section-4.1.4 + issuedAt *types.NumericDate // https://tools.ietf.org/html/rfc7519#section-4.1.6 + issuer *string // https://tools.ietf.org/html/rfc7519#section-4.1.1 + jwtID *string // https://tools.ietf.org/html/rfc7519#section-4.1.7 + notBefore *types.NumericDate // https://tools.ietf.org/html/rfc7519#section-4.1.5 + subject *string // https://tools.ietf.org/html/rfc7519#section-4.1.2 + privateClaims map[string]any +} + +// New creates a standard token, with minimal knowledge of +// possible claims. Standard claims include"aud", "exp", "iat", "iss", "jti", "nbf" and "sub". +// Convenience accessors are provided for these standard claims +func New() Token { + return &stdToken{ + mu: &sync.RWMutex{}, + privateClaims: make(map[string]any), + options: DefaultOptionSet(), + } +} + +func (t *stdToken) Options() *TokenOptionSet { + return &t.options +} + +func (t *stdToken) Has(name string) bool { + t.mu.RLock() + defer t.mu.RUnlock() + switch name { + case AudienceKey: + return t.audience != nil + case ExpirationKey: + return t.expiration != nil + case IssuedAtKey: + return t.issuedAt != nil + case IssuerKey: + return t.issuer != nil + case JwtIDKey: + return t.jwtID != nil + case NotBeforeKey: + return t.notBefore != nil + case SubjectKey: + return t.subject != nil + default: + _, ok := t.privateClaims[name] + return ok + } +} + +func (t *stdToken) Get(name string, dst any) error { + t.mu.RLock() + defer t.mu.RUnlock() + switch name { + case AudienceKey: + if t.audience == nil { + return jwterrs.ClaimNotFoundError{Name: name} + } + if err := blackmagic.AssignIfCompatible(dst, t.audience.Get()); err != nil { + return jwterrs.ClaimAssignmentFailedError{Err: err} + } + return nil + case ExpirationKey: + if t.expiration == nil { + return jwterrs.ClaimNotFoundError{Name: name} + } + if err := blackmagic.AssignIfCompatible(dst, t.expiration.Get()); err != nil { + return jwterrs.ClaimAssignmentFailedError{Err: err} + } + return nil + case IssuedAtKey: + if t.issuedAt == nil { + return jwterrs.ClaimNotFoundError{Name: name} + } + if err := blackmagic.AssignIfCompatible(dst, t.issuedAt.Get()); err != nil { + return jwterrs.ClaimAssignmentFailedError{Err: err} + } + return nil + case IssuerKey: + if t.issuer == nil { + return jwterrs.ClaimNotFoundError{Name: name} + } + if err := blackmagic.AssignIfCompatible(dst, *(t.issuer)); err != nil { + return jwterrs.ClaimAssignmentFailedError{Err: err} + } + return nil + case JwtIDKey: + if t.jwtID == nil { + return jwterrs.ClaimNotFoundError{Name: name} + } + if err := blackmagic.AssignIfCompatible(dst, *(t.jwtID)); err != nil { + return jwterrs.ClaimAssignmentFailedError{Err: err} + } + return nil + case NotBeforeKey: + if t.notBefore == nil { + return jwterrs.ClaimNotFoundError{Name: name} + } + if err := blackmagic.AssignIfCompatible(dst, t.notBefore.Get()); err != nil { + return jwterrs.ClaimAssignmentFailedError{Err: err} + } + return nil + case SubjectKey: + if t.subject == nil { + return jwterrs.ClaimNotFoundError{Name: name} + } + if err := blackmagic.AssignIfCompatible(dst, *(t.subject)); err != nil { + return jwterrs.ClaimAssignmentFailedError{Err: err} + } + return nil + default: + v, ok := t.privateClaims[name] + if !ok { + return jwterrs.ClaimNotFoundError{Name: name} + } + if err := blackmagic.AssignIfCompatible(dst, v); err != nil { + return jwterrs.ClaimAssignmentFailedError{Err: err} + } + return nil + } +} + +func (t *stdToken) Remove(key string) error { + t.mu.Lock() + defer t.mu.Unlock() + switch key { + case AudienceKey: + t.audience = nil + case ExpirationKey: + t.expiration = nil + case IssuedAtKey: + t.issuedAt = nil + case IssuerKey: + t.issuer = nil + case JwtIDKey: + t.jwtID = nil + case NotBeforeKey: + t.notBefore = nil + case SubjectKey: + t.subject = nil + default: + delete(t.privateClaims, key) + } + return nil +} + +func (t *stdToken) Set(name string, value any) error { + t.mu.Lock() + defer t.mu.Unlock() + return t.setNoLock(name, value) +} + +func (t *stdToken) DecodeCtx() DecodeCtx { + t.mu.RLock() + defer t.mu.RUnlock() + return t.dc +} + +func (t *stdToken) SetDecodeCtx(v DecodeCtx) { + t.mu.Lock() + defer t.mu.Unlock() + t.dc = v +} + +func (t *stdToken) setNoLock(name string, value any) error { + switch name { + case AudienceKey: + var acceptor types.StringList + if err := acceptor.Accept(value); err != nil { + return fmt.Errorf(`invalid value for %s key: %w`, AudienceKey, err) + } + t.audience = acceptor + return nil + case ExpirationKey: + var acceptor types.NumericDate + if err := acceptor.Accept(value); err != nil { + return fmt.Errorf(`invalid value for %s key: %w`, ExpirationKey, err) + } + t.expiration = &acceptor + return nil + case IssuedAtKey: + var acceptor types.NumericDate + if err := acceptor.Accept(value); err != nil { + return fmt.Errorf(`invalid value for %s key: %w`, IssuedAtKey, err) + } + t.issuedAt = &acceptor + return nil + case IssuerKey: + if v, ok := value.(string); ok { + t.issuer = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, IssuerKey, value) + case JwtIDKey: + if v, ok := value.(string); ok { + t.jwtID = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, JwtIDKey, value) + case NotBeforeKey: + var acceptor types.NumericDate + if err := acceptor.Accept(value); err != nil { + return fmt.Errorf(`invalid value for %s key: %w`, NotBeforeKey, err) + } + t.notBefore = &acceptor + return nil + case SubjectKey: + if v, ok := value.(string); ok { + t.subject = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, SubjectKey, value) + default: + if t.privateClaims == nil { + t.privateClaims = map[string]any{} + } + t.privateClaims[name] = value + } + return nil +} + +func (t *stdToken) Audience() ([]string, bool) { + t.mu.RLock() + defer t.mu.RUnlock() + if t.audience != nil { + return t.audience.Get(), true + } + return nil, false +} + +func (t *stdToken) Expiration() (time.Time, bool) { + t.mu.RLock() + defer t.mu.RUnlock() + if t.expiration != nil { + return t.expiration.Get(), true + } + return time.Time{}, false +} + +func (t *stdToken) IssuedAt() (time.Time, bool) { + t.mu.RLock() + defer t.mu.RUnlock() + if t.issuedAt != nil { + return t.issuedAt.Get(), true + } + return time.Time{}, false +} + +func (t *stdToken) Issuer() (string, bool) { + t.mu.RLock() + defer t.mu.RUnlock() + if t.issuer != nil { + return *(t.issuer), true + } + return "", false +} + +func (t *stdToken) JwtID() (string, bool) { + t.mu.RLock() + defer t.mu.RUnlock() + if t.jwtID != nil { + return *(t.jwtID), true + } + return "", false +} + +func (t *stdToken) NotBefore() (time.Time, bool) { + t.mu.RLock() + defer t.mu.RUnlock() + if t.notBefore != nil { + return t.notBefore.Get(), true + } + return time.Time{}, false +} + +func (t *stdToken) Subject() (string, bool) { + t.mu.RLock() + defer t.mu.RUnlock() + if t.subject != nil { + return *(t.subject), true + } + return "", false +} + +func (t *stdToken) PrivateClaims() map[string]any { + t.mu.RLock() + defer t.mu.RUnlock() + return t.privateClaims +} + +func (t *stdToken) UnmarshalJSON(buf []byte) error { + t.mu.Lock() + defer t.mu.Unlock() + t.audience = nil + t.expiration = nil + t.issuedAt = nil + t.issuer = nil + t.jwtID = nil + t.notBefore = nil + t.subject = nil + dec := json.NewDecoder(bytes.NewReader(buf)) +LOOP: + for { + tok, err := dec.Token() + if err != nil { + return fmt.Errorf(`error reading token: %w`, err) + } + switch tok := tok.(type) { + case json.Delim: + // Assuming we're doing everything correctly, we should ONLY + // get either tokens.OpenCurlyBracket or tokens.CloseCurlyBracket here. + if tok == tokens.CloseCurlyBracket { // End of object + break LOOP + } else if tok != tokens.OpenCurlyBracket { + return fmt.Errorf(`expected '%c', but got '%c'`, tokens.OpenCurlyBracket, tok) + } + case string: // Objects can only have string keys + switch tok { + case AudienceKey: + var decoded types.StringList + if err := dec.Decode(&decoded); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, AudienceKey, err) + } + t.audience = decoded + case ExpirationKey: + var decoded types.NumericDate + if err := dec.Decode(&decoded); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, ExpirationKey, err) + } + t.expiration = &decoded + case IssuedAtKey: + var decoded types.NumericDate + if err := dec.Decode(&decoded); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, IssuedAtKey, err) + } + t.issuedAt = &decoded + case IssuerKey: + if err := json.AssignNextStringToken(&t.issuer, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, IssuerKey, err) + } + case JwtIDKey: + if err := json.AssignNextStringToken(&t.jwtID, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, JwtIDKey, err) + } + case NotBeforeKey: + var decoded types.NumericDate + if err := dec.Decode(&decoded); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, NotBeforeKey, err) + } + t.notBefore = &decoded + case SubjectKey: + if err := json.AssignNextStringToken(&t.subject, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, SubjectKey, err) + } + default: + if dc := t.dc; dc != nil { + if localReg := dc.Registry(); localReg != nil { + decoded, err := localReg.Decode(dec, tok) + if err == nil { + t.setNoLock(tok, decoded) + continue + } + } + } + decoded, err := registry.Decode(dec, tok) + if err == nil { + t.setNoLock(tok, decoded) + continue + } + return fmt.Errorf(`could not decode field %s: %w`, tok, err) + } + default: + return fmt.Errorf(`invalid token %T`, tok) + } + } + return nil +} + +func (t *stdToken) Keys() []string { + t.mu.RLock() + defer t.mu.RUnlock() + keys := make([]string, 0, 7+len(t.privateClaims)) + if t.audience != nil { + keys = append(keys, AudienceKey) + } + if t.expiration != nil { + keys = append(keys, ExpirationKey) + } + if t.issuedAt != nil { + keys = append(keys, IssuedAtKey) + } + if t.issuer != nil { + keys = append(keys, IssuerKey) + } + if t.jwtID != nil { + keys = append(keys, JwtIDKey) + } + if t.notBefore != nil { + keys = append(keys, NotBeforeKey) + } + if t.subject != nil { + keys = append(keys, SubjectKey) + } + for k := range t.privateClaims { + keys = append(keys, k) + } + return keys +} + +type claimPair struct { + Name string + Value any +} + +var claimPairPool = sync.Pool{ + New: func() any { + return make([]claimPair, 0, 7) + }, +} + +func getClaimPairList() []claimPair { + return claimPairPool.Get().([]claimPair) +} + +func putClaimPairList(list []claimPair) { + list = list[:0] + claimPairPool.Put(list) +} + +// makePairs creates a list of claimPair objects that are sorted by +// their key names. The key names are always their JSON names, and +// the values are already JSON encoded. +// Because makePairs needs to allocate a slice, it _slows_ down +// marshaling of the token to JSON. The upside is that it allows us to +// marshal the token keys in a deterministic order. +// Do we really need it...? Well, technically we don't, but it's so +// much nicer to have this to make the example tests actually work +// deterministically. Also if for whatever reason this becomes a +// performance issue, we can always/ add a flag to use a more _optimized_ code path. +// +// The caller is responsible to call putClaimPairList() to return the +// allocated slice back to the pool. + +func (t *stdToken) makePairs() ([]claimPair, error) { + pairs := getClaimPairList() + if t.audience != nil { + buf, err := json.MarshalAudience(t.audience, t.options.IsEnabled(FlattenAudience)) + if err != nil { + return nil, fmt.Errorf(`failed to encode "aud": %w`, err) + } + pairs = append(pairs, claimPair{Name: AudienceKey, Value: buf}) + } + if t.expiration != nil { + buf, err := json.Marshal(t.expiration.Unix()) + if err != nil { + return nil, fmt.Errorf(`failed to encode "exp": %w`, err) + } + pairs = append(pairs, claimPair{Name: ExpirationKey, Value: buf}) + } + if t.issuedAt != nil { + buf, err := json.Marshal(t.issuedAt.Unix()) + if err != nil { + return nil, fmt.Errorf(`failed to encode "iat": %w`, err) + } + pairs = append(pairs, claimPair{Name: IssuedAtKey, Value: buf}) + } + if t.issuer != nil { + buf, err := json.Marshal(*(t.issuer)) + if err != nil { + return nil, fmt.Errorf(`failed to encode field "iss": %w`, err) + } + pairs = append(pairs, claimPair{Name: IssuerKey, Value: buf}) + } + if t.jwtID != nil { + buf, err := json.Marshal(*(t.jwtID)) + if err != nil { + return nil, fmt.Errorf(`failed to encode field "jti": %w`, err) + } + pairs = append(pairs, claimPair{Name: JwtIDKey, Value: buf}) + } + if t.notBefore != nil { + buf, err := json.Marshal(t.notBefore.Unix()) + if err != nil { + return nil, fmt.Errorf(`failed to encode "nbf": %w`, err) + } + pairs = append(pairs, claimPair{Name: NotBeforeKey, Value: buf}) + } + if t.subject != nil { + buf, err := json.Marshal(*(t.subject)) + if err != nil { + return nil, fmt.Errorf(`failed to encode field "sub": %w`, err) + } + pairs = append(pairs, claimPair{Name: SubjectKey, Value: buf}) + } + for k, v := range t.privateClaims { + buf, err := json.Marshal(v) + if err != nil { + return nil, fmt.Errorf(`failed to encode field %q: %w`, k, err) + } + pairs = append(pairs, claimPair{Name: k, Value: buf}) + } + + sort.Slice(pairs, func(i, j int) bool { + return pairs[i].Name < pairs[j].Name + }) + + return pairs, nil +} + +func (t stdToken) MarshalJSON() ([]byte, error) { + buf := pool.BytesBuffer().Get() + defer pool.BytesBuffer().Put(buf) + pairs, err := t.makePairs() + if err != nil { + return nil, fmt.Errorf(`failed to make pairs: %w`, err) + } + buf.WriteByte(tokens.OpenCurlyBracket) + + for i, pair := range pairs { + if i > 0 { + buf.WriteByte(tokens.Comma) + } + fmt.Fprintf(buf, "%q: %s", pair.Name, pair.Value) + } + buf.WriteByte(tokens.CloseCurlyBracket) + ret := make([]byte, buf.Len()) + copy(ret, buf.Bytes()) + putClaimPairList(pairs) + return ret, nil +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwt/token_options.go b/vendor/github.com/lestrrat-go/jwx/v3/jwt/token_options.go new file mode 100644 index 00000000000..0f54e056118 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwt/token_options.go @@ -0,0 +1,78 @@ +package jwt + +import "sync" + +// TokenOptionSet is a bit flag containing per-token options. +type TokenOptionSet uint64 + +var defaultOptions TokenOptionSet +var defaultOptionsMu sync.RWMutex + +// TokenOption describes a single token option that can be set on +// the per-token option set (TokenOptionSet) +type TokenOption uint64 + +const ( + // FlattenAudience option controls whether the "aud" claim should be flattened + // to a single string upon the token being serialized to JSON. + // + // This is sometimes important when a JWT consumer does not understand that + // the "aud" claim can actually take the form of an array of strings. + // (We have been notified by users that AWS Cognito has manifested this behavior + // at some point) + // + // Unless the global option is set using `jwt.Settings()`, the default value is + // `disabled`, which means that "aud" claims are always rendered as a arrays of + // strings when serialized to JSON. + FlattenAudience TokenOption = 1 << iota + + // MaxPerTokenOption is a marker to denote the last value that an option can take. + // This value has no meaning other than to be used as a marker. + MaxPerTokenOption +) + +// Value returns the uint64 value of a single option +func (o TokenOption) Value() uint64 { + return uint64(o) +} + +// Value returns the uint64 bit flag value of an option set +func (o TokenOptionSet) Value() uint64 { + return uint64(o) +} + +// DefaultOptionSet creates a new TokenOptionSet using the default +// option set. This may differ depending on if/when functions that +// change the global state has been called, such as `jwt.Settings` +func DefaultOptionSet() TokenOptionSet { + return TokenOptionSet(defaultOptions.Value()) +} + +// Clear sets all bits to zero, effectively disabling all options +func (o *TokenOptionSet) Clear() { + *o = TokenOptionSet(uint64(0)) +} + +// Set sets the value of this option set, effectively *replacing* +// the entire option set with the new value. This is NOT the same +// as Enable/Disable. +func (o *TokenOptionSet) Set(s TokenOptionSet) { + *o = s +} + +// Enable sets the appropriate value to enable the option in the +// option set +func (o *TokenOptionSet) Enable(flag TokenOption) { + *o = TokenOptionSet(o.Value() | uint64(flag)) +} + +// Enable sets the appropriate value to disable the option in the +// option set +func (o *TokenOptionSet) Disable(flag TokenOption) { + *o = TokenOptionSet(o.Value() & ^uint64(flag)) +} + +// IsEnabled returns true if the given bit on the option set is enabled. +func (o TokenOptionSet) IsEnabled(flag TokenOption) bool { + return (uint64(o)&uint64(flag) == uint64(flag)) +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwt/token_options_gen.go b/vendor/github.com/lestrrat-go/jwx/v3/jwt/token_options_gen.go new file mode 100644 index 00000000000..7e7cbf14aad --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwt/token_options_gen.go @@ -0,0 +1,25 @@ +// Code generated by "stringer -type=TokenOption -output=token_options_gen.go"; DO NOT EDIT. + +package jwt + +import "strconv" + +func _() { + // An "invalid array index" compiler error signifies that the constant values have changed. + // Re-run the stringer command to generate them again. + var x [1]struct{} + _ = x[FlattenAudience-1] + _ = x[MaxPerTokenOption-2] +} + +const _TokenOption_name = "FlattenAudienceMaxPerTokenOption" + +var _TokenOption_index = [...]uint8{0, 15, 32} + +func (i TokenOption) String() string { + i -= 1 + if i >= TokenOption(len(_TokenOption_index)-1) { + return "TokenOption(" + strconv.FormatInt(int64(i+1), 10) + ")" + } + return _TokenOption_name[_TokenOption_index[i]:_TokenOption_index[i+1]] +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwt/validate.go b/vendor/github.com/lestrrat-go/jwx/v3/jwt/validate.go new file mode 100644 index 00000000000..dbc43edbc26 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwt/validate.go @@ -0,0 +1,418 @@ +package jwt + +import ( + "context" + "fmt" + "strconv" + "time" + + jwterrs "github.com/lestrrat-go/jwx/v3/jwt/internal/errors" +) + +type Clock interface { + Now() time.Time +} +type ClockFunc func() time.Time + +func (f ClockFunc) Now() time.Time { + return f() +} + +func isSupportedTimeClaim(c string) error { + switch c { + case ExpirationKey, IssuedAtKey, NotBeforeKey: + return nil + } + return fmt.Errorf(`unsupported time claim %s`, strconv.Quote(c)) +} + +func timeClaim(t Token, clock Clock, c string) time.Time { + // We don't check if the claims already exist. It should have been done + // by piggybacking on `required` check. + switch c { + case ExpirationKey: + tv, _ := t.Expiration() + return tv + case IssuedAtKey: + tv, _ := t.IssuedAt() + return tv + case NotBeforeKey: + tv, _ := t.NotBefore() + return tv + case "": + return clock.Now() + } + return time.Time{} // should *NEVER* reach here, but... +} + +// Validate makes sure that the essential claims stand. +// +// See the various `WithXXX` functions for optional parameters +// that can control the behavior of this method. +func Validate(t Token, options ...ValidateOption) error { + ctx := context.Background() + trunc := getDefaultTruncation() + + var clock Clock = ClockFunc(time.Now) + var skew time.Duration + var baseValidators = []Validator{ + IsIssuedAtValid(), + IsExpirationValid(), + IsNbfValid(), + } + var extraValidators []Validator + var resetValidators bool + for _, o := range options { + switch o.Ident() { + case identClock{}: + if err := o.Value(&clock); err != nil { + return fmt.Errorf(`jwt.Validate: value for WithClock() option must be jwt.Clock: %w`, err) + } + case identAcceptableSkew{}: + if err := o.Value(&skew); err != nil { + return fmt.Errorf(`jwt.Validate: value for WithAcceptableSkew() option must be time.Duration: %w`, err) + } + case identTruncation{}: + if err := o.Value(&trunc); err != nil { + return fmt.Errorf(`jwt.Validate: value for WithTruncation() option must be time.Duration: %w`, err) + } + case identContext{}: + if err := o.Value(&ctx); err != nil { + return fmt.Errorf(`jwt.Validate: value for WithContext() option must be context.Context: %w`, err) + } + case identResetValidators{}: + if err := o.Value(&resetValidators); err != nil { + return fmt.Errorf(`jwt.Validate: value for WithResetValidators() option must be bool: %w`, err) + } + case identValidator{}: + var v Validator + if err := o.Value(&v); err != nil { + return fmt.Errorf(`jwt.Validate: value for WithValidator() option must be jwt.Validator: %w`, err) + } + switch v := v.(type) { + case *isInTimeRange: + if v.c1 != "" { + if err := isSupportedTimeClaim(v.c1); err != nil { + return err + } + extraValidators = append(extraValidators, IsRequired(v.c1)) + } + if v.c2 != "" { + if err := isSupportedTimeClaim(v.c2); err != nil { + return err + } + extraValidators = append(extraValidators, IsRequired(v.c2)) + } + } + extraValidators = append(extraValidators, v) + } + } + + ctx = SetValidationCtxSkew(ctx, skew) + ctx = SetValidationCtxClock(ctx, clock) + ctx = SetValidationCtxTruncation(ctx, trunc) + + var validators []Validator + if !resetValidators { + validators = append(baseValidators, extraValidators...) + } else { + if len(extraValidators) == 0 { + return jwterrs.ValidateErrorf(`no validators specified: jwt.WithResetValidators(true) and no jwt.WithValidator() specified`) + } + validators = extraValidators + } + + for _, v := range validators { + if err := v.Validate(ctx, t); err != nil { + return jwterrs.ValidateErrorf(`validation failed: %w`, err) + } + } + + return nil +} + +type isInTimeRange struct { + c1 string + c2 string + dur time.Duration + less bool // if true, d =< c1 - c2. otherwise d >= c1 - c2 +} + +// MaxDeltaIs implements the logic behind `WithMaxDelta()` option +func MaxDeltaIs(c1, c2 string, dur time.Duration) Validator { + return &isInTimeRange{ + c1: c1, + c2: c2, + dur: dur, + less: true, + } +} + +// MinDeltaIs implements the logic behind `WithMinDelta()` option +func MinDeltaIs(c1, c2 string, dur time.Duration) Validator { + return &isInTimeRange{ + c1: c1, + c2: c2, + dur: dur, + less: false, + } +} + +func (iitr *isInTimeRange) Validate(ctx context.Context, t Token) error { + clock := ValidationCtxClock(ctx) // MUST be populated + skew := ValidationCtxSkew(ctx) // MUST be populated + // We don't check if the claims already exist, because we already did that + // by piggybacking on `required` check. + t1 := timeClaim(t, clock, iitr.c1) + t2 := timeClaim(t, clock, iitr.c2) + if iitr.less { // t1 - t2 <= iitr.dur + // t1 - t2 < iitr.dur + skew + if t1.Sub(t2) > iitr.dur+skew { + return fmt.Errorf(`iitr between %s and %s exceeds %s (skew %s)`, iitr.c1, iitr.c2, iitr.dur, skew) + } + } else { + if t1.Sub(t2) < iitr.dur-skew { + return fmt.Errorf(`iitr between %s and %s is less than %s (skew %s)`, iitr.c1, iitr.c2, iitr.dur, skew) + } + } + return nil +} + +// Validator describes interface to validate a Token. +type Validator interface { + // Validate should return an error if a required conditions is not met. + Validate(context.Context, Token) error +} + +// ValidatorFunc is a type of Validator that does not have any +// state, that is implemented as a function +type ValidatorFunc func(context.Context, Token) error + +func (vf ValidatorFunc) Validate(ctx context.Context, tok Token) error { + return vf(ctx, tok) +} + +type identValidationCtxClock struct{} +type identValidationCtxSkew struct{} +type identValidationCtxTruncation struct{} + +func SetValidationCtxClock(ctx context.Context, cl Clock) context.Context { + return context.WithValue(ctx, identValidationCtxClock{}, cl) +} + +func SetValidationCtxTruncation(ctx context.Context, dur time.Duration) context.Context { + return context.WithValue(ctx, identValidationCtxTruncation{}, dur) +} + +func SetValidationCtxSkew(ctx context.Context, dur time.Duration) context.Context { + return context.WithValue(ctx, identValidationCtxSkew{}, dur) +} + +// ValidationCtxClock returns the Clock object associated with +// the current validation context. This value will always be available +// during validation of tokens. +func ValidationCtxClock(ctx context.Context) Clock { + //nolint:forcetypeassert + return ctx.Value(identValidationCtxClock{}).(Clock) +} + +func ValidationCtxSkew(ctx context.Context) time.Duration { + //nolint:forcetypeassert + return ctx.Value(identValidationCtxSkew{}).(time.Duration) +} + +func ValidationCtxTruncation(ctx context.Context) time.Duration { + //nolint:forcetypeassert + return ctx.Value(identValidationCtxTruncation{}).(time.Duration) +} + +// IsExpirationValid is one of the default validators that will be executed. +// It does not need to be specified by users, but it exists as an +// exported field so that you can check what it does. +// +// The supplied context.Context object must have the "clock" and "skew" +// populated with appropriate values using SetValidationCtxClock() and +// SetValidationCtxSkew() +func IsExpirationValid() Validator { + return ValidatorFunc(isExpirationValid) +} + +func isExpirationValid(ctx context.Context, t Token) error { + tv, ok := t.Expiration() + if !ok { + return nil + } + + clock := ValidationCtxClock(ctx) // MUST be populated + skew := ValidationCtxSkew(ctx) // MUST be populated + trunc := ValidationCtxTruncation(ctx) // MUST be populated + + now := clock.Now().Truncate(trunc) + ttv := tv.Truncate(trunc) + + // expiration date must be after NOW + if !now.Before(ttv.Add(skew)) { + return TokenExpiredError() + } + return nil +} + +// IsIssuedAtValid is one of the default validators that will be executed. +// It does not need to be specified by users, but it exists as an +// exported field so that you can check what it does. +// +// The supplied context.Context object must have the "clock" and "skew" +// populated with appropriate values using SetValidationCtxClock() and +// SetValidationCtxSkew() +func IsIssuedAtValid() Validator { + return ValidatorFunc(isIssuedAtValid) +} + +func isIssuedAtValid(ctx context.Context, t Token) error { + tv, ok := t.IssuedAt() + if !ok { + return nil + } + + clock := ValidationCtxClock(ctx) // MUST be populated + skew := ValidationCtxSkew(ctx) // MUST be populated + trunc := ValidationCtxTruncation(ctx) // MUST be populated + + now := clock.Now().Truncate(trunc) + ttv := tv.Truncate(trunc) + + if now.Before(ttv.Add(-1 * skew)) { + return InvalidIssuedAtError() + } + return nil +} + +// IsNbfValid is one of the default validators that will be executed. +// It does not need to be specified by users, but it exists as an +// exported field so that you can check what it does. +// +// The supplied context.Context object must have the "clock" and "skew" +// populated with appropriate values using SetValidationCtxClock() and +// SetValidationCtxSkew() +func IsNbfValid() Validator { + return ValidatorFunc(isNbfValid) +} + +func isNbfValid(ctx context.Context, t Token) error { + tv, ok := t.NotBefore() + if !ok { + return nil + } + + clock := ValidationCtxClock(ctx) // MUST be populated + skew := ValidationCtxSkew(ctx) // MUST be populated + trunc := ValidationCtxTruncation(ctx) // MUST be populated + + // Truncation always happens even for trunc = 0 because + // we also use this to strip monotonic clocks + now := clock.Now().Truncate(trunc) + ttv := tv.Truncate(trunc) + + // "now" cannot be before t - skew, so we check for now > t - skew + ttv = ttv.Add(-1 * skew) + if now.Before(ttv) { + return TokenNotYetValidError() + } + return nil +} + +type claimContainsString struct { + name string + value string + makeErr func(string, ...any) error +} + +// ClaimContainsString can be used to check if the claim called `name`, which is +// expected to be a list of strings, contains `value`. Currently, because of the +// implementation, this will probably only work for `aud` fields. +func ClaimContainsString(name, value string) Validator { + return claimContainsString{ + name: name, + value: value, + makeErr: fmt.Errorf, + } +} + +func (ccs claimContainsString) Validate(_ context.Context, t Token) error { + var list []string + if err := t.Get(ccs.name, &list); err != nil { + return ccs.makeErr(`claim %q does not exist or is not a []string: %w`, ccs.name, err) + } + + for _, v := range list { + if v == ccs.value { + return nil + } + } + return ccs.makeErr(`%q not satisfied`, ccs.name) +} + +// audienceClaimContainsString can be used to check if the audience claim, which is +// expected to be a list of strings, contains `value`. +func audienceClaimContainsString(value string) Validator { + return claimContainsString{ + name: AudienceKey, + value: value, + makeErr: jwterrs.AudienceErrorf, + } +} + +type claimValueIs struct { + name string + value any + makeErr func(string, ...any) error +} + +// ClaimValueIs creates a Validator that checks if the value of claim `name` +// matches `value`. The comparison is done using a simple `==` comparison, +// and therefore complex comparisons may fail using this code. If you +// need to do more, use a custom Validator. +func ClaimValueIs(name string, value any) Validator { + return &claimValueIs{ + name: name, + value: value, + makeErr: fmt.Errorf, + } +} + +func (cv *claimValueIs) Validate(_ context.Context, t Token) error { + var v any + if err := t.Get(cv.name, &v); err != nil { + return cv.makeErr(`claim %[1]q does not exist or is not a []string: %[2]w`, cv.name, err) + } + if v != cv.value { + return cv.makeErr(`claim %[1]q does not have the expected value`, cv.name) + } + return nil +} + +// issuerClaimValueIs creates a Validator that checks if the issuer claim +// matches `value`. +func issuerClaimValueIs(value string) Validator { + return &claimValueIs{ + name: IssuerKey, + value: value, + makeErr: jwterrs.IssuerErrorf, + } +} + +// IsRequired creates a Validator that checks if the required claim `name` +// exists in the token +func IsRequired(name string) Validator { + return isRequired(name) +} + +type isRequired string + +func (ir isRequired) Validate(_ context.Context, t Token) error { + name := string(ir) + if !t.Has(name) { + return jwterrs.MissingRequiredClaimErrorf(name) + } + return nil +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwx.go b/vendor/github.com/lestrrat-go/jwx/v3/jwx.go new file mode 100644 index 00000000000..fc394e51373 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwx.go @@ -0,0 +1,45 @@ +//go:generate ./tools/cmd/genreadfile.sh +//go:generate ./tools/cmd/genoptions.sh +//go:generate stringer -type=FormatKind +//go:generate mv formatkind_string.go formatkind_string_gen.go + +// Package jwx contains tools that deal with the various JWx (JOSE) +// technologies such as JWT, JWS, JWE, etc in Go. +// +// JWS (https://tools.ietf.org/html/rfc7515) +// JWE (https://tools.ietf.org/html/rfc7516) +// JWK (https://tools.ietf.org/html/rfc7517) +// JWA (https://tools.ietf.org/html/rfc7518) +// JWT (https://tools.ietf.org/html/rfc7519) +// +// Examples are stored in a separate Go module (to avoid adding +// dependencies to this module), and thus does not appear in the +// online documentation for this module. +// You can find the examples in Github at https://github.com/lestrrat-go/jwx/tree/v3/examples +// +// You can find more high level documentation at Github (https://github.com/lestrrat-go/jwx/tree/v2) +// +// FAQ style documentation can be found in the repository (https://github.com/lestrrat-go/jwx/tree/develop/v3/docs) +package jwx + +import ( + "github.com/lestrrat-go/jwx/v3/internal/json" +) + +// DecoderSettings gives you a access to configure the "encoding/json".Decoder +// used to decode JSON objects within the jwx framework. +func DecoderSettings(options ...JSONOption) { + // XXX We're using this format instead of just passing a single boolean + // in case a new option is to be added some time later + var useNumber bool + for _, option := range options { + switch option.Ident() { + case identUseNumber{}: + if err := option.Value(&useNumber); err != nil { + panic("jwx.DecoderSettings: useNumber option must be a boolean") + } + } + } + + json.DecoderSettings(useNumber) +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/options.go b/vendor/github.com/lestrrat-go/jwx/v3/options.go new file mode 100644 index 00000000000..b642a199d8f --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/options.go @@ -0,0 +1,30 @@ +package jwx + +import "github.com/lestrrat-go/option/v2" + +type identUseNumber struct{} + +type Option = option.Interface + +type JSONOption interface { + Option + isJSONOption() +} + +type jsonOption struct { + Option +} + +func (o *jsonOption) isJSONOption() {} + +func newJSONOption(n any, v any) JSONOption { + return &jsonOption{option.New(n, v)} +} + +// WithUseNumber controls whether the jwx package should unmarshal +// JSON objects with the "encoding/json".Decoder.UseNumber feature on. +// +// Default is false. +func WithUseNumber(b bool) JSONOption { + return newJSONOption(identUseNumber{}, b) +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/transform/BUILD.bazel b/vendor/github.com/lestrrat-go/jwx/v3/transform/BUILD.bazel new file mode 100644 index 00000000000..3333c6607c8 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/transform/BUILD.bazel @@ -0,0 +1,32 @@ +load("@rules_go//go:def.bzl", "go_library", "go_test") + +go_library( + name = "transform", + srcs = [ + "filter.go", + "map.go", + ], + importpath = "github.com/lestrrat-go/jwx/v3/transform", + visibility = ["//visibility:public"], + deps = [ + "@com_github_lestrrat_go_blackmagic//:blackmagic", + ], +) + +go_test( + name = "transform_test", + srcs = [ + "map_test.go", + ], + deps = [ + ":transform", + "//jwt", + "@com_github_stretchr_testify//require", + ], +) + +alias( + name = "go_default_library", + actual = ":transform", + visibility = ["//visibility:public"], +) \ No newline at end of file diff --git a/vendor/github.com/lestrrat-go/jwx/v3/transform/filter.go b/vendor/github.com/lestrrat-go/jwx/v3/transform/filter.go new file mode 100644 index 00000000000..da2972db6a4 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/transform/filter.go @@ -0,0 +1,115 @@ +package transform + +import "sync" + +// FilterLogic is an interface that defines the logic for filtering objects. +type FilterLogic interface { + Apply(key string, object any) bool +} + +// FilterLogicFunc is a function type that implements the FilterLogic interface. +type FilterLogicFunc func(key string, object any) bool + +func (f FilterLogicFunc) Apply(key string, object any) bool { + return f(key, object) +} + +// Filterable is an interface that must be implemented by objects that can be filtered. +type Filterable[T any] interface { + // Keys returns the names of all fields in the object. + Keys() []string + + // Clone returns a deep copy of the object. + Clone() (T, error) + + // Remove removes a field from the object. + Remove(string) error +} + +// Apply is a standalone function that provides type-safe filtering based on +// specified filter logic. +// +// It returns a new object with only the fields that match the result of `logic.Apply`. +func Apply[T Filterable[T]](object T, logic FilterLogic) (T, error) { + return filterWith(object, logic, true) +} + +// Reject is a standalone function that provides type-safe filtering based on +// specified filter logic. +// +// It returns a new object with only the fields that DO NOT match the result +// of `logic.Apply`. +func Reject[T Filterable[T]](object T, logic FilterLogic) (T, error) { + return filterWith(object, logic, false) +} + +// filterWith is an internal function used by both Apply and Reject functions +// to apply the filtering logic to an object. If include is true, only fields +// matching the logic are included. If include is false, fields matching +// the logic are excluded. +func filterWith[T Filterable[T]](object T, logic FilterLogic, include bool) (T, error) { + var zero T + + result, err := object.Clone() + if err != nil { + return zero, err + } + + for _, k := range result.Keys() { + if ok := logic.Apply(k, object); (include && ok) || (!include && !ok) { + continue + } + + if err := result.Remove(k); err != nil { + return zero, err + } + } + + return result, nil +} + +// NameBasedFilter is a filter that filters fields based on their field names. +type NameBasedFilter[T Filterable[T]] struct { + names map[string]struct{} + mu sync.RWMutex + logic FilterLogic +} + +// NewNameBasedFilter creates a new NameBasedFilter with the specified field names. +// +// NameBasedFilter is the underlying implementation of the +// various filters in jwe, jwk, jws, and jwt packages. You normally do not +// need to use this directly. +func NewNameBasedFilter[T Filterable[T]](names ...string) *NameBasedFilter[T] { + nameMap := make(map[string]struct{}, len(names)) + for _, name := range names { + nameMap[name] = struct{}{} + } + + nf := &NameBasedFilter[T]{ + names: nameMap, + } + + nf.logic = FilterLogicFunc(nf.filter) + return nf +} + +func (nf *NameBasedFilter[T]) filter(k string, _ any) bool { + _, ok := nf.names[k] + return ok +} + +// Filter returns a new object with only the fields that match the specified names. +func (nf *NameBasedFilter[T]) Filter(object T) (T, error) { + nf.mu.RLock() + defer nf.mu.RUnlock() + + return Apply(object, nf.logic) +} + +// Reject returns a new object with only the fields that DO NOT match the specified names. +func (nf *NameBasedFilter[T]) Reject(object T) (T, error) { + nf.mu.RLock() + defer nf.mu.RUnlock() + return Reject(object, nf.logic) +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/transform/map.go b/vendor/github.com/lestrrat-go/jwx/v3/transform/map.go new file mode 100644 index 00000000000..4eb80cb99fb --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/transform/map.go @@ -0,0 +1,46 @@ +package transform + +import ( + "errors" + "fmt" + + "github.com/lestrrat-go/blackmagic" +) + +// Mappable is an interface that defines methods required when converting +// a jwx structure into a map[string]any. +// +// EXPERIMENTAL: This API is experimental and its interface and behavior is +// subject to change in future releases. This API is not subject to semver +// compatibility guarantees. +type Mappable interface { + Get(key string, dst any) error + Keys() []string +} + +// AsMap takes the specified Mappable object and populates the map +// `dst` with the key-value pairs from the Mappable object. +// Many objects in jwe, jwk, jws, and jwt packages including +// `jwt.Token`, `jwk.Key`, `jws.Header`, etc. +// +// EXPERIMENTAL: This API is experimental and its interface and behavior is +// subject to change in future releases. This API is not subject to semver +// compatibility guarantees. +func AsMap(m Mappable, dst map[string]any) error { + if dst == nil { + return fmt.Errorf("transform.AsMap: destination map cannot be nil") + } + + for _, k := range m.Keys() { + var val any + if err := m.Get(k, &val); err != nil { + // Allow invalid value errors. Assume they are just nil values. + if !errors.Is(err, blackmagic.InvalidValueError()) { + return fmt.Errorf(`transform.AsMap: failed to get key %q: %w`, k, err) + } + } + dst[k] = val + } + + return nil +} diff --git a/vendor/github.com/lestrrat-go/option/.gitignore b/vendor/github.com/lestrrat-go/option/.gitignore new file mode 100644 index 00000000000..66fd13c903c --- /dev/null +++ b/vendor/github.com/lestrrat-go/option/.gitignore @@ -0,0 +1,15 @@ +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, built with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Dependency directories (remove the comment below to include it) +# vendor/ diff --git a/vendor/github.com/lestrrat-go/option/LICENSE b/vendor/github.com/lestrrat-go/option/LICENSE new file mode 100644 index 00000000000..188ea7685c6 --- /dev/null +++ b/vendor/github.com/lestrrat-go/option/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 lestrrat-go + +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/lestrrat-go/option/README.md b/vendor/github.com/lestrrat-go/option/README.md new file mode 100644 index 00000000000..cab0044ed3f --- /dev/null +++ b/vendor/github.com/lestrrat-go/option/README.md @@ -0,0 +1,245 @@ +# option + +Base object for the "Optional Parameters Pattern". + +# DESCRIPTION + +The beauty of this pattern is that you can achieve a method that can +take the following simple calling style + +```go +obj.Method(mandatory1, mandatory2) +``` + +or the following, if you want to modify its behavior with optional parameters + +```go +obj.Method(mandatory1, mandatory2, optional1, optional2, optional3) +``` + +Instead of the more clunky zero value for optionals style + +```go +obj.Method(mandatory1, mandatory2, nil, "", 0) +``` + +or the equally clunky config object style, which requires you to create a +struct with `NamesThatLookReallyLongBecauseItNeedsToIncludeMethodNamesConfig + +```go +cfg := &ConfigForMethod{ + Optional1: ..., + Optional2: ..., + Optional3: ..., +} +obj.Method(mandatory1, mandatory2, &cfg) +``` + +# SYNOPSIS + +Create an "identifier" for the option. We recommend using an unexported empty struct, +because + +1. It is uniquely identifiable globally +1. Takes minimal space +1. Since it's unexported, you do not have to worry about it leaking elsewhere or having it changed by consumers + +```go +// an unexported empty struct +type identFeatureX struct{} +``` + +Then define a method to create an option using this identifier. Here we assume +that the option will be a boolean option. + +```go +// this is optional, but for readability we usually use a wrapper +// around option.Interface, or a type alias. +type Option +func WithFeatureX(v bool) Option { + // use the constructor to create a new option + return option.New(identFeatureX{}, v) +} +``` + +Now you can create an option, which essentially a two element tuple consisting +of an identifier and its associated value. + +To consume this, you will need to create a function with variadic parameters, +and iterate over the list looking for a particular identifier: + +```go +func MyAwesomeFunc( /* mandatory parameters omitted */, options ...[]Option) { + var enableFeatureX bool + // The nolint directive is recommended if you are using linters such + // as golangci-lint + //nolint:forcetypeassert + for _, option := range options { + switch option.Ident() { + case identFeatureX{}: + enableFeatureX = option.Value().(bool) + // other cases omitted + } + } + if enableFeatureX { + .... + } +} +``` + +# Option objects + +Option objects take two arguments, its identifier and the value it contains. + +The identifier can be anything, but it's usually better to use a an unexported +empty struct so that only you have the ability to generate said option: + +```go +type identOptionalParamOne struct{} +type identOptionalParamTwo struct{} +type identOptionalParamThree struct{} + +func WithOptionOne(v ...) Option { + return option.New(identOptionalParamOne{}, v) +} +``` + +Then you can call the method we described above as + +```go +obj.Method(m1, m2, WithOptionOne(...), WithOptionTwo(...), WithOptionThree(...)) +``` + +Options should be parsed in a code that looks somewhat like this + +```go +func (obj *Object) Method(m1 Type1, m2 Type2, options ...Option) { + paramOne := defaultValueParamOne + for _, option := range options { + switch option.Ident() { + case identOptionalParamOne{}: + paramOne = option.Value().(...) + } + } + ... +} +``` + +The loop requires a bit of boilerplate, and admittedly, this is the main downside +of this module. However, if you think you want use the Option as a Function pattern, +please check the FAQ below for rationale. + +# Simple usage + +Most of the times all you need to do is to declare the Option type as an alias +in your code: + +```go +package myawesomepkg + +import "github.com/lestrrat-go/option" + +type Option = option.Interface +``` + +Then you can start defining options like they are described in the SYNOPSIS section. + +# Differentiating Options + +When you have multiple methods and options, and those options can only be passed to +each one the methods, it's hard to see which options should be passed to which method. + +```go +func WithX() Option { ... } +func WithY() Option { ... } + +// Now, which of WithX/WithY go to which method? +func (*Obj) Method1(options ...Option) {} +func (*Obj) Method2(options ...Option) {} +``` + +In this case the easiest way to make it obvious is to put an extra layer around +the options so that they have different types + +```go +type Method1Option interface { + Option + method1Option() +} + +type method1Option struct { Option } +func (*method1Option) method1Option() {} + +func WithX() Method1Option { + return &methodOption{option.New(...)} +} + +func (*Obj) Method1(options ...Method1Option) {} +``` + +This way the compiler knows if an option can be passed to a given method. + +# FAQ + +## Why aren't these function-based? + +Using a base option type like `type Option func(ctx interface{})` is certainly one way to achieve the same goal. In this case, you are giving the option itself the ability to "configure" the main object. For example: + +```go +type Foo struct { + optionaValue bool +} + +type Option func(*Foo) error + +func WithOptionalValue(v bool) Option { + return Option(func(f *Foo) error { + f.optionalValue = v + return nil + }) +} + +func NewFoo(options ...Option) (*Foo, error) { + var f Foo + for _, o := range options { + if err := o(&f); err != nil { + return nil, err + } + } + return &f +} +``` + +This in itself is fine, but we think there are a few problems: + +### 1. It's hard to create a reusable "Option" type + +We create many libraries using this optional pattern. We would like to provide a default base object. However, this function based approach is not reusuable because each "Option" type requires that it has a context-specific input type. For example, if the "Option" type in the previous example was `func(interface{}) error`, then its usability will significantly decrease because of the type conversion. + +This is not to say that this library's approach is better as it also requires type conversion to convert the _value_ of the option. However, part of the beauty of the original function based approach was the ease of its use, and we claim that this significantly decreases the merits of the function based approach. + +### 2. The receiver requires exported fields + +Part of the appeal for a function-based option pattern is by giving the option itself the ability to do what it wants, you open up the possibility of allowing third-parties to create options that do things that the library authors did not think about. + +```go +package thirdparty +, but when I read drum sheet music, I kind of get thrown off b/c many times it says to hit the bass drum where I feel like it's a snare hit. +func WithMyAwesomeOption( ... ) mypkg.Option { + return mypkg.Option(func(f *mypkg) error { + f.X = ... + f.Y = ... + f.Z = ... + return nil + }) +} +``` + +However, for any third party code to access and set field values, these fields (`X`, `Y`, `Z`) must be exported. Basically you will need an "open" struct. + +Exported fields are absolutely no problem when you have a struct that represents data alone (i.e., API calls that refer or change state information) happen, but we think that casually expose fields for a library struct is a sure way to maintenance hell in the future. What happens when you want to change the API? What happens when you realize that you want to use the field as state (i.e. use it for more than configuration)? What if they kept referring to that field, and then you have concurrent code accessing it? + +Giving third parties complete access to exported fields is like handing out a loaded weapon to the users, and you are at their mercy. + +Of course, providing public APIs for everything so you can validate and control concurrency is an option, but then ... it's a lot of work, and you may have to provide APIs _only_ so that users can refer it in the option-configuration phase. That sounds like a lot of extra work. + diff --git a/vendor/github.com/lestrrat-go/option/option.go b/vendor/github.com/lestrrat-go/option/option.go new file mode 100644 index 00000000000..bfdbb118c0d --- /dev/null +++ b/vendor/github.com/lestrrat-go/option/option.go @@ -0,0 +1,38 @@ +package option + +import "fmt" + +// Interface defines the minimum interface that an option must fulfill +type Interface interface { + // Ident returns the "identity" of this option, a unique identifier that + // can be used to differentiate between options + Ident() interface{} + + // Value returns the corresponding value. + Value() interface{} +} + +type pair struct { + ident interface{} + value interface{} +} + +// New creates a new Option +func New(ident, value interface{}) Interface { + return &pair{ + ident: ident, + value: value, + } +} + +func (p *pair) Ident() interface{} { + return p.ident +} + +func (p *pair) Value() interface{} { + return p.value +} + +func (p *pair) String() string { + return fmt.Sprintf(`%v(%v)`, p.ident, p.value) +} diff --git a/vendor/github.com/lestrrat-go/option/v2/.gitignore b/vendor/github.com/lestrrat-go/option/v2/.gitignore new file mode 100644 index 00000000000..66fd13c903c --- /dev/null +++ b/vendor/github.com/lestrrat-go/option/v2/.gitignore @@ -0,0 +1,15 @@ +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, built with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Dependency directories (remove the comment below to include it) +# vendor/ diff --git a/vendor/github.com/lestrrat-go/option/v2/LICENSE b/vendor/github.com/lestrrat-go/option/v2/LICENSE new file mode 100644 index 00000000000..188ea7685c6 --- /dev/null +++ b/vendor/github.com/lestrrat-go/option/v2/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 lestrrat-go + +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/lestrrat-go/option/v2/README.md b/vendor/github.com/lestrrat-go/option/v2/README.md new file mode 100644 index 00000000000..cab0044ed3f --- /dev/null +++ b/vendor/github.com/lestrrat-go/option/v2/README.md @@ -0,0 +1,245 @@ +# option + +Base object for the "Optional Parameters Pattern". + +# DESCRIPTION + +The beauty of this pattern is that you can achieve a method that can +take the following simple calling style + +```go +obj.Method(mandatory1, mandatory2) +``` + +or the following, if you want to modify its behavior with optional parameters + +```go +obj.Method(mandatory1, mandatory2, optional1, optional2, optional3) +``` + +Instead of the more clunky zero value for optionals style + +```go +obj.Method(mandatory1, mandatory2, nil, "", 0) +``` + +or the equally clunky config object style, which requires you to create a +struct with `NamesThatLookReallyLongBecauseItNeedsToIncludeMethodNamesConfig + +```go +cfg := &ConfigForMethod{ + Optional1: ..., + Optional2: ..., + Optional3: ..., +} +obj.Method(mandatory1, mandatory2, &cfg) +``` + +# SYNOPSIS + +Create an "identifier" for the option. We recommend using an unexported empty struct, +because + +1. It is uniquely identifiable globally +1. Takes minimal space +1. Since it's unexported, you do not have to worry about it leaking elsewhere or having it changed by consumers + +```go +// an unexported empty struct +type identFeatureX struct{} +``` + +Then define a method to create an option using this identifier. Here we assume +that the option will be a boolean option. + +```go +// this is optional, but for readability we usually use a wrapper +// around option.Interface, or a type alias. +type Option +func WithFeatureX(v bool) Option { + // use the constructor to create a new option + return option.New(identFeatureX{}, v) +} +``` + +Now you can create an option, which essentially a two element tuple consisting +of an identifier and its associated value. + +To consume this, you will need to create a function with variadic parameters, +and iterate over the list looking for a particular identifier: + +```go +func MyAwesomeFunc( /* mandatory parameters omitted */, options ...[]Option) { + var enableFeatureX bool + // The nolint directive is recommended if you are using linters such + // as golangci-lint + //nolint:forcetypeassert + for _, option := range options { + switch option.Ident() { + case identFeatureX{}: + enableFeatureX = option.Value().(bool) + // other cases omitted + } + } + if enableFeatureX { + .... + } +} +``` + +# Option objects + +Option objects take two arguments, its identifier and the value it contains. + +The identifier can be anything, but it's usually better to use a an unexported +empty struct so that only you have the ability to generate said option: + +```go +type identOptionalParamOne struct{} +type identOptionalParamTwo struct{} +type identOptionalParamThree struct{} + +func WithOptionOne(v ...) Option { + return option.New(identOptionalParamOne{}, v) +} +``` + +Then you can call the method we described above as + +```go +obj.Method(m1, m2, WithOptionOne(...), WithOptionTwo(...), WithOptionThree(...)) +``` + +Options should be parsed in a code that looks somewhat like this + +```go +func (obj *Object) Method(m1 Type1, m2 Type2, options ...Option) { + paramOne := defaultValueParamOne + for _, option := range options { + switch option.Ident() { + case identOptionalParamOne{}: + paramOne = option.Value().(...) + } + } + ... +} +``` + +The loop requires a bit of boilerplate, and admittedly, this is the main downside +of this module. However, if you think you want use the Option as a Function pattern, +please check the FAQ below for rationale. + +# Simple usage + +Most of the times all you need to do is to declare the Option type as an alias +in your code: + +```go +package myawesomepkg + +import "github.com/lestrrat-go/option" + +type Option = option.Interface +``` + +Then you can start defining options like they are described in the SYNOPSIS section. + +# Differentiating Options + +When you have multiple methods and options, and those options can only be passed to +each one the methods, it's hard to see which options should be passed to which method. + +```go +func WithX() Option { ... } +func WithY() Option { ... } + +// Now, which of WithX/WithY go to which method? +func (*Obj) Method1(options ...Option) {} +func (*Obj) Method2(options ...Option) {} +``` + +In this case the easiest way to make it obvious is to put an extra layer around +the options so that they have different types + +```go +type Method1Option interface { + Option + method1Option() +} + +type method1Option struct { Option } +func (*method1Option) method1Option() {} + +func WithX() Method1Option { + return &methodOption{option.New(...)} +} + +func (*Obj) Method1(options ...Method1Option) {} +``` + +This way the compiler knows if an option can be passed to a given method. + +# FAQ + +## Why aren't these function-based? + +Using a base option type like `type Option func(ctx interface{})` is certainly one way to achieve the same goal. In this case, you are giving the option itself the ability to "configure" the main object. For example: + +```go +type Foo struct { + optionaValue bool +} + +type Option func(*Foo) error + +func WithOptionalValue(v bool) Option { + return Option(func(f *Foo) error { + f.optionalValue = v + return nil + }) +} + +func NewFoo(options ...Option) (*Foo, error) { + var f Foo + for _, o := range options { + if err := o(&f); err != nil { + return nil, err + } + } + return &f +} +``` + +This in itself is fine, but we think there are a few problems: + +### 1. It's hard to create a reusable "Option" type + +We create many libraries using this optional pattern. We would like to provide a default base object. However, this function based approach is not reusuable because each "Option" type requires that it has a context-specific input type. For example, if the "Option" type in the previous example was `func(interface{}) error`, then its usability will significantly decrease because of the type conversion. + +This is not to say that this library's approach is better as it also requires type conversion to convert the _value_ of the option. However, part of the beauty of the original function based approach was the ease of its use, and we claim that this significantly decreases the merits of the function based approach. + +### 2. The receiver requires exported fields + +Part of the appeal for a function-based option pattern is by giving the option itself the ability to do what it wants, you open up the possibility of allowing third-parties to create options that do things that the library authors did not think about. + +```go +package thirdparty +, but when I read drum sheet music, I kind of get thrown off b/c many times it says to hit the bass drum where I feel like it's a snare hit. +func WithMyAwesomeOption( ... ) mypkg.Option { + return mypkg.Option(func(f *mypkg) error { + f.X = ... + f.Y = ... + f.Z = ... + return nil + }) +} +``` + +However, for any third party code to access and set field values, these fields (`X`, `Y`, `Z`) must be exported. Basically you will need an "open" struct. + +Exported fields are absolutely no problem when you have a struct that represents data alone (i.e., API calls that refer or change state information) happen, but we think that casually expose fields for a library struct is a sure way to maintenance hell in the future. What happens when you want to change the API? What happens when you realize that you want to use the field as state (i.e. use it for more than configuration)? What if they kept referring to that field, and then you have concurrent code accessing it? + +Giving third parties complete access to exported fields is like handing out a loaded weapon to the users, and you are at their mercy. + +Of course, providing public APIs for everything so you can validate and control concurrency is an option, but then ... it's a lot of work, and you may have to provide APIs _only_ so that users can refer it in the option-configuration phase. That sounds like a lot of extra work. + diff --git a/vendor/github.com/lestrrat-go/option/v2/option.go b/vendor/github.com/lestrrat-go/option/v2/option.go new file mode 100644 index 00000000000..f4fcca3b58a --- /dev/null +++ b/vendor/github.com/lestrrat-go/option/v2/option.go @@ -0,0 +1,47 @@ +package option + +import ( + "fmt" + + "github.com/lestrrat-go/blackmagic" +) + +// Interface defines the minimum interface that an option must fulfill +type Interface interface { + // Ident returns the "identity" of this option, a unique identifier that + // can be used to differentiate between options + Ident() any + + // Value assigns the stored value into the dst argument, which must be + // a pointer to a variable that can store the value. If the assignment + // is successful, it return nil, otherwise it returns an error. + Value(dst any) error +} + +type pair[T any] struct { + ident any + value T +} + +// New creates a new Option +func New[T any](ident any, value T) Interface { + return &pair[T]{ + ident: ident, + value: value, + } +} + +func (p *pair[T]) Ident() any { + return p.ident +} + +func (p *pair[T]) Value(dst any) error { + if err := blackmagic.AssignIfCompatible(dst, p.value); err != nil { + return fmt.Errorf("failed to assign value %T to %T: %s", p.value, dst, err) + } + return nil +} + +func (p *pair[T]) String() string { + return fmt.Sprintf(`%v(%v)`, p.ident, p.value) +} diff --git a/vendor/github.com/lestrrat-go/option/v2/set.go b/vendor/github.com/lestrrat-go/option/v2/set.go new file mode 100644 index 00000000000..def943407a9 --- /dev/null +++ b/vendor/github.com/lestrrat-go/option/v2/set.go @@ -0,0 +1,92 @@ +package option + +import ( + "sync" +) + +// Set is a container to store multiple options. Because options are +// usually used all over the place to configure various aspects of +// a system, it is often useful to be able to collect multiple options +// together and pass them around as a single entity. +// +// Note that Set is meant to be add-only; You usually do not remove +// options from a Set. +// +// The intention is to create a set using a sync.Pool; we would like +// to provide a centralized pool of Sets so that you don't need to +// instantiate a new pool for every type of option you want to +// store, but that is not quite possible because of the limitations +// of parameterized types in Go. Instead create a `*option.SetPool` +// with an appropriate type parameter and allocator. +type Set[T Interface] struct { + mu sync.RWMutex + options []T +} + +func NewSet[T Interface]() *Set[T] { + return &Set[T]{ + options: make([]T, 0, 1), + } +} + +func (s *Set[T]) Add(opt T) { + s.mu.Lock() + defer s.mu.Unlock() + s.options = append(s.options, opt) +} + +func (s *Set[T]) Reset() { + s.mu.Lock() + defer s.mu.Unlock() + s.options = s.options[:0] // Reset the options slice to avoid memory leaks +} + +func (s *Set[T]) Len() int { + s.mu.RLock() + defer s.mu.RUnlock() + return len(s.options) +} + +func (s *Set[T]) Option(i int) T { + var zero T + s.mu.RLock() + defer s.mu.RUnlock() + if i < 0 || i >= len(s.options) { + return zero + } + return s.options[i] +} + +// List returns a slice of all options stored in the Set. +// Note that the slice is the same slice that is used internally, so +// you should not modify the contents of the slice directly. +// This to avoid unnecessary allocations and copying of the slice for +// performance reasons. +func (s *Set[T]) List() []T { + s.mu.RLock() + defer s.mu.RUnlock() + return s.options +} + +// SetPool is a pool of Sets that can be used to efficiently manage +// the lifecycle of Sets. It uses a sync.Pool to store and retrieve +// Sets, allowing for efficient reuse of memory and reducing the +// number of allocations required when creating new Sets. +type SetPool[T Interface] struct { + pool *sync.Pool // sync.Pool that contains *Set[T] +} + +func NewSetPool[T Interface](pool *sync.Pool) *SetPool[T] { + return &SetPool[T]{ + pool: pool, + } +} + +func (p *SetPool[T]) Get() *Set[T] { + return p.pool.Get().(*Set[T]) +} + +func (p *SetPool[T]) Put(s *Set[T]) { + s.Reset() + p.pool.Put(s) +} diff --git a/vendor/github.com/open-policy-agent/opa/capabilities/v1.10.0.json b/vendor/github.com/open-policy-agent/opa/capabilities/v1.10.0.json new file mode 100644 index 00000000000..0a37621d0c5 --- /dev/null +++ b/vendor/github.com/open-policy-agent/opa/capabilities/v1.10.0.json @@ -0,0 +1,4867 @@ +{ + "builtins": [ + { + "name": "abs", + "decl": { + "args": [ + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "all", + "decl": { + "args": [ + { + "of": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "and", + "decl": { + "args": [ + { + "of": { + "type": "any" + }, + "type": "set" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "result": { + "of": { + "type": "any" + }, + "type": "set" + }, + "type": "function" + }, + "infix": "\u0026" + }, + { + "name": "any", + "decl": { + "args": [ + { + "of": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "array.concat", + "decl": { + "args": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "result": { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "array.reverse", + "decl": { + "args": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "result": { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "array.slice", + "decl": { + "args": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "assign", + "decl": { + "args": [ + { + "type": "any" + }, + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + }, + "infix": ":=" + }, + { + "name": "base64.decode", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "base64.encode", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "base64.is_valid", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "base64url.decode", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "base64url.encode", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "base64url.encode_no_pad", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "bits.and", + "decl": { + "args": [ + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "bits.lsh", + "decl": { + "args": [ + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "bits.negate", + "decl": { + "args": [ + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "bits.or", + "decl": { + "args": [ + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "bits.rsh", + "decl": { + "args": [ + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "bits.xor", + "decl": { + "args": [ + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "cast_array", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "cast_boolean", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "cast_null", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "null" + }, + "type": "function" + } + }, + { + "name": "cast_object", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "function" + } + }, + { + "name": "cast_set", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "of": { + "type": "any" + }, + "type": "set" + }, + "type": "function" + } + }, + { + "name": "cast_string", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "ceil", + "decl": { + "args": [ + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "concat", + "decl": { + "args": [ + { + "type": "string" + }, + { + "of": [ + { + "dynamic": { + "type": "string" + }, + "type": "array" + }, + { + "of": { + "type": "string" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "contains", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "count", + "decl": { + "args": [ + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "crypto.hmac.equal", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "crypto.hmac.md5", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "crypto.hmac.sha1", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "crypto.hmac.sha256", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "crypto.hmac.sha512", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "crypto.md5", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "crypto.parse_private_keys", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "dynamic": { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "crypto.sha1", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "crypto.sha256", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "crypto.x509.parse_and_verify_certificates", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "static": [ + { + "type": "boolean" + }, + { + "dynamic": { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "array" + } + ], + "type": "array" + }, + "type": "function" + } + }, + { + "name": "crypto.x509.parse_and_verify_certificates_with_options", + "decl": { + "args": [ + { + "type": "string" + }, + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "result": { + "static": [ + { + "type": "boolean" + }, + { + "dynamic": { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "array" + } + ], + "type": "array" + }, + "type": "function" + } + }, + { + "name": "crypto.x509.parse_certificate_request", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "function" + } + }, + { + "name": "crypto.x509.parse_certificates", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "dynamic": { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "crypto.x509.parse_keypair", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "function" + } + }, + { + "name": "crypto.x509.parse_rsa_private_key", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "function" + } + }, + { + "name": "div", + "decl": { + "args": [ + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + }, + "infix": "/" + }, + { + "name": "endswith", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "eq", + "decl": { + "args": [ + { + "type": "any" + }, + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + }, + "infix": "=" + }, + { + "name": "equal", + "decl": { + "args": [ + { + "type": "any" + }, + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + }, + "infix": "==" + }, + { + "name": "floor", + "decl": { + "args": [ + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "format_int", + "decl": { + "args": [ + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "glob.match", + "decl": { + "args": [ + { + "type": "string" + }, + { + "of": [ + { + "type": "null" + }, + { + "dynamic": { + "type": "string" + }, + "type": "array" + } + ], + "type": "any" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "glob.quote_meta", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "graph.reachable", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "of": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + }, + "type": "object" + }, + { + "of": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "of": { + "type": "any" + }, + "type": "set" + }, + "type": "function" + } + }, + { + "name": "graph.reachable_paths", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "of": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + }, + "type": "object" + }, + { + "of": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "of": { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + "type": "set" + }, + "type": "function" + } + }, + { + "name": "graphql.is_valid", + "decl": { + "args": [ + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "type": "any" + }, + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "graphql.parse", + "decl": { + "args": [ + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "type": "any" + }, + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "type": "any" + } + ], + "result": { + "static": [ + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "type": "array" + }, + "type": "function" + } + }, + { + "name": "graphql.parse_and_verify", + "decl": { + "args": [ + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "type": "any" + }, + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "type": "any" + } + ], + "result": { + "static": [ + { + "type": "boolean" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "type": "array" + }, + "type": "function" + } + }, + { + "name": "graphql.parse_query", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "function" + } + }, + { + "name": "graphql.parse_schema", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "function" + } + }, + { + "name": "graphql.schema_is_valid", + "decl": { + "args": [ + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "gt", + "decl": { + "args": [ + { + "type": "any" + }, + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + }, + "infix": "\u003e" + }, + { + "name": "gte", + "decl": { + "args": [ + { + "type": "any" + }, + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + }, + "infix": "\u003e=" + }, + { + "name": "hex.decode", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "hex.encode", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "http.send", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "result": { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "function" + }, + "nondeterministic": true + }, + { + "name": "indexof", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "indexof_n", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "dynamic": { + "type": "number" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "internal.member_2", + "decl": { + "args": [ + { + "type": "any" + }, + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + }, + "infix": "in" + }, + { + "name": "internal.member_3", + "decl": { + "args": [ + { + "type": "any" + }, + { + "type": "any" + }, + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + }, + "infix": "in" + }, + { + "name": "internal.print", + "decl": { + "args": [ + { + "dynamic": { + "of": { + "type": "any" + }, + "type": "set" + }, + "type": "array" + } + ], + "type": "function" + } + }, + { + "name": "internal.test_case", + "decl": { + "args": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "type": "function" + } + }, + { + "name": "intersection", + "decl": { + "args": [ + { + "of": { + "of": { + "type": "any" + }, + "type": "set" + }, + "type": "set" + } + ], + "result": { + "of": { + "type": "any" + }, + "type": "set" + }, + "type": "function" + } + }, + { + "name": "io.jwt.decode", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "static": [ + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "type": "string" + } + ], + "type": "array" + }, + "type": "function" + } + }, + { + "name": "io.jwt.decode_verify", + "decl": { + "args": [ + { + "type": "string" + }, + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "result": { + "static": [ + { + "type": "boolean" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "type": "array" + }, + "type": "function" + }, + "nondeterministic": true + }, + { + "name": "io.jwt.encode_sign", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "result": { + "type": "string" + }, + "type": "function" + }, + "nondeterministic": true + }, + { + "name": "io.jwt.encode_sign_raw", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + }, + "nondeterministic": true + }, + { + "name": "io.jwt.verify_eddsa", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "io.jwt.verify_es256", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "io.jwt.verify_es384", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "io.jwt.verify_es512", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "io.jwt.verify_hs256", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "io.jwt.verify_hs384", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "io.jwt.verify_hs512", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "io.jwt.verify_ps256", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "io.jwt.verify_ps384", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "io.jwt.verify_ps512", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "io.jwt.verify_rs256", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "io.jwt.verify_rs384", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "io.jwt.verify_rs512", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "is_array", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "is_boolean", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "is_null", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "is_number", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "is_object", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "is_set", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "is_string", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "json.filter", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "of": [ + { + "dynamic": { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "type": "any" + }, + "type": "array" + }, + { + "of": { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "any" + }, + "type": "function" + } + }, + { + "name": "json.is_valid", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "json.marshal", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "json.marshal_with_options", + "decl": { + "args": [ + { + "type": "any" + }, + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "static": [ + { + "key": "indent", + "value": { + "type": "string" + } + }, + { + "key": "prefix", + "value": { + "type": "string" + } + }, + { + "key": "pretty", + "value": { + "type": "boolean" + } + } + ], + "type": "object" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "json.match_schema", + "decl": { + "args": [ + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "type": "any" + }, + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "type": "any" + } + ], + "result": { + "static": [ + { + "type": "boolean" + }, + { + "dynamic": { + "static": [ + { + "key": "desc", + "value": { + "type": "string" + } + }, + { + "key": "error", + "value": { + "type": "string" + } + }, + { + "key": "field", + "value": { + "type": "string" + } + }, + { + "key": "type", + "value": { + "type": "string" + } + } + ], + "type": "object" + }, + "type": "array" + } + ], + "type": "array" + }, + "type": "function" + } + }, + { + "name": "json.patch", + "decl": { + "args": [ + { + "type": "any" + }, + { + "dynamic": { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "static": [ + { + "key": "op", + "value": { + "type": "string" + } + }, + { + "key": "path", + "value": { + "type": "any" + } + } + ], + "type": "object" + }, + "type": "array" + } + ], + "result": { + "type": "any" + }, + "type": "function" + } + }, + { + "name": "json.remove", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "of": [ + { + "dynamic": { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "type": "any" + }, + "type": "array" + }, + { + "of": { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "any" + }, + "type": "function" + } + }, + { + "name": "json.unmarshal", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "any" + }, + "type": "function" + } + }, + { + "name": "json.verify_schema", + "decl": { + "args": [ + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "type": "any" + } + ], + "result": { + "static": [ + { + "type": "boolean" + }, + { + "of": [ + { + "type": "null" + }, + { + "type": "string" + } + ], + "type": "any" + } + ], + "type": "array" + }, + "type": "function" + } + }, + { + "name": "lower", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "lt", + "decl": { + "args": [ + { + "type": "any" + }, + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + }, + "infix": "\u003c" + }, + { + "name": "lte", + "decl": { + "args": [ + { + "type": "any" + }, + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + }, + "infix": "\u003c=" + }, + { + "name": "max", + "decl": { + "args": [ + { + "of": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "any" + }, + "type": "function" + } + }, + { + "name": "min", + "decl": { + "args": [ + { + "of": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "any" + }, + "type": "function" + } + }, + { + "name": "minus", + "decl": { + "args": [ + { + "of": [ + { + "type": "number" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + }, + { + "of": [ + { + "type": "number" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "of": [ + { + "type": "number" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + }, + "type": "function" + }, + "infix": "-" + }, + { + "name": "mul", + "decl": { + "args": [ + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + }, + "infix": "*" + }, + { + "name": "neq", + "decl": { + "args": [ + { + "type": "any" + }, + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + }, + "infix": "!=" + }, + { + "name": "net.cidr_contains", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "net.cidr_contains_matches", + "decl": { + "args": [ + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "type": "any" + }, + "type": "array" + }, + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "type": "any" + } + }, + "type": "object" + }, + { + "of": { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + }, + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "type": "any" + }, + "type": "array" + }, + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "type": "any" + } + }, + "type": "object" + }, + { + "of": { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "of": { + "static": [ + { + "type": "any" + }, + { + "type": "any" + } + ], + "type": "array" + }, + "type": "set" + }, + "type": "function" + } + }, + { + "name": "net.cidr_expand", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "of": { + "type": "string" + }, + "type": "set" + }, + "type": "function" + } + }, + { + "name": "net.cidr_intersects", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "net.cidr_is_valid", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "net.cidr_merge", + "decl": { + "args": [ + { + "of": [ + { + "dynamic": { + "of": [ + { + "type": "string" + } + ], + "type": "any" + }, + "type": "array" + }, + { + "of": { + "type": "string" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "of": { + "type": "string" + }, + "type": "set" + }, + "type": "function" + } + }, + { + "name": "net.cidr_overlap", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "net.lookup_ip_addr", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "of": { + "type": "string" + }, + "type": "set" + }, + "type": "function" + }, + "nondeterministic": true + }, + { + "name": "numbers.range", + "decl": { + "args": [ + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "dynamic": { + "type": "number" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "numbers.range_step", + "decl": { + "args": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "dynamic": { + "type": "number" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "object.filter", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "of": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "any" + }, + "type": "function" + } + }, + { + "name": "object.get", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "type": "any" + }, + { + "type": "any" + } + ], + "result": { + "type": "any" + }, + "type": "function" + } + }, + { + "name": "object.keys", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "result": { + "of": { + "type": "any" + }, + "type": "set" + }, + "type": "function" + } + }, + { + "name": "object.remove", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "of": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "any" + }, + "type": "function" + } + }, + { + "name": "object.subset", + "decl": { + "args": [ + { + "of": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + }, + { + "of": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "any" + }, + "type": "function" + } + }, + { + "name": "object.union", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "result": { + "type": "any" + }, + "type": "function" + } + }, + { + "name": "object.union_n", + "decl": { + "args": [ + { + "dynamic": { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "array" + } + ], + "result": { + "type": "any" + }, + "type": "function" + } + }, + { + "name": "opa.runtime", + "decl": { + "result": { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "function" + }, + "nondeterministic": true + }, + { + "name": "or", + "decl": { + "args": [ + { + "of": { + "type": "any" + }, + "type": "set" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "result": { + "of": { + "type": "any" + }, + "type": "set" + }, + "type": "function" + }, + "infix": "|" + }, + { + "name": "plus", + "decl": { + "args": [ + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + }, + "infix": "+" + }, + { + "name": "print", + "decl": { + "type": "function", + "variadic": { + "type": "any" + } + } + }, + { + "name": "product", + "decl": { + "args": [ + { + "of": [ + { + "dynamic": { + "type": "number" + }, + "type": "array" + }, + { + "of": { + "type": "number" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "providers.aws.sign_req", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "type": "number" + } + ], + "result": { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "function" + } + }, + { + "name": "rand.intn", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + }, + "nondeterministic": true + }, + { + "name": "re_match", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "regex.find_all_string_submatch_n", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + }, + { + "type": "number" + } + ], + "result": { + "dynamic": { + "dynamic": { + "type": "string" + }, + "type": "array" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "regex.find_n", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + }, + { + "type": "number" + } + ], + "result": { + "dynamic": { + "type": "string" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "regex.globs_match", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "regex.is_valid", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "regex.match", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "regex.replace", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "regex.split", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "dynamic": { + "type": "string" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "regex.template_match", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + }, + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "rego.metadata.chain", + "decl": { + "result": { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "rego.metadata.rule", + "decl": { + "result": { + "type": "any" + }, + "type": "function" + } + }, + { + "name": "rego.parse_module", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "function" + } + }, + { + "name": "rem", + "decl": { + "args": [ + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + }, + "infix": "%" + }, + { + "name": "replace", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "round", + "decl": { + "args": [ + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "semver.compare", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "semver.is_valid", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "set_diff", + "decl": { + "args": [ + { + "of": { + "type": "any" + }, + "type": "set" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "result": { + "of": { + "type": "any" + }, + "type": "set" + }, + "type": "function" + } + }, + { + "name": "sort", + "decl": { + "args": [ + { + "of": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "split", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "dynamic": { + "type": "string" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "sprintf", + "decl": { + "args": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "startswith", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "strings.any_prefix_match", + "decl": { + "args": [ + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "string" + }, + "type": "array" + }, + { + "of": { + "type": "string" + }, + "type": "set" + } + ], + "type": "any" + }, + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "string" + }, + "type": "array" + }, + { + "of": { + "type": "string" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "strings.any_suffix_match", + "decl": { + "args": [ + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "string" + }, + "type": "array" + }, + { + "of": { + "type": "string" + }, + "type": "set" + } + ], + "type": "any" + }, + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "string" + }, + "type": "array" + }, + { + "of": { + "type": "string" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "strings.count", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "strings.render_template", + "decl": { + "args": [ + { + "type": "string" + }, + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "strings.replace_n", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "type": "object" + }, + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "strings.reverse", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "substring", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "sum", + "decl": { + "args": [ + { + "of": [ + { + "dynamic": { + "type": "number" + }, + "type": "array" + }, + { + "of": { + "type": "number" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "time.add_date", + "decl": { + "args": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "time.clock", + "decl": { + "args": [ + { + "of": [ + { + "type": "number" + }, + { + "static": [ + { + "type": "number" + }, + { + "type": "string" + } + ], + "type": "array" + } + ], + "type": "any" + } + ], + "result": { + "static": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + } + ], + "type": "array" + }, + "type": "function" + } + }, + { + "name": "time.date", + "decl": { + "args": [ + { + "of": [ + { + "type": "number" + }, + { + "static": [ + { + "type": "number" + }, + { + "type": "string" + } + ], + "type": "array" + } + ], + "type": "any" + } + ], + "result": { + "static": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + } + ], + "type": "array" + }, + "type": "function" + } + }, + { + "name": "time.diff", + "decl": { + "args": [ + { + "of": [ + { + "type": "number" + }, + { + "static": [ + { + "type": "number" + }, + { + "type": "string" + } + ], + "type": "array" + } + ], + "type": "any" + }, + { + "of": [ + { + "type": "number" + }, + { + "static": [ + { + "type": "number" + }, + { + "type": "string" + } + ], + "type": "array" + } + ], + "type": "any" + } + ], + "result": { + "static": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + } + ], + "type": "array" + }, + "type": "function" + } + }, + { + "name": "time.format", + "decl": { + "args": [ + { + "of": [ + { + "type": "number" + }, + { + "static": [ + { + "type": "number" + }, + { + "type": "string" + } + ], + "type": "array" + }, + { + "static": [ + { + "type": "number" + }, + { + "type": "string" + }, + { + "type": "string" + } + ], + "type": "array" + } + ], + "type": "any" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "time.now_ns", + "decl": { + "result": { + "type": "number" + }, + "type": "function" + }, + "nondeterministic": true + }, + { + "name": "time.parse_duration_ns", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "time.parse_ns", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "time.parse_rfc3339_ns", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "time.weekday", + "decl": { + "args": [ + { + "of": [ + { + "type": "number" + }, + { + "static": [ + { + "type": "number" + }, + { + "type": "string" + } + ], + "type": "array" + } + ], + "type": "any" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "to_number", + "decl": { + "args": [ + { + "of": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ], + "type": "any" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "trace", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "trim", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "trim_left", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "trim_prefix", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "trim_right", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "trim_space", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "trim_suffix", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "type_name", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "union", + "decl": { + "args": [ + { + "of": { + "of": { + "type": "any" + }, + "type": "set" + }, + "type": "set" + } + ], + "result": { + "of": { + "type": "any" + }, + "type": "set" + }, + "type": "function" + } + }, + { + "name": "units.parse", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "units.parse_bytes", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "upper", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "urlquery.decode", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "urlquery.decode_object", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "dynamic": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "type": "function" + } + }, + { + "name": "urlquery.encode", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "urlquery.encode_object", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "string" + }, + "type": "array" + }, + { + "of": { + "type": "string" + }, + "type": "set" + } + ], + "type": "any" + } + }, + "type": "object" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "uuid.parse", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "function" + } + }, + { + "name": "uuid.rfc4122", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + }, + "nondeterministic": true + }, + { + "name": "walk", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "static": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "type": "any" + } + ], + "type": "array" + }, + "type": "function" + }, + "relation": true + }, + { + "name": "yaml.is_valid", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "yaml.marshal", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "yaml.unmarshal", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "any" + }, + "type": "function" + } + } + ], + "wasm_abi_versions": [ + { + "version": 1, + "minor_version": 1 + }, + { + "version": 1, + "minor_version": 2 + } + ], + "features": [ + "keywords_in_refs", + "rego_v1" + ] +} diff --git a/vendor/github.com/open-policy-agent/opa/capabilities/v1.7.0.json b/vendor/github.com/open-policy-agent/opa/capabilities/v1.7.0.json new file mode 100644 index 00000000000..110c3eca919 --- /dev/null +++ b/vendor/github.com/open-policy-agent/opa/capabilities/v1.7.0.json @@ -0,0 +1,4850 @@ +{ + "builtins": [ + { + "name": "abs", + "decl": { + "args": [ + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "all", + "decl": { + "args": [ + { + "of": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "and", + "decl": { + "args": [ + { + "of": { + "type": "any" + }, + "type": "set" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "result": { + "of": { + "type": "any" + }, + "type": "set" + }, + "type": "function" + }, + "infix": "\u0026" + }, + { + "name": "any", + "decl": { + "args": [ + { + "of": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "array.concat", + "decl": { + "args": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "result": { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "array.reverse", + "decl": { + "args": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "result": { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "array.slice", + "decl": { + "args": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "assign", + "decl": { + "args": [ + { + "type": "any" + }, + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + }, + "infix": ":=" + }, + { + "name": "base64.decode", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "base64.encode", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "base64.is_valid", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "base64url.decode", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "base64url.encode", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "base64url.encode_no_pad", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "bits.and", + "decl": { + "args": [ + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "bits.lsh", + "decl": { + "args": [ + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "bits.negate", + "decl": { + "args": [ + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "bits.or", + "decl": { + "args": [ + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "bits.rsh", + "decl": { + "args": [ + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "bits.xor", + "decl": { + "args": [ + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "cast_array", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "cast_boolean", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "cast_null", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "null" + }, + "type": "function" + } + }, + { + "name": "cast_object", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "function" + } + }, + { + "name": "cast_set", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "of": { + "type": "any" + }, + "type": "set" + }, + "type": "function" + } + }, + { + "name": "cast_string", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "ceil", + "decl": { + "args": [ + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "concat", + "decl": { + "args": [ + { + "type": "string" + }, + { + "of": [ + { + "dynamic": { + "type": "string" + }, + "type": "array" + }, + { + "of": { + "type": "string" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "contains", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "count", + "decl": { + "args": [ + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "crypto.hmac.equal", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "crypto.hmac.md5", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "crypto.hmac.sha1", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "crypto.hmac.sha256", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "crypto.hmac.sha512", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "crypto.md5", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "crypto.parse_private_keys", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "dynamic": { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "crypto.sha1", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "crypto.sha256", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "crypto.x509.parse_and_verify_certificates", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "static": [ + { + "type": "boolean" + }, + { + "dynamic": { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "array" + } + ], + "type": "array" + }, + "type": "function" + } + }, + { + "name": "crypto.x509.parse_and_verify_certificates_with_options", + "decl": { + "args": [ + { + "type": "string" + }, + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "result": { + "static": [ + { + "type": "boolean" + }, + { + "dynamic": { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "array" + } + ], + "type": "array" + }, + "type": "function" + } + }, + { + "name": "crypto.x509.parse_certificate_request", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "function" + } + }, + { + "name": "crypto.x509.parse_certificates", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "dynamic": { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "crypto.x509.parse_keypair", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "function" + } + }, + { + "name": "crypto.x509.parse_rsa_private_key", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "function" + } + }, + { + "name": "div", + "decl": { + "args": [ + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + }, + "infix": "/" + }, + { + "name": "endswith", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "eq", + "decl": { + "args": [ + { + "type": "any" + }, + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + }, + "infix": "=" + }, + { + "name": "equal", + "decl": { + "args": [ + { + "type": "any" + }, + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + }, + "infix": "==" + }, + { + "name": "floor", + "decl": { + "args": [ + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "format_int", + "decl": { + "args": [ + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "glob.match", + "decl": { + "args": [ + { + "type": "string" + }, + { + "of": [ + { + "type": "null" + }, + { + "dynamic": { + "type": "string" + }, + "type": "array" + } + ], + "type": "any" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "glob.quote_meta", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "graph.reachable", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "of": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + }, + "type": "object" + }, + { + "of": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "of": { + "type": "any" + }, + "type": "set" + }, + "type": "function" + } + }, + { + "name": "graph.reachable_paths", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "of": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + }, + "type": "object" + }, + { + "of": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "of": { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + "type": "set" + }, + "type": "function" + } + }, + { + "name": "graphql.is_valid", + "decl": { + "args": [ + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "type": "any" + }, + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "graphql.parse", + "decl": { + "args": [ + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "type": "any" + }, + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "type": "any" + } + ], + "result": { + "static": [ + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "type": "array" + }, + "type": "function" + } + }, + { + "name": "graphql.parse_and_verify", + "decl": { + "args": [ + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "type": "any" + }, + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "type": "any" + } + ], + "result": { + "static": [ + { + "type": "boolean" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "type": "array" + }, + "type": "function" + } + }, + { + "name": "graphql.parse_query", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "function" + } + }, + { + "name": "graphql.parse_schema", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "function" + } + }, + { + "name": "graphql.schema_is_valid", + "decl": { + "args": [ + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "gt", + "decl": { + "args": [ + { + "type": "any" + }, + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + }, + "infix": "\u003e" + }, + { + "name": "gte", + "decl": { + "args": [ + { + "type": "any" + }, + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + }, + "infix": "\u003e=" + }, + { + "name": "hex.decode", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "hex.encode", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "http.send", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "result": { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "function" + }, + "nondeterministic": true + }, + { + "name": "indexof", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "indexof_n", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "dynamic": { + "type": "number" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "internal.member_2", + "decl": { + "args": [ + { + "type": "any" + }, + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + }, + "infix": "in" + }, + { + "name": "internal.member_3", + "decl": { + "args": [ + { + "type": "any" + }, + { + "type": "any" + }, + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + }, + "infix": "in" + }, + { + "name": "internal.print", + "decl": { + "args": [ + { + "dynamic": { + "of": { + "type": "any" + }, + "type": "set" + }, + "type": "array" + } + ], + "type": "function" + } + }, + { + "name": "internal.test_case", + "decl": { + "args": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "type": "function" + } + }, + { + "name": "intersection", + "decl": { + "args": [ + { + "of": { + "of": { + "type": "any" + }, + "type": "set" + }, + "type": "set" + } + ], + "result": { + "of": { + "type": "any" + }, + "type": "set" + }, + "type": "function" + } + }, + { + "name": "io.jwt.decode", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "static": [ + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "type": "string" + } + ], + "type": "array" + }, + "type": "function" + } + }, + { + "name": "io.jwt.decode_verify", + "decl": { + "args": [ + { + "type": "string" + }, + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "result": { + "static": [ + { + "type": "boolean" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "type": "array" + }, + "type": "function" + }, + "nondeterministic": true + }, + { + "name": "io.jwt.encode_sign", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "result": { + "type": "string" + }, + "type": "function" + }, + "nondeterministic": true + }, + { + "name": "io.jwt.encode_sign_raw", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + }, + "nondeterministic": true + }, + { + "name": "io.jwt.verify_es256", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "io.jwt.verify_es384", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "io.jwt.verify_es512", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "io.jwt.verify_hs256", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "io.jwt.verify_hs384", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "io.jwt.verify_hs512", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "io.jwt.verify_ps256", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "io.jwt.verify_ps384", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "io.jwt.verify_ps512", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "io.jwt.verify_rs256", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "io.jwt.verify_rs384", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "io.jwt.verify_rs512", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "is_array", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "is_boolean", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "is_null", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "is_number", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "is_object", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "is_set", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "is_string", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "json.filter", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "of": [ + { + "dynamic": { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "type": "any" + }, + "type": "array" + }, + { + "of": { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "any" + }, + "type": "function" + } + }, + { + "name": "json.is_valid", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "json.marshal", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "json.marshal_with_options", + "decl": { + "args": [ + { + "type": "any" + }, + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "static": [ + { + "key": "indent", + "value": { + "type": "string" + } + }, + { + "key": "prefix", + "value": { + "type": "string" + } + }, + { + "key": "pretty", + "value": { + "type": "boolean" + } + } + ], + "type": "object" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "json.match_schema", + "decl": { + "args": [ + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "type": "any" + }, + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "type": "any" + } + ], + "result": { + "static": [ + { + "type": "boolean" + }, + { + "dynamic": { + "static": [ + { + "key": "desc", + "value": { + "type": "string" + } + }, + { + "key": "error", + "value": { + "type": "string" + } + }, + { + "key": "field", + "value": { + "type": "string" + } + }, + { + "key": "type", + "value": { + "type": "string" + } + } + ], + "type": "object" + }, + "type": "array" + } + ], + "type": "array" + }, + "type": "function" + } + }, + { + "name": "json.patch", + "decl": { + "args": [ + { + "type": "any" + }, + { + "dynamic": { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "static": [ + { + "key": "op", + "value": { + "type": "string" + } + }, + { + "key": "path", + "value": { + "type": "any" + } + } + ], + "type": "object" + }, + "type": "array" + } + ], + "result": { + "type": "any" + }, + "type": "function" + } + }, + { + "name": "json.remove", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "of": [ + { + "dynamic": { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "type": "any" + }, + "type": "array" + }, + { + "of": { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "any" + }, + "type": "function" + } + }, + { + "name": "json.unmarshal", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "any" + }, + "type": "function" + } + }, + { + "name": "json.verify_schema", + "decl": { + "args": [ + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "type": "any" + } + ], + "result": { + "static": [ + { + "type": "boolean" + }, + { + "of": [ + { + "type": "null" + }, + { + "type": "string" + } + ], + "type": "any" + } + ], + "type": "array" + }, + "type": "function" + } + }, + { + "name": "lower", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "lt", + "decl": { + "args": [ + { + "type": "any" + }, + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + }, + "infix": "\u003c" + }, + { + "name": "lte", + "decl": { + "args": [ + { + "type": "any" + }, + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + }, + "infix": "\u003c=" + }, + { + "name": "max", + "decl": { + "args": [ + { + "of": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "any" + }, + "type": "function" + } + }, + { + "name": "min", + "decl": { + "args": [ + { + "of": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "any" + }, + "type": "function" + } + }, + { + "name": "minus", + "decl": { + "args": [ + { + "of": [ + { + "type": "number" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + }, + { + "of": [ + { + "type": "number" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "of": [ + { + "type": "number" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + }, + "type": "function" + }, + "infix": "-" + }, + { + "name": "mul", + "decl": { + "args": [ + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + }, + "infix": "*" + }, + { + "name": "neq", + "decl": { + "args": [ + { + "type": "any" + }, + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + }, + "infix": "!=" + }, + { + "name": "net.cidr_contains", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "net.cidr_contains_matches", + "decl": { + "args": [ + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "type": "any" + }, + "type": "array" + }, + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "type": "any" + } + }, + "type": "object" + }, + { + "of": { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + }, + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "type": "any" + }, + "type": "array" + }, + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "type": "any" + } + }, + "type": "object" + }, + { + "of": { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "of": { + "static": [ + { + "type": "any" + }, + { + "type": "any" + } + ], + "type": "array" + }, + "type": "set" + }, + "type": "function" + } + }, + { + "name": "net.cidr_expand", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "of": { + "type": "string" + }, + "type": "set" + }, + "type": "function" + } + }, + { + "name": "net.cidr_intersects", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "net.cidr_is_valid", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "net.cidr_merge", + "decl": { + "args": [ + { + "of": [ + { + "dynamic": { + "of": [ + { + "type": "string" + } + ], + "type": "any" + }, + "type": "array" + }, + { + "of": { + "type": "string" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "of": { + "type": "string" + }, + "type": "set" + }, + "type": "function" + } + }, + { + "name": "net.cidr_overlap", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "net.lookup_ip_addr", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "of": { + "type": "string" + }, + "type": "set" + }, + "type": "function" + }, + "nondeterministic": true + }, + { + "name": "numbers.range", + "decl": { + "args": [ + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "dynamic": { + "type": "number" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "numbers.range_step", + "decl": { + "args": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "dynamic": { + "type": "number" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "object.filter", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "of": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "any" + }, + "type": "function" + } + }, + { + "name": "object.get", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "type": "any" + }, + { + "type": "any" + } + ], + "result": { + "type": "any" + }, + "type": "function" + } + }, + { + "name": "object.keys", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "result": { + "of": { + "type": "any" + }, + "type": "set" + }, + "type": "function" + } + }, + { + "name": "object.remove", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "of": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "any" + }, + "type": "function" + } + }, + { + "name": "object.subset", + "decl": { + "args": [ + { + "of": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + }, + { + "of": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "any" + }, + "type": "function" + } + }, + { + "name": "object.union", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "result": { + "type": "any" + }, + "type": "function" + } + }, + { + "name": "object.union_n", + "decl": { + "args": [ + { + "dynamic": { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "array" + } + ], + "result": { + "type": "any" + }, + "type": "function" + } + }, + { + "name": "opa.runtime", + "decl": { + "result": { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "function" + }, + "nondeterministic": true + }, + { + "name": "or", + "decl": { + "args": [ + { + "of": { + "type": "any" + }, + "type": "set" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "result": { + "of": { + "type": "any" + }, + "type": "set" + }, + "type": "function" + }, + "infix": "|" + }, + { + "name": "plus", + "decl": { + "args": [ + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + }, + "infix": "+" + }, + { + "name": "print", + "decl": { + "type": "function", + "variadic": { + "type": "any" + } + } + }, + { + "name": "product", + "decl": { + "args": [ + { + "of": [ + { + "dynamic": { + "type": "number" + }, + "type": "array" + }, + { + "of": { + "type": "number" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "providers.aws.sign_req", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "type": "number" + } + ], + "result": { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "function" + } + }, + { + "name": "rand.intn", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + }, + "nondeterministic": true + }, + { + "name": "re_match", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "regex.find_all_string_submatch_n", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + }, + { + "type": "number" + } + ], + "result": { + "dynamic": { + "dynamic": { + "type": "string" + }, + "type": "array" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "regex.find_n", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + }, + { + "type": "number" + } + ], + "result": { + "dynamic": { + "type": "string" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "regex.globs_match", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "regex.is_valid", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "regex.match", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "regex.replace", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "regex.split", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "dynamic": { + "type": "string" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "regex.template_match", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + }, + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "rego.metadata.chain", + "decl": { + "result": { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "rego.metadata.rule", + "decl": { + "result": { + "type": "any" + }, + "type": "function" + } + }, + { + "name": "rego.parse_module", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "function" + } + }, + { + "name": "rem", + "decl": { + "args": [ + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + }, + "infix": "%" + }, + { + "name": "replace", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "round", + "decl": { + "args": [ + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "semver.compare", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "semver.is_valid", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "set_diff", + "decl": { + "args": [ + { + "of": { + "type": "any" + }, + "type": "set" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "result": { + "of": { + "type": "any" + }, + "type": "set" + }, + "type": "function" + } + }, + { + "name": "sort", + "decl": { + "args": [ + { + "of": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "split", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "dynamic": { + "type": "string" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "sprintf", + "decl": { + "args": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "startswith", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "strings.any_prefix_match", + "decl": { + "args": [ + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "string" + }, + "type": "array" + }, + { + "of": { + "type": "string" + }, + "type": "set" + } + ], + "type": "any" + }, + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "string" + }, + "type": "array" + }, + { + "of": { + "type": "string" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "strings.any_suffix_match", + "decl": { + "args": [ + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "string" + }, + "type": "array" + }, + { + "of": { + "type": "string" + }, + "type": "set" + } + ], + "type": "any" + }, + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "string" + }, + "type": "array" + }, + { + "of": { + "type": "string" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "strings.count", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "strings.render_template", + "decl": { + "args": [ + { + "type": "string" + }, + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "strings.replace_n", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "type": "object" + }, + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "strings.reverse", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "substring", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "sum", + "decl": { + "args": [ + { + "of": [ + { + "dynamic": { + "type": "number" + }, + "type": "array" + }, + { + "of": { + "type": "number" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "time.add_date", + "decl": { + "args": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "time.clock", + "decl": { + "args": [ + { + "of": [ + { + "type": "number" + }, + { + "static": [ + { + "type": "number" + }, + { + "type": "string" + } + ], + "type": "array" + } + ], + "type": "any" + } + ], + "result": { + "static": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + } + ], + "type": "array" + }, + "type": "function" + } + }, + { + "name": "time.date", + "decl": { + "args": [ + { + "of": [ + { + "type": "number" + }, + { + "static": [ + { + "type": "number" + }, + { + "type": "string" + } + ], + "type": "array" + } + ], + "type": "any" + } + ], + "result": { + "static": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + } + ], + "type": "array" + }, + "type": "function" + } + }, + { + "name": "time.diff", + "decl": { + "args": [ + { + "of": [ + { + "type": "number" + }, + { + "static": [ + { + "type": "number" + }, + { + "type": "string" + } + ], + "type": "array" + } + ], + "type": "any" + }, + { + "of": [ + { + "type": "number" + }, + { + "static": [ + { + "type": "number" + }, + { + "type": "string" + } + ], + "type": "array" + } + ], + "type": "any" + } + ], + "result": { + "static": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + } + ], + "type": "array" + }, + "type": "function" + } + }, + { + "name": "time.format", + "decl": { + "args": [ + { + "of": [ + { + "type": "number" + }, + { + "static": [ + { + "type": "number" + }, + { + "type": "string" + } + ], + "type": "array" + }, + { + "static": [ + { + "type": "number" + }, + { + "type": "string" + }, + { + "type": "string" + } + ], + "type": "array" + } + ], + "type": "any" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "time.now_ns", + "decl": { + "result": { + "type": "number" + }, + "type": "function" + }, + "nondeterministic": true + }, + { + "name": "time.parse_duration_ns", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "time.parse_ns", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "time.parse_rfc3339_ns", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "time.weekday", + "decl": { + "args": [ + { + "of": [ + { + "type": "number" + }, + { + "static": [ + { + "type": "number" + }, + { + "type": "string" + } + ], + "type": "array" + } + ], + "type": "any" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "to_number", + "decl": { + "args": [ + { + "of": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ], + "type": "any" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "trace", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "trim", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "trim_left", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "trim_prefix", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "trim_right", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "trim_space", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "trim_suffix", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "type_name", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "union", + "decl": { + "args": [ + { + "of": { + "of": { + "type": "any" + }, + "type": "set" + }, + "type": "set" + } + ], + "result": { + "of": { + "type": "any" + }, + "type": "set" + }, + "type": "function" + } + }, + { + "name": "units.parse", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "units.parse_bytes", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "upper", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "urlquery.decode", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "urlquery.decode_object", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "dynamic": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "type": "function" + } + }, + { + "name": "urlquery.encode", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "urlquery.encode_object", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "string" + }, + "type": "array" + }, + { + "of": { + "type": "string" + }, + "type": "set" + } + ], + "type": "any" + } + }, + "type": "object" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "uuid.parse", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "function" + } + }, + { + "name": "uuid.rfc4122", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + }, + "nondeterministic": true + }, + { + "name": "walk", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "static": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "type": "any" + } + ], + "type": "array" + }, + "type": "function" + }, + "relation": true + }, + { + "name": "yaml.is_valid", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "yaml.marshal", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "yaml.unmarshal", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "any" + }, + "type": "function" + } + } + ], + "wasm_abi_versions": [ + { + "version": 1, + "minor_version": 1 + }, + { + "version": 1, + "minor_version": 2 + } + ], + "features": [ + "keywords_in_refs", + "rego_v1" + ] +} diff --git a/vendor/github.com/open-policy-agent/opa/capabilities/v1.8.0.json b/vendor/github.com/open-policy-agent/opa/capabilities/v1.8.0.json new file mode 100644 index 00000000000..0a37621d0c5 --- /dev/null +++ b/vendor/github.com/open-policy-agent/opa/capabilities/v1.8.0.json @@ -0,0 +1,4867 @@ +{ + "builtins": [ + { + "name": "abs", + "decl": { + "args": [ + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "all", + "decl": { + "args": [ + { + "of": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "and", + "decl": { + "args": [ + { + "of": { + "type": "any" + }, + "type": "set" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "result": { + "of": { + "type": "any" + }, + "type": "set" + }, + "type": "function" + }, + "infix": "\u0026" + }, + { + "name": "any", + "decl": { + "args": [ + { + "of": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "array.concat", + "decl": { + "args": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "result": { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "array.reverse", + "decl": { + "args": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "result": { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "array.slice", + "decl": { + "args": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "assign", + "decl": { + "args": [ + { + "type": "any" + }, + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + }, + "infix": ":=" + }, + { + "name": "base64.decode", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "base64.encode", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "base64.is_valid", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "base64url.decode", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "base64url.encode", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "base64url.encode_no_pad", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "bits.and", + "decl": { + "args": [ + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "bits.lsh", + "decl": { + "args": [ + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "bits.negate", + "decl": { + "args": [ + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "bits.or", + "decl": { + "args": [ + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "bits.rsh", + "decl": { + "args": [ + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "bits.xor", + "decl": { + "args": [ + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "cast_array", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "cast_boolean", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "cast_null", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "null" + }, + "type": "function" + } + }, + { + "name": "cast_object", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "function" + } + }, + { + "name": "cast_set", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "of": { + "type": "any" + }, + "type": "set" + }, + "type": "function" + } + }, + { + "name": "cast_string", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "ceil", + "decl": { + "args": [ + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "concat", + "decl": { + "args": [ + { + "type": "string" + }, + { + "of": [ + { + "dynamic": { + "type": "string" + }, + "type": "array" + }, + { + "of": { + "type": "string" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "contains", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "count", + "decl": { + "args": [ + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "crypto.hmac.equal", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "crypto.hmac.md5", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "crypto.hmac.sha1", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "crypto.hmac.sha256", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "crypto.hmac.sha512", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "crypto.md5", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "crypto.parse_private_keys", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "dynamic": { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "crypto.sha1", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "crypto.sha256", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "crypto.x509.parse_and_verify_certificates", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "static": [ + { + "type": "boolean" + }, + { + "dynamic": { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "array" + } + ], + "type": "array" + }, + "type": "function" + } + }, + { + "name": "crypto.x509.parse_and_verify_certificates_with_options", + "decl": { + "args": [ + { + "type": "string" + }, + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "result": { + "static": [ + { + "type": "boolean" + }, + { + "dynamic": { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "array" + } + ], + "type": "array" + }, + "type": "function" + } + }, + { + "name": "crypto.x509.parse_certificate_request", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "function" + } + }, + { + "name": "crypto.x509.parse_certificates", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "dynamic": { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "crypto.x509.parse_keypair", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "function" + } + }, + { + "name": "crypto.x509.parse_rsa_private_key", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "function" + } + }, + { + "name": "div", + "decl": { + "args": [ + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + }, + "infix": "/" + }, + { + "name": "endswith", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "eq", + "decl": { + "args": [ + { + "type": "any" + }, + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + }, + "infix": "=" + }, + { + "name": "equal", + "decl": { + "args": [ + { + "type": "any" + }, + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + }, + "infix": "==" + }, + { + "name": "floor", + "decl": { + "args": [ + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "format_int", + "decl": { + "args": [ + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "glob.match", + "decl": { + "args": [ + { + "type": "string" + }, + { + "of": [ + { + "type": "null" + }, + { + "dynamic": { + "type": "string" + }, + "type": "array" + } + ], + "type": "any" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "glob.quote_meta", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "graph.reachable", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "of": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + }, + "type": "object" + }, + { + "of": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "of": { + "type": "any" + }, + "type": "set" + }, + "type": "function" + } + }, + { + "name": "graph.reachable_paths", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "of": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + }, + "type": "object" + }, + { + "of": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "of": { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + "type": "set" + }, + "type": "function" + } + }, + { + "name": "graphql.is_valid", + "decl": { + "args": [ + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "type": "any" + }, + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "graphql.parse", + "decl": { + "args": [ + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "type": "any" + }, + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "type": "any" + } + ], + "result": { + "static": [ + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "type": "array" + }, + "type": "function" + } + }, + { + "name": "graphql.parse_and_verify", + "decl": { + "args": [ + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "type": "any" + }, + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "type": "any" + } + ], + "result": { + "static": [ + { + "type": "boolean" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "type": "array" + }, + "type": "function" + } + }, + { + "name": "graphql.parse_query", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "function" + } + }, + { + "name": "graphql.parse_schema", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "function" + } + }, + { + "name": "graphql.schema_is_valid", + "decl": { + "args": [ + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "gt", + "decl": { + "args": [ + { + "type": "any" + }, + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + }, + "infix": "\u003e" + }, + { + "name": "gte", + "decl": { + "args": [ + { + "type": "any" + }, + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + }, + "infix": "\u003e=" + }, + { + "name": "hex.decode", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "hex.encode", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "http.send", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "result": { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "function" + }, + "nondeterministic": true + }, + { + "name": "indexof", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "indexof_n", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "dynamic": { + "type": "number" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "internal.member_2", + "decl": { + "args": [ + { + "type": "any" + }, + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + }, + "infix": "in" + }, + { + "name": "internal.member_3", + "decl": { + "args": [ + { + "type": "any" + }, + { + "type": "any" + }, + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + }, + "infix": "in" + }, + { + "name": "internal.print", + "decl": { + "args": [ + { + "dynamic": { + "of": { + "type": "any" + }, + "type": "set" + }, + "type": "array" + } + ], + "type": "function" + } + }, + { + "name": "internal.test_case", + "decl": { + "args": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "type": "function" + } + }, + { + "name": "intersection", + "decl": { + "args": [ + { + "of": { + "of": { + "type": "any" + }, + "type": "set" + }, + "type": "set" + } + ], + "result": { + "of": { + "type": "any" + }, + "type": "set" + }, + "type": "function" + } + }, + { + "name": "io.jwt.decode", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "static": [ + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "type": "string" + } + ], + "type": "array" + }, + "type": "function" + } + }, + { + "name": "io.jwt.decode_verify", + "decl": { + "args": [ + { + "type": "string" + }, + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "result": { + "static": [ + { + "type": "boolean" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "type": "array" + }, + "type": "function" + }, + "nondeterministic": true + }, + { + "name": "io.jwt.encode_sign", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "result": { + "type": "string" + }, + "type": "function" + }, + "nondeterministic": true + }, + { + "name": "io.jwt.encode_sign_raw", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + }, + "nondeterministic": true + }, + { + "name": "io.jwt.verify_eddsa", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "io.jwt.verify_es256", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "io.jwt.verify_es384", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "io.jwt.verify_es512", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "io.jwt.verify_hs256", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "io.jwt.verify_hs384", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "io.jwt.verify_hs512", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "io.jwt.verify_ps256", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "io.jwt.verify_ps384", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "io.jwt.verify_ps512", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "io.jwt.verify_rs256", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "io.jwt.verify_rs384", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "io.jwt.verify_rs512", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "is_array", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "is_boolean", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "is_null", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "is_number", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "is_object", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "is_set", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "is_string", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "json.filter", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "of": [ + { + "dynamic": { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "type": "any" + }, + "type": "array" + }, + { + "of": { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "any" + }, + "type": "function" + } + }, + { + "name": "json.is_valid", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "json.marshal", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "json.marshal_with_options", + "decl": { + "args": [ + { + "type": "any" + }, + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "static": [ + { + "key": "indent", + "value": { + "type": "string" + } + }, + { + "key": "prefix", + "value": { + "type": "string" + } + }, + { + "key": "pretty", + "value": { + "type": "boolean" + } + } + ], + "type": "object" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "json.match_schema", + "decl": { + "args": [ + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "type": "any" + }, + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "type": "any" + } + ], + "result": { + "static": [ + { + "type": "boolean" + }, + { + "dynamic": { + "static": [ + { + "key": "desc", + "value": { + "type": "string" + } + }, + { + "key": "error", + "value": { + "type": "string" + } + }, + { + "key": "field", + "value": { + "type": "string" + } + }, + { + "key": "type", + "value": { + "type": "string" + } + } + ], + "type": "object" + }, + "type": "array" + } + ], + "type": "array" + }, + "type": "function" + } + }, + { + "name": "json.patch", + "decl": { + "args": [ + { + "type": "any" + }, + { + "dynamic": { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "static": [ + { + "key": "op", + "value": { + "type": "string" + } + }, + { + "key": "path", + "value": { + "type": "any" + } + } + ], + "type": "object" + }, + "type": "array" + } + ], + "result": { + "type": "any" + }, + "type": "function" + } + }, + { + "name": "json.remove", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "of": [ + { + "dynamic": { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "type": "any" + }, + "type": "array" + }, + { + "of": { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "any" + }, + "type": "function" + } + }, + { + "name": "json.unmarshal", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "any" + }, + "type": "function" + } + }, + { + "name": "json.verify_schema", + "decl": { + "args": [ + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "type": "any" + } + ], + "result": { + "static": [ + { + "type": "boolean" + }, + { + "of": [ + { + "type": "null" + }, + { + "type": "string" + } + ], + "type": "any" + } + ], + "type": "array" + }, + "type": "function" + } + }, + { + "name": "lower", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "lt", + "decl": { + "args": [ + { + "type": "any" + }, + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + }, + "infix": "\u003c" + }, + { + "name": "lte", + "decl": { + "args": [ + { + "type": "any" + }, + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + }, + "infix": "\u003c=" + }, + { + "name": "max", + "decl": { + "args": [ + { + "of": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "any" + }, + "type": "function" + } + }, + { + "name": "min", + "decl": { + "args": [ + { + "of": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "any" + }, + "type": "function" + } + }, + { + "name": "minus", + "decl": { + "args": [ + { + "of": [ + { + "type": "number" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + }, + { + "of": [ + { + "type": "number" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "of": [ + { + "type": "number" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + }, + "type": "function" + }, + "infix": "-" + }, + { + "name": "mul", + "decl": { + "args": [ + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + }, + "infix": "*" + }, + { + "name": "neq", + "decl": { + "args": [ + { + "type": "any" + }, + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + }, + "infix": "!=" + }, + { + "name": "net.cidr_contains", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "net.cidr_contains_matches", + "decl": { + "args": [ + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "type": "any" + }, + "type": "array" + }, + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "type": "any" + } + }, + "type": "object" + }, + { + "of": { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + }, + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "type": "any" + }, + "type": "array" + }, + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "type": "any" + } + }, + "type": "object" + }, + { + "of": { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "of": { + "static": [ + { + "type": "any" + }, + { + "type": "any" + } + ], + "type": "array" + }, + "type": "set" + }, + "type": "function" + } + }, + { + "name": "net.cidr_expand", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "of": { + "type": "string" + }, + "type": "set" + }, + "type": "function" + } + }, + { + "name": "net.cidr_intersects", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "net.cidr_is_valid", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "net.cidr_merge", + "decl": { + "args": [ + { + "of": [ + { + "dynamic": { + "of": [ + { + "type": "string" + } + ], + "type": "any" + }, + "type": "array" + }, + { + "of": { + "type": "string" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "of": { + "type": "string" + }, + "type": "set" + }, + "type": "function" + } + }, + { + "name": "net.cidr_overlap", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "net.lookup_ip_addr", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "of": { + "type": "string" + }, + "type": "set" + }, + "type": "function" + }, + "nondeterministic": true + }, + { + "name": "numbers.range", + "decl": { + "args": [ + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "dynamic": { + "type": "number" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "numbers.range_step", + "decl": { + "args": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "dynamic": { + "type": "number" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "object.filter", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "of": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "any" + }, + "type": "function" + } + }, + { + "name": "object.get", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "type": "any" + }, + { + "type": "any" + } + ], + "result": { + "type": "any" + }, + "type": "function" + } + }, + { + "name": "object.keys", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "result": { + "of": { + "type": "any" + }, + "type": "set" + }, + "type": "function" + } + }, + { + "name": "object.remove", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "of": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "any" + }, + "type": "function" + } + }, + { + "name": "object.subset", + "decl": { + "args": [ + { + "of": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + }, + { + "of": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "any" + }, + "type": "function" + } + }, + { + "name": "object.union", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "result": { + "type": "any" + }, + "type": "function" + } + }, + { + "name": "object.union_n", + "decl": { + "args": [ + { + "dynamic": { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "array" + } + ], + "result": { + "type": "any" + }, + "type": "function" + } + }, + { + "name": "opa.runtime", + "decl": { + "result": { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "function" + }, + "nondeterministic": true + }, + { + "name": "or", + "decl": { + "args": [ + { + "of": { + "type": "any" + }, + "type": "set" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "result": { + "of": { + "type": "any" + }, + "type": "set" + }, + "type": "function" + }, + "infix": "|" + }, + { + "name": "plus", + "decl": { + "args": [ + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + }, + "infix": "+" + }, + { + "name": "print", + "decl": { + "type": "function", + "variadic": { + "type": "any" + } + } + }, + { + "name": "product", + "decl": { + "args": [ + { + "of": [ + { + "dynamic": { + "type": "number" + }, + "type": "array" + }, + { + "of": { + "type": "number" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "providers.aws.sign_req", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "type": "number" + } + ], + "result": { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "function" + } + }, + { + "name": "rand.intn", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + }, + "nondeterministic": true + }, + { + "name": "re_match", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "regex.find_all_string_submatch_n", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + }, + { + "type": "number" + } + ], + "result": { + "dynamic": { + "dynamic": { + "type": "string" + }, + "type": "array" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "regex.find_n", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + }, + { + "type": "number" + } + ], + "result": { + "dynamic": { + "type": "string" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "regex.globs_match", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "regex.is_valid", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "regex.match", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "regex.replace", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "regex.split", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "dynamic": { + "type": "string" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "regex.template_match", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + }, + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "rego.metadata.chain", + "decl": { + "result": { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "rego.metadata.rule", + "decl": { + "result": { + "type": "any" + }, + "type": "function" + } + }, + { + "name": "rego.parse_module", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "function" + } + }, + { + "name": "rem", + "decl": { + "args": [ + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + }, + "infix": "%" + }, + { + "name": "replace", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "round", + "decl": { + "args": [ + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "semver.compare", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "semver.is_valid", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "set_diff", + "decl": { + "args": [ + { + "of": { + "type": "any" + }, + "type": "set" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "result": { + "of": { + "type": "any" + }, + "type": "set" + }, + "type": "function" + } + }, + { + "name": "sort", + "decl": { + "args": [ + { + "of": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "split", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "dynamic": { + "type": "string" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "sprintf", + "decl": { + "args": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "startswith", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "strings.any_prefix_match", + "decl": { + "args": [ + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "string" + }, + "type": "array" + }, + { + "of": { + "type": "string" + }, + "type": "set" + } + ], + "type": "any" + }, + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "string" + }, + "type": "array" + }, + { + "of": { + "type": "string" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "strings.any_suffix_match", + "decl": { + "args": [ + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "string" + }, + "type": "array" + }, + { + "of": { + "type": "string" + }, + "type": "set" + } + ], + "type": "any" + }, + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "string" + }, + "type": "array" + }, + { + "of": { + "type": "string" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "strings.count", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "strings.render_template", + "decl": { + "args": [ + { + "type": "string" + }, + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "strings.replace_n", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "type": "object" + }, + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "strings.reverse", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "substring", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "sum", + "decl": { + "args": [ + { + "of": [ + { + "dynamic": { + "type": "number" + }, + "type": "array" + }, + { + "of": { + "type": "number" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "time.add_date", + "decl": { + "args": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "time.clock", + "decl": { + "args": [ + { + "of": [ + { + "type": "number" + }, + { + "static": [ + { + "type": "number" + }, + { + "type": "string" + } + ], + "type": "array" + } + ], + "type": "any" + } + ], + "result": { + "static": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + } + ], + "type": "array" + }, + "type": "function" + } + }, + { + "name": "time.date", + "decl": { + "args": [ + { + "of": [ + { + "type": "number" + }, + { + "static": [ + { + "type": "number" + }, + { + "type": "string" + } + ], + "type": "array" + } + ], + "type": "any" + } + ], + "result": { + "static": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + } + ], + "type": "array" + }, + "type": "function" + } + }, + { + "name": "time.diff", + "decl": { + "args": [ + { + "of": [ + { + "type": "number" + }, + { + "static": [ + { + "type": "number" + }, + { + "type": "string" + } + ], + "type": "array" + } + ], + "type": "any" + }, + { + "of": [ + { + "type": "number" + }, + { + "static": [ + { + "type": "number" + }, + { + "type": "string" + } + ], + "type": "array" + } + ], + "type": "any" + } + ], + "result": { + "static": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + } + ], + "type": "array" + }, + "type": "function" + } + }, + { + "name": "time.format", + "decl": { + "args": [ + { + "of": [ + { + "type": "number" + }, + { + "static": [ + { + "type": "number" + }, + { + "type": "string" + } + ], + "type": "array" + }, + { + "static": [ + { + "type": "number" + }, + { + "type": "string" + }, + { + "type": "string" + } + ], + "type": "array" + } + ], + "type": "any" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "time.now_ns", + "decl": { + "result": { + "type": "number" + }, + "type": "function" + }, + "nondeterministic": true + }, + { + "name": "time.parse_duration_ns", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "time.parse_ns", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "time.parse_rfc3339_ns", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "time.weekday", + "decl": { + "args": [ + { + "of": [ + { + "type": "number" + }, + { + "static": [ + { + "type": "number" + }, + { + "type": "string" + } + ], + "type": "array" + } + ], + "type": "any" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "to_number", + "decl": { + "args": [ + { + "of": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ], + "type": "any" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "trace", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "trim", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "trim_left", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "trim_prefix", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "trim_right", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "trim_space", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "trim_suffix", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "type_name", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "union", + "decl": { + "args": [ + { + "of": { + "of": { + "type": "any" + }, + "type": "set" + }, + "type": "set" + } + ], + "result": { + "of": { + "type": "any" + }, + "type": "set" + }, + "type": "function" + } + }, + { + "name": "units.parse", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "units.parse_bytes", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "upper", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "urlquery.decode", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "urlquery.decode_object", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "dynamic": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "type": "function" + } + }, + { + "name": "urlquery.encode", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "urlquery.encode_object", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "string" + }, + "type": "array" + }, + { + "of": { + "type": "string" + }, + "type": "set" + } + ], + "type": "any" + } + }, + "type": "object" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "uuid.parse", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "function" + } + }, + { + "name": "uuid.rfc4122", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + }, + "nondeterministic": true + }, + { + "name": "walk", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "static": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "type": "any" + } + ], + "type": "array" + }, + "type": "function" + }, + "relation": true + }, + { + "name": "yaml.is_valid", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "yaml.marshal", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "yaml.unmarshal", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "any" + }, + "type": "function" + } + } + ], + "wasm_abi_versions": [ + { + "version": 1, + "minor_version": 1 + }, + { + "version": 1, + "minor_version": 2 + } + ], + "features": [ + "keywords_in_refs", + "rego_v1" + ] +} diff --git a/vendor/github.com/open-policy-agent/opa/capabilities/v1.9.0.json b/vendor/github.com/open-policy-agent/opa/capabilities/v1.9.0.json new file mode 100644 index 00000000000..0a37621d0c5 --- /dev/null +++ b/vendor/github.com/open-policy-agent/opa/capabilities/v1.9.0.json @@ -0,0 +1,4867 @@ +{ + "builtins": [ + { + "name": "abs", + "decl": { + "args": [ + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "all", + "decl": { + "args": [ + { + "of": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "and", + "decl": { + "args": [ + { + "of": { + "type": "any" + }, + "type": "set" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "result": { + "of": { + "type": "any" + }, + "type": "set" + }, + "type": "function" + }, + "infix": "\u0026" + }, + { + "name": "any", + "decl": { + "args": [ + { + "of": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "array.concat", + "decl": { + "args": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "result": { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "array.reverse", + "decl": { + "args": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "result": { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "array.slice", + "decl": { + "args": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "assign", + "decl": { + "args": [ + { + "type": "any" + }, + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + }, + "infix": ":=" + }, + { + "name": "base64.decode", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "base64.encode", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "base64.is_valid", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "base64url.decode", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "base64url.encode", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "base64url.encode_no_pad", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "bits.and", + "decl": { + "args": [ + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "bits.lsh", + "decl": { + "args": [ + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "bits.negate", + "decl": { + "args": [ + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "bits.or", + "decl": { + "args": [ + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "bits.rsh", + "decl": { + "args": [ + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "bits.xor", + "decl": { + "args": [ + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "cast_array", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "cast_boolean", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "cast_null", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "null" + }, + "type": "function" + } + }, + { + "name": "cast_object", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "function" + } + }, + { + "name": "cast_set", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "of": { + "type": "any" + }, + "type": "set" + }, + "type": "function" + } + }, + { + "name": "cast_string", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "ceil", + "decl": { + "args": [ + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "concat", + "decl": { + "args": [ + { + "type": "string" + }, + { + "of": [ + { + "dynamic": { + "type": "string" + }, + "type": "array" + }, + { + "of": { + "type": "string" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "contains", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "count", + "decl": { + "args": [ + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "crypto.hmac.equal", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "crypto.hmac.md5", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "crypto.hmac.sha1", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "crypto.hmac.sha256", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "crypto.hmac.sha512", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "crypto.md5", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "crypto.parse_private_keys", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "dynamic": { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "crypto.sha1", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "crypto.sha256", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "crypto.x509.parse_and_verify_certificates", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "static": [ + { + "type": "boolean" + }, + { + "dynamic": { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "array" + } + ], + "type": "array" + }, + "type": "function" + } + }, + { + "name": "crypto.x509.parse_and_verify_certificates_with_options", + "decl": { + "args": [ + { + "type": "string" + }, + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "result": { + "static": [ + { + "type": "boolean" + }, + { + "dynamic": { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "array" + } + ], + "type": "array" + }, + "type": "function" + } + }, + { + "name": "crypto.x509.parse_certificate_request", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "function" + } + }, + { + "name": "crypto.x509.parse_certificates", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "dynamic": { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "crypto.x509.parse_keypair", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "function" + } + }, + { + "name": "crypto.x509.parse_rsa_private_key", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "function" + } + }, + { + "name": "div", + "decl": { + "args": [ + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + }, + "infix": "/" + }, + { + "name": "endswith", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "eq", + "decl": { + "args": [ + { + "type": "any" + }, + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + }, + "infix": "=" + }, + { + "name": "equal", + "decl": { + "args": [ + { + "type": "any" + }, + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + }, + "infix": "==" + }, + { + "name": "floor", + "decl": { + "args": [ + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "format_int", + "decl": { + "args": [ + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "glob.match", + "decl": { + "args": [ + { + "type": "string" + }, + { + "of": [ + { + "type": "null" + }, + { + "dynamic": { + "type": "string" + }, + "type": "array" + } + ], + "type": "any" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "glob.quote_meta", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "graph.reachable", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "of": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + }, + "type": "object" + }, + { + "of": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "of": { + "type": "any" + }, + "type": "set" + }, + "type": "function" + } + }, + { + "name": "graph.reachable_paths", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "of": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + }, + "type": "object" + }, + { + "of": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "of": { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + "type": "set" + }, + "type": "function" + } + }, + { + "name": "graphql.is_valid", + "decl": { + "args": [ + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "type": "any" + }, + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "graphql.parse", + "decl": { + "args": [ + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "type": "any" + }, + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "type": "any" + } + ], + "result": { + "static": [ + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "type": "array" + }, + "type": "function" + } + }, + { + "name": "graphql.parse_and_verify", + "decl": { + "args": [ + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "type": "any" + }, + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "type": "any" + } + ], + "result": { + "static": [ + { + "type": "boolean" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "type": "array" + }, + "type": "function" + } + }, + { + "name": "graphql.parse_query", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "function" + } + }, + { + "name": "graphql.parse_schema", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "function" + } + }, + { + "name": "graphql.schema_is_valid", + "decl": { + "args": [ + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "gt", + "decl": { + "args": [ + { + "type": "any" + }, + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + }, + "infix": "\u003e" + }, + { + "name": "gte", + "decl": { + "args": [ + { + "type": "any" + }, + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + }, + "infix": "\u003e=" + }, + { + "name": "hex.decode", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "hex.encode", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "http.send", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "result": { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "function" + }, + "nondeterministic": true + }, + { + "name": "indexof", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "indexof_n", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "dynamic": { + "type": "number" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "internal.member_2", + "decl": { + "args": [ + { + "type": "any" + }, + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + }, + "infix": "in" + }, + { + "name": "internal.member_3", + "decl": { + "args": [ + { + "type": "any" + }, + { + "type": "any" + }, + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + }, + "infix": "in" + }, + { + "name": "internal.print", + "decl": { + "args": [ + { + "dynamic": { + "of": { + "type": "any" + }, + "type": "set" + }, + "type": "array" + } + ], + "type": "function" + } + }, + { + "name": "internal.test_case", + "decl": { + "args": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "type": "function" + } + }, + { + "name": "intersection", + "decl": { + "args": [ + { + "of": { + "of": { + "type": "any" + }, + "type": "set" + }, + "type": "set" + } + ], + "result": { + "of": { + "type": "any" + }, + "type": "set" + }, + "type": "function" + } + }, + { + "name": "io.jwt.decode", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "static": [ + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "type": "string" + } + ], + "type": "array" + }, + "type": "function" + } + }, + { + "name": "io.jwt.decode_verify", + "decl": { + "args": [ + { + "type": "string" + }, + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "result": { + "static": [ + { + "type": "boolean" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "type": "array" + }, + "type": "function" + }, + "nondeterministic": true + }, + { + "name": "io.jwt.encode_sign", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "result": { + "type": "string" + }, + "type": "function" + }, + "nondeterministic": true + }, + { + "name": "io.jwt.encode_sign_raw", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + }, + "nondeterministic": true + }, + { + "name": "io.jwt.verify_eddsa", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "io.jwt.verify_es256", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "io.jwt.verify_es384", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "io.jwt.verify_es512", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "io.jwt.verify_hs256", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "io.jwt.verify_hs384", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "io.jwt.verify_hs512", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "io.jwt.verify_ps256", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "io.jwt.verify_ps384", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "io.jwt.verify_ps512", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "io.jwt.verify_rs256", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "io.jwt.verify_rs384", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "io.jwt.verify_rs512", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "is_array", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "is_boolean", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "is_null", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "is_number", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "is_object", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "is_set", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "is_string", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "json.filter", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "of": [ + { + "dynamic": { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "type": "any" + }, + "type": "array" + }, + { + "of": { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "any" + }, + "type": "function" + } + }, + { + "name": "json.is_valid", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "json.marshal", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "json.marshal_with_options", + "decl": { + "args": [ + { + "type": "any" + }, + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "static": [ + { + "key": "indent", + "value": { + "type": "string" + } + }, + { + "key": "prefix", + "value": { + "type": "string" + } + }, + { + "key": "pretty", + "value": { + "type": "boolean" + } + } + ], + "type": "object" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "json.match_schema", + "decl": { + "args": [ + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "type": "any" + }, + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "type": "any" + } + ], + "result": { + "static": [ + { + "type": "boolean" + }, + { + "dynamic": { + "static": [ + { + "key": "desc", + "value": { + "type": "string" + } + }, + { + "key": "error", + "value": { + "type": "string" + } + }, + { + "key": "field", + "value": { + "type": "string" + } + }, + { + "key": "type", + "value": { + "type": "string" + } + } + ], + "type": "object" + }, + "type": "array" + } + ], + "type": "array" + }, + "type": "function" + } + }, + { + "name": "json.patch", + "decl": { + "args": [ + { + "type": "any" + }, + { + "dynamic": { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "static": [ + { + "key": "op", + "value": { + "type": "string" + } + }, + { + "key": "path", + "value": { + "type": "any" + } + } + ], + "type": "object" + }, + "type": "array" + } + ], + "result": { + "type": "any" + }, + "type": "function" + } + }, + { + "name": "json.remove", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "of": [ + { + "dynamic": { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "type": "any" + }, + "type": "array" + }, + { + "of": { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "any" + }, + "type": "function" + } + }, + { + "name": "json.unmarshal", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "any" + }, + "type": "function" + } + }, + { + "name": "json.verify_schema", + "decl": { + "args": [ + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "type": "any" + } + ], + "result": { + "static": [ + { + "type": "boolean" + }, + { + "of": [ + { + "type": "null" + }, + { + "type": "string" + } + ], + "type": "any" + } + ], + "type": "array" + }, + "type": "function" + } + }, + { + "name": "lower", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "lt", + "decl": { + "args": [ + { + "type": "any" + }, + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + }, + "infix": "\u003c" + }, + { + "name": "lte", + "decl": { + "args": [ + { + "type": "any" + }, + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + }, + "infix": "\u003c=" + }, + { + "name": "max", + "decl": { + "args": [ + { + "of": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "any" + }, + "type": "function" + } + }, + { + "name": "min", + "decl": { + "args": [ + { + "of": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "any" + }, + "type": "function" + } + }, + { + "name": "minus", + "decl": { + "args": [ + { + "of": [ + { + "type": "number" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + }, + { + "of": [ + { + "type": "number" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "of": [ + { + "type": "number" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + }, + "type": "function" + }, + "infix": "-" + }, + { + "name": "mul", + "decl": { + "args": [ + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + }, + "infix": "*" + }, + { + "name": "neq", + "decl": { + "args": [ + { + "type": "any" + }, + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + }, + "infix": "!=" + }, + { + "name": "net.cidr_contains", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "net.cidr_contains_matches", + "decl": { + "args": [ + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "type": "any" + }, + "type": "array" + }, + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "type": "any" + } + }, + "type": "object" + }, + { + "of": { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + }, + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "type": "any" + }, + "type": "array" + }, + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "type": "any" + } + }, + "type": "object" + }, + { + "of": { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "of": { + "static": [ + { + "type": "any" + }, + { + "type": "any" + } + ], + "type": "array" + }, + "type": "set" + }, + "type": "function" + } + }, + { + "name": "net.cidr_expand", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "of": { + "type": "string" + }, + "type": "set" + }, + "type": "function" + } + }, + { + "name": "net.cidr_intersects", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "net.cidr_is_valid", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "net.cidr_merge", + "decl": { + "args": [ + { + "of": [ + { + "dynamic": { + "of": [ + { + "type": "string" + } + ], + "type": "any" + }, + "type": "array" + }, + { + "of": { + "type": "string" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "of": { + "type": "string" + }, + "type": "set" + }, + "type": "function" + } + }, + { + "name": "net.cidr_overlap", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "net.lookup_ip_addr", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "of": { + "type": "string" + }, + "type": "set" + }, + "type": "function" + }, + "nondeterministic": true + }, + { + "name": "numbers.range", + "decl": { + "args": [ + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "dynamic": { + "type": "number" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "numbers.range_step", + "decl": { + "args": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "dynamic": { + "type": "number" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "object.filter", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "of": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "any" + }, + "type": "function" + } + }, + { + "name": "object.get", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "type": "any" + }, + { + "type": "any" + } + ], + "result": { + "type": "any" + }, + "type": "function" + } + }, + { + "name": "object.keys", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "result": { + "of": { + "type": "any" + }, + "type": "set" + }, + "type": "function" + } + }, + { + "name": "object.remove", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "of": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "any" + }, + "type": "function" + } + }, + { + "name": "object.subset", + "decl": { + "args": [ + { + "of": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + }, + { + "of": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "any" + }, + "type": "function" + } + }, + { + "name": "object.union", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "result": { + "type": "any" + }, + "type": "function" + } + }, + { + "name": "object.union_n", + "decl": { + "args": [ + { + "dynamic": { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "array" + } + ], + "result": { + "type": "any" + }, + "type": "function" + } + }, + { + "name": "opa.runtime", + "decl": { + "result": { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "function" + }, + "nondeterministic": true + }, + { + "name": "or", + "decl": { + "args": [ + { + "of": { + "type": "any" + }, + "type": "set" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "result": { + "of": { + "type": "any" + }, + "type": "set" + }, + "type": "function" + }, + "infix": "|" + }, + { + "name": "plus", + "decl": { + "args": [ + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + }, + "infix": "+" + }, + { + "name": "print", + "decl": { + "type": "function", + "variadic": { + "type": "any" + } + } + }, + { + "name": "product", + "decl": { + "args": [ + { + "of": [ + { + "dynamic": { + "type": "number" + }, + "type": "array" + }, + { + "of": { + "type": "number" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "providers.aws.sign_req", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "type": "number" + } + ], + "result": { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "function" + } + }, + { + "name": "rand.intn", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + }, + "nondeterministic": true + }, + { + "name": "re_match", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "regex.find_all_string_submatch_n", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + }, + { + "type": "number" + } + ], + "result": { + "dynamic": { + "dynamic": { + "type": "string" + }, + "type": "array" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "regex.find_n", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + }, + { + "type": "number" + } + ], + "result": { + "dynamic": { + "type": "string" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "regex.globs_match", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "regex.is_valid", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "regex.match", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "regex.replace", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "regex.split", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "dynamic": { + "type": "string" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "regex.template_match", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + }, + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "rego.metadata.chain", + "decl": { + "result": { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "rego.metadata.rule", + "decl": { + "result": { + "type": "any" + }, + "type": "function" + } + }, + { + "name": "rego.parse_module", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "function" + } + }, + { + "name": "rem", + "decl": { + "args": [ + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + }, + "infix": "%" + }, + { + "name": "replace", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "round", + "decl": { + "args": [ + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "semver.compare", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "semver.is_valid", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "set_diff", + "decl": { + "args": [ + { + "of": { + "type": "any" + }, + "type": "set" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "result": { + "of": { + "type": "any" + }, + "type": "set" + }, + "type": "function" + } + }, + { + "name": "sort", + "decl": { + "args": [ + { + "of": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "split", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "dynamic": { + "type": "string" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "sprintf", + "decl": { + "args": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "startswith", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "strings.any_prefix_match", + "decl": { + "args": [ + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "string" + }, + "type": "array" + }, + { + "of": { + "type": "string" + }, + "type": "set" + } + ], + "type": "any" + }, + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "string" + }, + "type": "array" + }, + { + "of": { + "type": "string" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "strings.any_suffix_match", + "decl": { + "args": [ + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "string" + }, + "type": "array" + }, + { + "of": { + "type": "string" + }, + "type": "set" + } + ], + "type": "any" + }, + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "string" + }, + "type": "array" + }, + { + "of": { + "type": "string" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "strings.count", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "strings.render_template", + "decl": { + "args": [ + { + "type": "string" + }, + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "strings.replace_n", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "type": "object" + }, + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "strings.reverse", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "substring", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "sum", + "decl": { + "args": [ + { + "of": [ + { + "dynamic": { + "type": "number" + }, + "type": "array" + }, + { + "of": { + "type": "number" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "time.add_date", + "decl": { + "args": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "time.clock", + "decl": { + "args": [ + { + "of": [ + { + "type": "number" + }, + { + "static": [ + { + "type": "number" + }, + { + "type": "string" + } + ], + "type": "array" + } + ], + "type": "any" + } + ], + "result": { + "static": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + } + ], + "type": "array" + }, + "type": "function" + } + }, + { + "name": "time.date", + "decl": { + "args": [ + { + "of": [ + { + "type": "number" + }, + { + "static": [ + { + "type": "number" + }, + { + "type": "string" + } + ], + "type": "array" + } + ], + "type": "any" + } + ], + "result": { + "static": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + } + ], + "type": "array" + }, + "type": "function" + } + }, + { + "name": "time.diff", + "decl": { + "args": [ + { + "of": [ + { + "type": "number" + }, + { + "static": [ + { + "type": "number" + }, + { + "type": "string" + } + ], + "type": "array" + } + ], + "type": "any" + }, + { + "of": [ + { + "type": "number" + }, + { + "static": [ + { + "type": "number" + }, + { + "type": "string" + } + ], + "type": "array" + } + ], + "type": "any" + } + ], + "result": { + "static": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + } + ], + "type": "array" + }, + "type": "function" + } + }, + { + "name": "time.format", + "decl": { + "args": [ + { + "of": [ + { + "type": "number" + }, + { + "static": [ + { + "type": "number" + }, + { + "type": "string" + } + ], + "type": "array" + }, + { + "static": [ + { + "type": "number" + }, + { + "type": "string" + }, + { + "type": "string" + } + ], + "type": "array" + } + ], + "type": "any" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "time.now_ns", + "decl": { + "result": { + "type": "number" + }, + "type": "function" + }, + "nondeterministic": true + }, + { + "name": "time.parse_duration_ns", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "time.parse_ns", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "time.parse_rfc3339_ns", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "time.weekday", + "decl": { + "args": [ + { + "of": [ + { + "type": "number" + }, + { + "static": [ + { + "type": "number" + }, + { + "type": "string" + } + ], + "type": "array" + } + ], + "type": "any" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "to_number", + "decl": { + "args": [ + { + "of": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ], + "type": "any" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "trace", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "trim", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "trim_left", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "trim_prefix", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "trim_right", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "trim_space", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "trim_suffix", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "type_name", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "union", + "decl": { + "args": [ + { + "of": { + "of": { + "type": "any" + }, + "type": "set" + }, + "type": "set" + } + ], + "result": { + "of": { + "type": "any" + }, + "type": "set" + }, + "type": "function" + } + }, + { + "name": "units.parse", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "units.parse_bytes", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "upper", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "urlquery.decode", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "urlquery.decode_object", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "dynamic": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "type": "function" + } + }, + { + "name": "urlquery.encode", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "urlquery.encode_object", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "string" + }, + "type": "array" + }, + { + "of": { + "type": "string" + }, + "type": "set" + } + ], + "type": "any" + } + }, + "type": "object" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "uuid.parse", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "function" + } + }, + { + "name": "uuid.rfc4122", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + }, + "nondeterministic": true + }, + { + "name": "walk", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "static": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "type": "any" + } + ], + "type": "array" + }, + "type": "function" + }, + "relation": true + }, + { + "name": "yaml.is_valid", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "yaml.marshal", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "yaml.unmarshal", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "any" + }, + "type": "function" + } + } + ], + "wasm_abi_versions": [ + { + "version": 1, + "minor_version": 1 + }, + { + "version": 1, + "minor_version": 2 + } + ], + "features": [ + "keywords_in_refs", + "rego_v1" + ] +} diff --git a/vendor/github.com/open-policy-agent/opa/internal/bundle/utils.go b/vendor/github.com/open-policy-agent/opa/internal/bundle/utils.go index 836aa586b93..98093b774ea 100644 --- a/vendor/github.com/open-policy-agent/opa/internal/bundle/utils.go +++ b/vendor/github.com/open-policy-agent/opa/internal/bundle/utils.go @@ -72,7 +72,7 @@ func LoadWasmResolversFromStore(ctx context.Context, store storage.Store, txn st var resolvers []*wasm.Resolver if len(resolversToLoad) > 0 { // Get a full snapshot of the current data (including any from "outside" the bundles) - data, err := store.Read(ctx, txn, storage.Path{}) + data, err := store.Read(ctx, txn, storage.RootPath) if err != nil { return nil, fmt.Errorf("failed to initialize wasm runtime: %s", err) } diff --git a/vendor/github.com/open-policy-agent/opa/internal/config/config.go b/vendor/github.com/open-policy-agent/opa/internal/config/config.go index d4fae5fa65c..53dfc6d6cb3 100644 --- a/vendor/github.com/open-policy-agent/opa/internal/config/config.go +++ b/vendor/github.com/open-policy-agent/opa/internal/config/config.go @@ -120,8 +120,12 @@ func Load(configFile string, overrides []string, overrideFiles []string) ([]byte // regex looking for ${...} notation strings var envRegex = regexp.MustCompile(`(?U:\${.*})`) -// subEnvVars will look for any environment variables in the passed in string +// SubEnvVars will look for any environment variables in the passed in string // with the syntax of ${VAR_NAME} and replace that string with ENV[VAR_NAME] +func SubEnvVars(s string) string { + return subEnvVars(s) +} + func subEnvVars(s string) string { updatedConfig := envRegex.ReplaceAllStringFunc(s, func(s string) string { // Trim off the '${' and '}' @@ -131,10 +135,14 @@ func subEnvVars(s string) string { } varName := s[2 : len(s)-1] - // Lookup the variable in the environment. We play by - // bash rules.. if its undefined we'll treat it as an - // empty string instead of raising an error. - return os.Getenv(varName) + // Lookup the variable in the environment. We do not + // play by bash rules: if its undefined we'll keep it + // as-is, it could be replaced somewhere down the line. + // If it's set to "", we'll return that. + if lu, ok := os.LookupEnv(varName); ok { + return lu + } + return s }) return updatedConfig diff --git a/vendor/github.com/open-policy-agent/opa/internal/edittree/edittree.go b/vendor/github.com/open-policy-agent/opa/internal/edittree/edittree.go index 1dafc57b0b4..ebfa875d752 100644 --- a/vendor/github.com/open-policy-agent/opa/internal/edittree/edittree.go +++ b/vendor/github.com/open-policy-agent/opa/internal/edittree/edittree.go @@ -148,7 +148,6 @@ package edittree import ( "errors" "fmt" - "math/big" "sort" "strings" @@ -203,89 +202,13 @@ func NewEditTree(term *ast.Term) *EditTree { // it was found in the table already. func (e *EditTree) getKeyHash(key *ast.Term) (int, bool) { hash := key.Hash() - // This `equal` utility is duplicated and manually inlined a number of - // time in this file. Inlining it avoids heap allocations, so it makes - // a big performance difference: some operations like lookup become twice - // as slow without it. - var equal func(v ast.Value) bool - - switch x := key.Value.(type) { - case ast.Null, ast.Boolean, ast.String, ast.Var: - equal = func(y ast.Value) bool { return x == y } - case ast.Number: - if xi, ok := x.Int64(); ok { - equal = func(y ast.Value) bool { - if y, ok := y.(ast.Number); ok { - if yi, ok := y.Int64(); ok { - return xi == yi - } - } - - return false - } - break - } - - // We use big.Rat for comparing big numbers. - // It replaces big.Float due to following reason: - // big.Float comes with a default precision of 64, and setting a - // larger precision results in more memory being allocated - // (regardless of the actual number we are parsing with SetString). - // - // Note: If we're so close to zero that big.Float says we are zero, do - // *not* big.Rat).SetString on the original string it'll potentially - // take very long. - var a *big.Rat - fa, ok := new(big.Float).SetString(string(x)) - if !ok { - panic("illegal value") - } - if fa.IsInt() { - if i, _ := fa.Int64(); i == 0 { - a = new(big.Rat).SetInt64(0) - } - } - if a == nil { - a, ok = new(big.Rat).SetString(string(x)) - if !ok { - panic("illegal value") - } - } - - equal = func(b ast.Value) bool { - if bNum, ok := b.(ast.Number); ok { - var b *big.Rat - fb, ok := new(big.Float).SetString(string(bNum)) - if !ok { - panic("illegal value") - } - if fb.IsInt() { - if i, _ := fb.Int64(); i == 0 { - b = new(big.Rat).SetInt64(0) - } - } - if b == nil { - b, ok = new(big.Rat).SetString(string(bNum)) - if !ok { - panic("illegal value") - } - } - - return a.Cmp(b) == 0 - } - return false - } - - default: - equal = func(y ast.Value) bool { return ast.Compare(x, y) == 0 } - } // Look through childKeys, looking up the original hash // value first, and then use linear-probing to iter // through the keys until we either find the Term we're // after, or run out of candidates. for curr, ok := e.childKeys[hash]; ok; { - if equal(curr.Value) { + if ast.KeyHashEqual(curr.Value, key.Value) { return hash, true } diff --git a/vendor/github.com/open-policy-agent/opa/internal/jwx/buffer/buffer.go b/vendor/github.com/open-policy-agent/opa/internal/jwx/buffer/buffer.go deleted file mode 100644 index c383ff3b549..00000000000 --- a/vendor/github.com/open-policy-agent/opa/internal/jwx/buffer/buffer.go +++ /dev/null @@ -1,112 +0,0 @@ -// Package buffer provides a very thin wrapper around []byte buffer called -// `Buffer`, to provide functionalities that are often used within the jwx -// related packages -package buffer - -import ( - "encoding/base64" - "encoding/binary" - "encoding/json" - "fmt" -) - -// Buffer wraps `[]byte` and provides functions that are often used in -// the jwx related packages. One notable difference is that while -// encoding/json marshalls `[]byte` using base64.StdEncoding, this -// module uses base64.RawURLEncoding as mandated by the spec -type Buffer []byte - -// FromUint creates a `Buffer` from an unsigned int -func FromUint(v uint64) Buffer { - data := make([]byte, 8) - binary.BigEndian.PutUint64(data, v) - - i := 0 - for ; i < len(data); i++ { - if data[i] != 0x0 { - break - } - } - return Buffer(data[i:]) -} - -// FromBase64 constructs a new Buffer from a base64 encoded data -func FromBase64(v []byte) (Buffer, error) { - b := Buffer{} - if err := b.Base64Decode(v); err != nil { - return Buffer(nil), fmt.Errorf("failed to decode from base64: %w", err) - } - - return b, nil -} - -// FromNData constructs a new Buffer from a "n:data" format -// (I made that name up) -func FromNData(v []byte) (Buffer, error) { - size := binary.BigEndian.Uint32(v) - buf := make([]byte, int(size)) - copy(buf, v[4:4+size]) - return Buffer(buf), nil -} - -// Bytes returns the raw bytes that comprises the Buffer -func (b Buffer) Bytes() []byte { - return []byte(b) -} - -// NData returns Datalen || Data, where Datalen is a 32 bit counter for -// the length of the following data, and Data is the octets that comprise -// the buffer data -func (b Buffer) NData() []byte { - buf := make([]byte, 4+b.Len()) - binary.BigEndian.PutUint32(buf, uint32(b.Len())) - - copy(buf[4:], b.Bytes()) - return buf -} - -// Len returns the number of bytes that the Buffer holds -func (b Buffer) Len() int { - return len(b) -} - -// Base64Encode encodes the contents of the Buffer using base64.RawURLEncoding -func (b Buffer) Base64Encode() ([]byte, error) { - enc := base64.RawURLEncoding - out := make([]byte, enc.EncodedLen(len(b))) - enc.Encode(out, b) - return out, nil -} - -// Base64Decode decodes the contents of the Buffer using base64.RawURLEncoding -func (b *Buffer) Base64Decode(v []byte) error { - enc := base64.RawURLEncoding - out := make([]byte, enc.DecodedLen(len(v))) - n, err := enc.Decode(out, v) - if err != nil { - return fmt.Errorf("failed to decode from base64: %w", err) - } - out = out[:n] - *b = Buffer(out) - return nil -} - -// MarshalJSON marshals the buffer into JSON format after encoding the buffer -// with base64.RawURLEncoding -func (b Buffer) MarshalJSON() ([]byte, error) { - v, err := b.Base64Encode() - if err != nil { - return nil, fmt.Errorf("failed to encode to base64: %w", err) - } - return json.Marshal(string(v)) -} - -// UnmarshalJSON unmarshals from a JSON string into a Buffer, after decoding it -// with base64.RawURLEncoding -func (b *Buffer) UnmarshalJSON(data []byte) error { - var x string - if err := json.Unmarshal(data, &x); err != nil { - return fmt.Errorf("failed to unmarshal JSON: %w", err) - } - return b.Base64Decode([]byte(x)) -} diff --git a/vendor/github.com/open-policy-agent/opa/internal/jwx/jwa/elliptic.go b/vendor/github.com/open-policy-agent/opa/internal/jwx/jwa/elliptic.go deleted file mode 100644 index b7e35dc707b..00000000000 --- a/vendor/github.com/open-policy-agent/opa/internal/jwx/jwa/elliptic.go +++ /dev/null @@ -1,11 +0,0 @@ -package jwa - -// EllipticCurveAlgorithm represents the algorithms used for EC keys -type EllipticCurveAlgorithm string - -// Supported values for EllipticCurveAlgorithm -const ( - P256 EllipticCurveAlgorithm = "P-256" - P384 EllipticCurveAlgorithm = "P-384" - P521 EllipticCurveAlgorithm = "P-521" -) diff --git a/vendor/github.com/open-policy-agent/opa/internal/jwx/jwa/key_type.go b/vendor/github.com/open-policy-agent/opa/internal/jwx/jwa/key_type.go deleted file mode 100644 index 61d23844a17..00000000000 --- a/vendor/github.com/open-policy-agent/opa/internal/jwx/jwa/key_type.go +++ /dev/null @@ -1,67 +0,0 @@ -package jwa - -import ( - "errors" - "fmt" - "strconv" -) - -// KeyType represents the key type ("kty") that are supported -type KeyType string - -var keyTypeAlg = map[string]struct{}{"EC": {}, "oct": {}, "RSA": {}} - -// Supported values for KeyType -const ( - EC KeyType = "EC" // Elliptic Curve - InvalidKeyType KeyType = "" // Invalid KeyType - OctetSeq KeyType = "oct" // Octet sequence (used to represent symmetric keys) - RSA KeyType = "RSA" // RSA -) - -// Accept is used when conversion from values given by -// outside sources (such as JSON payloads) is required -func (keyType *KeyType) Accept(value any) error { - var tmp KeyType - switch x := value.(type) { - case string: - tmp = KeyType(x) - case KeyType: - tmp = x - default: - return fmt.Errorf("invalid type for jwa.KeyType: %T", value) - } - _, ok := keyTypeAlg[tmp.String()] - if !ok { - return errors.New("unknown Key Type algorithm") - } - - *keyType = tmp - return nil -} - -// String returns the string representation of a KeyType -func (keyType KeyType) String() string { - return string(keyType) -} - -// UnmarshalJSON unmarshals and checks data as KeyType Algorithm -func (keyType *KeyType) UnmarshalJSON(data []byte) error { - var quote byte = '"' - var quoted string - if data[0] == quote { - var err error - quoted, err = strconv.Unquote(string(data)) - if err != nil { - return fmt.Errorf("failed to process signature algorithm: %w", err) - } - } else { - quoted = string(data) - } - _, ok := keyTypeAlg[quoted] - if !ok { - return errors.New("unknown signature algorithm") - } - *keyType = KeyType(quoted) - return nil -} diff --git a/vendor/github.com/open-policy-agent/opa/internal/jwx/jwa/parameters.go b/vendor/github.com/open-policy-agent/opa/internal/jwx/jwa/parameters.go deleted file mode 100644 index 2fe72e1dbcc..00000000000 --- a/vendor/github.com/open-policy-agent/opa/internal/jwx/jwa/parameters.go +++ /dev/null @@ -1,29 +0,0 @@ -package jwa - -import ( - "crypto/elliptic" - - "github.com/open-policy-agent/opa/internal/jwx/buffer" -) - -// EllipticCurve provides a indirect type to standard elliptic curve such that we can -// use it for unmarshal -type EllipticCurve struct { - elliptic.Curve -} - -// AlgorithmParameters provides a single structure suitable to unmarshaling any JWK -type AlgorithmParameters struct { - N buffer.Buffer `json:"n,omitempty"` - E buffer.Buffer `json:"e,omitempty"` - D buffer.Buffer `json:"d,omitempty"` - P buffer.Buffer `json:"p,omitempty"` - Q buffer.Buffer `json:"q,omitempty"` - Dp buffer.Buffer `json:"dp,omitempty"` - Dq buffer.Buffer `json:"dq,omitempty"` - Qi buffer.Buffer `json:"qi,omitempty"` - Crv EllipticCurveAlgorithm `json:"crv,omitempty"` - X buffer.Buffer `json:"x,omitempty"` - Y buffer.Buffer `json:"y,omitempty"` - K buffer.Buffer `json:"k,omitempty"` -} diff --git a/vendor/github.com/open-policy-agent/opa/internal/jwx/jwa/signature.go b/vendor/github.com/open-policy-agent/opa/internal/jwx/jwa/signature.go deleted file mode 100644 index c601c46ea9a..00000000000 --- a/vendor/github.com/open-policy-agent/opa/internal/jwx/jwa/signature.go +++ /dev/null @@ -1,78 +0,0 @@ -package jwa - -import ( - "errors" - "fmt" - "strconv" -) - -// SignatureAlgorithm represents the various signature algorithms as described in https://tools.ietf.org/html/rfc7518#section-3.1 -type SignatureAlgorithm string - -var signatureAlg = map[string]struct{}{"ES256": {}, "ES384": {}, "ES512": {}, "HS256": {}, "HS384": {}, "HS512": {}, "PS256": {}, "PS384": {}, "PS512": {}, "RS256": {}, "RS384": {}, "RS512": {}, "none": {}} - -// Supported values for SignatureAlgorithm -const ( - ES256 SignatureAlgorithm = "ES256" // ECDSA using P-256 and SHA-256 - ES384 SignatureAlgorithm = "ES384" // ECDSA using P-384 and SHA-384 - ES512 SignatureAlgorithm = "ES512" // ECDSA using P-521 and SHA-512 - HS256 SignatureAlgorithm = "HS256" // HMAC using SHA-256 - HS384 SignatureAlgorithm = "HS384" // HMAC using SHA-384 - HS512 SignatureAlgorithm = "HS512" // HMAC using SHA-512 - NoSignature SignatureAlgorithm = "none" - PS256 SignatureAlgorithm = "PS256" // RSASSA-PSS using SHA256 and MGF1-SHA256 - PS384 SignatureAlgorithm = "PS384" // RSASSA-PSS using SHA384 and MGF1-SHA384 - PS512 SignatureAlgorithm = "PS512" // RSASSA-PSS using SHA512 and MGF1-SHA512 - RS256 SignatureAlgorithm = "RS256" // RSASSA-PKCS-v1.5 using SHA-256 - RS384 SignatureAlgorithm = "RS384" // RSASSA-PKCS-v1.5 using SHA-384 - RS512 SignatureAlgorithm = "RS512" // RSASSA-PKCS-v1.5 using SHA-512 - NoValue SignatureAlgorithm = "" // No value is different from none - Unsupported SignatureAlgorithm = "unsupported" -) - -// Accept is used when conversion from values given by -// outside sources (such as JSON payloads) is required -func (signature *SignatureAlgorithm) Accept(value any) error { - var tmp SignatureAlgorithm - switch x := value.(type) { - case string: - tmp = SignatureAlgorithm(x) - case SignatureAlgorithm: - tmp = x - default: - return fmt.Errorf("invalid type for jwa.SignatureAlgorithm: %T", value) - } - _, ok := signatureAlg[tmp.String()] - if !ok { - return errors.New("unknown signature algorithm") - } - *signature = tmp - return nil -} - -// String returns the string representation of a SignatureAlgorithm -func (signature SignatureAlgorithm) String() string { - return string(signature) -} - -// UnmarshalJSON unmarshals and checks data as Signature Algorithm -func (signature *SignatureAlgorithm) UnmarshalJSON(data []byte) error { - var quote byte = '"' - var quoted string - if data[0] == quote { - var err error - quoted, err = strconv.Unquote(string(data)) - if err != nil { - return fmt.Errorf("failed to process signature algorithm: %w", err) - } - } else { - quoted = string(data) - } - _, ok := signatureAlg[quoted] - if !ok { - *signature = Unsupported - return nil - } - *signature = SignatureAlgorithm(quoted) - return nil -} diff --git a/vendor/github.com/open-policy-agent/opa/internal/jwx/jwk/ecdsa.go b/vendor/github.com/open-policy-agent/opa/internal/jwx/jwk/ecdsa.go deleted file mode 100644 index 0677f4dc30f..00000000000 --- a/vendor/github.com/open-policy-agent/opa/internal/jwx/jwk/ecdsa.go +++ /dev/null @@ -1,120 +0,0 @@ -package jwk - -import ( - "crypto/ecdsa" - "crypto/elliptic" - "errors" - "fmt" - "math/big" - - "github.com/open-policy-agent/opa/internal/jwx/jwa" -) - -func newECDSAPublicKey(key *ecdsa.PublicKey) (*ECDSAPublicKey, error) { - - var hdr StandardHeaders - err := hdr.Set(KeyTypeKey, jwa.EC) - if err != nil { - return nil, fmt.Errorf("failed to set Key Type: %w", err) - } - - return &ECDSAPublicKey{ - StandardHeaders: &hdr, - key: key, - }, nil -} - -func newECDSAPrivateKey(key *ecdsa.PrivateKey) (*ECDSAPrivateKey, error) { - - var hdr StandardHeaders - err := hdr.Set(KeyTypeKey, jwa.EC) - if err != nil { - return nil, fmt.Errorf("failed to set Key Type: %w", err) - } - - return &ECDSAPrivateKey{ - StandardHeaders: &hdr, - key: key, - }, nil -} - -// Materialize returns the EC-DSA public key represented by this JWK -func (k ECDSAPublicKey) Materialize() (any, error) { - return k.key, nil -} - -// Materialize returns the EC-DSA private key represented by this JWK -func (k ECDSAPrivateKey) Materialize() (any, error) { - return k.key, nil -} - -// GenerateKey creates a ECDSAPublicKey from JWK format -func (k *ECDSAPublicKey) GenerateKey(keyJSON *RawKeyJSON) error { - - var x, y big.Int - - if keyJSON.X == nil || keyJSON.Y == nil || keyJSON.Crv == "" { - return errors.New("missing mandatory key parameters X, Y or Crv") - } - - x.SetBytes(keyJSON.X.Bytes()) - y.SetBytes(keyJSON.Y.Bytes()) - - var curve elliptic.Curve - switch keyJSON.Crv { - case jwa.P256: - curve = elliptic.P256() - case jwa.P384: - curve = elliptic.P384() - case jwa.P521: - curve = elliptic.P521() - default: - return fmt.Errorf("invalid curve name %s", keyJSON.Crv) - } - - *k = ECDSAPublicKey{ - StandardHeaders: &keyJSON.StandardHeaders, - key: &ecdsa.PublicKey{ - Curve: curve, - X: &x, - Y: &y, - }, - } - return nil -} - -// GenerateKey creates a ECDSAPrivateKey from JWK format -func (k *ECDSAPrivateKey) GenerateKey(keyJSON *RawKeyJSON) error { - - if keyJSON.D == nil { - return errors.New("missing mandatory key parameter D") - } - eCDSAPublicKey := &ECDSAPublicKey{} - err := eCDSAPublicKey.GenerateKey(keyJSON) - if err != nil { - return fmt.Errorf("failed to generate public key: %w", err) - } - dBytes := keyJSON.D.Bytes() - // The length of this octet string MUST be ceiling(log-base-2(n)/8) - // octets (where n is the order of the curve). This is because the private - // key d must be in the interval [1, n-1] so the bitlength of d should be - // no larger than the bitlength of n-1. The easiest way to find the octet - // length is to take bitlength(n-1), add 7 to force a carry, and shift this - // bit sequence right by 3, which is essentially dividing by 8 and adding - // 1 if there is any remainder. Thus, the private key value d should be - // output to (bitlength(n-1)+7)>>3 octets. - n := eCDSAPublicKey.key.Params().N - octetLength := (new(big.Int).Sub(n, big.NewInt(1)).BitLen() + 7) >> 3 - if octetLength-len(dBytes) != 0 { - return errors.New("failed to generate private key. Incorrect D value") - } - privateKey := &ecdsa.PrivateKey{ - PublicKey: *eCDSAPublicKey.key, - D: (&big.Int{}).SetBytes(keyJSON.D.Bytes()), - } - - k.key = privateKey - k.StandardHeaders = &keyJSON.StandardHeaders - - return nil -} diff --git a/vendor/github.com/open-policy-agent/opa/internal/jwx/jwk/headers.go b/vendor/github.com/open-policy-agent/opa/internal/jwx/jwk/headers.go deleted file mode 100644 index b1a6763dda0..00000000000 --- a/vendor/github.com/open-policy-agent/opa/internal/jwx/jwk/headers.go +++ /dev/null @@ -1,178 +0,0 @@ -package jwk - -import ( - "fmt" - - "github.com/open-policy-agent/opa/internal/jwx/jwa" -) - -// Convenience constants for common JWK parameters -const ( - AlgorithmKey = "alg" - KeyIDKey = "kid" - KeyOpsKey = "key_ops" - KeyTypeKey = "kty" - KeyUsageKey = "use" - PrivateParamsKey = "privateParams" -) - -// Headers provides a common interface to all future possible headers -type Headers interface { - Get(string) (any, bool) - Set(string, any) error - Walk(func(string, any) error) error - GetAlgorithm() jwa.SignatureAlgorithm - GetKeyID() string - GetKeyOps() KeyOperationList - GetKeyType() jwa.KeyType - GetKeyUsage() string - GetPrivateParams() map[string]any -} - -// StandardHeaders stores the common JWK parameters -type StandardHeaders struct { - Algorithm *jwa.SignatureAlgorithm `json:"alg,omitempty"` // https://tools.ietf.org/html/rfc7517#section-4.4 - KeyID string `json:"kid,omitempty"` // https://tools.ietf.org/html/rfc7515#section-4.1.4 - KeyOps KeyOperationList `json:"key_ops,omitempty"` // https://tools.ietf.org/html/rfc7517#section-4.3 - KeyType jwa.KeyType `json:"kty,omitempty"` // https://tools.ietf.org/html/rfc7517#section-4.1 - KeyUsage string `json:"use,omitempty"` // https://tools.ietf.org/html/rfc7517#section-4.2 - PrivateParams map[string]any `json:"privateParams,omitempty"` // https://tools.ietf.org/html/rfc7515#section-4.1.4 -} - -// GetAlgorithm is a convenience function to retrieve the corresponding value stored in the StandardHeaders -func (h *StandardHeaders) GetAlgorithm() jwa.SignatureAlgorithm { - if v := h.Algorithm; v != nil { - return *v - } - return jwa.NoValue -} - -// GetKeyID is a convenience function to retrieve the corresponding value stored in the StandardHeaders -func (h *StandardHeaders) GetKeyID() string { - return h.KeyID -} - -// GetKeyOps is a convenience function to retrieve the corresponding value stored in the StandardHeaders -func (h *StandardHeaders) GetKeyOps() KeyOperationList { - return h.KeyOps -} - -// GetKeyType is a convenience function to retrieve the corresponding value stored in the StandardHeaders -func (h *StandardHeaders) GetKeyType() jwa.KeyType { - return h.KeyType -} - -// GetKeyUsage is a convenience function to retrieve the corresponding value stored in the StandardHeaders -func (h *StandardHeaders) GetKeyUsage() string { - return h.KeyUsage -} - -// GetPrivateParams is a convenience function to retrieve the corresponding value stored in the StandardHeaders -func (h *StandardHeaders) GetPrivateParams() map[string]any { - return h.PrivateParams -} - -// Get is a general getter function for JWK StandardHeaders structure -func (h *StandardHeaders) Get(name string) (any, bool) { - switch name { - case AlgorithmKey: - alg := h.GetAlgorithm() - if alg != jwa.NoValue { - return alg, true - } - return nil, false - case KeyIDKey: - v := h.KeyID - if v == "" { - return nil, false - } - return v, true - case KeyOpsKey: - v := h.KeyOps - if v == nil { - return nil, false - } - return v, true - case KeyTypeKey: - v := h.KeyType - if v == jwa.InvalidKeyType { - return nil, false - } - return v, true - case KeyUsageKey: - v := h.KeyUsage - if v == "" { - return nil, false - } - return v, true - case PrivateParamsKey: - v := h.PrivateParams - if len(v) == 0 { - return nil, false - } - return v, true - default: - return nil, false - } -} - -// Set is a general getter function for JWK StandardHeaders structure -func (h *StandardHeaders) Set(name string, value any) error { - switch name { - case AlgorithmKey: - var acceptor jwa.SignatureAlgorithm - if err := acceptor.Accept(value); err != nil { - return fmt.Errorf("invalid value for %s key: %w", AlgorithmKey, err) - } - h.Algorithm = &acceptor - return nil - case KeyIDKey: - if v, ok := value.(string); ok { - h.KeyID = v - return nil - } - return fmt.Errorf("invalid value for %s key: %T", KeyIDKey, value) - case KeyOpsKey: - if err := h.KeyOps.Accept(value); err != nil { - return fmt.Errorf("invalid value for %s key: %w", KeyOpsKey, err) - } - return nil - case KeyTypeKey: - if err := h.KeyType.Accept(value); err != nil { - return fmt.Errorf("invalid value for %s key: %w", KeyTypeKey, err) - } - return nil - case KeyUsageKey: - if v, ok := value.(string); ok { - h.KeyUsage = v - return nil - } - return fmt.Errorf("invalid value for %s key: %T", KeyUsageKey, value) - case PrivateParamsKey: - if v, ok := value.(map[string]any); ok { - h.PrivateParams = v - return nil - } - return fmt.Errorf("invalid value for %s key: %T", PrivateParamsKey, value) - default: - return fmt.Errorf("invalid key: %s", name) - } -} - -// Walk iterates over all JWK standard headers fields while applying a function to its value. -func (h StandardHeaders) Walk(f func(string, any) error) error { - for _, key := range []string{AlgorithmKey, KeyIDKey, KeyOpsKey, KeyTypeKey, KeyUsageKey, PrivateParamsKey} { - if v, ok := h.Get(key); ok { - if err := f(key, v); err != nil { - return fmt.Errorf("walk function returned error for %s: %w", key, err) - } - } - } - - for k, v := range h.PrivateParams { - if err := f(k, v); err != nil { - return fmt.Errorf("walk function returned error for %s: %w", k, err) - } - } - return nil -} diff --git a/vendor/github.com/open-policy-agent/opa/internal/jwx/jwk/interface.go b/vendor/github.com/open-policy-agent/opa/internal/jwx/jwk/interface.go deleted file mode 100644 index 9c7846269e0..00000000000 --- a/vendor/github.com/open-policy-agent/opa/internal/jwx/jwk/interface.go +++ /dev/null @@ -1,71 +0,0 @@ -package jwk - -import ( - "crypto/ecdsa" - "crypto/rsa" - - "github.com/open-policy-agent/opa/internal/jwx/jwa" -) - -// Set is a convenience struct to allow generating and parsing -// JWK sets as opposed to single JWKs -type Set struct { - Keys []Key `json:"keys"` -} - -// Key defines the minimal interface for each of the -// key types. Their use and implementation differ significantly -// between each key types, so you should use type assertions -// to perform more specific tasks with each key -type Key interface { - Headers - - // Materialize creates the corresponding key. For example, - // RSA types would create *rsa.PublicKey or *rsa.PrivateKey, - // EC types would create *ecdsa.PublicKey or *ecdsa.PrivateKey, - // and OctetSeq types create a []byte key. - Materialize() (any, error) - GenerateKey(*RawKeyJSON) error -} - -// RawKeyJSON is generic type that represents any kind JWK -type RawKeyJSON struct { - StandardHeaders - jwa.AlgorithmParameters -} - -// RawKeySetJSON is generic type that represents a JWK Set -type RawKeySetJSON struct { - Keys []RawKeyJSON `json:"keys"` -} - -// RSAPublicKey is a type of JWK generated from RSA public keys -type RSAPublicKey struct { - *StandardHeaders - key *rsa.PublicKey -} - -// RSAPrivateKey is a type of JWK generated from RSA private keys -type RSAPrivateKey struct { - *StandardHeaders - *jwa.AlgorithmParameters - key *rsa.PrivateKey -} - -// SymmetricKey is a type of JWK generated from symmetric keys -type SymmetricKey struct { - *StandardHeaders - key []byte -} - -// ECDSAPublicKey is a type of JWK generated from ECDSA public keys -type ECDSAPublicKey struct { - *StandardHeaders - key *ecdsa.PublicKey -} - -// ECDSAPrivateKey is a type of JWK generated from ECDH-ES private keys -type ECDSAPrivateKey struct { - *StandardHeaders - key *ecdsa.PrivateKey -} diff --git a/vendor/github.com/open-policy-agent/opa/internal/jwx/jwk/jwk.go b/vendor/github.com/open-policy-agent/opa/internal/jwx/jwk/jwk.go deleted file mode 100644 index b13245d1728..00000000000 --- a/vendor/github.com/open-policy-agent/opa/internal/jwx/jwk/jwk.go +++ /dev/null @@ -1,153 +0,0 @@ -// Package jwk implements JWK as described in https://tools.ietf.org/html/rfc7517 -package jwk - -import ( - "crypto/ecdsa" - "crypto/rsa" - "encoding/json" - "errors" - "fmt" - - "github.com/open-policy-agent/opa/internal/jwx/jwa" -) - -// GetPublicKey returns the public key based on the private key type. -// For rsa key types *rsa.PublicKey is returned; for ecdsa key types *ecdsa.PublicKey; -// for byte slice (raw) keys, the key itself is returned. If the corresponding -// public key cannot be deduced, an error is returned -func GetPublicKey(key any) (any, error) { - if key == nil { - return nil, errors.New("jwk.New requires a non-nil key") - } - - switch v := key.(type) { - // Mental note: although Public() is defined in both types, - // you can not coalesce the clauses for rsa.PrivateKey and - // ecdsa.PrivateKey, as then `v` becomes any - // b/c the compiler cannot deduce the exact type. - case *rsa.PrivateKey: - return v.Public(), nil - case *ecdsa.PrivateKey: - return v.Public(), nil - case []byte: - return v, nil - default: - return nil, fmt.Errorf("invalid key type %T", key) - } -} - -// GetKeyTypeFromKey creates a jwk.Key from the given key. -func GetKeyTypeFromKey(key any) jwa.KeyType { - - switch key.(type) { - case *rsa.PrivateKey, *rsa.PublicKey: - return jwa.RSA - case *ecdsa.PrivateKey, *ecdsa.PublicKey: - return jwa.EC - case []byte: - return jwa.OctetSeq - default: - return jwa.InvalidKeyType - } -} - -// New creates a jwk.Key from the given key. -func New(key any) (Key, error) { - if key == nil { - return nil, errors.New("jwk.New requires a non-nil key") - } - - switch v := key.(type) { - case *rsa.PrivateKey: - return newRSAPrivateKey(v) - case *rsa.PublicKey: - return newRSAPublicKey(v) - case *ecdsa.PrivateKey: - return newECDSAPrivateKey(v) - case *ecdsa.PublicKey: - return newECDSAPublicKey(v) - case []byte: - return newSymmetricKey(v) - default: - return nil, fmt.Errorf("invalid key type %T", key) - } -} - -func parse(jwkSrc string) (*Set, error) { - - var jwkKeySet Set - var jwkKey Key - rawKeySetJSON := &RawKeySetJSON{} - err := json.Unmarshal([]byte(jwkSrc), rawKeySetJSON) - if err != nil { - return nil, fmt.Errorf("failed to unmarshal JWK Set: %w", err) - } - if len(rawKeySetJSON.Keys) == 0 { - - // It might be a single key - rawKeyJSON := &RawKeyJSON{} - err := json.Unmarshal([]byte(jwkSrc), rawKeyJSON) - if err != nil { - return nil, fmt.Errorf("failed to unmarshal JWK: %w", err) - } - jwkKey, err = rawKeyJSON.GenerateKey() - if err != nil { - return nil, fmt.Errorf("failed to generate key: %w", err) - } - // Add to set - jwkKeySet.Keys = append(jwkKeySet.Keys, jwkKey) - } else { - for i := range rawKeySetJSON.Keys { - rawKeyJSON := rawKeySetJSON.Keys[i] - if rawKeyJSON.Algorithm != nil && *rawKeyJSON.Algorithm == jwa.Unsupported { - continue - } - jwkKey, err = rawKeyJSON.GenerateKey() - if err != nil { - return nil, fmt.Errorf("failed to generate key: %w", err) - } - jwkKeySet.Keys = append(jwkKeySet.Keys, jwkKey) - } - } - return &jwkKeySet, nil -} - -// ParseBytes parses JWK from the incoming byte buffer. -func ParseBytes(buf []byte) (*Set, error) { - return parse(string(buf)) -} - -// ParseString parses JWK from the incoming string. -func ParseString(s string) (*Set, error) { - return parse(s) -} - -// GenerateKey creates an internal representation of a key from a raw JWK JSON -func (r *RawKeyJSON) GenerateKey() (Key, error) { - - var key Key - - switch r.KeyType { - case jwa.RSA: - if r.D != nil { - key = &RSAPrivateKey{} - } else { - key = &RSAPublicKey{} - } - case jwa.EC: - if r.D != nil { - key = &ECDSAPrivateKey{} - } else { - key = &ECDSAPublicKey{} - } - case jwa.OctetSeq: - key = &SymmetricKey{} - default: - return nil, errors.New("unrecognized key type") - } - err := key.GenerateKey(r) - if err != nil { - return nil, fmt.Errorf("failed to generate key from JWK: %w", err) - } - return key, nil -} diff --git a/vendor/github.com/open-policy-agent/opa/internal/jwx/jwk/key_ops.go b/vendor/github.com/open-policy-agent/opa/internal/jwx/jwk/key_ops.go deleted file mode 100644 index 628caae4ad5..00000000000 --- a/vendor/github.com/open-policy-agent/opa/internal/jwx/jwk/key_ops.go +++ /dev/null @@ -1,67 +0,0 @@ -package jwk - -import ( - "encoding/json" - "errors" - "fmt" -) - -// KeyUsageType is used to denote what this key should be used for -type KeyUsageType string - -const ( - // ForSignature is the value used in the headers to indicate that - // this key should be used for signatures - ForSignature KeyUsageType = "sig" - // ForEncryption is the value used in the headers to indicate that - // this key should be used for encryptiong - ForEncryption KeyUsageType = "enc" -) - -// KeyOperation is used to denote the allowed operations for a Key -type KeyOperation string - -// KeyOperationList represents an slice of KeyOperation -type KeyOperationList []KeyOperation - -var keyOps = map[string]struct{}{"sign": {}, "verify": {}, "encrypt": {}, "decrypt": {}, "wrapKey": {}, "unwrapKey": {}, "deriveKey": {}, "deriveBits": {}} - -// KeyOperation constants -const ( - KeyOpSign KeyOperation = "sign" // (compute digital signature or MAC) - KeyOpVerify KeyOperation = "verify" // (verify digital signature or MAC) - KeyOpEncrypt KeyOperation = "encrypt" // (encrypt content) - KeyOpDecrypt KeyOperation = "decrypt" // (decrypt content and validate decryption, if applicable) - KeyOpWrapKey KeyOperation = "wrapKey" // (encrypt key) - KeyOpUnwrapKey KeyOperation = "unwrapKey" // (decrypt key and validate decryption, if applicable) - KeyOpDeriveKey KeyOperation = "deriveKey" // (derive key) - KeyOpDeriveBits KeyOperation = "deriveBits" // (derive bits not to be used as a key) -) - -// Accept determines if Key Operation is valid -func (keyOperationList *KeyOperationList) Accept(v any) error { - switch x := v.(type) { - case KeyOperationList: - *keyOperationList = x - return nil - default: - return fmt.Errorf(`invalid value %T`, v) - } -} - -// UnmarshalJSON unmarshals and checks data as KeyType Algorithm -func (keyOperationList *KeyOperationList) UnmarshalJSON(data []byte) error { - var tempKeyOperationList []string - err := json.Unmarshal(data, &tempKeyOperationList) - if err != nil { - return errors.New("invalid key operation") - } - for _, value := range tempKeyOperationList { - _, ok := keyOps[value] - if !ok { - return errors.New("unknown key operation") - } - *keyOperationList = append(*keyOperationList, KeyOperation(value)) - } - return nil -} diff --git a/vendor/github.com/open-policy-agent/opa/internal/jwx/jwk/rsa.go b/vendor/github.com/open-policy-agent/opa/internal/jwx/jwk/rsa.go deleted file mode 100644 index d7b5089418f..00000000000 --- a/vendor/github.com/open-policy-agent/opa/internal/jwx/jwk/rsa.go +++ /dev/null @@ -1,133 +0,0 @@ -package jwk - -import ( - "crypto/rsa" - "encoding/binary" - "errors" - "fmt" - "math/big" - - "github.com/open-policy-agent/opa/internal/jwx/jwa" -) - -func newRSAPublicKey(key *rsa.PublicKey) (*RSAPublicKey, error) { - - var hdr StandardHeaders - err := hdr.Set(KeyTypeKey, jwa.RSA) - if err != nil { - return nil, fmt.Errorf("failed to set Key Type: %w", err) - } - return &RSAPublicKey{ - StandardHeaders: &hdr, - key: key, - }, nil -} - -func newRSAPrivateKey(key *rsa.PrivateKey) (*RSAPrivateKey, error) { - - var hdr StandardHeaders - err := hdr.Set(KeyTypeKey, jwa.RSA) - if err != nil { - return nil, fmt.Errorf("failed to set Key Type: %w", err) - } - - var algoParams jwa.AlgorithmParameters - - // it is needed to use raw encoding to omit the "=" paddings at the end - algoParams.D = key.D.Bytes() - algoParams.P = key.Primes[0].Bytes() - algoParams.Q = key.Primes[1].Bytes() - algoParams.Dp = key.Precomputed.Dp.Bytes() - algoParams.Dq = key.Precomputed.Dq.Bytes() - algoParams.Qi = key.Precomputed.Qinv.Bytes() - - // "modulus" (N) from the public key in the private key - algoParams.N = key.PublicKey.N.Bytes() - - // make the E a.k.a "coprime" - // https://en.wikipedia.org/wiki/RSA_(cryptosystem) - coprime := make([]byte, 8) - binary.BigEndian.PutUint64(coprime, uint64(key.PublicKey.E)) - // find the 1st index of non 0x0 paddings from the beginning - i := 0 - for ; i < len(coprime); i++ { - if coprime[i] != 0x0 { - break - } - } - algoParams.E = coprime[i:] - - return &RSAPrivateKey{ - StandardHeaders: &hdr, - AlgorithmParameters: &algoParams, - key: key, - }, nil -} - -// Materialize returns the standard RSA Public Key representation stored in the internal representation -func (k *RSAPublicKey) Materialize() (any, error) { - if k.key == nil { - return nil, errors.New("key has no rsa.PublicKey associated with it") - } - return k.key, nil -} - -// Materialize returns the standard RSA Private Key representation stored in the internal representation -func (k *RSAPrivateKey) Materialize() (any, error) { - if k.key == nil { - return nil, errors.New("key has no rsa.PrivateKey associated with it") - } - return k.key, nil -} - -// GenerateKey creates a RSAPublicKey from a RawKeyJSON -func (k *RSAPublicKey) GenerateKey(keyJSON *RawKeyJSON) error { - - if keyJSON.N == nil || keyJSON.E == nil { - return errors.New("missing mandatory key parameters N or E") - } - rsaPublicKey := &rsa.PublicKey{ - N: (&big.Int{}).SetBytes(keyJSON.N.Bytes()), - E: int((&big.Int{}).SetBytes(keyJSON.E.Bytes()).Int64()), - } - k.key = rsaPublicKey - k.StandardHeaders = &keyJSON.StandardHeaders - return nil -} - -// GenerateKey creates a RSAPublicKey from a RawKeyJSON -func (k *RSAPrivateKey) GenerateKey(keyJSON *RawKeyJSON) error { - - rsaPublicKey := &RSAPublicKey{} - err := rsaPublicKey.GenerateKey(keyJSON) - if err != nil { - return fmt.Errorf("failed to generate public key: %w", err) - } - - if keyJSON.D == nil || keyJSON.P == nil || keyJSON.Q == nil { - return errors.New("missing mandatory key parameters D, P or Q") - } - privateKey := &rsa.PrivateKey{ - PublicKey: *rsaPublicKey.key, - D: (&big.Int{}).SetBytes(keyJSON.D.Bytes()), - Primes: []*big.Int{ - (&big.Int{}).SetBytes(keyJSON.P.Bytes()), - (&big.Int{}).SetBytes(keyJSON.Q.Bytes()), - }, - } - - if keyJSON.Dp.Len() > 0 { - privateKey.Precomputed.Dp = (&big.Int{}).SetBytes(keyJSON.Dp.Bytes()) - } - if keyJSON.Dq.Len() > 0 { - privateKey.Precomputed.Dq = (&big.Int{}).SetBytes(keyJSON.Dq.Bytes()) - } - if keyJSON.Qi.Len() > 0 { - privateKey.Precomputed.Qinv = (&big.Int{}).SetBytes(keyJSON.Qi.Bytes()) - } - - k.key = privateKey - k.StandardHeaders = &keyJSON.StandardHeaders - k.AlgorithmParameters = &keyJSON.AlgorithmParameters - return nil -} diff --git a/vendor/github.com/open-policy-agent/opa/internal/jwx/jwk/symmetric.go b/vendor/github.com/open-policy-agent/opa/internal/jwx/jwk/symmetric.go deleted file mode 100644 index e76189f523e..00000000000 --- a/vendor/github.com/open-policy-agent/opa/internal/jwx/jwk/symmetric.go +++ /dev/null @@ -1,41 +0,0 @@ -package jwk - -import ( - "fmt" - - "github.com/open-policy-agent/opa/internal/jwx/jwa" -) - -func newSymmetricKey(key []byte) (*SymmetricKey, error) { - var hdr StandardHeaders - - err := hdr.Set(KeyTypeKey, jwa.OctetSeq) - if err != nil { - return nil, fmt.Errorf("failed to set Key Type: %w", err) - } - return &SymmetricKey{ - StandardHeaders: &hdr, - key: key, - }, nil -} - -// Materialize returns the octets for this symmetric key. -// Since this is a symmetric key, this just calls Octets -func (s SymmetricKey) Materialize() (any, error) { - return s.Octets(), nil -} - -// Octets returns the octets in the key -func (s SymmetricKey) Octets() []byte { - return s.key -} - -// GenerateKey creates a Symmetric key from a RawKeyJSON -func (s *SymmetricKey) GenerateKey(keyJSON *RawKeyJSON) error { - - *s = SymmetricKey{ - StandardHeaders: &keyJSON.StandardHeaders, - key: keyJSON.K, - } - return nil -} diff --git a/vendor/github.com/open-policy-agent/opa/internal/jwx/jws/headers.go b/vendor/github.com/open-policy-agent/opa/internal/jwx/jws/headers.go deleted file mode 100644 index dcadea43e23..00000000000 --- a/vendor/github.com/open-policy-agent/opa/internal/jwx/jws/headers.go +++ /dev/null @@ -1,154 +0,0 @@ -package jws - -import ( - "fmt" - - "github.com/open-policy-agent/opa/internal/jwx/jwa" -) - -// Constants for JWS Common parameters -const ( - AlgorithmKey = "alg" - ContentTypeKey = "cty" - CriticalKey = "crit" - JWKKey = "jwk" - JWKSetURLKey = "jku" - KeyIDKey = "kid" - PrivateParamsKey = "privateParams" - TypeKey = "typ" -) - -// Headers provides a common interface for common header parameters -type Headers interface { - Get(string) (any, bool) - Set(string, any) error - GetAlgorithm() jwa.SignatureAlgorithm -} - -// StandardHeaders contains JWS common parameters. -type StandardHeaders struct { - Algorithm jwa.SignatureAlgorithm `json:"alg,omitempty"` // https://tools.ietf.org/html/rfc7515#section-4.1.1 - ContentType string `json:"cty,omitempty"` // https://tools.ietf.org/html/rfc7515#section-4.1.10 - Critical []string `json:"crit,omitempty"` // https://tools.ietf.org/html/rfc7515#section-4.1.11 - JWK string `json:"jwk,omitempty"` // https://tools.ietf.org/html/rfc7515#section-4.1.3 - JWKSetURL string `json:"jku,omitempty"` // https://tools.ietf.org/html/rfc7515#section-4.1.2 - KeyID string `json:"kid,omitempty"` // https://tools.ietf.org/html/rfc7515#section-4.1.4 - PrivateParams map[string]any `json:"privateParams,omitempty"` // https://tools.ietf.org/html/rfc7515#section-4.1.9 - Type string `json:"typ,omitempty"` // https://tools.ietf.org/html/rfc7515#section-4.1.9 -} - -// GetAlgorithm returns algorithm -func (h *StandardHeaders) GetAlgorithm() jwa.SignatureAlgorithm { - return h.Algorithm -} - -// Get is a general getter function for StandardHeaders structure -func (h *StandardHeaders) Get(name string) (any, bool) { - switch name { - case AlgorithmKey: - v := h.Algorithm - if v == "" { - return nil, false - } - return v, true - case ContentTypeKey: - v := h.ContentType - if v == "" { - return nil, false - } - return v, true - case CriticalKey: - v := h.Critical - if len(v) == 0 { - return nil, false - } - return v, true - case JWKKey: - v := h.JWK - if v == "" { - return nil, false - } - return v, true - case JWKSetURLKey: - v := h.JWKSetURL - if v == "" { - return nil, false - } - return v, true - case KeyIDKey: - v := h.KeyID - if v == "" { - return nil, false - } - return v, true - case PrivateParamsKey: - v := h.PrivateParams - if len(v) == 0 { - return nil, false - } - return v, true - case TypeKey: - v := h.Type - if v == "" { - return nil, false - } - return v, true - default: - return nil, false - } -} - -// Set is a general setter function for StandardHeaders structure -func (h *StandardHeaders) Set(name string, value any) error { - switch name { - case AlgorithmKey: - if err := h.Algorithm.Accept(value); err != nil { - return fmt.Errorf("invalid value for %s key: %w", AlgorithmKey, err) - } - return nil - case ContentTypeKey: - if v, ok := value.(string); ok { - h.ContentType = v - return nil - } - return fmt.Errorf("invalid value for %s key: %T", ContentTypeKey, value) - case CriticalKey: - if v, ok := value.([]string); ok { - h.Critical = v - return nil - } - return fmt.Errorf("invalid value for %s key: %T", CriticalKey, value) - case JWKKey: - if v, ok := value.(string); ok { - h.JWK = v - return nil - } - return fmt.Errorf("invalid value for %s key: %T", JWKKey, value) - case JWKSetURLKey: - if v, ok := value.(string); ok { - h.JWKSetURL = v - return nil - } - return fmt.Errorf("invalid value for %s key: %T", JWKSetURLKey, value) - case KeyIDKey: - if v, ok := value.(string); ok { - h.KeyID = v - return nil - } - return fmt.Errorf("invalid value for %s key: %T", KeyIDKey, value) - case PrivateParamsKey: - if v, ok := value.(map[string]any); ok { - h.PrivateParams = v - return nil - } - return fmt.Errorf("invalid value for %s key: %T", PrivateParamsKey, value) - case TypeKey: - if v, ok := value.(string); ok { - h.Type = v - return nil - } - return fmt.Errorf("invalid value for %s key: %T", TypeKey, value) - default: - return fmt.Errorf("invalid key: %s", name) - } -} diff --git a/vendor/github.com/open-policy-agent/opa/internal/jwx/jws/interface.go b/vendor/github.com/open-policy-agent/opa/internal/jwx/jws/interface.go deleted file mode 100644 index e647c8ac937..00000000000 --- a/vendor/github.com/open-policy-agent/opa/internal/jwx/jws/interface.go +++ /dev/null @@ -1,22 +0,0 @@ -package jws - -// Message represents a full JWS encoded message. Flattened serialization -// is not supported as a struct, but rather it's represented as a -// Message struct with only one `Signature` element. -// -// Do not expect to use the Message object to verify or construct a -// signed payloads with. You should only use this when you want to actually -// want to programmatically view the contents for the full JWS Payload. -// -// To sign and verify, use the appropriate `SignWithOption()` nad `Verify()` functions -type Message struct { - Payload []byte `json:"payload"` - Signatures []*Signature `json:"signatures,omitempty"` -} - -// Signature represents the headers and signature of a JWS message -type Signature struct { - Headers Headers `json:"header,omitempty"` // Unprotected Headers - Protected Headers `json:"Protected,omitempty"` // Protected Headers - Signature []byte `json:"signature,omitempty"` // GetSignature -} diff --git a/vendor/github.com/open-policy-agent/opa/internal/jwx/jws/jws.go b/vendor/github.com/open-policy-agent/opa/internal/jwx/jws/jws.go deleted file mode 100644 index b2b22483061..00000000000 --- a/vendor/github.com/open-policy-agent/opa/internal/jwx/jws/jws.go +++ /dev/null @@ -1,220 +0,0 @@ -// Package jws implements the digital Signature on JSON based data -// structures as described in https://tools.ietf.org/html/rfc7515 -// -// If you do not care about the details, the only things that you -// would need to use are the following functions: -// -// jws.SignWithOption(Payload, algorithm, key) -// jws.Verify(encodedjws, algorithm, key) -// -// To sign, simply use `jws.SignWithOption`. `Payload` is a []byte buffer that -// contains whatever data you want to sign. `alg` is one of the -// jwa.SignatureAlgorithm constants from package jwa. For RSA and -// ECDSA family of algorithms, you will need to prepare a private key. -// For HMAC family, you just need a []byte value. The `jws.SignWithOption` -// function will return the encoded JWS message on success. -// -// To verify, use `jws.Verify`. It will parse the `encodedjws` buffer -// and verify the result using `algorithm` and `key`. Upon successful -// verification, the original Payload is returned, so you can work on it. -package jws - -import ( - "bytes" - "crypto/rand" - "encoding/base64" - "encoding/json" - "errors" - "fmt" - "io" - "strings" - - "github.com/open-policy-agent/opa/internal/jwx/jwa" - "github.com/open-policy-agent/opa/internal/jwx/jwk" - "github.com/open-policy-agent/opa/internal/jwx/jws/sign" - "github.com/open-policy-agent/opa/internal/jwx/jws/verify" -) - -// SignLiteral generates a Signature for the given Payload and Headers, and serializes -// it in compact serialization format. In this format you may NOT use -// multiple signers. -func SignLiteral(payload []byte, alg jwa.SignatureAlgorithm, key any, hdrBuf []byte, rnd io.Reader) ([]byte, error) { - encodedHdr := base64.RawURLEncoding.EncodeToString(hdrBuf) - encodedPayload := base64.RawURLEncoding.EncodeToString(payload) - signingInput := strings.Join( - []string{ - encodedHdr, - encodedPayload, - }, ".", - ) - signer, err := sign.New(alg) - if err != nil { - return nil, fmt.Errorf("failed to create signer: %w", err) - } - - var signature []byte - switch s := signer.(type) { - case *sign.ECDSASigner: - signature, err = s.SignWithRand([]byte(signingInput), key, rnd) - default: - signature, err = signer.Sign([]byte(signingInput), key) - } - if err != nil { - return nil, fmt.Errorf("failed to sign Payload: %w", err) - } - encodedSignature := base64.RawURLEncoding.EncodeToString(signature) - compactSerialization := strings.Join( - []string{ - signingInput, - encodedSignature, - }, ".", - ) - return []byte(compactSerialization), nil -} - -// SignWithOption generates a Signature for the given Payload, and serializes -// it in compact serialization format. In this format you may NOT use -// multiple signers. -// -// If you would like to pass custom Headers, use the WithHeaders option. -func SignWithOption(payload []byte, alg jwa.SignatureAlgorithm, key any) ([]byte, error) { - var headers Headers = &StandardHeaders{} - - err := headers.Set(AlgorithmKey, alg) - if err != nil { - return nil, fmt.Errorf("failed to set alg value: %w", err) - } - - hdrBuf, err := json.Marshal(headers) - if err != nil { - return nil, fmt.Errorf("failed to marshal Headers: %w", err) - } - // NOTE(sr): we don't use SignWithOption -- if we did, this rand.Reader - // should come from the BuiltinContext's Seed, too. - return SignLiteral(payload, alg, key, hdrBuf, rand.Reader) -} - -// Verify checks if the given JWS message is verifiable using `alg` and `key`. -// If the verification is successful, `err` is nil, and the content of the -// Payload that was signed is returned. If you need more fine-grained -// control of the verification process, manually call `Parse`, generate a -// verifier, and call `Verify` on the parsed JWS message object. -func Verify(buf []byte, alg jwa.SignatureAlgorithm, key any) (ret []byte, err error) { - - verifier, err := verify.New(alg) - if err != nil { - return nil, fmt.Errorf("failed to create verifier: %w", err) - } - - buf = bytes.TrimSpace(buf) - if len(buf) == 0 { - return nil, errors.New(`attempt to verify empty buffer`) - } - - parts, err := SplitCompact(string(buf)) - if err != nil { - return nil, fmt.Errorf("failed extract from compact serialization format: %w", err) - } - - signingInput := strings.Join( - []string{ - parts[0], - parts[1], - }, ".", - ) - - decodedSignature, err := base64.RawURLEncoding.DecodeString(parts[2]) - if err != nil { - return nil, fmt.Errorf("failed to decode signature: %w", err) - } - if err := verifier.Verify([]byte(signingInput), decodedSignature, key); err != nil { - return nil, fmt.Errorf("failed to verify message: %w", err) - } - - if decodedPayload, err := base64.RawURLEncoding.DecodeString(parts[1]); err == nil { - return decodedPayload, nil - } - return nil, fmt.Errorf("failed to decode Payload: %w", err) -} - -// VerifyWithJWK verifies the JWS message using the specified JWK -func VerifyWithJWK(buf []byte, key jwk.Key) (payload []byte, err error) { - - keyVal, err := key.Materialize() - if err != nil { - return nil, fmt.Errorf("failed to materialize key: %w", err) - } - return Verify(buf, key.GetAlgorithm(), keyVal) -} - -// VerifyWithJWKSet verifies the JWS message using JWK key set. -// By default it will only pick up keys that have the "use" key -// set to either "sig" or "enc", but you can override it by -// providing a keyaccept function. -func VerifyWithJWKSet(buf []byte, keyset *jwk.Set) (payload []byte, err error) { - - for _, key := range keyset.Keys { - payload, err := VerifyWithJWK(buf, key) - if err == nil { - return payload, nil - } - } - return nil, errors.New("failed to verify with any of the keys") -} - -// ParseByte parses a JWS value serialized via compact serialization and provided as []byte. -func ParseByte(jwsCompact []byte) (m *Message, err error) { - return parseCompact(string(jwsCompact)) -} - -// ParseString parses a JWS value serialized via compact serialization and provided as string. -func ParseString(s string) (*Message, error) { - return parseCompact(s) -} - -// SplitCompact splits a JWT and returns its three parts -// separately: Protected Headers, Payload and Signature. -func SplitCompact(jwsCompact string) ([]string, error) { - - parts := strings.Split(jwsCompact, ".") - if len(parts) < 3 { - return nil, errors.New("failed to split compact serialization") - } - return parts, nil -} - -// parseCompact parses a JWS value serialized via compact serialization. -func parseCompact(str string) (m *Message, err error) { - - var decodedHeader, decodedPayload, decodedSignature []byte - parts, err := SplitCompact(str) - if err != nil { - return nil, fmt.Errorf("invalid compact serialization format: %w", err) - } - - if decodedHeader, err = base64.RawURLEncoding.DecodeString(parts[0]); err != nil { - return nil, fmt.Errorf("failed to decode Headers: %w", err) - } - var hdr StandardHeaders - if err := json.Unmarshal(decodedHeader, &hdr); err != nil { - return nil, fmt.Errorf("failed to parse JOSE Headers: %w", err) - } - - if decodedPayload, err = base64.RawURLEncoding.DecodeString(parts[1]); err != nil { - return nil, fmt.Errorf("failed to decode Payload: %w", err) - } - - if len(parts) > 2 { - if decodedSignature, err = base64.RawURLEncoding.DecodeString(parts[2]); err != nil { - return nil, fmt.Errorf("failed to decode Signature: %w", err) - } - } - - var msg Message - msg.Payload = decodedPayload - msg.Signatures = append(msg.Signatures, &Signature{ - Protected: &hdr, - Signature: decodedSignature, - }) - return &msg, nil -} diff --git a/vendor/github.com/open-policy-agent/opa/internal/jwx/jws/message.go b/vendor/github.com/open-policy-agent/opa/internal/jwx/jws/message.go deleted file mode 100644 index 1366a3d7be9..00000000000 --- a/vendor/github.com/open-policy-agent/opa/internal/jwx/jws/message.go +++ /dev/null @@ -1,26 +0,0 @@ -package jws - -// PublicHeaders returns the public headers in a JWS -func (s Signature) PublicHeaders() Headers { - return s.Headers -} - -// ProtectedHeaders returns the protected headers in a JWS -func (s Signature) ProtectedHeaders() Headers { - return s.Protected -} - -// GetSignature returns the signature in a JWS -func (s Signature) GetSignature() []byte { - return s.Signature -} - -// GetPayload returns the payload in a JWS -func (m Message) GetPayload() []byte { - return m.Payload -} - -// GetSignatures returns the all signatures in a JWS -func (m Message) GetSignatures() []*Signature { - return m.Signatures -} diff --git a/vendor/github.com/open-policy-agent/opa/internal/jwx/jws/sign/ecdsa.go b/vendor/github.com/open-policy-agent/opa/internal/jwx/jws/sign/ecdsa.go deleted file mode 100644 index 5f3e8accad5..00000000000 --- a/vendor/github.com/open-policy-agent/opa/internal/jwx/jws/sign/ecdsa.go +++ /dev/null @@ -1,90 +0,0 @@ -package sign - -import ( - "crypto" - "crypto/ecdsa" - "crypto/rand" - "errors" - "fmt" - "io" - - "github.com/open-policy-agent/opa/internal/jwx/jwa" -) - -var ecdsaSignFuncs = map[jwa.SignatureAlgorithm]ecdsaSignFunc{} - -func init() { - algs := map[jwa.SignatureAlgorithm]crypto.Hash{ - jwa.ES256: crypto.SHA256, - jwa.ES384: crypto.SHA384, - jwa.ES512: crypto.SHA512, - } - - for alg, h := range algs { - ecdsaSignFuncs[alg] = makeECDSASignFunc(h) - } -} - -func makeECDSASignFunc(hash crypto.Hash) ecdsaSignFunc { - return ecdsaSignFunc(func(payload []byte, key *ecdsa.PrivateKey, rnd io.Reader) ([]byte, error) { - curveBits := key.Curve.Params().BitSize - keyBytes := curveBits / 8 - // Curve bits do not need to be a multiple of 8. - if curveBits%8 > 0 { - keyBytes++ - } - h := hash.New() - h.Write(payload) - r, s, err := ecdsa.Sign(rnd, key, h.Sum(nil)) - if err != nil { - return nil, fmt.Errorf("failed to sign payload using ecdsa: %w", err) - } - - rBytes := r.Bytes() - rBytesPadded := make([]byte, keyBytes) - copy(rBytesPadded[keyBytes-len(rBytes):], rBytes) - - sBytes := s.Bytes() - sBytesPadded := make([]byte, keyBytes) - copy(sBytesPadded[keyBytes-len(sBytes):], sBytes) - - out := append(rBytesPadded, sBytesPadded...) - return out, nil - }) -} - -func newECDSA(alg jwa.SignatureAlgorithm) (*ECDSASigner, error) { - signfn, ok := ecdsaSignFuncs[alg] - if !ok { - return nil, fmt.Errorf("unsupported algorithm while trying to create ECDSA signer: %s", alg) - } - - return &ECDSASigner{ - alg: alg, - sign: signfn, - }, nil -} - -// Algorithm returns the signer algorithm -func (s ECDSASigner) Algorithm() jwa.SignatureAlgorithm { - return s.alg -} - -// SignWithRand signs payload with a ECDSA private key and a provided randomness -// source (such as `rand.Reader`). -func (s ECDSASigner) SignWithRand(payload []byte, key any, r io.Reader) ([]byte, error) { - if key == nil { - return nil, errors.New("missing private key while signing payload") - } - - privateKey, ok := key.(*ecdsa.PrivateKey) - if !ok { - return nil, fmt.Errorf("invalid key type %T. *ecdsa.PrivateKey is required", key) - } - return s.sign(payload, privateKey, r) -} - -// Sign signs payload with a ECDSA private key -func (s ECDSASigner) Sign(payload []byte, key any) ([]byte, error) { - return s.SignWithRand(payload, key, rand.Reader) -} diff --git a/vendor/github.com/open-policy-agent/opa/internal/jwx/jws/sign/hmac.go b/vendor/github.com/open-policy-agent/opa/internal/jwx/jws/sign/hmac.go deleted file mode 100644 index de541755ef6..00000000000 --- a/vendor/github.com/open-policy-agent/opa/internal/jwx/jws/sign/hmac.go +++ /dev/null @@ -1,66 +0,0 @@ -package sign - -import ( - "crypto/hmac" - "crypto/sha256" - "crypto/sha512" - "errors" - "fmt" - "hash" - - "github.com/open-policy-agent/opa/internal/jwx/jwa" -) - -var hmacSignFuncs = map[jwa.SignatureAlgorithm]hmacSignFunc{} - -func init() { - algs := map[jwa.SignatureAlgorithm]func() hash.Hash{ - jwa.HS256: sha256.New, - jwa.HS384: sha512.New384, - jwa.HS512: sha512.New, - } - - for alg, h := range algs { - hmacSignFuncs[alg] = makeHMACSignFunc(h) - - } -} - -func newHMAC(alg jwa.SignatureAlgorithm) (*HMACSigner, error) { - signer, ok := hmacSignFuncs[alg] - if !ok { - return nil, fmt.Errorf(`unsupported algorithm while trying to create HMAC signer: %s`, alg) - } - - return &HMACSigner{ - alg: alg, - sign: signer, - }, nil -} - -func makeHMACSignFunc(hfunc func() hash.Hash) hmacSignFunc { - return hmacSignFunc(func(payload []byte, key []byte) ([]byte, error) { - h := hmac.New(hfunc, key) - h.Write(payload) - return h.Sum(nil), nil - }) -} - -// Algorithm returns the signer algorithm -func (s HMACSigner) Algorithm() jwa.SignatureAlgorithm { - return s.alg -} - -// Sign signs payload with a Symmetric key -func (s HMACSigner) Sign(payload []byte, key any) ([]byte, error) { - hmackey, ok := key.([]byte) - if !ok { - return nil, fmt.Errorf(`invalid key type %T. []byte is required`, key) - } - - if len(hmackey) == 0 { - return nil, errors.New(`missing key while signing payload`) - } - - return s.sign(payload, hmackey) -} diff --git a/vendor/github.com/open-policy-agent/opa/internal/jwx/jws/sign/interface.go b/vendor/github.com/open-policy-agent/opa/internal/jwx/jws/sign/interface.go deleted file mode 100644 index 25b592ed4e4..00000000000 --- a/vendor/github.com/open-policy-agent/opa/internal/jwx/jws/sign/interface.go +++ /dev/null @@ -1,46 +0,0 @@ -package sign - -import ( - "crypto/ecdsa" - "crypto/rsa" - "io" - - "github.com/open-policy-agent/opa/internal/jwx/jwa" -) - -// Signer provides a common interface for supported alg signing methods -type Signer interface { - // Sign creates a signature for the given `payload`. - // `key` is the key used for signing the payload, and is usually - // the private key type associated with the signature method. For example, - // for `jwa.RSXXX` and `jwa.PSXXX` types, you need to pass the - // `*"crypto/rsa".PrivateKey` type. - // Check the documentation for each signer for details - Sign(payload []byte, key any) ([]byte, error) - - Algorithm() jwa.SignatureAlgorithm -} - -type rsaSignFunc func([]byte, *rsa.PrivateKey) ([]byte, error) - -// RSASigner uses crypto/rsa to sign the payloads. -type RSASigner struct { - alg jwa.SignatureAlgorithm - sign rsaSignFunc -} - -type ecdsaSignFunc func([]byte, *ecdsa.PrivateKey, io.Reader) ([]byte, error) - -// ECDSASigner uses crypto/ecdsa to sign the payloads. -type ECDSASigner struct { - alg jwa.SignatureAlgorithm - sign ecdsaSignFunc -} - -type hmacSignFunc func([]byte, []byte) ([]byte, error) - -// HMACSigner uses crypto/hmac to sign the payloads. -type HMACSigner struct { - alg jwa.SignatureAlgorithm - sign hmacSignFunc -} diff --git a/vendor/github.com/open-policy-agent/opa/internal/jwx/jws/sign/rsa.go b/vendor/github.com/open-policy-agent/opa/internal/jwx/jws/sign/rsa.go deleted file mode 100644 index a671b7318ad..00000000000 --- a/vendor/github.com/open-policy-agent/opa/internal/jwx/jws/sign/rsa.go +++ /dev/null @@ -1,97 +0,0 @@ -package sign - -import ( - "crypto" - "crypto/rand" - "crypto/rsa" - "errors" - "fmt" - - "github.com/open-policy-agent/opa/internal/jwx/jwa" -) - -var rsaSignFuncs = map[jwa.SignatureAlgorithm]rsaSignFunc{} - -func init() { - algs := map[jwa.SignatureAlgorithm]struct { - Hash crypto.Hash - SignFunc func(crypto.Hash) rsaSignFunc - }{ - jwa.RS256: { - Hash: crypto.SHA256, - SignFunc: makeSignPKCS1v15, - }, - jwa.RS384: { - Hash: crypto.SHA384, - SignFunc: makeSignPKCS1v15, - }, - jwa.RS512: { - Hash: crypto.SHA512, - SignFunc: makeSignPKCS1v15, - }, - jwa.PS256: { - Hash: crypto.SHA256, - SignFunc: makeSignPSS, - }, - jwa.PS384: { - Hash: crypto.SHA384, - SignFunc: makeSignPSS, - }, - jwa.PS512: { - Hash: crypto.SHA512, - SignFunc: makeSignPSS, - }, - } - - for alg, item := range algs { - rsaSignFuncs[alg] = item.SignFunc(item.Hash) - } -} - -func makeSignPKCS1v15(hash crypto.Hash) rsaSignFunc { - return rsaSignFunc(func(payload []byte, key *rsa.PrivateKey) ([]byte, error) { - h := hash.New() - h.Write(payload) - return rsa.SignPKCS1v15(rand.Reader, key, hash, h.Sum(nil)) - }) -} - -func makeSignPSS(hash crypto.Hash) rsaSignFunc { - return rsaSignFunc(func(payload []byte, key *rsa.PrivateKey) ([]byte, error) { - h := hash.New() - h.Write(payload) - return rsa.SignPSS(rand.Reader, key, hash, h.Sum(nil), &rsa.PSSOptions{ - SaltLength: rsa.PSSSaltLengthAuto, - }) - }) -} - -func newRSA(alg jwa.SignatureAlgorithm) (*RSASigner, error) { - signfn, ok := rsaSignFuncs[alg] - if !ok { - return nil, fmt.Errorf(`unsupported algorithm while trying to create RSA signer: %s`, alg) - } - return &RSASigner{ - alg: alg, - sign: signfn, - }, nil -} - -// Algorithm returns the signer algorithm -func (s RSASigner) Algorithm() jwa.SignatureAlgorithm { - return s.alg -} - -// Sign creates a signature using crypto/rsa. key must be a non-nil instance of -// `*"crypto/rsa".PrivateKey`. -func (s RSASigner) Sign(payload []byte, key any) ([]byte, error) { - if key == nil { - return nil, errors.New(`missing private key while signing payload`) - } - rsakey, ok := key.(*rsa.PrivateKey) - if !ok { - return nil, fmt.Errorf(`invalid key type %T. *rsa.PrivateKey is required`, key) - } - - return s.sign(payload, rsakey) -} diff --git a/vendor/github.com/open-policy-agent/opa/internal/jwx/jws/sign/sign.go b/vendor/github.com/open-policy-agent/opa/internal/jwx/jws/sign/sign.go deleted file mode 100644 index c1432236fb7..00000000000 --- a/vendor/github.com/open-policy-agent/opa/internal/jwx/jws/sign/sign.go +++ /dev/null @@ -1,66 +0,0 @@ -package sign - -import ( - "crypto/x509" - "encoding/pem" - "errors" - "fmt" - - "github.com/open-policy-agent/opa/internal/jwx/jwa" -) - -// New creates a signer that signs payloads using the given signature algorithm. -func New(alg jwa.SignatureAlgorithm) (Signer, error) { - switch alg { - case jwa.RS256, jwa.RS384, jwa.RS512, jwa.PS256, jwa.PS384, jwa.PS512: - return newRSA(alg) - case jwa.ES256, jwa.ES384, jwa.ES512: - return newECDSA(alg) - case jwa.HS256, jwa.HS384, jwa.HS512: - return newHMAC(alg) - default: - return nil, fmt.Errorf(`unsupported signature algorithm %s`, alg) - } -} - -// GetSigningKey returns a *rsa.PrivateKey or *ecdsa.PrivateKey typically encoded in PEM blocks of type "RSA PRIVATE KEY" -// or "EC PRIVATE KEY" for RSA and ECDSA family of algorithms. -// For HMAC family, it return a []byte value -func GetSigningKey(key string, alg jwa.SignatureAlgorithm) (any, error) { - switch alg { - case jwa.RS256, jwa.RS384, jwa.RS512, jwa.PS256, jwa.PS384, jwa.PS512: - block, _ := pem.Decode([]byte(key)) - if block == nil { - return nil, errors.New("failed to parse PEM block containing the key") - } - - priv, err := x509.ParsePKCS1PrivateKey(block.Bytes) - if err != nil { - pkcs8priv, err2 := x509.ParsePKCS8PrivateKey(block.Bytes) - if err2 != nil { - return nil, fmt.Errorf("error parsing private key (%v), (%v)", err, err2) - } - return pkcs8priv, nil - } - return priv, nil - case jwa.ES256, jwa.ES384, jwa.ES512: - block, _ := pem.Decode([]byte(key)) - if block == nil { - return nil, errors.New("failed to parse PEM block containing the key") - } - - priv, err := x509.ParseECPrivateKey(block.Bytes) - if err != nil { - pkcs8priv, err2 := x509.ParsePKCS8PrivateKey(block.Bytes) - if err2 != nil { - return nil, fmt.Errorf("error parsing private key (%v), (%v)", err, err2) - } - return pkcs8priv, nil - } - return priv, nil - case jwa.HS256, jwa.HS384, jwa.HS512: - return []byte(key), nil - default: - return nil, fmt.Errorf("unsupported signature algorithm: %s", alg) - } -} diff --git a/vendor/github.com/open-policy-agent/opa/internal/jwx/jws/verify/ecdsa.go b/vendor/github.com/open-policy-agent/opa/internal/jwx/jws/verify/ecdsa.go deleted file mode 100644 index ba32078ac9e..00000000000 --- a/vendor/github.com/open-policy-agent/opa/internal/jwx/jws/verify/ecdsa.go +++ /dev/null @@ -1,67 +0,0 @@ -package verify - -import ( - "crypto" - "crypto/ecdsa" - "errors" - "fmt" - "math/big" - - "github.com/open-policy-agent/opa/internal/jwx/jwa" -) - -var ecdsaVerifyFuncs = map[jwa.SignatureAlgorithm]ecdsaVerifyFunc{} - -func init() { - algs := map[jwa.SignatureAlgorithm]crypto.Hash{ - jwa.ES256: crypto.SHA256, - jwa.ES384: crypto.SHA384, - jwa.ES512: crypto.SHA512, - } - - for alg, h := range algs { - ecdsaVerifyFuncs[alg] = makeECDSAVerifyFunc(h) - } -} - -func makeECDSAVerifyFunc(hash crypto.Hash) ecdsaVerifyFunc { - return ecdsaVerifyFunc(func(payload []byte, signature []byte, key *ecdsa.PublicKey) error { - - r, s := &big.Int{}, &big.Int{} - n := len(signature) / 2 - r.SetBytes(signature[:n]) - s.SetBytes(signature[n:]) - - h := hash.New() - h.Write(payload) - - if !ecdsa.Verify(key, h.Sum(nil), r, s) { - return errors.New(`failed to verify signature using ecdsa`) - } - return nil - }) -} - -func newECDSA(alg jwa.SignatureAlgorithm) (*ECDSAVerifier, error) { - verifyfn, ok := ecdsaVerifyFuncs[alg] - if !ok { - return nil, fmt.Errorf(`unsupported algorithm while trying to create ECDSA verifier: %s`, alg) - } - - return &ECDSAVerifier{ - verify: verifyfn, - }, nil -} - -// Verify checks whether the signature for a given input and key is correct -func (v ECDSAVerifier) Verify(payload []byte, signature []byte, key any) error { - if key == nil { - return errors.New(`missing public key while verifying payload`) - } - ecdsakey, ok := key.(*ecdsa.PublicKey) - if !ok { - return fmt.Errorf(`invalid key type %T. *ecdsa.PublicKey is required`, key) - } - - return v.verify(payload, signature, ecdsakey) -} diff --git a/vendor/github.com/open-policy-agent/opa/internal/jwx/jws/verify/hmac.go b/vendor/github.com/open-policy-agent/opa/internal/jwx/jws/verify/hmac.go deleted file mode 100644 index 25651a0f8d2..00000000000 --- a/vendor/github.com/open-policy-agent/opa/internal/jwx/jws/verify/hmac.go +++ /dev/null @@ -1,33 +0,0 @@ -package verify - -import ( - "crypto/hmac" - "errors" - "fmt" - - "github.com/open-policy-agent/opa/internal/jwx/jwa" - "github.com/open-policy-agent/opa/internal/jwx/jws/sign" -) - -func newHMAC(alg jwa.SignatureAlgorithm) (*HMACVerifier, error) { - - s, err := sign.New(alg) - if err != nil { - return nil, fmt.Errorf("failed to generate HMAC signer: %w", err) - } - return &HMACVerifier{signer: s}, nil -} - -// Verify checks whether the signature for a given input and key is correct -func (v HMACVerifier) Verify(signingInput, signature []byte, key any) (err error) { - - expected, err := v.signer.Sign(signingInput, key) - if err != nil { - return fmt.Errorf("failed to generated signature: %w", err) - } - - if !hmac.Equal(signature, expected) { - return errors.New("failed to match hmac signature") - } - return nil -} diff --git a/vendor/github.com/open-policy-agent/opa/internal/jwx/jws/verify/interface.go b/vendor/github.com/open-policy-agent/opa/internal/jwx/jws/verify/interface.go deleted file mode 100644 index e72c3ed7f76..00000000000 --- a/vendor/github.com/open-policy-agent/opa/internal/jwx/jws/verify/interface.go +++ /dev/null @@ -1,39 +0,0 @@ -package verify - -import ( - "crypto/ecdsa" - "crypto/rsa" - - "github.com/open-policy-agent/opa/internal/jwx/jws/sign" -) - -// Verifier provides a common interface for supported alg verification methods -type Verifier interface { - // Verify checks whether the payload and signature are valid for - // the given key. - // `key` is the key used for verifying the payload, and is usually - // the public key associated with the signature method. For example, - // for `jwa.RSXXX` and `jwa.PSXXX` types, you need to pass the - // `*"crypto/rsa".PublicKey` type. - // Check the documentation for each verifier for details - Verify(payload []byte, signature []byte, key any) error -} - -type rsaVerifyFunc func([]byte, []byte, *rsa.PublicKey) error - -// RSAVerifier implements the Verifier interface -type RSAVerifier struct { - verify rsaVerifyFunc -} - -type ecdsaVerifyFunc func([]byte, []byte, *ecdsa.PublicKey) error - -// ECDSAVerifier implements the Verifier interface -type ECDSAVerifier struct { - verify ecdsaVerifyFunc -} - -// HMACVerifier implements the Verifier interface -type HMACVerifier struct { - signer sign.Signer -} diff --git a/vendor/github.com/open-policy-agent/opa/internal/jwx/jws/verify/rsa.go b/vendor/github.com/open-policy-agent/opa/internal/jwx/jws/verify/rsa.go deleted file mode 100644 index 163ff84bcf1..00000000000 --- a/vendor/github.com/open-policy-agent/opa/internal/jwx/jws/verify/rsa.go +++ /dev/null @@ -1,88 +0,0 @@ -package verify - -import ( - "crypto" - "crypto/rsa" - "errors" - "fmt" - - "github.com/open-policy-agent/opa/internal/jwx/jwa" -) - -var rsaVerifyFuncs = map[jwa.SignatureAlgorithm]rsaVerifyFunc{} - -func init() { - algs := map[jwa.SignatureAlgorithm]struct { - Hash crypto.Hash - VerifyFunc func(crypto.Hash) rsaVerifyFunc - }{ - jwa.RS256: { - Hash: crypto.SHA256, - VerifyFunc: makeVerifyPKCS1v15, - }, - jwa.RS384: { - Hash: crypto.SHA384, - VerifyFunc: makeVerifyPKCS1v15, - }, - jwa.RS512: { - Hash: crypto.SHA512, - VerifyFunc: makeVerifyPKCS1v15, - }, - jwa.PS256: { - Hash: crypto.SHA256, - VerifyFunc: makeVerifyPSS, - }, - jwa.PS384: { - Hash: crypto.SHA384, - VerifyFunc: makeVerifyPSS, - }, - jwa.PS512: { - Hash: crypto.SHA512, - VerifyFunc: makeVerifyPSS, - }, - } - - for alg, item := range algs { - rsaVerifyFuncs[alg] = item.VerifyFunc(item.Hash) - } -} - -func makeVerifyPKCS1v15(hash crypto.Hash) rsaVerifyFunc { - return rsaVerifyFunc(func(payload, signature []byte, key *rsa.PublicKey) error { - h := hash.New() - h.Write(payload) - return rsa.VerifyPKCS1v15(key, hash, h.Sum(nil), signature) - }) -} - -func makeVerifyPSS(hash crypto.Hash) rsaVerifyFunc { - return rsaVerifyFunc(func(payload, signature []byte, key *rsa.PublicKey) error { - h := hash.New() - h.Write(payload) - return rsa.VerifyPSS(key, hash, h.Sum(nil), signature, nil) - }) -} - -func newRSA(alg jwa.SignatureAlgorithm) (*RSAVerifier, error) { - verifyfn, ok := rsaVerifyFuncs[alg] - if !ok { - return nil, fmt.Errorf(`unsupported algorithm while trying to create RSA verifier: %s`, alg) - } - - return &RSAVerifier{ - verify: verifyfn, - }, nil -} - -// Verify checks if a JWS is valid. -func (v RSAVerifier) Verify(payload, signature []byte, key any) error { - if key == nil { - return errors.New(`missing public key while verifying payload`) - } - rsaKey, ok := key.(*rsa.PublicKey) - if !ok { - return fmt.Errorf(`invalid key type %T. *rsa.PublicKey is required`, key) - } - - return v.verify(payload, signature, rsaKey) -} diff --git a/vendor/github.com/open-policy-agent/opa/internal/jwx/jws/verify/verify.go b/vendor/github.com/open-policy-agent/opa/internal/jwx/jws/verify/verify.go deleted file mode 100644 index 7370b4a2f1e..00000000000 --- a/vendor/github.com/open-policy-agent/opa/internal/jwx/jws/verify/verify.go +++ /dev/null @@ -1,56 +0,0 @@ -package verify - -import ( - "crypto/ecdsa" - "crypto/rsa" - "crypto/x509" - "encoding/pem" - "errors" - "fmt" - - "github.com/open-policy-agent/opa/internal/jwx/jwa" -) - -// New creates a new JWS verifier using the specified algorithm -// and the public key -func New(alg jwa.SignatureAlgorithm) (Verifier, error) { - switch alg { - case jwa.RS256, jwa.RS384, jwa.RS512, jwa.PS256, jwa.PS384, jwa.PS512: - return newRSA(alg) - case jwa.ES256, jwa.ES384, jwa.ES512: - return newECDSA(alg) - case jwa.HS256, jwa.HS384, jwa.HS512: - return newHMAC(alg) - default: - return nil, fmt.Errorf(`unsupported signature algorithm: %s`, alg) - } -} - -// GetSigningKey returns a *rsa.PublicKey or *ecdsa.PublicKey typically encoded in PEM blocks of type "PUBLIC KEY", -// for RSA and ECDSA family of algorithms. -// For HMAC family, it return a []byte value -func GetSigningKey(key string, alg jwa.SignatureAlgorithm) (any, error) { - switch alg { - case jwa.RS256, jwa.RS384, jwa.RS512, jwa.PS256, jwa.PS384, jwa.PS512, jwa.ES256, jwa.ES384, jwa.ES512: - block, _ := pem.Decode([]byte(key)) - if block == nil { - return nil, errors.New("failed to parse PEM block containing the key") - } - - pub, err := x509.ParsePKIXPublicKey(block.Bytes) - if err != nil { - return nil, err - } - - switch pub := pub.(type) { - case *rsa.PublicKey, *ecdsa.PublicKey: - return pub, nil - default: - return nil, fmt.Errorf("invalid key type %T", pub) - } - case jwa.HS256, jwa.HS384, jwa.HS512: - return []byte(key), nil - default: - return nil, fmt.Errorf("unsupported signature algorithm: %s", alg) - } -} diff --git a/vendor/github.com/open-policy-agent/opa/internal/report/report.go b/vendor/github.com/open-policy-agent/opa/internal/report/report.go index b517864ed34..bc71d66a3cc 100644 --- a/vendor/github.com/open-policy-agent/opa/internal/report/report.go +++ b/vendor/github.com/open-policy-agent/opa/internal/report/report.go @@ -6,17 +6,19 @@ package report import ( + "cmp" "context" "encoding/json" + "errors" "fmt" "net/http" "os" "runtime" "strconv" "strings" - "sync" "time" + "github.com/open-policy-agent/opa/internal/semver" "github.com/open-policy-agent/opa/v1/keys" "github.com/open-policy-agent/opa/v1/logging" "github.com/open-policy-agent/opa/v1/version" @@ -25,24 +27,25 @@ import ( "github.com/open-policy-agent/opa/v1/util" ) -// ExternalServiceURL is the base HTTP URL for a telemetry service. -// If not otherwise specified it will use the hard coded default. +// ExternalServiceURL is the base HTTP URL for a github instance used +// to query for more recent version. +// If not otherwise specified, it will use the hard-coded default, api.github.com. +// GHRepo is the repository to use, and defaults to "open-policy-agent/opa" // // Override at build time via: // // -ldflags "-X github.com/open-policy-agent/opa/internal/report.ExternalServiceURL=" +// -ldflags "-X github.com/open-policy-agent/opa/internal/report.GHRepo=" // -// This will be overridden if the OPA_TELEMETRY_SERVICE_URL environment variable +// ExternalServiceURL will be overridden if the OPA_TELEMETRY_SERVICE_URL environment variable // is provided. -var ExternalServiceURL = "https://telemetry.openpolicyagent.org" +var ExternalServiceURL = "https://api.github.com" +var GHRepo = "open-policy-agent/opa" // Reporter reports information such as the version, heap usage about the running OPA instance to an external service -type Reporter struct { - body map[string]any - client rest.Client - - gatherers map[string]Gatherer - gatherersMtx sync.Mutex +type Reporter interface { + SendReport(ctx context.Context) (*DataResponse, error) + RegisterGatherer(key string, f Gatherer) } // Gatherer represents a mechanism to inject additional data in the telemetry report @@ -50,7 +53,7 @@ type Gatherer func(ctx context.Context) (any, error) // DataResponse represents the data returned by the external service type DataResponse struct { - Latest ReleaseDetails `json:"latest,omitempty"` + Latest ReleaseDetails `json:"latest"` } // ReleaseDetails holds information about the latest OPA release @@ -66,20 +69,21 @@ type Options struct { Logger logging.Logger } +type GHVersionCollector struct { + client rest.Client +} + +type GHResponse struct { + TagName string `json:"tag_name,omitempty"` // latest OPA release tag + ReleaseNotes string `json:"html_url,omitempty"` // link to the OPA release notes + Download string `json:"assets_url,omitempty"` // link to download the OPA release +} + // New returns an instance of the Reporter -func New(id string, opts Options) (*Reporter, error) { - r := Reporter{ - gatherers: map[string]Gatherer{}, - } - r.body = map[string]any{ - "id": id, - "version": version.Version, - } +func New(opts Options) (Reporter, error) { + r := GHVersionCollector{} - url := os.Getenv("OPA_TELEMETRY_SERVICE_URL") - if url == "" { - url = ExternalServiceURL - } + url := cmp.Or(os.Getenv("OPA_TELEMETRY_SERVICE_URL"), ExternalServiceURL) restConfig := fmt.Appendf(nil, `{ "url": %q, @@ -99,21 +103,11 @@ func New(id string, opts Options) (*Reporter, error) { // SendReport sends the telemetry report which includes information such as the OPA version, current memory usage to // the external service -func (r *Reporter) SendReport(ctx context.Context) (*DataResponse, error) { +func (r *GHVersionCollector) SendReport(ctx context.Context) (*DataResponse, error) { rCtx, cancel := context.WithTimeout(ctx, 5*time.Second) defer cancel() - r.gatherersMtx.Lock() - defer r.gatherersMtx.Unlock() - for key, g := range r.gatherers { - var err error - r.body[key], err = g(rCtx) - if err != nil { - return nil, fmt.Errorf("gather telemetry error for key %s: %w", key, err) - } - } - - resp, err := r.client.WithJSON(r.body).Do(rCtx, "POST", "/v1/version") + resp, err := r.client.Do(rCtx, "GET", fmt.Sprintf("/repos/%s/releases/latest", GHRepo)) if err != nil { return nil, err } @@ -123,12 +117,12 @@ func (r *Reporter) SendReport(ctx context.Context) (*DataResponse, error) { switch resp.StatusCode { case http.StatusOK: if resp.Body != nil { - var result DataResponse + var result GHResponse err := json.NewDecoder(resp.Body).Decode(&result) if err != nil { return nil, err } - return &result, nil + return createDataResponse(result) } return nil, nil default: @@ -136,10 +130,50 @@ func (r *Reporter) SendReport(ctx context.Context) (*DataResponse, error) { } } -func (r *Reporter) RegisterGatherer(key string, f Gatherer) { - r.gatherersMtx.Lock() - r.gatherers[key] = f - r.gatherersMtx.Unlock() +func createDataResponse(ghResp GHResponse) (*DataResponse, error) { + if ghResp.TagName == "" { + return nil, errors.New("server response does not contain tag_name") + } + + v := strings.TrimPrefix(version.Version, "v") + sv, err := semver.NewVersion(v) + if err != nil { + return nil, fmt.Errorf("failed to parse current version %q: %w", v, err) + } + + latestV := strings.TrimPrefix(ghResp.TagName, "v") + latestSV, err := semver.NewVersion(latestV) + if err != nil { + return nil, fmt.Errorf("failed to parse latest version %q: %w", latestV, err) + } + + isLatest := sv.Compare(*latestSV) >= 0 + + // Note: alternatively, we could look through the assets in the GH API response to find a matching asset, + // and use its URL. However, this is not guaranteed to be more robust, and wouldn't use the 'openpolicyagent.org' domain. + downloadLink := fmt.Sprintf("https://openpolicyagent.org/downloads/%v/opa_%v_%v", + ghResp.TagName, runtime.GOOS, runtime.GOARCH) + + if runtime.GOARCH == "arm64" { + downloadLink = fmt.Sprintf("%v_static", downloadLink) + } + + if strings.HasPrefix(runtime.GOOS, "win") { + downloadLink = fmt.Sprintf("%v.exe", downloadLink) + } + + return &DataResponse{ + Latest: ReleaseDetails{ + Download: downloadLink, + ReleaseNotes: ghResp.ReleaseNotes, + LatestRelease: ghResp.TagName, + OPAUpToDate: isLatest, + }, + }, nil +} + +func (*GHVersionCollector) RegisterGatherer(_ string, _ Gatherer) { + // no-op for this implementation } // IsSet returns true if dr is populated. diff --git a/vendor/github.com/open-policy-agent/opa/internal/runtime/init/init.go b/vendor/github.com/open-policy-agent/opa/internal/runtime/init/init.go index 814847a12a1..de8ef874012 100644 --- a/vendor/github.com/open-policy-agent/opa/internal/runtime/init/init.go +++ b/vendor/github.com/open-policy-agent/opa/internal/runtime/init/init.go @@ -29,6 +29,7 @@ type InsertAndCompileOptions struct { MaxErrors int EnablePrintStatements bool ParserOptions ast.ParserOptions + BundleActivatorPlugin string } // InsertAndCompileResult contains the output of the operation. @@ -41,7 +42,7 @@ type InsertAndCompileResult struct { // store contents. func InsertAndCompile(ctx context.Context, opts InsertAndCompileOptions) (*InsertAndCompileResult, error) { if len(opts.Files.Documents) > 0 { - if err := opts.Store.Write(ctx, opts.Txn, storage.AddOp, storage.Path{}, opts.Files.Documents); err != nil { + if err := opts.Store.Write(ctx, opts.Txn, storage.AddOp, storage.RootPath, opts.Files.Documents); err != nil { return nil, fmt.Errorf("storage error: %w", err) } } @@ -68,6 +69,7 @@ func InsertAndCompile(ctx context.Context, opts InsertAndCompileOptions) (*Inser Bundles: opts.Bundles, ExtraModules: policies, ParserOptions: opts.ParserOptions, + Plugin: opts.BundleActivatorPlugin, } err := bundle.Activate(activation) @@ -122,10 +124,11 @@ func LoadPaths(paths []string, asBundle bool, bvc *bundle.VerificationConfig, skipVerify bool, + bundleLazyLoading bool, processAnnotations bool, caps *ast.Capabilities, fsys fs.FS) (*LoadPathsResult, error) { - return LoadPathsForRegoVersion(ast.RegoV0, paths, filter, asBundle, bvc, skipVerify, processAnnotations, false, caps, fsys) + return LoadPathsForRegoVersion(ast.RegoV0, paths, filter, asBundle, bvc, skipVerify, bundleLazyLoading, processAnnotations, false, caps, fsys) } func LoadPathsForRegoVersion(regoVersion ast.RegoVersion, @@ -134,6 +137,7 @@ func LoadPathsForRegoVersion(regoVersion ast.RegoVersion, asBundle bool, bvc *bundle.VerificationConfig, skipVerify bool, + bundleLazyLoading bool, processAnnotations bool, followSymlinks bool, caps *ast.Capabilities, @@ -159,6 +163,7 @@ func LoadPathsForRegoVersion(regoVersion ast.RegoVersion, WithFS(fsys). WithBundleVerificationConfig(bvc). WithSkipBundleVerification(skipVerify). + WithBundleLazyLoadingMode(bundleLazyLoading). WithFilter(filter). WithProcessAnnotation(processAnnotations). WithCapabilities(caps). @@ -171,12 +176,13 @@ func LoadPathsForRegoVersion(regoVersion ast.RegoVersion, } } - if len(nonBundlePaths) == 0 { + if asBundle { return &result, nil } files, err := loader.NewFileLoader(). WithFS(fsys). + WithBundleLazyLoadingMode(bundleLazyLoading). WithProcessAnnotation(processAnnotations). WithCapabilities(caps). WithRegoVersion(regoVersion). diff --git a/vendor/github.com/open-policy-agent/opa/internal/semver/semver.go b/vendor/github.com/open-policy-agent/opa/internal/semver/semver.go index 389eeccc18b..23c6c186d9c 100644 --- a/vendor/github.com/open-policy-agent/opa/internal/semver/semver.go +++ b/vendor/github.com/open-policy-agent/opa/internal/semver/semver.go @@ -233,3 +233,18 @@ func validateIdentifier(id string) error { // reIdentifier is a regular expression used to check that pre-release and metadata // identifiers satisfy the spec requirements var reIdentifier = regexp.MustCompile(`^[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*$`) + +// Compare compares two semver strings. +func Compare(a, b string) int { + aV, err := NewVersion(strings.TrimPrefix(a, "v")) + if err != nil { + return -1 + } + + bV, err := NewVersion(strings.TrimPrefix(b, "v")) + if err != nil { + return 1 + } + + return aV.Compare(*bV) +} diff --git a/vendor/github.com/open-policy-agent/opa/storage/interface.go b/vendor/github.com/open-policy-agent/opa/storage/interface.go index 0192c459c83..a21b5575e9a 100644 --- a/vendor/github.com/open-policy-agent/opa/storage/interface.go +++ b/vendor/github.com/open-policy-agent/opa/storage/interface.go @@ -19,6 +19,9 @@ type Store = v1.Store // generic MakeDir functionality in storage.MakeDir type MakeDirer = v1.MakeDirer +// NonEmptyer allows a store implemention to override NonEmpty()) +type NonEmptyer = v1.NonEmptyer + // TransactionParams describes a new transaction. type TransactionParams = v1.TransactionParams diff --git a/vendor/github.com/open-policy-agent/opa/v1/ast/annotations.go b/vendor/github.com/open-policy-agent/opa/v1/ast/annotations.go index 3465f0808f7..36f854c618d 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/ast/annotations.go +++ b/vendor/github.com/open-policy-agent/opa/v1/ast/annotations.go @@ -34,6 +34,7 @@ type ( RelatedResources []*RelatedResourceAnnotation `json:"related_resources,omitempty"` Authors []*AuthorAnnotation `json:"authors,omitempty"` Schemas []*SchemaAnnotation `json:"schemas,omitempty"` + Compile *CompileAnnotation `json:"compile,omitempty"` Custom map[string]any `json:"custom,omitempty"` Location *Location `json:"location,omitempty"` @@ -48,6 +49,11 @@ type ( Definition *any `json:"definition,omitempty"` } + CompileAnnotation struct { + Unknowns []Ref `json:"unknowns,omitempty"` + MaskRule Ref `json:"mask_rule,omitempty"` // NOTE: This doesn't need to start with "data.package", it can be relative + } + AuthorAnnotation struct { Name string `json:"name"` Email string `json:"email,omitempty"` @@ -151,6 +157,10 @@ func (a *Annotations) Compare(other *Annotations) int { return cmp } + if cmp := a.Compile.Compare(other.Compile); cmp != 0 { + return cmp + } + if a.Entrypoint != other.Entrypoint { if a.Entrypoint { return 1 @@ -403,6 +413,8 @@ func (a *Annotations) Copy(node Node) *Annotations { cpy.Schemas[i] = a.Schemas[i].Copy() } + cpy.Compile = a.Compile.Copy() + if a.Custom != nil { cpy.Custom = deepcopy.Map(a.Custom) } @@ -716,6 +728,44 @@ func (s *SchemaAnnotation) String() string { return string(bs) } +// Copy returns a deep copy of s. +func (c *CompileAnnotation) Copy() *CompileAnnotation { + if c == nil { + return nil + } + cpy := *c + for i := range c.Unknowns { + cpy.Unknowns[i] = c.Unknowns[i].Copy() + } + return &cpy +} + +// Compare returns an integer indicating if s is less than, equal to, or greater +// than other. +func (c *CompileAnnotation) Compare(other *CompileAnnotation) int { + switch { + case c == nil && other == nil: + return 0 + case c != nil && other == nil: + return 1 + case c == nil && other != nil: + return -1 + } + + if cmp := slices.CompareFunc(c.Unknowns, other.Unknowns, + func(x, y Ref) int { + return x.Compare(y) + }); cmp != 0 { + return cmp + } + return c.MaskRule.Compare(other.MaskRule) +} + +func (c *CompileAnnotation) String() string { + bs, _ := json.Marshal(c) + return string(bs) +} + func newAnnotationSet() *AnnotationSet { return &AnnotationSet{ byRule: map[*Rule][]*Annotations{}, diff --git a/vendor/github.com/open-policy-agent/opa/v1/ast/builtins.go b/vendor/github.com/open-policy-agent/opa/v1/ast/builtins.go index fde7e26b345..3d72aeab1f6 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/ast/builtins.go +++ b/vendor/github.com/open-policy-agent/opa/v1/ast/builtins.go @@ -198,6 +198,7 @@ var DefaultBuiltins = [...]*Builtin{ JWTVerifyES256, JWTVerifyES384, JWTVerifyES512, + JWTVerifyEdDSA, JWTVerifyHS256, JWTVerifyHS384, JWTVerifyHS512, @@ -346,7 +347,7 @@ var Equality = &Builtin{ types.Args(types.A, types.A), types.B, ), - canSkipBctx: true, + CanSkipBctx: true, } /** @@ -361,7 +362,7 @@ var Assign = &Builtin{ types.Args(types.A, types.A), types.B, ), - canSkipBctx: true, + CanSkipBctx: true, } // Member represents the `in` (infix) operator. @@ -375,7 +376,7 @@ var Member = &Builtin{ ), types.B, ), - canSkipBctx: true, + CanSkipBctx: true, } // MemberWithKey represents the `in` (infix) operator when used @@ -391,7 +392,7 @@ var MemberWithKey = &Builtin{ ), types.B, ), - canSkipBctx: true, + CanSkipBctx: true, } /** @@ -410,7 +411,7 @@ var GreaterThan = &Builtin{ ), types.Named("result", types.B).Description("true if `x` is greater than `y`; false otherwise"), ), - canSkipBctx: true, + CanSkipBctx: true, } var GreaterThanEq = &Builtin{ @@ -424,7 +425,7 @@ var GreaterThanEq = &Builtin{ ), types.Named("result", types.B).Description("true if `x` is greater or equal to `y`; false otherwise"), ), - canSkipBctx: true, + CanSkipBctx: true, } // LessThan represents the "<" comparison operator. @@ -439,7 +440,7 @@ var LessThan = &Builtin{ ), types.Named("result", types.B).Description("true if `x` is less than `y`; false otherwise"), ), - canSkipBctx: true, + CanSkipBctx: true, } var LessThanEq = &Builtin{ @@ -453,7 +454,7 @@ var LessThanEq = &Builtin{ ), types.Named("result", types.B).Description("true if `x` is less than or equal to `y`; false otherwise"), ), - canSkipBctx: true, + CanSkipBctx: true, } var NotEqual = &Builtin{ @@ -467,7 +468,7 @@ var NotEqual = &Builtin{ ), types.Named("result", types.B).Description("true if `x` is not equal to `y`; false otherwise"), ), - canSkipBctx: true, + CanSkipBctx: true, } // Equal represents the "==" comparison operator. @@ -482,7 +483,7 @@ var Equal = &Builtin{ ), types.Named("result", types.B).Description("true if `x` is equal to `y`; false otherwise"), ), - canSkipBctx: true, + CanSkipBctx: true, } /** @@ -502,7 +503,7 @@ var Plus = &Builtin{ types.Named("z", types.N).Description("the sum of `x` and `y`"), ), Categories: number, - canSkipBctx: true, + CanSkipBctx: true, } var Minus = &Builtin{ @@ -517,7 +518,7 @@ var Minus = &Builtin{ types.Named("z", types.NewAny(types.N, types.SetOfAny)).Description("the difference of `x` and `y`"), ), Categories: category("sets", "numbers"), - canSkipBctx: true, + CanSkipBctx: true, } var Multiply = &Builtin{ @@ -532,7 +533,7 @@ var Multiply = &Builtin{ types.Named("z", types.N).Description("the product of `x` and `y`"), ), Categories: number, - canSkipBctx: true, + CanSkipBctx: true, } var Divide = &Builtin{ @@ -547,7 +548,7 @@ var Divide = &Builtin{ types.Named("z", types.N).Description("the result of `x` divided by `y`"), ), Categories: number, - canSkipBctx: true, + CanSkipBctx: true, } var Round = &Builtin{ @@ -560,7 +561,7 @@ var Round = &Builtin{ types.Named("y", types.N).Description("the result of rounding `x`"), ), Categories: number, - canSkipBctx: true, + CanSkipBctx: true, } var Ceil = &Builtin{ @@ -573,7 +574,7 @@ var Ceil = &Builtin{ types.Named("y", types.N).Description("the result of rounding `x` _up_"), ), Categories: number, - canSkipBctx: true, + CanSkipBctx: true, } var Floor = &Builtin{ @@ -586,7 +587,7 @@ var Floor = &Builtin{ types.Named("y", types.N).Description("the result of rounding `x` _down_"), ), Categories: number, - canSkipBctx: true, + CanSkipBctx: true, } var Abs = &Builtin{ @@ -599,7 +600,7 @@ var Abs = &Builtin{ types.Named("y", types.N).Description("the absolute value of `x`"), ), Categories: number, - canSkipBctx: true, + CanSkipBctx: true, } var Rem = &Builtin{ @@ -614,7 +615,7 @@ var Rem = &Builtin{ types.Named("z", types.N).Description("the remainder"), ), Categories: number, - canSkipBctx: true, + CanSkipBctx: true, } /** @@ -631,7 +632,7 @@ var BitsOr = &Builtin{ ), types.Named("z", types.N).Description("the bitwise OR of `x` and `y`"), ), - canSkipBctx: true, + CanSkipBctx: true, } var BitsAnd = &Builtin{ @@ -644,7 +645,7 @@ var BitsAnd = &Builtin{ ), types.Named("z", types.N).Description("the bitwise AND of `x` and `y`"), ), - canSkipBctx: true, + CanSkipBctx: true, } var BitsNegate = &Builtin{ @@ -656,7 +657,7 @@ var BitsNegate = &Builtin{ ), types.Named("z", types.N).Description("the bitwise negation of `x`"), ), - canSkipBctx: true, + CanSkipBctx: true, } var BitsXOr = &Builtin{ @@ -669,7 +670,7 @@ var BitsXOr = &Builtin{ ), types.Named("z", types.N).Description("the bitwise XOR of `x` and `y`"), ), - canSkipBctx: true, + CanSkipBctx: true, } var BitsShiftLeft = &Builtin{ @@ -682,7 +683,7 @@ var BitsShiftLeft = &Builtin{ ), types.Named("z", types.N).Description("the result of shifting `x` `s` bits to the left"), ), - canSkipBctx: true, + CanSkipBctx: true, } var BitsShiftRight = &Builtin{ @@ -695,7 +696,7 @@ var BitsShiftRight = &Builtin{ ), types.Named("z", types.N).Description("the result of shifting `x` `s` bits to the right"), ), - canSkipBctx: true, + CanSkipBctx: true, } /** @@ -716,7 +717,7 @@ var And = &Builtin{ types.Named("z", types.SetOfAny).Description("the intersection of `x` and `y`"), ), Categories: sets, - canSkipBctx: true, + CanSkipBctx: true, } // Or performs a union operation on sets. @@ -732,7 +733,7 @@ var Or = &Builtin{ types.Named("z", types.SetOfAny).Description("the union of `x` and `y`"), ), Categories: sets, - canSkipBctx: true, + CanSkipBctx: true, } var Intersection = &Builtin{ @@ -745,7 +746,7 @@ var Intersection = &Builtin{ types.Named("y", types.SetOfAny).Description("the intersection of all `xs` sets"), ), Categories: sets, - canSkipBctx: true, + CanSkipBctx: true, } var Union = &Builtin{ @@ -758,7 +759,7 @@ var Union = &Builtin{ types.Named("y", types.SetOfAny).Description("the union of all `xs` sets"), ), Categories: sets, - canSkipBctx: true, + CanSkipBctx: true, } /** @@ -769,7 +770,7 @@ var aggregates = category("aggregates") var Count = &Builtin{ Name: "count", - Description: " Count takes a collection or string and returns the number of elements (or characters) in it.", + Description: "Count takes a collection or string and returns the number of elements (or characters) in it.", Decl: types.NewFunction( types.Args( types.Named("collection", types.NewAny( @@ -782,7 +783,7 @@ var Count = &Builtin{ types.Named("n", types.N).Description("the count of elements, key/val pairs, or characters, respectively."), ), Categories: aggregates, - canSkipBctx: true, + CanSkipBctx: true, } var Sum = &Builtin{ @@ -798,7 +799,7 @@ var Sum = &Builtin{ types.Named("n", types.N).Description("the sum of all elements"), ), Categories: aggregates, - canSkipBctx: true, + CanSkipBctx: true, } var Product = &Builtin{ @@ -814,7 +815,7 @@ var Product = &Builtin{ types.Named("n", types.N).Description("the product of all elements"), ), Categories: aggregates, - canSkipBctx: true, + CanSkipBctx: true, } var Max = &Builtin{ @@ -830,7 +831,7 @@ var Max = &Builtin{ types.Named("n", types.A).Description("the maximum of all elements"), ), Categories: aggregates, - canSkipBctx: true, + CanSkipBctx: true, } var Min = &Builtin{ @@ -846,7 +847,7 @@ var Min = &Builtin{ types.Named("n", types.A).Description("the minimum of all elements"), ), Categories: aggregates, - canSkipBctx: true, + CanSkipBctx: true, } /** @@ -866,7 +867,7 @@ var Sort = &Builtin{ types.Named("n", types.NewArray(nil, types.A)).Description("the sorted array"), ), Categories: aggregates, - canSkipBctx: true, + CanSkipBctx: true, } /** @@ -883,7 +884,7 @@ var ArrayConcat = &Builtin{ ), types.Named("z", types.NewArray(nil, types.A)).Description("the concatenation of `x` and `y`"), ), - canSkipBctx: true, + CanSkipBctx: true, } var ArraySlice = &Builtin{ @@ -897,7 +898,7 @@ var ArraySlice = &Builtin{ ), types.Named("slice", types.NewArray(nil, types.A)).Description("the subslice of `array`, from `start` to `end`, including `arr[start]`, but excluding `arr[end]`"), ), - canSkipBctx: true, + CanSkipBctx: true, } // NOTE(sr): this function really needs examples var ArrayReverse = &Builtin{ @@ -909,7 +910,7 @@ var ArrayReverse = &Builtin{ ), types.Named("rev", types.NewArray(nil, types.A)).Description("an array containing the elements of `arr` in reverse order"), ), - canSkipBctx: true, + CanSkipBctx: true, } /** @@ -926,13 +927,13 @@ var ToNumber = &Builtin{ types.N, types.S, types.B, - types.NewNull(), + types.Nl, )).Description("value to convert"), ), types.Named("num", types.N).Description("the numeric representation of `x`"), ), Categories: conversions, - canSkipBctx: true, + CanSkipBctx: true, } /** @@ -960,7 +961,7 @@ var RegexIsValid = &Builtin{ ), types.Named("result", types.B).Description("true if `pattern` is a valid regular expression"), ), - canSkipBctx: true, + CanSkipBctx: true, } var RegexFindAllStringSubmatch = &Builtin{ @@ -974,7 +975,7 @@ var RegexFindAllStringSubmatch = &Builtin{ ), types.Named("output", types.NewArray(nil, types.NewArray(nil, types.S))).Description("array of all matches"), ), - canSkipBctx: false, + CanSkipBctx: false, } var RegexTemplateMatch = &Builtin{ @@ -989,7 +990,7 @@ var RegexTemplateMatch = &Builtin{ ), types.Named("result", types.B).Description("true if `value` matches the `template`"), ), - canSkipBctx: true, + CanSkipBctx: true, } // TODO(sr): example:`regex.template_match("urn:foo:{.*}", "urn:foo:bar:baz", "{", "}")`` returns ``true``. var RegexSplit = &Builtin{ @@ -1002,7 +1003,7 @@ var RegexSplit = &Builtin{ ), types.Named("output", types.NewArray(nil, types.S)).Description("the parts obtained by splitting `value`"), ), - canSkipBctx: false, + CanSkipBctx: false, } // RegexFind takes two strings and a number, the pattern, the value and number of match values to @@ -1018,7 +1019,7 @@ var RegexFind = &Builtin{ ), types.Named("output", types.NewArray(nil, types.S)).Description("collected matches"), ), - canSkipBctx: false, + CanSkipBctx: false, } // GlobsMatch takes two strings regexp-style strings and evaluates to true if their @@ -1037,7 +1038,7 @@ The set of regex symbols is limited for this builtin: only ` + "`.`, `*`, `+`, ` ), types.Named("result", types.B).Description("true if the intersection of `glob1` and `glob2` matches a non-empty set of non-empty strings"), ), - canSkipBctx: true, + CanSkipBctx: true, } /** @@ -1064,7 +1065,7 @@ var AnyPrefixMatch = &Builtin{ types.Named("result", types.B).Description("result of the prefix check"), ), Categories: stringsCat, - canSkipBctx: true, + CanSkipBctx: true, } var AnySuffixMatch = &Builtin{ @@ -1086,7 +1087,7 @@ var AnySuffixMatch = &Builtin{ types.Named("result", types.B).Description("result of the suffix check"), ), Categories: stringsCat, - canSkipBctx: true, + CanSkipBctx: true, } var Concat = &Builtin{ @@ -1103,7 +1104,7 @@ var Concat = &Builtin{ types.Named("output", types.S).Description("the joined string"), ), Categories: stringsCat, - canSkipBctx: true, + CanSkipBctx: true, } var FormatInt = &Builtin{ @@ -1117,7 +1118,7 @@ var FormatInt = &Builtin{ types.Named("output", types.S).Description("formatted number"), ), Categories: stringsCat, - canSkipBctx: true, + CanSkipBctx: true, } var IndexOf = &Builtin{ @@ -1131,7 +1132,7 @@ var IndexOf = &Builtin{ types.Named("output", types.N).Description("index of first occurrence, `-1` if not found"), ), Categories: stringsCat, - canSkipBctx: true, + CanSkipBctx: true, } var IndexOfN = &Builtin{ @@ -1145,7 +1146,7 @@ var IndexOfN = &Builtin{ types.Named("output", types.NewArray(nil, types.N)).Description("all indices at which `needle` occurs in `haystack`, may be empty"), ), Categories: stringsCat, - canSkipBctx: true, + CanSkipBctx: true, } var Substring = &Builtin{ @@ -1160,7 +1161,7 @@ var Substring = &Builtin{ types.Named("output", types.S).Description("substring of `value` from `offset`, of length `length`"), ), Categories: stringsCat, - canSkipBctx: true, + CanSkipBctx: true, } var Contains = &Builtin{ @@ -1174,7 +1175,7 @@ var Contains = &Builtin{ types.Named("result", types.B).Description("result of the containment check"), ), Categories: stringsCat, - canSkipBctx: true, + CanSkipBctx: true, } var StringCount = &Builtin{ @@ -1188,7 +1189,7 @@ var StringCount = &Builtin{ types.Named("output", types.N).Description("count of occurrences, `0` if not found"), ), Categories: stringsCat, - canSkipBctx: true, + CanSkipBctx: true, } var StartsWith = &Builtin{ @@ -1202,7 +1203,7 @@ var StartsWith = &Builtin{ types.Named("result", types.B).Description("result of the prefix check"), ), Categories: stringsCat, - canSkipBctx: true, + CanSkipBctx: true, } var EndsWith = &Builtin{ @@ -1216,7 +1217,7 @@ var EndsWith = &Builtin{ types.Named("result", types.B).Description("result of the suffix check"), ), Categories: stringsCat, - canSkipBctx: true, + CanSkipBctx: true, } var Lower = &Builtin{ @@ -1229,7 +1230,7 @@ var Lower = &Builtin{ types.Named("y", types.S).Description("lower-case of x"), ), Categories: stringsCat, - canSkipBctx: true, + CanSkipBctx: true, } var Upper = &Builtin{ @@ -1242,7 +1243,7 @@ var Upper = &Builtin{ types.Named("y", types.S).Description("upper-case of x"), ), Categories: stringsCat, - canSkipBctx: true, + CanSkipBctx: true, } var Split = &Builtin{ @@ -1256,7 +1257,7 @@ var Split = &Builtin{ types.Named("ys", types.NewArray(nil, types.S)).Description("split parts"), ), Categories: stringsCat, - canSkipBctx: true, + CanSkipBctx: true, } var Replace = &Builtin{ @@ -1271,7 +1272,7 @@ var Replace = &Builtin{ types.Named("y", types.S).Description("string with replaced substrings"), ), Categories: stringsCat, - canSkipBctx: true, + CanSkipBctx: true, } var ReplaceN = &Builtin{ @@ -1291,7 +1292,7 @@ The old string comparisons are done in argument order.`, ), types.Named("output", types.S).Description("string with replaced substrings"), ), - canSkipBctx: true, + CanSkipBctx: true, } var RegexReplace = &Builtin{ @@ -1305,7 +1306,7 @@ var RegexReplace = &Builtin{ ), types.Named("output", types.S).Description("string with replaced substrings"), ), - canSkipBctx: false, + CanSkipBctx: false, } var Trim = &Builtin{ @@ -1319,7 +1320,7 @@ var Trim = &Builtin{ types.Named("output", types.S).Description("string trimmed of `cutset` characters"), ), Categories: stringsCat, - canSkipBctx: true, + CanSkipBctx: true, } var TrimLeft = &Builtin{ @@ -1333,7 +1334,7 @@ var TrimLeft = &Builtin{ types.Named("output", types.S).Description("string left-trimmed of `cutset` characters"), ), Categories: stringsCat, - canSkipBctx: true, + CanSkipBctx: true, } var TrimPrefix = &Builtin{ @@ -1347,7 +1348,7 @@ var TrimPrefix = &Builtin{ types.Named("output", types.S).Description("string with `prefix` cut off"), ), Categories: stringsCat, - canSkipBctx: true, + CanSkipBctx: true, } var TrimRight = &Builtin{ @@ -1361,7 +1362,7 @@ var TrimRight = &Builtin{ types.Named("output", types.S).Description("string right-trimmed of `cutset` characters"), ), Categories: stringsCat, - canSkipBctx: true, + CanSkipBctx: true, } var TrimSuffix = &Builtin{ @@ -1375,7 +1376,7 @@ var TrimSuffix = &Builtin{ types.Named("output", types.S).Description("string with `suffix` cut off"), ), Categories: stringsCat, - canSkipBctx: true, + CanSkipBctx: true, } var TrimSpace = &Builtin{ @@ -1388,7 +1389,7 @@ var TrimSpace = &Builtin{ types.Named("output", types.S).Description("string leading and trailing white space cut off"), ), Categories: stringsCat, - canSkipBctx: true, + CanSkipBctx: true, } var Sprintf = &Builtin{ @@ -1402,7 +1403,7 @@ var Sprintf = &Builtin{ types.Named("output", types.S).Description("`format` formatted by the values in `values`"), ), Categories: stringsCat, - canSkipBctx: true, + CanSkipBctx: true, } var StringReverse = &Builtin{ @@ -1415,7 +1416,7 @@ var StringReverse = &Builtin{ types.Named("y", types.S).Description("reversed string"), ), Categories: stringsCat, - canSkipBctx: true, + CanSkipBctx: true, } var RenderTemplate = &Builtin{ @@ -1430,7 +1431,7 @@ var RenderTemplate = &Builtin{ types.Named("result", types.S).Description("rendered template with template variables injected"), ), Categories: stringsCat, - canSkipBctx: true, + CanSkipBctx: true, } /** @@ -1451,7 +1452,7 @@ var RandIntn = &Builtin{ ), Categories: number, Nondeterministic: true, - canSkipBctx: false, + CanSkipBctx: false, } var NumbersRange = &Builtin{ @@ -1464,7 +1465,7 @@ var NumbersRange = &Builtin{ ), types.Named("range", types.NewArray(nil, types.N)).Description("the range between `a` and `b`"), ), - canSkipBctx: false, // needed for context timeout check + CanSkipBctx: false, // needed for context timeout check } var NumbersRangeStep = &Builtin{ @@ -1482,7 +1483,7 @@ var NumbersRangeStep = &Builtin{ ), types.Named("range", types.NewArray(nil, types.N)).Description("the range between `a` and `b` in `step` increments"), ), - canSkipBctx: false, // needed for context timeout check + CanSkipBctx: false, // needed for context timeout check } /** @@ -1507,7 +1508,7 @@ respectively. Other units are case-insensitive.`, ), types.Named("y", types.N).Description("the parsed number"), ), - canSkipBctx: true, + CanSkipBctx: true, } var UnitsParseBytes = &Builtin{ @@ -1526,7 +1527,7 @@ and "MiB" are equivalent).`, ), types.Named("y", types.N).Description("the parsed number"), ), - canSkipBctx: true, + CanSkipBctx: true, } // @@ -1546,7 +1547,7 @@ var UUIDRFC4122 = &Builtin{ types.Named("output", types.S).Description("a version 4 UUID; for any given `k`, the output will be consistent throughout a query evaluation"), ), Nondeterministic: true, - canSkipBctx: false, + CanSkipBctx: false, } var UUIDParse = &Builtin{ @@ -1560,7 +1561,7 @@ var UUIDParse = &Builtin{ types.Named("result", types.NewObject(nil, types.NewDynamicProperty(types.S, types.A))).Description("Properties of UUID if valid (version, variant, etc). Undefined otherwise."), ), Relation: false, - canSkipBctx: true, + CanSkipBctx: true, } /** @@ -1605,7 +1606,7 @@ var JSONFilter = &Builtin{ types.Named("filtered", types.A).Description("remaining data from `object` with only keys specified in `paths`"), ), Categories: objectCat, - canSkipBctx: true, + CanSkipBctx: true, } var JSONRemove = &Builtin{ @@ -1644,7 +1645,7 @@ var JSONRemove = &Builtin{ types.Named("output", types.A).Description("result of removing all keys specified in `paths`"), ), Categories: objectCat, - canSkipBctx: true, + CanSkipBctx: true, } var JSONPatch = &Builtin{ @@ -1670,7 +1671,7 @@ var JSONPatch = &Builtin{ types.Named("output", types.A).Description("result obtained after consecutively applying all patch operations in `patches`"), ), Categories: objectCat, - canSkipBctx: true, + CanSkipBctx: true, } var ObjectSubset = &Builtin{ @@ -1704,7 +1705,7 @@ var ObjectSubset = &Builtin{ ), types.Named("result", types.A).Description("`true` if `sub` is a subset of `super`"), ), - canSkipBctx: true, + CanSkipBctx: true, } var ObjectUnion = &Builtin{ @@ -1724,7 +1725,7 @@ var ObjectUnion = &Builtin{ ), types.Named("output", types.A).Description("a new object which is the result of an asymmetric recursive union of two objects where conflicts are resolved by choosing the key from the right-hand object `b`"), ), // TODO(sr): types.A? ^^^^^^^ (also below) - canSkipBctx: true, + CanSkipBctx: true, } var ObjectUnionN = &Builtin{ @@ -1740,7 +1741,7 @@ var ObjectUnionN = &Builtin{ ), types.Named("output", types.A).Description("asymmetric recursive union of all objects in `objects`, merged from left to right, where conflicts are resolved by choosing the key from the right-hand object"), ), - canSkipBctx: true, + CanSkipBctx: true, } var ObjectRemove = &Builtin{ @@ -1760,7 +1761,7 @@ var ObjectRemove = &Builtin{ ), types.Named("output", types.A).Description("result of removing the specified `keys` from `object`"), ), - canSkipBctx: true, + CanSkipBctx: true, } var ObjectFilter = &Builtin{ @@ -1781,7 +1782,7 @@ var ObjectFilter = &Builtin{ ), types.Named("filtered", types.A).Description("remaining data from `object` with only keys specified in `keys`"), ), - canSkipBctx: true, + CanSkipBctx: true, } var ObjectGet = &Builtin{ @@ -1797,7 +1798,7 @@ var ObjectGet = &Builtin{ ), types.Named("value", types.A).Description("`object[key]` if present, otherwise `default`"), ), - canSkipBctx: true, + CanSkipBctx: true, } var ObjectKeys = &Builtin{ @@ -1810,7 +1811,7 @@ var ObjectKeys = &Builtin{ ), types.Named("value", types.SetOfAny).Description("set of `object`'s keys"), ), - canSkipBctx: true, + CanSkipBctx: true, } /* @@ -1828,7 +1829,7 @@ var JSONMarshal = &Builtin{ types.Named("y", types.S).Description("the JSON string representation of `x`"), ), Categories: encoding, - canSkipBctx: true, + CanSkipBctx: true, } var JSONMarshalWithOptions = &Builtin{ @@ -1850,7 +1851,7 @@ var JSONMarshalWithOptions = &Builtin{ types.Named("y", types.S).Description("the JSON string representation of `x`, with configured prefix/indent string(s) as appropriate"), ), Categories: encoding, - canSkipBctx: true, + CanSkipBctx: true, } var JSONUnmarshal = &Builtin{ @@ -1863,7 +1864,7 @@ var JSONUnmarshal = &Builtin{ types.Named("y", types.A).Description("the term deserialized from `x`"), ), Categories: encoding, - canSkipBctx: true, + CanSkipBctx: true, } var JSONIsValid = &Builtin{ @@ -1876,7 +1877,7 @@ var JSONIsValid = &Builtin{ types.Named("result", types.B).Description("`true` if `x` is valid JSON, `false` otherwise"), ), Categories: encoding, - canSkipBctx: true, + CanSkipBctx: true, } var Base64Encode = &Builtin{ @@ -1889,7 +1890,7 @@ var Base64Encode = &Builtin{ types.Named("y", types.S).Description("base64 serialization of `x`"), ), Categories: encoding, - canSkipBctx: true, + CanSkipBctx: true, } var Base64Decode = &Builtin{ @@ -1902,7 +1903,7 @@ var Base64Decode = &Builtin{ types.Named("y", types.S).Description("base64 deserialization of `x`"), ), Categories: encoding, - canSkipBctx: true, + CanSkipBctx: true, } var Base64IsValid = &Builtin{ @@ -1915,7 +1916,7 @@ var Base64IsValid = &Builtin{ types.Named("result", types.B).Description("`true` if `x` is valid base64 encoded value, `false` otherwise"), ), Categories: encoding, - canSkipBctx: true, + CanSkipBctx: true, } var Base64UrlEncode = &Builtin{ @@ -1928,7 +1929,7 @@ var Base64UrlEncode = &Builtin{ types.Named("y", types.S).Description("base64url serialization of `x`"), ), Categories: encoding, - canSkipBctx: true, + CanSkipBctx: true, } var Base64UrlEncodeNoPad = &Builtin{ @@ -1941,7 +1942,7 @@ var Base64UrlEncodeNoPad = &Builtin{ types.Named("y", types.S).Description("base64url serialization of `x`"), ), Categories: encoding, - canSkipBctx: true, + CanSkipBctx: true, } var Base64UrlDecode = &Builtin{ @@ -1954,7 +1955,7 @@ var Base64UrlDecode = &Builtin{ types.Named("y", types.S).Description("base64url deserialization of `x`"), ), Categories: encoding, - canSkipBctx: true, + CanSkipBctx: true, } var URLQueryDecode = &Builtin{ @@ -1967,7 +1968,7 @@ var URLQueryDecode = &Builtin{ types.Named("y", types.S).Description("URL-encoding deserialization of `x`"), ), Categories: encoding, - canSkipBctx: true, + CanSkipBctx: true, } var URLQueryEncode = &Builtin{ @@ -1980,7 +1981,7 @@ var URLQueryEncode = &Builtin{ types.Named("y", types.S).Description("URL-encoding serialization of `x`"), ), Categories: encoding, - canSkipBctx: true, + CanSkipBctx: true, } var URLQueryEncodeObject = &Builtin{ @@ -2004,7 +2005,7 @@ var URLQueryEncodeObject = &Builtin{ types.Named("y", types.S).Description("the URL-encoded serialization of `object`"), ), Categories: encoding, - canSkipBctx: true, + CanSkipBctx: true, } var URLQueryDecodeObject = &Builtin{ @@ -2019,7 +2020,7 @@ var URLQueryDecodeObject = &Builtin{ types.NewArray(nil, types.S)))).Description("the resulting object"), ), Categories: encoding, - canSkipBctx: true, + CanSkipBctx: true, } var YAMLMarshal = &Builtin{ @@ -2032,7 +2033,7 @@ var YAMLMarshal = &Builtin{ types.Named("y", types.S).Description("the YAML string representation of `x`"), ), Categories: encoding, - canSkipBctx: true, + CanSkipBctx: true, } var YAMLUnmarshal = &Builtin{ @@ -2045,7 +2046,7 @@ var YAMLUnmarshal = &Builtin{ types.Named("y", types.A).Description("the term deserialized from `x`"), ), Categories: encoding, - canSkipBctx: true, + CanSkipBctx: true, } // YAMLIsValid verifies the input string is a valid YAML document. @@ -2059,7 +2060,7 @@ var YAMLIsValid = &Builtin{ types.Named("result", types.B).Description("`true` if `x` is valid YAML, `false` otherwise"), ), Categories: encoding, - canSkipBctx: true, + CanSkipBctx: true, } var HexEncode = &Builtin{ @@ -2072,7 +2073,7 @@ var HexEncode = &Builtin{ types.Named("y", types.S).Description("serialization of `x` using hex-encoding"), ), Categories: encoding, - canSkipBctx: true, + CanSkipBctx: true, } var HexDecode = &Builtin{ @@ -2085,7 +2086,7 @@ var HexDecode = &Builtin{ types.Named("y", types.S).Description("deserialized from `x`"), ), Categories: encoding, - canSkipBctx: true, + CanSkipBctx: true, } /** @@ -2107,7 +2108,7 @@ var JWTDecode = &Builtin{ }, nil)).Description("`[header, payload, sig]`, where `header` and `payload` are objects; `sig` is the hexadecimal representation of the signature on the token."), ), Categories: tokensCat, - canSkipBctx: true, + CanSkipBctx: true, } var JWTVerifyRS256 = &Builtin{ @@ -2121,7 +2122,7 @@ var JWTVerifyRS256 = &Builtin{ types.Named("result", types.B).Description("`true` if the signature is valid, `false` otherwise"), ), Categories: tokensCat, - canSkipBctx: false, + CanSkipBctx: false, } var JWTVerifyRS384 = &Builtin{ @@ -2135,7 +2136,7 @@ var JWTVerifyRS384 = &Builtin{ types.Named("result", types.B).Description("`true` if the signature is valid, `false` otherwise"), ), Categories: tokensCat, - canSkipBctx: false, + CanSkipBctx: false, } var JWTVerifyRS512 = &Builtin{ @@ -2149,7 +2150,7 @@ var JWTVerifyRS512 = &Builtin{ types.Named("result", types.B).Description("`true` if the signature is valid, `false` otherwise"), ), Categories: tokensCat, - canSkipBctx: false, + CanSkipBctx: false, } var JWTVerifyPS256 = &Builtin{ @@ -2163,7 +2164,7 @@ var JWTVerifyPS256 = &Builtin{ types.Named("result", types.B).Description("`true` if the signature is valid, `false` otherwise"), ), Categories: tokensCat, - canSkipBctx: false, + CanSkipBctx: false, } var JWTVerifyPS384 = &Builtin{ @@ -2177,7 +2178,7 @@ var JWTVerifyPS384 = &Builtin{ types.Named("result", types.B).Description("`true` if the signature is valid, `false` otherwise"), ), Categories: tokensCat, - canSkipBctx: false, + CanSkipBctx: false, } var JWTVerifyPS512 = &Builtin{ @@ -2191,7 +2192,7 @@ var JWTVerifyPS512 = &Builtin{ types.Named("result", types.B).Description("`true` if the signature is valid, `false` otherwise"), ), Categories: tokensCat, - canSkipBctx: false, + CanSkipBctx: false, } var JWTVerifyES256 = &Builtin{ @@ -2205,7 +2206,7 @@ var JWTVerifyES256 = &Builtin{ types.Named("result", types.B).Description("`true` if the signature is valid, `false` otherwise"), ), Categories: tokensCat, - canSkipBctx: false, + CanSkipBctx: false, } var JWTVerifyES384 = &Builtin{ @@ -2219,7 +2220,7 @@ var JWTVerifyES384 = &Builtin{ types.Named("result", types.B).Description("`true` if the signature is valid, `false` otherwise"), ), Categories: tokensCat, - canSkipBctx: false, + CanSkipBctx: false, } var JWTVerifyES512 = &Builtin{ @@ -2233,7 +2234,21 @@ var JWTVerifyES512 = &Builtin{ types.Named("result", types.B).Description("`true` if the signature is valid, `false` otherwise"), ), Categories: tokensCat, - canSkipBctx: false, + CanSkipBctx: false, +} + +var JWTVerifyEdDSA = &Builtin{ + Name: "io.jwt.verify_eddsa", + Description: "Verifies if an EdDSA JWT signature is valid.", + Decl: types.NewFunction( + types.Args( + types.Named("jwt", types.S).Description("JWT token whose signature is to be verified"), + types.Named("certificate", types.S).Description("PEM encoded certificate, PEM encoded public key, or the JWK key (set) used to verify the signature"), + ), + types.Named("result", types.B).Description("`true` if the signature is valid, `false` otherwise"), + ), + Categories: tokensCat, + CanSkipBctx: false, } var JWTVerifyHS256 = &Builtin{ @@ -2247,7 +2262,7 @@ var JWTVerifyHS256 = &Builtin{ types.Named("result", types.B).Description("`true` if the signature is valid, `false` otherwise"), ), Categories: tokensCat, - canSkipBctx: false, + CanSkipBctx: false, } var JWTVerifyHS384 = &Builtin{ @@ -2261,7 +2276,7 @@ var JWTVerifyHS384 = &Builtin{ types.Named("result", types.B).Description("`true` if the signature is valid, `false` otherwise"), ), Categories: tokensCat, - canSkipBctx: false, + CanSkipBctx: false, } var JWTVerifyHS512 = &Builtin{ @@ -2275,14 +2290,14 @@ var JWTVerifyHS512 = &Builtin{ types.Named("result", types.B).Description("`true` if the signature is valid, `false` otherwise"), ), Categories: tokensCat, - canSkipBctx: false, + CanSkipBctx: false, } // Marked non-deterministic because it relies on time internally. var JWTDecodeVerify = &Builtin{ Name: "io.jwt.decode_verify", Description: `Verifies a JWT signature under parameterized constraints and decodes the claims if it is valid. -Supports the following algorithms: HS256, HS384, HS512, RS256, RS384, RS512, ES256, ES384, ES512, PS256, PS384 and PS512.`, +Supports the following algorithms: HS256, HS384, HS512, RS256, RS384, RS512, ES256, ES384, ES512, PS256, PS384, PS512, and EdDSA.`, Decl: types.NewFunction( types.Args( types.Named("jwt", types.S).Description("JWT token whose signature is to be verified and whose claims are to be checked"), @@ -2296,7 +2311,7 @@ Supports the following algorithms: HS256, HS384, HS512, RS256, RS384, RS512, ES2 ), Categories: tokensCat, Nondeterministic: true, - canSkipBctx: false, + CanSkipBctx: false, } var tokenSign = category("tokensign") @@ -2315,7 +2330,7 @@ var JWTEncodeSignRaw = &Builtin{ ), Categories: tokenSign, Nondeterministic: true, - canSkipBctx: false, + CanSkipBctx: false, } // Marked non-deterministic because it relies on RNG internally. @@ -2332,7 +2347,7 @@ var JWTEncodeSign = &Builtin{ ), Categories: tokenSign, Nondeterministic: true, - canSkipBctx: false, + CanSkipBctx: false, } /** @@ -2348,7 +2363,7 @@ var NowNanos = &Builtin{ types.Named("now", types.N).Description("nanoseconds since epoch"), ), Nondeterministic: true, - canSkipBctx: false, + CanSkipBctx: false, } var ParseNanos = &Builtin{ @@ -2361,7 +2376,7 @@ var ParseNanos = &Builtin{ ), types.Named("ns", types.N).Description("`value` in nanoseconds since epoch"), ), - canSkipBctx: true, + CanSkipBctx: true, } var ParseRFC3339Nanos = &Builtin{ @@ -2373,7 +2388,7 @@ var ParseRFC3339Nanos = &Builtin{ ), types.Named("ns", types.N).Description("`value` in nanoseconds since epoch"), ), - canSkipBctx: true, + CanSkipBctx: true, } var ParseDurationNanos = &Builtin{ @@ -2385,7 +2400,7 @@ var ParseDurationNanos = &Builtin{ ), types.Named("ns", types.N).Description("the `duration` in nanoseconds"), ), - canSkipBctx: true, + CanSkipBctx: true, } var Format = &Builtin{ @@ -2401,7 +2416,7 @@ var Format = &Builtin{ ), types.Named("formatted timestamp", types.S).Description("the formatted timestamp represented for the nanoseconds since the epoch in the supplied timezone (or UTC)"), ), - canSkipBctx: true, + CanSkipBctx: true, } var Date = &Builtin{ @@ -2416,7 +2431,7 @@ var Date = &Builtin{ ), types.Named("date", types.NewArray([]types.Type{types.N, types.N, types.N}, nil)).Description("an array of `year`, `month` (1-12), and `day` (1-31)"), ), - canSkipBctx: true, + CanSkipBctx: true, } var Clock = &Builtin{ @@ -2432,7 +2447,7 @@ var Clock = &Builtin{ types.Named("output", types.NewArray([]types.Type{types.N, types.N, types.N}, nil)). Description("the `hour`, `minute` (0-59), and `second` (0-59) representing the time of day for the nanoseconds since epoch in the supplied timezone (or UTC)"), ), - canSkipBctx: true, + CanSkipBctx: true, } var Weekday = &Builtin{ @@ -2447,7 +2462,7 @@ var Weekday = &Builtin{ ), types.Named("day", types.S).Description("the weekday represented by `ns` nanoseconds since the epoch in the supplied timezone (or UTC)"), ), - canSkipBctx: true, + CanSkipBctx: true, } var AddDate = &Builtin{ @@ -2462,7 +2477,7 @@ var AddDate = &Builtin{ ), types.Named("output", types.N).Description("nanoseconds since the epoch representing the input time, with years, months and days added"), ), - canSkipBctx: true, + CanSkipBctx: true, } var Diff = &Builtin{ @@ -2481,7 +2496,7 @@ var Diff = &Builtin{ ), types.Named("output", types.NewArray([]types.Type{types.N, types.N, types.N, types.N, types.N, types.N}, nil)).Description("difference between `ns1` and `ns2` (in their supplied timezones, if supplied, or UTC) as array of numbers: `[years, months, days, hours, minutes, seconds]`"), ), - canSkipBctx: true, + CanSkipBctx: true, } /** @@ -2501,7 +2516,7 @@ concatenated PEM blocks. The whole input of concatenated PEM blocks can optional ), types.Named("output", types.NewArray(nil, types.NewObject(nil, types.NewDynamicProperty(types.S, types.A)))).Description("parsed X.509 certificates represented as objects"), ), - canSkipBctx: true, + CanSkipBctx: true, } var CryptoX509ParseAndVerifyCertificates = &Builtin{ @@ -2521,7 +2536,7 @@ with all others being treated as intermediates.`, types.NewArray(nil, types.NewObject(nil, types.NewDynamicProperty(types.S, types.A))), }, nil)).Description("array of `[valid, certs]`: if the input certificate chain could be verified then `valid` is `true` and `certs` is an array of X.509 certificates represented as objects; if the input certificate chain could not be verified then `valid` is `false` and `certs` is `[]`"), ), - canSkipBctx: true, + CanSkipBctx: true, } var CryptoX509ParseAndVerifyCertificatesWithOptions = &Builtin{ @@ -2546,7 +2561,7 @@ with all others being treated as intermediates.`, types.NewArray(nil, types.NewObject(nil, types.NewDynamicProperty(types.S, types.A))), }, nil)).Description("array of `[valid, certs]`: if the input certificate chain could be verified then `valid` is `true` and `certs` is an array of X.509 certificates represented as objects; if the input certificate chain could not be verified then `valid` is `false` and `certs` is `[]`"), ), - canSkipBctx: true, + CanSkipBctx: true, } var CryptoX509ParseCertificateRequest = &Builtin{ @@ -2558,7 +2573,7 @@ var CryptoX509ParseCertificateRequest = &Builtin{ ), types.Named("output", types.NewObject(nil, types.NewDynamicProperty(types.S, types.A))).Description("X.509 CSR represented as an object"), ), - canSkipBctx: true, + CanSkipBctx: true, } var CryptoX509ParseKeyPair = &Builtin{ @@ -2571,8 +2586,9 @@ var CryptoX509ParseKeyPair = &Builtin{ ), types.Named("output", types.NewObject(nil, types.NewDynamicProperty(types.S, types.A))).Description("if key pair is valid, returns the tls.certificate(https://pkg.go.dev/crypto/tls#Certificate) as an object. If the key pair is invalid, nil and an error are returned."), ), - canSkipBctx: true, + CanSkipBctx: true, } + var CryptoX509ParseRSAPrivateKey = &Builtin{ Name: "crypto.x509.parse_rsa_private_key", Description: "Returns a JWK for signing a JWT from the given PEM-encoded RSA private key.", @@ -2582,7 +2598,7 @@ var CryptoX509ParseRSAPrivateKey = &Builtin{ ), types.Named("output", types.NewObject(nil, types.NewDynamicProperty(types.S, types.A))).Description("JWK as an object"), ), - canSkipBctx: true, + CanSkipBctx: true, } var CryptoParsePrivateKeys = &Builtin{ @@ -2596,7 +2612,7 @@ If the input is empty, the function will return null. The input string should be ), types.Named("output", types.NewArray(nil, types.NewObject(nil, types.NewDynamicProperty(types.S, types.A)))).Description("parsed private keys represented as objects"), ), - canSkipBctx: true, + CanSkipBctx: true, } var CryptoMd5 = &Builtin{ @@ -2608,7 +2624,7 @@ var CryptoMd5 = &Builtin{ ), types.Named("y", types.S).Description("MD5-hash of `x`"), ), - canSkipBctx: true, + CanSkipBctx: true, } var CryptoSha1 = &Builtin{ @@ -2620,7 +2636,7 @@ var CryptoSha1 = &Builtin{ ), types.Named("y", types.S).Description("SHA1-hash of `x`"), ), - canSkipBctx: true, + CanSkipBctx: true, } var CryptoSha256 = &Builtin{ @@ -2632,7 +2648,7 @@ var CryptoSha256 = &Builtin{ ), types.Named("y", types.S).Description("SHA256-hash of `x`"), ), - canSkipBctx: true, + CanSkipBctx: true, } var CryptoHmacMd5 = &Builtin{ @@ -2645,7 +2661,7 @@ var CryptoHmacMd5 = &Builtin{ ), types.Named("y", types.S).Description("MD5-HMAC of `x`"), ), - canSkipBctx: true, + CanSkipBctx: true, } var CryptoHmacSha1 = &Builtin{ @@ -2658,7 +2674,7 @@ var CryptoHmacSha1 = &Builtin{ ), types.Named("y", types.S).Description("SHA1-HMAC of `x`"), ), - canSkipBctx: true, + CanSkipBctx: true, } var CryptoHmacSha256 = &Builtin{ @@ -2671,7 +2687,7 @@ var CryptoHmacSha256 = &Builtin{ ), types.Named("y", types.S).Description("SHA256-HMAC of `x`"), ), - canSkipBctx: true, + CanSkipBctx: true, } var CryptoHmacSha512 = &Builtin{ @@ -2684,7 +2700,7 @@ var CryptoHmacSha512 = &Builtin{ ), types.Named("y", types.S).Description("SHA512-HMAC of `x`"), ), - canSkipBctx: true, + CanSkipBctx: true, } var CryptoHmacEqual = &Builtin{ @@ -2697,7 +2713,7 @@ var CryptoHmacEqual = &Builtin{ ), types.Named("result", types.B).Description("`true` if the MACs are equals, `false` otherwise"), ), - canSkipBctx: true, + CanSkipBctx: true, } /** @@ -2722,7 +2738,7 @@ var WalkBuiltin = &Builtin{ )).Description("pairs of `path` and `value`: `path` is an array representing the pointer to `value` in `x`. If `path` is assigned a wildcard (`_`), the `walk` function will skip path creation entirely for faster evaluation."), ), Categories: graphs, - canSkipBctx: true, + CanSkipBctx: true, } var ReachableBuiltin = &Builtin{ @@ -2743,7 +2759,7 @@ var ReachableBuiltin = &Builtin{ ), types.Named("output", types.SetOfAny).Description("set of vertices reachable from the `initial` vertices in the directed `graph`"), ), - canSkipBctx: true, + CanSkipBctx: true, } var ReachablePathsBuiltin = &Builtin{ @@ -2764,7 +2780,7 @@ var ReachablePathsBuiltin = &Builtin{ ), types.Named("output", types.NewSet(types.NewArray(nil, types.A))).Description("paths reachable from the `initial` vertices in the directed `graph`"), ), - canSkipBctx: true, + CanSkipBctx: true, } /** @@ -2782,7 +2798,7 @@ var IsNumber = &Builtin{ types.Named("result", types.B).Description("`true` if `x` is a number, `false` otherwise."), ), Categories: typesCat, - canSkipBctx: true, + CanSkipBctx: true, } var IsString = &Builtin{ @@ -2795,7 +2811,7 @@ var IsString = &Builtin{ types.Named("result", types.B).Description("`true` if `x` is a string, `false` otherwise."), ), Categories: typesCat, - canSkipBctx: true, + CanSkipBctx: true, } var IsBoolean = &Builtin{ @@ -2808,7 +2824,7 @@ var IsBoolean = &Builtin{ types.Named("result", types.B).Description("`true` if `x` is an boolean, `false` otherwise."), ), Categories: typesCat, - canSkipBctx: true, + CanSkipBctx: true, } var IsArray = &Builtin{ @@ -2821,7 +2837,7 @@ var IsArray = &Builtin{ types.Named("result", types.B).Description("`true` if `x` is an array, `false` otherwise."), ), Categories: typesCat, - canSkipBctx: true, + CanSkipBctx: true, } var IsSet = &Builtin{ @@ -2834,7 +2850,7 @@ var IsSet = &Builtin{ types.Named("result", types.B).Description("`true` if `x` is a set, `false` otherwise."), ), Categories: typesCat, - canSkipBctx: true, + CanSkipBctx: true, } var IsObject = &Builtin{ @@ -2847,7 +2863,7 @@ var IsObject = &Builtin{ types.Named("result", types.B).Description("`true` if `x` is an object, `false` otherwise."), ), Categories: typesCat, - canSkipBctx: true, + CanSkipBctx: true, } var IsNull = &Builtin{ @@ -2860,7 +2876,7 @@ var IsNull = &Builtin{ types.Named("result", types.B).Description("`true` if `x` is null, `false` otherwise."), ), Categories: typesCat, - canSkipBctx: true, + CanSkipBctx: true, } /** @@ -2878,7 +2894,7 @@ var TypeNameBuiltin = &Builtin{ types.Named("type", types.S).Description(`one of "null", "boolean", "number", "string", "array", "object", "set"`), ), Categories: typesCat, - canSkipBctx: true, + CanSkipBctx: true, } /** @@ -2898,7 +2914,7 @@ var HTTPSend = &Builtin{ Description("the HTTP response object"), ), Nondeterministic: true, - canSkipBctx: false, + CanSkipBctx: false, } /** @@ -2921,7 +2937,7 @@ var GraphQLParse = &Builtin{ types.NewObject(nil, types.NewDynamicProperty(types.A, types.A)), }, nil)).Description("`output` is of the form `[query_ast, schema_ast]`. If the GraphQL query is valid given the provided schema, then `query_ast` and `schema_ast` are objects describing the ASTs for the query and schema."), ), - canSkipBctx: false, + CanSkipBctx: false, } // GraphQLParseAndVerify returns a boolean and a pair of AST object from parsing/validation. @@ -2941,7 +2957,7 @@ var GraphQLParseAndVerify = &Builtin{ types.NewObject(nil, types.NewDynamicProperty(types.A, types.A)), }, nil)).Description(" `output` is of the form `[valid, query_ast, schema_ast]`. If the query is valid given the provided schema, then `valid` is `true`, and `query_ast` and `schema_ast` are objects describing the ASTs for the GraphQL query and schema. Otherwise, `valid` is `false` and `query_ast` and `schema_ast` are `{}`."), ), - canSkipBctx: false, + CanSkipBctx: false, } // GraphQLParseQuery parses the input GraphQL query and returns a JSON @@ -2955,7 +2971,7 @@ var GraphQLParseQuery = &Builtin{ ), types.Named("output", types.NewObject(nil, types.NewDynamicProperty(types.A, types.A))).Description("AST object for the GraphQL query."), ), - canSkipBctx: true, + CanSkipBctx: true, } // GraphQLParseSchema parses the input GraphQL schema and returns a JSON @@ -2969,7 +2985,7 @@ var GraphQLParseSchema = &Builtin{ ), types.Named("output", types.NewObject(nil, types.NewDynamicProperty(types.A, types.A))).Description("AST object for the GraphQL schema."), ), - canSkipBctx: false, + CanSkipBctx: false, } // GraphQLIsValid returns true if a GraphQL query is valid with a given @@ -2986,7 +3002,7 @@ var GraphQLIsValid = &Builtin{ ), types.Named("output", types.B).Description("`true` if the query is valid under the given schema. `false` otherwise."), ), - canSkipBctx: false, + CanSkipBctx: false, } // GraphQLSchemaIsValid returns true if the input is valid GraphQL schema, @@ -3001,7 +3017,7 @@ var GraphQLSchemaIsValid = &Builtin{ ), types.Named("output", types.B).Description("`true` if the schema is a valid GraphQL schema. `false` otherwise."), ), - canSkipBctx: false, + CanSkipBctx: false, } /** @@ -3025,7 +3041,7 @@ var JSONSchemaVerify = &Builtin{ Description("`output` is of the form `[valid, error]`. If the schema is valid, then `valid` is `true`, and `error` is `null`. Otherwise, `valid` is `false` and `error` is a string describing the error."), ), Categories: objectCat, - canSkipBctx: true, + CanSkipBctx: true, } // JSONMatchSchema returns empty array if the document matches the JSON schema, @@ -3057,7 +3073,7 @@ var JSONMatchSchema = &Builtin{ Description("`output` is of the form `[match, errors]`. If the document is valid given the schema, then `match` is `true`, and `errors` is an empty array. Otherwise, `match` is `false` and `errors` is an array of objects describing the error(s)."), ), Categories: objectCat, - canSkipBctx: false, + CanSkipBctx: false, } /** @@ -3080,7 +3096,7 @@ var ProvidersAWSSignReqObj = &Builtin{ Description("HTTP request object with `Authorization` header"), ), Categories: providersAWSCat, - canSkipBctx: true, + CanSkipBctx: true, } /** @@ -3098,7 +3114,7 @@ var RegoParseModule = &Builtin{ types.Named("output", types.NewObject(nil, types.NewDynamicProperty(types.S, types.A))). Description("AST object for the Rego module"), ), - canSkipBctx: true, + CanSkipBctx: true, } var RegoMetadataChain = &Builtin{ @@ -3111,7 +3127,7 @@ The first entry in the chain always points to the active rule, even if it has no types.Args(), types.Named("chain", types.NewArray(nil, types.A)).Description("each array entry represents a node in the path ancestry (chain) of the active rule that also has declared annotations"), ), - canSkipBctx: true, + CanSkipBctx: true, } // RegoMetadataRule returns the metadata for the active rule @@ -3122,7 +3138,7 @@ var RegoMetadataRule = &Builtin{ types.Args(), types.Named("output", types.A).Description("\"rule\" scope annotations for this rule; empty object if no annotations exist"), ), - canSkipBctx: true, + CanSkipBctx: true, } /** @@ -3139,7 +3155,7 @@ var OPARuntime = &Builtin{ Description("includes a `config` key if OPA was started with a configuration file; an `env` key containing the environment variables that the OPA process was started with; includes `version` and `commit` keys containing the version and build commit of OPA."), ), Nondeterministic: true, - canSkipBctx: false, + CanSkipBctx: false, } /** @@ -3157,7 +3173,7 @@ var Trace = &Builtin{ types.Named("result", types.B).Description("always `true`"), ), Categories: tracing, - canSkipBctx: false, + CanSkipBctx: false, } /** @@ -3172,13 +3188,13 @@ var GlobMatch = &Builtin{ types.Named("pattern", types.S).Description("glob pattern"), types.Named("delimiters", types.NewAny( types.NewArray(nil, types.S), - types.NewNull(), + types.Nl, )).Description("glob pattern delimiters, e.g. `[\".\", \":\"]`, defaults to `[\".\"]` if unset. If `delimiters` is `null`, glob match without delimiter."), types.Named("match", types.S).Description("string to match against `pattern`"), ), types.Named("result", types.B).Description("true if `match` can be found in `pattern` which is separated by `delimiters`"), ), - canSkipBctx: false, + CanSkipBctx: false, } var GlobQuoteMeta = &Builtin{ @@ -3190,7 +3206,7 @@ var GlobQuoteMeta = &Builtin{ ), types.Named("output", types.S).Description("the escaped string of `pattern`"), ), - canSkipBctx: true, + CanSkipBctx: true, // TODO(sr): example for this was: Calling ``glob.quote_meta("*.github.com", output)`` returns ``\\*.github.com`` as ``output``. } @@ -3208,7 +3224,7 @@ var NetCIDRIntersects = &Builtin{ ), types.Named("result", types.B).Description("`true` if `cidr1` intersects with `cidr2`"), ), - canSkipBctx: true, + CanSkipBctx: true, } var NetCIDRExpand = &Builtin{ @@ -3220,7 +3236,7 @@ var NetCIDRExpand = &Builtin{ ), types.Named("hosts", types.SetOfStr).Description("set of IP addresses the CIDR `cidr` expands to"), ), - canSkipBctx: false, + CanSkipBctx: false, } var NetCIDRContains = &Builtin{ @@ -3233,7 +3249,7 @@ var NetCIDRContains = &Builtin{ ), types.Named("result", types.B).Description("`true` if `cidr_or_ip` is contained within `cidr`"), ), - canSkipBctx: true, + CanSkipBctx: true, } var NetCIDRContainsMatches = &Builtin{ @@ -3247,7 +3263,7 @@ var NetCIDRContainsMatches = &Builtin{ ), types.Named("output", types.NewSet(types.NewArray([]types.Type{types.A, types.A}, nil))).Description("tuples identifying matches where `cidrs_or_ips` are contained within `cidrs`"), ), - canSkipBctx: true, + CanSkipBctx: true, } var NetCIDRMerge = &Builtin{ @@ -3264,7 +3280,7 @@ Supports both IPv4 and IPv6 notations. IPv6 inputs need a prefix length (e.g. "/ ), types.Named("output", types.SetOfStr).Description("smallest possible set of CIDRs obtained after merging the provided list of IP addresses and subnets in `addrs`"), ), - canSkipBctx: true, + CanSkipBctx: true, } var NetCIDRIsValid = &Builtin{ @@ -3276,7 +3292,7 @@ var NetCIDRIsValid = &Builtin{ ), types.Named("result", types.B).Description("`true` if `cidr` is a valid CIDR"), ), - canSkipBctx: true, + CanSkipBctx: true, } var netCidrContainsMatchesOperandType = types.NewAny( @@ -3309,7 +3325,7 @@ var NetLookupIPAddr = &Builtin{ types.Named("addrs", types.SetOfStr).Description("IP addresses (v4 and v6) that `name` resolves to"), ), Nondeterministic: true, - canSkipBctx: false, + CanSkipBctx: false, } /** @@ -3325,7 +3341,7 @@ var SemVerIsValid = &Builtin{ ), types.Named("result", types.B).Description("`true` if `vsn` is a valid SemVer; `false` otherwise"), ), - canSkipBctx: true, + CanSkipBctx: true, } var SemVerCompare = &Builtin{ @@ -3338,7 +3354,7 @@ var SemVerCompare = &Builtin{ ), types.Named("result", types.N).Description("`-1` if `a < b`; `1` if `a > b`; `0` if `a == b`"), ), - canSkipBctx: true, + CanSkipBctx: true, } /** @@ -3382,7 +3398,7 @@ var SetDiff = &Builtin{ types.SetOfAny, ), deprecated: true, - canSkipBctx: true, + CanSkipBctx: true, } // NetCIDROverlap has been replaced by the `net.cidr_contains` built-in. @@ -3396,7 +3412,7 @@ var NetCIDROverlap = &Builtin{ types.B, ), deprecated: true, - canSkipBctx: true, + CanSkipBctx: true, } // CastArray checks the underlying type of the input. If it is array or set, an array @@ -3408,7 +3424,7 @@ var CastArray = &Builtin{ types.NewArray(nil, types.A), ), deprecated: true, - canSkipBctx: true, + CanSkipBctx: true, } // CastSet checks the underlying type of the input. @@ -3422,7 +3438,7 @@ var CastSet = &Builtin{ types.SetOfAny, ), deprecated: true, - canSkipBctx: true, + CanSkipBctx: true, } // CastString returns input if it is a string; if not returns error. @@ -3434,7 +3450,7 @@ var CastString = &Builtin{ types.S, ), deprecated: true, - canSkipBctx: true, + CanSkipBctx: true, } // CastBoolean returns input if it is a boolean; if not returns error. @@ -3445,7 +3461,7 @@ var CastBoolean = &Builtin{ types.B, ), deprecated: true, - canSkipBctx: true, + CanSkipBctx: true, } // CastNull returns null if input is null; if not returns error. @@ -3453,10 +3469,10 @@ var CastNull = &Builtin{ Name: "cast_null", Decl: types.NewFunction( types.Args(types.A), - types.NewNull(), + types.Nl, ), deprecated: true, - canSkipBctx: true, + CanSkipBctx: true, } // CastObject returns the given object if it is null; throws an error otherwise @@ -3467,7 +3483,7 @@ var CastObject = &Builtin{ types.NewObject(nil, types.NewDynamicProperty(types.A, types.A)), ), deprecated: true, - canSkipBctx: true, + CanSkipBctx: true, } // RegexMatchDeprecated declares `re_match` which has been deprecated. Use `regex.match` instead. @@ -3481,7 +3497,7 @@ var RegexMatchDeprecated = &Builtin{ types.B, ), deprecated: true, - canSkipBctx: false, + CanSkipBctx: false, } // All takes a list and returns true if all of the items @@ -3498,7 +3514,7 @@ var All = &Builtin{ types.B, ), deprecated: true, - canSkipBctx: true, + CanSkipBctx: true, } // Any takes a collection and returns true if any of the items @@ -3515,7 +3531,7 @@ var Any = &Builtin{ types.B, ), deprecated: true, - canSkipBctx: true, + CanSkipBctx: true, } // Builtin represents a built-in function supported by OPA. Every built-in @@ -3529,11 +3545,11 @@ type Builtin struct { // "minus" for example, is part of two categories: numbers and sets. (NOTE(sr): aspirational) Categories []string `json:"categories,omitempty"` - Decl *types.Function `json:"decl"` // Built-in function type declaration. - Infix string `json:"infix,omitempty"` // Unique name of infix operator. Default should be unset. - Relation bool `json:"relation,omitempty"` // Indicates if the built-in acts as a relation. - deprecated bool // Indicates if the built-in has been deprecated. - canSkipBctx bool // Built-in needs no data from the built-in context. + Decl *types.Function `json:"decl"` // Built-in function type declaration. + Infix string `json:"infix,omitempty"` // Unique name of infix operator. Default should be unset. + Relation bool `json:"relation,omitempty"` // Indicates if the built-in acts as a relation. + deprecated bool `json:"-"` // Indicates if the built-in has been deprecated. + CanSkipBctx bool `json:"-"` // Built-in needs no data from the built-in context. Nondeterministic bool `json:"nondeterministic,omitempty"` // Indicates if the built-in returns non-deterministic results. } @@ -3610,7 +3626,7 @@ func (b *Builtin) IsTargetPos(i int) bool { func (b *Builtin) NeedsBuiltInContext() bool { // Negated, so built-ins we don't know about (and who don't know about this option) // will get a built-in context provided to them. - return !b.canSkipBctx + return !b.CanSkipBctx } func init() { diff --git a/vendor/github.com/open-policy-agent/opa/v1/ast/capabilities.go b/vendor/github.com/open-policy-agent/opa/v1/ast/capabilities.go index a9925058622..844cb66f0ba 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/ast/capabilities.go +++ b/vendor/github.com/open-policy-agent/opa/v1/ast/capabilities.go @@ -14,6 +14,7 @@ import ( "slices" "sort" "strings" + "sync" "github.com/open-policy-agent/opa/internal/semver" "github.com/open-policy-agent/opa/internal/wasm/sdk/opa/capabilities" @@ -38,14 +39,15 @@ type VersionIndex struct { //go:embed version_index.json var versionIndexBs []byte -var minVersionIndex = func() VersionIndex { +// init only on demand, as JSON unmarshalling comes with some cost, and contributes +// noise to things like pprof stats +var minVersionIndexOnce = sync.OnceValue(func() VersionIndex { var vi VersionIndex - err := json.Unmarshal(versionIndexBs, &vi) - if err != nil { + if err := json.Unmarshal(versionIndexBs, &vi); err != nil { panic(err) } return vi -}() +}) // In the compiler, we used this to check that we're OK working with ref heads. // If this isn't present, we'll fail. This is to ensure that older versions of @@ -57,6 +59,24 @@ const FeatureRegoV1 = "rego_v1" const FeatureRegoV1Import = "rego_v1_import" const FeatureKeywordsInRefs = "keywords_in_refs" +// Features carries the default features supported by this version of OPA. +// Use RegisterFeatures to add to them. +var Features = []string{ + FeatureRegoV1, + FeatureKeywordsInRefs, +} + +// RegisterFeatures lets applications wrapping OPA register features, to be +// included in `ast.CapabilitiesForThisVersion()`. +func RegisterFeatures(fs ...string) { + for i := range fs { + if slices.Contains(Features, fs[i]) { + continue + } + Features = append(Features, fs[i]) + } +} + // Capabilities defines a structure containing data that describes the capabilities // or features supported by a particular version of OPA. type Capabilities struct { @@ -75,7 +95,6 @@ type Capabilities struct { // As of now, this only controls fetching remote refs for using JSON Schemas in // the type checker. // TODO(sr): support ports to further restrict connection peers - // TODO(sr): support restricting `http.send` using the same mechanism (see https://github.com/open-policy-agent/opa/issues/3665) AllowNet []string `json:"allow_net,omitempty"` } @@ -141,10 +160,8 @@ func CapabilitiesForThisVersion(opts ...CapabilitiesOption) *Capabilities { f.FutureKeywords = append(f.FutureKeywords, kw) } - f.Features = []string{ - FeatureRegoV1, - FeatureKeywordsInRefs, - } + f.Features = make([]string, len(Features)) + copy(f.Features, Features) } sort.Strings(f.FutureKeywords) @@ -202,13 +219,15 @@ func LoadCapabilitiesVersions() ([]string, error) { for _, ent := range ents { capabilitiesVersions = append(capabilitiesVersions, strings.Replace(ent.Name(), ".json", "", 1)) } + + slices.SortStableFunc(capabilitiesVersions, semver.Compare) + return capabilitiesVersions, nil } // MinimumCompatibleVersion returns the minimum compatible OPA version based on // the built-ins, features, and keywords in c. func (c *Capabilities) MinimumCompatibleVersion() (string, bool) { - var maxVersion semver.Version // this is the oldest OPA release that includes capabilities @@ -216,6 +235,8 @@ func (c *Capabilities) MinimumCompatibleVersion() (string, bool) { panic("unreachable") } + minVersionIndex := minVersionIndexOnce() + for _, bi := range c.Builtins { v, ok := minVersionIndex.Builtins[bi.Name] if !ok { diff --git a/vendor/github.com/open-policy-agent/opa/v1/ast/check.go b/vendor/github.com/open-policy-agent/opa/v1/ast/check.go index e3d2051a269..0da7e26514f 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/ast/check.go +++ b/vendor/github.com/open-policy-agent/opa/v1/ast/check.go @@ -310,7 +310,7 @@ func (tc *typeChecker) checkRule(env *TypeEnv, as *AnnotationSet, rule *Rule) { var err error tpe, err = nestedObject(cpy, objPath, typeV) if err != nil { - tc.err([]*Error{NewError(TypeErr, rule.Head.Location, err.Error())}) //nolint:govet + tc.err([]*Error{NewError(TypeErr, rule.Head.Location, "%s", err.Error())}) tpe = nil } } else if typeV != nil { @@ -1318,7 +1318,7 @@ func processAnnotation(ss *SchemaSet, annot *SchemaAnnotation, rule *Rule, allow tpe, err := loadSchema(schema, allowNet) if err != nil { - return nil, NewError(TypeErr, rule.Location, err.Error()) //nolint:govet + return nil, NewError(TypeErr, rule.Location, "%s", err.Error()) } return tpe, nil diff --git a/vendor/github.com/open-policy-agent/opa/v1/ast/compare.go b/vendor/github.com/open-policy-agent/opa/v1/ast/compare.go index c4754341de4..663ad5ae057 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/ast/compare.go +++ b/vendor/github.com/open-policy-agent/opa/v1/ast/compare.go @@ -5,9 +5,10 @@ package ast import ( - "encoding/json" + "cmp" "fmt" "math/big" + "strings" ) // Compare returns an integer indicating whether two AST values are less than, @@ -77,8 +78,7 @@ func Compare(a, b any) int { case Null: return 0 case Boolean: - b := b.(Boolean) - if a.Equal(b) { + if a == b.(Boolean) { return 0 } if !a { @@ -86,64 +86,10 @@ func Compare(a, b any) int { } return 1 case Number: - if ai, err := json.Number(a).Int64(); err == nil { - if bi, err := json.Number(b.(Number)).Int64(); err == nil { - if ai == bi { - return 0 - } - if ai < bi { - return -1 - } - return 1 - } - } - - // We use big.Rat for comparing big numbers. - // It replaces big.Float due to following reason: - // big.Float comes with a default precision of 64, and setting a - // larger precision results in more memory being allocated - // (regardless of the actual number we are parsing with SetString). - // - // Note: If we're so close to zero that big.Float says we are zero, do - // *not* big.Rat).SetString on the original string it'll potentially - // take very long. - var bigA, bigB *big.Rat - fa, ok := new(big.Float).SetString(string(a)) - if !ok { - panic("illegal value") - } - if fa.IsInt() { - if i, _ := fa.Int64(); i == 0 { - bigA = new(big.Rat).SetInt64(0) - } - } - if bigA == nil { - bigA, ok = new(big.Rat).SetString(string(a)) - if !ok { - panic("illegal value") - } - } - - fb, ok := new(big.Float).SetString(string(b.(Number))) - if !ok { - panic("illegal value") - } - if fb.IsInt() { - if i, _ := fb.Int64(); i == 0 { - bigB = new(big.Rat).SetInt64(0) - } - } - if bigB == nil { - bigB, ok = new(big.Rat).SetString(string(b.(Number))) - if !ok { - panic("illegal value") - } - } - - return bigA.Cmp(bigB) + return NumberCompare(a, b.(Number)) case String: b := b.(String) - if a.Equal(b) { + if a == b { return 0 } if a < b { @@ -153,8 +99,7 @@ func Compare(a, b any) int { case Var: return VarCompare(a, b.(Var)) case Ref: - b := b.(Ref) - return termSliceCompare(a, b) + return termSliceCompare(a, b.(Ref)) case *Array: b := b.(*Array) return termSliceCompare(a.elems, b.elems) @@ -164,11 +109,9 @@ func Compare(a, b any) int { if x, ok := b.(*lazyObj); ok { b = x.force() } - b := b.(*object) - return a.Compare(b) + return a.Compare(b.(*object)) case Set: - b := b.(Set) - return a.Compare(b) + return a.Compare(b.(Set)) case *ArrayComprehension: b := b.(*ArrayComprehension) if cmp := Compare(a.Term, b.Term); cmp != 0 { @@ -191,44 +134,31 @@ func Compare(a, b any) int { } return a.Body.Compare(b.Body) case Call: - b := b.(Call) - return termSliceCompare(a, b) + return termSliceCompare(a, b.(Call)) case *Expr: - b := b.(*Expr) - return a.Compare(b) + return a.Compare(b.(*Expr)) case *SomeDecl: - b := b.(*SomeDecl) - return a.Compare(b) + return a.Compare(b.(*SomeDecl)) case *Every: - b := b.(*Every) - return a.Compare(b) + return a.Compare(b.(*Every)) case *With: - b := b.(*With) - return a.Compare(b) + return a.Compare(b.(*With)) case Body: - b := b.(Body) - return a.Compare(b) + return a.Compare(b.(Body)) case *Head: - b := b.(*Head) - return a.Compare(b) + return a.Compare(b.(*Head)) case *Rule: - b := b.(*Rule) - return a.Compare(b) + return a.Compare(b.(*Rule)) case Args: - b := b.(Args) - return termSliceCompare(a, b) + return termSliceCompare(a, b.(Args)) case *Import: - b := b.(*Import) - return a.Compare(b) + return a.Compare(b.(*Import)) case *Package: - b := b.(*Package) - return a.Compare(b) + return a.Compare(b.(*Package)) case *Annotations: - b := b.(*Annotations) - return a.Compare(b) + return a.Compare(b.(*Annotations)) case *Module: - b := b.(*Module) - return a.Compare(b) + return a.Compare(b.(*Module)) } panic(fmt.Sprintf("illegal value: %T", a)) } @@ -427,3 +357,84 @@ func RefCompare(a, b Ref) int { func RefEqual(a, b Ref) bool { return termSliceEqual(a, b) } + +func NumberCompare(x, y Number) int { + xs, ys := string(x), string(y) + + var xIsF, yIsF bool + + // Treat "1" and "1.0", "1.00", etc as "1" + if strings.Contains(xs, ".") { + if tx := strings.TrimRight(xs, ".0"); tx != xs { + // Still a float after trimming? + xIsF = strings.Contains(tx, ".") + xs = tx + } + } + if strings.Contains(ys, ".") { + if ty := strings.TrimRight(ys, ".0"); ty != ys { + yIsF = strings.Contains(ty, ".") + ys = ty + } + } + if xs == ys { + return 0 + } + + var xi, yi int64 + var xf, yf float64 + var xiOK, yiOK, xfOK, yfOK bool + + if xi, xiOK = x.Int64(); xiOK { + if yi, yiOK = y.Int64(); yiOK { + return cmp.Compare(xi, yi) + } + } + + if xIsF && yIsF { + if xf, xfOK = x.Float64(); xfOK { + if yf, yfOK = y.Float64(); yfOK { + if xf == yf { + return 0 + } + // could still be "equal" depending on precision, so we continue? + } + } + } + + var a *big.Rat + fa, ok := new(big.Float).SetString(string(x)) + if !ok { + panic("illegal value") + } + if fa.IsInt() { + if i, _ := fa.Int64(); i == 0 { + a = new(big.Rat).SetInt64(0) + } + } + if a == nil { + a, ok = new(big.Rat).SetString(string(x)) + if !ok { + panic("illegal value") + } + } + + var b *big.Rat + fb, ok := new(big.Float).SetString(string(y)) + if !ok { + panic("illegal value") + } + if fb.IsInt() { + if i, _ := fb.Int64(); i == 0 { + b = new(big.Rat).SetInt64(0) + } + } + if b == nil { + b, ok = new(big.Rat).SetString(string(y)) + if !ok { + panic("illegal value") + } + } + + return a.Cmp(b) +} diff --git a/vendor/github.com/open-policy-agent/opa/v1/ast/compile.go b/vendor/github.com/open-policy-agent/opa/v1/ast/compile.go index f3ca101735c..62e22bf9376 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/ast/compile.go +++ b/vendor/github.com/open-policy-agent/opa/v1/ast/compile.go @@ -26,7 +26,11 @@ import ( // exiting. const CompileErrorLimitDefault = 10 -var errLimitReached = NewError(CompileErr, nil, "error limit reached") +var ( + errLimitReached = NewError(CompileErr, nil, "error limit reached") + + doubleEq = Equal.Ref() +) // Compiler contains the state of a compilation process. type Compiler struct { @@ -850,7 +854,7 @@ func (c *Compiler) PassesTypeCheckRules(rules []*Rule) Errors { tpe, err := loadSchema(schema, allowNet) if err != nil { - return Errors{NewError(TypeErr, nil, err.Error())} //nolint:govet + return Errors{NewError(TypeErr, nil, "%s", err.Error())} } c.inputType = tpe } @@ -955,8 +959,10 @@ func (c *Compiler) buildRuleIndices() { func (c *Compiler) buildComprehensionIndices() { for _, name := range c.sorted { WalkRules(c.Modules[name], func(r *Rule) bool { - candidates := r.Head.Args.Vars() - candidates.Update(ReservedVars) + candidates := ReservedVars.Copy() + if len(r.Head.Args) > 0 { + candidates.Update(r.Head.Args.Vars()) + } n := buildComprehensionIndices(c.debug, c.GetArity, candidates, c.RewrittenVars, r.Body, c.comprehensionIndices) c.counterAdd(compileStageComprehensionIndexBuild, n) return false @@ -1207,7 +1213,7 @@ func (c *Compiler) checkRuleConflicts() { continue // don't self-conflict } msg := fmt.Sprintf("%v conflicts with rule %v defined at %v", childMod.Package, rule.Head.Ref(), rule.Loc()) - c.err(NewError(TypeErr, mod.Package.Loc(), msg)) //nolint:govet + c.err(NewError(TypeErr, mod.Package.Loc(), "%s", msg)) } } } @@ -1281,7 +1287,9 @@ func (c *Compiler) checkSafetyRuleBodies() { m := c.Modules[name] WalkRules(m, func(r *Rule) bool { safe := ReservedVars.Copy() - safe.Update(r.Head.Args.Vars()) + if len(r.Head.Args) > 0 { + safe.Update(r.Head.Args.Vars()) + } r.Body = c.checkBodySafety(safe, r.Body) return false }) @@ -1310,19 +1318,24 @@ var SafetyCheckVisitorParams = VarVisitorParams{ // checkSafetyRuleHeads ensures that variables appearing in the head of a // rule also appear in the body. func (c *Compiler) checkSafetyRuleHeads() { - for _, name := range c.sorted { - m := c.Modules[name] - WalkRules(m, func(r *Rule) bool { + WalkRules(c.Modules[name], func(r *Rule) bool { safe := r.Body.Vars(SafetyCheckVisitorParams) - safe.Update(r.Head.Args.Vars()) - unsafe := r.Head.Vars().Diff(safe) - for v := range unsafe { - if w, ok := c.RewrittenVars[v]; ok { - v = w - } - if !v.IsGenerated() { - c.err(NewError(UnsafeVarErr, r.Loc(), "var %v is unsafe", v)) + if len(r.Head.Args) > 0 { + safe.Update(r.Head.Args.Vars()) + } + if headMayHaveVars(r.Head) { + vars := r.Head.Vars() + if vars.DiffCount(safe) > 0 { + unsafe := vars.Diff(safe) + for v := range unsafe { + if w, ok := c.RewrittenVars[v]; ok { + v = w + } + if !v.IsGenerated() { + c.err(NewError(UnsafeVarErr, r.Loc(), "var %v is unsafe", v)) + } + } } } return false @@ -1681,6 +1694,31 @@ func (c *Compiler) init() { return } + if defaultModuleLoader != nil { + if c.moduleLoader == nil { + c.moduleLoader = defaultModuleLoader + } else { + first := c.moduleLoader + c.moduleLoader = func(res map[string]*Module) (map[string]*Module, error) { + res0, err := first(res) + if err != nil { + return nil, err + } + res1, err := defaultModuleLoader(res) + if err != nil { + return nil, err + } + // merge res1 into res0, based on module "file" names, to avoid clashes + for k, v := range res1 { + if _, ok := res0[k]; !ok { + res0[k] = v + } + } + return res0, nil + } + } + } + if c.capabilities == nil { c.capabilities = CapabilitiesForThisVersion() } @@ -1701,7 +1739,7 @@ func (c *Compiler) init() { if schema := c.schemaSet.Get(SchemaRootRef); schema != nil { tpe, err := loadSchema(schema, c.capabilities.AllowNet) if err != nil { - c.err(NewError(TypeErr, nil, err.Error())) //nolint:govet + c.err(NewError(TypeErr, nil, "%s", err.Error())) } else { c.inputType = tpe } @@ -1869,7 +1907,7 @@ func (c *Compiler) resolveAllRefs() { WalkRules(mod, func(rule *Rule) bool { err := resolveRefsInRule(globals, rule) if err != nil { - c.err(NewError(CompileErr, rule.Location, err.Error())) //nolint:govet + c.err(NewError(CompileErr, rule.Location, "%s", err.Error())) } return false }) @@ -1894,7 +1932,7 @@ func (c *Compiler) resolveAllRefs() { parsed, err := c.moduleLoader(c.Modules) if err != nil { - c.err(NewError(CompileErr, nil, err.Error())) //nolint:govet + c.err(NewError(CompileErr, nil, "%s", err.Error())) return } @@ -2125,14 +2163,27 @@ func rewritePrintCalls(gen *localVarGenerator, getArity func(Ref) int, globals V var errs Errors safe := outputVarsForBody(body[:i], getArity, globals) safe.Update(globals) + + // Fixes Issue #7647 by adding generated variables to the safe set + WalkVars(body[:i], func(v Var) bool { + if v.IsGenerated() { + safe.Add(v) + } + return false + }) + args := body[i].Operands() + var vis *VarVisitor for j := range args { - vis := NewVarVisitor().WithParams(SafetyCheckVisitorParams) + vis = vis.ClearOrNew().WithParams(SafetyCheckVisitorParams) vis.Walk(args[j]) - unsafe := vis.Vars().Diff(safe) - for _, v := range unsafe.Sorted() { - errs = append(errs, NewError(CompileErr, args[j].Loc(), "var %v is undeclared", v)) + vars := vis.Vars() + if vars.DiffCount(safe) > 0 { + unsafe := vars.Diff(safe) + for _, v := range unsafe.Sorted() { + errs = append(errs, NewError(CompileErr, args[j].Loc(), "var %v is undeclared", v)) + } } } @@ -2140,17 +2191,17 @@ func rewritePrintCalls(gen *localVarGenerator, getArity func(Ref) int, globals V return false, errs } - arr := NewArray() + terms := make([]*Term, 0, len(args)) for j := range args { x := NewTerm(gen.Generate()).SetLocation(args[j].Loc()) capture := Equality.Expr(x, args[j]).SetLocation(args[j].Loc()) - arr = arr.Append(SetComprehensionTerm(x, NewBody(capture)).SetLocation(args[j].Loc())) + terms = append(terms, SetComprehensionTerm(x, NewBody(capture)).SetLocation(args[j].Loc())) } body.Set(NewExpr([]*Term{ NewTerm(InternalPrint.Ref()).SetLocation(body[i].Loc()), - NewTerm(arr).SetLocation(body[i].Loc()), + ArrayTerm(terms...).SetLocation(body[i].Loc()), }).SetLocation(body[i].Loc()), i) } @@ -2270,8 +2321,7 @@ func (c *Compiler) rewriteRefsInHead() { func (c *Compiler) rewriteEquals() { modified := false for _, name := range c.sorted { - mod := c.Modules[name] - modified = rewriteEquals(mod) || modified + modified = rewriteEquals(c.Modules[name]) || modified } if modified { c.Required.addBuiltinSorted(Equal) @@ -2281,8 +2331,7 @@ func (c *Compiler) rewriteEquals() { func (c *Compiler) rewriteDynamicTerms() { f := newEqualityFactory(c.localvargen) for _, name := range c.sorted { - mod := c.Modules[name] - WalkRules(mod, func(rule *Rule) bool { + WalkRules(c.Modules[name], func(rule *Rule) bool { rule.Body = rewriteDynamics(f, rule.Body) return false }) @@ -2546,19 +2595,21 @@ func createMetadataChain(chain []*AnnotationsRef) (*Term, *Error) { } func (c *Compiler) rewriteLocalVars() { - var assignment bool + args := NewVarVisitor() + argsStack := newLocalDeclaredVars() + for _, name := range c.sorted { mod := c.Modules[name] gen := c.localvargen WalkRules(mod, func(rule *Rule) bool { - argsStack := newLocalDeclaredVars() + args.Clear() + argsStack.Clear() - args := NewVarVisitor() - if c.strict { - args.Walk(rule.Head.Args) + if c.strict && len(rule.Head.Args) > 0 { + args.WalkArgs(rule.Head.Args) } unusedArgs := args.Vars() @@ -2603,45 +2654,51 @@ func (c *Compiler) rewriteLocalVars() { } func (c *Compiler) rewriteLocalVarsInRule(rule *Rule, unusedArgs VarSet, argsStack *localDeclaredVars, gen *localVarGenerator) (*localDeclaredVars, Errors) { - // Rewrite assignments contained in head of rule. Assignments can - // occur in rule head if they're inside a comprehension. Note, - // assigned vars in comprehensions in the head will be rewritten - // first to preserve scoping rules. For example: - // - // p = [x | x := 1] { x := 2 } becomes p = [__local0__ | __local0__ = 1] { __local1__ = 2 } - // - // This behaviour is consistent scoping inside the body. For example: - // - // p = xs { x := 2; xs = [x | x := 1] } becomes p = xs { __local0__ = 2; xs = [__local1__ | __local1__ = 1] } - nestedXform := &rewriteNestedHeadVarLocalTransform{ - gen: gen, - RewrittenVars: c.RewrittenVars, - strict: c.strict, - } - - NewGenericVisitor(nestedXform.Visit).Walk(rule.Head) - - for _, err := range nestedXform.errs { - c.err(err) - } + onlyScalars := !headMayHaveVars(rule.Head) + + var used VarSet + + if !onlyScalars { + // Rewrite assignments contained in head of rule. Assignments can + // occur in rule head if they're inside a comprehension. Note, + // assigned vars in comprehensions in the head will be rewritten + // first to preserve scoping rules. For example: + // + // p = [x | x := 1] { x := 2 } becomes p = [__local0__ | __local0__ = 1] { __local1__ = 2 } + // + // This behaviour is consistent scoping inside the body. For example: + // + // p = xs { x := 2; xs = [x | x := 1] } becomes p = xs { __local0__ = 2; xs = [__local1__ | __local1__ = 1] } + nestedXform := &rewriteNestedHeadVarLocalTransform{ + gen: gen, + RewrittenVars: c.RewrittenVars, + strict: c.strict, + } + + NewGenericVisitor(nestedXform.Visit).Walk(rule.Head) + + for _, err := range nestedXform.errs { + c.err(err) + } - // Rewrite assignments in body. - used := NewVarSet() + // Rewrite assignments in body. + used = NewVarSet() - for _, t := range rule.Head.Ref()[1:] { - used.Update(t.Vars()) - } + for _, t := range rule.Head.Ref()[1:] { + used.Update(t.Vars()) + } - if rule.Head.Key != nil { - used.Update(rule.Head.Key.Vars()) - } + if rule.Head.Key != nil { + used.Update(rule.Head.Key.Vars()) + } - if rule.Head.Value != nil { - valueVars := rule.Head.Value.Vars() - used.Update(valueVars) - for arg := range unusedArgs { - if valueVars.Contains(arg) { - delete(unusedArgs, arg) + if rule.Head.Value != nil { + valueVars := rule.Head.Value.Vars() + used.Update(valueVars) + for arg := range unusedArgs { + if valueVars.Contains(arg) { + delete(unusedArgs, arg) + } } } } @@ -2656,6 +2713,10 @@ func (c *Compiler) rewriteLocalVarsInRule(rule *Rule, unusedArgs VarSet, argsSta rule.Body = body + if onlyScalars { + return stack, errs + } + // Rewrite vars in head that refer to locally declared vars in the body. localXform := rewriteHeadVarLocalTransform{declared: declared} @@ -2676,6 +2737,30 @@ func (c *Compiler) rewriteLocalVarsInRule(rule *Rule, unusedArgs VarSet, argsSta return stack, errs } +func headMayHaveVars(head *Head) bool { + if head == nil { + return false + } + for i := range head.Args { + if !IsScalar(head.Args[i].Value) { + return true + } + } + if head.Key != nil && !IsScalar(head.Key.Value) { + return true + } + if head.Value != nil && !IsScalar(head.Value.Value) { + return true + } + ref := head.Ref()[1:] + for i := range ref { + if !IsScalar(ref[i].Value) { + return true + } + } + return false +} + type rewriteNestedHeadVarLocalTransform struct { gen *localVarGenerator errs Errors @@ -2684,9 +2769,7 @@ type rewriteNestedHeadVarLocalTransform struct { } func (xform *rewriteNestedHeadVarLocalTransform) Visit(x any) bool { - if term, ok := x.(*Term); ok { - stop := false stack := newLocalDeclaredVars() @@ -2787,7 +2870,7 @@ func (vis *ruleArgLocalRewriter) Visit(x any) Visitor { Walk(vis, vcpy) return k, vcpy, nil }); err != nil { - vis.errs = append(vis.errs, NewError(CompileErr, t.Location, err.Error())) //nolint:govet + vis.errs = append(vis.errs, NewError(CompileErr, t.Location, "%s", err.Error())) } else { t.Value = cpy } @@ -3163,7 +3246,7 @@ func (ci *ComprehensionIndex) String() string { return fmt.Sprintf("", NewArray(ci.Keys...)) } -func buildComprehensionIndices(dbg debug.Debug, arity func(Ref) int, candidates VarSet, rwVars map[Var]Var, node any, result map[*Term]*ComprehensionIndex) uint64 { +func buildComprehensionIndices(dbg debug.Debug, arity func(Ref) int, candidates VarSet, rwVars map[Var]Var, node Body, result map[*Term]*ComprehensionIndex) uint64 { var n uint64 cpy := candidates.Copy() WalkBodies(node, func(b Body) bool { @@ -3365,7 +3448,6 @@ func (vis *comprehensionIndexNestedCandidateVisitor) Walk(x any) { } func (vis *comprehensionIndexNestedCandidateVisitor) visit(x any) bool { - if vis.found { return true } @@ -3904,22 +3986,27 @@ func (vs unsafeVars) Slice() (result []unsafePair) { // If the body cannot be reordered to ensure safety, the second return value // contains a mapping of expressions to unsafe variables in those expressions. func reorderBodyForSafety(builtins map[string]*Builtin, arity func(Ref) int, globals VarSet, body Body) (Body, unsafeVars) { + vis := varVisitorPool.Get().WithParams(SafetyCheckVisitorParams) + vis.WalkBody(body) - bodyVars := body.Vars(SafetyCheckVisitorParams) - reordered := make(Body, 0, len(body)) - safe := VarSet{} - unsafe := unsafeVars{} + defer varVisitorPool.Put(vis) + + bodyVars := vis.Vars().Copy() + safe := bodyVars.Intersect(globals) + unsafe := make(unsafeVars, len(bodyVars)-len(safe)) for _, e := range body { - for v := range e.Vars(SafetyCheckVisitorParams) { - if globals.Contains(v) { - safe.Add(v) - } else { + vis.Clear().WithParams(SafetyCheckVisitorParams).Walk(e) + for v := range vis.Vars() { + if _, ok := safe[v]; !ok { unsafe.Add(e, v) } } } + reordered := make(Body, 0, len(body)) + output := VarSet{} + for { n := len(reordered) @@ -3928,15 +4015,16 @@ func reorderBodyForSafety(builtins map[string]*Builtin, arity func(Ref) int, glo continue } - ovs := outputVarsForExpr(e, arity, safe) + ovs := outputVarsForExpr(e, arity, safe, output) // check closures: is this expression closing over variables that // haven't been made safe by what's already included in `reordered`? vs := unsafeVarsInClosures(e) cv := vs.Intersect(bodyVars).Diff(globals) - uv := cv.Diff(outputVarsForBody(reordered, arity, safe)) + ob := outputVarsForBody(reordered, arity, safe) - if len(uv) > 0 { + if cv.DiffCount(ob) > 0 { + uv := cv.Diff(ob) if uv.Equal(ovs) { // special case "closure-self" continue } @@ -3965,18 +4053,22 @@ func reorderBodyForSafety(builtins map[string]*Builtin, arity func(Ref) int, glo // Update the globals at each expression to include the variables that could // be closed over. g := globals.Copy() + xform := &bodySafetyTransformer{ + builtins: builtins, + arity: arity, + } + gvis := &GenericVisitor{} for i, e := range reordered { if i > 0 { - g.Update(reordered[i-1].Vars(SafetyCheckVisitorParams)) + vis.Walk(reordered[i-1]) + g.Update(vis.Vars()) + vis.Clear().WithParams(SafetyCheckVisitorParams) } - xform := &bodySafetyTransformer{ - builtins: builtins, - arity: arity, - current: e, - globals: g, - unsafe: unsafe, - } - NewGenericVisitor(xform.Visit).Walk(e) + xform.current = e + xform.globals = g + xform.unsafe = unsafe + gvis.f = xform.Visit + gvis.Walk(e) } return reordered, unsafe @@ -4035,9 +4127,12 @@ func (xform *bodySafetyTransformer) Visit(x any) bool { func (xform *bodySafetyTransformer) reorderComprehensionSafety(tv VarSet, body Body) Body { bv := body.Vars(SafetyCheckVisitorParams) bv.Update(xform.globals) - uv := tv.Diff(bv) - for v := range uv { - xform.unsafe.Add(xform.current, v) + + if tv.DiffCount(bv) > 0 { + uv := tv.Diff(bv) + for v := range uv { + xform.unsafe.Add(xform.current, v) + } } r, u := reorderBodyForSafety(xform.builtins, xform.arity, xform.globals, body) @@ -4070,7 +4165,7 @@ func unsafeVarsInClosures(e *Expr) VarSet { WalkClosures(e, func(x any) bool { vis := &VarVisitor{vars: vs} if ev, ok := x.(*Every); ok { - vis.Walk(ev.Body) + vis.WalkBody(ev.Body) return true } vis.Walk(x) @@ -4088,8 +4183,9 @@ func OutputVarsFromBody(c *Compiler, body Body, safe VarSet) VarSet { func outputVarsForBody(body Body, arity func(Ref) int, safe VarSet) VarSet { o := safe.Copy() + output := VarSet{} for _, e := range body { - o.Update(outputVarsForExpr(e, arity, o)) + o.Update(outputVarsForExpr(e, arity, o, output)) } return o.Diff(safe) } @@ -4098,23 +4194,22 @@ func outputVarsForBody(body Body, arity func(Ref) int, safe VarSet) VarSet { // the given expression. For safety checks this means that they would be // made safe by the expr. func OutputVarsFromExpr(c *Compiler, expr *Expr, safe VarSet) VarSet { - return outputVarsForExpr(expr, c.GetArity, safe) + return outputVarsForExpr(expr, c.GetArity, safe, VarSet{}) } -func outputVarsForExpr(expr *Expr, arity func(Ref) int, safe VarSet) VarSet { - +func outputVarsForExpr(expr *Expr, arity func(Ref) int, safe VarSet, output VarSet) VarSet { // Negated expressions must be safe. if expr.Negated { return VarSet{} } + var vis *VarVisitor + // With modifier inputs must be safe. for _, with := range expr.With { - vis := NewVarVisitor().WithParams(SafetyCheckVisitorParams) + vis = vis.ClearOrNew().WithParams(SafetyCheckVisitorParams) vis.Walk(with) - vars := vis.Vars() - unsafe := vars.Diff(safe) - if len(unsafe) > 0 { + if vis.Vars().DiffCount(safe) > 0 { return VarSet{} } } @@ -4124,7 +4219,7 @@ func outputVarsForExpr(expr *Expr, arity func(Ref) int, safe VarSet) VarSet { return outputVarsForTerms(expr, safe) case []*Term: if expr.IsEquality() { - return outputVarsForExprEq(expr, safe) + return outputVarsForExprEq(expr, safe, output) } operator, ok := terms[0].Value.(Ref) @@ -4137,7 +4232,7 @@ func outputVarsForExpr(expr *Expr, arity func(Ref) int, safe VarSet) VarSet { return VarSet{} } - return outputVarsForExprCall(expr, ar, safe, terms) + return outputVarsForExprCall(expr, ar, safe, terms, vis, output) case *Every: return outputVarsForTerms(terms.Domain, safe) default: @@ -4145,22 +4240,26 @@ func outputVarsForExpr(expr *Expr, arity func(Ref) int, safe VarSet) VarSet { } } -func outputVarsForExprEq(expr *Expr, safe VarSet) VarSet { - +func outputVarsForExprEq(expr *Expr, safe VarSet, output VarSet) VarSet { if !validEqAssignArgCount(expr) { return safe } - output := outputVarsForTerms(expr, safe) + output.Update(outputVarsForTerms(expr, safe)) output.Update(safe) output.Update(Unify(output, expr.Operand(0), expr.Operand(1))) - return output.Diff(safe) + diff := output.Diff(safe) + + clear(output) + + return diff } -func outputVarsForExprCall(expr *Expr, arity int, safe VarSet, terms []*Term) VarSet { +func outputVarsForExprCall(expr *Expr, arity int, safe VarSet, terms []*Term, vis *VarVisitor, output VarSet) VarSet { + clear(output) - output := outputVarsForTerms(expr, safe) + output.Update(outputVarsForTerms(expr, safe)) numInputTerms := arity + 1 if numInputTerms >= len(terms) { @@ -4173,16 +4272,16 @@ func outputVarsForExprCall(expr *Expr, arity int, safe VarSet, terms []*Term) Va SkipObjectKeys: true, SkipRefHead: true, } - vis := NewVarVisitor().WithParams(params) - vis.Walk(Args(terms[:numInputTerms])) - unsafe := vis.Vars().Diff(output).Diff(safe) + vis = vis.ClearOrNew().WithParams(params) + vis.WalkArgs(Args(terms[:numInputTerms])) - if len(unsafe) > 0 { + unsafe := vis.Vars().Diff(output).DiffCount(safe) + if unsafe > 0 { return VarSet{} } - vis = NewVarVisitor().WithParams(params) - vis.Walk(Args(terms[numInputTerms:])) + vis = vis.Clear().WithParams(params) + vis.WalkArgs(Args(terms[numInputTerms:])) output.Update(vis.vars) return output } @@ -4197,8 +4296,13 @@ func outputVarsForTerms(expr any, safe VarSet) VarSet { if !isRefSafe(r, safe) { return true } - output.Update(r.OutputVars()) - return false + if !r.IsGround() { + // Avoiding r.OutputVars() here as it won't allow reusing the visitor. + vis := varVisitorPool.Get().WithParams(VarVisitorParams{SkipRefHead: true}) + vis.WalkRef(r) + output.Update(vis.Vars()) + varVisitorPool.Put(vis) + } } return false }) @@ -4231,19 +4335,17 @@ type localVarGenerator struct { } func newLocalVarGeneratorForModuleSet(sorted []string, modules map[string]*Module) *localVarGenerator { - exclude := NewVarSet() - vis := &VarVisitor{vars: exclude} + vis := NewVarVisitor() for _, key := range sorted { vis.Walk(modules[key]) } - return &localVarGenerator{exclude: exclude, next: 0} + return &localVarGenerator{exclude: vis.vars, next: 0} } func newLocalVarGenerator(suffix string, node any) *localVarGenerator { - exclude := NewVarSet() - vis := &VarVisitor{vars: exclude} + vis := NewVarVisitor() vis.Walk(node) - return &localVarGenerator{exclude: exclude, suffix: suffix, next: 0} + return &localVarGenerator{exclude: vis.vars, suffix: suffix, next: 0} } func (l *localVarGenerator) Generate() Var { @@ -4257,20 +4359,17 @@ func (l *localVarGenerator) Generate() Var { } func getGlobals(pkg *Package, rules []Ref, imports []*Import) map[Var]*usedRef { + globals := make(map[Var]*usedRef, len(rules)+len(imports)) - globals := make(map[Var]*usedRef, len(rules)) // NB: might grow bigger with imports - - // Populate globals with exports within the package. for _, ref := range rules { v := ref[0].Value.(Var) globals[v] = &usedRef{ref: pkg.Path.Append(StringTerm(string(v)))} } - // Populate globals with imports. for _, imp := range imports { path := imp.Path.Value.(Ref) if FutureRootDocument.Equal(path[0]) || RegoRootDocument.Equal(path[0]) { - continue // ignore future and rego imports + continue } globals[imp.Name()] = &usedRef{ref: path} } @@ -4635,8 +4734,6 @@ func rewriteComprehensionTerms(f *equalityFactory, node any) (any, error) { }) } -var doubleEq = Equal.Ref() - // rewriteEquals will rewrite exprs under x as unification calls instead of == // calls. For example: // @@ -5055,7 +5152,7 @@ type localDeclaredVars struct { assignment bool } -type varOccurrence int +type varOccurrence uint8 const ( newVar varOccurrence = iota @@ -5067,7 +5164,6 @@ const ( type declaredVarSet struct { vs map[Var]Var - reverse map[Var]Var occurrence map[Var]varOccurrence count map[Var]int } @@ -5075,12 +5171,19 @@ type declaredVarSet struct { func newDeclaredVarSet() *declaredVarSet { return &declaredVarSet{ vs: map[Var]Var{}, - reverse: map[Var]Var{}, occurrence: map[Var]varOccurrence{}, count: map[Var]int{}, } } +func (s *declaredVarSet) clear() *declaredVarSet { + clear(s.vs) + clear(s.occurrence) + clear(s.count) + + return s +} + func newLocalDeclaredVars() *localDeclaredVars { return &localDeclaredVars{ vars: []*declaredVarSet{newDeclaredVarSet()}, @@ -5088,21 +5191,39 @@ func newLocalDeclaredVars() *localDeclaredVars { } } +func (s *localDeclaredVars) Clear() { + var vs *declaredVarSet + if len(s.vars) > 0 { + vs = s.vars[0] + } + + clear(s.vars) + clear(s.rewritten) + + s.vars = s.vars[:0] + + if vs != nil { + s.vars = append(s.vars, vs.clear()) + } + if s.vars[0] == nil { + s.vars[0] = newDeclaredVarSet() + } + s.assignment = false +} + func (s *localDeclaredVars) Copy() *localDeclaredVars { stack := &localDeclaredVars{ - vars: []*declaredVarSet{}, - rewritten: map[Var]Var{}, + vars: make([]*declaredVarSet, 0, len(s.vars)), } for i := range s.vars { stack.vars = append(stack.vars, newDeclaredVarSet()) maps.Copy(stack.vars[0].vs, s.vars[i].vs) - maps.Copy(stack.vars[0].reverse, s.vars[i].reverse) maps.Copy(stack.vars[0].occurrence, s.vars[i].occurrence) maps.Copy(stack.vars[0].count, s.vars[i].count) } - maps.Copy(stack.rewritten, s.rewritten) + stack.rewritten = maps.Clone(s.rewritten) return stack } @@ -5125,7 +5246,6 @@ func (s localDeclaredVars) Peek() *declaredVarSet { func (s localDeclaredVars) Insert(x, y Var, occurrence varOccurrence) { elem := s.vars[len(s.vars)-1] elem.vs[x] = y - elem.reverse[y] = x elem.occurrence[x] = occurrence elem.count[x] = 1 @@ -5205,7 +5325,6 @@ func rewriteLocalVars(g *localVarGenerator, stack *localDeclaredVars, used VarSe } func rewriteDeclaredVarsInBody(g *localVarGenerator, stack *localDeclaredVars, used VarSet, body Body, errs Errors, strict bool) (Body, Errors) { - var cpy Body for i := range body { @@ -5238,12 +5357,22 @@ func rewriteDeclaredVarsInBody(g *localVarGenerator, stack *localDeclaredVars, u } func checkUnusedAssignedVars(body Body, stack *localDeclaredVars, used VarSet, errs Errors, strict bool) Errors { - if !strict || len(errs) > 0 { return errs } dvs := stack.Peek() + + hasAssignedVars := false + for _, occ := range dvs.occurrence { + if occ == assignedVar { + hasAssignedVars = true + } + } + if !hasAssignedVars { + return errs + } + unused := NewVarSet() for v, occ := range dvs.occurrence { @@ -5264,18 +5393,26 @@ func checkUnusedAssignedVars(body Body, stack *localDeclaredVars, used VarSet, e } unused = unused.Diff(rewrittenUsed) + if len(unused) == 0 { + return errs + } + + reversed := make(map[Var]Var, len(dvs.vs)) + for k, v := range dvs.vs { + reversed[v] = k + } for _, gv := range unused.Sorted() { found := false for i := range body { if body[i].Vars(VarVisitorParams{}).Contains(gv) { - errs = append(errs, NewError(CompileErr, body[i].Loc(), "assigned var %v unused", dvs.reverse[gv])) + errs = append(errs, NewError(CompileErr, body[i].Loc(), "assigned var %v unused", reversed[gv])) found = true break } } if !found { - errs = append(errs, NewError(CompileErr, body[0].Loc(), "assigned var %v unused", dvs.reverse[gv])) + errs = append(errs, NewError(CompileErr, body[0].Loc(), "assigned var %v unused", reversed[gv])) } } @@ -5291,6 +5428,17 @@ func checkUnusedDeclaredVars(body Body, stack *localDeclaredVars, used VarSet, c } dvs := stack.Peek() + + hasDeclaredVars := false + for _, occ := range dvs.occurrence { + if occ == declaredVar { + hasDeclaredVars = true + } + } + if !hasDeclaredVars { + return errs + } + declared := NewVarSet() for v, occ := range dvs.occurrence { @@ -5309,27 +5457,35 @@ func checkUnusedDeclaredVars(body Body, stack *localDeclaredVars, used VarSet, c } } - unused := declared.Diff(bodyvars).Diff(used) + dbv := declared.Diff(bodyvars) + if dbv.DiffCount(used) == 0 { + return errs + } - for _, gv := range unused.Sorted() { - rv := dvs.reverse[gv] + reversed := make(map[Var]Var, len(dvs.vs)) + for k, v := range dvs.vs { + reversed[v] = k + } + + for _, gv := range dbv.Diff(used).Sorted() { + rv := reversed[gv] if !rv.IsGenerated() { // Scan through body exprs, looking for a match between the // bad var's original name, and each expr's declared vars. foundUnusedVarByName := false for i := range body { varsDeclaredInExpr := declaredVars(body[i]) - if varsDeclaredInExpr.Contains(dvs.reverse[gv]) { + if varsDeclaredInExpr.Contains(rv) { // TODO(philipc): Clean up the offset logic here when the parser // reports more accurate locations. - errs = append(errs, NewError(CompileErr, body[i].Loc(), "declared var %v unused", dvs.reverse[gv])) + errs = append(errs, NewError(CompileErr, body[i].Loc(), "declared var %v unused", rv)) foundUnusedVarByName = true break } } // Default error location returned. if !foundUnusedVarByName { - errs = append(errs, NewError(CompileErr, body[0].Loc(), "declared var %v unused", dvs.reverse[gv])) + errs = append(errs, NewError(CompileErr, body[0].Loc(), "declared var %v unused", rv)) } } } @@ -5351,7 +5507,7 @@ func rewriteEveryStatement(g *localVarGenerator, stack *localDeclaredVars, expr if v := every.Key.Value.(Var); !v.IsWildcard() { gv, err := rewriteDeclaredVar(g, stack, v, declaredVar) if err != nil { - return nil, append(errs, NewError(CompileErr, every.Loc(), err.Error())) //nolint:govet + return nil, append(errs, NewError(CompileErr, every.Loc(), "%s", err.Error())) } every.Key.Value = gv } @@ -5363,7 +5519,7 @@ func rewriteEveryStatement(g *localVarGenerator, stack *localDeclaredVars, expr if v := every.Value.Value.(Var); !v.IsWildcard() { gv, err := rewriteDeclaredVar(g, stack, v, declaredVar) if err != nil { - return nil, append(errs, NewError(CompileErr, every.Loc(), err.Error())) //nolint:govet + return nil, append(errs, NewError(CompileErr, every.Loc(), "%s", err.Error())) } every.Value.Value = gv } @@ -5381,7 +5537,7 @@ func rewriteSomeDeclStatement(g *localVarGenerator, stack *localDeclaredVars, ex switch v := decl.Symbols[i].Value.(type) { case Var: if _, err := rewriteDeclaredVar(g, stack, v, declaredVar); err != nil { - return nil, append(errs, NewError(CompileErr, decl.Loc(), err.Error())) //nolint:govet + return nil, append(errs, NewError(CompileErr, decl.Loc(), "%s", err.Error())) } case Call: var key, val, container *Term @@ -5407,9 +5563,11 @@ func rewriteSomeDeclStatement(g *localVarGenerator, stack *localDeclaredVars, ex RefTerm(VarTerm(Equality.Name)), val, rhs, } - for _, v0 := range outputVarsForExprEq(e, container.Vars()).Sorted() { + output := VarSet{} + + for _, v0 := range outputVarsForExprEq(e, container.Vars(), output).Sorted() { if _, err := rewriteDeclaredVar(g, stack, v0, declaredVar); err != nil { - return nil, append(errs, NewError(CompileErr, decl.Loc(), err.Error())) //nolint:govet + return nil, append(errs, NewError(CompileErr, decl.Loc(), "%s", err.Error())) } } return rewriteDeclaredVarsInExpr(g, stack, e, errs, strict) @@ -5463,7 +5621,7 @@ func rewriteDeclaredAssignment(g *localVarGenerator, stack *localDeclaredVars, e switch v := t.Value.(type) { case Var: if gv, err := rewriteDeclaredVar(g, stack, v, assignedVar); err != nil { - errs = append(errs, NewError(CompileErr, t.Location, err.Error())) //nolint:govet + errs = append(errs, NewError(CompileErr, t.Location, "%s", err.Error())) } else { t.Value = gv } @@ -5478,7 +5636,7 @@ func rewriteDeclaredAssignment(g *localVarGenerator, stack *localDeclaredVars, e case Ref: if RootDocumentRefs.Contains(t) { if gv, err := rewriteDeclaredVar(g, stack, v[0].Value.(Var), assignedVar); err != nil { - errs = append(errs, NewError(CompileErr, t.Location, err.Error())) //nolint:govet + errs = append(errs, NewError(CompileErr, t.Location, "%s", err.Error())) } else { t.Value = gv } @@ -5845,7 +6003,6 @@ func isVirtual(node *TreeNode, ref Ref) bool { } func safetyErrorSlice(unsafe unsafeVars, rewritten map[Var]Var) (result Errors) { - if len(unsafe) == 0 { return } @@ -5897,7 +6054,7 @@ func safetyErrorSlice(unsafe unsafeVars, rewritten map[Var]Var) (result Errors) } func checkUnsafeBuiltins(unsafeBuiltinsMap map[string]struct{}, node any) Errors { - errs := make(Errors, 0) + var errs Errors WalkExprs(node, func(x *Expr) bool { if x.IsCall() { operator := x.Operator().String() diff --git a/vendor/github.com/open-policy-agent/opa/v1/ast/default_module_loader.go b/vendor/github.com/open-policy-agent/opa/v1/ast/default_module_loader.go new file mode 100644 index 00000000000..528c253e161 --- /dev/null +++ b/vendor/github.com/open-policy-agent/opa/v1/ast/default_module_loader.go @@ -0,0 +1,14 @@ +// Copyright 2025 The OPA Authors. All rights reserved. +// Use of this source code is governed by an Apache2 +// license that can be found in the LICENSE file. + +package ast + +var defaultModuleLoader ModuleLoader + +// DefaultModuleLoader lets you inject an `ast.ModuleLoader` that will +// always be used. If another one is provided with the ast package, +// they will both be consulted to enrich the set of modules dynamically. +func DefaultModuleLoader(ml ModuleLoader) { + defaultModuleLoader = ml +} diff --git a/vendor/github.com/open-policy-agent/opa/v1/ast/index.go b/vendor/github.com/open-policy-agent/opa/v1/ast/index.go index bcaf4a7068a..845447b6dc4 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/ast/index.go +++ b/vendor/github.com/open-policy-agent/opa/v1/ast/index.go @@ -213,7 +213,7 @@ func (i *baseDocEqIndex) Lookup(resolver ValueResolver) (*IndexResult, error) { return result, nil } -func (i *baseDocEqIndex) AllRules(_ ValueResolver) (*IndexResult, error) { +func (i *baseDocEqIndex) AllRules(ValueResolver) (*IndexResult, error) { tr := newTrieTraversalResult() // Walk over the rule trie and accumulate _all_ rules @@ -285,33 +285,51 @@ func newrefindices(isVirtual func(Ref) bool) *refindices { } } +// anyValue is a fake variable we used to put "naked ref" expressions +// into the rule index +var anyValue = Var("__any__") + // Update attempts to update the refindices for the given expression in the // given rule. If the expression cannot be indexed the update does not affect // the indices. func (i *refindices) Update(rule *Rule, expr *Expr) { - if expr.Negated { - return - } - if len(expr.With) > 0 { // NOTE(tsandall): In the future, we may need to consider expressions // that have with statements applied to them. return } + if expr.Negated { + // NOTE(sr): We could try to cover simple expressions, like + // not input.funky => input.funky == false or undefined (two refindex?) + return + } + op := expr.Operator() + if op == nil { + if ts, ok := expr.Terms.(*Term); ok { + // NOTE(sr): If we wanted to cover function args, we'd need to also + // check for type "Var" here. But since it's impossible to call a + // function with a undefined argument, there's no point to recording + // "needs to be anything" for function args + if ref, ok := ts.Value.(Ref); ok { // "naked ref" + i.updateEq(rule, ref, anyValue) + } + } + } + a, b := expr.Operand(0), expr.Operand(1) switch { case op.Equal(equalityRef): - i.updateEq(rule, expr) + i.updateEq(rule, a.Value, b.Value) case op.Equal(equalRef) && len(expr.Operands()) == 2: // NOTE(tsandall): if equal() is called with more than two arguments the // output value is being captured in which case the indexer cannot // exclude the rule if the equal() call would return false (because the // false value must still be produced.) - i.updateEq(rule, expr) + i.updateEq(rule, a.Value, b.Value) case op.Equal(globMatchRef) && len(expr.Operands()) == 3: // NOTE(sr): Same as with equal() above -- 4 operands means the output @@ -366,8 +384,7 @@ func (i *refindices) Mapper(rule *Rule, ref Ref) *valueMapper { return nil } -func (i *refindices) updateEq(rule *Rule, expr *Expr) { - a, b := expr.Operand(0), expr.Operand(1) +func (i *refindices) updateEq(rule *Rule, a, b Value) { args := rule.Head.Args if idx, ok := eqOperandsToRefAndValue(i.isVirtual, args, a, b); ok { i.insert(rule, idx) @@ -426,12 +443,7 @@ func (i *refindices) updateGlobMatch(rule *Rule, expr *Expr) { } func (i *refindices) insert(rule *Rule, index *refindex) { - - count, ok := i.frequency.Get(index.Ref) - if !ok { - count = 0 - } - + count, _ := i.frequency.Get(index.Ref) i.frequency.Put(index.Ref, count+1) for pos, other := range i.rules[rule] { @@ -454,7 +466,7 @@ func (i *refindices) index(rule *Rule, ref Ref) *refindex { } type trieWalker interface { - Do(x any) trieWalker + Do(any) trieWalker } type trieTraversalResult struct { @@ -816,11 +828,11 @@ func (node *trieNode) traverseUnknown(resolver ValueResolver, tr *trieTraversalR // for the argument number. So for `f(x, y) { x = 10; y = 12 }`, we'll // bind `args[0]` and `args[1]` to this rule when called for (x=10) and // (y=12) respectively. -func eqOperandsToRefAndValue(isVirtual func(Ref) bool, args []*Term, a, b *Term) (*refindex, bool) { - switch v := a.Value.(type) { +func eqOperandsToRefAndValue(isVirtual func(Ref) bool, args []*Term, a, b Value) (*refindex, bool) { + switch v := a.(type) { case Var: for i, arg := range args { - if arg.Value.Compare(a.Value) == 0 { + if arg.Value.Compare(a) == 0 { if bval, ok := indexValue(b); ok { return &refindex{Ref: Ref{FunctionArgRootDocument, InternedTerm(i)}, Value: bval}, true } @@ -843,8 +855,8 @@ func eqOperandsToRefAndValue(isVirtual func(Ref) bool, args []*Term, a, b *Term) return nil, false } -func indexValue(b *Term) (Value, bool) { - switch b := b.Value.(type) { +func indexValue(b Value) (Value, bool) { + switch b := b.(type) { case Null, Boolean, Number, String, Var: return b, true case *Array: diff --git a/vendor/github.com/open-policy-agent/opa/v1/ast/interning.go b/vendor/github.com/open-policy-agent/opa/v1/ast/interning.go index 564a3cc41f7..fc5a89f69a6 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/ast/interning.go +++ b/vendor/github.com/open-policy-agent/opa/v1/ast/interning.go @@ -18,7 +18,13 @@ type internable interface { // at any time without notice. var ( - InternedNullTerm = &Term{Value: Null{}} + InternedNullValue Value = Null{} + InternedNullTerm = &Term{Value: InternedNullValue} + + InternedBooleanTrueValue Value = Boolean(true) + InternedBooleanFalseValue Value = Boolean(false) + InternedBooleanTrueTerm = &Term{Value: InternedBooleanTrueValue} + InternedBooleanFalseTerm = &Term{Value: InternedBooleanFalseValue} InternedEmptyString = StringTerm("") InternedEmptyObject = ObjectTerm() @@ -27,11 +33,9 @@ var ( InternedEmptyArrayValue = NewArray() - booleanTrueTerm = &Term{Value: Boolean(true)} - booleanFalseTerm = &Term{Value: Boolean(false)} - // since this is by far the most common negative number - minusOneTerm = &Term{Value: Number("-1")} + minusOneValue Value = Number("-1") + minusOneTerm = &Term{Value: minusOneValue} internedStringTerms = map[string]*Term{ "": InternedEmptyString, @@ -52,6 +56,74 @@ func InternStringTerm(str ...string) { } } +// HasInternedValue returns true if the given value is interned, otherwise false. +func HasInternedValue[T internable](v T) bool { + switch value := any(v).(type) { + case bool: + return true + case int: + return HasInternedIntNumberTerm(value) + case int8: + return HasInternedIntNumberTerm(int(value)) + case int16: + return HasInternedIntNumberTerm(int(value)) + case int32: + return HasInternedIntNumberTerm(int(value)) + case int64: + return HasInternedIntNumberTerm(int(value)) + case uint: + return HasInternedIntNumberTerm(int(value)) + case uint8: + return HasInternedIntNumberTerm(int(value)) + case uint16: + return HasInternedIntNumberTerm(int(value)) + case uint32: + return HasInternedIntNumberTerm(int(value)) + case uint64: + return HasInternedIntNumberTerm(int(value)) + case string: + _, ok := internedStringTerms[value] + return ok + } + return false +} + +// InternedValue returns an interned Value for scalar v, if the value is +// interned. If the value is not interned, a new Value is returned. +func InternedValue[T internable](v T) Value { + return InternedValueOr(v, internedTermValue) +} + +// InternedValueOr returns an interned Value for scalar v. Calls supplier +// to produce a Value if the value is not interned. +func InternedValueOr[T internable](v T, supplier func(T) Value) Value { + switch value := any(v).(type) { + case bool: + return internedBooleanValue(value) + case int: + return internedIntNumberValue(value) + case int8: + return internedIntNumberValue(int(value)) + case int16: + return internedIntNumberValue(int(value)) + case int32: + return internedIntNumberValue(int(value)) + case int64: + return internedIntNumberValue(int(value)) + case uint: + return internedIntNumberValue(int(value)) + case uint8: + return internedIntNumberValue(int(value)) + case uint16: + return internedIntNumberValue(int(value)) + case uint32: + return internedIntNumberValue(int(value)) + case uint64: + return internedIntNumberValue(int(value)) + } + return supplier(v) +} + // Interned returns a possibly interned term for the given scalar value. // If the value is not interned, a new term is created for that value. func InternedTerm[T internable](v T) *Term { @@ -123,13 +195,33 @@ func InternedIntegerString(i int) *Term { return StringTerm(s) } +func internedBooleanValue(b bool) Value { + if b { + return InternedBooleanTrueValue + } + + return InternedBooleanFalseValue +} + // InternedBooleanTerm returns an interned term with the given boolean value. func internedBooleanTerm(b bool) *Term { if b { - return booleanTrueTerm + return InternedBooleanTrueTerm } - return booleanFalseTerm + return InternedBooleanFalseTerm +} + +func internedIntNumberValue(i int) Value { + if i >= 0 && i < len(intNumberTerms) { + return intNumberValues[i] + } + + if i == -1 { + return minusOneValue + } + + return Number(strconv.Itoa(i)) } // InternedIntNumberTerm returns a term with the given integer value. The term is @@ -158,10 +250,15 @@ func internedStringTerm(s string) *Term { return StringTerm(s) } +func internedTermValue[T internable](v T) Value { + return InternedTerm(v).Value +} + func init() { InternStringTerm( // Numbers - "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", + "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", + "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "40", "41", "42", "43", "44", "45", "46", "47", "48", "49", "50", "51", "52", "53", "54", "55", "56", "57", "58", "59", "60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "70", "71", "72", "73", "74", @@ -185,6 +282,9 @@ func init() { // Decisions "revision", "labels", "decision_id", "bundles", "query", "mapped_result", "nd_builtin_cache", "erased", "masked", "requested_by", "timestamp", "metrics", "req_id", + + // Whitespace + " ", "\n", "\t", ) } @@ -705,518 +805,1034 @@ var stringToIntNumberTermMap = map[string]*Term{ "512": intNumberTerms[512], } +var intNumberValues = [...]Value{ + Number("0"), + Number("1"), + Number("2"), + Number("3"), + Number("4"), + Number("5"), + Number("6"), + Number("7"), + Number("8"), + Number("9"), + Number("10"), + Number("11"), + Number("12"), + Number("13"), + Number("14"), + Number("15"), + Number("16"), + Number("17"), + Number("18"), + Number("19"), + Number("20"), + Number("21"), + Number("22"), + Number("23"), + Number("24"), + Number("25"), + Number("26"), + Number("27"), + Number("28"), + Number("29"), + Number("30"), + Number("31"), + Number("32"), + Number("33"), + Number("34"), + Number("35"), + Number("36"), + Number("37"), + Number("38"), + Number("39"), + Number("40"), + Number("41"), + Number("42"), + Number("43"), + Number("44"), + Number("45"), + Number("46"), + Number("47"), + Number("48"), + Number("49"), + Number("50"), + Number("51"), + Number("52"), + Number("53"), + Number("54"), + Number("55"), + Number("56"), + Number("57"), + Number("58"), + Number("59"), + Number("60"), + Number("61"), + Number("62"), + Number("63"), + Number("64"), + Number("65"), + Number("66"), + Number("67"), + Number("68"), + Number("69"), + Number("70"), + Number("71"), + Number("72"), + Number("73"), + Number("74"), + Number("75"), + Number("76"), + Number("77"), + Number("78"), + Number("79"), + Number("80"), + Number("81"), + Number("82"), + Number("83"), + Number("84"), + Number("85"), + Number("86"), + Number("87"), + Number("88"), + Number("89"), + Number("90"), + Number("91"), + Number("92"), + Number("93"), + Number("94"), + Number("95"), + Number("96"), + Number("97"), + Number("98"), + Number("99"), + Number("100"), + Number("101"), + Number("102"), + Number("103"), + Number("104"), + Number("105"), + Number("106"), + Number("107"), + Number("108"), + Number("109"), + Number("110"), + Number("111"), + Number("112"), + Number("113"), + Number("114"), + Number("115"), + Number("116"), + Number("117"), + Number("118"), + Number("119"), + Number("120"), + Number("121"), + Number("122"), + Number("123"), + Number("124"), + Number("125"), + Number("126"), + Number("127"), + Number("128"), + Number("129"), + Number("130"), + Number("131"), + Number("132"), + Number("133"), + Number("134"), + Number("135"), + Number("136"), + Number("137"), + Number("138"), + Number("139"), + Number("140"), + Number("141"), + Number("142"), + Number("143"), + Number("144"), + Number("145"), + Number("146"), + Number("147"), + Number("148"), + Number("149"), + Number("150"), + Number("151"), + Number("152"), + Number("153"), + Number("154"), + Number("155"), + Number("156"), + Number("157"), + Number("158"), + Number("159"), + Number("160"), + Number("161"), + Number("162"), + Number("163"), + Number("164"), + Number("165"), + Number("166"), + Number("167"), + Number("168"), + Number("169"), + Number("170"), + Number("171"), + Number("172"), + Number("173"), + Number("174"), + Number("175"), + Number("176"), + Number("177"), + Number("178"), + Number("179"), + Number("180"), + Number("181"), + Number("182"), + Number("183"), + Number("184"), + Number("185"), + Number("186"), + Number("187"), + Number("188"), + Number("189"), + Number("190"), + Number("191"), + Number("192"), + Number("193"), + Number("194"), + Number("195"), + Number("196"), + Number("197"), + Number("198"), + Number("199"), + Number("200"), + Number("201"), + Number("202"), + Number("203"), + Number("204"), + Number("205"), + Number("206"), + Number("207"), + Number("208"), + Number("209"), + Number("210"), + Number("211"), + Number("212"), + Number("213"), + Number("214"), + Number("215"), + Number("216"), + Number("217"), + Number("218"), + Number("219"), + Number("220"), + Number("221"), + Number("222"), + Number("223"), + Number("224"), + Number("225"), + Number("226"), + Number("227"), + Number("228"), + Number("229"), + Number("230"), + Number("231"), + Number("232"), + Number("233"), + Number("234"), + Number("235"), + Number("236"), + Number("237"), + Number("238"), + Number("239"), + Number("240"), + Number("241"), + Number("242"), + Number("243"), + Number("244"), + Number("245"), + Number("246"), + Number("247"), + Number("248"), + Number("249"), + Number("250"), + Number("251"), + Number("252"), + Number("253"), + Number("254"), + Number("255"), + Number("256"), + Number("257"), + Number("258"), + Number("259"), + Number("260"), + Number("261"), + Number("262"), + Number("263"), + Number("264"), + Number("265"), + Number("266"), + Number("267"), + Number("268"), + Number("269"), + Number("270"), + Number("271"), + Number("272"), + Number("273"), + Number("274"), + Number("275"), + Number("276"), + Number("277"), + Number("278"), + Number("279"), + Number("280"), + Number("281"), + Number("282"), + Number("283"), + Number("284"), + Number("285"), + Number("286"), + Number("287"), + Number("288"), + Number("289"), + Number("290"), + Number("291"), + Number("292"), + Number("293"), + Number("294"), + Number("295"), + Number("296"), + Number("297"), + Number("298"), + Number("299"), + Number("300"), + Number("301"), + Number("302"), + Number("303"), + Number("304"), + Number("305"), + Number("306"), + Number("307"), + Number("308"), + Number("309"), + Number("310"), + Number("311"), + Number("312"), + Number("313"), + Number("314"), + Number("315"), + Number("316"), + Number("317"), + Number("318"), + Number("319"), + Number("320"), + Number("321"), + Number("322"), + Number("323"), + Number("324"), + Number("325"), + Number("326"), + Number("327"), + Number("328"), + Number("329"), + Number("330"), + Number("331"), + Number("332"), + Number("333"), + Number("334"), + Number("335"), + Number("336"), + Number("337"), + Number("338"), + Number("339"), + Number("340"), + Number("341"), + Number("342"), + Number("343"), + Number("344"), + Number("345"), + Number("346"), + Number("347"), + Number("348"), + Number("349"), + Number("350"), + Number("351"), + Number("352"), + Number("353"), + Number("354"), + Number("355"), + Number("356"), + Number("357"), + Number("358"), + Number("359"), + Number("360"), + Number("361"), + Number("362"), + Number("363"), + Number("364"), + Number("365"), + Number("366"), + Number("367"), + Number("368"), + Number("369"), + Number("370"), + Number("371"), + Number("372"), + Number("373"), + Number("374"), + Number("375"), + Number("376"), + Number("377"), + Number("378"), + Number("379"), + Number("380"), + Number("381"), + Number("382"), + Number("383"), + Number("384"), + Number("385"), + Number("386"), + Number("387"), + Number("388"), + Number("389"), + Number("390"), + Number("391"), + Number("392"), + Number("393"), + Number("394"), + Number("395"), + Number("396"), + Number("397"), + Number("398"), + Number("399"), + Number("400"), + Number("401"), + Number("402"), + Number("403"), + Number("404"), + Number("405"), + Number("406"), + Number("407"), + Number("408"), + Number("409"), + Number("410"), + Number("411"), + Number("412"), + Number("413"), + Number("414"), + Number("415"), + Number("416"), + Number("417"), + Number("418"), + Number("419"), + Number("420"), + Number("421"), + Number("422"), + Number("423"), + Number("424"), + Number("425"), + Number("426"), + Number("427"), + Number("428"), + Number("429"), + Number("430"), + Number("431"), + Number("432"), + Number("433"), + Number("434"), + Number("435"), + Number("436"), + Number("437"), + Number("438"), + Number("439"), + Number("440"), + Number("441"), + Number("442"), + Number("443"), + Number("444"), + Number("445"), + Number("446"), + Number("447"), + Number("448"), + Number("449"), + Number("450"), + Number("451"), + Number("452"), + Number("453"), + Number("454"), + Number("455"), + Number("456"), + Number("457"), + Number("458"), + Number("459"), + Number("460"), + Number("461"), + Number("462"), + Number("463"), + Number("464"), + Number("465"), + Number("466"), + Number("467"), + Number("468"), + Number("469"), + Number("470"), + Number("471"), + Number("472"), + Number("473"), + Number("474"), + Number("475"), + Number("476"), + Number("477"), + Number("478"), + Number("479"), + Number("480"), + Number("481"), + Number("482"), + Number("483"), + Number("484"), + Number("485"), + Number("486"), + Number("487"), + Number("488"), + Number("489"), + Number("490"), + Number("491"), + Number("492"), + Number("493"), + Number("494"), + Number("495"), + Number("496"), + Number("497"), + Number("498"), + Number("499"), + Number("500"), + Number("501"), + Number("502"), + Number("503"), + Number("504"), + Number("505"), + Number("506"), + Number("507"), + Number("508"), + Number("509"), + Number("510"), + Number("511"), + Number("512"), +} + var intNumberTerms = [...]*Term{ - {Value: Number("0")}, - {Value: Number("1")}, - {Value: Number("2")}, - {Value: Number("3")}, - {Value: Number("4")}, - {Value: Number("5")}, - {Value: Number("6")}, - {Value: Number("7")}, - {Value: Number("8")}, - {Value: Number("9")}, - {Value: Number("10")}, - {Value: Number("11")}, - {Value: Number("12")}, - {Value: Number("13")}, - {Value: Number("14")}, - {Value: Number("15")}, - {Value: Number("16")}, - {Value: Number("17")}, - {Value: Number("18")}, - {Value: Number("19")}, - {Value: Number("20")}, - {Value: Number("21")}, - {Value: Number("22")}, - {Value: Number("23")}, - {Value: Number("24")}, - {Value: Number("25")}, - {Value: Number("26")}, - {Value: Number("27")}, - {Value: Number("28")}, - {Value: Number("29")}, - {Value: Number("30")}, - {Value: Number("31")}, - {Value: Number("32")}, - {Value: Number("33")}, - {Value: Number("34")}, - {Value: Number("35")}, - {Value: Number("36")}, - {Value: Number("37")}, - {Value: Number("38")}, - {Value: Number("39")}, - {Value: Number("40")}, - {Value: Number("41")}, - {Value: Number("42")}, - {Value: Number("43")}, - {Value: Number("44")}, - {Value: Number("45")}, - {Value: Number("46")}, - {Value: Number("47")}, - {Value: Number("48")}, - {Value: Number("49")}, - {Value: Number("50")}, - {Value: Number("51")}, - {Value: Number("52")}, - {Value: Number("53")}, - {Value: Number("54")}, - {Value: Number("55")}, - {Value: Number("56")}, - {Value: Number("57")}, - {Value: Number("58")}, - {Value: Number("59")}, - {Value: Number("60")}, - {Value: Number("61")}, - {Value: Number("62")}, - {Value: Number("63")}, - {Value: Number("64")}, - {Value: Number("65")}, - {Value: Number("66")}, - {Value: Number("67")}, - {Value: Number("68")}, - {Value: Number("69")}, - {Value: Number("70")}, - {Value: Number("71")}, - {Value: Number("72")}, - {Value: Number("73")}, - {Value: Number("74")}, - {Value: Number("75")}, - {Value: Number("76")}, - {Value: Number("77")}, - {Value: Number("78")}, - {Value: Number("79")}, - {Value: Number("80")}, - {Value: Number("81")}, - {Value: Number("82")}, - {Value: Number("83")}, - {Value: Number("84")}, - {Value: Number("85")}, - {Value: Number("86")}, - {Value: Number("87")}, - {Value: Number("88")}, - {Value: Number("89")}, - {Value: Number("90")}, - {Value: Number("91")}, - {Value: Number("92")}, - {Value: Number("93")}, - {Value: Number("94")}, - {Value: Number("95")}, - {Value: Number("96")}, - {Value: Number("97")}, - {Value: Number("98")}, - {Value: Number("99")}, - {Value: Number("100")}, - {Value: Number("101")}, - {Value: Number("102")}, - {Value: Number("103")}, - {Value: Number("104")}, - {Value: Number("105")}, - {Value: Number("106")}, - {Value: Number("107")}, - {Value: Number("108")}, - {Value: Number("109")}, - {Value: Number("110")}, - {Value: Number("111")}, - {Value: Number("112")}, - {Value: Number("113")}, - {Value: Number("114")}, - {Value: Number("115")}, - {Value: Number("116")}, - {Value: Number("117")}, - {Value: Number("118")}, - {Value: Number("119")}, - {Value: Number("120")}, - {Value: Number("121")}, - {Value: Number("122")}, - {Value: Number("123")}, - {Value: Number("124")}, - {Value: Number("125")}, - {Value: Number("126")}, - {Value: Number("127")}, - {Value: Number("128")}, - {Value: Number("129")}, - {Value: Number("130")}, - {Value: Number("131")}, - {Value: Number("132")}, - {Value: Number("133")}, - {Value: Number("134")}, - {Value: Number("135")}, - {Value: Number("136")}, - {Value: Number("137")}, - {Value: Number("138")}, - {Value: Number("139")}, - {Value: Number("140")}, - {Value: Number("141")}, - {Value: Number("142")}, - {Value: Number("143")}, - {Value: Number("144")}, - {Value: Number("145")}, - {Value: Number("146")}, - {Value: Number("147")}, - {Value: Number("148")}, - {Value: Number("149")}, - {Value: Number("150")}, - {Value: Number("151")}, - {Value: Number("152")}, - {Value: Number("153")}, - {Value: Number("154")}, - {Value: Number("155")}, - {Value: Number("156")}, - {Value: Number("157")}, - {Value: Number("158")}, - {Value: Number("159")}, - {Value: Number("160")}, - {Value: Number("161")}, - {Value: Number("162")}, - {Value: Number("163")}, - {Value: Number("164")}, - {Value: Number("165")}, - {Value: Number("166")}, - {Value: Number("167")}, - {Value: Number("168")}, - {Value: Number("169")}, - {Value: Number("170")}, - {Value: Number("171")}, - {Value: Number("172")}, - {Value: Number("173")}, - {Value: Number("174")}, - {Value: Number("175")}, - {Value: Number("176")}, - {Value: Number("177")}, - {Value: Number("178")}, - {Value: Number("179")}, - {Value: Number("180")}, - {Value: Number("181")}, - {Value: Number("182")}, - {Value: Number("183")}, - {Value: Number("184")}, - {Value: Number("185")}, - {Value: Number("186")}, - {Value: Number("187")}, - {Value: Number("188")}, - {Value: Number("189")}, - {Value: Number("190")}, - {Value: Number("191")}, - {Value: Number("192")}, - {Value: Number("193")}, - {Value: Number("194")}, - {Value: Number("195")}, - {Value: Number("196")}, - {Value: Number("197")}, - {Value: Number("198")}, - {Value: Number("199")}, - {Value: Number("200")}, - {Value: Number("201")}, - {Value: Number("202")}, - {Value: Number("203")}, - {Value: Number("204")}, - {Value: Number("205")}, - {Value: Number("206")}, - {Value: Number("207")}, - {Value: Number("208")}, - {Value: Number("209")}, - {Value: Number("210")}, - {Value: Number("211")}, - {Value: Number("212")}, - {Value: Number("213")}, - {Value: Number("214")}, - {Value: Number("215")}, - {Value: Number("216")}, - {Value: Number("217")}, - {Value: Number("218")}, - {Value: Number("219")}, - {Value: Number("220")}, - {Value: Number("221")}, - {Value: Number("222")}, - {Value: Number("223")}, - {Value: Number("224")}, - {Value: Number("225")}, - {Value: Number("226")}, - {Value: Number("227")}, - {Value: Number("228")}, - {Value: Number("229")}, - {Value: Number("230")}, - {Value: Number("231")}, - {Value: Number("232")}, - {Value: Number("233")}, - {Value: Number("234")}, - {Value: Number("235")}, - {Value: Number("236")}, - {Value: Number("237")}, - {Value: Number("238")}, - {Value: Number("239")}, - {Value: Number("240")}, - {Value: Number("241")}, - {Value: Number("242")}, - {Value: Number("243")}, - {Value: Number("244")}, - {Value: Number("245")}, - {Value: Number("246")}, - {Value: Number("247")}, - {Value: Number("248")}, - {Value: Number("249")}, - {Value: Number("250")}, - {Value: Number("251")}, - {Value: Number("252")}, - {Value: Number("253")}, - {Value: Number("254")}, - {Value: Number("255")}, - {Value: Number("256")}, - {Value: Number("257")}, - {Value: Number("258")}, - {Value: Number("259")}, - {Value: Number("260")}, - {Value: Number("261")}, - {Value: Number("262")}, - {Value: Number("263")}, - {Value: Number("264")}, - {Value: Number("265")}, - {Value: Number("266")}, - {Value: Number("267")}, - {Value: Number("268")}, - {Value: Number("269")}, - {Value: Number("270")}, - {Value: Number("271")}, - {Value: Number("272")}, - {Value: Number("273")}, - {Value: Number("274")}, - {Value: Number("275")}, - {Value: Number("276")}, - {Value: Number("277")}, - {Value: Number("278")}, - {Value: Number("279")}, - {Value: Number("280")}, - {Value: Number("281")}, - {Value: Number("282")}, - {Value: Number("283")}, - {Value: Number("284")}, - {Value: Number("285")}, - {Value: Number("286")}, - {Value: Number("287")}, - {Value: Number("288")}, - {Value: Number("289")}, - {Value: Number("290")}, - {Value: Number("291")}, - {Value: Number("292")}, - {Value: Number("293")}, - {Value: Number("294")}, - {Value: Number("295")}, - {Value: Number("296")}, - {Value: Number("297")}, - {Value: Number("298")}, - {Value: Number("299")}, - {Value: Number("300")}, - {Value: Number("301")}, - {Value: Number("302")}, - {Value: Number("303")}, - {Value: Number("304")}, - {Value: Number("305")}, - {Value: Number("306")}, - {Value: Number("307")}, - {Value: Number("308")}, - {Value: Number("309")}, - {Value: Number("310")}, - {Value: Number("311")}, - {Value: Number("312")}, - {Value: Number("313")}, - {Value: Number("314")}, - {Value: Number("315")}, - {Value: Number("316")}, - {Value: Number("317")}, - {Value: Number("318")}, - {Value: Number("319")}, - {Value: Number("320")}, - {Value: Number("321")}, - {Value: Number("322")}, - {Value: Number("323")}, - {Value: Number("324")}, - {Value: Number("325")}, - {Value: Number("326")}, - {Value: Number("327")}, - {Value: Number("328")}, - {Value: Number("329")}, - {Value: Number("330")}, - {Value: Number("331")}, - {Value: Number("332")}, - {Value: Number("333")}, - {Value: Number("334")}, - {Value: Number("335")}, - {Value: Number("336")}, - {Value: Number("337")}, - {Value: Number("338")}, - {Value: Number("339")}, - {Value: Number("340")}, - {Value: Number("341")}, - {Value: Number("342")}, - {Value: Number("343")}, - {Value: Number("344")}, - {Value: Number("345")}, - {Value: Number("346")}, - {Value: Number("347")}, - {Value: Number("348")}, - {Value: Number("349")}, - {Value: Number("350")}, - {Value: Number("351")}, - {Value: Number("352")}, - {Value: Number("353")}, - {Value: Number("354")}, - {Value: Number("355")}, - {Value: Number("356")}, - {Value: Number("357")}, - {Value: Number("358")}, - {Value: Number("359")}, - {Value: Number("360")}, - {Value: Number("361")}, - {Value: Number("362")}, - {Value: Number("363")}, - {Value: Number("364")}, - {Value: Number("365")}, - {Value: Number("366")}, - {Value: Number("367")}, - {Value: Number("368")}, - {Value: Number("369")}, - {Value: Number("370")}, - {Value: Number("371")}, - {Value: Number("372")}, - {Value: Number("373")}, - {Value: Number("374")}, - {Value: Number("375")}, - {Value: Number("376")}, - {Value: Number("377")}, - {Value: Number("378")}, - {Value: Number("379")}, - {Value: Number("380")}, - {Value: Number("381")}, - {Value: Number("382")}, - {Value: Number("383")}, - {Value: Number("384")}, - {Value: Number("385")}, - {Value: Number("386")}, - {Value: Number("387")}, - {Value: Number("388")}, - {Value: Number("389")}, - {Value: Number("390")}, - {Value: Number("391")}, - {Value: Number("392")}, - {Value: Number("393")}, - {Value: Number("394")}, - {Value: Number("395")}, - {Value: Number("396")}, - {Value: Number("397")}, - {Value: Number("398")}, - {Value: Number("399")}, - {Value: Number("400")}, - {Value: Number("401")}, - {Value: Number("402")}, - {Value: Number("403")}, - {Value: Number("404")}, - {Value: Number("405")}, - {Value: Number("406")}, - {Value: Number("407")}, - {Value: Number("408")}, - {Value: Number("409")}, - {Value: Number("410")}, - {Value: Number("411")}, - {Value: Number("412")}, - {Value: Number("413")}, - {Value: Number("414")}, - {Value: Number("415")}, - {Value: Number("416")}, - {Value: Number("417")}, - {Value: Number("418")}, - {Value: Number("419")}, - {Value: Number("420")}, - {Value: Number("421")}, - {Value: Number("422")}, - {Value: Number("423")}, - {Value: Number("424")}, - {Value: Number("425")}, - {Value: Number("426")}, - {Value: Number("427")}, - {Value: Number("428")}, - {Value: Number("429")}, - {Value: Number("430")}, - {Value: Number("431")}, - {Value: Number("432")}, - {Value: Number("433")}, - {Value: Number("434")}, - {Value: Number("435")}, - {Value: Number("436")}, - {Value: Number("437")}, - {Value: Number("438")}, - {Value: Number("439")}, - {Value: Number("440")}, - {Value: Number("441")}, - {Value: Number("442")}, - {Value: Number("443")}, - {Value: Number("444")}, - {Value: Number("445")}, - {Value: Number("446")}, - {Value: Number("447")}, - {Value: Number("448")}, - {Value: Number("449")}, - {Value: Number("450")}, - {Value: Number("451")}, - {Value: Number("452")}, - {Value: Number("453")}, - {Value: Number("454")}, - {Value: Number("455")}, - {Value: Number("456")}, - {Value: Number("457")}, - {Value: Number("458")}, - {Value: Number("459")}, - {Value: Number("460")}, - {Value: Number("461")}, - {Value: Number("462")}, - {Value: Number("463")}, - {Value: Number("464")}, - {Value: Number("465")}, - {Value: Number("466")}, - {Value: Number("467")}, - {Value: Number("468")}, - {Value: Number("469")}, - {Value: Number("470")}, - {Value: Number("471")}, - {Value: Number("472")}, - {Value: Number("473")}, - {Value: Number("474")}, - {Value: Number("475")}, - {Value: Number("476")}, - {Value: Number("477")}, - {Value: Number("478")}, - {Value: Number("479")}, - {Value: Number("480")}, - {Value: Number("481")}, - {Value: Number("482")}, - {Value: Number("483")}, - {Value: Number("484")}, - {Value: Number("485")}, - {Value: Number("486")}, - {Value: Number("487")}, - {Value: Number("488")}, - {Value: Number("489")}, - {Value: Number("490")}, - {Value: Number("491")}, - {Value: Number("492")}, - {Value: Number("493")}, - {Value: Number("494")}, - {Value: Number("495")}, - {Value: Number("496")}, - {Value: Number("497")}, - {Value: Number("498")}, - {Value: Number("499")}, - {Value: Number("500")}, - {Value: Number("501")}, - {Value: Number("502")}, - {Value: Number("503")}, - {Value: Number("504")}, - {Value: Number("505")}, - {Value: Number("506")}, - {Value: Number("507")}, - {Value: Number("508")}, - {Value: Number("509")}, - {Value: Number("510")}, - {Value: Number("511")}, - {Value: Number("512")}, + {Value: intNumberValues[0]}, + {Value: intNumberValues[1]}, + {Value: intNumberValues[2]}, + {Value: intNumberValues[3]}, + {Value: intNumberValues[4]}, + {Value: intNumberValues[5]}, + {Value: intNumberValues[6]}, + {Value: intNumberValues[7]}, + {Value: intNumberValues[8]}, + {Value: intNumberValues[9]}, + {Value: intNumberValues[10]}, + {Value: intNumberValues[11]}, + {Value: intNumberValues[12]}, + {Value: intNumberValues[13]}, + {Value: intNumberValues[14]}, + {Value: intNumberValues[15]}, + {Value: intNumberValues[16]}, + {Value: intNumberValues[17]}, + {Value: intNumberValues[18]}, + {Value: intNumberValues[19]}, + {Value: intNumberValues[20]}, + {Value: intNumberValues[21]}, + {Value: intNumberValues[22]}, + {Value: intNumberValues[23]}, + {Value: intNumberValues[24]}, + {Value: intNumberValues[25]}, + {Value: intNumberValues[26]}, + {Value: intNumberValues[27]}, + {Value: intNumberValues[28]}, + {Value: intNumberValues[29]}, + {Value: intNumberValues[30]}, + {Value: intNumberValues[31]}, + {Value: intNumberValues[32]}, + {Value: intNumberValues[33]}, + {Value: intNumberValues[34]}, + {Value: intNumberValues[35]}, + {Value: intNumberValues[36]}, + {Value: intNumberValues[37]}, + {Value: intNumberValues[38]}, + {Value: intNumberValues[39]}, + {Value: intNumberValues[40]}, + {Value: intNumberValues[41]}, + {Value: intNumberValues[42]}, + {Value: intNumberValues[43]}, + {Value: intNumberValues[44]}, + {Value: intNumberValues[45]}, + {Value: intNumberValues[46]}, + {Value: intNumberValues[47]}, + {Value: intNumberValues[48]}, + {Value: intNumberValues[49]}, + {Value: intNumberValues[50]}, + {Value: intNumberValues[51]}, + {Value: intNumberValues[52]}, + {Value: intNumberValues[53]}, + {Value: intNumberValues[54]}, + {Value: intNumberValues[55]}, + {Value: intNumberValues[56]}, + {Value: intNumberValues[57]}, + {Value: intNumberValues[58]}, + {Value: intNumberValues[59]}, + {Value: intNumberValues[60]}, + {Value: intNumberValues[61]}, + {Value: intNumberValues[62]}, + {Value: intNumberValues[63]}, + {Value: intNumberValues[64]}, + {Value: intNumberValues[65]}, + {Value: intNumberValues[66]}, + {Value: intNumberValues[67]}, + {Value: intNumberValues[68]}, + {Value: intNumberValues[69]}, + {Value: intNumberValues[70]}, + {Value: intNumberValues[71]}, + {Value: intNumberValues[72]}, + {Value: intNumberValues[73]}, + {Value: intNumberValues[74]}, + {Value: intNumberValues[75]}, + {Value: intNumberValues[76]}, + {Value: intNumberValues[77]}, + {Value: intNumberValues[78]}, + {Value: intNumberValues[79]}, + {Value: intNumberValues[80]}, + {Value: intNumberValues[81]}, + {Value: intNumberValues[82]}, + {Value: intNumberValues[83]}, + {Value: intNumberValues[84]}, + {Value: intNumberValues[85]}, + {Value: intNumberValues[86]}, + {Value: intNumberValues[87]}, + {Value: intNumberValues[88]}, + {Value: intNumberValues[89]}, + {Value: intNumberValues[90]}, + {Value: intNumberValues[91]}, + {Value: intNumberValues[92]}, + {Value: intNumberValues[93]}, + {Value: intNumberValues[94]}, + {Value: intNumberValues[95]}, + {Value: intNumberValues[96]}, + {Value: intNumberValues[97]}, + {Value: intNumberValues[98]}, + {Value: intNumberValues[99]}, + {Value: intNumberValues[100]}, + {Value: intNumberValues[101]}, + {Value: intNumberValues[102]}, + {Value: intNumberValues[103]}, + {Value: intNumberValues[104]}, + {Value: intNumberValues[105]}, + {Value: intNumberValues[106]}, + {Value: intNumberValues[107]}, + {Value: intNumberValues[108]}, + {Value: intNumberValues[109]}, + {Value: intNumberValues[110]}, + {Value: intNumberValues[111]}, + {Value: intNumberValues[112]}, + {Value: intNumberValues[113]}, + {Value: intNumberValues[114]}, + {Value: intNumberValues[115]}, + {Value: intNumberValues[116]}, + {Value: intNumberValues[117]}, + {Value: intNumberValues[118]}, + {Value: intNumberValues[119]}, + {Value: intNumberValues[120]}, + {Value: intNumberValues[121]}, + {Value: intNumberValues[122]}, + {Value: intNumberValues[123]}, + {Value: intNumberValues[124]}, + {Value: intNumberValues[125]}, + {Value: intNumberValues[126]}, + {Value: intNumberValues[127]}, + {Value: intNumberValues[128]}, + {Value: intNumberValues[129]}, + {Value: intNumberValues[130]}, + {Value: intNumberValues[131]}, + {Value: intNumberValues[132]}, + {Value: intNumberValues[133]}, + {Value: intNumberValues[134]}, + {Value: intNumberValues[135]}, + {Value: intNumberValues[136]}, + {Value: intNumberValues[137]}, + {Value: intNumberValues[138]}, + {Value: intNumberValues[139]}, + {Value: intNumberValues[140]}, + {Value: intNumberValues[141]}, + {Value: intNumberValues[142]}, + {Value: intNumberValues[143]}, + {Value: intNumberValues[144]}, + {Value: intNumberValues[145]}, + {Value: intNumberValues[146]}, + {Value: intNumberValues[147]}, + {Value: intNumberValues[148]}, + {Value: intNumberValues[149]}, + {Value: intNumberValues[150]}, + {Value: intNumberValues[151]}, + {Value: intNumberValues[152]}, + {Value: intNumberValues[153]}, + {Value: intNumberValues[154]}, + {Value: intNumberValues[155]}, + {Value: intNumberValues[156]}, + {Value: intNumberValues[157]}, + {Value: intNumberValues[158]}, + {Value: intNumberValues[159]}, + {Value: intNumberValues[160]}, + {Value: intNumberValues[161]}, + {Value: intNumberValues[162]}, + {Value: intNumberValues[163]}, + {Value: intNumberValues[164]}, + {Value: intNumberValues[165]}, + {Value: intNumberValues[166]}, + {Value: intNumberValues[167]}, + {Value: intNumberValues[168]}, + {Value: intNumberValues[169]}, + {Value: intNumberValues[170]}, + {Value: intNumberValues[171]}, + {Value: intNumberValues[172]}, + {Value: intNumberValues[173]}, + {Value: intNumberValues[174]}, + {Value: intNumberValues[175]}, + {Value: intNumberValues[176]}, + {Value: intNumberValues[177]}, + {Value: intNumberValues[178]}, + {Value: intNumberValues[179]}, + {Value: intNumberValues[180]}, + {Value: intNumberValues[181]}, + {Value: intNumberValues[182]}, + {Value: intNumberValues[183]}, + {Value: intNumberValues[184]}, + {Value: intNumberValues[185]}, + {Value: intNumberValues[186]}, + {Value: intNumberValues[187]}, + {Value: intNumberValues[188]}, + {Value: intNumberValues[189]}, + {Value: intNumberValues[190]}, + {Value: intNumberValues[191]}, + {Value: intNumberValues[192]}, + {Value: intNumberValues[193]}, + {Value: intNumberValues[194]}, + {Value: intNumberValues[195]}, + {Value: intNumberValues[196]}, + {Value: intNumberValues[197]}, + {Value: intNumberValues[198]}, + {Value: intNumberValues[199]}, + {Value: intNumberValues[200]}, + {Value: intNumberValues[201]}, + {Value: intNumberValues[202]}, + {Value: intNumberValues[203]}, + {Value: intNumberValues[204]}, + {Value: intNumberValues[205]}, + {Value: intNumberValues[206]}, + {Value: intNumberValues[207]}, + {Value: intNumberValues[208]}, + {Value: intNumberValues[209]}, + {Value: intNumberValues[210]}, + {Value: intNumberValues[211]}, + {Value: intNumberValues[212]}, + {Value: intNumberValues[213]}, + {Value: intNumberValues[214]}, + {Value: intNumberValues[215]}, + {Value: intNumberValues[216]}, + {Value: intNumberValues[217]}, + {Value: intNumberValues[218]}, + {Value: intNumberValues[219]}, + {Value: intNumberValues[220]}, + {Value: intNumberValues[221]}, + {Value: intNumberValues[222]}, + {Value: intNumberValues[223]}, + {Value: intNumberValues[224]}, + {Value: intNumberValues[225]}, + {Value: intNumberValues[226]}, + {Value: intNumberValues[227]}, + {Value: intNumberValues[228]}, + {Value: intNumberValues[229]}, + {Value: intNumberValues[230]}, + {Value: intNumberValues[231]}, + {Value: intNumberValues[232]}, + {Value: intNumberValues[233]}, + {Value: intNumberValues[234]}, + {Value: intNumberValues[235]}, + {Value: intNumberValues[236]}, + {Value: intNumberValues[237]}, + {Value: intNumberValues[238]}, + {Value: intNumberValues[239]}, + {Value: intNumberValues[240]}, + {Value: intNumberValues[241]}, + {Value: intNumberValues[242]}, + {Value: intNumberValues[243]}, + {Value: intNumberValues[244]}, + {Value: intNumberValues[245]}, + {Value: intNumberValues[246]}, + {Value: intNumberValues[247]}, + {Value: intNumberValues[248]}, + {Value: intNumberValues[249]}, + {Value: intNumberValues[250]}, + {Value: intNumberValues[251]}, + {Value: intNumberValues[252]}, + {Value: intNumberValues[253]}, + {Value: intNumberValues[254]}, + {Value: intNumberValues[255]}, + {Value: intNumberValues[256]}, + {Value: intNumberValues[257]}, + {Value: intNumberValues[258]}, + {Value: intNumberValues[259]}, + {Value: intNumberValues[260]}, + {Value: intNumberValues[261]}, + {Value: intNumberValues[262]}, + {Value: intNumberValues[263]}, + {Value: intNumberValues[264]}, + {Value: intNumberValues[265]}, + {Value: intNumberValues[266]}, + {Value: intNumberValues[267]}, + {Value: intNumberValues[268]}, + {Value: intNumberValues[269]}, + {Value: intNumberValues[270]}, + {Value: intNumberValues[271]}, + {Value: intNumberValues[272]}, + {Value: intNumberValues[273]}, + {Value: intNumberValues[274]}, + {Value: intNumberValues[275]}, + {Value: intNumberValues[276]}, + {Value: intNumberValues[277]}, + {Value: intNumberValues[278]}, + {Value: intNumberValues[279]}, + {Value: intNumberValues[280]}, + {Value: intNumberValues[281]}, + {Value: intNumberValues[282]}, + {Value: intNumberValues[283]}, + {Value: intNumberValues[284]}, + {Value: intNumberValues[285]}, + {Value: intNumberValues[286]}, + {Value: intNumberValues[287]}, + {Value: intNumberValues[288]}, + {Value: intNumberValues[289]}, + {Value: intNumberValues[290]}, + {Value: intNumberValues[291]}, + {Value: intNumberValues[292]}, + {Value: intNumberValues[293]}, + {Value: intNumberValues[294]}, + {Value: intNumberValues[295]}, + {Value: intNumberValues[296]}, + {Value: intNumberValues[297]}, + {Value: intNumberValues[298]}, + {Value: intNumberValues[299]}, + {Value: intNumberValues[300]}, + {Value: intNumberValues[301]}, + {Value: intNumberValues[302]}, + {Value: intNumberValues[303]}, + {Value: intNumberValues[304]}, + {Value: intNumberValues[305]}, + {Value: intNumberValues[306]}, + {Value: intNumberValues[307]}, + {Value: intNumberValues[308]}, + {Value: intNumberValues[309]}, + {Value: intNumberValues[310]}, + {Value: intNumberValues[311]}, + {Value: intNumberValues[312]}, + {Value: intNumberValues[313]}, + {Value: intNumberValues[314]}, + {Value: intNumberValues[315]}, + {Value: intNumberValues[316]}, + {Value: intNumberValues[317]}, + {Value: intNumberValues[318]}, + {Value: intNumberValues[319]}, + {Value: intNumberValues[320]}, + {Value: intNumberValues[321]}, + {Value: intNumberValues[322]}, + {Value: intNumberValues[323]}, + {Value: intNumberValues[324]}, + {Value: intNumberValues[325]}, + {Value: intNumberValues[326]}, + {Value: intNumberValues[327]}, + {Value: intNumberValues[328]}, + {Value: intNumberValues[329]}, + {Value: intNumberValues[330]}, + {Value: intNumberValues[331]}, + {Value: intNumberValues[332]}, + {Value: intNumberValues[333]}, + {Value: intNumberValues[334]}, + {Value: intNumberValues[335]}, + {Value: intNumberValues[336]}, + {Value: intNumberValues[337]}, + {Value: intNumberValues[338]}, + {Value: intNumberValues[339]}, + {Value: intNumberValues[340]}, + {Value: intNumberValues[341]}, + {Value: intNumberValues[342]}, + {Value: intNumberValues[343]}, + {Value: intNumberValues[344]}, + {Value: intNumberValues[345]}, + {Value: intNumberValues[346]}, + {Value: intNumberValues[347]}, + {Value: intNumberValues[348]}, + {Value: intNumberValues[349]}, + {Value: intNumberValues[350]}, + {Value: intNumberValues[351]}, + {Value: intNumberValues[352]}, + {Value: intNumberValues[353]}, + {Value: intNumberValues[354]}, + {Value: intNumberValues[355]}, + {Value: intNumberValues[356]}, + {Value: intNumberValues[357]}, + {Value: intNumberValues[358]}, + {Value: intNumberValues[359]}, + {Value: intNumberValues[360]}, + {Value: intNumberValues[361]}, + {Value: intNumberValues[362]}, + {Value: intNumberValues[363]}, + {Value: intNumberValues[364]}, + {Value: intNumberValues[365]}, + {Value: intNumberValues[366]}, + {Value: intNumberValues[367]}, + {Value: intNumberValues[368]}, + {Value: intNumberValues[369]}, + {Value: intNumberValues[370]}, + {Value: intNumberValues[371]}, + {Value: intNumberValues[372]}, + {Value: intNumberValues[373]}, + {Value: intNumberValues[374]}, + {Value: intNumberValues[375]}, + {Value: intNumberValues[376]}, + {Value: intNumberValues[377]}, + {Value: intNumberValues[378]}, + {Value: intNumberValues[379]}, + {Value: intNumberValues[380]}, + {Value: intNumberValues[381]}, + {Value: intNumberValues[382]}, + {Value: intNumberValues[383]}, + {Value: intNumberValues[384]}, + {Value: intNumberValues[385]}, + {Value: intNumberValues[386]}, + {Value: intNumberValues[387]}, + {Value: intNumberValues[388]}, + {Value: intNumberValues[389]}, + {Value: intNumberValues[390]}, + {Value: intNumberValues[391]}, + {Value: intNumberValues[392]}, + {Value: intNumberValues[393]}, + {Value: intNumberValues[394]}, + {Value: intNumberValues[395]}, + {Value: intNumberValues[396]}, + {Value: intNumberValues[397]}, + {Value: intNumberValues[398]}, + {Value: intNumberValues[399]}, + {Value: intNumberValues[400]}, + {Value: intNumberValues[401]}, + {Value: intNumberValues[402]}, + {Value: intNumberValues[403]}, + {Value: intNumberValues[404]}, + {Value: intNumberValues[405]}, + {Value: intNumberValues[406]}, + {Value: intNumberValues[407]}, + {Value: intNumberValues[408]}, + {Value: intNumberValues[409]}, + {Value: intNumberValues[410]}, + {Value: intNumberValues[411]}, + {Value: intNumberValues[412]}, + {Value: intNumberValues[413]}, + {Value: intNumberValues[414]}, + {Value: intNumberValues[415]}, + {Value: intNumberValues[416]}, + {Value: intNumberValues[417]}, + {Value: intNumberValues[418]}, + {Value: intNumberValues[419]}, + {Value: intNumberValues[420]}, + {Value: intNumberValues[421]}, + {Value: intNumberValues[422]}, + {Value: intNumberValues[423]}, + {Value: intNumberValues[424]}, + {Value: intNumberValues[425]}, + {Value: intNumberValues[426]}, + {Value: intNumberValues[427]}, + {Value: intNumberValues[428]}, + {Value: intNumberValues[429]}, + {Value: intNumberValues[430]}, + {Value: intNumberValues[431]}, + {Value: intNumberValues[432]}, + {Value: intNumberValues[433]}, + {Value: intNumberValues[434]}, + {Value: intNumberValues[435]}, + {Value: intNumberValues[436]}, + {Value: intNumberValues[437]}, + {Value: intNumberValues[438]}, + {Value: intNumberValues[439]}, + {Value: intNumberValues[440]}, + {Value: intNumberValues[441]}, + {Value: intNumberValues[442]}, + {Value: intNumberValues[443]}, + {Value: intNumberValues[444]}, + {Value: intNumberValues[445]}, + {Value: intNumberValues[446]}, + {Value: intNumberValues[447]}, + {Value: intNumberValues[448]}, + {Value: intNumberValues[449]}, + {Value: intNumberValues[450]}, + {Value: intNumberValues[451]}, + {Value: intNumberValues[452]}, + {Value: intNumberValues[453]}, + {Value: intNumberValues[454]}, + {Value: intNumberValues[455]}, + {Value: intNumberValues[456]}, + {Value: intNumberValues[457]}, + {Value: intNumberValues[458]}, + {Value: intNumberValues[459]}, + {Value: intNumberValues[460]}, + {Value: intNumberValues[461]}, + {Value: intNumberValues[462]}, + {Value: intNumberValues[463]}, + {Value: intNumberValues[464]}, + {Value: intNumberValues[465]}, + {Value: intNumberValues[466]}, + {Value: intNumberValues[467]}, + {Value: intNumberValues[468]}, + {Value: intNumberValues[469]}, + {Value: intNumberValues[470]}, + {Value: intNumberValues[471]}, + {Value: intNumberValues[472]}, + {Value: intNumberValues[473]}, + {Value: intNumberValues[474]}, + {Value: intNumberValues[475]}, + {Value: intNumberValues[476]}, + {Value: intNumberValues[477]}, + {Value: intNumberValues[478]}, + {Value: intNumberValues[479]}, + {Value: intNumberValues[480]}, + {Value: intNumberValues[481]}, + {Value: intNumberValues[482]}, + {Value: intNumberValues[483]}, + {Value: intNumberValues[484]}, + {Value: intNumberValues[485]}, + {Value: intNumberValues[486]}, + {Value: intNumberValues[487]}, + {Value: intNumberValues[488]}, + {Value: intNumberValues[489]}, + {Value: intNumberValues[490]}, + {Value: intNumberValues[491]}, + {Value: intNumberValues[492]}, + {Value: intNumberValues[493]}, + {Value: intNumberValues[494]}, + {Value: intNumberValues[495]}, + {Value: intNumberValues[496]}, + {Value: intNumberValues[497]}, + {Value: intNumberValues[498]}, + {Value: intNumberValues[499]}, + {Value: intNumberValues[500]}, + {Value: intNumberValues[501]}, + {Value: intNumberValues[502]}, + {Value: intNumberValues[503]}, + {Value: intNumberValues[504]}, + {Value: intNumberValues[505]}, + {Value: intNumberValues[506]}, + {Value: intNumberValues[507]}, + {Value: intNumberValues[508]}, + {Value: intNumberValues[509]}, + {Value: intNumberValues[510]}, + {Value: intNumberValues[511]}, + {Value: intNumberValues[512]}, } diff --git a/vendor/github.com/open-policy-agent/opa/v1/ast/parser.go b/vendor/github.com/open-policy-agent/opa/v1/ast/parser.go index e5837d678cb..8355186cb9e 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/ast/parser.go +++ b/vendor/github.com/open-policy-agent/opa/v1/ast/parser.go @@ -1056,7 +1056,7 @@ func (p *Parser) parseHead(defaultRule bool) (*Head, bool) { return nil, false } - ref := p.parseTermFinish(term, true) + ref := p.parseHeadFinish(term, true) if ref == nil { p.illegal("expected rule head name") return nil, false @@ -1259,23 +1259,25 @@ func (p *Parser) parseLiteralExpr(negated bool) *Expr { return nil } } - // If we find a plain `every` identifier, attempt to parse an every expression, - // add hint if it succeeds. - if term, ok := expr.Terms.(*Term); ok && Var("every").Equal(term.Value) { - var hint bool - t := p.save() - p.restore(s) - if expr := p.futureParser().parseEvery(); expr != nil { - _, hint = expr.Terms.(*Every) - } - p.restore(t) - if hint { - p.hint("`import future.keywords.every` for `every x in xs { ... }` expressions") + + if p.isFutureKeyword("every") { + // If we find a plain `every` identifier, attempt to parse an every expression, + // add hint if it succeeds. + if term, ok := expr.Terms.(*Term); ok && Var("every").Equal(term.Value) { + var hint bool + t := p.save() + p.restore(s) + if expr := p.futureParser().parseEvery(); expr != nil { + _, hint = expr.Terms.(*Every) + } + p.restore(t) + if hint { + p.hint("`import future.keywords.every` for `every x in xs { ... }` expressions") + } } } - return expr } - return nil + return expr } func (p *Parser) parseWith() []*With { @@ -1368,26 +1370,28 @@ func (p *Parser) parseSome() *Expr { } p.restore(s) - s = p.save() // new copy for later - var hint bool - p.scan() - if term := p.futureParser().parseTermInfixCall(); term != nil { - if call, ok := term.Value.(Call); ok { - switch call[0].String() { - case Member.Name, MemberWithKey.Name: - hint = true + + if p.isFutureKeyword("in") { + s = p.save() // new copy for later + var hint bool + p.scan() + if term := p.futureParser().parseTermInfixCall(); term != nil { + if call, ok := term.Value.(Call); ok { + switch call[0].String() { + case Member.Name, MemberWithKey.Name: + hint = true + } } } - } - // go on as before, it's `some x[...]` or illegal - p.restore(s) - if hint { - p.hint("`import future.keywords.in` for `some x in xs` expressions") + // go on as before, it's `some x[...]` or illegal + p.restore(s) + if hint { + p.hint("`import future.keywords.in` for `some x in xs` expressions") + } } for { // collecting var args - p.scan() if p.s.tok != tokens.Ident { @@ -1774,6 +1778,35 @@ func (p *Parser) parseTermFinish(head *Term, skipws bool) *Term { } } +func (p *Parser) parseHeadFinish(head *Term, skipws bool) *Term { + if head == nil { + return nil + } + offset := p.s.loc.Offset + p.doScan(false) + + switch p.s.tok { + case tokens.Add, tokens.Sub, tokens.Mul, tokens.Quo, tokens.Rem, + tokens.And, tokens.Or, + tokens.Equal, tokens.Neq, tokens.Gt, tokens.Gte, tokens.Lt, tokens.Lte: + p.illegalToken() + case tokens.Whitespace: + p.doScan(skipws) + } + + switch p.s.tok { + case tokens.LParen, tokens.Dot, tokens.LBrack: + return p.parseRef(head, offset) + case tokens.Whitespace: + p.scan() + } + + if _, ok := head.Value.(Var); ok && RootDocumentNames.Contains(head) { + return RefTerm(head).SetLocation(head.Location) + } + return head +} + func (p *Parser) parseNumber() *Term { var prefix string loc := p.s.Loc() @@ -1849,13 +1882,11 @@ func (p *Parser) parseString() *Term { } var s string - err := json.Unmarshal([]byte(p.s.lit), &s) - if err != nil { + if err := json.Unmarshal([]byte(p.s.lit), &s); err != nil { p.errorf(p.s.Loc(), "illegal string literal: %s", p.s.lit) return nil } - term := StringTerm(s).SetLocation(p.s.Loc()) - return term + return StringTerm(s).SetLocation(p.s.Loc()) } return p.parseRawString() } @@ -1864,8 +1895,7 @@ func (p *Parser) parseRawString() *Term { if len(p.s.lit) < 2 { return nil } - term := StringTerm(p.s.lit[1 : len(p.s.lit)-1]).SetLocation(p.s.Loc()) - return term + return StringTerm(p.s.lit[1 : len(p.s.lit)-1]).SetLocation(p.s.Loc()) } // this is the name to use for instantiating an empty set, e.g., `set()`. @@ -2343,7 +2373,7 @@ func (p *Parser) genwildcard() string { } func (p *Parser) error(loc *location.Location, reason string) { - p.errorf(loc, reason) //nolint:govet + p.errorf(loc, "%s", reason) } func (p *Parser) errorf(loc *location.Location, f string, a ...any) { @@ -2566,6 +2596,7 @@ type rawAnnotation struct { RelatedResources []any `yaml:"related_resources"` Authors []any `yaml:"authors"` Schemas []map[string]any `yaml:"schemas"` + Compile map[string]any `yaml:"compile"` Custom map[string]any `yaml:"custom"` } @@ -2633,6 +2664,40 @@ func (b *metadataParser) Parse() (*Annotations, error) { result.RelatedResources = append(result.RelatedResources, rr) } + if raw.Compile != nil { + result.Compile = &CompileAnnotation{} + if unknowns, ok := raw.Compile["unknowns"]; ok { + if unknowns, ok := unknowns.([]any); ok { + result.Compile.Unknowns = make([]Ref, len(unknowns)) + for i := range unknowns { + if unknown, ok := unknowns[i].(string); ok { + ref, err := ParseRef(unknown) + if err != nil { + return nil, fmt.Errorf("invalid unknowns element %q: %w", unknown, err) + } + result.Compile.Unknowns[i] = ref + } + } + } + } + if mask, ok := raw.Compile["mask_rule"]; ok { + if mask, ok := mask.(string); ok { + maskTerm, err := ParseTerm(mask) + if err != nil { + return nil, fmt.Errorf("invalid mask_rule annotation %q: %w", mask, err) + } + switch v := maskTerm.Value.(type) { + case Var, String: + result.Compile.MaskRule = Ref{maskTerm} + case Ref: + result.Compile.MaskRule = v + default: + return nil, fmt.Errorf("invalid mask_rule annotation type %q: %[1]T", mask) + } + } + } + } + for _, pair := range raw.Schemas { k, v := unwrapPair(pair) @@ -2916,6 +2981,11 @@ func IsFutureKeywordForRegoVersion(s string, v RegoVersion) bool { return yes } +// isFutureKeyword answers if keyword is from the "future" with the parser options set. +func (p *Parser) isFutureKeyword(s string) bool { + return IsFutureKeywordForRegoVersion(s, p.po.RegoVersion) +} + func (p *Parser) futureImport(imp *Import, allowedFutureKeywords map[string]tokens.Token) { path := imp.Path.Value.(Ref) diff --git a/vendor/github.com/open-policy-agent/opa/v1/ast/parser_ext.go b/vendor/github.com/open-policy-agent/opa/v1/ast/parser_ext.go index 42b0503690c..f3d4e0d188f 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/ast/parser_ext.go +++ b/vendor/github.com/open-policy-agent/opa/v1/ast/parser_ext.go @@ -687,7 +687,7 @@ func parseModule(filename string, stmts []Statement, comments []*Comment, regoCo case Body: rule, err := ParseRuleFromBody(mod, stmt) if err != nil { - errs = append(errs, NewError(ParseErr, stmt[0].Location, err.Error())) //nolint:govet + errs = append(errs, NewError(ParseErr, stmt[0].Location, "%s", err.Error())) continue } rule.generatedBody = true diff --git a/vendor/github.com/open-policy-agent/opa/v1/ast/performance.go b/vendor/github.com/open-policy-agent/opa/v1/ast/performance.go new file mode 100644 index 00000000000..3e285f963df --- /dev/null +++ b/vendor/github.com/open-policy-agent/opa/v1/ast/performance.go @@ -0,0 +1,85 @@ +// Copyright 2025 The OPA Authors. All rights reserved. +// Use of this source code is governed by an Apache2 +// license that can be found in the LICENSE file. +package ast + +import ( + "strings" + "sync" +) + +var builtinNamesByNumParts = sync.OnceValue(func() map[int][]string { + m := map[int][]string{} + for name := range BuiltinMap { + parts := strings.Count(name, ".") + 1 + if parts > 1 { + m[parts] = append(m[parts], name) + } + } + return m +}) + +// BuiltinNameFromRef attempts to extract a known built-in function name from a ref, +// in the most efficient way possible. I.e. without allocating memory for a new string. +// If no built-in function name can be extracted, the second return value is false. +func BuiltinNameFromRef(ref Ref) (string, bool) { + reflen := len(ref) + if reflen == 0 { + return "", false + } + + _var, ok := ref[0].Value.(Var) + if !ok { + return "", false + } + + varName := string(_var) + if reflen == 1 { + if _, ok := BuiltinMap[varName]; ok { + return varName, true + } + return "", false + } + + totalLen := len(varName) + for _, term := range ref[1:] { + if _, ok = term.Value.(String); !ok { + return "", false + } + totalLen += 1 + len(term.Value.(String)) // account for dot + } + + matched, ok := builtinNamesByNumParts()[reflen] + if !ok { + return "", false + } + + for _, name := range matched { + // This check saves us a huge amount of work, as only very few built-in + // names will have the exact same length as the ref we are checking. + if len(name) != totalLen { + continue + } + // Example: `name` is "io.jwt.decode" (and so is ref) + // The first part is varName, which have already been established to be 'io': + // io, jwt.decode io == io + if curr, remaining, _ := strings.Cut(name, "."); curr == varName { + // Loop over the remaining (now known to be string) terms in the ref, e.g. "jwt" and "decode" + for _, term := range ref[1:] { + ts := string(term.Value.(String)) + // First iteration: jwt.decode != jwt, so we continue cutting + // Second iteration: remaining is "decode", and so is term + if remaining == ts { + return name, true + } + // Cutting remaining (e.g. jwt.decode), and we now get: + // jwt, decode, false || jwt != jwt + if curr, remaining, _ = strings.Cut(remaining, "."); remaining == "" || curr != ts { + break + } + } + } + } + + return "", false +} diff --git a/vendor/github.com/open-policy-agent/opa/v1/ast/policy.go b/vendor/github.com/open-policy-agent/opa/v1/ast/policy.go index fd669f1e781..62c82f51ec0 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/ast/policy.go +++ b/vendor/github.com/open-policy-agent/opa/v1/ast/policy.go @@ -1050,10 +1050,10 @@ func (head *Head) MarshalJSON() ([]byte, error) { // Vars returns a set of vars found in the head. func (head *Head) Vars() VarSet { - vis := &VarVisitor{vars: VarSet{}} + vis := NewVarVisitor() // TODO: improve test coverage for this. if head.Args != nil { - vis.Walk(head.Args) + vis.WalkArgs(head.Args) } if head.Key != nil { vis.Walk(head.Key) @@ -1062,7 +1062,7 @@ func (head *Head) Vars() VarSet { vis.Walk(head.Value) } if len(head.Reference) > 0 { - vis.Walk(head.Reference[1:]) + vis.WalkRef(head.Reference[1:]) } return vis.vars } @@ -1119,8 +1119,8 @@ func (a Args) SetLoc(loc *Location) { // Vars returns a set of vars that appear in a. func (a Args) Vars() VarSet { - vis := &VarVisitor{vars: VarSet{}} - vis.Walk(a) + vis := NewVarVisitor() + vis.WalkArgs(a) return vis.vars } @@ -1243,7 +1243,7 @@ func (body Body) String() string { // control which vars are included. func (body Body) Vars(params VarVisitorParams) VarSet { vis := NewVarVisitor().WithParams(params) - vis.Walk(body) + vis.WalkBody(body) return vis.Vars() } @@ -1763,7 +1763,7 @@ func (q *Every) Compare(other *Every) int { // KeyValueVars returns the key and val arguments of an `every` // expression, if they are non-nil and not wildcards. func (q *Every) KeyValueVars() VarSet { - vis := &VarVisitor{vars: VarSet{}} + vis := NewVarVisitor() if q.Key != nil { vis.Walk(q.Key) } diff --git a/vendor/github.com/open-policy-agent/opa/v1/ast/rego_compiler.go b/vendor/github.com/open-policy-agent/opa/v1/ast/rego_compiler.go new file mode 100644 index 00000000000..78d0efc59ab --- /dev/null +++ b/vendor/github.com/open-policy-agent/opa/v1/ast/rego_compiler.go @@ -0,0 +1,17 @@ +package ast + +import "context" + +type regoCompileCtx struct{} + +func WithCompiler(ctx context.Context, c *Compiler) context.Context { + return context.WithValue(ctx, regoCompileCtx{}, c) +} + +func CompilerFromContext(ctx context.Context) (*Compiler, bool) { + if ctx == nil { + return nil, false + } + v, ok := ctx.Value(regoCompileCtx{}).(*Compiler) + return v, ok +} diff --git a/vendor/github.com/open-policy-agent/opa/v1/ast/syncpools.go b/vendor/github.com/open-policy-agent/opa/v1/ast/syncpools.go index cb150d39b52..82977c836bf 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/ast/syncpools.go +++ b/vendor/github.com/open-policy-agent/opa/v1/ast/syncpools.go @@ -17,6 +17,10 @@ type indexResultPool struct { pool sync.Pool } +type vvPool struct { + pool sync.Pool +} + func (p *termPtrPool) Get() *Term { return p.pool.Get().(*Term) } @@ -44,6 +48,17 @@ func (p *indexResultPool) Put(x *IndexResult) { } } +func (p *vvPool) Get() *VarVisitor { + return p.pool.Get().(*VarVisitor) +} + +func (p *vvPool) Put(vv *VarVisitor) { + if vv != nil { + vv.Clear() + p.pool.Put(vv) + } +} + var TermPtrPool = &termPtrPool{ pool: sync.Pool{ New: func() any { @@ -60,6 +75,14 @@ var sbPool = &stringBuilderPool{ }, } +var varVisitorPool = &vvPool{ + pool: sync.Pool{ + New: func() any { + return NewVarVisitor() + }, + }, +} + var IndexResultPool = &indexResultPool{ pool: sync.Pool{ New: func() any { diff --git a/vendor/github.com/open-policy-agent/opa/v1/ast/term.go b/vendor/github.com/open-policy-agent/opa/v1/ast/term.go index 6b21e3f53c3..18f8a423d9e 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/ast/term.go +++ b/vendor/github.com/open-policy-agent/opa/v1/ast/term.go @@ -12,7 +12,6 @@ import ( "fmt" "io" "math" - "math/big" "net/url" "regexp" "slices" @@ -61,20 +60,20 @@ func InterfaceToValue(x any) (Value, error) { case nil: return NullValue, nil case bool: - return InternedTerm(x).Value, nil + return InternedValue(x), nil case json.Number: if interned := InternedIntNumberTermFromString(string(x)); interned != nil { return interned.Value, nil } return Number(x), nil + case int: + return InternedValueOr(x, newIntNumberValue), nil case int64: - return int64Number(x), nil + return InternedValueOr(x, newInt64NumberValue), nil case uint64: - return uint64Number(x), nil + return InternedValueOr(x, newUint64NumberValue), nil case float64: return floatNumber(x), nil - case int: - return intNumber(x), nil case string: return String(x), nil case []any: @@ -452,7 +451,7 @@ func (term *Term) UnmarshalJSON(bs []byte) error { // Vars returns a VarSet with variables contained in this term. func (term *Term) Vars() VarSet { - vis := &VarVisitor{vars: VarSet{}} + vis := NewVarVisitor() vis.Walk(term) return vis.vars } @@ -586,10 +585,7 @@ type Boolean bool // BooleanTerm creates a new Term with a Boolean value. func BooleanTerm(b bool) *Term { - if b { - return &Term{Value: InternedTerm(true).Value} - } - return &Term{Value: InternedTerm(false).Value} + return &Term{Value: internedBooleanValue(b)} } // Equal returns true if the other Value is a Boolean and is equal. @@ -656,12 +652,12 @@ func NumberTerm(n json.Number) *Term { // IntNumberTerm creates a new Term with an integer Number value. func IntNumberTerm(i int) *Term { - return &Term{Value: Number(strconv.Itoa(i))} + return &Term{Value: newIntNumberValue(i)} } // UIntNumberTerm creates a new Term with an unsigned integer Number value. func UIntNumberTerm(u uint64) *Term { - return &Term{Value: uint64Number(u)} + return &Term{Value: newUint64NumberValue(u)} } // FloatNumberTerm creates a new Term with a floating point Number value. @@ -672,19 +668,10 @@ func FloatNumberTerm(f float64) *Term { // Equal returns true if the other Value is a Number and is equal. func (num Number) Equal(other Value) bool { - switch other := other.(type) { - case Number: - if n1, ok1 := num.Int64(); ok1 { - n2, ok2 := other.Int64() - if ok1 && ok2 { - return n1 == n2 - } - } - - return num.Compare(other) == 0 - default: - return false + if other, ok := other.(Number); ok { + return NumberCompare(num, other) == 0 } + return false } // Compare compares num to other, return <0, 0, or >0 if it is less than, equal to, @@ -692,17 +679,7 @@ func (num Number) Equal(other Value) bool { func (num Number) Compare(other Value) int { // Optimize for the common case, as calling Compare allocates on heap. if otherNum, yes := other.(Number); yes { - if ai, ok := num.Int64(); ok { - if bi, ok := otherNum.Int64(); ok { - if ai == bi { - return 0 - } - if ai < bi { - return -1 - } - return 1 - } - } + return NumberCompare(num, otherNum) } return Compare(num, other) @@ -718,13 +695,15 @@ func (num Number) Find(path Ref) (Value, error) { // Hash returns the hash code for the Value. func (num Number) Hash() int { - f, err := json.Number(num).Float64() - if err != nil { - bs := []byte(num) - h := xxhash.Sum64(bs) - return int(h) + if len(num) < 4 { + if i, err := strconv.Atoi(string(num)); err == nil { + return i + } + } + if f, ok := num.Float64(); ok { + return int(f) } - return int(f) + return int(xxhash.Sum64String(string(num))) } // Int returns the int representation of num if possible. @@ -765,15 +744,15 @@ func (num Number) String() string { return string(num) } -func intNumber(i int) Number { +func newIntNumberValue(i int) Value { return Number(strconv.Itoa(i)) } -func int64Number(i int64) Number { +func newInt64NumberValue(i int64) Value { return Number(strconv.FormatInt(i, 10)) } -func uint64Number(u uint64) Number { +func newUint64NumberValue(u uint64) Value { return Number(strconv.FormatUint(u, 10)) } @@ -1175,59 +1154,75 @@ func IsVarCompatibleString(s string) bool { return varRegexp.MatchString(s) } +var bbPool = &sync.Pool{ + New: func() any { + return new(bytes.Buffer) + }, +} + func (ref Ref) String() string { - if len(ref) == 0 { + // Note(anderseknert): + // Options tried in the order of cheapness, where after some effort, + // only the last option now requires a (single) allocation: + // 1. empty ref + // 2. single var ref + // 3. built-in function ref + // 4. concatenated parts + reflen := len(ref) + if reflen == 0 { return "" } - - if len(ref) == 1 { - switch p := ref[0].Value.(type) { - case Var: - return p.String() - } + if reflen == 1 { + return ref[0].Value.String() + } + if name, ok := BuiltinNameFromRef(ref); ok { + return name } - sb := sbPool.Get() - defer sbPool.Put(sb) + _var := ref[0].Value.String() + + bb := bbPool.Get().(*bytes.Buffer) + bb.Reset() + + defer bbPool.Put(bb) - sb.Grow(10 * len(ref)) - sb.WriteString(ref[0].Value.String()) + bb.Grow(len(_var) + len(ref[1:])*7) // rough estimate + bb.WriteString(_var) for _, p := range ref[1:] { switch p := p.Value.(type) { case String: str := string(p) - if varRegexp.MatchString(str) && !IsKeyword(str) { - sb.WriteByte('.') - sb.WriteString(str) + if IsVarCompatibleString(str) && !IsKeyword(str) { + bb.WriteByte('.') + bb.WriteString(str) } else { - sb.WriteByte('[') + bb.WriteByte('[') // Determine whether we need the full JSON-escaped form if strings.ContainsFunc(str, isControlOrBackslash) { - // only now pay the cost of expensive JSON-escaped form - sb.WriteString(p.String()) + bb.Write(strconv.AppendQuote(bb.AvailableBuffer(), str)) } else { - sb.WriteByte('"') - sb.WriteString(str) - sb.WriteByte('"') + bb.WriteByte('"') + bb.WriteString(str) + bb.WriteByte('"') } - sb.WriteByte(']') + bb.WriteByte(']') } default: - sb.WriteByte('[') - sb.WriteString(p.String()) - sb.WriteByte(']') + bb.WriteByte('[') + bb.WriteString(p.String()) + bb.WriteByte(']') } } - return sb.String() + return bb.String() } // OutputVars returns a VarSet containing variables that would be bound by evaluating // this expression in isolation. func (ref Ref) OutputVars() VarSet { vis := NewVarVisitor().WithParams(VarVisitorParams{SkipRefHead: true}) - vis.Walk(ref) + vis.WalkRef(ref) return vis.Vars() } @@ -1331,10 +1326,7 @@ func (arr *Array) Find(path Ref) (Value, error) { return nil, errFindNotFound } i, ok := num.Int() - if !ok { - return nil, errFindNotFound - } - if i < 0 || i >= arr.Len() { + if !ok || i < 0 || i >= arr.Len() { return nil, errFindNotFound } @@ -1355,12 +1347,7 @@ func (arr *Array) Get(pos *Term) *Term { return nil } - i, ok := num.Int() - if !ok { - return nil - } - - if i >= 0 && i < len(arr.elems) { + if i, ok := num.Int(); ok && i >= 0 && i < len(arr.elems) { return arr.elems[i] } @@ -1779,85 +1766,9 @@ func (s *set) Slice() []*Term { func (s *set) insert(x *Term, resetSortGuard bool) { hash := x.Hash() insertHash := hash - // This `equal` utility is duplicated and manually inlined a number of - // time in this file. Inlining it avoids heap allocations, so it makes - // a big performance difference: some operations like lookup become twice - // as slow without it. - var equal func(v Value) bool - - switch x := x.Value.(type) { - case Null, Boolean, String, Var: - equal = func(y Value) bool { return x == y } - case Number: - if xi, err := json.Number(x).Int64(); err == nil { - equal = func(y Value) bool { - if y, ok := y.(Number); ok { - if yi, err := json.Number(y).Int64(); err == nil { - return xi == yi - } - } - - return false - } - break - } - - // We use big.Rat for comparing big numbers. - // It replaces big.Float due to following reason: - // big.Float comes with a default precision of 64, and setting a - // larger precision results in more memory being allocated - // (regardless of the actual number we are parsing with SetString). - // - // Note: If we're so close to zero that big.Float says we are zero, do - // *not* big.Rat).SetString on the original string it'll potentially - // take very long. - var a *big.Rat - fa, ok := new(big.Float).SetString(string(x)) - if !ok { - panic("illegal value") - } - if fa.IsInt() { - if i, _ := fa.Int64(); i == 0 { - a = new(big.Rat).SetInt64(0) - } - } - if a == nil { - a, ok = new(big.Rat).SetString(string(x)) - if !ok { - panic("illegal value") - } - } - - equal = func(b Value) bool { - if bNum, ok := b.(Number); ok { - var b *big.Rat - fb, ok := new(big.Float).SetString(string(bNum)) - if !ok { - panic("illegal value") - } - if fb.IsInt() { - if i, _ := fb.Int64(); i == 0 { - b = new(big.Rat).SetInt64(0) - } - } - if b == nil { - b, ok = new(big.Rat).SetString(string(bNum)) - if !ok { - panic("illegal value") - } - } - - return a.Cmp(b) == 0 - } - - return false - } - default: - equal = func(y Value) bool { return Compare(x, y) == 0 } - } for curr, ok := s.elems[insertHash]; ok; { - if equal(curr.Value) { + if KeyHashEqual(curr.Value, x.Value) { return } @@ -1883,87 +1794,18 @@ func (s *set) insert(x *Term, resetSortGuard bool) { } func (s *set) get(x *Term) *Term { - hash := x.Hash() - // This `equal` utility is duplicated and manually inlined a number of - // time in this file. Inlining it avoids heap allocations, so it makes - // a big performance difference: some operations like lookup become twice - // as slow without it. - var equal func(v Value) bool - - switch x := x.Value.(type) { - case Null, Boolean, String, Var: - equal = func(y Value) bool { return x == y } - case Number: - if xi, err := json.Number(x).Int64(); err == nil { - equal = func(y Value) bool { - if y, ok := y.(Number); ok { - if yi, err := json.Number(y).Int64(); err == nil { - return xi == yi - } - } - - return false - } - break - } - - // We use big.Rat for comparing big numbers. - // It replaces big.Float due to following reason: - // big.Float comes with a default precision of 64, and setting a - // larger precision results in more memory being allocated - // (regardless of the actual number we are parsing with SetString). - // - // Note: If we're so close to zero that big.Float says we are zero, do - // *not* big.Rat).SetString on the original string it'll potentially - // take very long. - var a *big.Rat - fa, ok := new(big.Float).SetString(string(x)) - if !ok { - panic("illegal value") - } - if fa.IsInt() { - if i, _ := fa.Int64(); i == 0 { - a = new(big.Rat).SetInt64(0) - } - } - if a == nil { - a, ok = new(big.Rat).SetString(string(x)) - if !ok { - panic("illegal value") - } - } - - equal = func(b Value) bool { - if bNum, ok := b.(Number); ok { - var b *big.Rat - fb, ok := new(big.Float).SetString(string(bNum)) - if !ok { - panic("illegal value") - } - if fb.IsInt() { - if i, _ := fb.Int64(); i == 0 { - b = new(big.Rat).SetInt64(0) - } - } - if b == nil { - b, ok = new(big.Rat).SetString(string(bNum)) - if !ok { - panic("illegal value") - } - } - - return a.Cmp(b) == 0 - } - return false - - } - - default: - equal = func(y Value) bool { return Compare(x, y) == 0 } + if len(s.elems) == 0 { + return nil } + hash := x.Hash() + for curr, ok := s.elems[hash]; ok; { - if equal(curr.Value) { + // Pointer equality check first + if curr == x { + return curr + } + if KeyHashEqual(curr.Value, x.Value) { return curr } @@ -2194,24 +2036,21 @@ func (l *lazyObj) Find(path Ref) (Value, error) { } type object struct { - elems map[int]*objectElem - keys objectElemSlice - ground int // number of key and value grounds. Counting is - // required to support insert's key-value replace. + elems map[int]*objectElem + keys []*objectElem + ground int // number of key and value grounds. Counting is required to support insert's key-value replace. hash int sortGuard sync.Once // Prevents race condition around sorting. } func newobject(n int) *object { - var keys objectElemSlice + var keys []*objectElem if n > 0 { - keys = make(objectElemSlice, 0, n) + keys = make([]*objectElem, 0, n) } return &object{ elems: make(map[int]*objectElem, n), keys: keys, - ground: 0, - hash: 0, sortGuard: sync.Once{}, } } @@ -2222,19 +2061,13 @@ type objectElem struct { next *objectElem } -type objectElemSlice []*objectElem - -func (s objectElemSlice) Less(i, j int) bool { return Compare(s[i].key.Value, s[j].key.Value) < 0 } -func (s objectElemSlice) Swap(i, j int) { s[i], s[j] = s[j], s[i] } -func (s objectElemSlice) Len() int { return len(s) } - // Item is a helper for constructing an tuple containing two Terms // representing a key/value pair in an Object. func Item(key, value *Term) [2]*Term { return [2]*Term{key, value} } -func (obj *object) sortedKeys() objectElemSlice { +func (obj *object) sortedKeys() []*objectElem { obj.sortGuard.Do(func() { slices.SortFunc(obj.keys, func(a, b *objectElem) int { return a.key.Value.Compare(b.key.Value) @@ -2313,12 +2146,37 @@ func (obj *object) Insert(k, v *Term) { // Get returns the value of k in obj if k exists, otherwise nil. func (obj *object) Get(k *Term) *Term { - if elem := obj.get(k); elem != nil { - return elem.value + if len(obj.elems) == 0 { + return nil + } + + hash := k.Hash() + for curr := obj.elems[hash]; curr != nil; curr = curr.next { + // Pointer equality check always fastest, and not too unlikely with interning. + if curr.key == k { + return curr.value + } + + if KeyHashEqual(curr.key.Value, k.Value) { + return curr.value + } } return nil } +func KeyHashEqual(x, y Value) bool { + switch x := x.(type) { + case Null, Boolean, String, Var: + return x == y + case Number: + if y, ok := y.(Number); ok { + return x.Equal(y) + } + } + + return Compare(x, y) == 0 +} + // Hash returns the hash code for the Value. func (obj *object) Hash() int { return obj.hash @@ -2525,91 +2383,7 @@ func (obj *object) String() string { return sb.String() } -func (obj *object) get(k *Term) *objectElem { - hash := k.Hash() - - // This `equal` utility is duplicated and manually inlined a number of - // time in this file. Inlining it avoids heap allocations, so it makes - // a big performance difference: some operations like lookup become twice - // as slow without it. - var equal func(v Value) bool - - switch x := k.Value.(type) { - case Null, Boolean, String, Var: - equal = func(y Value) bool { return x == y } - case Number: - if xi, ok := x.Int64(); ok { - equal = func(y Value) bool { - if y, ok := y.(Number); ok { - if yi, ok := y.Int64(); ok { - return xi == yi - } - } - - return false - } - break - } - - // We use big.Rat for comparing big numbers. - // It replaces big.Float due to following reason: - // big.Float comes with a default precision of 64, and setting a - // larger precision results in more memory being allocated - // (regardless of the actual number we are parsing with SetString). - // - // Note: If we're so close to zero that big.Float says we are zero, do - // *not* big.Rat).SetString on the original string it'll potentially - // take very long. - var a *big.Rat - fa, ok := new(big.Float).SetString(string(x)) - if !ok { - panic("illegal value") - } - if fa.IsInt() { - if i, _ := fa.Int64(); i == 0 { - a = new(big.Rat).SetInt64(0) - } - } - if a == nil { - a, ok = new(big.Rat).SetString(string(x)) - if !ok { - panic("illegal value") - } - } - - equal = func(b Value) bool { - if bNum, ok := b.(Number); ok { - var b *big.Rat - fb, ok := new(big.Float).SetString(string(bNum)) - if !ok { - panic("illegal value") - } - if fb.IsInt() { - if i, _ := fb.Int64(); i == 0 { - b = new(big.Rat).SetInt64(0) - } - } - if b == nil { - b, ok = new(big.Rat).SetString(string(bNum)) - if !ok { - panic("illegal value") - } - } - - return a.Cmp(b) == 0 - } - - return false - } - default: - equal = func(y Value) bool { return Compare(x, y) == 0 } - } - - for curr := obj.elems[hash]; curr != nil; curr = curr.next { - if equal(curr.key.Value) { - return curr - } - } +func (*object) get(*Term) *objectElem { return nil } @@ -2618,89 +2392,9 @@ func (obj *object) get(k *Term) *objectElem { func (obj *object) insert(k, v *Term, resetSortGuard bool) { hash := k.Hash() head := obj.elems[hash] - // This `equal` utility is duplicated and manually inlined a number of - // time in this file. Inlining it avoids heap allocations, so it makes - // a big performance difference: some operations like lookup become twice - // as slow without it. - var equal func(v Value) bool - - switch x := k.Value.(type) { - case Null, Boolean, String, Var: - equal = func(y Value) bool { return x == y } - case Number: - if xi, err := json.Number(x).Int64(); err == nil { - equal = func(y Value) bool { - if y, ok := y.(Number); ok { - if yi, err := json.Number(y).Int64(); err == nil { - return xi == yi - } - } - - return false - } - break - } - - // We use big.Rat for comparing big numbers. - // It replaces big.Float due to following reason: - // big.Float comes with a default precision of 64, and setting a - // larger precision results in more memory being allocated - // (regardless of the actual number we are parsing with SetString). - // - // Note: If we're so close to zero that big.Float says we are zero, do - // *not* big.Rat).SetString on the original string it'll potentially - // take very long. - var a *big.Rat - fa, ok := new(big.Float).SetString(string(x)) - if !ok { - panic("illegal value") - } - if fa.IsInt() { - if i, _ := fa.Int64(); i == 0 { - a = new(big.Rat).SetInt64(0) - } - } - if a == nil { - a, ok = new(big.Rat).SetString(string(x)) - if !ok { - panic("illegal value") - } - } - - equal = func(b Value) bool { - if bNum, ok := b.(Number); ok { - var b *big.Rat - fb, ok := new(big.Float).SetString(string(bNum)) - if !ok { - panic("illegal value") - } - if fb.IsInt() { - if i, _ := fb.Int64(); i == 0 { - b = new(big.Rat).SetInt64(0) - } - } - if b == nil { - b, ok = new(big.Rat).SetString(string(bNum)) - if !ok { - panic("illegal value") - } - } - - return a.Cmp(b) == 0 - } - - return false - } - default: - equal = func(y Value) bool { return Compare(x, y) == 0 } - } for curr := head; curr != nil; curr = curr.next { - if equal(curr.key.Value) { - // The ground bit of the value may change in - // replace, hence adjust the counter per old - // and new value. - + if KeyHashEqual(curr.key.Value, k.Value) { if curr.value.IsGround() { obj.ground-- } @@ -2708,20 +2402,21 @@ func (obj *object) insert(k, v *Term, resetSortGuard bool) { obj.ground++ } + // Update hash based on the new value curr.value = v + obj.elems[hash] = curr + obj.hash = 0 + for ehash := range obj.elems { + obj.hash += ehash + obj.elems[ehash].value.Hash() + } - obj.rehash() return } } - elem := &objectElem{ - key: k, - value: v, - next: head, - } - obj.elems[hash] = elem + + obj.elems[hash] = &objectElem{key: k, value: v, next: head} // O(1) insertion, but we'll have to re-sort the keys later. - obj.keys = append(obj.keys, elem) + obj.keys = append(obj.keys, obj.elems[hash]) if resetSortGuard { // Reset the sync.Once instance. @@ -2742,19 +2437,6 @@ func (obj *object) insert(k, v *Term, resetSortGuard bool) { } } -func (obj *object) rehash() { - // obj.keys is considered truth, from which obj.hash and obj.elems are recalculated. - - obj.hash = 0 - obj.elems = make(map[int]*objectElem, len(obj.keys)) - - for _, elem := range obj.keys { - hash := elem.key.Hash() - obj.hash += hash + elem.value.Hash() - obj.elems[hash] = elem - } -} - func filterObject(o Value, filter Value) (Value, error) { if (Null{}).Equal(filter) { return o, nil diff --git a/vendor/github.com/open-policy-agent/opa/v1/ast/unify.go b/vendor/github.com/open-policy-agent/opa/v1/ast/unify.go index 3af52815f79..acbe275c0fc 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/ast/unify.go +++ b/vendor/github.com/open-policy-agent/opa/v1/ast/unify.go @@ -21,10 +21,12 @@ func isRefSafe(ref Ref, safe VarSet) bool { } func isCallSafe(call Call, safe VarSet) bool { - vis := NewVarVisitor().WithParams(SafetyCheckVisitorParams) + vis := varVisitorPool.Get().WithParams(SafetyCheckVisitorParams) vis.Walk(call) - unsafe := vis.Vars().Diff(safe) - return len(unsafe) == 0 + isSafe := vis.Vars().DiffCount(safe) == 0 + varVisitorPool.Put(vis) + + return isSafe } // Unify returns a set of variables that will be unified when the equality expression defined by @@ -173,11 +175,16 @@ func (u *unifier) unify(a *Term, b *Term) { } func (u *unifier) markAllSafe(x Value) { - vis := u.varVisitor() + vis := varVisitorPool.Get().WithParams(VarVisitorParams{ + SkipRefHead: true, + SkipObjectKeys: true, + SkipClosures: true, + }) vis.Walk(x) for v := range vis.Vars() { u.markSafe(v) } + varVisitorPool.Put(vis) } func (u *unifier) markSafe(x Var) { @@ -204,16 +211,21 @@ func (u *unifier) markSafe(x Var) { func (u *unifier) markUnknown(a, b Var) { if _, ok := u.unknown[a]; !ok { - u.unknown[a] = NewVarSet() + u.unknown[a] = NewVarSet(b) + } else { + u.unknown[a].Add(b) } - u.unknown[a].Add(b) } func (u *unifier) unifyAll(a Var, b Value) { if u.isSafe(a) { u.markAllSafe(b) } else { - vis := u.varVisitor() + vis := varVisitorPool.Get().WithParams(VarVisitorParams{ + SkipRefHead: true, + SkipObjectKeys: true, + SkipClosures: true, + }) vis.Walk(b) unsafe := vis.Vars().Diff(u.safe).Diff(u.unified) if len(unsafe) == 0 { @@ -223,13 +235,6 @@ func (u *unifier) unifyAll(a Var, b Value) { u.markUnknown(a, v) } } + varVisitorPool.Put(vis) } } - -func (*unifier) varVisitor() *VarVisitor { - return NewVarVisitor().WithParams(VarVisitorParams{ - SkipRefHead: true, - SkipObjectKeys: true, - SkipClosures: true, - }) -} diff --git a/vendor/github.com/open-policy-agent/opa/v1/ast/varset.go b/vendor/github.com/open-policy-agent/opa/v1/ast/varset.go index bccb035e30f..e5bd52ae8c8 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/ast/varset.go +++ b/vendor/github.com/open-policy-agent/opa/v1/ast/varset.go @@ -50,19 +50,23 @@ func (s VarSet) Copy() VarSet { // Diff returns a VarSet containing variables in s that are not in vs. func (s VarSet) Diff(vs VarSet) VarSet { - i := 0 + r := NewVarSetOfSize(s.DiffCount(vs)) for v := range s { if !vs.Contains(v) { - i++ + r.Add(v) } } - r := NewVarSetOfSize(i) + return r +} + +// DiffCount returns the number of variables in s that are not in vs. +func (s VarSet) DiffCount(vs VarSet) (i int) { for v := range s { if !vs.Contains(v) { - r.Add(v) + i++ } } - return r + return } // Equal returns true if s contains exactly the same elements as vs. diff --git a/vendor/github.com/open-policy-agent/opa/v1/ast/version_index.json b/vendor/github.com/open-policy-agent/opa/v1/ast/version_index.json index b84f09a2900..b02f785299c 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/ast/version_index.json +++ b/vendor/github.com/open-policy-agent/opa/v1/ast/version_index.json @@ -539,6 +539,13 @@ "PreRelease": "", "Metadata": "" }, + "io.jwt.verify_eddsa": { + "Major": 1, + "Minor": 8, + "Patch": 0, + "PreRelease": "", + "Metadata": "" + }, "io.jwt.verify_es256": { "Major": 0, "Minor": 17, diff --git a/vendor/github.com/open-policy-agent/opa/v1/ast/visit.go b/vendor/github.com/open-policy-agent/opa/v1/ast/visit.go index 16567014f40..4ae6569ad76 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/ast/visit.go +++ b/vendor/github.com/open-policy-agent/opa/v1/ast/visit.go @@ -563,12 +563,37 @@ func NewVarVisitor() *VarVisitor { } } +// Clear resets the visitor to its initial state, and returns it for chaining. +func (vis *VarVisitor) Clear() *VarVisitor { + vis.params = VarVisitorParams{} + clear(vis.vars) + + return vis +} + +// ClearOrNew returns a new VarVisitor if vis is nil, or else a cleared VarVisitor. +func (vis *VarVisitor) ClearOrNew() *VarVisitor { + if vis == nil { + return NewVarVisitor() + } + return vis.Clear() +} + // WithParams sets the parameters in params on vis. func (vis *VarVisitor) WithParams(params VarVisitorParams) *VarVisitor { vis.params = params return vis } +// Add adds a variable v to the visitor's set of variables. +func (vis *VarVisitor) Add(v Var) { + if vis.vars == nil { + vis.vars = NewVarSet(v) + } else { + vis.vars.Add(v) + } +} + // Vars returns a VarSet that contains collected vars. func (vis *VarVisitor) Vars() VarSet { return vis.vars @@ -661,7 +686,7 @@ func (vis *VarVisitor) visit(v any) bool { } } if v, ok := v.(Var); ok { - vis.vars.Add(v) + vis.Add(v) } return false } @@ -687,58 +712,55 @@ func (vis *VarVisitor) Walk(x any) { vis.Walk(x.Comments[i]) } case *Package: - vis.Walk(x.Path) + vis.WalkRef(x.Path) case *Import: vis.Walk(x.Path) - vis.Walk(x.Alias) + if x.Alias != "" { + vis.Add(x.Alias) + } case *Rule: vis.Walk(x.Head) - vis.Walk(x.Body) + vis.WalkBody(x.Body) if x.Else != nil { vis.Walk(x.Else) } case *Head: if len(x.Reference) > 0 { - vis.Walk(x.Reference) + vis.WalkRef(x.Reference) } else { - vis.Walk(x.Name) + vis.Add(x.Name) if x.Key != nil { vis.Walk(x.Key) } } - vis.Walk(x.Args) - + vis.WalkArgs(x.Args) if x.Value != nil { vis.Walk(x.Value) } case Body: - for i := range x { - vis.Walk(x[i]) - } + vis.WalkBody(x) case Args: - for i := range x { - vis.Walk(x[i]) - } + vis.WalkArgs(x) case *Expr: switch ts := x.Terms.(type) { case *Term, *SomeDecl, *Every: vis.Walk(ts) case []*Term: for i := range ts { - vis.Walk(ts[i]) + vis.Walk(ts[i].Value) } } for i := range x.With { vis.Walk(x.With[i]) } case *With: - vis.Walk(x.Target) - vis.Walk(x.Value) + vis.Walk(x.Target.Value) + vis.Walk(x.Value.Value) case *Term: vis.Walk(x.Value) case Ref: for i := range x { - vis.Walk(x[i]) + vis.Walk(x[i].Value) } case *object: x.Foreach(func(k, _ *Term) { @@ -755,29 +777,56 @@ func (vis *VarVisitor) Walk(x any) { vis.Walk(xSlice[i]) } case *ArrayComprehension: - vis.Walk(x.Term) - vis.Walk(x.Body) + vis.Walk(x.Term.Value) + vis.WalkBody(x.Body) case *ObjectComprehension: - vis.Walk(x.Key) - vis.Walk(x.Value) - vis.Walk(x.Body) + vis.Walk(x.Key.Value) + vis.Walk(x.Value.Value) + vis.WalkBody(x.Body) case *SetComprehension: - vis.Walk(x.Term) - vis.Walk(x.Body) + vis.Walk(x.Term.Value) + vis.WalkBody(x.Body) case Call: for i := range x { - vis.Walk(x[i]) + vis.Walk(x[i].Value) } case *Every: if x.Key != nil { - vis.Walk(x.Key) + vis.Walk(x.Key.Value) } vis.Walk(x.Value) vis.Walk(x.Domain) - vis.Walk(x.Body) + vis.WalkBody(x.Body) case *SomeDecl: for i := range x.Symbols { vis.Walk(x.Symbols[i]) } } } + +// WalkArgs exists only to avoid the allocation cost of boxing Args to `any` in the VarVisitor. +// Use it when you know beforehand that the type to walk is Args. +func (vis *VarVisitor) WalkArgs(x Args) { + for i := range x { + vis.Walk(x[i].Value) + } +} + +// WalkRef exists only to avoid the allocation cost of boxing Ref to `any` in the VarVisitor. +// Use it when you know beforehand that the type to walk is a Ref. +func (vis *VarVisitor) WalkRef(ref Ref) { + if vis.params.SkipRefHead { + ref = ref[1:] + } + for _, term := range ref { + vis.Walk(term.Value) + } +} + +// WalkBody exists only to avoid the allocation cost of boxing Body to `any` in the VarVisitor. +// Use it when you know beforehand that the type to walk is a Body. +func (vis *VarVisitor) WalkBody(body Body) { + for _, expr := range body { + vis.Walk(expr) + } +} diff --git a/vendor/github.com/open-policy-agent/opa/v1/bundle/bundle.go b/vendor/github.com/open-policy-agent/opa/v1/bundle/bundle.go index 10519eb9c4d..5b418c360b2 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/bundle/bundle.go +++ b/vendor/github.com/open-policy-agent/opa/v1/bundle/bundle.go @@ -21,6 +21,7 @@ import ( "path/filepath" "reflect" "strings" + "sync" "github.com/gobwas/glob" "github.com/open-policy-agent/opa/internal/file/archive" @@ -29,6 +30,7 @@ import ( astJSON "github.com/open-policy-agent/opa/v1/ast/json" "github.com/open-policy-agent/opa/v1/format" "github.com/open-policy-agent/opa/v1/metrics" + "github.com/open-policy-agent/opa/v1/storage" "github.com/open-policy-agent/opa/v1/util" ) @@ -435,6 +437,45 @@ type PlanModuleFile struct { Raw []byte } +var ( + pluginMtx sync.Mutex + + // The bundle activator to use by default. + bundleExtActivator string + + // The function to use for creating a storage.Store for bundles. + BundleExtStore func() storage.Store +) + +// RegisterDefaultBundleActivator sets the default bundle activator for OPA to use for bundle activation. +// The id must already have been registered with RegisterActivator. +func RegisterDefaultBundleActivator(id string) { + pluginMtx.Lock() + defer pluginMtx.Unlock() + + bundleExtActivator = id +} + +// RegisterStoreFunc sets the function to use for creating storage for bundles +// in OPA. If no function is registered, OPA will use situational defaults to +// decide on what sort of storage.Store to create when bundle storage is +// needed. Typically the default is inmem.Store. +func RegisterStoreFunc(s func() storage.Store) { + pluginMtx.Lock() + defer pluginMtx.Unlock() + + BundleExtStore = s +} + +// HasExtension returns true if a default bundle activator has been set +// with RegisterDefaultBundleActivator. +func HasExtension() bool { + pluginMtx.Lock() + defer pluginMtx.Unlock() + + return bundleExtActivator != "" +} + // Reader contains the reader to load the bundle from. type Reader struct { loader DirectoryLoader @@ -464,10 +505,11 @@ func NewReader(r io.Reader) *Reader { // specified DirectoryLoader. func NewCustomReader(loader DirectoryLoader) *Reader { nr := Reader{ - loader: loader, - metrics: metrics.New(), - files: make(map[string]FileInfo), - sizeLimitBytes: DefaultSizeLimitBytes + 1, + loader: loader, + metrics: metrics.New(), + files: make(map[string]FileInfo), + sizeLimitBytes: DefaultSizeLimitBytes + 1, + lazyLoadingMode: HasExtension(), } return &nr } @@ -721,7 +763,7 @@ func (r *Reader) Read() (Bundle, error) { modulePopts.RegoVersion = regoVersion } r.metrics.Timer(metrics.RegoModuleParse).Start() - mf.Parsed, err = ast.ParseModuleWithOpts(mf.Path, string(mf.Raw), modulePopts) + mf.Parsed, err = ast.ParseModuleWithOpts(mf.Path, util.ByteSliceToString(mf.Raw), modulePopts) r.metrics.Timer(metrics.RegoModuleParse).Stop() if err != nil { return bundle, err diff --git a/vendor/github.com/open-policy-agent/opa/v1/bundle/file.go b/vendor/github.com/open-policy-agent/opa/v1/bundle/file.go index 12e159254cf..d008c3d44c6 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/bundle/file.go +++ b/vendor/github.com/open-policy-agent/opa/v1/bundle/file.go @@ -462,7 +462,7 @@ func (it *iterator) Next() (*storage.Update, error) { f := it.files[it.idx] it.idx++ - isPolicy := false + var isPolicy bool if strings.HasSuffix(f.name, RegoExt) { isPolicy = true } diff --git a/vendor/github.com/open-policy-agent/opa/v1/bundle/keys.go b/vendor/github.com/open-policy-agent/opa/v1/bundle/keys.go index dbd8ff26971..f16fe37fc7e 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/bundle/keys.go +++ b/vendor/github.com/open-policy-agent/opa/v1/bundle/keys.go @@ -6,12 +6,14 @@ package bundle import ( + "crypto/x509" "encoding/pem" + "errors" "fmt" "os" + "strings" - "github.com/open-policy-agent/opa/internal/jwx/jwa" - "github.com/open-policy-agent/opa/internal/jwx/jws/sign" + "github.com/lestrrat-go/jwx/v3/jwa" "github.com/open-policy-agent/opa/v1/keys" "github.com/open-policy-agent/opa/v1/util" @@ -106,26 +108,53 @@ func (s *SigningConfig) WithPlugin(plugin string) *SigningConfig { // GetPrivateKey returns the private key or secret from the signing config func (s *SigningConfig) GetPrivateKey() (any, error) { + var keyData string - block, _ := pem.Decode([]byte(s.Key)) - if block != nil { - return sign.GetSigningKey(s.Key, jwa.SignatureAlgorithm(s.Algorithm)) + alg, ok := jwa.LookupSignatureAlgorithm(s.Algorithm) + if !ok { + return nil, fmt.Errorf("unknown signature algorithm: %s", s.Algorithm) } - var priv string - if _, err := os.Stat(s.Key); err == nil { - bs, err := os.ReadFile(s.Key) - if err != nil { + // Check if the key looks like PEM data first (starts with -----BEGIN) + if strings.HasPrefix(s.Key, "-----BEGIN") { + keyData = s.Key + } else { + // Try to read as a file path + if _, err := os.Stat(s.Key); err == nil { + bs, err := os.ReadFile(s.Key) + if err != nil { + return nil, err + } + keyData = string(bs) + } else if os.IsNotExist(err) { + // Not a file, treat as raw key data + keyData = s.Key + } else { return nil, err } - priv = string(bs) - } else if os.IsNotExist(err) { - priv = s.Key - } else { - return nil, err } - return sign.GetSigningKey(priv, jwa.SignatureAlgorithm(s.Algorithm)) + // For HMAC algorithms, return the key as bytes + if alg == jwa.HS256() || alg == jwa.HS384() || alg == jwa.HS512() { + return []byte(keyData), nil + } + + // For RSA/ECDSA algorithms, parse the PEM-encoded key + block, _ := pem.Decode([]byte(keyData)) + if block == nil { + return nil, errors.New("failed to parse PEM block containing the key") + } + + switch block.Type { + case "RSA PRIVATE KEY": + return x509.ParsePKCS1PrivateKey(block.Bytes) + case "PRIVATE KEY": + return x509.ParsePKCS8PrivateKey(block.Bytes) + case "EC PRIVATE KEY": + return x509.ParseECPrivateKey(block.Bytes) + default: + return nil, fmt.Errorf("unsupported key type: %s", block.Type) + } } // GetClaims returns the claims by reading the file specified in the signing config diff --git a/vendor/github.com/open-policy-agent/opa/v1/bundle/sign.go b/vendor/github.com/open-policy-agent/opa/v1/bundle/sign.go index edc41a1e503..30640731efe 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/bundle/sign.go +++ b/vendor/github.com/open-policy-agent/opa/v1/bundle/sign.go @@ -6,13 +6,11 @@ package bundle import ( - "crypto/rand" - "encoding/json" "fmt" - "maps" - "github.com/open-policy-agent/opa/internal/jwx/jwa" - "github.com/open-policy-agent/opa/internal/jwx/jws" + "github.com/lestrrat-go/jwx/v3/jwa" + "github.com/lestrrat-go/jwx/v3/jwk" + "github.com/lestrrat-go/jwx/v3/jwt" ) const defaultSignerID = "_default" @@ -51,7 +49,7 @@ type DefaultSigner struct{} // included in the payload and the bundle signing config. The keyID if non-empty, // represents the value for the "keyid" claim in the token func (*DefaultSigner) GenerateSignedToken(files []FileInfo, sc *SigningConfig, keyID string) (string, error) { - payload, err := generatePayload(files, sc, keyID) + token, err := generateToken(files, sc, keyID) if err != nil { return "", err } @@ -61,37 +59,35 @@ func (*DefaultSigner) GenerateSignedToken(files []FileInfo, sc *SigningConfig, k return "", err } - var headers jws.StandardHeaders - - if err := headers.Set(jws.AlgorithmKey, jwa.SignatureAlgorithm(sc.Algorithm)); err != nil { - return "", err - } - - if keyID != "" { - if err := headers.Set(jws.KeyIDKey, keyID); err != nil { - return "", err - } + // Parse the algorithm string to jwa.SignatureAlgorithm + alg, ok := jwa.LookupSignatureAlgorithm(sc.Algorithm) + if !ok { + return "", fmt.Errorf("unknown signature algorithm: %s", sc.Algorithm) } - hdr, err := json.Marshal(headers) + // In order to sign the token with a kid, we need a key ID _on_ the key + // (note: we might be able to make this more efficient if we just load + // the key as a JWK from the start) + jwkKey, err := jwk.Import(privateKey) if err != nil { - return "", err + return "", fmt.Errorf("failed to import private key: %w", err) + } + if err := jwkKey.Set(jwk.KeyIDKey, keyID); err != nil { + return "", fmt.Errorf("failed to set key ID on JWK: %w", err) } - token, err := jws.SignLiteral(payload, - jwa.SignatureAlgorithm(sc.Algorithm), - privateKey, - hdr, - rand.Reader) + // Since v3.0.6, jwx will take the fast path for signing the token if + // there's exactly one WithKey in the options with no sub-options + signed, err := jwt.Sign(token, jwt.WithKey(alg, jwkKey)) if err != nil { return "", err } - return string(token), nil + return string(signed), nil } -func generatePayload(files []FileInfo, sc *SigningConfig, keyID string) ([]byte, error) { - payload := make(map[string]any) - payload["files"] = files +func generateToken(files []FileInfo, sc *SigningConfig, keyID string) (jwt.Token, error) { + tb := jwt.NewBuilder() + tb.Claim("files", files) if sc.ClaimsPath != "" { claims, err := sc.GetClaims() @@ -99,12 +95,14 @@ func generatePayload(files []FileInfo, sc *SigningConfig, keyID string) ([]byte, return nil, err } - maps.Copy(payload, claims) + for k, v := range claims { + tb.Claim(k, v) + } } else if keyID != "" { // keyid claim is deprecated but include it for backwards compatibility. - payload["keyid"] = keyID + tb.Claim("keyid", keyID) } - return json.Marshal(payload) + return tb.Build() } // GetSigner returns the Signer registered under the given id diff --git a/vendor/github.com/open-policy-agent/opa/v1/bundle/store.go b/vendor/github.com/open-policy-agent/opa/v1/bundle/store.go index 33e6887d844..992bf78f632 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/bundle/store.go +++ b/vendor/github.com/open-policy-agent/opa/v1/bundle/store.go @@ -12,7 +12,10 @@ import ( "fmt" "maps" "path/filepath" + "slices" + "sort" "strings" + "sync" iCompiler "github.com/open-policy-agent/opa/internal/compiler" "github.com/open-policy-agent/opa/internal/json/patch" @@ -22,6 +25,15 @@ import ( "github.com/open-policy-agent/opa/v1/util" ) +const defaultActivatorID = "_default" + +var ( + activators = map[string]Activator{ + defaultActivatorID: &DefaultActivator{}, + } + activatorMtx sync.Mutex +) + // BundlesBasePath is the storage path used for storing bundle metadata var BundlesBasePath = storage.MustParsePath("/system/bundles") @@ -74,6 +86,12 @@ func moduleInfoPath(id string) storage.Path { func read(ctx context.Context, store storage.Store, txn storage.Transaction, path storage.Path) (any, error) { value, err := store.Read(ctx, txn, path) if err != nil { + if storage.IsNotFound(err) { + return nil, &storage.Error{ + Code: storage.NotFoundErr, + Message: strings.TrimPrefix(path.String(), "/system") + ": document does not exist", + } + } return nil, err } @@ -328,6 +346,11 @@ func readEtagFromStore(ctx context.Context, store storage.Store, txn storage.Tra return str, nil } +// Activator is the interface expected for implementations that activate bundles. +type Activator interface { + Activate(*ActivateOpts) error +} + // ActivateOpts defines options for the Activate API call. type ActivateOpts struct { Ctx context.Context @@ -340,15 +363,39 @@ type ActivateOpts struct { ExtraModules map[string]*ast.Module // Optional AuthorizationDecisionRef ast.Ref ParserOptions ast.ParserOptions + Plugin string legacy bool } +type DefaultActivator struct{} + +func (*DefaultActivator) Activate(opts *ActivateOpts) error { + opts.legacy = false + return activateBundles(opts) +} + // Activate the bundle(s) by loading into the given Store. This will load policies, data, and record // the manifest in storage. The compiler provided will have had the polices compiled on it. func Activate(opts *ActivateOpts) error { - opts.legacy = false - return activateBundles(opts) + plugin := opts.Plugin + + // For backwards compatibility, check if there is no plugin specified, and use default. + if plugin == "" { + // Invoke extension activator if supplied. Otherwise, use default. + if HasExtension() { + plugin = bundleExtActivator + } else { + plugin = defaultActivatorID + } + } + + activator, err := GetActivator(plugin) + if err != nil { + return err + } + + return activator.Activate(opts) } // DeactivateOpts defines options for the Deactivate API call @@ -1020,32 +1067,40 @@ func lookup(path storage.Path, data map[string]any) (any, bool) { return value, ok } -func hasRootsOverlap(ctx context.Context, store storage.Store, txn storage.Transaction, bundles map[string]*Bundle) error { - collisions := map[string][]string{} - allBundles, err := ReadBundleNamesFromStore(ctx, store, txn) +func hasRootsOverlap(ctx context.Context, store storage.Store, txn storage.Transaction, newBundles map[string]*Bundle) error { + storeBundles, err := ReadBundleNamesFromStore(ctx, store, txn) if suppressNotFound(err) != nil { return err } allRoots := map[string][]string{} + bundlesWithEmptyRoots := map[string]bool{} // Build a map of roots for existing bundles already in the system - for _, name := range allBundles { + for _, name := range storeBundles { roots, err := ReadBundleRootsFromStore(ctx, store, txn, name) if suppressNotFound(err) != nil { return err } allRoots[name] = roots + if slices.Contains(roots, "") { + bundlesWithEmptyRoots[name] = true + } } // Add in any bundles that are being activated, overwrite existing roots // with new ones where bundles are in both groups. - for name, bundle := range bundles { + for name, bundle := range newBundles { allRoots[name] = *bundle.Manifest.Roots + if slices.Contains(*bundle.Manifest.Roots, "") { + bundlesWithEmptyRoots[name] = true + } } // Now check for each new bundle if it conflicts with any of the others - for name, bundle := range bundles { + collidingBundles := map[string]bool{} + conflictSet := map[string]bool{} + for name, bundle := range newBundles { for otherBundle, otherRoots := range allRoots { if name == otherBundle { // Skip the current bundle being checked @@ -1055,22 +1110,41 @@ func hasRootsOverlap(ctx context.Context, store storage.Store, txn storage.Trans // Compare the "new" roots with other existing (or a different bundles new roots) for _, newRoot := range *bundle.Manifest.Roots { for _, otherRoot := range otherRoots { - if RootPathsOverlap(newRoot, otherRoot) { - collisions[otherBundle] = append(collisions[otherBundle], newRoot) + if !RootPathsOverlap(newRoot, otherRoot) { + continue + } + + collidingBundles[name] = true + collidingBundles[otherBundle] = true + + // Different message required if the roots are same + if newRoot == otherRoot { + conflictSet[fmt.Sprintf("root %s is in multiple bundles", newRoot)] = true + } else { + paths := []string{newRoot, otherRoot} + sort.Strings(paths) + conflictSet[fmt.Sprintf("%s overlaps %s", paths[0], paths[1])] = true } } } } } - if len(collisions) > 0 { - var bundleNames []string - for name := range collisions { - bundleNames = append(bundleNames, name) - } - return fmt.Errorf("detected overlapping roots in bundle manifest with: %s", bundleNames) + if len(collidingBundles) == 0 { + return nil } - return nil + + bundleNames := strings.Join(util.KeysSorted(collidingBundles), ", ") + + if len(bundlesWithEmptyRoots) > 0 { + return fmt.Errorf( + "bundles [%s] have overlapping roots and cannot be activated simultaneously because bundle(s) [%s] specify empty root paths ('') which overlap with any other bundle root", + bundleNames, + strings.Join(util.KeysSorted(bundlesWithEmptyRoots), ", "), + ) + } + + return fmt.Errorf("detected overlapping roots in manifests for these bundles: [%s] (%s)", bundleNames, strings.Join(util.KeysSorted(conflictSet), ", ")) } func applyPatches(ctx context.Context, store storage.Store, txn storage.Transaction, patches []PatchOperation) error { @@ -1149,3 +1223,29 @@ func ActivateLegacy(opts *ActivateOpts) error { opts.legacy = true return activateBundles(opts) } + +// GetActivator returns the Activator registered under the given id +func GetActivator(id string) (Activator, error) { + activator, ok := activators[id] + + if !ok { + return nil, fmt.Errorf("no activator exists under id %s", id) + } + + return activator, nil +} + +// RegisterActivator registers a bundle Activator under the given id. +// The id value can later be referenced in ActivateOpts.Plugin to specify +// which activator should be used for that bundle activation operation. +// Note: This must be called *before* RegisterDefaultBundleActivator. +func RegisterActivator(id string, a Activator) { + activatorMtx.Lock() + defer activatorMtx.Unlock() + + if id == defaultActivatorID { + panic("cannot use reserved activator id, use a different id") + } + + activators[id] = a +} diff --git a/vendor/github.com/open-policy-agent/opa/v1/bundle/verify.go b/vendor/github.com/open-policy-agent/opa/v1/bundle/verify.go index 829e98acdf8..82e308b49e2 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/bundle/verify.go +++ b/vendor/github.com/open-policy-agent/opa/v1/bundle/verify.go @@ -7,18 +7,52 @@ package bundle import ( "bytes" + "crypto/x509" "encoding/base64" "encoding/hex" "encoding/json" + "encoding/pem" "errors" "fmt" - "github.com/open-policy-agent/opa/internal/jwx/jwa" - "github.com/open-policy-agent/opa/internal/jwx/jws" - "github.com/open-policy-agent/opa/internal/jwx/jws/verify" + "github.com/lestrrat-go/jwx/v3/jwa" + "github.com/lestrrat-go/jwx/v3/jws/jwsbb" "github.com/open-policy-agent/opa/v1/util" ) +// parseVerificationKey converts a string key to the appropriate type for jws.Verify +func parseVerificationKey(keyData string, alg jwa.SignatureAlgorithm) (any, error) { + // For HMAC algorithms, return the key as bytes + if alg == jwa.HS256() || alg == jwa.HS384() || alg == jwa.HS512() { + return []byte(keyData), nil + } + + // For RSA/ECDSA algorithms, try to parse as PEM first + block, _ := pem.Decode([]byte(keyData)) + if block != nil { + switch block.Type { + case "RSA PUBLIC KEY": + return x509.ParsePKCS1PublicKey(block.Bytes) + case "PUBLIC KEY": + return x509.ParsePKIXPublicKey(block.Bytes) + case "RSA PRIVATE KEY": + return x509.ParsePKCS1PrivateKey(block.Bytes) + case "PRIVATE KEY": + return x509.ParsePKCS8PrivateKey(block.Bytes) + case "EC PRIVATE KEY": + return x509.ParseECPrivateKey(block.Bytes) + case "CERTIFICATE": + cert, err := x509.ParseCertificate(block.Bytes) + if err != nil { + return nil, err + } + return cert.PublicKey, nil + } + } + + return nil, errors.New("failed to parse PEM block containing the key") +} + const defaultVerifierID = "_default" var verifiers map[string]Verifier @@ -82,26 +116,42 @@ func (*DefaultVerifier) VerifyBundleSignature(sc SignaturesConfig, bvc *Verifica } func verifyJWTSignature(token string, bvc *VerificationConfig) (*DecodedSignature, error) { - // decode JWT to check if the header specifies the key to use and/or if claims have the scope. - - parts, err := jws.SplitCompact(token) + tokbytes := []byte(token) + hdrb64, payloadb64, signatureb64, err := jwsbb.SplitCompact(tokbytes) if err != nil { - return nil, err + return nil, fmt.Errorf("failed to split compact JWT: %w", err) } - var decodedHeader []byte - if decodedHeader, err = base64.RawURLEncoding.DecodeString(parts[0]); err != nil { - return nil, fmt.Errorf("failed to base64 decode JWT headers: %w", err) + // check for the id of the key to use for JWT signature verification + // first in the OPA config. If not found, then check the JWT kid. + keyID := bvc.KeyID + if keyID == "" { + // Use jwsbb.Header to access into the "kid" header field, which we will + // use to determine the key to use for verification. + hdr := jwsbb.HeaderParseCompact(hdrb64) + v, err := jwsbb.HeaderGetString(hdr, "kid") + switch { + case err == nil: + // err == nils means we found the key ID in the header + keyID = v + case errors.Is(err, jwsbb.ErrHeaderNotFound()): + // no "kid" in the header. no op. + default: + // some other error occurred while trying to extract the key ID + return nil, fmt.Errorf("failed to extract key ID from headers: %w", err) + } } - var hdr jws.StandardHeaders - if err := json.Unmarshal(decodedHeader, &hdr); err != nil { - return nil, fmt.Errorf("failed to parse JWT headers: %w", err) - } - - payload, err := base64.RawURLEncoding.DecodeString(parts[1]) - if err != nil { - return nil, err + // Because we want to fallback to ds.KeyID when we can't find the + // keyID, we need to parse the payload here already. + // + // (lestrrat) Whoa, you're going to trust the payload before you + // verify the signature? Even if it's for backwrds compatibility, + // Is this OK? + decoder := base64.RawURLEncoding + payload := make([]byte, decoder.DecodedLen(len(payloadb64))) + if _, err := decoder.Decode(payload, payloadb64); err != nil { + return nil, fmt.Errorf("failed to base64 decode JWT payload: %w", err) } var ds DecodedSignature @@ -109,17 +159,12 @@ func verifyJWTSignature(token string, bvc *VerificationConfig) (*DecodedSignatur return nil, err } - // check for the id of the key to use for JWT signature verification - // first in the OPA config. If not found, then check the JWT kid. - keyID := bvc.KeyID - if keyID == "" { - keyID = hdr.KeyID - } + // If header has no key id, check the deprecated key claim. if keyID == "" { - // If header has no key id, check the deprecated key claim. keyID = ds.KeyID } + // If we still don't have a keyID, we cannot proceed if keyID == "" { return nil, errors.New("verification key ID is empty") } @@ -130,18 +175,31 @@ func verifyJWTSignature(token string, bvc *VerificationConfig) (*DecodedSignatur return nil, err } - // verify JWT signature - alg := jwa.SignatureAlgorithm(keyConfig.Algorithm) - key, err := verify.GetSigningKey(keyConfig.Key, alg) - if err != nil { - return nil, err + alg, ok := jwa.LookupSignatureAlgorithm(keyConfig.Algorithm) + if !ok { + return nil, fmt.Errorf("unknown signature algorithm: %s", keyConfig.Algorithm) } - _, err = jws.Verify([]byte(token), alg, key) + // Parse the key into the appropriate type + parsedKey, err := parseVerificationKey(keyConfig.Key, alg) if err != nil { return nil, err } + signature := make([]byte, decoder.DecodedLen(len(signatureb64))) + if _, err = decoder.Decode(signature, signatureb64); err != nil { + return nil, fmt.Errorf("failed to base64 decode JWT signature: %w", err) + } + + signbuf := make([]byte, len(hdrb64)+1+len(payloadb64)) + copy(signbuf, hdrb64) + signbuf[len(hdrb64)] = '.' + copy(signbuf[len(hdrb64)+1:], payloadb64) + + if err := jwsbb.Verify(parsedKey, alg.String(), signbuf, signature); err != nil { + return nil, fmt.Errorf("failed to verify JWT signature: %w", err) + } + // verify the scope scope := bvc.Scope if scope == "" { diff --git a/vendor/github.com/open-policy-agent/opa/v1/config/config.go b/vendor/github.com/open-policy-agent/opa/v1/config/config.go index 62bfc65537f..1912d1f38ca 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/config/config.go +++ b/vendor/github.com/open-policy-agent/opa/v1/config/config.go @@ -9,6 +9,7 @@ import ( "encoding/json" "errors" "fmt" + "maps" "os" "path/filepath" "reflect" @@ -21,6 +22,59 @@ import ( "github.com/open-policy-agent/opa/v1/version" ) +// ServerConfig represents the different server configuration options. +type ServerConfig struct { + Metrics json.RawMessage `json:"metrics,omitempty"` + + Encoding json.RawMessage `json:"encoding,omitempty"` + Decoding json.RawMessage `json:"decoding,omitempty"` +} + +// Clone creates a deep copy of ServerConfig. +func (s *ServerConfig) Clone() *ServerConfig { + if s == nil { + return nil + } + + clone := &ServerConfig{} + + if s.Encoding != nil { + clone.Encoding = make(json.RawMessage, len(s.Encoding)) + copy(clone.Encoding, s.Encoding) + } + if s.Decoding != nil { + clone.Decoding = make(json.RawMessage, len(s.Decoding)) + copy(clone.Decoding, s.Decoding) + } + if s.Metrics != nil { + clone.Metrics = make(json.RawMessage, len(s.Metrics)) + copy(clone.Metrics, s.Metrics) + } + + return clone +} + +// StorageConfig represents Config's storage options. +type StorageConfig struct { + Disk json.RawMessage `json:"disk,omitempty"` +} + +// Clone creates a deep copy of StorageConfig. +func (s *StorageConfig) Clone() *StorageConfig { + if s == nil { + return nil + } + + clone := &StorageConfig{} + + if s.Disk != nil { + clone.Disk = make(json.RawMessage, len(s.Disk)) + copy(clone.Disk, s.Disk) + } + + return clone +} + // Config represents the configuration file that OPA can be started with. type Config struct { Services json.RawMessage `json:"services,omitempty"` @@ -38,15 +92,9 @@ type Config struct { NDBuiltinCache bool `json:"nd_builtin_cache,omitempty"` PersistenceDirectory *string `json:"persistence_directory,omitempty"` DistributedTracing json.RawMessage `json:"distributed_tracing,omitempty"` - Server *struct { - Encoding json.RawMessage `json:"encoding,omitempty"` - Decoding json.RawMessage `json:"decoding,omitempty"` - Metrics json.RawMessage `json:"metrics,omitempty"` - } `json:"server,omitempty"` - Storage *struct { - Disk json.RawMessage `json:"disk,omitempty"` - } `json:"storage,omitempty"` - Extra map[string]json.RawMessage `json:"-"` + Server *ServerConfig `json:"server,omitempty"` + Storage *StorageConfig `json:"storage,omitempty"` + Extra map[string]json.RawMessage `json:"-"` } // ParseConfig returns a valid Config object with defaults injected. The id @@ -122,38 +170,6 @@ func (c Config) NDBuiltinCacheEnabled() bool { return c.NDBuiltinCache } -func (c *Config) validateAndInjectDefaults(id string) error { - - if c.DefaultDecision == nil { - s := defaultDecisionPath - c.DefaultDecision = &s - } - - _, err := ref.ParseDataPath(*c.DefaultDecision) - if err != nil { - return err - } - - if c.DefaultAuthorizationDecision == nil { - s := defaultAuthorizationDecisionPath - c.DefaultAuthorizationDecision = &s - } - - _, err = ref.ParseDataPath(*c.DefaultAuthorizationDecision) - if err != nil { - return err - } - - if c.Labels == nil { - c.Labels = map[string]string{} - } - - c.Labels["id"] = id - c.Labels["version"] = version.Version - - return nil -} - // GetPersistenceDirectory returns the configured persistence directory, or $PWD/.opa if none is configured func (c Config) GetPersistenceDirectory() (string, error) { if c.PersistenceDirectory == nil { @@ -197,6 +213,123 @@ func (c *Config) ActiveConfig() (any, error) { return result, nil } +// Clone creates a deep copy of the Config struct +func (c *Config) Clone() *Config { + if c == nil { + return nil + } + + clone := &Config{ + NDBuiltinCache: c.NDBuiltinCache, + Server: c.Server.Clone(), + Storage: c.Storage.Clone(), + Labels: maps.Clone(c.Labels), + } + + if c.Services != nil { + clone.Services = make(json.RawMessage, len(c.Services)) + copy(clone.Services, c.Services) + } + if c.Discovery != nil { + clone.Discovery = make(json.RawMessage, len(c.Discovery)) + copy(clone.Discovery, c.Discovery) + } + if c.Bundle != nil { + clone.Bundle = make(json.RawMessage, len(c.Bundle)) + copy(clone.Bundle, c.Bundle) + } + if c.Bundles != nil { + clone.Bundles = make(json.RawMessage, len(c.Bundles)) + copy(clone.Bundles, c.Bundles) + } + if c.DecisionLogs != nil { + clone.DecisionLogs = make(json.RawMessage, len(c.DecisionLogs)) + copy(clone.DecisionLogs, c.DecisionLogs) + } + if c.Status != nil { + clone.Status = make(json.RawMessage, len(c.Status)) + copy(clone.Status, c.Status) + } + if c.Keys != nil { + clone.Keys = make(json.RawMessage, len(c.Keys)) + copy(clone.Keys, c.Keys) + } + if c.Caching != nil { + clone.Caching = make(json.RawMessage, len(c.Caching)) + copy(clone.Caching, c.Caching) + } + if c.DistributedTracing != nil { + clone.DistributedTracing = make(json.RawMessage, len(c.DistributedTracing)) + copy(clone.DistributedTracing, c.DistributedTracing) + } + + if c.DefaultDecision != nil { + s := *c.DefaultDecision + clone.DefaultDecision = &s + } + if c.DefaultAuthorizationDecision != nil { + s := *c.DefaultAuthorizationDecision + clone.DefaultAuthorizationDecision = &s + } + if c.PersistenceDirectory != nil { + s := *c.PersistenceDirectory + clone.PersistenceDirectory = &s + } + + if c.Plugins != nil { + clone.Plugins = make(map[string]json.RawMessage, len(c.Plugins)) + for k, v := range c.Plugins { + if v != nil { + clone.Plugins[k] = make(json.RawMessage, len(v)) + copy(clone.Plugins[k], v) + } + } + } + + if c.Extra != nil { + clone.Extra = make(map[string]json.RawMessage, len(c.Extra)) + for k, v := range c.Extra { + if v != nil { + clone.Extra[k] = make(json.RawMessage, len(v)) + copy(clone.Extra[k], v) + } + } + } + + return clone +} + +func (c *Config) validateAndInjectDefaults(id string) error { + if c.DefaultDecision == nil { + s := defaultDecisionPath + c.DefaultDecision = &s + } + + _, err := ref.ParseDataPath(*c.DefaultDecision) + if err != nil { + return err + } + + if c.DefaultAuthorizationDecision == nil { + s := defaultAuthorizationDecisionPath + c.DefaultAuthorizationDecision = &s + } + + _, err = ref.ParseDataPath(*c.DefaultAuthorizationDecision) + if err != nil { + return err + } + + if c.Labels == nil { + c.Labels = map[string]string{} + } + + c.Labels["id"] = id + c.Labels["version"] = version.Version + + return nil +} + func removeServiceCredentials(x any) error { switch x := x.(type) { case nil: diff --git a/vendor/github.com/open-policy-agent/opa/v1/format/format.go b/vendor/github.com/open-policy-agent/opa/v1/format/format.go index a9cc32e3cb7..75514d39c00 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/format/format.go +++ b/vendor/github.com/open-policy-agent/opa/v1/format/format.go @@ -18,6 +18,20 @@ import ( "github.com/open-policy-agent/opa/internal/future" "github.com/open-policy-agent/opa/v1/ast" "github.com/open-policy-agent/opa/v1/types" + "github.com/open-policy-agent/opa/v1/util" +) + +// defaultLocationFile is the file name used in `Ast()` for terms +// without a location, as could happen when pretty-printing the +// results of partial eval. +const defaultLocationFile = "__format_default__" + +var ( + elseVar ast.Value = ast.Var("else") + + expandedConst = ast.NewBody(ast.NewExpr(ast.InternedTerm(true))) + commentsSlicePool = util.NewSlicePool[*ast.Comment](50) + varRegexp = regexp.MustCompile("^[[:alpha:]_][[:alpha:][:digit:]_]*$") ) // Opts lets you control the code formatting via `AstWithOpts()`. @@ -38,6 +52,11 @@ type Opts struct { // Imports are only removed if [Opts.RegoVersion] makes them redundant. DropV0Imports bool + // SkipDefensiveCopying, if true, will avoid deep-copying the AST before formatting it. + // This is true by default for all Source* functions, but false by default for Ast* functions, + // as some formatting operations may otherwise mutate the AST. + SkipDefensiveCopying bool + Capabilities *ast.Capabilities } @@ -48,16 +67,11 @@ func (o Opts) effectiveRegoVersion() ast.RegoVersion { return o.RegoVersion } -// defaultLocationFile is the file name used in `Ast()` for terms -// without a location, as could happen when pretty-printing the -// results of partial eval. -const defaultLocationFile = "__format_default__" - // Source formats a Rego source file. The bytes provided must describe a complete // Rego module. If they don't, Source will return an error resulting from the attempt // to parse the bytes. func Source(filename string, src []byte) ([]byte, error) { - return SourceWithOpts(filename, src, Opts{}) + return SourceWithOpts(filename, src, Opts{SkipDefensiveCopying: true}) } func SourceWithOpts(filename string, src []byte, opts Opts) ([]byte, error) { @@ -72,6 +86,9 @@ func SourceWithOpts(filename string, src []byte, opts Opts) ([]byte, error) { parserOpts.RegoVersion = ast.RegoV1 } + // Copying the node does not make sense when both input and output are bytes. + opts.SkipDefensiveCopying = true + if parserOpts.RegoVersion == ast.RegoUndefined { parserOpts.RegoVersion = ast.DefaultRegoVersion } @@ -166,7 +183,9 @@ func AstWithOpts(x any, opts Opts) ([]byte, error) { // The node has to be deep copied because it may be mutated below. Alternatively, // we could avoid the copy by checking if mutation will occur first. For now, // since format is not latency sensitive, just deep copy in all cases. - x = ast.Copy(x) + if !opts.SkipDefensiveCopying { + x = ast.Copy(x) + } wildcards := map[ast.Var]*ast.Term{} @@ -233,10 +252,11 @@ func AstWithOpts(x any, opts Opts) ([]byte, error) { } case *ast.Rule: - if len(n.Head.Ref()) > 2 { + headLen := len(n.Head.Ref()) + if headLen > 2 { o.refHeads = true } - if len(n.Head.Ref()) == 2 && n.Head.Key != nil && n.Head.Value == nil { // p.q contains "x" + if headLen == 2 && n.Head.Key != nil && n.Head.Value == nil { // p.q contains "x" o.refHeads = true } } @@ -277,22 +297,22 @@ func AstWithOpts(x any, opts Opts) ([]byte, error) { } err := w.writeModule(x) if err != nil { - w.errs = append(w.errs, ast.NewError(ast.FormatErr, &ast.Location{}, err.Error())) + w.errs = append(w.errs, ast.NewError(ast.FormatErr, &ast.Location{}, "%s", err.Error())) } case *ast.Package: _, err := w.writePackage(x, nil) if err != nil { - w.errs = append(w.errs, ast.NewError(ast.FormatErr, &ast.Location{}, err.Error())) + w.errs = append(w.errs, ast.NewError(ast.FormatErr, &ast.Location{}, "%s", err.Error())) } case *ast.Import: _, err := w.writeImports([]*ast.Import{x}, nil) if err != nil { - w.errs = append(w.errs, ast.NewError(ast.FormatErr, &ast.Location{}, err.Error())) + w.errs = append(w.errs, ast.NewError(ast.FormatErr, &ast.Location{}, "%s", err.Error())) } case *ast.Rule: _, err := w.writeRule(x, false /* isElse */, nil) if err != nil { - w.errs = append(w.errs, ast.NewError(ast.FormatErr, &ast.Location{}, err.Error())) + w.errs = append(w.errs, ast.NewError(ast.FormatErr, &ast.Location{}, "%s", err.Error())) } case *ast.Head: _, err := w.writeHead(x, @@ -300,7 +320,7 @@ func AstWithOpts(x any, opts Opts) ([]byte, error) { false, // isExpandedConst nil) if err != nil { - w.errs = append(w.errs, ast.NewError(ast.FormatErr, &ast.Location{}, err.Error())) + w.errs = append(w.errs, ast.NewError(ast.FormatErr, &ast.Location{}, "%s", err.Error())) } case ast.Body: _, err := w.writeBody(x, nil) @@ -310,27 +330,27 @@ func AstWithOpts(x any, opts Opts) ([]byte, error) { case *ast.Expr: _, err := w.writeExpr(x, nil) if err != nil { - w.errs = append(w.errs, ast.NewError(ast.FormatErr, &ast.Location{}, err.Error())) + w.errs = append(w.errs, ast.NewError(ast.FormatErr, &ast.Location{}, "%s", err.Error())) } case *ast.With: _, err := w.writeWith(x, nil, false) if err != nil { - w.errs = append(w.errs, ast.NewError(ast.FormatErr, &ast.Location{}, err.Error())) + w.errs = append(w.errs, ast.NewError(ast.FormatErr, &ast.Location{}, "%s", err.Error())) } case *ast.Term: _, err := w.writeTerm(x, nil) if err != nil { - w.errs = append(w.errs, ast.NewError(ast.FormatErr, &ast.Location{}, err.Error())) + w.errs = append(w.errs, ast.NewError(ast.FormatErr, &ast.Location{}, "%s", err.Error())) } case ast.Value: _, err := w.writeTerm(&ast.Term{Value: x, Location: &ast.Location{}}, nil) if err != nil { - w.errs = append(w.errs, ast.NewError(ast.FormatErr, &ast.Location{}, err.Error())) + w.errs = append(w.errs, ast.NewError(ast.FormatErr, &ast.Location{}, "%s", err.Error())) } case *ast.Comment: err := w.writeComments([]*ast.Comment{x}) if err != nil { - w.errs = append(w.errs, ast.NewError(ast.FormatErr, &ast.Location{}, err.Error())) + w.errs = append(w.errs, ast.NewError(ast.FormatErr, &ast.Location{}, "%s", err.Error())) } default: return nil, fmt.Errorf("not an ast element: %v", x) @@ -339,6 +359,7 @@ func AstWithOpts(x any, opts Opts) ([]byte, error) { if len(w.errs) > 0 { return nil, w.errs } + return squashTrailingNewlines(w.buf.Bytes()), nil } @@ -418,7 +439,7 @@ func (w *writer) writeModule(module *ast.Module) error { sort.Slice(comments, func(i, j int) bool { l, err := locLess(comments[i], comments[j]) if err != nil { - w.errs = append(w.errs, ast.NewError(ast.FormatErr, &ast.Location{}, err.Error())) + w.errs = append(w.errs, ast.NewError(ast.FormatErr, &ast.Location{}, "%s", err.Error())) } return l }) @@ -426,7 +447,7 @@ func (w *writer) writeModule(module *ast.Module) error { sort.Slice(others, func(i, j int) bool { l, err := locLess(others[i], others[j]) if err != nil { - w.errs = append(w.errs, ast.NewError(ast.FormatErr, &ast.Location{}, err.Error())) + w.errs = append(w.errs, ast.NewError(ast.FormatErr, &ast.Location{}, "%s", err.Error())) } return l }) @@ -524,12 +545,12 @@ func (w *writer) writeRules(rules []*ast.Rule, comments []*ast.Comment) ([]*ast. var err error comments, err = w.insertComments(comments, rule.Location) if err != nil && !errors.As(err, &unexpectedCommentError{}) { - w.errs = append(w.errs, ast.NewError(ast.FormatErr, &ast.Location{}, err.Error())) + w.errs = append(w.errs, ast.NewError(ast.FormatErr, &ast.Location{}, "%s", err.Error())) } comments, err = w.writeRule(rule, false, comments) if err != nil && !errors.As(err, &unexpectedCommentError{}) { - w.errs = append(w.errs, ast.NewError(ast.FormatErr, &ast.Location{}, err.Error())) + w.errs = append(w.errs, ast.NewError(ast.FormatErr, &ast.Location{}, "%s", err.Error())) } if i < len(rules)-1 && w.groupableOneLiner(rule) { @@ -545,8 +566,6 @@ func (w *writer) writeRules(rules []*ast.Rule, comments []*ast.Comment) ([]*ast. return comments, nil } -var expandedConst = ast.NewBody(ast.NewExpr(ast.InternedTerm(true))) - func (w *writer) groupableOneLiner(rule *ast.Rule) bool { // Location required to determine if two rules are adjacent in the policy. // If not, we respect line breaks between rules. @@ -667,8 +686,6 @@ func (w *writer) writeRule(rule *ast.Rule, isElse bool, comments []*ast.Comment) return comments, nil } -var elseVar ast.Value = ast.Var("else") - func (w *writer) writeElse(rule *ast.Rule, comments []*ast.Comment) ([]*ast.Comment, error) { // If there was nothing else on the line before the "else" starts // then preserve this style of else block, otherwise it will be @@ -874,7 +891,7 @@ func (w *writer) writeBody(body ast.Body, comments []*ast.Comment) ([]*ast.Comme comments, err = w.writeExpr(expr, comments) if err != nil && !errors.As(err, &unexpectedCommentError{}) { - w.errs = append(w.errs, ast.NewError(ast.FormatErr, &ast.Location{}, err.Error())) + w.errs = append(w.errs, ast.NewError(ast.FormatErr, &ast.Location{}, "%s", err.Error())) } w.endLine() } @@ -1127,18 +1144,33 @@ func (w *writer) writeWith(with *ast.With, comments []*ast.Comment, indented boo return comments, nil } +// saveComments saves a copy of the comments slice in a pooled slice to and returns it. +// This is to avoid having to create a new slice every time we need to save comments. +// The caller is responsible for putting the slice back in the pool when done. +func saveComments(comments []*ast.Comment) *[]*ast.Comment { + cmlen := len(comments) + saved := commentsSlicePool.Get(cmlen) + + copy(*saved, comments) + + return saved +} + func (w *writer) writeTerm(term *ast.Term, comments []*ast.Comment) ([]*ast.Comment, error) { - currentComments := make([]*ast.Comment, len(comments)) - copy(currentComments, comments) + if len(comments) == 0 { + return w.writeTermParens(false, term, comments) + } currentLen := w.buf.Len() + currentComments := saveComments(comments) + defer commentsSlicePool.Put(currentComments) comments, err := w.writeTermParens(false, term, comments) if err != nil { if errors.As(err, &unexpectedCommentError{}) { w.buf.Truncate(currentLen) - comments, uErr := w.writeUnformatted(term.Location, currentComments) + comments, uErr := w.writeUnformatted(term.Location, *currentComments) if uErr != nil { return nil, uErr } @@ -1156,16 +1188,16 @@ func (w *writer) writeUnformatted(location *ast.Location, currentComments []*ast return nil, errors.New("original unformatted text is empty") } - rawRule := string(location.Text) - rowNum := len(strings.Split(rawRule, "\n")) + rowNum := bytes.Count(location.Text, []byte{'\n'}) + 1 - w.write(string(location.Text)) + w.writeBytes(location.Text) comments := make([]*ast.Comment, 0, len(currentComments)) for _, c := range currentComments { // if there is a body then wait to write the last comment if w.writeCommentOnFinalLine && c.Location.Row == location.Row+rowNum-1 { - w.write(" " + string(c.Location.Text)) + w.write(" ") + w.writeBytes(c.Location.Text) continue } @@ -1227,19 +1259,19 @@ func (w *writer) writeTermParens(parens bool, term *ast.Term, comments []*ast.Co case ast.String: if term.Location.Text[0] == '`' { // To preserve raw strings, we need to output the original text, - w.write(string(term.Location.Text)) + w.writeBytes(term.Location.Text) } else { // x.String() cannot be used by default because it can change the input string "\u0000" to "\x00" - var after, quote string + var after, quote []byte var found bool // term.Location.Text could contain the prefix `else :=`, remove it switch term.Location.Text[len(term.Location.Text)-1] { case '"': - quote = "\"" - _, after, found = strings.Cut(string(term.Location.Text), quote) + quote = []byte{'"'} + _, after, found = bytes.Cut(term.Location.Text, quote) case '`': - quote = "`" - _, after, found = strings.Cut(string(term.Location.Text), quote) + quote = []byte{'`'} + _, after, found = bytes.Cut(term.Location.Text, quote) } if !found { @@ -1247,7 +1279,8 @@ func (w *writer) writeTermParens(parens bool, term *ast.Term, comments []*ast.Co // e.g. partial_set.y to partial_set["y"] w.write(x.String()) } else { - w.write(quote + after) + w.writeBytes(quote) + w.writeBytes(after) } } @@ -1310,8 +1343,6 @@ func (w *writer) writeBracketed(str string) { w.write("[" + str + "]") } -var varRegexp = regexp.MustCompile("^[[:alpha:]_][[:alpha:][:digit:]_]*$") - func (w *writer) writeRefStringPath(s ast.String, l *ast.Location) { str := string(s) if w.shouldBracketRefTerm(str, l) { @@ -1563,7 +1594,7 @@ func (w *writer) writeComprehensionBody(openChar, closeChar byte, body ast.Body, defer w.startLine() defer func() { if err := w.down(); err != nil { - w.errs = append(w.errs, ast.NewError(ast.FormatErr, &ast.Location{}, err.Error())) + w.errs = append(w.errs, ast.NewError(ast.FormatErr, &ast.Location{}, "%s", err.Error())) } }() @@ -1627,7 +1658,7 @@ func (w *writer) writeImports(imports []*ast.Import, comments []*ast.Comment) ([ func (w *writer) writeImport(imp *ast.Import) error { path := imp.Path.Value.(ast.Ref) - buf := []string{"import"} + w.write("import ") if _, ok := future.WhichFutureKeyword(imp); ok { // We don't want to wrap future.keywords imports in parens, so we create a new writer that doesn't @@ -1638,15 +1669,17 @@ func (w *writer) writeImport(imp *ast.Import) error { if err != nil { return err } - buf = append(buf, w2.buf.String()) + w.write(w2.buf.String()) } else { - buf = append(buf, path.String()) + _, err := w.writeRef(path, nil) + if err != nil { + return err + } } if len(imp.Alias) > 0 { - buf = append(buf, "as "+imp.Alias.String()) + w.write(" as " + imp.Alias.String()) } - w.write(strings.Join(buf, " ")) return nil } @@ -1798,7 +1831,7 @@ func (w *writer) groupIterable(elements []any, last *ast.Location) ([][]any, err slices.SortFunc(elements, func(i, j any) int { l, err := locCmp(i, j) if err != nil { - w.errs = append(w.errs, ast.NewError(ast.FormatErr, &ast.Location{}, err.Error())) + w.errs = append(w.errs, ast.NewError(ast.FormatErr, &ast.Location{}, "%s", err.Error())) } return l }) @@ -2128,11 +2161,16 @@ func (w *writer) blankLine() { w.write("\n") } -// write the input string and writes it to the buffer. +// write writes string s to the buffer. func (w *writer) write(s string) { w.buf.WriteString(s) } +// writeBytes writes []byte b to the buffer. +func (w *writer) writeBytes(b []byte) { + w.buf.Write(b) +} + // writeLine writes the string on a newly started line, then terminate the line. func (w *writer) writeLine(s string) { if !w.inline { diff --git a/vendor/github.com/open-policy-agent/opa/v1/hooks/hooks.go b/vendor/github.com/open-policy-agent/opa/v1/hooks/hooks.go index caf69b12428..cb756e5020f 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/hooks/hooks.go +++ b/vendor/github.com/open-policy-agent/opa/v1/hooks/hooks.go @@ -9,6 +9,7 @@ import ( "fmt" "github.com/open-policy-agent/opa/v1/config" + topdown_cache "github.com/open-policy-agent/opa/v1/topdown/cache" ) // Hook is a hook to be called in some select places in OPA's operation. @@ -49,6 +50,10 @@ func (hs Hooks) Each(fn func(Hook)) { } } +func (hs Hooks) Len() int { + return len(hs.m) +} + // ConfigHook allows inspecting or rewriting the configuration when the plugin // manager is processing it. // Note that this hook is not run when the plugin manager is reconfigured. This @@ -64,10 +69,25 @@ type ConfigDiscoveryHook interface { OnConfigDiscovery(context.Context, *config.Config) (*config.Config, error) } +// InterQueryCacheHook allows access to the server's inter-query cache instance. +// It's useful for out-of-tree handlers that also need to evaluate something. +// Using this hook, they can share the caches with the rest of OPA. +type InterQueryCacheHook interface { + OnInterQueryCache(context.Context, topdown_cache.InterQueryCache) error +} + +// InterQueryValueCacheHook allows access to the server's inter-query value cache +// instance. +type InterQueryValueCacheHook interface { + OnInterQueryValueCache(context.Context, topdown_cache.InterQueryValueCache) error +} + func (hs Hooks) Validate() error { for h := range hs.m { switch h.(type) { - case ConfigHook, + case InterQueryCacheHook, + InterQueryValueCacheHook, + ConfigHook, ConfigDiscoveryHook: // OK default: return fmt.Errorf("unknown hook type %T", h) diff --git a/vendor/github.com/open-policy-agent/opa/v1/loader/loader.go b/vendor/github.com/open-policy-agent/opa/v1/loader/loader.go index 079bf043cd3..42a59d031f1 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/loader/loader.go +++ b/vendor/github.com/open-policy-agent/opa/v1/loader/loader.go @@ -21,6 +21,7 @@ import ( "github.com/open-policy-agent/opa/v1/ast" astJSON "github.com/open-policy-agent/opa/v1/ast/json" "github.com/open-policy-agent/opa/v1/bundle" + "github.com/open-policy-agent/opa/v1/loader/extension" "github.com/open-policy-agent/opa/v1/loader/filter" "github.com/open-policy-agent/opa/v1/metrics" "github.com/open-policy-agent/opa/v1/storage" @@ -98,6 +99,7 @@ type FileLoader interface { WithFilter(Filter) FileLoader WithBundleVerificationConfig(*bundle.VerificationConfig) FileLoader WithSkipBundleVerification(bool) FileLoader + WithBundleLazyLoadingMode(bool) FileLoader WithProcessAnnotation(bool) FileLoader WithCapabilities(*ast.Capabilities) FileLoader // Deprecated: Use SetOptions in the json package instead, where a longer description @@ -116,15 +118,16 @@ func NewFileLoader() FileLoader { } type fileLoader struct { - metrics metrics.Metrics - filter Filter - bvc *bundle.VerificationConfig - skipVerify bool - files map[string]bundle.FileInfo - opts ast.ParserOptions - fsys fs.FS - reader io.Reader - followSymlinks bool + metrics metrics.Metrics + filter Filter + bvc *bundle.VerificationConfig + skipVerify bool + bundleLazyLoading bool + files map[string]bundle.FileInfo + opts ast.ParserOptions + fsys fs.FS + reader io.Reader + followSymlinks bool } // WithFS provides an fs.FS to use for loading files. You can pass nil to @@ -167,6 +170,12 @@ func (fl *fileLoader) WithSkipBundleVerification(skipVerify bool) FileLoader { return fl } +// WithBundleLazyLoadingMode enables or disables bundle lazy loading mode +func (fl *fileLoader) WithBundleLazyLoadingMode(bundleLazyLoading bool) FileLoader { + fl.bundleLazyLoading = bundleLazyLoading + return fl +} + // WithProcessAnnotation enables or disables processing of schema annotations on rules func (fl *fileLoader) WithProcessAnnotation(processAnnotation bool) FileLoader { fl.opts.ProcessAnnotation = processAnnotation @@ -223,7 +232,7 @@ func (fl fileLoader) Filtered(paths []string, filter Filter) (*Result, error) { return err } - result, err := loadKnownTypes(path, bs, fl.metrics, fl.opts) + result, err := loadKnownTypes(path, bs, fl.metrics, fl.opts, fl.bundleLazyLoading) if err != nil { if !isUnrecognizedFile(err) { return err @@ -271,10 +280,13 @@ func (fl fileLoader) AsBundle(path string) (*bundle.Bundle, error) { WithMetrics(fl.metrics). WithBundleVerificationConfig(fl.bvc). WithSkipBundleVerification(fl.skipVerify). + WithLazyLoadingMode(fl.bundleLazyLoading). WithProcessAnnotations(fl.opts.ProcessAnnotation). WithCapabilities(fl.opts.Capabilities). WithFollowSymlinks(fl.followSymlinks). - WithRegoVersion(fl.opts.RegoVersion) + WithRegoVersion(fl.opts.RegoVersion). + WithLazyLoadingMode(fl.bundleLazyLoading). + WithBundleName(path) // For bundle directories add the full path in front of module file names // to simplify debugging. @@ -719,8 +731,22 @@ func allRec(fsys fs.FS, path string, filter Filter, errors *Errors, loaded *Resu } } -func loadKnownTypes(path string, bs []byte, m metrics.Metrics, opts ast.ParserOptions) (any, error) { - switch filepath.Ext(path) { +func loadKnownTypes(path string, bs []byte, m metrics.Metrics, opts ast.ParserOptions, bundleLazyLoadingMode bool) (any, error) { + ext := filepath.Ext(path) + if handler := extension.FindExtension(ext); handler != nil { + m.Timer(metrics.RegoDataParse).Start() + + var value any + err := handler(bs, &value) + + m.Timer(metrics.RegoDataParse).Stop() + if err != nil { + return nil, fmt.Errorf("bundle %s: %w", path, err) + } + + return value, nil + } + switch ext { case ".json": return loadJSON(path, bs, m) case ".rego": @@ -729,7 +755,7 @@ func loadKnownTypes(path string, bs []byte, m metrics.Metrics, opts ast.ParserOp return loadYAML(path, bs, m) default: if strings.HasSuffix(path, ".tar.gz") { - r, err := loadBundleFile(path, bs, m, opts) + r, err := loadBundleFile(path, bs, m, opts, bundleLazyLoadingMode) if err != nil { err = fmt.Errorf("bundle %s: %w", path, err) } @@ -755,7 +781,7 @@ func loadFileForAnyType(path string, bs []byte, m metrics.Metrics, opts ast.Pars return nil, unrecognizedFile(path) } -func loadBundleFile(path string, bs []byte, m metrics.Metrics, opts ast.ParserOptions) (bundle.Bundle, error) { +func loadBundleFile(path string, bs []byte, m metrics.Metrics, opts ast.ParserOptions, bundleLazyLoadingMode bool) (bundle.Bundle, error) { tl := bundle.NewTarballLoaderWithBaseURL(bytes.NewBuffer(bs), path) br := bundle.NewCustomReader(tl). WithRegoVersion(opts.RegoVersion). @@ -763,6 +789,7 @@ func loadBundleFile(path string, bs []byte, m metrics.Metrics, opts ast.ParserOp WithProcessAnnotations(opts.ProcessAnnotation). WithMetrics(m). WithSkipBundleVerification(true). + WithLazyLoadingMode(bundleLazyLoadingMode). IncludeManifestInData(true) return br.Read() } diff --git a/vendor/github.com/open-policy-agent/opa/v1/logging/logging.go b/vendor/github.com/open-policy-agent/opa/v1/logging/logging.go index 9e36a20bf8a..5ff27a21167 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/logging/logging.go +++ b/vendor/github.com/open-policy-agent/opa/v1/logging/logging.go @@ -261,3 +261,14 @@ func DecisionIDFromContext(ctx context.Context) (string, bool) { s, ok := ctx.Value(decisionCtxKey).(string) return s, ok } + +const batchDecisionCtxKey = requestContextKey("batch_decision_id") + +func WithBatchDecisionID(parent context.Context, id string) context.Context { + return context.WithValue(parent, batchDecisionCtxKey, id) +} + +func BatchDecisionIDFromContext(ctx context.Context) (string, bool) { + s, ok := ctx.Value(batchDecisionCtxKey).(string) + return s, ok +} diff --git a/vendor/github.com/open-policy-agent/opa/v1/metrics/metrics.go b/vendor/github.com/open-policy-agent/opa/v1/metrics/metrics.go index 316ffe78971..481f27337ed 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/metrics/metrics.go +++ b/vendor/github.com/open-policy-agent/opa/v1/metrics/metrics.go @@ -19,21 +19,27 @@ import ( // Well-known metric names. const ( - BundleRequest = "bundle_request" - ServerHandler = "server_handler" - ServerQueryCacheHit = "server_query_cache_hit" - SDKDecisionEval = "sdk_decision_eval" - RegoQueryCompile = "rego_query_compile" - RegoQueryEval = "rego_query_eval" - RegoQueryParse = "rego_query_parse" - RegoModuleParse = "rego_module_parse" - RegoDataParse = "rego_data_parse" - RegoModuleCompile = "rego_module_compile" - RegoPartialEval = "rego_partial_eval" - RegoInputParse = "rego_input_parse" - RegoLoadFiles = "rego_load_files" - RegoLoadBundles = "rego_load_bundles" - RegoExternalResolve = "rego_external_resolve" + BundleRequest = "bundle_request" + ServerHandler = "server_handler" + ServerQueryCacheHit = "server_query_cache_hit" + SDKDecisionEval = "sdk_decision_eval" + RegoQueryCompile = "rego_query_compile" + RegoQueryEval = "rego_query_eval" + RegoQueryParse = "rego_query_parse" + RegoModuleParse = "rego_module_parse" + RegoDataParse = "rego_data_parse" + RegoModuleCompile = "rego_module_compile" + RegoPartialEval = "rego_partial_eval" + RegoInputParse = "rego_input_parse" + RegoLoadFiles = "rego_load_files" + RegoLoadBundles = "rego_load_bundles" + RegoExternalResolve = "rego_external_resolve" + CompilePrepPartial = "compile_prep_partial" + CompileEvalConstraints = "compile_eval_constraints" + CompileTranslateQueries = "compile_translate_queries" + CompileExtractAnnotationsUnknowns = "compile_extract_annotations_unknowns" + CompileExtractAnnotationsMask = "compile_extract_annotations_mask" + CompileEvalMaskRule = "compile_eval_mask_rule" ) // Info contains attributes describing the underlying metrics provider. diff --git a/vendor/github.com/open-policy-agent/opa/v1/plugins/plugins.go b/vendor/github.com/open-policy-agent/opa/v1/plugins/plugins.go index dc2afccdade..ca8df1ee48b 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/plugins/plugins.go +++ b/vendor/github.com/open-policy-agent/opa/v1/plugins/plugins.go @@ -177,7 +177,8 @@ type StatusListener func(status map[string]*Status) // Manager implements lifecycle management of plugins and gives plugins access // to engine-wide components like storage. type Manager struct { - Store storage.Store + Store storage.Store + // Config values should be accessed from the thread-safe GetConfig method. Config *config.Config Info *ast.Term ID string @@ -215,17 +216,25 @@ type Manager struct { bootstrapConfigLabels map[string]string hooks hooks.Hooks enableTelemetry bool - reporter *report.Reporter + reporter report.Reporter opaReportNotifyCh chan struct{} stop chan chan struct{} parserOptions ast.ParserOptions + extraRoutes map[string]ExtraRoute + extraMiddlewares []func(http.Handler) http.Handler + extraAuthorizerRoutes []func(string, []any) bool + bundleActivatorPlugin string } -type managerContextKey string -type managerWasmResolverKey string +type ( + managerContextKey string + managerWasmResolverKey string +) -const managerCompilerContextKey = managerContextKey("compiler") -const managerWasmResolverContextKey = managerWasmResolverKey("wasmResolvers") +const ( + managerCompilerContextKey = managerContextKey("compiler") + managerWasmResolverContextKey = managerWasmResolverKey("wasmResolvers") +) // SetCompilerOnContext puts the compiler into the storage context. Calling this // function before committing updated policies to storage allows the manager to @@ -272,7 +281,6 @@ func validateTriggerMode(mode TriggerMode) error { // ValidateAndInjectDefaultsForTriggerMode validates the trigger mode and injects default values func ValidateAndInjectDefaultsForTriggerMode(a, b *TriggerMode) (*TriggerMode, error) { - if a == nil && b != nil { err := validateTriggerMode(*b) if err != nil { @@ -425,9 +433,15 @@ func WithTelemetryGatherers(gs map[string]report.Gatherer) func(*Manager) { } } +// WithBundleActivatorPlugin sets the name of the activator plugin to load bundles into the store +func WithBundleActivatorPlugin(bundleActivatorPlugin string) func(*Manager) { + return func(m *Manager) { + m.bundleActivatorPlugin = bundleActivatorPlugin + } +} + // New creates a new Manager using config. func New(raw []byte, id string, store storage.Store, opts ...func(*Manager)) (*Manager, error) { - parsedConfig, err := config.ParseConfig(raw, id) if err != nil { return nil, err @@ -442,6 +456,7 @@ func New(raw []byte, id string, store storage.Store, opts ...func(*Manager)) (*M maxErrors: -1, serverInitialized: make(chan struct{}), bootstrapConfigLabels: parsedConfig.Labels, + extraRoutes: map[string]ExtraRoute{}, } for _, f := range opts { @@ -493,7 +508,7 @@ func New(raw []byte, id string, store storage.Store, opts ...func(*Manager)) (*M } if m.enableTelemetry { - reporter, err := report.New(id, report.Options{Logger: m.logger}) + reporter, err := report.New(report.Options{Logger: m.logger}) if err != nil { return nil, err } @@ -519,7 +534,6 @@ func New(raw []byte, id string, store storage.Store, opts ...func(*Manager)) (*M // Init returns an error if the manager could not initialize itself. Init() should // be called before Start(). Init() is idempotent. func (m *Manager) Init(ctx context.Context) error { - if m.initialized { return nil } @@ -536,7 +550,6 @@ func (m *Manager) Init(ctx context.Context) error { } err := storage.Txn(ctx, m.Store, params, func(txn storage.Transaction) error { - result, err := initload.InsertAndCompile(ctx, initload.InsertAndCompileOptions{ Store: m.Store, Txn: txn, @@ -545,8 +558,8 @@ func (m *Manager) Init(ctx context.Context) error { MaxErrors: m.maxErrors, EnablePrintStatements: m.enablePrintStatements, ParserOptions: m.parserOptions, + BundleActivatorPlugin: m.bundleActivatorPlugin, }) - if err != nil { return err } @@ -562,7 +575,6 @@ func (m *Manager) Init(ctx context.Context) error { _, err = m.Store.Register(ctx, txn, storage.TriggerConfig{OnCommit: m.onCommit}) return err }) - if err != nil { if m.stop != nil { done := make(chan struct{}) @@ -581,14 +593,24 @@ func (m *Manager) Init(ctx context.Context) error { func (m *Manager) Labels() map[string]string { m.mtx.Lock() defer m.mtx.Unlock() - return m.Config.Labels + + return maps.Clone(m.Config.Labels) } // InterQueryBuiltinCacheConfig returns the configuration for the inter-query caches. func (m *Manager) InterQueryBuiltinCacheConfig() *cache.Config { m.mtx.Lock() defer m.mtx.Unlock() - return m.interQueryBuiltinCacheConfig + + return m.interQueryBuiltinCacheConfig.Clone() +} + +// GetConfig returns a deep copy of the manager's configuration. +func (m *Manager) GetConfig() *config.Config { + m.mtx.Lock() + defer m.mtx.Unlock() + + return m.Config.Clone() } // Register adds a plugin to the manager. When the manager is started, all of @@ -653,6 +675,59 @@ func (m *Manager) setCompiler(compiler *ast.Compiler) { m.compiler = compiler } +type ExtraRoute struct { + PromName string // name is for prometheus metrics + HandlerFunc http.HandlerFunc +} + +func (m *Manager) ExtraRoutes() map[string]ExtraRoute { + return m.extraRoutes +} + +func (m *Manager) ExtraMiddlewares() []func(http.Handler) http.Handler { + return m.extraMiddlewares +} + +func (m *Manager) ExtraAuthorizerRoutes() []func(string, []any) bool { + return m.extraAuthorizerRoutes +} + +// ExtraRoute registers an extra route to be served by the HTTP +// server later. Using this instead of directly registering routes +// with GetRouter() lets the server apply its handler wrapping for +// Prometheus and OpenTelemetry. +// Caution: This cannot be used to dynamically register and un- +// register HTTP handlers. It's meant as a late-stage set up helper, +// to be called from a plugin's init methods. +func (m *Manager) ExtraRoute(path, name string, hf http.HandlerFunc) { + if _, ok := m.extraRoutes[path]; ok { + panic("extra route already registered: " + path) + } + m.extraRoutes[path] = ExtraRoute{ + PromName: name, + HandlerFunc: hf, + } +} + +// ExtraMiddleware registers extra middlewares (`func(http.Handler) http.Handler`) +// to be injected into the HTTP handler chain in the server later. +// Caution: This cannot be used to dynamically register and un- +// register middlewares. It's meant as a late-stage set up helper, +// to be called from a plugin's init methods. +func (m *Manager) ExtraMiddleware(mw ...func(http.Handler) http.Handler) { + m.extraMiddlewares = append(m.extraMiddlewares, mw...) +} + +// ExtraAuthorizerRoute registers an extra URL path validator function for use +// in the server authorizer. These functions designate specific methods and URL +// prefixes or paths where the authorizer should allow request body parsing. +// Caution: This cannot be used to dynamically register and un- +// register path validator functions. It's meant as a late-stage +// set up helper, to be called from a plugin's init methods. +func (m *Manager) ExtraAuthorizerRoute(validatorFunc func(string, []any) bool) { + m.extraAuthorizerRoutes = append(m.extraAuthorizerRoutes, validatorFunc) +} + // GetRouter returns the managers router if set func (m *Manager) GetRouter() *http.ServeMux { m.mtx.Lock() @@ -683,7 +758,6 @@ func (m *Manager) setWasmResolvers(rs []*wasm.Resolver) { // Start starts the manager. Init() should be called once before Start(). func (m *Manager) Start(ctx context.Context) error { - if m == nil { return nil } @@ -765,7 +839,9 @@ func (m *Manager) DefaultServiceOpts(config *config.Config) cfg.ServiceOptions { } // Reconfigure updates the configuration on the manager. -func (m *Manager) Reconfigure(config *config.Config) error { +func (m *Manager) Reconfigure(newCfg *config.Config) error { + config := newCfg.Clone() + opts := m.DefaultServiceOpts(config) keys, err := keys.ParseKeysConfig(config.Keys) @@ -796,6 +872,7 @@ func (m *Manager) Reconfigure(config *config.Config) error { // don't erase persistence directory if config.PersistenceDirectory == nil { + // update is ok since we have the lock config.PersistenceDirectory = m.Config.PersistenceDirectory } @@ -846,7 +923,6 @@ func (m *Manager) UnregisterPluginStatusListener(name string) { // listeners will be called with a copy of the new state of all // plugins. func (m *Manager) UpdatePluginStatus(pluginName string, status *Status) { - var toNotify map[string]StatusListener var statuses map[string]*Status @@ -880,7 +956,6 @@ func (m *Manager) copyPluginStatus() map[string]*Status { } func (m *Manager) onCommit(ctx context.Context, txn storage.Transaction, event storage.TriggerEvent) { - compiler := GetCompilerOnContext(event.Context) // If the context does not contain the compiler fallback to loading the @@ -908,7 +983,6 @@ func (m *Manager) onCommit(ctx context.Context, txn storage.Transaction, event s resolvers := getWasmResolversOnContext(event.Context) if resolvers != nil { m.setWasmResolvers(resolvers) - } else if event.DataChanged() { if requiresWasmResolverReload(event) { resolvers, err := bundleUtils.LoadWasmResolversFromStore(ctx, m.Store, txn, nil) @@ -991,7 +1065,19 @@ func (m *Manager) updateWasmResolversData(ctx context.Context, event storage.Tri func (m *Manager) PublicKeys() map[string]*keys.Config { m.mtx.Lock() defer m.mtx.Unlock() - return m.keys + + if m.keys == nil { + return make(map[string]*keys.Config) + } + + result := make(map[string]*keys.Config, len(m.keys)) + for k, v := range m.keys { + if v != nil { + copied := *v + result[k] = &copied + } + } + return result } // Client returns a client for communicating with a remote service. diff --git a/vendor/github.com/open-policy-agent/opa/v1/plugins/rest/auth.go b/vendor/github.com/open-policy-agent/opa/v1/plugins/rest/auth.go index 9a8d58cc660..8ec337bd1e9 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/plugins/rest/auth.go +++ b/vendor/github.com/open-policy-agent/opa/v1/plugins/rest/auth.go @@ -29,9 +29,8 @@ import ( "strings" "time" - "github.com/open-policy-agent/opa/internal/jwx/jwa" - "github.com/open-policy-agent/opa/internal/jwx/jws" - "github.com/open-policy-agent/opa/internal/jwx/jws/sign" + "github.com/lestrrat-go/jwx/v3/jwa" + "github.com/lestrrat-go/jwx/v3/jws" "github.com/open-policy-agent/opa/internal/providers/aws" "github.com/open-policy-agent/opa/internal/uuid" "github.com/open-policy-agent/opa/v1/keys" @@ -391,11 +390,28 @@ func (ap *oauth2ClientCredentialsAuthPlugin) createAuthJWT(ctx context.Context, case ap.AzureKeyVault != nil: clientAssertion, err = ap.SignWithKeyVault(ctx, payload, header) default: - clientAssertion, err = jws.SignLiteral(payload, - jwa.SignatureAlgorithm(alg), - signingKey, - header, - rand.Reader) + // Parse the algorithm string to jwa.SignatureAlgorithm + algObj, ok := jwa.LookupSignatureAlgorithm(alg) + if !ok { + return nil, fmt.Errorf("unknown signature algorithm: %s", alg) + } + + // Parse headers + var headers map[string]any + if err := json.Unmarshal(header, &headers); err != nil { + return nil, err + } + + // Create protected headers + protectedHeaders := jws.NewHeaders() + for k, v := range headers { + if err := protectedHeaders.Set(k, v); err != nil { + return nil, err + } + } + + clientAssertion, err = jws.Sign(payload, + jws.WithKey(algObj, signingKey, jws.WithProtectedHeaders(protectedHeaders))) } if err != nil { return nil, err @@ -485,8 +501,37 @@ func (ap *oauth2ClientCredentialsAuthPlugin) parseSigningKey(c Config) (err erro return errors.New("signing_key refers to non-existent key") } - alg := jwa.SignatureAlgorithm(ap.signingKey.Algorithm) - ap.signingKeyParsed, err = sign.GetSigningKey(ap.signingKey.PrivateKey, alg) + alg, ok := jwa.LookupSignatureAlgorithm(ap.signingKey.Algorithm) + if !ok { + return fmt.Errorf("unknown signature algorithm: %s", ap.signingKey.Algorithm) + } + + // Parse the private key directly + keyData := ap.signingKey.PrivateKey + + // For HMAC algorithms, return the key as bytes + if alg == jwa.HS256() || alg == jwa.HS384() || alg == jwa.HS512() { + ap.signingKeyParsed = []byte(keyData) + return nil + } + + // For RSA/ECDSA algorithms, parse the PEM-encoded key + block, _ := pem.Decode([]byte(keyData)) + if block == nil { + return errors.New("failed to decode PEM key") + } + + switch block.Type { + case "RSA PRIVATE KEY": + ap.signingKeyParsed, err = x509.ParsePKCS1PrivateKey(block.Bytes) + case "PRIVATE KEY": + ap.signingKeyParsed, err = x509.ParsePKCS8PrivateKey(block.Bytes) + case "EC PRIVATE KEY": + ap.signingKeyParsed, err = x509.ParseECPrivateKey(block.Bytes) + default: + return fmt.Errorf("unsupported key type: %s", block.Type) + } + if err != nil { return err } diff --git a/vendor/github.com/open-policy-agent/opa/v1/rego/rego.go b/vendor/github.com/open-policy-agent/opa/v1/rego/rego.go index 0f5365b9b0e..2c4d8a8d916 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/rego/rego.go +++ b/vendor/github.com/open-policy-agent/opa/v1/rego/rego.go @@ -126,6 +126,8 @@ type EvalContext struct { strictBuiltinErrors bool virtualCache topdown.VirtualCache baseCache topdown.BaseCache + tracing tracing.Options + externalCancel topdown.Cancel // Note(philip): If non-nil, the cancellation is handled outside of this package. } func (e *EvalContext) RawInput() *any { @@ -180,6 +182,18 @@ func (e *EvalContext) Transaction() storage.Transaction { return e.txn } +func (e *EvalContext) TracingOpts() tracing.Options { + return e.tracing +} + +func (e *EvalContext) ExternalCancel() topdown.Cancel { + return e.externalCancel +} + +func (e *EvalContext) QueryTracers() []topdown.QueryTracer { + return e.queryTracers +} + // EvalOption defines a function to set an option on an EvalConfig type EvalOption func(*EvalContext) @@ -388,6 +402,14 @@ func EvalNondeterministicBuiltins(yes bool) EvalOption { } } +// EvalExternalCancel sets an external topdown.Cancel for the interpreter to use +// for cancellation. This is useful for batch-evaluation of many rego queries. +func EvalExternalCancel(ec topdown.Cancel) EvalOption { + return func(e *EvalContext) { + e.externalCancel = ec + } +} + func (pq preparedQuery) Modules() map[string]*ast.Module { mods := make(map[string]*ast.Module) @@ -427,6 +449,7 @@ func (pq preparedQuery) newEvalContext(ctx context.Context, options []EvalOption printHook: pq.r.printHook, capabilities: pq.r.capabilities, strictBuiltinErrors: pq.r.strictBuiltinErrors, + tracing: pq.r.distributedTracingOpts, } for _, o := range options { @@ -625,6 +648,8 @@ type Rego struct { bundlePaths []string bundles map[string]*bundle.Bundle skipBundleVerification bool + bundleActivationPlugin string + enableBundleLazyLoadingMode bool interQueryBuiltinCache cache.InterQueryCache interQueryBuiltinValueCache cache.InterQueryValueCache ndBuiltinCache builtins.NDBCache @@ -643,6 +668,8 @@ type Rego struct { plugins []TargetPlugin targetPrepState TargetPluginEval regoVersion ast.RegoVersion + compilerHook func(*ast.Compiler) + evalMode *ast.CompilerEvalMode } func (r *Rego) RegoVersion() ast.RegoVersion { @@ -813,7 +840,6 @@ type memo struct { type memokey string func memoize(decl *Function, bctx BuiltinContext, terms []*ast.Term, ifEmpty func() (*ast.Term, error)) (*ast.Term, error) { - if !decl.Memoize { return ifEmpty() } @@ -1167,6 +1193,23 @@ func SkipBundleVerification(yes bool) func(r *Rego) { } } +// BundleActivatorPlugin sets the name of the activator plugin used to load bundles into the store. +func BundleActivatorPlugin(name string) func(r *Rego) { + return func(r *Rego) { + r.bundleActivationPlugin = name + } +} + +// BundleLazyLoadingMode sets the bundle loading mode. If true, bundles will be +// read in lazy mode. In this mode, data files in the bundle will not be +// deserialized and the check to validate that the bundle data does not contain +// paths outside the bundle's roots will not be performed while reading the bundle. +func BundleLazyLoadingMode(yes bool) func(r *Rego) { + return func(r *Rego) { + r.enableBundleLazyLoadingMode = yes + } +} + // InterQueryBuiltinCache sets the inter-query cache that built-in functions can utilize // during evaluation. func InterQueryBuiltinCache(c cache.InterQueryCache) func(r *Rego) { @@ -1278,9 +1321,23 @@ func SetRegoVersion(version ast.RegoVersion) func(r *Rego) { } } +// CompilerHook sets a hook function that will be called after the compiler is initialized. +// This is only called if the compiler has not been provided already. +func CompilerHook(hook func(*ast.Compiler)) func(r *Rego) { + return func(r *Rego) { + r.compilerHook = hook + } +} + +// EvalMode lets you override the evaluation mode. +func EvalMode(mode ast.CompilerEvalMode) func(r *Rego) { + return func(r *Rego) { + r.evalMode = &mode + } +} + // New returns a new Rego object. func New(options ...func(r *Rego)) *Rego { - r := &Rego{ parsedModules: map[string]*ast.Module{}, capture: map[*ast.Expr]ast.Var{}, @@ -1294,6 +1351,8 @@ func New(options ...func(r *Rego)) *Rego { option(r) } + callHook := r.compiler == nil // call hook only if we created the compiler here + if r.compiler == nil { r.compiler = ast.NewCompiler(). WithUnsafeBuiltins(r.unsafeBuiltins). @@ -1317,7 +1376,11 @@ func New(options ...func(r *Rego)) *Rego { } if r.store == nil { - r.store = inmem.NewWithOpts(inmem.OptReturnASTValuesOnRead(r.ownStoreReadAst)) + if bundle.HasExtension() { + r.store = bundle.BundleExtStore() + } else { + r.store = inmem.NewWithOpts(inmem.OptReturnASTValuesOnRead(r.ownStoreReadAst)) + } r.ownStore = true } else { r.ownStore = false @@ -1346,8 +1409,8 @@ func New(options ...func(r *Rego)) *Rego { } if r.pluginMgr != nil { - for _, name := range r.pluginMgr.Plugins() { - p := r.pluginMgr.Plugin(name) + for _, pluginName := range r.pluginMgr.Plugins() { + p := r.pluginMgr.Plugin(pluginName) if p0, ok := p.(TargetPlugin); ok { r.plugins = append(r.plugins, p0) } @@ -1358,6 +1421,14 @@ func New(options ...func(r *Rego)) *Rego { r.compiler = r.compiler.WithEvalMode(ast.EvalModeIR) } + if r.evalMode != nil { + r.compiler = r.compiler.WithEvalMode(*r.evalMode) + } + + if r.compilerHook != nil && callHook { + r.compilerHook(r.compiler) + } + return r } @@ -1501,7 +1572,6 @@ func CompilePartial(yes bool) CompileOption { // Compile returns a compiled policy query. func (r *Rego) Compile(ctx context.Context, opts ...CompileOption) (*CompileResult, error) { - var cfg CompileContext for _, opt := range opts { @@ -1728,7 +1798,7 @@ func (r *Rego) PrepareForEval(ctx context.Context, opts ...PrepareOption) (Prepa } // nolint: staticcheck // SA4006 false positive - data, err := r.store.Read(ctx, r.txn, storage.Path{}) + data, err := r.store.Read(ctx, r.txn, storage.RootPath) if err != nil { _ = txnClose(ctx, err) // Ignore error return PreparedEvalQuery{}, err @@ -1876,6 +1946,11 @@ func (r *Rego) parseModules(ctx context.Context, txn storage.Transaction, m metr defer m.Timer(metrics.RegoModuleParse).Stop() var errs Errors + popts := ast.ParserOptions{ + RegoVersion: r.regoVersion, + Capabilities: r.capabilities, + } + // Parse any modules that are saved to the store, but only if // another compile step is going to occur (ie. we have parsed modules // that need to be compiled). @@ -1891,7 +1966,7 @@ func (r *Rego) parseModules(ctx context.Context, txn storage.Transaction, m metr return err } - parsed, err := ast.ParseModuleWithOpts(id, string(bs), ast.ParserOptions{RegoVersion: r.regoVersion}) + parsed, err := ast.ParseModuleWithOpts(id, string(bs), popts) if err != nil { errs = append(errs, err) } @@ -1901,7 +1976,7 @@ func (r *Rego) parseModules(ctx context.Context, txn storage.Transaction, m metr // Parse any passed in as arguments to the Rego object for _, module := range r.modules { - p, err := module.ParseWithOpts(ast.ParserOptions{RegoVersion: r.regoVersion}) + p, err := module.ParseWithOpts(popts) if err != nil { switch errorWithType := err.(type) { case ast.Errors: @@ -1933,6 +2008,7 @@ func (r *Rego) loadFiles(ctx context.Context, txn storage.Transaction, m metrics result, err := loader.NewFileLoader(). WithMetrics(m). WithProcessAnnotation(true). + WithBundleLazyLoadingMode(bundle.HasExtension()). WithRegoVersion(r.regoVersion). WithCapabilities(r.capabilities). Filtered(r.loadPaths.paths, r.loadPaths.filter) @@ -1944,7 +2020,7 @@ func (r *Rego) loadFiles(ctx context.Context, txn storage.Transaction, m metrics } if len(result.Documents) > 0 { - err = r.store.Write(ctx, txn, storage.AddOp, storage.Path{}, result.Documents) + err = r.store.Write(ctx, txn, storage.AddOp, storage.RootPath, result.Documents) if err != nil { return err } @@ -1964,6 +2040,7 @@ func (r *Rego) loadBundles(_ context.Context, _ storage.Transaction, m metrics.M bndl, err := loader.NewFileLoader(). WithMetrics(m). WithProcessAnnotation(true). + WithBundleLazyLoadingMode(bundle.HasExtension()). WithSkipBundleVerification(r.skipBundleVerification). WithRegoVersion(r.regoVersion). WithCapabilities(r.capabilities). @@ -2022,6 +2099,8 @@ func (r *Rego) parseQuery(queryImports []*ast.Import, m metrics.Metrics) (ast.Bo return nil, err } popts.SkipRules = true + popts.Capabilities = r.capabilities + return ast.ParseBodyWithOpts(r.query, popts) } @@ -2037,7 +2116,6 @@ func parserOptionsFromRegoVersionImport(imports []*ast.Import, popts ast.ParserO } func (r *Rego) compileModules(ctx context.Context, txn storage.Transaction, m metrics.Metrics) error { - // Only compile again if there are new modules. if len(r.bundles) > 0 || len(r.parsedModules) > 0 { @@ -2148,7 +2226,6 @@ func (r *Rego) compileQuery(query ast.Body, imports []*ast.Import, _ metrics.Met compiled, err := qc.Compile(query) return qc, compiled, err - } func (r *Rego) eval(ctx context.Context, ectx *EvalContext) (ResultSet, error) { @@ -2214,13 +2291,19 @@ func (r *Rego) eval(ctx context.Context, ectx *EvalContext) (ResultSet, error) { } // Cancel query if context is cancelled or deadline is reached. - c := topdown.NewCancel() - q = q.WithCancel(c) - exit := make(chan struct{}) - defer close(exit) - go waitForDone(ctx, exit, func() { - c.Cancel() - }) + if ectx.externalCancel == nil { + // Create a one-off goroutine to handle cancellation for this query. + c := topdown.NewCancel() + q = q.WithCancel(c) + exit := make(chan struct{}) + defer close(exit) + go waitForDone(ctx, exit, func() { + c.Cancel() + }) + } else { + // Query cancellation is being handled elsewhere. + q = q.WithCancel(ectx.externalCancel) + } var rs ResultSet err := q.Iter(ctx, func(qr topdown.QueryResult) error { @@ -2231,7 +2314,6 @@ func (r *Rego) eval(ctx context.Context, ectx *EvalContext) (ResultSet, error) { rs = append(rs, result) return nil }) - if err != nil { return nil, err } @@ -2304,7 +2386,6 @@ func (r *Rego) valueToQueryResult(res ast.Value, ectx *EvalContext) (ResultSet, } func (r *Rego) generateResult(qr topdown.QueryResult, ectx *EvalContext) (Result, error) { - rewritten := ectx.compiledQuery.compiler.RewrittenVars() result := newResult() @@ -2344,7 +2425,6 @@ func (r *Rego) generateResult(qr topdown.QueryResult, ectx *EvalContext) (Result } func (r *Rego) partialResult(ctx context.Context, pCfg *PrepareConfig) (PartialResult, error) { - err := r.prepare(ctx, partialResultQueryType, []extraStage{ { after: "ResolveRefs", @@ -2438,7 +2518,6 @@ func (r *Rego) partialResult(ctx context.Context, pCfg *PrepareConfig) (PartialR } func (r *Rego) partial(ctx context.Context, ectx *EvalContext) (*PartialQueries, error) { - var unknowns []*ast.Term switch { @@ -2502,13 +2581,19 @@ func (r *Rego) partial(ctx context.Context, ectx *EvalContext) (*PartialQueries, } // Cancel query if context is cancelled or deadline is reached. - c := topdown.NewCancel() - q = q.WithCancel(c) - exit := make(chan struct{}) - defer close(exit) - go waitForDone(ctx, exit, func() { - c.Cancel() - }) + if ectx.externalCancel == nil { + // Create a one-off goroutine to handle cancellation for this query. + c := topdown.NewCancel() + q = q.WithCancel(c) + exit := make(chan struct{}) + defer close(exit) + go waitForDone(ctx, exit, func() { + c.Cancel() + }) + } else { + // Query cancellation is being handled elsewhere. + q = q.WithCancel(ectx.externalCancel) + } queries, support, err := q.PartialRun(ctx) if err != nil { @@ -2570,7 +2655,6 @@ func (r *Rego) partial(ctx context.Context, ectx *EvalContext) (*PartialQueries, } func (r *Rego) rewriteQueryToCaptureValue(_ ast.QueryCompiler, query ast.Body) (ast.Body, error) { - checkCapture := iteration(query) || len(query) > 1 for _, expr := range query { @@ -2685,7 +2769,6 @@ type transactionCloser func(ctx context.Context, err error) error // the configured Rego object. The returned function should be used to close the txn // regardless of status. func (r *Rego) getTxn(ctx context.Context) (storage.Transaction, transactionCloser, error) { - noopCloser := func(_ context.Context, _ error) error { return nil // no-op default } @@ -2795,7 +2878,6 @@ type refResolver struct { } func iteration(x any) bool { - var stopped bool vis := ast.NewGenericVisitor(func(x any) bool { diff --git a/vendor/github.com/open-policy-agent/opa/v1/storage/inmem/ast.go b/vendor/github.com/open-policy-agent/opa/v1/storage/inmem/ast.go index 941cbeef51d..40f18ab0dea 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/storage/inmem/ast.go +++ b/vendor/github.com/open-policy-agent/opa/v1/storage/inmem/ast.go @@ -73,10 +73,9 @@ func (u *updateAST) Apply(v any) any { } func newUpdateAST(data any, op storage.PatchOp, path storage.Path, idx int, value ast.Value) (*updateAST, error) { - switch data.(type) { case ast.Null, ast.Boolean, ast.Number, ast.String: - return nil, errors.NewNotFoundError(path) + return nil, errors.NotFoundErr } switch data := data.(type) { @@ -94,11 +93,10 @@ func newUpdateAST(data any, op storage.PatchOp, path storage.Path, idx int, valu } func newUpdateArrayAST(data *ast.Array, op storage.PatchOp, path storage.Path, idx int, value ast.Value) (*updateAST, error) { - if idx == len(path)-1 { if path[idx] == "-" || path[idx] == strconv.Itoa(data.Len()) { if op != storage.AddOp { - return nil, invalidPatchError("%v: invalid patch path", path) + return nil, errors.NewInvalidPatchError("%v: invalid patch path", path) } cpy := data.Append(ast.NewTerm(value)) @@ -161,7 +159,7 @@ func newUpdateObjectAST(data ast.Object, op storage.PatchOp, path storage.Path, switch op { case storage.ReplaceOp, storage.RemoveOp: if val == nil { - return nil, errors.NewNotFoundError(path) + return nil, errors.NotFoundErr } } return &updateAST{path, op == storage.RemoveOp, value}, nil @@ -171,14 +169,7 @@ func newUpdateObjectAST(data ast.Object, op storage.PatchOp, path storage.Path, return newUpdateAST(val.Value, op, path, idx+1, value) } - return nil, errors.NewNotFoundError(path) -} - -func interfaceToValue(v any) (ast.Value, error) { - if v, ok := v.(ast.Value); ok { - return v, nil - } - return ast.InterfaceToValue(v) + return nil, errors.NotFoundErr } // setInAst updates the value in the AST at the given path with the given value. diff --git a/vendor/github.com/open-policy-agent/opa/v1/storage/inmem/inmem.go b/vendor/github.com/open-policy-agent/opa/v1/storage/inmem/inmem.go index 742d6c167f4..cdc43424dd5 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/storage/inmem/inmem.go +++ b/vendor/github.com/open-policy-agent/opa/v1/storage/inmem/inmem.go @@ -27,6 +27,7 @@ import ( "github.com/open-policy-agent/opa/internal/merge" "github.com/open-policy-agent/opa/v1/ast" "github.com/open-policy-agent/opa/v1/storage" + "github.com/open-policy-agent/opa/v1/storage/internal/errors" "github.com/open-policy-agent/opa/v1/util" ) @@ -50,6 +51,7 @@ func NewWithOpts(opts ...Opt) storage.Store { if s.returnASTValuesOnRead { s.data = ast.NewObject() + s.roundTripOnWrite = false } else { s.data = map[string]any{} } @@ -71,7 +73,7 @@ func NewFromObjectWithOpts(data map[string]any, opts ...Opt) storage.Store { if err != nil { panic(err) } - if err := db.Write(ctx, txn, storage.AddOp, storage.Path{}, data); err != nil { + if err := db.Write(ctx, txn, storage.AddOp, storage.RootPath, data); err != nil { panic(err) } if err := db.Commit(ctx, txn); err != nil { @@ -89,9 +91,8 @@ func NewFromReader(r io.Reader) storage.Store { // NewFromReader returns a new in-memory store from a reader that produces a // JSON serialized object, with extra options. This function is for test purposes. func NewFromReaderWithOpts(r io.Reader, opts ...Opt) storage.Store { - d := util.NewJSONDecoder(r) var data map[string]any - if err := d.Decode(&data); err != nil { + if err := util.NewJSONDecoder(r).Decode(&data); err != nil { panic(err) } return NewFromObjectWithOpts(data, opts...) @@ -120,35 +121,39 @@ type handle struct { } func (db *store) NewTransaction(_ context.Context, params ...storage.TransactionParams) (storage.Transaction, error) { - var write bool - var ctx *storage.Context + txn := &transaction{ + xid: atomic.AddUint64(&db.xid, uint64(1)), + db: db, + } + if len(params) > 0 { - write = params[0].Write - ctx = params[0].Context + txn.write = params[0].Write + txn.context = params[0].Context } - xid := atomic.AddUint64(&db.xid, uint64(1)) - if write { + + if txn.write { db.wmu.Lock() } else { db.rmu.RLock() } - return newTransaction(xid, write, ctx, db), nil + + return txn, nil } // Truncate implements the storage.Store interface. This method must be called within a transaction. func (db *store) Truncate(ctx context.Context, txn storage.Transaction, params storage.TransactionParams, it storage.Iterator) error { var update *storage.Update var err error - mergedData := map[string]any{} underlying, err := db.underlying(txn) if err != nil { return err } + mergedData := map[string]any{} + for { - update, err = it.Next() - if err != nil { + if update, err = it.Next(); err != nil { break } @@ -159,8 +164,7 @@ func (db *store) Truncate(ctx context.Context, txn storage.Transaction, params s } } else { var value any - err = util.Unmarshal(update.Value, &value) - if err != nil { + if err = util.Unmarshal(update.Value, &value); err != nil { return err } @@ -193,11 +197,7 @@ func (db *store) Truncate(ctx context.Context, txn storage.Transaction, params s // For backwards compatibility, check if `RootOverwrite` was configured. if params.RootOverwrite { - newPath, ok := storage.ParsePathEscaped("/") - if !ok { - return fmt.Errorf("storage path invalid: %v", newPath) - } - return underlying.Write(storage.AddOp, newPath, mergedData) + return underlying.Write(storage.AddOp, storage.RootPath, mergedData) } for _, root := range params.BasePaths { @@ -310,12 +310,7 @@ func (db *store) Read(_ context.Context, txn storage.Transaction, path storage.P return nil, err } - v, err := underlying.Read(path) - if err != nil { - return nil, err - } - - return v, nil + return underlying.Read(path) } func (db *store) Write(_ context.Context, txn storage.Transaction, op storage.PatchOp, path storage.Path, value any) error { @@ -323,12 +318,19 @@ func (db *store) Write(_ context.Context, txn storage.Transaction, op storage.Pa if err != nil { return err } + + if db.returnASTValuesOnRead || !util.NeedsRoundTrip(value) { + // Fast path when value is nil, bool, string or json.Number. + return underlying.Write(op, path, value) + } + val := util.Reference(value) if db.roundTripOnWrite { if err := util.RoundTrip(val); err != nil { return err } } + return underlying.Write(op, path, *val) } @@ -409,22 +411,12 @@ func (db *store) underlying(txn storage.Transaction) (*transaction, error) { return underlying, nil } -const rootMustBeObjectMsg = "root must be object" -const rootCannotBeRemovedMsg = "root cannot be removed" - -func invalidPatchError(f string, a ...any) *storage.Error { - return &storage.Error{ - Code: storage.InvalidPatchErr, - Message: fmt.Sprintf(f, a...), - } -} - func mktree(path []string, value any) (map[string]any, error) { if len(path) == 0 { // For 0 length path the value is the full tree. obj, ok := value.(map[string]any) if !ok { - return nil, invalidPatchError(rootMustBeObjectMsg) + return nil, errors.RootMustBeObjectErr } return obj, nil } diff --git a/vendor/github.com/open-policy-agent/opa/v1/storage/inmem/txn.go b/vendor/github.com/open-policy-agent/opa/v1/storage/inmem/txn.go index 28e68c20f2e..e76bccd013f 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/storage/inmem/txn.go +++ b/vendor/github.com/open-policy-agent/opa/v1/storage/inmem/txn.go @@ -7,6 +7,7 @@ package inmem import ( "container/list" "encoding/json" + "slices" "strconv" "github.com/open-policy-agent/opa/internal/deepcopy" @@ -34,13 +35,13 @@ import ( // Read transactions do not require any special handling and simply passthrough // to the underlying store. Read transactions do not support upgrade. type transaction struct { - xid uint64 - write bool - stale bool db *store updates *list.List - policies map[string]policyUpdate context *storage.Context + policies map[string]policyUpdate + xid uint64 + write bool + stale bool } type policyUpdate struct { @@ -48,28 +49,17 @@ type policyUpdate struct { remove bool } -func newTransaction(xid uint64, write bool, context *storage.Context, db *store) *transaction { - return &transaction{ - xid: xid, - write: write, - db: db, - policies: map[string]policyUpdate{}, - updates: list.New(), - context: context, - } -} - func (txn *transaction) ID() uint64 { return txn.xid } func (txn *transaction) Write(op storage.PatchOp, path storage.Path, value any) error { - if !txn.write { - return &storage.Error{ - Code: storage.InvalidTransactionErr, - Message: "data write during read transaction", - } + return &storage.Error{Code: storage.InvalidTransactionErr, Message: "data write during read transaction"} + } + + if txn.updates == nil { + txn.updates = list.New() } if len(path) == 0 { @@ -85,9 +75,20 @@ func (txn *transaction) Write(op storage.PatchOp, path storage.Path, value any) if update.Path().Equal(path) { if update.Remove() { if op != storage.AddOp { - return errors.NewNotFoundError(path) + return errors.NotFoundErr } } + // If the last update has the same path and value, we have nothing to do. + if txn.db.returnASTValuesOnRead { + if astValue, ok := update.Value().(ast.Value); ok { + if equalsValue(value, astValue) { + return nil + } + } + } else if comparableEquals(update.Value(), value) { + return nil + } + txn.updates.Remove(curr) break } @@ -106,7 +107,7 @@ func (txn *transaction) Write(op storage.PatchOp, path storage.Path, value any) // existing update is mutated. if path.HasPrefix(update.Path()) { if update.Remove() { - return errors.NewNotFoundError(path) + return errors.NotFoundErr } suffix := path[len(update.Path()):] newUpdate, err := txn.db.newUpdate(update.Value(), op, suffix, 0, value) @@ -129,33 +130,53 @@ func (txn *transaction) Write(op storage.PatchOp, path storage.Path, value any) return nil } +func comparableEquals(a, b any) bool { + switch a := a.(type) { + case nil: + return b == nil + case bool: + if vb, ok := b.(bool); ok { + return vb == a + } + case string: + if vs, ok := b.(string); ok { + return vs == a + } + case json.Number: + if vn, ok := b.(json.Number); ok { + return vn == a + } + } + return false +} + func (txn *transaction) updateRoot(op storage.PatchOp, value any) error { if op == storage.RemoveOp { - return invalidPatchError(rootCannotBeRemovedMsg) + return errors.RootCannotBeRemovedErr } var update any if txn.db.returnASTValuesOnRead { - valueAST, err := interfaceToValue(value) + valueAST, err := ast.InterfaceToValue(value) if err != nil { return err } if _, ok := valueAST.(ast.Object); !ok { - return invalidPatchError(rootMustBeObjectMsg) + return errors.RootMustBeObjectErr } update = &updateAST{ - path: storage.Path{}, + path: storage.RootPath, remove: false, value: valueAST, } } else { if _, ok := value.(map[string]any); !ok { - return invalidPatchError(rootMustBeObjectMsg) + return errors.RootMustBeObjectErr } update = &updateRaw{ - path: storage.Path{}, + path: storage.RootPath, remove: false, value: value, } @@ -163,21 +184,36 @@ func (txn *transaction) updateRoot(op storage.PatchOp, value any) error { txn.updates.Init() txn.updates.PushFront(update) + return nil } func (txn *transaction) Commit() (result storage.TriggerEvent) { result.Context = txn.context - for curr := txn.updates.Front(); curr != nil; curr = curr.Next() { - action := curr.Value.(dataUpdate) - txn.db.data = action.Apply(txn.db.data) - result.Data = append(result.Data, storage.DataEvent{ - Path: action.Path(), - Data: action.Value(), - Removed: action.Remove(), - }) + if txn.updates != nil { + if len(txn.db.triggers) > 0 { + result.Data = slices.Grow(result.Data, txn.updates.Len()) + } + + for curr := txn.updates.Front(); curr != nil; curr = curr.Next() { + action := curr.Value.(dataUpdate) + txn.db.data = action.Apply(txn.db.data) + + if len(txn.db.triggers) > 0 { + result.Data = append(result.Data, storage.DataEvent{ + Path: action.Path(), + Data: action.Value(), + Removed: action.Remove(), + }) + } + } + } + + if len(txn.policies) > 0 && len(txn.db.triggers) > 0 { + result.Policy = slices.Grow(result.Policy, len(txn.policies)) } + for id, upd := range txn.policies { if upd.remove { delete(txn.db.policies, id) @@ -185,11 +221,13 @@ func (txn *transaction) Commit() (result storage.TriggerEvent) { txn.db.policies[id] = upd.value } - result.Policy = append(result.Policy, storage.PolicyEvent{ - ID: id, - Data: upd.value, - Removed: upd.remove, - }) + if len(txn.db.triggers) > 0 { + result.Policy = append(result.Policy, storage.PolicyEvent{ + ID: id, + Data: upd.value, + Removed: upd.remove, + }) + } } return result } @@ -218,8 +256,7 @@ func deepcpy(v any) any { } func (txn *transaction) Read(path storage.Path) (any, error) { - - if !txn.write { + if !txn.write || txn.updates == nil { return pointer(txn.db.data, path) } @@ -231,7 +268,7 @@ func (txn *transaction) Read(path storage.Path) (any, error) { if path.HasPrefix(upd.Path()) { if upd.Remove() { - return nil, errors.NewNotFoundError(path) + return nil, errors.NotFoundErr } return pointer(upd.Value(), path[len(upd.Path()):]) } @@ -260,8 +297,7 @@ func (txn *transaction) Read(path storage.Path) (any, error) { return cpy, nil } -func (txn *transaction) ListPolicies() []string { - var ids []string +func (txn *transaction) ListPolicies() (ids []string) { for id := range txn.db.policies { if _, ok := txn.policies[id]; !ok { ids = append(ids, id) @@ -276,11 +312,13 @@ func (txn *transaction) ListPolicies() []string { } func (txn *transaction) GetPolicy(id string) ([]byte, error) { - if update, ok := txn.policies[id]; ok { - if !update.remove { - return update.value, nil + if txn.policies != nil { + if update, ok := txn.policies[id]; ok { + if !update.remove { + return update.value, nil + } + return nil, errors.NewNotFoundErrorf("policy id %q", id) } - return nil, errors.NewNotFoundErrorf("policy id %q", id) } if exist, ok := txn.db.policies[id]; ok { return exist, nil @@ -289,24 +327,24 @@ func (txn *transaction) GetPolicy(id string) ([]byte, error) { } func (txn *transaction) UpsertPolicy(id string, bs []byte) error { - if !txn.write { - return &storage.Error{ - Code: storage.InvalidTransactionErr, - Message: "policy write during read transaction", - } - } - txn.policies[id] = policyUpdate{bs, false} - return nil + return txn.updatePolicy(id, policyUpdate{bs, false}) } func (txn *transaction) DeletePolicy(id string) error { + return txn.updatePolicy(id, policyUpdate{nil, true}) +} + +func (txn *transaction) updatePolicy(id string, update policyUpdate) error { if !txn.write { - return &storage.Error{ - Code: storage.InvalidTransactionErr, - Message: "policy write during read transaction", - } + return &storage.Error{Code: storage.InvalidTransactionErr, Message: "policy write during read transaction"} + } + + if txn.policies == nil { + txn.policies = map[string]policyUpdate{id: update} + } else { + txn.policies[id] = update } - txn.policies[id] = policyUpdate{nil, true} + return nil } @@ -327,13 +365,33 @@ type updateRaw struct { value any // value to add/replace at path (ignored if remove is true) } +func equalsValue(a any, v ast.Value) bool { + if a, ok := a.(ast.Value); ok { + return a.Compare(v) == 0 + } + switch a := a.(type) { + case nil: + return v == ast.NullValue + case bool: + if vb, ok := v.(ast.Boolean); ok { + return bool(vb) == a + } + case string: + if vs, ok := v.(ast.String); ok { + return string(vs) == a + } + } + + return false +} + func (db *store) newUpdate(data any, op storage.PatchOp, path storage.Path, idx int, value any) (dataUpdate, error) { if db.returnASTValuesOnRead { - astData, err := interfaceToValue(data) + astData, err := ast.InterfaceToValue(data) if err != nil { return nil, err } - astValue, err := interfaceToValue(value) + astValue, err := ast.InterfaceToValue(value) if err != nil { return nil, err } @@ -343,10 +401,9 @@ func (db *store) newUpdate(data any, op storage.PatchOp, path storage.Path, idx } func newUpdateRaw(data any, op storage.PatchOp, path storage.Path, idx int, value any) (dataUpdate, error) { - switch data.(type) { case nil, bool, json.Number, string: - return nil, errors.NewNotFoundError(path) + return nil, errors.NotFoundErr } switch data := data.(type) { @@ -364,11 +421,10 @@ func newUpdateRaw(data any, op storage.PatchOp, path storage.Path, idx int, valu } func newUpdateArray(data []any, op storage.PatchOp, path storage.Path, idx int, value any) (dataUpdate, error) { - if idx == len(path)-1 { if path[idx] == "-" || path[idx] == strconv.Itoa(len(data)) { if op != storage.AddOp { - return nil, invalidPatchError("%v: invalid patch path", path) + return nil, errors.NewInvalidPatchError("%v: invalid patch path", path) } cpy := make([]any, len(data)+1) copy(cpy, data) @@ -417,7 +473,7 @@ func newUpdateObject(data map[string]any, op storage.PatchOp, path storage.Path, switch op { case storage.ReplaceOp, storage.RemoveOp: if _, ok := data[path[idx]]; !ok { - return nil, errors.NewNotFoundError(path) + return nil, errors.NotFoundErr } } return &updateRaw{path, op == storage.RemoveOp, value}, nil @@ -427,7 +483,7 @@ func newUpdateObject(data map[string]any, op storage.PatchOp, path storage.Path, return newUpdateRaw(data, op, path, idx+1, value) } - return nil, errors.NewNotFoundError(path) + return nil, errors.NotFoundErr } func (u *updateRaw) Remove() bool { diff --git a/vendor/github.com/open-policy-agent/opa/v1/storage/interface.go b/vendor/github.com/open-policy-agent/opa/v1/storage/interface.go index 1d035670662..a783caae090 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/storage/interface.go +++ b/vendor/github.com/open-policy-agent/opa/v1/storage/interface.go @@ -49,6 +49,11 @@ type MakeDirer interface { MakeDir(context.Context, Transaction, Path) error } +// NonEmptyer allows a store implemention to override NonEmpty()) +type NonEmptyer interface { + NonEmpty(context.Context, Transaction) func([]string) (bool, error) +} + // TransactionParams describes a new transaction. type TransactionParams struct { diff --git a/vendor/github.com/open-policy-agent/opa/v1/storage/internal/errors/errors.go b/vendor/github.com/open-policy-agent/opa/v1/storage/internal/errors/errors.go index d13fff50fc3..a478b9f257f 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/storage/internal/errors/errors.go +++ b/vendor/github.com/open-policy-agent/opa/v1/storage/internal/errors/errors.go @@ -11,27 +11,31 @@ import ( "github.com/open-policy-agent/opa/v1/storage" ) -const ArrayIndexTypeMsg = "array index must be integer" -const DoesNotExistMsg = "document does not exist" -const OutOfRangeMsg = "array index out of range" +const ( + ArrayIndexTypeMsg = "array index must be integer" + DoesNotExistMsg = "document does not exist" + OutOfRangeMsg = "array index out of range" + RootMustBeObjectMsg = "root must be object" + RootCannotBeRemovedMsg = "root cannot be removed" +) -func NewNotFoundError(path storage.Path) *storage.Error { - return NewNotFoundErrorWithHint(path, DoesNotExistMsg) -} +var ( + NotFoundErr = &storage.Error{Code: storage.NotFoundErr, Message: DoesNotExistMsg} + RootMustBeObjectErr = &storage.Error{Code: storage.InvalidPatchErr, Message: RootMustBeObjectMsg} + RootCannotBeRemovedErr = &storage.Error{Code: storage.InvalidPatchErr, Message: RootCannotBeRemovedMsg} +) func NewNotFoundErrorWithHint(path storage.Path, hint string) *storage.Error { - message := path.String() + ": " + hint return &storage.Error{ Code: storage.NotFoundErr, - Message: message, + Message: path.String() + ": " + hint, } } func NewNotFoundErrorf(f string, a ...any) *storage.Error { - msg := fmt.Sprintf(f, a...) return &storage.Error{ Code: storage.NotFoundErr, - Message: msg, + Message: fmt.Sprintf(f, a...), } } @@ -41,3 +45,10 @@ func NewWriteConflictError(p storage.Path) *storage.Error { Message: p.String(), } } + +func NewInvalidPatchError(f string, a ...any) *storage.Error { + return &storage.Error{ + Code: storage.InvalidPatchErr, + Message: fmt.Sprintf(f, a...), + } +} diff --git a/vendor/github.com/open-policy-agent/opa/v1/storage/internal/ptr/ptr.go b/vendor/github.com/open-policy-agent/opa/v1/storage/internal/ptr/ptr.go index c5e380af04d..bef39ebf497 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/storage/internal/ptr/ptr.go +++ b/vendor/github.com/open-policy-agent/opa/v1/storage/internal/ptr/ptr.go @@ -21,7 +21,7 @@ func Ptr(data any, path storage.Path) (any, error) { case map[string]any: var ok bool if node, ok = curr[key]; !ok { - return nil, errors.NewNotFoundError(path) + return nil, errors.NotFoundErr } case []any: pos, err := ValidateArrayIndex(curr, key, path) @@ -30,7 +30,7 @@ func Ptr(data any, path storage.Path) (any, error) { } node = curr[pos] default: - return nil, errors.NewNotFoundError(path) + return nil, errors.NotFoundErr } } @@ -38,24 +38,45 @@ func Ptr(data any, path storage.Path) (any, error) { } func ValuePtr(data ast.Value, path storage.Path) (ast.Value, error) { + var keyTerm *ast.Term + + defer func() { + if keyTerm != nil { + ast.TermPtrPool.Put(keyTerm) + } + }() + node := data for i := range path { key := path[i] switch curr := node.(type) { case ast.Object: - // This term is only created for the lookup, which is not.. ideal. - // By using the pool, we can at least avoid allocating the term itself, - // while still having to pay 1 allocation for the value. A better solution - // would be dynamically interned string terms. - keyTerm := ast.TermPtrPool.Get() - keyTerm.Value = ast.String(key) - - val := curr.Get(keyTerm) - ast.TermPtrPool.Put(keyTerm) - if val == nil { - return nil, errors.NewNotFoundError(path) + // Note(anders): + // This term is only created for the lookup, which is not great — especially + // considering the path likely was converted from a ref, where we had all + // the terms available already! Without chaging the storage API, our options + // for performant lookups are limitied to using interning or a pool. Prefer + // interning when possible, as that is zero alloc. Using the pool avoids at + // least allocating a new term for every lookup, but still requires an alloc + // for the string Value. + if ast.HasInternedValue(key) { + if val := curr.Get(ast.InternedTerm(key)); val != nil { + node = val.Value + } else { + return nil, errors.NotFoundErr + } + } else { + if keyTerm == nil { + keyTerm = ast.TermPtrPool.Get() + } + // 1 alloc + keyTerm.Value = ast.String(key) + if val := curr.Get(keyTerm); val != nil { + node = val.Value + } else { + return nil, errors.NotFoundErr + } } - node = val.Value case *ast.Array: pos, err := ValidateASTArrayIndex(curr, key, path) if err != nil { @@ -63,7 +84,7 @@ func ValuePtr(data ast.Value, path storage.Path) (ast.Value, error) { } node = curr.Elem(pos).Value default: - return nil, errors.NewNotFoundError(path) + return nil, errors.NotFoundErr } } diff --git a/vendor/github.com/open-policy-agent/opa/v1/storage/path.go b/vendor/github.com/open-policy-agent/opa/v1/storage/path.go index f774d2eeda7..16bb3e42c51 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/storage/path.go +++ b/vendor/github.com/open-policy-agent/opa/v1/storage/path.go @@ -8,40 +8,40 @@ import ( "errors" "fmt" "net/url" + "slices" "strconv" "strings" "github.com/open-policy-agent/opa/v1/ast" ) +// RootPath refers to the root document in storage. +var RootPath = Path{} + // Path refers to a document in storage. type Path []string // ParsePath returns a new path for the given str. func ParsePath(str string) (path Path, ok bool) { - if len(str) == 0 { - return nil, false - } - if str[0] != '/' { + if len(str) == 0 || str[0] != '/' { return nil, false } if len(str) == 1 { return Path{}, true } - parts := strings.Split(str[1:], "/") - return parts, true + + return strings.Split(str[1:], "/"), true } // ParsePathEscaped returns a new path for the given escaped str. func ParsePathEscaped(str string) (path Path, ok bool) { - path, ok = ParsePath(str) - if !ok { - return - } - for i := range path { - segment, err := url.PathUnescape(path[i]) - if err == nil { - path[i] = segment + if path, ok = ParsePath(str); ok { + for i := range path { + if segment, err := url.PathUnescape(path[i]); err == nil { + path[i] = segment + } else { + return nil, false + } } } return @@ -49,7 +49,6 @@ func ParsePathEscaped(str string) (path Path, ok bool) { // NewPathForRef returns a new path for the given ref. func NewPathForRef(ref ast.Ref) (path Path, err error) { - if len(ref) == 0 { return nil, errors.New("empty reference (indicates error in caller)") } @@ -85,36 +84,17 @@ func NewPathForRef(ref ast.Ref) (path Path, err error) { // is less than other, 0 if p is equal to other, or 1 if p is greater than // other. func (p Path) Compare(other Path) (cmp int) { - for i := range min(len(p), len(other)) { - if cmp := strings.Compare(p[i], other[i]); cmp != 0 { - return cmp - } - } - if len(p) < len(other) { - return -1 - } - if len(p) == len(other) { - return 0 - } - return 1 + return slices.Compare(p, other) } // Equal returns true if p is the same as other. func (p Path) Equal(other Path) bool { - return p.Compare(other) == 0 + return slices.Equal(p, other) } // HasPrefix returns true if p starts with other. func (p Path) HasPrefix(other Path) bool { - if len(other) > len(p) { - return false - } - for i := range other { - if p[i] != other[i] { - return false - } - } - return true + return len(other) <= len(p) && p[:len(other)].Equal(other) } // Ref returns a ref that represents p rooted at head. diff --git a/vendor/github.com/open-policy-agent/opa/v1/storage/storage.go b/vendor/github.com/open-policy-agent/opa/v1/storage/storage.go index ecc3829940b..38d51be405e 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/storage/storage.go +++ b/vendor/github.com/open-policy-agent/opa/v1/storage/storage.go @@ -111,6 +111,9 @@ func Txn(ctx context.Context, store Store, params TransactionParams, f func(Tran // path is non-empty if a Read on the path returns a value or a Read // on any of the path prefixes returns a non-object value. func NonEmpty(ctx context.Context, store Store, txn Transaction) func([]string) (bool, error) { + if md, ok := store.(NonEmptyer); ok { + return md.NonEmpty(ctx, txn) + } return func(path []string) (bool, error) { if _, err := store.Read(ctx, txn, Path(path)); err == nil { return true, nil diff --git a/vendor/github.com/open-policy-agent/opa/v1/topdown/aggregates.go b/vendor/github.com/open-policy-agent/opa/v1/topdown/aggregates.go index eec49f7b886..03d07668d85 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/topdown/aggregates.go +++ b/vendor/github.com/open-policy-agent/opa/v1/topdown/aggregates.go @@ -177,7 +177,7 @@ func builtinMin(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) err // The null term is considered to be less than any other term, // so in order for min of a set to make sense, we need to check // for it. - if min.Value.Compare(ast.InternedNullTerm.Value) == 0 { + if min.Value.Compare(ast.InternedNullValue) == 0 { return elem, nil } diff --git a/vendor/github.com/open-policy-agent/opa/v1/topdown/cache/cache.go b/vendor/github.com/open-policy-agent/opa/v1/topdown/cache/cache.go index 60f38aaba2f..d514bed787e 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/topdown/cache/cache.go +++ b/vendor/github.com/open-policy-agent/opa/v1/topdown/cache/cache.go @@ -43,12 +43,40 @@ type Config struct { InterQueryBuiltinValueCache InterQueryBuiltinValueCacheConfig `json:"inter_query_builtin_value_cache"` } +// Clone creates a deep copy of Config. +func (c *Config) Clone() *Config { + if c == nil { + return nil + } + + return &Config{ + InterQueryBuiltinCache: *c.InterQueryBuiltinCache.Clone(), + InterQueryBuiltinValueCache: *c.InterQueryBuiltinValueCache.Clone(), + } +} + // NamedValueCacheConfig represents the configuration of a named cache that built-in functions can utilize. // A default configuration to be used if not explicitly configured can be registered using RegisterDefaultInterQueryBuiltinValueCacheConfig. type NamedValueCacheConfig struct { MaxNumEntries *int `json:"max_num_entries,omitempty"` } +// Clone creates a deep copy of NamedValueCacheConfig. +func (n *NamedValueCacheConfig) Clone() *NamedValueCacheConfig { + if n == nil { + return nil + } + + clone := &NamedValueCacheConfig{} + + if n.MaxNumEntries != nil { + maxEntries := *n.MaxNumEntries + clone.MaxNumEntries = &maxEntries + } + + return clone +} + // InterQueryBuiltinValueCacheConfig represents the configuration of the inter-query value cache that built-in functions can utilize. // MaxNumEntries - max number of cache entries type InterQueryBuiltinValueCacheConfig struct { @@ -56,6 +84,29 @@ type InterQueryBuiltinValueCacheConfig struct { NamedCacheConfigs map[string]*NamedValueCacheConfig `json:"named,omitempty"` } +// Clone creates a deep copy of InterQueryBuiltinValueCacheConfig. +func (i *InterQueryBuiltinValueCacheConfig) Clone() *InterQueryBuiltinValueCacheConfig { + if i == nil { + return nil + } + + clone := &InterQueryBuiltinValueCacheConfig{} + + if i.MaxNumEntries != nil { + maxEntries := *i.MaxNumEntries + clone.MaxNumEntries = &maxEntries + } + + if i.NamedCacheConfigs != nil { + clone.NamedCacheConfigs = make(map[string]*NamedValueCacheConfig, len(i.NamedCacheConfigs)) + for k, v := range i.NamedCacheConfigs { + clone.NamedCacheConfigs[k] = v.Clone() + } + } + + return clone +} + // InterQueryBuiltinCacheConfig represents the configuration of the inter-query cache that built-in functions can utilize. // MaxSizeBytes - max capacity of cache in bytes // ForcedEvictionThresholdPercentage - capacity usage in percentage after which forced FIFO eviction starts @@ -66,6 +117,32 @@ type InterQueryBuiltinCacheConfig struct { StaleEntryEvictionPeriodSeconds *int64 `json:"stale_entry_eviction_period_seconds,omitempty"` } +// Clone creates a deep copy of InterQueryBuiltinCacheConfig. +func (i *InterQueryBuiltinCacheConfig) Clone() *InterQueryBuiltinCacheConfig { + if i == nil { + return nil + } + + clone := &InterQueryBuiltinCacheConfig{} + + if i.MaxSizeBytes != nil { + maxSize := *i.MaxSizeBytes + clone.MaxSizeBytes = &maxSize + } + + if i.ForcedEvictionThresholdPercentage != nil { + threshold := *i.ForcedEvictionThresholdPercentage + clone.ForcedEvictionThresholdPercentage = &threshold + } + + if i.StaleEntryEvictionPeriodSeconds != nil { + period := *i.StaleEntryEvictionPeriodSeconds + clone.StaleEntryEvictionPeriodSeconds = &period + } + + return clone +} + // ParseCachingConfig returns the config for the inter-query cache. func ParseCachingConfig(raw []byte) (*Config, error) { if raw == nil { diff --git a/vendor/github.com/open-policy-agent/opa/v1/topdown/copypropagation/copypropagation.go b/vendor/github.com/open-policy-agent/opa/v1/topdown/copypropagation/copypropagation.go index e582205f44b..7767e7ff520 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/topdown/copypropagation/copypropagation.go +++ b/vendor/github.com/open-policy-agent/opa/v1/topdown/copypropagation/copypropagation.go @@ -163,7 +163,8 @@ func (p *CopyPropagator) Apply(query ast.Body) ast.Body { // to the current result. // Invariant: Live vars are bound (above) and reserved vars are implicitly ground. - safe := ast.ReservedVars.Copy() + safe := ast.NewVarSetOfSize(len(p.livevars) + len(ast.ReservedVars) + 6) + safe.Update(ast.ReservedVars) safe.Update(p.livevars) safe.Update(ast.OutputVarsFromBody(p.compiler, result, safe)) unsafe := result.Vars(ast.SafetyCheckVisitorParams).Diff(safe) @@ -173,9 +174,8 @@ func (p *CopyPropagator) Apply(query ast.Body) ast.Body { providesSafety := false outputVars := ast.OutputVarsFromExpr(p.compiler, removedEq, safe) - diff := unsafe.Diff(outputVars) - if len(diff) < len(unsafe) { - unsafe = diff + if unsafe.DiffCount(outputVars) < len(unsafe) { + unsafe = unsafe.Diff(outputVars) providesSafety = true } diff --git a/vendor/github.com/open-policy-agent/opa/v1/topdown/crypto.go b/vendor/github.com/open-policy-agent/opa/v1/topdown/crypto.go index 2710d8a04a8..144c01ee953 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/topdown/crypto.go +++ b/vendor/github.com/open-policy-agent/opa/v1/topdown/crypto.go @@ -25,7 +25,7 @@ import ( "strings" "time" - "github.com/open-policy-agent/opa/internal/jwx/jwk" + "github.com/lestrrat-go/jwx/v3/jwk" "github.com/open-policy-agent/opa/v1/ast" "github.com/open-policy-agent/opa/v1/topdown/builtins" @@ -361,7 +361,7 @@ func builtinCryptoJWKFromPrivateKey(_ BuiltinContext, operands []*ast.Term, iter return iter(ast.InternedNullTerm) } - key, err := jwk.New(rawKeys[0]) + key, err := jwk.Import(rawKeys[0]) if err != nil { return err } diff --git a/vendor/github.com/open-policy-agent/opa/v1/topdown/eval.go b/vendor/github.com/open-policy-agent/opa/v1/topdown/eval.go index 023e9c09b3c..f05fd9d94a2 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/topdown/eval.go +++ b/vendor/github.com/open-policy-agent/opa/v1/topdown/eval.go @@ -106,6 +106,7 @@ type eval struct { tracers []QueryTracer tracingOpts tracing.Options queryID uint64 + timeStart int64 index int genvarid int indexing bool @@ -171,16 +172,17 @@ func (e *eval) string(s *strings.Builder) { func (e *eval) builtinFunc(name string) (*ast.Builtin, BuiltinFunc, bool) { decl, ok := ast.BuiltinMap[name] if ok { - f, ok := builtinFunctions[name] - if ok { + if f, ok := builtinFunctions[name]; ok { return decl, f, true } - } else { - bi, ok := e.builtins[name] - if ok { - return bi.Decl, bi.Func, true + if bi, ok := e.builtins[name]; ok { + return decl, bi.Func, true } } + if bi, ok := e.builtins[name]; ok { + return bi.Decl, bi.Func, true + } + return nil, nil, false } @@ -561,7 +563,6 @@ func (e *eval) fmtVarTerm() string { } func (e *eval) evalNot(iter evalIterator) error { - expr := e.query[e.index] if e.unknown(expr, e.bindings) { @@ -952,7 +953,7 @@ func (e *eval) evalCall(terms []*ast.Term, iter unifyIterator) error { var bctx *BuiltinContext // Creating a BuiltinContext is expensive, so only do it if the builtin depends on it. - if bi.NeedsBuiltInContext() { + if !bi.CanSkipBctx { var parentID uint64 if e.parent != nil { parentID = e.parent.queryID @@ -963,6 +964,10 @@ func (e *eval) evalCall(terms []*ast.Term, iter unifyIterator) error { capabilities = e.compiler.Capabilities() } + if e.time == nil { + e.time = ast.NumberTerm(int64ToJSONNumber(e.timeStart)) + } + bctx = &BuiltinContext{ Context: e.ctx, Metrics: e.metrics, @@ -1647,12 +1652,11 @@ func (e *eval) getRules(ref ast.Ref, args []*ast.Term) (*ast.IndexResult, error) var result *ast.IndexResult var err error + resolver.e = e if e.indexing { - resolver.e = e resolver.args = args result, err = index.Lookup(resolver) } else { - resolver.e = e result, err = index.AllRules(resolver) } if err != nil { @@ -4106,8 +4110,7 @@ func canInlineNegation(safe ast.VarSet, queries []ast.Body) bool { SkipClosures: true, }) vis.Walk(expr) - unsafe := vis.Vars().Diff(safe).Diff(ast.ReservedVars) - if len(unsafe) > 0 { + if vis.Vars().Diff(safe).DiffCount(ast.ReservedVars) > 0 { return false } } diff --git a/vendor/github.com/open-policy-agent/opa/v1/topdown/graphql.go b/vendor/github.com/open-policy-agent/opa/v1/topdown/graphql.go index 8539a9e0dc1..f3bdf8e414c 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/topdown/graphql.go +++ b/vendor/github.com/open-policy-agent/opa/v1/topdown/graphql.go @@ -675,7 +675,7 @@ const gqlCacheName = "graphql" func init() { - var defaultCacheEntries int = 10 + var defaultCacheEntries = 10 var graphqlCacheConfig = cache.NamedValueCacheConfig{ MaxNumEntries: &defaultCacheEntries, } diff --git a/vendor/github.com/open-policy-agent/opa/v1/topdown/http.go b/vendor/github.com/open-policy-agent/opa/v1/topdown/http.go index 36fa1572ec6..36c622e5a41 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/topdown/http.go +++ b/vendor/github.com/open-policy-agent/opa/v1/topdown/http.go @@ -99,6 +99,7 @@ var ( requiredKeys = ast.NewSet(ast.InternedTerm("method"), ast.InternedTerm("url")) httpSendLatencyMetricKey = "rego_builtin_http_send" httpSendInterQueryCacheHits = httpSendLatencyMetricKey + "_interquery_cache_hits" + httpSendNetworkRequests = httpSendLatencyMetricKey + "_network_requests" ) type httpSendKey string @@ -1315,7 +1316,7 @@ func parseCacheControlHeader(headers http.Header) map[string]string { ccDirectives := map[string]string{} ccHeader := headers.Get("cache-control") - for _, part := range strings.Split(ccHeader, ",") { + for part := range strings.SplitSeq(ccHeader, ",") { part = strings.Trim(part, " ") if part == "" { continue @@ -1535,6 +1536,9 @@ func (c *interQueryCache) ExecuteHTTPRequest() (*http.Response, error) { return nil, handleHTTPSendErr(c.bctx, err) } + // Increment counter for actual network requests + c.bctx.Metrics.Counter(httpSendNetworkRequests).Incr() + return executeHTTPRequest(c.httpReq, c.httpClient, c.req) } @@ -1586,6 +1590,10 @@ func (c *intraQueryCache) ExecuteHTTPRequest() (*http.Response, error) { if err != nil { return nil, handleHTTPSendErr(c.bctx, err) } + + // Increment counter for actual network requests + c.bctx.Metrics.Counter(httpSendNetworkRequests).Incr() + return executeHTTPRequest(httpReq, httpClient, c.req) } diff --git a/vendor/github.com/open-policy-agent/opa/v1/topdown/numbers.go b/vendor/github.com/open-policy-agent/opa/v1/topdown/numbers.go index a3f8f0854ff..1e05a247a93 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/topdown/numbers.go +++ b/vendor/github.com/open-policy-agent/opa/v1/topdown/numbers.go @@ -15,8 +15,10 @@ import ( type randIntCachingKey string -var zero = big.NewInt(0) -var one = big.NewInt(1) +var ( + zero = big.NewInt(0) + one = big.NewInt(1) +) func builtinNumbersRange(bctx BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { if canGenerateCheapRange(operands) { @@ -45,8 +47,9 @@ func builtinNumbersRangeStep(bctx BuiltinContext, operands []*ast.Term, iter fun if canGenerateCheapRangeStep(operands) { step, _ := builtins.IntOperand(operands[2].Value, 3) if step <= 0 { - return errors.New("numbers.range_step: step must be a positive number above zero") + return errors.New("numbers.range_step: step must be a positive integer") } + return generateCheapRange(operands, step, iter) } @@ -66,7 +69,7 @@ func builtinNumbersRangeStep(bctx BuiltinContext, operands []*ast.Term, iter fun } if step.Cmp(zero) <= 0 { - return errors.New("numbers.range_step: step must be a positive number above zero") + return errors.New("numbers.range_step: step must be a positive integer") } ast, err := generateRange(bctx, x, y, step, "numbers.range_step") @@ -158,11 +161,9 @@ func generateRange(bctx BuiltinContext, x *big.Int, y *big.Int, step *big.Int, f } func builtinRandIntn(bctx BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { - strOp, err := builtins.StringOperand(operands[0].Value, 1) if err != nil { return err - } n, err := builtins.IntOperand(operands[1].Value, 2) @@ -178,7 +179,7 @@ func builtinRandIntn(bctx BuiltinContext, operands []*ast.Term, iter func(*ast.T n = -n } - var key = randIntCachingKey(fmt.Sprintf("%s-%d", strOp, n)) + key := randIntCachingKey(fmt.Sprintf("%s-%d", strOp, n)) if val, ok := bctx.Cache.Get(key); ok { return iter(val.(*ast.Term)) diff --git a/vendor/github.com/open-policy-agent/opa/v1/topdown/query.go b/vendor/github.com/open-policy-agent/opa/v1/topdown/query.go index aee6ba12ebe..aadcc060cfd 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/topdown/query.go +++ b/vendor/github.com/open-policy-agent/opa/v1/topdown/query.go @@ -374,7 +374,7 @@ func (q *Query) PartialRun(ctx context.Context) (partials []ast.Body, support [] ctx: ctx, metrics: q.metrics, seed: q.seed, - time: ast.NumberTerm(int64ToJSONNumber(q.time.UnixNano())), + timeStart: q.time.UnixNano(), cancel: q.cancel, query: q.query, queryCompiler: q.queryCompiler, @@ -569,7 +569,7 @@ func (q *Query) Iter(ctx context.Context, iter func(QueryResult) error) error { ctx: ctx, metrics: q.metrics, seed: q.seed, - time: ast.NumberTerm(int64ToJSONNumber(q.time.UnixNano())), + timeStart: q.time.UnixNano(), cancel: q.cancel, query: q.query, queryCompiler: q.queryCompiler, diff --git a/vendor/github.com/open-policy-agent/opa/v1/topdown/strings.go b/vendor/github.com/open-policy-agent/opa/v1/topdown/strings.go index 53108ca0db0..13e9b81339c 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/topdown/strings.go +++ b/vendor/github.com/open-policy-agent/opa/v1/topdown/strings.go @@ -18,6 +18,7 @@ import ( "github.com/open-policy-agent/opa/v1/ast" "github.com/open-policy-agent/opa/v1/topdown/builtins" + "github.com/open-policy-agent/opa/v1/util" ) func builtinAnyPrefixMatch(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { @@ -514,18 +515,12 @@ func builtinSplit(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) e return err } - if !strings.Contains(string(s), string(d)) { + text, delim := string(s), string(d) + if !strings.Contains(text, delim) { return iter(ast.ArrayTerm(operands[0])) } - elems := strings.Split(string(s), string(d)) - arr := make([]*ast.Term, len(elems)) - - for i := range elems { - arr[i] = ast.InternedTerm(elems[i]) - } - - return iter(ast.ArrayTerm(arr...)) + return iter(ast.ArrayTerm(util.SplitMap(text, delim, ast.InternedTerm)...)) } func builtinReplace(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { diff --git a/vendor/github.com/open-policy-agent/opa/v1/topdown/tokens.go b/vendor/github.com/open-policy-agent/opa/v1/topdown/tokens.go index 831dc32b876..aea15dd26a4 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/topdown/tokens.go +++ b/vendor/github.com/open-policy-agent/opa/v1/topdown/tokens.go @@ -7,11 +7,13 @@ package topdown import ( "crypto" "crypto/ecdsa" + "crypto/ed25519" "crypto/hmac" "crypto/rsa" "crypto/sha256" "crypto/sha512" "crypto/x509" + "encoding/base64" "encoding/hex" "encoding/json" "encoding/pem" @@ -21,9 +23,9 @@ import ( "math/big" "strings" - "github.com/open-policy-agent/opa/internal/jwx/jwa" - "github.com/open-policy-agent/opa/internal/jwx/jwk" - "github.com/open-policy-agent/opa/internal/jwx/jws" + "github.com/lestrrat-go/jwx/v3/jwk" + "github.com/lestrrat-go/jwx/v3/jws/jwsbb" + "github.com/open-policy-agent/opa/v1/ast" "github.com/open-policy-agent/opa/v1/topdown/builtins" "github.com/open-policy-agent/opa/v1/topdown/cache" @@ -269,6 +271,31 @@ func verifyES(publicKey any, digest []byte, signature []byte) (err error) { return errors.New("ECDSA signature verification error") } +// Implements EdDSA JWT signature verification +func builtinJWTVerifyEdDSA(bctx BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + result, err := builtinJWTVerify(bctx, operands[0].Value, operands[1].Value, nil, verifyEd25519) + if err == nil { + return iter(ast.InternedTerm(result)) + } + return err +} + +func verifyEd25519(publicKey any, digest []byte, signature []byte) (err error) { + defer func() { + if r := recover(); r != nil { + err = fmt.Errorf("EdDSA signature verification error: %v", r) + } + }() + publicKeyEcdsa, ok := publicKey.(ed25519.PublicKey) + if !ok { + return errors.New("incorrect public key type") + } + if ed25519.Verify(publicKeyEcdsa, digest, signature) { + return nil + } + return errors.New("ECDSA signature verification error") +} + type verificationKey struct { alg string kid string @@ -309,15 +336,36 @@ func getKeysFromCertOrJWK(certificate string) ([]verificationKey, error) { return nil, fmt.Errorf("failed to parse a JWK key (set): %w", err) } - keys := make([]verificationKey, 0, len(jwks.Keys)) - for _, k := range jwks.Keys { - key, err := k.Materialize() - if err != nil { + keys := make([]verificationKey, 0, jwks.Len()) + for i := range jwks.Len() { + k, ok := jwks.Key(i) + if !ok { + continue + } + var key any + if err := jwk.Export(k, &key); err != nil { return nil, err } + var alg string + if algInterface, ok := k.Algorithm(); ok { + alg = algInterface.String() + } + + // Skip keys with unknown/unsupported algorithms + if alg != "" { + if _, ok := tokenAlgorithms[alg]; !ok { + continue + } + } + + var kid string + if kidValue, ok := k.KeyID(); ok { + kid = kidValue + } + keys = append(keys, verificationKey{ - alg: k.GetAlgorithm().String(), - kid: k.GetKeyID(), + alg: alg, + kid: kid, key: key, }) } @@ -616,19 +664,13 @@ func (constraints *tokenConstraints) validate() error { // verify verifies a JWT using the constraints and the algorithm from the header func (constraints *tokenConstraints) verify(kid, alg, header, payload, signature string) error { // Construct the payload - plaintext := []byte(header) - plaintext = append(plaintext, []byte(".")...) - plaintext = append(plaintext, payload...) - // Look up the algorithm - a, ok := tokenAlgorithms[alg] - if !ok { - return fmt.Errorf("unknown JWS algorithm: %s", alg) - } + plaintext := append(append([]byte(header), '.'), []byte(payload)...) + // If we're configured with asymmetric key(s) then only trust that if constraints.keys != nil { if kid != "" { if key := getKeyByKid(kid, constraints.keys); key != nil { - err := a.verify(key.key, a.hash, plaintext, []byte(signature)) + err := jwsbb.Verify(key.key, alg, plaintext, []byte(signature)) if err != nil { return errSignatureNotVerified } @@ -639,7 +681,7 @@ func (constraints *tokenConstraints) verify(kid, alg, header, payload, signature verified := false for _, key := range constraints.keys { if key.alg == "" { - err := a.verify(key.key, a.hash, plaintext, []byte(signature)) + err := jwsbb.Verify(key.key, alg, plaintext, []byte(signature)) if err == nil { verified = true break @@ -648,7 +690,7 @@ func (constraints *tokenConstraints) verify(kid, alg, header, payload, signature if alg != key.alg { continue } - err := a.verify(key.key, a.hash, plaintext, []byte(signature)) + err := jwsbb.Verify(key.key, alg, plaintext, []byte(signature)) if err == nil { verified = true break @@ -662,7 +704,11 @@ func (constraints *tokenConstraints) verify(kid, alg, header, payload, signature return nil } if constraints.secret != "" { - return a.verify([]byte(constraints.secret), a.hash, plaintext, []byte(signature)) + err := jwsbb.Verify([]byte(constraints.secret), alg, plaintext, []byte(signature)) + if err != nil { + return errSignatureNotVerified + } + return nil } // (*tokenConstraints)validate() should prevent this happening return errors.New("unexpectedly found no keys to trust") @@ -689,101 +735,26 @@ func (constraints *tokenConstraints) validAudience(aud ast.Value) bool { // JWT algorithms -type ( - tokenVerifyFunction func(key any, hash crypto.Hash, payload []byte, signature []byte) error - tokenVerifyAsymmetricFunction func(key any, hash crypto.Hash, digest []byte, signature []byte) error -) - -// jwtAlgorithm describes a JWS 'alg' value -type tokenAlgorithm struct { - hash crypto.Hash - verify tokenVerifyFunction -} - // tokenAlgorithms is the known JWT algorithms -var tokenAlgorithms = map[string]tokenAlgorithm{ - "RS256": {crypto.SHA256, verifyAsymmetric(verifyRSAPKCS)}, - "RS384": {crypto.SHA384, verifyAsymmetric(verifyRSAPKCS)}, - "RS512": {crypto.SHA512, verifyAsymmetric(verifyRSAPKCS)}, - "PS256": {crypto.SHA256, verifyAsymmetric(verifyRSAPSS)}, - "PS384": {crypto.SHA384, verifyAsymmetric(verifyRSAPSS)}, - "PS512": {crypto.SHA512, verifyAsymmetric(verifyRSAPSS)}, - "ES256": {crypto.SHA256, verifyAsymmetric(verifyECDSA)}, - "ES384": {crypto.SHA384, verifyAsymmetric(verifyECDSA)}, - "ES512": {crypto.SHA512, verifyAsymmetric(verifyECDSA)}, - "HS256": {crypto.SHA256, verifyHMAC}, - "HS384": {crypto.SHA384, verifyHMAC}, - "HS512": {crypto.SHA512, verifyHMAC}, +var tokenAlgorithms = map[string]struct{}{ + "RS256": {}, + "RS384": {}, + "RS512": {}, + "PS256": {}, + "PS384": {}, + "PS512": {}, + "ES256": {}, + "ES384": {}, + "ES512": {}, + "HS256": {}, + "HS384": {}, + "HS512": {}, + "EdDSA": {}, } // errSignatureNotVerified is returned when a signature cannot be verified. var errSignatureNotVerified = errors.New("signature not verified") -func verifyHMAC(key any, hash crypto.Hash, payload []byte, signature []byte) error { - macKey, ok := key.([]byte) - if !ok { - return errors.New("incorrect symmetric key type") - } - mac := hmac.New(hash.New, macKey) - if _, err := mac.Write(payload); err != nil { - return err - } - if !hmac.Equal(signature, mac.Sum([]byte{})) { - return errSignatureNotVerified - } - return nil -} - -func verifyAsymmetric(verify tokenVerifyAsymmetricFunction) tokenVerifyFunction { - return func(key any, hash crypto.Hash, payload []byte, signature []byte) error { - h := hash.New() - h.Write(payload) - return verify(key, hash, h.Sum([]byte{}), signature) - } -} - -func verifyRSAPKCS(key any, hash crypto.Hash, digest []byte, signature []byte) error { - publicKeyRsa, ok := key.(*rsa.PublicKey) - if !ok { - return errors.New("incorrect public key type") - } - if err := rsa.VerifyPKCS1v15(publicKeyRsa, hash, digest, signature); err != nil { - return errSignatureNotVerified - } - return nil -} - -func verifyRSAPSS(key any, hash crypto.Hash, digest []byte, signature []byte) error { - publicKeyRsa, ok := key.(*rsa.PublicKey) - if !ok { - return errors.New("incorrect public key type") - } - if err := rsa.VerifyPSS(publicKeyRsa, hash, digest, signature, nil); err != nil { - return errSignatureNotVerified - } - return nil -} - -func verifyECDSA(key any, _ crypto.Hash, digest []byte, signature []byte) (err error) { - defer func() { - if r := recover(); r != nil { - err = fmt.Errorf("ECDSA signature verification error: %v", r) - } - }() - publicKeyEcdsa, ok := key.(*ecdsa.PublicKey) - if !ok { - return errors.New("incorrect public key type") - } - r, s := &big.Int{}, &big.Int{} - n := len(signature) / 2 - r.SetBytes(signature[:n]) - s.SetBytes(signature[n:]) - if ecdsa.Verify(publicKeyEcdsa, digest, r, s) { - return nil - } - return errSignatureNotVerified -} - // JWT header parsing and parameters. See tokens_test.go for unit tests. // tokenHeaderType represents a recognized JWT header field @@ -882,42 +853,48 @@ func (header *tokenHeader) valid() bool { return true } -func commonBuiltinJWTEncodeSign(bctx BuiltinContext, inputHeaders, jwsPayload, jwkSrc string, iter func(*ast.Term) error) error { - keys, err := jwk.ParseString(jwkSrc) +func commonBuiltinJWTEncodeSign(bctx BuiltinContext, inputHeaders, jwsPayload, jwkSrc []byte, iter func(*ast.Term) error) error { + keys, err := jwk.Parse(jwkSrc) if err != nil { return err } - key, err := keys.Keys[0].Materialize() - if err != nil { - return err + + if keys.Len() == 0 { + return errors.New("no keys found in JWK set") } - if jwk.GetKeyTypeFromKey(key) != keys.Keys[0].GetKeyType() { - return errors.New("JWK derived key type and keyType parameter do not match") + + key, ok := keys.Key(0) + if !ok { + return errors.New("failed to get first key from JWK set") } - standardHeaders := &jws.StandardHeaders{} - jwsHeaders := []byte(inputHeaders) - err = json.Unmarshal(jwsHeaders, standardHeaders) + // Parse headers to get algorithm. + headers := jwsbb.HeaderParse(inputHeaders) + algStr, err := jwsbb.HeaderGetString(headers, "alg") if err != nil { - return err + return fmt.Errorf("missing or invalid 'alg' header: %w", err) } - alg := standardHeaders.GetAlgorithm() - if alg == jwa.Unsupported { - return errors.New("unknown signature algorithm") + // Make sure the algorithm is supported. + _, ok = tokenAlgorithms[algStr] + if !ok { + return fmt.Errorf("unknown JWS algorithm: %s", algStr) } - if (standardHeaders.Type == "" || standardHeaders.Type == headerJwt) && !json.Valid([]byte(jwsPayload)) { + typ, err := jwsbb.HeaderGetString(headers, "typ") + if (err != nil || typ == headerJwt) && !json.Valid(jwsPayload) { return errors.New("type is JWT but payload is not JSON") } - // process payload and sign - var jwsCompact []byte - jwsCompact, err = jws.SignLiteral([]byte(jwsPayload), alg, key, jwsHeaders, bctx.Seed) + payload := jwsbb.SignBuffer(nil, inputHeaders, jwsPayload, base64.RawURLEncoding, true) + + signature, err := jwsbb.Sign(key, algStr, payload, bctx.Seed) if err != nil { return err } - return iter(ast.StringTerm(string(jwsCompact))) + jwsCompact := string(payload) + "." + base64.RawURLEncoding.EncodeToString(signature) + + return iter(ast.StringTerm(jwsCompact)) } func builtinJWTEncodeSign(bctx BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { @@ -953,9 +930,9 @@ func builtinJWTEncodeSign(bctx BuiltinContext, operands []*ast.Term, iter func(* return commonBuiltinJWTEncodeSign( bctx, - string(inputHeadersBs), - string(payloadBs), - string(signatureBs), + inputHeadersBs, + payloadBs, + signatureBs, iter, ) } @@ -973,7 +950,7 @@ func builtinJWTEncodeSignRaw(bctx BuiltinContext, operands []*ast.Term, iter fun if err != nil { return err } - return commonBuiltinJWTEncodeSign(bctx, string(inputHeaders), string(jwsPayload), string(jwkSrc), iter) + return commonBuiltinJWTEncodeSign(bctx, []byte(inputHeaders), []byte(jwsPayload), []byte(jwkSrc), iter) } // Implements full JWT decoding, validation and verification. @@ -1248,6 +1225,10 @@ func extractJSONObject(s string) (ast.Object, error) { // getInputSha returns the SHA checksum of the input func getInputSHA(input []byte, h func() hash.Hash) []byte { + if h == nil { + return input + } + hasher := h() hasher.Write(input) return hasher.Sum(nil) @@ -1320,6 +1301,7 @@ func init() { RegisterBuiltinFunc(ast.JWTVerifyES256.Name, builtinJWTVerifyES256) RegisterBuiltinFunc(ast.JWTVerifyES384.Name, builtinJWTVerifyES384) RegisterBuiltinFunc(ast.JWTVerifyES512.Name, builtinJWTVerifyES512) + RegisterBuiltinFunc(ast.JWTVerifyEdDSA.Name, builtinJWTVerifyEdDSA) RegisterBuiltinFunc(ast.JWTVerifyHS256.Name, builtinJWTVerifyHS256) RegisterBuiltinFunc(ast.JWTVerifyHS384.Name, builtinJWTVerifyHS384) RegisterBuiltinFunc(ast.JWTVerifyHS512.Name, builtinJWTVerifyHS512) diff --git a/vendor/github.com/open-policy-agent/opa/v1/types/types.go b/vendor/github.com/open-policy-agent/opa/v1/types/types.go index f8d7db1ef0a..366903f0cb7 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/types/types.go +++ b/vendor/github.com/open-policy-agent/opa/v1/types/types.go @@ -17,6 +17,22 @@ import ( "github.com/open-policy-agent/opa/v1/util" ) +var ( + // Nl represents an instance of the null type. + Nl Type = NewNull() + // B represents an instance of the boolean type. + B Type = NewBoolean() + // S represents an instance of the string type. + S Type = NewString() + // N represents an instance of the number type. + N Type = NewNumber() + // A represents the superset of all types. + A Type = NewAny() + + // Boxed set types. + SetOfAny, SetOfStr, SetOfNum Type = NewSet(A), NewSet(S), NewSet(N) +) + // Sprint returns the string representation of the type. func Sprint(x Type) string { if x == nil { @@ -50,8 +66,6 @@ func NewNull() Null { return Null{} } -var Nl Type = NewNull() - // NamedType represents a type alias with an arbitrary name and description. // This is useful for generating documentation for built-in functions. type NamedType struct { @@ -116,9 +130,6 @@ func (Null) String() string { // Boolean represents the boolean type. type Boolean struct{} -// B represents an instance of the boolean type. -var B Type = NewBoolean() - // NewBoolean returns a new Boolean type. func NewBoolean() Boolean { return Boolean{} @@ -139,9 +150,6 @@ func (t Boolean) String() string { // String represents the string type. type String struct{} -// S represents an instance of the string type. -var S Type = NewString() - // NewString returns a new String type. func NewString() String { return String{} @@ -161,9 +169,6 @@ func (String) String() string { // Number represents the number type. type Number struct{} -// N represents an instance of the number type. -var N Type = NewNumber() - // NewNumber returns a new Number type. func NewNumber() Number { return Number{} @@ -256,13 +261,6 @@ type Set struct { of Type } -// Boxed set types. -var ( - SetOfAny Type = NewSet(A) - SetOfStr Type = NewSet(S) - SetOfNum Type = NewSet(N) -) - // NewSet returns a new Set type. func NewSet(of Type) *Set { return &Set{ @@ -513,9 +511,6 @@ func mergeObjects(a, b *Object) *Object { // Any represents a dynamic type. type Any []Type -// A represents the superset of all types. -var A Type = NewAny() - // NewAny returns a new Any type. func NewAny(of ...Type) Any { sl := make(Any, len(of)) diff --git a/vendor/github.com/open-policy-agent/opa/v1/util/backoff.go b/vendor/github.com/open-policy-agent/opa/v1/util/backoff.go index 1558f0cff8c..d58af616dae 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/util/backoff.go +++ b/vendor/github.com/open-policy-agent/opa/v1/util/backoff.go @@ -17,6 +17,8 @@ func DefaultBackoff(base, maxNS float64, retries int) time.Duration { // Backoff returns a delay with an exponential backoff based on the number of // retries. Same algorithm used in gRPC. +// Note that if maxNS is smaller than base, the backoff will still be capped at +// maxNS. func Backoff(base, maxNS, jitter, factor float64, retries int) time.Duration { if retries == 0 { return 0 diff --git a/vendor/github.com/open-policy-agent/opa/v1/util/json.go b/vendor/github.com/open-policy-agent/opa/v1/util/json.go index fdb2626c786..de95ed50bfa 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/util/json.go +++ b/vendor/github.com/open-policy-agent/opa/v1/util/json.go @@ -10,6 +10,7 @@ import ( "fmt" "io" "reflect" + "strconv" "sigs.k8s.io/yaml" @@ -19,15 +20,14 @@ import ( // UnmarshalJSON parses the JSON encoded data and stores the result in the value // pointed to by x. // -// This function is intended to be used in place of the standard json.Marshal -// function when json.Number is required. +// This function is intended to be used in place of the standard [json.Marshal] +// function when [json.Number] is required. func UnmarshalJSON(bs []byte, x any) error { return unmarshalJSON(bs, x, true) } func unmarshalJSON(bs []byte, x any, ext bool) error { - buf := bytes.NewBuffer(bs) - decoder := NewJSONDecoder(buf) + decoder := NewJSONDecoder(bytes.NewBuffer(bs)) if err := decoder.Decode(x); err != nil { if handler := extension.FindExtension(".json"); handler != nil && ext { return handler(bs, x) @@ -49,8 +49,8 @@ func unmarshalJSON(bs []byte, x any, ext bool) error { // NewJSONDecoder returns a new decoder that reads from r. // -// This function is intended to be used in place of the standard json.NewDecoder -// when json.Number is required. +// This function is intended to be used in place of the standard [json.NewDecoder] +// when [json.Number] is required. func NewJSONDecoder(r io.Reader) *json.Decoder { decoder := json.NewDecoder(r) decoder.UseNumber() @@ -87,6 +87,55 @@ func MustMarshalJSON(x any) []byte { // rego.Input and inmem's Write operations. Works with both references and // values. func RoundTrip(x *any) error { + // Avoid round-tripping types that won't change as a result of + // marshalling/unmarshalling, as even for those values, round-tripping + // comes with a significant cost. + if x == nil || !NeedsRoundTrip(*x) { + return nil + } + + // For number types, we can write the json.Number representation + // directly into x without marshalling to bytes and back. + a := *x + switch v := a.(type) { + case int: + *x = json.Number(strconv.Itoa(v)) + return nil + case int8: + *x = json.Number(strconv.FormatInt(int64(v), 10)) + return nil + case int16: + *x = json.Number(strconv.FormatInt(int64(v), 10)) + return nil + case int32: + *x = json.Number(strconv.FormatInt(int64(v), 10)) + return nil + case int64: + *x = json.Number(strconv.FormatInt(v, 10)) + return nil + case uint: + *x = json.Number(strconv.FormatUint(uint64(v), 10)) + return nil + case uint8: + *x = json.Number(strconv.FormatUint(uint64(v), 10)) + return nil + case uint16: + *x = json.Number(strconv.FormatUint(uint64(v), 10)) + return nil + case uint32: + *x = json.Number(strconv.FormatUint(uint64(v), 10)) + return nil + case uint64: + *x = json.Number(strconv.FormatUint(v, 10)) + return nil + case float32: + *x = json.Number(strconv.FormatFloat(float64(v), 'f', -1, 32)) + return nil + case float64: + *x = json.Number(strconv.FormatFloat(v, 'f', -1, 64)) + return nil + } + bs, err := json.Marshal(x) if err != nil { return err @@ -94,15 +143,28 @@ func RoundTrip(x *any) error { return UnmarshalJSON(bs, x) } +// NeedsRoundTrip returns true if the value won't change as a result of +// a marshalling/unmarshalling round-trip. Since [RoundTrip] itself calls +// this you normally don't need to call this function directly, unless you +// want to make decisions based on the round-tripability of a value without +// actually doing the round-trip. +func NeedsRoundTrip(x any) bool { + switch x.(type) { + case nil, bool, string, json.Number: + return false + } + return true +} + // Reference returns a pointer to its argument unless the argument already is // a pointer. If the argument is **t, or ***t, etc, it will return *t. // // Used for preparing Go types (including pointers to structs) into values to be -// put through util.RoundTrip(). +// put through [RoundTrip]. func Reference(x any) *any { var y any rv := reflect.ValueOf(x) - if rv.Kind() == reflect.Ptr { + if rv.Kind() == reflect.Pointer { return Reference(rv.Elem().Interface()) } if rv.Kind() != reflect.Invalid { diff --git a/vendor/github.com/open-policy-agent/opa/v1/util/performance.go b/vendor/github.com/open-policy-agent/opa/v1/util/performance.go index 467fe766bbc..09a8e740112 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/util/performance.go +++ b/vendor/github.com/open-policy-agent/opa/v1/util/performance.go @@ -3,6 +3,8 @@ package util import ( "math" "slices" + "strings" + "sync" "unsafe" ) @@ -62,3 +64,77 @@ func NumDigitsUint(n uint64) int { return int(math.Log10(float64(n))) + 1 } + +// KeysCount returns the number of keys in m that satisfy predicate p. +func KeysCount[K comparable, V any](m map[K]V, p func(K) bool) int { + count := 0 + for k := range m { + if p(k) { + count++ + } + } + return count +} + +// SplitMap calls fn for each delim-separated part of text and returns a slice of the results. +// Cheaper than calling fn on strings.Split(text, delim), as it avoids allocating an intermediate slice of strings. +func SplitMap[T any](text string, delim string, fn func(string) T) []T { + before, after, found := strings.Cut(text, delim) + if !found { + return []T{fn(text)} + } + + sl := append(make([]T, 0, strings.Count(text, delim)+1), fn(before)) + for found { + before, after, found = strings.Cut(after, delim) + sl = append(sl, fn(before)) + } + + return sl +} + +// SlicePool is a pool for (pointers to) slices of type T. +// It uses sync.Pool to pool the slices, and grows them as needed. +type SlicePool[T any] struct { + pool sync.Pool +} + +// NewSlicePool creates a new SlicePool for slices of type T with the given initial length. +// This number is only a hint, as the slices will grow as needed. For best performance, store +// slices of similar lengths in the same pool. +func NewSlicePool[T any](length int) *SlicePool[T] { + return &SlicePool[T]{ + pool: sync.Pool{ + New: func() any { + s := make([]T, length) + return &s + }, + }, + } +} + +// Get returns a pointer to a slice of type T with the given length +// from the pool. The slice capacity will grow as needed to accommodate +// the requested length. The returned slice will have all its elements +// set to the zero value of T. Returns a pointer to avoid allocating. +func (sp *SlicePool[T]) Get(length int) *[]T { + s := sp.pool.Get().(*[]T) + d := *s + + if cap(d) < length { + d = slices.Grow(d, length) + } + + d = d[:length] // reslice to requested length, while keeping capacity + + clear(d) + + *s = d + + return s +} + +// Put returns a pointer to a slice of type T to the pool. +func (sp *SlicePool[T]) Put(s *[]T) { + sp.pool.Put(s) +} diff --git a/vendor/github.com/open-policy-agent/opa/v1/util/read_gzip_body.go b/vendor/github.com/open-policy-agent/opa/v1/util/read_gzip_body.go index ddffe2a4de4..92c0df8b085 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/util/read_gzip_body.go +++ b/vendor/github.com/open-policy-agent/opa/v1/util/read_gzip_body.go @@ -27,55 +27,46 @@ var gzipReaderPool = sync.Pool{ // payload size, but not an unbounded amount of memory, as was potentially // possible before. func ReadMaybeCompressedBody(r *http.Request) ([]byte, error) { - var content *bytes.Buffer - // Note(philipc): If the request body is of unknown length (such as what - // happens when 'Transfer-Encoding: chunked' is set), we have to do an - // incremental read of the body. In this case, we can't be too clever, we - // just do the best we can with whatever is streamed over to us. - // Fetch gzip payload size limit from request context. - if maxLength, ok := decoding.GetServerDecodingMaxLen(r.Context()); ok { - bs, err := io.ReadAll(io.LimitReader(r.Body, maxLength)) - if err != nil { - return bs, err - } - content = bytes.NewBuffer(bs) - } else { - // Read content from the request body into a buffer of known size. - content = bytes.NewBuffer(make([]byte, 0, r.ContentLength)) - if _, err := io.CopyN(content, r.Body, r.ContentLength); err != nil { - return content.Bytes(), err - } + length := r.ContentLength + if maxLenConf, ok := decoding.GetServerDecodingMaxLen(r.Context()); ok { + length = maxLenConf + } + + content, err := io.ReadAll(io.LimitReader(r.Body, length)) + if err != nil { + return nil, err } - // Decompress gzip content by reading from the buffer. if strings.Contains(r.Header.Get("Content-Encoding"), "gzip") { - // Fetch gzip payload size limit from request context. gzipMaxLength, _ := decoding.GetServerDecodingGzipMaxLen(r.Context()) // Note(philipc): The last 4 bytes of a well-formed gzip blob will // always be a little-endian uint32, representing the decompressed // content size, modulo 2^32. We validate that the size is safe, // earlier in DecodingLimitHandler. - sizeTrailerField := binary.LittleEndian.Uint32(content.Bytes()[content.Len()-4:]) - if sizeTrailerField > uint32(gzipMaxLength) { - return content.Bytes(), errors.New("gzip payload too large") + sizeDecompressed := int64(binary.LittleEndian.Uint32(content[len(content)-4:])) + if sizeDecompressed > gzipMaxLength { + return nil, errors.New("gzip payload too large") } - // Pull a gzip decompressor from the pool, and assign it to the current - // buffer, using Reset(). Later, return it back to the pool for another - // request to use. + gzReader := gzipReaderPool.Get().(*gzip.Reader) - if err := gzReader.Reset(content); err != nil { + defer func() { + gzReader.Close() + gzipReaderPool.Put(gzReader) + }() + + if err := gzReader.Reset(bytes.NewReader(content)); err != nil { return nil, err } - defer gzReader.Close() - defer gzipReaderPool.Put(gzReader) - decompressedContent := bytes.NewBuffer(make([]byte, 0, sizeTrailerField)) - if _, err := io.CopyN(decompressedContent, gzReader, int64(sizeTrailerField)); err != nil { - return decompressedContent.Bytes(), err + + decompressed := bytes.NewBuffer(make([]byte, 0, sizeDecompressed)) + if _, err = io.CopyN(decompressed, gzReader, sizeDecompressed); err != nil { + return nil, err } - return decompressedContent.Bytes(), nil + + return decompressed.Bytes(), nil } // Request was not compressed; return the content bytes. - return content.Bytes(), nil + return content, nil } diff --git a/vendor/github.com/open-policy-agent/opa/v1/version/version.go b/vendor/github.com/open-policy-agent/opa/v1/version/version.go index ab229e76fea..4b9bc024216 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/version/version.go +++ b/vendor/github.com/open-policy-agent/opa/v1/version/version.go @@ -10,7 +10,7 @@ import ( "runtime/debug" ) -var Version = "1.6.0" +var Version = "1.10.0" // GoVersion is the version of Go this was built with var GoVersion = runtime.Version() diff --git a/vendor/github.com/segmentio/asm/LICENSE b/vendor/github.com/segmentio/asm/LICENSE new file mode 100644 index 00000000000..29e1ab6b05f --- /dev/null +++ b/vendor/github.com/segmentio/asm/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 Segment + +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/segmentio/asm/base64/base64.go b/vendor/github.com/segmentio/asm/base64/base64.go new file mode 100644 index 00000000000..dd2128d4a95 --- /dev/null +++ b/vendor/github.com/segmentio/asm/base64/base64.go @@ -0,0 +1,67 @@ +package base64 + +import ( + "encoding/base64" +) + +const ( + StdPadding rune = base64.StdPadding + NoPadding rune = base64.NoPadding + + encodeStd = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" + encodeURL = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_" + encodeIMAP = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+," + + letterRange = int8('Z' - 'A' + 1) +) + +// StdEncoding is the standard base64 encoding, as defined in RFC 4648. +var StdEncoding = NewEncoding(encodeStd) + +// URLEncoding is the alternate base64 encoding defined in RFC 4648. +// It is typically used in URLs and file names. +var URLEncoding = NewEncoding(encodeURL) + +// RawStdEncoding is the standard unpadded base64 encoding defined in RFC 4648 section 3.2. +// This is the same as StdEncoding but omits padding characters. +var RawStdEncoding = StdEncoding.WithPadding(NoPadding) + +// RawURLEncoding is the unpadded alternate base64 encoding defined in RFC 4648. +// This is the same as URLEncoding but omits padding characters. +var RawURLEncoding = URLEncoding.WithPadding(NoPadding) + +// NewEncoding returns a new padded Encoding defined by the given alphabet, +// which must be a 64-byte string that does not contain the padding character +// or CR / LF ('\r', '\n'). Unlike the standard library, the encoding alphabet +// cannot be abitrary, and it must follow one of the know standard encoding +// variants. +// +// Required alphabet values: +// * [0,26): characters 'A'..'Z' +// * [26,52): characters 'a'..'z' +// * [52,62): characters '0'..'9' +// Flexible alphabet value options: +// * RFC 4648, RFC 1421, RFC 2045, RFC 2152, RFC 4880: '+' and '/' +// * RFC 4648 URI: '-' and '_' +// * RFC 3501: '+' and ',' +// +// The resulting Encoding uses the default padding character ('='), which may +// be changed or disabled via WithPadding. The padding characters is urestricted, +// but it must be a character outside of the encoder alphabet. +func NewEncoding(encoder string) *Encoding { + if len(encoder) != 64 { + panic("encoding alphabet is not 64-bytes long") + } + + if _, ok := allowedEncoding[encoder]; !ok { + panic("non-standard encoding alphabets are not supported") + } + + return newEncoding(encoder) +} + +var allowedEncoding = map[string]struct{}{ + encodeStd: {}, + encodeURL: {}, + encodeIMAP: {}, +} diff --git a/vendor/github.com/segmentio/asm/base64/base64_amd64.go b/vendor/github.com/segmentio/asm/base64/base64_amd64.go new file mode 100644 index 00000000000..4136098eaa4 --- /dev/null +++ b/vendor/github.com/segmentio/asm/base64/base64_amd64.go @@ -0,0 +1,78 @@ +//go:build amd64 && !purego +// +build amd64,!purego + +package base64 + +import ( + "encoding/base64" + + "github.com/segmentio/asm/cpu" + "github.com/segmentio/asm/cpu/x86" +) + +const ( + encLutSize = 32 + decLutSize = 48 + minEncodeLen = 28 + minDecodeLen = 45 +) + +func newEncoding(encoder string) *Encoding { + e := &Encoding{base: base64.NewEncoding(encoder)} + if cpu.X86.Has(x86.AVX2) { + e.enableEncodeAVX2(encoder) + e.enableDecodeAVX2(encoder) + } + return e +} + +func (e *Encoding) enableEncodeAVX2(encoder string) { + // Translate values 0..63 to the Base64 alphabet. There are five sets: + // + // From To Add Index Example + // [0..25] [65..90] +65 0 ABCDEFGHIJKLMNOPQRSTUVWXYZ + // [26..51] [97..122] +71 1 abcdefghijklmnopqrstuvwxyz + // [52..61] [48..57] -4 [2..11] 0123456789 + // [62] [43] -19 12 + + // [63] [47] -16 13 / + tab := [encLutSize]int8{int8(encoder[0]), int8(encoder[letterRange]) - letterRange} + for i, ch := range encoder[2*letterRange:] { + tab[2+i] = int8(ch) - 2*letterRange - int8(i) + } + + e.enc = encodeAVX2 + e.enclut = tab +} + +func (e *Encoding) enableDecodeAVX2(encoder string) { + c62, c63 := int8(encoder[62]), int8(encoder[63]) + url := c63 == '_' + if url { + c63 = '/' + } + + // Translate values from the Base64 alphabet using five sets. Values outside + // of these ranges are considered invalid: + // + // From To Add Index Example + // [47] [63] +16 1 / + // [43] [62] +19 2 + + // [48..57] [52..61] +4 3 0123456789 + // [65..90] [0..25] -65 4,5 ABCDEFGHIJKLMNOPQRSTUVWXYZ + // [97..122] [26..51] -71 6,7 abcdefghijklmnopqrstuvwxyz + tab := [decLutSize]int8{ + 0, 63 - c63, 62 - c62, 4, -65, -65, -71, -71, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x15, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x13, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, + } + tab[(c62&15)+16] = 0x1A + tab[(c63&15)+16] = 0x1A + + if url { + e.dec = decodeAVX2URI + } else { + e.dec = decodeAVX2 + } + e.declut = tab +} diff --git a/vendor/github.com/segmentio/asm/base64/base64_arm64.go b/vendor/github.com/segmentio/asm/base64/base64_arm64.go new file mode 100644 index 00000000000..276f3002879 --- /dev/null +++ b/vendor/github.com/segmentio/asm/base64/base64_arm64.go @@ -0,0 +1,42 @@ +//go:build arm64 && !purego +// +build arm64,!purego + +package base64 + +import ( + "encoding/base64" +) + +const ( + encLutSize = 16 + decLutSize = 2 + minEncodeLen = 16 * 3 + minDecodeLen = 8 * 4 +) + +func newEncoding(encoder string) *Encoding { + e := &Encoding{base: base64.NewEncoding(encoder)} + e.enableEncodeARM64(encoder) + e.enableDecodeARM64(encoder) + return e +} + +func (e *Encoding) enableEncodeARM64(encoder string) { + c62, c63 := int8(encoder[62]), int8(encoder[63]) + tab := [encLutSize]int8{ + 'a' - 26, '0' - 52, '0' - 52, '0' - 52, '0' - 52, '0' - 52, '0' - 52, '0' - 52, + '0' - 52, '0' - 52, '0' - 52, c62 - 62, c63 - 63, 'A', 0, 0, + } + + e.enc = encodeARM64 + e.enclut = tab +} + +func (e *Encoding) enableDecodeARM64(encoder string) { + if encoder == encodeStd { + e.dec = decodeStdARM64 + } else { + e.dec = decodeARM64 + } + e.declut = [decLutSize]int8{int8(encoder[62]), int8(encoder[63])} +} diff --git a/vendor/github.com/segmentio/asm/base64/base64_asm.go b/vendor/github.com/segmentio/asm/base64/base64_asm.go new file mode 100644 index 00000000000..f9afadd7f26 --- /dev/null +++ b/vendor/github.com/segmentio/asm/base64/base64_asm.go @@ -0,0 +1,94 @@ +//go:build (amd64 || arm64) && !purego +// +build amd64 arm64 +// +build !purego + +package base64 + +import ( + "encoding/base64" + + "github.com/segmentio/asm/internal/unsafebytes" +) + +// An Encoding is a radix 64 encoding/decoding scheme, defined by a +// 64-character alphabet. +type Encoding struct { + enc func(dst []byte, src []byte, lut *int8) (int, int) + enclut [encLutSize]int8 + + dec func(dst []byte, src []byte, lut *int8) (int, int) + declut [decLutSize]int8 + + base *base64.Encoding +} + +// WithPadding creates a duplicate Encoding updated with a specified padding +// character, or NoPadding to disable padding. The padding character must not +// be contained in the encoding alphabet, must not be '\r' or '\n', and must +// be no greater than '\xFF'. +func (enc Encoding) WithPadding(padding rune) *Encoding { + enc.base = enc.base.WithPadding(padding) + return &enc +} + +// Strict creates a duplicate encoding updated with strict decoding enabled. +// This requires that trailing padding bits are zero. +func (enc Encoding) Strict() *Encoding { + enc.base = enc.base.Strict() + return &enc +} + +// Encode encodes src using the defined encoding alphabet. +// This will write EncodedLen(len(src)) bytes to dst. +func (enc *Encoding) Encode(dst, src []byte) { + if len(src) >= minEncodeLen && enc.enc != nil { + d, s := enc.enc(dst, src, &enc.enclut[0]) + dst = dst[d:] + src = src[s:] + } + enc.base.Encode(dst, src) +} + +// Encode encodes src using the encoding enc, writing +// EncodedLen(len(src)) bytes to dst. +func (enc *Encoding) EncodeToString(src []byte) string { + buf := make([]byte, enc.base.EncodedLen(len(src))) + enc.Encode(buf, src) + return string(buf) +} + +// EncodedLen calculates the base64-encoded byte length for a message +// of length n. +func (enc *Encoding) EncodedLen(n int) int { + return enc.base.EncodedLen(n) +} + +// Decode decodes src using the defined encoding alphabet. +// This will write DecodedLen(len(src)) bytes to dst and return the number of +// bytes written. +func (enc *Encoding) Decode(dst, src []byte) (n int, err error) { + var d, s int + if len(src) >= minDecodeLen && enc.dec != nil { + d, s = enc.dec(dst, src, &enc.declut[0]) + dst = dst[d:] + src = src[s:] + } + n, err = enc.base.Decode(dst, src) + n += d + return +} + +// DecodeString decodes the base64 encoded string s, returns the decoded +// value as bytes. +func (enc *Encoding) DecodeString(s string) ([]byte, error) { + src := unsafebytes.BytesOf(s) + dst := make([]byte, enc.base.DecodedLen(len(s))) + n, err := enc.Decode(dst, src) + return dst[:n], err +} + +// DecodedLen calculates the decoded byte length for a base64-encoded message +// of length n. +func (enc *Encoding) DecodedLen(n int) int { + return enc.base.DecodedLen(n) +} diff --git a/vendor/github.com/segmentio/asm/base64/base64_default.go b/vendor/github.com/segmentio/asm/base64/base64_default.go new file mode 100644 index 00000000000..1720da5ca70 --- /dev/null +++ b/vendor/github.com/segmentio/asm/base64/base64_default.go @@ -0,0 +1,14 @@ +//go:build purego || !(amd64 || arm64) +// +build purego !amd64,!arm64 + +package base64 + +import "encoding/base64" + +// An Encoding is a radix 64 encoding/decoding scheme, defined by a +// 64-character alphabet. +type Encoding = base64.Encoding + +func newEncoding(encoder string) *Encoding { + return base64.NewEncoding(encoder) +} diff --git a/vendor/github.com/segmentio/asm/base64/decode_amd64.go b/vendor/github.com/segmentio/asm/base64/decode_amd64.go new file mode 100644 index 00000000000..e85bf6a9256 --- /dev/null +++ b/vendor/github.com/segmentio/asm/base64/decode_amd64.go @@ -0,0 +1,9 @@ +// Code generated by command: go run decode_asm.go -pkg base64 -out ../base64/decode_amd64.s -stubs ../base64/decode_amd64.go. DO NOT EDIT. + +//go:build !purego + +package base64 + +func decodeAVX2(dst []byte, src []byte, lut *int8) (int, int) + +func decodeAVX2URI(dst []byte, src []byte, lut *int8) (int, int) diff --git a/vendor/github.com/segmentio/asm/base64/decode_amd64.s b/vendor/github.com/segmentio/asm/base64/decode_amd64.s new file mode 100644 index 00000000000..ade5442c3b6 --- /dev/null +++ b/vendor/github.com/segmentio/asm/base64/decode_amd64.s @@ -0,0 +1,143 @@ +// Code generated by command: go run decode_asm.go -pkg base64 -out ../base64/decode_amd64.s -stubs ../base64/decode_amd64.go. DO NOT EDIT. + +//go:build !purego + +#include "textflag.h" + +DATA b64_dec_lut_hi<>+0(SB)/8, $0x0804080402011010 +DATA b64_dec_lut_hi<>+8(SB)/8, $0x1010101010101010 +DATA b64_dec_lut_hi<>+16(SB)/8, $0x0804080402011010 +DATA b64_dec_lut_hi<>+24(SB)/8, $0x1010101010101010 +GLOBL b64_dec_lut_hi<>(SB), RODATA|NOPTR, $32 + +DATA b64_dec_madd1<>+0(SB)/8, $0x0140014001400140 +DATA b64_dec_madd1<>+8(SB)/8, $0x0140014001400140 +DATA b64_dec_madd1<>+16(SB)/8, $0x0140014001400140 +DATA b64_dec_madd1<>+24(SB)/8, $0x0140014001400140 +GLOBL b64_dec_madd1<>(SB), RODATA|NOPTR, $32 + +DATA b64_dec_madd2<>+0(SB)/8, $0x0001100000011000 +DATA b64_dec_madd2<>+8(SB)/8, $0x0001100000011000 +DATA b64_dec_madd2<>+16(SB)/8, $0x0001100000011000 +DATA b64_dec_madd2<>+24(SB)/8, $0x0001100000011000 +GLOBL b64_dec_madd2<>(SB), RODATA|NOPTR, $32 + +DATA b64_dec_shuf_lo<>+0(SB)/8, $0x0000000000000000 +DATA b64_dec_shuf_lo<>+8(SB)/8, $0x0600010200000000 +GLOBL b64_dec_shuf_lo<>(SB), RODATA|NOPTR, $16 + +DATA b64_dec_shuf<>+0(SB)/8, $0x090a040506000102 +DATA b64_dec_shuf<>+8(SB)/8, $0x000000000c0d0e08 +DATA b64_dec_shuf<>+16(SB)/8, $0x0c0d0e08090a0405 +DATA b64_dec_shuf<>+24(SB)/8, $0x0000000000000000 +GLOBL b64_dec_shuf<>(SB), RODATA|NOPTR, $32 + +// func decodeAVX2(dst []byte, src []byte, lut *int8) (int, int) +// Requires: AVX, AVX2, SSE4.1 +TEXT ·decodeAVX2(SB), NOSPLIT, $0-72 + MOVQ dst_base+0(FP), AX + MOVQ src_base+24(FP), DX + MOVQ lut+48(FP), SI + MOVQ src_len+32(FP), DI + MOVB $0x2f, CL + PINSRB $0x00, CX, X8 + VPBROADCASTB X8, Y8 + XORQ CX, CX + XORQ BX, BX + VPXOR Y7, Y7, Y7 + VPERMQ $0x44, (SI), Y6 + VPERMQ $0x44, 16(SI), Y4 + VMOVDQA b64_dec_lut_hi<>+0(SB), Y5 + +loop: + VMOVDQU (DX)(BX*1), Y0 + VPSRLD $0x04, Y0, Y2 + VPAND Y8, Y0, Y3 + VPSHUFB Y3, Y4, Y3 + VPAND Y8, Y2, Y2 + VPSHUFB Y2, Y5, Y9 + VPTEST Y9, Y3 + JNE done + VPCMPEQB Y8, Y0, Y3 + VPADDB Y3, Y2, Y2 + VPSHUFB Y2, Y6, Y2 + VPADDB Y0, Y2, Y0 + VPMADDUBSW b64_dec_madd1<>+0(SB), Y0, Y0 + VPMADDWD b64_dec_madd2<>+0(SB), Y0, Y0 + VEXTRACTI128 $0x01, Y0, X1 + VPSHUFB b64_dec_shuf_lo<>+0(SB), X1, X1 + VPSHUFB b64_dec_shuf<>+0(SB), Y0, Y0 + VPBLENDD $0x08, Y1, Y0, Y1 + VPBLENDD $0xc0, Y7, Y1, Y1 + VMOVDQU Y1, (AX)(CX*1) + ADDQ $0x18, CX + ADDQ $0x20, BX + SUBQ $0x20, DI + CMPQ DI, $0x2d + JB done + JMP loop + +done: + MOVQ CX, ret+56(FP) + MOVQ BX, ret1+64(FP) + VZEROUPPER + RET + +// func decodeAVX2URI(dst []byte, src []byte, lut *int8) (int, int) +// Requires: AVX, AVX2, SSE4.1 +TEXT ·decodeAVX2URI(SB), NOSPLIT, $0-72 + MOVB $0x2f, AL + PINSRB $0x00, AX, X0 + VPBROADCASTB X0, Y0 + MOVB $0x5f, AL + PINSRB $0x00, AX, X1 + VPBROADCASTB X1, Y1 + MOVQ dst_base+0(FP), AX + MOVQ src_base+24(FP), DX + MOVQ lut+48(FP), SI + MOVQ src_len+32(FP), DI + MOVB $0x2f, CL + PINSRB $0x00, CX, X10 + VPBROADCASTB X10, Y10 + XORQ CX, CX + XORQ BX, BX + VPXOR Y9, Y9, Y9 + VPERMQ $0x44, (SI), Y8 + VPERMQ $0x44, 16(SI), Y6 + VMOVDQA b64_dec_lut_hi<>+0(SB), Y7 + +loop: + VMOVDQU (DX)(BX*1), Y2 + VPCMPEQB Y2, Y1, Y4 + VPBLENDVB Y4, Y0, Y2, Y2 + VPSRLD $0x04, Y2, Y4 + VPAND Y10, Y2, Y5 + VPSHUFB Y5, Y6, Y5 + VPAND Y10, Y4, Y4 + VPSHUFB Y4, Y7, Y11 + VPTEST Y11, Y5 + JNE done + VPCMPEQB Y10, Y2, Y5 + VPADDB Y5, Y4, Y4 + VPSHUFB Y4, Y8, Y4 + VPADDB Y2, Y4, Y2 + VPMADDUBSW b64_dec_madd1<>+0(SB), Y2, Y2 + VPMADDWD b64_dec_madd2<>+0(SB), Y2, Y2 + VEXTRACTI128 $0x01, Y2, X3 + VPSHUFB b64_dec_shuf_lo<>+0(SB), X3, X3 + VPSHUFB b64_dec_shuf<>+0(SB), Y2, Y2 + VPBLENDD $0x08, Y3, Y2, Y3 + VPBLENDD $0xc0, Y9, Y3, Y3 + VMOVDQU Y3, (AX)(CX*1) + ADDQ $0x18, CX + ADDQ $0x20, BX + SUBQ $0x20, DI + CMPQ DI, $0x2d + JB done + JMP loop + +done: + MOVQ CX, ret+56(FP) + MOVQ BX, ret1+64(FP) + VZEROUPPER + RET diff --git a/vendor/github.com/segmentio/asm/base64/decode_arm64.go b/vendor/github.com/segmentio/asm/base64/decode_arm64.go new file mode 100644 index 00000000000..d44baa1dc52 --- /dev/null +++ b/vendor/github.com/segmentio/asm/base64/decode_arm64.go @@ -0,0 +1,7 @@ +//go:build !purego +// +build !purego + +package base64 + +func decodeARM64(dst []byte, src []byte, lut *int8) (int, int) +func decodeStdARM64(dst []byte, src []byte, lut *int8) (int, int) diff --git a/vendor/github.com/segmentio/asm/base64/decode_arm64.s b/vendor/github.com/segmentio/asm/base64/decode_arm64.s new file mode 100644 index 00000000000..4374d5ce171 --- /dev/null +++ b/vendor/github.com/segmentio/asm/base64/decode_arm64.s @@ -0,0 +1,203 @@ +#include "textflag.h" + +#define LOAD_ARGS() \ + MOVD dst_base+0(FP), R0; \ + MOVD R0, R3; \ + MOVD src_base+24(FP), R1; \ + MOVD R1, R4; \ + MOVD src_len+32(FP), R2; \ + BIC $31, R2, R2; \ + ADD R1, R2, R2 + +#define LOAD_ARG_LUT() \ + MOVD lut+48(FP), R5; \ + VLD2R (R5), [V0.B16, V1.B16] + +#define LOAD_CONST_LUT() \ + MOVD $·mask_lut(SB), R6; \ + MOVD $·bpos_lut(SB), R7; \ + MOVD $·shft_lut(SB), R8; \ + VLD1 (R6), [V2.B16]; \ + VLD1 (R7), [V3.B16]; \ + VLD1 (R8), [V4.B16]; \ + VMOVI $43, V5.B8; \ + VMOVI $47, V6.B8; \ + VMOVI $15, V7.B8; \ + VMOVI $16, V8.B8; \ + +#define LOAD_INPUT() \ + VLD4 (R4), [V10.B8, V11.B8, V12.B8, V13.B8] + +#define COMPARE_INPUT(v) \ + VCMEQ V10.B8, v.B8, V14.B8; \ + VCMEQ V11.B8, v.B8, V15.B8; \ + VCMEQ V12.B8, v.B8, V16.B8; \ + VCMEQ V13.B8, v.B8, V17.B8 + +#define UPDATE_INPUT(v) \ + VBIT V14.B8, v.B8, V10.B8; \ + VBIT V15.B8, v.B8, V11.B8; \ + VBIT V16.B8, v.B8, V12.B8; \ + VBIT V17.B8, v.B8, V13.B8 + +#define DECODE_INPUT(goto_err) \ + /* Create hi/lo nibles */ \ + VUSHR $4, V10.B8, V18.B8; \ + VUSHR $4, V11.B8, V19.B8; \ + VUSHR $4, V12.B8, V20.B8; \ + VUSHR $4, V13.B8, V21.B8; \ + VAND V7.B8, V10.B8, V22.B8; \ + VAND V7.B8, V11.B8, V23.B8; \ + VAND V7.B8, V12.B8, V24.B8; \ + VAND V7.B8, V13.B8, V25.B8; \ + /* Detect invalid input characters */ \ + VTBL V22.B8, [V2.B8], V22.B8; \ + VTBL V23.B8, [V2.B8], V23.B8; \ + VTBL V24.B8, [V2.B8], V24.B8; \ + VTBL V25.B8, [V2.B8], V25.B8; \ + VTBL V18.B8, [V3.B8], V26.B8; \ + VTBL V19.B8, [V3.B8], V27.B8; \ + VTBL V20.B8, [V3.B8], V28.B8; \ + VTBL V21.B8, [V3.B8], V29.B8; \ + VAND V22.B8, V26.B8, V26.B8; \ + VAND V23.B8, V27.B8, V27.B8; \ + VAND V24.B8, V28.B8, V28.B8; \ + VAND V25.B8, V29.B8, V29.B8; \ + WORD $0x0e209b5a /* VCMEQ $0, V26.B8, V26.B8 */; \ + WORD $0x0e209b7b /* VCMEQ $0, V27.B8, V27.B8 */; \ + WORD $0x0e209b9c /* VCMEQ $0, V28.B8, V28.B8 */; \ + WORD $0x0e209bbd /* VCMEQ $0, V29.B8, V29.B8 */; \ + VORR V26.B8, V27.B8, V26.B8; \ + VORR V28.B8, V29.B8, V28.B8; \ + VORR V26.B8, V28.B8, V26.B8; \ + VMOV V26.D[0], R5; \ + VMOV V26.D[1], R6; \ + ORR R6, R5; \ + CBNZ R5, goto_err; \ + /* Shift hi nibles */ \ + VTBL V18.B8, [V4.B8], V18.B8; \ + VTBL V19.B8, [V4.B8], V19.B8; \ + VTBL V20.B8, [V4.B8], V20.B8; \ + VTBL V21.B8, [V4.B8], V21.B8; \ + VBIT V14.B8, V8.B8, V18.B8; \ + VBIT V15.B8, V8.B8, V19.B8; \ + VBIT V16.B8, V8.B8, V20.B8; \ + VBIT V17.B8, V8.B8, V21.B8; \ + /* Combine results */ \ + VADD V18.B8, V10.B8, V10.B8; \ + VADD V19.B8, V11.B8, V11.B8; \ + VADD V20.B8, V12.B8, V12.B8; \ + VADD V21.B8, V13.B8, V13.B8; \ + VUSHR $4, V11.B8, V14.B8; \ + VUSHR $2, V12.B8, V15.B8; \ + VSHL $2, V10.B8, V10.B8; \ + VSHL $4, V11.B8, V11.B8; \ + VSHL $6, V12.B8, V12.B8; \ + VORR V10.B8, V14.B8, V16.B8; \ + VORR V11.B8, V15.B8, V17.B8; \ + VORR V12.B8, V13.B8, V18.B8 + +#define ADVANCE_LOOP(goto_loop) \ + VST3.P [V16.B8, V17.B8, V18.B8], 24(R3); \ + ADD $32, R4; \ + CMP R4, R2; \ + BGT goto_loop + +#define RETURN() \ + SUB R0, R3; \ + SUB R1, R4; \ + MOVD R3, ret+56(FP); \ + MOVD R4, ret1+64(FP); \ + RET + + +// func decodeARM64(dst []byte, src []byte, lut *int8) (int, int) +TEXT ·decodeARM64(SB),NOSPLIT,$0-72 + LOAD_ARGS() + LOAD_ARG_LUT() + LOAD_CONST_LUT() + +loop: + LOAD_INPUT() + + // Compare and normalize the 63rd and 64th characters + COMPARE_INPUT(V0) + UPDATE_INPUT(V5) + COMPARE_INPUT(V1) + UPDATE_INPUT(V6) + + DECODE_INPUT(done) // Detect invalid input characters + ADVANCE_LOOP(loop) // Store results and continue + +done: + RETURN() + + +// func decodeStdARM64(dst []byte, src []byte, lut *int8) (int, int) +TEXT ·decodeStdARM64(SB),NOSPLIT,$0-72 + LOAD_ARGS() + LOAD_CONST_LUT() + +loop: + LOAD_INPUT() + COMPARE_INPUT(V6) // Compare to '+' + DECODE_INPUT(done) // Detect invalid input characters + ADVANCE_LOOP(loop) // Store results and continue + +done: + RETURN() + + +DATA ·mask_lut+0x00(SB)/1, $0xa8 +DATA ·mask_lut+0x01(SB)/1, $0xf8 +DATA ·mask_lut+0x02(SB)/1, $0xf8 +DATA ·mask_lut+0x03(SB)/1, $0xf8 +DATA ·mask_lut+0x04(SB)/1, $0xf8 +DATA ·mask_lut+0x05(SB)/1, $0xf8 +DATA ·mask_lut+0x06(SB)/1, $0xf8 +DATA ·mask_lut+0x07(SB)/1, $0xf8 +DATA ·mask_lut+0x08(SB)/1, $0xf8 +DATA ·mask_lut+0x09(SB)/1, $0xf8 +DATA ·mask_lut+0x0a(SB)/1, $0xf0 +DATA ·mask_lut+0x0b(SB)/1, $0x54 +DATA ·mask_lut+0x0c(SB)/1, $0x50 +DATA ·mask_lut+0x0d(SB)/1, $0x50 +DATA ·mask_lut+0x0e(SB)/1, $0x50 +DATA ·mask_lut+0x0f(SB)/1, $0x54 +GLOBL ·mask_lut(SB), NOPTR|RODATA, $16 + +DATA ·bpos_lut+0x00(SB)/1, $0x01 +DATA ·bpos_lut+0x01(SB)/1, $0x02 +DATA ·bpos_lut+0x02(SB)/1, $0x04 +DATA ·bpos_lut+0x03(SB)/1, $0x08 +DATA ·bpos_lut+0x04(SB)/1, $0x10 +DATA ·bpos_lut+0x05(SB)/1, $0x20 +DATA ·bpos_lut+0x06(SB)/1, $0x40 +DATA ·bpos_lut+0x07(SB)/1, $0x80 +DATA ·bpos_lut+0x08(SB)/1, $0x00 +DATA ·bpos_lut+0x09(SB)/1, $0x00 +DATA ·bpos_lut+0x0a(SB)/1, $0x00 +DATA ·bpos_lut+0x0b(SB)/1, $0x00 +DATA ·bpos_lut+0x0c(SB)/1, $0x00 +DATA ·bpos_lut+0x0d(SB)/1, $0x00 +DATA ·bpos_lut+0x0e(SB)/1, $0x00 +DATA ·bpos_lut+0x0f(SB)/1, $0x00 +GLOBL ·bpos_lut(SB), NOPTR|RODATA, $16 + +DATA ·shft_lut+0x00(SB)/1, $0x00 +DATA ·shft_lut+0x01(SB)/1, $0x00 +DATA ·shft_lut+0x02(SB)/1, $0x13 +DATA ·shft_lut+0x03(SB)/1, $0x04 +DATA ·shft_lut+0x04(SB)/1, $0xbf +DATA ·shft_lut+0x05(SB)/1, $0xbf +DATA ·shft_lut+0x06(SB)/1, $0xb9 +DATA ·shft_lut+0x07(SB)/1, $0xb9 +DATA ·shft_lut+0x08(SB)/1, $0x00 +DATA ·shft_lut+0x09(SB)/1, $0x00 +DATA ·shft_lut+0x0a(SB)/1, $0x00 +DATA ·shft_lut+0x0b(SB)/1, $0x00 +DATA ·shft_lut+0x0c(SB)/1, $0x00 +DATA ·shft_lut+0x0d(SB)/1, $0x00 +DATA ·shft_lut+0x0e(SB)/1, $0x00 +DATA ·shft_lut+0x0f(SB)/1, $0x00 +GLOBL ·shft_lut(SB), NOPTR|RODATA, $16 diff --git a/vendor/github.com/segmentio/asm/base64/encode_amd64.go b/vendor/github.com/segmentio/asm/base64/encode_amd64.go new file mode 100644 index 00000000000..a83c81f1571 --- /dev/null +++ b/vendor/github.com/segmentio/asm/base64/encode_amd64.go @@ -0,0 +1,7 @@ +// Code generated by command: go run encode_asm.go -pkg base64 -out ../base64/encode_amd64.s -stubs ../base64/encode_amd64.go. DO NOT EDIT. + +//go:build !purego + +package base64 + +func encodeAVX2(dst []byte, src []byte, lut *int8) (int, int) diff --git a/vendor/github.com/segmentio/asm/base64/encode_amd64.s b/vendor/github.com/segmentio/asm/base64/encode_amd64.s new file mode 100644 index 00000000000..6797c977e88 --- /dev/null +++ b/vendor/github.com/segmentio/asm/base64/encode_amd64.s @@ -0,0 +1,87 @@ +// Code generated by command: go run encode_asm.go -pkg base64 -out ../base64/encode_amd64.s -stubs ../base64/encode_amd64.go. DO NOT EDIT. + +//go:build !purego + +#include "textflag.h" + +// func encodeAVX2(dst []byte, src []byte, lut *int8) (int, int) +// Requires: AVX, AVX2, SSE4.1 +TEXT ·encodeAVX2(SB), NOSPLIT, $0-72 + MOVQ dst_base+0(FP), AX + MOVQ src_base+24(FP), DX + MOVQ lut+48(FP), SI + MOVQ src_len+32(FP), DI + MOVB $0x33, CL + PINSRB $0x00, CX, X4 + VPBROADCASTB X4, Y4 + MOVB $0x19, CL + PINSRB $0x00, CX, X5 + VPBROADCASTB X5, Y5 + XORQ CX, CX + XORQ BX, BX + + // Load the 16-byte LUT into both lanes of the register + VPERMQ $0x44, (SI), Y3 + + // Load the first block using a mask to avoid potential fault + VMOVDQU b64_enc_load<>+0(SB), Y0 + VPMASKMOVD -4(DX)(BX*1), Y0, Y0 + +loop: + VPSHUFB b64_enc_shuf<>+0(SB), Y0, Y0 + VPAND b64_enc_mask1<>+0(SB), Y0, Y1 + VPSLLW $0x08, Y1, Y2 + VPSLLW $0x04, Y1, Y1 + VPBLENDW $0xaa, Y2, Y1, Y2 + VPAND b64_enc_mask2<>+0(SB), Y0, Y1 + VPMULHUW b64_enc_mult<>+0(SB), Y1, Y0 + VPOR Y0, Y2, Y0 + VPSUBUSB Y4, Y0, Y1 + VPCMPGTB Y5, Y0, Y2 + VPSUBB Y2, Y1, Y1 + VPSHUFB Y1, Y3, Y1 + VPADDB Y0, Y1, Y0 + VMOVDQU Y0, (AX)(CX*1) + ADDQ $0x20, CX + ADDQ $0x18, BX + SUBQ $0x18, DI + CMPQ DI, $0x20 + JB done + VMOVDQU -4(DX)(BX*1), Y0 + JMP loop + +done: + MOVQ CX, ret+56(FP) + MOVQ BX, ret1+64(FP) + VZEROUPPER + RET + +DATA b64_enc_load<>+0(SB)/8, $0x8000000000000000 +DATA b64_enc_load<>+8(SB)/8, $0x8000000080000000 +DATA b64_enc_load<>+16(SB)/8, $0x8000000080000000 +DATA b64_enc_load<>+24(SB)/8, $0x8000000080000000 +GLOBL b64_enc_load<>(SB), RODATA|NOPTR, $32 + +DATA b64_enc_shuf<>+0(SB)/8, $0x0809070805060405 +DATA b64_enc_shuf<>+8(SB)/8, $0x0e0f0d0e0b0c0a0b +DATA b64_enc_shuf<>+16(SB)/8, $0x0405030401020001 +DATA b64_enc_shuf<>+24(SB)/8, $0x0a0b090a07080607 +GLOBL b64_enc_shuf<>(SB), RODATA|NOPTR, $32 + +DATA b64_enc_mask1<>+0(SB)/8, $0x003f03f0003f03f0 +DATA b64_enc_mask1<>+8(SB)/8, $0x003f03f0003f03f0 +DATA b64_enc_mask1<>+16(SB)/8, $0x003f03f0003f03f0 +DATA b64_enc_mask1<>+24(SB)/8, $0x003f03f0003f03f0 +GLOBL b64_enc_mask1<>(SB), RODATA|NOPTR, $32 + +DATA b64_enc_mask2<>+0(SB)/8, $0x0fc0fc000fc0fc00 +DATA b64_enc_mask2<>+8(SB)/8, $0x0fc0fc000fc0fc00 +DATA b64_enc_mask2<>+16(SB)/8, $0x0fc0fc000fc0fc00 +DATA b64_enc_mask2<>+24(SB)/8, $0x0fc0fc000fc0fc00 +GLOBL b64_enc_mask2<>(SB), RODATA|NOPTR, $32 + +DATA b64_enc_mult<>+0(SB)/8, $0x0400004004000040 +DATA b64_enc_mult<>+8(SB)/8, $0x0400004004000040 +DATA b64_enc_mult<>+16(SB)/8, $0x0400004004000040 +DATA b64_enc_mult<>+24(SB)/8, $0x0400004004000040 +GLOBL b64_enc_mult<>(SB), RODATA|NOPTR, $32 diff --git a/vendor/github.com/segmentio/asm/base64/encode_arm64.go b/vendor/github.com/segmentio/asm/base64/encode_arm64.go new file mode 100644 index 00000000000..b6a38149285 --- /dev/null +++ b/vendor/github.com/segmentio/asm/base64/encode_arm64.go @@ -0,0 +1,6 @@ +//go:build !purego +// +build !purego + +package base64 + +func encodeARM64(dst []byte, src []byte, lut *int8) (int, int) diff --git a/vendor/github.com/segmentio/asm/base64/encode_arm64.s b/vendor/github.com/segmentio/asm/base64/encode_arm64.s new file mode 100644 index 00000000000..4654313bbd8 --- /dev/null +++ b/vendor/github.com/segmentio/asm/base64/encode_arm64.s @@ -0,0 +1,97 @@ +#include "textflag.h" + +#define Rdst R0 +#define Rsrc R1 +#define Rlen R2 +#define Rwr R3 +#define Rrem R4 +#define Rtmp R5 + +#define Vlut V0 +#define Vfld0 V6 +#define Vfld1 V7 +#define Vfld2 V8 +#define Vfld3 V9 +#define Vsrc0 V10 +#define Vsrc1 V11 +#define Vsrc2 V12 +#define Vr0a V13 +#define Vr1a V14 +#define Vr2a V15 +#define Vr3a V16 +#define Vr0b V17 +#define Vr1b V18 +#define Vr2b V19 +#define Vr3b V20 + +// func encodeARM64(dst []byte, src []byte, lut *int8) (int, int) +TEXT ·encodeARM64(SB),NOSPLIT,$0-72 + // Load dst/src info + MOVD dst_base+0(FP), Rdst + MOVD src_base+24(FP), Rsrc + MOVD src_len+32(FP), Rlen + MOVD lut+48(FP), Rtmp + VLD1 (Rtmp), [Vlut.B16] + + MOVD Rlen, Rrem + MOVD Rdst, Rwr + + VMOVI $51, V1.B16 + VMOVI $26, V2.B16 + VMOVI $63, V3.B16 + VMOVI $13, V4.B16 + +loop: + VLD3.P 48(Rsrc), [Vsrc0.B16, Vsrc1.B16, Vsrc2.B16] + + // Split 3 source blocks into 4 lookup inputs + VUSHR $2, Vsrc0.B16, Vfld0.B16 + VUSHR $4, Vsrc1.B16, Vfld1.B16 + VUSHR $6, Vsrc2.B16, Vfld2.B16 + VSHL $4, Vsrc0.B16, Vsrc0.B16 + VSHL $2, Vsrc1.B16, Vsrc1.B16 + VORR Vsrc0.B16, Vfld1.B16, Vfld1.B16 + VORR Vsrc1.B16, Vfld2.B16, Vfld2.B16 + VAND V3.B16, Vfld1.B16, Vfld1.B16 + VAND V3.B16, Vfld2.B16, Vfld2.B16 + VAND V3.B16, Vsrc2.B16, Vfld3.B16 + + WORD $0x6e212ccd // VUQSUB V1.B16, Vfld0.B16, Vr0a.B16 + WORD $0x4e263451 // VCMGT V2.B16, Vfld0.B16, Vr0b.B16 + VAND V4.B16, Vr0b.B16, Vr0b.B16 + VORR Vr0b.B16, Vr0a.B16, Vr0a.B16 + WORD $0x6e212cee // VUQSUB V1.B16, Vfld1.B16, Vr1a.B16 + WORD $0x4e273452 // VCMGT V2.B16, Vfld1.B16, Vr1b.B16 + VAND V4.B16, Vr1b.B16, Vr1b.B16 + VORR Vr1b.B16, Vr1a.B16, Vr1a.B16 + WORD $0x6e212d0f // VUQSUB V1.B16, Vfld2.B16, Vr2a.B16 + WORD $0x4e283453 // VCMGT V2.B16, Vfld2.B16, Vr2b.B16 + VAND V4.B16, Vr2b.B16, Vr2b.B16 + VORR Vr2b.B16, Vr2a.B16, Vr2a.B16 + WORD $0x6e212d30 // VUQSUB V1.B16, Vfld3.B16, Vr3a.B16 + WORD $0x4e293454 // VCMGT V2.B16, Vfld3.B16, Vr3b.B16 + VAND V4.B16, Vr3b.B16, Vr3b.B16 + VORR Vr3b.B16, Vr3a.B16, Vr3a.B16 + + // Add result of lookup table to each field + VTBL Vr0a.B16, [Vlut.B16], Vr0a.B16 + VADD Vr0a.B16, Vfld0.B16, Vfld0.B16 + VTBL Vr1a.B16, [Vlut.B16], Vr1a.B16 + VADD Vr1a.B16, Vfld1.B16, Vfld1.B16 + VTBL Vr2a.B16, [Vlut.B16], Vr2a.B16 + VADD Vr2a.B16, Vfld2.B16, Vfld2.B16 + VTBL Vr3a.B16, [Vlut.B16], Vr3a.B16 + VADD Vr3a.B16, Vfld3.B16, Vfld3.B16 + + VST4.P [Vfld0.B16, Vfld1.B16, Vfld2.B16, Vfld3.B16], 64(Rwr) + SUB $48, Rrem + CMP $48, Rrem + BGE loop + +done: + SUB Rdst, Rwr + SUB Rrem, Rlen + MOVD Rwr, ret+56(FP) + MOVD Rlen, ret1+64(FP) + RET + diff --git a/vendor/github.com/segmentio/asm/cpu/arm/arm.go b/vendor/github.com/segmentio/asm/cpu/arm/arm.go new file mode 100644 index 00000000000..47c695a075f --- /dev/null +++ b/vendor/github.com/segmentio/asm/cpu/arm/arm.go @@ -0,0 +1,80 @@ +package arm + +import ( + "github.com/segmentio/asm/cpu/cpuid" + . "golang.org/x/sys/cpu" +) + +type CPU cpuid.CPU + +func (cpu CPU) Has(feature Feature) bool { + return cpuid.CPU(cpu).Has(cpuid.Feature(feature)) +} + +func (cpu *CPU) set(feature Feature, enable bool) { + (*cpuid.CPU)(cpu).Set(cpuid.Feature(feature), enable) +} + +type Feature cpuid.Feature + +const ( + SWP Feature = 1 << iota // SWP instruction support + HALF // Half-word load and store support + THUMB // ARM Thumb instruction set + BIT26 // Address space limited to 26-bits + FASTMUL // 32-bit operand, 64-bit result multiplication support + FPA // Floating point arithmetic support + VFP // Vector floating point support + EDSP // DSP Extensions support + JAVA // Java instruction set + IWMMXT // Intel Wireless MMX technology support + CRUNCH // MaverickCrunch context switching and handling + THUMBEE // Thumb EE instruction set + NEON // NEON instruction set + VFPv3 // Vector floating point version 3 support + VFPv3D16 // Vector floating point version 3 D8-D15 + TLS // Thread local storage support + VFPv4 // Vector floating point version 4 support + IDIVA // Integer divide instruction support in ARM mode + IDIVT // Integer divide instruction support in Thumb mode + VFPD32 // Vector floating point version 3 D15-D31 + LPAE // Large Physical Address Extensions + EVTSTRM // Event stream support + AES // AES hardware implementation + PMULL // Polynomial multiplication instruction set + SHA1 // SHA1 hardware implementation + SHA2 // SHA2 hardware implementation + CRC32 // CRC32 hardware implementation +) + +func ABI() CPU { + cpu := CPU(0) + cpu.set(SWP, ARM.HasSWP) + cpu.set(HALF, ARM.HasHALF) + cpu.set(THUMB, ARM.HasTHUMB) + cpu.set(BIT26, ARM.Has26BIT) + cpu.set(FASTMUL, ARM.HasFASTMUL) + cpu.set(FPA, ARM.HasFPA) + cpu.set(VFP, ARM.HasVFP) + cpu.set(EDSP, ARM.HasEDSP) + cpu.set(JAVA, ARM.HasJAVA) + cpu.set(IWMMXT, ARM.HasIWMMXT) + cpu.set(CRUNCH, ARM.HasCRUNCH) + cpu.set(THUMBEE, ARM.HasTHUMBEE) + cpu.set(NEON, ARM.HasNEON) + cpu.set(VFPv3, ARM.HasVFPv3) + cpu.set(VFPv3D16, ARM.HasVFPv3D16) + cpu.set(TLS, ARM.HasTLS) + cpu.set(VFPv4, ARM.HasVFPv4) + cpu.set(IDIVA, ARM.HasIDIVA) + cpu.set(IDIVT, ARM.HasIDIVT) + cpu.set(VFPD32, ARM.HasVFPD32) + cpu.set(LPAE, ARM.HasLPAE) + cpu.set(EVTSTRM, ARM.HasEVTSTRM) + cpu.set(AES, ARM.HasAES) + cpu.set(PMULL, ARM.HasPMULL) + cpu.set(SHA1, ARM.HasSHA1) + cpu.set(SHA2, ARM.HasSHA2) + cpu.set(CRC32, ARM.HasCRC32) + return cpu +} diff --git a/vendor/github.com/segmentio/asm/cpu/arm64/arm64.go b/vendor/github.com/segmentio/asm/cpu/arm64/arm64.go new file mode 100644 index 00000000000..0c5134c76ee --- /dev/null +++ b/vendor/github.com/segmentio/asm/cpu/arm64/arm64.go @@ -0,0 +1,74 @@ +package arm64 + +import ( + "github.com/segmentio/asm/cpu/cpuid" + . "golang.org/x/sys/cpu" +) + +type CPU cpuid.CPU + +func (cpu CPU) Has(feature Feature) bool { + return cpuid.CPU(cpu).Has(cpuid.Feature(feature)) +} + +func (cpu *CPU) set(feature Feature, enable bool) { + (*cpuid.CPU)(cpu).Set(cpuid.Feature(feature), enable) +} + +type Feature cpuid.Feature + +const ( + FP Feature = 1 << iota // Floating-point instruction set (always available) + ASIMD // Advanced SIMD (always available) + EVTSTRM // Event stream support + AES // AES hardware implementation + PMULL // Polynomial multiplication instruction set + SHA1 // SHA1 hardware implementation + SHA2 // SHA2 hardware implementation + CRC32 // CRC32 hardware implementation + ATOMICS // Atomic memory operation instruction set + FPHP // Half precision floating-point instruction set + ASIMDHP // Advanced SIMD half precision instruction set + CPUID // CPUID identification scheme registers + ASIMDRDM // Rounding double multiply add/subtract instruction set + JSCVT // Javascript conversion from floating-point to integer + FCMA // Floating-point multiplication and addition of complex numbers + LRCPC // Release Consistent processor consistent support + DCPOP // Persistent memory support + SHA3 // SHA3 hardware implementation + SM3 // SM3 hardware implementation + SM4 // SM4 hardware implementation + ASIMDDP // Advanced SIMD double precision instruction set + SHA512 // SHA512 hardware implementation + SVE // Scalable Vector Extensions + ASIMDFHM // Advanced SIMD multiplication FP16 to FP32 +) + +func ABI() CPU { + cpu := CPU(0) + cpu.set(FP, ARM64.HasFP) + cpu.set(ASIMD, ARM64.HasASIMD) + cpu.set(EVTSTRM, ARM64.HasEVTSTRM) + cpu.set(AES, ARM64.HasAES) + cpu.set(PMULL, ARM64.HasPMULL) + cpu.set(SHA1, ARM64.HasSHA1) + cpu.set(SHA2, ARM64.HasSHA2) + cpu.set(CRC32, ARM64.HasCRC32) + cpu.set(ATOMICS, ARM64.HasATOMICS) + cpu.set(FPHP, ARM64.HasFPHP) + cpu.set(ASIMDHP, ARM64.HasASIMDHP) + cpu.set(CPUID, ARM64.HasCPUID) + cpu.set(ASIMDRDM, ARM64.HasASIMDRDM) + cpu.set(JSCVT, ARM64.HasJSCVT) + cpu.set(FCMA, ARM64.HasFCMA) + cpu.set(LRCPC, ARM64.HasLRCPC) + cpu.set(DCPOP, ARM64.HasDCPOP) + cpu.set(SHA3, ARM64.HasSHA3) + cpu.set(SM3, ARM64.HasSM3) + cpu.set(SM4, ARM64.HasSM4) + cpu.set(ASIMDDP, ARM64.HasASIMDDP) + cpu.set(SHA512, ARM64.HasSHA512) + cpu.set(SVE, ARM64.HasSVE) + cpu.set(ASIMDFHM, ARM64.HasASIMDFHM) + return cpu +} diff --git a/vendor/github.com/segmentio/asm/cpu/cpu.go b/vendor/github.com/segmentio/asm/cpu/cpu.go new file mode 100644 index 00000000000..6ddf4973f55 --- /dev/null +++ b/vendor/github.com/segmentio/asm/cpu/cpu.go @@ -0,0 +1,22 @@ +// Pakage cpu provides APIs to detect CPU features available at runtime. +package cpu + +import ( + "github.com/segmentio/asm/cpu/arm" + "github.com/segmentio/asm/cpu/arm64" + "github.com/segmentio/asm/cpu/x86" +) + +var ( + // X86 is the bitset representing the set of the x86 instruction sets are + // supported by the CPU. + X86 = x86.ABI() + + // ARM is the bitset representing which parts of the arm instruction sets + // are supported by the CPU. + ARM = arm.ABI() + + // ARM64 is the bitset representing which parts of the arm64 instruction + // sets are supported by the CPU. + ARM64 = arm64.ABI() +) diff --git a/vendor/github.com/segmentio/asm/cpu/cpuid/cpuid.go b/vendor/github.com/segmentio/asm/cpu/cpuid/cpuid.go new file mode 100644 index 00000000000..0949d3d584d --- /dev/null +++ b/vendor/github.com/segmentio/asm/cpu/cpuid/cpuid.go @@ -0,0 +1,32 @@ +// Package cpuid provides generic types used to represent CPU features supported +// by the architecture. +package cpuid + +// CPU is a bitset of feature flags representing the capabilities of various CPU +// architeectures that this package provides optimized assembly routines for. +// +// The intent is to provide a stable ABI between the Go code that generate the +// assembly, and the program that uses the library functions. +type CPU uint64 + +// Feature represents a single CPU feature. +type Feature uint64 + +const ( + // None is a Feature value that has no CPU features enabled. + None Feature = 0 + // All is a Feature value that has all CPU features enabled. + All Feature = 0xFFFFFFFFFFFFFFFF +) + +func (cpu CPU) Has(feature Feature) bool { + return (Feature(cpu) & feature) == feature +} + +func (cpu *CPU) Set(feature Feature, enabled bool) { + if enabled { + *cpu |= CPU(feature) + } else { + *cpu &= ^CPU(feature) + } +} diff --git a/vendor/github.com/segmentio/asm/cpu/x86/x86.go b/vendor/github.com/segmentio/asm/cpu/x86/x86.go new file mode 100644 index 00000000000..9e93537583d --- /dev/null +++ b/vendor/github.com/segmentio/asm/cpu/x86/x86.go @@ -0,0 +1,76 @@ +package x86 + +import ( + "github.com/segmentio/asm/cpu/cpuid" + . "golang.org/x/sys/cpu" +) + +type CPU cpuid.CPU + +func (cpu CPU) Has(feature Feature) bool { + return cpuid.CPU(cpu).Has(cpuid.Feature(feature)) +} + +func (cpu *CPU) set(feature Feature, enable bool) { + (*cpuid.CPU)(cpu).Set(cpuid.Feature(feature), enable) +} + +type Feature cpuid.Feature + +const ( + SSE Feature = 1 << iota // SSE functions + SSE2 // P4 SSE functions + SSE3 // Prescott SSE3 functions + SSE41 // Penryn SSE4.1 functions + SSE42 // Nehalem SSE4.2 functions + SSE4A // AMD Barcelona microarchitecture SSE4a instructions + SSSE3 // Conroe SSSE3 functions + AVX // AVX functions + AVX2 // AVX2 functions + AVX512BF16 // AVX-512 BFLOAT16 Instructions + AVX512BITALG // AVX-512 Bit Algorithms + AVX512BW // AVX-512 Byte and Word Instructions + AVX512CD // AVX-512 Conflict Detection Instructions + AVX512DQ // AVX-512 Doubleword and Quadword Instructions + AVX512ER // AVX-512 Exponential and Reciprocal Instructions + AVX512F // AVX-512 Foundation + AVX512IFMA // AVX-512 Integer Fused Multiply-Add Instructions + AVX512PF // AVX-512 Prefetch Instructions + AVX512VBMI // AVX-512 Vector Bit Manipulation Instructions + AVX512VBMI2 // AVX-512 Vector Bit Manipulation Instructions, Version 2 + AVX512VL // AVX-512 Vector Length Extensions + AVX512VNNI // AVX-512 Vector Neural Network Instructions + AVX512VP2INTERSECT // AVX-512 Intersect for D/Q + AVX512VPOPCNTDQ // AVX-512 Vector Population Count Doubleword and Quadword + CMOV // Conditional move +) + +func ABI() CPU { + cpu := CPU(0) + cpu.set(SSE, true) // TODO: golang.org/x/sys/cpu assumes all CPUs have SEE? + cpu.set(SSE2, X86.HasSSE2) + cpu.set(SSE3, X86.HasSSE3) + cpu.set(SSE41, X86.HasSSE41) + cpu.set(SSE42, X86.HasSSE42) + cpu.set(SSE4A, false) // TODO: add upstream support in golang.org/x/sys/cpu? + cpu.set(SSSE3, X86.HasSSSE3) + cpu.set(AVX, X86.HasAVX) + cpu.set(AVX2, X86.HasAVX2) + cpu.set(AVX512BF16, X86.HasAVX512BF16) + cpu.set(AVX512BITALG, X86.HasAVX512BITALG) + cpu.set(AVX512BW, X86.HasAVX512BW) + cpu.set(AVX512CD, X86.HasAVX512CD) + cpu.set(AVX512DQ, X86.HasAVX512DQ) + cpu.set(AVX512ER, X86.HasAVX512ER) + cpu.set(AVX512F, X86.HasAVX512F) + cpu.set(AVX512IFMA, X86.HasAVX512IFMA) + cpu.set(AVX512PF, X86.HasAVX512PF) + cpu.set(AVX512VBMI, X86.HasAVX512VBMI) + cpu.set(AVX512VBMI2, X86.HasAVX512VBMI2) + cpu.set(AVX512VL, X86.HasAVX512VL) + cpu.set(AVX512VNNI, X86.HasAVX512VNNI) + cpu.set(AVX512VP2INTERSECT, false) // TODO: add upstream support in golang.org/x/sys/cpu? + cpu.set(AVX512VPOPCNTDQ, X86.HasAVX512VPOPCNTDQ) + cpu.set(CMOV, true) // TODO: golang.org/x/sys/cpu assumes all CPUs have CMOV? + return cpu +} diff --git a/vendor/github.com/segmentio/asm/internal/unsafebytes/unsafebytes.go b/vendor/github.com/segmentio/asm/internal/unsafebytes/unsafebytes.go new file mode 100644 index 00000000000..913c9cc68b0 --- /dev/null +++ b/vendor/github.com/segmentio/asm/internal/unsafebytes/unsafebytes.go @@ -0,0 +1,20 @@ +package unsafebytes + +import "unsafe" + +func Pointer(b []byte) *byte { + return *(**byte)(unsafe.Pointer(&b)) +} + +func String(b []byte) string { + return *(*string)(unsafe.Pointer(&b)) +} + +func BytesOf(s string) []byte { + return *(*[]byte)(unsafe.Pointer(&sliceHeader{str: s, cap: len(s)})) +} + +type sliceHeader struct { + str string + cap int +} diff --git a/vendor/github.com/sirupsen/logrus/terminal_check_bsd.go b/vendor/github.com/sirupsen/logrus/terminal_check_bsd.go index 499789984d2..69956b425a1 100644 --- a/vendor/github.com/sirupsen/logrus/terminal_check_bsd.go +++ b/vendor/github.com/sirupsen/logrus/terminal_check_bsd.go @@ -1,4 +1,4 @@ -// +build darwin dragonfly freebsd netbsd openbsd +// +build darwin dragonfly freebsd netbsd openbsd hurd // +build !js package logrus diff --git a/vendor/github.com/sirupsen/logrus/terminal_check_unix.go b/vendor/github.com/sirupsen/logrus/terminal_check_unix.go index 04748b8515f..c9aed267a4c 100644 --- a/vendor/github.com/sirupsen/logrus/terminal_check_unix.go +++ b/vendor/github.com/sirupsen/logrus/terminal_check_unix.go @@ -1,5 +1,7 @@ +//go:build (linux || aix || zos) && !js && !wasi // +build linux aix zos // +build !js +// +build !wasi package logrus diff --git a/vendor/github.com/sirupsen/logrus/terminal_check_wasi.go b/vendor/github.com/sirupsen/logrus/terminal_check_wasi.go new file mode 100644 index 00000000000..2822b212fbf --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/terminal_check_wasi.go @@ -0,0 +1,8 @@ +//go:build wasi +// +build wasi + +package logrus + +func isTerminal(fd int) bool { + return false +} diff --git a/vendor/github.com/sirupsen/logrus/terminal_check_wasip1.go b/vendor/github.com/sirupsen/logrus/terminal_check_wasip1.go new file mode 100644 index 00000000000..108a6be12b1 --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/terminal_check_wasip1.go @@ -0,0 +1,8 @@ +//go:build wasip1 +// +build wasip1 + +package logrus + +func isTerminal(fd int) bool { + return false +} diff --git a/vendor/github.com/spf13/cobra/.golangci.yml b/vendor/github.com/spf13/cobra/.golangci.yml index 2c8f4808c1a..6acf8ab1ea0 100644 --- a/vendor/github.com/spf13/cobra/.golangci.yml +++ b/vendor/github.com/spf13/cobra/.golangci.yml @@ -12,14 +12,20 @@ # See the License for the specific language governing permissions and # limitations under the License. +version: "2" + run: - deadline: 5m + timeout: 5m + +formatters: + enable: + - gofmt + - goimports linters: - disable-all: true + default: none enable: #- bodyclose - # - deadcode ! deprecated since v1.49.0; replaced by 'unused' #- depguard #- dogsled #- dupl @@ -30,28 +36,24 @@ linters: - goconst - gocritic #- gocyclo - - gofmt - - goimports - #- gomnd #- goprintffuncname - gosec - - gosimple - govet - ineffassign #- lll - misspell + #- mnd #- nakedret #- noctx - nolintlint #- rowserrcheck - #- scopelint - staticcheck - #- structcheck ! deprecated since v1.49.0; replaced by 'unused' - - stylecheck - #- typecheck - unconvert #- unparam - unused - # - varcheck ! deprecated since v1.49.0; replaced by 'unused' #- whitespace - fast: false + exclusions: + presets: + - common-false-positives + - legacy + - std-error-handling diff --git a/vendor/github.com/spf13/cobra/README.md b/vendor/github.com/spf13/cobra/README.md index 71757151c33..8416275f48e 100644 --- a/vendor/github.com/spf13/cobra/README.md +++ b/vendor/github.com/spf13/cobra/README.md @@ -1,8 +1,14 @@ - -![cobra logo](https://github.com/user-attachments/assets/cbc3adf8-0dff-46e9-a88d-5e2d971c169e) +
+ +cobra-logo + +
Cobra is a library for creating powerful modern CLI applications. +Visit Cobra.dev for extensive documentation + + Cobra is used in many Go projects such as [Kubernetes](https://kubernetes.io/), [Hugo](https://gohugo.io), and [GitHub CLI](https://github.com/cli/cli) to name a few. [This list](site/content/projects_using_cobra.md) contains a more extensive list of projects using Cobra. @@ -11,6 +17,20 @@ name a few. [This list](site/content/projects_using_cobra.md) contains a more ex [![Go Reference](https://pkg.go.dev/badge/github.com/spf13/cobra.svg)](https://pkg.go.dev/github.com/spf13/cobra) [![Go Report Card](https://goreportcard.com/badge/github.com/spf13/cobra)](https://goreportcard.com/report/github.com/spf13/cobra) [![Slack](https://img.shields.io/badge/Slack-cobra-brightgreen)](https://gophers.slack.com/archives/CD3LP1199) +
+
+ Supported by: +
+
+ + Warp sponsorship + + +### [Warp, the AI terminal for devs](https://www.warp.dev/cobra) +[Try Cobra in Warp today](https://www.warp.dev/cobra)
+ +
+
# Overview diff --git a/vendor/github.com/spf13/cobra/SECURITY.md b/vendor/github.com/spf13/cobra/SECURITY.md new file mode 100644 index 00000000000..54e60c28c14 --- /dev/null +++ b/vendor/github.com/spf13/cobra/SECURITY.md @@ -0,0 +1,105 @@ +# Security Policy + +## Reporting a Vulnerability + +The `cobra` maintainers take security issues seriously and +we appreciate your efforts to _**responsibly**_ disclose your findings. +We will make every effort to swiftly respond and address concerns. + +To report a security vulnerability: + +1. **DO NOT** create a public GitHub issue for the vulnerability! +2. **DO NOT** create a public GitHub Pull Request with a fix for the vulnerability! +3. Send an email to `cobra-security@googlegroups.com`. +4. Include the following details in your report: + - Description of the vulnerability + - Steps to reproduce + - Potential impact of the vulnerability (to your downstream project, to the Go ecosystem, etc.) + - Any potential mitigations you've already identified +5. Allow up to 7 days for an initial response. + You should receive an acknowledgment of your report and an estimated timeline for a fix. +6. (Optional) If you have a fix and would like to contribute your patch, please work + directly with the maintainers via `cobra-security@googlegroups.com` to + coordinate pushing the patch to GitHub, cutting a new release, and disclosing the change. + +## Response Process + +When a security vulnerability report is received, the `cobra` maintainers will: + +1. Confirm receipt of the vulnerability report within 7 days. +2. Assess the report to determine if it constitutes a security vulnerability. +3. If confirmed, assign the vulnerability a severity level and create a timeline for addressing it. +4. Develop and test a fix. +5. Patch the vulnerability and make a new GitHub release: the maintainers will coordinate disclosure with the reporter. +6. Create a new GitHub Security Advisory to inform the broader Go ecosystem + +## Disclosure Policy + +The `cobra` maintainers follow a coordinated disclosure process: + +1. Security vulnerabilities will be addressed as quickly as possible. +2. A CVE (Common Vulnerabilities and Exposures) identifier will be requested for significant vulnerabilities + that are within `cobra` itself. +3. Once a fix is ready, the maintainers will: + - Release a new version containing the fix. + - Update the security advisory with details about the vulnerability. + - Credit the reporter (unless they wish to remain anonymous). + - Credit the fixer (unless they wish to remain anonymous, this may be the same as the reporter). + - Announce the vulnerability through appropriate channels + (GitHub Security Advisory, mailing lists, GitHub Releases, etc.) + +## Supported Versions + +Security fixes will typically only be released for the most recent major release. + +## Upstream Security Issues + +`cobra` generally will not accept vulnerability reports that originate in upstream +dependencies. I.e., if there is a problem in Go code that `cobra` depends on, +it is best to engage that project's maintainers and owners. + +This security policy primarily pertains only to `cobra` itself but if you believe you've +identified a problem that originates in an upstream dependency and is being widely +distributed by `cobra`, please follow the disclosure procedure above: the `cobra` +maintainers will work with you to determine the severity and ecosystem impact. + +## Security Updates and CVEs + +Information about known security vulnerabilities and CVEs affecting `cobra` will +be published as GitHub Security Advisories at +https://github.com/spf13/cobra/security/advisories. + +All users are encouraged to watch the repository and upgrade promptly when +security releases are published. + +## `cobra` Security Best Practices for Users + +When using `cobra` in your CLIs, the `cobra` maintainers recommend the following: + +1. Always use the latest version of `cobra`. +2. [Use Go modules](https://go.dev/blog/using-go-modules) for dependency management. +3. Always use the latest possible version of Go. + +## Security Best Practices for Contributors + +When contributing to `cobra`: + +1. Be mindful of security implications when adding new features or modifying existing ones. +2. Be aware of `cobra`'s extremely large reach: it is used in nearly every Go CLI + (like Kubernetes, Docker, Prometheus, etc. etc.) +3. Write tests that explicitly cover edge cases and potential issues. +4. If you discover a security issue while working on `cobra`, please report it + following the process above rather than opening a public pull request or issue that + addresses the vulnerability. +5. Take personal sec-ops seriously and secure your GitHub account: use [two-factor authentication](https://docs.github.com/en/authentication/securing-your-account-with-two-factor-authentication-2fa), + [sign your commits with a GPG or SSH key](https://docs.github.com/en/authentication/managing-commit-signature-verification/about-commit-signature-verification), + etc. + +## Acknowledgments + +The `cobra` maintainers would like to thank all security researchers and +community members who help keep cobra, its users, and the entire Go ecosystem secure through responsible disclosures!! + +--- + +*This security policy is inspired by the [Open Web Application Security Project (OWASP)](https://owasp.org/) guidelines and security best practices.* diff --git a/vendor/github.com/spf13/cobra/command.go b/vendor/github.com/spf13/cobra/command.go index dbb2c298ba0..78088db69ca 100644 --- a/vendor/github.com/spf13/cobra/command.go +++ b/vendor/github.com/spf13/cobra/command.go @@ -39,7 +39,7 @@ const ( ) // FParseErrWhitelist configures Flag parse errors to be ignored -type FParseErrWhitelist flag.ParseErrorsWhitelist +type FParseErrWhitelist flag.ParseErrorsAllowlist // Group Structure to manage groups for commands type Group struct { @@ -1296,6 +1296,11 @@ Simply type ` + c.DisplayName() + ` help [path to command] for full details.`, c.Printf("Unknown help topic %#q\n", args) CheckErr(c.Root().Usage()) } else { + // FLow the context down to be used in help text + if cmd.ctx == nil { + cmd.ctx = c.ctx + } + cmd.InitDefaultHelpFlag() // make possible 'help' flag to be shown cmd.InitDefaultVersionFlag() // make possible 'version' flag to be shown CheckErr(cmd.Help()) @@ -1872,7 +1877,7 @@ func (c *Command) ParseFlags(args []string) error { c.mergePersistentFlags() // do it here after merging all flags and just before parse - c.Flags().ParseErrorsWhitelist = flag.ParseErrorsWhitelist(c.FParseErrWhitelist) + c.Flags().ParseErrorsAllowlist = flag.ParseErrorsAllowlist(c.FParseErrWhitelist) err := c.Flags().Parse(args) // Print warnings if they occurred (e.g. deprecated flag messages). @@ -2020,7 +2025,7 @@ func defaultUsageFunc(w io.Writer, in interface{}) error { fmt.Fprint(w, trimRightSpace(c.InheritedFlags().FlagUsages())) } if c.HasHelpSubCommands() { - fmt.Fprintf(w, "\n\nAdditional help topcis:") + fmt.Fprintf(w, "\n\nAdditional help topics:") for _, subcmd := range c.Commands() { if subcmd.IsAdditionalHelpTopicCommand() { fmt.Fprintf(w, "\n %s %s", rpad(subcmd.CommandPath(), subcmd.CommandPathPadding()), subcmd.Short) diff --git a/vendor/github.com/spf13/cobra/completions.go b/vendor/github.com/spf13/cobra/completions.go index a1752f76317..d3607c2d2fe 100644 --- a/vendor/github.com/spf13/cobra/completions.go +++ b/vendor/github.com/spf13/cobra/completions.go @@ -115,6 +115,13 @@ type CompletionOptions struct { DisableDescriptions bool // HiddenDefaultCmd makes the default 'completion' command hidden HiddenDefaultCmd bool + // DefaultShellCompDirective sets the ShellCompDirective that is returned + // if no special directive can be determined + DefaultShellCompDirective *ShellCompDirective +} + +func (receiver *CompletionOptions) SetDefaultShellCompDirective(directive ShellCompDirective) { + receiver.DefaultShellCompDirective = &directive } // Completion is a string that can be used for completions @@ -375,7 +382,7 @@ func (c *Command) getCompletions(args []string) (*Command, []Completion, ShellCo // Error while attempting to parse flags if flagErr != nil { // If error type is flagCompError and we don't want flagCompletion we should ignore the error - if _, ok := flagErr.(*flagCompError); !(ok && !flagCompletion) { + if _, ok := flagErr.(*flagCompError); !ok || flagCompletion { return finalCmd, []Completion{}, ShellCompDirectiveDefault, flagErr } } @@ -480,6 +487,14 @@ func (c *Command) getCompletions(args []string) (*Command, []Completion, ShellCo } } else { directive = ShellCompDirectiveDefault + // check current and parent commands for a custom DefaultShellCompDirective + for cmd := finalCmd; cmd != nil; cmd = cmd.parent { + if cmd.CompletionOptions.DefaultShellCompDirective != nil { + directive = *cmd.CompletionOptions.DefaultShellCompDirective + break + } + } + if flag == nil { foundLocalNonPersistentFlag := false // If TraverseChildren is true on the root command we don't check for @@ -773,7 +788,7 @@ See each sub-command's help for details on how to use the generated script. // shell completion for it (prog __complete completion '') subCmd, cmdArgs, err := c.Find(args) if err != nil || subCmd.Name() != compCmdName && - !(subCmd.Name() == ShellCompRequestCmd && len(cmdArgs) > 1 && cmdArgs[0] == compCmdName) { + (subCmd.Name() != ShellCompRequestCmd || len(cmdArgs) <= 1 || cmdArgs[0] != compCmdName) { // The completion command is not being called or being completed so we remove it. c.RemoveCommand(completionCmd) return diff --git a/vendor/github.com/spf13/pflag/README.md b/vendor/github.com/spf13/pflag/README.md index 7eacc5bdbe5..388c4e5ead2 100644 --- a/vendor/github.com/spf13/pflag/README.md +++ b/vendor/github.com/spf13/pflag/README.md @@ -284,6 +284,33 @@ func main() { } ``` +### Using pflag with go test +`pflag` does not parse the shorthand versions of go test's built-in flags (i.e., those starting with `-test.`). +For more context, see issues [#63](https://github.com/spf13/pflag/issues/63) and [#238](https://github.com/spf13/pflag/issues/238) for more details. + +For example, if you use pflag in your `TestMain` function and call `pflag.Parse()` after defining your custom flags, running a test like this: +```bash +go test /your/tests -run ^YourTest -v --your-test-pflags +``` +will result in the `-v` flag being ignored. This happens because of the way pflag handles flag parsing, skipping over go test's built-in shorthand flags. +To work around this, you can use the `ParseSkippedFlags` function, which ensures that go test's flags are parsed separately using the standard flag package. + +**Example**: You want to parse go test flags that are otherwise ignore by `pflag.Parse()` +```go +import ( + goflag "flag" + flag "github.com/spf13/pflag" +) + +var ip *int = flag.Int("flagname", 1234, "help message for flagname") + +func main() { + flag.CommandLine.AddGoFlagSet(goflag.CommandLine) + flag.ParseSkippedFlags(os.Args[1:], goflag.CommandLine) + flag.Parse() +} +``` + ## More info You can see the full reference documentation of the pflag package diff --git a/vendor/github.com/spf13/pflag/bool_func.go b/vendor/github.com/spf13/pflag/bool_func.go new file mode 100644 index 00000000000..83d77afa89f --- /dev/null +++ b/vendor/github.com/spf13/pflag/bool_func.go @@ -0,0 +1,40 @@ +package pflag + +// -- func Value +type boolfuncValue func(string) error + +func (f boolfuncValue) Set(s string) error { return f(s) } + +func (f boolfuncValue) Type() string { return "boolfunc" } + +func (f boolfuncValue) String() string { return "" } // same behavior as stdlib 'flag' package + +func (f boolfuncValue) IsBoolFlag() bool { return true } + +// BoolFunc defines a func flag with specified name, callback function and usage string. +// +// The callback function will be called every time "--{name}" (or any form that matches the flag) is parsed +// on the command line. +func (f *FlagSet) BoolFunc(name string, usage string, fn func(string) error) { + f.BoolFuncP(name, "", usage, fn) +} + +// BoolFuncP is like BoolFunc, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) BoolFuncP(name, shorthand string, usage string, fn func(string) error) { + var val Value = boolfuncValue(fn) + flag := f.VarPF(val, name, shorthand, usage) + flag.NoOptDefVal = "true" +} + +// BoolFunc defines a func flag with specified name, callback function and usage string. +// +// The callback function will be called every time "--{name}" (or any form that matches the flag) is parsed +// on the command line. +func BoolFunc(name string, usage string, fn func(string) error) { + CommandLine.BoolFuncP(name, "", usage, fn) +} + +// BoolFuncP is like BoolFunc, but accepts a shorthand letter that can be used after a single dash. +func BoolFuncP(name, shorthand string, usage string, fn func(string) error) { + CommandLine.BoolFuncP(name, shorthand, usage, fn) +} diff --git a/vendor/github.com/spf13/pflag/count.go b/vendor/github.com/spf13/pflag/count.go index a0b2679f71c..d49c0143c18 100644 --- a/vendor/github.com/spf13/pflag/count.go +++ b/vendor/github.com/spf13/pflag/count.go @@ -85,7 +85,7 @@ func (f *FlagSet) CountP(name, shorthand string, usage string) *int { // Count defines a count flag with specified name, default value, and usage string. // The return value is the address of an int variable that stores the value of the flag. -// A count flag will add 1 to its value evey time it is found on the command line +// A count flag will add 1 to its value every time it is found on the command line func Count(name string, usage string) *int { return CommandLine.CountP(name, "", usage) } diff --git a/vendor/github.com/spf13/pflag/errors.go b/vendor/github.com/spf13/pflag/errors.go new file mode 100644 index 00000000000..ff11b66befe --- /dev/null +++ b/vendor/github.com/spf13/pflag/errors.go @@ -0,0 +1,149 @@ +package pflag + +import "fmt" + +// notExistErrorMessageType specifies which flavor of "flag does not exist" +// is printed by NotExistError. This allows the related errors to be grouped +// under a single NotExistError struct without making a breaking change to +// the error message text. +type notExistErrorMessageType int + +const ( + flagNotExistMessage notExistErrorMessageType = iota + flagNotDefinedMessage + flagNoSuchFlagMessage + flagUnknownFlagMessage + flagUnknownShorthandFlagMessage +) + +// NotExistError is the error returned when trying to access a flag that +// does not exist in the FlagSet. +type NotExistError struct { + name string + specifiedShorthands string + messageType notExistErrorMessageType +} + +// Error implements error. +func (e *NotExistError) Error() string { + switch e.messageType { + case flagNotExistMessage: + return fmt.Sprintf("flag %q does not exist", e.name) + + case flagNotDefinedMessage: + return fmt.Sprintf("flag accessed but not defined: %s", e.name) + + case flagNoSuchFlagMessage: + return fmt.Sprintf("no such flag -%v", e.name) + + case flagUnknownFlagMessage: + return fmt.Sprintf("unknown flag: --%s", e.name) + + case flagUnknownShorthandFlagMessage: + c := rune(e.name[0]) + return fmt.Sprintf("unknown shorthand flag: %q in -%s", c, e.specifiedShorthands) + } + + panic(fmt.Errorf("unknown flagNotExistErrorMessageType: %v", e.messageType)) +} + +// GetSpecifiedName returns the name of the flag (without dashes) as it +// appeared in the parsed arguments. +func (e *NotExistError) GetSpecifiedName() string { + return e.name +} + +// GetSpecifiedShortnames returns the group of shorthand arguments +// (without dashes) that the flag appeared within. If the flag was not in a +// shorthand group, this will return an empty string. +func (e *NotExistError) GetSpecifiedShortnames() string { + return e.specifiedShorthands +} + +// ValueRequiredError is the error returned when a flag needs an argument but +// no argument was provided. +type ValueRequiredError struct { + flag *Flag + specifiedName string + specifiedShorthands string +} + +// Error implements error. +func (e *ValueRequiredError) Error() string { + if len(e.specifiedShorthands) > 0 { + c := rune(e.specifiedName[0]) + return fmt.Sprintf("flag needs an argument: %q in -%s", c, e.specifiedShorthands) + } + + return fmt.Sprintf("flag needs an argument: --%s", e.specifiedName) +} + +// GetFlag returns the flag for which the error occurred. +func (e *ValueRequiredError) GetFlag() *Flag { + return e.flag +} + +// GetSpecifiedName returns the name of the flag (without dashes) as it +// appeared in the parsed arguments. +func (e *ValueRequiredError) GetSpecifiedName() string { + return e.specifiedName +} + +// GetSpecifiedShortnames returns the group of shorthand arguments +// (without dashes) that the flag appeared within. If the flag was not in a +// shorthand group, this will return an empty string. +func (e *ValueRequiredError) GetSpecifiedShortnames() string { + return e.specifiedShorthands +} + +// InvalidValueError is the error returned when an invalid value is used +// for a flag. +type InvalidValueError struct { + flag *Flag + value string + cause error +} + +// Error implements error. +func (e *InvalidValueError) Error() string { + flag := e.flag + var flagName string + if flag.Shorthand != "" && flag.ShorthandDeprecated == "" { + flagName = fmt.Sprintf("-%s, --%s", flag.Shorthand, flag.Name) + } else { + flagName = fmt.Sprintf("--%s", flag.Name) + } + return fmt.Sprintf("invalid argument %q for %q flag: %v", e.value, flagName, e.cause) +} + +// Unwrap implements errors.Unwrap. +func (e *InvalidValueError) Unwrap() error { + return e.cause +} + +// GetFlag returns the flag for which the error occurred. +func (e *InvalidValueError) GetFlag() *Flag { + return e.flag +} + +// GetValue returns the invalid value that was provided. +func (e *InvalidValueError) GetValue() string { + return e.value +} + +// InvalidSyntaxError is the error returned when a bad flag name is passed on +// the command line. +type InvalidSyntaxError struct { + specifiedFlag string +} + +// Error implements error. +func (e *InvalidSyntaxError) Error() string { + return fmt.Sprintf("bad flag syntax: %s", e.specifiedFlag) +} + +// GetSpecifiedName returns the exact flag (with dashes) as it +// appeared in the parsed arguments. +func (e *InvalidSyntaxError) GetSpecifiedFlag() string { + return e.specifiedFlag +} diff --git a/vendor/github.com/spf13/pflag/flag.go b/vendor/github.com/spf13/pflag/flag.go index 7c058de3744..2fd3c57597a 100644 --- a/vendor/github.com/spf13/pflag/flag.go +++ b/vendor/github.com/spf13/pflag/flag.go @@ -27,23 +27,32 @@ unaffected. Define flags using flag.String(), Bool(), Int(), etc. This declares an integer flag, -flagname, stored in the pointer ip, with type *int. + var ip = flag.Int("flagname", 1234, "help message for flagname") + If you like, you can bind the flag to a variable using the Var() functions. + var flagvar int func init() { flag.IntVar(&flagvar, "flagname", 1234, "help message for flagname") } + Or you can create custom flags that satisfy the Value interface (with pointer receivers) and couple them to flag parsing by + flag.Var(&flagVal, "name", "help message for flagname") + For such flags, the default value is just the initial value of the variable. After all flags are defined, call + flag.Parse() + to parse the command line into the defined flags. Flags may then be used directly. If you're using the flags themselves, they are all pointers; if you bind to variables, they're values. + fmt.Println("ip has value ", *ip) fmt.Println("flagvar has value ", flagvar) @@ -54,22 +63,26 @@ The arguments are indexed from 0 through flag.NArg()-1. The pflag package also defines some new functions that are not in flag, that give one-letter shorthands for flags. You can use these by appending 'P' to the name of any function that defines a flag. + var ip = flag.IntP("flagname", "f", 1234, "help message") var flagvar bool func init() { flag.BoolVarP(&flagvar, "boolname", "b", true, "help message") } flag.VarP(&flagval, "varname", "v", "help message") + Shorthand letters can be used with single dashes on the command line. Boolean shorthand flags can be combined with other shorthand flags. Command line flag syntax: + --flag // boolean flags only --flag=x Unlike the flag package, a single dash before an option means something different than a double dash. Single dashes signify a series of shorthand letters for flags. All but the last shorthand letter must be boolean flags. + // boolean flags -f -abc @@ -124,12 +137,17 @@ const ( PanicOnError ) -// ParseErrorsWhitelist defines the parsing errors that can be ignored -type ParseErrorsWhitelist struct { +// ParseErrorsAllowlist defines the parsing errors that can be ignored +type ParseErrorsAllowlist struct { // UnknownFlags will ignore unknown flags errors and continue parsing rest of the flags UnknownFlags bool } +// ParseErrorsWhitelist defines the parsing errors that can be ignored. +// +// Deprecated: use [ParseErrorsAllowlist] instead. This type will be removed in a future release. +type ParseErrorsWhitelist = ParseErrorsAllowlist + // NormalizedName is a flag name that has been normalized according to rules // for the FlagSet (e.g. making '-' and '_' equivalent). type NormalizedName string @@ -145,8 +163,13 @@ type FlagSet struct { // help/usage messages. SortFlags bool - // ParseErrorsWhitelist is used to configure a whitelist of errors - ParseErrorsWhitelist ParseErrorsWhitelist + // ParseErrorsAllowlist is used to configure an allowlist of errors + ParseErrorsAllowlist ParseErrorsAllowlist + + // ParseErrorsAllowlist is used to configure an allowlist of errors. + // + // Deprecated: use [FlagSet.ParseErrorsAllowlist] instead. This field will be removed in a future release. + ParseErrorsWhitelist ParseErrorsAllowlist name string parsed bool @@ -381,7 +404,7 @@ func (f *FlagSet) lookup(name NormalizedName) *Flag { func (f *FlagSet) getFlagType(name string, ftype string, convFunc func(sval string) (interface{}, error)) (interface{}, error) { flag := f.Lookup(name) if flag == nil { - err := fmt.Errorf("flag accessed but not defined: %s", name) + err := &NotExistError{name: name, messageType: flagNotDefinedMessage} return nil, err } @@ -411,7 +434,7 @@ func (f *FlagSet) ArgsLenAtDash() int { func (f *FlagSet) MarkDeprecated(name string, usageMessage string) error { flag := f.Lookup(name) if flag == nil { - return fmt.Errorf("flag %q does not exist", name) + return &NotExistError{name: name, messageType: flagNotExistMessage} } if usageMessage == "" { return fmt.Errorf("deprecated message for flag %q must be set", name) @@ -427,7 +450,7 @@ func (f *FlagSet) MarkDeprecated(name string, usageMessage string) error { func (f *FlagSet) MarkShorthandDeprecated(name string, usageMessage string) error { flag := f.Lookup(name) if flag == nil { - return fmt.Errorf("flag %q does not exist", name) + return &NotExistError{name: name, messageType: flagNotExistMessage} } if usageMessage == "" { return fmt.Errorf("deprecated message for flag %q must be set", name) @@ -441,7 +464,7 @@ func (f *FlagSet) MarkShorthandDeprecated(name string, usageMessage string) erro func (f *FlagSet) MarkHidden(name string) error { flag := f.Lookup(name) if flag == nil { - return fmt.Errorf("flag %q does not exist", name) + return &NotExistError{name: name, messageType: flagNotExistMessage} } flag.Hidden = true return nil @@ -464,18 +487,16 @@ func (f *FlagSet) Set(name, value string) error { normalName := f.normalizeFlagName(name) flag, ok := f.formal[normalName] if !ok { - return fmt.Errorf("no such flag -%v", name) + return &NotExistError{name: name, messageType: flagNoSuchFlagMessage} } err := flag.Value.Set(value) if err != nil { - var flagName string - if flag.Shorthand != "" && flag.ShorthandDeprecated == "" { - flagName = fmt.Sprintf("-%s, --%s", flag.Shorthand, flag.Name) - } else { - flagName = fmt.Sprintf("--%s", flag.Name) + return &InvalidValueError{ + flag: flag, + value: value, + cause: err, } - return fmt.Errorf("invalid argument %q for %q flag: %v", value, flagName, err) } if !flag.Changed { @@ -501,7 +522,7 @@ func (f *FlagSet) SetAnnotation(name, key string, values []string) error { normalName := f.normalizeFlagName(name) flag, ok := f.formal[normalName] if !ok { - return fmt.Errorf("no such flag -%v", name) + return &NotExistError{name: name, messageType: flagNoSuchFlagMessage} } if flag.Annotations == nil { flag.Annotations = map[string][]string{} @@ -538,7 +559,7 @@ func (f *FlagSet) PrintDefaults() { func (f *Flag) defaultIsZeroValue() bool { switch f.Value.(type) { case boolFlag: - return f.DefValue == "false" + return f.DefValue == "false" || f.DefValue == "" case *durationValue: // Beginning in Go 1.7, duration zero values are "0s" return f.DefValue == "0" || f.DefValue == "0s" @@ -551,7 +572,7 @@ func (f *Flag) defaultIsZeroValue() bool { case *intSliceValue, *stringSliceValue, *stringArrayValue: return f.DefValue == "[]" default: - switch f.Value.String() { + switch f.DefValue { case "false": return true case "": @@ -588,8 +609,10 @@ func UnquoteUsage(flag *Flag) (name string, usage string) { name = flag.Value.Type() switch name { - case "bool": + case "bool", "boolfunc": name = "" + case "func": + name = "value" case "float64": name = "float" case "int64": @@ -707,7 +730,7 @@ func (f *FlagSet) FlagUsagesWrapped(cols int) string { switch flag.Value.Type() { case "string": line += fmt.Sprintf("[=\"%s\"]", flag.NoOptDefVal) - case "bool": + case "bool", "boolfunc": if flag.NoOptDefVal != "true" { line += fmt.Sprintf("[=%s]", flag.NoOptDefVal) } @@ -911,12 +934,10 @@ func VarP(value Value, name, shorthand, usage string) { CommandLine.VarP(value, name, shorthand, usage) } -// failf prints to standard error a formatted error and usage message and +// fail prints an error message and usage message to standard error and // returns the error. -func (f *FlagSet) failf(format string, a ...interface{}) error { - err := fmt.Errorf(format, a...) +func (f *FlagSet) fail(err error) error { if f.errorHandling != ContinueOnError { - fmt.Fprintln(f.Output(), err) f.usage() } return err @@ -934,9 +955,9 @@ func (f *FlagSet) usage() { } } -//--unknown (args will be empty) -//--unknown --next-flag ... (args will be --next-flag ...) -//--unknown arg ... (args will be arg ...) +// --unknown (args will be empty) +// --unknown --next-flag ... (args will be --next-flag ...) +// --unknown arg ... (args will be arg ...) func stripUnknownFlagValue(args []string) []string { if len(args) == 0 { //--unknown @@ -960,7 +981,7 @@ func (f *FlagSet) parseLongArg(s string, args []string, fn parseFunc) (a []strin a = args name := s[2:] if len(name) == 0 || name[0] == '-' || name[0] == '=' { - err = f.failf("bad flag syntax: %s", s) + err = f.fail(&InvalidSyntaxError{specifiedFlag: s}) return } @@ -974,6 +995,8 @@ func (f *FlagSet) parseLongArg(s string, args []string, fn parseFunc) (a []strin f.usage() return a, ErrHelp case f.ParseErrorsWhitelist.UnknownFlags: + fallthrough + case f.ParseErrorsAllowlist.UnknownFlags: // --unknown=unknownval arg ... // we do not want to lose arg in this case if len(split) >= 2 { @@ -982,7 +1005,7 @@ func (f *FlagSet) parseLongArg(s string, args []string, fn parseFunc) (a []strin return stripUnknownFlagValue(a), nil default: - err = f.failf("unknown flag: --%s", name) + err = f.fail(&NotExistError{name: name, messageType: flagUnknownFlagMessage}) return } } @@ -1000,13 +1023,16 @@ func (f *FlagSet) parseLongArg(s string, args []string, fn parseFunc) (a []strin a = a[1:] } else { // '--flag' (arg was required) - err = f.failf("flag needs an argument: %s", s) + err = f.fail(&ValueRequiredError{ + flag: flag, + specifiedName: name, + }) return } err = fn(flag, value) if err != nil { - f.failf(err.Error()) + f.fail(err) } return } @@ -1014,7 +1040,7 @@ func (f *FlagSet) parseLongArg(s string, args []string, fn parseFunc) (a []strin func (f *FlagSet) parseSingleShortArg(shorthands string, args []string, fn parseFunc) (outShorts string, outArgs []string, err error) { outArgs = args - if strings.HasPrefix(shorthands, "test.") { + if isGotestShorthandFlag(shorthands) { return } @@ -1029,6 +1055,8 @@ func (f *FlagSet) parseSingleShortArg(shorthands string, args []string, fn parse err = ErrHelp return case f.ParseErrorsWhitelist.UnknownFlags: + fallthrough + case f.ParseErrorsAllowlist.UnknownFlags: // '-f=arg arg ...' // we do not want to lose arg in this case if len(shorthands) > 2 && shorthands[1] == '=' { @@ -1039,7 +1067,11 @@ func (f *FlagSet) parseSingleShortArg(shorthands string, args []string, fn parse outArgs = stripUnknownFlagValue(outArgs) return default: - err = f.failf("unknown shorthand flag: %q in -%s", c, shorthands) + err = f.fail(&NotExistError{ + name: string(c), + specifiedShorthands: shorthands, + messageType: flagUnknownShorthandFlagMessage, + }) return } } @@ -1062,7 +1094,11 @@ func (f *FlagSet) parseSingleShortArg(shorthands string, args []string, fn parse outArgs = args[1:] } else { // '-f' (arg was required) - err = f.failf("flag needs an argument: %q in -%s", c, shorthands) + err = f.fail(&ValueRequiredError{ + flag: flag, + specifiedName: string(c), + specifiedShorthands: shorthands, + }) return } @@ -1072,7 +1108,7 @@ func (f *FlagSet) parseSingleShortArg(shorthands string, args []string, fn parse err = fn(flag, value) if err != nil { - f.failf(err.Error()) + f.fail(err) } return } @@ -1135,12 +1171,12 @@ func (f *FlagSet) Parse(arguments []string) error { } f.parsed = true - if len(arguments) < 0 { + f.args = make([]string, 0, len(arguments)) + + if len(arguments) == 0 { return nil } - f.args = make([]string, 0, len(arguments)) - set := func(flag *Flag, value string) error { return f.Set(flag.Name, value) } @@ -1151,7 +1187,10 @@ func (f *FlagSet) Parse(arguments []string) error { case ContinueOnError: return err case ExitOnError: - fmt.Println(err) + if err == ErrHelp { + os.Exit(0) + } + fmt.Fprintln(f.Output(), err) os.Exit(2) case PanicOnError: panic(err) @@ -1177,6 +1216,10 @@ func (f *FlagSet) ParseAll(arguments []string, fn func(flag *Flag, value string) case ContinueOnError: return err case ExitOnError: + if err == ErrHelp { + os.Exit(0) + } + fmt.Fprintln(f.Output(), err) os.Exit(2) case PanicOnError: panic(err) diff --git a/vendor/github.com/spf13/pflag/func.go b/vendor/github.com/spf13/pflag/func.go new file mode 100644 index 00000000000..9f4d88f271c --- /dev/null +++ b/vendor/github.com/spf13/pflag/func.go @@ -0,0 +1,37 @@ +package pflag + +// -- func Value +type funcValue func(string) error + +func (f funcValue) Set(s string) error { return f(s) } + +func (f funcValue) Type() string { return "func" } + +func (f funcValue) String() string { return "" } // same behavior as stdlib 'flag' package + +// Func defines a func flag with specified name, callback function and usage string. +// +// The callback function will be called every time "--{name}={value}" (or equivalent) is +// parsed on the command line, with "{value}" as an argument. +func (f *FlagSet) Func(name string, usage string, fn func(string) error) { + f.FuncP(name, "", usage, fn) +} + +// FuncP is like Func, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) FuncP(name string, shorthand string, usage string, fn func(string) error) { + var val Value = funcValue(fn) + f.VarP(val, name, shorthand, usage) +} + +// Func defines a func flag with specified name, callback function and usage string. +// +// The callback function will be called every time "--{name}={value}" (or equivalent) is +// parsed on the command line, with "{value}" as an argument. +func Func(name string, usage string, fn func(string) error) { + CommandLine.FuncP(name, "", usage, fn) +} + +// FuncP is like Func, but accepts a shorthand letter that can be used after a single dash. +func FuncP(name, shorthand string, usage string, fn func(string) error) { + CommandLine.FuncP(name, shorthand, usage, fn) +} diff --git a/vendor/github.com/spf13/pflag/golangflag.go b/vendor/github.com/spf13/pflag/golangflag.go index d3dd72b7fee..e62eab53810 100644 --- a/vendor/github.com/spf13/pflag/golangflag.go +++ b/vendor/github.com/spf13/pflag/golangflag.go @@ -8,8 +8,18 @@ import ( goflag "flag" "reflect" "strings" + "time" ) +// go test flags prefixes +func isGotestFlag(flag string) bool { + return strings.HasPrefix(flag, "-test.") +} + +func isGotestShorthandFlag(flag string) bool { + return strings.HasPrefix(flag, "test.") +} + // flagValueWrapper implements pflag.Value around a flag.Value. The main // difference here is the addition of the Type method that returns a string // name of the type. As this is generally unknown, we approximate that with @@ -103,3 +113,49 @@ func (f *FlagSet) AddGoFlagSet(newSet *goflag.FlagSet) { } f.addedGoFlagSets = append(f.addedGoFlagSets, newSet) } + +// CopyToGoFlagSet will add all current flags to the given Go flag set. +// Deprecation remarks get copied into the usage description. +// Whenever possible, a flag gets added for which Go flags shows +// a proper type in the help message. +func (f *FlagSet) CopyToGoFlagSet(newSet *goflag.FlagSet) { + f.VisitAll(func(flag *Flag) { + usage := flag.Usage + if flag.Deprecated != "" { + usage += " (DEPRECATED: " + flag.Deprecated + ")" + } + + switch value := flag.Value.(type) { + case *stringValue: + newSet.StringVar((*string)(value), flag.Name, flag.DefValue, usage) + case *intValue: + newSet.IntVar((*int)(value), flag.Name, *(*int)(value), usage) + case *int64Value: + newSet.Int64Var((*int64)(value), flag.Name, *(*int64)(value), usage) + case *uintValue: + newSet.UintVar((*uint)(value), flag.Name, *(*uint)(value), usage) + case *uint64Value: + newSet.Uint64Var((*uint64)(value), flag.Name, *(*uint64)(value), usage) + case *durationValue: + newSet.DurationVar((*time.Duration)(value), flag.Name, *(*time.Duration)(value), usage) + case *float64Value: + newSet.Float64Var((*float64)(value), flag.Name, *(*float64)(value), usage) + default: + newSet.Var(flag.Value, flag.Name, usage) + } + }) +} + +// ParseSkippedFlags explicitly Parses go test flags (i.e. the one starting with '-test.') with goflag.Parse(), +// since by default those are skipped by pflag.Parse(). +// Typical usage example: `ParseGoTestFlags(os.Args[1:], goflag.CommandLine)` +func ParseSkippedFlags(osArgs []string, goFlagSet *goflag.FlagSet) error { + var skippedFlags []string + for _, f := range osArgs { + if isGotestFlag(f) { + skippedFlags = append(skippedFlags, f) + } + } + return goFlagSet.Parse(skippedFlags) +} + diff --git a/vendor/github.com/spf13/pflag/ipnet_slice.go b/vendor/github.com/spf13/pflag/ipnet_slice.go index 6b541aa8798..c6e89da18d8 100644 --- a/vendor/github.com/spf13/pflag/ipnet_slice.go +++ b/vendor/github.com/spf13/pflag/ipnet_slice.go @@ -73,7 +73,7 @@ func (s *ipNetSliceValue) String() string { func ipNetSliceConv(val string) (interface{}, error) { val = strings.Trim(val, "[]") - // Emtpy string would cause a slice with one (empty) entry + // Empty string would cause a slice with one (empty) entry if len(val) == 0 { return []net.IPNet{}, nil } diff --git a/vendor/github.com/spf13/pflag/string_to_string.go b/vendor/github.com/spf13/pflag/string_to_string.go index 890a01afc03..1d1e3bf91a3 100644 --- a/vendor/github.com/spf13/pflag/string_to_string.go +++ b/vendor/github.com/spf13/pflag/string_to_string.go @@ -4,6 +4,7 @@ import ( "bytes" "encoding/csv" "fmt" + "sort" "strings" ) @@ -62,8 +63,15 @@ func (s *stringToStringValue) Type() string { } func (s *stringToStringValue) String() string { + keys := make([]string, 0, len(*s.value)) + for k := range *s.value { + keys = append(keys, k) + } + sort.Strings(keys) + records := make([]string, 0, len(*s.value)>>1) - for k, v := range *s.value { + for _, k := range keys { + v := (*s.value)[k] records = append(records, k+"="+v) } diff --git a/vendor/github.com/spf13/pflag/text.go b/vendor/github.com/spf13/pflag/text.go new file mode 100644 index 00000000000..886d5a3d806 --- /dev/null +++ b/vendor/github.com/spf13/pflag/text.go @@ -0,0 +1,81 @@ +package pflag + +import ( + "encoding" + "fmt" + "reflect" +) + +// following is copied from go 1.23.4 flag.go +type textValue struct{ p encoding.TextUnmarshaler } + +func newTextValue(val encoding.TextMarshaler, p encoding.TextUnmarshaler) textValue { + ptrVal := reflect.ValueOf(p) + if ptrVal.Kind() != reflect.Ptr { + panic("variable value type must be a pointer") + } + defVal := reflect.ValueOf(val) + if defVal.Kind() == reflect.Ptr { + defVal = defVal.Elem() + } + if defVal.Type() != ptrVal.Type().Elem() { + panic(fmt.Sprintf("default type does not match variable type: %v != %v", defVal.Type(), ptrVal.Type().Elem())) + } + ptrVal.Elem().Set(defVal) + return textValue{p} +} + +func (v textValue) Set(s string) error { + return v.p.UnmarshalText([]byte(s)) +} + +func (v textValue) Get() interface{} { + return v.p +} + +func (v textValue) String() string { + if m, ok := v.p.(encoding.TextMarshaler); ok { + if b, err := m.MarshalText(); err == nil { + return string(b) + } + } + return "" +} + +//end of copy + +func (v textValue) Type() string { + return reflect.ValueOf(v.p).Type().Name() +} + +// GetText set out, which implements encoding.UnmarshalText, to the value of a flag with given name +func (f *FlagSet) GetText(name string, out encoding.TextUnmarshaler) error { + flag := f.Lookup(name) + if flag == nil { + return fmt.Errorf("flag accessed but not defined: %s", name) + } + if flag.Value.Type() != reflect.TypeOf(out).Name() { + return fmt.Errorf("trying to get %s value of flag of type %s", reflect.TypeOf(out).Name(), flag.Value.Type()) + } + return out.UnmarshalText([]byte(flag.Value.String())) +} + +// TextVar defines a flag with a specified name, default value, and usage string. The argument p must be a pointer to a variable that will hold the value of the flag, and p must implement encoding.TextUnmarshaler. If the flag is used, the flag value will be passed to p's UnmarshalText method. The type of the default value must be the same as the type of p. +func (f *FlagSet) TextVar(p encoding.TextUnmarshaler, name string, value encoding.TextMarshaler, usage string) { + f.VarP(newTextValue(value, p), name, "", usage) +} + +// TextVarP is like TextVar, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) TextVarP(p encoding.TextUnmarshaler, name, shorthand string, value encoding.TextMarshaler, usage string) { + f.VarP(newTextValue(value, p), name, shorthand, usage) +} + +// TextVar defines a flag with a specified name, default value, and usage string. The argument p must be a pointer to a variable that will hold the value of the flag, and p must implement encoding.TextUnmarshaler. If the flag is used, the flag value will be passed to p's UnmarshalText method. The type of the default value must be the same as the type of p. +func TextVar(p encoding.TextUnmarshaler, name string, value encoding.TextMarshaler, usage string) { + CommandLine.VarP(newTextValue(value, p), name, "", usage) +} + +// TextVarP is like TextVar, but accepts a shorthand letter that can be used after a single dash. +func TextVarP(p encoding.TextUnmarshaler, name, shorthand string, value encoding.TextMarshaler, usage string) { + CommandLine.VarP(newTextValue(value, p), name, shorthand, usage) +} diff --git a/vendor/github.com/spf13/pflag/time.go b/vendor/github.com/spf13/pflag/time.go new file mode 100644 index 00000000000..3dee424791a --- /dev/null +++ b/vendor/github.com/spf13/pflag/time.go @@ -0,0 +1,124 @@ +package pflag + +import ( + "fmt" + "strings" + "time" +) + +// TimeValue adapts time.Time for use as a flag. +type timeValue struct { + *time.Time + formats []string +} + +func newTimeValue(val time.Time, p *time.Time, formats []string) *timeValue { + *p = val + return &timeValue{ + Time: p, + formats: formats, + } +} + +// Set time.Time value from string based on accepted formats. +func (d *timeValue) Set(s string) error { + s = strings.TrimSpace(s) + for _, f := range d.formats { + v, err := time.Parse(f, s) + if err != nil { + continue + } + *d.Time = v + return nil + } + + formatsString := "" + for i, f := range d.formats { + if i > 0 { + formatsString += ", " + } + formatsString += fmt.Sprintf("`%s`", f) + } + + return fmt.Errorf("invalid time format `%s` must be one of: %s", s, formatsString) +} + +// Type name for time.Time flags. +func (d *timeValue) Type() string { + return "time" +} + +func (d *timeValue) String() string { + if d.Time.IsZero() { + return "" + } else { + return d.Time.Format(time.RFC3339Nano) + } +} + +// GetTime return the time value of a flag with the given name +func (f *FlagSet) GetTime(name string) (time.Time, error) { + flag := f.Lookup(name) + if flag == nil { + err := fmt.Errorf("flag accessed but not defined: %s", name) + return time.Time{}, err + } + + if flag.Value.Type() != "time" { + err := fmt.Errorf("trying to get %s value of flag of type %s", "time", flag.Value.Type()) + return time.Time{}, err + } + + val, ok := flag.Value.(*timeValue) + if !ok { + return time.Time{}, fmt.Errorf("value %s is not a time", flag.Value) + } + + return *val.Time, nil +} + +// TimeVar defines a time.Time flag with specified name, default value, and usage string. +// The argument p points to a time.Time variable in which to store the value of the flag. +func (f *FlagSet) TimeVar(p *time.Time, name string, value time.Time, formats []string, usage string) { + f.TimeVarP(p, name, "", value, formats, usage) +} + +// TimeVarP is like TimeVar, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) TimeVarP(p *time.Time, name, shorthand string, value time.Time, formats []string, usage string) { + f.VarP(newTimeValue(value, p, formats), name, shorthand, usage) +} + +// TimeVar defines a time.Time flag with specified name, default value, and usage string. +// The argument p points to a time.Time variable in which to store the value of the flag. +func TimeVar(p *time.Time, name string, value time.Time, formats []string, usage string) { + CommandLine.TimeVarP(p, name, "", value, formats, usage) +} + +// TimeVarP is like TimeVar, but accepts a shorthand letter that can be used after a single dash. +func TimeVarP(p *time.Time, name, shorthand string, value time.Time, formats []string, usage string) { + CommandLine.VarP(newTimeValue(value, p, formats), name, shorthand, usage) +} + +// Time defines a time.Time flag with specified name, default value, and usage string. +// The return value is the address of a time.Time variable that stores the value of the flag. +func (f *FlagSet) Time(name string, value time.Time, formats []string, usage string) *time.Time { + return f.TimeP(name, "", value, formats, usage) +} + +// TimeP is like Time, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) TimeP(name, shorthand string, value time.Time, formats []string, usage string) *time.Time { + p := new(time.Time) + f.TimeVarP(p, name, shorthand, value, formats, usage) + return p +} + +// Time defines a time.Time flag with specified name, default value, and usage string. +// The return value is the address of a time.Time variable that stores the value of the flag. +func Time(name string, value time.Time, formats []string, usage string) *time.Time { + return CommandLine.TimeP(name, "", value, formats, usage) +} + +// TimeP is like Time, but accepts a shorthand letter that can be used after a single dash. +func TimeP(name, shorthand string, value time.Time, formats []string, usage string) *time.Time { + return CommandLine.TimeP(name, shorthand, value, formats, usage) +} diff --git a/vendor/github.com/valyala/fastjson/.gitignore b/vendor/github.com/valyala/fastjson/.gitignore new file mode 100644 index 00000000000..6e92f57d464 --- /dev/null +++ b/vendor/github.com/valyala/fastjson/.gitignore @@ -0,0 +1 @@ +tags diff --git a/vendor/github.com/valyala/fastjson/.travis.yml b/vendor/github.com/valyala/fastjson/.travis.yml new file mode 100644 index 00000000000..472a82190c9 --- /dev/null +++ b/vendor/github.com/valyala/fastjson/.travis.yml @@ -0,0 +1,19 @@ +language: go + +go: + - 1.10.x + +script: + # build test for supported platforms + - GOOS=linux go build + - GOOS=darwin go build + - GOOS=freebsd go build + - GOOS=windows go build + + # run tests on a standard platform + - go test -v ./... -coverprofile=coverage.txt -covermode=atomic + - go test -v ./... -race + +after_success: + # Upload coverage results to codecov.io + - bash <(curl -s https://codecov.io/bash) diff --git a/vendor/github.com/valyala/fastjson/LICENSE b/vendor/github.com/valyala/fastjson/LICENSE new file mode 100644 index 00000000000..6f665f3e294 --- /dev/null +++ b/vendor/github.com/valyala/fastjson/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2018 Aliaksandr Valialkin + +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/valyala/fastjson/README.md b/vendor/github.com/valyala/fastjson/README.md new file mode 100644 index 00000000000..f32c6939376 --- /dev/null +++ b/vendor/github.com/valyala/fastjson/README.md @@ -0,0 +1,227 @@ +[![Build Status](https://travis-ci.org/valyala/fastjson.svg)](https://travis-ci.org/valyala/fastjson) +[![GoDoc](https://godoc.org/github.com/valyala/fastjson?status.svg)](http://godoc.org/github.com/valyala/fastjson) +[![Go Report](https://goreportcard.com/badge/github.com/valyala/fastjson)](https://goreportcard.com/report/github.com/valyala/fastjson) +[![codecov](https://codecov.io/gh/valyala/fastjson/branch/master/graph/badge.svg)](https://codecov.io/gh/valyala/fastjson) + +# fastjson - fast JSON parser and validator for Go + + +## Features + + * Fast. As usual, up to 15x faster than the standard [encoding/json](https://golang.org/pkg/encoding/json/). + See [benchmarks](#benchmarks). + * Parses arbitrary JSON without schema, reflection, struct magic and code generation + contrary to [easyjson](https://github.com/mailru/easyjson). + * Provides simple [API](http://godoc.org/github.com/valyala/fastjson). + * Outperforms [jsonparser](https://github.com/buger/jsonparser) and [gjson](https://github.com/tidwall/gjson) + when accessing multiple unrelated fields, since `fastjson` parses the input JSON only once. + * Validates the parsed JSON unlike [jsonparser](https://github.com/buger/jsonparser) + and [gjson](https://github.com/tidwall/gjson). + * May quickly extract a part of the original JSON with `Value.Get(...).MarshalTo` and modify it + with [Del](https://godoc.org/github.com/valyala/fastjson#Value.Del) + and [Set](https://godoc.org/github.com/valyala/fastjson#Value.Set) functions. + * May parse array containing values with distinct types (aka non-homogenous types). + For instance, `fastjson` easily parses the following JSON array `[123, "foo", [456], {"k": "v"}, null]`. + * `fastjson` preserves the original order of object items when calling + [Object.Visit](https://godoc.org/github.com/valyala/fastjson#Object.Visit). + + +## Known limitations + + * Requies extra care to work with - references to certain objects recursively + returned by [Parser](https://godoc.org/github.com/valyala/fastjson#Parser) + must be released before the next call to [Parse](https://godoc.org/github.com/valyala/fastjson#Parser.Parse). + Otherwise the program may work improperly. The same applies to objects returned by [Arena](https://godoc.org/github.com/valyala/fastjson#Arena). + Adhere recommendations from [docs](https://godoc.org/github.com/valyala/fastjson). + * Cannot parse JSON from `io.Reader`. There is [Scanner](https://godoc.org/github.com/valyala/fastjson#Scanner) + for parsing stream of JSON values from a string. + + +## Usage + +One-liner accessing a single field: +```go + s := []byte(`{"foo": [123, "bar"]}`) + fmt.Printf("foo.0=%d\n", fastjson.GetInt(s, "foo", "0")) + + // Output: + // foo.0=123 +``` + +Accessing multiple fields with error handling: +```go + var p fastjson.Parser + v, err := p.Parse(`{ + "str": "bar", + "int": 123, + "float": 1.23, + "bool": true, + "arr": [1, "foo", {}] + }`) + if err != nil { + log.Fatal(err) + } + fmt.Printf("foo=%s\n", v.GetStringBytes("str")) + fmt.Printf("int=%d\n", v.GetInt("int")) + fmt.Printf("float=%f\n", v.GetFloat64("float")) + fmt.Printf("bool=%v\n", v.GetBool("bool")) + fmt.Printf("arr.1=%s\n", v.GetStringBytes("arr", "1")) + + // Output: + // foo=bar + // int=123 + // float=1.230000 + // bool=true + // arr.1=foo +``` + +See also [examples](https://godoc.org/github.com/valyala/fastjson#pkg-examples). + + +## Security + + * `fastjson` shouldn't crash or panic when parsing input strings specially crafted + by an attacker. It must return error on invalid input JSON. + * `fastjson` requires up to `sizeof(Value) * len(inputJSON)` bytes of memory + for parsing `inputJSON` string. Limit the maximum size of the `inputJSON` + before parsing it in order to limit the maximum memory usage. + + +## Performance optimization tips + + * Re-use [Parser](https://godoc.org/github.com/valyala/fastjson#Parser) and [Scanner](https://godoc.org/github.com/valyala/fastjson#Scanner) + for parsing many JSONs. This reduces memory allocations overhead. + [ParserPool](https://godoc.org/github.com/valyala/fastjson#ParserPool) may be useful in this case. + * Prefer calling `Value.Get*` on the value returned from [Parser](https://godoc.org/github.com/valyala/fastjson#Parser) + instead of calling `Get*` one-liners when multiple fields + must be obtained from JSON, since each `Get*` one-liner re-parses + the input JSON again. + * Prefer calling once [Value.Get](https://godoc.org/github.com/valyala/fastjson#Value.Get) + for common prefix paths and then calling `Value.Get*` on the returned value + for distinct suffix paths. + * Prefer iterating over array returned from [Value.GetArray](https://godoc.org/github.com/valyala/fastjson#Object.Visit) + with a range loop instead of calling `Value.Get*` for each array item. + +## Fuzzing +Install [go-fuzz](https://github.com/dvyukov/go-fuzz) & optionally the go-fuzz-corpus. + +```bash +go get -u github.com/dvyukov/go-fuzz/go-fuzz github.com/dvyukov/go-fuzz/go-fuzz-build +``` + +Build using `go-fuzz-build` and run `go-fuzz` with an optional corpus. + +```bash +mkdir -p workdir/corpus +cp $GOPATH/src/github.com/dvyukov/go-fuzz-corpus/json/corpus/* workdir/corpus +go-fuzz-build github.com/valyala/fastjson +go-fuzz -bin=fastjson-fuzz.zip -workdir=workdir +``` + +## Benchmarks + +Go 1.12 has been used for benchmarking. + +Legend: + + * `small` - parse [small.json](testdata/small.json) (190 bytes). + * `medium` - parse [medium.json](testdata/medium.json) (2.3KB). + * `large` - parse [large.json](testdata/large.json) (28KB). + * `canada` - parse [canada.json](testdata/canada.json) (2.2MB). + * `citm` - parse [citm_catalog.json](testdata/citm_catalog.json) (1.7MB). + * `twitter` - parse [twitter.json](testdata/twitter.json) (617KB). + + * `stdjson-map` - parse into a `map[string]interface{}` using `encoding/json`. + * `stdjson-struct` - parse into a struct containing + a subset of fields of the parsed JSON, using `encoding/json`. + * `stdjson-empty-struct` - parse into an empty struct using `encoding/json`. + This is the fastest possible solution for `encoding/json`, may be used + for json validation. See also benchmark results for json validation. + * `fastjson` - parse using `fastjson` without fields access. + * `fastjson-get` - parse using `fastjson` with fields access similar to `stdjson-struct`. + +``` +$ GOMAXPROCS=1 go test github.com/valyala/fastjson -bench='Parse$' +goos: linux +goarch: amd64 +pkg: github.com/valyala/fastjson +BenchmarkParse/small/stdjson-map 200000 7305 ns/op 26.01 MB/s 960 B/op 51 allocs/op +BenchmarkParse/small/stdjson-struct 500000 3431 ns/op 55.37 MB/s 224 B/op 4 allocs/op +BenchmarkParse/small/stdjson-empty-struct 500000 2273 ns/op 83.58 MB/s 168 B/op 2 allocs/op +BenchmarkParse/small/fastjson 5000000 347 ns/op 547.53 MB/s 0 B/op 0 allocs/op +BenchmarkParse/small/fastjson-get 2000000 620 ns/op 306.39 MB/s 0 B/op 0 allocs/op +BenchmarkParse/medium/stdjson-map 30000 40672 ns/op 57.26 MB/s 10196 B/op 208 allocs/op +BenchmarkParse/medium/stdjson-struct 30000 47792 ns/op 48.73 MB/s 9174 B/op 258 allocs/op +BenchmarkParse/medium/stdjson-empty-struct 100000 22096 ns/op 105.40 MB/s 280 B/op 5 allocs/op +BenchmarkParse/medium/fastjson 500000 3025 ns/op 769.90 MB/s 0 B/op 0 allocs/op +BenchmarkParse/medium/fastjson-get 500000 3211 ns/op 725.20 MB/s 0 B/op 0 allocs/op +BenchmarkParse/large/stdjson-map 2000 614079 ns/op 45.79 MB/s 210734 B/op 2785 allocs/op +BenchmarkParse/large/stdjson-struct 5000 298554 ns/op 94.18 MB/s 15616 B/op 353 allocs/op +BenchmarkParse/large/stdjson-empty-struct 5000 268577 ns/op 104.69 MB/s 280 B/op 5 allocs/op +BenchmarkParse/large/fastjson 50000 35210 ns/op 798.56 MB/s 5 B/op 0 allocs/op +BenchmarkParse/large/fastjson-get 50000 35171 ns/op 799.46 MB/s 5 B/op 0 allocs/op +BenchmarkParse/canada/stdjson-map 20 68147307 ns/op 33.03 MB/s 12260502 B/op 392539 allocs/op +BenchmarkParse/canada/stdjson-struct 20 68044518 ns/op 33.08 MB/s 12260123 B/op 392534 allocs/op +BenchmarkParse/canada/stdjson-empty-struct 100 17709250 ns/op 127.11 MB/s 280 B/op 5 allocs/op +BenchmarkParse/canada/fastjson 300 4182404 ns/op 538.22 MB/s 254902 B/op 381 allocs/op +BenchmarkParse/canada/fastjson-get 300 4274744 ns/op 526.60 MB/s 254902 B/op 381 allocs/op +BenchmarkParse/citm/stdjson-map 50 27772612 ns/op 62.19 MB/s 5214163 B/op 95402 allocs/op +BenchmarkParse/citm/stdjson-struct 100 14936191 ns/op 115.64 MB/s 1989 B/op 75 allocs/op +BenchmarkParse/citm/stdjson-empty-struct 100 14946034 ns/op 115.56 MB/s 280 B/op 5 allocs/op +BenchmarkParse/citm/fastjson 1000 1879714 ns/op 918.87 MB/s 17628 B/op 30 allocs/op +BenchmarkParse/citm/fastjson-get 1000 1881598 ns/op 917.94 MB/s 17628 B/op 30 allocs/op +BenchmarkParse/twitter/stdjson-map 100 11289146 ns/op 55.94 MB/s 2187878 B/op 31266 allocs/op +BenchmarkParse/twitter/stdjson-struct 300 5779442 ns/op 109.27 MB/s 408 B/op 6 allocs/op +BenchmarkParse/twitter/stdjson-empty-struct 300 5738504 ns/op 110.05 MB/s 408 B/op 6 allocs/op +BenchmarkParse/twitter/fastjson 2000 774042 ns/op 815.86 MB/s 2541 B/op 2 allocs/op +BenchmarkParse/twitter/fastjson-get 2000 777833 ns/op 811.89 MB/s 2541 B/op 2 allocs/op +``` + +Benchmark results for json validation: + +``` +$ GOMAXPROCS=1 go test github.com/valyala/fastjson -bench='Validate$' +goos: linux +goarch: amd64 +pkg: github.com/valyala/fastjson +BenchmarkValidate/small/stdjson 2000000 955 ns/op 198.83 MB/s 72 B/op 2 allocs/op +BenchmarkValidate/small/fastjson 5000000 384 ns/op 493.60 MB/s 0 B/op 0 allocs/op +BenchmarkValidate/medium/stdjson 200000 10799 ns/op 215.66 MB/s 184 B/op 5 allocs/op +BenchmarkValidate/medium/fastjson 300000 3809 ns/op 611.30 MB/s 0 B/op 0 allocs/op +BenchmarkValidate/large/stdjson 10000 133064 ns/op 211.31 MB/s 184 B/op 5 allocs/op +BenchmarkValidate/large/fastjson 30000 45268 ns/op 621.14 MB/s 0 B/op 0 allocs/op +BenchmarkValidate/canada/stdjson 200 8470904 ns/op 265.74 MB/s 184 B/op 5 allocs/op +BenchmarkValidate/canada/fastjson 500 2973377 ns/op 757.07 MB/s 0 B/op 0 allocs/op +BenchmarkValidate/citm/stdjson 200 7273172 ns/op 237.48 MB/s 184 B/op 5 allocs/op +BenchmarkValidate/citm/fastjson 1000 1684430 ns/op 1025.39 MB/s 0 B/op 0 allocs/op +BenchmarkValidate/twitter/stdjson 500 2849439 ns/op 221.63 MB/s 312 B/op 6 allocs/op +BenchmarkValidate/twitter/fastjson 2000 1036796 ns/op 609.10 MB/s 0 B/op 0 allocs/op +``` + +## FAQ + + * Q: _There are a ton of other high-perf packages for JSON parsing in Go. Why creating yet another package?_ + A: Because other packages require either rigid JSON schema via struct magic + and code generation or perform poorly when multiple unrelated fields + must be obtained from the parsed JSON. + Additionally, `fastjson` provides nicer [API](http://godoc.org/github.com/valyala/fastjson). + + * Q: _What is the main purpose for `fastjson`?_ + A: High-perf JSON parsing for [RTB](https://www.iab.com/wp-content/uploads/2015/05/OpenRTB_API_Specification_Version_2_3_1.pdf) + and other [JSON-RPC](https://en.wikipedia.org/wiki/JSON-RPC) services. + + * Q: _Why fastjson doesn't provide fast marshaling (serialization)?_ + A: Actually it provides some sort of marshaling - see [Value.MarshalTo](https://godoc.org/github.com/valyala/fastjson#Value.MarshalTo). + But I'd recommend using [quicktemplate](https://github.com/valyala/quicktemplate#use-cases) + for high-performance JSON marshaling :) + + * Q: _`fastjson` crashes my program!_ + A: There is high probability of improper use. + * Make sure you don't hold references to objects recursively returned by `Parser` / `Scanner` + beyond the next `Parser.Parse` / `Scanner.Next` call + if such restriction is mentioned in [docs](https://github.com/valyala/fastjson/issues/new). + * Make sure you don't access `fastjson` objects from concurrently running goroutines + if such restriction is mentioned in [docs](https://github.com/valyala/fastjson/issues/new). + * Build and run your program with [-race](https://golang.org/doc/articles/race_detector.html) flag. + Make sure the race detector detects zero races. + * If your program continue crashing after fixing issues mentioned above, [file a bug](https://github.com/valyala/fastjson/issues/new). diff --git a/vendor/github.com/valyala/fastjson/arena.go b/vendor/github.com/valyala/fastjson/arena.go new file mode 100644 index 00000000000..9fe21a48c8c --- /dev/null +++ b/vendor/github.com/valyala/fastjson/arena.go @@ -0,0 +1,126 @@ +package fastjson + +import ( + "strconv" +) + +// Arena may be used for fast creation and re-use of Values. +// +// Typical Arena lifecycle: +// +// 1) Construct Values via the Arena and Value.Set* calls. +// 2) Marshal the constructed Values with Value.MarshalTo call. +// 3) Reset all the constructed Values at once by Arena.Reset call. +// 4) Go to 1 and re-use the Arena. +// +// It is unsafe calling Arena methods from concurrent goroutines. +// Use per-goroutine Arenas or ArenaPool instead. +type Arena struct { + b []byte + c cache +} + +// Reset resets all the Values allocated by a. +// +// Values previously allocated by a cannot be used after the Reset call. +func (a *Arena) Reset() { + a.b = a.b[:0] + a.c.reset() +} + +// NewObject returns new empty object value. +// +// New entries may be added to the returned object via Set call. +// +// The returned object is valid until Reset is called on a. +func (a *Arena) NewObject() *Value { + v := a.c.getValue() + v.t = TypeObject + v.o.reset() + return v +} + +// NewArray returns new empty array value. +// +// New entries may be added to the returned array via Set* calls. +// +// The returned array is valid until Reset is called on a. +func (a *Arena) NewArray() *Value { + v := a.c.getValue() + v.t = TypeArray + v.a = v.a[:0] + return v +} + +// NewString returns new string value containing s. +// +// The returned string is valid until Reset is called on a. +func (a *Arena) NewString(s string) *Value { + v := a.c.getValue() + v.t = typeRawString + bLen := len(a.b) + a.b = escapeString(a.b, s) + v.s = b2s(a.b[bLen+1 : len(a.b)-1]) + return v +} + +// NewStringBytes returns new string value containing b. +// +// The returned string is valid until Reset is called on a. +func (a *Arena) NewStringBytes(b []byte) *Value { + v := a.c.getValue() + v.t = typeRawString + bLen := len(a.b) + a.b = escapeString(a.b, b2s(b)) + v.s = b2s(a.b[bLen+1 : len(a.b)-1]) + return v +} + +// NewNumberFloat64 returns new number value containing f. +// +// The returned number is valid until Reset is called on a. +func (a *Arena) NewNumberFloat64(f float64) *Value { + v := a.c.getValue() + v.t = TypeNumber + bLen := len(a.b) + a.b = strconv.AppendFloat(a.b, f, 'g', -1, 64) + v.s = b2s(a.b[bLen:]) + return v +} + +// NewNumberInt returns new number value containing n. +// +// The returned number is valid until Reset is called on a. +func (a *Arena) NewNumberInt(n int) *Value { + v := a.c.getValue() + v.t = TypeNumber + bLen := len(a.b) + a.b = strconv.AppendInt(a.b, int64(n), 10) + v.s = b2s(a.b[bLen:]) + return v +} + +// NewNumberString returns new number value containing s. +// +// The returned number is valid until Reset is called on a. +func (a *Arena) NewNumberString(s string) *Value { + v := a.c.getValue() + v.t = TypeNumber + v.s = s + return v +} + +// NewNull returns null value. +func (a *Arena) NewNull() *Value { + return valueNull +} + +// NewTrue returns true value. +func (a *Arena) NewTrue() *Value { + return valueTrue +} + +// NewFalse return false value. +func (a *Arena) NewFalse() *Value { + return valueFalse +} diff --git a/vendor/github.com/valyala/fastjson/doc.go b/vendor/github.com/valyala/fastjson/doc.go new file mode 100644 index 00000000000..8076189cfe9 --- /dev/null +++ b/vendor/github.com/valyala/fastjson/doc.go @@ -0,0 +1,9 @@ +/* +Package fastjson provides fast JSON parsing. + +Arbitrary JSON may be parsed by fastjson without the need for creating structs +or for generating go code. Just parse JSON and get the required fields with +Get* functions. + +*/ +package fastjson diff --git a/vendor/github.com/valyala/fastjson/fastfloat/parse.go b/vendor/github.com/valyala/fastjson/fastfloat/parse.go new file mode 100644 index 00000000000..b37838da62c --- /dev/null +++ b/vendor/github.com/valyala/fastjson/fastfloat/parse.go @@ -0,0 +1,515 @@ +package fastfloat + +import ( + "fmt" + "math" + "strconv" + "strings" +) + +// ParseUint64BestEffort parses uint64 number s. +// +// It is equivalent to strconv.ParseUint(s, 10, 64), but is faster. +// +// 0 is returned if the number cannot be parsed. +// See also ParseUint64, which returns parse error if the number cannot be parsed. +func ParseUint64BestEffort(s string) uint64 { + if len(s) == 0 { + return 0 + } + i := uint(0) + d := uint64(0) + j := i + for i < uint(len(s)) { + if s[i] >= '0' && s[i] <= '9' { + d = d*10 + uint64(s[i]-'0') + i++ + if i > 18 { + // The integer part may be out of range for uint64. + // Fall back to slow parsing. + dd, err := strconv.ParseUint(s, 10, 64) + if err != nil { + return 0 + } + return dd + } + continue + } + break + } + if i <= j { + return 0 + } + if i < uint(len(s)) { + // Unparsed tail left. + return 0 + } + return d +} + +// ParseUint64 parses uint64 from s. +// +// It is equivalent to strconv.ParseUint(s, 10, 64), but is faster. +// +// See also ParseUint64BestEffort. +func ParseUint64(s string) (uint64, error) { + if len(s) == 0 { + return 0, fmt.Errorf("cannot parse uint64 from empty string") + } + i := uint(0) + d := uint64(0) + j := i + for i < uint(len(s)) { + if s[i] >= '0' && s[i] <= '9' { + d = d*10 + uint64(s[i]-'0') + i++ + if i > 18 { + // The integer part may be out of range for uint64. + // Fall back to slow parsing. + dd, err := strconv.ParseUint(s, 10, 64) + if err != nil { + return 0, err + } + return dd, nil + } + continue + } + break + } + if i <= j { + return 0, fmt.Errorf("cannot parse uint64 from %q", s) + } + if i < uint(len(s)) { + // Unparsed tail left. + return 0, fmt.Errorf("unparsed tail left after parsing uint64 from %q: %q", s, s[i:]) + } + return d, nil +} + +// ParseInt64BestEffort parses int64 number s. +// +// It is equivalent to strconv.ParseInt(s, 10, 64), but is faster. +// +// 0 is returned if the number cannot be parsed. +// See also ParseInt64, which returns parse error if the number cannot be parsed. +func ParseInt64BestEffort(s string) int64 { + if len(s) == 0 { + return 0 + } + i := uint(0) + minus := s[0] == '-' + if minus { + i++ + if i >= uint(len(s)) { + return 0 + } + } + + d := int64(0) + j := i + for i < uint(len(s)) { + if s[i] >= '0' && s[i] <= '9' { + d = d*10 + int64(s[i]-'0') + i++ + if i > 18 { + // The integer part may be out of range for int64. + // Fall back to slow parsing. + dd, err := strconv.ParseInt(s, 10, 64) + if err != nil { + return 0 + } + return dd + } + continue + } + break + } + if i <= j { + return 0 + } + if i < uint(len(s)) { + // Unparsed tail left. + return 0 + } + if minus { + d = -d + } + return d +} + +// ParseInt64 parses int64 number s. +// +// It is equivalent to strconv.ParseInt(s, 10, 64), but is faster. +// +// See also ParseInt64BestEffort. +func ParseInt64(s string) (int64, error) { + if len(s) == 0 { + return 0, fmt.Errorf("cannot parse int64 from empty string") + } + i := uint(0) + minus := s[0] == '-' + if minus { + i++ + if i >= uint(len(s)) { + return 0, fmt.Errorf("cannot parse int64 from %q", s) + } + } + + d := int64(0) + j := i + for i < uint(len(s)) { + if s[i] >= '0' && s[i] <= '9' { + d = d*10 + int64(s[i]-'0') + i++ + if i > 18 { + // The integer part may be out of range for int64. + // Fall back to slow parsing. + dd, err := strconv.ParseInt(s, 10, 64) + if err != nil { + return 0, err + } + return dd, nil + } + continue + } + break + } + if i <= j { + return 0, fmt.Errorf("cannot parse int64 from %q", s) + } + if i < uint(len(s)) { + // Unparsed tail left. + return 0, fmt.Errorf("unparsed tail left after parsing int64 form %q: %q", s, s[i:]) + } + if minus { + d = -d + } + return d, nil +} + +// Exact powers of 10. +// +// This works faster than math.Pow10, since it avoids additional multiplication. +var float64pow10 = [...]float64{ + 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, +} + +// ParseBestEffort parses floating-point number s. +// +// It is equivalent to strconv.ParseFloat(s, 64), but is faster. +// +// 0 is returned if the number cannot be parsed. +// See also Parse, which returns parse error if the number cannot be parsed. +func ParseBestEffort(s string) float64 { + if len(s) == 0 { + return 0 + } + i := uint(0) + minus := s[0] == '-' + if minus { + i++ + if i >= uint(len(s)) { + return 0 + } + } + + // the integer part might be elided to remain compliant + // with https://go.dev/ref/spec#Floating-point_literals + if s[i] == '.' && (i+1 >= uint(len(s)) || s[i+1] < '0' || s[i+1] > '9') { + return 0 + } + + d := uint64(0) + j := i + for i < uint(len(s)) { + if s[i] >= '0' && s[i] <= '9' { + d = d*10 + uint64(s[i]-'0') + i++ + if i > 18 { + // The integer part may be out of range for uint64. + // Fall back to slow parsing. + f, err := strconv.ParseFloat(s, 64) + if err != nil && !math.IsInf(f, 0) { + return 0 + } + return f + } + continue + } + break + } + if i <= j && s[i] != '.' { + s = s[i:] + if strings.HasPrefix(s, "+") { + s = s[1:] + } + // "infinity" is needed for OpenMetrics support. + // See https://github.com/OpenObservability/OpenMetrics/blob/master/OpenMetrics.md + if strings.EqualFold(s, "inf") || strings.EqualFold(s, "infinity") { + if minus { + return -inf + } + return inf + } + if strings.EqualFold(s, "nan") { + return nan + } + return 0 + } + f := float64(d) + if i >= uint(len(s)) { + // Fast path - just integer. + if minus { + f = -f + } + return f + } + + if s[i] == '.' { + // Parse fractional part. + i++ + if i >= uint(len(s)) { + // the fractional part may be elided to remain compliant + // with https://go.dev/ref/spec#Floating-point_literals + return f + } + k := i + for i < uint(len(s)) { + if s[i] >= '0' && s[i] <= '9' { + d = d*10 + uint64(s[i]-'0') + i++ + if i-j >= uint(len(float64pow10)) { + // The mantissa is out of range. Fall back to standard parsing. + f, err := strconv.ParseFloat(s, 64) + if err != nil && !math.IsInf(f, 0) { + return 0 + } + return f + } + continue + } + break + } + if i < k { + return 0 + } + // Convert the entire mantissa to a float at once to avoid rounding errors. + f = float64(d) / float64pow10[i-k] + if i >= uint(len(s)) { + // Fast path - parsed fractional number. + if minus { + f = -f + } + return f + } + } + if s[i] == 'e' || s[i] == 'E' { + // Parse exponent part. + i++ + if i >= uint(len(s)) { + return 0 + } + expMinus := false + if s[i] == '+' || s[i] == '-' { + expMinus = s[i] == '-' + i++ + if i >= uint(len(s)) { + return 0 + } + } + exp := int16(0) + j := i + for i < uint(len(s)) { + if s[i] >= '0' && s[i] <= '9' { + exp = exp*10 + int16(s[i]-'0') + i++ + if exp > 300 { + // The exponent may be too big for float64. + // Fall back to standard parsing. + f, err := strconv.ParseFloat(s, 64) + if err != nil && !math.IsInf(f, 0) { + return 0 + } + return f + } + continue + } + break + } + if i <= j { + return 0 + } + if expMinus { + exp = -exp + } + f *= math.Pow10(int(exp)) + if i >= uint(len(s)) { + if minus { + f = -f + } + return f + } + } + return 0 +} + +// Parse parses floating-point number s. +// +// It is equivalent to strconv.ParseFloat(s, 64), but is faster. +// +// See also ParseBestEffort. +func Parse(s string) (float64, error) { + if len(s) == 0 { + return 0, fmt.Errorf("cannot parse float64 from empty string") + } + i := uint(0) + minus := s[0] == '-' + if minus { + i++ + if i >= uint(len(s)) { + return 0, fmt.Errorf("cannot parse float64 from %q", s) + } + } + + // the integer part might be elided to remain compliant + // with https://go.dev/ref/spec#Floating-point_literals + if s[i] == '.' && (i+1 >= uint(len(s)) || s[i+1] < '0' || s[i+1] > '9') { + return 0, fmt.Errorf("missing integer and fractional part in %q", s) + } + + d := uint64(0) + j := i + for i < uint(len(s)) { + if s[i] >= '0' && s[i] <= '9' { + d = d*10 + uint64(s[i]-'0') + i++ + if i > 18 { + // The integer part may be out of range for uint64. + // Fall back to slow parsing. + f, err := strconv.ParseFloat(s, 64) + if err != nil && !math.IsInf(f, 0) { + return 0, err + } + return f, nil + } + continue + } + break + } + if i <= j && s[i] != '.' { + ss := s[i:] + if strings.HasPrefix(ss, "+") { + ss = ss[1:] + } + // "infinity" is needed for OpenMetrics support. + // See https://github.com/OpenObservability/OpenMetrics/blob/master/OpenMetrics.md + if strings.EqualFold(ss, "inf") || strings.EqualFold(ss, "infinity") { + if minus { + return -inf, nil + } + return inf, nil + } + if strings.EqualFold(ss, "nan") { + return nan, nil + } + return 0, fmt.Errorf("unparsed tail left after parsing float64 from %q: %q", s, ss) + } + f := float64(d) + if i >= uint(len(s)) { + // Fast path - just integer. + if minus { + f = -f + } + return f, nil + } + + if s[i] == '.' { + // Parse fractional part. + i++ + if i >= uint(len(s)) { + // the fractional part might be elided to remain compliant + // with https://go.dev/ref/spec#Floating-point_literals + return f, nil + } + k := i + for i < uint(len(s)) { + if s[i] >= '0' && s[i] <= '9' { + d = d*10 + uint64(s[i]-'0') + i++ + if i-j >= uint(len(float64pow10)) { + // The mantissa is out of range. Fall back to standard parsing. + f, err := strconv.ParseFloat(s, 64) + if err != nil && !math.IsInf(f, 0) { + return 0, fmt.Errorf("cannot parse mantissa in %q: %s", s, err) + } + return f, nil + } + continue + } + break + } + if i < k { + return 0, fmt.Errorf("cannot find mantissa in %q", s) + } + // Convert the entire mantissa to a float at once to avoid rounding errors. + f = float64(d) / float64pow10[i-k] + if i >= uint(len(s)) { + // Fast path - parsed fractional number. + if minus { + f = -f + } + return f, nil + } + } + if s[i] == 'e' || s[i] == 'E' { + // Parse exponent part. + i++ + if i >= uint(len(s)) { + return 0, fmt.Errorf("cannot parse exponent in %q", s) + } + expMinus := false + if s[i] == '+' || s[i] == '-' { + expMinus = s[i] == '-' + i++ + if i >= uint(len(s)) { + return 0, fmt.Errorf("cannot parse exponent in %q", s) + } + } + exp := int16(0) + j := i + for i < uint(len(s)) { + if s[i] >= '0' && s[i] <= '9' { + exp = exp*10 + int16(s[i]-'0') + i++ + if exp > 300 { + // The exponent may be too big for float64. + // Fall back to standard parsing. + f, err := strconv.ParseFloat(s, 64) + if err != nil && !math.IsInf(f, 0) { + return 0, fmt.Errorf("cannot parse exponent in %q: %s", s, err) + } + return f, nil + } + continue + } + break + } + if i <= j { + return 0, fmt.Errorf("cannot parse exponent in %q", s) + } + if expMinus { + exp = -exp + } + f *= math.Pow10(int(exp)) + if i >= uint(len(s)) { + if minus { + f = -f + } + return f, nil + } + } + return 0, fmt.Errorf("cannot parse float64 from %q", s) +} + +var inf = math.Inf(1) +var nan = math.NaN() diff --git a/vendor/github.com/valyala/fastjson/fuzz.go b/vendor/github.com/valyala/fastjson/fuzz.go new file mode 100644 index 00000000000..9130797c700 --- /dev/null +++ b/vendor/github.com/valyala/fastjson/fuzz.go @@ -0,0 +1,22 @@ +// +build gofuzz + +package fastjson + +func Fuzz(data []byte) int { + err := ValidateBytes(data) + if err != nil { + return 0 + } + + v := MustParseBytes(data) + + dst := make([]byte, 0) + dst = v.MarshalTo(dst) + + err = ValidateBytes(dst) + if err != nil { + panic(err) + } + + return 1 +} diff --git a/vendor/github.com/valyala/fastjson/handy.go b/vendor/github.com/valyala/fastjson/handy.go new file mode 100644 index 00000000000..a5d5618f09c --- /dev/null +++ b/vendor/github.com/valyala/fastjson/handy.go @@ -0,0 +1,170 @@ +package fastjson + +var handyPool ParserPool + +// GetString returns string value for the field identified by keys path +// in JSON data. +// +// Array indexes may be represented as decimal numbers in keys. +// +// An empty string is returned on error. Use Parser for proper error handling. +// +// Parser is faster for obtaining multiple fields from JSON. +func GetString(data []byte, keys ...string) string { + p := handyPool.Get() + v, err := p.ParseBytes(data) + if err != nil { + handyPool.Put(p) + return "" + } + sb := v.GetStringBytes(keys...) + str := string(sb) + handyPool.Put(p) + return str +} + +// GetBytes returns string value for the field identified by keys path +// in JSON data. +// +// Array indexes may be represented as decimal numbers in keys. +// +// nil is returned on error. Use Parser for proper error handling. +// +// Parser is faster for obtaining multiple fields from JSON. +func GetBytes(data []byte, keys ...string) []byte { + p := handyPool.Get() + v, err := p.ParseBytes(data) + if err != nil { + handyPool.Put(p) + return nil + } + sb := v.GetStringBytes(keys...) + + // Make a copy of sb, since sb belongs to p. + var b []byte + if sb != nil { + b = append(b, sb...) + } + + handyPool.Put(p) + return b +} + +// GetInt returns int value for the field identified by keys path +// in JSON data. +// +// Array indexes may be represented as decimal numbers in keys. +// +// 0 is returned on error. Use Parser for proper error handling. +// +// Parser is faster for obtaining multiple fields from JSON. +func GetInt(data []byte, keys ...string) int { + p := handyPool.Get() + v, err := p.ParseBytes(data) + if err != nil { + handyPool.Put(p) + return 0 + } + n := v.GetInt(keys...) + handyPool.Put(p) + return n +} + +// GetFloat64 returns float64 value for the field identified by keys path +// in JSON data. +// +// Array indexes may be represented as decimal numbers in keys. +// +// 0 is returned on error. Use Parser for proper error handling. +// +// Parser is faster for obtaining multiple fields from JSON. +func GetFloat64(data []byte, keys ...string) float64 { + p := handyPool.Get() + v, err := p.ParseBytes(data) + if err != nil { + handyPool.Put(p) + return 0 + } + f := v.GetFloat64(keys...) + handyPool.Put(p) + return f +} + +// GetBool returns boolean value for the field identified by keys path +// in JSON data. +// +// Array indexes may be represented as decimal numbers in keys. +// +// False is returned on error. Use Parser for proper error handling. +// +// Parser is faster for obtaining multiple fields from JSON. +func GetBool(data []byte, keys ...string) bool { + p := handyPool.Get() + v, err := p.ParseBytes(data) + if err != nil { + handyPool.Put(p) + return false + } + b := v.GetBool(keys...) + handyPool.Put(p) + return b +} + +// Exists returns true if the field identified by keys path exists in JSON data. +// +// Array indexes may be represented as decimal numbers in keys. +// +// False is returned on error. Use Parser for proper error handling. +// +// Parser is faster when multiple fields must be checked in the JSON. +func Exists(data []byte, keys ...string) bool { + p := handyPool.Get() + v, err := p.ParseBytes(data) + if err != nil { + handyPool.Put(p) + return false + } + ok := v.Exists(keys...) + handyPool.Put(p) + return ok +} + +// Parse parses json string s. +// +// The function is slower than the Parser.Parse for re-used Parser. +func Parse(s string) (*Value, error) { + var p Parser + return p.Parse(s) +} + +// MustParse parses json string s. +// +// The function panics if s cannot be parsed. +// The function is slower than the Parser.Parse for re-used Parser. +func MustParse(s string) *Value { + v, err := Parse(s) + if err != nil { + panic(err) + } + return v +} + +// ParseBytes parses b containing json. +// +// The function is slower than the Parser.ParseBytes for re-used Parser. +func ParseBytes(b []byte) (*Value, error) { + var p Parser + return p.ParseBytes(b) +} + +// MustParseBytes parses b containing json. +// +// The function panics if b cannot be parsed. +// The function is slower than the Parser.ParseBytes for re-used Parser. +func MustParseBytes(b []byte) *Value { + v, err := ParseBytes(b) + if err != nil { + panic(err) + } + return v +} diff --git a/vendor/github.com/valyala/fastjson/parser.go b/vendor/github.com/valyala/fastjson/parser.go new file mode 100644 index 00000000000..885e1841efa --- /dev/null +++ b/vendor/github.com/valyala/fastjson/parser.go @@ -0,0 +1,976 @@ +package fastjson + +import ( + "fmt" + "github.com/valyala/fastjson/fastfloat" + "strconv" + "strings" + "unicode/utf16" +) + +// Parser parses JSON. +// +// Parser may be re-used for subsequent parsing. +// +// Parser cannot be used from concurrent goroutines. +// Use per-goroutine parsers or ParserPool instead. +type Parser struct { + // b contains working copy of the string to be parsed. + b []byte + + // c is a cache for json values. + c cache +} + +// Parse parses s containing JSON. +// +// The returned value is valid until the next call to Parse*. +// +// Use Scanner if a stream of JSON values must be parsed. +func (p *Parser) Parse(s string) (*Value, error) { + s = skipWS(s) + p.b = append(p.b[:0], s...) + p.c.reset() + + v, tail, err := parseValue(b2s(p.b), &p.c, 0) + if err != nil { + return nil, fmt.Errorf("cannot parse JSON: %s; unparsed tail: %q", err, startEndString(tail)) + } + tail = skipWS(tail) + if len(tail) > 0 { + return nil, fmt.Errorf("unexpected tail: %q", startEndString(tail)) + } + return v, nil +} + +// ParseBytes parses b containing JSON. +// +// The returned Value is valid until the next call to Parse*. +// +// Use Scanner if a stream of JSON values must be parsed. +func (p *Parser) ParseBytes(b []byte) (*Value, error) { + return p.Parse(b2s(b)) +} + +type cache struct { + vs []Value +} + +func (c *cache) reset() { + c.vs = c.vs[:0] +} + +func (c *cache) getValue() *Value { + if cap(c.vs) > len(c.vs) { + c.vs = c.vs[:len(c.vs)+1] + } else { + c.vs = append(c.vs, Value{}) + } + // Do not reset the value, since the caller must properly init it. + return &c.vs[len(c.vs)-1] +} + +func skipWS(s string) string { + if len(s) == 0 || s[0] > 0x20 { + // Fast path. + return s + } + return skipWSSlow(s) +} + +func skipWSSlow(s string) string { + if len(s) == 0 || s[0] != 0x20 && s[0] != 0x0A && s[0] != 0x09 && s[0] != 0x0D { + return s + } + for i := 1; i < len(s); i++ { + if s[i] != 0x20 && s[i] != 0x0A && s[i] != 0x09 && s[i] != 0x0D { + return s[i:] + } + } + return "" +} + +type kv struct { + k string + v *Value +} + +// MaxDepth is the maximum depth for nested JSON. +const MaxDepth = 300 + +func parseValue(s string, c *cache, depth int) (*Value, string, error) { + if len(s) == 0 { + return nil, s, fmt.Errorf("cannot parse empty string") + } + depth++ + if depth > MaxDepth { + return nil, s, fmt.Errorf("too big depth for the nested JSON; it exceeds %d", MaxDepth) + } + + if s[0] == '{' { + v, tail, err := parseObject(s[1:], c, depth) + if err != nil { + return nil, tail, fmt.Errorf("cannot parse object: %s", err) + } + return v, tail, nil + } + if s[0] == '[' { + v, tail, err := parseArray(s[1:], c, depth) + if err != nil { + return nil, tail, fmt.Errorf("cannot parse array: %s", err) + } + return v, tail, nil + } + if s[0] == '"' { + ss, tail, err := parseRawString(s[1:]) + if err != nil { + return nil, tail, fmt.Errorf("cannot parse string: %s", err) + } + v := c.getValue() + v.t = typeRawString + v.s = ss + return v, tail, nil + } + if s[0] == 't' { + if len(s) < len("true") || s[:len("true")] != "true" { + return nil, s, fmt.Errorf("unexpected value found: %q", s) + } + return valueTrue, s[len("true"):], nil + } + if s[0] == 'f' { + if len(s) < len("false") || s[:len("false")] != "false" { + return nil, s, fmt.Errorf("unexpected value found: %q", s) + } + return valueFalse, s[len("false"):], nil + } + if s[0] == 'n' { + if len(s) < len("null") || s[:len("null")] != "null" { + // Try parsing NaN + if len(s) >= 3 && strings.EqualFold(s[:3], "nan") { + v := c.getValue() + v.t = TypeNumber + v.s = s[:3] + return v, s[3:], nil + } + return nil, s, fmt.Errorf("unexpected value found: %q", s) + } + return valueNull, s[len("null"):], nil + } + + ns, tail, err := parseRawNumber(s) + if err != nil { + return nil, tail, fmt.Errorf("cannot parse number: %s", err) + } + v := c.getValue() + v.t = TypeNumber + v.s = ns + return v, tail, nil +} + +func parseArray(s string, c *cache, depth int) (*Value, string, error) { + s = skipWS(s) + if len(s) == 0 { + return nil, s, fmt.Errorf("missing ']'") + } + + if s[0] == ']' { + v := c.getValue() + v.t = TypeArray + v.a = v.a[:0] + return v, s[1:], nil + } + + a := c.getValue() + a.t = TypeArray + a.a = a.a[:0] + for { + var v *Value + var err error + + s = skipWS(s) + v, s, err = parseValue(s, c, depth) + if err != nil { + return nil, s, fmt.Errorf("cannot parse array value: %s", err) + } + a.a = append(a.a, v) + + s = skipWS(s) + if len(s) == 0 { + return nil, s, fmt.Errorf("unexpected end of array") + } + if s[0] == ',' { + s = s[1:] + continue + } + if s[0] == ']' { + s = s[1:] + return a, s, nil + } + return nil, s, fmt.Errorf("missing ',' after array value") + } +} + +func parseObject(s string, c *cache, depth int) (*Value, string, error) { + s = skipWS(s) + if len(s) == 0 { + return nil, s, fmt.Errorf("missing '}'") + } + + if s[0] == '}' { + v := c.getValue() + v.t = TypeObject + v.o.reset() + return v, s[1:], nil + } + + o := c.getValue() + o.t = TypeObject + o.o.reset() + for { + var err error + kv := o.o.getKV() + + // Parse key. + s = skipWS(s) + if len(s) == 0 || s[0] != '"' { + return nil, s, fmt.Errorf(`cannot find opening '"" for object key`) + } + kv.k, s, err = parseRawKey(s[1:]) + if err != nil { + return nil, s, fmt.Errorf("cannot parse object key: %s", err) + } + s = skipWS(s) + if len(s) == 0 || s[0] != ':' { + return nil, s, fmt.Errorf("missing ':' after object key") + } + s = s[1:] + + // Parse value + s = skipWS(s) + kv.v, s, err = parseValue(s, c, depth) + if err != nil { + return nil, s, fmt.Errorf("cannot parse object value: %s", err) + } + s = skipWS(s) + if len(s) == 0 { + return nil, s, fmt.Errorf("unexpected end of object") + } + if s[0] == ',' { + s = s[1:] + continue + } + if s[0] == '}' { + return o, s[1:], nil + } + return nil, s, fmt.Errorf("missing ',' after object value") + } +} + +func escapeString(dst []byte, s string) []byte { + if !hasSpecialChars(s) { + // Fast path - nothing to escape. + dst = append(dst, '"') + dst = append(dst, s...) + dst = append(dst, '"') + return dst + } + + // Slow path. + return strconv.AppendQuote(dst, s) +} + +func hasSpecialChars(s string) bool { + if strings.IndexByte(s, '"') >= 0 || strings.IndexByte(s, '\\') >= 0 { + return true + } + for i := 0; i < len(s); i++ { + if s[i] < 0x20 { + return true + } + } + return false +} + +func unescapeStringBestEffort(s string) string { + n := strings.IndexByte(s, '\\') + if n < 0 { + // Fast path - nothing to unescape. + return s + } + + // Slow path - unescape string. + b := s2b(s) // It is safe to do, since s points to a byte slice in Parser.b. + b = b[:n] + s = s[n+1:] + for len(s) > 0 { + ch := s[0] + s = s[1:] + switch ch { + case '"': + b = append(b, '"') + case '\\': + b = append(b, '\\') + case '/': + b = append(b, '/') + case 'b': + b = append(b, '\b') + case 'f': + b = append(b, '\f') + case 'n': + b = append(b, '\n') + case 'r': + b = append(b, '\r') + case 't': + b = append(b, '\t') + case 'u': + if len(s) < 4 { + // Too short escape sequence. Just store it unchanged. + b = append(b, "\\u"...) + break + } + xs := s[:4] + x, err := strconv.ParseUint(xs, 16, 16) + if err != nil { + // Invalid escape sequence. Just store it unchanged. + b = append(b, "\\u"...) + break + } + s = s[4:] + if !utf16.IsSurrogate(rune(x)) { + b = append(b, string(rune(x))...) + break + } + + // Surrogate. + // See https://en.wikipedia.org/wiki/Universal_Character_Set_characters#Surrogates + if len(s) < 6 || s[0] != '\\' || s[1] != 'u' { + b = append(b, "\\u"...) + b = append(b, xs...) + break + } + x1, err := strconv.ParseUint(s[2:6], 16, 16) + if err != nil { + b = append(b, "\\u"...) + b = append(b, xs...) + break + } + r := utf16.DecodeRune(rune(x), rune(x1)) + b = append(b, string(r)...) + s = s[6:] + default: + // Unknown escape sequence. Just store it unchanged. + b = append(b, '\\', ch) + } + n = strings.IndexByte(s, '\\') + if n < 0 { + b = append(b, s...) + break + } + b = append(b, s[:n]...) + s = s[n+1:] + } + return b2s(b) +} + +// parseRawKey is similar to parseRawString, but is optimized +// for small-sized keys without escape sequences. +func parseRawKey(s string) (string, string, error) { + for i := 0; i < len(s); i++ { + if s[i] == '"' { + // Fast path. + return s[:i], s[i+1:], nil + } + if s[i] == '\\' { + // Slow path. + return parseRawString(s) + } + } + return s, "", fmt.Errorf(`missing closing '"'`) +} + +func parseRawString(s string) (string, string, error) { + n := strings.IndexByte(s, '"') + if n < 0 { + return s, "", fmt.Errorf(`missing closing '"'`) + } + if n == 0 || s[n-1] != '\\' { + // Fast path. No escaped ". + return s[:n], s[n+1:], nil + } + + // Slow path - possible escaped " found. + ss := s + for { + i := n - 1 + for i > 0 && s[i-1] == '\\' { + i-- + } + if uint(n-i)%2 == 0 { + return ss[:len(ss)-len(s)+n], s[n+1:], nil + } + s = s[n+1:] + + n = strings.IndexByte(s, '"') + if n < 0 { + return ss, "", fmt.Errorf(`missing closing '"'`) + } + if n == 0 || s[n-1] != '\\' { + return ss[:len(ss)-len(s)+n], s[n+1:], nil + } + } +} + +func parseRawNumber(s string) (string, string, error) { + // The caller must ensure len(s) > 0 + + // Find the end of the number. + for i := 0; i < len(s); i++ { + ch := s[i] + if (ch >= '0' && ch <= '9') || ch == '.' || ch == '-' || ch == 'e' || ch == 'E' || ch == '+' { + continue + } + if i == 0 || i == 1 && (s[0] == '-' || s[0] == '+') { + if len(s[i:]) >= 3 { + xs := s[i : i+3] + if strings.EqualFold(xs, "inf") || strings.EqualFold(xs, "nan") { + return s[:i+3], s[i+3:], nil + } + } + return "", s, fmt.Errorf("unexpected char: %q", s[:1]) + } + ns := s[:i] + s = s[i:] + return ns, s, nil + } + return s, "", nil +} + +// Object represents JSON object. +// +// Object cannot be used from concurrent goroutines. +// Use per-goroutine parsers or ParserPool instead. +type Object struct { + kvs []kv + keysUnescaped bool +} + +func (o *Object) reset() { + o.kvs = o.kvs[:0] + o.keysUnescaped = false +} + +// MarshalTo appends marshaled o to dst and returns the result. +func (o *Object) MarshalTo(dst []byte) []byte { + dst = append(dst, '{') + for i, kv := range o.kvs { + if o.keysUnescaped { + dst = escapeString(dst, kv.k) + } else { + dst = append(dst, '"') + dst = append(dst, kv.k...) + dst = append(dst, '"') + } + dst = append(dst, ':') + dst = kv.v.MarshalTo(dst) + if i != len(o.kvs)-1 { + dst = append(dst, ',') + } + } + dst = append(dst, '}') + return dst +} + +// String returns string representation for the o. +// +// This function is for debugging purposes only. It isn't optimized for speed. +// See MarshalTo instead. +func (o *Object) String() string { + b := o.MarshalTo(nil) + // It is safe converting b to string without allocation, since b is no longer + // reachable after this line. + return b2s(b) +} + +func (o *Object) getKV() *kv { + if cap(o.kvs) > len(o.kvs) { + o.kvs = o.kvs[:len(o.kvs)+1] + } else { + o.kvs = append(o.kvs, kv{}) + } + return &o.kvs[len(o.kvs)-1] +} + +func (o *Object) unescapeKeys() { + if o.keysUnescaped { + return + } + kvs := o.kvs + for i := range kvs { + kv := &kvs[i] + kv.k = unescapeStringBestEffort(kv.k) + } + o.keysUnescaped = true +} + +// Len returns the number of items in the o. +func (o *Object) Len() int { + return len(o.kvs) +} + +// Get returns the value for the given key in the o. +// +// Returns nil if the value for the given key isn't found. +// +// The returned value is valid until Parse is called on the Parser returned o. +func (o *Object) Get(key string) *Value { + if !o.keysUnescaped && strings.IndexByte(key, '\\') < 0 { + // Fast path - try searching for the key without object keys unescaping. + for _, kv := range o.kvs { + if kv.k == key { + return kv.v + } + } + } + + // Slow path - unescape object keys. + o.unescapeKeys() + + for _, kv := range o.kvs { + if kv.k == key { + return kv.v + } + } + return nil +} + +// Visit calls f for each item in the o in the original order +// of the parsed JSON. +// +// f cannot hold key and/or v after returning. +func (o *Object) Visit(f func(key []byte, v *Value)) { + if o == nil { + return + } + + o.unescapeKeys() + + for _, kv := range o.kvs { + f(s2b(kv.k), kv.v) + } +} + +// Value represents any JSON value. +// +// Call Type in order to determine the actual type of the JSON value. +// +// Value cannot be used from concurrent goroutines. +// Use per-goroutine parsers or ParserPool instead. +type Value struct { + o Object + a []*Value + s string + t Type +} + +// MarshalTo appends marshaled v to dst and returns the result. +func (v *Value) MarshalTo(dst []byte) []byte { + switch v.t { + case typeRawString: + dst = append(dst, '"') + dst = append(dst, v.s...) + dst = append(dst, '"') + return dst + case TypeObject: + return v.o.MarshalTo(dst) + case TypeArray: + dst = append(dst, '[') + for i, vv := range v.a { + dst = vv.MarshalTo(dst) + if i != len(v.a)-1 { + dst = append(dst, ',') + } + } + dst = append(dst, ']') + return dst + case TypeString: + return escapeString(dst, v.s) + case TypeNumber: + return append(dst, v.s...) + case TypeTrue: + return append(dst, "true"...) + case TypeFalse: + return append(dst, "false"...) + case TypeNull: + return append(dst, "null"...) + default: + panic(fmt.Errorf("BUG: unexpected Value type: %d", v.t)) + } +} + +// String returns string representation of the v. +// +// The function is for debugging purposes only. It isn't optimized for speed. +// See MarshalTo instead. +// +// Don't confuse this function with StringBytes, which must be called +// for obtaining the underlying JSON string for the v. +func (v *Value) String() string { + b := v.MarshalTo(nil) + // It is safe converting b to string without allocation, since b is no longer + // reachable after this line. + return b2s(b) +} + +// Type represents JSON type. +type Type int + +const ( + // TypeNull is JSON null. + TypeNull Type = 0 + + // TypeObject is JSON object type. + TypeObject Type = 1 + + // TypeArray is JSON array type. + TypeArray Type = 2 + + // TypeString is JSON string type. + TypeString Type = 3 + + // TypeNumber is JSON number type. + TypeNumber Type = 4 + + // TypeTrue is JSON true. + TypeTrue Type = 5 + + // TypeFalse is JSON false. + TypeFalse Type = 6 + + typeRawString Type = 7 +) + +// String returns string representation of t. +func (t Type) String() string { + switch t { + case TypeObject: + return "object" + case TypeArray: + return "array" + case TypeString: + return "string" + case TypeNumber: + return "number" + case TypeTrue: + return "true" + case TypeFalse: + return "false" + case TypeNull: + return "null" + + // typeRawString is skipped intentionally, + // since it shouldn't be visible to user. + default: + panic(fmt.Errorf("BUG: unknown Value type: %d", t)) + } +} + +// Type returns the type of the v. +func (v *Value) Type() Type { + if v.t == typeRawString { + v.s = unescapeStringBestEffort(v.s) + v.t = TypeString + } + return v.t +} + +// Exists returns true if the field exists for the given keys path. +// +// Array indexes may be represented as decimal numbers in keys. +func (v *Value) Exists(keys ...string) bool { + v = v.Get(keys...) + return v != nil +} + +// Get returns value by the given keys path. +// +// Array indexes may be represented as decimal numbers in keys. +// +// nil is returned for non-existing keys path. +// +// The returned value is valid until Parse is called on the Parser returned v. +func (v *Value) Get(keys ...string) *Value { + if v == nil { + return nil + } + for _, key := range keys { + if v.t == TypeObject { + v = v.o.Get(key) + if v == nil { + return nil + } + } else if v.t == TypeArray { + n, err := strconv.Atoi(key) + if err != nil || n < 0 || n >= len(v.a) { + return nil + } + v = v.a[n] + } else { + return nil + } + } + return v +} + +// GetObject returns object value by the given keys path. +// +// Array indexes may be represented as decimal numbers in keys. +// +// nil is returned for non-existing keys path or for invalid value type. +// +// The returned object is valid until Parse is called on the Parser returned v. +func (v *Value) GetObject(keys ...string) *Object { + v = v.Get(keys...) + if v == nil || v.t != TypeObject { + return nil + } + return &v.o +} + +// GetArray returns array value by the given keys path. +// +// Array indexes may be represented as decimal numbers in keys. +// +// nil is returned for non-existing keys path or for invalid value type. +// +// The returned array is valid until Parse is called on the Parser returned v. +func (v *Value) GetArray(keys ...string) []*Value { + v = v.Get(keys...) + if v == nil || v.t != TypeArray { + return nil + } + return v.a +} + +// GetFloat64 returns float64 value by the given keys path. +// +// Array indexes may be represented as decimal numbers in keys. +// +// 0 is returned for non-existing keys path or for invalid value type. +func (v *Value) GetFloat64(keys ...string) float64 { + v = v.Get(keys...) + if v == nil || v.Type() != TypeNumber { + return 0 + } + return fastfloat.ParseBestEffort(v.s) +} + +// GetInt returns int value by the given keys path. +// +// Array indexes may be represented as decimal numbers in keys. +// +// 0 is returned for non-existing keys path or for invalid value type. +func (v *Value) GetInt(keys ...string) int { + v = v.Get(keys...) + if v == nil || v.Type() != TypeNumber { + return 0 + } + n := fastfloat.ParseInt64BestEffort(v.s) + nn := int(n) + if int64(nn) != n { + return 0 + } + return nn +} + +// GetUint returns uint value by the given keys path. +// +// Array indexes may be represented as decimal numbers in keys. +// +// 0 is returned for non-existing keys path or for invalid value type. +func (v *Value) GetUint(keys ...string) uint { + v = v.Get(keys...) + if v == nil || v.Type() != TypeNumber { + return 0 + } + n := fastfloat.ParseUint64BestEffort(v.s) + nn := uint(n) + if uint64(nn) != n { + return 0 + } + return nn +} + +// GetInt64 returns int64 value by the given keys path. +// +// Array indexes may be represented as decimal numbers in keys. +// +// 0 is returned for non-existing keys path or for invalid value type. +func (v *Value) GetInt64(keys ...string) int64 { + v = v.Get(keys...) + if v == nil || v.Type() != TypeNumber { + return 0 + } + return fastfloat.ParseInt64BestEffort(v.s) +} + +// GetUint64 returns uint64 value by the given keys path. +// +// Array indexes may be represented as decimal numbers in keys. +// +// 0 is returned for non-existing keys path or for invalid value type. +func (v *Value) GetUint64(keys ...string) uint64 { + v = v.Get(keys...) + if v == nil || v.Type() != TypeNumber { + return 0 + } + return fastfloat.ParseUint64BestEffort(v.s) +} + +// GetStringBytes returns string value by the given keys path. +// +// Array indexes may be represented as decimal numbers in keys. +// +// nil is returned for non-existing keys path or for invalid value type. +// +// The returned string is valid until Parse is called on the Parser returned v. +func (v *Value) GetStringBytes(keys ...string) []byte { + v = v.Get(keys...) + if v == nil || v.Type() != TypeString { + return nil + } + return s2b(v.s) +} + +// GetBool returns bool value by the given keys path. +// +// Array indexes may be represented as decimal numbers in keys. +// +// false is returned for non-existing keys path or for invalid value type. +func (v *Value) GetBool(keys ...string) bool { + v = v.Get(keys...) + if v != nil && v.t == TypeTrue { + return true + } + return false +} + +// Object returns the underlying JSON object for the v. +// +// The returned object is valid until Parse is called on the Parser returned v. +// +// Use GetObject if you don't need error handling. +func (v *Value) Object() (*Object, error) { + if v.t != TypeObject { + return nil, fmt.Errorf("value doesn't contain object; it contains %s", v.Type()) + } + return &v.o, nil +} + +// Array returns the underlying JSON array for the v. +// +// The returned array is valid until Parse is called on the Parser returned v. +// +// Use GetArray if you don't need error handling. +func (v *Value) Array() ([]*Value, error) { + if v.t != TypeArray { + return nil, fmt.Errorf("value doesn't contain array; it contains %s", v.Type()) + } + return v.a, nil +} + +// StringBytes returns the underlying JSON string for the v. +// +// The returned string is valid until Parse is called on the Parser returned v. +// +// Use GetStringBytes if you don't need error handling. +func (v *Value) StringBytes() ([]byte, error) { + if v.Type() != TypeString { + return nil, fmt.Errorf("value doesn't contain string; it contains %s", v.Type()) + } + return s2b(v.s), nil +} + +// Float64 returns the underlying JSON number for the v. +// +// Use GetFloat64 if you don't need error handling. +func (v *Value) Float64() (float64, error) { + if v.Type() != TypeNumber { + return 0, fmt.Errorf("value doesn't contain number; it contains %s", v.Type()) + } + return fastfloat.Parse(v.s) +} + +// Int returns the underlying JSON int for the v. +// +// Use GetInt if you don't need error handling. +func (v *Value) Int() (int, error) { + if v.Type() != TypeNumber { + return 0, fmt.Errorf("value doesn't contain number; it contains %s", v.Type()) + } + n, err := fastfloat.ParseInt64(v.s) + if err != nil { + return 0, err + } + nn := int(n) + if int64(nn) != n { + return 0, fmt.Errorf("number %q doesn't fit int", v.s) + } + return nn, nil +} + +// Uint returns the underlying JSON uint for the v. +// +// Use GetInt if you don't need error handling. +func (v *Value) Uint() (uint, error) { + if v.Type() != TypeNumber { + return 0, fmt.Errorf("value doesn't contain number; it contains %s", v.Type()) + } + n, err := fastfloat.ParseUint64(v.s) + if err != nil { + return 0, err + } + nn := uint(n) + if uint64(nn) != n { + return 0, fmt.Errorf("number %q doesn't fit uint", v.s) + } + return nn, nil +} + +// Int64 returns the underlying JSON int64 for the v. +// +// Use GetInt64 if you don't need error handling. +func (v *Value) Int64() (int64, error) { + if v.Type() != TypeNumber { + return 0, fmt.Errorf("value doesn't contain number; it contains %s", v.Type()) + } + return fastfloat.ParseInt64(v.s) +} + +// Uint64 returns the underlying JSON uint64 for the v. +// +// Use GetInt64 if you don't need error handling. +func (v *Value) Uint64() (uint64, error) { + if v.Type() != TypeNumber { + return 0, fmt.Errorf("value doesn't contain number; it contains %s", v.Type()) + } + return fastfloat.ParseUint64(v.s) +} + +// Bool returns the underlying JSON bool for the v. +// +// Use GetBool if you don't need error handling. +func (v *Value) Bool() (bool, error) { + if v.t == TypeTrue { + return true, nil + } + if v.t == TypeFalse { + return false, nil + } + return false, fmt.Errorf("value doesn't contain bool; it contains %s", v.Type()) +} + +var ( + valueTrue = &Value{t: TypeTrue} + valueFalse = &Value{t: TypeFalse} + valueNull = &Value{t: TypeNull} +) diff --git a/vendor/github.com/valyala/fastjson/pool.go b/vendor/github.com/valyala/fastjson/pool.go new file mode 100644 index 00000000000..00cfb42fa62 --- /dev/null +++ b/vendor/github.com/valyala/fastjson/pool.go @@ -0,0 +1,52 @@ +package fastjson + +import ( + "sync" +) + +// ParserPool may be used for pooling Parsers for similarly typed JSONs. +type ParserPool struct { + pool sync.Pool +} + +// Get returns a Parser from pp. +// +// The Parser must be Put to pp after use. +func (pp *ParserPool) Get() *Parser { + v := pp.pool.Get() + if v == nil { + return &Parser{} + } + return v.(*Parser) +} + +// Put returns p to pp. +// +// p and objects recursively returned from p cannot be used after p +// is put into pp. +func (pp *ParserPool) Put(p *Parser) { + pp.pool.Put(p) +} + +// ArenaPool may be used for pooling Arenas for similarly typed JSONs. +type ArenaPool struct { + pool sync.Pool +} + +// Get returns an Arena from ap. +// +// The Arena must be Put to ap after use. +func (ap *ArenaPool) Get() *Arena { + v := ap.pool.Get() + if v == nil { + return &Arena{} + } + return v.(*Arena) +} + +// Put returns a to ap. +// +// a and objects created by a cannot be used after a is put into ap. +func (ap *ArenaPool) Put(a *Arena) { + ap.pool.Put(a) +} diff --git a/vendor/github.com/valyala/fastjson/scanner.go b/vendor/github.com/valyala/fastjson/scanner.go new file mode 100644 index 00000000000..89b38816f0a --- /dev/null +++ b/vendor/github.com/valyala/fastjson/scanner.go @@ -0,0 +1,94 @@ +package fastjson + +import ( + "errors" +) + +// Scanner scans a series of JSON values. Values may be delimited by whitespace. +// +// Scanner may parse JSON lines ( http://jsonlines.org/ ). +// +// Scanner may be re-used for subsequent parsing. +// +// Scanner cannot be used from concurrent goroutines. +// +// Use Parser for parsing only a single JSON value. +type Scanner struct { + // b contains a working copy of json value passed to Init. + b []byte + + // s points to the next JSON value to parse. + s string + + // err contains the last error. + err error + + // v contains the last parsed JSON value. + v *Value + + // c is used for caching JSON values. + c cache +} + +// Init initializes sc with the given s. +// +// s may contain multiple JSON values, which may be delimited by whitespace. +func (sc *Scanner) Init(s string) { + sc.b = append(sc.b[:0], s...) + sc.s = b2s(sc.b) + sc.err = nil + sc.v = nil +} + +// InitBytes initializes sc with the given b. +// +// b may contain multiple JSON values, which may be delimited by whitespace. +func (sc *Scanner) InitBytes(b []byte) { + sc.Init(b2s(b)) +} + +// Next parses the next JSON value from s passed to Init. +// +// Returns true on success. The parsed value is available via Value call. +// +// Returns false either on error or on the end of s. +// Call Error in order to determine the cause of the returned false. +func (sc *Scanner) Next() bool { + if sc.err != nil { + return false + } + + sc.s = skipWS(sc.s) + if len(sc.s) == 0 { + sc.err = errEOF + return false + } + + sc.c.reset() + v, tail, err := parseValue(sc.s, &sc.c, 0) + if err != nil { + sc.err = err + return false + } + + sc.s = tail + sc.v = v + return true +} + +// Error returns the last error. +func (sc *Scanner) Error() error { + if sc.err == errEOF { + return nil + } + return sc.err +} + +// Value returns the last parsed value. +// +// The value is valid until the Next call. +func (sc *Scanner) Value() *Value { + return sc.v +} + +var errEOF = errors.New("end of s") diff --git a/vendor/github.com/valyala/fastjson/update.go b/vendor/github.com/valyala/fastjson/update.go new file mode 100644 index 00000000000..f8099bdbb91 --- /dev/null +++ b/vendor/github.com/valyala/fastjson/update.go @@ -0,0 +1,110 @@ +package fastjson + +import ( + "strconv" + "strings" +) + +// Del deletes the entry with the given key from o. +func (o *Object) Del(key string) { + if o == nil { + return + } + if !o.keysUnescaped && strings.IndexByte(key, '\\') < 0 { + // Fast path - try searching for the key without object keys unescaping. + for i, kv := range o.kvs { + if kv.k == key { + o.kvs = append(o.kvs[:i], o.kvs[i+1:]...) + return + } + } + } + + // Slow path - unescape object keys before item search. + o.unescapeKeys() + + for i, kv := range o.kvs { + if kv.k == key { + o.kvs = append(o.kvs[:i], o.kvs[i+1:]...) + return + } + } +} + +// Del deletes the entry with the given key from array or object v. +func (v *Value) Del(key string) { + if v == nil { + return + } + if v.t == TypeObject { + v.o.Del(key) + return + } + if v.t == TypeArray { + n, err := strconv.Atoi(key) + if err != nil || n < 0 || n >= len(v.a) { + return + } + v.a = append(v.a[:n], v.a[n+1:]...) + } +} + +// Set sets (key, value) entry in the o. +// +// The value must be unchanged during o lifetime. +func (o *Object) Set(key string, value *Value) { + if o == nil { + return + } + if value == nil { + value = valueNull + } + o.unescapeKeys() + + // Try substituting already existing entry with the given key. + for i := range o.kvs { + kv := &o.kvs[i] + if kv.k == key { + kv.v = value + return + } + } + + // Add new entry. + kv := o.getKV() + kv.k = key + kv.v = value +} + +// Set sets (key, value) entry in the array or object v. +// +// The value must be unchanged during v lifetime. +func (v *Value) Set(key string, value *Value) { + if v == nil { + return + } + if v.t == TypeObject { + v.o.Set(key, value) + return + } + if v.t == TypeArray { + idx, err := strconv.Atoi(key) + if err != nil || idx < 0 { + return + } + v.SetArrayItem(idx, value) + } +} + +// SetArrayItem sets the value in the array v at idx position. +// +// The value must be unchanged during v lifetime. +func (v *Value) SetArrayItem(idx int, value *Value) { + if v == nil || v.t != TypeArray { + return + } + for idx >= len(v.a) { + v.a = append(v.a, valueNull) + } + v.a[idx] = value +} diff --git a/vendor/github.com/valyala/fastjson/util.go b/vendor/github.com/valyala/fastjson/util.go new file mode 100644 index 00000000000..03a53965a2a --- /dev/null +++ b/vendor/github.com/valyala/fastjson/util.go @@ -0,0 +1,30 @@ +package fastjson + +import ( + "reflect" + "unsafe" +) + +func b2s(b []byte) string { + return *(*string)(unsafe.Pointer(&b)) +} + +func s2b(s string) (b []byte) { + strh := (*reflect.StringHeader)(unsafe.Pointer(&s)) + sh := (*reflect.SliceHeader)(unsafe.Pointer(&b)) + sh.Data = strh.Data + sh.Len = strh.Len + sh.Cap = strh.Len + return b +} + +const maxStartEndStringLen = 80 + +func startEndString(s string) string { + if len(s) <= maxStartEndStringLen { + return s + } + start := s[:40] + end := s[len(s)-40:] + return start + "..." + end +} diff --git a/vendor/github.com/valyala/fastjson/validate.go b/vendor/github.com/valyala/fastjson/validate.go new file mode 100644 index 00000000000..196f1c3dc6c --- /dev/null +++ b/vendor/github.com/valyala/fastjson/validate.go @@ -0,0 +1,308 @@ +package fastjson + +import ( + "fmt" + "strconv" + "strings" +) + +// Validate validates JSON s. +func Validate(s string) error { + s = skipWS(s) + + tail, err := validateValue(s) + if err != nil { + return fmt.Errorf("cannot parse JSON: %s; unparsed tail: %q", err, startEndString(tail)) + } + tail = skipWS(tail) + if len(tail) > 0 { + return fmt.Errorf("unexpected tail: %q", startEndString(tail)) + } + return nil +} + +// ValidateBytes validates JSON b. +func ValidateBytes(b []byte) error { + return Validate(b2s(b)) +} + +func validateValue(s string) (string, error) { + if len(s) == 0 { + return s, fmt.Errorf("cannot parse empty string") + } + + if s[0] == '{' { + tail, err := validateObject(s[1:]) + if err != nil { + return tail, fmt.Errorf("cannot parse object: %s", err) + } + return tail, nil + } + if s[0] == '[' { + tail, err := validateArray(s[1:]) + if err != nil { + return tail, fmt.Errorf("cannot parse array: %s", err) + } + return tail, nil + } + if s[0] == '"' { + sv, tail, err := validateString(s[1:]) + if err != nil { + return tail, fmt.Errorf("cannot parse string: %s", err) + } + // Scan the string for control chars. + for i := 0; i < len(sv); i++ { + if sv[i] < 0x20 { + return tail, fmt.Errorf("string cannot contain control char 0x%02X", sv[i]) + } + } + return tail, nil + } + if s[0] == 't' { + if len(s) < len("true") || s[:len("true")] != "true" { + return s, fmt.Errorf("unexpected value found: %q", s) + } + return s[len("true"):], nil + } + if s[0] == 'f' { + if len(s) < len("false") || s[:len("false")] != "false" { + return s, fmt.Errorf("unexpected value found: %q", s) + } + return s[len("false"):], nil + } + if s[0] == 'n' { + if len(s) < len("null") || s[:len("null")] != "null" { + return s, fmt.Errorf("unexpected value found: %q", s) + } + return s[len("null"):], nil + } + + tail, err := validateNumber(s) + if err != nil { + return tail, fmt.Errorf("cannot parse number: %s", err) + } + return tail, nil +} + +func validateArray(s string) (string, error) { + s = skipWS(s) + if len(s) == 0 { + return s, fmt.Errorf("missing ']'") + } + if s[0] == ']' { + return s[1:], nil + } + + for { + var err error + + s = skipWS(s) + s, err = validateValue(s) + if err != nil { + return s, fmt.Errorf("cannot parse array value: %s", err) + } + + s = skipWS(s) + if len(s) == 0 { + return s, fmt.Errorf("unexpected end of array") + } + if s[0] == ',' { + s = s[1:] + continue + } + if s[0] == ']' { + s = s[1:] + return s, nil + } + return s, fmt.Errorf("missing ',' after array value") + } +} + +func validateObject(s string) (string, error) { + s = skipWS(s) + if len(s) == 0 { + return s, fmt.Errorf("missing '}'") + } + if s[0] == '}' { + return s[1:], nil + } + + for { + var err error + + // Parse key. + s = skipWS(s) + if len(s) == 0 || s[0] != '"' { + return s, fmt.Errorf(`cannot find opening '"" for object key`) + } + + var key string + key, s, err = validateKey(s[1:]) + if err != nil { + return s, fmt.Errorf("cannot parse object key: %s", err) + } + // Scan the key for control chars. + for i := 0; i < len(key); i++ { + if key[i] < 0x20 { + return s, fmt.Errorf("object key cannot contain control char 0x%02X", key[i]) + } + } + s = skipWS(s) + if len(s) == 0 || s[0] != ':' { + return s, fmt.Errorf("missing ':' after object key") + } + s = s[1:] + + // Parse value + s = skipWS(s) + s, err = validateValue(s) + if err != nil { + return s, fmt.Errorf("cannot parse object value: %s", err) + } + s = skipWS(s) + if len(s) == 0 { + return s, fmt.Errorf("unexpected end of object") + } + if s[0] == ',' { + s = s[1:] + continue + } + if s[0] == '}' { + return s[1:], nil + } + return s, fmt.Errorf("missing ',' after object value") + } +} + +// validateKey is similar to validateString, but is optimized +// for typical object keys, which are quite small and have no escape sequences. +func validateKey(s string) (string, string, error) { + for i := 0; i < len(s); i++ { + if s[i] == '"' { + // Fast path - the key doesn't contain escape sequences. + return s[:i], s[i+1:], nil + } + if s[i] == '\\' { + // Slow path - the key contains escape sequences. + return validateString(s) + } + } + return "", s, fmt.Errorf(`missing closing '"'`) +} + +func validateString(s string) (string, string, error) { + // Try fast path - a string without escape sequences. + if n := strings.IndexByte(s, '"'); n >= 0 && strings.IndexByte(s[:n], '\\') < 0 { + return s[:n], s[n+1:], nil + } + + // Slow path - escape sequences are present. + rs, tail, err := parseRawString(s) + if err != nil { + return rs, tail, err + } + for { + n := strings.IndexByte(rs, '\\') + if n < 0 { + return rs, tail, nil + } + n++ + if n >= len(rs) { + return rs, tail, fmt.Errorf("BUG: parseRawString returned invalid string with trailing backslash: %q", rs) + } + ch := rs[n] + rs = rs[n+1:] + switch ch { + case '"', '\\', '/', 'b', 'f', 'n', 'r', 't': + // Valid escape sequences - see http://json.org/ + break + case 'u': + if len(rs) < 4 { + return rs, tail, fmt.Errorf(`too short escape sequence: \u%s`, rs) + } + xs := rs[:4] + _, err := strconv.ParseUint(xs, 16, 16) + if err != nil { + return rs, tail, fmt.Errorf(`invalid escape sequence \u%s: %s`, xs, err) + } + rs = rs[4:] + default: + return rs, tail, fmt.Errorf(`unknown escape sequence \%c`, ch) + } + } +} + +func validateNumber(s string) (string, error) { + if len(s) == 0 { + return s, fmt.Errorf("zero-length number") + } + if s[0] == '-' { + s = s[1:] + if len(s) == 0 { + return s, fmt.Errorf("missing number after minus") + } + } + i := 0 + for i < len(s) { + if s[i] < '0' || s[i] > '9' { + break + } + i++ + } + if i <= 0 { + return s, fmt.Errorf("expecting 0..9 digit, got %c", s[0]) + } + if s[0] == '0' && i != 1 { + return s, fmt.Errorf("unexpected number starting from 0") + } + if i >= len(s) { + return "", nil + } + if s[i] == '.' { + // Validate fractional part + s = s[i+1:] + if len(s) == 0 { + return s, fmt.Errorf("missing fractional part") + } + i = 0 + for i < len(s) { + if s[i] < '0' || s[i] > '9' { + break + } + i++ + } + if i == 0 { + return s, fmt.Errorf("expecting 0..9 digit in fractional part, got %c", s[0]) + } + if i >= len(s) { + return "", nil + } + } + if s[i] == 'e' || s[i] == 'E' { + // Validate exponent part + s = s[i+1:] + if len(s) == 0 { + return s, fmt.Errorf("missing exponent part") + } + if s[0] == '-' || s[0] == '+' { + s = s[1:] + if len(s) == 0 { + return s, fmt.Errorf("missing exponent part") + } + } + i = 0 + for i < len(s) { + if s[i] < '0' || s[i] > '9' { + break + } + i++ + } + if i == 0 { + return s, fmt.Errorf("expecting 0..9 digit in exponent part, got %c", s[0]) + } + if i >= len(s) { + return "", nil + } + } + return s[i:], nil +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 643701bf456..587afe8b123 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -374,6 +374,9 @@ github.com/davidbyttow/govips/v2/vips # github.com/deckarep/golang-set v1.8.0 ## explicit; go 1.17 github.com/deckarep/golang-set +# github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 +## explicit; go 1.17 +github.com/decred/dcrd/dcrec/secp256k1/v4 # github.com/desertbit/timer v1.0.1 ## explicit; go 1.20 github.com/desertbit/timer @@ -883,6 +886,61 @@ github.com/leodido/go-urn/scim/schema ## explicit; go 1.23.5 github.com/leonelquinteros/gotext github.com/leonelquinteros/gotext/plurals +# github.com/lestrrat-go/blackmagic v1.0.4 +## explicit; go 1.23 +github.com/lestrrat-go/blackmagic +# github.com/lestrrat-go/dsig v1.0.0 +## explicit; go 1.23.0 +github.com/lestrrat-go/dsig +github.com/lestrrat-go/dsig/internal/ecutil +# github.com/lestrrat-go/dsig-secp256k1 v1.0.0 +## explicit; go 1.23.0 +github.com/lestrrat-go/dsig-secp256k1 +# github.com/lestrrat-go/httpcc v1.0.1 +## explicit; go 1.16 +github.com/lestrrat-go/httpcc +# github.com/lestrrat-go/httprc/v3 v3.0.1 +## explicit; go 1.23.0 +github.com/lestrrat-go/httprc/v3 +github.com/lestrrat-go/httprc/v3/errsink +github.com/lestrrat-go/httprc/v3/proxysink +github.com/lestrrat-go/httprc/v3/tracesink +# github.com/lestrrat-go/jwx/v3 v3.0.11 +## explicit; go 1.24.4 +github.com/lestrrat-go/jwx/v3 +github.com/lestrrat-go/jwx/v3/cert +github.com/lestrrat-go/jwx/v3/internal/base64 +github.com/lestrrat-go/jwx/v3/internal/ecutil +github.com/lestrrat-go/jwx/v3/internal/json +github.com/lestrrat-go/jwx/v3/internal/jwxio +github.com/lestrrat-go/jwx/v3/internal/keyconv +github.com/lestrrat-go/jwx/v3/internal/pool +github.com/lestrrat-go/jwx/v3/internal/tokens +github.com/lestrrat-go/jwx/v3/jwa +github.com/lestrrat-go/jwx/v3/jwe +github.com/lestrrat-go/jwx/v3/jwe/internal/aescbc +github.com/lestrrat-go/jwx/v3/jwe/internal/cipher +github.com/lestrrat-go/jwx/v3/jwe/internal/concatkdf +github.com/lestrrat-go/jwx/v3/jwe/internal/content_crypt +github.com/lestrrat-go/jwx/v3/jwe/internal/keygen +github.com/lestrrat-go/jwx/v3/jwe/jwebb +github.com/lestrrat-go/jwx/v3/jwk +github.com/lestrrat-go/jwx/v3/jwk/ecdsa +github.com/lestrrat-go/jwx/v3/jwk/jwkbb +github.com/lestrrat-go/jwx/v3/jws +github.com/lestrrat-go/jwx/v3/jws/internal/keytype +github.com/lestrrat-go/jwx/v3/jws/jwsbb +github.com/lestrrat-go/jwx/v3/jws/legacy +github.com/lestrrat-go/jwx/v3/jwt +github.com/lestrrat-go/jwx/v3/jwt/internal/errors +github.com/lestrrat-go/jwx/v3/jwt/internal/types +github.com/lestrrat-go/jwx/v3/transform +# github.com/lestrrat-go/option v1.0.1 +## explicit; go 1.16 +github.com/lestrrat-go/option +# github.com/lestrrat-go/option/v2 v2.0.0 +## explicit; go 1.23 +github.com/lestrrat-go/option/v2 # github.com/libregraph/idm v0.5.0 ## explicit; go 1.21 github.com/libregraph/idm @@ -1142,8 +1200,8 @@ github.com/onsi/gomega/matchers/support/goraph/edge github.com/onsi/gomega/matchers/support/goraph/node github.com/onsi/gomega/matchers/support/goraph/util github.com/onsi/gomega/types -# github.com/open-policy-agent/opa v1.6.0 -## explicit; go 1.23.8 +# github.com/open-policy-agent/opa v1.10.0 +## explicit; go 1.24.6 github.com/open-policy-agent/opa/ast github.com/open-policy-agent/opa/ast/json github.com/open-policy-agent/opa/bundle @@ -1163,12 +1221,6 @@ github.com/open-policy-agent/opa/internal/file/url github.com/open-policy-agent/opa/internal/future github.com/open-policy-agent/opa/internal/gojsonschema github.com/open-policy-agent/opa/internal/json/patch -github.com/open-policy-agent/opa/internal/jwx/buffer -github.com/open-policy-agent/opa/internal/jwx/jwa -github.com/open-policy-agent/opa/internal/jwx/jwk -github.com/open-policy-agent/opa/internal/jwx/jws -github.com/open-policy-agent/opa/internal/jwx/jws/sign -github.com/open-policy-agent/opa/internal/jwx/jws/verify github.com/open-policy-agent/opa/internal/lcss github.com/open-policy-agent/opa/internal/leb128 github.com/open-policy-agent/opa/internal/merge @@ -1739,6 +1791,15 @@ github.com/russross/blackfriday/v2 ## explicit github.com/rwcarlsen/goexif/exif github.com/rwcarlsen/goexif/tiff +# github.com/segmentio/asm v1.2.0 +## explicit; go 1.18 +github.com/segmentio/asm/base64 +github.com/segmentio/asm/cpu +github.com/segmentio/asm/cpu/arm +github.com/segmentio/asm/cpu/arm64 +github.com/segmentio/asm/cpu/cpuid +github.com/segmentio/asm/cpu/x86 +github.com/segmentio/asm/internal/unsafebytes # github.com/segmentio/kafka-go v0.4.49 ## explicit; go 1.23 github.com/segmentio/kafka-go @@ -1821,7 +1882,7 @@ github.com/shurcooL/httpfs/vfsutil # github.com/shurcooL/vfsgen v0.0.0-20230704071429-0000e147ea92 ## explicit; go 1.19 github.com/shurcooL/vfsgen -# github.com/sirupsen/logrus v1.9.3 +# github.com/sirupsen/logrus v1.9.4-0.20230606125235-dd1b4c2e81af ## explicit; go 1.13 github.com/sirupsen/logrus # github.com/skeema/knownhosts v1.3.0 @@ -1835,10 +1896,10 @@ github.com/spacewander/go-suffix-tree github.com/spf13/afero github.com/spf13/afero/internal/common github.com/spf13/afero/mem -# github.com/spf13/cobra v1.9.1 +# github.com/spf13/cobra v1.10.1 ## explicit; go 1.15 github.com/spf13/cobra -# github.com/spf13/pflag v1.0.6 +# github.com/spf13/pflag v1.0.10 ## explicit; go 1.12 github.com/spf13/pflag # github.com/stretchr/objx v0.5.2 @@ -1896,6 +1957,10 @@ github.com/unrolled/secure/cspbuilder # github.com/urfave/cli/v2 v2.27.7 ## explicit; go 1.18 github.com/urfave/cli/v2 +# github.com/valyala/fastjson v1.6.4 +## explicit; go 1.12 +github.com/valyala/fastjson +github.com/valyala/fastjson/fastfloat # github.com/vektah/gqlparser/v2 v2.5.30 ## explicit; go 1.22 github.com/vektah/gqlparser/v2/ast @@ -2105,8 +2170,6 @@ go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc/internal go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc/internal/envconfig go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc/internal/otlpconfig go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc/internal/retry -# go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.37.0 -## explicit; go 1.23.0 # go.opentelemetry.io/otel/metric v1.38.0 ## explicit; go 1.23.0 go.opentelemetry.io/otel/metric @@ -2468,7 +2531,7 @@ gotest.tools/v3/internal/assert gotest.tools/v3/internal/difflib gotest.tools/v3/internal/format gotest.tools/v3/internal/source -# sigs.k8s.io/yaml v1.5.0 +# sigs.k8s.io/yaml v1.6.0 ## explicit; go 1.22 sigs.k8s.io/yaml # stash.kopano.io/kgol/rndm v1.1.2