diff --git a/Cargo.lock b/Cargo.lock index 64ac700e5..496e10acf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,21 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "anyhow" +version = "1.0.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "216261ddc8289130e551ddcd5ce8a064710c0d064a4d2895c67151c92b5443f6" + [[package]] name = "atty" version = "0.2.11" @@ -31,12 +46,27 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array", +] + [[package]] name = "bumpalo" version = "3.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1ad822118d20d2c234f427000d5acc36eabe1e29a348c89b63dd60b13f28e5d" +[[package]] +name = "bytes" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e4cec68f03f32e44924783795810fa50a7035d8c8ebe78580ad7e6c703fba38" + [[package]] name = "bytes" version = "1.2.1" @@ -45,9 +75,9 @@ checksum = "ec8a7b6a70fde80372154c65702f00a0f56f3e1c36abbc6c440484be248856db" [[package]] name = "cc" -version = "1.0.36" +version = "1.0.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0c56216487bb80eec9c4516337b2588a4f2a2290d72a1416d930e4dcdb0c90d" +checksum = "e9f73505338f7d905b19d18738976aae232eb46b8efc15554ffc56deb5d9ebe4" [[package]] name = "cfg-if" @@ -63,13 +93,17 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.6" +version = "0.4.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45912881121cb26fad7c38c17ba7daa18764771836b34fab7d3fbd93ed633878" +checksum = "16b0a3d9ed01224b22057780a37bb8c5dbfe1be8ba48678e7bf57ec4b385411f" dependencies = [ + "iana-time-zone", + "js-sys", "num-integer", "num-traits", - "time", + "time 0.1.44", + "wasm-bindgen", + "winapi", ] [[package]] @@ -95,9 +129,9 @@ checksum = "db342ce9fda24fb191e2ed4e102055a4d381c1086a06630174cd8da8d5d917ce" dependencies = [ "heck", "proc-macro-error", - "proc-macro2 1.0.46", - "quote 1.0.21", - "syn 1.0.101", + "proc-macro2", + "quote", + "syn", ] [[package]] @@ -109,6 +143,24 @@ dependencies = [ "os_str_bytes", ] +[[package]] +name = "codespan-reporting" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" +dependencies = [ + "termcolor", + "unicode-width", +] + +[[package]] +name = "compute-static" +version = "0.1.0" +dependencies = [ + "fastly", + "log", +] + [[package]] name = "core-foundation" version = "0.9.3" @@ -125,6 +177,15 @@ version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" +[[package]] +name = "cpufeatures" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320" +dependencies = [ + "libc", +] + [[package]] name = "curl" version = "0.4.35" @@ -155,6 +216,59 @@ dependencies = [ "winapi", ] +[[package]] +name = "cxx" +version = "1.0.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4a41a86530d0fe7f5d9ea779916b7cadd2d4f9add748b99c2c029cbbdfaf453" +dependencies = [ + "cc", + "cxxbridge-flags", + "cxxbridge-macro", + "link-cplusplus", +] + +[[package]] +name = "cxx-build" +version = "1.0.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06416d667ff3e3ad2df1cd8cd8afae5da26cf9cec4d0825040f88b5ca659a2f0" +dependencies = [ + "cc", + "codespan-reporting", + "once_cell", + "proc-macro2", + "quote", + "scratch", + "syn", +] + +[[package]] +name = "cxxbridge-flags" +version = "1.0.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "820a9a2af1669deeef27cb271f476ffd196a2c4b6731336011e0ba63e2c7cf71" + +[[package]] +name = "cxxbridge-macro" +version = "1.0.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a08a6e2fcc370a089ad3b4aaf54db3b1b4cee38ddabce5896b33eb693275f470" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + [[package]] name = "encoding_rs" version = "0.8.17" @@ -164,6 +278,62 @@ dependencies = [ "cfg-if 0.1.7", ] +[[package]] +name = "fastly" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d14ee2f12a3191582449a2e080287eff8898fc52da61c437869d91c41b3ae2a" +dependencies = [ + "anyhow", + "bytes 0.5.6", + "cfg-if 1.0.0", + "fastly-macros", + "fastly-shared", + "fastly-sys", + "http", + "lazy_static", + "mime", + "serde", + "serde_json", + "serde_urlencoded", + "sha2", + "thiserror", + "time 0.3.17", + "url", +] + +[[package]] +name = "fastly-macros" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3d1b2980c09148cb84bfd18591943ee449a350dc1ff1ead69edbf012f7e2eef" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "fastly-shared" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f79939bdbbab8b1de759d584f386319454f8623681400675a07f9ad35f2b158" +dependencies = [ + "bitflags", + "http", + "thiserror", +] + +[[package]] +name = "fastly-sys" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d01e98274a6b12c85c0eef22924871cc12c54b5322268947322463e59d09336" +dependencies = [ + "bitflags", + "fastly-shared", +] + [[package]] name = "fastrand" version = "1.8.0" @@ -251,13 +421,23 @@ dependencies = [ "slab", ] +[[package]] +name = "generic-array" +version = "0.14.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" +dependencies = [ + "typenum", + "version_check", +] + [[package]] name = "h2" version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ca32592cf21ac7ccab1825cd87f6c9b3d9022c44d086172ed0966bec8af30be" dependencies = [ - "bytes", + "bytes 1.2.1", "fnv", "futures-core", "futures-sink", @@ -297,9 +477,9 @@ version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75f43d41e26995c17e71ee126451dd3941010b0514a81a9d11f3b341debc2399" dependencies = [ - "bytes", + "bytes 1.2.1", "fnv", - "itoa 1.0.3", + "itoa", ] [[package]] @@ -308,7 +488,7 @@ version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" dependencies = [ - "bytes", + "bytes 1.2.1", "http", "pin-project-lite", ] @@ -331,7 +511,7 @@ version = "0.14.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "02c929dc5c39e335a03c405292728118860721b10190d98c2a0f0efd5baafbac" dependencies = [ - "bytes", + "bytes 1.2.1", "futures-channel", "futures-core", "futures-util", @@ -340,7 +520,7 @@ dependencies = [ "http-body", "httparse", "httpdate", - "itoa 1.0.3", + "itoa", "pin-project-lite", "socket2 0.4.7", "tokio", @@ -355,13 +535,37 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" dependencies = [ - "bytes", + "bytes 1.2.1", "hyper", "native-tls", "tokio", "tokio-native-tls", ] +[[package]] +name = "iana-time-zone" +version = "0.1.53" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64c122667b287044802d6ce17ee2ddf13207ed924c712de9a66a5814d5b64765" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "winapi", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0703ae284fc167426161c2e3f1da3ea71d94b21bedbcc9494e92b28e334e3dca" +dependencies = [ + "cxx", + "cxx-build", +] + [[package]] name = "idna" version = "0.3.0" @@ -397,12 +601,6 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "879d54834c8c76457ef4293a689b2a8c59b076067ad77b15efafbb05f92a592b" -[[package]] -name = "itoa" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" - [[package]] name = "itoa" version = "1.0.3" @@ -442,6 +640,15 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "link-cplusplus" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9272ab7b96c9046fbc5bc56c06c117cb639fe2d509df0c421cad82d2915cf369" +dependencies = [ + "cc", +] + [[package]] name = "log" version = "0.4.17" @@ -459,9 +666,9 @@ checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" [[package]] name = "memchr" -version = "2.2.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2efc7bc57c883d4a4d6e3246905283d8dae951bb3bd32f49d6ef297f546e1c39" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" [[package]] name = "mime" @@ -475,9 +682,9 @@ version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a63337614a1d280fdb2880599af563c99e9f388757f8d6515d785d85d14fb01" dependencies = [ - "proc-macro2 1.0.46", - "quote 1.0.21", - "syn 1.0.101", + "proc-macro2", + "quote", + "syn", ] [[package]] @@ -486,9 +693,9 @@ version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f4313e4a66a442473e181963daf8c1e9def85c2d9fb0bb2ae59444260b28285" dependencies = [ - "itoa 1.0.3", + "itoa", "mini-internal", - "ryu 1.0.11", + "ryu", ] [[package]] @@ -499,7 +706,7 @@ checksum = "57ee1c23c7c63b0c9250c339ffdc69255f110b298b901b9f6c82547b7b87caaf" dependencies = [ "libc", "log", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", "windows-sys", ] @@ -558,6 +765,12 @@ version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e82dad04139b71a90c080c8463fe0dc7902db5192d939bd0950f074d014339e1" +[[package]] +name = "opaque-debug" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" + [[package]] name = "openssl" version = "0.10.42" @@ -579,9 +792,9 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b501e44f11665960c7e7fcf062c7d96a14ade4aa98116c004b2e37b5be7d736c" dependencies = [ - "proc-macro2 1.0.46", - "quote 1.0.21", - "syn 1.0.101", + "proc-macro2", + "quote", + "syn", ] [[package]] @@ -640,9 +853,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" dependencies = [ "proc-macro-error-attr", - "proc-macro2 1.0.46", - "quote 1.0.21", - "syn 1.0.101", + "proc-macro2", + "quote", + "syn", "version_check", ] @@ -652,20 +865,11 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" dependencies = [ - "proc-macro2 1.0.46", - "quote 1.0.21", + "proc-macro2", + "quote", "version_check", ] -[[package]] -name = "proc-macro2" -version = "0.4.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64c827cea7a7ab30ce4593e5e04d7a11617ad6ece2fa230605a78b00ff965316" -dependencies = [ - "unicode-xid", -] - [[package]] name = "proc-macro2" version = "1.0.46" @@ -675,22 +879,13 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "quote" -version = "0.6.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "faf4799c5d274f3868a4aae320a0a182cbd2baee377b378f080e16a23e9d80db" -dependencies = [ - "proc-macro2 0.4.29", -] - [[package]] name = "quote" version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" dependencies = [ - "proc-macro2 1.0.46", + "proc-macro2", ] [[package]] @@ -733,7 +928,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "431949c384f4e2ae07605ccaa56d1d9d2ecdb5cadd4f9577ccfab29f2e5149fc" dependencies = [ "base64", - "bytes", + "bytes 1.2.1", "encoding_rs", "futures-core", "futures-util", @@ -763,12 +958,6 @@ dependencies = [ "winreg", ] -[[package]] -name = "ryu" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b96a9549dc8d48f2c283938303c4b5a77aa29bfbc5b54b084fb1630408899a8f" - [[package]] name = "ryu" version = "1.0.11" @@ -785,6 +974,12 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "scratch" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8132065adcfd6e02db789d9285a0deb2f3fcb04002865ab67d5fb103533898" + [[package]] name = "security-framework" version = "2.7.0" @@ -810,32 +1005,32 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.91" +version = "1.0.147" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a72e9b96fa45ce22a4bc23da3858dfccfd60acd28a25bcd328a98fdd6bea43fd" +checksum = "d193d69bae983fc11a79df82342761dfbf28a99fc8d203dca4c3c1b590948965" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.91" +version = "1.0.147" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "101b495b109a3e3ca8c4cbe44cf62391527cdfb6ba15821c5ce80bcd5ea23f9f" +checksum = "4f1d362ca8fc9c3e3a7484440752472d68a6caa98f1ab81d99b5dfe517cec852" dependencies = [ - "proc-macro2 0.4.29", - "quote 0.6.12", - "syn 0.15.33", + "proc-macro2", + "quote", + "syn", ] [[package]] name = "serde_json" -version = "1.0.39" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a23aa71d4a4d43fdbfaac00eff68ba8a06a51759a89ac3304323e800c4dd40d" +checksum = "020ff22c755c2ed3f8cf162dbb41a7268d934702f3ed3631656ea597e08fc3db" dependencies = [ - "itoa 0.4.4", - "ryu 0.2.8", + "itoa", + "ryu", "serde", ] @@ -846,8 +1041,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" dependencies = [ "form_urlencoded", - "itoa 1.0.3", - "ryu 1.0.11", + "itoa", + "ryu", "serde", ] @@ -863,6 +1058,19 @@ dependencies = [ "serde_json", ] +[[package]] +name = "sha2" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +dependencies = [ + "block-buffer", + "cfg-if 1.0.0", + "cpufeatures", + "digest", + "opaque-debug", +] + [[package]] name = "slab" version = "0.4.2" @@ -896,25 +1104,14 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" -[[package]] -name = "syn" -version = "0.15.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec52cd796e5f01d0067225a5392e70084acc4c0013fa71d55166d38a8b307836" -dependencies = [ - "proc-macro2 0.4.29", - "quote 0.6.12", - "unicode-xid", -] - [[package]] name = "syn" version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e90cde112c4b9690b8cbe810cba9ddd8bc1d7472e2cae317b69e9438c1cba7d2" dependencies = [ - "proc-macro2 1.0.46", - "quote 1.0.21", + "proc-macro2", + "quote", "unicode-ident", ] @@ -962,17 +1159,63 @@ dependencies = [ "redox_termios", ] +[[package]] +name = "thiserror" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "time" -version = "0.1.42" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" +checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" dependencies = [ "libc", - "redox_syscall 0.1.54", + "wasi 0.10.0+wasi-snapshot-preview1", "winapi", ] +[[package]] +name = "time" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a561bf4617eebd33bca6434b988f39ed798e527f51a1e797d0ee4f61c0a38376" +dependencies = [ + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd" + +[[package]] +name = "time-macros" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d967f99f534ca7e495c575c62638eebc2898a8c84c119b89e250477bc4ba16b2" +dependencies = [ + "time-core", +] + [[package]] name = "tinyvec" version = "1.6.0" @@ -995,7 +1238,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a9e03c497dc955702ba729190dc4aac6f2a0ce97f913e5b1b5912fc5039d9099" dependencies = [ "autocfg", - "bytes", + "bytes 1.2.1", "libc", "memchr", "mio", @@ -1021,7 +1264,7 @@ version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0bb2e075f03b3d66d8d8785356224ba688d2906a371015e225beeb65ca92c740" dependencies = [ - "bytes", + "bytes 1.2.1", "futures-core", "futures-sink", "pin-project-lite", @@ -1061,6 +1304,12 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e604eb7b43c06650e854be16a2a03155743d3752dd1c943f6829e26b7a36e382" +[[package]] +name = "typenum" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" + [[package]] name = "unicode-bidi" version = "0.3.4" @@ -1086,10 +1335,10 @@ dependencies = [ ] [[package]] -name = "unicode-xid" -version = "0.1.0" +name = "unicode-width" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" +checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" [[package]] name = "url" @@ -1124,6 +1373,12 @@ dependencies = [ "try-lock", ] +[[package]] +name = "wasi" +version = "0.10.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" + [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" @@ -1149,9 +1404,9 @@ dependencies = [ "bumpalo", "log", "once_cell", - "proc-macro2 1.0.46", - "quote 1.0.21", - "syn 1.0.101", + "proc-macro2", + "quote", + "syn", "wasm-bindgen-shared", ] @@ -1173,7 +1428,7 @@ version = "0.2.83" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810" dependencies = [ - "quote 1.0.21", + "quote", "wasm-bindgen-macro-support", ] @@ -1183,9 +1438,9 @@ version = "0.2.83" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" dependencies = [ - "proc-macro2 1.0.46", - "quote 1.0.21", - "syn 1.0.101", + "proc-macro2", + "quote", + "syn", "wasm-bindgen-backend", "wasm-bindgen-shared", ] diff --git a/Cargo.toml b/Cargo.toml index 3ae9e2d4e..7a14a1ad2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,4 +2,5 @@ members = [ "setup-deploy-keys", "ansible/roles/dev-desktop/files/team_login", + "terraform/crates-io/compute-static" ] diff --git a/terraform/crates-io/compute-static/.cargo/config b/terraform/crates-io/compute-static/.cargo/config new file mode 100644 index 000000000..6b77899cb --- /dev/null +++ b/terraform/crates-io/compute-static/.cargo/config @@ -0,0 +1,2 @@ +[build] +target = "wasm32-wasi" diff --git a/terraform/crates-io/compute-static/.gitignore b/terraform/crates-io/compute-static/.gitignore new file mode 100644 index 000000000..9f6a0890d --- /dev/null +++ b/terraform/crates-io/compute-static/.gitignore @@ -0,0 +1,4 @@ +/target +**/*.rs.bk +/bin +/pkg diff --git a/terraform/crates-io/compute-static/Cargo.lock b/terraform/crates-io/compute-static/Cargo.lock new file mode 100644 index 000000000..c51de1b15 --- /dev/null +++ b/terraform/crates-io/compute-static/Cargo.lock @@ -0,0 +1,394 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "anyhow" +version = "1.0.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98161a4e3e2184da77bb14f02184cdd111e83bbbcc9979dfee3c44b9a85f5602" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bytes" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e4cec68f03f32e44924783795810fa50a7035d8c8ebe78580ad7e6c703fba38" + +[[package]] +name = "bytes" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec8a7b6a70fde80372154c65702f00a0f56f3e1c36abbc6c440484be248856db" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cpufeatures" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320" +dependencies = [ + "libc", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + +[[package]] +name = "fastly" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac81708c039cd2f95e09f3b700d36b46976de382dd47cf46e3f18a51aa70427d" +dependencies = [ + "anyhow", + "bytes 0.5.6", + "fastly-macros", + "fastly-shared", + "fastly-sys", + "http", + "lazy_static", + "mime", + "serde", + "serde_json", + "serde_urlencoded", + "sha2", + "thiserror", + "time", + "url", +] + +[[package]] +name = "fastly-compute-project" +version = "0.1.0" +dependencies = [ + "fastly", +] + +[[package]] +name = "fastly-macros" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99060e78d03bd1436bd4055c54cc5c62b1926e9c894b9bf00c40e8e5c276fd99" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "fastly-shared" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "238fb7af2219391cb024673302861adffd96cb3dbe4b602c2c7abef11ce5a5f9" +dependencies = [ + "bitflags", + "http", + "thiserror", +] + +[[package]] +name = "fastly-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa50606a08d3ee623033013d063e1843c5cb8c928fce3bd0f2c8ce4eaa460d8d" +dependencies = [ + "bitflags", + "fastly-shared", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "form_urlencoded" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "generic-array" +version = "0.14.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "http" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75f43d41e26995c17e71ee126451dd3941010b0514a81a9d11f3b341debc2399" +dependencies = [ + "bytes 1.2.1", + "fnv", + "itoa", +] + +[[package]] +name = "idna" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "itoa" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c8af84674fe1f223a982c933a0ee1086ac4d4052aa0fb8060c12c6ad838e754" + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.134" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "329c933548736bc49fd575ee68c89e8be4d260064184389a5b77517cddd99ffb" + +[[package]] +name = "mime" +version = "0.3.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" + +[[package]] +name = "num_threads" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44" +dependencies = [ + "libc", +] + +[[package]] +name = "opaque-debug" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" + +[[package]] +name = "percent-encoding" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" + +[[package]] +name = "proc-macro2" +version = "1.0.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94e2ef8dbfc347b10c094890f778ee2e36ca9bb4262e86dc99cd217e35f3470b" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "ryu" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09" + +[[package]] +name = "serde" +version = "1.0.145" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728eb6351430bccb993660dfffc5a72f91ccc1295abaa8ce19b27ebe4f75568b" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.145" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81fa1584d3d1bcacd84c277a0dfe21f5b0f6accf4a23d04d4c6d61f1af522b4c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.85" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e55a28e3aaef9d5ce0506d0a14dbba8054ddc7e499ef522dd8b26859ec9d4a44" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sha2" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +dependencies = [ + "block-buffer", + "cfg-if", + "cpufeatures", + "digest", + "opaque-debug", +] + +[[package]] +name = "syn" +version = "1.0.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e90cde112c4b9690b8cbe810cba9ddd8bc1d7472e2cae317b69e9438c1cba7d2" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "time" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c3f9a28b618c3a6b9251b6908e9c99e04b9e5c02e6581ccbb67d59c34ef7f9b" +dependencies = [ + "libc", + "num_threads", + "serde", +] + +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" + +[[package]] +name = "typenum" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" + +[[package]] +name = "unicode-bidi" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" + +[[package]] +name = "unicode-ident" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcc811dc4066ac62f84f11307873c4850cb653bfa9b1719cee2bd2204a4bc5dd" + +[[package]] +name = "unicode-normalization" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "url" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" diff --git a/terraform/crates-io/compute-static/Cargo.toml b/terraform/crates-io/compute-static/Cargo.toml new file mode 100644 index 000000000..7bceffcba --- /dev/null +++ b/terraform/crates-io/compute-static/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "compute-static" +description = "Compute@Edge function for static.crates.io" +version = "0.1.0" +edition = "2021" + +publish = false + +[profile.release] +debug = 1 + +[dependencies] +fastly = "0.8.9" +log = "0.4.17" diff --git a/terraform/crates-io/compute-static/README.md b/terraform/crates-io/compute-static/README.md new file mode 100644 index 000000000..e09907949 --- /dev/null +++ b/terraform/crates-io/compute-static/README.md @@ -0,0 +1,35 @@ +# Compute@Edge Function for `static.crates.io` + +We are using a [Compute@Edge](https://docs.fastly.com/en/guides/compute-at-edge) +function on [Fastly](https://fastly.com) to route incoming traffic for +`static.crates.io` to S3. The function tries to get crates from the primary +bucket, and will fail-over to a fallback if it receives any HTTP `5xx` +responses. + +## Deployment + +After making changes to the function, make sure to build a new release package +and update the hash in [`fastly-static.tf`](../impl/fastly-static.tf). We +manually update the hash to prevent accidentally overwriting the function. + +Build the function: + +```shell +cd compute-static +fastly compute build +``` + +Calculate the hash: + +```shell +cd compute-static +fastly compute hashsum +``` + +Copy the hash and paste it into [`fastly-static.tf`](../impl/fastly-static.tf). +Then run Terraform as usual. + +```shell +export FASTLY_API_KEY="" +terraform plan +``` diff --git a/terraform/crates-io/compute-static/fastly.toml b/terraform/crates-io/compute-static/fastly.toml new file mode 100644 index 000000000..d67ae4d58 --- /dev/null +++ b/terraform/crates-io/compute-static/fastly.toml @@ -0,0 +1,12 @@ +# This file describes a Fastly Compute@Edge package. To learn more visit: +# https://developer.fastly.com/reference/fastly-toml/ + +authors = ["infra@rust-lang.org"] +description = "Compute@Edge function for static.crates.io" +language = "rust" +manifest_version = 2 +name = "compute-static" +service_id = "" + +[scripts] + build = "cargo build --bin compute-static --release --target wasm32-wasi --color always" diff --git a/terraform/crates-io/compute-static/rust-toolchain.toml b/terraform/crates-io/compute-static/rust-toolchain.toml new file mode 100644 index 000000000..5914a5625 --- /dev/null +++ b/terraform/crates-io/compute-static/rust-toolchain.toml @@ -0,0 +1,3 @@ +[toolchain] +channel = "stable" +targets = [ "wasm32-wasi" ] diff --git a/terraform/crates-io/compute-static/src/config.rs b/terraform/crates-io/compute-static/src/config.rs new file mode 100644 index 000000000..2f981f171 --- /dev/null +++ b/terraform/crates-io/compute-static/src/config.rs @@ -0,0 +1,35 @@ +use fastly::ConfigStore; + +// Name of the dictionary. Must match the dictionary in `fastly-static.tf`. +const DICTIONARY_NAME: &str = "compute_static"; + +// Name of the dictionary item with the name of the primary host. +const PRIMARY_HOST: &str = "s3-primary-host"; + +// Name of the dictionary item with the name of the fallback host. +const FALLBACK_HOST: &str = "s3-fallback-host"; + +#[derive(Debug)] +pub struct Config { + pub primary_host: String, + pub fallback_host: String, +} + +impl Config { + pub fn from_dictionary() -> Self { + let dictionary = ConfigStore::open(DICTIONARY_NAME); + + // Lookup S3 hosts for current environment + let primary_host = dictionary + .get(PRIMARY_HOST) + .expect("failed to get S3 primary host from dictionary"); + let fallback_host = dictionary + .get(FALLBACK_HOST) + .expect("failed to get S3 fallback host from dictionary"); + + Self { + primary_host, + fallback_host, + } + } +} diff --git a/terraform/crates-io/compute-static/src/main.rs b/terraform/crates-io/compute-static/src/main.rs new file mode 100644 index 000000000..8b8c39cf8 --- /dev/null +++ b/terraform/crates-io/compute-static/src/main.rs @@ -0,0 +1,60 @@ +use fastly::http::{Method, StatusCode}; +use fastly::{Error, Request, Response}; +use log::warn; + +use crate::config::Config; + +mod config; + +#[fastly::main] +fn main(request: Request) -> Result { + let config = Config::from_dictionary(); + + if let Some(response) = limit_http_methods(&request) { + return Ok(response); + } + + send_request_to_s3(&config, &request) +} + +/// Limit HTTP methods +/// +/// Clients are only allowed to request resources using GET and HEAD requests. If any other HTTP +/// method is received, HTTP 403 Unauthorized is returned. +/// +/// We don't return HTTP 405 Method Not Allowed to maintain parity with CloudFront. +fn limit_http_methods(request: &Request) -> Option { + let method = request.get_method(); + + if method != Method::GET && method != Method::HEAD { + return Some( + Response::from_body("Method not allowed").with_status(StatusCode::UNAUTHORIZED), + ); + } + + None +} + +/// Forward client request to S3 +/// +/// The request that was received by the client is forwarded to S3. First, the primary bucket is +/// queried. If the response indicates a server issue (status code >= 500), the request is sent to +/// a fallback bucket in a different geographical region. +fn send_request_to_s3(config: &Config, request: &Request) -> Result { + let primary_request = request.clone_without_body(); + + let mut response = primary_request.send(&config.primary_host)?; + let status_code = response.get_status().as_u16(); + + if status_code >= 500 { + warn!( + "Request to host {} returned status code {}", + config.primary_host, status_code + ); + + let fallback_request = request.clone_without_body(); + response = fallback_request.send(&config.fallback_host)?; + } + + Ok(response) +} diff --git a/terraform/crates-io/envs.tf b/terraform/crates-io/envs.tf index 0229dd058..ece53e9ba 100644 --- a/terraform/crates-io/envs.tf +++ b/terraform/crates-io/envs.tf @@ -47,3 +47,7 @@ module "staging" { strict_security_headers = true } + +output "dns_challenge" { + value = module.staging.dns_challenges +} diff --git a/terraform/crates-io/impl/fastly-static.tf b/terraform/crates-io/impl/fastly-static.tf index 0c87e60c7..ba3eba746 100644 --- a/terraform/crates-io/impl/fastly-static.tf +++ b/terraform/crates-io/impl/fastly-static.tf @@ -1,4 +1,11 @@ -resource "fastly_service_vcl" "static" { +locals { + primary_host_name = aws_s3_bucket.static.region + fallback_host_name = aws_s3_bucket.fallback.region + dictionary_name = "compute_static" + package_path = "./compute-static/pkg/compute-static.tar.gz" +} + +resource "fastly_service_compute" "static" { name = var.static_domain_name domain { @@ -6,14 +13,52 @@ resource "fastly_service_vcl" "static" { } backend { + # Must be identical to s3-primary-host item in dictionary + name = local.primary_host_name + address = aws_s3_bucket.static.bucket_regional_domain_name - name = aws_s3_bucket.static.region override_host = aws_s3_bucket.static.bucket_regional_domain_name use_ssl = true port = 443 ssl_cert_hostname = aws_s3_bucket.static.bucket_regional_domain_name } + + backend { + # Must be identical to s3-fallback-host item in dictionary + name = local.fallback_host_name + + address = aws_s3_bucket.fallback.bucket_regional_domain_name + override_host = aws_s3_bucket.fallback.bucket_regional_domain_name + + use_ssl = true + port = 443 + ssl_cert_hostname = aws_s3_bucket.fallback.bucket_regional_domain_name + } + + dictionary { + name = local.dictionary_name + } + + package { + filename = local.package_path + source_code_hash = filesha512(local.package_path) + } +} + +resource "fastly_service_dictionary_items" "compute_static" { + for_each = { + for d in fastly_service_compute.static.dictionary : d.name => d if d.name == local.dictionary_name + } + + service_id = fastly_service_compute.static.id + dictionary_id = each.value.dictionary_id + manage_items = true + + items = { + "s3-primary-host" : local.primary_host_name + "s3-fallback-host" : local.fallback_host_name + } } resource "fastly_tls_subscription" "static" { @@ -24,17 +69,11 @@ resource "fastly_tls_subscription" "static" { resource "aws_route53_record" "static_tls_validation" { depends_on = [fastly_tls_subscription.static] - for_each = { - for challenge in fastly_tls_subscription.static.managed_dns_challenges : - trimprefix(challenge.record_name, "_acme-challenge.") => challenge - } - - # only reads the first element in the list since all elements are exactly the same (see above) - name = each.value[0].record_name - type = each.value[0].record_type + name = fastly_tls_subscription.static.managed_dns_challenge.record_name + type = fastly_tls_subscription.static.managed_dns_challenge.record_type zone_id = data.aws_route53_zone.static.id allow_overwrite = true - records = [each.value[0].record_value] + records = [fastly_tls_subscription.static.managed_dns_challenge.record_value] ttl = 60 } @@ -42,3 +81,7 @@ resource "fastly_tls_subscription_validation" "static" { depends_on = [aws_route53_record.static_tls_validation] subscription_id = fastly_tls_subscription.static.id } + +output "dns_challenges" { + value = fastly_tls_subscription.static.managed_dns_challenges +}