OpenConcerto

Dépôt officiel du code source de l'ERP OpenConcerto
sonarqube

svn://code.openconcerto.org/openconcerto

Comparer les révisions

Ignorer les espaces blanc Révision 143 → Révision 144

/trunk/OpenConcerto/.settings/org.eclipse.jdt.core.prefs
Nouveau fichier
0,0 → 1,12
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
org.eclipse.jdt.core.compiler.compliance=1.7
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
org.eclipse.jdt.core.compiler.debug.localVariable=generate
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.source=1.7
/trunk/OpenConcerto/.classpath
14,7 → 14,6
<classpathentry exported="true" kind="lib" path="lib/jdom-1.1.1.jar"/>
<classpathentry exported="true" kind="lib" path="lib/jgrapht-0.7.3.jar"/>
<classpathentry exported="true" kind="lib" path="lib/jpos111.jar"/>
<classpathentry exported="true" kind="lib" path="lib/mysql-connector-java-5.1.5-bin.jar"/>
<classpathentry exported="true" kind="lib" path="lib/ognl-2.6.5.jar"/>
<classpathentry exported="true" kind="lib" path="lib/resolver.jar"/>
<classpathentry exported="true" kind="lib" path="lib/RXTXcomm.jar"/>
35,10 → 34,15
<classpathentry kind="lib" path="lib/msv-20090415.jar"/>
<classpathentry exported="true" kind="lib" path="lib/jOpenCalendar.jar"/>
<classpathentry kind="lib" path="lib/h2-1.3.175-dropTableRestrict.jar"/>
<classpathentry kind="lib" path="lib/json-smart-1.3.1.jar"/>
<classpathentry kind="lib" path="lib/icu4j-56_1-module_format+calendar.jar"/>
<classpathentry kind="lib" path="lib/icu4j-56-data-western_europe.jar"/>
<classpathentry kind="lib" path="lib/DS_Desktop_Notify.jar"/>
<classpathentry kind="lib" path="lib/mime_util.jar"/>
<classpathentry kind="lib" path="lib/accessors-smart-1.1.jar"/>
<classpathentry kind="lib" path="lib/gson-2.8.1.jar"/>
<classpathentry kind="lib" path="lib/icudata_56.jar"/>
<classpathentry kind="lib" path="lib/javax.mail-1.6.0.jar"/>
<classpathentry kind="lib" path="lib/json-smart-2.2.1.jar"/>
<classpathentry kind="lib" path="lib/mysql-connector-java-5.1.40-bin.jar"/>
<classpathentry kind="output" path="bin"/>
</classpath>
/trunk/OpenConcerto/Configuration/Template/Default/AvoirF.ods
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
/trunk/OpenConcerto/Configuration/Template/Default/VenteFacture.ods
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
/trunk/OpenConcerto/Configuration/Template/Default/ReportingVentes.ods
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
/trunk/OpenConcerto/Configuration/Template/Default/ReportingVentes.ods
Nouveau fichier
Changements de propriété:
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Index: OpenConcerto/Configuration/Template/Default/FactureFournisseur.ods
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Index: OpenConcerto/Configuration/Template/Default/EtatStocks.xml
===================================================================
--- OpenConcerto/Configuration/Template/Default/EtatStocks.xml (revision 0)
+++ OpenConcerto/Configuration/Template/Default/EtatStocks.xml (revision 144)
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<contentDocument>
+ <element location="A3" type="Value" ValueName="DATE">
+ </element>
+
+ <table firstLine="6" endLine="57" endPageLine="57" lastColumn="D" table="SAISIE_VENTE_FACTURE">
+ <element location="A" type="fill">
+ <field name="CODE" />
+ </element>
+
+ <element location="B" type="fill">
+ <field name="NOM" />
+ </element>
+
+ <element location="C" type="fill">
+ <field name="QTE" />
+ </element>
+
+ <element location="D" type="fill">
+ <field name="TOTAL_HA" />
+ </element>
+ </table>
+</contentDocument>
\ No newline at end of file
Index: OpenConcerto/Configuration/Template/Default/ReportingTaxeComplementaire.odsp
===================================================================
--- OpenConcerto/Configuration/Template/Default/ReportingTaxeComplementaire.odsp (revision 0)
+++ OpenConcerto/Configuration/Template/Default/ReportingTaxeComplementaire.odsp (revision 144)
@@ -0,0 +1,9 @@
+<odsp>
+<spliteveryrow>
+ <sheet number="0">49</sheet>
+</spliteveryrow>
+<offset x="40" y ="20"/>
+<resize percent="85"/>
+
+
+</odsp>
\ No newline at end of file
Index: OpenConcerto/Configuration/Template/Default/DIPE.odsp
===================================================================
--- OpenConcerto/Configuration/Template/Default/DIPE.odsp (revision 0)
+++ OpenConcerto/Configuration/Template/Default/DIPE.odsp (revision 144)
@@ -0,0 +1,9 @@
+<odsp>
+<spliteveryrow>
+ <sheet number="0">68</sheet>
+</spliteveryrow>
+<offset x="40" y ="20"/>
+<resize percent="85"/>
+
+
+</odsp>
\ No newline at end of file
Index: OpenConcerto/Configuration/Template/Default/Avoir.ods
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Index: OpenConcerto/Configuration/Template/Default/CommandeClient.ods
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Index: OpenConcerto/Configuration/Template/Default/EtatStocks.ods
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Index: OpenConcerto/Configuration/Template/Default/EtatStocks.ods
===================================================================
--- OpenConcerto/Configuration/Template/Default/EtatStocks.ods (revision 0)
+++ OpenConcerto/Configuration/Template/Default/EtatStocks.ods (revision 144)
/OpenConcerto/Configuration/Template/Default/EtatStocks.ods
Changements de propriété:
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Index: OpenConcerto/Configuration/Template/Default/ExportArticle.xml
===================================================================
--- OpenConcerto/Configuration/Template/Default/ExportArticle.xml (revision 0)
+++ OpenConcerto/Configuration/Template/Default/ExportArticle.xml (revision 144)
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<contentDocument>
+
+ <table firstLine="2" endLine="10000" endPageLine="10000" lastColumn="AK">
+ <element location="A" type="fill" controleMultiline="false">
+ <field base="Societe" name="CODE"/>
+ </element>
+ <element location="C" type="fill" controleMultiline="false">
+ <field base="Societe" name="NOM"/>
+ </element>
+ <element location="I" type="fill">
+ <field base="Societe" name="FOURNISSEUR"/>
+ </element>
+ <element location="P" type="fill">
+ <field base="Societe" name="QTE_ACHAT"/>
+ </element>
+ <element location="Q" type="fill">
+ <field base="Societe" name="QTE_MIN"/>
+ </element>
+ <element location="R" type="fill">
+ <field base="Societe" name="PA_HT"/>
+ </element>
+ <element location="T" type="fill">
+ <field base="Societe" name="PV_HT"/>
+ </element>
+ <element location="AF" type="fill">
+ <field base="Societe" name="POIDS"/>
+ </element>
+
+ <element location="AG" type="fill">
+ <field base="Societe" name="FAMILLE"/>
+ </element>
+
+ <element location="AJ" type="fill">
+ <field base="Societe" name="PAYS"/>
+ </element>
+ <element location="AK" type="fill">
+ <field base="Societe" name="CODE_DOUANIER"/>
+ </element>
+
+ </table>
+
+</contentDocument>
\ No newline at end of file
Index: OpenConcerto/Configuration/Template/Default/EtatStocks.odsp
===================================================================
--- OpenConcerto/Configuration/Template/Default/EtatStocks.odsp (revision 0)
+++ OpenConcerto/Configuration/Template/Default/EtatStocks.odsp (revision 144)
@@ -0,0 +1,9 @@
+<odsp>
+<spliteveryrow>
+ <sheet number="0">57</sheet>
+</spliteveryrow>
+<offset x="40" y ="20"/>
+<resize percent="85"/>
+
+
+</odsp>
\ No newline at end of file
Index: OpenConcerto/Configuration/Template/Default/BonLivraison.ods
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Index: OpenConcerto/Configuration/Template/Default/FichePayeSimplifiee.xml
===================================================================
--- OpenConcerto/Configuration/Template/Default/FichePayeSimplifiee.xml (revision 0)
+++ OpenConcerto/Configuration/Template/Default/FichePayeSimplifiee.xml (revision 144)
@@ -0,0 +1,198 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<contentDocument>
+ <element location="B1" type="fill">
+ <field base="Common" table="SOCIETE_COMMON" name="TYPE" />
+ <field base="Common" table="SOCIETE_COMMON" name="NOM" />
+ </element>
+
+ <element location="B2" type="fill">
+ <field base="Common" table="SOCIETE_COMMON" name="ID_ADRESSE_COMMON">
+ <field base="Common" name="RUE" />
+ <field base="Common" name="VILLE" type="villeCP" />
+ <field base="Common" name="VILLE" type="ville" />
+ </field>
+ </element>
+
+ <element location="D7" type="fill">
+ <field base="Common" table="SOCIETE_COMMON" name="NUMERO_URSSAF" />
+ </element>
+
+ <element location="G7" type="fill">
+ <field base="Common" table="SOCIETE_COMMON" name="NUM_SIRET" />
+ </element>
+
+ <element location="J7" type="fill">
+ <field base="Common" table="SOCIETE_COMMON" name="NUM_APE" />
+ </element>
+
+ <element location="B5" type="replace" replacePattern="_">
+ <field name="ID_SALARIE">
+ <field name="CODE"/>
+ </field>
+ </element>
+
+ <element location="E5" type="replace" replacePattern="_" cellSize="75">
+ <field name="ID_SALARIE">
+ <field name="ID_INFOS_SALARIE_PAYE">
+ <field name="ID_CONTRAT_SALARIE">
+ <field name="NATURE" cellSize="75"/>
+ </field>
+ </field>
+ </field>
+ </element>
+
+
+ <element location="G2" type="fill">
+ <field name="DU" prefix="Paie du " type="date" datePattern="dd/MM/yy"/>
+ <field name="AU" prefix=" au " type="date" datePattern="dd/MM/yy"/>
+ </element>
+
+ <element location="D54" type="fill">
+ <field name="DU" type="datePaye" />
+ </element>
+
+ <element location="G9" type="fill">
+ <field name="ID_SALARIE">
+ <field name="PRENOM"/>
+ <field name="NOM"/>
+ </field>
+ </element>
+ <element location="G10" type="fill">
+ <field name="ID_SALARIE">
+ <field name="ID_ETAT_CIVIL">
+ <field name="ID_ADRESSE">
+ <field name="RUE"/>
+ </field>
+ </field>
+ </field>
+ </element>
+ <element location="G12" type="fill">
+ <field name="ID_SALARIE">
+ <field name="ID_ETAT_CIVIL">
+ <field name="ID_ADRESSE">
+ <field name="CODE_POSTAL"/>
+ <field name="VILLE"/>
+ </field>
+ </field>
+ </field>
+ </element>
+
+ <element location="D12" type="fill">
+ <field name="ID_VARIABLE_SALARIE">
+ <field name="CONGES_PRIS"/>
+ </field>
+ </element>
+ <element location="E12" type="fill">
+ <field name="ID_CUMULS_CONGES">
+ <field name="RESTANT"/>
+ </field>
+ </element>
+ <element location="F12" type="fill">
+ <field name="ID_CUMULS_CONGES">
+ <field name="ACQUIS"/>
+ </field>
+ </element>
+ <element location="B6" type="replace" replacePattern="_">
+ <field name="ID_SALARIE">
+ <field name="ID_ETAT_CIVIL">
+ <field name="NUMERO_SS"/>
+ </field>
+ </field>
+ </element>
+
+ <element location="B3" type="fill" >
+ <field name="ID_SALARIE">
+ <field name="ID_INFOS_SALARIE_PAYE">
+ <field name="ID_IDCC">
+ <field name="NOM" prefix="Convention collective : " cellSize="125"/>
+ </field>
+ </field>
+ </field>
+ </element>
+
+ <element location="B9" type="fill">
+ <field name="DETAILS_CONGES"/>
+ </element>
+
+ <element location="H52" type="fill">
+ <field name="COT_SAL"/>
+ </element>
+ <element location="I52" type="fill">
+ <field name="COT_PAT"/>
+ </element>
+
+
+ <element location="I54" type="fill">
+ <field name="NET_A_PAYER"/>
+ </element>
+
+ <element location="D57" type="fill">
+ <field name="SAL_BRUT"/>
+ </element>
+ <element location="E57" type="fill">
+ <field name="COT_SAL"/>
+ </element>
+ <element location="F57" type="fill">
+ <field name="COT_PAT"/>
+ </element>
+
+ <element location="G57" type="fill">
+ <field name="AVANTAGE_NATURE"/>
+ </element>
+
+ <element location="H57" type="fill">
+ <field name="NET_IMP"/>
+ </element>
+
+ <element location="I57" type="fill">
+ <field name="ALLEGEMENT_COTISATION"/>
+ </element>
+
+ <element location="D58" type="fill">
+ <field name="SAL_BRUT" type="cumulPaye"/>
+ </element>
+ <element location="E58" type="fill">
+ <field name="COT_SAL" type="cumulPaye"/>
+ </element>
+ <element location="F58" type="fill">
+ <field name="COT_PAT" type="cumulPaye"/>
+ </element>
+ <element location="G58" type="fill">
+ <field name="AVANTAGE_NATURE" type="cumulPaye"/>
+ </element>
+
+ <element location="H58" type="fill">
+ <field name="NET_IMP" type="cumulPaye"/>
+ </element>
+
+ <element location="I58" type="fill">
+ <field name="ALLEGEMENT_COTISATION" type="cumulPaye"/>
+ </element>
+
+ <table endPageLine="60" firstLine="15" endLine="51" lastColumn="J" base="Societe" table="FICHE_PAYE_ELEMENT"
+ blankLineBeforeStyle="Titre 1,Titre 2" fieldWhere="IMPRESSION" orderBy="POSITION">
+ <element location="B" type="fill" cellSize="52">
+ <field name="NOM" />
+ </element>
+ <element location="E" type="fill">
+ <field name="NB_BASE" />
+ </element>
+ <element location="F" type="fill">
+ <field name="TAUX_SAL" />
+ </element>
+ <element location="G" type="fill">
+ <field name="MONTANT_SAL_AJ" />
+ </element>
+ <element location="H" type="fill">
+ <field name="MONTANT_SAL_DED" />
+ </element>
+ <!-- <element location="I" type="fill">
+ <field name="TAUX_PAT" type="Devise" />
+ </element> -->
+ <element location="J" type="fill">
+ <field name="MONTANT_PAT" />
+ </element>
+
+
+ </table>
+</contentDocument>
\ No newline at end of file
Index: OpenConcerto/Configuration/Template/Default/ExportArticle.ods
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Index: OpenConcerto/Configuration/Template/Default/ExportArticle.ods
===================================================================
--- OpenConcerto/Configuration/Template/Default/ExportArticle.ods (revision 0)
+++ OpenConcerto/Configuration/Template/Default/ExportArticle.ods (revision 144)
/OpenConcerto/Configuration/Template/Default/ExportArticle.ods
Changements de propriété:
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Index: OpenConcerto/Configuration/Template/Default/DIPE.xml
===================================================================
--- OpenConcerto/Configuration/Template/Default/DIPE.xml (revision 0)
+++ OpenConcerto/Configuration/Template/Default/DIPE.xml (revision 144)
@@ -0,0 +1,150 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<contentDocument>
+ <element0 location="C1" type="Value" ValueName="SOCIETE">
+ </element0>
+
+ <element0 location="C2" type="Value" ValueName="TELEPHONE">
+ </element0>
+
+ <element0 location="A5" type="Value" ValueName="LIBELLE">
+ </element0>
+
+
+ <element0 location="E16" type="Value" ValueName="BASE" />
+ <element0 location="F16" type="Value" ValueName="ANCIENNETE" />
+ <element0 location="G16" type="Value" ValueName="TRANSPORT" />
+ <element0 location="H16" type="Value" ValueName="BRUT" />
+ <element0 location="I16" type="Value" ValueName="TAXE" />
+ <element0 location="J16" type="Value" ValueName="IRPP" />
+ <element0 location="K16" type="Value" ValueName="CAC" />
+ <element0 location="L16" type="Value" ValueName="CCF" />
+ <element0 location="M16" type="Value" ValueName="TDL" />
+ <element0 location="N16" type="Value" ValueName="RAV" />
+ <element0 location="O16" type="Value" ValueName="PV" />
+ <element0 location="P16" type="Value" ValueName="TOTAL_RETENU" />
+ <element0 location="Q16" type="Value" ValueName="NET" />
+
+
+
+ <element0 location="A30" type="Value" ValueName="NUMERO_EMPLOYEUR">
+ </element0>
+
+ <element0 location="I30" type="Value" ValueName="NUMERO_IDENTIFIANT_UNIQUE">
+ </element0>
+
+ <element0 location="E21" type="Value" ValueName="BASE_PENSION_FAM">
+ </element0>
+
+ <element0 location="H21" type="Value" ValueName="MONTANT_PENSION_FAM">
+ </element0>
+
+ <element0 location="E23" type="Value" ValueName="BASE_PENSION_VIEL">
+ </element0>
+
+ <element0 location="H23" type="Value" ValueName="MONTANT_PENSION_VIEL">
+ </element0>
+
+ <element0 location="E25" type="Value" ValueName="BASE_AT">
+ </element0>
+
+ <element0 location="H25" type="Value" ValueName="MONTANT_AT">
+ </element0>
+
+ <element0 location="H26" type="Value" ValueName="TOTAL_COT">
+ </element0>
+
+ <element0 location="O21" type="Value" ValueName="BASE_CCF">
+ </element0>
+
+ <element0 location="Q21" type="Value" ValueName="MONTANT_CCF">
+ </element0>
+
+ <element0 location="O23" type="Value" ValueName="BASE_FNE">
+ </element0>
+
+ <element0 location="Q23" type="Value" ValueName="MONTANT_FNE">
+ </element0>
+
+ <element0 location="Q26" type="Value" ValueName="TOTAL_FISCAL">
+ </element0>
+
+ <element0 location="H31" type="Value" ValueName="COT_PAT">
+ </element0>
+
+ <element0 location="H33" type="Value" ValueName="COT_SAL">
+ </element0>
+ <element0 location="H34" type="Value" ValueName="COT_TOTAL">
+ </element0>
+
+ <element0 location="Q31" type="Value" ValueName="TAX_PAT">
+ </element0>
+
+ <element0 location="Q33" type="Value" ValueName="TAX_SAL">
+ </element0>
+ <element0 location="Q34" type="Value" ValueName="TAX_TOTAL">
+ </element0>
+
+ <table0 firstLine="11" endLine="16" endPageLine="36" lastColumn="Q" table="ECRITURE" pageRef="P8">
+ <element location="A" type="fill">
+ <field name="NUMERO" />
+ </element>
+
+ <element location="B" type="fill">
+ <field name="NOM" />
+ </element>
+
+ <element location="C" type="fill">
+ <field name="CNPS" />
+ </element>
+
+ <element location="D" type="fill">
+ <field name="INTERNE" />
+ </element>
+
+ <element location="E" type="fill">
+ <field name="BASE" />
+ </element>
+
+ <element location="F" type="fill">
+ <field name="ANCIENNETE" />
+ </element>
+
+ <element location="G" type="fill">
+ <field name="TRANSPORT" />
+ </element>
+
+ <element location="H" type="fill">
+ <field name="BRUT" />
+ </element>
+
+ <element location="I" type="fill">
+ <field name="TAXE" />
+ </element>
+
+ <element location="J" type="fill">
+ <field name="IRPP" />
+ </element>
+ <element location="K" type="fill">
+ <field name="CAC" />
+ </element>
+ <element location="L" type="fill">
+ <field name="CCF" />
+ </element>
+ <element location="M" type="fill">
+ <field name="TDL" />
+ </element>
+ <element location="N" type="fill">
+ <field name="RAV" />
+ </element>
+ <element location="O" type="fill">
+ <field name="PV" />
+ </element>
+ <element location="P" type="fill">
+ <field name="TOTAL_RETENU" />
+ </element>
+ <element location="Q" type="fill">
+ <field name="NET" />
+ </element>
+
+ </table0>
+</contentDocument>
\ No newline at end of file
Index: OpenConcerto/Configuration/Template/Default/FichePayeSimplifiee.ods
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Index: OpenConcerto/Configuration/Template/Default/FichePayeSimplifiee.ods
===================================================================
--- OpenConcerto/Configuration/Template/Default/FichePayeSimplifiee.ods (revision 0)
+++ OpenConcerto/Configuration/Template/Default/FichePayeSimplifiee.ods (revision 144)
/OpenConcerto/Configuration/Template/Default/FichePayeSimplifiee.ods
Changements de propriété:
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Index: OpenConcerto/Configuration/Template/Default/DemandePrix.xml
===================================================================
--- OpenConcerto/Configuration/Template/Default/DemandePrix.xml (revision 0)
+++ OpenConcerto/Configuration/Template/Default/DemandePrix.xml (revision 144)
@@ -0,0 +1,106 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<contentDocument>
+ <element location="B1" type="fill">
+ <field base="Common" table="SOCIETE_COMMON" name="TYPE" />
+ <field base="Common" table="SOCIETE_COMMON" name="NOM" />
+ </element>
+
+ <element location="B2" type="fill">
+ <field base="Common" table="SOCIETE_COMMON" name="ID_ADRESSE_COMMON">
+ <field base="Common" table="ADRESSE_COMMON" name="RUE" />
+ </field>
+ </element>
+
+ <element location="B3" type="fill">
+ <field base="Common" table="SOCIETE_COMMON" name="ID_ADRESSE_COMMON">
+ <field base="Common" table="ADRESSE_COMMON" name="VILLE" type="villeCP" />
+ <field base="Common" table="ADRESSE_COMMON" name="VILLE" type="ville" />
+ <field base="Common" table="ADRESSE_COMMON" name="CEDEX" prefix="CEDEX " conditionField="HAS_CEDEX" />
+ </field>
+ </element>
+
+ <element location="B5" type="fill">
+ <field base="Common" table="SOCIETE_COMMON" name="TYPE"/>
+ <field base="Common" table="SOCIETE_COMMON" name="CAPITAL" prefix=" au capital de " suffix="€"/>
+ </element>
+
+ <element location="B6" type="fill">
+ <field base="Common" table="SOCIETE_COMMON" name="NUM_SIRET" prefix="N° de SIREN "/>
+ </element>
+
+ <element location="B7" type="replace" replacePattern="_">
+ <field base="Common" table="SOCIETE_COMMON" name="NUM_NII" />
+ </element>
+
+ <element location="B8" type="replace" replacePattern="_">
+ <field base="Common" table="SOCIETE_COMMON" name="NUM_TEL" />
+ </element>
+
+ <element location="B9" type="replace" replacePattern="_">
+ <field base="Common" table="SOCIETE_COMMON" name="NUM_FAX" />
+ </element>
+
+ <element location="B10" type="replace" replacePattern="_">
+ <field base="Common" table="SOCIETE_COMMON" name="MAIL" />
+ </element>
+
+
+ <element location="B16" type="fill">
+ <field name="ID_COMMERCIAL">
+ <field name="NOM" />
+ </field>
+ </element>
+
+ <element location="B13" type="fill">
+ <field name="NUMERO" />
+ </element>
+
+ <element location="C13" type="fill">
+ <field name="DATE" />
+ </element>
+
+
+
+
+ <element location="H10" type="fill">
+ <field name="ID_FOURNISSEUR">
+ <field name="TYPE" />
+ <field name="NOM" />
+ </field>
+ </element>
+
+ <element location="H11" type="fill">
+ <field name="ID_FOURNISSEUR">
+ <field name="ID_ADRESSE">
+ <field name="RUE" />
+ </field>
+ </field>
+ </element>
+
+ <element location="H13" type="fill">
+ <field name="ID_FOURNISSEUR">
+ <field name="ID_ADRESSE">
+ <field name="VILLE" type="villeCP" />
+ <field name="VILLE" type="ville" />
+ <field name="CEDEX" prefix="CEDEX " conditionField="HAS_CEDEX" />
+ </field>
+ </field>
+ </element>
+
+
+ <table endPageLine="57" firstLine="22" endLine="52" lastColumn="L" table="DEMANDE_PRIX_ELEMENT">
+ <element location="B" type="fill">
+ <field name="NOM" />
+ </element>
+
+ <element location="K" type="fill">
+ <field name="QTE" />
+ </element>
+
+
+ <element location="L" type="fill">
+ <field name="T_POIDS" />
+ </element>
+
+ </table>
+</contentDocument>
\ No newline at end of file
Index: OpenConcerto/Configuration/Template/Default/ReportingEcoContribution.xml
===================================================================
--- OpenConcerto/Configuration/Template/Default/ReportingEcoContribution.xml (revision 0)
+++ OpenConcerto/Configuration/Template/Default/ReportingEcoContribution.xml (revision 144)
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<contentDocument>
+
+
+ <element0 location="B2" type="Value" ValueName="PERIODE">
+ </element0>
+
+ <element0 location="C49" type="Value" ValueName="TOTAL_QTE">
+ </element0>
+
+ <element0 location="D49" type="Value" ValueName="TOTAL">
+ </element0>
+
+
+ <table firstLine="4" blankLineBeforeStyle="Titre 1,Titre 2" endLine="1999" endPageLine="2000" lastColumn="J" base="Societe" table="AFFAIRE" sheet="1">
+
+ <element location="A" type="fill">
+ <field base="Societe" name="CODE"/>
+ </element>
+
+<element location="B" type="fill">
+ <field base="Societe" name="NOM"/>
+ </element>
+<element location="C" type="fill">
+ <field base="Societe" name="QTE"/>
+ </element>
+
+ <element location="D" type="fill" >
+ <field base="Societe" name="TOTAL_ECO"/>
+ </element>
+
+ </table>
+
+
+
+</contentDocument>
\ No newline at end of file
Index: OpenConcerto/Configuration/Template/Default/ReportingVentes.odsp
===================================================================
--- OpenConcerto/Configuration/Template/Default/ReportingVentes.odsp (revision 0)
+++ OpenConcerto/Configuration/Template/Default/ReportingVentes.odsp (revision 144)
@@ -0,0 +1,9 @@
+<odsp>
+<spliteveryrow>
+ <sheet number="0">57</sheet>
+</spliteveryrow>
+<offset x="40" y ="20"/>
+<resize percent="85"/>
+
+
+</odsp>
\ No newline at end of file
Index: OpenConcerto/Configuration/Template/Default/DIPE.ods
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Index: OpenConcerto/Configuration/Template/Default/DIPE.ods
===================================================================
--- OpenConcerto/Configuration/Template/Default/DIPE.ods (revision 0)
+++ OpenConcerto/Configuration/Template/Default/DIPE.ods (revision 144)
/OpenConcerto/Configuration/Template/Default/DIPE.ods
Changements de propriété:
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Index: OpenConcerto/Configuration/Template/Default/FichePayeSimplifiee.odsp
===================================================================
--- OpenConcerto/Configuration/Template/Default/FichePayeSimplifiee.odsp (revision 0)
+++ OpenConcerto/Configuration/Template/Default/FichePayeSimplifiee.odsp (revision 144)
@@ -0,0 +1,9 @@
+<odsp>
+<spliteveryrow>
+ <sheet number="0">60</sheet>
+</spliteveryrow>
+<offset x="20" y ="20"/>
+<resize percent="92"/>
+
+
+</odsp>
\ No newline at end of file
Index: OpenConcerto/Configuration/Template/Default/BonReception.ods
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Index: OpenConcerto/Configuration/Template/Default/ReportingTaxeComplementaire.xml
===================================================================
--- OpenConcerto/Configuration/Template/Default/ReportingTaxeComplementaire.xml (revision 0)
+++ OpenConcerto/Configuration/Template/Default/ReportingTaxeComplementaire.xml (revision 144)
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<contentDocument>
+
+
+ <element0 location="B2" type="Value" ValueName="PERIODE">
+ </element0>
+
+ <element0 location="C49" type="Value" ValueName="TOTAL_QTE">
+ </element0>
+
+ <element0 location="D49" type="Value" ValueName="TOTAL_BASE">
+ </element0>
+
+ <element0 location="E49" type="Value" ValueName="TOTAL_TAXE">
+ </element0>
+
+ <table firstLine="4" blankLineBeforeStyle="Titre 1,Titre 2" endLine="1999" endPageLine="2000" lastColumn="J" base="Societe" table="AFFAIRE" sheet="1">
+
+ <element location="A" type="fill">
+ <field base="Societe" name="CODE"/>
+ </element>
+
+<element location="B" type="fill">
+ <field base="Societe" name="NOM"/>
+ </element>
+<element location="C" type="fill">
+ <field base="Societe" name="QTE"/>
+ </element>
+
+ <element location="D" type="fill" >
+ <field base="Societe" name="TOTAL_BASE"/>
+ </element>
+
+
+ <element location="E" type="fill" >
+ <field base="Societe" name="TOTAL_TAXE"/>
+ </element>
+ </table>
+
+
+
+</contentDocument>
\ No newline at end of file
Index: OpenConcerto/Configuration/Template/Default/DemandePrix.ods
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Index: OpenConcerto/Configuration/Template/Default/DemandePrix.ods
===================================================================
--- OpenConcerto/Configuration/Template/Default/DemandePrix.ods (revision 0)
+++ OpenConcerto/Configuration/Template/Default/DemandePrix.ods (revision 144)
/OpenConcerto/Configuration/Template/Default/DemandePrix.ods
Changements de propriété:
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Index: OpenConcerto/Configuration/Template/Default/ReportingEcoContribution.ods
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Index: OpenConcerto/Configuration/Template/Default/ReportingEcoContribution.ods
===================================================================
--- OpenConcerto/Configuration/Template/Default/ReportingEcoContribution.ods (revision 0)
+++ OpenConcerto/Configuration/Template/Default/ReportingEcoContribution.ods (revision 144)
/OpenConcerto/Configuration/Template/Default/ReportingEcoContribution.ods
Changements de propriété:
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Index: OpenConcerto/Configuration/Template/Default/VenteFacture.xml
===================================================================
--- OpenConcerto/Configuration/Template/Default/VenteFacture.xml (revision 143)
+++ OpenConcerto/Configuration/Template/Default/VenteFacture.xml (revision 144)
@@ -76,6 +76,8 @@
<element location="H11" type="address.customer.invoice.full">
</element>
+
+
<element location="L62" type="fill">
<field name="T_HT" type="devise" />
</element>
/trunk/OpenConcerto/Configuration/Template/Default/ReportingVentes.xml
Nouveau fichier
0,0 → 1,30
<?xml version="1.0" encoding="UTF-8" ?>
<contentDocument>
<element location="A1" type="Value" ValueName="NOM">
</element>
 
<element location="A3" type="Value" ValueName="DATE">
</element>
 
<table firstLine="6" endLine="57" endPageLine="57" lastColumn="E" table="SAISIE_VENTE_FACTURE">
<element location="A" type="fill">
<field name="CODE" />
</element>
 
<element location="B" type="fill">
<field name="NOM" />
</element>
<element location="C" type="fill">
<field name="QTE" />
</element>
 
<element location="D" type="fill">
<field name="TOTAL_HT" />
</element>
 
<element location="E" type="fill">
<field name="TOTAL_TTC" />
</element>
</table>
</contentDocument>
/trunk/OpenConcerto/Configuration/Template/Default/Devis.ods
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
/trunk/OpenConcerto/Configuration/Template/Default/ReportingTaxeComplementaire.ods
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
/trunk/OpenConcerto/Configuration/Template/Default/ReportingTaxeComplementaire.ods
Nouveau fichier
Changements de propriété:
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Index: OpenConcerto/Configuration/Template/Default/DemandePrix.odsp
===================================================================
--- OpenConcerto/Configuration/Template/Default/DemandePrix.odsp (revision 0)
+++ OpenConcerto/Configuration/Template/Default/DemandePrix.odsp (revision 144)
@@ -0,0 +1,9 @@
+<odsp>
+<spliteveryrow>
+ <sheet number="0">58</sheet>
+</spliteveryrow>
+<offset x="40" y ="20"/>
+<resize percent="85"/>
+
+
+</odsp>
\ No newline at end of file
Index: OpenConcerto/Configuration/Template/Default/ReportingEcoContribution.odsp
===================================================================
--- OpenConcerto/Configuration/Template/Default/ReportingEcoContribution.odsp (revision 0)
+++ OpenConcerto/Configuration/Template/Default/ReportingEcoContribution.odsp (revision 144)
@@ -0,0 +1,9 @@
+<odsp>
+<spliteveryrow>
+ <sheet number="0">49</sheet>
+</spliteveryrow>
+<offset x="40" y ="20"/>
+<resize percent="85"/>
+
+
+</odsp>
\ No newline at end of file
Index: OpenConcerto/Configuration/Template/PDF/3310_2.pdf
===================================================================
--- OpenConcerto/Configuration/Template/PDF/3310_2.pdf (revision 143)
+++ OpenConcerto/Configuration/Template/PDF/3310_2.pdf (revision 144)
@@ -1,886 +1,1075 @@
-%PDF-1.6 -%âãÏÓ
-6 0 obj -<</Linearized 1/L 44631/O 9/E 39191/N 1/T 44465/H [ 3436 407]>> -endobj -
-xref
-6 157
-0000000016 00000 n
-0000003843 00000 n
-0000003918 00000 n
-0000004312 00000 n
-0000004765 00000 n
-0000005056 00000 n
-0000005217 00000 n
-0000005380 00000 n
-0000005543 00000 n
-0000005674 00000 n
-0000005835 00000 n
-0000005996 00000 n
-0000006159 00000 n
-0000006318 00000 n
-0000006477 00000 n
-0000006636 00000 n
-0000006798 00000 n
-0000006959 00000 n
-0000007123 00000 n
-0000007285 00000 n
-0000007447 00000 n
-0000007609 00000 n
-0000007771 00000 n
-0000007932 00000 n
-0000008095 00000 n
-0000008257 00000 n
-0000008418 00000 n
-0000008582 00000 n
-0000008743 00000 n
-0000008904 00000 n
-0000009062 00000 n
-0000009220 00000 n
-0000009378 00000 n
-0000009536 00000 n
-0000009695 00000 n
-0000009854 00000 n
-0000010015 00000 n
-0000010174 00000 n
-0000010335 00000 n
-0000010496 00000 n
-0000010655 00000 n
-0000010814 00000 n
-0000010973 00000 n
-0000011134 00000 n
-0000011341 00000 n
-0000011571 00000 n
-0000011648 00000 n
-0000011794 00000 n
-0000012067 00000 n
-0000012161 00000 n
-0000012936 00000 n
-0000013025 00000 n
-0000013099 00000 n
-0000013170 00000 n
-0000013206 00000 n
-0000014361 00000 n
-0000014452 00000 n
-0000015536 00000 n
-0000016613 00000 n
-0000017207 00000 n
-0000017358 00000 n
-0000018303 00000 n
-0000019203 00000 n
-0000019609 00000 n
-0000019774 00000 n
-0000019823 00000 n
-0000021088 00000 n
-0000021796 00000 n
-0000021875 00000 n
-0000021957 00000 n
-0000022036 00000 n
-0000022118 00000 n
-0000022197 00000 n
-0000022279 00000 n
-0000022358 00000 n
-0000022440 00000 n
-0000022519 00000 n
-0000022601 00000 n
-0000022680 00000 n
-0000022762 00000 n
-0000022841 00000 n
-0000022923 00000 n
-0000023002 00000 n
-0000023084 00000 n
-0000023163 00000 n
-0000023245 00000 n
-0000023324 00000 n
-0000023406 00000 n
-0000023485 00000 n
-0000023567 00000 n
-0000023646 00000 n
-0000023728 00000 n
-0000023807 00000 n
-0000023889 00000 n
-0000023968 00000 n
-0000024051 00000 n
-0000024131 00000 n
-0000024214 00000 n
-0000024294 00000 n
-0000024377 00000 n
-0000024457 00000 n
-0000024540 00000 n
-0000024620 00000 n
-0000024703 00000 n
-0000024783 00000 n
-0000024866 00000 n
-0000024946 00000 n
-0000025029 00000 n
-0000025109 00000 n
-0000025192 00000 n
-0000025272 00000 n
-0000025355 00000 n
-0000025435 00000 n
-0000025518 00000 n
-0000025598 00000 n
-0000025681 00000 n
-0000025761 00000 n
-0000025844 00000 n
-0000025924 00000 n
-0000026007 00000 n
-0000026087 00000 n
-0000026170 00000 n
-0000026250 00000 n
-0000026333 00000 n
-0000026413 00000 n
-0000026496 00000 n
-0000026576 00000 n
-0000026659 00000 n
-0000026739 00000 n
-0000026822 00000 n
-0000026902 00000 n
-0000026985 00000 n
-0000027065 00000 n
-0000027148 00000 n
-0000027228 00000 n
-0000027311 00000 n
-0000027391 00000 n
-0000027474 00000 n
-0000027554 00000 n
-0000027637 00000 n
-0000027717 00000 n
-0000027800 00000 n
-0000030471 00000 n
-0000031375 00000 n
-0000032168 00000 n
-0000033011 00000 n
-0000033182 00000 n
-0000036855 00000 n
-0000037287 00000 n
-0000037591 00000 n
-0000037788 00000 n
-0000037845 00000 n
-0000038540 00000 n
-0000038752 00000 n
-0000039047 00000 n
-0000039125 00000 n
-0000003436 00000 n
-trailer
-<</Size 163/Prev 44455/Root 7 0 R/Info 5 0 R/ID[<D6D7F99391B95179C4934F04168803DF><A940CE7B8BF59E43BB240391604C126A>]>>
-startxref
-0
-%%EOF
-
-162 0 obj -<</Length 318/Filter/FlateDecode/I 515/S 101/V 376>>stream
-xÚb``˜ÅÀÀ»:O2  faàh`À
-ÝÒ:ˆHšfA1ƒ
-XâBþµìêYä…zö -ÕìêØ/4°?¨! ÈƒZ Tû ÊւЅjÊ «y4Ù¼e^ô˜9@É€Áõƒ¹c‹ Òƒb‹Ë â
- WÎj1h3= }СúåmæôÕ¨ ýq`À…ŒA“¹™™È1à?†é  eò ]ÊÀ¡ÍÌÂÊÆÎÁÉÅÍÃËÇ/ ($,"*&.!)%-#+'¯ ¨¤¬¢ª¦®¡©¥£ëèäìâêæîáéåíãë矐˜”œ’š–ž‘™•“›—_PXT\RZV^QYU]S[WßÐØÔÜÒÚÖÞÑÙ´š•aµÄI  –¬
-endstream -endobj -7 0 obj -<</Metadata 4 0 R/AcroForm 8 0 R/Pages 3 0 R/Type/Catalog>> -endobj -8 0 obj -<</Fields[11 0 R 12 0 R 13 0 R 14 0 R 15 0 R 16 0 R 17 0 R 18 0 R 19 0 R 20 0 R 21 0 R 22 0 R 23 0 R 24 0 R 25 0 R 26 0 R 27 0 R 28 0 R 29 0 R 30 0 R 31 0 R 32 0 R 33 0 R 34 0 R 35 0 R 36 0 R 37 0 R 38 0 R 39 0 R 40 0 R 41 0 R 42 0 R 43 0 R 44 0 R 45 0 R 46 0 R 47 0 R 48 0 R 49 0 R]/DA(/Helv 0 Tf 0 g )/DR<</Font<</Helv 2 0 R/ZaDb 51 0 R>>/Encoding<</PDFDocEncoding 1 0 R>>>>>> -endobj -9 0 obj -<</CropBox[0 0 595 842]/Annots 10 0 R/Parent 3 0 R/Contents[60 0 R 62 0 R 63 0 R 64 0 R 66 0 R 67 0 R 71 0 R 72 0 R]/Rotate 0/BleedBox[-6.86 -9.8 601.72 851.62]/MediaBox[0 0 595 842]/TrimBox[5.88 2.94 588.98 838.88]/Resources<</ColorSpace<</CS0 57 0 R/CS1 58 0 R/CS2 59 0 R/CS3 70 0 R>>/Font<</TT0 68 0 R/T1_0 54 0 R/T1_1 55 0 R/T1_2 56 0 R/T1_3 61 0 R/T1_4 65 0 R/T1_5 69 0 R>>/ProcSet[/PDF/Text]/ExtGState<</GS0 161 0 R>>>>/Type/Page>> -endobj -10 0 obj -[11 0 R 12 0 R 13 0 R 14 0 R 15 0 R 16 0 R 17 0 R 18 0 R 19 0 R 20 0 R 21 0 R 22 0 R 23 0 R 24 0 R 25 0 R 26 0 R 27 0 R 28 0 R 29 0 R 30 0 R 31 0 R 32 0 R 33 0 R 34 0 R 35 0 R 36 0 R 37 0 R 38 0 R 39 0 R 40 0 R 41 0 R 42 0 R 43 0 R 44 0 R 45 0 R 46 0 R 47 0 R 48 0 R 49 0 R] -endobj -11 0 obj -<</Rect[217.9 756.815 296.911 775.334]/Subtype/Widget/F 4/P 9 0 R/Q 2/T(B1_1_1)/DA(/Helv 9 Tf 0 g)/FT/Tx/Type/Annot/AA<</F 145 0 R/K 146 0 R>>>> -endobj -12 0 obj -<</Rect[218.517 733.976 297.529 751.877]/Subtype/Widget/F 4/P 9 0 R/Q 2/T(B1_2_1)/DA(/Helv 9 Tf 0 g)/FT/Tx/Type/Annot/AA<</F 143 0 R/K 144 0 R>>>> -endobj -13 0 obj -<</Rect[218.517 707.433 297.529 725.334]/Subtype/Widget/F 4/P 9 0 R/Q 2/T(B1_3_2)/DA(/Helv 9 Tf 0 g)/FT/Tx/Type/Annot/AA<</F 141 0 R/K 142 0 R>>>> -endobj -14 0 obj -<</Rect[38.2713 673.483 181.48 686.446]/Subtype/Widget/F 4/P 9 0 R/T(B1_3_1)/DA(/Helv 9 Tf 0 g)/FT/Tx/Type/Annot>> -endobj -15 0 obj -<</Rect[496.292 756.198 575.921 774.716]/Subtype/Widget/F 4/P 9 0 R/Q 2/T(A_04)/DA(/Helv 9 Tf 0 g)/FT/Tx/Type/Annot/AA<</F 139 0 R/K 140 0 R>>>> -endobj -16 0 obj -<</Rect[496.292 733.976 575.921 751.877]/Subtype/Widget/F 4/P 9 0 R/Q 2/T(A_05)/DA(/Helv 9 Tf 0 g)/FT/Tx/Type/Annot/AA<</F 137 0 R/K 138 0 R>>>> -endobj -17 0 obj -<</Rect[496.292 707.433 575.921 725.334]/Subtype/Widget/F 4/P 9 0 R/Q 2/T(B1_3_3)/DA(/Helv 9 Tf 0 g)/FT/Tx/Type/Annot/AA<</F 135 0 R/K 136 0 R>>>> -endobj -18 0 obj -<</Rect[496.91 683.359 576.539 701.26]/Subtype/Widget/F 4/P 9 0 R/Q 2/T(B1_4)/DA(/Helv 9 Tf 0 g)/FT/Tx/Type/Annot/AA<</F 133 0 R/K 134 0 R>>>> -endobj -19 0 obj -<</Rect[408.021 617.31 487.65 635.211]/Subtype/Widget/F 4/P 9 0 R/Q 2/T(C1_1)/DA(/Helv 9 Tf 0 g)/FT/Tx/Type/Annot/AA<</F 131 0 R/K 132 0 R>>>> -endobj -20 0 obj -<</Rect[408.021 598.792 487.65 617.31]/Subtype/Widget/F 4/P 9 0 R/Q 2/T(C1_2)/DA(/Helv 9 Tf 0 g)/FT/Tx/Type/Annot/AA<</F 129 0 R/K 130 0 R>>>> -endobj -21 0 obj -<</Rect[495.675 616.693 574.687 635.211]/Subtype/Widget/F 4/P 9 0 R/Q 2/T(ZCP_5)/DA(/Helv 9 Tf 0 g)/FT/Tx/Type/Annot/AA<</F 127 0 R/K 128 0 R>>>> -endobj -22 0 obj -<</Rect[495.675 598.792 574.687 617.31]/Subtype/Widget/F 4/P 9 0 R/Q 2/T(ZCP_6)/DA(/Helv 9 Tf 0 g)/FT/Tx/Type/Annot/AA<</F 125 0 R/K 126 0 R>>>> -endobj -23 0 obj -<</Rect[495.675 552.496 574.687 570.397]/Subtype/Widget/F 4/P 9 0 R/Q 2/T(ZCP_7_1)/DA(/Helv 9 Tf 0 g)/FT/Tx/Type/Annot/AA<</F 123 0 R/K 124 0 R>>>> -endobj -24 0 obj -<</Rect[495.675 533.978 574.687 551.879]/Subtype/Widget/F 4/P 9 0 R/Q 2/T(ZCP_7)/DA(/Helv 9 Tf 0 g)/FT/Tx/Type/Annot/AA<</F 121 0 R/K 122 0 R>>>> -endobj -25 0 obj -<</Rect[408.021 553.113 487.65 571.014]/Subtype/Widget/F 4/P 9 0 R/Q 2/T(C1_4_1)/DA(/Helv 9 Tf 0 g)/FT/Tx/Type/Annot/AA<</F 119 0 R/K 120 0 R>>>> -endobj -26 0 obj -<</Rect[408.021 533.978 487.65 551.262]/Subtype/Widget/F 4/P 9 0 R/Q 2/T(C1_4_3)/DA(/Helv 9 Tf 0 g)/FT/Tx/Type/Annot/AA<</F 117 0 R/K 118 0 R>>>> -endobj -27 0 obj -<</Rect[408.021 475.336 487.65 493.855]/Subtype/Widget/F 4/P 9 0 R/Q 2/T(C1_3_1)/DA(/Helv 9 Tf 0 g)/FT/Tx/Type/Annot/AA<</F 115 0 R/K 116 0 R>>>> -endobj -28 0 obj -<</Rect[408.021 456.818 487.65 474.719]/Subtype/Widget/F 4/P 9 0 R/Q 2/T(ZRP_1)/DA(/Helv 9 Tf 0 g)/FT/Tx/Type/Annot/AA<</F 113 0 R/K 114 0 R>>>> -endobj -29 0 obj -<</Rect[495.675 475.336 574.687 493.855]/Subtype/Widget/F 4/P 9 0 R/Q 2/T(C1_3_2)/DA(/Helv 9 Tf 0 g)/FT/Tx/Type/Annot/AA<</F 111 0 R/K 112 0 R>>>> -endobj -30 0 obj -<</Rect[495.675 456.818 574.687 474.719]/Subtype/Widget/F 4/P 9 0 R/Q 2/T(ZRP_2)/DA(/Helv 9 Tf 0 g)/FT/Tx/Type/Annot/AA<</F 109 0 R/K 110 0 R>>>> -endobj -31 0 obj -<</Rect[495.675 444.472 574.687 454.966]/Subtype/Widget/F 4/P 9 0 R/Q 2/T(C1_5)/DA(/Helv 9 Tf 0 g)/FT/Tx/Type/Annot/AA<</F 107 0 R/K 108 0 R>>>> -endobj -32 0 obj -<</Rect[495.675 418.547 574.687 433.361]/Subtype/Widget/F 4/P 9 0 R/Q 2/T(ZCP_8_1)/DA(/Helv 9 Tf 0 g)/FT/Tx/Type/Annot/AA<</F 105 0 R/K 106 0 R>>>> -endobj -33 0 obj -<</Rect[495.675 398.794 574.687 408.053]/Subtype/Widget/F 4/P 9 0 R/Q 2/T(C1_6)/DA(/Helv 9 Tf 0 g)/FT/Tx/Type/Annot/AA<</F 103 0 R/K 104 0 R>>>> -endobj -34 0 obj -<</Rect[495.675 373.485 574.687 392.004]/Subtype/Widget/F 4/P 9 0 R/Q 2/T(C1_7)/DA(/Helv 9 Tf 0 g)/FT/Tx/Type/Annot/AA<</F 101 0 R/K 102 0 R>>>> -endobj -35 0 obj -<</Rect[495.058 332.745 574.07 351.88]/Subtype/Widget/F 4/P 9 0 R/Q 2/T(C2_1)/DA(/Helv 9 Tf 0 g)/FT/Tx/Type/Annot/AA<</F 99 0 R/K 100 0 R>>>> -endobj -36 0 obj -<</Rect[495.058 309.288 574.07 327.189]/Subtype/Widget/F 4/P 9 0 R/Q 2/T(C2_2)/DA(/Helv 9 Tf 0 g)/FT/Tx/Type/Annot/AA<</F 97 0 R/K 98 0 R>>>> -endobj -37 0 obj -<</Rect[495.058 285.832 574.07 303.115]/Subtype/Widget/F 4/P 9 0 R/Q 2/T(C2_3)/DA(/Helv 9 Tf 0 g)/FT/Tx/Type/Annot/AA<</F 95 0 R/K 96 0 R>>>> -endobj -38 0 obj -<</Rect[495.058 262.375 574.07 280.893]/Subtype/Widget/F 4/P 9 0 R/Q 2/T(C2_4)/DA(/Helv 9 Tf 0 g)/FT/Tx/Type/Annot/AA<</F 93 0 R/K 94 0 R>>>> -endobj -39 0 obj -<</Rect[494.441 218.548 571.6 232.746]/Subtype/Widget/F 4/P 9 0 R/Q 2/T(ZCP_10)/DA(/Helv 9 Tf 0 g)/FT/Tx/Type/Annot/AA<</F 91 0 R/K 92 0 R>>>> -endobj -40 0 obj -<</Rect[184.566 207.437 220.369 222.869]/Subtype/Widget/F 4/P 9 0 R/Q 2/T(C2_5)/DA(/Helv 9 Tf 0 g)/FT/Tx/Type/Annot/AA<</F 89 0 R/K 90 0 R>>>> -endobj -41 0 obj -<</Rect[219.751 157.437 298.146 175.339]/Subtype/Widget/F 4/P 9 0 R/Q 2/T(ZCP_11)/DA(/Helv 9 Tf 0 g)/FT/Tx/Type/Annot/AA<</F 87 0 R/K 88 0 R>>>> -endobj -42 0 obj -<</Rect[219.751 125.956 298.146 144.475]/Subtype/Widget/F 4/P 9 0 R/Q 2/T(D1_1)/DA(/Helv 9 Tf 0 g)/FT/Tx/Type/Annot/AA<</F 85 0 R/K 86 0 R>>>> -endobj -43 0 obj -<</Rect[219.751 103.117 298.146 122.253]/Subtype/Widget/F 4/P 9 0 R/Q 2/T(ZCP_12)/DA(/Helv 9 Tf 0 g)/FT/Tx/Type/Annot/AA<</F 83 0 R/K 84 0 R>>>> -endobj -44 0 obj -<</Rect[495.675 156.203 575.304 174.721]/Subtype/Widget/F 4/P 9 0 R/Q 2/T(ZCP_13)/DA(/Helv 9 Tf 0 g)/FT/Tx/Type/Annot/AA<</F 81 0 R/K 82 0 R>>>> -endobj -45 0 obj -<</Rect[495.675 125.339 575.304 143.24]/Subtype/Widget/F 4/P 9 0 R/Q 2/T(ZRP_3)/DA(/Helv 9 Tf 0 g)/FT/Tx/Type/Annot/AA<</F 79 0 R/K 80 0 R>>>> -endobj -46 0 obj -<</Rect[495.675 101.882 575.304 121.018]/Subtype/Widget/F 4/P 9 0 R/Q 2/T(D1_2)/DA(/Helv 9 Tf 0 g)/FT/Tx/Type/Annot/AA<</F 77 0 R/K 78 0 R>>>> -endobj -47 0 obj -<</Rect[495.675 80.2776 575.304 98.1787]/Subtype/Widget/F 4/P 9 0 R/Q 2/T(D1_3)/DA(/Helv 9 Tf 0 g)/FT/Tx/Type/Annot/AA<</F 75 0 R/K 76 0 R>>>> -endobj -48 0 obj -<</Rect[466.663 40.7717 572.218 56.2037]/Subtype/Widget/F 4/P 9 0 R/Q 2/T(ZCP_15)/DA(/Helv 9 Tf 0 g)/FT/Tx/Type/Annot/AA<</F 73 0 R/K 74 0 R>>>> -endobj -49 0 obj -<</Rect[552.465 815.457 567.897 825.333]/Subtype/Widget/F 4/P 9 0 R/T(B1_1)/DA(/ZaDb 0 Tf 0 g)/FT/Btn/Type/Annot/MK<</CA(8)>>/AP<</D<</Off 52 0 R/NEANT 53 0 R>>/N<</NEANT 50 0 R>>>>/AS/Off>> -endobj -50 0 obj -<</Subtype/Form/Length 88/Resources<</Font<</ZaDb 51 0 R>>/ProcSet[/PDF/Text]>>/BBox[0 0 15.432 9.87646]>>stream
-q 1 1 13.432 7.8765 re W n 0 g BT
-/ZaDb 6.0449 Tf
-5.6698 2.892 Td
-5.8212 TL
-(8) Tj
-ET
- Q
-endstream -endobj -51 0 obj -<</Subtype/Type1/Name/ZaDb/BaseFont/ZapfDingbats/Type/Font>> -endobj -52 0 obj -<</Subtype/Form/Length 30/Resources<</ProcSet[/PDF]>>/BBox[0 0 15.432 9.87646]>>stream
-0.749 g 0 0 15.432 9.8765 re f
-endstream -endobj -53 0 obj -<</Subtype/Form/Length 111/Filter/FlateDecode/Resources<</Font<</ZaDb 51 0 R>>/ProcSet[/PDF/Text]>>/BBox[0 0 15.432 9.87646]>>stream
-H‰2Ð37±THW0BCS=c#K= s3S…¢T…4…BC4K˜Ã%Âò€êÓœB¸ô£]’Ìô L€æ„¤q™ê™™YZ(éYX)„¤ùF†@–—†…¦BH—k—B @€ê'R
-endstream -endobj -54 0 obj -<</Subtype/Type1/BaseFont/Helvetica-Bold/Encoding/WinAnsiEncoding/Type/Font>> -endobj -55 0 obj -<</Subtype/Type1/FontDescriptor 153 0 R/LastChar 233/Widths[278 333 278 556 556 889 667 222 333 333 389 660 278 333 278 278 556 556 556 556 556 556 556 556 556 556 278 278 660 660 660 500 800 667 667 722 722 611 556 778 722 278 500 667 556 833 722 778 611 778 667 611 556 722 611 889 611 611 611 333 278 333 660 500 333 556 611 556 611 556 278 611 556 222 222 500 222 833 556 556 611 611 333 500 278 556 500 722 500 500 500 333 222 333 660 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 222 0 0 0 500 0 0 0 0 0 0 0 0 0 278 0 556 556 0 0 0 0 0 800 0 0 0 333 0 0 0 660 0 0 0 556 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 556 0 0 0 0 0 0 0 0 556]/BaseFont/GENEJE+Helvetica-Light/FirstChar 32/Encoding/WinAnsiEncoding/Type/Font>> -endobj -56 0 obj -<</Subtype/Type1/BaseFont/Helvetica/Encoding/WinAnsiEncoding/Type/Font>> -endobj -57 0 obj -[/Separation/PANTONE#20Reflex#20Blue#20CV 59 0 R 148 0 R] -endobj -58 0 obj -[/Separation/PANTONE#20Warm#20Red#20CV 59 0 R 149 0 R] -endobj -59 0 obj -[/ICCBased 147 0 R] -endobj -60 0 obj -<</Length 1084/Filter/FlateDecode>>stream
-H‰œVÉn#7½÷Wð u‡ÅGY¶åX=Y`#ËÞecæóóŠ½h±¬É $ ·ªb½WÅz*úAF+¢ÓÒ OJ:+úÑi¢x^¿‰ûâ©PR-É…KN* -›ú±³!¡ð#aB’†’R0òÖJE>¥hÄü®ø0œ*1œÂHL‡gˆª“ŸEñáG¼ÿ´*8À]A)HK¿°‰ùJÀ\ˆÕü¾3·È2+B´2&-t”Z#{RŽ!!³›zÉMg£}çDVQه@´hƒPt҄À&†"Lx [Q¼52„u|~^Ç¡ ¬—0n¼•ÖºÁ6ü¶uIj,ÞÂN$µ‹M`¼îV‡ -y‡)˜&Á%ޝPÝl¢ƒÖ29ýö´‰ymî‚èC &6 SmJQ†DTÕÔÂ9T5W‡dhh<ªxÍ+PþÕå­è/RuÃ
-±*‰j.’ŒY_|Íú BÅÑGQÝåà´Wý Á6Jc²q¾±´cœ֗åä¬ê[péãsy<šÖ7“ó™!ºð×j<9k^_ðÛÁÉxÊWØþYý\ŒªŽ sSs íïƌ­Co0i=v‹w Þ7˜Äñû E›æ—%ç>œœžW£t}=Ô×ê×ÌIý03JÕwçõÛ¤Ë?F‡‘SòyÏ|ò}x)¢=µx‡Œv¨á† [v¹XÇãŠÍ7ƒò’ۖuµ'*$¦ª°ixY~ ¦Ed¤Û,m'Þ½ËÉa x Ü®Ð|t“ñ„3î·Bù¼[{Â~Æ&ßt¹,we-Ƨç“éàèd4³ò'Yõˆ¨”³^†£8ì6u ¾-ƒ"¢I|5“³ÉÙF6-»4zç¤3ß@£Ú“Qæ·^:Õ&ÔÉ^[*.>b{p›ð-’ðAÅ-Ïòè­r¬F{·qg…«ÕBüóð¼/=Ë«/‹^ßZÊ܃ð(®_ïá6h&ÖÓÿǽ²A'°ÆÐÈÇy»|Vcð õIöQsÔ¬O~‹ƒÛÖ÷h…¬N~wèä¯OüÀSB>ïûŠáSÒHçòRÅؽ¨'‚mØTÃî¯'zçŒ¤u‘ê'4DƒóB ††ñýõòéuñ,–ó¥¸]ˆÇ‡×çÅr¾¸¹ú„²à?3Ž®_ç/ˇûzkà”å“üT×\ÛÇÇÛåüêïÆ]Ü^‰Göy^>À}5ÓZ/oÅbõ"®—7ü&å;¬²'d 7B“ùÕÅu§ç¹Èó–o4ŠãÃRP)§,ËìØ6¤=¤S„‚, L/žë†fÇÓKàCƒ«:}S~žtÈl C˜c|gBi&‹ÖG#WÔ¡µ4zW4ÙÖB5ζŠ[4Dƒ’¥µHT ÖÀn„”’Ià -i¥ä³ìš’ð2ùn |*Ä ùá][
-endstream -endobj -61 0 obj -<</Subtype/Type1/BaseFont/Times-Roman/Encoding/WinAnsiEncoding/Type/Font>> -endobj -62 0 obj -<</Length 1013/Filter/FlateDecode>>stream
-H‰¼–MoÛ8†ïòæ(-b–Ã/Q{ë&Á‹½,bô²^Œ¬4,dÉÑGRì¯ß!%ײ¢mZ¬}1IÍ;/GFàôEh˜5çJZÍP
-Î¥…b»àLåð ‹ð `i“ªÅíâ¯Åã'•&µÈscAÍòÜrŽö‘šiQd¦X.pFùheÆey&Œ9“\ç¤R04Šdõ¹1RfJè$ðÛjñæê–CёtE½x³Â÷‚«{
-å3XÁƒ”9¬žÁ0#”Ii'Yț™<¡X&r«í"ù³ì`ã»]ÓùÞ75 -hµ½/*ú!Õ%H -eÒÐ
-TªÆC®>’ɐ,ä‘,Ïì˜G2+ÈQ–3ŠÁ0­ÆLM ú›V1Ž¹™ûü;Éì’7øèê'_¶´ŸÌ¶Ùø{¿–KhËÊõþ©„µTDm-„ðõ}Óniöq(/Á -ŸÖpï‹Šï¾h*W¶}è  An·«B@ݧK)Uò+”UÀñÁµ®î}×ÑÊ%욡M—*ZJÿYý1#² Ös Kdœö¸!ÿ›¦®£Ëžš¡ƒ¢©‹²­]Prî¥5ޅý$ޖñüv·–Fõ)ª¤»„¡†MÛø6ÑdQŒ1´‹ÃJ€PôD¤pá<ÙhŒ¨gùH -!&‹|oîšÌÝúÑTp®ò]ùo4ÐìÂDëÆÒðdÌÍv;Ônˆ¦œoK2¶+ë1Rwd‚ŠÊq£Û8õàê¡ÞJ¸ó2t”x}Q´$5‹íš&‹T&Qç÷ Q†ªÐu3¸ºŒâ00HQ'§ç±ú…6éëMiÂ:)îÔ -Uz9e;ñ}õV®ÓàÍêøú
-ºG¹°`¹e
-©±óbcÉ2CÀÏ€äH÷Âp®dÔeŒÆ(%2«Ž4)ݬНÇÏwž:GØdÆlF%ÄL?Ò¥4$oî”ž.Çt‰Bêä]ªuB…O¯MÑ&e×»}€®lŸˆË„‘Ñù©†Zª¡òPÑ Û½®ägW´›ð85A‘«èjú‰–Z5Ô#[¥ü¬/棽­9,l-÷ܞ_à&¹bôê8§&p7Ÿv -Ýz¶ÇõÐP'¹º9AËOyÍüE'2<o™±fz’¦Äw@U¹`–ÌýL¨/ÁûZ¥ÉŒÚµ601{;ôS}v“-½tÜ]õR•áy•½®ÌfžþÇ2û©Cm£Ò_CUS7ú2.ÒÒfŽë¸²$C‹‡Ê’¯ª¬ŸÇñ5•E-¥Á —Üã*¿ÿÛrün¢÷Òòœ•ÑǕu K,q€…ßK„ƒôwon÷G‹îUÕ5Ëÿ 0}+žE
-endstream -endobj -63 0 obj -<</Length 1006/Filter/FlateDecode>>stream
-H‰¼VKÛ6¾ è˜K¨¸äðÝ[ºIE¢‰Ë:(T[›(Ðc#Éi~‡åµ¼v‹E}1% -g†ßÌ÷qîRn6™@©ÓŸ«¯}Q -];@Վ}±ëšæЇ±¨úpi9l>ä?%œ!¢‚|Â0«5pÈ÷IÊæß&ÿLœs,£½RáëM.~“ ¿†ÂûÙУWdɗ¥òȼ …‚ ihCsŒòÜß_ãs.B|˜õ8ŏKř²Ü€ñžI!ä~›î»v„¯e;–l¥â°¯†±hw%”ãMw€îa+µè‹±"'0 L‡(¯“»t_BCŠ%|¿ÉÐjÔ)·±¯vŸŠq€²…ûž\~ª†ò q¥˜E¹Füìxà{fœ}ß>|òÀ”3æ¥Àϼ`ÆjȐÉüâ1ž÷Û~ó/s`Äàr텓LjEÅ·š#ì\üMØý&O¾$b²¦.rŽ彗¬SÌy͹’°k’`ÐLÕ§þõh NÐ1$_Y(‘¤Ës°e­“wɯW¼+™°T0+½  ½£õùVe$s©lLÌRL\'Æ -ãN/‰ù91½$情fNé+Þ©€>@ä× ×y9úö4/ɉ Òët̋ŽäfÀ½€?à9ËLtqsûŽ>q`صɜƒ©5ÓÄÊY6™çÌ+}™Ü'?äaûļë„üيýj©?yÂðºÀP¯
-¡øw)êÀR¥ÒÛ>0|_@dÎßo¬J_Á6­«m ”ÈC±§'a¨gŽ ÆI3íeÍ<É&ˆ¦_xk¹~Ê[Œ¬]( ÔF¤‘N¬r~a±üg¼¤cÜñ2¯·eó{w臲!Õ$̚¢Ý#0qòI‚ MÐJnd8ú]:z¸ïzrãÒæP/·´óÎËá
-+O -ã=%,‰sžÏ¼í¢,Æ@ëäGb8 œ@Ϭ‰:OéyøÜÑ58ï]ªGXuA~Ï*h(‹hå™ÿTÀÓ4þïrKä´>Ð>iø雫ð 3–ýcóëÓæÇUóOa…g¸jþ3ܨî8yÜEԜѫÌ_äB¹!™ R.ˆùA‘¤!Í'Ô|× Þ6½-DZ„f( -†«ØE¬pAʺÀÉÝÌ’˜º€‡i_GãAEÆ{vu1ä7ù‰$A'=`áZ ²N•9ͨJ£|};ž´Êq*’’î.æÓþr:ôÀÔ.E] -῜æ™ûiDj›±ïºº7èÒpž)ýËXgGQÐ3ÜŞÌ7ti¦ÅáOh…(jê¯ïL˜ª\úí¹ì’ u}pz^ƒÀ_ áªsc
-endstream -endobj -64 0 obj -<</Length 524/Filter/FlateDecode>>stream
-H‰ÌUM›0½Gê˜K%[
-îøslµê¡RµnKµ¢ +Q%Pûó;$ÐMVÝTé
-.Xf0oޛ÷ˆP ¢„tڈ˜VézÁP¡ãéÅ‡T>j çO ªT¡Îˆ„Šðp7‹Ø[ NI¡U8h»`âFWöî_<"—=òhl2ÞÐJ…
-já|þa<Jœc)—R²¼ûM¦­\we viá=ÿ–~!>]áP‰Â50w›ÖCØڒ6Ç/ D{•6“îf§ÍÈ"µ«Œ±þ|®–=Xïš^£„+c|"¡ŒþoMt¾@3¹1·iÀŸÏ¿Aabt`‡ ¹ß…aoò¶¬«}?ùù¦Ü‡{±‡uN›ZÜÝ}Ùf‘"ÉDRØ0²L"$É;ñTU7´çÙ6߀_Z©Ø³3kI¢SßÒZçÎR£³(Á®q–µN83Sgý5õ¬N†Šà()ÏSO-å R¯ÒfÒÝì´Y|Ašyn†S)SA´ou—¹=Á›³¯H9úÆê8ïÆ\¹ÝÕûü{¶L„®‚¼k›Z®|0C?üC¢ÝÑûûÜäÕª€m8§mê]½)ûê²* îBBfüÄëkBRüX­Ê¢‚öôÝÓ¸xŠCySÏ -Ô?·ž§X<æ.&×YÏx<WëMš„ß ýZ5r
-endstream -endobj -65 0 obj -<</Subtype/Type1/FontDescriptor 155 0 R/LastChar 1/Widths[834]/BaseFont/GEOAOI+EuropeanPi-Two/FirstChar 1/Encoding 156 0 R/Type/Font>> -endobj -66 0 obj -<</Length 875/Filter/FlateDecode>>stream
-H‰¼–KoÜ6Çïúæ(–á›Çí¥@Qrñ…²+*´ZGÄ?CIkiœ xE‘Cþç7Ã!ðÿ\|‘R ¢m¥0òCr—’Î6$µNÿ~Ø*CmÑWǦƒêðp슏uÙÁVi„¡¾á¡hy¼Oûj7ÔUÙÂ6ÝG»ÝñðЗPÞgÜy_îú!~…nh¡hšò±¥áÍ6Ë>ä&($?ï@£@5æû$˓åÿ%Œz)³‚Â<ƒÁØûkNÿ(àÞ{ž§ÉD½¿pž5,Þ®çÕ³ýå -OºiÒ½rÐݎ”fWä)3G*Ÿ9¾a°ý²ªڈ½<”Mc8öCÅÑ#7u}.Û®l/ØS^™kö¯es;å„ħèYDxIƒÎ»‚ðJ‘7éËkú
-µ:â—$ô¸0ٓ1Ί§¬ô•-†7Ghû4Á:ö™ôiQþ„º€9‚ÙFjJ?¶Çj?p¼Òºú·á-‡~Š™y¿¬Tá»Ö¬Á;³Ò¼8ü"Ê+»Ÿ
-YNCS%rv·9£t³)'ìæµé]úû‘Óÿ íX~vŸ†ª«æ²ÖômÁµê04Å0ŤjËî’ñ³ûRÛÀøM8È¢¾/§Ïì6pç…ôn ·N©[¸GÃoã>ž#cïË®¯šñKÌÿ¿Ž -‡à/²¸ÿ^à‹õëqÿ‘'Ÿ!ž9²šÅ°š—³:„ awHâ€øŸOLÍL¡NÞ%oW¦:p7.ðÆMFØ`ؔS6³.˜:ÙHv@jØhÇßÜÔɝګIµŒ˜Û«dPðZːӇ+…Vñ!¹Êq…0쨲!¨sç v½ŽüQñT¨„ñ±knö]^O­„‘‘}WÄÞÅ´ó¹­á ,+X-ø¸ž!’—ŠÉÓHÞ³¶`Vø(87Φ¿å/J¹§B–„%3ÀҟÀœôΧMٟ—o¶‚­d^SKê«;yö̝çù,­rgÒþòM,Ê ¾…°„–ŒˆÒâ‘°¢ëªCUÇRÀ­]Qómqnp‘qH.-–³C U#ˆùžØD98ùíPϞÇ7e˜€á­B1]çMôýxqÛ¸ÐÌ9ë y É/–T´¯ ¾6aÇ
-endstream -endobj -67 0 obj -<</Length 830/Filter/FlateDecode>>stream
-H‰Ì–KoÛ8€ïúx”°5Ëáð!S —Ø­°—¨(› -èáJr»Ý_¿CÊr»-œ.ÊCBœ×7ú6E‘­¤Íӛì}ñ6\ÒbŚ!—V2ÁŠM’òo¬¬xHV‚ ! \Á[î;g]8UÀdtþ‘‹¨VqG—Dü¯œnHÇ­dEûmc—¯Å,Ìf£‡Ú˖ç*šŽŠKE>hž[ÐÁömŠÙJ§D¤黾mýÈJT‚Õív7ù!s2}Éü¿Û¡nKÔ@Ǿc~7d§ýø2B”µa+àÂ`äñ•­û–DFV…Íäé»»òcð÷:H®\~Ný¶áà¨óËQ;Ey²\£µWB=û÷ÔäƒQÖíIC ¬ÔÊÕCÿ›RvÏ¢œkŽ ®ÅXΌ…ÿ²ÊÉq¥8èÙ4ÊE\ì}ž¤ãºM‹Ìª´Ÿ2™§U3ç`?¾ú•iSßw_æì&‹Üƒ>5ëäJ/ŒJÂvb8À2P„2; )¦å¼h”6<ãyÄ!9ØçŠz؈ TjÔe(%· CE*Õ\weúgIûÝ]Sûÿ(ZPi5²g}ÝmÏϪqßøÖwUÑ0øqÛw›ª›ÈÿáM‘|J ºKȍåÎW$•ÏPW"[·I8Wä_Κä]òבœ¶À4¡…Ÿ%쫝S.à@r¨å€jl Ñ$+0š äL"XOsÚ-ß³î×ÅEL<cù!ZnÑâLܾ“_×¾CӍS=íQir¶ý]ÝÔc5Õttò̀ã¨~ôÎüÌ*_œ5sðX,v„xa; ë̓xÑÐ< ž° –búf7ÅaH|ï"u?±ÑŸëµ?#ŒÑ]ðiXG±(*.¡iËgÑ>
-ùjãsñõËw¸K~иÃ)wVüFçÍ<37á•Ùìêùì$"X ñŒWÎ?O„æÚÊ^èK_±˜ˆc¿¸ì%8°ürÿo¿íÚç)͖[‘{=±j»­†ªÇ0uâ«Å董¡ÞTlo­ãUšç~ÎÖº!©._ô]öžý/ÀËûh´
-endstream -endobj -68 0 obj -<</Subtype/TrueType/FontDescriptor 151 0 R/LastChar 122/Widths[278 0 0 0 0 0 0 0 0 0 0 0 278 333 278 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 722 0 722 722 667 611 778 0 278 0 0 0 0 722 778 0 0 722 667 0 722 0 0 0 0 0 0 0 0 0 0 0 556 0 556 0 556 333 611 0 278 0 0 278 889 611 611 611 0 389 556 333 611 0 0 0 556 500]/BaseFont/Arial-BoldItalicMT/FirstChar 32/Encoding/WinAnsiEncoding/Type/Font>> -endobj -69 0 obj -<</Subtype/Type1/FontDescriptor 158 0 R/LastChar 2/Widths[500 790]/BaseFont/LEKOLE+Symbol/FirstChar 1/ToUnicode 159 0 R/Encoding 160 0 R/Type/Font>> -endobj -70 0 obj -[/Separation/All 59 0 R 150 0 R] -endobj -71 0 obj -<</Length 1194/Filter/FlateDecode>>stream
-H‰äUɎÛF¼È?t¨Àj÷¾'ãÀ€á80ÄäBõ8 (jLŠãA¾>õšÔ2Ÿ#Ød÷[«^uõ®\áǪšiÅc”L°j[”ü«~‹êïb)¸B’'e¸°zöð‘ö_WòÍ°ƒ˜"G4<âÈO5>:¦œçÒ{ͪÝצñ\ZVNa§ sdσɡóB©iC)Á¥žC+MæÚq)ã\Š2Gb.$W˕öӉßÊjáM¹?,T(7-«~¥×«ÅRYn×ÚÊíXš?ÛÄÖeÛ|êÒÀà}­@ðõbñ{õî2ã38ÒsÃ#p(›«âs!s-MtÜtܹ\Œ³.FïY½+èÀ®ðh5åÚ«âㅡ¡´^!!ǝñBhE†¯¯WŠ]¯˜Ì¶ºþ€´<ºö…ÍN[JÉ­´³Ûª=Ø>P -h®†U_µßnLÐÌ9®%Ý¡‘W‡Cê;[,­+¿e¿t‰ -ÍaÜÐ7¶MçÞ¶¬ûÜÜæÐ7õ©·LY6¤þ®IëëRn.QŸs6ÄQ$Césá°~ƒ¸Ûf¸MݐØmÆp`Ûq^6i‡Œz`¾÷Xm†¡Ù5-EÇ[†¸n7ýü>§yŽý*Î*¢¶Ý3h¾;#…¬Tð<¢/Á2Nó uŒ˜,( 7:<°•Vñ`J¤W‘-1Ý"ZlJ‰çO_žÅ,7è)ɝsæ—Óà‰BÚÊX›§e]®ÁVï»»Ôšž¥Ž¥±ß’@, -Ú¼é7]=€òà°3¢ÊÕEH>‚¶ž ¶}3!V -»ÛëÖ‰Í]úg›>ín[Äیõˆ^O=ófßïÆvÓôĈ34ßLZ+«K©cÙÑÖЮ•×ëÅ+v—Ʀm¡Þ×¥¾@FVo†tÄŒ4Öj®0—9o2öhû2Br+dä4GAy®P‰µŽGm<-X]"+<×ÁÄh,sÄ
-í±6YÄy4s4ì O[Ãh¦6¶¦·Ì«žNº˜²˜õÎØò`‰bž†Ñs#å j5dµ‡Ì„ÙÇi@‹ Ïù°ÄEהèÊÖ/ø0àŸ’³’dõ€zcCÝÆq°Åh$%h"ÏKä(n2µ¯W‚LädpÁôÀÃD¼¼ÀÐHeƒBrÏÌ{¿™i%֖RB<¯SÅçœÃ¤¿ùù§iȳšá,&ïI!ÆCÇþ–XÖgî -H¬MwD9¨Ë$&ã}6¯¾' -‚f¼’¸5|(¿£X‡¦³ö÷áGÁå±9ÛcÏÚ<&]—îÓZŠéºzF‰¬wÜ+¨ œÀœTé¡yœ‘nàã -§ ‡(<iÅÌXÉÞJK@¾~‹þ.¤MOÜ\â~E¨ù±+–'b~o 0e6šV'C‡ÁÒ†6ZÒ¦“!bDªÅMñ†Ykû"àô~ x¶ßOöǸGûcÜ£ýê¿õ„ÔÓ¥:_¨êÝ'è.‚PÜn:œDéEυÉâtÎûøõ¢…{÷<$$ð|ÿ¿8hpÄö¯ižtH
-endstream -endobj -72 0 obj -<</Length 638/Filter/FlateDecode>>stream
-H‰ìT»n1 ìõ,by”¨g'0Üv4Rœ/‚»âðï‡Z=¯Mw"9%ŠÌ ]€ÅêˆÉÁEqsx‡)ÁYFg@k ^ÂÅZŠÙ‚K Œ:ŽpLƒ„&‹& ›5hƒ C螳b0ê ÂN#ó„(¤”éZ9œËaa4փ‘ZÞÃâ0F¨öóQBl5u@ߓŠA‚)§JUðS#*5J ×®ø¢çØûŽ“mB›yîf”[‚c"ŒúíÖ]UvKîæNÝ䋭ы£'‡„ä;w±z=\uÕÜYôQž*t|ûx½›žfò8 Z˜MLh¢Ížˆ,‘Á²Û;¯`e|&HD«g’îØëì9Õ#ãiŒ…‰„=º4Õ)vÎéR¤‰í$·ýÇô÷aIvîx8ŠV–@Ô£™ÁPÛe)ÎÆN–ÛžºÝ5TGU9J½BktH¨€&±ÜöpT«úª~+-“K ÁÈçMšˆ8@ôŒål…ø¢÷+Ãý* Xï¿(™-o +ÁóEû§´©üJš~@ñŽ/0Þ§mšái«†ß—Ñû2z_Fÿó2ÒhØzb)Ièu0ÉrÞD‹†('—¤V´^Nê\%‘ÄoòªqIF%OS1+ ñ.ƒø†÷ã&[M³‡ç¾Õ›þá$eû©DCH°…"
-sfÒH‘‚ÌlŠ2½ÛEÝ}'2¶_•é!ïI›÷$åT!z9lnGØބUÒY˜+È80Õ
-°Óï`éƒó吰=©»Çëëéåzz…>=<fÜçM®4_ê¿^ÚèãfÝ[Ô2
-‘%Eþ¤üY¹V'3«s޺ׄ¿ zF
-endstream -endobj -73 0 obj -<</S/JavaScript/JS(AFNumber_Format\(0, 3, 2, 0, "", true\);)>> -endobj -74 0 obj -<</S/JavaScript/JS(AFNumber_Keystroke\(0, 3, 2, 0, "", true\);)>> -endobj -75 0 obj -<</S/JavaScript/JS(AFNumber_Format\(0, 3, 0, 0, "", true\);)>> -endobj -76 0 obj -<</S/JavaScript/JS(AFNumber_Keystroke\(0, 3, 0, 0, "", true\);)>> -endobj -77 0 obj -<</S/JavaScript/JS(AFNumber_Format\(0, 3, 0, 0, "", true\);)>> -endobj -78 0 obj -<</S/JavaScript/JS(AFNumber_Keystroke\(0, 3, 0, 0, "", true\);)>> -endobj -79 0 obj -<</S/JavaScript/JS(AFNumber_Format\(0, 3, 0, 0, "", true\);)>> -endobj -80 0 obj -<</S/JavaScript/JS(AFNumber_Keystroke\(0, 3, 0, 0, "", true\);)>> -endobj -81 0 obj -<</S/JavaScript/JS(AFNumber_Format\(0, 3, 2, 0, "", true\);)>> -endobj -82 0 obj -<</S/JavaScript/JS(AFNumber_Keystroke\(0, 3, 2, 0, "", true\);)>> -endobj -83 0 obj -<</S/JavaScript/JS(AFNumber_Format\(0, 3, 2, 0, "", true\);)>> -endobj -84 0 obj -<</S/JavaScript/JS(AFNumber_Keystroke\(0, 3, 2, 0, "", true\);)>> -endobj -85 0 obj -<</S/JavaScript/JS(AFNumber_Format\(0, 3, 0, 0, "", true\);)>> -endobj -86 0 obj -<</S/JavaScript/JS(AFNumber_Keystroke\(0, 3, 0, 0, "", true\);)>> -endobj -87 0 obj -<</S/JavaScript/JS(AFNumber_Format\(0, 3, 2, 0, "", true\);)>> -endobj -88 0 obj -<</S/JavaScript/JS(AFNumber_Keystroke\(0, 3, 2, 0, "", true\);)>> -endobj -89 0 obj -<</S/JavaScript/JS(AFNumber_Format\(1, 3, 0, 0, "", true\);)>> -endobj -90 0 obj -<</S/JavaScript/JS(AFNumber_Keystroke\(1, 3, 0, 0, "", true\);)>> -endobj -91 0 obj -<</S/JavaScript/JS(AFNumber_Format\(0, 3, 0, 0, "", true\);)>> -endobj -92 0 obj -<</S/JavaScript/JS(AFNumber_Keystroke\(0, 3, 0, 0, "", true\);)>> -endobj -93 0 obj -<</S/JavaScript/JS(AFNumber_Format\(0, 3, 0, 0, "", true\);)>> -endobj -94 0 obj -<</S/JavaScript/JS(AFNumber_Keystroke\(0, 3, 0, 0, "", true\);)>> -endobj -95 0 obj -<</S/JavaScript/JS(AFNumber_Format\(0, 3, 0, 0, "", true\);)>> -endobj -96 0 obj -<</S/JavaScript/JS(AFNumber_Keystroke\(0, 3, 0, 0, "", true\);)>> -endobj -97 0 obj -<</S/JavaScript/JS(AFNumber_Format\(0, 3, 0, 0, "", true\);)>> -endobj -98 0 obj -<</S/JavaScript/JS(AFNumber_Keystroke\(0, 3, 0, 0, "", true\);)>> -endobj -99 0 obj -<</S/JavaScript/JS(AFNumber_Format\(0, 3, 0, 0, "", true\);)>> -endobj -100 0 obj -<</S/JavaScript/JS(AFNumber_Keystroke\(0, 3, 0, 0, "", true\);)>> -endobj -101 0 obj -<</S/JavaScript/JS(AFNumber_Format\(0, 3, 0, 0, "", true\);)>> -endobj -102 0 obj -<</S/JavaScript/JS(AFNumber_Keystroke\(0, 3, 0, 0, "", true\);)>> -endobj -103 0 obj -<</S/JavaScript/JS(AFNumber_Format\(0, 3, 0, 0, "", true\);)>> -endobj -104 0 obj -<</S/JavaScript/JS(AFNumber_Keystroke\(0, 3, 0, 0, "", true\);)>> -endobj -105 0 obj -<</S/JavaScript/JS(AFNumber_Format\(0, 3, 2, 0, "", true\);)>> -endobj -106 0 obj -<</S/JavaScript/JS(AFNumber_Keystroke\(0, 3, 2, 0, "", true\);)>> -endobj -107 0 obj -<</S/JavaScript/JS(AFNumber_Format\(0, 3, 0, 0, "", true\);)>> -endobj -108 0 obj -<</S/JavaScript/JS(AFNumber_Keystroke\(0, 3, 0, 0, "", true\);)>> -endobj -109 0 obj -<</S/JavaScript/JS(AFNumber_Format\(0, 3, 0, 0, "", true\);)>> -endobj -110 0 obj -<</S/JavaScript/JS(AFNumber_Keystroke\(0, 3, 0, 0, "", true\);)>> -endobj -111 0 obj -<</S/JavaScript/JS(AFNumber_Format\(0, 3, 0, 0, "", true\);)>> -endobj -112 0 obj -<</S/JavaScript/JS(AFNumber_Keystroke\(0, 3, 0, 0, "", true\);)>> -endobj -113 0 obj -<</S/JavaScript/JS(AFNumber_Format\(0, 3, 0, 0, "", true\);)>> -endobj -114 0 obj -<</S/JavaScript/JS(AFNumber_Keystroke\(0, 3, 0, 0, "", true\);)>> -endobj -115 0 obj -<</S/JavaScript/JS(AFNumber_Format\(0, 3, 0, 0, "", true\);)>> -endobj -116 0 obj -<</S/JavaScript/JS(AFNumber_Keystroke\(0, 3, 0, 0, "", true\);)>> -endobj -117 0 obj -<</S/JavaScript/JS(AFNumber_Format\(0, 3, 0, 0, "", true\);)>> -endobj -118 0 obj -<</S/JavaScript/JS(AFNumber_Keystroke\(0, 3, 0, 0, "", true\);)>> -endobj -119 0 obj -<</S/JavaScript/JS(AFNumber_Format\(0, 3, 0, 0, "", true\);)>> -endobj -120 0 obj -<</S/JavaScript/JS(AFNumber_Keystroke\(0, 3, 0, 0, "", true\);)>> -endobj -121 0 obj -<</S/JavaScript/JS(AFNumber_Format\(0, 3, 0, 0, "", true\);)>> -endobj -122 0 obj -<</S/JavaScript/JS(AFNumber_Keystroke\(0, 3, 0, 0, "", true\);)>> -endobj -123 0 obj -<</S/JavaScript/JS(AFNumber_Format\(0, 3, 0, 0, "", true\);)>> -endobj -124 0 obj -<</S/JavaScript/JS(AFNumber_Keystroke\(0, 3, 0, 0, "", true\);)>> -endobj -125 0 obj -<</S/JavaScript/JS(AFNumber_Format\(0, 3, 0, 0, "", true\);)>> -endobj -126 0 obj -<</S/JavaScript/JS(AFNumber_Keystroke\(0, 3, 0, 0, "", true\);)>> -endobj -127 0 obj -<</S/JavaScript/JS(AFNumber_Format\(0, 3, 0, 0, "", true\);)>> -endobj -128 0 obj -<</S/JavaScript/JS(AFNumber_Keystroke\(0, 3, 0, 0, "", true\);)>> -endobj -129 0 obj -<</S/JavaScript/JS(AFNumber_Format\(0, 3, 0, 0, "", true\);)>> -endobj -130 0 obj -<</S/JavaScript/JS(AFNumber_Keystroke\(0, 3, 0, 0, "", true\);)>> -endobj -131 0 obj -<</S/JavaScript/JS(AFNumber_Format\(0, 3, 0, 0, "", true\);)>> -endobj -132 0 obj -<</S/JavaScript/JS(AFNumber_Keystroke\(0, 3, 0, 0, "", true\);)>> -endobj -133 0 obj -<</S/JavaScript/JS(AFNumber_Format\(0, 3, 0, 0, "", true\);)>> -endobj -134 0 obj -<</S/JavaScript/JS(AFNumber_Keystroke\(0, 3, 0, 0, "", true\);)>> -endobj -135 0 obj -<</S/JavaScript/JS(AFNumber_Format\(0, 3, 0, 0, "", true\);)>> -endobj -136 0 obj -<</S/JavaScript/JS(AFNumber_Keystroke\(0, 3, 0, 0, "", true\);)>> -endobj -137 0 obj -<</S/JavaScript/JS(AFNumber_Format\(0, 3, 0, 0, "", true\);)>> -endobj -138 0 obj -<</S/JavaScript/JS(AFNumber_Keystroke\(0, 3, 0, 0, "", true\);)>> -endobj -139 0 obj -<</S/JavaScript/JS(AFNumber_Format\(0, 3, 0, 0, "", true\);)>> -endobj -140 0 obj -<</S/JavaScript/JS(AFNumber_Keystroke\(0, 3, 0, 0, "", true\);)>> -endobj -141 0 obj -<</S/JavaScript/JS(AFNumber_Format\(0, 3, 0, 0, "", true\);)>> -endobj -142 0 obj -<</S/JavaScript/JS(AFNumber_Keystroke\(0, 3, 0, 0, "", true\);)>> -endobj -143 0 obj -<</S/JavaScript/JS(AFNumber_Format\(0, 3, 0, 0, "", true\);)>> -endobj -144 0 obj -<</S/JavaScript/JS(AFNumber_Keystroke\(0, 3, 0, 0, "", true\);)>> -endobj -145 0 obj -<</S/JavaScript/JS(AFNumber_Format\(0, 3, 0, 0, "", true\);)>> -endobj -146 0 obj -<</S/JavaScript/JS(AFNumber_Keystroke\(0, 3, 0, 0, "", true\);)>> -endobj -147 0 obj -<</Length 2575/Filter/FlateDecode/N 3/Alternate/DeviceRGB>>stream
-H‰œ–yTSwÇoɞ•°Ãc -[€°5la‘QIBHØADED„ª•2ÖmtFOE.®c­Ö}êÒõ0êè8´׎8GNg¦Óïï÷9÷wïïÝß½÷ó '¥ªµÕ0 Ö ÏJŒÅb¤ 
- 2y­.-;!à’ÆK°ZÜ ü‹ž^i½"LÊÀ0ðÿ‰-×é -@8(”µrœ;q®ª7èLöœy¥•&†Qëñq¶4±jž½ç|æ9ÚÄ
-V³)gB£0ñiœWו8#©8wÕ©•õ8_Å٥ʨQãüÜ«QÊj@é&»A)/ÇÙgº>'K‚óÈtÕ;\ú” -Ó¥$ÕºF½ZUnÀÜå˜(4TŒ%)뫔ƒ0C&¯”阤Z£“i˜¿óœ8¦Úbx‘ƒE¡ÁÁBÑ;…ú¯›¿P¦ÞÎӓ̹žAü om?çW=
-€x¯Íú·¶Ò-Œ¯Àòæ[›Ëû0ñ¾¾øÎ}ø¦y)7ta¾¾õõõ>j¥ÜÇTÐ7úŸ¿@ï¼ÏÇtܛò`qÊ2™±Ê€™ê&¯®ª6ê±ZL®Ä„?â_øóyxg)˔z¥ÈçL­UáíÖ*ÔuµSkÿSeØO4?׸¸c¯¯Ø°.òò· åÒR´ -߁Þô-•’2ð5ßáÞüÜÏ ú÷Sá>Ó£V­š‹“då`r£¾n~ÏôY &à+`œ;ÂA4ˆÉ 䀰ÈA9Ð=¨- t°lÃ`;»Á~pŒƒÁ ðGp| ®[`Lƒ‡`<¯ "A ˆ YA+äùCb(Š‡R¡,¨*T2B-Ð
-¨ꇆ¡Ðnè÷ÐQètº}MA ï —0Óal»Á¾°ŽSàx ¬‚kà&¸^Á£ð>ø0|>_ƒ'á‡ð,ÂG!"F$H:Rˆ”!z¤éF‘Qd?r 9‹\A&‘GÈ ”ˆrQ ¢áhš‹ÊÑ´íE‡Ñ]èaô4zBgÐ×Á–àE#H ‹*B=¡‹0HØIøˆp†p0MxJ$ùD1„˜D, V›‰½Ä­ÄÄãÄKÄ»ÄY‰dEò"EÒI2’ÔEÚBÚGúŒt™4MzN¦‘Èþär!YKî ’÷?%_&ß#¿¢°(®”0J:EAi¤ôQÆ(Ç()ӔWT6U@ æP+¨íÔ!ê~êêmêæD ¥eÒÔ´å´!ÚïhŸÓ¦h/èº']B/¢éëèҏӿ¢?a0nŒhF!ÃÀXÇØÍ8Åøšñ܌kæc&5S˜µ™˜6»lö˜Iaº2c˜K™MÌAæ!æEæ#…僰d¬VÖë(ëk–Íe‹Øél -»—½‡}Ž}ŸCâ¸qâ9
-N'çÎ)Î].ÂuæJ¸rî
-î÷ wšGä xR^¯‡÷[ÞoƜchžgÞ`>bþ‰ù$á»ñ¥ü*~ÿ ÿ:ÿ¥…EŒ…ÒbÅ~‹ËÏ,m,£-•–Ý–,¯Y¾´Â¬â­*­6X[ݱF­=­3­ë­·YŸ±~dó ·‘ÛtÛ´¹i ÛzÚfÙ6Û~`{ÁvÖÎÞ.ÑNg·Åî”Ý#{¾}´}…ý€ý§ö¸‘j‡‡ÏþŠ™c1X6„Æfm“Ž;'_9 œr:œ8Ýq¦:‹ËœœO:ϸ8¸¤¹´¸ìu¹éJq»–»nv=ëúÌMà–ï¶ÊmÜí¾ÀR 4 ö
-n»3Ü£ÜkÜGݯz=Ä•[=¾ô„=ƒ<Ë=G</zÁ^Á^j¯­^—¼ Þ¡ÞZïQïBº0FX'Ü+œòáû¤útøŒû<öuñ-ôÝà{Ö÷µ__•ß˜ß-G”,ê}çïé/÷ñ¿ÀHh 8ðm W 2p[àŸƒ¸AiA«‚Ný#8$X¼?øAˆKHIÈ{!7Ä<q†¸Wüy(!46´-ôãÐaÁa†°ƒa†W†ï ¿¿@°@¹`lÁݧYψÉH,²$òýÈÉ(Ç(YÔhÔ7ÑÎъèÑ÷b<b*böÅ<Žõ‹ÕÇ~ûL&Y&9‡Ä%ÆuÇMÄsâsã‡ã¿NpJP%ìM˜I JlN<žDHJIڐtCj'•KwKg’C’—%ŸN¡§d§ §|“ꙪO=–§%§mL»½Ðu¡váx:H—¦oL¿“!ȨÉøC&13#s$ó/Y¢¬–¬³ÙÜìâì=ÙOsbsúrnåºçsOæ1óŠòvç=ˏËïϟ\ä»hÙ¢óÖê‚#…¤Â¼Â…³‹ãoZ<]TÔUt}‰`IÒsK­—V-ý¤˜Y,+>TB(É/ÙSòƒ,]6*›-•–¾W:#—È7Ë*¢ŠÊe¿ò^YDYÙ}U„j£êAyTù`ù#µD=¬þ¶"©b{ųÊôÊ+¬Ê¯: !kJ4Gµm¥ötµ}uCõ%—®K7YV³©fFŸ¢ßY Õ.©=bàá?SŒîƕƩºÈº‘ºçõyõ‡Ø -چ žkï5%4ý¦m–7Ÿlqlio™Z³lG+ÔZÚz²Í¹­³mzyâò]íÔöÊö?uøuôw|¿"űN»ÎåwW&®ÜÛe֥ﺱ*|ÕöÕèjõê‰5k¶¬yÝ­èþ¢Ç¯g°ç‡^yïkEk‡Öþ¸®lÝD_p߶õÄõÚõ×7DmØÕÏîoê¿»1mãál {àûMśΠ-nßLÝlÜ<9”úO¤[þ˜¸™$™™üšhšÕ›B›¯œœ‰œ÷dÒž@ž®ŸŸ‹Ÿú i Ø¡G¡¶¢&¢–££v£æ¤V¤Ç¥8¥©¦¦‹¦ý§n§à¨R¨Ä©7©©ªª««u«é¬\¬Ð­D­¸®-®¡¯¯‹°°u°ê±`±Ö²K²Â³8³®´%´œµµŠ¶¶y¶ð·h·à¸Y¸Ñ¹J¹Âº;ºµ».»§¼!¼›½½¾
-¾„¾ÿ¿z¿õÀpÀìÁgÁãÂ_ÂÛÃXÃÔÄQÄÎÅKÅÈÆFÆÃÇAÇ¿È=ȼÉ:ɹÊ8Ê·Ë6˶Ì5̵Í5͵Î6ζÏ7ϸÐ9кÑ<ѾÒ?ÒÁÓDÓÆÔIÔËÕNÕÑÖUÖØ×\×àØdØèÙlÙñÚvÚûۀÜ܊ÝݖÞÞ¢ß)߯à6à½áDáÌâSâÛãcãëäsäüå„æ -æ–çç©è2è¼éFéÐê[êåëpëûì†ííœî(î´ï@ïÌðXðåñrñÿòŒóó§ô4ôÂõPõÞömöû÷Šøø¨ù8ùÇúWúçûwüü˜ý)ýºþKþÜÿmÿÿ ÷„óû
-
-endstream -endobj -148 0 obj -<</Length 761/FunctionType 0/Filter/FlateDecode/BitsPerSample 8/Domain[0 1]/Size[255]/Range[0 1 0 1 0 1]>>stream
-H‰,ÂiL’P×֟¶ÖÖVk«ÖªÕjë^µÎÕì>¼ïïoñÊû¾oóDäVNñ@T@ðTÀQÁÅyöÉz{GGG‡{û‡»»;;ûÃÞööž~koS¿»¶¾£[ßÑê «ZƒFkXYÝVk¶–Õ[Kê­Åe½jI¿°¤Wª6ç6ç”³Ê -ùìšlfmZ¡›Rè&å:©L+‘iÅSډÉÕq©fLª•hFÄ+ÃâÑøŠpL-UŽ,ó‡—D‹<á"W¸È¨ú‡T}ƒª^þ{`ÍS²xÊ®’É™ïæÌwõÏ3úæ:سíìÙ6Ö ½g¦•© 1ÔnµKNaÈɝrR§ŒØ!kiŸnn›&Чñô)\ë$–6‰¡JÑ)Š,m"K$ ‚(ō-bX³F˜h L@ñãõ¸ñ:ìX-v¬=Z­Büm©"‡+ÃåpQ\TÚ(* ‹ -Â"¨ *(¨ä× -åÕæÖ æ«ùÙUü¬*~æ߁ `%/½’—VÁK-禔s“˸ɥœ¤NBIBq|Q_\a_,° 7¦ 7:¿’φ䱣rY‘¹¬ˆVD6+<›–ÕšÕ’É Î`‚3ºÁéÝAi]i]©@†*Ã/…á›ÌðIêô6öJìðLìðHhwÿÓîßæ×æKwŽ¥;ÅwŒ¡;D·ÚCZí 4[`Í&’fIµŠ Z†S,Â)æá³0²Y(ùw(ùW(ùgéGé{0é[0é+˜øLü &~
-j1 -l1 -hþhüÁ¿ù=ЏðΏð֗ðƗðÚÿÊÿè{á{î…{æ…}ê‰}â‰}ìyäyèŽyàŽ¹ïŽ¹ç†¾ë†¾Bß¡oP7]Q7\Q×]P×\š®:#¯8#/;!/9!/:".8"Î;"Î9 Î: Î8 NÛÃOÙÃOÚÃOØÁMìMlm`ÿ[L¬Œ-ÐãÆæõÿÝ3
-
-endstream -endobj -149 0 obj -<</Length 650/FunctionType 0/Filter/FlateDecode/BitsPerSample 8/Domain[0 1]/Size[255]/Range[0 1 0 1 0 1]>>stream
-H‰Â[AП¤Øb‹ÝÝÒytH(Ý¡4Gwݍ€´”Hƒ„€’·=»³3îÜûÆËCC€% ,æÌӘÓbÙÇ̦w1µƒµÉÃm|¸…6Ñþ´¿öÖÑîÚYE;+ä¿%ôw m/¢­´56çÐæ,ú3ƒ6~¡i´>…Ö&ÑêO´:AþG+còò(Z•—Fä¥ayqH^$çä¹~y®Oží%gzä_Ýòt—<ÝIN}•';äŸíp¢M·þhãÍp¬ Ž5ÂÑ8ZGêàH-®…ßkàP5ª‚ƒ•p°”Ãþ2©¯ö•J½©·Dê)–¾‘Ý…RWÔ•/uæI¹Òש#[jÏÒ͔Ú2ÄÖt±%lN›SĦd±Q-6&‰ -Ib}¢XŸ Öŋuqbm¬X ªc@u4¨þª>ƒÊ(PÊ#AyYJÀ&hB€&”ƒâ PŠ…¢¡Ð_(ð#ó}…<!Ï[ÈýDæ|²•^B–§å!dzðî|Æ>ݍLsåS]øTg>EéÄ';ñjG^íÀ«íù${>юO°åTd¼Š‹³á⬹X+2ƒ‹¶à¢Í¹/J3î³)eBF“Fl¸!þž -S¾cCߒ!oÈà×lÐ+6è%¨|Á<gýŸ1J¿§ŒßÆ÷1ã£|Äx+2Ÿ0ï“^÷¯»ŒçÆCy›qWÞ¢?ܤÝnè^§]¯Ñ.´³ít•vºB:^¦.Ñöʋ´Ý%e{žR£Tú”>e}–²Rž!-OS§(󓔙òezœ29®5>¦«§5ÒÓÕ¾Wù/À–ñ.2
-
-endstream -endobj -150 0 obj -<</Length 700/FunctionType 0/Filter/FlateDecode/BitsPerSample 8/Domain[0 1]/Size[255]/Range[0 1 0 1 0 1]>>stream
-H‰úÿÿÿïß¿|ÿþõ˗ϟ>~|ÿþÝÛ7o^¿zýòÅËçϞ?}òôñ£Ç<ºïÁÝ;÷îܾ{ëæí×o^»zãê•k—/]½xáò…ó—Ν½pæô¹S'Ϟ<qúø±SGœ8røø¡ƒGî?²ß¡}{îÙ½×Î};·ïÙ¾m÷¶-;·lÞ±yãö¶nX·eÝÚMkWo\½jêëV,_»|隥KV-Y´rñ ç/[0oé¼¹KæÎ^4gÖÂY3̜>oÆ´¹Ó¦Ì™:y֔I3'M˜1±ú„¾©}=Sz»'÷tMìê˜ÐÙÞßÑÖ×ÖÒÓÚÜÝÒÔÕÔÐÙXßÑP×V_ÛZ[ÝRSÕ\]ÙTUÑPQV_^ZWVR[Z\SRT]\PY˜_QWžŸ[–—Sš›]’“UœQ”•^˜™–Ÿ‘š—–’›šœ“’”œ˜•”™Ÿ‘›“•™‘ž–èàîïæïêçâëìãäåèéàáæïîêçîâëæìãêäíâèíìèåäàéhïá`çî`ëfoãjgãbkíbcålmédmáheá`inoafgnjgnbkfbcjlmbdelhilhad`a¨on gf kª¯k¢§c¬«m¬«e¤£e¨­i ¥a ©®¯©®§¡¦«®ª£¦¢­ª¬­¢¤¥¢¤©¬¨¡¤ ®(¯¦ §*/«Dr2ʲÒJ2RŠÒ’
-RòRr’â²b2â¢2b"ÒbÂR¢Â’"B‚Bâ‚|b¼¢ü<"|ܼ\B<‚Ü\ìüœl|l¼¬<ì,Ül,\¬Ì@ÄÉÂÄÁÂÄÎÌÄÆÌÈÆÄÈ
-B ,Œ Ä D ÄFŒ0Du`å0 
-
-endstream -endobj -151 0 obj -<</StemV 133/FontName/Arial-BoldItalicMT/Flags 96/Descent -211/FontBBox[-560 -376 1157 1031]/Ascent 905/CapHeight 0/Type/FontDescriptor/ItalicAngle -15>> -endobj -152 0 obj -<</Subtype/Type1C/Length 3586/Filter/FlateDecode>>stream
-H‰lT PSgþoBnÂ+"ٛÕr#",¯,Êä!‹¢Ñ`©˜&Q
-tkkuÝ]-¢®m•ÚÝÝ鬸T¬ÔJ+¢ :Æl1ºŠ/XQ±j]΍'Œ{Cg;;;;wæܙóßï¿ßw¾sE¼„¢¨_ÎÍ-È}=÷WyæJ‹¹®Âhˆž_Q¾ªÎsÂ))NîµÙOÀùÉ1 w½Üô²\œ&wôEýõxNUõÆHaŒTk““fEybâDLòÄä™1Yeªzˬ.ÚX[g^[«ž·ÎXUS]Uc¨3›bÔê¬ÊJu¡çžZu¡¹Ö\cá³?ÓRWÔª -꺃ɼÖP³F]µR=¿b]UÝÆjs4ÿQ¥:k®Ú°Î[U£®à/¨]ÿVm…©ÂPSa®ù_m„âB"B&ù‘ #DCH4!q„Ä H"!ÙÞd)¡H!vB„$ó%#B"" -ä 2LQiT>e¤NPNA´àà[a°p«ð¸WŒW“W›×ˆh‰è°è[Ñ=Ðt‹X!N—‰JæJöHF½3¼7ys>é>Ÿ¿ø´ùû}Ûüüªýù üü«ü›üû¤Ò©uR˜^ª—r= -=%8Ñs¬Ööì­¼ìy?ê5=²Ž.WÜa´³3µqÎÌáß9‡ïç8ãØ
-Ûén™^W¨ïì9ßÑyžÅý°ÎtÆÅeÍÖj¯f;¯«0 £+9ÝÛ{º³··S¯ÓéKt¬¬¾‹Ëƒ£ÌRÚ=mÜ(:KKÕ\s=ø -Q@· !Úeb²ãVÐƍSEµRüUÓߏÙÒÝ®úzª»OW=ƒCçcæ+°ðNF©Îб\ñ¢€4$Œ€Jõ
-Ì}Â1,b€@èE‚|Àd@”JO?Àà )
-LÓaBò(}O&ˆ'“3ô¹xΟõóÇò¡ìx±TïùÉvh ž[›Ç¯ˆÎÑÒw­X©6;<³ 9=üÀ`ÈzLÆ(TÁæAÜç jˆüŸŠRa6¼d°¬óð5\ڎ)°–´C*,„¤uð&šYéA wð+`yEÝv!tËí®b=mAÿ¼÷ÕÛ$x],m°r¬ŽR\¸"»ÁÜ:fä—n=P:–Äò†,mÄpÌ`e—/ݺäƒ< g°ºƒé]—O~ùM«äÅMX~
-*€dbˆJvYm,²,¯ºÎÂ~kàQ»ÑV»É.{oÃCFö>zR¾iIÒîŒÙ3”ÓçôŒ±ù4&è/†D%ÌØ}ëH—ê®ÏhQÉ;š[ºûà£=‡Bn›±LUZfÑÏWØé¡ ïô­œ‰$©
-}wªx±måVób_òb_Êí=jäVëhpWˆƒSÌez¹}p¿ØíPd¥¸»°ò Û÷£¦*A2v"`Fô2ùå[ʳí°E§­øœ.tS]ÛDgÚκ¨sd…„秆ľÖ1òބާV0[©våÍkàš½—|…J4.Ã5˜ŠÿŠ‡i0ýö „À´ä{j(*6²0õãPYJç×¥9Ÿ°‰¡ Î.@*Á‹¾(){tcäüÍ'7]R;QW„½.)ÃIhTòÉñOïâ
-ÉúCP]ƒÏ`9lœwOh´Ya5°/?´ÙWÙùâ·À(óÈùFDtN~ŒzîåÁûO²²ÇÛ¡—yüaNø"SFzÎñÁÛöö,RøoXjåŠÜDªÀ'÷hF¯êÖ—2óæ\þ¼ù,oŽÈ$*îÖ¦i‰Gª+TžŸ¬ðb¢ OìÂ.ˆeP¼ïN1”ÉÏUüJ
-! 1&;§bð=-L¹s±í»“lãÊ~W‡˜ªL/ûÒ¹‰ -·y²£wÎtE”.5<t¡} Ý}@'fúþ{¼ú¹fbÌ`˜o ‹“Ú¨®á]ù]°ˆ`€¾Ñ›]&QÇÆM"øÞ¥a`š[*ÂVšÇ5Ø ÍM¶À¸«|óFÂcæÑð‹;ëyS&çÖ£†Å,š{êZZÆA¤uµvæ›%Âb& -wÂG»@3²¬/âÛ(–q¶{¾þ–¼~LWaÓ¸‰–rÁl.¹êp]îC"ëÜÀ%aèt<Œ+†0j x¼maçÐHWg$b€õ‹ fA†“ç– -“®•â¤Ã¬ZÿCžp¹Ër›;Ú8±Í-†&.Öæ®7ñˆï%S=õÂ!„,¹Ë4דk°¹4õ $wi&²\ñO»\‹ƒ÷4‚góœj€†Ù`„r¤!×óMr§
-þ‰ý .J -d@ê¿´@Ês”b)¦¥ò»k!ë©ñ^è·ÁuÓÁ)yÃÀ¨ßyIXº!ŒmÔ1ŽÞ-韲ûoCåáeç^zã'[ljǵßßOh–ÜþâhÇ°¦Î<‡¿Vaë¸É7y[7Ø^QáýæÉj{EMéÞc äÖ_*uÈž„5 Ɓ0'—òø0ZÜQ¨¨„ÕÕ͝wA¥”=}p·ì%¼w¦Œb‚g%ńó+qùµŠ´â\¾‚Y§€yß³x\ÛÂO=m´a\ãpi`ƒÍ}ÐC¥áæ"O­ÿÌ}/«†ƒr' -»øÎû7ëUÅĹÀí‚ ë^¬ÛÞV*¢âU%¨|+§© ÀVꩨµˆ§Õ¶õ@$mMÔñ0€ˆÔâ5)F«‚T£‚r~tDb@-ˆ´b%©v–ÆÎ"¶¶iú‘6¹Þå½y3ó~³3î®~2×ô¥faõº²ÙáSI‚)qûäñ0—÷Õ%›óæ¡ú«çŽtæiÏæžÍ­±¹bl ƒ3 IAÃýo-èlm:tÞ®åÂsV䙎ouåeägïöÙò¬b;?ýêáPƂGð _TOX€ž[´—˜»…ܺʗħg}`Þ"š·¤nݐåJg:Ò6Êë`ö¹!Á£®DØ˃[ãCP×E_ÔlÓ¢&{š~”€ê¸ûà-b¤ËNffٍÔF®YéÀO<ê£VÆ.¡ÂÀr›Ÿ¤HŠ*ɳª*ÒH éÐ]ÀñÁ$d#QׂîšæëÀÚÈ&eÎM
-ÐËH«À©\`ÈÍÚäH›øû<Ï7À#‰«–WSžè€êQÓZ@“­Ͷ‹ÀKU£?º‰ w©_uT/Pfô‚~¨»B†5Þ8ÖT&îd¸Í¤ÞC¿v¾m‡ÙÕéè$7QÁþÁžóíp:2Jl0òŸԃ¾Žžˆ^€ºf¡0¬®õÁ!1š™š¿4B@ÖÐ.9¢B8Ùd‡ÉŽífŸn‰ëê–M|ŸI’Míþ -lÕΚºÂ¢,˲Ðs,×eÍÈÈIÂÖ¼"†DIÉÊÐ䀑Jë2ŸÛMÅîæÑ-ƟtÚ+ñhvQµ9­-=¨ëÐ[„H—,¦É~,FÀ°hR-úµ -׎ÖWˆènÝ@œ fÄ컞N͎˭‚q+aˆ"×&›¨¶«š%8%9Ã0 -fËsî9¢­-©9sM¸_±èu;%¸ÇžÌþrÝ1­#5q¬0}‘iþBy•¢›á¥Ÿë±T>ŒÐÈņ¾b–ë©ïuç;bi.½°bcojÿ¶veÛú;r1ϝè»ÇÎË\÷F6‰µe ÷ó«îˆò7,—f…Å|L`#£\ Z%8‚­ÿR9§?wêXƒÅÊoèË\YÏaþd~}éQíñC'KN í¥ÉQ"þ,QYú÷MöGsŽˆŠ_½R{nÃÊÓBtܪ„ÕbÃU_§"¤&ÑEý=¢1ŠT…ÿÇ=âN7?‹òŒô¼¹/2yðûž ã"`0NÆ 0z®Œ'²Ê,f@)ÎFšm}¿Klr±ÿ>À‹ž4jfo„9¨yFån¢òn¼ë§Ušbò®D_ÅPT1ÁMD½Klŵ•-á„Bú.Ü1,&<u¦I)¹­Óð$Ubÿý7Lþ -Cÿ“Ç%–këM%ÜåROW\Î45û´J\Çs—Àµü!íe6hÁûÁ«”„v?ëLÍt<uºPõíS§)[ŧN•µNÕÅ°58WÂd~Ì®«à)€gÇÙDXˆí4 -¯=Qþu«ã½°BDpÛ¬¯DâltÜ$—Bûc;ܸ,9hbò‘Ž4š4è}¦ÙU]„±¼*~{Æ&K†`Ìú¬F趏…‘©7¶ô -a#¬ýê`iu¯2¥)ÈÆi9 >â‘I­K©îÐB—¿cÑ©2´§ìå4ñ¦M—ˆJ5;®%õÝ'§’q¼«¹Â@²\¬ž¥Gx_†Ë ´ ýÜR}*¿ã,ë4Í &¾¬ê© îËð5X¦Žb`6Zq!ÚÔ- +%PDF-1.7
+
+4 0 obj
+(Identity)
+endobj
+5 0 obj
+(Adobe)
+endobj
+8 0 obj
+<<
+/Filter /FlateDecode
+/Length 19263
+/Type /Stream
+>>
+stream
+xœì½y|TEÖ0\Uw¿½ï[:ݝN:K'$$B ’ˆ°š#a_THM!*;*8*àJÜA¥IX:®óÌ#Ž:‹yFud䙇AFI÷{êv‡eƙ÷}¿ï÷ý¾¸MÕ©[U§êÔ©S§Î¹uo@!¤C­ˆAõu㠋M7¬8Šn€Ü¦·LkîÝÿå!äý=äý8cébÿOCžù ¡²U “g7ϹEüúpB¾qŸÌ¹ù¶ÙmY˜EhHBCçϝ5mæzxh ðр¹a^!ÝmYá>sî-‹—÷sº2ྡ´Œ›Θö៿Ü»®CȽÿ–i˛mœy”„úþÓn™µçú¿Bèq¸%†æ…·.Nä¡OzÒH˛ÍjþïQ_Úʊ!dú­:6ÎzǑ,yÿTCÅßD—ˆèõô^
+ß5¼îÇ/ô‘˜ u%µ>½
+CâcÐ0#úñÇo7¢‹%}W'ÍÑEQâPðŽ #*D¯ú%PÊ0’£P*rr%Ѐ' ™÷Ñlb9¢XB/¶å%ºÑòaЪD›ž0z˜ÁÏïâ>ˆÅ%ÂÜ® œH$bCÜa:RÄò)’Hy*ìFÌ¯Qs‚EûÒPvÚb_@¡þ’îƒjÞ­h„§!”@Ê›Ò‡éñªÐ¿¹¸·Ô°Â4q“ÐÃìhkªl ôuïÅö¾@Oð»Ñ¿/GQZ·¯¤GAy>¤ä&Ñ1Cþ$½ÿªo[Ð7ðÖœpB½jú ô˾±öø³ò€0ÂFS¯Š_íùàþ>HkRã×BУÿÍÕ7ŽË/J×ÏÕýßñóÿ‹ ÆuýÿtQùøNj½5qáó`n¡«×Õëêuõºz]½®^W¯«×Õëêuõºz]½®^W¯«×Õëêuõºz]½®^W¯«×¿ºHê˜ÐŠšÂnü¥ãLL­så… Ë!$"¤Ñ"½™Åj³#'Bž´TÌ¬PvN.
+ç#TXÔ¿¸•(XŽW$‹‡U¯¹vU{BuõcǍŸ0qÒõ +Q4冋½Ì¢Ñ|5ÙüïFpß¿ ó÷Ñè ú?¿XÔq„ž¤o2PÊEù¨‚ rTƒF¢z4 EÊyh)º +µ¡ý¨½Xßø-~—z.鬬"ÀˆªÐt‡PšƒnFËÿ+ñÅÿö7#ñiâ»Ä㉠+‰µ=Oö<ñO'Ïÿ‡—R5A©rMÅàAåËJ#%Åý‹
+ûä‡órs²CY™ÁŒ€ß—îMó¸]N‡Ýfµ˜MFƒ^§ÕȒ(ðËŒò‡kšü±PSŒ +GŒ( ÷Ái1í²Œ¦˜²j®¬ó7©ÕüWÖT æ쨩$k*kb£¿Uäû‡ý±ßTýxòØHßWŒúc§Õôh5½YMë ‚¸snµ?†›üÃc5KçnÞT +ÍíÓÈÂÃfÉùhŸ¬¤R1G°yv Áj‚8†ÚG¨¢bî`õð˜+XM)ˆ1Yç͌Տm^í ¢ù1<lFpz ‡Æ aµ
+¦vã‡Åµÿ<:´Ñ¿/¿{ýF4½)¬œ9톆3-Jû0…¡ßê˜ãö“ÎK·Ð¸yXÃÚËK=̆áÎy~z»aÃZ¬{lÃå¥G£Ðà’¬š¦ +5Ðõ½ÀÄÚñ~荬Ž6ÄðjèÒOGBG•߬àpšÓ4ß“‚Cƒs7Ìo‚©qoˆ¡q·ÚÝn¥+уÜÃý&4±JO0:­:mŸmw[‡Kñ»®,)Èßg4%»OoH%´ºË³.–©)µ:MՎ»ÈYL)
+Žˆùgø’† Œi f +Df „jpE1`ÅfŒ̋IÚ6Ñ|Š㲌Aÿ†¿!€àéï®Ì™–Ê᳌C4Iå䢨Ay_:Çòò¨ˆÃ`NÆ!ê}iAþÒN2 Ølôö¡zàí´è B` @'xc§‚¦ÃM¬ulCòޏ¦{ڑRŽÆH-éî+±M¤%­}%ћ‚ ÉûÕEo‹‰¡‹ÿ F»eøÜA1lÿ7ų’åµãƒµc'7ø‡ohJñ¶vÂwÉòËR©˜eXã!©ñ0j)å ++ӛmŒÍ‚¼*Ô3c ¥šý51cӈd•‰Ó)ˆ—!u&ÎP,\BKQ¾ò~ð÷WP§ÝÀ½lˆÔN˜¼aƒ|EY +(  +j‚þš +M¦u&Z§ýÆà†.²“ìÜÐ<¼©oB;‡7zb5÷Fasñ V‚†î âuc÷)xÝøÉ +]FÐüë&4´L†5 +î˄²†.?¨\5—\Ì¥w~z‡j1z;Õ"O—‚P«ZʪêýŒNŒÔ<±/£$™gTóà*@û&´Vé`ÓÛ  #Ä~m¤0/tºb¥ ÙªÂv{¸¸+Ñ +‰A%j~ÁCÅ­G™=h**ì=íiöž¥ºX…%ƒ“°°¿
+ÛÅd±`-öU¹­A†TªÂ&Û!¼‚ö Ï!$ 0Ì.æéö´ð4d¨²2ÏÁ¨ˆßƒ€ÀõÏÁXžCߧrX ê™IK»FÅò0ϖb#„V{!¼C !Þ!ÔÓPö4"ÌÓÌSíFŸ±JfžD+!æQdÀù õmF•7t,ÅJ•‘yÕC (ƌFÝ4û =€T¯m/诲°¶CÖ¡þF z#²ºlƒ«÷
+Zc‡ÅN›¿§Ý`Rñîh/Š$Fgq=pa9ÂÌ,f
+"³`:À½§33‘N¥Sé0‹[¡¿J¨^ÉØÀBñ1UŒ¬fÜÈ£V[Ò®Oö³¤='¯F<ŒqªU Œ #2B{±Ï„QTæ¯ë4”¾uíF[ñ1f5#€äcZ¡–Ãg8ÆÈ0³²:’ ’®xs•–™Ãœlñ¸¼@mhA;4Teb†3iÈe71^dXä«p'óR>扎Pš¯ûó ŠõKÚ(t?$)ZC:túâî*‰¥1æ~˜€ûÕÎ7w„£ª“ƒŠ àñJH­T…~¤6À¬m€™Ú3µˆÚ҇˜õP²ê2·£ffÚ a;¤©XÙځ¡]j"3§¸‹q1N`Œñ°C®»CÒSʜíf‹ZÍÙ¡ÕWcn9¿ÚT˜ÅgñÂ#Lž:”ü§‡"4·ƒ¸cÉ©D;’cL0‚2Æˤ·Û|±*ÜSAöÙý.9N™D> Ñé&ïÁ=…¿NÁߤà&a¢›O.
+ò[
+{ªÒȗÐØTò´R„!¯ƒê#Ÿ‘NJù”t¡J€'à~&À.€%·Þöu’Î@ûcí:;,y½=\˜Jø²R ‡'•0ۋ«²ÈkäU”M|0૤,gy `7YŒÞx€”¢Á÷§à¯ÈQ*âä9V²t´ë) ±v‚½í</µ£ä]}¡ï(y‰ìAn¨úb{È +¹»:B™>Ãh“çÈâv¯Ï\%“§p> •ÚÐ
+‘™<Ý^FÙÜ~Ôïë"›ÉfÅY¦d)ʦ(«¨ hãÏòøËü;üUFr?(íÖ/Ùqò
+„Íd};[«ê…1ÑqÔ
+q›šj‚¸YM!ˆKϨ©J²ÕA ÐÆ
++!´B¸ <Íävw@ø„;՜Å–@XÚ¤0š£0šUŒfÀhŒfÀhV1šÕޗ@ M€ÑM€Ñ¤b4F`4F“ŠAémŒ&£0ê£0êUŒzÀ¨ŒzÀ¨W1ê£0êU 0ÀPCQ1ÀPC EÅPC EÅ(Œ"À(Œ"£0Š£0ŠTŒ"À(Œ"Ã~Àð†_Åð†0ü€áW1ü€á ¿Ša #`èbÃFÀ0ªFu~–@ =€Ñ=€Ñ£bôF`ôFŠÑ=€ÑC–ícŽW½(Çå8 WQŽÊq@9(ÇU”ã€rPŽ§†¾Xe±Ya%„V·p»·p»UÜnU¼–@ ¸1ÀˆF 0b*F 0b€Œ˜ŠŒ`ÄTŒ6ÀhŒ6ÀhS1Ú£ +0Ú£MÅhSw Šñ/”ÿ×SCî +"쵤çªp%úN…+Ð މö©ðh‡
+ï@w«ðvT¦Âe(¤BhO…‹‘OÄí¾2C•T@„©BØa/„W jê=ŸCHR%ƒ5uÂva¯ðŠÀízbàëøíü^þžÛË÷ðÄ_å!:U‚jA›Ôx%ÄßC€MâJ5UI"Ðoôl)ü"$¢˜Nû¿ÏÃïåáWòðÞ<¼)WIäZ̪šÎÊÀöáEâ;¡,”=4Óý¿søÚC|øhä*a€ßAØa„»!”A(†P! ‚OÍ˃ú +JFªÉ£²! øiÈn¿Àl•.¢Ã;:ÞÐ!‰ö“xGÚ³‹t¶g×8Ԟ=ÝW%áƒ(›ZEøÌÜ€{Û}'¡øÅ$x¡ÝwÀ®v_@c{v?SÚ³ã«Òá‰ÈÇRÔ )8ÆMá¸vß$¨6¶Ý— ܞ¢µó £,(ÍÅ +è$À¬Vf²§`»o0€Œv_9­-¢l:ñ˜G*y
+™ èû.ÜÀbEã;í{Ð÷ ÿ âñ©¿“ð^V'ž¤È¾£OBå*_{•LëÃþ°/cðíÈZï{ ÚÂY}øúùî/è!û> {½ÚE»ïnðõö(_«¯È·¸à¤ïVß(ß4ß8_cä·ûnð¥d¢(n {úê¡Á‘0Š¬vßµY*‰5¾Û|Š/ÛWî?Jù‹&Û-+8J9€Š“½çó²:©ŒO,ëÄ&%O8#l¦C…ÁBPÈÒ¯`Í¢QԋZQE‘Y‘ˆH´v&z”0}fgåÕÏx–Ƭš6ÓÇ{à0,4
+Å,L-©?×ƺg ÚéþعñÁN,ƒ+Ň☹ÕN®íãbeáژP?¥aÆ÷G!7Fց£2¡¡'hÖj}f±£Õ÷yºÆ®Õ÷E£Èi_Zé¬41•×TÿLԔŠÃ—.çåIolKíø†Øno4VL o´6v}¢ÑE D7¼º‹è)ˆ6t±ÍÄ0|Íg›«£Pí¤Z +¤YÕP6PMŠü´蓡´ÌQ²^С^€¨'ëPH­’uj=ÓzûNø‡WïóûÕ:YPëœÈB—Õ‰Üê}¡Z+èÇ +´núUÂrՆ|>¨RàS«`°ëԆ|Xí,Vx©JVªJéÅ*¥j_ ¾TǗ¬cÍé«ć:áÿ—׬¡aÜÑɊ×éC¢¦àðYšb—ÎuÆZ§ûýûV,I==
+5MŸ1—Âi³bK‚³ªc+‚Õþ}ý_ÿ™â×iqÿ`õ>ôúð +û^WfU·÷WúN«ŽvTV4T]Ñ×ú‹}5TüLc´±ÚWeÕÏWÑâJÚWí«ŠöU©Tª} +ŸGå¾¾aŸˆ†F‡Ý„D#ƒ 7yÑ¡vcó*Ð]ƒÎžÃ,»&iƒCc:´¨ ª ŠÁ:£Ezú$0Uä\18à9Œw¥ŠŒm
+E}¬E´Rm¬tlm,0~r•˜2íççìVz©ÅN4|^5üƒûÅj€ßå5Ñ­?{-þ¹kɒ%·ÒhIøV„jcyãkcÆ%‚]5UG!¯__èyû$ixg¢
+Ã@^L»£©0¼.´ñm¡®Ââ··xá1ØÁWB?Ž,k/TÝg²¬##‹ú/‹;
+K“ÜU
+Û݁bè¡£ P)ÌJBÅT‰ÍY› 6—µeµ´•ñ{pdúvЭ´½pƒ‡oíc$GÙ@íï©ö4¯ÚqM„ÃÑð­Xå×?3÷1}ñ%ö§ Úüâ¾ Iæߚjf"Ùû’>´%)$µp‰Š”l$yw1ºtÁBÜa”¦†( +…'ûB|^â$-£| šÜ› ©«½€>Á9؏:ðÈÎcîF‚tþ¦Û^ԋ÷~ڂÍà³ÙÑD4³P'Œîŏ%–&¾A× _¢§‡ð݉ÝP¾ ½‰Î„² úÑ,ô +ó%Š&E"Z‹4àӍÃv4 +} ¿¿ +¢‡ÐËø‰óêYÊÝÐ^ªBU‰WPº—Ý̝ ÐÌ'f$恅”6pâãÄç(„¢èôÐÆÝì@7¡Õhv1oBêaô,Šc-id†q¯@O#Ñ$´-CÐnô.6ãzîw&qGâH¡åMóÐ7¸&ϱÚĐÄgh
+êBoÃx鯛Âîä¦Ä+O$^ïû–ñQü*WÌÝß{Wâ©ÄKH ôôŽŒ~¦£{Ыèôßè¯deb%ÆCÏo`/öãpücâ"+È
+æÔFÛÔ.AÛQ fä0:‚Žo~‡zЗ؊=xžŽÀ%Z2“¼Ç<Æìg>d1û<ð;ˆ²€G‹Ñsè úôôæ ý"\çã…x+~÷ùŽüÀŠì=ìOl/Š÷ÄJŒIü +|n7ºݎVoŸAh?úOôú+útñ@<?…c¸G$’AêH3ÙÞó‹ÌææU¶”ÊÞÄþ†ýŒ[Ãm¦ ñ ;âÆ_Œ¿Ÿ8”xdGí‡P +pô.ŠçÐ+èhýSôô'*?Ðþ`<߽܊×á‡ð‹ø +ü>þF‰Ô_Lª¡×…dðénò yz>é Ÿ‘??“¿1“Á `Z˜§˜ÓÉg¾blˆíÇögëØÉlf¦˜»–Ïíâöp¯qgø
+~&ßÌ-Ü-¬ÿ£7¯÷qŸÅ;@vE¤ÛO¢§Aî÷ü ýO ¸…YpãκËq +®Å£ñõø< ߍ×â_âmø1ü4~ Fc Ð&Ud<™Ff‘Ud-¹ì‡ßaòù˜œ §rdÂLf$3™™Â,€1,fV0«€³0»™÷˜˜SÌ×Ìi˜5›Î.aogaw²ûÙ÷¹ë¸[à÷4÷
+×ͽÏ]à.ð„wói|!?ŸßÅÿIà…B½°^øPø±§á< ÜùÉqÁL'»‰•]‰OC†¼Œ< ó0VÅÿ J&ó¢§å@›¸X Åä6FŸYà#¨¿Vò„ÐíAíø÷¤‡}\ƒ>ÂMØÅîdpï’ÚÚh39JŽà¡h?© “Èã Â_®ø%Èûrô¾ ߊöàÓx¾—á•èCbgÆãU¨"ñ4a±„Gâ3(@w±3эÿþÄ—£ß£oâO²:ö Ÿ:јÑÐçøyô#æ߁vc@M-s/ÈûjDµ^#¬³•°] AnæßCûéé¶PÆaoGgÐßÑ7Üa¨¡ IOÅç±O²_$Ê°Â`•¡]°îæ¢kaÅ| Rr îéÝ +°ÒeÐ%Å°ªëÑd4Ý ZïD,ñxâžÄm‰…è׀û#ÎÇ?â6X€QÞ†ß&ô)ÞëðZôÿèŠÏDÝè[ìÄY¸ÖÃin)·™ÛÍíç^æ~Ã÷n¯BDÿ ¤Y†Ì@ï£oÑX„¹q¡|zí +èfeŽ¡a؍šaÍ怚ɭÐÊÝÀ½Ça=ƒµqôÄ +èetì€̀þEh§ø<jw@ÎLÐÚyèÏ0n=y>R ¥- µº¦ß£¯€Û •®|Ð Õx´õº̈́ z¼fà *ÍZÍüð;ÑPœŸ¼&X¡zäEåܘ üø˜Ä@29{LòÛ`÷ò kp Pa€qô"®C¥ñq@Øacø·*Y‰µÌ²øÍè×èy˜…]*TÓå¢~? +ÝOpœ:I¥bAg,°qŒ\"ÏÅ s‡JӉœa㹊ފ1Ƴ£{+P%¤ ê_0LY—….ø™î
+‡~B~¶›¾IÑ rü5ìגЇI Ґb%,sŠË1p>Žp“Ł<CÄ˛4Xãr¸)ċ! +a&DøÃä!0¨R´„n›0ƒ]²¦‹¯ö€—4ælcÅè“'§“¿1Æᳪ¿jò*+F{¿j ÷/Â5Õ5՘*aXƒE#~+ävò5nˆïêuÆ×`WüÐM¼Áã>}âo4 ;{»2Ɨ¶0 +§}äM·z½é^moM÷û"ùiEÞàɁ+:é +çJ'sžô¥ƒú¸Æx +¹Æáp£>¡"{Q>>“óo0ø}~âïĒâE<>Ãcþë^¤Åg´X{CÈA®ŠÑÜaàqãèÞƖs44¦cúV1úôÙӅ'!2™Ë1s¹­ín¼Óø«þE–È€’b»ÍÊ3BeV‡½¤¸l@i$;ÌxÄ%øߔG_|è‘iø]À•_àòû]ù®®8Îèލ¿ò▭—
+(„˜­ãåcoBx{SÿÌÌþ›6eeöÿñ¯ùié/¿üƛ/¿ü–šµI-¦®÷Mñ±d.pوj}Ža'CD #ɈÌâ1œAÿìÄæ\–þGû˜Ÿ-b ÛI¶t˜ž»‰JaãéÞ³0Õ¨²ÒXaùÍ8"¥Fˀ²BlV³ÃNf½úHیI«º×Ϲ¦4{
+ÿõØîHϱøûñëÿòl|×c³)%ÀE¥d¤âÌ&Ùò2GÞJv’]zAþ™”&«@¥i¿ø?ÜcZJyþ0JÍéޓWc”FSb7Û¬a†¯”6{ý+[w­}!>¶ýåóŸ/ù ~~O?ÿþ÷ñ³ñŸ(%Ñì$öC¼ŠKd$ÂM/b†0edz%ªÙ§ór'yZ1rxzÙDÚC\ڋòrÖâITØx¶·ñd’”,SàâoÅ­á»â+?€­IÀwÆï‰ÿ=~í{I¼ ?‡é.Zy@5¼,tâtÅÃ?Žjdy ™X~T+Ü¥³4ÕåÉ^7Hc/6•#Sy9ˆ^Ċ² ( ދ]yK&—MAÖa×;·ß×ì_œ6}"íïAˆ^€þ”©ØÈ@$“Ðeí³Û省÷/*ú¤+,QàäÄ)VÏuƒ&ô£•Úåò:y'Þ-ì–vêIoKâ$SÔuOòÍ1͵ÏuÏñ‰å¤œ +Ѝ$#ùáRn§ôkòÿ+éWºOÉïø¥u&£Óï$Nêde™íçQç3ˆA;ÃÄyOԁ}êΰžÐ¸¼¦Ò7”͹–ÑÀ‚Óáèä£ÆF\찛Œ¬.d2– +pdðo2Úa™ +(`2†B¤ø£å›6/ûèãø—ÔÛ½‘º’$ືíO7ÜJj~òà–oª&܇ëU¥jÂÍ°+‘W«€ƒOƒò$4I‘n"w l'Îí˜Êa®“ÜxH”8Œ´ø +ô7Ò¨è8ÄúX?cYÖ%Æ;a·N2ºb4ÕìªÎ<Ûx¦5&^(YV„â§}&E'Ùàæá‰ÌwÖÐ9,;I xq¥2õ€ó »Ëó.û–ó¸ó¸ë¸[æ–6Ì;Éõû°s7»#MäÝ~”×¹G°ÃœÃ\ÃÜb¦3ӕéfì!úuÎÇ=§=îݝ¶Û+š‘×èõ{û{—zWy7{?öŠ^:/v«-â%F­Ák„y'TV êáNòTÁZ}Ôôi µDKçN»ÃÂI'ìvØ 1rû 'ŒËˆ+½oϪ3
+•®ßÞpËIØԍ-ª^- 7RÇyÝí¦rJC»AŠÞXΊÆrN44•'ýÖè>ž ›Ð h$ËC<L-L“ªš£T2jÇ6CžDJƒàMô 80Š[A^Læ²Tƒ
+慬™Iõ,ð,/°Ú Ùƶï^šm˜+Æ¿vañÍOÏ_;º$~îZ;æâ?=„¥ßí«¼~⍳æߑöõ»ß¾4£czÕÙú¥Ñ°V<0K¹èS¥x­í¹#mcÙÁ<Ïí´ds­Ÿ9ÿàíV|Ÿý> È:Äb‡ÅðéŒZ¹g*Ú:Vt›tD§ÃöNLƒÏRh!Ê^ˇåŒ W ÀœbÈfwdëbÚn˜­Ýxb¥o“o»o¯ïçëNÔeâLwØ~± Ÿ@®¼‹‹élj9šÊ SB#zÛršîtTͨ,¥\¦ûP£%K][*÷„2ûE6!%ÅôM>Á
+fdŽÆFÝ¢±×/[4n@­oÑò†‘#fk⽞[^¿í½;ç|°bkü«ß¾ÿ¯Ì]°ªyþ/l_2ó®Õ0³)õö)«n^÷ꭞ£«_Ÿ¡ÇÌS€¯¥Ü~£’+êýÚ2ópóH×#º'õ[͟é%³Éb˜‚æÕfXtX'kµ:³ÉÔIÚ»^gÕëufÙJÍ3õx3,ë+˜xHå¡GÛÌdEç“ e"SvË;¬”Å«=â·Y+cíÄ{«Éä3I¡±ÒXgdŒ´ª‘öe1ô¬ÁL?îÀŠ;Ü>}'(fÝ2|ô8Â
+øç{aÁŠèÂצ”‚“0j‚*£º& #|qF[`ÖrýÂz08ðÅYQgäŠéȶÀæ#€¹`@#fNÁNíÒÑ +·ß6í¶¦“›É©Þ¿äß8ýfçmŠÿ:ðmÞ© 7m^»ö¦ù)þ÷¿ÆÏ|zàþ×>Ç'¾b=WÏDEXw Hôú"¡ÎÄyåfH¼ezËò ÷‰À.1.µ®22!”§€kkÐuÚì öÛ²ìµÙ[uۜÏêžw>ïޑ¾3{GþóE]îCéŽe–5–5ÖµÙìV0ŶÂü¦õÛ©°DÓYL?ÊÑÊ~uýH¿Ãä~XÀ݊ÑîŒ4§µ¦‘60 +Óxs ªå(9$§“ܯè̺ʌº ’A±3hŽ›ç|'¤eáulp»N0˲NØ]ýÿy +¨›JceocبJøtc˜.€F(·SòZÃa
+•öÙtª´³ÁŒlše±^œ
+ž¹,GÜ2ãËÞ?5¿éö•ñÞOÞ^ýÄÒ®©uõMSnjmr/‹^¿hqtÎ,ÆÑ辶g?þøÙÙÛóú½ã×ñy¿8±ì-<vS'ÔMmê½fñÝw.sçýtO®‚Ù±Âì8PW›jM³4·‹ëÅç¹çÅú–¨‹9 ï4í·¼Þ5u[LË$MT7Õ4ÎÒdá]Ü2û#Ž??·rs-àF`Áiöy
+ARÞyv8cÀ Êd#ävI¸Nú\:#1R'®ëhÖPà2=äQאMç<QgÆfw(›eé'´®Ìb¶ªiÎ6‚À§öqÊhÔ'Îè¢D—ü’Òa6AŸ„°ÊK›Ê×Fl”' ¿þvÓüí/þ„¥ß|ŽÓãÿ‡äÆ;Ǎ™Ó<aìB<>}|}ۅ;°æãϱ)¾3¾$¾ þø!&mݖ;î½ukò­sîð•$ãª.$$N(RYy„ρHP,§4Â+ÁÝ ¥> +eå¢<6Ë‘ µQW©æ“YÌln®8Gþš1Œâ15°Y’XAÂଠV„^bY?Ç[9ŽeÅí"«ÊÅíÈY„ax–ž•*z^ Ëb$j©SÓI¦)Vɵ‚/ÖI2É'á"©U"Òa’‰X¨!ùÁ
+qinœÑgȹ€» Zœ½ªC#uШS{n¸‚*“µwþjm?'‚±¢bí¯~•ÜR÷KIAaº‹ÖÆ4ãkcéc'ÃÆÌ$âí"+NāSöñìÀ©=5¹# üpÀÂ0Ü+ñ—[{Þ“ ÆåyノGÇ;¸Ã6oõƒ·ç§ç-`[ä£Jå²<<W¿<ï+öËJ›Äçä²ìfŸ­ÎFŠl{mÄf³3²ÌÑo͈x²›ùVžðµ9Ù{AsP³DÒD@ß«Šú)ýêû5õkî×Úos¿¶~¢¿_¨k†ù-E°•v’ýÇ÷c½`€ÏNn†ª§MƒªT“Ä–hm÷–Û¨I⦠uŸ…Z!Q¨t™ì&ye G²øB·Ê@q:éS`§ó\ pÿ¨^ÜãÔM(¸…ŒziÏÚÉ §®ÙÜøÔÒQñ/ã:œóڋy×]_;*ÿýÝØÜ:^¹í]î°÷†G¦Îy!œ}tåÌc-:‘°oÆ_ä¤ë¯­ž(q½]ñ咶qÌÐò¨=2-qŠ»ü-7úX³FZo]oߎ¶ñoI2jþÆHYRŽ6G—k͵/á–Hk8Q°‡ÅáÈ%yL'äpp[¥w˜74\%®ƒ}sœát†>h–›œÊ /x²âp°¢^ћ#úÚ©LÕ®bsFÀJÌQ2Ì2cø^? }Ô¦ÜE ÊmÙm6>¡H`˜½ϊñ÷Å1FÐIíÜ{6œa
+i¢‘Ú̘sÏýTAü»ƒ QÖ?¨¶û†Æó]ü÷ñuøvÁº]3‹ã¿s?·ô™_¿Ý¶t7ñL9ó +ބ'ãøáí7Æj­ú6þcüÛï¶P +ûHè4P#8J+•’Xî×:f±³´\ž£Ü1µϵs厞µžG¸-Îg¢bi1gŒ¢+{¯€…”LÒQ)–ÖöŠ@¥šÌ …Æ"#1R)ôÿ¬^A:ÊLÅÈaWÝ[žþ‚I!B¨Ü€=D¼‡šîêl*(›=úžéÏö~€sþð‹²S+*n?äw8-ôZüÔ¸§mFmž}íB©Þ<éÝ»Î6멌< žÅ©mV®9V³x³ÃEÜ^ŽpœÄ°YàÉR–‰_ː2Ò`Û¯+Ò):FÇJ~LÝ ‘öò©X®òيŸYV¬'o9ë –wŲb8ÐHª'j ¤ÂÃlå…oHO¯Ÿ)៏ù!ÞòP¿¨_ÔKh‘R Ôó\–à‹ÄWÄÏE¶PÜ,QDÉ!H@%_ZcƒàÞí×iˆæJú埣¿1é¬õV˜)ñ?GßVætï`2³÷qJÛsç{ œ¥Z.Oåì3J–Är2C$9‹5ïe0à žã€A¯œèçߣ2C6*Š®^פcšu­:B™Ü¦ëÖ±:¢I’ÙM½0•ÑK®EçSO
+Ue¥Vå4£ršI*0
+þÓ}ƒ¹øۂsH5ΉŸè=Êî}…TýXCîê] cº¶ÆÄ …ê vG"õ`–
+•J«#‚8…«çZ¹ŽóqM\3w†c[9êM3H$̧¡êAL7Õ$tPÇáŽE ØþÛS‹Qj(•ê#ž–E@-¥ï^œÃþ±èxæý9î%Ä¡kw½@ÛfAc!‘åÜa.ŸR¾×åS§íŽîM5­ŽÚöŒ·‡{駑?ÐyƒÉé0Ò§¢Ñ0!1¤aX˜3QEJ‘ýƒG¤ÎDOG
+*Ϧõƒ\ˆxI”¿¾“a“e Ic’O’|Ö/ÊsÈ\v–4_^F–³ÏJ»åÒaùœô£lßÎn–¶ËoJïȟìÇÒ§ò)ò5û¥ô­¬[&-—ï!÷²÷H÷ʛ‰Ð ™Eæ³s¤¹òRr+T“Z¶Zª•¯¯—dÁ)ê#d‘˕z!Z–—$ÙFܬCR³%KœVŠy½¶¶c#CÄzQÑÐH¥^£‹ˆŠ>;¢¡d=®iB#2Ô\$‚ŒD*h•à»;Ry#.<müð4Íðt&+ЋŸ%©˜a­ Í,3’ša´,!Zl$Aôé1øIºúÝ×a2P«)IqrŒŸáŠEX)bñØJ˜…c¿FK:É@Å r¤@E¤@%T죆4££+ÃxÌË°±â/Æ
+·ËØÛÒÛRáv‚k† ãÉêg©Ë¨½ÒJÙ=–ñ°nÄDÏ>Ÿ9ê¥Êa…[¨Ø`¬>èeü>‚e,à£ñÓñ?Ä¿ˆÿL'óõ5ìÝ?­ djè‚ ÕSø?½Äð¢‹qˆ¬Vpu˜5•t]ÒaS¨äÁˆ˜bA´
+‚Ȉ„Œü^1,1KGÌóï©OŸ6*.ES¯iÒ0͚V +iÓtkHR·‰RªQI}2~|D*¾B‹È—i0 Aô)¸S×µpÊ„µýèàCI9¢Z¥G‘@*DRFºITjTã‘j—þEÃÔZ­5¥b«¦TØ5î~q<DcgŠ…ak˜Õ ¦ÛÄvñ$ÃÿŠyOüLdüL¡a‹uâ/™íb³WŒ1¯ˆš¤Q^R!J‰j”÷(ºÂâñÓH°–BÎVE
+ô‹ ©µkÒýp‘HÁI‡O²…Á¤DCá2I¬Ä#Œ&ÅG…=¯ɧäkrJø;Ñd“a”°\X'¼@xªƒ]zå¥O¢H•ªC°iö“l‰Ò» €ùàÇæè…jjMDÁ;v˜yÐÓÊÄ­ÜVq›v›ž±  +‚3Û¹\Zf–™–ÛÖ°ëÅõÚ5úÕæõÖu¶uŽuÎ5n­`IpÛÌn«Ûis –ä*{ö^#Ù(ûeF¦v†¿È«x›¼ÍÞVo›—÷{Ïx‰×˜Ý†0}Þ[¤Îù½i+^¿hb©6Gcò©jåiª[Àn€UZ6 $eX!l5_ôe£ÃŠ_œ³¾WãÕññcñ®ø
+Üÿ«}û¾øáC=äÞmÍíáAàj="¾Ì«¹'‰ ç¢| ¶ÆyX”˔,žë²v9™k9<‡û˜#fS–N¯G#Ý­ +H´ÿ“e÷y‹Rãã¼FÃåZ>íJSê¢%•Ú¶/YS0a`*¦ ò`ÐE`h){üaü;¬·b÷ô­cæ¿óêÓ{—»qDiwØøÃÞµóL¶ÞOØ×âMý¦WÕÏÕÉÐ1Ýáa‡D6@ç•»Ë +# +× ó5óµôéx[ð þ„$ó"/;D»<@_£¯1¢Q2YõVƒÕ8@?Àp­a‰þ6ã²f¹´ÜµÔ»NZçZãå%»UÒôãõKô«ôéŸÑsz¿NkÕé´­Mç°gYŒVÜdm³«ù”]À8õԅÌF:£Žè>ôd·ñ1¾›?γüÚæ ö‹‚$°]εŒþ3.qM•…”¤*ÇKªè‰×eO T¼¥‘2´Øžzâ°˜~$4™.q\›…þ¨õµW›îœßòãEnœ]ñ»æWԍÈÜŠ;\÷îÝÏ}’6p͞øŸpåžh ÷qfLfÃÐQS´ݍG%¾bÿ
+k'W®é2uz漙ς£bGÅæ Ïâfå,æ—ëç|ªý8¨Êõ3¢Á¹ÚÙæ9y9sò—y×x·´æ ݱÓ}
+•Y.wdlÆØ૯ٖŒ–à]wÿ+㿂|XÎÓefdËu‘`­\««Îœ¯›¼Mw{Æz݆ŒòNÝ® ‹$K:>ƒºd—Ξ!de‹“œŠËYèÄ ÛÄy˜ÌBÐBZw¹Ïƒ=VÀT-tû#ôqd=n›qŽán,â¿°Š»ÜÈb¶ Or~Ÿp`‡bqDµBvÈÝϗÝfŒßP‹¿7%'ÐUð۔Ì׎o؇”QՃc<0¼ˆºM-᳍á“I¸(|v»¤êRÍ à‡Ç;øq<¿h·”g{ÀÝ;ífzw\1˜Ëu~s¹¬ÍûZÑk!OW.;i°”_ñ>[ßÃyÛ y®4£ø8R7,£&¸C~>CFô}Ò±¹øì2[ý•F€Òa“nœÀÛ¬;«JõñFa¿{ûÚM\s]¤ë/MkW~ÿ<¶b‡?a¹óλFæı÷–Ü›@¯Ä¿ŒÿöÀºÛÆFFzÌýOºí¥æ×gÿõ]]ˌҌòHVáì[Žm\ñû›0ýƒ(tR—úh‘,”ŠØ"®^j–Z¥Í’ÀcŽd± (9nv%Ýoq"ó‚!ú1½51úzÒLZÉf—ØûBjVÆ6ì#0+ªÑ[ÑðYÕ'S:©B5?aã(¥þþ<>š½/>†}íüùŸè§hŽ‘ T¹Ðe 
+’`%"]+^+ ×K“Œ[Œ[MÛlÙwÙ?±}ɟã5:­\P!Ë"i5~Ý{Ô¨RÝ O½§ÉÃ4{Z=Äï)ò´yº=¬ƒÝíw¹º]Œ‹*÷¿t'N«Ê@5Ã-L‰]]Ú°çõ$˜A]ÐÒqŽÆ²é+ZÝ8§è®/ýöÓV/l‚_8ù–9[^bÂâñóŸm‰N{lâŠsˆþ1yМ`|<Öw ‹Ô 4—«Æç÷ H·ø1þ˜|Ê~ÊqÔÐ]ÎmÅ[È#ì6n»(2HÊԘn—aÁ…ì|.
+ñ#ѵüõ0‹ !~Œ¬0¹<sñ‰ÓI¦+<-ì(L¸Ãdý&Š¶†Å+ÙVös¶‡eÙN¬Qä•L+ó9ÓF?¬ÕPÌÎÃXƒ}ÖV„1v —=kƒÖx¶±1ì<}Ѫ<}¥MyÉbêî0&m¥`&McºQ5”Ôƒ)Æ`Y0µ,1ÑôžÅUøV<êýîðO¯³×€ã“ük ÜxêUâÁÊS&Ö#e'Ëìn‡°GzVó;ü¡À¯ÖlÃ1r[…G¥‡4»ð³ŒäÆ6!‡„(ž$¬f6p$)‚ Ä%ûÙB¹š½Nž"¯bï•`·Ëmì‡ìe];P~}L~‹}G>Î
+2‘xÀˆ¼†eD?Í! y?
+nxÆ8+Pž-LXþ«åè!^±Ø"|-}¾Ù!ºuÀÊ£ôÕܐKj5tËÒ¤š–²ÕEùê¤*ì4$Ï%S¨ð¢[{%o +p%ù{ôSv„¥Z> ß=$™"òˆú RUë´´´ Eýq’Ïôþ[|žŒC؏¯„»ÇâGâ‡I/9ÏşôìÕãŸât/¢ÿ×¼Ñ] >/+C4¥Ý2f–c–c.™ö <ÁjŽŸ¨©Y¬~Å [q²3ÑIæ€TR~Ð(!h›'Ž`÷ûx9ŽCøâv=»C¢ü1ÂÊtO‚7“ Q’rg<w2õ~
+ìώrSÊ·aËèT`T¬ék+Nõ_¨ C콧ðÅãðÄÞ/É<flïQR}áÅÞG@âòØ]ø{؁t­jõw˜mT†{mzf¤6ªGjQE&‰©³L¦ .ö™=ÉÇÿ½ê!K#=µ‡q:ý~_ü;<ÚÃèF&¾fû±CPãe®àÓ8¯Ý=Ê3"mdÖ›¤®×õ¡Ù®9¡5¡_ºtïpwyÞr¿íÑò¼Îfç]öl>×u-#kÈþÿ&¯}%ò©‘x3‹û›òu™J¸_$SÉȁÈå,̼I2kÔóå"½!rÓsð˜÷ï^ÖëÍÇ%H\j541 ¤™*ŠÇ‘Ó t’ÅXA«“ó©m
+e*„bB|¨¡(VMzÿ˜+åè¢>ív-ÿ4.ª¢·G´îºŽ4oï§ê¤$70Ձ?wà:ÇTÇBãp•Ì«ê{âßrº‘>Š
+'ïNªZ6pÓÔ^µÓÂÉuÐ^èÅ-ÑÓ}J'372!sf&i GéÓzFoLnA-tQd çYvcµ;t/æéÛJt?.P–:Ä¢ö²zú¢žãY‰ðoß;ÚYËx²âßjŒ3âÙÆgMzì—o\W¿°v¾qÀ·™e +Õ× +/1jȟú=úPtý¡x罫¯K+s‰55íë&ßW›–åO;|pü·æbgvÅàIÅ¡²ÌYÀòµ +©~Bz¢ ™ç•þšò2ϵbžÄO’'Ù'9£i?|);X7ØRêÎÖêj-Ã= H²VâˆÜôÕ~N°Ò¹°h4$;¢»9§s 2ÐOß´¸ѓ —·2Éѧ{+¾þCÒ{8M÷?P-¸qXƒ¢™ÍϖgÛg;ç¥qàý©O¥€uæäU¶Í¢¾à•ò•Öb×Ýí¯Åã½]Sö)æÈÈÛïY5gÖîpâ§âŸ‰6%ú8É{®®yûžƒO=¡¾™c¯„•àBÿ¥Œm0DÍQû\Ã<ó<ûÎÛ\[ÉVí›Æ7Ÿ?v~Ã#~cùÆvž· ´ ´2²×8£ÚyZa¹Ì^æd–qË k¹5†õ®]æö.óA»¤W%ÔÑ«›5¢/ÑÑWzD…SDw³Hž™M¤@U¤@=T²äô0¬uŠüÓ\@…:šÐêÀÜp{„€Õån¨ºô¾NãèÓ᳧Ãô~ãÉpòù=À¤&ž&Ø'ÏôÊ8>ùQdûÇÿ¬ŸQ7ïΕ7Õ϶akøìo¾‰ÿÛO¿ö%ù®xü„v{|Ê—_µÍbgí¤þåàÝ´”ÜlV
+ÌQ>*GÍIiÙ¢q^’šÓ[ÓÉ &¢d‹¸F1ÕÚQ¶j×#’dUÅEC¥FÑk½¦Bväêu!L%Å`@îMTv¢ËÛPqq„-ç’£ZuIZõŠ@Vtóøyò<sRZøÆh Pš xÓS_.*ì´øOUû&Šÿ­ýnìê5Vß>mݪ93×>>%Š³Á;Ðc×CÄx¡y÷u ž{öÐSÛÕsà¯Ùl+JÃÏt!#¬“Mù#Ò£º-Æ]ÜNùˆtD×éE+A®åkäºô]ºƒüA÷[òÛڏåÚóÂ:]š!ͦ€†°)zSÄ`{Åöž±©Ò^©B½ ¹O—Ô\¯oÒ½ÓL½˜ƒ.O—˜Õ# ¯?y”‘›„á‚$t¦©P1€:m£Ö‹Ȟj6ÓïoXÙIٝ©PڒBT˜>5}aúöt6ݝ! OiÃðgB§é÷?V§’c­t*éˆ@;©®VwûÊ^ÕÉ1PÃL‰J攪¦°½¯*¨YÕoQ˜Ë)Ñí
+b’<D½­
+TªÞDOR +Ú¨v¯W€KzÚ©žv¯W€YIkC=hW |çÕzm©ˆûÁ`¦2Ž˜€jK[’ÞŽƒüˆ¾ÙÿóêyØúÁilæ{æîiC'g3Ë'ÝPQñ¸ÂGŸ:ðÀ@Âñ·âÇîÜ8ß|ûÊaÃnUe?>–mRwÐB<F™¾Ì»ÖKÌZ]sÿ5ºÖþ¬ƒïÏáRÂ(xÆL1D­Ñ¬I¹“€Ô› çMç-æÁºûàœ’|pzíµ9Õùg´½ù~س4Z&O«ËÖÛ¶Ü2g&•€ª¨­7©LêÐh“0'/)Á¬$ìI
+‚dó¨ßTŽ.8Ÿ!›½\@Acœ.>/Wr;颓\.·{SÜ–`§"£’Ì€ÙUtqõM­?ãicïÉ>eÝ{6õœ®oÿC*qjçí’6¢N¦¶}†A_£)§6QJÅ·¨ëÖ0Ï:/kNîìð¼Bžjygwôí{¥¼ú²@G)øCàùa£¼üՏÛp•è͙´ ,Ë¢[ÑýñÓ1~åV, i>²)þ×?]¸§iÎýëæκ§&{ -=`ï¼ñ±lúk°ûŇ/\{ôðüŠ®ûõäžçŸxêÉçÚè_`û%ø¨QÐkvÔ®„ +؇ËéD‡â¡¦?â¿cIàì\&i0Í5q‹Õd¶0V‚ +”©^FdÙj“íiä()þÌÈ^ '$,¹Õw0홑ÍÎ6'ivžq’ïØ‰¬!»M]¶P·Í†ÏØ°Íå¨L2¾eQ8u8©s©;UÿQ ý4ðÔ¡šbEò +ML7Ètbƒ2¢ª{ž&ñžuǦ=^獟ò½¦fAIül‹_nѼnSï¤ÿÎÉ¥Õë×ô~Gÿ»1’|ƒU=uв.$Ñs&“\©Hõi•bR·t\ú^â|R“´Rjƒ ŽáÖ·¾uEO—Ô6Ïñ+ö U™Ö%¦ÆuiàŸ7¶\v4ú|QØB‰N¾?…]ìAÌÆ/ü4Š +ýôYß;¶*…ãÕs1%—ÒÇÕs¤•‹qÝÜqîûäaØJ® +28 †m– aÔG r±ÿDIªïÔ+¹©³¯ñÛ`¥gãÁ](°¡/Ð,Zo×F˜ˆqF‚Õd¸8ÜYÔú™ÂÜñRSnkîöÜgùÂíþ€6–{<·'Wr së¡à•ÜÏsù\ŝ©„ûVµ¬àöÚé•jõ*é¬`4™²=ii¡lØi0†Ì&eri“ /æt’Åàö„¼i·0 +7¥á4È۟
+eÓ]´¡luc‘*)TÝÙP5[©‚P!3;’­ º&R˜ý^öçٌ!ۗݚ͠lvQv"›Ívå|QÑg§6%×Å9ÐáZ×ÄQuÇA-\öžÆ¢05yqØ°Q›×¡Z¾»*žÙÅ󒤮ÀÌÆîÙ[Šjž¾aÉÓ9 ¯Þ챃çö‹ŸJ¯P5· ~Š +=ðü„‰'L½¡z[o”L}²_ň[â„Ô<69¿fÕ#½’gŠlæ̎¶+NÁâ°LçŠl'‹a¶ŒÕbµá#Ç«ËÕ$èu¼V£óƒà©Ë|OúFí¿X®²&¤ÕSþêtڋ«6ù¡Ã•«VåÔ?-\Õ±¾h¹®X¦*“`ñ²Ñø©Ì±å#‡Aø¹4>Zç#é/ÌX¿ª=îcCï6wÕt­Ž›äQ©,حʈ¯ñ)ñË6ö-ò5GÌ.Î%‘¨q’e’=êÜJ¶ñÛÄ­ÚNé#ò;î÷ÒGÚSÜ)þkq§økòüëâ›Zn‰¸ž_%2&U
+5Ê"++XËw“§ÙC<úºÂäLîIC¬O£KóŒ³Á›çd1Uç¸Ñ1'_’¤ï©†².ÓÝã6ô>þß8ç»_Æ؀ý[,xøá ¶Œ{1¿!þÖ÷ÿ}Ubד»vµ=¾kïÆøÍìV¯lÎG•~-#,ÄaÊu喈§š©i©öüÝ#Q¿¥Ï='üÝ#Âú¹ÜG±k4Fƒ¾ÏG1åêõ†Ñ¨ŸšôRFŸ®€‰4žü'?EÕ·t£~Êe¶'}ÉF%=õ.]65?/z#æK^šß…IüBWæ:˜bûý³§ß½fƜu0µõ3ãŒ÷ÆÏÅ?­™Øû +Óձ牎OSûs
+Œ}:ŒÝ„¼è ¥Ì\A"ºˆµ"m©ÖU[G¥‰Í>ìmŽH”‹Ê×ë&Y¢Ž¨{’w‡¼#í¼tN÷ƒUkBze«±%5Á`ä`d§›sÁÛ™Lª£&m2b£Û—ÜúÏ]6þ³ÿ0üpKŠó¸yòlË<Ç<×l/0›xuãNztç¾üuBfdÙ³S,ـ™îùU`&~fõÌÙëWM›öËøÍÄ~íøuÛ±#ì›<å‰k˜ýÏl:¶÷±—¨·¶!¦Lý]JÎVKz<ž›Í-á˜Bsƒ~®¾ÙÌʒAëӒMڄ–Tjë´DÛI–)¹‚+œ!¼œƒ$£T$5K¬ä^iÞn&SÍ+Í{ÍÇͬوB˜Q%€VÜn­ËTمÓPŸ³zqAŸkt>‰œI/ÖwyqRZPmÌ1ž~ôOßK+U¿5HʂCP—¹ ·Ñ5=ì¦ê¦èõ×^3x\!ÚzSuéßúUíŽÿ7Œ±V´ƘG^Sºy³&Gp›y›uköÃy’`­±ó]—þ­À—Áóºs|®n¢n–îaÍVóΌ.­PT2«Cs2f†Öš×Z×dܓ)•…†ó5šQº:CM`h†‘™*ӖèiAi¦À˜I
+8uÙڌŒŒ ™¡äߪ]n½Í¶4wIÞ:Ûª¼GmçíÏØÔµâMŽ{ä=ŸËç»FìJš/â³ãÏíØ^"ê³6e‘,Åéd¹ó՗
+`ß©ÏÇEù¸0秊@¸JÀ™MíMÉwÛäÊäÎLϳ]á坔å`¿QŸÇ¤t¨úΠ݉N£Ô‘G)1í8”1 P˜€£Ž™xžã–±ƒ°î@ɱè´$Ç=•ÅlMŽ¦ÞÝ5¡²—¾|LÒ¾ÐØâ¡4¿¦vt 3 3Ô¬LzßÓáËLÞ»Üê½âÄM:< £&c›î¡Œ_e|˜Á2´:–u£”¥ŽJ¨ÍÞá(¨Ä)·F½ÏȊ¨gR^ØýNžJ±M¸ŸÁ }´GϨXµ¦Å51VF#OeÏ°„Á®@Óö‡í:hÔ¡”–Eôy›CÉʅÚ58|ê£-Ö1Ñ­ÀþepãzwÂMRƒW©Ô‹¾ã×ØBßö[”¼M2#u®”zE®Æä›M™‰wIc®4ä@|øî ®\kՖÓd»–žT}»OS®:d˜×÷½]œü/;3;õ&÷GNŽÔÇzEØm^0㖲,«mdü…)+>ûò³sâ?˜¦6,,ò§…ð«Ñ†³ßڋ Ãã&æ¤úmVSíIl8zÿÆþC†úìÁt[ÚìQµk~ùÛ¢úñkò÷슿Qrý29×0H?J5.r2vr˜-Vì0+v2’ Z'e·9Ú1Ó ÛÁ8:1ÛnÃtÓè@6ú-ébE¯ÕH…r!ßoªú,–UrœLÈažh«´n·îµ2MÖVëfëqë+‡¬F+ý µºÜËÛúÌ©ÚXè‰Á껾ÖD7=¶º<µ2žuQÕrZýªž¤Ÿ”Ðïêǀ¶ ÉªòÔÁ§ŽƒLÁҒÒ,¹½[“–=Ê9ý×Ý^®‘îº »ÙPO|ÂÝá4Ïgy%c‡÷¿×óÁ³ñõÀŸû@ˌgC`!=®8®7Í1má‰wñ¤ÂTKjM§ˆ ú3&VcG²Íj•%Þb +Ùlˆ*H½]µ“ì8kþßØI’xÑ@ñ‹ÿÚ­In2ÿ`5&â„BôÌzé,Œ3èؼ›v_‡]¾q•#åa×ö‰Óoܽ…´Å=³×-9‰»ÁQ€qjÀœ ãÔ`bãr܅F<D1‰UÅïy”Å<£EY«?Œ˜·ä–3Pæ-ÖöÅîõGdÄi¬È¥ÉByš¤Y‹¤ÔûÜ2ÖiÕ¶4’#Âb$aÉô̦QýÊ¡Ü£˜5Hf5²$‚yHKåôy âLˉht>õMOVçp¸r¥\§¾lR¤hXR®a+Ù:–a“"0Q[ƒ¶a?ýλ´¿jK愝£O7ÂNÕèJ~UKïU ݨ¾¥ˆui‡é3’äÛä8`qЇϖƇâpöۃ¼Þø.ā{½:0Ü^P@ғ<ÕO›TžnS6æo³d›Ð…?Îè8Qp³N>‡/CÅ8Š—r‡…xPƒG Û4çùó‚”ņ„<9Â’‡±cä×Yñ:y•g²·ÈËñòCìá°üû{ù‚¬cX¼j;ëgóä¶R®a%ë’Écä›äì!öù+ 09f'É`ѳ)Ŧ5E0+ ,"*ÕS4(9˜[I¨¯ö({f„ ]:YKŸÑ`šTP¬ ]vÚƧNÛÈ-í|‰@ш³êtÛu=:FÇÐlR¢¡Ùæ3ɇpɏ?g]š£zÎvÚ5Úبž¸ýã[¸¥ïÌ-™Âÿ«½ó‹‰£ø7³{wlÛ]î8à°Ð¹¶
+\¹ksÒÅó5ˆ=›bPŽpÀ¥ÀÁr­iR­/} ±1ÚÄh¢©<-m!­ÛÄãCÓÄXclš>Ô¤mú‚6&>àßÌ.x +ñ¥¾¿ÜÌ7ÃÜ·;vvo¾™w¥6¹n|Ó¢"ƒ‹èƒcm㳧§mnr³; Ö(¯Ì¨¢T’cÅÈþ+ߓ‹“Ùâ—7nÒmT)Þ"ۋÚß?’Š—x­êŽjk5Dâ‚-âY¯«4â5#î㎗;žŒ£¼½nÁ««¿î5)„¼jˆªŠÂmÁ¡A¼É/‘sØԍ@»Þ,Ü +|hCÜ›âbÄ#¸¹1æ¶þ¤bÕEâ|Æái¶4*B”P
+’$X›wÅ]³eõwn/Úꘃy‹w–^`iÙ½æw¸é«Ýiïdm]}Jút1öä¶ú—Î›Ø ?ƒð¢jÂ7%¬­ÒƒÅ$b­…;mú¾¥ªö„ÌP`Ýofàþ"†]B¢¼}º‚ϽÍb€]'­Å¿È¶âlêÉÔþc¯ì}9ò\bè^N:}¸J—†º¶VÝ
+Ì€RəîKÒ&hÁÊðÁI’&#ð”&Ìè3Þ70˜qÚ8gÜ6<Y¢© =­„Ë4;x~¦¨EØõ<?¡–ç…–à a ÛÆUèiFo™&œoð£Šm‘¾Ç9*ÜÇô1«ŠÞfe¬¹’èÑôª8ó·ô´RÂÖÕð6—àíç²ú}WØ-SVˆ°`8N·X*DÌyU¸ÅRCù.˜¼^i晄ˆzïèÚrÕ³ÌfÉ óò òlq…›,‹?ƒ»7ü·¢Œ¶;¹#ïa5X&ýÜÞ_ò+~ð“«ü·Tø™•Vɼš§GñÌ¢ùÞ±éۖ´Þ‘Sãxü;æ=hÇ^3Ö¡$¢aU!óׯã)¯‘/<_+>0°~>M¼Œ«v^â±Ëå¤êæ'WÉUZA-äMäWe«ò§:§Îyú9ÞÞkâ›­èª¸©õigµUmuÓȦyÁJ ã•ÀŠ~ÚøÁ¬7OT5#wƒƒðaè“êÚê‹á§k:ñÉ0Z;WûSס‘·"¿×OÔÿöÄ`ƒÒpªÑ׸и°åSöúÞYç£2®<6+ÿ‡¨¶NÓ: ‰D"‘H$‰D"‘H$‰D"‘H$ÉF@‡³Àß
+Çÿœ +Ù¹ìƒ! ­í>ž€k®¬€Ÿ/9²Z&{ËdÄH%ßq^Õ\ŽL †t¹2¼êÊJY¼Z&{Ëdç|΃Ð1„Á>ƒ,ú½‡IüàL‰˜†l”¹›ÁøœHцÿé†q„AãFñû˜¡,úYL}Ýa±§‡)2"mN¤Éৠô +cš ôm8ˆqyyœs9ÃvvÄblßX–õæ'ó…#SY–ÊÛSy;SÈå'ÛX÷ø8KçFÇ
+3,Éڇ³ÃmýV:ѹ;ÙV˜˜ê¶s™q–›aV°3ÃىŒ}åGþ[!ôƒ…M@'ì†$f±€™˜Y…C˜Qž!·@©~Ù¸GÀ?Üø²´
+endstream
+endobj
+11 0 obj
+<<
+/BaseFont /CIDFont+F1
+/DescendantFonts [ <<
+/BaseFont /CIDFont+F1
+/CIDSystemInfo <<
+/Ordering 4 0 R
+/Registry 5 0 R
+/Supplement 0
+>>
+/CIDToGIDMap /Identity
+/FontDescriptor <<
+/Ascent 905
+/CapHeight 715
+/Descent -211
+/Flags 6
+/FontBBox 6 0 R
+/FontFile2 8 0 R
+/FontName /CIDFont+F1
+/ItalicAngle 0
+/StemV 7 0 R
+/Type /FontDescriptor
+>>
+/Subtype /CIDFontType2
+/Type /Font
+/W 9 0 R
+>> ]
+/Encoding /Identity-H
+/Subtype /Type0
+/ToUnicode 10 0 R
+/Type /Font
+>>
+endobj
+12 0 obj
+(Identity)
+endobj
+13 0 obj
+(Adobe)
+endobj
+16 0 obj
+<<
+/Filter /FlateDecode
+/Length 24310
+/Type /Stream
+>>
+stream
+xœì¼y|”Å8<3ϵ÷>»Ù{7{d³›c I "y8‚"W8MHK$@P‘ rˆ(h+*à²„€áhIµZ)X­­Z…Z<[”ZJÈîûyö ÁÚþú¾ÿ¼ïçýðlfæûÌÌóÌ<3ß{f‚0BȌZ‡jG+.•{-߈®ƒÜÆió¦6½3ûe¨ÌGˆØ§-Y~<ð‡¿"Tz=BâøëšfÎ{{Yýf„ÂUpÃÌë—]÷RÛ²gêہPÓ3³fLþɂñ§à]‚ÐgdØËôÏÂûpŸ;kÞ¢¥ý‡e{ᾡÀ +×ϟ6µ¤ßÈ0BÏÍBÈ×6oêÒ&ûÓt(ï õÃ7L7㙠s^CèPúcmšß¼(]ˆ6!ôz-oZ8£)öþȃÅ_DÈøKöm‚wó¹UÓ¦X«þ©ó뽞øK^!Mß|ñÍýgwtΔ‘Î·zVŸ^JR£Ð`Ýqö&u•h×'4Ç\ú"UÁØ$£b4!þEh—@)Ç­Å¡T'lÊà~5åÞA×»N F‘'ô⏣ÂtZ:˜õ®ñ#‡‘‚Âa¯ðnj .“àVát: +o ûé—"^Ìt‰TªÁ@×h”²ÑLžG·ÐÐu_‰ž‡ûî£ÏòÍh„cª L„àË䍄0Â8zu÷¢ÿp ӝÂD´Ix]á1€Ÿàÿ‚¶‰•h^¦ÍƒZ]x×&ñyô …¡|Z×;Þ@Ãs“á¹’ ¬ÿq;ðž»2i^·ï«‡w^ a5P-¤C! ‡:Y‚°¿Öâ7ÒOÐúßí¯¡ù†dÒ+à=«àùjx.îoØÇú‹BB>ú/ýæçÑ~ý[žÚÇáZ@ÿ‡‹öñ¿•se@¿ÿÃß÷ úÿÐÅ7§Ïÿ8ææzôÿâcäýùsÑ¥ëÒuéºt]º.]—®K×¥ëÒuéºt]º.]—®K×¥ëÒuéºt]º.]—®K×ÿ¿.’Yrt ŽBØA¼°4Š ¡u.¾ CB:„Œ&„¬²ÍžåpºÜ¯ÏÈVëäÆâyù…¨¡âTŠPï>}Ù’æ¤ 4xHÍÐ˯våð#ÑèÚ1cǍŸ0ñªºztõä­•4šC£ùM j¹7gÒÛ»zs÷ÿ@ŽÅ;i´ý®÷YL—µ¾‡¸/]•EˆsP  ~èr4 A—ÑDt5j€î-A7¡­h;J¢6ԎÞDÇÑ×è4y=œöÒµÝ̓ù0áÉðäXöd#º-ýѓ_\x2ý—ÿú›¿wÓ Üô#éu¥×¤äãôßV´ÿûeêÏG P‚aVO?P©pYUÿ~•}+z——•ö*)îÙ£(QXŸåFs"áP0;à÷y=n—Ó‘e·ÉV‹Ùd4èu’(ðÁ¨¨&:´1œŒ7&ùxôŠ+zÐûèTȘÚ-£1†¬¡×I†YµðÅ5¨yݏj*jM¥«&–ÃU¨ªGQ¸&N +·ãIcê¾{H´>œ<Éà‘ ÞÈ`3À‘<®ñÌNâÆpMrè’Yëj‡Àëv +ƒ£ƒgz¡#€F€’îhÓNì€@Ü5ýv¤3C§’¾èš¤7:„ö ÉÅj¦NO֎©«âDê{%ñàiÑk“(:(iM°*h0k&)NJ¬™ðlú5è®ð΢ŽuëÛetmcÂ4=:}êäº$7µž¶aK@»C’î›Nx.ÜÂËíƒëÖt/õsëj<³Ãôvݺ5áäÖ1uÝK#4®¯‡wÀ³$6´qÝPhz= âðqah¬ª¯KâUÐd˜~ ý*õûfDkhNãœpRµnN#Lo]]iõù”½éãÈW^7¾.IVû£õS‡v:к±Ëvy•°÷â’E;e›:°;-Ö `2wft•1ˆU§Ðð±]#‹i¢Ã!’áiaèI]¾©/fôEë¦õ…jpÕcx*9fdvR?¸qÜæÓç“BLŽ†×ýDOþí✩™1&ÿQâIªA¹'‰da!Ei0Ì)ôq»ïÝ£hI;‰F›ä0$0|¨Ævj}¿bþH„Nð]í
+ºn’-cêÔû0ºÖߊ”âD}’4Ғ­Ä9–´h%]7F“Û p&uñ®?«ìʪ™Õ/‰]ÿ¥x†Z>|\tø˜Iuášu™±>þ¢;µ¼oWYJf +®ãü$?ÇJ)'wU¦7u¦$ƒ?‘!õôvIXÉrpxhRn¼Bë +‘ÈÿøP{ú}Š%Ët3Ù/qñ}ÿ‹î/êžiæãdøøIëÖ.*TS–IãÑøºHxpMʌÁ_{º£/ +õþ¤C6˜VüS³2·Uôgàz¸(vö(
+Œnݺ¡ÑðÐuë¦¶§[®†å躽äòʺ¦šF +qÚÓûîò'‡®¯‡±š…ûQ4hg¯³SÁkÇMªÛ+ƒÜY;¾®•`2¸qPýÎ\(«ÛæÎr Í¥™ô&LoÐp ÙJt¬¾/HèVʳ v?­#–§Óò0šÖNÔ<YË#Ç«y
+Ë£å1ƒÇ×uÇF’õ=ڋÆsù»âžÐÑ\:p­‰ìÐ^.ËníRÚ¹è.»³Ô:°†6‹Y†x>„rTJO႐/C¼B „B8
+tˆiiÂ|[ §%\6h +‡äyœžõÂ7X97úB‡BC +a
+„ +¶@Y=š3Â
+!œb%
+çn½¯ úîn½‹%»æ\_Ên§ª·“Øí®«êÕtä52L­ÖO­Ö«\Íî9HMóŠÔÔ+m¡©Á\Ú1ÐŹà#]Ðñ&ˆ19„¬£ÚÊ9QáÄLŽÂÙwåÆK·äx„9Âa4…Òn5ÛJHš|‹ì(D¾!'Õrr—ÅVºeà•äS´ÂAù~&F+Èq:æWCØá „#¾… ’ãð;¿OÈ'ÈJ>FŪ!L°ÂAßBÈÇËäO”?±˜ÂÕùÄ2ù>ë#ˆ­äC€>$B×Þm­¨,ÝˀDqÅ2€ÛŸì®Òvò»Ö
+£â0ӀQû¹PC˸œÖX¯P;çi­šj'ÙN„¶,!ï¡$ªø¾-¿‡Âj!4Bh‚ ô>@ï£!l…„X± !Lނð6„÷Q B-9Ú
+Í´“#­ñA¡.ò[òrÈ&¿féÛäu–þ†¼ÆÒ7! +Búy½5BPŽàRÒb(ȯvåÚCé6rÆ.q1„j£!L°‚H’œÖé!;¼d?z Ô÷iE_±ôô„)sBJ|0 `˜Fñ~—іð–8Q⛂[Åï¹ ÅïXâ7­ˆFñë—D£øô9Ñ(>i
+@4ŠDí䱗sóB£çâð@+¹FéF¥a”nD<¹‘þÐ<íÛ텅0b›•DAa¨en9€[Æâ–'pË Ür+nY‰[ªpË5¸%[¸%ˆ[ܲ÷…¡hÁJÛE·•Š·¼…[¶ã–fÜÇ-1ܒ‹[¸Bi'‘Öae,©aÉ®”è ½lp+‰ÀˆFç#ÀB|BšÝ)P)œ£Vöiš³«°Z½ïÙ¯tþÀ+È«ðà«0 +¯¢cx˜ W^…—¼
+/°B\ +a
+„ßBHC¡vt|‹­C¨†0Â
+ßBYw¾…@ÐüLw°Žg:=šÞ‘Wá—¿‰(Ùr@NÈWpØÄ£ƒé ©@.¨v›Î֎Í{þeþþ_f¤¨'÷ +(&bc&ÝÐúCv¨?ØßèÄ  X‡+QÇ í‹šÙ}oÐÑ´È –¶&ÂcÖÖxQh¶Ð§ö„~œ}h'~ØúC¸Ç­¡ßCÎ {Bïî ½YÜ®ƒœñv ɾ0«º7Ð7´ý-Vu%ln +ÝJ“=¡åËCs¬`†ZpM3Ü)ÖÐØø¤Ðð¾!kCJ3¼sO¨:pM¨J­Õ›>³'T]H¨`!t¶ ÀÙ 'T´ãYJ‘´Iª“FK}¤R©HŠH!)[òK]'ë,:“ΠÓéD¯#:¤s´§+ j1;D¶áXäiÌ3X&4¦Æ5ezXGЕ(™Å +'ÃÇ +ÂÓÓÐðkÃÉ3ã¢íØڊ„“öáhøøAɾ‰áíRzl²"1<)Õ^]·ã{ê!7Iւ”_׎Ó4k•ŸÚ{ƶUwûiš¿êîúzäq-©öTÛØ*‡ù‰¨1'.\ž‹àìä¦áãê’Ïg×'K)Î®žü5öâïð©š!{ñßiR_·—€¿«Kó¹Cê뇷㉬
+ã¿C=À˜¿³z:Ì´
+ë‚j½Íj½<õriõôzcõbz=«ÇcZogsn͐¹¹¬Ž;ŒšYfw¸{·bP'cu\-è-Vç-W ­“ÀªP%`U°X•ö±*/T)ÎT¹³«Ê¬%_¨P똏kuÌÇ¡Nâ½f J$ð®þõÓ&S£«1Z3Bcò®%³<ɖkÃáÓê3ÖX¼ñÚi³h:uF²>:cHrZtHxgÿÉ?Q<™÷ى&׌¯Û9Y™1¤µ¿Ò¿&:uHý®ËkË+.jëή¶Êkâeµôeå´­Ë+~¢¸‚_NÛª mUж.W.gm!†ãµu;uhP=èø,ÝEŒÀ×F¤~KnÀ·Äs«h+ېL˜Ïf´¨ÇÀiÐ-²PË:S乵ĿoËɐm‹B‰E‹›#OÍì!ê_3\µh1p5N4ÿ§ ÊjÀHÒ¼¡áÉÂqÓՠÍî”$Èm¤Ÿ”ì§å5 Û«™=!³Í丮Š4¯Šæéõ™Šÿ>ÿ‹3é`J-dÿ.¬ñ"Ô\Ï%ƒÃÇ`ã3&Ì>Ð¥¨xh®‡lÆ Ü¬½#ÓíD©÷ˆ~³-Î@™±X”IÕ'á‘fmHº.:X‰®[/DÂ>ä…àžE^>Ž<¥¿€ð%MS³Ó_Òrš’¯ÑµgBÛÐv<mGÑ+ø<µ 6DU !èt ú9Zbmä܉ÆÂO€üŸcoº +£ÇA°=ŽCݫЭhraOú+´­âޅ§V!3ÊAQ-šîÆ#ҋÑdtŒ¿U èԄ[Òué{Ò÷¥ŸBO£½Ü¯ÓÈˆ|hü§¿þ˜þêO܏BÇð}úÝHVZ æ£h!ÚÌ5ð8=3}zA7Bx4Æ$oŸ¾À| 7Þòd:™>µ¨ÍB›Ñ>Ü_N"ÂäôÈôaä‚6–Â[B­hüÚÑ/ЇØ$œJ?•>…¼¨ +ƒïiC¿Å\ªseªFL€Q*@•P2ý½Žâ(þ™/˜„RAnJ¿‡¨š½}žüÿ‹Ü
+¿ÜëüÐô dq¹—Ž6z +ýûp1'’2Ÿ<Æ-D:h±ü¦£Ù0ÞÂÛ?4ÚCLä÷$ÿNÌNO[`Fâèaô(ú6׆q3¾ +¿ÿB“)äaò)÷sþ9þwÒTøêkÐ<t7zý Ûq_<_gá[ð|/~ÆGñ—d Oæ’o¹YÜîü øã›ùۅÕÂ]◩ºÔ¡Ô;©¥KÓ«ÑÀ‡•ÐûûÑcðe{ÑôüŽ¡O±€Ø¿0Žà øfø݊ïÆOàmø9Ü­şâ¯@$ýŸ# i‰Hü üP(J‚†ùsò9¿£äoäÎÍåp ®7WÅÕsó¡Wk¸ðÛÍý™÷ñGø4Œs©°IØ"l^^N‰&é6ñoŸ²³°ó“J­MmJµ¦ÚÒFN˜C`pUAï§ÂoÌ÷&À¸è]l‚±óáB<€‘™‚çàx)Œäx3~šõý%|Féø[賙XŸ{’Þd +¿kÈ ²”±ûHyŸœå$ÎÈY9'WÈ]Î5p3¸EÜ2n—äÞæ>æ>åÎpçá—æ +|ˆÏáã|‚¿œŸÂ/æã¿à¿& ¿> +â<qµØ.þ´šR­4Fj6H{¤÷t€¯¢ÝèåîŽc|œ[ÉÕp»Ñ=¤Œ÷‚ ó[Àç)h:7’¦’mx-YŽÛH®°TìOúãQ臱~l!gHn$ŽÇ¡9¤—ú6ÑÁ?Iÿ*:É€oû-¼y©h·’oEjÅì,~+áÜoЇÜ1,ñ£xvã“äY®°àü¡E¸GÐKܼí&5Îé֏ÂÏ_Kñ÷\ÔàQ€EÜ_Ðíh.ù#: t¼=€§ó3Ñ=¨ ߂¾@ÏU7ˆ…¢¿IfóëHnC„ŽžQ¹˜èÜÀm¿% Åèo@Ÿp/B—¸‘ü)a,ž°­F Ò+Ñ2¡Žÿž‰8<ÅøãÀÝnáJù¤+€«Lž¶¨{ðÜHÈñ挼˜b3ü>ÁÍ¿
+¸ØoQ›8ž´£™‚×AˆÿMj,š”~=”ž‰nH߇z?X“¾Þ¸ +}†6 mxUêfÔ¦ä@Û#„¡äˆ04݃¬#qdÓÅó £Ãô5ü^‚›Â~´Žÿ‡ªÓëÓ¿ìÎûºÖð•ß@ Wp¨,5ŠìLåšà{¡1égÓ!l@³Ò×£ÑèzZÐT)sœÄ¿ƒï½Í cӋ¸©Ù0`­ÅÀîm˜1<.ßHEl[ "МÑù0×q^Ð9æ;h¥Óo‰[„w‹»‘åÁ JŠa£w£ÌÒùü~j7Z=^‡ÇãõøV¯¯WÂ~€lAz8Ù¢9Ÿ×Ëa¿Ç˧ù!ÈïI¶´ÆŒd3J@Oz‘Í»r^ì-Ò{'Ü[á•zê„Z\~Õ$OB>ÓpòôIù D¨údçI¹J®ª† ŒmöÊJÖôL,—õ*ñ ^¦ŒÅeÁD•…{…p8@Ź™‰5„ܼ3„m€²tfçƒÝ¨(¯g•D!²`S»ˆd£=„DH“ÐXV↬ò>e¥.§CŒæÄqŽèt¸ÊJûô.s¸ ãÿPvãc›Öí~yõª¸rpý¤AC p9÷ÿ3þì± ` +ô£™5õ“øIþ鵃ûÞ|¿¶èớm¾§ùl³¨ÿá_øžÇ>¢oàC‹^¿ˆÀ`ݒCaždt™bȳ‚ýc—t²ÜŽËv¡-¤ŠMÚb¹q2æ8îEÛ£ëÙàvž¡ƒ‹ªaP{•à'¶òŠ>e¢?§Œñ±û;rҁ•Ëò.‹Â÷§ÆÀßcË7vž;Z¿nÓþ_¤B©ðEíÏPLù$_&zƒŒ‘]O{`ØÂaHÛÐîK{úT›,“ |ßfµ2àD›Ù̀¿)VƒL°ZBbyўé#ñõ3+Šlåyqø•¹Ü.§L:WÂää\–wÓÊ“FIÁÇñŸìÝ´nÒïÎu~øM껔zù|ê|;è4j·ÿ±×*qÌU‚ +¸
+7Hì+õ +<w>p­@[?=9Ýpú„|0‘¡ ¬â`¯’²Þe0ÛR^Ÿ>{×^UZه;|xÁ]ñ‘Þ©WC»q;™Cæ½)Þ&Òđ‘x$4EÄ'4A/ßt·'1J>Ñ ŽŠGžìU‚ÀGöŽ8’ܾ{75c÷A´zÏ¡˜â!´³Ujw ~+”oåY/Ï44PRQ;µïðáÃÌNA*a~84n/âҟ´:*I{ú%ì¨|€Ã„ÛÂíà·„3ÆÀ 8dà¾DäK˜·ç q~×Mðæ*(Qƒ5BÏD£9 Óã¤8ÿÜÆTWøÛY]Ӟþ‚· €ÙĪ˜­&“iЫÉh4AlO©Øè½à¡÷’Lc?Í5RH­÷§—Ù<hB@¤±ÕDcI¦ñNBފÁäGÐlvëáa†KP¼™ô6d¢9Èe2Al¢y¨é0D‡a|èùwŠÿþ¦Óð&‘¾ésÀJ|£xF‘¾R¦9H6™hLóº^yámbØ+Í[IØøËôqä‚`‡`MWFñâ²Ö¸Öú¦EÐKF©Éá¼Ò;Ø?>k²s²w¬®4×8-ëzç\o£¹Q\b¼ÉºF|PÚ$¿éù¼/¾oüÈêëê.í-I¾k£ÃÀ÷Šƒ’»Y¯D¢å%zŒô²ž°£5Øh +ýƐÍ‹ÍB l:šikF`3)ax”ž©&ˆÕ@:Z±hcð»(žÁG7$NBLÁ† Ì nXªy_zaÝ sà¥Y²²G—È8d^<K¦üÑ&Ç£9’8aî»[—´.4çÝÇß[vïÞçn¹å¹çn½åÊò.æñe/NٕJ˜J¥^ÝþàËøÑÔߞÝwÎ7³WS,?¨w°Î€>T†Ԟ³ØÀ¾±Ø ~‹9Ål+ŸË¯ ÈC:þEë‘(N/`ÁoØPè("L¹\{ú8ã]|­ØzzYzÁœ+^Š<†0lñ™ €r¾ËBß%à0ØDð÷á*¼
+©„¿@GvÁMÕÈN`3ÕîJl«¤ã‰4é‰ÚDQê +¬¦Œœkøîø>-^Äß<à–ÐK—¿5zYô*Á(‰g/’€2èè(»eäFi…,‡ Æ.FW*5èm²Ù“•%N0Sœ±Ùð¢—e€‚!H1ÈM+ƒ´4°@IÐD¿6ØNö+&bp»Ã!ÙFH8ü±ø½Ã4>ŒŠ)Š$ªi|¨”’éjÐd·Ö ¢·ÚˆÖÎqÅhÏ"‚šGßÝ
+¯V?€P\ÿ›ÂFþ§Z£IÛ£­±Æ”>ý…þâ~á ¸_zC÷f@fª7·Ì5M·Üd¿)ëNûûg¾Ïü§|¦ƒÆ—³ˆ_ÈÙrP F£䫃T3ì d(¾ð9Ÿ.àþ©ó8sPn'OímövìÙM¿Ñ.ïÂÄdÐÕ ª*ãf†f÷»€¼”Xñ~²…‘Œû*&Ûîj°ûæ“„'ûH.¨Nv2²k êP‚òbFoUU 5œ°Ù)®@´ÆÒ3aÖ¬J&¤Ñ`_Ԁf(1æŒÄ+ƒúP­$šÃ$—ª±€Ô%^:_Aܱ'7»í¡›o{ïÍúþwÏ\ñì+OLnß>°jZÇ­‡>»nîÏY—u䃯·×=ੵS{Q
+œ˜þœwî%pÛÎØ|{)°«û6z=
+<OaJ Üà‚¨¤…5h08ƒ>X
+ÌQ³Éãm",Sj KqöN¨/¦Ì÷p1ý!{eu5Èä“0ù'_—_·Wʇ¥4ÐÉÏÌ.syµ™¯±]e[âçƺ®—ç8¦»›—9V›×9îô?m6aŽ!Ñd¶ð†v1Sº»S÷†qòž}ä)ä%³=ôR€nšíÚÛµ)¶wñb{ó”ðü0 {(‰„[$­ª¤U•ºªJÍqƶãÅå8/=ý2}*¾±‡§÷mõ¾‹÷ÑÿífìâÑ‹Úñ}ìH0uYãǧ +]l¹ó¥ PZ(²¨¸œ°˜ ^POÙKV…+£ª+®è5ü "сb;±-tÿÜ;žX^6Âa76·¯ž3{½£-òõKKߚ{ÝôÛ6¦¾|ÿWi|»ç¡5ÉÛnyÜñYº|ÚmwÜÞýÆÌÖéSéüÅ=©~Nµp,YØ|ی_ދLé³Ê‹t|Ì"CÆÂEëUvÎb±s‘Åz•µ³XÒ1†Çb‰ .Nͧ¬c±Àb‘Åz«bÁ^gšeÚlzÎô¦IÁ0ÿœçì@ÞÈ$r’`0rȳù-Žwpϙ1™y‰ÛOö#ØU[ây¨‚Þ2ðí亗Á d‡Ê +šà0¨Z¾aꅡW(fIɉ–K-‘ÞÒF+¡Ä`4;Ê‘I˜p„>LŸàÄú ÙmiÇëÙ|ÿÊ`*7NS²®’?—™ØOW©²UVâŒuÄ?°Z­0ÝÌáiÐ^ Üö=ÅXVÉåô¨äøìì*úŠz@¨£8LŠ±ÒÔR[iR╦œ¤=*ï¨Ç‰¿P,ÈÞ¸ÌVæŒÚ8&›:ï þìõ×ÛR½ñ”§¹=ç¯|:õ8°²û;çR>AõÈð
+âóJV›N;‹Œi0%ÅH¡ LDqS(‹i‡vsM¡aD¤V¢PSí,6zØ|ÓJl²/æB{†Ñ6ÓáÅ‹!ètìT„­< ˜-IöL¹dãXT¸PŽC©
+HªópÊd
+ìLZY<Ü·,{]ö¦¬g³^5½oúȯÓgy,…>N_"”÷@á€ÓÈY§=+ë-‹ÕaÉrX¬f`7JíˆbÙ
+6Åª8q¦S/[yü.eE ^ížmŠ<_^!oyùÿÀT<Œ©x0òÈâјŠgcØ~÷FV|?P^ßVËîŸb.¡‹™ËE쥁ÚBÀPØ84Ø >±F×3!Ê!&‚˜ôÁ ÀNø7G|w~L&+âŒpÀhÓ!QÛyÂ/œ][ÛöõW­ÏîòAçˣ︷ëÝ}úם¸E^wס'6·Ž®v‘¿¿˜Z29uæ7îm=N9ÊHÀ/'È¡lTH¸½ ~ŸbcckÏam´t§¡Q´ "ª}Âb C&V›qª©T“ÄtA¦…¬8„§`û󃊛͠Åø…œ Ãlb“éSÌ<‘ƒn™â”›I473OÜ[âð{‡å×4Üj8)j ¸Õc®‘çïð$ûøð\nº4]7Ç>=¼H·8°J·:ð¾î=—M
+ӉÍSy†H?Ä…"¬@¢yáh8B l´—µfýôãw©îØNEšÖgLÚӆ(¦aV¬ ³bÍ2Ã,°õe`pð§^¦º¯¼±8[_%+Ȩ:Ès±Ø`;®TrªÝSÜóÝ+ܼ›™n6Šn}Öí¢=u·“Ü]‰.KC•cÝQï¤*Ԙ0ƒaÊàsÓëÎ¥ÀæÀR<™¢D%™j:Ñd“+¨\ÎnhȝÛå)6wâÀ גf¶uÞxôŽ?§N<zç—Û?î¬}Ϩ…O=qóMÏóã,sJF– øæOÓSÿúݺ“·âáøüܯ¶½rþã†çëÛ{pÇÑ© Û\³ȌšË!3æáèx=ÊhJæõ&s3Ç:£™ÎÇŸU׬ÿ+ +È4…pՐÌÇ+ÀòZ2Ä8J>Ý° jä铣ä3ÔZ v9Õ+m•ªâGý"âD)ÚÇn¯˜Êí^Ÿ:9¼u/wÛ?îäÏn_ʞ:×þÑvü5~ãê +Tãªq£(*á†îEÍT÷16,y2´“ÉÍa÷Å,î¡éy]¼;~¡:³ìs%ºî}ì¾@#¼ì½*fq«SÄÉaœ<Ðuïc÷gg3º˜Ä=Ø|› ùƒ=©`»…LèÙÓ ŠB~ÐnR‚9Nïa~ƒ„•òJ›VÍР+´z8Í}Åiµ¸.šær&ZÝÉÞèd4í¼à¸Øù@-”“••]>ˆ—YGD­#¢Ú‘ÌaÕ¦}šÀy%‡fÒfé“N&uœìK/|ŸÖ´…‹3Ðe+½]¸À5Ì5,þ¹é«A_‚—£åø~‘nq¡i±ù&÷]h^ϯ֭4ÞaZm¾Ûý¶íõ,{°Ö@ØG“p¸˜&=ÂqÊS¼a
+z º±µ'î6Ò jl$HÙc¢Áæƒz¬ßGf¢D¦RB«”èâ5‰f«^cÅÈ*[‰µß«xK=ŒÁxƒñ0ãiNr˜k'3g.+Ìe…¹¬0·Ù©âa§â$΍½ÞÐdhÌ¡qºK¾uiÏöÊ6ˆT£Êð&×.@ êR)R/÷ÖüÁšòŒ 'Ëэçtg@xNÓõŸìøzî¼5w§Î|ðAê̽׮ž;k՝×Í\ÛoØÆq+·m¿mųœ¿àÁ9[?<¶õº
+Š­=Fwlø?ëŽÛ§L[sÇùôȍ£Ÿi¹íùmš?ŽRväáÖ½È
+¤¥Ãáô¨1“€,Žª”Î.ÒEÊ.™éàô>›BNF›y,Žªb’©d‘.âvɚ³¯íBmÌ%gè—Ýœ/C œÄl šœaøíQ%-N)ùÁ=6†á6æ\±ylE c~ºŠG[8‹Åj1f†¤Y¶‰0Տr¨ +N'ïP¢¡”I‰R6€ü”e*i?~­ËÑ­4>¥©|6FÔÿ¡Õ‹ÛúQSÅÝRÊûùF¸”èÕ®«¢×q×»æùfFoò-®÷ÝÜìzÎwÀ÷µëóð™pÖe®Ç\Û]\¿‚é"É£ÚbhË ‹áüàh˪h“øÝZUl·ÑN„4 iäÒ¼<¡}¸3ÅF:̴ب©´¶]¬&n,¢€â€¡CŒÑQL§
+~[Ù±mL\DG ©34”¡ .%Q“Ô¨anøÉ-;ªV8€ô.Ï£RRäc·1wa3"Q×Tš¶»n™:nymÜgÿ¼=ç±ôú†“7ßô÷'^üüæéEK[Ÿ»eùãxœ|Ó +#Vü±Éä™8ëþx ˛SI}—ú"µë¥ƒ\ùÃ{=²D5PÉ^0MVóq¶.ÖW ó%=«x®
+‹¼TÊõ>®Ë¬, r÷¤¬®E1֐ջÌÉAØ{øða®þðáóÏ>ŒHº!¡l\ YH65;¾×BçÛ2&Ï÷šŸDxÊùÜlY‘W-ÚL¥³*éDóT
+±{ÂèÓûŒ +Œ:]ÌÊʌ̪6Ø{X¬·°÷3Xb0¶Xefq~ז¾gÔHè{뙠bBG`q±\"ÏÔÍÒ7Êk¹ò›Âëb‡|J6ê„z<‘ÔʳŒIù¦˜ÿaÑó&ÞÌ[8£A/ð¼Élщ’dX'š$Œýb+ó¨†%“ŠÇÑ<'Íã¼ÉO郂  ŠœØNš=ҙ¾R&d6 4*vS͐¸±µüþÏmä1ߎ±b¬5uHÇLÜF6Ñ{Ù*‘È
+©E"ÒϬïÿAM/øóÀŒú¼òɓÈS]å;Y}¢Š®ûœ¤«t¥qMOKÕH°°åC‡,‡­Ô|xÒ8nx28fR]oåtÒ¾ô)0«¾§x_.hHü—+ŠËp”‹pY.ž'J){‡Ô}üBçÏ€ÿþÐМ@™°ïìP| 5„L›öÞx÷]TwÛzæW€_6jóàU{3U@×(x~htbôºh³þ½8Û·XhÒ7on7Šy.=çÉ+ º²õšöÖeM3ÜÏLf}–=XXXP€ÙAéP0hC:à)ö„Gc5”w+fªÇ{⢉*IÀä?Wb”“ŠvÊEE‘Σ¨£½æˆŠUâø˜ö¶î6Æ%‹¾-7èÛLúÅÀ<ú“¯úÓͼ0ÐÚÁ0sՇ3~ú3Œ‘3 ã£?ÛÆLDÕko`žú†Dÿɞ./|CU'ÄU£ØýHՙ¦^¯€¥UÉ wSb£«ÑXõ«Q}™-ÒÍif!Q)U}®ñhÊ*(£ð&ßö›æëf®ÚpU˯֧~†/[Ù÷ÊáCo{,õžwM|ð¤~ãï_ŸÚ.ì«ß;ãšgÊò´ÌÜÙ؋ks]7rØü‚s[%Sß¹CÇ.c>ØëÒ_K„w¾Ý=ÌÉ&XSö­_*S(F¥æi¨ -ÊnAwdoD›…¸§Í{¹6óæ£èDö?²m{¶-;›+óm…pèróDÇUΉÞYÂÜì›íwÙ7sY6¶á§È6Ûï-Yȁ|²CöñtY±5¿’IâšüJي0ï3óy½·^‰âa™¾›M›M›M;Öa`oÔÐ6Ñ^ê¼Ái“™­ÓÁ¦f€Œígc +Etµ ­…Ø-òќ\T{nY)ï–âTT§ÃN…ßöÊe©W?;™úÃÃ;ðàWþ„‹ú,{ågÏýeò¼ÏW?ù)!½¾=÷+|Ãï>ÃvÿM­÷=‘úöÞý©¯Ö ²á1àߓ€¾¬({{8„ëTz°ÉA+Ò¹5 î¾wFÉÉ|˜‡˜·[ÏSo`«•–Ú±T_([fã!3­XfRWþŸú_B¯!tð':sÛp÷*¼LéÃù%¨t¼Ž½Ÿ‡ˆFP.‡+Ëʼn~ÎÁv D] ‚][±}…p­Ä +ãÝ.· lø‹”fÀúŽ<†xaÒ­õ‹šGÝtïáU©¸òÞ§{Ռ|àúQÛSo ûœÙ#®M9ôl*õÜÔÒí}zÕ|õÌçÿ*¤çŽžÞF÷:Q›â… N'IˆãéàôA#ÒIۊe{¹4ž»2l›‰ÁgæõDnŒ1 Óÿß`zýà¦þWgp23¬#5FÑ0òô‰ã ½J`Pœ‘Lx‚Ï=ÿ—8ÿ{îaßöTõ‹)óvè(éü*øB=zB¹Œ}á w}$|à#a6â3þ?ú*ªÄ&þÙ§¤þí› ý'ÿÇo:¡z¨îöãïÙÆ}|þ3’쬥ßÒo{çu”ÿÌþ³øO R|~‡ßIóð5º,lçrsQÄî&1$ŒA8i?0ÝA v¢ãx^,W£¤\’r)%1Qn˜ã`$ò™_üûR¦¥dä²ùcZJ}7Yؒ‡ó²Ùe³!ËfC–°±³' Þø´«/b5#å†3™±Ù`P?S—í÷ê:J%õ·ý á£þ€/à +p¢).ǜñP\ããјǜA.kV*;²ÂÜ屁6ˆ‚úHår±ÍF@Pt£S—J@I 5àÞ1ÛE Îå–zàpt«ŽÃΏ«°q#ȼ +©£[ÿ˜ÚÒ¶ ×~´ãûâ;"×ê•#}×`rï­§êqçñ…Í{ñ5|7·ÍlÿyISËÈ1wŒ^»åPêû–©ØFçò D+/9œ£x FŽÅDbx)£lþÀæ 0êՃC:´‹¡ø\ øœÂ†Ÿ¢4¡+â»ú^ÆVÆw••«i5Í/PÓhLM³ƒjêñ©+é…f¹<,lv€ 9n@[QñÅHAµè:…{27"NP×S(%x2ò7B¾Ñ(„¢S;…<Á¿_ߍož\×ÚºeCý‚…U]º]haòG»Êle¶ƒ¯På FŽêc…0rºM1aÂsAéÂT%Ï*‰¨ÃÈ1œäØ pÿ3s:óoŒ^ü)FÿyƒÊ‹(ÅRšÝô
+ùôîÛéÌ>ˆh…þɜ[1é
+ÐÂbmaDƒÂ؆Îb¶1š‚Ñ@ ›ò)d²ÓbÁjâôÞhA:=1EúF™öì˳{h-£ŒèÚWæÛ¾×¾í|ÛEs¨s¬º£C>z´ƒ.O&êø"m£NHb$²˜c1ÏbÅ:àJ”B„±: CÊ,ì‹%͜¡{ ”[_°)l°—[Y$˜8„- Xt aè‡Ó·1€½d?™ˆìH&s†§ŠÚ„°×"êjKœ.>Í$luU•ú1 +Ý°EÝSèWV bÕ9ˆ_Ç/1­6ý†Ò4Ì4ÌÊð1s‘¥Ž»š_b^jYcÖ‰ «4÷±Œ&ù!’¢id1<Hâ6I›tÛ¸g%ÑN¬K‰@‚@t&³¹DШ3µŽÅ
+H:lA³Ùb‘é<5Ú[ìľlCfÜ«UëÚq/ÅeÒ˜Á¨š‡†°bZaÄÆ}ðÁl„Z¤+FšÑs¡°µIÆr;™ørXhZ <²m—­?’—îk¨òtR´d–ÜùºÝžhK JîöóýE-®5˙ÁI¯tÁ°ú2¥Ï–¾ÆõûÌ®ž4AY>”Ñ%ÎïwZ 47³âùޞH¥¥(ÂV=÷TTZJ+¸»äfV6õ`™¡ +Ô-(9ƒ‚ãîS#¶¨ +G±íAœ‹¯.qy{ã)X؟š¸#U'ì;÷ݽWÔ>̝?;”ÿ͹Þüñsaª-Nø±ð² ?v)Ã}V쐿Ûïçy™wÝF?ÿœ{åu çv{ü$œ­ØFgv+¾:¡N•<Á6%k’{Šg¢ï*ÿ]ì +rœ=hÔ;5áèԄ£“Îc Îx”m£ÛèCéMÒøœ¤®~1àk†Ò’æe“¨’PÍhÃג³­Œ;Yw²²—[ã”9©ûÀ˜ÜDb7Ì÷¦]P 4U½¡k?ÓÈï +•=KF‘Rž*ŠL¤UȨ¬ÙÊ ¨ìh^‹ûü}¡-µçà‘Ô¾m¿ÆÙøû—}uïoS oáyøÑWROÿéXjëî_ãI¿Lý+u—cÿ.lüYê3ÿÇA[s yPé§DìF ¶÷ L
+]§›3„Ñ>‹%ƒ‚ÑÁFƬ:ÐT3“F +°·§?Ýe÷•CzjWN^¹Þgç•Ë™ÔšI¡ü»²ãj9ԗ3)-W†³\¸2<Î890/°P¿Ô²ÌºÊ°Öú€ù9k»õKËVøUØfuØlV›Õ¤·ûIÄç2ˆvºKJðèõ.·ÏtÓg¬ УèT¸Ý(’ÃÔEÇjµè‚ªtw¸ŸQôÌJŽ[µ]“¢&cDêÀ/g6ºÈìò†pnSnK.—›ã!ÝÜì !<ÿ«Ö)f´Î7O¢ý·ý”Ö™Aï OÆFQ7}34‘è„›Êb¶ÛIÝì$tíCív¡ŒàV :ÅZi•ûÙìý(…ãŒXҟ(>o¥-Ç[i‡`Q•rŽB‚3ÃõÝ x°j²¢\O†LÔÙêÖ©ÈãdÝ¡·ozëݑùF¤O¿2ᆫzD†ÿ?¾jÓ¨žL•ûFÿzÙ#ïgÇrG-N-À½îXß×(u.æÊ*–]>‹íYœœþ‚ÿ+hË%äµ½(/㍍knY¶Òêf«Ìïe±ÅfÍUcÒ£4€m«½ìÂf ÂbÌâiÜ4¾™[Äó±¼Þ\e`07L‘]’;4oW/Mξ*ÿÎ,K”"ã\ +ˆi@\ò4 ʦ_­¬1 +ˆk@E¡Ê7ÇsI.—ëc-‰ÕO
+OŒNˆ]oœcžk¹Î1óÌx“ù&ëryqnsl5·Îx§yõnyUîí±ư̂¬›œÁŒZÐ#·ûã>}¼Ç*ðÙùÒ^q4ø€¹Ç2ÿ~⏹Ì=‚y1\5Tçe°‡>tqŒ1%@oPUzš4°ýQÅ'՟_é˵˜BL~¿NyŽˆ8–›y`­ù{øŠê|Øw҅z0ۆ)G2ãZ܈›ðF,âvœT,=h“´ièñ•zÍa¯×hTßµ(¦£\@YµÅBè:çi%DßYà+¨Ë3Œ#Ì#€ãvªÚÒÊv í]UûxJ­Þ^+̺]OÏ8U4ñ¬È åž Ñi:
+@gÔÑI[õ ‚éVUíÂÝoÑeUIYiÆæÏÍc‹_lïXÆãt¸]¼›•|?>ùeó”_/Ÿÿü¸ÚÉýS׏™=óÖï~þä«…}ÖíÏ%¯ì‹?¨k¹iõ¹GßHýã!üù†»¯Ô<¤ffÔ=5QñäŒù¿š>û핖»îYyõè²²¹ùýw/Y|¤yÑW”²J@ßÇ<îŸ(^‘ñ/‰Å"³Z¤ÿd»ˆÌj‘~Âv±QH A˜}Äþ—¾4ï
+«æ—Å0&ÅtåãÝ8³_øKÅÈø£.ÿÓTøO5.y^ãŠ)Uu¤oÔíy¨»6³†÷‰†Ïevö@õ×t³;èÖ+j“¬T6¿.åÌÛ·Ÿý]¥-$FÀMŠ!n­ãëtoêxÅNW–³¼œï¯Ê_©[b}FøÒ*™±Ñ-¶¢Þ¡I‡†•œÙC¿Þ'šýDínÕ°"rÆê>®ôdÚwC؅îZit5¹Z\œËÌÞÌÖÌć™Yàlƒ5tÅÎlSňAÃ_C—1ð\#†.1bhpRó‚Q][`¾7,`CØ¥|°“# °£Ël¥£7ØEêÒ«o|ezêÜ{¿MmzåòíËßß#ì;¿óãÔù'ïÁ毸Ñç[î¾öì€QՃn1”îVÄ'•,¡ˆ¡ c¨¼'³¯:¥m-:ËÔM%ûNÛ{ýŠlªH,Òÿº-³Íèku±ÔÀV¾©é¤JœKcÂbƒ/óòÏ&p.3ÌYœÙd@ec$ô:¡øãÃòLJmee€HÕl§ˆ_É-p!Êçb†bS‰©Ñt§îNýFS‡é”É6՚OŒ:’Y¨ÕcØEðÊêj¶üOôú°NpètÉa"8ôÐÔWa3txÑ1#<¿²V‡[tup±b&J~å‚7-„šc µ)óa£Ð!œ0!Öî26nSMˆt›< +Y=ˆâóžô¨‡Q2«2tQF5`´"+àÉß[õvL°³@V×í©µÕú0k±ÿÅtÓíêÆÙ"¸LµÊ0Øùëßáå=C9=ðú×;Áæ?÷‡–¦¥KùfûߕšM<Œó U<—ÀDÄ’ì!’ø/Ä0bK!0<z2²ŠuÎÊvò>]Å(½Ë9›Ö{ÔVæ¼ ßýÁ©ÙҘûøà~ÊãòR³qk©ZqóBBeŽ$¶‹LöK<“¨¿ìÚڋú‡é‘ºÓ?ÕŽô.³E{Gp[ªùƒðÝ©Ù÷‹y¬zþyüŽð
+âP£bäúº½åD±ÚÊéáˆ]pÃÑ©õ¹¼åµ¸–#
+W‹Gÿù†Œ ^@;׊Wsí¤qñò öâbvâá´êÆïÖÆ蒩o8ʕáwîýâïФ‡ÚQW¦¿äü”*È6¥HoÖz;Âsa!ÃÎ
+¿Âa… +æ†Â9æم%ëÌ« 6»ö=gvæk‹yìL…žñ>Ÿ¿Ç»?ÿ÷Hþïœç놸0ݕB73‰ìö š½)+M¡;äI–Wò•EÃø+Š&êê×éf'–˜Ö˜Þ4ý`þ!a«(·`^.Î-w—Fž)ó HA ØRmÙ`ÙbI[„-––o-œ¥kÉÖbʜ{ûZ; wZ‰ÐÓ¶ÁÁ"Ò +–8¥q ۍa±8w;y^1{»ñÜïèÄfºŽjò ¥ÎX0UžÚÝ2ÿ^c?çé9 j²1¡‹äRžQêþ¦òð\ž¢H.uªÒML¹*Ïb¦ÑŸ¨ˆõ+WY¹íäjŒ§Ð}êáxI|G\¨¤F Õ?@Ù{_èv&Ðh{U²½ÁhyIeG%ÙZ‰+éñ%e.}µ›-j»cžœb¦Í3ý¦˜qÅâ܃â‘„Äj‘ˆÆmêæm&Ë-̂a›­D3]Ø&,‘ùeD 3c˜‡WìÕ·ë€ + T}'‘¡°ÃL'»$s %>ûŒJ‰ê“‰Ꙓ®g¨ª¢¶©èKvтÕl˜ÞSÁ~½ËóÔý­S„\N§ÃåŽÆ9Q²u#T⪦ãÀåÍWôžûáL\V³vŲì¤ç†£w®}¾VÖ»sÜך?¹tÞìYOijoŸ0ô…U£VŽrX̾ܘᆗÕ/ð,¸k¸2õʞKO[uY_üq~@ÎY|EãÕ£/»‘RÓj ¦õù¡lü¦r3LÖ\¡·P#Õ¡dˆ„B9²À @ShcHì—Uåªòpð5èÌuÖ×5¾9ºëͳ¬7¸nðu„>0}èþÐûiÖßÜóþ%ûx(ò†…bk±£D¨¶*Âk­pðaö?ù³²IvZx‘ @”°Á°=š}ãÑô_ºŠ¬Ärç5bÙ¨-F^]532Š1z2.Å3še~Š¡¨Q;´g¤»[é\Óe{ã"l#ì`C[²3âà=0œ§0ÐPǐŽS†ÅéÀ ´oÅI|
+ó!\GcSÙNéSšÊ¦Žêa¦a;E=ÌPÓO¤¸Íªºh÷°‡-w°%oì +^^q‘ÖBÑj¡ºÖÀò@?gëÝ°•¢#ü±efŠs ®¢ 6P±ƒÄ)£hNö…Íd=žm[¸óÚ ”Ôw¿80—”O¸wɋO/^ò¢°¯óŸFox«9õmêýGñ¦ƒî:ü›£¯³Ó¢µé/¹“Àu}ø{‘;}JÉaÎ@6‚z[Y,«cªë¦q”[VX±Õˆ©¾ Do%O€7b‹SÒÑ“Ø€Il?=û 1#¬Ãï½®Ú‡Ji ŠÉåzg +vËçnÌjt?Læ6›Ÿ’Ÿò™tf¯a™ÍÍ›šÌ-ægL»õ{ »M&—iµé/„³äL±Î·®°rVLyg¼„­ +4B·6¢­è8:šœÕjDú€®ki¥ÉpŚkÑ1¾œãg:ýi«~£¬d¸”kL„0Ý+–èa
+ÓÔ¦“õaF†Â0BaèpCC‚a'C7'C='ãwÎÜ#IÕ‘,ÌGg IL:Iê)XV[êå/?Ôe&¨rÁ5,ÌüCHv¡o=”.<Mw.,Ԗ°l•Årà øc& ’¦ö`·º7ºœÓì2Û(NqU;³¿}éÃÔ¿~uçö?…vxWLZûüSw̹¯r¿|gc˘¬Üñ¸îõ¯¾ûþ+·Ï
+¸tLݗ‚*·oŽ™ËÍCÌBoGïÀUd¼a¬c\`&™.ÌÐOs4:Bï ¿ÏúØûYÖgŽoÝõ~Æx‹+Jø(Cî£ÜIê *pOW?ÒÛ<œÔ˜‡:†®2L4Ï4&~á:‹O[dìÍZ¶Ï1J6L‡»ˆé|ÿ2c:et>¿{™ÍbÌfÕ*\Œy b²|Ԇe›bk´µØ€/QÌU¹“ÍNY‚‰cʧl"ÅsãV6f$Ñy´Yè<Ú´E›¶X@¥‘Ò"»zI=ðÁž+1å^=ù|P:"“ÒOñc´ÄIAF?LîIA•®Î0EBò1œñËk»qj±3“¨3ѝõT1Wpœªk‰† ¬†zÆ#½©`ɦb°Ü}k߇Vü~ñœ÷noÜT¼«3üââ%Oo»yéã«[îÉ-˜[7f ±œJìo¿õ«×?|û•HÃA"Ó8;SÜ!p’ \ƒÐ Ÿ`œÁÍæëguNõ?°¡:¡Œ¥Pv€s° œuœññ½ìý¼½í#}c쓽cSíó|SKÅ¥Î3äŒGF.l5»Ýµ.jr®€u£¼U&²Ìû í#ÏS*Ñ8{‡Â¦J‚¾? ؂[;5rÑ1k¦Ö¸3èGÌT5kGºÌT±£#o¦¯Òç–'ÍØì Q}9/§éËT
+ᐋʆÉlWl™ÊL3û?ȹ’’[X®ÍµJõ*w›÷›w•W،³tÞ/–0 + æ_=y€g˜çfd×öL(P7hVu.¨ÊlgÌìc¢šÍB-¨~z‡av3Ž°ƒ"w;¢oö~•ú;þô{lÁç¿4´®š¶¾óC2ÆÔw❷<‡'ºŸlÃ!¡&œŸú$õƒÞ±o¾õàYÏP™“èÐ"¼‹Ü¸@ :ôØê-ö–xo“÷aÓ#æçÌ:Ÿ9ߜôvxy/VÅ*Ï֙9“5`ÀN’pdñœˆ [ؑÎbc˜¥ð™ÍEl0Ý&UÅäGîØY/½ú2+FIBåö*”z½Š¨9˜ß&Ÿùmr(=£¢ŒÇ滌_ۑñkÍÄ<[Þd‡¿AÏgg`Гï¼EÐl›'q¦;ÁQ?÷i°}՝Lœl Ž*vš·Ò¦î'pÈ6Q/‰:Ð{e½Ýl¢Õ8Q¸r%N=.¤[Yïò
+ê`>MÙ´“Àkݲ%Ëwû’“ý}KÇ9r„Û¼~ÁÜò¡WÙ5 m¼výùë€ò¥Æp_åQ!~Mi4G‘1æa¬qˆúlov‘1î(ŠVû8®4uL”ꌳŒg +ÿtZzF‹òDäÈÛX´µHêéSP]4Ô84RS0>2¾`¶4-2­ ±¨¥èü/#ßD¿Í³¹]¢³ìlËdILËaTÂq ê@GÁxm'ËY¬†šœ€Éàr–Åʺ•þNÛ+û½’Ç\1ç¨ËnÅÝènqóE0%dBãÆnƍÝ]ÜØ͸1=TÄr¿V¹1­Ee¸±[]ŠfÀYÖÏ*³æ,²âÊ 1d
+1d
+1d
+å´±³¦­|ÈZm +š†ú.¯¶2µú(®XsØñ‘mY=he¼ÙêM-ŠPöœuLd\±rwÍX4#ß3ôÌ݉̎êªWkˆp7ÝxÅl‰<u×4åÒn°ê™§5Þý¼Áu;Œ¥ƒ-_ë±à%ɏNÝðÎÝnzfÆG[ùõCÏ,¿eÛö›–n«ó‰•NŸT‘¼ W}ü Æël9?çû#K_à
+ßé8øö«¯¿J©v +BܗÌÃxÿ^ä’rºËÙjfxÅøÞ\ +·Ï̳,§Û[îÖÙL6'`d +’Ãh0i2פM7ÛàYHÇÑÓ+e}ÊÓzÜ¡Ç.&p]
+Û>—ÏbX=µ`ml#Óæõ>ZOϖ¥ÙípЉf^uvŽn½c÷gö°m£˜;´ ¼OyÒuÊEš\[]IWÚÅ»ˆƒMµƒM©ƒM¾#Æø†"C¯NÑÿªì=Žx¶7#³vVq3n¡š:ÚÄg8ÅYÕ@„±Â̎QÎËk=Ý·‰Ìö +€N_ŒÚÎSըę}GÑ"Å,¢ÉÍ:àˆnZ‰ô?F”©¦Ëå´EmlêE§mMÛ­K^Þ¶xníÝU`|w_ÃStN!¯¹yÜ=Ë;÷wX “[E÷ý ?«x‰AݦÒmC¹!ã=?¯9Îk‡pU€gsnªyY,²Xb1<Ü©©ÒÚÖ÷Nmë{§zЄ0Cc±Èb‰ÅX%ØAÚ&’LË`-÷c+(}èðÖoÔoÕ'õúcúSz éCú&}‹~K&ë¸>­7„ô ¿K<áô"ógõ`­ÞŠ‘(ˆ¼A”bâ·ð[ù$ßÁçÅþOæÂÏ«¦¡-g¦ŸgÓÏhû<¼&(xÍÕÏúi ¨ÀÒý V±ƒÜ0Չ®sE }a÷õ–‹/vðæ{m[[ÿ×#GÎ9ùø¹A¬¦ŸHÁýØlÚqe¡êmV=Ï&Õ%oQýRlÄU3˜Å&›Õ|Õ0f±‰ÅfóBLèϗ «Á­‰ç /d!l6Îaâm‚QbC׆Ô(J›u#Hj·¸ 9f0l4␱Ú8ÚÈÑ +CJÂÌ"fX™OÇdÖ¾‰Ž¢QÇì|ÆKÞ,ÇöÈå?æ¢Ô–®%×ÌòùT=’šÎ ¶Y¯k@meekdºùÕ¢“­qlðc½Eò#•ˆ~´¨LG«ÿ.Ð3Ê«ÛR³rú„*ú´• +|`ÿÕ;ïüpóC–a÷ñ“Ïm=4r:呷CTÁöЍTÌÝ)é"êÉì›ëF+чzà²;5\DêjÀðí“«è«î—+ï­¦%½Ô4GÝO§Ä€Q[…°E8&ð£!:%p!¡IhÒœÍ@8•ÙÑ71¦çMc Â`7“îœïû œ/»çc¨ŸÑ‘tI[âJ§µE¯  QüÅ@)€yÂÕ=vìîÇåm··±ívª$ã ÏDɧ{QVF–ÈÝþ‡
+Ø4 [¾€ø5À§ÙÚᜀø5À§&m¹Ç¬ +°j@–¦ÁÈ`כdi‚PÖ»Ø4À¬m×Ñiȱ?*#æò‚?¡ÿ³û³°ð{áL˜¸uá¨Þãë9. ˆNªzHXŒú¼²áh oŒm‘П%¶Ñ†m<3`=ÌxeafÀ:ؑ·Ìqx€3cù٘/ئmîfÌâ%èÑuÛ,ÕÛèÇ~ր¿«?kÀO)6ڀŸÉI?ów@nJØ~mʯ¹ý´…|DÊ¢ìõQƃ¢ŒCEcø(ÂÔ¹CB¨~Gߢb%ã&HÖöAÓÿ –‘Êç5ýý´â`âYEI¦Á on¬/Ýõcî¢úê˜:Ö̓×Ðý”½ïŸÏBDU{àæ#麕ÍÝ}Ó°ÅäȊ;L6?¶›šðÖ¬®ÿÄêéÿÙ`«ênv°”Év¦þw—ò—>3gÉ¡[ßzìù]ÑÉš~ÞV7}ÄÊ~|üþQS®­Û·cOgyôú)ýîªóÒºtiíæ{;?ÈètŸ%¹ðN%KàÄ,²Mn—ÿÂ}‘uŠ;“%òtÛx Ü2?(õ÷¤=|Xç°8\vÐé°è2Ì“ECZ‹Fq–Ì€r=Ló0ÎÈ´9#ÓæŒ]ڜ‘±c«‘9ݬžisFºVϐÃhÈø}Ï(ÌAfd
+£ßq”‡²­"ªÙyNyH“g«'ééððŽ”9] o\ ‡\ {\1uW£Í–Ùlû“
+áG
+­›BÇg¸[‡bÿ±‚8ÊÍÎCv]ªŠwš)y$ÔãEêÚH¬ ZžK´é +:ƒdàD9n-~l5Ø3C÷‡/oCŒÌ"C7¬XóÄ⏯• +m…s¯h~–?°£¦idéòÎf²ú†yï{»“q’þ’σ™7#/>¸ÇÉþ]Q–z¾žBÿR™A!/+°K¯érñ
+ÝD±^7Sœ­Ó•Ëýìý\½=5òpûpWg²0Y?Vn°7¸Æzæ óôÓåyöy®éž±S/
+櫹ñÂxÃզ빠Ãõ&ƒ;ÀK6`TÝwœÖö!|¯d1u<×Ϭ<?C©ë±IÌۖñ'k  ÈloTÍg¶@2 C±äÆÊK$Œ$Y
+Kœtázô:܊֘G5[º¨
+’EU–r‘ÉBìdbîl`ØÁ\1þÁ¸%bÿ×)ÐeL1'Næ_ë±3™¨—:k2ÿT¯;&È  +g -ëÕtŽøÖ«S¦87¡‘ßþÉ~‹M¸}¸ -4Õ"̓ó):†ö%b¨œ¨Ž¦ËûJԋ×<f¦°i“ÕšA
-<¶œRí-Š–—ñ}–%²å#£/+ü·^6ù¹—-þO^¶>çktQÁüªé”×ÿ%ë0nñð
-ŧAÒEµgZIoJ ®Ý ¡y šòÙÖ®´v³’ÜíùR¾Ç`¹v(ÿeãÑt
-
-endstream -endobj -153 0 obj -<</StemV 60/FontName/GENEJE+Helvetica-Light/FontFile3 152 0 R/Flags 32/Descent -204/FontBBox[-164 -212 1000 979]/Ascent 720/CapHeight 720/XHeight 518/Type/FontDescriptor/ItalicAngle 0/StemH 50/CharSet(/I/n/d/i/q/u/e/r/space/c/l/p/o/t/a/g/eacute/b/s/quoteright/f/one/zero/percent/V/comma/v/period/four/E/x/h/C/three/two/A/m/five/six/L/parenleft/agrave/slash/colon/seven/T/endash/parenright/R/nine/j/eight/B/O/S/y)>> -endobj -154 0 obj -<</Subtype/Type1C/Length 218/Filter/FlateDecode>>stream
-H‰bd`ad`ddswõwô÷Ôv--Ê/HMÌ ÈÔ -)ÏÉ(üaü!ÉòC–GÌå÷œ_5??°~7ãÿn)ðÝFpÁ÷h!fFF6¯CCS#çü‚Ê¢ÌôŒdMCKKǔü¤T…àÊâ’ÔÜbϼäü¢‚ü¢Ä’Ô=ǜ… úb… ÔâÔ¢2 (š Û‹˜Y¤¾÷ñý¼ö}ÑqÆï?Þ1ÿLú¾HôøŸwþì|õÓILÿýcú÷¼éßãºÙ~—Mg¿É -`xPN
-
-endstream -endobj -155 0 obj -<</StemV 78/FontName/GEOAOI+EuropeanPi-Two/FontFile3 154 0 R/Flags 4/Descent 0/FontBBox[-71 -264 1000 860]/Ascent 0/CapHeight 0/Type/FontDescriptor/ItalicAngle 0/CharSet(/L1152)>> -endobj -156 0 obj -<</Differences[1/L1152]/Type/Encoding>> -endobj -157 0 obj -<</Subtype/Type1C/Length 609/Filter/FlateDecode>>stream
-H‰bd`ab`ddäóqõö÷qÕ®ÌMÊωXüeø!ÇøCžé‡<óq–ò<b¿=~ïüuíW«ÜÆÿÝÝ’‡ý{‘À÷2þïՂ3~²1°M“R¬iJÎ/¨,ÊLÏ()NÌ+N,.I-Ê,ÎÎM,É000Ô30°p†É+h$k*ZZ˜ê€Hs0i "- -À¤¹‚cJ~RªBp%АÜbϼäü¢‚ü¢Ä’Ô=ǜˆ5
-E©Å©Ee@A¨/˜´30v0¶30}ÉÀÂp‹±þ{ߏŽï7¶Ï¿&ô½i¶ð‚ï]ߥD÷Ϟ߱œ£}kÑ´³R;çÏi”;™>7evíÜêÕ§Ìæ~0yvëêÂÉÙS²§fOI›Ö8}Ñ´³«ú›6OÕ¿nIùÚ¦YÙ½E J«ºóskš[;{öÐ9csßԅ'B»B{úõ5ÎHžÐÛØSÚÚ[3hfàÊî¥sŠæew6Քg®+šÕ4ascÿ”³9‹ëÓ²›²³›
-›[³'WO©^Ý:wöì™s7\Ï1gjgy«”gQC{¢\GþìòÅí|?WÕl~¿óû™mß73îÙü]vß÷ú]ß63ÿ8øCC´mióꌕ¡;”z£,\»[s¾`ù{æC»÷ô¬ë™ÏÃ֙_]X\šh?9u»ßå¥ßyWm<s÷»@ÜdgŽ?±Ž¢¿ƒ¿ëýÖû „zßÁ4§÷;â¿ƒå6‹}·ù. „6 ú·ìo „Ó q9¾Šy?MgýŽÁöœë7@€!!
-
-endstream -endobj -158 0 obj -<</StemV 85/FontName/LEKOLE+Symbol/FontFile3 157 0 R/Flags 4/Descent 0/FontBBox[-180 -293 1090 1010]/Ascent 0/CapHeight 0/Type/FontDescriptor/ItalicAngle 0/CharSet(/copyrightsans/asteriskmath)>> -endobj -159 0 obj -<</Length 224/Filter/FlateDecode>>stream
-H‰TP»nÃ0 ÜõSd¥¥-`hIZÀC›"n»ËmˆåÁIvtàäñÈ#é©;wÎ$ _Ñ«ŒÆ鈳_¢Bp2mTÚ³ŠÊÊ4‹ûuNh;7zh[B¯™œS\áЯvð·cóô5Fã&8|³Ÿß\è—nhÑ%h@Ð8zúáSZÌô.­u¶/ôç Fé&„¶a"€Nÿçßø¥{kÎÙ³ U¶ÁûËÛ« yÄ_s™VN{˜QKŒÙg½¿Z,¦ŒÃNj‚ÅC r`žÇl¿
-
-endstream -endobj -160 0 obj -<</Differences[1/asteriskmath/copyrightsans]/Type/Encoding>> -endobj -161 0 obj -<</TR2/Default/Type/ExtGState/SA false/SM 0.02>> -endobj -1 0 obj -<</Differences[24/breve/caron/circumflex/dotaccent/hungarumlaut/ogonek/ring/tilde 39/quotesingle 96/grave 128/bullet/dagger/daggerdbl/ellipsis/emdash/endash/florin/fraction/guilsinglleft/guilsinglright/minus/perthousand/quotedblbase/quotedblleft/quotedblright/quoteleft/quoteright/quotesinglbase/trademark/fi/fl/Lslash/OE/Scaron/Ydieresis/Zcaron/dotlessi/lslash/oe/scaron/zcaron 160/Euro 164/currency 166/brokenbar 168/dieresis/copyright/ordfeminine 172/logicalnot/.notdef/registered/macron/degree/plusminus/twosuperior/threesuperior/acute/mu 183/periodcentered/cedilla/onesuperior/ordmasculine 188/onequarter/onehalf/threequarters 192/Agrave/Aacute/Acircumflex/Atilde/Adieresis/Aring/AE/Ccedilla/Egrave/Eacute/Ecircumflex/Edieresis/Igrave/Iacute/Icircumflex/Idieresis/Eth/Ntilde/Ograve/Oacute/Ocircumflex/Otilde/Odieresis/multiply/Oslash/Ugrave/Uacute/Ucircumflex/Udieresis/Yacute/Thorn/germandbls/agrave/aacute/acircumflex/atilde/adieresis/aring/ae/ccedilla/egrave/eacute/ecircumflex/edieresis/igrave/iacute/icircumflex/idieresis/eth/ntilde/ograve/oacute/ocircumflex/otilde/odieresis/divide/oslash/ugrave/uacute/ucircumflex/udieresis/yacute/thorn/ydieresis]/Type/Encoding>> -endobj -2 0 obj -<</Subtype/Type1/Name/Helv/BaseFont/Helvetica/Encoding 1 0 R/Type/Font>> -endobj -3 0 obj -<</Count 1/Type/Pages/Kids[9 0 R]>> -endobj -4 0 obj -<</Subtype/XML/Length 3649/Type/Metadata>>stream
-<?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?>
-<x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core 4.0-c316 44.253921, Sun Oct 01 2006 17:14:39">
- <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
- <rdf:Description rdf:about=""
- xmlns:pdf="http://ns.adobe.com/pdf/1.3/">
- <pdf:Producer>Acrobat Distiller 5.0 (Windows)</pdf:Producer>
- </rdf:Description>
- <rdf:Description rdf:about=""
- xmlns:xap="http://ns.adobe.com/xap/1.0/">
- <xap:CreateDate>2002-01-07T10:25:57Z</xap:CreateDate>
- <xap:ModifyDate>2009-04-14T15:49:41+02:00</xap:ModifyDate>
- <xap:MetadataDate>2009-04-14T15:49:41+02:00</xap:MetadataDate>
- <xap:CreatorTool>PScript5.dll Version 5.2</xap:CreatorTool>
- </rdf:Description>
- <rdf:Description rdf:about=""
- xmlns:dc="http://purl.org/dc/elements/1.1/">
- <dc:format>application/pdf</dc:format>
- <dc:creator>
- <rdf:Seq>
- <rdf:li>GUILLE</rdf:li>
- </rdf:Seq>
- </dc:creator>
- <dc:title>
- <rdf:Alt>
- <rdf:li xml:lang="x-default">10217831_BAT_M8_BC.qxd</rdf:li>
- </rdf:Alt>
- </dc:title>
- </rdf:Description>
- <rdf:Description rdf:about=""
- xmlns:xapMM="http://ns.adobe.com/xap/1.0/mm/">
- <xapMM:DocumentID>uuid:e3285f3f-8d6d-4379-a839-6ccaac6dc85f</xapMM:DocumentID>
- <xapMM:InstanceID>uuid:b10b14b9-f4bc-44e9-ab18-0659d4f00d73</xapMM:InstanceID>
- </rdf:Description>
- </rdf:RDF>
-</x:xmpmeta>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-<?xpacket end="w"?>
-endstream -endobj -5 0 obj -<</CreationDate(D:20020107102557Z)/Author(GUILLE)/Creator(PScript5.dll Version 5.2)/Producer(Acrobat Distiller 5.0 \(Windows\))/ModDate(D:20090414154941+02'00')/Title(10217831_BAT_M8_BC.qxd)>> -endobj -xref
-0 6
+ㇶ—’zåè.7ý8aœþZáZ=êÙÞâ,ö¯-Pæ]t7þ†<uçka×ͽëXêäÞÖ5«[w­ZÓJ²pÞ=KRþ¿Ú{öð(Š<«ª{zú5Ó=ÌLÏL’Î$™L2!d’8Hó~-Fž’
+BÀ„`ÈC”••°¢øýNÅs?|žî
+òTÏYQqñ|ë‚ì'p¾8=/ç'²3¹ªêž8€ûÏÞýu_æ÷M÷¯{ºzª«~]õ{Wêð׿…yÐñ֛o½óڛoàÊ®O·²˜*Ü ÞcôÈêu¤:Ueôí:Ê×KåÂܪœªÜ1¹+ôM:?Ü?<4Å?%ÔÄ_&ÏóÏ µñËäVu¹Yh¿þ®÷hàhðݼÞyÇõ~ÝWÈÆÕxN +;\ÀNQ›Õ“Ò×¹iUr9_˜‹8_Ø)§–!-Cšå¸±¢#"TEC\ öŠ¬NÉB7,ߑS†DÝI_j8Êöè6 +G"¡íêWÒ=Õ¨ÚRĚ*XS[ À/[„2† 5ˤžcúá|C52㟂ò'Öà9– CP¼ïą6 jr%³M@žÌ|àËñÒ é“Õãë~×U·i»æ³ë›ï¬p=¶òº§ïéޑnµ½xÛôéúïۖ>{û¯†§Î2>ðæûo¾ñ! +&¥[™ã¸ßU†×튣²À4­’¹†œmª¶)ï¡<[“5äóŒ ÍôÌ -ò,
+-ÈëÍ{{ß}ŠûRþ* –¢ˆÏI¢y2š 7£Vô±üiàsߗکÐߐY‡7–ìNÎfqgûÕ ÓßÙÖKõˆ"^ªb( ”^…Í£ªŸ<Úã
+Uý(ª…ª~ªúQ(CA•1>ÒŠñʙ—ϧ#\•3;+fÑ:÷lLo¨ŽÇNu<vŸéDmj`sóÎ×îXʝ,ÍNF¯ÓWaׂN貌1µ–2ç{yÙ½³_LÛñî +¯unM<}]÷cϬ¼f[ºñ#.†ÐþPúÆÇîøi,óûÇ_ýÓ{ü‰pÊ7áÎ=ˆûÕŽÓ*=Pea!›`Dz3Ù%lË .^à‡Ç%8ÃC‰¾ˆ@b›xÈGtô È9)CÍæúûº‘ áGÕ5•rt°<‡ÿ2Õ#¦K9oªGÜü’zä„:¿¯‹D¦‘öJfRõÐz'˜ßE‚Í·ÂTÚñ<xÓÖQ­ +—]>j̘—{óØèݓ†?^2±aAWê=\ç†þ/˜¸e†2˜ó1•Ç&«Ñm,+W”‰D³R#õebÖL¤0ƒD2HA!ɧŒ5TÏñF† S„qEs"-‘Õº¢Ç<O•¿Â80à:µü¿-„f#¤VA10Ÿ'ÌçIóäyŽ6¾MhÛ¤6¹Í±+º«D!î–E¥µEÍb“´8º8ÖSØSÔ[t·ø€|WìÞòúˆø¤¼­ä‘ØÎèkQ_,#AD2Ha)Ê Öór™Gà2Åe“#"Ò1ݗlæKŠe‘ +êÑVªÈ +5oD+§F2­AkԮОÑþ¬qŠ–¯uhŸil¾v§†´1ä`z¤öÃK.WI°Š
+@dúÔëKP»Œêt% ¬˜—Ûž‹rÃ9vÖôR¡š—SíÊ)ÃCȈ +WHùA,Ò O QEŠ×Pý~Àܒ·U£Ù5”ÔtRJ£¾"µ _qß?.öþï÷PµWQ¾ÑîpòH,#ÿIʗeéË2cJ™éÉG‘¾=ä.eAZƒ‚’²Ä‚ªýU¨¡ª·
+US˜¢ ¥wÝl|df(#õ¢Ô’Oê¦S*ԋ:»(´îŠn +n?Q:äÑ`'KÇL=(‘Ï$ÒÚ0Ë"„G¡ì`v< ÇOw]œq„‰Ç;‰](K9M¬Æq’Lµ“ºÁyœø“Ý@¤ßäS’!y…6oyÔ¥ºUÊp‡BÌ‚¶!x“çŇΈ:d¾T ÁX‰ rq6òÕ\ÂњÁtCE ²øÚµkAֈIô`ó>qNêʒhIªIÔÖ]àvŒ!™ Q´áYåÖëW_WS|÷Á-£/*Û<ó7/6»¶ËÝ­«Û|¾Êк—îÓzð7þŽ /ëj7²0P\5yíÅWÅò㓮_˜1oF]a8×#U^=¯ùÁKŸ&ckQÿ÷¨Ì¶øa>Éc™Îd[ð5{á2ˆHƒ£ PÉLŒôj@Ù!BøT!®ˆ˜b$E€tœÃžˆ&{"Ã~;?^¿À¾ÂÞkßdgfj²o·ï·±s4Ȋê£ÄJQ©C†)©Yˆô¥=Â.
+cœÅ5›Â€ýyÔ°vǒó´64Cº©¿>Af´ÓÄ»Ìh®êjõPV˜F±ß´%–«Žæ¤ž¸H +þªþÊöòuëvîÞí‰Çò~PÕ²-ÚííéRwO+­«“5qàÏ 1´æøH÷øH Íw†æö&âXÄ{|2ôø$<¹pûj_F.õe˜ ߀\ê+ø‰¤Ò©ŸÊ¥~75 +øÉùéäåHý^ːdÙüT]á7saà&ë÷Ãý~è¿8H:¶„£Áï‚hEð¡àö` +šªTS +kª[åba`"%Ù»uáˆp\`…ÌD* L¤–ÅC¤vòtþ¨4*Pó‚p±vŽbͲ!\(vš“*u0ªOZ)äðËdU§Cq ÎL €EOVï25¤eek1Ÿ‚KZž%QªõÓW‘*I™†Õï_¾­Q•vI®«§O¿cÄ®vMZÞXӍîJíÜ8lâô™wނ’g?Á=$¶$Ü£"ª%ѧß[ùlœ#x¾k4òYÊρDŽßôU@j–?’ßÆ‘ç 7à]DˆßVÏöƒ¦nÐ{klD\I‘LiWRð¹Ã žlþӝx­½H´nB^AÄð†
+B¤8|xƒ>1nˆU$€Ž7Š\
+bBTL‚q˜(΁sP?WX— V¾U¸\ ¯E«øë„kÅõp=º™¹Õ~ ›ð;pŸ°Y|l_{í;ÄCà5ñð¾ø +ø\< úÄrü8bøĈŠub#0DÁf¸} nœD&‘7ñþæïF¨U¡Îò€Î ¤-È9*V¡g‘Í&KÄÏñh· +þŽŽƒÊ7ñ:ÑÎółè0aŽÏ !®ˆˆ¹CžGrvQ`´UÊPŽð†a½$õ< í6l½6dØ!èȀé«#dy:¨¥æ§æ§OÌ·2( +Ä{¹’çF’ØËÇòçO¶·v¬ömO5„H·ÿñDq~ þÍsé«ÙhjÝҎY+Ñ-ā‚)í?1¥©’ÐP‹ÒԌþ÷†ø³Ä¢£J‹qü¸
+e"”J"ŽáöñSúQÜP‰hIŽÐÏ%Z²Y¹‡½‡ßâ¼_ÙoÛÏí·¿©ŠáKãª5p¸´Þ!ñ•îKÙ&{“4×y/¼O¼OڋöɯKo8ßR?aÞÞq|ªžÝn«O%¸]JÀÇšÍI0…ÈDq4ܘ4d<nyç/á8ÆÎ ä8ÁÆ2x
+Qð+퀊âP%<º ‡ÄȪÈ)HՃࠀÔb xä8耎b™ñÊ2#
+à s)² ÄF7tOvÜ GDe!'Ü`ˆ¸g÷Ü%\/ÍË4ÖpêÌ +(҈{²kõ+o9ílÜ×êIµï4NXÎÅ\QÂêìùVîؤ¢¬ç¬wªÌ-Þٝj}=_ßd¦2Þå ä&%ÒÞRnRŽø“ þ’ãg ’*-ÉIÂHAR0™˜¾xՔ‘Ð%š{ ÓJµŸPMÆ
+™¨Àué-ÝV./Þùaz3¼ýè'ÃÓ_¢LŸ™8tLõÙ´œzNiJÏ'”TžÎü¦¤ Z†y´€i06=úèC·
+k©óûŒJSD•ùt+›W˜Š¥,k›9¸ˆQÎ&Æ\Ñ«0Ö7'qíè’!ëQj•ñàÑ`àpPSɎÊH”9 íTÂÄÁñ˜±<œŒyç(ψŒá0pÏ뱡 •lì²àö9î©D.qÔʵŽç—sÇ<“|Mî&OSN«»ÕӚ³Š[éXåúµ÷×979nsmpoðÜê½O|BúWõ×óÞ¯Ä÷þ·#¥žñö‡ó2¤ëóHá«ŒSÖ)Œ¢ +Tߔá̈;B°uŠ"«.·1š×ã)v‹^| ÈŠK.–D,"ˆâª/qä ¬†Qeø¥0
+ïC +»Ü†wšeH +nÍ®p¿äFî}pÌFÀøH~¢­eèòP¹Qf.‘ûe$ã+vVçOÔ°+¤¯ÆL +n¼É†©•Ä§Ô¾Y¥át0 ž¦æ&Cº< @±aÚuZ´»žꁩ۝3§nLožûæ¿Rÿð"3ք¢zûí©KŠ‘º¤¿Î»s’.+ü´‰LÏvf +yqO‰éçQG‚Q2CÉÜ_YãQ^?ÉïŠÚ¤ôòWŽÆ#ùñÏw¥ÛG +]='‘^ú¤+
+-SrÙXjË5kW¯DËξþ̘¦™„–cxT|Ó²¾¼¬9ÕÊôêއñÈ +«Üþ>û¶!`ŽÂ³>z؂‘R*Õ$LŠ“á4Ÿ,4ªóà,4‹o.QÛá"´K¬×Ãþzávx«pö¡ÆGa)’ü£ü‡ÐNÞÚ½jN•»“IP^ˆe 4\/ŠÅá A’7-$Ñ.œ¸ÐÌe#äˆ;E´*»xÞnã^À‚À¢[ŸAM=öˆã!'NùÀÙëüÎi£‰"ò“³ˆ7@ø € ô¨WSԞ2|µ(§ŒœˆSç-5Eä¢zõ$ærOR_IkÊR¬Ü–œ‚;{w)ŒòDž5['m‰^ÙKZ‘4¥™ú¥³ Χ¤ÁãaL!`í¾ØJ
+¼/4R ‹Ëø“f¤¨/‰¼øôý<À‘Ü5+$QÐ^[]CtÏM72‹S/w¬jƒ_ßÅðÜ]צ.¿^øgÐßoæW²—£(¡há,Øb†Š§JxDùNA•Ê&<L }ifפ8„Ês¨”pþüÎ|§c{ßa½ÃXðnúáD&¿M¢dXœG0ùŠXÅjÈÿ^’î ~æ¸ÔZê/àUàu;`˜Æy½Üìüpe©aøm¸Ÿì‡†×„™0áïÛCêæ3•èŠÓ;RRZI擀ÿ²êq¼à»T R‚óêq~©±à(.݁ˆ¯¦á•’WäÃ|³xþÏÅ;ã5¿Pþ² +(1H7FÔèƐª„¢?¨# Šâh‹nÐ7ëM-/ô3¬;ÇwÐñ6*ª†!ç;.«g•­Á2}/ózÊZ¡mÄs@Aw
+7æìCŸe ~q7îV0x£Œ1seµ§¿[e®¬–¢KE¥HNÎìõÌê²tŒ½Ûºz¶nëîÚ¶|фñ‹Ÿ°ˆýc÷Ö­ÝÝÛ¶öLX´hþâ[cÿ5Ò±âpþ: CÙbQŒ¬½è3Èt0kÀ†é5ÂKdU2Ĭ‡,܇<‹H°ØÌÝ@c?~܌Kõ¥h¤£¦§š9vÓ7!qbé/p“õÿ +¾Ávàžy†kÈÊZ4à™.]•½²ƒß
+–í†olÞLF½væK8Òv·_}×þ¹í°¿jGßóðnþauó¿åÑl¾s·<ä%ðOÙÉ¢ay9ƒ^ ÔC€˜z`¿ˆ/Á!ÔdÒºDɂ‡ ¢¿ÇRp*{¹0€Å`ÐՉ?°³“¸”xíæÒa«_Ώ_V^[ð?¾óèÍ#¦—Nô]AGf +·î]¸u90ÙðÚ8HV†@h=XÌ2ÀVύd)™
+r‚] 3k`=ÒìO^ˆk¸i)í‡@*Ç[2‰{»¾ž´¤½ÐSí)„s;ßþhÿ_ß²ÍÊ´$X–¾ …15å€Ñ»$A.ìC»w;h¤yf›1»Ey¸ô(·Ò= +¢à>8j§ïRJP)ÌÖõ A…?œî#q}þºjšû¬óDgêhòÏ7̞³ióŒQ’‘wy4×?êþËÄى©Ýò5lЛë{éB‰9çÁ—`)\MaüžAØvæ[Ûn’}4ß)ìeéŒcƒãùlp~¥|«Þïšë:ä®ôä`x–€åìÈÙáë$à?¨uk}ÁCÛàdèdØOavîßòU½¶`|dJ!**.vÿÝÝ[ÒVª”Éq¹§¼ȆÊß½rØÔªÞªÞêGk¤Zþ<(€q°¼ö–Ú'j]§Î…ºÒ_€¶ÿ#¸y>úßÁEJÌ„A„A„A„A„A„A„A„A„A„A„A„Aøÿ'ø 뱑OÝÜ®ÄG˜Ÿð–…3@"™Ã(Îfá\nàŒ¯„¬`ÝÓÄ!ðÁ‘Ž€δp&ë<›…sY¸YŸ'ªÀP0 ƒf«@ ÞOàjüí«À
+zf,>êÂ8Ù.Äç[éø—Ñ ƒfàsKqùÐMZð¾_½oã+Gc¼—%׶Òkâo½ßb|Ír¼ïËð¹°ä©Ë“zÕÐaÃôYWµèÓ:®îèYµ¢EÛѵ¢£kaOkÇÕúèöv}FëÒ«zºõ-Ý-]+[W43jÕu=ËWŒîj]Ø®·vë õž®…‹[–/ìZ¦w,ùû7ÍÀÀZ ÔáGìÁ±‚>úRp +~Pò@€þ²Ìùþ¢K]O
+endstream
+endobj
+19 0 obj
+<<
+/BaseFont /CIDFont+F2
+/DescendantFonts [ <<
+/BaseFont /CIDFont+F2
+/CIDSystemInfo <<
+/Ordering 12 0 R
+/Registry 13 0 R
+/Supplement 0
+>>
+/CIDToGIDMap /Identity
+/FontDescriptor <<
+/Ascent 905
+/CapHeight 716
+/Descent -211
+/Flags 6
+/FontBBox 14 0 R
+/FontFile2 16 0 R
+/FontName /CIDFont+F2
+/ItalicAngle 0
+/StemV 15 0 R
+/Type /FontDescriptor
+>>
+/Subtype /CIDFontType2
+/Type /Font
+/W 17 0 R
+>> ]
+/Encoding /Identity-H
+/Subtype /Type0
+/ToUnicode 18 0 R
+/Type /Font
+>>
+endobj
+20 0 obj
+<<
+/Filter /FlateDecode
+/Length 16338
+>>
+stream
+xœí}]#;nè{ÿŠ~`ßÒ·˜žÍX 79@‚<ØÁT€»/ùûW²]IQ²Ý-ÍÔg·M»Ä’(’"©iëÌÿ½OÛiÂlêï¼Û §Ië÷ÿœßþßxHi!œXí&Þÿþ_o*Ø­ !xÿ.üvò‡_ÎoÎêø£i€B°Rsz0‚Á ¼ûÛÛÿˆi« Ý3
+!åÖØ)QQxµ5‘|Ùù"“püÛ?¼ÿOBRÉ&ÿ‘¿Ât&2#QHÓÖ;mDzćI„$¢ CBET©÷K?P˜©h!÷Üó›²nëU$ËÂqŽÁ£ÛsçƏ Tq+~\Ŏ«Øq[ä ƅÀ=ž#¨w[‘ Ž {<7FҙÂV¦9ЫƒÐ= Ÿ[ƒ°ÇÅaÐغgáskva™#plݳð¹5HK)¶:ý-áغgáskÖQ)*oÍjä‚nÅq¶D-å$/ø¸Â㢗ÊÄG\TbN¤?&a­®ò´ƒ+1%€²‘bbÀsc„Õò¨m‘¨!pρçÆêÄÖzJ/î9ðÜ¡@CÔ÷–Ò {<7F(P¡ôV¦9‚×
+„îYøÜ€ã.¦’ªBÊA÷,|n +ߪÙA‚îYøÜ€¥9Niƒ×!€.k¥³éÿË?½MïÿýwڃO?ûç´Æÿÿß7°‚l\A‰C‰cÖÏ·ý*6c¶ …[ÅV˜¢ì ,ËCyCØ8–‡òÇÜV*yq…Š¡ÌatÓc¹‹
+ÎûÓZç¹ËÂDz=–¿h窤á¯Ð1–?„å{(R¨bð|åãcùË_D1%ۅ¬>@ÇXþ>–ï±ü¹¸©&|á¯Ð1–?„åûëø°|°:-ÀtYÀ_ÇÆKÃ8lì°d) ÄfXÞRä ÄÕ&Çb h?ðHû wt–ˆ¡ØÐËR1Üòx2Æâƒ[OÇP|hKà鋪hžŽ±ø Êä銯¬±™„säf ¶2,Sú ŸNy&dÐùê/hú÷ÿzûø3ÒùçßßþÏñ®¤ÛZwéŸ{ï08+¢*‚Û†¸b‚HÓY,šøÏùíßÿˆ`¹Û¨ÓïÓGµÛèòњ_š,Ÿ¤Þ9ðQ¹]~ÇÃɝŸ|^Y8ö¤ðƒø§‘HÑü–<I€8§ÝÆ!þ,Wµ(Šüm<øˆ™ÿ±Ë“$}ô‘@FÚLÛ¤ðþ?ÞÿüëÛ?þyŸé ÏMi'Ÿ¶G½u¼ØÊ8½eX¦ƒ@òn·±A#>Á×æ#r +¤`ÐÃF¢©d zÆÁ·¤5þ-þò;”|"øA»«'„þ¸‚,‹Þ+•ÍO&°0`$)““:A]ûȈ1îóˆW*”ƒ<±nhµ
+“Vœ0RiMVÜáßù…ã¶þh2Ëƚl[±DƖ%#°rŠŸ…£\ÝïkòmܾT»¸à˯Œô*¸›0oÉá]řùzÞ}LZ—g\”N4ö1ßTfZg с[—ïì’d#Óx§¶x§&ûÙS±žuú’ Á:¼ñö7î+è½\tìÈH4âÌ´SˆÑΰØÀŒjƒ~« ,•ìŸkÎy¡£§rüÌ̹dÈLç ™›By¼ù£í¯hK>ÝgóOô¥ß‰uó‡ëæ¿nþió_èŒ?y
+™‹ÜS?þ9}q¸ù3l¨°Ó¶¹«ˆÞÆ{Íæo¿õöO‡¶=¼¡“qû.=¢W“Í6‰8)wš!È>vfÀ:·Oq;Ä>Mã0OeÄtÄLpX(Jg;yÒUé]zi!Ø)pÓ9Éã9 Gëнõ.nöj!dÒàð"žn]“¼»Ðâì@UӘZÍ÷€«4àUÍy4¥ŸÖ52N«dwùÉpo%ÉÏþVÑ´ócˆ{°_Y靚ÔâÛm­twÌÅ"Ê©Öj¦?†ÃÕL¿©8Ÿ?&§¥ +‡õ(e#&èÙÒbj¢ÀMØýq&øD÷=jö¢FgL7BKÏô&{3µõÁÈ$¡0”Ÿ|ç´«2G}Ï'ÐKþÊØ¡uϹE^³5YzÐy—RJ7f=>Z·¦5‚ô,$í­^eQA²Äs{R®œ[yäÄHs¬›t/æëvDø›=·ºÚ?$èu² úÖDä\xô Š}Áà±ð9Þô}Ù{u(|H#aòqH(°—úCO<{vJ¯Dü¹WX²Þ«Q=ó_cÉ2º†Ž«¯C³-GýA­Üæ[&–ªïDßúGÞ]úªÕ€¬nòãÐ[ÀDӐ‹eö”gàؙ1¿™þċÌr{ªŠ,.­î¹gxbH‡í'Rº7ã’öÛ¿ZPóÈWaÿ<å:I'>e–§³ŸWÚÆá/e2ëírÚÆh¦~ð)nñý–Áå»?Ò!αšæ¼x£¶†¤íÞ5 ù8{(<›Üòy‡kÈg +ù Ó «œÜ
+¡m(ÌoôtB“üê²\ìÒæäÙ_nHö= &E¥gI~ô+JkcSü:ÆÔ‹µ:u¿ëÁÅ·;\ÈI,¥Ö]lZw±iÝÅÒ¿‡\8s\”Ηƒ‹o—¦¾NÁ©ÆU¢ÆZÎ\œˆ3ތUØy>x{TítI¿“8ò$qàIâОlã¡?6èÛt„./¦±:E€#‰ŸõèÙT¬ðÉþï{x£¨$:I,Hˆˆ0H‰·’³©¢]ªÍ¯ ;5µ_J¨úh§±è¥wV<nµhcõbº2‹žˆôÄw,H”V"y‘“1’+*Úèý)­:D‚±}kÈt®´£¦d²ã)ið¤Ó¡Ë·©RêrtÙ$žFéU3g?HD]¥€[¤‡T;îŽ_(W¥£Ú«P,=³Sí÷‰ß‘^qÙ©¹”Bj~uIŸ¸õ\P*uM1þO :ÆM9PôA8'gLÒu5( v;&•Ÿ…#v´úMBðÝ9™. +\îÚٓb42NÒéx»˜â\Õ)>ˆú±kÏyG~{î`ªýI²?Vqî¿2*D‡ k
+5 õ\¦Ó~ ¼;ôÒÄMŸÃñþ%Ocø5O»ä5O˜9~MQƒ½ÓáÉáPóØ:ëއ'RÉ­NÛû£Öbi6~ïsiro»5âõ׈×ñÒä}þÝkG˜x™W(öfØÀ½õhæè·¶•žêŠ®íD‡Øž3=\Ðý&.}ýÜræîäç9'ÃVLî÷úžœ|>ÞÏ;“4':YsÈUª¶ÇEВýK•4GÜ3ä]†ÊN'+DG¡^[͝>­sãUômҁ[…IâŠhɛœ3
+z~ÄÀ„Öç÷{øY·5©žv=ð{‡«ùópóçinKjíxùMé^~V1Öã]rqØ¡5½8,›‡eŸ +Œ  p Ý5×,qÜø5½uõ=jøiq€1xt{áÜø1¸í4=Ð}H¸çÀscp šÚêêš,Üsà¹1B†éØ)]W{<7Fҁ¹p
+A÷,|n +g­]"h•èž…Ï­AØs÷7!螅ϭAàhò8e¾¿ @÷,|n +ïQÜÝPzÕ×~‘NüKçùMîQS̽ƒ¸çÀsc„«¨5î9ðÜ܂ff¾w÷xnŒ®›ô6ºÀtÏÂçÖ \¢xHŠÆ½ƒ¢Ü;Ø€`.bDÐ= Ÿ[ƒÀkÐ|™2e@螅ϭAà]jv{І¯Eýú]j`Eó…‹ìâúú 2ÕSRÃØ
+x(¶Â„wK[Ιgy(oÇòPÞDT/܋+T e£ã˜Ë]4
+òý¥<×cÙCøX¶Çò“|E&Ï÷Xþ>–ï¡üÉh 6?Mø+t åãcùË_4Òòݛ<ßcùCøX¾Çòçt1=x¾Çò‡ð±|£ËsZ‡›eÉ yTp‹Å ¯ÿ`„ Œ‚àqïý‡ëˆH {ššÝ ŽÉ(¢Àd@ø]o0ÿÂv˵Uèò:»¬É¡w×1£bÝsdpŽ!НO£¶ +ÈÐr9c‡ù{Ç\o¨}Š³‘ÅšÁC%ÉD‡æ7B»®bÜÎ,#q!ûš¡`$.dï2ŒÄ…ÍO†„¡È1ÈÑ02Í8"FbÆGÄPlÈlሊ +.àUH*ÿqÝ|S\•Ëm™ZÖ¼¤ã¼ø¸ +CNJ‡‘m¬;¬k²:ç®çÃ7º©|Œ,Kô[xÎ~¼EÞèçÚ×®)Û)•­C'«×]nˆ²wɃgø·;Ú0]*gڝàé„äÖÁï¯m³WKí!i2×L;ZÌÕç¾­²zxyÐ;']{nàÅ! +*æ?È,¬Þi»/În‘ +É +‰² +MyÖäŽà²îP­L§ɪˆ Ë:xcç™Ë6:×SzÚ3 'úWèp"NÖRMêË6:iEUŽÀ…|ý[,ªÉsM?@J¨î5e360ä2‹ºâU;io±s£¬ŸÞWßiaÿÝÒ~¤÷KˆÂž.¼^o¸z‡kÖϚô ·2+Å!oB·.·4O{ƒK±å.Ö»-Ù͙&#©ÐûW½£Òx—;ñ1S'Š^µý:-†º©¿ßI™/²ôl/—„ªÕ˜V`Zm€ôïî6€ËZ©iÉq,î,½Æ +)¡òpü)ޕV¯Óm˜2Ì˸usÀË{©Sƒ¡jÔ³®Œ)tëÂ:mÄûWŒÖÝÕ_`JÔS¹nb„%_u1Út!½Ê-ï®â®®B¯ö wWu­ÿhÎÄë´ÃÓC{ÐH©£^LQK÷®ã䥍^¼ނM%ª@Ƶ i—u®-hÈWC½¿Ó]ž2þÒyÚÚ|í@3Zà^¹Ã©ZMœyó´{0¢û…ÌI•I²¼ÖÜ¿¦ýÌM/.T:
+Ž´ÿ½m€95D:e5Ý5„$oå”׸FBÃá Y#!Á׫<ÇSÊJú® 1Ô;Þ(˜$)×\†u¦­G'C ò•»× +RÏÄ&û(j³u6™ôœð{•ÑZ>ŽnL¾‹š¡û£“j!®:ŠB¿í‡_ªf»pù +'±õÄý¾cæœ8ÓKƵ§ ¢B=Aü J[Ý §ãØWwòAYvïÇ|ڙ潰K+óWZ!qe˜%€¥-w#¹ª°ž»ç.dt_O1ê°kOŽÞE«t%øÞt¦Ñ2ë½ÕÈÍ@ C\·!´ÕÏu™Xx9udDº=ó!U@ÇRïLsxû­G&Æ_WOÆÓNôϼ;Ó:RØyõôþÜ8¶ìH¾yìÊ +*º(©ÌÞ
+n径»~¦|w‘÷5“».T®'¼»Ó¬-¹åoušW§yušï½I”B#=Qª{ ¾Æ¡+È0&z¦§3³WÊ`ÞF?ÀôŽJk»¼sü¥°Ä¸Cæv’%wÅę#æŽ ¬{Æ{7Ùáº#æÍ¥gÌOãïqkGD\ϳ=#»Š.ÌA§H'¦Â¤ØogN”ÉE]uÓãÞ;õ™páÑ¡Ù=é$06įã‡à
+T ÌZyé=ýfËGýªLðVqlÑùÛñšû‘±*_¼—.uª%þ©„ë|ê+ ‚—úÊM÷‰žwrq™®Þ¤À›Ž<Ó»“ºô^¨vaˆ3Ú<¢qTAÚÛJR»¨Noݹ0¥ê{)Š1ù—[º–§!“z>7Çsoõ,\èb]+€çÍq2ΤÆiF9ʼn—ªYý=³ 'í%ª¯äð*³®¹]ß+¬jÕÒÐæîiPN›VùûGt½9ø “]#ºâpè®]PfU¨"ºösaM/>ªµS¶1ÔüщʅdX€Ïoœ<iɓ]jÕ®Yø°äî.ˆ¹*»Æ¥Ý
+,ÂR¿”£—hiš~ô/’º¼Ü,ú³˜ùË";©ZòíEML]4ՎÒŒªëŽìqH–Šêˆ¹WÌW•Ó`ò};xÔ[ Á[÷¸j“‰_ûn>Yë\ÖîÎ? ÜɺØN|— ¹²Ý‚è&4‘n èÝ”KR¯{qùqJ+o U¢ëÝH¤ —³ÓÂĆé,½³âaÏ:‘¯åe&ÞAiéøªŸø…ð/ïï2{ïKøÌ̸ÆoTwòå$—¶«÷vÞdÜÚOÇWçí1®ÎÛ꼁'm ½ì™–'ÍƑú f”~¦‚\ /8|¨i1L‹M˼Œ*‡Øÿ6´™Í ù´5lhÒö3Ä5Í7ðiw;µè\æyÛ(5j×ëvQ'xgftóè{MØ.ÃYÞpB˒"H(3M© Þ?þhˆ&L%ã™Y-/ZŠÚ†š·Øe"AÝ áÐX|—$AÄ2ÝÌ«Î'-ٞT¼N„ªÛ˜…¬ ]ósú_}ùK»‘ +ju–p}-¹í¬ï¶—O^C7Õ¯òÛå…ÔUUƒmz.òÒ«<È:0ÕZhÎó8Ì«ÃєqìB{‰¦;aJ>¼N%P¿JÓ½6ÝY›î|®éŽ –‹·=$Uä·H7¹Î®z"º¯òúž'l'xºu'ªWû™*¾»… +eX®<¾wº‰Ô‡{—RÚåÝ#–FÚÅ5b¹F,׈å½ýþhœ¿xíõö@¡jD,÷I +¼ÆlXÞ1\à;¢ˆí‰ÍVC³ +P'Ê=ø̹.@úRw]6Æð”N–±",}x‚u¹'ïd]nv'wDöº3 D”½ê³v§œTÛ ð·hdêۅ~:: +%ÒöŒ:‘’~Oà§õ2¬H¡÷c0‘YùÈxCz{“m~—ŠpK{ZNÖ/7`®–Ó´ZNÓoi9Ýå®tÁ)Ђåxc­9^`Î+ÓzÀH½¯Xú €Â۔&h!÷Üó›Sn+}
+OÃqŽÁ£ËÔ_'0-•|yx§Høµe’GÐ!‰þÓò0’‘G6ä¡]¾AŒ  p ݞd~3"—o€¡ÒÀ¸gG™ßlìá:d ÇP8Håžå²)’i Üs/an°@•)—~ç pρçÆjÔ!Ôv¸p;{<7F(Px#z÷xnŒP K?nDžÀ=ž#©O~k+A 螅ϭA8ŽT/A÷,|n +ÀÚ¤øãñó2„îYøÜ€­b^"‚îYøÜ€Ó½ZéoƒÆ†Ð= Ÿ[ƒp\=Ì»DÐ= Ÿ[ƒpôàR'¡hÑñ!ôš]ÀL:¯ÚÉlCrÕqÞK•2‹ûaJŠ›b„µ¶史@z¯—Ûçñ6xÅŠbâG(Pu<(Á ÷xnŒP Ëýõˆ^Üsà¹1B–ëò¡bÀ=ž#hô©D‚¢y{<7FRO—7'ñ8ôâ tÏÂçÖ ,óòtÏÂçÖ ¬³û…€îYøÜ€­e^"‚îYøÜ€½YR„‘bÐ= Ÿ[ƒpò¢O³H1è¢<:fñ¿üSô…ÿÿûï·ôxÿç·ÃÅûÿ¾-—LŸ¤RNµª3„‹óçÛ¿~Ÿ5ziqˆðøP|PeJ°!UjVàòDø œâƒò„øœGòä¦ÁÎËy¬<>VÎcå ññr+O›Yšr+O„•óXyB|¼œÇÊÓ§‡¢Æ6Dž…Ž±òDøX9•'ÄÇËy¬<CX"1sCÎcå‰ð±r+Oˆ—óPyjáøý¨Ð1Tž+ç¡òDøx9•giÜ<7ä<Vž+ç±ò„øx9•§Ñì~è+O„•óXyB|¼œÇÊÓIv?tŒ•'ÂÇÊy¬<!>^Îcå»:ÆÊácå<Vž/ç¡ò4S(Þ)/ç¡òÄøX9•'ÂÇËy„<Õr†Ÿðqû-€—'·ßÅǏ;¿9k–c¡ø¤[®ó›¶KQ8;,Z ·BWb”9eBðƒ—:æ„zFrǏ‹C=#ññ㢩9–¿²ÔA4~¦!µ|¬kñ‘Ú0|ü¸HžCñ±gÜóN¶Ê°ˆ9–ˆ¡Ø`”Ž%b(6Ãb‰Š +FxX"†bƒñ–ˆ¡Ø`t€%b$6ä;³D Å=K–ˆ¡Ø ßÅ1ôJX"†bƒ6;KÄHlÈc‰ø:6gõ6D L#ÂGêe0.: â鋪fDÇÀ8.TÎ<cñAõÌÓ1TÐ<cñAÍÓ1RÒ<cñA5ÍÓ1TÔ<cñAUÍÓ1TÖ<Cñ¡OÇߗê +r¶PýJçê&ÓxÃ$ýrQïÒêÇ ®[F·¶â`JkÍÒí`-ˆ5´ Ô)|…BM*[PהÈ^cTLBÿ§?ȸzgÚm5òU´÷3VíG¾õÚtD=)€«ï¸æ3¢ÌƒêÚÄumÁIæ}“QšþbiJTE¦*¾¬gL”WRxÿ\òr6è­M”…(°É-•àEÀâ*M;2]Ü.ø ÄÈS㗍hG{Þ¸Îýx惶f6œ½ñ}¸©ÍÇÇå|kürZ£éy–ƒˆ
+Q’2C¢SŸ_À\Ýsd#Dó8R±ˆÛ©a©‰S¿¤vƒ%25ª>T¤½4®D<ÙN•ªuoV}h›);!Ž1;´a Lۋ;§bPÑ~exÑD*Bç­à·\¢úGU€«š/]Ón|¤iÕ#—Ê÷Šh9D©ÅU3…FŒ¨Î¬Ã
+Fˆ©ó‚=QWeuñk»×;îÓÝíÏF;՘N_zßáäÑ,#ž7+5}N:R¼,û’Ø:V‰=á#¢æù¤ÝQOgŠo·¬f7‘¬SV©C+Áøo­f‡k5ûI{#zÍ©°®…u-|ñëçl‘|)!ÕBr×úþ¤!
+ž0l$ŸOö}>ejwZ§­§NSYÒq ÷†"×lS§Ïwî;Ïêš+wì¬!RßæE°Þ*vWeµ¬~sËX¬¾ÄÊÜ:~=æ„EÖ0ÞjuÏõ÷ò_ÉÊ~õ_Âáj³¯þëºÖµðxiOO~)^Ø­Ágßé­tÉí¸Î­ÙxEÿU_xßÀƒV+uêæãלä/pX7f5¯@¬ÉÊÜ:~=æú'®Xá{âÍÞÉa-&®ëc8\ôÕa]׺/í‡8¬WåyÇ­Ên%®{Xó¼¯Èóv;’ÊKnF,vGÂW÷Y#š°\¤Ãå%OL5=éE6ðè_gIÁAíÀ¿zõGÿDO¡±×/V.¿¹³°¦Í®ÌAÀ:^ô‘/dQßË©×"×e¯Nýc8\™Õ©_׺/íç<…~ ; eŒ!½ âNé.‹†?Ñ14ÃÇ+C›žÓ§_!šykõõˆÕ™X™[§Ã¯ÇÜçÓ¨Õ½X™ûC®ìc8\öՁ]׺/í§/ÖÑãغ©shÈY X-››€¬¶à:~‰ýVÌUóãu$ÖØ¿ÿÆyLÚ-­­Wé1®Vâê1­ka] —öóçñêt^£S“rñüy¼4·%®[ w’hiÖ¯áúãDÐeö[/ýØWœöº:ÓÆá³…DJ[>ûO77§4~tFš>v`ȳ¨t?µùÚ.ÔÍ4î;t¡nK¯Ù…ºÍŒÜ‘ï›Nš1¾ï!.P0RÊÒ§ï/´md0ËW| Æ’@$‹å]kK&Õw”×NsâÚ‚¼gÕ[%Ý4©Éð»;˜ò9¼Ö5Þ°N‡×”ØoÅ\?¥ûûSœˆ{½\íµÆwÃáêÓ®ñu-¬káñÒ~úqã£Px‡8Zî2º6ê(4HlÀ´+o©¿÷âF7/H@¨ã³'Ô`7Ý(R8Ü˜Ä ­Wïùº5×D­º^³BBıÀ¹öýŠjEÂtø="V¯
+Âîj&¨°ð˦²3(ÊUÇÀP<ȑΝðyÛ݉á:ÉîÕq: m?v~K ÄXq “ICGòíuHb»õmu€-Ñ?'Aú {q®mÉ:%¡óiãmBYg—ê NƒR½¶Çú”[±°BÀw`­¯ªn©ÀͲ/kDy!­z¸f’[ï#|õpÅájÕ¯îºÖµðxisÛj4ðûØAfBÊ­±Sځ~¾¹èí¦Îy˜Ÿoû·û‡÷ÿIHª}9ÿ‘¿J{¯?üe¦°µé/{ܾ£µcDzćI„´%ª¸%ÖFê}ÅÒOŒtOþÍ?€À=ž#¨:é’E0.î9ðÜ¡@I-±â„ãBàþM9¹Õ>½d4²
+Ó²ùáÁ£3Hç}Bª&TCàžG87É+`g€Y˜)ƒ@ðžÿbnSÀH0¦ainp_ Ñ Ûº–P(ºçQÎM F!ãsxç‘gH`h‡Ð=?Êüæâ¯Bü %Âá@ +¬{ïÜú9½5éM{D;„îYøÜ€£ “CcC螅ϭA€ž‰Æ{Ê>Hæºgásk¨ÃâÄI)¬tÏÂçÖ ¬ÂV$”H&ºgásk #ãæ Ü 5 ¡h +¡ÑÁjAÃC¸qËæƒV‚ïßÌ푀*†´B͍yøÛq{¾`ç´Âf +M¶Îà½T&>ã\t#Eúc2ÖÚ:•ßÊc…0Ø: ð³['?B~vëäG(Ð ¶NvsãG(P¸säðöÀçÆzÁ¦Én<üzÑÆÃ+W0T®üyåÚ€?¯\ƒ€™øyåÚÎòO+×Æ |rEÊ© ‚tSYE—(׿‹TýË?½Mïÿý÷[¿ÿóہ›÷ÿ}ƒêÊêòõi6@¸¶}/“Xÿõ«øLnƟðéCÐ.áð¡øQëçÙÎó=‚?µ +ñõx…å5þb] +ÆWä†øƒr6eÆ ”§üÂÒܐóPþ0>–ï±üE'øtÚ;7øËÂÇò=_œ‡"ÊÍ)‚/®¿d7Ÿ—ìüt Åçò$ÁWè‹OM‹ÞštŒÅ§=«?C׃v¿‹zÄ ¼œuK¸i(ào(> ·”Xœ°>‹;nH}ÐÏOŒÀo…¯ì«sƒŽ¯ã‹»í>r‡ãÂý§c(>´ñtŒÅ÷‡ÓAâÜ cÄzÈ·û"|dŸ:Á‡ï°—Æâû8Úÿ|èþÆEûKÇP|xÿcé‹í,cñ¡ý¥cì~kí5Âû‘ãìk°®Ó>—‚è—Ä÷-ôÚoy:ÆêmAí³«_ >¨_†â+ü¡÷gKLe°<9?}nØ5_Ç¡ùžÅ™c‰Š +š.,C±AÅ%b$6d¶°D Å7u–ˆ¡Øàg‰Š +,C±Aó%b$6d<°D ÅM–ˆ¡ØÊ:óD Å·–ˆ‘ØÐ&Îñuliï<ê¡MÂGú°p\¸ +ðtŒÅcÔ<cñÁ­Ñ10† ÆE›OÇX|0ÆÉÓ1TÑ>ÒǃãB%ÍÓ1RÓ<cñAEÍÓ1TÕ<cñAeÍÓ1R×<C}`W1ÇaV;?.>Šø\p¾@Ÿ‹¾¿§«'´FNéÐXŠÐ¨'ô¯POÈ°¡®\Raç_Rï4./꼉N WU™ˆªÈúk|ïQß)*#_ö諺Q¹NaeuÙ +*¶#çJÙ`oû­Wmˆ ós¤U]ÔG²uåX’kzþé
+ºœˆ 1ZÊin§öC’fwÿæ]Kē²ÿK÷yy^J×éð37=e…h°&>yTäI«›ímpa,® +´ëÑÝ*D­1¹BTæҝµBô1®Uqkßê§Ùãò•î]¸¨D’ߍؼD‘•+VnR;Þ?¯ŸÆ°¡,iœ‚¬û Y÷•DZ£tڐtҐå/½–1iÏ Šž¬4ž~ÀD} ï½Æ.§æ'´Ï|^‘vħ"mpãuÞ³MN0òÏö8éc˜¤oíž,G´¥KÕìõªÏб!®éE±þL3¡)ââ60¦rQ³$¾çme"dpK—rN)$„ÕÚE¿«°2÷•é t¯k žüdîå‡h±ä0¬~Èc8\ýÕéYðAe}Lj +V}ù…ß^õ¨P7¢‚ü–g½ªk1‰í¡ð׿;-‡¯ó›R²TdøO·‘«œ‘ÆApPŸ©ŒÕ¦1s_ +¼™FMVl¥O7Š¼G‚L§Ëà2OùcGcŠÎUõ…Фþ¶ë]ÊR_ށzåéiö¬n”¸fdo™9ÞLrºOÄöü|Ì%7èmÕøÇ9ïëºûqº7˜À/É&=ÍöDóS ê†TóÓ£ùiHÊþ!ruíÏjrÇNÚèÍGrõŒÂD×Ô¢M$½ßi£ø¹Û½<©ºC
+7'íN:ïß5„©¥sÛíò"¸òâ¤?ÁfÚÃC§l˜œH›±×š²íé©ÖšÓnkŽß×®»Ö褏> ü…Ö„®ÖåsÊDGM¹õ.Ú
+Š•ÉäÑbeZó궨‹èXHQüDi Áé^õc×^@dõÇ¡nõ‹É¶gÚëjm*²§>,a“*”Öޚ@ss~Eæ&ghn–gÕ5¹}™’Q€\¥†Ûÿóº.ÒɅ¥(?t“ÝBSëG +7ããìñÑãC¹Ãaôlî”4Òÿ£r–R h(Æܪ£z?V‡=Z…Å™y0͌PcvôjB¤lªk1ã}SÝUt•y&:ÜL»¶ ¾1}#/¨ëS0¦¸ ¡<Ô ý£ûóî-cNNJœ€tŽ¤³Æ<l¥Ë¨ì|λ`VHGg?9凸‘?ÝõçÂõ/Î:Ýì†uõìŸ·×¨ïc8\£¾kÔ·k:yUyšÆK{0âx6<eoi-ó-&ÚŧÑÎ
+¬q~Ëý+-Gb!ì„@â,8êÃÍ©ËÁôþþŸoêØ­ñUòôÃSeiùü¬Õ˳z':Dâø¬^‰ ­O Ó ›LùáÙÓ8›L{eR!È2Ïft,ÁkRÏ.šC±æᇠö؆0NB‹ dµÆ-ñk—œÝòe|6¿͌oŽ½ ÉP|¶,Œ ýÉL4%űÂòfLÊe @Éb(ïIn$ÐÂ`!9 ¯“H"ÔND^æà)"P~u‡gOœF¨_ž- <Uœ*鳙¡‚7 ­Q˜[Ø sdÁ³‹òä/¯€\^"ÈÙX•Ë›) Lz6¯¾ý €ù +ÿä¦ÇÏ«:ýêhŽdï¢ÓK9â§ôXÖBYˀ?üDÿ(S#sÄr’m-(VƢ̽iyPY‘‰9¼Ø“úËä‘I, 8'
+4ϲ¢LU­Fð<ž²RTgdõVæ„$g‘À
+º~2ñÙë:ê›EsÆE&ÐH,‹ÂF|¶l.E±#Øä) Š €ó+G0Mvµ н“>/¼ˆ"/Û²²ä‹Rۓ'Т:óp…ÓŒ©Îü}Qy`¨!Š
+4‹¡ —¥%¬dy–Ú<Àd„[h dÀÏ4™øEÂ%|Wù +ú" ²Z €Ì@çófoü
+ÕuêÐí}T]r©Lÿ¤ê:ýÉLÈ +ÐYT´šøE–¦5‘/] ì¨Ð˦U 5dvmio l%ÝÁ
+,=^Æ/?- ~Ëmr¸$rö¢exh^y?ߘÝ3s¨*¢x%Uæ3óUÓW ¤aÇÇ 8P{b÷kGçÂQÊvªj§zHMÑ—ž
+aVÓÁáf·a–x'­€¬®/¸ 5 ™¯×¬f|›"®æiékñÅ՜_ÑÏ7$yQCÙ 7 û8 Tź‡ãdiº9høtyýT©e§^ž1¦ž0L·е*Óŀ¹*,e´Ð'Ò É”œÀúRÅ3²ÄóÌäˆ"²„T€Ÿ {rx°ó3E&ŒFûffc8C&"0Ź„`"eYp005¿¼ô´.é×bð³ûNJht
+Ø°» ¿. °$U@eÓ@®¿gdõz²¨"
+‡½UÙš÷ˆ‘²0z¹ŸÂXq¤“¯|3+xœÞ0fÏ-ºÈ•m(+2 Ո܀¼h˜À× ^Ž€x¨ÖøÉ=}­¼ÃÒD'ͽӟŸ\œŠXP™‹©ø”’¨Øƒ‘‹ì¨d—ä40ÏN‘à ‚‘K¤e*q |‘ÀY.Ð¥™¨] °ôþ[öԊyë^‹ÓXÞ¢V2e}‚hB dïB¬~Ȁ¬çžÍNz„üÊí/F¥.Îßbhä$j]ýÐÒáÐáYg di@îxåeæþn2ˆ8)†»Fzь¦Xe 1¦’–×kÀd+b5eK†nD \
+hÉØI`‡1’yœY/›ú(ypL(†Ù8 b™×ŒÛâÔä\‚:Æ7‹ʀ„¬ßTž¥ÐÏe@ž¡¨àbZ7Dç0„‘ŸŸ*e\À©¶Ñ¡—.dB†´¥‘_´ÁÿõÕ¡±+¶Òó{œ}—vd‰ñÐ<­Æ&:þ3Ž–”[ô„qß²Ž8tº­aÕt<†ª‰Ë†`EpA(…êœÁÀ,‚1˜… +&ƒ`ž‹ÕÀ·Tb5<ڞª©òìCpc˙ +Ôx帲D¤ó¾;Mà鉆®Í!¨äa´¼#—£SÆí?N™â$‹êU1:GŽnâX_¶|Uח#ŸY­U±KrÀÚQtîA$¦%²Ð`43¿±êÆå °XªÅ׎^¤Å<¡Í—­8›=Ý@X‹jŒ0¦c¶• oëøDB¢û>4S!Ô³:—fîá݇ ì³ó2MF™2£o–Ìá/Çð¤¯Ùc¡g—XþÓÁ/ýÄ ÉA¼¡ñZ‘éQ{3'f©üä<2Ë\‘Ì”eÖãV@Ÿ¢Ç ¡¨~æø³ìnÀ ( ì„J/„
+[ý0ƒŠSq⠞½•A9ÍcáóB=ÑRŸ¶|I0ç!*ú’ÊN‹Ï™-}I$oÚ3Â*Þ
+ÈÅô%•¬ø’tíIí){´®õ¨n·õ¨èBÍEMÙßkØDæ +˜o§_BPŽc—‰ZL +$.^ÜÆy‡.§©æËÏ£hà˜3&=åw57M5Þ2LuNQ؀I<…ß“?””ßâÄ”¬Q™ŸÅÎÍl”…i£(¿EÅ0®=¤™uNX?æË۟%LìµÔÎÞF—;™—>Ð_˜|-Õüô×Õ©„Þ&“V%KfY¥Ù`öMÙtmÍ@ETìi8§O<•álÉÈYðZ   e¯œ7X\r@¥Â°{k-‹ß•=ÓR (ÂæÊ~»¼6[¢‘å8Á=SH‚äçuùƒQ¾<½dˤY˜±Å¦’€ÐfjKhu‘Xî\îaVœŒ®€1Àò⻑AU^žÉN$Lú);¶\”yN‹6šhŽ„8'ºšTý>adZU¶ÖQÙX* çªÔ9ê÷@9_§´ìÒ_þ €4/í €”eøbE5yÀ!|Ž&èz‡±žFý`¸£ìE0¹%«KgNÑ5
+if³SSÅr&z¤ôD‡8©Šº…_M¬\ÿóùMËjË °¸ð9бº€I”t?jôL`cÂtèÙ~à‚wâ˜,.Бð +œ3Su4ÁÅ €~"Àt¤Â*ŒÚÜ40”7 +ƒ1'0‡Á*èÅa0V¦¿LLеûBa°`ʑýô»¦²—Nø©T¶ ­ò!a*ÍnCg¬0•í‚ì6¸¾A欑˖óÖ@.Ûù̵F.Ûù̵F.Û4џeȯ—Ë\ñÁÅÓejt‚0к@5—ÃâüC«éh”}¨GÁƒ æl;Aâ$•šŽõËBF´˜³õüRÑRËø˺uBF]كŽw™Z)¶¢
+œoŠº +€ªSJ¸{mê´ÓM½R7çŠÖ+šÆM±z ¯ZW/Çà3Ðkú³&>Xûž "/kR³54™,µ•Ù•Éa¯)„ ¥œV"cÚÔ¦;( ¨M.xtO‹c68«­›IB§ö†õX™“¢MC‡ۘ£­Æ12—‡²a’X6|áI&LÁ…M}ôŸo]m6UÊ;hÀ›Éñ%ËF퉃ڦ• Ú€ž8àøß*\`.æ„CE8Á{¶´*5¢„Ъ–{Ñhz–©©ãʽdmðÖ9 +õZ€Ñ^0É™±ˆ7 wPÌs͖l&‘O…Wsøƕ_1‡QÙQ[Ã÷¯ì˜]¿Ž5l¦#›B¬ ‹Ì,—ºÞ'žMôPkÜ5ŽX%ñðšºs<¼JÍþz<¼ò:^#ΔY|%^Õè>Q<¼ìÏCâá4,nD‚?² îœ[ò,õð%T¾ÖÃ>/¨‡¯á¿\_9ڛ߸Þ³\«~‹º¿¼‚510&.éòáu èlÝs@[í\LJ²'€…èŽÉ”" +?¨î¯ W°SÅ± &|ݟªÚ©ÎÙ/¬èó$ªð©º?¶3’§öl–T”LÌ>{ÉÌö2—„ÉÖý•ÜÊJ'²¿* vs¿²?¦ö¢èÂ\öWø½ã¼¿î•Z·@È\RöwäšûeUØkkokÃV¼0KX6Ÿ-ûÓÕNu‹²?#åÒw\Ùp¿Ù$&~LϽΝrՖ9TZÔª¯»gB3îeŽnõ°SW•Žõ
+ +KUrÞ ‹ç
+µÓDõŽ)â4ò¸1¬ãBkŠj6^;¨ãb•<ô‚xMQy'ðüuãv3Î9ôâÕ¡p»Êg:ÕÆôŽS3m½µgOØQS=›_[ +]ìT؞QRíULÕ +;GŒ>aŒÐÊ]"Ž•knOVh}ÂUŸéO+Üä«á3æ
+jGFù€ŠO vÊ©ÒÙ0‰mó/$³Í1Pœ§Ÿ“òK’ÒT~ÐBÔÔ~ƒkž3=XoG×»ÔF×)m÷† m M]ÿEj–û>%SŽ«?º„4WxS7/ÁawjØՎ|V]– nx¶°A9Ìܝ&Âc³G3ì$ ù‹]l˜ê ‰p–§¬êg²aª´±Ù{Yñ6B~eñö†ÏÇ{ÜãÄñ 4m®J@= ®‘aa†½Ò‡WOÛÜ­CeYák‡Ê‰®Åjâ_‘3¶–m¥Qß*9y?ºC%§8_$"§ìe)WÓæî¦MåN´M›â*T›ÈjÚüò¦M vȆ Ù®¦Í×M¿uÑ´qb@ž5¡–¯ªè™ÓÎÅÁÀ³uäôçÓyéç³b`® ‡Àœváè{db
+(r /&:É¡m#A´µè êVæ€]¢bÛ´’µØJØnë|¶Ç>“xP©þw\«D3;ár©JŸÞq« ã¨:ÜAS‚±A™VÓÔ"ë^“•”Z"K&¸0@°ª™1ªünj~š)…ƒÖ@°8ê¯\ã”O_5xª7
+séÏh§wŒq\ïµ`í#Óºšsl1wN>?­ºwØv ^/sÞBï<B†©ÍoS›Rð`j²*ˆœS/©iŒ#¿òƒüj˜$ê +È¢. +ûÐÐÇ\#Õ*«¨ìR6[Yª¹Iù¡ˆàÁ±g|ÆB³¨¯6-.À gÏèå3p¬QW¼ ]ë,΍aΗêªù +k×mØs­*œ^ö¿£´ð|DÅÝÛS§LþãÚH±[-ˆ`ÖÜÔKEfD),]‹Û|…êyŠÛh"Âû³·­dHmUükmÛëÔ¶U– ŒQ¬µm ,{ô4ùµmò¾Ö¶QÈ-jی_
+Ú^#åº2¥ßהë5åz³¦\§Ål3ìw)TV™®mÈOªž¾\¯ £Tt-è U3„žbÓ;_¨PÕº­Š›§77ºU
+$}:° 4¾ƒ¸Nµ+!g.ƒå'
+†Ô +A{Œ)zbæÁFÍ¥+ó „’ÎA“âêî[w¦v°r1£sõíÙ¹­é\…KOÛOùaæ‚,Á€By®v^Ç刉ƒÏ
+‰G³íüå]yÓÍ™ÁÉ-<÷•Ë+©Âƒ¨ú“¹Œ*³Ç´(,ê¸nj'‚Ðœ£ÄÕÍ&¦¾‹Çb KÓ ’Ù° ð$¡¶­‹=-8žr˳cšp2æ-_ŒÁNGæN†VǪи£¯÷Ú(d±ÚŸõnœ*äŒ`ÀŒ‡`­ë¿ª‡¨…xÑ=8œ!úÞL@*æm¨¬c„¿§²øìùïÆñ•H˜#“£j¶U¸¸”êÊ£C*è„x_ ‰{ ÷H«©7õA;v*à/û¿4͂öùB[-K"×%¾¶%ᩁ—ÿ§,‰QÏcI8âRÍȼèXu ¸iIœÖ´$²qäí‹1–„\våê®?bIœìZ™_bIè©úáŖD6ÆXžŠ¯~½×Z~ʗr­ç™ŠL–èé=jÜéÙÅûKÞmËÔ¸3wÛò5î‚î0Lvd«Æ½[Ð>änÛï™ÎÒ0§ñLûewÛò5îÌݶÃkܙ»m/®qgî¶ý-k܋7cÁÛ«jܙ{lUã>þj[æhõk5î•éþœ5îޖä%®\ªrÊÖ+—¿ë•K’€Þå+—àîyæÊ%Mç/Ì=­+—L˜ÊŸj1Y×­-&1è}½rim1 d³^¹4%Õm€åPëJ÷<{e|ÝÂc¯ÖÝ xì_éJ÷ý]éV#¿aWºðØ×®tWî ‘Ú5LþóJ‘Éâ/Lëlnè3\ Q'N†¼óy‰t¬F^b]Ib#/±“^ØÏK<ñô[\ a§Ó«¶ºBd¹éÕÚ‚€îÔ"ƒÖÎï·é ‘DZ(•¶Yñ%œòÌWg—ÃǟoÓûŸû??Ä»’nqºÿüۛx‡Ö·x—Q~«¦Éyñ.¼PjùðçüöïÄ_©]Ú×âÊPâ?ÞÿüëÛ?þù”‹øMV§{Â0åÚíÄò@üøaw®|Òz·º|6ýظŸä.=ò +ð~2i¸©9þq$ìDF¥j/w ‡Ǘ¼Öô¥8kÌÍ^Š<ûR´ÛgMìK‰ÓÉÆDdDx…qªù…gñ‰A¯Çr“A%y44Gk&Þi’†`?«óM¹5ñɤìòqy7 Š}“ÂD-Nuȅ´º%NÆPêÒ®’ö@w8¥:5û:/ߨ£þËÕ@Þ.d‹€Ò´Å“TP}tǯ¿\.øò+#½Šî&Ì[røPi?§“N–`|˜„Ùšã‡e‘j¤¨¾5Õ3Y  Òí6¾0­8¸?¨¥5#xƒ
+[°*ì ‹ŒR’èQ4ŒÝ ðëh‘¦ÿ5ñG-tÑ"…Oh‹ +T½;³i[¶'ù2J£m@W²Áö´…3‚=C>±/.æ˜Ð4ᇟ+côÔÈ÷õ+§4`n(Á¿TÛ^õ¤H»~܄íØ¥‘f«>gN¾€ +Æi¯® +†&²ð·´Á€!”NÍWChZ +¡i5„žÏJé1â¨WxCèã5 ¡šh ‰6V5õ¶lÑ3‰6‰<6‰Œl=7K… +"„ÕìBóIB¯B݄÷d4ÙÝÉÖÿ}'»6Ä&hÚ@öýRâ€#2J*#‚H‘…ˆRS½nSUæ/1åðÛ%„’™0!\qtٞSµ¡‡¦‚|Òpª6]äzüÌ-¬(.œú
+VTJj&ªï
++êã^V”ÌÙ'«5­VÔ´ZQwP%g­Ôþ)*ï`í»Œª!Ÿ?Öh46¢k3(FBˆ– øÒ¨wHxGyøSi‘É£g~o¦Ò '~`:åÁ9LJÑû§ÒÝ!í0ÇËÅåäŒ^Ô8o´F–­Óˆi¨Ê“}áіoÑ.Ž +•Úb°$P$qÀ…°!–&Ž#Iô²{]Z*ÉI®kÎ'íð¹3á—ã (Eúˆ H%š­˜=ý‹ónù궰dO SEÄröH2œûŃ¹ +Zù*ì?ÄÖé°Jì×dîù¶´õ‡”k×N?ø†6ü¥½—ÓfܒQº:mápuÚÖÐwLJJå³Âe‰ýÁ>Du¬ŠƒÈr7øØÙ÷<bzW®
+téâH—»Ô +èQ\…­7$z‹£Í×PÎ#ŠûCÙ¥xµ0@¬ÖÓÊÜ:VæÄ{pCxÑ(9ç
+³ÞÜˬwvi½½šõáp5ëW³¾cÖËɛ¾Y¯›ºâÁqx¢$¼_ò9r: ÿûNœ¼ë}T©-N§ÉhÁO@OÁ~Ûµ¿Ô¨ÜÃMؗq„|R°ñçbò{àÆÓVËèÔÔQÇרûánµa`5iWæ¦u:¬Ì‰_ÝÃùUÎd ­"¥—4Cð xßïfKt£’Ø®¡ÖÅ·Žuñå!hÍÜ´“ Y ÈæùNq•¿èØK$þIÍ:LZ•·ºi&uP³Œd^hò[MB’¹d±m¨;x;’¼D~'ø}Yš½«>¾y{!çêŸt +¹è£¤¶Bq-ñk(¾ƒ“ŽÒÿ†ž›J'— ¥eöÒI܏Ú'Ú4¤mºemµ a‘£›ÜҞˆI=gHåknþý"
+¿>‡¿}Ô췏 þAÚWYP¿}ö·˜O£žÔIò6u§²ÖÂûž(?䲩'N¹ãBêÝ:)OSñïr6ç¦i=›[ÕþcÑz6×;›óZÐÜ]sá9þ3Å»j6”Ùurô‰~µcOuô«}¶fºñZt„OÓºçr´ö§‘£1Ì*ÞúQ7Ý.ª*¨,-³&u@B_J>Aáb¥o4Lyq´Ìj<Ðí‚x(ô£:¦¯˓×zÖ±[T‰ï¯9(ÆÑ¿sìÒãaÝ}ëç
+ǞS鈈d1¼8­Ã•³ýîç\ât¬'ƒ¿ðtÀIˆ=GG]˜Xtø7ÎÑ)í{VGç1®ŽÎêèPGǸÍ bz@Šn¢<Ö!ÆÑlx^G‡aCÙÞI>n 0Ñ$DRŸß©Tê§V½ Úvo/KRWgí:
+?z®˜ùδ¨¿;ÒQÄ`%ö,á±+-â;iNÑ—ëԋó0eÛ1 ®6öû¼ÑLì~|T»J­;kª|‚3S•f¦^šíAÈ÷½P~mÏ+Êût&/‚aUF: §íÂ~sóøY2W‡âU§6þ|ûÿ +Ãoó
+endstream
+endobj
+21 0 obj
+(Identity)
+endobj
+22 0 obj
+(Adobe)
+endobj
+25 0 obj
+<<
+/Filter /FlateDecode
+/Length 10670
+/Type /Stream
+>>
+stream
+xœí|y|UºèwNUuuõZ½wgëêtB:!! Á@²°Ä°“h$D¶$d#
+ .££‚Šˆ+°ƒ è¸+Ê,¿¹:‹0óp™QD\FM÷ûNu'ÀlwÞ}÷Ýßû#çäì_Õ9ç;ßz* 0Âfà`ú´Y¹ùç>¼ïmR‡½Mó—5·mÝ4q/€Ë}Gæ¯îTÆ~˜Y > @hZضhÙìcˊÜ'±ýö¢¥köݘ³ 뀯tqKó‚ß<¾ð3|×ï0-ÆÓDޏï²c;mñ²Î57~`\Ží0€£iéŠùÍ7=½ñ>€ê3¶/—5¯i3|(â\d4Â+˛—µ<0sÑ+sß æ¶+;£)š^€æÙx[GKÛ¤Yæ6€\³f¿º7Á¾Þü˜¹|®¹ô+­G ,<Ôñâ1V¾>¥rö÷¿ï_¤;%~$ž,Åq‘©P®{ìûß7Sw
+| ÂÅ!Ì`¤o¡Ÿƒ¸£ C.ÌÁU]‡óR¥Ü6²Ð
+÷BÕ²û9,¤V­@õžR*Qþ4è¢kÊcóÌ®)W°¦(ᗑ+H8Žô;õ +Ÿ!e;^_,-‰%µþÄÿ ÐÇàIúXt7ü'_ kàÿ2¯ÂÑNó4 ìøoô1’…koÀTÁ¬Är)¦k/XŽb0äUK^jãõ"œ¿\…_ ø•ÑObïQŸŸŠÏ±wlþÛyp,óÿtml]ÿ¤ÿ–à0 žàÿó@^%0†ÂP
+Ca( …¡0†ÂP
+Ca( …¡0†Âÿ@ ñ+V;p¬F0iàÂ%1¥ æҀƒjUoèü»KٌÁZÞÈ¿›¶¼¢²jâ¤ÉSàò˜6}ÆÌY0§ö
+v—ÀÅ®ÛÚះ[á_îBõüû‡{1Oe·Ð¸kÃ!Êa*,ÂEµÁ*X{ᜆ?)žh@…ÉTaj  Za)t Â|Ì`¢ÿëÆùÑ÷¢]§ïƒ})¨Qóvœ‚ãgËƍ-½lLÉèâQ…ù#órGäd²†gËHOó§úoJrRb‚Çír:ì6«E6›Œ½NҊç(ìJU“Êh
+ñþI“rXÛߌÍu4…쪺&¤4©`Ê¥A„\ø7Ádp’ÈJ)”æd+•~%t¢Â¯„IÌ:¬ßZá¯WBgÕzZç3Ԇ>>¡TºW(!Ò¤T†ªV/îªlªÀ÷uëuåþò]N6tëôXÕc-äò·u×8¢V¨«rL7­WJðWT†<þ
+¶„—^Ù¼ 4}F]eE¢ÏWŸ“"åóýóBàŸ2T(W§ iÊC¢:Òʶ·(ÝÙÇ»¶‡e˜×0,ð/h¾ª.Ä5׳9,œ·"äZwÆ}¡‰/·–×m½x4‘ëªt·*¬ÙÕµU íQwñ¨åõõø|–¦W5uUáÔÛݹ¸¶|¶•Ø¦Zü•¬§é%$ù'øw]ӄ’Ђ™k}= Á¾èiH¨Tºf×ù}¡²D}sER·ºf®íõÏ¥#9Ùݲ%†Ín“9^1/®´ Ž©5œÕªg¢“°ù'#„”ù
+®¤ÎͲ–ÑÐ54‚a¨'øThCkH*oê’Ç°~ö|HH—ýJ×W€Çî?ûé¥=ÍñMºü°*#ŽAÃñz(ee1ºËñ qãÔö¨œìÕaZäo“,}0½«“‹8÷ùØ©ÞÂ<l„6Ϩ‹µ˜—ØÁÜ@}ˆ6±‘ã#Ž9ldóÀÈàãM~$ßC*s;BڌÁ³ì´U."Î1ܯžå¯žÑP§Tv5Åq[=û’Vl|ôàX¼²•×q‰4^£‰œ:Š”xÕ 0kÔB|:þhTJ^µHŠjQªBrÓ¤X^¯óùþ͇ÂÑÏÙSjqá±ø2Cc—¶/»¤}Éò ].˜Ï Õ³ººt—ŒU¡Üéêªò+U]M]Íáèæy~EöwõчéÃ]m•M'Ž½%1Tµ½7±˜ŒAj¥0¡ÛO¶Íè’m³êúdßÛf×õPB˛&Ôw§áX]Ÿ‚’Ví¥ƒ½¬¥°T¤ôªU‡û‚›ÕQ^íPÛóÃÔ>í@ùaë“Õ> 9ݳ󞡏áhè))†é^ّÏÊ‘5í5Xó7·ÐýpÓ1Lç0ñ‡ù4Ls1qøøþž ~Ï\µè:#3+/¯ÉWÛÁI±RgŒ•Ò˜X™WÀàöõV®aí}½ùcbí¬‘±vZ:N/Ó}¸ÆsjnÆ<S¦M˜xœ|_¯#9ö˜dg=ԛ˜o>FBˆ‡ð¹‡Ô%>Ôá°ušfšHύ/&ŸàÛö¨ù&5Ÿ«æejž«ææøèŸÙìj~Lͪy®š—©ù45_¡æ*<9‹ñSŒŸ`ü3ùsÐ
+Ù¼DFUä%Álô’>"}O¡wW˜èƒÅ…ÞJ¹7S2ћ¥Óú¬IÞL¾¬
+o1Á÷‚DP§€Ë…|kµhƒaòÄӑ­Æþ­FÂ¤¬'ërïx‰Œ£<›®Ó=˜øž¬ïóø´¢6‘êèã=Þïs¤¶Çû7¬%=Þ¿zÔmÞo½g¼ßxŸñ~åâ}=ëqoBÝÓã +{Ã<BíÍ
+Óǃfï-ޙ¸¸3Þ5Þ¥ÞåŠ:´Ô‡EP5d5xëP¼á,Su–‰^|Ío%Vd… 9â +zoö䨏æ³GxGz;¼#¼êtÙ±é†Ç֖Ɋ#Þa8Yª:K¥wŽQ2JÅ;'î< îÜ/îÜ(î/î¼LÜY$î%îÌwæŠ;âÎtqg²h×Zµ²Ö¤5huZ­V£åµT Z{8z:`v¥]#³BóœWë2e93A]”h)L«¦Õ³&êÐñùP=O }=Ë&:”‚ Y«¡zöwht :,Fg†ŠÕ!qú•u݄ÜV½!º +Ysv]˜xXזD¦›ûðT=[nMdetË­õõà\]æ.³Ž³”TUüƒ¬)ž.wà’P=}mžr]¯è+bs6w²æNÖt'‡î¬žUz,¹>”Ï*ÑäúêÐîYÊUu}ä)òDeEy’õu}\6yªr&ëç²+êë«ñhT8$û§ÜS¬@8í¯¡ŒÁA™ö×*Obp~É.çTÀ¯ÂùÊ%p)äI—Å
+„s†.Åuú"¸î£þʊn¿à]GU˜£±w…JU¯A|^YÅ«‚x UAª.€äÄAF ‚ŒPgâÈo ƨ ÀÙL+´L*[­L¯ëÖ„zÔ\jé”ÛÆ©çnôŒ{8ñ(ü‚ûô¨¼uhýéý ¬ÌKI®ÆÒ`—ˆ‰A_æsoL<Ê9 B°ÛÊŸ3ž +!õ²!3#ãCù’ñ!»-8ÇEëìì\…ܕ­ƒ?+ãaU¼ì„êPÖ¬êP*ÍnQ¬D˪¢ûòúôúÊpôx¬sv–²NŽ쓤8 bãÈ´l2ÍKŠq õ•¸œèb v®TsdPá(xÔ´ø pD?Âô1+#­ÑÏØXdEôôÈ®‡ã)ž…c°za?Æn  `-܂ñø3tÁƒ°‹‚•è1íÃú3ä9Ú +°\èïü ò= OÀbD?È
+¯Ã ¨…]ÑÄzð ÏÕ}ÜkÜD?#Ud9Š‹D¨€™p„û Þ%<+¸…•ÑtZ%xNÐËqÝtY‹a2ztWášÁµ¾ ¿%™By”ý&TfáÌká6xÞ ;h ]E÷q¯ s¢÷Dqö;OèáV¡Ÿ×†«¾îÁ}œ#:b#/87oäËÈ_£ûpçàÆC%zŒ›á%xރà[2‡,¤:›kã~QÔ=„kNFïq
+Ƙƒä`bì>è¦qÛ#/E¾AÈaÌÁUÃÜâêü†Xˆ‡¤“ad™EZÉ^ò=i ½Žî£ßp—‰±ˆ{ˆ;Ìýž;Å}ÁOâ×ðjôÑÌhutqtMtOôXôˆS/z¯—ã;¯‚«¡wu-\7À6<­{1Þ{àaô Ã€Œ¿„Sðø¾!&’O.#¥d!YJÖ :Lž&ï_ÐFÚL¤'8?׀sïC¦¨à§ó+ù_D 2:²=Òy;jŠöD_~íGlzçéˆÑ¨ƒœy 삻qÆÇá „0…ßÂïàOˆ9 £LìÄEÒÈp’CrI™Nf²ˆt’µäzrÙIî&÷’éÅÕ<O^&¿!“ÏɗˆD3ÕS3õÒTšMsè:•.¢[éNú=LŸÅx’þŠ¾KK? _пrΎ1•Ëà&qS¸«¸Ün-·‘{ñù&wšçñüÌ|&ŸÍßÈ?Ìäßá?áÿ*è…Û„ÝÂO„„4 ‘5c5Ó5‹5whš÷DNœ!.7Š›ÄëÅ#¨ýüÚ' ¹£wzQ WÁðKò<¼Oösvú8™N!wç†%ÜOÉυj¸™–Ò©¡Nî/d5Y +îQrÎÃ4Bß%þ²žENÚN—Ð5¼™\Á?Ê÷“Nþ<GÏÀ~ú™z­`çÁÙV£~]FÆam,ƒû©ÞD«n ´Ã‹p¿F¢;ñÜw@£Èdv6ô|‚Üa!ep +òI?yH褐uÜÇÔµ¤Ÿž"— °5úu¤—NåÞ$góžEz©&‹i ™ýð!y|Hç@ +½â ¿"¿'2UXÌn9øÓÜdn!µÑgþî.ä BN8—s¯ÁUäÇÈý'h&Óp÷ù"?âq‹q•k(On@^xz¹I¼&À!î<Op¿&8ȯ!ËÉîhe#|¥ÙÏ?Åu E|RôÈïÈÃädô(ýŠ£ops"‹È½¼ùòGȽˆ!=<ŽÏߋc?h±–ŽüxÒ«e›„\^…’ër¸š|‰sb©ˆdÂTš
+KèxQÑØÄaðX”qòrN~Ã@ùpíܜÀîÖ8aJ7%Ï bԀH‹{@àÃdÄ!t"«&àÑj6N#å½Ò•Ï£Âúº´¿tª|¾´¦¿Ê°.ÿ€ÙÈ<ŸÅgIÇ ­*øAáŽÿà{Pøã̬z22ƒ›*üLP4ßgzÒDE¬†©Tû­&_õRÓ·&çSyÙ:w__sþ¬Œ?gQIŽÌ#„Z
+­ÅEÅ ÙF¦Ü·éúÚçn]ù~õÊÈ RG–|IxkÛ»"c"S~9¹Htwd-Tg­
+ZZud·i/ì5q&mÄKæ + SÃæRŽ&Èa2«{[Ä׍5gÙ2úã‹h$V‹ŠÑ_ÖQ2Gî¼ÓõW<{k'ѬZ)ü2r rç_"M'¶½»‘¼B¿O¦fÜû¤³MÂq”>{ŸžjžšÔšÀ™ÂÑ·‚5&K¡AÁl˜9-!=©„+2—XƒÉRêé2ýbÛ„¦Ä¦¤ùÉóRÖÓõ\íâv'>¬ s.¯ɉYà4I žGKÅ.(hJÔ¯ýòQ<b y5ˆj+UWæNðßü”º›š³q¼~¨ž[ÙY‹«ÄUB,Ö¶¹@ ÆQÄ1ÆQ…þT8¬¨¨ ßétØE Ñˆ>qMÒü}¾­°:Õµcñ¢{|Ý ß?³áͅ‹ƒ‘×nºÁGwúoèÞóL{ÑÔê‚Ò–[wܟð³?,~vÁ·Îþæšm¥û~$¼‹'’{zïÔšå½fK¡jž›²"[
+-ŠÑRèf]#õ–BÞmwÓ {™\Å­‘yÙdw:<²Õ\bú±ž”ìd&;oÍÑsž^‚õ$L›ƒvóz“3+O$¹" “LåɅå ÊçÛk¦Î#U-;k-Ém<#÷Ÿ·”XKˆµ$††FÕ FâҀ_‹l+òåó.1#ÝY_ÄÿòÅ«"{ù*òêg¿"—ý‰ø\O'ÞùËþï÷üäkÊ'F"? •G¶î£ï~iÙsß¹·#üñ³WP"~‡vŒ›ÖËö$"®X,–Šä‰âD©Jžl­ç®´.å–ñ­Ú%R«¡Õ¸ÂÚj[‘°Öº)áfn‹¥Ëú¨õ]멄Ä= §h·†–Ï®;¤ƒŽ~Ük0by2˜€¸4Éú¤BG3Áaâ€è­ Õ¢\VZVZj±ºJØFÙ闠CbŽžî1)šg£ÇAÀÄGý/T#jµ‚Áh2éͲÅb²Ù«Óåv;¶™´’Ž¶ô
+V ú}™Á™B*)V‡Ý*h­-Ö-&»E “¤Ó¥èMv½Þ„–âvØñ +q;¨dZ¯ÍÔRJ¨ÛšiµXôz.´’¤“´a²ê°À<a&—eZëݒÃ!¹Ý»Ʉ\t¼wx P-éj,5Ʌ¦\ýýA=·B¿IJÏésÊhÂ:\ÄzI¯ß-)ÂN6 D< &½Ã-ë]nWÕªs%—¢Iî±0âh¬ûœ¸sëþÀrùËöurcû kì”ccÇc +â‘Ï0{þ¢
+”ðuÀމˆzVž-E±†lF6È/máV -–ÂÅœh«lz饚ÁèÑ£ÉèÑõH·í¤Àæt“â·Ù4"ñsÃ4"×@ò¿¸=Y»ƒÒ¯"o¿p÷¨ùeýï?·Û.yÜ?Žþ0å™'nïç¶WE_ÿ†ìxø‡ñÜ×=ñBûõH­ ZMH­62?ØÚÉ­֚¸S½i¡ÐjÚ, à ņ–ÕºÕú­ôf£¨E‹&³,-V›,Ûd£-Eý+bÐëSt¢‡©l4¦ˆÔ.Ššfâɋ +›Qn ™FƒÏÞh “ï‚ ‰ÒõÌÀÞ* ßKbPÜ,RÝ7‡ƒ„HŒ:l¶õ’r™ _%‰öL‚
+L—èÂùÔSE¬Ç6 'uSÙÉ5ÖÕÄÎ=0<Àø9~Ѩ–êë¼ïúcüXA=J™eY©úrvž[7 ž'ZV^rd1†=,+:C¡ˆ"®KôÑØ6Bccì Ù)Úð‰z| HÁóß´OÈÈO~èXäí#·7™G…£ý¿ù቏õ½Ì]ý]7íôã;Nþ°Éâ¡ëðÄ8LÜLÉz´ªö¢¥zœˆ Žp»˜±“Ë{‰‡?ÑG×CL墉Rv¶‘”Ä!á
+läìÏ~׉Vž-r±Ûý˜/âÇ¡¿1
+^θ2‡¤ëÒõ~CzöÔuš\m‰ö
+ß"_˜¥çs33ŒœÒSü™ÎfÔå'dÙ:#’€Ñ™æu×L›7AÌÐå{9½«Îì$Î0ùY0%WÑd™•¨“ým~ꏦ-ÖBH‘SV¤p)ÏÒ5hÐd`®JôÆ@Í׍(ÑÕÕcÉõ²³ýg¶šFLˆ}Æg%,1ADŽþÄq®ÑøS3F¡¾Kc*o؝Ǿi‰œÆawù3l¨ùLÔ¡Jþ"N¾ú©ù»͸©y,™3Å1¢lmÇ.ßÓ£ÿÒ÷òÊ:ÏeIΧÍc3®XxÿõZ›ö7Ý8£úÉ­õ7ϲLÉSF–¥å·4Ê÷¸ºªmN[äۍÓò¯.$šeɸºäòyscßA+Ǔ¿~.L`B
+Ëxß´ôUŽ.Ë£–>‹f¸%7½,}¢£Ö±Ð¡Yç#œÕîHµá"­\R§ñÚ(õ°#sPä.ÍëՈ¶Lй½f½¤X˒$å&•%MK:—$$%…ɱ ¥,à§0)
+z¤< Hê0 +æ² ‡Ú4ôŠÀUÛÂÄd)c#U6vü#¹¤cc;:ÿ½mIèù7ÖõtqÊúÏ`—~ì€;Æ'Fæ¡îeZYS͇ÝÄáA +m¢zÖ¸q¢© ù‡—Õn¿üŽW§¯ÞxãØÖ½9YËÈõÍs÷,¼nî¼}ÅÑCÎOÿþ¯ný󞹹+:^'‡R·Ý¶…$\{ÓíwÝ·
+eÛJĵé9¶u%\«}Qâ]^µ<æ R¢»ÅB¯Jl•$­•ïÖ
+»Ó>\*'u´N«1§™féIZºÑ;Ù`ÞêՋ/Úÿu
+*~J>791#É\&ÙDMÕÉ£«lJF­hV6^b†œQ™®1fzÄ(ӚƶÏLTMœ9ßáŠï÷>ù]„<üøk=dåÕËö^¹¦®îrƒíÕN¿þ™~ð…=†–Ž®ÈG×oÛvRÔRÜåëHQfô€ôA2š\¸9+Ûå\¤+‰Ó˜ød×j˜D§Éž<\ô;&š®0iì.ô}}ºlG­n¡NCòu¥Žj2A7Å¡q›Í(Òí’½’h6éì^ª7¾eª3¼%›çšW˜÷šys˜¤ñɊ¡dô‘ô¸”9«"áLÿ¶{´B˘®Eá¸A=ûFTexúéq 0^TE¡Ý‰Û¦&ÊÉ?}ô®×÷œ[óJ˚C‘·‰äe_3eý‚›n\0~Ië¤{zNýêE2~ï1zÙwUä¹›çl~컍·¹å׌îA|ŒÇS÷@*ïâAB„x™éédX©cXÑd¦Þâ¾Åû=¨‡=/{ÐCÏÖ_›°5 ‰ ÀY‰Åœ i2iBˊÈd:Vx2‹OLȶì´îµR«•W¼х”a +ÓíŠ6߬˜ƒ.¥̲¹Í|
+15.-c\Œ<1úˆ¡G%æcõ7¶ŸQm5ä”׌T:ڙ©Š´Â#¦‰Å.ú41J!¾¸ÏMeDÎ=·úåE¸ãùÿeúáKþæù‡"it6Ù¶¤óiµÞð鲓[ž"÷|úÖԙ^Ï÷­#ë’ ÛvíE.iD¥QŽ6»^ ^ãI&®/OÙNÙ7É°Y9E ïଧӂu z§—L§Ójaš‰˜‰Øi6gCŒðœÆ‰ÒÈÖiç:eÔÿÖN4êœÎ:øNB¤\fՇ©ýKzs;J›uò—ªÂFùr†©h&`Xù&÷Œª‹™a…‘95íL° ˆ~k‰üº(È¥¥"&†µv”ü6qAñ8Š¤%ª’D,ý\ã &?èu¬œ_yƒïªq£Šíî7’ßx»gû]í Æ'ßï5¿cû Š\Á߈”
+$¹2b52+ó +•1‰=Ò>’òîiNFKÆæQBz oM·¦;Ê ÔË£[•írétžLc¦Ûãñë\¨]$ +@Æ)Âô¶`1×kݙ.M¦×¨Óx“Ín·äñÔ¡5äBlI®M.âuåº6»Þqñs]P§†iú!ɯÈèÕ¾L¢Êñ½,g”éÐ&"ºÂL—¬sé
+usãV³ˆÛɇ¨;?ûë¾lllïP- ¸?©_ šºàfd©âü,R«ªhUc•çV“ü’6&ÂU.¸\4gã_ÄÑÅœ‰ÆÈÖfw9/Huó4MM9uߤÜLë­{xïñO7ü¼=mÿ¯ýonÙÜwåGŽ”õ¡e»–Løђâ&˸q眒cµ;ξ×K²ï~å©ï£>·x¦™:kYq͌ +Dsí +?¸ë +vnc1KS-#ô +ƒºG¸W¸¸¯8^bŽÃå¹£ §I›¥“ç•r¥=ÒA阕4 ð<á4"²7—IEÑÏ;ë™Ï4+ºÅb&¯£TÅå¼$ Ò7{¡_¸™?ÉS>¨7ò«´¨>yWí¸‹Ôg =€ˆEy˜֌(S“Ê2Êøà¸tµÕ[ë5÷a¯=3«?6”œ+“rc¥+*Ùhò0µÕãñ•]ò±¢žq³}Ù(Î@,?WÊì0Eá"® ´“â‘Ø
+8R8ˆT¼ø}þì‰ßÛøŒïƒhj#WP¿Š[+œN¼Y"¹ö+ôÐÄ'œÁh¤ÏÈ[½HF¿ŽØوŠE½FT,fD¢Ñ¨è$‰è: ñHŽS%]Ð\2ÉWÖåêÊtÓt¼®VÒÙ2 £e›®¶÷"ZV­ûFUZàOÇ̒F¢nô"ѡډê†ãäl߀Cƽo•_*ÙÁlçŌFÑ(GB@:F$ôúee\ޘÊôS‡? Œ®¾i"ÃÇ_o¼ÇRsÏûþà;Õ PŠ!j’U¬D‚sÐáœ&lN
+œ–x…\apP8&D‘rœ?æ%©ÖJFÄÇ-É#(8ïÝ '‘ˆƒz´†ó1[lî11ZꈑÝÖ2 %`¤¤¶LIÅØBFB¬«×W+‘t`€t€‘ŽÚ‹¤qdåÓãÙ ßz)= +ÔßÐÓ §ÒsNIÚk‘·…£ßU!fÊѯ܌24‹LŽ­²ì ¤+ܓýŒÿXö;®×ýQÍÝ®»ýO9ŸJ=˜ýŒKSiªÕÎ1]a]hڔ­‘Hª6Õ4J[`ªÒj²Ù§åBnx¥YY “D‘KP‘ B“SRü^Å®°…x½ŠÙjõÛìv;받͞îÕx¼2x&ÑdyS˜™œ&¿ífÉZg—Á&Û(ZÄK‚Fo²œR‡ÂÕ+{©—õxÊYuD¾`&×ð`Ùk—mŒÕc„K¨Ö™«éÇ,V½¸ö‘U]†a@¥¡c#l”ÌÔÖܗV±&šT +42Ë[¨šÌ®¸á,r~[Ü
+Ð\Z/ÿpz˞Æù[3zçoÙâÚqøǶ ¥34ú—¾S_Xóè5©­|ÆÁöÚÖ«ÌßØ1²½6}¾6½°tޞ‡ûûé‰ÉÞÂ༃Ftx–hþ–àYºà\pzš8J¤~š¦-¢UÚZz…a!]«]cyÌrLûŒå-íëçtQ^ÃQ—K=« \Ò¦žzø~£l—±£C&F£lC¯ÝÔHÐB)Ñd\F#j1²&O÷êd,‚Æ2#‘ÓŒs+Œ¼ñº-;JŽö¸ê¶‹ÎÆ +.c\³Ã`F(»ÄBuàU3¢4PV
+ù ê9¤à8ƱǸzqcz饘9ˆñKp-rïï¶ähóu»¶¾Õ1¹ò–÷
+ñ}Ël_uÙ¦þ +ôy¹£&¼ö—ˆzÚ£3{&P`MXÐz˜…ÖC¢z5,‘¦Ô¶Tªö®ÞÞà¨M©õ®p4y5åé”WÛ×'¬K9Ä I^^DDoV ˜“[>¢,¶‰œ¸25£å"ß-LÕ¶dzº3$mrqlT5'‹™ É.ƒãZyÁÓw}uü“Û#çîúћKï\1¦c^¥Ã»kùœíí£ÈnRüցÏßz:òòk^ÜuçOs›ÖOœåÎ=3î}‡i†O"­ü$ܟ|ð]0µÒ[Ë_mnp,1 c£¼•|y²CHçG˜Žb¾Ô,ÈáèçÁ¸ù$†z÷²Ö}3¹ ¾õi<î Ãh2‰,’»5Z±Z(—ì¢K\|ʲ)Ùãd—פ·d‚IR anMS_0ù¸’Å‚†æ6U²ÊÌÒ¼\‚ÔL&N!U÷æ¸K•É†ç „0ŒT-s6ƪq·Ö‚~̯©D½˜SoÖ92H*”ùwø¸é3`ù8HÁ#ÞÆÝ3òÚò½ûjµ®é¶x:ªï=~]Såê– ‘Vá¹Û›«ÿöþȹýS_ì?ÆM¾vÄøédîÓ[wOÞõ‹rW"žÍp>¸^ân’vkwI¼Æè4î×¾Êÿ‰ÿŽÓdÐL~4)¢“ÈZr3MfÊé©ÙǞ„n­>Ž>sL ™Ñ} +šäBTɨ†P°AsvÑBm‚6TGŸ#WÅø‹ƒZYÕIoö‘RTK_ªº¸½£œýê 2±ûâªÆäBmbtÆTLŽK-{RâÚ¥>®¯P> VTÒ@󖑈X1fÓsȂ{sfÞ7³hڔÜÑs_+ià3Þ[¿z؁Ô_EÎFjÙ=üTä;ñ• +_Ög™Ñ G;Fp̀÷`åã½¾{S¹ÕÜ:ϝú; ¼ž¤ÂÌ|,} ª+[¸[Üûôû|·V¿MÏeÒ|©þÑ^1è¹dÔTXòĕæœiƒ4B†'xm¢à®OV‚2‘;I6s %R§°ÛÂüž œÃîÇ>×*.§Óôϝ c–´á…à”ô´“8_QûBŒ¥Û5çûÏ4bµã,Š³öÁ[v©`axb—^3ÉcŸ8lŪC­Þz¥ +c†¸ª7bw +$Lv•P3æλ®v͚´ôÈ2Ë+^;ôÚÏùn~óª«ç¤l8YTÛüêÖðuב%ú©Ë«šÆçfe­÷ _1i㡾» Mmµùù E +…³®ö“+¯¼R½uùŒþX8 °-˜5żмڼÕüÓݶG¤PÒñ¤m¨R3XõÙjgNoþ܂z Gî´%°ÑÄ^{dÓÄc§þYšˆÄš"IŸ–Ä*K;$N
+Ó½‰£{Ù'ËÆÀù3çÙ·Ìc÷è*ZT÷QOº¨îsTa1s +mÅsc~4ù$eüØ¥Á¼„ëv$ï(~gFOJ÷zWzVéîÛ-£2+ýiëv"lˆlÜ޸ͩ¤âþ6#]­æ3P E‚«<Zt‡þˆxD÷‘ã·(i%éFÃMî;Ä;tsj´ÃtÅîÕâj]§a•[“MråËd ïð¸Q9:=v'êÂMxÜNSŽ‚Ö®ÍCå¨%‚ ­Ç)iÑ74{©ÞãÖ ™NV]uN¦öÌîº2‘=Ó<s=+<¼'L7ô&"‡3™dPòrR8-|.p¹B™@Kp ºÑ/ÄÅßTÆ´±¯ŸíX ܞ3Gá,jH4RTǤúÑ+êµ·I¸ÂkŒßá¨Vsüú´Xµ¡ýœçØkëïJÝ|ø6ë䉗ïjõ9“›¿ÿÈñwo]Xþm鯟“[Z>ecmqyÝ Âþ_ ïAœZ /8ý&Úe¤ý*²‰_§k3~¬×T’j5 «aä(á š„ç bwͺN´w¤i" ´’f6ËÀø®À¢³¹\ՒÜia¶„Ž™k{ÄNA8~ý®¬ÞTç¬çԋ»óÕx;†mçÏL•+[*>„²š³íìæáLY¼DÛLý ›/þ¡]µ ŠI:Á¾bŸH4bQOÌL¦—­¾ntd•Âr÷Ù|×hò o;½¡b²ñ®ŽþµÅMҞh4vï.¥LÆʉ…ý.wPGII“†aÑG>á @xõ†K…Ÿ¤Âß
+€O3\Áàýÿ¾œXà3 Ÿ0øŒ ðȜ +ü#ô;Õ«© Úk¹EôZÊÅ>,
+›)¡a*Í;PÁÞÃõåÂ4r<èÊMíÞæŽÙ]ý_7²o +há6ª÷møÒgÏD¾Žj`¿ýÊ=O‹…C Áâ 3MS¤¡¢Fâ´ρæ³èe_èõ½PI¸0½§ +Dˆ}[I êõ.WwV’ƒ&Õ½º+»˜ 8ßf*;³zœ¸mkö½€‰GÕåS—ŽÒ
+Ò(x;=uG³eõ0þ£‡¸Ã0Í×Ç~+dÌ?Œ« ü·‘ŒûOãñ¿œ‹ûü?|2ÿŽ°EøV³Yt‹h7h7HéˆtDW®®Í0Úð©áS㍦ )dnŒïýÓøŅ(K²ï¿gý·Çû‡âPŠCq(Å¡8‡âPŠCq(Å¡8‡âPüÕ¿3ÁS0ðO~bÿ,ˆÕE˜‡­ÿ§3
+ފ×9ЯóÕ5ÕEI ì¿!ñRü±:'¯S0‘Yñ:wQ?Q]sQ=¶žGA|ȃ‘˜ +‹¡ËXË1uÂZhS{ʱՁu–7c«
+1GÆÃRŒ
+ÌľEø|'¬T[-X¶ ôjÌ äx¬·â³ ¶U…iÆÔ©¾oÂ,ò–`ß
+Xø_YË£J~ÞȑÊìÅ-J͊å+:׶µ(å+:ÚVt4w¶®X>B¿t©2³uÑâΕÊ̖•-«[ŒhÎ5*¯pD粶ñ­ÍK•Ö•J³ÒÙѼ eYsÇeÅÂþBh€ ntÆ<(Ä-vâ&ÚÔ­/‚U¸Q¶!vöÑóšäè0¸óïÿÀÿšÅã…
+endstream
+endobj
+28 0 obj
+<<
+/BaseFont /CIDFont+F3
+/DescendantFonts [ <<
+/BaseFont /CIDFont+F3
+/CIDSystemInfo <<
+/Ordering 21 0 R
+/Registry 22 0 R
+/Supplement 0
+>>
+/CIDToGIDMap /Identity
+/FontDescriptor <<
+/Ascent 905
+/CapHeight 715
+/Descent -211
+/Flags 6
+/FontBBox 23 0 R
+/FontFile2 25 0 R
+/FontName /CIDFont+F3
+/ItalicAngle 0
+/StemV 24 0 R
+/Type /FontDescriptor
+>>
+/Subtype /CIDFontType2
+/Type /Font
+/W 26 0 R
+>> ]
+/Encoding /Identity-H
+/Subtype /Type0
+/ToUnicode 27 0 R
+/Type /Font
+>>
+endobj
+29 0 obj
+<<
+/Filter /FlateDecode
+/Length 19850
+>>
+stream
+xœí}M‹ìȒå>~…ÖÊv—\. ª^÷h˜EÏô¢éՃžbˆl˜ÞÌßŇ܎™)B™‘÷FAA^ ÉåŸfÇ>ý_vÿwÞBûv¨¦?Žÿ©?–~úûûˆmŠ±ÏÓ9õ¡«ÿúß»ßÿ؅êÿÚýÃߚªmú·ÜãØVüÇ.VÐN«8ænzs›8VÍÔT~ëN?þñ¾û·¿„Ûùüüá_ã:Á?õùGÞb75“þ½úãŸwÿôÇî<È+ûÚ¿ +éôqßÓÜuom7ŽCWõ©y;<פÒËø£Ž-t%þˆ½úç§þl~ +oCÛL«yŏ·´ô]&àÓ&ó‘#üÒٞ‡iNY“»4~+‰ax§šcÕ¤¡ ¡œÑN1‹n%°’&†uàCÀÊáxÔ±Ïï@Œ±iÞº½Ýïú¡}뚩±•J3ûݟ»ýoÕ^äP]|k§†B¬úaz`j&ôS'ºæ8Úq¬ú¾y;LË0LNäscš|îrƒìyۇžýÇiôl-Ï#ŸÿèÚ·1>ƒM\\Wßàá4œV³™çw¿;¼t"¶oÍüʘgҙaÇ·æüjz‹§«¿OÝïóL=7=ÍNyðÜðiizwš»ÆP§•VHç/LNÔ¶9?(¤s‘tžõn’òàHm–>Û½ºß•ßVº sª‰ç¯”ÞK‘$ÔóÌHsi^®2 º{‹ øüµ‰šæŸû<‘òé»ÍÛ0ÒqÀ°I¦¹ø663©)‹ç7¤7¸‹ÆyÖF»…ŽïÆÆ|ä°ScvÄ:HKeþýæßväòyÍŽœï]ÙEudZGbœ‡„ÄI„yr²LCÌl ›.ËT˹Æ­qfçGåÛebk\SÙKÂ8dk<ÉÂ`æíT6åáur¬à/iia€×g²ì$iRfK¾惣:/óUš—ÍUf#ÀÄm6?XÚ® +ʤóíXËI*cxßIêvÞ°rđ÷†ò©ZN]ò#v ûÏ]ÇqÞ?dÂîBž.!d™ëò¡ÜL–Göu’ùٔGÆ,Ô±¤¹2{€fæ9uZÖq´ËɞÃŅÙÅGûìi£ýÌiS†Á.‰ì ù&Ò ór eå‘66–VÒ¯ «GÚà¾^öêôú&žšß†Zê'ÜÔ§'†òT9dç‰<ÊY1¤^+dZó<ï°7Êâìw²(H,³V^ß³67
+¢ñ´‘‚¨èÄwD3¿U‚hÞºT:eAŽ²7óܐlá~n².½:°óé,_‘cØÄ"K]h§+oË££íwBUvmC …o„2ºùÎLoÁ‰’"…z夜|ӹҏSçåH çðb[æ#bçWÙbùdð‚|YŽ!Ð;ïˆ÷}éɼ=ré»ìŒÃŽ.ë!;¤l8é{!;Jtíñ/“>"f:…Tõ.ŷٞÜTÖµv§¯Yh¹+
+YÃåäÀ¤¾<Š+XÉ£¿.ç !KouHY–!9“Ge»}¦O!oc²}.=í«~í—ôÙÁ£}‚l༶–)¨cg=ÚÙ\DEÑamd±ðÁ„#âe ä¥‹ *“ׯUŒ +r åh“5–]Bߐ6â†&«[ӍÀø½¢â9
+" +úL€éD²z«ÁlѓzÓÔØ¥%+Î „[”/×ä!¾ +vÃ1Ç#ƒŠÍDzˆTrr¤rÞ?k,ÿ†ÃF¦ïüY½óȑVìûê{i3£øê­Æx`U£eédÛ#*i A¡³,u²·³Ø
+Pp–µ +Ñm)«ÇŠŒõ<+ù…ÑZ4*áƒEaÔbÑüXЛä¨æ`iŠ{!ىqùL ø’˜{‘”­øfYâÆbKäÔ£yJ©Ñ°ÿ£AKp†²GMÐB²ƒER†MâŒ(2ƒX„ßDsìðüý‰Ì­22q²øò=Ä:À£ŽJ±]&è
+¿\TªÑï€Ñªê x­vCH–·@Q{§fyôaƒÁp6<¶wõ{„!’£…~<³+±X‡2 äi~p,Ì¥ø=b#C jy°÷ï–Õ)ß@b¹G +µœ%ÿØ1æç`öý¾¼‹ö}Qð¢Uÿ©²#2ò‹íûcsêU{[”ÃûÃÄ[mQçyÖ¶(ËN÷À®´-ªqf'ÒæÆI5黢+T ¢S ›X6Õ2tÕ[ƒ‹¶µ"ëì,ÐRŸ±Î¹“ˆ abA"¿nAn01‚sQ¶ú3‚å1€ Åm 3×àBâuÐV¥›aa¶Ø
+<QWÀ°j\¹ uÁ‚=Õun– Ù%# +²+3?øµb-„ùã¢éov­×2ׁÝõŒ.†Òü÷rU\/Î;äZWÅúÀc8Û1“ ‰¡+Þ •9<_į¢·o‡@—ƒ‹ƒexûûk:¼åöÍóIÒkš´(½¬¿ù
+éu'Ûjò—lŽú9¶aŠ÷³ +Ü$˜3žÛ:+"d@Ó^ôbYÙÖlÈ3Wk±² +8qŽÐí¶ëX…³Ù6ð!⢞Ç6p50Hø¶ym˜õ[Ó.;¿Zù;¿“2Bø±Z*¥ŒÈZ}H¹mϋñëÎ{þs•"6ˆtùje䢺›2Òۓ´AyŒ™yðkÊH9ªçy½U¹V’látãÛp®ùÈéÎAî·)#¾Ã × +ôeER²‚¼¡tžI8îhè N^ÑC 'Å‚óIޅŒQ:ÂpµóñI>,#¯[ „àõù –†1·fo©$>ù!bá`û¬ôƒ&Y?NJ+šeaz£?éü¡wE$Èb°G¿°’ãL4V $.ÌXø³„…†ˆ{HfpI¼2Í
+è¬Üª0À¾¼‚šÁ08’ì8¤û`9Sò…Æ{ ¶ilËô¢|a·Ê^)QH.û'‰®n F+Î'=CB‡CÙGàˆ<S|`zà±Æj=¿‹Åƒ1Ðà‰°~02g»>äleóÍ06~
+ëú+váDýûÄw‰]¸Ú>aä–Ø…ì÷Œ]øeíòå_Ë>ÑJ–è½bJ… câõ‘¦rJ`»çof]̅ý#IKfRæ%ÒÜk ÖÆÈû~†)8ROߝ™$+ü:ùF/‘sg0µ3\¤*¸\µÛ{,zI®RfÊ$”c!¤ÎˆjY"uBu܄äÿ!uî#lbŸxPàElÓixÝÍç‚(Hx±ñ3GàÒ¹ݹF„碳Â`¤ÍÚZ:SM2Ô[ÏTgw¼|ã♚‡·v¦0uϔœ´r¦ä˜]8S’ò±v¦’e{ÊBùá3=ÛÞp¦ÄÈ>Þ)ReiD¨+â¬Ì;—´yøTã’iÞw˜JN#ÍàÌônH¾Ål"ró mˆ@«!hR¥ƒÙWÍûÙ|vɼ4—†U/d0<±ymOÛ­ûò DŒÎºÙ.ÍQŸ0°îãögY÷½Â÷A/ó¬û¸ê~'çÒªGyݺŠõªuÿüÊgZ÷%õ01&ÊÙ#­ûiâÄÝ9eå•}õ¬§C“ñð
+æ9Qk,c~!˜Gì^¿z0ϵ<úÊ`ÿüÕƲ LúYŒe lxcÙJâéǍe][‚yž¯Â™ ³sÓ·T8ôž/¯p,—«¶T8 ÁÌéB…3áÚç7¸û<ùÊA €õ8˜W8›O%T8›üªpÆÏÜ8—z¼=¬ÄÒïEœÊäׄ]_¤#äš8=ë¥tsáÌy6Ñ F¢p¨ÃæJ`큓Úk)dI@„žB5)²×Â*C d5©Í€ð¼&•d¼ÞeÜÂipf+
+”:P`´Iև_©‚åØÇO²áàZÃ-ÞXŠý£º½,AÌ=)úíÊ –Vý}©œ °Å;•DaõDå;Ëåh™Œ¢þÁòº¾P&7wú»û'('ØXMo–t’XÛð)Œú²Ì—‹åC҅r‚­›=R3R[þ½9ý¥~Lé›ëë ¦@:ÿmê Æ’¸_S¯ˆ)óè«ÚKõ«½ü9ª½¼"¦Â:;
+íV…ô:õsQ#õ¼æMi¤Ž¬hΫd4ÒÖkyÈ0‰šJ¡¼"Î;ꍔ4À@œÒ'µFš½ú¬¶àÎ}ív5¯Ç +Ôh¤Î4¬Ê…+žÉPOiýW=wÚȰg}«ˆJJRIdöEKiÙAfY¦Â¸”Q +¬’¸Q—1Ȓùש5xŠaCtãHÎoê+k©®$Šµ+ÍT£±RACQ¢[A)Ö³ºk‘Ë›Q,œÎ‘À¬ž¡4äY ¥­(ˆÕß)sbxCD¢#"É&ÆÕºâLkÕe¨—°À<Qˆ$ÚÆÓFk¿ÐS†¶ŠÑnr…`\F±ò¨XE¤øµ X( Ì_ò.QDJÄÀŸªJr¸´&ڒÒÞ½|²Ö™–B0=& ×F¸ØҦܱ)€þµÔ¯j—¯ÛÁ×ðì‚aˆØ¢PçeÒ¹f¥zîÀjù¦äiÎr¡U.’;¥h‰}ƒÚ\t˜Ò†{«úiîÈ˲:]ª¼4‚Sýð/÷«Öú‰ +†X#u4 È£.$KÑ:`¸ý’œÔ0‚]+Äi½Ý¥jַᓻ™Ìq5ƒÀgW̙NpCbR³n)Ph¸
+ðNì™ÿR—% —3@…Jg¸E3Dçí¤<Žçwx|£T†¸!Ç®d·?‡.ƒùš:¡2±Huá"uî„ê¢$!uÐ ¡iÁ¡²ÂÀ¡ÙNeÞT8´·;i‡Jd„3cPÏ%ËÜ&*çàC8ô&§ÄÕ04YѸ.Œ»z +†º$c’Z‡¡b~ºC…}†vN-Y„¡Á2҅†š**è”ùÂØ݉½N0úah1ŹÄC³ÐZ[ _Ö(a5ŠÍaÈûBXyðÁԟÉ ÊÜkÄ©Æ<jÖûr7 ÚمR4…A;w’8M0â0èµh×1¨›­‹_ —`ä2Þ\z7ÚCþ :ž¬Ð‡ª“Ÿ!é9~EH…W„”ÞëRé>„T•_?1 +Æp¾UÌaÖîÆ¡¢Û=i°”]J½¹ÅKü* +´öFKƒµåÁsÃä
+Áê KƒEÏ¡Î_Ñ®õ›Jƒ¹4¥ni0{ø +Jƒe+„6”sÚàm¥ÁÜc¤ZXuSi°¢&•Ç~¢Ò`MßúCŽhw™3ïw$›¦Çp»”óômHYͅÉö¨]Li-ëEÒyÔþ†óÜZ¦AB‹«-é1boi„è¬5É;“wKŏCÂ(kÆYt1é133€ô˜yÀwIÁÊC˜#fÂh +žÓcHy–ÏKišP‚K²mE¸çáÉ$TH½´µr¥&ÐÖ5êðx}E`4s/æài=k5»ý@±Y¤é×y`mv_Wöê}©IDÇݓ—îe×õ’âÊ©l:½[1.œ¹µem]Jv yº<$.ýÝ­'9ÍÇ÷•\z~÷ë’Kíz%—†/N.½Þ²á̵±xï_÷ë]?kéÔìçŸ8L“î‰9f†Ñ³xEœw^>‡õí\¦ÞǪ÷4ª÷ןö.tBÉԓ€°Þ×À–²pÚÑуQ*Nú$¥N»Y:{hjb¨Q4–QóR">qÄå‹óF¢S|N%4zê¼ÞÌqâ8ñü =8•Îóý®ƒUýÌ»#“X¯Ì½IÀG[^·ñ6ª\!}0'ÓzäˤˆÂ]vL§Ò§Ä
+G˜q±&Ì#Æ}AI†ˆS"5GŒXõæekhÒ@”G~ˆ:Oóà>t–Oª²åz;EŠ6Z ©d"#od²išèþaGחàý®Š¼¿bçò «¿ë xTáÈFøLÅNh;kÒªoËb'Š÷-óÝ­'9?¶Fè-ù¿$Vü óÁ"p¢pÓeøInt,'ZøÏÿ=wíN7&Xoø×åÿ‚þ£zÝèø9ù¿ç „ÛØ·CEãH–~ºÈÌÿcª?þk÷kª¶éçŠVüÇ.V
+ëTc?i×]7výAr ýpd;Æê÷Ý¿ýezhøQÏ¢åðÏöÇaLÛ¨ÿ^ýñÏ»úãÒEÈÿó¿O}ùçéÿÿ#ö«ÿqr®Uÿo×týiÚ&i5Nzþ!æýXg»iæ}¯è}xëã8öñ0¡¤ÿ¹û_Ÿ3Ñ텉Ž!æãˆcW5Ý´-޺ӏóL/OíW÷¼éÚ·ñ´-šÔ +¾˜ô„0bÏÛ«öȤËý1«"çiãŽô^OéG–atÓ0’ú'ü˜þö£àŸýÑÀ¿òtfü[µ›:Ó¾9àof^uºfúöoÐÝí~Äv±)Ûýtõgû`?Ó.MÃÔCh¯^\©™ÀßóØ¨Ï¨Þ«)œšêÕgTwMÃ]ÛIêUÿõúÑÛYŸ#Ó£¨µÿ¢£sILôÝp2¶#=:ž,ÏëmÏnz5¶êÅ'=û”{!6}S$ù×Ç·vÚôCÙ Qq¸˜ãˆ]Ó¦dÆьÝØ<lñÒ8R“‡·éç!ttíÄ‚渍f­â¡u“4‹]^ê©iÕV;1˜³&ýh5O«͙ÎlF}ñH=Èlù Œ’æ0½f¥­’Múe=ûìöý}:pýòËæS¿™ÙŒ?Î_h Ã^þbLê×øWý²y:ÿ¶ÚV§~m’„Løëa·GkwqŸ»îËNc§—fnÌvñ4ΈËãad­!Œí…'AÕÚ¸üJûWÜŒGÆàŒwï@Œ±9i‚ÓdïwýÐÎ1â‹?([Ü¿þ·ê??®ñä|à†“zÒNR5Í·\¼+z>ã‡Ã÷&Ñ;«3‹tigÿYúÎ6)ÑÅЭK‰~YJ }Ž_7Ž”°­N›ã°Ž0Ž¦Wàô %Öð]¿$ï'‘`$BÖ¡ËK¯N‰ùÊ.XX4Á{|7­ªùo?|´2½—;Ù)É3I/õ]‹Ì‡]̼kZž$qÔúV­årlÖDZ¿øYÓ°ù¬Q<VôºI¨=ÕoBn[!~‹¯@ѧ:œã’tÏí’Ù]–,oºô?–7Š>Éú_F +6ß4ûdEÉ´½3‰fuhƘWzïz„Nºw£f(.7k •=¦z’4v›Ni¼Ö¾ra +ê‚Q¿W§å9÷ù¡Cy–ŸlŸ“Ú5Ó?tÏí&¿°IÖLgˌÜŸÒÚ.žzt™›–øàͶÑj`øÑ,8ۛŸ¸üÊeýà>íK§‰Mâ§iÇ&?øàŒa(¹MaRFó„™s[ŽüïÆüÐhlÒ®‰'m­6*¿ÞéM^ÛéF…Ƈ'u\ýSqÞ¨w¾Õä'žÝªWñסýь‹G}0€;.J:ß_ÝÝFcÙOuRèü ckv£fÍÚºûÅٟ„z“Jk +ý¦d¯æpæÇåÍbv’³®Ç¾êvK³ |´H?Ò²Ïáwݬ†^æ#Ëvš/ևÇ1 ÂãþÕ=ÏÝôæ86qœDxâì œ5yµZQ›Ù̏]Tó¯ìk?G¢0/EJNË8¡ŽvûáŠù½Ã§s71ën‡®š–u¶Ò̵Î=ýÛYä>ñ瞋¿+~¼¥¥ï2Ÿ6™á—ÎöYd¯ ,ÙCgñ±šIzbì0~9x⟬…÷]Û7ǨØa»@Å6øç6…‹Ê|´é +ÏqßCŸºxxeÃ$¦?Æ4¦þcó‘¦÷»ãe–0Hü“‘ßZjŸO1d-¶‹Ä?ù}¡˜Ð¦ÄÑâ"õOJ_jÈy’¡ñl°—6ú'¥¿/5äþ´­G5!Šú'¥¿/5"äæ`x8•%…¶uÓÞëfè6ß8 M{8}?Âƒýb:Šmióµý[j{Cš™øÑÍÇ[êG7oA¨7l¾…F€|Íæû +a}E%ĸ¾R§Vö}'±é@ŸÕG¿©ïf®þ¾3ì˜îñ½aœ£ +õ÷€~×ïÉ8Æé÷â3äã¾ëøô÷è¸ï;>qƒ¾/Œû¾ãSߣã¾ïøÆnÖµÞÆ}ßñ©ïÑqßá{rÚT©Ó.ä»|­@–’Eý¾ÓÈÝõkê¨+Üt·“>54«°êsH¿+g)ÃН +ú®£SŸã£¾ëèÔ1gƒ¾ïèðs|Ôwݘ
+ÑAßwtÈSø¨ï9º&…3Æc¥¯w>ê»OO;ÏÞw|]ÿvØÓÛï ã¾'>~ïÙ•’bÒH¿ó„âfú_¤#QRö¾C\hXÉÙ;‘7|šÔÙ>pßed2\#Ï»ÊvÚ®FžwýmWÍç]¿§ä8€¤ß½P…Ë)FQÄÔ÷´bt¿ïÑvõòÝw|q–|Zæ"ྣTâíªñ¹ïÝä4’2ïîmÁõ˜k•c.¡ sÔ¤
++j;î“Uœ‡Ž hþêéöæqp¥/öšÅæTÙ¤MÓ ‡]—4÷”î¾ñûqbw‡ÞÞ¸)MØî°èÏûâéWûïM¿ê8™}p´ëþuFˆ.TÊýZ‚ŠyÕWE¹ü–ÂÒ-gørEtxÕZ‚ßo+ñÌ«q_&©#敤Ãßãʏ>Qõw[µÿLÅiÆQ?ü¬Ñ ¹k‡·cvCwéa‡dë5ÜCv¿`®¯®! +Çbml¿7b>Vk& A¥Á†Ðá‘¡m*>¨a ‡RMó9¡ÍN5 ¦éÊ¥:Á+ô#¼B?Â+ôãÉípÐàÎ?qD;~D;„.™üI‡Z Q×Iݏ•t1@«“œ|ª….B±)×bµôÂÕÅ"Ò1\ßaE«a°ÊìÝRbuR×nt;§?­øÏÃߚ~:9ÝsßC‹҄[Îñ« Y'v¯WOÑÅ?t{`Ô1EZVË°˜éµ"".ÔDËÛ
+NÈÃóå}—^¿r
+ÿQ +ÅÔ~ÑCù%OºfŸ«C-tTä†h0ÏòÊókR߉#)MŠl§ø»:zíš&Õ}–&5i6ÇÊzݧkR£øC^šTx
+lÿÒ¤^šT×Ï.Ëcí¦ù§Ù6­Ìô¯CÔ‰É +Ãó‚Ã1ŽƒÉgú9Lìæã¾H†ÖVÖJ Œ6­_ãÝhæç£%˜LêiÚP!ÐàM£¥jw‚-ÏׯÔî3ÈZOißX k úSÚú6•²Ýÿ=t:Â}.',kªÜ(M¯ëZ%šMe,W-+þ,D}®®n`Œö0¯6¼Î%z[ÐÍ>ŠÚ öœ Ë缈ƒ=ì£or&Åôp785\…¥ž˜ÖªÛj†i%É°R…ã†Q͎Ζ¸ìÈÍzsE]Ð8Q[Siú eû¢ÄEqóÛ·¨ÇÙ¥pŒ4™¶ÝSǓ—÷°<­eãùíßIêêŽ#n© .äXl1¸|–ëz<ȝè?Åà‚Ÿ>”€;E~ú§Sóef¦®1þ23½ÌL/3ÓÓ8ìÛ0¶ƒ¹oÂ8ìûû6ô)WÅ'™™òok*ªÑ÷ÖtÝu?g¿víB÷¤aŒíÿÜ y Kô-TÁ6Æ6ç$n‰ß­á9‡5„q60³aeӅ /š47E ›¢„›«¾3ÄöÏÖN^þªQZÌïñ‚‰õ†@kÝAT*mNxZÓÿ¤%/“ž„ÅÒ¹‰Xç/üõG»¼ÜSrF­wâ¯möw<¿ò8í“f4Û[”ÇüYÊcŸ?UyD5jèŒòøR£^jÔK:þw锵«§,M€èT0"Nçy®~'5€ëx°»CWº¶”ò]9\˜3(´P¸Þ_N*J4ÎiØ6ŽØ]R±êîí‚ +¹,ÚÆm»»ì +qµ +…ŽÚMZüù øÄUý*®*X±_îIº³5òSaϗÀ³§«shðig¡ìãödšY±óÑ>y5ÊIýÌó‘ŠqNûÿàµûåRáÒ¹¼¶›/¬Õ×îby[îæ=ÛrU´ý ܍R·rýs(—'rc~‚+Àç{sËWôÅ»xùô|‰·Ü5Lî–V×·«Û©å¯¹!¡•;}ÕõÑ5¹¸–Ù’¯}ùùؘùò7Å×p峺<¾,䕗ÇãMÐvö§Ûœ{;ïK—û[¹ñbã¨)‹ÑÚ©Ë Gr4lv.xSã.š\}¦^—ˤÏd™k¸_ZžjáBhi²™çKn /—I'»GÔ»°Æ­¿à~X<økôÕ_rc÷ho×>ÍxtG/ g4Ù5^>Ͻì ù¦ÐÔ­úxßýÊ +ú5¹*ß¾îÿ’sDöj¹2ûJ¦šqûg¦Zî‚þSåç­\§îŽ 9È£}.…Á/VÌt±Zw8eÓÍ,–#_¤É-ö¸˜gê^ÏáÛ}v¤±‘…ÕÌB¶4WN¿-EgOò ÇN‹àØGMZTœ«Åep¼OíÐÁu{<nk¶Õ#À/¼"qDœ-AGËKבY¹¤xEÙ¨ó\ÁvRÙ÷C€)æÁÒSx¡ü!b¾pr¼ósÂ|´àsüt¿C†Úڝ½ ÁMޟ;%øÏâñ}§b "*Øì` ¡RÉ#ßèavæi/Œ‘`$…ÁÍ,ná÷eŸ8’å%㌠+é敵áøIsE…á‰%çx,wT~¿ï2‚þnöìôRNÑKñflg¿Ðþ~“´É§ï¿ù»ìád7’ðP$ËñPpÄƑ¼+»-Ig„ØÏo / +ɑ.°q! +ö4 2€ŠˆÈÜù¯DP•ÑDF÷(jŽ;ZMdlL7•ÖÑYί5TdJ‰~´E°ˆ°i-bÐèÅUv¨qQk º*@ ¢6L¬µµ#-1ÀhÅ)’νAî"2PhŽQê)CO˜X*«à°ŠÞ¨ZŠ٤ſ¬>ÊtOi¼gè™ihˆ>šÁÓ¢¬rG¸F$*n$8a+VÃ5H"Z‘€¤Â ‚Ì92?¦ ;Y®õ%ò*fkòA‘&ºû»VëœâV¸¤õ2öWõšŒµy´'MŽ +ùºlGÜŽ*)¯vþÁi¢HË:?M¤'š¨ûUÃsl(6~Ä¢ðŽ(Øä´äõ˜éëÑ£ª)RDì€VuB5ë›ðÉ8ßë0á“Réƒø$Yv‡˜tÀh¥,®Ÿ€ \ßò ³(à“­ƒ ûÜ
+á§Âøpò¦—¶E
+—VD£<y_~GÒYr
+)3DêyÖä#Ý<kҕæJFÒùñv2Þy®:Ø©rø
+MŔƒù‚²s±œôN ^£Æñ]15Ÿ[D­ ˆ5Ǿç?F»ò™ü¾#ÆfD}É°@Nš_AtèHz„2gÍàföLÂù+ ®Uy0óYä¦Þe'É)ãER„wk‘æÊæCcyßø>—¿»„y
+£È©#1™ÓK?u„’DqF“­S§‡äHˆW_„@j²%7ré>‰F{³éì…ûxĒÁ57bÔGM%Û5GM•Ÿòàh¹%ñ먽VvïXY‹ÐØ8Ro5>uXáÁ”)֍ܤÌù`GŒ– ô7ÈöˆÂE`ƒöVëÇmöp|£±X[„6E fÒÀþP(É[>Lû°¥pW«LãœH_|•ø®ÐPœ’#‰¨%æùHé“t2æ®ÑC[=?Š¹®¼ËY*b-ú_kõP¦ç,{µ–U/mg%JË;÷²9 8‘ÆÖÙY@Z$Q™Ø)óCÌ7¸šsD£Ò?̬Ž‹ÕÁڐÔ$CŠ
+Ü +V³BRòïFx··+Š¤râÄ´’a¼=;dû *‰D”Θõ¤³ŠòpxÑS’1-¡cî‰0ÿ‘Ig/¸¬#C<FÅBÜÅî lÄC+·»<Ï3ZÛ Z26ø<ËJó!âËT4§Z7Gc!µ š¶U¡±­µŒMªÈÉƒŽU“OhÜ[ՇºŠP}¨žÄ…P¾È¦$؃x`qîé«Ívj•¯¶wvc¡½›¯vÙ/‹Ö/TxñÏÌ3°änm̓p€³ÙLsüóÜ­òQd”gªv·&Ëë.¹[7°º{:ÜÈÙ3+’zGØY?ˆœˆÖN3ª;×éTD¡:¾»ªS’sZÜBPg› «£¢…`©lÅû~א+¤¥™ˆ¼óŠ ¦ɑ¤ÓH-ä=̀I,,ÜY­ +ÕÔeTéÂð ÑHÅEÐ ªŸ²±oÃÀE>Å
+WˆQ?Ǧ í1r‚Înq;Ì·p;cÂ9î®8ȑռäßØAî£w^ò´ƒ¼³Ç«º¿ƒÜ몟æ W´ïç!wÁÐÕ¢‡|lÖhö3½bƒ‡Ü…Xo¹#UÔC®>s?ù؉ñ$äùrí"gÙïj‚>6-ÙdÅøÎâl÷»ÚÚQ––×÷¬Í¸.ß×¹¥õ°Îè³(G"E ( º³¤_Pœ.èR‚pnÑ¥ÖìǍU|žL—BÒv]jp²sø)…w]—rö².U ]¶Xóë]y1œg¨ù&vÞo“Û’m—¿.·…A_¹-ø^›Û’Œa¤z嶼r[>)·å:†>.ØzÞ pgmîþÊ× +ý,àÎÕWŸ ðh?„†¼Ÿ5Ü¥Ôß(\öåý2Àc,ŌâpˆLæô‡`H/”üýQrcÅëS¢ä«}¾%Hvœ}$³x)’Ñjržª÷¦–¶#³ ĚT'Ú³F7ZXbùR7‹ŽÖž?*:Ê!QÜ?ú³{[õ–脿FÞŒ¤cNÃkwÆ#ÕЏ„Ò‘C'$ ¥sÇa¯ˆ.ðøb(Ý݅žƒá ÂW‹¡tÞKü»ËBO¶‚ßFè ¹µ2“zX/…ÒQVΜ’[>”.˜Ö|”IÅBéÀ»ÄJçÜ Èñ(¿¸&”n]M=–ֈ͹›­©¡qxãØ÷C!öªh,|c#?nÎv‚ôª¯ñª¯a§¢z…=QøЫ¾†žœŸ¼¾š¸žº¼†<ð*¯¡{Ï<t] ‰0ª>±ºFl28ä¿0qûê(’dpeFÁ†Äí™Ë©Äm&].wu}âöՑ󂋞:Ú£‡K DZÿDìë|œ­’  [±¯3à®^ +÷¢Ygû
+z +ð®Ã¾›\œ úº}Xã–o/@ß«]œDMôu'fô%6
+â©[B¾Ò\A¾ŽT-¤P
+x½òÎ{Oä+ބ‡"ßÎÊýeäÛ»½Œ4P\ºø#/Iè¾ù&§–ä‹xö+€¯—êä7¾Áé҈\Õ¾
+DùòÀ— ÜO¾Ù>· |È}ð%Ž¾ì¬Ýø¶­ò“œ/ð½ÙÅ>÷•ž,KªLDÅJ´ ;Ýöuö—óÖÚxëÌ-û1ÙíwÄx´ßY‰¨¬Ô()•ËöTÖîi\ +†û+¬@\#{o“)•iä„ «u"¬y´BÞçaV: jžZ[i_´EÀ>fC#\»ÝûC‹ìþ2ßßrܲÜssŽÊùϚf£ÔÌQ)œäŠ•Ñ ¿ÂßæÖiëßâKu÷¨}Ínõ¿Q«;×¾jLûà•”Ãj_͚®®}•­ØEÖ¾Êí¡
+Sj_Í]¹_í+gÔ¸±ö•÷X®¥¸K½jK]ðÔ`šzýÙµ¯œ2y[í+ µ-¹K½íJEk_Ñú¬ -¤ž{ÿ +j_9ªÇy>|Xóƒ8/îyÔ@¹²öÕèÄV&½P]¡p;·Zé@Ù¢©‘ 3w¶BÑŠÞj&sÈ}!Ña¼_/QHÛ3ñˆ'F|T&¢TÄ +0à¯ÊDllo¾M&bê!iº„ƒÜæø®”æƒaÃUi(¾õ‚Ùkg‰l-Î`Sl$gRçÍ!Vîϯdܖ½ðé1c¢ °PQËbøó'ÃÍ;e((ý³è1 æ,YÞ¸gK©ñaë¶øx”Ô½ÖÅbyÃ!HWCÐÄy»}Ê}ßñÂ}ß±ËýñíœO†þ­;ý6ßn›ôí©ÇËXÍ嬍¾èU_Îz¼²}ùýÃm¬-^xۘçÍû_vqú¥‰lã¤eôÔÐЉ ÉßXÜ 0òv03mFή¢mzsW0^É{˜Ú¦]YºÁ| ™¥#KÕl\*ÕÁÔûµvD§Ä¼ÐŽ?:¸`wڛ±Yû^v×m”÷Á\ökûg÷fÿ£]níðt4_oӆõ³wZ..Æù¶óŸ~óóߚéM+.vºCqðW:«åèȈV¦·ÍôšétòWrBÔ''"}Ö›&O²uÂæ¡ã¼ái{ŽÒ¡àÎAÔõCœ;~81QŸ˜^ïÜíV%…º<ã]ÚúþðÃ|­jYw#ٛÍÍ6 WRô¿íóv‰ìò¥ŽwáǸ|~â3×헇:õ–¼™Wg§W÷£:Œïþîn<Ï׶l›Ê+Ón¶Æõ.OÚßÔ?'>—gm½‡Çé:0ú¤8s^ü˜Ù;iDÆG'Ë|Ç ù·þ 0‘1Ž ü¯ê2úø…WÀ¯3 IˆÑý!t,Ç›(§'Þ5}8ÂêtøØAªèq~҄Ú#=”+Z–éå»û…þlS [ȞšúxÐ;ã]½‚·dO¹Ôlrµu]‹åG¬vbyuÁ™Õ–Ë“WIgB¥3‹æíé-¸h‘B+xgŸN0±bM¦ÑUf¨yµÏD>^£iw°Æ÷š˜™´S½dÎ%ÒZàå(³U$Ah趴Š²qŽÎéS^°ÖÏJ%°Ú¨D8,¬JáÅüÕdìõÅüU’¦ü¾&VJq +ö9ß՘ϲ-_'ljÔÑNÁ‘$²A…?…ù\)ªØ#ƒý ›‹fæ$F©{<»o5xù]U,_Éo/p $cý¯Cg¼èì÷¹ +GÖ¾Kk= H:÷›TQï‚ëPH9˜ï¢ €x|Èm~èfjÀ?#{¡°L—_‚Œµóš&.“*}Õ)"âHÚI²TWb—‚Ûì>Bn.àK9çÅfêŒÐä~!ã3üøõ^àŽh¬eŸ”“7Æþ¶‚ÄÖnrèŒ+õ^éûôŠàšRïÆP¯x’ÀÄä…PQ»ýnk=$i¸”Û1€3 Vh‰cJ‘%^@6œ‹,°2ĝ‰%Fo%œ˜E² ±/ +"‚hՃÞxQ +sA…$$‘T÷P.¦(—=v–e’Üxãm‚{0[öT7ld„$ÄMP{9U_ÌpI£$jŒÇ!ªX
+,XëÀP}=º^Ðwñ´W£Òƒn µÊó‚©=NÕ¾;Ç jr©J:Ê°Uށ¯î”Hnҙøyt°jċUk¼ïÖ×#H„ß OÖ$%ùˆK ©°üä#d¡I]QãêõjA(Kjº¤¨ÌÝX*ÜCtUwkRšGy(/ú{kâ"Ç ~TûföÂçU)ß½[-¦Ib¦ ,;«SAâ-jU“dÄY¼pv‰ç†eGVèO e‡‡\Ø!Ä:Sd6@aٟ‚˜G óô–'WV×o×5þW™ùML²•º•¹­ã7Ç£ž§l¯³õâÖ.ÿè0´®<9fÒ$!ª‹«ƒ£mš2¸ã÷¥@¾ȗùü
+$½+ý¥@~²µgö¥@º/(ÎòR ú KX]èoG>ÿ)£<½ç·o²²N ˜õí+eÿzl3S‚]M_b§W[°ôy5ð"ØbØk-«A‘$Hcn®“¨Çù»Wé`'ƒ›YK–[¹çc“Çȱɒv1kÙgbdFû š zƒàĊ ŽM–½³é³l«Ž&žn°V\Ä畹}WIŽ6’Tú„Õ@Y%axplLs²zISy×qÑä™#n%¡˜›Ä6#¨0ݾ³ÇNG9öA„‰½Ñê¥j˜YœšhÀñ"µ,vÌfúÈònd—Y¢ä1ãÄ.s¼1}ƒ…”Ÿ§ÌˆÄãê¥!hJƒiyÍ«+$WËþøê`-Ä…$L|쐏—Ɖi%bÀ[Æ¥$‰¡ÒÕtl¶-Pq@Ђ>§*Ô¶UïêËÔ$U{A|ƒÝûõ”ÖžAš°ƒê‡SJ(;艺E#H\Ä圷ƪ$4•-µ6ø¬ŸUVš¬â£#jŸ{½ær#`¢TZE;®d6Îó&64ʝ_gžñé.Viœ\§æbF‹ +á`÷2ÏÌÍ}Ä<ã
+ /™g\Ô5ÏpqJ
+M9[ áK•`ÙnžYµÅl7Ï8 +šXl⿓y¦÷ÿ.òÇO5ÏÈöL3ülg}÷:óL°ÃÐ&´Ï°`ÀûŒÛJ·Ûg\ð×­öç‡Z²ÏÌ3~Ñ>ãêm°Ï¤ò‘»Øgœ1†Ü²dŸqa­·Ùg\Â÷’}†TvÙdŸqÕ]bŸé“Ôì|ù®®›²^ªÂKìù§T{R ”‘k^ÌÍí ÊÔ}sšÃÂ_ª˜cwºŠ!ÂE$52zF…Õ©éU(5Ißc¹3N…Ž±X_EÅò?ó×ë÷ÕÃ\5YõIe «‰^«ø$§ËVªTªqiy…¤àÓå?ªÛ >õ£Jêxñ¨ËS6œWµ}ّ^v$MûYíHh4ºƒ +/;ÒíHC>ÍDsÏðѲ X
+’Þb˞¨£CÏØh5ã¥Bꮄ +žíBbw¼|BÒÈH½£J‡y”óq¥Á«`F`´zs>¥#u†ÔZ{êýh«p®ùäJª€_œèѯÈhµß¤êu‰aÂæL,†ƒ0Œ‘>„1®?tcxëº9ïôVãíŠìPl/×xKl š%—œVXêñŽ­[ ·»[·JáAìfw­s0«Ï‰­“•Dã­ Åoœ… u{l]²Üþ‚=÷Á±u 23WCM@QÍcëž?9Ëj7ÄÖ¹ëH¥ËˆÑ|çä,Ñ÷Š­sÖ-Š¬["5jbÍùÄغ"$üêÙY)øGåì,o +à>ïu6FùUÀeû¤ì,"Ÿ ;K¦ûnÙYBûPv–ðGùæ7ÎÎâ(h—ì ˜åæ:<Ä9s…˯âwô€Ý4;sæ:ñ¸°‚)øÕÂf¨Ã#ÄRtg•„£±@u„°Ï|C˜7óIM®«VUR¯‰™6)]›:<›s¢¡bx*[E´»–-0úí£x¥WÁ­ËÇû©+uçBAQÑìb~ïÁF7ÞÇ]£v‹uxú짝ÕáauÅk¢kÖ4Ú7Zž¦ì¨'÷‹Úâ­ ñ8­¾F£œÀi7›™Û©㘿g"åËØó)ŸÈØóU‰”/cÏËØSÿœ‰”Odì¹"å÷5ö*ÁÚ¿‹/u0´\€,ºäjP¹Ý…âBÉrHAfP´ J2/¡f{†ñ~ ç
+¬T0EòX^™µ„éŽÜ±bíª‰T›q ±€ù=êöfn¸j‰Ý«³LV½¼´ßÕ$MP©X¢«5ɯ$³Ú\4Ù¨øHçί‰×¿æû¨¾2Dœ‰˜j12gƒ4ò †f(¡î^2=uO]\@͑LM®'S/õ®ƺÃêÖÊGeç­
+ºÃm5wJ¨©¥aå“Xµª„cgÕª:ÃÇkz-·è¬\5[›ˆ^Ïb. )º¼&‹Ì®ˆWΫ†f0f®ªùmÉ`DA²Ø†àçƱQeH«Y-+’á` +Ÿ¬|µÀ”Ñ®¹þ:HÌFZ“Ë÷ôîâwŒKi^G³_g·™;u²¾T8X½Hßà~u±KÀ¨I$œ…Èn3í· &ÈÕ¯w (ƒr3чF¡-[ávMbÖÜZH|š(a‘˜֢ֈ[£Â,¸K™„Dá7¬qÒN9 „c[Ž¥2èËTðËqݱ&ojØUltîþá _•²žòÊ aԇç…Ø"Õs公øž4/$6ù­içHÇWbÈu·€0# o©?\Bu;—r<…øþÍÎwESü +¾5¹tZk7R(XǬ^Šì±ºPÓH†û˜Û_©fÄ~®”Àà‡±Pj7Þé¨à¢·ó÷;궕~7óŠ8ƒÌEO.ÉÅÑá8gƒµlÖ$Iǚœ©^Üý¹z™L¼;Š¦”Ì@p™AY»dfð4r’Ž]îÑc†Œ“­$fiÞmÑ]DÆ_რl3|þËÅk¡bÁ½yžÞîp;Uۜ:Òªö渹I7Å®t
+Ÿp Öu,:ðBÜöT¯€ÐiÖ  XaGр~q³¯‰™l-·¬‹£Êýö¹OÀŠgTO°’É´¿VÂÂ\så®ôWi){€n+-å|fßý|¥¥f®^¥¥Â­¥¥PÊ<ci)šR-”–rÑ)hYJ„¾JKU4bÅÑWח–âXì×*-u!¥ßíΟ¤´TLùë‘} p‰Jàp¥#LϯÇ2qKßÍöt «»±ò' P'þvb³@|‚œß±sXéèERF¼ÌÕ¥ÊâÙ”$s%•Å#0©,^Žþ<ŒNÄ<ÞN)l]Ê_ϧH)’:•‹_ÆJÜ1›ÞiÖف¹FÄËÌ ‰_ψœpzR{CˆÀr¶~^® tG%™œ°òàhßÅä¨"Ü Gí¬(¾TBÊBȦ^­ƒèˆ”!egD¡Æ šòà5$j‹Ïñoogš–8ï è)T„jÅP*«O`<ûaPÄpM¢<Ÿ7x³¨y.RIêÀº¼)½h}CÐl…]|hšF6‚Ï»Q˸N땑’Ðg‚7‰Ñ£ºpiUù>’P=i­DÄf×â&©â˜AЈTA|*ìo´§÷… ²uAªˆ¬pÞ,+VXé¼3Ù­‹ù¨²¬‹`'¥¢Ðê×[ƨ¯CIþÁÞ6G¼mÆÊàîR:kO¨ôU*…Y^C2ï–ïºH*T85DHNhj5Äåã"©”Ôë-üT–{ko.}ˆâxïZý±Ê™»ï%w~³Ho—þ²½êš›E¸S–Þ,Ò5Ž„eÈf*)õ—¼cMLe èÕFϨVa¢iûä»û²=9PÑKüÌDDKü­…Ù«6‰Ü<°;ŠÙ—íåEûâ´ï—íåE»§-wPùç¶XSO«iô©[kµ;Õë4jêÈ5:uVÐʤ؜{)¡L•òÔ¶À 5{
+†šFÒ)ü¹§ET œªCM]Ö*¾„¤æšÄ•Þjê}®!h
+B#ý§¨¶ˆ‰ >u9ö´ºC¤iߜ>Ýß3ï °¿ý}'„ñz$´ ‰Yˆ€»‘J2ñ:PÓn՛ª6‰*Í3P“êªêcØ1ÒÂÖµKà†¸[-ôò‡¯…žünö5«…ÞûcëÃAI= HPé2¥¨µK¬C¿:!:˕”ms‰:N’· +ÁÍ£”Ålãì’Ì6"j;%kç“è;e¿ˆöAT®zƒ¤”ÕF_GR’׺•û¹&¢©&Zr:”À)! ö\ô2[D#Ôù/H—$9A¼˜2)ÄLôJT*ÑGJ`ˆ“«h=ÙĈ¸r0n0rø<ZéKR;‘ÛenQÛ 7´«JQ"1h‘´4Üs$¯ ¿ë¨Ùìp>‹ùUŒòUŒ2­)¿ŠQÖW£ÌîÑoTŒ’ådçà¿ùk£Æ[%IPÙÖ/«dP»àW·J¾ŠQ¾ŠQ^e•¼"SkLoÇ Éfjüc¦–ú3µTS,Së
+F; +¥Ð4­<øŒTküMÿÔ5GKÁxHêê$©k\۞ó½>‚|!67’z—ˆ`]µõÝ­2—c¡„ƒV:썸:Ið5žþs;ÞIҚáUßRš‹)°5Ñ`kW£T¡›Ávª&a+õ¦Ò\“[Ksõ֜S­°‡Ô85gɁ
+‹u]ͦɩu ¸œÉ‰Xb_“„ë7`!öÃîYi.ŸÿMrˆ+Sƒg¥ Wñ)ª4×z.¼„u^¸Øäz±4—‹l®o.͕­`gkP™¤k’‚é±Ñ{j^šËñ”û„9£ê +®ªíA÷ J(áÚï:ÐqtŸ¼¢4—7°Ò\¤H×5è˜V±%ÂårÔ¼"©ÒïVšKh}^¤i>KâjV®ëz£a?îYšËm&\ë8¦ g~m¡_º9ÒUC?ýà&ÝÔ3'é7!?«䵪âU*šIJÚîU²Z½a×¥¤Ußó†]DzAÉ +»¾‡ ÿ¨VnØù™7ì’J·Ü°‹1ä£ý®ÞæŽyÝvÃî`›û/†Ð>ÿ†Ý&6À1_5°®›³ÌjÄ<øZb!m¿–Ø)FDª¾òZbÂTžçZâ¥ËD ” ©0š×µÄ!Ü£>fÓàm…ݽr ¬W›a(Ì?³Uç¼O×œ#®’µ$–ñQ¾OnmÀ„ŒLU$Ìï6V+Þ%]é‹_–ïŸ@u¸G…7N’ë¢Å2Ò’]<è"îqFÊ÷QYW]ÚGý|;gº9E1”ñÃò )Z¼Tì‹S~/äð`²›cZ2’íJ&5¸çŠ$5Þµ(TÄL‰(àÛ¸Épúê1"³pð:R—è¸ìâ+«)*‰è¸äüg¢ò'оϒ¥}¾Øw;ˆÌ,ÄäA‚e(™˜¬#  )¿Ò˜Ô2kmcÿ‰@CpIzO¡Ô†Ù,1m£<›îXÕE]ùƒ[骎ٴ¼’¥‹3XÀ‹_H¿!Ã"—(ê]Qå‹þ­$óZ6[™$³Ù€ʚTª0ž›`é¬8®tÝ­b¯h-çZº(.[¹M*•" /ŠÏ>š?ÄH?[¹q t~Ö¢„Ô°{AQGijµ³Vê®FVx…jw0W–#¼Kíl™
+:^À%K^†£ÕÒßw$?”ÜÉG칕Îe^ËGî‰ +–\Ԃ$Xî¼t-áyö‰‘­Ñ +QfÖ—ÿŽDã„V¹¤Tü.‰.#ù¤ª”z¸£ÊNuË«—½lÇw´K¼C$¸ÒÁÂÑ®º¯™ « Ç˵¥tta…3‘±{»ð Â.,UCJú{c†.]š-%£öD—KŒæW_*,ºh{+s*`oåä&Çg­ê‡²׆»4-¯ä·~Rfûxðy´xM[ùao~菢 KÇ°)øáù|)BˆwûvTàã혻ô¦^_t\ÙFUÏÕê€AÓPe¢8¿j>j8ÁëŽ`õ]¡·Xƒª„ªșšI‚£}û¦þ¸„ãÃT(9x½
+EÄÝwU¡\Æ U¡êÕDÉçÖ¡ºîÔjú^™‰gkžùqUô×i;Šaøn™C2ÃT)*óC<˜wËü`‘\ó×M>»ïaýÚ=Ž|Õµ{^ +Qˆ:Ç#2?н€™ΗP“Z¸õbæÇú–nº­‡Z¶ÕÝ2?|D$‰Û¯0éF½änÞ«oÌü äêQ™­›N²ì[ +–ùÄ÷c¼'—ÜàÊ©•¾²,5-µ(N¢×,6Œ„ƒi&ûÁ-ó•8U{=æSÇi!F¹<¬RK³†*p!8*Š_
+Á\aÝúÄðD‡Ö +_…Qòü¾'ãò[Nõ¤°œšíI%:+o7æs-ŒÅé?ÊkS“Õêè“H8!î€l€*ñ©«-…±èí £]Æ'–!#Ð\ҁ“4%MRl¨Á•ç]u,:1-D£6”i¤5×|¥yŸbª
+3çø=Ú¦\©ÑÆVå4Z1)ÇØ[\¢”XЊ% •T©-Uª;<çÖôTÓê¸ÅšÉw©I¸´¢‘Ñ(MÈ5œú¦(ñXze¬¦ÕjPÿ•k-M¸’h-ú`I‡ ns1m0ýÇ’à²IRÛz‰ËÎ
+ySb¢è°ÂM\Ý?ï‡Qj-‘4æTáÚ8óçOKÞìŸÞXÅ"’ïÓ>I„%]ÀY’ˆÈSÿ“`O>j4i^¨.7õŠâœSvë²C'“ ÒühᱦŸZ=D=?핛rŠûÀ`Å¡Þ»{¿ +{å;·žÝí~Ùf;å£(ýû@#š
+Îífzb³÷ídïÊúvËó™À )ÿÝrrzÈ4+öàd=7Ø{¿k¹kžºŸõýéSÍ=´.¶Ÿ=7ә‘H½¡j!7SHO›Éê²lÈ͔O¾¿Hn¦ ®ž47sÖà×YnftJ)&ù«ÜÌà´ÿM¹™îªÙšçk6Á4T=in&³ßnÈÍ$šýM¹™ÎI_=*7“„p»ß´Äý)7³µ«¦üWn¦>wÌÍ„r17ÓiB5IÂÔcÿšÜL·™¶¢ ‘Ý}üà„‡Ù ‹ /£ªX¨ +ƒòç½@³[\Ð
+*R݌&¼ÓńNJŸ)á…{+Ք“„!ñ2ŒNó¿ðBŠäфYJ äq8 H O”ð2dVÇæC§ggò¡8!c¨L̈h±©lçë¢gEŠ(«œê)Þ{e…»ãRŒ ¾²$¯š³±…h¯×¯RuV˜Õ¯Ru¯ 4Ág(Uw-sË3C»+"î÷­=¶C_«ð*qWˆ"øÐ/rôÕÖ£Ÿ—3Ê +ØZ†Ý$0©Â뤠~4±Ø‘¢á$©Ù¨ù-g?« ¤Ñëø‹wznlUœO ³&&èO
+³¶ÙõOf݆³7iüIîþD±f…ÓIšêsîþ£|&Šîö»?éÒ98RcŸªn¿ûÓq7Åtœ ©¾âîO¾_}÷'1—U wv¶ƒîþt÷@\ºâÚÀÜ"NUØp÷§3¢Ò»?u¸ºþîOW4 Z¸ûs°Í-•A"Iñ×TFZ0<æîO£Dïþt¡GÕõwÊiúÜ»?™Û™ÍÚݟW^ù¾áîORú斻?;;}·ßýÙÆtZ´ø*q¦~]fLªåOžØÔFT_Å!’nêUÂ*J¯â1ÈV¯âÁÝ_¶8„ Rx‡P ò*ñäÅ!®Ä +-qý20êËÀ|Êg˜Û‰ÖãÐßųk=WŸæÙeén,F­±ˆjѳëÊ?^ ;Bæ 'ž]A[—<»î@ª-L£OßàÙ%e½k’2RQ™¸O™óÕ\~¶ŠÁWfÞÊÕ¢UÏ®µ#òV³yvWQæƒ=»¾Wܳ‹¢ ¸c×Y©c×%âU<Rr¯©óv"»ú¶;ÈÚoi‡‹(Ú¶…ÒÃp…þî›ÐM=óEmÛ%c ¯ —í·ý.¿ðíc¯ —Çg¸|óÛÇ^.¯ ÃUž;ÃeÃíc2\.û6.m
+—>—/÷Ti ©å'Ց/Ò@Úò£ìðVM‘Ü¿ßA²ß´×A(ŒŠ ê#®}4èH $GQ¡cLÍÙë³]4¯š\eBâõ>VpªW%§¢øXð ÕGÑxÄ¢…bC2Á*xîy÷"7¿ÌÖ·œ¸|쯔Šëæ,ƒáí֌ Þ—lˆ#/f ­!œF_֒‡®È"Ýg –ô¼§ +´‹oí4ÿC÷Ênye·|uv ±–-pÉúáìo}e·À ¿qvËÄØÞº81·ñm‚N}2› ¶KÎÌ«m‚B]· 2b}½MPðôE› K´®Éµ„Z[¼£MP"ö?hÖ¼nl˜UŽ×¬~€Mm¤z]|½ªÞè~› “³­53|¹MPdH±_Yµü6AÏb¾Mp½`«km‚$øa6AAØÞ÷rÏZÓ¯ª7êõ½ªïX—j„XßT¨ÆD•ŠÑS'˜’\»ûë]Ïg ȩºžsÃ$ºžÕèzVM=µë9ç·æÐÓpG‹ÊuìÉ02tæµ¢ÚçGªMÕþ°Ái@±†Dm³2½ó<PªM]m³B½§5D, /cÞµsÖ0€~aQ-<«[‹j}Õ-òß°¨ÖëùOŽ]í»”²KØAg_ÔÄÁ +…;¬æ.D{ۀdŸ“\qeˆêD[pî8Yýîh[”¤fðï
+îÜBŒÔÙ/gŸ;›U’í<¼ìõ£ì3"ê¬Ñ`*Ýñ`2ûêÚÜ!dÏLGôNg1³ýM®ÛÓh\sBõ®'‡·q:"9~ô„xøbs°ÀT-Z“¶·™‚aULK^ÔÑ[DgvJî#×â;u*W²ïrRE*Ì6-·+E‘g€)"T†‹V']I’ÂMÉf ryëJƒ¦g‚_¢cqª¶ÙËÈûM(­å.Eª£MF¬‚
+Šøwö aVéì¸ÁŠëÒ
+¹¥©ÒÙq¥œÃ`md6+,DÔ«­ ¹!ëãع]DÔkõˆß·ÒyœåH¶Ö6A–w«bR0ÅÃú…P.hµZȀrÎÆûg@+ó+ê<”ÏD‘w,Ízao6îÖ®Îñ½¹¬ä-9´Ü®£zŸÛ…Kz)¦¼®÷ùÈυ„ÌÛÚÆ÷;?k{Æä÷*¾ˆˆÁj—(¸± ²ób‰Ð/¤Dõ ä7vò|!ÑEJ>¬½pç"IÀFòNŠä….’ÄϓHMç\@C÷\ç×½ó¦f&⪃ý6Ìv¼§S™;Ë͈£l™hZ˜Fìòî-U«™‚}^ªë#ìÖUéK>Ð詔ó1ÇtŸ;NYÿ~š¸ƒÏÈEúUânÎEzżâ숟<îàKs‘<‹yÅ„WÜýú¯wÛΤXBôåm¹HžV¯e'Õ÷MEj›Å¶œóÐDˆÚ6Δœ;DÅnèT¤HZ
+¬¢ê¤£Ø¬Qu*’ã–õÕ©H4ï螩H°‘ûPqÿ¢m±ç>pc‘—_fêן·âër—Ís–ߺƒzvˆ>êK*̍sžÂšøµƒT$t+ÎÜYOöµškuc­ˆ–Lp`&9éʵ(¨+û˾¤Ÿ°U­U±uޒ jNòZüéu¯ÈËž
+]±ÁÁerÃ{m®‡ïÝ£2óîßo¬øµ¢68¸Ã3‘:‚$/ž kºŸ»÷Ž@£ƒ‘¦²£ë]ǓÐ:©TLîî4B÷ºGˆÉ3 +k +˜é+
+Õ©óÉyúHÅk¶/*“£âª«SåI}-ª÷ïjöפh¿Uäeš`§“,ûF7ÔÄÃÞò!в½oÀ“œÚÈ]Šˆ~àn±Ð¸+ ¸Ü=õ««¼Y©$9lßéªoJ'Y9Ïõ‡ê#ç«¢)…Ù•«‰G·&uµõë¸JÂÓ9fIuߚ(ZÄ-?Ø5QŸ1ƒŒýïòæög¨¶ä)œ—ø²½ !ð_8Þø.¿åTwpª_黿xú./aÈÌ{"TA³ôÝK–-ðJßÕÓþJß + s Ìm¸tÂJ^P.¥U,*™´
+É,ÿ—ɪHÍ=£L˜}¹C?Ϻ¡4ã˪ûôr‡ê…}¹CÕx¹CÝ£/whýr‡†ŸÂšÚ¦Ð^¸—îe€û) pm N×[K6:ìwè…*:¤Ÿ°ýŽÝüGü {I\¶­8ˆø,®CÈ”¬)Œ8*zïÁÎ؀jŒøސ+A¸ÂƒÊ'¦ÙÅ O™†B,
+®òÜ3IÃüsm®K3­0)¼&3·ZHÕ·×Óp“}Ué˘s;i.áVÃÀìeÔBríS%Ò¢{¸cQ%;ç5"D^6Õ§`³C6ʈÐ}ßâÖcÛ+·I:£ +·»MD]):’ – °¶2“´E+J§Ú_r›(4/äÑAcþk]g•Ø=v
+4G©²X(˜‹víLŸ(œˆD {E\NýÄb¢ÚÜ„VÎæ§f‚Ý)\“KR•¡É%’éeD+3r8ˆ†£Ü=ä*“[0,vˆœÜ Ê*Yfl<F¢÷žO;Ѥ—*ÙØBoÉÕ1{…EÚjo‰¯—ҍAÄÞà2ÚÀ²ºE¦\fç–4âG¥j^]¢‡¤jºb<•Î³/©š«•wðZè;•Ù)_Y­ž#&thõœ{gòm/•Óö¸!.òž½ëŽL*¾âb7ÌÙøà²ð.§“Ä•ü}÷ÿFç«Ô
+endstream
+endobj
+30 0 obj
+<<
+/Filter /FlateDecode
+/Length 9790
+>>
+stream
+xœí=Ë®ë8r{…ÖÐ!)’¢€Æî½3`€,&i`AV +tÏ™M~?òC¬§héXö±OëÝð)I|ë]Eãö>Ûá_c÷.~  Ó#ÈÚÔûó/»oÏ¿š_wÆï}ÁáÜÌ v„eËa¥»áóò  çƯ€.ƒ% +–ÝÞù”lj¦Ë Û}›Æo˼hl®&”•°û>1Øq%Ê0Ы~o3oÒïc’ØÀ†9À¼X>€áy#0¬94 ;[z×wV¡À8Ýò«ü8~[BÝø#m„LœÖ»<½´P¶ª ì'ý2èe¼´}¨7—Ø”–-Ú»ßw½Ëò¿¡]’ËîÅöÀØyi‚òªã¯âÝÉh’mQçéê>`-ß"|)à…Â/X7ÚbœVé·Ýßvÿ;œ1¾„h».?Bòû¶þ…ÆÙÔïãð³Kͯï;ôQœ€Ç=ìlì›þ÷N6‰¾ä= `Ár j“E+ [ۂ€ÆǏ>A½(5ž™ @§op\ €L‚ì01ÊãWûñkç¦GƒIA¼së“X„lå8öt‡Ó%¹
+Fùú°3x”
+´´Ppä°7þð1ç3n:7ü?Š›…ø•œæ•]Â$¬±D4øÒ¢Õ°|ˆ‰]€
+™ÇäÈ|9@61è2n\"ߖé`P²¬ß‚¯§oma*ý8µÌÉðŲ§é
+’…©SÎ]Okì$dDŽZp µTæHh¢M [( àÚ&ÑIÇ  ¦kÀùÓ8@`LiDGà_ ác²âÅÞ3–g _`!eÌt™f4ÀT7ʯ¶ÉÑ`2®Nƒé
+Årã`b _¨˜q€Ã R]à ȁvü[LÒ—<ƒ*Ï #@$f*¶t2þRœÁˆÛNÀ‘ËO“!ÊP vC\ˆð玟y+…gÜ U +ÑÒ¾P¤ŽsSª&ôžAµË'€$tB°X:ñœt,–14[ñbûý)¡~…¦¥èd0_KÛñ9­DNܯ"lcQ›Ëü„kÜd?Ên7Ö\“Õpú.ìãQô<qú|‹û §Ç+gåÊ9¾¯˜go*¶µO bc¡c%S½k*¶å+£ªØ™nT±¹ÿ„*vR–}S±íÄZ"â–÷þ¨cÛ3q;6ú7¾y:½4šÊ¤¨{º…
+~Müö¤aÀa§×@s4XøÒ q%ˆŽÐBL +¡,LjP40 +á Au\QAh­Ññ‡Åê?"*d¡7Z)êJʄ…TÉ5†…Ž„‡]…ÐT~ÐQ”Ɲ¸<ìúÑrЯaÔÊVN,qž¨.µØ&F¯Å~J ѱ'N¢uÎj•ÃCè*²ˆHÑg0ã¹´†.Íbdt˔QÌZDšè¹ƒÅ 6³õ…cØ,aÁ*½cås(h®ÉDÞ²Õ8K-×ðZò +†E¯ô^:Ph*»…‚ˆ§dñ”`ö@[z/a[A ÁA¯*ÖQ£#’QPNÓdb6áÚ-h²u.ä†Á„°Y Ü`BK‡%O
+²Ø +,  Ã¿à£NŒ¿Ðì°dÛr}!o`m;QÌEDI&[Ó TÖKŸ×\WÖ²[ª&tüE¬ E•K3’Ä(dX{ʅ!Mª É:ƒ"•Ë®a}TÓÑa6€´¬†xÎPÈÚôŠ!ƒ|Ô'Ù'4c#„tZÐ¥@§íùžÓÞá(ª§Áj֐ƒ“•¯v¥w×;Ü»&ÅÇ$aBC sÇBþÂãfMfì¹½†,bËÇAñ³|¾P
+êíy©âš®½® ˜ƒZ#»$aA[LÅNBžnÇ¢ ܾÀx26r
+4+ŽÀxbG½r
+0SÂ*vLj.\5„¿xís¼KÀ¦uhi–AaY?À––2ßÂv@KšÞxÍÞ-6”M\±üزÅŠpMr(¯0`E½Â¡ÖtŠöþÜmwû©Æ¨ì6lqAÂÃN.ØÑù…ʇIa € +D¨†}=Y~^pá@<^q4Žn´T4sbE/:.“+hÙ¨Îó)š§P…Ó«½X´éí?"@} CߟQü¤Öú‘¸¿ï¢<AìAA–k
+=(¨hÅyxG@çüy¦ÃÈ».Ÿ—ÒWùþýOÍ?fâ{´gÜtíq¤)iû>ÝÌŬº£öC +åb€"cÃޔ\"ó•lqˆ6 m¿Í"-rȄÔO:û‰-´bÍÅÑÂ>|%ú¤e ½t¯¨RؗŠ†^Xvf_b(°XÉ»¬ÌG8èràW쏊ÿD±]’H%
+¬eÓ œ8vGNƒ
+E¨«áøÔ Îç÷V-K¤…pL‘õdŋB Ò°°GČ܄„Õ@/EæS|ÀXÜWb¬Øe+¢Ì, Èì5db,Ë-”YÂÁÐá½|a¤ƒ‰LUÕÝùIììBïHtq¢›]¿Šwd¶ë×qs§êúí¸àI-HŠå–( +žKÍ'Ôz Àâ筂`óp˜Õȱ5×/HÞ×\¿"êÒ(¤ç¼Œ"*rÂõ”Î'\¿VùÈ*ó&:¬¹¦VtÍõ8mšrýÔã®\饹æúõìxc­)Â@;Å +7?bƒ˜2>âúÍü=nÜõ¬[ j9‚—GÝ󛸥f€s Pa÷ÑLI7жpj×u ®‡D‰K>Šf"¸Zø]§üFs"©•0ê†ÆßÝ/¸ìå`zÉ[ñ‹ÕxëŒA8¶°™ìɃ«£ëN‹éî•0¨`fD%Ô#¶¨„»G%8©™=STÂdÿG¢®Ç)¬•½#'n r¼,â–G¸åJ3Çä8!ê>0ȑ ~W Ž0s…Â! e\J³Kié L +ât×®‘Æõ$ÉӞ;5 üc— šÐ?ljX%[ìjjX„ +«ÂM¹zjø¿›;‰Süe ³¥†YªN?>5lAðœ0¼˜WM +y` RÃ:N2õh Íc¿+§†%Ë@ÍcRÃZ…kE×{`jXôùÔ«÷+ÚФö¤¹Tˆò*Ì\Òàk¤\K¾EñRÞEoqÍ[ +—¶dô>Ÿ CKsj{Q kڛÚvßRZ>Jl]‰L{½dþË(ñLIÂ%R—*ž.ÄaúÐR= ˆÜ¶@„Ê›@nÒ8s ¯‰äŒX¤®˜Äª +ÝöHˆ¹,¨ˆMD™ù:ÀT‚$5^j°•CчAkŠbD”%‰È\$ë¹F­À’
+[3HáRBí"lE}qšK5Ùʂÿ(Ìçô­ð\*>岕«*½BŒ.E1¤ ±$‘ s•%a“í¥M”ý[¬ç
+'lDB,ciÄfÖlTTw4ÀŽv\šÄQ'šôŒäv‘¸ „Alð@:~L°ªféI} —y®2á~´j7ÁóU+0(®±½K%‘àWôæe›È*Sœ¹‚7Ÿ˜U&¬¥Í£²Ê4—œ¹KV™&ŽgC‚¾PVÌþ®Ye°oo§@9M Ö´Ýæ+f•aŸ òfFV™Ï’U¦‰ÌæS³Ê„6g^'«,ˆ +º1«LÉ/kî•UvS>Í]²Ê¬Y#«L€Í e•Å0°ënÐãíÓTpbnLS²²ß‰˜&xõÓcš„œfž5¦)ÚÇKèJ0KâÄ­yºº#ç Ýq|5w©û Ð}ZBÿܺ­¦Jè '!'b Ýk2²^÷¡K¦Jè
+A3‹ê>Ôbh^RBI#Fw{š›ë>€à»½ îCbÈãê>ÌΪ}T݇º7Jså|Ž„.¬ËÓzí Õ}vjóë>À؞IB~Œ-]UB¿¬)•Ðýø‰ã<Lá SR¶à@ŠðÜüºS8–“ xŸµð­§Vb51,R<»l²Œ‰@¡1ly +a/@Îb„@|B‘‹xŠ<…呬.t/w¤€4û«ª¹(
+‰-oé14Ÿ£{Ü»Êã4È|0Ÿ¢å\©Ùò)ÖɧPRI’O!Ã!¬¥¬Á½v:E²(x+ 1oÍp
+ʧݨÑ1 —Q‚(ÜátìX)Zvà°iÐbJØô-7j€¶™,ë÷jØtÇÕ¹©°i‘§ª†Mƒ,ýé„®†MƒTŠÃ¦—ÎUPËÕۆ¦Ô¬r£†ˆlUÌ^D¬\éFN~Û+&,0®r£†R^ƒJØ´ø¡ÄHƒØV@–KÍü°i§ˆ‹J6‡#;þ¶jväüfÚÞ<¾0Ó ÅE•Õ®ÔX'tþÅMëAjJÜôx¼QÜ´ž1×qsÀ‚+5Béd•+5@V‚ÔpÜôǃÔ‡®¤¦I³Š ËÏ<ýÍ̺R£îK^-n:%¤<«—ñ¶³Xý¿<k«×2¤æ²zjn½<keV¯¸³ô ©/ÂêëŽÊêggH)¬~í )•Õg+@z†Ôê¬~AŠÔX=°õ•X}˃¬^O‘z"V¯¤HÍfõ¹=묾î”ZÕwíi‹üVB +C·j[ 5|ZôÂw(¡v[a‰Ìßk~}áj·^ž»tžT÷ÉÎÌ Ha«;3;ù­ðZYwfz.(¿ª3‡h• Ïvf´HJv•æÌT"ËþÎ̌S>÷Ê:-F§ۜ™Û•urƒ7óúª7óz]ÿ˜ãÈ×X]ÿœÐµ¸¸®?y€Ê÷Ó¦žº®o×¼ò÷¥e^5¼Miá“zI¥eö•¿7(-’ülJ ëök+-};ú[¾D˜Åæ{Ù|/LßK½¾Ææ{±›ïå«û^îV èKø^’=ã¿_Õ>™È-r¹
+-GU¯«kp̖n‰µË(YÇF‰ç7ŠYì,vÅ$_ÍüUƒ“+‘ +_(¬­0MD„HÙ/-#ìhˆdãhe‚ԍrïeÃÒé@®§Ó +ä¦t:E]§ÑàãH˜Ì¾ž²Å8ûNsja ‚!jëÚ°Œ^Ç%@Ô$Îë$ÕÞ´ìEØM/$ìè9x™e™ åþYªõêwÙBŸ î•5/ŒrYlC2H1~Šð Î*UKÄ(÷ܜìÙä—QÉÅV4Âò%Á +E#±Q ¼ÍD"ýœ:Lž›vÝzŽãÔ[ñK0W–R!bځÑЊœ–˜§/‘lFƼïäLî¥äÓh¹+ÔZ‘¼¬H¸Cê;½oPbÒÌ#—r0s
+H1ʜ6*ÌM¹š|[Èt‚ü{-×ïš™¨èOEÊLÔÐB+-×TÑy'º™,6 R ¶öš ©s×ÀX3)à}‡)¼rqäK1¥+WŽ­¶SlÊÝ#Š±U±ª0[‹çߢk1ÅjÅ™ ,§8M;̅oJ +í¾¦`(ڄâèö #^Œzà ¬ó":äPä-Ÿmæš%TŒê6?µ„™æܶ~ò3£¤…ê‘V}׺CZw^Ð©k^°›Ú)-(©øJÒÎ× ÔM-
+ƒ˜Ù9·ªOúIrnyë +)ø^–Pz®”s›\GäøOrl<ɵ;OïØ™í\»3Û±! rl€Å`ÇÆÊ×îÜâØøâ×îÌslhª'VRÇ_‹ü¾«_CȟwñkóՂkwfû5”kwVök€‚ÕŽy×î¬ï×Q…W4‘çñkø’õR~ + / {Mø5f’¼›_#qˆÁå#‰_c\½ýc“Ÿã×(jô8Œ)¿Fà„mókŒ°/á×PJ¾–_£Å¥ö¶Ì»-ˆUˆt[æ¦%wb•ûŸ0ˆ5qt¸S«X‹Å´-žfçükÚzþ`A¬›­g³õÜZ@䶞G±¾²­ç11¬_ÚÖóDõC^ÄÖJj¡³Û·±ïs\5:«êB·’q`üŠ¬Š¿Pê®Cœ-YÅø[˜¬¤,ϕ+ÛºL¤5&sÁ ¨ÒG¢F¹º$ˆˆÎ+Œ&Êj£åÎ^|+0X˜4~2$Á]Árn’’}“zógÉHøžakÙÌQ_`Xœæ0âaYÛw$èDÈ«êÎáîÑò$+^IRÌôuK»(ÉhÔ£’r±Œ!äÆÒcÙûq¥áëÅg‹h.¬Y¯¡Á˜Šº•˜nI拡e³]b˧lïbzÙ#/øfõÙ¬>B¸Û¬>›Õ‡ÐºG¥.ßlõ‰þ´¹Þo×;*’Õ®wT"õ?ëzG[š{öHýK9’­¤ñ–V¿¥Õ7[I㗰HZ>fK«·–˜tÆ¿kZýýM’[Ick×0I&€=&)¯cFOʋ‚ùß=)‡
+]ЃÀ΄µ×{%åuœ¸5wIÊ”Qˆ%cOÊë +eõ¤¼Q,CIy ©õãÌý’òÀŠtǤ¼Ö³i`¶ü
+®¤(ã+$å%µžâV~˜A·òÃ[ùáýÎî»A¹ïÜ«Ü`œù*n7ß|권}ê:t9è Tä*Ô2·V( +a·Ä ·–ç
+æÖWÁCZl^rk%žpkÅ$;Ÿpk yÔ(Áú +‰á¿æ֚]‘· À5·–Tó8¡žíÖr̄3U‘W$zvªâ¸=íÖºKE^a ª²BêÖÆ!Õ­¥ñhn«I·ÀÖ«È;0šóð»íâãÕ/>ÐãâㇸD¼©bïm¶Š¼BÚ«¹n¹øø×AP¿]Ýu I sh&»›\"¿²ùByÁä¶Üu°rE^!º¼¸ë gp<_4³(-wK43Ðï¹^O£™#ó‚hæ‘Á¯Í<6‡¢™!nÎ+ ð~Ñ̞¿E¨z=š9”oŸ;šyу£™mfÝ6‰f¶Štv[4sæ/>U4³ØÞ¥ô²¿Oğjl]ñ'Å‚M²Ö· ŠËêœ@>‚äª/D‘(¡_ÅñqÅþj¥ês«±5rʪÚP±Š™¹:φz³›BÄ8*¡‹×NȚsÉÉAӛ% +)ÿˆpL,X9…@IË–ó„ՌɈ½>ü(r‚<U|/³ã„ïˑÅVUäS5 c)ÁD?ÆU@”B# óh@œÃ„D=!®t.ñR@L Ü& ú¼B •¼E&·ä˜]À`lfx"gmÉ +‚À„äOÆÒçaªfê¤` içÀe'·³ø~Ó­¶Á*"úVÛ`«m`íVÛ༠~z$±–˜¥£ñ×VÛ`«m`îH¬ï=¡5°³ªb´U՟µfÎïÝ ËtíšÔ%µ?#HÛD0#|*ß §"1æ¡èüjæ¯¬Í ò$1IµƉ¨,¶Ã ‚¥ô[CaAEHàFæ¬Ø°Bˆ–Û‚ +&T,
+„d6ƒ&ý & žKr +ÎN7J•H£—ˆŒXi˜{‚ ¶_ŸÔïŒh¦`€ìÅ谙Í9¢™n75øB´ó™½˜}Dƒ{ø„ g” ƒUf? +–†;Îç –³^4,\^í¼ü•á×(£¤Ýg`§Á^/䍏Ú>;םZóýš¶Ïá{°Ò * öû‰:® +©‹M8ÎË_ASÒñ­;*ùªÅØ È(e`m¦X|Hˆ“U2£ÔV0ŠÎI(¢×>Ç»„/ŸÔ È&D 0QR™ÀFy8äB]#_”^¦\Jҍ¢y¢™}û$Ð ÞàÐÌ;Ti^pª½C§úë²êõYæ²¾B}–ÄÁææ@Ö;Ôg™ÈzC}–²Êú, Y…®6_U{Æ@Vªô¸ú,·²vžÞ7ýꁬ[ +Œk`聬Ï]c d d}î
+d]`ºÞYO¿>/õ–[ k•Õ·8©o3NhjV
+bY¤,k¶°¬a;Rf \Q9Œô¶R…OdÞ +ôj9Õ¼B”0õº´ANF©sf”,NŠ! ó"¤ÉèÁOfæ%TF»2˜]€˜ ¦ Qý`ÚÎV³3cXôJ率…¦²ûQPt<%‹§$.S2JäQ2©©Í9(Ñ-6$PNc=FtšÉZ&uaGrÃû®Á² +²ºb…#suÆ(áÞD–¹bßÅÛjqÕ໘@£n9ƒ$®
+¤WÁÚ*1Fð¸ýO³ŸÕ¯) ¸w¡…è0ýš²Ž¿ˆù˜à,Ôö¦Ç^ 2¬=mXd–²ºÂŒ&¼)XÚ¹ìÚ;†*ö*b<|Ó(n;Å¢„!fœöbqŸÐŒÊZøjÆi Aý<Yùj'z'n8Ý|“„ ÓÄÅBý…ǁLãxÆB°3Jí .# d:œ­B¢dü;k‚øqƒóÂ؆Á9 UڍÇG¹«.9umÞûv³NÊ¥ïÃE”ö ÈhÖzP$@+®A|G@çüy‡‘ +­å¶T>z@ñßÿÔüc®˜ì¾F—óŠVè}µpæ†fí ‚ˆ‰B)ØFätn­: íLZáåÅðT¶åÒ°f(ãócºF¶0!@cèš~×ô{ÍýQ~qY¯Ñƒ„&Û|bÄ>“~P$`a{nYÁï¡Ô“37ð¸"']ó{X£€×O›/VÀÄXÕb…_U’ÌtLJˆÊTZ⪙ªàPø5¿‚‡Q,8”E°hƒ¡pHB—ÒìRZځŸ¥³#Ç¿£ŸÅK|žWk\ÍȌ»(ÕAt]HuªÄ²Å}¢iq8X®àÎÙU€%tç°Ãҟ—¥/{N¦1*AÒ®çÆ"‚J-ñ6J“$H—èðEÝJdô,X\ˆJ
+ Ø*œ/r‚ÃìÈ
+‡ª–Âí~aÓ²8ÄÄS¡¾8mZn>RAIš1u;²çj3Á‘¹vdÍË¡†@—ãÜjú#։]Qkžcæۑd¤y݅ž@^·ðˆHMÅñŽÅ…‘‘A¢º£(‰l“…TÕ}^ÈÛ&,T˜©DDç@-äADµb«•Â‚&«xID¨sVð×*¦õ#«iœ1u^ÄÁb$‘Ÿå>HÜòò|î€.wô®îq9̳ºDa¥îQ偨*™Ð9îQ×xÊ} ”O6J½W£#’©ë{/é>ašKa÷¦˜.pD¡i<Î}03~yú-lÛ=Üu5±ºI”~N÷AହÙ}‚lèF÷6AÔà/ì>€±ÝÝ}°D
+ʧö|xä}vZå>;š’ZæT&oæßg;ÿ>;裗ƒÁ¥)„ „ç6]E›‰_\B5OŸ]—†!v}Ÿíš¸¹$ϲ,‡n2#á"|
+“Ø× â‚eQÏ·ûLf¢"Êf!ÊbYTM€ JGP¢ ‰ +F`1̊†ˆð¤i†Èš°2cïØ c”;®JÄÔþÙ;F©ñÿ¾3J£ÔjÐ֕+@šh/–››Þ4aOªB
+ק²–¤|¡[ߌ’‡g%Üï„WEüü ҁŽÒq+N.ÂÕp%ޙ¨|ÚÕÄ!ï»Üz…NV]%‘ßÙÙæ—îþågß´¾Û§£‡»m~ùmç‚ë卥ŠW›³wû¶Ï¡ÍÍ/ï»ÿüÉÚнD:þ™ßüÓÛðÛ¾u6|Т?ãú+Úڏ7ç'?ú2½í›cñSGFÆF‘Þœ…?‡“ŽÄ¤a»Ž~LFéù°HcŽ<í,4ŸQuÐéy™O‰~ËÖ}ØWÙú-[ÊαùÒ +¦kÇF[ú-_iÒ_÷aaùJºé…fk~~3þtÃÇÙÈ{ëþ«ù寻¿üò„DZ÷Ãéh‡%Ïn<ŽmâOë¸Ü/a__«øÖѓl:‚ºd$.?]o~ÐÙÖr<ø³8qd$Ñ[tjÈ,ØñlqSlN‚v9FaÈ!úñæI7Ó§þÊÙ¦r
+"è+ޕ+G™MޒóFÉkä•mw‘g¨Á¦ÇéGôþLH¯Ø۶ƫª{À‘èÏÕRh/ÙÀŸ1*°-QÙM£ §ãìX ²Îp¡‚8||O§ý=‘¶†9 +ç§ý;}ê„üßÔ%G©«2ñz¬‰'u#Õi–ýþF1„´Ìö¢§§öŠE ë­Ä§&ïݺ^µqü ¸«í
+çRÎgªOvˆª8ÑÕ$6ŽÚl_CŸ0¢ÙMn«¯`ž0[v!cáu–ì°FŒªÕ-AœªÄ-6_Š ÓR#=;ìd…:Õ¯á“¥kk›[×!$‡¬jWŅuéá ˆÅɶLK½ÂÍ߈"?ð¦_Õк
+F,Í9Ùጟa Ç̚ÞÄ0Ü4} -w•ö¯ü*¡ž~×wo~’|²åÉ\<©Í«b’›^MÿímZcbrŽÔ=*²_±§5 ÅuûÆôÂÖєÑ1·Pr›ÖèžÜj¾éÈìÜ4¦0Z[7W]³ ­Ž4MUÚeè[c-õef,Ó¾ž¼|4š´“óãŒÈ×¥›ù$WîvÅÎ#)—ÇÜ즗ªb“„QJzæï {ÆO†à›+aUS°§IË:Ó²²ë÷¶íû.Ì7貘Ó]„â%0ü]ká}צ :;`(nCïn‰·/TF8-HîBt'ÿro]\>ôÇÅÿ؂ÄÐòþ®ß'Z@3wî”]×'²Òú»
+ŸjS§µ¡¿«ð÷©Fì};Š¦¨m]tmÊ@c.nïa¿ÈF›ëÛ8|ÓuJ»ãÅf?µ‘Ç$ËStÁÀ¼DÀ²DÀß5ðûD µ‘¿]K8ý÷¤ÿ¿ÿýÏ®ÐÕæßα¶Íÿít|ßWRNü°ûûÃےûQÙx'ð¡¿K0Í
+ýÅ0^òOûCðUûƒyô!îû¡‹Ü²ùõö.ó£ý¡ù­ÚÌà +K9F“¼OL|Õ ²ՙßÞ¡Îé‰øíýãsÆþ0†bøšŠÚ%ƒû[cP»tõ¬ºØ Av?XyŠCÃaÀà臹û1W…9êSy§çsÍ9N4üNèª=ê +W5Ž)×íQ?â”x¯yôõv)ñ^µ?µ]² w#mm«“¶¡¿ËÍëîf˜pqa†ôG…‹õúSÛ¥ûw§ùH·&]àës{ĝЙ_µÇaŽ—kHž ¨»ì!îïášýnˆW”°5Wt¢á÷)t:÷xé³u]›uÈÔ£A§sBý+?ˆÄ]s€´­/†?Œ·ü1uoÝøÁÙ„,Cíwlò¹bGÿFLìaÛ¾¥D:éq/?X/ØpÕÆ·S|nקž¹–>¶²4XæZòyX¸-܀ླý ’•­8Å>{䧙ƒÂmûaä!ŸÒQ°˜‹Ä øý´Ñ·!<×<n¿ÔБËh;jœoû·LP GqÚ ^õˆ0óz®ØŒ™·„{øB8Øï4nTùa[û·º/hºǬô®¯¼üݽUˆ•0YD£*ê#¤q/.‘w±õ„ísaë ‚Ù¶gé:æ%p= §ð
+`â¬ÎœD7š•)¤àÅ£ž>Èç钞ÑÍ kt +w%eHV)­£Á ÃßØ7öèǝ¾3.j鎫ÝÙR¿íáãxˆ¶V¾Ê<l1ï9ÃO]í{{üñÿÐåÞ/!÷æ|45ED,=:¤G)ýýJ¨Z%ð…Ç$° (qÉbHâ«Hôûµ ')\ÕS—¸ÌÉÆM¤6ön=šµ'#¢õ*¨Ï«­tyP­ÂÅ4|{=«÷m¿w}ï]9ñÕÀ3!Øz†~º¢1±æòQJžz×¥Šfà(*»–©‡ö„ã^'™ósíEÌ}¬í‹ ›§2|@ËxÚO$ÀÝM§úd\8šIE‰Å¸ùô¥O©¿‹C`Xì~pŸÜo3Œ™c½¦ Îh—>Kê}Ü4¡MÚ4¡'ӄRŸG*ÖÚ|t]‰Ž†ûø¬2–ïÚaÔÝÈT&4¡c´«„T¦P—ÚÚzš΄ÌW’Òx:ãôøÎI›<£º’2-Œÿ¤@ƒ}KógTÉ9a
+#Ojf8ª.7©–*IUJžþÒU2gªGºjâA– ϯñ´6¹ÈNDµÛ¹oÕl8?wՄú¥*rí<TÓf«þ«óqYŽÕ¢,LWMÉ}R@(þ­^å@ ½cLåI¦sü8´ ˆmžf-ר’ã_=À<•‡hÞ™Œ#–:‘/ěÅ·§ÅáK±À£ÅWÄOÃáEA<­k£ã#géx?s ¢T[WGR +½˜7û{µÛ¿Å1NPêÇkxÆcêò¤nL+R-×^ÆuŸnÝ}~£—¦¬<±Ñ‹Œü•¸?ùÑüE†F´Ô +?¸ÿà1†ÆXbíbhÄ]wvŒB~x×ُÉE7¯ö%8~3¯~Î 7óêf^­š´>¦Äi7uïÆIòìs<¥sßgWõŽcIðý)¿ao}ˆVšWÖ%üQCwÕ“G-eZ%Hß®T„e.ÔÄ:‘{T÷'½ð¢Ø=×¢ S£j…IÓÛd¸¶ ¶Ÿ¶+J”¯*QŽ‰nRyñÏ- +"ðXáÄ†%‹WMÕþúTìõÖùrðZŸœÛ'p0mZ?þjEï½¥3o>ÙtÑ·Ç3>’Bu>« LeŽ(!¬^h†]É@p¬ÜwN´þT_>œÆ‹œVyM¡œµÏÝ??[Œf
+ ¸UÔm«¢nðåÒøaÝNC}$f¯Ñ.täFŽ©cqÙ1s짺¿"ÄJø_øAÚaìDüus2r mGwÅ(ü¤¹PHB͟ ½æNqm¼}$‹*+í1Cãä҈µ  +w¢\oµN^8Ë뚥©É +ˆ«PcYæ:MŽWVS›ÞKºí¢¬.[}¼Í¡:ÊJ«èßvÿëÈ;
+endstream
+endobj
+31 0 obj
+<<
+/Font <<
+/F1 11 0 R
+/F2 19 0 R
+/F3 28 0 R
+>>
+>>
+endobj
+3 0 obj
+<<
+/Contents [ 20 0 R 29 0 R 30 0 R ]
+/CropBox [ 0.0 0.0 595.32001 841.92004 ]
+/MediaBox [ 0.0 0.0 595.32001 841.92004 ]
+/Parent 2 0 R
+/Resources 31 0 R
+/Rotate 0
+/Type /Page
+>>
+endobj
+10 0 obj
+<<
+/Length 1193
+>>
+stream
+/CIDInit /ProcSet findresource begin 12 dict begin begincmap /CIDSystemInfo << /Registry (Adobe) /Ordering (UCS) /Supplement 0 >> def /CMapName /Adobe-Identity-UCS def /CMapType 2 def 1 begincodespacerange <0000> <FFFF> endcodespacerange 62 beginbfchar <0003> <0020> <0004> <0021> <0008> <0025> <000B> <0028> <000C> <0029> <000E> <002B> <000F> <002C> <0011> <002E> <0013> <0030> <0014> <0031> <0015> <0032> <0016> <0033> <0018> <0035> <001B> <0038> <001C> <0039> <0024> <0041> <0025> <0042> <0026> <0043> <0027> <0044> <0028> <0045> <0029> <0046> <002B> <0048> <002C> <0049> <002F> <004C> <0030> <004D> <0031> <004E> <0032> <004F> <0033> <0050> <0035> <0052> <0036> <0053> <0037> <0054> <0038> <0055> <0039> <0056> <003B> <0058> <003C> <0059> <0044> <0061> <0045> <0062> <0046> <0063> <0047> <0064> <0048> <0065> <004A> <0067> <004B> <0068> <004C> <0069> <004F> <006C> <0050> <006D> <0051> <006E> <0052> <006F> <0053> <0070> <0054> <0071> <0055> <0072> <0056> <0073> <0057> <0074> <0058> <0075> <0059> <0076> <005B> <0078> <005C> <0079> <0065> <00C9> <006A> <00E0> <0070> <00E9> <00AC> <00C0> <00B1> <2013> <00B6> <2019> endbfchar endcmap CMapName currentdict /CMap defineresource pop end end
+endstream
+endobj
+9 0 obj
+[ 3 3 277 4 4 333 8 8 889 11 11 333 12 12 333 14 14 583 15 15 277 17 17 277 19 19 556 20 20 556 21 21 556 22 22 556 24 24 556 27 27 556 28 28 556 36 36 722 37 37 722 38 38 722 39 39 722 40 40 666 41 41 610 43 43 722 44 44 277 47 47 610 48 48 833 49 49 722 50 50 777 51 51 666 53 53 722 54 54 666 55 55 610 56 56 722 57 57 666 59 59 666 60 60 666 68 68 556 69 69 610 70 70 556 71 71 610 72 72 556 74 74 610 75 75 610 76 76 277 79 79 277 80 80 889 81 81 610 82 82 610 83 83 610 84 84 610 85 85 389 86 86 556 87 87 333 88 88 610 89 89 556 91 91 556 92 92 556 101 101 666 106 106 556 112 112 556 172 172 722 177 177 556 182 182 277 ]
+endobj
+6 0 obj
+[ -889 -211 889 905 ]
+endobj
+7 0 obj
+889
+endobj
+18 0 obj
+<<
+/Length 1319
+>>
+stream
+/CIDInit /ProcSet findresource begin 12 dict begin begincmap /CIDSystemInfo << /Registry (Adobe) /Ordering (UCS) /Supplement 0 >> def /CMapName /Adobe-Identity-UCS def /CMapType 2 def 1 begincodespacerange <0000> <FFFF> endcodespacerange 71 beginbfchar <0003> <0020> <0008> <0025> <000B> <0028> <000C> <0029> <000F> <002C> <0010> <002D> <0011> <002E> <0012> <002F> <0013> <0030> <0014> <0031> <0015> <0032> <0016> <0033> <0017> <0034> <0018> <0035> <0019> <0036> <001A> <0037> <001B> <0038> <001C> <0039> <001D> <003A> <0024> <0041> <0025> <0042> <0026> <0043> <0027> <0044> <0028> <0045> <0029> <0046> <002A> <0047> <002C> <0049> <002F> <004C> <0030> <004D> <0032> <004F> <0035> <0052> <0036> <0053> <0037> <0054> <0038> <0055> <0039> <0056> <003E> <005B> <0040> <005D> <0044> <0061> <0045> <0062> <0046> <0063> <0047> <0064> <0048> <0065> <0049> <0066> <004A> <0067> <004B> <0068> <004C> <0069> <004D> <006A> <004F> <006C> <0050> <006D> <0051> <006E> <0052> <006F> <0053> <0070> <0054> <0071> <0055> <0072> <0056> <0073> <0057> <0074> <0058> <0075> <0059> <0076> <005B> <0078> <005C> <0079> <005D> <007A> <0065> <00C9> <006A> <00E0> <006F> <00E7> <0070> <00E9> <0071> <00E8> <0072> <00EA> <007B> <00F4> <0083> <00B0> <00B1> <2013> <00B6> <2019> endbfchar endcmap CMapName currentdict /CMap defineresource pop end end
+endstream
+endobj
+17 0 obj
+[ 3 3 277 8 8 889 11 11 333 12 12 333 15 15 277 16 16 333 17 17 277 18 18 277 19 19 556 20 20 556 21 21 556 22 22 556 23 23 556 24 24 556 25 25 556 26 26 556 27 27 556 28 28 556 29 29 277 36 36 666 37 37 666 38 38 722 39 39 722 40 40 666 41 41 610 42 42 777 44 44 277 47 47 556 48 48 833 50 50 777 53 53 722 54 54 666 55 55 610 56 56 722 57 57 666 62 62 277 64 64 277 68 68 556 69 69 556 70 70 500 71 71 556 72 72 556 73 73 277 74 74 556 75 75 556 76 76 222 77 77 222 79 79 222 80 80 833 81 81 556 82 82 556 83 83 556 84 84 556 85 85 333 86 86 500 87 87 277 88 88 556 89 89 500 91 91 500 92 92 500 93 93 500 101 101 666 106 106 556 111 111 500 112 112 556 113 113 556 114 114 556 123 123 556 131 131 399 177 177 556 182 182 222 ]
+endobj
+14 0 obj
+[ -889 -211 889 905 ]
+endobj
+15 0 obj
+889
+endobj
+27 0 obj
+<<
+/Length 731
+>>
+stream
+/CIDInit /ProcSet findresource begin 12 dict begin begincmap /CIDSystemInfo << /Registry (Adobe) /Ordering (UCS) /Supplement 0 >> def /CMapName /Adobe-Identity-UCS def /CMapType 2 def 1 begincodespacerange <0000> <FFFF> endcodespacerange 29 beginbfchar <0003> <0020> <000B> <0028> <000C> <0029> <0015> <0032> <0026> <0043> <0031> <004E> <0044> <0061> <0045> <0062> <0046> <0063> <0047> <0064> <0048> <0065> <0049> <0066> <004A> <0067> <004C> <0069> <004D> <006A> <004F> <006C> <0050> <006D> <0051> <006E> <0052> <006F> <0053> <0070> <0055> <0072> <0056> <0073> <0057> <0074> <0058> <0075> <005D> <007A> <006A> <00E0> <0070> <00E9> <0071> <00E8> <00B6> <2019> endbfchar endcmap CMapName currentdict /CMap defineresource pop end end
+endstream
+endobj
+26 0 obj
+[ 3 3 277 11 11 333 12 12 333 21 21 556 38 38 722 49 49 722 68 68 556 69 69 556 70 70 500 71 71 556 72 72 556 73 73 277 74 74 556 76 76 222 77 77 222 79 79 222 80 80 833 81 81 556 82 82 556 83 83 556 85 85 333 86 86 500 87 87 277 88 88 556 93 93 500 106 106 556 112 112 556 113 113 556 182 182 222 ]
+endobj
+23 0 obj
+[ -833 -211 833 905 ]
+endobj
+24 0 obj
+833
+endobj
+2 0 obj
+<<
+/Count 1
+/Kids [ 3 0 R ]
+/Type /Pages
+>>
+endobj
+1 0 obj
+<<
+/Pages 2 0 R
+/Type /Catalog
+>>
+endobj
+32 0 obj
+<<
+/Author (Utilisateur)
+/CreationDate (D:20170504160720+02'00')
+/ModDate (D:20170504160720+02'00')
+/Producer (Microsoft: Print To PDF)
+/Title (3310-2016.pdf)
+>>
+endobj
+xref
+0 33
0000000000 65535 f
-0000039191 00000 n
-0000040382 00000 n
-0000040470 00000 n
-0000040521 00000 n
-0000044247 00000 n
-trailer
-<</Size 6>>
-startxref
-116
-%%EOF
+0000107898 00000 n
+0000107839 00000 n
+0000102366 00000 n
+0000000009 00000 n
+0000000035 00000 n
+0000104450 00000 n
+0000104487 00000 n
+0000000058 00000 n
+0000103805 00000 n
+0000102559 00000 n
+0000019409 00000 n
+0000019881 00000 n
+0000019908 00000 n
+0000106624 00000 n
+0000106662 00000 n
+0000019932 00000 n
+0000105878 00000 n
+0000104506 00000 n
+0000044331 00000 n
+0000044809 00000 n
+0000061222 00000 n
+0000061249 00000 n
+0000107781 00000 n
+0000107819 00000 n
+0000061273 00000 n
+0000107465 00000 n
+0000106682 00000 n
+0000072032 00000 n
+0000072510 00000 n
+0000092435 00000 n
+0000102299 00000 n
+0000107947 00000 n
+trailer
+<<
+/Info 32 0 R
+/Root 1 0 R
+/Size 33
+>>
+startxref
+108126
+%%EOF
Index: OpenConcerto/src/org/openconcerto/map/ui/VilleListModel.java
===================================================================
--- OpenConcerto/src/org/openconcerto/map/ui/VilleListModel.java (revision 143)
+++ OpenConcerto/src/org/openconcerto/map/ui/VilleListModel.java (revision 144)
@@ -24,7 +24,7 @@
* Cache used in ISearchableCombo<Ville>
*
*/
-public class VilleListModel extends AbstractListModel implements IMutableListModel<Ville> {
+public class VilleListModel extends AbstractListModel<Ville> implements IMutableListModel<Ville> {
// MAYBE use an immutable collection and reload on demand
@@ -61,7 +61,7 @@
}
@Override
- public void removeElement(Ville v) {
+ public void remove(Ville v) {
Ville.removeVille(v);
}
/trunk/OpenConcerto/src/org/openconcerto/openoffice/ODPackage.java
16,6 → 16,7
import static org.openconcerto.openoffice.ODPackage.RootElement.CONTENT;
import static org.openconcerto.openoffice.ODPackage.RootElement.META;
import static org.openconcerto.openoffice.ODPackage.RootElement.STYLES;
 
import org.openconcerto.openoffice.spreadsheet.SpreadSheet;
import org.openconcerto.openoffice.text.TextDocument;
import org.openconcerto.utils.CopyUtils;
62,8 → 63,6
import java.util.Set;
import java.util.zip.ZipEntry;
 
import net.jcip.annotations.GuardedBy;
 
import org.jdom.Attribute;
import org.jdom.DocType;
import org.jdom.Document;
73,6 → 72,8
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;
 
import net.jcip.annotations.GuardedBy;
 
/**
* An OpenDocument package, ie a zip containing XML documents and their associated files.
*
1181,7 → 1182,11
if (productInfo == null) {
// do *not* use "/product.properties" as it might interfere with products using this
// framework
final Properties props = PropertiesUtils.createFromResource(this.getClass(), "product.properties");
Properties props = PropertiesUtils.createFromResource(this.getClass(), "product.properties");
if (props == null) {
Log.get().warning("Neither ProductInfo singleton nor product.properties for " + this.getClass());
props = new Properties();
}
props.put(ProductInfo.NAME, this.getClass().getName());
productInfo = new ProductInfo(props);
}
/trunk/OpenConcerto/src/org/openconcerto/openoffice/generation/view/GenerationTaskView.java
13,7 → 13,7
/*
* Créé le 12 nov. 2004
*
*
*/
package org.openconcerto.openoffice.generation.view;
 
31,10 → 31,10
 
/**
* Permet de voir une GenerationTask dans une JList.
*
*
* @author Sylvain CUAZ
*/
public final class GenerationTaskView extends JPanel implements ListCellRenderer {
public final class GenerationTaskView extends JPanel implements ListCellRenderer<GenerationTask> {
private static final int MAX = 10;
private final JLabel label = new JLabel();
private final JProgressBar bar = new JProgressBar(0, MAX);
43,7 → 43,7
super();
this.setOpaque(false);
this.setLayout(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
final GridBagConstraints c = new GridBagConstraints();
c.gridx = 0;
c.weightx = 1;
c.fill = GridBagConstraints.HORIZONTAL;
55,12 → 55,12
 
/*
* (non-Javadoc)
*
*
* @see javax.swing.ListCellRenderer#getListCellRendererComponent(javax.swing.JList,
* java.lang.Object, int, boolean, boolean)
* java.lang.Object, int, boolean, boolean)
*/
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
GenerationTask task = (GenerationTask) value;
@Override
public Component getListCellRendererComponent(final JList<? extends GenerationTask> list, final GenerationTask task, final int index, final boolean isSelected, final boolean cellHasFocus) {
this.label.setText(task.getName());
this.bar.setValue((int) (task.getStatus().getCompletion() * MAX));
return this;
/trunk/OpenConcerto/src/org/openconcerto/openoffice/generation/view/BaseGenerationRapport.java
66,7 → 66,7
* A panel to choose a ReportType, see the tasks of the generation, and optionnaly open the
* document. NOTE: you have to call {@link #enableGeneration(boolean)} before being able to
* generate, because it's set to false in the constructor.
*
*
* @author ILM Informatique 27 déc. 2003
* @param <R> type of generation
*/
77,7 → 77,7
 
private final String label;
 
private FileAction(String label) {
private FileAction(final String label) {
this.label = label;
}
 
87,12 → 87,12
}
}
 
private JComboBox typeRapportComboSelection;
private JComboBox<ReportType> typeRapportComboSelection;
 
private JButton genererButton;
private JComboBox fileActionCombo;
private JComboBox<FileAction> fileActionCombo;
 
private JList tasksView;
private JList<GenerationTask> tasksView;
private JLabel status;
 
// le groupe dans lequel doivent être toutes les thread de la génération
114,7 → 114,7
 
private void uiInit() throws JDOMException, IOException {
setLayout(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
final GridBagConstraints c = new GridBagConstraints();
c.ipadx = 40;
c.insets = new Insets(2, 5, 0, 0);
c.gridx = 0;
124,7 → 124,7
c.fill = GridBagConstraints.HORIZONTAL;
 
final Map<String, JComponent> allEntries = new LinkedHashMap<String, JComponent>();
this.typeRapportComboSelection = new JComboBox(new ListComboBoxModel(this.getTypes().getTypes()));
this.typeRapportComboSelection = new JComboBox<>(new ListComboBoxModel<ReportType>(this.getTypes().getTypes()));
allEntries.put("Type de rapport", this.typeRapportComboSelection);
allEntries.putAll(this.getEntries());
 
144,10 → 144,10
c.weightx = 1;
this.add(new JButton(new AbstractAction("Ouvrir le dossier des rapports") {
@Override
public void actionPerformed(ActionEvent e) {
public void actionPerformed(final ActionEvent e) {
try {
Desktop.getDesktop().browse(reportDir.toURI());
} catch (Exception e1) {
} catch (final Exception e1) {
JOptionPane.showMessageDialog(BaseGenerationRapport.this, "Impossible d'ouvrir le dossier", "Erreur", JOptionPane.ERROR_MESSAGE);
}
}
163,7 → 163,7
this.genererButton.addActionListener(new GenerateAction());
 
c.gridx++;
this.fileActionCombo = new JComboBox(getAllowedActions());
this.fileActionCombo = new JComboBox<>(getAllowedActions());
this.fileActionCombo.setSelectedItem(FileAction.OPEN);
this.add(this.fileActionCombo, c);
this.fileActionCombo.setEnabled(false);
175,11 → 175,11
this.add(this.status, c);
 
c.gridy++;
this.tasksView = new JList(new TasksModel());
this.tasksView = new JList<>(new TasksModel());
this.tasksView.setCellRenderer(new GenerationTaskView());
c.fill = GridBagConstraints.BOTH;
c.weighty = 1;
JScrollPane scroll = new JScrollPane(this.tasksView);
final JScrollPane scroll = new JScrollPane(this.tasksView);
scroll.setPreferredSize(new Dimension(200, 400));
this.add(scroll, c);
}
186,10 → 186,10
 
/**
* Permet de modifier la liste des tâches.
*
*
* @author Sylvain CUAZ
*/
private static final class TasksModel extends AbstractListModel implements PropertyChangeListener {
private static final class TasksModel extends AbstractListModel<GenerationTask> implements PropertyChangeListener {
private List<GenerationTask> tasks;
 
{
196,15 → 196,17
this.tasks = new ArrayList<GenerationTask>(15);
}
 
@Override
public int getSize() {
return this.tasks.size();
}
 
public Object getElementAt(int index) {
@Override
public GenerationTask getElementAt(final int index) {
return this.tasks.get(index);
}
 
void add(GenerationTask task) {
void add(final GenerationTask task) {
this.tasks.add(task);
task.addPropertyChangeListener(this);
this.fireIntervalAdded(this, this.tasks.size(), this.tasks.size());
221,8 → 223,9
/*
* Une tache a changé.
*/
public void propertyChange(PropertyChangeEvent evt) {
int index = this.tasks.indexOf(evt.getSource());
@Override
public void propertyChange(final PropertyChangeEvent evt) {
final int index = this.tasks.indexOf(evt.getSource());
this.fireContentsChanged(this, index, index);
}
}
239,7 → 242,8
public GenerateAction() {
}
 
public void actionPerformed(ActionEvent e) {
@Override
public void actionPerformed(final ActionEvent e) {
enableGeneration(false);
final FileAction sel = (FileAction) BaseGenerationRapport.this.fileActionCombo.getSelectedItem();
// "génération..."
249,6 → 253,7
generate(sel);
// toujours le faire, même si interrompu
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
enableGeneration(true);
}
258,7 → 263,7
}
}
 
protected final void enableGeneration(boolean b) {
protected final void enableGeneration(final boolean b) {
this.fileActionCombo.setEnabled(b);
this.genererButton.setEnabled(b);
}
268,7 → 273,8
final ReportType type = (ReportType) this.typeRapportComboSelection.getSelectedItem();
final R rg = this.createGeneration(type);
rg.addTaskListener(new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
@Override
public void propertyChange(final PropertyChangeEvent evt) {
final TaskStatus st = (TaskStatus) evt.getOldValue();
if (st.getState().equals(TaskStatus.State.NOT_STARTED))
addTask((GenerationTask) evt.getSource());
283,7 → 289,7
try {
report = this.generate(rg);
if (report != null) {
for (Entry<String, ODSingleXMLDocument> e : report.entrySet()) {
for (final Entry<String, ODSingleXMLDocument> e : report.entrySet()) {
try {
final ODSingleXMLDocument singleDoc = e.getValue();
final File reportFile = singleDoc.saveToPackageAs(this.getFile(rg, e.getKey()));
302,25 → 308,25
conn.closeConnexion();
// can wait for the pdf since we're not in the EDT
EmailClient.getPreferred().compose(getEmailRecipient(rg), "Rapport", null, pdf.get());
} catch (Exception exn) {
} catch (final Exception exn) {
exn.printStackTrace();
ExceptionHandler.handle("Impossible de charger le document OpenOffice dans le logiciel de courriel", exn);
}
}
} catch (FileNotFoundException exn) {
} catch (final FileNotFoundException exn) {
// TODO tester pb de droits
ExceptionHandler.handle(BaseGenerationRapport.this, "Le fichier est déjà ouvert, veuillez le refermer avant de générer.", exn);
} catch (IOException exn) {
} catch (final IOException exn) {
ExceptionHandler.handle(BaseGenerationRapport.this, "Impossible de sauver le rapport", exn);
}
}
}
} catch (Throwable e) {
} catch (final Throwable e) {
ExceptionHandler.handle(BaseGenerationRapport.this, "Impossible de générer le rapport", e);
}
}
 
private Map<String, ODSingleXMLDocument> generate(org.openconcerto.openoffice.generation.ReportGeneration<?> rg) throws Throwable {
private Map<String, ODSingleXMLDocument> generate(final org.openconcerto.openoffice.generation.ReportGeneration<?> rg) throws Throwable {
clearTasks();
setStatus("Génération en cours...");
 
338,7 → 344,7
} else {
s = "Rapport généré en " + (System.currentTimeMillis() - start) / 1000 + " secondes.";
}
} catch (Throwable e) {
} catch (final Throwable e) {
s = "Erreur de génération.";
t = e;
}
352,6 → 358,7
 
private final void addTask(final GenerationTask task) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
((TasksModel) BaseGenerationRapport.this.tasksView.getModel()).add(task);
}
361,6 → 368,7
 
private final void clearTasks() {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
((TasksModel) BaseGenerationRapport.this.tasksView.getModel()).clear();
}
370,6 → 378,7
private final void setStatus(final String status) {
Log.get().info(this + " status: " + status);
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
BaseGenerationRapport.this.status.setText(status);
}
376,6 → 385,7
});
}
 
@Override
public String toString() {
return "Generation panel";
}
/trunk/OpenConcerto/src/org/openconcerto/ui/EmailComposer.java
40,7 → 40,20
}
to = to.trim();
subject = subject.trim();
final String title = EmailProps.getInstance().getTitle();
if (title != null && title.trim().length() > 0) {
subject = title + " " + subject;
}
 
text = text.trim();
final String header = EmailProps.getInstance().getHeader();
if (header != null && header.trim().length() > 0) {
text = header + "\n" + text;
}
final String footer = EmailProps.getInstance().getFooter();
if (footer != null && footer.trim().length() > 0) {
text = text + "\n" + footer;
}
 
EmailClient emailClient = null;
final int mode = EmailProps.getInstance().getMode();
/trunk/OpenConcerto/src/org/openconcerto/ui/table/TimestampTableCellEditor.java
23,8 → 23,8
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.sql.Timestamp;
65,6 → 65,7
this.allowNull = b;
}
 
@Override
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
final Component c = super.getTableCellEditorComponent(table, value, isSelected, row, column);
Date time = (Date) value;
99,17 → 100,9
});
}
});
t.addKeyListener(new KeyListener() {
t.addKeyListener(new KeyAdapter() {
 
@Override
public void keyTyped(KeyEvent e) {
}
 
@Override
public void keyReleased(KeyEvent e) {
}
 
@Override
public void keyPressed(KeyEvent e) {
 
if (e.getKeyCode() == KeyEvent.VK_DOWN) {
137,6 → 130,7
return super.stopCellEditing();
}
 
@Override
public void cancelCellEditing() {
super.cancelCellEditing();
hidePopup();
153,7 → 147,12
public void showPopup(Component c, Point p) {
this.popupOpen = true;
if (aPopup != null) {
this.aPopup.show(c, p.x, p.y);
try {
this.aPopup.show(c, p.x, p.y);
} catch (Exception e) {
// Se produit quand c n'est pas visible
System.err.println("cannot show popup : " + e.getMessage());
}
}
SwingUtilities.invokeLater(new Runnable() {
 
168,6 → 167,7
return popupOpen;
}
 
@Override
public Object getCellEditorValue() {
final Date v = (Date) super.getCellEditorValue();
long t = System.currentTimeMillis();
179,10 → 179,12
return new Timestamp(t);
}
 
@Override
public boolean isCellEditable(EventObject anEvent) {
return true;
}
 
@Override
public boolean shouldSelectCell(EventObject anEvent) {
return true;
}
203,10 → 205,9
}
final JFrame f = new JFrame(TimestampTableCellEditor.class.getName());
final Timestamp[][] rowData = new Timestamp[2][2];
long t = 5000000;
rowData[0][0] = new Timestamp(t);
rowData[0][1] = new Timestamp(t += 50000);
rowData[1][0] = new Timestamp(t += 50000);
rowData[0][0] = new Timestamp(5000000);
rowData[0][1] = new Timestamp(5000000 + 50000);
rowData[1][0] = new Timestamp(5000000 + 100000);
 
final JTable table = new EnhancedTable(rowData, new String[] { "a", "b" });
 
/trunk/OpenConcerto/src/org/openconcerto/ui/component/IComboCacheListModel.java
14,7 → 14,6
package org.openconcerto.ui.component;
 
import org.openconcerto.ui.component.combo.ISearchableCombo;
import org.openconcerto.utils.SwingWorker2;
import org.openconcerto.utils.change.CollectionChangeEvent;
import org.openconcerto.utils.change.IListDataEvent;
import org.openconcerto.utils.model.DefaultIMutableListModel;
23,6 → 22,7
import java.util.Collection;
import java.util.List;
 
import javax.swing.SwingWorker;
import javax.swing.event.ListDataEvent;
import javax.swing.event.ListDataListener;
 
81,7 → 81,7
 
public final void load(final Runnable r, final boolean readCache) {
if (this.cache.isValid()) {
new SwingWorker2<List<String>, Object>() {
new SwingWorker<List<String>, Object>() {
 
@Override
protected List<String> doInBackground() throws Exception {
/trunk/OpenConcerto/src/org/openconcerto/ui/component/ITextCombo.java
26,7 → 26,6
import org.openconcerto.ui.valuewrapper.ValueWrapper;
import org.openconcerto.utils.CompareUtils;
import org.openconcerto.utils.IFutureTask;
import org.openconcerto.utils.SwingWorker2;
import org.openconcerto.utils.checks.ValidListener;
import org.openconcerto.utils.checks.ValidState;
import org.openconcerto.utils.model.ListComboBoxModel;
57,6 → 56,7
import javax.swing.JComponent;
import javax.swing.JList;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import javax.swing.event.DocumentEvent;
import javax.swing.text.AbstractDocument;
import javax.swing.text.BadLocationException;
440,7 → 440,7
this.objToSelect = this.getValue();
this.cacheLoading = true;
final FutureTask<? extends ITextCombo> noop = IFutureTask.createNoOp(this);
final SwingWorker2<List<String>, Object> sw = new SwingWorker2<List<String>, Object>() {
final SwingWorker<List<String>, Object> sw = new SwingWorker<List<String>, Object>() {
@Override
protected List<String> doInBackground() throws Exception {
return force ? ITextCombo.this.cache.loadCache(false) : ITextCombo.this.cache.getCache();
/trunk/OpenConcerto/src/org/openconcerto/ui/component/combo/ISearchableCombo.java
99,6 → 99,8
import javax.swing.text.Document;
import javax.swing.text.JTextComponent;
 
import net.jcip.annotations.GuardedBy;
 
/**
* A lightweight component that allows to search for and select a single item. If a cache is
* associated, autocompletion is enabled and a popup list is available.
123,6 → 125,7
protected static final int LABEL_GAP = 2;
protected static final int BTN_GAP = 3;
 
@GuardedBy("this")
private SearchMode modeCompletion = MODE_CONTAINS;
// Popup de completion
private ISearchableComboCompletionThread<T> completionThread;
130,7 → 133,7
// fullList
private final DefaultIMutableListModel<ISearchableComboItem<T>> model;
protected ISearchableComboItem<T> initialValue;
// list for the popup
// list for the popup (contains ISearchableComboItem<T> & Action)
private final ListComboBoxModel listModel;
private final ISearchableComboItem<T> emptyItem;
private boolean includeEmpty;
160,6 → 163,7
private static Image imageSelectorEnabled;
private static Image imageSelectorDisabled;
// Option de filtrage
@GuardedBy("this")
private int minimumSearch = 1;
private int maximumResult = 300;
 
547,7 → 551,7
 
@Override
public void removeCurrentText() {
mutable.removeElement(getValue());
mutable.remove(getValue());
}
 
@Override
637,7 → 641,7
this.itemsByOriginalItem.clear();
} else {
for (final ISearchableComboItem<T> item : getModel().getList().subList(index0, index1 + 1)) {
this.itemsByOriginalItem.remove(item.getOriginal(), item);
this.itemsByOriginalItem.removeOne(item.getOriginal(), item);
}
}
getModel().removeElementsAt(index0, index1);
694,7 → 698,7
// get
 
ISearchableComboItem<T> getSelection() {
return this.getModel().getSelectedItem();
return this.getModel().getSelectedObject();
}
 
public T getValue() {
790,13 → 794,13
 
private final void setSelection(final ISearchableComboItem<T> val) {
log("entering " + this.getClass().getSimpleName() + ".setSelection " + val);
this.getModel().setSelectedItem(val);
this.getModel().setSelectedObject(val);
}
 
// as a result of setSelection() or a ITextSelectorItemsModel change
protected final void selectionChanged() {
this.updating = true;
final ISearchableComboItem<T> sel = this.getModel().getSelectedItem();
final ISearchableComboItem<T> sel = this.getModel().getSelectedObject();
this.getLabel().setIcon(sel == null ? null : this.getIcon(sel));
this.updateMargin();
// si invalidEdit la selection means nothing, so don't change the textField
893,11 → 897,10
}
 
if (this.completionThread != null) {
this.completionThread.stopNow();
this.completionThread.cancel(true);
}
this.completionThread = new ISearchableComboCompletionThread<T>(this, t);
this.completionThread.setPriority(Thread.MIN_PRIORITY);
this.completionThread.start();
this.completionThread.execute();
}
 
List<ISearchableComboItem<T>> getModelValues() {
1277,7 → 1280,7
this.updateMargin();
}
 
public void setMinimumSearch(final int j) {
public synchronized void setMinimumSearch(final int j) {
this.minimumSearch = j;
}
 
1286,7 → 1289,7
*
* @return nombre de lettre minimum.
*/
public int getMinimumSearch() {
public synchronized int getMinimumSearch() {
return this.minimumSearch;
}
 
1295,11 → 1298,11
 
}
 
public final SearchMode getCompletionMode() {
public synchronized final SearchMode getCompletionMode() {
return this.modeCompletion;
}
 
public final void setCompletionMode(SearchMode m) {
public synchronized final void setCompletionMode(SearchMode m) {
this.modeCompletion = m;
}
 
/trunk/OpenConcerto/src/org/openconcerto/ui/component/combo/ISearchableComboCompletionThread.java
16,25 → 16,31
import org.openconcerto.ui.component.combo.SearchMode.ComboMatcher;
import org.openconcerto.utils.IFutureTask;
import org.openconcerto.utils.RTInterruptedException;
import org.openconcerto.utils.model.IListModel;
import org.openconcerto.utils.model.ISearchable;
 
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
 
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
 
public class ISearchableComboCompletionThread<T> extends Thread {
public class ISearchableComboCompletionThread<T> extends SwingWorker<List<ISearchableComboItem<T>>, Object> {
private final ISearchableCombo<T> combo;
private final IListModel<T> sourceModel;
private final List<ISearchableComboItem<T>> toProcess;
private final String t;
private boolean stopNow;
private final int maxResults;
 
public ISearchableComboCompletionThread(final ISearchableCombo<T> combo, final String t) {
this.combo = combo;
this.sourceModel = combo.getCache();
this.toProcess = new ArrayList<>(combo.getModelValues());
this.t = t;
this.stopNow = false;
this.maxResults = this.getCombo().getMaximumResult();
}
 
private ISearchableCombo<T> getCombo() {
41,43 → 47,45
return this.combo;
}
 
@Override
public void run() {
computeAutoCompletion();
private final boolean isShowAll() {
return this.t == null;
}
 
public synchronized void stopNow() {
this.stopNow = true;
}
 
private synchronized boolean isStopped() {
return this.stopNow;
return Thread.currentThread().isInterrupted();
}
 
private void computeAutoCompletion() {
final boolean showAll = this.t == null;
@Override
protected List<ISearchableComboItem<T>> doInBackground() throws Exception {
final List<ISearchableComboItem<T>> l;
if (!showAll) {
if (!isShowAll()) {
l = getMatchingValues();
} else {
l = getMaxValues();
}
return l;
}
 
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
if (isStopped()) {
return;
}
getCombo().setMatchingCompletions(l, showAll);
}
});
 
@Override
protected void done() {
super.done();
try {
getCombo().setMatchingCompletions(this.get(), this.isShowAll());
} catch (InterruptedException e) {
// ne devrait pas arriver puisque done() appelée après doInBackground()
e.printStackTrace();
} catch (CancellationException e) {
// OK
} catch (ExecutionException e) {
if (!(e.getCause() instanceof RTInterruptedException))
// pas normal
e.printStackTrace();
}
}
 
private List<ISearchableComboItem<T>> getMaxValues() {
final List<ISearchableComboItem<T>> allVals = this.getCombo().getModelValues();
return allVals.subList(0, Math.min(this.getCombo().getMaximumResult(), allVals.size()));
final List<ISearchableComboItem<T>> allVals = this.toProcess;
return allVals.subList(0, Math.min(this.maxResults, allVals.size()));
}
 
private List<ISearchableComboItem<T>> getMatchingValues() {
93,8 → 101,8
Boolean searched = null;
// If there was a search and now the text is below minimum, we must unset the search
// Efficient since setSearch() only carry out its action if the search changes
if (getCombo().getCache() instanceof ISearchable) {
final ISearchable searchableListModel = (ISearchable) getCombo().getCache();
if (this.sourceModel instanceof ISearchable) {
final ISearchable searchableListModel = (ISearchable) this.sourceModel;
if (searchableListModel.isSearchable()) {
// Wait for the new values, which will be added to the model by a listener
final FutureTask<Object> noOp = IFutureTask.createNoOp();
109,10 → 117,10
}
}
if (!normalizedText.isEmpty() && searched != Boolean.FALSE) {
final List<ISearchableComboItem<T>> cache = getCombo().getModelValues();
final List<ISearchableComboItem<T>> cache = this.toProcess;
// don't filter twice
final ComboMatcher search = Boolean.TRUE.equals(searched) ? null : getCombo().getCompletionMode().matcher(normalizedText.toLowerCase());
final int maximumResult = getCombo().getMaximumResult();
final int maximumResult = this.maxResults;
 
for (int index = 0; index < cache.size(); index++) {
final ISearchableComboItem<T> itemO = cache.get(index);
/trunk/OpenConcerto/src/org/openconcerto/ui/list/selection/ListSelectionState.java
15,6 → 15,7
 
import static org.openconcerto.ui.list.selection.BaseListStateModel.INVALID_ID;
import static org.openconcerto.ui.list.selection.BaseListStateModel.INVALID_INDEX;
 
import org.openconcerto.ui.Log;
import org.openconcerto.utils.CollectionUtils;
import org.openconcerto.utils.cc.ITransformer;
161,8 → 162,11
this.selectIDs(Collections.singletonList(id));
}
 
public void selectIDs(final Collection<Integer> idsOrig) {
final List<Integer> ids = new ArrayList<Integer>(idsOrig);
public void selectIDs(final Collection<? extends Number> idsOrig) {
final List<Integer> ids = new ArrayList<Integer>(idsOrig.size());
for (final Number n : idsOrig) {
ids.add((Integer) (n instanceof Integer ? n : n.intValue()));
}
 
if (!this.getModel().isUpdating()) {
// sorted asc for use by CollectionUtils.aggregate()
/trunk/OpenConcerto/src/org/openconcerto/ui/light/LightUIComboBox.java
23,10 → 23,10
import net.minidev.json.JSONObject;
 
public class LightUIComboBox extends LightUserControl {
private static final String HAS_NOT_SPECIFIED_LINE = "has-not-specified-line";
private static final String VALUES = "values";
private static final String SELECTED_VALUE = "selected-value";
private static final String ALREADY_FILLED = "already-filled";
private static final String KEY_HAS_NOT_SPECIFIED_LINE = "has-not-specified-line";
private static final String KEY_VALUES = "values";
private static final String KEY_SELECTED_VALUE = "selected-value";
private static final String KEY_ALREADY_FILLED = "already-filled";
 
private boolean alreadyFilled = false;
private boolean hasNotSpecifedLine = false;
148,30 → 148,25
}
 
@Override
public LightUIElement clone() {
return new LightUIComboBox(this);
}
 
@Override
public JSONObject toJSON() {
final JSONObject json = super.toJSON();
 
if (this.values != null && this.values.size() > 0) {
if (this.values != null && !this.values.isEmpty()) {
final JSONArray jsonValues = new JSONArray();
for (final LightUIComboBoxElement value : this.values) {
jsonValues.add(value.toJSON());
}
json.put(VALUES, jsonValues);
json.put(KEY_VALUES, jsonValues);
}
 
if (this.alreadyFilled) {
json.put(ALREADY_FILLED, true);
json.put(KEY_ALREADY_FILLED, true);
}
if (this.hasNotSpecifedLine) {
json.put(HAS_NOT_SPECIFIED_LINE, true);
json.put(KEY_HAS_NOT_SPECIFIED_LINE, true);
}
if (this.selectedValue != null) {
json.put(SELECTED_VALUE, this.selectedValue.toJSON());
json.put(KEY_SELECTED_VALUE, this.selectedValue.toJSON());
}
 
return json;
181,8 → 176,8
public void fromJSON(final JSONObject json) {
super.fromJSON(json);
 
this.alreadyFilled = JSONConverter.getParameterFromJSON(json, ALREADY_FILLED, Boolean.class, false);
this.hasNotSpecifedLine = JSONConverter.getParameterFromJSON(json, HAS_NOT_SPECIFIED_LINE, Boolean.class, false);
this.alreadyFilled = JSONConverter.getParameterFromJSON(json, KEY_ALREADY_FILLED, Boolean.class, false);
this.hasNotSpecifedLine = JSONConverter.getParameterFromJSON(json, KEY_HAS_NOT_SPECIFIED_LINE, Boolean.class, false);
 
final JSONObject jsonSelectedValue = JSONConverter.getParameterFromJSON(json, "", JSONObject.class);
if (jsonSelectedValue != null) {
189,7 → 184,7
this.selectedValue = new LightUIComboBoxElement(jsonSelectedValue);
}
 
final JSONArray jsonValues = JSONConverter.getParameterFromJSON(json, VALUES, JSONArray.class);
final JSONArray jsonValues = JSONConverter.getParameterFromJSON(json, KEY_VALUES, JSONArray.class);
this.values = new ArrayList<LightUIComboBoxElement>();
if (jsonValues != null) {
for (final Object jsonValue : jsonValues) {
/trunk/OpenConcerto/src/org/openconcerto/ui/light/LightUIDate.java
38,7 → 38,7
}
 
public Timestamp getValueAsDate() {
if (this.getValue() != null && this.getValue() != "") {
if (this.getValue() != null && !this.getValue().isEmpty()) {
SimpleDateFormat df2 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.S");
try {
return new Timestamp(df2.parse(this.getValue()).getTime());
66,12 → 66,8
 
@Override
public void _setValueFromContext(Object value) {
final String strValue = (String) JSONConverter.getObjectFromJSON(value, String.class);
final String strValue = JSONConverter.getObjectFromJSON(value, String.class);
this.setValue(strValue);
}
 
@Override
public LightUIElement clone() {
return new LightUIDate(this);
}
}
/trunk/OpenConcerto/src/org/openconcerto/ui/light/LightUILabel.java
11,21 → 11,8
* When distributing the software, include this License Header Notice in each file.
*/
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.ui.light;
 
package org.openconcerto.ui.light;
 
import net.minidev.json.JSONObject;
 
public class LightUILabel extends LightUIElement {
68,8 → 55,4
};
}
 
@Override
public LightUIElement clone() {
return new LightUILabel(this);
}
}
/trunk/OpenConcerto/src/org/openconcerto/ui/light/Row.java
193,6 → 193,6
 
@Override
public String toString() {
return "Row index: " + this.id + " values: " + this.values;
return "Row id: " + this.id + " values: " + this.values;
}
}
/trunk/OpenConcerto/src/org/openconcerto/ui/light/LightUIContainer.java
23,11 → 23,10
import net.minidev.json.JSONObject;
 
public class LightUIContainer extends LightUIElement {
private List<LightUIElement> children;
private List<LightUIElement> children = new ArrayList<LightUIElement>(1);
 
public LightUIContainer(final String id) {
super(id);
this.children = new ArrayList<LightUIElement>();
}
 
public LightUIContainer(final JSONObject json) {
40,18 → 39,18
 
public void addChild(final LightUIElement child) {
if (child == null) {
throw new IllegalArgumentException("Attempt to put null child in container, id:" + this.getId());
throw new IllegalArgumentException("Attempt to put a null child in container, id:" + this.getId());
}
child.setReadOnly(this.isReadOnly());
child.setParent(this);
this.children.add(child);
}
 
public void addChildren(final List<LightUIElement> children) {
if (children == null) {
throw new IllegalArgumentException("List null, id:" + this.getId());
}
for(final LightUIElement child: children){
for (final LightUIElement child : children) {
this.addChild(child);
}
}
66,13 → 65,11
}
 
public void removeChild(final LightUIElement child) {
if (this.children != null)
this.children.remove(child);
this.children.remove(child);
}
 
public void removeChild(final int index) {
if (this.children != null)
this.children.remove(index);
this.children.remove(index);
}
 
public LightUIElement getChild(final int index) {
80,10 → 77,7
}
 
public <T extends LightUIElement> T getChild(final int index, final Class<T> expectedClass) {
if (this.children != null)
return expectedClass.cast(this.children.get(index));
else
return null;
return expectedClass.cast(this.children.get(index));
}
 
public <T extends LightUIElement> T getFirstChild(final Class<T> expectedClass) {
94,16 → 88,11
}
 
public int getChildrenCount() {
if (this.children != null) {
return this.children.size();
} else {
return 0;
}
return this.children.size();
}
 
public void clear() {
if (this.children != null)
this.children.clear();
this.children.clear();
}
 
public boolean replaceChild(final LightUIElement pChild) {
130,29 → 119,55
return false;
}
 
public LightUIElement findChild(final String searchParam, final boolean byUUID) {
return this.findChild(searchParam, byUUID, LightUIElement.class);
}
 
public <T extends LightUIElement> T findChild(final String searchParam, final boolean byUUID, final Class<T> expectedClass) {
public <T extends LightUIElement> T findChildByID(final String id, final Class<T> expectedClass) {
final int childCount = this.getChildrenCount();
LightUIElement result = null;
for (int i = 0; i < childCount; i++) {
final LightUIElement child = this.getChild(i);
if (byUUID) {
if (child.getUUID().equals(searchParam)) {
result = child;
break;
}
 
if (child.getId().equals(id)) {
result = child;
break;
} else {
if (child.getId().equals(searchParam)) {
result = child;
break;
 
if (child instanceof LightUIContainer) {
result = ((LightUIContainer) child).findChildByID(id, expectedClass);
if (result != null) {
break;
}
}
 
if (child instanceof LightUITable) {
result = ((LightUITable) child).findElementByID(id, expectedClass);
if (result != null) {
break;
}
}
}
}
 
if (result != null) {
if (expectedClass.isAssignableFrom(result.getClass())) {
return expectedClass.cast(result);
} else {
throw new InvalidClassException(expectedClass.getName(), result.getClass().getName(), result.getId());
}
}
return null;
}
 
public <T extends LightUIElement> T findChildByUUID(final String uuid, final Class<T> expectedClass) {
final int childCount = this.getChildrenCount();
LightUIElement result = null;
for (int i = 0; i < childCount; i++) {
final LightUIElement child = this.getChild(i);
if (child.getUUID().equals(uuid)) {
result = child;
break;
}
 
if (child instanceof LightUIContainer) {
result = ((LightUIContainer) child).findChild(searchParam, byUUID, expectedClass);
result = ((LightUIContainer) child).findChildByUUID(uuid, expectedClass);
if (result != null) {
break;
}
159,7 → 174,7
}
 
if (child instanceof LightUITable) {
result = ((LightUITable) child).findElement(searchParam, byUUID, expectedClass);
result = ((LightUITable) child).findElementByUUID(uuid, expectedClass);
if (result != null) {
break;
}
209,7 → 224,8
 
this.clear();
final LightUIContainer container = (LightUIContainer) element;
this.children = new ArrayList<LightUIElement>(container.children);
System.err.println("LightUIContainer.copy() warning children not copied");
this.children.addAll(container.children);
 
for (final LightUIElement child : this.children) {
child.setParent(this);
238,10 → 254,9
@Override
public JSONObject toJSON() {
final JSONObject result = super.toJSON();
if (this.children == null || !this.children.isEmpty()) {
if (!this.children.isEmpty()) {
result.put("childs", JSONConverter.getJSON(this.children));
}
 
return result;
}
 
250,11 → 265,10
super.fromJSON(json);
this.clear();
 
final JSONArray jsonElements = (JSONArray) JSONConverter.getParameterFromJSON(json, "childs", JSONArray.class);
this.children = new ArrayList<LightUIElement>();
final JSONArray jsonElements = JSONConverter.getParameterFromJSON(json, "childs", JSONArray.class);
if (jsonElements != null) {
for (final Object o : jsonElements) {
final JSONObject jsonElement = (JSONObject) JSONConverter.getObjectFromJSON(o, JSONObject.class);
final JSONObject jsonElement = JSONConverter.getObjectFromJSON(o, JSONObject.class);
if (jsonElement == null) {
throw new IllegalArgumentException("null element in json parameter");
}
/trunk/OpenConcerto/src/org/openconcerto/ui/light/LightUIFileUpload.java
48,20 → 48,13
}
 
@Override
public LightUIElement clone() {
return new LightUIFileUpload(this);
}
 
@Override
protected void copy(LightUIElement element) {
super.copy(element);
if (!(element instanceof LightUIFileUpload)) {
throw new InvalidClassException(this.getClassName(), element.getClassName(), element.getId());
}
 
final LightUIFileUpload files = (LightUIFileUpload) element;
this.sendFileUrl = files.sendFileUrl;
 
}
 
@Override
/trunk/OpenConcerto/src/org/openconcerto/ui/light/LightUILine.java
91,11 → 91,6
}
 
@Override
public LightUIElement clone() {
return new LightUILine(this);
}
 
@Override
protected void copy(LightUIElement element) {
super.copy(element);
 
128,8 → 123,8
@Override
public void fromJSON(final JSONObject json) {
super.fromJSON(json);
this.elementPadding = (Integer) JSONConverter.getParameterFromJSON(json, "element-padding", Integer.class);
this.elementMargin = (Integer) JSONConverter.getParameterFromJSON(json, "element-margin", Integer.class);
this.gridAlignment = (Integer) JSONConverter.getParameterFromJSON(json, "grid-alignment", Integer.class, ALIGN_GRID);
this.elementPadding = JSONConverter.getParameterFromJSON(json, "element-padding", Integer.class);
this.elementMargin = JSONConverter.getParameterFromJSON(json, "element-margin", Integer.class);
this.gridAlignment = JSONConverter.getParameterFromJSON(json, "grid-alignment", Integer.class, ALIGN_GRID);
}
}
/trunk/OpenConcerto/src/org/openconcerto/ui/light/LightUITextField.java
33,11 → 33,6
}
 
@Override
public LightUIElement clone() {
return new LightUITextField(this);
}
 
@Override
public JSONToLightUIConvertor getConvertor() {
return new JSONToLightUIConvertor() {
@Override
49,7 → 44,10
 
@Override
public Object getValueForContext() {
return (this.getValue() == null) ? null : ((this.getValue().trim().equals("")) ? null : this.getValue());
if (this.getValue() == null || this.getValue().trim().isEmpty()) {
return null;
}
return this.getValue();
}
 
@Override
/trunk/OpenConcerto/src/org/openconcerto/ui/light/LightUIElement.java
628,24 → 628,24
}
 
public void dump(PrintStream out, final int depth) {
final String type = this.getTypeAsString();
String valueType = "?";
final String typeAsString = this.getTypeAsString();
String valueTypeAsString = "?";
if (this.valueType != null) {
if (this.valueType == VALUE_TYPE_STRING) {
valueType = "string";
valueTypeAsString = "string";
} else if (this.valueType == VALUE_TYPE_INTEGER) {
valueType = "int";
valueTypeAsString = "int";
} else if (this.valueType == VALUE_TYPE_REF) {
valueType = "ref";
valueTypeAsString = "ref";
} else if (this.valueType == VALUE_TYPE_LIST) {
valueType = "list";
valueTypeAsString = "list";
} else if (this.valueType == VALUE_TYPE_DECIMAL) {
valueType = "decimal";
valueTypeAsString = "decimal";
}
}
 
String str = "LightUIElement" + "class:" + this.getClassName() + " type:" + type + " id:" + this.id + " uuid:" + this.UUID + " w:" + this.gridWidth + " fill:" + this.fillWidth;
str += " value:" + this.value + "(" + valueType + ")";
String str = "LightUIElement" + "class:" + this.getClassName() + " type:" + typeAsString + " id:" + this.id + " uuid:" + this.UUID + " w:" + this.gridWidth + " fill:" + this.fillWidth;
str += " value:" + this.value + "(" + valueTypeAsString + ")";
if (this.valueRange != null) {
str += "range: " + this.valueRange;
}
847,11 → 847,6
}
 
@Override
public LightUIElement clone() {
return new LightUIElement(this);
}
 
@Override
public String toString() {
return super.toString() + " " + this.id;
}
/trunk/OpenConcerto/src/org/openconcerto/ui/light/LightUIFrame.java
23,10 → 23,10
import net.minidev.json.JSONObject;
 
public class LightUIFrame extends LightUIContainer {
private static final String ACTIVE = "active";
private static final String TITLE_PANEL = "title-panel";
private static final String FOOTER_PANEL = "footer-panel";
private static final String CHILDREN_FRAME = "children-frame";
private static final String KEY_ACTIVE = "active";
private static final String KEY_TITLE_PANEL = "title-panel";
private static final String KEY_FOOTER_PANEL = "footer-panel";
private static final String KEY_CHILDREN_FRAME = "children-frame";
 
private Boolean active = false;
private LightUIPanel titlePanel = null;
155,16 → 155,26
}
 
@Override
public <T extends LightUIElement> T findChild(String searchParam, boolean byUUID, Class<T> childClass) {
final T result = super.findChild(searchParam, byUUID, childClass);
public <T extends LightUIElement> T findChildByID(String searchParam, Class<T> childClass) {
final T result = super.findChildByID(searchParam, childClass);
if (result != null) {
return result;
} else {
return this.footerPanel.findChild(searchParam, byUUID, childClass);
return this.footerPanel.findChildByID(searchParam, childClass);
}
}
 
@Override
public <T extends LightUIElement> T findChildByUUID(String searchParam, Class<T> childClass) {
final T result = super.findChildByUUID(searchParam, childClass);
if (result != null) {
return result;
} else {
return this.footerPanel.findChildByUUID(searchParam, childClass);
}
}
 
@Override
public void setReadOnly(boolean readOnly) {
super.setReadOnly(readOnly);
this.footerPanel.setReadOnly(readOnly);
176,9 → 186,8
* ".main.panel"
*
* @param child The panel which will replace the main panel
* @throws InvalidClassException
*/
public void addChild(final LightUIElement child) throws InvalidClassException {
public void addChild(final LightUIElement child) {
if (!(child instanceof LightUIPanel)) {
throw new InvalidClassException(LightUIPanel.class.getName(), child.getClassName(), child.getId());
}
194,9 → 203,8
*
* @param index No importance
* @param child The panel which will replace the main panel
* @throws InvalidClassException
*/
public void insertChild(int index, LightUIElement child) throws InvalidClassException {
public void insertChild(int index, LightUIElement child) {
if (!(child instanceof LightUIPanel)) {
throw new InvalidClassException(LightUIPanel.class.getName(), child.getClassName(), child.getId());
}
231,22 → 239,15
}
 
@Override
public LightUIElement clone() {
final LightUIFrame clone = new LightUIFrame(this);
clone.getFooterPanel().setParent(clone);
return clone;
}
 
@Override
public JSONObject toJSON() {
final JSONObject json = super.toJSON();
if (this.active) {
json.put(ACTIVE, true);
json.put(KEY_ACTIVE, true);
}
if (this.titlePanel != null) {
json.put(TITLE_PANEL, this.titlePanel.toJSON());
json.put(KEY_TITLE_PANEL, this.titlePanel.toJSON());
}
json.put(FOOTER_PANEL, this.footerPanel.toJSON());
json.put(KEY_FOOTER_PANEL, this.footerPanel.toJSON());
return json;
}
 
253,19 → 254,19
@Override
public void fromJSON(final JSONObject json) {
super.fromJSON(json);
this.active = JSONConverter.getParameterFromJSON(json, ACTIVE, Boolean.class, false);
this.active = JSONConverter.getParameterFromJSON(json, KEY_ACTIVE, Boolean.class, false);
 
final JSONObject jsonTitlePanel = JSONConverter.getParameterFromJSON(json, TITLE_PANEL, JSONObject.class);
final JSONObject jsonTitlePanel = JSONConverter.getParameterFromJSON(json, KEY_TITLE_PANEL, JSONObject.class);
if (jsonTitlePanel != null) {
this.titlePanel.fromJSON(jsonTitlePanel);
}
 
final JSONObject jsonFooterPanel = (JSONObject) JSONConverter.getParameterFromJSON(json, FOOTER_PANEL, JSONObject.class, null);
final JSONObject jsonFooterPanel = JSONConverter.getParameterFromJSON(json, KEY_FOOTER_PANEL, JSONObject.class, null);
if (jsonFooterPanel != null) {
this.footerPanel.fromJSON(jsonFooterPanel);
}
 
final JSONArray jsonChildrenFrame = (JSONArray) JSONConverter.getParameterFromJSON(json, CHILDREN_FRAME, JSONArray.class, null);
final JSONArray jsonChildrenFrame = JSONConverter.getParameterFromJSON(json, KEY_CHILDREN_FRAME, JSONArray.class, null);
this.childrenFrame = new ArrayList<LightUIFrame>();
if (jsonChildrenFrame != null) {
for (final Object objJsonFrame : jsonChildrenFrame) {
/trunk/OpenConcerto/src/org/openconcerto/ui/light/LightUIPanel.java
134,10 → 134,18
}
 
@Override
public void addChild(final LightUIElement line) {
if (!(line instanceof LightUILine)) {
throw new IllegalArgumentException("Only LightUILine are accepted in LightUIPanel");
public void addChild(final LightUIElement e) {
LightUILine line;
if (e instanceof LightUILine) {
line = (LightUILine) e;
} else {
line = new LightUILine();
line.addChild(e);
}
addLine(line);
}
 
public void addLine(final LightUILine line) {
// Ensure uniqueness of line id
line.setId(LightUILine.createId(this));
super.addChild(line);
175,7 → 183,13
this.addSpacer(out, depth);
out.println("Title : " + this.title);
this.addSpacer(out, depth);
out.println("v-scroll : " + this.isVerticallyScrollable() + " title-color: " + this.titleColor.toString() + " bg-title-color: " + this.titleBackgroundColor.toString());
if (this.titleColor != null) {
out.print(" title-color: " + this.titleColor.toString());
}
if (this.titleBackgroundColor != null) {
out.print(" bg-title-color: " + this.titleBackgroundColor.toString());
}
out.println("v-scroll : " + this.isVerticallyScrollable());
super.dump(out, depth);
this.addSpacer(out, depth);
out.println("------------------------");
183,7 → 197,7
 
@Override
public void _setValueFromContext(final Object value) {
final JSONObject jsonContext = (JSONObject) JSONConverter.getObjectFromJSON(value, JSONObject.class);
final JSONObject jsonContext = JSONConverter.getObjectFromJSON(value, JSONObject.class);
 
if (jsonContext == null) {
System.err.println("LightUIPanel.setValueFromContext() - json is null for this panel: " + this.getId());
211,11 → 225,6
}
 
@Override
public LightUIElement clone() {
return new LightUIPanel(this);
}
 
@Override
public JSONObject toJSON() {
final JSONObject result = super.toJSON();
if (this.title != null) {
230,7 → 239,6
if (!this.controlers.isEmpty()) {
result.put("controlers", JSONConverter.getJSON(this.controlers));
}
 
return result;
}
 
237,15 → 245,15
@Override
public void fromJSON(final JSONObject json) {
super.fromJSON(json);
this.title = (String) JSONConverter.getParameterFromJSON(json, "title", String.class, null);
this.titleColor = (Color) JSONConverter.getParameterFromJSON(json, "title-color", Color.class, null);
this.titleBackgroundColor = (Color) JSONConverter.getParameterFromJSON(json, "title-bgcolor", Color.class, null);
this.title = JSONConverter.getParameterFromJSON(json, "title", String.class, null);
this.titleColor = JSONConverter.getParameterFromJSON(json, "title-color", Color.class, null);
this.titleBackgroundColor = JSONConverter.getParameterFromJSON(json, "title-bgcolor", Color.class, null);
 
final JSONArray jsonControlers = (JSONArray) JSONConverter.getParameterFromJSON(json, "controlers", JSONArray.class);
final JSONArray jsonControlers = JSONConverter.getParameterFromJSON(json, "controlers", JSONArray.class);
if (jsonControlers != null) {
final int controlersSize = jsonControlers.size();
for (int i = 0; i < controlersSize; i++) {
final JSONObject jsonControler = (JSONObject) JSONConverter.getObjectFromJSON(jsonControlers.get(i), JSONObject.class);
final JSONObject jsonControler = JSONConverter.getObjectFromJSON(jsonControlers.get(i), JSONObject.class);
this.controlers.add(new LightControler((JSONObject) jsonControler));
}
}
/trunk/OpenConcerto/src/org/openconcerto/ui/light/LightUIButton.java
16,12 → 16,13
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
 
import net.minidev.json.JSONObject;
 
public class LightUIButton extends LightUIElement {
private List<ActionListener> clickListeners = new ArrayList<ActionListener>();
private transient List<ActionListener> clickListeners = new ArrayList<ActionListener>();
 
public LightUIButton(final JSONObject json) {
super(json);
32,11 → 33,27
this.init(TYPE_BUTTON);
}
 
public LightUIButton(final String id, String text) {
super(id);
this.init(TYPE_BUTTON);
this.setLabel(text);
}
 
protected LightUIButton(final String id, final int buttonType) {
super(id);
this.init(buttonType);
}
 
protected LightUIButton(final String id, final int buttonType, String text) {
super(id);
this.init(buttonType);
this.setLabel(text);
}
 
public void setText(String text) {
this.setLabel(text);
}
 
private void init(final int buttonType) {
this.setType(buttonType);
}
53,6 → 70,10
this.clickListeners.clear();
}
 
public List<ActionListener> getClickListeners() {
return Collections.unmodifiableList(this.clickListeners);
}
 
public void fireClick() {
for (final ActionListener listener : this.clickListeners) {
listener.actionPerformed(new ActionEvent(this, 1, "click"));
/trunk/OpenConcerto/src/org/openconcerto/ui/light/LightUITextArea.java
54,11 → 54,6
}
 
@Override
public LightUIElement clone() {
return new LightUITextArea(this);
}
 
@Override
protected void copy(final LightUIElement element) {
super.copy(element);
if (!(element instanceof LightUITextArea)) {
76,7 → 71,10
 
@Override
public Object getValueForContext() {
return (this.getValue() == null) ? null : ((this.getValue().trim().equals("")) ? null : this.getValue());
if (this.getValue() == null || this.getValue().trim().isEmpty()) {
return null;
}
return this.getValue();
}
 
@Override
89,7 → 87,7
@Override
public void fromJSON(final JSONObject json) {
super.fromJSON(json);
final Integer jsonValues = (Integer) JSONConverter.getParameterFromJSON(json, "nbline", Integer.class);
final Integer jsonValues = JSONConverter.getParameterFromJSON(json, "nbline", Integer.class);
this.nbLine = jsonValues.intValue();
}
 
/trunk/OpenConcerto/src/org/openconcerto/ui/light/ColumnSpec.java
74,6 → 74,11
this.maxWidth = maxWidth;
}
 
public ColumnSpec(final String id, final Class<?> valueClass, final String columnName, final Object defaultValue) {
this.init(id, valueClass, columnName, defaultValue, false, null);
this.setDefaultPrefs();
}
 
public ColumnSpec(final String id, final Class<?> valueClass, final String columnName, final Object defaultValue, final boolean editable, final LightUIElement editors) {
this.init(id, valueClass, columnName, defaultValue, editable, editors);
this.setDefaultPrefs();
/trunk/OpenConcerto/src/org/openconcerto/ui/light/LightUIImage.java
16,9 → 16,9
import net.minidev.json.JSONObject;
 
public class LightUIImage extends LightUIElement {
 
public LightUIImage(final String id, final String path) {
super(id);
 
this.setType(LightUIElement.TYPE_IMAGE);
this.setValue(path);
}
41,8 → 41,4
};
}
 
@Override
public LightUIElement clone() {
return new LightUIImage(this);
}
}
/trunk/OpenConcerto/src/org/openconcerto/ui/light/LightUIHourEditor.java
26,6 → 26,21
super(json);
}
 
@Override
public void fromJSON(JSONObject json) {
super.fromJSON(json);
this.hour = ((Number) json.get("hour")).intValue();
this.minute = ((Number) json.get("minute")).intValue();
}
 
@Override
public JSONObject toJSON() {
JSONObject o = super.toJSON();
o.put("hour", hour);
o.put("minute", minute);
return o;
}
 
public LightUIHourEditor(final String id, int hour, int minute) {
super(id);
this.hour = hour;
32,6 → 47,7
this.minute = minute;
this.setType(TYPE_HOUR_EDITOR);
this.setValueType(LightUIElement.VALUE_TYPE_INTEGER);
this.setValue(String.valueOf(getIntVal()));
}
 
public LightUIHourEditor(LightUIHourEditor lightUIHourEditor) {
38,6 → 54,7
super(lightUIHourEditor);
this.hour = lightUIHourEditor.hour;
this.minute = lightUIHourEditor.minute;
this.setValue(String.valueOf(getIntVal()));
}
 
public int getHour() {
68,18 → 85,20
 
@Override
public Object getValueForContext() {
return this.hour + 60 * this.minute;
return getIntVal();
}
 
public int getIntVal() {
return this.hour * 60 + this.minute;
}
 
@Override
public void _setValueFromContext(Object value) {
final Integer strValue = (Integer) JSONConverter.getObjectFromJSON(value, Integer.class);
final Integer strValue = JSONConverter.getObjectFromJSON(value, Integer.class);
this.hour = strValue / 60;
this.minute = strValue % 60;
// For JSON
this.setValue(String.valueOf(strValue));
}
 
@Override
public LightUIElement clone() {
return new LightUIHourEditor(this);
}
}
/trunk/OpenConcerto/src/org/openconcerto/ui/light/LightUICheckBox.java
59,11 → 59,6
}
 
@Override
public LightUIElement clone() {
return new LightUICheckBox(this);
}
 
@Override
public Object getValueForContext() {
return this.isChecked();
}
/trunk/OpenConcerto/src/org/openconcerto/ui/light/LightUITable.java
45,7 → 45,7
private Boolean autoSelectFirstLine = true;
private TableSpec tableSpec = null;
 
private List<ActionListener> selectionListeners = new ArrayList<ActionListener>();
private transient List<ActionListener> selectionListeners = new ArrayList<ActionListener>();
 
// Nombre de ligne à afficher par Row
private int linePerRow = 1;
246,6 → 246,7
return selectedRows;
}
 
@Override
public final boolean replaceChild(final LightUIElement pChild) {
pChild.setReadOnly(this.isReadOnly());
 
280,11 → 281,47
return false;
}
 
public final LightUIElement findElement(final String searchParam, final boolean byUUID) {
return this.findElement(searchParam, byUUID, LightUIElement.class);
public final <T extends LightUIElement> T findElementByID(final String searchParam, final Class<T> objectClass) {
if (this.hasRow()) {
 
for (int i = 0; i < this.getRowsCount(); i++) {
final Row row = this.getRow(i);
final List<Object> rowValues = row.getValues();
for (final Object value : rowValues) {
if (value instanceof LightUIContainer) {
final LightUIContainer panel = (LightUIContainer) value;
final T element = panel.findChildByID(searchParam, objectClass);
if (element != null) {
return element;
}
} else if (value instanceof LightUIElement) {
final LightUIElement element = (LightUIElement) value;
 
if (element.getId().equals(searchParam)) {
if (objectClass.isAssignableFrom(element.getClass())) {
return objectClass.cast(element);
} else {
throw new IllegalArgumentException(
"Element found at is not an instance of " + objectClass.getName() + ", element class: " + element.getClass().getName() + " element ID: " + element.getId());
}
}
 
if (element instanceof LightUITable) {
final T resultElement = ((LightUITable) element).findElementByID(searchParam, objectClass);
if (resultElement != null) {
return resultElement;
}
}
}
}
}
} else {
System.out.println("LightUITable.findElementByID() - No rows for table: " + this.getId());
}
return null;
}
 
public final <T extends LightUIElement> T findElement(final String searchParam, final boolean byUUID, final Class<T> objectClass) {
public final <T extends LightUIElement> T findElementByUUID(final String searchParam, final Class<T> objectClass) {
if (this.hasRow()) {
 
for (int i = 0; i < this.getRowsCount(); i++) {
293,34 → 330,24
for (final Object value : rowValues) {
if (value instanceof LightUIContainer) {
final LightUIContainer panel = (LightUIContainer) value;
final T element = panel.findChild(searchParam, byUUID, objectClass);
final T element = panel.findChildByUUID(searchParam, objectClass);
if (element != null) {
return element;
}
} else if (value instanceof LightUIElement) {
final LightUIElement element = (LightUIElement) value;
if (byUUID) {
if (element.getUUID().equals(searchParam)) {
if (objectClass.isAssignableFrom(element.getClass())) {
return objectClass.cast(element);
} else {
throw new IllegalArgumentException(
"Element found at is not an instance of " + objectClass.getName() + ", element class: " + element.getClass().getName() + " element ID: " + element.getId());
}
 
if (element.getUUID().equals(searchParam)) {
if (objectClass.isAssignableFrom(element.getClass())) {
return objectClass.cast(element);
} else {
throw new IllegalArgumentException(
"Element found at is not an instance of " + objectClass.getName() + ", element class: " + element.getClass().getName() + " element ID: " + element.getId());
}
} else {
if (element.getId().equals(searchParam)) {
if (objectClass.isAssignableFrom(element.getClass())) {
return objectClass.cast(element);
} else {
throw new IllegalArgumentException(
"Element found at is not an instance of " + objectClass.getName() + ", element class: " + element.getClass().getName() + " element ID: " + element.getId());
}
}
}
 
if (element instanceof LightUITable) {
final T resultElement = ((LightUITable) element).findElement(searchParam, byUUID, objectClass);
final T resultElement = ((LightUITable) element).findElementByUUID(searchParam, objectClass);
if (resultElement != null) {
return resultElement;
}
329,7 → 356,7
}
}
} else {
System.out.println("LightUITable.getElementById() - No rows for table: " + this.getId());
System.out.println("LightUITable.findElementByUUID() - No rows for table: " + this.getId());
}
return null;
}
530,7 → 557,11
}
}
} else {
throw new IllegalArgumentException("Impossible to find row: " + rowId.toString());
final List<Number> ids = new ArrayList<Number>(size);
for (int j = 0; j < size; j++) {
ids.add(this.getRow(j).getId());
}
throw new IllegalArgumentException("Impossible to find row: " + rowId.toString() + " known table row ids :" + ids);
}
}
}
539,11 → 570,6
}
 
@Override
public LightUIElement clone() {
return new LightUITable(this);
}
 
@Override
public JSONObject toJSON() {
final JSONObject json = super.toJSON();
if (this.allowSelection) {
575,7 → 601,7
this.autoSelectFirstLine = JSONConverter.getParameterFromJSON(json, AUTO_SELECT_FIRST_LINE, Boolean.class, true);
this.linePerRow = JSONConverter.getParameterFromJSON(json, LINE_PER_ROW, Integer.class);
 
final JSONObject jsonRawContent = (JSONObject) JSONConverter.getParameterFromJSON(json, TABLE_SPEC, JSONObject.class);
final JSONObject jsonRawContent = JSONConverter.getParameterFromJSON(json, TABLE_SPEC, JSONObject.class);
 
if (jsonRawContent != null) {
this.tableSpec = new TableSpec(jsonRawContent);
/trunk/OpenConcerto/src/org/openconcerto/ui/light/LightUIDropDownButton.java
33,11 → 33,6
}
 
@Override
public LightUIElement clone() {
return new LightUIDropDownButton(this);
}
 
@Override
public JSONToLightUIConvertor getConvertor() {
return new JSONToLightUIConvertor() {
@Override
/trunk/OpenConcerto/src/org/openconcerto/ui/light/LightUIButtonLink.java
16,6 → 16,7
import org.openconcerto.utils.CollectionUtils;
import org.openconcerto.utils.io.JSONConverter;
 
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
 
22,8 → 23,8
import net.minidev.json.JSONObject;
 
public class LightUIButtonLink extends LightUIElement {
private final static String OPEN_NEW_FRAME_KEY = "open-new-frame";
private final static String URL_PARAMETER_KEY = "url-parameter";
private static final String OPEN_NEW_FRAME_KEY = "open-new-frame";
private static final String URL_PARAMETER_KEY = "url-parameter";
 
private Boolean openNewFrame = false;
private Map<String, String> urlParameters = new HashMap<String, String>();
63,9 → 64,8
this.urlParameters.clear();
}
 
@Override
public LightUIElement clone() {
return new LightUIButtonLink(this);
public Map<String, String> getUrlParameters() {
return Collections.unmodifiableMap(urlParameters);
}
 
@Override
/trunk/OpenConcerto/src/org/openconcerto/ui/light/LightUIButtonUnmanaged.java
23,7 → 23,6
public LightUIButtonUnmanaged(final String id, final String label) {
super(id);
setType(LightUIElement.TYPE_BUTTON_UNMANAGED);
 
setGridWidth(1);
setLabel(label);
}
31,7 → 30,6
public LightUIButtonUnmanaged(final String id) {
super(id);
setType(LightUIElement.TYPE_BUTTON_UNMANAGED);
 
setGridWidth(1);
}
 
49,8 → 47,4
};
}
 
@Override
public LightUIElement clone() {
return new LightUIButtonUnmanaged(this);
}
}
/trunk/OpenConcerto/src/org/openconcerto/ui/light/RowSpec.java
13,19 → 13,20
package org.openconcerto.ui.light;
 
import org.openconcerto.utils.io.JSONAble;
 
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.List;
 
import org.openconcerto.utils.CollectionUtils;
import org.openconcerto.utils.io.JSONAble;
import org.openconcerto.utils.io.JSONConverter;
import net.minidev.json.JSONArray;
import net.minidev.json.JSONObject;
 
public class RowSpec implements Externalizable, JSONAble {
private static final String KEY_COLUMN_IDS = "column-ids";
private static final String KEY_TABLE_ID = "table-id";
private static final String KEY_CLASS = "class";
private String tableId;
private String[] columnIds;
 
60,27 → 61,24
 
@Override
public String toString() {
String r = "RowSpec:" + this.tableId + " : ";
for (int i = 0; i < this.columnIds.length; i++) {
if (i < this.columnIds.length - 1) {
r += this.columnIds[i] + ", ";
} else {
r += this.columnIds[i];
final StringBuilder b = new StringBuilder();
b.append("RowSpec:");
b.append(this.tableId);
b.append(" : ");
final int length = this.columnIds.length;
for (int i = 0; i < length; i++) {
b.append(this.columnIds[i]);
if (i < length - 1) {
b.append(", ");
}
}
return r;
return b.toString();
}
 
@Override
public void writeExternal(ObjectOutput out) throws IOException {
try {
out.writeUTF(this.tableId);
out.writeObject(this.columnIds);
 
} catch (Exception e) {
e.printStackTrace();
throw new IOException(e);
}
out.writeUTF(this.tableId);
out.writeObject(this.columnIds);
}
 
@Override
92,34 → 90,22
@Override
public JSONObject toJSON() {
final JSONObject result = new JSONObject();
result.put("class", "RowSpec");
result.put("table-id", this.tableId);
result.put("column-ids", this.columnIds);
result.put(KEY_CLASS, "RowSpec");
result.put(KEY_TABLE_ID, this.tableId);
result.put(KEY_COLUMN_IDS, this.columnIds);
return result;
}
 
@Override
public void fromJSON(final JSONObject json) {
this.tableId = (String) JSONConverter.getParameterFromJSON(json, "table-id", String.class);
 
final JSONArray jsonColumnIds = (JSONArray) json.get("column-ids");
if (jsonColumnIds != null) {
try {
this.columnIds = new String[jsonColumnIds.size()];
this.columnIds = CollectionUtils.castList((List<?>) jsonColumnIds, String.class).toArray(this.columnIds);
} catch (final Exception ex) {
throw new IllegalArgumentException("invalid value for 'possible-column-ids', List<String> expected");
}
}
 
if (!json.containsKey("table-id") || (json.get("table-id") instanceof String)) {
this.tableId = (String) json.get(KEY_TABLE_ID);
final JSONArray jsonColumnIds = (JSONArray) json.get(KEY_COLUMN_IDS);
if (!json.containsKey(KEY_COLUMN_IDS) || (json.get(KEY_COLUMN_IDS) instanceof JSONArray)) {
throw new IllegalArgumentException("value for 'value-type' not found or invalid");
}
if (!json.containsKey("column-ids") || (json.get("column-ids") instanceof JSONArray)) {
if (!json.containsKey(KEY_TABLE_ID) || (json.get(KEY_TABLE_ID) instanceof String)) {
throw new IllegalArgumentException("value for 'value-type' not found or invalid");
}
this.tableId = (String) json.get("table-id");
 
final int columnCount = jsonColumnIds.size();
this.columnIds = new String[columnCount];
for (int i = 0; i < columnCount; i++) {
/trunk/OpenConcerto/src/org/openconcerto/ui/light/LightUIListRow.java
50,10 → 50,6
return this.rowId;
}
 
public LightUIListRow clone() {
return new LightUIListRow(this);
}
 
@Override
public JSONObject toJSON() {
final JSONObject json = super.toJSON();
/trunk/OpenConcerto/src/org/openconcerto/ui/JDateTime.java
84,6 → 84,10
};
this.date.addValueListener(l);
this.time.addValueListener(l);
// set initial this.value
// can't rely on this.resetValue() below as it might not change this.date and this.time and
// thus might not trigger the listener.
updateValue();
 
this.setLayout(new GridBagLayout());
final GridBagConstraints c = new GridBagConstraints();
99,7 → 103,6
this.add(this.time, c);
 
this.resetValue();
updateValue();
}
 
protected void updateValue() {
/trunk/OpenConcerto/src/org/openconcerto/record/spec/RecordItemSpec.java
14,6 → 14,7
package org.openconcerto.record.spec;
 
import org.openconcerto.record.Constraint;
import org.openconcerto.record.ConstraintProperties;
import org.openconcerto.record.Constraints;
import org.openconcerto.record.Record;
import org.openconcerto.record.RecordRef;
42,6 → 43,7
private final boolean required;
private final Constraint isValid, isEmpty;
private final Map<String, Object> validProps;
private final Constraint validPropsConstraint;
private final boolean userMustCheck, userMustModify;
 
public RecordItemSpec(final String name, final Type type) {
71,6 → 73,7
this.required = required;
this.isValid = isValid == null ? Constraints.none() : isValid;
this.validProps = validProps == null ? Collections.<String, Object> emptyMap() : Collections.unmodifiableMap(new HashMap<String, Object>(validProps));
this.validPropsConstraint = Constraints.createFromProperties(this.validProps, type);
this.isEmpty = isEmpty == null ? Constraints.getDefaultEmpty() : isEmpty;
this.userMustCheck = userMustCheck;
this.userMustModify = userMustModify;
109,6 → 112,16
return this.validProps;
}
 
/**
* The constraint checking keys from {@link ConstraintProperties} in
* {@link #getValidProperties()}.
*
* @return the constraint.
*/
public final Constraint getValidPropertiesConstraint() {
return this.validPropsConstraint;
}
 
public final Constraint getEmptyConstraint() {
return this.isEmpty;
}
140,6 → 153,8
return EnumSet.of(Problem.VALIDITY);
}
}
if (!this.getValidPropertiesConstraint().check(obj))
return EnumSet.of(Problem.VALIDITY);
}
if (!this.getValidConstraint().check(obj))
return EnumSet.of(Problem.VALIDITY);
/trunk/OpenConcerto/src/org/openconcerto/record/Record.java
52,17 → 52,30
return this.items;
}
 
/**
* Return the passed item as a list.
*
* @param name the wanted item.
* @param clazz the wanted type.
* @return an immutable list, <code>null</code> if no item with the passed name exists in this,
* an empty list if the item's value is <code>null</code> or an empty list.
*/
public final <T> List<T> getAsList(final String name, Class<T> clazz) {
final Object val = this.getItems().get(name);
if (val == null)
return null;
if (val == null) {
if (this.getItems().containsKey(name))
return Collections.emptyList();
else
return null;
}
if (val instanceof List) {
for (final Object o : (List<?>) val) {
clazz.cast(o);
}
// safe since we return an immutable view
@SuppressWarnings("unchecked")
final List<T> res = (List<T>) val;
return res;
return Collections.unmodifiableList(res);
} else {
return Collections.singletonList(clazz.cast(val));
}
/trunk/OpenConcerto/src/org/openconcerto/record/ConstraintCombiner.java
Nouveau fichier
0,0 → 1,93
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.record;
 
import java.util.Collection;
 
public abstract class ConstraintCombiner {
 
public final Constraint combine(Constraint w1, Constraint w2) {
if (w1 == null)
return w2;
else
return this.combineNotNull(w1, w2);
}
 
protected abstract Constraint combineNotNull(Constraint w1, Constraint w2);
 
private static ConstraintCombiner AndCombiner = new ConstraintCombiner() {
@Override
protected Constraint combineNotNull(final Constraint c1, final Constraint c2) {
return new Constraint() {
@Override
public String getDeclarativeForm() {
return "(" + c1.getDeclarativeForm() + ") and (" + c2.getDeclarativeForm() + ")";
}
 
@Override
public boolean check(Object obj) {
return c1.check(obj) && c2.check(obj);
}
};
}
};
 
private static ConstraintCombiner OrCombiner = new ConstraintCombiner() {
@Override
protected Constraint combineNotNull(final Constraint c1, final Constraint c2) {
return new Constraint() {
@Override
public String getDeclarativeForm() {
return "(" + c1.getDeclarativeForm() + ") or (" + c2.getDeclarativeForm() + ")";
}
 
@Override
public boolean check(Object obj) {
return c1.check(obj) || c2.check(obj);
}
};
}
};
 
static private Constraint combine(Collection<Constraint> wheres, ConstraintCombiner c) {
Constraint res = null;
for (final Constraint w : wheres) {
res = c.combine(res, w);
}
return res;
}
 
static public Constraint or(Collection<Constraint> constraints) {
return combine(constraints, OrCombiner);
}
 
static public Constraint and(Collection<Constraint> constraints) {
return combine(constraints, AndCombiner);
 
}
 
static public Constraint not(final Constraint c1) {
return new Constraint() {
@Override
public String getDeclarativeForm() {
return "not (" + c1.getDeclarativeForm() + ")";
}
 
@Override
public boolean check(Object obj) {
return !c1.check(obj);
}
};
}
}
/trunk/OpenConcerto/src/org/openconcerto/record/RecordIO.java
13,6 → 13,8
package org.openconcerto.record;
 
import org.openconcerto.record.spec.Type;
 
import java.io.IOException;
import java.util.Set;
 
20,6 → 22,16
 
public Record fetch(final RecordKey key);
 
/**
* Fetch the record for the passed key.
*
* @param key the key.
* @param items which items to fetch, <code>null</code> meaning all, for {@link Type#RECORD} or
* {@link Type#RECORD_LIST} items join sub-item with '.' and for item names not only
* composed of <code>[a-zA-Z_0-9]</code> wrap them in double quotes, e.g. "ite
* m"."sub-item".
* @return the fetched record, <code>null</code> if none match.
*/
public Record fetch(final RecordKey key, final Set<String> items);
 
public Record insert(final Record r) throws IOException;
27,7 → 39,7
public void update(final Record r) throws IOException;
 
public Record copy(final RecordKey key) throws IOException;
 
public Record copy(final RecordKey key, final boolean forceFull) throws IOException;
 
public void delete(final RecordKey key) throws IOException;
/trunk/OpenConcerto/src/org/openconcerto/record/Constraints.java
13,8 → 13,23
package org.openconcerto.record;
 
import org.openconcerto.record.spec.Type;
import org.openconcerto.utils.CollectionUtils;
import org.openconcerto.utils.DecimalUtils;
import org.openconcerto.utils.NumberUtils;
import org.openconcerto.utils.checks.EmptyObjFromVO;
 
import java.math.BigDecimal;
import java.sql.Time;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
 
public final class Constraints {
 
static private final Constraint NONE = new Constraint() {
58,4 → 73,182
public static final Constraint getDefaultEmpty() {
return EMPTY;
}
 
private static final Pattern quotePattern = Pattern.compile("\"", Pattern.LITERAL);
private static final String quoteReplacement = Matcher.quoteReplacement("&quot;");
 
public static final String quote(final String s) {
return '"' + quotePattern.matcher(s).replaceAll(quoteReplacement) + '"';
}
 
public static final Constraint createFromProperties(final Map<String, Object> props, final Type type) {
if (props.isEmpty() || type == Type.BOOLEAN || type == Type.RECORD || type == Type.RECORD_LIST || type == Type.RECORD_REF || type == Type.RECORD_REF_LIST)
return none();
 
if (type == Type.STRING) {
return new PropsConstraintComparable<String>(props, String.class) {
 
private final Pattern regex;
 
{
final String regexp = (String) props.get(ConstraintProperties.REGEXP);
this.regex = regexp == null ? null : Pattern.compile(regexp);
}
 
@Override
protected void addDeclarativeChecks(List<String> res) {
super.addDeclarativeChecks(res);
final Number minSize = (Number) props.get(ConstraintProperties.MIN_SIZE);
if (minSize != null)
res.add("(string-length(.) >= " + minSize.intValue() + ")");
final Number maxSize = (Number) props.get(ConstraintProperties.MAX_SIZE);
if (maxSize != null)
res.add("(string-length(.) <= " + maxSize.intValue() + ")");
 
final String regexp = (String) props.get(ConstraintProperties.REGEXP);
if (regexp != null)
res.add("(matches(., " + quote(regexp) + "))");
}
 
@Override
public boolean checkCasted(String str) {
final Number minSize = (Number) props.get(ConstraintProperties.MIN_SIZE);
if (minSize != null && str.length() < minSize.intValue())
return false;
final Number maxSize = (Number) props.get(ConstraintProperties.MAX_SIZE);
if (maxSize != null && str.length() > maxSize.intValue())
return false;
 
if (this.regex != null && !this.regex.matcher(str).matches())
return false;
 
return super.checkCasted(str);
}
};
} else if (type == Type.DATETIME) {
return new PropsConstraintComparable<Date>(props, Date.class) {
@Override
protected String toString(Date v) {
return new java.sql.Timestamp(v.getTime()).toString();
}
};
} else if (type == Type.TIME) {
return new PropsConstraintComparable<Time>(props, Time.class);
} else if (type == Type.DECIMAL) {
return new PropsConstraintComparable<BigDecimal>(props, BigDecimal.class) {
 
@Override
protected String toString(BigDecimal v) {
return v.toPlainString();
}
 
@Override
public boolean checkCasted(BigDecimal n) {
final Number minSize = (Number) props.get(ConstraintProperties.MIN_SIZE);
if (minSize != null && DecimalUtils.intDigits(n) < minSize.intValue())
return false;
final Number maxSize = (Number) props.get(ConstraintProperties.MAX_SIZE);
if (maxSize != null && DecimalUtils.intDigits(n) > maxSize.intValue())
return false;
 
final Number decDigits = (Number) props.get(ConstraintProperties.DECIMAL_DIGITS);
if (decDigits != null && DecimalUtils.decimalDigits(n) > decDigits.intValue())
return false;
 
return super.checkCasted(n);
}
};
} else if (type == Type.INTEGER || type == Type.FLOAT) {
return new PropsConstraintNumber(props);
} else {
throw new IllegalArgumentException("Unknown type : " + type);
}
}
 
public static abstract class PropsConstraint<T> implements Constraint {
private final Map<String, Object> props;
private final Class<T> clazz;
 
private PropsConstraint(Map<String, Object> props, final Class<T> clazz) {
this.props = Collections.unmodifiableMap(new HashMap<>(props));
this.clazz = clazz;
}
 
public final Map<String, Object> getProps() {
return this.props;
}
 
protected final Class<T> getClazz() {
return this.clazz;
}
 
@Override
public final String getDeclarativeForm() {
final List<String> res = new ArrayList<>();
this.addDeclarativeChecks(res);
return CollectionUtils.join(res, " and ");
}
 
protected void addDeclarativeChecks(final List<String> res) {
this.addValueRangeChecks(res);
}
 
protected final void addValueRangeChecks(final List<String> res) {
final T minValue = this.clazz.cast(this.props.get(ConstraintProperties.MIN_VALUE));
if (minValue != null)
res.add("(. >= " + quote(toString(minValue)) + ")");
final T maxValue = this.clazz.cast(this.props.get(ConstraintProperties.MAX_VALUE));
if (maxValue != null)
res.add("(. <= " + quote(toString(maxValue)) + ")");
}
 
protected String toString(final T v) {
return v.toString();
}
 
@Override
public final boolean check(Object obj) {
return checkCasted(this.clazz.cast(obj));
}
 
protected boolean checkCasted(T obj) {
return checkValueRange(obj);
}
 
protected boolean checkValueRange(final T obj) {
final T minValue = this.clazz.cast(this.props.get(ConstraintProperties.MIN_VALUE));
if (minValue != null && compare(obj, minValue) < 0)
return false;
final T maxValue = this.clazz.cast(this.props.get(ConstraintProperties.MAX_VALUE));
if (maxValue != null && compare(obj, maxValue) > 0)
return false;
return true;
}
 
protected abstract int compare(final T obj1, final T obj2);
}
 
private static class PropsConstraintComparable<T extends Comparable<? super T>> extends PropsConstraint<T> {
 
private PropsConstraintComparable(Map<String, Object> props, final Class<T> clazz) {
super(props, clazz);
}
 
@Override
protected int compare(T obj1, T obj2) {
return obj1.compareTo(obj2);
}
}
 
private static class PropsConstraintNumber extends PropsConstraint<Number> {
 
private PropsConstraintNumber(Map<String, Object> props) {
super(props, Number.class);
}
 
@Override
protected int compare(Number obj1, Number obj2) {
return NumberUtils.compare(obj1, obj2);
}
}
}
/trunk/OpenConcerto/src/org/openconcerto/record/RecordManager.java
Nouveau fichier
0,0 → 1,67
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.record;
 
import org.openconcerto.utils.cc.ITransformer;
 
import java.io.IOException;
import java.util.Set;
 
public class RecordManager {
 
private ITransformer<String, RecordIO> ioProvider;
 
public RecordManager() {
}
 
public void setIOProvider(final ITransformer<String, RecordIO> ioProvider) {
this.ioProvider = ioProvider;
}
 
public RecordIO getIO(final String specName) {
return this.ioProvider.transformChecked(specName);
}
 
public final RecordIO getIO(final RecordRef ref) {
return this.getIO(ref.getSpec().getName());
}
 
public Record fetch(final RecordRef ref) {
return this.getIO(ref).fetch(ref.getKey());
}
 
public Record fetch(final RecordRef ref, final Set<String> items) {
return this.getIO(ref).fetch(ref.getKey(), items);
}
 
public Record insert(final Record r) throws IOException {
return this.getIO(r.getSpec()).insert(r);
}
 
public void update(final Record r) throws IOException {
this.getIO(r.getSpec()).update(r);
}
 
public Record copy(final RecordRef ref) throws IOException {
return this.getIO(ref).copy(ref.getKey());
}
 
public Record copy(final RecordRef ref, final boolean forceFull) throws IOException {
return this.getIO(ref).copy(ref.getKey(), forceFull);
}
 
public void delete(final RecordRef ref) throws IOException {
this.getIO(ref).delete(ref.getKey());
}
}
/trunk/OpenConcerto/src/org/openconcerto/sql/sqlobject/ITextArticleWithCompletion.java
23,7 → 23,6
import org.openconcerto.ui.component.text.TextComponent;
import org.openconcerto.utils.CompareUtils;
import org.openconcerto.utils.OrderedSet;
import org.openconcerto.utils.SwingWorker2;
import org.openconcerto.utils.cc.ITransformer;
import org.openconcerto.utils.checks.MutableValueObject;
import org.openconcerto.utils.model.DefaultIMutableListModel;
52,6 → 51,7
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.AbstractDocument;
399,7 → 399,7
this.searchStack.clear();
}
 
final SwingWorker2<List<IComboSelectionItem>, Object> worker = new SwingWorker2<List<IComboSelectionItem>, Object>() {
final SwingWorker<List<IComboSelectionItem>, Object> worker = new SwingWorker<List<IComboSelectionItem>, Object>() {
 
@Override
protected List<IComboSelectionItem> doInBackground() throws Exception {
/trunk/OpenConcerto/src/org/openconcerto/sql/sqlobject/IComboModel.java
15,7 → 15,6
 
import org.openconcerto.sql.model.SQLRow;
import org.openconcerto.sql.model.SQLRowAccessor;
import org.openconcerto.sql.model.SQLRowValues;
import org.openconcerto.sql.model.SQLSelect;
import org.openconcerto.sql.model.SQLTable;
import org.openconcerto.sql.model.SQLTableEvent;
31,7 → 30,7
import org.openconcerto.utils.CompareUtils;
import org.openconcerto.utils.RTInterruptedException;
import org.openconcerto.utils.StringUtils;
import org.openconcerto.utils.SwingWorker2;
import org.openconcerto.utils.Tuple2;
import org.openconcerto.utils.cc.ITransformer;
import org.openconcerto.utils.checks.EmptyChangeSupport;
import org.openconcerto.utils.checks.EmptyListener;
56,6 → 55,7
import java.util.regex.Pattern;
 
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import javax.swing.event.ListDataEvent;
import javax.swing.event.ListDataListener;
 
62,9 → 62,10
import net.jcip.annotations.GuardedBy;
 
/**
* A model that takes its values from a {@link ComboSQLRequest}. It listens to table changes, but
* can also be reloaded by calling {@link #fillCombo()}. It can be searched using
* {@link #search(SearchSpec)}. Like all Swing model, it ought too be manipulated in the EDT.
* A model that takes its values from a {@link ComboSQLRequest} and {@link #setNonDBItems(List)}. It
* listens to table changes, but can also be reloaded by calling {@link #fillCombo()}. It can be
* searched using {@link #search(SearchSpec)}. Like all Swing model, it ought too be manipulated in
* the EDT.
*
* @author Sylvain CUAZ
*/
71,6 → 72,12
public class IComboModel extends DefaultIMutableListModel<IComboSelectionItem> implements SQLTableModifiedListener, MutableValueObject<IComboSelectionItem>, EmptyObj, ISearchable {
 
private final ComboSQLRequest req;
// current filtered count in this model
@GuardedBy("EDT")
protected Integer nonDBCount = 0;
// superset of items that will eventually be in this model (after a doUpdateAll())
@GuardedBy("this")
private List<IComboSelectionItem> nonDBItems = Collections.emptyList();
 
private boolean filledOnce = false;
private ITransformer<List<IComboSelectionItem>, IComboSelectionItem> firstFillTransf = null;
84,8 → 91,12
private final EmptyChangeSupport emptySupp;
private final PropertyChangeSupport propSupp;
 
// est ce que la combo va se remplir, access must be synchronized
private SwingWorker2<?, ?> willUpdate;
// est ce que la combo va se remplir
@GuardedBy("this")
private SwingWorker<?, ?> willUpdate;
// how is the combo going to fill
@GuardedBy("this")
private FillMode willUpdateMode;
protected final List<Runnable> runnables;
// true from when the combo is filled with the sole "dots" item until it is loaded with actual
// items, no need to synchronize (EDT)
94,6 → 105,7
private int idToSelect;
 
// index des éléments par leurs IDs
@GuardedBy("EDT")
private Map<Integer, IComboSelectionItem> itemsByID;
 
@GuardedBy("this")
224,7 → 236,7
super.fireContentsChanged(source, index0, index1);
}
 
synchronized void setSleepState(SleepState newState) {
public synchronized void setSleepState(SleepState newState) {
assert SwingUtilities.isEventDispatchThread();
if (newState == SleepState.SLEEPING && !this.isSleepAllowed())
newState = SleepState.AWAKE;
294,7 → 306,22
this.requestDelay = delay;
}
 
public final void setNonDBItems(List<IComboSelectionItem> nonDBItems) {
this.setNonDBItems(nonDBItems, null);
}
 
/**
* Set the non DB items. This method is thread-safe.
*
* @param nonDBItems will replace all non DB items.
* @param r called after <code>nonDBItems</code> have been added, can be <code>null</code>.
*/
public synchronized final void setNonDBItems(List<IComboSelectionItem> nonDBItems, final Runnable r) {
this.nonDBItems = Collections.unmodifiableList(new ArrayList<>(nonDBItems));
this.fillCombo(r, FillMode.NO_DB);
}
 
/**
* Reload this combo. This method is thread-safe.
*/
public final void fillCombo() {
301,11 → 328,31
this.fillCombo(null, true);
}
 
public synchronized final void fillCombo(final Runnable r, final boolean readCache) {
public final void fillCombo(final Runnable r, final boolean readCache) {
this.fillCombo(r, readCache ? FillMode.DB_WITH_READ_CACHE : FillMode.DB_WITHOUT_READ_CACHE);
}
 
// in order of freshness
static private enum FillMode {
/**
* Refresh from DB.
*/
DB_WITHOUT_READ_CACHE,
/**
* Refresh from cache.
*/
DB_WITH_READ_CACHE,
/**
* Only change non-DB.
*/
NO_DB
}
 
private synchronized final void fillCombo(final Runnable r, final FillMode fillMode) {
// wholly synch otherwise we might get onScreen after the if
// and thus completely ignore that fillCombo()
if (this.isActive() || r != null) {
this.doUpdateAll(r, readCache);
this.doUpdateAll(r, fillMode);
} else {
this.isADirtyDrityGirl = true;
}
330,15 → 377,23
}
}
 
private void doUpdateAll(final Runnable r, final boolean readCache) {
private void doUpdateAll(final Runnable r, final FillMode requestedFillMode) {
log("entering doUpdateAll");
synchronized (this) {
this.isADirtyDrityGirl = false;
final FillMode fillMode;
final boolean firstFill = !this.filledOnce;
// déjà en train de se rafraîchir
if (this.willUpdate != null) {
this.willUpdate.cancel(true);
fillMode = requestedFillMode.compareTo(this.willUpdateMode) < 0 ? requestedFillMode : this.willUpdateMode;
} else {
updateAllBegun();
if (firstFill) {
fillMode = requestedFillMode == FillMode.NO_DB ? FillMode.DB_WITH_READ_CACHE : requestedFillMode;
} else {
fillMode = requestedFillMode;
}
}
// add the runnable to an attribute since the worker we are creating might be canceled
// and thus done() and r might never be called
349,15 → 404,23
final SearchSpec search = this.getSearch();
final List<String> searchQuery = this.getSearchQuery();
final Where searchForceInclude = this.getSearchForceInclude();
log("will call getComboItems(" + readCache + ", " + searchQuery + ", " + searchForceInclude + ")");
log("will call getComboItems(" + fillMode + ", " + searchQuery + ", " + searchForceInclude + ")");
// OK since immutable
final List<IComboSelectionItem> nonDBItems = this.nonDBItems;
// commencer l'update après, sinon modeToSelect == 0
final SwingWorker2<List<IComboSelectionItem>, Object> worker = new SwingWorker2<List<IComboSelectionItem>, Object>() {
final SwingWorker<Tuple2<Integer, List<IComboSelectionItem>>, Object> worker = new SwingWorker<Tuple2<Integer, List<IComboSelectionItem>>, Object>() {
 
@Override
protected List<IComboSelectionItem> doInBackground() throws InterruptedException {
protected Tuple2<Integer, List<IComboSelectionItem>> doInBackground() throws InterruptedException {
// attends 1 peu pour voir si on va pas être annulé
Thread.sleep(delay);
return SearchSpecUtils.filter(IComboModel.this.req.getComboItems(readCache, searchQuery, Locale.getDefault(), searchForceInclude), search);
final List<IComboSelectionItem> res = new ArrayList<>(nonDBItems.size() + 12);
res.addAll(SearchSpecUtils.filter(nonDBItems, search));
final int nonDBCount = res.size();
if (fillMode != FillMode.NO_DB) {
res.addAll(SearchSpecUtils.filter(IComboModel.this.req.getComboItems(fillMode == FillMode.DB_WITH_READ_CACHE, searchQuery, Locale.getDefault(), searchForceInclude), search));
}
return Tuple2.create(nonDBCount, res);
}
 
// Runs on the event-dispatching thread.
370,13 → 433,17
// une autre maj arrive
return;
 
final boolean firstFill = !IComboModel.this.filledOnce;
// store before removing since it can trigger a selection change
final int idToSelect = getWantedID();
List<IComboSelectionItem> items = null;
Tuple2<Integer, List<IComboSelectionItem>> countAndItems = null;
try {
items = this.get();
setAllItems(items);
countAndItems = this.get();
if (fillMode == FillMode.NO_DB) {
replaceItems(0, IComboModel.this.nonDBCount, countAndItems.get1());
} else {
setAllItems(countAndItems.get1());
}
IComboModel.this.nonDBCount = countAndItems.get0();
IComboModel.this.filledOnce = true;
} catch (InterruptedException e) {
// ne devrait pas arriver puisque done() appelée après doInBackground()
391,20 → 458,21
} finally {
// always clear willUpdate otherwise the combo can't recover
assert IComboModel.this.willUpdate == this;
IComboModel.this.setWillUpdate(null);
IComboModel.this.setWillUpdate(null, null);
}
// check if items could be retrieved
// TODO otherwise show the error to the user so he knows that items are
// stale and he could reload them
if (items != null) {
if (countAndItems != null) {
// restaurer l'état
// if there's only one item in the list and no previous ID to select
// and org.openconcerto.sql.sqlCombo.selectSoleItem=true,select the item
final boolean noSelection = idToSelect == SQLRow.NONEXISTANT_ID;
final List<IComboSelectionItem> items = getComboModel().getList();
if (items.size() == 1 && noSelection && Boolean.getBoolean("org.openconcerto.sql.sqlCombo.selectSoleItem"))
IComboModel.this.setSelectedItem(items.get(0));
IComboModel.this.setSelectedObject(items.get(0));
else if (noSelection && firstFill && getFirstFillSelection() != null)
IComboModel.this.setSelectedItem(getFirstFillSelection().transformChecked(items));
IComboModel.this.setSelectedObject(getFirstFillSelection().transformChecked(items));
// if the wanted ID has changed after we made the request, and we didn't
// get the it, retry
else if (!noSelection && getComboItem(idToSelect) == null && !CompareUtils.equals(getSearchForceInclude(), searchForceInclude))
419,7 → 487,7
}
}
};
this.setWillUpdate(worker);
this.setWillUpdate(worker, fillMode);
worker.execute();
}
}
435,20 → 503,35
this.getComboModel().setAllElements(items, false);
this.itemsByID.clear();
for (final IComboSelectionItem item : items)
this.itemsByID.put(item.getId(), item);
this.indexItem(item);
assert isSizeCoherent();
}
 
private void replaceItems(final int from, final int to, List<IComboSelectionItem> items) {
// don't change the selection, the caller will
this.getComboModel().replaceExclusive(from, to, items, false);
this.itemsByID.clear();
for (final IComboSelectionItem item : this.getComboModel().getList())
this.indexItem(item);
assert isSizeCoherent();
}
 
private void addItem(IComboSelectionItem item) {
this.getComboModel().addElement(item);
this.itemsByID.put(item.getId(), item);
indexItem(item);
assert isSizeCoherent();
}
 
private void removeItem(final int id) {
final IComboSelectionItem removed = this.itemsByID.remove(id);
if (removed != null)
this.getComboModel().removeElement(removed);
private void indexItem(IComboSelectionItem item) {
final IComboSelectionItem prev = this.itemsByID.put(item.getId(), item);
if (prev != null)
throw new IllegalStateException("Duplicate IDs : " + prev + " and " + item);
}
 
private boolean isSizeCoherent() {
return this.itemsByID.size() == this.getComboModel().getSize();
}
 
private IComboSelectionItem getComboItem(int id) {
assert SwingUtilities.isEventDispatchThread();
return this.itemsByID.get(id);
459,30 → 542,6
return privateItem == null ? null : new IComboSelectionItem(privateItem);
}
 
// refresh, delete or add the passed row
private void reloadComboItem(final int id, final IComboSelectionItem nItem) {
assert SwingUtilities.isEventDispatchThread();
if (nItem == null) {
removeItem(id);
} else {
final IComboSelectionItem item = this.getComboItem(id);
// does this combo currently displays id
if (item != null) {
// before replace() which empties the selection
final boolean selectedID = this.getSelectedId() == id;
this.getComboModel().replace(item, nItem);
this.itemsByID.put(id, nItem);
if (selectedID) {
// selectedItem is NOT part of the items, even for non-editable combos
this.setValue(id);
}
} else {
// don't know if and where to put the new item, so call fillCombo()
this.fillCombo();
}
}
}
 
private final void itemsChanged() {
final List<IComboSelectionItem> newVal = this.getList();
this.propSupp.firePropertyChange("items", null, newVal);
538,7 → 597,7
* @return the selected item (with a non-<code>null</code> label).
*/
public final IComboSelectionItem getSelectedValue() {
return this.getSelectedItem();
return this.getSelectedObject();
}
 
public final SQLTable getForeignTable() {
573,9 → 632,10
*/
public final int getSelectedId() {
final IComboSelectionItem o = this.getSelectedValue();
if (o != null && o.getId() >= SQLRow.MIN_VALID_ID)
if (o != null) {
assert o.getId() != SQLRow.NONEXISTANT_ID;
return o.getId();
else {
} else {
return SQLRow.NONEXISTANT_ID;
}
}
622,7 → 682,7
}
log("values are obsolete: wantedID = " + id);
} else if (id == SQLRow.NONEXISTANT_ID) {
this.setSelectedItem(null);
this.setSelectedObject(null);
log("NONEXISTANT_ID: setSelectedItem(null)");
} else {
final IComboSelectionItem item = this.getComboItem(id);
676,9 → 736,9
newItem.setFlag(IComboSelectionItem.ERROR_FLAG);
}
this.addItem(newItem);
this.setSelectedItem(newItem);
this.setSelectedObject(newItem);
} else {
this.setSelectedItem(item);
this.setSelectedObject(item);
}
}
}
767,33 → 827,17
 
// *** une table que nous affichons a changé
 
private boolean tableOnlyOnce() {
final SQLRowValues graphToFetch = this.req.getGraphToFetch();
for (final SQLRowValues item : graphToFetch.getGraph().getItems()) {
if (item != graphToFetch && item.getTable() == graphToFetch.getTable()) {
return false;
}
}
return true;
}
 
@Override
public void tableModified(SQLTableEvent evt) {
final int id = evt.getId();
if (id >= SQLRow.MIN_VALID_ID && this.getForeignTable().equals(evt.getTable()) && tableOnlyOnce()) {
// MAYBE SwingWorker à la fillCombo()
final IComboSelectionItem nItem = SearchSpecUtils.filterOne(this.req.getComboItem(id), getSearch());
SwingThreadUtils.invoke(new Runnable() {
@Override
public void run() {
reloadComboItem(id, nItem);
}
});
} else {
// if multiple rows were changed or if one row can affect multiple combo items (e.g.
// displaying mission and its previous date)
this.fillCombo();
}
/*
* Even when we know for sure that this event can only affect one item (i.e. the request
* only contains evt.getTable() as its primary table -- not MISSION and
* MISSION.ID_PREVIOUS), we cannot just call fillCombo() with the passed ID since every call
* cancels the previous one ; which only works when all calls do the same thing (e.g. we
* can't cancel a call to update ID 12 when a call to update ID 13 arrives). Ideally a queue
* would be needed, just like for ITableModel.
*/
this.fillCombo();
}
 
// *** search
811,8 → 855,9
return this.getSearch() != null && !this.getSearch().isEmpty();
}
 
private synchronized void setWillUpdate(SwingWorker2<?, ?> w) {
private synchronized void setWillUpdate(SwingWorker<?, ?> w, FillMode fillMode) {
this.willUpdate = w;
this.willUpdateMode = fillMode;
this.propSupp.firePropertyChange("willUpdate", null, this.willUpdate);
if (this.willUpdate == null) {
assert SwingUtilities.isEventDispatchThread() : "The end of an update should be in the EDT to be able change swing related attributes";
/trunk/OpenConcerto/src/org/openconcerto/sql/sqlobject/JUniqueTextField.java
69,7 → 69,7
*/
public class JUniqueTextField extends JPanel implements ValueWrapper<String>, Documented, TextComponent, RowItemViewComponent, SQLComponentItem, MouseListener {
 
public static int RETRY_COUNT = 5;
public static int RETRY_COUNT = 50;
public static int SLEEP_WAIT_MS = 200;
 
public static final boolean exists(final SQLField f, final String t, final Number idToExclude, final boolean withCache) throws RTInterruptedException {
/trunk/OpenConcerto/src/org/openconcerto/sql/sqlobject/ITextWithCompletion.java
22,7 → 22,6
import org.openconcerto.sql.request.ComboSQLRequest;
import org.openconcerto.ui.component.text.TextComponent;
import org.openconcerto.utils.OrderedSet;
import org.openconcerto.utils.SwingWorker2;
import org.openconcerto.utils.cc.ITransformer;
import org.openconcerto.utils.checks.MutableValueObject;
import org.openconcerto.utils.model.DefaultIMutableListModel;
53,6 → 52,7
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.AbstractDocument;
261,7 → 261,7
synchronized (this) {
this.isLoading = true;
}
final SwingWorker2<Object, Object> worker = new SwingWorker2<Object, Object>() {
final SwingWorker<Object, Object> worker = new SwingWorker<Object, Object>() {
 
// Runs on the event-dispatching thread.
@Override
/trunk/OpenConcerto/src/org/openconcerto/sql/Configuration.java
65,6 → 65,7
return new File(System.getProperty("user.home"), ".java/ilm/sql-config/");
}
 
@GuardedBy("this")
private static Configuration instance;
 
public static SQLFieldTranslator getTranslator(SQLTable t) {
72,17 → 73,33
return getInstance().getTranslator();
}
 
public static Configuration getInstance() {
public synchronized static Configuration getInstance() {
return instance;
}
 
public static final void setInstance(Configuration instance) {
Configuration.instance = instance;
try {
instance.migrateToNewDBConfDir();
} catch (IOException e) {
throw new IllegalStateException("Couldn't migrate");
setInstance(instance, false);
}
 
public static final Configuration setInstance(final Configuration instance, final boolean destroyPrevious) {
final Configuration prev;
synchronized (Configuration.class) {
prev = Configuration.instance;
// don't destroy new instance
if (prev == instance)
return prev;
Configuration.instance = instance;
if (instance != null) {
try {
instance.migrateToNewDBConfDir();
} catch (IOException e) {
throw new IllegalStateException("Couldn't migrate");
}
}
}
if (prev != null && destroyPrevious)
prev.destroy();
return prev;
}
 
static public final void migrateToNewDir(final File oldDir, final File newDir) throws IOException {
/trunk/OpenConcerto/src/org/openconcerto/sql/request/SQLCacheWatcher.java
32,7 → 32,7
 
private final ListenerAndConfig listener;
 
SQLCacheWatcher(final SQLData t) {
public SQLCacheWatcher(final SQLData t) {
super(t);
this.listener = new ListenerAndConfig(t.createTableListener(new SQLDataListener() {
@Override
/trunk/OpenConcerto/src/org/openconcerto/sql/request/SQLFieldTranslator.java
292,9 → 292,9
 
private Tuple2<String, SQLTable> load(DBRoot b, final String variant, final Element tableElem, final boolean lenient) {
final String tableName = tableElem.getAttributeValue("name");
SQLTable table = b.getTable(tableName);
if (table == null && this.dir != null && this.dir.getElement(tableName) != null)
table = this.dir.getElement(tableName).getTable();
SQLTable table = this.dir == null || this.dir.getElement(tableName) == null ? b.getTable(tableName) : this.dir.getElement(tableName).getTable();
if (table == null && this.dir != null && this.dir.getElementForCode(tableName) != null)
table = this.dir.getElementForCode(tableName).getTable();
if (table != null) {
for (final Element elem : getChildren(tableElem)) {
final String elemName = elem.getName().toLowerCase();
/trunk/OpenConcerto/src/org/openconcerto/sql/request/SQLRowView.java
16,6 → 16,7
import org.openconcerto.sql.Log;
import org.openconcerto.sql.element.SQLComponent;
import org.openconcerto.sql.element.SQLElement;
import org.openconcerto.sql.element.SQLElement.PrivateMode;
import org.openconcerto.sql.model.SQLRow;
import org.openconcerto.sql.model.SQLRowAccessor;
import org.openconcerto.sql.model.SQLRowValues;
23,6 → 24,7
import org.openconcerto.sql.model.SQLSelect;
import org.openconcerto.sql.model.SQLSelect.LockStrength;
import org.openconcerto.sql.model.SQLTable;
import org.openconcerto.sql.model.SQLTable.VirtualFields;
import org.openconcerto.sql.model.SQLTableEvent;
import org.openconcerto.sql.model.SQLTableEvent.Mode;
import org.openconcerto.sql.model.SQLTableModifiedListener;
204,7 → 206,7
public final SQLRowValues fetchRow(final int id, final LockStrength ls) {
if (id < SQLRow.MIN_VALID_ID)
return null;
final SQLRowValuesListFetcher fetcher = SQLRowValuesListFetcher.create(this.getElement().getPrivateGraph(null, false, true));
final SQLRowValuesListFetcher fetcher = SQLRowValuesListFetcher.create(this.getElement().createGraph(VirtualFields.ALL, PrivateMode.ALL_PRIVATES, true));
fetcher.setSelTransf(new ITransformer<SQLSelect, SQLSelect>() {
@Override
public SQLSelect transformChecked(SQLSelect sel) {
/trunk/OpenConcerto/src/org/openconcerto/sql/element/SQLElement.java
91,6 → 91,7
import org.openconcerto.utils.NumberUtils;
import org.openconcerto.utils.RTInterruptedException;
import org.openconcerto.utils.RecursionType;
import org.openconcerto.utils.ReflectUtils;
import org.openconcerto.utils.SetMap;
import org.openconcerto.utils.Tuple2;
import org.openconcerto.utils.Value;
107,6 → 108,7
 
import java.awt.Component;
import java.lang.reflect.Constructor;
import java.math.BigDecimal;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
200,7 → 202,8
private String parentFF;
 
// lazy creation
private SQLCache<SQLRowAccessor, Object> modelCache;
@GuardedBy("this")
private SQLCache<SQLRow, Object> modelCache;
 
private final Map<String, JComponent> additionalFields;
private final List<SQLTableModelColumn> additionalListCols;
248,6 → 251,9
this.mdPath = Collections.emptyList();
}
 
public void destroy() {
}
 
/**
* Should return the code for this element. This method is only called if the <code>code</code>
* parameter of the constructor is <code>null</code>.
898,9 → 904,9
return Collections.emptySet();
}
 
private final SQLCache<SQLRowAccessor, Object> getModelCache() {
private synchronized final SQLCache<SQLRow, Object> getModelCache() {
if (this.modelCache == null)
this.modelCache = new SQLCache<SQLRowAccessor, Object>(60, -1, "modelObjects of " + this.getCode());
this.modelCache = new SQLCache<SQLRow, Object>(60, -1, "modelObjects of " + this.getCode());
return this.modelCache;
}
 
957,7 → 963,7
final String field = group.getSingleField();
assert field != null;
 
final Path p = new PathBuilder(getTable()).add(k.getForeignLink()).build();
final Path p = new PathBuilder(getTable()).add(k.getForeignLink(), Direction.FOREIGN).build();
final SQLElementLink elemLink = this.getOwnedLinks().getByPath(p);
if (elemLink.getLinkType() == LinkType.COMPOSITION) {
final SQLElement privateElem = elemLink.getOwned();
995,6 → 1001,8
// SQLRowValues without ID
final Number toForeignID = to.getForeignIDNumber(field);
 
// if it's desired in the future, don't forget to only re-use ID if there's
// no reference to this private
if (toForeignID != null && !NumberUtils.areNumericallyEqual(fromForeignID, toForeignID))
throw new IllegalArgumentException("private have changed for " + field + " : " + fromPrivate + " != " + toPrivate);
if (toPrivate instanceof SQLRowValues) {
1016,17 → 1024,51
}
}
}
// now private referents
// now owned referents
for (final SQLElementLink elemLink : this.getOwnedLinks().getByPath().values()) {
if (elemLink.isJoin()) {
final Path pathToFK = elemLink.getPath().minusLast();
final Set<String> joinTableLocalContentFields = pathToFK.getLast().getFieldsNames(VirtualFields.LOCAL_CONTENT);
if (elemLink.getLinkType() == LinkType.COMPOSITION) {
final Tuple2<List<SQLRowValues>, Map<Number, SQLRowValues>> fromPrivatesTuple = indexRows(from.followPath(elemLink.getPath(), CreateMode.CREATE_NONE, false));
// already checked at the start of the method
assert fromPrivatesTuple.get0().isEmpty() : "Existing rows without ID : " + fromPrivatesTuple.get0();
final Map<Number, SQLRowValues> fromPrivates = fromPrivatesTuple.get1();
BigDecimal minOrder = null, maxOrder = null;
for (final SQLRowValues fromJoin : from.followPath(pathToFK, CreateMode.CREATE_NONE, false)) {
final BigDecimal order = fromJoin.getOrder();
assert order != null;
if (minOrder == null || minOrder.compareTo(order) > 0)
minOrder = order;
if (maxOrder == null || maxOrder.compareTo(order) < 0)
maxOrder = order;
}
 
final Tuple2<List<SQLRowValues>, Map<Number, SQLRowValues>> toPrivatesTuple = indexRows(to.followPath(elemLink.getPath(), CreateMode.CREATE_NONE, false));
final Collection<SQLRowValues> toValues = to.followPath(elemLink.getPath(), CreateMode.CREATE_NONE, false);
final Tuple2<List<SQLRowValues>, Map<Number, SQLRowValues>> toPrivatesTuple = indexRows(toValues);
final Map<Number, SQLRowValues> toPrivates = toPrivatesTuple.get1();
/*
* Order of joined rows are dictated by their join rows. To avoid needing
* knowledge from the entire table, join orders are unique only among their
* owner.
*/
/*
* Since almost no DB has deferrable constraints, use non-overlapping order : if
* there's space before minOrder, then use it, otherwise use space after
* maxOrder.
*/
BigDecimal toOrder;
if (minOrder == null || BigDecimal.valueOf(toValues.size()).compareTo(minOrder) < 0) {
toOrder = BigDecimal.ONE;
} else {
assert maxOrder != null : "Minimum order isn't null but maximum order is";
toOrder = maxOrder.add(BigDecimal.ONE);
}
final Map<SQLRowValues, BigDecimal> toPrivatesOrder = new IdentityHashMap<>();
for (final SQLRowValues toVals : toValues) {
toPrivatesOrder.put(toVals, toOrder);
toOrder = toOrder.add(BigDecimal.ONE);
}
 
final List<Number> onlyInFrom = new ArrayList<Number>(fromPrivates.keySet());
onlyInFrom.removeAll(toPrivates.keySet());
1046,10 → 1088,13
matchedPrivates.add(toPrivates.get(inBoth));
}
 
final SQLElement privateElem = elemLink.getOwned();
final boolean hasReferences = !privateElem.getLinksOwnedByOthers().getByType(LinkType.ASSOCIATION).isEmpty();
final SQLField toMainField = elemLink.getPath().getStep(0).getSingleField();
final SQLField toPrivateField = elemLink.getPath().getStep(-1).getSingleField();
for (final SQLRowValues privateSansID : toPrivatesTuple.get0()) {
if (!onlyInFrom.isEmpty()) {
// don't re-use existing ID if there can be rows referencing it
if (!hasReferences && !onlyInFrom.isEmpty()) {
matchedPrivates.add(fromPrivates.get(onlyInFrom.remove(0)));
matchedPrivates.add(privateSansID);
} else {
1056,11 → 1101,14
// insert new, always creating the join row
final SQLRowValues copy = privateSansID.deepCopy().removeReferents(toPrivateField);
res.getUpdateRow().put(elemLink.getPath(), true, copy);
final SQLRowValues toJoinRow = CollectionUtils.getSole(privateSansID.getReferentRows(toPrivateField));
final SQLRowValues joinRow = CollectionUtils.getSole(copy.getReferentRows(toPrivateField));
setContentFields(joinTableLocalContentFields, joinRow, toJoinRow);
setOrder(joinRow, toPrivatesOrder.get(privateSansID));
res.mapRow(copy2originalRows.transformChecked(privateSansID), copy);
}
}
 
final SQLElement privateElem = elemLink.getOwned();
final Iterator<SQLRowValues> iter = matchedPrivates.iterator();
while (iter.hasNext()) {
final SQLRowValues fromPrivate = iter.next();
1069,10 → 1117,14
final SQLRowValues fromJoin = CollectionUtils.getSole(fromPrivate.getReferentRows(toPrivateField));
if (fromJoin == null)
throw new IllegalStateException("Shared private " + fromPrivate.printGraph());
final SQLRowValues toJoin = CollectionUtils.getSole(toPrivate.getReferentRows(toPrivateField));
final UpdateScript updateScript = privateElem.update(fromPrivate, toPrivate, allowedToChangeTo, copy2originalRows);
 
final SQLRowValues joinCopy = new SQLRowValues(fromJoin, ForeignCopyMode.NO_COPY);
final SQLRowValues joinCopy = new SQLRowValues(fromJoin.getTable());
joinCopy.setID(fromJoin.getIDNumber());
assert joinCopy.getGraphSize() == 1;
setContentFields(joinTableLocalContentFields, joinCopy, toJoin);
setOrder(joinCopy, toPrivatesOrder.get(toPrivate));
joinCopy.put(toMainField.getName(), res.getUpdateRow());
joinCopy.put(toPrivateField.getName(), updateScript.getUpdateRow());
res.add(updateScript);
1083,54 → 1135,39
res.addToArchive(privateElem, fromPrivates.get(id));
}
} else {
final Path pathToFK = elemLink.getPath().minusLast();
final Step fkStep = elemLink.getPath().getStep(-1);
final String fkField = fkStep.getSingleField().getName();
final ListMap<Number, SQLRowValues> fromFKs = indexByFK(from.followPath(pathToFK, CreateMode.CREATE_NONE, false), fkField);
final ListMap<Number, SQLRowValues> toFKs = indexByFK(to.followPath(pathToFK, CreateMode.CREATE_NONE, false), fkField);
final List<SQLRowValues> fromFKs = new ArrayList<SQLRowValues>(from.followPath(pathToFK, CreateMode.CREATE_NONE, false));
final List<SQLRowValues> toFKs = new ArrayList<SQLRowValues>(to.followPath(pathToFK, CreateMode.CREATE_NONE, false));
 
// find foreignIDs that haven't changed
for (final Entry<Number, List<SQLRowValues>> e : toFKs.entrySet()) {
final Number foreignID = e.getKey();
final int count = e.getValue().size();
for (int i = 0; i < count; i++) {
if (fromFKs.containsKey(foreignID)) {
fromFKs.get(foreignID).remove(0);
fromFKs.removeIfEmpty(foreignID);
e.getValue().remove(0);
}
}
}
assert fromFKs.removeAllEmptyCollections().isEmpty() : "Should have been done along the way";
// do it after to avoid ConcurrentModificationException
toFKs.removeAllEmptyCollections();
 
// if there's more foreignIDs, re-use old join rows until we need to create new
// ones.
for (final Entry<Number, List<SQLRowValues>> e : toFKs.entrySet()) {
final Number foreignID = e.getKey();
final int count = e.getValue().size();
for (int i = 0; i < count; i++) {
assert !fromFKs.containsKey(foreignID) : "Should have been used above";
final SQLRowValues toUse;
if (fromFKs.isEmpty()) {
toUse = res.getUpdateRow().putRowValues(pathToFK, true);
for (final SQLRowValues rowWithFK : toFKs) {
final int ownedID = rowWithFK.getForeignID(fkField);
final SQLRowValues toUse;
if (fromFKs.isEmpty()) {
toUse = res.getUpdateRow().putRowValues(pathToFK, true);
} else {
// take first available join
final SQLRowValues fromJoin = fromFKs.remove(0);
// if its values are what is needed don't update the DB (don't try to
// compare local field values)
if (ownedID == fromJoin.getForeignID(fkField) && joinTableLocalContentFields.isEmpty()) {
toUse = null;
} else {
// take first available join
final Entry<Number, List<SQLRowValues>> fromEntry = fromFKs.entrySet().iterator().next();
final SQLRowValues fromJoin = fromEntry.getValue().remove(0);
fromFKs.removeIfEmpty(fromEntry.getKey());
// copy existing join ID to avoid inserting a new join in the DB
toUse = new SQLRowValues(fromJoin.getTable()).setID(fromJoin.getIDNumber());
res.getUpdateRow().put(elemLink.getPath().getStep(0), toUse);
}
toUse.put(fkField, foreignID);
}
if (toUse != null) {
setContentFields(joinTableLocalContentFields, toUse, rowWithFK);
toUse.put(fkField, ownedID);
res.mapRow(copy2originalRows.transformChecked(rowWithFK), toUse);
}
}
 
// lastly, delete remaining join rows (don't just archive otherwise if the main
// row is unarchived it will get back all links from every modification)
for (final SQLRowValues rowWithFK : fromFKs.allValues()) {
for (final SQLRowValues rowWithFK : fromFKs) {
res.addToDelete(rowWithFK);
}
}
1156,15 → 1193,19
return Tuple2.create(sansID, map);
}
 
static private ListMap<Number, SQLRowValues> indexByFK(final Collection<SQLRowValues> rows, final String fieldName) {
final ListMap<Number, SQLRowValues> res = new ListMap<Number, SQLRowValues>();
for (final SQLRowValues rowWithFK : rows) {
if (rowWithFK.isForeignEmpty(fieldName))
throw new IllegalArgumentException("Missing foreign key for " + fieldName);
else
res.add(rowWithFK.getForeignIDNumber(fieldName), rowWithFK);
static private void setOrder(final SQLRowValues row, final BigDecimal order) {
assert order != null;
row.put(row.getTable().getOrderField().getName(), order);
}
 
static private void setContentFields(final Set<String> joinTableLocalContentFields, final SQLRowValues newJoinRow, final SQLRowValues rowToStore) {
if (!joinTableLocalContentFields.isEmpty()) {
// copy passed LOCAL_CONTENT fields (e.g. label)
newJoinRow.putAll(rowToStore.getValues(joinTableLocalContentFields));
// reset those not passed
if (newJoinRow.hasID())
newJoinRow.fill(joinTableLocalContentFields, SQLRowValues.SQL_DEFAULT, false, true);
}
return res;
}
 
public final void unarchiveNonRec(int id) throws SQLException {
1256,27 → 1297,32
if (Log.get().isLoggable(Level.FINEST))
Log.get().finest("will cut : " + externReferences);
for (final Entry<SQLElementLink, ? extends Collection<SQLRowValues>> e : externReferences.entrySet()) {
if (e.getKey().isJoin()) {
final Path joinPath = e.getKey().getPath();
final Path toJoinTable = joinPath.minusLast();
final SQLTable joinTable = toJoinTable.getLast();
assert getElement(joinTable) instanceof JoinSQLElement;
final Set<Number> ids = new HashSet<Number>();
for (final SQLRowValues joinRow : e.getValue()) {
assert joinRow.getTable() == joinTable;
ids.add(joinRow.getIDNumber());
final SQLElementLink linkToCut = e.getKey();
try {
if (linkToCut.isJoin()) {
final Path joinPath = linkToCut.getPath();
final Path toJoinTable = joinPath.minusLast();
final SQLTable joinTable = toJoinTable.getLast();
assert getElement(joinTable) instanceof JoinSQLElement;
final Set<Number> ids = new HashSet<Number>();
for (final SQLRowValues joinRow : e.getValue()) {
assert joinRow.getTable() == joinTable;
ids.add(joinRow.getIDNumber());
}
// MAYBE instead of losing the information (as with simple foreign
// key), archive it
final String query = "DELETE FROM " + joinTable.getSQLName() + " WHERE " + new Where(joinTable.getKey(), ids);
getTable().getDBSystemRoot().getDataSource().execute(query);
for (final Number id : ids)
joinTable.fireRowDeleted(id.intValue());
} else {
final Link refKey = linkToCut.getSingleLink();
for (final SQLRowAccessor ref : e.getValue()) {
ref.createEmptyUpdateRow().putEmptyLink(refKey.getSingleField().getName()).update();
}
}
// MAYBE instead of losing the information (as with simple foreign key),
// archive it
final String query = "DELETE FROM " + joinTable.getSQLName() + " WHERE " + new Where(joinTable.getKey(), ids);
getTable().getDBSystemRoot().getDataSource().execute(query);
for (final Number id : ids)
joinTable.fireRowDeleted(id.intValue());
} else {
final Link refKey = e.getKey().getSingleLink();
for (final SQLRowAccessor ref : e.getValue()) {
ref.createEmptyUpdateRow().putEmptyLink(refKey.getSingleField().getName()).update();
}
} catch (Exception e1) {
throw new SQLException("Couldn't cut " + linkToCut + " in " + trees, e1);
}
}
Log.get().finest("done cutting links");
1617,49 → 1663,60
* @return an SQLRowValues of this element's table filled with
* {@link SQLRowValues#setAllToNull() <code>null</code>s} except for private foreign
* fields containing SQLRowValues.
* @deprecated renamed to {@link #createGraph()} since there's also join tables and each call
* creates a new instance.
*/
public final SQLRowValues getPrivateGraph() {
return this.getPrivateGraph(null);
return this.createGraph();
}
 
/**
* The graph of this table and its privates.
* The graph of this table, its privates and join tables.
*
* @param fields which fields should be included in the graph, <code>null</code> meaning all.
* @return an SQLRowValues of this element's table filled with <code>null</code>s according to
* the <code>fields</code> parameter except for private foreign fields containing
* SQLRowValues.
* @return a graph of SQLRowValues filled with <code>null</code>s.
*/
public final SQLRowValues getPrivateGraph(final VirtualFields fields) {
return this.getPrivateGraph(fields, false, true);
public final SQLRowValues createGraph() {
return this.createGraph(VirtualFields.ALL);
}
 
public final SQLRowValues getPrivateGraph(final VirtualFields fields, final boolean ignoreNotDeepCopied, final boolean includeJoins) {
final SQLRowValues res = includeJoins ? this.getOwnedJoinsGraph(fields) : new SQLRowValues(this.getTable());
if (fields == null) {
res.setAllToNull();
} else {
res.putNulls(this.getTable().getFieldsNames(fields));
}
for (final SQLElementLink link : this.getOwnedLinks().getByType(LinkType.COMPOSITION)) {
final SQLElement owned = link.getOwned();
if (ignoreNotDeepCopied && owned.dontDeepCopy()) {
res.remove(link.getPath().getStep(0));
} else {
res.put(link.getPath(), false, owned.getPrivateGraph(fields, ignoreNotDeepCopied, includeJoins));
}
}
return res;
/**
* The graph of this table, its privates and join tables.
*
* @param fields which fields should be included in the graph, not <code>null</code>.
* @return a graph of SQLRowValues filled with <code>null</code>s according to the
* <code>fields</code> parameter.
*/
public final SQLRowValues createGraph(final VirtualFields fields) {
return this.createGraph(fields, PrivateMode.ALL_PRIVATES, true);
}
 
public final SQLRowValues getOwnedJoinsGraph(final VirtualFields fields) {
final SQLRowValues res = new SQLRowValues(this.getTable());
for (final SQLElementLink link : this.getOwnedLinks().getByPath().values()) {
if (link.isJoin()) {
final SQLRowValues joinVals = res.putRowValues(link.getPath().getStep(0));
joinVals.fill(joinVals.getTable().getFieldsNames(fields == null ? VirtualFields.ALL : fields), null, false, true);
static public enum PrivateMode {
NO_PRIVATES, DEEP_COPIED_PRIVATES, ALL_PRIVATES;
}
 
static private final SQLRowValues putNulls(final SQLRowValues res, final VirtualFields fields) {
return res.fill(res.getTable().getFieldsNames(fields), null, false, true);
}
 
public final SQLRowValues createGraph(final VirtualFields fields, final PrivateMode privateMode, final boolean includeJoins) {
final SQLRowValues res = putNulls(new SQLRowValues(this.getTable()), fields);
if (includeJoins) {
for (final SQLElementLink link : this.getOwnedLinks().getByPath().values()) {
if (link.isJoin()) {
putNulls(res.putRowValues(link.getPath().getStep(0)), fields);
}
}
}
if (privateMode != PrivateMode.NO_PRIVATES) {
for (final SQLElementLink link : this.getOwnedLinks().getByType(LinkType.COMPOSITION)) {
final SQLElement owned = link.getOwned();
if (privateMode == PrivateMode.DEEP_COPIED_PRIVATES && owned.dontDeepCopy()) {
res.remove(link.getPath().getStep(0));
} else {
res.put(link.getPath(), false, owned.createGraph(fields, privateMode, includeJoins));
}
}
}
return res;
}
 
1874,6 → 1931,7
}
 
public final synchronized <S extends SQLTableModelSource> S initTableSource(final S res, final boolean minimal) {
res.init();
// do init first since it can modify the columns
if (!minimal)
this._initTableSource(res);
2003,7 → 2061,7
}, deep, archived);
}
 
void check(SQLRowAccessor row) {
protected final void check(SQLRowAccessor row) {
if (!row.getTable().equals(this.getTable()))
throw new IllegalArgumentException("row must of table " + this.getTable() + " : " + row);
}
2171,7 → 2229,7
this.check(row);
 
final Set<SQLElementLink> privates = this.getOwnedLinks().getByType(LinkType.COMPOSITION);
final SQLRowValues privateGraph = this.getPrivateGraph(VirtualFields.ALL, !full, true);
final SQLRowValues privateGraph = this.createGraph(VirtualFields.ALL, !full ? PrivateMode.DEEP_COPIED_PRIVATES : PrivateMode.ALL_PRIVATES, true);
// Don't make one request per private, just fetch the whole graph at once
// further with joined privates an SQLRow cannot contain privates nor carry the lack of them
// (without joins a row lacking privates was passed with just an SQLRow with undefined
2546,23 → 2604,54
}
 
/**
* Returns a java object modeling the passed row.
* Fetch the whole {@link #createGraph() graph} for the passed ID and wrap it in the model
* object.
*
* @param id the ID to fetch.
* @return a model object.
*/
public final Object fetchModelObject(Number id) {
final SQLRowValues r = createModelFetcher().fetchOne(id, true);
if (r == null)
throw new IllegalStateException("Missing " + id + " for " + this);
return this.getModelObject(r);
}
 
protected final SQLRowValuesListFetcher createModelFetcher() {
return SQLRowValuesListFetcher.create(this.createGraph());
}
 
public final Map<Number, Object> fetchModelObjects(Collection<? extends Number> ids) {
return this.fetchModelObjects(ids, Object.class);
}
 
public final <T> Map<Number, T> fetchModelObjects(Collection<? extends Number> ids, final Class<T> clazz) {
final List<SQLRowValues> rows = createModelFetcher().fetch(new Where(getTable().getKey(), ids), true);
final Map<Number, T> res = new LinkedHashMap<Number, T>();
for (final SQLRowValues r : rows) {
res.put(r.getIDNumber(), clazz.cast(this.getModelObject(r)));
}
return res;
}
 
/**
* Returns a java object modeling the passed row. No access to the DB will be performed.
*
* @param row the row to model.
* @return an instance modeling the passed row or <code>null</code> if there's no class to model
* this table.
* @see SQLRowAccessor#getModelObject()
* @see #canCreateModelObject()
*/
public Object getModelObject(SQLRowAccessor row) {
public final Object getModelObject(SQLRowAccessor row) {
check(row);
if (this.getModelClass() == null)
if (!canCreateModelObject())
return null;
 
final Object res;
// seuls les SQLRow peuvent être cachées
// only SQLRow are cached (otherwise need another cache to not return model objects with
// SQLRowValues if passed SQLRow and vice-versa)
if (row instanceof SQLRow) {
// MAYBE make the modelObject change
final CacheResult<Object> cached = this.getModelCache().check(row, Collections.singleton(row));
final CacheResult<Object> cached = this.getModelCache().check(row.asRow(), Collections.singleton(row));
if (cached.getState() == CacheResult.State.INTERRUPTED)
throw new RTInterruptedException("interrupted while waiting for the cache");
else if (cached.getState() == CacheResult.State.VALID)
2581,23 → 2670,32
return res;
}
 
private final Object createModelObject(SQLRowAccessor row) {
if (!RowBacked.class.isAssignableFrom(this.getModelClass()))
throw new IllegalStateException("modelClass must inherit from RowBacked: " + this.getModelClass());
final Constructor<? extends RowBacked> ctor;
try {
ctor = this.getModelClass().getConstructor(new Class[] { SQLRowAccessor.class });
} catch (Exception e) {
throw ExceptionUtils.createExn(IllegalStateException.class, "no SQLRowAccessor constructor", e);
protected final Object createModelObject(SQLRowAccessor row) {
return this.getModelClass().cast(this._createModelObject(row));
}
 
protected Object _createModelObject(SQLRowAccessor row) {
Constructor<?> ctor = ReflectUtils.getMatchingConstructor(this.getModelClass(), row.getClass(), this.getClass());
if (ctor == null) {
// deprecated constructor
try {
ctor = this.getModelClass().getConstructor(new Class[] { SQLRowAccessor.class });
} catch (NoSuchMethodException e) {
throw new IllegalStateException(this + " found no public suitable constructor in " + this.getModelClass());
}
}
try {
return ctor.newInstance(new Object[] { row });
return ctor.getParameterTypes().length == 2 ? ctor.newInstance(new Object[] { row, this }) : ctor.newInstance(new Object[] { row });
} catch (Exception e) {
throw ExceptionUtils.createExn(RuntimeException.class, "pb creating instance", e);
}
}
 
protected Class<? extends RowBacked> getModelClass() {
public boolean canCreateModelObject() {
return this.getModelClass() != null;
}
 
protected Class<?> getModelClass() {
return null;
}
 
2779,7 → 2877,7
 
private final SQLRowValues getPrivateGraphForEquals(final EqualOption option) {
// don't include joins as we only add those required by "option"
final SQLRowValues res = this.getPrivateGraph(option.fields, option.isIgnoreNotDeepCopied(), false);
final SQLRowValues res = this.createGraph(option.fields, option.isIgnoreNotDeepCopied() ? PrivateMode.DEEP_COPIED_PRIVATES : PrivateMode.ALL_PRIVATES, false);
for (final SQLRowValues item : new HashSet<SQLRowValues>(res.getGraph().getItems())) {
final SQLElement elem = getElement(item.getTable());
// remove parent
2854,7 → 2952,7
public final void removeComponentFactory(final String id, final ITransformer<Tuple2<SQLElement, String>, SQLComponent> t) {
if (t == null)
throw new NullPointerException();
this.components.remove(id, t);
this.components.removeOne(id, t);
}
 
private final SQLComponent createComponentFromFactory(final String id, final boolean defaultItem) {
/trunk/OpenConcerto/src/org/openconcerto/sql/element/BaseSQLComponent.java
396,7 → 396,8
if (v instanceof SQLComponentItem) {
((SQLComponentItem) v).added(this, v);
}
if (v.getComp() instanceof SQLComponentItem) {
// don't call the method twice
if (v.getComp() != v && v.getComp() instanceof SQLComponentItem) {
((SQLComponentItem) v.getComp()).added(this, v);
}
// reset just before adding to the UI :
/trunk/OpenConcerto/src/org/openconcerto/sql/element/SQLElementLink.java
46,6 → 46,7
private final Path path;
private final LinkType type;
private final String name;
// TODO final (see #setAction())
private ReferenceAction action;
 
protected SQLElementLink(SQLElement owner, Path path, SQLElement owned, final LinkType type, final String name, final ReferenceAction action) {
80,9 → 81,11
this.type = type;
if (name != null) {
this.name = name;
} else {
} else if (length == 1) {
final SQLField singleField = lastStep.getSingleField();
this.name = singleField != null ? singleField.getName() : lastStep.getSingleLink().getName();
} else {
this.name = lastStep.getFrom().getName();
}
assert this.getName() != null;
this.action = action;
202,6 → 205,8
return this.action;
}
 
// use SQLElementLinkSetup
@Deprecated
public final void setAction(ReferenceAction action) {
final List<ReferenceAction> possibleActions = getOwner().getPossibleActions(this.getLinkType(), this.getOwned());
if (!possibleActions.contains(action))
/trunk/OpenConcerto/src/org/openconcerto/sql/element/SQLElementDirectory.java
105,6 → 105,12
this.showAs = new ShowAs((DBRoot) null);
}
 
public synchronized final void destroy() {
for (final SQLElement elem : this.elements.values()) {
elem.destroy();
}
}
 
public final ShowAs getShowAs() {
return this.showAs;
}
262,9 → 268,9
public synchronized SQLElement removeSQLElement(SQLTable t) {
final SQLElement elem = this.elements.remove(t);
if (elem != null) {
this.tableNames.remove(elem.getTable().getName(), elem.getTable());
this.byCode.remove(elem.getCode(), elem.getTable());
this.byClass.remove(elem.getClass(), elem.getTable());
this.tableNames.removeOne(elem.getTable().getName(), elem.getTable());
this.byCode.removeOne(elem.getCode(), elem.getTable());
this.byClass.removeOne(elem.getClass(), elem.getTable());
// MAYBE only reset neighbours.
for (final SQLElement otherElem : this.elements.values())
otherElem.resetRelationships();
/trunk/OpenConcerto/src/org/openconcerto/sql/element/GroupSQLComponent.java
336,6 → 336,14
}
 
public JComponent createEditor(final String id) {
if (GlobalMapper.getInstance().get(id + ".editor") != null) {
try {
final Class<?> cl = (Class<?>) GlobalMapper.getInstance().get(id + ".editor");
return (JComponent) cl.newInstance();
} catch (final Exception e) {
e.printStackTrace();
}
}
if (id.startsWith("(") && id.endsWith(")*")) {
try {
final String table = id.substring(1, id.length() - 2).trim();
/trunk/OpenConcerto/src/org/openconcerto/sql/element/RowBacked.java
14,17 → 14,25
package org.openconcerto.sql.element;
 
import org.openconcerto.sql.Configuration;
import org.openconcerto.sql.element.SQLElementLink.LinkType;
import org.openconcerto.sql.model.PolymorphFK;
import org.openconcerto.sql.model.SQLBase;
import org.openconcerto.sql.model.SQLRow;
import org.openconcerto.sql.model.SQLRowAccessor;
import org.openconcerto.sql.model.SQLRowValues;
import org.openconcerto.sql.model.SQLRowValues.CreateMode;
import org.openconcerto.sql.model.SQLSelect.ArchiveMode;
import org.openconcerto.sql.model.SQLTable;
import org.openconcerto.sql.model.graph.Step;
import org.openconcerto.utils.CollectionUtils;
import org.openconcerto.utils.cc.ITransformer;
 
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
 
import org.apache.commons.collections.Transformer;
 
/**
* A class whose state comes from a row.
*
32,23 → 40,35
*/
public abstract class RowBacked {
 
protected static abstract class PropExtractor implements Transformer {
 
@Override
public final Object transform(Object input) {
return this.extract((SQLRowAccessor) input);
}
 
public abstract Object extract(SQLRowAccessor r);
protected static interface PropExtractor extends ITransformer<SQLRowAccessor, Object> {
}
 
private final SQLElement elem;
private final SQLRowAccessor r;
private final Map<String, PropExtractor> propExtractors;
private final Map<String, ITransformer<? super SQLRowAccessor, ?>> propExtractors;
private final Map<String, Object> values;
 
@Deprecated
public RowBacked(SQLRowAccessor r) {
this.r = r;
this.propExtractors = new HashMap<String, PropExtractor>();
this(r, Configuration.getInstance().getDirectory().getElement(r.getTable()));
}
 
/**
* Create a new instance.
*
* @param r the row to wrap, if r is a {@link SQLRowValues} then it must have the
* {@link SQLElement#createGraph() whole graph}.
* @param elem the element.
*/
public RowBacked(final SQLRowAccessor r, final SQLElement elem) {
elem.check(r);
this.elem = elem;
if (r instanceof SQLRow) {
this.r = new SQLRow(r.getTable(), r.getAbsolutelyAll());
} else {
this.r = ((SQLRowValues) r).toImmutable();
}
this.propExtractors = new HashMap<String, ITransformer<? super SQLRowAccessor, ?>>();
this.values = new HashMap<String, Object>();
 
for (final PolymorphFK f : PolymorphFK.findPolymorphFK(this.getTable())) {
57,6 → 77,16
}
 
/**
* Whether each linked object is fetched with its whole graph or just one row.
*
* @return <code>true</code> if the {@link SQLElement#createGraph() whole graph} is used.
*/
public final boolean hasGraph() {
// MAYBE allow SQLRowValues with no graph
return this.getRow() instanceof SQLRowValues;
}
 
/**
* Get a property value. If there's an extractor use it, otherwise there's must be a field named
* <code>propName</code>. If this field is a foreign key and there's a model object return it
* otherwise return the foreign row. If this field is not a foreign key just return its value.
69,29 → 99,25
return this.values.get(propName);
else {
final Object res;
if (this.propExtractors.containsKey(propName))
res = this.propExtractors.get(propName).extract(this.getRow());
else if (!this.getTable().contains(propName))
throw new IllegalArgumentException(propName + " is neither a property of " + this + " nor a field of " + this.getTable());
else if (this.getTable().getForeignKeys().contains(this.getTable().getField(propName))) {
if (this.getRow().isForeignEmpty(propName))
res = null;
else {
final SQLRowAccessor foreign = this.getRow().getForeign(propName);
final Object modelObj = getModelObject(foreign);
if (modelObj != null)
res = modelObj;
else
res = foreign;
if (this.propExtractors.containsKey(propName)) {
res = this.propExtractors.get(propName).transformChecked(this.getRow());
} else {
final SQLElementLink ownedLink = this.getElement().getOwnedLink(propName);
if (ownedLink != null) {
assert !ownedLink.isJoin();
final List<?> ownedRows = ownedLink.getOwned().canCreateModelObject() ? this.getOwnedObjects(ownedLink) : this.getOwnedRows(ownedLink);
assert ownedRows.size() <= 1 : "More than one row referenced by a field : " + ownedRows;
res = CollectionUtils.getSole(ownedRows);
} else {
res = this.getRow().getContainedObject(propName);
}
} else
res = this.getRow().getObject(propName);
}
this.values.put(propName, res);
return res;
}
}
 
protected final void putExtractor(String name, PropExtractor extr) {
protected final void putExtractor(String name, ITransformer<? super SQLRowAccessor, ?> extr) {
this.propExtractors.put(name, extr);
}
 
109,22 → 135,92
protected final void addPolymorphFK(final PolymorphFK fk) {
this.putExtractor(fk.getName(), new PropExtractor() {
@Override
public Object extract(SQLRowAccessor r) {
public Object transformChecked(SQLRowAccessor r) {
final String tableName = r.getString(fk.getTableField().getName());
final SQLTable foreignT = tableName == null ? null : r.getTable().getBase().getTable(tableName);
if (foreignT == null)
final SQLTable foreignT = tableName == null ? null : r.getTable().getDBRoot().findTable(tableName);
if (foreignT == null) {
return null;
else {
} else {
final int foreignID = r.getInt(fk.getIdField().getName());
final SQLRow foreignR = foreignT.getRow(foreignID);
if (foreignR == null)
throw new IllegalStateException("incoherent base, fk " + fk + " of " + r);
return foreignT.getRow(foreignID).getModelObject();
final SQLElement foreignElem = getElement().getDirectory().getElement(foreignT);
return getModelObject(foreignElem, foreignID);
}
}
});
}
 
public final List<SQLRowAccessor> getOwnedRows(final SQLElementLink link) {
return this.getOwnedRows(link, SQLRowAccessor.class);
}
 
public final <T extends SQLRowAccessor> List<T> getOwnedRows(final SQLElementLink link, final Class<T> clazz) {
if (link.getOwner() != this.getElement())
throw new IllegalArgumentException("Wrong link " + link);
 
final List<T> ownedRows;
if (this.getRow() instanceof SQLRow) {
if (!clazz.isAssignableFrom(SQLRow.class))
throw new ClassCastException("Cannot cast SQLRow to " + clazz);
ownedRows = new ArrayList<T>();
@SuppressWarnings("unchecked")
final List<? extends T> distantRows = (List<? extends T>) ((SQLRow) this.getRow()).getDistantRowsList(link.getPath(), ArchiveMode.UNARCHIVED);
ownedRows.addAll(distantRows);
} else {
final boolean isPrivate = link.getLinkType() == LinkType.COMPOSITION;
final Step lastStep = link.getPath().getStep(-1);
assert lastStep.isForeign();
final String lastFF = lastStep.getSingleField().getName();
if (link.isJoin()) {
ownedRows = new ArrayList<T>();
for (final SQLRowValues withFK : ((SQLRowValues) this.getRow()).followPath(link.getPath().minusLast(), CreateMode.CREATE_NONE, false)) {
assert !withFK.isForeignEmpty(lastFF) : "Empty join row";
final SQLRowAccessor ownedRow = withFK.getForeign(lastStep.getSingleLink());
assert ownedRow != null;
assert !isPrivate || ownedRow instanceof SQLRowValues : "Incomplete private graph";
ownedRows.add(clazz.cast(ownedRow));
}
} else {
if (this.getRow().isForeignEmpty(lastFF)) {
ownedRows = Collections.emptyList();
} else {
final SQLRowAccessor foreign = this.getRow().getForeign(lastFF);
ownedRows = Collections.singletonList(clazz.cast(foreign));
assert !isPrivate || foreign instanceof SQLRowValues : "Incomplete private graph";
}
}
}
return ownedRows;
}
 
public final List<Object> getOwnedObjects(final SQLElementLink link) {
return this.getOwnedObjects(link, Object.class);
}
 
public final <T> List<T> getOwnedObjects(final SQLElementLink link, final Class<T> clazz) {
if (link.getOwner() != this.getElement())
throw new IllegalArgumentException("Wrong link " + link);
if (!link.getOwned().canCreateModelObject())
throw new IllegalStateException("Cannot create model objects, perhaps use getOwnedRows()");
 
final List<SQLRowAccessor> ownedRows = this.getOwnedRows(link);
final List<T> modelObjects;
// non-private might already be fetched, but we can't be sure that
// it's complete
if (this.hasGraph() && link.getLinkType() != LinkType.COMPOSITION) {
final List<Number> ids = new ArrayList<Number>();
for (final SQLRowAccessor r : ownedRows) {
ids.add(r.getIDNumber());
}
modelObjects = new ArrayList<T>(link.getOwned().fetchModelObjects(ids, clazz).values());
} else {
modelObjects = new ArrayList<T>();
for (final SQLRowAccessor r : ownedRows) {
modelObjects.add(clazz.cast(link.getOwned().getModelObject(r)));
}
}
return modelObjects;
}
 
public final SQLTable getTable() {
return this.getRow().getTable();
}
137,6 → 233,11
return this.r;
}
 
// public since it is immutable
public final SQLRowValues getSQLRowValues() {
return (SQLRowValues) this.getRow();
}
 
public final SQLRow getSQLRow() {
return this.getRow().asRow();
}
145,20 → 246,18
return getRow().getID();
}
 
public RowBacked getParent() {
final SQLRowAccessor parent = this.getRow().getForeign(this.getElement().getParentForeignFieldName());
return (RowBacked) getModelObject(parent);
private final RowBacked getModelObject(final SQLElement elem, final Number id) {
return (RowBacked) (this.hasGraph() ? elem.fetchModelObject(id) : elem.getModelObject(elem.getTable().getRow(id.intValue())));
}
 
private final SQLElement getElement() {
return getElement(this.getTable());
public RowBacked getParent() {
final SQLElement parentElem = this.getElement().getParentLink().getParent();
// fetchContainer() returns a row with only keys.
final SQLRowValues parentID = this.getElement().fetchContainer(this.getRow());
return getModelObject(parentElem, parentID.getIDNumber());
}
 
private static final SQLElement getElement(SQLTable t) {
return Configuration.getInstance().getDirectory().getElement(t);
public final SQLElement getElement() {
return this.elem;
}
 
private static Object getModelObject(final SQLRowAccessor r) {
return getElement(r.getTable()).getModelObject(r);
}
}
/trunk/OpenConcerto/src/org/openconcerto/sql/element/GlobalMapper.java
41,7 → 41,9
List<String> l = objectsToIds.get(obj);
if (l == null) {
l = new ArrayList<String>(3);
objectsToIds.put(obj, l);
l.add(id);
objectsToIds.put(obj, l);
} else if (!l.contains(obj)) {
l.add(id);
}
/trunk/OpenConcerto/src/org/openconcerto/sql/element/ArchivedGraph.java
13,6 → 13,7
package org.openconcerto.sql.element;
 
import org.openconcerto.sql.element.SQLElement.PrivateMode;
import org.openconcerto.sql.element.SQLElementLink.LinkType;
import org.openconcerto.sql.model.SQLField;
import org.openconcerto.sql.model.SQLRow;
92,7 → 93,7
for (final Entry<SQLTable, Set<Number>> e : idsToExpandPrivate.entrySet()) {
final SQLElement elem = getElement(e.getKey());
final Set<Number> ids = e.getValue();
final SQLRowValues privateGraph = elem.getPrivateGraph(ARCHIVE_AND_FOREIGNS, false, true);
final SQLRowValues privateGraph = elem.createGraph(ARCHIVE_AND_FOREIGNS, PrivateMode.ALL_PRIVATES, true);
// if the element has privates or joins to expand
if (privateGraph.getGraphSize() > 1) {
// fetch the main row and its privates
274,7 → 275,7
assert prev == null : "Duplicate " + row + " in " + this.graph.printGraph();
// rows were fetched from a different link
if (privateToFetch != null)
privateToFetch.remove(v.getTable(), v.getIDNumber());
privateToFetch.removeOne(v.getTable(), v.getIDNumber());
}
existingRow.put(step, graphToAdd);
assert isIndexCoherent();
309,7 → 310,7
final SQLRowValuesListFetcher fetcher;
// don't fetch partial data
if (!elem.isPrivate())
fetcher = SQLRowValuesListFetcher.create(elem.getPrivateGraph(ARCHIVE_AND_FOREIGNS, false, true));
fetcher = SQLRowValuesListFetcher.create(elem.createGraph(ARCHIVE_AND_FOREIGNS, PrivateMode.ALL_PRIVATES, true));
else
// only needs IDs
fetcher = new SQLRowValuesListFetcher(new SQLRowValues(table).putNulls(table.getFieldsNames(VirtualFields.ARCHIVE)));
/trunk/OpenConcerto/src/org/openconcerto/sql/element/UpdateScript.java
29,6 → 29,7
import java.sql.SQLException;
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
282,4 → 283,32
else
return null;
}
 
public final Map<RowModifType, Integer> getModifTypesCount() {
return this.getModifTypesCount(true, false);
}
 
public final Map<RowModifType, Integer> getModifTypesCount(final boolean includeNone, final boolean includeZero) {
final Map<RowModifType, Integer> res = new HashMap<RowModifType, Integer>();
res.put(RowModifType.DELETION, this.toDelete.allValues().size());
res.put(RowModifType.ARCHIVAL, this.toArchive.allValues().size());
res.put(RowModifType.MODIFICATION, 0);
res.put(RowModifType.INSERTION, 0);
if (includeNone)
res.put(RowModifType.NONE, 0);
for (final SQLRowValues v : this.getTarget().getGraph().getItems()) {
final RowModifType m = this.getStoredValues(v).get0();
if (includeNone || m != RowModifType.NONE)
res.put(m, res.get(m) + 1);
}
if (!includeZero) {
final Iterator<Entry<RowModifType, Integer>> iter = res.entrySet().iterator();
while (iter.hasNext()) {
final Entry<RowModifType, Integer> e = iter.next();
if (e.getValue().equals(0))
iter.remove();
}
}
return res;
}
}
/trunk/OpenConcerto/src/org/openconcerto/sql/element/JoinSQLElement.java
20,6 → 20,7
import org.openconcerto.sql.model.graph.Path;
import org.openconcerto.sql.model.graph.PathBuilder;
import org.openconcerto.sql.model.graph.SQLKey;
import org.openconcerto.sql.model.graph.Step;
import org.openconcerto.sql.utils.SQLCreateTable;
import org.openconcerto.utils.Tuple2.List2;
 
26,6 → 27,7
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
 
/**
104,13 → 106,38
 
protected abstract void addForeignColumns(final SQLCreateTable res, final String toOwnerFK, final String toOwnedFK);
 
public final SQLCreateTable getCreateTable() {
protected final SQLCreateTable setupCreateTable(final SQLCreateTable res) {
final List2<String> fks = getFKs();
final SQLCreateTable res = new SQLCreateTable(this.getOwnerRoot(), this.tableName);
this.addForeignColumns(res, fks.get0(), fks.get1());
final String toOwner = fks.get0();
// don't require uniqueness across the whole table
res.setOrderConstraintFields(Collections.singleton(toOwner));
this.addForeignColumns(res, toOwner, fks.get1());
res.addVarCharColumn("LABEL", 100);
return res;
}
 
public final SQLCreateTable getCreateTable() {
return setupCreateTable(new SQLCreateTable(this.getOwnerRoot(), this.getTableName()));
}
 
public final SQLTable getJoinTable() {
return this.getOwnerRoot().getTable(this.getTableName());
}
 
public final JoinSQLElement createElement() {
return new JoinSQLElement(getJoinTable(), getFKs().get0());
}
 
public final SQLTable buildTable() throws SQLException {
return this.getOwnerRoot().createTable(getCreateTable());
}
 
public final JoinSQLElement buildElement() throws SQLException {
final SQLTable joinT = this.buildTable();
final JoinSQLElement res = createElement();
assert res.getTable() == joinT;
return res;
}
}
 
static public final class SQLTableBuilder extends Builder<SQLTableBuilder> {
147,11 → 174,6
res.addForeignColumn(toOwnerFK, this.ownerT);
res.addForeignColumn(toOwnedFK, this.ownedT);
}
 
public final JoinSQLElement buildElement() throws SQLException {
final SQLTable joinT = this.getOwnerRoot().createTable(getCreateTable());
return new JoinSQLElement(joinT, getFKs().get0());
}
}
 
static private final class CreateTableBuilder extends Builder<CreateTableBuilder> {
213,7 → 235,7
return new List2<Link>(linkToOwner, index == 0 ? fks.get(1) : fks.get(0));
}
 
public final Link getLinkToOwner() {
final Link getLinkToOwner() {
return this.links.get0();
}
 
221,7 → 243,11
return this.getLinkToOwner().getTarget();
}
 
public final Link getLinkToOwned() {
public final Step getStepFromOwner() {
return this.getPathFromOwner().getStep(0);
}
 
final Link getLinkToOwned() {
return this.links.get1();
}
 
229,7 → 255,12
return this.getLinkToOwned().getTarget();
}
 
public final Link getOppositeLink(final Link l) {
public final Step getStepToOwned() {
return this.getPathFromOwner().getStep(1);
}
 
// MAYBE remove (and even have the path as the only instance variable)
final Link getOppositeLink(final Link l) {
final Link l1 = this.links.get0();
final Link l2 = this.links.get1();
if (l1.equals(l)) {
249,6 → 280,16
return this.p;
}
 
/**
* Return the link going through this element.
*
* @return the link following {@link #getPathFromOwner()}.
*/
public final SQLElementLink getJoinLink() {
// don't store this as getDirectory() can change
return this.getDirectory().getElement(this.getOwnerTable()).getOwnedLinks().getByPath(getPathFromOwner());
}
 
// define methods with final
 
@Override
/trunk/OpenConcerto/src/org/openconcerto/sql/element/SQLComponentItem.java
16,8 → 16,8
import org.openconcerto.sql.request.SQLRowItemView;
 
/**
* If the component of a SQLRowItemView implement that, it will be passed its {@link SQLComponent}
* and its initialized {@link SQLRowItemView}.
* If a SQLRowItemView or its {@link SQLRowItemView#getComp() component} implement this interface,
* it will be passed its {@link SQLComponent} and its initialized {@link SQLRowItemView}.
*
* @author Sylvain CUAZ
* @see SQLRowItemView#getComp()
/trunk/OpenConcerto/src/org/openconcerto/sql/element/TreesOfSQLRows.java
16,6 → 16,7
import org.openconcerto.sql.Configuration;
import org.openconcerto.sql.Log;
import org.openconcerto.sql.TM;
import org.openconcerto.sql.element.SQLElement.PrivateMode;
import org.openconcerto.sql.element.SQLElement.ReferenceAction;
import org.openconcerto.sql.element.SQLElementLink.LinkType;
import org.openconcerto.sql.model.FieldRef;
229,7 → 230,7
final Map<SQLRow, SQLRowValues> res = new HashMap<SQLRow, SQLRowValues>();
 
// fetch privates of root rows
final SQLRowValues privateGraph = this.getElem().getPrivateGraph(ArchivedGraph.ARCHIVE_AND_FOREIGNS, false, true);
final SQLRowValues privateGraph = this.getElem().createGraph(ArchivedGraph.ARCHIVE_AND_FOREIGNS, PrivateMode.ALL_PRIVATES, true);
final NextRows privates = new NextRows(hasBeen, toCut);
// always fetch to have up to date values, and behave the same way whether the element has
// privates or not
318,7 → 319,7
// otherwise we would need to find and expand the parent rows of referents
if (refElem.isPrivate())
throw new UnsupportedOperationException("Cannot cascade to private element " + refElem + " from " + elemPath);
graphToFetch = refElem.getPrivateGraph(ArchivedGraph.ARCHIVE_AND_FOREIGNS, false, true);
graphToFetch = refElem.createGraph(ArchivedGraph.ARCHIVE_AND_FOREIGNS, PrivateMode.ALL_PRIVATES, true);
} else {
graphToFetch = new SQLRowValues(pathToTableWithFK.getFirst());
}
665,4 → 666,9
checkFetched();
return this.externReferences;
}
@Override
public String toString() {
return this.getClass().getSimpleName() + " for " + this.getElem() + " " + this.getRows();
}
}
/trunk/OpenConcerto/src/org/openconcerto/sql/translation/messages_fr.properties
25,9 → 25,11
contains=Contient
contains.exactly=Contient exactement
isLessThan=Est inférieur à
isLessThanOrEqualTo=Est inférieur ou égal à
isEqualTo=Est égal à
isExactlyEqualTo=Est exactement égal à
isGreaterThan=Est supérieur à
isGreaterThanOrEqualTo=Est supérieur ou égal à
isEmpty=Est vide
 
clone.newPlace=Nouvel emplacement (optionnel) :
/trunk/OpenConcerto/src/org/openconcerto/sql/translation/messages_en.properties
25,9 → 25,11
contains=Contains
contains.exactly=Contains exactly
isLessThan=Is less than
isLessThanOrEqualTo=Is less than or equal to
isEqualTo=Is equal to
isExactlyEqualTo=Is exactly equal to
isGreaterThan=Is greater than
isGreaterThanOrEqualTo=Is greater than or equal to
isEmpty=Is empty
 
clone.newPlace=New location (optional) :
/trunk/OpenConcerto/src/org/openconcerto/sql/utils/SQLCreateTableBase.java
107,7 → 107,7
return this.asString(transf, step.getTypes());
case ADD_INDEX:
case ADD_CONSTRAINT:
return new AlterTable(getSyntax(), getRootName(), getName()).mutateTo(this).asString(transf, step);
return new AlterTable(getSyntax(), getRootName(), getName()).asString(this.getClauses(), transf, step.getTypes());
default:
return null;
}
124,7 → 124,9
tableName = transformedName;
}
 
final List<String> genClauses = this.getClauses(tableName, transf, types);
final InAndOutClauses clauses = this.getClauses();
 
final List<String> genClauses = clauses.getInClauses().getClauses(this, tableName, transf, types);
if (genClauses.size() > 0) {
if (this.tmp) {
res.append("CREATE TEMPORARY TABLE ");
138,21 → 140,21
res.append(";");
}
 
this.outClausesAsString(res, tableName, types);
clauses.getOutClauses().appendTo(res, this, tableName, transf, types);
 
return res.toString();
}
 
@Override
protected void modifyClauses(final List<String> genClauses, final NameTransformer transf, final ClauseType type) {
super.modifyClauses(genClauses, transf, type);
if (type == ClauseType.ADD_COL && this.pk.size() > 0) {
genClauses.add("PRIMARY KEY (" + CollectionUtils.join(this.pk, ",", new ITransformer<String, String>() {
protected void modifyClauses(InAndOutClauses res) {
super.modifyClauses(res);
if (this.pk.size() > 0) {
res.getInClauses().addClause("PRIMARY KEY (" + CollectionUtils.join(this.pk, ",", new ITransformer<String, String>() {
@Override
public String transformChecked(String input) {
return SQLBase.quoteIdentifier(input);
}
}) + ")");
}) + ")", ClauseType.ADD_COL);
}
}
}
/trunk/OpenConcerto/src/org/openconcerto/sql/utils/UniqueConstraintCreatorHelper.java
Nouveau fichier
0,0 → 1,61
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.sql.utils;
 
import org.openconcerto.sql.model.SQLSyntax;
 
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
 
/**
* Allow to pass additional data to
* {@link ChangeTable#addUniqueConstraint(String, UniqueConstraintCreatorHelper)} than just the
* columns and the where.
*
* @author sylvain
*/
public class UniqueConstraintCreatorHelper {
 
private final List<String> columns;
private final String where;
private final String comment;
 
public UniqueConstraintCreatorHelper(List<String> columns, String where) {
this(columns, where, null);
}
 
public UniqueConstraintCreatorHelper(List<String> columns, String where, final String comment) {
super();
this.columns = Collections.unmodifiableList(new ArrayList<String>(columns));
this.where = where;
this.comment = comment;
}
 
public final List<String> getColumns() {
return this.columns;
}
 
public final String getWhere() {
return this.where;
}
 
public final String getComment() {
return this.comment;
}
 
public Object getObject(final SQLSyntax s) {
return null;
}
}
/trunk/OpenConcerto/src/org/openconcerto/sql/utils/SQLCreateTable.java
20,8 → 20,12
import org.openconcerto.sql.model.SQLTable;
import org.openconcerto.sql.model.graph.SQLKey;
 
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
 
/**
* Construct an CREATE TABLE statement with an ID, a field archive and order.
32,6 → 36,7
 
private final DBRoot b;
private boolean createID, createOrder, createArchive;
private List<String> orderConstraintFields;
 
public SQLCreateTable(final DBRoot b, final String name) {
super(b.getDBSystemRoot().getSyntax(), b.getName(), name);
43,6 → 48,7
public void reset() {
super.reset();
this.setPlain(false);
this.orderConstraintFields = Collections.singletonList(SQLSyntax.ORDER_NAME);
}
 
public final DBRoot getRoot() {
76,6 → 82,19
this.createOrder = createOrder;
}
 
public final void setOrderConstraintFields(final Collection<String> fields) {
final Set<String> set = new LinkedHashSet<>(fields);
final List<String> list;
if (!set.contains(SQLSyntax.ORDER_NAME)) {
list = new ArrayList<>(set.size() + 1);
list.add(SQLSyntax.ORDER_NAME);
list.addAll(set);
} else {
list = new ArrayList<>(set);
}
this.orderConstraintFields = Collections.unmodifiableList(list);
}
 
public final boolean isCreateArchive() {
return this.createArchive;
}
108,29 → 127,21
}
 
@Override
protected void modifyClauses(final List<String> genClauses, final NameTransformer transf, final ClauseType type) {
super.modifyClauses(genClauses, transf, type);
if (type == ClauseType.ADD_COL) {
if (this.isCreateID())
genClauses.add(0, SQLBase.quoteIdentifier(SQLSyntax.ID_NAME) + this.getSyntax().getPrimaryIDDefinition());
if (this.isCreateArchive())
genClauses.add(SQLBase.quoteIdentifier(SQLSyntax.ARCHIVE_NAME) + this.getSyntax().getArchiveDefinition());
if (this.isCreateOrder()) {
// MS unique constraint is not standard so add it in modifyOutClauses()
if (getSyntax().getSystem() == SQLSystem.MSSQL) {
genClauses.add(SQLBase.quoteIdentifier(SQLSyntax.ORDER_NAME) + this.getSyntax().getOrderType() + " DEFAULT " + this.getSyntax().getOrderDefault());
} else {
genClauses.add(SQLBase.quoteIdentifier(SQLSyntax.ORDER_NAME) + this.getSyntax().getOrderDefinition());
}
protected void modifyClauses(InAndOutClauses res) {
super.modifyClauses(res);
if (this.isCreateID())
res.getInClauses().addClause(0, SQLBase.quoteIdentifier(SQLSyntax.ID_NAME) + this.getSyntax().getPrimaryIDDefinition(), ClauseType.ADD_COL);
if (this.isCreateArchive())
res.getInClauses().addClause(SQLBase.quoteIdentifier(SQLSyntax.ARCHIVE_NAME) + this.getSyntax().getArchiveDefinition(), ClauseType.ADD_COL);
if (this.isCreateOrder()) {
// add constraint below
res.getInClauses().addClause(SQLBase.quoteIdentifier(SQLSyntax.ORDER_NAME) + this.getSyntax().getOrderDefinition(false), ClauseType.ADD_COL);
// TODO addUniqueConstraint() in superclass should add to an InAndOutClauses
if (getSyntax().getSystem() == SQLSystem.MSSQL) {
res.getOutClauses().addClause(this.createUniquePartialIndex("orderIdx", this.orderConstraintFields, null));
} else {
res.getInClauses().addClause(this.createUniqueConstraint("orderUniq", this.orderConstraintFields));
}
}
}
 
@Override
protected void modifyOutClauses(final List<DeferredClause> clauses, final ClauseType type) {
super.modifyOutClauses(clauses, type);
if (type == ClauseType.ADD_CONSTRAINT && this.isCreateOrder() && getSyntax().getSystem() == SQLSystem.MSSQL) {
clauses.add(this.createUniquePartialIndex("orderIdx", Collections.singletonList(SQLSyntax.ORDER_NAME), null));
}
}
}
/trunk/OpenConcerto/src/org/openconcerto/sql/utils/PartialUniqueTrigger.java
23,15 → 23,16
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
 
import net.jcip.annotations.GuardedBy;
 
import org.h2.api.Trigger;
import org.h2.util.StringUtils;
 
import net.jcip.annotations.GuardedBy;
 
public class PartialUniqueTrigger implements Trigger {
 
private final List<String> columns;
46,7 → 47,7
 
public PartialUniqueTrigger(List<String> columns, String where) {
super();
this.columns = new ArrayList<String>(columns);
this.columns = Collections.unmodifiableList(new ArrayList<String>(columns));
this.indexes = null;
if (where == null)
throw new IllegalArgumentException("Should be using a real index");
53,6 → 54,14
this.where = where;
}
 
public final List<String> getColumns() {
return this.columns;
}
 
public final String getWhere() {
return this.where;
}
 
@Override
public void init(Connection conn, String schemaName, String triggerName, String tableName, boolean before, int type) throws SQLException {
if (before)
/trunk/OpenConcerto/src/org/openconcerto/sql/utils/ChangeTable.java
41,13 → 41,14
import java.util.Collection;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Set;
import java.util.regex.Pattern;
 
import org.h2.api.Trigger;
 
/**
* Construct a statement about a table.
*
63,6 → 64,10
 
// group 1 is the columns, group 2 the where
public static final Pattern H2_UNIQUE_TRIGGER_PATTERN = Pattern.compile("\\snew " + PartialUniqueTrigger.class.getName() + "\\(\\s*java.util.Arrays.asList\\((.+)\\)\\s*,(.+)\\)");
// group 1 is the class name, e.g. CALL
// "org.openconcerto.sql.utils.ChangeTableTest$Test_PartialUniqueTrigger"
public static final String H2_UNIQUE_TRIGGER_CLASS_SUFFIX = "_" + PartialUniqueTrigger.class.getSimpleName();
public static final Pattern H2_UNIQUE_TRIGGER_CLASS_PATTERN = Pattern.compile("CALL\\s+\"(.*" + Pattern.quote(H2_UNIQUE_TRIGGER_CLASS_SUFFIX) + ")\"");
public static final Pattern H2_LIST_PATTERN = Pattern.compile("\\s*,\\s*");
 
public static final String MYSQL_TRIGGER_SUFFIX_1 = getTriggerSuffix(TRIGGER_EVENTS[0]);
92,15 → 97,35
}
 
public static enum ClauseType {
ADD_COL, ADD_CONSTRAINT, ADD_INDEX, DROP_COL, DROP_CONSTRAINT, DROP_INDEX, ALTER_COL, OTHER
ADD_COL, ADD_CONSTRAINT, ADD_INDEX, DROP_COL, DROP_CONSTRAINT, DROP_INDEX, ALTER_COL,
/**
* e.g. SET COMMENT.
*/
OTHER,
/**
* e.g. DROP TRIGGER.
*/
OTHER_DROP,
/**
* e.g. CREATE TRIGGER.
*/
OTHER_ADD;
}
 
public static enum ConcatStep {
// *_CONSTRAINT must be steps to allow to insert rows in different tables that references
// each other.
// *_INDEX should be steps to avoid constantly updating the index when inserting many rows.
 
// drop constraints first since, at least in pg, they depend on indexes
DROP_CONSTRAINT(ClauseType.DROP_CONSTRAINT),
// drop indexes before columns to avoid having to know if the index is dropped because its
// columns are dropped
DROP_INDEX(ClauseType.DROP_INDEX), ALTER_TABLE(ClauseType.ADD_COL, ClauseType.DROP_COL, ClauseType.ALTER_COL, ClauseType.OTHER),
DROP_INDEX(ClauseType.DROP_INDEX),
// drop first to allow to drop and re-create, DROP_COL last of DROP clauses since a column
// doesn't depend on anything (likewise ADD_COL first of ADD clauses), ALTER_COL & OTHER at
// the end to allow to use new fields
ALTER_TABLE(ClauseType.OTHER_DROP, ClauseType.DROP_COL, ClauseType.ADD_COL, ClauseType.OTHER_ADD, ClauseType.ALTER_COL, ClauseType.OTHER),
// likewise add indexes before since constraints need them
ADD_INDEX(ClauseType.ADD_INDEX), ADD_CONSTRAINT(ClauseType.ADD_CONSTRAINT);
 
107,7 → 132,7
private final Set<ClauseType> types;
 
private ConcatStep(ClauseType... types) {
this.types = new HashSet<ClauseType>();
this.types = new LinkedHashSet<ClauseType>();
for (final ClauseType t : types)
this.types.add(t);
}
394,12 → 419,135
}
}
 
static protected final class Clauses {
private final ListMap<ClauseType, DeferredGeneralClause> clauses;
 
Clauses() {
this.clauses = new ListMap<>();
}
 
Clauses(final Clauses clauses) {
this.clauses = new ListMap<>(clauses.clauses);
}
 
public void reset() {
this.clauses.clear();
}
 
public final void addClause(final String s, final ClauseType type) {
this.addClause(-1, s, type);
}
 
public final void addClause(final int index, final String s, final ClauseType type) {
this.addClause(index, new DeferredGeneralClause() {
@Override
public ClauseType getType() {
return type;
}
 
@Override
public String asString(ChangeTable<?> ct, SQLName tableName, NameTransformer transf) {
return s;
}
});
}
 
public final void addClause(final DeferredGeneralClause s) {
this.addClause(-1, s);
}
 
public final void addClause(final int index, final DeferredGeneralClause s) {
if (s != null) {
if (index < 0) {
this.clauses.add(s.getType(), s);
} else {
this.clauses.addAll(s.getType(), Collections.<DeferredGeneralClause> emptyList());
this.clauses.get(s.getType()).add(index, s);
}
}
}
 
public final void addAllClauses(List<DeferredGeneralClause> clauses) {
for (final DeferredGeneralClause c : clauses) {
this.addClause(c);
}
}
 
private final List<String> getClauses(final ChangeTable<?> ct, final SQLName tableName, final NameTransformer transf, final Set<ClauseType> types, final String intraTypeSep) {
final ITransformer<DeferredGeneralClause, String> tf = new ITransformer<DeferredGeneralClause, String>() {
@Override
public String transformChecked(DeferredGeneralClause input) {
return input.asString(ct, tableName, transf);
}
};
final List<String> res = new ArrayList<String>();
for (final ClauseType type : ORDERED_TYPES) {
if (types.contains(type)) {
final List<DeferredGeneralClause> clauses = this.clauses.getNonNull(type);
if (clauses.size() > 0) {
if (intraTypeSep == null) {
for (final DeferredGeneralClause c : clauses) {
res.add(tf.transformChecked(c));
}
} else {
res.add(CollectionUtils.join(clauses, intraTypeSep, tf));
}
}
}
}
return res;
}
 
// all clauses, not grouped
protected final List<String> getClauses(final ChangeTable<?> ct, final SQLName tableName, final NameTransformer transf, final Set<ClauseType> types) {
return this.getClauses(ct, tableName, transf, types, null);
}
 
protected final void appendTo(final StringBuffer res, final ChangeTable<?> ct, final SQLName tableName, final NameTransformer transf, final Set<ClauseType> types) {
final List<String> outClauses = this.getClauses(ct, tableName, transf, types);
if (outClauses.size() > 0) {
res.append("\n\n");
res.append(CollectionUtils.join(outClauses, "\n"));
}
}
}
 
static protected final class InAndOutClauses {
private final Clauses inClauses;
private final Clauses outClauses;
 
protected InAndOutClauses() {
this.inClauses = new Clauses();
this.outClauses = new Clauses();
}
 
protected InAndOutClauses(final InAndOutClauses c) {
this.inClauses = new Clauses(c.inClauses);
this.outClauses = new Clauses(c.outClauses);
}
 
public void reset() {
this.inClauses.reset();
this.outClauses.reset();
}
 
public boolean isEmpty() {
return this.inClauses.clauses.isEmpty() && this.outClauses.clauses.isEmpty();
}
 
public Clauses getInClauses() {
return this.inClauses;
}
 
public Clauses getOutClauses() {
return this.outClauses;
}
}
 
private String rootName, name;
private final SQLSyntax syntax;
private final List<FCSpec> fks;
private final ListMap<ClauseType, String> clauses;
private final ListMap<ClauseType, DeferredClause> inClauses;
private final ListMap<ClauseType, DeferredClause> outClauses;
private final InAndOutClauses clauses;
 
public ChangeTable(final SQLSyntax syntax, final String rootName, final String name) {
super();
407,9 → 555,7
this.rootName = rootName;
this.name = name;
this.fks = new ArrayList<FCSpec>();
this.clauses = new ListMap<ClauseType, String>();
this.inClauses = new ListMap<ClauseType, DeferredClause>();
this.outClauses = new ListMap<ClauseType, DeferredClause>();
this.clauses = new InAndOutClauses();
 
// check that (T) this; will succeed
if (this.getClass() != ReflectUtils.getTypeArguments(this, ChangeTable.class).get(0))
432,36 → 578,13
*/
public void reset() {
this.fks.clear();
this.clauses.clear();
this.inClauses.clear();
this.outClauses.clear();
this.clauses.reset();
}
 
public boolean isEmpty() {
return this.fks.isEmpty() && this.clauses.isEmpty() && this.inClauses.isEmpty() && this.outClauses.isEmpty();
return this.fks.isEmpty() && this.clauses.isEmpty();
}
 
protected T mutateTo(ChangeTable<?> ct) {
if (this.getSyntax() != ct.getSyntax())
throw new IllegalArgumentException("not same syntax: " + this.getSyntax() + " != " + ct.getSyntax());
this.setName(ct.getName());
for (final Entry<ClauseType, ? extends Collection<String>> e : ct.clauses.entrySet()) {
for (final String s : e.getValue())
this.addClause(s, e.getKey());
}
for (final DeferredClause c : ct.inClauses.allValues()) {
this.addClause(c);
}
for (final DeferredClause c : ct.outClauses.allValues()) {
this.addOutsideClause(c);
}
for (final FCSpec fk : ct.fks) {
// don't create index, it is already added in outside clause
this.addForeignConstraint(fk, false);
}
return thisAsT();
}
 
/**
* Adds a varchar column not null and with '' as the default.
*
661,7 → 784,7
// automatically created indexes are automatically dropped ; so if we added one here we
// would need to drop it in AlterTable.dropColumn()
if (createIndex && !getSyntax().getSystem().autoCreatesFKIndex())
this.addOutsideClause(new OutsideClause() {
this.addOutsideClause(new DeferredClause() {
@Override
public ClauseType getType() {
return ClauseType.ADD_INDEX;
668,8 → 791,8
}
 
@Override
public String asString(SQLName tableName) {
return getSyntax().getCreateIndex("_fki", tableName, fkSpec.getCols());
public String asString(ChangeTable<?> ct, SQLName tableName) {
return ct.getSyntax().getCreateIndex("_fki", tableName, fkSpec.getCols());
}
});
return thisAsT();
783,11 → 906,35
*
* @param name name of the constraint.
* @param cols the columns of the constraint, e.g. ["DESIGNATION"].
* @param where an optional where to limit the rows checked, can be <code>null</code>, e.g.
* "not ARCHIVED".
* @param where an optional where to limit the rows checked, can be <code>null</code>, e.g. "not
* ARCHIVED".
* @return this.
*/
public T addUniqueConstraint(final String name, final List<String> cols, final String where) {
return this.addUniqueConstraint(name, cols, where, null);
}
 
/**
* Add a unique constraint with additional data than the other methods. On {@link SQLSystem#H2}
* {@link UniqueConstraintCreatorHelper#getObject(SQLSyntax)} should return a {@link Trigger}
* class to be used instead of requiring to compile Java source code. The class name must end
* with {@value #H2_UNIQUE_TRIGGER_CLASS_SUFFIX} (needed so that {@link SQLTable} can recognize
* it).
*
* @param name name of the constraint.
* @param c data about the constraint.
* @return this.
* @see #addUniqueConstraint(String, List, String)
*/
public T addUniqueConstraint(final String name, final UniqueConstraintCreatorHelper c) {
return this.addUniqueConstraint(name, c.getColumns(), c.getWhere(), c);
}
 
private T addUniqueConstraint(final String name, final List<String> cols, final String where, final UniqueConstraintCreatorHelper c) {
assert c == null || c.getWhere() == where;
assert c == null || c.getColumns() == cols;
final String comment = c == null ? null : c.getComment();
 
final int size = cols.size();
if (size == 0)
throw new IllegalArgumentException("No cols");
796,75 → 943,57
if (system == SQLSystem.MSSQL) {
return this.addOutsideClause(createUniquePartialIndex(name, cols, where));
} else if (where == null) {
return this.addClause(new DeferredClause() {
@Override
public String asString(ChangeTable<?> ct, SQLName tableName) {
return ct.getConstraintPrefix() + "CONSTRAINT " + getQuotedConstraintName(tableName, name) + " UNIQUE (" + SQLSyntax.quoteIdentifiers(cols) + ")";
}
 
@Override
public ClauseType getType() {
return ClauseType.ADD_CONSTRAINT;
}
});
return this.addClause(createUniqueConstraint(name, cols));
} else if (system == SQLSystem.POSTGRESQL) {
return this.addOutsideClause(createUniquePartialIndex(name, cols, where));
} else if (system == SQLSystem.H2) {
// initial select to check uniqueness
if (checkExistingUniqueness()) {
// TODO should implement SIGNAL instead of abusing CSVREAD
this.addOutsideClause(new DeferredClause() {
final String body;
final Class<?> h2TriggerClass = c == null ? null : (Class<?>) c.getObject(getSyntax());
if (h2TriggerClass == null) {
final String javaWhere = StringUtils.doubleQuote(where);
final String javaCols = "java.util.Arrays.asList(" + CollectionUtils.join(cols, ", ", new ITransformer<String, String>() {
@Override
public ClauseType getType() {
return ClauseType.OTHER;
public String transformChecked(final String col) {
return StringUtils.doubleQuote(col);
}
 
@Override
public String asString(ChangeTable<?> ct, SQLName tableName) {
final String select = getInitialCheckSelect(cols, where, tableName);
return "SELECT CASE WHEN (" + select + ") > 0 then CSVREAD('Unique constraint violation') else 'OK' end case;";
}
});
}) + ")";
body = "AS $$ org.h2.api.Trigger create(){ return new " + PartialUniqueTrigger.class.getName() + "(" + javaCols + ", " + javaWhere + "); } $$";
assert H2_UNIQUE_TRIGGER_PATTERN.matcher(body).find();
} else {
PartialUniqueTrigger h2Trigger;
try {
h2Trigger = (PartialUniqueTrigger) h2TriggerClass.newInstance();
} catch (Exception e) {
throw new IllegalArgumentException("Couldn't instantiate " + h2TriggerClass, e);
}
if (!h2Trigger.getColumns().equals(cols) || !Objects.equals(SQLTable.workAroundForH2WhereTrigger(h2Trigger.getWhere()), SQLTable.workAroundForH2WhereTrigger(where)))
throw new IllegalArgumentException("Wrong parameters returned by " + h2TriggerClass);
if (!h2TriggerClass.getSimpleName().endsWith(H2_UNIQUE_TRIGGER_CLASS_SUFFIX))
throw new IllegalArgumentException("Class name invalid, must end by \'" + H2_UNIQUE_TRIGGER_CLASS_SUFFIX + "\' : " + h2TriggerClass);
body = "CALL " + SQLBase.quoteIdentifier(h2TriggerClass.getName());
// already checked above
assert H2_UNIQUE_TRIGGER_CLASS_PATTERN.matcher(body).find();
}
final String javaWhere = StringUtils.doubleQuote(where);
final String javaCols = "java.util.Arrays.asList(" + CollectionUtils.join(cols, ", ", new ITransformer<String, String>() {
final UniqueTrigger trigger = new UniqueTrigger(name, Arrays.asList(TRIGGER_EVENTS), comment) {
@Override
public String transformChecked(final String col) {
return StringUtils.doubleQuote(col);
}
}) + ")";
final String body = "AS $$ org.h2.api.Trigger create(){ return new " + PartialUniqueTrigger.class.getName() + "(" + javaCols + ", " + javaWhere + "); } $$";
assert H2_UNIQUE_TRIGGER_PATTERN.matcher(body).find();
return this.addOutsideClause(new UniqueTrigger(name, Arrays.asList(TRIGGER_EVENTS)) {
@Override
protected String getBody(SQLName tableName) {
return body;
}
});
} else if (system == SQLSystem.MYSQL) {
 
@Override
protected String getInitialCheckBody(SQLName tableName) {
final String select = getInitialCheckSelect(cols, where, tableName);
// TODO should implement SIGNAL instead of abusing CSVREAD
return "SELECT CASE WHEN (" + select + ") > 0 then CSVREAD('Unique constraint violation') else 'OK' end case;";
}
};
// initial select to check uniqueness
if (checkExistingUniqueness()) {
this.addOutsideClause(new DeferredClause() {
@Override
public ClauseType getType() {
return ClauseType.OTHER;
}
 
@Override
public String asString(ChangeTable<?> ct, SQLName tableName) {
final String procName = SQLBase.quoteIdentifier("checkUniqueness_" + tableName.getName());
String res = "DROP PROCEDURE IF EXISTS " + procName + ";\n";
res += "CREATE PROCEDURE " + procName + "() BEGIN\n";
final String select = getInitialCheckSelect(cols, where, tableName);
// don't put newline right after semicolon to avoid splitting here
res += "IF (" + select + ") > 0 THEN " + MYSQL_TRIGGER_EXCEPTION + "; END IF; \n";
res += "END;\n";
res += "CALL " + procName + ";";
return res;
}
});
this.addOutsideClause(trigger.createInitialCheckClause());
}
final UniqueTrigger trigger = new UniqueTrigger(name, Arrays.asList(TRIGGER_EVENTS[0])) {
return this.addOutsideClause(trigger);
} else if (system == SQLSystem.MYSQL) {
final UniqueTrigger trigger = new UniqueTrigger(name, Arrays.asList(TRIGGER_EVENTS[0]), comment) {
@Override
protected String getBody(final SQLName tableName) {
final String body = "BEGIN IF " + getNotNullWhere(cols, "NEW.") + " THEN\n" +
879,14 → 1008,37
+ "END IF; \n" + "END";
return body;
}
 
@Override
protected String getInitialCheckBody(SQLName tableName) {
final String procName = SQLBase.quoteIdentifier("checkUniqueness_" + tableName.getName());
String res = "DROP PROCEDURE IF EXISTS " + procName + ";\n";
res += "CREATE PROCEDURE " + procName + "() BEGIN\n";
final String select = getInitialCheckSelect(cols, where, tableName);
// don't put newline right after semicolon to avoid splitting here
res += "IF (" + select + ") > 0 THEN " + MYSQL_TRIGGER_EXCEPTION + "; END IF; \n";
res += "END;\n";
res += "CALL " + procName + ";";
return res;
}
};
// initial select to check uniqueness
if (checkExistingUniqueness()) {
this.addOutsideClause(trigger.createInitialCheckClause());
}
 
this.addOutsideClause(trigger);
for (int i = 1; i < TRIGGER_EVENTS.length; i++) {
this.addOutsideClause(new UniqueTrigger(name, Arrays.asList(TRIGGER_EVENTS[i])) {
this.addOutsideClause(new UniqueTrigger(name, Arrays.asList(TRIGGER_EVENTS[i]), comment) {
@Override
protected String getBody(final SQLName tableName) {
return trigger.getBody(tableName);
}
 
@Override
protected String getInitialCheckBody(SQLName tableName) {
return trigger.getInitialCheckBody(tableName);
}
});
}
return thisAsT();
895,6 → 1047,20
}
}
 
protected final DeferredClause createUniqueConstraint(final String name, final List<String> cols) {
return new DeferredClause() {
@Override
public String asString(ChangeTable<?> ct, SQLName tableName) {
return ct.getConstraintPrefix() + "CONSTRAINT " + getQuotedConstraintName(tableName, name) + " UNIQUE (" + SQLSyntax.quoteIdentifiers(cols) + ")";
}
 
@Override
public ClauseType getType() {
return ClauseType.ADD_CONSTRAINT;
}
};
}
 
// can't be inlined with javac 1.6
private boolean checkExistingUniqueness() {
return this instanceof AlterTable;
922,12 → 1088,6
});
}
 
private String getInitialCheckSelect(final List<String> cols, final String where, SQLName tableName) {
final Where notNullWhere = Where.createRaw(getNotNullWhere(cols));
final Where w = Where.and(notNullWhere, Where.createRaw(where));
return "SELECT count(*) FROM " + tableName + " where " + w + " group by " + SQLSyntax.quoteIdentifiers(cols) + " having count(*)>1";
}
 
static protected final String getQuotedConstraintName(final SQLName tableName, final String name) {
return SQLBase.quoteIdentifier(getIndexName(tableName, name));
}
942,20 → 1102,22
return new SQLName(tableName.getItem(-2), SQLSyntax.getSchemaUniqueName(tableName.getName(), indexName + getTriggerSuffix(event)));
}
 
static private abstract class UniqueTrigger implements DeferredClause {
static private abstract class UniqueTrigger extends DeferredClause {
 
private final String indexName;
private final List<String> events;
private final String comment;
 
public UniqueTrigger(String indexName, final List<String> events) {
public UniqueTrigger(String indexName, final List<String> events, final String comment) {
super();
this.indexName = indexName;
this.events = events;
this.comment = comment;
}
 
@Override
public final ClauseType getType() {
return ClauseType.OTHER;
return ClauseType.OTHER_ADD;
}
 
@Override
963,13 → 1125,38
// if there's only one event, it means the system doesn't support multiple so we need to
// get a unique trigger name for each one
final SQLName triggerName = getTriggerName(tableName, this.indexName, CollectionUtils.getSole(this.events));
return "CREATE TRIGGER " + triggerName + " AFTER " + CollectionUtils.join(this.events, ", ") + " on " + tableName + " FOR EACH ROW " + this.getBody(tableName) + ';';
final String createTriggerSQL = "CREATE TRIGGER " + triggerName + " AFTER " + CollectionUtils.join(this.events, ", ") + " on " + tableName + " FOR EACH ROW " + this.getBody(tableName)
+ ';';
return this.comment == null ? createTriggerSQL : "-- " + this.comment + "\n" + createTriggerSQL;
}
 
protected abstract String getBody(SQLName tableName);
 
protected abstract String getInitialCheckBody(SQLName tableName);
 
protected final String getInitialCheckSelect(final List<String> cols, final String where, SQLName tableName) {
final Where notNullWhere = Where.createRaw(getNotNullWhere(cols));
final Where w = Where.and(notNullWhere, Where.createRaw(where));
return "SELECT count(*) FROM " + tableName + " where " + w + " group by " + SQLSyntax.quoteIdentifiers(cols) + " having count(*)>1";
}
 
protected final DeferredClause createInitialCheckClause() {
return new DeferredClause() {
@Override
public ClauseType getType() {
// same type so that this is executed just before
return UniqueTrigger.this.getType();
}
 
@Override
public String asString(ChangeTable<?> ct, SQLName tableName) {
return getInitialCheckBody(tableName);
}
};
}
}
 
static protected final class DropUniqueTrigger implements DeferredClause {
static protected final class DropUniqueTrigger extends DeferredClause {
 
private final String indexName;
private final String event;
986,7 → 1173,7
 
@Override
public final ClauseType getType() {
return ClauseType.OTHER;
return ClauseType.OTHER_DROP;
}
 
@Override
1005,35 → 1192,22
* @return this.
*/
public final T addClause(String s, final ClauseType type) {
this.clauses.add(type, s);
this.clauses.getInClauses().addClause(s, type);
return thisAsT();
}
 
protected final List<String> getClauses(final SQLName tableName, final NameTransformer transf, final ClauseType type) {
final List<String> res = new ArrayList<String>(this.clauses.getNonNull(type));
for (final DeferredClause c : this.inClauses.getNonNull(type))
res.add(c.asString(this, tableName));
this.modifyClauses(res, transf, type);
protected final InAndOutClauses getClauses() {
final InAndOutClauses res = new InAndOutClauses(this.clauses);
this.modifyClauses(res);
return res;
}
 
protected void modifyClauses(final List<String> genClauses, final NameTransformer transf, final ClauseType type) {
if (type == ClauseType.ADD_CONSTRAINT) {
genClauses.addAll(this.getForeignConstraints(transf));
}
protected void modifyClauses(InAndOutClauses res) {
res.getInClauses().addAllClauses(this.getForeignConstraintsClauses());
}
 
protected final List<String> getClauses(final SQLName tableName, final NameTransformer transf, final Collection<ClauseType> types) {
final List<String> res = new ArrayList<String>();
for (final ClauseType type : ORDERED_TYPES) {
if (types.contains(type))
res.addAll(this.getClauses(tableName, transf, type));
}
return res;
}
 
public final T addClause(DeferredClause s) {
this.inClauses.add(s.getType(), s);
this.clauses.getInClauses().addClause(s);
return thisAsT();
}
 
1044,45 → 1218,10
* @return this.
*/
public final T addOutsideClause(DeferredClause s) {
if (s != null)
this.outClauses.add(s.getType(), s);
this.clauses.getOutClauses().addClause(s);
return thisAsT();
}
 
protected final void outClausesAsString(final StringBuffer res, final SQLName tableName, final Set<ClauseType> types) {
final List<String> outClauses = this.getOutClauses(tableName, types);
if (outClauses.size() > 0) {
res.append("\n\n");
res.append(CollectionUtils.join(outClauses, "\n"));
}
}
 
private final List<String> getOutClauses(final SQLName tableName, final Set<ClauseType> types) {
final List<String> res = new ArrayList<String>();
for (final ClauseType type : ORDERED_TYPES) {
if (types.contains(type)) {
final String outClauses = this.getOutClauses(tableName, type);
if (outClauses.length() > 0)
res.add(outClauses);
}
}
return res;
}
 
protected final String getOutClauses(final SQLName tableName, final ClauseType type) {
final List<DeferredClause> clauses = new ArrayList<DeferredClause>(this.outClauses.getNonNull(type));
this.modifyOutClauses(clauses, type);
return CollectionUtils.join(clauses, "\n", new ITransformer<DeferredClause, String>() {
@Override
public String transformChecked(DeferredClause input) {
return input.asString(ChangeTable.this, tableName);
}
});
}
 
protected void modifyOutClauses(final List<DeferredClause> genClauses, final ClauseType type) {
}
 
public final String asString() {
return this.asString(NameTransformer.NOP);
}
1100,13 → 1239,24
 
// [ CONSTRAINT "BATIMENT_ID_SITE_fkey" FOREIGN KEY ("ID_SITE") REFERENCES "SITE"("ID") ON
// DELETE CASCADE; ]
protected final List<String> getForeignConstraints(final NameTransformer transf) {
final List<String> res = new ArrayList<String>(this.fks.size());
protected final List<DeferredGeneralClause> getForeignConstraintsClauses() {
final List<DeferredGeneralClause> res = new ArrayList<>(this.fks.size());
for (final FCSpec fk : this.fks) {
// resolve relative path, a table is identified by root.table
final SQLName relRefTable = fk.getRefTable();
final SQLName refTable = transf.transformLinkDestTableName(getRootName(), getName(), relRefTable);
res.add(getConstraintPrefix() + this.getSyntax().getFK(this.name, fk.getCols(), refTable, fk.getRefCols(), fk.getUpdateRule(), fk.getDeleteRule()));
res.add(new DeferredGeneralClause() {
 
@Override
public ClauseType getType() {
return ClauseType.ADD_CONSTRAINT;
}
 
@Override
public String asString(ChangeTable<?> ct, SQLName tableName, NameTransformer transf) {
// resolve relative path, a table is identified by root.table
final SQLName relRefTable = fk.getRefTable();
final SQLName refTable = transf.transformLinkDestTableName(getRootName(), getName(), relRefTable);
return ct.getConstraintPrefix() + ct.getSyntax().getFK(tableName.getName(), fk.getCols(), refTable, fk.getRefCols(), fk.getUpdateRule(), fk.getDeleteRule());
}
});
}
return res;
}
1128,20 → 1278,21
return this.rootName;
}
 
public static interface DeferredClause {
// not public since the only use of the NameTransformer parameter is for foreign constraints.
// Client code can thus use DeferredClause.
protected static interface DeferredGeneralClause {
// ct necessary because CREATE TABLE( CONSTRAINT ) can become ALTER TABLE ADD CONSTRAINT
// necessary since the full name of the table is only known in #asString(String)
public String asString(final ChangeTable<?> ct, final SQLName tableName);
public String asString(final ChangeTable<?> ct, final SQLName tableName, final NameTransformer transf);
 
public ClauseType getType();
}
 
public static abstract class OutsideClause implements DeferredClause {
public abstract String asString(final SQLName tableName);
public static abstract class DeferredClause implements DeferredGeneralClause {
protected abstract String asString(final ChangeTable<?> ct, final SQLName tableName);
 
@Override
public String asString(ChangeTable<?> ct, SQLName tableName) {
return this.asString(tableName);
public final String asString(final ChangeTable<?> ct, final SQLName tableName, final NameTransformer transf) {
return this.asString(ct, tableName);
}
}
}
/trunk/OpenConcerto/src/org/openconcerto/sql/utils/CreateUser.java
40,9 → 40,8
public final List<String> getStatements(final DBSystemRoot sysRoot) {
final List<String> res = new ArrayList<String>();
final String qName = SQLBase.quoteIdentifier(this.name);
// TODO move SQLBase.quoteString() to DBSystemRoot
final String passKeyWord = sysRoot.getServer().getSQLSystem() == SQLSystem.MYSQL ? " IDENTIFIED BY " : " PASSWORD ";
res.add("CREATE USER " + qName + passKeyWord + SQLBase.quoteStringStd(this.password));
res.add("CREATE USER " + qName + passKeyWord + sysRoot.getSyntax().quoteString(this.password));
res.addAll(this.grant.getStatements(sysRoot));
return res;
}
/trunk/OpenConcerto/src/org/openconcerto/sql/utils/AlterTable.java
23,7 → 23,6
import org.openconcerto.sql.model.SQLTable;
import org.openconcerto.sql.model.graph.Link;
import org.openconcerto.utils.CollectionUtils;
import org.openconcerto.utils.StringUtils;
import org.openconcerto.utils.Tuple2;
import org.openconcerto.utils.cc.ITransformer;
 
207,7 → 206,7
}
 
private final AlterTable dropIndex(final String name, final boolean exact) {
return this.addOutsideClause(new OutsideClause() {
return this.addOutsideClause(new DeferredClause() {
@Override
public ClauseType getType() {
return ClauseType.DROP_INDEX;
214,8 → 213,8
}
 
@Override
public String asString(SQLName tableName) {
return getSyntax().getDropIndex(exact ? name : getIndexName(tableName, name), tableName);
public String asString(ChangeTable<?> ct, SQLName tableName) {
return ct.getSyntax().getDropIndex(exact ? name : getIndexName(tableName, name), tableName);
}
});
}
267,23 → 266,20
// DROP INDEX
// ALTER TABLE DROP COLUMN
// return list of clauses and their types (true : out/standalone, false : in)
private List<Tuple2<Boolean, List<String>>> getAllClauses(final NameTransformer transf, final Set<ClauseType> types, final SQLName tableName) {
private List<Tuple2<Boolean, List<String>>> getAllClauses(final InAndOutClauses allClauses, final NameTransformer transf, final Set<ClauseType> types, final SQLName tableName) {
final List<Tuple2<Boolean, String>> clauses = new ArrayList<Tuple2<Boolean, String>>();
Boolean lastIsStandalone = null;
for (final ClauseType type : ORDERED_TYPES) {
if (types.contains(type)) {
final List<Tuple2<Boolean, String>> inClauses = new ArrayList<Tuple2<Boolean, String>>();
for (final String inClause : this.getClauses(tableName, transf, type)) {
for (final String inClause : allClauses.getInClauses().getClauses(this, tableName, transf, Collections.singleton(type))) {
inClauses.add(Tuple2.create(false, inClause));
}
final List<Tuple2<Boolean, String>> outClauses = new ArrayList<Tuple2<Boolean, String>>();
for (final String inClause : allClauses.getOutClauses().getClauses(this, tableName, transf, Collections.singleton(type))) {
outClauses.add(Tuple2.create(true, inClause));
}
 
final String outClausesS = this.getOutClauses(tableName, type);
final List<Tuple2<Boolean, String>> outClauses;
if (!StringUtils.isEmpty(outClausesS))
outClauses = Collections.singletonList(Tuple2.create(true, outClausesS));
else
outClauses = Collections.emptyList();
 
// within a given type there's no mandatory order between in and out clauses, so try
// to group clauses to limit the number of SQL statements. By default
// (lastIsStandalone == null) inClauses before outClauses, as it might create the
318,11 → 314,15
}
 
private final String asString(final NameTransformer transf, final Set<ClauseType> types) {
return this.asString(this.getClauses(), transf, types);
}
 
protected final String asString(final InAndOutClauses allClauses, final NameTransformer transf, final Set<ClauseType> types) {
final SQLName tableName = transf.transformTableName(new SQLName(getRootName(), this.getName()));
 
final StringBuffer res = new StringBuffer(512);
final String alterTable = "ALTER TABLE " + tableName.quote();
for (final Tuple2<Boolean, List<String>> standaloneAndClauses : getAllClauses(transf, types, tableName)) {
for (final Tuple2<Boolean, List<String>> standaloneAndClauses : getAllClauses(allClauses, transf, types, tableName)) {
final List<String> genClauses = standaloneAndClauses.get1();
if (standaloneAndClauses.get0()) {
// e.g. "CREATE INDEX ;"
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLRowValuesCluster.java
14,6 → 14,7
package org.openconcerto.sql.model;
 
import org.openconcerto.sql.model.SQLRowValues.CreateMode;
import org.openconcerto.sql.model.SQLRowValues.FillMode;
import org.openconcerto.sql.model.SQLRowValues.ForeignCopyMode;
import org.openconcerto.sql.model.SQLRowValues.ReferentChangeEvent;
import org.openconcerto.sql.model.SQLRowValues.ReferentChangeListener;
379,8 → 380,8
* @param start when storing a subset, the start of <code>pruneGraph</code> in this, can be
* <code>null</code>.
* @param pruneGraph the maximum graph to store, can be <code>null</code>.
* @param checkValidity whether to ask for checking if foreign keys point to valid rows, see
* {@link SQLRowValues#setValidityChecked(SQLRowValues.ValidityCheck)}.
* @param checkValidity whether to {@link SQLRowValues#getInvalid() checking validity} of rows,
* see {@link SQLRowValues#setValidityChecked(SQLRowValues.ValidityCheck)}.
* @param fireEvent <code>false</code> if stored rows shouldn't be fetched and
* {@link SQLTableEvent} should not be fired.
* @return the store result.
1039,6 → 1040,76
}
 
/**
* Merge one graph (including its fields) into another.
*
* Merge
*
* <pre>
* LOCAL(DESIGNATION, ORDRE) <-- CPI(ORDRE)
* \--- SRC --/
* </pre>
*
* Into
*
* <pre>
* LOCAL(DESIGNATION, ARCHIVE) <-- CPI(ARCHIVE)
* </pre>
*
* Result in this :
*
* <pre>
* LOCAL(DESIGNATION, ORDRE, ARCHIVE) <-- CPI(ORDRE, ARCHIVE)
* \--- SRC --/
* </pre>
*
* @param start the graph that will be modified.
* @param graph the graph that will be merged (not modified).
*/
public final void merge(final SQLRowValues start, final SQLRowValues graph) {
this.containsCheck(start);
if (start == graph)
return;
if (!start.getTable().equals(graph.getTable()))
throw new IllegalArgumentException(start + " is not from the same table as " + graph);
final Map<SQLRowValues, SQLRowValues> from = new IdentityHashMap<>();
graph.getGraph().walk(graph, null, new ITransformer<State<Object>, Object>() {
@Override
public Object transformChecked(State<Object> input) {
final SQLRowValues previousReceiver = from.get(input.getPrevious());
final SQLRowValues alreadyMergedReceiver = from.get(input.getCurrent());
if (alreadyMergedReceiver != null) {
// fields already merged just add a link
previousReceiver.put(input.getPath().getStep(-1), alreadyMergedReceiver);
} else {
final SQLRowValues currentReceiver;
if (input.getPath().length() == 0) {
assert input.getCurrent() == graph;
assert previousReceiver == null;
currentReceiver = start;
} else {
currentReceiver = previousReceiver.followPath(input.getPath().subPath(-1));
}
final SQLRowValues actualReceiver;
if (currentReceiver != null) {
actualReceiver = currentReceiver;
// merge fields
actualReceiver.putAll(input.getCurrent().getAllValues(ForeignCopyMode.COPY_NULL), null, FillMode.DONT_OVERWRITE);
} else {
// node didn't exist in the receiving graph, copy the single node with all
// its fields
actualReceiver = new SQLRowValues(input.getCurrent(), ForeignCopyMode.COPY_NULL);
previousReceiver.put(input.getPath().getStep(-1), actualReceiver);
}
assert actualReceiver != null;
from.put(input.getCurrent(), actualReceiver);
}
return null;
}
// cycle allowed to go through all links
}, new WalkOptions(Direction.ANY).setRecursionType(RecursionType.BREADTH_FIRST).setStartIncluded(true).setForeignsOrderIgnored(false).setCycleAllowed(true));
}
 
/**
* Return a graphical representation of the tree rooted at <code>root</code>. The returned
* string is akin to the result of a query :
*
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLRequestLog.java
70,8 → 70,9
private boolean forShare;
private String threadId;
private static List<ChangeListener> listeners = new ArrayList<ChangeListener>(2);
private static JLabel textInfo = new JLabel("Total: ");
@GuardedBy("EDT")
private static JLabel textInfo;
@GuardedBy("EDT")
private static final DateFormat sdt = new SimpleDateFormat("HH:mm:ss.SS");
private static final DecimalFormat dformat = new DecimalFormat("##0.00");
 
156,10 → 157,12
for (int i = 0; i < stop; i++) {
listeners.get(i).stateChanged(null);
}
final long totalMs = getTotalMs();
final long totalSQLMs = getTotalSQLMs();
textInfo.setText("Total: " + totalMs + " ms, Swing: " + getTotalSwing() + " ms, SQL: " + totalSQLMs + " ms, processing: " + (totalMs - totalSQLMs) + " ms , " + getNbConnections()
+ " conn., " + getNbThread() + " threads. Total: " + list.size() + " / " + total_count);
if (textInfo != null) {
final long totalMs = getTotalMs();
final long totalSQLMs = getTotalSQLMs();
textInfo.setText("Total: " + totalMs + " ms, Swing: " + getTotalSwing() + " ms, SQL: " + totalSQLMs + " ms, processing: " + (totalMs - totalSQLMs) + " ms , " + getNbConnections()
+ " conn., " + getNbThread() + " threads. Total: " + list.size() + " / " + total_count);
}
}
});
}
228,6 → 231,9
}
 
public static void showFrame() {
if (textInfo != null)
return;
 
JFrame f = new JFrame("SQL monitoring");
final SQLRequestLogModel model = new SQLRequestLogModel();
final JTable table = new JTable(model);
470,6 → 476,7
 
p.add(sc, BorderLayout.CENTER);
 
textInfo = new JLabel("Total: ");
p.add(textInfo, BorderLayout.SOUTH);
f.setContentPane(p);
f.setSize(960, 480);
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLRow.java
191,7 → 191,9
final SQLSelect sel = new SQLSelect(true).addAllSelect(t.getFields(vfs));
sel.setLockStrength(l);
sel.setWhere(new Where(t.getKey(), "=", id));
return new SQLRow(t, id, t.getDBSystemRoot().getDataSource().execute1(sel.asString()));
@SuppressWarnings("unchecked")
final Map<String, ?> map = (Map<String, ?>) t.getDBSystemRoot().getDataSource().execute(sel.asString(), new IResultSetHandler(SQLDataSource.MAP_HANDLER, l.equals(LockStrength.NONE)));
return new SQLRow(t, id, map);
}
 
/**
287,11 → 289,11
/**
* Recharge les valeurs des champs depuis la base.
*/
public void fetchValues() {
public final void fetchValues() {
this.fetchValues(true);
}
 
SQLRow fetchValues(final boolean useCache) {
public final SQLRow fetchValues(final boolean useCache) {
return this.fetchValues(useCache, useCache);
}
 
604,17 → 606,44
}
 
public Set<SQLRow> getDistantRows(final Path path, final ArchiveMode archiveMode) {
if (path.length() == 0)
return SQLRowMode.check(archiveMode, this) ? Collections.singleton(this) : Collections.<SQLRow> emptySet();
// on veut tous les champs de la derniere table et rien d'autre
final List<List<String>> fields = new ArrayList<List<String>>(Collections.nCopies(path.length() - 1, Collections.<String> emptyList()));
fields.add(null);
final Set<List<SQLRow>> s = this.getRowsOnPath(path, fields, archiveMode);
final Set<SQLRow> res = new LinkedHashSet<SQLRow>(s.size());
for (final List<SQLRow> l : s) {
res.add(l.get(0));
return getDistantRows(path, archiveMode, true);
}
 
public Set<SQLRow> getDistantRows(final Path path, final ArchiveMode archiveMode, final boolean orderLast) {
return (Set<SQLRow>) getDistantRows(path, archiveMode, orderLast, false);
}
 
public List<SQLRow> getDistantRowsList(final Path path, final ArchiveMode archiveMode) {
// this method can return the same row multiple times, so don't use its order or the
// duplicated rows will always be grouped together.
return getDistantRowsList(path, archiveMode, false);
}
 
public List<SQLRow> getDistantRowsList(final Path path, final ArchiveMode archiveMode, final boolean orderLast) {
return (List<SQLRow>) getDistantRows(path, archiveMode, orderLast, true);
}
 
private Collection<SQLRow> getDistantRows(final Path path, final ArchiveMode archiveMode, final boolean orderLast, final boolean list) {
if (path.length() == 0) {
if (SQLRowMode.check(archiveMode, this))
return list ? Collections.singletonList(this) : Collections.singleton(this);
else
return list ? Collections.<SQLRow> emptyList() : Collections.<SQLRow> emptySet();
} else {
// on veut tous les champs de la derniere table et rien d'autre
final List<List<String>> fields = new ArrayList<List<String>>(Collections.nCopies(path.length() - 1, Collections.<String> emptyList()));
fields.add(null);
final List<List<SQLRow>> s = this.getRowsOnPath(path, fields, archiveMode, orderLast);
final List<SQLRow> resList = list ? new ArrayList<SQLRow>(s.size()) : null;
final Set<SQLRow> resSet = list ? null : new LinkedHashSet<SQLRow>(s.size());
final Collection<SQLRow> res = list ? resList : resSet;
assert res != null;
for (final List<SQLRow> l : s) {
assert l.size() == 1 : "Too many rows were created : " + l;
res.add(l.get(0));
}
return list ? Collections.unmodifiableList(resList) : Collections.unmodifiableSet(resSet);
}
return res;
}
 
/**
628,17 → 657,23
* <li><code>null</code> pour tous les champs</li>
* <li>une Collection de nom de champs, e.g. ["DESIGNATION","NUMERO"]</li>
* </ul>
* @return un ensemble de List de SQLRow.
* @return a list with one item per distant row, and each item has all the rows on the passed
* path.
*/
public Set<List<SQLRow>> getRowsOnPath(final List<String> path, final List<? extends Collection<String>> fields) {
public List<List<SQLRow>> getRowsOnPath(final List<String> path, final List<? extends Collection<String>> fields) {
return this.getRowsOnPath(Path.get(this.getTable()).addTables(path), fields);
}
 
public Set<List<SQLRow>> getRowsOnPath(final Path p, final List<? extends Collection<String>> fields) {
public List<List<SQLRow>> getRowsOnPath(final Path p, final List<? extends Collection<String>> fields) {
return this.getRowsOnPath(p, fields, ArchiveMode.UNARCHIVED);
}
 
public Set<List<SQLRow>> getRowsOnPath(final Path p, final List<? extends Collection<String>> fields, final ArchiveMode archiveMode) {
public List<List<SQLRow>> getRowsOnPath(final Path p, final List<? extends Collection<String>> fields, final ArchiveMode archiveMode) {
return this.getRowsOnPath(p, fields, archiveMode, true);
}
 
// returns a List since the same row might be linked several times to another
public List<List<SQLRow>> getRowsOnPath(final Path p, final List<? extends Collection<String>> fields, final ArchiveMode archiveMode, final boolean orderLast) {
final int pathSize = p.length();
if (pathSize == 0)
throw new IllegalArgumentException("path is empty");
646,7 → 681,7
throw new IllegalArgumentException("path and fields size mismatch : " + pathSize + " != " + fields.size());
if (p.getFirst() != this.getTable())
throw new IllegalArgumentException("path doesn't start with us : " + p.getFirst() + " != " + this.getTable());
final Set<List<SQLRow>> res = new LinkedHashSet<List<SQLRow>>();
final List<List<SQLRow>> res = new ArrayList<List<SQLRow>>();
 
final DBSystemRoot sysRoot = this.getTable().getDBSystemRoot();
Where where = sysRoot.getGraph().getJointure(p);
676,6 → 711,9
// plus les champs demandés
select.addAllSelect(t, fieldsCol);
}
if (!orderLast) {
select.addOrder(t);
}
}
// dans tous les cas mettre l'ID de la dernière table
final SQLTable lastTable = p.getLast();
682,9 → 720,11
select.addSelect(lastTable.getKey());
 
select.setWhere(where);
// determinist order even if there's no order field or invalid values in it
select.addOrderSilent(lastTable.getName());
select.addFieldOrder(lastTable.getKey());
if (orderLast) {
// determinist order even if there's no order field or invalid values in it
select.addOrderSilent(lastTable.getName());
select.addFieldOrder(lastTable.getKey());
}
 
// on ajoute une SQLRow pour chaque ID trouvé
sysRoot.getDataSource().execute(select.asString(), new ResultSetHandler() {
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLBackgroundTableCache.java
85,9 → 85,14
}
 
public synchronized SQLBackgroundTableCacheItem getCacheForTable(SQLTable t) {
final SQLBackgroundTableCacheItem item = this.list.get(t);
SQLBackgroundTableCacheItem item = this.list.get(t);
if (item != null) {
item.reloadFromDbIfNeeded();
} else {
System.err.println("SQLBackgroundTableCache.getCacheForTable() WARNING " + t.getName() + " is not registered (use add to register)");
this.add(t, 0);
item = this.list.get(t);
item.reloadFromDbIfNeeded();
}
return item;
}
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLRowValues.java
197,9 → 197,10
 
/**
* Set how {@link #getInvalid()} should be called before each data modification. Initially set
* to {@link ValidityCheck#TRUE_BY_DEFAULT}. NOTE : that the check also makes sure that
* referenced rows are not archived, so if it isn't performed a row could point to an archived
* row.
* to {@link ValidityCheck#TRUE_BY_DEFAULT}. NOTE : the check is performed outside the
* transaction and thus not always accurate. Only the DB can make sure of the validity
* efficiently : with foreign keys and a trigger to check that unarchived rows reference
* unarchived rows.
*
* @param vc the new mode, <code>null</code> to set the default.
*/
356,7 → 357,7
 
if (oldRowVals) {
final SQLRowValues vals = (SQLRowValues) old;
vals.referents.remove(f, this);
vals.referents.removeOne(f, this);
this.foreigns.remove(fieldName);
assert this.graph == vals.graph;
this.graph.remove(this, f, vals);
401,6 → 402,14
return g == null ? 1 : g.size();
}
 
public final Set<SQLTable> getGraphTables() {
final SQLRowValuesCluster g = this.getGraph(false);
if (g == null)
return Collections.singleton(this.getTable());
else
return g.getTables();
}
 
public final <T> void walkGraph(T acc, ITransformer<State<T>, T> closure) {
this.getGraph().walk(this, acc, closure);
}
1245,10 → 1254,14
}
 
public final SQLRowValues putAll(Map<String, ?> m, final Collection<String> keys) {
return this.loadAll(m, keys, false, FillMode.OVERWRITE);
return this.putAll(m, keys, FillMode.OVERWRITE);
}
 
static private enum FillMode {
final SQLRowValues putAll(Map<String, ?> m, final Collection<String> keys, final FillMode fillMode) {
return this.loadAll(m, keys, false, fillMode);
}
 
static enum FillMode {
CLEAR, OVERWRITE, DONT_OVERWRITE
}
 
1420,7 → 1433,7
 
public final void removeReferentListener(SQLField field, ReferentChangeListener l) {
if (this.referentsListener != null) {
this.referentsListener.remove(field, l);
this.referentsListener.removeOne(field, l);
}
}
 
1761,6 → 1774,10
this.putAll(m);
}
 
public void merge(final SQLRowValues v) {
this.getGraph().merge(this, v);
}
 
// *** modify
 
void checkValidity() {
1772,8 → 1789,7
}
 
/**
* Renvoie le premier pb dans les valeurs. C'est à dire la première clef externe qui pointe sur
* une ligne non valide.
* Return the first problem with a foreign key.
*
* @return <code>null</code> si pas de pb, sinon un Object[] :
* <ol>
1810,6 → 1826,7
if (!this.getFields().contains(ff))
return new Object[] { ff, null };
}
foreignLinks.keySet().removeAll(foreignLink.getCols());
// MAYBE also check foreign row is valid
}
} // else not a foreign key or already checked
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLResultSet.java
10,9 → 10,9
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.sql.model;
 
package org.openconcerto.sql.model;
 
import java.io.InputStream;
import java.io.Reader;
import java.math.BigDecimal;
40,904 → 40,903
import org.apache.commons.collections.map.LazyMap;
 
/**
* A resultSet that wraps onto another one, caching name to index translation,
* and using a ResultSetFullnameHelper.
* A resultSet that wraps onto another one, caching name to index translation, and using a
* ResultSetFullnameHelper.
*
* @author Sylvain
*/
public class SQLResultSet implements ResultSet {
 
static public final <T> T getValue(final ResultSet rs, final Class<T> clz, final int columnIndex)
throws SQLException {
final Object res;
if (clz == Object.class)
res = rs.getObject(columnIndex);
else if (Integer.class.isAssignableFrom(clz))
res = rs.getInt(columnIndex);
else if (Long.class.isAssignableFrom(clz))
res = rs.getLong(columnIndex);
else if (String.class.isAssignableFrom(clz))
res = rs.getString(columnIndex);
else if (Boolean.class.isAssignableFrom(clz))
res = rs.getBoolean(columnIndex);
else if (java.sql.Date.class.isAssignableFrom(clz))
res = rs.getDate(columnIndex);
else if (java.util.Date.class.isAssignableFrom(clz))
res = rs.getTimestamp(columnIndex);
else if (Short.class.isAssignableFrom(clz))
res = rs.getShort(columnIndex);
else if (Byte.class.isAssignableFrom(clz))
res = rs.getByte(columnIndex);
else if (Double.class.isAssignableFrom(clz))
res = rs.getDouble(columnIndex);
else if (Float.class.isAssignableFrom(clz))
res = rs.getFloat(columnIndex);
else if (Time.class.isAssignableFrom(clz))
res = rs.getTime(columnIndex);
else
res = rs.getObject(columnIndex);
return clz.cast(res);
}
static public final <T> T getValue(final ResultSet rs, final Class<T> clz, final int columnIndex) throws SQLException {
final Object res;
if (clz == Object.class)
res = rs.getObject(columnIndex);
else if (Integer.class.isAssignableFrom(clz))
res = rs.getInt(columnIndex);
else if (Long.class.isAssignableFrom(clz))
res = rs.getLong(columnIndex);
else if (String.class.isAssignableFrom(clz))
res = rs.getString(columnIndex);
else if (Boolean.class.isAssignableFrom(clz))
res = rs.getBoolean(columnIndex);
else if (java.sql.Date.class.isAssignableFrom(clz))
res = rs.getDate(columnIndex);
else if (java.util.Date.class.isAssignableFrom(clz))
res = rs.getTimestamp(columnIndex);
else if (Short.class.isAssignableFrom(clz))
res = rs.getShort(columnIndex);
else if (Byte.class.isAssignableFrom(clz))
res = rs.getByte(columnIndex);
else if (Double.class.isAssignableFrom(clz))
res = rs.getDouble(columnIndex);
else if (Float.class.isAssignableFrom(clz))
res = rs.getFloat(columnIndex);
else if (Time.class.isAssignableFrom(clz))
res = rs.getTime(columnIndex);
else
res = rs.getObject(columnIndex);
return clz.cast(res);
}
 
static public final <T> T getValue(final ResultSet rs, final Class<T> clz, final String columnLabel)
throws SQLException {
final Object res;
if (clz == Object.class)
res = rs.getObject(columnLabel);
else if (Integer.class.isAssignableFrom(clz))
res = rs.getInt(columnLabel);
else if (Long.class.isAssignableFrom(clz))
res = rs.getLong(columnLabel);
else if (String.class.isAssignableFrom(clz))
res = rs.getString(columnLabel);
else if (Boolean.class.isAssignableFrom(clz))
res = rs.getBoolean(columnLabel);
else if (java.sql.Date.class.isAssignableFrom(clz))
res = rs.getDate(columnLabel);
else if (java.util.Date.class.isAssignableFrom(clz))
res = rs.getTimestamp(columnLabel);
else if (Short.class.isAssignableFrom(clz))
res = rs.getShort(columnLabel);
else if (Byte.class.isAssignableFrom(clz))
res = rs.getByte(columnLabel);
else if (Double.class.isAssignableFrom(clz))
res = rs.getDouble(columnLabel);
else if (Float.class.isAssignableFrom(clz))
res = rs.getFloat(columnLabel);
else if (Time.class.isAssignableFrom(clz))
res = rs.getTime(columnLabel);
else
res = rs.getObject(columnLabel);
return clz.cast(res);
}
static public final <T> T getValue(final ResultSet rs, final Class<T> clz, final String columnLabel) throws SQLException {
final Object res;
if (clz == Object.class)
res = rs.getObject(columnLabel);
else if (Integer.class.isAssignableFrom(clz))
res = rs.getInt(columnLabel);
else if (Long.class.isAssignableFrom(clz))
res = rs.getLong(columnLabel);
else if (String.class.isAssignableFrom(clz))
res = rs.getString(columnLabel);
else if (Boolean.class.isAssignableFrom(clz))
res = rs.getBoolean(columnLabel);
else if (java.sql.Date.class.isAssignableFrom(clz))
res = rs.getDate(columnLabel);
else if (java.util.Date.class.isAssignableFrom(clz))
res = rs.getTimestamp(columnLabel);
else if (Short.class.isAssignableFrom(clz))
res = rs.getShort(columnLabel);
else if (Byte.class.isAssignableFrom(clz))
res = rs.getByte(columnLabel);
else if (Double.class.isAssignableFrom(clz))
res = rs.getDouble(columnLabel);
else if (Float.class.isAssignableFrom(clz))
res = rs.getFloat(columnLabel);
else if (Time.class.isAssignableFrom(clz))
res = rs.getTime(columnLabel);
else
res = rs.getObject(columnLabel);
return clz.cast(res);
}
 
static public final int getRowProcessedCount(final ResultSet rs) {
if (rs instanceof SQLResultSet) {
return ((SQLResultSet) rs).getRowProcessedCount();
} else {
// ResultSet.getRow() always return 0 after the last row
return 0;
}
}
static public final int getRowProcessedCount(final ResultSet rs) {
if (rs instanceof SQLResultSet) {
return ((SQLResultSet) rs).getRowProcessedCount();
} else {
// ResultSet.getRow() always return 0 after the last row
return 0;
}
}
 
private final ResultSet delegate;
private final ResultSetFullnameHelper helper;
private final Map indexes;
private int rowProcessedCount;
private final ResultSet delegate;
private final ResultSetFullnameHelper helper;
private final Map indexes;
private int rowProcessedCount;
 
public SQLResultSet(ResultSet delegate) {
this.delegate = delegate;
this.helper = new ResultSetFullnameHelper(this);
this.indexes = LazyMap.decorate(new HashMap(), new Transformer() {
public Object transform(Object input) {
final String colName = (String) input;
try {
return new Integer(doFindColumn(colName));
} catch (SQLException e) {
return e;
}
}
});
}
public SQLResultSet(ResultSet delegate) {
this.delegate = delegate;
this.helper = new ResultSetFullnameHelper(this);
this.indexes = LazyMap.decorate(new HashMap(), new Transformer() {
public Object transform(Object input) {
final String colName = (String) input;
try {
return new Integer(doFindColumn(colName));
} catch (SQLException e) {
return e;
}
}
});
}
 
private ResultSet getDelegate() {
return this.delegate;
}
private ResultSet getDelegate() {
return this.delegate;
}
 
public boolean absolute(int row) throws SQLException {
return getDelegate().absolute(row);
}
public boolean absolute(int row) throws SQLException {
return getDelegate().absolute(row);
}
 
public void afterLast() throws SQLException {
getDelegate().afterLast();
}
public void afterLast() throws SQLException {
getDelegate().afterLast();
}
 
public void beforeFirst() throws SQLException {
getDelegate().beforeFirst();
}
public void beforeFirst() throws SQLException {
getDelegate().beforeFirst();
}
 
public void cancelRowUpdates() throws SQLException {
getDelegate().cancelRowUpdates();
}
public void cancelRowUpdates() throws SQLException {
getDelegate().cancelRowUpdates();
}
 
public void clearWarnings() throws SQLException {
getDelegate().clearWarnings();
}
public void clearWarnings() throws SQLException {
getDelegate().clearWarnings();
}
 
public void close() throws SQLException {
getDelegate().close();
}
public void close() throws SQLException {
getDelegate().close();
}
 
public void deleteRow() throws SQLException {
getDelegate().deleteRow();
}
public void deleteRow() throws SQLException {
getDelegate().deleteRow();
}
 
public int findColumn(String columnName) throws SQLException {
final Object res = this.indexes.get(columnName);
if (res instanceof SQLException)
throw (SQLException) res;
else {
final int index = ((Number) res).intValue();
if (index < 1)
throw new SQLException(columnName + " not found");
else
return index;
}
}
public int findColumn(String columnName) throws SQLException {
final Object res = this.indexes.get(columnName);
if (res instanceof SQLException)
throw (SQLException) res;
else {
final int index = ((Number) res).intValue();
if (index < 1)
throw new SQLException(columnName + " not found");
else
return index;
}
}
 
private int doFindColumn(String columnName) throws SQLException {
try {
return getDelegate().findColumn(columnName);
} catch (SQLException e) {
try {
return this.helper.getIndex(columnName);
} catch (Exception exn) {
throw e;
}
}
}
private int doFindColumn(String columnName) throws SQLException {
try {
return getDelegate().findColumn(columnName);
} catch (SQLException e) {
try {
return this.helper.getIndex(columnName);
} catch (Exception exn) {
throw e;
}
}
}
 
public boolean first() throws SQLException {
return getDelegate().first();
}
public boolean first() throws SQLException {
return getDelegate().first();
}
 
public Array getArray(int i) throws SQLException {
return getDelegate().getArray(i);
}
public Array getArray(int i) throws SQLException {
return getDelegate().getArray(i);
}
 
public Array getArray(String colName) throws SQLException {
return getDelegate().getArray(colName);
}
public Array getArray(String colName) throws SQLException {
return getDelegate().getArray(colName);
}
 
public InputStream getAsciiStream(int columnIndex) throws SQLException {
return getDelegate().getAsciiStream(columnIndex);
}
public InputStream getAsciiStream(int columnIndex) throws SQLException {
return getDelegate().getAsciiStream(columnIndex);
}
 
public InputStream getAsciiStream(String columnName) throws SQLException {
return getDelegate().getAsciiStream(this.findColumn(columnName));
}
public InputStream getAsciiStream(String columnName) throws SQLException {
return getDelegate().getAsciiStream(this.findColumn(columnName));
}
 
public BigDecimal getBigDecimal(int columnIndex, int scale) throws SQLException {
return getDelegate().getBigDecimal(columnIndex, scale);
}
public BigDecimal getBigDecimal(int columnIndex, int scale) throws SQLException {
return getDelegate().getBigDecimal(columnIndex, scale);
}
 
public BigDecimal getBigDecimal(int columnIndex) throws SQLException {
return getDelegate().getBigDecimal(columnIndex);
}
public BigDecimal getBigDecimal(int columnIndex) throws SQLException {
return getDelegate().getBigDecimal(columnIndex);
}
 
public BigDecimal getBigDecimal(String columnName, int scale) throws SQLException {
return getDelegate().getBigDecimal(columnName, scale);
}
public BigDecimal getBigDecimal(String columnName, int scale) throws SQLException {
return getDelegate().getBigDecimal(columnName, scale);
}
 
public BigDecimal getBigDecimal(String columnName) throws SQLException {
return getDelegate().getBigDecimal(this.findColumn(columnName));
}
public BigDecimal getBigDecimal(String columnName) throws SQLException {
return getDelegate().getBigDecimal(this.findColumn(columnName));
}
 
public InputStream getBinaryStream(int columnIndex) throws SQLException {
return getDelegate().getBinaryStream(columnIndex);
}
public InputStream getBinaryStream(int columnIndex) throws SQLException {
return getDelegate().getBinaryStream(columnIndex);
}
 
public InputStream getBinaryStream(String columnName) throws SQLException {
return getDelegate().getBinaryStream(this.findColumn(columnName));
}
public InputStream getBinaryStream(String columnName) throws SQLException {
return getDelegate().getBinaryStream(this.findColumn(columnName));
}
 
public Blob getBlob(int i) throws SQLException {
return getDelegate().getBlob(i);
}
public Blob getBlob(int i) throws SQLException {
return getDelegate().getBlob(i);
}
 
public Blob getBlob(String colName) throws SQLException {
return getDelegate().getBlob(colName);
}
public Blob getBlob(String colName) throws SQLException {
return getDelegate().getBlob(colName);
}
 
public boolean getBoolean(int columnIndex) throws SQLException {
return getDelegate().getBoolean(columnIndex);
}
public boolean getBoolean(int columnIndex) throws SQLException {
return getDelegate().getBoolean(columnIndex);
}
 
public boolean getBoolean(String columnName) throws SQLException {
return getDelegate().getBoolean(this.findColumn(columnName));
}
public boolean getBoolean(String columnName) throws SQLException {
return getDelegate().getBoolean(this.findColumn(columnName));
}
 
public byte getByte(int columnIndex) throws SQLException {
return getDelegate().getByte(columnIndex);
}
public byte getByte(int columnIndex) throws SQLException {
return getDelegate().getByte(columnIndex);
}
 
public byte getByte(String columnName) throws SQLException {
return getDelegate().getByte(this.findColumn(columnName));
}
public byte getByte(String columnName) throws SQLException {
return getDelegate().getByte(this.findColumn(columnName));
}
 
public byte[] getBytes(int columnIndex) throws SQLException {
return getDelegate().getBytes(columnIndex);
}
public byte[] getBytes(int columnIndex) throws SQLException {
return getDelegate().getBytes(columnIndex);
}
 
public byte[] getBytes(String columnName) throws SQLException {
return getDelegate().getBytes(this.findColumn(columnName));
}
public byte[] getBytes(String columnName) throws SQLException {
return getDelegate().getBytes(this.findColumn(columnName));
}
 
public Reader getCharacterStream(int columnIndex) throws SQLException {
return getDelegate().getCharacterStream(columnIndex);
}
public Reader getCharacterStream(int columnIndex) throws SQLException {
return getDelegate().getCharacterStream(columnIndex);
}
 
public Reader getCharacterStream(String columnName) throws SQLException {
return getDelegate().getCharacterStream(this.findColumn(columnName));
}
public Reader getCharacterStream(String columnName) throws SQLException {
return getDelegate().getCharacterStream(this.findColumn(columnName));
}
 
public Clob getClob(int i) throws SQLException {
return getDelegate().getClob(i);
}
public Clob getClob(int i) throws SQLException {
return getDelegate().getClob(i);
}
 
public Clob getClob(String colName) throws SQLException {
return getDelegate().getClob(colName);
}
public Clob getClob(String colName) throws SQLException {
return getDelegate().getClob(colName);
}
 
public int getConcurrency() throws SQLException {
return getDelegate().getConcurrency();
}
public int getConcurrency() throws SQLException {
return getDelegate().getConcurrency();
}
 
public String getCursorName() throws SQLException {
return getDelegate().getCursorName();
}
public String getCursorName() throws SQLException {
return getDelegate().getCursorName();
}
 
public Date getDate(int columnIndex, Calendar cal) throws SQLException {
return getDelegate().getDate(columnIndex, cal);
}
public Date getDate(int columnIndex, Calendar cal) throws SQLException {
return getDelegate().getDate(columnIndex, cal);
}
 
public Date getDate(int columnIndex) throws SQLException {
return getDelegate().getDate(columnIndex);
}
public Date getDate(int columnIndex) throws SQLException {
return getDelegate().getDate(columnIndex);
}
 
public Date getDate(String columnName, Calendar cal) throws SQLException {
return getDelegate().getDate(columnName, cal);
}
public Date getDate(String columnName, Calendar cal) throws SQLException {
return getDelegate().getDate(columnName, cal);
}
 
public Date getDate(String columnName) throws SQLException {
return getDelegate().getDate(this.findColumn(columnName));
}
public Date getDate(String columnName) throws SQLException {
return getDelegate().getDate(this.findColumn(columnName));
}
 
public double getDouble(int columnIndex) throws SQLException {
return getDelegate().getDouble(columnIndex);
}
public double getDouble(int columnIndex) throws SQLException {
return getDelegate().getDouble(columnIndex);
}
 
public double getDouble(String columnName) throws SQLException {
return getDelegate().getDouble(this.findColumn(columnName));
}
public double getDouble(String columnName) throws SQLException {
return getDelegate().getDouble(this.findColumn(columnName));
}
 
public int getFetchDirection() throws SQLException {
return getDelegate().getFetchDirection();
}
public int getFetchDirection() throws SQLException {
return getDelegate().getFetchDirection();
}
 
public int getFetchSize() throws SQLException {
return getDelegate().getFetchSize();
}
public int getFetchSize() throws SQLException {
return getDelegate().getFetchSize();
}
 
public float getFloat(int columnIndex) throws SQLException {
return getDelegate().getFloat(columnIndex);
}
public float getFloat(int columnIndex) throws SQLException {
return getDelegate().getFloat(columnIndex);
}
 
public float getFloat(String columnName) throws SQLException {
return getDelegate().getFloat(this.findColumn(columnName));
}
public float getFloat(String columnName) throws SQLException {
return getDelegate().getFloat(this.findColumn(columnName));
}
 
public int getInt(int columnIndex) throws SQLException {
return getDelegate().getInt(columnIndex);
}
public int getInt(int columnIndex) throws SQLException {
return getDelegate().getInt(columnIndex);
}
 
public int getInt(String columnName) throws SQLException {
return getDelegate().getInt(this.findColumn(columnName));
}
public int getInt(String columnName) throws SQLException {
return getDelegate().getInt(this.findColumn(columnName));
}
 
public long getLong(int columnIndex) throws SQLException {
return getDelegate().getLong(columnIndex);
}
public long getLong(int columnIndex) throws SQLException {
return getDelegate().getLong(columnIndex);
}
 
public long getLong(String columnName) throws SQLException {
return getDelegate().getLong(this.findColumn(columnName));
}
public long getLong(String columnName) throws SQLException {
return getDelegate().getLong(this.findColumn(columnName));
}
 
public ResultSetMetaData getMetaData() throws SQLException {
return new SQLResultSetMetadata(getDelegate().getMetaData());
}
public ResultSetMetaData getMetaData() throws SQLException {
return new SQLResultSetMetadata(getDelegate().getMetaData());
}
 
public Object getObject(int arg0, Map arg1) throws SQLException {
return getDelegate().getObject(arg0, arg1);
}
public Object getObject(int arg0, Map arg1) throws SQLException {
return getDelegate().getObject(arg0, arg1);
}
 
public Object getObject(int columnIndex) throws SQLException {
return getDelegate().getObject(columnIndex);
}
public Object getObject(int columnIndex) throws SQLException {
return getDelegate().getObject(columnIndex);
}
 
public Object getObject(String arg0, Map arg1) throws SQLException {
return getDelegate().getObject(arg0, arg1);
}
public Object getObject(String arg0, Map arg1) throws SQLException {
return getDelegate().getObject(arg0, arg1);
}
 
public Object getObject(String columnName) throws SQLException {
return getDelegate().getObject(this.findColumn(columnName));
}
public Object getObject(String columnName) throws SQLException {
return getDelegate().getObject(this.findColumn(columnName));
}
 
public Ref getRef(int i) throws SQLException {
return getDelegate().getRef(i);
}
public Ref getRef(int i) throws SQLException {
return getDelegate().getRef(i);
}
 
public Ref getRef(String colName) throws SQLException {
return getDelegate().getRef(colName);
}
public Ref getRef(String colName) throws SQLException {
return getDelegate().getRef(colName);
}
 
public int getRow() throws SQLException {
return getDelegate().getRow();
}
public int getRow() throws SQLException {
return getDelegate().getRow();
}
 
public short getShort(int columnIndex) throws SQLException {
return getDelegate().getShort(columnIndex);
}
public short getShort(int columnIndex) throws SQLException {
return getDelegate().getShort(columnIndex);
}
 
public short getShort(String columnName) throws SQLException {
return getDelegate().getShort(this.findColumn(columnName));
}
public short getShort(String columnName) throws SQLException {
return getDelegate().getShort(this.findColumn(columnName));
}
 
public Statement getStatement() throws SQLException {
return getDelegate().getStatement();
}
public Statement getStatement() throws SQLException {
return getDelegate().getStatement();
}
 
public String getString(int columnIndex) throws SQLException {
return getDelegate().getString(columnIndex);
}
public String getString(int columnIndex) throws SQLException {
return getDelegate().getString(columnIndex);
}
 
public String getString(String columnName) throws SQLException {
return getDelegate().getString(this.findColumn(columnName));
}
public String getString(String columnName) throws SQLException {
return getDelegate().getString(this.findColumn(columnName));
}
 
public Time getTime(int columnIndex, Calendar cal) throws SQLException {
return getDelegate().getTime(columnIndex, cal);
}
public Time getTime(int columnIndex, Calendar cal) throws SQLException {
return getDelegate().getTime(columnIndex, cal);
}
 
public Time getTime(int columnIndex) throws SQLException {
return getDelegate().getTime(columnIndex);
}
public Time getTime(int columnIndex) throws SQLException {
return getDelegate().getTime(columnIndex);
}
 
public Time getTime(String columnName, Calendar cal) throws SQLException {
return getDelegate().getTime(columnName, cal);
}
public Time getTime(String columnName, Calendar cal) throws SQLException {
return getDelegate().getTime(columnName, cal);
}
 
public Time getTime(String columnName) throws SQLException {
return getDelegate().getTime(this.findColumn(columnName));
}
public Time getTime(String columnName) throws SQLException {
return getDelegate().getTime(this.findColumn(columnName));
}
 
public Timestamp getTimestamp(int columnIndex, Calendar cal) throws SQLException {
return getDelegate().getTimestamp(columnIndex, cal);
}
public Timestamp getTimestamp(int columnIndex, Calendar cal) throws SQLException {
return getDelegate().getTimestamp(columnIndex, cal);
}
 
public Timestamp getTimestamp(int columnIndex) throws SQLException {
return getDelegate().getTimestamp(columnIndex);
}
public Timestamp getTimestamp(int columnIndex) throws SQLException {
return getDelegate().getTimestamp(columnIndex);
}
 
public Timestamp getTimestamp(String columnName, Calendar cal) throws SQLException {
return getDelegate().getTimestamp(columnName, cal);
}
public Timestamp getTimestamp(String columnName, Calendar cal) throws SQLException {
return getDelegate().getTimestamp(columnName, cal);
}
 
public Timestamp getTimestamp(String columnName) throws SQLException {
return getDelegate().getTimestamp(this.findColumn(columnName));
}
public Timestamp getTimestamp(String columnName) throws SQLException {
return getDelegate().getTimestamp(this.findColumn(columnName));
}
 
public int getType() throws SQLException {
return getDelegate().getType();
}
public int getType() throws SQLException {
return getDelegate().getType();
}
 
public InputStream getUnicodeStream(int columnIndex) throws SQLException {
return getDelegate().getUnicodeStream(columnIndex);
}
public InputStream getUnicodeStream(int columnIndex) throws SQLException {
return getDelegate().getUnicodeStream(columnIndex);
}
 
public InputStream getUnicodeStream(String columnName) throws SQLException {
return getDelegate().getUnicodeStream(this.findColumn(columnName));
}
public InputStream getUnicodeStream(String columnName) throws SQLException {
return getDelegate().getUnicodeStream(this.findColumn(columnName));
}
 
public URL getURL(int columnIndex) throws SQLException {
return getDelegate().getURL(columnIndex);
}
public URL getURL(int columnIndex) throws SQLException {
return getDelegate().getURL(columnIndex);
}
 
public URL getURL(String columnName) throws SQLException {
return getDelegate().getURL(this.findColumn(columnName));
}
public URL getURL(String columnName) throws SQLException {
return getDelegate().getURL(this.findColumn(columnName));
}
 
// **
// **
 
public SQLWarning getWarnings() throws SQLException {
return getDelegate().getWarnings();
}
public SQLWarning getWarnings() throws SQLException {
return getDelegate().getWarnings();
}
 
public void insertRow() throws SQLException {
getDelegate().insertRow();
}
public void insertRow() throws SQLException {
getDelegate().insertRow();
}
 
public boolean isAfterLast() throws SQLException {
return getDelegate().isAfterLast();
}
public boolean isAfterLast() throws SQLException {
return getDelegate().isAfterLast();
}
 
public boolean isBeforeFirst() throws SQLException {
return getDelegate().isBeforeFirst();
}
public boolean isBeforeFirst() throws SQLException {
return getDelegate().isBeforeFirst();
}
 
public boolean isFirst() throws SQLException {
return getDelegate().isFirst();
}
public boolean isFirst() throws SQLException {
return getDelegate().isFirst();
}
 
public boolean isLast() throws SQLException {
return getDelegate().isLast();
}
public boolean isLast() throws SQLException {
return getDelegate().isLast();
}
 
public boolean last() throws SQLException {
return getDelegate().last();
}
public boolean last() throws SQLException {
return getDelegate().last();
}
 
public void moveToCurrentRow() throws SQLException {
getDelegate().moveToCurrentRow();
}
public void moveToCurrentRow() throws SQLException {
getDelegate().moveToCurrentRow();
}
 
public void moveToInsertRow() throws SQLException {
getDelegate().moveToInsertRow();
}
public void moveToInsertRow() throws SQLException {
getDelegate().moveToInsertRow();
}
 
public boolean next() throws SQLException {
rowProcessedCount++;
return getDelegate().next();
}
public boolean next() throws SQLException {
rowProcessedCount++;
return getDelegate().next();
}
 
public int getRowProcessedCount() {
return rowProcessedCount;
}
public int getRowProcessedCount() {
return rowProcessedCount;
}
 
public boolean previous() throws SQLException {
return getDelegate().previous();
}
public boolean previous() throws SQLException {
return getDelegate().previous();
}
 
public void refreshRow() throws SQLException {
getDelegate().refreshRow();
}
public void refreshRow() throws SQLException {
getDelegate().refreshRow();
}
 
public boolean relative(int rows) throws SQLException {
return getDelegate().relative(rows);
}
public boolean relative(int rows) throws SQLException {
return getDelegate().relative(rows);
}
 
public boolean rowDeleted() throws SQLException {
return getDelegate().rowDeleted();
}
public boolean rowDeleted() throws SQLException {
return getDelegate().rowDeleted();
}
 
public boolean rowInserted() throws SQLException {
return getDelegate().rowInserted();
}
public boolean rowInserted() throws SQLException {
return getDelegate().rowInserted();
}
 
public boolean rowUpdated() throws SQLException {
return getDelegate().rowUpdated();
}
public boolean rowUpdated() throws SQLException {
return getDelegate().rowUpdated();
}
 
public void setFetchDirection(int direction) throws SQLException {
getDelegate().setFetchDirection(direction);
}
public void setFetchDirection(int direction) throws SQLException {
getDelegate().setFetchDirection(direction);
}
 
public void setFetchSize(int rows) throws SQLException {
getDelegate().setFetchSize(rows);
}
public void setFetchSize(int rows) throws SQLException {
getDelegate().setFetchSize(rows);
}
 
// update*
// update*
 
public void updateArray(int columnIndex, Array x) throws SQLException {
getDelegate().updateArray(columnIndex, x);
}
public void updateArray(int columnIndex, Array x) throws SQLException {
getDelegate().updateArray(columnIndex, x);
}
 
public void updateArray(String columnName, Array x) throws SQLException {
getDelegate().updateArray(columnName, x);
}
public void updateArray(String columnName, Array x) throws SQLException {
getDelegate().updateArray(columnName, x);
}
 
public void updateAsciiStream(int columnIndex, InputStream x, int length) throws SQLException {
getDelegate().updateAsciiStream(columnIndex, x, length);
}
public void updateAsciiStream(int columnIndex, InputStream x, int length) throws SQLException {
getDelegate().updateAsciiStream(columnIndex, x, length);
}
 
public void updateAsciiStream(String columnName, InputStream x, int length) throws SQLException {
getDelegate().updateAsciiStream(columnName, x, length);
}
public void updateAsciiStream(String columnName, InputStream x, int length) throws SQLException {
getDelegate().updateAsciiStream(columnName, x, length);
}
 
public void updateBigDecimal(int columnIndex, BigDecimal x) throws SQLException {
getDelegate().updateBigDecimal(columnIndex, x);
}
public void updateBigDecimal(int columnIndex, BigDecimal x) throws SQLException {
getDelegate().updateBigDecimal(columnIndex, x);
}
 
public void updateBigDecimal(String columnName, BigDecimal x) throws SQLException {
getDelegate().updateBigDecimal(columnName, x);
}
public void updateBigDecimal(String columnName, BigDecimal x) throws SQLException {
getDelegate().updateBigDecimal(columnName, x);
}
 
public void updateBinaryStream(int columnIndex, InputStream x, int length) throws SQLException {
getDelegate().updateBinaryStream(columnIndex, x, length);
}
public void updateBinaryStream(int columnIndex, InputStream x, int length) throws SQLException {
getDelegate().updateBinaryStream(columnIndex, x, length);
}
 
public void updateBinaryStream(String columnName, InputStream x, int length) throws SQLException {
getDelegate().updateBinaryStream(columnName, x, length);
}
public void updateBinaryStream(String columnName, InputStream x, int length) throws SQLException {
getDelegate().updateBinaryStream(columnName, x, length);
}
 
public void updateBlob(int columnIndex, Blob x) throws SQLException {
getDelegate().updateBlob(columnIndex, x);
}
public void updateBlob(int columnIndex, Blob x) throws SQLException {
getDelegate().updateBlob(columnIndex, x);
}
 
public void updateBlob(String columnName, Blob x) throws SQLException {
getDelegate().updateBlob(columnName, x);
}
public void updateBlob(String columnName, Blob x) throws SQLException {
getDelegate().updateBlob(columnName, x);
}
 
public void updateBoolean(int columnIndex, boolean x) throws SQLException {
getDelegate().updateBoolean(columnIndex, x);
}
public void updateBoolean(int columnIndex, boolean x) throws SQLException {
getDelegate().updateBoolean(columnIndex, x);
}
 
public void updateBoolean(String columnName, boolean x) throws SQLException {
getDelegate().updateBoolean(columnName, x);
}
public void updateBoolean(String columnName, boolean x) throws SQLException {
getDelegate().updateBoolean(columnName, x);
}
 
public void updateByte(int columnIndex, byte x) throws SQLException {
getDelegate().updateByte(columnIndex, x);
}
public void updateByte(int columnIndex, byte x) throws SQLException {
getDelegate().updateByte(columnIndex, x);
}
 
public void updateByte(String columnName, byte x) throws SQLException {
getDelegate().updateByte(columnName, x);
}
public void updateByte(String columnName, byte x) throws SQLException {
getDelegate().updateByte(columnName, x);
}
 
public void updateBytes(int columnIndex, byte[] x) throws SQLException {
getDelegate().updateBytes(columnIndex, x);
}
public void updateBytes(int columnIndex, byte[] x) throws SQLException {
getDelegate().updateBytes(columnIndex, x);
}
 
public void updateBytes(String columnName, byte[] x) throws SQLException {
getDelegate().updateBytes(columnName, x);
}
public void updateBytes(String columnName, byte[] x) throws SQLException {
getDelegate().updateBytes(columnName, x);
}
 
public void updateCharacterStream(int columnIndex, Reader x, int length) throws SQLException {
getDelegate().updateCharacterStream(columnIndex, x, length);
}
public void updateCharacterStream(int columnIndex, Reader x, int length) throws SQLException {
getDelegate().updateCharacterStream(columnIndex, x, length);
}
 
public void updateCharacterStream(String columnName, Reader reader, int length) throws SQLException {
getDelegate().updateCharacterStream(columnName, reader, length);
}
public void updateCharacterStream(String columnName, Reader reader, int length) throws SQLException {
getDelegate().updateCharacterStream(columnName, reader, length);
}
 
public void updateClob(int columnIndex, Clob x) throws SQLException {
getDelegate().updateClob(columnIndex, x);
}
public void updateClob(int columnIndex, Clob x) throws SQLException {
getDelegate().updateClob(columnIndex, x);
}
 
public void updateClob(String columnName, Clob x) throws SQLException {
getDelegate().updateClob(columnName, x);
}
public void updateClob(String columnName, Clob x) throws SQLException {
getDelegate().updateClob(columnName, x);
}
 
public void updateDate(int columnIndex, Date x) throws SQLException {
getDelegate().updateDate(columnIndex, x);
}
public void updateDate(int columnIndex, Date x) throws SQLException {
getDelegate().updateDate(columnIndex, x);
}
 
public void updateDate(String columnName, Date x) throws SQLException {
getDelegate().updateDate(columnName, x);
}
public void updateDate(String columnName, Date x) throws SQLException {
getDelegate().updateDate(columnName, x);
}
 
public void updateDouble(int columnIndex, double x) throws SQLException {
getDelegate().updateDouble(columnIndex, x);
}
public void updateDouble(int columnIndex, double x) throws SQLException {
getDelegate().updateDouble(columnIndex, x);
}
 
public void updateDouble(String columnName, double x) throws SQLException {
getDelegate().updateDouble(columnName, x);
}
public void updateDouble(String columnName, double x) throws SQLException {
getDelegate().updateDouble(columnName, x);
}
 
public void updateFloat(int columnIndex, float x) throws SQLException {
getDelegate().updateFloat(columnIndex, x);
}
public void updateFloat(int columnIndex, float x) throws SQLException {
getDelegate().updateFloat(columnIndex, x);
}
 
public void updateFloat(String columnName, float x) throws SQLException {
getDelegate().updateFloat(columnName, x);
}
public void updateFloat(String columnName, float x) throws SQLException {
getDelegate().updateFloat(columnName, x);
}
 
public void updateInt(int columnIndex, int x) throws SQLException {
getDelegate().updateInt(columnIndex, x);
}
public void updateInt(int columnIndex, int x) throws SQLException {
getDelegate().updateInt(columnIndex, x);
}
 
public void updateInt(String columnName, int x) throws SQLException {
getDelegate().updateInt(columnName, x);
}
public void updateInt(String columnName, int x) throws SQLException {
getDelegate().updateInt(columnName, x);
}
 
public void updateLong(int columnIndex, long x) throws SQLException {
getDelegate().updateLong(columnIndex, x);
}
public void updateLong(int columnIndex, long x) throws SQLException {
getDelegate().updateLong(columnIndex, x);
}
 
public void updateLong(String columnName, long x) throws SQLException {
getDelegate().updateLong(columnName, x);
}
public void updateLong(String columnName, long x) throws SQLException {
getDelegate().updateLong(columnName, x);
}
 
public void updateNull(int columnIndex) throws SQLException {
getDelegate().updateNull(columnIndex);
}
public void updateNull(int columnIndex) throws SQLException {
getDelegate().updateNull(columnIndex);
}
 
public void updateNull(String columnName) throws SQLException {
getDelegate().updateNull(columnName);
}
public void updateNull(String columnName) throws SQLException {
getDelegate().updateNull(columnName);
}
 
public void updateObject(int columnIndex, Object x, int scale) throws SQLException {
getDelegate().updateObject(columnIndex, x, scale);
}
public void updateObject(int columnIndex, Object x, int scale) throws SQLException {
getDelegate().updateObject(columnIndex, x, scale);
}
 
public void updateObject(int columnIndex, Object x) throws SQLException {
getDelegate().updateObject(columnIndex, x);
}
public void updateObject(int columnIndex, Object x) throws SQLException {
getDelegate().updateObject(columnIndex, x);
}
 
public void updateObject(String columnName, Object x, int scale) throws SQLException {
getDelegate().updateObject(columnName, x, scale);
}
public void updateObject(String columnName, Object x, int scale) throws SQLException {
getDelegate().updateObject(columnName, x, scale);
}
 
public void updateObject(String columnName, Object x) throws SQLException {
getDelegate().updateObject(columnName, x);
}
public void updateObject(String columnName, Object x) throws SQLException {
getDelegate().updateObject(columnName, x);
}
 
public void updateRef(int columnIndex, Ref x) throws SQLException {
getDelegate().updateRef(columnIndex, x);
}
public void updateRef(int columnIndex, Ref x) throws SQLException {
getDelegate().updateRef(columnIndex, x);
}
 
public void updateRef(String columnName, Ref x) throws SQLException {
getDelegate().updateRef(columnName, x);
}
public void updateRef(String columnName, Ref x) throws SQLException {
getDelegate().updateRef(columnName, x);
}
 
public void updateRow() throws SQLException {
getDelegate().updateRow();
}
public void updateRow() throws SQLException {
getDelegate().updateRow();
}
 
public void updateShort(int columnIndex, short x) throws SQLException {
getDelegate().updateShort(columnIndex, x);
}
public void updateShort(int columnIndex, short x) throws SQLException {
getDelegate().updateShort(columnIndex, x);
}
 
public void updateShort(String columnName, short x) throws SQLException {
getDelegate().updateShort(columnName, x);
}
public void updateShort(String columnName, short x) throws SQLException {
getDelegate().updateShort(columnName, x);
}
 
public void updateString(int columnIndex, String x) throws SQLException {
getDelegate().updateString(columnIndex, x);
}
public void updateString(int columnIndex, String x) throws SQLException {
getDelegate().updateString(columnIndex, x);
}
 
public void updateString(String columnName, String x) throws SQLException {
getDelegate().updateString(columnName, x);
}
public void updateString(String columnName, String x) throws SQLException {
getDelegate().updateString(columnName, x);
}
 
public void updateTime(int columnIndex, Time x) throws SQLException {
getDelegate().updateTime(columnIndex, x);
}
public void updateTime(int columnIndex, Time x) throws SQLException {
getDelegate().updateTime(columnIndex, x);
}
 
public void updateTime(String columnName, Time x) throws SQLException {
getDelegate().updateTime(columnName, x);
}
public void updateTime(String columnName, Time x) throws SQLException {
getDelegate().updateTime(columnName, x);
}
 
public void updateTimestamp(int columnIndex, Timestamp x) throws SQLException {
getDelegate().updateTimestamp(columnIndex, x);
}
public void updateTimestamp(int columnIndex, Timestamp x) throws SQLException {
getDelegate().updateTimestamp(columnIndex, x);
}
 
public void updateTimestamp(String columnName, Timestamp x) throws SQLException {
getDelegate().updateTimestamp(columnName, x);
}
public void updateTimestamp(String columnName, Timestamp x) throws SQLException {
getDelegate().updateTimestamp(columnName, x);
}
 
public boolean wasNull() throws SQLException {
return getDelegate().wasNull();
}
public boolean wasNull() throws SQLException {
return getDelegate().wasNull();
}
 
public int getHoldability() throws SQLException {
return getDelegate().getHoldability();
}
public int getHoldability() throws SQLException {
return getDelegate().getHoldability();
}
 
public Reader getNCharacterStream(int columnIndex) throws SQLException {
return getDelegate().getNCharacterStream(columnIndex);
}
public Reader getNCharacterStream(int columnIndex) throws SQLException {
return getDelegate().getNCharacterStream(columnIndex);
}
 
public Reader getNCharacterStream(String columnLabel) throws SQLException {
return getDelegate().getNCharacterStream(columnLabel);
}
public Reader getNCharacterStream(String columnLabel) throws SQLException {
return getDelegate().getNCharacterStream(columnLabel);
}
 
public NClob getNClob(int columnIndex) throws SQLException {
return getDelegate().getNClob(columnIndex);
}
public NClob getNClob(int columnIndex) throws SQLException {
return getDelegate().getNClob(columnIndex);
}
 
public NClob getNClob(String columnLabel) throws SQLException {
return getDelegate().getNClob(columnLabel);
}
public NClob getNClob(String columnLabel) throws SQLException {
return getDelegate().getNClob(columnLabel);
}
 
public String getNString(int columnIndex) throws SQLException {
return getDelegate().getNString(columnIndex);
}
public String getNString(int columnIndex) throws SQLException {
return getDelegate().getNString(columnIndex);
}
 
public String getNString(String columnLabel) throws SQLException {
return getDelegate().getNString(columnLabel);
}
public String getNString(String columnLabel) throws SQLException {
return getDelegate().getNString(columnLabel);
}
 
public RowId getRowId(int columnIndex) throws SQLException {
return getDelegate().getRowId(columnIndex);
}
public RowId getRowId(int columnIndex) throws SQLException {
return getDelegate().getRowId(columnIndex);
}
 
public RowId getRowId(String columnLabel) throws SQLException {
return getDelegate().getRowId(columnLabel);
}
public RowId getRowId(String columnLabel) throws SQLException {
return getDelegate().getRowId(columnLabel);
}
 
public SQLXML getSQLXML(int columnIndex) throws SQLException {
return getDelegate().getSQLXML(columnIndex);
}
public SQLXML getSQLXML(int columnIndex) throws SQLException {
return getDelegate().getSQLXML(columnIndex);
}
 
public SQLXML getSQLXML(String columnLabel) throws SQLException {
return getDelegate().getSQLXML(columnLabel);
}
public SQLXML getSQLXML(String columnLabel) throws SQLException {
return getDelegate().getSQLXML(columnLabel);
}
 
public boolean isClosed() throws SQLException {
return getDelegate().isClosed();
}
public boolean isClosed() throws SQLException {
return getDelegate().isClosed();
}
 
public boolean isWrapperFor(Class<?> iface) throws SQLException {
return getDelegate().isWrapperFor(iface);
}
public boolean isWrapperFor(Class<?> iface) throws SQLException {
return getDelegate().isWrapperFor(iface);
}
 
public <T> T unwrap(Class<T> iface) throws SQLException {
return getDelegate().unwrap(iface);
}
public <T> T unwrap(Class<T> iface) throws SQLException {
return getDelegate().unwrap(iface);
}
 
public void updateAsciiStream(int columnIndex, InputStream x, long length) throws SQLException {
getDelegate().updateAsciiStream(columnIndex, x, length);
}
public void updateAsciiStream(int columnIndex, InputStream x, long length) throws SQLException {
getDelegate().updateAsciiStream(columnIndex, x, length);
}
 
public void updateAsciiStream(int columnIndex, InputStream x) throws SQLException {
getDelegate().updateAsciiStream(columnIndex, x);
}
public void updateAsciiStream(int columnIndex, InputStream x) throws SQLException {
getDelegate().updateAsciiStream(columnIndex, x);
}
 
public void updateAsciiStream(String columnLabel, InputStream x, long length) throws SQLException {
getDelegate().updateAsciiStream(columnLabel, x, length);
}
public void updateAsciiStream(String columnLabel, InputStream x, long length) throws SQLException {
getDelegate().updateAsciiStream(columnLabel, x, length);
}
 
public void updateAsciiStream(String columnLabel, InputStream x) throws SQLException {
getDelegate().updateAsciiStream(columnLabel, x);
}
public void updateAsciiStream(String columnLabel, InputStream x) throws SQLException {
getDelegate().updateAsciiStream(columnLabel, x);
}
 
public void updateBinaryStream(int columnIndex, InputStream x, long length) throws SQLException {
getDelegate().updateBinaryStream(columnIndex, x, length);
}
public void updateBinaryStream(int columnIndex, InputStream x, long length) throws SQLException {
getDelegate().updateBinaryStream(columnIndex, x, length);
}
 
public void updateBinaryStream(int columnIndex, InputStream x) throws SQLException {
getDelegate().updateBinaryStream(columnIndex, x);
}
public void updateBinaryStream(int columnIndex, InputStream x) throws SQLException {
getDelegate().updateBinaryStream(columnIndex, x);
}
 
public void updateBinaryStream(String columnLabel, InputStream x, long length) throws SQLException {
getDelegate().updateBinaryStream(columnLabel, x, length);
}
public void updateBinaryStream(String columnLabel, InputStream x, long length) throws SQLException {
getDelegate().updateBinaryStream(columnLabel, x, length);
}
 
public void updateBinaryStream(String columnLabel, InputStream x) throws SQLException {
getDelegate().updateBinaryStream(columnLabel, x);
}
public void updateBinaryStream(String columnLabel, InputStream x) throws SQLException {
getDelegate().updateBinaryStream(columnLabel, x);
}
 
public void updateBlob(int columnIndex, InputStream inputStream, long length) throws SQLException {
getDelegate().updateBlob(columnIndex, inputStream, length);
}
public void updateBlob(int columnIndex, InputStream inputStream, long length) throws SQLException {
getDelegate().updateBlob(columnIndex, inputStream, length);
}
 
public void updateBlob(int columnIndex, InputStream inputStream) throws SQLException {
getDelegate().updateBlob(columnIndex, inputStream);
}
public void updateBlob(int columnIndex, InputStream inputStream) throws SQLException {
getDelegate().updateBlob(columnIndex, inputStream);
}
 
public void updateBlob(String columnLabel, InputStream inputStream, long length) throws SQLException {
getDelegate().updateBlob(columnLabel, inputStream, length);
}
public void updateBlob(String columnLabel, InputStream inputStream, long length) throws SQLException {
getDelegate().updateBlob(columnLabel, inputStream, length);
}
 
public void updateBlob(String columnLabel, InputStream inputStream) throws SQLException {
getDelegate().updateBlob(columnLabel, inputStream);
}
public void updateBlob(String columnLabel, InputStream inputStream) throws SQLException {
getDelegate().updateBlob(columnLabel, inputStream);
}
 
public void updateCharacterStream(int columnIndex, Reader x, long length) throws SQLException {
getDelegate().updateCharacterStream(columnIndex, x, length);
}
public void updateCharacterStream(int columnIndex, Reader x, long length) throws SQLException {
getDelegate().updateCharacterStream(columnIndex, x, length);
}
 
public void updateCharacterStream(int columnIndex, Reader x) throws SQLException {
getDelegate().updateCharacterStream(columnIndex, x);
}
public void updateCharacterStream(int columnIndex, Reader x) throws SQLException {
getDelegate().updateCharacterStream(columnIndex, x);
}
 
public void updateCharacterStream(String columnLabel, Reader reader, long length) throws SQLException {
getDelegate().updateCharacterStream(columnLabel, reader, length);
}
public void updateCharacterStream(String columnLabel, Reader reader, long length) throws SQLException {
getDelegate().updateCharacterStream(columnLabel, reader, length);
}
 
public void updateCharacterStream(String columnLabel, Reader reader) throws SQLException {
getDelegate().updateCharacterStream(columnLabel, reader);
}
public void updateCharacterStream(String columnLabel, Reader reader) throws SQLException {
getDelegate().updateCharacterStream(columnLabel, reader);
}
 
public void updateClob(int columnIndex, Reader reader, long length) throws SQLException {
getDelegate().updateClob(columnIndex, reader, length);
}
public void updateClob(int columnIndex, Reader reader, long length) throws SQLException {
getDelegate().updateClob(columnIndex, reader, length);
}
 
public void updateClob(int columnIndex, Reader reader) throws SQLException {
getDelegate().updateClob(columnIndex, reader);
}
public void updateClob(int columnIndex, Reader reader) throws SQLException {
getDelegate().updateClob(columnIndex, reader);
}
 
public void updateClob(String columnLabel, Reader reader, long length) throws SQLException {
getDelegate().updateClob(columnLabel, reader, length);
}
public void updateClob(String columnLabel, Reader reader, long length) throws SQLException {
getDelegate().updateClob(columnLabel, reader, length);
}
 
public void updateClob(String columnLabel, Reader reader) throws SQLException {
getDelegate().updateClob(columnLabel, reader);
}
public void updateClob(String columnLabel, Reader reader) throws SQLException {
getDelegate().updateClob(columnLabel, reader);
}
 
public void updateNCharacterStream(int columnIndex, Reader x, long length) throws SQLException {
getDelegate().updateNCharacterStream(columnIndex, x, length);
}
public void updateNCharacterStream(int columnIndex, Reader x, long length) throws SQLException {
getDelegate().updateNCharacterStream(columnIndex, x, length);
}
 
public void updateNCharacterStream(int columnIndex, Reader x) throws SQLException {
getDelegate().updateNCharacterStream(columnIndex, x);
}
public void updateNCharacterStream(int columnIndex, Reader x) throws SQLException {
getDelegate().updateNCharacterStream(columnIndex, x);
}
 
public void updateNCharacterStream(String columnLabel, Reader reader, long length) throws SQLException {
getDelegate().updateNCharacterStream(columnLabel, reader, length);
}
public void updateNCharacterStream(String columnLabel, Reader reader, long length) throws SQLException {
getDelegate().updateNCharacterStream(columnLabel, reader, length);
}
 
public void updateNCharacterStream(String columnLabel, Reader reader) throws SQLException {
getDelegate().updateNCharacterStream(columnLabel, reader);
}
public void updateNCharacterStream(String columnLabel, Reader reader) throws SQLException {
getDelegate().updateNCharacterStream(columnLabel, reader);
}
 
public void updateNClob(int columnIndex, NClob clob) throws SQLException {
getDelegate().updateNClob(columnIndex, clob);
}
public void updateNClob(int columnIndex, NClob clob) throws SQLException {
getDelegate().updateNClob(columnIndex, clob);
}
 
public void updateNClob(int columnIndex, Reader reader, long length) throws SQLException {
getDelegate().updateNClob(columnIndex, reader, length);
}
public void updateNClob(int columnIndex, Reader reader, long length) throws SQLException {
getDelegate().updateNClob(columnIndex, reader, length);
}
 
public void updateNClob(int columnIndex, Reader reader) throws SQLException {
getDelegate().updateNClob(columnIndex, reader);
}
public void updateNClob(int columnIndex, Reader reader) throws SQLException {
getDelegate().updateNClob(columnIndex, reader);
}
 
public void updateNClob(String columnLabel, NClob clob) throws SQLException {
getDelegate().updateNClob(columnLabel, clob);
}
public void updateNClob(String columnLabel, NClob clob) throws SQLException {
getDelegate().updateNClob(columnLabel, clob);
}
 
public void updateNClob(String columnLabel, Reader reader, long length) throws SQLException {
getDelegate().updateNClob(columnLabel, reader, length);
}
public void updateNClob(String columnLabel, Reader reader, long length) throws SQLException {
getDelegate().updateNClob(columnLabel, reader, length);
}
 
public void updateNClob(String columnLabel, Reader reader) throws SQLException {
getDelegate().updateNClob(columnLabel, reader);
}
public void updateNClob(String columnLabel, Reader reader) throws SQLException {
getDelegate().updateNClob(columnLabel, reader);
}
 
public void updateNString(int columnIndex, String string) throws SQLException {
getDelegate().updateNString(columnIndex, string);
}
public void updateNString(int columnIndex, String string) throws SQLException {
getDelegate().updateNString(columnIndex, string);
}
 
public void updateNString(String columnLabel, String string) throws SQLException {
getDelegate().updateNString(columnLabel, string);
}
public void updateNString(String columnLabel, String string) throws SQLException {
getDelegate().updateNString(columnLabel, string);
}
 
public void updateRowId(int columnIndex, RowId x) throws SQLException {
getDelegate().updateRowId(columnIndex, x);
}
public void updateRowId(int columnIndex, RowId x) throws SQLException {
getDelegate().updateRowId(columnIndex, x);
}
 
public void updateRowId(String columnLabel, RowId x) throws SQLException {
getDelegate().updateRowId(columnLabel, x);
}
public void updateRowId(String columnLabel, RowId x) throws SQLException {
getDelegate().updateRowId(columnLabel, x);
}
 
public void updateSQLXML(int columnIndex, SQLXML xmlObject) throws SQLException {
getDelegate().updateSQLXML(columnIndex, xmlObject);
}
public void updateSQLXML(int columnIndex, SQLXML xmlObject) throws SQLException {
getDelegate().updateSQLXML(columnIndex, xmlObject);
}
 
public void updateSQLXML(String columnLabel, SQLXML xmlObject) throws SQLException {
getDelegate().updateSQLXML(columnLabel, xmlObject);
}
public void updateSQLXML(String columnLabel, SQLXML xmlObject) throws SQLException {
getDelegate().updateSQLXML(columnLabel, xmlObject);
}
 
@Override
public <T> T getObject(int columnIndex, Class<T> type) throws SQLException {
return getDelegate().getObject(columnIndex, type);
}
// ------------------------- JDBC 4.1 -----------------------------------
 
@Override
public <T> T getObject(String columnLabel, Class<T> type) throws SQLException {
return getDelegate().getObject(columnLabel, type);
}
@Override
public <T> T getObject(int columnIndex, Class<T> type) throws SQLException {
return getDelegate().getObject(columnIndex, type);
}
 
@Override
public <T> T getObject(String columnLabel, Class<T> type) throws SQLException {
return getDelegate().getObject(columnLabel, type);
}
}
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLSyntaxMySQL.java
19,7 → 19,7
import org.openconcerto.sql.model.graph.TablesMap;
import org.openconcerto.sql.utils.ChangeTable;
import org.openconcerto.sql.utils.ChangeTable.ClauseType;
import org.openconcerto.sql.utils.ChangeTable.OutsideClause;
import org.openconcerto.sql.utils.ChangeTable.DeferredClause;
import org.openconcerto.sql.utils.SQLUtils;
import org.openconcerto.sql.utils.SQLUtils.SQLFactory;
import org.openconcerto.utils.CollectionUtils;
194,9 → 194,9
// see http://dev.mysql.com/doc/refman/5.0/en/data-type-defaults.html
// (works the same way for 5.1 and 6.0)
if (Boolean.FALSE.equals(f.isNullable()))
res = null;
res = null;
else {
res = "NULL";
res = "NULL";
}
else if (javaType == String.class)
// this will be given to other db system, so don't use base specific quoting
594,8 → 594,9
});
}
 
public OutsideClause getSetTableComment(final String comment) {
return new OutsideClause() {
@Override
public DeferredClause getSetTableComment(final String comment) {
return new DeferredClause() {
@Override
public ClauseType getType() {
return ClauseType.OTHER;
602,8 → 603,8
}
 
@Override
public String asString(SQLName tableName) {
return "ALTER TABLE " + tableName.quote() + " COMMENT = " + SQLBase.quoteStringStd(comment) + ";";
protected String asString(ChangeTable<?> ct, SQLName tableName) {
return "ALTER TABLE " + tableName.quote() + " COMMENT = " + ct.getSyntax().quoteString(comment) + ";";
}
};
}
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLTable.java
28,7 → 28,9
import org.openconcerto.sql.model.graph.TablesMap;
import org.openconcerto.sql.request.UpdateBuilder;
import org.openconcerto.sql.utils.ChangeTable;
import org.openconcerto.sql.utils.PartialUniqueTrigger;
import org.openconcerto.sql.utils.SQLCreateMoveableTable;
import org.openconcerto.sql.utils.UniqueConstraintCreatorHelper;
import org.openconcerto.utils.CollectionUtils;
import org.openconcerto.utils.CompareUtils;
import org.openconcerto.utils.ExceptionUtils;
721,15 → 723,39
* @return the matching constraint, <code>null</code> if it cannot be found or if constraints
* couldn't be retrieved.
*/
public synchronized final Constraint getConstraint(ConstraintType type, List<String> cols) {
public final Constraint getConstraint(ConstraintType type, List<String> cols) {
if (type == null)
throw new IllegalArgumentException("Missing type");
final Set<Constraint> res = this.getConstraints(type, cols, false);
if (res == null)
return null;
if (res.size() > 1)
throw new IllegalStateException("More than one constraint matches (use getConstraints()) : " + res);
return CollectionUtils.getSole(res);
}
 
/**
* Search for constraints.
*
* @param type type of constraint, can be <code>null</code>.
* @param cols the fields names, not <code>null</code>.
* @param containing <code>true</code> if {@link Constraint#getCols() constraints columns}
* should {@link Collection#containsAll(Collection) contains all} the passed columns,
* <code>false</code> if they should be equal.
* @return the matching constraints, <code>null</code> if constraints couldn't be retrieved.
*/
public synchronized final Set<Constraint> getConstraints(ConstraintType type, List<String> cols, final boolean containing) {
if (cols == null)
throw new IllegalArgumentException("Missing columns");
if (this.constraints == null)
return null;
final Set<Constraint> res = new HashSet<>();
for (final Constraint c : this.constraints) {
if (c.getType() == type && c.getCols().equals(cols)) {
return c;
if ((type == null || c.getType() == type) && (containing ? c.getCols().containsAll(cols) : c.getCols().equals(cols))) {
res.add(c);
}
}
return null;
return res;
}
 
/**
1110,6 → 1136,8
final Set<SQLField> getFields(final Set<VirtualFieldPartition> vf) {
if (vf.isEmpty())
return Collections.emptySet();
else if (vf.equals(VirtualFields.ALL.set))
return Collections.unmodifiableSet(this.getFields());
 
final Set<SQLField> res;
// LOCAL_CONTENT is just ALL minus every other set
1131,6 → 1159,8
}
 
public final Set<String> getFieldsNames(final VirtualFields vfs) {
if (vfs.equals(VirtualFields.ALL))
return this.getFieldsName();
final Set<String> res = new HashSet<String>();
for (final SQLField f : this.getFields(vfs)) {
res.add(f.getName());
1247,7 → 1277,7
final BigDecimal maxOrder = (BigDecimal) this.getBase().getDataSource().execute(sel.asString(), new IResultSetHandler(SQLDataSource.SCALAR_HANDLER, useCache));
return maxOrder == null ? BigDecimal.ONE.negate() : maxOrder;
} catch (ClassCastException e) {
throw new IllegalStateException(orderField.getSQLName() + " must be " + SQLSyntax.get(this).getOrderDefinition(), e);
throw new IllegalStateException(orderField.getSQLName() + " must be " + SQLSyntax.get(this).getOrderDefinition(false), e);
}
}
 
1294,7 → 1324,8
* archivée.
*/
public SQLRow checkValidity(int ID) {
final SQLRow row = SQLRow.createFromSelect(this, VirtualFields.PRIMARY_KEY.union(VirtualFields.ARCHIVE), ID, LockStrength.SHARE);
// don't bother locking if we're outside a transaction
final SQLRow row = SQLRow.createFromSelect(this, VirtualFields.PRIMARY_KEY.union(VirtualFields.ARCHIVE), ID, LockStrength.NONE);
// l'inverse de getValidRow()
return row.isValid() ? null : row;
}
1990,7 → 2021,7
} else {
// partial unique index sometimes cannot be handled natively by the DB system
if (i.isUnique() && i.getFilter() != null && !system.isIndexFilterConditionSupported())
res.addUniqueConstraint(i.getName(), i.getCols(), i.getFilter());
res.addUniqueConstraint(i.getName(), i.createUniqueHelper());
else
res.addIndex(i);
}
2128,7 → 2159,7
// parse triggers, TODO remove them from triggers to output in getCreateTable()
if (thisSystem == SQLSystem.H2) {
for (final Trigger t : this.triggers.values()) {
final Matcher matcher = ChangeTable.H2_UNIQUE_TRIGGER_PATTERN.matcher(t.getSQL());
Matcher matcher = ChangeTable.H2_UNIQUE_TRIGGER_PATTERN.matcher(t.getSQL());
if (matcher.find()) {
final String indexName = ChangeTable.getIndexName(t.getName(), thisSystem);
final String[] javaCols = ChangeTable.H2_LIST_PATTERN.split(matcher.group(1).trim());
2138,6 → 2169,27
}
final String where = StringUtils.unDoubleQuote(matcher.group(2).trim());
indexes.add(createUniqueIndex(indexName, cols, where));
} else {
matcher = ChangeTable.H2_UNIQUE_TRIGGER_CLASS_PATTERN.matcher(t.getSQL());
if (matcher.find()) {
final String className = matcher.group(1);
final Class<?> triggerClass;
try {
triggerClass = Class.forName(className);
} catch (ClassNotFoundException e) {
throw new SQLException("Class not found for " + t, e);
}
PartialUniqueTrigger n;
try {
n = (PartialUniqueTrigger) triggerClass.newInstance();
} catch (Exception e) {
throw new SQLException("Couldn't instantiate class for " + t, e);
}
final String indexName = ChangeTable.getIndexName(t.getName(), thisSystem);
final Index idx = createUniqueIndex(indexName, n.getColumns(), n.getWhere());
idx.setH2Class(n.getClass());
indexes.add(idx);
}
}
}
} else if (thisSystem == SQLSystem.MYSQL) {
2286,9 → 2338,32
return filter;
}
 
@GuardedBy("uniqueH2Triggers")
private final Map<Tuple2<List<String>, String>, Class<? extends PartialUniqueTrigger>> uniqueH2Triggers = new HashMap<>();
 
public final void registerH2UniqueTrigger(Class<? extends PartialUniqueTrigger> uniqTriggerClass) throws InstantiationException, IllegalAccessException {
final PartialUniqueTrigger newInstance = uniqTriggerClass.newInstance();
final Tuple2<List<String>, String> key = Tuple2.create(newInstance.getColumns(), newInstance.getWhere().toUpperCase());
synchronized (this.uniqueH2Triggers) {
this.uniqueH2Triggers.put(key, uniqTriggerClass);
}
}
 
public static final String workAroundForH2WhereTrigger(final String where) {
return where.toUpperCase().replaceAll("[()]", "");
}
 
public final Class<? extends PartialUniqueTrigger> getH2UniqueTriggerClass(final List<String> cols, final String where) {
final Tuple2<List<String>, String> key = Tuple2.create(cols, workAroundForH2WhereTrigger(where));
synchronized (this.uniqueH2Triggers) {
return this.uniqueH2Triggers.get(key);
}
}
 
public final class Index extends SQLIndex {
 
private final List<String> cols;
private Class<? extends PartialUniqueTrigger> h2Class;
 
Index(final Map<String, Object> row) {
this((String) row.get("INDEX_NAME"), (String) row.get("COLUMN_NAME"), (Boolean) row.get("NON_UNIQUE"), (String) row.get("FILTER_CONDITION"));
2381,5 → 2456,23
}
return Value.getNone();
}
 
final void setH2Class(final Class<? extends PartialUniqueTrigger> triggerClass) {
this.h2Class = triggerClass;
}
 
final UniqueConstraintCreatorHelper createUniqueHelper() {
final Class<? extends PartialUniqueTrigger> h2Class = this.h2Class == null ? getH2UniqueTriggerClass(getCols(), getFilter()) : this.h2Class;
final String comment = h2Class == null ? null : "Unique constraint on " + getCols() + (getFilter() == null ? "" : " where " + getFilter());
return new UniqueConstraintCreatorHelper(getCols(), getFilter(), comment) {
@Override
public Object getObject(SQLSyntax s) {
if (s.getSystem() == SQLSystem.H2)
return h2Class;
else
return super.getObject(s);
}
};
}
}
}
/trunk/OpenConcerto/src/org/openconcerto/sql/model/Where.java
320,16 → 320,23
}
 
@Override
public boolean equals(final Object obj) {
if (obj instanceof Where) {
final Where o = ((Where) obj);
return this.getClause().equals(o.getClause()) && this.getFields().equals(o.getFields());
} else
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
final Where o = (Where) obj;
return this.getClause().equals(o.getClause()) && this.getFields().equals(o.getFields());
}
 
@Override
public int hashCode() {
return this.getClause().hashCode() + this.getFields().hashCode();
final int prime = 31;
int result = 1;
result = prime * result + this.getClause().hashCode();
result = prime * result + this.getFields().hashCode();
return result;
}
}
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLRowMode.java
14,12 → 14,11
package org.openconcerto.sql.model;
 
import org.openconcerto.sql.model.SQLSelect.ArchiveMode;
import org.openconcerto.utils.CollectionUtils;
import org.openconcerto.utils.cc.IPredicate;
 
import java.util.Collection;
 
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.Predicate;
 
/**
* Allow to specify which rows we're interested in.
*
95,9 → 94,10
}
 
public void filter(Collection<SQLRow> rows) {
CollectionUtils.filter(rows, new Predicate() {
public boolean evaluate(Object object) {
return check((SQLRow) object);
CollectionUtils.filter(rows, new IPredicate<SQLRow>() {
@Override
public boolean evaluateChecked(SQLRow r) {
return check(r);
}
});
}
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLRowValuesListFetcher.java
28,6 → 28,7
import org.openconcerto.utils.RecursionType;
import org.openconcerto.utils.Tuple2;
import org.openconcerto.utils.cc.ITransformer;
import org.openconcerto.utils.cc.LinkedIdentitySet;
import org.openconcerto.utils.cc.Transformer;
 
import java.sql.ResultSet;
35,10 → 36,12
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Deque;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
477,6 → 480,10
this.minGraph = null;
}
 
// MAYBE allow to remove by changing to
// addRequiredPath(Path)
// removeRequiredPath(Path)
// -> just a Set of Path, reduced at the start of fetch()
public synchronized final void requirePath(final Path p) {
this.checkFrozen();
if (this.getGraph().followPath(p) == null)
651,7 → 658,7
if (other.getGraph().hasForeigns())
throw new IllegalArgumentException("shouldn't have foreign rows");
 
final Path descendantPath = computePath(other.getGraph());
final Path descendantPath = other.getReferentPath();
final int descendantPathLength = descendantPath.length();
if (descendantPathLength == 0)
throw new IllegalArgumentException("empty path");
826,6 → 833,10
if (input.getFrom() != null) {
alias = getAlias(sel, input.getPath());
final String aliasPrev = input.getAcc();
// MAYBE use "INNER" for first step of a referent graft since the first node is
// ignored (the node from the parent graph is used)
// SITE <-- BATIMENT and graft is BATIMENT <-- LOCAL, empty BATIMENT are just
// discarded so best not to fetch them for nothing
final String joinType = isPathRequired(input.getPath()) ? "INNER" : "LEFT";
sel.addJoin(joinType, aliasPrev, input.getPath().getStep(-1), alias);
} else {
848,7 → 859,7
}
 
if (this.getSelID() != null)
sel.andWhere(getIDWhere(t, this.getSelID()));
sel.andWhere(getIDWhere(this.getSelID()));
final List<String> origSel = new ArrayList<String>(sel.getSelect());
SQLSelect res = sel;
for (final ITransformer<SQLSelect, SQLSelect> tr : this.getSelectTransformers()) {
859,10 → 870,10
return checkTr(origSel, res).andWhere(w);
}
 
static private Where getIDWhere(final SQLTable t, final Number id) {
public final Where getIDWhere(final Number id) {
if (id == null)
return null;
return new Where(t.getKey(), "=", id);
return new Where(getGraph().getTable().getKey(), "=", id);
}
 
static String getAlias(final SQLSelect sel, final Path path) {
1121,7 → 1132,7
throw new NullPointerException("Null ID");
if (this.getSelID() != null)
throw new IllegalStateException("ID already set to " + getSelID());
final List<SQLRowValues> res = this.fetch(getIDWhere(getGraph().getTable(), id), unmodifiableRows);
final List<SQLRowValues> res = this.fetch(getIDWhere(id), unmodifiableRows);
if (res.size() > 1)
throw new IllegalStateException("More than one row for ID " + id + " : " + res);
return CollectionUtils.getFirst(res);
1162,10 → 1173,70
}
 
public final List<SQLRowValues> fetch(final Where w, final ITransformer<SQLSelect, SQLSelect> selTransf, final Boolean unmodifiableRows) throws IllegalArgumentException {
return this.fetch(true, w, selTransf, unmodifiableRows);
return this.fetch(null, w, selTransf, unmodifiableRows);
}
 
private final List<SQLRowValues> fetch(final boolean merge, final Where w, final ITransformer<SQLSelect, SQLSelect> selTransf, final Boolean unmodifiableRows) throws IllegalArgumentException {
// same object passed to all recursive calls
static private final class MainResult {
private final Deque<GraftState> graftStates = new LinkedList<>();
 
private MainResult() {
super();
}
 
private GraftState getLastGraftState() {
return this.graftStates.peekLast();
}
 
private void push(final List<SQLRowValues> merged, final Path graftPlace) {
final GraftState graftState = this.getLastGraftState();
final Path recPath = graftState == null ? null : graftState.pathFromMain;
final GraftState recGraftState = new GraftState(merged, recPath, graftPlace);
this.graftStates.addLast(recGraftState);
}
 
private void pop() {
this.graftStates.removeLast();
}
}
 
static private final class GraftState {
 
private final Path pathFromMain;
 
// list of BATIMENT to only fetch what's necessary
private final Set<Number> ids = new HashSet<Number>();
// CollectionMap since the same row can be in multiple index of merged, e.g. when
// fetching *BATIMENT* -> SITE each site will be repeated as many times as it has
// children and if we want their DOSSIER they must be grafted on each line.
private final ListMap<Tuple2<Path, Number>, SQLRowValues> byRows = createCollectionMap();
 
private GraftState(final List<SQLRowValues> parentRows, final Path pathFromMain, final Path graftPlace) {
this.pathFromMain = pathFromMain == null ? graftPlace : pathFromMain.append(graftPlace);
final Path mapPath = Path.get(graftPlace.getLast());
for (final SQLRowValues vals : parentRows) {
// can be empty when grafting on optional row
for (final SQLRowValues graftPlaceVals : vals.followPath(graftPlace, CreateMode.CREATE_NONE, false)) {
this.ids.add(graftPlaceVals.getIDNumber());
this.byRows.add(Tuple2.create(mapPath, graftPlaceVals.getIDNumber()), graftPlaceVals);
}
}
assert this.ids.size() == this.byRows.size();
}
 
private Where createWhere() {
return new Where(this.pathFromMain.getLast().getKey(), this.ids);
}
}
 
private final List<SQLRowValues> fetch(MainResult mainRes, Where w, final ITransformer<SQLSelect, SQLSelect> selTransf, final Boolean unmodifiableRows) throws IllegalArgumentException {
final GraftState graftState = mainRes == null ? null : mainRes.getLastGraftState();
if (graftState != null) {
final Where graftWhere = graftState.createWhere();
if (graftWhere.equals(Where.FALSE))
return Collections.emptyList();
w = Where.and(w, graftWhere);
}
final SQLSelect req;
final Map<Path, Map<Path, SQLRowValuesListFetcher>> grafts;
final boolean freezeRows;
1215,7 → 1286,7
}
assert l.size() == graphSize : "All nodes weren't explored once : " + l.size() + " != " + graphSize + "\n" + this.getGraph().printGraph();
 
final boolean mergeReferents = merge && this.fetchReferents();
final boolean mergeReferents = this.fetchReferents();
final boolean mergeGrafts = grafts.size() > 0;
// if it is possible let the handler do the freeze, avoid another loop and further is
// multi-threaded
1228,39 → 1299,33
@SuppressWarnings("unchecked")
final List<SQLRowValues> res = (List<SQLRowValues>) table.getBase().getDataSource().execute(req.asString(), rsh, false);
// e.g. list of batiment pointing to site
final List<SQLRowValues> merged = mergeReferents ? merge(res) : res;
final List<SQLRowValues> merged;
if (!mergeReferents) {
merged = res;
} else if (graftState == null) {
merged = merge(res);
} else {
// merge before recursive call, so it can access the main graph
merged = mergeGraft(res, graftState.byRows);
}
if (mergeGrafts) {
if (mainRes == null) {
mainRes = new MainResult();
}
for (final Entry<Path, Map<Path, SQLRowValuesListFetcher>> graftPlaceEntry : grafts.entrySet()) {
// e.g. BATIMENT
final Path graftPlace = graftPlaceEntry.getKey();
final Path mapPath = Path.get(graftPlace.getLast());
// list of BATIMENT to only fetch what's necessary
final Set<Number> ids = new HashSet<Number>();
// byRows is common to all grafts to support CPI -> LOCAL -> BATIMENT and RECEPTEUR
// common to all grafts to support CPI -> LOCAL -> BATIMENT and RECEPTEUR
// -> LOCAL -> BATIMENT (ie avoid duplicate LOCAL)
// CollectionMap since the same row can be in multiple index of merged, e.g. when
// fetching *BATIMENT* -> SITE each site will be repeated as many times as it has
// children and if we want their DOSSIER they must be grafted on each line.
final ListMap<Tuple2<Path, Number>, SQLRowValues> byRows = createCollectionMap();
for (final SQLRowValues vals : merged) {
// can be empty when grafting on optional row
for (final SQLRowValues graftPlaceVals : vals.followPath(graftPlace, CreateMode.CREATE_NONE, false)) {
ids.add(graftPlaceVals.getIDNumber());
byRows.add(Tuple2.create(mapPath, graftPlaceVals.getIDNumber()), graftPlaceVals);
}
}
assert ids.size() == byRows.size();
mainRes.push(merged, graftPlace);
for (final Entry<Path, SQLRowValuesListFetcher> e : graftPlaceEntry.getValue().entrySet()) {
// e.g BATIMENT <- LOCAL <- CPI
final Path descendantPath = e.getKey();
assert descendantPath.getFirst() == graftPlace.getLast() : descendantPath + " != " + graftPlace;
final SQLRowValuesListFetcher graft = e.getValue();
 
// don't merge then...
final List<SQLRowValues> referentVals = graft.fetch(false, new Where(graft.getGraph().getTable().getKey(), ids), null, false);
// ...but now
merge(merged, referentVals, byRows, descendantPath);
graft.fetch(mainRes, null, null, false);
}
mainRes.pop();
}
}
if (freezeRows && !handlerCanFreeze) {
1375,6 → 1440,12
return merge(l, l, null, this.descendantPath);
}
 
private final List<SQLRowValues> mergeGraft(final List<SQLRowValues> l, final ListMap<Tuple2<Path, Number>, SQLRowValues> graftPlaceRows) {
if (graftPlaceRows == null)
throw new IllegalArgumentException("Missing map");
return merge(null, l, graftPlaceRows, this.descendantPath);
}
 
/**
* Merge a list of rowValues and optionally graft it onto another one.
*
1384,13 → 1455,13
* @param graftPlaceRows if this is a graft the destination rowValues, otherwise
* <code>null</code>, this instance will be modified.
* @param descendantPath the path to merge.
* @return the merged and grafted values.
* @return the merged list of main values, or the graft places if it's a graft.
*/
static private final List<SQLRowValues> merge(final List<SQLRowValues> tree, final List<SQLRowValues> graft, final ListMap<Tuple2<Path, Number>, SQLRowValues> graftPlaceRows,
Path descendantPath) {
final boolean isGraft = graftPlaceRows != null;
assert (tree != graft) == isGraft : "Trying to graft onto itself";
final List<SQLRowValues> res = isGraft ? tree : new ArrayList<SQLRowValues>();
final Collection<SQLRowValues> res = isGraft ? new LinkedIdentitySet<SQLRowValues>() : new ArrayList<SQLRowValues>();
// so that every graft is actually grafted onto the tree
final ListMap<Tuple2<Path, Number>, SQLRowValues> map = isGraft ? graftPlaceRows : createCollectionMap();
 
1433,6 → 1504,16
}
// don't call map.put() it has already been handled below
previous.put(ffName, destinationRows.get(0));
 
if (isGraft) {
final Path pathToGraftPlace = subPath.reverse();
for (final SQLRowValues r : destinationRows) {
final SQLRowValues graftPlaceRow = r.followPath(pathToGraftPlace);
if (graftPlaceRow == null)
throw new IllegalStateException("Row at graft place not found");
res.add(graftPlaceRow);
}
}
}
} else {
map.add(row, desc);
1445,7 → 1526,7
res.add(v);
}
}
return res;
return res instanceof List ? (List<SQLRowValues>) res : new ArrayList<>(res);
}
 
@Override
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLSyntax.java
20,8 → 20,9
import org.openconcerto.sql.model.SQLTable.SQLIndex;
import org.openconcerto.sql.model.graph.Link.Rule;
import org.openconcerto.sql.model.graph.TablesMap;
import org.openconcerto.sql.utils.ChangeTable;
import org.openconcerto.sql.utils.ChangeTable.ClauseType;
import org.openconcerto.sql.utils.ChangeTable.OutsideClause;
import org.openconcerto.sql.utils.ChangeTable.DeferredClause;
import org.openconcerto.sql.utils.SQLUtils;
import org.openconcerto.utils.CollectionUtils;
import org.openconcerto.utils.CompareUtils;
432,23 → 433,30
return 8;
}
 
public final Object getOrderDefault() {
public final String getOrderDefault() {
return null;
}
 
public final boolean isOrder(final SQLField f) {
public final boolean isOrderNullable() {
return true;
}
 
public final boolean isOrder(final SQLField f, final boolean checkConstraint) {
final SQLType type = f.getType();
if (type.getType() != Types.DECIMAL && type.getType() != Types.NUMERIC)
return false;
if (type.getSize() != getOrderPrecision() || ((Number) type.getDecimalDigits()).intValue() != getOrderScale())