From df8612e35519bbeaeb21fd51eba4c6d963510039 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Fri, 12 Mar 2021 14:20:25 -0500 Subject: [PATCH] Start work on multi-version support, test cleanup (#43) * some cleanup * start work on multi-version support * undelete some old examples, can update them later * move old examples --- .gitignore | 10 +- data/{ => 1.16.201}/biome_definitions.nbt | Bin data/{ => 1.16.201}/creativeitems.json | 0 .../{newproto.json => 1.16.201/protocol.json} | 0 data/1.16.201/skin_geom.txt | 1 + data/new/compile.js | 37 +- data/new/packet_map.yml | 317 --- data/new/proto.yml | 9 +- data/protocol.json | 2517 ----------------- data/provider.js | 45 + {samples => examples}/clientTest.js | 0 examples/createRelay.js | 38 + examples/{ => old}/chunk | Bin examples/{ => old}/client.js | 0 examples/{ => old}/deserialize.js | 0 examples/{ => old}/server.js | 0 examples/{ => old}/server_simple.js | 0 {samples => examples}/serverTest.js | 43 +- src/auth/chains.js | 32 +- src/auth/encryption.js | 7 +- src/auth/tests/encrypt.js | 232 -- src/auth/tests/encryptTest.js | 88 - src/auth/tests/jwtTest.js | 49 - src/client.js | 98 +- src/client/auth.js | 49 +- src/connection.js | 66 +- src/datatypes/promises.js | 12 - src/datatypes/util.js | 37 + src/options.js | 12 +- src/rak.js | 47 +- src/relay.js | 48 +- src/server.js | 23 +- src/serverPlayer.js | 17 +- src/transforms/encryption.js | 26 +- src/transforms/serializer.js | 27 +- 35 files changed, 369 insertions(+), 3518 deletions(-) rename data/{ => 1.16.201}/biome_definitions.nbt (100%) rename data/{ => 1.16.201}/creativeitems.json (100%) rename data/{newproto.json => 1.16.201/protocol.json} (100%) create mode 100644 data/1.16.201/skin_geom.txt delete mode 100644 data/new/packet_map.yml delete mode 100644 data/protocol.json create mode 100644 data/provider.js rename {samples => examples}/clientTest.js (100%) create mode 100644 examples/createRelay.js rename examples/{ => old}/chunk (100%) rename examples/{ => old}/client.js (100%) rename examples/{ => old}/deserialize.js (100%) rename examples/{ => old}/server.js (100%) rename examples/{ => old}/server_simple.js (100%) rename {samples => examples}/serverTest.js (69%) delete mode 100644 src/auth/tests/encrypt.js delete mode 100644 src/auth/tests/encryptTest.js delete mode 100644 src/auth/tests/jwtTest.js delete mode 100644 src/datatypes/promises.js create mode 100644 src/datatypes/util.js diff --git a/.gitignore b/.gitignore index f7f9591..2f39796 100644 --- a/.gitignore +++ b/.gitignore @@ -2,7 +2,11 @@ node_modules/ npm-debug.log package-lock.json __* -data/*.js src/**/*.json -src/**/*.txt -dist/ \ No newline at end of file +# Runtime generated data +data/*/sample +data/**/read.js +data/**/write.js +data/**/size.js +samples/*.txt +samples/*.json \ No newline at end of file diff --git a/data/biome_definitions.nbt b/data/1.16.201/biome_definitions.nbt similarity index 100% rename from data/biome_definitions.nbt rename to data/1.16.201/biome_definitions.nbt diff --git a/data/creativeitems.json b/data/1.16.201/creativeitems.json similarity index 100% rename from data/creativeitems.json rename to data/1.16.201/creativeitems.json diff --git a/data/newproto.json b/data/1.16.201/protocol.json similarity index 100% rename from data/newproto.json rename to data/1.16.201/protocol.json diff --git a/data/1.16.201/skin_geom.txt b/data/1.16.201/skin_geom.txt new file mode 100644 index 0000000..0c3cd70 --- /dev/null +++ b/data/1.16.201/skin_geom.txt @@ -0,0 +1 @@ +ewogICAiZm9ybWF0X3ZlcnNpb24iIDogIjEuMTQuMCIsCiAgICJtaW5lY3JhZnQ6Z2VvbWV0cnkiIDogWwogICAgICB7CiAgICAgICAgICJib25lcyIgOiBbCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgIm5hbWUiIDogImJlbHQiLAogICAgICAgICAgICAgICAicGFyZW50IiA6ICJib2R5IiwKICAgICAgICAgICAgICAgInBpdm90IiA6IFsgMC4wLCAyNC4wLCAwLjAgXQogICAgICAgICAgICB9LAogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICJsb2NhdG9ycyIgOiB7CiAgICAgICAgICAgICAgICAgICJhcm1vcl9vZmZzZXQuZGVmYXVsdF9uZWNrIiA6IFsgMC4wLCAyNC4wLCAwLjAgXQogICAgICAgICAgICAgICB9LAogICAgICAgICAgICAgICAibmFtZSIgOiAiYm9keSIsCiAgICAgICAgICAgICAgICJwYXJlbnQiIDogIndhaXN0IiwKICAgICAgICAgICAgICAgInBpdm90IiA6IFsgMC4wLCAyNC4wLCAwLjAgXQogICAgICAgICAgICB9LAogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICJuYW1lIiA6ICJib2R5YXJtb3IiLAogICAgICAgICAgICAgICAicGFyZW50IiA6ICJib2R5IiwKICAgICAgICAgICAgICAgInBpdm90IiA6IFsgMC4wLCAyNC4wLCAwLjAgXQogICAgICAgICAgICB9LAogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICJuYW1lIiA6ICJoZWFkIiwKICAgICAgICAgICAgICAgInBhcmVudCIgOiAiYm9keSIsCiAgICAgICAgICAgICAgICJwaXZvdCIgOiBbIDAuMCwgMjQuMCwgMC4wIF0KICAgICAgICAgICAgfSwKICAgICAgICAgICAgewogICAgICAgICAgICAgICAibmFtZSIgOiAiaGVsbWV0IiwKICAgICAgICAgICAgICAgInBhcmVudCIgOiAiaGVhZCIsCiAgICAgICAgICAgICAgICJwaXZvdCIgOiBbIDAuMCwgMjQuMCwgMC4wIF0KICAgICAgICAgICAgfSwKICAgICAgICAgICAgewogICAgICAgICAgICAgICAibmFtZSIgOiAibGVmdGFybSIsCiAgICAgICAgICAgICAgICJwYXJlbnQiIDogImJvZHkiLAogICAgICAgICAgICAgICAicGl2b3QiIDogWyA1LjAsIDIyLjAsIDAuMCBdCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgIm1pcnJvciIgOiB0cnVlLAogICAgICAgICAgICAgICAibmFtZSIgOiAibGVmdGFybWFybW9yIiwKICAgICAgICAgICAgICAgInBhcmVudCIgOiAibGVmdGFybSIsCiAgICAgICAgICAgICAgICJwaXZvdCIgOiBbIDUuMCwgMjIuMCwgMC4wIF0KICAgICAgICAgICAgfSwKICAgICAgICAgICAgewogICAgICAgICAgICAgICAibWlycm9yIiA6IHRydWUsCiAgICAgICAgICAgICAgICJuYW1lIiA6ICJsZWZ0Ym9vdCIsCiAgICAgICAgICAgICAgICJwYXJlbnQiIDogImxlZnRsZWciLAogICAgICAgICAgICAgICAicGl2b3QiIDogWyAxLjg5OTk5OTk3NjE1ODE0MiwgMTIuMCwgMC4wIF0KICAgICAgICAgICAgfSwKICAgICAgICAgICAgewogICAgICAgICAgICAgICAibmFtZSIgOiAibGVmdGl0ZW0iLAogICAgICAgICAgICAgICAicGFyZW50IiA6ICJsZWZ0YXJtIiwKICAgICAgICAgICAgICAgInBpdm90IiA6IFsgNi4wLCAxNS4wLCAwLjAgXQogICAgICAgICAgICB9LAogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICJuYW1lIiA6ICJsZWZ0bGVnIiwKICAgICAgICAgICAgICAgInBhcmVudCIgOiAicm9vdCIsCiAgICAgICAgICAgICAgICJwaXZvdCIgOiBbIDEuODk5OTk5OTc2MTU4MTQyLCAxMi4wLCAwLjAgXQogICAgICAgICAgICB9LAogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICJtaXJyb3IiIDogdHJ1ZSwKICAgICAgICAgICAgICAgIm5hbWUiIDogImxlZnRsZWdnaW5nIiwKICAgICAgICAgICAgICAgInBhcmVudCIgOiAibGVmdGxlZyIsCiAgICAgICAgICAgICAgICJwaXZvdCIgOiBbIDEuODk5OTk5OTc2MTU4MTQyLCAxMi4wLCAwLjAgXQogICAgICAgICAgICB9LAogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICJtaXJyb3IiIDogdHJ1ZSwKICAgICAgICAgICAgICAgIm5hbWUiIDogImxlZnRzb2NrIiwKICAgICAgICAgICAgICAgInBhcmVudCIgOiAibGVmdGxlZyIsCiAgICAgICAgICAgICAgICJwaXZvdCIgOiBbIDEuODk5OTk5OTc2MTU4MTQyLCAxMi4wLCAwLjAgXQogICAgICAgICAgICB9LAogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICJuYW1lIiA6ICJyaWdodGFybSIsCiAgICAgICAgICAgICAgICJwYXJlbnQiIDogImJvZHkiLAogICAgICAgICAgICAgICAicGl2b3QiIDogWyAtNS4wLCAyMi4wLCAwLjAgXQogICAgICAgICAgICB9LAogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICJuYW1lIiA6ICJyaWdodGFybWFybW9yIiwKICAgICAgICAgICAgICAgInBhcmVudCIgOiAicmlnaHRhcm0iLAogICAgICAgICAgICAgICAicGl2b3QiIDogWyAtNS4wLCAyMi4wLCAwLjAgXQogICAgICAgICAgICB9LAogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICJuYW1lIiA6ICJyaWdodGJvb3QiLAogICAgICAgICAgICAgICAicGFyZW50IiA6ICJyaWdodGxlZyIsCiAgICAgICAgICAgICAgICJwaXZvdCIgOiBbIC0xLjg5OTk5OTk3NjE1ODE0MiwgMTIuMCwgMC4wIF0KICAgICAgICAgICAgfSwKICAgICAgICAgICAgewogICAgICAgICAgICAgICAibG9jYXRvcnMiIDogewogICAgICAgICAgICAgICAgICAibGVhZF9ob2xkIiA6IFsgLTYuMCwgMTUuMCwgMC4wIF0KICAgICAgICAgICAgICAgfSwKICAgICAgICAgICAgICAgIm5hbWUiIDogInJpZ2h0aXRlbSIsCiAgICAgICAgICAgICAgICJwYXJlbnQiIDogInJpZ2h0YXJtIiwKICAgICAgICAgICAgICAgInBpdm90IiA6IFsgLTYuMCwgMTUuMCwgMC4wIF0KICAgICAgICAgICAgfSwKICAgICAgICAgICAgewogICAgICAgICAgICAgICAibmFtZSIgOiAicmlnaHRsZWciLAogICAgICAgICAgICAgICAicGFyZW50IiA6ICJyb290IiwKICAgICAgICAgICAgICAgInBpdm90IiA6IFsgLTEuODk5OTk5OTc2MTU4MTQyLCAxMi4wLCAwLjAgXQogICAgICAgICAgICB9LAogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICJuYW1lIiA6ICJyaWdodGxlZ2dpbmciLAogICAgICAgICAgICAgICAicGFyZW50IiA6ICJyaWdodGxlZyIsCiAgICAgICAgICAgICAgICJwaXZvdCIgOiBbIC0xLjg5OTk5OTk3NjE1ODE0MiwgMTIuMCwgMC4wIF0KICAgICAgICAgICAgfSwKICAgICAgICAgICAgewogICAgICAgICAgICAgICAibmFtZSIgOiAicmlnaHRzb2NrIiwKICAgICAgICAgICAgICAgInBhcmVudCIgOiAicmlnaHRsZWciLAogICAgICAgICAgICAgICAicGl2b3QiIDogWyAtMS44OTk5OTk5NzYxNTgxNDIsIDEyLjAsIDAuMCBdCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgIm5hbWUiIDogInJvb3QiCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgIm5hbWUiIDogIndhaXN0IiwKICAgICAgICAgICAgICAgInBhcmVudCIgOiAicm9vdCIsCiAgICAgICAgICAgICAgICJwaXZvdCIgOiBbIDAuMCwgMTIuMCwgMC4wIF0KICAgICAgICAgICAgfQogICAgICAgICBdLAogICAgICAgICAiZGVzY3JpcHRpb24iIDogewogICAgICAgICAgICAiaWRlbnRpZmllciIgOiAiZ2VvbWV0cnkucGVyc29uYV9lMTk5NjcyYThjMWE4N2UwLTAiLAogICAgICAgICAgICAidGV4dHVyZV9oZWlnaHQiIDogMS4wLAogICAgICAgICAgICAidGV4dHVyZV93aWR0aCIgOiAxLjAKICAgICAgICAgfQogICAgICB9LAogICAgICB7CiAgICAgICAgICJib25lcyIgOiBbCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgIm5hbWUiIDogImJlbHQiLAogICAgICAgICAgICAgICAicGFyZW50IiA6ICJib2R5IiwKICAgICAgICAgICAgICAgInBpdm90IiA6IFsgMC4wLCAyNC4wLCAwLjAgXQogICAgICAgICAgICB9LAogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICJsb2NhdG9ycyIgOiB7CiAgICAgICAgICAgICAgICAgICJhcm1vcl9vZmZzZXQuZGVmYXVsdF9uZWNrIiA6IFsgMC4wLCAyNC4wLCAwLjAgXQogICAgICAgICAgICAgICB9LAogICAgICAgICAgICAgICAibmFtZSIgOiAiYm9keSIsCiAgICAgICAgICAgICAgICJwYXJlbnQiIDogIndhaXN0IiwKICAgICAgICAgICAgICAgInBpdm90IiA6IFsgMC4wLCAyNC4wLCAwLjAgXSwKICAgICAgICAgICAgICAgInBvbHlfbWVzaCIgOiB7CiAgICAgICAgICAgICAgICAgICJub3JtYWxpemVkX3V2cyIgOiB0cnVlLAogICAgICAgICAgICAgICAgICAibm9ybWFscyIgOiBbCiAgICAgICAgICAgICAgICAgICAgIFsgMC4wLCAxLjAsIDAuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMCwgLTEuMCwgMC4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTEuMCwgMC4wLCAwLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAxLjAsIDAuMCwgMC4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4wLCAwLjAsIC0xLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjAsIDAuMCwgMS4wIF0KICAgICAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAgICAgInBvbHlzIiA6IFsKICAgICAgICAgICAgICAgICAgICAgWwogICAgICAgICAgICAgICAgICAgICAgICBbIDAsIDAsIDAgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAxLCAwLCAxIF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMiwgMCwgMiBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDMsIDAsIDMgXQogICAgICAgICAgICAgICAgICAgICBdLAogICAgICAgICAgICAgICAgICAgICBbCiAgICAgICAgICAgICAgICAgICAgICAgIFsgNCwgMSwgNCBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDUsIDEsIDUgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyA2LCAxLCA2IF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgNywgMSwgNyBdCiAgICAgICAgICAgICAgICAgICAgIF0sCiAgICAgICAgICAgICAgICAgICAgIFsKICAgICAgICAgICAgICAgICAgICAgICAgWyA4LCAyLCA4IF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgOSwgMiwgOSBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDEwLCAyLCAxMCBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDExLCAyLCAxMSBdCiAgICAgICAgICAgICAgICAgICAgIF0sCiAgICAgICAgICAgICAgICAgICAgIFsKICAgICAgICAgICAgICAgICAgICAgICAgWyAxMiwgMywgMTIgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAxMywgMywgMTMgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAxNCwgMywgMTQgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAxNSwgMywgMTUgXQogICAgICAgICAgICAgICAgICAgICBdLAogICAgICAgICAgICAgICAgICAgICBbCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMTYsIDQsIDE2IF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMTcsIDQsIDE3IF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMTgsIDQsIDE4IF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMTksIDQsIDE5IF0KICAgICAgICAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAgICAgICAgWwogICAgICAgICAgICAgICAgICAgICAgICBbIDIwLCA1LCAyMCBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDIxLCA1LCAyMSBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDIyLCA1LCAyMiBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDIzLCA1LCAyMyBdCiAgICAgICAgICAgICAgICAgICAgIF0KICAgICAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAgICAgInBvc2l0aW9ucyIgOiBbCiAgICAgICAgICAgICAgICAgICAgIFsgLTQuMCwgMjQuMCwgLTIuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDQuMCwgMjQuMCwgLTIuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDQuMCwgMjQuMCwgMi4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTQuMCwgMjQuMCwgMi4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTQuMCwgMTIuMCwgMi4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgNC4wLCAxMi4wLCAyLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyA0LjAsIDEyLjAsIC0yLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtNC4wLCAxMi4wLCAtMi4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTQuMCwgMTIuMCwgMi4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTQuMCwgMTIuMCwgLTIuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIC00LjAsIDI0LjAsIC0yLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtNC4wLCAyNC4wLCAyLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyA0LjAsIDEyLjAsIC0yLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyA0LjAsIDEyLjAsIDIuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDQuMCwgMjQuMCwgMi4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgNC4wLCAyNC4wLCAtMi4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTQuMCwgMTIuMCwgLTIuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDQuMCwgMTIuMCwgLTIuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDQuMCwgMjQuMCwgLTIuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIC00LjAsIDI0LjAsIC0yLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyA0LjAsIDEyLjAsIDIuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIC00LjAsIDEyLjAsIDIuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIC00LjAsIDI0LjAsIDIuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDQuMCwgMjQuMCwgMi4wIF0KICAgICAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAgICAgInV2cyIgOiBbCiAgICAgICAgICAgICAgICAgICAgIFsgMC4xNTYyNTAsIDAuOTk4MDQ2ODc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMjE4NzUwLCAwLjk5ODA0Njg3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjIxODc1MCwgMS4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4xNTYyNTAsIDEuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMjgxMjUwLCAxLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjIxODc1MCwgMS4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4yMTg3NTAsIDAuOTk4MDQ2ODc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMjgxMjUwLCAwLjk5ODA0Njg3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjEyNTAsIDAuOTkyMTg3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjE1NjI1MCwgMC45OTIxODc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMTU2MjUwLCAwLjk5ODA0Njg3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjEyNTAsIDAuOTk4MDQ2ODc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMjE4NzUwLCAwLjk5MjE4NzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4yNTAsIDAuOTkyMTg3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjI1MCwgMC45OTgwNDY4NzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4yMTg3NTAsIDAuOTk4MDQ2ODc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMTU2MjUwLCAwLjk5MjE4NzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4yMTg3NTAsIDAuOTkyMTg3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjIxODc1MCwgMC45OTgwNDY4NzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4xNTYyNTAsIDAuOTk4MDQ2ODc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMjUwLCAwLjk5MjE4NzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4zMTI1MCwgMC45OTIxODc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMzEyNTAsIDAuOTk4MDQ2ODc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMjUwLCAwLjk5ODA0Njg3NTAgXQogICAgICAgICAgICAgICAgICBdCiAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfSwKICAgICAgICAgICAgewogICAgICAgICAgICAgICAibmFtZSIgOiAiYm9keWFybW9yIiwKICAgICAgICAgICAgICAgInBhcmVudCIgOiAiYm9keSIsCiAgICAgICAgICAgICAgICJwaXZvdCIgOiBbIDAuMCwgMjQuMCwgMC4wIF0KICAgICAgICAgICAgfSwKICAgICAgICAgICAgewogICAgICAgICAgICAgICAibmFtZSIgOiAiaGVhZCIsCiAgICAgICAgICAgICAgICJwYXJlbnQiIDogImJvZHkiLAogICAgICAgICAgICAgICAicGl2b3QiIDogWyAwLjAsIDI0LjAsIDAuMCBdCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgIm5hbWUiIDogImhlbG1ldCIsCiAgICAgICAgICAgICAgICJwYXJlbnQiIDogImhlYWQiLAogICAgICAgICAgICAgICAicGl2b3QiIDogWyAwLjAsIDI0LjAsIDAuMCBdCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgIm5hbWUiIDogImphY2tldCIsCiAgICAgICAgICAgICAgICJwYXJlbnQiIDogImJvZHkiLAogICAgICAgICAgICAgICAicGl2b3QiIDogWyAwLjAsIDI0LjAsIDAuMCBdLAogICAgICAgICAgICAgICAicG9seV9tZXNoIiA6IHsKICAgICAgICAgICAgICAgICAgIm5vcm1hbGl6ZWRfdXZzIiA6IHRydWUsCiAgICAgICAgICAgICAgICAgICJub3JtYWxzIiA6IFsKICAgICAgICAgICAgICAgICAgICAgWyAwLjAsIDEuMCwgMC4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4wLCAtMS4wLCAwLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtMS4wLCAwLjAsIDAuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDEuMCwgMC4wLCAwLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjAsIDAuMCwgLTEuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMCwgMC4wLCAxLjAgXQogICAgICAgICAgICAgICAgICBdLAogICAgICAgICAgICAgICAgICAicG9seXMiIDogWwogICAgICAgICAgICAgICAgICAgICBbCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMCwgMCwgMCBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDEsIDAsIDEgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAyLCAwLCAyIF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMywgMCwgMyBdCiAgICAgICAgICAgICAgICAgICAgIF0sCiAgICAgICAgICAgICAgICAgICAgIFsKICAgICAgICAgICAgICAgICAgICAgICAgWyA0LCAxLCA0IF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgNSwgMSwgNSBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDYsIDEsIDYgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyA3LCAxLCA3IF0KICAgICAgICAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAgICAgICAgWwogICAgICAgICAgICAgICAgICAgICAgICBbIDgsIDIsIDggXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyA5LCAyLCA5IF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMTAsIDIsIDEwIF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMTEsIDIsIDExIF0KICAgICAgICAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAgICAgICAgWwogICAgICAgICAgICAgICAgICAgICAgICBbIDEyLCAzLCAxMiBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDEzLCAzLCAxMyBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDE0LCAzLCAxNCBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDE1LCAzLCAxNSBdCiAgICAgICAgICAgICAgICAgICAgIF0sCiAgICAgICAgICAgICAgICAgICAgIFsKICAgICAgICAgICAgICAgICAgICAgICAgWyAxNiwgNCwgMTYgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAxNywgNCwgMTcgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAxOCwgNCwgMTggXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAxOSwgNCwgMTkgXQogICAgICAgICAgICAgICAgICAgICBdLAogICAgICAgICAgICAgICAgICAgICBbCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMjAsIDUsIDIwIF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMjEsIDUsIDIxIF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMjIsIDUsIDIyIF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMjMsIDUsIDIzIF0KICAgICAgICAgICAgICAgICAgICAgXQogICAgICAgICAgICAgICAgICBdLAogICAgICAgICAgICAgICAgICAicG9zaXRpb25zIiA6IFsKICAgICAgICAgICAgICAgICAgICAgWyAtNC4yNTAsIDI0LjI1MCwgLTIuMjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgNC4yNTAsIDI0LjI1MCwgLTIuMjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgNC4yNTAsIDI0LjI1MCwgMi4yNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtNC4yNTAsIDI0LjI1MCwgMi4yNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtNC4yNTAsIDExLjc1MCwgMi4yNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyA0LjI1MCwgMTEuNzUwLCAyLjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDQuMjUwLCAxMS43NTAsIC0yLjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIC00LjI1MCwgMTEuNzUwLCAtMi4yNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtNC4yNTAsIDExLjc1MCwgMi4yNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtNC4yNTAsIDExLjc1MCwgLTIuMjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTQuMjUwLCAyNC4yNTAsIC0yLjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIC00LjI1MCwgMjQuMjUwLCAyLjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDQuMjUwLCAxMS43NTAsIC0yLjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDQuMjUwLCAxMS43NTAsIDIuMjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgNC4yNTAsIDI0LjI1MCwgMi4yNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyA0LjI1MCwgMjQuMjUwLCAtMi4yNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtNC4yNTAsIDExLjc1MCwgLTIuMjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgNC4yNTAsIDExLjc1MCwgLTIuMjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgNC4yNTAsIDI0LjI1MCwgLTIuMjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTQuMjUwLCAyNC4yNTAsIC0yLjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDQuMjUwLCAxMS43NTAsIDIuMjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTQuMjUwLCAxMS43NTAsIDIuMjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTQuMjUwLCAyNC4yNTAsIDIuMjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgNC4yNTAsIDI0LjI1MCwgMi4yNTAgXQogICAgICAgICAgICAgICAgICBdLAogICAgICAgICAgICAgICAgICAidXZzIiA6IFsKICAgICAgICAgICAgICAgICAgICAgWyAwLjE1NjI1MCwgMC45OTAyMzQzNzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4yMTg3NTAsIDAuOTkwMjM0Mzc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMjE4NzUwLCAwLjk5MjE4NzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4xNTYyNTAsIDAuOTkyMTg3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjI4MTI1MCwgMC45OTIxODc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMjE4NzUwLCAwLjk5MjE4NzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4yMTg3NTAsIDAuOTkwMjM0Mzc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMjgxMjUwLCAwLjk5MDIzNDM3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjEyNTAsIDAuOTg0Mzc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMTU2MjUwLCAwLjk4NDM3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjE1NjI1MCwgMC45OTAyMzQzNzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4xMjUwLCAwLjk5MDIzNDM3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjIxODc1MCwgMC45ODQzNzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4yNTAsIDAuOTg0Mzc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMjUwLCAwLjk5MDIzNDM3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjIxODc1MCwgMC45OTAyMzQzNzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4xNTYyNTAsIDAuOTg0Mzc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMjE4NzUwLCAwLjk4NDM3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjIxODc1MCwgMC45OTAyMzQzNzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4xNTYyNTAsIDAuOTkwMjM0Mzc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMjUwLCAwLjk4NDM3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjMxMjUwLCAwLjk4NDM3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjMxMjUwLCAwLjk5MDIzNDM3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjI1MCwgMC45OTAyMzQzNzUwIF0KICAgICAgICAgICAgICAgICAgXQogICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgIm5hbWUiIDogImxlZnRhcm0iLAogICAgICAgICAgICAgICAicGFyZW50IiA6ICJib2R5IiwKICAgICAgICAgICAgICAgInBpdm90IiA6IFsgNS4wLCAyMi4wLCAwLjAgXSwKICAgICAgICAgICAgICAgInBvbHlfbWVzaCIgOiB7CiAgICAgICAgICAgICAgICAgICJub3JtYWxpemVkX3V2cyIgOiB0cnVlLAogICAgICAgICAgICAgICAgICAibm9ybWFscyIgOiBbCiAgICAgICAgICAgICAgICAgICAgIFsgMC4wLCAxLjAsIDAuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMCwgLTEuMCwgMC4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTEuMCwgMC4wLCAwLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAxLjAsIDAuMCwgMC4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4wLCAwLjAsIC0xLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjAsIDAuMCwgMS4wIF0KICAgICAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAgICAgInBvbHlzIiA6IFsKICAgICAgICAgICAgICAgICAgICAgWwogICAgICAgICAgICAgICAgICAgICAgICBbIDAsIDAsIDAgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAxLCAwLCAxIF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMiwgMCwgMiBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDMsIDAsIDMgXQogICAgICAgICAgICAgICAgICAgICBdLAogICAgICAgICAgICAgICAgICAgICBbCiAgICAgICAgICAgICAgICAgICAgICAgIFsgNCwgMSwgNCBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDUsIDEsIDUgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyA2LCAxLCA2IF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgNywgMSwgNyBdCiAgICAgICAgICAgICAgICAgICAgIF0sCiAgICAgICAgICAgICAgICAgICAgIFsKICAgICAgICAgICAgICAgICAgICAgICAgWyA4LCAyLCA4IF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgOSwgMiwgOSBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDEwLCAyLCAxMCBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDExLCAyLCAxMSBdCiAgICAgICAgICAgICAgICAgICAgIF0sCiAgICAgICAgICAgICAgICAgICAgIFsKICAgICAgICAgICAgICAgICAgICAgICAgWyAxMiwgMywgMTIgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAxMywgMywgMTMgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAxNCwgMywgMTQgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAxNSwgMywgMTUgXQogICAgICAgICAgICAgICAgICAgICBdLAogICAgICAgICAgICAgICAgICAgICBbCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMTYsIDQsIDE2IF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMTcsIDQsIDE3IF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMTgsIDQsIDE4IF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMTksIDQsIDE5IF0KICAgICAgICAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAgICAgICAgWwogICAgICAgICAgICAgICAgICAgICAgICBbIDIwLCA1LCAyMCBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDIxLCA1LCAyMSBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDIyLCA1LCAyMiBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDIzLCA1LCAyMyBdCiAgICAgICAgICAgICAgICAgICAgIF0KICAgICAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAgICAgInBvc2l0aW9ucyIgOiBbCiAgICAgICAgICAgICAgICAgICAgIFsgNC4wLCAyNC4wLCAtMi4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgOC4wLCAyNC4wLCAtMi4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgOC4wLCAyNC4wLCAyLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyA0LjAsIDI0LjAsIDIuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDQuMCwgMTIuMCwgMi4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgOC4wLCAxMi4wLCAyLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyA4LjAsIDEyLjAsIC0yLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyA0LjAsIDEyLjAsIC0yLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyA0LjAsIDEyLjAsIDIuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDQuMCwgMTIuMCwgLTIuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDQuMCwgMjQuMCwgLTIuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDQuMCwgMjQuMCwgMi4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgOC4wLCAxMi4wLCAtMi4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgOC4wLCAxMi4wLCAyLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyA4LjAsIDI0LjAsIDIuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDguMCwgMjQuMCwgLTIuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDQuMCwgMTIuMCwgLTIuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDguMCwgMTIuMCwgLTIuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDguMCwgMjQuMCwgLTIuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDQuMCwgMjQuMCwgLTIuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDguMCwgMTIuMCwgMi4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgNC4wLCAxMi4wLCAyLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyA0LjAsIDI0LjAsIDIuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDguMCwgMjQuMCwgMi4wIF0KICAgICAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAgICAgInV2cyIgOiBbCiAgICAgICAgICAgICAgICAgICAgIFsgMC4zNDM3NTAsIDAuOTk4MDQ2ODc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMzc1MCwgMC45OTgwNDY4NzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4zNzUwLCAxLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjM0Mzc1MCwgMS4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC40MDYyNTAsIDEuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMzc1MCwgMS4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4zNzUwLCAwLjk5ODA0Njg3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjQwNjI1MCwgMC45OTgwNDY4NzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4zMTI1MCwgMC45OTIxODc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMzQzNzUwLCAwLjk5MjE4NzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4zNDM3NTAsIDAuOTk4MDQ2ODc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMzEyNTAsIDAuOTk4MDQ2ODc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMzc1MCwgMC45OTIxODc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuNDA2MjUwLCAwLjk5MjE4NzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC40MDYyNTAsIDAuOTk4MDQ2ODc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMzc1MCwgMC45OTgwNDY4NzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4zNDM3NTAsIDAuOTkyMTg3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjM3NTAsIDAuOTkyMTg3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjM3NTAsIDAuOTk4MDQ2ODc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMzQzNzUwLCAwLjk5ODA0Njg3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjQwNjI1MCwgMC45OTIxODc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuNDM3NTAsIDAuOTkyMTg3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjQzNzUwLCAwLjk5ODA0Njg3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjQwNjI1MCwgMC45OTgwNDY4NzUwIF0KICAgICAgICAgICAgICAgICAgXQogICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgIm1pcnJvciIgOiB0cnVlLAogICAgICAgICAgICAgICAibmFtZSIgOiAibGVmdGFybWFybW9yIiwKICAgICAgICAgICAgICAgInBhcmVudCIgOiAibGVmdGFybSIsCiAgICAgICAgICAgICAgICJwaXZvdCIgOiBbIDUuMCwgMjIuMCwgMC4wIF0KICAgICAgICAgICAgfSwKICAgICAgICAgICAgewogICAgICAgICAgICAgICAibWlycm9yIiA6IHRydWUsCiAgICAgICAgICAgICAgICJuYW1lIiA6ICJsZWZ0Ym9vdCIsCiAgICAgICAgICAgICAgICJwYXJlbnQiIDogImxlZnRsZWciLAogICAgICAgICAgICAgICAicGl2b3QiIDogWyAxLjg5OTk5OTk3NjE1ODE0MiwgMTIuMCwgMC4wIF0KICAgICAgICAgICAgfSwKICAgICAgICAgICAgewogICAgICAgICAgICAgICAibmFtZSIgOiAibGVmdGl0ZW0iLAogICAgICAgICAgICAgICAicGFyZW50IiA6ICJsZWZ0YXJtIiwKICAgICAgICAgICAgICAgInBpdm90IiA6IFsgNi4wLCAxNS4wLCAwLjAgXQogICAgICAgICAgICB9LAogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICJuYW1lIiA6ICJsZWZ0bGVnIiwKICAgICAgICAgICAgICAgInBhcmVudCIgOiAicm9vdCIsCiAgICAgICAgICAgICAgICJwaXZvdCIgOiBbIDEuODk5OTk5OTc2MTU4MTQyLCAxMi4wLCAwLjAgXSwKICAgICAgICAgICAgICAgInBvbHlfbWVzaCIgOiB7CiAgICAgICAgICAgICAgICAgICJub3JtYWxpemVkX3V2cyIgOiB0cnVlLAogICAgICAgICAgICAgICAgICAibm9ybWFscyIgOiBbCiAgICAgICAgICAgICAgICAgICAgIFsgMC4wLCAxLjAsIDAuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMCwgLTEuMCwgMC4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTEuMCwgMC4wLCAwLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAxLjAsIDAuMCwgMC4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4wLCAwLjAsIC0xLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjAsIDAuMCwgMS4wIF0KICAgICAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAgICAgInBvbHlzIiA6IFsKICAgICAgICAgICAgICAgICAgICAgWwogICAgICAgICAgICAgICAgICAgICAgICBbIDAsIDAsIDAgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAxLCAwLCAxIF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMiwgMCwgMiBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDMsIDAsIDMgXQogICAgICAgICAgICAgICAgICAgICBdLAogICAgICAgICAgICAgICAgICAgICBbCiAgICAgICAgICAgICAgICAgICAgICAgIFsgNCwgMSwgNCBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDUsIDEsIDUgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyA2LCAxLCA2IF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgNywgMSwgNyBdCiAgICAgICAgICAgICAgICAgICAgIF0sCiAgICAgICAgICAgICAgICAgICAgIFsKICAgICAgICAgICAgICAgICAgICAgICAgWyA4LCAyLCA4IF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgOSwgMiwgOSBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDEwLCAyLCAxMCBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDExLCAyLCAxMSBdCiAgICAgICAgICAgICAgICAgICAgIF0sCiAgICAgICAgICAgICAgICAgICAgIFsKICAgICAgICAgICAgICAgICAgICAgICAgWyAxMiwgMywgMTIgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAxMywgMywgMTMgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAxNCwgMywgMTQgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAxNSwgMywgMTUgXQogICAgICAgICAgICAgICAgICAgICBdLAogICAgICAgICAgICAgICAgICAgICBbCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMTYsIDQsIDE2IF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMTcsIDQsIDE3IF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMTgsIDQsIDE4IF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMTksIDQsIDE5IF0KICAgICAgICAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAgICAgICAgWwogICAgICAgICAgICAgICAgICAgICAgICBbIDIwLCA1LCAyMCBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDIxLCA1LCAyMSBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDIyLCA1LCAyMiBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDIzLCA1LCAyMyBdCiAgICAgICAgICAgICAgICAgICAgIF0KICAgICAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAgICAgInBvc2l0aW9ucyIgOiBbCiAgICAgICAgICAgICAgICAgICAgIFsgLTAuMTAwMDAwMDAxNDkwMTE2MSwgMTIuMCwgLTIuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDMuOTAwMDAwMDk1MzY3NDMyLCAxMi4wLCAtMi4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMy45MDAwMDAwOTUzNjc0MzIsIDEyLjAsIDIuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIC0wLjEwMDAwMDAwMTQ5MDExNjEsIDEyLjAsIDIuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIC0wLjEwMDAwMDAwMTQ5MDExNjEsIDAuMCwgMi4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMy45MDAwMDAwOTUzNjc0MzIsIDAuMCwgMi4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMy45MDAwMDAwOTUzNjc0MzIsIDAuMCwgLTIuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIC0wLjEwMDAwMDAwMTQ5MDExNjEsIDAuMCwgLTIuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIC0wLjEwMDAwMDAwMTQ5MDExNjEsIDAuMCwgMi4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTAuMTAwMDAwMDAxNDkwMTE2MSwgMC4wLCAtMi4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTAuMTAwMDAwMDAxNDkwMTE2MSwgMTIuMCwgLTIuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIC0wLjEwMDAwMDAwMTQ5MDExNjEsIDEyLjAsIDIuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDMuOTAwMDAwMDk1MzY3NDMyLCAwLjAsIC0yLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAzLjkwMDAwMDA5NTM2NzQzMiwgMC4wLCAyLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAzLjkwMDAwMDA5NTM2NzQzMiwgMTIuMCwgMi4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMy45MDAwMDAwOTUzNjc0MzIsIDEyLjAsIC0yLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtMC4xMDAwMDAwMDE0OTAxMTYxLCAwLjAsIC0yLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAzLjkwMDAwMDA5NTM2NzQzMiwgMC4wLCAtMi4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMy45MDAwMDAwOTUzNjc0MzIsIDEyLjAsIC0yLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtMC4xMDAwMDAwMDE0OTAxMTYxLCAxMi4wLCAtMi4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMy45MDAwMDAwOTUzNjc0MzIsIDAuMCwgMi4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTAuMTAwMDAwMDAxNDkwMTE2MSwgMC4wLCAyLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtMC4xMDAwMDAwMDE0OTAxMTYxLCAxMi4wLCAyLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAzLjkwMDAwMDA5NTM2NzQzMiwgMTIuMCwgMi4wIF0KICAgICAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAgICAgInV2cyIgOiBbCiAgICAgICAgICAgICAgICAgICAgIFsgMC4yODEyNTAsIDAuOTgyNDIxODc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMzEyNTAsIDAuOTgyNDIxODc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMzEyNTAsIDAuOTg0Mzc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMjgxMjUwLCAwLjk4NDM3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjM0Mzc1MCwgMC45ODQzNzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4zMTI1MCwgMC45ODQzNzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4zMTI1MCwgMC45ODI0MjE4NzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4zNDM3NTAsIDAuOTgyNDIxODc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMjUwLCAwLjk3NjU2MjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4yODEyNTAsIDAuOTc2NTYyNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjI4MTI1MCwgMC45ODI0MjE4NzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4yNTAsIDAuOTgyNDIxODc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMzEyNTAsIDAuOTc2NTYyNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjM0Mzc1MCwgMC45NzY1NjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMzQzNzUwLCAwLjk4MjQyMTg3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjMxMjUwLCAwLjk4MjQyMTg3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjI4MTI1MCwgMC45NzY1NjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMzEyNTAsIDAuOTc2NTYyNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjMxMjUwLCAwLjk4MjQyMTg3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjI4MTI1MCwgMC45ODI0MjE4NzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4zNDM3NTAsIDAuOTc2NTYyNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjM3NTAsIDAuOTc2NTYyNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjM3NTAsIDAuOTgyNDIxODc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMzQzNzUwLCAwLjk4MjQyMTg3NTAgXQogICAgICAgICAgICAgICAgICBdCiAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfSwKICAgICAgICAgICAgewogICAgICAgICAgICAgICAibWlycm9yIiA6IHRydWUsCiAgICAgICAgICAgICAgICJuYW1lIiA6ICJsZWZ0bGVnZ2luZyIsCiAgICAgICAgICAgICAgICJwYXJlbnQiIDogImxlZnRsZWciLAogICAgICAgICAgICAgICAicGl2b3QiIDogWyAxLjg5OTk5OTk3NjE1ODE0MiwgMTIuMCwgMC4wIF0KICAgICAgICAgICAgfSwKICAgICAgICAgICAgewogICAgICAgICAgICAgICAibmFtZSIgOiAibGVmdHBhbnRzIiwKICAgICAgICAgICAgICAgInBhcmVudCIgOiAibGVmdGxlZyIsCiAgICAgICAgICAgICAgICJwaXZvdCIgOiBbIDEuODk5OTk5OTc2MTU4MTQyLCAxMi4wLCAwLjAgXSwKICAgICAgICAgICAgICAgInBvbHlfbWVzaCIgOiB7CiAgICAgICAgICAgICAgICAgICJub3JtYWxpemVkX3V2cyIgOiB0cnVlLAogICAgICAgICAgICAgICAgICAibm9ybWFscyIgOiBbCiAgICAgICAgICAgICAgICAgICAgIFsgMC4wLCAxLjAsIDAuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMCwgLTEuMCwgMC4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTEuMCwgMC4wLCAwLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAxLjAsIDAuMCwgMC4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4wLCAwLjAsIC0xLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjAsIDAuMCwgMS4wIF0KICAgICAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAgICAgInBvbHlzIiA6IFsKICAgICAgICAgICAgICAgICAgICAgWwogICAgICAgICAgICAgICAgICAgICAgICBbIDAsIDAsIDAgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAxLCAwLCAxIF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMiwgMCwgMiBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDMsIDAsIDMgXQogICAgICAgICAgICAgICAgICAgICBdLAogICAgICAgICAgICAgICAgICAgICBbCiAgICAgICAgICAgICAgICAgICAgICAgIFsgNCwgMSwgNCBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDUsIDEsIDUgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyA2LCAxLCA2IF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgNywgMSwgNyBdCiAgICAgICAgICAgICAgICAgICAgIF0sCiAgICAgICAgICAgICAgICAgICAgIFsKICAgICAgICAgICAgICAgICAgICAgICAgWyA4LCAyLCA4IF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgOSwgMiwgOSBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDEwLCAyLCAxMCBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDExLCAyLCAxMSBdCiAgICAgICAgICAgICAgICAgICAgIF0sCiAgICAgICAgICAgICAgICAgICAgIFsKICAgICAgICAgICAgICAgICAgICAgICAgWyAxMiwgMywgMTIgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAxMywgMywgMTMgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAxNCwgMywgMTQgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAxNSwgMywgMTUgXQogICAgICAgICAgICAgICAgICAgICBdLAogICAgICAgICAgICAgICAgICAgICBbCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMTYsIDQsIDE2IF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMTcsIDQsIDE3IF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMTgsIDQsIDE4IF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMTksIDQsIDE5IF0KICAgICAgICAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAgICAgICAgWwogICAgICAgICAgICAgICAgICAgICAgICBbIDIwLCA1LCAyMCBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDIxLCA1LCAyMSBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDIyLCA1LCAyMiBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDIzLCA1LCAyMyBdCiAgICAgICAgICAgICAgICAgICAgIF0KICAgICAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAgICAgInBvc2l0aW9ucyIgOiBbCiAgICAgICAgICAgICAgICAgICAgIFsgLTAuMzQ5OTk5OTk0MDM5NTM1NSwgMTIuMjUwLCAtMi4yNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyA0LjE1MDAwMDA5NTM2NzQzMiwgMTIuMjUwLCAtMi4yNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyA0LjE1MDAwMDA5NTM2NzQzMiwgMTIuMjUwLCAyLjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIC0wLjM0OTk5OTk5NDAzOTUzNTUsIDEyLjI1MCwgMi4yNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtMC4zNDk5OTk5OTQwMzk1MzU1LCAtMC4yNTAsIDIuMjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgNC4xNTAwMDAwOTUzNjc0MzIsIC0wLjI1MCwgMi4yNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyA0LjE1MDAwMDA5NTM2NzQzMiwgLTAuMjUwLCAtMi4yNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtMC4zNDk5OTk5OTQwMzk1MzU1LCAtMC4yNTAsIC0yLjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIC0wLjM0OTk5OTk5NDAzOTUzNTUsIC0wLjI1MCwgMi4yNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtMC4zNDk5OTk5OTQwMzk1MzU1LCAtMC4yNTAsIC0yLjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIC0wLjM0OTk5OTk5NDAzOTUzNTUsIDEyLjI1MCwgLTIuMjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTAuMzQ5OTk5OTk0MDM5NTM1NSwgMTIuMjUwLCAyLjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDQuMTUwMDAwMDk1MzY3NDMyLCAtMC4yNTAsIC0yLjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDQuMTUwMDAwMDk1MzY3NDMyLCAtMC4yNTAsIDIuMjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgNC4xNTAwMDAwOTUzNjc0MzIsIDEyLjI1MCwgMi4yNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyA0LjE1MDAwMDA5NTM2NzQzMiwgMTIuMjUwLCAtMi4yNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtMC4zNDk5OTk5OTQwMzk1MzU1LCAtMC4yNTAsIC0yLjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDQuMTUwMDAwMDk1MzY3NDMyLCAtMC4yNTAsIC0yLjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDQuMTUwMDAwMDk1MzY3NDMyLCAxMi4yNTAsIC0yLjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIC0wLjM0OTk5OTk5NDAzOTUzNTUsIDEyLjI1MCwgLTIuMjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgNC4xNTAwMDAwOTUzNjc0MzIsIC0wLjI1MCwgMi4yNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtMC4zNDk5OTk5OTQwMzk1MzU1LCAtMC4yNTAsIDIuMjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTAuMzQ5OTk5OTk0MDM5NTM1NSwgMTIuMjUwLCAyLjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDQuMTUwMDAwMDk1MzY3NDMyLCAxMi4yNTAsIDIuMjUwIF0KICAgICAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAgICAgInV2cyIgOiBbCiAgICAgICAgICAgICAgICAgICAgIFsgMC40MDYyNTAsIDAuOTgyNDIxODc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuNDM3NTAsIDAuOTgyNDIxODc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuNDM3NTAsIDAuOTg0Mzc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuNDA2MjUwLCAwLjk4NDM3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjQ2ODc1MCwgMC45ODQzNzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC40Mzc1MCwgMC45ODQzNzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC40Mzc1MCwgMC45ODI0MjE4NzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC40Njg3NTAsIDAuOTgyNDIxODc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMzc1MCwgMC45NzY1NjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuNDA2MjUwLCAwLjk3NjU2MjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC40MDYyNTAsIDAuOTgyNDIxODc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMzc1MCwgMC45ODI0MjE4NzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC40Mzc1MCwgMC45NzY1NjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuNDY4NzUwLCAwLjk3NjU2MjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC40Njg3NTAsIDAuOTgyNDIxODc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuNDM3NTAsIDAuOTgyNDIxODc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuNDA2MjUwLCAwLjk3NjU2MjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC40Mzc1MCwgMC45NzY1NjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuNDM3NTAsIDAuOTgyNDIxODc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuNDA2MjUwLCAwLjk4MjQyMTg3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjQ2ODc1MCwgMC45NzY1NjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuNTAsIDAuOTc2NTYyNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjUwLCAwLjk4MjQyMTg3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjQ2ODc1MCwgMC45ODI0MjE4NzUwIF0KICAgICAgICAgICAgICAgICAgXQogICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgIm5hbWUiIDogImxlZnRzbGVldmUiLAogICAgICAgICAgICAgICAicGFyZW50IiA6ICJsZWZ0YXJtIiwKICAgICAgICAgICAgICAgInBpdm90IiA6IFsgNS4wLCAyMi4wLCAwLjAgXSwKICAgICAgICAgICAgICAgInBvbHlfbWVzaCIgOiB7CiAgICAgICAgICAgICAgICAgICJub3JtYWxpemVkX3V2cyIgOiB0cnVlLAogICAgICAgICAgICAgICAgICAibm9ybWFscyIgOiBbCiAgICAgICAgICAgICAgICAgICAgIFsgMC4wLCAxLjAsIDAuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMCwgLTEuMCwgMC4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTEuMCwgMC4wLCAwLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAxLjAsIDAuMCwgMC4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4wLCAwLjAsIC0xLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjAsIDAuMCwgMS4wIF0KICAgICAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAgICAgInBvbHlzIiA6IFsKICAgICAgICAgICAgICAgICAgICAgWwogICAgICAgICAgICAgICAgICAgICAgICBbIDAsIDAsIDAgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAxLCAwLCAxIF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMiwgMCwgMiBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDMsIDAsIDMgXQogICAgICAgICAgICAgICAgICAgICBdLAogICAgICAgICAgICAgICAgICAgICBbCiAgICAgICAgICAgICAgICAgICAgICAgIFsgNCwgMSwgNCBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDUsIDEsIDUgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyA2LCAxLCA2IF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgNywgMSwgNyBdCiAgICAgICAgICAgICAgICAgICAgIF0sCiAgICAgICAgICAgICAgICAgICAgIFsKICAgICAgICAgICAgICAgICAgICAgICAgWyA4LCAyLCA4IF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgOSwgMiwgOSBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDEwLCAyLCAxMCBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDExLCAyLCAxMSBdCiAgICAgICAgICAgICAgICAgICAgIF0sCiAgICAgICAgICAgICAgICAgICAgIFsKICAgICAgICAgICAgICAgICAgICAgICAgWyAxMiwgMywgMTIgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAxMywgMywgMTMgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAxNCwgMywgMTQgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAxNSwgMywgMTUgXQogICAgICAgICAgICAgICAgICAgICBdLAogICAgICAgICAgICAgICAgICAgICBbCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMTYsIDQsIDE2IF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMTcsIDQsIDE3IF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMTgsIDQsIDE4IF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMTksIDQsIDE5IF0KICAgICAgICAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAgICAgICAgWwogICAgICAgICAgICAgICAgICAgICAgICBbIDIwLCA1LCAyMCBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDIxLCA1LCAyMSBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDIyLCA1LCAyMiBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDIzLCA1LCAyMyBdCiAgICAgICAgICAgICAgICAgICAgIF0KICAgICAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAgICAgInBvc2l0aW9ucyIgOiBbCiAgICAgICAgICAgICAgICAgICAgIFsgMy43NTAsIDI0LjI1MCwgLTIuMjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgOC4yNTAsIDI0LjI1MCwgLTIuMjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgOC4yNTAsIDI0LjI1MCwgMi4yNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAzLjc1MCwgMjQuMjUwLCAyLjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDMuNzUwLCAxMS43NTAsIDIuMjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgOC4yNTAsIDExLjc1MCwgMi4yNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyA4LjI1MCwgMTEuNzUwLCAtMi4yNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAzLjc1MCwgMTEuNzUwLCAtMi4yNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAzLjc1MCwgMTEuNzUwLCAyLjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDMuNzUwLCAxMS43NTAsIC0yLjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDMuNzUwLCAyNC4yNTAsIC0yLjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDMuNzUwLCAyNC4yNTAsIDIuMjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgOC4yNTAsIDExLjc1MCwgLTIuMjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgOC4yNTAsIDExLjc1MCwgMi4yNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyA4LjI1MCwgMjQuMjUwLCAyLjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDguMjUwLCAyNC4yNTAsIC0yLjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDMuNzUwLCAxMS43NTAsIC0yLjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDguMjUwLCAxMS43NTAsIC0yLjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDguMjUwLCAyNC4yNTAsIC0yLjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDMuNzUwLCAyNC4yNTAsIC0yLjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDguMjUwLCAxMS43NTAsIDIuMjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMy43NTAsIDExLjc1MCwgMi4yNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAzLjc1MCwgMjQuMjUwLCAyLjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDguMjUwLCAyNC4yNTAsIDIuMjUwIF0KICAgICAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAgICAgInV2cyIgOiBbCiAgICAgICAgICAgICAgICAgICAgIFsgMC4zNDM3NTAsIDAuOTkwMjM0Mzc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMzc1MCwgMC45OTAyMzQzNzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4zNzUwLCAwLjk5MjE4NzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4zNDM3NTAsIDAuOTkyMTg3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjQwNjI1MCwgMC45OTIxODc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMzc1MCwgMC45OTIxODc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMzc1MCwgMC45OTAyMzQzNzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC40MDYyNTAsIDAuOTkwMjM0Mzc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMzEyNTAsIDAuOTg0Mzc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMzQzNzUwLCAwLjk4NDM3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjM0Mzc1MCwgMC45OTAyMzQzNzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4zMTI1MCwgMC45OTAyMzQzNzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4zNzUwLCAwLjk4NDM3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjQwNjI1MCwgMC45ODQzNzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC40MDYyNTAsIDAuOTkwMjM0Mzc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMzc1MCwgMC45OTAyMzQzNzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4zNDM3NTAsIDAuOTg0Mzc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMzc1MCwgMC45ODQzNzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4zNzUwLCAwLjk5MDIzNDM3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjM0Mzc1MCwgMC45OTAyMzQzNzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC40MDYyNTAsIDAuOTg0Mzc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuNDM3NTAsIDAuOTg0Mzc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuNDM3NTAsIDAuOTkwMjM0Mzc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuNDA2MjUwLCAwLjk5MDIzNDM3NTAgXQogICAgICAgICAgICAgICAgICBdCiAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfSwKICAgICAgICAgICAgewogICAgICAgICAgICAgICAibWlycm9yIiA6IHRydWUsCiAgICAgICAgICAgICAgICJuYW1lIiA6ICJsZWZ0c29jayIsCiAgICAgICAgICAgICAgICJwYXJlbnQiIDogImxlZnRsZWciLAogICAgICAgICAgICAgICAicGl2b3QiIDogWyAxLjg5OTk5OTk3NjE1ODE0MiwgMTIuMCwgMC4wIF0KICAgICAgICAgICAgfSwKICAgICAgICAgICAgewogICAgICAgICAgICAgICAibmFtZSIgOiAicmlnaHRhcm0iLAogICAgICAgICAgICAgICAicGFyZW50IiA6ICJib2R5IiwKICAgICAgICAgICAgICAgInBpdm90IiA6IFsgLTUuMCwgMjIuMCwgMC4wIF0sCiAgICAgICAgICAgICAgICJwb2x5X21lc2giIDogewogICAgICAgICAgICAgICAgICAibm9ybWFsaXplZF91dnMiIDogdHJ1ZSwKICAgICAgICAgICAgICAgICAgIm5vcm1hbHMiIDogWwogICAgICAgICAgICAgICAgICAgICBbIDAuMCwgMS4wLCAwLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjAsIC0xLjAsIDAuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIC0xLjAsIDAuMCwgMC4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMS4wLCAwLjAsIDAuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMCwgMC4wLCAtMS4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4wLCAwLjAsIDEuMCBdCiAgICAgICAgICAgICAgICAgIF0sCiAgICAgICAgICAgICAgICAgICJwb2x5cyIgOiBbCiAgICAgICAgICAgICAgICAgICAgIFsKICAgICAgICAgICAgICAgICAgICAgICAgWyAwLCAwLCAwIF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMSwgMCwgMSBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDIsIDAsIDIgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAzLCAwLCAzIF0KICAgICAgICAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAgICAgICAgWwogICAgICAgICAgICAgICAgICAgICAgICBbIDQsIDEsIDQgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyA1LCAxLCA1IF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgNiwgMSwgNiBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDcsIDEsIDcgXQogICAgICAgICAgICAgICAgICAgICBdLAogICAgICAgICAgICAgICAgICAgICBbCiAgICAgICAgICAgICAgICAgICAgICAgIFsgOCwgMiwgOCBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDksIDIsIDkgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAxMCwgMiwgMTAgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAxMSwgMiwgMTEgXQogICAgICAgICAgICAgICAgICAgICBdLAogICAgICAgICAgICAgICAgICAgICBbCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMTIsIDMsIDEyIF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMTMsIDMsIDEzIF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMTQsIDMsIDE0IF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMTUsIDMsIDE1IF0KICAgICAgICAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAgICAgICAgWwogICAgICAgICAgICAgICAgICAgICAgICBbIDE2LCA0LCAxNiBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDE3LCA0LCAxNyBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDE4LCA0LCAxOCBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDE5LCA0LCAxOSBdCiAgICAgICAgICAgICAgICAgICAgIF0sCiAgICAgICAgICAgICAgICAgICAgIFsKICAgICAgICAgICAgICAgICAgICAgICAgWyAyMCwgNSwgMjAgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAyMSwgNSwgMjEgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAyMiwgNSwgMjIgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAyMywgNSwgMjMgXQogICAgICAgICAgICAgICAgICAgICBdCiAgICAgICAgICAgICAgICAgIF0sCiAgICAgICAgICAgICAgICAgICJwb3NpdGlvbnMiIDogWwogICAgICAgICAgICAgICAgICAgICBbIC04LjAsIDI0LjAsIC0yLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtNC4wLCAyNC4wLCAtMi4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTQuMCwgMjQuMCwgMi4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTguMCwgMjQuMCwgMi4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTguMCwgMTIuMCwgMi4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTQuMCwgMTIuMCwgMi4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTQuMCwgMTIuMCwgLTIuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIC04LjAsIDEyLjAsIC0yLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtOC4wLCAxMi4wLCAyLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtOC4wLCAxMi4wLCAtMi4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTguMCwgMjQuMCwgLTIuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIC04LjAsIDI0LjAsIDIuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIC00LjAsIDEyLjAsIC0yLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtNC4wLCAxMi4wLCAyLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtNC4wLCAyNC4wLCAyLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtNC4wLCAyNC4wLCAtMi4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTguMCwgMTIuMCwgLTIuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIC00LjAsIDEyLjAsIC0yLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtNC4wLCAyNC4wLCAtMi4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTguMCwgMjQuMCwgLTIuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIC00LjAsIDEyLjAsIDIuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIC04LjAsIDEyLjAsIDIuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIC04LjAsIDI0LjAsIDIuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIC00LjAsIDI0LjAsIDIuMCBdCiAgICAgICAgICAgICAgICAgIF0sCiAgICAgICAgICAgICAgICAgICJ1dnMiIDogWwogICAgICAgICAgICAgICAgICAgICBbIDAuMDMxMjUwLCAwLjk5ODA0Njg3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjA2MjUwLCAwLjk5ODA0Njg3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjA2MjUwLCAxLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjAzMTI1MCwgMS4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4wOTM3NTAsIDEuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMDYyNTAsIDEuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMDYyNTAsIDAuOTk4MDQ2ODc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMDkzNzUwLCAwLjk5ODA0Njg3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjAsIDAuOTkyMTg3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjAzMTI1MCwgMC45OTIxODc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMDMxMjUwLCAwLjk5ODA0Njg3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjAsIDAuOTk4MDQ2ODc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMDYyNTAsIDAuOTkyMTg3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjA5Mzc1MCwgMC45OTIxODc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMDkzNzUwLCAwLjk5ODA0Njg3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjA2MjUwLCAwLjk5ODA0Njg3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjAzMTI1MCwgMC45OTIxODc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMDYyNTAsIDAuOTkyMTg3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjA2MjUwLCAwLjk5ODA0Njg3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjAzMTI1MCwgMC45OTgwNDY4NzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4wOTM3NTAsIDAuOTkyMTg3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjEyNTAsIDAuOTkyMTg3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjEyNTAsIDAuOTk4MDQ2ODc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMDkzNzUwLCAwLjk5ODA0Njg3NTAgXQogICAgICAgICAgICAgICAgICBdCiAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfSwKICAgICAgICAgICAgewogICAgICAgICAgICAgICAibmFtZSIgOiAicmlnaHRhcm1hcm1vciIsCiAgICAgICAgICAgICAgICJwYXJlbnQiIDogInJpZ2h0YXJtIiwKICAgICAgICAgICAgICAgInBpdm90IiA6IFsgLTUuMCwgMjIuMCwgMC4wIF0KICAgICAgICAgICAgfSwKICAgICAgICAgICAgewogICAgICAgICAgICAgICAibmFtZSIgOiAicmlnaHRib290IiwKICAgICAgICAgICAgICAgInBhcmVudCIgOiAicmlnaHRsZWciLAogICAgICAgICAgICAgICAicGl2b3QiIDogWyAtMS44OTk5OTk5NzYxNTgxNDIsIDEyLjAsIDAuMCBdCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgImxvY2F0b3JzIiA6IHsKICAgICAgICAgICAgICAgICAgImxlYWRfaG9sZCIgOiBbIC02LjAsIDE1LjAsIDAuMCBdCiAgICAgICAgICAgICAgIH0sCiAgICAgICAgICAgICAgICJuYW1lIiA6ICJyaWdodGl0ZW0iLAogICAgICAgICAgICAgICAicGFyZW50IiA6ICJyaWdodGFybSIsCiAgICAgICAgICAgICAgICJwaXZvdCIgOiBbIC02LjAsIDE1LjAsIDAuMCBdCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgIm5hbWUiIDogInJpZ2h0bGVnIiwKICAgICAgICAgICAgICAgInBhcmVudCIgOiAicm9vdCIsCiAgICAgICAgICAgICAgICJwaXZvdCIgOiBbIC0xLjg5OTk5OTk3NjE1ODE0MiwgMTIuMCwgMC4wIF0sCiAgICAgICAgICAgICAgICJwb2x5X21lc2giIDogewogICAgICAgICAgICAgICAgICAibm9ybWFsaXplZF91dnMiIDogdHJ1ZSwKICAgICAgICAgICAgICAgICAgIm5vcm1hbHMiIDogWwogICAgICAgICAgICAgICAgICAgICBbIDAuMCwgMS4wLCAwLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjAsIC0xLjAsIDAuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIC0xLjAsIDAuMCwgMC4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMS4wLCAwLjAsIDAuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMCwgMC4wLCAtMS4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4wLCAwLjAsIDEuMCBdCiAgICAgICAgICAgICAgICAgIF0sCiAgICAgICAgICAgICAgICAgICJwb2x5cyIgOiBbCiAgICAgICAgICAgICAgICAgICAgIFsKICAgICAgICAgICAgICAgICAgICAgICAgWyAwLCAwLCAwIF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMSwgMCwgMSBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDIsIDAsIDIgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAzLCAwLCAzIF0KICAgICAgICAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAgICAgICAgWwogICAgICAgICAgICAgICAgICAgICAgICBbIDQsIDEsIDQgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyA1LCAxLCA1IF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgNiwgMSwgNiBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDcsIDEsIDcgXQogICAgICAgICAgICAgICAgICAgICBdLAogICAgICAgICAgICAgICAgICAgICBbCiAgICAgICAgICAgICAgICAgICAgICAgIFsgOCwgMiwgOCBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDksIDIsIDkgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAxMCwgMiwgMTAgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAxMSwgMiwgMTEgXQogICAgICAgICAgICAgICAgICAgICBdLAogICAgICAgICAgICAgICAgICAgICBbCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMTIsIDMsIDEyIF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMTMsIDMsIDEzIF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMTQsIDMsIDE0IF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMTUsIDMsIDE1IF0KICAgICAgICAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAgICAgICAgWwogICAgICAgICAgICAgICAgICAgICAgICBbIDE2LCA0LCAxNiBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDE3LCA0LCAxNyBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDE4LCA0LCAxOCBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDE5LCA0LCAxOSBdCiAgICAgICAgICAgICAgICAgICAgIF0sCiAgICAgICAgICAgICAgICAgICAgIFsKICAgICAgICAgICAgICAgICAgICAgICAgWyAyMCwgNSwgMjAgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAyMSwgNSwgMjEgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAyMiwgNSwgMjIgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAyMywgNSwgMjMgXQogICAgICAgICAgICAgICAgICAgICBdCiAgICAgICAgICAgICAgICAgIF0sCiAgICAgICAgICAgICAgICAgICJwb3NpdGlvbnMiIDogWwogICAgICAgICAgICAgICAgICAgICBbIC0zLjkwMDAwMDA5NTM2NzQzMiwgMTIuMCwgLTIuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMDk5OTk5ODk3MTgxOTg3NzYsIDEyLjAsIC0yLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjA5OTk5OTg5NzE4MTk4Nzc2LCAxMi4wLCAyLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtMy45MDAwMDAwOTUzNjc0MzIsIDEyLjAsIDIuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIC0zLjkwMDAwMDA5NTM2NzQzMiwgMC4wLCAyLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjA5OTk5OTg5NzE4MTk4Nzc2LCAwLjAsIDIuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMDk5OTk5ODk3MTgxOTg3NzYsIDAuMCwgLTIuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIC0zLjkwMDAwMDA5NTM2NzQzMiwgMC4wLCAtMi4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTMuOTAwMDAwMDk1MzY3NDMyLCAwLjAsIDIuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIC0zLjkwMDAwMDA5NTM2NzQzMiwgMC4wLCAtMi4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTMuOTAwMDAwMDk1MzY3NDMyLCAxMi4wLCAtMi4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTMuOTAwMDAwMDk1MzY3NDMyLCAxMi4wLCAyLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjA5OTk5OTg5NzE4MTk4Nzc2LCAwLjAsIC0yLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjA5OTk5OTg5NzE4MTk4Nzc2LCAwLjAsIDIuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMDk5OTk5ODk3MTgxOTg3NzYsIDEyLjAsIDIuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMDk5OTk5ODk3MTgxOTg3NzYsIDEyLjAsIC0yLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtMy45MDAwMDAwOTUzNjc0MzIsIDAuMCwgLTIuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMDk5OTk5ODk3MTgxOTg3NzYsIDAuMCwgLTIuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMDk5OTk5ODk3MTgxOTg3NzYsIDEyLjAsIC0yLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtMy45MDAwMDAwOTUzNjc0MzIsIDEyLjAsIC0yLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjA5OTk5OTg5NzE4MTk4Nzc2LCAwLjAsIDIuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIC0zLjkwMDAwMDA5NTM2NzQzMiwgMC4wLCAyLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtMy45MDAwMDAwOTUzNjc0MzIsIDEyLjAsIDIuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMDk5OTk5ODk3MTgxOTg3NzYsIDEyLjAsIDIuMCBdCiAgICAgICAgICAgICAgICAgIF0sCiAgICAgICAgICAgICAgICAgICJ1dnMiIDogWwogICAgICAgICAgICAgICAgICAgICBbIDAuMTU2MjUwLCAwLjk4MjQyMTg3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjE4NzUwLCAwLjk4MjQyMTg3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjE4NzUwLCAwLjk4NDM3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjE1NjI1MCwgMC45ODQzNzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4yMTg3NTAsIDAuOTg0Mzc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMTg3NTAsIDAuOTg0Mzc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMTg3NTAsIDAuOTgyNDIxODc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMjE4NzUwLCAwLjk4MjQyMTg3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjEyNTAsIDAuOTc2NTYyNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjE1NjI1MCwgMC45NzY1NjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMTU2MjUwLCAwLjk4MjQyMTg3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjEyNTAsIDAuOTgyNDIxODc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMTg3NTAsIDAuOTc2NTYyNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjIxODc1MCwgMC45NzY1NjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMjE4NzUwLCAwLjk4MjQyMTg3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjE4NzUwLCAwLjk4MjQyMTg3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjE1NjI1MCwgMC45NzY1NjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMTg3NTAsIDAuOTc2NTYyNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjE4NzUwLCAwLjk4MjQyMTg3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjE1NjI1MCwgMC45ODI0MjE4NzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4yMTg3NTAsIDAuOTc2NTYyNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjI1MCwgMC45NzY1NjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMjUwLCAwLjk4MjQyMTg3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjIxODc1MCwgMC45ODI0MjE4NzUwIF0KICAgICAgICAgICAgICAgICAgXQogICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgIm5hbWUiIDogInJpZ2h0bGVnZ2luZyIsCiAgICAgICAgICAgICAgICJwYXJlbnQiIDogInJpZ2h0bGVnIiwKICAgICAgICAgICAgICAgInBpdm90IiA6IFsgLTEuODk5OTk5OTc2MTU4MTQyLCAxMi4wLCAwLjAgXQogICAgICAgICAgICB9LAogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICJuYW1lIiA6ICJyaWdodHBhbnRzIiwKICAgICAgICAgICAgICAgInBhcmVudCIgOiAicmlnaHRsZWciLAogICAgICAgICAgICAgICAicGl2b3QiIDogWyAtMS44OTk5OTk5NzYxNTgxNDIsIDEyLjAsIDAuMCBdLAogICAgICAgICAgICAgICAicG9seV9tZXNoIiA6IHsKICAgICAgICAgICAgICAgICAgIm5vcm1hbGl6ZWRfdXZzIiA6IHRydWUsCiAgICAgICAgICAgICAgICAgICJub3JtYWxzIiA6IFsKICAgICAgICAgICAgICAgICAgICAgWyAwLjAsIDEuMCwgMC4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4wLCAtMS4wLCAwLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtMS4wLCAwLjAsIDAuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDEuMCwgMC4wLCAwLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjAsIDAuMCwgLTEuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMCwgMC4wLCAxLjAgXQogICAgICAgICAgICAgICAgICBdLAogICAgICAgICAgICAgICAgICAicG9seXMiIDogWwogICAgICAgICAgICAgICAgICAgICBbCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMCwgMCwgMCBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDEsIDAsIDEgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAyLCAwLCAyIF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMywgMCwgMyBdCiAgICAgICAgICAgICAgICAgICAgIF0sCiAgICAgICAgICAgICAgICAgICAgIFsKICAgICAgICAgICAgICAgICAgICAgICAgWyA0LCAxLCA0IF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgNSwgMSwgNSBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDYsIDEsIDYgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyA3LCAxLCA3IF0KICAgICAgICAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAgICAgICAgWwogICAgICAgICAgICAgICAgICAgICAgICBbIDgsIDIsIDggXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyA5LCAyLCA5IF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMTAsIDIsIDEwIF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMTEsIDIsIDExIF0KICAgICAgICAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAgICAgICAgWwogICAgICAgICAgICAgICAgICAgICAgICBbIDEyLCAzLCAxMiBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDEzLCAzLCAxMyBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDE0LCAzLCAxNCBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDE1LCAzLCAxNSBdCiAgICAgICAgICAgICAgICAgICAgIF0sCiAgICAgICAgICAgICAgICAgICAgIFsKICAgICAgICAgICAgICAgICAgICAgICAgWyAxNiwgNCwgMTYgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAxNywgNCwgMTcgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAxOCwgNCwgMTggXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAxOSwgNCwgMTkgXQogICAgICAgICAgICAgICAgICAgICBdLAogICAgICAgICAgICAgICAgICAgICBbCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMjAsIDUsIDIwIF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMjEsIDUsIDIxIF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMjIsIDUsIDIyIF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMjMsIDUsIDIzIF0KICAgICAgICAgICAgICAgICAgICAgXQogICAgICAgICAgICAgICAgICBdLAogICAgICAgICAgICAgICAgICAicG9zaXRpb25zIiA6IFsKICAgICAgICAgICAgICAgICAgICAgWyAtNC4xNTAwMDAwOTUzNjc0MzIsIDEyLjI1MCwgLTIuMjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4zNDk5OTk5MDQ2MzI1Njg0LCAxMi4yNTAsIC0yLjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMzQ5OTk5OTA0NjMyNTY4NCwgMTIuMjUwLCAyLjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIC00LjE1MDAwMDA5NTM2NzQzMiwgMTIuMjUwLCAyLjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIC00LjE1MDAwMDA5NTM2NzQzMiwgLTAuMjUwLCAyLjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMzQ5OTk5OTA0NjMyNTY4NCwgLTAuMjUwLCAyLjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMzQ5OTk5OTA0NjMyNTY4NCwgLTAuMjUwLCAtMi4yNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtNC4xNTAwMDAwOTUzNjc0MzIsIC0wLjI1MCwgLTIuMjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTQuMTUwMDAwMDk1MzY3NDMyLCAtMC4yNTAsIDIuMjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTQuMTUwMDAwMDk1MzY3NDMyLCAtMC4yNTAsIC0yLjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIC00LjE1MDAwMDA5NTM2NzQzMiwgMTIuMjUwLCAtMi4yNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtNC4xNTAwMDAwOTUzNjc0MzIsIDEyLjI1MCwgMi4yNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjM0OTk5OTkwNDYzMjU2ODQsIC0wLjI1MCwgLTIuMjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4zNDk5OTk5MDQ2MzI1Njg0LCAtMC4yNTAsIDIuMjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4zNDk5OTk5MDQ2MzI1Njg0LCAxMi4yNTAsIDIuMjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4zNDk5OTk5MDQ2MzI1Njg0LCAxMi4yNTAsIC0yLjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIC00LjE1MDAwMDA5NTM2NzQzMiwgLTAuMjUwLCAtMi4yNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjM0OTk5OTkwNDYzMjU2ODQsIC0wLjI1MCwgLTIuMjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4zNDk5OTk5MDQ2MzI1Njg0LCAxMi4yNTAsIC0yLjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIC00LjE1MDAwMDA5NTM2NzQzMiwgMTIuMjUwLCAtMi4yNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjM0OTk5OTkwNDYzMjU2ODQsIC0wLjI1MCwgMi4yNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtNC4xNTAwMDAwOTUzNjc0MzIsIC0wLjI1MCwgMi4yNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtNC4xNTAwMDAwOTUzNjc0MzIsIDEyLjI1MCwgMi4yNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjM0OTk5OTkwNDYzMjU2ODQsIDEyLjI1MCwgMi4yNTAgXQogICAgICAgICAgICAgICAgICBdLAogICAgICAgICAgICAgICAgICAidXZzIiA6IFsKICAgICAgICAgICAgICAgICAgICAgWyAwLjAzMTI1MCwgMC45ODI0MjE4NzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4wNjI1MCwgMC45ODI0MjE4NzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4wNjI1MCwgMC45ODQzNzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4wMzEyNTAsIDAuOTg0Mzc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMDkzNzUwLCAwLjk4NDM3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjA2MjUwLCAwLjk4NDM3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjA2MjUwLCAwLjk4MjQyMTg3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjA5Mzc1MCwgMC45ODI0MjE4NzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4wLCAwLjk3NjU2MjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4wMzEyNTAsIDAuOTc2NTYyNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjAzMTI1MCwgMC45ODI0MjE4NzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4wLCAwLjk4MjQyMTg3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjA2MjUwLCAwLjk3NjU2MjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4wOTM3NTAsIDAuOTc2NTYyNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjA5Mzc1MCwgMC45ODI0MjE4NzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4wNjI1MCwgMC45ODI0MjE4NzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4wMzEyNTAsIDAuOTc2NTYyNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjA2MjUwLCAwLjk3NjU2MjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4wNjI1MCwgMC45ODI0MjE4NzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4wMzEyNTAsIDAuOTgyNDIxODc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMDkzNzUwLCAwLjk3NjU2MjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4xMjUwLCAwLjk3NjU2MjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4xMjUwLCAwLjk4MjQyMTg3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjA5Mzc1MCwgMC45ODI0MjE4NzUwIF0KICAgICAgICAgICAgICAgICAgXQogICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgIm5hbWUiIDogInJpZ2h0c2xlZXZlIiwKICAgICAgICAgICAgICAgInBhcmVudCIgOiAicmlnaHRhcm0iLAogICAgICAgICAgICAgICAicGl2b3QiIDogWyAtNS4wLCAyMi4wLCAwLjAgXSwKICAgICAgICAgICAgICAgInBvbHlfbWVzaCIgOiB7CiAgICAgICAgICAgICAgICAgICJub3JtYWxpemVkX3V2cyIgOiB0cnVlLAogICAgICAgICAgICAgICAgICAibm9ybWFscyIgOiBbCiAgICAgICAgICAgICAgICAgICAgIFsgMC4wLCAxLjAsIDAuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMCwgLTEuMCwgMC4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTEuMCwgMC4wLCAwLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAxLjAsIDAuMCwgMC4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4wLCAwLjAsIC0xLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjAsIDAuMCwgMS4wIF0KICAgICAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAgICAgInBvbHlzIiA6IFsKICAgICAgICAgICAgICAgICAgICAgWwogICAgICAgICAgICAgICAgICAgICAgICBbIDAsIDAsIDAgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAxLCAwLCAxIF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMiwgMCwgMiBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDMsIDAsIDMgXQogICAgICAgICAgICAgICAgICAgICBdLAogICAgICAgICAgICAgICAgICAgICBbCiAgICAgICAgICAgICAgICAgICAgICAgIFsgNCwgMSwgNCBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDUsIDEsIDUgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyA2LCAxLCA2IF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgNywgMSwgNyBdCiAgICAgICAgICAgICAgICAgICAgIF0sCiAgICAgICAgICAgICAgICAgICAgIFsKICAgICAgICAgICAgICAgICAgICAgICAgWyA4LCAyLCA4IF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgOSwgMiwgOSBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDEwLCAyLCAxMCBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDExLCAyLCAxMSBdCiAgICAgICAgICAgICAgICAgICAgIF0sCiAgICAgICAgICAgICAgICAgICAgIFsKICAgICAgICAgICAgICAgICAgICAgICAgWyAxMiwgMywgMTIgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAxMywgMywgMTMgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAxNCwgMywgMTQgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAxNSwgMywgMTUgXQogICAgICAgICAgICAgICAgICAgICBdLAogICAgICAgICAgICAgICAgICAgICBbCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMTYsIDQsIDE2IF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMTcsIDQsIDE3IF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMTgsIDQsIDE4IF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMTksIDQsIDE5IF0KICAgICAgICAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAgICAgICAgWwogICAgICAgICAgICAgICAgICAgICAgICBbIDIwLCA1LCAyMCBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDIxLCA1LCAyMSBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDIyLCA1LCAyMiBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDIzLCA1LCAyMyBdCiAgICAgICAgICAgICAgICAgICAgIF0KICAgICAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAgICAgInBvc2l0aW9ucyIgOiBbCiAgICAgICAgICAgICAgICAgICAgIFsgLTguMjUwLCAyNC4yNTAsIC0yLjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIC0zLjc1MCwgMjQuMjUwLCAtMi4yNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtMy43NTAsIDI0LjI1MCwgMi4yNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtOC4yNTAsIDI0LjI1MCwgMi4yNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtOC4yNTAsIDExLjc1MCwgMi4yNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtMy43NTAsIDExLjc1MCwgMi4yNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtMy43NTAsIDExLjc1MCwgLTIuMjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTguMjUwLCAxMS43NTAsIC0yLjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIC04LjI1MCwgMTEuNzUwLCAyLjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIC04LjI1MCwgMTEuNzUwLCAtMi4yNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtOC4yNTAsIDI0LjI1MCwgLTIuMjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTguMjUwLCAyNC4yNTAsIDIuMjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTMuNzUwLCAxMS43NTAsIC0yLjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIC0zLjc1MCwgMTEuNzUwLCAyLjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIC0zLjc1MCwgMjQuMjUwLCAyLjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIC0zLjc1MCwgMjQuMjUwLCAtMi4yNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtOC4yNTAsIDExLjc1MCwgLTIuMjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTMuNzUwLCAxMS43NTAsIC0yLjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIC0zLjc1MCwgMjQuMjUwLCAtMi4yNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtOC4yNTAsIDI0LjI1MCwgLTIuMjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTMuNzUwLCAxMS43NTAsIDIuMjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTguMjUwLCAxMS43NTAsIDIuMjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTguMjUwLCAyNC4yNTAsIDIuMjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTMuNzUwLCAyNC4yNTAsIDIuMjUwIF0KICAgICAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAgICAgInV2cyIgOiBbCiAgICAgICAgICAgICAgICAgICAgIFsgMC4wMzEyNTAsIDAuOTkwMjM0Mzc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMDYyNTAsIDAuOTkwMjM0Mzc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMDYyNTAsIDAuOTkyMTg3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjAzMTI1MCwgMC45OTIxODc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMDkzNzUwLCAwLjk5MjE4NzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4wNjI1MCwgMC45OTIxODc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMDYyNTAsIDAuOTkwMjM0Mzc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMDkzNzUwLCAwLjk5MDIzNDM3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjAsIDAuOTg0Mzc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMDMxMjUwLCAwLjk4NDM3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjAzMTI1MCwgMC45OTAyMzQzNzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4wLCAwLjk5MDIzNDM3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjA2MjUwLCAwLjk4NDM3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjA5Mzc1MCwgMC45ODQzNzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4wOTM3NTAsIDAuOTkwMjM0Mzc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMDYyNTAsIDAuOTkwMjM0Mzc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMDMxMjUwLCAwLjk4NDM3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjA2MjUwLCAwLjk4NDM3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjA2MjUwLCAwLjk5MDIzNDM3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjAzMTI1MCwgMC45OTAyMzQzNzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4wOTM3NTAsIDAuOTg0Mzc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMTI1MCwgMC45ODQzNzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4xMjUwLCAwLjk5MDIzNDM3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjA5Mzc1MCwgMC45OTAyMzQzNzUwIF0KICAgICAgICAgICAgICAgICAgXQogICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgIm5hbWUiIDogInJpZ2h0c29jayIsCiAgICAgICAgICAgICAgICJwYXJlbnQiIDogInJpZ2h0bGVnIiwKICAgICAgICAgICAgICAgInBpdm90IiA6IFsgLTEuODk5OTk5OTc2MTU4MTQyLCAxMi4wLCAwLjAgXQogICAgICAgICAgICB9LAogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICJuYW1lIiA6ICJyb290IgogICAgICAgICAgICB9LAogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICJuYW1lIiA6ICJ3YWlzdCIsCiAgICAgICAgICAgICAgICJwYXJlbnQiIDogInJvb3QiLAogICAgICAgICAgICAgICAicGl2b3QiIDogWyAwLjAsIDEyLjAsIDAuMCBdCiAgICAgICAgICAgIH0KICAgICAgICAgXSwKICAgICAgICAgImRlc2NyaXB0aW9uIiA6IHsKICAgICAgICAgICAgImlkZW50aWZpZXIiIDogImdlb21ldHJ5LmFuaW1hdGVkXzEyOHgxMjhfcGVyc29uYS1lMTk5NjcyYThjMWE4N2UwLTAiLAogICAgICAgICAgICAidGV4dHVyZV9oZWlnaHQiIDogMjA0OC4wLAogICAgICAgICAgICAidGV4dHVyZV93aWR0aCIgOiAxMjguMAogICAgICAgICB9CiAgICAgIH0sCiAgICAgIHsKICAgICAgICAgImJvbmVzIiA6IFsKICAgICAgICAgICAgewogICAgICAgICAgICAgICAibmFtZSIgOiAiYmVsdCIsCiAgICAgICAgICAgICAgICJwYXJlbnQiIDogImJvZHkiLAogICAgICAgICAgICAgICAicGl2b3QiIDogWyAwLjAsIDI0LjAsIDAuMCBdCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgImxvY2F0b3JzIiA6IHsKICAgICAgICAgICAgICAgICAgImFybW9yX29mZnNldC5kZWZhdWx0X25lY2siIDogWyAwLjAsIDI0LjAsIDAuMCBdCiAgICAgICAgICAgICAgIH0sCiAgICAgICAgICAgICAgICJuYW1lIiA6ICJib2R5IiwKICAgICAgICAgICAgICAgInBhcmVudCIgOiAid2Fpc3QiLAogICAgICAgICAgICAgICAicGl2b3QiIDogWyAwLjAsIDI0LjAsIDAuMCBdCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgIm5hbWUiIDogImJvZHlhcm1vciIsCiAgICAgICAgICAgICAgICJwYXJlbnQiIDogImJvZHkiLAogICAgICAgICAgICAgICAicGl2b3QiIDogWyAwLjAsIDI0LjAsIDAuMCBdCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgIm5hbWUiIDogImhhdCIsCiAgICAgICAgICAgICAgICJwYXJlbnQiIDogImhlYWQiLAogICAgICAgICAgICAgICAicGl2b3QiIDogWyAwLjAsIDI0LjAsIDAuMCBdLAogICAgICAgICAgICAgICAicG9seV9tZXNoIiA6IHsKICAgICAgICAgICAgICAgICAgIm5vcm1hbGl6ZWRfdXZzIiA6IHRydWUsCiAgICAgICAgICAgICAgICAgICJub3JtYWxzIiA6IFsKICAgICAgICAgICAgICAgICAgICAgWyAwLjAsIDEuMCwgMC4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4wLCAtMS4wLCAwLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtMS4wLCAwLjAsIDAuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDEuMCwgMC4wLCAwLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjAsIDAuMCwgLTEuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMCwgMC4wLCAxLjAgXQogICAgICAgICAgICAgICAgICBdLAogICAgICAgICAgICAgICAgICAicG9seXMiIDogWwogICAgICAgICAgICAgICAgICAgICBbCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMCwgMCwgMCBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDEsIDAsIDEgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAyLCAwLCAyIF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMywgMCwgMyBdCiAgICAgICAgICAgICAgICAgICAgIF0sCiAgICAgICAgICAgICAgICAgICAgIFsKICAgICAgICAgICAgICAgICAgICAgICAgWyA0LCAxLCA0IF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgNSwgMSwgNSBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDYsIDEsIDYgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyA3LCAxLCA3IF0KICAgICAgICAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAgICAgICAgWwogICAgICAgICAgICAgICAgICAgICAgICBbIDgsIDIsIDggXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyA5LCAyLCA5IF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMTAsIDIsIDEwIF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMTEsIDIsIDExIF0KICAgICAgICAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAgICAgICAgWwogICAgICAgICAgICAgICAgICAgICAgICBbIDEyLCAzLCAxMiBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDEzLCAzLCAxMyBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDE0LCAzLCAxNCBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDE1LCAzLCAxNSBdCiAgICAgICAgICAgICAgICAgICAgIF0sCiAgICAgICAgICAgICAgICAgICAgIFsKICAgICAgICAgICAgICAgICAgICAgICAgWyAxNiwgNCwgMTYgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAxNywgNCwgMTcgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAxOCwgNCwgMTggXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAxOSwgNCwgMTkgXQogICAgICAgICAgICAgICAgICAgICBdLAogICAgICAgICAgICAgICAgICAgICBbCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMjAsIDUsIDIwIF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMjEsIDUsIDIxIF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMjIsIDUsIDIyIF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMjMsIDUsIDIzIF0KICAgICAgICAgICAgICAgICAgICAgXQogICAgICAgICAgICAgICAgICBdLAogICAgICAgICAgICAgICAgICAicG9zaXRpb25zIiA6IFsKICAgICAgICAgICAgICAgICAgICAgWyAtNC41MCwgMzIuNTAsIC00LjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgNC41MCwgMzIuNTAsIC00LjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgNC41MCwgMzIuNTAsIDQuNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtNC41MCwgMzIuNTAsIDQuNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtNC41MCwgMjMuNTAsIDQuNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyA0LjUwLCAyMy41MCwgNC41MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDQuNTAsIDIzLjUwLCAtNC41MCBdLAogICAgICAgICAgICAgICAgICAgICBbIC00LjUwLCAyMy41MCwgLTQuNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtNC41MCwgMjMuNTAsIDQuNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtNC41MCwgMjMuNTAsIC00LjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTQuNTAsIDMyLjUwLCAtNC41MCBdLAogICAgICAgICAgICAgICAgICAgICBbIC00LjUwLCAzMi41MCwgNC41MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDQuNTAsIDIzLjUwLCAtNC41MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDQuNTAsIDIzLjUwLCA0LjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgNC41MCwgMzIuNTAsIDQuNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyA0LjUwLCAzMi41MCwgLTQuNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtNC41MCwgMjMuNTAsIC00LjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgNC41MCwgMjMuNTAsIC00LjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgNC41MCwgMzIuNTAsIC00LjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTQuNTAsIDMyLjUwLCAtNC41MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDQuNTAsIDIzLjUwLCA0LjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTQuNTAsIDIzLjUwLCA0LjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTQuNTAsIDMyLjUwLCA0LjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgNC41MCwgMzIuNTAsIDQuNTAgXQogICAgICAgICAgICAgICAgICBdLAogICAgICAgICAgICAgICAgICAidXZzIiA6IFsKICAgICAgICAgICAgICAgICAgICAgWyAwLjI1MCwgMC42MjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC41MCwgMC42MjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC41MCwgMC43NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjI1MCwgMC43NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjc1MCwgMC43NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjUwLCAwLjc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuNTAsIDAuNjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuNzUwLCAwLjYyNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjAsIDAuNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjI1MCwgMC41MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMjUwLCAwLjYyNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjAsIDAuNjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuNTAsIDAuNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjc1MCwgMC41MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuNzUwLCAwLjYyNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjUwLCAwLjYyNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjI1MCwgMC41MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuNTAsIDAuNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjUwLCAwLjYyNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjI1MCwgMC42MjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC43NTAsIDAuNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAxLjAsIDAuNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAxLjAsIDAuNjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuNzUwLCAwLjYyNTAgXQogICAgICAgICAgICAgICAgICBdCiAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfSwKICAgICAgICAgICAgewogICAgICAgICAgICAgICAibmFtZSIgOiAiaGVhZCIsCiAgICAgICAgICAgICAgICJwYXJlbnQiIDogImJvZHkiLAogICAgICAgICAgICAgICAicGl2b3QiIDogWyAwLjAsIDI0LjAsIDAuMCBdLAogICAgICAgICAgICAgICAicG9seV9tZXNoIiA6IHsKICAgICAgICAgICAgICAgICAgIm5vcm1hbGl6ZWRfdXZzIiA6IHRydWUsCiAgICAgICAgICAgICAgICAgICJub3JtYWxzIiA6IFsKICAgICAgICAgICAgICAgICAgICAgWyAwLjAsIDEuMCwgMC4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4wLCAtMS4wLCAwLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtMS4wLCAwLjAsIDAuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDEuMCwgMC4wLCAwLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjAsIDAuMCwgLTEuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMCwgMC4wLCAxLjAgXQogICAgICAgICAgICAgICAgICBdLAogICAgICAgICAgICAgICAgICAicG9seXMiIDogWwogICAgICAgICAgICAgICAgICAgICBbCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMCwgMCwgMCBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDEsIDAsIDEgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAyLCAwLCAyIF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMywgMCwgMyBdCiAgICAgICAgICAgICAgICAgICAgIF0sCiAgICAgICAgICAgICAgICAgICAgIFsKICAgICAgICAgICAgICAgICAgICAgICAgWyA0LCAxLCA0IF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgNSwgMSwgNSBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDYsIDEsIDYgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyA3LCAxLCA3IF0KICAgICAgICAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAgICAgICAgWwogICAgICAgICAgICAgICAgICAgICAgICBbIDgsIDIsIDggXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyA5LCAyLCA5IF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMTAsIDIsIDEwIF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMTEsIDIsIDExIF0KICAgICAgICAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAgICAgICAgWwogICAgICAgICAgICAgICAgICAgICAgICBbIDEyLCAzLCAxMiBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDEzLCAzLCAxMyBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDE0LCAzLCAxNCBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDE1LCAzLCAxNSBdCiAgICAgICAgICAgICAgICAgICAgIF0sCiAgICAgICAgICAgICAgICAgICAgIFsKICAgICAgICAgICAgICAgICAgICAgICAgWyAxNiwgNCwgMTYgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAxNywgNCwgMTcgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAxOCwgNCwgMTggXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAxOSwgNCwgMTkgXQogICAgICAgICAgICAgICAgICAgICBdLAogICAgICAgICAgICAgICAgICAgICBbCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMjAsIDUsIDIwIF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMjEsIDUsIDIxIF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMjIsIDUsIDIyIF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMjMsIDUsIDIzIF0KICAgICAgICAgICAgICAgICAgICAgXQogICAgICAgICAgICAgICAgICBdLAogICAgICAgICAgICAgICAgICAicG9zaXRpb25zIiA6IFsKICAgICAgICAgICAgICAgICAgICAgWyAtNC4wLCAzMi4wLCAtNC4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgNC4wLCAzMi4wLCAtNC4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgNC4wLCAzMi4wLCA0LjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtNC4wLCAzMi4wLCA0LjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtNC4wLCAyNC4wLCA0LjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyA0LjAsIDI0LjAsIDQuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDQuMCwgMjQuMCwgLTQuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIC00LjAsIDI0LjAsIC00LjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtNC4wLCAyNC4wLCA0LjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtNC4wLCAyNC4wLCAtNC4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTQuMCwgMzIuMCwgLTQuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIC00LjAsIDMyLjAsIDQuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDQuMCwgMjQuMCwgLTQuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDQuMCwgMjQuMCwgNC4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgNC4wLCAzMi4wLCA0LjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyA0LjAsIDMyLjAsIC00LjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtNC4wLCAyNC4wLCAtNC4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgNC4wLCAyNC4wLCAtNC4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgNC4wLCAzMi4wLCAtNC4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTQuMCwgMzIuMCwgLTQuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDQuMCwgMjQuMCwgNC4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTQuMCwgMjQuMCwgNC4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTQuMCwgMzIuMCwgNC4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgNC4wLCAzMi4wLCA0LjAgXQogICAgICAgICAgICAgICAgICBdLAogICAgICAgICAgICAgICAgICAidXZzIiA6IFsKICAgICAgICAgICAgICAgICAgICAgWyAwLjI1MCwgMC44NzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC41MCwgMC44NzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC41MCwgMS4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4yNTAsIDEuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuNzUwLCAxLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjUwLCAxLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjUwLCAwLjg3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjc1MCwgMC44NzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4wLCAwLjc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMjUwLCAwLjc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMjUwLCAwLjg3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjAsIDAuODc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuNTAsIDAuNzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC43NTAsIDAuNzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC43NTAsIDAuODc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuNTAsIDAuODc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMjUwLCAwLjc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuNTAsIDAuNzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC41MCwgMC44NzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4yNTAsIDAuODc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuNzUwLCAwLjc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDEuMCwgMC43NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAxLjAsIDAuODc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuNzUwLCAwLjg3NTAgXQogICAgICAgICAgICAgICAgICBdCiAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfSwKICAgICAgICAgICAgewogICAgICAgICAgICAgICAibmFtZSIgOiAiaGVsbWV0IiwKICAgICAgICAgICAgICAgInBhcmVudCIgOiAiaGVhZCIsCiAgICAgICAgICAgICAgICJwaXZvdCIgOiBbIDAuMCwgMjQuMCwgMC4wIF0KICAgICAgICAgICAgfSwKICAgICAgICAgICAgewogICAgICAgICAgICAgICAibmFtZSIgOiAibGVmdGFybSIsCiAgICAgICAgICAgICAgICJwYXJlbnQiIDogImJvZHkiLAogICAgICAgICAgICAgICAicGl2b3QiIDogWyA1LjAsIDIyLjAsIDAuMCBdCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgIm1pcnJvciIgOiB0cnVlLAogICAgICAgICAgICAgICAibmFtZSIgOiAibGVmdGFybWFybW9yIiwKICAgICAgICAgICAgICAgInBhcmVudCIgOiAibGVmdGFybSIsCiAgICAgICAgICAgICAgICJwaXZvdCIgOiBbIDUuMCwgMjIuMCwgMC4wIF0KICAgICAgICAgICAgfSwKICAgICAgICAgICAgewogICAgICAgICAgICAgICAibWlycm9yIiA6IHRydWUsCiAgICAgICAgICAgICAgICJuYW1lIiA6ICJsZWZ0Ym9vdCIsCiAgICAgICAgICAgICAgICJwYXJlbnQiIDogImxlZnRsZWciLAogICAgICAgICAgICAgICAicGl2b3QiIDogWyAxLjg5OTk5OTk3NjE1ODE0MiwgMTIuMCwgMC4wIF0KICAgICAgICAgICAgfSwKICAgICAgICAgICAgewogICAgICAgICAgICAgICAibmFtZSIgOiAibGVmdGl0ZW0iLAogICAgICAgICAgICAgICAicGFyZW50IiA6ICJsZWZ0YXJtIiwKICAgICAgICAgICAgICAgInBpdm90IiA6IFsgNi4wLCAxNS4wLCAwLjAgXQogICAgICAgICAgICB9LAogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICJuYW1lIiA6ICJsZWZ0bGVnIiwKICAgICAgICAgICAgICAgInBhcmVudCIgOiAicm9vdCIsCiAgICAgICAgICAgICAgICJwaXZvdCIgOiBbIDEuODk5OTk5OTc2MTU4MTQyLCAxMi4wLCAwLjAgXQogICAgICAgICAgICB9LAogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICJtaXJyb3IiIDogdHJ1ZSwKICAgICAgICAgICAgICAgIm5hbWUiIDogImxlZnRsZWdnaW5nIiwKICAgICAgICAgICAgICAgInBhcmVudCIgOiAibGVmdGxlZyIsCiAgICAgICAgICAgICAgICJwaXZvdCIgOiBbIDEuODk5OTk5OTc2MTU4MTQyLCAxMi4wLCAwLjAgXQogICAgICAgICAgICB9LAogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICJtaXJyb3IiIDogdHJ1ZSwKICAgICAgICAgICAgICAgIm5hbWUiIDogImxlZnRzb2NrIiwKICAgICAgICAgICAgICAgInBhcmVudCIgOiAibGVmdGxlZyIsCiAgICAgICAgICAgICAgICJwaXZvdCIgOiBbIDEuODk5OTk5OTc2MTU4MTQyLCAxMi4wLCAwLjAgXQogICAgICAgICAgICB9LAogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICJuYW1lIiA6ICJyaWdodGFybSIsCiAgICAgICAgICAgICAgICJwYXJlbnQiIDogImJvZHkiLAogICAgICAgICAgICAgICAicGl2b3QiIDogWyAtNS4wLCAyMi4wLCAwLjAgXQogICAgICAgICAgICB9LAogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICJuYW1lIiA6ICJyaWdodGFybWFybW9yIiwKICAgICAgICAgICAgICAgInBhcmVudCIgOiAicmlnaHRhcm0iLAogICAgICAgICAgICAgICAicGl2b3QiIDogWyAtNS4wLCAyMi4wLCAwLjAgXQogICAgICAgICAgICB9LAogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICJuYW1lIiA6ICJyaWdodGJvb3QiLAogICAgICAgICAgICAgICAicGFyZW50IiA6ICJyaWdodGxlZyIsCiAgICAgICAgICAgICAgICJwaXZvdCIgOiBbIC0xLjg5OTk5OTk3NjE1ODE0MiwgMTIuMCwgMC4wIF0KICAgICAgICAgICAgfSwKICAgICAgICAgICAgewogICAgICAgICAgICAgICAibG9jYXRvcnMiIDogewogICAgICAgICAgICAgICAgICAibGVhZF9ob2xkIiA6IFsgLTYuMCwgMTUuMCwgMC4wIF0KICAgICAgICAgICAgICAgfSwKICAgICAgICAgICAgICAgIm5hbWUiIDogInJpZ2h0aXRlbSIsCiAgICAgICAgICAgICAgICJwYXJlbnQiIDogInJpZ2h0YXJtIiwKICAgICAgICAgICAgICAgInBpdm90IiA6IFsgLTYuMCwgMTUuMCwgMC4wIF0KICAgICAgICAgICAgfSwKICAgICAgICAgICAgewogICAgICAgICAgICAgICAibmFtZSIgOiAicmlnaHRsZWciLAogICAgICAgICAgICAgICAicGFyZW50IiA6ICJyb290IiwKICAgICAgICAgICAgICAgInBpdm90IiA6IFsgLTEuODk5OTk5OTc2MTU4MTQyLCAxMi4wLCAwLjAgXQogICAgICAgICAgICB9LAogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICJuYW1lIiA6ICJyaWdodGxlZ2dpbmciLAogICAgICAgICAgICAgICAicGFyZW50IiA6ICJyaWdodGxlZyIsCiAgICAgICAgICAgICAgICJwaXZvdCIgOiBbIC0xLjg5OTk5OTk3NjE1ODE0MiwgMTIuMCwgMC4wIF0KICAgICAgICAgICAgfSwKICAgICAgICAgICAgewogICAgICAgICAgICAgICAibmFtZSIgOiAicmlnaHRzb2NrIiwKICAgICAgICAgICAgICAgInBhcmVudCIgOiAicmlnaHRsZWciLAogICAgICAgICAgICAgICAicGl2b3QiIDogWyAtMS44OTk5OTk5NzYxNTgxNDIsIDEyLjAsIDAuMCBdCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgIm5hbWUiIDogInJvb3QiCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgIm5hbWUiIDogIndhaXN0IiwKICAgICAgICAgICAgICAgInBhcmVudCIgOiAicm9vdCIsCiAgICAgICAgICAgICAgICJwaXZvdCIgOiBbIDAuMCwgMTIuMCwgMC4wIF0KICAgICAgICAgICAgfQogICAgICAgICBdLAogICAgICAgICAiZGVzY3JpcHRpb24iIDogewogICAgICAgICAgICAiaWRlbnRpZmllciIgOiAiZ2VvbWV0cnkuYW5pbWF0ZWRfZmFjZV9wZXJzb25hLWUxOTk2NzJhOGMxYTg3ZTAtMCIsCiAgICAgICAgICAgICJ0ZXh0dXJlX2hlaWdodCIgOiA2NC4wLAogICAgICAgICAgICAidGV4dHVyZV93aWR0aCIgOiAzMi4wCiAgICAgICAgIH0KICAgICAgfQogICBdCn0K \ No newline at end of file diff --git a/data/new/compile.js b/data/new/compile.js index 9ba4669..a4ebce5 100644 --- a/data/new/compile.js +++ b/data/new/compile.js @@ -8,11 +8,14 @@ const fs = require('fs') const { ProtoDefCompiler } = require('protodef').Compiler +// Parse the YML files and turn to JSON function genProtoSchema() { const { parse, compile } = require('protodef-yaml/compiler') + let version // Create the packet_map.yml from proto.yml const parsed = parse('./proto.yml') + version = parsed['!version'] const packets = [] for (const key in parsed) { if (key.startsWith('%container')) { @@ -30,31 +33,39 @@ function genProtoSchema() { l1 += ` 0x${id.toString(16).padStart(2, '0')}: ${name}\n` l2 += ` if ${name}: ${fname}\n` } - const t = `!import: types.yaml\nmcpe_packet:\n name: varint =>\n${l1}\n params: name ?\n${l2}` + // TODO: skip creating packet_map.yml and just generate the ProtoDef map JSON directly + const t = `#Auto-generated from proto.yml, do not modify\n!import: types.yaml\nmcpe_packet:\n name: varint =>\n${l1}\n params: name ?\n${l2}` fs.writeFileSync('./packet_map.yml', t) compile('./proto.yml', 'protocol.json') + return version } -genProtoSchema() - -fs.writeFileSync('../newproto.json', JSON.stringify({ types: require('./protocol.json') }, null, 2)) -fs.unlinkSync('./protocol.json') //remove temp file - -function createProtocol() { +// Compile the ProtoDef JSON into JS +function createProtocol(version) { const compiler = new ProtoDefCompiler() - const protocol = require('../newproto.json').types + const protocol = require(`../${version}/protocol.json`).types compiler.addTypes(require('../../src/datatypes/compiler-minecraft')) compiler.addTypes(require('prismarine-nbt/compiler-zigzag')) compiler.addTypesToCompile(protocol) - fs.writeFileSync('../read.js', 'module.exports = ' + compiler.readCompiler.generate()) - fs.writeFileSync('../write.js', 'module.exports = ' + compiler.writeCompiler.generate()) - fs.writeFileSync('../size.js', 'module.exports = ' + compiler.sizeOfCompiler.generate()) + fs.writeFileSync(`../${version}/read.js`, 'module.exports = ' + compiler.readCompiler.generate()) + fs.writeFileSync(`../${version}/write.js`, 'module.exports = ' + compiler.writeCompiler.generate()) + fs.writeFileSync(`../${version}/size.js`, 'module.exports = ' + compiler.sizeOfCompiler.generate()) const compiledProto = compiler.compileProtoDefSync() return compiledProto } -console.log('Generating JS...') -createProtocol() \ No newline at end of file +function main() { + const version = genProtoSchema() + + fs.writeFileSync(`../${version}/protocol.json`, JSON.stringify({ types: require('./protocol.json') }, null, 2)) + fs.unlinkSync('./protocol.json') //remove temp file + fs.unlinkSync('./packet_map.yml') //remove temp file + + console.log('Generating JS...') + createProtocol(version) +} + +main() \ No newline at end of file diff --git a/data/new/packet_map.yml b/data/new/packet_map.yml deleted file mode 100644 index 3734525..0000000 --- a/data/new/packet_map.yml +++ /dev/null @@ -1,317 +0,0 @@ -!import: types.yaml -mcpe_packet: - name: varint => - 0x01: login - 0x02: play_status - 0x03: server_to_client_handshake - 0x04: client_to_server_handshake - 0x05: disconnect - 0x06: resource_packs_info - 0x07: resource_pack_stack - 0x08: resource_pack_client_response - 0x09: text - 0x0a: set_time - 0x0b: start_game - 0x0c: add_player - 0x0d: add_entity - 0x0e: remove_entity - 0x0f: add_item_entity - 0x11: take_item_entity - 0x12: move_entity - 0x13: move_player - 0x14: rider_jump - 0x15: update_block - 0x16: add_painting - 0x17: tick_sync - 0x18: level_sound_event_old - 0x19: level_event - 0x1a: block_event - 0x1b: entity_event - 0x1c: mob_effect - 0x1d: update_attributes - 0x1e: inventory_transaction - 0x1f: mob_equipment - 0x20: mob_armor_equipment - 0x21: interact - 0x22: block_pick_request - 0x23: entity_pick_request - 0x24: player_action - 0x26: hurt_armor - 0x27: set_entity_data - 0x28: set_entity_motion - 0x29: set_entity_link - 0x2a: set_health - 0x2b: set_spawn_position - 0x2c: animate - 0x2d: respawn - 0x2e: container_open - 0x2f: container_close - 0x30: player_hotbar - 0x31: inventory_content - 0x32: inventory_slot - 0x33: container_set_data - 0x34: crafting_data - 0x35: crafting_event - 0x36: gui_data_pick_item - 0x37: adventure_settings - 0x38: block_entity_data - 0x39: player_input - 0x3a: level_chunk - 0x3b: set_commands_enabled - 0x3c: set_difficulty - 0x3d: change_dimension - 0x3e: set_player_game_type - 0x3f: player_list - 0x40: simple_event - 0x41: event - 0x42: spawn_experience_orb - 0x43: clientbound_map_item_data - 0x44: map_info_request - 0x45: request_chunk_radius - 0x46: chunk_radius_update - 0x47: item_frame_drop_item - 0x48: game_rules_changed - 0x49: camera - 0x4a: boss_event - 0x4b: show_credits - 0x4c: available_commands - 0x4d: command_request - 0x4e: command_block_update - 0x4f: command_output - 0x50: update_trade - 0x51: update_equipment - 0x52: resource_pack_data_info - 0x53: resource_pack_chunk_data - 0x54: resource_pack_chunk_request - 0x55: transfer - 0x56: play_sound - 0x57: stop_sound - 0x58: set_title - 0x59: add_behavior_tree - 0x5a: structure_block_update - 0x5b: show_store_offer - 0x5c: purchase_receipt - 0x5d: player_skin - 0x5e: sub_client_login - 0x5f: initiate_web_socket_connection - 0x60: set_last_hurt_by - 0x61: book_edit - 0x62: npc_request - 0x63: photo_transfer - 0x64: modal_form_request - 0x65: modal_form_response - 0x66: server_settings_request - 0x67: server_settings_response - 0x68: show_profile - 0x69: set_default_game_type - 0x6a: remove_objective - 0x6b: set_display_objective - 0x6c: set_score - 0x6d: lab_table - 0x6e: update_block_synced - 0x6f: move_entity_delta - 0x70: set_scoreboard_identity - 0x71: set_local_player_as_initialized - 0x72: update_soft_enum - 0x73: network_stack_latency - 0x75: script_custom_event - 0x76: spawn_particle_effect - 0x77: available_entity_identifiers - 0x78: level_sound_event_v2 - 0x79: network_chunk_publisher_update - 0x7a: biome_definition_list - 0x7b: level_sound_event - 0x7c: level_event_generic - 0x7d: lectern_update - 0x7e: video_stream_connect - 0x7f: add_ecs_entity - 0x80: remove_ecs_entity - 0x81: client_cache_status - 0x82: on_screen_texture_animation - 0x83: map_create_locked_copy - 0x84: structure_template_data_export_request - 0x85: structure_template_data_export_response - 0x86: update_block_properties - 0x87: client_cache_blob_status - 0x88: client_cache_miss_response - 0x89: education_settings - 0x8b: multiplayer_settings - 0x8c: settings_command - 0x8d: anvil_damage - 0x8e: completed_using_item - 0x8f: network_settings - 0x90: player_auth_input - 0x91: creative_content - 0x92: player_enchant_options - 0x93: item_stack_request - 0x94: item_stack_response - 0x95: player_armor_damage - 0x97: update_player_game_type - 0x9a: position_tracking_db_request - 0x99: position_tracking_db_broadcast - 0x9c: packet_violation_warning - 0x9d: motion_prediction_hints - 0x9e: animate_entity - 0x9f: camera_shake - 0xa0: player_fog - 0xa1: correct_player_move_prediction - 0xa2: item_component - 0xa3: filter_text_packet - - params: name ? - if login: packet_login - if play_status: packet_play_status - if server_to_client_handshake: packet_server_to_client_handshake - if client_to_server_handshake: packet_client_to_server_handshake - if disconnect: packet_disconnect - if resource_packs_info: packet_resource_packs_info - if resource_pack_stack: packet_resource_pack_stack - if resource_pack_client_response: packet_resource_pack_client_response - if text: packet_text - if set_time: packet_set_time - if start_game: packet_start_game - if add_player: packet_add_player - if add_entity: packet_add_entity - if remove_entity: packet_remove_entity - if add_item_entity: packet_add_item_entity - if take_item_entity: packet_take_item_entity - if move_entity: packet_move_entity - if move_player: packet_move_player - if rider_jump: packet_rider_jump - if update_block: packet_update_block - if add_painting: packet_add_painting - if tick_sync: packet_tick_sync - if level_sound_event_old: packet_level_sound_event_old - if level_event: packet_level_event - if block_event: packet_block_event - if entity_event: packet_entity_event - if mob_effect: packet_mob_effect - if update_attributes: packet_update_attributes - if inventory_transaction: packet_inventory_transaction - if mob_equipment: packet_mob_equipment - if mob_armor_equipment: packet_mob_armor_equipment - if interact: packet_interact - if block_pick_request: packet_block_pick_request - if entity_pick_request: packet_entity_pick_request - if player_action: packet_player_action - if hurt_armor: packet_hurt_armor - if set_entity_data: packet_set_entity_data - if set_entity_motion: packet_set_entity_motion - if set_entity_link: packet_set_entity_link - if set_health: packet_set_health - if set_spawn_position: packet_set_spawn_position - if animate: packet_animate - if respawn: packet_respawn - if container_open: packet_container_open - if container_close: packet_container_close - if player_hotbar: packet_player_hotbar - if inventory_content: packet_inventory_content - if inventory_slot: packet_inventory_slot - if container_set_data: packet_container_set_data - if crafting_data: packet_crafting_data - if crafting_event: packet_crafting_event - if gui_data_pick_item: packet_gui_data_pick_item - if adventure_settings: packet_adventure_settings - if block_entity_data: packet_block_entity_data - if player_input: packet_player_input - if level_chunk: packet_level_chunk - if set_commands_enabled: packet_set_commands_enabled - if set_difficulty: packet_set_difficulty - if change_dimension: packet_change_dimension - if set_player_game_type: packet_set_player_game_type - if player_list: packet_player_list - if simple_event: packet_simple_event - if event: packet_event - if spawn_experience_orb: packet_spawn_experience_orb - if clientbound_map_item_data: packet_clientbound_map_item_data - if map_info_request: packet_map_info_request - if request_chunk_radius: packet_request_chunk_radius - if chunk_radius_update: packet_chunk_radius_update - if item_frame_drop_item: packet_item_frame_drop_item - if game_rules_changed: packet_game_rules_changed - if camera: packet_camera - if boss_event: packet_boss_event - if show_credits: packet_show_credits - if available_commands: packet_available_commands - if command_request: packet_command_request - if command_block_update: packet_command_block_update - if command_output: packet_command_output - if update_trade: packet_update_trade - if update_equipment: packet_update_equipment - if resource_pack_data_info: packet_resource_pack_data_info - if resource_pack_chunk_data: packet_resource_pack_chunk_data - if resource_pack_chunk_request: packet_resource_pack_chunk_request - if transfer: packet_transfer - if play_sound: packet_play_sound - if stop_sound: packet_stop_sound - if set_title: packet_set_title - if add_behavior_tree: packet_add_behavior_tree - if structure_block_update: packet_structure_block_update - if show_store_offer: packet_show_store_offer - if purchase_receipt: packet_purchase_receipt - if player_skin: packet_player_skin - if sub_client_login: packet_sub_client_login - if initiate_web_socket_connection: packet_initiate_web_socket_connection - if set_last_hurt_by: packet_set_last_hurt_by - if book_edit: packet_book_edit - if npc_request: packet_npc_request - if photo_transfer: packet_photo_transfer - if modal_form_request: packet_modal_form_request - if modal_form_response: packet_modal_form_response - if server_settings_request: packet_server_settings_request - if server_settings_response: packet_server_settings_response - if show_profile: packet_show_profile - if set_default_game_type: packet_set_default_game_type - if remove_objective: packet_remove_objective - if set_display_objective: packet_set_display_objective - if set_score: packet_set_score - if lab_table: packet_lab_table - if update_block_synced: packet_update_block_synced - if move_entity_delta: packet_move_entity_delta - if set_scoreboard_identity: packet_set_scoreboard_identity - if set_local_player_as_initialized: packet_set_local_player_as_initialized - if update_soft_enum: packet_update_soft_enum - if network_stack_latency: packet_network_stack_latency - if script_custom_event: packet_script_custom_event - if spawn_particle_effect: packet_spawn_particle_effect - if available_entity_identifiers: packet_available_entity_identifiers - if level_sound_event_v2: packet_level_sound_event_v2 - if network_chunk_publisher_update: packet_network_chunk_publisher_update - if biome_definition_list: packet_biome_definition_list - if level_sound_event: packet_level_sound_event - if level_event_generic: packet_level_event_generic - if lectern_update: packet_lectern_update - if video_stream_connect: packet_video_stream_connect - if add_ecs_entity: packet_add_ecs_entity - if remove_ecs_entity: packet_remove_ecs_entity - if client_cache_status: packet_client_cache_status - if on_screen_texture_animation: packet_on_screen_texture_animation - if map_create_locked_copy: packet_map_create_locked_copy - if structure_template_data_export_request: packet_structure_template_data_export_request - if structure_template_data_export_response: packet_structure_template_data_export_response - if update_block_properties: packet_update_block_properties - if client_cache_blob_status: packet_client_cache_blob_status - if client_cache_miss_response: packet_client_cache_miss_response - if education_settings: packet_education_settings - if multiplayer_settings: packet_multiplayer_settings - if settings_command: packet_settings_command - if anvil_damage: packet_anvil_damage - if completed_using_item: packet_completed_using_item - if network_settings: packet_network_settings - if player_auth_input: packet_player_auth_input - if creative_content: packet_creative_content - if player_enchant_options: packet_player_enchant_options - if item_stack_request: packet_item_stack_request - if item_stack_response: packet_item_stack_response - if player_armor_damage: packet_player_armor_damage - if update_player_game_type: packet_update_player_game_type - if position_tracking_db_request: packet_position_tracking_db_request - if position_tracking_db_broadcast: packet_position_tracking_db_broadcast - if packet_violation_warning: packet_packet_violation_warning - if motion_prediction_hints: packet_motion_prediction_hints - if animate_entity: packet_animate_entity - if camera_shake: packet_camera_shake - if player_fog: packet_player_fog - if correct_player_move_prediction: packet_correct_player_move_prediction - if item_component: packet_item_component - if filter_text_packet: packet_filter_text_packet diff --git a/data/new/proto.yml b/data/new/proto.yml index 0a3bd85..f296075 100644 --- a/data/new/proto.yml +++ b/data/new/proto.yml @@ -1,4 +1,9 @@ -# Created from MiNET docs +# Created from MiNET and gophertunnel docs +# The version below is the latest version this protocol schema was updated for. +# The output protocol.json will be in the folder for the version +!version: 1.16.201 + +# Some ProtoDef aliases string: ["pstring",{"countType":"varint"}] ByteArray: ["buffer",{"countType":"varint"}] SignedByteArray: ["buffer",{"countType":"zigzag32"}] @@ -12,8 +17,10 @@ byterot: native MapInfo: native nbt: native +# load the packet map file !import: packet_map.yml +#todo: docs !StartDocs: Packets # # Login Sequence diff --git a/data/protocol.json b/data/protocol.json deleted file mode 100644 index f3affcd..0000000 --- a/data/protocol.json +++ /dev/null @@ -1,2517 +0,0 @@ -{ - "types": { - "string": [ - "pstring", - { - "countType": "i16" - } - ], - "lstring": [ - "pstring", - { - "countType": "li16" - } - ], - "vector3": [ - "container", - [ - { - "name": "x", - "type": "lf32" - }, - { - "name": "y", - "type": "lf32" - }, - { - "name": "z", - "type": "lf32" - } - ] - ], - "vector2": [ - "container", - [ - { - "name": "x", - "type": "f32" - }, - { - "name": "y", - "type": "f32" - } - ] - ], - "playerlocation": [ - "array", - { - "countType": "li16", - "type": [ - "container", - [ - { - "name": "x", - "type": "lf32" - }, - { - "name": "y", - "type": "lf32" - }, - { - "name": "z", - "type": "lf32" - }, - { - "name": "yaw", - "type": "f32" - }, - { - "name": "pitch", - "type": "f32" - }, - { - "name": "headYaw", - "type": "f32" - } - ] - ] - } - ], - "encapsulated_packet": [ - "container", - [ - { - "name": "name", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "0xfe": "mcpe" - } - } - ] - }, - { - "name": "params", - "type": [ - "switch", - { - "compareTo": "name", - "fields": { - "mcpe": "mcpe_packet" - } - } - ] - } - ] - ], - "mcpe_packet": [ - "container", - [ - { - "name": "name", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "0x01": "game_login", - "0x02": "play_status", - "0x03": "server_to_client_handshake", - "0x04": "client_to_server_handshake", - "0x05": "disconnect", - "0x06": "resource_packs_info", - "0x07": "resource_pack_stack", - "0x08": "resource_pack_client_response", - "0x09": "text", - "0x0a": "set_time", - "0x0b": "start_game", - "0x0c": "add_player", - "0x0d": "add_entity", - "0x0e": "remove_entity", - "0x0f": "add_item_entity", - "0x11": "take_item_entity", - "0x12": "move_entity", - "0x13": "move_player", - "0x14": "rider_jump", - "0x15": "update_block", - "0x16": "add_painting", - "0x17": "explode", - "0x18": "level_sound_event_old", - "0x19": "level_event", - "0x1a": "block_event", - "0x1b": "entity_event", - "0x1c": "mob_effect", - "0x1d": "update_attributes", - "0x1e": "inventory_transaction", - "0x1f": "mob_equipment", - "0x20": "mob_armor_equipment", - "0x21": "interact", - "0x22": "block_pick_request", - "0x23": "entity_pick_request", - "0x24": "player_action", - "0x25": "entity_fall", - "0x26": "hurt_armor", - "0x27": "set_entity_data", - "0x28": "set_entity_motion", - "0x29": "set_entity_link", - "0x2a": "set_health", - "0x2b": "set_spawn_position", - "0x2c": "animate", - "0x2d": "respawn", - "0x2e": "container_open", - "0x2f": "container_close", - "0x30": "player_hotbar", - "0x31": "inventory_content", - "0x32": "inventory_slot", - "0x33": "container_set_data", - "0x34": "crafting_data", - "0x35": "crafting_event", - "0x36": "gui_data_pick_item", - "0x37": "adventure_settings", - "0x38": "block_entity_data", - "0x39": "player_input", - "0x3a": "full_chunk_data", - "0x3b": "set_commands_enabled", - "0x3c": "set_difficulty", - "0x3d": "change_dimension", - "0x3e": "set_player_game_type", - "0x3f": "player_list", - "0x40": "simple_event", - "0x41": "telemetry_event", - "0x42": "spawn_experience_orb", - "0x43": "clientbound_map_item_data_", - "0x44": "map_info_request", - "0x45": "request_chunk_radius", - "0x46": "chunk_radius_update", - "0x47": "item_frame_drop_item", - "0x48": "game_rules_changed", - "0x49": "camera", - "0x4a": "boss_event", - "0x4b": "show_credits", - "0x4c": "available_commands", - "0x4d": "command_request", - "0x4e": "command_block_update", - "0x4f": "command_output", - "0x50": "update_trade", - "0x51": "update_equipment", - "0x52": "resource_pack_data_info", - "0x53": "resource_pack_chunk_data", - "0x54": "resource_pack_chunk_request", - "0x55": "transfer", - "0x56": "play_sound", - "0x57": "stop_sound", - "0x58": "set_title", - "0x59": "add_behavior_tree", - "0x5a": "structure_block_update", - "0x5b": "show_store_offer", - "0x5c": "purchase_receipt", - "0x5d": "player_skin", - "0x5e": "sub_client_login", - "0x5f": "initiate_web_socket_connection", - "0x60": "set_last_hurt_by", - "0x61": "book_edit", - "0x62": "npc_request", - "0x63": "photo_transfer", - "0x64": "modal_form_request", - "0x65": "modal_form_response", - "0x66": "server_settings_request", - "0x67": "server_settings_response", - "0x68": "show_profile", - "0x69": "set_default_game_type", - "0x6a": "remove_objective", - "0x6b": "set_display_objective", - "0x6c": "set_score", - "0x6d": "lab_table", - "0x6e": "update_block_synced", - "0x6f": "move_entity_delta", - "0x70": "set_scoreboard_identity_packet", - "0x71": "set_local_player_as_initialized_packet", - "0x72": "update_soft_enum_packet", - "0x73": "network_stack_latency_packet", - "0x75": "script_custom_event_packet", - "0x76": "spawn_particle_effect", - "0x77": "available_entity_identifiers", - "0x78": "level_sound_event_v2", - "0x79": "network_chunk_publisher_update", - "0x7a": "biome_definition_list", - "0x7b": "level_sound_event" - } - } - ] - }, - { - "name": "params", - "type": [ - "switch", - { - "compareTo": "name", - "fields": { - "game_login": "packet_game_login", - "play_status": "packet_play_status", - "server_to_client_handshake": "packet_server_to_client_handshake", - "client_to_server_handshake": "packet_client_to_server_handshake", - "disconnect": "packet_disconnect", - "resource_packs_info": "packet_resource_packs_info", - "resource_pack_stack": "packet_resource_pack_stack", - "resource_pack_client_response": "packet_resource_pack_client_response", - "text": "packet_text", - "set_time": "packet_set_time", - "start_game": "packet_start_game", - "add_player": "packet_add_player", - "add_entity": "packet_add_entity", - "remove_entity": "packet_remove_entity", - "add_item_entity": "packet_add_item_entity", - "take_item_entity": "packet_take_item_entity", - "move_entity": "packet_move_entity", - "move_player": "packet_move_player", - "rider_jump": "packet_rider_jump", - "update_block": "packet_update_block", - "add_painting": "packet_add_painting", - "explode": "packet_explode", - "level_sound_event_old": "packet_level_sound_event_old", - "level_event": "packet_level_event", - "block_event": "packet_block_event", - "entity_event": "packet_entity_event", - "mob_effect": "packet_mob_effect", - "update_attributes": "packet_update_attributes", - "inventory_transaction": "packet_inventory_transaction", - "mob_equipment": "packet_mob_equipment", - "mob_armor_equipment": "packet_mob_armor_equipment", - "interact": "packet_interact", - "block_pick_request": "packet_block_pick_request", - "entity_pick_request": "packet_entity_pick_request", - "player_action": "packet_player_action", - "entity_fall": "packet_entity_fall", - "hurt_armor": "packet_hurt_armor", - "set_entity_data": "packet_set_entity_data", - "set_entity_motion": "packet_set_entity_motion", - "set_entity_link": "packet_set_entity_link", - "set_health": "packet_set_health", - "set_spawn_position": "packet_set_spawn_position", - "animate": "packet_animate", - "respawn": "packet_respawn", - "container_open": "packet_container_open", - "container_close": "packet_container_close", - "player_hotbar": "packet_player_hotbar", - "inventory_content": "packet_inventory_content", - "inventory_slot": "packet_inventory_slot", - "container_set_data": "packet_container_set_data", - "crafting_data": "packet_crafting_data", - "crafting_event": "packet_crafting_event", - "gui_data_pick_item": "packet_gui_data_pick_item", - "adventure_settings": "packet_adventure_settings", - "block_entity_data": "packet_block_entity_data", - "player_input": "packet_player_input", - "full_chunk_data": "packet_full_chunk_data", - "set_commands_enabled": "packet_set_commands_enabled", - "set_difficulty": "packet_set_difficulty", - "change_dimension": "packet_change_dimension", - "set_player_game_type": "packet_set_player_game_type", - "player_list": "packet_player_list", - "simple_event": "packet_simple_event", - "telemetry_event": "packet_telemetry_event", - "spawn_experience_orb": "packet_spawn_experience_orb", - "clientbound_map_item_data_": "packet_clientbound_map_item_data_", - "map_info_request": "packet_map_info_request", - "request_chunk_radius": "packet_request_chunk_radius", - "chunk_radius_update": "packet_chunk_radius_update", - "item_frame_drop_item": "packet_item_frame_drop_item", - "game_rules_changed": "packet_game_rules_changed", - "camera": "packet_camera", - "boss_event": "packet_boss_event", - "show_credits": "packet_show_credits", - "available_commands": "packet_available_commands", - "command_request": "packet_command_request", - "command_block_update": "packet_command_block_update", - "command_output": "packet_command_output", - "update_trade": "packet_update_trade", - "update_equipment": "packet_update_equipment", - "resource_pack_data_info": "packet_resource_pack_data_info", - "resource_pack_chunk_data": "packet_resource_pack_chunk_data", - "resource_pack_chunk_request": "packet_resource_pack_chunk_request", - "transfer": "packet_transfer", - "play_sound": "packet_play_sound", - "stop_sound": "packet_stop_sound", - "set_title": "packet_set_title", - "add_behavior_tree": "packet_add_behavior_tree", - "structure_block_update": "packet_structure_block_update", - "show_store_offer": "packet_show_store_offer", - "purchase_receipt": "packet_purchase_receipt", - "player_skin": "packet_player_skin", - "sub_client_login": "packet_sub_client_login", - "initiate_web_socket_connection": "packet_initiate_web_socket_connection", - "set_last_hurt_by": "packet_set_last_hurt_by", - "book_edit": "packet_book_edit", - "npc_request": "packet_npc_request", - "photo_transfer": "packet_photo_transfer", - "modal_form_request": "packet_modal_form_request", - "modal_form_response": "packet_modal_form_response", - "server_settings_request": "packet_server_settings_request", - "server_settings_response": "packet_server_settings_response", - "show_profile": "packet_show_profile", - "set_default_game_type": "packet_set_default_game_type", - "remove_objective": "packet_remove_objective", - "set_display_objective": "packet_set_display_objective", - "set_score": "packet_set_score", - "lab_table": "packet_lab_table", - "update_block_synced": "packet_update_block_synced", - "move_entity_delta": "packet_move_entity_delta", - "set_scoreboard_identity_packet": "packet_set_scoreboard_identity_packet", - "set_local_player_as_initialized_packet": "packet_set_local_player_as_initialized_packet", - "update_soft_enum_packet": "packet_update_soft_enum_packet", - "network_stack_latency_packet": "packet_network_stack_latency_packet", - "script_custom_event_packet": "packet_script_custom_event_packet", - "spawn_particle_effect": "packet_spawn_particle_effect", - "available_entity_identifiers": "packet_available_entity_identifiers", - "level_sound_event_v2": "packet_level_sound_event_v2", - "network_chunk_publisher_update": "packet_network_chunk_publisher_update", - "biome_definition_list": "packet_biome_definition_list", - "level_sound_event": "packet_level_sound_event" - } - } - ] - } - ] - ], - "packet_game_login": [ - "container", - [ - { - "name": "protocol", - "type": "i32" - }, - { - "name": "edition", - "type": "i8" - }, - { - "name": "body", - "type": [ - "buffer", - { - "countType": "varint" - } - ] - } - ] - ], - "packet_play_status": [ - "container", - [ - { - "name": "status", - "type": "i32" - } - ] - ], - "packet_server_to_client_handshake": [ - "container", - [ - { - "name": "token", - "type": "string" - } - ] - ], - "packet_client_to_server_handshake": [ - "container", - [] - ], - "packet_disconnect": [ - "container", - [ - { - "name": "hide_disconnect_reason", - "type": "bool" - }, - { - "name": "message", - "type": "string" - } - ] - ], - "packet_resource_packs_info": [ - "container", - [ - { - "name": "must_accept", - "type": "bool" - }, - { - "name": "has_scripts", - "type": "bool" - }, - { - "name": "behahaviorpackinfos", - "type": "varint" - }, - { - "name": "resourcepackinfos", - "type": "varint" - } - ] - ], - "packet_resource_pack_stack": [ - "container", - [ - { - "name": "must_accept", - "type": "bool" - }, - { - "name": "behaviorpackidversions", - "type": "varint" - }, - { - "name": "resourcepackidversions", - "type": "varint" - }, - { - "name": "is_experimental", - "type": "bool" - } - ] - ], - "packet_resource_pack_client_response": [ - "container", - [ - { - "name": "response_status", - "type": "u8" - }, - { - "name": "resourcepackids", - "type": "varint" - } - ] - ], - "packet_text": [ - "container", - [ - { - "name": "type", - "type": "i8" - }, - { - "name": "source", - "type": [ - "switch", - { - "compareTo": "type", - "fields": { - "1": "string", - "3": "string" - }, - "default": "void" - } - ] - }, - { - "name": "message", - "type": [ - "switch", - { - "compareTo": "type", - "fields": { - "0": "string", - "1": "string", - "2": "string", - "3": "string", - "4": "string", - "5": "string" - }, - "default": "void" - } - ] - } - ] - ], - "packet_set_time": [ - "container", - [ - { - "name": "time", - "type": "varint" - } - ] - ], - "packet_start_game": [ - "container", - [ - { - "name": "entity_id_self", - "type": "varint" - }, - { - "name": "runtime_entity_id", - "type": "varint" - }, - { - "name": "player_gamemode", - "type": "varint" - }, - - { - "name": "spawn", - "type": "vector3" - }, - - { - "name": "pitch", - "type": "lf32" - }, - { - "name": "yaw", - "type": "lf32" - }, - - { - "name": "seed", - "type": "varint" - }, - { - "name": "dimension", - "type": "varint" - }, - { - "name": "generator", - "type": "varint" - }, - { - "name": "gamemode", - "type": "varint" - }, - { - "name": "difficulty", - "type": "varint" - }, - - { - "name": "x", - "type": "varint" - }, - { - "name": "y", - "type": "varint" - }, - { - "name": "z", - "type": "varint" - }, - - { - "name": "has_achievements_disabled", - "type": "bool" - }, - { - "name": "time", - "type": "varint" - }, - { - "name": "edu_mode", - "type": "bool" - }, - { - "name": "has_edu_features_enabled", - "type": "bool" - }, - { - "name": "rain_level", - "type": "lf32" - }, - { - "name": "lightning_level", - "type": "lf32" - }, - { - "name": "has_confirmed_platform_locked_content", - "type": "bool" - }, - { - "name": "is_multiplayer", - "type": "bool" - }, - { - "name": "broadcast_to_lan", - "type": "bool" - }, - { - "name": "xbox_live_broadcast_mode", - "type": "varint" - }, - { - "name": "platform_broadcast_mode", - "type": "varint" - }, - { - "name": "enable_commands", - "type": "bool" - }, - { - "name": "is_texturepacks_required", - "type": "bool" - }, - - { - "name": "u8", - "type": "u8" - }, - - { - "name": "bonus_chest", - "type": "bool" - }, - { - "name": "map_enabled", - "type": "bool" - }, - { - "name": "permission_level", - "type": "varint" - }, - - { - "name": "server_chunk_tick_range", - "type": "i32" - }, - - { - "name": "has_locked_behavior_pack", - "type": "bool" - }, - { - "name": "has_locked_resource_pack", - "type": "bool" - }, - - { - "name": "is_from_locked_world_template", - "type": "bool" - }, - { - "name": "use_msa_gamertags_only", - "type": "bool" - }, - { - "name": "is_from_world_template", - "type": "bool" - }, - { - "name": "is_world_template_option_locked", - "type": "bool" - }, - { - "name": "use_v1_villagers", - "type": "bool" - }, - - { - "name": "level_id", - "type": "string" - }, - { - "name": "world_name", - "type": "string" - }, - { - "name": "premium_world_template_id", - "type": "string" - }, - { - "name": "is_trial", - "type": "bool" - }, - { - "name": "current_tick", - "type": "i64" - }, - { - "name": "enchantment_seed", - "type": "varint" - }, - - { - "name": "blockstates", - "type": "u8" - }, - { - "name": "itemtable", - "type": "u8" - }, - { - "name": "multiplayer_correlation_id", - "type": "string" - } - ] - ], - "packet_add_player": [ - "container", - [ - { - "name": "uuid", - "type": "string" - }, - { - "name": "username", - "type": "string" - }, - - { - "name": "entity_id_self", - "type": "varint" - }, - { - "name": "runtime_entity_id", - "type": "varint" - }, - { - "name": "platform_chat_id", - "type": "string" - }, - - { - "name": "position", - "type": "vector3" - }, - { - "name": "motion", - "type": "vector3" - }, - - { - "name": "pitch", - "type": "lf32" - }, - { - "name": "yaw", - "type": "lf32" - }, - { - "name": "head_yaw", - "type": "lf32" - }, - - { - "name": "item", - "type": "u8" - }, - { - "name": "metadata", - "type": "u8" - }, - - { - "name": "flags", - "type": "varint" - }, - { - "name": "command_permission", - "type": "varint" - }, - { - "name": "action_permissions", - "type": "varint" - }, - { - "name": "permission_level", - "type": "varint" - }, - { - "name": "custom_stored_permissions", - "type": "varint" - }, - - { - "name": "user_id", - "type": "i64" - }, - { - "name": "links", - "type": "u8" - }, - { - "name": "device_id", - "type": "string" - } - ] - ], - "packet_add_entity": [ - "container", - [ - { - "name": "entity_id_self", - "type": "varint" - } - ] - ], - "packet_remove_entity": [ - "container", - [ - { - "name": "entity_id_self", - "type": "varint" - } - ] - ], - "packet_add_item_entity": [ - "container", - [ - { - "name": "entity_id_self", - "type": "varint" - }, - { - "name": "runtime_entity_id", - "type": "varint" - }, - { - "name": "item", - "type": "varint" - }, - { - "name": "x", - "type": "lf32" - }, - { - "name": "y", - "type": "lf32" - }, - { - "name": "z", - "type": "lf32" - }, - { - "name": "speed_x", - "type": "lf32" - }, - { - "name": "speed_y", - "type": "lf32" - }, - { - "name": "speed_z", - "type": "lf32" - }, - { - "name": "metadata", - "type": "varint" - }, - { - "name": "is_from_fishing", - "type": "bool" - } - ] - ], - "packet_take_item_entity": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint" - }, - { - "name": "target", - "type": "varint" - } - ] - ], - "packet_move_entity": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint" - }, - { - "name": "flags", - "type": "u8" - }, - { - "name": "position", - "type": "playerlocation" - } - ] - ], - "packet_move_player": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint" - }, - { - "name": "x", - "type": "lf32" - }, - { - "name": "y", - "type": "lf32" - }, - { - "name": "z", - "type": "lf32" - }, - { - "name": "pitch", - "type": "lf32" - }, - { - "name": "yaw", - "type": "lf32" - }, - { - "name": "head_yaw", - "type": "lf32" - }, - { - "name": "mode", - "type": "u8" - }, - { - "name": "on_ground", - "type": "bool" - }, - { - "name": "other_runtime_entity_id", - "type": "varint" - } - ] - ], - "packet_rider_jump": [ - "container", - [ - { - "name": "unknown", - "type": "varint" - } - ] - ], - "packet_update_block": [ - "container", - [ - { - "name": "coordinates", - "type": "varint" - }, - { - "name": "block_runtime_id", - "type": "varint" - }, - { - "name": "block_priority", - "type": "varint" - }, - { - "name": "storage", - "type": "varint" - } - ] - ], - "packet_add_painting": [ - "container", - [ - { - "name": "entity_id_self", - "type": "varint" - }, - { - "name": "runtime_entity_id", - "type": "varint" - }, - { - "name": "coordinates", - "type": "varint" - }, - { - "name": "direction", - "type": "varint" - }, - { - "name": "title", - "type": "string" - } - ] - ], - "packet_explode": [ - "container", - [ - { - "name": "position", - "type": "vector3" - }, - { - "name": "radius", - "type": "varint" - }, - { - "name": "records", - "type": "varint" - } - ] - ], - "packet_level_sound_event_old": [ - "container", - [ - { - "name": "sound_id", - "type": "u8" - }, - { - "name": "position", - "type": "vector3" - }, - { - "name": "block_id", - "type": "varint" - }, - { - "name": "entity_type", - "type": "varint" - }, - { - "name": "is_baby_mob", - "type": "bool" - }, - { - "name": "is_global", - "type": "bool" - } - ] - ], - "packet_level_event": [ - "container", - [ - { - "name": "event_id", - "type": "varint" - }, - { - "name": "position", - "type": "vector3" - }, - { - "name": "data", - "type": "varint" - } - ] - ], - "packet_block_event": [ - "container", - [ - { - "name": "coordinates", - "type": "varint" - }, - { - "name": "case_1", - "type": "varint" - }, - { - "name": "case_2", - "type": "varint" - } - ] - ], - "packet_entity_event": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint" - }, - { - "name": "event_id", - "type": "u8" - }, - { - "name": "data", - "type": "varint" - } - ] - ], - "packet_mob_effect": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint" - }, - { - "name": "event_id", - "type": "u8" - }, - { - "name": "effect_id", - "type": "varint" - }, - { - "name": "amplifier", - "type": "varint" - }, - { - "name": "particles", - "type": "bool" - }, - { - "name": "duration", - "type": "varint" - } - ] - ], - "packet_update_attributes": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint" - }, - { - "name": "attributes", - "type": "varint" - } - ] - ], - "packet_inventory_transaction": [ - "container", - [ - { - "name": "transaction_type", - "type": "varint" - }, - { - "name": "transaction", - "type": "varint" - } - ] - ], - "packet_mob_equipment": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint" - }, - { - "name": "item", - "type": "varint" - }, - { - "name": "slot", - "type": "u8" - }, - { - "name": "selected_slot", - "type": "u8" - }, - { - "name": "windows_id", - "type": "u8" - } - ] - ], - "packet_mob_armor_equipment": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint" - }, - { - "name": "helmet", - "type": "varint" - }, - { - "name": "chestplate", - "type": "varint" - }, - { - "name": "leggings", - "type": "varint" - }, - { - "name": "boots", - "type": "varint" - } - ] - ], - "packet_interact": [ - "container", - [ - { - "name": "action_id", - "type": "u8" - }, - { - "name": "target_runtime_entity_id", - "type": "varint" - } - ] - ], - "packet_block_pick_request": [ - "container", - [ - { - "name": "x", - "type": "varint" - }, - { - "name": "y", - "type": "varint" - }, - { - "name": "z", - "type": "varint" - }, - { - "name": "add_user_data", - "type": "bool" - }, - { - "name": "selected_slot", - "type": "u8" - } - ] - ], - "packet_entity_pick_request": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "u64" - }, - { - "name": "selected_slot", - "type": "u8" - } - ] - ], - "packet_player_action": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint" - }, - { - "name": "action_id", - "type": "varint" - }, - { - "name": "coordinates", - "type": "varint" - }, - { - "name": "face", - "type": "varint" - } - ] - ], - "packet_entity_fall": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint" - }, - { - "name": "fall_distance", - "type": "lf32" - }, - { - "name": "is_in_void", - "type": "bool" - } - ] - ], - "packet_hurt_armor": [ - "container", - [ - { - "name": "health", - "type": "varint" - } - ] - ], - "packet_set_entity_data": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint" - }, - { - "name": "metadata", - "type": "varint" - } - ] - ], - "packet_set_entity_motion": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint" - }, - { - "name": "velocity", - "type": "vector3" - } - ] - ], - "packet_set_entity_link": [ - "container", - [ - { - "name": "ridden_id", - "type": "varint" - }, - { - "name": "rider_id", - "type": "varint" - }, - { - "name": "link_type", - "type": "u8" - }, - { - "name": "unknown", - "type": "u8" - } - ] - ], - "packet_set_health": [ - "container", - [ - { - "name": "health", - "type": "varint" - } - ] - ], - "packet_set_spawn_position": [ - "container", - [ - { - "name": "spawn_type", - "type": "varint" - }, - { - "name": "coordinates", - "type": "varint" - }, - { - "name": "forced", - "type": "bool" - } - ] - ], - "packet_animate": [ - "container", - [ - { - "name": "action_id", - "type": "varint" - }, - { - "name": "runtime_entity_id", - "type": "varint" - } - ] - ], - "packet_respawn": [ - "container", - [ - { - "name": "x", - "type": "lf32" - }, - { - "name": "y", - "type": "lf32" - }, - { - "name": "z", - "type": "lf32" - } - ] - ], - "packet_container_open": [ - "container", - [ - { - "name": "window_id", - "type": "u8" - }, - { - "name": "type", - "type": "u8" - }, - { - "name": "coordinates", - "type": "varint" - }, - { - "name": "runtime_entity_id", - "type": "varint" - } - ] - ], - "packet_container_close": [ - "container", - [ - { - "name": "window_id", - "type": "u8" - } - ] - ], - "packet_player_hotbar": [ - "container", - [ - { - "name": "selected_slot", - "type": "varint" - }, - { - "name": "window_id", - "type": "u8" - }, - { - "name": "select_slot_", - "type": "bool" - } - ] - ], - "packet_inventory_content": [ - "container", - [ - { - "name": "inventory_id", - "type": "varint" - }, - { - "name": "input", - "type": "varint" - } - ] - ], - "packet_inventory_slot": [ - "container", - [ - { - "name": "inventory_id", - "type": "varint" - }, - { - "name": "slot", - "type": "varint" - }, - { - "name": "item", - "type": "varint" - } - ] - ], - "packet_container_set_data": [ - "container", - [ - { - "name": "window_id", - "type": "u8" - }, - { - "name": "property", - "type": "varint" - }, - { - "name": "value", - "type": "varint" - } - ] - ], - "packet_crafting_data": [ - "container", - [ - { - "name": "recipes", - "type": "varint" - } - ] - ], - "packet_crafting_event": [ - "container", - [ - { - "name": "window_id", - "type": "u8" - }, - { - "name": "recipe_type", - "type": "varint" - }, - { - "name": "recipe_id", - "type": "string" - }, - { - "name": "input", - "type": "varint" - }, - { - "name": "result", - "type": "varint" - } - ] - ], - "packet_gui_data_pick_item": [ - "container", - [] - ], - "packet_adventure_settings": [ - "container", - [ - { - "name": "flags", - "type": "varint" - }, - { - "name": "command_permission", - "type": "varint" - }, - { - "name": "action_permissions", - "type": "varint" - }, - { - "name": "permission_level", - "type": "varint" - }, - { - "name": "custom_stored_permissions", - "type": "varint" - }, - { - "name": "user_id", - "type": "i64" - } - ] - ], - "packet_block_entity_data": [ - "container", - [ - { - "name": "coordinates", - "type": "varint" - }, - { - "name": "namedtag", - "type": "varint" - } - ] - ], - "packet_player_input": [ - "container", - [ - { - "name": "motion_x", - "type": "lf32" - }, - { - "name": "motion_z", - "type": "lf32" - }, - { - "name": "jumping", - "type": "bool" - }, - { - "name": "sneaking", - "type": "bool" - } - ] - ], - "packet_full_chunk_data": [ - "container", - [ - { - "name": "chunk_x", - "type": "varint" - }, - { - "name": "chunk_z", - "type": "varint" - } - ] - ], - "packet_set_commands_enabled": [ - "container", - [ - { - "name": "enabled", - "type": "bool" - } - ] - ], - "packet_set_difficulty": [ - "container", - [ - { - "name": "difficulty", - "type": "varint" - } - ] - ], - "packet_change_dimension": [ - "container", - [ - { - "name": "dimension", - "type": "varint" - }, - { - "name": "position", - "type": "vector3" - }, - { - "name": "respawn", - "type": "bool" - } - ] - ], - "packet_set_player_game_type": [ - "container", - [ - { - "name": "gamemode", - "type": "varint" - } - ] - ], - "packet_player_list": [ - "container", - [ - { - "name": "records", - "type": "varint" - } - ] - ], - "packet_simple_event": [ - "container", - [ - { - "name": "event_type", - "type": "u8" - } - ] - ], - "packet_telemetry_event": [ - "container", - [ - { - "name": "entity_id_self", - "type": "varint" - }, - { - "name": "unk1", - "type": "varint" - }, - { - "name": "unk2", - "type": "u8" - } - ] - ], - "packet_spawn_experience_orb": [ - "container", - [ - { - "name": "position", - "type": "vector3" - }, - { - "name": "count", - "type": "varint" - } - ] - ], - "packet_clientbound_map_item_data_": [ - "container", - [ - { - "name": "mapinfo", - "type": "varint" - } - ] - ], - "packet_map_info_request": [ - "container", - [ - { - "name": "map_id", - "type": "varint" - } - ] - ], - "packet_request_chunk_radius": [ - "container", - [ - { - "name": "chunk_radius", - "type": "varint" - } - ] - ], - "packet_chunk_radius_update": [ - "container", - [ - { - "name": "chunk_radius", - "type": "varint" - } - ] - ], - "packet_item_frame_drop_item": [ - "container", - [ - { - "name": "coordinates", - "type": "varint" - } - ] - ], - "packet_game_rules_changed": [ - "container", - [ - { - "name": "rules", - "type": "u8" - } - ] - ], - "packet_camera": [ - "container", - [ - { - "name": "unknown1", - "type": "varint" - }, - { - "name": "unknown2", - "type": "varint" - } - ] - ], - "packet_boss_event": [ - "container", - [ - { - "name": "boss_entity_id", - "type": "varint" - }, - { - "name": "event_type", - "type": "varint" - } - ] - ], - "packet_show_credits": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint" - }, - { - "name": "status", - "type": "varint" - } - ] - ], - "packet_available_commands": [ - "container", - [] - ], - "packet_command_request": [ - "container", - [ - { - "name": "command", - "type": "string" - }, - { - "name": "command_type", - "type": "varint" - }, - { - "name": "unknown_uuid", - "type": "string" - }, - { - "name": "request_id", - "type": "string" - }, - { - "name": "unknown", - "type": "bool" - } - ] - ], - "packet_command_block_update": [ - "container", - [ - { - "name": "is_block", - "type": "bool" - } - ] - ], - "packet_command_output": [ - "container", - [] - ], - "packet_update_trade": [ - "container", - [ - { - "name": "window_id", - "type": "u8" - }, - { - "name": "window_type", - "type": "u8" - }, - { - "name": "unknown0", - "type": "varint" - }, - { - "name": "unknown1", - "type": "varint" - }, - { - "name": "unknown2", - "type": "varint" - }, - { - "name": "is_willing", - "type": "bool" - }, - { - "name": "trader_entity_id", - "type": "varint" - }, - { - "name": "player_entity_id", - "type": "varint" - }, - { - "name": "display_name", - "type": "string" - }, - { - "name": "namedtag", - "type": "varint" - } - ] - ], - "packet_update_equipment": [ - "container", - [ - { - "name": "window_id", - "type": "u8" - }, - { - "name": "window_type", - "type": "u8" - }, - { - "name": "unknown", - "type": "u8" - }, - { - "name": "entity_id", - "type": "varint" - }, - { - "name": "namedtag", - "type": "varint" - } - ] - ], - "packet_resource_pack_data_info": [ - "container", - [ - { - "name": "package_id", - "type": "string" - }, - { - "name": "max_chunk_size", - "type": "u32" - }, - { - "name": "chunk_count", - "type": "u32" - }, - { - "name": "compressed_package_size", - "type": "u64" - } - ] - ], - "packet_resource_pack_chunk_data": [ - "container", - [ - { - "name": "package_id", - "type": "string" - }, - { - "name": "chunk_index", - "type": "u32" - }, - { - "name": "progress", - "type": "u64" - }, - { - "name": "length", - "type": "u32" - } - ] - ], - "packet_resource_pack_chunk_request": [ - "container", - [ - { - "name": "package_id", - "type": "string" - }, - { - "name": "chunk_index", - "type": "u32" - } - ] - ], - "packet_transfer": [ - "container", - [ - { - "name": "server_address", - "type": "string" - }, - { - "name": "port", - "type": "u8" - } - ] - ], - "packet_play_sound": [ - "container", - [ - { - "name": "name", - "type": "string" - }, - { - "name": "coordinates", - "type": "varint" - }, - { - "name": "volume", - "type": "lf32" - }, - { - "name": "pitch", - "type": "lf32" - } - ] - ], - "packet_stop_sound": [ - "container", - [ - { - "name": "name", - "type": "string" - }, - { - "name": "stop_all", - "type": "bool" - } - ] - ], - "packet_set_title": [ - "container", - [ - { - "name": "type", - "type": "varint" - }, - { - "name": "text", - "type": "string" - }, - { - "name": "fade_in_time", - "type": "varint" - }, - { - "name": "stay_time", - "type": "varint" - }, - { - "name": "fade_out_time", - "type": "varint" - } - ] - ], - "packet_add_behavior_tree": [ - "container", - [ - { - "name": "behaviortree", - "type": "string" - } - ] - ], - "packet_structure_block_update": [ - "container", - [] - ], - "packet_show_store_offer": [ - "container", - [ - { - "name": "unknown0", - "type": "string" - }, - { - "name": "unknown1", - "type": "bool" - } - ] - ], - "packet_purchase_receipt": [ - "container", - [] - ], - "packet_player_skin": [ - "container", - [ - { - "name": "uuid", - "type": "string" - }, - { - "name": "skin_id", - "type": "string" - }, - { - "name": "skin_name", - "type": "string" - }, - { - "name": "old_skin_name", - "type": "string" - } - ] - ], - "packet_sub_client_login": [ - "container", - [] - ], - "packet_initiate_web_socket_connection": [ - "container", - [ - { - "name": "server", - "type": "string" - } - ] - ], - "packet_set_last_hurt_by": [ - "container", - [ - { - "name": "unknown", - "type": "varint" - } - ] - ], - "packet_book_edit": [ - "container", - [] - ], - "packet_npc_request": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint" - }, - { - "name": "unknown0", - "type": "u8" - }, - { - "name": "unknown1", - "type": "string" - }, - { - "name": "unknown2", - "type": "u8" - } - ] - ], - "packet_photo_transfer": [ - "container", - [ - { - "name": "file_name", - "type": "string" - }, - { - "name": "image_data", - "type": "string" - }, - { - "name": "unknown2", - "type": "string" - } - ] - ], - "packet_modal_form_request": [ - "container", - [ - { - "name": "form_id", - "type": "varint" - }, - { - "name": "data", - "type": "string" - } - ] - ], - "packet_modal_form_response": [ - "container", - [ - { - "name": "form_id", - "type": "varint" - }, - { - "name": "data", - "type": "string" - } - ] - ], - "packet_server_settings_request": [ - "container", - [] - ], - "packet_server_settings_response": [ - "container", - [ - { - "name": "form_id", - "type": "varint" - }, - { - "name": "data", - "type": "string" - } - ] - ], - "packet_show_profile": [ - "container", - [ - { - "name": "xuid", - "type": "string" - } - ] - ], - "packet_set_default_game_type": [ - "container", - [ - { - "name": "gamemode", - "type": "varint" - } - ] - ], - "packet_remove_objective": [ - "container", - [ - { - "name": "objective_name", - "type": "string" - } - ] - ], - "packet_set_display_objective": [ - "container", - [ - { - "name": "display_slot", - "type": "string" - }, - { - "name": "objective_name", - "type": "string" - }, - { - "name": "display_name", - "type": "string" - }, - { - "name": "criteria_name", - "type": "string" - }, - { - "name": "sort_order", - "type": "varint" - } - ] - ], - "packet_set_score": [ - "container", - [ - { - "name": "entries", - "type": "u8" - } - ] - ], - "packet_lab_table": [ - "container", - [ - { - "name": "useless_byte", - "type": "u8" - }, - { - "name": "lab_table_x", - "type": "varint" - }, - { - "name": "lab_table_y", - "type": "varint" - }, - { - "name": "lab_table_z", - "type": "varint" - }, - { - "name": "reaction_type", - "type": "u8" - } - ] - ], - "packet_update_block_synced": [ - "container", - [ - { - "name": "coordinates", - "type": "varint" - }, - { - "name": "block_runtime_id", - "type": "varint" - }, - { - "name": "block_priority", - "type": "varint" - }, - { - "name": "data_layer_id", - "type": "varint" - }, - { - "name": "unknown0", - "type": "varint" - }, - { - "name": "unknown1", - "type": "varint" - } - ] - ], - "packet_move_entity_delta": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint" - }, - { - "name": "flags", - "type": "u8" - } - ] - ], - "packet_set_scoreboard_identity_packet": [ - "container", - [ - { - "name": "entries", - "type": "u8" - } - ] - ], - "packet_set_local_player_as_initialized_packet": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint" - } - ] - ], - "packet_update_soft_enum_packet": [ - "container", - [] - ], - "packet_network_stack_latency_packet": [ - "container", - [ - { - "name": "timestamp", - "type": "i64" - }, - { - "name": "need_response", - "type": "bool" - } - ] - ], - "packet_script_custom_event_packet": [ - "container", - [ - { - "name": "event_name", - "type": "string" - }, - { - "name": "event_data", - "type": "string" - } - ] - ], - "packet_spawn_particle_effect": [ - "container", - [ - { - "name": "dimension_id", - "type": "u8" - }, - { - "name": "entity_id", - "type": "varint" - }, - { - "name": "position", - "type": "vector3" - }, - { - "name": "particle_name", - "type": "string" - } - ] - ], - "packet_available_entity_identifiers": [ - "container", - [ - { - "name": "namedtag", - "type": "varint" - } - ] - ], - "packet_level_sound_event_v2": [ - "container", - [ - { - "name": "sound_id", - "type": "u8" - }, - { - "name": "position", - "type": "vector3" - }, - { - "name": "block_id", - "type": "varint" - }, - { - "name": "entity_type", - "type": "string" - }, - { - "name": "is_baby_mob", - "type": "bool" - }, - { - "name": "is_global", - "type": "bool" - } - ] - ], - "packet_network_chunk_publisher_update": [ - "container", - [ - { - "name": "coordinates", - "type": "varint" - }, - { - "name": "radius", - "type": "varint" - } - ] - ], - "packet_biome_definition_list": [ - "container", - [ - { - "name": "namedtag", - "type": "varint" - } - ] - ], - "packet_level_sound_event": [ - "container", - [ - { - "name": "sound_id", - "type": "varint" - }, - { - "name": "position", - "type": "vector3" - }, - { - "name": "block_id", - "type": "varint" - }, - { - "name": "entity_type", - "type": "string" - }, - { - "name": "is_baby_mob", - "type": "bool" - }, - { - "name": "is_global", - "type": "bool" - } - ] - ] - } -} diff --git a/data/provider.js b/data/provider.js new file mode 100644 index 0000000..3475db3 --- /dev/null +++ b/data/provider.js @@ -0,0 +1,45 @@ +const { Versions } = require('../src/options') +const { getFiles } = require('../src/datatypes/util') + +const fileMap = {} + +// Walks all the directories for each of the supported versions in options.js +// then builds a file map for each version +// { 'protocol.json': { '1.16.200': '1.16.200/protocol.json', '1.16.210': '1.16.210/...' } } +function loadVersions() { + for (const version in Versions) { + let files = [] + try { + files = getFiles(__dirname + '/' + version) + } catch {} + for (let file of files) { + const rfile = file.replace(__dirname + '/' + version + '/', '') + fileMap[rfile] ??= [] + fileMap[rfile].push([Versions[version], file]) + fileMap[rfile].sort().reverse() + } + } +} + +module.exports = (protocolVersion) => { + return { + // Returns the most recent file based on the specified protocolVersion + // e.g. if `version` is 1.16 and a file for 1.16 doesn't exist, load from 1.15 file + getPath(file) { + if (!fileMap[file]) { + throw Error('Unknown file ' + file) + } + for (const [ pver, path ] of fileMap[file]) { + if (pver <= protocolVersion) { + // console.debug('for', file, 'returining', path) + return path + } + } + throw Error('unknown file ' + file) + } + } +} + +loadVersions() +// console.log('file map', fileMap) +// module.exports(Versions['1.16.210']).open('creativeitems.json') \ No newline at end of file diff --git a/samples/clientTest.js b/examples/clientTest.js similarity index 100% rename from samples/clientTest.js rename to examples/clientTest.js diff --git a/examples/createRelay.js b/examples/createRelay.js new file mode 100644 index 0000000..008027b --- /dev/null +++ b/examples/createRelay.js @@ -0,0 +1,38 @@ +const { Relay } = require('../src/relay') + +function createRelay() { + console.log('Creating relay') + /** + * Example to create a non-transparent proxy (or 'Relay') connection to destination server + * In Relay we de-code and re-encode packets + */ + const relay = new Relay({ + /* Hostname and port for clients to listen to */ + hostname: '0.0.0.0', + port: 19130, + /** + * Who does the authentication + * If set to `client`, all connecting clients will be sent a message with a link to authenticate + * If set to `server`, the server will authenticate and only one client will be able to join + * (Default) If set to `none`, no authentication will be done + */ + auth: 'server', + + /** + * Sets if packets will automatically be forwarded. If set to false, you must listen for on('packet') + * events and + */ + auto: true, + + /* Where to send upstream packets to */ + destination: { + hostname: '127.0.0.1', + port: 19132, + // encryption: true + } + }) + + relay.create() +} + +createRelay() \ No newline at end of file diff --git a/examples/chunk b/examples/old/chunk similarity index 100% rename from examples/chunk rename to examples/old/chunk diff --git a/examples/client.js b/examples/old/client.js similarity index 100% rename from examples/client.js rename to examples/old/client.js diff --git a/examples/deserialize.js b/examples/old/deserialize.js similarity index 100% rename from examples/deserialize.js rename to examples/old/deserialize.js diff --git a/examples/server.js b/examples/old/server.js similarity index 100% rename from examples/server.js rename to examples/old/server.js diff --git a/examples/server_simple.js b/examples/old/server_simple.js similarity index 100% rename from examples/server_simple.js rename to examples/old/server_simple.js diff --git a/samples/serverTest.js b/examples/serverTest.js similarity index 69% rename from samples/serverTest.js rename to examples/serverTest.js index ac50b53..b03b27c 100644 --- a/samples/serverTest.js +++ b/examples/serverTest.js @@ -1,8 +1,9 @@ process.env.DEBUG = 'minecraft-protocol raknet' const { Server } = require('../src/server') -const CreativeItems = require('../data/creativeitems.json') +// const CreativeItems = require('../data/creativeitems.json') const NBT = require('prismarine-nbt') const fs = require('fs') +const DataProvider = require('../data/provider') let server = new Server({ @@ -10,6 +11,14 @@ let server = new Server({ }) server.create('0.0.0.0', 19132) +function getPath(packetPath) { + return DataProvider(server.options.protocolVersion).getPath(packetPath) +} + +function get(packetPath) { + return require(getPath('sample/' + packetPath)) +} + let ran = false server.on('connect', ({ client }) => { @@ -50,35 +59,35 @@ server.on('connect', ({ client }) => { client.queue('inventory_slot', {"inventory_id":120,"slot":i,"uniqueid":0,"item":{"network_id":0}}) } - client.queue('inventory_transaction', require('../src/packets/inventory_transaction.json')) - client.queue('player_list', require('../src/packets/player_list.json')) - client.queue('start_game', require('../src/packets/start_game.json')) + client.queue('inventory_transaction', get('packets/inventory_transaction.json')) + client.queue('player_list', get('packets/player_list.json')) + client.queue('start_game', get('packets/start_game.json')) client.queue('item_component', {"entries":[]}) - client.queue('set_spawn_position', require('../src/packets/set_spawn_position.json')) + client.queue('set_spawn_position', get('packets/set_spawn_position.json')) client.queue('set_time', { time: 5433771 }) client.queue('set_difficulty', { difficulty: 1 }) client.queue('set_commands_enabled', { enabled: true }) - client.queue('adventure_settings', require('../src/packets/adventure_settings.json')) + client.queue('adventure_settings', get('packets/adventure_settings.json')) - client.queue('biome_definition_list', require('../src/packets/biome_definition_list.json')) - client.queue('available_entity_identifiers', require('../src/packets/available_entity_identifiers.json')) + client.queue('biome_definition_list', get('packets/biome_definition_list.json')) + client.queue('available_entity_identifiers', get('packets/available_entity_identifiers.json')) - client.queue('update_attributes', require('../src/packets/update_attributes.json')) - client.queue('creative_content', require('../src/packets/creative_content.json')) - client.queue('inventory_content', require('../src/packets/inventory_content.json')) + client.queue('update_attributes', get('packets/update_attributes.json')) + client.queue('creative_content', get('packets/creative_content.json')) + client.queue('inventory_content', get('packets/inventory_content.json')) client.queue('player_hotbar', {"selected_slot":3,"window_id":0,"select_slot":true}) - client.queue('crafting_data', require('../src/packets/crafting_data.json')) - client.queue('available_commands', require('../src/packets/available_commands.json')) + client.queue('crafting_data', get('packets/crafting_data.json')) + client.queue('available_commands', get('packets/available_commands.json')) client.queue('chunk_radius_update', {"chunk_radius":5}) - client.queue('set_entity_data', require('../src/packets/set_entity_data.json')) + client.queue('set_entity_data', get('packets/set_entity_data.json')) - client.queue('game_rules_changed', require('../src/packets/game_rules_changed.json')) + client.queue('game_rules_changed', get('packets/game_rules_changed.json')) client.queue('respawn', {"x":646.9405517578125,"y":65.62001037597656,"z":77.86255645751953,"state":0,"runtime_entity_id":0}) - for (const file of fs.readdirSync('../src/chunks')) { - const buffer = Buffer.from(fs.readFileSync('../src/chunks/' + file, 'utf8'), 'hex') + for (const file of fs.readdirSync(`../data/${server.options.version}/sample/chunks`)) { + const buffer = Buffer.from(fs.readFileSync(`../data/${server.options.version}/sample/chunks/` + file, 'utf8'), 'hex') // console.log('Sending chunk', chunk) client.sendBuffer(buffer) } diff --git a/src/auth/chains.js b/src/auth/chains.js index 5083a03..20ded36 100644 --- a/src/auth/chains.js +++ b/src/auth/chains.js @@ -52,6 +52,8 @@ function verifyAuth(chain) { console.log('verified with mojang key!', x5u) } + // TODO: Handle `didVerify` = false + pubKey = decoded.identityPublicKey ? mcPubKeyToPem(decoded.identityPublicKey) : x5u finalKey = decoded.identityPublicKey || finalKey // non pem data = { ...data, ...decoded } @@ -87,22 +89,22 @@ function encodeLoginJWT(localChain, mojangChain) { module.exports = { encodeLoginJWT, decodeLoginJWT } -function testServer() { - const loginPacket = require('./login.json') +// function testServer() { +// const loginPacket = require('./login.json') - // console.log(loginPacket) - const authChains = JSON.parse(loginPacket.data.chain) - const skinChain = loginPacket.data.clientData +// // console.log(loginPacket) +// const authChains = JSON.parse(loginPacket.data.chain) +// const skinChain = loginPacket.data.clientData - try { - var { data, chain } = decodeLoginJWT(authChains.chain, skinChain) - } catch (e) { - console.error(e) - throw new Error('Failed to verify user') - } +// try { +// var { data, chain } = decodeLoginJWT(authChains.chain, skinChain) +// } catch (e) { +// console.error(e) +// throw new Error('Failed to verify user') +// } - console.log('Authed') - // console.log(loginPacket) -} +// console.log('Authed') +// // console.log(loginPacket) +// } -// testServer() \ No newline at end of file +// // testServer() \ No newline at end of file diff --git a/src/auth/encryption.js b/src/auth/encryption.js index d758f41..21ebbdb 100644 --- a/src/auth/encryption.js +++ b/src/auth/encryption.js @@ -2,11 +2,15 @@ const JWT = require('jsonwebtoken') const crypto = require('crypto') const { Ber } = require('asn1') const ec_pem = require('ec-pem') +const fs = require('fs') +const DataProvider = require('../../data/provider') const SALT = '🧂' const curve = 'secp384r1' function Encrypt(client, server, options) { + const skinGeom = fs.readFileSync(DataProvider(options.protocolVersion).getPath('skin_geom.txt'), 'utf-8') + client.ecdhKeyPair = crypto.createECDH(curve) client.ecdhKeyPair.generateKeys() client.clientX509 = writeX509PublicKey(client.ecdhKeyPair.getPublicKey()) @@ -84,7 +88,6 @@ function Encrypt(client, server, options) { } client.on('server.client_handshake', startClientboundEncryption) - client.on('client.server_handshake', startServerboundEncryption) client.createClientChain = (mojangKey) => { @@ -118,7 +121,7 @@ function Encrypt(client, server, options) { SkinId: '5eb65f73-af11-448e-82aa-1b7b165316ad.persona-e199672a8c1a87e0-0', SkinData: 'AAAAAA==', SkinResourcePatch: 'ewogICAiZ2VvbWV0cnkiIDogewogICAgICAiYW5pbWF0ZWRfMTI4eDEyOCIgOiAiZ2VvbWV0cnkuYW5pbWF0ZWRfMTI4eDEyOF9wZXJzb25hLWUxOTk2NzJhOGMxYTg3ZTAtMCIsCiAgICAgICJhbmltYXRlZF9mYWNlIiA6ICJnZW9tZXRyeS5hbmltYXRlZF9mYWNlX3BlcnNvbmEtZTE5OTY3MmE4YzFhODdlMC0wIiwKICAgICAgImRlZmF1bHQiIDogImdlb21ldHJ5LnBlcnNvbmFfZTE5OTY3MmE4YzFhODdlMC0wIgogICB9Cn0K', - SkinGeometryData: require('./geom'), + SkinGeometryData: skinGeom, "SkinImageHeight": 1, "SkinImageWidth": 1, "ArmSize": "wide", diff --git a/src/auth/tests/encrypt.js b/src/auth/tests/encrypt.js deleted file mode 100644 index e5aca37..0000000 --- a/src/auth/tests/encrypt.js +++ /dev/null @@ -1,232 +0,0 @@ -const crypto = require('crypto') -const JWT = require('jsonwebtoken') -const constants = require('./constants') -const { Ber } = require('asn1') -const ec_pem = require('ec-pem'); - -// function Encrypt(client, options) { -// this.startClientboundEncryption = (pubKeyBuf) => { - -// } -// client.on('start_encrypt', this.startClientboundEncryption) -// } - -// module.exports = Encrypt - - -// Server -> Client : sent right after the client sends us a LOGIN_PACKET so -// we can start the encryption process -// @param {key} - The key from the client Login Packet final JWT chain -function startClientboundEncryption(pubKeyBuf) { - // create our ecdh keypair - const type = 'secp256k1' - const alice = crypto.createECDH(type) - const aliceKey = alice.generateKeys() - const alicePublicKey = aliceKey.toString('base64') - const alicePrivateKey = mcPubKeyToPem(alice.getPrivateKey('base64')) - // get our secret key hex encoded - // const aliceSecret = alice.computeSecret(pubKeyBuf, null, 'hex') - - // (yawkat:) - // From the public key of the remote and the private key of the local, - // a shared secret is generated using ECDH. The secret key bytes are - // then computed as sha256(server_token + shared_secret). These secret - // key bytes are 32 bytes long. - const salt = Buffer.from('', 'utf-8') - let secret = crypto.createHash('sha256').update(Buffer.concat([salt, pubKeyBuf])).digest() - console.log('alice', alicePrivateKey) - const pem = mcPubKeyToPem(alice.getPrivateKey().toString('base64')) - console.log('pem', pem) - - const token = JWT.sign({ - salt, - signedToken: alicePublicKey - }, pem, { algorithm: 'ES384' }) - - console.log('Token', token) - - // get our Secret Bytes from the secret key - - - // alice.setPrivateKey( - // crypto.createHash('sha256').update('alice', 'utf8').digest() - // ) - - // using (var sha = SHA256.Create()) - // { - // secret = sha.ComputeHash(secretPrepend.Concat(agreement.CalculateAgreement(remotePublicKey).ToByteArrayUnsigned()).ToArray()); - // } - - - - const bob = crypto.createECDH('secp256k1'); - - - // URI x5u = URI.create(Base64.getEncoder().encodeToString(serverKeyPair.getPublic().getEncoded())); - - // JWTClaimsSet claimsSet = new JWTClaimsSet.Builder().claim("salt", Base64.getEncoder().encodeToString(token)).build(); - // SignedJWT jwt = new SignedJWT(new JWSHeader.Builder(JWSAlgorithm.ES384).x509CertURL(x5u).build(), claimsSet); - - // signJwt(jwt, (ECPrivateKey) serverKeyPair.getPrivate()); - - // return jwt; -} - -function testECDH() { - const crypto = require('crypto') - const alice = crypto.createECDH('secp256k1') - const bob = crypto.createECDH('secp256k1') - - // Note: This is a shortcut way to specify one of Alice's previous private - // keys. It would be unwise to use such a predictable private key in a real - // application. - alice.setPrivateKey( - crypto.createHash('sha256').update('alice', 'utf8').digest() - ); - - // Bob uses a newly generated cryptographically strong - // pseudorandom key pair bob.generateKeys(); - - const alice_secret = alice.computeSecret(bob.getPublicKey(), null, 'hex') - const bob_secret = bob.computeSecret(alice.getPublicKey(), null, 'hex') - - // alice_secret and bob_secret should be the same shared secret value - console.log(alice_secret === bob_secret) -} - -function testECDH2() { - const type = 'secp256k1' - const alice = crypto.createECDH(type); - const aliceKey = alice.generateKeys(); - - // Generate Bob's keys... - const bob = crypto.createECDH(type); - const bobKey = bob.generateKeys(); - - console.log("\nAlice private key:\t", alice.getPrivateKey().toString('hex')); - console.log("Alice public key:\t", aliceKey.toString('hex')) - - console.log("\nBob private key:\t", bob.getPrivateKey().toString('hex')); - console.log("Bob public key:\t", bobKey.toString('hex')); - - - // Exchange and generate the secret... - const aliceSecret = alice.computeSecret(bobKey); - const bobSecret = bob.computeSecret(aliceKey); - - console.log("\nAlice shared key:\t", aliceSecret.toString('hex')) - console.log("Bob shared key:\t\t", bobSecret.toString('hex')); - //wow it actually works?! -} - -function mcPubKeyToPem(mcPubKeyBuffer) { - console.log(mcPubKeyBuffer) - if (mcPubKeyBuffer[0] == '-') return mcPubKeyBuffer - let pem = '-----BEGIN PUBLIC KEY-----\n' - let base64PubKey = mcPubKeyBuffer.toString('base64') - const maxLineLength = 65 - while (base64PubKey.length > 0) { - pem += base64PubKey.substring(0, maxLineLength) + '\n' - base64PubKey = base64PubKey.substring(maxLineLength) - } - pem += '-----END PUBLIC KEY-----\n' - return pem -} - -function readX509PublicKey(key) { - var reader = new Ber.Reader(Buffer.from(key, "base64")); - reader.readSequence(); - reader.readSequence(); - reader.readOID(); // Hey, I'm an elliptic curve - reader.readOID(); // This contains the curve type, could be useful - return Buffer.from(reader.readString(Ber.BitString, true)).slice(1); -} - -function testMC() { - // const pubKeyBuf = Buffer.from(constants.PUBLIC_KEY, 'base64') - // const pem = mcPubKeyToPem(pubKeyBuf) - // console.log(mcPubKeyToPem(pubKeyBuf)) - // const publicKey = crypto.createPublicKey({ key: pem, format: 'der' }) - - const pubKeyBuf = readX509PublicKey(constants.PUBLIC_KEY) - - // console.log('Mojang pub key', pubKeyBuf.toString('hex'), publicKey) - startClientboundEncryption(pubKeyBuf) -} - -function testMC2() { - // const mojangPubKeyBuf = Buffer.from('MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE8ELkixyLcwlZryUQcu1TvPOmI2B7vX83ndnWRUaXm74wFfa5f/lwQNTfrLVHa2PmenpGI6JhIMUJaWZrjmMj90NoKNFSNBuKdm8rYiXsfaz3K36x/1U26HpG0ZxK/V1V', 'base64') - // const pem = mcPubKeyToPem(mojangPubKeyBuf) - // const publicKey = crypto.createPublicKey({ key: pem }) - - const publicKey = readX509PublicKey(constants.PUBLIC_KEY) - - const curve = 'secp384r1' - const alice = crypto.createECDH(curve) - // const keys = crypto.generateKeyPair('ec',) - - // const bob = crypto.generateKeyPairSync('ec', { - // namedCurve: type - // }) - // alice.setPrivateKey(bob.privateKey.export({ type: 'pkcs8', format: 'pem' })) - // alice.setPublicKey(bob.publicKey.export({ type: 'spki', format: 'pem' })) - - // console.log(bob) - - const aliceKey = alice.generateKeys() - - const alicePEM = ec_pem(alice, curve) - - const alicePEMPrivate = alicePEM.encodePrivateKey() - const alicePEMPublic = alicePEM.encodePublicKey() - - // const alicePublicKey = aliceKey.toString('base64') - // const alicePrivateKey = alice.getPrivateKey().toString('base64') - const aliceSecret = alice.computeSecret(publicKey, null, 'hex') - - console.log('Alice private key PEM', alicePEMPrivate) - console.log('Alice public key PEM', alicePEMPublic) - console.log('Alice public key', alice.getPublicKey('base64')) - console.log('Alice secret key', aliceSecret) - - - var sign = crypto.createSign('RSA-SHA256') - sign.write('something') - sign.end() -// // const pem2 = -// // `-----BEGIN PRIVATE KEY----- -// // ${alice.getPrivateKey('base64')} -// // -----END PRIVATE KEY-----` - -// console.log('PEM', bob.privateKey) - const sig = sign.sign(alicePEMPrivate, 'hex') - console.log('Signature', sig) - - - - const token = JWT.sign({ - salt: 'HELLO', - signedToken: alice.getPublicKey('base64') - }, alicePEMPrivate, { algorithm: 'ES384' }) - console.log('Token', token) - - const verified = JWT.verify(token, alicePEMPublic, { algorithms: 'ES384' }) - console.log('Verified!', verified) -} - -function testMC3() { - var Ber = require('asn1').Ber; - var reader = new Ber.Reader(new Buffer(constants.PUBLIC_KEY, "base64")); - reader.readSequence(); - reader.readSequence(); - reader.readOID(); // Hey, I'm an elliptic curve - reader.readOID(); // This contains the curve type, could be useful - var pubKey = reader.readString(Ber.BitString, true).slice(1); - var server = crypto.createECDH('secp384r1'); - server.generateKeys(); - console.log(server.computeSecret(pubKey)); - -} - -// testECDH2() -testMC2() \ No newline at end of file diff --git a/src/auth/tests/encryptTest.js b/src/auth/tests/encryptTest.js deleted file mode 100644 index d1d83ef..0000000 --- a/src/auth/tests/encryptTest.js +++ /dev/null @@ -1,88 +0,0 @@ -const crypto = require('crypto') -const JWT = require('jsonwebtoken') -const constants = require('./constants') -const { Ber } = require('asn1') -const ec_pem = require('ec-pem') - -function readX509PublicKey(key) { - var reader = new Ber.Reader(Buffer.from(key, "base64")); - reader.readSequence(); - reader.readSequence(); - reader.readOID(); // Hey, I'm an elliptic curve - reader.readOID(); // This contains the curve type, could be useful - return Buffer.from(reader.readString(Ber.BitString, true)).slice(1); -} - -function writeX509PublicKey(key) { - var writer = new Ber.Writer(); - writer.startSequence(); - writer.startSequence(); - writer.writeOID("1.2.840.10045.2.1"); - writer.writeOID("1.3.132.0.34"); - writer.endSequence(); - writer.writeBuffer(Buffer.concat([Buffer.from([0x00]), key]), Ber.BitString); - writer.endSequence(); - return writer.buffer.toString("base64"); -} - -function test(pubKey = constants.PUBLIC_KEY) { - const publicKey = readX509PublicKey(pubKey) - const curve = 'secp384r1' - const alice = crypto.createECDH(curve) - const aliceKey = alice.generateKeys() - const alicePEM = ec_pem(alice, curve) - const alicePEMPrivate = alicePEM.encodePrivateKey() - const alicePEMPublic = alicePEM.encodePublicKey() - const aliceSecret = alice.computeSecret(publicKey, null, 'hex') - console.log('Alice private key PEM', alicePEMPrivate) - console.log('Alice public key PEM', alicePEMPublic) - console.log('Alice public key', alice.getPublicKey('hex')) - console.log('Alice secret key', aliceSecret) - - // Test signing manually - const sign = crypto.createSign('RSA-SHA256') - sign.write('🧂') - sign.end() - const sig = sign.sign(alicePEMPrivate, 'hex') - console.log('Signature', sig) - - // Test JWT sign+verify - const x509 = writeX509PublicKey(alice.getPublicKey()) - const token = JWT.sign({ - salt: 'HELLO', - signedToken: alice.getPublicKey('base64') - }, alicePEMPrivate, { algorithm: 'ES384', header: { x5u: x509 } }) - console.log('Encoded JWT', token) - // send the jwt to the client... - - const verified = JWT.verify(token, alicePEMPublic, { algorithms: 'ES384' }) - console.log('Decoded JWT', verified) - // Good -} - -/** - * Alice private key PEM -----BEGIN EC PRIVATE KEY----- -MIGkAgEBBDBGgHZwH3BzieyJrdrVTVLmrEoUxpDUSqSzS98lobTXeUxJR/OmywPV -57I8YtnsJlCgBwYFK4EEACKhZANiAATjvTRgjsxKruO7XbduSQoHeR/6ouIm4Rmc -La9EkSpLFpuYZfsdtq9Vcf2t3Q3+jIbXjD/wNo97P4Hr5ghXG8sCVV7jpqadOF8j -SzyfajLGfX9mkS5WWLAg+dpi/KiEo/g= ------END EC PRIVATE KEY----- - -Alice public key PEM -----BEGIN PUBLIC KEY----- -MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE4700YI7MSq7ju123bkkKB3kf+qLiJuEZ -nC2vRJEqSxabmGX7HbavVXH9rd0N/oyG14w/8DaPez+B6+YIVxvLAlVe46amnThf -I0s8n2oyxn1/ZpEuVliwIPnaYvyohKP4 ------END PUBLIC KEY----- - -Alice public key 04e3bd34608ecc4aaee3bb5db76e490a07791ffaa2e226e1199c2daf44912a4b169b9865fb1db6af5571fdaddd0dfe8c86d78c3ff0368f7b3f81ebe608571bcb02555ee3a6a69d385f234b3c9f6a32c67d7f66912e5658b020f9da62fca884a3f8 -Alice secret key 76feb5d420b33907c4841a74baa707b717a29c021b17b6662fd46dba3227cac3e256eee9e890edb0308f66a3119b4914 -Signature 3066023100d5ea70b8fc5e441c5e93d9f7dcde031f54291011c950a4aa8625ea9b27f7c798a8bc4de40baf35d487a05db6b5c628c6023100ae06cc2ea65db77138163c546ccf13933faae3d91bd6aa7108b99539cdb1c86f1e8a3704cb099f0b00eebed4ee75ccb2 -Encoded JWT eyJhbGciOiJFUzM4NCIsInR5cCI6IkpXVCJ9.eyJzYWx0IjoiSEVMTE8iLCJzaWduZWRUb2tlbiI6IkJPTzlOR0NPekVxdTQ3dGR0MjVKQ2dkNUgvcWk0aWJoR1p3dHIwU1JLa3NXbTVobCt4MjJyMVZ4L2EzZERmNk1odGVNUC9BMmozcy9nZXZtQ0ZjYnl3SlZYdU9tcHAwNFh5TkxQSjlxTXNaOWYyYVJMbFpZc0NENTJtTDhxSVNqK0E9PSIsImlhdCI6MTYxMTc4MDYwNX0._g8k086U7nD-Tthn8jGWuuM3Q4EfhgqCfFA1Q5ePmjqhqMHOJvmrCz6tWsCytr2i-a2M51fb9K_YDAHbZ66Kos9ZkjF4Tqz5fPS880fM9woZ_1xjh7nGcOQ6sbY81zyi -Decoded JWT { - salt: 'HELLO', - signedToken: 'BOO9NGCOzEqu47tdt25JCgd5H/qi4ibhGZwtr0SRKksWm5hl+x22r1Vx/a3dDf6MhteMP/A2j3s/gevmCFcbywJVXuOmpp04XyNLPJ9qMsZ9f2aRLlZYsCD52mL8qISj+A==', - iat: 1611780605 -} - */ - -test() \ No newline at end of file diff --git a/src/auth/tests/jwtTest.js b/src/auth/tests/jwtTest.js deleted file mode 100644 index acf5307..0000000 --- a/src/auth/tests/jwtTest.js +++ /dev/null @@ -1,49 +0,0 @@ -function test() { - const chain = require('./sampleChain.json').chain - - let data = {} - - // There are three JWT tokens sent to us, one signed by the client - // one signed by Mojang with the Mojang token we have and another one - // from Xbox with addition user profile data - // We verify that at least one of the tokens in the chain has been properly - // signed by Mojang by checking the x509 public key in the JWT headers - let didVerify = false - - let pubKey = mcPubKeyToPem(constants.PUBLIC_KEY_NEW) - console.log(pubKey) - for (var token of chain) { - // const decoded = jwt.decode(token, pubKey, 'ES384') - console.log('Decoding...', token) - const decoded = JWT.verify(token, pubKey, { algorithms: 'ES384' }) - console.log('Decoded...') - console.log('Decoded', decoded) - - // Check if signed by Mojang key - const [header] = token.split('.') - const hdec = Buffer.from(header, 'base64').toString('utf-8') - const hjson = JSON.parse(hdec) - if (hjson.x5u == constants.PUBLIC_KEY && !data.extraData?.XUID) { - didVerify = true - console.log('verified with mojang key!', hjson.x5u) - } - - pubKey = mcPubKeyToPem(decoded.identityPublicKey) - data = { ...data, ...decoded } - } - console.log('Result', data) -} - -function test2() { - const chain = require('./login.json') - const token = chain.data.clientData - // console.log(token) - - const pubKey = mcPubKeyToPem(constants.CDATA_PUBLIC_KEY) - - const decoded = JWT.verify(token, pubKey, { algorithms: 'ES384' }) - - // console.log('Decoded', decoded) - - fs.writeFileSync('clientData.json', JSON.stringify(decoded)) -} diff --git a/src/client.js b/src/client.js index 9419202..1bbd167 100644 --- a/src/client.js +++ b/src/client.js @@ -1,22 +1,25 @@ const fs = require('fs') const debug = require('debug')('minecraft-protocol') +const auth = require('./client/auth') +const Options = require('./options') const { Connection } = require('./connection') const { createDeserializer, createSerializer } = require('./transforms/serializer') const { Encrypt } = require('./auth/encryption') -const auth = require('./client/auth') -const Options = require('./options') const { RakClient } = require('./Rak') +const { serialize } = require('./datatypes/util') + +const debugging = false class Client extends Connection { /** @param {{ version: number, hostname: string, port: number }} options */ constructor(options) { super() this.options = { ...Options.defaultOptions, ...options } - this.serializer = createSerializer() - this.deserializer = createDeserializer() this.validateOptions() + this.serializer = createSerializer(this.options.version) + this.deserializer = createDeserializer(this.options.version) - Encrypt(this, null, options) + Encrypt(this, null, this.options) if (options.password) { auth.authenticatePassword(this, options) @@ -28,26 +31,29 @@ class Client extends Connection { this.startQueue() this.inLog = (...args) => console.info('C ->', ...args) this.outLog = (...args) => console.info('C <-', ...args) - // this.on('decrypted', this.onDecryptedPacket) } validateOptions() { - // console.log('Options', this.options) if (!this.options.hostname || this.options.port == null) throw Error('Invalid hostname/port') - if (this.options.version < Options.MIN_VERSION) { - throw new Error(`Unsupported protocol version < ${Options.MIN_VERSION} : ${this.options.version}`) + + if (!Options.Versions[this.options.version]) { + console.warn('Supported versions: ', Options.Versions) + throw Error(`Unsupported version ${this.options.version}`) + } + this.options.protocolVersion = Options.Versions[this.options.version] + if (this.options.protocolVersion < Options.MIN_VERSION) { + throw new Error(`Protocol version < ${Options.MIN_VERSION} : ${this.options.protocolVersion}, too old`) } } onEncapsulated = (encapsulated, inetAddr) => { - // log(inetAddr.address, ': Encapsulated', encapsulated) const buffer = Buffer.from(encapsulated.buffer) this.handle(buffer) } connect = async (sessionData) => { - const hostname = this.options.hostname || '127.0.0.1' - const port = this.options.port || 19132 + const hostname = this.options.hostname + const port = this.options.port this.connection = new RakClient({ useWorkers: true, hostname, port }) this.connection.onConnected = () => this.sendLogin() @@ -64,14 +70,13 @@ class Client extends Connection { ] const encodedChain = JSON.stringify({ chain }) - // const skinChain = JSON.stringify({}) const bodyLength = this.clientUserChain.length + encodedChain.length + 8 debug('Auth chain', chain) this.write('login', { - protocol_version: this.options.version, + protocol_version: this.options.protocolVersion, payload_size: bodyLength, chain: encodedChain, client_data: this.clientUserChain @@ -83,7 +88,7 @@ class Client extends Connection { // We're talking over UDP, so there is no connection to close, instead // we stop communicating with the server console.warn(`Server requested ${packet.hide_disconnect_reason ? 'silent disconnect' : 'disconnect'}: ${packet.message}`) - process.exit(1) + process.exit(1) // TODO: handle } close() { @@ -109,32 +114,28 @@ class Client extends Connection { } readPacket(packet) { - // console.log('packet', packet) const des = this.deserializer.parsePacketBuffer(packet) const pakData = { name: des.data.name, params: des.data.params } this.inLog('-> C', pakData.name/*, serialize(pakData.params).slice(0, 100)*/) - // No idea what this exotic 0xA0 packet is, it's not implemented anywhere - // and seems empty. Possible gibberish from the raknet impl - if (pakData.name == '160' || !pakData.name) { // eslint-ignore-line - console.warn('?? Ignoring extraneous packet ', des) - return - } - - // Packet verifying (decode + re-encode + match test) - if (pakData.name) { - this.tryRencode(pakData.name, pakData.params, packet) - } - - // console.info('->', JSON.stringify(pakData, (k,v) => typeof v == 'bigint' ? v.toString() : v)) - // Packet dumping - try { - if (!fs.existsSync(`./packets/${pakData.name}.json`)) { - fs.writeFileSync(`./packets/${pakData.name}.json`, serialize(pakData.params, 2)) - fs.writeFileSync(`./packets/${pakData.name}.txt`, packet.toString('hex')) + if (debugging) { + // Packet verifying (decode + re-encode + match test) + if (pakData.name) { + this.tryRencode(pakData.name, pakData.params, packet) } - } catch { } + // console.info('->', JSON.stringify(pakData, (k,v) => typeof v == 'bigint' ? v.toString() : v)) + // Packet dumping + try { + const root = __dirname + `../data/${this.options.version}/sample/` + if (!fs.existsSync(root + `packets/${pakData.name}.json`)) { + fs.writeFileSync(root + `packets/${pakData.name}.json`, serialize(pakData.params, 2)) + fs.writeFileSync(root + `packets/${pakData.name}.txt`, packet.toString('hex')) + } + } catch { } + } + + // Abstract some boilerplate before sending to listeners switch (des.data.name) { case 'server_to_client_handshake': this.emit('client.server_handshake', des.data.params) @@ -142,27 +143,22 @@ class Client extends Connection { case 'disconnect': // Client kicked this.onDisconnectRequest(des.data.params) break - case 'crafting_data': - fs.writeFileSync('crafting.json', JSON.stringify(des.data.params, (k, v) => typeof v == 'bigint' ? v.toString() : v)) - break - case 'start_game': - fs.writeFileSync('start_game.json', JSON.stringify(des.data.params, (k, v) => typeof v == 'bigint' ? v.toString() : v)) - break - case 'level_chunk': - // fs.writeFileSync(`./chunks/chunk-${chunks++}.txt`, packet.toString('hex')) - break + // case 'crafting_data': + // fs.writeFileSync('crafting.json', JSON.stringify(des.data.params, (k, v) => typeof v == 'bigint' ? v.toString() : v)) + // break + // case 'start_game': + // fs.writeFileSync('start_game.json', JSON.stringify(des.data.params, (k, v) => typeof v == 'bigint' ? v.toString() : v)) + // break + // case 'level_chunk': + // // fs.writeFileSync(`./chunks/chunk-${chunks++}.txt`, packet.toString('hex')) + // break default: // console.log('Sending to listeners') } - this.emit(des.data.name, des.data.params) + // Emit packet + this.emit(des.data.name, des.data.params) } } -var chunks = 0; - -function serialize(obj = {}, fmt) { - return JSON.stringify(obj, (k, v) => typeof v == 'bigint' ? v.toString() : v, fmt) -} - module.exports = { Client } \ No newline at end of file diff --git a/src/client/auth.js b/src/client/auth.js index 5502b43..20775d2 100644 --- a/src/client/auth.js +++ b/src/client/auth.js @@ -1,16 +1,5 @@ -const XboxLiveAuth = require('@xboxreplay/xboxlive-auth') -const debug = require('debug')('minecraft-protocol') -const fetch = require('node-fetch') -const authConstants = require('./authConstants') const { MsAuthFlow } = require('./authFlow.js') -const getFetchOptions = { - headers: { - 'Content-Type': 'application/json', - 'User-Agent': 'node-minecraft-protocol' - } -} - /** * Obtains Minecaft profile data using a Minecraft access token and starts the join sequence * @param {object} client - The client passed to protocol @@ -71,33 +60,25 @@ async function authenticateDeviceCode (client, options) { } } -function checkStatus (res) { - if (res.ok) { // res.status >= 200 && res.status < 300 - return res.json() - } else { - throw Error(res.statusText) - } -} - module.exports = { authenticatePassword, authenticateDeviceCode } -async function msaTest () { - // MsAuthFlow.resetTokenCaches() +// async function msaTest () { +// // MsAuthFlow.resetTokenCaches() - await authenticateDeviceCode({ - connect(...args) { - console.log('Connecting', args) - }, - emit(...e) { - console.log('Event', e) - } - }, {}) -} +// await authenticateDeviceCode({ +// connect(...args) { +// console.log('Connecting', args) +// }, +// emit(...e) { +// console.log('Event', e) +// } +// }, {}) +// } -// debug with node microsoftAuth.js -if (!module.parent) { - msaTest() -} +// // debug with node microsoftAuth.js +// if (!module.parent) { +// msaTest() +// } diff --git a/src/connection.js b/src/connection.js index 367896c..eda0ca9 100644 --- a/src/connection.js +++ b/src/connection.js @@ -2,11 +2,26 @@ const BinaryStream = require('@jsprismarine/jsbinaryutils').default const BatchPacket = require('./datatypes/BatchPacket') const cipher = require('./transforms/encryption') const { EventEmitter } = require('events') -const Reliability = require('jsp-raknet/protocol/reliability') - +const Versions = require('./options') const debug = require('debug')('minecraft-protocol') class Connection extends EventEmitter { + versionLessThan(version) { + if (typeof version === 'string') { + return Versions[version] < this.options.version + } else { + return version < this.options.version + } + } + + versionGreaterThan(version) { + if (typeof version === 'string') { + return Versions[version] > this.options.version + } else { + return version > this.options.version + } + } + startEncryption(iv) { this.encryptionEnabled = true this.inLog('Started encryption', this.sharedSecret, iv) @@ -15,14 +30,10 @@ class Connection extends EventEmitter { this.q2 = [] } - write(name, params) { // TODO: Batch - // console.log('Need to encode', name, params) - var s = this.connect ? 'C' : 'S' - if (this.downQ) s += 'P' - this.outLog('NB <- ' + s, name,params) + write(name, params) { + this.outLog('sending', name, params) const batch = new BatchPacket() const packet = this.serializer.createPacketBuffer({ name, params }) - // console.log('Sending buf', packet.toString('hex').) batch.addEncodedPacket(packet) if (this.encryptionEnabled) { @@ -51,8 +62,6 @@ class Connection extends EventEmitter { //TODO: can we just build Batch before the queue loop? const batch = new BatchPacket() this.outLog('<- BATCH', this.q2) - // For now, we're over conservative so send max 3 packets - // per batch and hold the rest for the next tick const sending = [] for (let i = 0; i < this.q.length; i++) { const packet = this.q.shift() @@ -65,28 +74,10 @@ class Connection extends EventEmitter { } else { this.sendDecryptedBatch(batch) } - // this.q2 = [] } }, 20) } - writeRaw(name, buffer) { // skip protodef serializaion - // temporary hard coded stuff - const batch = new BatchPacket() - if (name == 'biome_definition_list') { - // so we can send nbt straight from file without parsing - const stream = new BinaryStream() - stream.writeUnsignedVarInt(0x7a) - stream.append(buffer) - batch.addEncodedPacket(stream.getBuffer()) - } - - if (this.encryptionEnabled) { - this.sendEncryptedBatch(batch) - } else { - this.sendDecryptedBatch(batch) - } - } /** * Sends a MCPE packet buffer @@ -121,21 +112,11 @@ class Connection extends EventEmitter { // TODO: Rename this to sendEncapsulated sendMCPE(buffer, immediate) { this.connection.sendReliable(buffer, immediate) - // if (this.worker) { - // this.outLog('-> buf', buffer) - // this.worker.postMessage({ type: 'queueEncapsulated', packet: buffer, immediate }) - // } else { - // const sendPacket = new EncapsulatedPacket() - // sendPacket.reliability = Reliability.ReliableOrdered - // sendPacket.buffer = buffer - // this.connection.addEncapsulatedToQueue(sendPacket) - // if (immediate) this.connection.sendQueue() - // } } // These are callbacks called from encryption.js onEncryptedPacket = (buf) => { - this.outLog('ENC BUF', buf) + this.outLog('Enc buf', buf) const packet = Buffer.concat([Buffer.from([0xfe]), buf]) // add header this.outLog('Sending wrapped encrypted batch', packet) @@ -143,8 +124,6 @@ class Connection extends EventEmitter { } onDecryptedPacket = (buf) => { - // console.log('🟢 Decrypted', buf) - const stream = new BinaryStream(buf) const packets = BatchPacket.getPackets(stream) @@ -168,10 +147,7 @@ class Connection extends EventEmitter { } } } - // console.log('[client] handled incoming ', buffer) } } -function serialize(obj = {}, fmt) { - return JSON.stringify(obj, (k, v) => typeof v == 'bigint' ? v.toString() : v, fmt) -} + module.exports = { Connection } \ No newline at end of file diff --git a/src/datatypes/promises.js b/src/datatypes/promises.js deleted file mode 100644 index c3763e1..0000000 --- a/src/datatypes/promises.js +++ /dev/null @@ -1,12 +0,0 @@ -module.exports = { - sleep(ms) { - return new Promise(resolve => setTimeout(resolve, ms)) - }, - - waitFor(cb, withTimeout) { - return Promise.race([ - new Promise((res, rej) => cb(res)), - sleep(withTimeout) - ]) - } -} \ No newline at end of file diff --git a/src/datatypes/util.js b/src/datatypes/util.js new file mode 100644 index 0000000..1c8c3d8 --- /dev/null +++ b/src/datatypes/util.js @@ -0,0 +1,37 @@ +const fs = require('fs'); + +function getFiles(dir) { + var results = []; + var list = fs.readdirSync(dir); + list.forEach(function (file) { + file = dir + '/' + file; + var stat = fs.statSync(file); + if (stat && stat.isDirectory()) { + /* Recurse into a subdirectory */ + results = results.concat(getFiles(file)); + } else { + /* Is a file */ + results.push(file); + } + }); + return results; +} + +module.exports = { + sleep(ms) { + return new Promise(resolve => setTimeout(resolve, ms)) + }, + + waitFor(cb, withTimeout) { + return Promise.race([ + new Promise((res, rej) => cb(res)), + sleep(withTimeout) + ]) + }, + + serialize(obj = {}, fmt) { + return JSON.stringify(obj, (k, v) => typeof v == 'bigint' ? v.toString() : v, fmt) + }, + + getFiles +} \ No newline at end of file diff --git a/src/options.js b/src/options.js index dc329ea..e6fb930 100644 --- a/src/options.js +++ b/src/options.js @@ -1,12 +1,16 @@ // Minimum supported version (< will be kicked) -const MIN_VERSION = 422 +const MIN_VERSION = '1.16.201' // Currently supported verson -const CURRENT_VERSION = 422 - +const CURRENT_VERSION = '1.16.201' const defaultOptions = { // https://minecraft.gamepedia.com/Protocol_version#Bedrock_Edition_2 version: CURRENT_VERSION } -module.exports = { defaultOptions, MIN_VERSION, CURRENT_VERSION } \ No newline at end of file +const Versions = { + '1.16.210': 428, + '1.16.201': 422 +} + +module.exports = { defaultOptions, MIN_VERSION, CURRENT_VERSION, Versions } \ No newline at end of file diff --git a/src/rak.js b/src/rak.js index ad216a0..09510ad 100644 --- a/src/rak.js +++ b/src/rak.js @@ -3,6 +3,7 @@ const Listener = require('jsp-raknet/listener') const EncapsulatedPacket = require('jsp-raknet/protocol/encapsulated_packet') const RakClient = require('jsp-raknet/client') const ConnWorker = require('./rakWorker') +const { waitFor } = require('./datatypes/util') try { var { Client, Server, PacketPriority, PacketReliability, McPingMessage } = require('raknet-native') } catch (e) { @@ -12,14 +13,14 @@ try { class RakNativeClient extends EventEmitter { constructor(options) { super() - this.onConnected = () => {} - this.onCloseConnection = () => {} - this.onEncapsulated = () => {} + this.onConnected = () => { } + this.onCloseConnection = () => { } + this.onEncapsulated = () => { } this.raknet = new Client(options.hostname, options.port, 'minecraft') this.raknet.on('encapsulated', thingy => { // console.log('Encap',thingy) - const { buffer, address, guid }=thingy + const { buffer, address, guid } = thingy this.onEncapsulated(buffer, address) }) this.raknet.on('connected', () => { @@ -51,18 +52,17 @@ class RakNativeClient extends EventEmitter { class RakNativeServer extends EventEmitter { constructor(options = {}) { super() - console.log('opts',options) - this.onOpenConnection = () => {} - this.onCloseConnection = () => {} - this.onEncapsulated = () => {} + this.onOpenConnection = () => { } + this.onCloseConnection = () => { } + this.onEncapsulated = () => { } this.raknet = new Server(options.hostname, options.port, { maxConnections: options.maxConnections || 3, - minecraft: { }, + minecraft: {}, message: new McPingMessage().toBuffer() }) - + this.raknet.on('openConnection', (client) => { - client.sendReliable = function(buffer, immediate) { + client.sendReliable = function (buffer, immediate) { const priority = immediate ? PacketPriority.IMMEDIATE_PRIORITY : PacketPriority.MEDIUM_PRIORITY return this.send(buffer, priority, PacketReliability.RELIABLE_ORDERED, 0) } @@ -70,12 +70,13 @@ class RakNativeServer extends EventEmitter { }) this.raknet.on('closeConnection', (client) => { - console.log('!!! Client CLOSED CONNECTION!') + console.warn('! Client closed connection') + // TODO: need to handle this properly.. this.onCloseConnection(client) }) this.raknet.on('encapsulated', (thingy) => { - const { buffer, address, guid }=thingy + const { buffer, address, guid } = thingy // console.log('ENCAP',thingy) this.onEncapsulated(buffer, address) }) @@ -89,8 +90,8 @@ class RakNativeServer extends EventEmitter { class RakJsClient extends EventEmitter { constructor(options = {}) { super() - this.onConnected = () => {} - this.onEncapsulated = () => {} + this.onConnected = () => { } + this.onEncapsulated = () => { } if (options.useWorkers) { this.connect = this.workerConnect this.sendReliable = this.workerSendReliable @@ -145,9 +146,9 @@ class RakJsServer extends EventEmitter { constructor(options = {}) { super() this.options = options - this.onOpenConnection = () => {} - this.onCloseConnection = () => {} - this.onEncapsulated = () => {} + this.onOpenConnection = () => { } + this.onCloseConnection = () => { } + this.onEncapsulated = () => { } if (options.useWorkers) { throw Error('nyi') @@ -159,13 +160,13 @@ class RakJsServer extends EventEmitter { async plainListen() { this.raknet = new Listener() await this.raknet.listen(this.options.hostname, this.options.port) - this.raknet.on('openConnection', (conn) => { - conn.sendReliable = function(buffer, immediate) { + this.raknet.on('openConnection', (conn) => { + conn.sendReliable = function (buffer, immediate) { const sendPacket = new EncapsulatedPacket() sendPacket.reliability = Reliability.ReliableOrdered sendPacket.buffer = buffer this.connection.addEncapsulatedToQueue(sendPacket) - if (immediate) this.raknet.sendQueue() + if (immediate) this.raknet.sendQueue() } this.onOpenConnection(conn) }) @@ -174,7 +175,7 @@ class RakJsServer extends EventEmitter { } } -module.exports = { - RakClient: Client ? RakNativeClient : RakJsClient, +module.exports = { + RakClient: Client ? RakNativeClient : RakJsClient, RakServer: Server ? RakNativeServer : RakJsServer } \ No newline at end of file diff --git a/src/relay.js b/src/relay.js index 0fee6af..08314d1 100644 --- a/src/relay.js +++ b/src/relay.js @@ -4,6 +4,7 @@ const { Client } = require("./client") const { Server } = require("./server") const { Player } = require("./serverPlayer") const debug = require('debug')('minecraft-protocol relay') +const { serialize } = require('./datatypes/util') /** @typedef {{ hostname: string, port: number, auth: 'client' | 'server' | null, destination?: { hostname: string, port: number } }} Options */ @@ -67,7 +68,6 @@ class RelayPlayer extends Player { console.warn('Old', packet.toString('hex')) console.log('Failed to re-encode', name, params) process.exit(1) - throw Error('re-encoding fail for' + name + ' - ' + JSON.stringify(params)) } } @@ -159,7 +159,7 @@ class Relay extends Server { client.once('join', () => { // Intercept once handshaking done ds.upstream = client ds.flushUpQueue() - console.log('UPSTREAM HAS JOINED') + console.log('Connected to upstream server') client.readPacket = (packet) => ds.readUpstream(packet) }) this.upstreams.set(clientAddr.hash, client) @@ -167,7 +167,7 @@ class Relay extends Server { closeUpstreamConnection(clientAddr) { const up = this.upstreams.get(clientAddr.hash) - if (!up) throw Error(`unable to close non-existant connection ${clientAddr.hash}`) + if (!up) throw Error(`unable to close non-open connection ${clientAddr.hash}`) up.close() this.upstreams.delete(clientAddr.hash) debug('relay closed connection', clientAddr) @@ -188,43 +188,5 @@ class Relay extends Server { } } -function serialize(obj = {}, fmt) { - return JSON.stringify(obj, (k, v) => typeof v == 'bigint' ? v.toString() : v, fmt) -} - -function createRelay() { - console.log('Creating relay') - /** - * Example to create a non-transparent proxy (or 'Relay') connection to destination server - * In Relay we de-code and re-encode packets - */ - const relay = new Relay({ - /* Hostname and port for clients to listen to */ - hostname: '0.0.0.0', - port: 19130, - /** - * Who does the authentication - * If set to `client`, all connecting clients will be sent a message with a link to authenticate - * If set to `server`, the server will authenticate and only one client will be able to join - * (Default) If set to `none`, no authentication will be done - */ - auth: 'server', - - /** - * Sets if packets will automatically be forwarded. If set to false, you must listen for on('packet') - * events and - */ - auto: true, - - /* Where to send upstream packets to */ - destination: { - hostname: '127.0.0.1', - port: 19132, - // encryption: true - } - }) - - relay.create() -} - -createRelay() \ No newline at end of file +// Too many things called 'Proxy' ;) +module.exports = { Relay } \ No newline at end of file diff --git a/src/server.js b/src/server.js index 2e3a924..1dff4e7 100644 --- a/src/server.js +++ b/src/server.js @@ -9,18 +9,23 @@ class Server extends EventEmitter { constructor(options) { super() this.options = { ...Options.defaultOptions, ...options } - this.serializer = createSerializer() - this.deserializer = createDeserializer() + this.validateOptions() + this.serializer = createSerializer(this.options.version) + this.deserializer = createDeserializer(this.options.version) this.clients = {} this.clientCount = 0 - this.validateOptions() - this.inLog = (...args) => console.debug('S', ...args) - this.outLog = (...args) => console.debug('S', ...args) + this.inLog = (...args) => console.debug('C -> S', ...args) + this.outLog = (...args) => console.debug('S -> C', ...args) } validateOptions() { - if (this.options.version < Options.MIN_VERSION) { - throw new Error(`Unsupported protocol version < ${Options.MIN_VERSION} : ${this.options.version}`) + if (!Options.Versions[this.options.version]) { + console.warn('Supported versions: ', Options.Versions) + throw Error(`Unsupported version ${this.options.version}`) + } + this.options.protocolVersion = Options.Versions[this.options.version] + if (this.options.protocolVersion < Options.MIN_VERSION) { + throw new Error(`Protocol version < ${Options.MIN_VERSION} : ${this.options.protocolVersion}, too old`) } } @@ -39,7 +44,7 @@ class Server extends EventEmitter { } onEncapsulated = (buffer, address) => { - debug(address, 'Encapsulated', buffer) + this.inLog('encapsulated', address, buffer) const client = this.clients[address] if (!client) { throw new Error(`packet from unknown inet addr: ${address}`) @@ -57,6 +62,4 @@ class Server extends EventEmitter { } } -const hash = (inetAddr) => inetAddr.address + '/' + inetAddr.port - module.exports = { Server } \ No newline at end of file diff --git a/src/serverPlayer.js b/src/serverPlayer.js index 8d05c6a..3f41817 100644 --- a/src/serverPlayer.js +++ b/src/serverPlayer.js @@ -16,15 +16,14 @@ class Player extends Connection { this.server = server this.serializer = server.serializer this.deserializer = server.deserializer - // console.log('serializer/des',this.serializer,this.deserializer) this.connection = connection this.options = server.options Encrypt(this, server, this.options) this.startQueue() this.status = ClientStatus.Authenticating - this.inLog = (...args) => console.info('S ->', ...args) - this.outLog = (...args) => console.info('S <-', ...args) + this.inLog = (...args) => console.info('S -> C', ...args) + this.outLog = (...args) => console.info('C -> S', ...args) } getData() { @@ -33,17 +32,17 @@ class Player extends Connection { onLogin(packet) { let body = packet.data - debug('Body', body) + // debug('Login body', body) this.emit('loggingIn', body) const clientVer = body.protocol_version - if (this.server.options.version) { - if (this.server.options.version < clientVer) { - this.sendDisconnectStatus(failed_client) + if (this.server.options.protocolVersion) { + if (this.server.options.protocolVersion < clientVer) { + this.sendDisconnectStatus('failed_client') return } } else if (clientVer < MIN_VERSION) { - this.sendDisconnectStatus(failed_client) + this.sendDisconnectStatus('failed_client') return } @@ -55,6 +54,7 @@ class Player extends Connection { var { key, userData, chain } = decodeLoginJWT(authChain.chain, skinChain) } catch (e) { console.error(e) + // TODO: disconnect user throw new Error('Failed to verify user') } console.log('Verified user', 'got pub key', key, userData) @@ -66,7 +66,6 @@ class Player extends Connection { this.version = clientVer } - /** * Disconnects a client before it has joined * @param {string} play_status diff --git a/src/transforms/encryption.js b/src/transforms/encryption.js index dee6469..d2c1794 100644 --- a/src/transforms/encryption.js +++ b/src/transforms/encryption.js @@ -1,20 +1,20 @@ -const { PassThrough, Transform } = require('readable-stream') +const { Transform } = require('readable-stream') const crypto = require('crypto') const aesjs = require('aes-js') const Zlib = require('zlib') -const CIPHER = 'aes-256-cfb8' +const CIPHER_ALG = 'aes-256-cfb8' function createCipher(secret, initialValue) { - if (crypto.getCiphers().includes(CIPHER)) { - return crypto.createCipheriv(CIPHER, secret, initialValue) + if (crypto.getCiphers().includes(CIPHER_ALG)) { + return crypto.createCipheriv(CIPHER_ALG, secret, initialValue) } return new Cipher(secret, initialValue) } function createDecipher(secret, initialValue) { - if (crypto.getCiphers().includes(CIPHER)) { - return crypto.createDecipheriv(CIPHER, secret, initialValue) + if (crypto.getCiphers().includes(CIPHER_ALG)) { + return crypto.createDecipheriv(CIPHER_ALG, secret, initialValue) } return new Decipher(secret, initialValue) } @@ -54,14 +54,11 @@ class Decipher extends Transform { function computeCheckSum(packetPlaintext, sendCounter, secretKeyBytes) { let digest = crypto.createHash('sha256'); let counter = Buffer.alloc(8) - // writeLI64(sendCounter, counter, 0); counter.writeBigInt64LE(sendCounter, 0) - // console.log('Send counter', counter) digest.update(counter); digest.update(packetPlaintext); digest.update(secretKeyBytes); let hash = digest.digest(); - // console.log('Hash', hash.toString('hex')) return hash.slice(0, 8); } @@ -74,21 +71,14 @@ function createEncryptor(client, iv) { function process(chunk) { const buffer = Zlib.deflateRawSync(chunk, { level: 7 }) - // client.outLog('🟡 Compressed', buffer, client.sendCounter) const packet = Buffer.concat([buffer, computeCheckSum(buffer, client.sendCounter, client.secretKeyBytes)]) client.sendCounter++ - // client.outLog('writing to cipher...', packet, client.secretKeyBytes, iv) client.cipher.write(packet) } - // const stream = new PassThrough() - client.cipher.on('data', client.onEncryptedPacket) - return (blob) => { - // client.outLog(client.options ? 'C':'S', '🟡 Encrypting', client.sendCounter, blob) - // stream.write(blob) process(blob) } } @@ -99,6 +89,8 @@ function createDecryptor(client, iv) { client.receiveCounter = client.receiveCounter || 0n function verify(chunk) { + // TODO: remove the extra logic here, probably fixed with new raknet impl + // console.log('Decryptor: checking checksum', client.receiveCounter, chunk) // client.outLog('🔵 Inflating', chunk) // First try to zlib decompress, then see how much bytes get read @@ -139,8 +131,6 @@ function createDecryptor(client, iv) { client.decipher.on('data', verify) return (blob) => { - // client.inLog(client.options ? 'C':'S', ' 🔵 Decrypting', client.receiveCounter, blob) - // client.inLog('Using shared key', client.secretKeyBytes, iv) client.decipher.write(blob) } } diff --git a/src/transforms/serializer.js b/src/transforms/serializer.js index e07b63c..c7a70ed 100644 --- a/src/transforms/serializer.js +++ b/src/transforms/serializer.js @@ -1,9 +1,9 @@ const { ProtoDefCompiler, CompiledProtodef } = require('protodef').Compiler const { FullPacketParser, Serializer } = require('protodef') -function createProtocol() { - const protocol = require('../../data/newproto.json').types - console.log('Proto', protocol) +// Compiles the ProtoDef schema at runtime +function createProtocol(version) { + const protocol = require(`../../data/${version}/protocol.json`).types var compiler = new ProtoDefCompiler() compiler.addTypesToCompile(protocol) compiler.addTypes(require('../datatypes/compiler-minecraft')) @@ -13,8 +13,8 @@ function createProtocol() { return compiledProto } - -function getProtocol() { +// Loads already generated read/write/sizeof code +function getProtocol(version) { const compiler = new ProtoDefCompiler() compiler.addTypes(require('../datatypes/compiler-minecraft')) compiler.addTypes(require('prismarine-nbt/compiler-zigzag')) @@ -26,22 +26,19 @@ function getProtocol() { } return new CompiledProtodef( - compile(compiler.sizeOfCompiler, '../../data/size.js'), - compile(compiler.writeCompiler, '../../data/write.js'), - compile(compiler.readCompiler, '../../data/read.js') - // compiler.sizeOfCompiler.compile(fs.readFileSync(__dirname + '/../../data/size.js', 'utf-8')), - // compiler.writeCompiler.compile(fs.readFileSync(__dirname + '/../../data/write.js', 'utf-8')), - // compiler.readCompiler.compile(fs.readFileSync(__dirname + '/../../data/read.js', 'utf-8')) + compile(compiler.sizeOfCompiler, `../../data/${version}/size.js`), + compile(compiler.writeCompiler, `../../data/${version}/write.js`), + compile(compiler.readCompiler, `../../data/${version}/read.js`) ) } -function createSerializer() { - var proto = getProtocol() +function createSerializer(version) { + var proto = getProtocol(version) return new Serializer(proto, 'mcpe_packet'); } -function createDeserializer() { - var proto = getProtocol() +function createDeserializer(version) { + var proto = getProtocol(version) return new FullPacketParser(proto, 'mcpe_packet'); }