From 60bc179ab048693a4b9f3e50e8bcba9aa273860d Mon Sep 17 00:00:00 2001 From: Sebastian Piaskowy Date: Wed, 24 Sep 2025 15:30:50 +0200 Subject: [PATCH 1/4] Add 3D monkey example prototype --- .../public/assets/3d-monkey/monkey.obj | 2068 +++++++++++++++++ .../src/examples/react/3d-monkey/index.html | 2 + .../src/examples/react/3d-monkey/index.tsx | 103 + .../examples/react/3d-monkey/load-model.ts | 46 + .../src/examples/react/3d-monkey/meta.json | 5 + .../src/examples/react/3d-monkey/render.ts | 52 + .../src/examples/react/3d-monkey/schemas.ts | 26 + .../examples/react/3d-monkey/thumbnail.png | Bin 0 -> 185059 bytes 8 files changed, 2302 insertions(+) create mode 100644 apps/typegpu-docs/public/assets/3d-monkey/monkey.obj create mode 100644 apps/typegpu-docs/src/examples/react/3d-monkey/index.html create mode 100644 apps/typegpu-docs/src/examples/react/3d-monkey/index.tsx create mode 100644 apps/typegpu-docs/src/examples/react/3d-monkey/load-model.ts create mode 100644 apps/typegpu-docs/src/examples/react/3d-monkey/meta.json create mode 100644 apps/typegpu-docs/src/examples/react/3d-monkey/render.ts create mode 100644 apps/typegpu-docs/src/examples/react/3d-monkey/schemas.ts create mode 100644 apps/typegpu-docs/src/examples/react/3d-monkey/thumbnail.png diff --git a/apps/typegpu-docs/public/assets/3d-monkey/monkey.obj b/apps/typegpu-docs/public/assets/3d-monkey/monkey.obj new file mode 100644 index 000000000..7b24ff961 --- /dev/null +++ b/apps/typegpu-docs/public/assets/3d-monkey/monkey.obj @@ -0,0 +1,2068 @@ +# Blender v2.93.1 OBJ File: 'Suzanne.blend' +# www.blender.org +mtllib Suzanne.mtl +o Suzanne +v 0.437500 0.164062 0.765625 +v -0.437500 0.164062 0.765625 +v 0.500000 0.093750 0.687500 +v -0.500000 0.093750 0.687500 +v 0.546875 0.054688 0.578125 +v -0.546875 0.054688 0.578125 +v 0.351562 -0.023438 0.617188 +v -0.351562 -0.023438 0.617188 +v 0.351562 0.031250 0.718750 +v -0.351562 0.031250 0.718750 +v 0.351562 0.132812 0.781250 +v -0.351562 0.132812 0.781250 +v 0.273438 0.164062 0.796875 +v -0.273438 0.164062 0.796875 +v 0.203125 0.093750 0.742188 +v -0.203125 0.093750 0.742188 +v 0.156250 0.054688 0.648438 +v -0.156250 0.054688 0.648438 +v 0.078125 0.242188 0.656250 +v -0.078125 0.242188 0.656250 +v 0.140625 0.242188 0.742188 +v -0.140625 0.242188 0.742188 +v 0.242188 0.242188 0.796875 +v -0.242188 0.242188 0.796875 +v 0.273438 0.328125 0.796875 +v -0.273438 0.328125 0.796875 +v 0.203125 0.390625 0.742188 +v -0.203125 0.390625 0.742188 +v 0.156250 0.437500 0.648438 +v -0.156250 0.437500 0.648438 +v 0.351562 0.515625 0.617188 +v -0.351562 0.515625 0.617188 +v 0.351562 0.453125 0.718750 +v -0.351562 0.453125 0.718750 +v 0.351562 0.359375 0.781250 +v -0.351562 0.359375 0.781250 +v 0.437500 0.328125 0.765625 +v -0.437500 0.328125 0.765625 +v 0.500000 0.390625 0.687500 +v -0.500000 0.390625 0.687500 +v 0.546875 0.437500 0.578125 +v -0.546875 0.437500 0.578125 +v 0.625000 0.242188 0.562500 +v -0.625000 0.242188 0.562500 +v 0.562500 0.242188 0.671875 +v -0.562500 0.242188 0.671875 +v 0.468750 0.242188 0.757812 +v -0.468750 0.242188 0.757812 +v 0.476562 0.242188 0.773438 +v -0.476562 0.242188 0.773438 +v 0.445312 0.335938 0.781250 +v -0.445312 0.335938 0.781250 +v 0.351562 0.375000 0.804688 +v -0.351562 0.375000 0.804688 +v 0.265625 0.335938 0.820312 +v -0.265625 0.335938 0.820312 +v 0.226562 0.242188 0.820312 +v -0.226562 0.242188 0.820312 +v 0.265625 0.156250 0.820312 +v -0.265625 0.156250 0.820312 +v 0.351562 0.242188 0.828125 +v -0.351562 0.242188 0.828125 +v 0.351562 0.117188 0.804688 +v -0.351562 0.117188 0.804688 +v 0.445312 0.156250 0.781250 +v -0.445312 0.156250 0.781250 +v 0.000000 0.429688 0.742188 +v 0.000000 0.351562 0.820312 +v 0.000000 -0.679688 0.734375 +v 0.000000 -0.320312 0.781250 +v 0.000000 -0.187500 0.796875 +v 0.000000 -0.773438 0.718750 +v 0.000000 0.406250 0.601562 +v 0.000000 0.570312 0.570312 +v 0.000000 0.898438 -0.546875 +v 0.000000 0.562500 -0.851562 +v 0.000000 0.070312 -0.828125 +v 0.000000 -0.382812 -0.351562 +v 0.203125 -0.187500 0.562500 +v -0.203125 -0.187500 0.562500 +v 0.312500 -0.437500 0.570312 +v -0.312500 -0.437500 0.570312 +v 0.351562 -0.695312 0.570312 +v -0.351562 -0.695312 0.570312 +v 0.367188 -0.890625 0.531250 +v -0.367188 -0.890625 0.531250 +v 0.328125 -0.945312 0.523438 +v -0.328125 -0.945312 0.523438 +v 0.179688 -0.968750 0.554688 +v -0.179688 -0.968750 0.554688 +v 0.000000 -0.984375 0.578125 +v 0.437500 -0.140625 0.531250 +v -0.437500 -0.140625 0.531250 +v 0.632812 -0.039062 0.539062 +v -0.632812 -0.039062 0.539062 +v 0.828125 0.148438 0.445312 +v -0.828125 0.148438 0.445312 +v 0.859375 0.429688 0.593750 +v -0.859375 0.429688 0.593750 +v 0.710938 0.484375 0.625000 +v -0.710938 0.484375 0.625000 +v 0.492188 0.601562 0.687500 +v -0.492188 0.601562 0.687500 +v 0.320312 0.757812 0.734375 +v -0.320312 0.757812 0.734375 +v 0.156250 0.718750 0.757812 +v -0.156250 0.718750 0.757812 +v 0.062500 0.492188 0.750000 +v -0.062500 0.492188 0.750000 +v 0.164062 0.414062 0.773438 +v -0.164062 0.414062 0.773438 +v 0.125000 0.304688 0.765625 +v -0.125000 0.304688 0.765625 +v 0.203125 0.093750 0.742188 +v -0.203125 0.093750 0.742188 +v 0.375000 0.015625 0.703125 +v -0.375000 0.015625 0.703125 +v 0.492188 0.062500 0.671875 +v -0.492188 0.062500 0.671875 +v 0.625000 0.187500 0.648438 +v -0.625000 0.187500 0.648438 +v 0.640625 0.296875 0.648438 +v -0.640625 0.296875 0.648438 +v 0.601562 0.375000 0.664062 +v -0.601562 0.375000 0.664062 +v 0.429688 0.437500 0.718750 +v -0.429688 0.437500 0.718750 +v 0.250000 0.468750 0.757812 +v -0.250000 0.468750 0.757812 +v 0.000000 -0.765625 0.734375 +v 0.109375 -0.718750 0.734375 +v -0.109375 -0.718750 0.734375 +v 0.117188 -0.835938 0.710938 +v -0.117188 -0.835938 0.710938 +v 0.062500 -0.882812 0.695312 +v -0.062500 -0.882812 0.695312 +v 0.000000 -0.890625 0.687500 +v 0.000000 -0.195312 0.750000 +v 0.000000 -0.140625 0.742188 +v 0.101562 -0.148438 0.742188 +v -0.101562 -0.148438 0.742188 +v 0.125000 -0.226562 0.750000 +v -0.125000 -0.226562 0.750000 +v 0.085938 -0.289062 0.742188 +v -0.085938 -0.289062 0.742188 +v 0.398438 -0.046875 0.671875 +v -0.398438 -0.046875 0.671875 +v 0.617188 0.054688 0.625000 +v -0.617188 0.054688 0.625000 +v 0.726562 0.203125 0.601562 +v -0.726562 0.203125 0.601562 +v 0.742188 0.375000 0.656250 +v -0.742188 0.375000 0.656250 +v 0.687500 0.414062 0.726562 +v -0.687500 0.414062 0.726562 +v 0.437500 0.546875 0.796875 +v -0.437500 0.546875 0.796875 +v 0.312500 0.640625 0.835938 +v -0.312500 0.640625 0.835938 +v 0.203125 0.617188 0.851562 +v -0.203125 0.617188 0.851562 +v 0.101562 0.429688 0.843750 +v -0.101562 0.429688 0.843750 +v 0.125000 -0.101562 0.812500 +v -0.125000 -0.101562 0.812500 +v 0.210938 -0.445312 0.710938 +v -0.210938 -0.445312 0.710938 +v 0.250000 -0.703125 0.687500 +v -0.250000 -0.703125 0.687500 +v 0.265625 -0.820312 0.664062 +v -0.265625 -0.820312 0.664062 +v 0.234375 -0.914062 0.632812 +v -0.234375 -0.914062 0.632812 +v 0.164062 -0.929688 0.632812 +v -0.164062 -0.929688 0.632812 +v 0.000000 -0.945312 0.640625 +v 0.000000 0.046875 0.726562 +v 0.000000 0.210938 0.765625 +v 0.328125 0.476562 0.742188 +v -0.328125 0.476562 0.742188 +v 0.164062 0.140625 0.750000 +v -0.164062 0.140625 0.750000 +v 0.132812 0.210938 0.757812 +v -0.132812 0.210938 0.757812 +v 0.117188 -0.687500 0.734375 +v -0.117188 -0.687500 0.734375 +v 0.078125 -0.445312 0.750000 +v -0.078125 -0.445312 0.750000 +v 0.000000 -0.445312 0.750000 +v 0.000000 -0.328125 0.742188 +v 0.093750 -0.273438 0.781250 +v -0.093750 -0.273438 0.781250 +v 0.132812 -0.226562 0.796875 +v -0.132812 -0.226562 0.796875 +v 0.109375 -0.132812 0.781250 +v -0.109375 -0.132812 0.781250 +v 0.039062 -0.125000 0.781250 +v -0.039062 -0.125000 0.781250 +v 0.000000 -0.203125 0.828125 +v 0.046875 -0.148438 0.812500 +v -0.046875 -0.148438 0.812500 +v 0.093750 -0.156250 0.812500 +v -0.093750 -0.156250 0.812500 +v 0.109375 -0.226562 0.828125 +v -0.109375 -0.226562 0.828125 +v 0.078125 -0.250000 0.804688 +v -0.078125 -0.250000 0.804688 +v 0.000000 -0.289062 0.804688 +v 0.257812 -0.312500 0.554688 +v -0.257812 -0.312500 0.554688 +v 0.164062 -0.242188 0.710938 +v -0.164062 -0.242188 0.710938 +v 0.179688 -0.312500 0.710938 +v -0.179688 -0.312500 0.710938 +v 0.234375 -0.250000 0.554688 +v -0.234375 -0.250000 0.554688 +v 0.000000 -0.875000 0.687500 +v 0.046875 -0.867188 0.687500 +v -0.046875 -0.867188 0.687500 +v 0.093750 -0.820312 0.710938 +v -0.093750 -0.820312 0.710938 +v 0.093750 -0.742188 0.726562 +v -0.093750 -0.742188 0.726562 +v 0.000000 -0.781250 0.656250 +v 0.093750 -0.750000 0.664062 +v -0.093750 -0.750000 0.664062 +v 0.093750 -0.812500 0.640625 +v -0.093750 -0.812500 0.640625 +v 0.046875 -0.851562 0.632812 +v -0.046875 -0.851562 0.632812 +v 0.000000 -0.859375 0.632812 +v 0.171875 0.218750 0.781250 +v -0.171875 0.218750 0.781250 +v 0.187500 0.156250 0.773438 +v -0.187500 0.156250 0.773438 +v 0.335938 0.429688 0.757812 +v -0.335938 0.429688 0.757812 +v 0.273438 0.421875 0.773438 +v -0.273438 0.421875 0.773438 +v 0.421875 0.398438 0.773438 +v -0.421875 0.398438 0.773438 +v 0.562500 0.351562 0.695312 +v -0.562500 0.351562 0.695312 +v 0.585938 0.289062 0.687500 +v -0.585938 0.289062 0.687500 +v 0.578125 0.195312 0.679688 +v -0.578125 0.195312 0.679688 +v 0.476562 0.101562 0.718750 +v -0.476562 0.101562 0.718750 +v 0.375000 0.062500 0.742188 +v -0.375000 0.062500 0.742188 +v 0.226562 0.109375 0.781250 +v -0.226562 0.109375 0.781250 +v 0.179688 0.296875 0.781250 +v -0.179688 0.296875 0.781250 +v 0.210938 0.375000 0.781250 +v -0.210938 0.375000 0.781250 +v 0.234375 0.359375 0.757812 +v -0.234375 0.359375 0.757812 +v 0.195312 0.296875 0.757812 +v -0.195312 0.296875 0.757812 +v 0.242188 0.125000 0.757812 +v -0.242188 0.125000 0.757812 +v 0.375000 0.085938 0.726562 +v -0.375000 0.085938 0.726562 +v 0.460938 0.117188 0.703125 +v -0.460938 0.117188 0.703125 +v 0.546875 0.210938 0.671875 +v -0.546875 0.210938 0.671875 +v 0.554688 0.281250 0.671875 +v -0.554688 0.281250 0.671875 +v 0.531250 0.335938 0.679688 +v -0.531250 0.335938 0.679688 +v 0.414062 0.390625 0.750000 +v -0.414062 0.390625 0.750000 +v 0.281250 0.398438 0.765625 +v -0.281250 0.398438 0.765625 +v 0.335938 0.406250 0.750000 +v -0.335938 0.406250 0.750000 +v 0.203125 0.171875 0.750000 +v -0.203125 0.171875 0.750000 +v 0.195312 0.226562 0.750000 +v -0.195312 0.226562 0.750000 +v 0.109375 0.460938 0.609375 +v -0.109375 0.460938 0.609375 +v 0.195312 0.664062 0.617188 +v -0.195312 0.664062 0.617188 +v 0.335938 0.687500 0.593750 +v -0.335938 0.687500 0.593750 +v 0.484375 0.554688 0.554688 +v -0.484375 0.554688 0.554688 +v 0.679688 0.453125 0.492188 +v -0.679688 0.453125 0.492188 +v 0.796875 0.406250 0.460938 +v -0.796875 0.406250 0.460938 +v 0.773438 0.164062 0.375000 +v -0.773438 0.164062 0.375000 +v 0.601562 0.000000 0.414062 +v -0.601562 0.000000 0.414062 +v 0.437500 -0.093750 0.468750 +v -0.437500 -0.093750 0.468750 +v 0.000000 0.898438 0.289062 +v 0.000000 0.984375 -0.078125 +v 0.000000 -0.195312 -0.671875 +v 0.000000 -0.460938 0.187500 +v 0.000000 -0.976562 0.460938 +v 0.000000 -0.804688 0.343750 +v 0.000000 -0.570312 0.320312 +v 0.000000 -0.484375 0.281250 +v 0.851562 0.234375 0.054688 +v -0.851562 0.234375 0.054688 +v 0.859375 0.320312 -0.046875 +v -0.859375 0.320312 -0.046875 +v 0.773438 0.265625 -0.437500 +v -0.773438 0.265625 -0.437500 +v 0.460938 0.437500 -0.703125 +v -0.460938 0.437500 -0.703125 +v 0.734375 -0.046875 0.070312 +v -0.734375 -0.046875 0.070312 +v 0.593750 -0.125000 -0.164062 +v -0.593750 -0.125000 -0.164062 +v 0.640625 -0.007812 -0.429688 +v -0.640625 -0.007812 -0.429688 +v 0.335938 0.054688 -0.664062 +v -0.335938 0.054688 -0.664062 +v 0.234375 -0.351562 0.406250 +v -0.234375 -0.351562 0.406250 +v 0.179688 -0.414062 0.257812 +v -0.179688 -0.414062 0.257812 +v 0.289062 -0.710938 0.382812 +v -0.289062 -0.710938 0.382812 +v 0.250000 -0.500000 0.390625 +v -0.250000 -0.500000 0.390625 +v 0.328125 -0.914062 0.398438 +v -0.328125 -0.914062 0.398438 +v 0.140625 -0.757812 0.367188 +v -0.140625 -0.757812 0.367188 +v 0.125000 -0.539062 0.359375 +v -0.125000 -0.539062 0.359375 +v 0.164062 -0.945312 0.437500 +v -0.164062 -0.945312 0.437500 +v 0.218750 -0.281250 0.429688 +v -0.218750 -0.281250 0.429688 +v 0.210938 -0.226562 0.468750 +v -0.210938 -0.226562 0.468750 +v 0.203125 -0.171875 0.500000 +v -0.203125 -0.171875 0.500000 +v 0.210938 -0.390625 0.164062 +v -0.210938 -0.390625 0.164062 +v 0.296875 -0.312500 -0.265625 +v -0.296875 -0.312500 -0.265625 +v 0.343750 -0.148438 -0.539062 +v -0.343750 -0.148438 -0.539062 +v 0.453125 0.867188 -0.382812 +v -0.453125 0.867188 -0.382812 +v 0.453125 0.929688 -0.070312 +v -0.453125 0.929688 -0.070312 +v 0.453125 0.851562 0.234375 +v -0.453125 0.851562 0.234375 +v 0.460938 0.523438 0.429688 +v -0.460938 0.523438 0.429688 +v 0.726562 0.406250 0.335938 +v -0.726562 0.406250 0.335938 +v 0.632812 0.453125 0.281250 +v -0.632812 0.453125 0.281250 +v 0.640625 0.703125 0.054688 +v -0.640625 0.703125 0.054688 +v 0.796875 0.562500 0.125000 +v -0.796875 0.562500 0.125000 +v 0.796875 0.617188 -0.117188 +v -0.796875 0.617188 -0.117188 +v 0.640625 0.750000 -0.195312 +v -0.640625 0.750000 -0.195312 +v 0.640625 0.679688 -0.445312 +v -0.640625 0.679688 -0.445312 +v 0.796875 0.539062 -0.359375 +v -0.796875 0.539062 -0.359375 +v 0.617188 0.328125 -0.585938 +v -0.617188 0.328125 -0.585938 +v 0.484375 0.023438 -0.546875 +v -0.484375 0.023438 -0.546875 +v 0.820312 0.328125 -0.203125 +v -0.820312 0.328125 -0.203125 +v 0.406250 -0.171875 0.148438 +v -0.406250 -0.171875 0.148438 +v 0.429688 -0.195312 -0.210938 +v -0.429688 -0.195312 -0.210938 +v 0.890625 0.406250 -0.234375 +v -0.890625 0.406250 -0.234375 +v 0.773438 -0.140625 -0.125000 +v -0.773438 -0.140625 -0.125000 +v 1.039062 -0.101562 -0.328125 +v -1.039062 -0.101562 -0.328125 +v 1.281250 0.054688 -0.429688 +v -1.281250 0.054688 -0.429688 +v 1.351562 0.320312 -0.421875 +v -1.351562 0.320312 -0.421875 +v 1.234375 0.507812 -0.421875 +v -1.234375 0.507812 -0.421875 +v 1.023438 0.476562 -0.312500 +v -1.023438 0.476562 -0.312500 +v 1.015625 0.414062 -0.289062 +v -1.015625 0.414062 -0.289062 +v 1.187500 0.437500 -0.390625 +v -1.187500 0.437500 -0.390625 +v 1.265625 0.289062 -0.406250 +v -1.265625 0.289062 -0.406250 +v 1.210938 0.078125 -0.406250 +v -1.210938 0.078125 -0.406250 +v 1.031250 -0.039062 -0.304688 +v -1.031250 -0.039062 -0.304688 +v 0.828125 -0.070312 -0.132812 +v -0.828125 -0.070312 -0.132812 +v 0.921875 0.359375 -0.218750 +v -0.921875 0.359375 -0.218750 +v 0.945312 0.304688 -0.289062 +v -0.945312 0.304688 -0.289062 +v 0.882812 -0.023438 -0.210938 +v -0.882812 -0.023438 -0.210938 +v 1.039062 0.000000 -0.367188 +v -1.039062 0.000000 -0.367188 +v 1.187500 0.093750 -0.445312 +v -1.187500 0.093750 -0.445312 +v 1.234375 0.250000 -0.445312 +v -1.234375 0.250000 -0.445312 +v 1.171875 0.359375 -0.437500 +v -1.171875 0.359375 -0.437500 +v 1.023438 0.343750 -0.359375 +v -1.023438 0.343750 -0.359375 +v 0.843750 0.289062 -0.210938 +v -0.843750 0.289062 -0.210938 +v 0.835938 0.171875 -0.273438 +v -0.835938 0.171875 -0.273438 +v 0.757812 0.093750 -0.273438 +v -0.757812 0.093750 -0.273438 +v 0.820312 0.085938 -0.273438 +v -0.820312 0.085938 -0.273438 +v 0.843750 0.015625 -0.273438 +v -0.843750 0.015625 -0.273438 +v 0.812500 -0.015625 -0.273438 +v -0.812500 -0.015625 -0.273438 +v 0.726562 0.000000 -0.070312 +v -0.726562 0.000000 -0.070312 +v 0.718750 -0.023438 -0.171875 +v -0.718750 -0.023438 -0.171875 +v 0.718750 0.039062 -0.187500 +v -0.718750 0.039062 -0.187500 +v 0.796875 0.203125 -0.210938 +v -0.796875 0.203125 -0.210938 +v 0.890625 0.242188 -0.265625 +v -0.890625 0.242188 -0.265625 +v 0.890625 0.234375 -0.320312 +v -0.890625 0.234375 -0.320312 +v 0.812500 -0.015625 -0.320312 +v -0.812500 -0.015625 -0.320312 +v 0.851562 0.015625 -0.320312 +v -0.851562 0.015625 -0.320312 +v 0.828125 0.078125 -0.320312 +v -0.828125 0.078125 -0.320312 +v 0.765625 0.093750 -0.320312 +v -0.765625 0.093750 -0.320312 +v 0.843750 0.171875 -0.320312 +v -0.843750 0.171875 -0.320312 +v 1.039062 0.328125 -0.414062 +v -1.039062 0.328125 -0.414062 +v 1.187500 0.343750 -0.484375 +v -1.187500 0.343750 -0.484375 +v 1.257812 0.242188 -0.492188 +v -1.257812 0.242188 -0.492188 +v 1.210938 0.085938 -0.484375 +v -1.210938 0.085938 -0.484375 +v 1.046875 0.000000 -0.421875 +v -1.046875 0.000000 -0.421875 +v 0.882812 -0.015625 -0.265625 +v -0.882812 -0.015625 -0.265625 +v 0.953125 0.289062 -0.343750 +v -0.953125 0.289062 -0.343750 +v 0.890625 0.109375 -0.328125 +v -0.890625 0.109375 -0.328125 +v 0.937500 0.062500 -0.335938 +v -0.937500 0.062500 -0.335938 +v 1.000000 0.125000 -0.367188 +v -1.000000 0.125000 -0.367188 +v 0.960938 0.171875 -0.351562 +v -0.960938 0.171875 -0.351562 +v 1.015625 0.234375 -0.375000 +v -1.015625 0.234375 -0.375000 +v 1.054688 0.187500 -0.382812 +v -1.054688 0.187500 -0.382812 +v 1.109375 0.210938 -0.390625 +v -1.109375 0.210938 -0.390625 +v 1.085938 0.273438 -0.390625 +v -1.085938 0.273438 -0.390625 +v 1.023438 0.437500 -0.484375 +v -1.023438 0.437500 -0.484375 +v 1.250000 0.468750 -0.546875 +v -1.250000 0.468750 -0.546875 +v 1.367188 0.296875 -0.500000 +v -1.367188 0.296875 -0.500000 +v 1.312500 0.054688 -0.531250 +v -1.312500 0.054688 -0.531250 +v 1.039062 -0.085938 -0.492188 +v -1.039062 -0.085938 -0.492188 +v 0.789062 -0.125000 -0.328125 +v -0.789062 -0.125000 -0.328125 +v 0.859375 0.382812 -0.382812 +v -0.859375 0.382812 -0.382812 +vt 0.890955 0.590063 +vt 0.870622 0.589649 +vt 0.860081 0.560115 +vt 0.904571 0.559404 +vt 0.856226 0.850547 +vt 0.868067 0.821510 +vt 0.888398 0.821999 +vt 0.900640 0.853232 +vt 0.853018 0.521562 +vt 0.920166 0.524546 +vt 0.847458 0.888748 +vt 0.914672 0.888748 +vt 0.828900 0.590771 +vt 0.798481 0.569535 +vt 0.795104 0.838402 +vt 0.826436 0.818537 +vt 0.854402 0.604754 +vt 0.852534 0.805700 +vt 0.854107 0.625459 +vt 0.828171 0.633354 +vt 0.827598 0.775964 +vt 0.853157 0.785002 +vt 0.791018 0.645443 +vt 0.791018 0.762238 +vt 0.855181 0.668527 +vt 0.842358 0.702491 +vt 0.844839 0.707525 +vt 0.856142 0.742025 +vt 0.867508 0.642291 +vt 0.867293 0.768782 +vt 0.890474 0.641909 +vt 0.900375 0.666964 +vt 0.901223 0.745592 +vt 0.890219 0.770183 +vt 0.918898 0.699697 +vt 0.921180 0.713713 +vt 0.931889 0.636832 +vt 0.968392 0.645333 +vt 0.968213 0.770220 +vt 0.931368 0.777093 +vt 0.905882 0.627902 +vt 0.904990 0.784860 +vt 0.906232 0.605742 +vt 0.933717 0.593037 +vt 0.931250 0.820926 +vt 0.904357 0.807013 +vt 0.968392 0.573812 +vt 0.965038 0.841671 +vt 0.902359 0.607909 +vt 0.889591 0.593275 +vt 0.900583 0.804677 +vt 0.887178 0.818729 +vt 0.899781 0.626257 +vt 0.898822 0.786233 +vt 0.887842 0.636527 +vt 0.887351 0.775442 +vt 0.870908 0.635245 +vt 0.870376 0.775972 +vt 0.859881 0.623942 +vt 0.858859 0.786774 +vt 0.859664 0.608186 +vt 0.857942 0.802505 +vt 0.871664 0.593961 +vt 0.869299 0.817249 +vt 0.879400 0.616512 +vt 0.878029 0.795063 +vt 0.540260 0.053805 +vt 0.536419 0.062072 +vt 0.518925 0.059681 +vt 0.518916 0.050294 +vt 0.501452 0.062043 +vt 0.497626 0.053770 +vt 0.551930 0.058338 +vt 0.542788 0.064089 +vt 0.495083 0.064047 +vt 0.485955 0.058273 +vt 0.555073 0.061900 +vt 0.546290 0.072669 +vt 0.491565 0.072625 +vt 0.482805 0.061829 +vt 0.563812 0.076586 +vt 0.548333 0.084893 +vt 0.489507 0.084858 +vt 0.474014 0.076511 +vt 0.583135 0.108495 +vt 0.555621 0.121749 +vt 0.482177 0.121781 +vt 0.454527 0.108481 +vt 0.605512 0.165134 +vt 0.647395 0.200502 +vt 0.621513 0.227818 +vt 0.553118 0.209599 +vt 0.416514 0.229490 +vt 0.389677 0.201890 +vt 0.432024 0.165644 +vt 0.485339 0.210053 +vt 0.676379 0.233241 +vt 0.664761 0.253225 +vt 0.372747 0.256357 +vt 0.360308 0.235899 +vt 0.715342 0.265392 +vt 0.683908 0.279995 +vt 0.353696 0.284606 +vt 0.320452 0.270303 +vt 0.707254 0.310054 +vt 0.687515 0.311539 +vt 0.351187 0.317440 +vt 0.330721 0.316853 +vt 0.697446 0.332673 +vt 0.676824 0.323937 +vt 0.362723 0.329722 +vt 0.341964 0.339667 +vt 0.662817 0.372521 +vt 0.639050 0.357330 +vt 0.402772 0.362131 +vt 0.379297 0.378686 +vt 0.626842 0.395792 +vt 0.618316 0.375151 +vt 0.424583 0.379267 +vt 0.416915 0.400552 +vt 0.604826 0.397804 +vt 0.600808 0.377857 +vt 0.442396 0.381222 +vt 0.439252 0.401540 +vt 0.553095 0.390512 +vt 0.559674 0.357011 +vt 0.482938 0.358497 +vt 0.490934 0.391862 +vt 0.521923 0.386009 +vt 0.521086 0.343868 +vt 0.577279 0.340156 +vt 0.599845 0.344815 +vt 0.441977 0.347815 +vt 0.464579 0.342230 +vt 0.615546 0.342005 +vt 0.425972 0.345582 +vt 0.634472 0.332311 +vt 0.406362 0.336480 +vt 0.662406 0.312804 +vt 0.377061 0.317685 +vt 0.668440 0.297958 +vt 0.370304 0.302644 +vt 0.664101 0.277872 +vt 0.374100 0.281778 +vt 0.639236 0.253047 +vt 0.398938 0.255633 +vt 0.613992 0.242662 +vt 0.424464 0.244473 +vt 0.572941 0.258564 +vt 0.466409 0.259709 +vt 0.563905 0.272007 +vt 0.519760 0.248864 +vt 0.475886 0.273078 +vt 0.558527 0.316594 +vt 0.482619 0.317843 +vt 0.520277 0.294764 +vt 0.556923 0.291214 +vt 0.483433 0.292249 +vt 0.525483 0.068967 +vt 0.518928 0.067899 +vt 0.512375 0.068956 +vt 0.531231 0.073829 +vt 0.506626 0.073811 +vt 0.531019 0.087431 +vt 0.506827 0.087416 +vt 0.532042 0.127713 +vt 0.532669 0.090920 +vt 0.505177 0.090908 +vt 0.505828 0.127728 +vt 0.538112 0.158382 +vt 0.518981 0.151749 +vt 0.518941 0.128358 +vt 0.499851 0.158434 +vt 0.518925 0.093952 +vt 0.518927 0.085180 +vt 0.548362 0.173560 +vt 0.537959 0.175966 +vt 0.535214 0.166808 +vt 0.502799 0.166857 +vt 0.500100 0.176033 +vt 0.489683 0.173693 +vt 0.544281 0.193366 +vt 0.537248 0.187577 +vt 0.500890 0.187571 +vt 0.493996 0.193428 +vt 0.519841 0.200843 +vt 0.528757 0.191785 +vt 0.509219 0.191626 +vt 0.517577 0.190607 +vt 0.519132 0.185382 +vt 0.518998 0.159028 +vt 0.531131 0.171631 +vt 0.519016 0.165599 +vt 0.506910 0.171667 +vt 0.519099 0.179457 +vt 0.528222 0.186316 +vt 0.509787 0.186260 +vt 0.533528 0.184215 +vt 0.504547 0.184206 +vt 0.533449 0.176739 +vt 0.504604 0.176791 +vt 0.561572 0.167779 +vt 0.476363 0.167996 +vt 0.559475 0.149319 +vt 0.478371 0.149447 +vt 0.596138 0.133426 +vt 0.441395 0.133592 +vt 0.601169 0.147885 +vt 0.436337 0.148194 +vt 0.518925 0.083865 +vt 0.528933 0.084957 +vt 0.508915 0.084945 +vt 0.529036 0.075429 +vt 0.508820 0.075415 +vt 0.523751 0.070508 +vt 0.514106 0.070501 +vt 0.518929 0.069468 +vt 0.521560 0.074970 +vt 0.518928 0.074259 +vt 0.516297 0.074966 +vt 0.524236 0.076691 +vt 0.513619 0.076684 +vt 0.524601 0.079886 +vt 0.513252 0.079879 +vt 0.518926 0.079331 +vt 0.571787 0.277295 +vt 0.568351 0.292904 +vt 0.468070 0.278617 +vt 0.471978 0.294282 +vt 0.573085 0.311386 +vt 0.467790 0.313081 +vt 0.584855 0.327708 +vt 0.456477 0.329961 +vt 0.580734 0.266620 +vt 0.458737 0.268049 +vt 0.611720 0.255725 +vt 0.427062 0.257728 +vt 0.632494 0.262853 +vt 0.406068 0.265508 +vt 0.653658 0.279971 +vt 0.384904 0.283634 +vt 0.656064 0.297636 +vt 0.383015 0.301864 +vt 0.652752 0.310186 +vt 0.386858 0.314615 +vt 0.629040 0.323864 +vt 0.411556 0.327673 +vt 0.614408 0.331972 +vt 0.426727 0.335361 +vt 0.601033 0.333624 +vt 0.440344 0.336537 +vt 0.590644 0.321516 +vt 0.601799 0.328453 +vt 0.450408 0.323919 +vt 0.439372 0.331331 +vt 0.613335 0.327083 +vt 0.427623 0.330358 +vt 0.626851 0.320513 +vt 0.413648 0.324175 +vt 0.646248 0.306421 +vt 0.393381 0.310510 +vt 0.649541 0.296225 +vt 0.389662 0.300183 +vt 0.647785 0.283486 +vt 0.391040 0.287071 +vt 0.629829 0.267263 +vt 0.408893 0.269959 +vt 0.612641 0.261560 +vt 0.426254 0.263693 +vt 0.585166 0.270991 +vt 0.454369 0.272583 +vt 0.578124 0.281900 +vt 0.461798 0.283441 +vt 0.579548 0.309340 +vt 0.461204 0.311233 +vt 0.577524 0.293776 +vt 0.462754 0.295432 +vt 0.553209 0.433063 +vt 0.523031 0.433628 +vt 0.492809 0.434538 +vt 0.609819 0.431516 +vt 0.435860 0.435740 +vt 0.648174 0.419316 +vt 0.396518 0.425416 +vt 0.692106 0.388274 +vt 0.350292 0.396229 +vt 0.726332 0.341754 +vt 0.312756 0.350588 +vt 0.735879 0.312112 +vt 0.301067 0.320593 +vt 0.729900 0.256393 +vt 0.304876 0.261087 +vt 0.698172 0.216906 +vt 0.337414 0.219179 +vt 0.663103 0.190671 +vt 0.373474 0.191872 +vt 0.626908 0.015608 +vt 0.649444 0.022378 +vt 0.660451 0.076084 +vt 0.621440 0.048089 +vt 0.376796 0.075296 +vt 0.388827 0.021586 +vt 0.411318 0.015131 +vt 0.416419 0.047631 +vt 0.567460 0.000144 +vt 0.577206 0.032801 +vt 0.470636 0.000144 +vt 0.460782 0.032656 +vt 0.518922 0.024886 +vt 0.547413 0.041724 +vt 0.490511 0.041669 +vt 0.558059 0.053871 +vt 0.479842 0.053785 +vt 0.576951 0.057998 +vt 0.460920 0.057845 +vt 0.611687 0.078268 +vt 0.425932 0.077985 +vt 0.626663 0.111357 +vt 0.410618 0.111244 +vt 0.629482 0.130456 +vt 0.623495 0.146796 +vt 0.413741 0.147158 +vt 0.407648 0.130594 +vt 0.619303 0.159841 +vt 0.418035 0.160361 +vt 0.945900 0.079569 +vt 0.886245 0.121777 +vt 0.849114 0.099732 +vt 0.891780 0.036916 +vt 0.183115 0.092127 +vt 0.141314 0.112482 +vt 0.078961 0.060719 +vt 0.142277 0.021467 +vt 0.788458 0.080826 +vt 0.805584 0.010786 +vt 0.246353 0.076510 +vt 0.232648 0.003484 +vt 0.687018 0.077204 +vt 0.672384 0.022201 +vt 0.349875 0.075955 +vt 0.365979 0.020991 +vt 0.760215 0.193244 +vt 0.789046 0.233323 +vt 0.271553 0.193871 +vt 0.241255 0.236977 +vt 0.994525 0.167705 +vt 0.909112 0.183261 +vt 0.107928 0.179083 +vt 0.011829 0.155367 +vt 0.911671 0.402429 +vt 0.862868 0.338556 +vt 0.894128 0.301884 +vt 0.962901 0.344752 +vt 0.123776 0.315519 +vt 0.160557 0.356821 +vt 0.106400 0.432652 +vt 0.043968 0.367038 +vt 0.915360 0.259804 +vt 0.999856 0.254640 +vt 0.098965 0.266968 +vt 0.000144 0.259113 +vt 0.749542 0.334683 +vt 0.766337 0.300809 +vt 0.789162 0.313727 +vt 0.267408 0.310142 +vt 0.288183 0.346496 +vt 0.242992 0.325552 +vt 0.815314 0.276388 +vt 0.846174 0.293397 +vt 0.213065 0.285164 +vt 0.178537 0.304983 +vt 0.845007 0.256352 +vt 0.873517 0.265922 +vt 0.179662 0.263312 +vt 0.147089 0.274284 +vt 0.859075 0.228168 +vt 0.886999 0.233769 +vt 0.162803 0.231720 +vt 0.131514 0.237587 +vt 0.842355 0.195160 +vt 0.875030 0.184705 +vt 0.145224 0.182749 +vt 0.176788 0.196179 +vt 0.794286 0.364062 +vt 0.239776 0.382592 +vt 0.770185 0.379538 +vt 0.268122 0.398737 +vt 0.845499 0.449967 +vt 0.185281 0.484099 +vt 0.815858 0.445381 +vt 0.770572 0.444261 +vt 0.755700 0.418603 +vt 0.287033 0.442912 +vt 0.271364 0.473316 +vt 0.219260 0.477186 +vt 0.819845 0.468071 +vt 0.215894 0.503605 +vt 0.809631 0.233887 +vt 0.219168 0.237388 +vt 0.829287 0.219562 +vt 0.199067 0.222464 +vt 0.786480 0.117591 +vt 0.715482 0.139727 +vt 0.246666 0.114850 +vt 0.319538 0.139409 +vt 0.785486 0.152330 +vt 0.245969 0.151002 +vt 0.837382 0.156361 +vt 0.858171 0.137775 +vt 0.171653 0.132294 +vt 0.196622 0.155241 +vt 0.506166 0.904851 +vt 0.432388 0.894943 +vt 0.438797 0.870229 +vt 0.491058 0.881714 +vt 0.315867 0.868209 +vt 0.321637 0.893225 +vt 0.247207 0.901159 +vt 0.263032 0.878321 +vt 0.572792 0.860484 +vt 0.604825 0.879946 +vt 0.181486 0.854693 +vt 0.148729 0.873349 +vt 0.586396 0.793977 +vt 0.619962 0.791615 +vt 0.169745 0.787474 +vt 0.136063 0.784093 +vt 0.549027 0.746412 +vt 0.563786 0.739211 +vt 0.208656 0.740879 +vt 0.194086 0.733241 +vt 0.500314 0.711729 +vt 0.508270 0.697693 +vt 0.258399 0.707497 +vt 0.250811 0.693249 +vt 0.438641 0.680683 +vt 0.434803 0.658882 +vt 0.320962 0.677959 +vt 0.325318 0.656224 +vt 0.505666 0.730944 +vt 0.452955 0.700023 +vt 0.306136 0.696976 +vt 0.252524 0.726592 +vt 0.542850 0.755753 +vt 0.214575 0.750414 +vt 0.568148 0.787367 +vt 0.188269 0.781375 +vt 0.555495 0.826352 +vt 0.199850 0.820889 +vt 0.501231 0.844356 +vt 0.253846 0.840502 +vt 0.457832 0.840040 +vt 0.297562 0.837358 +vt 0.796021 0.176969 +vt 0.783193 0.187449 +vt 0.233625 0.175620 +vt 0.246955 0.187075 +vt 0.391039 0.611891 +vt 0.394766 0.686125 +vt 0.369913 0.610196 +vt 0.364838 0.684445 +vt 0.391747 0.862097 +vt 0.401605 0.841460 +vt 0.354026 0.840297 +vt 0.363377 0.861308 +vt 0.435018 0.718280 +vt 0.323658 0.715731 +vt 0.433669 0.729661 +vt 0.384658 0.710299 +vt 0.374400 0.708969 +vt 0.324726 0.727177 +vt 0.410995 0.747662 +vt 0.427812 0.742828 +vt 0.347028 0.745816 +vt 0.330270 0.740536 +vt 0.418086 0.784946 +vt 0.384657 0.795423 +vt 0.372270 0.794472 +vt 0.338952 0.783073 +vt 0.431333 0.817535 +vt 0.324790 0.815460 +vt 0.816266 0.203086 +vt 0.825107 0.209762 +vt 0.199767 0.214827 +vt 0.209828 0.206161 +vt 0.802192 0.184609 +vt 0.226485 0.183086 +vt 0.448505 0.804621 +vt 0.473386 0.824700 +vt 0.307886 0.802031 +vt 0.282357 0.821525 +vt 0.435868 0.779569 +vt 0.321237 0.777208 +vt 0.423718 0.754191 +vt 0.334089 0.752045 +vt 0.437950 0.749777 +vt 0.319919 0.747250 +vt 0.445392 0.731997 +vt 0.312907 0.729222 +vt 0.440995 0.724383 +vt 0.317510 0.721697 +vt 0.455277 0.713731 +vt 0.303460 0.710657 +vt 0.512485 0.828811 +vt 0.242975 0.824574 +vt 0.550942 0.811814 +vt 0.204839 0.806417 +vt 0.552139 0.787682 +vt 0.204331 0.782156 +vt 0.539407 0.764539 +vt 0.217774 0.759319 +vt 0.508439 0.743135 +vt 0.249419 0.738732 +vt 0.470841 0.748408 +vt 0.454776 0.761665 +vt 0.286960 0.745020 +vt 0.302729 0.758742 +vt 0.488870 0.770464 +vt 0.475403 0.783904 +vt 0.268291 0.766661 +vt 0.281439 0.780511 +vt 0.503673 0.787562 +vt 0.494476 0.802470 +vt 0.252972 0.783410 +vt 0.261790 0.798626 +vt 0.518562 0.791602 +vt 0.516802 0.807339 +vt 0.237920 0.787045 +vt 0.239243 0.802891 +vt 0.484068 0.628776 +vt 0.543385 0.683538 +vt 0.276936 0.625067 +vt 0.216123 0.678120 +vt 0.581052 0.726933 +vt 0.177176 0.720426 +vt 0.616701 0.759965 +vt 0.140379 0.752377 +vt 0.707492 0.759884 +vt 0.660647 0.741167 +vt 0.049526 0.748824 +vt 0.097038 0.732052 +vt 0.745511 0.652100 +vt 0.677256 0.670436 +vt 0.019409 0.639749 +vt 0.083564 0.662038 +vt 0.740843 0.572428 +vt 0.671403 0.592656 +vt 0.033664 0.564403 +vt 0.092820 0.589862 +vt 0.834578 0.206879 +vt 0.834705 0.206959 +vt 0.051216 0.522659 +vt 0.145041 0.562595 +vt 0.620420 0.565675 +vt 0.498072 0.552315 +vt 0.264218 0.550140 +vn 0.6650 -0.2008 0.7194 +vn -0.6650 -0.2008 0.7194 +vn 0.8294 -0.3036 0.4689 +vn -0.8294 -0.3036 0.4689 +vn 0.4155 -0.7933 0.4449 +vn -0.4155 -0.7933 0.4449 +vn 0.3600 -0.5089 0.7820 +vn -0.3600 -0.5089 0.7820 +vn -0.0787 -0.5394 0.8384 +vn 0.0787 -0.5394 0.8384 +vn -0.2696 -0.8413 0.4685 +vn 0.2696 -0.8413 0.4685 +vn -0.7707 -0.3352 0.5420 +vn 0.7707 -0.3352 0.5420 +vn -0.4689 -0.1940 0.8617 +vn 0.4689 -0.1940 0.8617 +vn -0.4767 0.1907 0.8581 +vn 0.4767 0.1907 0.8581 +vn -0.7672 0.3264 0.5521 +vn 0.7672 0.3264 0.5521 +vn -0.2519 0.8173 0.5182 +vn 0.2519 0.8173 0.5182 +vn -0.0949 0.5696 0.8164 +vn 0.0949 0.5696 0.8164 +vn 0.3667 0.5370 0.7597 +vn -0.3667 0.5370 0.7597 +vn 0.4141 0.7672 0.4898 +vn -0.4141 0.7672 0.4898 +vn 0.8277 0.2952 0.4771 +vn -0.8277 0.2952 0.4771 +vn 0.6713 0.1971 0.7145 +vn -0.6713 0.1971 0.7145 +vn 0.8111 0.3244 -0.4867 +vn -0.8111 0.3244 -0.4867 +vn 0.2052 0.8206 -0.5334 +vn -0.2052 0.8206 -0.5334 +vn -0.4223 0.7806 -0.4607 +vn 0.4223 0.7806 -0.4607 +vn -0.8241 0.3225 -0.4658 +vn 0.8241 0.3225 -0.4658 +vn -0.8137 -0.3487 -0.4650 +vn 0.8137 -0.3487 -0.4650 +vn -0.4223 -0.7806 -0.4607 +vn 0.4223 -0.7806 -0.4607 +vn 0.2052 -0.8206 -0.5334 +vn -0.2052 -0.8206 -0.5334 +vn 0.7995 -0.3510 -0.4875 +vn -0.7995 -0.3510 -0.4875 +vn 0.4000 -0.0623 0.9144 +vn -0.4000 -0.0623 0.9144 +vn 0.3069 -0.1754 0.9354 +vn -0.3069 -0.1754 0.9354 +vn 0.0945 -0.1835 0.9785 +vn -0.0945 -0.1835 0.9785 +vn -0.0624 -0.0283 0.9977 +vn 0.0624 -0.0283 0.9977 +vn -0.0624 0.0260 0.9977 +vn 0.0624 0.0260 0.9977 +vn 0.0996 0.1729 0.9799 +vn -0.0996 0.1729 0.9799 +vn 0.3036 0.1656 0.9383 +vn -0.3036 0.1656 0.9383 +vn 0.4002 0.0572 0.9147 +vn -0.4002 0.0572 0.9147 +vn 0.1231 -0.8616 0.4924 +vn -0.1231 -0.8616 0.4924 +vn 0.2190 -0.8647 0.4520 +vn -0.2190 -0.8647 0.4520 +vn 0.5902 -0.4550 0.6668 +vn -0.5902 -0.4550 0.6668 +vn 0.7689 -0.0506 0.6374 +vn -0.7689 -0.0506 0.6374 +vn 0.7796 0.0900 0.6197 +vn -0.7796 0.0900 0.6197 +vn 0.3241 -0.8188 0.4739 +vn -0.3241 -0.8188 0.4739 +vn 0.3857 -0.6629 0.6417 +vn -0.3857 -0.6629 0.6417 +vn 0.6895 -0.4193 0.5906 +vn -0.6895 -0.4193 0.5906 +vn 0.6588 -0.3634 0.6588 +vn -0.6588 -0.3634 0.6588 +vn 0.5465 0.3707 0.7509 +vn -0.5465 0.3707 0.7509 +vn 0.5064 0.6464 0.5706 +vn -0.5064 0.6464 0.5706 +vn 0.6092 0.5167 0.6015 +vn -0.6092 0.5167 0.6015 +vn -0.0441 0.6610 0.7491 +vn 0.0441 0.6610 0.7491 +vn -0.7246 0.3187 0.6110 +vn 0.7246 0.3187 0.6110 +vn -0.5880 0.5554 0.5880 +vn 0.5880 0.5554 0.5880 +vn 0.5361 -0.3909 0.7482 +vn -0.5361 -0.3909 0.7482 +vn 0.2207 -0.4690 0.8552 +vn -0.2207 -0.4690 0.8552 +vn -0.0794 -0.5321 0.8429 +vn 0.0794 -0.5321 0.8429 +vn -0.0825 -0.6575 0.7490 +vn 0.0825 -0.6575 0.7490 +vn 0.0457 -0.5667 0.8226 +vn -0.0457 -0.5667 0.8226 +vn 0.2784 -0.2130 0.9365 +vn -0.2784 -0.2130 0.9365 +vn 0.3813 -0.1824 0.9063 +vn -0.3813 -0.1824 0.9063 +vn 0.3357 -0.2878 0.8969 +vn -0.3357 -0.2878 0.8969 +vn 0.3762 0.0603 0.9246 +vn -0.3762 0.0603 0.9246 +vn -0.1352 0.2680 0.9539 +vn 0.1352 0.2680 0.9539 +vn 0.3961 -0.4321 0.8102 +vn -0.3961 -0.4321 0.8102 +vn 0.1856 -0.2474 0.9510 +vn -0.1856 -0.2474 0.9510 +vn 0.0099 -0.1948 0.9808 +vn -0.0099 -0.1948 0.9808 +vn 0.0721 -0.6966 0.7138 +vn -0.0721 -0.6966 0.7138 +vn 0.1863 -0.5723 0.7986 +vn -0.1863 -0.5723 0.7986 +vn 0.3157 -0.2708 0.9094 +vn -0.3157 -0.2708 0.9094 +vn 0.3063 -0.0265 0.9516 +vn -0.3063 -0.0265 0.9516 +vn 0.3266 -0.1306 0.9361 +vn -0.3266 -0.1306 0.9361 +vn -0.0137 0.0574 0.9983 +vn 0.0137 0.0574 0.9983 +vn -0.0026 -0.0656 0.9978 +vn 0.0026 -0.0656 0.9978 +vn 0.0000 0.0000 1.0000 +vn 0.8174 -0.5744 -0.0442 +vn -0.8174 -0.5744 -0.0442 +vn 0.9494 0.2297 -0.2144 +vn -0.9494 0.2297 -0.2144 +vn 0.0825 0.9073 -0.4124 +vn -0.0825 0.9073 -0.4124 +vn -0.8836 0.3555 0.3047 +vn 0.8836 0.3555 0.3047 +vn 0.4207 -0.8797 0.2218 +vn -0.4207 -0.8797 0.2218 +vn 0.2873 -0.5747 0.7663 +vn -0.2873 -0.5747 0.7663 +vn -0.6542 0.6019 0.4580 +vn 0.6542 0.6019 0.4580 +vn 0.1052 0.7892 0.6051 +vn -0.1052 0.7892 0.6051 +vn 0.7582 0.2916 0.5832 +vn -0.7582 0.2916 0.5832 +vn 0.3889 -0.7130 0.5834 +vn -0.3889 -0.7130 0.5834 +vn 0.0463 0.2314 0.9718 +vn -0.0463 0.2314 0.9718 +vn 0.0335 -0.4018 0.9151 +vn -0.0335 -0.4018 0.9151 +vn -0.4452 -0.1610 0.8809 +vn 0.4452 -0.1610 0.8809 +vn -0.2182 -0.4364 0.8729 +vn 0.2182 -0.4364 0.8729 +vn 0.4341 -0.1290 0.8916 +vn -0.4341 -0.1290 0.8916 +vn 0.3008 0.0501 0.9524 +vn -0.3008 0.0501 0.9524 +vn 0.8123 0.3010 0.4996 +vn -0.8123 0.3010 0.4996 +vn 0.8753 0.2574 0.4093 +vn -0.8753 0.2574 0.4093 +vn 0.9385 0.1601 0.3060 +vn -0.9385 0.1601 0.3060 +vn 0.2237 -0.6539 0.7227 +vn -0.2237 -0.6539 0.7227 +vn -0.1536 -0.1997 0.9677 +vn 0.1536 -0.1997 0.9677 +vn -0.2733 -0.1025 0.9565 +vn 0.2733 -0.1025 0.9565 +vn -0.0976 0.1952 0.9759 +vn 0.0976 0.1952 0.9759 +vn -0.1582 0.9494 0.2713 +vn 0.1582 0.9494 0.2713 +vn -0.6934 0.7082 0.1328 +vn 0.6934 0.7082 0.1328 +vn -1.0000 0.0000 0.0000 +vn 1.0000 0.0000 0.0000 +vn 0.3051 -0.9450 0.1181 +vn -0.3051 -0.9450 0.1181 +vn 0.0298 -0.2981 0.9541 +vn -0.0298 -0.2981 0.9541 +vn 0.1353 -0.3479 0.9277 +vn -0.1353 -0.3479 0.9277 +vn -0.5085 -0.2755 0.8158 +vn 0.5085 -0.2755 0.8158 +vn -0.3843 -0.0419 0.9223 +vn 0.3843 -0.0419 0.9223 +vn -0.2083 0.0374 0.9774 +vn 0.2083 0.0374 0.9774 +vn -0.5721 -0.4767 0.6674 +vn 0.5721 -0.4767 0.6674 +vn -0.1369 -0.7531 0.6435 +vn 0.1369 -0.7531 0.6435 +vn 0.4088 -0.6071 0.6814 +vn -0.4088 -0.6071 0.6814 +vn 0.5740 -0.4130 0.7070 +vn -0.5740 -0.4130 0.7070 +vn 0.5665 -0.0968 0.8183 +vn -0.5665 -0.0968 0.8183 +vn 0.5703 0.1180 0.8129 +vn -0.5703 0.1180 0.8129 +vn 0.4823 0.5621 0.6719 +vn -0.4823 0.5621 0.6719 +vn 0.2604 0.6114 0.7473 +vn -0.2604 0.6114 0.7473 +vn 0.1640 0.3607 0.9182 +vn -0.1640 0.3607 0.9182 +vn -0.0178 0.2495 0.9682 +vn 0.0178 0.2495 0.9682 +vn 0.3273 -0.4166 0.8481 +vn -0.3273 -0.4166 0.8481 +vn 0.2811 -0.2610 0.9235 +vn -0.2811 -0.2610 0.9235 +vn -0.2542 -0.6514 0.7149 +vn 0.2542 -0.6514 0.7149 +vn -0.0260 -0.8455 0.5333 +vn 0.0260 -0.8455 0.5333 +vn -0.3518 -0.2606 0.8991 +vn 0.3518 -0.2606 0.8991 +vn -0.3523 -0.0110 0.9358 +vn 0.3523 -0.0110 0.9358 +vn -0.1317 0.4608 0.8777 +vn 0.1317 0.4608 0.8777 +vn -0.0342 0.6159 0.7870 +vn 0.0342 0.6159 0.7870 +vn 0.3603 0.5836 0.7277 +vn -0.3603 0.5836 0.7277 +vn 0.4988 0.5300 0.6858 +vn -0.4988 0.5300 0.6858 +vn 0.6667 -0.3333 0.6667 +vn -0.6667 -0.3333 0.6667 +vn 0.8165 -0.0731 0.5727 +vn -0.8165 -0.0731 0.5727 +vn 0.7840 0.1161 0.6098 +vn -0.7840 0.1161 0.6098 +vn -0.5306 0.8111 -0.2461 +vn 0.5306 0.8111 -0.2461 +vn -0.8511 0.3695 -0.3730 +vn 0.8511 0.3695 -0.3730 +vn -0.2446 0.8675 -0.4331 +vn 0.2446 0.8675 -0.4331 +vn 0.5924 0.7465 -0.3030 +vn -0.5924 0.7465 -0.3030 +vn 0.3685 0.8758 -0.3118 +vn -0.3685 0.8758 -0.3118 +vn 0.2821 0.9151 -0.2880 +vn -0.2821 0.9151 -0.2880 +vn 0.8561 0.1340 -0.4991 +vn -0.8561 0.1340 -0.4991 +vn 0.5342 -0.7233 -0.4376 +vn -0.5342 -0.7233 -0.4376 +vn 0.3849 -0.8131 -0.4368 +vn -0.3849 -0.8131 -0.4368 +vn 0.2335 -0.5806 -0.7800 +vn -0.2335 -0.5806 -0.7800 +vn 0.2449 -0.0583 -0.9678 +vn -0.2449 -0.0583 -0.9678 +vn 0.1163 -0.4535 -0.8837 +vn -0.1163 -0.4535 -0.8837 +vn 0.1152 -0.9836 -0.1388 +vn -0.1152 -0.9836 -0.1388 +vn 0.1184 -0.9669 -0.2260 +vn -0.1184 -0.9669 -0.2260 +vn 0.9597 -0.0085 -0.2808 +vn -0.9597 -0.0085 -0.2808 +vn 0.9319 0.1629 -0.3242 +vn -0.9319 0.1629 -0.3242 +vn 0.1626 0.0207 -0.9865 +vn -0.1626 0.0207 -0.9865 +vn -0.0188 -0.2177 -0.9758 +vn 0.0188 -0.2177 -0.9758 +vn 0.7538 -0.2926 -0.5884 +vn -0.7538 -0.2926 -0.5884 +vn 0.9196 0.1379 -0.3678 +vn -0.9196 0.1379 -0.3678 +vn 0.9297 0.3127 -0.1944 +vn -0.9297 0.3127 -0.1944 +vn 0.9120 0.3376 -0.2329 +vn -0.9120 0.3376 -0.2329 +vn 0.9407 0.3338 -0.0607 +vn -0.9407 0.3338 -0.0607 +vn 0.1761 -0.8805 -0.4402 +vn -0.1761 -0.8805 -0.4402 +vn 0.3708 -0.4733 -0.7991 +vn -0.3708 -0.4733 -0.7991 +vn 0.3107 -0.8284 -0.4660 +vn -0.3107 -0.8284 -0.4660 +vn 0.2793 -0.9515 -0.1287 +vn -0.2793 -0.9515 -0.1287 +vn 0.3139 -0.9321 -0.1807 +vn -0.3139 -0.9321 -0.1807 +vn 0.9762 -0.2083 -0.0609 +vn -0.9762 -0.2083 -0.0609 +vn 0.8267 -0.5066 0.2447 +vn -0.8267 -0.5066 0.2447 +vn 0.3449 -0.1158 -0.9315 +vn -0.3449 -0.1158 -0.9315 +vn 0.1203 0.9644 0.2355 +vn -0.1203 0.9644 0.2355 +vn 0.1275 0.9744 -0.1851 +vn -0.1275 0.9744 -0.1851 +vn 0.3492 0.5947 -0.7241 +vn -0.3492 0.5947 -0.7241 +vn 0.4153 0.8981 -0.1449 +vn -0.4153 0.8981 -0.1449 +vn 0.1845 0.7036 0.6863 +vn -0.1845 0.7036 0.6863 +vn 0.6056 0.7794 0.1608 +vn -0.6056 0.7794 0.1608 +vn 0.7033 0.6806 -0.2053 +vn -0.7033 0.6806 -0.2053 +vn 0.6679 0.2007 -0.7166 +vn -0.6679 0.2007 -0.7166 +vn 0.4948 0.4342 -0.7528 +vn -0.4948 0.4342 -0.7528 +vn 0.6423 0.7459 -0.1761 +vn -0.6423 0.7459 -0.1761 +vn 0.7182 0.6788 0.1530 +vn -0.7182 0.6788 0.1530 +vn 0.7388 0.3972 0.5444 +vn -0.7388 0.3972 0.5444 +vn 0.3428 0.9261 -0.1579 +vn -0.3428 0.9261 -0.1579 +vn 0.2270 0.5740 0.7867 +vn -0.2270 0.5740 0.7867 +vn -0.1722 0.1046 -0.9795 +vn 0.1722 0.1046 -0.9795 +vn 0.0425 0.9150 0.4013 +vn -0.0425 0.9150 0.4013 +vn -0.1616 0.1847 0.9694 +vn 0.1616 0.1847 0.9694 +vn 0.9791 0.1973 0.0483 +vn -0.9791 0.1973 0.0483 +vn 0.9470 0.0918 0.3079 +vn -0.9470 0.0918 0.3079 +vn 0.9794 0.1905 -0.0661 +vn -0.9794 0.1905 -0.0661 +vn 0.9938 0.0312 -0.1070 +vn -0.9938 0.0312 -0.1070 +vn 0.7116 -0.7008 0.0501 +vn -0.7116 -0.7008 0.0501 +vn 0.3722 -0.9243 0.0847 +vn -0.3722 -0.9243 0.0847 +vn 0.4465 -0.8644 0.2310 +vn -0.4465 -0.8644 0.2310 +vn 0.6066 -0.7578 0.2405 +vn -0.6066 -0.7578 0.2405 +vn 0.7325 -0.6368 0.2407 +vn -0.7325 -0.6368 0.2407 +vn 0.2637 -0.4499 0.8533 +vn -0.2637 -0.4499 0.8533 +vn 0.5568 -0.3181 -0.7673 +vn -0.5568 -0.3181 -0.7673 +vn 0.5004 -0.2807 -0.8190 +vn -0.5004 -0.2807 -0.8190 +vn 0.3190 -0.8494 -0.4205 +vn -0.3190 -0.8494 -0.4205 +vn 0.7198 -0.6356 -0.2793 +vn -0.7198 -0.6356 -0.2793 +vn 0.4972 -0.4408 -0.7473 +vn -0.4972 -0.4408 -0.7473 +vn 0.3506 0.3807 0.8557 +vn -0.3506 0.3807 0.8557 +vn 0.4566 0.1715 0.8730 +vn -0.4566 0.1715 0.8730 +vn 0.2583 0.1055 0.9603 +vn -0.2583 0.1055 0.9603 +vn 0.2455 -0.0802 0.9661 +vn -0.2455 -0.0802 0.9661 +vn 0.4643 -0.0599 0.8837 +vn -0.4643 -0.0599 0.8837 +vn 0.6225 -0.3045 0.7210 +vn -0.6225 -0.3045 0.7210 +vn 0.4500 0.6590 0.6027 +vn -0.4500 0.6590 0.6027 +vn -0.2667 0.8309 0.4884 +vn 0.2667 0.8309 0.4884 +vn -0.8284 0.2291 0.5111 +vn 0.8284 0.2291 0.5111 +vn -0.5251 -0.3566 0.7727 +vn 0.5251 -0.3566 0.7727 +vn 0.4546 -0.5665 0.6873 +vn -0.4546 -0.5665 0.6873 +vn 0.6996 -0.4497 0.5552 +vn -0.6996 -0.4497 0.5552 +vn 0.7220 -0.6827 -0.1126 +vn -0.7220 -0.6827 -0.1126 +vn -0.1919 0.2860 0.9388 +vn 0.1919 0.2860 0.9388 +vn 0.9048 -0.3734 -0.2047 +vn -0.9048 -0.3734 -0.2047 +vn 0.1034 0.1551 0.9825 +vn -0.1034 0.1551 0.9825 +vn 0.0841 0.9318 0.3530 +vn -0.0841 0.9318 0.3530 +vn 0.6446 -0.0883 0.7594 +vn -0.6446 -0.0883 0.7594 +vn 0.4309 0.4740 0.7678 +vn -0.4309 0.4740 0.7678 +vn 0.8032 -0.4847 0.3462 +vn -0.8032 -0.4847 0.3462 +vn 0.5811 -0.4128 0.7014 +vn -0.5811 -0.4128 0.7014 +vn 0.5910 -0.4305 0.6822 +vn -0.5910 -0.4305 0.6822 +vn 0.9818 -0.1804 -0.0591 +vn -0.9818 -0.1804 -0.0591 +vn 0.9105 -0.3965 -0.1175 +vn -0.9105 -0.3965 -0.1175 +vn 0.9972 -0.0181 -0.0725 +vn -0.9972 -0.0181 -0.0725 +vn 0.7313 -0.6543 0.1925 +vn -0.7313 -0.6543 0.1925 +vn 0.7867 -0.6079 0.1073 +vn -0.7867 -0.6079 0.1073 +vn 0.7022 -0.7022 0.1170 +vn -0.7022 -0.7022 0.1170 +vn 0.1840 0.9816 -0.0511 +vn -0.1840 0.9816 -0.0511 +vn 0.9352 0.3301 0.1284 +vn -0.9352 0.3301 0.1284 +vn 0.6633 -0.7463 0.0553 +vn -0.6633 -0.7463 0.0553 +vn -0.0085 0.9970 0.0767 +vn 0.0085 0.9970 0.0767 +vn 0.6237 -0.7061 0.3354 +vn -0.6237 -0.7061 0.3354 +vn 0.2733 -0.8925 0.3587 +vn -0.2733 -0.8925 0.3587 +vn -0.8328 -0.5080 -0.2200 +vn 0.8328 -0.5080 -0.2200 +vn -0.8339 0.2377 -0.4981 +vn 0.8339 0.2377 -0.4981 +vn -0.5655 0.7847 -0.2539 +vn 0.5655 0.7847 -0.2539 +vn -0.0560 0.9962 0.0672 +vn 0.0560 0.9962 0.0672 +vn 0.1445 0.0222 0.9893 +vn -0.1445 0.0222 0.9893 +vn 0.3275 0.0645 0.9427 +vn -0.3275 0.0645 0.9427 +vn 0.3127 0.0232 0.9496 +vn -0.3127 0.0232 0.9496 +vn 0.1710 0.0274 0.9849 +vn -0.1710 0.0274 0.9849 +vn 0.3487 0.2849 0.8929 +vn -0.3487 0.2849 0.8929 +vn 0.4006 -0.0343 0.9156 +vn -0.4006 -0.0343 0.9156 +vn 0.2572 -0.0603 0.9645 +vn -0.2572 -0.0603 0.9645 +vn 0.0637 -0.0106 0.9979 +vn -0.0637 -0.0106 0.9979 +vn -0.3637 0.7039 0.6101 +vn 0.3637 0.7039 0.6101 +vn 0.6299 0.0355 0.7759 +vn -0.6299 0.0355 0.7759 +vn 0.4472 -0.2002 0.8717 +vn -0.4472 -0.2002 0.8717 +vn 0.5072 -0.2141 0.8348 +vn -0.5072 -0.2141 0.8348 +vn 0.5258 0.2619 0.8093 +vn -0.5258 0.2619 0.8093 +vn 0.2980 0.5802 0.7580 +vn -0.2980 0.5802 0.7580 +vn 0.0930 -0.9924 -0.0805 +vn -0.0930 -0.9924 -0.0805 +vn 0.5006 -0.8657 0.0080 +vn -0.5006 -0.8657 0.0080 +vn 0.9285 -0.2497 0.2748 +vn -0.9285 -0.2497 0.2748 +vn 0.8393 0.5424 -0.0378 +vn -0.8393 0.5424 -0.0378 +vn -0.2355 0.9367 -0.2589 +vn 0.2355 0.9367 -0.2589 +vn -0.4499 0.8838 -0.1285 +vn 0.4499 0.8838 -0.1285 +vn -0.5384 -0.0098 -0.8427 +vn 0.5384 -0.0098 -0.8427 +vn -0.1910 -0.0241 -0.9813 +vn 0.1910 -0.0241 -0.9813 +vn 0.4046 0.0266 -0.9141 +vn -0.4046 0.0266 -0.9141 +vn -0.7819 0.6231 0.0197 +vn 0.7819 0.6231 0.0197 +vn 0.5428 -0.2063 -0.8142 +vn -0.5428 -0.2063 -0.8142 +vn -0.2474 -0.9231 -0.2945 +vn 0.2474 -0.9231 -0.2945 +usemtl None +s off +f 47/1/1 1/2/1 3/3/1 45/4/1 +f 4/5/2 2/6/2 48/7/2 46/8/2 +f 45/4/3 3/3/3 5/9/3 43/10/3 +f 6/11/4 4/5/4 46/8/4 44/12/4 +f 3/3/5 9/13/5 7/14/5 5/9/5 +f 8/15/6 10/16/6 4/5/6 6/11/6 +f 1/2/7 11/17/7 9/13/7 3/3/7 +f 10/16/8 12/18/8 2/6/8 4/5/8 +f 11/17/9 13/19/9 15/20/9 9/13/9 +f 16/21/10 14/22/10 12/18/10 10/16/10 +f 9/13/11 15/20/11 17/23/11 7/14/11 +f 18/24/12 16/21/12 10/16/12 8/15/12 +f 15/20/13 21/25/13 19/26/13 17/23/13 +f 20/27/14 22/28/14 16/21/14 18/24/14 +f 13/19/15 23/29/15 21/25/15 15/20/15 +f 22/28/16 24/30/16 14/22/16 16/21/16 +f 23/29/17 25/31/17 27/32/17 21/25/17 +f 28/33/18 26/34/18 24/30/18 22/28/18 +f 21/25/19 27/32/19 29/35/19 19/26/19 +f 30/36/20 28/33/20 22/28/20 20/27/20 +f 27/32/21 33/37/21 31/38/21 29/35/21 +f 32/39/22 34/40/22 28/33/22 30/36/22 +f 25/31/23 35/41/23 33/37/23 27/32/23 +f 34/40/24 36/42/24 26/34/24 28/33/24 +f 35/41/25 37/43/25 39/44/25 33/37/25 +f 40/45/26 38/46/26 36/42/26 34/40/26 +f 33/37/27 39/44/27 41/47/27 31/38/27 +f 42/48/28 40/45/28 34/40/28 32/39/28 +f 39/44/29 45/4/29 43/10/29 41/47/29 +f 44/12/30 46/8/30 40/45/30 42/48/30 +f 37/43/31 47/1/31 45/4/31 39/44/31 +f 46/8/32 48/7/32 38/46/32 40/45/32 +f 47/1/33 37/43/33 51/49/33 49/50/33 +f 52/51/34 38/46/34 48/7/34 50/52/34 +f 37/43/35 35/41/35 53/53/35 51/49/35 +f 54/54/36 36/42/36 38/46/36 52/51/36 +f 35/41/37 25/31/37 55/55/37 53/53/37 +f 56/56/38 26/34/38 36/42/38 54/54/38 +f 25/31/39 23/29/39 57/57/39 55/55/39 +f 58/58/40 24/30/40 26/34/40 56/56/40 +f 23/29/41 13/19/41 59/59/41 57/57/41 +f 60/60/42 14/22/42 24/30/42 58/58/42 +f 13/19/43 11/17/43 63/61/43 59/59/43 +f 64/62/44 12/18/44 14/22/44 60/60/44 +f 11/17/45 1/2/45 65/63/45 63/61/45 +f 66/64/46 2/6/46 12/18/46 64/62/46 +f 1/2/47 47/1/47 49/50/47 65/63/47 +f 50/52/48 48/7/48 2/6/48 66/64/48 +f 61/65/49 65/63/49 49/50/49 +f 50/52/50 66/64/50 62/66/50 +f 63/61/51 65/63/51 61/65/51 +f 62/66/52 66/64/52 64/62/52 +f 61/65/53 59/59/53 63/61/53 +f 64/62/54 60/60/54 62/66/54 +f 61/65/55 57/57/55 59/59/55 +f 60/60/56 58/58/56 62/66/56 +f 61/65/57 55/55/57 57/57/57 +f 58/58/58 56/56/58 62/66/58 +f 61/65/59 53/53/59 55/55/59 +f 56/56/60 54/54/60 62/66/60 +f 61/65/61 51/49/61 53/53/61 +f 54/54/62 52/51/62 62/66/62 +f 61/65/63 49/50/63 51/49/63 +f 52/51/64 50/52/64 62/66/64 +f 89/67/65 174/68/65 176/69/65 91/70/65 +f 176/69/66 175/71/66 90/72/66 91/70/66 +f 87/73/67 172/74/67 174/68/67 89/67/67 +f 175/71/68 173/75/68 88/76/68 90/72/68 +f 85/77/69 170/78/69 172/74/69 87/73/69 +f 173/75/70 171/79/70 86/80/70 88/76/70 +f 83/81/71 168/82/71 170/78/71 85/77/71 +f 171/79/72 169/83/72 84/84/72 86/80/72 +f 81/85/73 166/86/73 168/82/73 83/81/73 +f 169/83/74 167/87/74 82/88/74 84/84/74 +f 79/89/75 92/90/75 146/91/75 164/92/75 +f 147/93/76 93/94/76 80/95/76 165/96/76 +f 92/90/77 94/97/77 148/98/77 146/91/77 +f 149/99/78 95/100/78 93/94/78 147/93/78 +f 94/97/79 96/101/79 150/102/79 148/98/79 +f 151/103/80 97/104/80 95/100/80 149/99/80 +f 96/101/81 98/105/81 152/106/81 150/102/81 +f 153/107/82 99/108/82 97/104/82 151/103/82 +f 98/105/83 100/109/83 154/110/83 152/106/83 +f 155/111/84 101/112/84 99/108/84 153/107/84 +f 100/109/85 102/113/85 156/114/85 154/110/85 +f 157/115/86 103/116/86 101/112/86 155/111/86 +f 102/113/87 104/117/87 158/118/87 156/114/87 +f 159/119/88 105/120/88 103/116/88 157/115/88 +f 104/117/89 106/121/89 160/122/89 158/118/89 +f 161/123/90 107/124/90 105/120/90 159/119/90 +f 106/121/91 108/125/91 162/126/91 160/122/91 +f 163/127/92 109/128/92 107/124/92 161/123/92 +f 108/125/93 67/129/93 68/130/93 162/126/93 +f 68/130/94 67/129/94 109/128/94 163/127/94 +f 110/131/95 128/132/95 160/122/95 162/126/95 +f 161/123/96 129/133/96 111/134/96 163/127/96 +f 128/132/97 179/135/97 158/118/97 160/122/97 +f 159/119/98 180/136/98 129/133/98 161/123/98 +f 126/137/99 156/114/99 158/118/99 179/135/99 +f 159/119/100 157/115/100 127/138/100 180/136/100 +f 124/139/101 154/110/101 156/114/101 126/137/101 +f 157/115/102 155/111/102 125/140/102 127/138/102 +f 122/141/103 152/106/103 154/110/103 124/139/103 +f 155/111/104 153/107/104 123/142/104 125/140/104 +f 120/143/105 150/102/105 152/106/105 122/141/105 +f 153/107/106 151/103/106 121/144/106 123/142/106 +f 118/145/107 148/98/107 150/102/107 120/143/107 +f 151/103/108 149/99/108 119/146/108 121/144/108 +f 116/147/109 146/91/109 148/98/109 118/145/109 +f 149/99/110 147/93/110 117/148/110 119/146/110 +f 114/149/111 164/92/111 146/91/111 116/147/111 +f 147/93/112 165/96/112 115/150/112 117/148/112 +f 114/149/113 181/151/113 177/152/113 164/92/113 +f 177/152/114 182/153/114 115/150/114 165/96/114 +f 110/131/115 162/126/115 68/130/115 112/154/115 +f 68/130/116 163/127/116 111/134/116 113/155/116 +f 112/154/117 68/130/117 178/156/117 183/157/117 +f 178/156/118 68/130/118 113/155/118 184/158/118 +f 177/152/119 181/151/119 183/157/119 178/156/119 +f 184/158/120 182/153/120 177/152/120 178/156/120 +f 135/159/121 137/160/121 176/69/121 174/68/121 +f 176/69/122 137/160/122 136/161/122 175/71/122 +f 133/162/123 135/159/123 174/68/123 172/74/123 +f 175/71/124 136/161/124 134/163/124 173/75/124 +f 131/164/125 133/162/125 172/74/125 170/78/125 +f 173/75/126 134/163/126 132/165/126 171/79/126 +f 166/86/127 187/166/127 185/167/127 168/82/127 +f 186/168/128 188/169/128 167/87/128 169/83/128 +f 131/164/129 170/78/129 168/82/129 185/167/129 +f 169/83/130 171/79/130 132/165/130 186/168/130 +f 144/170/131 190/171/131 189/172/131 187/166/131 +f 189/172/132 190/171/132 145/173/132 188/169/132 +f 185/167/133 187/166/133 189/172/133 69/174/133 +f 189/172/134 188/169/134 186/168/134 69/174/134 +f 130/175/135 131/164/135 185/167/135 69/174/135 +f 186/168/135 132/165/135 130/175/135 69/174/135 +f 142/176/136 193/177/136 191/178/136 144/170/136 +f 192/179/137 194/180/137 143/181/137 145/173/137 +f 140/182/138 195/183/138 193/177/138 142/176/138 +f 194/180/139 196/184/139 141/185/139 143/181/139 +f 139/186/140 197/187/140 195/183/140 140/182/140 +f 196/184/141 198/188/141 139/186/141 141/185/141 +f 138/189/142 71/190/142 197/187/142 139/186/142 +f 198/188/143 71/190/143 138/189/143 139/186/143 +f 190/171/144 144/170/144 191/178/144 70/191/144 +f 192/179/145 145/173/145 190/171/145 70/191/145 +f 70/191/146 191/178/146 206/192/146 208/193/146 +f 207/194/147 192/179/147 70/191/147 208/193/147 +f 71/190/148 199/195/148 200/196/148 197/187/148 +f 201/197/149 199/195/149 71/190/149 198/188/149 +f 197/187/150 200/196/150 202/198/150 195/183/150 +f 203/199/151 201/197/151 198/188/151 196/184/151 +f 195/183/152 202/198/152 204/200/152 193/177/152 +f 205/201/153 203/199/153 196/184/153 194/180/153 +f 193/177/154 204/200/154 206/192/154 191/178/154 +f 207/194/155 205/201/155 194/180/155 192/179/155 +f 199/195/156 204/200/156 202/198/156 200/196/156 +f 203/199/157 205/201/157 199/195/157 201/197/157 +f 199/195/158 208/193/158 206/192/158 204/200/158 +f 207/194/159 208/193/159 199/195/159 205/201/159 +f 139/186/160 140/182/160 164/92/160 177/152/160 +f 165/96/161 141/185/161 139/186/161 177/152/161 +f 140/182/162 142/176/162 211/202/162 164/92/162 +f 212/203/163 143/181/163 141/185/163 165/96/163 +f 142/176/164 144/170/164 213/204/164 211/202/164 +f 214/205/165 145/173/165 143/181/165 212/203/165 +f 144/170/166 187/166/166 166/86/166 213/204/166 +f 167/87/167 188/169/167 145/173/167 214/205/167 +f 81/85/168 209/206/168 213/204/168 166/86/168 +f 214/205/169 210/207/169 82/88/169 167/87/169 +f 209/206/170 215/208/170 211/202/170 213/204/170 +f 212/203/171 216/209/171 210/207/171 214/205/171 +f 79/89/172 164/92/172 211/202/172 215/208/172 +f 212/203/173 165/96/173 80/95/173 216/209/173 +f 131/164/174 130/175/174 72/210/174 222/211/174 +f 72/210/175 130/175/175 132/165/175 223/212/175 +f 133/162/176 131/164/176 222/211/176 220/213/176 +f 223/212/177 132/165/177 134/163/177 221/214/177 +f 135/159/178 133/162/178 220/213/178 218/215/178 +f 221/214/179 134/163/179 136/161/179 219/216/179 +f 137/160/180 135/159/180 218/215/180 217/217/180 +f 219/216/181 136/161/181 137/160/181 217/217/181 +f 217/217/182 218/215/182 229/218/182 231/219/182 +f 230/220/183 219/216/183 217/217/183 231/219/183 +f 218/215/184 220/213/184 227/221/184 229/218/184 +f 228/222/185 221/214/185 219/216/185 230/220/185 +f 220/213/186 222/211/186 225/223/186 227/221/186 +f 226/224/187 223/212/187 221/214/187 228/222/187 +f 222/211/188 72/210/188 224/225/188 225/223/188 +f 224/225/189 72/210/189 223/212/189 226/224/189 +f 224/225/190 231/219/190 229/218/190 225/223/190 +f 230/220/191 231/219/191 224/225/191 226/224/191 +f 225/223/192 229/218/192 227/221/192 +f 228/222/193 230/220/193 226/224/193 +f 183/157/194 181/151/194 234/226/194 232/227/194 +f 235/228/195 182/153/195 184/158/195 233/229/195 +f 112/154/196 183/157/196 232/227/196 254/230/196 +f 233/229/197 184/158/197 113/155/197 255/231/197 +f 110/131/198 112/154/198 254/230/198 256/232/198 +f 255/231/199 113/155/199 111/134/199 257/233/199 +f 181/151/200 114/149/200 252/234/200 234/226/200 +f 253/235/201 115/150/201 182/153/201 235/228/201 +f 114/149/202 116/147/202 250/236/202 252/234/202 +f 251/237/203 117/148/203 115/150/203 253/235/203 +f 116/147/204 118/145/204 248/238/204 250/236/204 +f 249/239/205 119/146/205 117/148/205 251/237/205 +f 118/145/206 120/143/206 246/240/206 248/238/206 +f 247/241/207 121/144/207 119/146/207 249/239/207 +f 120/143/208 122/141/208 244/242/208 246/240/208 +f 245/243/209 123/142/209 121/144/209 247/241/209 +f 122/141/210 124/139/210 242/244/210 244/242/210 +f 243/245/211 125/140/211 123/142/211 245/243/211 +f 124/139/212 126/137/212 240/246/212 242/244/212 +f 241/247/213 127/138/213 125/140/213 243/245/213 +f 126/137/214 179/135/214 236/248/214 240/246/214 +f 237/249/215 180/136/215 127/138/215 241/247/215 +f 179/135/216 128/132/216 238/250/216 236/248/216 +f 239/251/217 129/133/217 180/136/217 237/249/217 +f 128/132/218 110/131/218 256/232/218 238/250/218 +f 257/233/219 111/134/219 129/133/219 239/251/219 +f 238/250/220 256/232/220 258/252/220 276/253/220 +f 259/254/221 257/233/221 239/251/221 277/255/221 +f 236/248/222 238/250/222 276/253/222 278/256/222 +f 277/255/223 239/251/223 237/249/223 279/257/223 +f 240/246/224 236/248/224 278/256/224 274/258/224 +f 279/257/225 237/249/225 241/247/225 275/259/225 +f 242/244/226 240/246/226 274/258/226 272/260/226 +f 275/259/227 241/247/227 243/245/227 273/261/227 +f 244/242/228 242/244/228 272/260/228 270/262/228 +f 273/261/229 243/245/229 245/243/229 271/263/229 +f 246/240/230 244/242/230 270/262/230 268/264/230 +f 271/263/231 245/243/231 247/241/231 269/265/231 +f 248/238/232 246/240/232 268/264/232 266/266/232 +f 269/265/233 247/241/233 249/239/233 267/267/233 +f 250/236/234 248/238/234 266/266/234 264/268/234 +f 267/267/235 249/239/235 251/237/235 265/269/235 +f 252/234/236 250/236/236 264/268/236 262/270/236 +f 265/269/237 251/237/237 253/235/237 263/271/237 +f 234/226/238 252/234/238 262/270/238 280/272/238 +f 263/271/239 253/235/239 235/228/239 281/273/239 +f 256/232/240 254/230/240 260/274/240 258/252/240 +f 261/275/241 255/231/241 257/233/241 259/254/241 +f 254/230/242 232/227/242 282/276/242 260/274/242 +f 283/277/243 233/229/243 255/231/243 261/275/243 +f 232/227/244 234/226/244 280/272/244 282/276/244 +f 281/273/245 235/228/245 233/229/245 283/277/245 +f 67/129/246 108/125/246 284/278/246 73/279/246 +f 285/280/247 109/128/247 67/129/247 73/279/247 +f 108/125/248 106/121/248 286/281/248 284/278/248 +f 287/282/249 107/124/249 109/128/249 285/280/249 +f 106/121/250 104/117/250 288/283/250 286/281/250 +f 289/284/251 105/120/251 107/124/251 287/282/251 +f 104/117/252 102/113/252 290/285/252 288/283/252 +f 291/286/253 103/116/253 105/120/253 289/284/253 +f 102/113/254 100/109/254 292/287/254 290/285/254 +f 293/288/255 101/112/255 103/116/255 291/286/255 +f 100/109/256 98/105/256 294/289/256 292/287/256 +f 295/290/257 99/108/257 101/112/257 293/288/257 +f 98/105/258 96/101/258 296/291/258 294/289/258 +f 297/292/259 97/104/259 99/108/259 295/290/259 +f 96/101/260 94/97/260 298/293/260 296/291/260 +f 299/294/261 95/100/261 97/104/261 297/292/261 +f 94/97/262 92/90/262 300/295/262 298/293/262 +f 301/296/263 93/94/263 95/100/263 299/294/263 +f 308/297/264 309/298/264 328/299/264 338/300/264 +f 329/301/265 309/302/265 308/303/265 339/304/265 +f 307/305/266 308/297/266 338/300/266 336/306/266 +f 339/304/267 308/303/267 307/307/267 337/308/267 +f 306/309/268 307/305/268 336/306/268 340/310/268 +f 337/308/269 307/307/269 306/309/269 341/311/269 +f 89/67/270 91/70/270 306/309/270 340/310/270 +f 306/309/271 91/70/271 90/72/271 341/311/271 +f 87/73/272 89/67/272 340/310/272 334/312/272 +f 341/311/273 90/72/273 88/76/273 335/313/273 +f 85/77/274 87/73/274 334/312/274 330/314/274 +f 335/313/275 88/76/275 86/80/275 331/315/275 +f 83/81/276 85/77/276 330/314/276 332/316/276 +f 331/315/277 86/80/277 84/84/277 333/317/277 +f 330/314/278 336/306/278 338/300/278 332/316/278 +f 339/304/279 337/308/279 331/315/279 333/317/279 +f 330/314/280 334/312/280 340/310/280 336/306/280 +f 341/311/281 335/313/281 331/315/281 337/308/281 +f 326/318/282 332/316/282 338/300/282 328/299/282 +f 339/304/283 333/317/283 327/319/283 329/301/283 +f 81/85/284 83/81/284 332/316/284 326/318/284 +f 333/317/285 84/84/285 82/88/285 327/319/285 +f 209/206/286 342/320/286 344/321/286 215/208/286 +f 345/322/287 343/323/287 210/207/287 216/209/287 +f 81/85/288 326/318/288 342/320/288 209/206/288 +f 343/323/289 327/319/289 82/88/289 210/207/289 +f 79/89/290 215/208/290 344/321/290 346/324/290 +f 345/322/291 216/209/291 80/95/291 347/325/291 +f 79/89/292 346/324/292 300/295/292 92/90/292 +f 301/296/293 347/325/293 80/95/293 93/94/293 +f 77/326/294 324/327/294 352/328/294 304/329/294 +f 353/330/295 325/331/295 77/332/295 304/333/295 +f 304/329/296 352/328/296 350/334/296 78/335/296 +f 351/336/297 353/330/297 304/333/297 78/337/297 +f 78/335/298 350/334/298 348/338/298 305/339/298 +f 349/340/299 351/336/299 78/337/299 305/341/299 +f 305/339/300 348/338/300 328/299/300 309/298/300 +f 329/301/301 349/340/301 305/341/301 309/302/301 +f 326/318/302 328/299/302 348/338/302 342/320/302 +f 349/340/303 329/301/303 327/319/303 343/323/303 +f 296/291/304 298/293/304 318/342/304 310/343/304 +f 319/344/305 299/294/305 297/292/305 311/345/305 +f 76/346/306 316/347/306 324/327/306 77/326/306 +f 325/331/307 317/348/307 76/349/307 77/332/307 +f 302/350/308 358/351/308 356/352/308 303/353/308 +f 357/354/309 359/355/309 302/356/309 303/357/309 +f 303/353/310 356/352/310 354/358/310 75/359/310 +f 355/360/311 357/354/311 303/357/311 75/361/311 +f 75/359/312 354/358/312 316/347/312 76/346/312 +f 317/348/313 355/360/313 75/361/313 76/349/313 +f 292/362/314 294/289/314 362/363/314 364/364/314 +f 363/365/315 295/290/315 293/366/315 365/367/315 +f 364/364/316 362/363/316 368/368/316 366/369/316 +f 369/370/317 363/365/317 365/367/317 367/371/317 +f 366/369/318 368/368/318 370/372/318 372/373/318 +f 371/374/319 369/370/319 367/371/319 373/375/319 +f 372/373/320 370/372/320 376/376/320 374/377/320 +f 377/378/321 371/374/321 373/375/321 375/379/321 +f 314/380/322 378/381/322 374/377/322 376/376/322 +f 375/379/323 379/382/323 315/383/323 377/378/323 +f 316/347/324 354/358/324 374/377/324 378/381/324 +f 375/379/325 355/360/325 317/348/325 379/382/325 +f 354/358/326 356/352/326 372/373/326 374/377/326 +f 373/375/327 357/354/327 355/360/327 375/379/327 +f 356/352/328 358/351/328 366/369/328 372/373/328 +f 367/371/329 359/355/329 357/354/329 373/375/329 +f 358/351/330 360/384/330 364/364/330 366/369/330 +f 365/367/331 361/385/331 359/355/331 367/371/331 +f 290/386/332 292/362/332 364/364/332 360/384/332 +f 365/367/333 293/366/333 291/387/333 361/385/333 +f 74/388/334 360/384/334 358/351/334 302/350/334 +f 359/355/335 361/385/335 74/389/335 302/356/335 +f 284/390/336 286/391/336 288/392/336 290/386/336 +f 289/393/337 287/394/337 285/395/337 291/387/337 +f 284/390/338 290/386/338 360/384/338 74/388/338 +f 361/385/339 291/387/339 285/395/339 74/389/339 +f 73/396/340 284/390/340 74/388/340 +f 74/389/341 285/395/341 73/397/341 +f 294/289/342 296/291/342 310/343/342 362/363/342 +f 311/345/343 297/292/343 295/290/343 363/365/343 +f 310/343/344 312/398/344 368/368/344 362/363/344 +f 369/370/345 313/399/345 311/345/345 363/365/345 +f 312/398/346 382/400/346 370/372/346 368/368/346 +f 371/374/347 383/401/347 313/399/347 369/370/347 +f 314/380/348 376/376/348 370/372/348 382/400/348 +f 371/374/349 377/378/349 315/383/349 383/401/349 +f 348/338/350 350/334/350 386/402/350 384/403/350 +f 387/404/351 351/336/351 349/340/351 385/405/351 +f 318/342/352 384/403/352 386/402/352 320/406/352 +f 387/404/353 385/405/353 319/344/353 321/407/353 +f 298/293/354 300/295/354 384/403/354 318/342/354 +f 385/405/355 301/296/355 299/294/355 319/344/355 +f 300/295/356 344/321/356 342/320/356 384/403/356 +f 343/323/357 345/322/357 301/296/357 385/405/357 +f 342/320/358 348/338/358 384/403/358 +f 385/405/359 349/340/359 343/323/359 +f 300/295/360 346/324/360 344/321/360 +f 345/322/361 347/325/361 301/296/361 +f 314/380/362 322/408/362 380/409/362 378/381/362 +f 381/410/363 323/411/363 315/383/363 379/382/363 +f 316/347/364 378/381/364 380/409/364 324/327/364 +f 381/410/365 379/382/365 317/348/365 325/331/365 +f 320/406/366 386/402/366 380/409/366 322/408/366 +f 381/410/367 387/404/367 321/407/367 323/411/367 +f 350/334/368 352/328/368 380/409/368 386/402/368 +f 381/410/369 353/330/369 351/336/369 387/404/369 +f 324/327/370 380/409/370 352/328/370 +f 353/330/371 381/410/371 325/331/371 +f 400/412/372 388/413/372 414/414/372 402/415/372 +f 415/416/373 389/417/373 401/418/373 403/419/373 +f 400/412/374 402/415/374 404/420/374 398/421/374 +f 405/422/375 403/419/375 401/418/375 399/423/375 +f 398/421/376 404/420/376 406/424/376 396/425/376 +f 407/426/377 405/422/377 399/423/377 397/427/377 +f 396/425/378 406/424/378 408/428/378 394/429/378 +f 409/430/379 407/426/379 397/427/379 395/431/379 +f 394/429/380 408/428/380 410/432/380 392/433/380 +f 411/434/381 409/430/381 395/431/381 393/435/381 +f 392/433/382 410/432/382 412/436/382 390/437/382 +f 413/438/383 411/434/383 393/435/383 391/439/383 +f 410/432/384 420/440/384 418/441/384 412/436/384 +f 419/442/385 421/443/385 411/434/385 413/438/385 +f 408/428/386 422/444/386 420/440/386 410/432/386 +f 421/443/387 423/445/387 409/430/387 411/434/387 +f 406/424/388 424/446/388 422/444/388 408/428/388 +f 423/445/389 425/447/389 407/426/389 409/430/389 +f 404/420/390 426/448/390 424/446/390 406/424/390 +f 425/447/391 427/449/391 405/422/391 407/426/391 +f 402/415/392 428/450/392 426/448/392 404/420/392 +f 427/449/393 429/451/393 403/419/393 405/422/393 +f 402/415/394 414/414/394 416/452/394 428/450/394 +f 417/453/395 415/416/395 403/419/395 429/451/395 +f 318/342/396 320/406/396 444/454/396 442/455/396 +f 445/456/397 321/407/397 319/344/397 443/457/397 +f 320/458/398 390/437/398 412/436/398 444/459/398 +f 413/438/399 391/439/399 321/460/399 445/461/399 +f 310/343/400 318/342/400 442/455/400 312/398/400 +f 443/457/401 319/344/401 311/345/401 313/399/401 +f 382/462/402 430/463/402 414/414/402 388/413/402 +f 415/416/403 431/464/403 383/465/403 389/417/403 +f 412/436/404 418/441/404 440/466/404 444/459/404 +f 441/467/405 419/442/405 413/438/405 445/461/405 +f 438/468/406 446/469/406 444/459/406 440/466/406 +f 445/461/407 447/470/407 439/471/407 441/467/407 +f 434/472/408 446/469/408 438/468/408 436/473/408 +f 439/471/409 447/470/409 435/474/409 437/475/409 +f 432/476/410 448/477/410 446/469/410 434/472/410 +f 447/470/411 449/478/411 433/479/411 435/474/411 +f 430/463/412 448/477/412 432/476/412 450/480/412 +f 433/479/413 449/478/413 431/464/413 451/481/413 +f 414/414/414 430/463/414 450/480/414 416/452/414 +f 451/481/415 431/464/415 415/416/415 417/453/415 +f 312/398/416 448/482/416 430/483/416 382/400/416 +f 431/484/417 449/485/417 313/399/417 383/401/417 +f 312/398/418 442/455/418 446/486/418 448/482/418 +f 447/487/419 443/457/419 313/399/419 449/485/419 +f 442/455/420 444/454/420 446/486/420 +f 447/487/421 445/456/421 443/457/421 +f 416/452/422 450/480/422 452/488/422 476/489/422 +f 453/490/423 451/481/423 417/453/423 477/491/423 +f 450/480/424 432/476/424 462/492/424 452/488/424 +f 463/493/425 433/479/425 451/481/425 453/490/425 +f 432/476/426 434/472/426 460/494/426 462/492/426 +f 461/495/427 435/474/427 433/479/427 463/493/427 +f 434/472/428 436/473/428 458/496/428 460/494/428 +f 459/497/429 437/475/429 435/474/429 461/495/429 +f 436/473/430 438/468/430 456/498/430 458/496/430 +f 457/499/431 439/471/431 437/475/431 459/497/431 +f 438/468/432 440/466/432 454/500/432 456/498/432 +f 455/501/433 441/467/433 439/471/433 457/499/433 +f 440/466/434 418/441/434 474/502/434 454/500/434 +f 475/503/435 419/442/435 441/467/435 455/501/435 +f 428/450/436 416/452/436 476/489/436 464/504/436 +f 477/491/437 417/453/437 429/451/437 465/505/437 +f 426/448/438 428/450/438 464/504/438 466/506/438 +f 465/505/439 429/451/439 427/449/439 467/507/439 +f 424/446/440 426/448/440 466/506/440 468/508/440 +f 467/507/441 427/449/441 425/447/441 469/509/441 +f 422/444/442 424/446/442 468/508/442 470/510/442 +f 469/509/443 425/447/443 423/445/443 471/511/443 +f 420/440/444 422/444/444 470/510/444 472/512/444 +f 471/511/445 423/445/445 421/443/445 473/513/445 +f 418/441/446 420/440/446 472/512/446 474/502/446 +f 473/513/447 421/443/447 419/442/447 475/503/447 +f 458/496/448 456/498/448 480/514/448 478/515/448 +f 481/516/449 457/499/449 459/497/449 479/517/449 +f 478/515/450 480/514/450 482/518/450 484/519/450 +f 483/520/451 481/516/451 479/517/451 485/521/451 +f 484/519/452 482/518/452 488/522/452 486/523/452 +f 489/524/453 483/520/453 485/521/453 487/525/453 +f 486/523/454 488/522/454 490/526/454 492/527/454 +f 491/528/455 489/524/455 487/525/455 493/529/455 +f 464/504/456 476/489/456 486/523/456 492/527/456 +f 487/525/457 477/491/457 465/505/457 493/529/457 +f 452/488/458 484/519/458 486/523/458 476/489/458 +f 487/525/459 485/521/459 453/490/459 477/491/459 +f 452/488/460 462/492/460 478/515/460 484/519/460 +f 479/517/461 463/493/461 453/490/461 485/521/461 +f 458/496/462 478/515/462 462/492/462 460/494/462 +f 463/493/463 479/517/463 459/497/463 461/495/463 +f 454/500/464 474/502/464 480/514/464 456/498/464 +f 481/516/465 475/503/465 455/501/465 457/499/465 +f 472/512/466 482/518/466 480/514/466 474/502/466 +f 481/516/467 483/520/467 473/513/467 475/503/467 +f 470/510/468 488/522/468 482/518/468 472/512/468 +f 483/520/469 489/524/469 471/511/469 473/513/469 +f 468/508/470 490/526/470 488/522/470 470/510/470 +f 489/524/471 491/528/471 469/509/471 471/511/471 +f 466/506/472 492/527/472 490/526/472 468/508/472 +f 491/528/473 493/529/473 467/507/473 469/509/473 +f 464/504/474 492/527/474 466/506/474 +f 467/507/475 493/529/475 465/505/475 +f 392/433/476 390/437/476 504/530/476 502/531/476 +f 505/532/477 391/439/477 393/435/477 503/533/477 +f 394/429/478 392/433/478 502/531/478 500/534/478 +f 503/533/479 393/435/479 395/431/479 501/535/479 +f 396/425/480 394/429/480 500/534/480 498/536/480 +f 501/535/481 395/431/481 397/427/481 499/537/481 +f 398/538/482 396/425/482 498/536/482 496/539/482 +f 499/537/483 397/427/483 399/540/483 497/541/483 +f 400/542/484 398/538/484 496/539/484 494/543/484 +f 497/541/485 399/540/485 401/544/485 495/545/485 +f 388/546/486 400/542/486 494/543/486 506/547/486 +f 495/545/487 401/544/487 389/548/487 507/549/487 +f 494/543/488 502/531/488 504/530/488 506/547/488 +f 505/532/489 503/533/489 495/545/489 507/549/489 +f 494/543/490 496/539/490 500/534/490 502/531/490 +f 501/535/491 497/541/491 495/545/491 503/533/491 +f 496/539/492 498/536/492 500/534/492 +f 501/535/493 499/537/493 497/541/493 +f 314/380/494 382/400/494 388/550/494 506/551/494 +f 389/548/495 383/552/495 315/553/495 507/549/495 +f 314/554/496 506/547/496 504/530/496 322/555/496 +f 505/532/497 507/549/497 315/553/497 323/556/497 +f 320/458/498 322/555/498 504/530/498 390/437/498 +f 505/532/499 323/556/499 321/460/499 391/439/499 diff --git a/apps/typegpu-docs/src/examples/react/3d-monkey/index.html b/apps/typegpu-docs/src/examples/react/3d-monkey/index.html new file mode 100644 index 000000000..b8b02d5f5 --- /dev/null +++ b/apps/typegpu-docs/src/examples/react/3d-monkey/index.html @@ -0,0 +1,2 @@ + + diff --git a/apps/typegpu-docs/src/examples/react/3d-monkey/index.tsx b/apps/typegpu-docs/src/examples/react/3d-monkey/index.tsx new file mode 100644 index 000000000..f533ca327 --- /dev/null +++ b/apps/typegpu-docs/src/examples/react/3d-monkey/index.tsx @@ -0,0 +1,103 @@ +import tgpu from 'typegpu'; +import * as d from 'typegpu/data'; +import * as m from 'wgpu-matrix'; +import { fragmentShader, vertexShader } from './render.ts'; +import { loadModel } from './load-model.ts'; +import { bindGroupLayout, modelVertexLayout, Uniforms } from './schemas.ts'; + +// setup + +const canvas = document.querySelector('canvas') as HTMLCanvasElement; +const context = canvas.getContext('webgpu') as GPUCanvasContext; +const presentationFormat = navigator.gpu.getPreferredCanvasFormat(); +const root = await tgpu.init(); + +context.configure({ + device: root.device, + format: presentationFormat, + alphaMode: 'premultiplied', +}); + +// models + +const monkeyModel = await loadModel( + root, + '/TypeGPU/assets/3d-monkey/monkey.obj', +); + +// buffers + +const uniformsBuffer = root.createBuffer(Uniforms).$usage('uniform'); + +// bind groups + +const bindGroup = root.createBindGroup(bindGroupLayout, { + uniforms: uniformsBuffer, +}); + +// pipelines + +const renderPipeline = root['~unstable'] + .withVertex(vertexShader, modelVertexLayout.attrib) + .withFragment(fragmentShader, { format: presentationFormat }) + .withDepthStencil({ + format: 'depth24plus', + depthWriteEnabled: true, + depthCompare: 'less', + }) + .createPipeline(); + +const depthTexture = root.device.createTexture({ + size: [canvas.width, canvas.height], + format: 'depth24plus', + usage: GPUTextureUsage.RENDER_ATTACHMENT, +}); + +// frame + +function frame(time: DOMHighResTimeStamp) { + const modelMatrix = m.mat4.rotationY(time / 1000, d.mat4x4f()); + m.mat4.scale(modelMatrix, [0.5, 0.5, 0.5], modelMatrix); // optional scaling + + const viewMatrix = m.mat4.lookAt([0, 0, -3], [0, 0, 0], [0, 1, 0]); + const projectionMatrix = m.mat4.perspective( + Math.PI / 4, + canvas.clientWidth / canvas.clientHeight, + 0.1, + 100, + ); + const viewProjectionMatrix = m.mat4.multiply( + projectionMatrix, + viewMatrix, + d.mat4x4f(), + ); + + const clearColor = [0.1, 0.2, 0.3, 1.0]; + + uniformsBuffer.write({ + modelMatrix, + viewProjectionMatrix, + }); + + renderPipeline + .withColorAttachment({ + view: context.getCurrentTexture().createView(), + clearValue: clearColor, + loadOp: 'clear', + storeOp: 'store', + }) + .withDepthStencilAttachment({ + view: depthTexture.createView(), + depthClearValue: 1.0, + depthLoadOp: 'clear', + depthStoreOp: 'store', + }) + .with(modelVertexLayout, monkeyModel.vertexBuffer) + .with(bindGroupLayout, bindGroup) + .draw(monkeyModel.polygonCount, 1); // 1 instance + + root['~unstable'].flush(); + requestAnimationFrame(frame); +} + +requestAnimationFrame(frame); diff --git a/apps/typegpu-docs/src/examples/react/3d-monkey/load-model.ts b/apps/typegpu-docs/src/examples/react/3d-monkey/load-model.ts new file mode 100644 index 000000000..8f7f367d4 --- /dev/null +++ b/apps/typegpu-docs/src/examples/react/3d-monkey/load-model.ts @@ -0,0 +1,46 @@ +import { load } from '@loaders.gl/core'; +import { OBJLoader } from '@loaders.gl/obj'; +import type { TgpuRoot } from 'typegpu'; +import * as d from 'typegpu/data'; +import { modelVertexLayout } from './schemas.ts'; + +export async function loadModel( + root: TgpuRoot, + modelPath: string, +) { + const modelMesh = await load(modelPath, OBJLoader); + const polygonCount = modelMesh.attributes.POSITION.value.length / 3; + + const vertexBuffer = root + .createBuffer(modelVertexLayout.schemaForCount(polygonCount)) + .$usage('vertex') + .$name(`model vertices of ${modelPath}`); + + const modelVertices = []; + for (let i = 0; i < polygonCount; i++) { + modelVertices.push({ + modelPosition: d.vec3f( + modelMesh.attributes.POSITION.value[3 * i], + modelMesh.attributes.POSITION.value[3 * i + 1], + modelMesh.attributes.POSITION.value[3 * i + 2], + ), + modelNormal: d.vec3f( + modelMesh.attributes.NORMAL.value[3 * i], + modelMesh.attributes.NORMAL.value[3 * i + 1], + modelMesh.attributes.NORMAL.value[3 * i + 2], + ), + textureUV: d.vec2f( + modelMesh.attributes.TEXCOORD_0.value[2 * i], + 1 - modelMesh.attributes.TEXCOORD_0.value[2 * i + 1], + ), + }); + } + modelVertices.reverse(); + + vertexBuffer.write(modelVertices); + + return { + vertexBuffer, + polygonCount, + }; +} diff --git a/apps/typegpu-docs/src/examples/react/3d-monkey/meta.json b/apps/typegpu-docs/src/examples/react/3d-monkey/meta.json new file mode 100644 index 000000000..976f106c6 --- /dev/null +++ b/apps/typegpu-docs/src/examples/react/3d-monkey/meta.json @@ -0,0 +1,5 @@ +{ + "title": "React: 3D Monkey", + "category": "react", + "tags": ["experimental"] +} diff --git a/apps/typegpu-docs/src/examples/react/3d-monkey/render.ts b/apps/typegpu-docs/src/examples/react/3d-monkey/render.ts new file mode 100644 index 000000000..263a1f40d --- /dev/null +++ b/apps/typegpu-docs/src/examples/react/3d-monkey/render.ts @@ -0,0 +1,52 @@ +import tgpu from 'typegpu'; +import * as d from 'typegpu/data'; +import * as std from 'typegpu/std'; +import { + bindGroupLayout, + ModelVertexInput, + ModelVertexOutput, +} from './schemas.ts'; + +export const vertexShader = tgpu['~unstable'].vertexFn({ + in: ModelVertexInput, + out: ModelVertexOutput, +})((input) => { + const worldPosition = std.mul( + bindGroupLayout.$.uniforms.modelMatrix, + d.vec4f(input.modelPosition, 1.0), + ); + const canvasPosition = std.mul( + bindGroupLayout.$.uniforms.viewProjectionMatrix, + worldPosition, + ); + + const worldNormal = std.normalize( + std.mul( + bindGroupLayout.$.uniforms.modelMatrix, + d.vec4f(input.modelNormal, 0.0), + ).xyz, + ); + + return { + canvasPosition: canvasPosition, + worldNormal: worldNormal, + }; +}); + +export const fragmentShader = tgpu['~unstable'].fragmentFn({ + in: ModelVertexOutput, + out: d.vec4f, +})((input) => { + const baseColor = d.vec3f(1.0, 0.5, 0.2); // monkey color - orange + const lightDirection = std.normalize(d.vec3f(0.5, 0.5, -1.0)); + const ambientLight = 0.2; + + const diffuseStrength = std.max( + std.dot(input.worldNormal, lightDirection), + 0.0, + ); + const finalLight = ambientLight + diffuseStrength * (1.0 - ambientLight); + const finalColor = std.mul(finalLight, baseColor); + + return d.vec4f(finalColor, 1.0); +}); diff --git a/apps/typegpu-docs/src/examples/react/3d-monkey/schemas.ts b/apps/typegpu-docs/src/examples/react/3d-monkey/schemas.ts new file mode 100644 index 000000000..4c75d0023 --- /dev/null +++ b/apps/typegpu-docs/src/examples/react/3d-monkey/schemas.ts @@ -0,0 +1,26 @@ +import tgpu from 'typegpu'; +import * as d from 'typegpu/data'; + +export const ModelVertexInput = { + modelPosition: d.vec3f, + modelNormal: d.vec3f, + textureUV: d.vec2f, // field can be removed +} as const; + +export const ModelVertexOutput = { + canvasPosition: d.builtin.position, + worldNormal: d.vec3f, +} as const; + +export const Uniforms = d.struct({ + viewProjectionMatrix: d.mat4x4f, + modelMatrix: d.mat4x4f, +}); + +export const modelVertexLayout = tgpu.vertexLayout((n: number) => + d.arrayOf(d.struct(ModelVertexInput), n) +); + +export const bindGroupLayout = tgpu.bindGroupLayout({ + uniforms: { uniform: Uniforms }, +}); diff --git a/apps/typegpu-docs/src/examples/react/3d-monkey/thumbnail.png b/apps/typegpu-docs/src/examples/react/3d-monkey/thumbnail.png new file mode 100644 index 0000000000000000000000000000000000000000..889b2f297ba683488ec1634279f09728f080fc21 GIT binary patch literal 185059 zcmeFa2{e^!8$bNmaYCm7MUhBoGNcU2v^yD+P&6nRN`slqGN03_%$*8_P%2HR%=7M4 zoXU_0nMHO|4hy>3Slc>oaZ?haJ+TG8M;}WH z3DO>MvQiQ<(B37u&CcPNpsd6Oi48)^?1F-ViVjDQZ_!g#pMD*FQW7$Eac-NbDjS4|D_Z5-8Oj%E%P_D&Xdwt{Hf z!$<6#os@)x&_sX#nOf&DH;eBx**Z>d3pOZ;ej_O*u|e|hvEfxk^y!ve7H-F^52#w$ z0L@?y<&7I;HY(Cy_~BRIr=)w;fc{nK&GfI*{fhC`y^hBmw%OUhq)y7;88-bg{V%6q zRFp(}r=!Ibp=qB2rIpzgCI9A{GJ98Ab_OtVxrM6k9{36(hyF05uWP2h!uL!hp{H8~ z7ZL=S&{W;J$Bn78_ThX&aM2v88Xp78b?0k-y?DiUv&r$Kw6b2-MS^5sc!T*redCwR za*K&lJu#yAUml|U%8m3BvB2-YjfEa#X8xHVi3I%jN#VhtiTZyUY7r~zQi6HM;(wfT zDUtb4ix*t9Xam7|X$|S09^63K&-stUntoYO(3DuTW;gSHrs~v#rbP2k|B3G3)O2ew=FmIOk7qMCvrax;d^YRkPie?(6!|?qn~fr;X)&9o_?`fmO;b$M zVm3`No2K|4lh39pzC*+`YR;x9X44ekA!1rQX44e2X^J0Eb2d#eo2K}l$($CC*)+v$ zn&O9=>1>)}Hcdg7-==}aY?@*=O+lB*oDz@OG{tP1;(I1@T0CaEDQ43YvuTPSV)EHE z#SbKzO;gOKDQ43YKg8s-X^J06GMlEDO;gOKDHvn&X@`5Zo8o&6GMlEDO;gOKDZc9i zPK()YitjPVY?@*=O);CM_^uB)EoKjWe2+n9(-gC5irF;9cYVNUF?;A^_Rt6JWP*77 z-+1UFn6!8Ax4Qu7t>SD%IU7;_AmFow@7col4?*^9L^&H#;!zZ&tY`c4r`^Tbi1ND! zJsVNZMwD0-g&d68{`~)&3*VGuJv!A#i_(5t+0)~$)3EAQv9#m1O>(bfcC~N39J#Ff zp=f&aol8#+zdRUlsp6emi^ki-lG@3a3aV;%e=lqTAgY?PO|!iO=od-8C3oC&esZlJDv!a>Z(VPad$-!PB`6pH?s0Mc4;> zrLyDY&+b{7-TZawfcGxeG0=N5j!-fGrEf}eJkdmBdoWU*I~<7MhI5$p^iSZDlRY;MBOj`~8fz-#>FJWa8^VSfXhbAxc;~X&O-2R+8{+#+q#iuD}9jS)vOANMtR>iY0V|&f& z6k(jGd;Q#*$m~JfOydOwle@Z_v@qg=gpR}3N((fOZ^yRAe3$g{gU^C}GZ4^Nssh%L|W9(&~ls(Z;y6r5S)p0ONc zCpfoSarl}rWe)p2RKyoCv&e<99Q@xzj>*sG>r1;5ptfV`VkXeM`>hO`7o$aHqBwR% zyyc|V2*OWOP=wl_AaWT>G?E1 zHqIsaW`%oTTNCVE4vdO1i!Hu@Gv1RG^l9Xov7Sm%Ylm^JkgwPeYu$#{+IjH+!&(<2 z#ajFzqLTXY!^AD_WWw}Ls{+2-%^AQp$DYu)3{uMHckqkK+^P$s^2faspRFfd*2-dl z%64v0=I#k8M(A1fN{=|tTX|trjz8b$ZNPrw!L8P143j3HNxK6NFifi8SM|ZiHZ!cU ztS6#6(M^reTHA!FsV_yIWib)$Xi^-2)2NuDDFvf1?JD}ym?tcMd;7#ZDh+1dv@3%Fa&G{4bh4#xso`vGBV`eS zN`_jm%FL>}<88wG*omq=N~>@kZRZ49B~5JL!#QrhdV}s{d&Em-FK^=<^*XVZB}|o0 zc?|EGNCN(K3{if@mrdSlnn(!B7>ItncQv;lDE&&&dcvH80l%2@bzslcZ~3m^r08U~ z7NI&masO3Wr4A-8hKV~rozlg3_8;HvTteJf(8e~}u%KzqbsGne<$Z@wGEmD6l%Obz z?+<)lX|_~hs-uSd*4ToKL-FvckT189)W3XHm7UN#E5Eg=a>Qd-sx}DLA`WgXe90kP zKc3Y&FNqOY*m)F=hS-H$hgqLgp=287BhWlILTlT+mX8w z;@4DEg$~4l$}scFP_h!LBE3r>0AG%$zXou{1QL-4El=>#P?Z5 zZ|74Z+)pr?$7--Y!=p+Y=KL_{e&Rf7729ac@OC~HLi6QWoOjU(WaI}Qi{ZqjWQ2e4 zIj;Ak86o_{;s`;lOa@Gn8aHEMDEdoovq%idJESwNu(*Qp>QWJy+m#PjVwWIceK#VENfTXl7CExooG{d&%i6s zV4!F6Nx5}6nTHo$UQO+PQm#2+PPH)hpz+X=frlomU{c{G;38pgVdP;o-OaNk;axRXus+~*m&92_=}_ElNGs^Xx^)g^A;gLqOtxQ z{a(S^Z!=9M1X-#$y9M}5Y}JdZ(X{Ctwz$Yrki;(dNp3m5-M>iU&#B85w%ifuQYo>z z7cAtPYsKjA8X(0!#TSeVhbJr2&iF*w?b*Pn@;*aHJ>o$Ps|mxjThX+?%KnT`dwJeC zU%@!H&c}p7+Kw~YZm^o>*L5?zECnxzoRnq9U(V#%4raCg0NYShDUZo@Gu4*rs%wPl zL$-Vd!J7ka;c{PVR-Dosc>V&nt8)`)cUE$ul~a(pC$H;Ubq-3Et(y*xErs9}Ep55G zAAkSB+6Q99cE6V&Mvk|<4K#7{no40jp#uH3br*uJ%#*-JO-lwJA3y|6S>Bbh!^JXI1kvyJLI~QxlCCHW!$Hn z9BX%11DDs{JfeB1hu!C@=sV@63%fNZ6xFq;?8KvRhIn;Y5xsum&T9Pi4Q#m}*k`~+ zewe$CWDqdSpu;P`Kj^(2TZMD2S*JOj5X{@hY=8FagdfRQW=R=tC~l?XNOi!_og9?;RYQ{OM7R*6N$`fPO}HFn zU=yF;DVS^>Og3_t^+&T>1n8#NmLS7Grf9hNo5qm@@I>QqihTs{R%`p zu1SX>Lfyc2?;hew<*j=i8;@(3R4YJW8(ZT)fegpB*r<(Uv?9_ zR74sXsHOz8^!TNb0YU;O8vz8CFdg+Db^dgNHLkl=9H-lDwl&14-BC*|`8XWothjMC3o(|U%8UuGKQ7 z!dxFUV&p5Mn}lTNa)dc9-n}bPZ1rpV^RCdsH&N9Rq+P@=rRBy9d)9_MM@btqfP@W- zt-7}YPj8!~ASz#Eq_Q?pIWph`&Q(*5=BAO>q27Ydvgch_lTIX?3`G!&iQ*7H1_SqM z4e*v@$5MR9f6)?7@WWRwn37@IAQ|9`mlDui?1YQVh;lu}nRK zbnv67xl$~$KBTbVy(IkKA~o{ojTxS~0_<6KhJggTxDb1D%=J`wVSic-K+8nZ0>)@@ zFh;az$XXC#@M?e7Xfa7dPO^(-orfES61LN)*-NtX?^l_cz1mL5|jW5o72XDQ{DhUmtC=t(>%CcMs!@Ww4h>DhzOoueg))YxA$Vwb1GkRw^z9d3}A>I{Zo@|KqiH*50 z62o)N)no}%{U7(0&($VD3drE*z#s(mk^X&3(V#-0uM)8(iHD_5z;tSaSv+FKA zX-0+X0Z>ojyh#SgXkOyl5Q#~A4=gDGlRsPN+lnoo%u%yrvi+RWB9TQ*mg79KY2KE^8`$9 z?QjYYTO@^mc51S<8*#=N3IbA}i+S4bQr2O&nCX6wSgiWcd+PYW*<(D6PEG_E$X>lV zn}?VhK3I(6?Hu#>^1QKy;6$W#RNqbnTa|#@DtjA%w(3TcdzjDa$M2U0z%3l<7E-8d zHvXja19x&f#Df)gdZS^yPt)S;qSqey!kV@KuP&es&LtiA{l}THlP2HF63Km zl&3!U3kNyuHSW1&J^(8)&o1dE##^!xionxCgkwD3C&&g6oKLzFoFx|%oqFt;n)?N^ z0~0?M9^}Sgw~__Pz}c#&j&`1wLlH3h{=D>Vz`k|y5g4uPcLNc48Vp|IqLEF$K?n|1 zM!J>8tG6UTrt4__=d@>#xet5Au=?Au`as+J$FS8?(kTVh{+^1L;i_M9Bg*?M#0r=< z@HFMyy`85<)Oj~zUIj%4iLs+eBA$(1hf<=yrwU(aHwq4kZTk>Gw0(#g^6-EV@nR{S z>dKsX5!n>Qk=Rv(oX_PYOf-rTPJ(||m1Hu6n9xv$TiwiX*oIYC!W(>LA(Vq)RUbuc zH+E6j;vIR>gkeYu1^Jae(|!OBHziS0(#A{XSc z1y;~jVcplHXi}%ZLddD+|C?0=P<(npCL+?F+WTi0C>VN1UNa$OHYKF3w(>||HPwEB zo3zXez>@V{x6<&j?;^V(SjknNO`_dDmvEAsEj+d?NbDi?$R+h;?T30seW`=9m_OSqqKYCL@F;fh5_q+ zNMN5ocEqi`v%BN%`vjR`5#JoIgB}~2fFxGG#NZ0C7nKu_txo(6qcyk{7pU^~F-uF! zEUQzVC1j0?_|}Gmx%TJjGw(W7j}I|(Me;bw0|G&(n58i?4Y^8&F06p z0k?E7?v_%*&@wFK5`V{*p^Pks{N~kX`iJshD;1s-oRr3-yu32tOI(Q-?n^610AJc` zB~!4>gP*$Jb|&)YjjPY_<)|3ZR`Dv;%OZIRA-$Uo$ClM7d_Kx|JR1X|2a>%4lj9zn zx5l2@%lyEOPiDtml;h|(UQeoNvg5#>?L7p#7GqUVjC+i{%z8}ZQB|(zN;cQcfUqP{Mh3yqQC(z0M0qU7SqV*`1mhw#3Y8UhQQ1ZZC*0>if zA{fLfBJX{5-G&OB4%w7PgrJ%R*Vk{0h+`F$+M~iw+*QOwEXqX)58WQk-(-ZzRSma+ z)@1uf^FNi+0@LLYKOwMVwKhg>h#PJ|bs^MgelA<=gaMJMVH~9W531oSu=ZX|{M!MH zOeIHR4b`~1?--?)AjyWPTEi4*U>f#p8@5=tjbJ@=(+}UmD<~bbtdFzw)}{*4ErlP4 zE#@Nw_F038vM%r}#)jUbh?CY&c1Bnh+(hiuq?H z{|zAmXqnw$(Wj^q^Iaf|i}rF*=KhYGkN?07H6#w#)mPVtE^RpvtXy;U^Vn6AFW&+a z+=KB)`cQuS3SPWe?3ee!Cqz-$FJ`V)Zb*!NDpk6x06?-cM(D>OG|>>x)vt(Ric-&> z%1zwZSAN<}dh(pqb;p20npQ2n6-xS{Ri#WASb4?eC7w(*osa7zE_Y=sVFB`k&&BWs9a~{A_h20-)*z{!X+n@}Wzwh5T7bOWk6p-PsDEWBWEtR^d^p4eh$wR2ArOhW8FU~aI2Q@0q z-qeP>Py(bspq{^2+deczx1U$3@Z;nZA{8?vC8ANL|5N(Y)0kYFuI<(Jo>Yof)b$F| zIj1qE(h{9r)q7oy@MbX`iTH#!GDM^7)mxXRp4bqOlZ+i7FB%&v_>*m-azkYE3VvXr zTD2lDk$i+Pot=Q(g}YrFmSHGkze?+4M4`Kb9lAu)%T;#zXQR(>!qLud~Lz z*%(}goHaU=?QM_-d)g?2-cRT=>4F>{Q|Hw! zc)6!}J)nT+@7YqA0GsYNEg%G)!RzJuq9i!IfL{ujAz3%@fnfow&;st*;69r%u>ohj6%5OR$wU9$v(bXh1xgKG^n8rL2=rVq)&3( z?_>9`h4kkl6~2SGmx=0=W?ln$s${F*rSY;@gD(d-$S!p`g@>TeLJ{>^m8zOq72}fjr*V;JE>WtSNVBH58@9&U@ls+!G{%I<|O+<>h&(#Bg6^Z+}jjl^Aqw zMZT*|xonlXw8iG>y~!R>hWl67;6`=?<+3PS!g%M z_#rD0{l(!g=PETyOo;Gb%vuE}oN`pGVh zIUx;aGs>a&r|Vb7;>t`J^`(NS{BVXp%5xv{tL!v05JT?$>rmHb;%Y6tmB8~B2xnPk zB@ZSB(EcMzbv*IUo3De-r`zOWqtAaUH1gLe%Do?prMq;wSswfETU{ch^ zpjA*5^?!wzt2$Wn*l-1gu68dfTbtjusdR1nLJO9r>O|J&`G5LgulSOG1Iqp+yb||8 zeAtZfLzZ4!)7#e*ZNRtf<2H6OO%#+)mT^^X713Lk!&%$qu+0T4_ z=y(sWV{lJhYIOiHnEn`lT(B3C-rMN2l1!wttf)0ilNQGvFX9uHo&bDV^0NY(X^7;sRM znpU!XZ8%W>QxMHJ&nY0Cum~tHdflBd96cDQI?hg!$iX|A+{gekbKD{^On`JFq|5)% z*ONJ)8NB*%3-!99Y@zoBxnyVW;9#j!^X)b%)J0$K*Sxojd4tL^2Dj}EtTA_#?SVJF zB>cSC0CLz*wEd0Mh@3Ap=if}y<%Aw-Dl}iTSxe)-{MFvt>vo%RL^W{4Q|Wn5wASPbz9*8%Ds`kxaQcE%#6N&LMW?_i z`Fh&|clL8o?&QvIYnK6bRy#PAQ;Li`OK&jKNNF+OFU9F;q!rCYi579iHN_o-PPt4^ z7yne^)rIjggQ-%X_Bm+N_*gD`A~3cpjy2Bvd@gQbv{3T>>)=5Q@$%IL0UM8R7P&CT zzs~&qh*=P!Vf`~z!FONnWvkpZhif}12Y7vC8`TXAGfbGwm1N#y6pGsmwX1uVHq-NA zkvZpZna`+MfT5OK)t1Ze(ZE!T&M8^0oh)s7cBo}cw#&I$OuMh2O}1X6`ux6!Rq7n% zIq8e=aiCN8)lLz-)^Ly+8XE(QVCd25p&K0UYLB)xoVqY1dbCx`i67#X#Trxb3XPzE z0?=XPj&~Rhi-DPp6}iLksjTkgiI5~!JHeBD&`P$xR+JkmqCFFhGHtv~85YTNK-8O} zzP|Tzf>4Ot7jM;~Bmg`O@6owR?^raau|PlFh3(RsTb|A3%qXACX|K%919$Mwbq}84 z*ugFK;f1lm860gL$Q&i8Va#Fe1bgs9M|~tp;brwHzPl3pCQ09uw$xyLz+ot9)-{df zT(ea zEJp)&Gr!ugL_)&c@Y`Jg4LRoHsnq~S&oXo-l_ZoC9F!Lm%nyIZK!b7@0BJ8bp0pMe zLJ~WncJapa%4tM4xsdxdu9cV1>??2ManE#lwf2kq`t~CMvD31fwDZ(y^#oKt&W-mN z@qtRnnkr&_Dt<1ste{M!@YN~7YjCs_U8mXDCYqDMlk>W@wrW75@}rdcP%QU#)@Cz>2Fzeneh1Y* zWWGrp%XyltJP(bPt0PmpEH(wdiy%aMYJIMIa0K@>=G5Nc>6yw>utwipRTVuMF!?N5 zMNAlX5t&Fc`c}UPLg}d`N!Z%9-tB53tFZ0DDE*dk{R=~$j$0o1#=l*woFGw6Ij}=N zG=w8qchwpa>vGO(__k3e=$R)xnDU)t6@&1h&h5`ljmLRcozGOV)+urOTW(9O5pxnR z`h*6Seli&!&1h!*6Sw!2D5%n|#;dg1%vB({@#cSS0vmbd8-HG~=0LYjj%p86d0t>) z!r@7F5Zy^H+r$WHR%1$i5r8>3ekf99>{&9WB^z|Evz5ijRxI^<+I85`a^D^#wMbH( zCP^pmjOEHo7%-7nUD|+cGm`_H-6!wnVg6n!YbP{B2pDPB)Mxf>3Fg>dzd|;la3n#` zzrW-Yg%ol;VK_Sb(3}%%wUxH03mbEgo9$U~tkonl`TmBh)?r%j;Ys0lS5|Y{Y?=ZC zk17tnZ5-srF^Fx_`o~#HU;mW?)utY4H@v5PrVfm_b-gB&Uo|#EyISonHr2YFeSS}E zQmNhYdu7@smoOE}SPs$X`H+g}nJ@b;%r((bkNLr`?RdY0HNt@#eZOLUUllE}ohrJ) zQJ{RdTZ-gg_oVF-hf8t*;o{#o2SJzaljv&@K9D>77vZit+PWjY^%9iX;j@t1v@ZERqZb{bxNQ8zQ{a zTXKqMYFWW))(?%F+L6x!KQ^khRM?x06wHBss~UT}-`Et4>JJ&;4LmiFji@o#lYtVm zKWGp1Vv5)1x@6f7rcWOEx-@=F_a1OJKO+X;qdZ_yw3$FL#@_^Pb8%vO;AUYqzRF0{ zwY_S3VRZB^jQS)7WMf)=*G;6Xf*U<>=Lw;#rvCLH}BnOdg2%J0h9 z!5rYR7oEB!`rTLV*COtTtzQ_AdV~exV<#7Zq-eom#}B=ylEmHQUy=l`|jj zKGDJ3r82YkQq4cQR`yLHEP8cZD!&y4& z#J!^p9>|t_51jxaJ%m!!4?0uy^N`(w1KXO#ZZ1=ybpv`xU_vruo6Cb$C^1_iplRBs zY*}qiy_0MnwN@Ei_`xQn1m5Bjg#zfm*ge7txa-L~`WIsNuD907|Ga$}8a!(Jy-G`s zBd1(z^Xjg;vu!>Kp7EvQRSLlGVc!u$Z!8r5K3X;!9H`)%H66H_N=-rOnOUN)gcfPdg>h`F#yD4kO~X5~!paeOn^ znq?`^T$7Nr-@A?x7Aj_&WuQc0uVLVSfw&R6ey&8Nx1s^(%u5>V7LR^|~#P+-&mFg`OZ1d;`bmK7)rEc0O z{q9PwT3xhwzQ=qJLZ^}j#~t&dl)c&F{6Bf@a_YI>XR#u7S_t>!tDNaHx;b|Z6zKS! zL^ecec+U$8k=l}fqM-szO=tJG#gMIQn@BUl@Yjv*dx>3xrC80+7@Qo+`mXdedRyCU z6c;{Tw!QrH3CM~$rVn?^AYqhoEn6#NJqoQFqPKds(mXPE&o+eK<_!n1(}$TM02Ljb zH^b;{Oxyu<{M)%IjA9-0%+S;+sJu_9BLyIMr|9n!FOwJ1NUU=g#4ZB1tA`DX)bA$i|ekq4h>xcvZhlW z%1Dq9!9rxT|0zeWafgh6oNrufM(NGO1}=24Twd7k%J(`j*cwQJcZaxUbq}86+i)tV zd?Mk^8d7G1eiQwxxb7CL#vvinTjo95KXz(I?W6iM@lCw3r-Gr~!E=ZgSia(J zxkp3ZcXC!$b%Ounokj2eP*B$Ckk{Entjy3uvU^S~-u*hfRifaYNqpa(3{*77sM?;~ zn}5?bzGLaPA|CLos_H(g;GJQ5RyU7=^-d}%+D9Md`e~vw9!l#h{&J{3vn05H-==tJ zxx89SPW2*MRFW<}yy7NnT-ds7*Ye>{D1un55(SOI3{BpLP|NG@a@DWt$#kBj8!V2t z=C<&h@g(oy!i2`_HuTo)<{51PH980wUT+_MYxryIP$+aXV>dqdbs(tfZaj!}7%MZU zLkPJYjURgJO_cd~m-(9{6=U_HrTo(-^GvtA*P5ONFi>1CdT8EP%U5nF&-|71f!@l^ zJiI76S+Xij`e@e6p3l|ho}b015DYvHm7Q~=gQxItsh4pAQe)4O0B~q=h9X2fbaH>9 zKfNEe$&Wgipu)%1En;(^`#AqzTj1%vA9#vsN_;yyTaelvhvmT((P{Dadbt$(1O@pb z8M4*7hQB^k4a=$DHo+ULn>USV0mSFCpL|owr^GP6tRwXd<-iN8eayQC|H9BGNfbcW zQo&M*9wRTaLAmdBOZw@f{_9**bk=8-4-d+RZKa{F@is^j8EqSiX74Y(Y689Nqi*~( z|76Xm7D0WP>@#*b7Vqqsu`#fDo9UJDGRa!bAd$QEttqR%I<$nbU1S{ScoqhHTU%p-m(iqzKYwBD?@2wDAiwnM8wxYsKZsNx~ibOPRbB$0TU(h ziXA-x++1Mzvi#rL=(81mS13M16|of=<_=OamR9=LUo=>g!s^UD$D&`vl}o7?A&-yz zwlX*eVvs`5>Ji@Xk#!%o5QP58tzkcNPf9S zYIOngt`DDq1EqOM(IPCwz(gNbb1FkZdBEj`B7JPKi*^z~6vnr#uDS&vqi6{rgD507 zMWH>M8OPG>T+3yg$}Hr2+g#zmg>)bf%`tgrNmT$ZIdFa-7E|k@^A2osC70;uc|bcc z&}a1g&sOriCatnoTbbVO!_vymi@r%{rh>}Lx$#5U9zEe)iJm|tz7v{E2yVaH9I*8I z4ESpSX-Yfq8A=F z5-6PR1I=5Qiy-cIh&bPZk-%gzJ4PQ z&%b!NffJNk9XEBlwqrkZsYCDbv7_PiGiIX3<^Gr3F8uEP;By-6VK1L&Zct&unJE%I z5jr{Mm+8P|FO znlRn&rzNcN7h*}T=3-!YX|6&WM!)%fd9?F){MV<7nn*C~2HVIy!$=&w&ZuQ2C{{oUA zQ~5y&Q?(h1BS-oJR^5C4=)01iGx9G1brNgp+JQP-zIjvj9&Y>cY4N4um5!?TZB@M! zVk1j@6Zw0w%5gioB&*a*YCXLo-)A51kDZK;3DucY8`HfwWez^;^{h~DscYYJCICfU z9*|Uham%*;s!NY-Th8DxY8f?%AHq8N5>TLCno2I$n@CF|VM4XIP9rnDlB`;f_q%*76(ZjJ?;)8FO4j6P{)O1lDwB?Qp~ zfcaBaeWJt!U}wIU&avC5)fC0_an_#;8z2rf%eM;ENZtxZT(kdq*9M0Y0P{wHU61G$I1#H z-KfhICUeS~PI@RcuAOw{eLGi;XuY3_c@E1E3Y^?u%;4AGAq2hbb~dVCaKBSm-q&S@ zguU_h%RJ?eR8E0?1U)dNb<*Cny_nxLFVM`!R(dhj&z6DXi| zP@`0h&AtrYD(PO+^}L{dZz{DiDN!37a`#GHa?BMqro61Rq&2G_dGk2hOz=$%YQr(1 z219xg_q+-6lUyk$OK-JYXvLX&;V--wGvsVs3bXjk$bg#1+FFwi|I)OLMza=;sVM6k z&7e>+<;|rRtYjga9qs7Rw>JzFAYZSkh93EEv!ZheS(+bYMD6TqKZLBShEr7^)1`Lo z$-1}Gb8sC^5w=e$!jIb-98GBLu z(&)+Q{IjYECkjKSaN-+#AeGdrTGewTY0PIElyw@hvQG0o5HioO+>`V>+{J;;IP^}l zN4xvB17s-9*z(1LgY@F*iDVkhew(tEf6Lk5G@B^ctwuQ8;WS%JiM|oyL8)O|CQm+y)+~_ zKZPW(+(J%`_E>O1>2H_L(FuvRgH*(tj6uwm)Ie_V!Fo4*GpI<^@VA_`Is7lIsiU!` z6lcv$eVR-BV!g*VMc>b#7J)r&7fpggbX!t`cZ1^>a}4)hrDNh_COvAOLZ0pt*MWk- zEL&Pz=Ue1e%?;j8(=Nm*GN@g&h;`6y6XJ({qf5jQ+2|GAy)KG(|=5kaS z*luG+kL+h|O|(ROqDD=7+cWXMvb)GwZy6=fwOjn}4S=Lo~kR<9wN^XLN}lv|KLm`9?3r z@)t6-KA-Q>;4I9)*jNo|=1>0rK{JPZ;vt{GFbyksuNrIkuoGztBy{-o>o=0QR8^;( z8I=8ZSXM{FGDA!+?a_UXt1bo8A6)VapcsEqk@FIk8cLLMAA7ab{d$-cVDnzXD2S}r zaa{qYABDi2(;;x#Ze6O9%@L@Tz3{&e?Mil3b?Cab$)m6FQ;;mj|2}|)zWlTzR>>-V zc{p^+$KmYdCYhe_rB8HAf;lbE=-F9brR^kny$@;~GVj9L%jH|$ScvtPv0mh6boJZ+{a#&`epHPnxN%>EhK5WmX zE8QTMY&Qy?Kx1mwC!2|vaKgs2ZYii}VwwAhG|jH*{Rg`?G1%oZI@a`={}esmFp;)_ zmi~PB&02ah{h3zK6^b)r9Z*KwR%x!-vfUZ2LHjcFH3#Q&cqeG z*MCH|Oh9NujADLe(A(Gh_WCI1w}p_c;6$hB1#^$hKrxSx(Jo^B9qIC6w;dupZqwz~ z|2Ca)qtLPp&x1xwh*a|c`mSqAJL;rX)Ka2HXVd+H5JX)~6RlMinHvAgpDsx@j_Y=} z+9tFNRYTAtHWl=I^Jkzzc6*_C>^|@Z#Uqc<2V}kSVE&bhc4KGipz*P_NacyN{1xzY9*lN6ZOO)(0oxgyrWz`aJa#+S!os z8wWy4peq$)i>?vP^-tRP$J=`}6&0LWMFZjbr|fGP^jb1wUt}jMI!a=$_1gOFvDA`n zeZkM`&K4R-*tdEBh^o;*bf4&hFKcM3V=$xYWVFM!y4&$>p^HsVXnw|yDl9>FN}uf( zDRHPD=e6nI)oZGm-}p@Xs67PNd~p)hwSE%KPd5E)E+Y#wk<(iy+CdB}Xx>Q4Pf7K( z82qQ;87+AFp(R9R1J*%Ii3gEiv7{1fb6!Hbp6SSXi}0poqj;NX5Gt${;wgg=w2db6 zhCk=`O~uW$`elRFH}!%Z2NeBew8CNM?lw#|RzP1~@41+CdfBYu7#8pzPm$_7w54`O zWZ1beI50ge_a_UU=B$Rz&81D4!{x~@}-$a&Vx2iOEjhdI-gEryuO3Q6N}Od8|%L+4y_v!Xe{-oa#2ZnOWZH z3iHddj3huk-M^K(=Fclip@U7`D85heV<;lE$bbG+kf2?x$wBibZX)!Ez|i9(aP3w6 zt@*exPTfAnX`OJ-9_{P?HMFnecI62U>o!S(b^mCv?Xxqg5BC^vqnl%+?MN{~_H+L9 z$WDfXV&q~iERE~JVhQ=tNX>&~xhWyMN24NB2mK7nz-dYR9<%fBNGfWVJY%k=UHS zG#`w6^+2I;Lak15aT6_iQMwT#lc5lHB_ihx+x)Bg%Y42@U!Taxk*N9>?ipr4F(_&v zrxU5x2TZkuK#heC9-$ZX2djEJLVZ?5**9I$^}fnwGcwjVFpW^1;>}}Y5X8Ks!G_Gv z+ga4QeA;o~)W{?$-f34EU0M)isQetjFz^!Qilu@fHh1KtKVa);GWqu_jf@NdIU^j!os`Q2QI89Ty zVUPFeh2L9R7RKs>0dc>If}@JvY_Y*lhLR31gRYF^Z%#zItr{_3!-9Q8fI68`wF_&> z5ZnaqSEiflA2QB zX-P?z(}RG)64aFPIG)R~e3G_w+3XNVRp}fPZIwuCq^h>)hfXEl|5lVYl0ca}IM}YV zvIk=++*xSav>m(OkM@5L*e=!L4$=K`%bkCk>@T8H9BrcX!O>RWFDM8pOgPRk1^Cw+ z8^=(Q9>3ckwSzhfVA0ou_2{VG7Jrd>MMVP2h^_rwkd!vGY+_MuS=f|w=GgLdlwdKd ztPn+%_t1b!1j8MPw;>sEd&~_pb9c#BUsPN<|2LwyhoU}c>_QSjsGSS8iD0MPed3=V^@FyH?ToKgX8JJuRLkG<;bS>Nv z!ElLU4crv=z)l$J^Kk`IN!=Xj*7q9H?T&0z+zfZ>)L(OiU=)-%iobU9wQK@JqUmGN z1^$Hz=`#qDF$fZ)BFrR6>w3{u;tdI--Ldyw`ucjU`#SE8Uhe)}vdzjI#W{ta@7oDL zD{o?5Eu_6%6$Yy^Xu5Z9CO6F?frvA}a>V3&;G^wZi)p(X&zk4doer^|b9^qCRVSYa z)J;)z(gA08TYGB$URT|^wmneHHrh{BQE;tp%MOV?;bs&ulpG_Yp`a5jS)_TqQ@B8O zpQbibr%>QPxT>_UlH%n;(!AgQ)b5mL%9c~8bkn*Xaz#8p_sj?7yC0H+$`55Rn-(?+ zNHBTwylY|=^d(5&{vnG|SbS^FW_G91&;~!aiK@*Y$)df~JfSaT#m3?%UV;D)PeFjBQr6lY5fn_Ui{) zibq(cYzxj1{(SlE`o0S^Ianv-*|WE$UncEJrF?0KWb(?a&~+p0&7@aL zFs1U3bnx&Hr{>pUbeoZw6r*O9@d209uAb-HS9z8xbsaZLcU$jZuKoN;-8C5-@3l== z;Ih=T@UpZw@r8y9oQtjdT4jWXc8mBN3u=2ILToZ#A;BcZIj%}DF)t#2`{xLg1o2ck zSMA%+wBK}-UP9meX63*7Ir7_MPNhg0dfGO0-2BG3`!5^DBO+CLDmP|S9cN3@4=$^& zyrtK^S>d~&L}xNT=-e(r{JZ&*NE7dxCTJ18PV-7!T>)G6tp#py;LaRE#sy}dj_ z8>B)LKN+QI*!VZ%r#!|9#knw`VThba10(-ygFEqDm20r!E!yriBeUOC* zgUu%RHjPZP2vh#r$A?54PkdDx(v#&&c^2D}YCLLL0{Z*rvU7Hc&sF|dSIe-}s^iaR z)+yy7P6~CbKQw(A1FKl;VNUymIKS_B4BtunP4@bHdb6MnbTN~E!t*Z~nv`qI%go*1 zZ}@_SP5!^W9;wbMjcMr|Pmg@P{JGbj=O)YI6a4@Ti+{sL6SU`QCJ_oum^jods>voy z4}aShAB&3-+E%6b@asc~^6qXqyeT>vBgrW(Hm~cKi{AwibeT~Ezg~$ThSw8a1=|kd zWD^3bqV{Vn{$T{A@g0?PgTMIL0(URA$3TT1EjIhb&m&~X3YT9#9Sh1Y3d{a{S$uMN!kY`#O$aZtbrQc+ z9rWm&&>6b689kebpj|yosy17thm-JOi5m+&ElNM6pgji=u@0Mj(MRTuXQ^75 zE*pwOe4llFY~Pjy5^=U|^Fc~$USyMA8#0eO7GEkYD0LoOexg0&&84)8E+!R8!eX~)c?}!VyProY;t1oQ9dKf z+?%_Kin+hfmNdimDwtt=7ADaH^md<;M1k#*V5&{;y;$;3xUQ|{NqM%=ReMEaev=PP2MC0~K-K{fI80%6pzhBzwOpWjj5|YPgUwGE4hS791N} z4VAOmq6_WLRyi?$9Z;qTRXww1?y9;s z(3Iqk%5`>$Zn|Q2Z-(DB*{+oymbab{z$tY%sJv>Tkp^UseFSrVq0@4|44!5ZrOxLF z_c?m4@gPw@B`2R^Z3`XsENi@LH<9wpaPKy&9V;5aq)r|k%Ahf#LI3o8nZ^ru%#H_s zcOI+vPf%4Z9#AptXyc^Rp7Wt!I;EY}o~hX}UuHeMRrRwYxj^Ka_$1!$T6gT{%k4!p zRLcWYYYgC*sjsnpOz+5pvqj)QiUZhZG}|G#Mn*;VVIUV5WPSUYdy1bQ}&#vJ?o|E;VUA?=qix!_Dczprrb1j%=P)q)b+if>b027l^B zhMW0(8kU|LITSoV5M)AAb?Y9L#{-E|-Yb}Ot#iDw$#+VUOHaCZx+69s`zN2*E<#MQ zlgE03xG^ydL1Nf$n4(87hQpjSTgFZ7Q@5qmt#K~yZ$T#MzWx8|#4>%9q^N>i38^>MePMQeuXrKISy;m1^J|Bpj8Eg8W44K^TO$_9D4Xa< znOtq@q;oD$6(F?m9c)@Ej&0*-@Gdhw;yQEtX=}5deewNoxvr;PM+4l%;eFRZ_8F!c6_QF)TpCjUJ=@+nu z?WiPS;L!D|b6?1owvj&N_#XdH#{-i+1HXk;!(4}&?vC{9h&x(|uxFp9#f#&3yjbC3 zgb+QIns1J&#MnF#(TM`7_4MHna{NZ`dEdSX1QperCTL$eD8yaZp`ny`_YfN49r7VQibkSglq^*r6<@AvPZ zK647{w>4u>pBoH<-`J-AXc7GmYq*e(9ZB1^VG8P-O2L`+7|eb%K6ur^46GHuS8JWe zOw#_IlU(-)Lloc+fWM(9BH}kJ67#% z8J4jxcXfD%<#?}M#$w)a$O=MIWa-{Q^A2w~!v_l0tU@xzWX=!?fVlFiKrGl$0-5uY zZ``pw)8ee@AyQ5MWFyrj$v^MtPbZQMO8|^Ob$d*l$C_xdS}bF%=9|8X!TaxrNY^yq z?iV#oZ&m#|ScsPqo9!!LL)(nkw{*&f^pCMNnT2($fSI`oW~TGzJDDz@q&HE~$OGFO z+28{Lz8x3v{6U0-zFmtjFVk&5Qs9n=V@BAV9V#Z?V?NHe!#3L+K3o0s8#k>xA@1I} zWgk7>KP%%_sh4>eai)5)&!e%r`V1=&KV1%4NHN{QO-#WA^`7=+w^aGkI=(}s?Ve)4 z(1&o%BFI=@hz-6@FNT7vOnHdT1N@ss7S!+S^Y^cG+h4)vxV-uUxSWS-km2U?uyE6+ zDYI7&Al1;~!;k_xiu-B<&XP>_Oca;73+X{WHy#OO-@Qko^wN?!Ip|aNU`r*iG4cJF zs)CJ75Znn0sern8XtUvy|+s?5mNiD5PNv#I53s-P=(W_+2U0jCE+iMHc zx@AbdI7Lry%EX|L?xX)R`_x64oKQgYW06V)OS<=1LG00KF&grBsfEB`_cS^y%$xiS zSDI&99g&=$Jmn+VRbM|iGdkxtP6;nNF1)Le@K#hG6{i>8MTns(|A#gT8rq!j;R+9Z zjG@D^d9;h_{rb(deeWqYOPW^KTHNakSLg2^M-f`5*zi3M1U~+G(z&;WFE%u_^&*}IT?G$Po5g-eXSRxRCLlC4DbH{N;7Eb8jzx(3&%0h z+PpWefH38V5NuP0RJ~KdzQ@nh$1X$%4e^7p(_Bpolf? zN~!bRzHl;*`3`K9Aa{BYApBAQb?wtPjL?H_vy)#QBuE~*ke$~%%ZMUW(!IYgIQjmz zt1X)wfxm8jv=|(jnP;(`ld?lyV5nz~W=15LdiN97Jh%t79sxvH!HP5tAiC|SL(;WO zZ)`qT?xbmsZhpnS7V+R|pYiR1-u*-W7V=TnpTYBv7J-~o%2Bw{kq&;hF<)<*?3wp! z!EM`B`==P|{pD&puboAuR9WcIGOx1IUkkEneou|o6RQA~w-Ywqb&v|pPGIGOC|Vy6 zLLE(zlUlQ&nLZEYw|@yp@jY+(&zNji!ghE5pWCjYA*4FWxJ3l$cFX!R*Kl&dz#QQ& z-_Pln-duj_SGP|28sN^3>G+0A()-_H(_O01@Q6&qAg2!t8kn*FsXMsca>sP$Mmx67BmoZ8P&b zulF>0zg^$o=iVDWpa1T|=kfUTn)5p6d7kHa&UwAdCZkk-!NARz;8oYfI8y3nibL?$2}ab6abv6YzK1Ferr9b)UFG8sOf#_0<@ zJn0)T^CIGde=1MfkC(1gCU#MQq`wtHEfbJw6|Fkp2m0>^K@$Wrpq{sR!Gj4J-$noL z{6ul&Nr9(a*W>H)@*(z9N%zJPe&XzZ`4f{6cR$E=dxNhLoC?OlpEYxs7fz^nq@1do zX{+A-&>t8MFc|tuS_q#|scUCi3Z#w76S~=Mvtm6U16-6;d!MhvI_AWw%XO1`-&=GS z#6zPdPV-nS0A`22qWN!nAl{T8h!f$?GJ;>3)VsaKE4J{OU zZ0l=*bt+~->k%3~SnCmk1FS;+F7Nyf2!+D$+xp@h;r_@IyUZadXTb$h<}Y()h@zC{ zuv){-TGnrAhQ(&+$UHyu`tN4c4sI?bLK3KbW-Fm)T!fr-a>@i*ypyI$DfAimzu#r| zDZn_RxIRK2OKk~#pf!{-jz1O6kVXA8F!JAIps2s~P2XfEq|<#t=homomOQx{ipyC= z0`Iz8qJja13eAqn?#y`7)_A$0~35XjI9 z{%AJmOemqrrJc%VS{@YKP(|+Bc{sus`>9k5#PAspuf#WLSIN1v#;1ftr^SPAItp}C zg!ruiCb9FX{!fMWJ3n|mT(R7QPfB>)?Mp~wp*-_W=u!@)E4D~m7At7jpAZL*Fqvo0 zjLfkRMMAoPlX>nGbI9cjkT-v(;WH-9^8!Bu_V`Lx&1M8^~>`Tx5$=G2qh||0dxdbF;c`l9}AkL z;d`kygbMZ&FmnHm3MwnPWx1xhjH{@QWnC-=VjdOjm+Tn7GQ%R-qge@B3`*d7ay-|& z!d1JWBp(7*<&7G>5E1i{MA!R{{?)YvGEmd(z8QGK2akUVC5S=HkN))-RL4YT5!!h& z=+~!5uii|gk*VAiv7sg|t5(RJ$S!QrW|+ETssBFt-xbu~0X9_I?wHec9#5_`M*a?o zX@0}f>PKVH-#sD*$W|`%t+tc=3$kMZtVsVR=3ynx^Py4%-xi`f^+ zt*B4m%^=KHgajn=GL#rGL)n7cEzOO;H347CcTK1k=1!die}DNVF-xmttvFu^uHZIx27egJucjk9z#2kMrJQSU2S4j#s}f~rQKr*EJhd-VHEe383A__>J`$KOZJeR2)er8&CAz}WlYCE=WG(8Cx@(2; z{B}RW98C5_m~-v#wOO5V5h!mANo;0--7q^o4)z^ z$ojcGG79*713lWdrsDhVRteAMo~-|E`|icjeC2)kfxpqOJF-MznC>|p0*IW22)B9W z@ye6`BjM-T{OR;%$Vo<&SYvgIMCI0kGE>ma!Yo5uq9p6&Z1~0TMQ9Bp;e9~b!9ex9 zl<7qF+>^B4HeuaS1g&mnb0GZnu5DCFJaZD5h~j&E!_oDWtFg8@{%c-04fgN<71^4k z;Cfly^n2rQ*IP53(;e?s?QzUOJ$aHW)&6}|PRr5F=ZCI1AtXx`nr9H#)Lm#E@?Hj~ zjNUx_f2lln98Aq}{F5L#bZvwz-gj5ol29Xm0g-1I?P`U6j|~%QW9OBX^)@;h7$^2G z?NCgW1c@o(4{b3}f-U-$;K-CW91503zu)@%iv-e~f^M2=p7jcU(<7ZaU_r2u`~~WN z6VtxVd%1oU<%mSpikkL`Zb>m^w#72HL>l81Jo)1PQ;{vfM3CN7L=i*-UGf6kN`l&B z4z$g=D^Qe~m(dG_`E-P4N$3v)Ictxq>Xz+BLmc<{?M^I)JI-`+FIyrZBp{X+m|nbt z$eaGcTbx)h1e4b5sG)rthhbSGx`4E)vewI|gm|!kC;kx%P-2a^8&I>F-MMXMtR#?kd5}qpatl+pRUE!Y6snb~P$El95hVn<>lC^v({+Et*+7wA2VFWK5*GX6FI(>|m8-B4A}3~gDi z{U3y|vJNC!^e`_?#??&C$A+-sufND}k>x}-)x>uHAn)tx<9UE7!2_0Vhf9!%^C8^K zav<%-=Y`GsbeVa^Z9m8Z|B7+ZivZ&a*jAeO46Zt=9$0&-cUMe$YKM~J@*jma0rqIp z$k4!*pwp~F&91A<2*qPsIhcR#FSvZvWVK_uUcl*9HanfN;jdr3_=An#VaqGo;s}zy zA)13(H(!R(8S3k~&g>EJzW)OAzw<4Ot_t5i2Y_3kt`=p%Ik$nvDPFAG#-p%6xbo-9jc5-yw;uUMXVaU*i(yfbXUtt*VsE)y~)ns;0l;X zZ+e6~%upo23rDTa}rvC)}%N&Zy@pJjT)b<)Gp2>B6S86C`+TEtzCi3rpj zj+=-%q^tk`97iRhl*!Dqg#16+DH4+5)Zm|Rf;uB!Oq?OaMA`3f7dPjs>JPALAYdZ^ z5Ubt_=^v4(kVc@qsQIUX;`iF`$!=+H!5K$0e!>ajsJwu1AqE60?xu%-{)QK{vAP9! zrHhi^cg3g72YFBL|H?##5 zLl~_GSpi7tX1_I1YS~UH2;_-d|BxxgS&b|+;PyS+RDll;fnoj&AzOtU^BnV)kP8e` zGnDT$SoY9)5}TA=dA_RI+%b21L#MhdCqa_pvC>5ZR~h7fvg@x*22C5P5N&8cVZ*w8)D`^{3I?^3M^SN*wzRrGdU?2YLR%Dy%U-(}cCj zE&eu<#Q&8-Re&cfExkD%2iZ2dPJswAqkj0Gm!H_N zW}Dd7!hRMxk*0@*M8MAq3B#M{D-l8$Ne*l(Cb z1}}$BCg#xbC?@V??D!5S{O}X}WvE|H9ZH(2LQgy>c#Ok9p}gqHOUPi_x_VboOiu23 zBtp~6tFTnm>(3hj&oXry?E6@?_LyFUS~0bht#5L$DX&%U8ofl!*ARJ(nFB85S6wMoiDcuKfL!SK@#fQ_C@W7!5@P&s%#RVA9Vw~lHzhDx`@@)#9(FfTW|Ta zTetjrt)L-s>h8xyvZZIk2@MIIB?8{kgo;)X^%Zkh%$2|e16kr|dofq(wAIpM9H(oH zDFvSam8oZd(vl0>yF`Tx`pfI8qpe!K;#_)G)9YJ5O;`91AUO$7iWyDnJSZsE_JSP! zB>D|YZ-EteJxY)2K|d%x7GsehnM-Jlgaa&TN`Jz^vr1VH+=H{#8)>G1SL9rMXK+Nj z@jnF#Di98pTpEMB1c#ext;JmS(>Q1MZlTaai(5nxslV7Y_&A8bRxOsEAh3h2P~zS? zIG!;3(g<4Ogoay2DMJ_PswV%2!eI6faKpcfYiQ)X*2)z}Vap`2VL+ERLMtm3Zas*5 zZU%%+UFy>hz`;6<8%(Uib4I6oaDoThpX2A(RJ!2yJ$}LMpM<6$>7(m-{N>-n%7~>! zt1=t}H6LBG8H>`upALg3CUMx5y!Ubf4DExgT#@60DzyXc*-JANiSu5-l^x& z-XjpC-2$L1q@6F&?+tnU*mcW|hXQQFxfpf|i0P z`ti{pSS7zB%>|VYcYhE*a=8UeD64|Y@gX8G%nB|lM)lcfJXKig)a1gwc){wR#f%`J z;HBE*v2^w4(cTcq*H;48V-+6g;aJIc#n?irzo|CZ9z+c4x;V}##mTWJ)BZGU8gjDy zpv#mMThLu))OAko^}q3=lpBu9PT0c#5oPC#jwTw%dGixO_84&p_0_MOA#C<7bxLJ_ z$(kiMf1A+aDO#BKxbwV6gy=mV)~lYt{K&*dt}Cp6&|~YHFRM=q_x>BU+kP8C4*SGgH~vTV*m9}O|(ywrytInU)^fT8&1Q9FK#St!4&klo(8Kyy(3g$nU7&B z^Z0)}kV`>@mZw!q64HnXwGx`XwLL1fjcDo-|BkhtDqK5OjEfXglx5bS}U4g9% ztiLxQQ)2F`0+VG+-KCxNN2 zkJ2M8)gsW7YQUa1W^V}du?!H}L~po^d$KC?fJ4C1z(~wWlQ1id^^Q`7BZaAQ7@Als z>WT8Ma9-*_6Vm;%%BfRJqM<8f+CR$mVB|z>mP&he_uRGLEcALyAojkHkT$K_iy>e0jfp04`94_0OiKONqQmEwg@x@(a<*4l;* zF$5cu7c+SOwf|FDNIw%?FykH zO(3O-6Gl}c(o#8JHo7Q)qnF0GQpSB*Ut2*F-A(U4_9U5~tS3QrZC4vv$Y9bR|2}N@rgE!GN zWFq{~Hay7+nzu2Hri~+NY1jsan6AsH@eJO%$eWw*`JR%`_szGtu~NJOs%S$2m+trs zeH^-O9MG#K%Dug@b~u)V&6PS(G^?41<5pBSJA1zFihRC10K z6;hIb5KO}7-!474N{7aH<1e@v)El0{h2^JK_SW09ct)wKFiL>&6RaIEk6*wOpH!Cn zV$@*5kD&%N$YzAG4u>dYGgfizF`Uh?Y1A6w$vqr;XTO_W?~5=1)|0$gA}SLa&eEQk z#ngX{#q1Eg&&1hHkRb+L(d6$-B^iG~OjNxhEx*KAkLj^-%iyiF&1|NQnRPLbe-v zKuNZ9&>xD~$bQr3og}8bY<`=qpNG2p>XpzO! zR$cGn%DTa3>1mcQZI;=B!}DfaK=`g?^Bm~iXG|)9w*UlE&|3fl)8<_r=Cs6Fp@LE{ z0vgLR9oaz!D<7hu7xH5nU^*gO#|VIN4LN_Eee5or^GBg)xO!denzv7nm0yoAmKN#2 zr6Gn)PJ;eKZc45Nr{TVF?(ItJx)A_lvj;=gyNd(3hR^UWrc&mNZgUm+Mi6cpzz{vw zHT#Zu@&_0a?vKey$!!`ClYRFipc1Vwb2t(41Nrh#8zClJY%wT|W|68kr%oahbyY!9mlV~&fHNM1g- zu+u1Zv!elL$2OzJU^1>k-9nXE@ouwIg37ywrA7=QfLw_gg!1G!}@KFhq>#I$b_# zZyp_AK~LOW3uF4%>>r#uzbGRtymtO&hby6WS>fp=n`w_-J}a+;4@h)JbG|f9c{&_- z0D%#GlEXNkNonS-!6p;?Plf&OGn`5@xI@;noA+9ns%elN=9|=BEYI2PmUx4j%~0r+ z5tB;|)?$CS63shLjK>9qxU=Eb{+r6nqTWxdqd(0ZcJ@(FQqAjz?ds?04@<60R@0N; zqNTO|{O22M8M@lCl}CE=l;*JB`t+HOaUr=*n+onjYYbiyuc`!N8pqVNms)(0)6x=~>uEkg z3(6Jmq#AV=JXL7ix=31d$kJVUJkQ}BtIGkIsn1%?1^=%$<6ic4aK*iP%3thdcn2$Y zZGD&Dw0T9kY4*ovpij|Hc2F;ip#?;o&Pc&0)?7hsr?OIxnCR-lEF+oSS}>l(xZQ75<)J zV1ZQD#*`K#+@1%wl58+8igRhNR&f3Z<*T9HA+|lMKlJHz+^x+}>T;z9o3Q1>YBT)( z!vco#&!skqbB*}+T(Rg}u}rCtgww9NB}$5MiJ;t7ix}@Pf1AB`W#)tvOBh$e;~!YK z8g$5rwf!(x_n9U{nl^U{-h~{N3kZ=MI(vf@@c*ia9P3l9@B(eKO>Sjt&im4QLzG@# zzhAqN;bGrAot=HL=K6XqN@x3aLwilLP`j!HAJ)I{!+b30=usUr*AD%1;~{H`-+gSa zvbChJ1Xh?W?;M&&BcWM_$h*+***NA)eR;zK;Py|jOM4<9@k|1!UkME{` z4Fb|I@nM}bcIx_L9WIk1WP{c<-(LHg@;XoabJh<29ag?*&k6*@vRe?N6pma9iiJ;G zB5&9Fg>08gh>%UUi*A;2x_!9jh@E9pJ`7?nX6+k3QO8|Fi?MBXx8$~tYg&LYoa4fo zj>jdr^Un??tvfdw4@?275QqW2M{364|Mhh$hiR19v*rTBce_N_);pB}l_tWi`|sIp z@2C)WSVw8w+w)}`!$XNa>4P|9uuw{y^lTPM;yE5jopR@-37pJzh(1pES3##z18!4` z9(&dc)6HSXyV}&-9tw8SZVd&W*B^Dr!*r}xlj88+&;$*1qhXVT z8cp5qmoDm4Gd!sK_(o~Tk`7qS$Wq$*#m>>d-da-=$$XjJzqoFHf;yRf?;YdN{SjIk(zaUoBNJ z93bNQkmA5WBiDL_Tq}vlrHGI#*?QCZ?;sb0LEe7v{Z&Bt39{T}>h_nUj364xtTLG% zpQ(9L9^usbnxM4KPz>G&lX>VU9H$e*Q5=P1sX~whJ{6vEqzX zBO$d?8lONajK1WNi;m@9n%jE*=83?mdBtp6ogjP;&ZQ03SUXDO<_l{l^|L;SM z12~Dmw6rp2`EaDPp9f*`t|v4>Q_r!xyMC>m69aU3H^ za{Y~%T%1vIsZe@19G_gMY+x;Gxozud`^g3wI(3on1|VQ^;EXW-(d3F&Y)Ob<7Zs1aLI`^!G zL?iZ&B0gx&p86bdD##F=cGxr-udICq1W-;kI80di>ava(N2{U` z;8)f{NhWmDAn(Tn2lXP@aN9RFoQrJO+jvxnU_+;Zp`_)7+?N&yg2p}$FmYFIToc+) zSHli-r6c%EXX3J$#X#=o8K`5V3vkyO;}rnCyCbFF+n)&-Ip(mcb>5BQAb;rhCC*#q zop9`Cc)0t7%oXRuj8DhB+f@7A`uP zXTIsF<0|=b*1O9r>dih;lB+4(dpSIQ2mf;I^W5$uHtZc?U2iO6Xr%#{YjVA>VC zC?QJ$EKS0^uF(o2>SqCa|spgNRwUHiR z+2PJs8=8G&6W~jOCs$;U{Q7QX)wq-6D~JIsft-((b94;R`Q8GJmF}P%yScN_II4mg z9A4<5Nq-UEAHmEUM_f^*nxRKGqU4ccZ)}GMPWqgBc94vA0dm2IL>Fuufn1O-BZ_yy zG7m0?Oxx1;@-3FwQcp*8XrCA;oR+`KxW_M?)ZU~$f^yT}L5W{s{>#euYTsYW@tw&1 zVoRqUA-bQTAgSJ$_4ZCcSZZrb87FZUC9(->x}s;x)ZGvGZRM8&VN_iS1kDklgR7ga zzRndONxUEwA_0g-QtBMbr{Kwe2dbL9c_({dz5Q3@-1#>GfT>&{Fcpdm&;e>r($fWa zIv_sm6*!$mcJINrx%mc#3Skv+sU`!Ldf}~`Ccj#_+3@T%)SN5t(i8`4yG*cMAhEOy zSc7a=wYz*0-gb@AT-Jt4$A{I%wbAu{`M-h?y!s3QyN#$z<<3L_+v0z8Br#y$gYDk_ zTH7sqh5YUt+aVH4sZc7PfVW*a9IoY;AMP(TdoQ9=Z02|&Vz@3v*&^7Mytv1wXOaE9 z6Ap2u3kQmKP3gy%`B>r_>*$TRic7nP;2_cDP9KyO#1c7y0;!^eD^@-ZZ#r6^Ft@AC z4GtGT=~>ip-72m$d<$P$$Y0mvt;L6vks=?if%rIRg?8Ij6tOOZh-D$3XP-(g!HWuI ztI~u>A39Pz#<5?qy5lg2tr>@JCt~DTIh3!2q!B;<~8}}}~4arNWhAceD)Ed`nNlFVPmKG_HzK$}j zon`RcBmr`Sge`OZIqDbAt5RDrgUI+z1EqzQ>yf*B;#qNsEQ!SKS?r2cgCkCX+SI=k z{Uui*M>KZpA0?zUK_?97lA9#frXHj1Z%THLey33Nf*2F)QB2s+lOs?)=d@}#p7*ak-ob!? zp`>-rL@+^|vzIF_N?^Tkl$4bxh|GcwYqZYiAXSAmCrl`L?LYrxH7Hl*V(SztuTX+W1Ft+QhUa4bqd zqPeFfb?Y|D{2ez%WYn3!LKpanH|f-cSd4=1m6BT9@wK)#0{|nx!%7&b0$vGysk3Bvma&iutp{`KiyexOE1!17Dod*m=31?|O{XGGE1S zNEUYn#13@+Y(E_oLYY@8aBvVf9`f!|BE}%1$FdPlz#7~AR#agD!W_&O9tE{*b{7OwtA#?tW=&6q^PrTo59^_>eN2#5Y@~pR zCSRv8h&;KO!mh~8g6O!-ay(tF(-{45MF#F}e}e4j?D!lij4XWYI$+%{{;reg`AQ?9wTyuA;;~2+_!3t7*lO!|X0<8Ts~b!eA5C{-{`ks&ix^8r>oxUm z?P6^=lUfDxrku}|iFxh&&aW(B*e#k-&>TSxHsTaK9Q^PP91>(c;vwyzYqcZy<^}v^ z+l)KMfd*Q2t?)4Ix>^x-pRso5@!EudFw;&6Eps&B!tCC944%UD4xXo)p9pQO!i2Lw zY&>FFC(0?3gq-po)#rAVnx}zs@qt^V7LnE{j*4MiRMgvC+JXJ*Aq2(LO?d7L9Swsi z3f3@&V`sLg^Ro_HO)w|gWbj=NH^=9|4>Jky69+X@%(WGafdlr_LvBTGvE$68M*R%d z#5@=Qx2*EjtL~`Tw(vI*YkpPdbGGHrPss$s@IRQH@}|y4Y*t}& z@{gZYh$&tVBFqH>=IlVFQ{4`Yk@)Q50wr-pmp8eOwRvnh+duc-!;2jQRC$7dKw%M>kZ9l|ONZr&SZj=nzUL z_)Aa5W6LE>ob>2^LSyC|mNa!|Z%W!h$rGjT_kp>mG8DRDZq+}!_$(WD@;0$g^aV*p z@_R=S>P`;|=QV}X=SXXwx?Bb82U?X=gXQhA{(w&Tlg%(HrZMBKkv5;QN**-SMUA2q ze?Hs#=d+QyouILFTaPBBH`1^rXc}vDxu*y|Y}chJbFSANp_D~X?+MEu@K1q$%=VXL zte^|mt@@DGdAD=v>noPq=M6L#!kOSYq>m7r4r>SQGr3wMQ+>;B|dOEoa2fho{OkmT{>YfV#O$QOHw#ybnfiz?rwjW=Fj zi#eyKA!5QlxFMBbuI^l=`5`G^z>aI*l(Jy;Zx|2RhmG zBJjDVi=WT_%9}{TwjefTa(ozmCU>S}vm(jxL77D6M{1f5dxyPgwxT0NgZ4tSw+=+; zo7;`h(K0I>a@1~sWHRv`xvHd3l&0gYi-?nv^q5{2A zX08PO#I=ycb`B$NZ0sDGQkzkvX;fL$3oV)6sT!Ey`6gTswuKtFnyp74O2Oo3`tXSU zQ+ZWhw}&(JI;g{t<$s=d*d+XyZmu^PG_|z#97_yRl>B8zDtneR2s$u4;==gChEyS0{RI)WrPM+$D8EL$Rudpd8v<94z*9@_v}!P%HQ#Vn zKi_ccAxvkMEcu-Ptf&oXqB#ODRlJ#Zsk_VIP7)(_7S^Sma;l(mrlKv zDn5W8sE_MN(P>KK&0&^4;A5@N`=~GeDX-3Qb6D`arq7#qUv6qrDz)9ZuPLMLp9=6SkJs{0;Ftp#cTPO^M`0Ws z4=|2+ytGSjytC(EQTZ#p%#_?JMDjK*@~C^V-qS>O<>B3aw1x8$U8vS z>|?25xg?(DrmCch^GoZAtan(^Rk%P&uscJ^MvyAG9>DvV3HoHR&csr zq_zJk$9=n!uG#l2oWW6G!o#=5t5vUCZfASz%2w+3pv9L3)cv^(Jtpj)eehNN7$AMO&a?XW-&Fv%Gp=vm1LWzQ)4Q9*_HfYqTia*9v8e4}{7r?+9 zR()Yi3DsT-K~*!k34##3&xa3o{sK-p%y2DX0PYshxRW`qBZvlc1rIzp;DJpYwS5}$ znM&irCg$xaazBAqUFCK&5DjECO3cy>7cZ0#fWfdQ-kO9pgAyiSBb(cgeT zt5R`>P#Ovkc_ly^?cG^n*L->3F1H+ol$Bh~Eysk}jWA;~`==x{0}T9RiQtEZ9DH|p z<5?AiFt@XyK<7d{dxyBg9NQZqLQ5DPLEHMta6|e}$r>r`X|qlqH6s9w0Mf#QMoz?& zfpa6T4kZQK6?=RE?2EUpHPm1ydzm$_V<<=Q$#8z5>Y`Q;v#u3&Ja#v@;qy|vu3RYi zlL$%)X~;&D&`z!X4VTaaBx1N-2IrC+GFqX&DOQ|3U&@-{aVDa_Cw~3xPojAAjx1ea+^L!_PF3Xm>R z2mGx}^XK~875|~6L`SDlU$Z?4nM{~qvQ;zNT2k-Y@(;CetA1lRd9+S{gi4L&+9m&l z9Ja*{RT54F09FKSJL$&nm5`vAb{ZxCt71X+{KM5YYyDh{T|^dB!dt8in-*mDvh$R_ zR`)8W(o)%V>fJ8KRC^zhvw+r_x8;}L>#oL-rP?ewBloVq5HEB7`K?^I_d!Dh-V1*9ZVNOlD;^X#Pkp*=ATL9dW&0OuM zCri3^YyswE&-7y!8~3>y^=)aEIV`nb8#F_&?2ah@ki{abaq{<9x>D*yl7S5P=XK;Gn?&5X?JUdnZ|qbMRq&#LW57)k%-dmDp#!uafD;xSS{IE~4etdSo zVBRkaV>?9;Y+Z2Tn&rj;H@I-j~*oz1NlEX`1r=Yr2IBokq|=Y-fuw zJNZjfO;0kDI%Upm=%ub;AA_%GKP=Jc)k-WZNs0(xc`VF#B1k2n(r~a5x4LV6@F_iw z3>KS+x7e*UGgp!fXMJO_V?Whm`N(3z1dCA-;`Y)lR}w7N6;ER~TwlmBQP4j;b-Ph; z4OW9a)J^GgKIP?TAdJe_<)J^J&M6J68mH3LvlC~#uFYrzX@z6U!?9me{kVytATmwm zJ`{_7R2M3p*N)X;MT>>!_snE??BCiC#3@yimDD1nkwAwEY{oRtoromMz0h1_|X%3SbQB+ zM000mk5_)JTOgPljOiu%LWUxqYH+KB$1Ac*?$o5t96 zrC{%xga!YzrDwl%9q(Hx63Hab#V%hH-y!&03z`haEo7t#Z&U4Ccxn1~d+c6th zB@@j6-QF^$OdJ)Yi=?Z|dokr9$oHR3C?1GIMzPX`ednroxRT7=+G7sDzdptyNbmJ;u1Bnxy#Z#h@SfLpn<{0r$ zUU$&0l_y=YZwkf9>dL5FqRbV`n}xS|T6G0&V>#_*r_7&btp5pg*@XC3lNg?F8H0S0 zW}Is97&nlzVZuvsQp|A-U8H9GFQCiLpem9|qhBDdVCy;rJg2LkrD{zeVB8D?+KuKl zR(*L^$wkY<_^5a=Ua?&1_=KilX2BY?nPBX&B6*j2P;kCCLX{#52eBk zdwi~+hDR+*pECNp9-Dgq{!0l5y!?@0yW?>X+tRgUF80H*p*bTz2#}IexX+H?oTY#G zh87YRI1(9WViqD+Dz=~TmeA6b$HZEL`gES=~@oXw8+eA!FE_Ad9EZ|d#k72V2j{gX(*)4~m|%+L zF5JJq9FJJ=WhQse%A9f0Q>JDl@e@nMhuXH9+CJ@S-TquycJkG?ur*oZ>vx zNA%b1yH)6XUC9`-O*+cvidicJ(eTjqe?2@DhdHqu-ifh2-?q{PVgx5f;QWF`^LCec z9?>9~&v%W6Yx9y_wtV{7-fM>jk?UQX&cgc<`Bz0SSzEz9`q=`dR7po$chtXb^K6E< zfOHc?EaNchVM0qpZxiKWEtUW9oSI%30tO`lFnsSRn~_5TJ-BoECw=jvC5n#>a*ui( z5Yv0i)8Oa%KD!lAGt*ufn4Tt|>CKx=IoMgYKX*E~HkL(lTVFe&NzncO_DKmi_qcD* z{W}7*d#sHsaDcXPNa0Y@wZ>kGTE_HG468M!*~_4O14+~>Yhvk|c`ZkJ9F@?PnpL{> zGg!wp-Qs$&bPY&%EH*i~VoZyvg+=l}o_3E^4v5MzKf{|3{c^r?X|?gnm;S=x zr9&~hC^*HE+qkS*515^Hx%=U1TrbS+$`Mt;~O`wT*wMtjZ5 zRlDDf#HDG^G;VhR^D{YUaR=XzEB_0Ad>i>O8xIv--+RhtBxKi)2z zH0)}ui8$2N#GB1nygO%OhtUy+w|UJ(c#k5a%S%be(osiCOiAN3R1ul^-ix3}8DX&K zBF<0A>p-?4cdj-O{Hn~<kn7n>yB4%1Ec24Jb@<|6gGH*+`jS9U=JhZ%|=5q}$&e zjT3l=ITZk6tYu#={FFZ}nkDlh*Qd{T?_NRs6$TYi*z`n84Os@>?FeJp)}m#LCqH38 zK}Hu!lV-06xV~cZDwL#GNnO##CF#9G=tD_Uf;cZ7B-0C;WqO4^G3XE62Qqcs>u1%F zMCy4-M99Wpn60Lsxd)QS4t^35+UG9(THM|98N9MmCYKH*$ay#mMWEjKRl>{y?5RXX zeu~yVd6Q740~Bt$4!)SBAf`;^DBK-NFf}mckvg<}kK|<2>)2{7mT0Q|!;{k21ql(@ zG>Ah_20Vjupq4icayaHEbbzw+El13B@WW3HIE+Ak@$%x`vADx}t5lLs?%zt=r#!L3 ztjou7MN6&z&Wr(EE~?yf`~-E8)d@E$M`n?rVy+7{IOOxvtsPVD!Sf+lAPWAG;c`HD zeP%f&!=N$1KoW>!YTwvUHP*msUHVLcg(T_fc@oVa$#oSBQAEmiwk8`VGlv(@dHPe$Y zkDW{K*p0|z+vw%EUhvFSWgP$x-HjgUbJdS?scy&%tb)IKfkU_8@I}2T;%H3l@YbII z3=TR7gC`R(_e0aX5xSop8EtO90P34&!&tC-T{S3Zq^ z1wCB`PgC2#VWl7Q9aiIOo%GZ7F%RlrKoT@wQEyyy-fE4O`E7n7`mmyP<)O~zg+)pccB9>l zfD;!^KRC!8kb9W;b`FmV#%O~f*Ulh;pfbOt_DO~1a1QEyl3_I!oP$#7u**Qgu*$kl z+ZywLSMI<2?ZiN@8D2@M$A(sUbNSac_p|qx53Lrn+O?MVSz|9Zp1!uE>TZv8ylHlP zJJ$2)d*vUIm=Y20?!VwENT>Tuvv;Cqu1*H7nVTkz2J*>W?_zL6j^ieFS<~2u3q8{B zU#X}qBnO*agJ9bgTfctbu#SOAEg-q&_irDT)t_anDZD)bwS^|1NLcCVySx_H|1-%L z%#RgI3Pas)qhjgLe_Jfwe2XX>hoI+UoK1sgJW8u>JO~#%2 z75@ud$QTLxbP9nBp;s5F>Gn_YO06dX=QB6E$II=kou$#1+cHVVO{W+S&;}_hDwFHn zyAARj*TFJY9Dk9BNAlNt{J4p+a1MnH0!AgCE31?VB57RMW+OgqUyiq7!zg7w*(v({ zjcA^apUM7j7ulhhR3wH6!tXsXf7U?84q5pR!lx6-An zc3Wq2eH&#~#=eVUt}6bRholD#>;+Wy|lKcFnb+uoY5Jkl1m zTbe%K{UV|=&47dT8y zC2_hyfJ$ctE%Oq4yp30Btpig7=-gs>ZGwMTH=~H$5NKB2<~6Hq@5qno@ez7ZrQpYc zhakuI$T-@lQx7n$|0jBFcagZX`#=7KRfgP_)R*fi)l)ulqF|PHg*h{Nyzx05*74dM zd_de*tmq12-iv-Q?_^c?o80!RqQ5~qc0kNisqA`FUp`-6G0bkXJK|dMJC5?6Vwu+7 z?1()QU)Cm? zh{>qx1Yk#RSF-HL3AiQa4HKrp+c(SJ3O}a*fpdS_|APAmhamSCBN%=vGJKt58SWML znY^*V8ul&S_qy;{fhpa#k5_KqS@ujr!Q7|8ZqzT^Ov=kc5{WEcA}K+u4oAAS$Kd>Z z+(cM)*b!VR{CL}BI5FEtIe8u>)_C0iLeJKu2KC7)1kXV)cd~4!%Hcg{TvsZBdq$7b z@=-b+*HppfDH$5|f9M~ch;#Q82lH&(0`%#RUe}y^56$=s{=7{(*fPXfdse zQC!M`aKbC>;Gn2v1|MtvWhKMYq!4TFcxPZSq+v zzF1PhSiXB;*eU5t7AyVcuhD(95Q9ltg<~+yR5-T{S0PORcWzHKjeRDCqoS}Wq*f>2 z#v>%bG`T1km;d|9d!yB(Q?Zh{h!*mLdmMBq?#t^8aa)UJ>p+?~8hG7lGEPfVMxSMx zaG&e+DEm(^Zz9gTd;S~dJrIr93jG$Yx%|D?qCAJK1Fh;cN3ck3msaYXbbG}YTHp~T zxFZWQX^wXNgM=IfKQt!s4UH|o9 z-EN$9_v4QG%bYhDt8(VyA*~cCYfVP#`*BV&2OIJJo$^L9FAJa{U%b-hLPUDR;i7@! z!78hjx}D7jH2A9W_Qk(N_Fq#@B#LBXi56Q~_+A5>gpog0i^0 z|K95@rZ*D!(+GhdTff*FzFb7emoABT5pBKqH{>7U|k_x5{dd5Koy46DPRhM*aQ zfBnG zi-Dhv@j&c`G~#t#S8-F()f2mfxwYm77yZbOyvPR^zh&S8uU}&@mhyRKBI}Uk;Si38Iqzn4UdiUGI8pfANJU|i_r11fk6MRD1|{xFy>qtcnW(x2!-gT+ zr3%GXQ~g{^xyZBTENROV99HL>rYK&f`@tSu2p<+YU5%gUwwVajIC-Svew+Z`Gfarg zy$GkZ>J%*U1ZK=ge00?{J&JE*BKVRqeg|8f{ zxKr@F^8`3fjJvEC4)7)n;{?z;;$6afoz1FT8lqA(+Dz%NddLf~n74<`7tpaR+x+wJ> z#Gv~lO6TC{)(+ODx&03t`O~FwJKeRcrI?;Q$nRl^z}N3)W)P;0I}n9dGFpiDi4ka_ z`_2EJrOn{0f+t0-c`n_|jcq%k8(o+1cz2vuonJ&_#Fv;W#+fMP+E$CcorBIr9VEI$I;W^vALzLfTn0DHGvu=r1PX-^$ ziU_cO*O4rnZ1*M8JMdGE?z0FT|4n-;Y9pl!%+Babk2$QH8ay>V#BP^&P@dApCuf)< zA-m(4i{YE0`t*Hba6N`@@_4+_177&@i>eil%MKs12)1_Lxhf}c4mazs8NDmh`=sYY1l_nbj@XQacxm1hZ^>bLum+Usc3)|G<5U=JyHB zqNGb#1BIhRhkS4np58FwM3viHJNmKT_cn=p_0m^Js+spmY~0~Se_gvoA$3w#lynX^ zbIX}3_R^g8Ynm(c>BH=e9`~f}9Mz_IIgI>RDc`d;Gvd0T!n&qfuUDt+nro~4HP3Gp zX4ZMlGjiV~YtH;9zrjojz{o85KmCSrUFMu_^N$`Ov2RKR3)W|2UNiq{ ziiKJYA30gg|BYLKU$ExeUjT5bBBb*G*R%S4!lj|4);dQ;zo2R9W0VgGcQ~&u>{0JY zahX>fL@%aIFZEu^HoQh{`DkmO^2p_WaZ8SD?D+HrN3T6q?6|C~9m{-{EZCqDJ#FkE z-9b5x*^FoK`r&&#`X7TlHPdC$P8{EvGU6(r|GUl#lb!KV&%B?wG~A|couezYKi15q zEyLzPL{Sp^db!)kJmCWi&T6CEeGlQ?g8E*7h<@(UZW@C}=^JgQX0lCE7n`PrLC9cFeG_TeFCcCP$* zWs+W3q(zZd@5j}xn?EsB-y^DHb`S3`&nJSp6*c}KnERkGX~T}*mg937OAny1B~QwF zPkYBwQY>8Z)m7RrHsutz#VNUdbhnQ3aa+2D7o+X>ec9rbN(Tk)UK}(mZUqNFu4Fzo zTHp4M%Fu+i_sz9lA=^JB*qLQ_?7FQpW=-+?=$aP|Vg6GN)ErmeezZJ3-9)FsdNh2! zOh;;`2YjM&M};ennaxD?#U~$69HBRKQfY#g=7$!r_l?~y($2!gYuLB80?Zs3fSF#Y zXBaSU9}_~2-Y#V&_dGQ^Rd!2~X{s)K zJ2%-ba~Bj(G3nEA3rZ^JsfOqG=S;*&6|tMF zYjQt7r{NYgg-l+)C|GmG@1w3DUii|s~528GhhfQ(w^L-5zP8+j?yp_T(D|(^S z71I!TIdW>#S1fOwL3htHytY@a!+vpu{uX^UFGffC^!P>!S4@&q-Q#b1m66w>7dMo? zeW$jtK7CGe`aUcJjXIeJUv*8FExnQx`k#VxE?^1qushLVrF}&i(QXjckSXcP1@U4~9 zCG*md)|@(*xUX*5pD6}sKXnAGYV|fR|ftk%JpSjnuspGMq&bX zr?JLl;$Db|*>FpVG;>d>aHu|gr&05sVqFPc^Uj$!{FprO-jY}BiMjS%i|N{d%wu*O zGy7?IGn(30?XP<_Koe^*-`Kk>=CEyt=j$0)B6a*-Snwe2`hb{*Lc_6?=~PuLfx z+};j;d}~y{ZOg*A$se+?8^tgSU(Oi-q~iJJkM`i zwD+}l^0w@Ay5`wBJy<4ZzbZ{Kb8HG{H~KwIZmEVZDc;#P5m&OEgTtOu@x*l`4b{p3 zD4L2Z``W7YwiPtj&b8yAb%A!NIvm?2{$fw1xc{N+oku>J+qPo#Z%)cn)2os<%&d@G zSg$BGA<@NSJNDe+0WQZJ8j?GdbjOD#?zgCR zmp;8_FW-^3R@hQLKD*NJuGBGp*GC(pr|r%=Cs^*04d23Ysqce=r}0Q~Y^;3gfHOaEd-Sd`RjXj(ETHz&~g3k(c)|B_&WODU7M;t zcSszeOB>WoMHH%Yk$qEC2OTJg^{BQ3&@LlQl(>N_9u1HTew{QDH+mj35@9rhytXbx z|7_wN_tx6DkTofMuzq&iucCnm9!Bw4#Y6F)YcWOJ$UOFORu1j3a7AOf!eoEenn%h! zPGYB#zk&zYosN1?X}#~qkA?JrM#NNk=l=g>a&4Go+hIhQm`A6(^$P!V8oW-j81g<&D*&dFIrb4EVcHWI~oHj_-5m{N?4%&bO8$4BhY} z>H_E+fL%W0ai1mX$7`PBSYeLSP;<$g@9#$s{y*y8JF2O4>jMsmf)y1jN*hr|QGr1O zr35P~Dk{wes3@o?h$tnLz*rCzP)9^TilX#l!$J!qDi(@J6O^uW2rZOAl5amJBtlsEmpK=o#hVpe{;IFJEc zvgn`F2nqKAv4>Mgn+_w@X*v=j-}Gyusq^aZ^IX346u&DD(wtwms-gmOGMe@&mCjrz zV|h@eXJu>(&&lXlJCP6bBBtsFS36B(C@_y!X3b1AJ(Q+YieW0B2O1HeB2M3IS@@Tg z0t`tW@R1>4DFTSv)8}}X(4*KbtvHayxqgo=y_Y;Qr(?D8{GuM=lD#j8XqS~x_SmvA7krLp!C;}(hm~pVR0z6S}lL$Cx@efuq@0^-dkl_?;TDV{4>d@ zNG}s*0_$9Zdsu*}ti|(iRd&-`Uey`1fiboC+=oxf7~Cz5kQ?^YHz8NEmV{L z=RkdtGLOE(-PEs?iNgRC%p@?(CGBw6kRMtvPb<*W{1`~B)oi>%dGqu}?)zq)Zxr+N z&kD#DwHWtQm^3>B0zjWpw@nXP&th|l(Q7-zfm4F(2)EP~7fFLu+|vAlj@X=uH*bnG z%^pn;fbjd%1E!z{WUM9ZyFVbNCP|ulgkBpFeAnl;6cW|?`x>v^yg4;w(QML4~+|km~F7;!vr|kq(km_8`VPO&A^DS%1G|Kp1 zUIZBUKSlr}pa!W}6H$OVP#Z_2rHAg*wMlu z)kXUd@FKgnKe(-NPx0V9%$G(yIJ4c9TvI%+%irzb&F#I1X^(r`_ErKC;2f!Fvlo2O z*8RjnZz)Q8e);t(_b{iz1KH^4j)O7XuPf_wzyo z{oi_k0hr^(PTMCMiTj&xF{5XbjSF|0rmYv{0!n2c1{Oo%-EP0L@*9>)#1Aaf8$vpa zcl&%kY?s5!ohOHtnDcUHgy)&&8LEGh-#F&$O=E@9RBkG090R2lkt)uYC7`k?yum!Aw^Efig1+9wFTnJeSpk=X&2a#E_gElo)YJIRdG*)z}H zFjmOtV(#hBI^8}%I+tovsLDl~n%zGB!394$W*UXBDBb^rmqL$eVBF%R(0>cybP465 zzYz1#N#OYvs~!@#GF;F910K*if$|(4aEviCWXf^?B%5a~N3tStIt@ob=HA5@gHHVf0XXdTL&DK5MVSLE7;I*^e7i9x(KIVt zIeX?CR##Jzm7b>y50~;>r=Ind8-25^d!2`Z*V4GR6&7a$cm>!J4Z0@}bLftUvPr_S(%sSzPm{DiJ8D_G-78V*^0vEhxSR@Ja|+jMmTx>806stJPKzklVtY;f z9EQB+zTH0N;hqD$m}Tc~_acXvHVFH+wsLcxPidPRW=jr`F1)9C+Y2PRwQVlJ zdS%cR_EyK*XHdPzK7YGEaVF)>{~`fPIoKwf<7q;OT!D}_9GBD}V6Iz521Pl8123gK za@?YH9kuXLw}O>sD=*?pZ>{FqBKusQtq_y259 zPZ79M`fv=cR6E1~|IRrlhf7D`Tt)}U{hg7Pkz~P<=A=lcH!o|xc+f1l0Fe6EKU8U@ z2z`r(>W|x(l1wS5bGw0WPL&NbmtSCf(q-=*A|24K*+$GsJ3Kym8tU*cFGZiu9@e)e;;6cL(=L$~jMD zu}|^n0e;`%o=1-xKB(+dINK!7(C@HK&7G-pHi%X+Pjd*MI44+2SsY}N8AN{jhe=UI zD{T_jBPrcsrrj)hD7ocTt_l~N2p;$B!9VgAp`YKPjdq-A#oRzVOT zzZjDHlwRv?tng?E@!#3VI->_7;I>o#m&SeY_S}E@xdqTi2acB~_}R$<%^-k6=I%W! zvVdN5yhx=fGCbfk*?7he2no7{BVG`s+NcS&Z~SvIu0|Q|;F-o9*i8VqzKoBXPnw#< zcyv1NS>=#D9O_N%Dsc`U!WG?iNblopuH=RWUQ7R<Acr}6W z5;#i@dFa*rtPhVXO`kA!B|;{b)$<)$3^#ElKXi-Eu)pum42m^ z)??sG9luh)IWo!$WGZq`qsoF=kn@-IWSRrB3Ar)Hc&kFaG*b-wDG8avR>Oau>re>y8KbyZpnx*#BDA9 zFO%zE#@^CS7A zSF+ya_X;%9$1cgDz zp!z2Kd1V$9X_1f=O9Bdh7Bvt-=Iz96a#YWuU-Dg+tf>M}t9VDtCJS{e!8 zmy07a>QzcqGrnORYCLj9?RVcXq=^TJ209fP=mpc2@q9jx$6OCiV62x3mGVj5G^h{MmOI!I@^?Hx%GYKX%K2Tfbz_ zx&LB%V@c@F%&+HqR^%xf7Y?RUMyjRD6y;DPzng6GAwZW^qNpK99voXB$xmW-FFZ8} zgQ!oayOzrL6vc8$DcBER_-*9AzGiBMpaBjTS1D*i=1cVm*otpoIdDOnPI743nmME8PL>eDiGBkC{Mw~8^<0i^w zA!59(|If5l_;Qh-zuXg&-3%%A@5e;>xmeuPTN0$J^R1*Ldykv4=BlLkA{}qJqSaW6 z8iw538?kf{hZF1lx1|(~OdGVD!}0;Iqe$>N?xeeu>jUT(}@1JQ$;QP~4)x%jJnWmbx9 zMEG%9Z_~oh^9qWD5fxhEa&mJ|n8CpB#tPT$uT&JtJF_Z+5koiD5z(Okj||VI#WuC_6MxM%sCKRqP_+!%^_s7 zG$gg3TZ5;mq%twOF;0zHe6gUyjJ`b1)3mc>FZW?gpDTYS&?bKeMS|)0Q~K7Sd0kQ0 zM^ABN-$(=o)$W<}Uv3$BiTXl-u=ta8sRU=|WQIA)B*4dKQHPJm|fj!VVCoR^vhnc31 zKttmWM6mxqf`-c5QCsU09vcR+^@*P8yUTFMb|~d9^?ZF#zT`w&;d|&vBw{}HLc>Vm z&G6xZKYzFffQ0Qouf>-~d)Z{Idt@Hv1P=+}-lFEBpga5;1&pJB+ZlC;E%MAv8><7IyhkI#~uLRv~9nzJ@C=P_nW zmf_|+*CQWL1hwXMhw|qqj#A}^hY0-q5Oi^{FVpnbR=o6@iKYCR%&T8wukn8Oh!OeS z7hwABNzm_uNKHJ`c9h{&i!wH$cKV8z>`hirV0-|D@Bfjuj7U2Lz8ln=_}yzT^-kNm z7yoW~Aq`OP%7%3{QAW?$k|A|7>bwIV8rz%}=h4^-9RY2@SoW3iMyf+4`2O8KF$F9c z9%rZJgs%g?1Q&Vyl7``w;srV3#tPLuobnjwFL6qS8p?R)6EYrQw8vDc`?q6w2PIo% zP=Pa;GEf`+y~TCY)8j{)>D9-!A54f^?95mc$;;{2`P8${aOsZa$IsSs$qLy(t6yC% z#iKjs=GHj|@Orhr(m?}UTD?-a28A)bjR!RK{3Xz2<|hWlYlaN|b5hZ=?m-!a>nrhE ze1gC#k~FPC=g&Q^N!ItvfA_+As`wy+$UR3xM+GNG5uHs|w5H=&Z9ZkAX>^yG&;L!58jYW;@tGte;{mQHq zUPtqcQ0X@_3|8`KtjmuLIK_jNo>Ko3R`R_AL^;wVLYNe3GSxXaW-sMWfcr7c?$lSk^Hg{wy5OwU=RwVq|h`n{Hi@3!5;aW6s){*7+yL`Wv z7fKnx7%Ph4qh%5+zOUdZNK{8^D3|+$XO3PkABr1B4y@xfI!a6D)A@~#X@~8o80l|C zM37FR=_@`Dmi?DJSjeg1$DWA)*e_OrF@75ydq|33cVuHzXRibNe*fY01N*J(3BR?( z$o$saWRUpbO6bG;ejJqGe|X%~-7t{z@`KKw{;3;kK}o2ev-(32^w>Er#CRlrZZQ-V zNf+?2`0W-{Mb?9z4{=(hg%G;{v4fNhH106}JX_pt#p%_|k;t8?GAYq?1SxW#RXs@+ zYJ}B+R5ai>Xq$NBBJQ`hYXiJakM#?3Ufs1EDr?SMS1SEj2m~9m%OepWSpgj8^RYAW z07>#tM}$O)O7RdJwiCo$cOXm2py@EotwP!0WNf#=>0@5(NPIJb0;c0%d}t#`G_VKGy;v*$Ynxu9DuWf>m zwr?YD<YcP{=10nGKN1_8h~BLP@^PYOl& z#0fN)RaTH%v%iBPka!vECaKsN*bm>wzm=~gxeItM;{z%GgR#z;)@R1)=Mw9;>o;m%3cN)1+Hd0jZAK7Ie|fZ>U-``g>=hkF|eL6H+7*ocN2m$VIkXI5?Z{ zBCm)%1qKZ7!-Hx}S=S>KtOjp~)S2YWRN0+a;o>l?o;@-b^jlkaf-WDjt-6RZ+RT89 z_}0Wv(;I*enZK26v{Fhol6k%FETd^*Ht6;c`o{QdIvaAW!t9;V-!WSGuMt7bT_+pfT$MxDx}j>9hnGtwoNo zw|zyVqH(HeS#!;>JMkR(+Ns)O&g1#=5l`0aul09dolFkmA5*Y0yJFr)aG@s zpdU|&`jf(_OUZtdWy{+IU{x1o(230i&M3%XaN95i?aldI2F#ZUfA1KAgy~#i(iBC) z^%qq%yErd>1;N#<&FF&0v<36g<9_K?MFFo9V~rIK0#d_*)N66}%*246WJf?$EPS^t z#C9#LQ!3xjWvi{6Oq1l22fgC|-r@9uYJXdiD$==qfA!O=P4BB@cR2KVZt)6ri-Rb- zouQ*I-#;%+1FdNpN_Sbm4ZBlpWPAWnQ1DM2s~TFBO}uV%-hHr^3TrGhwtQO=fqwYe z%J9RFu&JUi7y9|jub@h<=M{m>Ji((@fV8IzSTEkkv^G(oZ=)Ns{!AZg&+Yoa5B_5c zMJdI=-+{DCo!g**K-$Eo&*Hi7KTOtq_B&7jn+EY(j)hvjzIqlvvTBGt0v((xdeNy8kcES+me?wU^sg@zgOI%Y2N1mgZU#4y#p zg}!_n_T{chUCASyh?Rz@2_48=n!?wNsuH9uB^4rWxc;2afDON!t6A+YW`MGE1Jo6u z;nmQNxb+Wip#F_!j(qM+;V7x@INMQvNg1%j-QeJqk}8TnzkhE zqh0unUoV=v8Az4CgBO7`mJO$`clL!Oy{lF+;w@ZfRMJ>3rMFOnP=E*24|Dk4syAQo zVZA@jpla7eJqul%F$#S799UaLt(-z?k(%DCE`MU1q2;Z&D^Rw!nswLHBGVBWu!0f4 zo{ci|9`<5tsUD1iSpM}ZGNiGA;{ngttb`Uuf>q4w(_BB)+}-9EIXwi5LJs8kkSsGk zb`3KOauXVKU!Hux^PRq#s7K(h>LJPx&5AOoG)U5)S?g-tEFbLFFPa;n1PD%a`gUr= z-BLwKw4?5_A%e-d&5nQ?tO*7wzr=9m6PX3njzsDcvl+N)lLX0YAPXgTh%4gDGfoJ? zCal>Ewu~)J-Z`x~Fvj=JkV2(FpXt0MA+6{f?zE!XYaOZQ&SQM2$jt*nvs?ADDtyoC zR*@^PhT;qQ{wJT~qnjob+``i7NOJe56LYYj@Fs@uqZqm!*j^S3-w(dSR52dGLPIz) zG@#Cnnd3x9d^n988n9Q4HYvdOPj%NMet#??Yc#29;|EO@Wza<0F0NBz1jghl`aqtv zopF}APBiCY$1Q~M#Gy_XhVksA&A?g>P#Cm04iDh4D*_sSU%KAoM*RX!btSlsDa3d9 zjPodhf^2b*sMml=X|qX*!P)PlB{VE9fL?1$|6v?q*pCji8h?&l$uG-pP31@X()x^|JW0+IBJy?dc2zR4ZOAw6jt#KA_JDf)|Xq(6!#TT<)M#OB><7Rj8 z!*@B{39LD%V*`_zSaIy(G`wZyhxXTSn_+n=4wV=qT7lvBXxynz!XiLpz0|mpUrG$# zM(eP(um5;g4EcT_uQOJ)80ql4&U{Dm^v!=G;KvPLN?p;zcr&20fsAWoA8#z zcn`FDqK5a|-yS``{Wa{jUqJZnPrz@l7No}DS2gZyu>Ei>uFoGNkMT{7Hz3Z<1`b9oNC1r3$&Zd!791UAiM#u(&;{5yi z)pHmUNjO%AQn$)E-Tw|K4kw8CD=Nb*ui<6bsaXK<-`Nnj znplN7lCioK2EFC7^E7IX`IJ3CJ-Ec*U<#Qd{=SCo#DJ2S zyDOZ(M+UZ6HzrVFWji#2ht}h|E%=+ZIEX+gHr1Pe1YyhnS;RA6efwYs(b)G+;Qg1x zM|%&9A}hes|M^5KK#8;Ruli&7XwXphZ!E=JbhdfW%D>p)Y&G8t%`I|OeLv36ac{W& zV!(1g#Ad@#J8k3R7qBdWM|*zG-^2y1;pAqsOiDu}HEw8&c;&mlX-V-uB!}M#a!5kH zbQv`U?|xNNS=9A*6%YuvSjCtNPn1#(61|Q_&0nCcUtFHwsoagrs2Y>4R@fP=^<@5X z6z2992S9GkodrK>`f3PN|3?>ecgI70EV9OpZwpncQCRcU^v6TRId_H`M`~Jd@4-{? zp97n|{P_y?Oz#7UUZD-=P?>yQ0Q3@8nL0SCiZn{X|h#WO=t@VO+(S8KX z5pAqZAYK!D*bR?S`Y(A50I0;rTtttl-fqZ8F4|!U2Rz62zv4MfNH)F%+5G!+o^t?H zWrtO<-pQ@0xRu91Ss?QPKLgKc*q`9Dr&cM&#>OoNqb~^zdxu_&@fyh<{5tgE`1x?d_}4V4R@vNnT`%31o!(}++6^!0EM!Nt zo(pwEc!mR^8bwQ`-i2-1&bJXonNR8@X_*Q?`_R{pRxM0c?r|F;(&}e-GF#lQ)YZA` za?$Dtx2B}uu(f5t3ogmtS=uo?z0QS+2+~l_!e#Leg~v%T-_MhHvKZ%q<{_rib=1AO z-nt~1UEZ(n?;BczN65{N=-vRhW5fbc$OD$}FtR|dmmpB%wmA-JtQUjzE-Q9+5=)Fy zpbPc7JspsJyU)CY?qC!PU~wi7m!aOVGB0+_Zu<)O5-h*dPxR-nULHn>&k0L;Rq>Qp zdj%N9da;GL=Ta1jgXSlC$RBDp+4W3R?ltx~1@o}hplc%v(ZCC!+9SR|7QNuJ>};MY zO}#Z0UGXs>8in(yGl~a>So6UL&)ugYob1|)_xNDhBtcFunaz4MP^6=_fMYA4@-~D@ zQ!lom1K?N4Q>>Bh1sy9wwy}q38|bjojLn_+oWghy09_B8xtQ0ErDt%!B)U8$ zA-d@u-@q%+ji_41J0j%IlHhB91z&sVm(7xVUwdGx8oQQy&6P1NLH0J>tZM1+RsZ;z z03nY!3bnTbh3{NK_?`ygd+M5N^NHcxfuy}QohhOkz2_PBh?HF^4kr3V*Ldv+2b%DR zVrhXG2y0Fdg$NQw*rq82QOrT>@cNq;?BDzwTvGbdMR&OQK*ccl;AjCxR&*gzyd{XD z5|IX<3whxvz8D&vo6auMd9j)GIM~EIk5=hl_AiYs%}pa3_kKWH+vD;GhhWneLgcm? zKV6i+>1+}I-ksy(;OE_dc&Vy4AHO3cKQ+VJt z+6kvF-8-svb}ZDWI5UVNwj+$YZN&N%vk3CgNAkEa-C;o~b!LQ{0D7&R1`DCD{uH+6{NGk3=++2w0dIaR|Cs?``Vx#Cq zO~ZE@F2Y8vzr$1h2n_wsk*({JEQUUe$`w3_e|^a>{{peOxH0X+-NjDA0CfVHph^sB z*LiUzzIJ6uWBWKdi*%B%zkWgK(p|z!bSLuzi1o($)4bZrYCG&&*f2Q*+hT+`bHg;} zQb<7spgyi&0t%4pI(psxA7V(-W|m$jb$XYRD8d!Q-}04<-a7KQf-fc$G2G%a&{;gw zLk)Z&4tgADFGn9({FdppO*snDsY;>EsLiKxp08eWgFhxIS!r1Gw&oHP{J&#x-K~5Z1o_GlsQl{eycEBItM5E1j zadw@UAk-jk6{3d`QsT(qK4g0RfDJcg>@D}UE7({8uu>k|-Osp( zjfU~T1#kGj4_t9V(;U7&HqCm}efoQpiOv3$<*m=)7VC4-^44`JthJ3}H-B3*T{h#T zVA#!HB9`BDyC#2S?oSn}j>a zHM4yBZ^D@hN9Zlev|T5SzsmiSF+o6*wEOP*$-KWHjh`d55okQ8yT{yqeHVHSX(7eQ zd-VOEpQOw?HcS1fNYguxc`Z*c0*+4)vM5d8{%>hC{#2B0m(XSnOQ3zIa~ev=cJE9507cCbwKtlEkVY6hE6nvYkt3$6Pc3sgVvt)s|SVU;{b(pqLvWBA%X`0!MISz06ccTjCG(Mt` z(eIq&nT{;!(BM{@AP4{PBp;EK9^6w8~AAPOmhM!9bQQ7m2kZ2>_P z8BM@{KIbOwEH^IRqY0h?-gxa5$2d#Nc{C9&Sh{0>746qkF6i5&EbL7v=evxxi48F5$d2CF(BR8^tHR)`Rm6d zWt0v0K-N4sDgEA9cgQuDn5pU<5gr=)N*PebZWt$2H&27%Ks}4iFdR4s4F^_8)^*pZ zoAZYQk6r2BofgWyzh}BH%JeZ9Bs%H^mpGEj3*ZtBeg(78@5Ki5^arXIP|CNIRxiix zIUCd}wPJE16Y>*VTGk z#E-f?y8JdZ5j9Sd!uavyO3&$5tN|3>uOdf2mv~eljM5tYp(JN#>6#%vYa4qKc6i#V zkFp+S_5av29cK04qFMdto~zRObLa49^~D!x8qtStnU>6o2{-{RoqL-1^vT{cH&yT> zU*q9KW&SOjM&T!~p{mS26~MCxcOeSAkEwh?PAip(ZBVAzTeMcbU2e33Zm}g?sZLC$ zakWx%VszOip24@DK*hi>Q7z~f_l{Wc9QnCbDTwd z^9S&S(@Ez%?mZV!{h)$btdq1l|9j<8x6S8xmO}b=tLfZ#-w=nwQ_j}YB=nF*+jYt_ zy`R|{Bx)M=LtIopif&lLTxEGE_vr6rGryy7-10ZwL-KKNU%+CB-X6tB)ylc}VhHp5 zSxqc-Zu`)R_Oi8%>ywApRCyUCw1(t9uETHs-gSGuOuTEEtBS4$3^z@1z#~W4)G7h@ zwZA*y7Jmxe)_$4J5cn9~v7PO3=&|z`Zt6eq`{;ND3tj;{((!-!3VtLx;4k}D0_yxv zklsVeSRNN$HoF#V{W-FAHyh`d_87XCKN$E&=%2<A2+i(|L+Cn?g^t2V9~d!xMSA|q7}S;h2>eW_HQb<(&p!qd`=o;>EL#xwdo zSMdw|-YX}-r8d};6u#?NjKc42A@KpHOI1E`&!t-TPEX*b?r?y(vsrH z#y71-dWo0^+eq|aYr*c-gz*%(YU&(T2kra`R+XXm>fXxMWAOtjh7-$t8nvubm@730 zF`92!KUe|%gYi=ZQEuAkKMZLjlPit|L~%%xswNFpR#0ELuR|-Y?p8A0e-ygOanzMc zHCq@@i*o{FT-R7{?X~?{^t`cpPuWN&jNzP6n1`M>m0%rJ0b*d}W?G~Zp}a7Xv8W1! zu%22!#_0XQ^8CT;6Tx@Thn}L$e@gGO04qyGCzuCFSpQs?4HHQKejBD+`+k`6&wF2; zJc#NpcvP=)K<}tzu}d|1LBxIC0S25-@6Q!pn)UXP56?a(k52nou7@1gxapJZkMni` z;9_!9g;3vDP7f{rgICPY5xNR&l@%$F4pZcLrlR|Gh&9Rw~W&*gGoH`&`dKsL?O7pXhrqa(hd^`l22BT$y2>>MYH^k zcPU;WZ_hwgvW>CfQ#o8dSq^o;&~YErSBy)rQBdy5jLc)-to8s$Sa$xmCsx^Av?t0? z;I7D<5gxEqMg`rKFPM}6Nc{7YYn4OCuMFtUpBbOTqfjOp^8080?4R1R-*$lgV z)m_G1k@ljz+Dn+!^0JCwY-P|FfSc00#AvFu82b=KKOihSg8=5$VR3yB)yVn1{4)0Y(Q?Aa_&-v`z`!M|C zSG&s%j;Npy{KG8Y_^D6$u;ur23^;z&!Saj59IWqxkRz#TcKVrTTY2RqoIQj>MHaom z{KkE4-Wv=reh0}EEp2raRX_eh^Z6xTIaI2y>YwSl;VT?>A1;t<4FkzRh#&_kBnMae z9SMRQ0%5^(yw;|BQsJ`m!66qEh*zule;Q2wcI)^}*$+k32U_e4O%8>9w?hUKTs91J z?nvuzgWU0-502yVyMVVMibuviS0sVnG&_4-0#kRO^({^3WIL5&&WEFmBL1k%Dk%s| z0pR#!eYsDx#W9_{k(EO?lEWB+9A+aqn9zgD`53C2Py{T&O<+oUxm;PYFdwc(^nE~> zO7pRt^1ztXA6;#44W2v=ua{8y7P4=BmKb1afDC!3-#a;f_@ZN6lM^7nWAO@Wa5hOuxr#G*(BA&RU+Q6w+LB9a(I7rukL5fF$~xUmR++9LIO20QpEwN z&D#`C#dFo_{;A`SBJyJEzB~MoFIzN>iM)3RM2%I%sDZM0TD{2={eOuX@=^hPoGH@v z;U-SPKhnFGd-t8Cn$b|(Zc@Bsla_V3%8s-bD6DXC)6b110NTPPfSjGtzZK11$8q; z%G>Bh69!EC%h(-h^vxw$6nuXxyk-i3xc=xMQn-psno+~d%uiO$1>H3(GsPgz+Yu$S z21zK(*&=`-AtsD^254(ZTZ7|DU={tP5um&<6WrAQr^^joL>K2{^!62q^m)3HL=vdL~y3AZra8zb( zDNVJOPFUMv4TV*JTymE4mz|ldFE^agKxlN%`@{zMvbQ^jtq#8Opk9D9z_R0`cUAQ$ z&kyDJmdfCw$zTE#?}^s(nK_j)=ruIKJZczxt}Py8iu!#&CStmV0WHf<#i;XL^YK20 z-ta*!=8aAw8EzaxxGY8C(voIouft1Ns;2ISMc|9${B)`QQCgdpH*zLua6F(X^u`c@ zUEKCoz4~&R^;Q*KbxH*iQARZK;aun_rn-bYd_v0JitHz)9?y*P7J-i=53nAq<328< z37|>u(yRxMsoyZ2Tcp-@&N!eaQHR2uc%k17cXVIWof=((*G$+m)E)d4ze!UE7AdTP)ET&{hqJF8{ZZD|xYUZxy(D;Saj;mE&bNC?X(%Ib$i-8e(9Os{*Et_C z=KJSy9&FgE|6v{J!g*IZIi|FUPJPq}-Z_1QJXTNc}V< zklyX3({OI{Gpe+TS$PiH!r$z{*l(esjuGfT zZjDDF#`UjX0jmcf#MH{TuYHwXB2{$a$IGDjfF-3W>77*8$0pZpMHZ*bll{IXK$Bki zdOOO(EFC*jI%l?iTn9TWtYJ0cKTeg1MpY!uhTyf9BCqwNLM}yy*N!+P0taue&d?C5 za!-BM>~~y#8WdtzO={&iCA7GT63q8IhL0 zW&Y%PlgDEGsOU+ez;Sx$8INIA!9P=3-?DWlHgcTGQqZ7vgG-fg(@=e?VS09!0{Em43Jp6b~;R86{; zV%cy-=15jwhk$eEM#GbPM=j7VN4EN5yvsGtqZBe>kQ-w_UfrKV~1hq`|A~1}4KjO)XC91zHY2;)+`|gy8BS2#F`*#?8=-^0b%N(rS z`3!2WAg()J3L6?mJjll?L34$+508x+L0~8v1FU?!TLkQH2r4d&bvyGv273Y>p^F-R z;t8WZC1^mRHI;r0CbNrH+YLo|+F-}iDIWp&n{9)NE@#xQXD+LPlYv+RZ2L306*R12 zpD!N8y|{-H@(!u_I4_GmsCnc3IcIwxC$@wAxXGzE>uw+FzP|AO#;Tf8A<9ga>mNYsGqM-uVX%}Hw$=Ug=17aB49d29$IS#Hk> zs<#}eURz2y-k$Izq0MvgZokHS?3}8-&75s>7Jd62)KS=KHjI;&|8+WkwjN!S2vtsj@5s_2+ zzIR+MD4{L-Z0>|*nK65=Z$iy|hWha^O^snD>zPgh#tZ#M3cpUtlZBKf&&B4`lH_Rj64lx{jB|jP(RQ&~ZH9qp zTznacDVQK8CnP2(`W0V-n8JZ0R^!^&Sa6T|WZbNz`w0k{N!f_lBk!Y?8#RWqgT1Fl zJ`N>eaVV7F3?z{=s8A0#=jWd1GFrgly=J!SuV6?N=`Q8yl2rcer-Ackc9rL_eC;cG zp91=PJeb!oS0#tof2P5{*0BCJa}atK0*#HDMB`I~V}`4@VfChcsyj;y&w1LhA}6kQ z!*jk)P7#0u&FA+?xovFRNw6mqW$@JO?}fL|NK$V`CRrC7EK|ecEB&C(~a+&>Hl)ZPy?q2heSn0auO(BjlunN_t?4%t zY*_3Y$`zDPTCPzgS5W0VL4~?$v>whe2dI#C3pEVNP+xXMqCnf8A+q>m&AV{Y*1NII z7XT3KW-^X*{6p>YV5b@|F%yD`twJWYitfFgU}8Wo+pIFst}K79DNlTN;q_#u^vnBn zanxLvi_E>>)%Qdr{_K;8?&pk^Sgy};HX(Bb$&{? z=&Frh+B5a;o1X5V2_2ZmDjUdl=>1{y!;Fp%W*rYs<}m~~HfST=uydTg?wkZ&1Nt?B zYnMi@-BIt%W}a)Wn))l;X<5m7)S(g1*f~ z`ZkyDwVbbSld#$-j&oJN*s>RJsUOtw2R717^4w-0Wp|Y)Nv6p?eH*|Apvp(ZFzC-A zYE2r`vFxO%6y^nGd0z0ItHf{>eqXgvO78FuPs#J-KvK{WX}HQyk7N{qizdVJoG-U6 zncaQ<owL)qdoU1$$MkVrJbL`377wmhVa7`JPrNWalny^?U0GJ`e?~ z`)m+ZoHJm$U0_CO9*Jo!4jy&n%JKl3KlQFkI_w^M+ypGnNj&f;$S<}#kNUJLCf*pClB& zW+K&pKW_#F!%jIRSq0XmF4?HAdcv=(dXk2Xcc6gX38jrO(hA~YO&-x3@KBCdrFST_*bKkcEM!P+ky$aOA( zrh!$|@fnW!Ma7osDIcm{kt^v3QS~c+mWOduKlzUY$Zd28S(6RHnzkZqx=p{3K(HoM zO?~oP6&gWy&e*?<+u!zG1)iGo+99n3(WVRs9+v}a%Dy{w1j%b0PhhUC%;8H#V0xc6 zdX0y|g`51>@X)(kUB@Vm=Qs=9J6E<2Sf;CgwWAHVVPp2i{=5cC-?@Yl>7bytgE9`S zxS&d-FV$hK4xW*FgLI4CB49UEIjOUedlRc4t8`2q58|c^0$YVzlTy)q%%>el>s&OI%PklQ`bQti z-%Mctq5a&ecr`L)8v7{tK8oP^qnFrfV{ zK00Q0+N&fkG<@w<^qWAf#6WCnGe~ehl7DFo1o5mEq8lmg_YgyEg7a~ahBF44YB zzx(@GxAeDAiIzVxtl1Z8ZN2Tmo9jEcgrlP0G3pc|9gfTxR6G;ON0Xp$%9y^T3MUhq z5NQ0#h@4&6`018jL8z;F!cZ$>GQ-Eg18Qlk3c3XU;EXL2NUB2Y+>whj$KGH*?GnMK zA(Ea}t>&k({Dfvr7#PteBdzQiCtrpug+>HuvB$f0?rpk@YVXl#N>6J%Q3dpxA38k- zP``*pcb~!!obv@)(8No0xdmt)yoo&UmX``lSvuNW!}osV>R1H+p&KLur#R|i_^j8t zj0PZtw7K3|oXqrn3ppC4nmRtrExe0Lt>bnmDl<`!^=uu#nHMGxt7C_^$Li#U5;QWN zpuGqH$MEfAXc52Wo{z4Nj%R3PU-^ubjVPGqqfIb}F~O7*1Y?Q>qd+y{H@_4`9Dz4= zx7hRcy+-=c?8wFkQtSW{^Z9BwcD93R&+2`yLuocynfU+$8a?W6UQuyl6@%0bif_hrZ=!r@=kgevl!zmg+fDEO%ux>gN$gh`*s! zt<5~|13%}4J#<}p^qoBB($?%YlScddDV=dOh(K|l??v-*$R+M(w0*!q#}=m+*= zjUs}oNg`Dfbui*H_PN8i7E*gHs-xU=CKrmuK!L;Sh4=14Z3wyaW=If##9zi`D2&`3 z!U9Y}Vt85b4e|Hes&iuq66%D5>~md@E_M!Aj|rHMtS3)W(O9<$=Ao~rJIjo!@*wh> z6rzq0CX0JeC!CeN=NgW>!8q>J{)Tmz{l^v2qdX{U8J41a5ZiRps479Ddl7s+Kp0Fw zLFZxUDtQ8WjdlZdve)VE2`%55_I-`H);4O7I}c1O*Ifg+Z)jfvEJj(78ZqKrR|Xb* zr10SL1%Wp`ofi1Y3htVq0nugKR|B{BZHVN~UyuSch0in81nSBmYY;uPQOzy%IVo~~uktLJFuuuqEj#s7+{U9}H zG0)k;cL-BFir_+01p8CXea&Y(S-#>?at5Gp8-_5Pwy|hKm7YrpILNQ_(eUj~Cw|NVij2{aMdMl`l?CGSsSz@_GLXX5s6|YaZ)r8X(5Fgu-Y8 z45P6+RTB?H2Sg!N_>y_skdRvgizK15`t>zVQgA$Hz24D0+|O~E8xVj)+D@UxUzD0n?lKHU^o5LDaJuO(ub%KpQ=p91aU%K25=4+eG0SVI8Pw<>B zuaF%Zaod@_pa@Z5-t6TL`B1z+C-8OwpnY~lmrbkp!pt>HFkyq4p~k~Fm-zvv-%s@X z)vKh@+KBURpFQvBG0y*Xor@yG>_q(8*Xx(B%O zuo`kjXtzw{Q^v879b`FU9vyfTKF1a|s0FG2#d8!z(16b|tsm>QcP!}D>pIU|g;x)g z8Dn0CpmJzInQF|?EHk$v8mS6m#dc^b*x@5(+EXA3y{rBZN5~d919{{szopkZ^|ihi zwqkz!{Y;)?P%%gcka2L@k%4q{RHvw?779GsYiL5F*`ZL|*>U)Gc)dcVQ%5izGzYM1 z|80N1L*NcyF?VjP!KygQT4yc3aMI>PFGpi##rRlRjA{3T5-zT|aYE!QD`x8P?P$2+ zq~I{{ux231C=(>30g}07`QZvdGHB{I-|si>GEO-PB~h4XIuo;-5Six?VM@DcL*j@{ zX-}wsJ%+TBFf{WT6?Kjg*_-e*y8-x&_ZxKPVkmJv6qG;POrKzW|vV*%Prk*584e}b=Ra0wh(A@G_7wpjV5 zc~=uqo}Jv9&h(1GY$&;BTOkybi^m%(P%c<;CuSF1(7&wWY6^Tm*yOj;V;Be_zsdoC zum_)PlJi}0i^113*4d$`?j!d9n}^9!8u*Bme!Rj-*N2R)!wfAyMk*u?LI z?(i$vYGJ+Z^F1#7YL23`%LGJb8g~R{{-8vyv)*Qy)-W>xwy`ug>G;gpzO1<0spt-x zF#Ret469fU-T~ygE*ozt%z-3yYUZ^)gsO*=7fLWhm)XWIf6R>zRbCr~2Jeg7x&*QeQqMKi(9KT8nz!-KKoFO5xm@a@cM%Y7j+u z4MZLMH5t7K59yuz+ZcWy3mg6Y+~T(sG2>lEvtzTdL)n@Fo~@;$4GrmeSLgDzZIU1h z#naU3HfakmQIhBW<7Hy@@)MCs--g`9XJop;ZFrrO}zyr&%^%; z;b5usGJRl1Jn(huQE{Pkb{D}+M{LQ8b^6UG^^F%7?Y;e1ChUy#GdBUi9R zYVNbG=0T?8G3qm&&-?Dc6r{xmJec+(Duwg6IUDe-x-XH_lU2#KcimLhk^lPPZ{O}k z%G|V=c0~41ju6>tSrNAOBxrdj+32&ruuEs(o5p4{vBpQxXHb3t-2ctkZ33o*$|uQ? zVcQ0p_69*a5qKq+0YQkAdu1BmGfeTQCAl9>5Z$b<6{vQzaHZyA+2aC7WXC&-Xdj%v zJPeyBoVPc4c{+EVu#7iPC_4O%O2tSHTZ;Nz4EGG~LWqD!5)8-3>=w0`pwm&zt2bEr zLOBXOqrN;{cnevS25wRA0LqiD%r3%3Bmk!(x=TFoxA-lBjpgW$2034>tP6*H-)uUI zmK{C1iEpT5+%tY*#NF$*OD$=4LA{|JTJLaDY#3PoYcOki&$lLlD^NEaNR8qnRf-~$ zphQJa%Jy5dYeEiZ)R%S(FCi%{#ijIcJH*)HJv#}rCW=5uXko}K?h5z1v8IbAb`Dro zp$&~`IFzjzJDPZL$8L)Oe{}v|yy?KyQy`~9iK3hLNNw9PcLnXgpf37|)kTD16BTd~ z58rw%Ar!5h0;KnLuA4qEkM4@Q*S~NI;*s8yds_d5kNRA`HmXpcy)_8+S%;Go;!x*K zWxD|%CV|1NO6ov~d2gt0=!%5(U|LuF79|;i$j~B)(Ot^wB9U3(A`?K(p}s3o1RCQF zxIa-VLlQ1d@^Slhb!oznCKn`#a?}i_MJeCwBidP-;1<| zdg3_bJw^!&{WlCwC5!{vf%8+e%#^^LpF5l~egzBtJRDDkOL=d9X7%#&1lTD6%&eHD z+|d)khU8I(3@t{`-AkP5d;kUCx)U$f;o13aK!(QGW9zQqS+esmMxZdC5okJj6mgkW z{D2EDD^+oCeg#28w9KIZ~=s?Vo8`sXS^;|#2)$mkL9`Na$LoB?qnqhT_f+2$S zhOS*WG>qi7Vi|-?+{X1#8~MPT^YVDAj@@kU6P_$x!@MfAetzx~2A$!$dmnp^bKg&Z zSlhDEL=EyriC`-3^ujO7Ie6SF%ldvm&Bvf{(xjv!OozYP~XfN5Mr~I>v=HOid#CLr{>lbed zhZ3*~6tjM(ej@z>C9wAE{0-08Y3ZU?AIV2We|lPF+Cpe)a=hpiSk(Lqj+Pw3_OJu; zKN6c5qN`ClD33dkrvP7u{rFQ37Z|oGLx>Y5uztVPb@xk|M$b&W4@2kTr~VmBX@eOV zLuYt1ZDw?*XwTy}Z+4%g^ifsOKJD(DbQ&F z3%(H05$$f`KP)`_1k2e~s`w`LlcW~0{gm#k`_s!tc3SVV8A>$j2ooUx_OhYbuv)1V z?w6X^O`mG}p&FX(BGmaZhC2NuO_;10-Y$; zN)xyl`466#qN$-4t{3k1(M^UbS$>+kbecARwQC2@jhkxgx=HXCU&;Rtrznh)j=8wA zuR@!H?g;TsEFgo^Yr~-&t?1XTUX&=rS+B(cQ|r_;95udDqupv5+F zz3P%zu-0eG?|=yGngGHZI!;5e9l6f?6s$j0!!J)VD%o%0eS-M=v|()gm4nuf7h{(Q zbn8?!uiKR#`Jt+Y-1uJj!f)5Fd~%sjsT39!_|BHkV4BXn zQp)1%Xz`|3NJTTBua`B$l?AK0aT>2{TKxmbm_2(x!*wK1`InswE)=K^u+y6oab~)&n%Bnn8||F2Bun12Ho^J%0m$&zXzkcEDM5HBS_1+w z>ZA3CZ_`BuvP(~S4)uH7)CJhHNp1r|52-_@1`}Bj(q{B)cZ5hrox)sX+kbEm4oDmCkNQ)FCa`B*pV36p|&_IHy&-=dR#weK=RIi-{8DfJG%cQ=+e*fsSn zKdWA#)ab(KO87DUgSC@tNdkiGiKGevK_L2HbwWzAF-aif&}HM56q&Kle3%RE`gM?(BC{ zJ>L0BLZZd)DQN=(>bVBwBdoUN?E~h`fz}K;`sXuo*3R>FB-w*`7HTExG`mSE$>~A* zSq{-(Z~Jbpj}3KLrnkd1TBt9%XfIha{%lSIvu3M*@6niGH%W4V)z>CE+j2?hZqri9 z_oR&COgXMV;jJ0!n3RP?T7+&=`)T{rnU4=f@8g^_DKM>kSi{<|E7N<`hX&@cKk}WQ zYH{R38uNa88lP;K#$4NJ#2TFC$~kVLoXnQ%VU{YFi=`Vg%Io*dHKKoxXSUV`aU5#B zG%u>LjvDSu(=~q(?$+QiXG-Q+v|WzU!?oZBDdZW^ci9Tutj`ieXadteLlQl*uo{_*I+8C$|u zk`(=6x@@)l;qw?{vrQE-p_TXO zWA!h}1khEj$C+cFN&K;Y;{=s?N+4Aw?4|aZKu}UjrvV4V^tV-Oi1wIL(E9a)^ zGr{b5|A9+cE{|a`9+j9 z)^{kUJ&R|zQ6oCNe)yMMnCYWj#G;g5l}QW+C;6&c$7L?VX(^L;7JCNS_nu&7^|hC$RLKafh3}GBmp^- zKxC7Cy9qRr&h(cWJMX`p%}!?bd!P3?-rY?IF=zLIwiO>2$ulcWnk^)#ydpEi%T_ma zw0EYguL>0y>8rbLx0OiEo3J#+`*SGJ2Kn^sk8KI}on+M=uTETG9{nu%RC-nrW4n|B zFMV@7@$21&fN=a}&EX#_6p&Y9@z_H&raT|47Mh;7XATu|HKBx|wbWA3dV9>Gv*wvb zHLfuYmU~vYXX<6DCRO^T%as93E% z;+mXjJ=fxYnmIMg+vUn9OS$bfa7s9B>l%uSr%-G!INUgPrXy`$p4n{zp_d6me2^r;77^ycu?H1VpzEjxudd|tTj zOu7C}%H-y97LAzCza-CJw|H4)Q~t zy7!pt1Y4&PSP@HNX-hL7G?*qDTG%dmT7{0!$-*^C$qm0R1xe?lWwyd5W6e^sZp>mI zlCKacNh*{=-kdI?etW4lf;X=Hja$VhrlbA#MbWCQS6AaY6gwD`z0c~5*FA1voBd=u zzu`%o94R8V8{u{`Tjw2NIbJd9qDJ0OosL_!M_1K`>a}inztYq6&g?4k3O5c)Q@m?~ z^JWC+^HozuQExq*Wu}F0-q;}J`WnhX73CMnkbw%F#vU^j&obv$GRru2hB4*qc*38t z?VM8%i)ngk+O+g&BmE$^|;;4ET^unGrK`?j~pNQqB zqO-B%Z zHqN-M@!Me`Qm)~#$Xk?$vzwGC(e8?R_0B?bbnL#Ukv5tdOVZR<;Yy08(xy!xhK0~; z<^A1Q(y@-_CVN<>-D%Y3Im8lPEA2<_Oyn-asVl4* zD8uC*>e{0vSp$=3#e!vWW58 z8lLwNooeS59YtU{7Ia!|b&Ku{RL{JmA=Y|6a7`o~l!V}I$mf~4$PBkP1av234_*`$ zRwxo8d7{7?J>6oL>eNff1o_W&A}88lowL=wVgFxYIC2=v=(bVsN<_U2b5?s>hcedu zP9=9rX-RgbHvX85>dvXJ{iJ6{?bajC>bc30~7YmF!QK@RdP3Bw@jkkfzuAOAL_l&AG9I}J8`q(ziRWXr#mJNjG5Dy zVI1~c7%%|4O8a5#zkGUMDNEv8*pk4>jSIS3tDOeu;$=?phF$p zIgkgChXWvhJRAVgBeK?I0rGIb3Xq2bR{jspV?zSlW1FuK_eC}sTfT&`_}an^2mS_| C9n6pb literal 0 HcmV?d00001 From e3d9ca29ae13688d6539830a29d2462d5ece0441 Mon Sep 17 00:00:00 2001 From: Sebastian Piaskowy Date: Mon, 29 Sep 2025 10:48:36 +0200 Subject: [PATCH 2/4] Extend typegpu-react API --- packages/typegpu-react/src/index.ts | 3 + .../typegpu-react/src/use-mirrored-uniform.ts | 2 +- packages/typegpu-react/src/use-render.ts | 182 ++++++++++++++---- .../typegpu-react/src/use-uniform-value.ts | 2 +- 4 files changed, 152 insertions(+), 37 deletions(-) diff --git a/packages/typegpu-react/src/index.ts b/packages/typegpu-react/src/index.ts index 5d1e878c4..313e031f7 100644 --- a/packages/typegpu-react/src/index.ts +++ b/packages/typegpu-react/src/index.ts @@ -1,4 +1,7 @@ export { useFrame } from './use-frame.ts'; export { useRender } from './use-render.ts'; export { useUniformValue } from './use-uniform-value.ts'; +export type { UniformValue } from './use-uniform-value.ts'; export { useMirroredUniform } from './use-mirrored-uniform.ts'; +export type { MirroredValue } from './use-mirrored-uniform.ts'; +export { useRoot } from './root-context.tsx'; diff --git a/packages/typegpu-react/src/use-mirrored-uniform.ts b/packages/typegpu-react/src/use-mirrored-uniform.ts index c408a189f..7987d88aa 100644 --- a/packages/typegpu-react/src/use-mirrored-uniform.ts +++ b/packages/typegpu-react/src/use-mirrored-uniform.ts @@ -3,7 +3,7 @@ import { useRoot } from './root-context.tsx'; import { useEffect, useMemo, useRef, useState } from 'react'; import type { ValidateUniformSchema } from 'typegpu'; -interface MirroredValue { +export interface MirroredValue { schema: TSchema; readonly $: d.InferGPU; } diff --git a/packages/typegpu-react/src/use-render.ts b/packages/typegpu-react/src/use-render.ts index fdbbe45e2..e4cb74ddc 100644 --- a/packages/typegpu-react/src/use-render.ts +++ b/packages/typegpu-react/src/use-render.ts @@ -1,44 +1,106 @@ -import * as d from 'typegpu/data'; -import tgpu from 'typegpu'; +import type * as d from 'typegpu/data'; +import tgpu, { + type TgpuBuffer, + type TgpuVertexLayout, + type VertexFlag, +} from 'typegpu'; import { useRoot } from './root-context.tsx'; import { useMemo, useRef } from 'react'; import { useFrame } from './use-frame.ts'; +import type { + FragmentInConstrained, + FragmentOutConstrained, +} from '../../typegpu/src/core/function/tgpuFragmentFn.ts'; +import type { + VertexInConstrained, + VertexOutConstrained, +} from '../../typegpu/src/core/function/tgpuVertexFn.ts'; +import type { OmitBuiltins } from '../../typegpu/src/builtin.ts'; type InferRecord = { [K in keyof T]: d.Infer; }; -export interface UseRenderOptions { - vertex?: () => void; +export interface UseRenderOptions< + VIn extends VertexInConstrained, + VOut extends VertexOutConstrained, + FIn extends FragmentInConstrained, + FOut extends FragmentOutConstrained, + TData extends d.WgslArray | d.Disarray, +> { + /** + * The input layout for the vertex shader. + */ + vertexIn: VIn; + + /** + * The output layout for the vertex shader. + */ + vertexOut: VOut; + + /** + * A kernel function that runs per-vertex on the GPU. + */ + vertex: (input: InferRecord) => InferRecord; + + /** + * The input layout for the fragment shader. + */ + fragmentIn: FIn; + + /** + * The output layout for the fragment shader. + */ + fragmentOut: FOut; /** * A kernel function that runs per-pixel on the GPU. */ - fragment: (input: InferRecord) => d.v4f; -} + fragment: (input: InferRecord) => d.Infer; -const DefaultVarying = { - uv: d.vec2f, -}; + /** + * Layout describing the data structure in the vertex buffer. + */ + vertexLayout?: TgpuVertexLayout; -const fullScreenTriangle = tgpu['~unstable'].vertexFn({ - in: { vertexIndex: d.builtin.vertexIndex }, - out: { pos: d.builtin.position, ...DefaultVarying }, -})((input) => { - const pos = [d.vec2f(-1, -1), d.vec2f(3, -1), d.vec2f(-1, 3)]; - const uv = [d.vec2f(0, 1), d.vec2f(2, 1), d.vec2f(0, -1)]; + /** + * Buffer with model geometry. + */ + vertexBuffer?: TgpuBuffer & VertexFlag; - return { - pos: d.vec4f(pos[input.vertexIndex] as d.v2f, 0, 1), - uv: uv[input.vertexIndex] as d.v2f, - }; -}); + /** + * The number of vertices to draw. + */ + vertexCount: number; + + /** + * Enables depth testing. Defaults to `false`. + */ + depthTest?: boolean; +} const presentationFormat = navigator.gpu.getPreferredCanvasFormat(); -export function useRender(options: UseRenderOptions) { +export function useRender< + VIn extends VertexInConstrained, + VOut extends VertexOutConstrained, + FIn extends VertexOutConstrained & FragmentInConstrained, + FOut extends FragmentOutConstrained, + TData extends d.WgslArray | d.Disarray, +>( + options: + & UseRenderOptions< + VIn, + VOut, + FIn, + FOut, + TData + > + & { fragmentIn?: OmitBuiltins }, +) { const ref = useRef(null); const ctxRef = useRef(null); + const depthTextureRef = useRef(null); const root = useRoot(); // Only considering the first passed-in fragment function. @@ -46,21 +108,44 @@ export function useRender(options: UseRenderOptions) { // but we can make this more robust by computing a hash with unplugin-typegpu. // TODO: You can also use the React Nook trick to track functions based on their // place in the code. Simpler and more reliable? ((x)=>x)`` + const vertexRef = useRef(options.vertex); const fragmentRef = useRef(options.fragment); + // biome-ignore lint/correctness/useExhaustiveDependencies: This value needs to be stable + const vertexFn = useMemo(() => { + return tgpu['~unstable'].vertexFn({ + in: options.vertexIn, + out: options.vertexOut, + })(vertexRef.current); + }, []); + + // biome-ignore lint/correctness/useExhaustiveDependencies: This value needs to be stable const fragmentFn = useMemo(() => { return tgpu['~unstable'].fragmentFn({ - in: { ...DefaultVarying }, - out: d.vec4f, + in: options.fragmentIn, + out: options.fragmentOut, })(fragmentRef.current); }, []); + // biome-ignore lint/correctness/useExhaustiveDependencies: This value needs to be stable const pipeline = useMemo(() => { - return root['~unstable'] - .withVertex(fullScreenTriangle, {}) - .withFragment(fragmentFn, { format: presentationFormat }) - .createPipeline(); - }, [root, fragmentFn]); + let pipelineBuilder = root['~unstable'] + .withVertex( + vertexFn, + options.vertexLayout ? options.vertexLayout.attrib : undefined, + ) + .withFragment(fragmentFn, { format: presentationFormat }); + + if (options.depthTest) { + pipelineBuilder = pipelineBuilder.withDepthStencil({ + format: 'depth24plus', + depthWriteEnabled: true, + depthCompare: 'less', + }); + } + + return pipelineBuilder.createPipeline(); + }, [root, options]); useFrame(() => { const canvas = ref.current; @@ -70,16 +155,43 @@ export function useRender(options: UseRenderOptions) { ctxRef.current.configure({ device: root.device, format: presentationFormat, + alphaMode: 'premultiplied', + }); + } + + if ( + options.depthTest && + (depthTextureRef.current === null || + depthTextureRef.current.width !== canvas.width) + ) { + depthTextureRef.current?.destroy(); + depthTextureRef.current = root.device.createTexture({ + size: [canvas.width, canvas.height], + format: 'depth24plus', + usage: GPUTextureUsage.RENDER_ATTACHMENT, + }); + } + + let renderPass = pipeline.withColorAttachment({ + view: ctxRef.current.getCurrentTexture().createView(), + loadOp: 'load', + storeOp: 'store', + }); + + if (options.depthTest) { + renderPass = renderPass.withDepthStencilAttachment({ + view: depthTextureRef.current.createView(), + depthClearValue: 1.0, + depthLoadOp: 'clear', + depthStoreOp: 'store', }); } - pipeline - .withColorAttachment({ - view: ctxRef.current.getCurrentTexture().createView(), - loadOp: 'load', - storeOp: 'store', - }) - .draw(3); + if (options.vertexLayout && options.vertexBuffer) { + renderPass = renderPass.with(options.vertexLayout, options.vertexBuffer); + } + + renderPass.draw(options.vertexCount); }); return { ref }; diff --git a/packages/typegpu-react/src/use-uniform-value.ts b/packages/typegpu-react/src/use-uniform-value.ts index 9330c47f3..63a7d05cb 100644 --- a/packages/typegpu-react/src/use-uniform-value.ts +++ b/packages/typegpu-react/src/use-uniform-value.ts @@ -3,7 +3,7 @@ import { useRoot } from './root-context.tsx'; import { useEffect, useMemo, useRef, useState } from 'react'; import type { ValidateUniformSchema } from 'typegpu'; -interface UniformValue> { +export interface UniformValue> { schema: TSchema; value: TValue; readonly $: d.InferGPU; From dba1d2ee41b04b8e8ac10ea428e1264393f0e355 Mon Sep 17 00:00:00 2001 From: Sebastian Piaskowy Date: Mon, 29 Sep 2025 10:49:08 +0200 Subject: [PATCH 3/4] Implement 3D monkey example with new API --- .../src/examples/react/3d-monkey/index.html | 3 +- .../src/examples/react/3d-monkey/index.tsx | 174 ++++++++---------- .../examples/react/3d-monkey/load-model.ts | 18 +- .../react/3d-monkey/monkey-renderer.tsx | 72 ++++++++ .../src/examples/react/3d-monkey/render.ts | 52 ------ .../src/examples/react/3d-monkey/schemas.ts | 7 +- .../src/examples/react/triangle/index.tsx | 58 ++---- 7 files changed, 184 insertions(+), 200 deletions(-) create mode 100644 apps/typegpu-docs/src/examples/react/3d-monkey/monkey-renderer.tsx delete mode 100644 apps/typegpu-docs/src/examples/react/3d-monkey/render.ts diff --git a/apps/typegpu-docs/src/examples/react/3d-monkey/index.html b/apps/typegpu-docs/src/examples/react/3d-monkey/index.html index b8b02d5f5..974ed97c0 100644 --- a/apps/typegpu-docs/src/examples/react/3d-monkey/index.html +++ b/apps/typegpu-docs/src/examples/react/3d-monkey/index.html @@ -1,2 +1 @@ - - +
diff --git a/apps/typegpu-docs/src/examples/react/3d-monkey/index.tsx b/apps/typegpu-docs/src/examples/react/3d-monkey/index.tsx index f533ca327..d0f584349 100644 --- a/apps/typegpu-docs/src/examples/react/3d-monkey/index.tsx +++ b/apps/typegpu-docs/src/examples/react/3d-monkey/index.tsx @@ -1,103 +1,89 @@ -import tgpu from 'typegpu'; +import { useEffect, useState } from 'react'; +import { + useFrame, + useMirroredUniform, + useRoot, + useUniformValue, +} from '@typegpu/react'; import * as d from 'typegpu/data'; import * as m from 'wgpu-matrix'; -import { fragmentShader, vertexShader } from './render.ts'; -import { loadModel } from './load-model.ts'; -import { bindGroupLayout, modelVertexLayout, Uniforms } from './schemas.ts'; - -// setup - -const canvas = document.querySelector('canvas') as HTMLCanvasElement; -const context = canvas.getContext('webgpu') as GPUCanvasContext; -const presentationFormat = navigator.gpu.getPreferredCanvasFormat(); -const root = await tgpu.init(); - -context.configure({ - device: root.device, - format: presentationFormat, - alphaMode: 'premultiplied', -}); - -// models - -const monkeyModel = await loadModel( - root, - '/TypeGPU/assets/3d-monkey/monkey.obj', -); - -// buffers - -const uniformsBuffer = root.createBuffer(Uniforms).$usage('uniform'); - -// bind groups - -const bindGroup = root.createBindGroup(bindGroupLayout, { - uniforms: uniformsBuffer, -}); - -// pipelines - -const renderPipeline = root['~unstable'] - .withVertex(vertexShader, modelVertexLayout.attrib) - .withFragment(fragmentShader, { format: presentationFormat }) - .withDepthStencil({ - format: 'depth24plus', - depthWriteEnabled: true, - depthCompare: 'less', - }) - .createPipeline(); - -const depthTexture = root.device.createTexture({ - size: [canvas.width, canvas.height], - format: 'depth24plus', - usage: GPUTextureUsage.RENDER_ATTACHMENT, -}); - -// frame - -function frame(time: DOMHighResTimeStamp) { - const modelMatrix = m.mat4.rotationY(time / 1000, d.mat4x4f()); - m.mat4.scale(modelMatrix, [0.5, 0.5, 0.5], modelMatrix); // optional scaling +import { loadModel, type Model } from './load-model.ts'; +import { Uniforms } from './schemas.ts'; +import { MonkeyRenderer } from './monkey-renderer.tsx'; + +let changeMonkeyColor: () => void; + +function App() { + const root = useRoot(); + const [model, setModel] = useState(null); + const [currentModelColor, setCurrentModelColor] = useState( + d.vec3f(1.0, 0.5, 0.2), + ); // initial color - orange + + changeMonkeyColor = () => { + setCurrentModelColor(d.vec3f(Math.random(), Math.random(), Math.random())); + }; + + const time = useUniformValue(d.f32, 0); + const modelColor = useMirroredUniform(d.vec3f, currentModelColor); + const uniforms = useUniformValue(Uniforms); + + // Model loading + useEffect(() => { + loadModel(root, '/TypeGPU/assets/3d-monkey/monkey.obj').then(setModel); + }, [root]); + + // Animation loop + useFrame(() => { + time.value = performance.now() / 1000; + const modelMatrix = m.mat4.rotationY(time.value, d.mat4x4f()); + m.mat4.scale(modelMatrix, [0.5, 0.5, 0.5], modelMatrix); + + const viewMatrix = m.mat4.lookAt([0, 0, -3], [0, 0, 0], [0, 1, 0]); + const projectionMatrix = m.mat4.perspective(Math.PI / 4, 16 / 9, 0.1, 100); + const viewProjectionMatrix = m.mat4.multiply( + projectionMatrix, + viewMatrix, + d.mat4x4f(), + ); + + uniforms.value = { modelMatrix, viewProjectionMatrix }; + }); - const viewMatrix = m.mat4.lookAt([0, 0, -3], [0, 0, 0], [0, 1, 0]); - const projectionMatrix = m.mat4.perspective( - Math.PI / 4, - canvas.clientWidth / canvas.clientHeight, - 0.1, - 100, - ); - const viewProjectionMatrix = m.mat4.multiply( - projectionMatrix, - viewMatrix, - d.mat4x4f(), + return ( +
+ {model + ? ( + + ) + :
Loading...
} +
); +} - const clearColor = [0.1, 0.2, 0.3, 1.0]; +// #region Example controls and cleanup - uniformsBuffer.write({ - modelMatrix, - viewProjectionMatrix, - }); +import { createRoot } from 'react-dom/client'; - renderPipeline - .withColorAttachment({ - view: context.getCurrentTexture().createView(), - clearValue: clearColor, - loadOp: 'clear', - storeOp: 'store', - }) - .withDepthStencilAttachment({ - view: depthTexture.createView(), - depthClearValue: 1.0, - depthLoadOp: 'clear', - depthStoreOp: 'store', - }) - .with(modelVertexLayout, monkeyModel.vertexBuffer) - .with(bindGroupLayout, bindGroup) - .draw(monkeyModel.polygonCount, 1); // 1 instance - - root['~unstable'].flush(); - requestAnimationFrame(frame); +const reactRoot = createRoot( + document.getElementById('example-app') as HTMLDivElement, +); +reactRoot.render(); + +export const controls = { + 'Monkey color': { + onButtonClick: () => { + changeMonkeyColor(); + }, + }, +}; + +export function onCleanup() { + setTimeout(() => reactRoot.unmount(), 0); } -requestAnimationFrame(frame); +// #endregion diff --git a/apps/typegpu-docs/src/examples/react/3d-monkey/load-model.ts b/apps/typegpu-docs/src/examples/react/3d-monkey/load-model.ts index 8f7f367d4..1e9a6bd77 100644 --- a/apps/typegpu-docs/src/examples/react/3d-monkey/load-model.ts +++ b/apps/typegpu-docs/src/examples/react/3d-monkey/load-model.ts @@ -1,13 +1,29 @@ import { load } from '@loaders.gl/core'; import { OBJLoader } from '@loaders.gl/obj'; +import type { TgpuBuffer, VertexFlag } from 'typegpu'; import type { TgpuRoot } from 'typegpu'; import * as d from 'typegpu/data'; import { modelVertexLayout } from './schemas.ts'; +export type ModelVertex = d.WgslArray< + d.WgslStruct<{ + readonly modelPosition: d.Vec3f; + readonly modelNormal: d.Vec3f; + readonly textureUV: d.Vec2f; + }> +>; + +export type VertexBuffer = TgpuBuffer & VertexFlag; + +export type Model = { + vertexBuffer: VertexBuffer; + polygonCount: number; +}; + export async function loadModel( root: TgpuRoot, modelPath: string, -) { +): Promise { const modelMesh = await load(modelPath, OBJLoader); const polygonCount = modelMesh.attributes.POSITION.value.length / 3; diff --git a/apps/typegpu-docs/src/examples/react/3d-monkey/monkey-renderer.tsx b/apps/typegpu-docs/src/examples/react/3d-monkey/monkey-renderer.tsx new file mode 100644 index 000000000..d0fe8cf1a --- /dev/null +++ b/apps/typegpu-docs/src/examples/react/3d-monkey/monkey-renderer.tsx @@ -0,0 +1,72 @@ +import { + type MirroredValue, + type UniformValue, + useRender, +} from '@typegpu/react'; +import * as d from 'typegpu/data'; +import * as std from 'typegpu/std'; +import type { Model } from './load-model.ts'; +import { + ModelFragmentInput, + ModelVertexInput, + modelVertexLayout, + ModelVertexOutput, + type Uniforms, +} from './schemas.ts'; + +export function MonkeyRenderer({ + model, + uniforms, + modelColor, +}: { + model: Model; + uniforms: UniformValue>; + modelColor: MirroredValue; +}) { + const { ref } = useRender({ + vertexIn: ModelVertexInput, + vertexOut: ModelVertexOutput, + vertex: (input) => { + 'kernel'; + const worldPosition = std.mul( + uniforms.$.modelMatrix, + d.vec4f(input.modelPosition, 1.0), + ); + const canvasPosition = std.mul( + uniforms.$.viewProjectionMatrix, + worldPosition, + ); + + const worldNormal = std.normalize( + std.mul(uniforms.$.modelMatrix, d.vec4f(input.modelNormal, 0.0)).xyz, + ); + + return { + canvasPosition: canvasPosition, + worldNormal: worldNormal, + }; + }, + fragmentIn: ModelFragmentInput, + fragmentOut: d.vec4f, + fragment: (input) => { + 'kernel'; + const lightDirection = std.normalize(d.vec3f(0.5, 0.5, -1.0)); + const ambientLight = 0.2; + + const diffuseStrength = std.max( + std.dot(input.worldNormal, lightDirection), + 0.0, + ); + const finalLight = ambientLight + diffuseStrength * (1.0 - ambientLight); + const finalColor = std.mul(finalLight, modelColor.$); + + return d.vec4f(finalColor, 1.0); + }, + vertexBuffer: model.vertexBuffer, + vertexCount: model.polygonCount, + vertexLayout: modelVertexLayout, + depthTest: true, + }); + + return ; +} diff --git a/apps/typegpu-docs/src/examples/react/3d-monkey/render.ts b/apps/typegpu-docs/src/examples/react/3d-monkey/render.ts deleted file mode 100644 index 263a1f40d..000000000 --- a/apps/typegpu-docs/src/examples/react/3d-monkey/render.ts +++ /dev/null @@ -1,52 +0,0 @@ -import tgpu from 'typegpu'; -import * as d from 'typegpu/data'; -import * as std from 'typegpu/std'; -import { - bindGroupLayout, - ModelVertexInput, - ModelVertexOutput, -} from './schemas.ts'; - -export const vertexShader = tgpu['~unstable'].vertexFn({ - in: ModelVertexInput, - out: ModelVertexOutput, -})((input) => { - const worldPosition = std.mul( - bindGroupLayout.$.uniforms.modelMatrix, - d.vec4f(input.modelPosition, 1.0), - ); - const canvasPosition = std.mul( - bindGroupLayout.$.uniforms.viewProjectionMatrix, - worldPosition, - ); - - const worldNormal = std.normalize( - std.mul( - bindGroupLayout.$.uniforms.modelMatrix, - d.vec4f(input.modelNormal, 0.0), - ).xyz, - ); - - return { - canvasPosition: canvasPosition, - worldNormal: worldNormal, - }; -}); - -export const fragmentShader = tgpu['~unstable'].fragmentFn({ - in: ModelVertexOutput, - out: d.vec4f, -})((input) => { - const baseColor = d.vec3f(1.0, 0.5, 0.2); // monkey color - orange - const lightDirection = std.normalize(d.vec3f(0.5, 0.5, -1.0)); - const ambientLight = 0.2; - - const diffuseStrength = std.max( - std.dot(input.worldNormal, lightDirection), - 0.0, - ); - const finalLight = ambientLight + diffuseStrength * (1.0 - ambientLight); - const finalColor = std.mul(finalLight, baseColor); - - return d.vec4f(finalColor, 1.0); -}); diff --git a/apps/typegpu-docs/src/examples/react/3d-monkey/schemas.ts b/apps/typegpu-docs/src/examples/react/3d-monkey/schemas.ts index 4c75d0023..6f6fa75bc 100644 --- a/apps/typegpu-docs/src/examples/react/3d-monkey/schemas.ts +++ b/apps/typegpu-docs/src/examples/react/3d-monkey/schemas.ts @@ -4,7 +4,6 @@ import * as d from 'typegpu/data'; export const ModelVertexInput = { modelPosition: d.vec3f, modelNormal: d.vec3f, - textureUV: d.vec2f, // field can be removed } as const; export const ModelVertexOutput = { @@ -12,6 +11,8 @@ export const ModelVertexOutput = { worldNormal: d.vec3f, } as const; +export const ModelFragmentInput = ModelVertexOutput; + export const Uniforms = d.struct({ viewProjectionMatrix: d.mat4x4f, modelMatrix: d.mat4x4f, @@ -20,7 +21,3 @@ export const Uniforms = d.struct({ export const modelVertexLayout = tgpu.vertexLayout((n: number) => d.arrayOf(d.struct(ModelVertexInput), n) ); - -export const bindGroupLayout = tgpu.bindGroupLayout({ - uniforms: { uniform: Uniforms }, -}); diff --git a/apps/typegpu-docs/src/examples/react/triangle/index.tsx b/apps/typegpu-docs/src/examples/react/triangle/index.tsx index 4626f459d..49f1d9a99 100644 --- a/apps/typegpu-docs/src/examples/react/triangle/index.tsx +++ b/apps/typegpu-docs/src/examples/react/triangle/index.tsx @@ -1,61 +1,36 @@ import * as d from 'typegpu/data'; -import { - useFrame, - useMirroredUniform, - useRender, - useUniformValue, -} from '@typegpu/react'; +import { useFrame, useRender, useUniformValue } from '@typegpu/react'; import { hsvToRgb } from '@typegpu/color'; -// TODO: We can come up with a more sophisticated example later -function ColorBox(props: { color: d.v3f }) { - const color = useMirroredUniform(d.vec3f, props.color); - - const { ref } = useRender({ - fragment: () => { - 'kernel'; - return d.vec4f(color.$, 1); - }, - }); - - return ( - - ); -} - -let randomizeColor: () => void; - function App() { - const [currentColor, setCurrentColor] = useState(d.vec3f(1, 0, 0)); const time = useUniformValue(d.f32, 0); - randomizeColor = () => { - setCurrentColor(d.vec3f(Math.random(), Math.random(), Math.random())); - }; - useFrame(() => { time.value = performance.now() / 1000; }); const { ref } = useRender({ + vertex: ({ vertexIndex }) => { + 'kernel'; + const pos = [d.vec2f(-1, -1), d.vec2f(3, -1), d.vec2f(-1, 3)]; + const uv = [d.vec2f(0, 1), d.vec2f(2, 1), d.vec2f(0, -1)]; + + return { + pos: d.vec4f(pos[vertexIndex] as d.v2f, 0, 1), + uv: uv[vertexIndex] as d.v2f, + }; + }, fragment: () => { 'kernel'; const t = time.$; const rgb = hsvToRgb(d.vec3f(t * 0.5, 1, 1)); - return d.vec4f(rgb, 1); }, }); return ( -
+
-
); } @@ -63,20 +38,11 @@ function App() { // #region Example controls and cleanup import { createRoot } from 'react-dom/client'; -import { useState } from 'react'; const reactRoot = createRoot( document.getElementById('example-app') as HTMLDivElement, ); reactRoot.render(); -export const controls = { - 'Randomize box color': { - onButtonClick: () => { - randomizeColor(); - }, - }, -}; - export function onCleanup() { setTimeout(() => reactRoot.unmount(), 0); } From df8f03f16e0d522711a7ab7d310f301d99f92e2b Mon Sep 17 00:00:00 2001 From: Sebastian Piaskowy Date: Thu, 2 Oct 2025 16:39:23 +0200 Subject: [PATCH 4/4] Improve layout and canvas resizing --- .../src/examples/react/3d-monkey/index.html | 6 ++++- .../src/examples/react/3d-monkey/index.tsx | 18 ++++++--------- .../react/3d-monkey/monkey-renderer.tsx | 22 ++++++++++++++++++- 3 files changed, 33 insertions(+), 13 deletions(-) diff --git a/apps/typegpu-docs/src/examples/react/3d-monkey/index.html b/apps/typegpu-docs/src/examples/react/3d-monkey/index.html index 974ed97c0..4cbda6940 100644 --- a/apps/typegpu-docs/src/examples/react/3d-monkey/index.html +++ b/apps/typegpu-docs/src/examples/react/3d-monkey/index.html @@ -1 +1,5 @@ -
+
+
diff --git a/apps/typegpu-docs/src/examples/react/3d-monkey/index.tsx b/apps/typegpu-docs/src/examples/react/3d-monkey/index.tsx index d0f584349..5eafaa98c 100644 --- a/apps/typegpu-docs/src/examples/react/3d-monkey/index.tsx +++ b/apps/typegpu-docs/src/examples/react/3d-monkey/index.tsx @@ -50,18 +50,14 @@ function App() { uniforms.value = { modelMatrix, viewProjectionMatrix }; }); + if (!model) return null; + return ( -
- {model - ? ( - - ) - :
Loading...
} -
+ ); } diff --git a/apps/typegpu-docs/src/examples/react/3d-monkey/monkey-renderer.tsx b/apps/typegpu-docs/src/examples/react/3d-monkey/monkey-renderer.tsx index d0fe8cf1a..688b3cb3e 100644 --- a/apps/typegpu-docs/src/examples/react/3d-monkey/monkey-renderer.tsx +++ b/apps/typegpu-docs/src/examples/react/3d-monkey/monkey-renderer.tsx @@ -3,6 +3,7 @@ import { type UniformValue, useRender, } from '@typegpu/react'; +import { useEffect } from 'react'; import * as d from 'typegpu/data'; import * as std from 'typegpu/std'; import type { Model } from './load-model.ts'; @@ -68,5 +69,24 @@ export function MonkeyRenderer({ depthTest: true, }); - return ; + // Ensure canvas pixel resolution matches its display size + useEffect(() => { + const canvas = ref.current; + if (!canvas) return; + const resize = () => { + canvas.width = canvas.clientWidth * window.devicePixelRatio; + canvas.height = canvas.clientHeight * window.devicePixelRatio; + }; + const observer = new window.ResizeObserver(resize); + observer.observe(canvas); + resize(); + return () => observer.disconnect(); + }, [ref]); + + return ( + + ); }