From 33e2beb52d4d8237c1eb483266876e255b7184c0 Mon Sep 17 00:00:00 2001 From: Samuel ORTION Date: Tue, 30 Mar 2021 16:26:55 +0200 Subject: [PATCH] Added spectrogram generator with python --- composer.lock | 69 + public/composer.json | 5 + public/database/authors.sql | 71 + public/database/categories.sql | 66 + public/database/records.sql | 78 + public/database/replies.sql | 81 + public/database/topics.sql | 81 + public/forum/categories.php | 16 +- public/forum/createtopic.php | 84 + public/forum/index.php | 2 +- public/forum/newtopic.php | 56 + public/forum/topics/index.php | 29 + public/forum/topics/sendreply.php | 71 + public/forum/topics/topics.php | 130 ++ public/scripts/script.js | 68 +- public/spectrogram3.png | Bin 0 -> 105386 bytes public/src/spectro.py | 22 + public/src/spectro_cli.py | 19 + public/src/spectro_librosa.py | 46 + public/styles/style.css | 13 +- public/upload/submitmetadata.php | 3 + public/vendor/autoload.php | 7 + public/vendor/composer/ClassLoader.php | 479 +++++ public/vendor/composer/InstalledVersions.php | 292 +++ public/vendor/composer/LICENSE | 19 + public/vendor/composer/autoload_classmap.php | 10 + .../vendor/composer/autoload_namespaces.php | 10 + public/vendor/composer/autoload_psr4.php | 9 + public/vendor/composer/autoload_real.php | 57 + public/vendor/composer/autoload_static.php | 31 + public/vendor/composer/installed.json | 59 + public/vendor/composer/installed.php | 33 + public/vendor/composer/platform_check.php | 26 + public/vendor/erusev/parsedown/LICENSE.txt | 20 + public/vendor/erusev/parsedown/Parsedown.php | 1712 +++++++++++++++++ public/vendor/erusev/parsedown/README.md | 86 + public/vendor/erusev/parsedown/composer.json | 33 + 37 files changed, 3850 insertions(+), 43 deletions(-) create mode 100644 composer.lock create mode 100644 public/composer.json create mode 100644 public/database/authors.sql create mode 100644 public/database/categories.sql create mode 100644 public/database/records.sql create mode 100644 public/database/replies.sql create mode 100644 public/database/topics.sql create mode 100644 public/forum/createtopic.php create mode 100644 public/forum/newtopic.php create mode 100644 public/forum/topics/index.php create mode 100644 public/forum/topics/sendreply.php create mode 100644 public/forum/topics/topics.php create mode 100644 public/spectrogram3.png create mode 100644 public/src/spectro.py create mode 100644 public/src/spectro_cli.py create mode 100644 public/src/spectro_librosa.py create mode 100644 public/vendor/autoload.php create mode 100644 public/vendor/composer/ClassLoader.php create mode 100644 public/vendor/composer/InstalledVersions.php create mode 100644 public/vendor/composer/LICENSE create mode 100644 public/vendor/composer/autoload_classmap.php create mode 100644 public/vendor/composer/autoload_namespaces.php create mode 100644 public/vendor/composer/autoload_psr4.php create mode 100644 public/vendor/composer/autoload_real.php create mode 100644 public/vendor/composer/autoload_static.php create mode 100644 public/vendor/composer/installed.json create mode 100644 public/vendor/composer/installed.php create mode 100644 public/vendor/composer/platform_check.php create mode 100644 public/vendor/erusev/parsedown/LICENSE.txt create mode 100644 public/vendor/erusev/parsedown/Parsedown.php create mode 100644 public/vendor/erusev/parsedown/README.md create mode 100644 public/vendor/erusev/parsedown/composer.json diff --git a/composer.lock b/composer.lock new file mode 100644 index 0000000..9cc842a --- /dev/null +++ b/composer.lock @@ -0,0 +1,69 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "f493960dbf3229f8998effb35c5e910d", + "packages": [ + { + "name": "erusev/parsedown", + "version": "1.7.4", + "source": { + "type": "git", + "url": "https://github.com/erusev/parsedown.git", + "reference": "cb17b6477dfff935958ba01325f2e8a2bfa6dab3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/erusev/parsedown/zipball/cb17b6477dfff935958ba01325f2e8a2bfa6dab3", + "reference": "cb17b6477dfff935958ba01325f2e8a2bfa6dab3", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "php": ">=5.3.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35" + }, + "type": "library", + "autoload": { + "psr-0": { + "Parsedown": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Emanuil Rusev", + "email": "hello@erusev.com", + "homepage": "http://erusev.com" + } + ], + "description": "Parser for Markdown.", + "homepage": "http://parsedown.org", + "keywords": [ + "markdown", + "parser" + ], + "support": { + "issues": "https://github.com/erusev/parsedown/issues", + "source": "https://github.com/erusev/parsedown/tree/1.7.x" + }, + "time": "2019-12-30T22:54:17+00:00" + } + ], + "packages-dev": [], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": [], + "platform-dev": [], + "plugin-api-version": "2.0.0" +} diff --git a/public/composer.json b/public/composer.json new file mode 100644 index 0000000..37ac237 --- /dev/null +++ b/public/composer.json @@ -0,0 +1,5 @@ +{ + "require": { + "erusev/parsedown": "^1.7" + } +} diff --git a/public/database/authors.sql b/public/database/authors.sql new file mode 100644 index 0000000..64f5536 --- /dev/null +++ b/public/database/authors.sql @@ -0,0 +1,71 @@ +-- phpMyAdmin SQL Dump +-- version 5.1.0 +-- https://www.phpmyadmin.net/ +-- +-- Host: localhost +-- Generation Time: Mar 30, 2021 at 01:11 PM +-- Server version: 10.5.9-MariaDB +-- PHP Version: 7.4.17RC1 + +SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO"; +START TRANSACTION; +SET time_zone = "+00:00"; + + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!40101 SET NAMES utf8mb4 */; + +-- +-- Database: `chirocanto` +-- + +-- -------------------------------------------------------- + +-- +-- Table structure for table `authors` +-- + +CREATE TABLE `authors` ( + `id` int(11) NOT NULL, + `firstname` varchar(125) NOT NULL, + `lastname` varchar(125) NOT NULL, + `username` varchar(25) NOT NULL, + `email` varchar(125) NOT NULL, + `website` varchar(125) NOT NULL, + `password` varchar(125) NOT NULL, + `entry_timestamp` timestamp NOT NULL DEFAULT current_timestamp() +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +-- +-- Dumping data for table `authors` +-- + +INSERT INTO `authors` (`id`, `firstname`, `lastname`, `username`, `email`, `website`, `password`, `entry_timestamp`) VALUES +(9, 'Samuel', 'ORTION', 'UncleSamulus', 'samuel.ortion@orange.fr', 'https://samuel.ortion.xyz', '$2y$10$31D2YXTFzhUM9gLDcXXEvuzp4EKN3DFv7No5G8/wXE1rUuDgu8mUO', '2021-03-29 17:21:59'); + +-- +-- Indexes for dumped tables +-- + +-- +-- Indexes for table `authors` +-- +ALTER TABLE `authors` + ADD PRIMARY KEY (`id`); + +-- +-- AUTO_INCREMENT for dumped tables +-- + +-- +-- AUTO_INCREMENT for table `authors` +-- +ALTER TABLE `authors` + MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=10; +COMMIT; + +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; diff --git a/public/database/categories.sql b/public/database/categories.sql new file mode 100644 index 0000000..7107fe6 --- /dev/null +++ b/public/database/categories.sql @@ -0,0 +1,66 @@ +-- phpMyAdmin SQL Dump +-- version 5.1.0 +-- https://www.phpmyadmin.net/ +-- +-- Host: localhost +-- Generation Time: Mar 30, 2021 at 01:11 PM +-- Server version: 10.5.9-MariaDB +-- PHP Version: 7.4.17RC1 + +SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO"; +START TRANSACTION; +SET time_zone = "+00:00"; + + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!40101 SET NAMES utf8mb4 */; + +-- +-- Database: `chirocanto` +-- + +-- -------------------------------------------------------- + +-- +-- Table structure for table `categories` +-- + +CREATE TABLE `categories` ( + `id` int(11) NOT NULL, + `cat_name` varchar(125) NOT NULL, + `cat_description` varchar(125) NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +-- +-- Dumping data for table `categories` +-- + +INSERT INTO `categories` (`id`, `cat_name`, `cat_description`) VALUES +(1, 'Records', 'Topics related to uploaded records.'); + +-- +-- Indexes for dumped tables +-- + +-- +-- Indexes for table `categories` +-- +ALTER TABLE `categories` + ADD PRIMARY KEY (`id`); + +-- +-- AUTO_INCREMENT for dumped tables +-- + +-- +-- AUTO_INCREMENT for table `categories` +-- +ALTER TABLE `categories` + MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=2; +COMMIT; + +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; diff --git a/public/database/records.sql b/public/database/records.sql new file mode 100644 index 0000000..c14e637 --- /dev/null +++ b/public/database/records.sql @@ -0,0 +1,78 @@ +-- phpMyAdmin SQL Dump +-- version 5.1.0 +-- https://www.phpmyadmin.net/ +-- +-- Host: localhost +-- Generation Time: Mar 30, 2021 at 01:11 PM +-- Server version: 10.5.9-MariaDB +-- PHP Version: 7.4.17RC1 + +SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO"; +START TRANSACTION; +SET time_zone = "+00:00"; + + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!40101 SET NAMES utf8mb4 */; + +-- +-- Database: `chirocanto` +-- + +-- -------------------------------------------------------- + +-- +-- Table structure for table `records` +-- + +CREATE TABLE `records` ( + `id` int(11) NOT NULL, + `entry_timestamp` bigint(11) NOT NULL DEFAULT current_timestamp(), + `author_id` int(11) NOT NULL, + `recordist_name` varchar(125) NOT NULL, + `file_name` varchar(125) NOT NULL, + `license` varchar(25) NOT NULL, + `species` varchar(125) NOT NULL, + `subspecies` varchar(125) NOT NULL, + `sound_type` varchar(25) NOT NULL, + `country` varchar(125) NOT NULL, + `lat` varchar(20) NOT NULL, + `lng` varchar(20) NOT NULL, + `date` date NOT NULL, + `time` time NOT NULL, + `remarks` text NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +-- +-- Dumping data for table `records` +-- + +INSERT INTO `records` (`id`, `entry_timestamp`, `author_id`, `recordist_name`, `file_name`, `license`, `species`, `subspecies`, `sound_type`, `country`, `lat`, `lng`, `date`, `time`, `remarks`) VALUES +(2, 20210330072954, 9, 'Samuel ORTION', 'PaRecAR628069_20200526_040726.wav', 'CC-by-nc-sa-4.0', 'Pipistrellus kuhlii', '', 'echolocation', 'France', '47.87840601525087', ' 0.21813243633005192', '2020-05-26', '04:07:00', ''); + +-- +-- Indexes for dumped tables +-- + +-- +-- Indexes for table `records` +-- +ALTER TABLE `records` + ADD PRIMARY KEY (`id`); + +-- +-- AUTO_INCREMENT for dumped tables +-- + +-- +-- AUTO_INCREMENT for table `records` +-- +ALTER TABLE `records` + MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=3; +COMMIT; + +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; diff --git a/public/database/replies.sql b/public/database/replies.sql new file mode 100644 index 0000000..a182126 --- /dev/null +++ b/public/database/replies.sql @@ -0,0 +1,81 @@ +-- phpMyAdmin SQL Dump +-- version 5.1.0 +-- https://www.phpmyadmin.net/ +-- +-- Host: localhost +-- Generation Time: Mar 30, 2021 at 01:12 PM +-- Server version: 10.5.9-MariaDB +-- PHP Version: 7.4.17RC1 + +SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO"; +START TRANSACTION; +SET time_zone = "+00:00"; + + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!40101 SET NAMES utf8mb4 */; + +-- +-- Database: `chirocanto` +-- + +-- -------------------------------------------------------- + +-- +-- Table structure for table `replies` +-- + +CREATE TABLE `replies` ( + `id` int(11) NOT NULL, + `reply_content` text NOT NULL, + `reply_date` datetime NOT NULL DEFAULT current_timestamp(), + `reply_topic` int(8) NOT NULL, + `reply_by` int(8) NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +-- +-- Dumping data for table `replies` +-- + +INSERT INTO `replies` (`id`, `reply_content`, `reply_date`, `reply_topic`, `reply_by`) VALUES +(1, 'It is probably better a *Pipistrellus pipistrellus*.', '2021-03-30 13:56:01', 1, 9); + +-- +-- Indexes for dumped tables +-- + +-- +-- Indexes for table `replies` +-- +ALTER TABLE `replies` + ADD PRIMARY KEY (`id`), + ADD KEY `reply_topic` (`reply_topic`), + ADD KEY `reply_by` (`reply_by`); + +-- +-- AUTO_INCREMENT for dumped tables +-- + +-- +-- AUTO_INCREMENT for table `replies` +-- +ALTER TABLE `replies` + MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=2; + +-- +-- Constraints for dumped tables +-- + +-- +-- Constraints for table `replies` +-- +ALTER TABLE `replies` + ADD CONSTRAINT `replies_ibfk_1` FOREIGN KEY (`reply_topic`) REFERENCES `topics` (`id`) ON DELETE CASCADE ON UPDATE CASCADE, + ADD CONSTRAINT `replies_ibfk_2` FOREIGN KEY (`reply_by`) REFERENCES `authors` (`id`) ON UPDATE CASCADE; +COMMIT; + +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; diff --git a/public/database/topics.sql b/public/database/topics.sql new file mode 100644 index 0000000..5615fc8 --- /dev/null +++ b/public/database/topics.sql @@ -0,0 +1,81 @@ +-- phpMyAdmin SQL Dump +-- version 5.1.0 +-- https://www.phpmyadmin.net/ +-- +-- Host: localhost +-- Generation Time: Mar 30, 2021 at 01:12 PM +-- Server version: 10.5.9-MariaDB +-- PHP Version: 7.4.17RC1 + +SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO"; +START TRANSACTION; +SET time_zone = "+00:00"; + + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!40101 SET NAMES utf8mb4 */; + +-- +-- Database: `chirocanto` +-- + +-- -------------------------------------------------------- + +-- +-- Table structure for table `topics` +-- + +CREATE TABLE `topics` ( + `id` int(11) NOT NULL, + `topic_subject` varchar(255) NOT NULL, + `topic_date` datetime NOT NULL DEFAULT current_timestamp(), + `topic_cat` int(8) NOT NULL, + `topic_by` int(8) NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +-- +-- Dumping data for table `topics` +-- + +INSERT INTO `topics` (`id`, `topic_subject`, `topic_date`, `topic_cat`, `topic_by`) VALUES +(1, 'Pipistrellus kuhlii record', '2021-03-30 11:42:08', 1, 9); + +-- +-- Indexes for dumped tables +-- + +-- +-- Indexes for table `topics` +-- +ALTER TABLE `topics` + ADD PRIMARY KEY (`id`), + ADD KEY `topic_cat` (`topic_cat`), + ADD KEY `topic_by` (`topic_by`); + +-- +-- AUTO_INCREMENT for dumped tables +-- + +-- +-- AUTO_INCREMENT for table `topics` +-- +ALTER TABLE `topics` + MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=2; + +-- +-- Constraints for dumped tables +-- + +-- +-- Constraints for table `topics` +-- +ALTER TABLE `topics` + ADD CONSTRAINT `topics_ibfk_1` FOREIGN KEY (`topic_cat`) REFERENCES `categories` (`id`) ON DELETE CASCADE ON UPDATE CASCADE, + ADD CONSTRAINT `topics_ibfk_2` FOREIGN KEY (`topic_by`) REFERENCES `authors` (`id`) ON UPDATE CASCADE; +COMMIT; + +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; diff --git a/public/forum/categories.php b/public/forum/categories.php index 8dc662e..723c59b 100644 --- a/public/forum/categories.php +++ b/public/forum/categories.php @@ -3,6 +3,7 @@ ini_set('display_errors', 1); ini_set('display_startup_errors', 1); error_reporting(E_ALL); $root = realpath($_SERVER["DOCUMENT_ROOT"]); +include("$root/vendor/erusev/parsedown/Parsedown.php"); require "$root/database/credentials.php"; // Connect the database @@ -18,6 +19,8 @@ try{ $req = $db->prepare('SELECT * FROM `categories`'); $req->execute(); $rows = $req->fetchAll(PDO::FETCH_ASSOC); + +$Parsedown = new Parsedown(); ?>

Categories

@@ -30,11 +33,12 @@ $rows = $req->fetchAll(PDO::FETCH_ASSOC); - - - - +?> + + +

+ + @@ -44,6 +48,6 @@ foreach ($rows as $row) { - + diff --git a/public/forum/createtopic.php b/public/forum/createtopic.php new file mode 100644 index 0000000..8cf6535 --- /dev/null +++ b/public/forum/createtopic.php @@ -0,0 +1,84 @@ + PDO::ERRMODE_EXCEPTION + )); + }catch (Exception $e){ + die("Error : ".$e->getMessage()); + } + $req = $db->prepare('INSERT INTO `topics` (topic_subject, topic_date, topic_cat, topic_by) VALUES (:topic_subject, now(), :topic_cat, :topic_by)'); + $req->execute(array( + "topic_subject"=>$topic_subject, + "topic_cat"=>$topic_cat, + "topic_by"=>$topic_by + )); +} + +ini_set('display_errors', 1); +ini_set('display_startup_errors', 1); +error_reporting(E_ALL); +session_start(); + +$_SESSION['error_msg'] = ""; +if (isset($_POST['submit'])) +{ + if (isset($_SESSION['username'])) { + + $root = realpath($_SERVER["DOCUMENT_ROOT"]); + require "$root/database/credentials.php"; + // Connect the database + try{ + $db = new PDO("mysql:host=$host;dbname=$database;charset=utf8", + $user, + $password, + array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION + )); + }catch (Exception $e){ + die("Error : ".$e->getMessage()); + } + $req = $db->prepare('SELECT id FROM authors WHERE username=:username'); + $req->execute(array( + "username"=>$_SESSION['username'] + )); + if ($data = $req->fetch()) + { + $user_id = $data['id']; + } + if (isset($_POST['topic_subject'])) + { + $topic_subject = $_POST['topic_subject']; + } else + { + $_SESSION['error_msg'] .= "You did not enter a proper topic subject. \n"; + } + if (isset($_POST['category'])) + { + $id_cat = $_POST['category']; + } else + { + $_SESSION['error_msg'] .= "You did not enter a proper topic category. \n"; + } + } else { + $_SESSION['error_msg'] .= "You did not log in.\n"; + header('Location: '."/auth/login/"); + } +} else +{ + $_SESSION['error_msg'] .= "You did not sumit the category creation form.\n"; +} + +if ($_SESSION['error_msg'] == "") +{ + create_topic($topic_subject, $id_cat, $user_id); + header('Location: '."/forum"); +} else { + header('Location: '."/auth/login/"); +} +?> \ No newline at end of file diff --git a/public/forum/index.php b/public/forum/index.php index 0912984..845cc07 100644 --- a/public/forum/index.php +++ b/public/forum/index.php @@ -13,7 +13,7 @@ $root = realpath($_SERVER["DOCUMENT_ROOT"]); - Chiro - Canto + Forum | Chiro - Canto diff --git a/public/forum/newtopic.php b/public/forum/newtopic.php new file mode 100644 index 0000000..9731c27 --- /dev/null +++ b/public/forum/newtopic.php @@ -0,0 +1,56 @@ + PDO::ERRMODE_EXCEPTION + )); +}catch (Exception $e){ + die("Error : ".$e->getMessage()); +} +$req = $db->prepare('SELECT cat_name, cat_description FROM `categories` WHERE id=:id'); +$req->execute(array( + "id"=>$_GET['cat'] +)); +if ($data = $req->fetch()) +{ + $cat_name = $data['cat_name']; + $cat_description = $data['cat_description']; +} +?> + + + + + + + + Chiro - Canto + + + + + +
+

Forum

+

Create a new topic

+
+ + + + + + +
+ + + + \ No newline at end of file diff --git a/public/forum/topics/index.php b/public/forum/topics/index.php new file mode 100644 index 0000000..bc209b7 --- /dev/null +++ b/public/forum/topics/index.php @@ -0,0 +1,29 @@ + + + + + + + + + Forum | Chiro - Canto + + + + + +
+

Forum

+ +
+ + + + \ No newline at end of file diff --git a/public/forum/topics/sendreply.php b/public/forum/topics/sendreply.php new file mode 100644 index 0000000..a8ca7f5 --- /dev/null +++ b/public/forum/topics/sendreply.php @@ -0,0 +1,71 @@ + PDO::ERRMODE_EXCEPTION + )); + }catch (Exception $e){ + die("Error : ".$e->getMessage()); + } + $req = $db->prepare('SELECT id FROM `authors`WHERE username=:username'); + $req->execute(array( + "username"=>$reply_by + )); + if ($data=$req->fetch()) + { + $user_id = $data['id']; + } + $req = $db->prepare('INSERT INTO `replies` (reply_content, reply_date, reply_topic, reply_by) VALUES (:reply_content, now(), :reply_topic, :reply_by)'); + $req->execute(array( + "reply_content"=>$reply_content, + "reply_topic"=>$topic_id, + "reply_by"=>$user_id + )); +} + +ini_set('display_errors', 1); +ini_set('display_startup_errors', 1); +error_reporting(E_ALL); +session_start(); + +$_SESSION['error_msg'] = ""; +if (isset($_POST['submit'])) +{ + if (isset($_SESSION['username'])) { + if (isset($_POST['topic_id'])) + { + $topic_id = $_POST['topic_id']; + } else + { + $_SESSION['error_msg'] .= "You did not enter your reply. \n"; + } + if (isset($_POST['reply'])) + { + $reply_content = $_POST['reply']; + } else + { + $_SESSION['error_msg'] .= "You did not enter your reply. \n"; + } + } else { + $_SESSION['error_msg'] .= "You did not log in.\n"; + header('Location: '."/auth/login/"); + } +} else +{ + $_SESSION['error_msg'] .= "You did not sumit the reply form.\n"; +} + +if ($_SESSION['error_msg'] == "") +{ + send_reply($reply_content, $topic_id, $_SESSION['username']); + header('Location: '."/forum/topics/?topic$topic_id"); +} else { + header('Location: '."/auth/login/"); +} +?> \ No newline at end of file diff --git a/public/forum/topics/topics.php b/public/forum/topics/topics.php new file mode 100644 index 0000000..b4130f9 --- /dev/null +++ b/public/forum/topics/topics.php @@ -0,0 +1,130 @@ + PDO::ERRMODE_EXCEPTION + )); +}catch (Exception $e){ + die("Error : ".$e->getMessage()); +} + +if (isset($_GET['topic'])){ + $topic_id = $_GET['topic']; + $req = $db->prepare('SELECT topic_subject FROM topics WHERE id=:id'); + $req->execute(array( + "id"=>$topic_id + )); + if ($data = $req->fetch()) + { + $subject = $data['topic_subject']; + } + $req = $db->prepare('SELECT * FROM replies WHERE reply_topic=:id_topic'); + $req->execute(array( + "id_topic"=>$topic_id + )); + try { + $rows = $req->fetchAll(PDO::FETCH_ASSOC); + ?> +

+
text($row['cat_description'])?>
+ + + + + + + + + prepare('SELECT firstname, lastname, username FROM `authors` WHERE id=:user_id'); + $req->execute(array( + "user_id"=>$reply_by + )); + if ($data = $req->fetch()) + { + $username = $data['username']; + $firstname = $data['firstname']; + $lastname = $data['lastname']; + } + ?> + + + + + + + +
AuthorReplyDate
($username)"?>text($row['reply_content'])?>
+
+
+ + + + + +
+getMessage()); + echo "Can fetch topic data.\n"; + } +} +else { + + $req = $db->prepare('SELECT * FROM `topics`'); + $req->execute(); + $rows = $req->fetchAll(PDO::FETCH_ASSOC); + + ?> +

Topics

+ + + + + + + + + + + prepare('SELECT firstname, lastname, username FROM `authors` WHERE id=:user_id'); + $req->execute(array( + "user_id"=>$topic_by + )); + if ($data = $req->fetch()) + { + $username = $data['username']; + $firstname = $data['firstname']; + $lastname = $data['lastname']; + } + ?> + + + + + + + +
SubjectsAnswersAuthorCreation date
+j>;47z)BTWj)|oTeGi%S5XZAc3rKTc}|Mb;U004mhQ9(un06-500MJ%(u^(IB zjW2FIK7>4Ebv-m)tUbKU+^hh~W*)ANE*_3{=C3`i+}!P4ocX!la`AAyw)OCEbr$)D7*ebWk~&kE*n{hiP-(T0hY9!M; zb8*oz7pxse=?QP{dk3rjzz)|GW48|`*eSWc4Z+zHR#%1<>GYl=5B;>MO=%2 z#V@byCVO(JOf_g^Coq@NJVqTG|J7UDv3#je?0pJ-Di^H(>zxZ9AoyRO@Lx6e+XA{C zJN;L0F*ytX!T;QuqTNQ!Gk_p+RypHJlW|BL4~$Xcd=``5dQ|G$lXH~(ePZRf+q z!$x(}NMf(K%jR!vfMICIQ8+hr&L%IQZTjVZ+xBq&XuyHH+se)Ig?H5#!$((nx1Fr1 zLQI^{WPA*26ujEl2Z2}`TZXW|A+}^mqu8X&VYU-97qST!W?2!?bL%_!iSM(8i?x$q zn=RbVCh?6%&WhTUcX%c7(DSWgi|;AbGGBa5khL(GqMX?d7WNE?%7oNKd~KGv{2ZJ+ zO2ujFRzswxafPhHrP%TGgN!q?MImdsC#mpL7uup?cQ(qk^NSj_xSj^96{K*C>t11X zALmZ?HN#Hcp6rEY@L`mfeOYSBArA3R&Le4tdATuT-MrP7KN2XHwVqnKLl6AJg8gkD zBJ;U83o|Qr`WDW{dj*S3)c5K1;&aoSspUVkHyB%N4!>v?v?sm}?@ux7kMQ#0%;|1} z-_RB<YNh!*k{QaCB;v!kDMtk)z<9@W$o^sGY4GAI&(uWbZ4D$M%-)SS%flO zjr;0Pw$NuLZHDpc%KRXmVi!r9r0aEC3;VFE>bs`%CWzBdvBJL4Wby=84uwT>m{2vc zqS5-H*l$3^g%G&VP?vb;NG!AsYyIjNuugdrZgM&5L%jlej6biE!2#rDduhE(=XFe9 z7202~0<%Tws|M1k&YeKhma^-rqRo?}ddjzqB0^#b6L$Fo13rZ+Yl}82`bf527kh)2 z?GXO)8IrL{D-V&0-??PWhUFe6wq*$b`mY#!ngLFEYrO#H33&|2MzTlHuBY9d-hzyF zz6>(ia#vh_0+bJ@yOUL`Uf|Nep{-a!KN?4=2ioIs8N$7zr#yq(JQmW$N)K6iehXy) zwLuXj5i~Y6e&`@uB!r5x(}OlNIDha>pkQ4C_gmhTU|*{M0O=lxzLk4WNH@gB9Pde( z{&}!fv-mcNyO@QNs1OwUMlv)7^X+V#>Pm~mWC#-_c|iPJf#AwJRe_*{>MyE6>dc!i zElx}#qKP^6eo|;5o`Z0Bv-1C(-&=Qf~)946)!)d8s z_oFfoI6IH6r00^5GO3CeoLl{|`(;(H#T)73$T4((9cAK#Y0FXdGW}Ivi!}0L$-$cI zCgazIGVcf~9yC@!#SI+&_BS2n!qL&T+AXZHS;5PS0n*>6XA_iEJMui91I0oOr^z9Q zYmL%{q)xEp-DpVN{!2%0%(=K-V3xZ!KjCW$RNL_!!m;< zz2|2hx}oL@kcimrZsIV%dM~1Rm~0h)KIK{qy2As~)}LBm7*j@;<8JY?3Z{ zg?x3CEe~T|7Tn*&h`Z%T0v=VWPbG|_e!KLr(>A@S-<#6J0*ZmgG901UTD zr%-FZY6(Rxg|2ixamb)f>&8a$>W$q7!1VhA%ld;I0UXp^p*^gZ)uDy5)u0W+I~8CL zHROEibRI6Ad;6K7|CJRV*$>m`4R99Z{7kt(vAV-gxW+r|lXiXIivC%pEEeXvVbrd^ z4K0~uv#yNduYC8x3B_XU$y~=l%{$JoInV&id2y1w>j*S5WnVKDUpmQ(``X=7&na+) zH;c(<=(rW$L-PGM^O(W&@J7c?t69fa7VZ1o?4}B+iT!#7;L>gm>y3el9FPO{e4;QP6<0~nTx2{X72fQ;TBz2dbIdv4 zvX%!lfWw@K%FCpx;T7b#TewX)GG=*-2X)Clyw|dj8hNtnW>kvovoKu>hY`c;B}J83#`sslmKc`=oXl?BG&TQE7Y`Y6qe-;_RT|i8<1b z54#_62DA+YYxQ4?r+D^UskGFQ(FHFCQ!TBK=I=As(3J_*W#0^6Sxx6uaAD#6Qd$x( zk$=xEEgH&VD!`wjqSlDf91*{{{|X=QaP@+Lf7OK0~6ui~$yUUk0T5RIA2icZbRLMsxdWS|`;0Cd?`2#fyR2T_nwp6U$Pa_P6+L zJwtbZLV|1|a2qfmQ|KaQ%dDP?OHox*olPa_2k9F&R_xQ%*r1an0D(=H5tnZwM@fb?8{f=?ezj+^Y)ek#@h}Y!RoX!CdM|Z z^<)BXs<3GC9IY1eb{OV8iG)i(($3p_(PEMe04wXF-oOBVKjhT%(s;)YKt)M-)PO{1 zYBWbnbDJDALp@)lC892LCG?nzX}>lE7f61mf`ajXK>8Pt|@0;`;%D3vsY?Wew-$qICg-prD7nsL_finJU(j1KzJxJ-*?1= zXCCzt26(ISjO5z+>z=U)ov-rpxq#$1=1`6J5i!ttlnUuyF2Lyv`X~KGwD^wfcMA}e z2NYG*+!_3VYCia>dt9BXTnnEOp-PmJeShEC(nkox_7B)&wpU4rvz?Ssrof%!cv|0l zYeTCsEc=`Y%cxQ~qpyc$TTZ@a?JE0}am&7N1)A zu^TCv6dO1mYQfd?!)m+i6}P1IUdf_49TPXdA| zUr*Mj9FrdwgLY{RWPB@tsdNJ@wG<0Z#o71OChz%u*2?&n!YrPdyz}GjJT`#|KQHFs(=bXsLq}Hk&>X^U+YCwr>R=RuE+s-)C)|+c8VH$C$?J2c6%$NLe z8=y?$n3JCH4Mk#{iNmkqQ1GcWjhNt7N1Si;#Ti0+wlVP|zi4V`Jt}{NnpUz2%h7LU z_V*ds)llu#9Un)Lskn004Jk597+M)Lsry~vGlk3^pftY%J~bBA_>hseLLiXI!)yQ?{E^zfGwjFDn!&#p^}TyFZ5D8QOiHvdo<#F!4E~iJ_-dTchu`bxc-jjfuym7|&TY2DD74C8=v=5lzjV3(n7$ldV z4qo7d^1ufhr*j>PtZ1~0!DGDnwsErFnZnY5M%nmX0A7K|;$-OnfGa1B`V?Al;5E0i zQ?svvfw6BvR801Pn&MTmeh14b?;cHmM)uwjddVI9gP6#vJmVGaj4Pq3} zTIT(5>y|C%h*qC`*aGRbzoUVoz{zxA?p30d38@W~v-1_kZ3pCUlgQnVU%epY22Cj% zz$@CfHEz>!z#DHh3~C1_DH2f-^79d`@S4@{YVPkIS~A`P07|Heyz9JOZonxa$e-W} zC%BMGfU+x`4Mx^kacVn~?TTz}6e>1+Z+2vT)vDb|FNmxN<$LDFzv&Le^3)EF{^T_K z^L(g+%=@BJpc1&`VwD7X8b|o*Z5B3Q5!1|5QR9pa5i-ffP$s?>-^1Y2OH!vp5+!6* zXyKL0EIW2Bl}dGoY>c)U6fZs>gD!qA;kVIMk&m|b)0g)j_?fPv@WAnz!Q6U*b^3;? zB3EBRI)3rnwOd21ORUX=bUgL##*2l_ID?S+mkX6#l2>1wr!n?-mM5?)Ip4GkCMsEv zbOh%hgb-+KglCDK=GHORwTU$Pw5hWCyZasN3D)Zaf@Ogf*Ic!ZVRIQN;WOfxtlNA8 zw6ch-F733HW80`@jZyh0%@REPaE&;OpE|*|H9CnY*HZE7gx?q0ZeacezT9fkE0Mms z{aW-LXPq6~=%;+OaV4J*g{M5n=2<0|^h5H%5==c$-$qk&YelyEO}&zS_I6e3z3_#p zli0z)Hm%?3U8b+s0Zf~bkNu-T1 zgNr+V7-0t(Ix5TlVERB^LGiL);B!d#iE6|4CqK~8TAp~36AJSQ#F@P)81(I^14-|( z2lubvrI2Mp_JA)Zf#BI4aqwmhu&=s&1#AXl`7xePxbGCb_f$6`#mW4gMfNro%29u& z>WqG+CBT7)zyH3?;fe*f;i8f&`25+y3t9ngJRfRdrsWF%s^Jk8lAxbIEJASwl-1fA zWhE4yhD53yd0S_6vkn;_Qz28NFgkdR60cbNeP8*YoX1ONLhd5m99LofG@q7f7N2~s z*c+Bkc_yRTS3uv(VrZKU43nQ;!T6l4uI`uEE@xyC_&p_patm{(McMJr9Q?s1L3Xc( ziIA48%Prsqe;o%PL|GcT=xmNkHT}JpM$5dF^F5sA7sW+`Bfo9!HCje; zzH?1=(hE|h>$yRS`s#T^KkI*US{`jM%r&W1o78J#2 z?}qWuWop1BmfxPeW`3wTKosF#yV!^39zw*z&Bac0IA1Hy!7kiWRedOZNobhNazu5^ z$2WH)m3B@1FIZp%HXUkAs4p)TD}pi;U7W7Uml=Q46rus%OOepqonu-cOOiK1)+Dq@ z(Wr{}sn?|pc)aWoP@heLo7v$&j4&V_-Oe{}@zio1LAKi9Ovm#Ud^}vHZJ=lVVrNZo z&Oqg82C~9-IOkRk`)n?{pgo1sFayPx=vdcUZa5^2*2Hl@>Ikov$6LdVX(T)Y^vbT# z7wr`@V^q;;Yhpmi*2q9yfehaoUdiu+*Mp4?l@_)O*+4&%{$R^#YcHfX$wCIKBjYU5 z(j{xTu%eRwrBaYze3|Zj0Eq~Zm+NCOxu;q9$4JfM5cav!YHn|^(J9q9Q|sTiJDltA z)UCz+$O@Hs%Y#gR(_b;PT-Fw*{^x_lVnfVy>;Ma|^dRddUI94jsanGQ4qcTPT(rSs zdm#TaMJ(jLIE{5Zqwv62NxmknC+3O_))DEXbq>4kd{^h|xPbR#0@(I`hTJDV2c`9f zeAn-FHcH1~NHmvPoWp*>@vHi(NJ~8By#lfc@_PT+dB9#>Us1t2EiD34gY--O7h?Y= z>BP7qO9aEJm}=67C&wuqOV$LUv)(07x385Hy&3~_R@0tHx)QJIfA_^xNh1%*Bc{K| z;Ag+4bCaKmPT%?97_4`jZLPBW{5a?1)kb}wStaS6Nn2H{(SS zSzq`BI%lS8LpaG`jc!7r*!17yvos$@bG!lPsx(Z8Uz~iO!nhq&E4QptTpiE63yj8t z(e9(qtWeFd^}++G6RGLD>;Ad;3#omPPIG2KrY6kPN3EfpckD**9@K^^HYs|_jl*Ks ztG0S4XtpPNbd60;9Oc$wzvG`9MbTDn<{tCgGc|xq4X(GAP8u+^vQgv=);+R)%1i8< z;xnL8jQ-6G)pw(kY;%q(pWQQ{3q}6|kX@~rU0DZ#a#X&7Y>q8S>sqN31<@79C;5EQ z2ngA|6vO zSOjh0H9f@uqsUxpU$0TAQ5v8ph;z1F^-$aUU1zb2v4Q6vRp_eftM?na9YcdE3@c1Q z5%Po;m{KT6)ot&kA}XW&SyKl6C4)FAjQ?F*AcH@Pw~_tP zIsu{eAlZLD8J;s^yM*oT^4B~=-KfLnxRoz$k7n0A#52c=XuA`ThflQHUgxT%(#r07 z(<5{cLckH>-{$nN%z2gkL^&i0IE2pc(RZ|Cy~GHpR4;2bJTmFrnJLm}1ON>H*wT$Bp#Pod_gAr5Z~bX_~OL zT`I^xMptCv;I#8;XO>;ErW5IuXov<-j%Uz2H$j*et{gV zFtW>SRHB;vm{LH9vwi=2o%nj^)Zb*V*L4uR^1+@~9_@<|dG$&|jYn65&OLW%vsG4> z#5?FllR(L6OkS?TwP$=?^L1G8^csgxBZ+{^nWxVyKm0zl*N8Hx-c1HRe_%C%$X5B) zS+J1?6VKfCjZDhN3lP{=Y|8(?7C!N>VdetAW~1S!5&g%-&2@9+l?RL|((r75+4NqS z*GDF_vznXsvcH$LDb8^-t-;t&B{0sa3H(Bi%StXE--*@b+s!m6yX;u-u@%h}!mZ~# zPAWNqE7i1F(Rp#C*Gj$D$eh*Cw_5U~dCWvPozd3C=x&PTEzr63+7zEp%AP&A(PK=C zG1FyPZm)+R?9xm~Ep^z@8D#tUWb z&oGZYL=rh~4n7`xzZs_zjBl9y$1X1MP3M@A_DQ9R}m{k#@!#r9bliVLPfw9;;6$fC44L>wcv>{O%S-)rx=F&Ky|( z)sikKDUOEljJ5Zg*#0isXKFPT61gkCdGS_DoWNT*nLq6t4O~6`gFsBx&x2{vQ&b2s z&ZBMqv>8b+QqJQXgED>dJb}ajx4{6R`g+o>&yma8q*j8)%G2i`meH!VHtM zN?;Yht&$dbBUYSKS0;kd{muEzuIKh`aU$z=W_7k7S~9+Ap^15nf#(Z_uMo}ofnA68 zNt3z-Rt3DOAbn5l?FO*jQ1#m4c$dkA6t+eV0FKe*cu($Gj;KV|T$MSo-i4A&Xa>B@ zV+>-SLg*R{@f9?GRMu?d)&7>TQzyZVn(VT;x%h&0%S^%JIeb!QH&p5K{1ZiWohz45 z2pC(9%agiH&BrLl2;LB#X_^(sC4ZKN%wjThwuWTOn@&+{Xu0Q`g z?xO_p<=ySsAO=(e8yEMTy^wJ$#0U!*0eitEwbZOg;*?&k7pR-iu(d>vpfI)X2z40H~dpjg->m)QzQ zexI^fN`z}Gh3_a(p zPG}$2gOcL|&x%g!BgB-r+KxV4O{8_atx%pGWr~_2X^ezu$uY?%GoFq&N%|N_s4yDe zEm!;;E4NLs;sC6Y9yUx8QrPOHimD@Ky=>4{7o5Y$m*X*Ub;m^}xl?8&czeNt4a0jp zeBz=TR)o)8HYj`SpS3+pP6;@osv4o$1s8M(lCz07&V#3%x;;xy=u##6tvNiceznJF z>!#RT|Mf4XNYwJ%86~nerneuF7jMkVaRz`hM$9XxVk-;}H$e|BS2_>7CIjRh zM_5AZG5j(z8~85Xp>3DF+^IpA5kcSYZZ2RTlUsA2nP1Cq@-F`{H&&O4?c1G9*9B@V zpXOdfMna2d?`*GX53jj=mXOBG^z;S>25#qbHn7vY2mhp#fSLN7td9SZRosdf8e;~%E`8#8A`%>oT&es^$2^^>)T)n6--o#V|H!fo=# zb-FJJI)pjab}!$MzO<#Qvd_fM>X)^2-RIFFU~X99`(4R4&9S1hD9 ziggzxpEaUXSH6#$xRoq=Oe(t_txC;-JQha*%a3pL^ltNZWl@n()Qkyt>yl?ycF_IR z&mj!jOUbKEmwW4<2N2|=ML>|XN$#U!??WYs6Y#j()Z%Ew*z#^SnB6Ic8B#uqI=7>= zf8JjsL42Uz4 z%aPJ|ZLU3MZ>{-~bcSloN4{9dJ@zDH?8&cblUKNPJ=U55%>>H(O|0&OpmVs>PT1BH zucQO0`w3=QQe4?lO%3POT;84D75T%O2~?Wqgov0}$ZaEXZ>7`Z;7hz8snw|9`m@It z1+JoQ6G+~HkJZ1Kn><|4AlOZ=qNzkYV^XiC%EV<+?TA!^jZ_2Yft7d~F~}XAEPuMy z*!VM**F&otwnTh5QPC%iUta{62olN(uT3H}Ep5je#il`ZdQ;3B9q=VK3}Pqv4E>Uq zu_wRLjFSRNFK?%&^xOR=NpLUSRZ4bbhJI@7M4LzQ$bnN7ls?(t1B}@uskO;c?U)i9 z%SHK}oHbr}!r_xiAA5_|g;7IG$CMC9$_GlzMj)+zz`Q*neCE2op>dPJI;`@BO=M#Z z@O-!XzyNh(Q_(-iHhRr)3|%MEUJ>(?r&M(BPdto8d~Tbtud-qnTLrbG&Bc6o8?r8n z++(nk9b6Y=S-BqBh)%YMIsMeyZqvatA)*OsLv_(y`@&V1sdjuy#%S`_Gtt^M5*0T{ z@-D;L_MKcra_v1PwRDW$l;!%`-+MiJ_e{8GQI9NF0GuH41cbnx1hqo#3wdznitzmA ziL7=zd)vE!?1PFs^=xAbXIZDONcYk_YFxoj(w~<}q2U;^dstqF>BsLri!KOqsBV51 zP`7O$uPuJFcIH&Iz^qA=tF3) z+}&ctE6gfLuV~r{O;V0kcYr@nS<5PUW0x_IVydARG(CLJ2EU*v5Z!EQ_c7TfzOpH; zQm~6?_vHtBlVTvq1JzSLqGi8PM0Sfas2?4EHtj}RpGk~GHIKrBfO9m#9sS!s(7F`4 z+dnT~jd%^x-i^}^1RVOU_}>ljk0u+qv}<)-PuGzlT-uK1gieR}-6{Op1Or@BguIXP z7g4odDSnSUltz~oaeby^NyzO9>|bCWd=S6*Ia=fFJfFJFE|9!#YUS0Fj~CH&x(2b! zv30iZRPWkdvgm3<%WbTtKG?`vUBOEgy%MtrhP<~4IWXF2KNdhd_sK9}dDs-@iTASK z<}^Tk9c$STdbW8cR^@_rtE{d{TTdNt94IEWoCu%qTdpbM=(pf_d-=!osnq3bVj%(m zPajK~v2Vrg!Qp*v+r!;qn)`@Q*^h^Ed9hCiZfU=u?`8~>>Xsgn&B@$op!SH!q3EM$ z9k!ira6g=IgUWz})WVE7gfz)G5|`aSV>S~88EI}V4%6htcGYDw9^LZiW~PH1MKJ~r z0kk_52Ncwnu#@*mvz1Kt>1DPshxFP&w3HLW4#$hXp)>j*0Z^ZZj4g5MI9`(YTgQQh zS_7OLS?$9mX+U2i!*-ZhSq*Ro^c*QNv|AjcBv&8`g*TGHMtA5!mSfUJ3O5c_`s5zi z!Qqh|HDH+vgiTe+{!~EK5OYHtp1)VtH_G&e=tktAh|N0Fs2_1PZeaOy@RsfXG$7!ssN)q$d zEf`r|2W3l2qm2u`s?Ad}sgL^t9jq-u_J#)hfotlCIeR$92sOMxNV8~neFzYM3IOqb z;e1myok#Hpry06MwV`TUQdVx-SCTYUgx=)MiJ+!55w%|JRoT9~6>i79e zOzuV7)&SD@Lip+`@4@FPD(~`%&%@0Mcjw(gC+DH>%&$hSG$YRp(VMx^)Wh46!{o#J zgTqvldxS}9mP?1;{Zi+R7xLW%NX>)7!`xMzW9DPuVD6BNd{SOBegJ_65)?Q4SP2iO z$+zLGhbnS^(%K-?!Sfvr<#?7}g4CR!fQ+1(SvX^r}^Zr@@>kl7bXNdU;q?ASH=7vxw;qu2^ouJKQr{ zVh6=%RE&Sqw|xgJ)1-}uDDnJt0mM;rG`j`+1a&QE@_IFall|6gIM^p=nm@Efnh#mU znQd(8#Q)x9?K8t|td>0A9UP*~0|A!~o#zgZ=;=qlSnZGdtj?>flXZ#v^~V;)&NIbE zU5<@MTvfT~2IF-58%{o0cfVV=*?4olpXAkXnsYMwh@jn;eYOUc4g&YSW$x&7u~ zZW)jMCcpd`AqM_IX`g)u6ZVVt!vMrg(A^B;Hy-zpRp5qvpv-@eUG0yxr~k5==w<2u1zmZe+2mrfhi;3;4+H9LU-zGw50R-RmWd#08fprw>!S9M4$dq-N(t|7wM#>`?ynPB5!c9zboh z(CH*yaQT^x?e27m)(E6?oOv#GbVnrkmq2G+#~+~uk(r&JdkA?@KNCP1ZwSd(?Kpbf z0hcLKM(2*a^o6_SrmO3RmcT+*S;;NDC&B4+7fj<6Q zl6a;@r@avTnLueCYXjK*1PkD-FD_!oltLY!a;-F)%c*5!%XBU9Fn^KvIKR(CZ61l1J(ckay zfZtL`WS}l zAX~SfajLWNLp^Mn zCtcc^=qze_I?uJ17$hPB!0=?am!iPn(QVvj7F^i6YABxnm#Ldt9;V~zyT)&yA<7wN zexZ-`FZ>TS`E^+YFA68f3N(%S;brL0{88buaP;2ghtE@0FWgSysrO<8&m`&;;psyO zTOp09pl`^g|{=B*h7tuKE=2xWk z--Txb&u<{hFUg$}r^#M8Ti9fnwE)!f3&_euHw&r{L*%Dgux#CEi#;RyJ}|XV>w~W7 zYaN-&9f+?>vET-1DJ{6WhkIKi976P-S?NQcOL4JrO)#mK1@#(R7B|>+O}oylJi9i( zqdq%Zfizl+PE->fvT3q3?T{}~D(+9WLUQF(>&Dj2_k_n9;1q8+8Gu)0!8QSXm)o6} z6jwa)aaWKA_R$hC@WJ@zP{s37R>cC7r@s7{#qVglCDv9*d02q$p4H zszy>H%`9K}bo|sjj_?Q^eewE{UBG(sY^KUWHj$nvitXNdgHzPu9W%N1&&$9AJ6d=M;9(H8I2HrNt2C?aI1SHKuck@3bzoec%x<6ymBn zmsU;eDZ!2Uskgwd9`IVYwwEFqc4q1*T$m?|W3Za|Zs!ZdV@*EpIeN_70uRO_@=Z?N zViLVAy0gi;9lu19VgWaf{)4|Qq$&3O#jsNHxYACnaxGKoNpvPU*oWdEv^rq*!4D_F z7uh_fkp?wN*4I`2dNNK%6hZG+&~xJKKdCd;)8A#KramE33Z5!bf%R|)^F zHPEPE9L1(Y z$ji2iVEPtX!OF1BXW{zm>VOX~hP0&&950*uyxPFd@IiDn&E3~}Qmagxr@~W{-~=ox zfGdOL9i~>HHg>qx*E5sqEm;#|J;vlZscg?$Yqnf}F1~Q##5a(?Hk^dO9$eKa;1ott zTV+5s?>FNsGYY=GSvk(8wHJdoHTzyU_=a-7)#E=B@ALo}_h{h}N)bZEMd!KhTEZ3+ zJqD-SSRLhQ3QzWSe(+tHrWud*jGPp3@|#nL!nN_X)gSUh9JabLCBH$BZ*kW9JCN5g zzFp5X#5Z}m(}(#3cI&X{=LAtPK82Y2bCB=+f5YMf^9ir?Hm*>Hayx}qtMk3r99ME+ zxwjbgPr4R|j(U9^E1Rwv@C6@FiJ<8GaIu`fW-1yYKz#ASSyuN)?rYrVyq1_XFUA*n zXY}fK&ou-Rnv{CR`FM(Rf<1W(Ynhikgc$qccfKKNMl%WBKfkbT@Gv2>#A)X=Rgbkf zT1e=_Gueps3?5lX)Cs|5&hHMFz!1b!;5{PxOe^Q-Uz8kRzoQDoL#$NSp=;3tDTph` zpW146)1ux0)tK?>d2f!uN(pJQ@I{AXTePQ`{y&t5HY0HfpS8F+P)iW~4TyS8d+4`b zUf1xRvAB^mjDx~JLV7b+-Phja)a)AU?Q^Fb!rI`&#+|zE_(r5TcDLa;kX;ZK>@bgA zjY8YvJDB3h%aFjM?H5z{$Ey})HsX9;JjRs$ORHbx*SMmHm=0tD1-Ug8;vXz>&(x^1 zsro|jB18sa&7o3w;PQ2I*S`&l;aeRe-!5rKpxjuOdu7feBRQ$)?oW)6Cflaz$P&~J z5e41gcA$5Pr}%DdM4i9ZatU%c61GBS8yz}z>eRwiH1o$<4^@;NCy=OtsoEs17AKp& zOkyEawXR!}8*`oS#9kDhU{KjVSbC`axq^YytFZ6domjT=P}{?PCpDWGsfc{__3YW& zGd(!mHAUG%SQ;J@i?=>L$han;?9xn`?~mM;V$Zjez1BhsCNM)JC~i zJTPYDAzU~U@oD82lJrQ2%X;l*T;(e44tA~FR#SbY#e|_U6~c4g6})9|WbC_^wiC_m z=`5rtK%8`cd1hXqsrH~7fErEW{+-uRtZIo4U?)TC*P~Y;CZ62c@niC)>l%2>uS7Y! ze9J$|cY5P@LIOa5;1F~tm=qM$7s{E&)m#8Cn$N{Ycr#J!dS(w(yC3xNDb#O9AK@8)unM!3NXdK{~o=vf<*+!!+zNX9^@&! zE8f-Jy7HLgtZ$<6n_lk%@SaNS_&P+u60_ooC}O2n>Sh{m!+4tUef}N_`dJY##zjaz zVjlJ1y)H?joa;+ZvYdtBImH!jez3zo6yKMql7Lsfcy039uH(tA)0?@W`w~x#Wln5ss%)fWpt%*6u zA8&ar9AxLM$zl!rIdXN#Z!(X~?sQ~sUI&YfB_0k`E{SaoH+O{lOS{B-l-9DJ=s=W& z7N!Q*b{w_tDFkzJ=nxrHO`?{p$tqG3j46ZBmvv7w*-TnxC8}R{!9)tBfKL#eZ-eF* zm3_yR$XRJWQ`6-s=R_JNoUq`ZH1SPoVdEe0&!y)2 zH+!>zfldkU^cFStd~@8>sliL?b$k~< z7Q!EcZ!nNYZ0OWl1aOD4&%GbvZN71|c{TLP9f}kYmlWmh*pMo0p3Hm`H_0@hH0gM>M z)3*Sge*f@uy?K@T&RL-^j?8hf(<8<=3mA`hg8FeAq+Xoutvy%K_DFdH?3P+NHU_k} z`I7$-d8*eftJ)!(m6A9rJfuq>iF(~pr z_v;_|k+T@Vhad?K%cK4~_Z+pvx#_*nc^i4Zqjg1u6D=}wmpEZKVM|dU-D^nvo@?0r znS05g$h{!PM=%YpVLBO8@9q3i*1_UOcwO*ns3ZKxU>6diuey)(7NPW=C@9~OXCgzA ztXO||@#)bK!M5Qgb+3%g0&12iP`l4r(fe1$5aWz(U2R@`dvNU(p@_dO898mCeL^m? z;}YAo%3!BH*J;80C^?_mNRxQ>jp^(Dm#0K}=3o5Cg=2Q0Ei#q{)icnH0EJ@I9WeTY&J1BJU*>GVb1@V7I1l)2P% z%5BE6;M)nWGs2h%=LiKMIdyPrEU{@>;dO5Bdm{^hG$}%^Ri2B?*KD;OlX>mpW?^^6 zP`+J#aT%n|-E>%|O|JNQ`kU2(Gt>N9fJxjvt|Yr86ELs2%f5uRIq!;609)Vs?O>td zt(cRd4Y+pg!cnt2PTebh;xTU1lT&$wy@E5sE=1}^qwIZmF)u~J1%zfq%VJIhi2w4I zO*Op{XdNbt%v7uq*Y$GToDav^fLMC6>|0@%KA(i4qX@z`Q@K;UHbx67K+B{JxwT|3 z!GlP*tbAi*B<8SKS8>{dq3c>miSm(4%{!VO;Bt9#>{VY|>B-HJe_8UYZ&7r!Z7~$T z2qkmn+A*S%fXl5OUF*?T_46onkp(C>WS=H38EeI1Lmm?}i=F8cx%e0R?_qQ!l#-VE zSes(uOlP2bpMq>j?ou9sy-XN&B&M^BJ|8pof-ncsOtxP99%k4Oqda1Ydq^l}D{t%r zCMxzkoA;{(Au?ipgu`(O?Scc}B44xp>esc%!`+5zj|K-I7%{;rvkZ zj&HG2c#bbba|S{(_`vP8`@M*1$YJua|M&Z$I3wFD$E+EB8=S|z4)5<8K*GEfGJG(T z8SeRp-_T<(BZ97{O(ngE;ejk#jk*{( zZolQyanYi8Bk9f1;;}Af36G#bdJ_8k9Fi}lPUC)@ZChLk;FpVi_}Sjr(l(@s=7r5> ztHuEoQj`D{s;k^|+v5qJ&5@+GY;vNz4ku0HZ#4b1W}(^P|N5IHU|ol*9W8I+gz(?3 zspPQSut*CGG@GZ*d=4u#9sbR@X6sUb@o}yX5BRnw8gh0!q-rbtOxxw>!gkqZ)8oRql@AN zfW*-x5|s_j$g5`y&7iFz8JvQcZsN42)qH7bV05EJ*ku=>zt9jB@h+!r>E*EeC~*L1!g6Y_Pvm+&%!xRt0@&&?ysRlV2x(k_SJ%CG zb7X3bl@uY^0b_rDrNN+WvJJiNDn@%Cq0eX^P&4R6y4=JV!RilMw-mS;in&~HAqae~ z`)A|K@xb`c_Yq|&>V3k<*-e^)M+*2?j&?CXrL9KG`(X^pd0vF=j$a@e{@uD`6Glr#&M1m<ZSY5xw(vZXXVB7`fdU*zM z`jp2%$LVLg6PG_rKT7VG+||63mNQhEDh4h2#~*bJnV4fXe90qSLheo%#GBO%Rs}NQ zX(D~-i91+SAI{&zez&Lr{rpkorY+FCiVUW1AMPT+<&XGwTXpUwT*kNp3pT@kjY?`6 zHXHl|2ybS0sd!Gwa^_lV)|V8^k0Ba`117995RPK&0Tf<*k82eyDPy0b>ggDp`*N4& zJU|hU?MMgplp7xW!AoT4RKRB%B8doo|Mb^=RrI3&QiqaxMI>!YK)@aPaWCpHyf3d9;&0(Gq(`7p>15iRTJJ zXD{eZ_OEl5iq7$@`!qh?$lpzFS+ZZM$U5LppETznis;N2mj1)1Rd#ek_{BnM%JC7p zx3id^fNCo7&Z%70DlWf3%q>u$YOTCjS0SP+9Rp>FdFe3SWOv1w z^S>7!(vqoX_Qw_!9`oGz#xG~jn`bcoq^jD4WFQp%=A~wyxU~aiOaZ@~ACXX5c|Z1W z6TV7vkF=!GZGA0^6hSO9&)qzph*BeYl%5AY%K)Xff}n)GZ>simtK6l*Q2g zXY)(sb5vV;6*&XAT%W?G#v=ZuZ!YiDU5|g5$orV<=`FQ+7Hpe#G#uD-A5%HacutR; z5^c07im>;XD8?tgePj!yk$c(Wc&KzQEJBSq{=n9=4>Wtm@uLf&|2U$yDsuSvKz7&v zL)lq|MfF9GnvjwbkrEjYlx_qhhLD!-9*{;-xuh%f3PmOjjck>lVa1 zfnvaG#Bx=SVi9-7|Bd3`TmgF|uCA)`(6>sL2;_OZdCKxkIx*OF@=K@{gWfn?SF#{S z=!2uFaP)=kKX>%9%=I59=IbNVZ)fFvBkvMH3%ihRZvSWRzm9F!%Oj$Vd(Py_yLSDX z45~|$T_u(+#R<{H$OB*~EX&{|^NO_%e6q;R!qHatBRzBaH9pbvf$P)y)Nkl!_>e*v4qARd;kIhOvRh3zg}bNounSQo=a==vGzcbm@Gu|M>-=E7YHye`s{>$$@d$7p|gd`V%nRH9)~yQA|eKbGS0I>aB=ae{la zib%n(X<)BogoYG-v#;!#e5+V%K3+~rN808bSypi*h}k=_Sn64IK_@eW?N5yS79Gxr8&7w2+%3N8H_PNzi1;2gaz&L!i3A|z`z z5Av=S-eyvcZyXbp|Ag&?nAIk`l)#3sRe}%|20IUz-TtnRB()w=y}O&#kF7pym%h1K zK4*jf5k^RgW9W0Ld&ef#8Iq$@Q4+Z}6S(~Ayp7DZUEYO|5U}uKqCT&BcD13rbHYl; zPS3QL|482^`1~BtNYs3;5u4#8X}GvgR%=XxgPeWO89o)6wQUUXWD?0qv*IyDz|{KABi{jW}yeL8vZ*;44h*VEZZPPXp5u7Dc_Wj>C$(pd|R_0vD}LvA5a zr%=FbAkB<}eQTRw7dhtu zXy&mz&|VMoM$qD%%`olG#E%&S%}G%`;Xx^ovL4|K`{~!uppAQv0LB?!Q5MM86S$z% z{d70g*U>G`WG}QE6|#R7W%HJOmw1xWE(G-!AO^v*o=06D44n;S?GUH9#h{_B<|166Y~1>9DJ!!ky$UoA z9tm@J z19vh&aG5Db{>pbdOgmhu61k!MKHfcTi}5Axy{O1y?|R}q^TcBS)HASQVL`gp;Z%}x z&UbLAkxhE0ubt!PF1jC*y~7Bw;R(X%lDR$Au#_)4Lzg4t(fzji$mBs6RKR zkvjqE?YB1;XL&6=N>{76?tS?&d%_as34!?!5hOG6`R00zoUp-vkqAP9jPM50S%r4z zXZ!B^3!mdBlB{3kqQ1fZ@xkX1ndwfVv~LwhVhpug+`GB{e!b^UWBWDj_Kf5b|JrzQIfFB748Dn2X zd8hoc9yH$FQ@f|dj=K>$W9<khYb-8u55*z~JkFuh?T9-2t=m&));(i2ne^H_8- zL${G1gO+O)n&Q|)&K@OaH&xsT$utYUn)WGrnBe-|2>t)yV#50gLXvs^9ZNrH!1aL4 zkacM`J@w5*=+@aVM=FQkY2<$|s-$Gh8v)wgEN3Ov-6)>1fy*P$aqppcI+-(G!<~V6 zx)PC=zfO@)Xu|dFWTDJGCY;BeOj~5$abzMR_>*e@`Y9j3zR0W zAF^o$a?V;;Qhl*@eW8LoqrWb@)_8S+@+Q*jkM_BK|D2atSyz|3TQ+JCk;^+6G;{UA z2KJ-J0o|vbusYA$uq%^!d4sM2t=`r$;5t8hDtvUM&1WvXJ4it=A9X!*6;AKD!;{Oz zkn7|0?Y?1{eK_~&j}1M|!csq2=~hK$O#+e|I!F`IHgrwyfEROY^CMF1xEGj*lAPo< ziAPD}!lLYAi*EpLWlaK@WLD+-A;tvnps$8(1_%p1T*Pd>nfIlZNKVoAB2>AgEA?Vl zKTQy^T9}ZFR^wXWsVGg-Z&6;Qc~08=QxQM@YT!y;!8(9OiaF~2R$BD8*Il^;>FTk- zevmQk%;AKWC*L94^VXBSv(=v^JgQn0!(;WJ?Q& zLi9rOI#@>(UeL#tY13TVj1hXDb;Ae5juR*N+b;k*jRsR$btbH+2Vm#o0;kembgK`T zKq%}88(s(fCCse(~8e&M645BR0OuX81Cl?x&yUl#7-tbrWPdc176 zzYYLOGaQhfP(Pkh599Oyr5X1ebIvfQeuBi2P&s?<^@ydU+3lNu(fq4ANpfq`ZQ_+t zt~Dx>|Ghq$_7J8=WQY^#$EBB2df#tMzeu9*_U~>yxP37vRgodo#^a&`lYq_0kk-WMbWcUcn_c6 zIp5&?Wd*p>bGdz$%QM9Qtfb=FkCC?Y0BdHCaS7a|N(jZFvz9();X2qmOW z=`(p-n(GG%3(Im}^>jLHo*zP@?J2`gfgNxXfHeR-_8d3Z$*`$mx_TOWLf_QK0@1Oy z)_a5cx)nU=2?q7m=bC@H!j5;|q%l`wm`K6;G>q18K95aL6*IO6ec6FjRbzB&=OpuH zEL%9-x+VTtFUI(;cj<(g(X@;U|De`m zkA5Mmi~r*5e;`-)Rb+Qu_icN3VoS$1+u2XDE)_qxjQ@wAc1z(+3S{{8`)>_T%)Kk> zxIc7Ao$tD6?wdQs1)ZQFgUBjftskOt8(G4TWZ=1-d=?+;Bgx(gpYp_)x4zb*V0kV# zA2g$?L^2!FK;S3+6Hivv|9a7@RyQU~PGhhqj$Nyhnzd@FpoJ3r>5#L+FQI|ZaleI8 zM)0TJUZ-DUk2z%CNvBM-ogR~#BlBf`)R;YIzr6nqevKzeEL+m#dL%^ehi~Mj*1!+e zAhN~MOPvj^X3J96&7i|~d~z)si$0RR)e;EkIjI4MN5VJxE{4z74-$$^<3B$G&}gd) z`}@&HL8PhIQclcZj<|;0#dz8a z-Qflw**SGsThVc0mn}fUO>vHnFmCfc2_bX6Kux*^RA~3ZJfWk$4tuIv7+)i1^nRkb z9Q@8Rr6jlP9K17slW#+n{k=3Fp9(p^EuD%r9cQ20p19&H=dpMsUmuLo`XB6v1ifkv zki{Zr|KXNMo^+T*+aTTum5%l-tzTGr^=7VRNFH?d^19FHPU`x?;nA(_23EQKme6y+ z3;#EUSoe)&5b2Hwd0xX+WYwEcOcb4xK3s-&Jq2b^e!g*qK2U(UQm&#UnMiD1m#$hH z;*h=n#Zr6flKEGF`4V59)jMsWW3i}V82PFr{YGU{qoZaP_?}U~b6((N6 zWNuq`U+cJSUmRJnf>y?i`4SUkDWRa2@3v%j`pTF%xs^D^2#K3@&HM{xz;2Oe!ZzjX^`~=kKw;0 zihp7HW`zq`!USYS!pIeWFS|Q6NEvcF@Ii3Y<7Xb6l=*9qEgTVVBxv3>qjG4h2!BKC z@Q<3AO#F0iBpJU<^5WAvsnpLvw(yqF2E+bOPz`txx~i7>uZDxJ)_Y*H>ZNjwMz9de zjCcMGcQXeY9!^t-T=|s7n}Y|s+Slm&AD~5EN_*GuD$oA)aD}feXpa%~dR3meUt6{e z*%>VxS>UC*UQl;P+26wgH7Qek9oKW#;`F<`oEGP{cOB2T!ds3ieTTSa!9}-*U~o4z zZt=1B@;uTvwnE>eZV2$)dWb;k%Dz69+$Jvy$57pL&ZO>D##4jeLN)Hah^<+czS}1r zjmI4T!?Kz*SQiuK_{CQKIt+^lT30q1*~T7Oj)>S$?A^MEJ}V17j8xI8RV?>S>zj9u zh$g<+{e%c&&)n%|FSVoj&OZEY?dFDm>s<7l`iXyLj&(kKEBFOjfRN9q9HK+X?PozK zYy~LC69oU9{0(^{xLUxDO22-~Y-kb}b_}RmqAli`f_TPgoSPo13%+tv33b62CmqK8 z`mlt`B~!9Sol^6@r-(XEtSduV1p@UC&QZ~78Fs3Y^}r|7lumQ~y2v_rihZbM)bfYS zy!bdp*oMG*HHS*eD_9SJ&Zx^#_(-Zk+HG@h?a!E#Qgb7Yn&mEj;O=A7S=klS+_`;> zDPiHhXIXF({ARyYFsJ+Upm$?XghN(Wt48XhKdA6pbLm++3IqQMjgp8ASUop-c46@^K{Yvsz0ei^Y22jt3{_9oAMbc=0Y z*sK|@k^lr0r;}h-yqWedxB@6I=W*?n=f#;h4PCYp+t!y~^>Dd02rWkX| zTJ?cayr%A4c>WuTVbx-`60P6G46+EJDET(r^?orLJ5z&|`JNEeZd%+@mkD1r6wE%t z@mNBEILE7|l=_I?pP0qwdU+~fLaxsozZ8h=^% zemWt$CcjgMCTKBDN16hKC-u_!kQ~igN9@eOY<#?rl z=?R$BXt?wpRYFx#_RmIBg)y|HERoGDOXK1U!jsNDx&odXtgpu*!iqQBm$W|YW`Jjm zUqtIJ-gOam+2r)`8e)-uAx$1t%wnNcyT-FwO^4*;1z!A_ZMC{D_hZ!lY!s003?ojC zH9jvb+a2k9Vy)~GMuOAKh(|^;xWr2bDu-OpCIVvE3NpwZnsYE`W}NP-{G5_VP#j@8 z^N<@2e-I*AZs27$M7tDAOc!NdPodg|O(0nqjkKvyDwIRb!XtfJMj$0;-|Q1JD35Zp z_INiq!H0dQlGWhtxOM8>AdL9<_6@Ar2;U>(2I^OK>>cR=`9pdqP&D52&m@-S?Xcx$ z)&2`#762x-)+#zFupRHfd02+NqK5-DjqS4-j_c_k&zLB!Ye4scel2rhucOShkN`3d zhI2+gq(Nt@6fUKoatAZ2+NZ0R_-VrG$d;{pF&2^J?D_1KS-rUKhl&fAs0r#9(HAHV z^3-!RT2xxy6SEV9`v_KYAb5}Mpt_I6Gd}6<@AHUoe{-@jcRH5I29`>oo`@Yf)PYN+ z((PGGR(`0MfZOP63DS=+Tii1{Xx{F3zmMMs8xDT8&u4Jx#F%$X@CiSBG-4GhYzWVx zcc5La2yIXhibtkoQxSpIJRx`n)G9K*idgH6^V5?shAq3(U;9-KTwc^6&KraS8z4%7~w^NzY*c^W=Q7(}!B~ zxA%G>8t*H{%N3^RMD0lT*}9re@`Ao7Pg<`Ak40!t3HVz2r~!RmtE>?_Da*uUyxd~~ z-4YFfbqPLn0^XmiIX%CQzihNGWd8*?8C>@K(jEnlH^@Qd3`^rV(Yo*Cu`)sa%t94&R*T!BEeFJ)RHM-e)e>oX7W53ddDh#E-CSH0)ZLd+48dpo>1r@fb|g29Hsv@zd_CTLVnp!U ztkFSNm&k5Zq5HV4{<>RU|43!O3oG~gKO3coFOI$4(#>o{R!vfDad!hA7#s=BJ&Ig& zJ|`;$qCAWH$!oQ_2({67qg%2GUKN$pkV2WOf-23*ecRb2bKUGi(LxI)!J*Fk!KJ3RxW&c}$#M3!J>K{nP zo`APi+*RZE?d_S^C-pv_nMcRBvK@^v4PIRQo62@?Q+&f4T<#-EU){f|a=L-&m7S%F zvkCFM^!qJ=`^&RpU%J%-BTLIDUvw&OC}S8xZJ7JxoYbQwAPL-Jmbn+|;%hPOWivNj zE2Zb}dmw?8_<9|>�W*dpm=LOYt}`pM|5y9mMBrc-by1@W{3@^6mS0pFW|1=S#Dy)-Lf(MU?VOcf1pFWjGG5eLw=nOBxKSI|jjgJWYVf)& zWVc!D5^}TR4>59BF?HI38_m*NbZ3;RQx6VLOht9&3)wJOZ0SREd@8sDu|5GW8nK=v zXDS?=MD;DUUQq&uYg0;f|2%LP>%@v|IwQ%3yK;Nm|Jx5hdFIV<{w z#02)SQI@0$)AkI1SMWfHmMA}~RO~x^5oHDj8z{S}3b&28NUJFH1U!t~;ha+t9pzJb z+*t`6s+;J}p;^;&V(CU1UF1j0jrL@}?`CB1MeUv|zXE*ju2?3`%YqUT-96_h4bSnV zznNZFf@+)^cj?rM60Cie8C7pttHY``nk%r#i+tubhlWMCg zX7t1Sd*A-$3y(b zf%`aodw1xlJ{$yc9!6X=TI1rMgqnNbWz9dX{yl|hb@iMq8+OGFD9tNgtGF4ace+}K z)JXs~6Jc6C&-xm=*b5uQ zknk|Na%ik6<65(&l$kh_89TSqZ}Q|Z)py;EOi~LYI5LZV?%H?>YmC`2n3JwUcCzYZ z{_0IaD=hanUH9b+j{=b^vG50ZQI`H>*v9Sa$WSd8A7(ZmPE!{6?v#ivtt#G0T> zR2$Rgg=YvyIfF%WFOR}K_4U9@m6*9eRG1lEe_rjo?^WiH)|uw#4EHOv_pil5n(J%~ z&&j1-jRxn>u@4p2AG9=X;`$hu)mZK7$=A}h`^h!H)V6VKH7~*YZ*VL5Sf|pgf%T%l zF52G^*Gj#{-MhtTVnKLb5H-xGE;?qQ_jz;YA3``1x&$bx<%Bei^v>mqn$%NHC8#TR zJpsomE$T%FwLg!3ET_-W`Oa@ocSIGjTBIVf7M|1I79CVpw|+h}rY;rKEB&;)E#-r4 zC!gXLzx2$RrB<$?0Z1=e!H0n`)DZZaGY{butvalnP+jRihEQK{K9xjF#R#ardf3Xz z5$jWTRHO8x1-3DRwj3&Q>2(t{XYg6#imB8xeuT>;C8Ns*Hx#NRa#UcxlS%R*U4LKU zCPrb{k5+YKQWF{@3C$<7pCKYkE?U-NbzLp(Dy{F4!td|j82vL60cswLhc}9?pmCzb z4jmZ>@-DxW_oLmOUM{%7>}E)p1)ann?O#Y1+D;mMHISOE+$!e|7Ov*6Cl-9n%TD&K zb%`V&F0aHk5B*@$Qm@N=woWOEaJFl`(lC)0 zLTGD*>JrJaom|3eNzL~kG}4J(bb_i4Ux=5hMg;~pKNEteaPswny?pg*MfdI0k9E9! zt*@_0$LD~^q^N6jkMn24nJ;5ms|y)*;-LS&xL*A;p`3B`?Pes__SZi?bfRM`55&m~ zi^3YVdUaM0G>HB*4>G|TnRc}y*tZSo`XjR0{FU|1iq4;2X8z*EYWHGja4-TD?Gp=K zUybM8^PD0D!WY#y>3`3|>i<-?ug>pr#=TgFSWaI7e$n{)+7VSo>Kk5zGG!(%3L<|O z*Ocj1K5}J-_$GVka1_a8v}39-bJ@P~HT=rYA}W>p8yBag8Au%{GF14r+R;NHJ2H56 zUE39NY%8b>jNZY$Y;#(-%DX5r2pYYe);%IYk`oM8YNVq&b)|xi232}q#ZBG?<;T@i z{yc=V%jnJu-Q|;+LZ{(5Kvf}UX;ohb=mM@a7ihkqJK_6$vACSbR=X``pyoFDE$e4OpWf4}15yNhawckg2J9l#JI0mv&im8Mn!c!| z@!W)I4EiyS2cJ|X7*$%m;Vbc0U-|vN&P%%%EA^u^&b7EeS=P zLv0F1#1o%ZFyhDpJ$*qh?~jHyT{^DP%&SXZWq&LSUBNYP_NAs(VZp!90)hGzvVv3R zwDPze(BXr|bg8#zY@ZKjy}qp3O!;Q!G`a9t<6i^n50rP7jh9Azz-G!LpX)|s35}Zo zX+O_8z2Hsl{OX#seQi^W-CGp+Liq6A+9-u08(fpv(&TR@&QtKO#6F3m7GWJd|!Xs=j0--YhB3;U{3+-rch2}>>9n`>vcty8?w z)_|XoXCLpl0=WDB@sv*L^QmSydKh(=x#`mD=%ayL<}!Ll{@I$)lKKiUK(uq)v;6e_ z8tV@@msN9#0@5c_3bQ`FzEYtnIU>O=IrW^@$g&~!7OoN~2!|dl;h+j_f8rGMG+$9Z6W-|{efj2B!$UOMSxdD$BeyKJ<)UHTWo zYu>aBFJsV=iwxzfsByrkoTt1@wriMODLe-$KHuC}OfZ^V%P*_D3|}k%q11{6cR7tf zbY|CK#O^9B0vd(l-PRBmq;3(f^Y}jWsN{o`F?l~<*K`9^>{Q1;t>AsiI`;G;YM=cr z#%Z&ubOS5`sIr}`?jP$cGKsj?7;rdBcJr7kT@Xx{9Jp1CFPI{qoxSS*n;#{35jr!a z9(8+;R6QnAF#v>gM{nDze5biLYO#!#D40O7rAC&Un6Q;x&fQ5B=i$ zhdp)_t$K``w0M6fD2{o51$RCr#=x9jA?16D5uCH7<7R_uP zj7@rRbISa-y!NdyzkjYqp5C-yb{`5Mv`OnstCIXVC5AWL4tATbwme+tR7+PXT2^Jbj`yB~=G_ zRX0D`pLLERb#5oNT@GT~FH|Ty&~?e3Nwlw>n=2WS>gCU0X=s@-kU?0-Aq0!*=F(h6 zBN`m!`xJDMC07+W^$lpm*=%-*euJ~S2+fp=$uF;@wWNypFN9as z?=otpNi-5Zb-G@@csiK+`r3W{(rRmCU_!Jqg_MS4=p1jgvhtW`Wk;cCwMsLNGU{U*~dh6XV~bWLHImhbKFRd_`37a;~% z-Dk}-6a0Go_w&=S&|VP+Kj+oUxkNi?{rsvzBsh_6N@gTQd>(u8@2ByCjLkxO7oEk8IXqrMAIry>0_Fz* zUWA{e5DyCw2ef46+ZVgmHc_e$hOy0y-u-ONZ8$c{1#Ftq%cz?IydS#~r)to9o=hKr zi@MOkeWORO#u23GNAh}utUK-Te*E!TH1c-bXNPC|DLwp@2LDfg^K{3@kGXG$354r5po6}@A4%155Cnf*wUqDi zKgbe!|FaK#ZWv;~0#G>_$ejNuqoXTW5`xD!o-R@mTSuL=d;NZxR4SqrG)bmT zrD6&1g8^)KeD@U5Y2UrUvJLY4ntHYWwFW+hTdCan@Y}X_(&3=>^EZ4@$C1cjx6EGA z3h7l515hppUc}I5PVnXpWIq>GyiWD zYFne}Bjz0EaA*VSy%*ze8m?Mt>3k-Lt(s+u-IAF5F}VOFnEc(JkJMEku&>EB1p~(o zu5D&{4=TS(5bjyCc~#%)*b_Vd-1ui+%*XW@AA0U6lRsB-r)R-9TA#_<*yz6}EQ?r) zpfVRkFfNr0+t9>prX771J*F71#MeOVCSxL|S5&C~j^*k`8WGlco#OT!q{_oF6b(qtHvdPwBPwAf8kIV2?;# z_J3!pwkJTguCoc7h5n1aU)hjfN)5B9`aW?Gd|e4p)zbf}YT!xp7n6LB*Fw8Y`F*Jb zSrQagEmCw$;sAGw-$g{{F4zq6!AOfi5#J|3deSyderN6M`#rn^p?gSM1QEntMZ8#< zxrH28y8|{dHc>lLs7k>UzIBtvn*^U3-k?0qBgV)3?nn10)zVh?UFsw4e;!6TWv>LJ z*G%Dm*f1pO;-$Jk1 z(NU7r+-8+^pHs2tXoM2GUPPcp6%j2?SHr1>&eR5d*LayOGOcst$u{E#E?(Odk)Ax? z=aYkI6W6BWU_hg}UH6D`^B=%4SKVH@Me;AZzh;R`N_a+cy`&w;6^1XtdNWc=0|L6eAFHO;r?K{IK}5r5tCMts--yO@C&RgL3Wl{##`Z z%%V98{aU|wd{9>@iBv74F;6M!=?{N;tS&--45QHc4!8J3{zZ1KOF>$Ox{)pGkPxdn^2a$y%#rk@+x1y$ch)$5 zj^|Fg(`Gb3srl5U7RCNSe%Qcvsu4T?ii`RKQY_|ce=GfN6652^*FeXD&75!zGro!{ zw1EKb9TO>TUF(D|F7r|A0hT2HO1-syhjA+gywHkdWU(=rzA1g+JUKhzR%?sUNrW&Q{}NWWlb7O z6!n0VP#&Se`aP^bm7K=_`nqwPMlJ9oBHO%uBjw*zp=@$C**~|wop&+On&U9-4Z?P6 zN!5;(>OC#vJRDbUWT*%G@J@3Kp51kp(y&il=V!5xSFujHw|`}j;R4BSUBk4yndgoCec8{E zB)JjNiL^Bt>*vDm{C^|A%&7i1`IU+!5&y?vMytlb4y`p$)1r_D$m;p!cGx{5F4)IW z7{2zz4Ghawg<5q(JN|yIuq9-iM$|?18AW|lzVs#oZ+DvPx0cpmG2-je$A$Z3L3(qG zDZlH^)c^tljR!ZZQ59ny>n$%Sx{b}?Q+BUu`bfwXeOj~{5V}>YIR?`xRIb%}C>Qn* zczHyuTIL;28KUR<*rajVbvMyI_M=2_QLSZfx#jmL42d0{7~2s@Gj2)6{IRnOtoRnV zIl42|V2^r1t`nn%NE}={G1cRr3*EWko6fDmp!BD>ph|M1Lh(b|rxKqmtp9$6B2gwJ z-re*@#79R2X$KoZQenKFlaZiz{x_xm%uih577~q%_rI@wZ1!1h@y#^w_!o>+VdY@~ zWpj{j&>`iAE#;vnQSD&v-C*uOaVm&e*?VdFX_JN|cmB`lnbV?qsyPsJ@||qJd-WXP ziKsMU%e|Q?-5O%4O?uMfIzfw5j|?^`jL%4$!aL^qU@H+3C6c`xK^cQi6nWW;c2_-8 z;%qs@x5lL6`t#t}xq`_lQ)aG-`Cm2#9noxQx+#Y- zE8};=iBAbry5YAKuv~bNXKcuTThW*?OG-q^!m%Gpfr0yR`=;Z#lMH9~^cVOwQm85j z(Z6EUy2a(4gIgq}Ks|J66vr;qGH|HB5d&(7yV#V{eD^D;a&`*B9?*`*G z_A2TV|Bm{M&cr4I6Z)Lj#Iqd7V&8&oE}#zW%uvnOvxD?N`(bwcRYSrS=xxZc{Sh8l z_5j4fzKwFmr^XVfS_Dy5hD~Q#@Kb`cc*xM9hd!vi2WhKR+2o0a|$`qoQ*-NRE z`-C@E2}oehDFBMMG}llybEpK_xnM7Hq6x24j(Ctgl-MOoF>O$e9{iL%k78W;ru{{7 z6q_bJqP7gukByDKTt>R;qI{|Qb$BYJ!SFyoW_S+fJ=rB?u*f$3J~*Pxr6|;Y=dF}J2LvibIrTD0n(P^r@We8c|Msr%UZP4nwT%!c( zuXeiCzDzw-@b#Wb`JsQY-6eU;_UEF=Jbl}s`UW_w%2#?Qx`=kDJZm(YR(9(NVlY(U z`JVW#@*v!0=z(_kfl)F zbz+42c7&_sZPC`6iU_8@0N%USf2dh1Dt+23~Y zI{U;D1&int^>mnpS3x#acv#x6>9tNVJ)vpo9=q9Ec4SDL#qn1vvK&x4p*PDg^((Ri zh18aP9$Q4H@#sUQU*+ivak{o#GmBfRRu7H*TW(cG14WL{2*B*SFVqTSZdDc`TY+Gz zlGV0t9^LZ?4PB6%(*&{y*ITOQ$SN?3Ui#}lU(>_O8iHwEbD05i035 zUdu|IxG~wjreig?z+m#($_9ZYc?ygR$&*ugM1p*jy1kereGT_ssDrIQ9d z=l=I}wWNGlx**3eCl$-ebp7^9!Dw8Xy__*=FBB6Gt^IEbxCHr^z=3Dq% zx*6@?xiVkbkVL3J2*(#eJ&iZ|Uo1?U`Vq?BaZh|yxtt1{V2bnfvqX!R??Zo)rUGP? zNV^7qbNhrScpZ(R*=V)6qTrnSyk=_O++vf}QAz}dg8-P_78WMZB$fa|ntY~O37Kh7 z_^K}d5Vp(tK`@5Eu(zSI&1(p6uA12;p4jBGJr?>d08rRqLbgX!y*RnM(v0TnWUL=8 zZsf8mAU~D$aRb%Vgwn-NXLB$tP>c7NnWj{?F(Bk*Zr4FoiPw^I{gYAFP2R5~Tuq%g z!hND8+j#*P;3psNQiC>9(Uwj7L5z$3nc6WL=X?NArg(QF1S|^8_ma=e*{>4K{5;aJ zo4k^Q9>^+-@KuM5V6=Hna*8e5hQgYYM{*@sz~zmMJWJ!C-VL?gyZn1z65IH*4?>%R zI&^7!?EEBo(2C5liMs3UYm@k?KR{XvfymTrU*=JSI8GhrFN>*r=}!f>ve8&|`mW&$ zHoJ8G7q+5&fBx&ook^2DXl4F4O`@J2pA{nY`;~`)LwlI?G?1wNA7eE(2RrOA*QZrb zmaQ;;g&A!2J)>u@>;s4Gaf5w*XO6}a^DRl?u}S0`I6F9_nAOxmGHL8;tE`O#oya!k zWKn$yLfvGA0sv_!^I(@NLXKH2-{ezMFglV-{so_civ+0N`R2w_aMO&0MU-?8<-v7OM zwBg(S-`$dgH|}Onb+XpdMH11OidoX6UoQT+xxhe@#V#&{{SLGnCdQh+_Bn;7tc#>! z0nVIaPW1~k6!*JmKgO^>CLc!hm_mhD>;&(rNc9_y@bzsidL$R|*lBX!gm!1v^DODJ zy~*B@Ap0Z_cq`cNZDsB74N43Fk86M09W>h-l~Ts)=--i!^}zd~yZ&W1-NS*vl}faC zUz%EPxz_?n|NQ%-@TD=k!jPLg3X=g@gel|RFZd+^FDr^D^kY8&S(xb_$ZT0$tFM|; zFy|RtVS8L;q5Cq(A-VZ8K|nG-vXA}dK3cCV{6oe(544iiLSwQKW0eSwKrtYnUkw(D zrPgI!xuEC`086>EyjvguujeiS?1YZuw-FVXm9@B- z(pP?T)WPwe?er@cXtzpYx$vTrsp-FSnr9W4eW+_m<%ov-0|20_1w3$W#Ie^SVkW9j z_T$pL?Dp5Jd0!r!xQx1fTaGXx{~<-h>K3o+r%!&r4Bm+;R3C#Ix3B?|KPssj>{CO5 z!s8$PATFC;w=vkzlQLecoU4R!z7*TA7U*_EJIa5*DqL+t5`dxGNv2_rd!7RJV_tss z+&}rys?NwR(PkNEA~fV9OkS8;RQ9Q(6&1`iA>WM#-;5a%`N`sdjsgPqnD)&i_& zyDGKnW?pq}h=DWG1*Wk=Iw3QA4k6WsW=+Er3+_54WqtZ4_rsu@oWqajB^Bcy4Y$}X z-aQHqYt3+2wNU&BYbI8ezL&yGH!e20Im_esG#j+z!R?m=U|Z?sNFsO@KKsH6bd#0* zAn#xbo~$R|s%N|&Os0`c9EMR@tgUQB zSAMzC=7Tab85LwMp>Cx_c_PwCX<+cBOM2vi7oChzY-x;JmemF@bLAFzVt!j;r)91T z&u5>}zArwsFfK;V)3K|I88mAi_K5S&S^Hk(vi(A6m!sqC_bor@DHP_se@Dhm_w#G*$t!etI&cTWmu#v#1Fk zV(!<)-S~TZvO7N%mpTRlO{d55nmM&1RW*e1s1nbA+jUil%1uY+(r~}2@ZM3jt2G0{ zCCG*u5*b7X8XdD}V}R^)wx@613R?W(v=!n%+;%WLW;+&lU2tv)s85(c&*Xa(#4du}SRS&lgd1QM*glx51Rf-6!Ab499n%;x@AyBdCKk3?wSJN`u-rG` zZ%kq1E|5*E3Tq@Tn{d{0z8x;iUT_&3^xj$w}#vihv<~p8NzU|1&`8&gjVkX>2o*S zsCW^!b=^n5k%#srj5m>FLJGF_)D1WjD2~Cx=ro-D)=E=S>?&tJ2Nre6PjNVp2Q?vm zSso5@=}Ii17q z^h9FJaVR{d{YKVRqbnKsHF>%J!L5Ei1!;cqp|I+`rixEv%X_cDt{0`2y|rKhRZKL< z`?as_HbmOHoA4i+2>8Yr_#2Udrjx5c!^FfP_r(ueh-FhW*jKk?L2!bm@t63k<$3HG ztKipf8gDh*!9%CkQfpD}&2?WNyD>VxDWvlR_W|s3b22}*$%_DG$Q!C&p?KuwnI1HZ zDe0c01~Sq`hYHpPGjCyMjbEHANlOdTg>>rp_q13#D}QJhLv)TZ|wj? zPn*7ZtM|^2f#+{f*1OUgH zqENN0ufkUGY-j{4FN__7eN_+`H}DwVILy;OdM&BQeGvYnk`$SJlkXd=vETKyz3d<@ zq0S2Rn-bKFzx$aNZ{2&sW`OcD1p=-Gr;F`;fsip=JFhIh0S*Nq&(N5vUSJY?!!#}< zY9Qrivwhq9(Xk1tSWgid`nmLe295ps(qw0z*5p@KiU5d^%0)sj5sUfzOflch^%ezM zHrByoaZrWKK5Z@6h(kfk_$F@sQ65*Xtdup10TwVEJxLj{0H6-%%J~8*;__M`Nof%gn$Bqh?EE_NSD$zAOa%NlEY8}Lxq^I-O@u#cMmD>pZV^d-|oKH|DJv4;rL>BnCE_;bAPV;x+Vhg^$Mz{fpnKP z&*B$ezHM@u?VS^-_WM&GES1MR{fozA-SM=(-Y5Fh&=$&fiQ4{f&!S(lX=fzJqNb80 zT?}MiQ>F|X-%BS5(LY0sXY~w-``PV#4)!Wok~S5Xz4$cCk$f$WQ&5nG&=r3EU&a=f z^KDFYXCiKv9QC1wt5Cfi?7Zqjpq8bn)|LGcTLc>MfEP}>WP)73ckhKR4!i5~ohRN= zZ)tXd;iNDUr{U^aE7Ws`gtnDHobTghLyB4dIGzOYK{AyRV-=#gN`mBP>1Um|cRyy{ z)uk3PUJbZF~YKaVL__8azlWKI|7zbmd z8Yt7?A==2sC~ZkkJcus>0$Lq{i;a6m{9YjE=2H0Hzs_FM63-g0#3P6c_4&Ege){Pa zF;lKB6?|z-&OM4l*7y1b?M^xJ^GtA0vsNjJEqx`-SL$7@{Q6R60Oo1Rky42RinT3c z?+iVRBr4;n`}6#Cpcf8P>Slf|zyS-oW|MKP0Ah6NoeSdqEsj zNONjr+5XmVqY|n3164P``$W14Z1F3EmwWb|0DDoX12ks-%V{0c(b~p%oj6w*2&L`z zq#B64$yWrEOt-tIe2#`IQ^=U={X>uz?OC9Qp=EA|6>dlZKf`=$znPp?burK-GO@TN=R&ZTIXc%)@%NWq7{pIOu?pGD^J?oeYXK07zI>^T8 z&-^2Pvi#wYt{W}g!G2EWay!4hCt6ZIK(%YbGv_#M&;jk6u}G|G?FHd29&Pc5wPnH^q1k^3=UWILnce){*%qfhJZei{4;?CyAMh_~jL!*pllK;H z8|B1m6Wmw$B_Fb>lGAUr{<&&*59DvQYBL?> zZj|l9e`2Ok{n)}SNz11PrMvT_m>qg{g}L0IK%8-VRsolkx1FZuy))m)7`#VFMG5V{ z{Zd6ck{hpoYBs518P(I{kzP7Bni>L>qP7wtvn^F-4*_-%c{*GTw5MjVF;_Bk9o<+`DQ!eUWJzN@uy5qJsl0Rf$Ws4+QPZ^BTmJ= z<6pwRMbJwaYd_O{JF9o5ZO{hgMtdi0aXz)=o4Hu6^WhXlo!W3~q260?okaO>{~(u1 z1}bz8-<#-@3b&(in8<^3(--CwNIdqFJRT-?m^dKHoAr^=xha@=h3EVj4qUJIJS*II zGyNFwbmg8>XS2HVyF0rVElnd#jrbJX&`JDf1Q+^4M0*=h_-g5o)08ufQCgynrY4e? zXvsFG#yj*?@a>yxU=4C@!*qy{pSt6m<~-4Rv`>%htr*TySD|f_{5O2gohBl}(|5l~ zpVEMe`YQ=4ro+tks@|%|lJP`&f9825XJLD+6V9|H5y}#>Ig=2&R{L&nGC6%;IG z{(m?ht?4MXo$x5;B|g)EAY>nE+g&3mW>oiSd}H-5c*P6} zyHqTt=9PK=#;&R0n28dRRGMpS^KEJ(1`DH1Ocvw)1QUR?Oqx^VVZQNOR9RA4+eG(8 zb&AKY>iojR_%tOxlc|aO61iz_1xWo7_>5OCz^?v}>ovXNjov~Df>VCrsJsi6I@UYM zok?WxaAyBWv$f1bqeV?e`a*sqcx_QG%Jp$tP4i9B^ zTE^nnfdIl&eUDtrR5qILzQ`w^|3NxlJ~~BYqFmLa?Vls*hdUq5yiu=&wASZ1!ncolQW?S3wQ&D*c5 zoL*oQ4c>|=N8gL-Nh#A_Xhw7mrVKYmus|PSPwL2Nk57Yi#tbAyiH1EX1I1{$O0q)D zALyZK*}w&3BM`N(WT`GsAJjKU(y8xM5mZF74E3#+<|I-DK}igiczsl9+vo+9qP~}k zL4e_I@hY~5S^r9H`o2SbPU=Qu{6F$><(Z!i>==+&3zFRd1;LP^-JRMZiZ-3(cStuq znFxV`u^V2Ku7JnkE;?GqMs?)4q^Y=S(bmpSb_yz(uNAQQg6NO#AT>Z0d-F6#h=k_U zyax`uZ?G8kNkRF-R7a@jba6Y~pCfFdRe@CN(D1`r;Q-q+(6{8a1qiV6$xzIsu~b$> zazk^7*^@)@4#XC^_X~DGYOa_9*XJwXc42qc9J}E7O<(bTHwRE>mcLx)q+$qNu}z%BJ5A_ z2plJ(7*q89d9Ht2` zB5&19y;PaqwB~M;w9sL~Kc>rfb+((~2kT9i#8+PeH1bGVI`A^Qo$9c#G0X6i%>~VB zGCLd?k+V|2SZ``>b=sx)%SIKTk@A$=ngD&_;r+qh zHo?drr$<(a?itJHQn64AU$Mr)Gu(7Aba?U4+qZ`9!!t}3k+y@um1(xs0(J>}du5BG zy~{$Kz7I<+F>e6f;iNg-Ov2qgCB1*SnKb>MTJX>9jln`Um49)@2Dx(IcDbey1e`sY zlIWS647}gefL2JJUBqm*bt>>lCBz~ED0!wDzuQ8)lR4e5dvJV>-XnVWO*3Mb@uLegvl8n%^S_Z&$~_PeZ_7BAx0KwVQ8Y?ZmMS`edeE~MWxzP ze_!#%E6#|+d?{VAfg@%_|$p!33l!|=}?y2HG( zf}n8>myhAt@iW3b6Scsfn0 zF*}dD36i?_n=>2|N!DL>FSn@DZ6S;_VGoF&%?t?*vuiiZS%ga;>(QR;rAl7vh#CA%nSAoNj1h2m&#_S&dr9iP{ z8&-w(|Ce5~pzmk>{p9U$hl5oVf#aKGO@w>Z0RihKdjU?0iVLW}Ve0^S4B2b9Q6ehL z{5Q!nrs+@~y9Z1w*!S_@khhkUxYmGY7f~t=9{8BwKn^)U+2+%(% z>L!E!lRH3$dRgMqE9a^L#K+B;=@}(XNZ(va3|*tJzx8^mW5RzE%&V!^md10nyHmAe z%qU*#_P6f^`G5cN*>Lw!aH#)Fc-j8^UwiRxztI{0|AC|d?kffM{U%*;mae{1 zf|FS{%`ztZ{?+qI&dKEf%rx5WgKjBgEYLH5OK1EtcGQV?x#yJMa~H-E2xfuMNKyCb z6V>nln&H&GuEv&6n-HM%AaAPPL@)h~v%*^dxzp(xyt)gPQ3i;8j>D;>Q#Y)#-=tB8f==0yH1Wy>FG*9)XtX`}ll<#t<>a$xp=v^e>pu zwNoXmU%=^80YGPa{Op6Jt@_$C=T`ofk^~isftDxrac&mpLZ{7KMjc4JMq^>G)F7j= zn@DV0lZ-)J%K(Zka4z1=FY^2soyF#=PSBXpnEa6BiE`ftkE3V!9Au~L7;At#J6Pny zpks?Kv0j;}=5?WCj1)*$PR{6hW~vX%1O7MpXJX>>z3g8b$&x*8oI)jKE5TX*mjrCnQVQ+hoE~g-Wsp$gRGxVLf8zW_ZAmB=&b!qi}@0q za+v#ZD<%MgtwOw?IWp{pisc(2aMJxIx{t$j0?5Y|JRGp){?@NyE5mkNy!|VhF&JOo ziJ;5x0{pGm@6&fW^Z-K$4rKj#-JfWh8od|7AMBe5Ns0qq2e~MBd@#O1(;sD`Q)OcN zF$;aQezbks@Nlu&Bu9^~5mG(%yC6==kMpCJH}q}Rw^ly5zVr?1c13FBrdvlGyGFx$ zw2dr>dRsjn`oceXLH^{-wvjf{`QBN)W++RY+-8gPwSMr(6v8WHL+y+mJFawW++uz3 zvIoniEnjgN9T7K7A@^CLJUW>_ht0=+Qx z$zCuvlo_yr{n?bE`~1~M(0hs6{W$1O^c(9^yLV%XYB8=%8n&gXa`S+tda}JP4}F

jf z6qP0zZrVExm?^S~)&KnmW@3QY^&ROG0cqy{+QT(tsOOE>n1&G1)oI43I;EyaUE@^Y3Q!Pmb$Lh94m#9~v*D zM4)Zko1}5tU45jl8ODSUsbAOdKk|t3Rs$nT({9&DLtW_xn^^e30hJL6b@JP51B5Px zQcs5XOACp@TcFi}-(0ljuAi7|O#K{&a~EegSrGF}?Nk1y-uh}w@aVOU2Gj7sQuA+P zLF?X*qZEEV5ZxfG^c%vJTWOb7|7YS?4sOvJ8O&sZe}W|&Uu@5;r}kP$h`}(%~6cL%;#fy<2EOT`e=*X za+%Q9?Nu_q`s7p1CXuzv%V$c!9*+3>9z|&OgT{f{B)=Osrn4pK^>ud7-mf}eM908O zDDc<6rYiZMwZ-wSglZ0Ikx@RGKKo7TM`nKMys*s0W4;?hkeZ{5vM3p~sLV#+)f-V) zeREtodnm2C+S#mQB9<`5@HFemmVN(wQJF5aC?jF*gJdJY zDNRS>wn7ilcz3ux;P@b7d}nv+Z(X~%L>0Pm|MxRn4K|!7F%xdQhHVy{jaz4X=DujW z-tQ)b7 zP$+Pf-hYj6CZ>&acbEZmuhwbSzHW^_n2g~kk>nDt6ULGykcg!(iKVbVI~kG~j&ojW z!^OluO^*099apOdln>eVe!0B1kkgou*gRw~)FI^c?uz&!f{Wi!o+DJR3#ebxC^2T> zuk#S(yCTC(Ye^Z(ct$@mj^STp7;(U1U~|%L!%ziPk%SjYVm75&_7dftRhfrxKGv*k zR8;wO{^w#}nBH0HH9kB6);u>^2vWdaj;cl%zi9fRZa1SWzMMx`O3E5tjVAVW(in4N z^@eMh$IrLsv)YPy)9zNnfg4K!=1QG8iSOc z&Q>a%eOALQaUslPFz9=Q>)MJCpGlYB!iggz)z0#$FzTQ{mM-?N1x2Xs;3tiZwEo|0 zV`H8zmeSX#{}B6wyW0bd0`B+o+r#XI|B|#TjOU`5CC3jN>W$^9X#Rv*lBvZoUdYuT zKCjPTc@M`m)#A@v&XE}DSYi*BO>4j)XFR$FU*&xWB0_r17*A+DcR-7re3+2vDvj?E z&Dt!c6}q-vQjriWx%yIK8WN~a$jeWD;W>_mCV#%w(F|u5i;y_7Gc2$MxK%$8lTch3 z1|(~bnxb$RM*m{;DGnIi)fkxHOp@DUfkU+hpv0--)ZF01ciKUm$W`CD&eSNTy5grk zq@9X$8`_HH0HNI1UCmj8XiGMF30+4qO!6A`Lto#H_M3mLi`~J~>0tTd-S;kXTvG&4 z`lk=a2KnwugVJ0%^g6&?5TnRu?wJ-8_!&{KFEJUF;(isb_Qn>)QEVY@V_2D{%{ZHM zYDV{n>w3Ij`e-+FTL`!UHpJ|sqp3=wi1vZ$FrN>}!h_C#$6Naoddm8Vxy{YWg&NB)xxWXM4VTElWy^}rqL6kJyOSnPE|KWv64J9fBvzy;NY z*@RqXt}u`E6KQA=HtapPLAqb+@+%#;SyoecH!iE~ph{R>13cRLVIKrPJ!fQ(;{OS& zKMb`~>su(Jw^NGZMdn^JpBG(_6}U2F2nvJg-!&6N97VwON8AEyO4q4NWu{@PU&bt> zAl-|cx|;`a71Y!B!>5#yr9K*oCA=X_hSCy2%|Lp{1AHtPZqdygQwM*EYewxdNtwKE~Z#gv!}e1Ks^+^A9{PU zqUio2cA5jT!98TVXVh?c|63 zk=L7As(M6f(`$De?8N;Zq25iBgpUyw_kngYQN6VMa|lwTB=Z)5C_Qzx<11M#-q>Ph z_!kCYKv5_Kr#n$E1RUUL{!`7i?OrHUIqS>6q9sc;w5{#O>yx0!(+#JLNj*TBFjqF9 z@SOEvz2jh)MU^V3QUVb~f6d7gXKi3TX~?KG6&|qz0o4S5;XS`d69Z4Zyr+TOs}3;I zrM^_f`|*z4k@svG7#?t1A+)v7fiB$%>B5R&+*5=xaq+E?q;kL&l%iSJEi59Sn@rg> zfnr{9=37YUMy=cKxg7vUsP;AvYIL~}5$fK0{&bYJD`AlN#J?!n3uI2Hc3+G2u*Rxx zYK$nLl+71XK0Wk>TB-oS8E;!klqvQ3ckWK+z(9>p~*UOle z7PIdR-}_76L&kr0pm>U%kp~qtE4Kg8`~aPiw*qQEBKRT`8;zQS2RMhds$Asg6df&~ zL8@82i@!nU*D_Hb^K+i{JFOUS!9CuC%D$dPhHNfQShxxrpQUdFAihHyP)1eVpeXv8 zs4?Wr@Bb<$jeT`)#*a%ZjKlYSM}JxC_QAZAmbPf;=g~lIfG3ucr$^6~B4PcS0weBD zm@hys$%t~g1RwJ(7LV-JtE=%gvR zMYdlb<77fD$|*baGu|{!Y)e-dincIf&@;zvP5+qbIu^-5Q@#)H0_=sW`Dzv_>&Gtt z;_?_;%-in@UBU6TscB85X6}hb`Ya%+RniNPUXX1yoO)}?CU=@I3~5UFQ6Ri`HMRB6 z?qV*v{!_82b*zGc(YoOZ8Z9wLdOonYD+iuvWH>)~UhL%MvcseqFu}+a1&X?Rw*8~H zj;ivY*3QHRBN-W;+AnegnkSONbk;Kq9CB`A5x-P!bY2Xsx<9Ks#OrM?8{#exkU7YT zS2iK4L6&8{9^T-fd%3i?Wi_FV=0ftk77da#5e>F1vF{nH8U~I_NIQG7(V7T`)@kJ9 z?Bh;yp&9-yM>6;~;A3Xm67rLBDn4TNBug?N!v#C4HRa`bBtUTHPt-yjs^IA95!Pp{7GcA%=D4;&x6Mub@3L2kzVKPTDAiEMxYk{4@mgk!ZAEYg8AiG?ENLaDH z66%vPLAb z4d$2Q_hs*GJM=EOi|jo4sL+5TRi+3AGe8$1((ZqY80-Cszb{y5saAg%aII#V)1fYw z7r)M2%N;)bjFY??Hx{T|63qNd@Fv<~DAvO8Kx&9QVXJK?Wg~9jTjE1ZK1ynjU<^R6 ztpRKsnt5!GdNAgWI_q)6$(M=&#LwYWX-v!{AL2xK8vX!B9he9Q3wE-d4)6^xBJ37b z7+vCO|4rm`1TbWi1@dDiG906`VP&D|q~joNR=!t<>GARf7TybWH!Nv2+JPbnE9Jf+ z+NpwoR?gT@i3J)a!`YEw?nk!v1(gTZ5z%}zVM4c5ZOrf^m{7|kQzrPFyBKKMnH%F> z^30hex)$#q)qReak3U#ccs$j_G~t5dJms4rFmm_z;Y9uQzmRQLEX2Mj7xBUaqy+hO zDvI;eTK9~!Ti0?P;*}sGMXk;=5c7J%_4Gja{GKhN6=se(Jb9J5L0D~@A4~Q7-ScXJ ztV^G5s1l55E@|F`VVrIUQMh)k?_*=}rIH47JEp%t9PW4Ej;Dv@%EQas@rqJ^0=i#% zkenXnx}I(i3VQGh-v7ccHxFWFePQgp#4}JC%9F}C|5V<_ufD%TZaC?De1~I9;Et8R zz0dg6eAF$hv`rzG;YBe-CDp*4v$Ws0+#Wu~ut#Wb$~$Pte0YW9%fyefH1yaZu#)B+ z!74xe`=uu0zEdvEPGQTaN>6~fxw^i%-oe?4he~>`CUt)ie<`;~#j_aem2Ych1Ejsr z+!!9TT_s3X_#oK8v)p4NxRG1JWd+Z3x+-Kl9=l+Qu?6deQ@!+!*O5f7+f2 zO+@NWv2MO8I4Elf1Y_QT)l}8qPnRq<3cp>#u;W>$^d&}54ad^hpW}XrB6a+WW_8m4 zP0~Hik;J9aCl^Pn(8ZDZxB5%ak`;S^{P6?chMJ?$kxh?bs|IfCRZuG*DR? zlvB%&xkc&Arb0n{c#~?x0(1oAMv)qm%6h^vRe z59>N40WPWfk=0hVfptO(A^4Wk!_=}hfW$=mnt*2|EbM@ims=|b&MfO z5=;QpK*EA%nJTdK@u;zZq5@3K9b z|E$uL7fdy(;x_Jx=;zhjVqA)Q*Yu+WQBua7##+!8xkg|7Apw#-q)o1kffi7C`o zyT|Ev1Gh1Qbka8E*A|tn14hnuckYV4&rfjV^{sZ*)ciXu+*0Ss+5CxWk8+CTwN9`LdiVbB;HhlBT9mP__jpmxv!uM)M8G*eb+q=%N zgO~WmXH0Y35B{<)y}Hf29Q!KcEhruj)^%?EcHES2XQoPB*Ufi&!7&~M&V#IfTRVW{ z`#9#S-^ni+&FaHZ#*;Ai5;HoZR*z((XR}3+?W3bBZ*>{0=Oc+Z`Ef)AW&L@xQkbgb zK*WcK>W}qIW8pN9tbDYStrD%ppoWeg6a2-LdAff}P&IpyNHkge&?HYX8UJZ{G*S;s zFWEM%=k{E1<(XQURnnx!C5e86x<8r}0Sf}nroeoQ?h{&(_ACoJU~cYKb3BRY!K+WR zv1po`0da}PlQG{J@8mAavch!>BxobX+BJ@#-4byucW?f561UDtyEe;9sdrv+aSm#oc6msoIFd;b*ON zvU+)s{)}}yw=XxkG#ef^hK6!l!KO1^{aO_O8=ubaV;+}^#Z0>0OIu^rkB&gV0#kZL zaQU=wpwYMaGF2AeOA&_{#k94j&4OwN&JIeY6*M=G`VOWei)Qty**VNBk)Hz9Iu}te z`2D)Xc+Y4oDqsM3*^s$A`xLxx85z-hGsxBswIcRV zL{ZOoYl8K12Tl99_~r^?0IB?^+n0)BnCY%@qmlVL20*E8ncYk8E5>!2>M;YCcZi-b zflHh5*%hT5b>@B>@Fi#mr~kD;N+V_V^&&)<{S#LRda`PA#-&*X{Q%?1-M?2GL8|!| z8BV|pum3TQFU1`!!+^YKyI)rZLAac{Ds@v=?QuIceTXH(O4znz7 z`#aJJs5T1+fN7!Ht)g=~eOmN>^LQ7pSJL{lB7H2dE=ey#fEb?YwR~Zst0Qaf-`rg3o=+ zwetHQI^A>`S)a+~*T$=JMH%wbYIc9y-=rt;eC_A^7G+FYLL{i?mb6J(M}68D!fy1P zU#AIzn>7?++E5&&I7xc|ys?_e#r>e)(Iz#d2r2z$4#UHND8b|*h9eMkDV5Hp7>c{5 zZr>!wj5I%zqPlewstz^(w1|H)xLg;E9b5k~_`MD3bG>w|%gO0lEk|%~H2=0$6^_Jh zTqt|0^Zoq@;WX!Ik|<-DeVl8~Zh&sEVW?sGMMLdz*FE_er(!22`dGcZ+~M9Q>Tg z>A#wlO-uf1CGQ7FweRy}BKGH|J4yoGY;G<5o``0+R$FQILxCdti_^elC2r6Zr$o>+ zS)0Sfg2W5VXL#Vm#DAhcOs%RdBKC;Hqs)3ulTBDZ${lCnXEy>u`KEHVdN8#Ggp%np z_T_^akd%Z>53wXolCxXxP79& z37IMSI^X1o3$AF*XC$X(bb zQx7$I&U!p_k{sdc9XRzQ+idQ0e}7B1+89*r=ByYs3oB=cW=z#3R(n7VL70jljnF-Z ztGj1TBK!f^mtqU6bb=m9*;TEDs-Pc+J3XJuRyI*G^Sxf;tIvlYNV`ILHA?ikawf7T zO&9U;=%194R?vh(Q3jm3vN14Hdy%CF|Ek&4W*fW5`W? zeul&vj^?_axY0}wzB}9H_dtWZiZ@#oC@TbK1Q_zW3o(lP5Aa`6|*tSyWdT_7RFT`jV;MIO*JiOW9=N5JFT}n*#n8K z|G@uMeu&5!}j9=L%;`AZsRd{-DW(Sf_i%7MN=u6l9}dTk-*a$|SDtgJXk= z=Xo*}m6^+Mnhf94N3-6mQgp!lx*K_V<{Z<~R#b&CxTlk@3 zZy42ixJ&21%vgX4-ia)FRZH%ECXbzJy+xniVx=XQ@y3@_p1yLjpdNC*dcOf(Wt+M?$gCBBl(JaUQIrg11QV*U3AX>cjOLz^KOT~uK93Y#wwJUyN zM*s_$aql|+f6XXNm88+Y>!|a%D#}}#w{erHVKX~?6*FP!7!qocpQj6X04|X9?%ie_ z_8f)gf8kt;qgyK&VMS;{GKkZeTHWc(3I$XI*C@fr+x_0hs(G$(kh4`?luK#Th$r35 ze5TG9mSy~AF&{@8T{K>!m>`<~Aij<;dQvIHeVIL0N>(zp!np$K@SJT{%AdVM^tuyw zhlE_l=iJ>_7yD@_P(!!ru9LuH%!y#<;{%M;1VjH|B1MWrqAR4HC#j3v{}}`-ZnrB| z+sS<@|6OL>HF#lIk%EvA%sl!a=J|#H^JuL60SnahVh6LmcjtFEzD}4CHLBIOH6-NU zFTQ{O8KRDh)Vx2+$@#1*_{cf5Tv~W;NGv9!FJT9ljGh<2pYu9;{HAX_mBwW7(jePK zPK(Aq$=v%8xJ^>zd$UV-CB$bDqizV(8nXCA{GiH-od|bL5rnB|yqeo{3$5dmb6}?M z5NL`w7X#}7E2O7u?|rKKU|eUO5>vYzYmT-X%!vfOYO?5+Z!)>kTP)$WRJbmPQ>qCm zDb1L8{>@U9`c=Lizpc{p*w~rs{O{iGR}1jNYn9x630p6{_j?X?O8*LCx82l(vcKVj z9=BEvkJDK%wu9EDRj!Mq+{Mt;4SV_c+NsB`{CB^4yFXsS97Q?8Fh<%V#FhMsiL=!F zaB}+t=W(XVsqlIT8>emR)TE$Vj6zCmV>4_FmNBu2Y#8jb6*Ed7FHm$G-henO{m_^u zeta(93fsWs-Hdt=Dk{J!$e!HJ>g5?b(>3DSc4ucXdiZXa%4tkRq_;hgXqJEfo6Ea& z+kqN>BZ7?&&{JcUq=@Q>MtMDUspBDF9bf$-*wGa{}Q)l-12_=NerN8zt8O{ z*;k6atFkiQ64L&6tW9qi>^Ea9hTjPpNhsil1vov?pS<^>ZkS>tWmKX8L2820V4M|*Pq!}p1xJz zx_qD(DO6B<^HO>uGATfk0!pgvS0pvolDe582?R#IDWKg#yPMz1t=_};!(1G!;AKcO zr{3p3wgP*##?+*d^}eHuY`vJls!rTz$r{oU<;LO71du}v#&SS?$FCy9J|KSItIjWR zt=|0?3@U@lH`le_DHNa)CA?^QF!QP+J$e!EX)50Di1W}75)Jq3y}bi?rKs6a4^k*g z2eXQrNtSB+;W7FXfE%l~b&>q({By^Y6~lQjSLf)EG!vXdxq_1N#*eB1^!UF6%<9Zb zQprB!#4avNaqn67q22xC5hu4_KsE-XoqyuX-3bl_7rEPKDe&4=^jBwky8WF!=90zc z7C2c`9U>FSO))`#n?F3EL*9F@>U!bqsnO0*%C2Acf?$6FQlG8|Hn7?#7;gzjx+1{9 zvm!QG;F0ycT9-(@DG9fa#K^tnauvu)juK7W#7JjJ2^jQtWKgT$MzUaE5MA@9|2xQ4 z{}{Q;)`U6Osrnkn0|OFZvW-}jz@YW0i~a=pKl+?=$Ny8GWAJ}nQ*24^e^O|5jiIyn zovuG22g#C8<&=9zJTyvEi#Qk@Pure5a8&ZB$4pGFrk(o!tbUE)9lc?MBZSs1n7+jP ziZFczAHA_Dp`{*v;G|0NkNxDI|=4-e-@uhVFuU zzsMY)eg{m_D!VP`EP5uAXmh;-9+5WD7!Z?duUer$^0{V-E;$hQ&6XiJc4xtYIuI zy;E3V?!O00^T`k;MGS^eP;0rGsOUpa8E5o2-`yM}mX+~%p5{DH@Be?}8~!+bN`4jm z=YIldVQ$XQ0*s1hJpXXS%Pn@@g4yY2$O+(G8OgaLI>6z=Br4p$6{fuNyJ6m0vTmMm zVimm++DO$Bt2G#ExQ%biko5C~=zWrLCvt;O{~6*0_AhKf^Bf3hJAD} zb<%3->+0i-+cDpti+4ARm{*Ga);LSR4iLM_udxL^Kg}fS#ZqdQ7}bp8CFXw%T*gXY zQZ}59Dy>s!#O)V3`E_+7(29D;aUs{G-WLwKHM0r7J^r{%mbrTShv zIQ&34QI(M!-;@E@aTd^whk!HP>`~)^v|=umIu$#$46Ml4!sb1sTs-T{v&4Gx*v`)!Bsi z{3NNn2ef#lgTV`on6PC!_Ql)1MP6NF?^+CAK#npnlPxtS7!~iQNG;`gTPWgZOK5c?#q+?eGC@qzHaEz+IFdVMgmD_@GHkN<3dj{}J!*aj}$4DuaNu zOC2kDc`pF67Ce6XKCq1+4HMZN_}7U)8YH^HGFa%Z@r`@4`&|z7O}weJG@_|{>P2tG z=cjz+UW81wI}w}Kh5WO-&USfq;>eMGtWs#Up65;dAbW7-dDiN0#4P%Tqa#3@fj!CF ze!T30KC?=n=t{e#di1L|`4U5V*g4L^9uD8PgC8F|(!RMtP{3%X&?M*4gKzH?5-vRX z&GZZQPda)M?ne+pAa%t)r4tm11@3Z;@(h z>7P8ChB|W`k@X{<1@0itI@bd~@X*VIuf-ld#Y=e=coe=0n@~t`KW3iMDQhup{xm1CO9RVJMnTcuHSGHAuc!6P)CoCv0=rB!7B-Me9u#Nk29QWUh0#Z1lRdyj}4i zU&?&=C_GXwU!Jb&2ymh$f@cu*UTigyjqq<-1zHu7Z_M?{v1*b`N#P(R+pmSN;@^wV zcII9)@g>WWyOPGXf*wK-boL#?13%f9Icy+!USD3PWWPht>8W}6Px<(H#fKL~j58>a zK7Gg#Poi8F;B~4@pRi@Mdy`WC(R#xq*CLUGc?-@)e0icLXXgGT!`Sx-dLGmuX(29? zpk8ec{N=N;Q$F9s8Ad(AQKm@?CEaF=_;w+VAKJWQV&sD4C5%_<_L`lR><7JyUVq+`jEeM6wV1u2ZJ5DZ3)VBG(ES|T4xz&@5+U@UxpF3R+7KX1_9<}9L zsgDTo0wgIHmn+&6FP{^_E7d@^S-~!cpSMiTm~nrVbB`+W07`_R;B;F%RcasS@6wI2 zSmX7p{>*$;eQFs5>%(-bA*T7pNmx}#WEW>gmuB#vcR0IOu#Pn*>O65 zMnf`Ef*(yd+3C*wvhu&fFBI>oXJm+60r7c}ppT49B`1yv1E$L)UrVb7Xsz2m^N5ms zT3|{r;ya~yUa2?Bk}UEU#gtDjg^sup4(9et7;07?^s3s67)V5Sjz*T2>G1vTZK>lo zU!dljaU{vjp4Y=!uwfp{aXR~P41+O*TaD1Y9w=XFsO2=f@7tTCUCfd3m=yFtM!AB~ z1y%a|kD{;T%FN7zL&Po6JLNI}I+0+@9pzdBAEW;K{Dr4qRv+hCoW_~SCAp67wIU+D zH)P22Xtty8JeqN;c~+2lsn{!)Ww*FETqkrX>GET zb@Tv8&OAEh3uV?J_FHO_2h5t>f0qI>Svn*(`c?M;<<2^WFGY9%!+b_W9T`skqvMQa zgQ>3__a~?R2I1J+ApaSnH{!&KfTt1uPaP|o`%Bi;rd<)UCTQFo4h0c?pRoB8yZMs- zfY;=HpNtsrKyRHGQmU(8{ldL5fVbtIGu%W{O{@O#w+}vl#r37%w@Ne6wHxcYP=Oh~ z!3?CY1^1zFpo`p&ov8USTrFWG!)Yk|&y$gSMSLl)o$APp=`E`o-MVsu*eCBEN#yZ; z`MZZF-QNmGrmAS^;hc4q{MU?|wj5X83h)XgB_;)VkLVXd-_A77MgsiYB12S$+ZRYD zRQqzl9h03Wy{V^n)m@ekn-qcWJG&(ycNLWTV=OeI$Z~j;X#gSm z1@FbM)^{-?!miQWOjPOnj~N=aKhfqg6iL=F9WAxl9l0CQ)fa^|evd#nNYa?PbYnx! zV@+v2$l#B&DhyV{12#jVg;b8pL}8+8UnJrgGeU|pa!XS^AmY^IJTac}cEzT1<=fC~f`lYHH@;S<=A=kA19%qAy--hb8alN-8^UN#u79&~>FoAJE z+jPoxSt;{XU%uViRGFFRxK6Lo_*lQF4XAcfK*@47-j(TW8#S%<^zCpi_F`+Vo3TDm zZ$Cuvtw+~JyJcvHqc=FOKTr$p*#Sn1J&7&`JU#_0xyTn&^Zm+*m!-?M1G&%)_C2N` zDj$jjI}L9Ln(L8x;6|{qFZLNIv#7b~TY*jrWqq#*wTTgNc5Z+~OPRMyYQGA!r|^1V z4&`K7zf<+hvI%hb(+3Ia5FQ9LH~4u9`$$m+``^H}G+O#%S5?q!8T z`mA9Vi-j+yJ}L`((nCsjG7j!x&+7Ju_gGyLG7C$2*tica)MMaKfzryeTwX9r%)M8_AtN7L4v#Of zm;C+GV@cG~vct_(Y*hFP!9M%NG%04Bj7orn8)^+^7V7D;izVp$+ArYv^|MRa_7dXh z&Pl=;>?ff3s-yBvsiQp#ZkwP|&8_|Ipjb5mT{|(T9!a%5bo%Qu=YVGMp;QqszQOo{ ziPRgq8HZ^PtD7>}0|GxLk{nm9?7r_YQiIOGZJ$3kMYCa&HQY+VKZ&~DBy}}x$E(1< z`us&o=C|qYq?hyb81(QTrDRcVmw>bQEPY9C38lwD=IBc5HOkBLQ~nJO1;$f~q-AlA z{z+!%@Mfy7^Ou+{amwWBY&KK1Cn}oERj{CeS?VhD+`4z`Pxu7+YBfvu%1Szvax3brU`RkGN;}mIOrWI_d_|X2=qZlg$YCn~!Uxegoram8^XTFzfbeB5yeRZ4Y4V{tjo;s3xDEL4qe@9rv+!PmV@`yr)9`%htLB z$Od)JLc=7~asJqWHO2gX3IC@nTSLABQO{#~h-cHIg|A66|7`)^A44xtXMX@t=5EndaXzr-xb&Iz)txqwJLKV8I1n40@1DlTmp$ zS|?N+C&zqY@by|4m(7k4cS!n{IFFwOPwpoa=)^Fv{wCjEF89VqkZ@eG$!0=Ld~G;0 zvE{qu&jnDM7T>>m28XSzI%3&51emK|YmmiE%4!}(LFov~iJCb1MZAu7t%=W0i}UW; zm7d7+!MW19*59*zyjZ4wTs6rzzdon%2?2g-Is?(Xgo+@W!|#tG24W}5F`vu5u4 zx~l7~Q|IixA3_Ijf`&gO6rZ^8mGWrpu1``{SKBeM1u0`qw0yS7+>mX?%`8TEIcWZF zLai$=blb9PD$(9BsmX$SXQ+nOYF@-kux*(ITl%&!L}&C?W6g&)C^O}dt?!lPS5`$a zrNTqBO%v{2CC{)h3fR);FwAx7HJ3lC&uTA=z~3N>a8ZegUap4RuLN3QwUHpy@)PkY zjv&L70IJwU1G5Ov{#u4gG9S1uXOGEqkw>-Ts)A8Mh_!hQv75Hd-=3xfxI9`crKhT0 zGcgNNTt-X3mMwTm%wRFMToIRKa_@rRsaedpG`tlFS{8ZWck1afi-ShK_yn53t7eKk zTA9*mxKF*+42zvvnj}?7^B+g&dX=+bRZGVYjhtPQ(u!Ia$4T7g-K|xqu*~){XOq4* zyXP~|zx{v^^&2abRCkUNnR)E&37Ik}e<^aKmw5~9{FiN{ecTk|5ji^h1*rdz z+_#!?-g8EUc_1nnGsqhNaPMFUv^uyzv$eZlID;J-N|CRcVD1Zf^@;`aEnm!IA3(lM z*4XR4bXd{SL`d>1KT|wyMXB{*qFKDGhoHVl)M(fR(%pX1%^nvU>L9vn$v#}~jM#-H z>ZrZ0hEwL>NxYkX5Rj$mm49H9LmG^eYvi5gy$Flo3P`;f52xB$U}C7WP2#eOUSAu+ zO?V|qgzPA7|tJ|=>DocOp*%#qWmPq}fv&|04Feep}I+83GJopsFSvaO)59-SQ* znmZ#%M|xW(`%-k=t7N>5W)aiqHpWS9CTddai63cSru?q+@N*2x23z7j*Khr!Y@IMG47t@HQKeZ8{j zYRkldZ0^6ln3D@+tXY@}sh32Kear7dC37J$!EPQ`zj!z}KAu}IK&@|8OGMP!f_5(p zd*TGW1At7>p&If45@@^13*Ms&b(k9PRnlp^3I}RtAym;Q+~kVXZ!T>RNl^Jk(4b3x zQ-A;|76(*%?DForQAVpN%*raagitWuj?xt4tGd_VlYaRYsSX#D5_Io%^hmRHrM69b zm~ePj2~e5N?EJli6gN0Q&;Hk~m?y)1Mo3zdi5)_>|J&hruy6Nu?`n$#&B6dO!~&-1*pspM6D~$ z={ZZ$dS2^ef1a+8YIwTu8s+#TI%qgP!fB-2EC` zZVBC6@tZLwk6)rRwK8uz(7wTx4PZ)YU&)6V+Co4e*S~k`RcS^|otjQdQ$UPCP(K$9 z2Em!tt$-seAa+EO9|G|YHZxMsJAq2-1g26e>^@xrMBMtGOiw@gHeh&x3ny0rrDw9QWW#7fhiysOxM`Q5>pM&RCUa^jP;%_x=}Wq&y~I-GFnT8;+LX+z$TipKuB%$E zhGo^MjMZ-){*HLl>Mo|23>nCY8{{?2#PWtkW0ltWB&0G-xUYV?W!ZZedqZ(O(jL}=o*^QJ*-bo>-C2z>;%dkGvunfA{kY>xHkIK+I!N;!4U%q1)3u(&bhFwM z+x^nxyNwTxxI(m4Dc)tB;lj&VMV(HHLay0>R;BU<{K}YgP=G*bO{L#dyEz6!~;_58xU}g!_+ECdTz=&&1c!1EYK2=gh~j#9EOr z6eNg2|0km0N1Z_ohgnaQxSgOP=tmH2gUGo!(`I8I?F$=v?RLG*N#i>wnVq1JPBo$> z**M8A}2+wAvQsF z9lniOJuzINiVv2E{dy$3o&i>*_mFGB)6OgebT9R5|5I_u%L2uEWWFxAWvM&YW2}d- z7Ud=s&$-;vYTp*kvotA{ekt!zr4vUg0_-2pan`xAFpaun9!cSEMu^Z?oq7_YcD;!VZelOT>HFm!*#6mg<+1Bv7wpf&OEn7ETBbvNah6~8{ z$O@oKs<>E;EL_yqQje?^_i;t-Hz*Ff?lu`Y?yO>IOVeu5T95CLHPMTYiY>%?w!&`= zWQ+-Vp74$UGRA$@3b`&?Khk_a&QY&@uJUem5d{EvQkSsSLm%q8LfQi1f#?2>y^m;ILdwTVQo$hOiV(_W{ySLrO^Et+eOhwc_x zaW$%@^dH5h6Yl~UD7PD+9Ch809XaYF`4^xb%eo)wN83yJ`f2=s-jieRUu$R>P&}W7AKu_~+8 z;YLCN{-xLeL(=_GThz7sR+@iDRR`2Yw&UJkhvPzY{BlUevf2`&Vv5bm!t@1C@bI z@Y9o6?`^X|E>Lt?s|PA}>e%<8#WQ_l$&7+bhaZjQfb!>u*so!$ z-WZM5(pmhe2R&Z{t?CRhdT4dxTz%Oyiy?VYqh})BHR*aBb4S6)mOe@;K&Dc<5+BwK zrc0H$9*jKIyEQv3@>*jb!fLb*fitAfS=!qwOhte}qEKBQ3*yF5w}w?orh~%%_Ajuw zcsZ+mp<*AhZYvMrrF(+1*uQVqgy!yXLQ?M2*D6mXmm6z?ip?Sxr52;=zTx@&R332O z-Fo!=&PM6)CCPv10$<({?s=$^ZhSC=D;Y57fSRLfreKEAed;y#J6_^g=5x1*JP&92 z(@?`yQf$%%{cX%E*V3{d@0G$;Fv!}9X_>6Uh<$#oX3v#QzufEo4l-klV4(n#< zsfB2mTR&~h`-#;HnD8tCR~hT6VzQuTvmf=f(=d{)>QvvS3D!zG8n*q>MrU(6q$9;e z@vg~+ZrtlJb9TM=V!d9S@x?9QZyc$Vt2y@~3{0-CwA`*BokVy`H^HyB&M!@ROYjiD zk!zvYTz+JAeasm=K<|Wr!tsh{(U)VHbHhkC+M7t{d9{WdzU@Bc2U?wAe|;->4;wCc zZpIk><|8|P>LRf$(rNLeOyB69q1nve;B|%dbaI9rEW?@D`|)U&`Kq;$hOU42%Mw1T z#-P2RhIw@b6E1;6g1)XltE_z|2z|yS3RK0nWDs^*-c$6ZOA)r1|0RNzPh(l0Ypmu| z_kIs-Lgjl1-|1q&`1x#odb{H|^A(-YIqoT24tDfo#pjYv6Q!sqePe@FoCbue^`4Z; zlwNg^?zjFzV=sCleC9Oe4x9$_&AuZ$4DzyGOeUjc3X{ekbthG4Ahuh>=iT_gPr$22 z20+5xLgJ$(+$&FyMYZLaX+ZK){-;oaD{GJ$pJ1|%_(#lpIY+XHun43(=|1{><+PNts%m3#5U+hKewy&4MAvDn= zIDRcYHtB-{((1F`I+nTpdU%)Iin!=BeoS0F)EQAFtU)m*=93naV*69Us|9i1P^_g( z8eac;&@JBLP1B~auU>^vLM&Wb75Iq*RZ`Wz(SUNP`*WF#{{m;8^13Chx*#DUjOYC- zlx>7upLIN4z^p12D|uAP7q!{dB8t4|i-y4^ELHYDb;YO!Pt${O5XB`hl2{RL{c@@( zF}IJOE0T86d6?#)C^1nqORyF+_YGk>5D#ugM?6OSRU)hE`=Wlp4f6J6fiP^LRW}W{ z_IU@2J_Qr&_q8zT)dqmL1fo}sadVN{F1ewzox3mup234aCr;OM_4jvhY>Lo35DXUr z*}YHojxGCwDE$<5?;BEqmu{Wwo1i1G(R&Qc2s8d~=KMkZ^1hDL``?r{wR1z{{l@Qo z20ViWE08pEzzU{`o16!p|Hg>R+D_3tN1QY9|H;R8L$GAkI>JMV_o&AE-MpV^aLi+O z8_h!*Mj^fdCepeQ>gdn|#ic`91K;#R*D1)(hY)8{Kul%ZNkfv1WeVdq#Rav-F9-v$ z3xc|wU!(6y6W5~T=1BDy_A|}vyTCxMhs5S{fpvj=srluTGUo}Xl;38!Sa3{Oqz$k> z@=Y88zuHQl;L$iKDyvNoU;nU=Mruj*%+5rj0@cGwM=*gxuv&HNuR_#hK1~ga9a(>m z5C`Pdp!EldU+()0t33MwU-ljG??Wz16OHz2TVSwA#trp0YzuM@No*&^-g*u){V3C> zWQwhHiCvBohq&OSq{QM+OG_OS-wbjs|Cv4s(-ofC{T}73ZiIUFq`SQ|H^LK1VJ|uq zcbOEn)Y5knc!+KW$8t-;b9B@K1Q?TiPjqv_n0&SJ|H?I$-nNS4#yKqdik;~;;XFqt zOW6oly#9PVCH}652-WB_pk9c0A(mbxm@fMh;!$S%R%Ylyt!obhR1Kybf!@Hg^{2JX zzpfk~TWIn2;SvY={k!~^40ee7ID(ZaA4YR~kEaPehX0KDA3T<~mxl?wtt+_yEar=~ zzRlnhbu5UI@DIG*v9I%tZ}U75X;k6isKSjka);Xjw$=(*y8?}By0z1A)0smvjsvTL zIAv6UN=97G0xD;|b~vrRg#;`?{DG9QX-?-h0B!V~b+e%Xk;i)JB06RXqmFMtEQky) z7bFisyDu~?{x?I@AVhw=d!_DA9bxl<6#`&oVE7$;AntueitQ?%c9xgBMym_=VOb-1 z`+kV$^h4jJJLbZY4)NIc@h>eWK{Tt>YVm)>)44%y;sBkplxp8*r#8=4#250u#f2R zuW#TVw&@>87qC3irTt9jQu40-w4(B$n9+w?EyX60e7u(oua*Cj%%3J%i;6L+b*@O- zhjskr7pX`nWdL_~cOcjPUc;n0-Te>{ndms)xXwnQX#8YIlQ6J;sr_p=?5KPG`JkWF zT_m=PrmV`%6wr|ROF#3OnRRN9U5--_1wrylvNIbm z?Vl$agH&tCt*s}?yB7cAfONH#dTNk~CI;1i3J5PHW6A$OS#)Hpvm1&mAb3+|HX_bS zSO(qaR^;UbQFCK1^78r)se_?1d}T8sIRP*~6l0`dbWcRDzj0YLni}4Q;AU>{=nQKL zQwg9{dRgm8_^oi2yGVhxF!^%U5RZ7h*La{0M&UHqS(W$22U6_a`$LcmW%LuM(gi~QW2~fo!Wkl4hLh;{vU14*>;x3>1s!i^@Wnu@&6{h)RGdkV-iP*{7@J5 zxvx3#QeEBagk_3GXpJHz<8q9|vVBwkg{3;6bTf;rBW7Do@2?#*I!v#KPxN`7eiKJe zu_l#=bBX=)xRgLvi_V*f?<1>HJN_I1S4tEYM%kZ2lG)6BQ-1BoieZ$X&5-R4&DNP2 zB=*@6+}(F8o|JEqRWK_zflV^82w&2YZ0uA}fK}sm#q4s;jMc&}1m_$TR#jCaU>o6N zZx-M8LjR}c5BE@aTt(`c9OY=;9xUReJ$tM z#6R%BzUOIpEI-=xO0|BcAN($KLr6|a$prDSIx_zO8^`2)8?^p{bz5Lz=l{oDo9KO& zdYVt|Nt*cJhawa5P@(u<1v#Z#)wGxFI33TDa9(!Zuorp*vld8e0H0T#$DBmZqzY{bm&B`U6mi`3=qUXg5bpr!(@7T1Ds~vwLuYrZ# z+{D;cZ!~+l+@=;^v4y={YM<1Yo;GQY4=qhRD-8ii`MMPBL9XpF3AQt6C%sUvZ9-Cf1M{nlWA)g^oJJQX@S^ z3*=6UFU!KjZ80BW9dDFxXf)AtgC&|>rI!3!v4H;3RG2naK+09BAemi!L(XDo@eG0| zVx8Qqnz3I&4OXvOPs48V1(%JPZ+JAk6w8ih0rfi5bt&QZ+)(9PPRPA4X-3Rf9G^d> zm_ev53Tl+d1>G^dE#A*VlU^P;3qkdP)p}1K>+S(AS?MXWo7Rfo!8t8j|6R@>;%{)C zQf~ZzV!02U90;6%2hJ{?4FiiJKVYpN>krNjI3GD+eBWa{K>2rt0{qVC@mm|53iI)A zMnm)1y2+vR1M9LW!BQ}O#{c+hA6!ykEBL?z!C5l9-o>R{LaM#(#8ct7hhHPXI$TaW z#!i6n61m+HD+_X!Hls~PF30zo4a=Oq*5pMCG^hFQXXhl~(XD!W*)*hPN78cTd9XrF z0%!hqtLIeJ2$uU|>GYp5DC3(O{R+lo>X}!#2_c#LPOE#P!j6}353;vD{eICc%@s9P zzGr_+5G#&@Vf_C)tBtvDRj-3`ufH68J|L*zYg+C@3GcB3O+*D2lJiskr%pq8-$8Lq z_j$P=xf+C=TY z=h_)R*eHyE(zlNZc%%YqGabe z9LdfT)21*_@~yG@#?js#DTp7@DbX|1@ZQAv^D}V)ueW=_jf%1HTP2J8vyI8Y+vz@c z#>jIN_B9e|>dD4@8;_gH^}YxX=3g|`L0jlcg!S*Y%vaVF<*Bq>r42czP8SHrX7vjjV@tOj+M+@YDjcoUXsr=hmga&uPF z)WW?v?}=4Rc@BC74}cr$pJA)X6Z{dsBJijQakiW7R>Vt)Erzz+fd%`O*F##)sv1#| zkXtBI+$8-i?{5ZUWh8s^|Dus$7rH^((GX+!0XsyUF=*v=><+J^;d<(AA3~8Ucdw$iGVkkQ4KlvxQzGX#5VnyH zR38GY&pFIn^!xd9Dv*dP%m_)Jhgg|Vm^2uNx!$ zzfi`Y_e9v5+-3iI77-OS=6*pd@{YwgO=wLYlZ5KPS|!wRMe}eD1^dZU(1s%W0DtP~ zjP6h-*wv>SljoRPvp-P@WM6fNci%Yuw`5KGuJ(>;UFc+5z=F-prNvf-=QOusqGM>D0pP@wqnD5JNVQ$o=uv*Tpgq7` zt7`#sCJDS`wIeInf08^gR~q;syVpXxJ?P1U2I+L||}J`j|K{&+mc0g+@!<$U||3bbZ6Y zOJ~8g;Ke1KpbGQ2fdAVk=I2U0^1`hQl-$`b*Vn*qAFFWtEqlkRppDVwQQ@bI@Bb?JKKjjJPlWHM2prK{HNB4^0{4LsqZC>=l?KAgTw!aFvmej*C)>_27tk5H+ zA0FSS)>qbs5{_m*L{Y{%|4 zg<=@n-##*ar&!wC2Qfn@H{^qK&dGEzANK1X`jmUl5~XR8q`dL}}_0lmckq&{Z{E=feU@dB%j> z?HTVR`EfA!L04A0Xi(2`CYt$vrkS*CpNgGE`8A(1_r~m$4bbHlZNT?9K zpS=I|na+lU`<4w4Ied*F&<~&H@cB+G*l;|f!COAXB&tAEDK4Khjw%5Zpy^OmHim-V-o{q@S1MpZYz2fl|KhfuGc z%G0dwhllmp#mZ&PZqI7p12^f!7$JK;Ri70QK2WDTf$}0xWw{hMt7jQ>v3`vEsz{TV zUD$HT8jYZrJUkhECIb8g?_vDR3y?XDq;kF)s>Ch?=rX!&;drrOmkM!|lkLYn20V?= z&&7>3*{nhA`J|b%X7rTw)1)35a{19=#+Em2iXjRM_>W*y^q6Eh)r~$~6S{6#BmC~bR5`)UtFnmt5LKs`^!arGX zL%=@rM-xBT9bO@hrb7~xnOz&7nV{9K2rK}E~F<+3@-1-#c7R0yp zL?bG5ktEmCW-R#VX78UwFgVFhl#ub#y}`_z{8Aet>KP4NH2cb@<~>9+b=p2%Byxn zp4qd8c5h@f)w_H|n3i{KK0E_cvj&?|njm;6?ES_QB=dud9hGLkX)UAc#=A98v|ABd zVa}I_W1L2If0`~EJncW>);>{xv!~hn1@XLtx3yo~t{Y|XRdS+gsY{1y zl``P|O)jcMl)5JOfcWM&2ck0bgNz^Q|Nc2nqC06x?~&O_WM0RmyNM=xE!|QO?1HQB zXB0_2b~E9qKUqg+JX}|k*1N;J>J-hKkjk?skyY%Hb#JC{qytR* z+Fd)f>XcYN@d;NRE{3VfI&qd{M>`%J=oK5hYW{rKO83lSUTBNjfS2jXp7SZ0&WYha ztHbs$MeKy@f0{%hG5c0=dMJV~H=VTPZyy zz+OscGHZ*2B4bpqP-`QMQuQ_a>}4E#1xxd%N~lPoZy|YR+p4`@Fu=R0hA6N;tzJuDjpG5= zN;us)Z-En0HZVgM%WKpar1pI#IUwTjGR3-ep8bV>S*6v%)o{cFSHlALS%(0_>EFyQ zhgxjP9f70yxJ@%{>X-|=bD)iyRH>VZGs@fYyw#?&=yYbz_RuG7p}x}3$Pfv5+#wu} zW$0x%sA=;wq2wIyIX)>kEy(S~CEm9<7=1ww)~eucW?P;hp(m1J z{&l3yZ`Z@b&6W=L)YYyuUPU9gdYSw4YrQzt?SXx3&&k{H>cBV8rPH8K+*{>84 zi!O%qMC`^hCYC)+CagqZfk93RjIlewZ;POaPcv_GEQ5k886A4#O$$i&nJPD&X5hW)lC@BPJp zZ7chn_#EsKL+h--11ay$gqc0WQe1;f3v3u+1=*S~)%;c#O6?L(b4h7x431*0({-Bl zz%R+OPN5t(i~b>*h?LcJ(BIz~o^}v==dBV-rZe0jIbP+=+0^q5C*}U8ZOF&8yF7uB z5y=p$z6$e=hKp5><#jN%`nycHEaR6177@O%rS34ZFPJDh&@jnfT)pPrlz)hi#s+X* zxC*r;J;_!org2j%v|lVHtdg_guU2f;?s!#gW<|-JJ5Q8$r%YClN@QhgT?Ja!4!G_( zZ!AD%m&weg3ADo2CDG&ZC(TND$<=&{TSm_pbc{dj7h#87GwEz!rfamClDv6w*`F(4 zhcZ;P;iz0+Ezxtw>`!=+tZws?bcUWk>QM#Z`Gb9%Z`vJn-5_i=- zq!M_R;{%c3mF);Dt!|>6I?ZiQGXZ#6Rb);Wz0K|!eyz@$Qt&HctPR$@c^G=!nS7Sd z$`-Ssn3vEuKnPHm6>zl<>rbC8f9OEwSGVfD!Y2u@OUJUZN zVcoZa>y98wyZkEWF>zVcXG3J4spjG z)$;*b3e7x4Z5w5j?W&drETL_uck{2RuBcs>?^>6|8R~-lPZnLo)>}YzK`()y&+Jzz8IzyG8)mxm! zxO(o)#<6{^v_UuAqyaA37V+AH%Hkl7wKcbs^i1)*TJ zI{%Tj5GD^Ya!X`@e!nnTz34U~CYp;BH%CnEQOaHEYR*Rpn)n(Tkg%>L6e6E5y66{P zEGw+0l2Wb|pXlK~RzA=;3yM4bF*fB~2f9YBLlTzA9mh@BO`7=5RjWo8v!MxyJ&;7? zIr9Hw5V>eM*hT=l!NxaqzG~RVV-6$ij#NhiRK~$D}Js1jD}gEOO)NQ*KJaFR_k^;CQk- zi{^cut=|mN`HL17QWR4L<+bOYf!aQqoPT|FLhiPP4BIvk(jmvi;o4 z9lL>|K`EwYe2@5N50VGz7$MxMYdaaUAoyN7)h|wA7PYSAfjSkCsh|_+|1&7nbBl3i zdVp5@d2taqxv+eDNUkqT>-RS!fBooI){D!q(WYf`e4-AX==`9OkiXu+MDL=Xth=kb zp-QZ1=x9-Zd70wHy2MsRuW;KF@5kVZW0LB)i(#;feI3h4r)OuIJfFtQ@}3|Hx@^f^ zjc#+hcPeNt^2TMmDW`IqqPn6sv9z_^pr&ip4arXKVv)szbz5E6I=Q%4jl|)mJC^d< z(*b?~k86#q+V^LW(F2a_c;eJLDC)s{YyGhv#W#Zg0T=IRq(ufjI6EG)#u2QhoH_rb#A^y@7IRNH!q$M?`aQ>z3tqvhY4QUW9JPI) zJ-Pl;!nR5M)E9=OEp{i-R8qJUIB}eX(!~>OM!bP$5E^~A z3{C{5=wb3khTD>n>Tb&Qo=&69d&PC&eC?D=kkE~e2~E}nEA2lVyS$V+oUMwedC9{w z&$jI6fH`KQw=@@=?o=e+O<(io>#xK&v}d%w9I2PzPJ6!^Fhj_pH_QV%6VwGxQE86s zCIuEJ#b#=3aN3bs!%u!VuvkiqbM=z#WP6AND0-kZ3%Htw)i}x7#LRk_o0K5t#X#l} z&JyXnF2(O=z!7kF+R?85DD%WU(CP~+U*P6|=75$esh-t0t;6_J$4TYTlQv%Is+;l7 z{B(Nf0jy=Yh2RxuxokGKjE3p+ZWU$bP4w<+A$pVKxRfkZP`U*PKRw1nA9E0Ik z`mT|GVh?8=vHqnB^>MxmU;T8zUde>B3q)hK*VJ3ftMNh)@7sYw4z0HJdggny*wnv= zawKX%7H_NV>am@^Z(h(#fh+P#^I70oOU|@Nj6Rq$kxK1Mdr_Y+LoG|9Z&1VeUY`V* z&8%y>z(!cDlo&2btSPW(nZOD=%gh-}L8N+HSSr*AJ&x)%Hx2}-5b6QkKy+}Wx1_Db zmjnzzs+rn>fc0<3x&R`_y*(&;$z^sqjQGpRMw; zhVv96%tLMx+!`i^&X;60_C=!cEzjsqcNCrxeXo`IesO8#m8vstUu+ zUj)FVbkEsaPM62?1>fc#VOd9}ReO0~j$}~I|Ck1Xe zY7D+9l*B({8-pa58F!Ao%-eO8O38^e=b)R%2ejI22P9{el&uMZu96%)-P&hn_T$aG z#8E{6*&39XU&KRcR1k^2eq)D=Bt0~5{>7il4CIeCQb@kiBPxIvbI5DJb z>b%Xodk1=ov$t&^%jJlC>>|X4P58wnr;R5Y8C3<3s&aOJp_&@CaO#W&ZOGU1<6{~! zic-oyVaq4sLS=boX=}oY2EG#lG_{%{t;n(z_{oZ~HL7dehD{y)zapSY` zuA_pN(eF0|`>meRUHx6jBdf@~8HsJ`=9w>X+lld0KxOzD+AMA;29Hm*KRp+b<^L_K zO^Foes=VO-WFl}KGZ-!%qRbY%BX9rPH=bv6=K#nPIWe=aTB^+`y?F+TpJX%~Id5Zg zTF8FIXEM9G&}_|GZ-_&CXF6@fYE5PbaHh2JNV&T zzoJVcnnlY6ftM^o?PqQ*1?%5QBWG2-YtrS+3Fl{=R*Ab>RyD1uCZE#lMPR9~=aAfH z|A@@6!d2rVXV^KxRuuHG0361gspnB9^b>m$r}I$nD-J=-A4!j+48ku7A*ckyaRYtG z&M~C+_;683cK7U_+W5<#ew&HNiTe~TZ0B`A( zQuf5ApxFJU8rk|p6#K=2i+`qkyCNpSZ9})gLXYEQem)3va_eO)%)MZDP41nVxdVQ4 zl>4*Xa!DWpPElpZppo{nM1d+ZOR);yEdyas~jyVDnzJ60zPxXzWg za9PE2A$EU+li+`;wH7MGQq9a#SE?*mmD&#LL*6Mh)`pw%5Q`;_ATK4G`NLZ$_MABY z9TVd7dLGs+pJOLxFBrEMZ7l~%+m-W0&VEoGl4>?7y2zPW2jxcbcrtV`!&#Pm*tBqCxy((;NEW&^$|ETtp61sd&Zt8YJ zRnlmry}${Vt9h|Y+HIMkQAIR}F|(txv~&jbqrwqXl7BwY?ClgaD9w7;x557RHNSe2 z3wkq4{yVH^!?;W~{f22$jqKUvr6{kH$&cf<$d=?Vd%40{+{DHcGkbYSSClqulTqi5 zMt;|EN!sn66Mv0oWsf+x$%-nFg#+Roj!`~;9%%}j4{w$hQ0*;k9>zQ<_zV$@0MOlC zPuzvmRmmtjnU`4)nxy@`#hbJHK>x}h-0I?R+WohiKVN~u|DKTq8>f^ij5h?4Y5ZFJbFNtX4c$gCkF z)G>(6l3ui-3x<;n+sC9Fq+dDIH*8XxCn-2ZJ4q;$;Z$3HZmYN}k(g(AU>!ACg{Pr$ zv4kyPQpcUJonM@Mv~`&-+X&|2@lhl;<0eXIo0N}Tq@iiUdVxNtcI|tWpz#d8v7nyw zs>DV-8FK>W!zO&o$T^wUp$h~w+p;J6R_?fKbZ|p%!t=4Mr|T1+BEMws*9%tJUnA!P zry>5*y2$0Lv(XzhXkxifLOj@XPEX_2qZl&wT{;Gx1bI=zp9Xj83E*K6DA6x}kI;)6 zdzh}uzeQ0e;Rn(ZvYDkwVP{0m$rpX(praLD-dZl;lidN=<8h7Gj}ZI~c&J<%*@Mr9Rh=3O79X20RKan;0D?IKVx~P~FI>@>aTO z-{fRW`dTY+ioQWgq5EsW-5%3ZcL`%?9!0uT8dL3=9p#sayur{^P{KgHi@THcLUxYX z234*bn=CUPsfGPb@ntcihrmh<*l2{8YIp#Puq??Pn0feh@CzWI4{25QV%3qeq!(1W zu)A-35UqNH3tnx41LUobc!1q&M{inYKaB7&*DyTZO#<_%7 zj9k?kZP|@h?1k)`WAV3X{=Wd9e_H04~hVuNkK z{#s|WR0Id7WXD0iCBCg$tCEEN)^a)PzC5VZbKGx_b&e?fw}60ppoWAg5&~(7y%wkH z!V4Z(pq|X9a#}R~WwM~sC{UTd{oYIk4m`ozdN|GcliG8`%uJ6W4uqAM<)JB7cu#8a zLvcyw`>ZS7YuE+!3iRp|kCaOX5ZVPkL&a6GGZ zSBkhYAtCpMIMC?jEmH9*d6?Vz-6hZ}SbK~*gf|bx&eOg*7Z8nX1}EyD6s7q7i?u{$ zk&^38`S)U)P10GzkDBnBtls2t1MQntBU9B)_NK&A5Yi=`31?F7;6%HHswIhLXA zduS%EeuLtIU0+!38d8JTQ@3hE9Xb^0b}xY)jU+U+;v!}PephIfi|WrIUABNbo8mW~ zbez|i>R=(pkq4wmX6CuN?^@x2w?AhF%3GBirbOesgK$fK%DM_bCjw>^868gRR5PAz zif!vfyT0PLj1sR&y zJHv^7|4|>zc)BV#W`*?WWtHV?QoU(X7UubIZaGJ5yC(ONZ70jTx&My0NuI@Qb@DU~ zo@$+_nWLvvt7VGZ=Q1|dYUG0I7~i?JX1IY0>2<>4W|ME}ENyni#OHI3QoT4`E7*qn z#lhYJK``=oc*9h6cc|M=p3|3`#1dEQ= zj}UhVDek1M**fFRmK$n$Wa+1FKTq-QyQh?({qNrZ66i>UgStbZZ#0>-Z>?93XcQ}|G!S6VM+w;puQY@c5@H2p}MvYWEDrqnVi z%_;M;YwEHo_UAMb;%=s+&?PT(aWG{?Cj`A8nDsup~Xf8 zs}|!kzxKNSX`rS;Fc|sd& z`>b93@>>hk4I)D>rn~vOQI{<=6?(`Q5^W+ZfRUVcxh0mRWy6ffdfNQH1E}8O&xH5vK3{SXEt(SXo}`T{ z`=B;6nCdJf{1bxSn_TOQ_c;(H#qE6)x`TMh-eTDwG6GS?ZI8v^`h_D=k9@Czfdjyput7V{Ck}l z+1(}Kdjs$j)cW34GNL$Gk&8St=oz8GL6lC!r79|$i58iLcRRL6cazgYZUTMkOxVA< znv7Q57PKAInjE;EUN(opm5mn)n%I}sOSPnPEyx+2A9m2ux6?b6coXA^;O6uBI(A6{ zs%7YYUoUnq2X5IDH;__vQ4Mm#R zCeH77v0tJkeCo^&9fKG#>c}D`R6U0fmot(f>h2rU{yHBX!6O#bp+_!4*CQfB zHRdV|q0MH1IcmBOm5e26Qr?s?<cphXkUAAI*Ys0Uq59T!$F8(}*4Ki@~I z-VwZRu)NX0T0`>B*Q$Rwx*rR=8Cy|%!E4rS$U{Rz&ly`U`0wXapEUoe4fi~{o;(~< zQ9;{K%@>Vp*H8aGw}$=`EVf?<(Dyfaoi*)(qk#7ch|@Q2-^*jhCqK3Ebu1{;oHOn_ z&H$D?bvszp-xRx4@*{84*~Vuks5CT(l!AnC4wNs_0O`eamrxCBOhNufm?4_Xjr8@# zO@}R&elSpJl|AU+2g`*`Yf{A6lc#H!`v76iTNE&G_7uO6kp$`gqsH$}Huckq= zXjdvOu#8E0wjq+nKyyEvX-`5;EP5qw(A1ez*=MD#)su}>qGs(vD3>XHHt2_eq#Ls|^HqRM@t?7E+v53TF1tt*Tk90c5N^FC;^4JK@} zZ@wS0?}1$!eMerGN4v1z*RVISN$t@8Z68}(Tc7`8shdv<)2>PQZ%H70$oXzUT-Vk% z0}0=12>U9UHr>s{!zeF)hC-7jWsNtM-;nA>0JxK5O+r8 zw7T~@1rBg+gezFe;B-xqW0=%loWsUfr!BBjb4@wIsX*>=lM?m3iLnNvzlN(B*r z|5ppi{&3Xal{uwnIbA$ErO1!FF(V_D4s%L(4XP~UZSw++CrpMJl*5^sqA&Yikehibl zt)rvA$5n^g2P6~Ji3U3K0*zyr;|AclfZ-Z1HRJX%Wk##7{M~dv&&0z|-$62D1l}_)OD8m-(j72aQ99fXQX+v8?rgdg?Hda#^I0*P?jgG+H!!!jM=K!XL$&OZG6e_-N{4g>M~v=) zO=GP8k;J#bH2bf7*S@IRVc=L$yDiVBoy)eX!JZySf`?+U5+3j<;$L>YS%cG@T(&C0 z`Q7NR4rkZFqt|S^BZSq&ec254AHVu;>pui4#G+C_BV*5$yDfk@);(!;oGUBQXDSC1 zw+UCn1bft*U1o+BB1qq&85W#U+ToQZ;^T*;~}g z-00KDo}^`Au@e}uk-;Z{E)$Pv%^pjmz z9Z#E<(22JC{ms7_g>Vo=TS{n)zd@3Hl`-Ok&-kjP^J517Xc0l$AAwt3+~al9;ju1CUBueLY(L zqDVM<0cCN1G65A^SU&9!^br()Vru}3@6`ew3ov9x6b3kv^;LJ}Yx>j!3AQ%8Mv@Uk zD*-OoqxI^H_I}oWQ%@l^e_=xsnwG9m=}Oo^-sE*g+IxP+Cj2-SQ%Obje(rOd*al}p>s}xvZne#7J4~?Fi5`Lrzsi*DU;B`-G24vKw5Ve z;i>pV_{n&y+i3+I#?`sW{X-ZubsOx{kkZ~T$5jF#N5H^^a30n`v)JxS3fRH%^h?TW z85i`OclE(Njit_3k-nKK&HLL#^CkLeP>0j@IJANs+fx~TQA6u{Pxa6b-0HtU?U2u4 z5(3hd_rEv0K4kW7FcW}k@r-rzHnC~{>A$$+YcOWuThqEdBE&X0dA+A?^MMY0$PkX0 zZQd8M?|`GVd*U+h^V0*zqFEFNNd?7hT@O8CH!MddBNGtEW zbM<)iX7vT5YtvX@FYQxU^j~BVu}nc2;U>u}rcUh!cF$d7wtpFd|6N}Gy=VP%Sa&If8UY=bKi}8K`cTD&}^4|$HX!EgXvjgUf_p*b*JHxbX5SD)7FUT+s1JUq}4Jm9(R%lh|{ zwa49c$9-es{b=%BlJ!dYA9s8JT*v21^=beF@5`M%lnT`ewM((HrMA0d&5Ezj9V&CjAR$MRY#;MwuO)%5Z^@wd_Chg7#=MLvx?o(CkR2I|E-V7q3k6`v`tLq6MIAMdilnK^;F~nJ zuT-(}Gw5Q7QY8KQdy50zpM$|sJxmQW9AkpylxJ~@6y%?5$}bK~wq_M%7o&+!i8kp{ zYC|(GVLX)E4N1UZQKK2b$?J*r8jcnngsV5{Joi{4tJv$xxTnHNZLd<{6LP6L5QEE% z*{qARbdAA8Kh``9ohp*Vj^8rJTlDDf!z*>imYxR9t&&kcUpNSKiPxMjcG={92;%Ag4|Fft-4dd8;65dTv?I$g&mZMO$T#UZkAzyrat@0px&RmCq=2$f zZF!pPFm9&5u|$^WW)CUI)DqN?GvA7EC`Qx?4rZ1pKzDvJPc0!A)ef{8i5b&W#5O&LgZt_l`Vb!MP8dZ z6C=1^u0a04?fEXV@QWa6gaXW61f;~i&n?&?lO!ENnHPDZ#5InkGc7!zWKO!3JHL;9 zkNPwGD*A63c-Er3Tx66B(#_uLps#jIA!9#D{27)pTz^; z1QK^mkO&y8>t#IiS#&qt-3!E9y=9t8aq?Q=Fd18^7@a}_cekOSX$`8$gA=}8VPnhg z&Squ#UQx6Wj{~dEl5rlcTNBXx;P1{+^0KVmxN1O)1VJseZIW||7PmU8&js!!5%4CN z7hfY7#`!WeRsO+0H{L2MbdaYUm{e(8c}{I6^jJ)_QfXJj@Fyh_Wj!s;Q7 zj~7(!NE=&bem+Wv{9rpT%W{Jk;a50Y`SbO^N0ZWSW?YB`>Acj4^W=^OAz>MVn12vB z(v5s1WA*M)b<4DrbUm8rSJJ;>`MVX(rFkwj-Ayc-WZjvIrtNoGSnlpSv0f zp{W+&&;A5%AQz9RNuzYv1H%tFlc_tAZO`(){KYl>+u*1Cdv72zeYA`CQf-6tEZZs> zRPxom+QgIs!2TR_R4w$yK4V3DqlGtwpv;jV({*k6IzuSUfUi$3JhbQbhkQW8{@Z>F z&K=|^mH*Kn6jUv_h3Hkb3ywvWhW0FW>tHpfLuDTj8Ms-%>u*vb4Ikp5(Vl3RP+1js z`%9bmIi;^yg1j1*$>WndyZw(wSF$tX=gCU(pNH$rVp=l?Qqc0e1v){yoZSk>b`0uZ%q_4Hlhm?8{Jyk|))__6O9qldbN5 zJX1s;L*{@YN__EPa_M&$%D5Au)X~HIs;YUaHqQpe=`UTB`-xx}w zLE=lUZ+R2=#9a@3uh^R$pgg3+xOQun%C$g70k zaN;Mfx`SvVms>X`4(AfHrMV|}@_j{G^nCx^ZoF`>J*soxwzE8sjZ@H*aj%(UfOKI# zg;t>Dt0MPx1m2oFmG=0c`B+|I<`K`qhWWP^L!M$e@y!mKpcN@z`Gfd3Kh{ekzhRa4e`uBcvmIj@Fx%{JFN;TYuyO{kmlZu%(7l!E1w=~&)^$8OQU;uKQ%7@V z$dM5fom^Wdfd|VVP&#sT7G3J>)l}NSw59v<2u@zwfrri$XP7y4ms_FB?>V)?fZQvu z`<1FK-1iuyy^cY@K)REF4EnEKo_FyhWIk0X+e`t(~k+Djw=GrJ}$a8cc+=gg%e-}BY;@~Y>)1)zQZITpLov#9mrt1@` z+J&))ojkA@^lsHFK^JJix80ih%m;H}A8MVM^A)oITC<{yo@&ynxJ@`CH$KtmrG`!g z(x5urwmOZc34nrzbAYG>eVt_(kLe5D)X!*MpN2>x{HxPW!s2vQXhYoc_oFB^~3%xDsA-hbU?ek{k4_f5}@fI8`GSSXA7K_X*@~ibiOW zT)Fd|5k=c(gA$iT%>TVkrG9(Run4_b*-rLVeU2ZizN+|}#mr{hq4i6ThM}Q`EFgtT zYmma*2D|6YeJ%be4+pxzM@?vxvh1gl6y>x)*OQRrqb9b&oyex{Vx+U5$ZMrgA`C31 zJ=)jHU-b(d>n#a{@`I!2_nWuu$ba2}DzNL#@UwOHBm>*6s73D%nJ&Dm=O*|7^WUg{H$C%%^2U9oF0Pj2x{+!2R#HqF-US_a!{kh(+8G#D?Ql!@87$7Dvi{3o1*u@GR@Hy*M)<7qH==;vcj!k2K@ z>DzR(p7Q}>jV1*yS**XZ98aigaU8nix9;TQ)VO`omNe~mS6py_S`czoaruxAICFNg z>64mqx5>)j=ttr@{S(#B%Ol&0Uh@^Nb6j#GJATP}CcDkX^LwVsP|>v>;$_|}3Ov5l zYm0n(e!`kC7+yRm5s)?Ui?mAW*Q@NH+A$6R8&dhGOm~_~sYigxb9Sy0d%h1+go-ctAe&6`#LG}jCI`i2O{%JHFZ1Z^bJ{bCi|o%jvaELF-f@@4J#5u zK;Aq_SSoI9&M3Jb1GF4R{5^4eo0pbVV;42aEJ|vGhQ0`+vobdO7vff?{%l+#9Si zFfPQncp6^`o?2Kq&MfsPG$%N(a|N9P=9hA10@pdadfc&Va72M(!jntZ2nJQKn?Q@% z8J{fFNYPbaiK{{{JUb4{gd?Ti+4dV>m&B?Kj(~knigq$r^bW*MBl61Wyi0ELJi@r7 z8O!7tiK?9hL7}tC{3-7205u2hdPpP)IOHq54y=wEg27t!YDhGtO1K9m5`uPXR| z*!X{s_fW1#xXOdjEN*&{nM5(%=Ua!sZ8{#m4ie7RlT)5u8>e6=>%04t4)~oT`+VT! zeppErqRs7W+5^L%4jhR}1fB1*7uJp}MBJ}u2hc{fzrbd z_`5YugF<1o?$r4cH|V3*I9{l4Zsu0x9D#UWi`3M36ER9oRPm+}d@su0i|$~KaIUwN zY}0Tmu4Thm>7!_q_Rz^y_39vNbnPr>Txb1)3nH>us_l_-I-0h^IbR7YDox&@*EupV zYqgKFD{42FSRA_qCxHmG?q~vPpy5~cZcOBTB|?7C#=dtF@>#w#BjshQ@EGu+qUp6@=`2ik~7B{YRNuMFm)3C zvVvcp%QQ%Yp}E|85xH^eX$&-+cV+zK)u>IgZ*`X%g=DJI_?$+k&ghVi_K^Liguge@ zo`KB1_BiRT&rXYW{G0Oj4#3Gh29}U{;}S9Ry_F}_KcvUou#5@`vff!G;geRlR>iAL zB-qcL(?9y7UI1(ZToQ_Wxp(^AzIIuERMdJfJVjze7id)ztVCihE=~oC9B`VsD!LPI zXWkz6v~Vd^LQN)=4Hv@V8_1tVmyN~dR`N`+c^8GZH^K>w5viX2!y(FKV03p_9{L?V zlYoq7cszWmGO+fy4jY}~zF|j|0D>2H>Lg?M=asDWOv0PSYL4C{oU)&1iJm~m^+rpG z+54tO=u{Uw)a`MH{uM$Ra@B0Zw!0P_kmB zy6o)i^mm~fiS*QSL-(3vJ#?XwVZwv!19a(%wGw-ipxY}oNmbV!h%SGvG!A)CXVx>x z=KeZks?K|r8UU_eFuG9;oqfymM~JlnA`a>pM)Ic!@~IJIQCb#aO7c*6seyvwN`SrP z<5y)-c&MRp8%#x+gFw5c@B2@T9*isMzm4`a{3xNbBFG;30=Cygi&>e*%iCR#jA5GQ zgV5@KOg7fc*${K#yVvZLS&EDEGG?KwEjFJB%bX#9sp$&t)L*Uu!6T0nH%&zA8AbJ;x33~jjn-7Nh-p7j?b2^?Un=oyu$axY`}8TY_}t`Kw*q$Y#LirL~eR(ueCr|Sa;8J`%f%GgRF4DMM z(y%IWFQo4!Yysk!ldeS>#w;QiAq%&_*@zmX3?q%7D`pLFslb+ARI`2H;b^6|(L!Si{T)hccT$ntz z0}L7wW}L2-#K^=m7gw=mv$7FLH9xCga6FrHH_}5VX_-s{y1QvbK`bFJPw<5m6uigsR}J*HEQ?3-G-8CXT4)Fc64RAZBJOr>J!mwnex|y zdY2WKO!vHJ0D=c|czm__OHeZ36h(sGiJU;YBOh}yaIc`RJ1!Oh88tN(KIFRtT1-Ns ziY25bLn;)Is*6|vC>#p2GmVJL9>JEBV1+0G|K!74`$s&YXQ|$No|<76CYdgCJy07K zcW9C0h_E|(bs9(7-ko_Gv#$HoTI)Su!F-_6V! zxL*#0Tw^G1?e}9cVgRMQ2J7R(_%Evl5p($;Q@cZRSoZo@xi4*!cGZOxTCM9A$a3rA z?9_xneHm7VtVSjf(~q#akHex)l+lDlF~HENJSa@H?A_r&TE@|_{_>lMY0?4RKuNCb z-Rd5Fa%F6bV(3&{3HIOaXIh$i5S-=EE~KR_Sb&iG9XTr1fmBZ15uSYCk4#4VGOROM zM@3Z6(MotR-YDnfhLq);!+}$$VKgOX@N18UwL~xhJ+1;pj>@z`MGO47hCg_8zv{U- zSY%@bRBxaR?`)MuC-WM_MBoti1epcSl=!mKHxtI?M$zH&>=GPBr#U3EWvdfA*HBcJ zGwk!$=Q^P+u<98?-#z{DA?3;k_Wdm@zzq6bCy1{E$1(c`y+#{gjt#rkI4`z$Y}bx2 zNigUu6i_ZdxLu2ue1kzW&^r}1sNykwPBDJLp{E=gdip(6-~Basf}@yeS!w3B)M`&a zht6$DfN_Bs#-A#S97EaJ0;|kbY0-=3MTVDC4i@!M6SldX_^-)*+Hp+?!J2wtRRSu9 zwpByXoI7UmIpQ8pS|BkNcweKu;CG?U>`;^!%In!;i!C`*<=>}q5Q!v(%PgIfAd*OS zq(4%W+hVAi`$YBZaFp9lJyNA_5$NIaG_Dcj`m8YkA`Ftl`*P`V?4h>*sPFAI58iO> z%NLo)u?FXXV=S34kmN#X21UZGu8qWKdu}+Sz1K=UH{s#JJyOyimynNW<~PNSEQcV| z>;$koHb105=zH^9#LkmmGOrHkFyVH+yqbP!`CSvudTtTqFb1~E;ZT2=!ZX6$To}f5 z!@IG`S3^7F3eaaGx$Evg50??H`Q=6hxFppG;=6!YKy0dRk|9~8?^102Q3bQbfpzy<=bU31 zou*c3osdaHVRY*F%4wQkvQ&`6boli3Y$Tb-Xw`LZ;OWg3ms+zHmctDq#ic*4BSaYR zEZu3$yYHLUxjYzy=JV%y<;_%>NxH(0g2T#Bjz?vQF=6eA4N;tv=jFtg3x^7~z@6dp zLGY|{qa>Exdt?vq; z1d1t1l;vw3J_^(yXDo@$+DIr{N@QbX1fc1<1x&>8bo*(Miq52;S%IpB{3U=S#>8s4 z?kxHIR1#h+GXzl~nm2mycE;b>7C}@uWj4?bM@J~Fvt1kYc8K|OWD5PO%OJ+ z&4;7b%u&f0XdkK8;o0Wv!KOnJ*_U4$*+=CDi{PEPB}+UNwzjZu1beYMVU)n-3R^Yr zVAmEXHlA50;J56V=79b&Sn?j-u5WPN%s{Z+>m0FnK?ROBK@W(sLbcP^1}|$xV$lVi zzj<~65xBN?+6Hm6QlWX(y>{v{W{rLQQzJ^A{~o_#HCbqL=*Tq}HjcIBT_CL4CBHJy zLlujBp$k8oZ`?;dlac=(PB}GT$NLZy!6I-sI-do_)>DLx+4>%~hk(_1wm)FzN(A)R z)E?qu`G~Z;4Yl@D(;;mRj^;5-vlGvp9XW=hY}cwOo|h2ioRdEBiFXFiSsHkKgxxHs zK;Q>0#8(O4T^utGQl`caeYI|wjf#t0hRNy(SP%Zp|%{p}+wkQOOz!8Y8VMel* zfyij~IstQr{;weGi4AAGLJ7-7C(;j9wrvq}DX9+9svYNhfNlXb$-RBidAn)6ljwh5 zS46|ZUP;mJ6PA}0Obl2q!fM7o%!9tcxF}l*_4FvWVGDP28Uh-cT%I@u*lY^hB?{pL zEu`{I?uvGW-otZ1^rHi}?+7+NG^AL(Kujl4^rQ8Wt+kY@K?kzpmT$4o#q3l8Ms`|>}6iK#elsN3yDq%ZH-*Rq95%Z z*#yPc$k{*R+?|X>?c`--)SY(AAQOBkCpxPN(?cM~E@0~N?@2^_qxaUzNYR37az`Q(a*?1 zOuApG(lA{1%g#)yyo2|Z_d)9;8PDrOmJrr#Wo9Sen)(Jb$rNAQgwUii?b1iNxO9v* zN*wn&0LyDu2Ebpq<0YRL$2;2Tvksbir#5U}zq3+8?&{%Zuyn>Ek!PAJX@J!R{U}#Y z8os2^pw;Q?=zX>E>9_bk24(?OQ6Vp}z-`LgwvCB}04YqS#2XznL-od}oRrT~Cn|Iu zZmfnh9+@fY1+jy(`sYt*eI$)10PcgMo@N?H7kr=~j}}!vU!RFVayz7(=LFyM^{yng z9S#Hc0~5=pl^^}tK=_aY5`jU!lNGmJIpK)0U(L?Tray7j9pbMoVp-8_9{M4khKPNu zdk$Hc^YvPoL9?`Wg8+7a0;onaUR}mRa-RQAk{U;?!s?o-OmzrD|M~lszjYg%LGJY=hNv1`?Bn*IF3&wc|7pvlU!kMtcp<7WEe<*pf^}>5Jo0Q(+x@ zxQ>`07lNx<{q;_ut8pLyOh>^PO9jhTfAXTl)J#NXRD9>)T7&QezWj%I-OV%yvudV_ zI*(5g{NncU1WP#@8*Lj3B{AhNT$j8qY?J7uB~vQ*&~64tRON=HY8hX*d5CdmYZ#Y>$HHfsw5Cw~u!y zZb_m&ofG5tCR~7&pXig-q&_oB9G3N20)^5N=ds>t zQ2!oU_say1Fv8KzzCIGlQ4=g_d(gfo#7v^$Y3Bs-<(f3HI_{%`T&-aOvgCN(HD$wQiX;Eiv$N|Q5S9i{uJL#KU3m$km3)u4 z0ciENI+F<(sP`??Ua^aw*b;H^E#p>uJ<)mSc%H2Do3?{cVw4`ERaRn7bY#3&^&SS< zlu68-kd#>$je|T-=4d=0Qcqeif}~N3nl_3}9iE8+lg)RUsWH*9;_E1ZOSK%o(y%d1 zz=MLD-2XiwW&%v3>8Nwr$xApQ_>)lc**uItaY;0*M_-Hz#<6`lULC6pDU~QG*=Z3T z`F@Twa2=JvTqP1|aL4vp^eiDDv+C3hDj@)s5duwf2owEE4_tl=%RPk6!cA`fz7R)X zhe;AsJvyb|?ym($aKsMl z-mRQ~l@e*k%e zQs|V244lq62-s`TL8Q5wHKZ3`X2IM6jyD%GlD5`1&Tt{8W48`)pn{i?aliy)%GaMk z5Rp;iiasodkS8pGGerz8TX5*fh9g*R@i)w^kF${6i)eC^ua*#TjK%jY7(2e$Tn3{6 zKT_y-JwJu^ZX*U`8&&lMPTfu}><7gj1n<7hf&3GlhcBmLw2=0R1pYTY9OxCU+c+dg~7m&-N4bU zZj^5f`&Mu2e%lMVKrT%o2oP<%<%lsVokp^QbFxxd%lU!S&->!%)Nn!4@uq$!vq)d; z6h6*PDM3pHE@zcrfd-=8*_fr2*g%Wv;<_RCC@uc^<1}X#|zn{2jbX#9yYkohUa^;c^NO?MHmO zp8Z3C!vT#9zV?`>B ziyluc!{7x#A3TK<2tLwaakxQhk)FtkwsV zvO-}UoD|$M3lSqOD#RQPdfcQw0%mZb>{Mz_-k>sd5`B={;Gb_bkmOr#&e$cH_FGiS z1ldTxP#mqkuRiY!t~GzOAZZmcv2a@*x$u(q8X2w|BNeWH`*pCz0CR3qaL;Mw-#Zi7 z!kKPjR`i^IlJgth%(0u31=g>yh-m>ZJIM`}P7hqXpEo=^r?e`{hfy#D*l50mbUF_E z9mR69FXQ&mHersN>4K;cP?S+ny2&vkvDk1xikhEAXC27&99qs)!u%oFMtwj!v*5pw z58@;vPi3mh;fe>L)q0JUJi<@eWgW5|jv{qBGE^_HGuaIr1y3>?oeU;#{RuWCpdQRB z56HNc8BE-cUK_Hq{d$#%_Pw0(_iLz2L|9A%!56kX`lr)a`{ds8LRnVXm>O(+hSTfX zpYTs5^q`+6e~b;1SJK{8Y?B~EoFHOyW~0h&6grb0)kU0I7GA}awlo645rU((C6z}V zcP$^Yqn6jPr{WLi50+vt9zoFV9M#ioXO`QG5?i-SK&I%}t3|iJCT)|2r|yEOAy1%2 z*mI`eAc{QABMzC4^L0#(m7Q_zc{m+H;HJ?bK1ow_j{2 z>uyoLjO2ltefg)R`t7NVTI;6YLc{5oaGlL@X^`M#sAx1=3dH zur(hqsiTqv>aV6_GFVNc$wAN6;ymY9aEgeg;lTCat^Rny;Bq!)=M6rf;UHKZ(2~eZ z9hH}^rL{oK>uH#mkkv5CR&cAiPTE*FQ%s&bB~l@9GY)N%!A(wBY8DjU6r6ChthyL2 zULpYP@;00$ClU-R`lSEnF&2DrMx{Z%veSHZQW13^tUBgzEW!X0$YC)>Qn@l z9q2}3qGK(_zd#5vVMD=H#;CgdD&>jpr=oA4)`=5`bI^VJWhTSOWQpUK5!=1kS=&ND zTVh2z>wncEWaKA==^jZ1XAGQ(q}t+*0-(*6>7eZL@j&p`5`ghJc`-2mD56I($ok=| zHb$^ZX_R%3^h6vI%B_2s>-53ltBqDrh1zKfL44~u^Ty;Vb~|1&2BUqO1NU?eBnz*A z)m(Fuy|G=AASY^iVI~={@TiU%bQl*{Q+zh#O1W7(h$4@AIQb4~zN@qvtK)=Jf6jseIqGkF*MaQ6Wh-Z|EU5^@c(;Q@L3vT z)rrkz=#?-_$BgC0ZhVN$Lgv#OJ`*y}%MYUuovsJIAVXTk>yM@Nbudv`0Uey`Z|_a( z!cbUT&vR|MKAm5Uak&Re@J(s?=Xo#|Oy-`YuRQ8E3q;oFag2(N%mG4}kKl0Z1=%*y z8K>9bw%`USs613Ry>!I9vJL-G*i&CSEDXPW|C}OpB-zg13ebUp+M%tbyTfzGKt)Lw z7eUpJtjEr$>(MDoLQ|crzBQ-WTEWfU5mr;B1Yq9QaF(Oj9#HBiYhC~V>IT0<5{SC8 z{@R1;UTkNsv#8M zW=pUbxnG!|!nkqhP%}}O%ILT|)9H^`512ryf@9K}fYdn^^&?fSe*N*Ffx+W%6WJ%x zwPCgrE$~xt5c~Lo(iORmEmkuN7itLdsM0ST@p4@TF-m&bjbxzoG#Ej?!)Z6QTf>9W zJL7fV^-MTZ(w`T^>39(Q)wg!;g_Cahj{g+84&7yVrTu>J0s8lTPNmTG8*p0m=I#D| z0cLT@%@dTP zC@PPe+-~pa&A<><$slOS<8}tnkn+nYy^5N;Btw^kAf?CD0gI8G)6<6 zkMe;-?nAcKjq9ngUT}e!sMR9)V3l_+NwZ4Lkl&%&6+#Y@svuo=zOIXsHy}^3wH(TG z_{&#!-37DEFnh<_jo)}ET41kjHGwE=ut(9A_(4i?kuwLOGVdgh%Y5f|_i3vizK4&? z&RS4|lSCaj#|V|7*2p+drcrB8Rkwk*tq(=UOw$yKipyMWL4jop@>)@TAl{k@h z*2~*^*fqD1n`dlP+VVlB3l0X3Euvg&*1wst&!pB8eJZI!!F=oVP$tDa#4 zQC@XU5UA(Msb`9p8heH(cB%(R7R5N&rQJXESZA&Ecq5f-&72wwAU&TNfy#lsbB#ff zGv<#L=1Dj%;geOzGqY7HYmWHZ&VV7VzxIK8HxQXHhJ{q4IZOom;9#aNW^N{<%5LJ2 zy-3O_D@NUtTWWmWZDzFDPiTxHz($bEKBuCengsQM*j+{h?pmYx7ITKFywPucGtvuI z8I}iGv-qb%U#$hgz(<8uIX_k$H|7qe3nZP0#`z=aMVPbsO`!a6W#VwDp!*`>NrrH4M4(G(4fS<-Y^fS|H3g8=*4tpKRec6o#>cQGZi*kjo?0D1! z9jJMcf+;Ic#Vk{2xm`zK3?bD7EdR6My7QV<^XqAu-9^LFE;rbVUA;&}ogvoPwjSdjbS zN!#5$2riJX08|pShS+10+@ALmsU~(I-h9Ax+(E9*%qs(AV&3P{H$5{Hj$nRKB$)b; zIib2L8?|s9u;aY9ge#3uNj>L;X`ny$`u_VAL8gq4!L!ipw+_xJiJU9d>My<&!(YZY zFCt=QVmo)@EOXwBsD-IrdaDOPK4l+_1UvM*rTTsjeK0|NKg#rR@Pd3zDWA1;r+(re!>2fzyufLJn?O|T z?@>mY09_sX`){>VDDb%{$%^PjvkBb-YMFgEJ?RX>-K3GU+IiWvf$+e#= zbLZtYTn}jk{*@5#7fE8>cEP6Y{qgXBFFEK~n6Q`KYmfa;ht6J**KrU81mSZxtnHdr z(+=3uL;$upd!g8X*^AfzasQfk0@=G08Mqw?t7v8Sus)|8N&*>G{P=lt!vwnCN~7wv_?D@PKF#P44``S=HOoO*`t2X!)eX2LmYaJl0M5nn@HMowJl zX6a6D)7OZ*21-WiBkO<2&ed&Cp5y~>fu=u>Z8Zm#W{-gZtssfGHOV2yU=x{V`Z>WH zsq(XLw(D|ACyQE1ORzbGZC}Tfdb zya_z53VBkk&*}}<>aHfcsx4N&1~X!4N_PAW8de-`A7BC#(0Z7STSJRT2^(jRu}Y}7 zkc69!-9iJRmX&a<2-VyxE4KU_g@nBZAA+?{A4OEi&PsPP%H2o^v!ze!CjGt0FVJ{I zbSVG@CMv-^Gor7>^$w$)CsmX&Pj<0Jr%~?hM4RyAu%sKKU-4dPMW4?h@wEGs!_z|8 zqwN48S4B_5pnk^#zEs03IviUH9TpRw@CiP#6rxntnwgWUb*~-7h_(49=NG?u0NNeb zsu_spBT*^k=7a`p@q+;M;cjMob-gZB4K^(4gtc9^BI@3f>c(d2dOrM*ud@hNb=_M0bR{PnHb$UocT zrDch}4$3^FBcu@kbh4trh*e6nZXf9=!`P-Tt+OpZ{eT)qfvG8oJfhCGW14$vhr;6l z$VEY2qBq6*-Y5oR-P?0BO&ts>$60LJuYm8eNaH}w=dG3SQ zxdWxac8A@MM~(89`=q*Vl+3@H;(Z@;cq!?<1j*#!imNrYvue0SQ=}%PJiiQxcJc_1 zwBB?(jbX6FW2N}yx9&om!VfBov$~ve;lNgsx_@K4b&db(f|R@>nxK0E!(4!1C(YGP zP9%T1(otG$RxlEL7&VC{+?AA%%yngTrnY=kbr2j|q}Qh1Px%-fiH&Bz+sbiMIdvj3 zf&hr9nSI}v@=7OEwM`e@gei%K*_W9;Fgz<OciH6d3|HT$4YN8R$sw ztoy-FzsY`<_Yneu?-qk!f%mgL_m#8j_;+nTxYHTS@OcO36M4@*8Z+!}?0mTLJdewb zxUA@;0(Lwvs@*^Cb7R4C3jgql&-TgQrJW!5f3@~VNQwfBTN$x_V(@;oB>? z$NrU(>DclI+Fx+zjn`a8DAV*OYgx0e+|hWWMI3I3zNw{kTbNLcBpfVJ-5u#N{eR0O zLLquHNp=sRu9fGAyYT4_waR&S_P7n?Bq*;-2;EfvWbPQkLE=W0{BTu{K{UqW%9x27 zW@@q1;RzX2KWnn&fb0SLMbu3*SCVd@QArK|4SM;zA??zy`A&5!(npTG-fY-HDq@ID z0l$;kk+^D$;ya26uRaa6!vgwpXb$--4j6CCfwedAc)l5;>m26u8jp$Cm4e++{{6-B zH|Ib3TKK>VZDEK$Z2T74D}VC9@S7yZVuqnH49*l^LPc!%3~_T|dAvk=fHDQHVkoeC z%rNSoN2J8Z#C4V20ymu>69WyjR`C)1u@9~3?bMAtBttDGAtdF;6{pT}#CnIBQTeYyJ+UX%uv7|9K2S@+B}9J8*CWIVd${NpsdB zTjNEb6r*cR;POIxSr0cYg?YQ)ciuwhN~#(IcvwAVi9=hR<3|4zrQ|OdonZmR803%D za}(_T0?3V-{rERKGyB=k{{-81JA!wcHp&Cz_crPmmD+Vk?mp|a9r#}}lLcZI+|O4X zA@YBF1z+UIIDsqT`vbvB{V8DH)U3=pp0=nra>%JO;WetI=1eQx1=Dq-h{ufaPmdUVLj#JYS`G$#rn zHoV3Z2gXAMu{$D4(r*kYeb!5P^`E+c#SFt>QS1Ky2LJGXjDaBv?tcxFXe*oPj*ovFVa|k5H~b z`tx;GGhnTS`O|*OP?3Y(qw32Z7-a87-~%OxGgQE=81GOQn6f+F){KNWqH?D!8sSOQ zfKPou=V1#$Oy*g$#qnNDkkEk1_y?k2&Rf>Sfgh^u6oM7p)NrBpt2tdqvgC@qJ8DpD~!QI0*Y9lFk&HDU06{Kr;N zv!-=DUi$qzK$Cqwcv&6Y`;cY96gurigYXL;nR4zNq`-(tfsgeVA>MBVpVpTI;TKG^ zo^bLD{G<=uLl!!a#w$9l#yuB`MyWf|_g*u?FLdn84VlqC!ldJ~?ku{lU)J{%H@nMu zQuI>VHARE;;21{6Z%U&$H+#|Ew{etaaCwZ8`>?upzq-F)=*8}QT<(m3+peo?P3$|~ z;8E*y?M1|Q3E)Epdm?##!9!H9`1vN39|^)^>%Z!MZmt8k*4|!n_73GgI4BI>YN*b_ z8m=xenv!4#j?x6H8Ao<$N^hVe6=~Rp0a{#fc88L4lZL=T1nkx4+d|LNIH_tbYIUds-Q7&lFZhN>q*V~`v zGVZ1L9RqR_f)_h@V?f4q9OE(oJ5Z8nB%k@M7&YB=M#M!q2%9GmHEbw0!Iv4+$d}%I z%{4-B0_OX@aph-`4v#zX;scW>5_n|I*!?#Hvs>381B9N-voQ$Qv}E&}wNWVA4Rhjr zr=eVMwX-AD;bR6G50Q^07I&e*VgO)L3!~1TTqM4M;+vGQ{)p2Fpg|V%b^ADJ6T!F? z2G1ticp7}W^p)LYqDD;xB-emgszb|&z_Q!f3lC0Ms6o&psEE)&C*hTQk9!W9 zPR=&$T75-)OZs|KRgGdbL6$GrPo#Fjc;X!TOlh86sC5a=aYsWKHT*bzC!}F0=Y$8_QG;Z#IJz{jadzOX0?4tK@=Tm;_8k10?jb^fFmvXs!UaMa6u!bv!zR_e`HQvdQtL(F zd(ZBN!M^1TnBlqhKH-LhVBfTd`v0>Lj_K??B56)!>^w1S!47Px0WH%vh@?0<-7nl1 z%R85i-pXN>W9a!-bDWOz23nr*TR zgNId)rY|cu0L8Q*zv3I@8O2bW!iwCBugXN~+C}&y8acDgI`)T-HX15KG;eqze3rUs zJgb1ca+`{30&Pi+-`$e$Bn$!AjM>S@)Tob?TrSIiua=p6(<#54+Ot|k{G=#DN^%(6 zE*j*U3xhEp6{J?C#%0JUYux{6akL&zq?ibAgJrah*UA5|HK&#a+ge|g0nN*|yd9dG zRfN_c(v__RShnf`vu_n_~* zZ|y{H*!A*y-Q+xWo$URG#<~Tw$FiRq`CnPy7UkZ*>%Ok9?29mX&XXU|uP|!JDTNKw zV#s7HKk84ICsWV1%Qnw(aaj-g%K%jfKblO|u1VZgd@ue!M2Q7b&}~+^5i9C$P?YF_ zNwM(F4?_!y{DIVkB7qf16{9Vbtmh3Nl}p*n_=Y1uOa01D{QCTr+i~IFLEu)Bh;u6Q zptJ^NuXt|D)+XP3&EhCR+b~hLD`)}Hdf#70TPD}w1<76o?~$$+RJAWdO4;rGQo(jf zJq}I{NNLmGAJLyS%lT?~e6jRs^*Ej|@on@oQ3_Uq>P)%MP;~-`~TR*GQCjvY4IA|wm91@6;3AZ$Ul1?weZnh zw*u3=iSX`da*gI@N9FJ5)uVOFZa6M(;t(Nw_kYwvK=2&k%*xN|fhyGYGJDQ4|AU6H z_dZWQft}|Ln|`0~?qC^e=n2mW=YQOZt1MS+n63}7L;XJY(|gl#lFof~kTB$g@3H-S zv+uwC78q5~8-dk*Dgs6oJi+rk)W;70=bO)cg2P7qxl8_QUag0a(W2C>%K480q$lQg z1)*;()*f!(RjKvlp+cMzD|IFwC_Yn?Txz(BZIF5Bh9}#+PBrq88Jb`dn_@<&rc)Gg z4w_(se?Zip7lu#5(9Wxjwz5KL8x zBpmv9u+TVYNL%=1O+^-(G9ijPRdD=l5v2YkOM1pycwGC%Xqv!0le{1>JpqT`3Zi}n z2k+8=U_b9j$i4iCz+$|8Nua>X*dkEM0y;Kep?ShA$NG#iImJHVPRb9n-Q?qNC(pHk zKDiju`M-)Y}Vbv zXV5caXG0fNB8DvbFd4|B%M>+lko;mwOgPmf_s%b>mST3ZYEFp))Zx=fh-I>Tu6}CD z51skRbBNSu{^*PMzsJgb-Q{G)$-eDQ>U+83Yr{6pl5>mHbwF^R%7Us5x4o!B2;we#T%)kJ`qV)Ne$RDcwP9ryl$jda=PC(@tlACtJtDZ;GJB0t_I6YD`Iia+;5DFvvvdl`6fjm7@w<2Req2^ zKvMU_Fxstf1{1iT=}WkGPvrkkA`VD0;W-A+&z*)!z73CreaVdtR1>c-&dtYi6w#`UmkC2(b2ZefsITtw<=Y$B}EBnAjcHF4;X9IxBJl z?@W7Wxod~)g-g-g^1(J5OMg8Nt@)7#x>U5AIMCF7m2EK++kQqSlfMXw(7WN*|XbCi;R-P~x8 zJ-;g_qKGUw-F`E^x{eZvKKxy8j=uK|Vf@e^F~SLfyGu;e3#Lc# zQexlN`u(JQs6Enhc+9^hykqlZ;WY=0`G`FSr;hA85gc$FHjzlXu*|F-ha z_7K3DBspv)s7CP)3peeNJc744IjiwNk@>Fxk1*BRqq_t`oI+t%?rj{bGwxI#5uwN` zB>_#$(mnc+p1bX@xgNR`v!d<`)i^|k7My)J$~klC zE+KQL;9wi}GTeVbe0x?|@1Fc<{|%;S*rM1#8h(&Rg_ul-#EI8!k5>;tDbVbg{M@Zv z%H46(B%S`W(OZ5Y%iW~IYG$Eu zz6!yc5p_;D^ecMy2oPC>o6urhHyjHuL*>>xMX62Us2iAr!uGHe>81-Ij_%I=PC{tL zPi;x1O={<6T#QL4;%(x3a!>Z{cbStWo~aKlsRwuMZqhr3R9H}v&yiT%Qaj?k_PX3s z4}6D(x@~J((h)BEUkOsOUzXLHurdw>lb+b{eiha}MUX56Y-6re&B0#9S`0XSU*_N^ z+y~z--%fDjVAmbL4u`je^Nr4(Lq)D1@fnGQQy>MvNF>3zfWmeKz0xm29_Y={zLm`x zL%1=YO7I>Y+l9Ks%_ra`Jgebq7{%dgOm#Gv7Vkg>W5l^oCe0ObJNq6VTUo$z6Y)XI zRe~>~WSj{SEfUWET|GJU2Z)h(AKOo2+0+ME5=r8gAEm)Ka8Kc@|#< ztC5@ZapKUofStWzu1Sdu_u>82)aRgi(1A>dH3Bkziyr)wC{OW~1V>cW7dv+S5wSpbKe~Q)GYSAB9PcAy|1BZd7zWhROM!5j+@z-;Ab^P)3ypZ=zdZ6|DXU$G_K z?mzkD!Wj?6gf)72wJsjyHd@Q+^lZH&`NdFLJVh4E=YgslzjFTHp*`_2f$`Mbzb(T( z8iPiO=by6`B~7Z&79lyNEJtgsg*4a0m2uq=5`t0v_Ug6%yNdPYV*yp*e)+prO6N}YFpAd(ld{|n+g;6g z&%`QD8un~il<$JtO8mx7hv7ox(jeJegb0B^GIOo7(BdC0mn1(zHCaW0hiq5GH@Y&5 z;STvjIi7#ugfzcq;=aUZB7 z)%7;K1!m~~B`t_ya8E_xpU&D@QXAyXcz1t_dWe1*5f!4J9oDXKIl7M~0obh_X}FSx z7QqSG3pgt&%#$1jRKe-{#u^I1_atupxMw-}`By4Jae++R=o>I@Ah_X})c-pkGU1KE z0Lf*PiSTNBQwagDtOlC(dzs7XAquX1oqvh$vosC{IjEqBj~vothV7B&OMB0#in{Q>43pA3 zl7X=JT!#it{Oe)Tq+jkJNT17)f4&Mq(RNnY8II37W&%oCNo0X>ZpD`-IvDpxwtCKR zB*q6Jl;VH=*w_|$2Qq4?k#Dj6+js(74@Wi9PIF_sjNH3tMx)0OJb2%*#uS9Xw?Zt~VvK zG|0{27ZvuceweUYRr&FkSXOUqtc*K!vK7AHeV2P7mne_BizO;|Jm1g-c}yJGx;FM- z69w4)3gu`$TF&T@ai7y%oj967lGT(|rL{{i^sSFI!NN-^F{^+JAx)&tu!`~ZgO8mfBxA#Hr zY9~Z_Uge|RCeU0-?jmm2S@;0TzBpfs;lChvafhnxe`1#wavt&>S_nstif;!*p@Jrd z7)DrD84U$I+Gd?|VUKi7Jxy>G{3O@XYs;-6)`T&`QF4r>pJv;GNjJnNFN4J@6Lo?8@)19X9sG~u+>)~xd>+Spv4lRRm@vT!Q z0RRWweu?d`uuo}6VJ`Y9SlGI=Z9hC;^Ti4=WT1ffY(PoGRnQ>|;$yjS%f*#KsU8F40` z$pghvr!ir=@UMz1GIqQ0z&PvTYfxpp$(I#^`#gqpHPWA3NB? zAT0p}Qyzfo1l^w1{X}8O1uY4$c#Z)Na=# z(1biE8fRp3SE!h}2kof#)a0hz{s5B4$Fqjz3(9(2BL;GfFih5Fs)r8IZ8lC?q@qju z&aard*|HuT4i(~%2%yR0llt=>$dVAC=a9FeTHCXQJ#;MtGt?uQ(Yicx3SUaD z3=y;49g4_RCG)8;vggFb%I;a(sbaDOl-q1#QIvM3+6|-CM#o(WGsi2TrfSkZP11oo zyrq*(u$#7}4t>?ApnJ&XgXFG3axk8!@@l#WpFmA)?AodSQWy3lrG zF=i7Jniv*&l!jyMY=y38G$b}f*M_e1&l z6`^m+U+4TPiB@tR$=r~&8D=O^pz%ZMSD{LbX5}9Q^`ijU!FL6mQI_7y1`eCweIUT- z$o)2P$-g0A-2b!^VN z?rv#kY2B+Z>?jinj_ z;MG~WWDDJ;>v+5j;1wkaUjEDVmt}AiN6-U&chXnd@kdNzFlBrjSSb&*&f;{vY&6aq z@v_aAw&wY_e7mM@k0t--AJ6*^)wvnWKTIIQ{ov2MTLGcrEU9infmwQi7&S){I$6RM zDbHi=5*1nbI%fB5UI>4z26>Me4RX*h)BjOH>L#e{z=xrbOc>HdFAE{=^X% zU`mOu4$~;Xf_rcp<&V4qGaWscps<0tpRk zR;o`BjF5VYooL1!S}cXzX|4w-b;qdC@Vt^z>b2}B<4P66V z!Dn&2+uFI$GlWgQ82%xjxY1=7y2GWjH=M%r6-hNb%AT8Ji>J%s7>EHexDa<5X4HVJ zZHd;fYQQ2rncwAs8&Hmd!7B)MRa;@rc=fkXGu3PyC`S-?(O}svidd$~b`g3JzlxES z(eL9pIf-keD-4om_GHAChIp_sWdU3Jcx$TGzQfjhYt%(*N7*y=w$3QT!zabyzl7M7 z!?$VWralc3y#=+|X#0sg0&XOFl1gy0B7bMUFIIg#yCO=g2-reUjg!=0y(sc@$ZvHd zE0h(iy`ap(?#T}|&9s4%Rn1&=R{->=GpgIO9+_X>Vk9G-S2q&}p3WtHI({A#bQBY~ zdg>e{uL!Q>Z|vWdp5sL_7f-vez4lY%-azCyFm-8tu-YPsQO9l=AbUVSeOb2Egr#Bz zzcun7nc=clbs7E5CpARwP5ct zIkPcm^_d$^Ql^1v zx0x%FQz{_6SBq_#W=0^~YN2`jPE$Bf62Z}4cG2qDv zk-=!)YNNVV^iA{SkX6DHLZFOmumc~0IhE?X>3+B9CGj!IM*wME?=A#|K}yxAdt_^d#~^RwxZ?MBmu z*)**7YvZuWc%OJwVG}Q+q%@+SEE$98XfM!=v;ZCNJla`ZE6;64WlfAKRflOVr)L6E zv74*01wPO8ZX+4K4U$ewEVc-U!TWs$sk02VoZssOJlWhEq`BNku@oK7h7gG>a4TW8FEi2Eiv0@R`y!8!S9$IDs-&pABj)pMOUk!+PRW{Es zdyIadW%vtXtd|~lqtV;e!CqM%I*X{1!7t%9vLH?pWZL<(gb~g+)2+nS`E6iv-*T1u zH&Ga6W5T~2M!u|fJ&e=}W+3-Y_&#Y9S|Pwtyb`rd_xTdnBD-KZD3i@q_}uA?J6~o` zD$cgdLepG=%-X}>)20eIgfg2^HKJ?)a4wwpgvmJN35gLgB3Pg*n}K*`njmkU>ZGZoXYgQ;aYq zGZH?U<#&e5*V02YtBHhZP1*BatBF~CMqy>gK6G9dfXD#q2bOi!MKtQDeq?W4XLw}H z;qs8n#lmX3AMTjrGM{%>bSivG`?N=KAO{sH*f4X@2+!?m#0S~enU!B244=u+SDE#W z6Cvvp+Im_YL{a_AH*+n?-ox3d(Y)&1>o+wJa>BiV57n^|WF6s1wzwU)Fyyb6seR7! zWp{VI>X_BlnO+X>HxjV*Hq_^ghH)au%W_wrCwjjfK^!(mH8w>5abgtNE1nWQT%)$I^e%YjU0EU5*@?4T7_tqD7)G<&s-|_< z!(M4K>q0mg72X7YFnW7{z-qC=4+Zlk`b@d?foGmoO;p=j3?UY}wbe4hZY}-~_YV;1 zQLda6gTt1bB6bBDHe-1_jcpk(UinL04m6oB2J6^NM#M7ESJhf!mfBbs&Es$eC7h3sqOykNh$YVR&#aivZj8IIX*>Qp{d-u+K~VKi9vT^ zsNsAofEYtlZp5(LRw$d-UFYRxfYK#b2L6H$?d9x2zzX?&#mg0XKYEcRSJV_9ON)?) z(|{z4+{4+6{-&)f9VE{F(S$_YTq!?6O7g=9iHdbE@rtGTh=-deH1r9X=g}pW^+p8T7_IPkS-Civ|E=ki9aDHF0X`obfJ?O$5+UMi2aB@pJV6N_B!_EswB-lj1XiMvl2s6cRiULx+;Ob_A#?9BvBa*_2GHH&5N5H{Vep%aTec zW~5p}FHCJe(ZA|q&(8dIFioaSSz_^@_5wg)@7&pGk8ZqHXinShWt)}8usi1;813Q3 zb^<1N928>J4g^mlfVneKH9`GwkMOCYYd;8w^p^EmnN@6t>$diPE-u7NcXDvoB@e#| zZ6x@$ewg!;#zr4aCt@>9c~WF1qx$x6vz8%FPEva^3lSEIcU8^ovUo2I0e3 zgoRZ=JYj3iju!fjBznK)$vPgpXz_(qoz*xnvaLCd?I*5Ae8U0KT)Z2k4l? z%wANA6k%MqZN?|qFMC|i=ZpZD&*{QU9Xlt;`inqx?=>_7Bi;kuC{n`1L5@9=H_y*o z+|Lbue5_X5O}9P#mW{*9!tBvxF+>GC_{9|K({Jw-v-z{{OU$AOA3skrzAvj&U*O>x zM|$4u-)zXD7KdeR-bQlTl`>5fS!w?=Bn(P`U}J{a56An5tADbW}F)MKhLfAvqK|{soxp zar1fAiwj}jr9tj-Lyf<~@hxnnBY~cFQV-W6IiI#`I-=B@0Y+<3YwN{kV~YjJqDy&} zli^>Hgvf_>eg*9a=rRjTW)Ywd8N5IN{!fyEu+te z1?orj-~Q=Ez4xn@`j2en79X=^O6=r_)_lkr?~;br{sVKZfga9w+K+(egQ$l=8ya!A z--#g>YY4Y3hy0Ti#grP>A;g&@@+TbR@zpT7Db4DX#L!1huQym1HCfxgpEJ92>f=Ru zFQjjj$pY^kI(R8^@iC_xx@O7N_f0OCJ7RTM=8EOrKC>1C}lgoH4BGifB|c`8B>EkT|MDetrWj& zH3^LhZ7@^eHq!n${sx66k05rLXQE#$JfQf!iq-(iHn8e8VOE>aY8N;jB2HzZD&TVX z+fB9qkJ>VF#tRLD;^?YkjshOv%+7`9k{Og+=T*^fyel27Wi2U_i#jOX_Q*wPByk1T zZU-j>HJobG8ylOvIuR9^CIb5=^xv)X0o`5n$hhA=vbVXdTcKiFgf$=XZmC8oo1VVw>oE79JL2YX074`u`<5NNeE46 zOOT%2aXUTK%uU!AFJ8l%P6Y`o$4uIQ{5@%1dEAX&?braJFvU9G@ICA(GretnPiFhQ;p}Xug@_1^FjL-?T*1hckI;tP?Sm!%2i7!fhG^8RL~G}$|E8l3}6 z^$1mbU~gwtFh=-rd`z}SR3Mldp$+Sin}ns;TsRlZj&(Tl4|2eb^49ajv(Vx`>MDZ} zZfD+3tMyjVg>vl|k)`yh+)Z}uP5R2@PSS|xpop8J*HQXISf*=u6?Qj&=ia>M?i1xo zae-*j!H=C~6BRrg+`8*OAHV*`XoyQ_o#Wj>VPP2}Gv3c}Q)T4HF3fIdAe<3%C)xx2 zfUO}PbAl1F%Qj$dYB=crei5md!J=N_R)uz-2N2^=HHcP9EZxwHN>q@p2GRfS(GGb| z@-D)TbhNn5hKsupyyy>+_}cAo>NPHXx_7UT3bz?9i|RY#~KX1fCe-1K{V}7@q3ll zA{onBv@S<0F3~@C%2+L%aUP6D$ehV1tuRcV|7Pu+FJ(B=P!Aa%O%1vwom{o?mNZ+u z4sFWX|NH|+u6@qClblh%^T6!|wllsJPnlK2ypVx_QKz&^c>j~n^L^R>|=eSmB z0&w}3qWgv0w|Ck+RvPEzGeq)(`IjsmuK&UBh|KGtq^y>Wx&=m*P7>6hQ0!Yq)8g-^ z>|QvLAOlf{UzspqL`)Q~3G>_@0h)RsuLFzg96`5kzk)&+7N z+XeHBDT*2>ScsBUnNi!f!ezX*B_C0Z6{zVC3)>CxQ9N^J5e*XLxz1hQ2(y#9jlhPb$u#2&)ee7P{_i^sRO6m~lOGj1 z>tmTZxhSU+FwN}+o#Tms<{UF`Tu?UCf1+aO!XilJz(MP<#g3loJdXvOF1LDYf3iha zGvh{r>Kids+zEY@b?*IjQE~d^AmfTTGkUX8^e@YS#>i5O2*sOk^9;)^?c6;H`O_n1 zl6K~++LT8nkPWgJ5|98JEau%Kq>>y0(L;`e zu7b8#iUUcw&l3B-?|RK&sM9VBRlS-_TeVdwN>c2rc=wvH1kmoXY6_}>HhY^OsGtz| zm6C}W28#*FRKA2uGiO0N2O+feb%*nNp$5{fWNdPi5N4#^*CuD-D62l~;x23bnMMF6(xe{l7VB8d*P0L0$7uLf1U)_VrD)pY?m9CLrLi zmH23{fh}BJWWoyf<>i%3RtY?Vv&A;N%=2n|bOA3N{UU;cNLYI?fbK_vB6tzp#ud)% zw=)};spMPD@~)19%BNq)GLj8)LHd$>dRHQgxpF2(yH)d-KHv6LKevRn3*%gecG6@) zJk_P)q?^@}ahdZzUbMF@$95+8Vy+ z_ZXv}lE<*tDq-3`|54rXtY0Y&RR-Kk8d0JfE{XYlFyM1bv7~^ zA7=gFHRuIDwafq8?0->P4f_dLhVQx;98o1H6hs|1A&f-qq#ZE(gqBjo)| zp{7Y^VKO^8Y?%HXSuD-Vk62=+pN~c4^4N80HEJ%>p=~*X@Hy;$@ie+lAu`$Z}{YbQHr5*@z9A<%9l#Qtl5!IzH7) zM$2soV6JVk1PDhToHLQ)LT^2g=;V!a7ze7f`0&Ai56Fhy3z-2Ko! zTK9-~2i85#RKz%%4!ulylo1+SrgvbB!j8h~zv2Rb(mST_8@AzC%^_SF>n;Se3#&>X zO>-(iCNQ(hKS7f7^^hBui8>61Nj}^`!X_@KzmZHI2}-Tza$ujUHiyJ77yGxfN<#m> z47G=W7*ho0sU_|T#LKvUqV{cGY1sMij|Lgt4XH#fRo`uc>&SGf1hp%k*h(8Et~_tM zaJla8gt0tr{(%NV5ypArp%5slMi1D`VI)o8aF{32C=S?8!ELP*Rl~XT-|tX*K1fy2V z&Y>QS4M!Qz9xVI-y&Ps1m`pT5#%r;$eC_qS6EdHU%|gTqr1g_nH4(x{H*^S<+p5!Z|8XCac-9;Wk0*`LiucCn_*=yCvI)Bff`syV_Iwd}1T-^DJ<)Q8 zpd{&~Gi^StwiI5d0MPQ@+NWzNB1?YxC3Z;Rp;|AKH@qt(K53ImPeomKS(GsC;8%_m6Sw=L>t-$!VXp6Hu`ov%|RRmwLcMBX%BCUVATP{Awcu@ zXO*`h*yn1d@;P)P8DO;2hUcr5EnuUK=uzl#7m=T`V1xvee|o{% z7OfRqcUwG5dRJt=`BEPHP5ji61;w7;u#aLUrPKyHd z`k@N$i#l6tfKpeLX-CAV$@URxFYZZic)1{N=!Ppucce(bV;s<_uPE1;C(+xYDt%;G zner^65y5O7;%%PjUBP>!)d#QVIkOiB;$}jv=iC2k0)C&@pS(R6ojq2cf8AA?z5%|b zeq~40Gn{*y5x$J76z=rLBcLlJ5n<)cdts!uO!tYn39%4Oc2HswQ=1LCL!#N^?l1&~ z&5t)E!tyDljQL3iFZ`>U3q5xZF*Wiew}6_D*dT`LU?Qf}F4z4HWdp=2(y2duq+;2K zKR@oLB-1|Pp4PnRjK#23^ra!C7-TJt_Y9(sG8%Bg*CB*krOFnfEYTJ4iYj7&O1>y-7;<_VeWI*fZxeRh$Q!+;uJxe*OAmj9YhaF3K% z0O>J+G0vTq+bI$H=cVyQVj_hPxp-RPFvyrWFb^Y+HyJ@MW#vudw8owEqFLQ*I>^nj z`wvTs7X_);<6+{3{0mj{{P54~U%e2>RYW!of4C^;Xb@yRSeS<4yhI*fo7Y zfMv)Hj%fr5j(c3x{K@4(18(F+Ej3dUA?}jMMJNcPvF)HLZT!7Sn7l+Y_*5Htm^?hT zL|BO&oA)H$@917=2dv_uOXvf)2)6?jO*#uwIt`p8$UhJEM1l~_Jt0_hl%5ljdjvTM zld$AGzLWL(@4B#J%FWd0Lpk@{zM&61b9mqe^R1yd1fztv96X2D4hH+X|BHsijvSq( z>_AqStq6q+r4w}vvL}&#WA8{XOMY4Ug*Mwo+4d*&_HEu6DI0cRSP;km;JMIZw{sUQ zmbc}R$N(dz9*6Y53!ZCqUNrg`rH<%Yq(1QP50AKs&|_4CQ;hOD4vf(#G^0YXm_nw5 z5}Rah%m`(C+PgpD4!-Iwypp|Es)MS5D{VOF^s;^&4;rb~*Zc$Shv+k};p~Y#(I>IH zA^uED=&>Qz5HTlTcSvq=$8&E68E;DvNp2C**ai>lHx+jjiR5f#fvdRQ!L><{96lW! zUo!u%y(^Du>Pq7w$f6mH%dn_OwAP|Uh;)&tA*pD~QH!*0aRxP7#-X+}fD3s*7AXQ5 zg=Tb)T7?=t*5X!TixMo5hpbjAY2_dzTQ(sTg={2wNnYNYd+9jNe?9a6ZT6p;t14T8{^6OROhR+PWassxD1)F4)4@qhEe{ zee0urS-CqHDOgPq|1WDNg5P5?UehRlHJA7Wqf6hraVzV6&-ZUoq8r-3&T1|WopU6< zyDY>DI<=Pdxp1cOL<-kGZ$nDN@V$dF=U z6DwkyAcqETxkX{xYA^f?F43Ov_GaB>rg-UY+z@WkE}Vj+q>Hrtn#`RmF#C6N2t6Pun8YaKJ$zp%(5^lgH18|) z?HzrMx4g@m9*)=a2y~gXiS04~t)t8HeoBwZ+#2;3t0qtvEq)liHzH7kwJ^48xVWBf z^gL5$jjUv|TlM;j`OYiJiKB%{)`j$5ppAX@!>~VWtk;As8{?#9Z|@JOY^+sm(;GudQt2tG-M%NoupYNPCYas4nB+`jUk+EbwhVs>F1?#v=rsPRrT5_YAovW4k;$h_)` ze@|p~Ntl86jeI#Z;l*=u5M4>AiLcj_v)NK=vK*)}iuf?`35Ub2~smy$E&l8H+>J==KtA5$f7 z5EeSQ97Sgx?ymw#`c~gqWeZ^7nXbD(ZVu>!?LDLi1JPj;b(wTfQP=K6Jv?$65G3aQ zji{vFZ8w*`}|A28gkrlrM(h*A*2ZlUmepRQCf(>2N(y zGR(68ZR_K8_O8{|Ua7Aa8&wjcK{KCq7j|%*-(h+Nv3CG4bYLx9e68r|8Oc($Ax2G= zda9(;boW0~H8JqJ44oFQkQP<3hnJ4JPYsM~JU2AWrJRY2xT{vx7>m|#?)O1S>`7_| zM}9e z0RQeH<|oMjXk3iUyoz!#L!4aJ0mJ@Q(t5lhAC@-Td=M!Uo;}@WD z=$GBNizKv*j$lp|>bsj{_bW=pj;6{W*@(DJuofPnNjvHJ9JyPjxAOP z=u}J>#0}Qn7q}qJigABx!Cdvor|Q7o-3756vzbScWQ zPN4-m(7 zetANJJ_Kot*$ui$=Z_hf#76_5w|Ix@0VJ4=RDx5MIbcK(<2$lWD0 zoG%!^EA^z3Q#Io8gE?SwaQ^vm;vNf6>fm9(f8;hiP04D$bI=r(d5GAq?^HkUw7H;7 z*SSY3a*X8(hTBSUZ1oSL*Mer&1cfC9BYoZHOBkMu3@Sx5WD-XaPg02~O3`o(bfm5| z?c-TNl93EaAm6!Ig?f>amuv~1Z?(;k zEdj@YQ7`JsA3UJd8d1p}aW*)XV^A7__1NT1s|HNP-UN)1S6+H(wgv67$;J#m+g+-~A81>_@4p`6IA`&)GKDnYiR5~pS;_^jydHy&U~!e z?5Re8*|kHHw@!vvp}1H0u4yM;4gmBK##8+QS_6&M9-|s0pDTPd*dvwtZHdmGAtN0i za$q+y5@RF}qs5!?d&!(x=?w?^eO~Y!C+GH`+oWzLxlaVfbDk8^Xzd0(Th_Ogc`2I? zE*`CoNRRA@pR5{W*19I-eIjN44AvocUZA0lG&Iz2s}xR&^s?@psakuYcD52Qb|DB7 z0SBcWKA51#Jv=k@TPIbf%wn7C-|$AR2j7akdKj-3`jq8>yJ0Px#ga))X8bGc zHV}!o0;}Xpq?c<~w?{}JL7~K%ALSubAMBLB%nfMlB{y&Q{Z8ueTUrygLsteCreGHM+y5)!62*&idkWtSgqHszC&_LH vOGW>cuSEQ>`O1re|9{cn(#qfIUYyit=RT=OniWU^ul4V4T34O4=ktF7qg9VU literal 0 HcmV?d00001 diff --git a/public/src/spectro.py b/public/src/spectro.py new file mode 100644 index 0000000..38b2416 --- /dev/null +++ b/public/src/spectro.py @@ -0,0 +1,22 @@ +#import the pyplot and wavfile modules +import matplotlib.pyplot as plt +from scipy.io import wavfile +# Read the wav file (mono) +file = "Car721035-2020-Pass0-Z2-PaRecAR628069_20200725_005937_000.wav" +file_path = f"/var/www/chiro-canto/public/storage/records/{file}" +print(file) +samplingFrequency, signalData = wavfile.read(file_path) +# Plot the signal read from wav file +# plt.subplot(211) +# plt.title('Spectrogram of a wav file with piano music') +# plt.plot(signalData) +# plt.xlabel('Sample') +# plt.ylabel('Amplitude') +# plt.subplot(212) +plt.specgram(signalData,Fs=samplingFrequency) +# plt.xlabel('Time') +# plt.ylabel('Frequency') +plt.savefig(f'/var/www/chiro-canto/public/storage/records/{file}') +plt.show() + + \ No newline at end of file diff --git a/public/src/spectro_cli.py b/public/src/spectro_cli.py new file mode 100644 index 0000000..b30258b --- /dev/null +++ b/public/src/spectro_cli.py @@ -0,0 +1,19 @@ +import matplotlib.pyplot as plt +import librosa +import numpy as np +import os +import sys + +args = sys.argv + +file_path = args[1] +file_name = os.path.basename(file_path) + +(sig, rate) = librosa.load(file_path, sr=None, mono=True, dtype=np.float32) +plt.specgram(sig, Fs=rate, NFFT=2048) + +plt.subplots_adjust(left=0,right=1,bottom=0,top=1) +plt.axis('tight') +plt.axis('off') + +plt.savefig(f"/var/www/chiro-canto/public/storage/spectrograms/{file_name}.png") \ No newline at end of file diff --git a/public/src/spectro_librosa.py b/public/src/spectro_librosa.py new file mode 100644 index 0000000..2f3ddf8 --- /dev/null +++ b/public/src/spectro_librosa.py @@ -0,0 +1,46 @@ +_wav_file_ = "/var/www/chiro-canto/public/storage/records/PaRecAR628069_20200526_040726.wav" + +def spectogram_librosa(_wav_file_): + import librosa + import pylab + import numpy as np + import matplotlib.pyplot as plt + + (sig, rate) = librosa.load(_wav_file_, sr=None, mono=True, dtype=np.float32) + plt.specgram(sig, Fs=rate) + plt.savefig('spectrogram3.png') + +def graph_spectrogram_wave(wav_file): + import wave + import pylab + import matplotlib.pyplot as plt + def get_wav_info(wav_file): + wav = wave.open(wav_file, 'r') + frames = wav.readframes(-1) + sound_info = pylab.fromstring(frames, 'int16') + frame_rate = wav.getframerate() + wav.close() + return sound_info, frame_rate + sound_info, frame_rate = get_wav_info(wav_file) + # pylab.figure(num=3, figsize=(10, 6)) + # pylab.title('spectrogram pylab with wav_file') + plt.specgram(sound_info, Fs=frame_rate) + plt.savefig('spectrogram2.png') + + +def graph_wavfileread(_wav_file_): + import matplotlib.pyplot as plt + from scipy import signal + from scipy.io import wavfile + import numpy as np + sample_rate, samples = wavfile.read(_wav_file_) + frequencies, times, spectrogram = signal.spectrogram(samples,sample_rate,nfft=1024) + plt.pcolormesh(times, frequencies, 10*np.log10(spectrogram)) + plt.ylabel('Frequency [Hz]') + plt.xlabel('Time [sec]') + plt.savefig("spectogram1.png") + + +spectogram_librosa(_wav_file_) +#graph_wavfileread(_wav_file_) +#graph_spectrogram_wave(_wav_file_) \ No newline at end of file diff --git a/public/styles/style.css b/public/styles/style.css index fc04f87..3328c30 100644 --- a/public/styles/style.css +++ b/public/styles/style.css @@ -79,7 +79,7 @@ input { } /* Style inputs with type="text", select elements and textareas */ -input[type=text], input[type=email], input[type=url], input[type=password], select, textarea { +input[type=text], input[type=email], input[type=url], input[type=password], input[type=number], select, textarea { width: 100%; /* Full width */ padding: 12px; /* Some padding */ border: 1px solid #ccc; /* Gray border */ @@ -201,7 +201,7 @@ iframe html body { h3, p{ padding: 1em; - width: 15em; + width: auto; } p.large { @@ -223,6 +223,15 @@ tr:nth-child(even) { background-color: #dddddd; } +table a { + text-decoration: none; + color: black; +} + +table a:hover { + font-style: italic; +} + #searchbar { display: flex; flex-direction: row; diff --git a/public/upload/submitmetadata.php b/public/upload/submitmetadata.php index 1f54d59..1b54196 100644 --- a/public/upload/submitmetadata.php +++ b/public/upload/submitmetadata.php @@ -28,6 +28,9 @@ if (isset($_POST['submit'])) if (move_uploaded_file($_FILES['file']['tmp_name'], $target_file)) { echo "The file ". htmlspecialchars(basename($_FILES['file']['name']))." has been uploaded."; + // Create a spectogram of the file : + + exec("python $root./src/spectro_cli.py ".$_FILES['file']['name']); } else { echo "Sorry, there was an error uploading your file"; } diff --git a/public/vendor/autoload.php b/public/vendor/autoload.php new file mode 100644 index 0000000..b232792 --- /dev/null +++ b/public/vendor/autoload.php @@ -0,0 +1,7 @@ + + * Jordi Boggiano + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Composer\Autoload; + +/** + * ClassLoader implements a PSR-0, PSR-4 and classmap class loader. + * + * $loader = new \Composer\Autoload\ClassLoader(); + * + * // register classes with namespaces + * $loader->add('Symfony\Component', __DIR__.'/component'); + * $loader->add('Symfony', __DIR__.'/framework'); + * + * // activate the autoloader + * $loader->register(); + * + * // to enable searching the include path (eg. for PEAR packages) + * $loader->setUseIncludePath(true); + * + * In this example, if you try to use a class in the Symfony\Component + * namespace or one of its children (Symfony\Component\Console for instance), + * the autoloader will first look for the class under the component/ + * directory, and it will then fallback to the framework/ directory if not + * found before giving up. + * + * This class is loosely based on the Symfony UniversalClassLoader. + * + * @author Fabien Potencier + * @author Jordi Boggiano + * @see https://www.php-fig.org/psr/psr-0/ + * @see https://www.php-fig.org/psr/psr-4/ + */ +class ClassLoader +{ + private $vendorDir; + + // PSR-4 + private $prefixLengthsPsr4 = array(); + private $prefixDirsPsr4 = array(); + private $fallbackDirsPsr4 = array(); + + // PSR-0 + private $prefixesPsr0 = array(); + private $fallbackDirsPsr0 = array(); + + private $useIncludePath = false; + private $classMap = array(); + private $classMapAuthoritative = false; + private $missingClasses = array(); + private $apcuPrefix; + + private static $registeredLoaders = array(); + + public function __construct($vendorDir = null) + { + $this->vendorDir = $vendorDir; + } + + public function getPrefixes() + { + if (!empty($this->prefixesPsr0)) { + return call_user_func_array('array_merge', array_values($this->prefixesPsr0)); + } + + return array(); + } + + public function getPrefixesPsr4() + { + return $this->prefixDirsPsr4; + } + + public function getFallbackDirs() + { + return $this->fallbackDirsPsr0; + } + + public function getFallbackDirsPsr4() + { + return $this->fallbackDirsPsr4; + } + + public function getClassMap() + { + return $this->classMap; + } + + /** + * @param array $classMap Class to filename map + */ + public function addClassMap(array $classMap) + { + if ($this->classMap) { + $this->classMap = array_merge($this->classMap, $classMap); + } else { + $this->classMap = $classMap; + } + } + + /** + * Registers a set of PSR-0 directories for a given prefix, either + * appending or prepending to the ones previously set for this prefix. + * + * @param string $prefix The prefix + * @param array|string $paths The PSR-0 root directories + * @param bool $prepend Whether to prepend the directories + */ + public function add($prefix, $paths, $prepend = false) + { + if (!$prefix) { + if ($prepend) { + $this->fallbackDirsPsr0 = array_merge( + (array) $paths, + $this->fallbackDirsPsr0 + ); + } else { + $this->fallbackDirsPsr0 = array_merge( + $this->fallbackDirsPsr0, + (array) $paths + ); + } + + return; + } + + $first = $prefix[0]; + if (!isset($this->prefixesPsr0[$first][$prefix])) { + $this->prefixesPsr0[$first][$prefix] = (array) $paths; + + return; + } + if ($prepend) { + $this->prefixesPsr0[$first][$prefix] = array_merge( + (array) $paths, + $this->prefixesPsr0[$first][$prefix] + ); + } else { + $this->prefixesPsr0[$first][$prefix] = array_merge( + $this->prefixesPsr0[$first][$prefix], + (array) $paths + ); + } + } + + /** + * Registers a set of PSR-4 directories for a given namespace, either + * appending or prepending to the ones previously set for this namespace. + * + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param array|string $paths The PSR-4 base directories + * @param bool $prepend Whether to prepend the directories + * + * @throws \InvalidArgumentException + */ + public function addPsr4($prefix, $paths, $prepend = false) + { + if (!$prefix) { + // Register directories for the root namespace. + if ($prepend) { + $this->fallbackDirsPsr4 = array_merge( + (array) $paths, + $this->fallbackDirsPsr4 + ); + } else { + $this->fallbackDirsPsr4 = array_merge( + $this->fallbackDirsPsr4, + (array) $paths + ); + } + } elseif (!isset($this->prefixDirsPsr4[$prefix])) { + // Register directories for a new namespace. + $length = strlen($prefix); + if ('\\' !== $prefix[$length - 1]) { + throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); + } + $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; + $this->prefixDirsPsr4[$prefix] = (array) $paths; + } elseif ($prepend) { + // Prepend directories for an already registered namespace. + $this->prefixDirsPsr4[$prefix] = array_merge( + (array) $paths, + $this->prefixDirsPsr4[$prefix] + ); + } else { + // Append directories for an already registered namespace. + $this->prefixDirsPsr4[$prefix] = array_merge( + $this->prefixDirsPsr4[$prefix], + (array) $paths + ); + } + } + + /** + * Registers a set of PSR-0 directories for a given prefix, + * replacing any others previously set for this prefix. + * + * @param string $prefix The prefix + * @param array|string $paths The PSR-0 base directories + */ + public function set($prefix, $paths) + { + if (!$prefix) { + $this->fallbackDirsPsr0 = (array) $paths; + } else { + $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths; + } + } + + /** + * Registers a set of PSR-4 directories for a given namespace, + * replacing any others previously set for this namespace. + * + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param array|string $paths The PSR-4 base directories + * + * @throws \InvalidArgumentException + */ + public function setPsr4($prefix, $paths) + { + if (!$prefix) { + $this->fallbackDirsPsr4 = (array) $paths; + } else { + $length = strlen($prefix); + if ('\\' !== $prefix[$length - 1]) { + throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); + } + $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; + $this->prefixDirsPsr4[$prefix] = (array) $paths; + } + } + + /** + * Turns on searching the include path for class files. + * + * @param bool $useIncludePath + */ + public function setUseIncludePath($useIncludePath) + { + $this->useIncludePath = $useIncludePath; + } + + /** + * Can be used to check if the autoloader uses the include path to check + * for classes. + * + * @return bool + */ + public function getUseIncludePath() + { + return $this->useIncludePath; + } + + /** + * Turns off searching the prefix and fallback directories for classes + * that have not been registered with the class map. + * + * @param bool $classMapAuthoritative + */ + public function setClassMapAuthoritative($classMapAuthoritative) + { + $this->classMapAuthoritative = $classMapAuthoritative; + } + + /** + * Should class lookup fail if not found in the current class map? + * + * @return bool + */ + public function isClassMapAuthoritative() + { + return $this->classMapAuthoritative; + } + + /** + * APCu prefix to use to cache found/not-found classes, if the extension is enabled. + * + * @param string|null $apcuPrefix + */ + public function setApcuPrefix($apcuPrefix) + { + $this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null; + } + + /** + * The APCu prefix in use, or null if APCu caching is not enabled. + * + * @return string|null + */ + public function getApcuPrefix() + { + return $this->apcuPrefix; + } + + /** + * Registers this instance as an autoloader. + * + * @param bool $prepend Whether to prepend the autoloader or not + */ + public function register($prepend = false) + { + spl_autoload_register(array($this, 'loadClass'), true, $prepend); + + if (null === $this->vendorDir) { + return; + } + + if ($prepend) { + self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders; + } else { + unset(self::$registeredLoaders[$this->vendorDir]); + self::$registeredLoaders[$this->vendorDir] = $this; + } + } + + /** + * Unregisters this instance as an autoloader. + */ + public function unregister() + { + spl_autoload_unregister(array($this, 'loadClass')); + + if (null !== $this->vendorDir) { + unset(self::$registeredLoaders[$this->vendorDir]); + } + } + + /** + * Loads the given class or interface. + * + * @param string $class The name of the class + * @return bool|null True if loaded, null otherwise + */ + public function loadClass($class) + { + if ($file = $this->findFile($class)) { + includeFile($file); + + return true; + } + } + + /** + * Finds the path to the file where the class is defined. + * + * @param string $class The name of the class + * + * @return string|false The path if found, false otherwise + */ + public function findFile($class) + { + // class map lookup + if (isset($this->classMap[$class])) { + return $this->classMap[$class]; + } + if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) { + return false; + } + if (null !== $this->apcuPrefix) { + $file = apcu_fetch($this->apcuPrefix.$class, $hit); + if ($hit) { + return $file; + } + } + + $file = $this->findFileWithExtension($class, '.php'); + + // Search for Hack files if we are running on HHVM + if (false === $file && defined('HHVM_VERSION')) { + $file = $this->findFileWithExtension($class, '.hh'); + } + + if (null !== $this->apcuPrefix) { + apcu_add($this->apcuPrefix.$class, $file); + } + + if (false === $file) { + // Remember that this class does not exist. + $this->missingClasses[$class] = true; + } + + return $file; + } + + /** + * Returns the currently registered loaders indexed by their corresponding vendor directories. + * + * @return self[] + */ + public static function getRegisteredLoaders() + { + return self::$registeredLoaders; + } + + private function findFileWithExtension($class, $ext) + { + // PSR-4 lookup + $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext; + + $first = $class[0]; + if (isset($this->prefixLengthsPsr4[$first])) { + $subPath = $class; + while (false !== $lastPos = strrpos($subPath, '\\')) { + $subPath = substr($subPath, 0, $lastPos); + $search = $subPath . '\\'; + if (isset($this->prefixDirsPsr4[$search])) { + $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1); + foreach ($this->prefixDirsPsr4[$search] as $dir) { + if (file_exists($file = $dir . $pathEnd)) { + return $file; + } + } + } + } + } + + // PSR-4 fallback dirs + foreach ($this->fallbackDirsPsr4 as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) { + return $file; + } + } + + // PSR-0 lookup + if (false !== $pos = strrpos($class, '\\')) { + // namespaced class name + $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1) + . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR); + } else { + // PEAR-like class name + $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext; + } + + if (isset($this->prefixesPsr0[$first])) { + foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) { + if (0 === strpos($class, $prefix)) { + foreach ($dirs as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { + return $file; + } + } + } + } + } + + // PSR-0 fallback dirs + foreach ($this->fallbackDirsPsr0 as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { + return $file; + } + } + + // PSR-0 include paths. + if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) { + return $file; + } + + return false; + } +} + +/** + * Scope isolated include. + * + * Prevents access to $this/self from included files. + */ +function includeFile($file) +{ + include $file; +} diff --git a/public/vendor/composer/InstalledVersions.php b/public/vendor/composer/InstalledVersions.php new file mode 100644 index 0000000..39f17c0 --- /dev/null +++ b/public/vendor/composer/InstalledVersions.php @@ -0,0 +1,292 @@ + + * Jordi Boggiano + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Composer; + +use Composer\Autoload\ClassLoader; +use Composer\Semver\VersionParser; + +/** + * This class is copied in every Composer installed project and available to all + * + * To require it's presence, you can require `composer-runtime-api ^2.0` + */ +class InstalledVersions +{ + private static $installed = array ( + 'root' => + array ( + 'pretty_version' => 'dev-main', + 'version' => 'dev-main', + 'aliases' => + array ( + ), + 'reference' => '8192e30810af84d5b9cb756af8834e31842d5bf8', + 'name' => '__root__', + ), + 'versions' => + array ( + '__root__' => + array ( + 'pretty_version' => 'dev-main', + 'version' => 'dev-main', + 'aliases' => + array ( + ), + 'reference' => '8192e30810af84d5b9cb756af8834e31842d5bf8', + ), + 'erusev/parsedown' => + array ( + 'pretty_version' => '1.7.4', + 'version' => '1.7.4.0', + 'aliases' => + array ( + ), + 'reference' => 'cb17b6477dfff935958ba01325f2e8a2bfa6dab3', + ), + ), +); + private static $canGetVendors; + private static $installedByVendor = array(); + + /** + * Returns a list of all package names which are present, either by being installed, replaced or provided + * + * @return string[] + * @psalm-return list + */ + public static function getInstalledPackages() + { + $packages = array(); + foreach (self::getInstalled() as $installed) { + $packages[] = array_keys($installed['versions']); + } + + + if (1 === \count($packages)) { + return $packages[0]; + } + + return array_keys(array_flip(\call_user_func_array('array_merge', $packages))); + } + + /** + * Checks whether the given package is installed + * + * This also returns true if the package name is provided or replaced by another package + * + * @param string $packageName + * @return bool + */ + public static function isInstalled($packageName) + { + foreach (self::getInstalled() as $installed) { + if (isset($installed['versions'][$packageName])) { + return true; + } + } + + return false; + } + + /** + * Checks whether the given package satisfies a version constraint + * + * e.g. If you want to know whether version 2.3+ of package foo/bar is installed, you would call: + * + * Composer\InstalledVersions::satisfies(new VersionParser, 'foo/bar', '^2.3') + * + * @param VersionParser $parser Install composer/semver to have access to this class and functionality + * @param string $packageName + * @param string|null $constraint A version constraint to check for, if you pass one you have to make sure composer/semver is required by your package + * + * @return bool + */ + public static function satisfies(VersionParser $parser, $packageName, $constraint) + { + $constraint = $parser->parseConstraints($constraint); + $provided = $parser->parseConstraints(self::getVersionRanges($packageName)); + + return $provided->matches($constraint); + } + + /** + * Returns a version constraint representing all the range(s) which are installed for a given package + * + * It is easier to use this via isInstalled() with the $constraint argument if you need to check + * whether a given version of a package is installed, and not just whether it exists + * + * @param string $packageName + * @return string Version constraint usable with composer/semver + */ + public static function getVersionRanges($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + $ranges = array(); + if (isset($installed['versions'][$packageName]['pretty_version'])) { + $ranges[] = $installed['versions'][$packageName]['pretty_version']; + } + if (array_key_exists('aliases', $installed['versions'][$packageName])) { + $ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']); + } + if (array_key_exists('replaced', $installed['versions'][$packageName])) { + $ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']); + } + if (array_key_exists('provided', $installed['versions'][$packageName])) { + $ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']); + } + + return implode(' || ', $ranges); + } + + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + + /** + * @param string $packageName + * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present + */ + public static function getVersion($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + if (!isset($installed['versions'][$packageName]['version'])) { + return null; + } + + return $installed['versions'][$packageName]['version']; + } + + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + + /** + * @param string $packageName + * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present + */ + public static function getPrettyVersion($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + if (!isset($installed['versions'][$packageName]['pretty_version'])) { + return null; + } + + return $installed['versions'][$packageName]['pretty_version']; + } + + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + + /** + * @param string $packageName + * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as reference + */ + public static function getReference($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + if (!isset($installed['versions'][$packageName]['reference'])) { + return null; + } + + return $installed['versions'][$packageName]['reference']; + } + + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + + /** + * @return array + * @psalm-return array{name: string, version: string, reference: string, pretty_version: string, aliases: string[]} + */ + public static function getRootPackage() + { + $installed = self::getInstalled(); + + return $installed[0]['root']; + } + + /** + * Returns the raw installed.php data for custom implementations + * + * @return array[] + * @psalm-return array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[]}, versions: list} + */ + public static function getRawData() + { + return self::$installed; + } + + /** + * Lets you reload the static array from another file + * + * This is only useful for complex integrations in which a project needs to use + * this class but then also needs to execute another project's autoloader in process, + * and wants to ensure both projects have access to their version of installed.php. + * + * A typical case would be PHPUnit, where it would need to make sure it reads all + * the data it needs from this class, then call reload() with + * `require $CWD/vendor/composer/installed.php` (or similar) as input to make sure + * the project in which it runs can then also use this class safely, without + * interference between PHPUnit's dependencies and the project's dependencies. + * + * @param array[] $data A vendor/composer/installed.php data set + * @return void + * + * @psalm-param array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[]}, versions: list} $data + */ + public static function reload($data) + { + self::$installed = $data; + self::$installedByVendor = array(); + } + + /** + * @return array[] + */ + private static function getInstalled() + { + if (null === self::$canGetVendors) { + self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders'); + } + + $installed = array(); + + if (self::$canGetVendors) { + foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) { + if (isset(self::$installedByVendor[$vendorDir])) { + $installed[] = self::$installedByVendor[$vendorDir]; + } elseif (is_file($vendorDir.'/composer/installed.php')) { + $installed[] = self::$installedByVendor[$vendorDir] = require $vendorDir.'/composer/installed.php'; + } + } + } + + $installed[] = self::$installed; + + return $installed; + } +} diff --git a/public/vendor/composer/LICENSE b/public/vendor/composer/LICENSE new file mode 100644 index 0000000..62ecfd8 --- /dev/null +++ b/public/vendor/composer/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) Nils Adermann, Jordi Boggiano + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/public/vendor/composer/autoload_classmap.php b/public/vendor/composer/autoload_classmap.php new file mode 100644 index 0000000..b26f1b1 --- /dev/null +++ b/public/vendor/composer/autoload_classmap.php @@ -0,0 +1,10 @@ + $vendorDir . '/composer/InstalledVersions.php', +); diff --git a/public/vendor/composer/autoload_namespaces.php b/public/vendor/composer/autoload_namespaces.php new file mode 100644 index 0000000..2357cf9 --- /dev/null +++ b/public/vendor/composer/autoload_namespaces.php @@ -0,0 +1,10 @@ + array($vendorDir . '/erusev/parsedown'), +); diff --git a/public/vendor/composer/autoload_psr4.php b/public/vendor/composer/autoload_psr4.php new file mode 100644 index 0000000..b265c64 --- /dev/null +++ b/public/vendor/composer/autoload_psr4.php @@ -0,0 +1,9 @@ += 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded()); + if ($useStaticLoader) { + require __DIR__ . '/autoload_static.php'; + + call_user_func(\Composer\Autoload\ComposerStaticInit2a1773885b3c09785f9319782aba9af7::getInitializer($loader)); + } else { + $map = require __DIR__ . '/autoload_namespaces.php'; + foreach ($map as $namespace => $path) { + $loader->set($namespace, $path); + } + + $map = require __DIR__ . '/autoload_psr4.php'; + foreach ($map as $namespace => $path) { + $loader->setPsr4($namespace, $path); + } + + $classMap = require __DIR__ . '/autoload_classmap.php'; + if ($classMap) { + $loader->addClassMap($classMap); + } + } + + $loader->register(true); + + return $loader; + } +} diff --git a/public/vendor/composer/autoload_static.php b/public/vendor/composer/autoload_static.php new file mode 100644 index 0000000..dd0714e --- /dev/null +++ b/public/vendor/composer/autoload_static.php @@ -0,0 +1,31 @@ + + array ( + 'Parsedown' => + array ( + 0 => __DIR__ . '/..' . '/erusev/parsedown', + ), + ), + ); + + public static $classMap = array ( + 'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php', + ); + + public static function getInitializer(ClassLoader $loader) + { + return \Closure::bind(function () use ($loader) { + $loader->prefixesPsr0 = ComposerStaticInit2a1773885b3c09785f9319782aba9af7::$prefixesPsr0; + $loader->classMap = ComposerStaticInit2a1773885b3c09785f9319782aba9af7::$classMap; + + }, null, ClassLoader::class); + } +} diff --git a/public/vendor/composer/installed.json b/public/vendor/composer/installed.json new file mode 100644 index 0000000..cb6fbe8 --- /dev/null +++ b/public/vendor/composer/installed.json @@ -0,0 +1,59 @@ +{ + "packages": [ + { + "name": "erusev/parsedown", + "version": "1.7.4", + "version_normalized": "1.7.4.0", + "source": { + "type": "git", + "url": "https://github.com/erusev/parsedown.git", + "reference": "cb17b6477dfff935958ba01325f2e8a2bfa6dab3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/erusev/parsedown/zipball/cb17b6477dfff935958ba01325f2e8a2bfa6dab3", + "reference": "cb17b6477dfff935958ba01325f2e8a2bfa6dab3", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "php": ">=5.3.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35" + }, + "time": "2019-12-30T22:54:17+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-0": { + "Parsedown": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Emanuil Rusev", + "email": "hello@erusev.com", + "homepage": "http://erusev.com" + } + ], + "description": "Parser for Markdown.", + "homepage": "http://parsedown.org", + "keywords": [ + "markdown", + "parser" + ], + "support": { + "issues": "https://github.com/erusev/parsedown/issues", + "source": "https://github.com/erusev/parsedown/tree/1.7.x" + }, + "install-path": "../erusev/parsedown" + } + ], + "dev": true, + "dev-package-names": [] +} diff --git a/public/vendor/composer/installed.php b/public/vendor/composer/installed.php new file mode 100644 index 0000000..4fc8702 --- /dev/null +++ b/public/vendor/composer/installed.php @@ -0,0 +1,33 @@ + + array ( + 'pretty_version' => 'dev-main', + 'version' => 'dev-main', + 'aliases' => + array ( + ), + 'reference' => '8192e30810af84d5b9cb756af8834e31842d5bf8', + 'name' => '__root__', + ), + 'versions' => + array ( + '__root__' => + array ( + 'pretty_version' => 'dev-main', + 'version' => 'dev-main', + 'aliases' => + array ( + ), + 'reference' => '8192e30810af84d5b9cb756af8834e31842d5bf8', + ), + 'erusev/parsedown' => + array ( + 'pretty_version' => '1.7.4', + 'version' => '1.7.4.0', + 'aliases' => + array ( + ), + 'reference' => 'cb17b6477dfff935958ba01325f2e8a2bfa6dab3', + ), + ), +); diff --git a/public/vendor/composer/platform_check.php b/public/vendor/composer/platform_check.php new file mode 100644 index 0000000..7621d4f --- /dev/null +++ b/public/vendor/composer/platform_check.php @@ -0,0 +1,26 @@ += 50300)) { + $issues[] = 'Your Composer dependencies require a PHP version ">= 5.3.0". You are running ' . PHP_VERSION . '.'; +} + +if ($issues) { + if (!headers_sent()) { + header('HTTP/1.1 500 Internal Server Error'); + } + if (!ini_get('display_errors')) { + if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') { + fwrite(STDERR, 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . implode(PHP_EOL, $issues) . PHP_EOL.PHP_EOL); + } elseif (!headers_sent()) { + echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL; + } + } + trigger_error( + 'Composer detected issues in your platform: ' . implode(' ', $issues), + E_USER_ERROR + ); +} diff --git a/public/vendor/erusev/parsedown/LICENSE.txt b/public/vendor/erusev/parsedown/LICENSE.txt new file mode 100644 index 0000000..8e7c764 --- /dev/null +++ b/public/vendor/erusev/parsedown/LICENSE.txt @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2013-2018 Emanuil Rusev, erusev.com + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/public/vendor/erusev/parsedown/Parsedown.php b/public/vendor/erusev/parsedown/Parsedown.php new file mode 100644 index 0000000..1b9d6d5 --- /dev/null +++ b/public/vendor/erusev/parsedown/Parsedown.php @@ -0,0 +1,1712 @@ +DefinitionData = array(); + + # standardize line breaks + $text = str_replace(array("\r\n", "\r"), "\n", $text); + + # remove surrounding line breaks + $text = trim($text, "\n"); + + # split text into lines + $lines = explode("\n", $text); + + # iterate through lines to identify blocks + $markup = $this->lines($lines); + + # trim line breaks + $markup = trim($markup, "\n"); + + return $markup; + } + + # + # Setters + # + + function setBreaksEnabled($breaksEnabled) + { + $this->breaksEnabled = $breaksEnabled; + + return $this; + } + + protected $breaksEnabled; + + function setMarkupEscaped($markupEscaped) + { + $this->markupEscaped = $markupEscaped; + + return $this; + } + + protected $markupEscaped; + + function setUrlsLinked($urlsLinked) + { + $this->urlsLinked = $urlsLinked; + + return $this; + } + + protected $urlsLinked = true; + + function setSafeMode($safeMode) + { + $this->safeMode = (bool) $safeMode; + + return $this; + } + + protected $safeMode; + + protected $safeLinksWhitelist = array( + 'http://', + 'https://', + 'ftp://', + 'ftps://', + 'mailto:', + 'data:image/png;base64,', + 'data:image/gif;base64,', + 'data:image/jpeg;base64,', + 'irc:', + 'ircs:', + 'git:', + 'ssh:', + 'news:', + 'steam:', + ); + + # + # Lines + # + + protected $BlockTypes = array( + '#' => array('Header'), + '*' => array('Rule', 'List'), + '+' => array('List'), + '-' => array('SetextHeader', 'Table', 'Rule', 'List'), + '0' => array('List'), + '1' => array('List'), + '2' => array('List'), + '3' => array('List'), + '4' => array('List'), + '5' => array('List'), + '6' => array('List'), + '7' => array('List'), + '8' => array('List'), + '9' => array('List'), + ':' => array('Table'), + '<' => array('Comment', 'Markup'), + '=' => array('SetextHeader'), + '>' => array('Quote'), + '[' => array('Reference'), + '_' => array('Rule'), + '`' => array('FencedCode'), + '|' => array('Table'), + '~' => array('FencedCode'), + ); + + # ~ + + protected $unmarkedBlockTypes = array( + 'Code', + ); + + # + # Blocks + # + + protected function lines(array $lines) + { + $CurrentBlock = null; + + foreach ($lines as $line) + { + if (chop($line) === '') + { + if (isset($CurrentBlock)) + { + $CurrentBlock['interrupted'] = true; + } + + continue; + } + + if (strpos($line, "\t") !== false) + { + $parts = explode("\t", $line); + + $line = $parts[0]; + + unset($parts[0]); + + foreach ($parts as $part) + { + $shortage = 4 - mb_strlen($line, 'utf-8') % 4; + + $line .= str_repeat(' ', $shortage); + $line .= $part; + } + } + + $indent = 0; + + while (isset($line[$indent]) and $line[$indent] === ' ') + { + $indent ++; + } + + $text = $indent > 0 ? substr($line, $indent) : $line; + + # ~ + + $Line = array('body' => $line, 'indent' => $indent, 'text' => $text); + + # ~ + + if (isset($CurrentBlock['continuable'])) + { + $Block = $this->{'block'.$CurrentBlock['type'].'Continue'}($Line, $CurrentBlock); + + if (isset($Block)) + { + $CurrentBlock = $Block; + + continue; + } + else + { + if ($this->isBlockCompletable($CurrentBlock['type'])) + { + $CurrentBlock = $this->{'block'.$CurrentBlock['type'].'Complete'}($CurrentBlock); + } + } + } + + # ~ + + $marker = $text[0]; + + # ~ + + $blockTypes = $this->unmarkedBlockTypes; + + if (isset($this->BlockTypes[$marker])) + { + foreach ($this->BlockTypes[$marker] as $blockType) + { + $blockTypes []= $blockType; + } + } + + # + # ~ + + foreach ($blockTypes as $blockType) + { + $Block = $this->{'block'.$blockType}($Line, $CurrentBlock); + + if (isset($Block)) + { + $Block['type'] = $blockType; + + if ( ! isset($Block['identified'])) + { + $Blocks []= $CurrentBlock; + + $Block['identified'] = true; + } + + if ($this->isBlockContinuable($blockType)) + { + $Block['continuable'] = true; + } + + $CurrentBlock = $Block; + + continue 2; + } + } + + # ~ + + if (isset($CurrentBlock) and ! isset($CurrentBlock['type']) and ! isset($CurrentBlock['interrupted'])) + { + $CurrentBlock['element']['text'] .= "\n".$text; + } + else + { + $Blocks []= $CurrentBlock; + + $CurrentBlock = $this->paragraph($Line); + + $CurrentBlock['identified'] = true; + } + } + + # ~ + + if (isset($CurrentBlock['continuable']) and $this->isBlockCompletable($CurrentBlock['type'])) + { + $CurrentBlock = $this->{'block'.$CurrentBlock['type'].'Complete'}($CurrentBlock); + } + + # ~ + + $Blocks []= $CurrentBlock; + + unset($Blocks[0]); + + # ~ + + $markup = ''; + + foreach ($Blocks as $Block) + { + if (isset($Block['hidden'])) + { + continue; + } + + $markup .= "\n"; + $markup .= isset($Block['markup']) ? $Block['markup'] : $this->element($Block['element']); + } + + $markup .= "\n"; + + # ~ + + return $markup; + } + + protected function isBlockContinuable($Type) + { + return method_exists($this, 'block'.$Type.'Continue'); + } + + protected function isBlockCompletable($Type) + { + return method_exists($this, 'block'.$Type.'Complete'); + } + + # + # Code + + protected function blockCode($Line, $Block = null) + { + if (isset($Block) and ! isset($Block['type']) and ! isset($Block['interrupted'])) + { + return; + } + + if ($Line['indent'] >= 4) + { + $text = substr($Line['body'], 4); + + $Block = array( + 'element' => array( + 'name' => 'pre', + 'handler' => 'element', + 'text' => array( + 'name' => 'code', + 'text' => $text, + ), + ), + ); + + return $Block; + } + } + + protected function blockCodeContinue($Line, $Block) + { + if ($Line['indent'] >= 4) + { + if (isset($Block['interrupted'])) + { + $Block['element']['text']['text'] .= "\n"; + + unset($Block['interrupted']); + } + + $Block['element']['text']['text'] .= "\n"; + + $text = substr($Line['body'], 4); + + $Block['element']['text']['text'] .= $text; + + return $Block; + } + } + + protected function blockCodeComplete($Block) + { + $text = $Block['element']['text']['text']; + + $Block['element']['text']['text'] = $text; + + return $Block; + } + + # + # Comment + + protected function blockComment($Line) + { + if ($this->markupEscaped or $this->safeMode) + { + return; + } + + if (isset($Line['text'][3]) and $Line['text'][3] === '-' and $Line['text'][2] === '-' and $Line['text'][1] === '!') + { + $Block = array( + 'markup' => $Line['body'], + ); + + if (preg_match('/-->$/', $Line['text'])) + { + $Block['closed'] = true; + } + + return $Block; + } + } + + protected function blockCommentContinue($Line, array $Block) + { + if (isset($Block['closed'])) + { + return; + } + + $Block['markup'] .= "\n" . $Line['body']; + + if (preg_match('/-->$/', $Line['text'])) + { + $Block['closed'] = true; + } + + return $Block; + } + + # + # Fenced Code + + protected function blockFencedCode($Line) + { + if (preg_match('/^['.$Line['text'][0].']{3,}[ ]*([^`]+)?[ ]*$/', $Line['text'], $matches)) + { + $Element = array( + 'name' => 'code', + 'text' => '', + ); + + if (isset($matches[1])) + { + /** + * https://www.w3.org/TR/2011/WD-html5-20110525/elements.html#classes + * Every HTML element may have a class attribute specified. + * The attribute, if specified, must have a value that is a set + * of space-separated tokens representing the various classes + * that the element belongs to. + * [...] + * The space characters, for the purposes of this specification, + * are U+0020 SPACE, U+0009 CHARACTER TABULATION (tab), + * U+000A LINE FEED (LF), U+000C FORM FEED (FF), and + * U+000D CARRIAGE RETURN (CR). + */ + $language = substr($matches[1], 0, strcspn($matches[1], " \t\n\f\r")); + + $class = 'language-'.$language; + + $Element['attributes'] = array( + 'class' => $class, + ); + } + + $Block = array( + 'char' => $Line['text'][0], + 'element' => array( + 'name' => 'pre', + 'handler' => 'element', + 'text' => $Element, + ), + ); + + return $Block; + } + } + + protected function blockFencedCodeContinue($Line, $Block) + { + if (isset($Block['complete'])) + { + return; + } + + if (isset($Block['interrupted'])) + { + $Block['element']['text']['text'] .= "\n"; + + unset($Block['interrupted']); + } + + if (preg_match('/^'.$Block['char'].'{3,}[ ]*$/', $Line['text'])) + { + $Block['element']['text']['text'] = substr($Block['element']['text']['text'], 1); + + $Block['complete'] = true; + + return $Block; + } + + $Block['element']['text']['text'] .= "\n".$Line['body']; + + return $Block; + } + + protected function blockFencedCodeComplete($Block) + { + $text = $Block['element']['text']['text']; + + $Block['element']['text']['text'] = $text; + + return $Block; + } + + # + # Header + + protected function blockHeader($Line) + { + if (isset($Line['text'][1])) + { + $level = 1; + + while (isset($Line['text'][$level]) and $Line['text'][$level] === '#') + { + $level ++; + } + + if ($level > 6) + { + return; + } + + $text = trim($Line['text'], '# '); + + $Block = array( + 'element' => array( + 'name' => 'h' . min(6, $level), + 'text' => $text, + 'handler' => 'line', + ), + ); + + return $Block; + } + } + + # + # List + + protected function blockList($Line) + { + list($name, $pattern) = $Line['text'][0] <= '-' ? array('ul', '[*+-]') : array('ol', '[0-9]+[.]'); + + if (preg_match('/^('.$pattern.'[ ]+)(.*)/', $Line['text'], $matches)) + { + $Block = array( + 'indent' => $Line['indent'], + 'pattern' => $pattern, + 'element' => array( + 'name' => $name, + 'handler' => 'elements', + ), + ); + + if($name === 'ol') + { + $listStart = stristr($matches[0], '.', true); + + if($listStart !== '1') + { + $Block['element']['attributes'] = array('start' => $listStart); + } + } + + $Block['li'] = array( + 'name' => 'li', + 'handler' => 'li', + 'text' => array( + $matches[2], + ), + ); + + $Block['element']['text'] []= & $Block['li']; + + return $Block; + } + } + + protected function blockListContinue($Line, array $Block) + { + if ($Block['indent'] === $Line['indent'] and preg_match('/^'.$Block['pattern'].'(?:[ ]+(.*)|$)/', $Line['text'], $matches)) + { + if (isset($Block['interrupted'])) + { + $Block['li']['text'] []= ''; + + $Block['loose'] = true; + + unset($Block['interrupted']); + } + + unset($Block['li']); + + $text = isset($matches[1]) ? $matches[1] : ''; + + $Block['li'] = array( + 'name' => 'li', + 'handler' => 'li', + 'text' => array( + $text, + ), + ); + + $Block['element']['text'] []= & $Block['li']; + + return $Block; + } + + if ($Line['text'][0] === '[' and $this->blockReference($Line)) + { + return $Block; + } + + if ( ! isset($Block['interrupted'])) + { + $text = preg_replace('/^[ ]{0,4}/', '', $Line['body']); + + $Block['li']['text'] []= $text; + + return $Block; + } + + if ($Line['indent'] > 0) + { + $Block['li']['text'] []= ''; + + $text = preg_replace('/^[ ]{0,4}/', '', $Line['body']); + + $Block['li']['text'] []= $text; + + unset($Block['interrupted']); + + return $Block; + } + } + + protected function blockListComplete(array $Block) + { + if (isset($Block['loose'])) + { + foreach ($Block['element']['text'] as &$li) + { + if (end($li['text']) !== '') + { + $li['text'] []= ''; + } + } + } + + return $Block; + } + + # + # Quote + + protected function blockQuote($Line) + { + if (preg_match('/^>[ ]?(.*)/', $Line['text'], $matches)) + { + $Block = array( + 'element' => array( + 'name' => 'blockquote', + 'handler' => 'lines', + 'text' => (array) $matches[1], + ), + ); + + return $Block; + } + } + + protected function blockQuoteContinue($Line, array $Block) + { + if ($Line['text'][0] === '>' and preg_match('/^>[ ]?(.*)/', $Line['text'], $matches)) + { + if (isset($Block['interrupted'])) + { + $Block['element']['text'] []= ''; + + unset($Block['interrupted']); + } + + $Block['element']['text'] []= $matches[1]; + + return $Block; + } + + if ( ! isset($Block['interrupted'])) + { + $Block['element']['text'] []= $Line['text']; + + return $Block; + } + } + + # + # Rule + + protected function blockRule($Line) + { + if (preg_match('/^(['.$Line['text'][0].'])([ ]*\1){2,}[ ]*$/', $Line['text'])) + { + $Block = array( + 'element' => array( + 'name' => 'hr' + ), + ); + + return $Block; + } + } + + # + # Setext + + protected function blockSetextHeader($Line, array $Block = null) + { + if ( ! isset($Block) or isset($Block['type']) or isset($Block['interrupted'])) + { + return; + } + + if (chop($Line['text'], $Line['text'][0]) === '') + { + $Block['element']['name'] = $Line['text'][0] === '=' ? 'h1' : 'h2'; + + return $Block; + } + } + + # + # Markup + + protected function blockMarkup($Line) + { + if ($this->markupEscaped or $this->safeMode) + { + return; + } + + if (preg_match('/^<(\w[\w-]*)(?:[ ]*'.$this->regexHtmlAttribute.')*[ ]*(\/)?>/', $Line['text'], $matches)) + { + $element = strtolower($matches[1]); + + if (in_array($element, $this->textLevelElements)) + { + return; + } + + $Block = array( + 'name' => $matches[1], + 'depth' => 0, + 'markup' => $Line['text'], + ); + + $length = strlen($matches[0]); + + $remainder = substr($Line['text'], $length); + + if (trim($remainder) === '') + { + if (isset($matches[2]) or in_array($matches[1], $this->voidElements)) + { + $Block['closed'] = true; + + $Block['void'] = true; + } + } + else + { + if (isset($matches[2]) or in_array($matches[1], $this->voidElements)) + { + return; + } + + if (preg_match('/<\/'.$matches[1].'>[ ]*$/i', $remainder)) + { + $Block['closed'] = true; + } + } + + return $Block; + } + } + + protected function blockMarkupContinue($Line, array $Block) + { + if (isset($Block['closed'])) + { + return; + } + + if (preg_match('/^<'.$Block['name'].'(?:[ ]*'.$this->regexHtmlAttribute.')*[ ]*>/i', $Line['text'])) # open + { + $Block['depth'] ++; + } + + if (preg_match('/(.*?)<\/'.$Block['name'].'>[ ]*$/i', $Line['text'], $matches)) # close + { + if ($Block['depth'] > 0) + { + $Block['depth'] --; + } + else + { + $Block['closed'] = true; + } + } + + if (isset($Block['interrupted'])) + { + $Block['markup'] .= "\n"; + + unset($Block['interrupted']); + } + + $Block['markup'] .= "\n".$Line['body']; + + return $Block; + } + + # + # Reference + + protected function blockReference($Line) + { + if (preg_match('/^\[(.+?)\]:[ ]*?(?:[ ]+["\'(](.+)["\')])?[ ]*$/', $Line['text'], $matches)) + { + $id = strtolower($matches[1]); + + $Data = array( + 'url' => $matches[2], + 'title' => null, + ); + + if (isset($matches[3])) + { + $Data['title'] = $matches[3]; + } + + $this->DefinitionData['Reference'][$id] = $Data; + + $Block = array( + 'hidden' => true, + ); + + return $Block; + } + } + + # + # Table + + protected function blockTable($Line, array $Block = null) + { + if ( ! isset($Block) or isset($Block['type']) or isset($Block['interrupted'])) + { + return; + } + + if (strpos($Block['element']['text'], '|') !== false and chop($Line['text'], ' -:|') === '') + { + $alignments = array(); + + $divider = $Line['text']; + + $divider = trim($divider); + $divider = trim($divider, '|'); + + $dividerCells = explode('|', $divider); + + foreach ($dividerCells as $dividerCell) + { + $dividerCell = trim($dividerCell); + + if ($dividerCell === '') + { + continue; + } + + $alignment = null; + + if ($dividerCell[0] === ':') + { + $alignment = 'left'; + } + + if (substr($dividerCell, - 1) === ':') + { + $alignment = $alignment === 'left' ? 'center' : 'right'; + } + + $alignments []= $alignment; + } + + # ~ + + $HeaderElements = array(); + + $header = $Block['element']['text']; + + $header = trim($header); + $header = trim($header, '|'); + + $headerCells = explode('|', $header); + + foreach ($headerCells as $index => $headerCell) + { + $headerCell = trim($headerCell); + + $HeaderElement = array( + 'name' => 'th', + 'text' => $headerCell, + 'handler' => 'line', + ); + + if (isset($alignments[$index])) + { + $alignment = $alignments[$index]; + + $HeaderElement['attributes'] = array( + 'style' => 'text-align: '.$alignment.';', + ); + } + + $HeaderElements []= $HeaderElement; + } + + # ~ + + $Block = array( + 'alignments' => $alignments, + 'identified' => true, + 'element' => array( + 'name' => 'table', + 'handler' => 'elements', + ), + ); + + $Block['element']['text'] []= array( + 'name' => 'thead', + 'handler' => 'elements', + ); + + $Block['element']['text'] []= array( + 'name' => 'tbody', + 'handler' => 'elements', + 'text' => array(), + ); + + $Block['element']['text'][0]['text'] []= array( + 'name' => 'tr', + 'handler' => 'elements', + 'text' => $HeaderElements, + ); + + return $Block; + } + } + + protected function blockTableContinue($Line, array $Block) + { + if (isset($Block['interrupted'])) + { + return; + } + + if ($Line['text'][0] === '|' or strpos($Line['text'], '|')) + { + $Elements = array(); + + $row = $Line['text']; + + $row = trim($row); + $row = trim($row, '|'); + + preg_match_all('/(?:(\\\\[|])|[^|`]|`[^`]+`|`)+/', $row, $matches); + + foreach ($matches[0] as $index => $cell) + { + $cell = trim($cell); + + $Element = array( + 'name' => 'td', + 'handler' => 'line', + 'text' => $cell, + ); + + if (isset($Block['alignments'][$index])) + { + $Element['attributes'] = array( + 'style' => 'text-align: '.$Block['alignments'][$index].';', + ); + } + + $Elements []= $Element; + } + + $Element = array( + 'name' => 'tr', + 'handler' => 'elements', + 'text' => $Elements, + ); + + $Block['element']['text'][1]['text'] []= $Element; + + return $Block; + } + } + + # + # ~ + # + + protected function paragraph($Line) + { + $Block = array( + 'element' => array( + 'name' => 'p', + 'text' => $Line['text'], + 'handler' => 'line', + ), + ); + + return $Block; + } + + # + # Inline Elements + # + + protected $InlineTypes = array( + '"' => array('SpecialCharacter'), + '!' => array('Image'), + '&' => array('SpecialCharacter'), + '*' => array('Emphasis'), + ':' => array('Url'), + '<' => array('UrlTag', 'EmailTag', 'Markup', 'SpecialCharacter'), + '>' => array('SpecialCharacter'), + '[' => array('Link'), + '_' => array('Emphasis'), + '`' => array('Code'), + '~' => array('Strikethrough'), + '\\' => array('EscapeSequence'), + ); + + # ~ + + protected $inlineMarkerList = '!"*_&[:<>`~\\'; + + # + # ~ + # + + public function line($text, $nonNestables=array()) + { + $markup = ''; + + # $excerpt is based on the first occurrence of a marker + + while ($excerpt = strpbrk($text, $this->inlineMarkerList)) + { + $marker = $excerpt[0]; + + $markerPosition = strpos($text, $marker); + + $Excerpt = array('text' => $excerpt, 'context' => $text); + + foreach ($this->InlineTypes[$marker] as $inlineType) + { + # check to see if the current inline type is nestable in the current context + + if ( ! empty($nonNestables) and in_array($inlineType, $nonNestables)) + { + continue; + } + + $Inline = $this->{'inline'.$inlineType}($Excerpt); + + if ( ! isset($Inline)) + { + continue; + } + + # makes sure that the inline belongs to "our" marker + + if (isset($Inline['position']) and $Inline['position'] > $markerPosition) + { + continue; + } + + # sets a default inline position + + if ( ! isset($Inline['position'])) + { + $Inline['position'] = $markerPosition; + } + + # cause the new element to 'inherit' our non nestables + + foreach ($nonNestables as $non_nestable) + { + $Inline['element']['nonNestables'][] = $non_nestable; + } + + # the text that comes before the inline + $unmarkedText = substr($text, 0, $Inline['position']); + + # compile the unmarked text + $markup .= $this->unmarkedText($unmarkedText); + + # compile the inline + $markup .= isset($Inline['markup']) ? $Inline['markup'] : $this->element($Inline['element']); + + # remove the examined text + $text = substr($text, $Inline['position'] + $Inline['extent']); + + continue 2; + } + + # the marker does not belong to an inline + + $unmarkedText = substr($text, 0, $markerPosition + 1); + + $markup .= $this->unmarkedText($unmarkedText); + + $text = substr($text, $markerPosition + 1); + } + + $markup .= $this->unmarkedText($text); + + return $markup; + } + + # + # ~ + # + + protected function inlineCode($Excerpt) + { + $marker = $Excerpt['text'][0]; + + if (preg_match('/^('.$marker.'+)[ ]*(.+?)[ ]*(? strlen($matches[0]), + 'element' => array( + 'name' => 'code', + 'text' => $text, + ), + ); + } + } + + protected function inlineEmailTag($Excerpt) + { + if (strpos($Excerpt['text'], '>') !== false and preg_match('/^<((mailto:)?\S+?@\S+?)>/i', $Excerpt['text'], $matches)) + { + $url = $matches[1]; + + if ( ! isset($matches[2])) + { + $url = 'mailto:' . $url; + } + + return array( + 'extent' => strlen($matches[0]), + 'element' => array( + 'name' => 'a', + 'text' => $matches[1], + 'attributes' => array( + 'href' => $url, + ), + ), + ); + } + } + + protected function inlineEmphasis($Excerpt) + { + if ( ! isset($Excerpt['text'][1])) + { + return; + } + + $marker = $Excerpt['text'][0]; + + if ($Excerpt['text'][1] === $marker and preg_match($this->StrongRegex[$marker], $Excerpt['text'], $matches)) + { + $emphasis = 'strong'; + } + elseif (preg_match($this->EmRegex[$marker], $Excerpt['text'], $matches)) + { + $emphasis = 'em'; + } + else + { + return; + } + + return array( + 'extent' => strlen($matches[0]), + 'element' => array( + 'name' => $emphasis, + 'handler' => 'line', + 'text' => $matches[1], + ), + ); + } + + protected function inlineEscapeSequence($Excerpt) + { + if (isset($Excerpt['text'][1]) and in_array($Excerpt['text'][1], $this->specialCharacters)) + { + return array( + 'markup' => $Excerpt['text'][1], + 'extent' => 2, + ); + } + } + + protected function inlineImage($Excerpt) + { + if ( ! isset($Excerpt['text'][1]) or $Excerpt['text'][1] !== '[') + { + return; + } + + $Excerpt['text']= substr($Excerpt['text'], 1); + + $Link = $this->inlineLink($Excerpt); + + if ($Link === null) + { + return; + } + + $Inline = array( + 'extent' => $Link['extent'] + 1, + 'element' => array( + 'name' => 'img', + 'attributes' => array( + 'src' => $Link['element']['attributes']['href'], + 'alt' => $Link['element']['text'], + ), + ), + ); + + $Inline['element']['attributes'] += $Link['element']['attributes']; + + unset($Inline['element']['attributes']['href']); + + return $Inline; + } + + protected function inlineLink($Excerpt) + { + $Element = array( + 'name' => 'a', + 'handler' => 'line', + 'nonNestables' => array('Url', 'Link'), + 'text' => null, + 'attributes' => array( + 'href' => null, + 'title' => null, + ), + ); + + $extent = 0; + + $remainder = $Excerpt['text']; + + if (preg_match('/\[((?:[^][]++|(?R))*+)\]/', $remainder, $matches)) + { + $Element['text'] = $matches[1]; + + $extent += strlen($matches[0]); + + $remainder = substr($remainder, $extent); + } + else + { + return; + } + + if (preg_match('/^[(]\s*+((?:[^ ()]++|[(][^ )]+[)])++)(?:[ ]+("[^"]*"|\'[^\']*\'))?\s*[)]/', $remainder, $matches)) + { + $Element['attributes']['href'] = $matches[1]; + + if (isset($matches[2])) + { + $Element['attributes']['title'] = substr($matches[2], 1, - 1); + } + + $extent += strlen($matches[0]); + } + else + { + if (preg_match('/^\s*\[(.*?)\]/', $remainder, $matches)) + { + $definition = strlen($matches[1]) ? $matches[1] : $Element['text']; + $definition = strtolower($definition); + + $extent += strlen($matches[0]); + } + else + { + $definition = strtolower($Element['text']); + } + + if ( ! isset($this->DefinitionData['Reference'][$definition])) + { + return; + } + + $Definition = $this->DefinitionData['Reference'][$definition]; + + $Element['attributes']['href'] = $Definition['url']; + $Element['attributes']['title'] = $Definition['title']; + } + + return array( + 'extent' => $extent, + 'element' => $Element, + ); + } + + protected function inlineMarkup($Excerpt) + { + if ($this->markupEscaped or $this->safeMode or strpos($Excerpt['text'], '>') === false) + { + return; + } + + if ($Excerpt['text'][1] === '/' and preg_match('/^<\/\w[\w-]*[ ]*>/s', $Excerpt['text'], $matches)) + { + return array( + 'markup' => $matches[0], + 'extent' => strlen($matches[0]), + ); + } + + if ($Excerpt['text'][1] === '!' and preg_match('/^/s', $Excerpt['text'], $matches)) + { + return array( + 'markup' => $matches[0], + 'extent' => strlen($matches[0]), + ); + } + + if ($Excerpt['text'][1] !== ' ' and preg_match('/^<\w[\w-]*(?:[ ]*'.$this->regexHtmlAttribute.')*[ ]*\/?>/s', $Excerpt['text'], $matches)) + { + return array( + 'markup' => $matches[0], + 'extent' => strlen($matches[0]), + ); + } + } + + protected function inlineSpecialCharacter($Excerpt) + { + if ($Excerpt['text'][0] === '&' and ! preg_match('/^&#?\w+;/', $Excerpt['text'])) + { + return array( + 'markup' => '&', + 'extent' => 1, + ); + } + + $SpecialCharacter = array('>' => 'gt', '<' => 'lt', '"' => 'quot'); + + if (isset($SpecialCharacter[$Excerpt['text'][0]])) + { + return array( + 'markup' => '&'.$SpecialCharacter[$Excerpt['text'][0]].';', + 'extent' => 1, + ); + } + } + + protected function inlineStrikethrough($Excerpt) + { + if ( ! isset($Excerpt['text'][1])) + { + return; + } + + if ($Excerpt['text'][1] === '~' and preg_match('/^~~(?=\S)(.+?)(?<=\S)~~/', $Excerpt['text'], $matches)) + { + return array( + 'extent' => strlen($matches[0]), + 'element' => array( + 'name' => 'del', + 'text' => $matches[1], + 'handler' => 'line', + ), + ); + } + } + + protected function inlineUrl($Excerpt) + { + if ($this->urlsLinked !== true or ! isset($Excerpt['text'][2]) or $Excerpt['text'][2] !== '/') + { + return; + } + + if (preg_match('/\bhttps?:[\/]{2}[^\s<]+\b\/*/ui', $Excerpt['context'], $matches, PREG_OFFSET_CAPTURE)) + { + $url = $matches[0][0]; + + $Inline = array( + 'extent' => strlen($matches[0][0]), + 'position' => $matches[0][1], + 'element' => array( + 'name' => 'a', + 'text' => $url, + 'attributes' => array( + 'href' => $url, + ), + ), + ); + + return $Inline; + } + } + + protected function inlineUrlTag($Excerpt) + { + if (strpos($Excerpt['text'], '>') !== false and preg_match('/^<(\w+:\/{2}[^ >]+)>/i', $Excerpt['text'], $matches)) + { + $url = $matches[1]; + + return array( + 'extent' => strlen($matches[0]), + 'element' => array( + 'name' => 'a', + 'text' => $url, + 'attributes' => array( + 'href' => $url, + ), + ), + ); + } + } + + # ~ + + protected function unmarkedText($text) + { + if ($this->breaksEnabled) + { + $text = preg_replace('/[ ]*\n/', "
\n", $text); + } + else + { + $text = preg_replace('/(?:[ ][ ]+|[ ]*\\\\)\n/', "
\n", $text); + $text = str_replace(" \n", "\n", $text); + } + + return $text; + } + + # + # Handlers + # + + protected function element(array $Element) + { + if ($this->safeMode) + { + $Element = $this->sanitiseElement($Element); + } + + $markup = '<'.$Element['name']; + + if (isset($Element['attributes'])) + { + foreach ($Element['attributes'] as $name => $value) + { + if ($value === null) + { + continue; + } + + $markup .= ' '.$name.'="'.self::escape($value).'"'; + } + } + + $permitRawHtml = false; + + if (isset($Element['text'])) + { + $text = $Element['text']; + } + // very strongly consider an alternative if you're writing an + // extension + elseif (isset($Element['rawHtml'])) + { + $text = $Element['rawHtml']; + $allowRawHtmlInSafeMode = isset($Element['allowRawHtmlInSafeMode']) && $Element['allowRawHtmlInSafeMode']; + $permitRawHtml = !$this->safeMode || $allowRawHtmlInSafeMode; + } + + if (isset($text)) + { + $markup .= '>'; + + if (!isset($Element['nonNestables'])) + { + $Element['nonNestables'] = array(); + } + + if (isset($Element['handler'])) + { + $markup .= $this->{$Element['handler']}($text, $Element['nonNestables']); + } + elseif (!$permitRawHtml) + { + $markup .= self::escape($text, true); + } + else + { + $markup .= $text; + } + + $markup .= ''; + } + else + { + $markup .= ' />'; + } + + return $markup; + } + + protected function elements(array $Elements) + { + $markup = ''; + + foreach ($Elements as $Element) + { + $markup .= "\n" . $this->element($Element); + } + + $markup .= "\n"; + + return $markup; + } + + # ~ + + protected function li($lines) + { + $markup = $this->lines($lines); + + $trimmedMarkup = trim($markup); + + if ( ! in_array('', $lines) and substr($trimmedMarkup, 0, 3) === '

') + { + $markup = $trimmedMarkup; + $markup = substr($markup, 3); + + $position = strpos($markup, "

"); + + $markup = substr_replace($markup, '', $position, 4); + } + + return $markup; + } + + # + # Deprecated Methods + # + + function parse($text) + { + $markup = $this->text($text); + + return $markup; + } + + protected function sanitiseElement(array $Element) + { + static $goodAttribute = '/^[a-zA-Z0-9][a-zA-Z0-9-_]*+$/'; + static $safeUrlNameToAtt = array( + 'a' => 'href', + 'img' => 'src', + ); + + if (isset($safeUrlNameToAtt[$Element['name']])) + { + $Element = $this->filterUnsafeUrlInAttribute($Element, $safeUrlNameToAtt[$Element['name']]); + } + + if ( ! empty($Element['attributes'])) + { + foreach ($Element['attributes'] as $att => $val) + { + # filter out badly parsed attribute + if ( ! preg_match($goodAttribute, $att)) + { + unset($Element['attributes'][$att]); + } + # dump onevent attribute + elseif (self::striAtStart($att, 'on')) + { + unset($Element['attributes'][$att]); + } + } + } + + return $Element; + } + + protected function filterUnsafeUrlInAttribute(array $Element, $attribute) + { + foreach ($this->safeLinksWhitelist as $scheme) + { + if (self::striAtStart($Element['attributes'][$attribute], $scheme)) + { + return $Element; + } + } + + $Element['attributes'][$attribute] = str_replace(':', '%3A', $Element['attributes'][$attribute]); + + return $Element; + } + + # + # Static Methods + # + + protected static function escape($text, $allowQuotes = false) + { + return htmlspecialchars($text, $allowQuotes ? ENT_NOQUOTES : ENT_QUOTES, 'UTF-8'); + } + + protected static function striAtStart($string, $needle) + { + $len = strlen($needle); + + if ($len > strlen($string)) + { + return false; + } + else + { + return strtolower(substr($string, 0, $len)) === strtolower($needle); + } + } + + static function instance($name = 'default') + { + if (isset(self::$instances[$name])) + { + return self::$instances[$name]; + } + + $instance = new static(); + + self::$instances[$name] = $instance; + + return $instance; + } + + private static $instances = array(); + + # + # Fields + # + + protected $DefinitionData; + + # + # Read-Only + + protected $specialCharacters = array( + '\\', '`', '*', '_', '{', '}', '[', ']', '(', ')', '>', '#', '+', '-', '.', '!', '|', + ); + + protected $StrongRegex = array( + '*' => '/^[*]{2}((?:\\\\\*|[^*]|[*][^*]*[*])+?)[*]{2}(?![*])/s', + '_' => '/^__((?:\\\\_|[^_]|_[^_]*_)+?)__(?!_)/us', + ); + + protected $EmRegex = array( + '*' => '/^[*]((?:\\\\\*|[^*]|[*][*][^*]+?[*][*])+?)[*](?![*])/s', + '_' => '/^_((?:\\\\_|[^_]|__[^_]*__)+?)_(?!_)\b/us', + ); + + protected $regexHtmlAttribute = '[a-zA-Z_:][\w:.-]*(?:\s*=\s*(?:[^"\'=<>`\s]+|"[^"]*"|\'[^\']*\'))?'; + + protected $voidElements = array( + 'area', 'base', 'br', 'col', 'command', 'embed', 'hr', 'img', 'input', 'link', 'meta', 'param', 'source', + ); + + protected $textLevelElements = array( + 'a', 'br', 'bdo', 'abbr', 'blink', 'nextid', 'acronym', 'basefont', + 'b', 'em', 'big', 'cite', 'small', 'spacer', 'listing', + 'i', 'rp', 'del', 'code', 'strike', 'marquee', + 'q', 'rt', 'ins', 'font', 'strong', + 's', 'tt', 'kbd', 'mark', + 'u', 'xm', 'sub', 'nobr', + 'sup', 'ruby', + 'var', 'span', + 'wbr', 'time', + ); +} diff --git a/public/vendor/erusev/parsedown/README.md b/public/vendor/erusev/parsedown/README.md new file mode 100644 index 0000000..b5d9ed2 --- /dev/null +++ b/public/vendor/erusev/parsedown/README.md @@ -0,0 +1,86 @@ +> I also make [Caret](https://caret.io?ref=parsedown) - a Markdown editor for Mac and PC. + +## Parsedown + +[![Build Status](https://img.shields.io/travis/erusev/parsedown/master.svg?style=flat-square)](https://travis-ci.org/erusev/parsedown) + + +Better Markdown Parser in PHP + +[Demo](http://parsedown.org/demo) | +[Benchmarks](http://parsedown.org/speed) | +[Tests](http://parsedown.org/tests/) | +[Documentation](https://github.com/erusev/parsedown/wiki/) + +### Features + +* One File +* No Dependencies +* Super Fast +* Extensible +* [GitHub flavored](https://help.github.com/articles/github-flavored-markdown) +* Tested in 5.3 to 7.1 and in HHVM +* [Markdown Extra extension](https://github.com/erusev/parsedown-extra) + +### Installation + +Include `Parsedown.php` or install [the composer package](https://packagist.org/packages/erusev/parsedown). + +### Example + +``` php +$Parsedown = new Parsedown(); + +echo $Parsedown->text('Hello _Parsedown_!'); # prints:

Hello Parsedown!

+``` + +More examples in [the wiki](https://github.com/erusev/parsedown/wiki/) and in [this video tutorial](http://youtu.be/wYZBY8DEikI). + +### Security + +Parsedown is capable of escaping user-input within the HTML that it generates. Additionally Parsedown will apply sanitisation to additional scripting vectors (such as scripting link destinations) that are introduced by the markdown syntax itself. + +To tell Parsedown that it is processing untrusted user-input, use the following: +```php +$parsedown = new Parsedown; +$parsedown->setSafeMode(true); +``` + +If instead, you wish to allow HTML within untrusted user-input, but still want output to be free from XSS it is recommended that you make use of a HTML sanitiser that allows HTML tags to be whitelisted, like [HTML Purifier](http://htmlpurifier.org/). + +In both cases you should strongly consider employing defence-in-depth measures, like [deploying a Content-Security-Policy](https://scotthelme.co.uk/content-security-policy-an-introduction/) (a browser security feature) so that your page is likely to be safe even if an attacker finds a vulnerability in one of the first lines of defence above. + +#### Security of Parsedown Extensions + +Safe mode does not necessarily yield safe results when using extensions to Parsedown. Extensions should be evaluated on their own to determine their specific safety against XSS. + +### Escaping HTML +> ⚠️  **WARNING:** This method isn't safe from XSS! + +If you wish to escape HTML **in trusted input**, you can use the following: +```php +$parsedown = new Parsedown; +$parsedown->setMarkupEscaped(true); +``` + +Beware that this still allows users to insert unsafe scripting vectors, such as links like `[xss](javascript:alert%281%29)`. + +### Questions + +**How does Parsedown work?** + +It tries to read Markdown like a human. First, it looks at the lines. It’s interested in how the lines start. This helps it recognise blocks. It knows, for example, that if a line starts with a `-` then perhaps it belongs to a list. Once it recognises the blocks, it continues to the content. As it reads, it watches out for special characters. This helps it recognise inline elements (or inlines). + +We call this approach "line based". We believe that Parsedown is the first Markdown parser to use it. Since the release of Parsedown, other developers have used the same approach to develop other Markdown parsers in PHP and in other languages. + +**Is it compliant with CommonMark?** + +It passes most of the CommonMark tests. Most of the tests that don't pass deal with cases that are quite uncommon. Still, as CommonMark matures, compliance should improve. + +**Who uses it?** + +[Laravel Framework](https://laravel.com/), [Bolt CMS](http://bolt.cm/), [Grav CMS](http://getgrav.org/), [Herbie CMS](http://www.getherbie.org/), [Kirby CMS](http://getkirby.com/), [October CMS](http://octobercms.com/), [Pico CMS](http://picocms.org), [Statamic CMS](http://www.statamic.com/), [phpDocumentor](http://www.phpdoc.org/), [RaspberryPi.org](http://www.raspberrypi.org/), [Symfony demo](https://github.com/symfony/symfony-demo) and [more](https://packagist.org/packages/erusev/parsedown/dependents). + +**How can I help?** + +Use it, star it, share it and if you feel generous, [donate](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=528P3NZQMP8N2). diff --git a/public/vendor/erusev/parsedown/composer.json b/public/vendor/erusev/parsedown/composer.json new file mode 100644 index 0000000..f8b40f8 --- /dev/null +++ b/public/vendor/erusev/parsedown/composer.json @@ -0,0 +1,33 @@ +{ + "name": "erusev/parsedown", + "description": "Parser for Markdown.", + "keywords": ["markdown", "parser"], + "homepage": "http://parsedown.org", + "type": "library", + "license": "MIT", + "authors": [ + { + "name": "Emanuil Rusev", + "email": "hello@erusev.com", + "homepage": "http://erusev.com" + } + ], + "require": { + "php": ">=5.3.0", + "ext-mbstring": "*" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35" + }, + "autoload": { + "psr-0": {"Parsedown": ""} + }, + "autoload-dev": { + "psr-0": { + "TestParsedown": "test/", + "ParsedownTest": "test/", + "CommonMarkTest": "test/", + "CommonMarkTestWeak": "test/" + } + } +}