From 49238e2dec3e31b7495bb3ef7b2ff9a3d37df60a Mon Sep 17 00:00:00 2001 From: dsr0018 <36934513+dsr0018@users.noreply.github.com> Date: Wed, 19 Feb 2020 11:15:44 +0100 Subject: [PATCH 01/12] Update build.xml consider test failure as build failure --- build.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.xml b/build.xml index dfc5ddb4..06eb4ed6 100644 --- a/build.xml +++ b/build.xml @@ -39,7 +39,7 @@ - + @@ -83,4 +83,4 @@ - \ No newline at end of file + From 806e45995821b7c241b06b3fa8fe08bfc2017e48 Mon Sep 17 00:00:00 2001 From: dsr0018 Date: Wed, 19 Feb 2020 12:17:14 +0100 Subject: [PATCH 02/12] Test GetInstance MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Comprueba el funcionamiento correcto del patrón Singleton --- .../gii/dass/test/c01/ReusablePoolTest.java | 26 +++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/src/test/ubu/gii/dass/test/c01/ReusablePoolTest.java b/src/test/ubu/gii/dass/test/c01/ReusablePoolTest.java index ae9b0d18..68f6ea53 100644 --- a/src/test/ubu/gii/dass/test/c01/ReusablePoolTest.java +++ b/src/test/ubu/gii/dass/test/c01/ReusablePoolTest.java @@ -9,6 +9,10 @@ import org.junit.Before; import org.junit.Test; +import java.lang.reflect.Field; + +import ubu.gii.dass.c01.ReusablePool; + /** * @author alumno * @@ -16,10 +20,20 @@ public class ReusablePoolTest { /** + * Inicialización de test * @throws java.lang.Exception */ @Before - public void setUp() throws Exception { + public void setUp() throws Exception { + // Utilizando Reflection podemos asegurarnos de trabajar siempre + // con una "nueva" instancia de Singleton en cada Test. + // Esta solución no me gusta demasiado, pero no veo cómo + // pueden hacerse las pruebas realmente independientes si no es así. + // (Porque no es posible garantizar que una prueba conserve + // el estado interno de una instancia Singleton) + Field instance = ReusablePool.class.getDeclaredField("instance"); + instance.setAccessible(true); + instance.set(null, null); } /** @@ -31,10 +45,18 @@ public void tearDown() throws Exception { /** * Test method for {@link ubu.gii.dass.c01.ReusablePool#getInstance()}. + * Comprueba el funcionamiento correcto del patrón Singleton */ @Test public void testGetInstance() { - fail("Not yet implemented"); + ReusablePool pool = ReusablePool.getInstance(); + assertNotNull("Se ha devuelto un objeto nulo", pool); + + ReusablePool pool2 = ReusablePool.getInstance(); + assertNotNull("Se ha devuelto un objeto nulo", pool2); + + assertSame("Se espera la misma instancia para el Singleton", pool, pool2); + } /** From 483171b8373e84ebfcaadf24249a439a01d1202f Mon Sep 17 00:00:00 2001 From: danielsetoubu Date: Wed, 19 Feb 2020 12:29:56 +0100 Subject: [PATCH 03/12] Test AcquireReusable 01 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Test de adquisición de dos objetos reusables diferentes --- .../gii/dass/test/c01/ReusablePoolTest.java | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/test/ubu/gii/dass/test/c01/ReusablePoolTest.java b/src/test/ubu/gii/dass/test/c01/ReusablePoolTest.java index 68f6ea53..fb1805b7 100644 --- a/src/test/ubu/gii/dass/test/c01/ReusablePoolTest.java +++ b/src/test/ubu/gii/dass/test/c01/ReusablePoolTest.java @@ -12,6 +12,8 @@ import java.lang.reflect.Field; import ubu.gii.dass.c01.ReusablePool; +import ubu.gii.dass.c01.NotFreeInstanceException; +import ubu.gii.dass.c01.Reusable; /** * @author alumno @@ -61,10 +63,23 @@ public void testGetInstance() { /** * Test method for {@link ubu.gii.dass.c01.ReusablePool#acquireReusable()}. + * Test de adquisición de dos objetos reusables diferentes + * @throws NotFreeInstanceException */ @Test - public void testAcquireReusable() { - fail("Not yet implemented"); + public void testAcquireReusable01() throws NotFreeInstanceException { + ReusablePool pool = ReusablePool.getInstance(); + + Reusable r1 = pool.acquireReusable(); + assertNotNull(r1); + assertTrue(r1 instanceof Reusable); + + Reusable r2 = pool.acquireReusable(); + assertNotNull(r2); + assertTrue(r2 instanceof Reusable); + + assertFalse("Se esperaban instancias diferentes de Reusable", r1.util().equals(r2.util())); + } /** From 8fb119d747029536d3b55824317b3b7273a940c1 Mon Sep 17 00:00:00 2001 From: dsr0018 <36934513+dsr0018@users.noreply.github.com> Date: Wed, 19 Feb 2020 12:41:05 +0100 Subject: [PATCH 04/12] Update build.xml --- build.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.xml b/build.xml index 06eb4ed6..d22c0fa0 100644 --- a/build.xml +++ b/build.xml @@ -39,7 +39,7 @@ - + From 646aa0cdb032567e852e0402d3b73fd425a5f19e Mon Sep 17 00:00:00 2001 From: dsr0018 Date: Wed, 19 Feb 2020 12:56:19 +0100 Subject: [PATCH 05/12] Test AquireReusable 02 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Comprueba la excepción NotFreeInstanceException si se solicitan más de dos objetos reusable --- .../ubu/gii/dass/test/c01/ReusablePoolTest.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/test/ubu/gii/dass/test/c01/ReusablePoolTest.java b/src/test/ubu/gii/dass/test/c01/ReusablePoolTest.java index fb1805b7..d090239b 100644 --- a/src/test/ubu/gii/dass/test/c01/ReusablePoolTest.java +++ b/src/test/ubu/gii/dass/test/c01/ReusablePoolTest.java @@ -81,6 +81,22 @@ public void testAcquireReusable01() throws NotFreeInstanceException { assertFalse("Se esperaban instancias diferentes de Reusable", r1.util().equals(r2.util())); } + + /** + * Test method for {@link ubu.gii.dass.c01.ReusablePool#acquireReusable()}. + * Comprueba la excepción NotFreeInstanceException si se solicitan más de dos objetos reusable + * @throws NotFreeInstanceException + */ + @SuppressWarnings("unused") + @Test(expected = NotFreeInstanceException.class) + public void testAcquireReusable02() throws NotFreeInstanceException { + ReusablePool pool = ReusablePool.getInstance(); + + Reusable r1 = pool.acquireReusable(); + Reusable r2 = pool.acquireReusable(); + Reusable r3 = pool.acquireReusable(); + + } /** * Test method for {@link ubu.gii.dass.c01.ReusablePool#releaseReusable(ubu.gii.dass.c01.Reusable)}. From fb1cc89c9dafa7a8689acc98662753ec4872ea24 Mon Sep 17 00:00:00 2001 From: dsr0018 Date: Wed, 19 Feb 2020 13:00:54 +0100 Subject: [PATCH 06/12] Test ReleaseReusable 01 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Comprueba que se liberan correctamente los objetos del pool y quedan a disposición de los clientes. --- .../gii/dass/test/c01/ReusablePoolTest.java | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/test/ubu/gii/dass/test/c01/ReusablePoolTest.java b/src/test/ubu/gii/dass/test/c01/ReusablePoolTest.java index d090239b..9f278019 100644 --- a/src/test/ubu/gii/dass/test/c01/ReusablePoolTest.java +++ b/src/test/ubu/gii/dass/test/c01/ReusablePoolTest.java @@ -12,6 +12,7 @@ import java.lang.reflect.Field; import ubu.gii.dass.c01.ReusablePool; +import ubu.gii.dass.c01.DuplicatedInstanceException; import ubu.gii.dass.c01.NotFreeInstanceException; import ubu.gii.dass.c01.Reusable; @@ -100,10 +101,23 @@ public void testAcquireReusable02() throws NotFreeInstanceException { /** * Test method for {@link ubu.gii.dass.c01.ReusablePool#releaseReusable(ubu.gii.dass.c01.Reusable)}. + * Comprueba que se liberan correctamente los objetos del pool y quedan a disposición de los clientes. + * @throws NotFreeInstanceException + * @throws DuplicatedInstanceException */ @Test - public void testReleaseReusable() { - fail("Not yet implemented"); + public void testReleaseReusable01() throws NotFreeInstanceException, DuplicatedInstanceException { + ReusablePool pool = ReusablePool.getInstance(); + Reusable r1 = pool.acquireReusable(); + Reusable r2 = pool.acquireReusable(); + + pool.releaseReusable(r1); + pool.releaseReusable(r2); + + Reusable r2b = pool.acquireReusable(); + Reusable r1b = pool.acquireReusable(); + + assertSame("No se recupera el objeto liberado",r1,r1b); + assertSame("No se recupera el objeto liberado",r2,r2b); } - } From d24df01d33bccae595fd3b58f4a2bf0bce74ac3b Mon Sep 17 00:00:00 2001 From: dsr0018 Date: Wed, 19 Feb 2020 13:03:45 +0100 Subject: [PATCH 07/12] Test ReleaseReusable 02 Comprueba que no se permite liberar un objeto ya liberado. --- .../ubu/gii/dass/test/c01/ReusablePoolTest.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/test/ubu/gii/dass/test/c01/ReusablePoolTest.java b/src/test/ubu/gii/dass/test/c01/ReusablePoolTest.java index 9f278019..1aa45388 100644 --- a/src/test/ubu/gii/dass/test/c01/ReusablePoolTest.java +++ b/src/test/ubu/gii/dass/test/c01/ReusablePoolTest.java @@ -120,4 +120,21 @@ public void testReleaseReusable01() throws NotFreeInstanceException, DuplicatedI assertSame("No se recupera el objeto liberado",r1,r1b); assertSame("No se recupera el objeto liberado",r2,r2b); } + + /** + * Test method for {@link ubu.gii.dass.c01.ReusablePool#releaseReusable(ubu.gii.dass.c01.Reusable)}. + * Comprueba que no se permite liberar un objeto ya liberado. + * @throws NotFreeInstanceException + * @throws DuplicatedInstanceException + */ + @Test(expected = DuplicatedInstanceException.class) + public void testReleaseReusable02() throws NotFreeInstanceException, DuplicatedInstanceException { + ReusablePool pool = ReusablePool.getInstance(); + + Reusable r1 = pool.acquireReusable(); + + pool.releaseReusable(r1); + pool.releaseReusable(r1); + + } } From 61be41e9586f025936c2bf75c38840d29770fced Mon Sep 17 00:00:00 2001 From: dsr0018 <36934513+dsr0018@users.noreply.github.com> Date: Wed, 19 Feb 2020 17:40:07 +0100 Subject: [PATCH 08/12] Disable codecov patch coverage --- .codecov.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.codecov.yml b/.codecov.yml index 50989250..fedf3661 100644 --- a/.codecov.yml +++ b/.codecov.yml @@ -2,4 +2,5 @@ coverage: round: up range: 0..100 precision: 3 - \ No newline at end of file + status: + patch: false From 5079ace69149d1992cb52c2b78070cf221183d74 Mon Sep 17 00:00:00 2001 From: dsr0018 <36934513+dsr0018@users.noreply.github.com> Date: Wed, 19 Feb 2020 17:45:13 +0100 Subject: [PATCH 09/12] Update README.md --- README.md | 91 ++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 87 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 4078dc6e..8e43b70b 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,89 @@ -poolobject -========== +## Medir para caracterizar entidades de productos y procesos software +[![Universidad de Burgos](https://www.ubu.es/sites/all/themes/ubu_theme/images/UBUEscudo-1910.png "Universidad de Burgos")](http://www.ubu.es "Universidad de Burgos") -Java code example of design creational pattern pool object +**Práctica 01 - Desarrollo avanzado de sistemas software** +Grado en Ingeniería informática - Universidad de burgos -Example to apply good practise in software developmemnt: test and mesurement. +Daniel Setó Rey + +------------ +[TOCM] + +[TOC] + +### Enunciado de la práctica +En la práctica se va simular un pequeño desarrollo de un producto software para realizar mediciones sobre él. +El objetivo es establecer un caso de estudio que sirva para caracterizar y evaluar tanto el producto desarrollado como el proceso seguido. +#### Descripción del producto +Dado un código de ejemplo del patrón diseño creacional Pool Object, se debe crear una batería de pruebas tal que las coberturas de sus clases sean del 100%. El código de las clases se puede obtener en el repositorio +https://github.com/clopezno/poolobject. +La batería de pruebas JUnit debe estar contenida en la clase `ubu.gii.dass.test.c01.ReusablePoolTest.java` +#### Descripción del proceso +El proceso de desarrollo de la batería de pruebas se va a gestionar utilizando el control de versiones del sistema Git proporcionado por el repositorio de proyectos GitHub (https://github.com). +Los pasos para gestionar el procesos son los siguientes: +1. Cada miembro del equipo tiene que estar registrado en GitHub, Travis CI y Codecov.io. +2. Uno de los miembros tiene que realizar un fork del repositorio donde se encuentra el código que se quiere probar https://github.com/clopezno/poolobject. El nuevo repositorio tiene que ser público. +3. Invitar al resto de miembros del equipo para que puedan participar en el desarrollo de las pruebas. +4. Vincular el proyecto con Travis CI y Codecov.io. +5. Cada nuevo test realizado ejecutar un commit/push al repositorio del grupo. El texto del commit tiene que describir el caso de prueba añadido. +6. Verificar el resultado de las pruebas en el pipeline de integración continua y cómo la calidad del producto va mejorando con las sucesivas integraciones. + +------------ + +### Ejecución y resultados + +#### Setup y configuración +Se ha hecho un fork del repositorio https://github.com/clopezno/poolobject y se han enlazado las correspondientes cuentas de travis CI y codeconv. + +Inicialmente se detectó un problema que impedía la correcta finalización del build en Travis con la configuración del repositorio. Tras realizar diferentes comprobaciones y estudiar posibles soluciones, el asunto se resuelve mediante una modificación en travis.yml. por parte del profesor de la asignatura (https://github.com/clopezno/poolobject/commit/704d82252d75e8799a5d724d1ca119199dc2cbaa) + +Realizamos finalmente un nuevo fork, correspondiente al presente proyecto (https://github.com/dsr0018/poolobject) y solicitamos un build desde Travis, comprobando que el setup inicial actúa como se espera. + +En nuestro entorno de desarrollo, basado en Eclipse, clonamos el repositorio git y creamos un proyecto de Java para el desarrollo y ejecución local de test. + +#### Casos de prueba y desarrollo de test +Con el objetivo de lograr una cobertura del 100% de `ubu.gii.dass.main.c01.ReusablePool.java` se diseñan varios casos de prueba basados en el *stub* proporcionado con la práctica. Algunos test se dividen en varios casos de prueba independientes. Los test se ejecutan con jUnit 4. +En la siguiente tabla resumimos los casos de prueba diseñados y su implementación: + +|Método|Caso|Descripción|Test|Resultado esperado| +|---------|-----|-------------|----|-----------------------| +|getInstance()|testGetInstance|Comprueba el funcionamiento correcto del patrón Singleton|Petición consecutiva de dos instancias de ReusablePool|Se obtienen dos referencias no nulas al mismo objeto (instancia Singleton)| +|acquireReusable()|testAcquireReusable01|Test de adquisición de dos objetos reusables diferentes|Se solicitan consecutivamente dos objetos Reusable al pool ReusablePool|Se obtienen dos instancias no nulas diferentes de Reusable| +|acquireReusable()|testAcquireReusable02|Comprueba la excepción NotFreeInstanceException si se solicitan más de dos objetos reusable|Se solicitan consecutivamente tres objetos reusables mediante acquireReusable()|Se lanza la excepción NotFreeInstanceException| +|releaseReusable()|testReleaseReusable01|Comprueba que se liberan correctamente los objetos del pool y quedan a disposición de los clientes.|Se solicitan al pool dos objetos Reusable, se liberan y a continuación vuelven a solicitarse otros dos objetos Reusable.|En la segunda fase se obtienen los objetos Reusable liberados en la primera.| +|releaseReusable()|testReleaseReusable02|Comprueba que no se permite liberar un objeto ya liberado.|Se solicitan consecutivamente dos veces la liberación de un objeto Reusable.|Se lanza la excepción DuplicatedInstanceException| +#### Cuestiones planteadas +**¿Se ha realizado trabajo en equipo?** +No, dado que la práctica se ha realizado de modo individual. No obstante, se debe indicar que el setup empleado y el proceso de trabajo sería muy similar, dado que en el contexto de esta práctica no son de esperar problemas de integración continua derivados de la colaboración de varios participantes. + +**¿Tiene calidad el conjunto de pruebas disponibles?** +Se considera que el conjunto de pruebas diseñado tiene un nivel elevado de calidad, debido a los siguientes motivos: +1. El código a probar consiste en una aplicación sencilla del patrón Singleton, cuyos requisitos funcionales son simples y ha permitido diseñar casos de prueba basados directamente en la utilización típica (trivial) de los métodos de la clase. En un proyecto más complejo de software puede ser mucho más complicado conseguir una buena cobertura funcional. +2. Mediante las herramientas automáticas podemos comprobar que mediante el conjunto de test empleado se consigue una cobertura del 100% de las clases que implementan Pool Object. Según codecov: https://codecov.io/gh/dsr0018/poolobject/tree/master/src/main/ubu/gii/dass/c01 + + +**¿Cuál es el esfuerzo invertido en realizar la actividad?** +Se estima un esfuerzo individual de aproximadamente 8 horas para la realización de la práctica, de acuerdo al desglose presentado en la siguiente tabla: + +|Tarea|Horas-persona| +|------|-----------------| +|Setup y configuración inicial
Incluye solución de problemas con el repositorio original|4| +|Diseño y desarrollo de test|2| +|Análisis de los resultados y documentación|2| + +**¿Cuál es el número de fallos encontrados en el código?** + +No se han encontrado fallos en el código cubierto por el conjunto de casos diseñado, como puede comprobarse en el log de Travis correspondiente al último build del proyecto: +```shell + 61 [junit] Running ubu.gii.dass.test.c01.ReusablePoolTest + 62 [junit] Testsuite: ubu.gii.dass.test.c01.ReusablePoolTest + 63 [junit] Tests run: 5, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.045 sec + 64 [junit] Tests run: 5, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.045 sec + 65 [junit] +``` +https://travis-ci.org/dsr0018/poolobject + +#### Conclusiones +La práctica ha constituido una buena primera aproximación al empleo práctico de un pipeline de integración continua en Java, en relación a los conceptos teóricos de medición y calidad en el desarrollo de software. +Destacar que el trabajo aparentemente inutil realizado inicialmente, derivado de la incorrecta configuración de Travis, ha servido al autor para estudiar bastantes posibilidades que desconocía de configuración de Ant. +Además, la práctica ha provocado una interesante reflexión acerca de la mejor manera de realizar un conjunto de test unitarios sobre instancias Singleton (un aspecto este que en opinión del autor no está resuelto de manera completamente satisfactoria) From d4303cc546780f355960fdcfa7c84e50243b69df Mon Sep 17 00:00:00 2001 From: dsr0018 <36934513+dsr0018@users.noreply.github.com> Date: Wed, 19 Feb 2020 18:01:27 +0100 Subject: [PATCH 10/12] Create image folder for doc --- img/dummy | 1 + 1 file changed, 1 insertion(+) create mode 100644 img/dummy diff --git a/img/dummy b/img/dummy new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/img/dummy @@ -0,0 +1 @@ + From 481981bcc927c5fc3878d49bbe2e70c161de86fd Mon Sep 17 00:00:00 2001 From: dsr0018 <36934513+dsr0018@users.noreply.github.com> Date: Wed, 19 Feb 2020 18:01:43 +0100 Subject: [PATCH 11/12] Add files via upload --- img/codecov.PNG | Bin 0 -> 24590 bytes img/emma.PNG | Bin 0 -> 16944 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 img/codecov.PNG create mode 100644 img/emma.PNG diff --git a/img/codecov.PNG b/img/codecov.PNG new file mode 100644 index 0000000000000000000000000000000000000000..8f62ce9d8cc97220bc4a3255cd5d82edd34261ac GIT binary patch literal 24590 zcmeFZ2UJsSw=RmJqN0Kzpwhea4^Vnh5Rf7$y+PtuJyk2na?xl zioIcNcJlc7<7{kfC(W;2wPj;FNMd63WBev>(p#@;)knff2 zSJ>EUlR5Wp9|rc1-Mi)z!p3&$^ZwrfTwp1fjSW<2e)Wp|15YY;wNAL}_R50j8b@1s zAJ^_NONTQ06U+sNGIzIPTW)Wwgz6v>sTFK@m?}l_u$ESBr$=4uxE}gwM;qJbFC~Ie zi>k`Cxv+xSvmD|VZdW@iUOspT!!0Hr6vGz#A>+^ysJRCE;pB3De)e+ya=x}1IaimQ zJ5aJ1-=Dp_u#mkFF{h3six`LlcCxX(RuKbS12*JA;=Xrm^Ss>}`=6H!?tvqw+8Ix| zjgE>xO$m8%-2`)hjn-E?gX>dZV|)0mMHx8q{h#}X-+BUNXWQTg3$n36Q($ZlMIHnD z4^N^`vVAoM_SxQF0S*m63hc9K0B66^e(7pkJz)4;||KB<3 za+>Dk1LM8r6=wC0CTni$g-JZWbm8K`4-X#hTh(XeF7PrUVD$Z!-hqJ}Y3%LSXvSax z(>`*Vw}88GJUCwK-k%R2tYEjTVhK*|YkVG!>eg{ip^U3-U!VDJ^*D7^7qp4drZSAZ zXgRuFT{)++x5@aR)lW8vSSOoTjl$?qLO{^!7}BdIY$_zFLo5nSaR@8cHQT1i5wY>CsKy-?*3`|_&KZ@sj&_e_T%#wquHhdJoi&}_+Xj-#cA5(MZQqRlaUYj? z+%PMxD+a4${x#V=nE~L4TaVoc&E5S*!2xO&^A*sFDgOJ~70BxQ>KJ}2%)o5%dKq?_ z)AltrCneM;y4bggwQXii2<tvGKONM;TMFPa@k#GlmNimk9BZk+NE>rB#jMEZvvm(zvUeRj2YSM-u`6PYa_ zIBbgHqncro20?PIZkvkLWmEQ18NI{TTpfz*sN`T&rY=bZ+*?(l{W>X(dB^PhC5k5{ zrA5EaLxHxF<(o?bQGdW*fT3MKYVE@<$?&jy0YjwpWT->oOr?g5m!7Z^(8mW0psn2Y; z_O=5+4y?*3|2Mr;9AGz$-EkNu@VZFm9f`U`ux<+@Bozkuu}wM%dd-e279<9!VG@32 zQo|(5F);Ho1M4~DY?esMjIA)2?}-a*tFPYnBz~;vM21!n7i7CYQ}nn8TQMV@Useni z91UstO*RB2s3?`I3K4+>OPSKZcW2+ZbD z6e9cL&h*fbH`_^3c>9c_#~wDTjA;RD_TVQL?TpE$nA}{yG!vv;!q=gcL3#-oLmM9Jtf%3 zw6w~3Q#8~9udPfaJm(QUj8>$(xcO~7Bv!WKFAfe^zuHSP#)&%fT zO(zWo>dlP``##?&S(ZV4mfU{lF=GR)dn12)V8znWP>GZ%lGy!?kxqJ_9yp+#bRFFK zq;@u!H)BO$W7zsOL!;PIB z!MY6~#`ed%LBHl(r+7_fR zI*H&`-j5kZ_InnSsQ2?wFXbn*Iu;mMYQw@W%1^+2Nmoe6cF#68otgx8d`lwGCAM!r zkxmQm(4hAC=v^NtI;#u1zN9M5s$Kg`UgcZNBI4|Ci{h*yfFtkjeTf@SVw$4%n#gM~ zHKlFcm5OrTOg@~Nj;Hbcd)}{qGjW%qBgvjYQ{s{YILl5j5VY1rZVvf7NVWdz5&$Xs zV1_z&t>@Io!tArl-EgbJ?yr*x?OB<|UFO7L&GN~@$9PaO7+~psi8gR*UpD~YF zz2bFK#6yAfhVPhok@C@@TSf&Oyx_Q^Pdj2|Vx*@j?T6l+x0+wS_1G%a{;a4J-~REL zV)jptAw{fGyBywBzXOM;9#r-KA}>V2+6+j~QLc z`bz$IC|jcJ4})v+-5TOWDpyL6@B(g&*-7zz;V?f;lzF-#{jXr0eg>5hsw@!CuT<`{ z8(zz5TzNqqEa2z0WM17Hv@B;Hs10bA2T5ZNk4Zc|5&E~Y9^1P=1gB#Y6}tEe3_w=% z{?kvjSc6V+HG$*ON%?Dwr^I&Q;j@@~VKZ&_8=HcAp6+aHNKRiZjqLqS-O&oWpV<^K zn=w5|wgI)QD=^&duuve{GW#*%{-}PBD;e zXXKVALwVKk3o$nsHXZa<0EF#aEi7$$qoH$bS|=;vdVvjgklI{pHWak7kVaS$4g3;BufOU1>QdDhqN~ zQO?BO`<6BkpQ8a2un~>))Wd{fcPa*~U%XpuYCq@v{Ddz}f|NNCCg!|+geU`kImr3O z2tzS0;7ISMN4nz4YGH{v+?i9&13B;XlqMrs^_x-m7P6sEYO>7L;IQjvn4H-kywh_K zKN)(w*F^lJv(~2N>g2(_;U^m^>={&8#Y=Y;0g6O&YOdbK>!yV`h*vDs`&$}hI&LWW z#oh=s(4fK7ef`|Jf0ML8od0s*E{0W~T3y zPHGpCkp>|~kvo$t@lH~-*g9@{W*ZS#=X-FoUmPncSkf6N(&ms$YZQpJ%iMdUwVBB> z-=lTeJqn*FnK9@<7Bo5bxhgYsSDj18<3f-*TA;n3mndE7yOrCPlrBg-DvmOO*AY-o z9qE;x#s?ZI%teJ)>^zRzxMh^figD{IEN*WmA@`6r~`}4OP}&reWo% ze*rOtNR7l=jqg2>OP5`4b;Q)#V^*zep=Z7?>~tr6mZ;sBlYKmElDl4aP0=WNC7CUtjuOfzWL!>gm*dn|irDRG)(jkf(;$>M=*XJ?v9oSO)0 z1b=-b4pQ!ZJbBDIO4xHtUjJtW`!Zo!d?2>Rd`3LqmA^i5fx1)`de>V z{TBE^b`Y;6WP&if%)62u<$0e}M`UWD8J4Qi;JTgiaMn;Cai$O#CD$+1ZdQ4N9!y2f z-Aw;Hy=<5YSEivx3#XE;b%aHC!dp9P>y?PLh{FSfLGh*3w-B5`m zKZ;2?80M76^*Y`$Rw*Jmq~vNhcaeb6r5^xB-9*;nPs7qVIwbRt4y~wR`9{c{xRnQQ ztJb-u3%QIoTP*|Wk&b&b!)S~=Nv(v1tG&et_#RXsh{v?|E4A21(z}9*%OvHmBgU5o zvl{KJyz;_txYvv+iHwZOwj;|T1Eu6!Pi2lwyp5bTt;Jr@L?f@_-$&-fH&wHCrpzC; zULM~{2oHP;o35KqHc&XsTHBnC*;_qgh8aRX@3bIe@po6}>&H3_`9eieD+P2^)3wP9 zl})mlpTC)x%oL_VbJk}P-ZZZ8IaNRumQR~SwK`QcUu)MO8>Fus3!)-z?@{`zw4)2s zHEsJf^3K|*gM#1qeplHs?E377*h4nM9ApBIbKzTvS{h`Rnh5*Iz!=32nkVz2Bd|hK z0kGNPhR55Xh50wpZEI(H^qK1So~CHL+aEn(kONkojAco!T{ymPA_s}>yIf`8y{z#kAa-2+8>yZlb!U>ZuU%mp*Fn3sr~ZJsQe+@* zrkq<6LEm2as;_$LD2WJvB&X^Mi^?uzT}1~u10pn>tL?P6<>$0=)*1LOh8fgSoN2-d zGOlrX{0Is4DWF|gIvQ#so4IS8(>3HbtqyAcweGcPL*5K0YMtt=^bhnF8WbRI*?8vD zvZ*$)tcy98EwN0QbaY~RV22cwKD2mhF@9PUq@2lXG?wAXIVAR-WFUHm#kkE zu))w()3~PS+YZF2?J|U+>Dq6WM+Q|T%KNsc3^H zlTA&6&|QK^htcELIwVOxTkCe3fuS|6T~fr`t5`nUKT$}RNE7|Xx1yg|*b)1EuV#8m zDW|!nxC*RHAp6W@8ruJgO3mC8uhof6vS#Cm8Eg^zw z)V*X46<2AE0Hl##=r8l2)=jr`Ny8m7EcnL zsW-(8v@u@nJk#r0Y_3nN8+buR1PTZ`MVq_V&D~v{D??6;vi2;324yyTzgITFV)V** zN8+NxNU#F#@A(_MD=+f#!`yc_T#POAY(;_(`4))QNYvDw^9P(NZ#Y$jQBWFKvg0T};-#PWR5;>c&`Y zIlUL~nKFIL3I@Ury=-?$#qZq%)|=h$+tLD_lEY=QjsO5f{540CQ%_s~!0bZHz)FWA z#(AV>Zw#}XYHPIEkyvC$Y`b}ufH~lcbA;jW*fvR+> zoo?rKOZK{INz`qj!Mxdet(HOB$%OEyztllI6$}>y&xwDA-i0c5zuf;1y#Ig9JsQxA zFCFdXN5zH7UlpD|`RCj##oiAB@Djk*!u}u0+{*w{2W+%M`-B1;+gI8Bloz0J4ITlc zD6nlD+ov=DKG0V;874^u{sH8G;&RW(9maQ4H?)7;r&nw()D_{jRfsSk( zy(bnCT@9V6H-lcPL55?M9tQaa_}D6X>Ph?b(Rp^8Rhykr*;f7C(wu#jS$KM(ngbP1 zzcUjAwLrAV`X1EJ&y(La_qkx*rS+|6H#_Hay5j_Xw_2fQw>dWtPmqb}C|4FNFNnSQ zx^AFoZLiF}hL3njN~I=$2HdQV*}LM0Z`p+c4u~2cZ1?8N3g#4C zovJ~yQOZL!2Q-mc8x;gmnWSf3S?T?_fTRKWdamm zAj&j3U67b8G7SF==J7C4=J}is+wAW7iwk$_Ps)MnfKh_knJbL}$6q>$cpSUd*r61d zS7}33Z0isWC+)U;++_O_qb*0=B|H<*ryp!(dnx)=V~Zo2{^FSR1JKxKcU7%do*QFG zkuUKtv|J9l^XLYK3BqSs4it6!Mtw8AXJx*&xrpD?>LJvr z7Ph=5)g+Yl&$mKHQU{`**NXC)rvh}-80wZnZGV?$j&|elkUEh`@9f3YDXpaP`g@pF zUMde@R)$9EKdc4dm#^qkPPrGi7vg&^>%Q=~IHpX}NCdlq^ioR@+^308p-#`=Dv(y! zMtAN-D{nr?+zbiwzgYZQ<^D#t{kTwb6I!?lp@q)7;8X+8gGSD)ewz=sx0!-OkU#QH zCn>2opkV_!EuK>lU8!onY`GeXd&7>ZoD-=~`i_xstN8EQ5%#m{=OddIxTZfmUlzL? zd^1qcTbwlKr7hK}ex%+81B)v-W{G|_>wEjmojj=SOK+!bv*hFt&H#wj!u(H`eHpOw6L`oX}azt)8 z=^}?o%g1oG!XzfQy%9{7{$Wt`eFj>QGva2i@*$JxXVb^?daivVzu|_}49H|FhLJz? z-&i7L{mFeZ+sWd0z&vYq_x4mQ)GXM7b^@z=h3DbNH^j36F&=c6P0~_{1tZ; zX)>g^QO(rRoACYLv6-f}B2B0d2PmO4L~8Dzhtl<9v_}hk>lY+UkBna z;KccdR;kV@Fn}ZkBIs8(a9rnOXga_m0>3)~kbnT_0cb|Rm5XfI618F^fQJME>gxmD zXJP?v5Fjc6A5UH`zNXl%0g#1&(s_qX&BW^p#vEW10VCM|lP>jc1Wg!c3!3*IkkM zxv7?8{eNt^BqhmJ48)iGx^qsk`z2nv)@L_tI$aZ5{Zha6C(mk67ut%R{Fw4WGaC_&ylipHrpU1etP61y9?8E(*G}!(+Bmh2IoX|)Qjxo=p)zpg!HIl@ zZ0NS<^z(G9ddm(Cqfx(~{WL9YyYh1WPbfmgav|KE>?7kgMYa(2Ejgk*-u+Vgef!fp zJ?J7c%UEeuX2hVQv+Ew(s?*|4wZit4pf-VCN%QN#bXr?xbp)P#3?&_O%Wxy_kl|G` zo=yQJwsXnYmf9>uCvRL7ELr{1ayfliiaiy!xgx33D^Pn^VqBHj-&NcN{|lFR8PGYk+y079fN9!Z9b>EzzMqJl5=!xpyS(J!Sd+zPc0>>_JQ|lea?iJ z+28CAy7Ae9EYPC|-+9vO22|gaV^qA4*?KfbQ5*e_Ww=i9h1TU)dz(9RoC_rmlU+qy zAEq2hu7H2Gck*;u=Bz=6IB4=y@Kvi~-pLtX&j!4D)V<}l!gSr+`>hhU1C88xUo9x9 zOyZF?ZSM7}g-1)TROVQ|^fc>>BaBjY(lX4eBp+>sW5gDzC<5oB%|()W7BRsG-u%TS zFgeQ_k4bZA9?)Gf7{!UD6W{7jBsH7YqHr|#<>)BA@hx}rQ!oX|_Kv&6YUb9bjfq^@ zMvsUNEOLV`F{Mj+72K$QE<)E)Favoqp|A?!hGQCS4MJy1noDOI7e-?fKZW1$M?caP z-*4e`nBjEm0{e-`+^!M905oy2T?ptQXxf z;8uyb{C&uvo`QlBwq1XL8SdksC>IBs2B4X--H6Nf!bIzrx`g-~N&oBw1yXFSv##T; zzlW@#Xt-79@PZh7Dm9P8=7lb%&AtbtAGjF)Bm?GTBtP4QP`gbyTq#j?b9}RWdM3mF z2fA{q`Uj+m)IXdY_x976joCqc=z){ooOvA{vB)-doQ5Q}BaF3vj;I%atV>>-`;y7J z#WF^hp|WSV&)f8?BEDRC7UFqu7LJq9i86xmjpC+s2NFjF9iROSqso8&-KK$_(C@ZK z-AsY$b}^mP_|iJ;Q>c29VkB!k;~V4KjN~6Ee>HAm5|S~sz}3GPPL?8JMn^w+mv+~y z+}=_%y9G73dXXoiz=iiR+4~fnUBjEE7MeXJVDstBWYnVfEtsUNA}NZsHgitv$na`X zLE#4T2wl`@#jY=koYgV}#!3Ac!D}7M$O++|bgD3%Ty?sbNgZ8nBppq}?Sy}RewvE1 ztVl);X&6?(UL2E8PW|!33UZ8qxO`cNcg0pu$z8~FpbtBOi!kSPY^Jv z~6W1XyDX_0Gt(axDw&K+3EImsXFTF4ViygYLS4Rfbr?3gtIe#Ykc0XphOS z&Vb}Xte5% zgEt)7we>odBY87l>e;Zv+L<$={`wv6JYxk|j!FajLlqIk$<~=0&B8S*d_=?+XnI3h ztg!{#Hm-|G+oN}-(*+kho=@1cDlx`%w}{)%o?ngh3{a2Ya~;t3Wd^0p!{b7@$DE>b zU8t5&A_k;OvJi=mA=We?KvE5qlbkQMUjO#3<?B($9M3FM19bzKW&J6*DSU5Y-NPyWyn-5Yv_dc*KHH^M z)7J(-(2nei9^elC6V$wv29wjw82yx5Xd+o78RH!9{wU;WHl)#h~!X_GlUbB6;hpBdLm35aP4Nm#pT&hq>lOt+Oapg7gRr=!Z(-EK{ zwPuyBx*;Y)ItfZ%p>9G%d$*?PIh#|;gtudt7_}y9D}^p|LJ`gV8>qdxPb2~OWFM>4 zblYS(bHa(-q=m#6xzx-gXx2<2MB`^bw#PAzHjh-D>KBBfp8!kWFc>Q?mOgxA?_A&3 z>%)JHk~Ic+6nYb{Pfm$9e+X}mfJ^;7_P{a>b^+Zy6;o_Ds zSWt?ZLJig!%X8p(hynEKeLQIag1DWg%kb!yp8{}T4j_i_Lqq_#0WkBA2=r$=r``G@1U)bdDPbcI+3B4dsIYZYRTYiO2{}@YPx$k)@7|bzG-~K~@&y2C z+l*-o9Esk0^&XzC>xova-$&H^8*#!B{E;BDco)@%2er<*zJ9}sf$D2@(C>@uzY^TP zBc9a`1mCxEK?3xc8R6EIVtYjFCBgu2LEG(+cT2>RnJ;XVQ4pQX7ne9D)AWKi~6>&%WX%>pbFoF`H0K+r|8C<5c&rLxer(Y|9N$b{K%i2O8&ed>R#Uk z+P|VTPA?Ti7Y=IJvt(l6Hj-tN^BXy}C^_}Ql0z8zqV|{I+QSyuE#CrfBL^7h3r|r? zFk>umgh#%iU18Zr-vgKS{*>A>x@w@o0C7P4q=*ycSy^=(dR)MhK35)~IGo`&bLESO z!W-4`ivTKWoMbfY?EVCuStahw-}cZn70;kKZ7nN$IcN=4`s`l#+~vO=iwzIk40>+G zJ&4X~tU0VblrM`7$F}wI8aiR>5XGTQ3}sQv-xzNUXhYU!GM~RMxETu~CVmkw(GTsw zdi$=Vhq+6{BTs$DsZdI=ET8DLnfdyh(ZC9oUG1QxAkXCnC#ai}N`Kxb|EXnfWs0@i zvbN&yE`tYqeVC=0vai$}I4>ENd+yn}k>i|y%#0nY^XT?CoN3T_Iqqh1=7;OR z^ScPt682xu$atIBvX2>u0NT$|wI*TrlsY%DTC#wVbej_{7zch9l0e2oVL`cKx{Fg`lrwM2dYydf|4Q+IBJn!kF_IvIaihN z6`P#$xKER!lpPAPf&Q`~dsDl1(mA~kb1HalZTv2)P{s8IJHsCf(D?zO%qk!|X;VS23Kcs?+wVnr>EnuFoujYTqe+ zt}pq8Pr7T@C<+}+*KV*Hsgst+Wt62rb&+V=(zVymBixOekU@9d4OfZe!u=E??#FC5zs zc1w*-FARJ@A1YF<7)Z=PcI{<>0ewY$&FwU;mz`+)5?;{_kKkisK^;xsYGf)g6>x_bJL-?%9r_JLV+`2OrR?8F1 zzv7-i$@}R`%6|GnB6#g1YcIv&B!|%E#U~=_<$5cHev)6O?15ZvQJea8ghd^Vb|0a* zW29Y!i-f8g@X$B-)y^_mv~XJU<4Wwy3vfl!;pIf*&8DW=D3C26%YRK+RIM`??Kn{< ztY1gXkH?2ONF@jEBCKLcP#dq`{Bn_85M zrdh*m#w;_eKCo!h^YBlTU$KZ$`!gg$m3&f>mW3U zK8vdSsNwd{(SOQ--#TY&RdbYq*!nn$>hS0Q@gNm{ zoP4WqaK2JgL~QKIr-Ck#jT1qd_OvFp=ofK7l91uS2MSO?Q}8bX>bSw6dT6$v?Q#bf z;bjE->tQ*12|iNX@-VTVH|^)*YUn_yN0?t__l|eX{_-k7Xwz5+;55spT4tX{sbLI7 zhi!GNw(qA13SI|Y_H-su=VSQw?D+XwdCV$>65jKX#+0hZ?1u@zsuVl?sQE^dI;qqu zw6L_NiEc)Caqq^>Mwk*wY)Ug77CVt2mqu;tH3*PjJa^w?PV~9jpsrPR$lf@F8Dxvj zGxy!w@gaBWD_3WYQO@5*fZcvJt`Gv;F?HTT{7XMpN3y(^;_p+#y)VmDz1dNJMZLm# z>-_*MU)nKCFsH4 zI&1oME!e4E{ak2f&nS!rxpXdqxYcjQA8{hfJ3rF_eCcMuSoOHxESwtTZMz>H!*d-+ z>-JI!`h z>2IPF_<@4g)KxFDA%I)Gqy9Hdy5X@;wVEFI*JW2Prcu3d$-F>QjCWopc{}#Wx(bhN zk3a5|y1})JevyCF0kHiB`@g||J=25#KO&3&2N-yv70R0HeLg*5=lfWj{u5Ws4Q+*dyBf2w7+Q=(HTnGW+}n2(AW=} zJZzjsGGp&Rg5uDId%norTsa2^&fA1phwX1V)gkKXRVyLylI!f)1p>f$9%qnIJ=o=Y z;k(YXvn=dg1x2MO7a6a2H%2n(D~Y+YNJnG?$jz%nx_7Ga$Q2CiQ5C)_WN*D?I0z75 z?c~;Rp8IIKqSm_ugUdc2I)wC3d(@4gZKn#%#gAU(Sxy-h8I`Se?LPOXL663V(YL>P z{(_{cnvycezfkH&=B}m=%y=`<)_MD4+G3)0$2tFOHT7_dTNOr&mgf9!uYdSQZ)wZe z4{bpduaql{)G!cAZ)_>8(*eVSaK&R3u^D9&&7I;c!2SKtpoV~~MZ5w5`LiLg8VD60 z&6h;LOSL@bKVJv%*MAg<3opK;LLIe!XPMtZ>Z`Xe+}JX0%&2L!b8mRpCjNEP7Pc6D zy;*65kC+d1@3_KdNn5KUb)?Mf$v6BWJcDZu6E-oEtjLK!!`VJ}{n6Xx==|{9i1iC$ zyJ$?S!_}mP*Erk*0_G)jy+xuG)y+?^KYk$Th21@Ux7?-KeZ?4~MVuWDF9(H%iO-40 z`sc5rVA>jSGmiR6;cbTk%GcKIodQ%s0?I4TzFi3A`)}wBO@a|IR z8KoqQqF_+N(}uO37^SL=O&GC%4BZ7^Niv=dXKJi%H}~?-dKN5EIcOD_6$1K;i;a21 zP$1GS1smGwTDUl;DZ0AJ_Ut(n15Z)UBwN!(k>4Jlp9fJOx?)4!Tc4y9Ne&0(56eiP zj}fb1G|TP_%O{GYNo!bsZ5Km<#@{-9>dWdRhy+@g+rbROJKMiDJ=g6jGxIm<*mWK0 z`SM(Zw-&C`eHr{8L}qm&3hmd$H)Q2AL3C^A?Jn^I8bdHg&1y}wz82T@Rtu(iH1wuI zo?tx>gG#HA0c|25{`lj>fWOnZXXJ)d>hhIhbOIng$Zg@$DpU5}J%*Cc9UvlXmy?&1 zMMNLfx~Bt!v_xT9N8fWCp+J3f)2)E)0@9vRapxR-c;KFhWa`W0_y@M-BT6KS1%{y! z_kg0Xw0V))p24u}>n|B*zoThd@1|U3;Oa=)tHg-QlPu1LgN) zc`jm}!a^(=R#V_IBp${j3iq`a6VuV&nMplZ5ioo6q}x+=m}7o+KPYtVtQkZCAO_bJxAQ1A{KIC0y&QM%Qln@aRjn#Wjij43XXz6<4s$YsGR^&ByV@%r=UrUObhf(|gb`2ZNG&??_P?g$>qkel!k?{2?C zR2wQ9j}}GAZ6CQ@Ww&LMv1^1nj?R;n`aCqVlE2cj_QN@Kb$`97R8T>M!R8ot5N4nI z^?fW0qF1oimZE2n9yNl*ev?5|x7CLsw4zhh1g~5=VJJeW^f_1;kuCks_51p)Zr29? z?&Rs8`d+TvAEl(*OrqD9_?=+3vp!)r-ecil#v@l_D=RU5nl33$mv^0UXjO_f66eoZmw3Ub0M{}Wx!!U0rmlh zlvF}Zbkl=EvlAwYL5}IQnXr{ea4qhk_FR~Yi6if9F%{ou=Q$#xDFgRbb*aYPh35t5 zJgW8Be|Uu((E8T)Qo;bU!}f2X{GXV-B+Xgq#i>}Jz186VpqYPJ>HEJN%}8+oov8Bk z#(g-0A4tWzA>!jTh1FJ|r(*9mRNXrF;ghPSx*WesK2O~o)(2ss>?YLvt2ei-{^30H z`tcG4fHhM43d)o7T{)7lx0hE>Q`45rtS=w}N;q@pEZe_~4lXl(pmw6g+`DbfDrBKlnG!{|PohfmV(>)FeHb#K z>eM{5(Y;9l`9o9l3EzJS71rGODtS6-0Lor}Or2Ez)WY&U_S)|EChmP3 zYb@SUAQ2zCG#)?&m`B8}&yV`dKvFt}&i)tTBA8M}m-ksm#s^xskDkDd71dL2_uyFj z92&?jfB-kasD~*pj;)cdVz35|zlh7v6R=!C#D0t__H)}N{SK`_*lA@a$Lt0g{+V*% z{+HaBOM4J@VnA0VW{7Nx#{RYyOlN3}H(ibG_2Qy^fwV!~EHGgnsUDW#c!+!qn^~t^ zQ@)b*)>>O)OE3VJg8lV}YTDYk*Hbz#4FH%*NU$rYLc~np^Pr}~ZdkcOW2UyIgJYZq zfcU7+4l`0JDqU@AbGp5k!L3P=Te=n|sKjxXgD$6y+z<*B5}ImW1^(|4Y5bocQr!Ld zFCP`v-+H8am8fjdvX7FfngB;UU~mc|3ajmZPfDoa_$qx8+=>i#Rw2P2xEpVa-y3&T zAw8OT234^FO40aU+uo9p$Vs8bWksNcRg(KIyP}n*{8Q6`N<7Y*LA@D+Iu9A3+TkV~ ztb21=Q6(U$5~5ZOmEE^IfULUlz4s(vE=Hys+NBqQ#AUV=G8rBmRk!xJz zh8f9#(qU&*;q2-pjVREiE}iThN1wE+_WKe*E!_kzQol9%5i+@&i1dmef|19l;comD)ph5EVxx3sM*62B-8l)8&g!ArX2(w-XwDX?8yGtx@xl*`dIe3Ue-^V^|(rn1|bw?R6ZbKnsZ)#YiT2@o_NH)}RBf`ykP`yfA z`^53ePnkcwG@RbzdC=4!jTFC|aEi{4Zo~~#6?NOshh!+j4BtiUQHQEHzN*R*17<5R z64E4U*3j^wWLP{+K z=jQjf!FCzcwP#;keI|s4P);a1`CEHxxnTUJ_oZb0{_)j6lQLug@`4^MmQCK|ExC_P zg1Ehn>38)ZK>8=yO^+(5`TKlIUMCYr|%_$U2vZ0!LfWXYoyoAon zAZhZtM8td@-snmN`MP1CbWO!cjWgi|hzKO?y~yPfpq>${{yvBpK&V6{MV}xIcW`GI ztPMqTqFjj%tFsu1)@rK-4bCfDCInQO%q)}s-l|!X?H?tA0_gox0`YUzBGKECBN-)M z;t~wE_S34c+FpP4l>+(oz&Sslw!o1!24ZCTvIJKE4Za&84oB@k4pyTe%>egwE!*Am z=)5>F$-^hMD0RFI8Xg}RNWefrNE>)S?rA5HmIB>NPM!GT_dAH{sFPbaQe zClIpAS9=3L0M3_25(XaQkj}OWB;TkA)L#PZo~saVNtYY=>RPRqzg3AQP<7wbtNOiB zNYgA_Yrlp0Y04`xQXwBWVsyV3`lz_1FgT+AF_g;))ZAran#Ii20)n5s}`9~f@H3`O=V6yj+&C;ylnToyj zhP_ikA6!+^ser8OoL_K5o(#3_wZhNZ)y*Me4RHOmVXZ8nb740)+QW|j4jR?oy+sa) zwrz|0buGJa6 zh)GZspm^dlD`tkvepN8XVBFtV?4>O%%atBm6!W`RQ^AHKWdI zEG$2$PO7s@D(dUAIx<^%tQ+xU?+i(v)She7R|}kJ!xzBUHi=n zO_y^Bm*Ifs7C&{2r#>>3I>+M&NkPM83r;SSPMCFS%Ft9uBu5tkNZ@dB3pL9=RFb4t z#Ve@x{pL)cfPu~HA7o3X0wqQqvv(~DlM7k&9T1=_g+M?0G#Vp4=M65!?(W$k?KL@> zT6bEO+#f@6g`L~$>aCTK*3L0=x9Xt?r}i9K{|cyKM8};q#A+LgRt{Cz4W-*D5rDTl z9K0mWQutPfnu807kuKddQVL8OKL_KL{;9e5zGd7Th=V87k(0ekb!jWV`_ke43QZ6{ zhWqpov`JwjPxS`TAZ-3h&>$b7lgGvP+goWbBH!TjBjb{~wK(WNyzEMwse6-DMZ{0M ze^-IlY)RKR``~mO#BxI;Q?b>ya+3Kh`^vyCgx8SFYGH=JB2@{yd#o-$)7?wBwim;A zPPUmx$F3VnRyVKTT`iW6*o~MT=v&hxGVySYYDHS%@GcEoqs5Tx{P{y+`q6?yml`&Z zcY0678TaNz8=LFenCD}p|_{2Eon=wM*& z&66zKl9|^ux91@z(RnWn*WI&;lZx%jefKr3A&wE50R5&TL2}q_zU$2>q+|}1Ww~c7XWLUr<`*3@62P5IjWQkYm?L;)dnl{8E+TJ65d8Y-j?r~+^O?Ygk=7WYvr&2BWp;G?YlM)^U#WYB66#~4cJ2vQg0-Qv@RkiR{%6=P~3f$__`5# zuEo@Kaqoe9sb%H<>8TC7~S+J6=)Qn{`Pk7SkU@+lj+B#{EV7D zla=o)F9doqZ-FYi;iT5(x@ipOk1eLPUh!m3yNu!Q>#am+y)235tjMP@Y@qCEK7QyW zHRA2*SLZ@}Fb<4|(1^OJU1&3HWO6tv{z|PDn++WJ=`$COcPEEJIBsYxt>0=W!#sheAC6~gTfQh0Y4m}r+^etD zShU=7;ieOpLpOZQ{tO8MgLQX^<2hoa+ETNt<vG}P6 zXOacYe`GC8ll*{pSG?hB>G#2qI}JURK{nm-PJTXgJI#2a(PAAqIX?IQ>gMdjncn|D ze!4pyryE6C9kHZHn9?aB+sPp^l7!rCrH#r)#N>8$(v6#p=5Aq2aKYXs>JR!NoYsoz!#m(IOl#;HTg(z)+q_8IM8sx#%jW@)5`=nEJ0MJK&Glkvv) z*J2%)vn$Y?yeArC{jXaH;NCMFOJly7Vr!;J{vHlCx{Ygkn2e9)07xcI&~~*LoT(!) z;D+e(o2r7{K+1^w7>Y|!FgSx=7yu>EP^KfECmud19G{^`Ec{^)@s#0$Fof3lVs{~X z=OyPDANd0xib4JSTZgj&G>9WFK&9BtOPhcEh!K}(&GDxST|-fINUsvU`%>lLdQaMx z^?e9^P#|#&H@qk4jpAzm(S#$!T&i$0SDFPBG;S9}A$v+?FT>NSZ22{p+feLi)zIU6 zd>BdBMLUXRM_3wl?_cPx0|IU*!g0b?+B8YoAgJXD33jOL^t3%yuTF*a|~2UfjTi^<+Wh)h0_66cBb6pOnov2HrfB(uvk784oZ+Y-LfN-zmb z(LTBYT;Phlm1Aeqe=_(gZNBe_&?IgoaE);O@jT~|1O`(P1GWL%^N%aQI)?+Gg$ex*RzRg2pBVF%pa%p{%txtli-YugiQjhI@U0;oTJ4>!>R%w&4ZH7RQbqjZ z+x_Z=mcK=#G_WLP>PUB&Of6j1mu0udQ|R=mS>~TW;Yh&6LCI&7kKx4bH0je*Q)4smA}?M4P@fL()%G9Grjk z=SnU|{+r8p1_|MEt(B~fsr@&(bMJGdP0)nT>y=kBI_%#&!Zu(%b7Ql127n=d=(m3( z|4AP7sZ+Dul6$VD1X-iYLZqe?9dz5*&90pvn!!nO`;<#4XURC$`I%J z$Sa5eM9;Ck7?FDAeWn=TK(7=Vruj>Ts<93|hLGxB-BwClW=IG8SfdTHFVQ6i=>8_& z^MWgvXpg>Xm7SHEE>Nz(-5|_}{a$_8WXYr2sG9l3!RZEF2YCI(49}&1Laiw+{l{@> zE-YkJB#R+$ZU!3r{&@LP9hM>z#L4xsS&jYY0oj*M-@?TudhM9Xq$EQ!%VIT>)f=)W zAFup0xAwwdhjM0ModTs zomck7&v(tv3FCK!Js#!wpf*hPmT|jqoi`T;r2Mpwvl68+z1BLMn?MkHeZciYU_Gb1 z3rNAX;^xe=8e1$M7F*U5LB6vEr)%wII^Y#{Rsz9n2kIObl$fA^1W5nxU(x*47J9xj zyIBBlT(r|>)+k=sqv@zM?UaedF4xjN2$mw4yWn}ghtljhtwC^kffe8@U^^!y2zuWWg)s}TplX#@+zFNSqDYJ4;04K`jsKE; zHbM)nu7vn+z;OxdP$?UWzcTrE?#BWRZStLWRJH5M_6hpwh8=(>Ys{`JLar{#I}m7L z$oHP6FceRiYkWS^Xhu3Aavi5bE2p<36C#LuTYd=iioNmYC+PN{#a{2=bj2`H7iUGh zdMrOB2m|yM#!VYROx9`E3pvjsoJi;>7VEurxw$Z@(#F;?k9hR;*-vd%67*p72im<` zyd8?2pLDetNbp(ND@Pw71&&R_YL;dKjeim*HBn64ooxd#YBk0H{t3T0Me=gNY?W}c zw2>-tl?;ncL%DUk0fl|2j)&4UHbsI{t99itg%fAo3l9T!FZ4;NA+~6&{0m?d2lcA4 zhk@QOqKRh#q7$3*16eHgpb%1|UenZH74|SRfmt;@Iox=i6u3noo->J;1Qv6=g)z>k z`xzqq7>GASE+l{CHzkV-$0*OZsRqABlcNZ2D)7>UQT_F|vhnJ$hPb@1lgY@5E#_T$ zS~mT0$C0Qs3E8Lwl7YNPt%|CsBF;?@ev`Xp&4o3?={9F9@iaA~s5wMDk6Gn{J13vL z#%cfXO+!e)3*l31CLzzp#Gw&1UlZom%Ef7TDN%f^3Zfd_stsvgj5>BG)Wtpgm2s0> zAr66XJ8G5<3GMaK}d;_f=}uQ9ee8H^v;DHQS&E7>+s@Iz=<1es(8iZu>U5 zv>S-Ke1g+xsyb$W)jP#dg^Xthhz=#k-{e|h0Gjn2)Udf*AD9uG;K(yFZAV2@*(0BV z$MzNbwMAt4z22}&Fu|pOl+3+fy-9Rk$hYUbjqvs4VMgarIk1rgoH=DB$joXF7KQhj z)*Op=IDWxmnL!Ip4=p9`rZvO$PxnMtpg4onys4LlfKB6^>pKCmurbeC-SK`_222Ig zBV`<$p6`##XN?c@$Mw4pT-s}PkUdmz03h|&o~x^0kwCHfKnYYbH$6TJTFF1fk#q%N zfFK+llK`ub8xXy_~VN+-CMYA!Ilx4 zit7VyXC9RWAYG;5AL}Wt-JLV^2R^`Cc<7^KoS$HOqya{-vA(Z*t?;xBLhZ@AqmHl- zIV}W~Z{>ECky_L+3txC+?c46JU}Ac(?#Oy!z{B^`U0p(P{F%s(!vm}wnXY#;^BeV}4YO<}hqDfrAUD~NbDv{x3F|Od+Mx0BbPLW_F508edYO?l({?gjI+nU^hGPFdEql1s{ILnHJPzZfBI+^1#iK{Y|l=rm2Lo=V@?#W5uh^l-nB6!y${As%oYRixwYBkFneh+WBA^xSsPzeg`?Gbkf zwqa^ux$byMEKbhzt!WlN)iiYq0()^RiBh@YXV6-(e4nMqOqQIc3E^dmlV!M$*eZ~a zd|WLM7B#0BsGtYur#ox6_4qa7A$m>~G-2J@o^ppa6%)(cOp&g@&fd1LIe5f^@p z-a?R3@GiRVrNCT#F}7aUm7(f5;ljJvzaN%9x)$rHc{{5lS$?fv%-*%-DiqYc&AHrr zh8C6S#|mr18qCTK_5!|WGNk)+#I1t(8v^Z}vv{t8mcJnu>|MN<3vAP-j@vV`AT8NVIkO9FEk%igOj_|l{yRF?$b zvospNfz8Pd++?cXxA=`YNSe{sKsMY#D{`0arq(KBpRt%K%STn5QCB<_x1KKWx6h8r zW^Vh)Jw~5=ekc9NAJSR*H|&!f{WfLz3C-QIsh18-^SvH54W7t#SUsNG2yo_?Z`MAv zP1w~#zn>3GrjL^4hr5&Dm1T~hlQNtS@vBHcJN|MTemllI2lQe66XwUgyp>0dla5~5 z$;o#|hPWgr+`wbY^37FepR``lB~RJ`3rDda^fVnJg*8AoG{<&Fe|eL-K>SIM46b@d zdtcaFhbvCyp*@MeQ1Tkg{_!FdQ-$NmJ_HQauP{{Xe-pc{@gL~sBqy~g%9RR9Zq-3m zOWQz@3>@c=KI~|JzdX?`S2_IV#h2Iq4Ra_)`%Ka$4%4n}Y1ZiK*CGKM)KwU7{7*>c z{~Iz2)4oqLz&XS>_|c>vnu$Lq{x6MD-R_2E5hREi|~E=ww8PeO=Evd7qlEQ3-cAz8*wcG>rJX4HtRV;{S+ zGnSYc495IUx~}`ay6*e=KG*a8{qxMrK4Z?~{G7+|aByz&}uW_q$ia&*Z8v033LeqG*q%U(~FRui4d>&h> z$g^^lY;?9}47O%$X1?|CNN_7CKvpS|S>!XlZ0coE8&RD4*+`pA)a=wH< zdFK#XV?zOEXh?K5gc952gv4~PK8jc(BCD?UQ*BCNVI9&`2h(eM7>Esc%s;H<^xZOl zdEw~6M~>KQ7WZGz$TBm#gKl1t_T8;EI~3}VXObL6PHYoxWqr5V&!$#8C{;UA1m1QF zFM<5kLFgfNX+Lu@J-QuL$`7mBAD{iQUxy>^NI}MxJmm29+p`+9^Pl02&+$Q*m^X@F znA3s|Q`1?ye&2oFp((PIk0C&^gcNInkodNALLYK-;kAeMbNuVef4&yIvx+K$-{b~f zPhYjV{~vzapK;>Va{(;o14hD2=4f)&RTXqGHRu}EpKmL+luzq{#Az|=9z4G}SYqMT z!AN%llzO_sNs_h`JlK8*tq^$_%_+Hm4v()Mx4OWUh${ZE@!Fix@Ynw^`fUZ6;Ug^u zgL13#LTX=m1!;Ln(J$%6fk2PdV~x=@;WV|%yEx7__dj(^cY=BSd?%PMhgIo~*iC?- zRnAM#+KUyH!QWlor}UB?=H~k);Hq;37h{rD`QEI&_{eqdbxB?YhN>0$^3tr4a(70A z-OTFA3S#1*UA8&bO8?xDu1A}o0b%IUJ99;k6&=|tS})8uIc#{D-ABbi!o64HVKyw+ z?j{^Nt`#MD0n2}P0gqivL2+2<-Drx+<;bpvv576gdza!dZgygdR|5O22k|{^IdP>% zcB)A;;u2y@kqE1{SxhTdlgn0>vj4~LdnPu6m}Gg?Y@W{Ngv-P`OjZ;&%iiq!NltVp z4{JqBzX{#j6Si#5Gg#1CEQ0D{3??cUKkbt8zRW?I2m8WAEEk*jdXdi-$9?@oht*S- zKXqHrVds00Qp*mC)e*I`6FHSa-uf9;%4^OUn~~9GDjiWB_irp-=XD&}XhyY|m09Ag zXY8}W%hUZT(mS8T?d{ZgsP?b7=w&19#*0zTQvH3V(l`~?51y3+Rcj#OG^AMw*4}yTEK@Kk_9w1QvnE=f!=ONiW(emb^-1A(=G(;3c9KX$ibPYP#gZ$A%BDpc?vwi%qd?JQwHx}q+1xJAdFOYcYu8RQK5|CxGQ%5{HA>$hFxZ_Tr*96(T4Jri0$!>h zMNu(@g4bwScV=1L`oV5pn{R}Xk+dgk8FSEoTfiq9@)S;Za~8<9wv-Dc)KW*(@D~l< z6%3`D+a{G5Jy?iXtADz|x}7^Hi08alwrZj*&thvplEz$#&<*Xy?d;fsN3+xvAf#%| zQpRy`Uly*zr5gz)J*OCrbZjS-i;H#>>ydIRUXM^vh9rlXaCrg8k;-ONpM-r+X`w#Y zmwVG|bH)|_paRo0(#lmQ(Cf!YUNPP7O<|Q>T5phFSoBX1h`LWZ8`EI~$zkwdJFIlk zUY)+~Sh<2{%q*naW=YwWsZ?j0~vHXZm_+4pTuM$DN(Y}i8QPvZYPcx}eT%Al#8v%S?XlK3H`0*ew>EjqNaM7ts>Ezkc=L0XS zxrP-Ve-#soYvPl#X)Z&t$97EQihJABTj!WscXmZnqE}|s z;KA058g$jlI7>yaQk)fCo$W*x-A;*=&BBt6XPJ1fOP#$e@4Tmkn4@McuRz{TeSK}UH?n5iKj9hzCZ7B@0i?zXwryv$i_0~{$&WU9>gSODkdlX zyu137Snp;Qw!&_Jiipg%K}5)oI-ETGI^R|Ir1#vtr_y3m`X?m%(y8Xph16*lk3FRl06$-CXoxLok;-4t1+iC|ctzgS_BF*H|X;QGC)Dic>Jk&BlyO;MBr z56pSsTkw+uNrGtT*B$;=N+2?#8@I?Fx4c&Al7h*{y9{``;Yl$LaT^Yu#j3;XRWMkk zp`%WM=6N=Gj_Y!Zr+HpSP9k-GZjLLSDkvUy~;IZ2;aC}jIO zHQ4QXiO*cmU6zf?X2l5!gAL=*C^obYwouapzt!gEn?fvT{=`+6z4WtvNnpNNSjX)VF#bMj#*U)ah@ug{oPdRCkCJd3%oWaBlU3YfTHK z^`>!VC0YqK1`fpd(`$N=-gp8jAqJBYEu@aw*;QX3T`QS=$CXwn=v-zV&X;TvIpg?d zm{%V)e!hinu?A|DtQsd|KNKUrgd(9EFP~*=9=SBdT!d1pf@K6DabtopTveElt*aUq zd{cHk+#M6F*&(~|{D)KQv?1ZjaMCwcFF|Pjk>)cCb$Dp}aJI=fpA@QD4|w~9?dB=M zsB8fy-Z_88YrxZ092O{lUpu9$Xf2<4HczTg0he#hUiZKj?JHXg(%xM=dsyjS^V<}h z_s;i=x9Z;#@_getj_mRJjEKI%GgWHtl;)235zg-OjBY=4)B@_d*~W}HR4Y;8Hdmtb zF{P7zC6gE2zb|_nU0b{?|5@y2nPIPevV+kV(g~9+*ihf{4w~=kP3Ms`N+4gapHcl% z8~UYr(1n~Si8A^*T)FzLwyPnQp72TvT={qq4J?Rvc;c%=XX(7FuR#WRJG<5x_m1u# zMAl=49RdA*;i8!Y55Ns9hv8adMd8UW4@HSC&7+iB|JZ@G+FFTOo8c+`7mhAIObUHD z2$}FoI9bGc24ESY%XxG=5s~-&Co7dH^m*ZsmQR2^9X>x zLWLho?9-rz;vfOSL~(ASxuUpxq5{$;z>FH?FUwpUPdz8}3|OA?+mJ!Gcjgm2qcFlS zBPxrq9rKkiJD}|L)7qXeAiK|=uIKx^?~!U`AvjL~y{nHK7})^o_Ii&^lEY$fC@19x ziIcq0_b?5nxLrDKY`sXoBTRIM_BJRW;?=Z~FzPY;gno1o^x5pVD)(@x zC^gEaDeB`nHgKv?zUO_c@VSO!>U-z%{VQ#B3(q4fi!JSrK+De2Za3=WT}V#0tkN{$ zQ9ySRcdVC1z8g|GDvI#@Bz_!@ZazL#xKKhJhh#GNH|H*i<&l3e9$}l6^3%ZnjM1&*^n= zM{@K_;*b7@Y?R%br&_|6j;`A7x(cgE{Nj760doASwtg%Xi1d(Zd2h$H!ksc4lk55P zoztYUT~fC#HL*xX{><$0%?M^QOlt@g>eA&hmo?^7RlGvk&1Z%NgqQkz@A`$-dIcuB zNv>^73125nXg4yUjttOy_-aBz%>6cotQWqV5Xv|qSba15Dc&Q6!rA?!;K;V_)8S@l zu-xSLXdn8VcO^2qqQ%OZb|xg*(#>U)*?u#70|A)F%rq_N>60VnpFcmM=X{nFuOc^a za+9fIx}{H*vT&{fXp(Tq9|Nr@q{Cp;V5>UXuOIPLM}UNl>ZB z4Mm5vP1;_Vh6y34brp7MUziuA%3+FkID^cA48JtQ88+ohrbNEA@Y0~K6USk}elR}t z9urnUov?9R9p$xB=e9gYiRScneOZYlXKTXdY9?}hY+V$bl7|HC8{1~}GFB5y7wg{ns~a`F>9!ei)}f98Rz5cQm*!{e@F z4aJ7KD^o&y&E^k*#D2q;XVIg`bC12(#A?vA%xs_-Op;1?sp1SiE-iLk6x~UA+)86=_x0^LFMCNixGc_h8(l$wr+B|} z^m{G@Tg{vzkdt`pv&efX?|QN+KWGW-g}Z*T%gaQ+F*e#tX?bE@Y}`md8VOD3%+7mwfx7P8yfP>M`AqX(q0NtuhZ3dH zz;!*^$$Yx%qr7iM5g(9WcjZupm$`z1t4P1D>}gR2``p20weYi>KX&(n9>0nuJj;^t zBT^ghF3S@N9Ht20@y+#Fuw^k+wvLbc8?#YTq2K~qq=|!?%W!;&36y&7mBQnGuFv+2 z%ss;-mO+Ci4K={O0DVs9J$Q>kpKw1gNlfYF z;e(I9xGx8~+o|DDXuyGyfQ&P`N(V%t6$hwoTF`?-bPqdT0M7uj`vh4E039mOXMd_Z z8K=E3f5!VxcxeKGH$WT)9cAH9P4e?C>>TkjYdd@V-{+)tGLSsIb)$U8TdKQrm2efY z@lC+34ea;wyw7gw!;~&RZUOR+y<4v27gXK&r>caUl)y&JtwZ-{_*47sYHDpplm+xG zeqy=?Cfux1W7^0y!MQ4IKQ0f7eCHwm6w%+ed76iAOJB+ChKtWP^>APZz6tblV{2Mu znIv3XJY`#A*Qa=2C}?lwMGo`whVqU>wgG!*@PZQaM#={G_A1xzk)$nhg1QCdS$feU z*CWf6@Ew~89qhGqB*l8O+ZQovR(?iDi3)3x7o{3>7B6a2!tnYmm{Pi(! z{2|j}<%v^9V7*4(vMM;rK=N}JTqw|5Vi8w+F|96lD>U2LjC8Kz8N1{4NV62($j|~f z?IJktEaM=kogG+P3c1F(&d;H(PcGRv+0DTtNv-)1OVDM}@z|}%XeMf3<-1lhTe9yh zqQ#dwL&1mXyousH;Pk@ei@Zr%^<-(f6XdEhYhNKRpy(v7-Wxr|iaSeXZa-c#^&DY( zl&V)cRJn9N{y9WCv&eTA(`O;PlS~N|U9hW}k6>nanHzDP;SJP+omL5@>rQR;NRniH z|A>*Uf$zB|7ug0)!xqJwbK0muPxAdGrDO9x2NdY_I)P)ve&k9|((FnXcsGO{S$H^k zI$C2R@__q9s$`8Nm8gYF2`}mQ9VKGjcCy;NE@S?Mmh|gcwbEH0iT}nX$}(6mD|o^| zo6t-h-UCS{9j7nal1303$p%d*L2fzRqe?W{3r> z!=H90(WKJGly>kTkLm0hoEFpw(6%BWLzuU5wp9u0xWJn;$E5`16BaG1r39xsYuSVW z5|Ujo(@@wf++X=$u?xAyk)Hf1$7A|S?6_{AX*>~EghED{`>p3ul6V;8^4$m(-V2!! zzjzgovD;_TO}OP*7Wm?~$l>L_`BoF*DYOOAn+zMa80-W{$)D+idLTsK;q-=e#rsd?7Jeytk zW>4eDM0okd9&T~xpSlG~@z1TfLn(_1g!V<9o`@=U9P94SmUq_mKD^!dyPBfR>Z7GH zI5~|cG`i<(v=oe*z?`6y7Dvi!TwNtLUk~K6JoxU;sTc7Fz_DPk*^=y4?HgAe0lZ}n z+j%nE;eC6KD;prbSLfE4h?;eOP?E{*%A*ULhm}PT7IZf#0eoz3x##!|<_m`8DxJ=A zc#;f;E7$$HA~?X=!LUu`TE!lz=!ld-O2OR;ATi`_s=60s{HQBTE1B541$V#4d)F^1 zHt{N^#lV&a%r5PDPb)mvaj2ds-S9~^{Y3?n*b+#S^{;3rLiPA7^{K&vn?makoiA#^ z4qZ|iJN#zLvcVsGDoRbtK?p@(n4S4g&`u-}q05O_Ky`=1O;s#}d|&g7SBv$SmW)3- zl`GVv9>0arciZ~v_c42=`Yi*62c0jaeDe3#QJg18R`ORYTti}oO*N0 z*E4xGXf39msj5es2~4n9-{R+zT;5s?c#gq)V)b%XIJ@W_fL!ei82dU3v zQfK8idgT6sG&A%!Kp^Jd71S?V`*&>2q`P7LySaYz%6I=Gth9i%s)oVD%I-1mqowHb z2{Z#J=kV{M3*h;nmsG#uDuB7{E87#4R5%Ev-*DV!E+r)oUzv;*eSL^#7ckZtP3BPm zZWofm`=z=t2Fjv-+^~fycvg?uUK0~ExMdQVS^hOgYGPq~#zoLUA?xhAfLZ6NT3%JV z_DqTY$&y3H1u=Ocm8N~75`knZ^_^vR8JO~=2|#kLSLRp6Z<~F2wNHrcRhv5U3CzqJ zZ*6i^tIYG0FKTn8aYmfaQz3H`UFK07Z?GeSkQ)_~PTHD5=2$szKx_}6(O6InT1~@N zT~CK|?OrO_U20A*AF&D7_Fj7-)Z^;WfxW`h_8?(ORC8H`Zz{E@eY+ItId!%p#&w(l*siij&_eF6BgTv@W@(rtOu2RNoC zh0}nLxIgW%I1=*2t2hw0v$0(6GNX<#Xb*>w*_X!@Zqj-brjr#-HEwW{j*odvjd~4Z zR?-bQk#T#=m6*lT3ZsD$I4_ynvc&n%au?B*7vIFpo4w{^RW6-XV>Ks&3L{$aAcN!Dx&4uwR1?4?-*r)=+B^dLF%GZtCT zd<8b{2O}9IgXRdnRD8*qF2;c#Z6+T|z~huUo>_4d_*=gwg8MsHXACAb(cp*nR!mz6PBd*B9MDkhCOYv%X8trp}sCUjO2NH z?82{;sb`mX8Ml1D$;h$o8gDR8IFy;O5h=^cCvzjuE#qu)oq{#A0qbXDisGxe> zec;~Z1W{asTsXRTUk1xTxFMfHEWDfo$6|@N!n(q8bIQ8)ULtbK8s1}yHB-Y;NMdfQ zbCkpwGO^jFMZ)kCs>*Nnc&*1CxNCC{V{P*}nrUv=>)nX3i~N|4T)F^TD_HyeXfR9Z zA|ykusEJA;MjI=(9z)v5RO@rc%2hW%C}(Jx2DTj-T)4eauHEs(@0@WKq}q02=m8fR z;mqPOFy>E%Ixg)XKdi)ca2vtR)I><7 z`$PQMq7^n)R&B_N9qFbzqe>73SH@*dVoC^oSRYDoAmn? za&?KU3W>K(?p!nBFE{>W)w>=f(Ato z{_`{MU=m4~H<9gjdz#Vb@|;A|pcZSzp2^vSr=H{4ERFpoaiUOZ)QvndoyeVF#c-jb znwv8&@2)f6w0KD6urm6n1NISWN7K)g&$f_;JZ;g@`OU~cXq2~OBd6#yfT=gaRGHq) z1$J@;nEwZ+u1WSlj=g>2B^;PU`5Z-G+xPYyKVjer=U%gp3B_%D9St@J|NPBQmOKkOgr)N$pCLa)DbAgdGKN6Jw-%QNm>=B}w0#y)G^&^sBfv%byh4C=(7PikNlwsp zZL4RLoCA$)_A#hobS-%+&TW1H6ia7tGeLsiuq@d&iM1J$zYDwaawoZJ^&1i%sD&C0 zsy)_4)@r&)w{=b_&aHPNi+(va0htAGmy2t=wI6)gdB$gdrHI-VLTi`bRNE^fN_D*v zSaR<&Il^n5Tp--9vz7$BD!i+*&Kt-UN@(WF`w#yqtFnPN6f z{X4{T&M7EO?2YmYz{smTwiDzp{k4sRbfiK=83fes^o6tdIZXvZYX0A-Nl#a2HMylL zE8_mGrvvMADcXHI958AY8pzjk{|={^i#yoIAW+iL{|QqiEUW>w*#DCHybb$- zZmW)a>d(=D%Bc^;=T!X1zqp*jO9D?^C$6|H5@d=t zAYkgMDuss`AJYBPr;gE~beV*{ex%I$_>#m7w)6M>1hqnhtm(A0s8OXwRZ$|py zWi_vY6qP%y+YpJtDjjAa%W?TLf{82j%x3~ke@=!7^#q^cB@9mwIyDC^Y_*idSWOU8 zKWI+*3^kTlS{RvFC};{$Loz_k7X4> zdI9IUR#2$@a3-`1#4OhvbK(rfxN2^!dl^(U{u$7sZ3arkRQ|TMY{K)M1GA6#)9=P& z_?+<4A<3m6My@O(s*f52*weG4%GvKYY0%qcC!bCMTCJGLac@9b3Q)aH;7AG2eG8v(v@oy)K*jFv)-^`@ z$Z*JeJ;^WD7!LML^(6`r4vdnNoT8u?@@iEk#Ry% zV|5$yMrr+tkJFN*{&%dPJ1l0aE1@(#B3GaPx)=aNG)Z)Pn`0$oq+{Cjf;tixvUMqe z=8PZG><%!@$iz)X$aOMn7F2r4WfI5de&FoIawoy`25}0fbE~`#p2u;aysAIgA z?n|7cFMmqLm-`W3sY^}zyuO-l&&d~jnbt5R*J@Ps+Pxc|iNxuY+j^ceqKpLD6w$d- z1w;qy*&Y&A>@~muus7JR5Q?Wij~riN@s#^{;R0m7Keb`zQp*ZpmoH8qB*^>czNTsl z3}+yC`F##na40SOS_|a!qyw_q92nsNB2)3ZVl|T{6HKp0>h-@Ol6T19sK>D+Sy*Qtc?90m**x1DQ#aT3u+VmH z!YBsP(CRzYKYbD+sINFC-LE)evjN`gc$aj$R%@6v8Lw$P=Gg1PQO?EEB{=LJVYYa3 zi%gU2DmdW<_nk78HNDTnC{;lz$U?$}%^MgGuU62Y&0sB6sjX6}O@QosmAGdDxJ$<* z$Dw>l($LPH`Vq;V-F}n#Dxv%g7)BtIBf{3tM}ItT`*n$dP1#`iZ8w}llnO3lCSE4S z02bCF%(3${%O2IQLQ@Vjrg}AcLnQ|gh+Ij1E91>o(Y6nwo_)}$QT7l^q&Xg_>|BSs zi320ch>JnyMU^Vs_I>?gQO1%$ATM_JOd8*bEOpc`xS=_?vZi=3#__P;0Cmw&yycXL ztsPJKP!(Hc>#l@x_;qZ1N%^9yX5hjgubAmhfuv}vfRDpRv&FNclA)nKlL?W?MSEAaEs+gq@bq%-6|mk zObOjjtRhd5jPPdl?v4&uwt7b{e9g~_Vjax{fsr=Cey(d5}O-$a7^kfIU&< z0nb`X4H7dk7P~TwM3py~1;y3ga5@|N&7yvdq?f&caX4jCtf=RczNI=xe#dKO7&}qG zH454hXl9}iL1;5edR-mE&~4Sy0rSB;9cPNb6BU*XbP!{2EfhE3_3^fB1v{fag4PsQ zV#!mwx_yM)VpU_!u2+hOrz;ux&Nw*W1)8Bd^hp=za8d zOXuwrHIGtmzl!esNw?F`09qcaGc17rc##S39^A1$jUbL6vm7X@oiXQ60#d~Ovg8Y% z4&eIqTH$y;%;TP{$z%+ z?%ckPgs~EkQ?BgYFKfvTP1AmX_h+sr658=L8)pRCB%$jb$3;_#%L~04Nw;)IVu@)! znsIWrf!h3 z#w!0(%!0zdA{I*tf zzM)_ANz_E9o(I>pgA}N0^IzmgD)PMN)(#4cT{IjTZyK;MyP#1^G76ow$qRw z*-G0>Gc=QBeH`A}H@qUSI^GbGw#vQB(=L$vaFi4 z$J5^0mrdQ-8~#*^e~wW!6rYGEactaxkgjq_%jsV2#Bu_u&@5gVC!xp2V9xk(8P)Q| zpX=X!Fq6h*DZl*kVQQcW5gRC}!I^msZ~S+)!T~x-_d5^*<0*;9{_q`BJI`7H3MtzE zf2)uv^vD0dDI}IIpf#6lcF6Mc@24`0)R^yEa5Y<=Kt{PMNTyVd$_F*MXx*T+gW-4s zwXE(GN-yzPCOBNts1;>e;(9kF$Q|j!bA}lCR$y1=s{xh?B${ekzI+MMcQL1Gvv&E) z#LH`b7V`U>jS zHtcJSoIp$0{+Eo%wd5vDocy*5lvQT*czc4j)aaVItnYe$=8%+p&gEWdu;lP}dewkj z32)PZtr}8mOv3e!zL7$URtwpU7EP?Lwcx+87I#r{Js4sz5&Kiq)1Wp(lapuIy0zHV zi1JR3W*5Y~lDYDN3bF*WC`%`Yh{+cb3Oza!)-fDpDbVr#a?@1I$iUE(rIj%MErMG% zQw|6Bdli->ZU0NYl;$$d??R#EwR6^~h5=0R3z@C^lP;h!JToEEy{nut>L}k65CWqWJ}M; zq%16@Uxop4LsU6s>@gOu5WY5-gJrv@kWHyKWMk#xnKN6|3_g~8W9>*wG@9BtiaQm z5L=q@DA7#ng|-YdsF~lghp5m_RdP|>Dh96C*^t|t_7pMvCQB<{uL@efE_b)gK~^;q z%2oy*oqAITl( zF8#4#w3kHPN-D%;KCgXZ3U*JMG zk@soMw|$_Qn?_P0o$iwDk-mwqI@Hsf`G2@6c+3j*-W|JyaPw}Q;h6|yX^WfFE%Mk@ zX=?A|`q9F5NHnzrW?py@`HUWz0)-z?@Wr1{fkGkXjRrNaJsq8Q#cObI9N*K;iAz?% zJRTdH{XENtL`dC2*Ou*YYidM;h#1iBcHOLeF-wHP`SnuJ%zzW8QPc zpg(aD8kQM+3cy84N&{{>{F_5~ySv-E5zeU1XfC4r02hP&>1@i9<1&E?=Uf>2!CtE} zK+Qt5XC~CZYDnA%)|SvAoz-YLWBGzg@$4w`X==0?G_zwp9`0FIqdDe!$OQ)Pwx8b`#t+4|C@RC(#ki8+-ahqPRpQk_AUO! z`&bpUV@Ks7o+YY0vXss5a;=&?8y(6S=>8+ z&7uHvr`E@Tj-|hP1Jwy}24MctX=mHY>Z9;0U|P{~m?@A0bnn>TjY!BTox;6)S;@%N zBHHC`V`*8X&t6dDIASD!0>=7 zO*zn?_3R;bt5P$A}@{I6EMO2-A4A>fqmfKQj!vU&?S zSzRjADF$z7fU6_CbY<{4Hq&jgPeudpIC2+n2>CdHEdH<|UlrwkCyTtM?^)#U@vg+K zKG!SK@&wT5?0t0rdhi}XYA6%}`NYL1R*>!zXQ>t^_i2?!2z$ECM{l_$95DN*AL;Bg zzO~-<|6N}e9O@tf>Hf|fGOLx%wz4J6q3Ai#vy{O3;Dc?V5F3_RCsVg`1p9!K78J@& zJ^TfGK1&=?O}@%7x{q+0&iq$os(ajWOMlKy?Ux^b}# ztm<~|Y()==gsw}K0^wM&@V{VKEisqbYl5;^{dtLFs%zNXd=uF z%h)&`v?+breUGrmUiSG7W>HZA^frRZVR^5DPfN%X7A^8`LAatbn)F;g&&0f;==6|7 z=N1yWkG_F9+51gVBOJg;(n|gTK>eU;7tPb2QlXKO>~l;Hfl7Wh;x4-t)4vk~jx!nY zX{)yjyFEFrc5&t*EEZ9n$n=|NUzD z!`@XyZ7P@y_=)G)++@-j&}I&-xPL6~xLLc%Z%5+$W9SzpYfXX@`LM-C+KVEVy-Ye| zcd~JsTtSVw{H}hpc;&X9JJP=*f_ZP>2O?64sW6KQ=Zoa+aDpT@|C(bweZ-+~GN(Q_ z0LT(yH0Sxy{p3hAw^mVAwI!|3xDn=clRjX`RRi+~3+vO%gWeBWHtb^@%6nwMlJ3;& zsqwK6*aqISjH6ag2GnKxj1wJk^^P*6!MB4kp6nm;cU}DI`SyH5%lr@^Tk2>aT^q+fdq5RwiTYC7AJhg>9_LX1SAhB3&a zr}f%L#JIdq5lv`P+nuXD2`;mH1TPQBQ|4FQKc{I^uOC2#BM{aSx5%QEvB&r?sBlU= zNoEO@2lZehU%$&_1)%K&>hzh@2P^c?&_b)p-;w1ZKIiUbv74@F9^1+6mrrXY>;rep;JwNedQlg=;am92Pz61hZ_1`{5Bv+5A=F2{B0tG&vH=a%%62XiLd?O20_~E zUD80W2fd6-h4eOS8q zL>4xiXjsRYqN6h=78F*G|I|qjvY{1CO{yZ+^XVV`4eb6OIz=^ENq*Kw$c0Y`A+?eS z2rsl{#L6igaZYhLwggPXM{F(JeGk}tK=l{TymklSIf!ta8Cjl&~YU;cd}q3h!(Sb};*P6r|uPeWvv7e8LKzOfB?ZBzWuWY8yAbLuCWq)$?TRP$B?qHkzBwK z-M85C?+L|@k@KD}H~`usaWF#nv9I*hHbmJbjdEVZg3enEB0KgUO`~cW=rwx#abzpI z>WwhiHATgvR4iScIC}{j;Ep-qpgZ5cUvL;M4-R9ONz-dB^ChXy4+fXTyfcUIgOT-3 zkJaM715}_cv_CZMC6|*>WZM3{lPTn1xX>qb)tW0(A?#@0JG{QntYnpTKvMFaTv(iW zV-3O2_as0B3&v3H>iU{WTxtXVQZO(Cex?&=1eXUYa_WeeKk7w6m3@71uQZP+5-&4vr_I zf@Ag}V^NX8^7My<(CU@xd-tJp4rg}MuSTr+xJxc9=$)FQ{c#{&KJ)2|tU%jvE?Fag zL6AfvwqroNC##^F{*L6Q@2#gVht?|`_-&H&E-D;>hmI#DWgwXM}}Xiukz=)g^jeQoawL~XL3zuH#cKGeAx@JePkJ^~$$h5BjU<6_;7DHn))tuJ@ zoDPJ`MARqdO|MR4q1NW8mPo5=sm?#g466z{q~3N)g~XhCvyZ(1xX>IhkADg-w-3N2 zyd;#5v%2GZqU1N97qRt5Os9lG95TaicWI-ONuJO3eD+E)7KvQ10_bc`xC_PJKR1Q5 zcp_gTS=MvKa$VYqv%e&5>ivYT^1(#m1)S`pnp9l!E9^_Yd{UxfJ zo11y%(F(=WF0Ari@yX+!{sYf^Un^8hpRyb@eCDH@$>xlFHX0a(t4}0`A73$z8~djD z#MrZrCBOediZ03$)XE;zK6M(d7AB(aF)mpH#<qem5f@J-HAEf+=?ad$k$FwU z484yu;9biYAk4lW(igYS(RpY7Pz%jKM8-)Yk)=;;|Bxrg0<88aRBLf~Xs85%ZYTch zn48V6xWfqS9t$y#36gpRmy%6R=Y6n`emoX8tLU;kqtFgckvzV#+F88xTx>qkS?&2l z;QH0^aT~u{O_v|l%`@_0gc6g7mWe)bBTth6#gP)!J+jDk`BKtBkbvfp$ZS=4ZyEfaYLVoz|*+%fJ2b=_b&SJU1W?mJnjZ)Y>BldcJ_D2Uj^K&*>t_Rh z-Iw*{0G58AaX7do{qK16pFZDzoe%_W+ZX=3Jo!&a^j|{$ZxH(5h8q8W6WsqLzW=Y+ fQ*RV`hr(r?@qFxU(LEs$@K96MzEgPX@yq`M=GlT< literal 0 HcmV?d00001 From 66c9d5819d87529cf739673cb033e7f9027d3a11 Mon Sep 17 00:00:00 2001 From: dsr0018 <36934513+dsr0018@users.noreply.github.com> Date: Wed, 19 Feb 2020 18:04:57 +0100 Subject: [PATCH 12/12] Update README.md --- README.md | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 8e43b70b..6f50c24b 100644 --- a/README.md +++ b/README.md @@ -7,9 +7,6 @@ Grado en Ingeniería informática - Universidad de burgos Daniel Setó Rey ------------ -[TOCM] - -[TOC] ### Enunciado de la práctica En la práctica se va simular un pequeño desarrollo de un producto software para realizar mediciones sobre él. @@ -45,7 +42,7 @@ En nuestro entorno de desarrollo, basado en Eclipse, clonamos el repositorio git Con el objetivo de lograr una cobertura del 100% de `ubu.gii.dass.main.c01.ReusablePool.java` se diseñan varios casos de prueba basados en el *stub* proporcionado con la práctica. Algunos test se dividen en varios casos de prueba independientes. Los test se ejecutan con jUnit 4. En la siguiente tabla resumimos los casos de prueba diseñados y su implementación: -|Método|Caso|Descripción|Test|Resultado esperado| +|Método|Caso|Descripción|Test|Result. esperado| |---------|-----|-------------|----|-----------------------| |getInstance()|testGetInstance|Comprueba el funcionamiento correcto del patrón Singleton|Petición consecutiva de dos instancias de ReusablePool|Se obtienen dos referencias no nulas al mismo objeto (instancia Singleton)| |acquireReusable()|testAcquireReusable01|Test de adquisición de dos objetos reusables diferentes|Se solicitan consecutivamente dos objetos Reusable al pool ReusablePool|Se obtienen dos instancias no nulas diferentes de Reusable| @@ -54,15 +51,21 @@ En la siguiente tabla resumimos los casos de prueba diseñados y su implementaci |releaseReusable()|testReleaseReusable02|Comprueba que no se permite liberar un objeto ya liberado.|Se solicitan consecutivamente dos veces la liberación de un objeto Reusable.|Se lanza la excepción DuplicatedInstanceException| #### Cuestiones planteadas **¿Se ha realizado trabajo en equipo?** + No, dado que la práctica se ha realizado de modo individual. No obstante, se debe indicar que el setup empleado y el proceso de trabajo sería muy similar, dado que en el contexto de esta práctica no son de esperar problemas de integración continua derivados de la colaboración de varios participantes. **¿Tiene calidad el conjunto de pruebas disponibles?** + Se considera que el conjunto de pruebas diseñado tiene un nivel elevado de calidad, debido a los siguientes motivos: 1. El código a probar consiste en una aplicación sencilla del patrón Singleton, cuyos requisitos funcionales son simples y ha permitido diseñar casos de prueba basados directamente en la utilización típica (trivial) de los métodos de la clase. En un proyecto más complejo de software puede ser mucho más complicado conseguir una buena cobertura funcional. 2. Mediante las herramientas automáticas podemos comprobar que mediante el conjunto de test empleado se consigue una cobertura del 100% de las clases que implementan Pool Object. Según codecov: https://codecov.io/gh/dsr0018/poolobject/tree/master/src/main/ubu/gii/dass/c01 +![Cobertura codecov](./img/codecov.PNG) +También hemos comprobado localmente la cobertura mediante eclEmma para Eclipse: +![Cobertura codecov](./img/emma.PNG) **¿Cuál es el esfuerzo invertido en realizar la actividad?** + Se estima un esfuerzo individual de aproximadamente 8 horas para la realización de la práctica, de acuerdo al desglose presentado en la siguiente tabla: |Tarea|Horas-persona| @@ -85,5 +88,7 @@ https://travis-ci.org/dsr0018/poolobject #### Conclusiones La práctica ha constituido una buena primera aproximación al empleo práctico de un pipeline de integración continua en Java, en relación a los conceptos teóricos de medición y calidad en el desarrollo de software. + Destacar que el trabajo aparentemente inutil realizado inicialmente, derivado de la incorrecta configuración de Travis, ha servido al autor para estudiar bastantes posibilidades que desconocía de configuración de Ant. + Además, la práctica ha provocado una interesante reflexión acerca de la mejor manera de realizar un conjunto de test unitarios sobre instancias Singleton (un aspecto este que en opinión del autor no está resuelto de manera completamente satisfactoria)