From 804c1ed5dd99abb0e79eca3d41937603173ff746 Mon Sep 17 00:00:00 2001 From: manu Date: Wed, 23 Aug 2023 10:11:29 +0200 Subject: [PATCH] [ADD]website_contact_lastname: New module to set lastname from portal --- .../odoo/addons/website_contact_lastname | 1 + setup/website_contact_lastname/setup.py | 6 + website_contact_lastname/__init__.py | 5 + website_contact_lastname/__manifest__.py | 23 +++ .../controllers/__init__.py | 5 + website_contact_lastname/controllers/main.py | 159 ++++++++++++++++++ .../controllers/portal.py | 63 +++++++ website_contact_lastname/models/__init__.py | 5 + .../models/res_partner.py | 26 +++ website_contact_lastname/models/res_users.py | 37 ++++ website_contact_lastname/readme/CONFIGURE.rst | 1 + .../readme/CONTRIBUTORS.rst | 3 + .../readme/DESCRIPTION.rst | 2 + website_contact_lastname/readme/USAGE.rst | 8 + .../static/description/icon.png | Bin 0 -> 35820 bytes .../views/auth_signup_login_templates.xml | 23 +++ .../views/portal_templates.xml | 42 +++++ website_contact_lastname/views/templates.xml | 43 +++++ 18 files changed, 452 insertions(+) create mode 120000 setup/website_contact_lastname/odoo/addons/website_contact_lastname create mode 100644 setup/website_contact_lastname/setup.py create mode 100644 website_contact_lastname/__init__.py create mode 100644 website_contact_lastname/__manifest__.py create mode 100644 website_contact_lastname/controllers/__init__.py create mode 100644 website_contact_lastname/controllers/main.py create mode 100644 website_contact_lastname/controllers/portal.py create mode 100644 website_contact_lastname/models/__init__.py create mode 100644 website_contact_lastname/models/res_partner.py create mode 100644 website_contact_lastname/models/res_users.py create mode 100644 website_contact_lastname/readme/CONFIGURE.rst create mode 100644 website_contact_lastname/readme/CONTRIBUTORS.rst create mode 100644 website_contact_lastname/readme/DESCRIPTION.rst create mode 100644 website_contact_lastname/readme/USAGE.rst create mode 100644 website_contact_lastname/static/description/icon.png create mode 100644 website_contact_lastname/views/auth_signup_login_templates.xml create mode 100644 website_contact_lastname/views/portal_templates.xml create mode 100644 website_contact_lastname/views/templates.xml diff --git a/setup/website_contact_lastname/odoo/addons/website_contact_lastname b/setup/website_contact_lastname/odoo/addons/website_contact_lastname new file mode 120000 index 0000000000..c444f62428 --- /dev/null +++ b/setup/website_contact_lastname/odoo/addons/website_contact_lastname @@ -0,0 +1 @@ +../../../../website_contact_lastname \ No newline at end of file diff --git a/setup/website_contact_lastname/setup.py b/setup/website_contact_lastname/setup.py new file mode 100644 index 0000000000..28c57bb640 --- /dev/null +++ b/setup/website_contact_lastname/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +) diff --git a/website_contact_lastname/__init__.py b/website_contact_lastname/__init__.py new file mode 100644 index 0000000000..ea6bb1f80b --- /dev/null +++ b/website_contact_lastname/__init__.py @@ -0,0 +1,5 @@ +# Copyright 2023 Manuel Regidor +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from . import controllers +from . import models diff --git a/website_contact_lastname/__manifest__.py b/website_contact_lastname/__manifest__.py new file mode 100644 index 0000000000..48fda778d2 --- /dev/null +++ b/website_contact_lastname/__manifest__.py @@ -0,0 +1,23 @@ +# Copyright 2023 Manuel Regidor +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +{ + "name": "Website Contact Lastname", + "version": "15.0.1.0.0", + "category": "Website", + "website": "https://github.com/OCA/website", + "author": "Sygel Technology," "Odoo Community Association (OCA)", + "license": "AGPL-3", + "application": False, + "installable": True, + "depends": [ + "auth_signup", + "website_account_fiscal_position_partner_type", + "partner_firstname", + ], + "data": [ + "views/templates.xml", + "views/auth_signup_login_templates.xml", + "views/portal_templates.xml", + ], +} diff --git a/website_contact_lastname/controllers/__init__.py b/website_contact_lastname/controllers/__init__.py new file mode 100644 index 0000000000..294141a404 --- /dev/null +++ b/website_contact_lastname/controllers/__init__.py @@ -0,0 +1,5 @@ +# Copyright 2023 Manuel Regidor +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from . import main +from . import portal diff --git a/website_contact_lastname/controllers/main.py b/website_contact_lastname/controllers/main.py new file mode 100644 index 0000000000..ab0cdb9f37 --- /dev/null +++ b/website_contact_lastname/controllers/main.py @@ -0,0 +1,159 @@ +# Copyright 2023 Manuel Regidor +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from odoo import _ +from odoo.http import request + +from odoo.addons.auth_signup.controllers.main import AuthSignupHome +from odoo.addons.website_sale.controllers.main import WebsiteSale + + +class WebsiteSale(WebsiteSale): + def _get_mandatory_fields_shipping(self, country_id=False): + req = super()._get_mandatory_fields_shipping(country_id) + req += ["firstname"] + if "name" in req: + req.remove("name") + return req + + def _get_mandatory_fields_billing(self, country_id=False): + req = super()._get_mandatory_fields_billing(country_id) + req.append("firstname") + if request.env.context.get("fiscal_position_type") == "b2c": + req.append("lastname") + # Name is removed as this field cannot be explicitly edited + # It is edited in the backend through the fields first name + # and lastname + if "name" in req: + req.remove("name") + return req + + def values_postprocess(self, order, mode, values, errors, error_msg): + new_values, errors, error_msg = super(WebsiteSale, self).values_postprocess( + order=order, mode=mode, values=values, errors=errors, error_msg=error_msg + ) + new_values.update( + { + "firstname": values.get("firstname") or "", + "lastname": values.get("lastname") or "", + } + ) + # Name is removed as this field cannot be explicitly edited + # It is edited in the backend through the fields first name + # and lastname + new_values.pop("name") + return new_values, errors, error_msg + + def checkout_form_validate(self, mode, all_form_values, data): + required_fields = [ + f for f in (all_form_values.get("field_required") or "").split(",") if f + ] + # Name is removed as this field cannot be explicitly edited + # It is edited in the backend through the fields first name + # and lastname + if "name" in required_fields: + required_fields.remove("name") + all_form_values["field_required"] = ",".join(required_fields) + error, error_message = super().checkout_form_validate( + mode, all_form_values, data + ) + if data.get("partner_id"): + partner_su = ( + request.env["res.partner"] + .sudo() + .browse(int(data["partner_id"])) + .exists() + ) + can_edit_vat = ( + partner_su.parent_id.can_edit_vat() + if partner_su.parent_id + else partner_su.can_edit_vat() + ) + firstname_change = ( + partner_su + and "firstname" in data + and data["firstname"] != partner_su.firstname + ) + if firstname_change and not can_edit_vat: + error["firstname"] = "error" + error_message.append( + _( + "Changing your name is not allowed once invoices have been" + " issued for your account. Please contact us directly for " + "this operation." + ) + ) + # When lastname field in form is empty, its values is False + # When lastname field in backend is empty, its values is '' + # In that case, if both are compared, they are considered to be + # different so data['lastname'] != partner_su.lastname would + # return True although no real change would have been applied. + lastname_change = ( + partner_su + and "lastname" in data + and data["lastname"] != partner_su.lastname + and (data["lastname"] or partner_su.lastname not in ["", False]) + ) + if lastname_change and not can_edit_vat: + error["lastname"] = "error" + error_message.append( + _( + "Changing your last name is not allowed once invoices have" + " been issued for your account. Please contact us directly" + " for this operation." + ) + ) + + # Prevent change the partner name, lastname if + # it is an internal user. + if (firstname_change or lastname_change) and not all( + partner_su.user_ids.mapped("share") + ): + error.update( + { + "firstname": "error" if firstname_change else None, + "lastname": "error" if lastname_change else None, + } + ) + error_message.append( + _( + "If you are ordering for an external person, please place " + "your order via the backend. If you wish to change your " + "name or last name, please do so in the account settings " + "or contact your administrator." + ) + ) + return error, error_message + + +class AuthSignupHome(AuthSignupHome): + def get_auth_signup_qcontext(self): + qcontext = super().get_auth_signup_qcontext() + qcontext.update( + { + k: v + for (k, v) in request.params.items() + if k + in { + "lastname", + } + } + ) + if "name" in qcontext: + qcontext["firstname"] = qcontext["name"] + if ( + "error" not in qcontext + and request.httprequest.method == "POST" + and qcontext.get("fiscal_position_type") == "b2c" + and not qcontext.get("lastname") + ): + qcontext["error"] = _("Lastname is required for B2C users.") + return qcontext + + def _prepare_signup_values(self, qcontext): + values = super()._prepare_signup_values(qcontext) + if "firstname" in qcontext: + values["firstname"] = qcontext["firstname"] + if "lastname" in qcontext: + values["lastname"] = qcontext["lastname"] + return values diff --git a/website_contact_lastname/controllers/portal.py b/website_contact_lastname/controllers/portal.py new file mode 100644 index 0000000000..e99afd139f --- /dev/null +++ b/website_contact_lastname/controllers/portal.py @@ -0,0 +1,63 @@ +# Copyright 2023 Manuel Regidor +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from odoo import _ +from odoo.http import request + +from odoo.addons.portal.controllers.portal import CustomerPortal + + +class CustomerPortal(CustomerPortal): + + CustomerPortal.OPTIONAL_BILLING_FIELDS += [ + "firstname", + "lastname", + ] + + def details_form_validate(self, data): + context = dict(request.env.context) + # 'name' field cannont be updated as it would recompute fields + # firstname and lastname. That is why it is set in context + # that changes in field name need to be ignored. + context.update({"name_ignore": True}) + request.env.context = context + error, error_message = super().details_form_validate(data) + partner = request.env.user.partner_id + if partner.can_edit_vat(): + if "firstname" in data and not data.get("Name"): + error["firstname"] = "error" + error_message.append(_("Firstname is mandatory.")) + if ( + "lastname" in data + and not data.get("lastname") + and ( + (data.get("fiscal_position_type") == "b2c") + or ( + partner.fiscal_position_type == "b2c" + and not data.get("fiscal_position_type") == "b2b" + ) + ) + ): + error["lastname"] = "error" + error["fiscal_position_type"] = "error" + error_message.append(_("Lastname is mandatory for B2C users.")) + else: + if "firstname" in data and data.get("firstname") != partner.firstname: + error["firstname"] = "error" + error_message.append( + _( + "Changing Name is not allowed once document(s) have been " + "issued for your account. Please contact us directly for " + "this operation." + ) + ) + if "lastname" in data and data.get("lastname") != partner.lastname: + error["lastname"] = "error" + error_message.append( + _( + "Changing Lastname is not allowed once document(s) have " + "been issued for your account. Please contact us directly " + "for this operation." + ) + ) + return error, error_message diff --git a/website_contact_lastname/models/__init__.py b/website_contact_lastname/models/__init__.py new file mode 100644 index 0000000000..a227d7676d --- /dev/null +++ b/website_contact_lastname/models/__init__.py @@ -0,0 +1,5 @@ +# Copyright 2023 Manuel Regidor +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from . import res_users +from . import res_partner diff --git a/website_contact_lastname/models/res_partner.py b/website_contact_lastname/models/res_partner.py new file mode 100644 index 0000000000..943a233393 --- /dev/null +++ b/website_contact_lastname/models/res_partner.py @@ -0,0 +1,26 @@ +# Copyright 2023 Manuel Regidor +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl-3). + +from odoo import api, models +from odoo.http import request + + +class Partner(models.Model): + _inherit = "res.partner" + + @api.model + def signup_retrieve_info(self, token): + res = super().signup_retrieve_info(token) + partner = self._signup_retrieve_partner(token, raise_exception=True) + res.update( + { + "name": partner.firstname, + "lastname": partner.lastname, + } + ) + return res + + def write(self, vals): + if vals.get("name") and request.env.context.get("name_ignore"): + vals.pop("name") + return super().write(vals) diff --git a/website_contact_lastname/models/res_users.py b/website_contact_lastname/models/res_users.py new file mode 100644 index 0000000000..01138a8976 --- /dev/null +++ b/website_contact_lastname/models/res_users.py @@ -0,0 +1,37 @@ +# Copyright 2023 Manuel Regidor +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl-3). + +from odoo import api, models + + +class ResUsers(models.Model): + _inherit = "res.users" + + @api.model + def signup(self, values, token=None): + if token: + partner = self.env["res.partner"]._signup_retrieve_partner( + token, check_validity=True, raise_exception=True + ) + partner_user = partner.user_ids and partner.user_ids[0] or False + # Don't update firstname and lastname if partner + # related to user exists (i.e. when resetting password) + if partner_user: + values.pop("firstname", None) + values.pop("lastname", None) + return super().signup(values, token) + + def _create_user_from_template(self, values): + user = super()._create_user_from_template(values) + # Because of the way the name is computed, it is important to + # reset the values so the final name is correct. + # It cannot be done before (the way would be setting the value of name + # if param. values to '') as the funcion _create_user_from_template + # checks that values contains a value for 'name' + user.write( + { + "firstname": values.get("firstname"), + "lastname": values.get("lastname"), + } + ) + return user diff --git a/website_contact_lastname/readme/CONFIGURE.rst b/website_contact_lastname/readme/CONFIGURE.rst new file mode 100644 index 0000000000..05dcf8709a --- /dev/null +++ b/website_contact_lastname/readme/CONFIGURE.rst @@ -0,0 +1 @@ +No configuration needed. diff --git a/website_contact_lastname/readme/CONTRIBUTORS.rst b/website_contact_lastname/readme/CONTRIBUTORS.rst new file mode 100644 index 0000000000..9a9de12727 --- /dev/null +++ b/website_contact_lastname/readme/CONTRIBUTORS.rst @@ -0,0 +1,3 @@ +* `Sygel `_: + + * Manuel Regidor diff --git a/website_contact_lastname/readme/DESCRIPTION.rst b/website_contact_lastname/readme/DESCRIPTION.rst new file mode 100644 index 0000000000..f77181f0df --- /dev/null +++ b/website_contact_lastname/readme/DESCRIPTION.rst @@ -0,0 +1,2 @@ +This module allows users to introduce and edit their lastname +from the portal. diff --git a/website_contact_lastname/readme/USAGE.rst b/website_contact_lastname/readme/USAGE.rst new file mode 100644 index 0000000000..995cc089f7 --- /dev/null +++ b/website_contact_lastname/readme/USAGE.rst @@ -0,0 +1,8 @@ +Lastname can be set from 3 differents places in the portal: + +* Signup page +* User's details page +* Checkout billing address page +* Checkout shipping address page + +In all cases but the checkout shipping address page, lastname field must be filled if the user is B2C. Otherwise, it can be left blank. In the checkout shipping address page, lastname can be left blank. diff --git a/website_contact_lastname/static/description/icon.png b/website_contact_lastname/static/description/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..207fb7ad5535215836f426bcebfdccdbc51c0d27 GIT binary patch literal 35820 zcmcG02UJsC);7H>Rk{L#6ltLtkQSt)fFOb(BB6tXUZsN|9YhpCsvt!v5<*8HAfYI| zhK`{0D!t~v!Fk*K^Ua!XUO(4j3CTTopR>!epS{nyH$q!W^&A;984eE4IdwIqJ2*JF zDZtNn5+dLe&JrDU;6Gf~JE{se#a*n6z#pVeYKE>jI6|D*A6%~-hzD?iq3vA*Hv>%# zDRW1AAyW%SGfN>adne#(92^-hDd1OoOE*(?FMF7StCW}Q<+CfKfZwqn3twhGyTr{- z_OgMdHoKyuizWLtA#owlWjQi-c6J#T3oEHRN-F;t4*Vs1*~ZPyNlIAQ)6-MPQ%uOw z#adY8`t|F=AW>maQ94z8R(Z}QuHlq_A%U2L7)Y#klgvG+AKb98r; zy?hxf==Xm==jmo^^@k(}*MBSvSfDWW8(|S4knr#K28PODKb5-eVrvOV#@=5}MCRqjCk}3Lv?sn^ z#2Y+jw5^)(yOcl;+QF-OcO=Yyv(GfvSOSmW>X7XCRMg)1)R&Ep$hPQk-%R+d-|6I* ziPuwW3vXp1`rU3u5K%O)Ir9JRKd2MY`$m3)ph+e)W@r79e$>(gPHJkC5^Cn*x#vLc}y!{^_`i+34H=@PX>mOp=vzBZ~Oe@|K!S*9-V zCgbfn?Rca(p*x+z&8!MZttFWNb(gGCysYlwz)0Q_@eNUPnn)2F)u0^H2b|4GTy*Ab z=;bJsFy#6{lkRpA-%3%kwXKoa^z?LXM!^zlGwUglHpx?^(0t{h>kkNOvI3>7c+d*+ zR!dEvX-3VG?FbACd2*>vM>)iww_Lwv{TXQh*S|wkt0GOd@MxYS2^?`{JE08sDos*u zW~_pm`T%{adfL3Oy4GEN`RxN{ZEC_qqK8%*3L-?Sz~rLsLKqW5%qXJk?vJmVzuBy+ zK(p8OQ>B|2vsPCsO1yS(&dQ`BiqDr6O_H}^$D32ab*GtCF3avAvdFb*TM^00XA5M* zrDq}5B@ym%Y-Ri>75S_+{wo#r&GF7#(StBMeZUNI2i zCPhivsG2St=;>w1NFFrhp=YlU8o`9rr@8wJ7@}z5m%47#DHvp#74Ob$;wI4&4v0vT z*r>ia*QU|?Y{dMg4g?2+CjdSVm?Lv4R;1J|mm>Ot-IXhFyRz)SVvpEB+XMpzh&oH= zuBf-=R-jE(8l)v1JU{-%OA&|zyQXo!Et<};i9?4 zq6QNq|Ip2wX2UkBxW=ojxc%Jl5dY_3d1btQx&a*$zKGEoN%fTMq$f=@g;>L1EXyvr zSXi^PIxEJQA_zt{x5YW=B5nJ#z+dZV=XuC9Z`x5_J@vd$NKlHxQ71WDH>ZjYM7_@5 z3_hyCF^_k+%E<}qQ6fao<^R*F#fLt%@|f)794)GspmKRG zhlNz1H24lTe5ne$Rz|vxk2QNAjk}=01^k|nzz(`|$+Bj2F@ok z#s5#1D()jSrQTNr=SD06MGYirjp`%=hJ-7Ra^3|ZP zgQdtguIL!C^4Pl4xoR5(Uod~JUHHUzus>;Pz=G)Pw`Hbbm6yAD9#HFEHnSfaQO}ob4z*!LDM#-I*Ptg59fV zvwr@xlb}_$3&a1H3h@5q65i@}3anovjFoH~b zsrDM_EfkJ8$4~raR5ri0WKSD4Xhn9N;a}Ne>R+bFf3n2`vM+B~Id=mUO2y9`v}Z;! zq9OZhntK{q8J3MB$&pVxE{T)PI=@i^{ zW8zWBu~x^e$>#j^7Is6QueI~2Y;?yl#h?(Z z+g2U;FOtv!(SMSJEDOEYKa0$q6F{4Zff@^t>uksEK`CzuyCL`k#qCKN3Tj)bZf~eQ zMnv+BMyWR45y8>?&*1pcJj=f%1*5DeR=Pwe3ScD5Kt?qye5BJL`%T|^MTD#Z{Wcn= z^MT$cPxG<;b8lWxm2aE@?@JO`BP5&6p7uB}&GJXiVI4}H(&hvVJC7Zw|e+OqSx_x-kxmxAMK zL2#YU3SAC+g=*^tprV z?J-J&SMqXA3FJ8ROEk(O1|K_b4h-JkIwJTUK9zI$pu7S$`A-BODhiOhDJi4+)qIlT9J-iu zJwq#4XsRH-u#vxm`i&d@hnX_8Mcd@@*9Ml!&k!S6g@O-n4aRQmz*=wT{+L24qpv?z z<(v~oasg!_fw&G_+xKXa1HG#aJQ>o3WuQ|jOf1`F*G2r;Jr{nl{)*IAnP#?yW|EY*UYDhyu13Svp z3kxMH#&;>W&jOT->uRQW>+b>jfM9fa%kG{;?O<}uAm14-s0H|cb+9hr$Os_9k3gK` zxrmP@Smm-QaL<0ecSzf-2z6lUbYXvv!4yWbE{kE;i-UPN0$mV7ryiB zU6?S`VlyDM$(r$sJX~5L?g_b^{EnRe7S2YH7vBE0BePXepN&6gU zGKP{_i&>ALcd z;xXbw@q0ymyIVKwi5%X=8}rp-3IbfFC!3GUm>lP8nV?tFxmRJfl5(wJ3P>AFaF%cDLesBK^W%HvkN$@}2yZ{w9hZ(91f@8H`g z#CHsYzPy4{wILJ$6s2du{)Vpeou--lCP^OqVtb0%S)ljWJpP@G#u++iF=0!umWxXa z!jw#>^cRd^V71d#lOx)O))ONBk?Ym$HEHrtQ`K{=#Hayq{ZFUX*ZDU9!#w{x1%>9O zWdODED3`uItC52bQ9>VsLM9ar%?0h(=JN-)p3}ah^O|orfjJh4u_Wli;Ob0FYI{a$ z7q{UgQ-EatuB*;2)r{v_^ZsE}GUHb}gM*Zrq{?S40i0?4O@a-(UDT*$WRGKEPA6ev z*NY&yS5(87(8E2jp89~1F~rwJxpvNJt>XfKtwVj@KO8!4aBy9Dq~x;sS`pc& z093S1l_!CGEhKL=m2@DSO=h#uGukEd=$|XUf(#S2Rs35>?XTuAECt8q(7~;^?vdWW zmHb|>Zl|aVCZI*#@bKmnjRsbH&$X)gj8(y!jDWc>ZvHn&>Y8=)(r%o~dxy*Dw1UrX z%cb+?xs=?{y?c;AZn}02V*^9HK=Kcv?Gc$95s`(=3H@ zgrgPz6wvo}MrI*LeVR{2@K9?ouoKO=0&S&KYvrZwi)!~9wk9aJ+@M&mE|@w)_nz{J zuQ>mmS5NlorWtkzn?=RQ-^|DzYuH__J-=Q~FQyf3;a}#@0d#(T!>3lC`cAfJM z49>J+Arr7Up0UrO83CgKdL=yPuxnoZ>za+60wb%8@#!o_X=-eJWC;z> z#OS)$_%CTIb(h_rI!8#C|1mGAK8{T{X*f0XuQOF2y9X?Cf%UG>y_wsxJP2-`O}*3+ zb@LzJng+n4!8QiWvBYgIhsc}qv=@$q{ys2kbY&b>KTjYAdKNEG(HiQz9WjNq5funb z!IV_K(60YzSsX<+mCDQfs$p>iEsa#AyaJ4%w?v#ZBmMh!(91yXt8VsVSwa7MZ9AQI zUBaODE2I!|X+R3%0+qETY~ zKD8{fqQ7zwR=zHZ`!{>hIQ9S$u|Fe)_f7u5Y@*x>v{EAC|0g0fvwVy=THNKvSZue6kb|715YOa2w(580R7uV9`PUgbQ^ekui)10r*1}Yx08K`qc zM3(=RemT9B6tm$|HpedmI9NG0Vc7ji^Fd5Wqh_>*U4JbIxZk{I;4wceVrE2@W($J9 zp!v3|HE}(S7wkg6a!|~lCyTh)lLaBgcXSm1oUiRXcH!Wi*BBtsD6Zr>_rwFcl5O%&@9FB@3Q(o zAeKVI9v&fJ{byeGRZj68Lo21$)IObPu1gte?z#2Sf$NWBgnLOFm)W8Xae*jl<7%8T zLl`&6!tz?MA&TRjNZ&=N!#;1bpUT(&*AUy-Pckv1!}5Elwse(&>mO|8d<>Z{pC94Y zC!VR47X5jTz#F9~Zc7V7W8c#evIEA*EvnGzn|D)R{&Jl8R=*Ur#CSQ^16U`Gb>ZXF zk=$A{jH`#gljqeAQXgnZyIi2?qu&T&gnba`ekbET+gSHh<<}Z)qZ~k=lKv$={ zsH;bo)gF$^tuGnb4KdJ7w3jbW5dEE_55s zZ*}W88!^W^`f8JWjfh-Fi%Q=R_Lf-sW$GZUoyX^B_lcLzbUjjY9%X z)u#CqF5mx3xP0?{={xnVoO2_6$_1_In}AtyEC27zT3gg*5)kNj`vH)MHwcP%ju8qg zSs<+Qmi=^Iy-1<+zsQ6If)5+UQ#y@f<|pV`QvGV2-pyw$mK69nUCN>Y{e<5aSm6If ztRr_w`nFcXF`Z9Z5U>x@sQz(#tDEc*UD$LKPUy4O`TKaESKi+F6V0$6lq-3zLUY0H z!e2{6HD{}yJCQ9!Hb8y&NbIcHaA@{NvjJ3&;x0{%F-qI zso1iG0hbIHs5`I_I{2#~^u%;xWuc0r3xGTNTqXO2h)_@ivJ?2O z6^~wIy3hAtf?PT9HHiP-a+rb7Q(*sxgvUL*8$!GE!M@4Un3n*^OP;Xgw7WvT3MX?) zx;_jGTkR01wsBCy;2aiSy^ii4>lTw59sN33zg&<#(`UPO)GtDl!m#ga5n7j0>o@s^ zQr`g~=VDe+SJ&SxE_=a*fHy?sXC1-h@~h(DB@hQ`{wIufoj}R*G(RB>XP?M^|b}pl|EjiTIp&@`}TfR+9T{h zNZkMOY^@O8$Cv0Qkx#iOK6b(vCi3GRoOU_90ji$dhg%syI=FG=zhg{HLkByk<4P&c zdphU?RPN(b!}6+EG-9_dVx7~J`>e<{&G|*NK`Tm6Z$}H}u9BWrvK7^7M%E3v)jewI z=1ZMP)$=p2(h2{fyxPwQ?5+#Vl~a?p8wjmzn;`<`rNh?x2kyPn6;~9-!t@i3Gg8!~ z{%b<-IjcmO;i>*P7r0Ve{pb5M()_~~839A{hDb!5g8c2f$28)I1gpsU>78FtwLRO~ z*xXyc2tAG^mG-d~8=248xqf5Qn1Kuzz^{u&Ry>__bu7O?5a}!3bz@fZmGfky%(8Y@ zXY}VYI=!D2P@K2MCF79(DGC)i8FTn|sSwyM>*097@noH1^vDfUo^_bj<}pH!hreD| zks}i*#>~I0yiLyX%>LU9FGln3;A21c%JoMw64I6Ej->-@$yy((jnK1ARcuqCPw`hc zgdgo-mfT~P!xr7`)%+6Is2J%j>FU)I8~<5y;?QS_`TJM9R^HzH`;tr_-LoFv^>8f^ z`#}|&b{}SSbd1<8e5lgOaGnfT@MlwU^Y4-aSaLObq^Jvt%Ub@S3JFP>)sn#!b|XT? z@IwOu&UnQJ>u`RJ%YTCr#6MrdFT0)o(Q}=?1hL$jR*e{mz3|042(9v$9;teFByM8eYFNW0nsdw1t6Gmg;}QlB&eXA2ovfbK*?>qR2F)?1)J ztPq2rLPr0F5Z*#yM|ZWGA4=4NmEd#ABs(bEwtrul1L#s?Te^#H{`-Wp9sB*hq_@*y zOCHEux`F~(X;@^*{ah9UL()bdh(fgmbT(7a9a`S}hrz@DrIi=Smsd6^r>aOfD>$v8 z6`tVTV=@0MpTUhz4l-OholUH#PW%o0^#)1{`Y_Oa={brH7dU)A<2z4{CwaZT4#^cD zNurX|-0uGO%^{(vosD)MN14F*Q4wosVpNPQMgY?L#9*U5Qh_(&CoC2G_jpkX*7wu7 z*hI3*D+a1XwWJ4dXDl=pVr~24=3UV~*7)cU-dZn`7<1*iVH5(hirOQeKK7CntMj zkwq^gNttmxfq5+D)vb>`z)oZd{eiVEtmgnOCn+SrOHin^df(~&tDW9MO@mw!C`EK= zP`fbTya>3)l{b_R475pZM7$T0bU*3JR-M{6kOwCK7imNXsSAVs3lL*?J9EvFQ$-%m zrZ+gEAv&Ri^T&sS-K^{MhT!|=(0U3DZ>+CsTA0l=1uNLd=qv`$o~F;WfeAIf9p6uB zk;ldFG*O{zjuC41UwZ78_qLWJ)t)ybRmt76fRZg>Ta|bsklvJn5ntC7TIvZNL`^Q< zRjZKW#P{NPqTuvx3GQqKe7R)?eSWs8rUWVmdb%d4e9`-(+j585#I%>*lsf=d;Nd42 z!H)H$ctJ#O>%N$cqjUOjA%Oigo6lN06q6S89&%ZG8Q0i5DC%mWyqY) z60;QAKpMKItea1iKF z8o<{PgWQ`KzX2bHu#;@&EUe|@gLH(!owsF$=_~l4(PHy`vU+TC2Y{^}yjH;n5pg#m z^Rd7@qGZ*}Y(K;xY+ta&{LwH{1f)l#Qj11!b>~Xu)Es%3(AC?g;MF`XB{7F;QAD4C zRi|yFrTO(*kJV9it7}gHVI8l7bcC>O#?)QyZ3>A5&-U9XiV=wusZ{QaqzB}ty*EU& z)f9CRBN!vjH35s)H-oxiK^5_`YwB(AGWpn&%sX1EPG)>rQP6u7w+yDELTb;;Ulrdn z1y9BGY9X~bl%FEn3hRCL-;W*NFI3x;q3H(oTNxR7@UsnJD+kuIsqB7kdcs%7=z56b zpPEu=Bn9cfs7e5L^&)bwbO6?H9lM5Iis&Pxk?e zh6bOTWK06S7-OHVl!Ex29>1IY;veK{mXKR8;SJya)}HM+xfChZ0BCLHJibva0ub8i z^?cPBog2uM@sQ=UND1(R%)H$QBHl}=ry;ap-75~^mS#u~k1A6Bxn-Z!}a*l)8BOy~x;@HdCHGNI9Ch*_C#kNveFV8ICx zf2lFtQ6w-blYt0afkxlP+jFUJA#&MW=#_|T9eS~24ybb09BLjF6R@{DN!TDOM^>2a z&Qt>Ih>2Q1Zb7bzl)zCfx-0?A`>;Km^zY$pqX~Fck007=w;GZBtGX-yGhiaGZQ z7+2AO%mmmqCQyQk_=?$W_w%)ydSk!IYG7*)b)blLfJZ<|tr%+TyTp&i^6X0; z%VUBJML{*F76c4ZT7jyb0~4a-vh3pn`0Xh=USL6})01###wIs4?y&(7jvdym-eN@D z9Y|gVmTqg`nv#>YQ6ipK7$crBx{@1BMK4536e*%T;G6TvbkUE!$zEqJDRI9SaGn-q z7YMY3HJg`@byo{L@uPs*GUXpdWg;c`6w%)B&EwWiyow9nJ?#d5HYs>SSJ23qpfqdf zc2o@Je50&88ca?hq1Qb-1wMDL@fkJ*=b0E!%x1f_eV0n?=^3Flhnl#%**5r8cFzE1 z0Y+*zo0YD}qeN^Cy>g+4vj^MsO`)QmV1Mn+ya;;)@~X8#oF5}5Q9TY6cjh{>BA|CD zZaKs0syz6*c=XA+eyt3DmX9JO&P3ehXfKcB{_qps2#KzNXtEkjT*om0n9{UafXskP z#9fINPaV~b5Ed&3a+W0;@c;=AqQapGb)Gh?}M+9P? zG~bF1$m?5meCe^|HU^Ce(h-?19_~N&JnE{rgsxUEIa}ZJP z7vwhvmfLl*IZt!Ss}rEF`dvT})i5San9UM@9D|hVW4*8@x9$MzYW>){VslDwA7U{sp3Ir= z=@8&59*lqr0`r$|K?*RiKtAug&8CeCOkZ;IG=oGYb~=k;VUL6{Y1M4DdIFxunj!1G z-8oC$!DrV9NQw@M4l)!5$6fN9HLtw3>%so_U0wxfs!0Bk(y(!0Tf+$wP=+YAfGtwo?k; zWQ8VfDs4YDx%g77G@JGJ$aO>9WTGh9FHUuo#-2q2JH-QzABCuZ!>|Uw!vmAU9TN`# z@;a?De~STYu}duBfZ;k4gC?pG&Uq!pDN`QTGulUd8QEl{6278A*!y=;tPGgZ23XkB zQ|6Zu$95f9+G3~Giqrxuu#JNF%B1{w2Y7+5oX=3LNJ$FCg9()B5hSn>IE5wE3(o*T z!oPd`UcJjgLu+k$Wo6Z3Eb$s-Yu4Li3GZUPV#*AJ6vZ@y{7miGYlVJUrkdQ<$O7M~>^(w9*JlHpt;zW3%@q z&Dyo|b08rQi+6%fz@1?qp5bCaIZ0XB6E|@s1I`vCJtKMq)#B7>SIc?S!Irgh6NoAsr&kN^G4Ske-sjPy2hkFF z_yf+hxtrz)aS9v$DDydBXNK~4YeHpYEd2G4+RyKoW(NE$c9z0N@AuvG)7SF}Td(sx zgsMNQ27DG&;u>JhnN}`>X?uO7wMc7Z^A^!!f9jC?eyJg&OJVltgG1H&bN?lJbsx^g z+j+KP7RWW&jC!5lJjO+Mf2k9mX1*tJ19RN28gLAS`Nib0VJ13+{o#^nGhmM{)06fu zuY5f1@o}wDWd|UrCwTM0!v>ENbi}N;!|S7$Iz~3z3@I4&3PVGc7w9CkB@XVr^ZDhW zIfUD}g>8&PA7jt^K0e5YGH z&`h?tEy!j@?6yzI{;LDZ2wNYsI?0L&YtfTc1+mEqE0=j?{f6m}cH~;r_vpnrh=AQh zt;D0)Z;~SRin0hzT+vlA6C0+#MmfMzH6!BfhFL_5A7`EP5wT6eR9DT}F9W zz6t85W?(%!PfP-zealpWQjzrAtbHzMPoFObgvEjSW^Gr~R8Pl`Y=keem!{zpoKV%W zjaAnaNzd|C-st1^j$21sX>v+8-Y|DqkEP?g4rC2 z^}n5vKrQeA-D=Bxtzg6v(}?jY4cIIoHSy41FPBbP!D;wk^z;%%Jc#X5=34B{DN6vw*E?{^kN}6T4MoLQ38{?|W z{OPVwIdHh51GRql68+Oxp@UJJK=)GX zQhh26q5Dk0!Cf*|fFwD7c$W1v_F(wNV6Mcp(^QH|-sRuk1u!`7Zn;wX8n1Z5Q^Lbj z7nwl0nSwWd_#^RXH5>dSoV>Qy_A!%MDauOOY}Ql2nm_l-*BxnW4w`MYd2fz1mZyvf z7bO~>Vm}BSIlTbV78KGN1C@SOg5MW-IDzq8XR8q5-suEFj9-*FBgG@x^Tqt;y&Lxm zWiU<{_%qB8pHt3NyO6XA2#J1fp=B90K;B#yhG&|&YCj+Z4?i4%! z`5&ND=7raK^J)5eoqN}|E?IPEBjWlJX}#y$PA+QJRrM;xrzC@;7@zFVrDg9qmis3h znjrz1$rMx71M7v)>*w&wZ$?D44iVF`A?ZgyIG~HglXtCjU3n-G9K*Pb zva2x6w9FN5r%$;BT9hE)Ux$*hcg=nXpbuGtg&Tv0Av-O`O~wem%!ePlDx~@uODoFe zh761cTF=H&V#k#(G(2(E-A>2>t=)sHs^i{b`eBsrC=>@;ry)9@xbM;Lt`pBgSQbUX zsVJVksdCJzooM#?5UU}wb9y`W zc&bzUNlQ6CVOOZld6m6)D5Fi%UYXXiasUIZ1V_E@Y>kWWrBPI>*taWiwXEm&8iOE} z*^29?=)ssv@>aOLzT4%mU?weugoJYXy{yrLP5w^<6UytYqB;-9;T`*F6hP%g&wivM zuF_AFL$wZFf7A2o&H(8Sd4c=yLTmK_pXiBfH&~0;qoT86>8n8>tny4 zm9JR}p3>_M8w!d~^2!o~yjPrV+z29$oI6z6YJDTqS9Sq_TPx+Jnx@&f!Zei0-U^un zwpp-^M4ql=c1-K}9q&$fQxv~Hx?=}U{ zJY8F4b!g==yb{ivcmqNvBOuX0gHe0YnylXeECY4-CGp`@9ba698o=VKDDZ*D^5I|N zZj-SW5Kt@oZf7GuiMsB1`v!~0i4}zdfE#I3$_`w~$cgXizxTmWaOqHUk_EVVn|an# ze>yJ%Glz8cPEHMe3&4RDvIII98N~p#*s#S_H@xvK*aI?$#Y^@qH1VO%wCT9->~8Pv zSg%0aD}XcTHa$nd0)xB{I0L{vjW2Gcrl#9weO8^r)IV0g>S^$ z*_rz+2w903gznoBGhL+w!gHPSdaJABs8Us}12)<{5*ht`AU;+l2%iPaNZp85;xa4> z_ous`@#_8-fA@-`qof2OU=uul=iAh1z<9UCw*Qs4Y%U@N6!Q%fm6k z8{kNPzPqGKu72HMa;ix(B_kM_TIsW|Oim4b2X5FwC3fUHr!OwbxKr79f-X~-wo^7d47JYy#tP%*hVfFTn^%?^hcouWFQ6kW)$G2JsB#)``g ztdY8No34Z1)OF*34(L%$N{WHv4L<_>; z@sCB8>6yF^T%13mekAZ34{u?rL}d7&@#B2YqNJ%&3E1#Tvf);_{G&Pl4O?i74v^P~)?#HUq!MQ4Z!L=ma=`5c2T&EZ6hqb#LS!WE{RW7UWKr-0~ zQMWs}62ryuEVr|#(*;UABmHTa0qz5j0No@yp3pSDw;o+uEeQUeQCdPfmR9i1ylGcT z3(cc)`FWte5`?U%`&L#mV?-Nm_R~||s!lx5SbrCRmbLs|`jm^Zo4Sm<<#wH(64HA{ zf?v8iqZpz-S)N|scfh2uvFSw}4#EVyZsc7ul#Xgszoc@WKrFEDUXdEi>gee0KMT4lX8dcE1pzMCD=3OK%BE(z(3_ktKC0| z8H?X*5t89U0yL%O`&>D!4^A$ntB?;hD|oiRqX+n*vy{$1+!<*y+**6eX;*;`7i*3- zw?GC2%nH|=uh@sD9}fZVXqfGM^2rl&uR6@&J!=zTEh+S-8np)OCDqAW=0hEJEuKg# zz%sX^?{Czy8IG+2?J#sW;#0J_CDO##)4cKBS}lC7Syi~Z*aY%$pnT&kjwtyEVHzKY z8VIhZuzhR)cPnh4dOJJ5k{}0OlA%SM0PIbSGq47zZara3y`=Tc?ZNv_Y0M#U<#?;L zBba@SQaAC`+#xqayivS@kmu;(qs74a?`0^fhx4x1Dzm^g-Ni13@j&ZxTjW&v>gS6w z8HGD9E%JuO8B(J@%Sx>Bg!!-3?sf~70q=rJ62dn*`24l#ea$|yPP$%XLPtC;$ zwuA|%tABOs;Om64ULB>BwEo3c+;dhp1F1DS{UvxWA2u$=E~o}czRP&6EYk0QSp?VeX)I*nd;dS4f1^4RSMD(+=`cNfePjF8T$mCj^4p5AVr;?Vdi z)G8=SIk6|!P#Q(9d8|`b`8xTk|GV3B8^F+|s4JcxA;Hz*9@b*7#B67w6uzr=VZ>cd z4~BQ_I^ga(a$60mv-HW76_cM6nX68uA>PwBx3>D+ue@Hq*flvr9(UW{oM%p9m~XPr zt*o>~9zqdq-TMx*3HiR_*}EfFYMTYTa)h3|l25*Bn}i$u`LU3s_3&Qt_-JS+-o24_ zaTH?`6aL!ynIM+F8|d;OnVzlUeu@1wE%zy7&f8Ny>-FoOP6g?Cf(S4NhNU$m+$u>J zHT#j^Pd}2g5-9@0XpgAwc=_2FlAh(zV4v9oR1{|(8||0?>Km-vB^u0Y9w;)s=CM|@ zoM_}GbbfqrnaK6wL+5}!-RjmQflF0v0Y^xP()N#MTk=&~(hw&$JN@=toUb%oz%I@g zdRDf!AIUUO0@_Au>6n?R5CVLW3EA-D~Encjvz4tSL-pFh2L z#+StS?U+85k_{6!RrRGsQY>frMHj3J%xazqz#55hT}>6AvdIGhxpHM?GnLAT(_zRV z66knHMM3Ye<%WP7o42I#l2Z6?ZK$(S8yaf^LGCrw^kHu);Pl%!2{xx^2R3B4wwN+w znz4=dFUV6z%tGe<0myeYM^rlcLO36XJP6*~v3!2MV`5_5Vm2k-EWlbUI|19pYiSEK zve8PZKW6y02(dE18BV7`(d5W%up3vMOjAmrix#K4p$y>zC{}oX1QzKRvK+?`Dg#_Q zaObi|%)~NWZ8=4VR9cZ~Q>Tsa+L=jY%RcH_QgRGmFkAe6Qx$S8V?EU))%7VDu>>1X zQXHh-VgdHauMz>rcgFji>0V!sBB6$x0+JJBuis7j5dJd71a=;60Ov%_WMnl1SB13CkrYA zFg%-_YT%motHvzkJklV$ajbGbAy)%-CgXhyJ3I~DH*YEeLuGy+`pz+GGG#cfa3t+q zN?Ih*kQ z4VXx!9f{x{jx{#7(8aOUeZU$XAD)DQX^?URle*S{b_nwxj@P^XAwCRDchHv9L6QGSg1cRF*`slD7{Z~QW z>%dD07OD=T9Dr+gn|>FtNSNnskJ$@wX=@R?k+aNSL3+OZK6WQsQ>+B@!QW}&(yc9_ zg4#ZY?Puyj>PiH{0rjt`*s<&3-{A@*%{_M_(|EAMf6qbdKy_%P>uINwF1919M}&Rj zM9()9iw|xRxO(k^WYmpcD({fvVpmmi=Qdsv)FsoN^m2vDCk9j4t^Ezjf;SUyJM$`iy;+dhb87yma|FWm;EQM#ZMM#0@FfY#;>HrEEOL$ zot_NVv#(cu3&*PTeA@4FyiENQxD3g^$#t7c?DEib?`fn73mp*lV zSjS9Gv2FxzKB_=R?~NN+w;&g=x-GyT9-L>*mJ$VENFHcs6t{U8eZ}KVf;Gl#UEzofzhhBb%pcTv{29R@tO9I=(z9$*r1S#O z%!@xb6WNed*Z1)FJdRuWMS!YcFa7x)C^Q0t$iH50 zDSoU$ich0aF|9WLno3!Tue2`y1%5$|_s;G*=G;NPuF}YB`0~3OMs^)!KzWbcWvcSq zKjHL@KPnz2tqlfUc}v3WllZ!s`)oN!_%47)>=fKnJ>azSu;xtH6k`T@0$az3DAeX1 zZgdI^OP?$}C26ulcrV|KzvwCHfIxmR7jgWe0=$XF7q9T62uPnO-B>(MQ5{T3GEo}E zsjE-|EhSW)h8rt0%HFYHxf*ZO@Oa)6bC{S^sSI#XBd)2N0Mb|@?cL=J1ccU11NyF= zOVfh-=Z5e$Ha}N_@Ih+_ei{^+ifuayyPMsHL_Pdy5KqoTEfP!C(fxwz z3SgTz1i>2NmoIybP@nJy9+jU=VU`uOTb$?`OqmtUhp^{PU|~Tg9|ADIsd~@H?k?}x zFULhNZ;4$2B63WeT|_cqpx;vFACTPL}33L=FJ?Z3vIo4AncuSj) zHAue(x34*Iag*vOy|_FUCt^6w-)#~-kHy2^22GEkCgDd#OqRMh)z7GPEFuq*X_^QV z1SM$_&h*z8JbP!7`3nH-W}NBQ0A1Gt>F$%KV>S6uiloct3^swVUIjsP6345J|t z1n|0&=P7!d^xBt#p))>1r7eXF{=ZOMN$*w+b49`jG$o-&J|c> zLR313xjt<0U0gR%-Rh=K=}jfGYi2|X;8!;67W)h@OAwM^&^s^qI1E4|!JHdvnk>g^ zowB$y-`Y)l5BLNd>__NR>@#o+94TNyL38u?kGxKk`*4i3lW1rN07oKw1)b~&cJ)|Y zDyQYWo(RN~`E}Z%Fp-iQL`}JYhfhBWCW$xE)8&S+V=?9HZJMx$PC`rB*q24zy;`T4 zvR~d0W+@%T?iLH+ADOtM;1vtVdFYMn&wG(B)X-pE4-rfX_X}B|eAgL}oPjOEM6`Qv zZ%X4SNdVxi1Msn1-Yu}<`e%ycsbU=ZpzA$hahR1TVmd2<(utAi?-~YdEy$;gPUJC| z@GGa9njf!GuWPF*VxyHSY2|#_22TY3_}8kPd9|z8h=3P;noE)cL0ZB=wA(NjKxe-x zCCqS-%(;<0{^tl-Bge72Sq8aQc@_3e9}9q54*<35q|@60*#0zVNddhy{vwh;vTOAB;feD*mDm(y@aQsQk zOb$cpp;vSY-hwvjLy}EkJ6278M8FvkKSH66WuvbSUwGnbfQp_9 z3$Xu#n`u3%ofkga>tBl<3e3c@jSb|HMT(>h{`;c!nRi z+n&f8+m@K}1~E`M++lxzT@<40-NXR0#m`CsSe`Aw@~+65S7fWUaX3V5)f7|Owi$dc zcK0asGco}tr`-mGpSJM;H!EZIva$yNv% zq%6r25z3k+yF-R7W6i#l3fU=CmNc?6C?we_`$$={@7v7$?m?aN_IuC!9=(0}+jBk7 zb$vdc>vP@D{oLZ1l6c9FpM10t-$7U9qs&76SAaHwX|4{`Y~&J5dCclUIf8lSSwVfc zZ!(jcUP_@-t(0XA{Yb|76-DhaOA7y69`m#zM}H`0X7~IBpQ1zGO%qTF;qvu^S%zI1 zL-ev2Z?X{aG4rqxI-3oz#$uc9c^IKjR2Cs9g{iKUu#@PzWMjyxw^dDqG){?9?A+dc zx!3O8k-@nsO8j1)#O^rfawBCaxUF65>L-UN@Ik7CtK3T|7GHW%WHMB)}!U{-lkc{mOQUj#Mj7&U&FP* z{QrcvzE6bYR8uv=vbn($03qj(g|Gs7if=JEwI-q~?*ua(!IJ1xUQhg(2jejQVa~Ha zBU)()aCT3wIOKIucj7iuSW}gNeT(*_ed^s+z5D=%7led^rlJl3 z22t@`99Nd72s8K2Tn-R4?jYGAQYSzQj!3U=rFyTg3s!l`O2<&ov{=w)H9kH~qGOh- zf1OpZ*?2B9p0P%o8e zJ@@{m7;*Hhoj=~OH#g0U4^mCTCy}gWP8B>}+qLx#c`#LS6TgtN+VGrOTp@%d)oHI> zJGu9;Vw`25AH>z$s_J!!T1cg_uPn7%WjzBc1;>wOvJlc);F=;wTcHsvWy%`jbHO(@ zEqS1&pbRhmOBn`ATJo{m<1rO476$uG>D2PkpP1r^citqhD7^wRe`YpTkNh6Ee#qsg3(@H85*H><^kun?#)mSeEW^Io62X) zHuTNt^7NQ&C=Xs~rw9GzAtppCzCD*3T47 z#X8`%<~-ZJJd=s%5PQnHx<`dk6<1hh$`;mC#J>@d z8t3m2-+4g@KFgWo| z`>gGlBZD1Pd86!wWcp#|YFHzmqanRB9k9fSFJx704C<4j^h2ON$5IuRhpgqHp(GiT zl6|I~bEmt4DgBw;gHh+9 z;^L2iy*!?4#|)FPK8C@2c{U(?^InHo}#|_AxA8)h%kR8eMSlz)G0&C1R;sI@i zcUtw)e|9eyzvPG!x0#F^UDC|oX@@6BR^eYfW)<5RpmmvG=Fu^n3N5V>tY2-%LCOoX zG>9ha6*30Z97sDy0UD&2)^BH7j2?NE69&3sQ~nS)8G;r_olaIKi71R@U-|)Fij=|LI z6u>4PaE#H7;$^|eFhT40-I~JU+6-n}R)BDUTJ!+S3QkJEsTIg5z~8Qt;@ClpV~5su zB;I&l{_N!VBiYM(Aj$77TkoKl!64-I87`A*rX{;}L4Z2*?eQ_51_oA>Jet~IKBBU2 z1&AX@M9bKQn*8z#!MFvT|B}w-ksxBRMRX{=4WBi}zc|V4TU+Jpr zQt4N?^^j{m(1Mt5rWVakp(Pqvno(=3cTuD~z<6gsdxp5ux~n#>tOu$(vQ6uS>DTh{ zj*pQbag~$xJHCw5fxk(eC!>Y{J8qNzTS*(hui@p7jZx~pY(s}~*CUBL#U4iojg-x@knUA=k&EnVkOa| zj`{0gOh~`cyz|miLSE2uOKL+^(_9NC>2>Wc%!MEX9<0UV0`i*B76)d9;$h z5^wT&NOk21rLkX#Ye8RKd7-7goRzH5p$aR5w$~E87eadcXm6cfSIG!vR@4|k5==CFMSa6ql=4#2FjfRY=us zMA`a>)-Ji{(+a>21@n7_sFX7i7+L8EwV$%>#4|g}XOpBQf0~BaW$mexB3_y1uuv$o z|J}DhPzK2&D0Tx%NaEUFNW1&}-M05)80bj8QF)^yOrdvDDq(&3I$E1|PN}aN6hioq zr!Y?e$twP-Lq=dYETk-dV`58Wp6jd<%#-djtLF7jqtvah7<#=Ef+^8F8XsgrWAXuL zpQ^WB)e8l(RC;}qjbju}=9#8fqfpKVFP=fDcw`<5AR(dyFSqFf8*QA_LTT@P_7mAD zAk|E4iq;Nh_??b^&*RUJ#kRikreV$-?PD?%{i+-$)~h~6F{f>OBs&j07L74@ER8OX zplZg)hg1v07GeD_mR0%54v_JD^?#7Yr)n7HeC0tf72|{UVg85{7FNjZ#1pbWnvFtO zaB5ZsXw}dz{4Z`UZ3g{UHB}QJ-io=V{J3Ce8E|T|>jB=%0W3d7Kkf9hx5(^*=WR+L-cQ zkFCbZ*c6g+dkk!xA;IFsQo5v$`r0c-Wf5Qf@SQp`7eO?a!1IQZXS#-0AtUj|A}J8U zg{gpDM9{A>62M2X=}s|=kONQA6q!+@d-&=HiMu11L!5O3!;E_>j(hGPzJte!D0w~x zO+@uzfIA_V%LT_m1$snJMPmC)0YxZ_yGsoRuH6}mtyJnGe;|v)>gT4HUcrx{y9D*k z>w@2EE%a;iF*a2Q@%AhIH3j@5v+Q}4tJ4cnlV>!64#geO8xzesK?aOD!7Nje0Qkzea_>keG~9m?}2Jsc7r&F~}{0$gm8O6kOx?{UUnZ2@bp*>Umx)T~#O5R}QX0dVH$l|LThe+BL2iIaNHIBJ7i$B&p{@?@~#3(wVES9NPdAgt6bI?>UDYHnzs`A&#)cI zw}{j5Yu*OaqKTZJCUZrBq2?cU9PgkTf-UTDY_Wa)3D;n%4;bKT!p0Ttb4=0}{HvDB z8E81$o|S?5B51jLmfBR!`Mc)pd_(TFn}V2=xFpZL+E-l00$sLx3Rg}lD;rVr_`IHh z?uzv~E%9f4Y*s?7PG7+~oRUd{`P}=i0U#j-wSU1?-M~$B?CP#!UVJdY8wV6xHbhCo zV6VKS|EavG-dL^HEaYwKdo!|3aVts92qS5z(_GO~U_BjY6+ai)BT}XB)LSlcMjSNe z0HZ%e^VzZbwNEtF1DYmccNyr%EJKHba3&5g7vPI$$GiL!d~ss#EG!D8_i>pR7lkz^ zNuf$ddD<(53`JP@@Nq9wl{z&HSC42qf3{UOIQ!FiBV z#cF0nZ1lJ^C7NM3f=iSGRi$SiUU=*2nnHsc6i9 zTus64!75T#&|l3{-BGfISd$+JJMy6fBS{b^b>c&Pn;%%yqS=mC9|8z%aC?=L*8q1LE0UHCFmo%ag=Ei{X5 zD>Q7Io*jJdrS0L76=-Jv#&IaMZL@;=F<6L`7Pf9OAo z@Fog0s1k;8uul9}qw8_@|FhO*^+r(7#UU0*dfmZ5Dpl_SCwTQFGPPV&!tfjwFL<-8 zv$wSkwB(&$LHwufF&+Q>GCU#Y7y4s(*((XE`)Jr95}wMQ_1qSFn~{YRgocO1V!-?F zQ@_8ap(r~F@aZ~nx(;UU31h+tIJCCS55!6q`2Dd;vD?^+y#oBha3x+ko&hX7!{b)bC z^6(p^DdTL(W&ENxBK?osbKHyxFS|>S*wX6)MoEfTLkD0}1lFl8N) z*0eP1Bd3`Cj!2|ITXRlrGstfuLXCA6P6guAHx8K7@p4gg@wXUQXm?QG-0N-}?SBzI zdBewlBYa`bU^KW(`F_`=7ed?Z+Slw}h$h#(4r~+<+k#a&Psqr7-JYSzj|mp!q?ZW& zPWp16-(ZYKGr?;&J#a9@{MTGTRqKKUgCz7)@JEi>VD4vAwT%VG4Gj6mkY+h} zhI%Eu6eEn$w@rq^XHh0D&~A4-Nl98y>hMI$=?!NdYUjsZ|8&&461B7 zSdh|ZiIzB$?>BO9T=urPIz{zTm%mVaoy9!hcXSAd0r-u@uI6!Giu@v}1~IQK#&a+} z)!eHg9&Il>5t5z^ldiRGJmf}bZKkYVM3q!MTwi@f!ncvd&6P+Y{YLM~(oup#P+pt1 z-lQ{1r{bVrEZ;_LcVF#3r!|33Ezi@J<8nXX`lWykikU+0uf=VQbwoE?#?!hI0f7&B^m4l3UUJj`*mCKX1fVTAZiKMd~v2cE+ znDlA6%P5vz$ey%uhy0kbbdI z+A41`(VdgRq@|-L!rSg}$8|HkS%p{m-D`!o{5G{q^4^qQnyRv6p6n`>dh7Ws;fDh7@ijAUvY*y< zZ;_@B6tcWEeGw{jxVkFH8tbcp$Fcn4b>|dXycN5gFbAnvKxW)d-AcH8r^~%>CQGq@ zp&)RZcottbTF8f5q}}3a4EI<4BOi3FvW{^f1FQIWIGtr6Plrx!f4WmoQS0NAttkR| z{6gB2Jy<>taoRP5gXw@V>ilc0ET0c#^LC#&L}uVdc?u0{F5wN7?X>1N22z2nJ~vFr z{TrUcp?%0`8p#?Zxphy%x^1Pop8dABTNhg~?Gnh;b>-hs4bnck(Yhr#cBXjNgh+8l zwpg6Sqs!d@`^P7vVfOi&`@1=+QU2rI-CqWj(XBaHf7y^*MiGsR2cmc8AcQz^j>BI#uRrW<@vm0wVr{l`m~D%6Je$V?+u{g|FjZ0=%C3opDaTdk>Z?eta!qk zjF$4S*2t=UE%HqeCGX^JIo7#9ALIH&Yf>dIB|yF*uzW!nUz6~k!pd?c0qreKKa94g zcX3Bdu4;~-A*}&<`jZ#czsd`>&2ltm!L6%TYVaf(_TmjhXfYXlu~8S9jENh955BUM zx;6Kbbo$0#$uTM>zs8O>TFmF(6z{Ej-=b3WNH@1`ih4C!BLP@m4{o>{O=k1~F6!T+62g=HNuix;xea>#pq+cLKZV=?@B{?}E85f?JetP2YCB)pOcgkbt3T)VZxMrPm$W3i@<;HCXuUj-8CksdEh5#Ow5+tZ!gJ#UdfnC|N;3bf z0;X)ur}uxmetv-Km#x-{ds*aVCAj3E7nYmGTGbGvqPh#8DoJgXz7zV_V5B@TR@1bQ zjaZvkkYf~2nA{5P$a=gs4uubTRC~nksU4lrFR7iL)n*6e8}sw_P7SyCh3r zoA|VV1zl~0x5a*9TfI1eu@$?$(a^$N(RvNsYJI+lLEDaumd+^sJoU1E z!>|qVulQ0A|A(~uufh???cu&p;lp3qB>J1jMqk8ER-@)XJ7!hG-Fs00en51HSSRmr zB30=lvZX_Px0K&GqzQ(Sze{XA|4f_``#QP6Pl%J#`oRbPu@kNFr0LXSCnE+YNG}rh ztj#~d4lYx7tYbvyTJ-$-y+=R3)!sBXQ{L2swL4OETN8SOeLnKLAjD?>LQ(Hy2kRiM znC%V4$cW*SY!Xep36mF>X7pUk1Jf~)&4jK3yP`aFr$Nz1{$I6!1dV#-(;>zc-Ze%( zdh5tyJmecEDCwmJQGo}ZcwF3r(vv$qzZY|15s7R-sgAJBKuc!4YT9AZ81UHuFA-*I zqIT_aTU0n{#rYrbIlN!^%ohgDC8I}S$S0NIje3%fi|S&X5o7&`X&0LdXto5>3c_E$ z_QiQp=(%*S@Wx(A$Bu+%w=VZlr&YRlgbd%E38m6LRk+Njb1enkzg8F|eAa+e%@x5M zC5c*K+5$+V{7z5e{n{NbLX`A+gIia8qvysd+hL6rb|a zp0o)1?yqmyx*+?JZkSlX`n8ny8cFO|?i5?sSPp3!tj?S-A^hk#zJto1<_;C?uVtV_ z%1}>J(!;Tm-(;6|%%!B9cXw}9u}woOKg3P&yR6`o?~9q`?NDiK6foZ|;ga#Ek-gU| zs#sI3BfVatD;9nDmG<(m&l)0;z1Wc~n?*66L6_9Y<}suED(}b3NFTeJM&9NdjK5as$e#$IUbvD=mk}d zPqI2T$P&9zr}))ewQNcjp)U4CbDWON65cS0&-iFhS7AB((4__2&8-CuJhosAPjRJs zX^fdi*Tx*3yXW&#Ez&vJ#iNt>Vc#<>^>H6g&P@f4UPfEO(Ic_iaMiMJvN7sn<%6Ru zg`G|rXGcG;!V=jXZ~u}^sAnVL=%u62&+*)F9iI5^YRd*@yu?RwWo!7QvSqbn$2MX> zCRQpt8`~Xr1~6FJr?oeajPRs~y}q+;Unnc;M!L^0L2qbP3QrahDpvMBQB2B8^6s0l zM=_dt_Zpkp2JJG`j;UR@XL?QI=o0D7aJ|4 zrv^5haL{@Qmfd$;^__-7ZV(d2k$ioIp|o5_T*KOB$Y`sRE4N2fS(C>T2N@P|vJUa@-k@0UK#Y;J`u zWFThbXl`J)n zO-;S{b}I`a{<_~}^)l%;!EjB&_0aF2C7|7hCvj*;%|O@he~fAzlXT2VxV%Z4*lAip$2{ zcv8nmUDhJ}Nda|1iu~^G@{d)@-;U|0Rvg%`OP6GxF?-c`FsG_FTro-9J+UbhO)!j~ zzc-XLQNBws|B1PkpuVss0+s#%p(_cz53)kuS<2-2gQXrYI*7{QMu&ULFfdJJpY2cD zy=<|^%di&QWd-*x>w@oYbKxfk)#dxQ(*iI0R$~|tmSwF63#fAw)z1@}KRa}T`<<&X zffNnnWBNb;?J*|BaOkE8tr{I)xrPURlrN|$ + + + + diff --git a/website_contact_lastname/views/portal_templates.xml b/website_contact_lastname/views/portal_templates.xml new file mode 100644 index 0000000000..26566f8654 --- /dev/null +++ b/website_contact_lastname/views/portal_templates.xml @@ -0,0 +1,42 @@ + + + + + diff --git a/website_contact_lastname/views/templates.xml b/website_contact_lastname/views/templates.xml new file mode 100644 index 0000000000..f56ab28416 --- /dev/null +++ b/website_contact_lastname/views/templates.xml @@ -0,0 +1,43 @@ + + + + +