From 3d7d07564bc454dd1b58dcfe4234544fca4c57f2 Mon Sep 17 00:00:00 2001 From: Ardi Loot Date: Fri, 20 Feb 2026 22:01:21 +0200 Subject: [PATCH 1/5] Update README and docs - Modernize README.md: add pre-commit badge, installation section, quick example, development section, fix typos - Fix Introduction.rst: complete publication #2 reference (was 'TPB'), fix typos, update technical features for ARM support - Fix GettingStarted.rst: update Python requirement to >=3.10, fix typos throughout, add second-order nonlinear TMM example --- README.md | 87 +++++++++++++++++++++++++++++++++++------ docs/GettingStarted.rst | 48 +++++++++++------------ docs/Introduction.rst | 29 +++++++------- 3 files changed, 111 insertions(+), 53 deletions(-) diff --git a/README.md b/README.md index 9e74eb0..ce8e063 100644 --- a/README.md +++ b/README.md @@ -1,33 +1,94 @@ [![PyPI version](https://badge.fury.io/py/NonlinearTMM.svg)](https://badge.fury.io/py/NonlinearTMM) [![Pytest](https://github.com/ardiloot/NonlinearTMM/actions/workflows/pytest.yml/badge.svg)](https://github.com/ardiloot/NonlinearTMM/actions/workflows/pytest.yml) [![PyPI](https://github.com/ardiloot/NonlinearTMM/actions/workflows/publish.yml/badge.svg)](https://github.com/ardiloot/NonlinearTMM/actions/workflows/publish.yml) +[![Pre-commit](https://github.com/ardiloot/NonlinearTMM/actions/workflows/pre-commit.yml/badge.svg)](https://github.com/ardiloot/NonlinearTMM/actions/workflows/pre-commit.yml) - -# NonlinearTMM : Nonlinear transfer-matrix method +# NonlinearTMM: Nonlinear transfer-matrix method ## Overview -Transfer-matrix method (TMM) is powerful analytical method to solve Maxwell equations in layered structures. However, standard TMM is limited by infinite plane waves (e.g no Gaussian beam excitation) and it is only limited to linear processes (i.e calculation of second-harmonic, sum-frequency, difference-frequency generation is not possible). The aim of this package is extand standard TMM to include those features. The physics of those extensions are described in the follwoing publications, first extends the standard TMM to nonlinear processes and the second extends to the beams with arbritary profiles. +Transfer-matrix method (TMM) is a powerful analytical method to solve Maxwell's +equations in layered structures. However, standard TMM is limited to infinite plane +waves (e.g. no Gaussian beam excitation) and to linear processes (i.e. calculation +of second-harmonic, sum-frequency, and difference-frequency generation is not +possible). The aim of this package is to extend standard TMM to include those +features. The physics of these extensions are described in the following +publications: -1. [A. Loot and V. Hizhnyakov, “Extension of standard transfer-matrix method for three-wave mixing for plasmonic structures,” Appl. Phys. A, vol. 123, no. 3, p. 152, 2017.](https://link.springer.com/article/10.1007%2Fs00339-016-0733-0) -2. [A. Loot and V. Hizhnyakov, “Modeling of enhanced spontaneous parametric down-conversion in plasmonic and dielectric structures with realistic waves,” Journal of Optics, vol. 20, no. 055502, 2018.](http://iopscience.iop.org/article/10.1088/2040-8986/aab6c0/meta) +1. [A. Loot and V. Hizhnyakov, "Extension of standard transfer-matrix method for three-wave mixing for plasmonic structures," Appl. Phys. A, vol. 123, no. 3, p. 152, 2017.](https://link.springer.com/article/10.1007%2Fs00339-016-0733-0) +2. [A. Loot and V. Hizhnyakov, "Modeling of enhanced spontaneous parametric down-conversion in plasmonic and dielectric structures with realistic waves," J. Opt., vol. 20, no. 055502, 2018.](https://doi.org/10.1088/2040-8986/aab6c0) -For additional details see our documentation https://ardiloot.github.io/NonlinearTMM/. For getting started guide see [Getting started](https://ardiloot.github.io/NonlinearTMM/GettingStarted.html). +For additional details, see the [documentation](https://ardiloot.github.io/NonlinearTMM/). +For a getting started guide, see [Getting started](https://ardiloot.github.io/NonlinearTMM/GettingStarted.html). ## Main features -In addition to the standard TMM features this package also supports: +In addition to the standard TMM features, this package also supports: -* Calculation of Gaussian beam (or any other beam) propagartion inside layered structures -* Calculation of nonlinear processes SHG/SFG/DFG +* Calculation of Gaussian beam (or any other beam) propagation inside layered structures +* Calculation of nonlinear processes: SHG, SFG, DFG ## Technical features -* Written in C++ -* Python wrapper written in Cython -* Parallerization through OpenMP -* Use of SSE instructions for speedup +* Core written in C++ +* Python bindings via Cython +* OpenMP parallelization (Linux and Windows) +* Supports Linux (x86_64), Windows (x64, ARM64), and macOS (ARM64) + +## Installation + +Requires Python >= 3.10. + +```bash +pip install NonlinearTMM +``` + +## Quick example + +```python +import math +import numpy as np +from NonlinearTMM import TMM, Material + +# Define materials +prism = Material.Static(1.5) +ag = Material.Static(0.054007 + 3.4290j) # Silver @ 532nm +air = Material.Static(1.0) + +# Set up TMM (Kretschmann configuration) +tmm = TMM(wl=532e-9, pol="p", I0=1.0) +tmm.AddLayer(math.inf, prism) +tmm.AddLayer(50e-9, ag) +tmm.AddLayer(math.inf, air) + +# Sweep angle of incidence +betas = np.sin(np.radians(np.linspace(0, 80, 500))) * 1.5 +result = tmm.Sweep("beta", betas) + +print(f"Min reflectance: {result.Ir.min():.4f}") +``` ## Documentation https://ardiloot.github.io/NonlinearTMM/ + +## Development + +```bash +# Clone with submodules (Eigen) +git clone --recurse-submodules https://github.com/ardiloot/NonlinearTMM.git +cd NonlinearTMM + +# Install dev environment +uv sync + +# Run tests +uv run pytest + +# Run pre-commit checks +uv run pre-commit run --all-files +``` + +## License + +MIT diff --git a/docs/GettingStarted.rst b/docs/GettingStarted.rst index d977257..23cc31a 100644 --- a/docs/GettingStarted.rst +++ b/docs/GettingStarted.rst @@ -11,7 +11,7 @@ code. Requirements: -* `Python >= 3.6 `_ +* `Python >= 3.10 `_ Dependencies: @@ -23,7 +23,7 @@ Installation through pip is done like: pip install NonlinearTMM -Alternatively, it is possible to install the package form the source code by +Alternatively, it is possible to install the package from the source code by .. code-block:: bash @@ -41,30 +41,30 @@ The package has three main classes: * :class:`TMM` * :class:`SecondOrderNLTMM` -Class :class:`Material` is responsible to represent the properties of optical -material. Mainly wavelength dependent refractive indices and second-order -suceptibility tensor for nonlinear processes. +Class :class:`Material` is responsible for representing the properties of optical +material, mainly wavelength-dependent refractive indices and second-order +susceptibility tensor for nonlinear processes. -Class :class:`TMM` (alias of :class:`NonlinearTMM`) is has all the standard TMM features: +Class :class:`TMM` (alias of :class:`NonlinearTMM`) has all the standard TMM features: * Both p- and s-polarization -* Arbritarty angle of incidence +* Arbitrary angle of incidence * Calculation of reflection, transmission and absorption of plane waves (:any:`GetIntensities ` and :any:`GetAbsorbedIntensity `) -* Calculaion of electric and magnetic fields inside structure (:any:`GetFields ` and :any:`GetFields2D `) +* Calculation of electric and magnetic fields inside structure (:any:`GetFields ` and :any:`GetFields2D `) * Calculation of field enhancement (:any:`GetEnhancement `) * Sweep over any parameter (:any:`Sweep `) In addition to those standard features, the class has similar functionality to -work with waves with arbritarty profile (e.g. Gaussian beam). The configuration +work with waves with arbitrary profile (e.g. Gaussian beam). The configuration of the beam is done through attribute :any:`wave ` (see class :any:`_Wave`). -The interface for the calculations with arbritarty beams is similar to standard TMM: +The interface for the calculations with arbitrary beams is similar to standard TMM: * Calculation of reflection, transmission and absorption of beams (:any:`WaveGetPowerFlows `) -* Calculaion of electric and magnetic fields inside structure (:any:`WaveGetFields2D `) +* Calculation of electric and magnetic fields inside structure (:any:`WaveGetFields2D `) * Calculation of field enhancement (:any:`WaveGetEnhancement `) * Sweep over any parameter (:any:`WaveSweep `) -Finally, :class:`SecondOrderNLTMM` class ic capable of calculating second-order +Finally, :class:`SecondOrderNLTMM` class is capable of calculating second-order nonlinear processes like second-harmonic generation, sum-frequency generation and difference frequency generation. This has similar interface as :any:`TMM` - it supports both the plane waves and beams. @@ -78,20 +78,20 @@ Plane waves example As an example three layer structure consisting of a prism (z < 0), 50 nm thick silver film and air is studied. Such kind of structure supports surface plasmon resonance (SPP) if excited by p-polarized light and is named Kretschmann -configuration. The example code is shown bellow and could be divided into +configuration. The example code is shown below and could be divided into following steps: 1. Specifying materials refractive indices. 2. Initializing :class:`TMM`, setting params and adding layers. -3. By using :any:`Sweep ` calculate the dependence of reflection, transmission and enhancment factor on the angle of incidence. -4. Find the plasmonic resonance by maximum enhancment. +3. By using :any:`Sweep ` calculate the dependence of reflection, transmission and enhancement factor on the angle of incidence. +4. Find the plasmonic resonance by maximum enhancement. 5. Calculate 1D fields at plasmonic resonance by :any:`GetFields `. 6. Calculate 2D fields at plasmonic resonance by :any:`GetFields2D `. 7. Plot all results .. literalinclude:: ../Examples/ExampleTMM.py -The results of the calculations are shown bellow. Indeed there is a sharrp dip +The results of the calculations are shown below. Indeed there is a sharp dip in the reflection (R) near the angle of incidence ca 44 degrees. At the same angle the field enhancement factor is maximum and is more than 12 times. In the second the results of the fields calculations at plasmonic resonance is presented. Indeed, @@ -111,14 +111,14 @@ to 10 μm. .. literalinclude:: ../Examples/ExampleTMMForWaves.py -The results of those calculations are bellow. Despite the fact, that the structure +The results of those calculations are below. Despite the fact, that the structure is the same, the dip in the reflection is different. The reason for this behaviour is that as the resonances of SPPs are narrow, they also require well collimated -beam to excite them. Also field enhancment is ca 3 times lower, as expected. On +beam to excite them. Also field enhancement is ca 3 times lower, as expected. On the right side, the electrical field norm is shown. It is clearly visible, that -Gaussian beam is incident form the left, and it gets reflected from the metal film (z = 0). +Gaussian beam is incident from the left, and it gets reflected from the metal film (z = 0). Part of the energy is transmitted to excite SPPs at the metal-air interface. The -excited SPPs are propagating on the metal film and are absorbe after ca 20 μm of +excited SPPs are propagating on the metal film and are absorbed after ca 20 μm of propagation. .. image:: images/TMMForWaves-example.png @@ -129,9 +129,7 @@ Second-order nonlinear TMM Plane waves example =================== -Will be added in near future. +As an example, second-harmonic generation (SHG) in a nonlinear crystal is +calculated. The example code is shown below. -Gaussian wave example -===================== - -Will be added in near future. +.. literalinclude:: ../Examples/ExampleSecondOrderNonlinearTmm.py diff --git a/docs/Introduction.rst b/docs/Introduction.rst index 4d62c9c..87ff90a 100644 --- a/docs/Introduction.rst +++ b/docs/Introduction.rst @@ -5,17 +5,16 @@ Introduction Overview ******** -Transfer-matrix method (TMM) is powerful analytical method to solve Maxwell -equations in layered structures. However, standard TMM is limited by infinite -plane waves (e.g no Gaussian beam excitation) and it is only limited to linear -processes (i.e calculation of second-harmonic, sum-frequency, difference-frequency -generation is not possible). The aim of this package is extand standard TMM to -include those features. The physics of those extensionsare described in the -follwoing publications, first extends the standard TMM to nonlinear processes -and the second extends to the beams with arbritary profiles. +Transfer-matrix method (TMM) is a powerful analytical method to solve Maxwell's +equations in layered structures. However, standard TMM is limited to infinite +plane waves (e.g. no Gaussian beam excitation) and to linear processes (i.e. +calculation of second-harmonic, sum-frequency, and difference-frequency +generation is not possible). The aim of this package is to extend standard TMM to +include those features. The physics of these extensions are described in the +following publications: -1. `A. Loot and V. Hizhnyakov, “Extension of standard transfer-matrix method for three-wave mixing for plasmonic structures,” Appl. Phys. A, vol. 123, no. 3, p. 152, 2017. `_ -2. TPB +1. `A. Loot and V. Hizhnyakov, "Extension of standard transfer-matrix method for three-wave mixing for plasmonic structures," Appl. Phys. A, vol. 123, no. 3, p. 152, 2017. `_ +2. `A. Loot and V. Hizhnyakov, "Modeling of enhanced spontaneous parametric down-conversion in plasmonic and dielectric structures with realistic waves," J. Opt., vol. 20, no. 055502, 2018. `_ Main features @@ -23,13 +22,13 @@ Main features In addition to the standard TMM features this package also supports: -* Calculation of Gaussian beam (or any other beam) propagartion inside layered structures +* Calculation of Gaussian beam (or any other beam) propagation inside layered structures * Calculation of nonlinear processes SHG/SFG/DFG Technical features ================== -* Written in C++ -* Python wrappers written in Cython -* Parallerization through OpenMP -* Use of SSE instructions for speedup +* Core written in C++ +* Python bindings via Cython +* OpenMP parallelization (Linux and Windows) +* Supports Linux (x86_64), Windows (x64, ARM64), and macOS (ARM64) From 522ec73eb3415c272b33d4fbf48b53e7d8d112b5 Mon Sep 17 00:00:00 2001 From: Ardi Loot Date: Fri, 20 Feb 2026 22:10:29 +0200 Subject: [PATCH 2/5] Fix additional typos and grammar in docs - Update copyright year to 2026 in conf.py - Fix Texinfo placeholder description in conf.py - Fix grammar and phrasing throughout GettingStarted.rst - Fix 'physics are' -> 'physics is' in README.md --- README.md | 2 +- docs/GettingStarted.rst | 48 ++++++++++++++++++++--------------------- docs/conf.py | 6 +++--- 3 files changed, 28 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index ce8e063..7b68c9d 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ equations in layered structures. However, standard TMM is limited to infinite pl waves (e.g. no Gaussian beam excitation) and to linear processes (i.e. calculation of second-harmonic, sum-frequency, and difference-frequency generation is not possible). The aim of this package is to extend standard TMM to include those -features. The physics of these extensions are described in the following +features. The physics of these extensions is described in the following publications: 1. [A. Loot and V. Hizhnyakov, "Extension of standard transfer-matrix method for three-wave mixing for plasmonic structures," Appl. Phys. A, vol. 123, no. 3, p. 152, 2017.](https://link.springer.com/article/10.1007%2Fs00339-016-0733-0) diff --git a/docs/GettingStarted.rst b/docs/GettingStarted.rst index 23cc31a..8cefb2e 100644 --- a/docs/GettingStarted.rst +++ b/docs/GettingStarted.rst @@ -6,7 +6,7 @@ Getting started Installation ************ -Installation of NonlinearTMM package is possible through pip or from source +Installation of the NonlinearTMM package is possible through pip or from source code. Requirements: @@ -15,7 +15,7 @@ Requirements: Dependencies: -* C++ code depends on `Eigen library `_ (already included in package) +* C++ code depends on `Eigen library `_ (already included in package) Installation through pip is done like: @@ -66,7 +66,7 @@ The interface for the calculations with arbitrary beams is similar to standard T Finally, :class:`SecondOrderNLTMM` class is capable of calculating second-order nonlinear processes like second-harmonic generation, sum-frequency generation and -difference frequency generation. This has similar interface as :any:`TMM` - it +difference frequency generation. This has a similar interface to :any:`TMM` - it supports both the plane waves and beams. Standard TMM @@ -75,50 +75,50 @@ Standard TMM Plane waves example =================== -As an example three layer structure consisting of a prism (z < 0), 50 nm thick silver -film and air is studied. Such kind of structure supports surface plasmon -resonance (SPP) if excited by p-polarized light and is named Kretschmann +As an example, a three-layer structure consisting of a prism (z < 0), a 50-nm-thick silver +film and air is studied. Such a structure supports surface plasmon +resonance (SPR) if excited by p-polarized light and is named Kretschmann configuration. The example code is shown below and could be divided into -following steps: +the following steps: -1. Specifying materials refractive indices. +1. Specifying material refractive indices. 2. Initializing :class:`TMM`, setting params and adding layers. 3. By using :any:`Sweep ` calculate the dependence of reflection, transmission and enhancement factor on the angle of incidence. -4. Find the plasmonic resonance by maximum enhancement. +4. Find the plasmonic resonance from the maximum enhancement. 5. Calculate 1D fields at plasmonic resonance by :any:`GetFields `. 6. Calculate 2D fields at plasmonic resonance by :any:`GetFields2D `. 7. Plot all results .. literalinclude:: ../Examples/ExampleTMM.py -The results of the calculations are shown below. Indeed there is a sharp dip -in the reflection (R) near the angle of incidence ca 44 degrees. At the same angle -the field enhancement factor is maximum and is more than 12 times. In the second -the results of the fields calculations at plasmonic resonance is presented. Indeed, -surface wave on the silver-air interface is excited and characteristic pattern of -fields for SPP is visible. +The results of the calculations are shown below. Indeed, there is a sharp dip +in the reflection (R) near the angle of incidence of approximately 44 degrees. At the same angle, +the field enhancement factor is at its maximum and is more than 12 times the incident field. In the lower +panels, the results of the field calculations at plasmonic resonance are presented. +Indeed, a surface wave on the silver-air interface is excited and the characteristic +pattern of fields for SPP is visible. .. image:: images/TMM-example.png Gaussian wave example ===================== -Previous example was entirely about standard TMM. Now, the calculations are -extended to the beams, in this case Gaussian beam. The steps of the calculations +The previous example was entirely about standard TMM. Now, the calculations are +extended to beams, in this case a Gaussian beam. The steps of the calculations remain the same, except :class:`_Wave` parameters must be set (:class:`TMM` has -attribute :any:`TMM.wave`). Gaussian beam power is set to 10 mW and waist size +attribute :any:`TMM.wave`). The Gaussian beam power is set to 10 mW and the waist size to 10 μm. .. literalinclude:: ../Examples/ExampleTMMForWaves.py -The results of those calculations are below. Despite the fact, that the structure +The results of those calculations are below. Despite the fact that the structure is the same, the dip in the reflection is different. The reason for this behaviour -is that as the resonances of SPPs are narrow, they also require well collimated -beam to excite them. Also field enhancement is ca 3 times lower, as expected. On -the right side, the electrical field norm is shown. It is clearly visible, that -Gaussian beam is incident from the left, and it gets reflected from the metal film (z = 0). +is that as the resonances of SPPs are narrow, they also require a well-collimated +beam to excite them. Also, the field enhancement is approximately 3 times lower, as expected. On +the right side, the electric field norm is shown. It is clearly visible that +a Gaussian beam is incident from the left, and it gets reflected from the metal film (z = 0). Part of the energy is transmitted to excite SPPs at the metal-air interface. The -excited SPPs are propagating on the metal film and are absorbed after ca 20 μm of +excited SPPs are propagating on the metal film and are absorbed after approximately 20 μm of propagation. .. image:: images/TMMForWaves-example.png diff --git a/docs/conf.py b/docs/conf.py index c89aed7..e7106a2 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -56,7 +56,7 @@ # General information about the project. project = "NonlinearTMM" -copyright = "2017-2025, Ardi Loot" +copyright = "2017-2026, Ardi Loot" author = "Ardi Loot" # The version info for the project you're documenting, acts as replacement for @@ -80,7 +80,7 @@ # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. -# This patterns also effect to html_static_path and html_extra_path +# These patterns also affect html_static_path and html_extra_path exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] # The name of the Pygments (syntax highlighting) style to use. @@ -162,7 +162,7 @@ "NonlinearTMM Documentation", author, "NonlinearTMM", - "One line description of project.", + "Nonlinear transfer-matrix method.", "Miscellaneous", ), ] From 74100dc918044f92fff81f3a7ec870e7c86370d7 Mon Sep 17 00:00:00 2001 From: Ardi Loot Date: Fri, 20 Feb 2026 22:14:03 +0200 Subject: [PATCH 3/5] Fix remaining grammar issues in rst docs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 'physics are' → 'physics is' in Introduction.rst - 'is named Kretschmann configuration' → 'is known as the Kretschmann configuration' in GettingStarted.rst - Remove unnecessary article in 'both the plane waves and beams' in GettingStarted.rst --- docs/GettingStarted.rst | 4 ++-- docs/Introduction.rst | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/GettingStarted.rst b/docs/GettingStarted.rst index 8cefb2e..9fa2784 100644 --- a/docs/GettingStarted.rst +++ b/docs/GettingStarted.rst @@ -67,7 +67,7 @@ The interface for the calculations with arbitrary beams is similar to standard T Finally, :class:`SecondOrderNLTMM` class is capable of calculating second-order nonlinear processes like second-harmonic generation, sum-frequency generation and difference frequency generation. This has a similar interface to :any:`TMM` - it -supports both the plane waves and beams. +supports both plane waves and beams. Standard TMM ************ @@ -77,7 +77,7 @@ Plane waves example As an example, a three-layer structure consisting of a prism (z < 0), a 50-nm-thick silver film and air is studied. Such a structure supports surface plasmon -resonance (SPR) if excited by p-polarized light and is named Kretschmann +resonance (SPR) if excited by p-polarized light and is known as the Kretschmann configuration. The example code is shown below and could be divided into the following steps: diff --git a/docs/Introduction.rst b/docs/Introduction.rst index 87ff90a..8b57c83 100644 --- a/docs/Introduction.rst +++ b/docs/Introduction.rst @@ -10,7 +10,7 @@ equations in layered structures. However, standard TMM is limited to infinite plane waves (e.g. no Gaussian beam excitation) and to linear processes (i.e. calculation of second-harmonic, sum-frequency, and difference-frequency generation is not possible). The aim of this package is to extend standard TMM to -include those features. The physics of these extensions are described in the +include those features. The physics of these extensions is described in the following publications: 1. `A. Loot and V. Hizhnyakov, "Extension of standard transfer-matrix method for three-wave mixing for plasmonic structures," Appl. Phys. A, vol. 123, no. 3, p. 152, 2017. `_ From 8217dbe3fde3eb7be4686920cea5f5bc613a3dcd Mon Sep 17 00:00:00 2001 From: Ardi Loot Date: Fri, 20 Feb 2026 22:17:23 +0200 Subject: [PATCH 4/5] Overhaul README with TOC, hero image, API table, and more Inspired by GeneralTmm README structure: - Add Python version and License badges - Add hero image (Gaussian beam SPP excitation) - Add 'See also' callout linking to GeneralTmm - Add full Table of Contents - Bold feature names with descriptions - Add API Overview table (Material, TMM, SecondOrderNLTMM) - Restructure examples with images (SPP, Gaussian beam, SHG) - Add References section with blockquoted citations - Expand Development section with subsections (Setup, Tests, Linting, CI table) - Add Releasing section with setuptools-scm workflow - Link License to LICENSE file --- README.md | 194 +++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 149 insertions(+), 45 deletions(-) diff --git a/README.md b/README.md index 7b68c9d..676f0f0 100644 --- a/README.md +++ b/README.md @@ -1,56 +1,95 @@ [![PyPI version](https://badge.fury.io/py/NonlinearTMM.svg)](https://badge.fury.io/py/NonlinearTMM) +[![Python](https://img.shields.io/pypi/pyversions/NonlinearTMM)](https://pypi.org/project/NonlinearTMM/) +[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![Pytest](https://github.com/ardiloot/NonlinearTMM/actions/workflows/pytest.yml/badge.svg)](https://github.com/ardiloot/NonlinearTMM/actions/workflows/pytest.yml) -[![PyPI](https://github.com/ardiloot/NonlinearTMM/actions/workflows/publish.yml/badge.svg)](https://github.com/ardiloot/NonlinearTMM/actions/workflows/publish.yml) [![Pre-commit](https://github.com/ardiloot/NonlinearTMM/actions/workflows/pre-commit.yml/badge.svg)](https://github.com/ardiloot/NonlinearTMM/actions/workflows/pre-commit.yml) +[![Build and upload to PyPI](https://github.com/ardiloot/NonlinearTMM/actions/workflows/publish.yml/badge.svg)](https://github.com/ardiloot/NonlinearTMM/actions/workflows/publish.yml) + +# NonlinearTMM: Nonlinear Transfer-Matrix Method + +A Python library for optical simulations of **multilayer structures** using the transfer-matrix method, extended to support **nonlinear processes** (SHG, SFG, DFG) and **Gaussian beam propagation**. + +

+ Gaussian beam exciting surface plasmon polaritons +

+ +> **See also:** [GeneralTmm](https://github.com/ardiloot/GeneralTmm) — a 4×4 TMM for **anisotropic** (birefringent) multilayer structures. + +## Table of Contents + +- [Features](#features) +- [Installation](#installation) +- [API Overview](#api-overview) +- [Examples](#examples) + - [Surface Plasmon Polaritons](#surface-plasmon-polaritons--exampletmmpy) + - [Gaussian Beam Excitation](#gaussian-beam-excitation--exampletmmforwavespy) + - [Second-Harmonic Generation](#second-harmonic-generation--examplesecondordernonlineartmmpy) +- [References](#references) +- [Documentation](#documentation) +- [Development](#development) + - [Setup](#setup) + - [Running tests](#running-tests) + - [Code formatting and linting](#code-formatting-and-linting) + - [CI overview](#ci-overview) +- [Releasing](#releasing) +- [License](#license) + +## Features + +- **Standard TMM** — reflection, transmission, absorption for p- and s-polarized plane waves at arbitrary angles +- **Parameter sweeps** — over wavelength, angle of incidence, layer thickness, or any other parameter +- **1D and 2D electromagnetic field profiles** — E and H field distributions through the structure +- **Field enhancement** — calculation of field enhancement factors (e.g. for SPP excitation) +- **Gaussian beam propagation** — any beam profile through layered structures, not just plane waves +- **Second-order nonlinear processes** — SHG, SFG, DFG in multilayer structures +- **Wavelength-dependent materials** — interpolated from measured optical data (YAML format) +- **High performance** — C++ core (Eigen) with Cython bindings, OpenMP parallelization +- **Cross-platform wheels** — Linux (x86_64), Windows (x64, ARM64), macOS (ARM64); Python 3.10–3.13 -# NonlinearTMM: Nonlinear transfer-matrix method - -## Overview - -Transfer-matrix method (TMM) is a powerful analytical method to solve Maxwell's -equations in layered structures. However, standard TMM is limited to infinite plane -waves (e.g. no Gaussian beam excitation) and to linear processes (i.e. calculation -of second-harmonic, sum-frequency, and difference-frequency generation is not -possible). The aim of this package is to extend standard TMM to include those -features. The physics of these extensions is described in the following -publications: - -1. [A. Loot and V. Hizhnyakov, "Extension of standard transfer-matrix method for three-wave mixing for plasmonic structures," Appl. Phys. A, vol. 123, no. 3, p. 152, 2017.](https://link.springer.com/article/10.1007%2Fs00339-016-0733-0) -2. [A. Loot and V. Hizhnyakov, "Modeling of enhanced spontaneous parametric down-conversion in plasmonic and dielectric structures with realistic waves," J. Opt., vol. 20, no. 055502, 2018.](https://doi.org/10.1088/2040-8986/aab6c0) - -For additional details, see the [documentation](https://ardiloot.github.io/NonlinearTMM/). -For a getting started guide, see [Getting started](https://ardiloot.github.io/NonlinearTMM/GettingStarted.html). +## Installation -## Main features +```bash +pip install NonlinearTMM +``` -In addition to the standard TMM features, this package also supports: +Pre-built wheels are available for most platforms. A C++ compiler is only needed when installing from source. -* Calculation of Gaussian beam (or any other beam) propagation inside layered structures -* Calculation of nonlinear processes: SHG, SFG, DFG +## API Overview -## Technical features +The library exposes three main classes: `Material`, `TMM`, and `SecondOrderNLTMM`. -* Core written in C++ -* Python bindings via Cython -* OpenMP parallelization (Linux and Windows) -* Supports Linux (x86_64), Windows (x64, ARM64), and macOS (ARM64) +| Class / method | Purpose | +|---|---| +| `Material(wls, ns)` | Wavelength-dependent material from arrays of λ and complex n | +| `Material.Static(n)` | Constant refractive index (shortcut) | +| `Material.FromFile(path)` | Load material from a YAML data file | +| `TMM(wl=…, pol=…, I0=…)` | Create a solver; `wl` = wavelength (m), `pol` = `"p"` or `"s"` | +| `tmm.AddLayer(d, mat)` | Append layer (`d` in m, `inf` for semi-infinite) | +| `tmm.Sweep(param, values)` | Solve for an array of values of any parameter | +| `tmm.GetFields(zs)` | E, H field profiles along the layer normal | +| `tmm.GetFields2D(zs, xs)` | E, H on a 2-D grid | +| `tmm.GetEnhancement(layerNr)` | Field enhancement in a given layer | +| `tmm.wave` | Access `_Wave` parameters for Gaussian beam calculations | +| `tmm.WaveSweep(param, values)` | Parameter sweep for beam calculations | +| `tmm.WaveGetFields2D(zs, xs)` | 2-D field map for beam excitation | +| `SecondOrderNLTMM(…)` | Second-order nonlinear TMM (SHG, SFG, DFG) | -## Installation +For the full API, see the [reference documentation](https://ardiloot.github.io/NonlinearTMM/Reference.html). -Requires Python >= 3.10. +## Examples -```bash -pip install NonlinearTMM -``` +### Surface Plasmon Polaritons — [ExampleTMM.py](Examples/ExampleTMM.py) -## Quick example +Kretschmann configuration (prism | 50 nm Ag | air) at 532 nm. Demonstrates +reflection sweeps, field enhancement, and 1D/2D field visualization of surface +plasmon polaritons. ```python import math import numpy as np from NonlinearTMM import TMM, Material -# Define materials +# Materials prism = Material.Static(1.5) ag = Material.Static(0.054007 + 3.4290j) # Silver @ 532nm air = Material.Static(1.0) @@ -63,32 +102,97 @@ tmm.AddLayer(math.inf, air) # Sweep angle of incidence betas = np.sin(np.radians(np.linspace(0, 80, 500))) * 1.5 -result = tmm.Sweep("beta", betas) - -print(f"Min reflectance: {result.Ir.min():.4f}") +result = tmm.Sweep("beta", betas, outEnh=True, layerNr=2) ``` +

+ SPP reflection, enhancement, and field profiles +

+ +### Gaussian Beam Excitation — [ExampleTMMForWaves.py](Examples/ExampleTMMForWaves.py) + +Same Kretschmann structure excited by a 10 mW Gaussian beam (waist 10 μm). +Shows how finite beam width affects resonance depth and field enhancement. + +

+ Gaussian beam SPP excitation +

+ +### Second-Harmonic Generation — [ExampleSecondOrderNonlinearTmm.py](Examples/ExampleSecondOrderNonlinearTmm.py) + +Second-harmonic generation in a nonlinear crystal, calculated with the +`SecondOrderNLTMM` class. Supports SHG, SFG, and DFG processes. + +## References + +> Loot, A., & Hizhnyakov, V. (2017). Extension of standard transfer-matrix method for three-wave mixing for plasmonic structures. *Applied Physics A*, 123(3), 152. [doi:10.1007/s00339-016-0733-0](https://link.springer.com/article/10.1007%2Fs00339-016-0733-0) +> +> Loot, A., & Hizhnyakov, V. (2018). Modeling of enhanced spontaneous parametric down-conversion in plasmonic and dielectric structures with realistic waves. *Journal of Optics*, 20, 055502. [doi:10.1088/2040-8986/aab6c0](https://doi.org/10.1088/2040-8986/aab6c0) + ## Documentation -https://ardiloot.github.io/NonlinearTMM/ +Full documentation is available at https://ardiloot.github.io/NonlinearTMM/. + +- [Getting started](https://ardiloot.github.io/NonlinearTMM/GettingStarted.html) — installation, package structure, examples +- [API reference](https://ardiloot.github.io/NonlinearTMM/Reference.html) — complete class and method reference ## Development +### Setup + ```bash -# Clone with submodules (Eigen) git clone --recurse-submodules https://github.com/ardiloot/NonlinearTMM.git cd NonlinearTMM -# Install dev environment +# Install uv if not already installed: +# https://docs.astral.sh/uv/getting-started/installation/ + +# Create venv, build the C++ extension, and install all dependencies uv sync +``` + +### Running tests + +```bash +uv run pytest -v +``` + +### Code formatting and linting -# Run tests -uv run pytest +[Pre-commit](https://pre-commit.com/) hooks are configured to enforce formatting (ruff, clang-format) and catch common issues. To install the git hook locally: -# Run pre-commit checks -uv run pre-commit run --all-files +```bash +uvx pre-commit install +``` + +To run all checks manually: + +```bash +uvx pre-commit run --all-files ``` +### CI overview + +| Workflow | Trigger | What it does | +|----------|---------|--------------| +| [Pytest](.github/workflows/pytest.yml) | Push to `master` / PRs | Tests on {ubuntu, windows, macos} × Python 3.10 | +| [Pre-commit](.github/workflows/pre-commit.yml) | Push to `master` / PRs | Runs ruff, clang-format, ty, and other checks | +| [Publish to PyPI](.github/workflows/publish.yml) | Release published | Builds wheels + sdist via cibuildwheel, uploads to PyPI | +| [Publish docs](.github/workflows/publish_docs.yml) | Release published | Builds Sphinx docs and deploys to GitHub Pages | + +## Releasing + +Versioning is handled automatically by [setuptools-scm](https://github.com/pypa/setuptools-scm) from git tags. + +1. **Ensure CI is green** on the `master` branch. +2. **Create a new release** on GitHub: + - Go to [Releases](https://github.com/ardiloot/NonlinearTMM/releases) → **Draft a new release** + - Create a new tag following [PEP 440](https://peps.python.org/pep-0440/) (e.g. `v1.2.0`) + - Target the `master` branch (or a specific commit on master) + - Click **Generate release notes** for auto-generated changelog + - For pre-releases (e.g. `v1.2.0rc1`), check **Set as a pre-release** — these upload to TestPyPI instead of PyPI +3. **Publish the release** — the workflow builds wheels for Linux (x86_64), Windows (x64, ARM64), and macOS (ARM64) and uploads to [PyPI](https://pypi.org/project/NonlinearTMM/). + ## License -MIT +[MIT](LICENSE) From 5cfa1dae6acd2bdc43f9caaaf1ce4332a03bd06b Mon Sep 17 00:00:00 2001 From: Ardi Loot Date: Fri, 20 Feb 2026 22:29:57 +0200 Subject: [PATCH 5/5] Improve SHG example with schematic and fix README issues MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add setup schematic, SHG intensity, and thickness dependence panels to ExampleSecondOrderNonlinearTmm.py - Add savefig to all three example scripts - Add SHG example image and description to GettingStarted.rst - Remove non-existent Material.FromFile from API table - Fix Python version range: 3.10-3.14 (matches CI matrix) - Fix CI table: show full Python version range - Fix grammar: 'Same' → 'The same', add articles, add commas - Use 'uv run pre-commit install' instead of 'uvx' --- Examples/ExampleSecondOrderNonlinearTmm.py | 127 +++++++++++++++++---- Examples/ExampleTMM.py | 1 + Examples/ExampleTMMForWaves.py | 1 + README.md | 25 ++-- docs/GettingStarted.rst | 6 + docs/images/SecondOrderNLTMM-example.png | Bin 0 -> 63856 bytes 6 files changed, 126 insertions(+), 34 deletions(-) create mode 100644 docs/images/SecondOrderNLTMM-example.png diff --git a/Examples/ExampleSecondOrderNonlinearTmm.py b/Examples/ExampleSecondOrderNonlinearTmm.py index 3220327..e273779 100644 --- a/Examples/ExampleSecondOrderNonlinearTmm.py +++ b/Examples/ExampleSecondOrderNonlinearTmm.py @@ -7,46 +7,125 @@ from NonlinearTMM import Material, SecondOrderNLTMM -if __name__ == "__main__": - # Define params - wlP1 = 1000e-9 - wlP2 = 1000e-9 - polP1 = "s" - polP2 = "s" - polGen = "s" - I0P1 = 1.0 - I0P2 = I0P1 - betas = np.linspace(0.0, 0.99, 10000) - crystalD = 1000e-6 + +def CalcSHG() -> None: + # Parameters + # --------------------------------------------------------------------------- + wl = 1000e-9 # Pump wavelength + pol = "s" # Polarization + I0 = 1.0 # Intensity of incident pump wave + crystalD = 1000e-6 # Crystal thickness + betas = np.linspace(0.0, 0.99, 10000) # Sweep range for beta # Define materials + # --------------------------------------------------------------------------- wlsCrystal = np.array([400e-9, 1100e-9]) nsCrystal = np.array([1.54, 1.53], dtype=complex) prism = Material.Static(1.0) crystal = Material(wlsCrystal, nsCrystal) - dielectric = Material.Static(1.0) crystal.chi2.Update(d22=1e-12) + dielectric = Material.Static(1.0) # Init SecondOrderNLTMM + # --------------------------------------------------------------------------- tmm = SecondOrderNLTMM() - tmm.P1.SetParams(wl=1000e-9, pol="s", beta=0.2, I0=1.0) - tmm.P2.SetParams(wl=1000e-9, pol="s", beta=0.2, I0=1.0) - tmm.Gen.SetParams(pol="s") + tmm.P1.SetParams(wl=wl, pol=pol, beta=0.2, I0=I0) + tmm.P2.SetParams(wl=wl, pol=pol, beta=0.2, I0=I0) + tmm.Gen.SetParams(pol=pol) # Add layers tmm.AddLayer(math.inf, prism) tmm.AddLayer(crystalD, crystal) tmm.AddLayer(math.inf, dielectric) - # Sweep over beta = sin(th) * n_prism - sr = tmm.Sweep("beta", betas, betas) + # Beta sweep + # --------------------------------------------------------------------------- + sr = tmm.Sweep("beta", betas, betas, outP1=True, outGen=True) + + # Crystal thickness sweep at normal incidence (beta = 0) + # --------------------------------------------------------------------------- + thicknesses = np.linspace(10e-6, 2000e-6, 200) + shg_t = np.empty(len(thicknesses)) + for i, d in enumerate(thicknesses): + tmm2 = SecondOrderNLTMM() + tmm2.P1.SetParams(wl=wl, pol=pol, beta=0.0, I0=I0) + tmm2.P2.SetParams(wl=wl, pol=pol, beta=0.0, I0=I0) + tmm2.Gen.SetParams(pol=pol) + tmm2.AddLayer(math.inf, prism) + tmm2.AddLayer(d, crystal) + tmm2.AddLayer(math.inf, dielectric) + tmm2.Solve() + intensities = tmm2.GetIntensities() + shg_t[i] = intensities.Gen.T + + # Plot results + # --------------------------------------------------------------------------- + fig, axes = plt.subplots(1, 3, figsize=(9.6, 3.2)) + + # Left: Schematic of the setup + ax = axes[0] + ax.set_xlim(-1, 5) + ax.set_ylim(-2, 2) + ax.set_aspect("equal") + ax.axis("off") + ax.set_title("Setup") + + # Draw layers + from matplotlib.patches import Rectangle - # Plot generated reflection and transmission - plt.title(rf"SHG generation from crystal (d = {1e6 * crystalD:.0f} $\mu m$)") - plt.plot(betas, sr.Gen.Ir, label="R") - plt.plot(betas, sr.Gen.It, label="T") - plt.legend() - plt.xlabel(r"$\beta$") - plt.ylabel(r"($W / m^{2}$)") + ax.add_patch(Rectangle((-0.5, -1.5), 1.5, 3, fc="#ddeeff", ec="k", lw=0.8)) + ax.add_patch(Rectangle((1, -1.5), 2, 3, fc="#ffe0cc", ec="k", lw=1.2)) + ax.add_patch(Rectangle((3, -1.5), 1.5, 3, fc="#ddeeff", ec="k", lw=0.8)) + ax.text(0.25, -1.8, "air", ha="center", fontsize=8) + ax.text(2.0, -1.8, r"$\chi^{(2)}$ crystal", ha="center", fontsize=8) + ax.text(3.75, -1.8, "air", ha="center", fontsize=8) + # Pump arrow + ax.annotate( + "", + xy=(0.9, 0.3), + xytext=(-0.6, 0.3), + arrowprops=dict(arrowstyle="-|>", color="C0", lw=2), + ) + ax.text(-0.5, 0.6, r"$\omega$ pump", fontsize=7, color="C0") + + # SHG arrows (reflected + transmitted) + ax.annotate( + "", + xy=(-0.6, -0.3), + xytext=(0.9, -0.3), + arrowprops=dict(arrowstyle="-|>", color="C3", lw=1.5, ls="--"), + ) + ax.text(-0.5, -0.7, r"$2\omega$ R", fontsize=7, color="C3") + + ax.annotate( + "", + xy=(4.6, -0.3), + xytext=(3.1, -0.3), + arrowprops=dict(arrowstyle="-|>", color="C3", lw=2), + ) + ax.text(3.7, -0.7, r"$2\omega$ T", fontsize=7, color="C3") + + # Middle: SHG R, T vs beta + ax = axes[1] + ax.plot(betas, sr.Gen.Ir, label="R") + ax.plot(betas, sr.Gen.It, label="T") + ax.set_xlabel(r"$\beta$") + ax.set_ylabel(r"Intensity ($W/m^{2}$)") + ax.set_title(r"SHG intensity vs $\beta$") + ax.legend() + + # Right: SHG T vs crystal thickness + ax = axes[2] + ax.plot(thicknesses * 1e6, shg_t) + ax.set_xlabel(r"Crystal thickness ($\mu m$)") + ax.set_ylabel(r"SHG transmitted ($W/m^{2}$)") + ax.set_title(r"Thickness dependence ($\beta$ = 0)") + + fig.tight_layout() + fig.savefig("docs/images/SecondOrderNLTMM-example.png", dpi=100) plt.show() + + +if __name__ == "__main__": + CalcSHG() diff --git a/Examples/ExampleTMM.py b/Examples/ExampleTMM.py index 25f219c..62ed4b0 100644 --- a/Examples/ExampleTMM.py +++ b/Examples/ExampleTMM.py @@ -89,6 +89,7 @@ def CalcSpp() -> None: plt.colorbar(label=r"$E_z$ (V/m)") plt.tight_layout() + plt.savefig("docs/images/TMM-example.png", dpi=100) plt.show() diff --git a/Examples/ExampleTMMForWaves.py b/Examples/ExampleTMMForWaves.py index 106d1a1..809ff93 100644 --- a/Examples/ExampleTMMForWaves.py +++ b/Examples/ExampleTMMForWaves.py @@ -81,6 +81,7 @@ def CalcSppGaussianBeam() -> None: plt.colorbar(cm, label=r"$‖E‖$ (kV/m)") plt.tight_layout() + plt.savefig("docs/images/TMMForWaves-example.png", dpi=100) plt.show() diff --git a/README.md b/README.md index 676f0f0..17d5b2f 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ A Python library for optical simulations of **multilayer structures** using the - **Second-order nonlinear processes** — SHG, SFG, DFG in multilayer structures - **Wavelength-dependent materials** — interpolated from measured optical data (YAML format) - **High performance** — C++ core (Eigen) with Cython bindings, OpenMP parallelization -- **Cross-platform wheels** — Linux (x86_64), Windows (x64, ARM64), macOS (ARM64); Python 3.10–3.13 +- **Cross-platform wheels** — Linux (x86_64), Windows (x64, ARM64), macOS (ARM64); Python 3.10–3.14 ## Installation @@ -62,7 +62,6 @@ The library exposes three main classes: `Material`, `TMM`, and `SecondOrderNLTMM |---|---| | `Material(wls, ns)` | Wavelength-dependent material from arrays of λ and complex n | | `Material.Static(n)` | Constant refractive index (shortcut) | -| `Material.FromFile(path)` | Load material from a YAML data file | | `TMM(wl=…, pol=…, I0=…)` | Create a solver; `wl` = wavelength (m), `pol` = `"p"` or `"s"` | | `tmm.AddLayer(d, mat)` | Append layer (`d` in m, `inf` for semi-infinite) | | `tmm.Sweep(param, values)` | Solve for an array of values of any parameter | @@ -111,7 +110,7 @@ result = tmm.Sweep("beta", betas, outEnh=True, layerNr=2) ### Gaussian Beam Excitation — [ExampleTMMForWaves.py](Examples/ExampleTMMForWaves.py) -Same Kretschmann structure excited by a 10 mW Gaussian beam (waist 10 μm). +The same Kretschmann structure excited by a 10 mW Gaussian beam (waist 10 μm). Shows how finite beam width affects resonance depth and field enhancement.

@@ -120,8 +119,14 @@ Shows how finite beam width affects resonance depth and field enhancement. ### Second-Harmonic Generation — [ExampleSecondOrderNonlinearTmm.py](Examples/ExampleSecondOrderNonlinearTmm.py) -Second-harmonic generation in a nonlinear crystal, calculated with the -`SecondOrderNLTMM` class. Supports SHG, SFG, and DFG processes. +Second-harmonic generation (SHG) in a 1 mm nonlinear crystal with +χ⁽²⁾ nonlinearity. Two s-polarized pump beams at 1000 nm generate a +second-harmonic signal at 500 nm. The `SecondOrderNLTMM` class also supports +sum-frequency generation (SFG) and difference-frequency generation (DFG). + +

+ SHG reflected and transmitted intensity vs beta +

## References @@ -162,20 +167,20 @@ uv run pytest -v [Pre-commit](https://pre-commit.com/) hooks are configured to enforce formatting (ruff, clang-format) and catch common issues. To install the git hook locally: ```bash -uvx pre-commit install +uv run pre-commit install ``` To run all checks manually: ```bash -uvx pre-commit run --all-files +uv run pre-commit run --all-files ``` ### CI overview | Workflow | Trigger | What it does | |----------|---------|--------------| -| [Pytest](.github/workflows/pytest.yml) | Push to `master` / PRs | Tests on {ubuntu, windows, macos} × Python 3.10 | +| [Pytest](.github/workflows/pytest.yml) | Push to `master` / PRs | Tests on {ubuntu, windows, macos} × Python {3.10–3.14} | | [Pre-commit](.github/workflows/pre-commit.yml) | Push to `master` / PRs | Runs ruff, clang-format, ty, and other checks | | [Publish to PyPI](.github/workflows/publish.yml) | Release published | Builds wheels + sdist via cibuildwheel, uploads to PyPI | | [Publish docs](.github/workflows/publish_docs.yml) | Release published | Builds Sphinx docs and deploys to GitHub Pages | @@ -189,9 +194,9 @@ Versioning is handled automatically by [setuptools-scm](https://github.com/pypa/ - Go to [Releases](https://github.com/ardiloot/NonlinearTMM/releases) → **Draft a new release** - Create a new tag following [PEP 440](https://peps.python.org/pep-0440/) (e.g. `v1.2.0`) - Target the `master` branch (or a specific commit on master) - - Click **Generate release notes** for auto-generated changelog + - Click **Generate release notes** for an auto-generated changelog - For pre-releases (e.g. `v1.2.0rc1`), check **Set as a pre-release** — these upload to TestPyPI instead of PyPI -3. **Publish the release** — the workflow builds wheels for Linux (x86_64), Windows (x64, ARM64), and macOS (ARM64) and uploads to [PyPI](https://pypi.org/project/NonlinearTMM/). +3. **Publish the release** — the workflow builds wheels for Linux (x86_64), Windows (x64, ARM64), and macOS (ARM64), and uploads to [PyPI](https://pypi.org/project/NonlinearTMM/). ## License diff --git a/docs/GettingStarted.rst b/docs/GettingStarted.rst index 9fa2784..eeef1eb 100644 --- a/docs/GettingStarted.rst +++ b/docs/GettingStarted.rst @@ -133,3 +133,9 @@ As an example, second-harmonic generation (SHG) in a nonlinear crystal is calculated. The example code is shown below. .. literalinclude:: ../Examples/ExampleSecondOrderNonlinearTmm.py + +The results show the reflected and transmitted SHG intensity as a function +of the propagation parameter β. Two s-polarized pump beams at 1000 nm +generate a second-harmonic signal at 500 nm in a 1 mm nonlinear crystal. + +.. image:: images/SecondOrderNLTMM-example.png diff --git a/docs/images/SecondOrderNLTMM-example.png b/docs/images/SecondOrderNLTMM-example.png new file mode 100644 index 0000000000000000000000000000000000000000..5dde0bf87af38fe8a4a7febd5f1c3247d06a9d4b GIT binary patch literal 63856 zcmd3ObySsI_wAviM7kRlR9d7W-tMFD9rK)OMsB&AWhBn9b` zuDc%J_xpZ#+%fLB|K2fR7{EEt-h0JdbIwhuhT2UMA_gK93PqxPOYtrWg;R$@VO=LU z1OMZ+Pi+lrYjadxn^ceb@MWpg!u>||wcC&VWxz$eDT_Q=`U z!AXLjAM@Yu;In^h$^X^Br3+q#(BYQ86ADFYf_!3S%4S%hPJgoJ%|dXe`}=^c;?|QmpVd9Jgs1 z?|vY0IrDKmW`gy}E6>M|)$Hs#liu!bNo{p>s6OsWh!&VlD8HPQmBmKj|L;c#Lu9)Z z&VT<&z(M%}#rfZVTH{^tCH(KV-oqj^{?9)M(siz5$Nl$pGO7Q6|FO&%l|(V}uyo_K zpVcvk)d!2&8dP`*qV{U-d%{>NhBidPD_)%H$+Z5cA>h$&COiwhbtgQh6^7rg)fDfE-hu}*E}B4_Wwq3 z@#00d%~meQZt2~+Usv19zpPdgKN)wSJ=k6fo=@>%;YxC*U~!)%uR2`)LSI^3R79~m z=0tk0d<&~j6^7hvrF3vQj63hTnwnZx$AysRf=+WPxB+s8?!VrA#3YDd>V>+c0`OVf zP^7X)0x09X^{GcasaP?5_ruZ@f-O3_mhx*^)~a_|nxE4LxUP&$_3J)p+MiE}QVOS; zdab2~g_@n4GaV{0aa;V9;n2eTL~Qy47naK3N0NI;GHB=&F}3^QPORz4(f-HonXfCZ z4J)o(HVkrN^*Q>*4jWCh=S4*aOE5pH+%?eDPsSXBPu{jrzI1bUcc(Aj2xj%JlU%C` zxUBWjc&x$^<-3&kdom&;SO_eEiF23kP!L(8?afz z_@pe2+k+3HV2|Gw6p)FIIpDOlwf$KsVwzkTEjMcnA%FBe9q;ku$30~jgXc`*6yCKD zBnD%64IGvWThg88yN0SgMSUODECi7-@~rgCG0Av|#fxCV5)+x67yAf>EW55PJN@oq ze@-uS1~XD3r>1r;{+gBl$?>6CQy8`5%K4cuYc&e_M%6D862i?Q#hb4(^+#5Z?4KSi z<!|8(K}CYt{JWqY(-AHTtJKqN23tZ#=Jib@5IC zW>n;Oi$&TaRW9Jn-g*P6kOeET`@bn1V%^!3rtlqBt`dKZkXt9GuJ-iU{+iVfTy>fK z_kZG;C0$dWto;;oTW7PY*|%{1-Gen+Zr=iL6X*?$X1~omU7Fdt9O4ktdvhg zMlws9PSiZzTm7=O-p*f}>bbjGwo6{`T4IQ?KnOmo7ny2;i13Qd zpwZ6JXo*#Tax|yO!jBJbtDol`ChM@OP7am`BP=add!NeaIE_{ZQ;6G>bUI!6^3i56 zuZfT=(Rk0c?e*nvot;XjC&wRV&R}Cv(bC>2FNWv89_QIn^!V3pCWygI-TdUKt)JDN zI4GUmdx7w|kODiwJmGU%ox86UdHbL6Cev@r)O@Ese10i_R3;N!Bbb!cZqIA7&d<6b zh-7=hvNQezwuUHXq!D8{?00BbU)@c{&#B2R4e#P(f@Sb8z^pAHHa>4ATt4o3>HF3I@?=sh zq>BT&HX}O_eQb1R)9=Lc#YwnaQIpzGL?Y_ZM2+-~C>CC3N>rumO4$C^{OE!8K+fA= zdMFJeBR-z18NYaAV`CX*WT!*U!~fV3UGB!E!dCq!NVIMAHgK-fX5yb?5(s>VU6(BF zsd4wNe^-*^D8p%bIG=p)M^!kl2Lyp3%#v5GTya>Rl!bcGYL7p^{kFPgS>bq?BV`UAJ$)c~7}E8ns)}i4q*MrF0}m>5{70*y#&xBCvPF6> z&TR7W=K}YwxxdRU$;si#g_S>XcmJG=EWWH^q|^orb-&X2tL9DSz@3#*v;ECqaUvK7 z=q>@mHUqbaO_&`U$$wN$D}HNlr`*};e_ZD-*_XxAq>UHncoa|&tuNr0K((YlQ&#AY;Jk-mXICLMh_DHDt2{IF( zow!h`5Yj>2q)cMIM@L7`b+QK7{?oJit}uw&J@?pNG#RgSDcec8YEA_4VfST4go=u4 zGAldp_M;}o@bDaq@WutZtnDX(U^mGnqs1Z@pJ8^PjBg4Vv?EL(sK1UnD zR-^W{$1$&~QR~o>Q!%4u2WyNXw%5g&Zb18`VBn`&kV(;V8vPvnDybX_Jc^?~)jh2W z%HPq7y^jzxB~c(sag~%loR+_t-ZIgoJqQv7NtT$yM2C7py^=@dkXmOoX`w&#mT#G{ zzsSCfx`L_%AT`}aNMaqTO(MHQ2q=xFKJ84S#r8q&eGeKwR{b7Tr-bKlTd8$DN zfm1YF9s4Z*y~MJc1x3D5uRD+V@tzQ1NLp~*$nZ^z245^3$Y56ErGeao`P!pR;+nnb z@Mp{B?o)xZXKQ7lETDY1x+MA2HcVfxZWY$AO21yNLck4*U|#QwD=&Zu^NKm|T2}t5 zb!;`UDO{xD{&3Vv!jXFTjSTixA?}H}`9+J)_&}Mb2Xt4izrg<& zWM;ZZo$Sr*ZMO3}Lh+cIOR#T7vL3*}G=PJqClgPDp(rx$Jo#+sw$&->xbPv?^mk9% z-k)A|M*s@V!t<2sQhpEyY3eC56$>8|dJ4^ME>G05B8|`=kGKGWhe^VjfY+d`@ddj= zPpOS=U#!pIeYh(Hp7`e)V?u_q(VY^Ib`W#$U0| zvdS2qR#jB!t>t>c>P#U2FY)uYAgQ&zG&lp8tgJ-3U%c+=!Jn_@vG;>EW?J55W)ifp zc=8x|t_a)ytfJ4a+6*(9Nbx=(JltJtxfpBss%U?PW5y-pU;JLr={mx;GF;rUEEmWBRk+EN*-B!?As`Omc~lFl#=GMxW2cKvMFRLi@Frlk>Zmp~j5-eKDNB zCNs*!l9jvWq-R=(W#RnW-ElRS;=~*| zSUi5SFAo>vM=%IK9!X@l>F6kk)LxZjDSALzC=`PJ&)yyI&U&k%;}z<&w+FTG3s2A+z69lO(92bO&_LH@v*b5=uzP z`99|{zZ{vOYAV20h+)x>DsR(u-x!tKF-J;mezU&ljb%KLqrdJ^{gI{p?X$nL#!D&$ z-5@bq>0$$DeEQq@C`G_G+tXavwJSoy+)#B387X`#A1bVRImf&YSHxB;W?rPEL>(P@ zIWG^918BSY>&b_Bz|&^ajiG?|jPK1WzqT#sr$Ocu0UqPL+wS<2 zB#{U<0*>s8`DD*^2*~*~{ zt-~s&pHZsS0Y2wxsn{8@(KIrOgnrN>eF`tU(W5|W9#J>jeQ|U-JQ(WZ)LYBsuQ;Sq zzHfyrr(+E4zCs<20I*>Sh*2%!CQNAkIR@o<_lPEKeY37p!VpEcHDnf*20Py#%P)#n z;k|O@w)HYpG)i4VN4$IGb`gQZwDAY@GW)a9ZjjR3_o@xp4=^aNG!Zy2<-qL zjdp}7=y!^{)XSDvFu7%Pa1d}{AqX~8p_2(irVY% zxy-L3arNQDhd5!I808~u@uWxz zjH>b1zDBFd5TfX=JtFfyJ$_OJ<-qM=A!EDkV+5mU^Xm8)$LUZmSU3{m$kZTnxGeOX zP7oUgZ#p3hm9edHkEL8UScAjiO8GkoQw00f9Ii?pK@<7?v-*pb6!#%=%7FK$0J_%K z`QebXRBsO$hyjvv_@T^2IQYw-nD06OgAIVc_!&vA@g}2*;!ZuEw78D%wb%%?1E6xO zC*-1&NdVmN*vaX8t&dN;8B%gNOqi@{6rr^A5!4)Q-sxX)&9*BykY0En-3K$G!SQrB zzjp0}{gC=n(xdHuc)_Qq)6=Ga(V=n0&q+B<`c^_mJ`P_AzvRC*nz{W1X3+|hT0b28 zED}bMYhEJeZB!;}J>=(aWOgQq>cR|Wvv&l8zXnVVBqGB}`7lQ?3tMX&&T|y2L#;pB z+ptzsi}V1vd0Y(G1sMTIW%g2kN$DE7e;9eMOesuvb}?mT?6a23XTwFnRZOv+96)iP zqgvjn#a~nA<>f`k^4-ref+7KPK>ag9$0$fDIWpHYvPXXxe6YI~b@5KjBrL5N#t=dG z&4*{{1W-3w+%L!+{661%f*^po?iBljX$7M@w{N3RE=vQ#5sq-E?~rI3B<8Pr@nXe` zILQ0>zy#9fVCPoe@UjS7Gb}Z}G6OuytTF7E)jk^&|*xsDL=w?xrZ+hcC(r z&?&;=1fb0)x=n|=0ju)8=Ba1PfjkAQuoQ=)4*sx$R$lWJMwDkXy!WnaQX!K~WOv4| z@XZHWA5}s$C_gn7 zg>u+iH|h22%}{SS+TYqhU=4=59pJh7-u>b!h{%{0XxjJ)u>q6xS@|m1D5M0SLWq5v z;_WwQTOq-i@0D5y!uX1m^C6%MOu6t=0a^a;&!+w9vBY~^48@t4E7^@BQhGAE152m5j;}B&`_4p4s-5y^CICz!Mgh%0eC8Zeh`7@n!ov*JJe5R71Zc)? z>am$~eSd1BapfM8{v`*0s90HDhCwO5Amb|Y7Q|2Qx-f7~m%{u3TXIR|ch4h)$ok$) z)XaxiBY8HmTNNobCMN9hqV{>T2Br(W8KlUb{8Fbc93r+u zzO3GR>{CvhSzM*R)-K4Abtxzn05STb!+ky}7yz$&Wi`UtP58+E^ghHeNx6|BL=}{* z&|Y;}Y2GcY>wrDZ*81#C1&hr*7jpRX{U+BnE_L7muoPL?D3QwYmw-8fQ29On<;m^k zFj^%|l@wv%Pw?>Y2mWGxbapNfaH(oUhFV-q!< zq$>~d2(M#f8tuA|#Nt4TifF-% zqBMMD@5w7R0!uceGd*iS>Zo4PL&Bf#^UT22or%5gO5X*c0#gJl{aYWXFnds#!=d6d zK3xX>?HLO!^q30OQ}guj*-9nQm@ffjKsP`Lp^qztQl+0#)siGoz5)28iz%PS?as1D z(ZP^U?UA{=JWRPOm8L<^)YKHzjZkQiQK!_L2g}z==d}qUY*okJ8_I z2q}h8m2(|$10XIDs_M~b8Rmxw4mnnp%^+Wc_dhd+|K*N&Hs8f#SX#)kzZ8wC};j)I1qnRNl$*tK~kRVcl&&7oP)MvJ6cA9LP(eY zW3nJVB&94(SUmY>uMl+kEFkCp7n(GUZ?hX&IXQ|zY+<2lPY$>vWl!AN9f5aakpilZ za999R-0XeS2@?3JMMM8`LTAw?9x@z)Zo-gO|J&oiAf1Ipx4??)2v zy(xStNEf%$7H~R1ns|x?;r#sw(VrpkQ`qlrM%{qS1BAi~ zk<+eCp2(JUIHBy%Rz$4Ssd$ziupAcKt738cpHhat`^cdTjZF#C ze{%QGOlJTyRKN}-1Cx_XGB5))8Oa`30CK$1VOJKr34I3w(gFJ0)EiwR#}TIg87~B( zht8LXE7HjOa1r|7;+nV*+$~D$9zXkNkIjgs)@OE-hEYiQz^3H4_^F0(Mgi%Qp z!Momw<2C#8=BvGnwhDjW`r-v&oB!|;e(xeBh!8LzFKiP8Ajd@d5xiJcboy2qA?>Yxv^F{*X}# zBAY-Y@oou+F18n$wEoFlyu?RgZT1tU~kzT|$ZqfBiKXB`rkc%!OOi8e+Oo$TK zk+U4_secBJvj z@RDH-B4thPiG%9;&j$|@BS=|A+9Rc!7*@6C?u}aSV}}8K%c3t zgC5Ap=d7|UgGQdYc8vddd&TsML=oR_JjaK-Ex@`U42;?KVt<^J`_(gN>3pF)Qm{V# zLyr1=%mkWB7(CqKgU)zig)govwt?y`;Vm;?dCSMrPgl409ol)zQ-NIp{#dJR{`|jU zX!?#E%jCUV2$TT=6OrVQmlw5XK}OcI^jC4=Nb6aBjKf$PV1S?m+^ z`Y2pAQROZK40Ge_Ze_9sPAF=yu1l9L`KDh|OHd$Fj7iP90#g-&EbD${Ro4(4Fe;Nh z3voV;xPWCCzOnCxfH`0(1EDjWLv*d5Pj~M>YcK(r)h%<_(dWQY5IfI(7{xeI901N!LZ!^eDfZpJ6ifBV6C4G~4Cjg$X>NJ$%*|I1BrJy)`>Xx8P6$k?! zB!=7t+WO6jXnL7E@=jzgS8HD)adGdE-KfGF!WiWX01TlaB@91Q`rGU73j^IXEB+}Ah)DMP7K_VOn1@avZf}4j5&Aw;r@*_MU z?R{r*gam}XPCnBT)dG^>_f$C?;JGD%&6fXy=(=1fUKBt}H$$NgMv!%X78>DX(Z2r? z+&L~@0&!lAQSMCjC%l9ZeE`9xxd!FUum&s?qo`dYM7lrHiC`#c2_Zl4 z06a6o2UKz~pwwiKong$PMc@#!Upa=KDPVV+?mrn11YyP8`6&U%o7b;jBYYKrx7l$v z0{P$*5yey&_={rYsR;N0m~K)cy})UN%Kz47e0we4ljIL_^Kg8U^I_!Z zks!lm=NR{4yoCE#TL^g$DS(j0S6=8*eu9Do4Mt~a%L|6-B9g!J*E1)kpE%3=)Q{YF zH1a?94v<;hpsWR+K+fCSJAx`00yrnc_2kn$bBNG+CUWlC)?O2vHRU8PK4_wI+GtLM#6*hE%%m0ISuDGtiN zV0`GkSZL!1+EoKwG>^Utc#os~yLgGF9yi%rYAWMh!8T#)7my_xP$CROA631hV@?PBC3^asx&v~Hh)m$Oz8X5=C4L>ozhH%Crxjn4pfbBQA0}Z=)2C>Q$T~)?fcD=pWQO4WPoHXK6YUFdGWlyPlYllO!510a5@K1PGXFO#pQC|zf z@XXXzvk8)q8+68G?U~iY%gBFL6{?T5Jot0;WT>K?D*tB>aYng4#i8$6veTtA{4T$QcEd_e)*F(R@ z$MYIu)y>|pF4W}21m?DNBJbfHEtAOC3lp}us1Bnt;k20m^wQq(nXjiGEc_2hJHrIbBFi|@AuY6&ZG4I%+w)& zD9>T3mxZpyU2Z|)mw#wt@@KOa$%*}*eEleM9nO zgpXm?R?wun6ow5$2QZM+Am`suQVQ(-NKT=LmH49N2RW&OaG?-ZS{KVy_Y0KTLrlHN z&ipdDt#4U6E>ye|X~e_-H(fbGN(`yI0R#x&4YYnC;ahqMm?eTIe`)Lke`< zIGLvsEMDt!8J!##aNoMMD_%>dygU}_<~wY-r9xQt?6D2~24#l^k1fYitB0i4uYDC! zD^fqT?-CESZi)YOEpbTaBoHs(ONcL=J3TKvL#F7DaHKH*AwnynmLc1PYGbB7N>VBQg2k-k;0+hL~+qz-zSl->wiz=EaL79-5OBVr}<8~PpnSkhN)YV zeNlJBZn(2Oi=<3k*snU7!uqy5>~r>DHdVG|+dT@H6%fNf#6+7AU z$~6ji-)?Q{M`n4Ck6MaNYTj<kjJJGS3-VOLkjeGaPkiNqbg&%;gn@@Yy?>Y*Al)Sz^JtC%_A)(0W zG9n?kx{)3FJ6EMY#?%1&;;5vAR&u}Ma!#ap-COIy*F03%%(8z8q>#SN&9@7Thdxm# zOVwKwdx|$&w<-%yrl_cH-*H%V%hbv^hwxUYx{kL(-$9nE+HB*d6XXa?JF%JsJd3D( z8_*Xg!93(Uu?B4bj9rL|CqADTfVAvtkL|}JeXplUIS0FfNVfV1xS0!*7aI=-u9}&5 z;4qyE<|GXp;@xvGmX5x-!rt>~5hqcJpDL4p2BGUEPImP?T25W9JzBV~hNWNnw(HKc zfBQyHg&`jTVBIGD@WBF*Tu-gct1i7w1#(sZ!YM2lcQ=E5#TT8eGX)e80!h~=14udO z&Q62LddoLYtkv+phm>NX3samfmrW3VG?42XfukjME z*`H%X{2LY3z?IN}l?kNDAmr&l7*T@rx@v3gVcc|wgLK`FuY6!$IjTE^dN6dTH7v~8 zLuc5XA{%?MIw4(CX1{i`*<4_U}Cw@8j!{njCcYvKnG z8nO4ZMsvLbsA%Q%3}Ni=ZnVDw1`d==>V{y_ZeR3UKWhF^v1GlMv1;8{mPpW)8U$xZ z9T*OG=)znsQe<@!wV&Oly)A+Z(X#kZVWJmfkp-m!-Ou?~u)om#Ko;BFQ%GpgKE=X< z#XoZz@u$H~8y_42>#GD~F5t&#_jjgnD*x#Jr!W{Y7jSMB`18Ib)6|K6-&<_GuFWM7 z@wJ#iC8bV4CtEGAf+}G*QSBA4|C>VVer1oo-W9C8Q1+gG!gF?iSO0BN{*kf8{P_^; zM#K+=7~>FS04U=E+u^HEN5KfOlxqGqV0(mfbFwpR?vIB~G>M-@^X+#@%O0HIo)F~K z>VFfB33&a9?6=~T$YR%z26_XHSN`)BLwhcB^M(R~TTT>;!c*UGvNi#=_6(xO1k^t; z3E?7?5?i6b=wgU$E0b|RLB|VAVRH3S_7bs(ukOd4A>~dVFET9WxV%)(KgHrzkNM7V8MeghNUiSW+~zHCO~UVb4~yJtt|?u}!A^RQ zFQ(x7@v(I8zPukCmriaxGq-0pnsK$82iZ3*>PKPB$k0b&_T8+jt9F6Wa-J)M=L7gp zeqf#+?x?mhfwkv4s1r~OEhj<7RDhWPI7FYxkn@qZTK8H_33$6qyRD0o7gY$`9}Ws> zvG>@rICD&$q@5jZeRYeRhwI=9*PZ`X^$o2u*1Z$`j9k>t3D!01`4Vanq7kFa_bfCw zP)~PGb6_qzckkh|?VlH?^@Vo=IyK01pyM@}ePDQ(w85GpDA|yMiagz0yo=lZB0EvF zwUo)W#tq)!@?T^flA_)$hLL+ldQ%*OC8tdc?vZte14Zulb7*^SCh(-Au1j+^&?U+=nqV4;=iasgFx6-M2DGS zv4>qmdJDp=dcpLLunfp3Qw6&34>M48H1FOu-MdZu^#W^^P;7C0o8hms?!M7fiwit_ z)H$4=Cvq|*Kw=&J$Q`bbO0p7PbSonoaWa#o{wjB`Hu3_BO0U*i`lDJ>yzo9Ia`Qx0 z&EPtjVj_=z5iYnUE+c~y$iwHr)YlBvTEK2hOzSI;B#hX9T|TlWV#t0V{RAPuAbB{Y zEq=ULzQn`RR}1pXo1V`I{x7fIrW9Ef=NS*~#8YjY${hKV!?*9mdZW|G52g{-(Xti( zhRkvu%zvTv;Adl$7T0~(CCfH;HCAE=}sC~&Uvgd#;g_6Al|{{w|KQPpZ058q-*aF8C*=r zLR*@jb5K&kJMymWwGeBg);074UTQGj`>9&bM^(nEW7ieCchg(@;8k5Jq1RU~n=cn{ zPP;#>>t)?-e|=_0%|NbC!}M782pX3uC`)ezISDJB7qFwa4u)c(rUQGBZrPno7%>P2 zMlcq9Umr#sIiH>8Z%5I?1PzQ$_Nmd`yRTjl)Yy(tyxv#XbH7PgQ?qn-N(O7rL~?jX zUMIPq`+*S=+jNuXNt;~|#%wO9Uftl_WUb8;(=AF`f+$h9tX?{7>Gi;-_2BwF%pg0@ zQEe~D=*j*s`#rbqb6!;*!F^q`;Vy+{tt(8zo_GUCXdc7jCq75SYxzTwySlb57rB@& z7Yey7S^dIF{}+#i4`j$R$PZ`0^#zh#cC*BZS7Pz!J%rK*xrv~k=^r6g}IcTlDGA?TIO;=nW7{j zCQcG*(u^0e3F=G`c}YOC4u#wVY>XAlMeXb0OP&FzMkC@KOR#(8Da#Eptxvy={a&c5 zTkymwsh1}1tvIT}vba}=O!zg3NsF@GpkV?@SqH=VM;{#kc3d4{3D988Kz&7&Z4kGP z0_>m`ku0H5wWlYNAZPPRb8>NUU37}wS3vpl9?pt)w9>?y;w2A$ zYt8>Yso{p7>X$HX)2?XeLcRpolggzR&ZB-mhPn#hA6^+PaoUpEFXhdzl=TY{)%!!i zJKQ$C>~Sxmw0C+Wh;GV|g+O`t&Y7KL9c5Je#^Et+3vG?T7ZMlZMR81|nW2Xc|Lhn4 zJ$ISy&no!LT}=KHB6fNGyTelo7sYH9D>mK zh{_3x8sk8>IdOXOB++ZL)eQtJMB77zHl*NLbi}eT;e8|Axami#{4W%y5~L9VdpICp@_tjGA=j8;Xm z4*M^irPew2_SKDt2DE|E&l_*i>T~%DFVgfW$W@PARzcO7&qR^Glqx-zIX?@vvLQKTp!}E zf=_4pXEh_Z5EzhABG$-*5Fy+^5<@Bzc#E&*Z6FLGFxe(h+ucBTM9kiB`9r7zxaD5w zGaDvkF@(STM=0qSjQoa5&+`N*d+4AO>hG2-Kg=LWOSUz*{3WePXYh7OvlPIVX-91> zHXeORZtS!;Y%#&8N;jTfDH`H77F}{GPhT8mojlWwzuy0szb?F*h{;;7$+@6$Zdq@t zg!=J0J9aEXX2RE4QRNO6tB0({FhU`RDlx*u^uLgSbhnnYT+Ytp;;={lNvcK3li!^k$y#J9=ZKD-& z&c2z9L&saFab)^;fYjBvXWe073nCMO;6e72c!)kA;G`$AIqRp^gOiA5LSM8%*hdz6 z|K+8*R&Bdn>SYfdT!nADZ_QQedUURwh|7xvR=#->CoQXQhp`@gFub+7S>UR33s=Br zt^IMl`NJ%Am#V*v0ojX{eGEMpqmz$*ObtPzWGiyk8*?|M3e`IAhto-WTtm!52+>5moX`E2WZ5sFJDmKR zC)QmjAjk3=3vqU2p;ZQ&K!}lrcMG+(t9>bFgy^m1t|cZ^_j(5L-)4@S&40O|haOF^Yaq6|jzhWRaV+xv?qqih#n5i{h^ z-@ZV!{EUWigze(WCp8&uNirhh6^n+t=+4}2e9A4{BAbhpG0OQFordPzCRQyt9V{tO zMLe>2%L=74KO|eP?zv4|E?D}MwL$#bSq_;!<>f`@%gtY}r8tgYdmahkh?zf!im0el z1Y7{3OCv-(NMjq|C@=$sZrx1^9NSOp-Rp*lmIzfE8!R#~q=%mcN`{&PWVq!ii2Ndj z@Wpfr^ER*Fa^r(pqlo!|naz5r6F3>b_ynI8iO<%JG-S6-3zGrHlM+^cWKY5fMeX+{6$Gkdr8J>52 zTW8#q{`>3Cm8&}e)GuxMF4<(Lye^zJp!&%aB18pk)?&tklL4D~RLzWaa&KN>4%NPL zc9_Jk?4?11ZHjen#cKza@LOjjn=1Fr`o#E|?RC=!W%`lhOdoNC3lUX+e%ujTDe2Y7 zHkKf%IKd-78 z$UnTy7fXz6=4@;91`O9G!$s!5A!87E0tB7OJ}vbo+0%V>7*NKov@l=8#NO`myr@q^ z4=YGA{$$9;E>3ze{%};dHSA8|bTjW_Qaiyz1NJXgwxjRZucTtQ9uB6oZL7$U^X$8* zj~{=cj-~iI7q_*W$xK@CiO9K%#rSV7w{F4vAVzWU64D@+8pNNZS87d-xaSaw1>}!xqR3~DBFv{=nhVXeGf8D^TOFS{H=mxS)V=FWEDii7;r}&tp%}i8 z1@WfVoSt|hP699mG?Y(xhr{P67V%6l$xJT62*I%G)kf_(eRHLNTYbZe_zCsts;` zE&Lo4h+!SGIFi;oC)I~?D>w)&rC3MN+&Z}kqup++NE|k=n@`;^|$2*SQnib5NU%@mT0_wR5s7;_iMfY-E zBw1Q{6|`KGR$#T6!=R8#xrM@i1rBY&3p&q2aYNW2>RNCakBLy zxopb?=AmArm7m`hpI4)}{6~wqHD;>{#QOrM!pMCUxPZ}w2w7lGF@|tgONbG0m3NH* zCQ-^Z)Kh0>3zfmGE3T7S#{O_Hi0rn+`>`N=y$eP&yaR9Ywo53gt{){^vz=VRJ7E~w z$V$k*KB}kQMVxHQc;PRb(5MWTRtj#lgABIpD=hqaAwvQqx4CZeRrt+Q#@SKt#JA#- zw$s};Ji=q%yb-rmw&>~7lC|h~qGDqN5LW~d48orm?Kj=sh<+o|9ygwBD zcp<YgVvQX4v``FuaLkqc)U6Wol=!u!v~$r}+2?BFtiTQ4_K zWS*i>pjGqg)?A|a|PUw6t zHuJ+BayK3Qs1GI9j*pYA`(u)Jr0ZO>Xfn9*D>~Q)v@^4;_ZUrVqys(`YZdpeTs>i& zn-_uMp8a5s!+E4aXREm^nzh>tbgQ5juHI@5F6GeLyVUe$o_=Hp8cwlv@;?j}z}IPD zg6j)R8XUljKLr;ZvRr?L=Un)WZzMiy#eKJ7)kV$Vh4<}UI6wJoHZ-5^=7vtjt3a{b z-g0?`-0%Yxu|6M~6(Zh&IO#mnQBlxODl+`yJ|o7n4d=VKVluA*i}8R~l7=0|tLekD zrpjrapx1i0+`S-z9@{00h2O!8-ac|_rzE3_ot_sVzT+z0G}t(+AEB!kpT(Up|LJTH ziBjgCI7zZKqj>-IP4T)}gtiX}_`k4V*6(RA&)6PtzB)CaTxWG1@&BV`@vd#_qrG3* z@elhuOrW`gl===XBNE_Zt0hE>R2kV1xOua}WnRRN4|hFpf&)%dPcH=EcpB)@2i;)Y zR!gvAM580b>qMmd0E8EzQ!%pxXK-P0NB7RfmKt^$D~7+sR;b+jim{MBpiPYU z>A=R43Mq>61(%93+{L96v84klai+kfKXDVMZsb%9gGWy4gwYoDS&=t3bv(c*qsm8< zgs}@h7CTJItH4DCxb51AkOts5O>?r8+g`WE=D+nG?Hb*IXP(k)u9VO=O!iw3^Ww+r zY}<^A*X+3W1n@l*c^(c9ow;l$gvsUd;l-H}*d#laG~w2kv?6t|?Y<&g{>HMDhs;yj zZ_mkQMcYp#KjUa@Sv#Aild)GV3%Nu0Qp~<;;|wgpbgyH6YYGZy^WX!Yl^1B?XS?=T z109YdVSUs2Q-LwAxh^Bv>G6noJqfPMuK)>O0xJP`i2jO4^?@*q^Rl~C%r)x7*@Gq2c^! z=w6e=$Q=x!iNn0etq=n?a{I;mcw6@@!!?2@Ki#>IYcCm{MI@}&JVfKy%IySYoohkQ z{p0pfMlHUCEL=1$yp4X8t@W|58QQN*Ggsn<-Ab(NntXl>P3rtR;`NP1=8r2ui*5c# zM&HLc1+5E&T>DMGdz_S*%O1#V$U1xO-Kjb_=InKqghc=RS+(iI-GXGFRq^LSC;QZu zGJh_f>^IpH4!7#6%qf}5qf^BVcA4`UeKTt1VnZKHuI_ehi`(XAuw~q{cycL+sCt|; zt!r4HoWP_feBxbuBfmpK4y(%iSJKPvr(M^O+i{Ae<~^x$det7n$e0XcI30K(_Pdwk z%p&E$d?;wCMnb%#DtvO+c-uB3_ZDjwQC}mrmCet>+O;X^>*LJ}#ev^E&XBV3d!9$-eab2lwDKhz_#7tWuv>%N& zdz5*`Z}YqCRWXO_yO&PwgCA%~E-m09vQB21^TH227WF^fdT@!~V`n)O=uC-6Xkn8L zr@Hi(#4?WR%;61IOq>2u)$vpA;$os}FU5bl&5&fM-n#rT*j1CDB%(@bN9^TqAp&Db zmPxwL@4SX`9@Xl}-=E!nh!=DZZP?Zs%4_sKE|6>nD+cXnA)SpaIYYka>!#Yt-m@wE zMkkx*Pp%7lB}>k(PD!%s!9aZW^_KOVGe9cPUyN!{TzpecUo zn5z)KFMMtL@kb6lL=QFx`+uB(2{s%`lE{Yx&E6({RL5y>FAdqVcedjUDZ4&Ug{+D$ zxU5gh(_v#g9+lJBa(uVUsD6Q_e)O|}YY`v3_8rrAe{B%mNo%=lbR2s+u7<{>;ftM1 zI~P*DSa`U^Ae}8QDgLr0--=$Bj7LZCisVyY_qFWY*lU6-vr=_cmi;##IZB~Zl@7yq z3h$|Zr|UZt3YTA+kVy*IDa4!##sC>FaK8_gVG?>R%ths7*N3Im3|`WE?+;lK6Vz)W z*$6j?@qhx1UDYx)d=9DuJz}PZn;$}t?whWY&T?peEB`<)?x6pY(_>wfD)yCBNwJg7 zPhAqDYvBi9gX*)`MRl}|%cVXhHBV4p;WJ-Hjeg5jy`GtXYrv6=o_peRiN{OOq^oIe zc~&}RZ0+d8bs)ODcUhl${N2FkQqFE`U)s7cx6nV_W#k|E+c4!4L8s%1he^yV#>j7% zNFVuslW#w)D2t;eWN~6tokoZ_H07rYWba^8`-+Ngmyzjr18mzs?wWzi3i)jW2xE}0 zM2w&XFghZ-g!jq5B_cE+zuN)?%e9hLK|#-4(_jqeYlC)`^Vx>nSFX;we$Mueoc zUerq)DSNDw+x=$ZCOV?u$GrcI{!1>8v^ruJG&)T{i9ogAS4lkE%klD0U>S^P2-1>A zf45TxUN`8}TqR92vb(m{ua;NjE}dI_I(;cn?{g`8`vm5fwv+sLmR{_mb9K!gXI_=} z65ax3PZOgLJSAc$&Ab0)F$I2e2R-=B8o`~#RKjyd6K%Y<28XF1c8X18Ac0X@+*{lL zB{C)&mG|MA?GPEFivP8r?$)0Ey`>A%d@9^vhwGK~h#wfP?WclARV~4q(dgR925O6R zYO27R%2rS+#!qAD!f!<Mflmzt#fIAD}_=-6Sk8Q0>Z8-g}m@5f4# zK^M>=DEY4DDow3)wAuLYY8Sw0dHc>Cl9W;iVPKcP!U-`KU4fNOc7Cl(Ax=c}1HI9pf;-q*zokD9LyKB9=|UrK&F_KX?+K^W&NZ z>u;g+SBCT%vTO4qj_ke1;`}4F^x{`kWN_nU`6XSOH?_BtwO=M35o6ab1j=K(KJJZE zNZsFl?lsRHE%|rq%;JS>zhB`FHlqEFd2MyN{d%KYVA@2qckG>^+Rg`|<(lI>LSz{y z3G`N?%Ub9#**Y9-Mx0}*E(IT7(PfRkv zr2oQm)6j6^OH4v3eaqt4XnB7afy*p(wZVh?osBh>AhlrC8;&ogXkHq$;%3xk&*N3$F6N*VXXsN4>OcATNXaipnndWU=#<1f|5dWxGZCr zCz1_X`LGiE*?Wiw?OWP-4+U1M_zo<)`S<8sL_P&?RhIma9Yq@k;m@6f=#VU$_9jy} zKhk7hj9c{HJTZpYOT#`Vb4dS;)epw7iaV;>VOl`Qq{T!I12HYy6 zp)si4ReAG0G(Lb+glMbk66v!>lY%1!&*#?V=IQCGkaO|nIg#Bs)Z}YC3BjM-vxFu6 zLbya)C`pJ#Lc{5%Dz7W5^qU`ijhFUgU)?RJQ9t(LZwprls?xzokMrTVI7y>z+9KF9 zuXp6@=2+Lwkv;m1uU8yR9b;R_hxx)wT5!2MX7_|^6)SS&@=lKR=>9gtP1L9&8eO$B&RQ`yYeteH%H7dWb_}LI`w=Gs-9O?C z`9GZ{{Mo6ue9BhM%Uvc+3_Tx9R(Z@U=vBM04q#+`Y4exD{iH`G1E>=ySz_5jI=;h| zX@sXmy5?M0QaEzi7r9#p!H3ws#V{;#?_&xoB)H}JIQ2{j6mv(po0 zbCOeXH)>P<+!wcV8+#e-`OZ>!(2gh^X?L;f zO6N-8G-ZshRJqP5Uq`O6yKltkzUQ@=o8wph+<%~MN3kN)vr-bR)j6#Hb@Z~ndQE10 z@55Zw$0NU0zbHGas3_k*+7Bh&U4wvhE1(EN45cE?(A_N| z-AIEVNJ)oCcc(~5gGi?|N_U9BdFJ;&7w7g|c;Q+uT+F=h6Z^aOXY*yhp($-j+$ykD z=_?GNsHGxdKppW6gdyUC%C3I;Uo;sMIPl6lzr36`y`Rf?ru<`lh!i;_!jk00WbG1?jCv`PvnlCS751qlEDqm zsFJ#)!&IWCyKSCGOV)RhI-x1_nxxFX-mebEwRc~NbULeS5q@L9Gx?J(``h(3=^kHs zPf7WW(}E7Y;*H}kqo`jVrP}NMT2kU2Q7Qa@k6&;+^YA>UhhAiQ){vc(+wG9&P^X-vbe^sTTIwa< z2u0-~O@1sYbZC|}h99@Ehhhnv@_I~IopbsQp1;!+YGL(He>B>LT?0^qD>#dcDqd_tmIn`SmTWud*M# zy{x%T==vo8``}6N9w7IDN+Ss**a3OO1k>VR3#?tP)S7OgJhy^3z`?&_BYBfLB7CBA4ikPg4?Dw8@2#39dJb@aI)Y1rg zYUaDQl(ZSu5Lr7AbhN5qkam>e8cRuW=4Y;%YPk7AuLMzsw>Y(K_gq`g=vG`_5;%2? zy+gA=>2BNeqK4PAIQY~Fcq+R!o4|x}9Y>4ZTghO*CKF5bg)C$H3MdUs_sfi@<#6XV zVWk2yALop=bnwGsQ0EqfIsOK-c*oJWk5{Hcb-9nr1`m|oV~SKL7i{*6g$;c^$s2TJ zZJ@+PKXCK)wCE}Rd*~NyW7_<+Z@()5!QXz><28yxxFoFeZc!(0ZN$kc~6QxS4?z))g>aA#EZk5RhZp&Z(!i z9QYcj_)De(3%>qQ0AyzvK|JthfIkRosi>#~0wEb+p3WH^0x~RU$jA!vOD%jIL)&is zQBTT0*3G(_LfC##Z&Iu$#@I|&aCh_P_Z3&EIXYv-Dr(oj{N)!suMwL1uWSnsP%a)S zGf400OzjJLX_kf*@adLCk0c3|6$)a`QdQtaNayG%*Nd1xm3!gE(wepP!9_x^OyTQ+ zsiz_4B2w;a{Ap<)gAXf4&xmP~$6oR%Det^U3K|yr( z+5%m#qO*2Te8bM{sNG4n>+!?im3HjBEH-?fM;M1tMo(KlLszV^>a;zR{{RoRse!!| z2Mm3lWelal7+xnfrFdlz^P1OQBj+n|LE@T>X&=LKmoEmU-k)%q*{ z_cjbwNiTt_(LZJRxbZ%5`52pNh=YUUTNZ4K(%k1_?;A*W(p9kw%;qV20}0V;igu`$ zlVDEBGq9b6uxhJ%*hH*Ts>~z224i#Z)C+pFkYedgH$u>~dsph?HQ4s5dQkI1A|#{3z$J z`=xW zgI`GJW#WIzT87bfb83e{EXgKiMKe5kP>3}c4gI9g#~@9j4pZDk(#w*r|y_LMXH(Uf)-qWZ6EcZ@xp)4f@(!h|>W z1tqqE8m$$xXk~LRp+I_zAe#VhH<(-zeg)Ppq*WIQ=L7-Jj0wwv?99@jwSCFij7D{y zCNm7DJF-s1CgNxd<>@US%+=ve7`AR1Rj!cP5LmQ@%oGEx478$UhqKOci3S-4LueU< zx{kppLDo5MVrx#$$NFgi_lqCTP>duxGKxlKfSCpKO7Ak)-Q;J~jSI)sN6HIF77w2fyTvtX zQ;L3pDt=qcPx@AM*Oikytey!5!#a9MTQmGSKrlvtnBeLR5Mfm{H7y5mE1dUkNK^ee zS4wdg5%}%t9&b=jFv?3}_fXzK@ygQE=dU%}2=xE?+V%}UdSmpb4nszWO+tbJ84(B6 zrC^Esn13Tk@{0>T(e}RdLF)J}lDQuO`{C@2|*vh(1*%w|Vy) zH{80SrrGbqw^0b+WPUJDOICuZfyi{0Z39l7K;1KpU7Z0ew-k_x(^3AEIqco?R`iod z>dh0ai#6u3%z~Iq=r>#p)oR`V{uoL2GF;0Mr8tFg39}h>4UN}O)c0k<$k5MJEMTsn zH#avo0i5A@yN?IbX$$0ABuHZBg~-E1!j7KAYK%)i}kcjuuXuBi?Dt6c+33^6%x{>J1Og92b5;l6#==7M7no z4-K+Hv|_f!WNPmIq3|rhzbt%&)N>Nntip)=bgC=F_+0g|LcMsqn-ykiZI!b73N8Z( zLNwk*Oz#ahhwrcQ{9Kv6C2XruS>(drUkzY3n4X|nm>_RL)mU7!(8 zVM2>d?uARSkyJ~7(E9+w-{7zW7#AcE6(DgUT_%5yvpv_a!88%9_m5!7q^RID{S*%d~EhxqLb3qsjQPlOS|w?3sZ~=!d*; zzM&|_fxnOxY%%*ZV@PV1qO4S`{FX`SiU0MYH?Q@Nhx~aWrFn3@y;NVUy08Q6v&c{u zAKhx{=%php7tMF}#N3f7I+V%F)}tj&)}-qw!sNSadv(?`pTi}?N1zIXR%~2J0|W)=xT zu4+$|o>BQ^zdfFp-5Mis9BQMlPX*9J;8Di^GWHcLf}igU0T2;~Qr`&$n6CCxZ!|SE z^FDv>IU?tqm+t6ec@wUl>!ZoMa80*T#HO-HsJXDTuXaXcEsi;nipG5e2~REQP0-)O zS(@l0`$n>%z2(*0m9V5m`>t`~N5xArREMLoDCuY}syGWlN)0Dy7$wdck@eE4t?dFc zRuDlNtQ15r*vn{Savck`=t_7l{wct7_R9+8>$1kNFl33hxoX{`=7p$XQ!$itPH{B* zF?5vm-9PSLQK8a{ENfX5Hb4uQL}7c;aYZ1iRMS8uol`r3mLVitpS^O zp6T9*j>iG)&spsXho13uUUJ21DieevKC(?ud*c8L-)`}UThn9qV@T`Uv8FPEj|&Bz z+s;5k$>$~trZCH$EB5-t3|%9FlwVd+s2y0k1a7*^bq`XD;y3@A-W~AgBW?RU@EFs{ z9c#r&yLa08#!LkK|9QsHi)!At1A{@iZhe&9 zauHEYKgt$7x?2w43_P!5$&6dMF!_hG8VGXlz;|6cgVhVGRPY>X6Y6uK);vTG3%Gdo zR{;N_2xjVj=%`L-X;hLj*{pQ!m@ zJf{S+oZU)@yXIr_fuwn+5DL|n*i>#+lrekR_BhRq`efy^maO>GV@NnBe%=T2owSiI zaL^PO+YOVT64v)|uvtX#*?^zb4IA_h?7hv--yO($Q{1CedOmEiH#x1|_(TD`0dNQx z&RM|QdX#+z3@M^WBx~Q?Jj=74HYq8|+X4Z>4!y)))uTl~ABRa6a>@uJ$Qn?2eV@Cn z8;D?fwt3lp$I*Z+?@$}a5Dnz8;~>#0NK_*dyId4OMv4f4Xu61f010#H6P z61bu8D}akRstmZr1^r$8**jhh)G|R_n!|-nyv&D-mFho}%LCxHKkE3vr3!86E zJcr0P-bkAm{HB80+mlZaIztQB<8L@q5* z;S#{k83_DUQUp%iqA044Jm4S-T~V2eHdH0IE|+(r&qk_fGTJq_ZX@nno=g4ba@oB@ z)F{K0DL=nYO~?8jGjjTGQF;cVm|cl-P1aMgd_RwAV2JYd$ZcBOfx5|~^Pj2(87P~? z3$tG8i86GiD&;H;Z1{(p&SFy;{j^T`p@=#g1AxS$C+5D5CVT|+yuH9c#=qG+^C3Ou zu+9d%dT)%$xB7r@Vp{}C`M1F?O!UUXrIR!G;Tj|Hp&Vz|O$hqn`>z4#=pTMPJU{)6 zYJ|e?tr*oej9HP2-{y)qF)ROsc1D%_@7Yw+V7H`_X)qfP-8?>-pxbk6Ds@pHhkBzcxs~vrgYd1sFeuadqJb(K;5S(WE9{H<>7Fkc2bP!f0OBXjvJ;pIs z-0)oDZT~>bl~~6hDpc98IPaM)W>a)Ya5K6+EF z(pYazp<}v4vRzarKIlafO=WvW*6VG@Xk z>K&wF{nXfLtbuB=ln2M9okE@jEc~7flMQcv#RB>8@qrh~vEyf^Hsu#pT~{|XHl2~o z9~qv~FSZI*2WwS7+bWxkAuWq(S62LW+y#P19!fGva7E>f zeZy(6X5?jIQj+xx{6sWCC-)iyZqj5R$7fw(Soe~Ae$}0$#oAJjsydH@M%TVAHm$tb zaCc2Dt?_9eDRC#tmM^}$ZF7Bs=BuJ`E;{FxqxnE5}X-kR?jTj!&( z-A8oBN{X;F-@*(KznD=|4b;JHOmE!i!O?QSg!ikcY?L1h*3|oDG~MfA3fP(>rEe^! z)k%}L>=;JW!#ObLt*y@PG^YBUp^YRw)0?ViLeaC-nfVFFsQ_++K9gynJl)XmWpkhW z0inX}Nb`HDL11V5Mun~K-L8^j_#E?C&-raE^RWUEM-HGHHvu#fcXvW`bo4R6o92US zN2;iYBmC5Q`8|jc|1pC3T=XDMdEhVD?X)5yBL9^h3<;N7qE#AV`HIoZ4tS}cS$zN1 zEoIzSa;408b2L0?)^y=Q8`tfcsteWn zwYG@Qp?1C9&l&ZjwP1W63UH+UbJ?V?O>?MPn<-_9=K#|Y4c33*^_FKCzLa`X{zkYA zyE>Vu&?)c8wJgnzeAPLxC|8>W6l}Ad{2H|eXR#Z*Cisl z8UQ75)hBTm^zWaww+`qt0HiYjcW3)-UI8d_oGk0w#P~*v;FGd?TG=}ibQPs`jI~ONuXtng~eD@}@+9s@BQ~Vf}r_rxQMct?W5O|omhkTqzmeQ8Kz^s0aR$EXxH_os8R4NkimMN!Pg-Za~pI~5kTNen(? zIOD0eTz5)&h=t(i48Kpr2FgzEX`xNg&GI_RLakZQt=>9eVLrq1nThfR5{lX4%y)WD z6)h@kDEgvDUOzwHz=`TJL703E93;8`gf9$<*h98`R9OsB07zv%;0PfDX#&QbfpuXk z1)Z_dtn|SqlqBh;%Od=H%#XY_D6D zrtFY=qGH>}B|!zsNrKt~WGXn~g*7Ymu^%%1n+62a?6JZ(rvREYU(bcq)f2s(yTc52 z2=^IJrA3YH`98xMYxAPW^}y{g4+69aUH{4jxF8KW{W_k>sq8tC`b)?1Z(O$VrF#H^ z_G0YRJS5`V0uRwnTcbe74^!4hiw`flA&V-X7A>nD}2y(1qPmqxk~VRhynjMIxl)dG{DcZK*) zuZB|1kz{6doTr zSZ9`gj?((s+y|_uz7*A>>iYlqRz5v4awL0$iL*Y2>k-1j_u0Lzk`+bz<5^zcP&&oE zoCH1QSqFz}!z3KUQ_vr(Gt({54;^@qo=3R* zpt9&uUFx~6%^G}iUY6@`z7ML!vR+DFw74|F6lSiqr(+RX0GN^ zy=`ghe7J#0`@b55c*Tt=%vjN%q|5fAgb$=xz}&4yhM z#Km(o_-4-^PX~OMKi*TxoNj$^3hdkYZEcHZ*GPmH$WLN&zlwRtY?^0Mp^9RHH}f7^ z2#ctNa=)8>j5XHpA?;uA2v7KNtk`8dWwJfNmxee&bFB}QLpaI?_5$v5_T@V~v{8N) zZEXCS*40Jyv6fE`_ouf^wq3c_J{T+!$W>ur4(t(mMHE9v4eeC){uR@g|M$*sY!|B(gtYLP8y^j+qso0hnYPbm=$7dDwrWJzA^ z7R8RTRd~(sht=yZe(-S4qC;$_%GuAOaN6vuPq^Cuz5B{omwGDfl4Yq`2Cj#)hRUpq zdI?50WSu76&74uk`k`<{5o5q~|2<{Q$%t54Y+#K)nl@$)I%7>UlW@P?W zuRHVpCAa>`xc_BRbCyXPWT;=*5tqGwI2et=M7U(w`0Nd_F-YSXsyc&jrAg!A=N*`@ zoAYjRbhtKSYnk@3KywcKuuL?Kvec{9fH%};hOD_mJP!BHSerr55{>Ko=jI&Xmobzp z>N|1=$8SITcMyt=vYOBV?Kh3iu=jSn&neBEi%ZtEO$N?8$i1xQD72ZzO1>$v_DI_C znJZ}H?A4L%XoBqOU1N@#h|fM6BfzCS)aM!K8boJy2h}%xNY|g?K+lIVnwi*qZNAtCt`C-gk#cPN z*z&Izkiz&hO>~6~a*W}wgppECZ^ zZs{-k@rGR|=YrS@FUMI;uUp&~Y;od- zwlJbg4F3})GV*Y4{qh_3W~$<4Q`Tad74HB1xp=g~c*u|z*hO~gIEs6HvJjyc4XvmrFrugO!pbzW2%2}cP zVx77|#z4?-931*xagrF;OoS+x5wk>?d^q^<8Y0Hag-Ma6@{bb)s1M&XP zzNKqY(2Ma(Y4UGiNZ7M(!(!-VG7wdwU-^hqFbqsr+Z9yL*35m2go%jlnFK5=Vz^1{ zO_r2IyVQPHn@?vnK6xD0wB}a!V+~?wHH90c|D`CkDlkp&E|`U`dsH%lvgx~>sW){_ z}ziwBcCjJatZ!JBEsmJv7vaX(s=H^Q5-G%_WNml|jj-#w^g?+_i zW5+pjoHq@>(d^kY7E*zwChib(cMYAED;WqXfjW@duE&OzMT}MmV>Z6OJ^P_~b~N=L z2ktEmsUj+{56Q_RwIp2k>-S5HVM~iJTWh{YMW{T3>M2VB&Xl_~+R7<5FbuDq|GnQd z;#VtZ$o>sv3AcyF;cTkQ!* zqsVCwj8gkM5Ji(1OB0y;&!Q0}Atvl)X`vQLR*0L^f$(+Ru$0GMIq}u{SbwEsjBCf0 z*uGT7XwG5~jbLoTHBd&l20dw;#grUK`DXV#TP;L7eTy0tBJI~_J}%8L4@44By9AnW za)0meHSYd~zdO*b^26sUEYGWFZ-`LUvAk`qUZ<*=3@cipx=U5#_<0ANaf*MOPJ3b% zfHYKzOeHj^<+&!EBa+D_)(@4(o1-ddTeIfS|1;+cA*&F8Ax6M`PrFRJ8Wk{yy8w$Q z8f3NC((Ed}Az>3B!Y$%p`HxI6&R3!ixBm^%_1u3S+40m%kp0#|JK*;HlvA#txOsFS zh@WAh%yjQV_UxRuu)HW9Nq-EIl)TpoOR!j`=8{=^NT#U>RbZeLFR`Kfghg`6`~F|n zx?BDv!_S+>v>QmYSh8IF-ew8PuDfQWrnvb`Dy1Enp44dV&UC0ZVr(r(wdk}KHd0TOe<(4f!&HMTv(~G*SISN!o5G9YG z`33^($a=)#YzYS7O##Snad140Mpn=P@B9^*IUm$T9_Qk&&<9qQ*p~96KOcdv0P5t z4>GnDW?LuO4R7_WtLgb_`gkZp{SAv;-A_XEwX1s%^CNNJOo?E=&Yd^qdw5e@mh@ip zHYFhUA?Mqk%J3|Y5o|Xwn|e;#c}_*>WK!Bc_K6?} z+K5uL@XT+$Fc>%M)oTdmpxPUS5|KKvuK3^MIoSu3*RAK;2mIZBxR#ffhiW%nCIu*5 zT`^c{WEg;o8vibNjxD)p0{*!jL3lRr>LG}!%^NIOT>$&a)nfdFLO%hQqm=W9oO4bj zXC<3US+ZI2AKZ?|H5ZxWdM(5qG#SM%@nY=s1RC1J-!d^t#TU5FW?T$3kg7%OZ?g$ zDQmM%exsDq8Oxd+D&O!4?_s&^Tk)yi>Iq>PI}%96HaAGPzN|(4FHNThdJ19zO`NN; zjYQ(#(YvaYP0-2}1g?%&iw&QP7r0MufAE@-TLW`;8v2o+XnxkV{rC0gc4fETfM>9E z$G@zw^^?Sdfnl)_9`XBsuKGUv^`M9(+a^7a9Wefb^J~Cw`M1G=+#e-pC`_8*z;*v6mCVj)5_*%AOEz4x=ueBZ%*T6uI+6hll|I=Ds?JU zt*8HLQcI+>?QO6oONxxnB zz;I>f^-KJcK|?fv0~h57P!^;CaMfw{2tnV&XMFa2P%OEnYD3!H0&1*ej{^L|?Md$+ zn$Pfu%R&pohfoO8LZ0Kf*D$>}B{_jd@CEla*2I(V;>;24{KLf%Pt=>P7~p@v*U)r| z6;i%$9+!kYMD#RlraV-YHjXlr>#*AV(ye(`Y`w~+Rj@9VaxO!~Y9_keoR^cAg>)y( zE76*7SF(TYu9jm`)@#pD8mq2j?o6!<0Lg}2{zEXTI*0&J0D$h8{nbYx?3Y@mP@>gd z_$NUK5>YoXnI(K&n3+;}OnbZo+h0aaKUWNlj}Bs`PoQO+cneLKb=IROoQ~B{BlU&^ zJedN?moOmvnt^S|dcLlB;>#mEBWh}XiMOXv<90uVsoWa)i#;k|AI6V;YD_fc(0_^| zo%%%$>9_)$7QQ|<9Q*yquyLp^EAM>8 zC`;xd&e!9mSmy~Pt-t~P_YMeYNjb2qlo#5^_TTZB$u}UGpb@qTNXgDBPGr~xP`g1F zLpd5n!G{d*z*0_y%^$J-9?D9OR{Od`q-w#27*ys-UHia#o}*bHqca_M((X?kd2zuo z-51^c98*0VWSteVoJGVzPAx*r3HoxmbcTh(zHOzJL@({)%q0tl)ZAGDUGo=^E$F4eLzswff`k3ay^mB*8JZIeyZht(6=msfCMDR>Ij8 z{q=$SVaRSmuF9fgp(0a+t<+KZC#{7Z`&$zr{gx|bX#;3a@Cy&=0ljth7w zAwlz(7AF*Gdb3e-s)v(y>Pl!UBbpkYGO$Y!U5kV_e_2L93A&L$ecLS7KK1#D)a~>! z!|8U{_ur78wF z$v`M#*@UJH1N+~ax@9$npPo5)ekaz;(8MB~I&G|LuW#SIO1y}B?!fHhakyl3sCQjB zU+M*X8g5_*h|D+SrQc7toFSmbG+nZXVtpIG`=XsY4JN0rQwA%;D_QboW_2 z!hHPR-xQDlRt}#^8(h#sIu|;a6P27hHrXO{BWUoL1lM&s59NP1o@2G&(kyBbloG=| z0Z|E1*%|&*!T5BsXF=fuC@er?LDjbk2zUs!rB5NX07*#T)W+0sN|f{FLgH*5n6)SR z(2Nva<`X7!HvI~tv$s(Ucoh!mj#X6m>M(?|0BW28Sv-N96*kqBvqdV}d#$`RvB4Xf zbfK)rbTQO^055^64f_OM3qN5ctm6Hg*ARB@)dOE5)7^Uvr6ea9x7*yppiR*mqD)!q z*5?7L=!v3Y)=r7V#Pr0KT9>taYOOk{6!4kmTTkwpU^u0=IzBexz@2(v{9LQ!jf1w( zvQe8Af_u^+%81_bn@WaCm)F#uGTP7V-_EAX(nGz?>A+!TSH)pk zGbIP-ZD2EDe(##8SKze|+w&AgtvR`(1_3SVmdrVsX>8+r5IJ(O7X>6bdX#S$ofC1= z97Ga(oNhZ^rO0xxC;<_mF+3=%~06o56GrOVN-xpSQfRTbQUKJkwRqp8SD;l}b zmF&=}G*-J1>9U8RbggZc62ILvH%R94wPDU0ums}ER#BnY_o3}^K`Juv>;9y)`OV2O z5nf;lqj|A?o=+gl`M%6Tt@#!0j3$0rWQ~#gFGKbV79`dNl)E8079tL>y87W3C|>Mk zWnU|Fw8JpE)aYvL2xx_ISmH5bDFwzkfB1UVj6ZND;NR9k)Dc;anib~ip-87O(pATwc&l;CXr^aFxE_B9JQmD|{u;-Qqp{65 z`pJ`Y>V&lH^ri9mQzxomv2AGO8&)E~Jf9*?>;wzYbMv=Rhmh^=kIfNjD;QPNrz!j6 zcKs-^&M;AZtPB{j^&~ILmIcf09pRO5?1kvfJ-Tkj2VvKmWKSFoVxeFa_7FfQTnF?T zBp&y*Y*k73ub~h9TsvEBZ@+w4x(Y2QgFDtet{LazACAB zELk5Iq?^c$tQFo?{A+#@t?;QtvX61H{#+0t7wcEyOHh@9i@6=`ChKaq$;V<2j07*5 zwY9yME<#)CUNt|uOka{uHgg zTG_^y^q)D*s6N^`k6qSl?2V1CsdX84afY_a0EpWJ!--$Jc$0Sq`!6MPy35TO6n}}y zyd|ad1VP(pc;~yF0iDV4s?mUW3bDzhmr`%P_P|%)&8fa6bw15(^vzC=f8rwwl#6xHHs6$Zat! z=I@6x-TZO*&{SpI$sHodW9rEFXjG@Zgq52VvrWar+5P)EN^BU|$B2Gigwq>o4rqzW zceJYrYBk%^nG`iR$5eG>$%$I*+C0;GSzxWBR9}4WI<=UWLh_Gpd>YOl)BE*`$S1JZ zju!ysU~#g|^)-~-Tly9Uz4HCO_n!__4_IRDVJKh)nO5?LEiURp#`TZwhuZp|qm;4Z z7|u3QKD|AnJxTG8{!x~Kw>nTU-3K~tMFjes>krZE8fV6Sy4m}z%wAkvz*^{?>R^YF zrEYpTZhCq*By&MOs|3W%zKc4@y;8aLzf#_{{m1{5@Zg(Pm*12V-Gyh6Eqh@7Kcl;C z8f?D6dLpZ*%y02gwTWO8+nPCj=aS6F(cLui!U$odL@MH!Q>Xy|dL^SeRfJR0I~npd zMKdXW1d($c?vnq(6sE>&Xn*Wy$1;^@JjY7L$Z&=z z=c6`U!VnE>_4Slv8W{87xYRJw8_nY|V(`!VBzK+yYHZWWYS!=g7RJ0DB0{UJSFmgI zFKVbd`y1j9^U56!?~re7)sGrD9Xqi5 zR7xjYVbk!z!aL*Je$Y*u!b;{Xwis#F4+%}(diNjf!9{YO?UK>S@!77YD;?g?d|kJ@ zU2hCjXawuT8`6*a3b{`5YW^>M64E9->!PHWf5 z24twKN_Ll=E9%=u@z#7~k)Qxd-X0=3T%h{)q4(thK46Xlw%C93%KmufOkn{LoHW{i z8J9rvttA#NZ`?Gr&~he3-a;l?odn;luqCr!AH+z)Cg46HQ?h-l`f`ZONE!I4(xjf@ zwP`0=o(=p8%IeOn?=u-38pI=Tvb$%piIS`}Hw7JhZx$gV zm~A%T(`Sx|MpAv;726;JxQxqa_GEAOn$tpC#)tZ}(uBRZrCp9~43#5Qw)esCz_*me zABJISWLU3#0%sid3S{9Un>Dil!z6u+bwA>b=|QIol4Fj_5*|ZkcX1sCW6h8j102_p zm}MusIPVxA`Q%djPiXcBT4lE{peyLAWT8ELQazDB>qHi}4fUA;Ndl=S-u{&>q5cZ` zGLd~#4fb=vAYMTa_{|yJ(*=RSU&gb^wI-uWU);TYx{tTmfZlXnI=^|mdEBeB=&;)T zr3V`1cNBFndR zo~mf;Q+t$G?^hS@E=z+mSXMT#ic^oCA7 z_h*a!>O{)j1fL-bK9*s|&41pyo~K3ujf0Rrf)o0XGl=uKL}SM!rF=qmg9&T%4TncJDR+)hV1g z+6lv_a-8BGUwKb%s;$rpmookCyPv(3*rm|X8Cm}ItPQkXn8HZ~=C8nNtOz$yd%=|jf@|8|kKix1 zP$;zIwnB*5oD_2xh1-UG86Sbek+XJ-jCLA)@I7=z8#V1#C+lV;yA*-p>@3A+ljQPo zTZqQL(tzSq)kgaqbgKX({T(z;#UtI&*ZPueJJgc%^$=G?I;?YU8Z$L384ECBUZ?V- z01mk{=t=(1(f;=5O9&I8hi+?}t?~^n)2}#j*k7Gf-p-`}R7$b^h?i5rZOm%`9li9c zUG8L;?GJV1KV#Frg6A@h=L^O3m1*jvhE(&Vs19Us@wnC<*L>eJWX(WnIkJ68Gd86y zwYcpr1!7f!!wBMYUn{9D2zx@%cwqAvBXVvbK2;gb=`5`RMcY>1-CD+@+q$}IXy&SGd!*xdD5 zb=i^*6z=JCaBjM)K(mJxPR(o3N?zbG$#>T%ub0baj69 zu8HMrw8@UPx6H)$|G<14#xk=692zZ|D2^}(EH}dlyWQ0UEVpI#k;=lO0`%?7&3$v} z#krd?PHuzgt{0`|qdp~GqI1=z*lrhB_KZH+SyArY0f+mYLAQYm_?P(1tKz$hP2t62 z1y2(57f`-I5-G}8ypCS7V@$0pvZ=bNdK}8EgYC5`eH!J$K5NN z?rFk7a`Od@YlRhyPEB@Q;tIGIh5NlCKoYlfYdWN0B{cX?3+>EA-}WI+W#st~ahzU5 zR$5hA%}3ImJu%;c-@k8d^vC+IRF7>9$`lqWUe*RxmXzP>{n)bX`+38uP~o#7_7bwt zy&q;Z?Aa763f<{|9T`cWSA0|sO`x=L8*9NhY8NMj5PAM~4A~kD+y1LJVazYpBb9L3 zxOV>M((UNieXyD*`eKSfrc!imGH7BqUF`~G2P;o%DU&Ejl82Wu)dVlXZ*K15S=#dz z+*#ch{X_%5`lB0uoxKyVyGO(G7pcB3o4u6Z>3dDSnlnN1Y!KiiW57>Z3#BwHN)F&F zZ}aqxC}s=mth&&CC00rjpZ}f`s~9V+MlpBl`P7r3|F;b@}8Oe&~z?@C| z$f=`TIj$rMRP)R&Qv;XkHv~LeC#H(Iy%(_iHV@(COm6}wI`~op$aEhto(iol;QoOd z)PAgHBf`=9C7R%qYH*{Xoz!u4gxL)`f}-+LWd#{ts#;h*QWj}NcXHS1{#iw=-$zdf zQK1oz^=y00`gmY^ z$J)+tB|z5xBF{4*A{@pS+*xe}=AFK6{x41Yu6G~~%8KPYk$~b*$OCb&qzve&xVWP) z#}44TzL1vGI6IzlX#e@cw6smz(3nd4wIX;6!@c9H1ie>!WYgEM=Y+5ofZ8Zi)QYh^ zh~?JsxTe8z>w|$ads)#6rIE@22w}l>4O2W}h^e+OzN?Qrv?&9YLV05L!V<%q*3|OO z6LH+k4xSoeJfE@CR~F`88VN5@*wY~EJ%V?F+^Hi>htK81z|y(XOlIaUeY{am1256q z$h~vOlaPR0YOL@aK?i6v%Kfca+gOL`V)1o6Xgf-X%?*QN@fqRGgibLJhZn&IoDV@*Qr(APdWJ3C;a1k{n!8w?${%+WVmgs-W7+suRzceV`*W zUyK+d-*i5KHuOY+B{<5e*GdTf{@t6Ma|;l?$Q9&wzV-fpeOr$Q+6jDb_j8 zq?z=M-=*Er#;~Db`d@UMJ<|>Mno2Yw)725|Xz|o(<1$+d?HngpP=aI?A9!}EN{$rS z+3%Duj~K5iX|e7x3MH5H(6zGFA6vtuv_GER8X&>_&#pH4oN304^h!Z zu)s5ML&5#sx5!-#s-WY{Q7UGNm5$q7WitKQ>`*khF- zh?&$0_)~B>Np@Hnd&2iLBOi{^a-3@GdIz2hl!yh*<6@}yJCf|$)Cwgbs(F|54+Oj> z&9*g$jC^G-@k7c(E$j*Tjmn0uf?3HliSa^7ai(HpDBp(=eZ8vUo!)fe_~CBl8Ytvk z${w`}C9k(j*z)(OUAbq8-NO&kM4&U!6Kchgu8PMEMRIb5?p!keyVY{a^re}+^&vJq zMia~5G%ELZ*C?^<4E-RoypWMw641lOGvA*RFzqj9t*ou8@5I zkb>xHV){9GeQ~bF+^R1ZP8I$-R5QgJ_LL`-c^&|2yfZ~gOz-k9QVD>NEkE44|I6rS zW+fuDdRUMI8UH^-y>(QS-}nAKl$6pXDIiiqN{UE}fHXsQOC!>aGy;M&2m&JAUDDm1 z(j_p`UB5H$&-Yo+U%Ff@mUGX!&)IvQ>v~;*Xv+qPq&8Wv*EGAnp5pENcu_N`|LS~o zSvJqQosJxNXuGJJ7K);a!84Psu^27DGAU)v8=8{M#w-ez(lzsKQBrAS+M%%;QRo9&B&Z{4$*I|24af#~M; z6b8rTVr8gr1j;hOr3%tRi^8*of?z1u6P5hR-B5B6XBCGtsICDm03@Ac>NNo>v`0|la~U4=!qxCdIq^KEWn zCYwtYE}(!X#7l@>Q=wMauyoNpgGG_-g)74rqRJ+n{OWi6UzFyz;(S9-Vr3_;)YRB- zvUQ?a3H{EVh+Hc-22{a+gx-46y8JebPfQe!8hTmsm|Ney_9`X$K(W?=#(LzpX5QXS zAYJB(S9wXV*H|J?7S`G=@2bIbGeRv^zo}uyXBOpk;n@ep(We=I7_~H-2d})sR$UJ! zKlD*Z#_CYWX=(@m*cEIg5VBSC zPdF=%-0}y7PHaJ!_(-8-o?Jxu92Ogir#ftEhbtOZgzZQDi$W;()v=!S0)5FB%0{d5 zTv598Q)R_T`gLi1o053ue9TeSlE#2%+JF?vvVoCm;|rJH{f4u^ zf_DKqnQB1+>Qa)55jx*A4P)kst`I5(sMzdo7u@)wbQ=e+i#B zosW?PjQl40{pch3A|4dfeXt;*5w{p{j}MW!d*|Zt;B8?D8`_^`6uO zJvDvu_)aF(*l=ckBkEyueZ%(htfem+U_%C%?)v?yc>_^>QYVW6(^U88 zdsC<30C$+hYJ>zLOQfMd2|jh->S~R>5XzhxWe1PQpm&Bc@uPb z_KBhfg|iASlc)EsNRxD-mhTzsrP*nJL;;Cs5-)L(XQfME2TRqwk{6D{sct*Kwpbg` z0^%T@j*Z1+s;$Kr&Am+0J!813{)-Rmb#azhL4UiXNi_V2=kYAT_pbRLX@t*~98fx5 zA%cCcw}Dfo3#e&!f0#*DzlFVA?q}SIwtt}a)U+4bqiGeF3FR4}F#szY8mm`Z;oZ0J z^&M-zb}NGL0gx4lEcfs%(P9sk8ESor%*%)}kY$T`(DLvG0pSI4ud9gl1<=M}V2$NY zxaJn?M-7W($gH*Dsa?rojpGCnkkv9BMsdIce%uInMrx1vG1?CZXj30a36>3!6b;0ZB$g6kU+i;lDEVFFXsq|1Q>X> zzz8W4*a#5e^N4UcWPb=E)gUe*;n(yfi!oUG?aoN<6we)fOyiT*Bq9XcNLHFE%Y$;X zh^*S%)zGxHi{yyX2i<3z-e!V6&`hvUeJY^ZWC&JG@04G_1)c3*=xtGQXv|`BH9jjg zD-?}D)qD0c=r;xYOBFn-i3(*fMlr#6EbG3OsBK2qg~V?F0rWj>P>==DmMEQ1Tq3&;OD<5Anq9l z;Z9aDQ3UG%q*jWHi6J3a-iR3L7I62kVnTp30Vnsofomq~3rP+(&fWjMfQL3K+8M3Y zJnyKLsTsdokJzx)Jk>llnG{7JI{`k243IX#tO_x%LNt?roU=MCWJ@ByetCN`;s{b) zv%v@sVU*DKK0|0)h!MHx;lvYJm9K(5&PI`vFE# zkxI5{DCzdMvyQYV z8D8K9cXj1_p*D2VFLD%a|8<56$@tMwak;cs=vxWF(aG|79iS)hvFRkVmBC0QTA=DdjSg9-OALX&rFCP5CzJOJx?j^eNSOf%MPY8B8GuB9!S>M;6>jS2Ka__2 zs?feg^x0SFnx2;EsI;TncD7%>E^5+_1DjK!XzDdY2iw`j;El#pPLf2~_j%U(ro$*U zc&$bQ`t4ii;$M1V@tw1>jOn;u08bw9m+of|Y0wTKMTK|wUSR+etYW1zPFbBEq0l4N z*vNKnzz5sQ2^v(eUj)9ptJM_rS^6Wj2w>R;ds?=4L1h^R$>x6?)_O39#m5P8oYu0) z1jESObPpEb4@D%^ErKKlnaDc;j-~MNJ)6=P1L=#mK%~`PW}THXYA0&LVNzk#^!KN} z+|5lo|I^F;f3r719Y@vS6#>Wgl?gy3iAb{t5+1he)4!j=^&JTLG3x&ER7QFbA}T=H z4PvtpV4hF^7PaaW&CGK2i|`;IMsO`fLT!?HH&fL_eRk?R;tMT1dl!~rhQ4k;*>6hX zD4-c(Je zpR#{$3VuS$-5T}8v63yE{Dy&c)1^Sv^Jyj(E9yKbG)Hiiy4IPL8?xf-Je$yV&duGh081} zQ+luhsX)3;n!>XoNoykA{ng!gmYHRyo%vgOCk@1^tf`h1&y}gUSfPd5a~PdsUkPQi zMvZ-yD7*WyoMDkz_mm2GC~t8&go5RsO$MR02`FY><^(hsbQzDZ02QBuJW*vCQT3zo z5r*dt=jGtwH#UGmv%wtPgJlcv10S-#0j}~=b$LUDb0(W87-o3*nUESy%)}`NWCeWG z5BpAs%guTX!U_H-!sf2A`-268t)5(smYYbQ{`*4#p4L=t4weu|A-xI_qC=q^>t6EN zL?5>b_NQXqKUmne&(C=1SWppp5#x*~4#3NV459SgFTVsS73Ho6`XJq6b@1iLd#il_ zk)g`)I>rQbVPFE=rZU!gPqeh7WBGkG*z)VP#)K2>{L3CAWJdAU64yR{%4rSpJD*$f zoFfuX!n^xDt4Vg156ByFGju43Rq>*X9#2JiJmLLAjL~Do@f-|WPx-=|Dzny9*gxYD zctV|kM`18?w&Ku~RSaG7UxeSz{LA8;!0rBvV&cI43JwwDZAj`iXPVqQ;%ye}a5(^Y zg>_BEujeD%+RT`~nNbq3DJU2!!KNq}I)|wf1vN_NVnq>q&DGcU#1Ftm!65LBbL?b;pumfOn5Ncp?8IHa;svr}j_ZGF>*3*=lkCnqP zPxkeWxDXBy!5~j}q6yXXz{fB6gGnN=eZoG*&mAFuVfr#xB4cS`nrZ+nXCw&;nO!6t z#JBHDD%1e%q*^a+7FQEm0Cs}8-z zB|G_=eNmRF_iaUY)>C@6L?#wxurwr3+xh=HzyP6jwPRtmBP1p@H8oan--FL@gXUl8 zV=hzmeedw;+-00d#d|yZ7MFn#oq3d-M-Gv) zIdWP}GBsUor6vh`@_~)I3`9ij&sSq_Zf-JXV27St#|NS5xX)D82(PV)6qOO31w{U% zC|fm(i2s})CYNYT`FThqifxkKg(Y11Cs~A?Rx~)FaSAy@y(O5S^s`V_93404*&_U_ zvmBL{GUL7OrLo?=S1`+H%}2kk^eIjE&MeOX2liD>Wvp1w2-Zu65@cJP@>-3efmdoe zX@!F&xyrJ;CV>?~s43xw_^8ToG9eeJ-@CdYk^3XujqUBd1#rNCb19fmL4Y=2Pz}~a z<+|t(^7vK($wf9_I@uvfz1jGn(pKvl9-7#6eMF-=3f(k+=a{n-WBiaI`fZ(1sOFQw zzV}i+L6T&cj%|e0AG})`74AHN?Xj2( zRs9-h1=NdYql%TGn3ceR+cMs>IgRC6%`N_JQa|)hNwunRSCF}NvPfr;XhcWeTz~(5 z#EPY3{wzGG6O8$EH+)aY^nK11=u(Q`(A&Z6gD(S;F0lvrsjV4>m>eCu9GB z7IY9c{{LfB0m%b$Xy|0M^-TNr$=?O9H#7jv8V>R&7Y1iZ3dGSA;bhoHT@+E&_Ls} z&DZW!QyXN4kQK1? z7W1mJ@p;Bb6cj{g=xciDv8z2B1P5El{yZ4mVN8KBU>*&?jdM)S9lEj&YA58{O<7@% z&SQuDQ)c_A8^4&bMapyQAt`a!F%6s^7-$_HAe$We*dGyhEm>{y|7*>_o$Jy9cf9F* zrI=~bz%uHVu1WI<&58f|uuLhHRLlIrK{yX~;~j-RAa+rh9G&EsOZEK@$w_GiR*+GE z0E4uG&cbds;XSp(i!hk3Y}^EbATt=v6GBqC7C`*0=tl&Y=RJ8syxD}@t=~E=E(|>@ znd4wLqbhg;A%;0gc1IFpv0_f)NcJ4o4+TV?r8S@lw%XVg1LWin%|uQ$ohE?YD97-R z8q;SoEfZTK<}Ipsc4YR12hD<;*il#I0>AH+h9>3gVM>V}e#xJZ+pvTFZ%HJ88rTR- z_W?bM79<{>lF*QY@R|2+`|myZLLWQbN|j&CeMLfQ+Vu3inJd<3%j!96RV>v$H~|;! zdm=JkI1m7x--w#Yr#3EXIGVRE%>-%94vtIAFj%2{+nd5Stwp4xJz?#X@(}bQi3qb| z9Uu!Bfd_~Xy{#89eHBGRZ(hzW#-TZ+@T0);TWbU(bb50W&7rC;4o+z(<7{@W8!45F z+LeR4^wve#+b%J)qFfP|Es7Q@v39mG!r)TQuH439;`q|`v5{l`*RzNxd~vCyLDVmz z1w5j|0hZXP4~KC;wYD+cWq}tn!ntdw&_**_$t6V8B0~z8GWguVa(4s`j3IaivyHAC zIFtg0mvo^&FOA+_Z(knF&fZMQb4OpKNt+y0UM*~Fy<_Neqt_TIuQhnxoM?>!j?FFr zaFx$ESZ-;VpA;zbD6?QiI>Fs+SJKQZdyIX;I(Mg4nl~6x1j<$%iBxhYBj)7q<1C{D z2jqL0RbZ22i<@YXJ6u$I?#6T9+mz_e#wlu8=V5=565OCtXu%sU+_b;2 zgx-Fl;>k=O@br5c1BFgA5bWyq)-B`!=hB(e*+*rREG5l#5Aj;DdvP(f*Zok1xi#~q zvM*cBZ$XN%b$`FlWn@a0Jx?n9J{$p1(RYjV7%I0GXo%aF|T64gTQQw*B)lcrUQ!a^g%azhRm)8 z2+nM+>Ml}3lhR>1wP8$|>9MC2P#PQH8%k88QLl(;-zGkZbk&^O0yT}Acoa&xJh^>S;aL4XvavOlCQ>b~**?#Lxh(l>kA|TvPP*wL_+w7w8CJYq z+CGoB``q(SpGqX4Kn)ZjOeZ=3<>op~k71iw-C{h#I*y{PpTDT7D+@iRFOIER*Ti+; zA%3>oOdR4VcjEe_ICgM5Wu3SK3>>Nk9kYG@I2KwuwaIz5}^$6FyF6LKi6N9xk40ioB(KMEkrq+SGQsrz{V-xR!~a zxa5)^ZViQ%v66Iqtha4W z_;jr$(#%2rx1tf_Y>A8ilO4``;NeU>&{`ukZ5RNl;`qypXug8D+WnZ6`eTaDrR|AE ze}9e~^WQcWcOd{4?`S?$aIbG~L~N<-mfs^=)`tzgk_d3YTFZqx&*H_S?wD_B$#sAP zNI2c+5GUGEm60X+Ag*DRg`8dk z>qER)2N!vF!Tj_^2H!WY))-Pa7Z9aXv8#I^@+Sp7VaTAqsZQqn zms%lm`5157(f_%QEz_R_yi0l&nU?AqITYTNY<#vqPwy9IB~zqdf+QBC*P4XQa_ob7 zgBZ)BKVQw}0=zH24<@}4a&urFf2b18?w4)UwnidloZ0y=JA;+6Te7P`a&;*+8?r+EWTe$~Dj_lBp-Ccx-Yi5N-)F7orpD5rU3u8ubfaJOcA z8Mxcu=P_>}lF6zwVv>0E&g>PO^|{@WCE z&8GByXP{&W2eg8^7g?igewSV7H;sb|(L47}sc_UEq;=fjcXf;dCOsdjwtDh{SIPe% z4ak7WXKLMoXvl{W@OT5-N+AIX;7I z5&nGM>q5VF5+@hLOo_`q>SYT>J+pEDsS}5QVYeXd23IhNj;G%cJf%v%q^+zU2;ugt zXrX{iorPzq)y8on*!oeiI$lX*Di1FrBKaSNTXjAoWCZ7m)i1hTc0RGmXY+F6i2h%IAs zwJBxVqVnhZGOYj4BPDH=*qsPwsQwtz|>JA;0(~+)xtS5qSlW>#qG^(g`$l^ z#sfQAL2ur^GiKz-Dt=u!cJ{^2qKCDRsFV>*;hrDzHINB?4iJ>wwyICRt|#vqwW;3L zirmH#`_sCYAzuw%^Jj{OYl-4@b$+(>+{dOdEYoK!_}sm|?D$tmH3i_nZe zXs7jpzfI2V-$%32h1a5-X-gLTGZh4_9HPo&Z#oo*v|b*qgNaMNy=&tigcbX1YU*BG zSPj0r{al9G8c)d4Qn=^Ow;h_<_0<3>Tij%EEc=@svYO;l(XOKIsF_eW7{OL6$F&h2 zehul_Ewu)R5_msO_!6$cd=cb})ks8iWhwqn*G3dI4S$UN3q92t_WIN{_&gf5aLa_F zU$rO}ty%1oaSP2A%-?d|j?6ckIO9q$@RkEVkaZp`n@^AMTkflyP7YB)kgSM@iuAZ# zIYuxZ>ecJvx%X}2rG1ZFQLRSYPm87Z4i47lTUvZnZVmK@O5Q(ArOmhA2Ox0m6S>k7 z%MWLzzD7rDT^<}O{L5a19L;LN;Td5p0+q&+*tMHF|16O|+tSh#CZxRUbBqZ33SCws z(uNMKPdZsMxTvF=Uj0(`&m#6YuD`;wT&GMB*L(JH*8B7<&P|=3gGh2F@Cb6#H6uw; z$xSw{dcSVZ(OH^1sA@|K{qr`Ofu>{t7N~ z$G{qu^BbQD=1%PN{lX9P9{t^+^UOY(hL$tW%O(_v zE&qCWWbZv?Mc1@rOjWfd8Dme(A~lZKLQHO3>wZz2KZY;I7Wt(N4*#zOK^5!7GSmAo z#wswSdu)8&eLhvbL~S2aRB;!!Ko9{J`DMSard+l30o%C3sN)gBgg4-`9{%G6G}7ddZeB%G_PPx$=EC*>#8)cr z!Bhy4CzA^QbZs%6``+Xb92E>P183IK+c{qR=D4r0ttcuIsFq^4LZe9%{7V!F1@5dN z9WPCmBesV#m+hZ+C7)g%OkbYU&`1|%i9kz2zWoP{#Ru0kJR7(F0Dl2Q zUyb?VhI9nO=e`V9=KN(F+KaOw5HBf!ul4tW+2ps-lIy!Nc4*g9r4pI=0UKh=pC%+5 zLL$LD<21<~i+Y{mQZkLq@UtLqTt+3cWZ^GiX;2XjbkBA&2rm&Ot*4k#% z^nfyGE}v8$lt&|7KGg~J=KZEx0JjPncNbMq=;`d)xMcIKjw0f~@%P+oXbgXBj*NwOO}=1uSiBTKV^VL9bLNWwwyE z;BlcEAXb?2-%!{anuGFB6kCSTMz$5ZDEnM`u6Aq%TSXYbbW<_)f_}5q1G>|dELd$8 zg-fH#KgyR!!&ehnW2p3x@(O=fm;y|3sVM zEp^FbQWz4TS$eTNEi~NU6ZW-Vupf7J+4V9p=D^nGoS*#4D0Bm-L){4uR%_6HH7ukLk$VO(D_A0d$S52}JD~`sykJi;(;njlA z;UNJe;MzyXOy4}YHb&SUu4`)2yKj0D3W(fmi&}p@u-a`+&OXP_r!>HW!n zR55N-5;J$xF?bE%ssGD1M~(TjcpLAvz+O+v#$F`3{&!vVWe9Nz8Se9(oAH+i%HDL# z6jas^WQ{>(F2!NX>5{`vGrO13j!6K}i+gi%AdQG)HR~rr43;hrJ8-$&k4>xWm#NWl zC|kWR{%ltz*L=m4lYdOfbb|6Vgk(=&Ip{)L>bEqQ3j#C+x@yK}LUg;glE4RkVm!;- zujR~aj09!nj@w(`T0uMllj80BaZML)?|6CZes^^SebYJ0;Dpx%LMA1-v{jlQWkWxZ zGRi3T1s2kJO85eHSVwTSOUh=VVCT{+s2<6t($mK;mjD?t9x$$EDtChdo_Wnt8W}Fy zX)CtXo1y|%gGA{I+YWf~sz|qvIhq8Y5(sNZ=v^=s#ih>l0%EpZ`cj1(!5}E|jJr?)s zA;RjwxgbUW%I9jp4F8d6*plE+B| z*|_;aCzaBoW29%uM5LmuMNBe?a4tXzZPck(UVr=Eq*THFxa*$si7L?VzU9#WEt4k= zk8_`_Hj!oNblKuut#NL*TP15UTrae;HnDO_GGOA|V|LGMHE?ypU4F;@Q8Th6k*Bss z96DRI`~*3v{yg|xoB%M=Z@%3@5yO?;d6%WefhhNPq^)n0x2M6Ti&b^i5V6k_ECYB2 zV`qa3xDLRn2pk^2hEi7JTB<+J6ZJTHzE%Z1FlUs-GR0&-YPXOu{{m*H*;8j7=ots(0e%69Vr9I}$=pNwKmQ)_5!gOq03 z_%q(Vo5OErh}ZXAoW`(ysnezx4>6Vjz>z4BZ)5_zg%Cf$!Xp6{ZyR=^03LBLa#nz( z+*kr^E`F2Ess+8>NRP6&dvxn7W=&|13Um^@XRwGT@RV8o5*HTz)M@d5TJf6)DKn~X zLJ}gN)>o!83g2?)0W*KP-U=2ma7()Y%vhtwwm2C*4A4tr^-aOn@@c|QJ+s$a9^4$_ zr@Xv+Hw7%CNaad1S?ERkMa-}tl?ssUtu5n|U-E}HcM7R%0&g;KL1=(Ns7}lhhuGw6@u1uf^J^@sp)WmQzS$ zSGs8ZckPmoy{E~1A^(kPa<bBE8 z)A(M(N4?+T1%6dP*+iZ-Aa6`8A%37@Ty`;y?(B(7ObgiP37s0o3{^|Bo13_;XAFvA zl)I0=EC-HL=_;9c1}zzxu;x#RAn7z`E_Nd(m_$x8^7nUAF2U~Qz01Mq4sLw5R0%>- ze?v`DS}!+CsF0KQ7M?!M%Tj=ed^jI|&0bLOu%40Z|5WrGrli}dhvd5WPL429x58s^ zFhl#puQ$T=YT8fPli$?5{*|1tsh$#_bCwtVfu$rg#}DgW)(TdMO*ph8ZJB0WcWZc2 z=wi6{@w4TNy-m3-a9??q?!=LJwRmvh6`iUbloczBTfQ+X)#Nvi^`gO`NHf^Tr17!% zqF?@OL2kKCNZcsT`7s57rVOSWZ8^i4cEauA2j#^)##k;!ny$$D!-y{C<06 zBfW@GRWeb748Cfek_T_Q{gWu1vE`jKl4~YpU4UL^-v6=PZs*ghv{%kpL#h1Inwn$) zNgoPW)5c)GW@2Z5yEk3zc)THF7l{Y1+`f0H#O7T};m)|M#)k;CuzVmmaoDE0S8IsM zQL>tFZkuY$&nQ?xZd`}MpU}|IjQIwySNs1iMj5LG$5s{{Cavi;!=jpQl25({3rlSY zzO}@Aj75&p71ZG5x{7fHRYzLW#@Q5@qtIDKWOLRpYpEf$R8h(bzD0R%W_=;S-G72%Q@(!JKZ)rl70$J+G?xbeH zBowGsDn|cod5GVBgmeFJDR}(1S^wv9`+zQywjJTubkzyIq3QRjfh5>xtG|?2&xHX$ zG)$aT{0A$X2Y=Vx1N(o0vn$%&6_xcMxm`_&o0yNVf*a$>ojb1yTv-L`}-UF5bTwDr)^`9YhM8ba#(1`$Hyyh zxUFx;erL8<2EJsmw8EB=^_X_A;OMCT>d2$p)Cii!gwsR5=G&f*?;IiU37UVml?$6Q zY-}ENzYD^^5dGv$p&AP!sNKlOXv$Q1ivFoKbQKNt)LM8VB9NTy$)EM0*l5{2jlO%UoUfHkDI`CzoBw@KpDf88%4W(&vX`CSjd|6z zS*OoroEw;{yY0ymeG;h+yR zK%1x{uGfEJpqiJg4tq&UOPiG?SvZB2Fav<6^#Nf0tOAi(eg&WH_iS+2mIkp_Zmf?lc6VlW}6Qk(5pR*_f9L z{ycy&m2g~?68trFo*isD!?}`V4Nt(wOn*ob|4!NpHh{MP`;7neX&6Wopy%f&otv9` zJ(4A!DXObW+3@La0BABbGRoBvfw8CibA+3l*M|wfo`w%DMa56HhGM>de*$4*W9tHY zdfCTK*}BF?r)~WvH~gVgY|lpo1O%gn8XS^RQncLM1c-15$cf-JxQ*v>T$B9Q1W5Xq zH#h6x>K#%4%vXK*oR`ORdaz6b;ruZE93uMu{p0ys`)CS&I}H8Q`TlH=4E#>|p(?f2 zV^xv)>7}Tr?VGCiRmIH(&%{kjuf7o&-)UEDt}EV2>pwg(HT}GFAKX;4KXi4uTjPf( z#$ptoOsZyRTU@@vsaJ@N5p;Nb!%1v$jiHSdE2!OzswmI` z_70;y#m!HiO9$I3Wn)*&vOMR_`)xHVc+FP<-jem*BJP3bw$s0qDBjL!kD}NZ=l(2< zD^u-dpSX&nEJVv3J~KL=v zv!LFQ5ov90@|hQqA`mZc;B&=*L-ndNOgz)N(rSvOaWJvjUG3myfZNX_D<)kZ2h79H zM%av^XhebafOfFgqqG{aQQwK>SyJzQSPaRZh5Qtr`epWOiD!b(w0MjNKLPE6 zwf2B}U>3@_IIWpCa0I~~$_LocAG4%5FSoDbSGB6m->}Uws~hyPGb^)E7T9V%AHbaA zJEt2U+`S!<%|R|1W?>IYO;fVX-(MCtn&kC=#o@8P+Il`thjoxhi5treH)!ZvmP?XYYSFe3tS$|+1ev}y&%eT}n5cWt zRLJ*(G(akcWO_Qq9h$RWW%OofdQUrDHUEmpN|i;tt;(QUwr}Ac>nmvin{BRHrk%jZ zGr!G1Q8|l;l4RV`;nvf6-^2%3$N!)U# zgbExtgYy+z^OK*b&k)b9rrLa)8NHw z`J`rzYL43BG+G2hBEhxRq(WGroVa!TUh*vShURJzN#W48IE(4br)ASjzMs=wDaA1f zb>}K4m`Mw^v;6hr3YZ*~Kcw}vHB*8;Q;o?}*qq@x(-J7i)GOL_etT8u0vsH;)YR06 zCnpkGT2Fri7|kwUe*dUdH6oW@yV@!UfF@uvsUX+06`ZyXJEOGv7**w@vq>OonidLu zOvtFv8Ow0Z!J<*3>mMDB8;nC04xW-BkVMsaU2%JPd9AFj`UeCcyLozwsLX6BlVgib z3NE4q4&eGcKK)ML@;##)JJAzW%U%`s@(6MWvp+eu?h{@AH(i@s!l>6nCb+;xyah>b zyRCRBqB9fC5LNmpi&1u_FbF89YZ~Osgl;+D?HAw5XNhovc!6O8gDv5(3^PPjBLOqW zYVRfngijJ!Uw>riXZe(6`wq*QRiZkm0wy=a*h=c%PCFWJrXU+MM-Hnj>LOSj5D!pf zDdaQUm8$WvEf&x8OO2`3;a1Zb&9?ilp&x~=xkK$-P1mW<@Jar?@DwtKyA?9;1PeM~ znM1(XC>DFq7O26TQ`O9x?#>r1XUk|SDk=&Fop#sPKLf2PqErd}@sZyk4(5EzHLcJSwnY{OeyMG-McIXNWa^VUcu1bePXPpJ(f&G6Y=7pOBc zK-G3U*k7hE=|!B%lHY091XmIH0MEwT62rQ`j1xN>lT5gVJl zyP|f}HnjbB_HxbEoqx>-S~{9+*2cSOb?<$u+k^{|sL5elA$)^wOsbuygtqf(ZE2_A zajgp{s4Y5xYA*_CZ?XLDrA`MpTD}0~QYMf`B9dJ32nYheJEC5iiR*uq=t4U}`i${u zEI46ktLnxptpq#Olr+g1h6%8zT;dOl$gv-nKW9521m)trsy$Mmp)R?i*MxS>#>DpoZ`;OhdSwMb@bDeCzG4n^rpzgK#qYIO7 zT0*0@e;zXXil{WJUh0*3D9c=-9AQJ$%^7}sFEw0$d^h*pXMdCtww&?#os7(CGwO1a z`^&8C>~fDYE5v^V@Gv@}Mds_OHJAU^wYnk&2226+FoaY2G2*m%KzRv$?7+`J9Fs-&XP@JmBjL%jbQd+ic zppaMNoNkqAJwmw4XZoPdL{w4Y?X3Fw{+a+LhG;0Sj?Mm^fQqHx)@kFNxVX5(xec+| z&T{|&uuES?h2m@`-raKJ9TlC{TR%!l9J*YvBJ5}V7+Al2q~cxl4MpcvnlJom4c0lvQN8 z8PjXAX!pjE6IgCAunKgoeO6kL^q;E(-GSROg%$m4N29{B$#=dVTpiUNwbFB57mCyA zu;}m_>P;JK(T)z-u3dB5;gSC!52AT-2^B4}35ZIT$vh@)JM0P1u6auuv7Se>=z!TW`0z`TIx9M4^h z!+(%Kcc)FOpw}neACH{Ys2^yJwr0%=lSMO5xmoYy6AQK54LS7ln5y;7kH~eXPvhM2 z0us6sYwtr zN&+>J@Z#r_^Y-_*$fEeqYfQP*_geP9&i;MN@=(dUrlIplAir=rorR8x2}4Uu3**TX zDR7=4RyOF09D5?d!|Tkz7sdb7sBJnhDct)5e^s$kEA$HY8CAueHbdt8$EH6C5=Qbf z(I~SkX*bDJS3fSV&wBHgy|KeE=SjWqceCyYS#_MTCegAbMk~;rlD?b5iVjI)h zpHJ^q875CvOIG~u=r`lz5E*>)x`>A9a_~tmOv~_7=l3EZ~5kDri`_mOO zs59$&{$kw8=3)}IL$>zPj_%F+ueowV4${j;YlrKC)B9qM3#;%LJ@GNR-VSpe2;|{4 zCX^pPl7HO)2jANE;s`$n#bu1CMqlCymsil{^Ut^)=cYxp4HFu1g%&8+uBeu4QI#g*LbrH4aIn- zqd&xwc&$n9?+$!T!0GSc@H-F0Cdi$}}($=U? zroe+Fy9$q71PG`Nxg2TXTD&B?YgwgrMdAq;>H^qR@tIu&)&*UGIhnSIg3sz*o_+q8 znKi9ywg?SD@jqa;hd*K^JcNQ|lf7*arIdIIInf{Ob!QesB|C6f{28W ztHg@fK@n7Oh98-&C8}+E3!bP&DSmpxuq6)vxe=Qhw!mEdB({nvZc+bTdv?je0;Xv4 zASqTtX;|L(SRj2lgoy0uK-C&wAULoXS-~A-9X}5gRxGz{i=Hl{>7`t*tt|6%xxgJy zZHWV==;;n8D;(*-)OXj z&rlED8GVv-ICs`x-1xYX(QDWKsH0RqaUH14#`?f*EuDjruof+FQsJ9pxSz5PGau<4 z7rYd!Y`tw=a#zP*xg%D-taTxB`C#5Bw7SFnV}@sil-0?CQb*YYt*oU*1TkU+)hKw7 z5;<$WAMXC?0bO=BTSbvOt_f3vQfm7<0rq z2^-ZgsvH+SidP4TM{K(J75AyL?P_^Dq)+N5)$~-tvcPsuWXJuPSm3MC9JZ@HbrN(WXF?Sje?%jx!9s`By#YbQFmlgmGWiB z;EhhEi6uB|m;P88+3TTyO;8QZO`t(u^cup|zmq#{3g70>zPlBM*^O+^8?B)Swf9H5 zHF_bZ#My|`?!wAp1WD$YjFiDfBATtSZc{X_>ac0vx1jj_!JVc)h++}hqoQ6{Y&!m8 zz_zzs^}QzfmZ*ZdEp2&@5|e4DWp+^)vU7py8#8mZn%Qm%J6|+4EIF+c<}(%XZq1x5 zBFW~}rbL;oI{^wzx4tW)z5+eM9|(IX1~!7XMdN*n4-mrm#Kb|H1BuxH+zMM7q4_X_ z|8Vidt+8MgzV+BOlCXq0Zly|v-MX0RLuPDotRhsE^EAD7w?pZMaoyMKpa?Wc~RXa0UM7v@cl zaz^j3OHb={hC15%?r@jIkKkK%oA>gzPm@l8RAb$8;oz1ldUbbTPkWiofuL7I&ox^D z#QS{bMWxHi&W-{8ab*nTZcFCwl_AoB{pG9gT3WEfa+l}7USaMVjF34fzZTTg>~kFr zYg({Zslc3L=XmGpqi6d4C2eSSdW=flt3st;#JDEKr%U0CWNW+OUXF>!OVi&fNha~M zp&b#7NmVjYwF`JGtR1RsDX4OEiwQ02TBZt93QR0xvgT9M0?e62hvDR<`6MUdvO~F( z*l6BYDA75gN{Lu(e8ZzQd(Mfnen21{$A41!|(5U_}5v>$;)va?UeWjjb9<~Mw^OnX(_y5S<8eY-QPN0dU zlV8?b<8Ay60KekUNuy(;>#8k1_IMhJ_q;Hq+vkjvla35KBWi_e;xE}pY&nN(D1pRbngVFe`+WYLgyKBmwAa*es}n#erAFOy*HG8LLlx1Qj+tbX#R^tCKEYO|`96x0aO4V+m zDT*T<`4~Vep*N7(^-=ss4r;JkU9mXrzP~EVS^Csk1yGLghFw7ORg z^K&uS6Q2vW@;U>33&K zk0)^N+GK( zQ~B>%?hjOntbn8CI7;Au#RFv%KD83=43_NZ?93AYd&}1H6Jp=~Bkj#WDo{woRBGs; zA=EY}^UyP_l@q9viKm;Z_MIsnE6}Zxu5*F7+;(sM^D2J887Ti;<*Ecybwa=FNeMVr zLmDSa=pSgC`&ypsb#cgO)Q`|y+&vkgeyXjt8bRHY#zh5Zpox}-7;8)G%fRo#@s%)HA$y2FmvaosF}k-S;ff+f@H z4l3BaG20)4`a~B{&w`%|IyC!BN*a9i^FRB&_J7rUnt(r;{X3b-<`94?NJ3mZU_~$| zCx?lxcu^&D051 z&$kTSj?nk6p;uIqmUKDWUpC(_G4*9u$1NV!7CMA8-ahewXnp<9)5|k4K1-dX`U`d( zX2$iGXQbBw6#4J&MwF`91X>GcHm7fpEp*JU@^Huqi0Sl{AL*A2YhHdr9m)PJvi_*M z^iK6OttGk7WBSgkZMMktbJrUVFM)THo`#11Mr)FUs@P=vSr7k|M_jgA7B?aZQtL1u zrB++wfx_PS_SKym;V0X%B2yG@z59_h_ZlVFpQY;=F)HtXOH06r*=rFjv3Z#=?qY?- z%KkIj+cT}Gvbg>YYrJ>HYvRi_`Zi&~R&rHF^5ZWAX&a55e@++4nx*i~Y80@2V9<7Im4nuGIxCstJ5in2Xiz`{{*)yTEPsG5=>HgBa_qr*W8sy zW7&S|w+xXaB?(1Tk|{(;grY%6B10ronM;O{AyZ|FzKVpXugNS#88T-IU*SbE6=fDt z#&g~3TkChuKj*Kr)@jvRy^HsKpXYw=d+%%SeeG-SKlb~uQIIE9K6sGs>eZjKk@R$Q z-5A$%wO`mEi(#TqpNIX3Oq`a<9?vPy6`oW13R(Hem8b|_OJh0Rm2)VvH0_mf!)?I~ zqj_0M)O8aZ`CCQmBfepwp5`sy9Ge|BUc=VB(A{@he!OZ~vE137iHv_1_X~ahvBh+1 z9mCYc_43;TgI}ynEA#KZ9kuJDP*Y+`RomCc+d8+@d^z}HB6XMdP&?jB|1Bn+#+U4p(i@f6x}p5?ho}ZG805^#!%-_ohN7omwaq z&p}43tSJwzk;MmbYnF|08r2oC#JiVx_;a<5Ic*pzZLf=NcRwU7{~;|du;q?mp~P^$ z+v`&wR-4$1`nNmk3c^8$pg73hS96i;lfCs0HlMT@gWUtgohsg`;a^WNJDHj$Z|3}1 zs250K>6Y_aYv$~%Tim2im!h#kOs{*8lXv3N`1)uEzu1b!nD%Em)Szx^hqj1Sc(#js zu1vB1-(AgH74OIPw3MaA(f2!iT34V(vo+P@*#2S;r-mEi5UFS@MPD7_FdFWC?ra^e z^->u<2UA`;B44m|`}TXW{GU5WTnu3W`F;B~o!w)~!(sMTNK{SLo>jx7POU9l`H_*} z{${`7#}%#){#3)k2On-17k%cF&JC}86;iFZaGbfIp~&vaCA)#(#|uBY^fXWNPpjqY z>)aR(J6(2TKDt5Sl$Jux`E}c6?JAj_cbr|h;Q`ys1!ty-@<{>1#G~tYUWZt;M02ap zjBK60oH9`~p1YHd((t!AoxSp6=KciAl)A^Ny5;+lt&7qhaYs1)Fw{J+6}al|1xshq z!R6^ETh`IlZW_rAcl;uib<&*QDB4VSy7NnY?{I+0z1vJvr%y46iKQ9L+de&C|F)Lv zpo~lR>bTLhD+PQD9BPCvQRn(CCRa_XobnkftP~LaRD3&smZQ1Qw`&~FjOzYxA58LFVc*WRz6TOD*W$T7H8H8ylj?ypJ z9KQQ~-1Dwhac4o~_my)$TP!BevtCp6vR^JjVeEI{Ps?59$9I)3yfaTP5U%^|sag6& zWy{KE+&}Y@8i$o0g$mxa-_ZM}bI+Jjzm}521C7e`U-dO#sZ_3%0Vb2h_j)UD#u;Ag zmy=@S9xTun@tPTwm_b%>jYIcchZT#3IQ^^V+h`d#7aiBR8vEqpuEY~6Zm$@i194c7 zbzm@1BQ(H7JFe*R2DSRmiX9QNnuZCb)859a)4LRRGqJs1{Oz6ki$ACvA^3kGO8-7g3Hyka} zwxjdbXuNGDY zn#uUW>?o-zBdc5ql0|J~A-K*T4*vPoW=Jh4Q5g+7!S-1*Y1^POu^<1*qF3`p(G?E zG}$sLt&xgIOyom&b@JuLCi;E+j91hB3*sXFq76pcLIbQAqt`CXsLP<#8u^2XiHVhy z^G3~Gv6gE8UFP0DPPA8Q=?z(hkm=!I1ZeFX9I@VQ6Bm&^|0$iFbMzr|Xp6*@mue)T z#Fl96xP4@|Ewy1_0;k^Q2hV}bqM2vIW>1->S}f|*mKpx%+w{0S6!-^6Y}A%+mE3Tm zh7x(0e_lUbcayRmsnRXyc5{}Mmn%JN)Ojf=tu&>ln0;lHx#AYp(=moi-~ZA*Ve2U@ z(C@!kCix`_{lAMwVB4Rc9v2|;qyPTu2gXC>5y)IyFQoeb6-7s=xn8=oJB&xsK4U>s zao!*3uDHCMj+K>_n&@eVd>j$O=W+41r5uhb0w-JHz#q-+9_`fu%cr^amP?O?+Ru1bJ% zLf5yUc&zRlAJ6l#qhlQE2VJr+}vDVTs11{8Pg545uBr-J=CU7`z)hzbGCl(wgEy5_|7+_r8M|Hau6jXB;1^z z4{Xkvb-G3JxGq*GY^bN`zL2tMPXF*hN7}T6wr_a2F4d$+^wc8Co$7yUXKXuqCp{}` z_Y`WS;#O8xE;EzoR~Q;!&o(1tpr|+23!T!|UVBti(+Uc@X2!1+@Sk0o-p!U_s;+XMvmQokR;Gl5Q0 zwCY1s5G~B{vmx{eSrr!-+k%mSkFAGjN$cy;!WzQUqxZ4HFs8HfOdCXZ?b)+O`pV3u zJ9q9>+z~T*r?Yc?d$!G8vsGTS=|84(wy)i=p|UNca66h^-Sj8$552a);de71Y0Nap_GveNwW$K^+hl z77n?6`?hTLfx~z*e+izTuG5q+7K%ZDJlOi;$?4(0{J@h%6G#RY<9oGg7?qBbYIbLWwN(7WMMOfEodKy`K(F6> zahB)A4z?lic0$A}3V-%6_4W3aa*aZ6q|PA6_Iy99zN$LKa3Ol1v+*&h3kXDC!( zniU*oCtX?g_T(L28j$Dm7|J>V8u$0(q325ct$p2VegY3x2O)A$PIT4?C{6bA>} zjedgAJli2A7L=BjR#3}Ut~=XbA0LiNYCa0+VY^PS84fKDzw9Kf_v+CSbV^D}gfgHo zH>RSaqa#yoyE!K$K`nf<%!MA>4d30nOXvto0Y~BDwK|rg$7c7X+Ub-#J$Za#|jMz{C)H;g+eax@?}|v>-$~-#sSG=wt_DZ7zVc03LMj}%Am_elerUCNx^KdUxCe>X2}p7S6( z)Fa(kJShw-SC$}1qpPo~t6QHO9}{Do zyt1;b%h(Mn*k{Fza(y7FW;*$`5vE;0LQ<0O^f5A=UsUuRtK~$x#VWDbjP}Wy5L{M5=tGtU~0N$q_c=cPp`!~GucIJeSPe`1MnW`?FfP}2cLkz z3RpT+C060+`F;Fo^t8zu7IosCxYtN2A9=Hazyqy`%Yl*h+j`wk+Fu`?+qo-jny;=!V`8 z!7}hT_r8mJo*T4j{NwMoDr#(b@CGwn##U*fXgEf)E~P;%dc>&{w_oxOWH^<-wWBSR^S$QfFzQdtO#`8K%JZdD;2W;Ez!AJb ztO6hJ3yPA*J;58xX~IpU5&08Tpu38bgyXTbvty?+DnpbMx~N(b3lnugo^1 z|1?%^J?8FK!eKY2o2sN@5oS(aBnCtO#o|Sv7Ww7aLzf0VFnUane5r=5ni}Z{9_e_^ z6!#uyA0`6|Q{m^Xc$n32P|j3EZabBJW*J7ZmK*keK9`(bbTUa-1`NB%TetGORf1NR z6LtYiynkSz+&`W%eMMIFac^sDKl|^c%*{`CGOS+hlKYd+mP-YKNzrem7~CtO=0j5W ztlLH}*p)W-YuI(;t7W_wEwVkEtQw zCrQxZTBdkPcl;297Qa7bPKbEuf2A`k3L*T7KwOBT7<)$kiev3@I967%!# zC&2@52HPc5H9(Q+!k6mx9}BO<{98`NP2MM*n-BH9ylsSZb+t$cHu7jSFhEG#V2&I3AkA|i@&96H}E zr=e+G!Q-iQS|#0m6?{)^X{p~80IQ*r047`PC}Hr3=X-e;pR&)QF1!R>jvP5lp@Je- z9T^!(#kXxV3qk%cICP_AV3Gs%T`w$^`L}Q1Y(dM*Vvf9hs6#UQ`bJ61bXdtdw{Mq+ zam$uqXH{bJv|=bPhuMsXIj59$8MGTK7iI>Nq^YT8Z zu=U&e2TcHU5%ouxfe(Vxw$xq4b~oiNeSHHCU@NSpK8(iY_T^vt`(HeGz$=YKbLp$y zm;;F0*Vm^j(!N}u(*c$w1|m2|4;?x~KogGV8KgqZ5%*YuYnXj8KdoSjbK?8=vp})= zMc?4WjAH-8I(73B&_pi$gSFHkQ~~$83~{&;0eb=m@@Etme)8KiCeocqYDz|fi!GQ; zt8=K_HWdxI7tHA244D`i-S1`g_Q`H}6E(p8CPd$1vGJjrK5WqYbGr$M5HZTVc|O}< zg<&0FJ52ivVB5^GF~`21o)TphmDbNyxAftEdYP?4hC7Q)#^R)@@`xInQTlx01m0~u zt_#tS8A>D0xgFV?j!vuFo&EeaLRdy7>RFR@Gg2SY7e61m6CGW(smOa#Ax8eP#Kicx zslC1Z5Gs9^va+)I(wQ$_v_c&{Iw?trAUa9Q+B0ZO4%>W#SG$NuE;g(#S~7@^j!ryO zwRC1`xQ4)GJF>~48+aq{^=nDsaA~hOw-!lg1KWt0~!#*ARX0P=%dEwBP zxw%n4Mmyu_XlZu=EH`6y2&jIsVNdq?d}TAbHy)2qHtn+=?SI@;?DKDI#mmqW5x5jh z{)vX1muArZd4Uk>e+!!aFWyFt1|Uv=|0CsmoZJk+(*f!02nf}{&l;=Xa-e>Zw`t31 z3LE&0&CalD)d3fmoQ_#{43HSF5{Rc3#H(%m9Wa}!c`f|1Qinx#>Z>h|mb6;K#YG(W z$(Q;F_=h;W9mJ#k=U(6`LzrlGGN?U!Gn|xB6Qe zpf&>wOQmb)mHwLxn-4BUt!w;aF`}RZYeeQWq>`9Ljr1`z?!3y&U5ve*ptZws?&k&h ziCW2XI7Wy>g1^0g(u*L0GP$`4M2Q~Y1|L+Zfu1waYW(xpuY|0uzgj+xb(f0cz*F7; z#;jpwU54#xvry|;mU&G@Vj2rEBJx5h!C{oqU&%Qfl0;S0eg9Qk%?}O3v-uS zdow=dXgn!3bSR)RF){g&X2OG@^-HYHfNb-(OQ$l;84=XdhpPIihH?^3rmOQK)C?Mg zbA;X9(ma?}WS^l3aDui2;x!zdoe%2huo1JI#4jDBU8&v*u{gd2l|)Fw9Ak)+>bDWCC^WrEhCN_4Ws_D@ITZ2zU@-Ld!c0g(dO3 zk_W^2e^(c5GGFay2k@0Qf`iAQe`eO2X#v$QOXnCQY&MZV8O}98@WkT>xOdCSf`Wp) z_?9#imTZGiZ%fCENId1RGI zWEdlPbY27*buMY!H_uNd-Mn}223EVfe1l0DfF|Wl54VBb_Ob+(pawYk7vF&xvg|uJ zMMXu8^bx9pb4%M2yKSBz^A&$(Y9o=5CesTk zpcuW|$Ind4=#bJCUBGbnMEI@DSs^rnKnV95d>0MUCMziZ0Ri1OPd~rch&95mpr_&5 zyY5c!MY{`L$MW39`M?RRtv;cxU7L6XxD3Vk^4X!m!C)S*pUZHPC}?W*=*9aF9Xl2f z6T?M$fGv#ivR~dYF)}KFat1gn%fm*F#7Z;E4Sbg$fj|jZ$C#wMEEu02+YaH$nrvCEf%hS=uUwoJG z&dh6%X;Cn%yKz89Owe5Nay9iIZiBr=3kwUD%kwa=9*qIw6O?%Q%aH;;xA3qxZK_MU z6&YD#s7X2+LPA!>_5VbwiQ?nqLs5!hs9DN>;;CULN8nH*u$)-hD$4T=SKYEelR0Q> zE3BJ*YD<)Sl}the2N7>1(I?V3i7?h5-3|AP{dAuiBBaDEf`W`la~r<2r+dKSoBH%= zSGF^vY;$w-u7c@LD)3B=ubgf4jm=K@x8>XccrI;fYUhA8QqP>p*MdC2Cp3h6$ zwe5e{*o7=689Fo?|4}yUQte-`sjxAjdO*d#khL{FcS%`!IpWA_#;%eQWpgX5i31mP zb=je`>1OdnGoIcoWJBN;AWGzl*IzEUQe!~&}O)?%+!jSyMw)Lc?rF{c4Eu@!9 zJbh_S4RXXYL<*kV7Pj`;g}Gk{F8y_r%CX~!{dx4{iJ|-=rtZ9{jg}-FU}OP(g*4UG z%W#w$i@d#&XW$bTXC?VK;~c5;|Il8)e*NvccY&{8@AbTLrMtJ6Mp03b1j7h`ND_q1 zdrhj``XMJ9xz8@-St^J>gN?@*_F$oKG{5ZQGR!*X3#k22GhV^*;>8lIjz#t;dJ%v; z&LZ+@_;%@QQ_=?9K4F==xx1f*Ct&Z_vi3T5Jv6i&RZWObu0SU##l2pXB5YE~omR9U zhpfc-%wQVL)5+W?j~?y+TYJ3OgsYjBD{b(YhK4EvYUFzJG7-uppkF?-&u>@IZ`4Nh z#U7+Z;EOYZJm^!sw9RM-4#4%rY`eLIp{J1_IUWJcxH5z&;+Vk!t3*s8sevGox~+ct z`}Y#bdU-!WY(QU?Q6A12p|W8$5}~h-n4h=I+Z2pF(X}u?i`=X7t?kE% zBh5!3Lb6auhh0ZjCjslC8+!Puone%u)$05A?~kD}(hEj7S>#8DZ`BTDueDFdTr1v=m<>ULear~IPMFj}R+K1PVzP7&O3Kb^}E)t89u;A9i1 zfa6Fy1~J6$LG`Qwl8ewbz5zF&ce&k}&VXjA@ZdsnP{Jn!!6e~ES5G0xxRA3loOwXA>p??>QaCF!O}w0qpbHQv~M>>e)~ zYY5QAo=