@mml-io/3d-web-client-core 0.10.1 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/build/index.js CHANGED
@@ -34,6 +34,9 @@ var round = (n, digits) => {
34
34
  var ease = (target, n, factor) => {
35
35
  return round((target - n) * factor, 5);
36
36
  };
37
+ function clamp(value, min, max) {
38
+ return Math.min(Math.max(value, min), max);
39
+ }
37
40
  var remap = (value, minValue, maxValue, minScaledValue, maxScaledValue) => {
38
41
  return minScaledValue + (maxScaledValue - minScaledValue) * (value - minValue) / (maxValue - minValue);
39
42
  };
@@ -106,6 +109,8 @@ var CameraManager = class {
106
109
  this.targetDistance = this.initialDistance;
107
110
  this.distance = this.initialDistance;
108
111
  this.desiredDistance = this.initialDistance;
112
+ this.phi = Math.PI / 2;
113
+ this.theta = Math.PI / 2;
109
114
  this.dragging = false;
110
115
  this.target = new Vector32(0, 1.55, 0);
111
116
  this.hadTarget = false;
@@ -174,17 +179,24 @@ var CameraManager = class {
174
179
  this.setTarget(target);
175
180
  }
176
181
  reverseUpdateFromPositions() {
177
- if (this.phi === null || this.theta == null)
178
- return;
179
182
  const dx = this.camera.position.x - this.target.x;
180
183
  const dy = this.camera.position.y - this.target.y;
181
184
  const dz = this.camera.position.z - this.target.z;
182
185
  this.targetDistance = Math.sqrt(dx * dx + dy * dy + dz * dz);
183
- this.targetTheta = (this.theta + 2 * Math.PI) % (2 * Math.PI);
184
- this.targetPhi = Math.max(0, Math.min(Math.PI, this.phi));
186
+ this.targetTheta = Math.atan2(dz, dx);
187
+ this.targetPhi = Math.acos(dy / this.targetDistance);
185
188
  this.phi = this.targetPhi;
186
189
  this.theta = this.targetTheta;
187
190
  this.distance = this.targetDistance;
191
+ this.desiredDistance = this.targetDistance;
192
+ this.targetFOV = remap(
193
+ this.targetDistance,
194
+ this.minDistance,
195
+ this.maxDistance,
196
+ this.minFOV,
197
+ this.maxFOV
198
+ );
199
+ this.fov = this.targetFOV;
188
200
  }
189
201
  adjustCameraPosition() {
190
202
  this.rayCaster.set(
@@ -244,14 +256,13 @@ var CameraManager = class {
244
256
  };
245
257
 
246
258
  // src/character/Character.ts
247
- import { Color as Color3, Vector3 as Vector35 } from "three";
259
+ import { Color as Color3, Group, Vector3 as Vector34 } from "three";
248
260
 
249
261
  // src/character/CharacterModel.ts
250
262
  import {
251
263
  AnimationClip,
252
264
  AnimationMixer,
253
265
  LoopRepeat,
254
- MeshStandardMaterial,
255
266
  Object3D
256
267
  } from "three";
257
268
 
@@ -659,36 +670,10 @@ var CharacterModel = class {
659
670
  );
660
671
  this.applyMaterialToAllSkinnedMeshes(this.material);
661
672
  }
662
- updateAnimation(targetAnimation, deltaTime) {
663
- var _a;
673
+ updateAnimation(targetAnimation) {
664
674
  if (this.currentAnimation !== targetAnimation) {
665
675
  this.transitionToAnimation(targetAnimation);
666
676
  }
667
- (_a = this.animationMixer) == null ? void 0 : _a.update(deltaTime);
668
- }
669
- hideMaterialByMeshName(meshName) {
670
- if (!this.mesh)
671
- return;
672
- this.mesh.traverse((child) => {
673
- if (child.type === "Bone" && child.name === "mixamorigHeadTop_End") {
674
- this.headBone = child;
675
- }
676
- if (child.type === "SkinnedMesh" && child.name === meshName) {
677
- child.material = new MeshStandardMaterial({
678
- color: 16711680,
679
- transparent: true,
680
- opacity: 0
681
- });
682
- }
683
- });
684
- }
685
- setShadows(mesh, castShadow = true, receiveShadow = true) {
686
- mesh.traverse((child) => {
687
- if (child.type === "SkinnedMesh") {
688
- child.castShadow = castShadow;
689
- child.receiveShadow = receiveShadow;
690
- }
691
- });
692
677
  }
693
678
  applyMaterialToAllSkinnedMeshes(material) {
694
679
  if (!this.mesh)
@@ -699,11 +684,6 @@ var CharacterModel = class {
699
684
  }
700
685
  });
701
686
  }
702
- initAnimationMixer() {
703
- if (this.animationMixer !== null || this.mesh === null)
704
- return;
705
- this.animationMixer = new AnimationMixer(this.mesh);
706
- }
707
687
  async loadMainMesh() {
708
688
  const mainMeshUrl = this.characterDescription.meshFileUrl;
709
689
  const scale = this.characterDescription.modelScale;
@@ -717,12 +697,17 @@ var CharacterModel = class {
717
697
  this.mesh.add(model);
718
698
  this.mesh.name = name;
719
699
  this.mesh.scale.set(scale, scale, scale);
720
- this.setShadows(this.mesh);
700
+ this.mesh.traverse((child) => {
701
+ if (child.type === "SkinnedMesh") {
702
+ child.castShadow = true;
703
+ child.receiveShadow = true;
704
+ }
705
+ });
706
+ this.animationMixer = new AnimationMixer(this.mesh);
721
707
  }
722
708
  }
723
709
  async setAnimationFromFile(animationFileUrl, animationType) {
724
710
  return new Promise(async (resolve, reject) => {
725
- this.initAnimationMixer();
726
711
  const animation = await this.characterModelLoader.load(animationFileUrl, "animation");
727
712
  if (typeof animation !== "undefined" && animation instanceof AnimationClip) {
728
713
  this.animations[animationType] = this.animationMixer.clipAction(animation);
@@ -737,9 +722,10 @@ var CharacterModel = class {
737
722
  });
738
723
  }
739
724
  transitionToAnimation(targetAnimation, transitionDuration = 0.15) {
740
- if (!this.mesh || this.currentAnimation === null)
725
+ if (!this.mesh)
741
726
  return;
742
727
  const currentAction = this.animations[this.currentAnimation];
728
+ this.currentAnimation = targetAnimation;
743
729
  const targetAction = this.animations[targetAnimation];
744
730
  if (!targetAction)
745
731
  return;
@@ -752,7 +738,11 @@ var CharacterModel = class {
752
738
  targetAction.setLoop(LoopRepeat, Infinity);
753
739
  targetAction.enabled = true;
754
740
  targetAction.fadeIn(transitionDuration);
755
- this.currentAnimation = targetAnimation;
741
+ }
742
+ update(time) {
743
+ if (this.animationMixer) {
744
+ this.animationMixer.update(time);
745
+ }
756
746
  }
757
747
  };
758
748
 
@@ -978,8 +968,10 @@ var defaultLabelPadding = 0;
978
968
  var defaultLabelWidth = 0.25;
979
969
  var defaultLabelHeight = 0.125;
980
970
  var defaultLabelCastShadows = true;
981
- var CharacterTooltip = class {
982
- constructor(parentModel) {
971
+ var tooltipGeometry = new PlaneGeometry(1, 1, 1, 1);
972
+ var CharacterTooltip = class extends Mesh3 {
973
+ constructor() {
974
+ super(tooltipGeometry);
983
975
  this.visibleOpacity = 0.85;
984
976
  this.targetOpacity = 0;
985
977
  this.fadingSpeed = 0.02;
@@ -995,25 +987,22 @@ var CharacterTooltip = class {
995
987
  fontColor: defaultFontColor,
996
988
  castShadows: defaultLabelCastShadows
997
989
  };
998
- this.setText = this.setText.bind(this);
999
- this.material = new MeshBasicMaterial2({
990
+ this.tooltipMaterial = new MeshBasicMaterial2({
1000
991
  map: null,
1001
992
  transparent: true,
1002
- opacity: 0
993
+ opacity: 0,
994
+ side: FrontSide
1003
995
  });
1004
- this.material.side = FrontSide;
1005
- this.geometry = new PlaneGeometry(1, 1, 1, 1);
1006
- this.mesh = new Mesh3(this.geometry, this.material);
1007
- this.mesh.position.set(0, 1.6, 0);
1008
- this.mesh.visible = false;
1009
- parentModel.add(this.mesh);
996
+ this.material = this.tooltipMaterial;
997
+ this.position.set(0, 1.6, 0);
998
+ this.visible = false;
1010
999
  }
1011
1000
  redrawText(content) {
1012
- if (!this.material) {
1001
+ if (!this.tooltipMaterial) {
1013
1002
  return;
1014
1003
  }
1015
- if (this.material.map) {
1016
- this.material.map.dispose();
1004
+ if (this.tooltipMaterial.map) {
1005
+ this.tooltipMaterial.map.dispose();
1017
1006
  }
1018
1007
  const { texture, width, height } = THREECanvasTextTexture(content, {
1019
1008
  bold: true,
@@ -1037,17 +1026,17 @@ var CharacterTooltip = class {
1037
1026
  },
1038
1027
  alignment: this.props.alignment
1039
1028
  });
1040
- this.material.map = texture;
1041
- this.material.map.magFilter = LinearFilter2;
1042
- this.material.map.minFilter = LinearFilter2;
1043
- this.material.needsUpdate = true;
1044
- this.mesh.scale.x = width / (100 * fontScale);
1045
- this.mesh.scale.y = height / (100 * fontScale);
1046
- this.mesh.position.y = 1.6;
1029
+ this.tooltipMaterial.map = texture;
1030
+ this.tooltipMaterial.map.magFilter = LinearFilter2;
1031
+ this.tooltipMaterial.map.minFilter = LinearFilter2;
1032
+ this.tooltipMaterial.needsUpdate = true;
1033
+ this.scale.x = width / (100 * fontScale);
1034
+ this.scale.y = height / (100 * fontScale);
1035
+ this.position.y = 1.6;
1047
1036
  }
1048
1037
  setText(text, temporary = false) {
1049
1038
  this.redrawText(text);
1050
- this.mesh.visible = true;
1039
+ this.visible = true;
1051
1040
  this.targetOpacity = this.visibleOpacity;
1052
1041
  if (temporary) {
1053
1042
  setTimeout(() => {
@@ -1059,37 +1048,101 @@ var CharacterTooltip = class {
1059
1048
  this.targetOpacity = 0;
1060
1049
  }
1061
1050
  update(camera) {
1062
- this.mesh.lookAt(camera.position);
1063
- const opacity = this.mesh.material.opacity;
1051
+ this.lookAt(camera.position);
1052
+ const opacity = this.tooltipMaterial.opacity;
1064
1053
  if (opacity < this.targetOpacity) {
1065
- this.mesh.material.opacity = Math.min(
1066
- this.mesh.material.opacity + this.fadingSpeed,
1054
+ this.tooltipMaterial.opacity = Math.min(
1055
+ this.tooltipMaterial.opacity + this.fadingSpeed,
1067
1056
  this.targetOpacity
1068
1057
  );
1069
1058
  } else if (opacity > this.targetOpacity) {
1070
- this.mesh.material.opacity = Math.max(
1071
- this.mesh.material.opacity - this.fadingSpeed,
1059
+ this.tooltipMaterial.opacity = Math.max(
1060
+ this.tooltipMaterial.opacity - this.fadingSpeed,
1072
1061
  this.targetOpacity
1073
1062
  );
1074
- if (opacity >= 1 && this.mesh.material.transparent === true) {
1075
- this.mesh.material.transparent = false;
1076
- this.mesh.material.needsUpdate = true;
1077
- } else if (opacity > 0 && opacity < 1 && this.mesh.material.transparent === false) {
1078
- this.mesh.material.transparent = true;
1079
- this.mesh.material.needsUpdate = true;
1063
+ if (opacity >= 1 && this.tooltipMaterial.transparent) {
1064
+ this.tooltipMaterial.transparent = false;
1065
+ this.tooltipMaterial.needsUpdate = true;
1066
+ } else if (opacity > 0 && opacity < 1 && !this.tooltipMaterial.transparent) {
1067
+ this.tooltipMaterial.transparent = true;
1068
+ this.tooltipMaterial.needsUpdate = true;
1080
1069
  }
1081
- if (this.mesh.material.opacity <= 0) {
1082
- this.mesh.visible = false;
1070
+ if (this.tooltipMaterial.opacity <= 0) {
1071
+ this.visible = false;
1072
+ }
1073
+ }
1074
+ }
1075
+ };
1076
+
1077
+ // src/character/Character.ts
1078
+ var Character = class extends Group {
1079
+ constructor(characterDescription, characterModelLoader, characterId, modelLoadedCallback, cameraManager, composer) {
1080
+ super();
1081
+ this.characterDescription = characterDescription;
1082
+ this.characterModelLoader = characterModelLoader;
1083
+ this.characterId = characterId;
1084
+ this.modelLoadedCallback = modelLoadedCallback;
1085
+ this.cameraManager = cameraManager;
1086
+ this.composer = composer;
1087
+ this.model = null;
1088
+ this.color = new Color3();
1089
+ this.tooltip = null;
1090
+ this.speakingIndicator = null;
1091
+ this.tooltip = new CharacterTooltip();
1092
+ this.add(this.tooltip);
1093
+ this.load();
1094
+ }
1095
+ async load() {
1096
+ this.model = new CharacterModel(this.characterDescription, this.characterModelLoader);
1097
+ await this.model.init();
1098
+ this.add(this.model.mesh);
1099
+ if (this.speakingIndicator === null) {
1100
+ this.speakingIndicator = new CharacterSpeakingIndicator(this.composer.postPostScene);
1101
+ }
1102
+ this.color = this.model.material.colorsCube216[this.characterId];
1103
+ this.modelLoadedCallback();
1104
+ }
1105
+ updateAnimation(targetAnimation) {
1106
+ var _a;
1107
+ (_a = this.model) == null ? void 0 : _a.updateAnimation(targetAnimation);
1108
+ }
1109
+ update(time, deltaTime) {
1110
+ var _a;
1111
+ if (!this.model)
1112
+ return;
1113
+ if (this.tooltip) {
1114
+ this.tooltip.update(this.cameraManager.camera);
1115
+ }
1116
+ if (this.speakingIndicator) {
1117
+ this.speakingIndicator.setTime(time);
1118
+ if (this.model.mesh && this.model.headBone) {
1119
+ this.speakingIndicator.setBillboarding(
1120
+ (_a = this.model.headBone) == null ? void 0 : _a.getWorldPosition(new Vector34()),
1121
+ this.cameraManager.camera
1122
+ );
1083
1123
  }
1084
1124
  }
1125
+ if (typeof this.model.material.uniforms.time !== "undefined") {
1126
+ this.model.material.uniforms.time.value = time;
1127
+ this.model.material.uniforms.diffuseRandomColor.value = this.color;
1128
+ this.model.material.update();
1129
+ }
1130
+ this.model.update(deltaTime);
1131
+ }
1132
+ getCurrentAnimation() {
1133
+ var _a;
1134
+ return ((_a = this.model) == null ? void 0 : _a.currentAnimation) || 0 /* idle */;
1085
1135
  }
1086
1136
  };
1087
1137
 
1138
+ // src/character/CharacterManager.ts
1139
+ import { Euler, Group as Group2, Quaternion as Quaternion5, Vector3 as Vector38 } from "three";
1140
+
1088
1141
  // src/character/LocalController.ts
1089
- import { Line3, Matrix4, Quaternion as Quaternion2, Raycaster as Raycaster2, Vector3 as Vector34 } from "three";
1142
+ import { Line3, Matrix4, Quaternion as Quaternion2, Raycaster as Raycaster2, Vector3 as Vector35 } from "three";
1090
1143
  var LocalController = class {
1091
- constructor(model, id, collisionsManager, keyInputManager, cameraManager, timeManager) {
1092
- this.model = model;
1144
+ constructor(character, id, collisionsManager, keyInputManager, cameraManager, timeManager) {
1145
+ this.character = character;
1093
1146
  this.id = id;
1094
1147
  this.collisionsManager = collisionsManager;
1095
1148
  this.keyInputManager = keyInputManager;
@@ -1098,7 +1151,7 @@ var LocalController = class {
1098
1151
  this.collisionDetectionSteps = 15;
1099
1152
  this.capsuleInfo = {
1100
1153
  radius: 0.4,
1101
- segment: new Line3(new Vector34(), new Vector34(0, 1.05, 0))
1154
+ segment: new Line3(new Vector35(), new Vector35(0, 1.05, 0))
1102
1155
  };
1103
1156
  this.maxWalkSpeed = 6;
1104
1157
  this.maxRunSpeed = 8.5;
@@ -1111,17 +1164,16 @@ var LocalController = class {
1111
1164
  this.characterWasOnGround = false;
1112
1165
  this.characterAirborneSince = 0;
1113
1166
  this.currentHeight = 0;
1114
- this.characterVelocity = new Vector34();
1115
- this.vectorUp = new Vector34(0, 1, 0);
1116
- this.vectorDown = new Vector34(0, -1, 0);
1167
+ this.characterVelocity = new Vector35();
1168
+ this.vectorUp = new Vector35(0, 1, 0);
1169
+ this.vectorDown = new Vector35(0, -1, 0);
1117
1170
  this.rotationOffset = 0;
1118
1171
  this.azimuthalAngle = 0;
1119
1172
  this.tempMatrix = new Matrix4();
1120
1173
  this.tempSegment = new Line3();
1121
- this.tempVector = new Vector34();
1122
- this.tempVector2 = new Vector34();
1174
+ this.tempVector = new Vector35();
1175
+ this.tempVector2 = new Vector35();
1123
1176
  this.rayCaster = new Raycaster2();
1124
- this.thirdPersonCamera = null;
1125
1177
  this.speed = 0;
1126
1178
  this.targetSpeed = 0;
1127
1179
  this.networkState = {
@@ -1132,11 +1184,6 @@ var LocalController = class {
1132
1184
  };
1133
1185
  }
1134
1186
  update() {
1135
- var _a, _b;
1136
- if (!((_a = this.model) == null ? void 0 : _a.mesh) || !((_b = this.model) == null ? void 0 : _b.animationMixer))
1137
- return;
1138
- if (!this.thirdPersonCamera)
1139
- this.thirdPersonCamera = this.cameraManager.camera;
1140
1187
  const { forward, backward, left, right, run, jump, anyDirection, conflictingDirection } = this.keyInputManager;
1141
1188
  this.forward = forward;
1142
1189
  this.backward = backward;
@@ -1148,28 +1195,28 @@ var LocalController = class {
1148
1195
  this.conflictingDirections = conflictingDirection;
1149
1196
  this.targetSpeed = this.run ? this.maxRunSpeed : this.maxWalkSpeed;
1150
1197
  this.speed += ease(this.targetSpeed, this.speed, 0.07);
1151
- this.rayCaster.set(this.model.mesh.position, this.vectorDown);
1198
+ this.rayCaster.set(this.character.position, this.vectorDown);
1152
1199
  const minimumDistance = this.collisionsManager.raycastFirstDistance(this.rayCaster.ray);
1153
1200
  if (minimumDistance !== null) {
1154
1201
  this.currentHeight = minimumDistance;
1155
1202
  }
1156
1203
  if (anyDirection || !this.characterOnGround) {
1157
1204
  const targetAnimation = this.getTargetAnimation();
1158
- this.model.updateAnimation(targetAnimation, this.timeManager.deltaTime);
1205
+ this.character.updateAnimation(targetAnimation);
1159
1206
  } else {
1160
- this.model.updateAnimation(0 /* idle */, this.timeManager.deltaTime);
1207
+ this.character.updateAnimation(0 /* idle */);
1161
1208
  }
1162
1209
  if (this.anyDirection)
1163
1210
  this.updateRotation();
1164
1211
  for (let i = 0; i < this.collisionDetectionSteps; i++) {
1165
1212
  this.updatePosition(this.timeManager.deltaTime / this.collisionDetectionSteps, i);
1166
1213
  }
1167
- if (this.model.mesh.position.y < 0)
1214
+ if (this.character.position.y < 0)
1168
1215
  this.resetPosition();
1169
1216
  this.updateNetworkState();
1170
1217
  }
1171
1218
  getTargetAnimation() {
1172
- if (!this.model.mesh)
1219
+ if (!this.character)
1173
1220
  return 0 /* idle */;
1174
1221
  if (this.conflictingDirections)
1175
1222
  return 0 /* idle */;
@@ -1201,31 +1248,26 @@ var LocalController = class {
1201
1248
  }
1202
1249
  }
1203
1250
  updateAzimuthalAngle() {
1204
- var _a;
1205
- if (!this.thirdPersonCamera || !((_a = this.model) == null ? void 0 : _a.mesh))
1206
- return;
1207
- const camToModelDistance = this.thirdPersonCamera.position.distanceTo(this.model.mesh.position);
1251
+ const camToModelDistance = this.cameraManager.camera.position.distanceTo(
1252
+ this.character.position
1253
+ );
1208
1254
  const isCameraFirstPerson = camToModelDistance < 2;
1209
1255
  if (isCameraFirstPerson) {
1210
- const cameraForward = new Vector34(0, 0, 1).applyQuaternion(this.thirdPersonCamera.quaternion);
1256
+ const cameraForward = new Vector35(0, 0, 1).applyQuaternion(
1257
+ this.cameraManager.camera.quaternion
1258
+ );
1211
1259
  this.azimuthalAngle = Math.atan2(cameraForward.x, cameraForward.z);
1212
1260
  } else {
1213
1261
  this.azimuthalAngle = Math.atan2(
1214
- this.thirdPersonCamera.position.x - this.model.mesh.position.x,
1215
- this.thirdPersonCamera.position.z - this.model.mesh.position.z
1262
+ this.cameraManager.camera.position.x - this.character.position.x,
1263
+ this.cameraManager.camera.position.z - this.character.position.z
1216
1264
  );
1217
1265
  }
1218
1266
  }
1219
1267
  computeAngularDifference(rotationQuaternion) {
1220
- var _a;
1221
- if (!((_a = this.model) == null ? void 0 : _a.mesh))
1222
- return 0;
1223
- return 2 * Math.acos(Math.abs(this.model.mesh.quaternion.dot(rotationQuaternion)));
1268
+ return 2 * Math.acos(Math.abs(this.character.quaternion.dot(rotationQuaternion)));
1224
1269
  }
1225
1270
  updateRotation() {
1226
- var _a;
1227
- if (!this.thirdPersonCamera || !((_a = this.model) == null ? void 0 : _a.mesh))
1228
- return;
1229
1271
  this.updateRotationOffset();
1230
1272
  this.updateAzimuthalAngle();
1231
1273
  const rotationQuaternion = new Quaternion2();
@@ -1234,18 +1276,12 @@ var LocalController = class {
1234
1276
  const desiredTime = 0.07;
1235
1277
  const angularSpeed = angularDifference / desiredTime;
1236
1278
  const frameRotation = angularSpeed * this.timeManager.deltaTime;
1237
- this.model.mesh.quaternion.rotateTowards(rotationQuaternion, frameRotation);
1279
+ this.character.quaternion.rotateTowards(rotationQuaternion, frameRotation);
1238
1280
  }
1239
1281
  addScaledVectorToCharacter(deltaTime) {
1240
- var _a;
1241
- if (!((_a = this.model) == null ? void 0 : _a.mesh))
1242
- return;
1243
- this.model.mesh.position.addScaledVector(this.tempVector, this.speed * deltaTime);
1282
+ this.character.position.addScaledVector(this.tempVector, this.speed * deltaTime);
1244
1283
  }
1245
1284
  updatePosition(deltaTime, _iter) {
1246
- var _a;
1247
- if (!((_a = this.model) == null ? void 0 : _a.mesh))
1248
- return;
1249
1285
  if (this.characterOnGround) {
1250
1286
  if (!this.jump)
1251
1287
  this.canJump = true;
@@ -1262,45 +1298,45 @@ var LocalController = class {
1262
1298
  this.characterVelocity.y += deltaTime * this.gravity;
1263
1299
  this.canJump = false;
1264
1300
  }
1265
- this.model.mesh.position.addScaledVector(this.characterVelocity, deltaTime);
1301
+ this.character.position.addScaledVector(this.characterVelocity, deltaTime);
1266
1302
  this.tempVector.set(0, 0, 0);
1267
1303
  if (this.forward) {
1268
- const forward = new Vector34(0, 0, -1).applyAxisAngle(this.vectorUp, this.azimuthalAngle);
1304
+ const forward = new Vector35(0, 0, -1).applyAxisAngle(this.vectorUp, this.azimuthalAngle);
1269
1305
  this.tempVector.add(forward);
1270
1306
  }
1271
1307
  if (this.backward) {
1272
- const backward = new Vector34(0, 0, 1).applyAxisAngle(this.vectorUp, this.azimuthalAngle);
1308
+ const backward = new Vector35(0, 0, 1).applyAxisAngle(this.vectorUp, this.azimuthalAngle);
1273
1309
  this.tempVector.add(backward);
1274
1310
  }
1275
1311
  if (this.left) {
1276
- const left = new Vector34(-1, 0, 0).applyAxisAngle(this.vectorUp, this.azimuthalAngle);
1312
+ const left = new Vector35(-1, 0, 0).applyAxisAngle(this.vectorUp, this.azimuthalAngle);
1277
1313
  this.tempVector.add(left);
1278
1314
  }
1279
1315
  if (this.right) {
1280
- const right = new Vector34(1, 0, 0).applyAxisAngle(this.vectorUp, this.azimuthalAngle);
1316
+ const right = new Vector35(1, 0, 0).applyAxisAngle(this.vectorUp, this.azimuthalAngle);
1281
1317
  this.tempVector.add(right);
1282
1318
  }
1283
1319
  if (this.tempVector.length() > 0) {
1284
1320
  this.tempVector.normalize();
1285
1321
  this.addScaledVectorToCharacter(deltaTime);
1286
1322
  }
1287
- this.model.mesh.updateMatrixWorld();
1323
+ this.character.updateMatrixWorld();
1288
1324
  this.tempSegment.copy(this.capsuleInfo.segment);
1289
- this.tempSegment.start.applyMatrix4(this.model.mesh.matrixWorld).applyMatrix4(this.tempMatrix);
1290
- this.tempSegment.end.applyMatrix4(this.model.mesh.matrixWorld).applyMatrix4(this.tempMatrix);
1325
+ this.tempSegment.start.applyMatrix4(this.character.matrixWorld).applyMatrix4(this.tempMatrix);
1326
+ this.tempSegment.end.applyMatrix4(this.character.matrixWorld).applyMatrix4(this.tempMatrix);
1291
1327
  this.collisionsManager.applyColliders(this.tempSegment, this.capsuleInfo.radius);
1292
1328
  const newPosition = this.tempVector;
1293
1329
  newPosition.copy(this.tempSegment.start);
1294
1330
  const deltaVector = this.tempVector2;
1295
- deltaVector.subVectors(newPosition, this.model.mesh.position);
1331
+ deltaVector.subVectors(newPosition, this.character.position);
1296
1332
  const offset = Math.max(0, deltaVector.length() - 1e-5);
1297
1333
  deltaVector.normalize().multiplyScalar(offset);
1298
- this.model.mesh.position.add(deltaVector);
1334
+ this.character.position.add(deltaVector);
1299
1335
  this.characterOnGround = deltaVector.y > Math.abs(deltaTime * this.characterVelocity.y * 0.25);
1300
1336
  if (this.characterWasOnGround && !this.characterOnGround) {
1301
1337
  this.characterAirborneSince = Date.now();
1302
1338
  }
1303
- this.coyoteTime = this.characterVelocity.y < 0 && this.characterOnGround === false && Date.now() - this.characterAirborneSince < this.coyoteTimeThreshold;
1339
+ this.coyoteTime = this.characterVelocity.y < 0 && !this.characterOnGround && Date.now() - this.characterAirborneSince < this.coyoteTimeThreshold;
1304
1340
  this.characterWasOnGround = this.characterOnGround;
1305
1341
  if (this.characterOnGround) {
1306
1342
  this.characterVelocity.set(0, 0, 0);
@@ -1310,130 +1346,33 @@ var LocalController = class {
1310
1346
  }
1311
1347
  }
1312
1348
  updateNetworkState() {
1313
- var _a;
1314
- if (!((_a = this.model) == null ? void 0 : _a.mesh)) {
1315
- this.networkState = {
1316
- id: this.id,
1317
- position: new Vector34(),
1318
- rotation: { quaternionY: 0, quaternionW: 1 },
1319
- state: 0 /* idle */
1320
- };
1321
- } else {
1322
- const characterQuaternion = this.model.mesh.getWorldQuaternion(new Quaternion2());
1323
- const positionUpdate = new Vector34(
1324
- this.model.mesh.position.x,
1325
- this.model.mesh.position.y,
1326
- this.model.mesh.position.z
1327
- );
1328
- this.networkState = {
1329
- id: this.id,
1330
- position: positionUpdate,
1331
- rotation: { quaternionY: characterQuaternion.y, quaternionW: characterQuaternion.w },
1332
- state: this.model.currentAnimation
1333
- };
1334
- }
1349
+ const characterQuaternion = this.character.getWorldQuaternion(new Quaternion2());
1350
+ const positionUpdate = new Vector35(
1351
+ this.character.position.x,
1352
+ this.character.position.y,
1353
+ this.character.position.z
1354
+ );
1355
+ this.networkState = {
1356
+ id: this.id,
1357
+ position: positionUpdate,
1358
+ rotation: { quaternionY: characterQuaternion.y, quaternionW: characterQuaternion.w },
1359
+ state: this.character.getCurrentAnimation()
1360
+ };
1335
1361
  }
1336
1362
  resetPosition() {
1337
- var _a;
1338
- if (!((_a = this.model) == null ? void 0 : _a.mesh))
1339
- return;
1340
1363
  this.characterVelocity.y = 0;
1341
- this.model.mesh.position.y = 3;
1364
+ this.character.position.y = 3;
1342
1365
  this.characterOnGround = false;
1343
1366
  }
1344
1367
  };
1345
1368
 
1346
- // src/character/Character.ts
1347
- var Character = class {
1348
- constructor(characterDescription, characterModelLoader, id, isLocal, modelLoadedCallback, collisionsManager, keyInputManager, cameraManager, timeManager, composer) {
1349
- this.characterDescription = characterDescription;
1350
- this.characterModelLoader = characterModelLoader;
1351
- this.id = id;
1352
- this.isLocal = isLocal;
1353
- this.modelLoadedCallback = modelLoadedCallback;
1354
- this.collisionsManager = collisionsManager;
1355
- this.keyInputManager = keyInputManager;
1356
- this.cameraManager = cameraManager;
1357
- this.timeManager = timeManager;
1358
- this.composer = composer;
1359
- this.controller = null;
1360
- this.name = null;
1361
- this.model = null;
1362
- this.color = new Color3();
1363
- this.position = new Vector35();
1364
- this.tooltip = null;
1365
- this.speakingIndicator = null;
1366
- this.load();
1367
- }
1368
- async load() {
1369
- this.model = new CharacterModel(this.characterDescription, this.characterModelLoader);
1370
- await this.model.init();
1371
- if (this.tooltip === null) {
1372
- this.tooltip = new CharacterTooltip(this.model.mesh);
1373
- }
1374
- if (this.speakingIndicator === null) {
1375
- this.speakingIndicator = new CharacterSpeakingIndicator(this.composer.postPostScene);
1376
- }
1377
- this.color = this.model.material.colorsCube216[this.id];
1378
- if (this.isLocal) {
1379
- this.controller = new LocalController(
1380
- this.model,
1381
- this.id,
1382
- this.collisionsManager,
1383
- this.keyInputManager,
1384
- this.cameraManager,
1385
- this.timeManager
1386
- );
1387
- }
1388
- this.modelLoadedCallback();
1389
- }
1390
- update(time) {
1391
- var _a;
1392
- if (!this.model)
1393
- return;
1394
- if (this.tooltip) {
1395
- this.tooltip.update(this.cameraManager.camera);
1396
- }
1397
- if (this.speakingIndicator) {
1398
- this.speakingIndicator.setTime(time);
1399
- if (this.model.mesh && this.model.headBone) {
1400
- this.speakingIndicator.setBillboarding(
1401
- (_a = this.model.headBone) == null ? void 0 : _a.getWorldPosition(new Vector35()),
1402
- this.cameraManager.camera
1403
- );
1404
- }
1405
- }
1406
- this.model.mesh.getWorldPosition(this.position);
1407
- if (typeof this.model.material.uniforms.time !== "undefined") {
1408
- this.model.material.uniforms.time.value = time;
1409
- this.model.material.uniforms.diffuseRandomColor.value = this.color;
1410
- this.model.material.update();
1411
- }
1412
- }
1413
- };
1414
-
1415
- // src/character/CharacterManager.ts
1416
- import { Euler, Group, Quaternion as Quaternion4, Vector3 as Vector37 } from "three";
1417
-
1418
1369
  // src/character/RemoteController.ts
1419
- import {
1420
- AnimationMixer as AnimationMixer2,
1421
- Object3D as Object3D4,
1422
- Quaternion as Quaternion3,
1423
- Vector3 as Vector36
1424
- } from "three";
1370
+ import { Quaternion as Quaternion3, Vector3 as Vector36 } from "three";
1425
1371
  var RemoteController = class {
1426
- constructor(character, characterModelLoader, id) {
1372
+ constructor(character, id) {
1427
1373
  this.character = character;
1428
- this.characterModelLoader = characterModelLoader;
1429
1374
  this.id = id;
1430
- this.characterModel = null;
1431
- this.animationMixer = new AnimationMixer2(new Object3D4());
1432
- this.animations = /* @__PURE__ */ new Map();
1433
1375
  this.currentAnimation = 0 /* idle */;
1434
- this.characterModel = this.character.model.mesh;
1435
- this.characterModel.updateMatrixWorld();
1436
- this.animationMixer = new AnimationMixer2(this.characterModel);
1437
1376
  this.networkState = {
1438
1377
  id: this.id,
1439
1378
  position: { x: 0, y: 0, z: 0 },
@@ -1444,48 +1383,23 @@ var RemoteController = class {
1444
1383
  update(clientUpdate, time, deltaTime) {
1445
1384
  if (!this.character)
1446
1385
  return;
1447
- this.character.update(time);
1448
1386
  this.updateFromNetwork(clientUpdate);
1449
- this.animationMixer.update(deltaTime);
1450
- }
1451
- async setAnimationFromFile(animationType, fileName) {
1452
- const animation = await this.characterModelLoader.load(fileName, "animation");
1453
- const animationAction = this.animationMixer.clipAction(animation);
1454
- this.animations.set(animationType, animationAction);
1455
- if (animationType === 0 /* idle */) {
1456
- animationAction.play();
1457
- }
1458
- }
1459
- transitionToAnimation(targetAnimation, transitionDuration = 0.15) {
1460
- if (this.currentAnimation === targetAnimation)
1461
- return;
1462
- const currentAction = this.animations.get(this.currentAnimation);
1463
- const targetAction = this.animations.get(targetAnimation);
1464
- if (!targetAction)
1465
- return;
1466
- if (currentAction) {
1467
- currentAction.enabled = true;
1468
- targetAction.reset().setEffectiveTimeScale(1).setEffectiveWeight(1).fadeIn(transitionDuration).play();
1469
- currentAction.crossFadeTo(targetAction, transitionDuration, true);
1470
- } else {
1471
- targetAction.play();
1472
- }
1473
- this.currentAnimation = targetAnimation;
1387
+ this.character.update(time, deltaTime);
1474
1388
  }
1475
1389
  updateFromNetwork(clientUpdate) {
1476
- if (!this.characterModel)
1477
- return;
1478
1390
  const { position, rotation, state } = clientUpdate;
1479
- this.characterModel.position.lerp(new Vector36(position.x, position.y, position.z), 0.15);
1391
+ this.character.position.lerp(new Vector36(position.x, position.y, position.z), 0.15);
1480
1392
  const rotationQuaternion = new Quaternion3(0, rotation.quaternionY, 0, rotation.quaternionW);
1481
- this.characterModel.quaternion.slerp(rotationQuaternion, 0.6);
1393
+ this.character.quaternion.slerp(rotationQuaternion, 0.6);
1482
1394
  if (state !== this.currentAnimation) {
1483
- this.transitionToAnimation(state);
1395
+ this.currentAnimation = state;
1396
+ this.character.updateAnimation(state);
1484
1397
  }
1485
1398
  }
1486
1399
  };
1487
1400
 
1488
- // src/character/CharacterManager.ts
1401
+ // src/character/url-position.ts
1402
+ import { Quaternion as Quaternion4, Vector3 as Vector37 } from "three";
1489
1403
  function encodeCharacterAndCamera(character, camera) {
1490
1404
  return [
1491
1405
  ...toArray(character.position),
@@ -1494,135 +1408,96 @@ function encodeCharacterAndCamera(character, camera) {
1494
1408
  ...toArray(camera.quaternion)
1495
1409
  ].join(",");
1496
1410
  }
1497
- function decodeCharacterAndCamera(hash, character, camera) {
1411
+ function decodeCharacterAndCamera(hash) {
1498
1412
  const values = hash.split(",").map(Number);
1499
- character.position.fromArray(values.slice(0, 3));
1500
- character.quaternion.fromArray(values.slice(3, 7));
1501
- camera.position.fromArray(values.slice(7, 10));
1502
- camera.quaternion.fromArray(values.slice(10, 14));
1413
+ return {
1414
+ character: {
1415
+ position: new Vector37(values[0], values[1], values[2]),
1416
+ quaternion: new Quaternion4(values[3], values[4], values[5], values[6])
1417
+ },
1418
+ camera: {
1419
+ position: new Vector37(values[7], values[8], values[9]),
1420
+ quaternion: new Quaternion4(values[10], values[11], values[12], values[13])
1421
+ }
1422
+ };
1503
1423
  }
1424
+
1425
+ // src/character/CharacterManager.ts
1504
1426
  var CharacterManager = class {
1505
- constructor(composer, characterModelLoader, collisionsManager, cameraManager, timeManager, inputManager, clientStates, sendUpdate) {
1427
+ constructor(composer, characterModelLoader, collisionsManager, cameraManager, timeManager, keyInputManager, clientStates, sendUpdate) {
1506
1428
  this.composer = composer;
1507
1429
  this.characterModelLoader = characterModelLoader;
1508
1430
  this.collisionsManager = collisionsManager;
1509
1431
  this.cameraManager = cameraManager;
1510
1432
  this.timeManager = timeManager;
1511
- this.inputManager = inputManager;
1433
+ this.keyInputManager = keyInputManager;
1512
1434
  this.clientStates = clientStates;
1513
1435
  this.sendUpdate = sendUpdate;
1514
- /*
1515
- TODO - re-enable updating location hash when there is a solution that waits for models to load (currently if the
1516
- character was standing on a model and the page is reloaded the character falls into the model before it loads and
1517
- can be trapped).
1518
- */
1519
- this.updateLocationHash = false;
1436
+ this.updateLocationHash = true;
1437
+ this.headTargetOffset = new Vector38(0, 1.3, 0);
1520
1438
  this.id = 0;
1521
- this.loadingCharacters = /* @__PURE__ */ new Map();
1522
1439
  this.remoteCharacters = /* @__PURE__ */ new Map();
1523
1440
  this.remoteCharacterControllers = /* @__PURE__ */ new Map();
1524
1441
  this.characterDescription = null;
1525
- this.character = null;
1442
+ this.localCharacter = null;
1526
1443
  this.cameraOffsetTarget = 0;
1527
1444
  this.cameraOffset = 0;
1528
1445
  this.speakingCharacters = /* @__PURE__ */ new Map();
1529
- this.group = new Group();
1530
- }
1531
- /* TODO:
1532
- 1) Separate this method into spawnLocalCharacter and spawnRemoteCharacter
1533
- 2) Make this synchronous to avoid having loadingCharacters and instead manage
1534
- the mesh loading async (would allow us to show a nameplate where a remote
1535
- user is before the asset loads).
1536
- */
1537
- spawnCharacter(characterDescription, id, isLocal = false, spawnPosition = new Vector37(), spawnRotation = new Euler()) {
1446
+ this.group = new Group2();
1447
+ }
1448
+ spawnCharacter(characterDescription, id, isLocal = false, spawnPosition = new Vector38(), spawnRotation = new Euler()) {
1449
+ var _a;
1538
1450
  this.characterDescription = characterDescription;
1539
- const characterLoadingPromise = new Promise((resolve) => {
1540
- const character = new Character(
1541
- characterDescription,
1542
- this.characterModelLoader,
1451
+ const character = new Character(
1452
+ characterDescription,
1453
+ this.characterModelLoader,
1454
+ id,
1455
+ () => {
1456
+ },
1457
+ this.cameraManager,
1458
+ this.composer
1459
+ );
1460
+ if (isLocal) {
1461
+ const quaternion = new Quaternion5().setFromEuler(character.rotation);
1462
+ this.sendUpdate({
1543
1463
  id,
1544
- isLocal,
1545
- () => {
1546
- var _a, _b, _c, _d, _e, _f, _g;
1547
- if (window.location.hash && window.location.hash.length > 1) {
1548
- decodeCharacterAndCamera(
1549
- window.location.hash.substring(1),
1550
- character.model.mesh,
1551
- this.cameraManager.camera
1552
- );
1553
- } else {
1554
- spawnPosition = spawnPosition || getSpawnPositionInsideCircle(3, 30, id, 0.4);
1555
- character.model.mesh.position.set(spawnPosition.x, spawnPosition.y, spawnPosition.z);
1556
- character.model.mesh.rotation.set(spawnRotation.x, spawnRotation.y, spawnRotation.z);
1557
- character.position.set(spawnPosition.x, spawnPosition.y, spawnPosition.z);
1558
- character.model.mesh.updateMatrixWorld();
1559
- const quaternion = new Quaternion4().setFromEuler(character.model.mesh.rotation);
1560
- this.sendUpdate({
1561
- id,
1562
- position: {
1563
- x: spawnPosition.x,
1564
- y: spawnPosition.y,
1565
- z: spawnPosition.z
1566
- },
1567
- rotation: { quaternionY: quaternion.y, quaternionW: quaternion.w },
1568
- state: 0 /* idle */
1569
- });
1570
- }
1571
- character.model.hideMaterialByMeshName("SK_Mannequin_2");
1572
- if (!isLocal) {
1573
- (_b = (_a = character.model) == null ? void 0 : _a.mesh) == null ? void 0 : _b.position.set(spawnPosition.x, spawnPosition.y, spawnPosition.z);
1574
- (_d = (_c = character.model) == null ? void 0 : _c.mesh) == null ? void 0 : _d.updateMatrixWorld();
1575
- character.position.set(spawnPosition.x, spawnPosition.y, spawnPosition.z);
1576
- }
1577
- this.group.add(character.model.mesh);
1578
- if (isLocal) {
1579
- this.id = id;
1580
- this.character = character;
1581
- (_e = this.character.tooltip) == null ? void 0 : _e.setText(`${id}`);
1582
- } else {
1583
- this.remoteCharacters.set(id, character);
1584
- const remoteController = new RemoteController(character, this.characterModelLoader, id);
1585
- remoteController.setAnimationFromFile(
1586
- 0 /* idle */,
1587
- characterDescription.idleAnimationFileUrl
1588
- );
1589
- remoteController.setAnimationFromFile(
1590
- 1 /* walking */,
1591
- characterDescription.jogAnimationFileUrl
1592
- );
1593
- remoteController.setAnimationFromFile(
1594
- 2 /* running */,
1595
- characterDescription.sprintAnimationFileUrl
1596
- );
1597
- remoteController.setAnimationFromFile(
1598
- 4 /* air */,
1599
- characterDescription.airAnimationFileUrl
1600
- );
1601
- (_f = remoteController.characterModel) == null ? void 0 : _f.position.set(
1602
- spawnPosition.x,
1603
- spawnPosition.y,
1604
- spawnPosition.z
1605
- );
1606
- this.remoteCharacterControllers.set(id, remoteController);
1607
- (_g = character.tooltip) == null ? void 0 : _g.setText(`${id}`);
1608
- }
1609
- resolve(character);
1464
+ position: {
1465
+ x: spawnPosition.x,
1466
+ y: spawnPosition.y,
1467
+ z: spawnPosition.z
1610
1468
  },
1469
+ rotation: { quaternionY: quaternion.y, quaternionW: quaternion.w },
1470
+ state: 0 /* idle */
1471
+ });
1472
+ }
1473
+ if (isLocal) {
1474
+ this.id = id;
1475
+ this.localCharacter = character;
1476
+ this.localController = new LocalController(
1477
+ this.localCharacter,
1478
+ this.id,
1611
1479
  this.collisionsManager,
1612
- this.inputManager,
1480
+ this.keyInputManager,
1613
1481
  this.cameraManager,
1614
- this.timeManager,
1615
- this.composer
1482
+ this.timeManager
1616
1483
  );
1617
- });
1618
- this.loadingCharacters.set(id, characterLoadingPromise);
1619
- return characterLoadingPromise;
1484
+ this.localCharacter.position.set(spawnPosition.x, spawnPosition.y, spawnPosition.z);
1485
+ this.localCharacter.rotation.set(spawnRotation.x, spawnRotation.y, spawnRotation.z);
1486
+ } else {
1487
+ this.remoteCharacters.set(id, character);
1488
+ const remoteController = new RemoteController(character, id);
1489
+ remoteController.character.position.set(spawnPosition.x, spawnPosition.y, spawnPosition.z);
1490
+ remoteController.character.rotation.set(spawnRotation.x, spawnRotation.y, spawnRotation.z);
1491
+ this.remoteCharacterControllers.set(id, remoteController);
1492
+ }
1493
+ (_a = character.tooltip) == null ? void 0 : _a.setText(`${id}`);
1494
+ this.group.add(character);
1620
1495
  }
1621
1496
  getLocalCharacterPositionAndRotation() {
1622
- if (this.character && this.character.model && this.character.model.mesh) {
1497
+ if (this.localCharacter && this.localCharacter && this.localCharacter) {
1623
1498
  return {
1624
- position: this.character.model.mesh.position,
1625
- rotation: this.character.model.mesh.rotation
1499
+ position: this.localCharacter.position,
1500
+ rotation: this.localCharacter.rotation
1626
1501
  };
1627
1502
  }
1628
1503
  return {
@@ -1632,54 +1507,48 @@ var CharacterManager = class {
1632
1507
  }
1633
1508
  clear() {
1634
1509
  for (const [id, character] of this.remoteCharacters) {
1635
- this.group.remove(character.model.mesh);
1510
+ this.group.remove(character);
1636
1511
  this.remoteCharacters.delete(id);
1637
1512
  this.remoteCharacterControllers.delete(id);
1638
1513
  }
1639
- if (this.character) {
1640
- this.group.remove(this.character.model.mesh);
1641
- this.character = null;
1514
+ if (this.localCharacter) {
1515
+ this.group.remove(this.localCharacter);
1516
+ this.localCharacter = null;
1642
1517
  }
1643
- this.loadingCharacters.clear();
1644
1518
  }
1645
1519
  setSpeakingCharacter(id, value) {
1646
1520
  this.speakingCharacters.set(id, value);
1647
1521
  }
1648
1522
  update() {
1649
- var _a, _b, _c, _d;
1650
- if (this.character) {
1651
- this.character.update(this.timeManager.time);
1523
+ var _a, _b, _c;
1524
+ if (this.localCharacter) {
1525
+ this.localCharacter.update(this.timeManager.time, this.timeManager.deltaTime);
1652
1526
  if (this.speakingCharacters.has(this.id)) {
1653
- (_a = this.character.speakingIndicator) == null ? void 0 : _a.setSpeaking(this.speakingCharacters.get(this.id));
1527
+ (_a = this.localCharacter.speakingIndicator) == null ? void 0 : _a.setSpeaking(this.speakingCharacters.get(this.id));
1654
1528
  }
1655
- if ((_b = this.character.model) == null ? void 0 : _b.mesh) {
1656
- this.cameraOffsetTarget = this.cameraManager.targetDistance <= 0.4 ? 0.13 : 0;
1657
- this.cameraOffset += ease(this.cameraOffsetTarget, this.cameraOffset, 0.1);
1658
- const targetOffset = new Vector37(0, 1.3, this.cameraOffset);
1659
- targetOffset.applyQuaternion(this.character.model.mesh.quaternion);
1660
- this.cameraManager.setTarget(this.character.position.add(targetOffset));
1661
- }
1662
- if (this.character.controller) {
1663
- this.character.controller.update();
1664
- if (this.timeManager.frame % 2 === 0) {
1665
- this.sendUpdate(this.character.controller.networkState);
1666
- }
1529
+ this.cameraOffsetTarget = this.cameraManager.targetDistance <= 0.4 ? 0.13 : 0;
1530
+ this.cameraOffset += ease(this.cameraOffsetTarget, this.cameraOffset, 0.1);
1531
+ const targetOffset = new Vector38(0, 0, this.cameraOffset);
1532
+ targetOffset.add(this.headTargetOffset);
1533
+ targetOffset.applyQuaternion(this.localCharacter.quaternion);
1534
+ this.cameraManager.setTarget(targetOffset.add(this.localCharacter.position));
1535
+ this.localController.update();
1536
+ if (this.timeManager.frame % 2 === 0) {
1537
+ this.sendUpdate(this.localController.networkState);
1667
1538
  }
1668
1539
  for (const [id, update] of this.clientStates) {
1669
1540
  if (this.remoteCharacters.has(id) && this.speakingCharacters.has(id)) {
1670
1541
  const character = this.remoteCharacters.get(id);
1671
- (_c = character == null ? void 0 : character.speakingIndicator) == null ? void 0 : _c.setSpeaking(this.speakingCharacters.get(id));
1542
+ (_b = character == null ? void 0 : character.speakingIndicator) == null ? void 0 : _b.setSpeaking(this.speakingCharacters.get(id));
1672
1543
  }
1673
1544
  const { position } = update;
1674
- if (!this.remoteCharacters.has(id) && !this.loadingCharacters.has(id)) {
1545
+ if (!this.remoteCharacters.has(id)) {
1675
1546
  this.spawnCharacter(
1676
1547
  this.characterDescription,
1677
1548
  id,
1678
1549
  false,
1679
- new Vector37(position.x, position.y, position.z)
1680
- ).then((_character) => {
1681
- this.loadingCharacters.delete(id);
1682
- });
1550
+ new Vector38(position.x, position.y, position.z)
1551
+ );
1683
1552
  }
1684
1553
  const characterController = this.remoteCharacterControllers.get(id);
1685
1554
  if (characterController) {
@@ -1688,15 +1557,15 @@ var CharacterManager = class {
1688
1557
  }
1689
1558
  for (const [id, character] of this.remoteCharacters) {
1690
1559
  if (!this.clientStates.has(id)) {
1691
- (_d = character.speakingIndicator) == null ? void 0 : _d.dispose();
1692
- this.group.remove(character.model.mesh);
1560
+ (_c = character.speakingIndicator) == null ? void 0 : _c.dispose();
1561
+ this.group.remove(character);
1693
1562
  this.remoteCharacters.delete(id);
1694
1563
  this.remoteCharacterControllers.delete(id);
1695
1564
  }
1696
1565
  }
1697
1566
  if (this.updateLocationHash && this.timeManager.frame % 60 === 0) {
1698
1567
  window.location.hash = encodeCharacterAndCamera(
1699
- this.character.model.mesh,
1568
+ this.localCharacter,
1700
1569
  this.cameraManager.camera
1701
1570
  );
1702
1571
  }
@@ -1708,8 +1577,9 @@ var CharacterManager = class {
1708
1577
  import { LoadingManager } from "three";
1709
1578
  import { GLTFLoader as ThreeGLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
1710
1579
  var CachedGLTFLoader = class extends ThreeGLTFLoader {
1711
- constructor(manager) {
1580
+ constructor(manager, debug = false) {
1712
1581
  super(manager);
1582
+ this.debug = debug;
1713
1583
  this.blobCache = /* @__PURE__ */ new Map();
1714
1584
  }
1715
1585
  setBlobUrl(originalUrl, blobUrl) {
@@ -1721,7 +1591,9 @@ var CachedGLTFLoader = class extends ThreeGLTFLoader {
1721
1591
  load(url, onLoad, onProgress, onError) {
1722
1592
  const blobUrl = this.getBlobUrl(url);
1723
1593
  if (blobUrl) {
1724
- console.log(`Loading cached ${url.split("/").pop()}`);
1594
+ if (this.debug === true) {
1595
+ console.log(`Loading cached ${url.split("/").pop()}`);
1596
+ }
1725
1597
  super.load(blobUrl, onLoad, onProgress, onError);
1726
1598
  } else {
1727
1599
  super.load(url, onLoad, onProgress, onError);
@@ -1749,20 +1621,14 @@ var LRUCache = class {
1749
1621
  this.cache.set(key, value);
1750
1622
  }
1751
1623
  };
1752
- var _CharacterModelLoader = class _CharacterModelLoader {
1753
- constructor(maxCacheSize = 100) {
1624
+ var CharacterModelLoader = class {
1625
+ constructor(maxCacheSize = 100, debug = false) {
1626
+ this.debug = debug;
1754
1627
  this.ongoingLoads = /* @__PURE__ */ new Map();
1755
1628
  this.loadingManager = new LoadingManager();
1756
- this.gltfLoader = new CachedGLTFLoader(this.loadingManager);
1629
+ this.gltfLoader = new CachedGLTFLoader(this.loadingManager, this.debug);
1757
1630
  this.modelCache = new LRUCache(maxCacheSize);
1758
1631
  }
1759
- /* TODO: decide between below lazy initialization or eager on this file's bottom export */
1760
- static getInstance() {
1761
- if (!_CharacterModelLoader.instance) {
1762
- _CharacterModelLoader.instance = new _CharacterModelLoader();
1763
- }
1764
- return _CharacterModelLoader.instance;
1765
- }
1766
1632
  async load(fileUrl, fileType) {
1767
1633
  const cachedModel = this.modelCache.get(fileUrl);
1768
1634
  if (cachedModel) {
@@ -1770,19 +1636,27 @@ var _CharacterModelLoader = class _CharacterModelLoader {
1770
1636
  this.gltfLoader.setBlobUrl(fileUrl, blobURL);
1771
1637
  return this.loadFromUrl(fileUrl, fileType, cachedModel.originalExtension);
1772
1638
  } else {
1773
- console.log(`Loading ${fileUrl} from server`);
1639
+ if (this.debug === true) {
1640
+ console.log(`Loading ${fileUrl} from server`);
1641
+ }
1774
1642
  const ongoingLoad = this.ongoingLoads.get(fileUrl);
1775
1643
  if (ongoingLoad)
1776
- return ongoingLoad;
1644
+ return ongoingLoad.then((loadedModel) => {
1645
+ const blobURL = URL.createObjectURL(loadedModel.blob);
1646
+ return this.loadFromUrl(blobURL, fileType, loadedModel.originalExtension);
1647
+ });
1777
1648
  const loadPromise = fetch(fileUrl).then((response) => response.blob()).then((blob) => {
1778
1649
  const originalExtension = fileUrl.split(".").pop() || "";
1779
- this.modelCache.set(fileUrl, { blob, originalExtension });
1780
- const blobURL = URL.createObjectURL(blob);
1650
+ const cached = { blob, originalExtension };
1651
+ this.modelCache.set(fileUrl, cached);
1781
1652
  this.ongoingLoads.delete(fileUrl);
1782
- return this.loadFromUrl(blobURL, fileType, originalExtension);
1653
+ return cached;
1783
1654
  });
1784
1655
  this.ongoingLoads.set(fileUrl, loadPromise);
1785
- return loadPromise;
1656
+ return loadPromise.then((loadedModel) => {
1657
+ const blobURL = URL.createObjectURL(loadedModel.blob);
1658
+ return this.loadFromUrl(blobURL, fileType, loadedModel.originalExtension);
1659
+ });
1786
1660
  }
1787
1661
  }
1788
1662
  async loadFromUrl(url, fileType, extension) {
@@ -1813,9 +1687,6 @@ var _CharacterModelLoader = class _CharacterModelLoader {
1813
1687
  }
1814
1688
  }
1815
1689
  };
1816
- _CharacterModelLoader.instance = null;
1817
- var CharacterModelLoader = _CharacterModelLoader;
1818
- var MODEL_LOADER = CharacterModelLoader.getInstance();
1819
1690
 
1820
1691
  // src/input/KeyInputManager.ts
1821
1692
  var KeyInputManager = class {
@@ -1884,9 +1755,10 @@ var KeyInputManager = class {
1884
1755
  import {
1885
1756
  InteractionManager,
1886
1757
  MMLClickTrigger,
1887
- PromptManager
1758
+ PromptManager,
1759
+ LoadingProgressManager
1888
1760
  } from "mml-web";
1889
- import { Group as Group2 } from "three";
1761
+ import { Group as Group3 } from "three";
1890
1762
  var MMLCompositionScene = class {
1891
1763
  constructor(targetElement, renderer, scene, camera, audioListener, collisionsManager, getUserPositionAndRotation) {
1892
1764
  this.renderer = renderer;
@@ -1896,7 +1768,7 @@ var MMLCompositionScene = class {
1896
1768
  this.collisionsManager = collisionsManager;
1897
1769
  this.getUserPositionAndRotation = getUserPositionAndRotation;
1898
1770
  this.chatProbes = /* @__PURE__ */ new Set();
1899
- this.group = new Group2();
1771
+ this.group = new Group3();
1900
1772
  this.promptManager = PromptManager.init(targetElement);
1901
1773
  const { interactionListener, interactionManager } = InteractionManager.init(
1902
1774
  targetElement,
@@ -1905,6 +1777,7 @@ var MMLCompositionScene = class {
1905
1777
  );
1906
1778
  this.interactionManager = interactionManager;
1907
1779
  this.interactionListener = interactionListener;
1780
+ this.loadingProgressManager = new LoadingProgressManager();
1908
1781
  this.mmlScene = {
1909
1782
  getAudioListener: () => this.audioListener,
1910
1783
  getRenderer: () => this.renderer,
@@ -1940,6 +1813,9 @@ var MMLCompositionScene = class {
1940
1813
  },
1941
1814
  prompt: (promptProps, callback) => {
1942
1815
  this.promptManager.prompt(promptProps, callback);
1816
+ },
1817
+ getLoadingProgressManager: () => {
1818
+ return this.loadingProgressManager;
1943
1819
  }
1944
1820
  };
1945
1821
  this.clickTrigger = MMLClickTrigger.init(targetElement, this.mmlScene);
@@ -2384,7 +2260,7 @@ var n8ssaoOptions = {
2384
2260
  aoSamples: [2, 4, 8, 16, 32, 64],
2385
2261
  denoiseSamples: [2, 4, 8, 16, 32, 64],
2386
2262
  denoiseRadius: [3, 6, 12],
2387
- viewMode: ["Combined", "AO", "Split", "No AO"]
2263
+ viewMode: ["Combined", "AO", "No AO", "Split", "Split AO", "No AO"]
2388
2264
  };
2389
2265
  var ssaoMaterialParams = [
2390
2266
  "fade",
@@ -2480,10 +2356,10 @@ var SSAOFolder = class {
2480
2356
  this.aoDisplay = this.n8ssao.addBinding(n8ssaoValues, "viewMode", {
2481
2357
  view: "radiogrid",
2482
2358
  groupName: "viewMode",
2483
- size: [2, 2],
2359
+ size: [3, 2],
2484
2360
  cells: (x, y) => ({
2485
- title: `${n8ssaoOptions.viewMode[y * 2 + x]}`,
2486
- value: `${n8ssaoOptions.viewMode[y * 2 + x]}`
2361
+ title: `${n8ssaoOptions.viewMode[y * 3 + x]}`,
2362
+ value: `${n8ssaoOptions.viewMode[y * 3 + x]}`
2487
2363
  }),
2488
2364
  label: "viewMode"
2489
2365
  });
@@ -2855,7 +2731,6 @@ var TweakPane = class {
2855
2731
  };
2856
2732
 
2857
2733
  // src/rendering/composer.ts
2858
- import { N8AOPostPass } from "n8ao";
2859
2734
  import {
2860
2735
  EffectComposer as EffectComposer2,
2861
2736
  RenderPass,
@@ -2875,25 +2750,25 @@ import {
2875
2750
  } from "postprocessing";
2876
2751
  import {
2877
2752
  AmbientLight,
2878
- Color as Color6,
2879
- Fog,
2880
- HalfFloatType,
2753
+ Color as Color7,
2754
+ Fog as Fog2,
2755
+ HalfFloatType as HalfFloatType2,
2881
2756
  LinearSRGBColorSpace,
2882
2757
  LoadingManager as LoadingManager2,
2883
2758
  PMREMGenerator,
2884
- Scene as Scene3,
2885
- Vector2 as Vector22,
2886
- WebGLRenderer as WebGLRenderer2
2759
+ Scene as Scene4,
2760
+ Vector2 as Vector27,
2761
+ WebGLRenderer as WebGLRenderer4
2887
2762
  } from "three";
2888
2763
  import { RGBELoader } from "three/examples/jsm/loaders/RGBELoader.js";
2889
2764
 
2890
2765
  // src/sun/Sun.ts
2891
- import { CameraHelper, Color as Color5, DirectionalLight, Group as Group3, OrthographicCamera, Vector3 as Vector38 } from "three";
2892
- var Sun = class extends Group3 {
2766
+ import { CameraHelper, Color as Color5, DirectionalLight, Group as Group4, OrthographicCamera, Vector3 as Vector39 } from "three";
2767
+ var Sun = class extends Group4 {
2893
2768
  constructor() {
2894
2769
  super();
2895
2770
  this.debug = false;
2896
- this.sunOffset = new Vector38(
2771
+ this.sunOffset = new Vector39(
2897
2772
  39 * (Math.PI / 180),
2898
2773
  50 * (Math.PI / 180),
2899
2774
  100
@@ -2920,7 +2795,7 @@ var Sun = class extends Group3 {
2920
2795
  this.directionalLight.shadow.mapSize.set(this.shadowResolution, this.shadowResolution);
2921
2796
  this.directionalLight.castShadow = true;
2922
2797
  this.setColor();
2923
- this.updateCharacterPosition(new Vector38(0, 0, 0));
2798
+ this.updateCharacterPosition(new Vector39(0, 0, 0));
2924
2799
  this.add(this.directionalLight);
2925
2800
  if (this.debug === true && this.camHelper instanceof CameraHelper) {
2926
2801
  this.add(this.camHelper);
@@ -2958,7 +2833,7 @@ var Sun = class extends Group3 {
2958
2833
  if (!this.target)
2959
2834
  return;
2960
2835
  const distance = this.sunOffset.z;
2961
- const sphericalPosition = new Vector38(
2836
+ const sphericalPosition = new Vector39(
2962
2837
  distance * Math.sin(polarAngle) * Math.cos(azimuthalAngle),
2963
2838
  distance * Math.cos(polarAngle),
2964
2839
  distance * Math.sin(polarAngle) * Math.sin(azimuthalAngle)
@@ -3114,44 +2989,1353 @@ var GaussGrainEffect = new ShaderMaterial2({
3114
2989
  dithering: true
3115
2990
  });
3116
2991
 
3117
- // src/rendering/composer.ts
3118
- var Composer = class {
3119
- constructor(scene, camera, spawnSun = false) {
3120
- this.width = 1;
3121
- this.height = 1;
3122
- this.resolution = new Vector22(this.width, this.height);
3123
- this.isEnvHDRI = false;
3124
- this.bcs = BrightnessContrastSaturation;
3125
- this.gaussGrainEffect = GaussGrainEffect;
3126
- this.ambientLight = null;
3127
- this.sun = null;
3128
- this.scene = scene;
3129
- this.postPostScene = new Scene3();
3130
- this.camera = camera;
3131
- this.spawnSun = spawnSun;
3132
- this.renderer = new WebGLRenderer2({
3133
- powerPreference: "high-performance",
3134
- antialias: false,
3135
- stencil: false,
3136
- depth: false
3137
- });
3138
- this.renderer.info.autoReset = false;
3139
- this.renderer.setSize(this.width, this.height);
3140
- this.renderer.shadowMap.enabled = true;
3141
- this.renderer.shadowMap.type = rendererValues.shadowMap;
3142
- this.renderer.toneMapping = rendererValues.toneMapping;
3143
- this.renderer.toneMappingExposure = rendererValues.exposure;
3144
- this.setAmbientLight();
3145
- this.setFog();
3146
- this.effectComposer = new EffectComposer2(this.renderer, {
3147
- frameBufferType: HalfFloatType
3148
- });
3149
- this.renderPass = new RenderPass(this.scene, this.camera);
3150
- this.normalPass = new NormalPass2(this.scene, this.camera);
3151
- this.normalPass.enabled = ppssaoValues.enabled;
3152
- this.normalTextureEffect = new TextureEffect({
3153
- blendFunction: BlendFunction2.SKIP,
3154
- texture: this.normalPass.texture
2992
+ // src/rendering/post-effects/n8-ssao/N8SSAOPass.ts
2993
+ import { Pass } from "postprocessing";
2994
+ import {
2995
+ Color as Color6,
2996
+ DataTexture,
2997
+ FloatType,
2998
+ Fog,
2999
+ FogExp2,
3000
+ HalfFloatType,
3001
+ LinearFilter as LinearFilter3,
3002
+ NearestFilter,
3003
+ NoColorSpace,
3004
+ OrthographicCamera as OrthographicCamera3,
3005
+ RGBAFormat as RGBAFormat2,
3006
+ RedFormat,
3007
+ RepeatWrapping,
3008
+ ShaderMaterial as ShaderMaterial4,
3009
+ Uniform as Uniform7,
3010
+ Vector2 as Vector26,
3011
+ Vector3 as Vector313,
3012
+ WebGLMultipleRenderTargets,
3013
+ WebGLRenderTarget
3014
+ } from "three";
3015
+
3016
+ // src/rendering/post-effects/n8-ssao/BlueNoise.ts
3017
+ var BlueNoise = "5L7pP4UXrOIr/VZ1G3f6p89FIWU7lqc7J3DPxKjJUXODJoHQzf/aNVM+ABlvhXeBGN7iC0WkmTjEaAqOItBfBdaK5KSGV1ET5SOKl3x9JOX5w2sAl6+6KjDhVUHgbqq7DZ5EeYzbdSNxtrQLW/KkPJoOTG4u5CBUZkCKHniY9l7DUgjuz708zG1HIC8qfohi1vPjPH9Lq47ksjRrjwXD4MlVCjdAqYFGodQ8tRmHkOfq4wVRIAHvoavPHvN1lpk3X4Y1yzAPGe8S9KBs3crc4GwlU1dEOXiWol/mgQqxkNqB1xd04+0Bmpwj0GcCc4NUi+c731FUxjvaexCkCJ0qhrJJ++htWqetNC4NewClu8aFRSwrqiJEGe+qtTg4CYCHaF1wJI0sy/ZBQAI0qAMyBvVjWZlv2pdkCaro9eWDLK5I4mbb8E4d7hZr9dDJiTJm6Bmb5S+2F7yal/JPdeLUfwq7jmVLaQfhv4tWMJAt7V4sG9LuAv2oPJgSj1nnlBvPibfHM2TrlWHwGCLGxW/5Jm2TotaDL+pHDM5pn1r0UuTZ24N8S5k68bLHW9tfD+2k4zGev23ExJb4YTRKWrj82N5LjJ26lj1BkGZ0CsXLGGELoPaYQomjTqPxYqhfwOwDliNGVqux9ffuybqOKgsbB51B1GbZfG8vHDBE2JQGib1mnCmWOWAMJcHN0cKeDHYTflbDTVXajtr68mwfRje6WueQ/6yWqmZMLWNH7P27zGFhMFqaqfg11Q88g/9UA/FROe9yfq0yOO0pnNAxvepFy2BpEbcgG+mCyjCC01JWlOZlIPdf1TtlyOt7L94ToYGCukoFt4OqwOrofamjECpSgKLLmrRM+sNRAw12eaqk8KtdFk7pn2IcDQiPXCh16t1a+psi+w9towHTKPyQM0StKr61b2BnN1HU+aezFNBLfHTiXwhGTbdxLLmrsAGIVSiNAeCGE8GlB0iOv2v78kP0CTmAPUEqnHYRSDlP+L6m/rYjEK6Q85GRDJi2W20/7NLPpSOaMR++IFvpkcwRuc59j8hh9tYlc1xjdt2jmp9KJczB7U9P43inuxLOv11P5/HYH5d6gLB0CsbGC8APjh+EcCP0zFWqlaACZweLhVfv3yiyd8R3bdVg8sRKsxPvhDaPpiFp9+MN+0Ua0bsPr+lhxfZhMhlevkLbR4ZvcSRP6ApQLy3+eMh9ehCB3z5DVAaN3P6J8pi5Qa88ZQsOuCTWyH6q8yMfBw8y8nm6jaOxJhPH6Hf0I4jmALUBsWKH4gWBnyijHh7z3/1HhQzFLRDRrIQwUtu11yk7U0gDw/FatOIZOJaBx3UqbUxSZ6dboFPm5pAyyXC2wYdSWlpZx/D2C6hDO2sJM4HT9IKWWmDkZIO2si/6BKHruXIEDpfAtz3xDlIdKnnlqnkfCyy6vNOPyuoWsSWBeiN0mcfIrnOtp2j7bxjOkr25skfS/lwOC692cEp7TKSlymbsyzoWg/0AN66SvQYo6BqpNwPpTaUu25zMWlwVUdfu1EEdc0O06TI0JmHk4f6GZQbfOs//OdgtGPO6uLoadJycR8Z80rkd88QoNmimZd8vcpQKScCFkxH1RMTkPlN3K7CL/NSMOiXEvxrn9VyUPFee63uRflgaPMSsafvqMgzTt3T1RaHNLLFatQbD0Vha4YXZ/6Ake7onM65nC9cyLkteYkDfHoJtef7wCrWXTK0+vH38VUBcFJP0+uUXpkiK0gDXNA39HL/qdVcaOA16kd2gzq8aHpNSaKtgMLJC6fdLLS/I/4lUWV2+djY9Rc3QuJOUrlHFQERtXN4xJaAHZERCUQZ9ND2pEtZg8dsnilcnqmqYn3c1sRyK0ziKpHNytEyi2gmzxEFchvT1uBWxZUikkAlWuyqvvhteSG9kFhTLNM97s3X1iS2UbE6cvApgbmeJ/KqtP0NNT3bZiG9TURInCZtVsNZzYus6On0wcdMlVfqo8XLhT5ojaOk4DtCyeoQkBt1mf5luFNaLFjI/1cnPefyCQwcq5ia/4pN4NB+xE/3SEPsliJypS964SI6o5fDVa0IERR8DoeQ+1iyRLU1qGYexB61ph4pkG1rf3c2YD6By1pFCmww9B0r2VjFeaubkIdgWx4RKLQRPLENdGo8ezI5mkNtdCws19aP1uHhenD+HKa8GDeLulb2fiMRhU2xJzzz9e4yOMPvEnGEfbCiQ17nUDpcFDWthr68mhZ4WiHUkRpaVWJNExuULcGkuyVLsQj59pf6OHFR7tofhy9FMrWPCEvX1d5sCVJt8yBFiB6NoOuwMy4wlso9I2G4E5/5B2c6vIZUUY9fFujT3hpkdTuVhbhBwLCtnlIjBpN4cq+waZ0wXSrmebcl+dcrb7sPh9jKxFINkScDTBgjSUfLkC3huJJs/M4M8AOFxbbSIVpBUarYFmLpGsv+V6TJnWNTwI41tubwo7QSI1VOdRKT/Pp8U3oK2ciDbeuWnAGAANvQjGfcewdAdo6H83XzqlK/4yudtFHJSv9Y+qJskwnVToH1I0+tJ3vsLBXtlvMzLIxUj/8LcqZnrNHfVRgabFNXW0qpUvDgxnP3f54KooR3NI+2Q/VHAYFigMkQE5dLH6C6fGs/TKeE6E2jOhZQcP9/rrJjJKcLYdn5cw6XLCUe9F7quk5Yhac+nYL5HOXvp6Q/5qbiQHkuebanX77YSNx34YaWYpcEHuY1u/lEVTCQ7taPaw3oNcn/qJhMzGPZUs3XAq48wj/hCIO2d5aFdfXnS0yg57/jxzDJBwkdOgeVnyyh19Iz1UqiysT4J1eeKwUuWEYln23ydtP7g3R1BnvnxqFPAnOMgOIop2dkXPfUh/9ZKV3ZQbZNactPD4ql5Qg9CxSBnIwzlj/tseQKWRstwNbf17neGwDFFWdm/8f+nDWt/WlKV3MUiAm3ci6xXMDSL5ubPXBg/gKEE7TsZVGUcrIbdXILcMngvGs7unvlPJh6oadeBDqiAviIZ/iyiUMdQZAuf/YBAY0VP1hcgInuWoKbx31AOjyTN2OOHrlthB3ny9JKHOAc8BMvqopikPldcwIQoFxTccKKIeI815GcwaKDLsMbCsxegrzXl8E0bpic/xffU9y1DCgeKZoF2PIY77RIn6kSRdBiGd8NtNwT74dyeFBMkYraPkudN26x9NPuBt4iCOAnBFaNSKVgKiZQruw22kM1fgBKG7cPYAxdHJ8M4V/jzBn2jEJg+jk/jjV4oMmMNOpKB5oVpVh7tK529Z+5vKZ0NSY2A4YdcT0x4BdkoNEDrpsTmekSTjvx9ZBiTHrm9M/n/hGmgpjz4WEjttRfAEy5DYH5vCK/9GuVPa4hoApFaNlrFD/n2PpKOw24iKujKhVIz41p1E0HwsCd/c17OA0H0RjZi1V/rjJLexUzpmXTMIMuzaOBbU4dxvQMgyvxJvR6DyF3BaHkaqT4P3FRYlm+zh8EEGgmkNqD1WRUubDW62VqLoH8UEelIpL7C8CguWWGGCAIDPma9bnh+7IJSt0Cn6ACER2mYk8dLsrN70RUVLiE0ig+08yPY9IOtuqHf/KYsT84BwhMcVq7t8q1WVjpJGNyXdtIPIjhAzabtrX03Itn29QO3TCixE9WpkHIOdAoGvqCrw1D3x9g9Px8u0yZZuulZuGy0veSY34KDSlhsO1zx2ZMrpDBzCHPB4niwApk6NevIvmBxU3+4yaewDvgEQDJ6Of5iRxjAIpp9UO8EzNY4blj4qh8SCSZTqbe/lShE6tNU9Y5IoWHeJxPcHF9KwYQD7lFcIpcscHrcfkHJfL2lL1zczKywEF7BwkjXEirgBcvNWayatqdTVT5oLbzTmED3EOYBSXFyb2VIYk3t0dOZWJdG1nP+W7Qfyeb8MSIyUGKEA57ptPxrPHKYGZPHsuBqQuVSrn0i8KJX+rlzAqo8AawchsJ26FckxTf5+joTcw+2y8c8bushpRYEbgrdr64ltEYPV2AbVgKXV3XACoD1gbs01CExbJALkuItjfYN3+6I8kbiTYmdzBLaNC+xu9z/eXcRQV1Lo8cJoSsKyWJPuTncu5vcmfMUAWmuwhjymK1rhYR8pQMXNQg9X+5ha5fEnap+LhUL1d5SURZz9rGdOWLhrMcMKSaU3LhOQ/6a6qSCwgzQxCW2gFs53fpvfWxhH+xDHdKRV6w29nQ6rNqd9by+zm1OpzYyJwvFyOkrVXQUwt4HaapnweCa7Tj2Mp/tT4YcY3Q/tk1czgkzlV5mpDrdp1spOYB8ionAwxujjdhj5y9qEHu0uc36PAKAYsKLaEoiwPnob0pdluPWdv4sNSlG8GWViI+x/Z4DkW/kSs2iE3ADFjg4TCvgCbX3v0Hz0KZkerrpzEIukAusidDs2g/w0zgmLnZXvVr5kkpwQTLZ0L6uaTHl0LVikIuNIVPmL3fOQJqIdfzymUN0zucIrDintBn6ICl/inj5zteISv5hEMGMqtHc2ghcFJvmH3ZhIZi34vqqTFCb9pltTYz582Y3dwYaHb9khdfve1YryzEwEKbI8qm62qv+NyllC+WxLLAJjz0ZaEF2aTn35qeFmkbP6LDYcbwqWxA0WKsteB7vy8bRHE4r8LhubWDc0pbe90XckSDDAkRej0TQlmWsWwaz18Tx2phykVvwuIRzf4kt9srT8N7gsMjMs0NLAAldabFf2tiMoaaxHcZSX51WPc1BrwApMxih227qTZkcgtkdK1h314XvZKUKh/XysWYnk1ST4kiBI1B9OlfTjB3WHzTAReFLofsGtikwpIXzQBc/gOjz2Thlj36WN0sxyf4RmAFtrYt64fwm+ThjbhlmUTZzebLl4yAkAqzJSfjPBZS2H/IvkkTUdVh0qdB6EuiHEjEil5lk9BTPzxmoW4Jx543hiyy4ASdYA2DNoprsR9iwGFwFG3F2vIROy4L5CZrl230+k733JwboSNBKngsaFPtqo+q3mFFSjC1k0kIAFmKihaYSwaSF7konmYHZWmchuaq15TpneA2ADSRvA07I7US0lTOOfKrgxhzRl0uJihcEZhhYWxObjvNTJ/5sR4Aa5wOQhGClGLb746cJhQ2E6Jie1hbGgWxUH7YSKETptrTeR/xfcMNk2WM12S0XElC9klR8O7jLYekEOZdscP0ypSdoCVZAoK+2ju2PHE869Q9rxCs9DVQco4BriiPbCjN/8tBjsah4IuboR5QbmbyDpcdXVxGMxvWKIjocBuKbjb+B4HvkunbG0wX0IFCjQKoNMFIKcJSJXtkP3EO+J16uh4img0LQlBAOYwBLupu5r1NALMo0g3xkd9b4f7KoCBWHeyk24FmYUCy/PGLv0xErOTyORp8TJ5nnc2k1dOVBTJok7iHye9dwxwRVP3c7eAS8pMmJYHGpzIHz6ii2WJm8HMTPAZdA4q+ugj3PNCL/N45kyglqvQV4f/+ryDDG5RPy5HVoV9FVuJcq2dxF9Y0heVoipV6q1LyfAeuMzbsUV+rsSBmCSV+1CdKlxy0T0Y6Om0X6701URm2Ml6DIQgJ/3KO6kwcMYRrmKsY7TfxWhSXZll+1PfyRXe9HS0t1IKTQMZL7ZqQ8D/o+en57Y9XAQ9C+kZYykNr0xOMxEwu2+Cppm69mQyTm3H7QX6kHvXF201r+KVAf354qypJC5OHSeBU47bM1bTaVmdVEWQ+9CcvvHdu8Ue5UndHM+EeukmR82voQpetZ7WJjyXs+tPS60nk09gymuORoHNtbm0VuvyigiEvOsyHiRBW7V6FyTCppLPEHvesan91SlEh1/QEunq+qgREFXByDwNKcAH5s8/RFg8hP4wcPmFqX0xXGSKY087bqRLsBZe52jThx0XLkhKQUWPvI18WQQS3g2Ra1pzQ1oNFKdfJJjyaH5tJH6w0/upJobwB8KZ5cIs9LnVGxfBaHXBfvLkNpab7dpU6TdcbBIc+A4bqXE/Xt8/xsGQOdoXra4Us5nDAM6v2BNBQaGMmgMfQQV+ikTteSHvyl8wUxULiYRIEKaiDxpBJnyf9OoqQdZVJ8ahqOvuwqq5mnDUAUzUr/Lvs1wLu2F+r4eZMfJPL4gV5mKLkITmozRnTvA7VABaxZmFRtkhvU5iH9RQ1z26ku7aABokvptx7RKZBVL6dveLKOzg0NC7HAxcg5kE1wuyJiEQLOpO0ma3AtWD2Q2Wmn2oPZeDYAwVyEpxuwDy7ivmdUDSL95ol3h2JByTMovOCgxZ1q4E5nwwa7+4WtDAse6bDdr27XgAi5Px3IWbyZ/vRiECKwOMeJSuIl8A4Ds0emI3SgKVVWVO5uyiEUET+ucEq0casA+DQyhzRc8j+Plo0pxKynB/t0uXod1FVV4fX1sC4kDfwFaUDGQ4p9HYgaMqIWX3OF/S8+vcR0JS0bDapWKJwAIIQiRUzvh5YwtzkjccbbrT9Ky/qt5X7MAGA0lzh43mDF9EB6lCGuO/aFCMhdOqNryvd73KdJNy3mxtT8AqgmG4xq7eE1jKu6rV0g8UGyMatzyIMjiOCf4lIJFzAfwDbIfC72TJ/TK+cGsLR8blpjlEILjD8Mxr7IffhbFhgo12CzXRQ2O8JqBJ70+t12385tSmFC8Or+U8svOaoGoojT1/EmjRMT7x2iTUZ7Ny02VGeMZTtGy029tGN1/9k7x3mFu63lYnaWjfJT1m1zpWO3HSXpGkFqVd/m3kDMv4X9rmLOpwEeu8r6TI6C2zUG+MT6v90OU3y5hKqLhpyFLGtkZhDmUg/W1JGSmA8N1TapR4Kny+P6+DuMadZ9+xBbv06nfOjMwkoTsjG0zFmNbvlxEjw+Pl5QYK+V8Qyb+nknZ0Nb/Ofi9+V0eoNtTrtD1/0wzUGGG5u2D/J1ouO/PjXFJVx6LurVnPOyFVbZx7s3ZSjSq+7YN3wzTbFbUvP8GBh7cKieJt56SIowQ2I577+UEXrxUKMFO+XaLLCALuiJWB2vUdpsT+kQ+adoeTfwOulXhd/KZ7ygjj6PhvGT1xzfT7hTwd6dzSB4xV70CesHC0dsg2VyujlMGBKjg5snbrHHX/LNj3SsoLGSX+bZNTDDCNTXh+dCVPlj4K8+hJ/kVddrbtZw26Hx5qYiv3oNNg5blHRSPtmojhZmBQAz8sLC9nAuWNSz1dIofFtlryEKklbdkhBCcx5dhj7pinXDNlCeatCeTCEjYCpZ3HRf5QzUcRR1Tdb3gwtYtpPdgMxmWfJGoZSu1EsCJbIhS16Ed97+8br4Ar1mB1GcnZVx/HPtJl4CgbHXrrDPwlE4od8deRQYLt9IlsvCqgesMmLAVxB+igH7WGTcY/e3lLHJ4rkBgh2p1QpUBRb/cSQsJCbosFDkalbJigimldVK7TIHKSq2w8mezku9hgw8fXJxGdXoL1ggma52kXzjP78l0d0zMwtTVlt0FqnRyGLPGEjmICzgSp7XPFlUr7AeMclQ4opqwBFInziM5F8oJJ8qeuckGOnAcZZOLl1+ZhGF17pfIuujipwFJL7ChIIB2vlo0IQZGTJPNa2YjNcGUw+a/gWYLkCp+bOGIYhWr08UIE709ZEHlUoEbumzgpJv1D0+hWYNEpj+laoZIK5weO2DFwLL6UBYNrXTm9YvvxeN9U9oKsB3zKBwzFFwDgid5ESMhy68xBnVa55sCZd+l5AnzT8etYjIwF/BGwEx1jjzFv32bk6EeJulESARh8RZ48o7rKw67UZpudPa15SDnL8AL8xMV2SC0D1P53p190zhCFkMmEiir2olwxcJppl/kLm6/0QSUQLNaxi1AC3Pg1CTosX2YQr73PjEIxIlg4mJ62vP7ZyoHE55B0SX9YrrrCPtNsrJEwtn6KOSt7nLT3n3DLJTPbLulcqQ1kETP6Huts29oP+JLEqRGWgnrqMD+mhCl1XCZifjgQ39AeudE8pyu2DqnYU3PyPbJhStq1HbP+VxgseWL+hQ+4w1okADlA9WqoaRuoS7IY77Cm40cJiE6FLomUMltT+xO3Upcv5dzSh9F57hodSBnMHukcH1kd9tqlpprBQ/Ij9E+wMQXrZG5PlzwYJ6jmRdnQtRj64wC/7vsDaaMFteBOUDR4ebRrNZJHhwlNEK9Bz3k7jqOV5KJpL74p2sQnd7vLE374Jz+G7H3RUbX17SobYOe9wKkL/Ja/zeiKExOBmPo0X29bURQMxJkN4ddbrHnOkn6+M1zTZHo0efsB23WSSsByfmye2ZuTEZ12J3Y8ffT6Fcv8XVfA/k+p+xJGreKHJRVUIBqfEIlRt987/QXkssXuvLkECSpVEBs+gE1meB6Xn1RWISG6sV3+KOVjiE9wGdRHS8rmTERRnk0mDNU/+kOQYN/6jdeq0IHeh9c6xlSNICo9OcX1MmAiEuvGay43xCZgxHeZqD7etZMigoJI5V2q7xDcXcPort7AEjLwWlEf4ouzy2iPa3lxpcJWdIcHjhLZf1zg/Kv3/yN1voOmCLrI1Fe0MuFbB0TFSUt+t4Wqe2Mj1o2KS0TFQPGRlFm26IvVP9OXKIQkjfueRtMPoqLfVgDhplKvWWJA673+52FgEEgm+HwEgzOjaTuBz639XtCTwaQL/DrCeRdXun0VU3HDmNmTkc6YrNR6tTVWnbqHwykSBswchFLnvouR0KRhDhZiTYYYNWdvXzY+61Jz5IBcTJavGXr9BcHdk/3tqaLbwCbfpwjxCFSUs1xfFcRzRfMAl+QYuCpsYGz9H01poc1LyzhXwmODmUSg/xFq/RosgYikz4Om/ni9QCcr28ZPISaKrY7O+CspM/s+sHtnA9o9WgFWhcBX2LDN2/AL5uB6UxL/RaBp7EI+JHGz6MeLfvSNJnBgI9THFdUwmg1AXb9pvd7ccLqRdmcHLRT1I2VuEAghBduBm7pHNrZIjb2UVrijpZPlGL68hr+SDlC31mdis0BjP4aZFEOcw+uB17y5u7WOnho60Vcy7gRr7BZ9z5zY1uIwo+tW1YKpuQpdR0Vi7AxKmaIa4jXTjUh7MRlNM0W/Ut/CSD7atFd4soMsX7QbcrUZZaWuN0KOVCL9E09UcJlX+esWK56mre/s6UO9ks0owQ+foaVopkuKG+HZYbE1L1e0VwY2J53aCpwC77HqtpyNtoIlBVzOPtFvzBpDV9TjiP3CcTTGqLKh+m7urHvtHSB/+cGuRk4SsTma9sPCVJ19UPvaAv5WB8u57lNeUewwKpXmmKm5XZV91+FqCCT6nVrrrOgXfYmGFlVjqsSn3/yufkGIdtmdD0yVBcYFR3hDx43e3E4iuiEtP3Me9gcsBqveQdKojKR//qD2nEDY0IktMgFvH+SqVWi9mAorym92NEGbY8MeDjp553MiTXCRSASPt+Ga5q7pB9vwFQCTpaoevx0yEfrq9rMs3eU6wclBMJ9Ve8m6QuLYZ58J41YG3jW/khW92h6M/vbFIUPuopZ6VVtpciesU74Ef7ic8iSymDohGeUn4ubT0vRsXmbsjaJaYhL8f+8I5EiD5l680MJbxX/4GYrOg4iPQqpKp0qddSu/HKtznHeVyxgTwhfEORMCwnaqetVSzvidaWN9P+fXtGXfEP9cTdwx2gKVfDdICq7hecgRhIs0qlCt6+5pGlCc6kWoplHa/KjP+FJdXBU/IDoKMxRjFhSYkggIkhvRKiN/b2ud8URPF+lB87AGAwyMjr/Wju2Uj5IrppXZWjI3d14BdKE2fhALyQPmHqqA+AXd2LwvRHcBq4mhOQ4oNRWH7wpzc6Pggfcbv9kqhLxrJKEaJqA6Rxi+TDNOJstd5DoRVCDjmVspCVyHJsFEWPg9+NA8l1e4X2PDvOd5MPZAGw6LRhWqeZoSQcPf9/dGJYAyzCmttlRnx0BfrKQ/G9i5DVJft9fuJwMi3OD/0Dv1bRoxcXAyZ0wMJ6rwk9RjRTF4ZK8JviCCNuVt/BqQYiphOzWCpnbwOZt6qXuiAabQWrS4mNXQ7cEErXR/yJcbdFp5nWE1bPBjD0fmG3ovMxmOq5blpcOs0DtNQpci1t+9DKERWAO53IVV/S4yhMklvIp0j0FIQgwjdUptqmoMYGVWSI5YkTKLHZdXRDv9zs+HdFZt1QVcdlGOgATro3fg6ticCrDQKUJC7bYX50wdvetilEwVenHhlr85HMLRLTD6nDXWId4ORLwwe5IXiOhpuZTVTv+xdkTxJofqeCRM/jcZqQlU0gFVTlYlfwMi6HKR2YG4fQ8TOtgR+yV+BMZb6L5OwDc/28/xdfD7GXFaVA2ZSObiIxBwT2Zev637EuvpM6rxcogdM4FJFa0ZhF7nrqtNsqWg5M7hZMORpjd4szf/wS+Ahs1shY54Ct5J1dOBO4sdEtSnRc0P9PhgyOCt6aQW98R22DpAcNTDe72AHK40vutKTPfpokghRPuGvz0dulBPKfC3O4KVDCyWrJGO7Ikdu06A0keKlVfi0tGcpO0NhzXEh75NHyMysAMV19fq7//sPC0For1k2uFEvq8lwrMAfmP7afR69U2RqaILHe7glpc8HmVf87Qb2ohsw+Di9U+ePdHLecS66MhB/0OwdcXR5WBcWTZLGq/kiAaT+bzkjR8GIpWdv6pfIgQ+Q0xdiKvo+gNB7/Nf9knNJGxnh7LeZEFtMn517tNc74PPS0M4K3I6HHZqNPA+VZcBc/g5a2ARyqKrJ4Z3krsuA+VOJJz2KJpBMgCCWFln3u7k6/q3DETAubKG/pt3ObaNT0NI0Qug90L2ip5dHnZJUjPTvK5E96aX/4mRU2u8n8kh6MKbY7ANBro3huF06U+JvfyELQP25oIaj+n0ITQ4KT9rXZD4EtBIOj95fYNldDN3io/VMIvWNj9P/b95WEMq8UAVfG2XG0N6fSYdnBEC7sUEbatbDICH9qA8TTuW9kEt9DlFOZFP7bdfYLa/khSY8W5K/AkIIAPXtMvyVKyESjKx9nfragssxC0jFMVY94d8lOAwRocdS/l/P43cBGa3IqDa0ihGPcmwS8O8Vj16Uy55rOrnN0shhRJZdW8I7F0Q0KeHc35GFo4aJOFc25gNafBu1V/VO0qS4Qkb6wjRrnlepUWjtYyaDABZceValuOMtoDdeIITWKOJiwGPpB12lQgwkmXh9M86podb0D117mNQ8ElluFvbaS8RTKQ6lyj88dUwoJU/ofOeubhoXWBF8eNumkVJu+As3ED/AvLlrV91UowIWI2m8HBG+a3k247ZKAGYsOcWe7fTWqL8eqwM5ZFuoXbeugPKuMOAtOsN+4dSwkhrSAlfGNTzFwEmCNWtzpa9CgPbYNcmoHtO8pj8qMvlGET6nrkJoQ2lp5MEUV1E2A4ZH70JUlCLXvqTIpZlzyxdr5p/GZiD1/BuFOGbyfFzhuxaC/l3lC2jjt6GNRBa06AqqPlYtdA7kiidYa5Qi0/XpXiMDyMXNOj3kmJEaXufW0GO8+DF8OoMULX1vvjCePKNis4AmxQKLCF+cjf/wyilCJvuiyLVPSdsuRTPZ0AhpdDF/1uFmDwG7iP3qYwNsKzqd3sYdnMolCOuQOIHWy1eQpWhuV+jmSeAC5zCc0/KsOIXkZPdiw8vtB33jEBpezpGDBP4JLY2wH1J7Fzp8y8RICqVd25mDT2tDb/L1mh4fv9TOfDH5dTeATqu+diOZi+/sIt18hiTovPsVQVaqXLPRx/4R/uH/86tBMcF+WBkThKLfblcVCIECc8DgNRVX97KdrsCeIK+CvJZMfwrftcDZDZyp7G8HeKl7bPYnTKX88dXAwAyz66O2chkPDHy/2K2XcT/61XnlAKgPwtI8yP9Vu45yh55KHhJu93mL4nfo8szp/IyDjmFHtSMqqoWsj8WaVhbjXgzZxcqZcyOe7pUK6aXF/Y32LnBOt0WN28UmHRiOpL525C63I2JQPX8vvOU0fz2ij74OeJ1Apgu3JRObfdo9xGDpp7cv3TdULEfNS6Gu3EJu7drBsBsogUqUc6wAUW3ux0/1hLVI/JEKJrAGm8g72C2aJSsGAsKFW4CBvBXVlNIKa5r7HvT1BeGYBfxTR1vhNlFFNN8WQYwr39yT/13XzRGiF2IsfE8HcN0+lN1zN/OnzekVBKkFY11GgrK5CLxrE/2HCEMwQb9yOuP2rTXiZzTEETp/ismFGcTWmbM9G1Sn2D/x3G74uWYZY4rgKB2Zo2bTKS6QnM5x1Yee66Y1L7K44AyiY5K2MH5wrTwxMFh+S8LzNQ25z6sunWZyiRwFIIvSnioltUXNiOr+XMZ6O9h9HcHxZJkfF0tUm6QkU7iJ2ozXARitiL86aqVsMOpmvdIBROhUoanPtCjgft8up3hAaKpw9Qs9MzYtBA2ijHXotzarkV3zKEK0dFFQUwT74NgCmGGuSCEDmFCezXPC9BhyGhmzNa6rQeQQz+r9CmGUZjIQEPsHwe86oCOQhWaHERsv5ia9rZvJ//7UXO7B329YUkLLAiqpLRsVV5XpcfdawlJqi/BVcCqO6dr9YJTFFRMVGhfUbB9YWNvYPY6RyaydAFYq1YIBQxuNAGfYWLMAHtt2XRHoOKCLz+qf5HCVBDOPOktQ3SdJBfxUkaiD585bmTzMwU3oeXUHZ55EC99Kz9kk4ZXMIENwVVpqW2JmGIcUiutIMj2KkpjE2QD+dIZUCxcX57kH7hiuUPnKCTdaw4KN95XPeFRvMcvo5L8LexWqvaJPECzwXCs/4XPAlSMpWUzBBjK3pEnkbueMkMJQrYcnXf7PjbAoJra1VLX4YuscQLpaeYWbT+h24hCFrfcHjxxx6WTSe4AGY/KHRZCQKqTuFWt0D8RmGWmvXSdg1ptIefYPshuIVZT7CV4Ny67fvjJugy0TNYHqoCO45CB88kxrvIsih19DqjD0UqiJsTFPcGW3P/ULOG3nb8CjpgVTIoa5nO9ZYEX4uEHu8hLXrJPjV1lTQ5xTdZVagg+Wj8V0EE4yPsTc345KM6lVXqLiHtm+G6edC4GVEiPgd98g+twSYm18gCsPnjqlLcFm9e72CLJbYD+ocIZOxuVjrX6IKh9fh7WqdIZ66x9PWkDGOVVGkx7jM76Ywe16DX9ng205kg5eq+R2q2MguTJxYv/wWHliD9mOYpzZKNXYC3Wr4iBGkm54hBwkPzFhiX/VBHdVH/KJ1ZIMOHxIN6arKdxrm6EBsgwDt0mPe0MX1HRUMq8ctcmysU6xX0bzM1J07kAvq33jw1q0Pq2cyMWme8F7aVkfhzZEFdyi8fVBQav0YZqvAjZ83WKH726rBx5Bn7GHFthR6H4lFsltu+jWmsAibJ3kpWMG/QbncU7n9skIBL0MuXXtj9sJg+4Dl0XhKJ1LcrMydaIgyrgZgScP4k8YQvcsBmD26X1iYXKLzMYfZn2IfRjznsrJ1e5cnl/3a5xiNoI6n1x1U36FWckJbyx+hiSZg0QqAqeeSvzFYMlZ2REnO/a6yoQhu7PdHMYEPFIvfyGeyCU8e7rpju4DrlOhszj9rOIpNsvCkuD+TLyf5J7D/wsPkBpscFVI1q7oUSU9bN30vH5AqnO7bsf+9rGhtVjOJQ32H9hHSAzR2ape4L0Cz4WxaySm4jvuGXwkFp5NMMLrgZ8LdA+5uLuyxO5SMOmJNDBcbbLefv7z6LyxBwltnfQLd7qqpG1MmNcoLUcx73BkNF/xpdS0cKd6G646ntChXSeTZJJTFYGw39T7fqXDPKoG2cF7/ZcTvME42gXLVjTqzAER1Rt5m7GYsh0X0+XgOeW9MJqE5j/rpGzY6vUu6ACcCTzDMdZHiWELpDnvgE1hmztLcSYz0MtNyUBLqvylUJJnJu79Sku9NMHCTkgqozTnhMFfduV2NLCSYvAI5HUvQp1h/M02vKFD6eosIkGTg6mujUo1W8hy5Knf/erkBQC9LzNqPAYCgR+hczgevta88NNqSlBZryq9QNeUK7RpbvHjoNhUKAAeNYH55LeTW36KyFaXdAkBvyNP9xmRuBokPi2OhqDby6IZ61mwfzG+GmACkS+G80A4WGON5izgJWeeDK91jzusfOi0RmEsVJXwbVUr8u/J2LCQaMnHhi+wJTEPN9tS2b6W4GRGCNmtjAMgPsP357nOeD3H2tcDAPu5xQBKMHf/j4ZhXlkvvy3YmBJsjsd4pSOlfPZCnw5JvzxEXM5JIc+E2mU4CgB0mdJnH4NEsCHYNeVRDXFNuyZUE4nuvaJf1h+11AWLdAZ72D9XNRcxfb2+XHZN/SN48U7yl+sNZhg5gn/PD8wkBtnRj1zBUPIWnoMP6yGUEEzuT+VaX3x2jEIZAZsr3rs9wCfY1Ss0EdIFFzBbyruUup4EPanbSYew5tf16/ZWVup5iykttuqL4xoC/jdZWsAZeSfDSd3fP9kbyAFYXkf0Q2lmxaTkKRZrCo9XCoiUG4yP1URJ5G7+HSOhhJp0Anz0N07QZtyFUye6rcgiOFbtyoO1lkuV0iQ602MTyFK9xLqNHtNy4cJaTO6hjtiwNynVc34ZA6H7k8ai6S6eF6jIG0xJx+JfP97lzuCZr8vU5SIzImaNpiQhyvDbz23//PJcOk7hD4iIvJzfIgOGIR6ZPEJpWHZQoacbF+omeHw8aWHaNOfaIyGeG4lEryMfhtNmWh4RAIpn8dLs7ZE2eTVDwK++xDoSUgh47WDmKlZ/k6OosEUoQjk7Q+Kp7OxwgMFShAv6z4pTW8loVj2+qXLQ0T3hmIue8qHy1o/HXjm089m71t6mrrUyDftqMYtmfvQXKDlZ+K1HR/FkqPSqcjGlcPPIwbMw3wIFKBdVMJ4pFLt+oOIkWZMw8pkoYZ3byw4LmAF+7BdicGXFcb5PWtDw5XNNVc6eB9dv0rAEpgr5J+bLr010bpfGw+IkRoxDbkDFmQdEQUSElP5bViLo1ur/23KN0jEwl+rGC6AUMKxHcv+T9F1Ktpn8jSSrKxJnVkK8UD/tH5DN6nXB8mjUdFU539e9ywLtLYCwmHYVEVqnFmdubduaSd1ivIo4pTsX+mJcOAkrR1D60RIoocCBIdwJhCBM1rOE2XSlPo0U+khALvw+zfxYzwzd4roWlLJkZheFRR8QB8v4USwmAcDswUZ2P/7v7Xa51Fs7orYebYyww4YW5869Y/c6Kq2eTR9HLSjYuChTkXaDygoo8nz/yJ0KzfX8oowaNAwz8HvQdlLU9V9hjqYMURyYvPzZ60G0itmUdZwB+sY6rUkMAZZtWStbDFmnk/dQorhwr3121XQWffrK3as0g29ASwxbsZ3dZAq/96b7/XWckbjmo8+jwdE680DzoEUUivnBgowMuBQxHXoGyp+w/cSGY88rWtmwoyNNIvChs/QsZRnbdV7y8x7t2RkliJV/j8e6qfctrTsMV22zoqgQuTSNFh7U7p/Q49L0kygXNnEYXCBDgi5BeNWxu7VjULcUHI+lGj+OTCEATzWrDmaynq3wT9IAejtvh3esCu6sEu9JOsXxMDpqxm4Tzl+pt2Wa5Bq3TM5TKH4N7KLir8FGIPA569+uJ1VEL3fW8Jyigz/nEUjAVYrdCWq2MnS4hQVgcvXq9aF7Xke/k++rAtIQqckPNwjKrV2t7HCOrA1ps88Y5Rw1Zp+9itnB71j8tNiQc7mV1kUCQXkoi5fOsq1uC6hUPUL7Z69NAM6lg0c/aeiifHoi35v+pVBh7CDM1XfvYpiK5JIbIQFHafmnhHfRTnMagKcjdE7zzgtxkTPKVrObTySTT51g9bB5ro/dzn/sB24fNM2LGJuRQsmC49PLi1jTRfZaLpo8Txxxczij5Pl2vur+S1wQW3W5qyVcIUySZHtFDQHv+EYDoZG1T1J7D91vEIV8dHzUBzW1UyuxRbP+M/CM/vsas6RzmS5traXnQ0Jzv9hYXxKHcs15TQCP744XsLjzFjILYURXFnhM+nnV0iO6nwls9TR4tlz1J9/NvE8FGg5mgpZA4htS05AK0NnU2gxuqf2vjCyWlm3ypKvaX4vxh8Um1MHGB2NTeAFhbDyGm+5w2zqJAWxVlj6dVePb5yR+aMhuz05YubCQJ0BOtoYQ6PoDoW5fCwCtXj5SHvCgL/3B5z2mcXWaRTf8/GsFAfX/ntdWZWFc2xg8MJeenwZ4dZUToce43If4zVb1ex3BMAWGhgkPwR5EgktZhW3Yi+nsnZTUr9FYI160YhAraB0zMV+ouHz6hYm25/ETDM0MTmcypoGgZISSkfwYAQaHGY45yZ91K4A4Mm4fnbMk8GTc4orypT3NLBqAxYdcY/qCH82PpIkmVOEHi1NoYaUymuImLLcib5pmd2MHTB3JR+4rLdRc3gtQ9zeFdciciRiWviu3HkqaLSxJeI2rgc7OKQslItumACQow89elXmi4P3gTZeCauvMH5nF4VrBcLjjwGD+KlKqe/RWIEgT2wGqAgSuL6b+RTTPnQZzxZ5y5HQJkEEKJp5NfoB8hJBM8qn6xbOFtyzBjVBrwSS1zCJR3lEc9ODQ5Wu/xct9/2Q6qLHnmNx6XwZus/i8rEd6UsVxGtoDrm+Br0L5oUojlwdcqyVV4PIMsR60JhZwJtgX7izQWj+GOeF9DA8Wexdmv6DWjgR8LEBp9YuPAM8tJDu3uCumNqHnF2ATYX/tuVO55OgQuiUhmDmJbF9jJyifBRtxOVI9DCNLUY71IXZYTuiYcnILQ/XHuVJ8aHDStL0N+3eYNvXwHi2vEiTPnBqzsC4TsPnFVnYY042j5i7C11AVdBZ1pGSa52jM9dIL119rry0mgGxFzI8xPs+7bmMfYKh37A4HtA081olG1m9S4Zch2hoNCGVvVhd6UL7C2d5hKIBHoB+Uxarq/4aQXhh7IWjSj+ca7Vhqb4+ZwY3nHXh2S9JH4XZxQojbe/eINxYlozTYtT2rpU/xbj+W2hXjFQ+z+dQ8wh9751MP0UpjutQdxz3/FJYAEG5BF400JXWCBs7KrCRf/l+F+d9EuwVk6thOPDB+HNS9iWlLmDgXvY6K0vgiyoeA3An+jWufdAG1suUMBuJT+/w0FNJZbObUT8c5q5WtQxASQF6E+/u8UwVBs1eo8jTamCrcdhZJlADJbqn3crcDHQlBQNGq7btcGKiJXW6q0cn3F0xzf+k1JJS2testB3rx15ZPTDXm8QV5XE2qxBOdM2n6t5YbxyNOmEdsHx+hMp+y9pWkcgw1NikeXuafJvzcjaNwE1Ad6gG79S68aO7jWpKgBETYLmV4ONHhBk7Be8tjf2WVvWMDQvQdOnk448yeMv1tQKU1xev0L171e/qxkMZbmkfKnd29XRCK2hgNNJhwt1qiYWZGKz7Di6K3fGDT7DO2YQ7WU33svE/WKGbWQEvzUV2w+VNYDocI4yxQ6i3i4zU2TjmjCwu5Pk+Ja9HSwLpEoUswq3tFJ1jimthgMXd7KjSl6Qd0K+vxWT8G4/+xITHsWDGSfQTSdFQth5uVVfa8wrkDZHTGVgpJys2ik+3I0dSf6TNo6A/sVptyY/kx1hdAWKPI6t/xj6s+fPMU3hg1vkEB0RRHq/tCy3KUUhzU/d0JKxTyjvUms5iy1GbOFco0NA4t83SK9sBmtLWm4kOLLflyxqgQYP08iyXwYXzKnlQ6VTipuaspSJ9g5H5Lu3eLMnPKbhcwuEg0VZ80ppJWjUnhS3rL35erzysp+fJhxsUs86m28/UwW+IgrS5Y0zWaxlFJ8xML5wk8sg1ragF+eNajyI0Y4mwStxt1RZH2BjaAhvu+SnNNIK88thEgZEsoHv+ii+OMmXJL7dnAiINVDz3tCnqDgpQX9OguNGgZj3axcjq1UgxDw785yNIpqNiLgv57399jVmJ0/RStNswaFIs6FtnkilFZldxj6m562jL4p5g3Y9XCiXRJX6nq2PGJFifFR7EyPG4jDMnBM4t+O8ZpEp3th7TCxEw+ZG4afHl4sNFaqxyLh6+979tt0Aq9BrqI+CS2U7HJoKiGmyVU1lFa3/0O5mNC1bzRgNMy+GXyifLwJP7FwUSUmxmVRpn+gnXWoIuswPutsiciurvN6lsMG7yqEc2Y5ZI3jrPgPq0xEKPZpF7teJa0TQn8BQL4Th+hjv2ByfwKookyXEmj0d1KMcsmfKaeKK3cZZubiYqmSCrnGpYTwgPk5itKucVtjViuswQsDR6TuyGSIHYvlz7wkLg1Rr0K9kV1o8RgABlhbLrN74cVWJW6TnfXN0q12JFMpUbEa8t1+j440FA+17o8qa8PQ9igkctVROVIfB3jU5vtGm5pYYHYSDvU2TEc15pIz19ka1q6c/7WXfF8+POkApdOw7nn7Kqz6V4tru7NXgnA/u0g6+fPRT3hp/QrDQwMsjwNCZxdWrR6pgCBDJNc7/KAlwC0UZ4yWQs0KsuwbbOgcTxQPK54wiXr7s+221hzZ8RVxfoRUKM3e4lpxHC83JllxlrV760tl06f7/65qhE1jhMfivAUXIXfRMe3uY/G2TpWYzDrw5Cm5cS062Bx9lhHq9gtJp8xZwAtSdSuW/Kd7+orEAiswA76N8ezmVGYgNaYlQ/xk930LAWAtKVBC4U6R08L45IohB1kFia7XJs0TcaT2zBZoLFuOGu4iJaoAnfjL3uS6gnRH7G7A+aT6ETlmkYUfgrBuaSLLDJfhPJe01PfN0oqBTeQURasl3N8BZiQSgdr0aDv3hPTiog4NSyfAUyy98WP7dnTDWQTY+Qwzgk1uxwRqHl5MpC/84Cuw1TXfRlgJrwPop10kCHjmffnFdxCe2J3R3J5j+3H/sZn3IUu3Suy+I+dAOMWvzwExNR3RRPVelZAhtarKlXPWNjPRIVP4JsAFSRXs3o/fSYAPaV/zP8q6DltH47/rYhCLdy/LrpOsbaLf09eACcClJosNefetNElkSFSuCgeY7oTAAl+8Y2zOXJb/bgEDpoDXfQqc6lnlBr/WsmVznkBS1M7ufiqpxvKXjwvR4WxLbh5NbMNy8LsnX4UiuAi8XonbSUcVZKQOWBYUecSOMj6jMG8gHu7WNreBHY90lV7FocDprSrSbexkAtMW9KlXcnrOyLnZdodGYdxz8aw71HztIqLhRdCOB6NyzHPoS2hDy6wLk0I5Jr2t+U0A+A7EsgSn/Ih03A5CspHnVF4MOic+Lck3m61Um+GHDEe4DrHBhmgtDlRQl1XJ/V/VumCHtUDDcZCkgjVMBOmVOGYW0Rcdi1ahdjhBcFlfjA+5cRjBop1aNDvdrf7CxkLVgxiCxhRctW8wczM8+kVmIrGtkaHGlr8y2D098HXE23r7fnJFUU68zyeyM265igNOGPzFG0dIgUDWN6S3ZcfMERJdWVvpGhVEHXNLeWqHiTcF3wOt0FbJY4XHEpmkoG9MQPJJ4ueQ01+MB+SR0rCSGzlE8zod19q75LlLWgzogpnJoD4gPxUYcX+Gpc5Ly4nk+Zm8LDXcNR7SNVxLh6NAcx8ekjb/AC7ADlRnfuHaHJaBodZr7RBX9FLTvocY6kY8bavdAkQicE9bbwGLkZu6whTCJ56lOvM39ijehpTOFqR3V53nQx4hfOvwRPU2y2w7UU8yiRbcyaX6jGJ9CRvl9ybV1tebTp5MMuMnwLcx/lven0w9T0atJuiUE2WtYGiVMaP3EchABl5AsyaCpu/BKAWDFvU2vaCL2/fJBKCKLjxG6xzT4Mh4wHhH3/EqsGSoQAHu2wbHmXHj2LvoW19GXDa2oyeKRwGG1PU+S7mE/S+UmjHiDF1oqJ0R5QsdjAZYN1MzpNX5YDqWYfhfdjAXyFQaVyGKkp1oEGTR8MK6jaGfRDFd41u2Ex8ac8jKPYu3pXsk8gu+m9tr1RVzTTuDsACW4S1h32yFHX7qpXSmA0QVEcR8W9j2Juu0pcYqTmdis88VgT3gq7iYue5Hx/3K6hFQa9rZrNSDcjaSQlNn4LSqs20bypnKqpzvnnxjMdz5StbzvoAJKgVZa4DLCVoJW765/KyTF4s4YztmAT1c0pTmKJHTpa106FegDo8p2zD6uOnwpYi0vJlRMDe9wPT6964UfAf6lq3qWypUOx9q6BbKEYt7K3gWMXDNN6wAm1fNnSOnZ4JkbPq7jLQrl0wL1V7QwO/sXneKGfTgUL28I5iPVG9dA2gS7Ki005JUR7Vmw4gX4TJvy1WS74cIXD08LCF5obqcZwamuoZ+FPMJEck0TLHjyH1baPr55/Cy0ptDfRJ7d89pbP48tLMHG5dO11Z8xSSpPGQSgXDWmpsNsmm+MvxJjMCi7OFDHxxpmTtjgnOCq+c7Fi1DybfhAntviKccz+sj+OPKPYOKeYYPLvq6MpUx/chSvBccg9dfbeqetQNCs3eiCFZTU1mrDido/mib64STMgsa+IKLk9PyxGGbVSQB9GsHto6f5prAFIbRDSItDedz3t5+Nn69FFS0nEfmkF7hKBmNVce5xv65USKGBoHYxJyutSGnRIq7vMDsAMvirOEJOzNi5Kt7fypuSU2c2Npo6UH5jMOkePH0TwgpammO3Fb2FX6f11309z/mqRmQ949HHRj/wMzKNx95M9pwKf+UQkMEwisL3YVotvHhCv4y00Ui0Ql8dR7tGqFcSdYtmoAOuAodkBNs4PZSjAAF7S/szwLddFMdCyB/dWPgFUiUE+WmUUCjYrKfJLQfNNpQ4NKaF57w7Kp/isZVwQPUJyjJavN3fQNKU+F74jVBJYQEcEdw0Niinyea0l9PJ1/AcTm/LI91RZjDvLI81pnat7RKU2P4/TnIAa3hIEfeg4iGQ+wTDlURK6YjNpN5s5VkQW9w7sDYKU4XmjyZsCQLxztqd4SDQvLyuPDhURAJXKfR1c7tq3mRu4usFHPqz7HgS0X7kNxiWWR3fb3uVwbgKpmgLYkwKrXKt09COw4MjhxeZlDXKy7nNLHXAIKPtferWQnZLboonQXK81x+BB3oUidBehK1swSXxVbscj/LsfONu/xYEXYPM3aMqIYd+2hAnFvDHbdrJLhGEd3sG5PyxqhzejhQJo9wauFK3xmPYqxB99J8zYU9/yzrEZNzzbvPoR9vUlE3Ha4zspVDzHHffPZMJ1VLZkKqGCf8ZqupqMt6T+NRPfmPm2xeDgvzMrRJEL4/zzlu7Z35smvzbgeC25VP2CUrZkRxEi15A0769ojdO1d7C9OG+swj1ROMM3NgKdeBADoRMeJkRZcZ1FbQu6C0BS9NNSaoxtFzYT4lX7+PQ7BKa84yrN+ujVVef+SgnEie1G0N+eOtbZF/UU+wkeerWjloYqFiqo0vBnmxh+TwNMo9I/8lfU2XTCT0K4OoWE08ipyNHjxHvfhY6qa3x4HzdQ8+jkiO5+j91YkihS5memfpFREHP/2veN5XcRue2zCVuAub8V6vDlOvyP+PBm+owyRhMmng5wwGGIXsOkQekXrXpE/6dFjkHwwoFoj5bIFiqp+4wHpSWRbv2xGrRpd2c87FzMP6Hfj/3LWIBqFiNOAxBw+AAP1XqUBszdZhzOSQrQS4Ein4fyV7MaGsB0VsMF4bPb4lx/foTGQRJv45LpoxDd84xCawHaX7jpXUrOdkFxx2oUvY2xqpgIvcVufwd+zAnaaVTnEyDXD7S/o/xrrk4mgTjXhcjj5Rzrbr23NmuZQvpdNzny5MCR9bwvIRIqzOZZLsstZSCDYa56JTvzxgBs20dYTtTUbe21uljlWqGfSh2bYAzOpf6UguK30ZxNXgLHs6Y6urtxFA5iLYvlue5mDONW0MOtQjhqr8fRbCkYneiDkvzHkQVT4F9v9vxh2SIGPBH8bZb8ugo/BSgXojeSdNXbBAIDsB6DUNSXnwlu/bFLaCqSbvu4+YLplwO1JbtrMf9ZUfsxerAZjB7E/zl3qwgK27FswemUmSM4i37YAVhQSocuV8AcDI/CSeCDNPavESshDQ8A/lVIrAJAMdP/rHXouiNU8RL/TIvfQiuZEb6dkIKMGGOW5kT8vO8pivWnT4v7qmwuJo52AS1r/RyQ2g/7c9ZJgmMIzf0GvJJRfMNu1utRNuLWHOm9JIMcJK3qiDtVpGCDP45W1oTTMUnMC91kYhP0GHjhCW8V38xhjHgFFBfuWMsmSQ9MvNqKXiqtUhDAkIy0PW7YSKaKUv6zctAiIk+Jt17kG6LpNVOeMvJnlVBaJSkKe0HTJJUMvf8R2zna35/yh2wNlWLzIP3BJR5aRNxkV94ICOlycI1/JYRZtzvWMNoIpQrdNvyBuBydhSwhRwPo079Xk/XQZpbhzN/KK4NbdJQV0JIMP+Y5UBIM3TTYlFGYVjcvA5yVozkimco91Fx/eo+ydgAx1gMezTh+bYxCtXPYkMoPdtaElRusxlmdSV9zgF4Np+iylun3LVxCycAFxGCFsmARf6y4I6zXY0tx81aQyalr3/ih+ZjxGNWdhItgNLdEZ/BOIJpPoAveh2bKbEFxU/M0+4xqDo3Ox8MnNn8Lmv15NJigSvJV+y2W/ZogEXNiv0/nuFzZGr0pKujOShzcdkEVlMw8mNZXZCbtM9V+mfawtLxCTvo+enFWhJcFv8LVTFycDjPGBXRQKNN+z68HJtYdpH++g5WdhQpCO+DE7Qdu6TmZgtetrpU2ZlgpslOx+4hb3aXaqbdc92LCh51er8vm1GQ9uWD9+fAPRV50ixhgc5zi2Jsg1xQVxzlaELRWJ5biyF+eCwNV0oFnTbBHr3Glm9qlGVOpoOsQC8hlNG88fxeAekkCGnHFn6i5WzyO7ShDYbZ2KM4eqndyy01v+6TFhmkxgc0dndt7EzRCcEfBxSaWZwcev6MDZcuvSZQ9CNSd4Tx25TY6UAbrhikuP1vNFfPdZhCG1pe6vx4D6Ez3zIb0zDa42FPpxWvIpEeXb7YTcfZOahSpSYaWLH/vq0F3U1KO7ZxliZpoMBBYJs91IE0bOkrPNQ/USYY0qKCO3CU+AFbOYxzKWBkIglrX34377BZ18MKQCv1KWfIHEeguSpvrNH5RQOD4LeiH2gdx1MOAKphlL41F4RpxaU4dy8xERFgqoyICQq9XmQ8WJSokwqvhQM0fLtsvyCO2PAkJ3BZg5IqoR5q/GdTLgOWPFR53Nqw9Ma5vBzZcQ4+iZgetmKg5ZIn+/7Jbi+VlViXuD9CaAUtdEmnwWTS7wZWuskVvc/SDaaKV+Jz6HrZTHo3UrAu0IZDBkXWmL+mTTjdTb1A+MdhKkY/hvFNwXj1FzUngsN58u/kTdJ3Xi0hy7efR6faAOi4SKGaiOty8lxDFkiD9wq2GW1EZEsoWGw/WzxXhWDzYY8CC7WuLFHc+x19jhH+FiLXwDIARRtnkJPF2BUPZ9+grZ3tjqAWhhN3h74w5pooRQUNATy05A9HDLnILGSCtfESoSilqtqAIQ/TV2t3KhOc+teDf5t+DqZDdB8Ob9YXyklrSO73pR0QAxPvQj57c6FIR5dOciqeHZ2LRABMROo8Jk8V6JFewCL8TCd/A5MSbXLky1cW7mXobqgeEXdFDoEydKo5oCuyn+2JYI/7pIGFAzErlHZ5hOaiT17HC3zp2HpJwsIAb4/oIoZ8x8ak43Yp83Ermq55Dg8HxKGHXbXs47sh0PzQELTGFsf5eO3lYAuJjMneoYWk8W/3tW2WLntEKBZEW4hOFgo8K58Rj0vk5KLyezu1d8SO/JcuxpOJqFUM2sxBmbQ/9qqwb90R0WulpR/Ju84bQ5/fTh7po/pbBb7AQaYNdK3fatD3K4TLHAaa66MQzp/+ZGyCjzo5OXRzJ8UHyg/YpNHvvlOpwQIOjakpLHwGV4WsLDPjEIqG23ily3LL0dlkYQxj3Xx0ApCo35zYGoGOtIclYS83MnI5TwVdQ+Hg453WFQN694DaqhGaL/dm0KncXYqXLi5polgT4DOrzD4oSVhrkh8GW2PaXjOFDCLPcn4RQj8dRGIJuV81LxMPZ0UL6zpkaebhbFBxcRJe38UiTbUPDjFWk2jBqzrBvXcKmgdDcmRyJhIpuq+3DQY464AlY42z2EM0yIK0I6b+VgpanMfpdWo7OxKY8RM5tSJv340/qD8SxrYsybMuUkF8fHj7HcvxEPC5YYrH4LW1YKg6QaeFZLvPbrHZHvi4OXLKkN8cGQO8019OKqcv6QnBlj01e7qS5evoGm53rv+VmDxxCXDiOrDg+IaPeMPrn8TJ1oReXYI3yb+4HQbikxP5TQXHk4YXPUv95+KmkxGsRgTwP71YiMpqNXp0loHZeXRp9i3euKrVtxMM0e6XAoACwNtcc6sOuhZVb1htBLudzahrDFt5GkdlwHjZl5y0LbvSHwII+qYeDwRKTTzyXaInHIM+8rc5TrjUlPRVwB5LKFpQnV8e7vLv7T7V/iJTW9h9TnRtNCSGcofBWYm5P7wZcAq3AFamEW/GMbo27ldz0plt5HI53ddWkn9IuCZY+Iy0MATUh3YenRTbVgdLYtu893SuN6EL4e9V4NhlzUjI8nOS6B99ecyC1Ot8sDahQpWHbmt2YvWGyL3S9tEVLKYs+LnghBmmSl2uPWfqPobPwBHNLW21LUjfZb7jfLMTsMp3icGO1npK/rCsUgdBVKVg0Ys+/WKuTmVJoC8Oe5h3PK1TQhbpZ2ytP9nlutQPtLAEt+CVT90DfVkn7lHLOX8AfS6HLzfHeAhu1alnl19RHKV1LI0G7RPzYgVaSpX7th9f06uo2WpxjL86i/2uzK2qj/ClHbGDyQr3F9/axmq4kJ7zZFVXVVwfiFr5bhUGVZeQJHKFAcsnqPKsb8vHyB9SpFpT9U1U7D4aS9vYgqajxhC+hOkolJV2dKAxysCkWBo3SPiPUrSQYZxOWwWCoQzbV0oeaDEcgUtqI3nq9TSmpQ688/+wb26P2CHLY1H7q5lypXSrnwnnztq/jN1o9lyvLmLyGguV0VJnDCREkiUNrZqGG06MsyA+Phd9CuFoM5M1Pyk7S6TJaHdTw0ni3n5ysAup0kyxr65lFc81NcH8xSmpp+iOEtQZrH/y01k1rGMRJAGFhi+nDecpUlnrh+qBOCMZCcSCovOPJrxjZnZJDMLdpMVu+tBSVS1nKxsYjY9Dtq1/++riVfLUVhzofIcIgQQPOqHioELxU3EpCcZMoL9laa5YlOZAMEp5apx7CphrkL+fyKbBAf8ctwVd93FTo7F5Oc/alNsCgK6lHruPROtN2RybiLqx8P5LTUZXU+Aoyz08zYHasR3U8hPDKj+6arWXR9yWdJoMn45prCSURKKy3+JHgvs2Ot6v6GbEtdCumgCttv2VNoU3KOqUwqNIWHqYm4eMijTM9VWB7umEyp7UPOI8fduHJY0W9xSCZdvc2xMjo3Zdu2o/WZKDMOSh9UmLvo45IBppD2dG++HJu8kbfFdlwuIxk2KHhgHQeNKcHhFkYGRzL2VJVMOAb0Co64wvds5CaYl9ZmBm4zuGDeaO2eI1XM4+rD/HmZyRF62SabgAe8TF43VuMutigJJMfbW2UK0azGLFbOfujnHD+GGBYmSmOQbUCOY99HYvswBQA6r9hrc2jtsUUxLVjxnZ4JnIrTwIVdWCTPtpJpvlA7m01/4tbUMyz9mv1jdN1jkiHQCJXXKg8bJ+aqW6rbwbn5yDSHBTcFXIegrhHGAjJOZI1pyP83Z3vMYTAJoo8V9IwyS+U6OVg78+IhSYHDYjRs8FrF8smHQ9h4qAYxp49rRP2d5uxLAuP72GvZaYvfeLOkMrcg0PkPuq7NsXhMFmiZa6PKBH1l+oKHI5DBLdZCvCwTPdXqmnz8gLzVRb/ixLTSdit2nrzt0x+5rDeZT+ac31NKNskQs6noKlQccyD3UxzfVZFmcbpmrfPsZD0Ve34xpKWk/E9Khn4A5yVPVq+dwnv0EyYecPqXGU7R8suTW0A6NJWweLI3iSGDlQXzMYsSWkSMhFTfyA2vTDt/3wXk+mVU6bRNkZvNnyVHYiA4tmnNwdh/RVsk/EgSerfTIf5VBmuAc2IKSeL5Nbrg3acgFj80mI8SWsc3dNAGCBLLMP89gH5UnLTKq78d9SxQH/g7DVnBh/qnBdw5CDrw/uMzcdXSxWqGIFcnQZt/1aOHxUg88MN2w+FPx/V75gy2wzEVe6G51PQIR2tZsxbv62HhgjwtlzrVREw/yzlaAiuXC26cnpvQzWXp2mOgihyPCWqq38nEadX2T7f1Y5zGxEGBaT//IcL/BsquAJX5EDbX8X1p8nLWR2yyjFRvqC/jssoCJBCDJOsZvoBfXqQSEKhNARH1YfueeKBslAwLi24/wAO1BHptlf1kQFNsOPlDvlYednrEp3a4SAz/G7LIVEsZBu0EKWZu/euB/XKdkGonP6t6lgEcCOw8mceuzvEVzyoPnMyzrqoNQXJb9C8ZCXSiedKiCgNwfNkpVlHbUgE2Rb9WFScOeEad+T+jT8XlSc8rcvkIuhAv/gxRu2eb2GonLTyokjcGF1EBpCJbhy2H3lhL0rdZIw1okA5pBg2oRfQceXTPzhuNKorTEF7t1UIgDqIo7/loxyTgbtKu29o9K9KujvCqUGyPY7upcfiZLNBVKh5uXAAZjQjhlhBp0ukmO4Avxu4xAVhCtnsOIA/tAm94U3HEuSr3wq+ZLo8pyoC9EB/q3pOzQRyCTkozmJwo1Ln/2xEbtNnS2S0NUIS3yz3/mBIdxONHxqP9FW+uoGI1F415lI1nZwK0SoPA0+flaokBGEoXgZnO4GOExU7VOjdPns59ekmDxqNhEHeAF5i5N/3W2NC1XGFjTpqLrnCECiwVkOTrLtp2ehUIaejOG6+1336YQSKMSsL4zhUjw6SQKryVRz5Ldn3R5/r8AOi02RJkQXPdvPsl/FMg96E/cJmIFLmEDzr1Gkh9G3zisG4pqM/MV6XIz+CtDUh6hmJB97VzN8jaPSS90vgDjvnaNlKky2/zIhE9ObugwrftI+Oi2a4VVaB/Mwn3VmaWjsU9NOf2usbcN/GLQMjvfeU/YvyEERPKw1leXZWWk1HXzY3P9MUq6MZq1hkEgFzds51mv8mnp1i4pQprPwY0TId1szXwe5TG+R5mMD76nGPQr7/EhQWksjsgGs7Zy5QYvMcGV5tcXJR+6hlHFIAc/M6XjkKYtwm673Bi+K1tNO9i1YBePTur4I+gMsOK7f7980mcJXhgdWdhNzUN2JvFsvXq3zZRG2V30sJtJYxj0aUv1u4/ppVHi1iHnTY3gDHsrQS8YwMX5XwZ2gcFYYe2wd7ZO9swr0gb8zf/fXx8QWKPXcK1UdJk3760B/TMlpWLCbhkqVoSTsOqzgkmFmFteCCTGhNyvFhw1RrTIWzRxq8Tj5FirvKvtkp2GAVhnZ7vnr71pyI0rKwQbVxKZuqM7GAvn2mRBj5p8djlHUsh/r/eBECptpbbjP5nFyuN4mvQLZCaxeTkDUzd/kNGLIzBFv1CElQO+xmf7Dzt1f7GM1Bh+wLDCJZlhcVDXbtPuGssdEie3lZNiWcXMTjZtWAT5MCmpq6JCRuFSHZYGKcSFZ9kOYJfEqLIcWdzpTA+Hmu+ktgSUwXVSwkaa/aHdZXh7IOyrudCBalCZpgXGRNbhN2XpEY60DXXO1Ci5ayZSoxtG0WRCC50+XtgWz7qgX5MRA5S+jzXCYy7O7Nn0ljVxiBxQNCZKZMTqi6mPfy2LZx76uyRUXHjnpJJEimflHDUxyX7fFg7iJvSrsZMH6Uv2xbfQNx5eCbx3oKycUrBY22KPmgfg/w07CDVsw6tb5VxPg5/X38cQtXI47U7MAGGjO28II12T+PjaXHlstPtkUQNn0DKkCYis+kVAkA1wyAJgYKLGnKD3nlVCarYqCkNIZbiVwO2Ydjl7N6iOtvvbAfuq7VKZLo0jEdw1YdsRaHcuJQulgb51JyELzYBkP1hd03IDcZfPg5XmNvYQSOINsCSn3BuLtkCPZRalK7+S97zxvJHiJCZJM9XP785NZ8B8fqDe/Ot0BS3PH1ptErwxBtpgfOj4d/41nrSjJQf9bV1kfdBHJxYbHILxOsWkZvoP/Z4Sl0Yx3bDjTF96xf96+6uIoQ351Ce6DeTwTnkPr20YwATlnhskWIddUohklNITCq/07zkiEc3B58uiBG6d9YAc4h/7s44FN2RG1UuZWeojrOZIhElvDP4KqHcOYbqqS95o7ilQH5ONJfy+aYiB+sPpn35HfHG3duLpNvBjXc+Klf4IKrFHjeVty02xPTNnbdL4gtkqPqMLhSgR/fDXzxJbSScqewiF1wdVoJ/fGL/nGWZfVlDHOQKD+/i/mqwXqvNqxtZeRHwoe/bodk66B9soOnZp36gdzVMRRQsQiBFf+HXjRcrRf9FsGghw3+qoN0JeeMvDJrkSBPsESDai/uVOzn2Ohge+UVdi050fdWpsjP0D/QuTdYs6QyI9xnhU8WT2+KBKzoZ7Bq8fOdKPeLulUhJjT34/EOnUloqus8+pzqNh/UdUOhgTlrbkuTfsaIYDm87u/GNIl3N53uaU8bgaBjpz0jdu1f59K4KFDtwUUeEUoeYx6DEkWKHdi7dtHhQF44lbysk7PqERrsuAQu2D5tDMl7kFoGdI8r/s8rMytJzYBU40wqeFvTl0ZVLdOB6Ya9E/f8VPbGx5MdpYqYMLMyB0QxVdnoJ+tgAQVWfH+jtOHD3PsjuT8dOTSrupuvHWRHQoGI1Qj1Hc6k+Mg84FAZ/gzl3SEzuGWZKFwuo2D3EiG95D2Z1szTqAuFRmT1nEh20tkC4ysmXx6JtN0taK1iRR62s2uNW5rSAvMEJ8yotr3UhJe22brlQn8Gvcq1I0aODaHJucQKVe6SXyfcDWODMw8xf+2C7Zx5a4Qlh7pJs550DictL4OxcDXKvVmLgVWRwb3moxv4kcxzm89EERJXCl7X/BziBkGQWOHPGF+6K5NFJYOFVv4+NyFq+OPMaSWZKoydplufY+CYyL63T8MCMmwqLTmAE8h0prhi174wnx7DHZWYuRJSYZ63uz97AGOzyI3aebclnud77znbZetbWUripe+AadLQeZPtWsF+FNiaXCy/98km137lWewyc7Gamai1Hd3Ls+KMMVh0R3NKTQ08TIClDfMKwUGKy/7YZlJHU3uW60X0r74Afh02v5MJgVOYkjmors6GAaDU7yKHydfkXYd6nEjYc76xws1LDLWCNNKBtUHNyLseOyNDgmHiJ41lXvq638RzDGis8WIniOb/pbTs+HsQVGPi6mxG+CU+oflMR6/qx3pVP+GPgqa0U0lo8MVmI1cBgSnPGgrh+J+m9TVg8nivua0EQP7xai44ruC5gsAVOp9bLsDXfHQujo6IpBmpfbbU8PDavZpTuJtmflVQuOImnRQ5kKoQz2NBFjdiHH3cF9QLgDP5vz/W5trCy22Uk+TCjXjdbCCHB3rJhKYTwiyQUf8xu6yTKtIwrbw4tzFgXDODmWYEnnpDupk3b4AP3qz4AZ2En5wi6aZV287AgCF4vH8TlWLni1E5Hd93vLxSYLBWSuj3eXGFtWyWpBkIeKu+YsBh19VeakA8OePM0ILu6dYYl9DNIK3kU1ybH+A5xYhFI/EqSX3vtNs6V5eQgxYLvu0hYFjiG+n8JzqLQVROiVa8XNQDYJtDAetPFSuEtGI3B8rnbbrNo9TJn/z3lRYq0ecBIe7a03vLESwhKOm1bGTk2kPMv/Sh9wyCOmIore7JhSFT9HIjonBfi+gcdDLfFt7dpShJmW1gkcXmitWwm1cC480CraHm/or2MHphB9Q1bmt/SBXFqXJdcv5GTt3IS2fRgqThhInCjRkh7Dk1iS2vMBLSGtRPppb4FEu762JehUMQxxLQre365CKoJGvJwVde91XQ+bDp5ZsMu/QHmLgITmwGXSpQFQlQBajqquxlwIOe2cyfezaSHIoRNLcwjW+epnmAtmmWA9KU29v/cA2iuWbj9ZV7HR4anhHkjbxnzKPHnIZ7Mm5wAf2o/3xUhnfH++quS20TdhalHgNhusidPKWyKWV8ZjFLgb1fX2r7ifLyUtxuKHHIfCWXQJ/DKeU61vxmPT34MTi2Q9r7/sK1CYuHVqMBsgtfenn31bUzCoyPN89KiO5wHveqnk3uyHnJSUBVTQQ3NyRPmeRKTQvWEBZ4QWcSgMyZF0RQgvUXRcp6KflF056fwahSioP622TdcTVYi4cAwSZLWDvfjoKFLMowPQpzn6ogXHc93fFA5NZmnwslSuesOyNI1EE3RM8kzat6thkmpOiGmm69Yn8yNuxz1YuuPWekoybkee106T9WTPXo44ea9E5QH2Ig6FZn716DBa2FyXHG1B+YfnmhbEpANlOi61BoGO4+G3WMJDokJXj9GhNsFqdaLjA1pkhLP+/mGCZoYsxNI+A+sMvWyoj+PMWeR8koRz+r9pNVEWT70WhiAkNTrojdr0sBLwxIM7D4zT+cVy96ZE+ABi9CqkM9VK7iOfkJVp7AqCqQ9EZ9emn8rB8zfoQZUBrVd6YS2AqiTFt0nJ8HfPGmnBWf3Xi5CgyWoLAmHJp/AfTdHB0+Ns5DlhL6UJ+O/6xys+CWVKtL9S8fVHkpwZZMJn6jVtiUTtXjywmiVXw9a6f/G7Qd4tZtcoS3aytxXYA9aGGmEeBobjiammhUaMDicH3nlOkDvvz19NqWOvHC2SMv7OQHtDIykYerPuoLz6SQNOBtw6oX2Sj3ZLITBDcWNx9CuZYYVaE+vleXnATrwn+PnuQ34jL52tp85aIOk684SUlQ8uyO2t+eIOHndZ3oxD+BcMAba/JVxRYUAUZoEw3D80WWOz0/ul+fYbhFnffx3PgOy2LLiu82D5FMSpi+Pd4EkIFTgfv7p/0vnX1wp0VpNzyXs/5S/4z0RFS21vIF67k1ERTfFuhLM/8fdbKognohMqTNF/+oqvXXLuJB7IHeDdn1X2eParLBEpz8y9CAN2g5VdE7EimekAOhkw+tTzqeEsgyQL4iVDnWrP/RcBd6CDm16/5t+I1SAxCn9wo8knzmpg8DYP8V/vHw8Stu7cliAt+G/VR4XPNZXWF2rZBeQO75os2jFJrbtkfhN9BzHT4HGgXTjyTy8NGsiQdeOw12GjYKCyxP+34kRHZqYsn0pFvVubB0+/emKRgiGXNRWQwMSvAB1xvTprD0Zyt08BjP/4W9HGNfNBcA0Qb9qF5hdQ4dDqpKAFLoIW2gFEVKOganw3M9/4WP9ckP0/g6kaJDRurtxNgT+PjvWYEWlFa80wKYCkd/0ZChV94njjGyg0t98Pz3AL2AFAhvRRiJwdfRcQqqhWkv/o6X45d5w1YLJOye3v7rgta7Ya0jAl/an42ng5Wz4S5we7n2+1W94JnpoGyV8WW2HYjKLkKmp4hBKlNtb5y4W1MrsG/wfq2N5Xrz2kqhdPQL/YoxgCQd6Y2KNkADVu7TxugQRWVuNL0BUj3JRFyWNeCmB74Wsz54OPnbq0GFFxzSkoiJ3Rtq8yEJMKvOMMalFKH7YFHKjb2nwrKVfuUUuRtTfJDiBuaEHHoX+MUrM2bBaAsSdnY5PjqcMBn/wwojQxzt2MoOCC3OEArr09ghhsj2M0mue5ntQcmcC1R/sK3zfShGJuazS+mJUeKxk5u36CYj8+SJCq8ZEv7bNf1+BywGeDQoTDGq6Yh1xW3Suwo2O/ykazTPK/TdVOICyiwK8MuQpK+FX3mqSPzxfLwFJ/iYDjs0WgW2kqXYgm+gkNToB5+jYH83Xlt0cbtEmkkBaVGlHz61rVuWzrK1yjn5nYHKvKCrBPPRth3AKDQQB83fdrbgIeIfB3iHya5NPpEyxbzmtN5Dnk7GqrQ4uu4h3QSoHU+74zs31cWqIx4SZ2bwWLvIxUtR6gufZhNZoMcmSB5z1O9TKvHMORD+VmuiqzsyJKA1OaApB+b9x6u9FTvUkalgl0r7raV+wRqimc2D7B1z/OiSagdd5UME2igLGUcgPlMSX1VsKQp/9yDiYei87KTBA2NPCUmgaLwVdvQFFFxWp2vGCY/KCUvxt3FOu6xIgwS4Vybvbj6feUCkrQPpO/wPHJPhAobSj/aa5YrUvjHMcQkDZwfc9mvghrk/PIPvcJa5InhVBfjh3Xr9vIvA4ac+m+pywS/EqkSX55xgiyj0TB1EE0NT3W2CPFdVD88P72SpdFzHS/6XsmbGtM8JE/m8eojzd4PM1bNADliZ+XG/9hbcKg6PftVKyKKt/8Bz4lGsHyT0VKj2vDGp/qDGBajSHrqzmpEjW5LXsb5kTV6HgbMcnPW2dzQju9N1sI/gPVlgGmk0bHKOX2Ws1q4aPizhcM/XiJ5EZNUK6bZNUeFaUJVTvGxglRUY7vdnoVOe0Raho3huh1XDeTlHpk/2gBjjhUQXe8FN5A4zcRqkNtKpSVq0xyw9j3yQlQxq/Lnqklpz8lXmzHkz8sX9HJjHwyn8UAjblvN0ZFIk4liejx0lVACoKvpsT9+pQoLY4weMHRzcuVC60DUFkaqLfclS4UJti5WK4FE3dYcc0OilX50uscLJomlR6pXriD6ELNNBWOSMt50CJjPkyt3Zn/xj1dlPVP1t6XExK+b3jMoULLPOrEGvjELfAMM1qcuBb0AijkIuFca8f8xapUlkvLjmmJW7RK94r8HaPzvmHHSqX9MXdivNI4A+JHy0VCe79UZZJvzMGzpnsj+Q6k3EItDBiA12fTMlSbEOMAWCdQq9TtyUiAaAqJozMzryEg0k+yVHqCc/DyJcCE2V4WXIhEnsOc5c8f4ChWfUaONhPPWogpDs/lyVCvp3m0NSfrAJKNiVy5aNC9gZ6c9BqwYgj/cDO3kdam6gCjhR+akALFYmt4ixHkWxKhDTGs5K+CwRiKJnvxP9dbxRPCBHbiVa8gsd2GuiNHZD98MNwXMdMC0MubVodd7dnyk3UQFfCIIL1osPxY0ZJ6DvZXwtZ2I0th6aqlTMULVo+lhSIU/5qO63lTSa3MgPRJEOi0AJ8/UlZuvgqLw9dyEDQoHTKWOsq+6fzoAyvIpv14fLaY+braPd6NkSaq0RClMenK1QLH87NZriUaeuCo6SZ7/CfUt2K6VOt0AjIK2jR0vorf6R8+TVzxZb+QdLimH9pU5tQc73xW93QRPMGy/gCK+R+YzmV4fHK52GWBEBL05EEoTY6OYG1WWji66dWnVTg0uPNw839p/yjLxkCfdTaH+v6hVUCd6HlROj6W8Mil6AYGC7NI2+qkZvJh/dAw/iQspXQNwwWHr6slLIp0hBHYTDh/J7Ba7ZR6cp3iU4bSXdmzhTahYDev4yKiIHyN64EANhI5OHYv1G4KXfIOvQizYWchPhzQg5eVGNMxsqrvWVxjtIbkKuHzE+IcA2NZ83GKz0D8z5zmgRnoJGKigseP9TmMS7BgAqtqyixA/SLc1KEUWrhXOQ6kA5ZQRazp3wwSa404cppBnfsS8EsEpbr/gXyW36cZ9pt1RhzyxGxDUmnZeBz/Uf1AP+gyLIg9x04u1fThm2w/H1ZXGvVqsO1VqutV5gUhFkdkwoCjzz3F3FUr1v0njGYT2mSZYvoF/fSd1W11c5VIhkEO06US5wYRmHVPYXmZnbK5YHQ8pkIDJ0yqssqFK34CuHE8RWb+Dr4omk779QOOcYomAMYQ9ILt2KUk2uNlahW/IjGtenuGLxb/t3aFoVz4oNwMZ7iyp4td8mdzgJAfnCcYtklubGAUB9k6bGC5DSkf5VFarnGEBWz600VGR8QywZ+jIYFZbtKT2QdDOYP6k7D8qVgEZByGmRedZRWaQDTggLyNgDD6pQwEeSs82+hTxWypqwU3zuAWqfwil+mytzVnKztyvMFJyJwPFaPr4Z3mTjyxCR2Jv674JVGGMUSWb0l+GtcYtd+NBGChwr8mB2hlyccget9liJhQEb0XgXfgVRlHlbO+jlZ9CcAew0Nw+tRcWgNnz/GL9Kur7RohRhaYZBBmQA6JhvzkazHRcdZDn0zDkfBmYP1PfQjP3d6qqx6gE7vrb3lBKEfK3Y/nCe4COdpr23oZCoIpssGXmqE8CGpO2bEwkSN6uqeqR4UtWR+xsgOzNeR49PTLJpFEAkXha5YaecJ8t/KR+eG7/HKV23zPZAMvHDC1rdxQ0l+6wlIgZbUybjBe6yusL7isRuuYYwg4+8+4lia2ox8RCdvmXlt00ZshBnAIfLkSwIqUzCcsD/d1ZG6Az728L4FCIqBKpbA6bzkJ87lYQpbaHpwPpqu3S0UqNDCwgg3q9MEn02X16E4xibz/rLx7NMDtHcwMOt9r1dVU6Hws9TvJVH7THrnSFESgN5eBy53Nq2Fdb8mySTxz5CitvVE+ZjHaYS3hq9Bax+uS7TxMIT4qJE7HGdsHM1/9uPNBylhP04Lck39JMe8v2dPOSJzyQoy8m/8Fc6h+X+5/mBVA9jAsG4vmx/KdUW+NXxgRt//SS2Ib7aGILsjOz+ZZQu/NMeuAsP1pFRTN90rqIVULbJ20ZJlrjoZD1VxHEoDFFGVWCVOT3jGK+vFD06gc3yDUSnZ7ZHjGmw4ZiAglY2nm78aUpXxI4BfUHqL6YQKFDCazUIryLi53RczlaTh0ry7WN4WpWK9sPJ0J49fu6RGUMYZd3+NrRvEdOrS5n+EJOTkr4lNzo8vawcYnR/n1Dq0rCHu5o2BGBEHABJbsFLi/mlWFO1MjpvUu6UPJjXlXse6MtBROT/mQfyegWGmFRQ7Q/O+rJp471+tQF10+bvkExfBoTQrewd5UwhAUODpyeW+aK6vx2AroUo2bGBZ/ZjcsJFfMYEMsm47LdQSq7T7peI2Ex+4/9oIAJGfhidbXA9UYPNhxigFTg83CETNYfYVkoambj3vv4MZNtE/wrIfTguBNqkQk9ebLPTmY2U4UCzbYqPKO5vjaZXeVksobDAJzhVjoU7p9TdFmNMyLyCQJryBSOcm0hFk/pcwcV15KZ/+IIqeQGPkTbiY1haWSnuQYBeyW5uSPHGtYw28cQS/v3rToNAUGVBSQ6zpBt4CHvaOfEJhuDJYZCcxvPeOStdCzaoSQn9nDe8wDc1MXrJ0+9N9TAKcS6u8ANLCLY4UfHLGf884/LFIn4OLOlRcNl7FS1IJgu1/vLm4INkgHt5ISp2vC3MFJHz1zJnopnKS1AgJtCmhJRZDaW6wis8CJ0KAJW0Yy0+kWI3lJ9N8yqJht68FMNVgkgaAGi5LuKmkZWm+ztKvf9gT8hJrXZkM/QdHI6wy9BqVeWa7g7ZM1YLbUv37YSnLmGsCrl/UVi/tG+fZbzY4bGye0zH08VQpGmyd/v++fS9EtasmbkQEIYnmLZLxO+tNHp3myIGwYBZVXjlWvrCiQcsP/Fu9l0HWmLBu3gvuJ4phtJsXXllJdM8iZIQR8Z6zEMs+cqVL7+TYhxDd0c0l4sbyIEw6N+V0v3ZbUlidyekdcz/aIomGdZtmdI+1QUrrHw7eDXT+G3zbTZMXxpEgJc4zY5bH5az8eHzwoo8QUleUKpVRrsErGmSF6GPJ2OltKYL6/C4zx4rHdcfsrQTcWBmrBWMMiFiU4NGtpYeACqYafRyu8j8x7ltp3nxVbsPO0MSoaR8tv61/q+YCqHX3h4vy4HzjCYEl+4ZDtj2+mawuj4J0rBpcDw+spzuCQ2khFbks09lPGxK8HYJl0Y/lNLUxGLZ+2h6+EFSaD22bYzF7dk/EhCWh6u/v1HUVKC/r/Wl6JHtd1V68J9zdOTgbvJuQug4r4vUV3JJolQQ5tecHKqcNoYjOIs6BZTlfB+yHGfGdxTKsGxbU/4taKuH8Qpd/M7fIG5zebrpiDHV97T4jiUNt7K64/u1e/+erXV34aOjfddcKNO76EzIf1pfD+KivBsRlzlsjj17aDPq/lnKHQCLsD+3TK021HNzhZyuwpLRKS3KE0XH/0TqUOr3VqLMcsSZM6349QJDznPG+sUqeS6wwMWp28TAoDKdmjzW6f+2au71HsOzLIeWencRa5JapKkVTYpvwMIC8u2L+/hYGJmk0588rq6Nnqe041NMzU6lj1K5KmSj0ZRiVpzu2FSTl4PBYHAuhe5dtwnRQwvvNqIELVxKMFWedxxB7UO4zpYRe2x0zH4X6pI2m4g6YdCs08vR9B7omy/goQUYbUZA+wJamq7/c0FhkNm74Mp05NSCK1Dcy1+9qp82p8XVkUB4+SsVRJ/Tqtn8v2esmemr7zjCfjLicMb05JqNoL6zzz0KaYkXeStBrF9+T7EbZTo2Fa/wS5NhJvRoZc8QUfS46HX8HIZ8A6LK8zKtROnakAnEEFoonVlvYR71xYuBAXbjtxfu/bteN8WkArB3//qp+3btpi2SIMyK6rX03iCLnzOd2OrPnD6xqgVT35e6NUMpN7EJSz0DRRzyze1J+Dx3cfx0M577W84qifD51mZG8VNbBf+5PxmGGrGOmkO+Q41YnCkx51D+X3CXsNAjaz/XfcPJUXJ00vaQyfYDtmFq4kU1ZHdnep48T4IskzPsYT9or3rd/ubiYLqeBqjnGbuNWb9ZdPDxkeBmJwYTjsTU+VugQmtz5+C3QBX0piVh3d7BK+Hk4mO3q8qJVQXeIqs4hKuRvBfIwwUyKg9W1x8dv+EwESuk2Bgs1+Zc3wzx4eGasynWs3V360wH3fKXZFTckeHZdgtzTqcQPC2hCHhSXyFMyljvrneLE+c+b/YQ0XcDBam1oAPzvKmmcgER6AqnyC32Ic4HMP4FQN2rh4Y2ntrawByV+9oq/Z8hdwQEPYRYiELBCnuGGXDQbl3ZLuUo0vfKU/AuMwYfNXmNM2vkn/GRrpc5WDP+MEL80tbJDZfDNBRfpfcvVpf75u0LrkIIjnU4adaolZWzB2yjIVwNrF7zF//n4N5xHeaGc7Vh1EYRdc0h2l23qFvLBNQ5kHbmX8Yta2Vj4DU6eBN3XyJBvJf9iL4x+hw1hx/7Ej5U8EZr/Qhgoni5r9PxBfU3fdvXICGW9DzST7GV141bvyMDXblFG5PizNjJUVAWNSxIAStz6+eDAbkYeAKTj6DIR6ysFvZAloBLCgSdMFd3ol/WXDQh3BbBtLqO9hp08BfumZjLpTJGRAIHzDizXZfhbgqejNSS27BIXQLV0muwzgXGqYt9McSvtLWo1Fos3k6Nu2qGyFftqQyDz0/bmgvtZyiFce/SLYnjt2Q9BnlmUVBWOtbDPvUgOSizvJDhdiSkbLLP96MJ7dKO3eUK2nZnpb4s4b2XGF4T6gC4qo9TDv9z2SY4Rffb/RjPs76P0YiWADpPB/nQjC2tDRlxt4sdNCIjmMsLgU+cr8cpyaMSYI9maP4HHww2jTPkGKvF6H6+DFAF+jAZKT9oi23gpZ2zavE0xXPkF7a2FTNJ3bwxvsJV+o0fXZAkmouYq6B2+6ccHhnUIeL10QtZaPoZPJB7/Xry/2Nv+JJFmQ/p2NSiO5bYGA8ej1vh5QlWhaX3JMs5gMBnyyIfXIMf4im0WEUnCPAJzq9q04Tmxzy7nGKKEf31kAp6IFk95aj0AogL7iljLVJlOXNvV7BwZn4dKfuZweSEZBqy+Mvual0TVDHiwHuIuXbvaw+OkU7aeAfck0Hc6H0jgt9g6Rxb6dAuaiKEN1cUYtD88y0b9Arq1q6ML9B20/FunTnZNF+IHgsg641FfllDFpQ+dqrIPKQ8IkLx/2ppx0ivQSrehNaf5dwtBjnPHroRGzG/RWOdiW0COPzepxIqcsWjhfmBXSUD7YCvPm/qTGcSnhcriFKew6a5s0AgK03I1gEifX6y90cJBY9REbQ7yW/XB+zAXN1XZQVEs7r+0ajtx8KvVBKJksKj5YFGdhEennMbwgCJJIMdt/pJD6FIcNVegt2LiQS70DAJeiNNG86dQVNYNZmYEfo8oa002xKLh1+rHlBX40iY8Wlv7FqswQFktpyLn5oSdo1jBRz8V3aRIOmhSnrs2wxGwGBEVEXvRm8RZVvSQ0xlKMVWs9Y7nnmJ9jEVuDL08D2ES3plzvCNP3FpKQeSknFeVBXv5T1Yk0/X5vdj1J1LYa6Ffxxrv90ObLHARkCI+tz6+0i5cZTinvgIYLMVnV/OL+m4RCsTy/+9VQPsYv6X2qSSlVdQ3KM1SOntMNUBpb4C0MsDh10xHQ0cbJK0gsR6X93ru63BDYbRZmPISt1casVwVVE7+u3l55XJGJ0Ev6S+2zpNqOAH66RuzpVskXE6X8x6wHOfp5PAI/7YG3Zozh1U27IXGEEKIm13Rt/nTE3pKWA7i1NFdVQKQ0CNdqEsBkjiuM41dd5rIbR4DMnoDva07v1esxYBGU4JWJUJQyejYbI9p7pqjrpHZUNlz2exX1lTAks+WxY6CExoPlSlNNv6AIsE0VdPmHOj4m0a8bigDelTpIL1WoePLhblmhRlkPDKiZvkzz6eG8vLeJjCGJL1+VFa4QREBVyuhcpZm1ygJm9kuQ+8v4yEMw0VO+TKee6sMFRVc/kS4IirJupnw48LoR2aRk+GuDBZ25xnKFxdSYqZqvWlEcemsbzl7wvQg5z2xKxEUsquyGziyzd/X+XFl/ct9KRLzyyb6ComIL8Wam9x6LPNZXvhO0QQZmQ8T2MFjmRJ42WyRzfyLGkJKft94uO0Yy6Fflo3AoIEon3XBygpi3Je932ToU5EKoikvqkeLFACpsBN5dseemiMdHxOJKrVJDdTS0qCcTzPCyz506oyENFdelskwdghmUnWyXK2WeJX2CBXudNUBON/i8kMdtJm52REvmGqVmxe5aricuTCGLbgZtYvigT++E7xltEh/ZgUoMP+d8vaPU/HdhZaUjsgQ8OoqZeezvNR2JFm2on+IliVyYQ/58LmZ2stgKoBbs4SllwiTpNRw7ecL2WR8bbg05aTN00C8aGWtReWSsYsirJ0K0I97flI2gJRRN717wESryWahXUAFZAdyD08j9SIZQm+wq5GkoUkK5cQ3wk1x01x4fKLPgPIj6D6lZiylqvWGtl6KxCfoSQXlNZIHeDsrIRqhINxdrCinM0iMMkveNxhqrEzhnBn8F6nXVY5zUDLzOXpp338I2HycFa2pueObEof3HQgFEMnHS3/CDKwJAyYl3HyA4X5vXUE8MMa79gYELseTf0IEUJRsfSa873vl6n29lFq+GCqF1I+mB5PSyLFvgHv6hG5Hd14PAHTKhY+xzCgOwwRZxygPwNET0UiO9ynH0p3j7GAFEs+VSjl4ArhHJbySohRLfm6B7FxxYJLJxJlQr5UdD+5Vs0nM6CehSZZNYw4FzcpYoL6nS+wGGSNKLVLXgbgvzAbT4B1J4GMS16IKMlo5S/dzM/NM4NI+a1Fuk4qwaewoHqGp78vgp+SkuhLyAVhI2Or50Id4LlHwRon9o7JT3D2pibchFvFi2VTEx6cLX/qorW2YGSSmnu9+M8teW9DIRH1TfabuDIuLk16NFz3kNr5QLPGAd0JzN2IYFA140yqfi9LfBcZI3aUK/Gt2bfMMk8eqttN8c92OmUYKUaHbB9C9cpEwaOYs49MztuGtI0VMqDDHN8HiRP55BpRIJtIWbSyi0/LOC94XhzqGVyuzaVaBfg0f++sV8wy7ytxlQYA9w1ejE0XaCkpM9zbOrymf4OrEaIyQX84Z9e6wQ1czIvOihnSaq/fcFdkxJcMzE2kWcARwWT1U80dW6B+v6HdclWMyMWLYr49iKWrhm7o1yumJKxVGiv1Rx3Tw61jrh+vuNjikpFRxa0F9G7ZWs57nuhaIeT8ZRjYzuyq4WZBEXs4CyfvmZxGcS4/G2aWon2O/UkjqrfdbBUF0yavSPdNJacaaZxFQNejGDPK7SCF82XxiahbNpwFs/t07gbCJkDUvvKjqaYv1SNJBa21RKsOuGJNKO/F6HTjc1Q5t8lqLL4e83gWTT4aubYGtE+D4e9zdPPo2R3dvG7bDrCQosp62YhTaV3B/kEQGqtzvu59fbgA6lFyGe7urhYr3TWCBFYBmrEpB78fWnXUEd1z0LSzMcWL6vuh4CJYR0tg1jX4H0wkw9mkbM07MXopLJ2Rt7/aL3Hl3MjO8h/1lqNlK74QTbgkurmgd23XflEcMhjO52Y/Wsz+CqwkBCDN8SUcd0hvJ6srikURdDKw75ZZMyms8NdzvzfsXreeCzpVaPKbkgWo0BlD+qWqaXziVa7YTSezNkCD1UBphMwE3IFwG3+Oja0AILbwR+VMjirrIkRPt+DMtp+OKLpkiE15AVv3jn19brZGZkhhAsuT2sTiWSjLvxJkMICAGdQY6CcJ1bmQsycrXCCxoxrME8B5k7aYQkl31h4kmnvmUA1Uo5bGEJkzebQNuMeVIRwKr7shM3Y3iowzuO8Jm833ALhjeDbR9i+ajGdiv5nuQcBDW0PZ0CB/GHvnmE702e3iEmWKin/StmkbfvsVh9mXnjLzZCRfht3g5Fu6OpDSsq1DSVUie4hNThGTSTWkOhTKbARv54Bxp1m/BqW0CfvfUJMQYci+HzQBrAw7lHJI8klNzq1wbwtxf0zzTFIpYQcsU3ddDWDMuciKmN+BHJ47B6FkgX4uR5QSWzLqgN2wQK1aLp2hgMJGqMII4rLK56VcDk89QQhw6cy8PCM19olNpuDwdrQFvP+77wiyyKx8Z4MVJNxV5vJWOwvF+aDouZMW5HNno5d960qcPPO89qYm6Zh6UO7MyFx272aWYtu/0+UZ6eThOP3s/uMGRarrYNGVN2bkl0VbM7ZArP2AnCQLuPoIbkry4nTS/RsIdFmPg98zeYI4R0RY41FQsBym1OXnJcHtmKPjfEXuujVQGfCPrCZsaT+vFbMFWIvUy7OxquIvdi2DVp3+q3E3NGG06d/cz77wgHGWrfcy5LJIzCMZHkk6m2QnZCXYVXwMsVhJI9nJcgG/CrU5lgDb/DlVEsXG06BHIuqVfnTyLdAQZYmJlEEk43pdgF69V12XC+sB9W5Tfm3jPwiHn/VmGszkYx+Er49CLbyk3hDBSKuzDj+nzCo77ZO40EIP4ZROdSwWlf5S8wfYcAzjNdj/aZ8uknw3tur126RfCzMA+cUo5mPaZL9cVp33X0mRTUIS2vgtwDRgsSSX5xcJUWR8gZbdeqyqQEEAeDu3+BMlrgYP2SH/le2u1yfVFn5JX9VQ04X9mmABR/KOd3rAYqR+OQwLWao9MXVS1y+0OKo0FlXuirKuPaY1BQbY3Vo05Gf/+N+u4rDcFBQqiCrYhgRAEjvVW9eNCaOsukcJWEaDuo/pWCYGJLadm4ssTCPvVVEJNBfVXAcTIxH4EFtWFMJUy5of50QNXNZBl+oRuFIkdbt04DeU6j2A3vzzP+IkMahLD6zBVJv+xRBIc5fODvnJMmJRMI8kcyMFqxpeWZAHxC68tGFNyl6yyGN95SwNYXwDSIQCPlL9bzjZaWNWvs5puiP2lbEBlDw5vCHtVmb/sD8QBgOhRassChwM5o5g4lhlD4u86wmdmVmhmEXnCyLeQJ0rRtqYIWRhg72ieDnqmPvOkDTWtKR38TeJwrK/7IRYfbNspygrU6yV9YtJyw3I3uEkDgbPrpcNUpISYvzv3beFg3ZN+swedqf3IVKkcdiAezu/KpHGHPyvX9oT6qzTS342/DenW9ctM197UfFl4rk21KxSma1KnLIWlGGasMF4+G3dxTnqBscul4CqNda6Qy8ita7HCzKlYa86yljm+HQA2B5ArJoZy4LNxeT9izFuQhEoEhUTNJQj2pCc/O44h8GpQX6XgpaAvAQJLVNq0yXGFbzb3O54XQ6sm557+lT3A+VWPyCJn1MLbsssHIdFhJcMtBFQYi0bS+exQ4Rq74xNE2CIRSzi3nj5TNy2AoO0gdyBC0/2iH67UB581jmM92OHqgD4EzAzyxDauPnlIdZu0nWwB4dtxWN+meq/faIuQpK2hoRP/ULwIJ9r3xyxtXxfFwJ3YquXldSEnxoPiYD85u0OAHvKOG6+3eBraUiOgvdfp1EjiroeSLLFutuPPV9XqhAReYPaRy87OAkV5tzSqvyfufCvOMTtkpxApWsJ9n+cNM2uBWu4lj1oDjGasCfCt6cfgCzh6UbZanbL/qCgf/iHjKYaavIiRLJrU2BuzdsP97XHkXLYbbfsHVTlXSohKOXOJ+3LiR6ix9UFLo9qieejYk+P4e5wC64jGQLSxJzYt3cErx1Rtc2+xlJaEBynLN4hLl/qOrgBM7a+yswC0Mh2OieA4SR6MfM9WK/FOWbVyoUBIUAKOhhIZp2LOgukk0/DInn7sF7dRP6Nw77MaAcYg6k0gdjQN9/1wtGVSBm+6LwkI+xfcK9l+JiWepXul+/EEdV7XXp/9lUsW4RQmIkda9H38FJj3EYJTrG4hEU9YWtNd2lKI1683cXFVzSMkh+2nuu9K0JUBoAnrYkKVZpAKF9G7y5n/KMZrP2xPuUFSOaruqriffSEX9Euj/k5dgewEyQCFTif83LhkIjt5qJ1LyI4ynIznWl1SoAdecEp+I5WmKBB2fr5yw33NX94q6HIP0jW3Np2E0r1f7fUjqdxV+iCRULU+yAwPXFvTL7HqfFLj+wCfIbOg+nsW03rGTf1haLvAZA/nC52pSDnC4f0qOiA6WtK20BldZUaA6GO3m5ZOCGyemGK4a12hM3BXnbladA/yTRV+pH7IiT/9WOijGGNXzV+K4wmdmRjU3It+QwUCRat2mGkEHhOcQY06pWeQqBGjHkWcceX8/drkk+tYysHMXVk8hLhLGjUVgivK1Ra4K+RtUcZO5fkVkWQ4W8fyo2tafhGEDSsflUH7yj8wsATBE9YpskR+r7Ac8xqdxtEAfRioGXSprjbLI2DAZZz9HAYR7rUHzvh/UPpFvrLbd/hFf7sF3RimWNpiGsQRZ11RqfZkck9IJu/FPU2DYr/HWUdskJHuLufXCvDbKn0F9sM31Hn3zIuAMTUc+tQsO9ll6jnNnW9Ulo7d32jEQMqJIrWQL5+Se0a8lKRp+XhYp4IfyUaTRC58vFEjKupeFEpU4EOp1AjeALc7vZV0ovza8QSl3ru6xFpY0/ckElMOChkhLWSDHLCKaFK/qC/SIfT50GJZnkCr5SgXZRddXq8Gc6XNjIzSdCF+9YlUFKMiri/sn1Gp/dEMhARah97GidLqitLNBlF+H8XoQmdrM3GXBSCN6izNn2ON0OzpCxOuM917OZCw2ZC0DSvNuTOFCGGYf1TYgUbgK2KKc4zm/25dz3GhVpFqs6x4yhZBbiy/6FD1vXW/aIcDiSUoIhwrUtxuGGZijb47Jz8JfUTblzx4eNPbXeYpygkQo1xXonjeouTuJvAH/zH+FK50zOLAtbN9AO6xjfX09CsjKitMVlHWmmQybLoBHBPkC5IbAZxvs3cH1VAcy2X90WL6y/0SXNsGeLBdr1OWVuYg+/wUNiR7QnP2ec7jNrZZOosT6Olwn02Dh6zSwKoDnMFLfk7lBO0p9mWjex7gEFXNfxFO19qmaoISUZEgdTuy7sHgrD/36o3XeFdzLFoFnOJa4yaENBXdTSmVZacz+5IGdVkEgjQt/TxuhNGHGtQuzNDfM4iNZ28Ly9S9WkUGMNAfDRLr4ipZkJxUA6HnlOi4Yb04/Ze8rB+HEXpDGC5Jpr4fN62LQh8o6kxknE1P5/rNmz43jehFlRUvCyNi3Y5St7lC7a2ogCt3Za6M7AshQdbVV2+R2DuuiLEJz0MLhnn/1/F2Z2U3h560PrnhR0Gc/5GW5DwO/DGrR/4PvL046BKjUp1lfrtKfE4osRTS9/oB0GrNW3cYgvhU8ld61sHhKOf4P94t4n7h9zdRXDaFv4ORPHokkY+NA9QA49RmsGMfJLu1/RXuluq0J4fsUUBoa9dL9T0yDJXvGtuoln8aYrNzoapa7E8cR73/wX6KwBPpwCUUlxsBtOj0rnca7zu5FqJC5W0U8Yt529SAI0S6nmWnS8zguQLRzf/gRLaqSQ6E9T6Q84u1cs56dzBMv2eBG+zAKw2V0x1NJX1gC8M2MYZpScdXEKPG1442UFWTEUlkM9OjbR4FurtJNV4IqEu1htlgltESO0SeZMHZ1JM7bNtYegevwPSCmW+S8uEGj7FTSSV0HbDg1rOnt4Ws8DxqN2T/HOXNd5NGboZ8VTSD6g6rLWcoWOwsyeG08GPG6KHPiLRunEdTPNmY74ObRGT1VCHP7nmBYmjnH+kqK6rDyrEoNjdqc8uG8yZrHWBXU9weqD5rpQ6S/annq7P/GiYepA2ZDdJA/GbdxpHYatPgkXt5sop564gVHZamW6cq/cdADaLCXWt1WgK7y11WaQR90YOen8BECQ56pmJbLvzzfWBhUUJP+dAEEK4o4wZv2+IBAFEdNkNF3mKntsLE5PDLA/IEiV0rziyORzLJsoxRMCQV/HlpCkXsaizcHT/vxU9iadf2hOkKehGum3973fFs7uRlqxz/oDerFL0617PqG+VYIxjeRb2IRLZJGH8vp8ITzF7U7HUg8Crs3WpVY5r8wxn8tzGvUUwY5csVu15Vmm1xcs0UL/lUCkrOXdLtlaa4pHLeQgpd/vu1ZzjMOcgzfQaIwiZK+fMZjRLAHUf83TSCOkovb3xPkD0jElmb4TBqFrwn8G4KWr+RM58qhCnlVimQ390m8YLz+fNHbBRDs7GJgHSK+v5Z9cwZq4glnR2eTjnqTy8Wo7BEg24CL/RT1AKzOIE7muo8oegzn8R6qab08LzTcbb0ippsScfjQoJhsr4jKG2pMVczpCYqptZcGD5rxTHFbL3+NDnEUptRMyARhF2FMiM7pgaB/IpAna1AHa5EPt7oBdzMGg7kOdSOpxrPXbdP3l/+QCfCLMpCsxFd3VAxA/IPVvK8JaenCYCadhyZ6rJeGxTUh11+OOAjrXIJxb/EbIy8rv6h7hywPp9ZhPCcgt9BN808JhGIaKwtL85jO5nipQyAF690xJ9A2DMuCx55TSG88fN6rqBMYDI+I+DtFmoAqJB27B/xxN9xMLnQwLcLCHOx4GIFCq3/6i7gwJePjoG/HKNb0XjhuEQmYFzTgtt/uIo1bBX4C+y1jrb+R0mRj+RyaDkRus8W4WW73qbcjpjIh2tGUY6KJyhEaKiK+LHG5euQeYZO4zXoKbZOWiJTvJNNVrWugpXkIIIE4zK/g4JKATQjtaC1qbJ6khaJHxOTS2goU5zGyjmaPKvVPrBh27E7E2iZ/6omwpBARV/9EKeU1m4Msz8Q7y3MzEF0C8VIIqAxB+Fk8qG970lhV/ZIX6CsxiHqybemqil3Qv/cWKm96fPoMJWSA1dcF03dSwSyNMdvKKBCYVYLuqr2pISKPaNRJJw2R43RNE6avh/TNA1tGJ/ilW/e4LbOvIh7cS2OsbjyXcD6WS0DYaDa+og0lSxehZQiDSt2fVdtF+DO7/cEUAM3uju47Fl17rUPkRPaheA+6/jpSYK5Nh6rSwO8Pbi1y4/L0L5SStva0NcscpH0pw/3Y9+Eqw1SDVvRn2r2d8vRC6YhQywdhKWraKGBMILqjiU2l5d3jb1tnQIwi95QiTJW7MAjJD4Plr9FGRGlM4NQyAiG8wSAKUbRCpmxE+zk9YhXjiC/Rbt983pV0VzovJW+90dH65IOb2VS+Wk+MpsRgZ86uEuxeGPyB++07HlAwqFjq0sm5Lvom/rcHSaLduJrDdabujYJRWbbY2QZptvGwTHAiaqsAafE9NQa2oq6hV8+E2YRbdEcrirxyx9JVWpti7CsFfA/egMevH0MR40/X1jQzMYbw6mr01MI833RiE3EuU79cpspC8tuN6QxFB7ExHF8yrFQ4vRniEkTgKc8kT2tC2HgNJJ+l/FwYXky6qbHj1cMtBGVOw3SFMHn5l5odYVrLqhL6R4DujKq/CEsEj742QjUogvrSb9DOh1Mm5Z7n6MI+YHii3bWp2abi25FJIiX3GM/137MQVr4wwQ5IQETnYx0CoXX1nLeqLjQ2VlOulhy58iVxN5d0Q2TEV6MPr+wA6lluGEC5890db42elDUvTbbMcjHGrT7WA4eEhNLqVT35NhLruSPkwg1UCAUz94Dj23i6dqS1MPh40Oyi0W+wfoWYXIw+siweU3qKdQM/IWLUwDjgMQuiK+CTyRgR/Cg+XmfazCLiF1JChK7C2x+ROCl4t2WjYngGRxBWRQqqrNqx1EesLx8Z8GOimBJK3Ip3O0TWp1z6fhibUBvCtBpCBH7Wz0MrsYEtW/6gd/rLbB2IcMxOrxgW5u+/ZBOjd+9Zg9SRf7ln5tqXgM7wZE2rj4u7BOezWvuyca2TpJkQOR8U/bR+LRjmN6RAS7MCfYSPtJWSbZYnQL8vGmJb39SyiYiER2Via1nlShjJEe3JgCwTOTiIQJ5h+NQeEs7qWkpIDJiQHb7VwcR7T1gLGhKAqUT5DPO5zvGPny/DOh+Lo+Xhxf5wTkF5p5yY0vM1gw2UZQ2nhCedQ+PBxACaAeuBYTyBs9aNWvYATPBLUtXJ3H/+rMIUQ3Xz5MJKdV6OhLEEK73rb9hfjPlA0gKO4j120U6VHh4AJvL3WqjaY/KCbwpCzUCADZmnJdpD4p4U5ry6/YuhcWXcVV4dFm5J8qADBWw9jPITjUtkf0lhIJkzhXLTcXQBZaaunvCCxyWh6ifYzNTTCGJcUD6DyfGam2zj4qdBy7DwBaL2S2IxicF7F2ubPDvx0+DEQVydAIF4Utn+/niyxDQpGlaaG5eRQcfYEHaZeHBOfZ8x6KnSsZnB8YZbLVBcEF3Mv/87cj4r/BYDYAaUWrrm/rWPImSVpvPlB3xQvVG305B+bCj4kIW4ZWzFnX7/nApDibPZxncAV04laDsD872g54z55DZylkUKHXF7Y5iFwsc0HDovYpJ1P+XIAb4pKZnw/e2BrTZn6jCeAAvAt6Z8EdXqS/KoRwK37xhZL7w17n2PYpqnoCtRAvnU/CocUq+el+PFEwM2GkhLBAJXvVbqxBMfPWlA8XMNY1+dfsV9Uy0C+WgSzcXw/ylN23DlELK9DPZ1nzFCvyDWygh1ABv0LXhuVuDEraYOrX0J/NpbYoxjl/mfncXN1DorfumMjOo/dWEk/OvdZ8w/66CtISpGM2htGRpT929qEz+kRM+2XpAqcSS9GOrLWVVUVIm3Ez/yIqAWm019Td/ytbE6eeYJaY+mJpelcp0h+4Y1hmcF9J6cZQEJi7foY8n1psVTCzE0QYMX+ScYxKxb/bU9eproUaSNTxHeNhomtba4y/CfLAZYXndn5ndeIjFIsRWRpwX3HwrIsKxRgd52tRs/iun5uy44w8u2wZgayiPbOTWGXUn/BDqak5EZebXbdQHyE0yEhUO5HcDnE6xlAuZFDSKLDTTZz9bWcfe1wy8KhSOwh15cBRibt+faUQgl7/5na6Nl5d1o7iUWTjOhjQa4z2Pha1PNGSn0hZFeICMKGtHJ6EGQbB+HF6+M2e8YSQjJ2cnG2SVpdzXlnkzxYqwXv0s0WM8nggSh7Viq5joXNiF3RJ0A9637p1HFJd2I7GrQ4ZTOWRi8jcZaL/25Pox9feMT7VDPV6TT++0Ri3a1aLS8IABZh2dWfxnBmXDWPdvrxmBiF3eePVqd2ZM5bI9YAN23/3qVLElDeD61xvgRdjkXkl2tqif3zsX1gGp9mzEm6suh1kWL75XC2kXlrCreiNi2pfI+iWVFJDXPd3MBNp7VSAZRp1jpt3ug1pQEM470lZXwotpDljklvGxuNeKwTuKNJw0EK74nc0d851QXL9P4pxZdM7pkmbA7IU2S2Xa/AJRP2VOz3Kyp9oW6FgoQi4noNkoHeNnprbQod8n+dQSSbMzNRZIuL/riHaxoOHkaGYwROCZwqcbK1tUnU2Qt1J+3UTvklj6wOD/d8lrZG7ucjZiCyHxK5XVtzq9lDJ4N1FvARCTUfnLeOLc5bmrtGvb8mmsr0lDDyR5607k41wzglZH1fExfmsXrEjiNLSzSKGb7FVusl07/BgeCclDsQkds2G654GVeUpX7UHaqQBEmJsIyvfxvz85+WyRaoYuQfSH9WpJLeUoXpUt7+Crnl1Jqz+eARyCmzL59OUUBwBuoQAl5VddIrfG6xvDA/RZBOV5AfwjOrJ2xRo4N42rCSFCcnOY7xfewl6tVLetiM2tGLqRLc9k/owyHriX1A9BnluzfDc5xdEUKyuwzWPG+tZGNDV0WLl1JyHPflzcBpj92G0AR0lGaMSZuKui5/LUMn69X9wPKc6FVkNEHEjHjQKPQjuFCokjN+N/6DlMscpE48IhHIa0Ghrc36GwGEiPRymXWKD/di92yfjZjDM3fdHBdwSxJRSBVKHSwh6Ey1/zWZRZ4kk+KMS8HuroIw1UPa+PDVpsSIKvmqZnZisbfHFWNW/dl9n5+wM4VIzhmrETz3k9WU3s+z84SHh2f7dGT/G5WvoisBYAgwm+pqFS0A8xyhy4PiKfgS+6TgnQD5hDEerpzgFSaMcw3yvDZ0+xfL0yznf0uY8N6APiqHdoJZOWqTPnTIbeBLc5dvFdh+mvD+sDtl8BAWzYR7QkSgnx30Ru7TH5a/g4byacurCNvG0lTgpkj9w42uqBp1zMsKr2riOCQwfCRKkuSX9CGADOYGqCHh1JUsk6RwvI9OvM9fCJoL7Sap8NUQ7mAvdB2ougA01NdqxVo8NeGta0R9C7QybiN4uAtDxw2zLTG9+0we68JkqZrj9tJilUV/f4wOLc83GfstXOVF2bAJ6zf56YworQQEDj6QnC+lqyMkGAr0QuAikm0jqS7fy9bYSBz5hekPILc94b8aUau3Kt69QI1kFEmcb19aFQA4bSegA9/hFi61RDIVQ7iOBqViYdGaK8d3zH5qWIjed0hR9e6o4zELdXWhOVOcPCmZIYYXvgUsAyGUoCszsCiTdwOaPEL2kRnYh0mNSZGb6/kr8XfbyUdbEZ7mDBYy0yTDxhkrpIoJmVutN6FHk/E4cTEolaGnv7x+QxQIKZus8IEygpdtBDxj+lC5M6HaJ313pLDYbjpCA+oYl11ISRJ/fB2oIdDBHFLefQmF1uHk7vtSmIyI7Q9HG0qxu8QRWecP8ipKR1o4bGrAhR2KcGEDE6k8r2F7N9lNUZCswXi/EXaOlPb9fdsaw1Sspku1xrmyADIImEs//XiPqI3Jl8BlrsHf1mAVCBmlqE7usMbDEpilt45ia5CXzVqlIZ95Fesu48LEATS3dyXVEjwQAqVbFBttbLfXvX4LhaGKv6P3XBsKWvqEFfq1rPYdohHtQH03ehlVMpZ/BRCBFV6dffGCrIa7OngRAbORd6wsIcR/gQSxhfrfHFmb9Ws3Pk/SikwIvAIYljNbXbvIpKTROSiPcmBDp4hxLkrjR+MfBFZLV5I4usLY6WYmjhT2kzW9XAxxLYCELLIf6lg6p/GFgpoRTm+yQ6PYtmKVvdTHyBxv28y3vTiy+reYBZqmC7x0TDasiMCcA+TxdKgDY4s61MpZyI1+RUzeMfx1qh9MBXg1tI/HSKpcUj7+qTrwp35J3ezefo6UZiEWMPBtx0/tJyaej7NUmUHVRBJfB1q0bsw4yHfui2ZOPNh/6R2/I0j09t9QGeRxpuJzB6DNbaPTOmER6WTXYEGXq7DhzkvCP247uSz6r7MfaasDs419fVF4RAt4XoxkFRmk3sjrhpNSeuDoG5RpjE4pI3rH/ESPaF6RIIJBiAbVU/ct/nKrDmBQPBYlNob0WmW07GhOvvz0m/BXTsPB8qA8Iesm6PsDuOLEEm5+jbniDFyXfndwIXHgWBB1GCyGV52MU+5iXguncQS8T+WyxaPDqCCXMjwPJxGObdF8mBkG2+SpqaBQkeN+1IL8Cbb72d3ySQUR/uO+N9v36KAiKVEPx8EERU0vfKi53JWN50+LSYqgHmF0UrnnHCNpcwfX8ezokGL4sK/rgFZlXnIqg6a8EJh7DfMOwMgTwRjjZ+TrXsj7SA6EaMRroFgxXRIOGDPYZgkadllrCosfuVZqNQwAY1cDJzuD4ocR7PgZYXbCA3g9Jd1PRx7PyRTNad56qFMVIv/9AYYd32opL/KQOuEa2LIoyMUHWsHVeJEgDnTAizkdfigKSmZVUDrztoGXA+B+9B+MYT2q5BETXJUKRLiEw3upTpXnlh7hkEk8/0D3rV1lUxxSlnDzLfFArxdnXRhBNu085RxiTwTISjItGPuj0MQknBfLTi9AeLTT9QUKRG7bxHm7P2Kei6fVAeNBP31q/OVsTuBJZfKaxLodsCxObxFdyJNLV2tAt+2SCAO5/VWcDOd7Or0wzbVGwbXJr73+/PYn3VfNQ4CSxdqgXNPWDqh9ZFVRQbSeb+bFmOpdkO7C70y6dTSHVuHlIY33/KV1QHDJ226atG4ltS4fk0ZNDrmPZ2Lps6qyMYO+Wkmsyw/ECuxfXcZ0zM7vmLjkk/LsX/XG0vaL3KZb2C51I5TVf8fBJmMxHHzKvaXDwSTGiya0f8ZZ3olqbqcd2cjXM0jicXlX0cJsaB81POyuItwEiYZwsHn4gymrnlD0mfAro2YoSC7KxDdL1DQVO+0a7fN1fLkv8ElaXx46Z8EGJ/W6akIr6uEuiFIQB9fHujgNzIzAgaDEYVITJJO5XQkyimdgaTBvra1hUbw4jb8imqVpd7G9dSoQVNPatqBlbm7NLsdI/einfpw6HdFlo9bpLb/wBxf2BGK/YWhn6LhzEvBuRuBZJTDv7HV9WfnA2SyT3HV/F6f+23aOYC8rxO7QQ1FI4/0m/OAHdCwYedzx6F6TIlSh668B+Id3ZxNP3V+Z82Tt/AHYSzDsxyYC8mxyk+Za4Q6u8y70AKpUm1NPP2WMeSHfqCc5mUcG67RR+sJWZg7P5iG4FPnFmWKv1nwwk+fM0IIA5p7xmHnj1zbj89sN0hc81tzI6enBjIyPd6P5GXzsmp9IRHKS506SAEK7IxfjQLxkNK1x+M8YAYLrD1qWXqo03kTvXgYllmtbguZX1FQGpXYjbZzgqSLxcXTKqQ/GhYqBJzZtvPaYGODBTozt0Rw6/vP+hTUJGOAYcEWWr5Mqy4792lLWmElkf2k2HiF5268DSkEL2oQl+VXl2NXgbfa8xxQoI7lpuNkURcA/pNz/go3LD+w41q4eQy20ecjCwekr0XfODump0XPUm2vvNfk4P/tAVA2PLhl21zoFOrSKjd6D1AiMtz/f41uWlBWCDDY4tDRMhyGsls4GW7P8b0/dGx6VTgC6oCCWxMyJyOgl5RPaFDE/EzGGGL9XUm5X9L3crn0DvEELm/Vx6HwlGWtnfZK7dA8/zJkr9b7PBgLeFlmXyfUBxZHF8kxgW5tcxvkEz0roS70jNLvk3QNCTUIwCHnqk5NRDEaewDCzjTR5lKzNzx1RHHJNiZZJ0lXrAsSM03iKPyYNdJfMwUAvRlKP49yIx7XS9cvseBWVvGNAc2I0PmR6Xc9KjqauqjgG/Q8i16OIPtQ2Ll3qDkunTNq2O65AEFG5qycHaB2/159N4n67iMEpyNowNdkq/ZlDxsX4dRKNvBUJaYqhID70qa2Rgq8+AzqTaJhuYrqrDDO1n/0rWggrBcFsYwo7ujJZblKGamFf+3B5MTAXNUOKn5PW91Gx56gtqTqz1dYMML1dFR/KZUZom7Wky7v9EfKnYbBseAvDuBFBFFCuXnhvWc/JS4ipUIe59Ls/kL+W5lteo1xt5bkJYfug17vGw6cqrOjTG4nQXZ+RbEDCMTf5JZ4DBcuVv+tGPyucc3B6R9NMF/lc4ubulrqcBPhRUjGBILbQ+4uBJ9eUHMAj2ijfMskRMLcV5FdgqIWhiEvxNVlZSRrzTzySfBUjZHCJQtbgDZ8nRWLwk6rQKWD5aSHuJh0vBgvlNTP+a4P7p59l0FYBPtoNpiFl/dOo05KHesQCueTxj7IB6io9sqTWxTu2PK2C3ACiXWNyxs52441hxg3eco87pSRV1NUvQeac35o3tgUpXtmtl2yHh3QO1mQ55wSqIri3PtVxJ57l0nOuyav/0ixzLEq3QlLZmLb8Y2JVlrdQMjhpcC1j0DS+VHrYIB4JgyXacVu9PCRoC5Y2+p8qfeJA3OFreaabxWxz5omyn/l55+ufQkO5e9iODCdLWl2crwLrUpaMCi8EUcVXGb3Z8oBCUdwuuohn1sivwQp1O+DaRFYXIbHQibdPfq4dU8WeiYJ4WKMlNEuQr/BRIGwOrAIM3Ppjmzvh27Lyx6xK14sUHgNy2ggNG57CBbXznFP/0NVrUQef5mMdso3AJ33SJxInqYebzcZ2pEVYHYczXE/+mcptBHb4ANtGohwQabL1xmFHav/wFH/al8TKjzGnYiFLEifJHL7OJD0x/rtzWuCrDToEWPBNtRKXFZqz/kBH6gsxzy/TUzP6R+C/A456FbGm8soK/uYyafgNmX0re6fgXeehUvtDCXdAUJElJt7AMv+VMdIrrOK7TAaHo6E8Khx1rq48yOqMqtC08so9cQh/AV760CiEtSm6PBL7JKCZBV4m7t8Gbbc4TQRawpuwTFyS/vt1JBnAQUBDPdEddlJlVAfbGy+OKkohOw9BB/JY9rDZQK1o/kpfl82umHijUnj0gVqhJCsrzUxYl+ygkRPDEPZqUIo/+AtsGplmBSxL8bUE1iBc8lCtShF2iqMC1DdHIH1DcucbSNtxOF9LY4IMng4T9eTYzDr+gnOPVxWBYMambJUexTzxyvFOneFg3r4FBEHqG3QZRgnKISYUQKv9B23A8vhFRe8uNZpBtiMtXqOQlVEbO/HzkRbqVaGj4s2XRVlhO+ewkvEaTp4pNLXG1OVF6ncxf3Fq94KmGuG29LLsFI1fuX35J0TsRNGo+TCioyTrXLVEjPztNVQL1/q5tGSrMPhfJEaQxHcrnqhVVqN1gfF+JK9Pgcud/lGa+Ig7eKQpJuUN+PYhBYQ/b6ahi4nLNe5+d8rQlfK/gl3OQ3WDGWuUMOt1YlBKoX+99JWlZr6tTAVgDF0NSHs5fqbU0euO7cXKnvVB3taBFHP6/KKZCBfGqzNo6DgZgiAELh1EYOni64dmOWUuwAQCKu+L8tnTFLlL6uKkaNtO8YGlOBVU9mQFYx4aGPgGEI/HTycxYXBClfKbmSErtcsuhalOh73FnzRz/thPjvRJcRwPtZmCHs1nYjivLMWWGprl4fRUOlrCDiwNU+9TZuaVsuCxj/4DzKfcla139igH7Z+0uskWkEq/c0mrsRLlVpl8ln0G77hwK9rLKc+RLeI6KLKy3Um5C6Of3qiKNoY/7ad3EFvdP4VICsuTMTii/bee9efmKAiym0A+l3hS7SofuEJ46In7BEO+Kf597wnd6s5mL1d5zNRBdOEmfNKyPdUuCW3u/SfFQes7nYlfV/B1DOE9p/pmgK+bx+eZdZUMu44uBGlaPvej5wxU9aumiyt/uCCZ4PyO0OYfFAMMqTaYcI8GxYeHO/3tDJsJisLleLpS/gvPLbEksIm3R4OCJ21S4P//uyzQ4EJZyYmWZjtknKJbz0vFEi0zDWnZHl4kvpMSPlVI8cEAG5r0JoNN59joEsMhUcPZ1YtIDYX9cnR711x6SQEnBGgTz6d3b1iebIdotlgqE03w87xlD0+qEykcVizaOB3Z+ocaMGWybZTIdpR4niV9mDm65EzKK8VQq59iMlABk54A7zAlMdkYNmaRuWJN+bLJ7RqEZf8vrpM0+3cwD0NctuwJJA13JIJVFlPStNIXzAW4pp1OnTx3rMZQfF+o4p92WDkF2tx1MUdC14Er9l1RlYsEYnOubj2IotL4tkgKwnE219ZsjXb8PJFkzakaWhRBJAkgbR6myiYFsJgC/lellsN9g1ML0j4HX4rwIzHbq20FDkBdfqN9SUnIbJf0QQr+QxHx4f0kRekXaqKZYUXYMbRKa6OObLPOaKGft7xFAgT2pHuSw7kdfloER91zsJPWQJbkAzyDFkkgUg80kW7n7n+WBN3CMXA3lU6QR23Ipx/98577h2OGkpcp5YiTX/TikBkcza+iwBGNBi/j+GwW8tGbKxpiSNEQqUDdqfscbVMQ+OSYGoeQKSLwREfUGDjR/emc+ZAJsy3sraTZkpHFZAI69dwO1dvsOw/Q+O/2lgghmEsk6NKzmfI+OYuOG2UoagP9Le/y9UABk4VHk54+6fW891qe1yVDT2KUc5hNeePBaQwVb5BQYPt/+2xEpqsHC4GY37hXyRSGvfwYa7DGUDbMKd8vud28h67mpOl7fe4uFRe/HOKf3TFs+9RX+QpL0+C2b4R/8VfkUQOABt4tcaDV34nU/UFXBUDvPYMYe0F24AZPIWphY9bLwt+tWvmuWwhvAgPN1rxvo3hpXvQNSPsVKgFUKENrmSCjWPYCUoQfJFpepI6oqpsVwJt6IlBFGO4soABNOS2KtnF9P7E9sSLK1WWOdGvYNhxKO5/D5ACMSM3oLy6XvjzPe57hP26DKKsIbhLZqcz8tJOcm1zlVKV87cVqDh5iOgGkNIKp7JU8eBp4VRPvv6peu3DR+ROhro3GOnpo6Cdltkq395hUi+pDXzwcONA2YjC4BKvX3JGZi77wJboSzwwPelRCe5297Gau3hHdjkNfDMaoCdfo4BX1IthlFNEHUm2nTsuiPe/rOux7FSlxIwT09NqnvyBmWQYcleqlPEreuoCZRFvXL07v84AxlxNdJM/atDmCjpmzumIoYOf4uVqV/8ZnSwV78WW0S0R7AwI0EDq4B6IaI6AUBwPrNLY0eeSw24zQ6qVAgBGW5aK79Mg+Skj4XxdPl8axMl4x6nwmnAfEBIju1ssp4yr/gdi9kl+ScGW3r5NVqJ1fXRkW9O0A6JBottvWGypQioSH2C46bepNpt5dXRK28XY0hseEnW9fDBaUMHziavWy8Q7jttulrsjOd5WunqGz20rPiwX/3fdKuQgv0g4CDqGBMamo9htCyKqN0qTOxWP5MmZG0lur+eIMwtcrfYqJujT19J3dps8mrCySt1MRdmlNIykG8cIMszw/nMlRV1DmpxNn2zf3gflXm1sXSH00EqrICj29dnyNSbIteQOqjPLqBf2QDDVVCAgcCz7vER9m5X4XkTIeB4ppqaFa2UHE05QSkAhs7FkyPf40UFGlKG8GnrdKq0ZLUk9m5jleTBwhdDsYP8HCDKRE6LS48qLHD4pvSl3XFvmH8KBEmyeyNwwJzAJQd8MqhmKsdandB6Ec1bHOw8agmVGP/vvY2C60X8AnR2r2HhdkUbclW9+ozjmxmipA1AJIZnqxg4aa1Le0RHfU2vkpf68y/rFMYgCXue7eNqxoS0NkOw9a9/WcDFJOh0Grb8zYjPgaSDENIFMCM0H5OlIqq2r2FKGkaQSMzVm87r9L7fysa4xxVMD0h7CIExLBVbCe1/r/WavK3yPhHVe3XBjyVTDOqI4/90N/Cm5KnqxFrVYOHbwMIXa3GwNwVME+38OpXvNwD6l+jN8BDCRDEjGDFC+WObTdm+5/tfm0QeEfVUYFtA7gTobiCnl8rywroMyBHNClofz+W7OhssrGuos+fRhh8kBA+Ni0fYdhKK+qCZaY0LUDpn17UUKCX6dOZccCYzSsD2iSQP74pFnhlkOzACsapdT20zbjF6ZqLgELUPT8IglaX38zP6zfdyBF+NjNf247XNtmIz4QCO5iRy/GcS8jjaWMfTxI3EbUvzrprtgRQDOz/eMnyVQVbbFiTMZfhfQLeu+j6iY0Qs/QYGFdHefwzAYuVpPhVZK/tXsy6DAioLlmNDzAu1eQ5ihCnobO+MOZtSD0+uTpiOAvPwGWf52xDUHj4zbdFtZULPV4c1TmWflDGMkg/Ia6kPHprHErwFTGoBg+1D6oX8lSPdz5srAF0RbktUTmq44+USAYYowZQOVbM3BWMc603Oy9SQD3buNTgzJ7yaMBbo/pjkzVrpW5xYH0Ra11ykiz32vo4nBg9Zvm92KHWhJm7uQJV5DMPA1JHBWBMcjz/uZupwXqjoTffeHZ17N3waXUaR7cZDs94ewlhsbQrmI7/A4zJDUZj0qKiVQhn3f3AneEhDwl6GUdCBdKY14q9n6ay58twW2PRXXPJ6UE6TUs6oqH/0xgDpP3bx/mfcCUy5oo91agCPtpTfowGZ0tyw5mIOsUqvdURDhjuWLX/WIqaPlYx3zmJ3ahTcxtC5xQgKWrQskF57LaOvwYN0lzIwz/joNYkiZwLyB7Joi0CsWWRC6SapEN5TClIisNQtNPmfwKaKYb+Hguo76RtcQMXdRZWjEJNHq8KZKeg/uWWDOW6aygLP9JDrNNW7JfWDyHPR8GL+29zBAD5FY1WZXsmYfdKU1VTLLzAHERJJGTpwKZH5k0uZrDYM8zG9WX+RVDM8bsmN8cI2wKz0Td8GEq9T4DvY6FuhMsqPGHC1tkLdxuwBYP0Lu2RvjXaxodrZhKfkkIwGcfm+lFS4WMFPCz3FwWwuvNLNqv7c85xnk3aXWl49yCW0YTzTqwyKuKWSIFJum5G8BBjvxx2yDOZMh18M2WhRGX5VA0p3eAilBsGa54P+iEat2c0lLnTrXg7fzDLJrjO/213hRmT/92zHwHShntUiR+9KUWKWRcx9OrMWfefEo/p2FR7dbNWoP/P/se7JJUfBzJixcPvTzMvSTQrccDAmpwoLnh6pnsAF37U9Cakvwb0EZzywhYhfUyAZ4oAu4R1X55yrbJifKRbLIC6NaYqZxbpzV9ec4/SFSjJKEvmVGa9tHfUJayAvrPPbVHNaxlbdJOOn7f43GTTdGGufXu/daAhuYtol2y5rFVUxlDpyKCfYRz3fOyJZEjhxizetlF5kpK8kUuEpKNWnSG9VEdmcn7Tu0/U9Pho+IZiTincXepD9zQXGusmr6j19TKRCe4dmbGmRl1cDDNABYeOKT51fHc6+d1Q9T2n1UMmkd+aiSUgNIrogqtnInezaEs7HmtmpjKttWg7ulLhPvEEnGE5TqPY3iCItPzYojGET4V755b+cNmqdG6OBTlbYjDs4AAp+ho1Iq8R/eWa0/FOyB4K5JLQ/WqwpaNPuaoufHcJMEld4peiw/7uIRZ9U4otV2lACBY2PfSUUu7vJ/iZUtvPoJmd8K/BmbnNo2iumTtQxEeARnjsHdzf1JrE1L6NGFsI7t81c5GCgmWILKM5pWDA5HO53I6aju6916JkUl1YcYyk9Hwwf/waKzGbNaeXD2d1jBd+rriDyPgR5p32kxAb41vjMM5QjUrVztISMmbVDBnx2qArnLJ6ECRGZcfK4U6LCAMxRtE+Y32MobWIYqbeJLCsaF4pCXyZjPABVmN36NRAavX8RXO80JuF2m/Snmg2NL0dSW67EVH9I4fcFSjpL73r6ohLh/V+uK3786Tpz4u9p1byZEEFVjn4eK4wBNeQ7DGhdbFbRTt6/9b55EBMfJGakrqZ4U+Fgnh2uIpidUcG+iBjHE5HMRX2ZKkKLyYQElkw/Kbj2w8OvDaxd8rzWoSUnwkiP9DB4L1FBdrrf9anTqNfPehHTBlyG9cgcQLrR8tQEZN9zuxs8BV1Zf+cIk9kSStcCODphQCbZP7NYhgTuqPh967gyo6DhJVEeM/gq2arEo3NkVtX7D7mzM4zzsjwEazeZbygY6xwP5F5NLqPJ0Hxncni2XMn/GdHQmTbQF1zee4LOhZaDlBzMZLsKXcJ3sJsBmPODcSW/FKYiVgzz7wLdz0C3bFpTwedWpIZzG+H0kpS6hOFF5yNj/xUGHEQK75qxYUFuXq2vFITPVf7aaAWUF+eBV5VbBqFcUccHNaTmGaDdRTdXTurKJ8ATxX0DHWz2qNhGP4nrYJRCKI12hvvahdfR6RlR+zca42mjybVuHEEGrU2KvnHy9+mmlQDH4jYHZKC6knkne5Q28ldgrISAF0p2u8YVTy2bGLZqUkIV6zWDXi0DuZMiQhOJwUgZQNnrjzpboxif7CaCAFdxHukA5fPTubF6aLOTWCnS/EP8ZSOIyNGpkn86BVLEgxNoCo5XDdJHdnSB0Zy+5O4NQSsoKdZzikwg0eSvXAE6j6WW27irlXjNHHxiuOY/LaFsSgXv62JfK2/O09r1DMjpxv32Y457Wd8wFBf9V6i6CdLP2Z9qNFsxcP88S7N6b5FAkZAkO78T3f4mpUVnXed/QQC1AAudBr+gg118i202+jHf4m1tBvD2iwt/8PqoAWQSajReU2kDJ91lZ9cqfgKVbzge5mUlKDSh7aeClFOoVz9UEdTQyNyjj+u7JaX9DWyqtt6955fcvBJF1aKEjjPQjYV4+FQr9Fnd8NqWavBRL91OUcILzXVselzvLQtPmmvtdhkUNi8G+O+b/qcVyHvls9lJjRGbe0YWtuq9zXA02yIjtBjoQd1vY0EmEFvb3u3xiPt9Wix6NZ7ljWQVbw229SAPrh/hsIECHTLmxKxWD3/K6TUieQeqJIfpcIoOQcgmvHDyyRUevzKImeikRzg+ly1+qSicz7hh/DCm/39Fyk6M86XNkhcEgJKANNt1matUHBPuMmqkqR0Irsee0uIofjg8efSzC4Ml6OzAV1PuydANODV+SaVqKrg8qTvT2ROpiQHqoOAq3EdFRo1QW+1ak/AYmGEVA4cF99A82GRm5mLHhLHqOSqBVNF5d+tjFko2morW+bAtWqE3Mhi2uYPJEeL+puWOoJaLV9uHtQIj2GvjqEnPiF3gSNk2kq1rb+v31DDwcalu1nsmfE1n7J39uQgliDyyoBoudkZrUtnIUrDsC6iGs/DA1YU+EpC8VYQ4iw91D0O8kJIRK0Zo3YzUzYnm6vxq+9EDAP5SWf+Eyupwlhcyq7rgfu0UcsS/cyy18bZBvpooyg1q0GNkTJ+MwtXBtDoaChHEqMdF/a7GjUgboSb8jHDJrfqRhQ/bbI62r8nHoOa6UgOaJLxxg1EhXpXmkd3Rch7uNxgpPzxP/mBdrGsygnoth1z7Q/YLYJb7LwpuGREdhP+ef4imi3CBmJrq9pWR8/s43S4uxqNYHUv9ha9RBACBhuz+S4xTQTZaCKSoDHnxC8CxGhiHczvJUTlt4rrWQpu9+AvsrR2wMvwqpTTd2ETTsO/P3JJiLBUvcs0TXCPCRY2h9Nx8ZqMz8XSEqa9ByDLoNM8PxxK/62v/Wkztb9dlxfHsl4u4UjIZo5lD7knNDevOZvFRYHhwFE22lXrX+Sffrt3y9R1DKaG/GlAPLQQX/Hetzpmce0TT69U3cFZSUWj1hcJa25OoCXx3O5jXSizjPu68eF6JRu4ly0GPmihJAcdY54LAu+PeTtHdGWaRfb6RVp9zxwP+2PoTSQm+qFhD5LkhsYuT1IwWLIAUjU9P0z7IOUj2QP4sYABt2vX5hJCVUnjOBPVGQTmwyR8LSRc2WvhlmD4DMitovW8AmruHvsuxxMnY/ybXB0f6jgvY+7tMu0sJN5r4DBEBXa37SH5PepbiAlY5L6+09qF9dbg57qZdXr+Lkj+9ODwIdoY9Ogs9QXAMPBK9sNLNDM1mFaODMVpqeBBx3+/X8BkyPofOmxl+kYJsG1PP50FDBXj0A4uVUwSXOnyDvjHd5pupMiy5DyOMVDjPDi22YVTeKKPxtGz5/wLm/x/DzHO4PBKlriUyR2fdazZ8MZwZO2yzm40RwLqezNhsNT7aqhOqWBMfTbYcyVtVzrROKLQ/cw8h9MBYgLQZ5m7RtajLhjAmwWRubbOysVY9+MbTxulvSqQymjxTj0/yGmowXOk8LorLHbyciHZbi5Wipq5e028xOnXPq0SO1Ei/BmXFCr+iw4toQwld1d5KXZJaq1eDPduqLEuVRpKA9CzB7KJsTTpdrYpMaOsIFM7Wgr9Oh/caoRAohQN6A6HSrmbUuxffYlS4ymc4W40QYfauuqpQ/JTXe2l3gW1vBU3Q0CQWi+YnGMAlM7QCe806vIrrgQmejgYb3z21bFn0KNZj8qMbtk0fubcrDYYwmBhjZezZtAK7N3MQKKCODWwtmN/WYEGctudKJzRB3xrBGIXPbh2oyOsQ4psvw2packPl36ulG2AlW5rvS3xsDrZG0jPgcLNOBZVquBKudvtx5EyYnivmLREWPn30cbkfL4RsfTwuJVSFZZJFh6UkofGq/bkz/WqbPwyDk8xppCVNz7JQstijvxEWrb40THMQJebLnzyY2q2jx2SLecaR7/0b676f5ddR3aDQqQxzS6YlPvFcYbw+8vic5SAk75H9CSsEorQCVlJSk7DU5HBRkzDnV2QtTJe9fsfqy1sQNBXqUXzv+3HDVDSjlHNPKEmNGm5+zlEP/Pa0mLR8hxOG5PeuHfsO4YAaC+btxGwKVWC9Se7tv8fBJBx1n+Kox6GyPB1SVukkNQkjh9dl8s6dR8uwRo6Ep3zrpyoDHwNvpGU0zV5/27gpveUjCyrt2ZF4TOPsS/WygLkfE2dbNXsNDXjU0kggbh+REnbrOGVNbeYAoc4ZX0aRdyTYOFzlRKaGo4MoHLkMH9FMwYlY+jItBYVbIzsByLIUmu7xM7N3q4VtOAzdBtYpwYx/5yTIIJ9yh2VZWg/uPZimDRgASUeaIeF/TU+n3NBLOkQvsf4CKuJi9s4FqpE2p0HLaw6yIcFU8mcl8Jx6XPWv+eL9Uv+Eyr1QVYQfaJcVwJ6kjFn9GSZ3uvbIxaZMwi7x+nNLp60sgdzogotqc5oVT+LDsygUDk+S361me7L2BWYFkcDER/Rx+J0tgDZ6wwKRu7kFtxCpqtt19WgsF6LzpqmDlLORvOsY68JnuZgBdo7ozFmFR6uGXxbySNeCvPKl92vkVsYEYjZ70nSsNQz9WiIy0pcd4Cjnd16gHVj3X+IIr+ZH/gTnYy0JQvVtpoQKA3yqTH8ZK5WAWFLSXjNeHCwtYmaan6uJoOWW3ktmR0n9j0uxSEniCHfobcaa4adhh6U65iKCHer9DsvpoFJxkj5jhGLhPSjJ+hLddzatV/1Ocn1CE5uZoZAMtgkhUYN5zk9+VUjJxOTjDsX8kQFan+fCSw0rK8IhXNp3dynfHXSYCNq076Pn60lpsgbLC41pl75UNjAtdkXJ0OFBP9SOFxYd/qxoACmCf2c4BNjgll3P8P77ikGQPLbKe6Bprf5RR7SLTcoLj+WEriYD+XvlnCQ6gwN09MIkc6PH+xS8JfJD7iyBoSsLx/L/1AzaxG7e0eIP2dxroERhpC6jg8arrg7XQBksDHIJZIPRhy16WjWaucMUOLtxrgBU9rezETjoCtMnBYdaOAagkVHdueRkp+p0+SRoZ4ejQaCwhOiYRYYJC7NsV73oO8dwYLioC3qILoo9B/eMud5uERJdTB+L3gaZcXObntZ43fegezhpmSwHyw4dM10xfsXF1MY5XAR1XmGR9Qz8Yrc2BSBiUUf1wSye1tGQLKtmsheBI0zWEKzJu8/tdWQ84lcWgnXo9INPwDU5XiJi0OyBQbwRH1ahR14L10g9kAYWlDK/0N3VzcgYYursjTtw/2wSHmfTGJsx5NOXmMmVliBLLHGu6G0jFBLZtUkH7EzFzorhlKhKRrLqXXlXpO8crQ3CHEcZLu9XzwCc9SvkPe94gxwonijdizLHtGfLLKLF1cdtXMFa7Mf4P/JQHiBZIRXBzCKoqPaIuvh7X4/SQdEJnxbsIECUF90ZnrLUpBjTXiX4XAc3Mse7eTXKyZp8Q3Sf1S3esZyDQl+BBER4PmbGOeQ+K1112FbEeyqQZg56WiQ0jRCUmP+Kew9A1ZxSjutLVOfkpuBwoSkP4RGNoe7WrmyTXKI6nk1Tnz0oe2Vm3PjBDf8Gwhe+fwAYSAjlPra1TtCj1uu1GcdIAm6ViQn9Srqf1ym9fPIxInLxt48mCIl6DSTi4ZJ+XkJrz2dXWQqhpSF4nNWapdIjJH+p1Opedufkw0xHlr4vORb9BCJ3W8vAPdZSqI7VxbNaaOfqhI/8w7L9horVKv7MLnEr2l2XgUM6+i5Ix58xgRlYVxa+ltEdaupD5yktPEOlldMIatEHTM9j7h7hxVvQPEbtQP6BmDdVaPz2u/o7+Aiy4lsXGE+Km2ss6828uqY4y28croxcwQBaemP2+4hEA88WmmXnQTmIMFje/i5qVzP/dynhApy5GEB55hU7+jPdveexxyrULupZB1hjyqISvKscuKXOXZUnp8dPLlTkOIlOhMu9t4Vx5PLPIDK0SdUiZ95AlS0+/1macnq6hXYYejgXigt9NePxN2PY9CC0HftH0q8httvBeLZ48ootbmSIZgK7/Wm1zqq/lUDZBL6CYC5KDyLg/WfRKIQMNyN2X432uLr/f/9AoV132hvDNWvIbdgJKmzFwnqjd8+MjwrCINW480Y/0ve7EpvtXHg4WzJv5MuILg89gjdMk86QRO9Q/YKdmb+HV6eMqRTq/oudO/E6zvH3NzGgHNz/zI4Clc1kXUMDTrnDpBI2KbWe//7iI6d1A8nhX4F+4tGki7hfsA4VOK83fdLmcdAGqQRjtItVXa3J7vhE+x0h3K+fVJpM2FZDdY7gVF9ME1rtQmyQOE+F7b6vQAUregqMnIegpxtIKRhyTvfx+DFWZLf+VUZHUO+CicH8sE+9LpldACFUpG+WMfE56X+8xIB5l+Eu4ij2kBUNYythq4o1kyIEuD1kt9XQ97gS9+waaIHokWae6jm/Y8Govgmk31Z2M0SBZAIeudbA/y6RkBys3zsWVHoPxD73jIs92cougppJ3Uxf/pQcoOw/qt20epdVJgHhT5/Rg5mNf+bvQ4LJnwSxs7VE9Qc/myZF4IFBUAom49bMTIghVW6RJ2gfXkP6ovc0THTEpxZWx4zTkARVTfH75vftaIkZptS+h3ERciwL+zFBfxojqrdRqqdkYWAVmXpf+ueckOfXPrN5b9eEwl8OJWgoXwyPM73RDn5ix09+qYTUbhIRquBAIHnO03H3q5TFdSXzP+sPDF+FV61ALiJwLttts7/NF2qhFJI57p4sixeZfoEtm0Dg5wGwPCH6tc6aqO8oe5R+IkDR8TuyFEN2w2kBdTxxvejaSoap3bQlCW4svakUIjVrpe7zCbbcGL0xSe/T3hysCfb20Xj0oFitmmY1Q+1QAbHJj3MfeeZfxuvYYoF7mLnb9sF2SPQEFrRwt08qapY0ODw4ReEM3TamVg4j3BvgKWWLIeWrMXPSM+I3hBzjUn6TbqMNWIPDWj5FBYrWBwXYB71BOpmX+5iYomjHoQ7LUcQ867QRS3qZXYnBbLy/FO2tEGfzE/rGyNxED2nvMySIIs4Fx3fZIsIZn/tCkocG9krZ5TWha4eDI3zmyCQeBMYsXlRDNsMfjEEBFh6/Qhq12c9IUp606kEY5bwbG/QnU+IAyJhlftn2f8iRL5A7v4R9oAJGU2GYjNHqZUGg2z6az4YMtQyXcV9X9WBRlaYnfVIRsmuVGDhDBIoG6C8AkCK6LdXd0NgeShgVCNpx7iacd6L5r4rVi1Gco6rCBwBfwyIJs4Fhnq8IZrURn9zhkJ2FenUPijnbIom4cDNJT3zqMfvySGt4ko2KqwoGDH25QLfuWMbcuRhuQwYKgCX9VgClxETR6DM5DNjTv7F3ysG0kI8NKZ5AZDzjJnJD4VVPwVR/fNKHpzgM8QQGSapVEbQCuiSw0xjHphp0eDxZeames1Mp9WwQ2puhmhj5ql1Lv0eYJEpN8RFa01yfNY0KZkTpYzcO/Ckhbb36k9esVXSMPl1G/K7/sR9Mcqvz7tEmdFwGaO02c6azfLxlRg6byx5y5aqHXBgH+N8X+0pGSjHsaENs0tEcJU4XtLrRLBJGIFVEe3TvIYkvc3siaU1d3xi9t7TPq1L/+hMRqojqmp8jBLyo7KEuYZeOKHFM3mUkV+XkyhiFhmwxtLgSsGMbh8fE6hCR2rTOIinlmsF74yj7IpViQkLbyCbrvDt5/yX6I7Y1abrFs7QBI3D9QnlxlwbgZHvFTKeaFKcI3NvUQFQURMimQ5M+eF6vwSlYff+7/cWpYmvPrIh9BVONzVYOe2tQdAWWT5fJSYL5Upt0L6Dl/pZObBEdo+FPC4b2+iU09eJ6vb/kc2/uq9CvCUV9KB+C/CPAJdOu7vq8wf/Yxy8081PEnm7VGsIzzoFYnDvfYTUyPhdXV2yICWljxWqkyEe4e1n+SZCRACDyiLTdzj5Dq5ThMdA+CNJhV09iM2iW1Pgf2XiLDkIpNo8ugDtNdVTMEBsO+uHzrqEI+EwMOFr2gevD8TkmyjvrYH9Bw6rkARUFwc7DRpOCIaACn2Edjv7bmiS3MFeVgdj1y0Rv+v1DYqY6EwHst3CNlpq6XBW7Q/fu+F1R20aHUR5Z1LIZ7wvY0E/w99bKzAyUjG7671ZUYF6F5+Ynv4Cm0twLZ+GTrBp8VL/LMeq8XYgzYldrklMglyWJS7iWBhdA5GraO3m3rO2AorN4N62bHcpIhG8kbvIkybnRVTEWt5a5f7iIYJN61OO1gLp+lMKa9CuaUR/y9eoF3/jHgqh6iPSadglFYQ/GTsLkzIXMTFtBelXwJHtvmQtoXItuOsLGvL2IK/M295YD8SaNfSND8zTfgUXGYQRyrzsPYC1cxWOto+YkW9R3EinZBFUy/5HWXF6WeqLcPADGeJH3U642mjV9hMqA/GY+7DcN2bpls25VizlGv+FyH0qhDmmd0gUS8y90rDX+Xk6y6McJ6S7gM/DYcoTHv/2NeKg4rjMw8TqrlL9LBcLKWQxtuJxVX7ObKDCs6fNlfUj6iRrGPFdJD+ziFknCJKgixZ5RJQEQZi2MefRmUYi5crYu3Oh50a5Jf+upvNzFAo7KhxO8WRvoqnLO0wvvdcPsaVUOIcvfZoUierdTyFyoxwnJI91KCBroEodybtBGshuLseewOL8RJP+H2Oqsca/SYdeeRtivXY+FFQeTQ33eeX3DdtS0+wgHXVCCQk/CkG/az4aY+ExO9eyJRmpeKAXose57USPZEoRKo6m3uIY0rsGhjw0xAS7X1DuBTFVuo29v3dChgu70cPjpl5/xQmrPdA36PXNZRWOszr9FtTYYxG7dHUooremnYo1QnUGWsN/xygLq9TDGLLhVH/pc4pD+15uGiALFzU4PINmfD25G8LAsJea1dQlpC1s7rkYJUQqIwFNDY4Eh0dawLn8fCol/rhUCEbEHM1dJlCBpXxKfm7zt/ZpsbXgy68nEkEoLjs9rk0E9GFFZoYLZv/4qZR7nl7qBbeALu0FWvdWoNb4hCvlkME+i5nbMafn9uVxxXlpXBlOxHA7IKvKJLMXQanWkuK9A+2VI1JSDoY06+R0/g5TPJIHfO3roljfhM9ncx6Qrk66xY1H0+2UgF+oQgm28A27u9+T4rGo0sT6suA8Jdwthg1T9gojZro33dFb5pubkZ5ZHchLzsKkibaR3DHxf769V4iImNuKKrpgMMK8vcvF4YgFx9Asca63MVyNPtp5+zXPASns3bwdmsxnn1S54GTdkB4DwX4L7JXMnQGqIaS+mPgWxbIZbFcDNIrMilEIEGFczfvcACtmReTyzqnpITyfsh5QK4RKX9ZWtvUy4bWXjsLYbNV7MrrZsT82c9cmf4f8I0sSYqVIlcUYgI782imxBuEKs3OWcogWDmwlr9TGLtVSSTlyzHUW4PU9f7Wv06gLioBSoAf5esTj3FD9kKtTKQZfTKEIOcCYWcfIk4IkcfoFGKSLqsHhBpBOTfEJ6dxkBJXCSlknDrb8XJYO4/96XFd4ThAg4/Heg3u5p1kP3QG2yMuUrty2cFQaT3cWMABIB2diEu/1KfFFSKbfjTp8aUhb99C/ZA5m7h8JWsGwT5Ml9Uhw6CmNHyRA15TyVwIsOH0I1tFeVqQaoqT7wGjyqrJ9bI+WtpjMv5CAGQfj+k2aPOJZ/zLvxAtkd/Bzh9BZPEwVE0I0DI82uWK72P5+mHKig5zbXYrQE5bSNA9/gHvSND2qLV3hLPnoJp5q/NeZX7mhb2aWf7qkF8iM4HEHQ6YiYA+E+kPmfMGabHq62QBi8sSJ3yb68iTcA4YT6f+gJb6G3adGkY9eeu7XQZiQEi2fXRSKUOj/zLkyh4R3hOAX6xhT1yCvCHT2Jb9tAzSMxe0RFbM3g6b/VHgP8nyZkt45j1ZYBTwOpQIaFU7nU5focNbiclNOds9b6I+FOnBXwyAf1ViJPMKBBofmR8wg+77g5o3CiYUzQ+KdNxUo14XQc58/GKrIq3XSIefM9azql5sX7KlTsU8DGT1HlHIYnd10cJYsAEHoN0mLKcHTySHsjTFesKWsmK+siZFXhlavE6F44mweXOrX6FBoELRrvIrsst4OH+O47VaML4CK/cNrjlTodfRr3u2XZsHCcw9kXLGX/15sm10DYmP3G3387x7LDyVoplrs0pzIvfcy41eb2Ob/wM6tQNLxQKnfSbL0eyYL+RWR09qeHT/lWpCFvcISYlmdF/jMaIWDyxE/LA1tguYOSiQtSqHfgqHr1n/k5nFhnUBnU1J1eys/8qySmWwIplgfD3uNcFHlg6trf2B11Om/f7E9onO53sWHhas4nNuhBJsUn2OjOnOAFZi2dcAvexHytVxIdybjHcEdXUcp0jkab19hwZ0RddTUGjtyulBmpbfGD+4d+oynTEjmMlYS/pfoCyhEk9XbgbBf7wtFs5qleFrCmB0NrUYZLxmw+2wFqYEUy2hYP3ZxY8uhRZeFXZfhOD58zGBx7lo4yMjiBc0zvOGqVQm8d4tk1CRpyGJOGJWVU4EpHPxqgMP6hV7f0IxJugziIEJHavrZauRXe0/THYEOKpl/a4jm/fah+oAzHRBqwetjJBSjNp5LaZ3ZUNQElZJBDOF1e4muumSHF6da394Cvppq45QN1B2wYBfbx4Y9fnq5b+heTNTCmP9XhMQGniDhmdhGzfPUY5YPvTUhEcaaA2ucNDUO/xvaUVhXDIodrM/05R31bnFkjUjn34N7Aiuagl9VB9SjYsu83Ws9eoevaZVwZMC4uiZko2GtNzZCyMHRq6GKhvEGBiM1gLyvMZk3eR2dGcn19YX72JnDBY6RWncG7lGAg0YZR9lyoCyQ13gtnyBi05gPlO9yOeIYGqQrhgRpR+pAvx4czdaBMpVI7SgZMAhMSsdPUEQ9stTtwSabBmrln0uHsOMhDvi0bNRUWUmqnu3eiLgzk2XKGyTaHCe59vZZcmDkk8aOO6pTw5H+DWALBPMcCOmfIz4cF9E5zesXbQkQNDFk7vlnAcetbpid+Ce9MnTb3Clhv0lL7lyusJYCpLpalVXmQ67YNR+IIDh9vW7XeWnU3FFfdnO0yqCON1josSLVMTTaH/T3Q7Y+gOUofDwwXaGyGRB+4GRC2kk7zANlgd7PmE5kXda4IpmTbP2OqUJ/O9EXW4aslQR5PtYy3tNMamtk4Lwzb6WIFll7MVBneG5vPfEGslblvK4unzLLIvceI6WxhiZNc/nr10k9nn8ikKPz5jmA9oC+lWIE8QR4XYTcO6WZ7VMORykmWLBbTE1NQc8/TBpYSaYjlsyOK50EEwZC6/hyMiltFDU/OcVfSs/4s0Rk68qJkU5mIFxzQcySQSzLKmqQzkbb2ZlC8MLMP8Tt/ui2UK3r3IoyOWjDNfAV+2/iYAbaU/gcEuC9PqZbBCpHpobrsMSJpIpAbdk+lZArMaQfdQP2kY9Krk6TsjNb/ad7Ghc/HTlJyxRISEoijGyuLhUJB5Ch35PrR1oibmRE3vvhC5cWj/AFFMlliT5ELHoj9ieMLEG0BOkVRUXKuv2bfaF8AdXORnzTtMfXYqB8UVY5TvybX4Mkg9YXaiDDrp7KV8wVHpmx3MIlmRkznG4Q7DbYNTZBEi2yxQfQW37NrAOyCP8AXP/EHi/BLLFg/ip1tleZLojlnpdzKgSmJyi4IRDWNifCtFxTRjzh2z9DNa3KUZLZnixrksQWHwp2gRkmuu7HYPHYIQrdjih0WnNb7CL7hFDLjbfGaVLQh5Fu7SHtZTqDYzgY4QnM/x2PC8v6+qmCAMbOvWxZOIxjgpUF1ud2/e41K1bJAXPTZ0ctJLsigJDqNH6fNsXGGXNx7cwJPgP6INK3Qxc3ylfv0L1e9m37k+CqkJJTN6MvvQuae8WjO1l0JvBh6yHIrZgf/Bt/DNS1QULgHfUCLdwH6GVXxn8JChzrTEJL4dTZGD6nCwPWD+eeU/jxNc/wph/HYngIZcSTOnA7ZoHemc7pUYXx0Nr45Sbce9CyAvFnCzoIYbXxoDXYVwt/7sf509VEfvoLzjbFrRKr4vntb5dgeDiwRX6neO0yQZsOSoVjVvOOSAuP4PT+ezKgOTL5CMeBFh5fTyCTneXHNexLrs1pBpLHH3kmt/Gi6938ByjJyGR1wM7/rvRQQoS1drQjQ0vefqIJKlavxUAyi0PuILAyGGfaeCzz00DKjY1cowpRuwwf7rYPEZOByjttnqj6EUZ84F5gZp+4HJmTpMjNq0q/lyKFhwHKG0wkVp5h+gESx82VKGR+mbao8YOh23JnEy+eNJ45yos7d1gFc6GC67dt+OzE5TpAYicEpe2YtuuIHNt0hQpdLBdS8eqx9D9RSrya3h16jYIp9Ogfv58USTrQa6bOJgC6Fuw3VSohoUOQpQ/XY+PVKw2eV8Q1N6yxzymT6QIiLizm3kcA+jtFVJVj/IlTTGr7Tj6P8fQmh0ag3AJfRbLs8nmEQ1QHGUtaUv9djTgKNG5hVLyiujHLL77tNlHcYLwqquU6Z2V+WMoDwfBiMDqK39/tNhs7dXQhQTHYkold5VgNmV+WJr8ETyoKTHTS8g1RZL+KCbZw1LZoGTgR6eNleq+XGRggG9pbw1+WcW0jzJpvQle+pDWTA3yPaJogeuohg7EijR/48Se6kjwNpGStelAHWNOtzrfgmNxtH9r1eSRWLz79nRNF5th43Vy+rZ9FcwK7PlfJojQmk6yDIgDVpS2IJtFflHkl2pdrA/ZK4Grks9dfURGUNk54HimplKaYEZX5dE2M9W/60vxTLBE6XeIZ01h4YiHBHGMX+eAHZAHpSk2dFZUbQL/ylbq8VdzyOCnwzB532xAsz2XqmJFNJCZ6YuvEpyZtLa07GuhPki8MeZUI63KN4jC30SSX7/bWpsMyfpqrzmMI+cCYlmRUB0Mu4kG/untuIlFzWG2JnuSThOvNB87WuxDF4K9MPLtApA2nPV+2yMqZtQu/5eBgMzg8/6FBhddJz3kV0onK4Jbo71w6dhI4czF3ksh7/wVe0vAH8B/pVGb1v7xscPIhg6KL+hvTtq6g1+kCPpBURUhkj6yrfPgZ3/Xtc22MaQJp0ouI8smF0IW7P8ZfkCNRlxyoz5rOlXJ2YoBYf+hZJACLpIW6Ecg7s2fptIWtvuAgGvGV7dSNLkYv17ghjkJQx6tLucnApd6V56PAKNj/7Yyi6MOC9uwvXC4HnQSolMT49c6/5ZRIfWauOyw+arQBxET3gqjgZPldHDuhPDdYxffuJ1ityuwa75OUwVzCfQ3DhhKAfuieBFYqqN1i5usxjNFwKad4V39gjt2wLjcS1yX59qz0LCyVW9KbSYU9A28hy5DC7hdtdQxRU9PX4vfg8R4KZzpT7OhJe4Rwnuob88KsYJT3Xdb5uQj/iI2b9k+IAL2RazReg2nxwi3ia771jH8mWcStAs1NJu+cMgx6oarFqLe8b1HSRxQ7za0WtQhVKdhOSo+l5MyUbO7l4rtMf8vOidRDYSBoESyiDirZR/lirb7mNwOHR9B00U3KDHjR+/6/p0FjHCVpWNOzJcWfIRQkZ6XmbdXoGNbYi+/6K31kVQSpEiFHlf0XTAzQKDh03BJv6aoldSXInQfAEINY34mN7TGvaILI1iq1F8qQD9LdUyM1y1GkmIcoViAyaqPmTF6srtanuyTM4L1D0wyuj0tEVAfuycGdwEON4fnsCqlt5T6S1obgnUutprS4s5WpzQgzd4U9TRXJErli2+o2bS7A/uISBZhgh/679K/zLda6gWtuZwAvTGNdCbAN9uwZti3Hk9kKWrIq/zDHz00+fSYLcc5sgjgY5sWd/F9nGirgGojICMTxUzGmVVyjsC+0iZ7i++UKuLA2KCekIgylXj+DAZVKUFgBgXYW5+1bwyASMUltB5MhCcaMuivyyhZw3MJ7OjjmJyH+sH7zwWOwFaztw+KQpl6ETunGZ4wgXDkkep9RDpXHKdERy5R1KfOfi61l4kXklOVi+UvIPbGuKxTqSuKxjgg5aUU0X3V/EKdOugbYyeYKlYTyfe6Py6u2Z+A0k4k2giHiUVqkoC8MKxTXxmChSs68WryAMhUxyo84ORdwTONcLdmrVJbnyH+ugmyyx9iKEPADsMijuo2U3uJDa7Wnfr9gcycQq006VxIwrhk0FV/BDjqzquNOsEJXdrimGw0G+JVU4/5BNk+lE5kSCYz9cOOfNBtbtPUoVHnu1jfPwwGlaTc7GUxPcDFnEgwaHh5znVnSwPAAdXz5o6vI34Epz0NKfx11wmUjfW8nTAn60/CwPV4XjHM2yzXbq/EA9hUimpPyH+gMWQc8fiEpaTtk7l1iADxvDO8EMdlaQ0nXdXnhCuCrsoC+Uvlb9IaXpTbhDyzTzYYUPRsJ1khYU6+UMPk1YHn7mE5V3/F28Yia/wrwDdF+R6TmVzsqudzix7NyUGk46wXs0WaHIURcZDicGiV7SEhoVNTU0zgBoaSd49LNnCcmSgWRMUa0JKdpcVnfovdDcIyEcqOXD4VeP1baW1O5XKi8DuZzNuEL/drafxlkHz2RIla0Jp8ILNn7S3fdeg9UhAx9q0+SKtkZq2KsJrdjjyAjr3GfTjVIDAz98414NxYOtS7EWs2ZaFK7+4WBYoC5Hkeq4b/TVXen2W5sxGUXGVbea0PfIOieEzqtacY9iZH8JBwrLvaO9mQx8S8Xs1qoQA5mRuhLUFIcDGMj1wJK/K+vclB5Bl071Plrpq5+L4WJ77f/haemR3QBDVN+DYo/NMMFkqokI7b1nRwuzDmI5dEx4XMlGANd6UtZZVQ12+CHjwiLfAM9yPWaei6wRjGbxBRZUWxyt/lA3BanlqVbrdSdMBG5p3j4Pa9sSfYjUr77zB9h2qpnC6V8u1+XFmGBTP3y97KCCHykGfB6mbCNng2OYcDfFxSp12MaqtqOwry+xB9gUkHlnfW9DENAGqcYOxFOWwZHAJEeIuPuyLr3pc8euQGkJA6K1rmHJDoeAl370hmHY+Wk02WBNr6bOj8owlbEPXZobBQ/xU4JVN9l2GH0nnIedokXyCvBiq+jOf90wECFhhyXgaKiOos+J5t5i72+cySCooSeyr88ULT2mwUuMCLDw9Pty72PByiEtatpiqNeZF8Kladg4jD+8iY+w8ru/PveAVmrABMft/YevFyzmyB1LNidUz8yrnolKmitwK2bPJrQzSfyMg7RCZtnj801QmxB2Hh1RdODJ04NYCR84mkyeVmLrySQsPfWBiZawIPusj3W803YTrCIFZh55a7RhYSAh5uolGsv0TMC+pfZ8CJFMfhrjIkPX4iPlpoVij0m+1EDPaObMhssohxiQLjAb8un88eH/6Z8SnJxoDDY9JjIkM28xe9G9BMqE8CdRizNqXF+yzFoq+i0JXmGCunk6mGwVz7dw0Aht2yZLXL1jgrrUpP84ikBVljLiJmABWcOUt5aq4e2FLPP4IYwNw6/6kBGhUw92jqGvzzSz2IXFoSGkFThCZ6Hdi95k3hbTR+UyOtNXxKf3qOHtoG1+tO5u2H6XvCe4OZ0IsSdV2C22f4X0XRjnoLI9dkAJcmaPzyLbgrWgj/dizWHsrNz5PzGCCZ7zywhZMyk6RrEJ5ucZ5k4Fosm8+U94ZyJFHYaHthMhJSLgoHd9plpggxNFeaBMx2BdSg8d0qM1P9s3xHTr7n+uvFsfU5qJafAkyfAi/gC+OLxCw0uMl/XJ+id3bpdG4VxQwyKvZaxCWrPaRHIy9KcdR43jv9jfykGUTzB9KjyF1G0SkyMHMeY5wgAmcEp9B8ffD92GR4FQExXAD/Rm70xyf9mrg0HowJ+Y5o1trz3gJx6Em+pGPt0PvCVSXsmyA7BLMqIiL8iKyvmFzR0O7FJPoUD5dZJ1eKn4tDUJJ4Umb72XTHqR1qs8KsHPpu1Bas2jM6FoTMyoX5aScTz2RVJH0xso6SkxxuMBg3uUblz4fj83SnK1GADX8ZJtrY6l5lrbF1/ZuSi1BShVAdFnfBB3Sh1SW4KQz2mL+Y4svWwspzeGp4W6pTFKdMDjOxHzkJHkAfLjLjqf+T1Axa9og+Cl7gRTi70bSWjsQM9F19HqH1IdJOoerLMQTLpuVpFU//G6/hsxG6sFsnzMJ7n73SbIizBrcriqJQot6sKe+uP1gONUVuBIPlDJA49atkvafSdkS4NR+zciAFrwoHjdIsVSJKqDxAVrM15uFJb4cUI1Z5j3Wgo4gLqLZDMdNtYKJ1P7oBTGSBKZGTqguAYXj9FtcQ4sSbuwAvEKj0iSHfGzNYpAzMhIVEl+O5tVLe4s/3uEd9Gsrl6bogS5HKQwX3XK8Vnj7lf+5qIQiTSzRnfkEpdxxgU0LAZG7OSxjiHkVD2gFaZ1GjKhIedce7dFUwac8qA8Ut250wwH7O4rKHFECWEhhPfyyNNFFWeFrcIjCB9QkpXuz0U80DXFirexggv6bCvxlzrpYL2A02HykHogeIIum14ATyzZnKSfKNZqYUHkFr6qN2/mPO1WK01C9CpwXcl3fLEficn+qMiFNH5a/JFJBAF2ZZWJ5EP8mGzPCF9CDlr0z0YHruP+6bAUG47CNw5yDdR0WDTjq/DqDE8W+/fc6iTB4r9945YbHjR76ZqoOFAkp3KnRniRLdWK5iKvLCCH/Jf9vzHnX4LfdHlAiEucOADd6aaTJnMDTB0DnLoW9pvA/TvJPoH2GYOwUyBgDkGv7VLqRPzjz9nIWylnnWqIlm7L9YRAuucHIleKaTQCeUrXP0Wnyp2nmBxzeDiVOPsap6l6MYLHO4xg8HBAK3J1dgvBpIjcYDKZexJV5mf8c0hpw5ODKTwdkKCeeTezcPXh/9nI/FlRcIYy8sH3nKCQ0EEucVi+uinLNXGTmZXSuB5jYC2k1R6X8FYDLSs7G3qg+Wa30/SZZVsN+vbIWPDRqs9HMz/V2eXRrxClGwzMRZTnpwuqrD1GTjLUluOf9uPygJGxe+/EB6Ak5UCCsCWe2GLD5iZX8ywqGyaP9CGKOOsQ504tSVjAMPPpKo7Ex8LT3xYdh4QReijfasLvMKd8/bu689y+WY+S8IO9LXV7KYzmOOycnb7imsjeiBPCZgNd2Hd2fLIQOaLorPkKjFZcGRaNO6lp+pBPTMvw9QIbYuQZBlhu48VmV3i/3Y0m71BChUWR3cdNSS4D96YC5J0Y7ZFqMHBW6G9p9pf1EMvsoq2dzX2wSvNYXqdP47zyePLrk+nreb97cBNao7U34lHDXeFQ+HqT8XvcE26g42SyQZmHFRlH2UZ0kohpcgm7Li2wAo0IHMre/0XfRV0HtarB6og11KC3Z7/RUcqKzEPA7ZEJQgZNgBZE02MFT702HN67p516Nvqkm0Gjx83wQdQMeqxlml8LDK0V5SdTdnatEK7C+bhiQ3CLRBupVuTeGYhJY/BbrqiE1SY1vdXZ2SFuvNbcrI6ErGJV8/qH1acDEtu58Cm9IYXlR4R//8FS+sjKjiIPcuzVQ+9bV25MODrRYTzxFJYbLhp2Um/HKOncgLdKHj7tOrMZfxR6CrV1qRAGh+vD5dMMDkqvh3RtFI8M/B+95gOm4879zLjARkfVycAOqjJdoBfgWjWNsJnafTkmc7B3nIQv/Doeol9zaGW/DlpeEHHLSCVAFpPcoRFbXqIB0NIfCnsKcK8GmaNVe1S1WmDjR9kV2WjYdDpu3d+gX3edjZ363f9jQEbUhFXtuRXOQv+gmYCubqBrqUoagUdP7xj0HIFEZg93/KZ2CrZfN9t0A6WcpUJBI5WLyoLnqf11jJxzi7XP7icTGifXh8HPdPwOvmb7A1BFcfY2H1yrgpQ9LL1WPc8f4dqfuE91BNq8DtcEql3/06rGk4gsNyWI77GnH9IKwUsAFlrpUmA3zzUPojorig8/2Cbd3TjsCKM9wxliCLyKPngKsM1KFkqM6bMFtyxYYrU2eewcxYM6RkLIzuCbt2tjjkrWkSVoIS5lGaeH9ACsgsCD8uBJTg2FG+jOXwTTSCvGIWOiSPmrIKKcqEISVvUcMWhHEeUKjXTMdtBmPl8s4WipwTYa2j7rmaa0RNf7IXAOT77NGep/q0h0KdWRo5UPERTufgAqHgtum1dZEPq6OH8ILA+nokd8MXPhCko+zgkNqNlrLQew5ugiVBI+TSaF0+Nh/0lIpsCoBQWlDacVD+Vx3x3aSXTbkp6URafBo7r4W0YMJYL0MnwFM5mzSBvH459mHAZ0yzT09dEXgjVW9/ggg2LxRO6yGo5FTpGQS5EwMSjG3crtd3U4X4CO+KX5W46TC5B/X/DpEipFhWLaE6rpYO0r44KwsS9Ge9H2dfFY3QNvXA1sWHN6WR25HgQ091u/FmxcmTXpvXerH0b5xRi1MwmGmrK4ZAT1TapoD8+smzXuW4xfFWkVDOL7zk9xNtB53A3+dJrIzc5OTB601UXSFtQkX3hWaSnhB0fIWaxp9w7vGQDYtDAeTTDigrLMhVNfLUpJcIxhrMjO0Amicb+Ubauev6gApJbByzVQRTWq047GGRSYgxukHnlk5+xWTYTi31cQQCJ9ILZRJ3tV05M1AIgNeeDW2H8IBJqkzSl9nnKSajGYOD7eMyjHHWbG4SEV8CvAH8Iew6SodPSlX4spOyb4O8XdYQ2bne98jMMolgBIbc8j1VfPhmdPcqVcmf5qMjZcC2VzGSMF9s4863hYPVGq86Huy5cmg6zBz+qDU3yje9vmEr3yJ6kZhF5z8UdlkJdjq/581O9VuCR2B3lyEAfQoUZot9HdVILawreyRxAy11JlpE3UoO/fi5/5omkUs0A7Gvb5+bsteFVIW+9l+qR2dINow47smAidv0bLLEr/yqKcUanjvixyzAQCM5CVzq0r7rDR9M7wjLxBq9eBWRVmyK9TfSJqXHjL8T3l8phqzWGZrkRC5oiPO6C5Wf59fFDP+ituUaiEqytebX0Feyu7U5Leql5gBMTdDPsmK7KUOyA5TuWxjGc7dN7kJKEYpro0VWRhjMArMIGbutu6vN2OSHb6nvd508S4Q34uCRKu96bSAD7YHASNVhzXv8N8jroYf5Y7E9s4wTpkvo3BZkkWqpF0M1vka3jjUC/JuZvw9V8avX+D9bciICl12vr/bQJxDe+TN9MQwDJwOe5HRWZKtCtH/1/2brHVDE381FF3JIILjZf20UTFL4MLwmZtFv3M88Bv1x6hEyoaAlZ5p5QEWzlw8bJBt8orARhiododtduYtJBSF7octT9JzbeKdozaif0LBWL/u9RjbeVNLZ8UV44Ye6Sz56Vn8QlwftWL01WoPryii3ZZ930Zx6Ins/HGvGQmHAD+2qvuKQAs8Y6ublb+Dvhp3Y2NNMjsuzOvb6m4YtkPzbhlctKadex8tBQuo0zhmSxfDIZm5VnEDdG2vZ6kcykYFxgAz3wrkVyXQnwxyQIeYMIHQYT+257jBWD0yJIiC3PqmohMzTC/65XVgSsowG2kgnlR7pYY18nBQ8aVfJ64D79rH2pymM4xMU1Zk/OS14XiDcldhO0c0RhQxiPSY72XYxpiaKVYmzOcEvI1PzQa7+LVZ6pBIwn8ffWvhqa38b3IskTs4RBkYs9i+i9/AqdAQg2IOeWv2fuo5tEcFyefI9nATJXQchbBEQO2Cj3kaBe2X+81o97B22kYSwjOkgZybf53qZFQ6p/N0dL/VnuL1cYTGi8k6rMpkKGx4j+Mc/fcHUVNXTKhyO10FkvHiN+qSbJGepJ/aLXoLZ8RET0Bshv/4hAQgzeS7yl0n74cedqdnmAeHmQ2CyXvMM0MWpEvA2ezZIKU+WvUSaGpTt1kvMloerqnqxHLfT01Yh2n3iD29EWnrQsyjedi1I5SUgvQKBM9G+oAai15cO1con2QFz3UK7w7ZgzM+vPmbk2QqR87fzlbdTSAhrLXzqVfLnWBA/4+5aC+0BRMZ6iX9lH3QXtKU9D01K3HprdilL456y5lsl38VQaMbz9hk0LgquziMY01Znz2WE4ClHG9cF/e7stVmn89oNFUE9NZ1RAc97KzDEWHLoKwlCG6L20/2Gj7/M6PDhsvhY+FMzYRg+v/0jo2gPT0UTCfaLBDRVvKQgUSYPMG1dr6ox7ohepBUS0msHq/V7A6Y9WfKDgSLatqTzwhOXnuXAoFc1LsdlV/Nv7XHqg5TAohZGa1mOn44SyY1fyPMCxL1QmxvhBC7mxDyj9DUnBpbjdAzrBW0mUzZ51brDVW3f0A8oKL6FYBf0mwK6YxDMJogq94OPgpZyKHKBYvJXMfs6u0pYnEn/jPeTVQMK6uY9Egww5setjqwdQmwi1ea0/uoNw7QKPorCWZohFt4VB+HUy/ObjCDdxryIg/y0wXGMwFyftSyf0v/ESOVaUNOHg1aA0SQ0KOwx/oqBneMvSoxZc7SqvQaHcx3ZLg7I0FQgQ9799KuVGTfGNgWvzIMnHqMNnCyCLJMNoNQK9XA4Wkq+6tVuCUREehKj+szE6KlaSwgAPfb6JeGqIyBrjJK/wNw2yPaYB9wHia3A56M5r4OplAvdVjO1vrsc4I8LAy1zqqpo0yM1hfixHeLNDG6ufXaX/4mWxYpqL3hBHpPbnox49P3jj/wGgdZFaJe1JTer036xd0Xak5qCI6SV86xqAdAChv6sj7ESw0SU7w0leCi/08lfYfucRQHdzjO3JkA7lvHw0ouMCSCweP+ms5HlStT1HLlgQ/pkLQ0HiDkuoPtTY6fDW0UPlH3ebKJKJsiIlEwAnWQ1ExfQhfs1IRdbEO6sgyC7u2YqSye9WFoH3s0+d4P2X78UPcUsRitbiSflMds3+5ixk47wEAbwHOouv3l0AUb9zZIP32hh+8n3fJx3LXT4wqErJXRmufydvyJuKW5IkA+rD7B5y3hJGUFrf+je8x2WEZ93MMZZjKF3R4hY4E82J7y0z9znWEXqtnGce0dejOBkrf6CbP1VCh4ixhRvmOXO9yA0A2XQqeWYNfk1eUkRWlybRDBiE5SOOtjudxOpqC6Hv0XRqdL58/dsrEItVoppvb13l9MrZRKzOe/vtw9JP9aAkOa7ra6MbT/3YE4LlEJ5ticKWKe+rOGibg+N20Vx6Vg7J3byZG9+hIpULnZWH4Tq3LmlMA+oUfgAbbzPl3twbDuQozSElI95KSsXaBWevUxIWPQdY+4eolMlTtLwn+51SP6BWFEiioYy+r2Rza4OqKJPMbx7t0CZCtpMKxYQ5JCowbAH7J4Y3Eh3C04j1H/2a7qH3cVo01mg0KjVVR59qENmLLCnQ4LNMS3i2XshEK7QAIvi4D+egZPpMUywog3s+tqRiaGXIEMFp3rd3TuvLXVT9tpJGxjgQLGMKXmGL1MVjoN97by2NaOn0JoIbOQqeBIHTVbBYNON5DD3XP+rStPIfVbuHd+90TJpGh8BlfV0dLneK2wDMnndVGVvQLhvaQxu6sL3XsvtxmQzeFWUSHLeAlmTc9yNQKkXtOJWS9faewS8yotiXdJQ6EI1vpVOHgh46gljSllVDRx9qlH7i2QFU/dKpaQEbpAFUBI/eSUGbpgT2ORGcUGXXDWjQJQo+nCkQVnIMRUCP367os5Iw4Rb3LDvOi+/mwcBozzUa4WkjVcSIURKO3RTFCiY9j3O6C5MBS6Y0WbBooC0nOzhKxL8xMIIaM/tnyEzIdlABrz3f9XlCiQ0hh+C7/bNp14eUvnjcHWjBOSw8E7BjzeXkRQkpIuZSOriwZ8PiOLZxCkXFOQ4hbXa4Tu69lccJ9Hd0F1lxkg5QnAhhfx5WdcTkBH3SibBUMCLPb/cYypz6s4GGDMV5smYibldp//j9gbCEhqanpxLsoexOMik4SOt879z21iz+8V3wgG8CicQsmxcsqCc5QUqOZhnpO4qAFgzHF+noxN835P4xf5EsOcPvYWwtzK3WEYVGy5tuvxE5WZB246SGIDgeC4sMge0B4p70Tse4b6NjlPHW+90GmqnySqY83r0ilaew46qmwi4RzmOcPehbn4YPCoISjQ44RURV++dfU53vcKhkSj6cWuh75tdSSUNMysFwoP+lN2gGTwxOfrha9wWxDPpimhEBVrt6dcBIvdoUbCLTDQDZuUOVVhZP4sATqq8z7Ai0STnGxzKmAHG+3I+/tvrDN/OOTHwR6W5aWSRj+M5wmS5hfdvimlus2z4pE6RV+l6scSEX3XjFUVgbSuuufln4qZfmgBxNvIZmkPtMh4WHAtuqRVdgDOLksqdhjqc9jrNVpRsYL4L5fXaKhNXYNJfTorxbaoSpoqj6ZEp05xsc4y4Qryx7BRs3iYvuHRbCUsiCPmmGdUPXDn6H7woEjiz1YeriH6NPF5au5aVrtcw0DvEgLLKMuVq6QvzE1mu+x9AFhhIEE3jVvzGWs7x+IBGJ2hfG8Kb57q5sDsPmddrc0s2doavGt3j59SpKkbETAVxcSwwHbpAEsYTNPM1KhVl7EPpQp+gNotyPx7hI11xG47CrYE7+4xlCFpaDwvf9FWescjE9qNrcgCXvSeme0GAOo6QjsttWQcRguwWZb6OG1VPN2xZcfyUeEGLHhPkrziDDf4SHNaCcXXJ9CtFdyRMVueZNWqaoSKhpFI91MMLSXju3pGbSzJlM8FPf/oxZbRADvlZZCyb8fbb4mQVBZZ3GWV4hj4PCrLA1qQvEqs9XLsRnoal9WaSQhWRzLJmCurnGGRc6wxyAAejp0pAR70k0M8R+ziXphTbSz5jU2xp2cFe1EhegrqPqjFAtYWbYwsm9X969oYf76RSVpD5DfI8iDfFILBkfvnZaZtHikQ2tfNY1T0QOYafZ+dfiQjWZxqrDxXDWbc/jYZSbOzpgJ0HvC9wodOgTk5d5d9dmNrnM0LH8bvtI4zgktUZdf/DkYM10EF8yMhbFqvpMTi+TaLBUNd9aLSzSGAqu41xsKxsEYHFPhxozYZMPCafc4U5t8Ja7k34czb9pTsN2JFnwl8AmZSpI39KzBoEcD8fz0CAcio2KlaDIhPF8V0HkEbwc2c0mkpBazhOMI1d4cxnKG15nlJ+haP4D9g/H1z7jIEHS7enL9st+r19iJpqLFuJiKD2NT7LXyBzaAcFxIJ/fo4roeZSvHUyfgqUjSVcPiszEAuk4Fgqjxih+ln6TZW8b5sbDIvrB1Ul++c1B63XbFgHdVJTaRPzIXeh5f5u+QYvfa7pHyQV0ZUIv4SnfFMvTC0g0/fdaaBd9rcpxu/CBpbobKZgCIyVRDZGdPlZs8UGyu7+Hxb64E/k0YIIyG0d7ZSIcU1dOwyAQt25Ow5B4W/oUhgU+Gf+qB/Eqf+V11+GylEkiyGag2sSabnAwgaqTr549u7USX8FH6EnKLv1g9jl2zIU7C6GM3aeDn8kP+9aBM0Agrl165RV4/UHaXPnrBjs3YOHlrMK9jziNkwwt6+rC5FPPvSm2uVuOQouD4+Rk/8X2VoT+8bijB9PNpfsOsNhiSOVgntu7dzfzJItraFExs2ylPt0vanTgZJP3SIxPvZsgaDSBNmxIh0KPLS+EZkJ1Xy0gY8WVOZDbYF9v0GJta6+GUy7ek8lisYumJ1nyw90NF5n7L6H1aFMYqA/WI2COJA7pWaf9Ugf5pniETIJNyNXtonwZOLeCG380p2a2m5Fs4WDJIbVCtkJ77ah+h3HMvJJ0fzW8OXfnZDuzbWB935lP5zr2+vOc7CL44LjNt8p2deJJKd+d8n1mwKwxWxUjkxJRVlpIqwq1a+Sfeu1oNGDaOXyS/LVoiWAi4/RFFK77j8sVBWyTeqc13DCYWKdEbHTgEcIdtBewm3fvU99V8J4gYLJijdis2O/D+3FBz8kG/SwAXwjzKgO1TmXuA3syLPxxfnEUxttkUPpzQJgAzcN6o79tpHr3QWX3TVy4USKZJPX/G7/sFv7TB2RKaM9LvG8518UTl/oNK6/mqMpSOqsv0xRVzNjumgamqz/e3LG3e1lkrW5SquqlrDJIrN90AProjO2hsva2vAv1ZNPbHVfvH6K8KnMmDbXcZImS+YAXafdXLVILS/Q0MSKuRaLPQABT6AsH1SpBlkiSLXyhT/gT5IbfD6Z1Jx0n7l33o2uGW4lgd8BRn8WUeEHBHEn2SCXVQwlREQtvN7iSC2y8qSngF4ytc3vgOucrGccauebyUn9sdKmkhMom+XHRGLg4yr7NW/ZAq8UDCTjimw0unj204NYoihtZTNdXwgmCpqzA6Y4a3S/braI7FEXELgpjVSnB+dqkyFq3Tny2G8lAz1OtN0TZdE3wgbqL8XtsE5Ut1NayTqmPNmEhJVC0f6ZfMop0HP5VawTxA+lq1XoeRAoIGH0ojuV+9O13sh2V2zoxj5jVyNGuZDtqZVlEeSIRI05PVi7nZfKw+EuT5YTkdX/qnx/AmQXABJR8mEbt5A8Oab2RqMdG+P0zvDI0gODnGDSO2w4ZOrD1zi5LnYaIljibbOMhpDWcwsd6Ry5eUmiLQ24OpaErO6a3/sYLybm9xOJLqfn7DNg/5SKBxEfKNyyUYP4KtkSMQI5Xo7dHcIhqH4l3CRK/gB7WtFU6bj0mReNJIitL8grYbUyZpqDuMDT5s5WQsWjOEmRSbMiH7HIkEIPvRu0WxMnRCJKjGFWdlKGqK96T7jlsEHCjsPjk/9VEQ4W5qB2tRAFGJ5YGgbmyYxqxGxduvkNdd3IZKcIbvtEtH4X7aHeyV4Dcn4wkEzUNRRhISM51Av5I1mwi2lj3DP8d6K9iFzNVDCSb+eb9pBu+SEqYrvFC8WKSi8OcZDj50KV871120hgz6n6OZy1KOh8OzKNuCKFt9mVlUfJKzD9gcuL53q+oTHGGIKFz4+4/zLC13N3l3y4Fn9dzM02uGyBGoJXmF3jrwW9OguOsh1FVykE1suM6kC/e005VRngkgcn29tixbfGSx7k8JzTId+5wTXE1HgKXCtGlwA7L6FxS+RUGGP2az1Em91D7THACjjqlVdoDOltQ7Yb4S8n4kG/m/CvtFfQB0e/e/JMgICLGKds6v5THENB7WYOdJ0P5s3GQzdbeXjUAG5Y2WCUBs5LZ6xDZzv1L7jfUHqBbmnHW7U4g+UTYB/tW7B0Ya0JAbpzWFSoVQH6CbY6q9fM8ccelwWdxeWdjZm+TcmBAHpje+emw8T5mUgl7Omvks7D2xk04/HjynzVyBN2dI3dBgxTkB1keL9tMN0WgyjY0ddKI8pigHP9lOa8hb7F2bZIa/FqS6JJPPHnlyPbVl+weIG7j4ocmWH/OkvaT4qtcbnafk2ocwOkjSqUob66ehit1UDMwKXreD2R92MZugTHNe/PWAZesANg9eBbm2p+4kqK52j8MW3AhqaffDN+kK195DUM4FLVYm8BQhOF+OWoM5tTD8LImCNRenutbU6qRxpaMDXCBU37/K3Y7eobcg/IaZaBuw44FteI67Hdgufk5VqCDjlK7jDBUtVq07hpPI9ymWW/m3nNLQlusNGDSBNYXOUBDRWNnHira/1eo9GEwVgpXn2tG1PUUxT15p/fbfGXCvpsj0QlzwErC0ge/Oqlsh7E0QhpqDAcvlBJOiXDD/bv01SkM269rmghWHJPUbmpq4trj7H6cCMXMIwWgOLaTXR0w3tamzJpReC8FXDNwkxSCbmg/ag17JdPyptz7mR3k6KvXor6tFCfEv85TW7CDWLEap1AC12Ym+LK9/CxdKPnXz9Qz4xNXGn3sG1wAfthifQfjDyiCnLo2uhuMzI9yKxH4PUTt52mReMLmnHFrrLpDYcPC+cU7ge55guYhGv/ANB92YzoXrI+Hs6gdXnnfE8GGhfydGwvKBKCtpDecGnu41Mz28j9/LTVtSV9WZEoxANMgPGo4BDbY2p69ixYGQWATdyg9TRDAK7f/Lrlubat60yuVZ9wcwqZ7NBP71mX6NEgdvfK1EgMnkZzsDQl/wWDHdAoOYCo4pKwY5I/V26cKTO4aMYcV/YDdgglOtas2KtIXBJAcgotsV4YfF+CDN4T5WdX808VdXh3/UXLrAdcMDF3QIXj1HyUHIOkXBH7DXICbJt9eNiowRXiuB0d1J/FqjPFe2IlNdXnwFwpRusB5PLSv0Lk/AdI1gQmao8wwLmnoh/L9riMbMMsWAOI+5B71d+lGTKlxx4hQn4ixRfedyZUUsRcpGrgAS1XqCKzggl0/LFuyQpe9BsgvZGkEHQ4ELkl6bcLtiHZ+7uFxmRjnV7v8PP1Whug1igIT3OTMnmb/dGJPuGKY5fRdvWoatxfNU3ABi+fY7eHiPqC0gQDpAC19twVfWBtBur+ST+y7fzmSE5Q0C3mcp8/31XIdqm7sEZJHtFnXBgaTyG+fWRGAY70K10IBvKH2TE6IMzm1k92/Cn2payTupKTtojgP3uaWIgFVgV0lD0WGR0PanqiKtrBFwqznvb/rz2PgpSjWd2BESLQpxY+6tmKXZnjvY9xfR12CQ8o/aKz1t+XxCSzy0uE5f/kaFUCrwxjL8gT7SEUJshp//5/yvPFJHgJlgsvXp+gRQCSzz+vS6rl3BhMsbj/HzwJYz8GsWppOQDGVswlOHEaFE/qhImhDrt2DUfNxtt21GW7KwJRn9/mtYIjlnnwgESPEpwoLyTru3SsVGzRxnZG6x+BiseUs57lTdb3H8KG7UPeH1SSjy9wZHELnar9x5cOtOR7lOvyjWm4Ab18Q+qoMxxLCFit0V8SmOu7AU8XGY3eSXb6Ly+kaQmDkRlOstgmcj+rD34KNz7LTvLL0O1Z9J/nCjp+1flOFgtbd7Yg0t5eNrPuppxYxJfSpnJRNL4S3YTffnV+x+zVsuioseET/On2wNi/TnL2rAQIKswi7Er3Sv48D/+PLsa2WJOSk6DqcCLmusILDiz0FwKEhMewrxtNyM2IAE0/6hiopIQoUgC6U8CLirhWbfVibSnCGZlF5uywIcaUlcEaYP/evokbi1NSquO62XNnWR4+fB3M1N7LaI5pwdHYOKEjg9OaSiTtEDypKGOVxZhdQS0jEvZ46foNS4SBpwZfPn60p6pQldNUmimhWeU5LUnEpZYjPJU6hmAsh4AKaLFfJANrZ9ou428yoEIFuiY9UgOYkqtSUocWxyijxK+NTtuDdbh7NJcyLIl6CUBWQjZiL34Bk0Qe3vmT9tpIKus3r5CvEdEu5Va2Wxm8CQJT9bESzuFBeH0QIRybKFAUVqNa9tCXukd1jwLXYKWsuMuFda8R1UjVG2cvAZ+R3lBV+nLksL4Ti6lubX3hKFcSyFsG5rK9pJt5nlSGIkBLP/HFqLL/KX0S96NdOo4CS+GYPBk+lBZxz6Yie12vvUj8l4t1ik/5PmvbLOTPCcaoPeZ7APUQIKIcxcNUDin3R1okbeAUGwt7Ja3G0ntQokBhlajisyXeqbfPLrTTKpTauclKp+DGdyBsbzFHEYtIqZnlLe5wjluF/UID6EgwWPGj0FVKM59Jom3+0Y1QTb+IKqHZv/0FIEEuVItlJHSixdza2w0UN80Hyc/eUGv6SBybC/EEs9cOcLBR1eeQXXe7p7hfIhtxxBrGhk9n7jom/4LXF125WzPmMCUiNyE8iO7sVSmRf/iSNFBveZWGPeCirfJ8a43fk5jCfA3NPEJyMAamu3Q5im0DKo8aonWXtye9iE8vraixlVTAGSXFMjP3+XiOE9jrnXTDzARnt7+9gvHctQpaAI0za6N7bq9R1lb55jILwmx4Ih4OA0K1/Xx7B9jytPFBRhEO8xqXLhxotsIRjnGRvnkMK/KJ1YhE9T2mNmclLYgMSn+7dzik8BzoHt+EcXstV8yNpTspqsnS96ATq3A66NbF449w9JqViBt4gWi7yVzt3kR4XSJ8iEB5anMqG+EsSyrMQVv0sMeEysGx+yYs6G2xPJw3zqTq4RzDQXPhYra/VMlt7E8zzl4D7L3HS3kkWf4ZkmFmnjcENPQdkmohl6p/gqkOg+8McyzNxxb5Fl19DsSr3MTuSMqhSKDn95ibzYCEdrZXJiKaqu7BFBuju+jSObOPchog2IsE/u/3U/UK2mntvSnD0qNkPYoRTskBnLJ3NJamL0V4sEbryX8NMr7MKMJ0+h2+xMKY4KERpvUrd0c6ABXWHqLdY1QTugC/5dhdoLy3+KwgG5FnL0MZw6qvOvHkKQRoQrcKLuwUld15s05QxurH67A9eAr02a/vUWNBIgP6vOa69ZZuZKElWttIerRDGIAkZ54fw7HBctSZtfspPxaliwbOEH/Laxot3ZQonzvXknSVodzZHA1Jw7BcNRsYvl+KJ0Y6pMRPpIbaN/QSuHtnjUoej+vlVhq5021xMUPKxCK/D8rSRbOmduHG85/JrIimgo5wXWP83lLvRaxwCxeTGVt44fTUqsfUARmQcS3f5DbHR9SZ4nJYIEvcCjIqLezJ3I6S7xBop57j3ZyMQX0Xxr5mc6IUmrlOXM9fJG5iDZQQ9rWsGZ0Y26GzTAEsD6pjPuDa1XAT1MRpxyZ8zN53sl1YEV0E0EHvZqcnBnqMTXRh6zC9PwDXEk3OHs2zLLIjBhY5+7lDxp1X0qcm8XtWorat33mUx+kEDDgaDUdpclQq/ZM6mMYoF433nKbCKDxCozugSPVaRjNPosMDy8FujvIJSb763XuBGBIYLS9x+HZhYiUa9xod0xKV9aRt7yczWWlLgfK8qn4fULHMBSP48m/wTWfDBdTH8uDAKt5WM033+2bCpxDhmZtE+d7XP65yBTOf9/EWaCG+Gs9/5kVbWS0JlfoDH6Si2tVCzCRGfV0XZAUWfXOMJ5F9dkMagbwaeqVqqbVONDQGg8zID5MUV7IkazdAz4JLOXsn1RuZnoZNIGV2Na15+dRKYUAmXFmkWBJpPMBwT8N4bd8VZwBnhm3WzH9S0sbpoP0sgf2OmPvQ6smMyfkVK+OLjXYubmtioAhdwDb5/pLRg3PGwfHEz6v9OOe4AK8iw2cma49tV44In8Rc9jGcqSQlFXPdlC8366ke4U/ITFy0/SQBl1vWvGk40KycwWGaLf8cCtEi/4X2W8961i6lYnpfNQhGcQyC8s2oIOW+Pw545Thq3ZBEyNC8YDr/pzCEmBI8U3A4IiQJoHiD9kUMNd8wfzysC2Kqc4OGeWYsJxmDev4Jn4HV+vqpgN6xxSEMABhRMdTteHiJAgnQEX9BR2V1sNqh5EcMvQNYYa5+bblQn7Rli1UFCtQkP6ECmGkxmPNkg2CGS2mmf0/WEuTZSyPMtbbrnftPgleOmJ3jSm0m1EU9fQHQo1NZti+KczpJ8mSYIVtXzXh4rNJcL3Fm7Bbftpjmj5UnuDpPk8HvqKOj2DGJyk4R0Md1x7umiH0DTOXaLwO0EI94k7n6R8nfqiwekgUQZ1rRek0HViM5YN0JLWp4f4NRE8ErcGNSHZd58+9Kx8lmkc9ogfQmX0rX1kB8QQzNbH+eVDee0jOQNUgQcew3y+0QbifXrtLHXDIxsqsej41Kz7vfcQRE1zUnY2phYNILK8a657zyHNMzPiRhxs28s1JX2kiCMEloubOXnc8BzU+n7LM9wztf63eFWN/eWHXVivSdCWg5DfWsk2CF8aFJrOP277QEPdkWlOlewCVEkLjyd5wUn9ZzaKOJKnDQDLfliiRLTKlU8TOeQj8jOU8FfpM9tayJTDpxw6sVlZuJRAILfxn+QAGIB/W1FGDjuuVu62hFDBdvzVSfge95Ebf9pclp0GrpV3S+gwBWn5J7aGiim/fRyIN7YVVXJsnAnVeq90vDdAV0XearTqjT2Ck/AMkBW6T/ls/6VUVnFWs01wxkahKR0tRwyLRKgHefm3RWie/pTVQpUMZw+/7ozQSW+7vuZd8lsvT1iX5rwlpiaFnOnDbHsr1As6vLETd5HVbcBCGbJHcS7ax9Byd50jdYyagUtjAaHYX8ryyuR/bDkw1o4j8+hXMfbzy+CVmgrfRDyl4dn+5LxrqRAXLoDKpQREAHqdLSsVSJh1s8KnZ/SsUVq27cq+O6LMSBmhT4X3E750rmWwCsoCre6bT//oFWYALjp2SbcxnULBaTvnYDHtfEbO1m/3c9nJk8ZO5KHQTV88ivTWN/S2EXwmisTPdcupMrvI8e48QZdkZu9WHyKron7MKhGFJw6Z0KZ3tleVrvvJo89siUwByPY+Hs4gkKPBQbLQOaedcv/xeM+Ih8rl1eHEC/C65xWVciToVqSGp9HfbhVzFSrO6kBnv7mJwnRLvMEwqiNankVdJJMw4icU3lKyw/ecNSWIUddqlbThYMiq8nHjRRufs+28cq0OI9zhpvxFvFgSZE/eAYvm0x+9lZO+EH9NkBngaqU1NMYhdombNuy3awUN9p0mJQ//e9L65YbShgoc+ZUlNy+c6F6gDEHXV0JrzevPIZFAe2RyRa2dNqzLvihAAMCszYueqszzXRkSyobx5+LTLK2V3lfg3wbS9DzP3QW7VHdHbjZcttQRvtjrGveJnNn2DE2ZDIbvkCrT0H8RzbGDdmIq4P1ey+hoY/W6NuZKOz4dv4HUNznxdKV1Wf3MvqUv35r2jTKvpPWBUWNm5fytX/QJwp6qkIOsSx7Y67BSCbCDVLM8/VcMG+T0j+INrgL9sfT1ICtACH8BI0G6ViUZPVzzCmQHW2oVIwZjAoFl6+meO/pD8teO1E+1y03mCpYfW9S8qhtH2GhlFlebPf4NbezVv9xbXKWz0xezRNQWqUqtYRTUbuzK7KTvjG4rQHfzBpVmK4wDLnSIwdSzTSk1fPNeY0WOpPZTLlvQ59xwgfFrb326vT2hS1JAZ9E6sujFtKTiJ7bxI6o4cBhDaX+adXREThhR+MwA4TqD7rga/o9iY7d6TVRe14CS2S3iSQsD0R6ApnhG/2Wa0A0AY2NtWTjmabdKU+KgIRDP9RQYVjXiF1qC+xyNVG03I9vpmEpY/G/zC4nLOKgXAZ/uTikHI9Afbkhfgfgo9arWbix5eH7WUo9RQygDzwCnVSjbXc7MihEufVj6WGbK963pw8VjY3RS8IH1cy2yZbIcKLO5CgAUcXJfF2+McnDLKtXxyZaf7SPA6KJq+zF2NHyfoeTOwHhGqNcnHVr1hT73pcoyXyfvCYBnG1Bp/aR9t8hoI7CXM3UZOisWGA1SHZ2jf7k9GlRnp3mF/c1AV+JjvUsnZrsybEOQJg/dn/9eJkyykQHjbF56zgcPX6DdMG03WKUMlYz+uOZ+5DZy9E9MZOZ9GMoLFdrIPPQQLjv+GlCMpoyHPXkzIODjHAID2PrnaRpqWVHh0rnieDILKq+Emrd5RnjgE9pDUXWTmHaKuqqYlcgEz4zbi46dbWrAAFBjsQq1rLHIiPJEcwFLCOY4JNlXRXQJqCUKXk2d1RSBGzDP6HDSpo863BhVRFFF6uIpjQV7j5ebFe3UkkO/+coIo2BTAcgBqOtQ134s9a4QJvofuqBYMGOBMsWZ+sn/2AOxDx6SfAnDFGw==";
3018
+
3019
+ // src/rendering/post-effects/n8-ssao/DepthDownSample.ts
3020
+ import { Matrix4 as Matrix42, Uniform as Uniform3, Vector2 as Vector22 } from "three";
3021
+ var DepthDownSample = {
3022
+ uniforms: {
3023
+ sceneDepth: new Uniform3(null),
3024
+ resolution: new Uniform3(new Vector22()),
3025
+ near: new Uniform3(0.1),
3026
+ far: new Uniform3(1e3),
3027
+ viewMatrixInv: new Uniform3(new Matrix42()),
3028
+ projectionMatrixInv: new Uniform3(new Matrix42()),
3029
+ logDepth: new Uniform3(false)
3030
+ },
3031
+ depthWrite: false,
3032
+ depthTest: false,
3033
+ vertexShader: (
3034
+ /* glsl */
3035
+ `
3036
+ varying vec2 vUv;
3037
+ void main(void) {
3038
+ vUv = uv;
3039
+ gl_Position = vec4(position, 1);
3040
+ }`
3041
+ ),
3042
+ fragmentShader: (
3043
+ /* glsl */
3044
+ `
3045
+ uniform highp sampler2D sceneDepth;
3046
+ uniform vec2 resolution;
3047
+ uniform float near;
3048
+ uniform float far;
3049
+ uniform bool logDepth;
3050
+ uniform mat4 viewMatrixInv;
3051
+ uniform mat4 projectionMatrixInv;
3052
+ varying vec2 vUv;
3053
+
3054
+ layout(location = 1) out vec4 gNormal;
3055
+
3056
+ vec3 getWorldPosLog(vec3 posS) {
3057
+ vec2 uv = posS.xy;
3058
+ float z = posS.z;
3059
+ float nearZ = near;
3060
+ float farZ = far;
3061
+ float depth = pow(2.0, z * log2(farZ + 1.0)) - 1.0;
3062
+ float a = farZ / (farZ - nearZ);
3063
+ float b = farZ * nearZ / (nearZ - farZ);
3064
+ float linDepth = a + b / depth;
3065
+ vec4 clipVec = vec4(uv, linDepth, 1.0) * 2.0 - 1.0;
3066
+ vec4 wpos = projectionMatrixInv * clipVec;
3067
+ return wpos.xyz / wpos.w;
3068
+ }
3069
+
3070
+ vec3 getWorldPos(float depth, vec2 coord) {
3071
+ if (logDepth) {
3072
+ return getWorldPosLog(vec3(coord, depth));
3073
+ }
3074
+ float z = depth * 2.0 - 1.0;
3075
+ vec4 clipSpacePosition = vec4(coord * 2.0 - 1.0, z, 1.0);
3076
+ vec4 viewSpacePosition = projectionMatrixInv * clipSpacePosition;
3077
+
3078
+ vec4 worldSpacePosition = viewSpacePosition;
3079
+ worldSpacePosition.xyz /= worldSpacePosition.w;
3080
+
3081
+ return worldSpacePosition.xyz;
3082
+ }
3083
+
3084
+ vec3 computeNormal(vec3 worldPos, vec2 vUv) {
3085
+ ivec2 p = ivec2(vUv * resolution);
3086
+ float c0 = texelFetch(sceneDepth, p, 0).x;
3087
+ float l2 = texelFetch(sceneDepth, p - ivec2(2, 0), 0).x;
3088
+ float l1 = texelFetch(sceneDepth, p - ivec2(1, 0), 0).x;
3089
+ float r1 = texelFetch(sceneDepth, p + ivec2(1, 0), 0).x;
3090
+ float r2 = texelFetch(sceneDepth, p + ivec2(2, 0), 0).x;
3091
+ float b2 = texelFetch(sceneDepth, p - ivec2(0, 2), 0).x;
3092
+ float b1 = texelFetch(sceneDepth, p - ivec2(0, 1), 0).x;
3093
+ float t1 = texelFetch(sceneDepth, p + ivec2(0, 1), 0).x;
3094
+ float t2 = texelFetch(sceneDepth, p + ivec2(0, 2), 0).x;
3095
+ float dl = abs((2.0 * l1 - l2) - c0);
3096
+ float dr = abs((2.0 * r1 - r2) - c0);
3097
+ float db = abs((2.0 * b1 - b2) - c0);
3098
+ float dt = abs((2.0 * t1 - t2) - c0);
3099
+ vec3 ce = getWorldPos(c0, vUv).xyz;
3100
+ vec3 dpdx = (
3101
+ (dl < dr)
3102
+ ? ce - getWorldPos(l1, (vUv - vec2(1.0 / resolution.x, 0.0))).xyz
3103
+ : -ce + getWorldPos(r1, (vUv + vec2(1.0 / resolution.x, 0.0))).xyz
3104
+ );
3105
+ vec3 dpdy = (
3106
+ (db < dt)
3107
+ ? ce - getWorldPos(b1, (vUv - vec2(0.0, 1.0 / resolution.y))).xyz
3108
+ : -ce + getWorldPos(t1, (vUv + vec2(0.0, 1.0 / resolution.y))).xyz
3109
+ );
3110
+ return normalize(cross(dpdx, dpdy));
3111
+ }
3112
+
3113
+ void main(void) {
3114
+ vec2 uv = vUv - vec2(0.5) / resolution;
3115
+ vec2 pixelSize = vec2(1.0) / resolution;
3116
+ vec2[] uvSamples = vec2[4](
3117
+ uv,
3118
+ uv + vec2(pixelSize.x, 0.0),
3119
+ uv + vec2(0.0, pixelSize.y),
3120
+ uv + pixelSize
3121
+ );
3122
+ float depth00 = texture2D(sceneDepth, uvSamples[0]).r;
3123
+ float depth10 = texture2D(sceneDepth, uvSamples[1]).r;
3124
+ float depth01 = texture2D(sceneDepth, uvSamples[2]).r;
3125
+ float depth11 = texture2D(sceneDepth, uvSamples[3]).r;
3126
+ float minDepth = min(min(depth00, depth10), min(depth01, depth11));
3127
+ float maxDepth = max(max(depth00, depth10), max(depth01, depth11));
3128
+ float targetDepth = minDepth;
3129
+
3130
+ if (mod(gl_FragCoord.x + gl_FragCoord.y, 2.0) > 0.5) {
3131
+ targetDepth = maxDepth;
3132
+ }
3133
+
3134
+ int chosenIndex = 0;
3135
+ float[] samples = float[4](depth00, depth10, depth01, depth11);
3136
+
3137
+ for(int i = 0; i < 4; ++i) {
3138
+ if (samples[i] == targetDepth) {
3139
+ chosenIndex = i;
3140
+ break;
3141
+ }
3142
+ }
3143
+
3144
+ gl_FragColor = vec4(samples[chosenIndex], 0.0, 0.0, 1.0);
3145
+ gNormal = vec4(
3146
+ computeNormal(
3147
+ getWorldPos(samples[chosenIndex], uvSamples[chosenIndex]), uvSamples[chosenIndex]
3148
+ ),
3149
+ 0.0
3150
+ );
3151
+ }`
3152
+ )
3153
+ };
3154
+
3155
+ // src/rendering/post-effects/n8-ssao/EffectCompositer.ts
3156
+ import { Matrix4 as Matrix43, Uniform as Uniform4, Vector2 as Vector23, Vector3 as Vector310 } from "three";
3157
+ var EffectCompositer = {
3158
+ uniforms: {
3159
+ sceneDiffuse: new Uniform4(null),
3160
+ sceneDepth: new Uniform4(null),
3161
+ tDiffuse: new Uniform4(null),
3162
+ projMat: new Uniform4(new Matrix43()),
3163
+ viewMat: new Uniform4(new Matrix43()),
3164
+ projectionMatrixInv: new Uniform4(new Matrix43()),
3165
+ viewMatrixInv: new Uniform4(new Matrix43()),
3166
+ cameraPos: new Uniform4(new Vector310()),
3167
+ resolution: new Uniform4(new Vector23()),
3168
+ color: new Uniform4(new Vector310()),
3169
+ blueNoise: new Uniform4(null),
3170
+ downsampledDepth: new Uniform4(null),
3171
+ time: new Uniform4(0),
3172
+ intensity: new Uniform4(10),
3173
+ renderMode: new Uniform4(0),
3174
+ gammaCorrection: new Uniform4(false),
3175
+ logDepth: new Uniform4(false),
3176
+ ortho: new Uniform4(false),
3177
+ near: new Uniform4(0.1),
3178
+ far: new Uniform4(1e3),
3179
+ screenSpaceRadius: new Uniform4(false),
3180
+ radius: new Uniform4(0),
3181
+ distanceFalloff: new Uniform4(1),
3182
+ fog: new Uniform4(false),
3183
+ fogExp: new Uniform4(false),
3184
+ fogDensity: new Uniform4(0),
3185
+ fogNear: new Uniform4(Infinity),
3186
+ fogFar: new Uniform4(Infinity),
3187
+ colorMultiply: new Uniform4(true)
3188
+ },
3189
+ depthWrite: false,
3190
+ depthTest: false,
3191
+ vertexShader: (
3192
+ /* glsl */
3193
+ `
3194
+ varying vec2 vUv;
3195
+ void main(void) {
3196
+ vUv = uv;
3197
+ gl_Position = vec4(position, 1);
3198
+ }`
3199
+ ),
3200
+ fragmentShader: (
3201
+ /* glsl */
3202
+ `
3203
+ uniform sampler2D sceneDiffuse;
3204
+ uniform highp sampler2D sceneDepth;
3205
+ uniform highp sampler2D downsampledDepth;
3206
+ uniform sampler2D tDiffuse;
3207
+ uniform sampler2D blueNoise;
3208
+ uniform vec2 resolution;
3209
+ uniform vec3 color;
3210
+ uniform mat4 projectionMatrixInv;
3211
+ uniform mat4 viewMatrixInv;
3212
+ uniform float intensity;
3213
+ uniform float renderMode;
3214
+ uniform float near;
3215
+ uniform float far;
3216
+ uniform bool gammaCorrection;
3217
+ uniform bool logDepth;
3218
+ uniform bool ortho;
3219
+ uniform bool screenSpaceRadius;
3220
+ uniform bool fog;
3221
+ uniform bool fogExp;
3222
+ uniform bool colorMultiply;
3223
+ uniform float fogDensity;
3224
+ uniform float fogNear;
3225
+ uniform float fogFar;
3226
+ uniform float radius;
3227
+ uniform float distanceFalloff;
3228
+ uniform vec3 cameraPos;
3229
+ varying vec2 vUv;
3230
+
3231
+ highp float linearize_depth(highp float d, highp float zNear,highp float zFar) {
3232
+ return (zFar * zNear) / (zFar - d * (zFar - zNear));
3233
+ }
3234
+
3235
+ highp float linearize_depth_ortho(highp float d, highp float nearZ, highp float farZ) {
3236
+ return nearZ + (farZ - nearZ) * d;
3237
+ }
3238
+
3239
+ highp float linearize_depth_log(highp float d, highp float nearZ,highp float farZ) {
3240
+ float depth = pow(2.0, d * log2(farZ + 1.0)) - 1.0;
3241
+ float a = farZ / (farZ - nearZ);
3242
+ float b = farZ * nearZ / (nearZ - farZ);
3243
+ float linDepth = a + b / depth;
3244
+ return (
3245
+ ortho
3246
+ ? linearize_depth_ortho(linDepth, nearZ, farZ)
3247
+ : linearize_depth(linDepth, nearZ, farZ)
3248
+ );
3249
+ }
3250
+
3251
+ vec3 getWorldPosLog(vec3 posS) {
3252
+ vec2 uv = posS.xy;
3253
+ float z = posS.z;
3254
+ float nearZ =near;
3255
+ float farZ = far;
3256
+ float depth = pow(2.0, z * log2(farZ + 1.0)) - 1.0;
3257
+ float a = farZ / (farZ - nearZ);
3258
+ float b = farZ * nearZ / (nearZ - farZ);
3259
+ float linDepth = a + b / depth;
3260
+ vec4 clipVec = vec4(uv, linDepth, 1.0) * 2.0 - 1.0;
3261
+ vec4 wpos = projectionMatrixInv * clipVec;
3262
+ return wpos.xyz / wpos.w;
3263
+ }
3264
+
3265
+ vec3 getWorldPos(float depth, vec2 coord) {
3266
+ #ifdef LOGDEPTH
3267
+ return getWorldPosLog(vec3(coord, depth));
3268
+ #endif
3269
+
3270
+ float z = depth * 2.0 - 1.0;
3271
+ vec4 clipSpacePosition = vec4(coord * 2.0 - 1.0, z, 1.0);
3272
+ vec4 viewSpacePosition = projectionMatrixInv * clipSpacePosition;
3273
+
3274
+ vec4 worldSpacePosition = viewSpacePosition;
3275
+ worldSpacePosition.xyz /= worldSpacePosition.w;
3276
+ return worldSpacePosition.xyz;
3277
+ }
3278
+
3279
+ vec3 computeNormal(vec3 worldPos, vec2 vUv) {
3280
+ ivec2 p = ivec2(vUv * resolution);
3281
+ float c0 = texelFetch(sceneDepth, p, 0).x;
3282
+ float l2 = texelFetch(sceneDepth, p - ivec2(2, 0), 0).x;
3283
+ float l1 = texelFetch(sceneDepth, p - ivec2(1, 0), 0).x;
3284
+ float r1 = texelFetch(sceneDepth, p + ivec2(1, 0), 0).x;
3285
+ float r2 = texelFetch(sceneDepth, p + ivec2(2, 0), 0).x;
3286
+ float b2 = texelFetch(sceneDepth, p - ivec2(0, 2), 0).x;
3287
+ float b1 = texelFetch(sceneDepth, p - ivec2(0, 1), 0).x;
3288
+ float t1 = texelFetch(sceneDepth, p + ivec2(0, 1), 0).x;
3289
+ float t2 = texelFetch(sceneDepth, p + ivec2(0, 2), 0).x;
3290
+ float dl = abs((2.0 * l1 - l2) - c0);
3291
+ float dr = abs((2.0 * r1 - r2) - c0);
3292
+ float db = abs((2.0 * b1 - b2) - c0);
3293
+ float dt = abs((2.0 * t1 - t2) - c0);
3294
+ vec3 ce = getWorldPos(c0, vUv).xyz;
3295
+ vec3 dpdx = (
3296
+ (dl < dr)
3297
+ ? ce - getWorldPos(l1, (vUv - vec2(1.0 / resolution.x, 0.0))).xyz
3298
+ : -ce + getWorldPos(r1, (vUv + vec2(1.0 / resolution.x, 0.0))).xyz
3299
+ );
3300
+ vec3 dpdy = (
3301
+ (db < dt)
3302
+ ? ce - getWorldPos(b1, (vUv - vec2(0.0, 1.0 / resolution.y))).xyz
3303
+ : -ce + getWorldPos(t1, (vUv + vec2(0.0, 1.0 / resolution.y))).xyz
3304
+ );
3305
+ return normalize(cross(dpdx, dpdy));
3306
+ }
3307
+
3308
+ #include <common>
3309
+ #include <dithering_pars_fragment>
3310
+
3311
+ void main(void) {
3312
+ vec4 sceneTexel = texture2D(sceneDiffuse, vUv);
3313
+ float depth = texture2D(sceneDepth, vUv).x;
3314
+
3315
+ #ifdef HALFRES
3316
+ vec4 texel;
3317
+ if (depth == 1.0) {
3318
+ texel = vec4(0.0, 0.0, 0.0, 1.0);
3319
+ } else {
3320
+ vec3 worldPos = getWorldPos(depth, vUv);
3321
+ vec3 normal = computeNormal(getWorldPos(depth, vUv), vUv);
3322
+
3323
+ float totalWeight = 0.0;
3324
+ float radiusToUse = (
3325
+ screenSpaceRadius
3326
+ ? distance(worldPos, getWorldPos(depth, vUv + vec2(radius, 0.0) / resolution))
3327
+ : radius
3328
+ );
3329
+ float distanceFalloffToUse = (
3330
+ screenSpaceRadius
3331
+ ? radiusToUse * distanceFalloff
3332
+ : distanceFalloff
3333
+ );
3334
+ for(float x = -1.0; x <= 1.0; x++) {
3335
+ for(float y = -1.0; y <= 1.0; y++) {
3336
+ vec2 offset = vec2(x, y);
3337
+ ivec2 p = ivec2((vUv * resolution * 0.5) + offset);
3338
+ vec2 pUv = vec2(p) / (resolution * 0.5);
3339
+ float sampleDepth = texelFetch(downsampledDepth,p, 0).x;
3340
+ vec4 sampleInfo = texelFetch(tDiffuse, p, 0);
3341
+ vec3 normalSample = sampleInfo.xyz * 2.0 - 1.0;
3342
+ vec3 worldPosSample = getWorldPos(sampleDepth, pUv);
3343
+ float tangentPlaneDist = abs(dot(worldPos - worldPosSample, normal));
3344
+ float rangeCheck = exp(
3345
+ -1.0 * tangentPlaneDist * (1.0 / distanceFalloffToUse)) * max(dot(normal, normalSample),
3346
+ 0.0
3347
+ );
3348
+ float weight = rangeCheck;
3349
+ totalWeight += weight;
3350
+ texel += sampleInfo * weight;
3351
+ }
3352
+ }
3353
+ if (totalWeight == 0.0) {
3354
+ texel = texture2D(tDiffuse, vUv);
3355
+ } else {
3356
+ texel /= totalWeight;
3357
+ }
3358
+ }
3359
+ #else
3360
+ vec4 texel = texture2D(tDiffuse, vUv);
3361
+ #endif
3362
+
3363
+ #ifdef LOGDEPTH
3364
+ texel.a = clamp(texel.a, 0.0, 1.0);
3365
+ if (texel.a == 0.0) {
3366
+ texel.a = 1.0;
3367
+ }
3368
+ #endif
3369
+
3370
+ float finalAo = pow(texel.a, intensity);
3371
+ float fogFactor;
3372
+ float fogDepth = distance(cameraPos, getWorldPos(depth, vUv));
3373
+
3374
+ if (fog) {
3375
+ if (fogExp) {
3376
+ fogFactor = 1.0 - exp(-fogDensity * fogDensity * fogDepth * fogDepth);
3377
+ } else {
3378
+ fogFactor = smoothstep(fogNear, fogFar, fogDepth);
3379
+ }
3380
+ }
3381
+
3382
+ finalAo = mix(finalAo, 1.0, fogFactor);
3383
+ vec3 aoApplied = color * mix(vec3(1.0), sceneTexel.rgb, float(colorMultiply));
3384
+ if (renderMode == 0.0) {
3385
+ gl_FragColor = vec4( mix(sceneTexel.rgb, aoApplied, 1.0 - finalAo), sceneTexel.a);
3386
+ } else if (renderMode == 1.0) {
3387
+ gl_FragColor = vec4( mix(vec3(1.0), aoApplied, 1.0 - finalAo), sceneTexel.a);
3388
+ } else if (renderMode == 2.0) {
3389
+ gl_FragColor = vec4( sceneTexel.rgb, sceneTexel.a);
3390
+ } else if (renderMode == 3.0) {
3391
+ if (vUv.x < 0.5) {
3392
+ gl_FragColor = vec4( sceneTexel.rgb, sceneTexel.a);
3393
+ } else if (abs(vUv.x - 0.5) < 1.0 / resolution.x) {
3394
+ gl_FragColor = vec4(1.0);
3395
+ } else {
3396
+ gl_FragColor = vec4(mix(sceneTexel.rgb, aoApplied, 1.0 - finalAo), sceneTexel.a);
3397
+ }
3398
+ } else if (renderMode == 4.0) {
3399
+ if (vUv.x < 0.5) {
3400
+ gl_FragColor = vec4( sceneTexel.rgb, sceneTexel.a);
3401
+ } else if (abs(vUv.x - 0.5) < 1.0 / resolution.x) {
3402
+ gl_FragColor = vec4(1.0);
3403
+ } else {
3404
+ gl_FragColor = vec4(mix(vec3(1.0), aoApplied, 1.0 - finalAo), sceneTexel.a);
3405
+ }
3406
+ }
3407
+
3408
+ #include <dithering_fragment>
3409
+
3410
+ if (gammaCorrection) {
3411
+ gl_FragColor = LinearTosRGB(gl_FragColor);
3412
+ }
3413
+ }
3414
+ `
3415
+ )
3416
+ };
3417
+
3418
+ // src/rendering/post-effects/n8-ssao/EffectShader.ts
3419
+ import { Matrix4 as Matrix44, Uniform as Uniform5, Vector2 as Vector24, Vector3 as Vector311 } from "three";
3420
+ var EffectShader = {
3421
+ uniforms: {
3422
+ sceneDiffuse: new Uniform5(null),
3423
+ sceneDepth: new Uniform5(null),
3424
+ sceneNormal: new Uniform5(null),
3425
+ projMat: new Uniform5(new Matrix44()),
3426
+ viewMat: new Uniform5(new Matrix44()),
3427
+ projViewMat: new Uniform5(new Matrix44()),
3428
+ projectionMatrixInv: new Uniform5(new Matrix44()),
3429
+ viewMatrixInv: new Uniform5(new Matrix44()),
3430
+ cameraPos: new Uniform5(new Vector311()),
3431
+ resolution: new Uniform5(new Vector24()),
3432
+ time: new Uniform5(0),
3433
+ samples: new Uniform5([]),
3434
+ samplesR: new Uniform5([]),
3435
+ bluenoise: new Uniform5(null),
3436
+ distanceFalloff: new Uniform5(1),
3437
+ radius: new Uniform5(5),
3438
+ near: new Uniform5(0.1),
3439
+ far: new Uniform5(1e3),
3440
+ logDepth: new Uniform5(false),
3441
+ ortho: new Uniform5(false),
3442
+ screenSpaceRadius: new Uniform5(false)
3443
+ },
3444
+ depthWrite: false,
3445
+ depthTest: false,
3446
+ vertexShader: (
3447
+ /* glsl */
3448
+ `
3449
+ varying vec2 vUv;
3450
+ void main(void) {
3451
+ vUv = uv;
3452
+ gl_Position = vec4(position, 1);
3453
+ }
3454
+ `
3455
+ ),
3456
+ fragmentShader: (
3457
+ /* glsl */
3458
+ `
3459
+ #define SAMPLES 16
3460
+ #define FSAMPLES 16.0
3461
+ uniform sampler2D sceneDiffuse;
3462
+ uniform highp sampler2D sceneNormal;
3463
+ uniform highp sampler2D sceneDepth;
3464
+ uniform mat4 projectionMatrixInv;
3465
+ uniform mat4 viewMatrixInv;
3466
+ uniform mat4 projMat;
3467
+ uniform mat4 viewMat;
3468
+ uniform mat4 projViewMat;
3469
+ uniform vec3 cameraPos;
3470
+ uniform vec2 resolution;
3471
+ uniform float time;
3472
+ uniform vec3[SAMPLES] samples;
3473
+ uniform float[SAMPLES] samplesR;
3474
+ uniform float radius;
3475
+ uniform float distanceFalloff;
3476
+ uniform float near;
3477
+ uniform float far;
3478
+ uniform bool logDepth;
3479
+ uniform bool ortho;
3480
+ uniform bool screenSpaceRadius;
3481
+ uniform sampler2D bluenoise;
3482
+ varying vec2 vUv;
3483
+
3484
+ highp float linearize_depth(highp float d, highp float zNear,highp float zFar) {
3485
+ return (zFar * zNear) / (zFar - d * (zFar - zNear));
3486
+ }
3487
+
3488
+ highp float linearize_depth_ortho(highp float d, highp float nearZ, highp float farZ) {
3489
+ return nearZ + (farZ - nearZ) * d;
3490
+ }
3491
+
3492
+ highp float linearize_depth_log(highp float d, highp float nearZ,highp float farZ) {
3493
+ float depth = pow(2.0, d * log2(farZ + 1.0)) - 1.0;
3494
+ float a = farZ / (farZ - nearZ);
3495
+ float b = farZ * nearZ / (nearZ - farZ);
3496
+ float linDepth = a + b / depth;
3497
+ return (
3498
+ ortho
3499
+ ? linearize_depth_ortho(linDepth, nearZ, farZ)
3500
+ : linearize_depth(linDepth, nearZ, farZ)
3501
+ );
3502
+ }
3503
+
3504
+ vec3 getWorldPosLog(vec3 posS) {
3505
+ vec2 uv = posS.xy;
3506
+ float z = posS.z;
3507
+ float nearZ =near;
3508
+ float farZ = far;
3509
+ float depth = pow(2.0, z * log2(farZ + 1.0)) - 1.0;
3510
+ float a = farZ / (farZ - nearZ);
3511
+ float b = farZ * nearZ / (nearZ - farZ);
3512
+ float linDepth = a + b / depth;
3513
+ vec4 clipVec = vec4(uv, linDepth, 1.0) * 2.0 - 1.0;
3514
+ vec4 wpos = projectionMatrixInv * clipVec;
3515
+ return wpos.xyz / wpos.w;
3516
+ }
3517
+
3518
+ vec3 getWorldPos(float depth, vec2 coord) {
3519
+ #ifdef LOGDEPTH
3520
+ return getWorldPosLog(vec3(coord, depth));
3521
+ #endif
3522
+ float z = depth * 2.0 - 1.0;
3523
+ vec4 clipSpacePosition = vec4(coord * 2.0 - 1.0, z, 1.0);
3524
+ vec4 viewSpacePosition = projectionMatrixInv * clipSpacePosition;
3525
+
3526
+ vec4 worldSpacePosition = viewSpacePosition;
3527
+ worldSpacePosition.xyz /= worldSpacePosition.w;
3528
+ return worldSpacePosition.xyz;
3529
+ }
3530
+
3531
+ vec3 computeNormal(vec3 worldPos, vec2 vUv) {
3532
+ ivec2 p = ivec2(vUv * resolution);
3533
+ float c0 = texelFetch(sceneDepth, p, 0).x;
3534
+ float l2 = texelFetch(sceneDepth, p - ivec2(2, 0), 0).x;
3535
+ float l1 = texelFetch(sceneDepth, p - ivec2(1, 0), 0).x;
3536
+ float r1 = texelFetch(sceneDepth, p + ivec2(1, 0), 0).x;
3537
+ float r2 = texelFetch(sceneDepth, p + ivec2(2, 0), 0).x;
3538
+ float b2 = texelFetch(sceneDepth, p - ivec2(0, 2), 0).x;
3539
+ float b1 = texelFetch(sceneDepth, p - ivec2(0, 1), 0).x;
3540
+ float t1 = texelFetch(sceneDepth, p + ivec2(0, 1), 0).x;
3541
+ float t2 = texelFetch(sceneDepth, p + ivec2(0, 2), 0).x;
3542
+ float dl = abs((2.0 * l1 - l2) - c0);
3543
+ float dr = abs((2.0 * r1 - r2) - c0);
3544
+ float db = abs((2.0 * b1 - b2) - c0);
3545
+ float dt = abs((2.0 * t1 - t2) - c0);
3546
+ vec3 ce = getWorldPos(c0, vUv).xyz;
3547
+ vec3 dpdx = (
3548
+ (dl < dr)
3549
+ ? ce - getWorldPos(l1, (vUv - vec2(1.0 / resolution.x, 0.0))).xyz
3550
+ : -ce + getWorldPos(r1, (vUv + vec2(1.0 / resolution.x, 0.0))).xyz
3551
+ );
3552
+ vec3 dpdy = (
3553
+ (db < dt)
3554
+ ? ce - getWorldPos(b1, (vUv - vec2(0.0, 1.0 / resolution.y))).xyz
3555
+ : -ce + getWorldPos(t1, (vUv + vec2(0.0, 1.0 / resolution.y))).xyz
3556
+ );
3557
+ return normalize(cross(dpdx, dpdy));
3558
+ }
3559
+
3560
+ void main(void) {
3561
+ vec4 diffuse = texture2D(sceneDiffuse, vUv);
3562
+ float depth = texture2D(sceneDepth, vUv).x;
3563
+
3564
+ if (depth == 1.0) {
3565
+ gl_FragColor = vec4(vec3(1.0), 1.0);
3566
+ return;
3567
+ }
3568
+
3569
+ vec3 worldPos = getWorldPos(depth, vUv);
3570
+
3571
+ #ifdef HALFRES
3572
+ vec3 normal = texture2D(sceneNormal, vUv).rgb;
3573
+ #else
3574
+ vec3 normal = computeNormal(worldPos, vUv);
3575
+ #endif
3576
+
3577
+ vec4 noise = texture2D(bluenoise, gl_FragCoord.xy / 128.0);
3578
+ vec3 randomVec = normalize(noise.rgb * 2.0 - 1.0);
3579
+ vec3 tangent = normalize(randomVec - normal * dot(randomVec, normal));
3580
+ vec3 bitangent = cross(normal, tangent);
3581
+ mat3 tbn = mat3(tangent, bitangent, normal);
3582
+ float occluded = 0.0;
3583
+ float totalWeight = 0.0;
3584
+
3585
+ float radiusToUse = (
3586
+ screenSpaceRadius
3587
+ ? distance(worldPos, getWorldPos(depth, vUv + vec2(radius, 0.0) / resolution))
3588
+ : radius
3589
+ );
3590
+ float distanceFalloffToUse = (
3591
+ screenSpaceRadius
3592
+ ? radiusToUse * distanceFalloff
3593
+ : distanceFalloff
3594
+ );
3595
+ float bias = (0.1 / near) * fwidth(distance(worldPos, cameraPos)) / radiusToUse;
3596
+ for(float i = 0.0; i < FSAMPLES; i++) {
3597
+ vec3 sampleDirection = tbn * samples[int(i)];
3598
+ float moveAmt = samplesR[int(mod(i + noise.a * FSAMPLES, FSAMPLES))];
3599
+ vec3 samplePos = worldPos + radiusToUse * moveAmt * sampleDirection;
3600
+ vec4 offset = projMat * vec4(samplePos, 1.0);
3601
+ offset.xyz /= offset.w;
3602
+ offset.xyz = offset.xyz * 0.5 + 0.5;
3603
+ float sampleDepth = textureLod(sceneDepth, offset.xy, 0.0).x;
3604
+ #ifdef LOGDEPTH
3605
+ float distSample = linearize_depth_log(sampleDepth, near, far);
3606
+ #else
3607
+ float distSample = (
3608
+ ortho
3609
+ ? linearize_depth_ortho(sampleDepth, near, far)
3610
+ : linearize_depth(sampleDepth, near, far)
3611
+ );
3612
+ #endif
3613
+ float distWorld = (
3614
+ ortho
3615
+ ? linearize_depth_ortho(offset.z, near, far)
3616
+ : linearize_depth(offset.z, near, far)
3617
+ );
3618
+ float rangeCheck = smoothstep(0.0, 1.0, distanceFalloffToUse / (abs(distSample - distWorld)));
3619
+ vec2 diff = gl_FragCoord.xy - ( offset.xy * resolution);
3620
+ float weight = dot(sampleDirection, normal);
3621
+ occluded += rangeCheck * weight *
3622
+ (distSample + bias < distWorld ? 1.0 : 0.0) *
3623
+ (
3624
+ (
3625
+ dot(diff, diff) < 1.0 ||
3626
+ (sampleDepth == depth) ||
3627
+ (offset.x < 0.0 || offset.x > 1.0 || offset.y < 0.0 || offset.y > 1.0) ? 0.0 : 1.0
3628
+ )
3629
+ );
3630
+ totalWeight += weight;
3631
+ }
3632
+ float occ = clamp(1.0 - occluded / totalWeight, 0.0, 1.0);
3633
+ gl_FragColor = vec4(0.5 + 0.5 * normal, occ);
3634
+ }`
3635
+ )
3636
+ };
3637
+
3638
+ // src/rendering/post-effects/n8-ssao/FullScreenTriangle.ts
3639
+ import {
3640
+ BufferAttribute,
3641
+ BufferGeometry,
3642
+ Mesh as Mesh4,
3643
+ OrthographicCamera as OrthographicCamera2,
3644
+ Sphere
3645
+ } from "three";
3646
+ var FullScreenTriangle = class {
3647
+ constructor(material) {
3648
+ this.camera = new OrthographicCamera2();
3649
+ this.geometry = new BufferGeometry();
3650
+ this.geometry.setAttribute(
3651
+ "position",
3652
+ new BufferAttribute(new Float32Array([-1, -1, 3, -1, -1, 3]), 2)
3653
+ );
3654
+ this.geometry.setAttribute("uv", new BufferAttribute(new Float32Array([0, 0, 2, 0, 0, 2]), 2));
3655
+ this.geometry.boundingSphere = new Sphere();
3656
+ this.geometry.computeBoundingSphere = function() {
3657
+ };
3658
+ this.mesh = new Mesh4(this.geometry, material);
3659
+ this.mesh.frustumCulled = false;
3660
+ }
3661
+ get material() {
3662
+ return this.mesh.material;
3663
+ }
3664
+ set material(value) {
3665
+ this.mesh.material = value;
3666
+ }
3667
+ render(renderer) {
3668
+ renderer.render(this.mesh, this.camera);
3669
+ }
3670
+ dispose() {
3671
+ this.mesh.material.dispose();
3672
+ this.mesh.geometry.dispose();
3673
+ }
3674
+ };
3675
+
3676
+ // src/rendering/post-effects/n8-ssao/PoissionBlur.ts
3677
+ import { Matrix4 as Matrix45, Uniform as Uniform6, Vector2 as Vector25, Vector3 as Vector312 } from "three";
3678
+ var PoissionBlur = {
3679
+ uniforms: {
3680
+ sceneDiffuse: new Uniform6(null),
3681
+ sceneDepth: new Uniform6(null),
3682
+ tDiffuse: new Uniform6(null),
3683
+ projMat: new Uniform6(new Matrix45()),
3684
+ viewMat: new Uniform6(new Matrix45()),
3685
+ projectionMatrixInv: new Uniform6(new Matrix45()),
3686
+ viewMatrixInv: new Uniform6(new Matrix45()),
3687
+ cameraPos: new Uniform6(new Vector312()),
3688
+ resolution: new Uniform6(new Vector25()),
3689
+ time: new Uniform6(0),
3690
+ r: new Uniform6(5),
3691
+ blueNoise: new Uniform6(null),
3692
+ radius: new Uniform6(12),
3693
+ worldRadius: new Uniform6(5),
3694
+ index: new Uniform6(0),
3695
+ poissonDisk: new Uniform6([]),
3696
+ distanceFalloff: new Uniform6(1),
3697
+ near: new Uniform6(0.1),
3698
+ far: new Uniform6(1e3),
3699
+ logDepth: new Uniform6(false),
3700
+ screenSpaceRadius: new Uniform6(false)
3701
+ },
3702
+ depthWrite: false,
3703
+ depthTest: false,
3704
+ vertexShader: (
3705
+ /* glsl */
3706
+ `
3707
+ varying vec2 vUv;
3708
+ void main(void) {
3709
+ vUv = uv;
3710
+ gl_Position = vec4(position, 1.0);
3711
+ }`
3712
+ ),
3713
+ fragmentShader: (
3714
+ /* glsl */
3715
+ `
3716
+ uniform sampler2D sceneDiffuse;
3717
+ uniform highp sampler2D sceneDepth;
3718
+ uniform sampler2D tDiffuse;
3719
+ uniform sampler2D blueNoise;
3720
+ uniform mat4 projectionMatrixInv;
3721
+ uniform mat4 viewMatrixInv;
3722
+ uniform vec2 resolution;
3723
+ uniform float r;
3724
+ uniform float radius;
3725
+ uniform float worldRadius;
3726
+ uniform float index;
3727
+ uniform float near;
3728
+ uniform float far;
3729
+ uniform float distanceFalloff;
3730
+ uniform bool logDepth;
3731
+ uniform bool screenSpaceRadius;
3732
+ varying vec2 vUv;
3733
+
3734
+ highp float linearize_depth(highp float d, highp float zNear,highp float zFar) {
3735
+ highp float z_n = 2.0 * d - 1.0;
3736
+ return 2.0 * zNear * zFar / (zFar + zNear - z_n * (zFar - zNear));
3737
+ }
3738
+
3739
+ highp float linearize_depth_log(highp float d, highp float nearZ,highp float farZ) {
3740
+ float depth = pow(2.0, d * log2(farZ + 1.0)) - 1.0;
3741
+ float a = farZ / (farZ - nearZ);
3742
+ float b = farZ * nearZ / (nearZ - farZ);
3743
+ float linDepth = a + b / depth;
3744
+ return linearize_depth(linDepth, nearZ, farZ);
3745
+ }
3746
+
3747
+ highp float linearize_depth_ortho(highp float d, highp float nearZ, highp float farZ) {
3748
+ return nearZ + (farZ - nearZ) * d;
3749
+ }
3750
+
3751
+ vec3 getWorldPosLog(vec3 posS) {
3752
+ vec2 uv = posS.xy;
3753
+ float z = posS.z;
3754
+ float nearZ =near;
3755
+ float farZ = far;
3756
+ float depth = pow(2.0, z * log2(farZ + 1.0)) - 1.0;
3757
+ float a = farZ / (farZ - nearZ);
3758
+ float b = farZ * nearZ / (nearZ - farZ);
3759
+ float linDepth = a + b / depth;
3760
+ vec4 clipVec = vec4(uv, linDepth, 1.0) * 2.0 - 1.0;
3761
+ vec4 wpos = projectionMatrixInv * clipVec;
3762
+ return wpos.xyz / wpos.w;
3763
+ }
3764
+
3765
+ vec3 getWorldPos(float depth, vec2 coord) {
3766
+ #ifdef LOGDEPTH
3767
+ return getWorldPosLog(vec3(coord, depth));
3768
+ #endif
3769
+
3770
+ float z = depth * 2.0 - 1.0;
3771
+ vec4 clipSpacePosition = vec4(coord * 2.0 - 1.0, z, 1.0);
3772
+ vec4 viewSpacePosition = projectionMatrixInv * clipSpacePosition;
3773
+
3774
+ vec4 worldSpacePosition = viewSpacePosition;
3775
+ worldSpacePosition.xyz /= worldSpacePosition.w;
3776
+ return worldSpacePosition.xyz;
3777
+ }
3778
+
3779
+ #include <common>
3780
+
3781
+ #define NUM_SAMPLES 16
3782
+
3783
+ uniform vec2 poissonDisk[NUM_SAMPLES];
3784
+
3785
+ void main(void) {
3786
+ const float pi = acos(-1.0);
3787
+ vec2 texelSize = vec2(1.0 / resolution.x, 1.0 / resolution.y);
3788
+ vec2 uv = vUv;
3789
+ vec4 data = texture2D(tDiffuse, vUv);
3790
+ float occlusion = data.a;
3791
+ float baseOcc = data.a;
3792
+ vec3 normal = data.rgb * 2.0 - 1.0;
3793
+ float count = 1.0;
3794
+ float d = texture2D(sceneDepth, vUv).x;
3795
+ if (d == 1.0) {
3796
+ gl_FragColor = data;
3797
+ return;
3798
+ }
3799
+ vec3 worldPos = getWorldPos(d, vUv);
3800
+ float size = radius;
3801
+ float angle;
3802
+
3803
+ if (index == 0.0) {
3804
+ angle = texture2D(blueNoise, gl_FragCoord.xy / 128.0).x * PI2;
3805
+ } else if (index == 1.0) {
3806
+ angle = texture2D(blueNoise, gl_FragCoord.xy / 128.0).y * PI2;
3807
+ } else if (index == 2.0) {
3808
+ angle = texture2D(blueNoise, gl_FragCoord.xy / 128.0).z * PI2;
3809
+ } else {
3810
+ angle = texture2D(blueNoise, gl_FragCoord.xy / 128.0).w * PI2;
3811
+ }
3812
+
3813
+ mat2 rotationMatrix = mat2(cos(angle), -sin(angle), sin(angle), cos(angle));
3814
+ float radiusToUse = (
3815
+ screenSpaceRadius
3816
+ ? distance(worldPos, getWorldPos(d, vUv + vec2(worldRadius, 0.0) / resolution))
3817
+ : worldRadius
3818
+ );
3819
+ float distanceFalloffToUse = (
3820
+ screenSpaceRadius
3821
+ ? radiusToUse * distanceFalloff
3822
+ : distanceFalloff
3823
+ );
3824
+
3825
+ for(int i = 0; i < NUM_SAMPLES; i++) {
3826
+ vec2 offset = (rotationMatrix * poissonDisk[i]) * texelSize * size;
3827
+ vec4 dataSample = texture2D(tDiffuse, uv + offset);
3828
+ float occSample = dataSample.a;
3829
+ vec3 normalSample = dataSample.rgb * 2.0 - 1.0;
3830
+ float dSample = texture2D(sceneDepth, uv + offset).x;
3831
+ vec3 worldPosSample = getWorldPos(dSample, uv + offset);
3832
+ float tangentPlaneDist = abs(dot(worldPos - worldPosSample, normal));
3833
+ float rangeCheck = (
3834
+ (dSample == 1.0)
3835
+ ? 0.0
3836
+ : exp(
3837
+ -1.0 * tangentPlaneDist * (1.0 / distanceFalloffToUse)
3838
+ ) * max(dot(normal, normalSample), 0.0) * (1.0 - abs(occSample - baseOcc))
3839
+ );
3840
+ occlusion += occSample * rangeCheck;
3841
+ count += rangeCheck;
3842
+ }
3843
+
3844
+ if (count > 0.0) {
3845
+ occlusion /= count;
3846
+ }
3847
+
3848
+ #ifdef LOGDEPTH
3849
+ occlusion = clamp(occlusion, 0.0, 1.0);
3850
+ if (occlusion == 0.0) {
3851
+ occlusion = 1.0;
3852
+ }
3853
+ #endif
3854
+ gl_FragColor = vec4(0.5 + 0.5 * normal, occlusion);
3855
+ }
3856
+ `
3857
+ )
3858
+ };
3859
+
3860
+ // src/rendering/post-effects/n8-ssao/N8SSAOPass.ts
3861
+ var bluenoiseBits = Uint8Array.from(atob(BlueNoise), (c) => c.charCodeAt(0));
3862
+ function checkTimerQuery(timerQuery, gl, pass) {
3863
+ const available = gl.getQueryParameter(timerQuery, gl.QUERY_RESULT_AVAILABLE);
3864
+ if (available) {
3865
+ const elapsedTimeInNs = gl.getQueryParameter(timerQuery, gl.QUERY_RESULT);
3866
+ const elapsedTimeInMs = elapsedTimeInNs / 1e6;
3867
+ pass.lastTime = elapsedTimeInMs;
3868
+ } else {
3869
+ setTimeout(() => checkTimerQuery(timerQuery, gl, pass), 1);
3870
+ }
3871
+ }
3872
+ var N8SSAOPass = class extends Pass {
3873
+ constructor(scene, camera, width = 512, height = 512) {
3874
+ super();
3875
+ this.lastTime = 0;
3876
+ this.autosetGamma = true;
3877
+ this.samples = [];
3878
+ this.samplesR = [];
3879
+ this.samplesDenoise = [];
3880
+ this.copyQuadMaterial = new ShaderMaterial4({
3881
+ uniforms: { tDiffuse: new Uniform7(null) },
3882
+ depthWrite: false,
3883
+ vertexShader: (
3884
+ /* glsl */
3885
+ `
3886
+ varying vec2 vUv;
3887
+ void main(void) {
3888
+ vUv = uv;
3889
+ gl_Position = vec4(position, 1);
3890
+ }
3891
+ `
3892
+ ),
3893
+ fragmentShader: (
3894
+ /* glsl */
3895
+ `
3896
+ uniform sampler2D tDiffuse;
3897
+ varying vec2 vUv;
3898
+ void main(void) {
3899
+ gl_FragColor = texture2D(tDiffuse, vUv);
3900
+ }
3901
+ `
3902
+ )
3903
+ });
3904
+ this.copyQuad = new FullScreenTriangle(this.copyQuadMaterial);
3905
+ this.width = width;
3906
+ this.height = height;
3907
+ this.camera = camera;
3908
+ this.scene = scene;
3909
+ this.configuration = new Proxy(
3910
+ {
3911
+ aoSamples: 16,
3912
+ aoRadius: 5,
3913
+ denoiseSamples: 8,
3914
+ denoiseRadius: 12,
3915
+ distanceFalloff: 1,
3916
+ intensity: 5,
3917
+ denoiseIterations: 2,
3918
+ renderMode: 0,
3919
+ color: new Color6(0, 0, 0),
3920
+ gammaCorrection: true,
3921
+ logarithmicDepthBuffer: false,
3922
+ screenSpaceRadius: false,
3923
+ halfRes: false,
3924
+ depthAwareUpsampling: true,
3925
+ colorMultiply: true
3926
+ },
3927
+ {
3928
+ set: (target, propName, value) => {
3929
+ const oldProp = target[propName];
3930
+ target[propName] = value;
3931
+ if (propName === "aoSamples" && oldProp !== value) {
3932
+ this.configureAOPass(this.configuration.logarithmicDepthBuffer);
3933
+ }
3934
+ if (propName === "denoiseSamples" && oldProp !== value) {
3935
+ this.configureDenoisePass(this.configuration.logarithmicDepthBuffer);
3936
+ }
3937
+ if (propName === "halfRes" && oldProp !== value) {
3938
+ this.configureAOPass(this.configuration.logarithmicDepthBuffer);
3939
+ this.configureHalfResTargets();
3940
+ this.configureEffectCompositer(this.configuration.logarithmicDepthBuffer);
3941
+ this.setSize(this.width, this.height);
3942
+ }
3943
+ if (propName === "depthAwareUpsampling" && oldProp !== value) {
3944
+ this.configureEffectCompositer(this.configuration.logarithmicDepthBuffer);
3945
+ }
3946
+ if (propName === "gammaCorrection") {
3947
+ this.autosetGamma = false;
3948
+ }
3949
+ return true;
3950
+ }
3951
+ }
3952
+ );
3953
+ this.configureEffectCompositer(this.configuration.logarithmicDepthBuffer);
3954
+ this.configureSampleDependentPasses();
3955
+ this.configureHalfResTargets();
3956
+ this.writeTargetInternal = new WebGLRenderTarget(this.width, this.height, {
3957
+ minFilter: LinearFilter3,
3958
+ magFilter: LinearFilter3,
3959
+ depthBuffer: false
3960
+ });
3961
+ this.readTargetInternal = new WebGLRenderTarget(this.width, this.height, {
3962
+ minFilter: LinearFilter3,
3963
+ magFilter: LinearFilter3,
3964
+ depthBuffer: false
3965
+ });
3966
+ this.outputTargetInternal = new WebGLRenderTarget(this.width, this.height, {
3967
+ minFilter: LinearFilter3,
3968
+ magFilter: LinearFilter3,
3969
+ depthBuffer: false
3970
+ });
3971
+ this.bluenoise = new DataTexture(bluenoiseBits, 128, 128);
3972
+ this.bluenoise.colorSpace = NoColorSpace;
3973
+ this.bluenoise.wrapS = RepeatWrapping;
3974
+ this.bluenoise.wrapT = RepeatWrapping;
3975
+ this.bluenoise.minFilter = NearestFilter;
3976
+ this.bluenoise.magFilter = NearestFilter;
3977
+ this.bluenoise.needsUpdate = true;
3978
+ this.lastTime = 0;
3979
+ this.needsDepthTexture = true;
3980
+ this.needsSwap = true;
3981
+ this.r = new Vector26();
3982
+ this.c = new Color6();
3983
+ }
3984
+ configureHalfResTargets() {
3985
+ if (this.configuration.halfRes) {
3986
+ this.depthDownsampleTarget = new WebGLMultipleRenderTargets(
3987
+ this.width / 2,
3988
+ this.height / 2,
3989
+ 2,
3990
+ {
3991
+ depthBuffer: false
3992
+ }
3993
+ );
3994
+ this.depthDownsampleTarget.texture[0].format = RedFormat;
3995
+ this.depthDownsampleTarget.texture[0].type = FloatType;
3996
+ this.depthDownsampleTarget.texture[0].minFilter = NearestFilter;
3997
+ this.depthDownsampleTarget.texture[0].magFilter = NearestFilter;
3998
+ this.depthDownsampleTarget.texture[1].format = RGBAFormat2;
3999
+ this.depthDownsampleTarget.texture[1].type = HalfFloatType;
4000
+ this.depthDownsampleTarget.texture[1].minFilter = NearestFilter;
4001
+ this.depthDownsampleTarget.texture[1].magFilter = NearestFilter;
4002
+ this.depthDownsampleQuad = new FullScreenTriangle(new ShaderMaterial4(DepthDownSample));
4003
+ } else {
4004
+ if (this.depthDownsampleTarget) {
4005
+ this.depthDownsampleTarget.dispose();
4006
+ this.depthDownsampleTarget = null;
4007
+ }
4008
+ if (this.depthDownsampleQuad) {
4009
+ this.depthDownsampleQuad.dispose();
4010
+ this.depthDownsampleQuad = null;
4011
+ }
4012
+ }
4013
+ }
4014
+ configureSampleDependentPasses() {
4015
+ this.configureAOPass(this.configuration.logarithmicDepthBuffer);
4016
+ this.configureDenoisePass(this.configuration.logarithmicDepthBuffer);
4017
+ }
4018
+ configureAOPass(logarithmicDepthBuffer = false) {
4019
+ this.samples = this.generateHemisphereSamples(this.configuration.aoSamples);
4020
+ this.samplesR = this.generateHemisphereSamplesR(this.configuration.aoSamples);
4021
+ const e = { ...EffectShader };
4022
+ e.fragmentShader = e.fragmentShader.replace("16", this.configuration.aoSamples.toString()).replace("16.0", this.configuration.aoSamples.toString() + ".0");
4023
+ if (logarithmicDepthBuffer) {
4024
+ e.fragmentShader = "#define LOGDEPTH\n" + e.fragmentShader;
4025
+ }
4026
+ if (this.configuration.halfRes) {
4027
+ e.fragmentShader = "#define HALFRES\n" + e.fragmentShader;
4028
+ }
4029
+ if (this.effectShaderQuad) {
4030
+ this.effectShaderQuad.material.dispose();
4031
+ this.effectShaderQuad.material = new ShaderMaterial4(e);
4032
+ } else {
4033
+ this.effectShaderQuad = new FullScreenTriangle(new ShaderMaterial4(e));
4034
+ }
4035
+ }
4036
+ configureDenoisePass(logarithmicDepthBuffer = false) {
4037
+ this.samplesDenoise = this.generateDenoiseSamples(this.configuration.denoiseSamples, 11);
4038
+ const p = { ...PoissionBlur };
4039
+ p.fragmentShader = p.fragmentShader.replace("16", this.configuration.denoiseSamples.toString());
4040
+ if (logarithmicDepthBuffer) {
4041
+ p.fragmentShader = "#define LOGDEPTH\n" + p.fragmentShader;
4042
+ }
4043
+ if (this.poissonBlurQuad) {
4044
+ this.poissonBlurQuad.material.dispose();
4045
+ this.poissonBlurQuad.material = new ShaderMaterial4(p);
4046
+ } else {
4047
+ this.poissonBlurQuad = new FullScreenTriangle(new ShaderMaterial4(p));
4048
+ }
4049
+ }
4050
+ configureEffectCompositer(logarithmicDepthBuffer = false) {
4051
+ const e = { ...EffectCompositer };
4052
+ if (logarithmicDepthBuffer) {
4053
+ e.fragmentShader = "#define LOGDEPTH\n" + e.fragmentShader;
4054
+ }
4055
+ if (this.configuration.halfRes && this.configuration.depthAwareUpsampling) {
4056
+ e.fragmentShader = "#define HALFRES\n" + e.fragmentShader;
4057
+ }
4058
+ if (this.effectCompositerQuad) {
4059
+ this.effectCompositerQuad.material.dispose();
4060
+ this.effectCompositerQuad.material = new ShaderMaterial4(e);
4061
+ } else {
4062
+ this.effectCompositerQuad = new FullScreenTriangle(new ShaderMaterial4(e));
4063
+ }
4064
+ }
4065
+ generateHemisphereSamples(n) {
4066
+ const points = [];
4067
+ for (let k = 0; k < n; k++) {
4068
+ const theta = 2.399963 * k;
4069
+ const r = Math.sqrt(k + 0.5) / Math.sqrt(n);
4070
+ const x = r * Math.cos(theta);
4071
+ const y = r * Math.sin(theta);
4072
+ const z = Math.sqrt(1 - (x * x + y * y));
4073
+ points.push(new Vector313(x, y, z));
4074
+ }
4075
+ return points;
4076
+ }
4077
+ generateHemisphereSamplesR(n) {
4078
+ const samplesR = [];
4079
+ for (let i = 0; i < n; i++) {
4080
+ samplesR.push((i + 1) / n);
4081
+ }
4082
+ return samplesR;
4083
+ }
4084
+ generateDenoiseSamples(numSamples, numRings) {
4085
+ const angleStep = 2 * Math.PI * numRings / numSamples;
4086
+ const invNumSamples = 1 / numSamples;
4087
+ const radiusStep = invNumSamples;
4088
+ const samples = [];
4089
+ let radius = invNumSamples;
4090
+ let angle = 0;
4091
+ for (let i = 0; i < numSamples; i++) {
4092
+ samples.push(
4093
+ new Vector26(Math.cos(angle), Math.sin(angle)).multiplyScalar(Math.pow(radius, 0.75))
4094
+ );
4095
+ radius += radiusStep;
4096
+ angle += angleStep;
4097
+ }
4098
+ return samples;
4099
+ }
4100
+ setSize(width, height) {
4101
+ this.width = width;
4102
+ this.height = height;
4103
+ const c = this.configuration.halfRes ? 0.5 : 1;
4104
+ this.writeTargetInternal.setSize(width * c, height * c);
4105
+ this.readTargetInternal.setSize(width * c, height * c);
4106
+ if (this.configuration.halfRes && this.depthDownsampleTarget) {
4107
+ this.depthDownsampleTarget.setSize(width * c, height * c);
4108
+ }
4109
+ this.outputTargetInternal.setSize(width, height);
4110
+ }
4111
+ setDepthTexture(depthTexture) {
4112
+ this.depthTexture = depthTexture;
4113
+ }
4114
+ render(renderer, inputBuffer, outputBuffer) {
4115
+ const xrEnabled = renderer.xr.enabled;
4116
+ renderer.xr.enabled = false;
4117
+ let ext;
4118
+ let timerQuery = null;
4119
+ let gl = null;
4120
+ gl = renderer.getContext();
4121
+ if (this.debugMode) {
4122
+ ext = gl.getExtension("EXT_disjoint_timer_query_webgl2");
4123
+ if (ext === null) {
4124
+ console.error("EXT_disjoint_timer_query_webgl2 not available, disabling debug mode.");
4125
+ this.debugMode = false;
4126
+ gl = null;
4127
+ }
4128
+ }
4129
+ if (this.debugMode && gl) {
4130
+ timerQuery = gl.createQuery();
4131
+ gl.beginQuery(ext.TIME_ELAPSED_EXT, timerQuery);
4132
+ }
4133
+ if (renderer.capabilities.logarithmicDepthBuffer !== this.configuration.logarithmicDepthBuffer) {
4134
+ this.configuration.logarithmicDepthBuffer = renderer.capabilities.logarithmicDepthBuffer;
4135
+ this.configureAOPass(this.configuration.logarithmicDepthBuffer);
4136
+ this.configureDenoisePass(this.configuration.logarithmicDepthBuffer);
4137
+ this.configureEffectCompositer(this.configuration.logarithmicDepthBuffer);
4138
+ }
4139
+ if (inputBuffer.texture.type !== this.outputTargetInternal.texture.type) {
4140
+ this.outputTargetInternal.texture.type = inputBuffer.texture.type;
4141
+ this.outputTargetInternal.texture.needsUpdate = true;
4142
+ }
4143
+ this.camera.updateMatrixWorld();
4144
+ this.r.set(this.width, this.height);
4145
+ let trueRadius = this.configuration.aoRadius;
4146
+ if (this.configuration.halfRes && this.configuration.screenSpaceRadius) {
4147
+ trueRadius *= 0.5;
4148
+ }
4149
+ if (this.configuration.halfRes && this.depthDownsampleQuad) {
4150
+ const depthDownsampleUniforms = this.depthDownsampleQuad.material.uniforms;
4151
+ renderer.setRenderTarget(this.depthDownsampleTarget);
4152
+ depthDownsampleUniforms.sceneDepth.value = this.depthTexture;
4153
+ depthDownsampleUniforms.resolution.value = this.r;
4154
+ depthDownsampleUniforms.near.value = this.camera.near;
4155
+ depthDownsampleUniforms.far.value = this.camera.far;
4156
+ depthDownsampleUniforms.projectionMatrixInv.value = this.camera.projectionMatrixInverse;
4157
+ depthDownsampleUniforms.viewMatrixInv.value = this.camera.matrixWorld;
4158
+ depthDownsampleUniforms.logDepth.value = this.configuration.logarithmicDepthBuffer;
4159
+ this.depthDownsampleQuad.render(renderer);
4160
+ }
4161
+ if (!this.effectShaderQuad)
4162
+ return;
4163
+ const effectShaderUniforms = this.effectShaderQuad.material.uniforms;
4164
+ effectShaderUniforms.sceneDiffuse.value = inputBuffer.texture;
4165
+ effectShaderUniforms.sceneDepth.value = this.configuration.halfRes ? this.depthDownsampleTarget.texture[0] : this.depthTexture;
4166
+ effectShaderUniforms.sceneNormal.value = this.configuration.halfRes ? this.depthDownsampleTarget.texture[1] : null;
4167
+ effectShaderUniforms.projMat.value = this.camera.projectionMatrix;
4168
+ effectShaderUniforms.viewMat.value = this.camera.matrixWorldInverse;
4169
+ effectShaderUniforms.projViewMat.value = this.camera.projectionMatrix.clone().multiply(this.camera.matrixWorldInverse.clone());
4170
+ effectShaderUniforms.projectionMatrixInv.value = this.camera.projectionMatrixInverse;
4171
+ effectShaderUniforms.viewMatrixInv.value = this.camera.matrixWorld;
4172
+ effectShaderUniforms.cameraPos.value = this.camera.getWorldPosition(new Vector313());
4173
+ effectShaderUniforms.resolution.value = this.configuration.halfRes ? this.r.clone().multiplyScalar(1 / 2).floor() : this.r;
4174
+ effectShaderUniforms.time.value = performance.now() / 1e3;
4175
+ effectShaderUniforms.samples.value = this.samples;
4176
+ effectShaderUniforms.samplesR.value = this.samplesR;
4177
+ effectShaderUniforms.bluenoise.value = this.bluenoise;
4178
+ effectShaderUniforms.radius.value = trueRadius;
4179
+ effectShaderUniforms.distanceFalloff.value = this.configuration.distanceFalloff;
4180
+ effectShaderUniforms.near.value = this.camera.near;
4181
+ effectShaderUniforms.far.value = this.camera.far;
4182
+ effectShaderUniforms.logDepth.value = renderer.capabilities.logarithmicDepthBuffer;
4183
+ effectShaderUniforms.ortho.value = this.camera instanceof OrthographicCamera3;
4184
+ effectShaderUniforms.screenSpaceRadius.value = this.configuration.screenSpaceRadius;
4185
+ renderer.setRenderTarget(this.writeTargetInternal);
4186
+ this.effectShaderQuad.render(renderer);
4187
+ const poissonBlurUniforms = this.poissonBlurQuad.material.uniforms;
4188
+ for (let i = 0; i < this.configuration.denoiseIterations; i++) {
4189
+ if (!poissonBlurUniforms || !this.poissonBlurQuad)
4190
+ return;
4191
+ [this.writeTargetInternal, this.readTargetInternal] = [
4192
+ this.readTargetInternal,
4193
+ this.writeTargetInternal
4194
+ ];
4195
+ poissonBlurUniforms.tDiffuse.value = this.readTargetInternal.texture;
4196
+ poissonBlurUniforms.sceneDepth.value = this.configuration.halfRes ? this.depthDownsampleTarget.texture[0] : this.depthTexture;
4197
+ poissonBlurUniforms.projMat.value = this.camera.projectionMatrix;
4198
+ poissonBlurUniforms.viewMat.value = this.camera.matrixWorldInverse;
4199
+ poissonBlurUniforms.projectionMatrixInv.value = this.camera.projectionMatrixInverse;
4200
+ poissonBlurUniforms.viewMatrixInv.value = this.camera.matrixWorld;
4201
+ poissonBlurUniforms.cameraPos.value = this.camera.getWorldPosition(new Vector313());
4202
+ poissonBlurUniforms.resolution.value = this.configuration.halfRes ? this.r.clone().multiplyScalar(1 / 2).floor() : this.r;
4203
+ poissonBlurUniforms.time.value = performance.now() / 1e3;
4204
+ poissonBlurUniforms.blueNoise.value = this.bluenoise;
4205
+ poissonBlurUniforms.radius.value = this.configuration.denoiseRadius * (this.configuration.halfRes ? 1 / 2 : 1);
4206
+ poissonBlurUniforms.worldRadius.value = trueRadius;
4207
+ poissonBlurUniforms.distanceFalloff.value = this.configuration.distanceFalloff;
4208
+ poissonBlurUniforms.index.value = i;
4209
+ poissonBlurUniforms.poissonDisk.value = this.samplesDenoise;
4210
+ poissonBlurUniforms.near.value = this.camera.near;
4211
+ poissonBlurUniforms.far.value = this.camera.far;
4212
+ poissonBlurUniforms.logDepth.value = renderer.capabilities.logarithmicDepthBuffer;
4213
+ poissonBlurUniforms.screenSpaceRadius.value = this.configuration.screenSpaceRadius;
4214
+ renderer.setRenderTarget(this.writeTargetInternal);
4215
+ this.poissonBlurQuad.render(renderer);
4216
+ }
4217
+ const effectCompositerUniforms = this.effectCompositerQuad.material.uniforms;
4218
+ if (!effectCompositerUniforms || !this.effectCompositerQuad)
4219
+ return;
4220
+ effectCompositerUniforms.sceneDiffuse.value = inputBuffer.texture;
4221
+ effectCompositerUniforms.sceneDepth.value = this.depthTexture;
4222
+ effectCompositerUniforms.near.value = this.camera.near;
4223
+ effectCompositerUniforms.far.value = this.camera.far;
4224
+ effectCompositerUniforms.projectionMatrixInv.value = this.camera.projectionMatrixInverse;
4225
+ effectCompositerUniforms.viewMatrixInv.value = this.camera.matrixWorld;
4226
+ effectCompositerUniforms.logDepth.value = renderer.capabilities.logarithmicDepthBuffer;
4227
+ effectCompositerUniforms.ortho.value = this.camera instanceof OrthographicCamera3;
4228
+ effectCompositerUniforms.downsampledDepth.value = this.configuration.halfRes ? this.depthDownsampleTarget.texture[0] : this.depthTexture;
4229
+ effectCompositerUniforms.resolution.value = this.r;
4230
+ effectCompositerUniforms.blueNoise.value = this.bluenoise;
4231
+ effectCompositerUniforms.intensity.value = this.configuration.intensity;
4232
+ effectCompositerUniforms.renderMode.value = this.configuration.renderMode;
4233
+ effectCompositerUniforms.screenSpaceRadius.value = this.configuration.screenSpaceRadius;
4234
+ effectCompositerUniforms.radius.value = trueRadius;
4235
+ effectCompositerUniforms.distanceFalloff.value = this.configuration.distanceFalloff;
4236
+ effectCompositerUniforms.gammaCorrection.value = this.autosetGamma ? this.renderToScreen : this.configuration.gammaCorrection;
4237
+ effectCompositerUniforms.tDiffuse.value = this.writeTargetInternal.texture;
4238
+ effectCompositerUniforms.color.value = this.c.copy(this.configuration.color).convertSRGBToLinear();
4239
+ effectCompositerUniforms.colorMultiply.value = this.configuration.colorMultiply;
4240
+ effectCompositerUniforms.cameraPos.value = this.camera.getWorldPosition(new Vector313());
4241
+ effectCompositerUniforms.fog.value = !!this.scene.fog;
4242
+ if (this.scene.fog) {
4243
+ if (this.scene.fog instanceof Fog && this.scene.fog.isFog === true) {
4244
+ effectCompositerUniforms.fogExp.value = false;
4245
+ effectCompositerUniforms.fogNear.value = this.scene.fog.near;
4246
+ effectCompositerUniforms.fogFar.value = this.scene.fog.far;
4247
+ } else if (this.scene.fog instanceof FogExp2) {
4248
+ effectCompositerUniforms.fogExp.value = true;
4249
+ effectCompositerUniforms.fogDensity.value = this.scene.fog.density;
4250
+ } else {
4251
+ console.error(`Unsupported fog type ${this.scene.fog.constructor.name} in SSAOPass.`);
4252
+ }
4253
+ }
4254
+ renderer.setRenderTarget(this.outputTargetInternal);
4255
+ this.effectCompositerQuad.render(renderer);
4256
+ renderer.setRenderTarget(this.renderToScreen ? null : outputBuffer);
4257
+ this.copyQuad.material.uniforms.tDiffuse.value = this.outputTargetInternal.texture;
4258
+ this.copyQuad.render(renderer);
4259
+ if (this.debugMode && gl && timerQuery) {
4260
+ gl.endQuery(ext.TIME_ELAPSED_EXT);
4261
+ checkTimerQuery(timerQuery, gl, this);
4262
+ }
4263
+ renderer.xr.enabled = xrEnabled;
4264
+ }
4265
+ enableDebugMode() {
4266
+ this.debugMode = true;
4267
+ }
4268
+ disableDebugMode() {
4269
+ this.debugMode = false;
4270
+ }
4271
+ setDisplayMode(mode) {
4272
+ this.configuration.renderMode = ["Combined", "AO", "No AO", "Split", "Split AO"].indexOf(
4273
+ mode
4274
+ );
4275
+ }
4276
+ setQualityMode(mode) {
4277
+ if (mode === "Performance") {
4278
+ this.configuration.aoSamples = 8;
4279
+ this.configuration.denoiseSamples = 4;
4280
+ this.configuration.denoiseRadius = 12;
4281
+ } else if (mode === "Low") {
4282
+ this.configuration.aoSamples = 16;
4283
+ this.configuration.denoiseSamples = 4;
4284
+ this.configuration.denoiseRadius = 12;
4285
+ } else if (mode === "Medium") {
4286
+ this.configuration.aoSamples = 16;
4287
+ this.configuration.denoiseSamples = 8;
4288
+ this.configuration.denoiseRadius = 12;
4289
+ } else if (mode === "High") {
4290
+ this.configuration.aoSamples = 64;
4291
+ this.configuration.denoiseSamples = 8;
4292
+ this.configuration.denoiseRadius = 6;
4293
+ } else if (mode === "Ultra") {
4294
+ this.configuration.aoSamples = 64;
4295
+ this.configuration.denoiseSamples = 16;
4296
+ this.configuration.denoiseRadius = 6;
4297
+ }
4298
+ }
4299
+ };
4300
+
4301
+ // src/rendering/composer.ts
4302
+ var Composer = class {
4303
+ constructor(scene, camera, spawnSun = false) {
4304
+ this.width = 1;
4305
+ this.height = 1;
4306
+ this.resolution = new Vector27(this.width, this.height);
4307
+ this.isEnvHDRI = false;
4308
+ this.bcs = BrightnessContrastSaturation;
4309
+ this.gaussGrainEffect = GaussGrainEffect;
4310
+ this.ambientLight = null;
4311
+ this.sun = null;
4312
+ this.scene = scene;
4313
+ this.postPostScene = new Scene4();
4314
+ this.camera = camera;
4315
+ this.spawnSun = spawnSun;
4316
+ this.renderer = new WebGLRenderer4({
4317
+ powerPreference: "high-performance",
4318
+ antialias: false,
4319
+ stencil: false,
4320
+ depth: false
4321
+ });
4322
+ this.renderer.info.autoReset = false;
4323
+ this.renderer.setSize(this.width, this.height);
4324
+ this.renderer.shadowMap.enabled = true;
4325
+ this.renderer.shadowMap.type = rendererValues.shadowMap;
4326
+ this.renderer.toneMapping = rendererValues.toneMapping;
4327
+ this.renderer.toneMappingExposure = rendererValues.exposure;
4328
+ this.setAmbientLight();
4329
+ this.setFog();
4330
+ this.effectComposer = new EffectComposer2(this.renderer, {
4331
+ frameBufferType: HalfFloatType2
4332
+ });
4333
+ this.renderPass = new RenderPass(this.scene, this.camera);
4334
+ this.normalPass = new NormalPass2(this.scene, this.camera);
4335
+ this.normalPass.enabled = ppssaoValues.enabled;
4336
+ this.normalTextureEffect = new TextureEffect({
4337
+ blendFunction: BlendFunction2.SKIP,
4338
+ texture: this.normalPass.texture
3155
4339
  });
3156
4340
  this.ppssaoEffect = new SSAOEffect2(this.camera, this.normalPass.texture, {
3157
4341
  blendFunction: ppssaoValues.blendFunction,
@@ -3165,7 +4349,7 @@ var Composer = class {
3165
4349
  bias: ppssaoValues.bias,
3166
4350
  fade: ppssaoValues.fade,
3167
4351
  resolutionScale: ppssaoValues.resolutionScale,
3168
- color: new Color6().setRGB(ppssaoValues.color.r, ppssaoValues.color.g, ppssaoValues.color.b),
4352
+ color: new Color7().setRGB(ppssaoValues.color.r, ppssaoValues.color.g, ppssaoValues.color.b),
3169
4353
  worldDistanceThreshold: ppssaoValues.worldDistanceThreshold,
3170
4354
  worldDistanceFalloff: ppssaoValues.worldDistanceFalloff,
3171
4355
  worldProximityThreshold: ppssaoValues.worldProximityThreshold,
@@ -3177,11 +4361,11 @@ var Composer = class {
3177
4361
  this.bloomEffect = new BloomEffect({
3178
4362
  intensity: extrasValues.bloom
3179
4363
  });
3180
- this.n8aopass = new N8AOPostPass(this.scene, this.camera, this.width, this.height);
4364
+ this.n8aopass = new N8SSAOPass(this.scene, this.camera, this.width, this.height);
3181
4365
  this.n8aopass.configuration.aoRadius = n8ssaoValues.aoRadius;
3182
4366
  this.n8aopass.configuration.distanceFalloff = n8ssaoValues.distanceFalloff;
3183
4367
  this.n8aopass.configuration.intensity = n8ssaoValues.intensity;
3184
- this.n8aopass.configuration.color = new Color6().setRGB(
4368
+ this.n8aopass.configuration.color = new Color7().setRGB(
3185
4369
  n8ssaoValues.color.r,
3186
4370
  n8ssaoValues.color.g,
3187
4371
  n8ssaoValues.color.b
@@ -3357,19 +4541,19 @@ var Composer = class {
3357
4541
  fileInput.click();
3358
4542
  }
3359
4543
  setFog() {
3360
- const fogColor = new Color6().setRGB(
4544
+ const fogColor = new Color7().setRGB(
3361
4545
  envValues.fog.fogColor.r,
3362
4546
  envValues.fog.fogColor.g,
3363
4547
  envValues.fog.fogColor.b
3364
4548
  );
3365
- this.scene.fog = new Fog(fogColor, envValues.fog.fogNear, envValues.fog.fogFar);
4549
+ this.scene.fog = new Fog2(fogColor, envValues.fog.fogNear, envValues.fog.fogFar);
3366
4550
  }
3367
4551
  setAmbientLight() {
3368
4552
  if (this.ambientLight) {
3369
4553
  this.scene.remove(this.ambientLight);
3370
4554
  this.ambientLight.dispose();
3371
4555
  }
3372
- const ambientLightColor = new Color6().setRGB(
4556
+ const ambientLightColor = new Color7().setRGB(
3373
4557
  envValues.ambientLight.ambientLightColor.r,
3374
4558
  envValues.ambientLight.ambientLightColor.g,
3375
4559
  envValues.ambientLight.ambientLightColor.b
@@ -3435,16 +4619,16 @@ import {
3435
4619
  } from "mml-web";
3436
4620
  import {
3437
4621
  Box3,
3438
- Color as Color7,
4622
+ Color as Color8,
3439
4623
  DoubleSide,
3440
4624
  Euler as Euler2,
3441
- Group as Group4,
4625
+ Group as Group5,
3442
4626
  Line3 as Line32,
3443
- Matrix4 as Matrix42,
3444
- Mesh as Mesh4,
4627
+ Matrix4 as Matrix46,
4628
+ Mesh as Mesh5,
3445
4629
  MeshBasicMaterial as MeshBasicMaterial3,
3446
4630
  Ray,
3447
- Vector3 as Vector39
4631
+ Vector3 as Vector314
3448
4632
  } from "three";
3449
4633
  import { VertexNormalsHelper } from "three/examples/jsm/helpers/VertexNormalsHelper.js";
3450
4634
  import * as BufferGeometryUtils from "three/examples/jsm/utils/BufferGeometryUtils.js";
@@ -3452,12 +4636,12 @@ import { MeshBVH, MeshBVHVisualizer } from "three-mesh-bvh";
3452
4636
  var CollisionsManager = class {
3453
4637
  constructor(scene) {
3454
4638
  this.debug = false;
3455
- this.tempVector = new Vector39();
3456
- this.tempVector2 = new Vector39();
3457
- this.tempVector3 = new Vector39();
4639
+ this.tempVector = new Vector314();
4640
+ this.tempVector2 = new Vector314();
4641
+ this.tempVector3 = new Vector314();
3458
4642
  this.tempRay = new Ray();
3459
- this.tempMatrix = new Matrix42();
3460
- this.tempMatrix2 = new Matrix42();
4643
+ this.tempMatrix = new Matrix46();
4644
+ this.tempMatrix2 = new Matrix46();
3461
4645
  this.tempBox = new Box3();
3462
4646
  this.tempEuler = new Euler2();
3463
4647
  this.tempSegment = new Line32();
@@ -3488,13 +4672,13 @@ var CollisionsManager = class {
3488
4672
  group.updateWorldMatrix(true, false);
3489
4673
  const invertedRootMatrix = this.tempMatrix.copy(group.matrixWorld).invert();
3490
4674
  group.traverse((child) => {
3491
- if (child.type === "Mesh") {
3492
- const mesh = child;
3493
- const clonedGeometry = mesh.geometry.clone();
4675
+ const asMesh = child;
4676
+ if (asMesh.isMesh) {
4677
+ const clonedGeometry = asMesh.geometry.clone();
3494
4678
  if (child !== group) {
3495
- mesh.updateWorldMatrix(true, false);
4679
+ asMesh.updateWorldMatrix(true, false);
3496
4680
  clonedGeometry.applyMatrix4(
3497
- this.tempMatrix2.multiplyMatrices(invertedRootMatrix, mesh.matrixWorld)
4681
+ this.tempMatrix2.multiplyMatrices(invertedRootMatrix, asMesh.matrixWorld)
3498
4682
  );
3499
4683
  }
3500
4684
  for (const key in clonedGeometry.attributes) {
@@ -3520,11 +4704,11 @@ var CollisionsManager = class {
3520
4704
  };
3521
4705
  if (this.debug) {
3522
4706
  newBufferGeometry.boundsTree = meshBVH;
3523
- const wireframeMesh = new Mesh4(newBufferGeometry, new MeshBasicMaterial3({ wireframe: true }));
4707
+ const wireframeMesh = new Mesh5(newBufferGeometry, new MeshBasicMaterial3({ wireframe: true }));
3524
4708
  const normalsHelper = new VertexNormalsHelper(wireframeMesh, 0.25, 65280);
3525
4709
  const visualizer = new MeshBVHVisualizer(wireframeMesh, 4);
3526
- visualizer.edgeMaterial.color = new Color7("blue");
3527
- const debugGroup = new Group4();
4710
+ visualizer.edgeMaterial.color = new Color8("blue");
4711
+ const debugGroup = new Group5();
3528
4712
  debugGroup.add(wireframeMesh, normalsHelper, visualizer);
3529
4713
  group.matrixWorld.decompose(debugGroup.position, debugGroup.quaternion, debugGroup.scale);
3530
4714
  visualizer.update();
@@ -3603,7 +4787,7 @@ var CollisionsManager = class {
3603
4787
  const realDistance = intersectionSegment.distance();
3604
4788
  if (realDistance < capsuleRadius) {
3605
4789
  if (!collisionPosition) {
3606
- collisionPosition = new Vector39().copy(closestPointOnSegment).applyMatrix4(meshState.matrix);
4790
+ collisionPosition = new Vector314().copy(closestPointOnSegment).applyMatrix4(meshState.matrix);
3607
4791
  }
3608
4792
  const ratio = realDistance / modelReferenceDistance;
3609
4793
  const realDepth = capsuleRadius - realDistance;
@@ -3659,6 +4843,15 @@ export {
3659
4843
  MMLCompositionScene,
3660
4844
  Sun,
3661
4845
  TimeManager,
3662
- TweakPane
4846
+ TweakPane,
4847
+ clamp,
4848
+ decodeCharacterAndCamera,
4849
+ ease,
4850
+ encodeCharacterAndCamera,
4851
+ getSpawnPositionInsideCircle,
4852
+ remap,
4853
+ round,
4854
+ roundToDecimalPlaces,
4855
+ toArray
3663
4856
  };
3664
4857
  //# sourceMappingURL=index.js.map