From 5a27096b91e29400005bc15f06310a3cbf686c23 Mon Sep 17 00:00:00 2001 From: tf17270 Date: Fri, 19 Apr 2024 10:30:48 +0100 Subject: [PATCH] switch laptops commit --- conda/meta.yaml | 15 +- .../03_frequency_domain_channel_modelling.py | 112 ++-- docs/examples/rayhits.npy | Bin 0 -> 9331328 bytes docs/examples/rect_reflectorref.ply | Bin 0 -> 881 bytes docs/examples/reference_reflectorplate.ply | Bin 0 -> 881 bytes lyceanem/base_classes.py | 92 +-- lyceanem/electromagnetics/empropagation.py | 567 +----------------- lyceanem/geometry/geometryfunctions.py | 46 +- lyceanem/geometry/targets.py | 120 ++-- lyceanem/models/frequency_domain.py | 144 ++--- lyceanem/tests/data/rect_reflectorref.ply | Bin 0 -> 881 bytes lyceanem/tests/reflectordata.py | 47 +- lyceanem/tests/test_targets.py | 37 ++ 13 files changed, 376 insertions(+), 804 deletions(-) create mode 100644 docs/examples/rayhits.npy create mode 100644 docs/examples/rect_reflectorref.ply create mode 100644 docs/examples/reference_reflectorplate.ply create mode 100644 lyceanem/tests/data/rect_reflectorref.ply create mode 100644 lyceanem/tests/test_targets.py diff --git a/conda/meta.yaml b/conda/meta.yaml index 2e80b71..ad98c7e 100644 --- a/conda/meta.yaml +++ b/conda/meta.yaml @@ -1,9 +1,9 @@ -{ % set name = "lyceanem" % } - { % set version = "0.0.4" % } +{% set name = "lyceanem" %} +{% set version = "0.0.4" %} package: - name: { { name|lower } } - version: { { version } } + name: {{ name|lower }} + version: {{ version }} source: url: https://pypi.io/packages/source/{{ name[0] }}/{{ name }}/LyceanEM-{{ version }}.tar.gz @@ -11,7 +11,7 @@ source: build: noarch: python - script: { { PYTHON } } -m pip install . -vv + script: {{ PYTHON }} -m pip install . -vv number: 0 requirements: @@ -24,14 +24,15 @@ requirements: - open3d-admin::open3d - pip: - -lyceanem==0.0.4 + - lyceanem=={{ version }} about: home: https://lyceanem-python.readthedocs.io/en/latest/index.html - summary: LyceanEM is a Python library for modelling electromagnetic propagation for sensors and communications. You can find the documentation at https://lyceanem-python.readthedocs.io/en/latest/ + summary: LyceanEM is a Python library for modeling electromagnetic propagation for sensors and communications. You can find the documentation at https://lyceanem-python.readthedocs.io/en/latest/ license: GPL-3.0 license_file: LICENSE.txt extra: recipe-maintainers: - LyceanEM + diff --git a/docs/examples/03_frequency_domain_channel_modelling.py b/docs/examples/03_frequency_domain_channel_modelling.py index 8d0db19..78238b1 100644 --- a/docs/examples/03_frequency_domain_channel_modelling.py +++ b/docs/examples/03_frequency_domain_channel_modelling.py @@ -15,7 +15,6 @@ """ import numpy as np -import open3d as o3d # %% # Frequency and Mesh Resolution @@ -32,6 +31,7 @@ import lyceanem.geometry.targets as TL import lyceanem.geometry.geometryfunctions as GF + transmit_horn_structure, transmitting_antenna_surface_coords = TL.meshedHorn( 58e-3, 58e-3, 128e-3, 2e-3, 0.21, mesh_resolution ) @@ -48,38 +48,33 @@ # rotation_vector1 = np.radians(np.asarray([90.0, 0.0, 0.0])) rotation_vector2 = np.radians(np.asarray([0.0, 0.0, -90.0])) -transmit_horn_structure = GF.open3drotate( - transmit_horn_structure, - o3d.geometry.TriangleMesh.get_rotation_matrix_from_xyz(rotation_vector1), -) -transmit_horn_structure = GF.open3drotate( +transmit_horn_structure = GF.mesh_rotate( transmit_horn_structure, - o3d.geometry.TriangleMesh.get_rotation_matrix_from_xyz(rotation_vector2), -) -transmit_horn_structure.translate(np.asarray([2.695, 0, 0]), relative=True) -transmitting_antenna_surface_coords = GF.open3drotate( - transmitting_antenna_surface_coords, - o3d.geometry.TriangleMesh.get_rotation_matrix_from_xyz(rotation_vector1), + rotation_vector1 ) -transmitting_antenna_surface_coords = GF.open3drotate( - transmitting_antenna_surface_coords, - o3d.geometry.TriangleMesh.get_rotation_matrix_from_xyz(rotation_vector2), -) -transmitting_antenna_surface_coords.translate(np.asarray([2.695, 0, 0]), relative=True) +transmit_horn_structure = GF.mesh_rotate(transmit_horn_structure,rotation_vector2) + +transmit_horn_structure = GF.translate_mesh(transmit_horn_structure,np.asarray([2.695, 0, 0])) + +transmitting_antenna_surface_coords = GF.mesh_rotate(transmitting_antenna_surface_coords,rotation_vector1) + +transmitting_antenna_surface_coords = GF.mesh_rotate( + transmitting_antenna_surface_coords,rotation_vector2) + +transmitting_antenna_surface_coords = GF.translate_mesh(transmitting_antenna_surface_coords,np.asarray([2.695, 0, 0])) # %% # Position Receiver # ------------------ # rotate the receiving horn to desired orientation and translate to final position. -receive_horn_structure = GF.open3drotate( - receive_horn_structure, - o3d.geometry.TriangleMesh.get_rotation_matrix_from_xyz(rotation_vector1), -) -receive_horn_structure.translate(np.asarray([0, 1.427, 0]), relative=True) -receiving_antenna_surface_coords = GF.open3drotate( - receiving_antenna_surface_coords, - o3d.geometry.TriangleMesh.get_rotation_matrix_from_xyz(rotation_vector1), -) -receiving_antenna_surface_coords.translate(np.asarray([0, 1.427, 0]), relative=True) + +receive_horn_structure = GF.mesh_rotate(receive_horn_structure,rotation_vector1) +receive_horn_structure = GF.translate_mesh(receive_horn_structure,np.asarray([0, 1.427, 0])) +receiving_antenna_surface_coords = GF.mesh_rotate(receiving_antenna_surface_coords,rotation_vector1) +receiving_antenna_surface_coords = GF.translate_mesh(receiving_antenna_surface_coords,np.asarray([0, 1.427, 0])) + +receive_horn_structure = GF.mesh_rotate(receive_horn_structure,rotation_vector2) +receiving_antenna_surface_coords = GF.mesh_rotate(receiving_antenna_surface_coords,rotation_vector2) + # %% # Create Scattering Plate @@ -89,18 +84,19 @@ reflectorplate, scatter_points = TL.meshedReflector( 0.3, 0.3, 6e-3, wavelength * 0.5, sides="front" ) + position_vector = np.asarray([29e-3, 0.0, 0]) rotation_vector1 = np.radians(np.asarray([0.0, 90.0, 0.0])) -scatter_points = GF.open3drotate( +scatter_points = GF.mesh_rotate( scatter_points, - o3d.geometry.TriangleMesh.get_rotation_matrix_from_xyz(rotation_vector1), + rotation_vector1 ) -reflectorplate = GF.open3drotate( +reflectorplate = GF.mesh_rotate( reflectorplate, - o3d.geometry.TriangleMesh.get_rotation_matrix_from_xyz(rotation_vector1), + rotation_vector1 ) -reflectorplate.translate(position_vector, relative=True) -scatter_points.translate(position_vector, relative=True) +reflectorplate = GF.translate_mesh(reflectorplate,position_vector) +scatter_points = GF.translate_mesh(scatter_points,position_vector) # %% # Specify Reflection Angle @@ -110,13 +106,12 @@ plate_orientation_angle = 45.0 rotation_vector = np.radians(np.asarray([0.0, 0.0, plate_orientation_angle])) -scatter_points = GF.open3drotate( +scatter_points = GF.mesh_rotate( scatter_points, - o3d.geometry.TriangleMesh.get_rotation_matrix_from_xyz(rotation_vector), -) -reflectorplate = GF.open3drotate( + rotation_vector) +reflectorplate = GF.mesh_rotate( reflectorplate, - o3d.geometry.TriangleMesh.get_rotation_matrix_from_xyz(rotation_vector), + rotation_vector ) from lyceanem.base_classes import structures @@ -129,21 +124,8 @@ # Use open3d function :func:`open3d.visualization.draw_geometries` to visualise the scene and ensure that all the # relavent sources and scatter points are correct. Point normal vectors can be displayed by pressing 'n' while the # window is open. -mesh_frame = o3d.geometry.TriangleMesh.create_coordinate_frame( - size=0.5, origin=[0, 0, 0] -) -o3d.visualization.draw_geometries( - [ - transmitting_antenna_surface_coords, - receiving_antenna_surface_coords, - scatter_points, - reflectorplate, - mesh_frame, - receive_horn_structure, - transmit_horn_structure, - ] -) -# %% + + # .. image:: ../_static/03_frequency_domain_channel_model_picture_01.png # @@ -176,6 +158,7 @@ scattering=1, ) + # %% # Examine Scattering # --------------------- @@ -184,6 +167,8 @@ # through different angles from 0 to 90 degrees in 1 degree steps. + + angle_values = np.linspace(0, 90, 91) angle_increment = np.diff(angle_values)[0] responsex = np.zeros((len(angle_values)), dtype="complex") @@ -195,27 +180,16 @@ rotation_vector = np.radians( np.asarray([0.0, 0.0, plate_orientation_angle + angle_increment]) ) -scatter_points = GF.open3drotate( - scatter_points, - o3d.geometry.TriangleMesh.get_rotation_matrix_from_xyz(rotation_vector), -) -reflectorplate = GF.open3drotate( - reflectorplate, - o3d.geometry.TriangleMesh.get_rotation_matrix_from_xyz(rotation_vector), -) +scatter_points = GF.mesh_rotate(scatter_points,rotation_vector) +reflectorplate = GF.mesh_rotate(reflectorplate,rotation_vector) + from tqdm import tqdm for angle_inc in tqdm(range(len(angle_values))): rotation_vector = np.radians(np.asarray([0.0, 0.0, angle_increment])) - scatter_points = GF.open3drotate( - scatter_points, - o3d.geometry.TriangleMesh.get_rotation_matrix_from_xyz(rotation_vector), - ) - reflectorplate = GF.open3drotate( - reflectorplate, - o3d.geometry.TriangleMesh.get_rotation_matrix_from_xyz(rotation_vector), - ) + scatter_points = GF.mesh_rotate(scatter_points,rotation_vector) + reflectorplate = GF.mesh_rotate(reflectorplate,rotation_vector) Ex, Ey, Ez = FD.calculate_scattering( aperture_coords=transmitting_antenna_surface_coords, sink_coords=receiving_antenna_surface_coords, diff --git a/docs/examples/rayhits.npy b/docs/examples/rayhits.npy new file mode 100644 index 0000000000000000000000000000000000000000..b9b0f2bd8e951d2872d91f149fd5d2296ae567d7 GIT binary patch literal 9331328 zcmeFtp$fuK0EOXMeTv(z!omhJM9enDVlc^Y8wPQ5Cl>K3d|~G+n7_ZB6Ti>yu-zXg z*)w~^rX9{Hu0mXQ%b17Q_34r7+o?}Y`};Tbb!f+bxYYM{+_SQ*szp)c^E|x6UrjR+ zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PFZDp#uQ` z0000W|JO!HaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!$24jl^s0000C^0%JFu0qIw0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>Yx5 F4+P`%8_fU! literal 0 HcmV?d00001 diff --git a/docs/examples/rect_reflectorref.ply b/docs/examples/rect_reflectorref.ply new file mode 100644 index 0000000000000000000000000000000000000000..6aa4f9da8beec51b41324e07458e7adee972e1ab GIT binary patch literal 881 zcmZ`#y-ve05DtVNDNkXsA|Xm8#DX%w&dd}!$(2TOoyc`i!UQW~>;o|H04xj$i4I5z z-h;htEFJK89rT#_>Z zR60Ugxvv_w8vj8m@ta2I@ju74P@u@$d8b-HaOFK*AL&7Q|NR zK#WSb=9bW1%-mu_jLHf~t70u?Ud%u`i?u2i#8yFwzvX$}uCi@qI@xIozVhCtGMw-+ pz>ZFo_coMa(Z>L1+XR`AQFnBJiEf(?CfGqnt%J0h2!EI$$v-XWMV$Zu literal 0 HcmV?d00001 diff --git a/docs/examples/reference_reflectorplate.ply b/docs/examples/reference_reflectorplate.ply new file mode 100644 index 0000000000000000000000000000000000000000..6aa4f9da8beec51b41324e07458e7adee972e1ab GIT binary patch literal 881 zcmZ`#y-ve05DtVNDNkXsA|Xm8#DX%w&dd}!$(2TOoyc`i!UQW~>;o|H04xj$i4I5z z-h;htEFJK89rT#_>Z zR60Ugxvv_w8vj8m@ta2I@ju74P@u@$d8b-HaOFK*AL&7Q|NR zK#WSb=9bW1%-mu_jLHf~t70u?Ud%u`i?u2i#8yFwzvX$}uCi@qI@xIozVhCtGMw-+ pz>ZFo_coMa(Z>L1+XR`AQFnBJiEf(?CfGqnt%J0h2!EI$$v-XWMV$Zu literal 0 HcmV?d00001 diff --git a/lyceanem/base_classes.py b/lyceanem/base_classes.py index 9a84380..11260dc 100644 --- a/lyceanem/base_classes.py +++ b/lyceanem/base_classes.py @@ -1,7 +1,7 @@ import copy import numpy as np -import open3d as o3d +import meshio from scipy import interpolate as sp from scipy.spatial.transform import Rotation as R import pyvista as pv @@ -47,7 +47,7 @@ def rotate_matrix(self, new_axes, replace=True): class points(object3d): """ Structure class to store information about the geometry and materials in the environment, holding the seperate - shapes as :class:`open3d.geometry.TriangleMesh` data structures. Everything in the class will be considered an integrated unit, rotating and moving together. + shapes as :meshio.Mesh data structures. Everything in the class will be considered an integrated unit, rotating and moving together. This class will be developed to include material parameters to enable more complex modelling. Units should be SI, metres @@ -93,7 +93,7 @@ def add_points(self, new_points): Parameters ----------- - new_points : :class:`open3d.geometry.PointCloud` + new_points : :class:`meshio.Mesh with no cells` the point cloud to be added to the point cloud collection Returns @@ -119,21 +119,22 @@ def create_points(self, points, normals): ------- None """ - new_point_cloud = o3d.geometry.PointCloud() - new_point_cloud.points = o3d.utility.Vector3dVector(points.reshape(-1, 3)) - new_point_cloud.normals = o3d.utility.Vector3dVector(normals.reshape(-1, 3)) + mesh_vertices = points.reshape(-1, 3) + mesh_normals = normals.reshape(-1, 3) + new_point_cloud = meshio.Mesh(points=mesh_vertices, cells=[], point_data={"normals": mesh_normals}) + self.add_points(new_point_cloud) def rotate_points( - self, rotation_matrix, rotation_centre=np.zeros((3, 1), dtype=np.float32) + self, rotation_vector, rotation_centre=np.zeros((3, 1), dtype=np.float32) ): """ rotates the components of the structure around a common point, default is the origin Parameters ---------- - rotation_matrix : open3d rotation matrix - o3d.geometry.TriangleMesh.get_rotation_matrix_from_xyz(rotation_vector) + rotation_matrix : open3d rotation vector + 3,1numpy array rotation_centre : 1*3 numpy float array centre of rotation for the structures @@ -143,9 +144,10 @@ def rotate_points( """ # warning, current commond just rotates around the origin, and until Open3D can be brought up to the # latest version without breaking BlueCrystal reqruiements, this will require additional code. + assert rotation_vector.shape == (3,) for item in range(len(self.points)): - self.point[item] = GF.open3drotate( - self.point[item], rotation_matrix, rotation_centre + self.point[item] = GF.mesh_rotate( + self.point[item], rotation_vector, rotation_centre ) def translate_points(self, vector): @@ -162,7 +164,7 @@ def translate_points(self, vector): None """ for item in range(len(self.points)): - self.points[item].translate(vector) + self.points[item] = GF.translate_mesh(self.points[item], vector) def export_points(self, point_index=None): """ @@ -173,20 +175,46 @@ def export_points(self, point_index=None): combined points """ if point_index == None: - combined_points = o3d.geometry.PointCloud() + for item in range(len(self.points)): - combined_points = combined_points + self.points[item] + if item == 0: + points = np.array(self.points[item].points) + points = np.append(points, self.points[item].points, axis=0) + point_data = np.array(len(self.points[0].point_data), points.shape[0]) + for data in self.points[0].point_data: + pointssofar = 0 + for item in range(1,len(self.points)): + point_data_element = np.array(self.points[item][data]) + point_data[pointssofar:point_data_element.shape[0]] = point_data_element + pointssofar+= point_data_element.shape[0] + points = GF.mesh_transform(points, self.pose, False) + + + combinded_points = meshio.Mesh(points, point_data=point_data) + + - combined_points.transform(self.pose) else: - combined_points = o3d.geometry.PointCloud() for item in point_index: - combined_points = combined_points + self.points[item] + if item == 0: + points = np.array(self.points[item].points) + points = np.append(points, self.points[item].points, axis=0) + point_data = np.array(len(self.points[0].point_data), points.shape[0]) + for data in self.points[0].point_data: + pointssofar = 0 + for item in point_index: + point_data_element = np.array(self.points[item][data]) + point_data[pointssofar:point_data_element.shape[0]] = point_data_element + pointssofar+= point_data_element.shape[0] + + points = GF.mesh_transform(points, self.pose, False) + + combinded_points = meshio.Mesh(points, point_data=point_data) - combined_points.transform(self.pose) - return combined_points + + return combinded_points class structures(object3d): @@ -202,7 +230,7 @@ class structures(object3d): def __init__(self, solids=None): super().__init__() - # solids is a list of open3D :class:`open3d.geometry.TriangleMesh` structures + # solids is a list of open3D :class:`meshio.Mesh` structures if solids == None: # no points provided at creation, print("Empty Object Created, please add solids") @@ -268,7 +296,7 @@ def rotate_structures( """ for item in range(len(self.solids)): - self.solids[item] = GF.open3drotate( + self.solids[item] = GF.mesh_rotate( self.solids[item], rotation_matrix, rotation_centre ) @@ -286,7 +314,7 @@ def translate_structures(self, vector): None """ for item in range(len(self.solids)): - self.solids[item].translate(vector, relative=True) + self.solids[item] = GF.translate_mesh(self.solids[item],vector, relative=True) def export_vertices(self, structure_index=None): """ @@ -362,7 +390,9 @@ def triangles_base_raycaster(self): triangles = np.empty((0), dtype=base_types.triangle_t) for item in range(len(self.solids)): temp_object = copy.deepcopy(self.solids[item]) - temp_object.transform(self.pose) + points = temp_object.points + points = GF.mesh_transform(points, self.pose, False) + triangles = np.append(triangles, RF.convertTriangles(temp_object)) return triangles @@ -397,8 +427,7 @@ def rotate_antenna( Parameters ---------- - rotation_matrix : open3d rotation matrix - o3d.geometry.TriangleMesh.get_rotation_matrix_from_xyz(rotation_vector) + rotation_matrix : 3*3 numpy array rotation_centre : 1*3 numpy float array centre of rotation for the structures @@ -406,7 +435,7 @@ def rotate_antenna( -------- None """ - self.antenna_xyz = GF.open3drotate( + self.antenna_xyz = GF.mesh_rotate( self.antenna_xyz, rotation_matrix, rotation_centre ) # translate to the rotation centre, then rotate around origin @@ -414,16 +443,7 @@ def rotate_antenna( temp_origin = np.matmul(rotation_matrix, temp_origin) self.pose[:3, 3] = temp_origin.ravel() + rotation_centre.ravel() self.pose[:3, :3] = np.matmul(rotation_matrix, self.pose[:3, :3]) - # for item in range(len(self.structures.solids)): - # if (self.structures.solids[item] is not None): - # self.structures.solids[item] = GF.open3drotate( - # self.structures.solids[item], rotation_matrix, rotation_centre - # ) - # for item in range(len(self.points.points)): - # if (self.points.points[item] is not None): - # self.points.points[item] = GF.open3drotate( - # self.points.points[item], rotation_matrix, rotation_centre - # ) + def translate_antenna(self, vector): """ diff --git a/lyceanem/electromagnetics/empropagation.py b/lyceanem/electromagnetics/empropagation.py index dd5492a..637ea00 100644 --- a/lyceanem/electromagnetics/empropagation.py +++ b/lyceanem/electromagnetics/empropagation.py @@ -1148,6 +1148,12 @@ def freqdomainkernal( ray_component[0] *= loss ray_component[1] *= loss ray_component[2] *= loss + print("hi from thread", cu_ray_num) + + + if source_sink_index[cu_ray_num, 0] == 0 & source_sink_index[cu_ray_num, 1] == 36: + print( "efield via scatter", network_index[cu_ray_num, 1], (float)(ray_component[0].real), (float)(ray_component[1].real), (float)(ray_component[2].real)) + # print(ray_component[0].real,ray_component[1].real,ray_component[2].real) # add real components cuda.atomic.add( @@ -2391,91 +2397,6 @@ def IsoGPUFreqDomain(source_num, sink_num, full_index, point_information, wavele return scattering_network_comp -def EMWrapperMerged( - source_num, - sink_num, - point_informationv2, - full_index, - scattering_coefficient, - wavelength, -): - # diff_sources=np.size(np.unique(full_index[:,0])) - paths, polar_coefficients = EMGPUJointPathLengthandPolar( - source_num, sink_num, full_index, point_informationv2 - ) - # polar_coefficients=EMGPUPolarMixing(source_num,sink_num,full_index,point_informationv2) - # ray_components=EM.EMGPUWrapper(num_sources,num_sinks,full_index,point_informationv2,wavelength) - depthslice, scatter_index = targettingindex(full_index) - loss = pathloss(paths, wavelength) * ( - np.abs(np.power(scattering_coefficient, scatter_index - 1)) - * np.exp(-1j * np.pi) - ) - full_rays = loss.reshape(loss.shape[0], 1) * polar_coefficients - if full_index.shape[1] == 2: - depth_slicelos = full_index - scatter_map2 = RF.scatter_net_sortEM( - source_num, - sink_num, - np.zeros((source_num, sink_num, 3, 1), dtype=np.complex64), - depth_slicelos, - full_rays, - 0, - ) - elif full_index.shape[1] == 3: - depth_slicelos = depthslice[scatter_index == 1, :] - depth_slicebounce = depthslice[scatter_index == 2, :] - scatter_map2 = RF.scatter_net_sortEM( - source_num, - sink_num, - np.zeros((source_num, sink_num, 3, 2), dtype=np.complex64), - depth_slicelos, - full_rays[scatter_index == 1, :], - 0, - ) - scatter_map2 = RF.scatter_net_sortEM( - source_num, - sink_num, - scatter_map2, - depth_slicebounce, - full_rays[scatter_index == 2, :], - 1, - ) - elif full_index.shape[1] == 4: - depth_slicelos = depthslice[scatter_index == 1, :] - depth_slicebounce1 = depthslice[scatter_index == 2, :] - depth_slicebounce2 = depthslice[scatter_index == 3, :] - scatter_map2 = RF.scatter_net_sortEM( - source_num, - sink_num, - np.zeros((source_num, sink_num, 3, 3), dtype=np.complex64), - depth_slicelos, - full_rays[scatter_index == 1, :], - 0, - ) - scatter_map2 = RF.scatter_net_sortEM( - source_num, - sink_num, - scatter_map2, - depth_slicebounce1, - full_rays[scatter_index == 2, :], - 1, - ) - scatter_map2 = RF.scatter_net_sortEM( - source_num, - sink_num, - scatter_map2, - depth_slicebounce2, - full_rays[scatter_index == 3, :], - 1, - ) - - # deallocate memory on gpu - ctx = cuda.current_context() - deallocs = ctx.deallocations - deallocs.clear() - return scatter_map2 - - # @njit def time_indexing(arr, starting_num, arr_length, fill_value=0.0): if arr_length < arr.shape[0]: @@ -3869,483 +3790,7 @@ def pathlossv2(lengths, wavelength): return channel -# @njit(cache=True, nogil=True) -def losChannel( - source_point, - source_normal, - source_weight, - source_information, - sink_point, - sink_normal, - sink_weight, - sink_information, - scattering_coefficient, - wavelength, -): - """ - - Parameters - ---------- - source_point : 1*3 float - source coordinates (xyz) - source_normal : 1*3 float - source normal (xyz) - sink_point : 1*3 float - sink coordinates (xyz) - sink_normal : 1*3 float - sink normal (xyz) - channel : 1*3 complex - excitation function in global reference frame Ex,Ey,Ez - wavelength : 1 float - wavelength of interest - - Need to define stokes parameters of each vector, thus turning all weights into stokes vectors - Returns - ------- - channel : as defined - - """ - wave_vector = (2 * np.pi) / wavelength - channel = np.zeros((3), dtype=np.complex64) - outgoing_dir = np.zeros((3), dtype=np.float32) - lengths = np.zeros((1), dtype=np.float32) - outgoing_dir[0], outgoing_dir[1], outgoing_dir[2], lengths = RF.calc_dv( - source_point, sink_point - ) - if lengths == 0: - loss1 = 1.0 - else: - loss1 = (np.exp(lengths * wave_vector * 1j)) * ( - wavelength / (4 * np.pi * (lengths)) - ) - ray_field = ( - launchtransform(source_normal, outgoing_dir, source_weight, source_information) - * scattering_coefficient - ) - channel = ray_field * sink_weight * loss1 - - return channel - - -@njit(cache=True, nogil=True) -def losChannelv2( - source_point, - source_normal, - source_weight, - source_information, - sink_point, - sink_normal, - sink_weight, - sink_information, - wavelength, -): - """ - - Parameters - ---------- - source_point : 1*3 float - source coordinates (xyz) - source_normal : 1*3 float - source normal (xyz) - sink_point : 1*3 float - sink coordinates (xyz) - sink_normal : 1*3 float - sink normal (xyz) - channel : 1*3 complex - excitation function in global reference frame Ex,Ey,Ez - wavelength : 1 float - wavelength of interest - - Need to define stokes parameters of each vector, thus turning all weights into stokes vectors - Returns - ------- - channel : as defined - - """ - wave_vector = (2 * np.pi) / wavelength - channel = np.zeros((3), dtype=np.complex64) - outgoing_dir = np.zeros((3), dtype=np.float32) - lengths = np.zeros((1), dtype=np.float32) - outgoing_dir[0], outgoing_dir[1], outgoing_dir[2], lengths = RF.calc_dv( - source_point, sink_point - ) - if lengths == 0: - loss1 = 1.0 - else: - loss1 = (np.exp(lengths * wave_vector * 1j)) * ( - wavelength / (4 * np.pi * (lengths)) - ) - ray_field = launchtransform( - source_normal, outgoing_dir, source_weight, source_information - ) # *ray_phase - channel = ray_field * sink_weight * loss1 - - return channel, lengths / scipy.constants.c - - -@njit(cache=True, nogil=True) -def losplus1Channel( - source_point, - source_normal, - source_weight, - source_information, - scatter_point, - scatter_normal, - scatter_weight, - scatter_information, - sink_point, - sink_normal, - sink_weight, - sink_information, - scattering_coefficient, - wavelength, -): - """ - - Parameters - ---------- - source_point : 1*3 float - source coordinates (xyz) - source_normal : 1*3 float - source normal (xyz) - sink_point : 1*3 float - sink coordinates (xyz) - sink_normal : 1*3 float - sink normal (xyz) - channel : 1*2 complex - channel propagation coefficients for local h, local v from the source to the sink - wavelength : 1 float - wavelength of interest - - Returns - ------- - channel : as defined - - """ - wave_vector = (2 * np.pi) / wavelength - channel = np.zeros((3), dtype=np.complex64) - outgoing_dir = np.zeros((3), dtype=np.float32) - scatter_outgoing_dir = np.zeros((3), dtype=np.float32) - lengths = np.zeros((1), dtype=np.float32) - lengths2 = np.zeros((1), dtype=np.float32) - outgoing_dir[0], outgoing_dir[1], outgoing_dir[2], lengths = RF.calc_dv( - source_point, scatter_point - ) - ray_field = ( - launchtransform(source_normal, outgoing_dir, source_weight, source_information) - * scattering_coefficient - ) - ( - scatter_outgoing_dir[0], - scatter_outgoing_dir[1], - scatter_outgoing_dir[2], - lengths2, - ) = RF.calc_dv(scatter_point, sink_point) - if lengths == 0 or lengths2 == 0: - loss2 = 1.0 - else: - loss2 = (np.exp((lengths + lengths2) * wave_vector * 1j)) * ( - wavelength / (4 * np.pi * (lengths + lengths2)) - ) - - channel = ( - launchtransform( - scatter_normal, - scatter_outgoing_dir, - ray_field * sink_weight, - scatter_information, - source=False, - arrival_vector=outgoing_dir * -1, - ) - * loss2 - * scattering_coefficient - ) - - return channel - - -@njit(cache=True, nogil=True) -def losplus1Channelv2( - source_point, - source_normal, - source_weight, - source_information, - scatter_point, - scatter_normal, - scatter_weight, - scatter_information, - sink_point, - sink_normal, - sink_weight, - sink_information, - wavelength, -): - """ - - Parameters - ---------- - source_point : 1*3 float - source coordinates (xyz) - source_normal : 1*3 float - source normal (xyz) - sink_point : 1*3 float - sink coordinates (xyz) - sink_normal : 1*3 float - sink normal (xyz) - channel : 1*2 complex - channel propagation coefficients for local h, local v from the source to the sink - wavelength : 1 float - wavelength of interest - - Returns - ------- - channel : as defined - - """ - wave_vector = (2 * np.pi) / wavelength - channel = np.zeros((3), dtype=np.complex64) - outgoing_dir = np.zeros((3), dtype=np.float32) - scatter_outgoing_dir = np.zeros((3), dtype=np.float32) - lengths = np.zeros((1), dtype=np.float32) - lengths2 = np.zeros((1), dtype=np.float32) - outgoing_dir[0], outgoing_dir[1], outgoing_dir[2], lengths = RF.calc_dv( - source_point, scatter_point - ) - ray_field = launchtransform( - source_normal, outgoing_dir, source_weight, source_information - ) # *ray_phase - ( - scatter_outgoing_dir[0], - scatter_outgoing_dir[1], - scatter_outgoing_dir[2], - lengths2, - ) = RF.calc_dv(scatter_point, sink_point) - if lengths == 0 or lengths2 == 0: - loss2 = 1.0 - else: - loss2 = (np.exp((lengths + lengths2) * wave_vector * 1j)) * ( - wavelength / (4 * np.pi * (lengths + lengths2)) - ) - - channel = ( - launchtransform( - scatter_normal, - scatter_outgoing_dir, - ray_field * sink_weight, - scatter_information, - source=False, - arrival_vector=outgoing_dir * -1, - ) - * loss2 - ) - - return channel, (lengths + lengths2) / scipy.constants.c - - -@njit(cache=True, nogil=True) -def losplus2Channel( - source_point, - source_normal, - source_weight, - source_information, - scatter_point, - scatter_normal, - scatter_weight, - scatter_information, - scatter_point2, - scatter_normal2, - scatter_weight2, - scatter_information2, - sink_point, - sink_normal, - sink_weight, - sink_information, - scattering_coefficient, - wavelength, -): - """ - - Parameters - ---------- - source_point : 1*3 float - source coordinates (xyz) - source_normal : 1*3 float - source normal (xyz) - sink_point : 1*3 float - sink coordinates (xyz) - sink_normal : 1*3 float - sink normal (xyz) - channel : 1*2 complex - channel propagation coefficients for local h, local v from the source to the sink - wavelength : 1 float - wavelength of interest - - Returns - ------- - channel : as defined - - """ - wave_vector = (2 * np.pi) / wavelength - channel = np.zeros((3), dtype=np.complex64) - outgoing_dir = np.zeros((3), dtype=np.float32) - scatter_outgoing_dir = np.zeros((3), dtype=np.float32) - scatter_outgoing_dir2 = np.zeros((3), dtype=np.float32) - lengths = np.zeros((1), dtype=np.float32) - lengths2 = np.zeros((1), dtype=np.float32) - lengths3 = np.zeros((1), dtype=np.float32) - # scatter from source to point 1 - outgoing_dir[0], outgoing_dir[1], outgoing_dir[2], lengths = RF.calc_dv( - source_point, scatter_point - ) - ray_field1 = ( - launchtransform(source_normal, outgoing_dir, source_weight, source_information) - * scattering_coefficient - ) - # scatter from point 1 to point 2 - ( - scatter_outgoing_dir[0], - scatter_outgoing_dir[1], - scatter_outgoing_dir[2], - lengths2, - ) = RF.calc_dv(scatter_point, scatter_point2) - ray_field2 = ( - launchtransform( - scatter_normal, - scatter_outgoing_dir, - ray_field1 * scatter_weight, - scatter_information, - source=False, - arrival_vector=outgoing_dir * -1, - ) - * scattering_coefficient - ) - ( - scatter_outgoing_dir2[0], - scatter_outgoing_dir2[1], - scatter_outgoing_dir2[2], - lengths3, - ) = RF.calc_dv(scatter_point2, sink_point) - if lengths == 0 or lengths2 == 0 or lengths3 == 0: - loss3 = 1.0 - else: - loss3 = (np.exp((lengths + lengths2 + lengths3) * wave_vector * 1j)) * ( - wavelength / (4 * np.pi * (lengths + lengths2 + lengths3)) - ) - - channel = ( - launchtransform( - scatter_normal2, - scatter_outgoing_dir, - ray_field2 * sink_weight, - scatter_information2, - source=False, - arrival_vector=scatter_outgoing_dir * -1, - ) - * loss3 - * scattering_coefficient - ) - - return channel - - -@njit(cache=True, nogil=True) -def losplus2Channelv2( - source_point, - source_normal, - source_weight, - source_information, - scatter_point, - scatter_normal, - scatter_weight, - scatter_information, - scatter_point2, - scatter_normal2, - scatter_weight2, - scatter_information2, - sink_point, - sink_normal, - sink_weight, - sink_information, - wavelength, -): - """ - - Parameters - ---------- - source_point : 1*3 float - source coordinates (xyz) - source_normal : 1*3 float - source normal (xyz) - sink_point : 1*3 float - sink coordinates (xyz) - sink_normal : 1*3 float - sink normal (xyz) - channel : 1*2 complex - channel propagation coefficients for local h, local v from the source to the sink - wavelength : 1 float - wavelength of interest - - Returns - ------- - channel : as defined - - """ - wave_vector = (2 * np.pi) / wavelength - channel = np.zeros((3), dtype=np.complex64) - outgoing_dir = np.zeros((3), dtype=np.float32) - scatter_outgoing_dir = np.zeros((3), dtype=np.float32) - scatter_outgoing_dir2 = np.zeros((3), dtype=np.float32) - lengths = np.zeros((1), dtype=np.float32) - lengths2 = np.zeros((1), dtype=np.float32) - lengths3 = np.zeros((1), dtype=np.float32) - # scatter from source to point 1 - outgoing_dir[0], outgoing_dir[1], outgoing_dir[2], lengths = RF.calc_dv( - source_point, scatter_point - ) - ray_field1 = launchtransform( - source_normal, outgoing_dir, source_weight, source_information - ) # *ray_phase - # scatter from point 1 to point 2 - ( - scatter_outgoing_dir[0], - scatter_outgoing_dir[1], - scatter_outgoing_dir[2], - lengths2, - ) = RF.calc_dv(scatter_point, scatter_point2) - ray_field2 = launchtransform( - scatter_normal, - scatter_outgoing_dir, - ray_field1 * scatter_weight, - scatter_information, - source=False, - arrival_vector=outgoing_dir * -1, - ) - ( - scatter_outgoing_dir2[0], - scatter_outgoing_dir2[1], - scatter_outgoing_dir2[2], - lengths3, - ) = RF.calc_dv(scatter_point2, sink_point) - if lengths == 0 or lengths2 == 0 or lengths3 == 0: - loss3 = 1.0 - else: - loss3 = (np.exp((lengths + lengths2 + lengths3) * wave_vector * 1j)) * ( - wavelength / (4 * np.pi * (lengths + lengths2 + lengths3)) - ) - - channel = ( - launchtransform( - scatter_normal2, - scatter_outgoing_dir, - ray_field2 * sink_weight, - scatter_information2, - source=False, - arrival_vector=scatter_outgoing_dir * -1, - ) - * loss3 - ) - return channel, (lengths + lengths2 + lengths3) / scipy.constants.c @njit(cache=True, nogil=True) diff --git a/lyceanem/geometry/geometryfunctions.py b/lyceanem/geometry/geometryfunctions.py index 0747dbf..f1c9c8c 100644 --- a/lyceanem/geometry/geometryfunctions.py +++ b/lyceanem/geometry/geometryfunctions.py @@ -41,7 +41,7 @@ def tri_centroids(triangle_mesh): centroid_cloud = meshio.Mesh(points=centroids, cells=[], point_data=triangle_mesh.cell_data) return centroids, centroid_cloud -def mesh_rotate(mesh, rotation, rotation_centre=np.zeros((3, 1), dtype=np.float32)): +def mesh_rotate(mesh, rotation, rotation_centre=np.zeros((1, 3), dtype=np.float32)): """ Rotate a mesh by a given rotation vector about a given center. """ @@ -54,6 +54,7 @@ def mesh_rotate(mesh, rotation, rotation_centre=np.zeros((3, 1), dtype=np.float3 rotated_points = r.apply(mesh.points - rotation_centre) + rotation_centre cell_data = mesh.cell_data point_data = mesh.point_data + if 'normals' in mesh.point_data: #rotate normals cloud @@ -65,10 +66,39 @@ def mesh_rotate(mesh, rotation, rotation_centre=np.zeros((3, 1), dtype=np.float3 normals = mesh.cell_data['normals'] rotated_normals = r.apply(normals) cell_data['normals'] = rotated_normals + if 'nx' in mesh.point_data and 'ny' in mesh.point_data and 'nz' in mesh.point_data: + #rotate normals cloud + normals = np.array([mesh.point_data['nx'], mesh.point_data['ny'], mesh.point_data['nz']]).T + rotated_normals = r.apply(normals) + point_data['nx'] = rotated_normals[:, 0] + point_data['ny'] = rotated_normals[:, 1] + point_data['nz'] = rotated_normals[:, 2] + if 'nx' in mesh.cell_data and 'ny' in mesh.cell_data and 'nz' in mesh.cell_data: + #rotate normals cloud + normals = np.array([mesh.cell_data['nx'], mesh.cell_data['ny'], mesh.cell_data['nz']]).T + rotated_normals = r.apply(normals) + cell_data['nx'] = rotated_normals[:, 0] + cell_data['ny'] = rotated_normals[:, 1] + cell_data['nz'] = rotated_normals[:, 2] + mesh_return = meshio.Mesh(points=rotated_points, cells=mesh.cells) + mesh_return.point_data = point_data + mesh_return.cell_data = cell_data - return meshio.Mesh(points=rotated_points, cells=mesh.cells, point_data=point_data, cell_data=cell_data) + return mesh_return + +def mesh_transform(array, transform_matrix, rotate_only): + for i in range(array.shape[0]): + point_dummy = np.ones((4,)) + if rotate_only: + point_dummy[3] = 0 + point_dummy[:3] = array[i,:] + point_dummy = np.matmul(transform_matrix, point_dummy) + array[i,:] = point_dummy[:3] + return array + + def mesh_conversion(conversion_object): """ Convert the provide file object into triangle_t format @@ -186,6 +216,18 @@ def elevationtotheta(el): return theta +def translate_mesh(mesh, translation_vector): + """ + Translate a mesh by a given translation vector. + """ + translated_points = mesh.points + translation_vector + cell_data = mesh.cell_data + point_data = mesh.point_data + mesh_return = meshio.Mesh(points=translated_points, cells=mesh.cells) + mesh_return.point_data = point_data + mesh_return.cell_data = cell_data + return mesh_return + @vectorize(["(float32(float32))", "(float64(float64))"]) def thetatoelevation(theta): diff --git a/lyceanem/geometry/targets.py b/lyceanem/geometry/targets.py index b05352b..ff1b1b1 100755 --- a/lyceanem/geometry/targets.py +++ b/lyceanem/geometry/targets.py @@ -3,7 +3,8 @@ import copy import numpy as np -import open3d as o3d +import meshio +import pyvista as pv import scipy.stats import solid as sd from importlib_resources import files @@ -13,6 +14,8 @@ from ..geometry import geometryfunctions as GF from ..raycasting import rayfunctions as RF from ..utility import math_functions as math_functions +import meshio + EPSILON = 1e-6 # how close to zero do we consider zero? @@ -28,7 +31,7 @@ def NasaAlmond(resolution="quarter"): Returns ------- - NasaAlmond : o3d triangle mesh + NasaAlmond : meshio triangle mesh the physical structure of the nasa almond NasaAlmond_points : o3d points the mesh points for scattering @@ -38,19 +41,26 @@ def NasaAlmond(resolution="quarter"): stream = files("lyceanem.geometry.data").joinpath( "NasaAlmondHalfWavelengthv2.stl" ) - NasaAlmond = o3d.io.read_triangle_mesh(str(stream)) + NasaAlmond = meshio.read(str(stream)) + nasa = pv.read(str(stream)) + elif resolution == "quarter": stream = files("lyceanem.geometry.data").joinpath( "NasaAlmondQuarterWavelengthv2.stl" ) - NasaAlmond = o3d.io.read_triangle_mesh(str(stream)) + NasaAlmond = meshio.read(str(stream)) + nasa = pv.read(str(stream)) elif resolution == "tenth": stream = files("lyceanem.geometry.data").joinpath( "NasaAlmondTenthWavelengthv2.stl" ) - NasaAlmond = o3d.io.read_triangle_mesh(str(stream)) + NasaAlmond = meshio.read(str(stream)) + nasa = pv.read(str(stream)) + + nasa.compute_normals(inplace=True) + + NasaAlmond.point_data["normals"] = nasa.point_normals - NasaAlmond.compute_vertex_normals() # points=np.asarray(NasaAlmond.vertices) # normals=np.asarray(NasaAlmond.vertex_normals) _, scatter_cloud = GF.tri_centroids(NasaAlmond) @@ -242,7 +252,7 @@ def parabola(radius, focal_length, thickness, mesh_length, mesh="all"): # run openscad and export to stl converttostl() - parabola_mesh = o3d.io.read_triangle_mesh("temp.stl") + parabola_mesh = meshio.read("temp.stl") parabola_mesh.compute_vertex_normals() parabola_mesh.compute_triangle_normals() _, parabola_scatter_cloud = GF.tri_centroids(parabola_mesh) @@ -595,7 +605,7 @@ def meshed_pipe( # run(["openscad-nightly", "-o", "temp.stl", "temp.scad", "--export-format=binstl"]) converttostl() - structure = o3d.io.read_triangle_mesh("temp.stl") + structure = meshio.read("temp.stl") structure.compute_vertex_normals() scatter_cloud = RF.points2pointcloud(np.copy(test_faces)) scatter_cloud.normals = o3d.utility.Vector3dVector(np.copy(face_normals)) @@ -908,8 +918,8 @@ def meshed_cylinder( # run(["openscad-nightly", "-o", "temp.stl", "temp.scad", "--export-format=binstl"]) converttostl() - # structure = o3d.io.read_triangle_mesh("temp.stl") - temp_mesh = o3d.io.read_triangle_mesh("temp.stl") + # structure = meshio.read("temp.stl") + temp_mesh = meshio.read("temp.stl") temp_mesh.compute_vertex_normals() scatter_cloud = RF.points2pointcloud(np.copy(test_faces)) scatter_cloud.normals = o3d.utility.Vector3dVector(np.copy(face_normals)) @@ -1168,32 +1178,48 @@ def meshed_trapazoid(radius1, radius2, height, mesh_length, mesh="centres"): # run(["openscad-nightly", "-o", "temp.stl", "temp.scad", "--export-format=binstl"]) converttostl() - structure = o3d.io.read_triangle_mesh("temp.stl") + structure = meshio.read("temp.stl") structure.compute_vertex_normals() scatter_cloud = RF.points2pointcloud(np.copy(test_faces)) scatter_cloud.normals = o3d.utility.Vector3dVector(np.copy(face_normals)) return structure, scatter_cloud - def rectReflector(majorsize, minorsize, thickness): """ create a primative of the right size, assuming always orientated with normal aligned with zenith, and major axis with x, adjust position so the face is centred on (0,0,0) """ - - reflector1 = o3d.geometry.TriangleMesh.create_box(majorsize, minorsize, thickness) - translate_dist = np.array( - [-majorsize / 2.0, -minorsize / 2.0, -(thickness + EPSILON)] - ) - # fine_mesh=reflector1.subdivide_midpoint(3) - fine_mesh = reflector1 - fine_mesh.compute_vertex_normals() - fine_mesh.paint_uniform_color([0.79, 0.50, 0.24]) - fine_mesh.translate(translate_dist, relative=True) - - return fine_mesh + print("majorsize",majorsize) + print("minorsize",minorsize) + print("thickness",thickness) + + halfMajor = majorsize / 2.0 + halfMinor = minorsize / 2.0 + pv_mesh = pv.Box((-halfMajor, halfMajor, -halfMinor, halfMinor, -(thickness+EPSILON),- EPSILON)) + pv_mesh = pv_mesh.triangulate() + pv_mesh.compute_normals(inplace=True,consistent_normals=False) + triangles = np.reshape(np.array(pv_mesh.faces),(12,4)) + triangles = triangles[:,1:] + + mesh = meshio.Mesh(pv_mesh.points, {"triangle": triangles}) + + + mesh.point_data["nx"] = pv_mesh.point_normals[:,0] + + mesh.point_data["ny"] = pv_mesh.point_normals[:,1] + mesh.point_data["nz"] = pv_mesh.point_normals[:,2] + mesh.point_data["normals"] = pv_mesh.point_normals + mesh.cell_data["normals"] = pv_mesh.cell_normals + red = np.zeros((8, 1), dtype=np.float32) + green = np.ones((8, 1), dtype=np.float32) * 0.259 + blue = np.ones((8, 1), dtype=np.float32) * 0.145 + + mesh.point_data["red"] = red + mesh.point_data["green"] = green + mesh.point_data["blue"] = blue + return mesh def shapeTrapezoid(x_size, y_size, length, flare_angle): @@ -1236,7 +1262,7 @@ def shapeTrapezoid(x_size, y_size, length, flare_angle): length, ] ) - triangle_list = np.zeros((12, 3), dtype=np.int32) + triangle_list = np.zeros(((12, 3)), dtype=int) triangle_list[0, :] = [0, 1, 3] triangle_list[1, :] = [2, 3, 1] triangle_list[2, :] = [0, 3, 4] @@ -1249,12 +1275,28 @@ def shapeTrapezoid(x_size, y_size, length, flare_angle): triangle_list[9, :] = [5, 6, 1] triangle_list[10, :] = [4, 7, 5] triangle_list[11, :] = [6, 5, 7] - mesh = o3d.geometry.TriangleMesh() - mesh.vertices = o3d.utility.Vector3dVector(mesh_vertices) - mesh.triangles = o3d.utility.Vector3iVector(triangle_list) - mesh.compute_triangle_normals() - mesh.paint_uniform_color(np.array([0, 0.259, 0.145])) - + mesh = meshio.Mesh( + points=mesh_vertices, + cells=[("triangle", triangle_list)],) + print(mesh) + triangle_list = np.insert(triangle_list, 0, 3, axis=1) + + pv_mesh = pv.PolyData( mesh_vertices, faces = triangle_list) + pv_mesh.compute_normals(inplace=True,consistent_normals=False) + + + mesh.point_data["nx"] = pv_mesh.point_normals[0,:] + mesh.point_data["ny"] = pv_mesh.point_normals[1,:] + mesh.point_data["nz"] = pv_mesh.point_normals[2,:] + mesh.point_data["normals"] = pv_mesh.point_normals + mesh.cell_data["nx"] = pv_mesh.cell_normals[0,:] + red = np.zeros((8, 1), dtype=np.float32) + green = np.ones((8, 1), dtype=np.float32) * 0.259 + blue = np.ones((8, 1), dtype=np.float32) * 0.145 + + mesh.point_data["red"] = red + mesh.point_data["green"] = green + mesh.point_data["blue"] = blue return mesh @@ -1287,6 +1329,8 @@ def meshedReflector(majorsize, minorsize, thickness, grid_resolution, sides="all the populating surfaces """ + print("meshing reflector") + print("args", majorsize, minorsize, thickness) reflector = rectReflector(majorsize, minorsize, thickness) mesh_points = gridedReflectorPoints( majorsize, minorsize, thickness, grid_resolution, sides @@ -1950,13 +1994,14 @@ def meshedHorn( mesh_points : :class:`open3d.geometry.PointCloud` the source points for the horn aperture """ + print("HIHIH") structure = shapeTrapezoid( majorsize + (edge_width * 2), minorsize + (edge_width * 2), length, flare_angle ) mesh_points = gridedReflectorPoints( majorsize, minorsize, 1e-6, grid_resolution, sides ) - mesh_points.translate(np.asarray([0, 0, 1e-6])) + return structure, mesh_points @@ -2404,9 +2449,7 @@ def gridedReflectorPoints( np.append(source_normals, back_normals, axis=0), side_normals, axis=0 ) # mesh_normals=np.append(source_normals,back_normals,axis=0) - mesh_points = o3d.geometry.PointCloud() - mesh_points.points = o3d.utility.Vector3dVector(np.copy(mesh_vertices)) - mesh_points.normals = o3d.utility.Vector3dVector(np.copy(mesh_normals)) + elif sides == "front": x = np.linspace( -(majorsize / 2), @@ -2438,9 +2481,8 @@ def gridedReflectorPoints( mesh_vertices = source_coords mesh_normals = source_normals - mesh_points = o3d.geometry.PointCloud() - mesh_points.points = o3d.utility.Vector3dVector(np.copy(mesh_vertices)) - mesh_points.normals = o3d.utility.Vector3dVector(np.copy(mesh_normals)) + mesh_points = meshio.Mesh(points=mesh_vertices, cells=[], point_data={"normals": mesh_normals}) + return mesh_points @@ -2705,7 +2747,7 @@ def BullsEye(O2, n_rings, innerdia, period, ht, basethick, grid_resolution): # run(["openscad-nightly", "-o", "d.stl", "d.scad", "--export-format=binstl"]) converttostl() - solid = o3d.io.read_triangle_mesh("d.stl") + solid = meshio.read("d.stl") solid.compute_vertex_normals() # o3d.visualization.draw_geometries([test_structure]) diff --git a/lyceanem/models/frequency_domain.py b/lyceanem/models/frequency_domain.py index f028315..4da4cb8 100644 --- a/lyceanem/models/frequency_domain.py +++ b/lyceanem/models/frequency_domain.py @@ -1,7 +1,6 @@ import copy import numpy as np -import open3d as o3d from ..base_types import scattering_t from ..electromagnetics import empropagation as EM @@ -9,6 +8,7 @@ from ..geometry import targets as TL from ..raycasting import rayfunctions as RF from ..utility.math_functions import calc_dv_norm +import meshio def aperture_projection( @@ -143,17 +143,17 @@ def calculate_farfield( sinks, np.zeros((len(sinks), 3), dtype=np.float32), sink_normals, lengths ) sink_cloud = RF.points2pointcloud(sinks) - sink_cloud.normals = o3d.utility.Vector3dVector(sink_normals) + sink_cloud.point_data["normals"] = o3d.utility.Vector3dVector(sink_normals) num_sources = len(np.asarray(aperture_coords.points)) num_sinks = len(np.asarray(sink_cloud.points)) environment_triangles=GF.mesh_conversion(antenna_solid) if project_vectors: conformal_E_vectors = EM.calculate_conformalVectors( - desired_E_axis, np.asarray(aperture_coords.normals), antenna_axes + desired_E_axis, np.asarray(aperture_coords.point_data["normals"]), antenna_axes ) else: - if desired_E_axis.shape[0]==np.asarray(aperture_coords.normals).shape[0]: + if desired_E_axis.shape[0]==np.asarray(aperture_coords.point_data["normals"]).shape[0]: conformal_E_vectors=copy.deepcopy(desired_E_axis) else: conformal_E_vectors = np.repeat( @@ -169,8 +169,8 @@ def calculate_farfield( axis=0, ) unified_normals = np.append( - np.asarray(aperture_coords.normals).astype(np.float32), - np.asarray(sink_cloud.normals).astype(np.float32), + np.asarray(aperture_coords.point_data["normals"]).astype(np.float32), + np.asarray(sink_cloud.point_data["normals"]).astype(np.float32), axis=0, ) unified_weights = np.ones((unified_model.shape[0], 3), dtype=np.complex64) @@ -200,13 +200,13 @@ def calculate_farfield( aperture_coords.points ).astype(np.float32)[:, 2] point_informationv2[0:num_sources]["nx"] = np.asarray( - aperture_coords.normals + aperture_coords.point_data["normals"] ).astype(np.float32)[:, 0] point_informationv2[0:num_sources]["ny"] = np.asarray( - aperture_coords.normals + aperture_coords.point_data["normals"] ).astype(np.float32)[:, 1] point_informationv2[0:num_sources]["nz"] = np.asarray( - aperture_coords.normals + aperture_coords.point_data["normals"] ).astype(np.float32)[:, 2] # set position and velocity of sinks point_informationv2[num_sources : (num_sources + num_sinks)]["px"] = sinks[:, 0] @@ -247,11 +247,11 @@ def calculate_farfield( ) unified_normals = np.append( np.append( - np.asarray(aperture_coords.normals).astype(np.float32), - np.asarray(sink_cloud.normals).astype(np.float32), + np.asarray(aperture_coords.point_data["normals"]).astype(np.float32), + np.asarray(sink_cloud.point_data["normals"]).astype(np.float32), axis=0, ), - np.asarray(scatter_points.normals).astype(np.float32), + np.asarray(scatter_points.point_data["normals"]).astype(np.float32), axis=0, ) unified_weights = np.ones((unified_model.shape[0], 3), dtype=np.complex64) @@ -283,13 +283,13 @@ def calculate_farfield( aperture_coords.points ).astype(np.float32)[:, 2] point_informationv2[0:num_sources]["nx"] = np.asarray( - aperture_coords.normals + aperture_coords.point_data["normals"] ).astype(np.float32)[:, 0] point_informationv2[0:num_sources]["ny"] = np.asarray( - aperture_coords.normals + aperture_coords.point_data["normals"] ).astype(np.float32)[:, 1] point_informationv2[0:num_sources]["nz"] = np.asarray( - aperture_coords.normals + aperture_coords.point_data["normals"] ).astype(np.float32)[:, 2] # point_informationv2[0:num_sources]['ex']=unified_weights[0:num_sources,0] # point_informationv2[0:num_sources]['ey']=unified_weights[0:num_sources,1] @@ -320,13 +320,13 @@ def calculate_farfield( scatter_points.points ).astype(np.float32)[:, 2] point_informationv2[(num_sources + num_sinks) :]["nx"] = np.asarray( - scatter_points.normals + scatter_points.point_data["normals"] ).astype(np.float32)[:, 0] point_informationv2[(num_sources + num_sinks) :]["ny"] = np.asarray( - scatter_points.normals + scatter_points.point_data["normals"] ).astype(np.float32)[:, 1] point_informationv2[(num_sources + num_sinks) :]["nz"] = np.asarray( - scatter_points.normals + scatter_points.point_data["normals"] ).astype(np.float32)[:, 2] point_informationv2[:]["ex"] = unified_weights[:, 0] point_informationv2[:]["ey"] = unified_weights[:, 1] @@ -496,10 +496,11 @@ def calculate_scattering( if not multiE: if project_vectors: conformal_E_vectors = EM.calculate_conformalVectors( - desired_E_axis, np.asarray(aperture_coords.normals), antenna_axes + desired_E_axis, np.asarray(aperture_coords.point_data["normals"]), antenna_axes ) else: - if desired_E_axis.shape[0] == np.asarray(aperture_coords.normals).shape[0]: + print(aperture_coords) + if desired_E_axis.shape[0] == np.asarray(aperture_coords.point_data["normals"]).shape[0]: conformal_E_vectors = copy.deepcopy(desired_E_axis) else: conformal_E_vectors = np.repeat( @@ -508,10 +509,10 @@ def calculate_scattering( else: if project_vectors: conformal_E_vectors = EM.calculate_conformalVectors( - desired_E_axis, np.asarray(aperture_coords.normals), antenna_axes + desired_E_axis, np.asarray(aperture_coords.point_data["normals"]), antenna_axes ) else: - if desired_E_axis.shape[0] == np.asarray(aperture_coords.normals).shape[0]: + if desired_E_axis.shape[0] == np.asarray(aperture_coords.point_data["normals"]).shape[0]: conformal_E_vectors = copy.deepcopy(desired_E_axis) else: conformal_E_vectors = np.repeat( @@ -528,8 +529,8 @@ def calculate_scattering( axis=0, ) unified_normals = np.append( - np.asarray(aperture_coords.normals).astype(np.float32), - np.asarray(sink_coords.normals).astype(np.float32), + np.asarray(aperture_coords.point_data["normals"]).astype(np.float32), + np.asarray(sink_coords.point_data["normals"]).astype(np.float32), axis=0, ) unified_weights = np.ones((unified_model.shape[0], 3), dtype=np.complex64) @@ -555,13 +556,13 @@ def calculate_scattering( aperture_coords.points ).astype(np.float32)[:, 2] point_informationv2[0:num_sources]["nx"] = np.asarray( - aperture_coords.normals + aperture_coords.point_data["normals"] ).astype(np.float32)[:, 0] point_informationv2[0:num_sources]["ny"] = np.asarray( - aperture_coords.normals + aperture_coords.point_data["normals"] ).astype(np.float32)[:, 1] point_informationv2[0:num_sources]["nz"] = np.asarray( - aperture_coords.normals + aperture_coords.point_data["normals"] ).astype(np.float32)[:, 2] # set position and velocity of sinks point_informationv2[num_sources : (num_sources + num_sinks)]["px"] = np.asarray( @@ -574,13 +575,13 @@ def calculate_scattering( sink_coords.points ).astype(np.float32)[:, 2] point_informationv2[num_sources : (num_sources + num_sinks)]["nx"] = np.asarray( - sink_coords.normals + sink_coords.point_data["normals"] ).astype(np.float32)[:, 0] point_informationv2[num_sources : (num_sources + num_sinks)]["ny"] = np.asarray( - sink_coords.normals + sink_coords.point_data["normals"] ).astype(np.float32)[:, 1] point_informationv2[num_sources : (num_sources + num_sinks)]["nz"] = np.asarray( - sink_coords.normals + sink_coords.point_data["normals"] ).astype(np.float32)[:, 2] point_informationv2[:]["ex"] = unified_weights[:, 0] @@ -601,7 +602,7 @@ def calculate_scattering( if project_vectors: conformal_E_vectors = EM.calculate_conformalVectors( desired_E_axis[0, :].reshape(1, 3), - np.asarray(aperture_coords.normals).astype(np.float32), + np.asarray(aperture_coords.point_data["normals"]).astype(np.float32), ) else: conformal_E_vectors = np.repeat( @@ -613,7 +614,7 @@ def calculate_scattering( if project_vectors: conformal_E_vectors = EM.calculate_conformalVectors( desired_E_axis[0, :].reshape(1, 3), - np.asarray(aperture_coords.normals).astype(np.float32), + np.asarray(aperture_coords.point_data["normals"]).astype(np.float32), ) else: if desired_E_axis.size == 3: @@ -636,11 +637,11 @@ def calculate_scattering( ) unified_normals = np.append( np.append( - np.asarray(aperture_coords.normals).astype(np.float32), - np.asarray(sink_coords.normals).astype(np.float32), + np.asarray(aperture_coords.point_data["normals"]).astype(np.float32), + np.asarray(sink_coords.point_data["normals"]).astype(np.float32), axis=0, ), - np.asarray(scatter_points.normals).astype(np.float32), + np.asarray(scatter_points.point_data["normals"]).astype(np.float32), axis=0, ) unified_weights = np.ones((unified_model.shape[0], 3), dtype=np.complex64) @@ -669,13 +670,13 @@ def calculate_scattering( aperture_coords.points ).astype(np.float32)[:, 2] point_informationv2[0:num_sources]["nx"] = np.asarray( - aperture_coords.normals + aperture_coords.point_data["normals"] ).astype(np.float32)[:, 0] point_informationv2[0:num_sources]["ny"] = np.asarray( - aperture_coords.normals + aperture_coords.point_data["normals"] ).astype(np.float32)[:, 1] point_informationv2[0:num_sources]["nz"] = np.asarray( - aperture_coords.normals + aperture_coords.point_data["normals"] ).astype(np.float32)[:, 2] # point_informationv2[0:num_sources]['ex']=unified_weights[0:num_sources,0] # point_informationv2[0:num_sources]['ey']=unified_weights[0:num_sources,1] @@ -694,13 +695,13 @@ def calculate_scattering( # point_informationv2[num_sources:(num_sources+num_sinks)]['vy']=0.0 # point_informationv2[num_sources:(num_sources+num_sinks)]['vz']=0.0 point_informationv2[num_sources : (num_sources + num_sinks)]["nx"] = np.asarray( - sink_coords.normals + sink_coords.point_data["normals"] ).astype(np.float32)[:, 0] point_informationv2[num_sources : (num_sources + num_sinks)]["ny"] = np.asarray( - sink_coords.normals + sink_coords.point_data["normals"] ).astype(np.float32)[:, 1] point_informationv2[num_sources : (num_sources + num_sinks)]["nz"] = np.asarray( - sink_coords.normals + sink_coords.point_data["normals"] ).astype(np.float32)[:, 2] point_informationv2[(num_sources + num_sinks) :]["px"] = np.asarray( scatter_points.points @@ -712,13 +713,13 @@ def calculate_scattering( scatter_points.points ).astype(np.float32)[:, 2] point_informationv2[(num_sources + num_sinks) :]["nx"] = np.asarray( - scatter_points.normals + scatter_points.point_data["normals"] ).astype(np.float32)[:, 0] point_informationv2[(num_sources + num_sinks) :]["ny"] = np.asarray( - scatter_points.normals + scatter_points.point_data["normals"] ).astype(np.float32)[:, 1] point_informationv2[(num_sources + num_sinks) :]["nz"] = np.asarray( - scatter_points.normals + scatter_points.point_data["normals"] ).astype(np.float32)[:, 2] point_informationv2[:]["ex"] = unified_weights[:, 0] point_informationv2[:]["ey"] = unified_weights[:, 1] @@ -751,9 +752,9 @@ def calculate_scattering( for e_inc in range(desired_E_axis.shape[0]): conformal_E_vectors = EM.calculate_conformalVectors( desired_E_axis[e_inc, :], - np.asarray(aperture_coords.normals).astype(np.float32), + np.asarray(aperture_coords.point_data["normals"]).astype(np.float32), ) - unified_weights[0:num_sources, :] = conformal_E_vectors / num_sources + unified_weights[0:num_sources, :] = conformal_E_vectors# / num_sources point_informationv2[:]["ex"] = unified_weights[:, 0] point_informationv2[:]["ey"] = unified_weights[:, 1] point_informationv2[:]["ez"] = unified_weights[:, 2] @@ -782,24 +783,24 @@ def calculate_scattering( for e_inc in range(desired_E_axis.shape[1]): conformal_E_vectors = EM.calculate_conformalVectors( desired_E_axis[e_inc, :], - np.asarray(aperture_coords.normals).astype(np.float32), + np.asarray(aperture_coords.point_data["normals"]).astype(np.float32), ) for element in range(num_sources): point_informationv2[0:num_sources]["ex"] = 0.0 point_informationv2[0:num_sources]["ey"] = 0.0 point_informationv2[0:num_sources]["ez"] = 0.0 point_informationv2[element]["ex"] = ( - conformal_E_vectors[element, 0] / num_sources + conformal_E_vectors[element, 0] #/ num_sources ) point_informationv2[element]["ey"] = ( - conformal_E_vectors[element, 1] / num_sources + conformal_E_vectors[element, 1] #/ num_sources ) point_informationv2[element]["ez"] = ( - conformal_E_vectors[element, 2] / num_sources + conformal_E_vectors[element, 2] #/ num_sources ) unified_weights[0:num_sources, :] = 0.0 unified_weights[element, :] = ( - conformal_E_vectors[element, :] / num_sources + conformal_E_vectors[element, :]# / num_sources ) scatter_map = EM.EMGPUFreqDomain( num_sources, @@ -827,6 +828,7 @@ def calculate_scattering( Ex = scatter_map[:, :, 0] Ey = scatter_map[:, :, 1] Ez = scatter_map[:, :, 2] + print(scatter_map.shape,"scatter_map.shape") return Ex, Ey, Ez @@ -858,8 +860,8 @@ def calculate_scattering_isotropic( axis=0, ) unified_normals = np.append( - np.asarray(aperture_coords.normals).astype(np.float32), - np.asarray(sink_coords.normals).astype(np.float32), + np.asarray(aperture_coords.point_data["normals"]).astype(np.float32), + np.asarray(sink_coords.point_data["normals"]).astype(np.float32), axis=0, ) unified_weights = np.ones((unified_model.shape[0], 3), dtype=np.complex64) @@ -885,13 +887,13 @@ def calculate_scattering_isotropic( aperture_coords.points ).astype(np.float32)[:, 2] point_informationv2[0:num_sources]["nx"] = np.asarray( - aperture_coords.normals + aperture_coords.point_data["normals"] ).astype(np.float32)[:, 0] point_informationv2[0:num_sources]["ny"] = np.asarray( - aperture_coords.normals + aperture_coords.point_data["normals"] ).astype(np.float32)[:, 1] point_informationv2[0:num_sources]["nz"] = np.asarray( - aperture_coords.normals + aperture_coords.point_data["normals"] ).astype(np.float32)[:, 2] # set position and velocity of sinks point_informationv2[num_sources : (num_sources + num_sinks)]["px"] = np.asarray( @@ -904,13 +906,13 @@ def calculate_scattering_isotropic( sink_coords.points ).astype(np.float32)[:, 2] point_informationv2[num_sources : (num_sources + num_sinks)]["nx"] = np.asarray( - sink_coords.normals + sink_coords.point_data["normals"] ).astype(np.float32)[:, 0] point_informationv2[num_sources : (num_sources + num_sinks)]["ny"] = np.asarray( - sink_coords.normals + sink_coords.point_data["normals"] ).astype(np.float32)[:, 1] point_informationv2[num_sources : (num_sources + num_sinks)]["nz"] = np.asarray( - sink_coords.normals + sink_coords.point_data["normals"] ).astype(np.float32)[:, 2] point_informationv2[:]["ex"] = unified_weights[:, 0] @@ -938,11 +940,11 @@ def calculate_scattering_isotropic( ) unified_normals = np.append( np.append( - np.asarray(aperture_coords.normals).astype(np.float32), - np.asarray(sink_coords.normals).astype(np.float32), + np.asarray(aperture_coords.point_data["normals"]).astype(np.float32), + np.asarray(sink_coords.point_data["normals"]).astype(np.float32), axis=0, ), - np.asarray(scatter_points.normals).astype(np.float32), + np.asarray(scatter_points.point_data["normals"]).astype(np.float32), axis=0, ) unified_weights = np.ones((unified_model.shape[0], 3), dtype=np.complex64) @@ -971,13 +973,13 @@ def calculate_scattering_isotropic( aperture_coords.points ).astype(np.float32)[:, 2] point_informationv2[0:num_sources]["nx"] = np.asarray( - aperture_coords.normals + aperture_coords.point_data["normals"] ).astype(np.float32)[:, 0] point_informationv2[0:num_sources]["ny"] = np.asarray( - aperture_coords.normals + aperture_coords.point_data["normals"] ).astype(np.float32)[:, 1] point_informationv2[0:num_sources]["nz"] = np.asarray( - aperture_coords.normals + aperture_coords.point_data["normals"] ).astype(np.float32)[:, 2] # point_informationv2[0:num_sources]['ex']=unified_weights[0:num_sources,0] # point_informationv2[0:num_sources]['ey']=unified_weights[0:num_sources,1] @@ -996,13 +998,13 @@ def calculate_scattering_isotropic( # point_informationv2[num_sources:(num_sources+num_sinks)]['vy']=0.0 # point_informationv2[num_sources:(num_sources+num_sinks)]['vz']=0.0 point_informationv2[num_sources : (num_sources + num_sinks)]["nx"] = np.asarray( - sink_coords.normals + sink_coords.point_data["normals"] ).astype(np.float32)[:, 0] point_informationv2[num_sources : (num_sources + num_sinks)]["ny"] = np.asarray( - sink_coords.normals + sink_coords.point_data["normals"] ).astype(np.float32)[:, 1] point_informationv2[num_sources : (num_sources + num_sinks)]["nz"] = np.asarray( - sink_coords.normals + sink_coords.point_data["normals"] ).astype(np.float32)[:, 2] point_informationv2[(num_sources + num_sinks) :]["px"] = np.asarray( scatter_points.points @@ -1014,13 +1016,13 @@ def calculate_scattering_isotropic( scatter_points.points ).astype(np.float32)[:, 2] point_informationv2[(num_sources + num_sinks) :]["nx"] = np.asarray( - scatter_points.normals + scatter_points.point_data["normals"] ).astype(np.float32)[:, 0] point_informationv2[(num_sources + num_sinks) :]["ny"] = np.asarray( - scatter_points.normals + scatter_points.point_data["normals"] ).astype(np.float32)[:, 1] point_informationv2[(num_sources + num_sinks) :]["nz"] = np.asarray( - scatter_points.normals + scatter_points.point_data["normals"] ).astype(np.float32)[:, 2] point_informationv2[:]["ex"] = unified_weights[:, 0] point_informationv2[:]["ey"] = unified_weights[:, 1] diff --git a/lyceanem/tests/data/rect_reflectorref.ply b/lyceanem/tests/data/rect_reflectorref.ply new file mode 100644 index 0000000000000000000000000000000000000000..6aa4f9da8beec51b41324e07458e7adee972e1ab GIT binary patch literal 881 zcmZ`#y-ve05DtVNDNkXsA|Xm8#DX%w&dd}!$(2TOoyc`i!UQW~>;o|H04xj$i4I5z z-h;htEFJK89rT#_>Z zR60Ugxvv_w8vj8m@ta2I@ju74P@u@$d8b-HaOFK*AL&7Q|NR zK#WSb=9bW1%-mu_jLHf~t70u?Ud%u`i?u2i#8yFwzvX$}uCi@qI@xIozVhCtGMw-+ pz>ZFo_coMa(Z>L1+XR`AQFnBJiEf(?CfGqnt%J0h2!EI$$v-XWMV$Zu literal 0 HcmV?d00001 diff --git a/lyceanem/tests/reflectordata.py b/lyceanem/tests/reflectordata.py index fc05a7e..7bd3aec 100644 --- a/lyceanem/tests/reflectordata.py +++ b/lyceanem/tests/reflectordata.py @@ -5,11 +5,12 @@ import math import numpy as np -import open3d as o3d +import meshio import scipy.io as io from importlib_resources import files import lyceanem.geometry.geometryfunctions as GF +import pyvista as pv import lyceanem.geometry.targets as tl import lyceanem.raycasting.rayfunctions as RF import lyceanem.tests.data @@ -37,29 +38,37 @@ def exampleUAV(frequency): bodystream = files(lyceanem.tests.data).joinpath("UAV.stl") arraystream = files(lyceanem.tests.data).joinpath("UAVarray.stl") - body = o3d.io.read_triangle_mesh(str(bodystream)) - array = o3d.io.read_triangle_mesh(str(arraystream)) + #body = o3d.io.read_triangle_mesh(str(bodystream)) + #array = o3d.io.read_triangle_mesh(str(arraystream)) + body = meshio.read(bodystream) + array = meshio.read(arraystream) rotation_vector1 = np.asarray([0.0, np.deg2rad(90), 0.0]) rotation_vector2 = np.asarray([np.deg2rad(90), 0.0, 0.0]) - body = GF.open3drotate( - body, o3d.geometry.TriangleMesh.get_rotation_matrix_from_xyz(rotation_vector1) - ) - body = GF.open3drotate( - body, o3d.geometry.TriangleMesh.get_rotation_matrix_from_xyz(rotation_vector2) - ) - array = GF.open3drotate( - array, o3d.geometry.TriangleMesh.get_rotation_matrix_from_xyz(rotation_vector1) - ) - array = GF.open3drotate( - array, o3d.geometry.TriangleMesh.get_rotation_matrix_from_xyz(rotation_vector2) - ) - body.translate(np.asarray([0.25, 0, 0]), relative=True) - array.translate(np.asarray([0.25, 0, 0]), relative=True) - array.translate(np.array([-0.18, 0, 0.0125]), relative=True) - body.translate(np.array([-0.18, 0, 0.0125]), relative=True) + body = GF.mesh_rotate( + body,rotation_vector1) + body = GF.mesh_rotate(body,rotation_vector2) + array = GF.mesh_rotate( array,rotation_vector1) + array = GF.mesh_rotate(array,rotation_vector2) + + body = GF.translate_mesh(body,np.asarray([0.25, 0, 0])) + array = GF.translate_mesh(array,np.asarray([0.25, 0, 0])) + array = GF.translate_mesh(array,np.array([-0.18, 0, 0.0125])) + body = GF.translate_mesh(body,np.array([-0.18, 0, 0.0125])) + + triangle_list_body = np.asarray(body.cells[0].data) + mesh_vertices = np.asarray(body.points) + + triangle_list = np.insert(triangle_list_body, 0, 3, axis=1) + + pv_mesh = pv.PolyData( mesh_vertices, faces = triangle_list) + pv_mesh.compute_normals(inplace=True,consistent_normals=False) + body.point_data + + array.compute_vertex_normals() array.paint_uniform_color(np.array([0, 1.0, 1.0])) body.compute_vertex_normals() + body.paint_uniform_color(np.array([0, 0.259, 0.145])) wavelength = 3e8 / frequency diff --git a/lyceanem/tests/test_targets.py b/lyceanem/tests/test_targets.py new file mode 100644 index 0000000..aa4d06c --- /dev/null +++ b/lyceanem/tests/test_targets.py @@ -0,0 +1,37 @@ +import meshio +from ..geometry import targets as TG +import numpy as np + +def are_meshes_equal(mesh0, mesh1, rtol=1e-5): + # Check vertices + ## loop through each cell checking points have correect valsue + cells0 = mesh0.cells[0].data + cells1 = mesh1.cells[0].data + a = np.zeros((cells0.shape[0], 2)) + for i in range(cells0.shape[0]): + for j in range((cells1).shape[1]): + a[cells0[i][j]][0] += 1 + a[cells1[i][j]][1] += 1 + print(a) + + b = 0 + for i in range(cells0.shape[0]): + for j in range((cells1).shape[0]): + for k in range((mesh1.cells[0].data).shape[1]): + if np.allclose(mesh0.points[cells0[i][k]],mesh1.points[cells1[j][k]], rtol=rtol): + b +=1 + ## check point data + assert b > cells0.shape[0]*3 + assert cells0.shape[0] == cells1.shape[0] + assert 0 + + + + +def test_rect_reflector(): + reference = meshio.read('data/rect_reflectorref.ply') + result = TG.rectReflector(0.3, 0.3, 0.006) + + are_meshes_equal(result, reference) + +