From ea7df087a078b2b6320fb04d624c100b25f3d102 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20Br=C3=BCckl?= Date: Tue, 8 Nov 2016 07:06:49 +0100 Subject: [PATCH 1/2] =?UTF-8?q?update=20Repo=20f=C3=BCr=2010.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dev/INSTANCE Update cam_custom.launch | 15 -- dev/Server.launch | 15 -- dev/odoo-server-dev-ha.conf | 15 -- dev/odoo-server-dev-sk.conf | 15 -- ...er-dev-br.conf => odoo-server-dev-xx.conf} | 0 dmi/run1/{cam_dmi => dp_dmi}/__init__.py | 0 dmi/run1/{cam_dmi => dp_dmi}/__openerp__.py | 0 dmi/run1/{cam_dmi => dp_dmi}/res.users.csv | 0 .../static/description/icon.png | Bin patches/gevent_eclipse_patch.patch | 13 - patches/report_header.patch | 11 - patches/rml_align.patch | 11 - setup/{cam => dp} | 0 setup/lib/cli.py | 56 ++-- setup/lib/config_at.py | 26 +- setup/lib/environments.py | 7 +- setup/lib/functions.py | 244 +++++++++++------- 17 files changed, 189 insertions(+), 239 deletions(-) delete mode 100644 dev/INSTANCE Update cam_custom.launch delete mode 100644 dev/Server.launch delete mode 100644 dev/odoo-server-dev-ha.conf delete mode 100644 dev/odoo-server-dev-sk.conf rename dev/{odoo-server-dev-br.conf => odoo-server-dev-xx.conf} (100%) rename dmi/run1/{cam_dmi => dp_dmi}/__init__.py (100%) rename dmi/run1/{cam_dmi => dp_dmi}/__openerp__.py (100%) rename dmi/run1/{cam_dmi => dp_dmi}/res.users.csv (100%) rename dmi/run1/{cam_dmi => dp_dmi}/static/description/icon.png (100%) delete mode 100644 patches/gevent_eclipse_patch.patch delete mode 100644 patches/report_header.patch delete mode 100644 patches/rml_align.patch rename setup/{cam => dp} (100%) diff --git a/dev/INSTANCE Update cam_custom.launch b/dev/INSTANCE Update cam_custom.launch deleted file mode 100644 index 8d50033c..00000000 --- a/dev/INSTANCE Update cam_custom.launch +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/dev/Server.launch b/dev/Server.launch deleted file mode 100644 index 42252cac..00000000 --- a/dev/Server.launch +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/dev/odoo-server-dev-ha.conf b/dev/odoo-server-dev-ha.conf deleted file mode 100644 index abad481e..00000000 --- a/dev/odoo-server-dev-ha.conf +++ /dev/null @@ -1,15 +0,0 @@ -[options] - -xmlrpc_port = 8080 -; This is the password that allows database operations: -; admin_passwd = admin -db_host = False -db_port = 5432 -db_user = False -db_password = False - -addons_path = ext/odoo/addons,ext/custom-addons,dmi/run1 -timezone = Europe/Brussels - -#dbfilter_test = ['.*',] -show_debug = 1 \ No newline at end of file diff --git a/dev/odoo-server-dev-sk.conf b/dev/odoo-server-dev-sk.conf deleted file mode 100644 index abad481e..00000000 --- a/dev/odoo-server-dev-sk.conf +++ /dev/null @@ -1,15 +0,0 @@ -[options] - -xmlrpc_port = 8080 -; This is the password that allows database operations: -; admin_passwd = admin -db_host = False -db_port = 5432 -db_user = False -db_password = False - -addons_path = ext/odoo/addons,ext/custom-addons,dmi/run1 -timezone = Europe/Brussels - -#dbfilter_test = ['.*',] -show_debug = 1 \ No newline at end of file diff --git a/dev/odoo-server-dev-br.conf b/dev/odoo-server-dev-xx.conf similarity index 100% rename from dev/odoo-server-dev-br.conf rename to dev/odoo-server-dev-xx.conf diff --git a/dmi/run1/cam_dmi/__init__.py b/dmi/run1/dp_dmi/__init__.py similarity index 100% rename from dmi/run1/cam_dmi/__init__.py rename to dmi/run1/dp_dmi/__init__.py diff --git a/dmi/run1/cam_dmi/__openerp__.py b/dmi/run1/dp_dmi/__openerp__.py similarity index 100% rename from dmi/run1/cam_dmi/__openerp__.py rename to dmi/run1/dp_dmi/__openerp__.py diff --git a/dmi/run1/cam_dmi/res.users.csv b/dmi/run1/dp_dmi/res.users.csv similarity index 100% rename from dmi/run1/cam_dmi/res.users.csv rename to dmi/run1/dp_dmi/res.users.csv diff --git a/dmi/run1/cam_dmi/static/description/icon.png b/dmi/run1/dp_dmi/static/description/icon.png similarity index 100% rename from dmi/run1/cam_dmi/static/description/icon.png rename to dmi/run1/dp_dmi/static/description/icon.png diff --git a/patches/gevent_eclipse_patch.patch b/patches/gevent_eclipse_patch.patch deleted file mode 100644 index 0ada5b26..00000000 --- a/patches/gevent_eclipse_patch.patch +++ /dev/null @@ -1,13 +0,0 @@ ---- ext/odoo/odoo-dev.py 2015-04-08 10:11:02.000000000 +0200 -+++ ext/odoo/odoo-dev.py 2015-04-08 10:11:02.000000000 +0200 -@@ -0,0 +1,10 @@ -+#!/usr/bin/env python -+import sys -+if sys.modules.get("gevent") is not None: -+ del sys.modules['gevent'] -+import openerp -+ -+if __name__ == "__main__": -+ openerp.cli.main() -+ -+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/patches/report_header.patch b/patches/report_header.patch deleted file mode 100644 index 3b9c7d53..00000000 --- a/patches/report_header.patch +++ /dev/null @@ -1,11 +0,0 @@ ---- ext/odoo/openerp/report/report_sxw.py 2015-04-15 12:18:30.132784074 +0200 -+++ ext/odoo/openerp/report/report_sxw.py 2015-04-15 11:48:21.743518606 +0200 -@@ -476,6 +476,8 @@ - processed_rml = etree.XML(rml) - if report_xml.use_global_header: - rml_parser._add_header(processed_rml, self.header) -+ else: -+ rml_parser._add_header(processed_rml, 'internal') - processed_rml = self.preprocess_rml(processed_rml,report_xml.report_type) - if rml_parser.logo: - logo = base64.decodestring(rml_parser.logo) \ No newline at end of file diff --git a/patches/rml_align.patch b/patches/rml_align.patch deleted file mode 100644 index 4a688bf1..00000000 --- a/patches/rml_align.patch +++ /dev/null @@ -1,11 +0,0 @@ ---- ext/odoo/openerp/report/render/rml2pdf/trml2pdf.py 2014-01-14 14:18:12.302306370 +0100 -+++ ext/odoo/openerp/report/render/rml2pdf/trml2pdf.py 2014-01-14 14:18:16.770419846 +0100 -@@ -740,7 +740,7 @@ - rowheights = [utils.unit_get(f.strip()) for f in node.get('rowHeights').split(',')] - if len(rowheights) == 1: - rowheights = rowheights[0] -- table = platypus.LongTable(data = data, colWidths=colwidths, rowHeights=rowheights, **(utils.attr_get(node, ['splitByRow'] ,{'repeatRows':'int','repeatCols':'int'}))) -+ table = platypus.LongTable(data = data, colWidths=colwidths, rowHeights=rowheights, **(utils.attr_get(node, ['splitByRow'] ,{'repeatRows':'int','repeatCols':'int', 'hAlign':'str'}))) - if node.get('style'): - table.setStyle(self.styles.table_styles[node.get('style')]) - for s in styles: diff --git a/setup/cam b/setup/dp similarity index 100% rename from setup/cam rename to setup/dp diff --git a/setup/lib/cli.py b/setup/lib/cli.py index 44026a37..8cf73576 100755 --- a/setup/lib/cli.py +++ b/setup/lib/cli.py @@ -5,18 +5,18 @@ import urlparse from config_at import Config from environments import ENVIRONMENTS, Environment -from functions import CamadeusFunctions +from functions import DatenpolFunctions def main(): def _usage(): - print '\nVerwendung: cam.py [/]\n' + print '\nVerwendung: dp.py [/]\n' print 'Commands:\n' print ' create Neue Datenbank erstellen' print ' create_from_dump Neue Datenbank von Dump erstellen' print ' setup Modulinstallation, Konfigurationen' print ' setup_part setup_function Aufruf eines einzelnen Setup-Schrittes' print ' "setup_part info" listet die verfügbaren Setup-Schritte auf' - print ' rollout Setzt Dokumentnummern, importiert Benutzer, setzt cam_dmi auf noupdate, ...' + print ' rollout Setzt Dokumentnummern, importiert Benutzer, setzt dp_dmi auf noupdate, ...' print ' update module_name Modul updaten' print ' install module_name Modul installieren' print ' uninstall module_name Modul deinstallieren' @@ -35,7 +35,7 @@ def main(): _usage() # RUNBOT - # ./cam runbot create [db] [port] [working-dir] + # ./dp runbot create [db] [port] [working-dir] if argv[0] == 'runbot': import os @@ -67,7 +67,7 @@ def main(): print 'Unbekannte Umgebung' _usage() - instance = CamadeusFunctions(env, config) + instance = DatenpolFunctions(env, config) methods = None @@ -81,8 +81,8 @@ def main(): 'create_db', 'login', 'install_module_sale', - 'setup_accounting', - 'setup_accounting2', + #'setup_accounting', + #'setup_accounting2', 'set_admin_rights', ] @@ -101,32 +101,32 @@ def main(): 'uninstall_chat', 'install_modules', 'set_warehouse', - 'base_config', - 'sale_config', + #'base_config', + #'sale_config', #'finance_config', - 'hr_config', - 'stock_config', - 'mrp_config', - 'stock_set_cost_method', - 'set_incoterms', - 'purchase_config', + #'hr_config', + #'stock_config', + #'mrp_config', + #'stock_set_cost_method', + #'set_incoterms', + #'purchase_config', 'set_date_format', 'set_company', 'set_taxes', 'set_uom', 'set_steuerzuordnung', - 'setup_journals', + #'setup_journals', 'set_currencies', 'set_decimal_price', - 'set_default_values', - 'set_translations', - 'set_default_removal_strategy', - 'default_set_order_policy', - 'delete_mail_server', - 'update_values', - 'update_special_values', + #'set_default_values', + #'set_translations', + #'set_default_removal_strategy', + #'default_set_order_policy', + #'delete_mail_server', + #'update_values', + #'update_special_values', 'set_sys_params', - 'setup_reports', + #'setup_reports', ] if cmd == 'setup': @@ -135,10 +135,10 @@ def main(): if cmd == 'rollout': methods = [ 'login', - 'set_dokumentennummern', - 'set_dmi_noupdate', - 'dmi_confirm_inventory', - 'import_users', + #'set_dokumentennummern', + #'set_dmi_noupdate', + #'dmi_confirm_inventory', + #'import_users', ] if cmd == 'update': diff --git a/setup/lib/config_at.py b/setup/lib/config_at.py index 757b9056..00f1f29b 100644 --- a/setup/lib/config_at.py +++ b/setup/lib/config_at.py @@ -2,7 +2,7 @@ class Config(): def __init__(self): - self.dump_file = 'upgraded_file_name.dump' + self.dump_file = 'odoo_backup.dump' self.module_name = None self.lang = 'de_DE' # de_DE, en_US @@ -14,23 +14,23 @@ class Config(): self.uom_decimals = 3 # Nachkommastellen Mengeneinheiten self.company_data = { - 'name': 'Camadeus GmbH', - 'street': 'Wiedner Hauptstraße 135/B3', + 'name': 'datenpol gmbh', + 'street': 'Lederergasse 32', 'street2': False, - 'city': 'Wien', - 'zip': '1050', - 'phone': '+43 1 78910 96 70', + 'city': 'Linz', + 'zip': '4020', + 'phone': '+43 732 997 035-0', 'fax': False, - 'email': 'office@camadeus.at', - 'website': 'http://www.camadeus.at/', - 'company_registry': '280076b', + 'email': 'office@datenpol.at', + 'website': 'http://www.datenpol.at/', + 'company_registry': '359270p', 'country_id': 'at', # 'de' für Deutschland 'logo': False, - 'vat': 'ATU 62991855', + 'vat': 'ATU 66309611', 'rml_header1': False, 'vat_check_vies': True, 'tax_calculation_rounding_method': 'round_globally', - 'logo': '../ext/custom-addons/cam_custom/static/src/img/logo.png', + 'logo': '../ext/custom-addons/dp_custom/static/src/img/logo.png', } self.mail_server = { @@ -241,8 +241,8 @@ class Config(): ] self.default_values = [ # ir.values - #('product.template', 'type', 'service'), - #('product.template', 'type', 'XML:xmlid'), #mit prefix "XML:" kann eine XML ID übergeben werden + ('product.template', 'type', 'service'), + ('product.template', 'type', 'XML:xmlid'), #mit prefix "XML:" kann eine XML ID übergeben werden ] self.data_updates = { diff --git a/setup/lib/environments.py b/setup/lib/environments.py index 29ab25dc..57534db1 100644 --- a/setup/lib/environments.py +++ b/setup/lib/environments.py @@ -26,11 +26,8 @@ Port: %s ENVIRONMENTS = { # Local environments are listed with passwords 'br': Environment('http://localhost', '8080', 'INSTANCE_1', 'admin', 'x', 'admin'), - 'sk': Environment('http://localhost', '8080', 'INSTANCE_1', 'admin', 'x', 'admin'), - 'ha': Environment('http://localhost', '8080', 'INSTANCE_1', 'admin', 'x', 'admin'), - 'jb': Environment('http://localhost', '8080', 'INSTANCE_1', 'admin', 'x', 'admin'), - 'uk': Environment('http://localhost', '8080', 'INSTANCE_1', 'admin', 'x', 'admin'), + # Remote environments are always listed without passwords! # Do not store them here, you have to type them anyway! - 'test': Environment('https://INSTANCE.camadeus.at', '443', 'INSTANCE_1', 'admin'), + 'test': Environment('https://INSTANCE.datenpol.at', '443', 'INSTANCE_1', 'admin'), } diff --git a/setup/lib/functions.py b/setup/lib/functions.py index 1237b4b8..0b28b55e 100644 --- a/setup/lib/functions.py +++ b/setup/lib/functions.py @@ -8,7 +8,8 @@ import xmlrpclib import requests -class CamadeusFunctions(): + +class DatenpolFunctions(): def __init__(self, environment, config): self.env = environment self.config = config @@ -16,23 +17,22 @@ class CamadeusFunctions(): def create_db(self): """Neue Datenbank erstellen""" - payload = {'fields': [ {'name': 'super_admin_pwd', 'value': self.env.super_admin_pw}, - {'name': 'db_name', 'value': self.env.dbname}, - {'name': 'demo_data', 'value': False}, - {'name': 'db_lang', 'value': self.config.lang}, - {'name': 'create_admin_pwd', 'value': self.env.pwd}, - ] - } - payload = {'params': payload} - json_data = json.dumps(payload) - headers = {'content-type': 'application/json'} - r = requests.post('%s:%s/web/database/create' % (self.env.host, self.env.port), data=json_data, headers=headers, auth=self.env.basic_auth, verify=False) - if r and r.json().get('result', False): - return True - else: - msg = pprint.pformat(r.json().get('error', '????')) - print 'Error occured: %s' % msg + params = { + 'master_pwd': self.env.super_admin_pw, + 'name': self.env.dbname, + 'login': self.env.username, + 'password': self.env.pwd, + 'lang': self.config.lang, + 'country_code': self.config.company_data.get('country_id', 'at'), + } + if self.env.demo: + params.update(demo=1) + + base_url = '%s:%s/web/database/create' % (self.env.host, self.env.port) + res = requests.post(base_url, params=params, verify=False, stream=True) + if not res.ok: return False + return True def create_dump(self): """ Erstelle Odoo-Dump""" @@ -43,9 +43,9 @@ class CamadeusFunctions(): 'backup_pwd': self.env.super_admin_pw, 'token': 'x', } - + res = requests.post(base_url, params=params, verify=False, stream=True) - + if res.headers['Content-Type'].startswith('application/octet-stream'): with open(self.config.dump_file, 'wb') as fh: chunk_size = 100000 @@ -69,12 +69,11 @@ class CamadeusFunctions(): print "\nACHTUNG: Nicht vergessen './cam [env] anonym' auszuführen, sodass es zu keiner Kommunikation mit dem Produktivsystem kommt" return True - def login(self): """Login""" # Get the uid - sock_common = xmlrpclib.ServerProxy ('%s:%s/xmlrpc/common' % (self.env.host, self.env.port)) + sock_common = xmlrpclib.ServerProxy('%s:%s/xmlrpc/common' % (self.env.host, self.env.port)) self.uid = sock_common.login(self.env.dbname, self.env.username, self.env.pwd) if not self.uid: raise Exception('Authentication Error') @@ -84,12 +83,12 @@ class CamadeusFunctions(): def _execute(self, *args): return self.sock.execute(self.env.dbname, self.uid, self.env.pwd, *args) - def _readAndReturnFile(self, filename, encode =''): - fi = open (filename, 'r') + def _readAndReturnFile(self, filename, encode=''): + fi = open(filename, 'r') content = '' - if encode=='': + if encode == '': content = fi.read() - elif encode=='base64': + elif encode == 'base64': content = base64.b64encode(fi.read()) else: sys.exit(-1) @@ -100,7 +99,7 @@ class CamadeusFunctions(): """Setze Unternehmensdaten (Allgemein, RML, Logo)""" vals = self.config.company_data - dummy,country_id = self._execute('ir.model.data', 'get_object_reference', 'base', vals['country_id']) + dummy, country_id = self._execute('ir.model.data', 'get_object_reference', 'base', vals['country_id']) if vals.get('logo', False): vals['logo'] = self._readAndReturnFile(vals['logo'], encode='base64') @@ -195,8 +194,9 @@ class CamadeusFunctions(): if hasattr(self.config, 'incoterms'): terms = self.config.incoterms - for name,code in terms: - existing_ids = self._execute('stock.incoterms', 'search', ['|', ('active', '=', True), ('active', '=', False), ('code', '=', code)]) + for name, code in terms: + existing_ids = self._execute('stock.incoterms', 'search', + ['|', ('active', '=', True), ('active', '=', False), ('code', '=', code)]) if existing_ids: vals = { 'active': True, @@ -210,7 +210,7 @@ class CamadeusFunctions(): } self._execute('stock.incoterms', 'create', vals) - codes = [code for name,code in terms] + codes = [code for name, code in terms] inactive_ids = self._execute('stock.incoterms', 'search', [('code', 'not in', codes)]) self._execute('stock.incoterms', 'write', inactive_ids, {'active': False}) @@ -227,7 +227,8 @@ class CamadeusFunctions(): def install_module_sale(self): """Modul 'Sale' installieren""" - modules_to_install = self._execute('ir.module.module', 'search', [('name', '=', 'sale'), ('state', '!=', 'installed')]) + modules_to_install = self._execute('ir.module.module', 'search', + [('name', '=', 'sale'), ('state', '!=', 'installed')]) self._execute('ir.module.module', 'button_install', modules_to_install) self._execute('base.module.upgrade', 'upgrade_module', modules_to_install) return True @@ -235,7 +236,8 @@ class CamadeusFunctions(): def install_modules(self): """Module installieren""" - modules_to_install = self._execute('ir.module.module', 'search', [('name', 'in', self.config.modules), ('state', '!=', 'installed')]) + modules_to_install = self._execute('ir.module.module', 'search', + [('name', 'in', self.config.modules), ('state', '!=', 'installed')]) self._execute('ir.module.module', 'button_install', modules_to_install) self._execute('base.module.upgrade', 'upgrade_module', modules_to_install) return True @@ -261,15 +263,15 @@ class CamadeusFunctions(): seq_dict = self.config.sequences # Lieferschein - if seq_dict.get('picking.out',False): + if seq_dict.get('picking.out', False): self._set_picking_sequence_prefix('outgoing', 'picking.out') - if seq_dict.get('picking.in',False): + if seq_dict.get('picking.in', False): self._set_picking_sequence_prefix('incoming', 'picking.in') - if seq_dict.get('picking.int',False): + if seq_dict.get('picking.int', False): self._set_picking_sequence_prefix('internal', 'picking.int') # Angebot - if seq_dict.get('sale.order',False): + if seq_dict.get('sale.order', False): s_ids = self._execute('ir.sequence', 'search', [('code', '=', 'sale.order')]) if len(s_ids) != 1: return False @@ -277,7 +279,7 @@ class CamadeusFunctions(): return False # Arbeitsschein - if seq_dict.get('work.order',False): + if seq_dict.get('work.order', False): s_ids = self._execute('ir.sequence', 'search', [('code', '=', 'work.order')]) if len(s_ids) != 1: return False @@ -285,7 +287,7 @@ class CamadeusFunctions(): return False # EK-Angebot - if seq_dict.get('purchase.order',False): + if seq_dict.get('purchase.order', False): s_ids = self._execute('ir.sequence', 'search', [('code', '=', 'purchase.order')]) if len(s_ids) != 1: return False @@ -293,7 +295,7 @@ class CamadeusFunctions(): return False # Rechnungsnummer - if seq_dict.get('account.invoice',False): + if seq_dict.get('account.invoice', False): j_ids = self._execute('account.journal', 'search', [('code', '=', 'VK')]) if len(j_ids) != 1: return False @@ -323,15 +325,15 @@ class CamadeusFunctions(): def set_admin_rights(self): """Setze Administrator Rechte""" - dummy,user_id = self._execute('ir.model.data', 'get_object_reference', 'base', 'user_root') + dummy, user_id = self._execute('ir.model.data', 'get_object_reference', 'base', 'user_root') groups = [] # Technische Eigenschaften - dummy,group_id = self._execute('ir.model.data', 'get_object_reference', 'base', 'group_no_one') + dummy, group_id = self._execute('ir.model.data', 'get_object_reference', 'base', 'group_no_one') groups.append((4, group_id)) # Finanzmanager - dummy,group_id = self._execute('ir.model.data', 'get_object_reference', 'account', 'group_account_manager') + dummy, group_id = self._execute('ir.model.data', 'get_object_reference', 'account', 'group_account_manager') groups.append((4, group_id)) vals = { @@ -354,20 +356,22 @@ class CamadeusFunctions(): """Konfiguration Kontenplan""" c = self.config - sales_tax_ids = self._execute('account.tax.template', 'search', [('description', '=', c.sales_tax), ('parent_id', '=', False)]) + sales_tax_ids = self._execute('account.tax.template', 'search', + [('description', '=', c.sales_tax), ('parent_id', '=', False)]) if not sales_tax_ids: return False - purchase_tax_ids = self._execute('account.tax.template', 'search', [('description', '=', c.purchase_tax), ('parent_id', '=', False)]) + purchase_tax_ids = self._execute('account.tax.template', 'search', + [('description', '=', c.purchase_tax), ('parent_id', '=', False)]) if not purchase_tax_ids: return False # Set Your Accounting Options - dummy,currency_id = self._execute('ir.model.data', 'get_object_reference', 'base', 'EUR') + dummy, currency_id = self._execute('ir.model.data', 'get_object_reference', 'base', 'EUR') vals = {} vals['chart_template_id'] = c.chart_template_id vals['sale_tax'] = sales_tax_ids[0] vals['purchase_tax'] = purchase_tax_ids[0] - vals['company_id'] = 1 # Default + vals['company_id'] = 1 # Default vals['currency_id'] = currency_id wizard_id = self._execute('wizard.multi.charts.accounts', 'create', vals) self._execute('wizard.multi.charts.accounts', 'action_next', [wizard_id]) @@ -426,7 +430,7 @@ class CamadeusFunctions(): return False # Update names - for uom_xml_id,name in c.active_uoms.items(): + for uom_xml_id, name in c.active_uoms.items(): uom_id = self._execute('ir.model.data', 'xmlid_to_res_id', uom_xml_id) res = self._execute('product.uom', 'write', [uom_id], {'name': name}, context) if not res: @@ -443,10 +447,13 @@ class CamadeusFunctions(): self._execute('account.fiscal.position', 'write', invalid_ids, {'active': False}) # Mappings inaktiver Steuern löschen (also wenn rechte Seite eine inaktive Steuer ist, wie z. B "strf. i.g.L")) - valid_position_ids = self._execute('account.fiscal.position', 'search', [('name', 'in', c.valid_fiscal_positions)]) + valid_position_ids = self._execute('account.fiscal.position', 'search', + [('name', 'in', c.valid_fiscal_positions)]) valid_tax_ids = self._execute('account.tax', 'search', [('parent_id', '=', False)]) - position_tax_line_ids = self._execute('account.fiscal.position.tax', 'search', [('position_id', 'in', valid_position_ids), ('tax_dest_id', 'not in', valid_tax_ids)]) + position_tax_line_ids = self._execute('account.fiscal.position.tax', 'search', + [('position_id', 'in', valid_position_ids), + ('tax_dest_id', 'not in', valid_tax_ids)]) vals = {'tax_dest_id': False} return self._execute('account.fiscal.position.tax', 'write', position_tax_line_ids, vals) @@ -454,9 +461,9 @@ class CamadeusFunctions(): """Aktualisiere Modul""" module_name = self.config.module_name - mod_ids = self._execute('ir.module.module', 'search', [('name', '=', module_name),('state', '=', 'installed')]) + mod_ids = self._execute('ir.module.module', 'search', [('name', '=', module_name), ('state', '=', 'installed')]) if not len(mod_ids) == 1: - raise Exception('Module "%s" not found or not installed.' % module_name) + raise Exception('Module "%s" not found or not installed.' % module_name) self._execute('ir.module.module', 'button_upgrade', mod_ids) self._execute('base.module.upgrade', 'upgrade_module', []) @@ -466,9 +473,10 @@ class CamadeusFunctions(): """Installiere Modul""" module_name = self.config.module_name - mod_ids = self._execute('ir.module.module', 'search', [('name', '=', module_name), ('state', '=', 'uninstalled')]) + mod_ids = self._execute('ir.module.module', 'search', + [('name', '=', module_name), ('state', '=', 'uninstalled')]) if not len(mod_ids) == 1: - raise Exception('Module "%s" not found or is not in state "uninstalled".' % module_name) + raise Exception('Module "%s" not found or is not in state "uninstalled".' % module_name) self._execute('ir.module.module', 'button_install', mod_ids) self._execute('base.module.upgrade', 'upgrade_module', []) @@ -484,9 +492,9 @@ class CamadeusFunctions(): def uninstall_module(self): """Deinstalliere Modul""" module_name = self.config.module_name - mod_ids = self._execute('ir.module.module', 'search', [('name','=',module_name),('state','=','installed')]) + mod_ids = self._execute('ir.module.module', 'search', [('name', '=', module_name), ('state', '=', 'installed')]) if not len(mod_ids) == 1: - raise Exception("Module '%s' not found or is not installed." % module_name) + raise Exception("Module '%s' not found or is not installed." % module_name) self._execute('ir.module.module', 'button_uninstall', mod_ids) self._execute('base.module.upgrade', 'upgrade_module', []) @@ -495,9 +503,10 @@ class CamadeusFunctions(): def cancel_upgrade_module(self): """Modul Upgrade abbrechen""" module_name = self.config.module_name - mod_ids = self._execute('ir.module.module', 'search', [('name','=',module_name),('state','=','to upgrade')]) + mod_ids = self._execute('ir.module.module', 'search', + [('name', '=', module_name), ('state', '=', 'to upgrade')]) if not len(mod_ids) == 1: - raise Exception("Module '%s' not found or is not installed." % module_name) + raise Exception("Module '%s' not found or is not installed." % module_name) self._execute('ir.module.module', 'button_upgrade_cancel', mod_ids) return True @@ -520,7 +529,8 @@ class CamadeusFunctions(): """Aktualisiere Modul""" for module_name in self.config.modules: - mod_ids = self._execute('ir.module.module', 'search', [('name', '=', module_name), ('state', '=', 'installed')]) + mod_ids = self._execute('ir.module.module', 'search', + [('name', '=', module_name), ('state', '=', 'installed')]) if not len(mod_ids) == 1: raise Exception('Module "%s" not found or ist not installed.' % module_name) self._execute('ir.module.module', 'button_upgrade', mod_ids) @@ -531,7 +541,8 @@ class CamadeusFunctions(): def set_warehouse(self): """Name des Zentrallagers setzen""" - is_installed = self._execute('ir.module.module', 'search', [('name', '=', 'stock'), ('state', '=', 'installed')]) + is_installed = self._execute('ir.module.module', 'search', + [('name', '=', 'stock'), ('state', '=', 'installed')]) if is_installed: vals = { 'name': self.config.warehouse_name or self.config.company_data.get('name', 'Mein Unternehmen'), @@ -547,7 +558,7 @@ class CamadeusFunctions(): def set_dmi_noupdate(self): """DMI: Einträge auf 'no update' setzen""" - domain = [('module','=','cam_dmi'), ('noupdate', '=', False)] + domain = [('module', '=', 'dp_dmi'), ('noupdate', '=', False)] data_ids = self._execute('ir.model.data', 'search', domain) vals = {'noupdate': True} @@ -556,7 +567,7 @@ class CamadeusFunctions(): def dmi_confirm_inventory(self): """DMI: Lagerstand einbuchen""" - dummy,inventory_id = self._execute('ir.model.data', 'get_object_reference', 'cam_dmi','inv_init') + dummy, inventory_id = self._execute('ir.model.data', 'get_object_reference', 'dp_dmi', 'inv_init') inventory = self._execute('stock.inventory', 'read', inventory_id, ['state']) @@ -620,12 +631,13 @@ class CamadeusFunctions(): vals = {} vals['res_model'] = 'res.users' vals['file'] = self._readAndReturnFile(self.config.users_file) - fields = [u'id', u'name', u'login', u'email', u'groups_id/id', False, u'tz', u'mobile', u'phone', u'function'] - options = {u'headers': True, u'quoting': u'"', u'separator': u',', u'encoding': u'utf-8'} + fields = [u'id', u'name', u'login', u'email', u'groups_id/id', False, u'tz', u'mobile', u'phone', + u'function'] + options = {u'headers': True, u'quoting': u'"', u'separator': u',', u'encoding': u'utf-8'} wizard_id = self._execute('base_import.import', 'create', vals) if wizard_id: - messages = self._execute('base_import.import', 'do', wizard_id, fields,options) + messages = self._execute('base_import.import', 'do', wizard_id, fields, options) if messages: print messages return False @@ -677,11 +689,11 @@ class CamadeusFunctions(): def set_default_values(self): """Defaultwerte für Dokumente setzen""" - for model,field,value in self.config.default_values: + for model, field, value in self.config.default_values: # Falls XML ID (prefix "XML:") dann die DB ID holen if value[0:4] == 'XML:': xml_id = value[4:] - dummy,dummy2,res_id = self._execute('ir.model.data', 'xmlid_lookup', xml_id) + dummy, dummy2, res_id = self._execute('ir.model.data', 'xmlid_lookup', xml_id) if not res_id: raise Exception('Defaultwerte anlegen: XML ID %s nicht vorhanden!' % (xml_id)) value = res_id @@ -704,9 +716,9 @@ class CamadeusFunctions(): def update_special_values(self): """Spezialwerte setzen""" - #Z. B.: + # Z. B.: ## Lösche alle Anreden außer Herr und Frau - #data_deletes = [ + # data_deletes = [ # 'base.res_partner_title_doctor', # 'base.res_partner_title_miss', # 'base.res_partner_title_prof', @@ -715,8 +727,8 @@ class CamadeusFunctions(): # 'base.res_partner_title_ltd', # 'sale.email_template_edi_sale', # 'account.email_template_edi_invoice', - #] - #for xml_id in data_deletes: + # ] + # for xml_id in data_deletes: # try: # dummy,model,res_id = self._execute('ir.model.data', 'xmlid_lookup', xml_id) # self._execute(model, 'unlink', [res_id]) @@ -728,8 +740,8 @@ class CamadeusFunctions(): def update_values(self): """Existierende Daten aktualisieren""" - for xml_id,vals in self.config.data_updates.items(): - dummy,model,res_id = self._execute('ir.model.data', 'xmlid_lookup', xml_id) + for xml_id, vals in self.config.data_updates.items(): + dummy, model, res_id = self._execute('ir.model.data', 'xmlid_lookup', xml_id) self._execute(model, 'write', [res_id], vals) return True @@ -737,7 +749,7 @@ class CamadeusFunctions(): def set_sys_params(self): """Systemparameter setzen""" - for key,value in self.config.system_parameters.items(): + for key, value in self.config.system_parameters.items(): param_ids = self._execute('ir.config_parameter', 'search', [('key', '=', key)]) vals = { 'key': key, @@ -749,6 +761,17 @@ class CamadeusFunctions(): self._execute('ir.config_parameter', 'create', vals) return True + def remove_sys_params(self): + """Systemparameter entfernen""" + + for key, value in self.config.system_parameters_remove_on_rollout.items(): + print key + param_ids = self._execute('ir.config_parameter', 'search', [('key', '=', key)]) + print param_ids + if param_ids: + self._execute('ir.config_parameter', 'unlink', param_ids) + return True + def setup_reports(self): """Berichte konfigurieren""" @@ -763,13 +786,13 @@ class CamadeusFunctions(): def invalidate_email(self): """In E-Mail-Adressen @ durch # ersetzen, um unbeabsichtigen E-Mail-Versand zu vermeiden""" - #E-Mail adressen von res_partner: @ -> # - p_ids = self._execute('res.partner', 'search', [('email','ilike','%@%')]) + # E-Mail adressen von res_partner: @ -> # + p_ids = self._execute('res.partner', 'search', [('email', 'ilike', '%@%')]) partner = self._execute('res.partner', 'read', p_ids, ['email']) for p in partner: id = p['id'] email = p['email'] - new_email = email.replace('@','#') + new_email = email.replace('@', '#') self._execute('res.partner', 'write', [id], {'email': new_email}) def finance_config(self): @@ -786,10 +809,10 @@ class CamadeusFunctions(): """Anonymisieren der Daten""" res = True - #res &= self.make_anonymous_one('make_anonymous_partner') - #res &= self.make_anonymous_one('make_anonymous_project') - #res &= self.make_anonymous_one('make_anonymous_employee') - #res &= self.make_anonymous_one('make_anonymous_leads') + # res &= self.make_anonymous_one('make_anonymous_partner') + # res &= self.make_anonymous_one('make_anonymous_project') + # res &= self.make_anonymous_one('make_anonymous_employee') + # res &= self.make_anonymous_one('make_anonymous_leads') res &= self.make_anonymous_one('make_anonymous_mailserver') res &= self.make_anonymous_one('make_anonymous_cron') return res @@ -809,27 +832,27 @@ class CamadeusFunctions(): ids = self._execute('res.partner', 'search', []) for id in ids: vals = { - 'name': 'Partner %s' % id, - 'street': '----', - 'email': 'test@example.com', - } + 'name': 'Partner %s' % id, + 'street': '----', + 'email': 'test@example.com', + } self._execute('res.partner', 'write', [id], vals) def make_anonymous_project(self): - if(self._execute('ir.module.module', 'search', [('name', '=', 'project'), ('state', '=', 'installed')])): + if (self._execute('ir.module.module', 'search', [('name', '=', 'project'), ('state', '=', 'installed')])): ids = self._execute('project.project', 'search', []) for id in ids: vals = { - 'name': 'Projekt %s' % id, - } + 'name': 'Projekt %s' % id, + } self._execute('project.project', 'write', [id], vals) - #Tasks + # Tasks ids = self._execute('project.task', 'search', []) for id in ids: vals = { - 'name': 'Aufgabe %s' % id, - } + 'name': 'Aufgabe %s' % id, + } self._execute('project.task', 'write', [id], vals) def make_anonymous_employee(self): @@ -837,21 +860,21 @@ class CamadeusFunctions(): ids = self._execute('hr.employee', 'search', []) for id in ids: vals = { - 'name': 'Mitarbeiter %s' % id, - 'work_email': 'test@example.com', - } - self._execute('hr.employee','write', [id], vals) + 'name': 'Mitarbeiter %s' % id, + 'work_email': 'test@example.com', + } + self._execute('hr.employee', 'write', [id], vals) def make_anonymous_leads(self): if (self._execute('ir.module.module', 'search', [('name', '=', 'crm'), ('state', '=', 'installed')])): ids = self._execute('crm.lead', 'search', []) for id in ids: vals = { - 'name': 'Lead %s' % id, - 'email_from': 'test@example.com', - 'description': '', - } - ids = self._execute('crm.lead','write', [id], vals) + 'name': 'Lead %s' % id, + 'email_from': 'test@example.com', + 'description': '', + } + ids = self._execute('crm.lead', 'write', [id], vals) def make_anonymous_mailserver(self): server_ids = self._execute('ir.mail_server', 'search', []) @@ -864,3 +887,28 @@ class CamadeusFunctions(): cron_ids = self._execute('ir.cron', 'search', []) if cron_ids: self._execute('ir.cron', 'write', cron_ids, {'active': False}) + + def set_ext_ids(self): + """ExtIDs für Accounts und Types""" + + # # Konten Ext IDs + # lst_accs = ['200000', '330000', '250000', '350000'] # odoo 9 nummern + # for acc in lst_accs: + # res_id = self._execute('account.account', 'search', [('code', '=', acc)]) + # # print "---------------------------------------------" + # # print acc + # # print res_id + # vals = { + # 'name': 'cust_account_mapp_' + acc, + # 'module': 'account', + # 'model': 'account.account', + # 'res_id': res_id[0], + # } + # try: + # self._execute('ir.model.data', 'create', vals) + # except: + # print "Fehler Anlage ExtID " + 'cust_account_mapp_' + acc + + + + return True From d395314c59402b59779c71052eb0a87864074c4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20Br=C3=BCckl?= Date: Tue, 8 Nov 2016 07:18:49 +0100 Subject: [PATCH 2/2] =?UTF-8?q?update=20f=C3=BCr=2010.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ext/custom-addons/cam_custom/cam_custom.py | 148 --- .../cam_custom/cam_custom_data.xml | 7 - .../cam_custom/cam_custom_view.xml | 111 -- .../cam_custom/static/description/icon.png | Bin 2870 -> 0 bytes .../cam_custom/static/src/img/favicon.ico | Bin 67646 -> 0 bytes .../cam_custom/static/src/img/logo.png | Bin 83455 -> 0 bytes .../cam_custom/views/custom_theme.xml | 11 - .../cam_customer_pricelist/__init__.py | 24 - .../cam_customer_pricelist/__openerp__.py | 39 - .../cam_customer_pricelist.py | 256 ---- .../cam_customer_pricelist_view.xml | 117 -- .../security/ir.model.access.csv | 3 - .../static/description/icon.png | Bin 2870 -> 0 bytes .../static/src/img/favicon.ico | Bin 67646 -> 0 bytes .../cam_invoice_skonto/__init__.py | 24 - .../cam_invoice_skonto/__openerp__.py | 42 - .../cam_invoice_skonto/cam_invoice_skonto.py | 403 ------- .../cam_invoice_skonto_data.xml | 50 - .../cam_invoice_skonto_view.xml | 87 -- .../static/src/img/icon.png | Bin 11169 -> 0 bytes .../cam_max_width/__openerp__.py | 40 - .../cam_max_width/static/description/icon.png | Bin 2870 -> 0 bytes .../static/src/css/max_width.css | 10 - .../cam_max_width/views/max_width.xml | 12 - ext/custom-addons/cam_reports/__init__.py | 24 - ext/custom-addons/cam_reports/__openerp__.py | 37 - ext/custom-addons/cam_reports/cam_reports.py | 93 -- .../cam_reports/report/account.invoice.rml | 236 ---- .../cam_reports/report/briefkopf.rml | 99 -- .../cam_reports/report/mrp.production.rml | 123 -- ext/custom-addons/cam_reports/report/page.rml | 53 - .../cam_reports/report/purchase.order.rml | 225 ---- .../cam_reports/report/purchase.quotation.rml | 168 --- .../cam_reports/report/sale.order.rml | 275 ----- .../cam_reports/report/stock.picking.rml | 101 -- .../cam_reports/reports_data.xml | 34 - .../cam_reports/static/description/icon.png | Bin 2870 -> 0 bytes .../cam_reports/static/src/img/warning.png | Bin 6439 -> 0 bytes ext/custom-addons/cam_testenv/__init__.py | 26 - ext/custom-addons/cam_testenv/__openerp__.py | 46 - ext/custom-addons/cam_testenv/background.xcf | Bin 80934 -> 0 bytes .../cam_testenv/controllers/__init__.py | 24 - .../controllers/testenv_controller.py | 67 -- .../cam_testenv/print_background.xcf | Bin 82174 -> 0 bytes ext/custom-addons/cam_testenv/report.py | 49 - .../cam_testenv/static/description/icon.png | Bin 2870 -> 0 bytes .../cam_testenv/static/src/css/testenv.css | 20 - .../static/src/img/back-testenv.jpg | Bin 22037 -> 0 bytes .../static/src/img/print_background.png | Bin 26060 -> 0 bytes .../static/src/img/print_test_inkscape.svg | 69 -- .../static/src/img/print_test_n.svg | 70 -- .../cam_testenv/static/src/js/testenv.js | 32 - .../cam_testenv/views/cam_testenv.xml | 42 - ext/custom-addons/cam_work_order/__init__.py | 25 - .../cam_work_order/__openerp__.py | 40 - .../cam_work_order/cam_work_order.py | 162 --- .../cam_work_order/cam_work_order_data.xml | 49 - .../cam_work_order/cam_work_order_view.xml | 211 ---- .../security/ir.model.access.csv | 5 - .../static/description/icon.png | Bin 2870 -> 0 bytes .../{cam_max_width => dp_custom}/__init__.py | 2 + .../{cam_custom => dp_custom}/__openerp__.py | 19 +- .../dp_custom/data/dp_custom_data.xml | 127 ++ .../{cam_custom => dp_custom}/i18n/de.po | 9 +- .../models}/__init__.py | 5 +- .../dp_custom/models/ir_ui_menu.py | 54 + .../dp_custom/security/ir.model.access.csv | 2 + .../dp_custom/static/description/icon.png | Bin 0 -> 2225 bytes .../dp_custom/static/src/img/favicon.ico | Bin 0 -> 26622 bytes .../dp_custom/static/src/img/logo.png | Bin 0 -> 2225 bytes .../views/dp_custom_view.xml} | 5 + ext/custom-addons/dp_report/__init__.py | 3 + ext/custom-addons/dp_report/__openerp__.py | 23 + ext/custom-addons/dp_report/i18n/de.po | 19 + .../dp_report/models/__init__.py | 1 + .../security/ir.model.access.csv | 0 .../dp_report/views/delivery.xml | 75 ++ ext/custom-addons/dp_report/views/invoice.xml | 65 + ext/custom-addons/dp_report/views/layouts.xml | 58 + .../dp_report/views/saleorder.xml | 85 ++ .../mail_follower_control/README.md | 20 - .../mail_follower_control/__init__.py | 24 - .../mail_follower_control/__openerp__.py | 60 - .../mail_follower_control/i18n/de.pot | 84 -- .../i18n/mail_follower_control.pot | 82 -- .../mail_follower_control.py | 296 ----- .../static/src/css/mail_follower_control.css | 15 - .../static/src/js/mail_follower_control.js | 82 -- .../mail_follower_control/views/templates.xml | 52 - .../mail_follower_control/views/views.xml | 64 - .../oerp_no_phoning_home/README.md | 15 - .../oerp_no_phoning_home/__init__.py | 1 - .../oerp_no_phoning_home/__openerp__.py | 29 - .../oerp_no_phoning_home/base_view.xml | 7 - .../oerp_no_phoning_home/mail.py | 25 - .../oerp_no_phoning_home/mail_data.xml | 26 - .../static/src/img/icon.png | Bin 11169 -> 0 bytes .../static/src/js/announcement.js | 13 - .../static/src/xml/base.xml | 17 - .../sale_order_optional/__init__.py | 22 - .../sale_order_optional/__openerp__.py | 42 - .../sale_order_optional.py | 134 --- .../sale_order_optional_data.xml | 6 - .../sale_order_optional_view.xml | 17 - .../static/description/icon.png | Bin 2870 -> 0 bytes .../sale_order_reminder/__init__.py | 22 - .../sale_order_reminder/__openerp__.py | 44 - .../sale_order_reminder/email_template.xml | 46 - .../sale_order_reminder.py | 67 -- .../sale_order_reminder_data.xml | 16 - .../sale_order_reminder_view.xml | 31 - .../static/description/icon.png | Bin 2870 -> 0 bytes .../web_printscreen_zb/__init__.py | 27 - .../web_printscreen_zb/__openerp__.py | 41 - .../web_printscreen_zb/controllers.py | 185 --- .../static/src/js/web_printscreen_export.js | 122 -- .../static/src/xml/web_printscreen_export.xml | 16 - .../web_printscreen_zb/trml2pdf.py | 1044 ----------------- .../views/web_printscreen_zb.xml | 12 - 119 files changed, 533 insertions(+), 6614 deletions(-) delete mode 100644 ext/custom-addons/cam_custom/cam_custom.py delete mode 100644 ext/custom-addons/cam_custom/cam_custom_data.xml delete mode 100644 ext/custom-addons/cam_custom/cam_custom_view.xml delete mode 100644 ext/custom-addons/cam_custom/static/description/icon.png delete mode 100644 ext/custom-addons/cam_custom/static/src/img/favicon.ico delete mode 100644 ext/custom-addons/cam_custom/static/src/img/logo.png delete mode 100644 ext/custom-addons/cam_custom/views/custom_theme.xml delete mode 100644 ext/custom-addons/cam_customer_pricelist/__init__.py delete mode 100644 ext/custom-addons/cam_customer_pricelist/__openerp__.py delete mode 100644 ext/custom-addons/cam_customer_pricelist/cam_customer_pricelist.py delete mode 100644 ext/custom-addons/cam_customer_pricelist/cam_customer_pricelist_view.xml delete mode 100644 ext/custom-addons/cam_customer_pricelist/security/ir.model.access.csv delete mode 100644 ext/custom-addons/cam_customer_pricelist/static/description/icon.png delete mode 100644 ext/custom-addons/cam_customer_pricelist/static/src/img/favicon.ico delete mode 100644 ext/custom-addons/cam_invoice_skonto/__init__.py delete mode 100644 ext/custom-addons/cam_invoice_skonto/__openerp__.py delete mode 100644 ext/custom-addons/cam_invoice_skonto/cam_invoice_skonto.py delete mode 100644 ext/custom-addons/cam_invoice_skonto/cam_invoice_skonto_data.xml delete mode 100644 ext/custom-addons/cam_invoice_skonto/cam_invoice_skonto_view.xml delete mode 100644 ext/custom-addons/cam_invoice_skonto/static/src/img/icon.png delete mode 100755 ext/custom-addons/cam_max_width/__openerp__.py delete mode 100644 ext/custom-addons/cam_max_width/static/description/icon.png delete mode 100644 ext/custom-addons/cam_max_width/static/src/css/max_width.css delete mode 100644 ext/custom-addons/cam_max_width/views/max_width.xml delete mode 100644 ext/custom-addons/cam_reports/__init__.py delete mode 100644 ext/custom-addons/cam_reports/__openerp__.py delete mode 100644 ext/custom-addons/cam_reports/cam_reports.py delete mode 100644 ext/custom-addons/cam_reports/report/account.invoice.rml delete mode 100644 ext/custom-addons/cam_reports/report/briefkopf.rml delete mode 100644 ext/custom-addons/cam_reports/report/mrp.production.rml delete mode 100644 ext/custom-addons/cam_reports/report/page.rml delete mode 100644 ext/custom-addons/cam_reports/report/purchase.order.rml delete mode 100644 ext/custom-addons/cam_reports/report/purchase.quotation.rml delete mode 100644 ext/custom-addons/cam_reports/report/sale.order.rml delete mode 100644 ext/custom-addons/cam_reports/report/stock.picking.rml delete mode 100644 ext/custom-addons/cam_reports/reports_data.xml delete mode 100644 ext/custom-addons/cam_reports/static/description/icon.png delete mode 100644 ext/custom-addons/cam_reports/static/src/img/warning.png delete mode 100644 ext/custom-addons/cam_testenv/__init__.py delete mode 100644 ext/custom-addons/cam_testenv/__openerp__.py delete mode 100644 ext/custom-addons/cam_testenv/background.xcf delete mode 100644 ext/custom-addons/cam_testenv/controllers/__init__.py delete mode 100644 ext/custom-addons/cam_testenv/controllers/testenv_controller.py delete mode 100644 ext/custom-addons/cam_testenv/print_background.xcf delete mode 100644 ext/custom-addons/cam_testenv/report.py delete mode 100644 ext/custom-addons/cam_testenv/static/description/icon.png delete mode 100644 ext/custom-addons/cam_testenv/static/src/css/testenv.css delete mode 100644 ext/custom-addons/cam_testenv/static/src/img/back-testenv.jpg delete mode 100644 ext/custom-addons/cam_testenv/static/src/img/print_background.png delete mode 100644 ext/custom-addons/cam_testenv/static/src/img/print_test_inkscape.svg delete mode 100644 ext/custom-addons/cam_testenv/static/src/img/print_test_n.svg delete mode 100644 ext/custom-addons/cam_testenv/static/src/js/testenv.js delete mode 100644 ext/custom-addons/cam_testenv/views/cam_testenv.xml delete mode 100644 ext/custom-addons/cam_work_order/__init__.py delete mode 100644 ext/custom-addons/cam_work_order/__openerp__.py delete mode 100644 ext/custom-addons/cam_work_order/cam_work_order.py delete mode 100644 ext/custom-addons/cam_work_order/cam_work_order_data.xml delete mode 100644 ext/custom-addons/cam_work_order/cam_work_order_view.xml delete mode 100644 ext/custom-addons/cam_work_order/security/ir.model.access.csv delete mode 100644 ext/custom-addons/cam_work_order/static/description/icon.png rename ext/custom-addons/{cam_max_width => dp_custom}/__init__.py (98%) mode change 100755 => 100644 rename ext/custom-addons/{cam_custom => dp_custom}/__openerp__.py (73%) create mode 100644 ext/custom-addons/dp_custom/data/dp_custom_data.xml rename ext/custom-addons/{cam_custom => dp_custom}/i18n/de.po (71%) rename ext/custom-addons/{cam_custom => dp_custom/models}/__init__.py (91%) create mode 100644 ext/custom-addons/dp_custom/models/ir_ui_menu.py create mode 100644 ext/custom-addons/dp_custom/security/ir.model.access.csv create mode 100644 ext/custom-addons/dp_custom/static/description/icon.png create mode 100644 ext/custom-addons/dp_custom/static/src/img/favicon.ico create mode 100644 ext/custom-addons/dp_custom/static/src/img/logo.png rename ext/custom-addons/{cam_customer_pricelist/cam_customer_pricelist_data.xml => dp_custom/views/dp_custom_view.xml} (93%) create mode 100644 ext/custom-addons/dp_report/__init__.py create mode 100644 ext/custom-addons/dp_report/__openerp__.py create mode 100644 ext/custom-addons/dp_report/i18n/de.po create mode 100644 ext/custom-addons/dp_report/models/__init__.py rename ext/custom-addons/{cam_custom => dp_report}/security/ir.model.access.csv (100%) create mode 100644 ext/custom-addons/dp_report/views/delivery.xml create mode 100644 ext/custom-addons/dp_report/views/invoice.xml create mode 100644 ext/custom-addons/dp_report/views/layouts.xml create mode 100644 ext/custom-addons/dp_report/views/saleorder.xml delete mode 100644 ext/custom-addons/mail_follower_control/README.md delete mode 100644 ext/custom-addons/mail_follower_control/__init__.py delete mode 100644 ext/custom-addons/mail_follower_control/__openerp__.py delete mode 100644 ext/custom-addons/mail_follower_control/i18n/de.pot delete mode 100644 ext/custom-addons/mail_follower_control/i18n/mail_follower_control.pot delete mode 100644 ext/custom-addons/mail_follower_control/mail_follower_control.py delete mode 100644 ext/custom-addons/mail_follower_control/static/src/css/mail_follower_control.css delete mode 100644 ext/custom-addons/mail_follower_control/static/src/js/mail_follower_control.js delete mode 100644 ext/custom-addons/mail_follower_control/views/templates.xml delete mode 100644 ext/custom-addons/mail_follower_control/views/views.xml delete mode 100644 ext/custom-addons/oerp_no_phoning_home/README.md delete mode 100644 ext/custom-addons/oerp_no_phoning_home/__init__.py delete mode 100644 ext/custom-addons/oerp_no_phoning_home/__openerp__.py delete mode 100644 ext/custom-addons/oerp_no_phoning_home/base_view.xml delete mode 100644 ext/custom-addons/oerp_no_phoning_home/mail.py delete mode 100644 ext/custom-addons/oerp_no_phoning_home/mail_data.xml delete mode 100644 ext/custom-addons/oerp_no_phoning_home/static/src/img/icon.png delete mode 100644 ext/custom-addons/oerp_no_phoning_home/static/src/js/announcement.js delete mode 100644 ext/custom-addons/oerp_no_phoning_home/static/src/xml/base.xml delete mode 100755 ext/custom-addons/sale_order_optional/__init__.py delete mode 100755 ext/custom-addons/sale_order_optional/__openerp__.py delete mode 100644 ext/custom-addons/sale_order_optional/sale_order_optional.py delete mode 100644 ext/custom-addons/sale_order_optional/sale_order_optional_data.xml delete mode 100644 ext/custom-addons/sale_order_optional/sale_order_optional_view.xml delete mode 100644 ext/custom-addons/sale_order_optional/static/description/icon.png delete mode 100755 ext/custom-addons/sale_order_reminder/__init__.py delete mode 100755 ext/custom-addons/sale_order_reminder/__openerp__.py delete mode 100644 ext/custom-addons/sale_order_reminder/email_template.xml delete mode 100644 ext/custom-addons/sale_order_reminder/sale_order_reminder.py delete mode 100644 ext/custom-addons/sale_order_reminder/sale_order_reminder_data.xml delete mode 100644 ext/custom-addons/sale_order_reminder/sale_order_reminder_view.xml delete mode 100644 ext/custom-addons/sale_order_reminder/static/description/icon.png delete mode 100644 ext/custom-addons/web_printscreen_zb/__init__.py delete mode 100644 ext/custom-addons/web_printscreen_zb/__openerp__.py delete mode 100644 ext/custom-addons/web_printscreen_zb/controllers.py delete mode 100644 ext/custom-addons/web_printscreen_zb/static/src/js/web_printscreen_export.js delete mode 100644 ext/custom-addons/web_printscreen_zb/static/src/xml/web_printscreen_export.xml delete mode 100644 ext/custom-addons/web_printscreen_zb/trml2pdf.py delete mode 100644 ext/custom-addons/web_printscreen_zb/views/web_printscreen_zb.xml diff --git a/ext/custom-addons/cam_custom/cam_custom.py b/ext/custom-addons/cam_custom/cam_custom.py deleted file mode 100644 index 6a3ab475..00000000 --- a/ext/custom-addons/cam_custom/cam_custom.py +++ /dev/null @@ -1,148 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# OpenERP, Open Source Management Solution -# Copyright (C) 20014-2016 Camadeus GmbH (). -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -# -############################################################################## - -from openerp import fields, models -from openerp import api -from openerp.tools.translate import _ -from openerp import SUPERUSER_ID -from openerp import tools -from lxml import etree - -DISABLED_MENUS = [ -] - -class ir_ui_menu(models.Model): - _inherit = 'ir.ui.menu' - - @tools.ormcache(skiparg=2) - def get_disabled_menu_ids(self, cr, uid, context=None): - data_obj = self.pool.get('ir.model.data') - - menu_ids = [] - for menu in DISABLED_MENUS: - module,xml_id = menu.split('.') - menu = data_obj.get_object(cr, uid, module, xml_id) - if menu: - menu_ids.append(menu.id) - return menu_ids - - def _filter_visible_menus(self, cr, uid, ids, context=None): - if uid != 1: - disabled_ids = self.get_disabled_menu_ids(cr, uid) - - ids = [id for id in ids if id not in disabled_ids] - - ids = super(ir_ui_menu, self)._filter_visible_menus(cr, uid, ids, context) - return ids - -class res_partner(models.Model): - _inherit = 'res.partner' - - @api.model - def fields_view_get_address(self, arch): - """ verhindert das Überschreiben von address_format """ - return arch - - -class mail_notification(models.Model): - _inherit = 'mail.notification' - - # override original function - def get_signature_footer(self, cr, uid, user_id, res_model=None, res_id=None, context=None, user_signature=True): - """ Format a standard footer for notification emails (such as pushed messages - notification or invite emails). - Format: -

--
- Administrator -

-
- Sent from Your Company using OpenERP. -
- """ - footer = "" - if not user_id: - return footer - - # add user signature - user = self.pool.get("res.users").browse(cr, SUPERUSER_ID, [user_id], context=context)[0] - if user_signature: - if user.signature: - signature = user.signature - else: - signature = "--
%s" % user.name - footer = tools.append_content_to_html(footer, signature, plaintext=False) - - # add company signature -# if user.company_id.website: -# website_url = ('http://%s' % user.company_id.website) if not user.company_id.website.lower().startswith(('http:', 'https:')) \ -# else user.company_id.website -# company = "%s" % (website_url, user.company_id.name) -# else: -# company = user.company_id.name -# sent_by = _('Sent by %(company)s using %(odoo)s') -# -# signature_company = '
%s' % (sent_by % { -# 'company': company, -# 'odoo': "Odoo" -# }) -# footer = tools.append_content_to_html(footer, signature_company, plaintext=False, container_tag='div') - - return footer - -# class product_product(osv.osv): -# _inherit = 'product.product' -# -# def name_get(self, cr, user, ids, context=None): -# if context is None: -# context = {} -# c = context.copy() -# c.update({'display_default_code': False}) -# return super(product_product, self).name_get(cr, user, ids, context=c) - -class sale_order_line(models.Model): - _inherit = 'sale.order.line' - - @api.onchange('name') - def onchange_name(self): - if self.name != False and self.product_id.id == False: - ir_values = self.pool.get('ir.values') - company = self.env['res.company'].search([], limit=1) - taxes_id = ir_values.get_default(self._cr, self._uid, 'product.template', 'taxes_id', company_id=company.id) - at = self.env['account.tax'].search([('id','=',isinstance(taxes_id, list) and taxes_id[0] or taxes_id)]) - self.tax_id = at - -class product_product(models.Model): - _inherit = 'product.product' - - def name_get(self, cr, user, ids, context=None): - """ beim Angebot die Nummer nicht in das Feld Bezeichnung übernehmen""" - if context is None: - context = {} - c = context.copy() - if c.get('partner_id', False): - if not c.get('quantity', False): - c.update({'display_default_code': False}) - return super(product_product, self).name_get(cr, user, ids, context=c) - -class res_country(models.Model): - _inherit = 'res.country' - - active = fields.Boolean('Aktiv', default=True) \ No newline at end of file diff --git a/ext/custom-addons/cam_custom/cam_custom_data.xml b/ext/custom-addons/cam_custom/cam_custom_data.xml deleted file mode 100644 index 3018e5f9..00000000 --- a/ext/custom-addons/cam_custom/cam_custom_data.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/ext/custom-addons/cam_custom/cam_custom_view.xml b/ext/custom-addons/cam_custom/cam_custom_view.xml deleted file mode 100644 index 8852021a..00000000 --- a/ext/custom-addons/cam_custom/cam_custom_view.xml +++ /dev/null @@ -1,111 +0,0 @@ - - - - - - tree,kanban,form - - - - - - - - partner_section_form - res.partner - - - -
- - - -
-
- - -
- - - -
-
-
-
- - - - product_template_variant_kanban - product.template - - - - - - - - - product_template_custom_tree - product.template - - - - - - - - - - - - - - tree,form,kanban - - - - - product.supplierinfo.form.view - product.supplierinfo - - - - - - - - - - - - - Dokumente - ir.actions.act_window - ir.attachment - form - tree,form - -

- Click to create a new document. -

- The Documents repository gives you access to all attachments, such - as mails, project documents, invoices etc. -

-
-
- - -
-
diff --git a/ext/custom-addons/cam_custom/static/description/icon.png b/ext/custom-addons/cam_custom/static/description/icon.png deleted file mode 100644 index fd7ee3b90ede569d07369b51f5036c9c0de4e9b2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2870 zcma);XE+-Q8-}B$h*9cO(W+W8YHu|osHhRtII2;j?V%bgv4WyawMr>zjo4~b6^+KO zy-LNX+F~ST?OlX?&iVKK`>ywTp7(j5>w5p+(Uum*9Kb6;006*Y0yDHe+m`=`<-(cA zac`HLEe4deF%(eRE3kZaTyQltHU!ZBne6&P+*!lw19LzD0Bk(}hyj342c4D7XcKcI zW-<`Sp$PPl67mE9fR!eO`Zhu1Yh%GazvlUywloDOO)Yim{s0j;a?#54`AdvV-hL1F$(fA01)q<;M!IO%tp|u$GvJx2X^o z{e$_6>Uy12iCX}UM;Tn_!q-B9f=&!Di11?=YpE7i0{aIN@a9|6r)mA&i}5GnGjAmA zw?8N;oOBeYJ2jyH^V+O%bLbv+WF!W)E!MJl71JBjo>IMoB*ISnuY#+*p-Y-9k#tlt zN3)hh97P~ReMf1eUC&eQt{3C+%+vHZJHvgC=G-KFm`vkWq48V}shZ26XbA!3QzC{ar}NWJJhF{igFlv7-q zf4m)BjX(%7Dy8PlIj{6HuQk$-#WEd}YdU>FjRe8^-6wO$=g~t>jCi$lVW<#-`9n3f zWvDNEp08hVUip=?LYls4xnx4#oR1drA$6d|r6o{K^xN(P03Gh4<^{jlz^^P78mfw5 zdqm-2kKmfAbp|<)fp~diLoigXT=5c>{aFKppr8J%h~Pb+0EStuja%ZEf->8Do417; z0_8>09&Qa4_d|uT9?$xW>E7$t6NEKE7w&4rUIx0nHPcrMek>OwdQvy5ahXI4g)`3{f$S(I%G@1pfg z)0k2}E1D~io212z-rs+0VnUQm zy*C}pWzHodbU(Ft%(9$CQ+xV1cdS~RhWz5cemoUld+XXXk;pjJmqU-JGYFsqsKVo)?DwZ_)op)|L)g1n@r%~EAz{rOPPApX#SOmoO20b&BvCv4EOE0@;x$ks7mU;&W$TkIR;WOYrwy2btFLyeSOrCKp%-t^oLp(U0m^@$C*{7T}B@oIqV z#;WkO7@RsGMY}am6zL|+qF0}^t(DY&#e4?X3>wK-2w!XY(5g*ma$j>Q#`$_+0`bKKfRHs;;Mj&PL;*W*EtQca3ZS zr^@AKAVv!@(Q@?}FXW$)0FP%C!irRcHuKu{wK0L}JThehQyy67AAE~BFQ7rz6o$h) zpNeV@LWp}D&LM(!t)4X0?VF|3FFhv&!u(`Wr^Kj_$iY;zTz=gGIhqnuk0#hso=^}e z7~Sug|FS!Darg}p9Y9^WB9V!C-Ju%ZsvK7RQ}l#_GHdYUU+ZEl?dQ^}RDKKdIhtYE zKRGeM7Uaywx~wws{S<_YAV68ka2FCZQ;3k2P$Qgbpj-nO)#$2bW}$2K@*{Q*jFby zrX$i8?lZin&Y{|m@K*83En;;!+7g3lLvc688W-fz`H8Tmub-cAn+luppv>O7$?F_9Zu44tSoitvJqrgZGlRnLom-s9DUHdeV`}OR!MeC)a%+;7mpBwLo<9P8=MKZAS%|7|oWyn+c6V31EINKDtsoNn$z)P2zw)cX zK>=-_h%R2<(Ilg%PJ$-`lEJeIb$C2T&qYK(%f!lx`>e{bWNCEi|2bs=_m3!%-(H2>n5T$7cRT_qoL##|;hnL1V}_&-*)wY5!0Shp1HtvHlFU@f+%zc+Zvi6Z-t42)LC zl$Y;(EGfxf{3Yc|0Br@)1~sR-Sr}hEa8z;QT4g#6mQ|> zp%@deeoHy*!=^x|@PDqHhX~CS=H`kVYd~CFgx|k^|JmVdRI2jdN&%~XReDdy^(|gs zUr<$~Opx|{YAwVPV^(U>Xtbq+18Y-P5-vT&i=WyVPk$HRH3rt+ZN;dS=uC(Y1>#Qw zFY+Lf`pV|O8^s{y94th?xe;-$GwvF7bGB9HuP+hqD&4&qTB+*Zf|bZSHa2bRWRh9t zJre_i^I$O8#@3dAoKU-Qqq~dr#%HF9f%a7I@bJ*a#>R*C$Ct7N8X8(0oSf|0T^{ss z4|-2Ip<;Y``Uy|h>7Y$AY`FaC9gPnKty z;Rb~FUuXIVJTs2P*^pV1^{CgS-2C;B%T zHxLyRM7Bl+_XU;39n>JZARw|fTeCIL3*BeF?^K<8>%D&6fbd>-L$|+U-R<35Ro{1( zI#u_QNF0Ix1`kf)|Lqc8k3AyMB#}sTh2Rhm>Tzx!=%0urYNh)3!GYpj(eG=qum0E* zqfGtP;$Mq@EeEPU2Ws`d`eT$yJ*vgO7XM6eAd{S}z4yW6Y$mYhJ!>&Kco=1}FKh9y z88~H%1BVCxWeF*hL|KrNDl5aWXum8zr`Nf2W!z4>u41l~zb?3^1lzc$g!|mqV-?>! zuIItO=J3Fu*pmb7YbWf}@|acJzvPbnwluiU{$S^x=eQWx#qlAN7*}@h!v%lpT-@hQ zzpY>Pl$IrmOZFrRi%Jr^c9$e}?krC1*ioF=zN09yZF^B-Q~vIISFJ6O#mlzH+%NKF z&Z2xR7cSi@D^~50&H1};+>Yyb{f>g-L;-%!`|y56#d{LGzdcJ!>N`1vYFkV8lqPne-?wZnZ2#%JP4d7KbLHp2x#Ov06t|;+?J@Npkz?x(k>lzQmE#)> zl@l5bmAZ`{b<$+0oY?qL2uj;-G)zv!c^w_%^ltT`LiZqU}0l$0jh2e!?}1m?HcrZ9dIU$nvNHtdv_-&!GqZk;MQy`Pq&>OKUlAC@}6LorrNfg>8F3;!#_QZU)~C)%kH}GV9+ajXpOjzzcAC6DD^K#b6kbq- zcqFy~`xmQLgmt>(H4T5&1H?|&H_jG_+R*hIcjixgWw{KvWRe_7n-1Gcd(8f>Yr2_) zS%6CxkJnYZf_l-vkRy;2uzf6i(2=kU=OBI<_rg-igY8Q74YYHiEeN;M;k&nEH39$B zI4+Kp1hI8#V#DU$pXR=_O!}RdD@Q<==zG;4d;QZsPSx!!;_duG$Tj*0k3H+*IiNlU z+w>7f9Q&a3`St`EGwDlNziC&#ix-19hw(tFf#Xt0G(HIY$XFi2Gf7W-Omm`jO zNXJ|*&Z7QQM|=;oPL9VMTOJ7;cgnfBG9CGf-GwDS4qz-~Hem1ip2~shh`;$Yav=2m zTaiB*Iew8eXgyrV>Z;q3@2n~MzQ26%?egucgPg*NEgqK<&n%QJ+X~yeyb$dG`pS=o ziE+4{ig~zS9r4%tNB+%mnlaGb_kSWsBG=|(dg?p-#>*k8`<^RF?R0sB#PJWwf89G% z@;2>4cey@_IpAV}(1zMIsb%%V-~5_u*V??D^1DC1Cy8Sp@Z%+7zrT8P2wbmi_HD;@ z;+O~ImOI|n+>yf-v5}7l_62+XCR2Z@JlmiB(B?BQb_?=2iElmNFlQgAQ11@`O!v19 zY701abooe*69@ffs^@@<17bU{_jsVX;2&acT;aUi9fLmt&mZ*q9&d)%1uO&IaI#QVPeD39Ca`Z`PAI3e5^P-%o zFnZBh>b@-yEw`jTYs7@NM{GC1^!X2@BG)Cg`1^K_mOfu=3;5%s$c%L zy2Tx?pExdR*mk(goV^~?Bk=vuCFY8h2i#91RgJ&nWbCUrp1I^_ugbTu*21u_#eX08 z=Ho)<3Yi<@ytl@I-lnG0{pw=>$xqg$uxL+W=u`7F=k0Pk;I$v$I}YqaKOByJAo7Lm zuSbPz3kKgeOPDK-be=q@hWc;5iR0DYO&v^@h)Q}$Z;4S z&YZmg-RpBfzKrm#%0k@g!N`}ZqKYmHJA!nY9 zd2+v31^&iKS1&i8_ukBPi1+=xJz{&vfx1DvJZM_vnJ<64&KC6yPod`RL0@TVW` zciu$VinZxFzV>5m^SRXl|I$5W39flNy52CU*W?K=k0XwOG=3})#|yU()8#&sc!Bn6 zyx`--!#i$(Zg8z5bcgHKxh9V9AZVVAYX_ir77JF5{^R)^^TYmdjqbo3ree+X6LM11 z5s=|hkJ5x&wlg20`UU*KZ&7kdYxdL5VW#a~vNxU$Ar21HmGrdg-xAi&~Q!%be zC$T>=n^cvy$l}W(`d{>%6ku&J*GxLQYxcM-Q}Cz69QM4x|IiPClZ)^UP2J`r zf%%hiQnRNZD7md%ARnBh=S0AZCT1(lPB<=@9Z0ej^eMnHIi4W4jzc`oZCkH>EY|4i z`vF*wbpn6eY?zkEVx6HL$9b;Ra`zL^A$tKi^+@Z)P6W4LKVS<=d;k z|A(Z2h=&?K@h|gb%&w2b1N>t6!CCZhA|uz4aZr8s(1$zA6`9I$2I1 zFhSb)93>|<9j5PmkT>L;>7el;$v^XarX+>i$0IK|5bwK0J|M`oXUYIn7XOh0l>Dtl z7xX-HGIacDY0zS{O8w?fg9jAyA(RSuk;Y!sgUwL?;r+;o@FNuZ5REI6VvE>^u%C{D zy=>iOq?~{0B)R>+-j_+QEtfA>Zbx&HZJ6!v!SQ)Z^5sdaOS<;vx25mdo)Gxu|Sj;1P?OxXZ=%ANiNR#cs=xGlr(HPMx{ZE zG2p;6fjCYyXyG}bWx$DM*xmcbh#chZ0AlS7t=WLLhZks0Udtm+oe5xDevbZP5Cn z%+#OtM^b5h2c0QGuJ<>0egd5w3+%^BqZVVOK}&9X0T(LdMf1_#Mx?V9uoK>oB>NEf z5sfR7;|tn}6B<1sIX%Y6AMTzhYc`~;r(&HoUN+1*mgX@hjsxTc&&M`m^u)z-D%S67 zEUK}15O1h`&Y=A-$1%5N>|*4D+MsfR(02Mh;+Vh7X)j5`789g#%L!U4 z55NU2n~%dWFXV)7gCpcgIXgj{VYVXVMqn#~_#)y3_)xde2vl5E(K&6G=YhY^lo_k!tbcx1<4BDSeT?CBJ)6D&c8K%nEgpjp*rhpP^}%Ro zrv9ui!%|~E^bI-q*@7){e53Kwxb;M7)bd$r)cRTQfZLE(xv&Sh;K2m!L%fq{(`nBG-4D0z zd|aA;! z{%RYeeiVFbp)_&tkj1da&qbg64e;9k88$~+ba)Em z3d1g4{)%y;;{?m{ISc#kHz;{u=s(9LoMUl5!1=Xo;Lkp=zU4OOc`qCI0kE7bP1-_Q zPXZ5292dxkCT*UBeSm-yjf@w*R6C*e!Z?v)FJL1g|KWXy*^Bzk$KZZr<<>hsmffg} z)(?2Ij;8<2m&dvv>o%{gOx$mHFV|*Xy93`I7Oy>b%(r zZ0lSIa}tq_0G?^LE8qrgKgXotK?i(;Abh7ZyZB=*3i^ZJRB7GgHDLdeG^Mn85#jb>zA3X8lPH(PoEE<=!7-}C zwp<=d`QbQ{%!z;tYFDt2d(^?VDVDF^t}y`P)lB^*^^K367(Y?JKApD>xt$lKS-Y2| zSz8m&1>;0pasonbC@&_XbfUbVy`bF)IMD>Qq6v9{(!~?bZZv`qX-qz#Y|wmywCeo4 z-1o4v`-+dRpM7J+bU3LEd(r#7U0aIZU-PSJ!177po-zipv8nQ+eBRsTEXV~D^1+L@ z9m%|Kx}Iz=XagR_m~;r(JT_(}uy_^tzm_6AMtQ}Fa>IDx z`JlXjoe1njG9Tzi%vLxqs1H#;@*M1Du6+N>X|jA(0U$HKRJl#x8@835SDOOP^O{k) zOQmz~T*Tr}`Md>ln_ilR<5SCf4@ZndTTz}9Iv?WaLfm{vzzMSz^dTm+6N~|nleqoQ zAGkaaFv-+kYM&VX%=zAS=K^5#hBVK46T;Hub!nCZX-6?`1bk3lID4Ufqnxd9{)2p= zt%!KxV~a+uo<|(^g4})Id{ob{cfLBcz6W#P*%L{u+q7H0d->~#1DT^p$#MET7V}vV zC!*YDYTny85%R*%kHL4;^AgzzZ!26b;!!#8@)xCy>q4`HKc8c{k;01x&aDmb;nG?zfazc4woM36T!ttYNlC7Z42<(NAE9y6&BRX+H1 zlj6@hMLr+f2NUz~UZD+O%-I0>&ic(Q&&j-nAD0VEiK!>?YZ!lw9IjwXii>0)JBjO zDYl{+Z3gTFCAJmD3;K_jrD+sjI3H5K#S3!HuVzUJ`AGeTSUtmSJ9aQici-5?jLKam zUHeReO|K~D9p|#*xsViFku*;h_>hY1g~b)#kDLI%k+*rb#(>$t-};uZ)|$LRjQ8J> zRvo8#nF=0w=|Da}ln;&lfx7rhl>(wt2d=?leQCRmbVz0i+X4&xsDx949(}7sd&cEjoe| zuoo?8Bh+_T8Tb&j6EP<&wrJeyHRNJv$dnlyP&KFb#!K7JRB1MV_b);pT>9f_ST8V6 z8Z?_A4VsQeIUe!gI44a}QksngR%0-i2x#=&6JEfe|bQDTR6AIQ- zB*|0Y8|6urx(!FjletT>j(-W-KIVn>(9idzP3QN3Kjqy>T6s<=H;fm?2`$NoWKNJD zE$BmXVjq%ZE9gUDD;l-`B-I8VBLoH~+^c(yY@YY1w%) zgr$=f7?-x_1nK;omuFGN(!A5N(!A3|FS#fo9do6b$^?`qxBS#!4uSbDoj= zhtA7B{uui`Fl-g@`T+QU2w_QiUs{_eCt_}doZxn3FCtz{#W5%9N4&kDtx#TgU(&Gk zn=6B|Der?{739VT7nFRi}kD1={zTx)4 ze$M{f&&^LbJ;)0FUe}oW`{ygakapevAvxVCpMeJ^juYgCO2iG%i>{6rv>D}jk?coO zZACN0o9A8f5BcD;ZRjSnJBzx%Ke$xIwOPU6+rc8_{!YJmk+knV2kYY?-9JY;TP3Ia zY^=coCn9mY$T2=>>Fq^#mH{uiIX}`S$&bXGXqNMVTzutRS+IPk!@rgTQQj+?_!kzI zCVHK_NILYG=VdNRFXV&@IN^DbLvGMckP}*dhHVIJM#zh{$_L|wFKH)ye9GQH;OmWL4-~b$Vu2@b~tXx&O}n7D>k*3#DVv1%b@>e6Z4Sf;OT9?L-gS3G#w` zfSu6Ncwzp7C4Gl4BmaT1cKey~FV}t{TX(tjIMu}uR|g(s1%Iz=)c+2>zmQJ77E7m- z7ontp3zVM52`lI0nDK%3f}9{9Q10;v=K=@#QcZZi}}ERu3Uffidy{B@ITx5cj);w=D)r4W%(6kg>*p~iE_j7fxL+A zh1rZHuoosFA3{zrwjehaAs;wj2HpI1E&f%Fe^FVYQ=e7Rt?z2cD(QMEw^vFx@&RSn zzAGT)1WM%v>_Q)k*$U%?^B-MkBa-Zd`4Hm-%P){GS_u2UsuurhfPc5s*GTtM*Fx6d z-5V#}PX!++;6yia!gv8Lbc^^vZWu3&51t?DKb#MV`QSLhxT0;>#qx`rR!dQB-Y?4g zSPYU?`w#u^eXhs8A4)IXv?MRQ^s{Yp!t;XMpv~w*I{{H2LO#Ttpv`cx1i27PyY5Tn z=Qpg8Ejvr`?tx|q#R2~DTx_Thhud~G@V7pt{{P_G zjZXhP?#>3p`k!P6a1CvP*#mbDzQH(wQh5{X+cg$jFs|s-dllaK$deC0b!)%EZ{b

}s^z-)h{@KL882bOOzukb8@1g#K*Ta|SJ?(eC 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 SE^lkMLy0O|WrL&H*!*8e+L0Lm diff --git a/ext/custom-addons/cam_custom/static/src/img/logo.png b/ext/custom-addons/cam_custom/static/src/img/logo.png deleted file mode 100644 index eab51af1e2e7019771f52312e77a8c4994ead3aa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 83455 zcmbTdWl&trx+sjhCb$HL;O_3hA-KE4;O+r}ySuyV;4Z=4-5nC#=d$-XdG|S0_q#v7 zsj2GKy&mg+w0nBO6y+t65%3Vez`&5DzKMMY1B3De0|SSEgZLOh*{7oZXmFjyHJp|0 z%$(f}9ZkW6P3(+JiKT1}%}u|X8k%@GjF|F)fkB#Cs%SWC$jR~;+u1T0{tJe|-PZmC z8w`w3(B0n9*xJ;Y*vQn}62MP-)!t1?Y-z$zs?ILQBxf&bYGL`!)6rDfQ(nc`)7qHZ zgj7&~n9rT(gMh86vmvp&tqs75$DN<_-*kCCp8qw>NJ{)~5NB(C(*F`lLr#%c)XveA zn4N)@-k6D*nV5rvftih+gM*oln1zX%g^}sw%R$e~#>39R!@^1Y-yhNsZjL5qJm1A6 z{+riFkDt`S+1Z|lk=$$+O&W7&v04K7)6vRxO zj2$iQoh|JE#Q&mbXk_Q&%uo6u>3>bZ)?QBTAHo2q|6Zt%C1Z3qv}a^yU}Chj{nxzy z4ejLo-Sj_V{9mD+R6OiW8NZu4*||6xf9S)E>@V`i+Wo&7{R{9z8Xg5l%MYa(+KAa1 zyV#lnoTbG0Nk85&m{^+dFtdn@v2$}s2(yWDh_f&=3v;ruiHLHE3X2MJaY-<-{H5`K z!(|cY5P91FJ^ru8S>`{0K>+x_C?BtmlmCtUU$7gW{-O52 z@zL5S{zF;>`2U6fzerEh|Ce00u8woml?*{<|56oW)61HRorSy{DEe{w~ z-Zw@$dztkTboz1Z6kX8Y@5-$EX8aH<1gAo2)s6K#|B*4(qz6Yfx9V8!mYLuIEHqmZ zq{74umg~21mal-%&wMFkK(psd_8b6%hnVZ8e9wuD<=Eon)N*FJ-a2vHZSxaW1u%_- z6eQZu#gr>uRI4~YGuC&U1WlKCp$}Qr&YN4%|GsgoTXJ`tHkVg{U+i+0ed0Mpms*#T z?Ls`B{rTK4_B1U_SgjvU06JSpY)qZK|I)90?FonLVm^ zL&MFrut?H-ByQ+pMA*c1&aY-to=6%@bx#JP4ug;SCKwYr0d(E9gEkkOqT-%pcvV3+ z(=R1la<^X;|FBcmi7JcxF%9M<3fQaNhqm^{g_xmm({Vk9ZciJtNPa7x4bMC#I z`s3nXVkrALP3rk5sj~7%`G3@$r|mTY{!Pl|ii3^%GyGnoP9r$51E{?{~Pb~KRYH-_GKeJ6jUiqL4k81(ZHQT5ba z65KY z=`%Aqq3^M@Y)&(@(K}`19j&_9S!*8m6f3L@s&nR|*LoxRQTlZMI8qRxQ>4#ytR%KY z*`cLnH~ZBN`|$FDRojhuWTxxqsDQ(*l(vYG2sVg$sCbuIb*DumSTXo>S16=bB7p|F z$R4dQd-5f83!#NdaG6@ZupqP!E_Lt`MEY$Sg4iGhqBui#-312`S_%|iud_ii} z2qpGK+C4P^@}zv#G82*HKe>XiQqG8BI>Of|>7R(hd>ya~q^qY>e7Pa8tm&Vv;m#Rd zGaa3$GHNb6uC=(f6%BADP%8eXNn$oq&h!w!xiY9+7k*7XRi^RY8QFmr#D89ZAQ-2f zw@hwA4Up+}J~FL2ZGE=Y#qQE{QFsUt#6!=pwv1RH-U*8h-w7-K`B$a2jMMZ7xDdgP ziR!)f*b@*wx#6v^Z$PBC=b_!}5{#cR zZ*BT+3+M5~mWHib9^SS#;%-waGNvWXNTjZ2hTdcWg_pqjJ`w9utgNsAQmZ@_;6+aRSeC|Y4JGuelA;`H--cmORSVX!|Y_f)^t6qyRIn~Z@t znle{mPt=m?^RE%Ed!o8^d{RzYekZOFJw*y!E`%q*U)10@M#w_84Ih@e^?V&Tu^m>vAwB+9|K?LBF8s=FH`?I96Vi7@%6 zixVM{xBVW0h1gb8ds&`{lY8){Hrho>Up={q6FJUtRvACntgvt3>*75qq?ZY>!k;9_Y`f20O+ z|M`T=`d6x4pX20)=hper!!BG!p7j>jr6U0?cgIcyc143Bi?J5+iK;I9f>Wym4i;do9cl7_4+nu{ zjDF)&6SHX24}T~MQ)^?BPdS2vcj>zRw(9gT%e86Nek{!YK1}AqoAbJm4 zMZN7E{vq~H_4DICUz>&w#rviqP*5LDiEfRW#+gEAd_YH%evh1>)UrmT?%_F?=?m~amzo0bH zt2yu*3p<6S(y!MG4=PTjcY%OiS^NhOrgNyBq1kzX(y$rtHcUyplgSf{_+uM0(3KCF z*HBWd^ImwVW3HHp=wG+Sfs6_Tkl@J_SAGf%n7;M9Y&WrtfDCHnrjvmS3g7>7Xqswq?*sB)k$Zk`dMff9G8*`v@s1S&jUseog-d zEQR~}yw&3dV(=S=Ok}non5ci=L!Urs{9_wwTPQQF6KfFG%wJppi$}hLWD15@lma>o z+(|~3nzJO)`CG^ce?CcO9cA_#^Fw-{s%q|3HkndRN}e0C4;H~V%0HzSz6qG==;^_p z0WWmq>%V9vBzj^cSdXUjBE8l4yFeCSHo_zCXUQJUpJyNFG92*`x5qsu$(_YTa&>!S z_e+{!Y*5+OZk7kXWZ4KRF(Tz(rT%Wc;1zrV|C+=E@AywP{V`Ic{S9RBJobyv@6QJ( zP*7hyVyfaYxyci+=RlEeu2^y{^snSjGV*S(IYsgvjSw8WnK`X&7 z%ufmubjnVRSvjDi>$YLG1ZMS7Xb1oA$Blp8|5%N%%7LX;IH8EpN3-Km=vJ_UWQu!&geIegoU~ATASYj&L-AEo>uz?=4_3OM<_>tzw5XXEV{I%bgA8^ zlODvefA~-Qxs#`aA|Hf;4yIT-y3$1kFG^A>igD0FSZ%p7=-2XvKb0uaU7yu3DiUFW z5r##75P{|e?OZt+l=PvMy5Rk|-TP;Ub~@$(rejRsV0=@}_@05#qk5Z*NiMd;gRL8A zTp|k>Z@&o0Ew8p69<|{?!0bTv)4g|SSj_z2C=D+GC z{-{9xkV`k{?a?4xW|CQoLHgY$POwdgzT9_ixChhoyW|O zwU9+lYfNA0xeXt7@Vm@^I$jPFoPXEpqevYUlH*+E=d?POjv{8z_0w% z2cKp^S!EmDF2B3&oJE3GEiJ_Cl~CzF1t}94;M;RAn)Zahr$~!}ZZL7N{t=XeVIU|% zrH62(uUFrD80o0jKP(b}9KP@gOf(E2=h20^VQPBTlutEOu8gu-`^#pF9FpuW+qOG| zaT{c@a{D70QIJ=KPq9=bT7U-5_WX&fwP3<$Bl0At6p^Fu+Zgh)Xub1K406|V)Ci|d zrdKY`{g^@Jk^P*$Ia*FnQxh}tHhT0#&y)@`NvSH}MxR3_P(ycG1LZn%-DT5#NcQwB z)_>cvRL|yuZvXhruz6+UU{2{h)YXYw8||I--KJX)cq?|{n>g;d>qlez78J85u^JzQ z*u6j+>_>_Ylvm{^q3~3u!u<%dt7tq>^-dD_C3lCOEc=rOm0j&EY-oLKo_t73vuk8B z)&}E_*Qoq?2amv-+Q9RO;0e8A(W_}NsKDl#j0z^&8W5TJ4Ks(NIja0h{FGJBp)FX- zO^u8YqFNV4rm%)caZDsY(Z?Q69vF!ik%eF9468+*iof^NNdj(h`Gc$SLU zZ*$<@WeR4QdK)&Fh4#V{Uy*b!S7lV6C32U76Ke@3do?6&z5**!I=4)za(btBHC}_m z@Y?2WN8!CFsV1LVqC9qpp65-H+0ySs z)j^?e(K!CM;U$Ey?o6-bEQ&i8#A&zG9b0oHP?x?F<^-u}M9&SDe%HXd5-4KI|r_6K41L?$bns!iB1C37*$E`R0NI$lB=0qh}>pB|7?F@!jJ$X3U34s7mRpR ztc=*@{LPHe#A~hjHPXT zLj>akO1V~Cr+@0sg$DWhJs?jx?a89WBHxgEF56PaeoM-vvJUb6s=X=KVGC^U@6C$E z9|*`YGvGuy@2j_^?0Srs+%qB>Oa8M(MY}RJd7|1M~DZXKyaM!;%T;4b8((D3#$4 zgQZ^*TGDQRhGGc?)5FMhC9x@ZltlO>)0@NnaJqxqXN0JS$c^sL-DSAMDD^kn{H);b z!8of*R~hUIVc*8Rt?l0ervS+zz`>YmROfPR6KT-`aZm%jl7)!eVw&0}#Q>P*So4!D z+SR-Q{#f>wdG8mMUV|oo$UBiI%Y~{6#a|9HD6aMS4pcIZ;MkejbV4}i6wZbMIQLt; z$o-*JET0U4c8En|{-(Ku{AYtpKh7uzJmT|wOoQmFW$aBp*l7p-pNsrdOs0%}E{dQO z7`r*=K0~q0W;>)ML0o{I`sQ=Kho!a0-jMxVwEbGHkGM1H=w$4I7I?8MFsO;d6hmk{ zV|N2;_ZOB}w?HQ?m$&?VEVuo3Z(86XOb9_7w~e0tKo|})^MLyv%%%$lAu(DBDT$NB z!MexAfn*s)o46}2Y6-mC>kPiMLiab%-^%Vp*JXia6bcOx#z3%guAHAs7M>D303Hg% z@0+;SV*ZX}xc4tZ*li4+w01kpy0)7LBn|9`pC(**sPsygAs225nEm?N%4}kR`&f~H zK@wp{!S9ODr#vt-4NT3m>0Nc&4gG|P=X2JB2{37f9u1N5DKO(X?&4JVkul9Je$E7U zR`a=kirDx)-$%cy(}aHHv=LI(L=&0*^QcypHlc(!jX#Gyl=z_{*Dd{6Jg{m91oD0T zVMPhiB(w*X8XK%&nG;3ItcZBcpUGhVBwn}r-sug6q3=p5y}kPra(GelprQ`_F}nhi z4FeJSe?L)4SEOL(_~zg4Hx!j{rt5(3`nKV;k1!p`Ml_&Rc+|Z|+1d5TPn?xSCo<*5$rdw7uH5TiP_EKEeL_jn-shd20P5 z)l=!y)@aA1OKYs{`8P@l>k`srM15&%mwdP_#bv#%)a#+Gh^b?!R6Nb@i!U$k|^$V1d5TewmTxA(Y% zJczO$o9Z^85;lQtT{wFC?IO!sn_%<&B2d7hi+sZr%xL>-<5l$eELt+1$4gl1`@na+ zW3HQyXvFH`@xe9+ScT7dq!np)vMs)<4hMFKonr`N>KX4l2u4s2mVun}G^H4k(!>%E z^W;8H(5l;`FErxXxTWOZTT0W%T&ad|QiJNe^ej(B>eET$C#OU7); zfJ?)loOADQ!%``7sMgSz zIR1BMu1i@HZSfNLlzVjR@5Ir7Kg|zs!TGxZ%iT7=EQZ?5aF_e*j$#C=$=Vi5XX)3w zOn-*}a~mvGFwM)R#%1$CgysUSJ<#1Hr&@s+A-g&vL5Nf&A60vtzNZu5&)dNSZ(;&} zojB2@B#!pg2V{4Q9u$3b#crfPRxMcM=i=dS6W~XXH@!-VCtN{C?%Na|=lI&9EUQMN zYi=QkU&a}|aVEN9oy=VI9P}PcYsNC2C`?LblCL=M!4~AGUh%?){W5#jD)jG$z!)qkY5+vB78S zSxqELml#2t?5g*=NJ$xH8J@9>kE5%yh%?_cP}NkdZE@2!rf}=3_nR_W_iJTIWr0^l zpQumRzOIR7x{&2urN>wopS{?SD(iNS>w=LpZQEqt+M&~P(FP0hk(R>svk?oVUTJt_ znxn>Xd&y0`bv#3yB_&(y8VM#|(9F9zP#j8OWo@YYm_^OSb6n_&j=21FnOo7@Be!K& z^F`OKAW+oIEz{-uk>-)TRHm& zyer3xLHl)*PPnX_ozPN9l0PaF_|jLluTtz{?K>qX7z|RCYXU=t_s2PoWtSQ8-EJJm zq3y0n^lbue{SybsYew1=Ekfu&R7)VadodZrmM06i`19 zcE%>FAu}nT9#`dUV9kabQRZcHXy*dCTFi(qx3=@RS5Pq?q(5Imd~*9pod*@4AU3b(x1T`Onk{tnb(n9d!6B#ZHT$$H(m z;bru}e}+MvZc#(Lm4p}=z}=FU0EcESUrQm^r__46Ps=NyS+8dWZtuM6q8dNpKX1Ra z)wJc_>@K-xJCvQKPhJi;_GCVUcp;}g57Fmd<4BNbeJM;!|x~=*5UE2 z_iQ(}&P&~La|u42)cv@VeeF668lk}R(&t(FoXFrn&ho3A0gGbNs_vOVc+M70gPUXy2LSvSuoew_{WM+&gMudEHW zDW6p!&n%~9pDuWSCa7xyYRA8<9*z7wCIZux8HKNStn*(c&vIAuzUVnB-?)GU1Zxz4 z4zQ|I??y<@PjNRc!QxotB_?p_1nvnEBWMy9G>)oC?^6)o0nYSgf9H#qpo96yADG(ikOt6V1=3fv4ci%(^X&2 zTqxP7ez*7ZNO21*e0yp8!bm4JN>0Brye1M)vIkUsc54tlX1I^c;A!fwmK84znxv(w zA^6sf`&E2p_w(N4#TK*W#LCT2oX~SVq#2xcB*}(yh3GciZ@(`h${GVPOVht#O&lS1 z%FM3rf7P*`r3_X!bG>et_u9h3_JF3;N-(v(_En3&$ybp5PKcMVtADeDrP%(^v zAwYTg5O66Ju$w~~VHNGHPjz?Qt#YDn)WV4dRtIgWLQSvQJkSrNS*v{pD-%<>J971V zc(z^YFnm!Len?8T*#%dGa$$fouKXxGtgc|pbQ*g-@q6dye**(3Z1L2>FGXD+^7#!PnpS)3e`FIp88 z6^FwRW4*`$LyuB{VH#NPgJq%{b}I3B&?V!H7`DF)+&R=0uq`for#5DzZlu9!dvWC! zr|fBtB>U3V_`K87FQi*SkCpr&&Knr^8CA>JNycy5jG>Ur5}JPtf=(Rqbda#r8{FAR z+yO3cbgSJz<8UBM*l0!J$Hwr*H!?)jOqnsL<`(}^A(vZSB;f7U`|5-KbLSG0_gO;A zod+i3gEsP-s|`3kTBCnJ@ccVFi;aq9e>vgOTh4pU+w^H;K$u3dZUiOZapV2IFydl) zQuin6Ugg3k6y!U<121jRanyn8L&js!E*`7oOe1FUc1;G2yXqXjy@d7UB!zT>cL8b9 z4M&@;SPtEA-Sgxkw9sHGj*xv%BV^ap!3ya2+jv08+^~qW;LQSpKMmlh4p`A&S_lh4 zv2z?4y$Y)6PQ6>YY6_Z~1y4BTSiT$+EvrYq(25&s>XcI$l9qLv{)qHYS)X?zeJnMSKwJlZ@!;xq0At-k#U;MzOs0UJ?X_XfaTYuwo%%z#h z$F`7ea-yomYCAW`g_t!tS%kq?x?ENt&~T!qC@N$0!R=3q7_68o7wF}yTM z|7m%S0m=5KcOBnjH_*=KOdF>At<3(2qhOYSDL|-J{T?Y6%lfvX<@Sho^DTS!bMpeY zgv|idWU2i{SOB|b2}JvR0IyLbqJ10+-&l4Mr_Gw{hCZ^-O+tCBvOpImr~bT3^WuD8 zmDY)xbIei|O^x4(+EY7^WvScK!2TwC3PR|l*F_6UnEtAe$&uy_%HtM34@1WgKISI- zcE9E^KKJ6aN5J=mJvGO!SKW&22k&!#J5a?altZOrlivx}h)>&v&=FAwqUu~xHEG37o>$u==iX#h^I+b%>w%H-9Nb<=U&3OH;pTU6AIIXO01fWg4df+-{qhPptrLl*?%nkDbnt+*3e`NTYcR&mJz}Fij{hK&f`=qv^Nos zoodpWW?$xEEDA}O^>L23S^wqvwWbSqhN)(X5e@F%Y~!i1wf73tO_=izakpJ3Zz9(e zC$GGb6%MeJ512ZGOKzYFI7ro*XMmC$NhCqi^BcZDt40Re5Qh{R7pDK9J?2}T*f6(> z0F=G@++ccM=x%5o{(8JeFcq4`Xrzy%9w9$&y|0JtdaE#)RC1stTFa+j@bwqb*2ABh zXR%Kd!1D47z~DL8AJw}p<_10KrY@eyc&>K4MyP(ds3g+!t{JPeL^ETUigjE@i9|7s0*X-OJkh?Zc?`OJe*reSkp?5Ev?n?0rB63A&@LPJuSVs&l#0 zQ>NeC9P%Y}-6Q!)o@uDvwc7kOZ*33qg+#_WXX}0Vimt|2D8M`oO{S5ZJ5nz}1*UX; zx9IY@X*a#NnMP#s7fZ@K+Mo+k#ygc=+FhETIw4_K9FOXE%fUaC&tFnD^6VTsQ-(fm zIZRYQdr#?>;04lf-Nkcny-_;1oFnp6OcLR@H;e*yo~z8}JQr*bggeY0tF>*^a}Q-M zUNnnzD^P*7NQ~#mRmYhcL|%=T-q=~Q37s9^&Nv&cJ7WgkJfx@!p0ZI(&2*+!!mtVT zqi&Fq>D$EP5@~85^=Y>9!lVoDR~;i#Dnz3B%`8mrWQVFprLRcRz=w!Af%c=g@1^XM z-2|PrvbW^~Z`yk8mTN@aZpYo-k;PvjsnO0cVL)%JqMURt?OM6Z;!~QubjUI5wVnt# z7?qyF3>`gBqESmj3qMDl)?o@Ks$cIPK&oYKWfX>~%P??q98Z*exbcDfg|BV4jEUKs zKj;pyY41*&+ngq8YWar0V9kN{S8<7+zXv;j2}Hqt(q>=)FQvbZB_~mPV|n0p?9`HP zH39iObtK%++c3w{rO#yQE$hKRx@5S~7Jgjdp2>GEjtQume0nF|IqSMY8mk^avA zU1ZeiX4qzFpp`4$!x_&eqJ&MPzhgw-6dO|*LOaCch2R8PB$*Sow{}}6M+fBIjg_~((C7}`hp%A8pU4~Dx2>+G09)r^^3HPIopq= zVniFgZ;>; z5sBLI8KMhPC=E!UYAp#*C0Am*6Q^fmrLu-xKPhNWn~c16G+&oL7^}~d)7Dk=lxwo4 zav?pm$))Um%N$-jU;FmhNBV6OqpqV^UBZ3+CZ{|>O6;o}sH)h6m0Qcc0EkNo_C#^B zG7GCIMsKgZyRoeLtjyu#Fo?JYy1h7{`l2@34R_K?iFQ7A2E8{oYEMM!CC|SMI=E_) z6~1VvVdKrnU5GAYxqPgM2|81MI?X`?%Q)+r@#0ferb{buRRgkvdNyJmq#%A;Aac^! z5LpMD!I8l6=<(YfQgs7@cQQtR-}Y#E+#$@b(@w5lbnYwnPTuXw%=8rCE>yj?p@^~| zl4$sT<1EXYPgEX+!Z34!urSXa$(nPQsDKu@SUVFY$*y9GopTPB|PFMmNwcX^i2L)J-2HbfT;Geqf7r z2rE9sK4A&PiJEL12CrXL6;Z0=`+L$5SG#@*Ph}%MY;A&j_vBmGBmXZ~_9g1=&uKmC zy_QhxS0Eoq9v<6QxdepH;sG6-l6y0@;-8Kb{qF(x{prOBNw^JnPkr^~nR+mH2R4Hf z@M8zF;YFiBQ3VJG2uwyy{Ed2PAk3IG5qwnws+Btt(H4Z-3%Kg}Sps;rf9v=Q7GNz= zzZt7cBzM8U+j`unZW@S_u60FOs^LbCe&A~GLRkHsNs)zD;Q66-txLhN$55O43nEm4 zIY~SWV^u_6&a2E*uq{V5w94@L*EENa++}!7Hr3z^z0Eg9q5_@B;wwteSLLLdOrNv^ z^Dj;1fUsD>#+>=jR--@pw>ZD;Z5s|XOw1S+p&hF3E;}Q;r>5XS zwu6b}^kd*+8Lk{E-p*N(S5PQ^;!=lCUcObW{*|DKT0Uw*oCya!bC4|dQ0D>b= zdZA2Ji*|X55GN3Jx2nc(GPV9Ve9C1Yy3sgc=IwT|In4VD)>=Kg{VJL~s8`wOO3m95zMO4X#IHO=OGDa3! z5;u=7&8G)_T81ux z#aL{(drhc1wjif3$gkV9qg+#B$FqpN$rezHrR)rLGK(_aZPurC_)*#*^>;$pX3owI zce_ORGM~FqfoHht-CoQ}V8*nG2_+Ql{kS`53lex{h;4CGJ*<94dpRIpgofrk{`_m0 zn`8gEO*o^e!kC?q!?#}1-P!i@1mSvZ`QyCV?DJl=G>kSgJWX4NQQbT+k>VJv(4fQ0 zz4Q;)!aVjD54E)VYD>LBG5MqqrS4jSu07#}YB3k}BsRqH)0~nMR#Kbvb`b0#Z zh(TvNbhj{JtYA*>d=eLR!yQu26xa8S6zP~v*jXyM+8VoNoCvLujO>YxCoq`{C0H6S z6s>F1PU&VbkwuwPs9Zh28R1$l`|V+U)#-hX2TwlA?Hj_laRKFH-7#p7pUP6ImGJ8v z#Sr7K%aZfAnkw4gXzV9cMop|^Sm-Q}9jv_We{h;9aIG(*7mQU++fqQGX4AB(j2wp| zFWC(TWKFbXuIFd;cmXvlm$gjjxd6?~I)D*xMTZ8(y3e#fL(YJ77qeze*Z}wZA>^+p z0A8n>mP!T3Eh;864BNr=cN)sWp1f=e=!29=&I=bsIn!p8#)?5z_)E~D zUg0OxQS8k>Gukk7xU8H55CJKo{{~yLe>!$5P%FDRUwzZm(hzXMGLG7CdNgnU=X(4P zA(O?cbv~yM@?tAB7RJ*3LL;aJtFmK|`s+RdZB7M+=F;y~vB4Xnx{c?(i;eAec3b=7 z`{25US_)cV=BMaG_C)OtBprdgT>*|V8EiiZQMsQGcu;O4L=RO2J)TXT6hyQwi3c$I}oB&}n6b z7kzIwjMzDmMYlYbk6|v@b>2~mbtX4n^)Gp%K=zvn8>MghG3NIUsyrJTyX6NL`vlGz zT(xo7tM-|1Elg)Mf&u%9s+%?)2V3D{@m+9F^fpQKKO>A zIW%f~xK>yO8*laqi*%Nkw=jPP2^eX|SzW5D_~ONcBSa>iL!b{#b)|Is1V#%gR?ntG$oiWbNh8Ap*(4m?BfPdS=^w zJ^T_MM%Qvp87?2HNkuFDy4EfR(tt?oeEag3w{LAovA=y|Q`KoRUG+*=pfgB}2Ny>b zu8u*g=CbJv1?K;%gz6YlRg#{uGO|1Xhim?XW7C@e|MY(Ai8wZnwP|WIDi>3|*@zf( zrp+S@iXdeD<}-@bo_w6kb8OrKyxZ+5tnJ@`ecusGpHaL9(3Mi!beSwEXH&EKhqU!s z@wS;GR~ZVhiE&E~lkjP*H4sGKjA+XoAiIEOawbWx@?J;UUnvXl3M-+F`7jVcR53KJ zhiOUO(i!P?q+$;N?}M{#C7-{uac4+mp6~aW(`lt>d$R`N99gTe&Du0sp2a(pAu)Eb z7h@|Av@prf_u=+(+z6kkGri7RF7c>bqt*;CyVmkgI&OWL?JR#>wzEbgtv3+Fy{o1X zPbzWz9^ydcYOy1i`N>Rs6KLcLnPU1W2jP4&t^LIn`_d5>qGe;GNCYp@Uy8QHsKfH) zS9_LOv;*>1TjTAvtvB6Hq5Cn^4>dh(XZeFGZG$w0erFi2VFcrd=qj}6k^qDe{=V5p z27`kx1g@5%`t8yv3ANIaL`kjv1Q4$GDH6Qwa>uoImp#aq2VM4hmNY87$z&*R0dREl zwxxO!)@19B%-8P$2$BpoJu{p} z#r#kS{ABS0UCl9e|fqo6DxN8QWmT$o5Qjo}jebCNTv#kt&s?X817y$D^$5vgfECjX(C}b)XbVYZ1gri zo%`7%Pu94%VX4h)v_R82?3pFH;ukG4xe)$#g{8r~c6(12^p!9UrEf{D{AI!>sB_xo zu(_~4D{1EIh}K@*%9jep_DDn0-3gyQ4t$;IrIj``z@DGED0hyf-Zox3=v`lIf+Qf{@MHd^*qhZvJ^ zu!IW^@9;$-Iek18ls(x`s^j&uQ_Q+TLmM^9dlvDW#UzxoID~1Y4+*=g6KKhalh2!- z>rQQxhtbMdJ2oT(yY=nk2HB)&xx~?y24ghuGtnw^7+%=sjGaTU3ajhsyDAV-n|$iH z_SLbSeq;qwrNh%cbjD932haJy(#{jeRN1cMt?zk{zvt-S+a6py&orhEKykq};}{CA zGz|JSuE^+q(W#Ml;7tav>_t4Mo+)4`*wURcybK-{$_32TdEPd_h>J}KuP@J7iL18r zFx0phZYaoa+YzjSe_X^}G7QqGZ7I;$mQf<3$0w$KYQwgml?h+c+aflfTQ!JLbDjEI zE_Jlt>~ca$=2#6vcUWRe#vv^Uw+sa21^jMJDpEx~NZwS}=nVMoT8Yx=I)iE>CQ6oJ zX0-kXWylu_+klqA5AVgTbj3-9l`m*-5iqz(3CGD_wOUP$>{9N?#@`ny=v{JG=B30c zF5PQ$49srrN%P=1FkQ{47XD1b&TVO0_9_%9Q?(lc$^+N#l>LM=rgS3KA273Dw4#fJZg3d{iXT^g|TCha8k;ASSF>?f{JEk9ABVUTy;=@^Ag(|YL{yoB19ZAy41z)*b#@w-E%?XT zU9%zVVP#^{QaEDR6?~lV5yI$(53I{ttqD?^9c|+GT(wm7voa=)91Hd)Bw#j@}@XTI=& z2zAHWr;XW2lMdA>C(;R|>M_+X)4aa-cC9ZDF&0XaYJVG#%??6WhO*)bIf$eI0qC_` znJj~7xf9W0fk!EoV6qaV&9mB0EXo71*Wa8z&NuqDF{tThs;$Pp>#5flf%EXF+V%wr ziTF!F9`}tVo#&<2%KS(`(rIkIT@D-(SDJO07^g&sY#?SX(F~U1#@QdSERuE?gF@37&jE+2p7rytK0~M8(0D&5w z&Yjel%4(}($tmGy-Zv^Osu^q0>`QEInoACwf08xib#M6nKo`w);ic6JRinARYMHqX z)nYRYCob(!`c8 zzFcw9p;&K`rJIM9<=tKr4CW3ITPu{(R$Q<7TE#g8pdB26OcW^Al&3b*2$@&|oe5?= zZCVp9S^YW{*C#hA;>irpZ;uz*Ivu!;D7waDDfHB76N!?^N2hxOWIW8DHvs_z8PRdpKuz6!U9zU4DgBsH>CihAi9e7VD`k9(_7K@@j^?x>aP6Esk- zQk3acE{WX9j9;V?H=!i85}(tCAvR`lf-I`-99SgBSZmZA-e2O9bLD$LOOWkHYp3L2 zChuVBIOoW=7OjxhZGWO*tZ(i`v7k5`pzSsj?3V5IrEnEVXgyK%LdhGx5=(qguCeuC zh_9g!)*)a`Y$=_2C*Z+2pi6DE$BH` zF(J}-B;Osff(=;SVm@=2jdrgcs~1TZ-chdjXWz|q3*+bKcF}va7?h%A1;%kCuL(F0 z-=g{&t`c>OT#R!)-K?BJx_gMX#edujXW}f4_ok9PEvCdxy~dHIP{@7HNc&;GcGxFst@M;WdH?6;I!Yo* zyTxdcDx|i;{I-;{F(K_313_mevaXWW>kwM{jVn7|O>Dz~dCz6x;q)TH`kAGsZQ6Ct zQ4K{T|D-WwP98Ej#}gxh79Hmq2gierL4}XQ(ve`x0)!$zucEQ$b5FD7-wb0{H-JeP$d8oynX{0w+>W3Xzn8Mk z;y-`_6hv;qv)?9N? zq#Ir-*06M^NK@1psip}mqIQI04lL&i%3B3}AIwIRBi?_rOfACFdb}JicX>RGX2-SOP z$|Fq{aCP8CLnD?a{Cu(9M_3t@m4s9%xfA6cD_aSSw+ts8x3&&?vM)YA$ytVBSjJCB zvLA-hw@{2PluK+e_)+zrb)QDM`mSG`9`4Gj-iDN{E6#1sCM|nmB=GAesIX_kQXG1* z+J(2b??CJ?h}g}!a~M@(B?u^d-;3sft5P-DNyfTUjwXmI`}f+0RTVqJbcwcMbd>d7 z36ssy+}~W}S=EO4T|<}hiK84CKHm{cx=uX*GH=#>crQ*PDIL{bG?(YrAKcK=;4+?- zbm1#Qx&$j6Wwh;aTn0D?dlG23&3cR^p<#yY=^qir{gycOVZxeJ9E@7CLC2;y z`nV}ohCky9EnxO>{G`ZZ%GW$q71PX(aQpS+7u@?Ydw{(ijTNf`uczBlE0vg6?P2!* zag%KB&-7~VE3JHM0bwqN($$8E@|&1@2N~!8164q(zg3eIjgvT}#H!AVPE*+q>Ni){ z*^pWy2n})zLaL6~ADF|p-p(n_0i*^R{gK=b2vz>x1)lt~oMfA&O+n(o0#G$37sa|V z2yyE%=cuq=Fn!R`otOWg8GrlDxwqYSz<+*g+O?NJ0Eyvc4<)0aA&#sLZNS)gf3!iA zF}HBJ*|FKT9BDPaqA9)7XJob)SwY|IjC_?~glkRS*1A_WX7FVURE2Ir18$77*&;g) zy0aN0%L(~fFZ(yWbcZCuBc)vIkaX8WIjP2dD`aq~JAKzsFqw84Et zi3qCW>?@ocyvBB1mENeyo_(sV#j*(_L$_#B-)16ZSwVcb+~*^!Yl@J{O~P8d~WKS7xa=G*p8k%&sA`c^$h5eCgnxj{!6x zhNa@eYZV)rHSKT4mjnZJoP8dX$+}0My!#~foiyOIjUDuSzt*oQJ+qlUFZFpyUL3a1 z#MC->*K(B`h@)F=W)`Qi3!Fm+Iq7q6-^SOw(>q{X;GPgVZX}mI>#CWb{odSL@925w zYpoF;oj000d`zmsnAcn~6p0SqB^nbBFZyLGCMelf9Y-pItH?l=UU-&d3ft&himg?B#QwqDBU~nAJ4NTbPa!dPI!`>63zabyyh`W| zC*ymu3^Z7wX@M2o2aSI#mF8EKlnF=EGc;qoGOb!zagj;wBBQ)>Yl@N8nMC;1M4ex9 zgB`x0-E`te4>Vvq&}y9&OU2$rlQLKh|7dnM(Y|97V8>|}0)$|lL~?&J+*saJG85T$oIo+e(rE~d@wZ{2TwFHa zNhGU8^`M4j2dqg)AAscdvZtQkOfzKr4qp}J>lPX^&&QX_py3H$-0U4V*fx3Y+@M}{ zU2wLqF7`zh?Q!|3Coc6Rd-O@M7CV=~q}-h&S8jFX6{xXltJFxDjge1A6~I6>>Tiwu z`uOW`$BWs6j*c6X!z7Gbw48=-TLfvtqHX4_yV=fyr_?rMOzxgLJ1%)!tF{W;i=#$c zo5WD*dt{hoPd*zm87!Awzy!If%P3V-9J;h-Mc3=!4M6>iy;ZtL6d!+pqej}TCsPaC z16RJRd$O5%r?W#M*xP{_ZRugMe#xvQ+S3>%B~B@##$ptWn$ic!TY>U258Ot>%|F8e#bhy@eEyuD+_C#> zA0NEw9?%A`#*KAk0dUo6g-I(rtHP+s@f6x^qVU{HrDs=m9Cv1m?QN8vN}4&o=p9YF zxFVc)3RPN945W6eP7@}`4o}yw2DPLn^Cf$b|UFGhte|64jmzWu| z1DC&Ha~L3iz5e*d=M(yRX;9hY&zkd{e{0t5(6iLka&_Cpo!dwfz|Otg;^i|xnZvGWWJXxOe%tI0nCdYKWWCi=D+no#BHxOT`L(Or zcCFSc1GS{y)6q5KZ@&pMK0o-An-$OX3DU#V^j28q4I>ew^g%m`}W-{6-3o2?Z6&33&4X`ecoSiY_S8`bB2kI94yD+jY> zGii5WdnF^gdW`Ie=eTqqZz{CUugYZ{<6$b5Gs-)*D4)FI=Ni_wXsQz;ea35k@lAAugQ;`1 z3nw5uAAi?nXJn3=o7}DXQbrQvqA!ZYuy0Y7je_l#Sjauc$-dJ(TRYFY$hRbaMU@~n z=lPi}IJ6Uz`Y;%$dMhlKm#=jdonSqU2z#o)HzN#7OgB}4&T}p#*2h;<-4M?{j7b)n zsa(It{nUif!`74~-*>&*LxW{>6`S-OY{dQpPH4z>(m<74d~>Xt1K`yqwV#i*6c5Fw zhr9LeQ*~W@TIQI8DHFjB5HDh7>bkn3gREFC^ey&kJwY2SBDPvIr+WfVT~pgzLG?58 zf%%++ROAfOArBo)`^$gqdHa>FluLV00C1*LM8ZQq;jMtYi&)!SKxN8Es!lxH-O&-v z?J$|}Dm2yS8aDeNRZi;3TA$PW(fqv^=8SrnGxk`i6|tA88K@nOt#@ zD!m}zZ!wo!@F16Wg0`(HppN&&StC}6#dKZvny$+)Pz_PZ$}PSl`m2WJ_Pokp``0pe zo_P_?N-HvL)uwAqlb|(TUb~{guHNJR5UzXN43)^>=NqfXGfqdzvL*guvS(fl6q7WG zszuE8lX4Wlc=-%Y$x!$ouei|CD_b7s+MprSS)qy2auD)M7kH*D8B-I2@x1}ut6}sK~^AdAId^>F?-4pHtU5W{p}=W zAGgMi!&A}!f`bnkHN>PwC|-;bxk_SI)v^|`Etpm#91*;N^dqg3lMY^m$suYNs{!xG zC#R0<>SBfmlSK$vW5$I~dr0yhfIW=G-o5Y1Fitkz zTCxoDLmJ|~RG@Gwn2DJa&rux#7yXm!9n@mhJ6}H*S3RVXFsIq`>+>srOVZ6YXP5L6 z_SB`mYGuY&mRp%UUD;z#Wv{koGt=1G`HDxpuEI)-(>G?oDwhTw?6wnxW|XnFJ0{=Lu;iL?JkM9T&b zbo9+I*Y_JD>&CNjY<6L`Gczz95*$ToYTQTt7BKn~8scxDI2I=0=Jp0~?5H+|UDcu2 zba69WmF*Vo%q2%9I4i+z^@f>P<*uH5lLK56u>+xJ7Aq!2&oeq&3AzFMKl%F&Cn`tw zju|fG7ChYlxqp7?E!S*)>qY&azi#-K-zq+Gx7xi!#qBh>Gll2)s43N+KL`g7fR0;l zzZqZ;a@wy6&W!@`rAz^2#+`R|#CC4A!BGvWy``FqESCjdf{pV>aepGg>-gFkMw zoI7_9ihiROQ{foS8XPfN$QWYyJN%4cjrMWr*Uq@1AY&qcSRJTQPsw4g@s zwU@-eMrR zd{ONs05UeR-JP#KzVPr`ri^azt>xr$dJ#N#{yeX{c1?mss$R1E( zDvo*AVKj$`bs&VQ`@B<7XJ~p;_7o_t=}I|6cp)h@qSCU$Jy^YRQ(eM2L(()Lx|PbM z$t}9s=8S1f3G}?;`Ruc#?butFtfmF7{SVPPgQjG26|HUIyqxt*_p|#1Rh<=z z`QF7{m%fd!LNKn`XBja10u1}V;KXyf-*M%@O^bABZE-JGMlt$SEz=FX+>-+qX+sPobiTtE2M;LV(85+l+s*n;Va*GA8OLfGMxG04`~>u z?Ykf~bev&;zIMPs>J;#KLo}8qISeqaj`wmiqbQA$lbKe*M6+LK?5Dc2Dj#a{9nEoOW3$K2%gj4DbJR(}5yz`(v)HkP zI^I6w&e_PdNt8gr(P^!GAr;0vYf4Sm%mj8=74F(*DYdERS=*T1FPa{ic_;c*l@Z>H zc41wJao{F9=Rh2bYfV_zLRBdiR{az>7m$TAa@RQC73*~89oa$^cE9Ed>;38M>A3im!o8~| zy?WJHIkkvxv3fPL->KmG={)zmLhnn zRaGsg>^EL zqVCBYhX7pChh2Rx!{4dz1{ni}KAttWjFW^yFx!W7_pQp`zgnqVi82KT&+a%iVqeE* zjy*AR^vRjSj)Tr=aXmGMZa5N#sl3~yn6x4xcS=m$%tU6N8GPAh0FY2}TQ#n-w$LF* zk+Lm`Ot+PgHfu1)9N%_hnsbP$pCJ2ae~jN&GOh~EH3QG6i1|hqc?6{GauYT!-z=FBhdEx6EsmJb1E-T!(ssY41 zx43uKr-oFtZN)7O+J6s!`&ppi1>ZG2F05&pQkFKp6AJhwE2i zu1NB>Dx=v;nJPuB(o7>A4M^3S^U)XD`_Osj#pn+cbQx7CvGlRsoTKuqQGcaU$gKfR zFYxY+!UGF1EF-JC)-M~$rJAU~r99h`HPdzB8|Vn`y71E6-DFJjJa<9Q`ut@e_pmit zaCqVJnV%ShuIXZBPLOZWMjbP+$SepBIj-yK3kGg~&@Kggr<|RJNeO0!4XRXC3-Ud$ z3pxP9=$3_6vy`*1+zy<3>cw#P4w!L3d_9&$H!;3tS4I%K@u61dZe6R4i6XcFzO&GU zYfa4X@*BQk8wI`BR*mpe^Sn)kzi@=zHDb0?Q}K!BFh_qrIO5QVZl#h`Cp|0F)q&WI z4;Gy#d(D)r7fidXSNo+_Lxehq`F%yL4uepOu52VQzNrcdK;5PP~Ve|&Zxbc9R2 zV22SvO$mh6w$yCC_NbIadOH*N&nF1XUNU zjC6K`33();P%88-?Yj6Hlx)HYb1oM*CPR$+!oc)5zJ1`92TkC*DQIP7ExZm=9LXIS zyc*l-kOY&FIGy#D1F00+nRb9`M_795#uCCR^&=c%Y>hVC z?baVotj%$R?8ztRmp-DrH@pGIJ}MKjA&i~bfm5;IDqFUKk`7=bcVv8XAA{VC1%1|d zG^`u8<)Q~Z%pWVGGshpCIeuRD_!F~7pOiV~Bt7SF6=b|i47fC)1LL`w68{`|&B^JjRL}V*>mb8|=v33JIbEu{trm{r*H2|sjpPUw zKT7g-8_;(P+#$JROW}bvZvQlO=JvoXm1y~QzxF(9y}O+*IQ)d*$o;}iFRQYl2Ah?> zp}nS96$9?0l#%IRj2T{hN9Vv4K1>S*?GG1e6E>cRa-{@^$K6@tWvag-lGkyQ-`nz9!C8i6)1!L}e+F&ekf>ilWK5Uc9 zH3y2;g2It`u&Pp@Z;VqzO;|B9dQs;oXAG$8eSf@0#60+8`!=ssvPtf1igCM9Lfd`O zczIVRuVgqj<4ik9M#uhu3w9lsDusn7HWgNHRO%kgfGPuYcVtdDq~pXBI*vOoIQqow zQKtlR4kr?#r$icTX3yIz?}s~gpdZ6MZ613&0btMXGxB_eF;3KU$xu?RVHd&yGgbEt zh&>N&mAnj<&!A1pxyQB1ApNpbTbJ6#D4vsnTiE$~Z}J{^s=n0q7o#+G)9AY7b#DLA zE&`6-mtQpa^94y)sYEPs>>U-VJs4gg6)8-DX~WdH-J<^vE_`smPZm_Ri|vc{4{wpR z-Fg0bg}!I~y5HkY0~NeIbzhi-7W*FOw1g_=?*m1YotC@*5nFjxcKISsUe{(7#&uaZ z+A&GtE5#zU)KEE^4LxU{>vJE#`TOEVczcsf7|#ZT#QKaiG@S3i`T1#P=*Fz&!reDI z2@@B{u=F&nXAPtqFIx))s`H}PaGA6tSKXIiFmU|>PBBKaM~6(hGgPvsFm;k38BQF( zx4vQH8aYINYjDxS`+a)Y^*fF&q_`fmAteJ?%ebX~(bpVK{&`ff*`%K9VA^Hp^xtwH ztDm3=6~GAcP;H4;rCmW{8;di9*7v#b)n-5*Rj4&vzrOQ%uLo2$BUw#JeD`rDWKMW>=e$>`jvjI)XkYr3S{w~GrnHMYdQ?C*`p&C&b#q(kZr2OJ;we@*5_ej@v2IKZ_;A`|Xn)3S9<$T$c zOx&|431*F!pwCZAA!LKlRZ?rxRgSJSG~MT40r7Tai@DGnkE&7*V~@ORWPg|RK8PIY z0`P4iCVOqUKQ?^(0!xQnqxYn=#?cvnU1rsRPl)!v9I&59Q^4WNn7PT9U`cz zG_=!kM2MgH_#*8Xz6qMjoBXncU6;K*Q84y>7Lp3d*7U<+ypv2wQF=0InCdy}++8={ z8ydC(O}y?Z-Tbj#H0lgaT>d!Pmm@qNLmM`xj60Z!v#+VA6{bAIv9c5Rkb2@gj!y+l zF)m^N==ZS^r`<+%wT=!fo=$uirLC$`s*P`#B9ZsFattssx@t zmu8v239Yc`rTfk8IOCYY%Jux4wRslmwcc?w2N0&nRR!O{SV1bacGE;vjhv%2G~w>t zP~Te9ySAUajDhYr>9C%&&g?nwvhFi4(lh6zbm#30G(uAF1hIYPYZIEinNLKS5KRB> zSL8+?)2RXD8PO^gxvg|JCvIwGAXS7LPjS~JGdOgviX#pnOlzufEtV7YUg&Vc>eAZh zC;LW6bFKU0SE-)aytlaXvg3?P0RrRPH>{E9M|QTt0>GdURaib zH=$AkcikM(EuTpV?SC8XFl0|W2ZDg&OD>$UheLQ22Ud!d*a0j)+1okyaK)N;UVPT} z!E#NUlpcQcx0X8rC7gTru&?7%V{v3~5hnLLw%p5V0szeJ>Nw_fJ|n=>W;1#wiArm- zRdE}Plc`dy&+leFLE4KAn?@uPh8vzJJ^2D;BA#i$2^G}2b{9EIy7PjQVft)L+FxS! zv`aA?K*_jv9)ZCyjvH4W1Bzvu(Il+Zdu~(8{o3@MaE$w9svInA%$RuNck|W&Vx={o-u#n=ksb{kts)dFMh`3ZoVGa< zR3d}faJGd8E5&1Bl%Y<$64=iMN#kGFuAY0uSMKDV8z8s)o(N5)t*`sat4fdk$N+Z& znQS5W@y}nZ$Y=$p(+il$hhW_J#5XXj*oViEa5HF9bV*Tef0j~{2h5R^Ph;bLsMB4fJp1X)C z*N(S7F!_09A6`T4s49M%+{an7t3AwuDFcXo&@5n(U;69DB-M0YdPVGvU^+i-X2;pb zTcHN+CZN%_=^=Gxio4Fo59)a6o>LRsko!bCmHf(%pT0#k>)l1)8Ccq@io=$9O&JeD zbRWB?b-emGawPhV7%CpAjUWa$2zDES8_CEjw~Q64k<8Sv+^l%D?rm~}}@smYW zcY1Z5W0One`O^q@wOdd(*(Y{ZYwGth2_A2&aL|4E73_pS;4Z||rgxuz5_$PdSXO>y zs_qLl8@0n{RJ@?<_o=%&s_Krq_M6tk3Ees^hiF0^So{bM4>)Tn^pa4dlBt>~y^uN( z{cMkS4^z=lKAyMDvyHLy$dkgZ4EMVyaZb7?G~3<78cx85D8JH}il*Mw9GqXB-UBNd zg2y{*acjRR46Azg2d?}5qNdMfbo)HG8)woDpy`E`o4@k2oxYhqIO1FH1DnatU@-2P zUbT}<(#NgO1o98xRantvFsdnbn~k}Lep`;)ZI9K4JKo`wyJJjPy~F#>oNl5r{!UHc z^KouDc3yh5J@bh%G$faN)brP*58u?xq6Kw8)K@nBK1=+7|fU*7d}bHi7809 zm~U`}$I#6S8_^ohK<7noAf0iFn%I_upgJzSB-gu^tN)F5ZRU;bv|LqTRM`Ly$LN7p zl~Kc|k}IJM2l9i<7EizQnyJy~7}yDh9p{`|=zWHD5ylo|uV~0!;nTH|DG~<0OWDq{?lWtah^z14ae5r87yhq)(l~2sD97V$Y?s`3%O+rr(N+5R~%z_o?v5h z2}cpg0mM;eJ4*wiSE*LbC51_4an~^i4X@eg#>-IMWVJFUjw0|dTIacVyQ>T)sA}J7 zxl}6c+}?T6G%f(;SP)G9of>h^_H@5EUB{%qR>@qg`dA|c#K#vFA8kuiJ}(i?q-+D4|*x{V}73aK~m_6mJK8`0-tr zo|OOXlUAleO=3v9s+6+o`z9_@i!JkN^E>&)vD!V4-vkAHxCPLwzC=8Xa)RtpZk(#4 z&3iC{xs8Qnr@*u(%>vM!XI*Tmt82kTsv#lRXjP~xA2xs34q*D5v`d7p zJx?^q`86+uL;aX?$3UthPjUU4aQmQZE8_lOh)(*KcO^`D(9=$0`#MD)P2-|h?pBnr z=hc^jSF$m#Jh;NONg047+2n6AXPy8hN|^LMmiP<3j~|o3PRfTmnb8b#4wlzET;AHR zD3<1u@Sxrcm=%VPnX3;w9#RS9lx^R2?v>Fe58W~def!aPMHm+jb17I=USuCAR>^Ae z;S~2M+neI14H08I*t-_r&W>a^Pr!@xPo6wca^BIkSzE$B%E~{%WVTmKb+5U|i&ii(DjGz4z(o?C<;c>UEzv zQ#7(b!^9cQoH?`i+G~CF{oc1>pO>!myXKAT`1yO4vU{}%aS#+Pj{jMtt$5c|C)z(b zOWeP5T}}+Ul!;+i3+VcC(|h&O(33inK^s=r!!j6zLPM>>-EPb{Vf=bB)1$3*x8$6G z#AbAV?3YwsZYlxYAui0Ad*<7m(iUlRq|qea_LfLjv&r2Cc8%F^Px`yG2wSpfeW7&A z2&#jt(QJfnGdD`NAlfN{uT*Xu@zddL1DpQ->n~q(*_MC%G7a~arhu2ZmV%n-hspMD zyfijdhWOY!0DhJVV|B4|`~Z}xZFr)G%*$>8D5(a=wJ(TxnJn+1_iLr!?CCo=we=(0 z+S0`nO-DR*|1Bas=Tk{nouQRuG~=pE6(}2w8l8eCw=FuI&!1gv+XIED$1Bz$1Xtk6 z*D0g#r$gbku~HB(-?>ec-}l`6^RQ)O3Kt z;%%0Y-D?&KN(V8sQ?LdUjn|)Pf9F-wQE@{QrjzlZXC4+%Kwo~F5{{{)-U*tmN`#ie z?u-5ZlRKU?ER%#aQ2qke`JSt-99y!$3`%Ua#upaUi_ zGhj)*62G8)=d5>KsvAm<_eOG!9(x))bPjFVrIU$@qABH266h13L`=;fU4uk)iGj3H zq077L{-+QBquqSQY;Q;C@#@KBTz2jQ62My|TpgK&G@HhVDMH~@Rmr`KIS}{bfmUX) z{fHyW+*ny-vixI7=SmZNX1TK=?&@f_9v)0H22+&hZFKv_g!*ra?h6^qaw^7QPTo3I zji#`KBZuNXS5_6b(k@lBw(Q6lF`A|cDAz)cIvAFsCb!j7C=-&`KbiJKkr+oyx-WZ! z1U?s`k2c7f@yv#&)YL=PBxVC0ZXHzH`Pa6c_}BF}H%tVqRbhw8qHHL0N0j!s7-jC7 zc{9(@YF9Q-(ko*tWQxNO%=Dtnsibc}O(@Tb0@YBMYIX_Tzd9E6;dOuhZ=1gMokd^# zHAabn~$03i~l#=a7)QsNRz|16-J-7mZPdfT&1U=K8c%_g@@SI z1lhrayk8A+C}%%M7lFZ?zJqP8ALaIzn)4_hcztB>j)x^7>9|47QFX^|9>0$6RjpX( z;;R)Qp#cY@$@BS)CFhlKPeZm%N=winvgIQGP2Bv6eenIiAy_J#%rQAjJ_dGApF zlMgUr91gI@MXuIqO|1@Sp}V*39Y>4CpvY$Y!dQ&$_sZU`JY0w-l|;o$*2lpYo|Hv5 z<0qB)q9{mH|FS2rPzAI~IDY!s5C%&8x~NvFNQYp?MJEGq14maNSQ`q_LXr6WT!G&k zKxNTb5ivKa=XcmBZ0#fM>seI7Mq}u%N2Koqonxx?AOFk%Mcdw#IU9tsD$F`Bx!U+> zGz2r6Rln=<^BRDK@yy<%VR{6}J59Q7Y7UgQ$kBlkhpmv3F`{J4<#f@|$iNTo^=1kr z@&qPX%kY`#qH?(HUb46@PFAta6^siv!)ZVtw(Xe&bJJb+GDzC?Iep002nQ0nX$`NI zZ%r!;Pq9vp-D}LV4(?HRgAKez5C_r7?j3BB0KyPm_iIl z&V}u3$$nr}QyuM?7Q_~*AUy?|Yq>CgQ|-I`5!fb^A^Rh>zKzXpbw7$LlBFw%rhD+7 z;_*3^OHeRLXm2n#XXtHsJGDy|;i5JGwc6dXeCcI$1GU=h-~Js*HS@?`#+hzqn3@1*qw`@@ua8z=gc_q6SzK zBVMCh_b&g;@4oT7AFJ=$qNGF!YWrO(d92wjd40Hd&=&%FjM%7Q)#WKC8!&7$O6HaD3}Wti5Hc?)7C4;NBrU;@*Pp2T{;f zwv-As%#rq~j5IlcWDZwFRv_LpqwTayv<|K&Agoz`-+961>^t|Ny*#cYIb(o5k&;mg z%0!{MWl+}DwKdJLBgzxyH+J27Q_mG2*k@2D-_%d+cm03Kf<2Iuj4Hq29ySeZ2Z5;T z{Bwt&Sy2c`wurnj*SJV~gZinpF{o3~rb0R1|ID&EpW;^C$&lxYDZBnBe~2bQiha4A zi!y4ej64&k%%B*07nyzOM0?J=$hBHkIZCn@$^kKS(mEB?YPp#`R?!R6Abz9d3RC;E zje?1u2C6@O5AGS#kH?ikA+tRa9UNxFUG6T+5(*Xs826ZpK za@Y0ug03;U#X*ZkPn%a1cmYZq4pLD;F@Sg{lXl*7OV3pww)y{*4Eq*p>Ok{$x!wp; zMUxg1HL7%PkTVWe0tojfm{6Tvtj%A5TKkTyh@3ZqnN+fkK!a1dpkxjW$WZNpZZ`?O zNckN>6-4!2+ieT7Qq?@LW`Udxx^IJ9@u2fya`1qEKi|B{nkJ&e`1=pq>#hw@}zS!@qW)dcH&-bA7AeG79baXgXAF z+gfWv+Hvnd;Vtf;f=5|lB>vKH#(Suh+ugeU?3rv9k%Wht3-L;aPXXB9OppgZrrgiV zb3S<2&EmlD>M~xU&tp>@OoBFb{Lmo7L|`Khvq-;gyVNksshlHc z9=Cue&AlHDarwX6jG1JEZ(vEDWvNZTw+z9fOj#lz4AMlm)eqpQ-alyBVOceIerEC1 zqw$e}WXnHcd;(#FouXLtLRgt!@hdu%>pxV5H>AV#z&4TI#$J9EtR7X-kWBsqg93r6 zBUpix#HlIkpva{xqX`9JbjGANtC;T7ZmmG9q3YLYrEQ?7Ohy@7o$$pc%CKIWLL(i_ zA8jfvC~P6OFPr^)U*7uUhge;bbZJnrh*#t+MNr-IS=tFIxN0Cn))m}I1voJLW+fCK zvq_pUya5Q>@CM?T6gxnk`eX&gj;ursZ`}3#$3A+}|M|lFpZt`mRO-0^S@qQq0;VI| z8gq6_-N0y}n^(4942eSn7LA=m){Vvp*fKmVxpX<+)RYZSoa^%B&frHwrs&{DQtcYp zJ$&y|@y^X9=L!nt?<-wVr8NH+qXD9J1iXRBWguGqde>!FSM4G3+dYSLzH`ygvnwQ- zY$4g)DBF_7nBsQ!7>u$h#?(&O~p}pU~bN0JFYFd0S$)bf- zM?=c+>Q&wa<)xFd)n!#I2iVU#wyIXr);&v+T7d)txz>2JpOKHe+g;UorJdLfirYeKD}mFJ>$-xaz}Qm59AIAP8o{f}*b_@_0_QP1750tyjz6l$w@ z6NX_aG@iTyMhV6v;fEyFbe=F8Or?l!6Tn(vZ$FqiK?pO7Hc2Z(aV$|kcSl2((qXvq z>i_usN&UMQeC)HNh-Wp)qr7(m^~PxAjnSK~o34b=rjA>)eaj`7WR z-PE(>gZpS-TO1_hDjFJE?O98-Q&JkG6SX4(p}~U1>;+u?znQ(AXDu2k7Z8GkV$9H! zd4%s`{!@lagFk#yrCYAu2emyX?ASEwd`5+4{#M41Du z0Vd&~Z#=_g(IOo6kumL9fp*F^-Y2@Cl7q?k06fa2NiEtXhw}t4$#>!ez>-eBf>B38 z5#$ZVr^!{?#nOOIsxT{)%}IP{m-EL2EUgYrY~3uV45qh6E(Kf^D}x5bipP=U%&FLM z{`p46Q{##m#gDz|4px~TNU2B365jQmPtJPb+5Yd`E5E^uqM#Z#h{8B4Y92Eu4v1oS zb_-@Uewn|kZ42JkA;E9>QCMlJOs-fC9uj%%XtN_HuII|&wLki^qSkighksMK5@0py zQc*7IG&N#c0~0pTDV$iAB~wv$O-ji3f5|Q*Wm7Mfi*}neud*pt-nGw|1*Xbw*<}ub z34cVoTPhR+7`W}bqFN?15Xox?EER3b1w)a!3BV!B&eoI!fi4lwIR9kc)7NANl|Smf z_!|7{uc_czu#(qebH)r@*&nxvk&I4dDMT2`*-|mHz=cEJb?=kxPlljPxl2>zA$xiuxH3F%lST4RGIpQ?y{EH!HP$&jQd3%6@#~Kwr zgFDS&Jc#AE_$L3D$>BN0H~Q~dYLlg^4iYA}7hP}!1kHZG>--aW@BGXvxE#KidGXcs z=l@EaH|Yjs;{Y;}IsQIV^B5JSQ`mOj)5i_%r1EBcL!8NWTFQVH@ly6>TldCWxbTc7U zj>+?_;tVyU1dOVXzW%wdbRBx++{=HOn`;K?RzQyl?DNglQo05D`HFfEH#|fv>F;Mt zEa|gsK6y2<_u$8Y-`$d3l&u?vzW)l=xCn(o7Jyiy0t7t z=Po3qaJaGK(WUd=^^qyx)oQj%7vUhSvj(#nc6rO&FOsTMYPgMo3-}hwz#4>r8O%8Q zVrqPgl#|Uh#w*)FLTHZ_4FM!XiM`qT%n$8g7?+N!zV?m!_I?q-)SyMsf*U?6^rQzC zqB~Z;-JA=SWDN>7kE9coW5z5gnu;&dc1IwS=?eB!c#upRr`Wn~==(2w4?WLIo>nVj zGV3TMw!yB4#hHD@m1sgJQ^Hl`gsNP@IpZ@qnKmytMx-8Ok8v;_mW>pJ0M`do7UJE^{r)U} z6-C1}5QC|V01!)K_!ys{Rfshi!hlmh55l2+)J(yXtE3bS|3NJ$UVpP?=H z6$d++x6cE(`rsg3?qeolgut@d^Vi1dN`sZdRJC@KBWi0hWwWI&?tXSz(mf&tZwgtISr{3(y1?e!5|( z_aH8}`CN^9EnT(9AJ3 zootT4A?U%qd|WmNI`10i1t%`!rk+dRi`8VJn!CDI>%HvUowq)wfmdbhEOjC%^@mN7 zA(>-hn*7pX%St`c)_ZOi=@!{NJ~bO$vSnMn*<9T;8!Hgz>tRWJ8IB%F1xKZ%UZz`T zUV;*|3|=iTUg-r82*zOlXUa7}r~XwR|-#mqph<`L27v3Zz! z5w#_dRKX(otDHx9puq=j6w!t({iRuM zmH&>$snfei8>9jfbICQ_D(9()LbHGxaEJWw%q8ay-~1S5z$59ruD8%(>{IoK0}wA` zoA122@0yQJRi)Dv$eYZYc{oWj*{@-Pm)|MmIsh74m1rD@6yx^(uYJ`=Q89u@1eh-} z?(Yp~ns8F^bh1onjQre9+8o_rVO~_qTIfVISG%eRLn&cBz~Jb6g(wSTr6i>!%$D$3 z1&peye>jp~ys=WS@As{W8G#zCF zG5YHUo2-n3?OeHY%}wO%r^G=QW~?39LKhG2V_XgTP#n-;bwiq<6Kq3i+?@77q2dDx}QFn1kuzh zb)A$0M}bNy3Q?xsIr_uj|FsLg^`Pi$X@MA-RZq*_YHM--$$1e4zB2Q}}J5dg{dj#yw8gWQH7 z<0k;>k|(3!thR7&`_ZR0;fK~I7g*2YE4SbBn3{%V7CFEw>ZZ9KI^-)oWQy}eA%gx| z>FBrL_cYc=d3y(&YJ8cSk)V9EopCU!BWa2P4{sUt&|3HG&eM+^dTA{(2ziZdz0;>U z30U3K!517SnnWH4e)#wtp>?Q#VdoDX7cZz6zvtH5q{o6VGxCZUS?W9*N8qLQbH}lB zx{iB?1__xe2`Ie-8G2>6`LK4=%B)wWErnBR)Kl{eEzyI8>f4)h8 zacaTPEM@neclm0w1bA07X^M>bd)WA5P0v5(Bw^@4filI57Lb9-sdQ%-O?F_7g)%ze z(Q(P+QOHY1Rkm%T9Z$Ws>T7?#=##&19;o0%$<)Cyv3_C?nceNjNqsHVte#s#~lTm;}- zE_oz%@=*+oY=7kDL$3aa30WO0%mj8igwc;*P^yH!Bv)CDz;Tnj6sWUkGzKuOyfpKI z3kF_VV=GwF+eoX*LD@~0gIU5WG~9Y-KniODMX=}DGTr*1C4k-igJ5@1l#VcoYh90~&$V!l?WSEaDo0>P|=$ywQ|`2~91lzUrlsSJ#m`Z5&vD z|Eh%hvuaR^W3Ay*(q4c(Rk#A(mtSi1Q^@FT`5J6wGw_}Z-h=Q3MRg#VAyxb#fir~} zJd0v+%-301R$#y;)WGY*qdOkCrSCnTu-Yz@5zsBNic&sPBD13o6!RLpWyj!|lh#r- zNeAo;VWn}~XQ0OLVEL~GDosI;mnh%Hp|na%xx#mk^{m29y>vkX=ySJ?(vQ5{ve_P*_KLZr^4NaYx^XzKu4K&8KM^eog*c0 zx{*hPL|pLb4{5pSi|DzyYO!_-oZk40e^~hbPqy_P3KpdLcF^6j)7xsKEHkAInZhuu zp1jIJVW@e+7T5jbKj>jPAuI{#@S7b>wGQYH4P@mmG?Zep<>TFZ&y8frEJQ4>qVxPP zdQ)%+%TB8kafLb)TIaJbf3K@ERh$;>Ci)KRJng8#SJz;H*v2^KVfU@*FGYHS+3VkO z*DZ%!{ZS{1r>B)BHTp?b^1;LCw^ku;!f7sy2I!>gB%Zt52y8U(Q*RrQn-KJhYXsL9m6G>5(C zUdb!EAJTPEm=ETR9t8Z8lsKWB{bV%thRhPPln3etML(;GYgy`7B9;RNMtj>Y)f*=d zg6&W|l{R8^n!DsZptmTPsLPga8E2N!4%+(W&p6}gffrXx;b_zetvHyRApZ~(k)<&X z6mxPwY~vl@omZw?z#Rd@L>CsL?w?;U24Bq5l$FhRR=m6vhFM{R37hbg)F%eO4Kl`AXIhZnazslW zE*b=-B+b)JG`eS3`-17)&W)jdVrFccNpV0hY=X&-^$l`DWsn(WvkpSNp=QIMkcH9t zt(H2X?#r(`?xqVi|JCPqFa5r#YbhFzLcT`9?Les7h_C?Utbjxk6lIQU9<3@}pkhF5 z6dD7_O*Uh#7G~y%1Q}SxX~8l86HPaw|H)JIgqO29>F9V%aF)bSsxl`pD|M=1O-Bk!(_p; zZ6?snzouZxo5MkeRJi9iEwIUP@}^NV8m^pnMjbt=_nDQYV%~3#gcK z^^h#}zqpc(4nq4(!JP5zV+anw0+6%FIb6H_N%;rr@-Mc}nmOy_b6JHPJy{a*>WUKO z8!r`p8sZVesUG0c#38$Hxw}Dn_=dGU%F=Y{km=C7{CUB}I4w4))-z+~JFj4#Fbgv| zU!V@6l6~NFE?wMTrduHC_!UIg@SzbvC?QkXgJmf_mrt|7B^Ok|wm!5BB|o8ZIg@e3 zXrUG=C<2N*>UpL_%FYuK1+)0%&ylnJJ-bD0aQjw0(gQv>L>PHNaBL|Q?Ug{9u)}A1 zp9*XcWntz2YTdImnE;LX6e{*W)$Vmd%ub)pFT%8_4#ctmLKe`oR%tf{R~5apKNJUv zsj+%xO=Gjx6D|KsNzkIiGz`Oyv-V!+O4Yi}Xd4#HZ(faw_(0ps93Gg?tz7TlLmCvT zndk|W(qTZc?hjk0c01?a9Z1;a36rViNOCC?5=riiLykP+e}A>_Ll3O|KYuc`d>v>u zS2@xp5cV}t6gI#GLW7fSD3cj7R7X%Nlsd8GR5vFx%WaQfj)c|;q7Wr}(!?`vBF_Ig zG#h4SEZ}R26u?-vi7mT}tG<5gNuT*#Ti*h3fxte`3|gvxLr0q~a%;*m{YgeDgS=#n zDEVaW6UqBvEd8|po3u)%JH2S%#QQpySJN!}$|5kVk5HJn9?Z24#E(F`4s<E4WR+P65j1GbRW}zA;M8S3v|3v))^M&}8h9nIrSkGl=LPu8!K+9B{ z>=v7I=`|=%Nco?JASe@`QUg?8fc$>J$Q&hi%?P@mgR+FLuf%R_^(N}K%<&o>9NGE3 z+jVn?*LXBxGtmVXe;P?mpO8E9?vm6G3j>NUw;=K~^=a>j;H)MJHo;&S5H zyJmTF`hLyhupi|&i$Z*20YctH;1pr@g{P5}KZ6QpLNpggTwIV%_3z5!Jb;k>bm>H@Ik06XP#L=MIV9M+L%M6mPJ7p&@B;byRpMsHMQqk^qVE);?2IH;4$%>JR&DEZH>@SdGHHH?Cj9-JdGK1lya z5g7uCwbel>q5UMXJ58-K>i73S3RBVB^0s!N&X-xVLg+!F@}Vx+L;rfT7f2V)-HyLu z%pMRw9qMP3P8wVPD24_UOvYZeb#n#to~F0p=5gr9ZJv8(&!8D4R1dnXvt!~n1vO@4 zZ?Lfu>pJ)9ldga8n7{gR$B7FHf$x&n2sM-mZ~0Z}%23d4u!bCWQkN%cl%?q-dEyFh zM^U_=)jj$$J?Y;eaG7=?7Ru3`chD!8#(#?pJ8wo`ygCkj` zg`$n-Uin_l$VyG9GE^x>ykGa37ejYPqklxIz$cYUZ@e(zSJjv*Ls}IJ*+Dd#s~Wse zu=Tgyc<9w1H790j_Bc{2%`4ZZ^6`+m_5m5iu~du0Yc+xO8QmA2zx(CY9F_Uiq=f|| zN7n!<0W@3Pw z^Vt_(;uHr{{E{aRjef(6QKi6Z1zlA}$y7_+PFduEhD&JI9oGv5YPIbP4-6J|eXF_z zo>*46Yq4~7Wx@sOVM=v`V$PDQxe-Zl0DAjhukfo@qxY=E)Z0mWNAv}k4z^8VP04VD zy8Q-~)lI+5j4@M}WmzvnkBztAbl6Y)ygbZmgl)oWi|))*v~EEy93uSye``deUBrFEktrO)40Z|fjwpjv6L=PEg|4l0CNm;(5m~o~-Q`(Im z1Jzc2`^HoL+aDXI$G1(oRR|QjWXI&WbSmfADpIcysvh@bljMrU(*Zi71&ZSj7B%>_ zoCB*51?Tu6J>h}d-U18kkc!~-;ca(5tfLgA5)Q0TQK5-L05V}IW+3wvkId_+9Y|Xz z=)LqORQ0|24w6EQQmUi9tLKt4cHHxw#GgyAPU)+nn}TONEGhx>Ww ztf~ZHB87Qg!&Ruj5=Xg%pY=fg8a#T=s->&bw^mzuqA9Rtl}4$E5a3 zVQ6I?r=0gk3TAl3-Lx&=^~}=?KMg}`UT>`5Qz+?bO&JdiC?|Il#8uuaWXV(PD(t)9 zD(&ua19C{2te$*?xj(jNB1Os)qxs+BhQ47+B`xHB6}anNw?8a+L=d922-81ub9dm; zP7s6!*xM>{`>47jS7TR<&AIG-Vg%lf-bX``5I2p9x6ixetgZJxDY!92gi$`gLW#{_ zr0eD5EFi(b+PP|9l-Uxlh{G$&yIUT57Ki$4GrA`OKbM7XX5os_aliyWmVzN!b_$;& z99mu&Z5oZUyd0?Qe0`;?jc`dNV`ck-0;<@<1$g1BDTE1?LX&8aR|%-ryi!ZhHSbV1 z7V$6wW$b^x$lD^wEzYc3Nv>EkZCnE|F2I7RoSAJd-(;g1^0R16mr%xI^P z(JB^umT-YkHS2dZ`d7R2`p)fRv@fSN-P*CO(CU|(7{by=uqG1$sjK4wLAN&KT^Swpg~ zioSVG&g-HwQ!FK_@VX-u7JB?zWcUs6YXKEPWR!_#h=^E~vU$~5cz&GHqsm~BAu4J( zxNiHlryiPr(bckS$M}Ay%FrL}Z3HanHC0%^>e^D4Q!=hZrlA>CpRqhB89W76&WgQz zB7Hn!)5>yl@M9{xxgx%D0R8emd%u4N+dWu-O@VBMIv66aVm=_s)Y1|&3W_yg=Gn*9 zX3rmU*Ql9QfoYc(dj68Dx8AcX5Yq)GTWQrH+|^-4l%H&P41H?(uA}`!TOPjk&}%=z zo#mcX9Z)ruj13KHM$V8~K3u5EW0MFtc_TT~qcDUfww8=z-DfWry{STY0?7^qh2kJ{ z-NNMIYPu(FUcn49?_RbXsM!6~{e_$&XvoNeLrx5UB^@Y#w~dt=X_0;Gb+0vF9-5cuM1-tAbm zlSDp9vR}zxE}y4-m_275TbsK;c{s0%W|M8VjE3$^9L3p7uHJa(4?xQ66$U+1$Y4^x zUXie+!y*2GGSfj>f^t&x;e_?!`qukzT<}w$nr!FLJZqq6lswb@Am=L~-(U%L2ddm# z|9Ag&x8(k(Vq{=w-A>JJQ#1P$%u>c2@O>h04Zp5+b=oqVUHX^vkpRr-Zr&nW1GxnIRdE zILD`KbJ+BGRwwQpVAVv65fM}_y|n=#P*plAk3@azX6x3bA#@wwx}6NkB3h|v2r~6d z-Yc~kthG!BY-QJ6$EB9;p3mrXN*ELH(g0?#o!sm=V{WQWzN%}%q6NSD`NMzp^TTUj z+xg(q9S=X)zwC|CdV`|?>Wi{h1EI{gcp$Is%B;+_{-x*uXI_7uQRd(T^e0roWb5s9 zpF2F;zsfeReCnH&j2et!hHIg#E=-NM7(t#{OPm{=Ti|JNdXWIyKL^M&m zipI*m!debw>)o;wTHVr*#?B*XLB!0%92&E+cehEr4<=a$><8F1h3nBRV%u-Ou@Etw zY>=y3Dc98}%yaDK&U^*PfqB$eW&SjG$rY+@)I5VxRJj^^1Z>VF*E04ML?h0kG$C|+ z2_DT+JVBe5E&Z!RuU-hu753NOe)D1P`Ggk#vN_O%!*AV{(-2L{DTybv)p_COaJ8Ao zgGb)F1#YQ4tz~}Ob^2jLFK-s(E=uqcEbhm)FI~w76v7m0GKN7-D_5{ajd1(k!PT#C zf9i2POjkZ36hdmUb_vZS#o|6Zskfbb{u!D?p@O##sTndbLv$;X1dC$z>xEv1uDvz* zi$5i)mVC!ucYarJR0)tCnwU5WPE9pBs1$f0jT~c@_(wz1d~ti-IOknUm}yrlm#C;@ zLCG6PXQ0+rBZ%Z`&Aa3p2461Z3`-duh{*#Rwfj84?xg$PN#(NOt1zW#Pp*m#^7q!? zar0!;E%KF=DHkq;eiQWFB2nPU+^IDCojh4~T@T*RR2jQpd_o`zxj3pt-5qbR@(hGUI77JPdLu@$D-K#T zEHmY{3!8G3#H_yU^>k0%?Mz{HMn&thu}yQ~Qjh_9a;SzWbT1gQfKZP^-# zB<|xtZfN^XNd&^xIn;SY;SyT^v;|!h3^Wp11Y@%sp0q+|`M-|tnanh)#^2!5{N)B_ zsa=wF5?b4UG%G+J55C>D&1AaUg~E3T)T35@qG z`6;W6+KdODyup8fj>C`dTr_|1&8<3;CeLd|(;F5D9#;4uQ|yTffATBIhP~;*rv!sj zS2s*pbt@chG`>c1!TGpqpj<^HUhVXFMpY4$Rse)`Q(MLCJ@>r+mv57c&QT8DBd_s7 ziD4RhVw-{LfJ>4G0srL4bZbbg(ynJ8+4Gi5FeSL$3UQlPrT81f>-oYznWW-LYU%*GY#DE?-xO zgt;I=aVY)=l&P*exft&roLX=$+9r^Q$C|EBuY2g3vj+CIb@wR2CenP%)OwL!jcXg3 zCJ5BGe32Q4$_WaB0&6>6pc~p!{kpc!-m@+%Kac!H zdA);s2Uff^@Y)N5t6m#e_13`3)x&RXM@c+k_~Zc!*)A$wabZw{+$vYdq<~9t2Kk5) z$oN-6Q*5xqTN4gQy7zPp$j~lzg9h#kZU_yxnGos!&wWtV{Pq_U5JC|=5 z-M*!>@384<#*C%AC9gtBTNoWd#Tw}u2%wmdJ+#qUE|XI00sdHo*%~^$i)~`AhgMZY zX9k)wvTK+1P|V8j9Za|mtPe9GVMsgK*Urs1b;D!4X|@aK z&3f^Y026lPO8-SgC^RzeF`yWt*4uvh@PIv&^-F2 zbiA-2=81wc(@V=&8OVY!F^PrH(}Gu-uqt8}rrv=0gIqMEU1zlYrKgU#{3oa93ABw- z(op|zW*1ss7)!F{k6>wMo?EPn*ecSz3r}FioYriz)(A24Rx+UGvFRlgg#7my{oKms}*vxyWp@zKQj=B@|fz?z`+gEC1z2 z69;6HtE#eP7Pyixc6z9yHA}BQ;ypjBHvD9}xa4)r!luLtzi>y)moEbeQ zpJVREPAA7*Bs+E$N07jDyMr0A3rH3eoFr>vOO5>8_z@7=41y7{vpOq`ZD0Cb-8qv* zN`Y!8Rwd8skKI?zAW?YPOsc)8Q#Ajoin&16K#C>gt)m_VA5j65oE=Bpj(e0ZzJ^3n0u1VFJD4uV4W6E?l5SVE{Y~UTpd(>cfOH{P|KBC5aBXVN<8U>fS`MoVRy&ocyK#DGSV8 zj+QCbH|}aU;d*Av$52sOMph93<;&bku3SLk%1zjN(mOTw942Nr+@Vpk(rt6*qED;q zI3X0HU&hPkscWo0Sd!q{iP6CgJ85Kqb<6|@m7AKlLW{&1w#D+&2iCq$bs;p{(2!kn z7K~SHPBU*wu?wd(MJGM?pzou-cdp7p_G?h87Mce`2(|XEqfhQS=G49=*D2Dt6{Cyuz{C#Pqj+s4ZMB|v({OgRw& z$U-_W56nueQry9snRoygGG-+zk>_Mpn+1HKd4kbh+s*L3nP@o(COi-mE~izEqnp?5 z{K0Z)A>6OxjH=|%h_;{%5f6FS2Ndd{75)i#p>n6qJ^v~`qZ5ZlktJ2_1aFofB+b?= zgX*Cq3}8Y6c*BFsaCm@s&74$g3;f<1^VzO4WK({RC#cI-j6_$CU}iqr=N#H~{9!|{ zZxV$@sj4YR>40Ny`c?zu5-&(@?pJc$7Sa%NJ(nN#-=h1B$F52v-Jp5roi5lKf;c4Y z4H{N}$e!teglLPJ7zoKDB6C|205DX*C5p#rTW@fws6q=`$xUA0yne@%uZd*^Ss|3X z?LsRXvDq98WwjPE2MPtvha&kb$|R|8$@?bA=S-~c>?_&K8V=P(+n^9m6~P}_sXS9= zf`z=ElJ_!|P%%^if*FT`&5u4;4D9CJz0AmhG8gc*bp7ZLqOc70MaT&OVY!ef9+0$m zirHjrpMG%N%mQ%9t75x=)wg}EF)E=)g`ntHli1O|%@|n!F(sCvf@{GG7?667TcpxH z!#BVw9|>eQ)>tK#Srnz{exA#}cv6eeQ6?0eAO6A5fMYGkscy)OrzIsKTFF{ss|}NZ z_xKPsVjX?+F&w*cfB-<2mHMTeQ=?!eE2t`hozE@yE`Pq~%*CF#)YPnz%#kDkld%cA zUU{yld6Kye`!Y>km)$uKD#S)+F{uUXp)hPv*P(|=x}g23PefMA)N8Rw4i4_!p!~Qvb^3{i{~=zp=7^)!Km#J3)=1qFO(7K2eUpDdu3PlNRv= zZlVHJY^wR0Q#>W6n4&@+4h`s!+m00E7ZjE)oQyEi?v<}kTXS)&*)4g%gmAkzpRKQz zJS04L2wlda5vfpyIJ+S;sT8ZOl&3AYs>avowjDt${9vkeAb#isMpK<`yW^WO5t!|f!@GfsN!x)D}BWv}4+d5~?J^$3rkGv3Fi=0}_0PZ7KMA;&3 zM*2gw^QpdfWc~f$J?bZa9$>OyLh_V+D8b?QwP9eCyOD6sfjkT#tFF?<4!-Z=^Vhs_ zn`CZ4XmF}Qqfl@JkH|>-dCZ1QO!wV+fr=ZCQM*XC6dgl+*_5Be)!#3Fr48m?bV-!G zWWzh=-aeUmbAcNA@CooHTLSkG6BLoFm`|jjtCkkj)JJLEx8CtBP>khjB@4v^i9VHV zoH=J_klcF4YH^M78*N++W_9v87reWL!bN^Rz>FDlFM7x3`=1d`+7O-O$|V_>L4Fb& zAzbAm3xxnCML=tkthvS-{q+s^-LUZepO*7VZVai#2%4lyuOtsN%r=bjZqDw9yckig z0SoA}FW|mUxTITG)oK+@*;WsG{cB$@xGZiLhNF+X8KkDjK$f7)LLEZDG^NztNSJ@x znYMbR8ii0%{%|wrinNrm5XY7>1lrLfgHMiXai%>5KHRgW$zWV|vhU+)syOOojD)6_ zGNeZnSo?w_(4Uhbubh+BbH#c{Mh#LGZN@#^e-iEgqnznQOcCBbmXZT{bWn`{{)zA))B`j*Pca5OkZz{ zTz|zy4ix>9tOSz=&xlcG)_M4`T?>w#xA-R=Y^6Thzw(v6t6tsp#!CasU)%Ze8++Go zg}NBiZ8VU#F(qrJ3ZM!xz!dea($5YTEao-!lPk&BDE zmZk6Soh|F3s122yv{onp<*b>V(MkfBSkJMFCMX*{H!(3)0<88Ihu3U8C~*8El5Lr1 zy5-i}ioj{)TR_dFB>kUY#I$CEGbs8lJ*%yAhL*M<&n9KfmhSd|9TX7IsVkOjdgOVx z!!4ypxEm=O^i$%2;&CHg)fMNsE|zKaZPzb+-_HR|wu?&?5L<=IOTl97%J#Vk*dhJ_3cj3v|LOmO3oj1Z+Dq{QWOVn}%r zk2LhthO0qTqXmnvF@QX~EtA8}wpZ7c-xmj~rh-&WoSiqk z6WH>XWCe4QA2|(Jm><34G;H@#PCUy1Gw3XVxj_9Pu8_30~j5ee?J4+Vto>8}4{?WakiR!)?)l zr1V{sWsa8^s_cVjGb7!IbOy}FlM^ZlNcA-P*Kc*v+x|?qjPPh}o^Bj7M&TG-(!yiS z3fM&1irv`Bl{=PsmzJ;flkkI^aG4T;x9R`ZN8@*ExZSpkog% zQy_>H7`#F_HC#C85vxQ3eC03jc~@So1A9x}+NAFc&cCWxmTq?blK0^k|C%wUQ;`{h zitdExi^0S)wH&7AOhy&?C$4+&85$XYu9*|-k9%VSYM9jsFK3Fs)d{UXr{vw78@(Wn zVIR{8%suxCDP<<6ZyVyjB50?)4WV3qX!?RCu2#xfa)^kdr-8#1INhoVM}mc7;DuThMDWz4{ERuWpNOk698(Eskex>FRFuMp-*~S7)%C2VLQYV597rLOd^gx~ z9EbF1VpxX}~GO-y9d87`z@_o;L{?9}w3e~_l+6NXLd5st4 zJCsK&dgQKt3neCF%fUY);VAw@za z1zIanV>Je+Gu>iZ9uM@aRGF=o*%daHedSNAsh~ph8lmeySCubfw@zUJ%`vJ~+#1x{ z``&Sp%&JkgAHni+MGpwAZ2+?7fc%-s&=fbz7QBgbu(DxFML=l!F<%Z>RyFwkbDXA5 zsM2I$6DKDG77$Dl>pJQignu=V;zl9t|4h<_W!`2{82Qqi&1IEn2>Ft%J`z>}W>&l_-N*=wNsa zQaqG{+b{-&&OsrW<(ASFJ5`R-TthMh;_6o=LY<2C-g!s9_Y(`>`-#REhd18y?dAXS zkK0~&i%DH9a1=}i^$XCnc}UIMiJl}$oL`_JA5$1~MQl8}S z7^>Nl!bD9j95)#ShO=8%m!e?v&OgJBf~xVnRE?fm%dc3-@>j_Nf33@UF(oG!2|y(&YoWX&muHHD($M1J6GN7Do|c=@JlZvO7Zhwim} zz!haRsxte!Cc;@mJVQaxERi9WK7^taiUQpgAt;~=xfJY0cLQWtvpGrn$}*oDS$og* zi$3_v+FgNVH)(x#OBKrfT5Pyy$;YZyjt)Ay6bz_#3^HloM`ex#U*=j8{qyoaeR0bx zYm^o@Lr#i~FP2GlK^s+OG~HEat7H#Zxg_nPjqRg zDU=x(j!A38i8z$+cNSzb+5+4F-6v6N*83jx`^-G@I9d5}J19XqCu5D7?={N zqX~3{8qqOD8riaE#|ux+edi@p9ahLQE!Y*rX5R3ui^IhOoOjf(&Q2Tp zeIb7=mkh65_kv!i)y(PNkJN2wo!uy3* z@`f?}vSs<|tv`4rMfFfl>cjyKSV%2wRTD5Sz)OA{bG2ZYcDUC93aKY7Wf_abYGe$k zD*eb;F1`Nf_kVJ-GRGd)E+PavMyGe90#ph%DNJf*uUg zHVz!cABBAY=K;1qu{?XALf`LNq`{n+k&!iv47wH|&kp(OMuBue$h=RM95P2xuKtw4 znW%X6ty`}@_PS4d@-?28cyqgrRDikKh?SIL6OU>4JIob*B&4X$awgloTJ8xa$^;)d z6c1MgaVx~h`)Fm3-LF6Q^k4q7YHcbiJPNq~C|@KUbBY==eF%L8iuGQ4g9YcFV|36+ zM|c+M8E$(qqhH2UHBh|K;Ut2m&`Om>oTx>Sjt85~hQ5m6e)iL@_pYDZq^`#*_Nh^@ zuI|nw=MJyi?wlK!XAml(u$ZB$BEP$cUI9@C1wzQF+*A$u^{SixZSGkY>jX$4K+Qv! zmxtq?XSD-qLi$f!!kagKGYVFbIc?%NyhL9*FSBn8|L(#2ie$KtH23&L;L$cf^9BQ& z?lOZZk7I))17`2Y751o>b)gs-xUJ>Bfbe~Qc`9IBe_1m>;m3XW*XN&e>3tvhsi6(K z8yv*orz}@!9>eC%D>nA8?egg|hlXYghH0Yx8qBfF`(%9Gnx&*x$Jpwdfwliu%CJ zT$&+FWKHqyYU+aTUH0JcraiW1r?WL4>tL7{gji~7rf!}{o#Ys+Y(VTUT0iO z4RN1WAekD6Alq}o^GVmJX~P5yRJ?oTI~A)Rezq9uug&NgGqh@6l_wK$rwpQ@1q`$r zGT428-3+ZiwZ^4ZzOL`$%UAu^T>|_kf1`nh^trl5Ly^Y3Psm;{a-!<_Cb`ZNQAV}p zUu{SbTImoPaQLO~X2wT1iK(Jz&6<(~unKmBFt9UAZN`Rh0^l*Q(UQLA-OC;s-mps+ zzXRR{eWuW~WbL)9E&>Gcl({l=5c#p>xpO797}*t=cQk^P7>X#6rz)VRBOtT`K5kHh z02Q7zm08Q|1oew+9(}RVzo%{1Y`gd{9vkjCM6cf-%J)$qvS;r>wF*4&m95=qdP?&@ zBAh6g5E7j#t3VA#-`O?xv>K^E8VzsXc-JrdOk>Y5)>u^`d8!TG1^EH85LWHD7Lun+J_z2c27mIyXKNcS|79BpYZim!KRXI2qyjjL+y7f$XL6d!> z4LCS`~-~Di_+56 zBm@Z{s-ITO3FoKBtLi4{l3H98v`l?8`Hzh<%lkwX4n`m08#1GkGO%K~wuCWL^a0V@ikpr5^$wuobG%kg^r<8_ zfGI=pu?oc!wY7ffw+gw{P-=UkYz-mm9f-0pg63s;zxSxqI`3+AMFd&Rzw}|xE(9!d&OT=7g@-QMUYP4ypQ?<^*D*}S!CW#zo)?KSg*AFB>&ScyS^#A?77P>%g-jM2G9+|mcCzRS?tV1hBR z2zH=2Q0@RqJexY{>QTCj)EA)sB9i^5f6&O85$ns;g*AqT*W7ahH~=KIUScZzO=#}d zEf)zLTJ@>!L0u%OCnEHMrS(wX2h?^0^iR<4n#He>HRV%@Z|MI?-#Yp|B)n?q0Wc()mp?RLS`#5URA?oJhbvP-6?1v!Q* zAPa#}0$^~e46FHZ8YqC#sS5QOKK#vUb)53&h*fQ_RFuUuj0{3E)Lo8SNDR%%nh5o$P` zFN3I7yD$^*s93E`$A-(!hd(@qhGZ^V3@fiwj0G_zTq8>P(#IZh&Z%-XPd7Pub@?O1 z*+|q%`Mky8lTFOssz!x`&WOKQAKG~PBW~Z>axY~lWV2+=Y4eIg*-G_Rh!q&E@T_HC zfFVVM#B)NTyTUx3+%%@CI8d%@=aE0&5_3An{3liH+mMdh^v~5m&X3b@`0UfqVfdZW zEGxnTO)!`+Qifbftcq7DcACQDJ1PrxGG6(oub%jGzg_E|C1zU4P?MJjsK&7JA|E*hv2AWLN*+hzUds!pWiux$PlsG|?(P+Li?pvm;oZ$7 zzVz_@46LdO6*I-R&Zcg_D?Y;R0np{{P-!F!%8e||bMF~!t znb5AGRqZ1`TvOdW#25bI3s3#|Kj4rauaRYmeH*kW45J!6)N_=a9dqq_!Q!dFRcBb9 zErT`3hqEkmY*kT!vnY?ZPYUVBDBqfW`uT<7N9S^!5D*aaDkf>+BPXonj+}PL0?REx zg=&EZw(Nc8Pdl_^ z^AG-pnSrjUb4D=x#M9aAcG^=nR$hbLEf}y02^A_>mGD4LtS0Iag^pHrI^yP)jm0D4;9Q}_eJz=pd`jFVOr}{C@8)>r zY(PK~fJ~CxM^qa7N8Y;Y+b3N2%PtTZf1Y2M)8^}0k#}cRgzQy?7~8MLYHqUZwe(%Q zguZ^a)PW+Qg#?w4z>UDUl!mJHIw`vo*JVr>GHc1RIZWqtpn5;!c}*D=Y*g6bAL)Kx{m-RGT=nfEulblhD4L*YV%R!R`}?);{N0;Nzh|fs zJ>Rjf%&@Q^eWxD<9bJ~?v`I;{t*cvrA5i%`j8GUtzvqBg#e{n0!+e)sRyg zVS#08yXC26W`J@Ey_AwEV71Qn292OJsCE-sXGLQnEsZYg_{ujH!qGWr zFMRKicYVZWFb9-PQ5Ln$&S@1WrCE|(fv!kE{S^eARKXSic`izl zLzriO{-5+T9e_s*lKBv^?(WT7A6Qn%9!>)!v3o^)pRe~sut3$jKvzy6iA@N6X8}|* zmdN)7JRwp`mk}z{*UJ1V4`jk{t5dFO>pd>C{B3OIZPy=v-KSOcZz85d1K26Wk6|tl zuc{fd3}I{7I%%PBu;7wwko|!ewW~?QAW+nxU@^7-7+LOExh_$_=Occz^N^l-r=4%} zBBEy1&zS2WllD;F`HUwYo4|pAYgq8lI z=+uNUOl%$tfXAYi@As~Uk{@F*ha_NmH{>-nrcW)&> zHqzBZvA~yqkTS|tnkyQbNLh|)J;qyKF{M2r8>sKDbfAs;re_{n`Q5L-dE0|STL;7= z6L>zV$;(4e7<->q2}n^6Nmo$@o%7CG)P3}c8ab^ok=#}!v**!;m8pxg6&Zy_=6Vn) zuCiIqOrB7+nho(|m2Q=5-goZl8}5Bl(}arnT+K~-1qDeN7;O7AxvE5`Qz4RQHM=Rx zZ1N2s{LTOV6W^LY|NM8$m_cy-as8JjlE<&Q?duQy-sj~=A`n6%c^#xlQ?qQ+zAd=m zd|OCpu7%y!-CJm+og^VHH(;T@K+3i{AkXzpMMWF}?zemh22)8MiT1^&r{5f0x1xLD z@lz-gR*+zn$9iLQ*NB$b;ee@%F8S-0H?!j{Eh(#|7?V2tW=|UhT?^eUc_CegAGQl$ z6uTNcb|1)leX4GwP^kZ$(nGUE@tv&V5P2{<14ohW(`X<-IHZHhL-U=_{@_rNZo!0A z{`P;?WjGagE`NiPN~|_D+$-_=Ap_>lWOeA7dx(@R12*Yy1=MhHmQd?Fw7b2d(=?VG zVQAI)*mUQ2>Wzk`KPIDr0YS1Aj6aw_kO%33nvC>m06osYOdKNzbP7+O2OQ&jx=_s} zGSi&4dGjjF5UpfQCQ{cyfgEWP;zqIpvHIcX8Y3fZot;1v+3v*RdDCY6aw#S!1(F#S zZ#@9Y8DI-$QP$Hs<{vrh__=#mZIccIvgsV<6Z`y@u9i@=ah0KS*W)^{;Ji~5`?ujG zBwKJ#?Fq$AlqP3uqCOiYKv7eA?V7s14R?N%>O~M6%oCC0oX0*;ZeI1>A;Rp;jd6NrTZkGVCR71GZwYxeC!Vdb;b#iG~{+J4(;C6|JJKJUwd))8!v5o z?zzp+t!V5WR)9gRQ6bChWoT4rX{mkgO$8NU8S`;P7b=$W)Q^44Feq6`d$4ML(a}&t z_DV3o&~N(4Ko3bCA_I-5prArve2nE;^&i}iSGGlL{zVtBz55BS5V;E2&cThgp_l81 z6%a})`Y~MASQV5;3+3}uBek?=^!AT@eDVMN;}bvfn|7FeVpAeN{Qti6{V)9$t4o`O zV5VDXyuNY*Ba90#TmsraRr(S2(LV1`aao8(O?&2sd*h>A1?lj|C++IM2!${e)f@iqppf3;tx52^uP#DAd#kKJ6GCd*^%iv zbl$YleYcH$*|Lq&yKWvUo6`HrvawcrC|ZQrsX7B5a?$y_-@HrI`%U?) z38Jj358&tF0GZn{_%~Il(VWw2qSJy3PY*x_gPpRiPv&E5GiPDkGRCOOi>ds?L~7g^IXD zG6H*6Z&~_N7o@EEW2ReJG)9L;c%w12dthYuFpe~03(u3*1Vubf`@YmD%?3!r-8QrB zgb)9kx6n4$tziDpB$rH}6<8QZnBh-dS#!ZgVi`2T6Qhk6ush0gVtCPv=N7{+2T;Ue zRc)2lWvb#Hd>nbz2cG@HUo~VOR}5(sGBsAV(}(!_6}v3Tz+-oi)Bfbjn$Gdq1Otoy z#>4;p58u4yhKs)VS94E1Th#!3RGtN1fu9eVGHYr3x4ih&HWA=8Sa`+zB#G15=#!4Q3#gspC>J<^a)r6*0u_QRL={~qG~M7( z0~(O0BkHtR>!^C7m;g;cvcCl;x#()~?gxNwO#P+(Co!lg)k$+hm&z_@?Vr-fy9a>-}l(H;cM;#+UA)JNa zfw&Vz5cdIr0*<3-Ei5-3xxxZiwf3NEA9^8Esj6z<>yuprYOvieuEya3-Z?|=h}r>T z{9FpeWsQ{W`r(siV#FeDE2JdjT5@jUf?NQ^5*N~B<2GpyKz6@h`Q)($`9yh~pH#+?kERm7^|P9km=%~#kwov0$kZ7@lEr9^&FHh|cXmtK3I zSEE(pRQ_jh{aag~c!SK2EYj9i)NA5Iem_bFMDc;rNhX>FF2Y9%L3zUFTP<}UDjVICw}BJntP_TLzJ3Rtgx=F>&!4yDX_;A3mh4u4Ntz7VHg`jK2-%d zZffOi2>lQcPml;liDNnOx~n^T=dkf1Z%yk7-DWcL;NiYyAzC=a7&xBQWM|cJWMKH# zE6*S<@)Xg+=ZfeKn%nlIPL%fx)4&0#w$<6c@tY@q{J*IY*ycL)-HT3}apdfQ^}DeQ z|JyXfyDI2{2TqIDuuAsb@|(r8!4amtd_@hRpw$mPx8|X%j=J)lr~d4x7A|>zd(Rwl znKxJpS+lvt!*A@_@z#Aez5cELSoio#f^MUHI$TwNz`}G0rffMiCP^n=(u~M$ap*ZG z)O!20j{%t}Hr4a%K4#vYH#buQiW-5&W+QnOB@eFY`QJpwohr5*%VKb3VOquyBGW4q z+IxTPv+w;z@8OHzXA&gUwl}>w2%oYJHWWTUAvHl?i>$7f|9tE2|5|bLBYHBAl*q(1 zfRptW6V{{#y~my~#Up7GPPfRg2hUh^s%YsJ#B#Ey`Cb-LHt>u`Uwnufg(CzhXrvma zNZB;DE`@rE#@6rMb=bQ*v=GqGGreajq{w=US=L6E#dFuR_mIFpE3M|ph;qYxBfTDpR*c^=_pOfDD300 zNOl%l;4=d=y2#jq#n%#i&VL>mpIw!*Qf5k8ig;x@6df#PdF|dDy|2<>-3b`bIUptRzqY z&i>3FjO$8`E+}IxGoma-`rOUOl|;xSMG3mce7`1;=i6UhCrCSFu!%~wBAYX`>|3X~ z!dq^I!L3`h5_r>Hp?-YCm6t64#$DyT7Ao*o9l*#^cz%|e%_;|K!dO-0RXE_9q@2ZK z^@Gp8^}w^W_Rsd6dffa|7R_38eDC2$w|Dn+^z@eb`RG9Z=-yrZ>(}gFy=wdN*LS|M zL6ZBa*s5UM?0hMljZ=y$Q!)tQ+73X~ zj7sV{>|UyJu^2iOs7|gjySch1jcmV| z@>Ln6V8WBKK0mQ~0L?mwO*&V>ctohb;VuJM@3F@lGo;EOhIB{Nn)K-dbE9i+zJ(PM zr@$qJpae3@DHP0*`7&0eSHsZ3og=@S>AO-UxvC0}B8~GTJR+(}gZJe}eP~qh6Mpd1 zk|B-NfHyCpMcW3GCT2X3$DOCpn!b>G3S?(0jS(AX>`c|u zs@yhn$Sr6R;y~_Ms3}@WiYi`ke7@5R+Uv!gUiDnCDY9PL;h=_dgvDf|l@~_`PQspO0c%TJc=LPy0b9`u&}c> zb-Am8{&E}T%ga9gx?j*-6q4(GP zbqbxOiGXjJ)(2(Gn3-@gsoIg3Etxj*qJ3&l%Ddk4%5%G4-9R-nGNCFM{=?;-dk$@N z6Xw#U9C}GJhZsQgf?z7wkYm_gBGO?`d~hK$eOCKrm~6; z`AFOy9k7*c4+hw}z=9VbxgIpY+i$+v4EPdV^o9Rd*nh>x-}3KcGPV++7$&WJ$jmr& zX=fFhPBM!KxhSY%wIIsd&YoyaXwjD83Jlid5|x2G^ulX87t9*mIH07CMdcK$^3}@r zb^Z}l%W$IV)1!ujal_rrJZ>Ctn_QW3(v%to{$~45wtkUU{GHT#GE`80k8SJFGmq&x z`eZdRp$a8pLcMxBl)v3~)`gAsf3MYL{G)a(sw!tDBlUy?C)h&Qe$!)OR#G|TWul;L zhFvSR-uGMotLqDYa?HCfS$Nr13od$h@6jhY#&SF9sc8CzOhBy|9@_HUBWoYNYt18% zZhLN}cv#%oAx<_Q-S^ZxnpaPJJ@=#q?Y(`?c(JE1-C|rfJmo^nIPS>3&%c=x>{{wZ zr8n(pEx5x!1FIyn_Bxx*vVuyL*y?ebGDm3$?Evw;kqx`IKlj+Yv#&UiRF1(6<;$bG zb4lAkO3?aLNG8HEmuN|&nTc-3xgGE;#@1rH*$+eJV) z8!@8sli;JCQWZf5*2;A2y~GaiWQ#F1rLgj*e?=*1Q(8vFy9q{qS7*o=mNr`^;mmWC zQ&8r#4+ZtO3@{ej2o*#@>=qkIrpA=XuObDN)^%od z<6qB4fGMJnf9Aw3DuHX4(c6#WMdKij`-#PKPCf@<+(8*ab;E=v0P>_p8?Ok2X^I0Pib^BOG8>vv9pL+x2V5$%ROSabX3l@iV;~>XJidoCg#Rg z^=gflu))?MZ#j(tA*i`xMZS0FI&vD08ZbaHxWd!u~oXgzTC*HgXW?j)j&7 z&^8KOt0fa{Rn4aEYkw&RML5dE8XjGF=eJJ!$Y)yVb}Atz3_Gcw+8>KTJ=U7e3>n~` z4JFlgfW}K;4a`k%so8sAZ_9dQc~P|)9gDyGx84kDtG|enwW6vn;Px%$E4g0x3%t4j z1p?}(NJCm_nQ<-)8D>7`fJnEz0v8$PlxEa~djA7EqnLq!`MVp^rsj@bvSY>_QVDhVE!1A4|oF+0O--LqqPsP>9JsCuq zeSz8*T%jPPPJH=|`reUUudd(4)|!_yO^8KS9ikAxb!qw6R{t-NFR^B z`U5&Hnijjq$4-GvkE-W{6VcNV&V1T0C0ZJZ{GSFD)9_Qi(tRK~%^!?j9Q;N7;r-CQ zp>AjkVYs$(n~U&i&CT~V8lwkNd?Z<9NsIfjHTOTlWaF9AJCC}_at-}Y*Mae$2I_rU#?Z>j1kn zi*MX|g9eR(Eo8T3k?avhsU4)&4s&ZBonM=xPow4&wdz1tg_D)qfnM5U5sp38+QKi)H@-!8$SLT(u#UN~PEjL9aOK*%E~_}g zSAxcakUfur%^m}|a*sD-svN60vc!ZUHw@rODaMRDL#=E*0ljsz*->&PEnlr z!X3w3UIn%-w9Dqkt{=y+!90 z68BD~3jzmfqWH4lyS3o^*IwyZ2huME*^AyP9gP+ePe)&LXL4wAcJ|6me+C5Se*Mdm zluV4cuA6Z5mc*=T7GR6p?QxW?YGSXK<9&i@-uh4EqGoLsID}&A)wEdGtHriSe3D|@ z7rYJJ=oiRqj^T=13iKd7us6&!WO3sU!F?zvS1i=E%yg`*Sg?9zK@QbW-jCuA%~otc zUVP$PaFsS~Vrs8+{ihxoB2Fla@KUKs&I->kzZT4RD&@-jV%h*z>HgccH|^eSfP}4# z?uu*M2R6hK`ekm(kROIUtw)T98&W#@IrI;*M3QVr-4q zKP4zPOYx4RA@Sk^jB!i1FhG|hJZ|yOrF#M04v6w9C@08vBe3cSgP0Anq;Z%b??~4B z%L`o~qK=HCHn~Shd)%6XUso~Svgpoo1X!#XcL}PVQ>9tS7;y~SJp;`^1A!W@d<)_UbV0>DV8LI_>5vLH~p$J01KRX2U6L$XloO)jjuWPt^I znPuaa{AxW`jR9=6go?kiwFObucVykF?3N)O}6eBGkFKvx-no(Y}r1&Vy*@8 z9026de`VErqCY`we}Du<%BmUd$p(>~s%`67v(uYx&cbyYm~VhMh7=T8wI(ZG&MHD0 z?r(030%}^)+4VbUP@6+t(8gd%ohnw(rP@7(y+cN94H0eTby4sPNPCcWX44WDujOjm z6mNE0&z0k`XQ!82I}(KfiBEutm_jp;Y~kAwJ~=+2g~GV$ndyw_2A(ycvU(}nH|X^! z0YZ5xbBkuwDO^iau|GH^`PAC&x~)+k8M^7xqOXm}CU77FYX$Lwh+S#zRkm7B_^0x` zSCBGXQ#_z1r=ME4h>Si9%_RlUTijOpSyb-u!3AJdntP*|L8~vmH2e4>X5!6yGN!PU ziFyb^*2Y2Woe?+<>yQF?A!pnnaV>g8RWFGH!$@j1N%x^#fO>&yQ~+lO#2HWurRP8( zu362()f#4f{n48;xI~2_4J)Q&g_c-CMTdkOw+@yQoD4=vy5d*_WQ0oM%&kgK4Pp!? z&^sHvl37O^MkZ5e;eePhRdL`~vC_$aZDgQmAF^_QIEoD9UMFikj}B*pB?ZLYsJh$Qd> z7>$mUa^#|Si|Ss?j9Row2l9>@s1#_U5PN8oqy<2<%LYUQ6|PVdrEpRxv6@B(TkdV*X?y4qSB}+no2cCR*x;mB-a4)N(>0 zWdb6HKJqlNS-}!S%Lp-Y9!hHr>b~(}WUT~X)W=qx=e0R@!q_fBVj#4G0WZb%rezKq zq&9eGIHZ*Y2pcp8T?)lp1+ZNyGdJbR(EqLf&PVPr&9kV)3Qs?$6J`j(+j87yybbcA zUkC}jhgf%rtX!-}y*7}gxOpcCNpWG{HW*@qtCX==U?yo-LX5s@A4w?SD{JMA!z#hx zWSu)i5(1ctjJT8C7MM}9I?mx^8U&381D3>D<7l7C za0{s{)=a%Zn6S>5qm6^nhJ|rBSV34rb+$>PH1L&xzJQSH!2>vv zO^}#PzHdgc=0a{H=>cu)Pq9dy$2>C2f6oeE4aKAW6Pb zAsd8T%eTUfEHf;ZV&Zd4?H~&D43ogP2WS6m{ibKnY&#`rV*uZrgyE4k+ z_y-0v7&c8QFs5EL#0z1oh{Vf5HpM;DY=pKK=U>MrG)Krwgh`%MTM@FV)`~#dt*d8# z{>uWOidn5xi$1R`JU0*6h7LM0rBNcP0yU3FF1Jx8LK}A}sVCPi!gMMMtKy;n1f>>~ z&E<;FLgC;OUBwJ59o2T$ay``rLc{!`hXz46s4|@HSyJ59Pnf-wmUB!PJrP%UgtSHo zWPBhhOG+tF?Sm=aF_R)x{LPI=O~9$L?x0%6TVkp=*hVk5vGr?G`s zE>@<;v)Fw>b?V&D-J+TYaO{U~p;1W8HMj-rsf`?G^@y;_ zVttMi<%j=+G9Lcaguuv}HGmM;v=!#DAjtvH&5A>=HJC()E?l!VtMIk3}pLIIU3^90FW#s&`ZlnCU8p?_7H7ah1Y3DY9HI8EC=~Pb|Hlc*+nq01);e{a5^;dYN|>o?W%==H9KexDwMz9>Udt@O$i?{IQyzPVl6P zRZ!Jw=9TJ{kR3TfR?vz+ozg-gd;TTPyp&~)m6LnoY(;&QDB7?oq*e16-#bg}BGjN{ z2ps!idAfy!fHM~g6nuI_9pu@#e84eZhr?IFTkaXjJ_Kie*@M!PvQ$$H=paMKswLF-8^zp26{iWVfdN zb6QwNYC`U}Gho}BZ-{@#h2Msjs;uA|#e_gffjW&Qq-D9KdH-SPGe$9h4SU*bXz>1| zpkfi){;U{>_1pl23Zi$5q;C}}Q>6BrpDGX-37}b?8Z>xEF`JrwIzfd65WTw7Xn-Z& zvNam1ic+py)7a+SX^f2Sd4ycS$Yr=?f-F&j)ME$?39TH@l6-7A*;Pkmceas%g69e_ zb=j60&LI_^nA{4H9UlWr2vG^gKaNaL>E$hYfjQmWqOAcsE0+oGe*X<%N#~&pSPexF z;dD*9aO(Jy^$6h7VT23I3U$~~L;|Z)SIAa@w&Re1IT^yvOTv(~7L)44HEzkGMxpJ@ zApRH#@1Hw%es>}uMNw43)oaao;Y7WL&Szc06ji~&zYwI~OF6x9IjJA*${xzntAJ1` z$SJ#{E0#HTdcr7)!hPW|xJ0GExL`fLNaYn&pl2&d6CzFRzqoo;p^+GwxAqwX1qavt zbEnS#c|^xnBwq{AX@#7a^(1Dn9)^e*f~e&PhuB+E(oU~mObmXMA#NO8NJ^-96e zC)l^sx8FwBX+etJ1I}}&=_87wYe+B)4s9rVBquF9kj2j6N@LI`q)^+bGoZ0QLdL5_qT-+u5Ea;D%p4Z> zf%Iy}$a|q1nGxNydPuA=5(uwbn;f|#rhFSBY=)9ogr32LRJaRFznIgQtui?PuwC4bsn>&vjXDmVG@_jKs&#=3!BiIC#;N8&Q2n>+R&(Qw(NK^myed~QH?z*lp?3nEGwVa?H~<`8EY<5nk7)vh0x@TW8qf424PvMH_Xf z|JDn94l0n*$O!g%I&<>{R|#Yz8F0%oukr*?gLel<)JWjOY|z~)!_*_aO`DFM9a1_9 za>6*3t1F-&dc6=3a|$3QM`l5S3aS38d$E)@(`N=m#sF6JOelT!5O}w6MK-1v;gJ+x zw=vFuBG3h@W_=&m4W$+d&LohIjQTW0%p+`-8cfG zv!Rkufeq;hNom^m*^Il#_G5zq54SlJ$epw?bKLjOlV^_s_>yZ3V>U zr(!#wNkzaZ^`|u>yyI$GUfxzYWXG#3DpIF%=I0}HY~>ngDCp3W?F=Yy5;E3D5^cxw z;ek%6gj7Lq%()k2_k!W5s?cgrp574k$O8qSlUw#!QXWu4y$di2@g{r7B(70YN?*np zx`_qclZ~c_j;V3YIzz|JMf97wx+n~fMUiGd7q%Y1mMqznsG>H4G+G^;`oTD)+NHJggmY0k%wBHJqu z>c6#zjxF7>p$Z8X0gnDetnw`+83snJ-+VEmG37nY0-~zF_Pk}gCscp=f7ZK4md*FP zCJ)jzQf%Jw3+}k!dvl0CFPVT{2~aJNu{@9^Gbt8C))Hzn2COuPLdG0w{K263rrmP! zRTXo;2-Vw$A$cS&}oUEj*p$)R4;0oDrVHjj+ zqQ}gNr`VD8-O8(`11UB2LE82~PpK&>io&V+Y2j={>q#gW1S&Z{Tmbt(=j zee-2R(<<~(XuYjfW431A+7E%%hpGPdItiLhRCzV&QE>_(Ff3@`9>-iL^Mc6|@Wcpdsh#)egnyS@LsUepDcw8v90p|HY$076WQRTxDec|d|{ z>_!9Ko>U5SY`&Al93k8Dt(qIz>X^buY$&5>Af#U999=(r{*O1GYCPq8TG$5}T-gKy zLFkoGe1b)AWTc`;N@!Z7vg_lQZyY~-c3Q!(K>|~m)b)#4HOy<2&n%M7Hict zBV8Z2!{P5{L;9rL{^_x436K~xN?bpnOqb@BpL!nZtZf!(GU=EXnqkfdk^cJTYj;lH zge2Y-cQo~hd+3=VZF@#aqJm?q7Z>mHWL{rhLrYcij}A?_bVp?c-5~Jn&aLZzadoRv zBNJN=@=96`WPGo>b3id2UOd}7MMi0U9Ym$OG_CUV3xLMCcmez98H&h~{_C*U@1D7V z6VnKXMUMB^@m1fKeQW?pF_O7kuA9AZDl&weNXZ0i4tlcT`xBwrhev}FtG;d-lP#LJ z)L)Xw6WD(8s0r|NyiBmLOrQl$W+M8i;Cfq&cn~EkSt<|D-Y?9rs-&f%0+eg zexupnpD~crya@N!2dX+#s$p7)vSf#T&BmPnb=dzPX6;mQVa)x#=Aav(od|}L#~8%?%nbUE`;(98h;4JC)O63fi@&ItktyHF-fNoIFEy>*Ss1QX1avu>Y(!3K*)*{t|NwG|YC2NV1dyrQ`WocK|m3-)X zXq9I1nf7ddelq3w;^~NB0>;4z=~rlPOgXkQl1KG!aj6{T@fhOv_U4e9SF|<_Tz&qcl2a6NQwt} z(kzcS?L0-XdQY1R1;#Y#sv^cMrr(B%qxu|`_*Px%-a`p9Cmv)eg}Y23`{QD`t2daT_Lic9DK*#LY&3<2)+b%P!`Ogw zR#a>v@d@&cZQ2R3;CU~=JpBvwGVh>7+fGLEu2BB6PFTJcwWO=KfFIVF6%%MY>h&g{eMPBupvjc0x0*Rs2IsG*L81Ue)oTR< z{E0?v(TlhNl_MyDrh;(>A}clvD7<&X7jKX3t;q~UYz1t;)Q&V>WULmhiN9Kbj6ogz z_ST4#i)WBJU64kSlVnb>pc}}DmlT+C?c%!LU6OAmVN-^paMu-dI z6kamw6-aqNv<5w~`g?%~Bd@N{@d+IOWc7FuwQPB?-GZV+L(5iUrGS7tHp$%F{t;^$ zkhpXKP>~x&^V~BVAw55{j@ieLW{v@GSg-Lat#6~T&AOWXd?-g+&Ob23WJ)JjFQY~! zL;@6~zMZN1s5f1F)2h8TZ)o_xx#oZ%T?xg}m^cm;7$Lj}$O1!ovww-5SYL;HLko9b z`A3C5EooF8Q3q%s3CIVjj))rw5Gviievj3^`xP#V&Ga~tmD&*qIC9UkqT*l$mE|P? zD42J&_vLyG=)7dHUqqk|?FycKf@HoE{!66C2+>%uz@nkuS1hkK@Iyw90CGKWRmoWG zF#bgxb?K$CV_MX}zAdETEek>M7F_cRsS8HLCA$`k3+a7`zozw>6n$U>WJKk+cPqSCh^VWtQ zR<2rLkzmMqw~vjnod#L{3IS)?d6z4`J@m zO8}dd;_V;fg%?b0HhK$Z!{RMkFalY&W?0oH$<_-K6=8BuO1Y~)e%hVnvzxv{9C=bB z3Z=BcRpxNwEq4AIiIN_jhiE0mxJCa%FHfh zKpNxGJkoBE+KU-*f*CX5;lx<|gj4IjNxhv6c(Qg5zjV$Qpp@+RIL)L34%fUKv8IzU z>e}1*maU9x8ae&E_^Z>C(@(Ac8W8;wh=mhz{xWeZ>jO#gLKk?bA8lWT`G)M!*83Y| zK`chyLZgf!GU^c_6yLN)x9=DB-1JZJRz0oN58~2NfKU&|6HW)J537nd#zS6zL9Wt} zG$DlCoxn6$of%uG%eTt^z5VEq8wyt~p>s>9d>pYT1#%C(7%MB=#Vd3{j~1mAhBN{W zvrssVF(1H8&$DVYRoCT%|nH0#X9WvJsYe``;8c%9f!w`v4FX&cb?b#Q_0%^bTdn(Ek!z zx@ed0=Cql;+BYl`k|Frel#@{0Y8e#Qt|tia(FzWG}Nz(EEp!^ab;MswxQ) zWhx_5xVFV+lt6aRW9k5jG8GzxWD)5+2LEkYwyb08+h?z17y#VVLmxh)gZ6Y5owQ3W z-MI&{s#R$sk7r`#y|s1W*wSyQ>d(L?X*W+1MzcDtlp|AvwMA-|^$RbOYs~{esn$I( zfh;l>RO}M>5YarqwK&*fM495?iIv|&!vH`_6j4w?E4u2g5ySwDC%NyTQ8t)oxVpFf z#5Qh ztB)@Imgr46O~p>{6Ts-YWqiXUX*w!Skwsn!#>U~3`YbBhwma<&1?K$oQtSPR)ju#c zNF;JVslX`YssbS;(g`Qr=^5siqglH-)5lfX8&v}DU;YxKL`)O~Z_g*#!nITV( zU`AN|9!xAyPE@0rxd?gG8Ag2mWZ)7L76X8QhZR9y%2iulXlg$YD-9vDsp>ObpZNVy zY~zmjItq(Z@tz(*S0a55n(MwZ@zKp2qidBxnAe%rU^J-MfRQ3e&G@RLd-Zla2Nb^= ziupepR>E1qw3Z`*Sc*bRpd%I$q@5B_G%VqhclvHWTPhf^aqyVo*GU|3A^n&&qD zNea8+%1X{y0V!%xksV#TBYg{H=xr5oFVA#=LgiK)a}3H5G}>QN>)P8#FD`4{w${r} z)*AAO5)cGA12j{r2!Ei$C^Qf=bBfQx{Ku?xE?XrO%B6+?<7G&@cW3A5R}anmfySm# zBL*Qs&kufH-PU3@m+aVw6h?Qr5NXYodh6ob5J zBzY5TQNjd;S-*__KyjMh2FLJS*@NRGplE1lnQD}!2U6DEjJ+!~YL+^m*m~fhW`l^; z<)h0eR0yw*bG1g>j#6)4Ik#;uDI9^z#i}`-Mx|Z8WZQN)g#nQyN$8c#8^p}#nxYt9 zseVAwLP=L{k&HF(7){P@`zP(*Epu>~Vb3SFBz^lJa0FK%%R_#7|M$gK{=vF?;OoR}PS)e+UK7oLT*}@R}E~cj< zfoL6ZD+1&}<*cH)&OEMwxJH!|J{})ltueFeQ)?ygPP(sfKa56AZ?(de>-X63*YPD& zcYQwo?%A8P9*<50s$wG)o3AvJ3A6WcN;V+ya_8PKR20f*2531gx~O8@1&R3z+l2Mt zI_+^n;|o>o|7_Lg-!}UN=nj{MuPT!JaElDmVqJRuw`n)w`ez#tvfA?Pk&XT2c7((n z;w#%L2{9X-4GM`~SL@GmfR7xhdWhdY*+A0L|C+qu$dVQH-+ZH7-@%H>OhB|n5733w z+fE}2A*5-&go8^lv`Hv%j8OJY9Ggy)`t4 zf>1$;W;K063Ny4tI!v(%7&*Rtwk5@)b2zIiphi?+7+5`L&jL&r)|Sf>9eUwut>j+w zz_^4uiOYV0B;-%u?L4Lyle}7$EuX~dti827NISD>S;@}*0QONV=|ALgm4=`?x5E5wRgcb4eX8}TZFtb&L)_GiGY zRG?Tw&7;eH;Q@^~`n`D52WoQKiS^%A>^(>*U!qSwzrxY1d`I5mwzRJPM|VY91QD^Y zU22F?XdD`10f7;fL?9vl){9FH6ci(DOVm~m zys;v{#)d+|orHjs_{Np1JUgg#=YG&+B2i<^-1#sfF0*^xto20k_Puuod|LRs$cK7?~WO>7b%fjx#NQ7bqikp$SK9a}kn-_*(1|2;=S z+<-}kASTX+tLkBPc|DwvRD9A_u?l^jhLD#RGb&e-xq+<_O5%#u5b}^IY?N1NO+OFn z`=qoYzBdq7Dk{8e^;`_vBxMvzwCr?j=~jJz!D)r6M>P^e&=lr)z1%3?Dj*DsE2#qrjQu)6K4nT4FL?V0X83hO$`wZe1+&si}cNfIC{mO@yTo%g!7+b1qxPAbjgs_FVBoYT8! zNQuZoe1bD{>fa-QErM^PqRtPz3JYnNB-Gl*;Y*w3j36pG}f zNj>SM&+&zchFQ>9e5RBtEKEa%lyH`qbNr)1qNI7-gphzFx;0+ZBB-+Zf+3>2Dl#?}s=y*a$pi`ucf7WD z+le0*9$ULvyDSd#A>K7^vQuAHmygZ?7X7JWuZm(x zxp(QWBh(vDT3@AZdCz8TB53627H{1Y`z3OXyP1rW_}1Nl=`C!0Wl^i1v)_^AH)NC< zr;F<8Uv{FD6yWEl#}JYR*O_aH5m?__LZV~!PB7_F6Q0sr^_E7Y{5yeJ3bR+ZsS*}z z+WgdyyRf|xDi)8`nT<(kPp)MUOM#3rp=tq&N#UxAg$6x%lAE3esxV_u#?CDWlkZ>t zGZFC^DqUC3ao|(3RWmx&5MPJAwCy1wlAuKE9uU5*;uR#v?IjipvCnSXn||+>Ij9hg zBgg)EpP*n~JIa&xfSg~r>0V5d%vD+d-W=i^P&ha+IwCkWCN#cyQ1Q}*DprfGRLdu< z2&2>?0Uvq}x2`nP@CN4Ygls*^akD>;nnENdN$UnPKpvit`BIQ>^V12WXgC%PZSdH- zK{IwSiX$F)gl$t{CCfMbXm;KACZ1fo=)|(`&TjihSDjf74+;L~T-F{AM!+&+2e+MZu8{k`YHo&ygq+|t!s79yw6`qwNbktHo6 zn71nZI3Hdrto(GxrsKZ@*1?s;D5P+D2#b1p-PhQfp+IV;Ne9r3qqICW?HMaAu1=w* z$JA*N5LX)JCf6`+kh4E6O-s6utMyUqlt-?v(j*^*eWg&fSfHPOP>~}35%GcHk>;=n zV!VWeSQJsV3_1eSEvMEm^lWajj^v=$)%vj4xt|dz)$RY>ZhdXAq};fC{CFOUjb4?$U`cDqL_3Q#BB19EE*gY?-Lg8Td0WQ zv}U7SaHyoZkS=$c{yfR3;^&d`wKk z`f-h0#x?EY8(x?v6%wGxGD5AF7ev*cd;_;AgkI6O;@#6%srydUJdiU3q~mikbzV8Y ztgZ4YqB%$2GV3gM;X_9JgKF3!SroHD_Dn*rIAroG9Oxe&>>n2F7aFP;NI)t$biD;Lz7l8EsVm#Eil6qXV!oyucvO|vDIti+NfI1I2}1rk9b@q zi?o4Mt;Nr+Y2+pvQ-_d;BZ$ecrLooCTN#}I1_+IaH3)JxTAFKtEW!&h@;HUPy;WEo zU9<#B&;Y^RJvan+2=1=I2?Td{NN{%u?(VJw!QI^*f(-6@JO4T7>E7o%FY^NP&Fo&g zR;{Y)-W7{eHJY*MJ86l7cU&9k3(C9)eD8+gx(tT}#kSd4Kk27yG<=IiD?Tt)$!SMGkv#C9m0-2yN{Y|! z?l2J)MSdtJ#Y~24a)jiJi1HY(IN>KCaXkCB>wR8PMd!qh|5aC{@>3-?9kR_APgU_h z3B&FFZSTV+q_MbHw^4Cg)8~tLzBAS5n;y2$1EYTDosL_7K~BwIXxVS}xT(WL0xNJ6 zmZ8NSB-I#H3lu6J1}cs5n|^*E^TuGuWGkZ9CP0g9qy6Yf5uS#&5dVbH@gaAfPz-p; zK{y+ZVPr|cMyIRqbFgfClm5%~`ANv6HgUmLAoeGZoJFVX8a~uCL#?CVLnA-P=`|y& zGEu+LcVlA0dZ=W?B@QRNE*;b5eR_z+J{?6~n|VI_Q*i%=&xf%JS@A%LCNklm{P~s? z%mej^6`K%Z?_P&l9YxlOi>>AWM}^4H8DL4lUAibDvq4W2?|;IPNCD~ zc3@k`j!3}%dZ>H#J+sU0Z3cLfe1hF)vUsnbsJqq1pHWU~aEHFaYp(kAzCh)R1Q_Rw z%3`80>jCF)&4-S-K<>(5u_M8ha+l42bI_7|K;qe>p2 zXN*FyfbrvVbMRU8#`6E5@+qkK!!CX_p^QbP`~25{l9Gm%pIz{Cj=7wawYSz00$P$K zObSi)Z=dVhvQvpnWz*mOTix@BqbKuHiVF3$yrD0c-@Y3kvh}{zPe7u@&22ileJYhI zxD<{Q5ldJw@YdF+KK))GK$)a^m-2tV844WRFY=XTy@+>h@ixbLCn33mQxrkKBQ!_S;;wE1n{1X$t3SL?~NIkG%1L=~iSsoLo-qH2%4Qs$IddU_rQQ0gMe zxTU1}_{hEa@}8u}#Kd%wsK|ZD?LLV8@?P_0^FnHK>r2;^{d6w#d7^d7M z7tK$$E~^58|8h&w>eHAIJv$Za(07j?ie#$^&OfC>LJ=a#&-GdHwj28k(MU^PcD`U0 zmr`s~?a*JTuz0YLQ}G3MnO=WYSWl6qiku6|?F7y+sS^h@w-xovBHV&G{5} z%JV-JC@%9E^=o7tt4P+zAACYmNxtpYqMoRAeo`!olytGMv=E<*nRAK^Ma05%RE(?( zB6X9l66!h}`;Hya4PifZ6zu$>2>cO(l|^~fBW3L*Rc`WSu~1q68_ji!U%$Y4vQ%po zT-fVU`En2#&RrA=h~YyyTg}#$g-+#EGD5bRJj5cZRaHhvq|xW<1coc-JcbFOJV;^& zL2`wvOO*a^#fZyDSQaIvnW^jlQU`N9pcDFvDSZw)DfxtkX$=#vZ2nPAG%_JHqiJDL9mD&frt_3S?T#RR{Av#YFg2sF+YA zV!nQ@1$!}%;Y-j|l#d^uo&_7N+`d{{1O|Seilo*)u=~HFVikjgwH?tiYEYac|ACTv zjldd@ROBVn?p*WB5(#^Bn>4=xYI+T8Vj6`Mv&<C=jV4O^xAx_`N6@>A3!YVD(7)kv83VSSwH zpi64`g!P9`TP1;q{MN|El3T>kN6vk>LfV6q2!&P*n)vXXNonnzOx#WN>p}}~O9W=A zrUuMVPxv2Y8=aw&dP|wVPfD>Hu_46PEUTe+>58$60nL*2>>5Fz&^xQT`S%%2qwV%C zTHHDXp3Qi@!YlM=>lMKlPiO08iz`CSwhSSiT+~eIuU2_4qb0`I=2DJu(sA)Hl?lOB zJQ}3APV>a!aaOT+8qC%q6 z=&8a$*~ifxtnjOs^S}P~o1S^hUyYIhFNC8B0XGZmLnzqC#c9ZCk3Z1XJ%Wi%hFn5T zF47SD55|w@xeZ4@&y5{n4;{bmp>jDW=q_w?RE|)Z-kolceZM2Ua=81J-rxN;jX=KN z@NY|CN?lT}h1+aYie0BI8OzR5QKohw{`!(dx}JZ8L9BFmt7s@VL%|JUA8OD2#okqW zVjIJEij2GVCm!A|3zw4ooz8sfF>RAsvQq8qkAB-ai-a{7hNZQFllugWl0R0H>D~6X zSL3TXGZ03Umm3A(+)wd# z+t0D6vi~p}A?>RoKDUebYP{$D*^Y!dv2MF0#Tezb*V~|uzdI|5UOhvZK0%TEUUoE2 zWAEJDoYi6#mCsSBY^vRiVlb5(teof@Y;n(N;Mg?hE*><<{te6-@B|}3kGQA8k7ESy<#LU00P=eNO z``=^uyt3(y2Pje+yQCZ)uWnBk;}cXHSS(mmA)%l|MMWF1M7)@}5dL93ZO!+)zw-!5O6oRc=ddB;uN9k~kSjC;xzE;oOt1-x9X>g+Z< z*~}(L^TP?NLjC8qwqh;k%Q#A^-!-fCeGCjXGnA@1yl)3dy558KFSdJ!hozf{J|rzI zEm^9UTQn;-+k)^pEFs9sro<<4@AC*B?>7TNkT1I|HR%mHJ6sqa8QfUjPbY=!T76$( z9~*(s#-i77hIzR#P*)dl+}i}NHl1(O>sUn*a8*UD3va-|z^a$)gIvM9Q3M=is?AkJ z52o{@#lkHHey>4ue>E_dKwci~aQ35lNot=W~ zZ7yyE)aEuWS9`-5oY3ZqYIP>1Z7wI_;EJC{;5hZ9mZPt$P2irM9@dtLWX5#6wU%K& z@Kmm-lvJoBa5Gl`+{r@aZda4lA`?6N9B4}gtcnfX0`L>c@2%DBzH0p$<+RKFlKd@! z4q4pq9l|DXu}ZI9I3PGJFeK!VFf#E!8i0~tcKUeX!$CxQKtf{Y@RR~VfMj(kCymVY z|2rk9^L|IK8_24B%n;;3Y`5O(WVT%QLl)cb{yff)sB{;BzMv!&f`O8Htqr7_!73~wbqCS=iR}XsL zdpsQ#k0vvoJjq-BZL?aOcvqW7HeL zEU364DJFKd{v5M9{x&U{-}&Mg{hD*TXX#(P*7bf(ArXm5aQOE6oJ6O-Rs4E2y1@El zq=j3AefsOcT#s4g(`$81EnloE*}8*s1FtO?${tc@{e9jIz9nBkx1;6e?$fV@YSY}iX_*}4u$vsI`bRx=8LDj@>hlHd7e_sT7 zVAk@!^`>dSXg*)o4|m?>w>uD((W$d2lqC9_+PF|ivMXhol=Q+pe&%?-{9r5S3Iu=S#htU9pt%SRV za6J77FGigv%NfdC&s)p>aIBc{aPprKD}#2xR(`zNHy(@zFV~yx4j`p4>CK!8ds$3f zMlgS7)@yT~DHui~;2cAy1`fHmS-cs&-|!MjH>8L-=Ces9S*#{`x!St9VMit)ry%Eb z{<}n(D_t62xU;hhpr^+yaD}N@SRBqbK%>b_AjezQK|KTJ7t8D9ai9vSl=Fjq(hr{> zs%8pD8*EmwwVYD;y!L>X&1%z?K{|)k+4=eT4o(uSDz-`Q?cs$giQkLz{zy_Q!Ix%F z%hiQS(GcWTPjH$07f#M9pJ!ww0(P2jWop*e3^59F^70_}%bno_Y7Ub|+t;?fzWlZ7 zhx<)Gmy?a#Bu#xEa3h(Zpr8jmmEynlRA3^_FPHQo)GNRugCN_|&2!dPo?3E=I?p~E zZa{~%l3r1SDI=qsmmmmnIuMR(~}Wkdb^5z@Aa@cq$E{5uV8Z8|r| zxr%RA7h5Sh4d&a2hbgtL=CxX`XKOsh1J26Q^Hpqnjbx(1$m8hXzN6V<1NZI6e94## z3No_X05}xiy|}FJ@iFx=R&G~7SD4J;QEkUyv9|6Djhhr$+!SwvB$hMB;N)>RZm?Z% zGs7q}L6!R}H~89R_8wzg`TO@0aDl3g2NhC_hAreTpU=BuNZwmvK@Y0G#}Djqd{%Re zdLv1?lMF?g3pFa!7OM>?&Oz96e|Ih@zGFByn@t)_Pfyz#@bGm9dP4_?;OIBo`gnVL zyJoF`4Mo7YMe>SVG{c5w_`6sIn z-6K^rG6|pMv6)^>pKelfbBzdVN#?@v|SFVI2_H~uJiGrD+FbA zQ$oR+r}d!GY7wX(_2@SE438x(zna}#1!46b{!o4*zFOD%r+!scOe+u6<#9bA%Zwx=BXi|zW?{hPxHsgG9kY9{ z%Fwx#C%$QMtrswIr!`s>1P>*Ddpu9AkkMc|-Zqj{b}`)eWAp&Wz?+PUO8hMRzcFGv z84-a#ni}eNl+tQcLuD@};lkUf9cDfJ4zHZly%X({D5M&V==^nBc#&IWbP85{1YBa^ zb}xB37bJt3?7f#!HI6d-)xvD0cH`CS{pN0$Mzy{%0GKiSS0CZ=or^S9$~9Idne^H! zbecQG!q9c|(^&T-ILb96&~%Zji$JXaP9-Sbv^yV>cXQ&8rSmu~{8kjAYB<1K3+N31 zK6NHG3>MUK#p`mM*y_}^_qQiW4i_8{gotx@UyOMTP#-8*WK_1C(+FJ;R46N(5lB^r}Ut89WB)w#}ci)+L<9E|clH5yF{J^?C+-S15oJ*S+=V!iFQ?N-QAYJ)f^ zy!@v?1y#;TND@7X*C~sy{qvm-uq$C%1OBUE$~8wDoW=YhRO()TnK*5E0-p=~yc>92 zCtAu0Iqj>fjOe0vD)qH6?Zc$=ETz)-FQ3XucZG~R^iX^F3%Lk+oz4GF<-RNe9Enl; zrm|>n*-9CC9rDhyEx57s+15c$jv*VzuIu_Pi9SVK+tn*+;(KiefUNHmuaY@&!Hqy+ z7pWFcAScO&%!h!hE4CXRuW_8sH{<9lNPO5W2cwDdATw*P%6w|%QdzToIHR9=6|x0y z57O=IkE03Iz0Wthx_}Mzav=0#?{05z58Kv>^b38{8NA~1H+GTdYOTrUB-`(-_R;A(c@9% z2~unfG&Hn1#_>^c*7hI{!|(f(>Mm@;Kg|CoTXfsjc1GnUVJS#hhrOIK+JkwxXqrV3 zZQmOTWF2>VW+H!K#Rte#j?5hUTlC6KtqMtO^qRsDT$PYy)NX^-98MUM(? zfR7zcWKv_pI2Jl5m7FAGJ2*JZ7Rev-?tr}9%qFukYZW+wmYK=-4l!0Gz}~=-Z2WfDHztO5oX$x z4xKqbofW?fzfRXMZB{5l{`&Z9;34(C)E7Pa^ElgUyZJP^2!n#j@tnn7ttDq!2iuRK z0a2A^+x7S7uEPfdfIwCMB=qV}94eGe5qy7PtC~l`e^6O%vZ=>sr`qs;SkB4Gp;axq z@c#pli?K8gw(_?Ow+)YG=>+I#_0I}v7qf~&`_AV;VaIkYt|Y{rQ+Q!5=qom!f375Y z65L36Z`(g)q!i>_h+y9&1E`kI!i_W5QzbW%n}q!`i&B zjm$q~DG?H(8M;z8hPHqgwRZ3E$xW|8utm!#5JXz`MqTipkB*J>qJl=&nE<*{@~5A8 zM*fJ1fQ%dXhkB`Nlxq_Xn^73NE=KRq!(ZYkceVlIvzUQ?JMsSj1ux#hCP1qSUi-{< z(vM@X=O-g8`wDIbPq44!v6&VW6`@r!F)_U*X&Q{1{t6#A0~U(Kdg;sM36p-u??OaN z?V=*9tB=z1`ab*n7}U{+=5S%s-!qQa@mlkuvW`)S7wwd?^Fyx>C#k5Yu;dhfMTBYb z{~Qq*J5TlM1?iTll`?n!?uh{y)DM73v>dX9?ClLF82E5xzdvomk%X_Yk=9Rj%TWmm zzAc+&?@J`_k0$Rs#}@xb-|dIvQ%}i)b)qkDe*IylYg*k=_YH!CK%}3;L#&-nOdJr8 zEr6hPq}l7FE9x}_&e}VtjQj~N0DGgp;?2XCrwvu%Tl#3YYS8XFUa8YOaCYkd5_bMA*xXGMksO6%7ukXCpb6}5fKRAZ>w})~ zFUmFnDhvk`mHg%0Hr8gP!DBay>ydpKjf{fA#DhZy%B%UTQXtc!TC z(Irkc2N^K$!DV|Kq?VM>Y}pcG!fA81>QhKYd%is$UJB!4V;@|MoGeyTL*GE)-~ivP z{Pjoud(DRrA11plAg7f$9xb~ynL+GJMxdNe1satr+0l5<3pHF}_-Vi0Z@@;qMe^BI zG~t7fI}PPn5zGUAue&ju9Ol$dEqx}q&n^kOEVWkQSoBRM!}lB`@J97NWwK8y3J%q z!_NAnx%B_=+LqyJ1G8R}82KH=h4&#eO`g~L^>(FGQ7eAdfevRXg5;#{;v<@hXjmgL zEPEcDr-;aLv=I&jg7wp5sES^eaH3}XQ8ljIA)tXg-5iOApg6dcdEFB)r$!+sd4c7n z8UCcyJ2e!UF*S0%(XN;c zs5#6p2UhV?^|r4omTct~LyXTuQ*Uo43+03KM1=(fa%t=i4;N^6Cq=!?SR@8xW(ivK z=i#vK15wW}4*=jQW|2w)%|N5mI|!Kcyb2WiQOsED{7NxspidW(UGl=!h zs!U=Oo<#lhp3dlMP%07?t&9}K_EA@UxzP%Txc~zT??--ZE6+q`tU9-|cbw2V$SY;v z`N(Z1Ph9p{M$p!4)w&9Ugv6jS?ee$Z%Vh{XmK`{Ir+2#-=o`J~kF$z{*6UB@W?+fE zx6wq}*#-;MH*o`BoixzCK$Stnm zw51r^7}3jsu3b-fF?4iv1RSPQB4bp0#(ITl^?&_lctYl6TwU#Q!6{C%hXCIHlCj(m`EIMx7v=Dq6hV=xJ345V6gou=cI#^F_^4k>j zE%1oI=E-H_+3m-kFQt%t!xGY|Hi05VsNhi?e+O_wZ*jFRgWb>X{b<(g zLhg$^EDEtVFn(u14D^Pe9JV!nRxOe{nk(HMNuq~O0U@FI7D+92%B6<-77mgsj;&qo z)5~SOzz98Tw!Z6of#+{-oF^B`Hb7?0ADbPYa_cO$9DeNm=Q|{RYJjX}%+eoT?=iu1 zr%*P3HHJ1OXaqm@mT~xaQ5k@WHSJVBAmc(xI55$+av(@c6~oigvBEqwq_cs<+65V$ zQBh;C$zfWqw8bK#G<=ju@v5~O)95+;^snewcttff!DH==!Xk7@mUih5osQCs?=Zd%uh=XwtyXzU@7kdbj z+Rx%T#Z(LN|5|4Si)_8sNeku)W zhhAXF49_c;{lZVpkj;j(RWA3x~?w2;4qysw*CgAUI{?R zBII%8=J9>l>?QHOcx(_J2t_O@}d$Z07HkJ?|_!+gKes27=-x8wuk)yWOsY}sN-Rd|nJZ%!ovND#(;cq*rfx zU*94Vt!S31U0x18d%r!l0J5)shx>G{Z$>*zw8@R;UB3yd&t*SOV0--74j@7RtKA3Y z#3=>?Fx)qdg{F+_o>!oC2NyhS@|7X1@t?`wFTj#MzOfcM-uhUm@0{|Z3;b~L zD0-~{(c>t2Y$+o3$iXe0g{kP~FY^S!)qudV(%*$?r48!+g%Ef7i7NvGWCcheo3{}lnX9$-kUqK6Sm3SmuJbAVJ*nlo{S{yg zZ?aikX*@CKZR;)RVYp2*3keL=x1HSS38E;P{QbCO42n-kxarQwV7K4$C-K$7BPK>Z z%}{1a!y0D%WM|0pWE>&e4{VkN|g9f8xi`0Y!)Jwchz z$L|vb5mRQGaz&@!L3gEp{`~n?Z{~J9cX_tn9(d$%Ar^Y8J zcW`17aeAuQ+kfne@^U+0c^2R=*IaLRL-~?TYzxv_5xBlPCb8w`kU%sNfq_d=D|+wVy$!Z_Qm3T1I5 zW8PXE@`DY0Zn5B&$QQ1zo@Cp;9*>_zA#FIs2;40>P2L{*tv6WgCej+1@H?^+xfI+H z8ITWE3=dPYE|ABj_No$=*ZKeaPh3>Ds0|~#>Pa~O5)fZ$2!%sQxH`VC4|2X=KZgp# z9aI{2;H_k<{X*J9z2x2??_{j>k%vgM)a>f-gL#W{XxSfjoxn_cfou{(2`eha2@CH8 zq*P_+Dt!=e7N~JZnCOdw)Cz95PzsZQ<3Rc$EgBu>5sH3`J@inMvE;M+tm*iM$Kkr7 z5Rqu~DexQp03Ee!I)B|4+G|m)2#Ek6Uz-H+@fL6cp5GqL05Jhz;ZwY6*{<*1uiL#s zOKrD{(g~kKf`VFe6TSXS{kRoZ;-#-+4+7(vZ}{AUfb|3BrU=4}FGk+LT%g@-yL*=; zoy54~JfqK5We^h`?fS|ap4VWvDcmPA@ubODRd&qW^%9?zHBbq~w9q{o%_I6xgGFH7 zf&3QcIkakzxTW37i$t8KSWQOXzbLdl`$)Cwvd((bxF_qz@G%utEy=s!N=U8@@p0Q= zh}mc^WS_(jFFsr+6lYN+kuIK7a10JZZq7t%k!KM@9gpsB^h#b;6F!tfRuMiLc0S1W{TmK>KI zzzXn5RE#J@yS_NQF&;u+krw9aLv=iRzP&asn# zyeW)uAN{$^xdV85xDY>D8nAt=I@ECs2XeMYl6#V%C!05_)mE@Fx zNR=}ddalrIz2aB71l?}{6=fG=%-Gjwgb`L)I7~o7k`2s!zW3`ptxktlmh3{Rq6YP5 zlTGhAIM_QTWHTx<8pSoDa{%s4r`DUMjtlNR0P2l__a#h*;_n}FA`{iB#mLP8gm3pX z^i_1}amEJUR=0ZFYYH)D;fU% z2=dj%QLZdNMx;~?E~Y9lF)2RBc78B*GK@19cnbQ1nlTmhjg5wuANI#%cfGlReyK!M z+DmoU%abgi!zy6nFJg8o3gT57Rl;Ko0P4AirDfT;9^gVOOisoOqP^ZOX7k`nzg#CX zzW8MFx(Hy2N#ZlIvpX+TEDQe>-g98U9tFw?u-Q)UU^4qrR~}ybut)!Zr+|(`;d&7$pU?Q9Q_bd! zax!(R^#zON4u)U*@OZH9dHX87d3(LzZ#pel)r$d>2bpfQnPm3nd&okfp6hbLYP1{_en zN5p`Vt(n3I01N7nhMdJ4V&t;;r2|U$T()~)o}2d58crCoac~q7SQ3b*4JV_C_y`51 z3=L!L#adlXii+{W6GCIXhLX$&Ug#A0ANO`+?qL|fmbb_1P6uNS+@&_C(c`ccz#+i7 zwC^W?l%SX`XcKb*9xSLQU%@*)3k#F9DPiS@5i0~Zj(B)IO#L5d4AUvhKyTd;xU%mm zbOIa=n^k@UU2H>yXCbnpz>WCAXc^)=J2!30d%H9S7uw)LazJ}|%jEV1P zkp`Ebp6}AJKBkuo+)H(3zR&qwvn4E#Aw9sDRbwX=goX}bGip0B9zGXt@~MXDHb+Nf zv0Ry+EZDrzqob$6!osc?w5k>>WFY#^m#G8Z%qV7mE8IIkeTFwROO%uYBzUHWz$=X; zS83h9K!AI$kQ+zU!eP|&5QgDWopaab_*f?z>@TMmcefD?_^&{Thz8~$D^i%i6XNKB z9OpsNHDa?1PKs3;$NS z)GXSS>6I3lMSzPXx&sS}Id{@y#OQ_L@Yo5XZcPUK!ZbidgF5UpsA5k31F!IPI0Au!)``sIWWc~7_tNp=tmID91*EgL7mt@kfIu^)YcWB2*bK#LRBAg> zU5zpyR%q3d%W9Ga6}QfKKaOCTdAbgSj^;M!0?7zMsE92|enx(NU8ud6q3J%cEp1K( z*np51e%Djndt({|N|=#?7CZmCDsvoMTyCGIPc|YBUvB|JX(E&F(4>LlSvJl|?(?jZ zdvvTYx77jzv74n(gDwd=r&&=^QI&QhovPI5e;i4La_x$HrKc=bdG$AUU5=u;SnoDl z)=K))1*ltiI=Af*Rx=2OJuA9^C@x<4ap9|!Gs5w#F)xqdZw#eAaeOf$Q{>xnj+}dp z_IC>&4{1X=T4;GrZSkKfqkZ>j4L}w|F13yjEArKup*fN7+M)FgE3E<$*ML1IrZ?Nr z+yq|Xc~SfN6_Degmaq~nW{Uv7mo~jE#b;z>u2fZ3b#}-LNeVCtI1baay_SGMH;G0$ zp2P#_e`3kea{YsYA>J7@;~^*{uDC7xS?$9nDi29MV}jocjW5R}kO(gC`$Xf3Zbq3q ztriucp@HusFT*cA{5E&63wW=-D-B29BI}(#W?O$gPzJNj#)@19>c`w7d}k>HH2f?M ztIzhB_vd-(qeZ&7JS~9P324MWoTUCIP6*#z*WrR66ve_ttW1!5)<5mWk-Zh0CMxK0 zRlPed^!%kmh6P_$>i6C)oeBcP<1#4drh#*aP=|L!#UWz5tv?i-W>$$BnyjCKpo8yk zDk$t$C=Cx+2Qp4Xd&r#GLSo+esd>{kgkGP3^R2`}h#ab&p77Je-a@4gV6P+_w+=qv zFsc-UvMt@+%uZg6bVy6102UMQXmo43oIK<ZEd%ge%`0#y}QWZbXrIC?L<`ogjafTw7Z(_tF+=PTbgC_CMGCVbVzX8&;)V3g@q ze7+pK)ebRjtQ1>QV6xpE2fU>GwGe*pV|SE)DmkEgnTS|a0~(pn!!}&%ijsA(s+iaw zeRbyuXcmBz^)A0I`EUG-ny?PiWasB=t)e^DJjb)9Al>Buz^{kV&N|(nlH>zAq2v|Y z$0<@lJRdIB$0rT%r}2$0VsGc&l@UeP3-~)K-0_0;4)(F6F50e-@UXU@liPwIj|3?~SlDM7AS(zFf0eImlzS(RTJTDQWCl7c5Q+!#Bt}Tt)M2y(U+%_SyJUC&=kg z!I9)@s{|v4|6cbUD81{rCg-D>>aMquCkmM&i_R7Ckrd`hy6>d{u*h3MJ>V{OS!DY< zG2IUL48De}+*#~F z7J@1E!TOsw%}Kbk@(j!|2Ge;gdy54HaFhJkH^5H)x=_C@{=;fzt`ums^P=BtEndLQ zo3#2Jfl(trdighiybR!qUOEX9aJg>xRM%Jg=(jl^g;780fn1XaQIL`GgnS{*dYvfn zhF#qA^)zPP;6C9F#n=HBQBUCIr}+{*iYiWf?(3xTP`}df=eSC&e-!q@jhpDsvc?PdyqsQ90NX6$} ziyyoJ$4%Cj(BPnk$vVWcw4&9ncPD@+ItHLcuSG6!0Qnug_Jy3^ z1nlOqLs%A*N>{+D5A@+GdH;!EzTlnv)(=|AM8Ulv9|Qs62;kB)f$(@(svn=Xwzlxt z%z^_0(Q692PXVyX{KOyJ!kWE;MX#R5`U9V&Jmg(quKti>4G#H~b&xd)NavtYNB~4F z?1k6$)C`!UM-6}e(-Qyry!)TFSm^|XPXxx7R&$1oC+H*|gK$cpPFDpq&X4_W+*glw z=>=ElNO_@A_oesuTWNy$*EeXYNoeIzA6$oNjjTp-p3AQKPMV1CY! zru+UOSs^I0PWxpf5CsZ-lDMk05W^7qImKG9{ILZkd)cjKaT4yhgGaDIO`J&Yh?@3+ z+KwrxAq!c~At3ce2xsl73>j+;5dHja=X(IxF;5K$1h(644gx^r00bO9VbVV9J~|yv z2t1#@JBZ69009fRbk22a&UQ#U_MzerUBSO|f6@f8nT^jmxBI<4QkUZ&0&q*M@O!G! zDg_Z|;yOrm*5qnDI0n-I$iN#@+AGm4$6iBP^{hYW2P~>!` z6@z-hl?dKSh*`gb+y0L~Fa}=j0!i07!y4SL=Bm-6e1LycwB9jnLO%E|aCM#^bJuYA zGIYZkO(L{WZD#;}dyEUi`0PlU(tZGYcmNgD7`(&rX^RwukW*1N7mCrOR;mJM==%Zk z1YT>)KPoy>^;&_rR06f)w&X+x&w8oqARb$hRs9%jwiyEC``fdf%|}M9uRJ0lNM6Oj znvla4iEaH)szf6TExRU^HAZmL@d;(}l<)b0SqIdR0pXoxuu^UJXhbIp>C5wn^MDmM2-E`_w5Bn zz)Nr>sRy`hE+-3xfHLL_h#k|j`xSl1e($ebfW;UX_!&qDkT&PO&fT;E`A8sBc2`B$ zj_PQ$DiAMmnE_NeV1=(%I6FN>9UTm3~>Hub+DSLG}`(^i)n=nLqdg zYxE|@6+BYSVHR6Lm)(5XypA1`lOuJN{$rdZ@$_d?b93Cs`R}!nc-PYPMez84dHvop z>bocHL<2lln{B+#TFty}{dHxE)34%r{l?5)=y#=2J5;r=HPkea@PVX4@m|BL9Sj8V43zHk z&%U3bq?b-@T@9A*$Gx64l2RpYJ)c{A@iIvChV-g-_K#g1R4@S?0 z4`L~g&R;%ZO)t}DYk|l-#fhtx!p&^6mp1s6a=%*Kfgsb8l7Nh}(8$Q$)NGX$<1D)^ zka3)(1Tp9|MXEiqvCd#%B=q$5ii+CwiV}PZ{`vOSbjOKatIIc(l$?CF@hZ7^g6~zy z7oSSP|M0fbXf--AA|V+h`wAGULX(+%IM~=47tX?GW$J*w1kgg014>vR88W-1WoKX@ zIXJ(9*jQ=9Sivdn#U^+?c5rp&HfPzmSjfkxxH8gwbK`RvG}>XSGR(fby!^beeBZwL zuF(;8V7(PzLAi_%h+icaJ*Q@UMUT}6|;>%NsUV88c4RMRu#CvK9Pd8U$pHT56Wfx$!5AT!CE-Ne>| zm;Q=}*XL=pdBd~5=)mA6;!~ZZ)L-&utkiFSwXQf{WQoq6Yh-lS{aOhda0#$OF1x$A zMK14WFqg4$K7%M-(nwt$h|l#j$0<585*3}}EddIG)K)-l-dw*06GyQ;rpG7=#ZLt% zxkUc;h}l|FcXZ7CeVp&sMbri#t(BGk>65bt zUtq7`AnXXv26^<9;QYHOhi!>kS$KGWxVR9Hd(F;Fp=?E1X?uHladC*#CX9k^x}u`2 zpV#8quV0XE9um><@iX%2oJ71gMnCqakB(@yg(;6t#+KO(vUtF)_#>7Hct@$#uLq50 z+3VzH{vkZGi7gbVFNgvWeszo3DT%Rk%+j>_2Hfo{HdINAp#A-z)h5vMS!ZytXH#i$ zF{6u1BM!4Zrsg=6j>Od$cFLPYz>S=d6{7AQyGDrEWPMD{erK1qeZD_`KdtYo?{al@ zjZJ^)x$8j`@&y7K80hHydo!(^5h5?JKA|MnAHU=!b0Hpf5!*&56jeA1#`GZXyKf4u zP^OY_UljifySuET`i1Yue33RwN=$U#8=3|NBsDd)P&Xf0D>fStrjIm>q(#Af_G;ZN zN_AIOe0+}#5dpfyj5RU@M5vC?sbvG|Pjj!NBsX1%C7JZtzuUT(S|z-Xw2rHHY}-nb zZ|oMF&ITMCrx`8RuYdo5!`h*W-uMo>bK&zH9G$%_U)~ZgJHb~YJr_iGcWeqn#;0oZ z*qwiKlh@RPp=ko3ASpzCsiEb{CPPb<6UTf*Cnh0DzEBgJxw@d#GZee2(5}uejB*=G z<&3%%3C_3cpS}-1bVru_8#Mo3Q5E&+@$nH5CfXhMW#+>$)aTVD^1B=3c@Nouj1v>^ zWMqe3iG}+yy^ITO5QUJj@$TK}ay`I8FbupMUaohEh%~4#5gzvKYQqao-}f;k+xKZ0aEgLMLQHHE zLPMp{w`9X3X4zONg-5MClxQ&HxrQDW4%n(+hp-Q0@aV+60`Ikvc|0iKM*MJ0x&Vf2 zkmdI#iGgtdGZ|iiyG#)T6qmI}6`*;P9YfQGtEwjK5K+=bStAPzcLQ9AnTct5d^{-; zTv9Rw<4pkt0f8b(=@IA^K5N+Dc3*4d4sR6dra-+`{2@3qj%u!%p{e`TUBR8E!(@P$ z#bNUcyUXU74#Pn$ny={r3k=r}&TposiDX81`&T3W5I>|^$Z6E@@QHDWrFG!@LR1b# z2l210<^T4$=c-Q}e~i5wV0<>mZ^{=`E{>WNI1%ov8z@u%*&!0cve7CQZy1Rw7D-{k798(OJ zdjazdxV1*Z3D96HbagXMZuH$`bgZmot*j&^;g)d$w%^9~#SovXwxLu-ynMJ*dg`yU zb|zDl31b~;S0Wtm&;IWgww9LW*47plp9_Cg{Mp(fEp>Ie3r=ilDa4QZOiL?WJ*gj; znwpt_fr`3i`|PeyxU6e(P%+(`g4i8qKuk!Ok(PG+1F^Z07E@%^)YFr<-Te>b*w|Rj zrTCD@a2|LayjEpqW(N0&Ba1^sLc;8~>9JnCCu;Hqcj4wm+m6-Iz4j9yAepW5VM3%8)kN@_r&~@yO-YD&H@t*yWx&Wgwe^2ZIya zvIY`+<9~ft@bP$FJB|CxkLeH7#g`gnbBQoRZe#M8sr~Bs!8R3UKBZ;9Rjr+#xC-N; zwgdtKVrKygNjLg{T(TVvoVjB?UAF?K*&LN^i-q)Em|1}eFJhGE!#VC+|?H$*(Uu zF*n)~ui2QeD7!WfR3?He**W3}?$=LkCPsW}rm1e4=)@*RFc1)ZjKJ4{fbf_6AkhG9 x9pLqK4f6l<{r~>-|MmX=-# - - - - - - \ No newline at end of file diff --git a/ext/custom-addons/cam_customer_pricelist/__init__.py b/ext/custom-addons/cam_customer_pricelist/__init__.py deleted file mode 100644 index 9bf10d74..00000000 --- a/ext/custom-addons/cam_customer_pricelist/__init__.py +++ /dev/null @@ -1,24 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# OpenERP, Open Source Management Solution -# Copyright (C) 20014-2016 Camadeus GmbH (). -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -# -############################################################################## - -import cam_customer_pricelist - -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/ext/custom-addons/cam_customer_pricelist/__openerp__.py b/ext/custom-addons/cam_customer_pricelist/__openerp__.py deleted file mode 100644 index 9455a401..00000000 --- a/ext/custom-addons/cam_customer_pricelist/__openerp__.py +++ /dev/null @@ -1,39 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# OpenERP, Open Source Management Solution -# Copyright (C) 20014-2016 Camadeus GmbH (). -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -# -############################################################################## - -{ - 'name': 'Camadeus Customer Pricelist', - 'category': 'Custom', - 'version': '1.0', - 'description': """Prices per user basis""", - 'author': 'Camadeus GmbH', - 'website': 'http://www.camadeus.at', - 'depends': ['product'], - 'data': [ - 'cam_customer_pricelist_view.xml', - 'cam_customer_pricelist_data.xml', - 'security/ir.model.access.csv', - ], - 'installable': True, - 'auto_install': False, -} - -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/ext/custom-addons/cam_customer_pricelist/cam_customer_pricelist.py b/ext/custom-addons/cam_customer_pricelist/cam_customer_pricelist.py deleted file mode 100644 index baa6ff00..00000000 --- a/ext/custom-addons/cam_customer_pricelist/cam_customer_pricelist.py +++ /dev/null @@ -1,256 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# OpenERP, Open Source Management Solution -# Copyright (C) 20014-2016 Camadeus GmbH (). -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -# -############################################################################## - -from openerp.osv import fields, osv -from openerp.tools.translate import _ -import openerp.addons.decimal_precision as dp -import datetime -import time - -class product_pricelist_item(osv.osv): - - _inherit = "product.pricelist.item" - - def _price_field_get(self, cr, uid, context=None): - pt = self.pool.get('product.price.type') - ids = pt.search(cr, uid, [], context=context) - result = [] - for line in pt.browse(cr, uid, ids, context=context): - result.append((line.id, line.name)) - - result.append((-1, _('Other Pricelist'))) - result.append((-2, _('Supplier Prices on the product form'))) - result.append((-3, _('Kundenbezogener Preis'))) - return result - - _columns = { - 'base': fields.selection(_price_field_get, 'Based on', required=True, size=-1, help="Base price for computation."), - } - -class product_pricelist_customer(osv.osv): - - _name = "product.pricelist.customer" - _inherit = ['mail.thread'] - - _columns = { - 'partner_id': fields.many2one('res.partner', 'Kunde', domain="[('customer','=',True)]", required=True), - 'product_id': fields.many2one('product.product', 'Produkt', required=True), - 'unit_price': fields.float('Preis pro Einheit', digits_compute=dp.get_precision('Product Price'), track_visibility='onchange'), - 'min_quantity': fields.integer('Mindestbestellmenge', track_visibility='onchange'), - 'date_start': fields.date('Begindatum', track_visibility='onchange'), - 'date_end': fields.date('Enddatum', track_visibility='onchange'), - } - -class product_pricelist(osv.osv): - - _inherit = "product.pricelist" - - def _price_rule_get_multi(self, cr, uid, pricelist, products_by_qty_by_partner, context=None): - context = context or {} - date = context.get('date') or time.strftime('%Y-%m-%d') - - products = map(lambda x: x[0], products_by_qty_by_partner) - currency_obj = self.pool.get('res.currency') - product_obj = self.pool.get('product.template') - product_uom_obj = self.pool.get('product.uom') - price_type_obj = self.pool.get('product.price.type') - - if not products: - return {} - - version = False - for v in pricelist.version_id: - if ((v.date_start is False) or (v.date_start <= date)) and ((v.date_end is False) or (v.date_end >= date)): - version = v - break - if not version: - raise osv.except_osv(_('Warning!'), _("At least one pricelist has no active version !\nPlease create or activate one.")) - categ_ids = {} - for p in products: - categ = p.categ_id - while categ: - categ_ids[categ.id] = True - categ = categ.parent_id - categ_ids = categ_ids.keys() - - is_product_template = products[0]._name == "product.template" - if is_product_template: - prod_tmpl_ids = [tmpl.id for tmpl in products] - prod_ids = [product.id for product in tmpl.product_variant_ids for tmpl in products] - else: - prod_ids = [product.id for product in products] - prod_tmpl_ids = [product.product_tmpl_id.id for product in products] - - # Load all rules - cr.execute( - 'SELECT i.id ' - 'FROM product_pricelist_item AS i ' - 'WHERE (product_tmpl_id IS NULL OR product_tmpl_id = any(%s)) ' - 'AND (product_id IS NULL OR (product_id = any(%s))) ' - 'AND ((categ_id IS NULL) OR (categ_id = any(%s))) ' - 'AND (price_version_id = %s) ' - 'ORDER BY sequence, min_quantity desc', - (prod_tmpl_ids, prod_ids, categ_ids, version.id)) - - item_ids = [x[0] for x in cr.fetchall()] - items = self.pool.get('product.pricelist.item').browse(cr, uid, item_ids, context=context) - - price_types = {} - - results = {} - for product, qty, partner in products_by_qty_by_partner: - results[product.id] = 0.0 - rule_id = False - price = False - - # Final unit price is computed according to `qty` in the `qty_uom_id` UoM. - # An intermediary unit price may be computed according to a different UoM, in - # which case the price_uom_id contains that UoM. - # The final price will be converted to match `qty_uom_id`. - qty_uom_id = context.get('uom') or product.uom_id.id - price_uom_id = product.uom_id.id - qty_in_product_uom = qty - if qty_uom_id != product.uom_id.id: - try: - qty_in_product_uom = product_uom_obj._compute_qty( - cr, uid, context['uom'], qty, product.uom_id.id or product.uos_id.id) - except except_orm: - # Ignored - incompatible UoM in context, use default product UoM - pass - - for rule in items: - if rule.min_quantity and qty_in_product_uom < rule.min_quantity: - continue - if is_product_template: - if rule.product_tmpl_id and product.id != rule.product_tmpl_id.id: - continue - if rule.product_id: - continue - else: - if rule.product_tmpl_id and product.product_tmpl_id.id != rule.product_tmpl_id.id: - continue - if rule.product_id and product.id != rule.product_id.id: - continue - - if rule.categ_id: - cat = product.categ_id - while cat: - if cat.id == rule.categ_id.id: - break - cat = cat.parent_id - if not cat: - continue - - if rule.base == -1: - if rule.base_pricelist_id: - price_tmp = self._price_get_multi(cr, uid, - rule.base_pricelist_id, [(product, - qty, False)], context=context)[product.id] - ptype_src = rule.base_pricelist_id.currency_id.id - price_uom_id = qty_uom_id - price = currency_obj.compute(cr, uid, - ptype_src, pricelist.currency_id.id, - price_tmp, round=False, - context=context) - elif rule.base == -2: - seller = False - for seller_id in product.seller_ids: - if (not partner) or (seller_id.name.id != partner): - continue - seller = seller_id - if not seller and product.seller_ids: - seller = product.seller_ids[0] - if seller: - qty_in_seller_uom = qty - seller_uom = seller.product_uom.id - if qty_uom_id != seller_uom: - qty_in_seller_uom = product_uom_obj._compute_qty(cr, uid, qty_uom_id, qty, to_uom_id=seller_uom) - price_uom_id = seller_uom - for line in seller.pricelist_ids: - if line.min_quantity <= qty_in_seller_uom: - price = line.price - elif rule.base == -3: - ppc_obj = self.pool.get('product.pricelist.customer') - ppc_ids = ppc_obj.search(cr, uid, [('partner_id','=',partner), ('product_id','=',product.id)], context=context) - - ppc_best = False - today = datetime.date.today() - for ppc in ppc_obj.browse(cr, uid, ppc_ids, context=context): - ppc_start = ppc.date_start or '0001-01-01' - ppc_start = datetime.datetime.strptime(ppc_start, '%Y-%m-%d').date() - ppc_end = ppc.date_end or '9999-01-01' - ppc_end = datetime.datetime.strptime(ppc_end, '%Y-%m-%d').date() - - # 1) Entweder es gibt noch kein best oder die best min_qty muss kleiner sein als die canditate min_qty - # 2) Die qty aus der Zeile muss größer sein als die canditate min_qty - # 3) Heute muss zwischen start und end datum der candite regel sein - if (not ppc_best or ppc_best.min_quantity < ppc.min_quantity) and qty_in_product_uom >= ppc.min_quantity and ppc_start <= today <= ppc_end: - ppc_best = ppc - - if ppc_best: - price = ppc_best.unit_price - else: - continue - - else: - if rule.base not in price_types: - price_types[rule.base] = price_type_obj.browse(cr, uid, int(rule.base)) - price_type = price_types[rule.base] - - # price_get returns the price in the context UoM, i.e. qty_uom_id - price_uom_id = qty_uom_id - price = currency_obj.compute( - cr, uid, - price_type.currency_id.id, pricelist.currency_id.id, - product_obj._price_get(cr, uid, [product], price_type.field, context=context)[product.id], - round=False, context=context) - - if price is not False: - price_limit = price - price = price * (1.0+(rule.price_discount or 0.0)) - if rule.price_round: - price = tools.float_round(price, precision_rounding=rule.price_round) - - convert_to_price_uom = (lambda price: product_uom_obj._compute_price( - cr, uid, product.uom_id.id, - price, price_uom_id)) - if rule.price_surcharge: - price_surcharge = convert_to_price_uom(rule.price_surcharge) - price += price_surcharge - - if rule.price_min_margin: - price_min_margin = convert_to_price_uom(rule.price_min_margin) - price = max(price, price_limit + price_min_margin) - - if rule.price_max_margin: - price_max_margin = convert_to_price_uom(rule.price_max_margin) - price = min(price, price_limit + price_max_margin) - - rule_id = rule.id - break - - # Final price conversion to target UoM - price = product_uom_obj._compute_price(cr, uid, price_uom_id, price, qty_uom_id) - - results[product.id] = (price, rule_id) - return results - -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/ext/custom-addons/cam_customer_pricelist/cam_customer_pricelist_view.xml b/ext/custom-addons/cam_customer_pricelist/cam_customer_pricelist_view.xml deleted file mode 100644 index 711f5a09..00000000 --- a/ext/custom-addons/cam_customer_pricelist/cam_customer_pricelist_view.xml +++ /dev/null @@ -1,117 +0,0 @@ - - - - - - product_pricelist_customer_form - product.pricelist.customer - -

- - - - - - - - - - -
- - -
- - - - - - product_pricelist_customer_tree - product.pricelist.customer - - - - - - - - - - - - - - product_pricelist_customer_search - product.pricelist.customer - - - - - - - - - - - - - - - Kundenbez. Preise - ir.actions.act_window - product.pricelist.customer - form - tree,form - - - - Kundenbez. Preise - ir.actions.act_window - product.pricelist.customer - form - tree,form - [('product_id.product_tmpl_id', '=', active_id)] - {'default_product_id': active_id} - - - - Kundenbez. Preise - ir.actions.act_window - product.pricelist.customer - form - tree,form - [('partner_id', '=', active_id)] - {'default_partner_id': active_id} - - - - - - - product.template.product.form - product.template - - - -
- - 17 - - - - diff --git a/ext/custom-addons/cam_work_order/security/ir.model.access.csv b/ext/custom-addons/cam_work_order/security/ir.model.access.csv deleted file mode 100644 index e20db9d7..00000000 --- a/ext/custom-addons/cam_work_order/security/ir.model.access.csv +++ /dev/null @@ -1,5 +0,0 @@ -id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink -modify_work_order,modify_order_sale_user,model_work_order,base.group_sale_salesman,1,1,1,1 -modify_work_order_line,modify_order_line_sale_user,model_work_order_line,base.group_sale_salesman,1,1,1,1 -access_work_category,work_category_user,model_work_category,base.group_sale_salesman,1,0,0,0 -modify_work_category,work_category_manager,model_work_category,base.group_sale_manager,1,1,1,1 diff --git a/ext/custom-addons/cam_work_order/static/description/icon.png b/ext/custom-addons/cam_work_order/static/description/icon.png deleted file mode 100644 index fd7ee3b90ede569d07369b51f5036c9c0de4e9b2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2870 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. +# datenpol gmbh +# Copyright (C) 2013-TODAY datenpol gmbh() # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -21,17 +21,16 @@ { - 'name': 'Camadeus Anpassungen', + 'name': 'datenpol Anpassungen', 'category': 'Custom', 'version': '1.0', 'description': """Individuelle Anpassungen""", - 'author': 'camadeus GmbH', - 'website': 'http://www.camadeus.at', - 'depends': ['sale','mail','product','account','knowledge'], - 'data': [ - 'cam_custom_view.xml', - 'cam_custom_data.xml', - 'views/custom_theme.xml', + 'author': 'datenpol gmbh', + 'website': 'http://www.datenpol.at', + 'depends': ['base'], + 'data': [ + 'data/dp_custom_data.xml', + 'views/dp_custom_view.xml', 'security/ir.model.access.csv', ], 'installable': True, diff --git a/ext/custom-addons/dp_custom/data/dp_custom_data.xml b/ext/custom-addons/dp_custom/data/dp_custom_data.xml new file mode 100644 index 00000000..458fac35 --- /dev/null +++ b/ext/custom-addons/dp_custom/data/dp_custom_data.xml @@ -0,0 +1,127 @@ + + + + + + + + + + Stück + + + + + 100 Stk. + + bigger + + + + + 1000 Stk. + + bigger + + + + + + Rolle(n) + + + + + + Satz + + + + + + Arbeitstag + + + + + + + mm + + smaller + + + + + Quadratm. + + + + + + + + + + + + Kubikm. + + + + Kubikm. + + + + + + + + Paket(e) + + + + + + + + Paar(e) + + + + + + + + + min + + + + + + Größe + radio + + + + + + + + + + + + + + diff --git a/ext/custom-addons/cam_custom/i18n/de.po b/ext/custom-addons/dp_custom/i18n/de.po similarity index 71% rename from ext/custom-addons/cam_custom/i18n/de.po rename to ext/custom-addons/dp_custom/i18n/de.po index fbbd795a..d975f048 100644 --- a/ext/custom-addons/cam_custom/i18n/de.po +++ b/ext/custom-addons/dp_custom/i18n/de.po @@ -6,8 +6,8 @@ msgid "" msgstr "" -"Project-Id-Version: camadeus\n" -"Report-Msgid-Bugs-To: Andreas Brueckl \n" +"Project-Id-Version: datenpol\n" +"Report-Msgid-Bugs-To: Andreas Brueckl \n" "POT-Creation-Date: 2014-09-23 16:26+0000\n" "PO-Revision-Date: 2014-08-14 16:14+0000\n" "Last-Translator: FULL NAME \n" @@ -18,8 +18,3 @@ msgstr "" "X-Launchpad-Export-Date: 2014-09-24 09:44+0000\n" "X-Generator: Launchpad (build 17196)\n" -#. module: cam_custom -#: field:product.product,default_code:0 -#: field:product.template,default_code:0 -msgid "Internal Reference" -msgstr "Artikelnummer" diff --git a/ext/custom-addons/cam_custom/__init__.py b/ext/custom-addons/dp_custom/models/__init__.py similarity index 91% rename from ext/custom-addons/cam_custom/__init__.py rename to ext/custom-addons/dp_custom/models/__init__.py index 8dbb873f..b32476c6 100644 --- a/ext/custom-addons/cam_custom/__init__.py +++ b/ext/custom-addons/dp_custom/models/__init__.py @@ -2,7 +2,7 @@ ############################################################################## # # OpenERP, Open Source Management Solution -# Copyright (C) 20014-2016 Camadeus GmbH (). +# Copyright (C) 2004-2010 Tiny SPRL (). # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -19,7 +19,8 @@ # ############################################################################## -import cam_custom +import ir_ui_menu + # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/ext/custom-addons/dp_custom/models/ir_ui_menu.py b/ext/custom-addons/dp_custom/models/ir_ui_menu.py new file mode 100644 index 00000000..d2652712 --- /dev/null +++ b/ext/custom-addons/dp_custom/models/ir_ui_menu.py @@ -0,0 +1,54 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# datenpol gmbh +# Copyright (C) 2013-TODAY datenpol gmbh() +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +from openerp import fields, models +from openerp import api +from openerp.tools.translate import _ +from openerp import SUPERUSER_ID +from openerp import tools +from lxml import etree + +DISABLED_MENUS = [ +] + +class ir_ui_menu(models.Model): + _inherit = 'ir.ui.menu' + + @tools.ormcache(skiparg=2) + def get_disabled_menu_ids(self, cr, uid, context=None): + data_obj = self.pool.get('ir.model.data') + + menu_ids = [] + for menu in DISABLED_MENUS: + module,xml_id = menu.split('.') + menu = data_obj.get_object(cr, uid, module, xml_id) + if menu: + menu_ids.append(menu.id) + return menu_ids + + def _filter_visible_menus(self, cr, uid, ids, context=None): + if uid != 1: + disabled_ids = self.get_disabled_menu_ids(cr, uid) + + ids = [id for id in ids if id not in disabled_ids] + + ids = super(ir_ui_menu, self)._filter_visible_menus(cr, uid, ids, context) + return ids diff --git a/ext/custom-addons/dp_custom/security/ir.model.access.csv b/ext/custom-addons/dp_custom/security/ir.model.access.csv new file mode 100644 index 00000000..08145a00 --- /dev/null +++ b/ext/custom-addons/dp_custom/security/ir.model.access.csv @@ -0,0 +1,2 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink + diff --git a/ext/custom-addons/dp_custom/static/description/icon.png b/ext/custom-addons/dp_custom/static/description/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..8387d76554e8c52cf9256f9dc3f0358744f26f8e GIT binary patch literal 2225 zcmV;i2u}BjP)e zSad^gZEa<4bO1wgWnpw>WFU8GbZ8()Nlj2!fese{005UN6GXZYpd*5GTM;9mttz230kztuXpqw7k0!Bk-aY#xp76VI(r5cRu^;~ayve)o z`g`Zx^W&a#fjsiaBab}t$Rm%O1kLpVeEvYW6vi3`uOQG;0ObG{0Vo1c82h&o0Amac z3c?@*S0U*yqwkfR@9k}wxT6U4cv@TwO0Ihd_zE+s0W3~qx(I+C0Dmlq7KS=I_l!7} zKyTgFVuQ>r%)AM}k_@~e0>V*g^6nEy_W#{61lHC*zVOz(@Q;XTTbxQ}8r@Rz)3ZS& zWmHv*uYVgrD}aS_u|F~Rxp~p~Etyp9j1aiKq51x($uAP{`7AJ$L(HQ2c*n0^$q53h zH*Q%^B!4qkQa7zM67L?n@v*0LTWzfb*3>sW3C6Qo?6!4_uvy>L)jpPW1XkAt_Yi1X zwmZHI^f6pDCl2o&)-j*ZLSB8aH5bT>NlcZ%#Od1F#}{UW1m=L+PAiE<*z}~U&aU*- zwyAL%@~(l<7h7pnh8*XaFap9!FwQXWfgpT=8DER{LkXyoMaHiIe05GFFc!o9Lv@ac zXy*qvN_NFtJFh=jX&BV3{)i0V8i3s*Y`&yQme(Jw6oO7q@eT+-><+cH&MJW(Pm9Z4 zeElo|RjR9SJhcDGnZh}u=o1-;O0F@mV{EuIG?SZBv$1&H`D6wj(ulmjlk;q zU@I~GK$+=Kcc{&lI%p(v2*A$K;nElE`ghfJO^pQnPW=EPY+Z`Pm9Za&u|S1*#O2GBu;T% zBf=R5{?Hw2>q$r7eZGKO&Nu!Bpd$WvxC|B6}U~Iy8e=SmQtMC9E zfUYC$R~UFrF$|4b2_%9~8S0sf6R-?sXkJ!^*4kBLdwU?`Q6-b{G8}}0XkkbhDwIXW zDlG*1{DE>c0B5*PIf=l|&OIZHSoY|)G5MSp0;Mq4s9}_Dr#3slmSlot_GlrH!7G&g z@EjZoI2ewg@!BW+&7GXjkN$ zP9V?c50t9~0|^8sJp#MB+Q&dRs(hvIdps?!oR>bsP%9BeVgjR&z)829_9`QbW1UDj zi}el7_s6PcZxc$~o=mxlZ34SH_MKG^paDFSOc_MB!IZoMO1iEB7 zuXu=3X&J~QdDC<$9qJCXeK(!CjdUI!yxjNpvWluOfVIk>Jj*Mp?ps{E?nE*@92wd3 zHf~uj1Wu}w7i%_r%x-VX^m!H?i%itH6kBA0LH<;%Te|RgT3qgu|NJ!3x&T~~aD7on zm6@Sqv4i~=ddeyubQ5T`@^$W&jBhPlS@qw0OV+(HThi$D2P+Hj8hw>O8xnm~hU?3^ zO7v!}<)48*B5Y5$%jm;mTT}85HNuFG1qz~tn{<{Z&-$ek47^5!U86Tjdv#U$`}~1& zQ-~mef|#axF()pah?fK#*PaY9@k<0cl?s_Yf1q5F@hB4-)pY!n_vF&GCl-~iYYM>L z#XAuO&I!UGOY}3uJMmQkEX4vMS<1vqh-oE&O4zt_iwFlzc5TmONpi-oewsY6i9R)x zdSw8)fAv#BA}5=yHzBz|9(m-EM;>|Pk)!w@TDLdXvm#rS00000NkvXXu0mjf$QcM^ literal 0 HcmV?d00001 diff --git a/ext/custom-addons/dp_custom/static/src/img/favicon.ico b/ext/custom-addons/dp_custom/static/src/img/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..3c33e99bbdd94ba4a177804b29d9dfa9769712e6 GIT binary patch literal 26622 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 literal 0 HcmV?d00001 diff --git a/ext/custom-addons/cam_customer_pricelist/cam_customer_pricelist_data.xml b/ext/custom-addons/dp_custom/views/dp_custom_view.xml similarity index 93% rename from ext/custom-addons/cam_customer_pricelist/cam_customer_pricelist_data.xml rename to ext/custom-addons/dp_custom/views/dp_custom_view.xml index aab2e2f0..b24d2621 100644 --- a/ext/custom-addons/cam_customer_pricelist/cam_customer_pricelist_data.xml +++ b/ext/custom-addons/dp_custom/views/dp_custom_view.xml @@ -1,5 +1,10 @@ + + + + + diff --git a/ext/custom-addons/dp_report/__init__.py b/ext/custom-addons/dp_report/__init__.py new file mode 100644 index 00000000..5305644d --- /dev/null +++ b/ext/custom-addons/dp_report/__init__.py @@ -0,0 +1,3 @@ +# -*- coding: utf-8 -*- + +from . import models \ No newline at end of file diff --git a/ext/custom-addons/dp_report/__openerp__.py b/ext/custom-addons/dp_report/__openerp__.py new file mode 100644 index 00000000..8b51bdec --- /dev/null +++ b/ext/custom-addons/dp_report/__openerp__.py @@ -0,0 +1,23 @@ +# -*- coding: utf-8 -*- + +{ + 'name': 'datepol Report Anpassungen', + 'category': 'Custom', + 'version': '1.0', + 'summary': """Individuelle Report Anpassungen""", + 'description': """Individuelle Report Anpassungen""", + 'author': 'datenpol gmbh', + 'website': 'http://www.datenpol.at', + 'depends': ['base'], + 'data': [ + # 'security/ir.model.access.csv', + 'views/layouts.xml', + 'views/saleorder.xml', + 'views/invoice.xml', + 'views/delivery.xml', + ], + # only loaded in demonstration mode + 'demo': [], + 'installable': True, + 'auto_install': False, +} diff --git a/ext/custom-addons/dp_report/i18n/de.po b/ext/custom-addons/dp_report/i18n/de.po new file mode 100644 index 00000000..6762beec --- /dev/null +++ b/ext/custom-addons/dp_report/i18n/de.po @@ -0,0 +1,19 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * dp_report +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo 10.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2015-10-12 09:17+0000\n" +"PO-Revision-Date: 2016-10-13 11:58+0000\n" +"Last-Translator: datenpol\n" +"Language-Team: German (http://www.transifex.com/odoo/odoo-9/language/de/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Language: de\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + + diff --git a/ext/custom-addons/dp_report/models/__init__.py b/ext/custom-addons/dp_report/models/__init__.py new file mode 100644 index 00000000..7c68785e --- /dev/null +++ b/ext/custom-addons/dp_report/models/__init__.py @@ -0,0 +1 @@ +# -*- coding: utf-8 -*- \ No newline at end of file diff --git a/ext/custom-addons/cam_custom/security/ir.model.access.csv b/ext/custom-addons/dp_report/security/ir.model.access.csv similarity index 100% rename from ext/custom-addons/cam_custom/security/ir.model.access.csv rename to ext/custom-addons/dp_report/security/ir.model.access.csv diff --git a/ext/custom-addons/dp_report/views/delivery.xml b/ext/custom-addons/dp_report/views/delivery.xml new file mode 100644 index 00000000..8063c308 --- /dev/null +++ b/ext/custom-addons/dp_report/views/delivery.xml @@ -0,0 +1,75 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/ext/custom-addons/dp_report/views/invoice.xml b/ext/custom-addons/dp_report/views/invoice.xml new file mode 100644 index 00000000..436df4e1 --- /dev/null +++ b/ext/custom-addons/dp_report/views/invoice.xml @@ -0,0 +1,65 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/ext/custom-addons/dp_report/views/layouts.xml b/ext/custom-addons/dp_report/views/layouts.xml new file mode 100644 index 00000000..ecd180e0 --- /dev/null +++ b/ext/custom-addons/dp_report/views/layouts.xml @@ -0,0 +1,58 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/ext/custom-addons/dp_report/views/saleorder.xml b/ext/custom-addons/dp_report/views/saleorder.xml new file mode 100644 index 00000000..4526105b --- /dev/null +++ b/ext/custom-addons/dp_report/views/saleorder.xml @@ -0,0 +1,85 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/ext/custom-addons/mail_follower_control/README.md b/ext/custom-addons/mail_follower_control/README.md deleted file mode 100644 index 604def8e..00000000 --- a/ext/custom-addons/mail_follower_control/README.md +++ /dev/null @@ -1,20 +0,0 @@ -# mail_follower_control - -This addon allows better control over follower handling for the chatter view. - -## Goals: - -- Checkbox "Do not automatically add as follower" for res.partner -- Set this new Checkbox to True by default -- Show the followers and additional recipients that will receive an email (notify always + email) -- Show a warning when adding additional recipients if the new recipient will not receive an email -- Show followers that will not receive Messages in Red -- Write the followers that received an email to mail.message in a new field to view them in message thread views - -- ToDo: Always show all the followers when writing a message in full message composer - - ToDo: Allow to remove some followers just for the current mail -- ToDo: BCC Field for all Chatter E-Mails - - ToDo: Do NOT add BCC Recipients as followers regardless of the checkbox "Do not automatically ad as follower" - - - diff --git a/ext/custom-addons/mail_follower_control/__init__.py b/ext/custom-addons/mail_follower_control/__init__.py deleted file mode 100644 index 9a1c6cfe..00000000 --- a/ext/custom-addons/mail_follower_control/__init__.py +++ /dev/null @@ -1,24 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# OpenERP, Open Source Management Solution -# Copyright (C) 20014-2016 Camadeus GmbH (). -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -# -############################################################################## -import mail_follower_control - -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: - diff --git a/ext/custom-addons/mail_follower_control/__openerp__.py b/ext/custom-addons/mail_follower_control/__openerp__.py deleted file mode 100644 index 02ece0ca..00000000 --- a/ext/custom-addons/mail_follower_control/__openerp__.py +++ /dev/null @@ -1,60 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# OpenERP, Open Source Management Solution -# Copyright (C) 20014-2016 Camadeus GmbH (). -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -# -############################################################################## - - -{ - 'name': 'Mail Follower Control', - 'version': '1.0', - 'category': 'Custom', - 'author': 'DataDialog, Michael Karrer (original version for v7 by camadeus)', - 'website': 'http://www.datadialog.net', - 'installable': True, - 'description': """ -mail_follower_control -===================== - -This addon allows better control over follower handling for the chatter view. - -Goals: ------- - -- Checkbox "Do not automatically add as follower" for res.partner -- Set this new Checkbox to True by default -- Show the followers and additional recipients that will receive an email (notify always + email) -- Show a warning when adding additional recipients if the new recipient will not receive an email -- Show followers that will not receive Messages in Red -- Write the followers that received an email to mail.message in a new field to view them in message thread views - -- ToDo: Always show all the followers when writing a message in full message composer - - ToDo: Allow to remove some followers just for the current mail -- ToDo: BCC Field for all Chatter E-Mails - - ToDo: Do NOT add BCC Recipients as followers regardless of the checkbox "Do not automatically ad as follower" - - """, - 'depends': ['web', 'mail'], - 'qweb': [ - 'views/templates.xml', - ], - 'data': [ - 'views/views.xml', - ], - -} \ No newline at end of file diff --git a/ext/custom-addons/mail_follower_control/i18n/de.pot b/ext/custom-addons/mail_follower_control/i18n/de.pot deleted file mode 100644 index 8c23befd..00000000 --- a/ext/custom-addons/mail_follower_control/i18n/de.pot +++ /dev/null @@ -1,84 +0,0 @@ -# Translation of Odoo Server. -# This file contains the translation of the following modules: -# * mail_follower_control -# -msgid "" -msgstr "" -"Project-Id-Version: Odoo Server 8.0\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-04-29 12:25+0000\n" -"PO-Revision-Date: 2015-04-29 12:25+0000\n" -"Last-Translator: <>\n" -"Language-Team: \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: \n" -"Plural-Forms: \n" - -#. module: mail_follower_control -#: field:res.partner,no_subscribe:0 -msgid "Do not add as Follower automatically" -msgstr "Nicht automatisch als Follower hinzufügen" - -#. module: mail_follower_control -#: model:ir.model,name:mail_follower_control.model_mail_thread -msgid "Email Thread" -msgstr "" - -#. module: mail_follower_control -#: model:ir.model,name:mail_follower_control.model_mail_compose_message -msgid "Email composition wizard" -msgstr "" - -#. module: mail_follower_control -#: model:ir.model,name:mail_follower_control.model_mail_wizard_invite -msgid "Invite wizard" -msgstr "" - -#. module: mail_follower_control -#: model:ir.model,name:mail_follower_control.model_mail_message -msgid "Message" -msgstr "Nachricht" - -#. module: mail_follower_control -#: view:mail.compose.message:mail_follower_control.mail_message_wizard_form_view -#: field:mail.compose.message,follower_ids:0 -msgid "Notified by eMail" -msgstr "Benachrichtigt per E-Mail" - -#. module: mail_follower_control -#: model:ir.model,name:mail_follower_control.model_mail_mail -msgid "Outgoing Mails" -msgstr "Ausgehende E-Mails" - -#. module: mail_follower_control -#: model:ir.model,name:mail_follower_control.model_res_partner -msgid "Partner" -msgstr "Kontakt" - -#. module: mail_follower_control -#: field:mail.message,notified_by_email_ids:0 -msgid "Partners notified by e-mail" -msgstr "Benachrichtigt per E-Mail" - -#. module: mail_follower_control -#: code:addons/mail_follower_control/mail_follower_control.py:261 -#, python-format -msgid "Some partners will not be notified by e-mail!" -msgstr "Einige Kontakte werden nicht per E-Mail benachrichtigt!" - -#. module: mail_follower_control -#: code:addons/mail_follower_control/mail_follower_control.py:262 -#, python-format -msgid "The following partners will not be notified by e-mail but they will still get a message in odoo (if they have a login):\n" -"\n" -"%s" -msgstr "Folgende Kontakte werden keine Benachrichtigung per E-Mail bekommen. Diese Kontakte bekommen jedoch zumindest eine Benachrichtigung in Ihren odoo Posteingang sofern sie sich einloggen können.: \n" -"\n" -"%s" - -#. module: mail_follower_control -#: view:mail.compose.message:mail_follower_control.mail_message_wizard_form_view -msgid "onchange_partner_ids(partner_ids, follower_ids, model, res_id, context)" -msgstr "" - diff --git a/ext/custom-addons/mail_follower_control/i18n/mail_follower_control.pot b/ext/custom-addons/mail_follower_control/i18n/mail_follower_control.pot deleted file mode 100644 index 3ec91c84..00000000 --- a/ext/custom-addons/mail_follower_control/i18n/mail_follower_control.pot +++ /dev/null @@ -1,82 +0,0 @@ -# Translation of Odoo Server. -# This file contains the translation of the following modules: -# * mail_follower_control -# -msgid "" -msgstr "" -"Project-Id-Version: Odoo Server 8.0\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-04-29 12:25+0000\n" -"PO-Revision-Date: 2015-04-29 12:25+0000\n" -"Last-Translator: <>\n" -"Language-Team: \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: \n" -"Plural-Forms: \n" - -#. module: mail_follower_control -#: field:res.partner,no_subscribe:0 -msgid "Do not add as Follower automatically" -msgstr "" - -#. module: mail_follower_control -#: model:ir.model,name:mail_follower_control.model_mail_thread -msgid "Email Thread" -msgstr "" - -#. module: mail_follower_control -#: model:ir.model,name:mail_follower_control.model_mail_compose_message -msgid "Email composition wizard" -msgstr "" - -#. module: mail_follower_control -#: model:ir.model,name:mail_follower_control.model_mail_wizard_invite -msgid "Invite wizard" -msgstr "" - -#. module: mail_follower_control -#: model:ir.model,name:mail_follower_control.model_mail_message -msgid "Message" -msgstr "" - -#. module: mail_follower_control -#: view:mail.compose.message:mail_follower_control.mail_message_wizard_form_view -#: field:mail.compose.message,follower_ids:0 -msgid "Notified by eMail" -msgstr "" - -#. module: mail_follower_control -#: model:ir.model,name:mail_follower_control.model_mail_mail -msgid "Outgoing Mails" -msgstr "" - -#. module: mail_follower_control -#: model:ir.model,name:mail_follower_control.model_res_partner -msgid "Partner" -msgstr "" - -#. module: mail_follower_control -#: field:mail.message,notified_by_email_ids:0 -msgid "Partners notified by e-mail" -msgstr "" - -#. module: mail_follower_control -#: code:addons/mail_follower_control/mail_follower_control.py:261 -#, python-format -msgid "Some partners will not be notified by e-mail!" -msgstr "" - -#. module: mail_follower_control -#: code:addons/mail_follower_control/mail_follower_control.py:262 -#, python-format -msgid "The following partners will not be notified by e-mail but they will still get a message in odoo (if they have a login):\n" -"\n" -"%s" -msgstr "" - -#. module: mail_follower_control -#: view:mail.compose.message:mail_follower_control.mail_message_wizard_form_view -msgid "onchange_partner_ids(partner_ids, follower_ids, model, res_id, context)" -msgstr "" - diff --git a/ext/custom-addons/mail_follower_control/mail_follower_control.py b/ext/custom-addons/mail_follower_control/mail_follower_control.py deleted file mode 100644 index f0b0f377..00000000 --- a/ext/custom-addons/mail_follower_control/mail_follower_control.py +++ /dev/null @@ -1,296 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# OpenERP, Open Source Management Solution -# Copyright (C) 20014-2016 Camadeus GmbH (). -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -# -############################################################################## - -from openerp.osv import fields, osv -from openerp.tools.translate import _ -from openerp import SUPERUSER_ID - - -class res_partner(osv.Model): - _inherit = "res.partner" - - _columns = { - 'no_subscribe': fields.boolean("Do not add as Follower automatically"), - } - _defaults = { - 'no_subscribe': True, - } - - def get_partners_notify_by_email(self, cr, uid, ids, message_type, context): - """ Return the list of partners which will be notified per mail, based on their preferences. - :param message_type: type of message - - """ - notify_pids = [] - user = self.pool.get('res.users').browse(cr,uid,uid) - for partner in self.browse(cr, uid, ids): - # Do not send to partners without email address defined - if not partner.email: - continue - # Partner does not want to receive any emails - if partner.notify_email == 'none': - continue - - # Exclude own partner - if partner.email == user.email: - continue - - notify_pids.append(partner.id) - return notify_pids -res_partner() - - -class mail_thread(osv.AbstractModel): - _inherit = "mail.thread" - - # Add data for JS to mark follower in red that will not receive an email - # - # FULL OVERWRITE of function to add 'notify_email': --> stupid but needed - # (this function will be called by the java script mail_followers.js to get the follower data) - # we need to know notify_email in the qweb template to mark followers in red that will not receive an email - # we alter mail_followers.js in addons-own/mail_follower_control/static/src/js/mail_follower_control.js to add - # notify_email to the display_followers function - def read_followers_data(self, cr, uid, follower_ids, context=None): - result = [] - technical_group = self.pool.get('ir.model.data').get_object(cr, uid, 'base', 'group_no_one', context=context) - for follower in self.pool.get('res.partner').browse(cr, uid, follower_ids, context=context): - is_editable = uid in map(lambda x: x.id, technical_group.users) - is_uid = uid in map(lambda x: x.id, follower.user_ids) - data = (follower.id, - follower.name, - {'is_editable': is_editable, 'is_uid': is_uid, 'notify_email': follower.notify_email, }, - ) - result.append(data) - return result - - # Do not subscript followers with no_subscribe=True (except force_subscription is in the context) - # - # message_post will call message_subscribe to add followers - # we alter this method to take our new field no_subscribe into account - def message_subscribe(self, cr, uid, ids, partner_ids, subtype_ids=None, context=None): - if context is None: - context = {} - - # 1.) Filter all mail_post_autofollow_partner_ids if they exists to respect the no_subscribe setting - if context.get('mail_post_autofollow') and context.get('mail_post_autofollow_partner_ids'): - context['mail_post_autofollow_partner_ids'] = self.pool.get('res.partner').search(cr, uid, [ - ('no_subscribe', '=', False), - ('id', 'in', context.get('mail_post_autofollow_partner_ids'), ) - ]) - - # 2.) Filter partner_ids: to respect the no_subscribe setting (except 'force_subscription' is set) - # HINT: force_subscription is set by java script to allow adding a follower with no_subscribe=True by the - # add followers links in the chatter window - without this the follower could not be added by any method. - if not context.get('force_subscription'): - partner_ids = self.pool.get('res.partner').search(cr, uid, [ - ('no_subscribe', '=', False), - ('id', 'in', partner_ids), - ]) - - # Remove force_subscription from the context after the filtering is done - if context.get('force_subscription'): - context.pop('force_subscription') - - res = super(mail_thread, self).message_subscribe(cr, uid, ids, partner_ids, subtype_ids, context) - return res -mail_thread() - - -# Allow to add followers with no_subscribe=True at least with the invite wizard (Add Followers Link) -class invite_wizard(osv.osv_memory): - _inherit = 'mail.wizard.invite' - - # Add force Subscription to the context so that followers can be added even if no_subscribe=True - def add_followers(self, cr, uid, ids, context=None): - if context is None: - context = {} - context['force_subscription'] = True - - return super(invite_wizard, self).add_followers(cr, uid, ids, context) -invite_wizard() - - -class mail_message(osv.Model): - _inherit = "mail.message" - # Add field notified_by_email_ids to store this data from mail.mail if a mail was sent - # WARNING: do not use relation= for old style many2many fields - will be ignored!!!! - # WARNING: always use a custom name for the relation table e.g.: mail_message_res_partner_notified_by_email_rel - # if you use none the system may generate one that is already in use and both fields will have - # the related fields - which is very hard to debug. - _columns = { - 'notified_by_email_ids': fields.many2many('res.partner', - 'mail_message_res_partner_notified_by_email_rel', - 'mail_message_id', 'res_partner_id', - string='Partners notified by e-mail'), - } - - # Update Dict for JS rendering of messages with field notified_by_email_ids - # HINT: _message_read_dict returns a dict representation of the message. This representation is - # used in the JS client code, to display the messages. Partners and - # attachments related stuff will be done in post-processing in batch. - def _message_read_dict(self, cr, uid, message, parent_id=False, context=None): - res = super(mail_message, self)._message_read_dict(cr, uid, message, parent_id, context) - - # ToDo: Create a dict wich holds name and id for each id in ids (partner) - needed in template! - vals = {'notified_by_email_ids': [[p.id, p.name] for p in message.notified_by_email_ids]} - # print 'vals: %s' % vals - res.update(vals) - return res - -mail_message() - - -# Check Receipients while composing a mail (Full composing dialog not quick dialogue) and give a warning -# if the added recipients will not receive an e-mail by setting -class mail_compose_message(osv.TransientModel): - _inherit = "mail.compose.message" - - _columns = { - 'follower_ids': fields.many2many('res.partner', - 'mail_compose_message_followers_rel', - 'wizard_id', - 'partner_id', - string='Notified by eMail', readonly=True), - } - - # This will recalculate/set the field follower_ids for the current mail_compose_message (which is a transient model - # so its not a problem to recalculate it here on the fly) - def get_record_data(self, cr, uid, values, context=None): - - res = super(mail_compose_message, self).get_record_data(cr, uid, values, context) - - # if this message belongs to a resource add follower ids that will receieve an email to the result dict - if values.get('model') and values.get('res_id'): - p_obj = self.pool.get('res.partner') - fol_obj = self.pool.get("mail.followers") - - # get all followers for the current resource (= model and res_id) - fol_ids = fol_obj.search(cr, SUPERUSER_ID, [ - ('res_model', '=', values.get('model')), - ('res_id', '=', values.get('res_id')), - ('subtype_ids', 'in', 1) # ID 1 is always the subtyp "Discussion" - ], context=context) - - # get the res.partner objects of the followers (mail.followers) of this resource - followers = set(fo.partner_id for fo in fol_obj.browse(cr, SUPERUSER_ID, fol_ids, context=context)) - - # get the res.partner ids for the objects in followers - follower_ids = [f.id for f in followers] - - # filter out all followers without an email or with notify_email set to none - notify_pids = p_obj.get_partners_notify_by_email(cr, uid, follower_ids, 'comment', context) - - # add follower_ids tp the result dict - # This result dict is used by the ??? - I DONT KNOW TILL NOW! - res.update({'follower_ids': notify_pids}) - - return res - - def onchange_partner_ids(self, cr, uid, ids, partner_ids, follower_ids, model, res_id, context=None): - - # We unwrap the variable partner_ids which most likely has a form of e.g. [(6, 0, [7]), ] - # see https://doc.odoo.com/v6.0/developer/2_5_Objects_Fields_Methods/methods.html/#osv.osv.osv.write - p_ids = [] - # Unwrap: Only take the first list or tuble - if isinstance(partner_ids, (list, tuple)): - partner_ids = partner_ids[0] - # 4 means "link to existing record with id = ID" so we add new links which in fact is nonsense since - # p_ids is empty at this time anyway. - if isinstance(partner_ids, (list, tuple)) and partner_ids[0] == 4 and len(partner_ids) == 2: - p_ids.add(partner_ids[1]) - # 6 means "replace the list of linked IDs" so we replace the partner ids - if isinstance(partner_ids, (list, tuple)) and partner_ids[0] == 6 and len(partner_ids) == 3 and partner_ids[2]: - p_ids = partner_ids[2] - elif isinstance(partner_ids, (int, long)): - p_ids.add(partner_ids) - else: - pass # we do not manage anything else - - p_obj = self.pool.get('res.partner') - - # get all partners that have an email and also notify_email is not none - parterns_to_notify = p_obj.get_partners_notify_by_email(cr, uid, p_ids, "comment", context) - - # find any partners in p_ids that are not in parterns_to_notify - partners_not_to_notify = [p for p in p_ids if p not in parterns_to_notify] - - # get the names of the partners that will not get an email - partners = p_obj.name_get(cr, uid, partners_not_to_notify, context=context) - partner_names = [p[1] for p in partners] - - # Update follower_ids - # Update the values for the wizzard (found in addons/email_template/wizard/mail_compose_message.py) - # HINT: There was no docu in how to update the wizard but at least i found an example - i have no idea - # If this is the same for all wizards - p_obj = self.pool.get('res.partner') - fol_obj = self.pool.get("mail.followers") - - # get all followers for the current resource (= model and res_id) - fol_ids = fol_obj.search(cr, SUPERUSER_ID, [ - ('res_model', '=', model), - ('res_id', '=', res_id), - ('subtype_ids', 'in', 1) # ID 1 is always the subtyp "Discussion" - ], context=context) - - # get the res.partner objects of the followers (mail.followers) of this resource - followers = set(fo.partner_id for fo in fol_obj.browse(cr, SUPERUSER_ID, fol_ids, context=context)) - - # get the res.partner ids for the objects in followers - follower_ids = [f.id for f in followers] - - # filter out all followers without an email or with notify_email set to none - follower_partner_ids = p_obj.get_partners_notify_by_email(cr, uid, follower_ids, 'comment', context) - - # update the follower_ids to reflect the newly added partners to notify by mail if any - values = {'follower_ids': list(set(follower_partner_ids + parterns_to_notify)), } - - - # Warn if any partners found that will not get an email - if partner_names: - warning = { - 'title': _('Some partners will not be notified by e-mail!'), - 'message': _('The following partners will not be notified by e-mail but they will still get a message in odoo (if they have a login):\n\n%s') % ('\n'.join(partner_names)) - } - res = {'warning': warning, 'value': values} - else: - res = {'value': values} - return res -mail_compose_message() - - - - -# This will update the new custom field mail_sent for the model mail.notification - seems useless ... because -# it will be true if the smtp server takes over the mail which des not guarantee sending was successful -class mail_mail(osv.Model): - _inherit = 'mail.mail' - - def _postprocess_sent_message(self, cr, uid, mail, context=None, mail_sent=True): - - # Copy the notified_by_email_ids to the mail.message - # Hint: It seems that notified_by_email_ids of mail.message is already there but in the state of the initial - # setting so we have to update it here after we send the message to inculde the right notified_by_email_ids - if mail_sent and mail.recipient_ids and mail.mail_message_id: - mail.mail_message_id.notified_by_email_ids = mail.recipient_ids - - - return super(mail_mail, self)._postprocess_sent_message(cr=cr, uid=uid, mail=mail, - context=context, mail_sent=mail_sent) diff --git a/ext/custom-addons/mail_follower_control/static/src/css/mail_follower_control.css b/ext/custom-addons/mail_follower_control/static/src/css/mail_follower_control.css deleted file mode 100644 index 31c40dcf..00000000 --- a/ext/custom-addons/mail_follower_control/static/src/css/mail_follower_control.css +++ /dev/null @@ -1,15 +0,0 @@ - -.oe_follower_red { - color: red !important; -} - -.oe_follower_orange { - color: orange !important; -} - -.oe_msg_notify_mail { - margin-left: 4px; - overflow: hidden; - margin-top: -4px; - font-size: 11px; -} \ No newline at end of file diff --git a/ext/custom-addons/mail_follower_control/static/src/js/mail_follower_control.js b/ext/custom-addons/mail_follower_control/static/src/js/mail_follower_control.js deleted file mode 100644 index 48789eb0..00000000 --- a/ext/custom-addons/mail_follower_control/static/src/js/mail_follower_control.js +++ /dev/null @@ -1,82 +0,0 @@ -openerp.mail_follower_control = function (session) { - - session.mail_followers.Followers = session.mail_followers.Followers.extend({ - - /** FULL OVERWRITE: because we need to add more data to the records: 'notify_email' - * Do not forget to update the python function "read_followers_data" in "mail_follower_control.py" - * ("read_followers_data" is called by JS function "fetch_followers" which then calls "display_followers") - * - * */ - display_followers: function (records) { - var self = this; - this.message_is_follower = false; - console.log('RECORDS:'); - console.log(records); - this.followers = records || this.followers; - // clean and display title - var node_user_list = this.$('.oe_follower_list').empty(); - this.$('.oe_follower_title').html(this._format_followers(this.followers.length)); - self.message_is_follower = _.indexOf(this.followers.map(function (rec) { return rec[2]['is_uid']}), true) != -1; - // truncate number of displayed followers - var truncated = this.followers.slice(0, this.displayed_nb); - _(truncated).each(function (record) { - partner = { - 'id': record[0], - 'name': record[1], - 'is_uid': record[2]['is_uid'], - 'is_editable': record[2]['is_editable'], - 'notify_email': record[2]['notify_email'], - 'avatar_url': session.mail.ChatterUtils.get_image(self.session, 'res.partner', 'image_small', record[0]) - }; - console.log('partner'); - console.log(partner); - $(session.web.qweb.render('mail.followers.partner', {'record': partner, 'widget': self})).appendTo(node_user_list); - // On mouse-enter it will show the edit_subtype pencil. - if (partner.is_editable) { - self.$('.oe_follower_list').on('mouseenter mouseleave', function(e) { - self.$('.oe_edit_subtype').toggleClass('oe_hidden', e.type == 'mouseleave'); - self.$('.oe_follower_list').find('.oe_partner').toggleClass('oe_partner_name', e.type == 'mouseenter'); - }); - } - }); - // FVA note: be sure it is correctly translated - if (truncated.length < this.followers.length) { - $(session.web.qweb.render('mail.followers.show_more', {'number': (this.followers.length - truncated.length)} )).appendTo(node_user_list); - } - }, - - do_follow: function () { - /** - * Add this context value to force subscription - */ - var context = new session.web.CompoundContext(this.build_context(), {'force_subscription': 1}); - console.log('do_follow'); - - this.ds_model.call('message_subscribe_users', [[this.view.datarecord.id], [this.session.uid], undefined, context]) - .then(this.proxy('read_value')); - - _.each(this.$('.oe_subtype_list input'), function (record) { - $(record).attr('checked', 'checked'); - }); - - } - - }); - - // HINT: Add recipient_ids to MessageCommon - message common is extended by: - // mail.ThreadMessage AND - // mail.ThreadComposeMessage so both should have recipients_ids now for ThreadComposeMessage it will be - // useless for now because this is updated after we post the message. - // session.mail.MessageCommon = session.mail.MessageCommon.extend({ - // HINT2: mail.MessageCommon did not work ?!? - openerp.mail.ThreadMessage = openerp.mail.ThreadMessage.extend({ - template: 'mail.thread.message', - - init: function (parent, datasets, options) { - this._super(parent, datasets, options); - - this.notified_by_email_ids = datasets.notified_by_email_ids || []; - } - }); - -}; diff --git a/ext/custom-addons/mail_follower_control/views/templates.xml b/ext/custom-addons/mail_follower_control/views/templates.xml deleted file mode 100644 index 99443360..00000000 --- a/ext/custom-addons/mail_follower_control/views/templates.xml +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - - - - - - - - - - - - - -
- By e-mail to: - - - - - - - - - - , - - - -
-
-
- - - - - - - - -
diff --git a/ext/custom-addons/mail_follower_control/views/views.xml b/ext/custom-addons/mail_follower_control/views/views.xml deleted file mode 100644 index 3c6455b7..00000000 --- a/ext/custom-addons/mail_follower_control/views/views.xml +++ /dev/null @@ -1,64 +0,0 @@ - - - - - - - - - - chatterimprovments.res_partner.form - res.partner - - - - - - - - - - - chatterimprovments.mail_message_wizard.form - mail.compose.message - - - - - - - - - - onchange_partner_ids(partner_ids, follower_ids, model, res_id, context) - - - - - - - mail_view_message_form_extended - mail.message - - - - - - - - - - - - diff --git a/ext/custom-addons/oerp_no_phoning_home/README.md b/ext/custom-addons/oerp_no_phoning_home/README.md deleted file mode 100644 index 54a855dd..00000000 --- a/ext/custom-addons/oerp_no_phoning_home/README.md +++ /dev/null @@ -1,15 +0,0 @@ -Stop Phoning Home Feature from OpenERP -====================================== - -Note: ------ - -* For V8 checkout master branch -* for V7 checkout 7.0 branch - -Remove Few Phoning home feature effect from Core OpenERP. ---------------------------------------------------------- - -* Stop Scheduler for Sending Company/Database information to Odoo/OpenERP company. -* Remove ``Your OpenERP is not supported.``. -* Change sequence of the ``Apps`` and ``Update`` menu and arrange ``Installed Modules`` at first position. \ No newline at end of file diff --git a/ext/custom-addons/oerp_no_phoning_home/__init__.py b/ext/custom-addons/oerp_no_phoning_home/__init__.py deleted file mode 100644 index fc631b41..00000000 --- a/ext/custom-addons/oerp_no_phoning_home/__init__.py +++ /dev/null @@ -1 +0,0 @@ -import mail diff --git a/ext/custom-addons/oerp_no_phoning_home/__openerp__.py b/ext/custom-addons/oerp_no_phoning_home/__openerp__.py deleted file mode 100644 index eb8dab59..00000000 --- a/ext/custom-addons/oerp_no_phoning_home/__openerp__.py +++ /dev/null @@ -1,29 +0,0 @@ -# -*- coding: utf-8 -*- -{ - 'name': 'Stop Phoning Home', - 'version': '1.0', - 'category': '', - "sequence": 14, - 'complexity': "easy", - 'category': 'Hidden', - 'description': """ - Remove Few Phoning home feature effect from Core OpenERP. - """, - 'author': 'Ruchir Shukla', - 'website': 'www.bizzappdev.com', - 'depends': ["mail",'web'], - 'init_xml': [], - 'data': [ - "base_view.xml", - "mail_data.xml", - ], - 'demo_xml': [], - 'test': [ - ], - 'qweb' : [ - "static/src/xml/base.xml", - ], - 'installable': True, - 'auto_install': True, -} -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/ext/custom-addons/oerp_no_phoning_home/base_view.xml b/ext/custom-addons/oerp_no_phoning_home/base_view.xml deleted file mode 100644 index a9449c48..00000000 --- a/ext/custom-addons/oerp_no_phoning_home/base_view.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/ext/custom-addons/oerp_no_phoning_home/mail.py b/ext/custom-addons/oerp_no_phoning_home/mail.py deleted file mode 100644 index bb0980a1..00000000 --- a/ext/custom-addons/oerp_no_phoning_home/mail.py +++ /dev/null @@ -1,25 +0,0 @@ -# -*- coding: utf-8 -*- - -from openerp.osv import osv -import logging - -_logger = logging.getLogger(__name__) - -from openerp.tools import config - -config['publisher_warranty_url'] = '' - - -class publisher_warranty_contract(osv.osv): - _inherit = 'publisher_warranty.contract' - - def update_notification(self, cr, uid, ids, cron_mode=True, - context=None): - - _logger.info("NO More Spying Stuff") - - return True - - -publisher_warranty_contract() - diff --git a/ext/custom-addons/oerp_no_phoning_home/mail_data.xml b/ext/custom-addons/oerp_no_phoning_home/mail_data.xml deleted file mode 100644 index 5315dc4b..00000000 --- a/ext/custom-addons/oerp_no_phoning_home/mail_data.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - Update Notification - - - 1 - weeks - -1 - - - - - 1000 - - - - - diff --git a/ext/custom-addons/oerp_no_phoning_home/static/src/img/icon.png b/ext/custom-addons/oerp_no_phoning_home/static/src/img/icon.png deleted file mode 100644 index 9ad73d74e66cc4b16f1901d708c576c2bbac87d7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11169 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 diff --git a/ext/custom-addons/oerp_no_phoning_home/static/src/js/announcement.js b/ext/custom-addons/oerp_no_phoning_home/static/src/js/announcement.js deleted file mode 100644 index 0d7e1fde..00000000 --- a/ext/custom-addons/oerp_no_phoning_home/static/src/js/announcement.js +++ /dev/null @@ -1,13 +0,0 @@ -openerp.oerp_no_phoning_home = function(instance) { - instance.web.WebClient.include({ - show_application: function() { - return $.when(this._super.apply(this, arguments)); - }, - _ab_location: function(dbuuid) { - // return _.str.sprintf('https://services.openerp.com/openerp-enterprise/ab/css/%s.css', dbuuid); - }, - show_annoucement_bar: function() { - return; - } - }); -}; diff --git a/ext/custom-addons/oerp_no_phoning_home/static/src/xml/base.xml b/ext/custom-addons/oerp_no_phoning_home/static/src/xml/base.xml deleted file mode 100644 index 97da789c..00000000 --- a/ext/custom-addons/oerp_no_phoning_home/static/src/xml/base.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - - diff --git a/ext/custom-addons/sale_order_optional/__init__.py b/ext/custom-addons/sale_order_optional/__init__.py deleted file mode 100755 index 24bf354f..00000000 --- a/ext/custom-addons/sale_order_optional/__init__.py +++ /dev/null @@ -1,22 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# OpenERP, Open Source Management Solution -# Copyright (C) 20014-2016 Camadeus GmbH (). -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -# -############################################################################## - -import sale_order_optional diff --git a/ext/custom-addons/sale_order_optional/__openerp__.py b/ext/custom-addons/sale_order_optional/__openerp__.py deleted file mode 100755 index c7c2ba19..00000000 --- a/ext/custom-addons/sale_order_optional/__openerp__.py +++ /dev/null @@ -1,42 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# OpenERP, Open Source Management Solution -# Copyright (C) 20014-2016 Camadeus GmbH (). -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -# -############################################################################## - -{ - 'name': "Optional Lines for Sale Orders", - 'version': "1.0", - 'category': "Sales", - 'description': """ - This addon adds optional sale order lines. - """, - 'author': "Camadeus GmbH", - 'website': "http://www.camadeus.at", - 'css': [], - 'images': [], - 'depends': ['sale'], - 'data': ['sale_order_optional_view.xml', - 'sale_order_optional_data.xml', - ], - 'installable': True, - 'auto_install': False, - 'application': False, -} - -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/ext/custom-addons/sale_order_optional/sale_order_optional.py b/ext/custom-addons/sale_order_optional/sale_order_optional.py deleted file mode 100644 index dd997a96..00000000 --- a/ext/custom-addons/sale_order_optional/sale_order_optional.py +++ /dev/null @@ -1,134 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# OpenERP, Open Source Management Solution -# Copyright (C) 20014-2016 Camadeus GmbH (). -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -# -############################################################################## - -from openerp.osv import fields, osv -import openerp.addons.decimal_precision as dp - -class sale_order(osv.osv): - _inherit = "sale.order" - - def _amount_line_tax(self, cr, uid, line, context=None): - val = 0.0 - if not line.optional: - for c in self.pool.get('account.tax').compute_all(cr, uid, line.tax_id, line.price_unit * (1-(line.discount or 0.0)/100.0), line.product_uom_qty, line.product_id, line.order_id.partner_id)['taxes']: - val += c.get('amount', 0.0) - return val - - def _amount_all(self, cr, uid, ids, field_name, arg, context=None): - cur_obj = self.pool.get('res.currency') - res = {} - for order in self.browse(cr, uid, ids, context=context): - res[order.id] = { - 'amount_untaxed': 0.0, - 'amount_tax': 0.0, - 'amount_total': 0.0, - } - val = val1 = 0.0 - cur = order.pricelist_id.currency_id - for line in order.order_line: - val1 += line.price_subtotal - val += self._amount_line_tax(cr, uid, line, context=context) - res[order.id]['amount_tax'] = cur_obj.round(cr, uid, cur, val) - res[order.id]['amount_untaxed'] = cur_obj.round(cr, uid, cur, val1) - res[order.id]['amount_total'] = res[order.id]['amount_untaxed'] + res[order.id]['amount_tax'] - return res - - def _amount_all_wrapper(self, cr, uid, ids, field_name, arg, context=None): - """ Wrapper because of direct method passing as parameter for function fields """ - return self._amount_all(cr, uid, ids, field_name, arg, context=context) - - def _get_order(self, cr, uid, ids, context=None): - result = {} - for line in self.pool.get('sale.order.line').browse(cr, uid, ids, context=context): - result[line.order_id.id] = True - return result.keys() - - _columns = { - 'amount_untaxed': fields.function(_amount_all_wrapper, digits_compute=dp.get_precision('Account'), string='Untaxed Amount', - store={ - 'sale.order': (lambda self, cr, uid, ids, c={}: ids, ['order_line'], 10), - 'sale.order.line': (_get_order, ['price_unit', 'tax_id', 'discount', 'product_uom_qty'], 10), - }, - multi='sums', help="The amount without tax.", track_visibility='always'), - 'amount_tax': fields.function(_amount_all_wrapper, digits_compute=dp.get_precision('Account'), string='Taxes', - store={ - 'sale.order': (lambda self, cr, uid, ids, c={}: ids, ['order_line'], 10), - 'sale.order.line': (_get_order, ['price_unit', 'tax_id', 'discount', 'product_uom_qty'], 10), - }, - multi='sums', help="The tax amount."), - 'amount_total': fields.function(_amount_all_wrapper, digits_compute=dp.get_precision('Account'), string='Total', - store={ - 'sale.order': (lambda self, cr, uid, ids, c={}: ids, ['order_line'], 10), - 'sale.order.line': (_get_order, ['price_unit', 'tax_id', 'discount', 'product_uom_qty'], 10), - }, - multi='sums', help="The total amount."), - } - -class sale_order_line(osv.osv): - _inherit = 'sale.order.line' - - def _fnct_line_invoiced(self, cr, uid, ids, field_name, args, context=None): - res = dict.fromkeys(ids, False) - for this in self.browse(cr, uid, ids, context=context): - res[this.id] = this.invoice_lines and \ - all(iline.invoice_id.state != 'cancel' for iline in this.invoice_lines) or \ - this.optional - return res - - def _order_lines_from_invoice(self, cr, uid, ids, context=None): - # direct access to the m2m table is the less convoluted way to achieve this (and is ok ACL-wise) - cr.execute("""SELECT DISTINCT sol.id FROM sale_order_invoice_rel rel JOIN - sale_order_line sol ON (sol.order_id = rel.order_id) - WHERE rel.invoice_id = ANY(%s)""", (list(ids),)) - return [i[0] for i in cr.fetchall()] - - def _amount_line(self, cr, uid, ids, field_name, arg, context=None): - tax_obj = self.pool.get('account.tax') - cur_obj = self.pool.get('res.currency') - res = {} - if context is None: - context = {} - for line in self.browse(cr, uid, ids, context=context): - if not line.optional: - price = line.price_unit * (1 - (line.discount or 0.0) / 100.0) - taxes = tax_obj.compute_all(cr, uid, line.tax_id, price, line.product_uom_qty, line.product_id, line.order_id.partner_id) - cur = line.order_id.pricelist_id.currency_id - res[line.id] = cur_obj.round(cr, uid, cur, taxes['total']) - else: - res[line.id] = 0 - return res - - _columns = { - 'invoiced': fields.function(_fnct_line_invoiced, string='Invoiced', type='boolean', - store={ - 'account.invoice': (_order_lines_from_invoice, ['state'], 10), - 'sale.order.line': (lambda self,cr,uid,ids,ctx=None: ids, ['invoice_lines'], 10) - }), - 'price_subtotal': fields.function(_amount_line, string='Subtotal', digits_compute= dp.get_precision('Account')), - 'optional': fields.boolean('Optional'), - } - - def _prepare_order_line_invoice_line(self, cr, uid, line, account_id=False, context=None): - if not line.optional: - return super(sale_order_line, self)._prepare_order_line_invoice_line(cr, uid, line, account_id, context=context) - else: - return False - \ No newline at end of file diff --git a/ext/custom-addons/sale_order_optional/sale_order_optional_data.xml b/ext/custom-addons/sale_order_optional/sale_order_optional_data.xml deleted file mode 100644 index d13a406f..00000000 --- a/ext/custom-addons/sale_order_optional/sale_order_optional_data.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/ext/custom-addons/sale_order_optional/sale_order_optional_view.xml b/ext/custom-addons/sale_order_optional/sale_order_optional_view.xml deleted file mode 100644 index 66056673..00000000 --- a/ext/custom-addons/sale_order_optional/sale_order_optional_view.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - sale.order.form.optional - sale.order - - - - - - - - - - diff --git a/ext/custom-addons/sale_order_optional/static/description/icon.png b/ext/custom-addons/sale_order_optional/static/description/icon.png deleted file mode 100644 index fd7ee3b90ede569d07369b51f5036c9c0de4e9b2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2870 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. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -# -############################################################################## - -import sale_order_reminder diff --git a/ext/custom-addons/sale_order_reminder/__openerp__.py b/ext/custom-addons/sale_order_reminder/__openerp__.py deleted file mode 100755 index b5fb2f90..00000000 --- a/ext/custom-addons/sale_order_reminder/__openerp__.py +++ /dev/null @@ -1,44 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# OpenERP, Open Source Management Solution -# Copyright (C) 20014-2016 Camadeus GmbH (). -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -# -############################################################################## - -{ - 'name': "Reminder for Sale Orders", - 'version': "1.0", - 'category': "Sales", - 'description': """ - This addon adds the field 'offer_valid_until' in the sale order. If this date is passed and the order is still in state 'draft' or 'sent', then - a reminder email is sent to the sales person every day. - """, - 'author': "Camadeus GmbH", - 'website': "http://www.camadeus.at", - 'css': [], - 'images': [], - 'depends': ['sale'], - 'data': ['sale_order_reminder_view.xml', - 'sale_order_reminder_data.xml', - 'email_template.xml', - ], - 'installable': True, - 'auto_install': False, - 'application': False, -} - -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/ext/custom-addons/sale_order_reminder/email_template.xml b/ext/custom-addons/sale_order_reminder/email_template.xml deleted file mode 100644 index 512bc06f..00000000 --- a/ext/custom-addons/sale_order_reminder/email_template.xml +++ /dev/null @@ -1,46 +0,0 @@ - - - - - - - - - Erinnerung: Angebot - ${(object.user_id and object.user_id.email or '')|safe} - Erinnerung: Angebot ${object.name} - ${object.user_id and object.user_id.partner_id.id} - - - -

Erinnerung für folgendes offenes Angebot:

- -

- - - - - - - - - - - - - - - - - -
Name:${object.name}
Datum: ${object.date_order}
Kunde: ${object.partner_id.display_name}
Auftragsvolumen (netto): ${object.amount_untaxed}
- -

-
- -]]>
-
-
-
diff --git a/ext/custom-addons/sale_order_reminder/sale_order_reminder.py b/ext/custom-addons/sale_order_reminder/sale_order_reminder.py deleted file mode 100644 index 3c42ac54..00000000 --- a/ext/custom-addons/sale_order_reminder/sale_order_reminder.py +++ /dev/null @@ -1,67 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# OpenERP, Open Source Management Solution -# Copyright (C) 20014-2016 Camadeus GmbH (). -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -# -############################################################################## - -from openerp import models, fields, api, _ -from datetime import datetime, timedelta -from openerp.tools import DEFAULT_SERVER_DATE_FORMAT as DATE_FORMAT - -class res_company(models.Model): - _inherit = 'res.company' - - sale_offer_days = fields.Integer(string='Tage Gültigkeit Angebot', default=14) - -class sale_order(models.Model): - _inherit = 'sale.order' - - @api.model - def _offer_valid_until(self): - user = self.env['res.users'].browse(self._uid) - - now = datetime.now() - res = now + timedelta(days=user.company_id.sale_offer_days) - return res.strftime(DATE_FORMAT) - - - offer_valid_until = fields.Date(string='Angebot gültig bis', index=True, - readonly=True, states={'draft': [('readonly', False)], 'sent': [('readonly', False)]}, - default=_offer_valid_until) - - @api.model - def order_reminder_job(self): - today = fields.Date.today() - orders = self.search([('offer_valid_until','<',today),('state','in',('draft','sent')),('user_id','!=',False)]) - template_id = self.env['ir.model.data'].xmlid_to_res_id('sale_order_reminder.email_template_sale_reminder') - context = {'append_link': True} - for order in orders: - res = self.pool.get('email.template').send_mail(self._cr, self._uid, template_id, order.id, True, context=context) - return True - -class mail_mail(models.Model): - _inherit = 'mail.mail' - - def create(self, cr, uid, vals, context=None): - # notification field: set if it comes from order reminder job - if context is None: - context = {} - - if context.get('append_link'): - vals['notification'] = True - return super(mail_mail, self).create(cr, uid, vals, context=context) \ No newline at end of file diff --git a/ext/custom-addons/sale_order_reminder/sale_order_reminder_data.xml b/ext/custom-addons/sale_order_reminder/sale_order_reminder_data.xml deleted file mode 100644 index 044a3708..00000000 --- a/ext/custom-addons/sale_order_reminder/sale_order_reminder_data.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - Reminder for Sale Orders - 1 - days - -1 - - - - - - - diff --git a/ext/custom-addons/sale_order_reminder/sale_order_reminder_view.xml b/ext/custom-addons/sale_order_reminder/sale_order_reminder_view.xml deleted file mode 100644 index 589e3c62..00000000 --- a/ext/custom-addons/sale_order_reminder/sale_order_reminder_view.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - sale_order_valid_until_form - sale.order - - - - - - - 20 - # - - - "res_company_order_days_form" - res.company - - - - - - - - - - - - diff --git a/ext/custom-addons/sale_order_reminder/static/description/icon.png b/ext/custom-addons/sale_order_reminder/static/description/icon.png deleted file mode 100644 index fd7ee3b90ede569d07369b51f5036c9c0de4e9b2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2870 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. -# -############################################################################## - -import trml2pdf -import controllers - -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: \ No newline at end of file diff --git a/ext/custom-addons/web_printscreen_zb/__openerp__.py b/ext/custom-addons/web_printscreen_zb/__openerp__.py deleted file mode 100644 index b074cd8e..00000000 --- a/ext/custom-addons/web_printscreen_zb/__openerp__.py +++ /dev/null @@ -1,41 +0,0 @@ -# -*- encoding: utf-8 -*- -############################################################################## -# -# Copyright (c) 2013 ZestyBeanz Technologies Pvt. Ltd. -# (http://wwww.zbeanztech.com) -# contact@zbeanztech.com -# prajul@zbeanztech.com -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# -############################################################################## - -{ - 'name': 'Web Printscreen ZB', - 'version': '1.0', - 'category': 'Web', - 'description': """ - Module to export current active tree view in to excel report - """, - 'author': 'Zesty Beanz Technologies', - 'website': 'http://www.zbeanztech.com', - 'depends': ['web'], - 'data': ['views/web_printscreen_zb.xml'], - 'qweb': ['static/src/xml/web_printscreen_export.xml'], - 'installable': True, - 'auto_install': False, - 'web_preload': False, -} - -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: \ No newline at end of file diff --git a/ext/custom-addons/web_printscreen_zb/controllers.py b/ext/custom-addons/web_printscreen_zb/controllers.py deleted file mode 100644 index 8c383af8..00000000 --- a/ext/custom-addons/web_printscreen_zb/controllers.py +++ /dev/null @@ -1,185 +0,0 @@ -# -*- encoding: utf-8 -*- -############################################################################## -# -# Copyright (c) 2013 ZestyBeanz Technologies Pvt. Ltd. -# (http://wwww.zbeanztech.com) -# contact@zbeanztech.com -# prajul@zbeanztech.com -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# -############################################################################## - -try: - import json -except ImportError: - import simplejson as json -import openerp.addons.web.http as openerpweb -from openerp.addons.web.controllers.main import ExcelExport -from openerp.addons.web.controllers.main import Export -import re -from cStringIO import StringIO -from lxml import etree -import trml2pdf -import time, os -import locale -import openerp.tools as tools -try: - import xlwt -except ImportError: - xlwt = None - -class ZbExcelExport(ExcelExport): - _cp_path = '/web/export/zb_excel_export' - - def from_data(self, fields, rows): - workbook = xlwt.Workbook() - worksheet = workbook.add_sheet('Sheet 1') - style = xlwt.easyxf('align: wrap yes') - font = xlwt.Font() - font.bold = True - style.font = font - ignore_index = [] - count = 0 - for i, fieldname in enumerate(fields): - if fieldname.get('header_data_id', False): - field_name = fieldname.get('header_name', '') - worksheet.write(0, i-count, field_name, style) - worksheet.col(i).width = 8000 - else: - count += 1 - ignore_index.append(i) - style = xlwt.easyxf('align: wrap yes') - bold_style = xlwt.easyxf('align: wrap yes') - font = xlwt.Font() - font.bold = True - bold_style.font = font - for row_index, row in enumerate(rows): - count = 0 - for cell_index, cell_value in enumerate(row): - if cell_index not in ignore_index: - cell_style = style - if cell_value.get('bold', False): - cell_style = bold_style - cellvalue = cell_value.get('data', '') - if isinstance(cellvalue, basestring): - cellvalue = re.sub("\r", " ", cellvalue) - if cell_value.get('number', False) and cellvalue: - cellvalue = float(cellvalue) - if cellvalue is False: cellvalue = None - worksheet.write(row_index + 1, cell_index - count, cellvalue, cell_style) - else: - count += 1 - fp = StringIO() - workbook.save(fp) - fp.seek(0) - data = fp.read() - fp.close() - return data - - @openerpweb.httprequest - def index(self, req, data, token): - data = json.loads(data) - return req.make_response( - self.from_data(data.get('headers', []), data.get('rows', [])), - headers=[ - ('Content-Disposition', 'attachment; filename="%s"' - % data.get('model', 'Export.xls')), - ('Content-Type', self.content_type) - ], - cookies={'fileToken': token} - ) - -class ExportPdf(Export): - _cp_path = '/web/export/zb_pdf' - fmt = { - 'tag': 'pdf', - 'label': 'PDF', - 'error': None - } - - @property - def content_type(self): - return 'application/pdf' - - def filename(self, base): - return base + '.pdf' - - def from_data(self, uid, fields, rows, company_name): - pageSize=[210.0,297.0] - new_doc = etree.Element("report") - config = etree.SubElement(new_doc, 'config') - def _append_node(name, text): - n = etree.SubElement(config, name) - n.text = text - _append_node('date', time.strftime(str(locale.nl_langinfo(locale.D_FMT).replace('%y', '%Y')))) - _append_node('PageSize', '%.2fmm,%.2fmm' % tuple(pageSize)) - _append_node('PageWidth', '%.2f' % (pageSize[0] * 2.8346,)) - _append_node('PageHeight', '%.2f' %(pageSize[1] * 2.8346,)) - _append_node('PageFormat', 'a4') - _append_node('header-date', time.strftime(str(locale.nl_langinfo(locale.D_FMT).replace('%y', '%Y')))) - _append_node('company', company_name) - l = [] - t = 0 - temp = [] - tsum = [] - skip_index = [] - header = etree.SubElement(new_doc, 'header') - i = 0 - for f in fields: - if f.get('header_data_id', False): - value = f.get('header_name', "") - field = etree.SubElement(header, 'field') - field.text = tools.ustr(value) - else: - skip_index.append(i) - i += 1 - lines = etree.SubElement(new_doc, 'lines') - for row_lines in rows: - node_line = etree.SubElement(lines, 'row') - j = 0 - for row in row_lines: - if not j in skip_index: - para = "yes" - tree = "no" - value = row.get('data', '') - if row.get('bold', False): - para = "group" - if row.get('number', False): - tree = "float" - col = etree.SubElement(node_line, 'col', para=para, tree=tree) - col.text = tools.ustr(value) - j += 1 - transform = etree.XSLT( - etree.parse(os.path.join(tools.config['root_path'], - 'addons/base/report/custom_new.xsl'))) - rml = etree.tostring(transform(new_doc)) - self.obj = trml2pdf.parseNode(rml, title='Printscreen') - return self.obj - -class ZbPdfExport(ExportPdf): - _cp_path = '/web/export/zb_pdf_export' - - @openerpweb.httprequest - def index(self, req, data, token): - data = json.loads(data) - uid = data.get('uid', False) - return req.make_response(self.from_data(uid, data.get('headers', []), data.get('rows', []), - data.get('company_name','')), - headers=[('Content-Disposition', - 'attachment; filename=PDF Export'), - ('Content-Type', self.content_type)]) -# cookies={'fileToken': long(token)}) - -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/ext/custom-addons/web_printscreen_zb/static/src/js/web_printscreen_export.js b/ext/custom-addons/web_printscreen_zb/static/src/js/web_printscreen_export.js deleted file mode 100644 index dfcbe0a2..00000000 --- a/ext/custom-addons/web_printscreen_zb/static/src/js/web_printscreen_export.js +++ /dev/null @@ -1,122 +0,0 @@ -openerp.web_printscreen_zb = function(instance, m) { - - var _t = instance.web._t; - var QWeb = instance.web.qweb; - - instance.web.ListView.include({ - load_list: function () { - var self = this; - this._super.apply(this, arguments); - self.$pager.find(".oe_list_button_import_excel").unbind('click').click(function(event){self.export_to_excel("excel")}) - self.$pager.find(".oe_list_button_import_pdf").unbind('click').click(function(event){self.export_to_excel("pdf")}) - }, - export_to_excel: function(export_type) { - var self = this - var export_type = export_type - view = this.getParent() - // Find Header Element - header_eles = self.$el.find('.oe_list_header_columns') - header_name_list = [] - $.each(header_eles,function(){ - $header_ele = $(this) - header_td_elements = $header_ele.find('th') - $.each(header_td_elements,function(){ - $header_td = $(this) - text = $header_td.text().trim() || "" - data_id = $header_td.attr('data-id') - if (text && !data_id){ - data_id = 'group_name' - } - header_name_list.push({'header_name': text.trim(), 'header_data_id': data_id}) - // } - }); - }); - - //Find Data Element - data_eles = self.$el.find('.oe_list_content > tbody > tr') - export_data = [] - $.each(data_eles,function(){ - data = [] - $data_ele = $(this) - is_analysis = false - if ($data_ele.text().trim()){ - //Find group name - group_th_eles = $data_ele.find('th') - $.each(group_th_eles,function(){ - $group_th_ele = $(this) - text = $group_th_ele.text().trim() || "" - is_analysis = true - data.push({'data': text, 'bold': true}) - }); - data_td_eles = $data_ele.find('td') - $.each(data_td_eles,function(){ - $data_td_ele = $(this) - text = $data_td_ele.text().trim() || "" - if ($data_td_ele && $data_td_ele[0].classList.contains('oe_number') && !$data_td_ele[0].classList.contains('oe_list_field_float_time')){ - text = text.replace('%', '') - text = instance.web.parse_value(text, { type:"float" }) - data.push({'data': text || "", 'number': true}) - } - else{ - data.push({'data': text}) - } - }); - export_data.push(data) - } - }); - - //Find Footer Element - - footer_eles = self.$el.find('.oe_list_content > tfoot> tr') - $.each(footer_eles,function(){ - data = [] - $footer_ele = $(this) - footer_td_eles = $footer_ele.find('td') - $.each(footer_td_eles,function(){ - $footer_td_ele = $(this) - text = $footer_td_ele.text().trim() || "" - if ($footer_td_ele && $footer_td_ele[0].classList.contains('oe_number')){ - text = instance.web.parse_value(text, { type:"float" }) - data.push({'data': text || "", 'bold': true, 'number': true}) - } - else{ - data.push({'data': text, 'bold': true}) - } - }); - export_data.push(data) - }); - - //Export to excel - $.blockUI(); - if (export_type === 'excel'){ - view.session.get_file({ - url: '/web/export/zb_excel_export', - data: {data: JSON.stringify({ - model : view.model, - headers : header_name_list, - rows : export_data, - })}, - complete: $.unblockUI - }); - } - else{ - console.log(view) - new instance.web.Model("res.users").get_func("read")(this.session.uid, ["company_id"]).then(function(res) { - new instance.web.Model("res.company").get_func("read")(res['company_id'][0], ["name"]).then(function(result) { - view.session.get_file({ - url: '/web/export/zb_pdf_export', - data: {data: JSON.stringify({ - uid: view.session.uid, - model : view.model, - headers : header_name_list, - rows : export_data, - company_name: result['name'] - })}, - complete: $.unblockUI - }); - }); - }); - } - }, - }); -}; diff --git a/ext/custom-addons/web_printscreen_zb/static/src/xml/web_printscreen_export.xml b/ext/custom-addons/web_printscreen_zb/static/src/xml/web_printscreen_export.xml deleted file mode 100644 index 7af23f9e..00000000 --- a/ext/custom-addons/web_printscreen_zb/static/src/xml/web_printscreen_export.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - PDF - - Excel - - - diff --git a/ext/custom-addons/web_printscreen_zb/trml2pdf.py b/ext/custom-addons/web_printscreen_zb/trml2pdf.py deleted file mode 100644 index 5a29c331..00000000 --- a/ext/custom-addons/web_printscreen_zb/trml2pdf.py +++ /dev/null @@ -1,1044 +0,0 @@ -# -*- encoding: utf-8 -*- -############################################################################## -# -# Copyright (c) 2013 ZestyBeanz Technologies Pvt. Ltd. -# (http://wwww.zbeanztech.com) -# contact@zbeanztech.com -# prajul@zbeanztech.com -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# -############################################################################## - - -import sys -import copy -import reportlab -import re -from reportlab.pdfgen import canvas -from reportlab import platypus -from openerp.report.render.rml2pdf import utils -from openerp.report.render.rml2pdf import color -import os -import logging -from lxml import etree -import base64 -from reportlab.platypus.doctemplate import ActionFlowable -from openerp.tools.safe_eval import safe_eval as eval -from reportlab.lib.units import inch,cm,mm -from openerp.tools.misc import file_open -from reportlab.pdfbase import pdfmetrics -from reportlab.lib.pagesizes import A4, letter - -try: - from cStringIO import StringIO - _hush_pyflakes = [ StringIO ] -except ImportError: - from StringIO import StringIO - -_logger = logging.getLogger(__name__) - -encoding = 'utf-8' - -def _open_image(filename, path=None): - """Attempt to open a binary file and return the descriptor - """ - if os.path.isfile(filename): - return open(filename, 'rb') - for p in (path or []): - if p and os.path.isabs(p): - fullpath = os.path.join(p, filename) - if os.path.isfile(fullpath): - return open(fullpath, 'rb') - try: - if p: - fullpath = os.path.join(p, filename) - else: - fullpath = filename - return file_open(fullpath) - except IOError: - pass - raise IOError("File %s cannot be found in image path" % filename) - -class NumberedCanvas(canvas.Canvas): - def __init__(self, *args, **kwargs): - canvas.Canvas.__init__(self, *args, **kwargs) - self._codes = [] - self._flag=False - self._pageCount=0 - self._currentPage =0 - self._pageCounter=0 - self.pages={} - - def showPage(self): - self._currentPage +=1 - if not self._flag: - self._pageCount += 1 - else: - self.pages.update({self._currentPage:self._pageCount}) - self._codes.append({'code': self._code, 'stack': self._codeStack}) - self._startPage() - self._flag=False - - def pageCount(self): - if self.pages.get(self._pageCounter,False): - self._pageNumber=0 - self._pageCounter +=1 - key=self._pageCounter - if not self.pages.get(key,False): - while not self.pages.get(key,False): - key += 1 - self.setFont("Helvetica", 8) - self.drawRightString((self._pagesize[0]-30), (self._pagesize[1]-40), - " %(this)i / %(total)i" % { - 'this': self._pageNumber+1, - 'total': self.pages.get(key,False), - } - ) - - def save(self): - """add page info to each page (page x of y)""" - # reset page counter - self._pageNumber = 0 - for code in self._codes: - self._code = code['code'] - self._codeStack = code['stack'] - self.pageCount() - canvas.Canvas.showPage(self) -# self.restoreState() - self._doc.SaveToFile(self._filename, self) - -class PageCount(platypus.Flowable): - def __init__(self, story_count=0): - platypus.Flowable.__init__(self) - self.story_count = story_count - - def draw(self): - self.canv.beginForm("pageCount%d" % self.story_count) - self.canv.setFont("Helvetica", utils.unit_get(str(8))) - self.canv.drawString(0, 0, str(self.canv.getPageNumber())) - self.canv.endForm() - -class PageReset(platypus.Flowable): - def draw(self): - self.canv._doPageReset = True -class PageReset(platypus.Flowable): - def draw(self): - self.canv._doPageReset = True - -class _rml_styles(object,): - def __init__(self, nodes, localcontext): - self.localcontext = localcontext - self.styles = {} - self.styles_obj = {} - self.names = {} - self.table_styles = {} - self.default_style = reportlab.lib.styles.getSampleStyleSheet() - - for node in nodes: - for style in node.findall('blockTableStyle'): - self.table_styles[style.get('id')] = self._table_style_get(style) - for style in node.findall('paraStyle'): - sname = style.get('name') - self.styles[sname] = self._para_style_update(style) - - self.styles_obj[sname] = reportlab.lib.styles.ParagraphStyle(sname, self.default_style["Normal"], **self.styles[sname]) - - for variable in node.findall('initialize'): - for name in variable.findall('name'): - self.names[ name.get('id')] = name.get('value') - - def _para_style_update(self, node): - data = {} - for attr in ['textColor', 'backColor', 'bulletColor', 'borderColor']: - if node.get(attr): - data[attr] = color.get(node.get(attr)) - for attr in ['fontName', 'bulletFontName', 'bulletText']: - if node.get(attr): - data[attr] = node.get(attr) - for attr in ['fontSize', 'leftIndent', 'rightIndent', 'spaceBefore', 'spaceAfter', - 'firstLineIndent', 'bulletIndent', 'bulletFontSize', 'leading', - 'borderWidth','borderPadding','borderRadius']: - if node.get(attr): - data[attr] = utils.unit_get(node.get(attr)) - if node.get('alignment'): - align = { - 'right':reportlab.lib.enums.TA_RIGHT, - 'center':reportlab.lib.enums.TA_CENTER, - 'justify':reportlab.lib.enums.TA_JUSTIFY - } - data['alignment'] = align.get(node.get('alignment').lower(), reportlab.lib.enums.TA_LEFT) - return data - - def _table_style_get(self, style_node): - styles = [] - for node in style_node: - start = utils.tuple_int_get(node, 'start', (0,0) ) - stop = utils.tuple_int_get(node, 'stop', (-1,-1) ) - if node.tag=='blockValign': - styles.append(('VALIGN', start, stop, str(node.get('value')))) - elif node.tag=='blockFont': - styles.append(('FONT', start, stop, str(node.get('name')))) - elif node.tag=='blockTextColor': - styles.append(('TEXTCOLOR', start, stop, color.get(str(node.get('colorName'))))) - elif node.tag=='blockLeading': - styles.append(('LEADING', start, stop, utils.unit_get(node.get('length')))) - elif node.tag=='blockAlignment': - styles.append(('ALIGNMENT', start, stop, str(node.get('value')))) - elif node.tag=='blockSpan': - styles.append(('SPAN', start, stop)) - elif node.tag=='blockLeftPadding': - styles.append(('LEFTPADDING', start, stop, utils.unit_get(node.get('length')))) - elif node.tag=='blockRightPadding': - styles.append(('RIGHTPADDING', start, stop, utils.unit_get(node.get('length')))) - elif node.tag=='blockTopPadding': - styles.append(('TOPPADDING', start, stop, utils.unit_get(node.get('length')))) - elif node.tag=='blockBottomPadding': - styles.append(('BOTTOMPADDING', start, stop, utils.unit_get(node.get('length')))) - elif node.tag=='blockBackground': - styles.append(('BACKGROUND', start, stop, color.get(node.get('colorName')))) - if node.get('size'): - styles.append(('FONTSIZE', start, stop, utils.unit_get(node.get('size')))) - elif node.tag=='lineStyle': - kind = node.get('kind') - kind_list = [ 'GRID', 'BOX', 'OUTLINE', 'INNERGRID', 'LINEBELOW', 'LINEABOVE','LINEBEFORE', 'LINEAFTER' ] - assert kind in kind_list - thick = 1 - if node.get('thickness'): - thick = float(node.get('thickness')) - styles.append((kind, start, stop, thick, color.get(node.get('colorName')))) - return platypus.tables.TableStyle(styles) - - def para_style_get(self, node): - style = False - sname = node.get('style') - if sname: - if sname in self.styles_obj: - style = self.styles_obj[sname] - else: - _logger.warning('Warning: style not found, %s - setting default!\n' % (node.get('style'),) ) - if not style: - style = self.default_style['Normal'] - para_update = self._para_style_update(node) - if para_update: - # update style only is necessary - style = copy.deepcopy(style) - style.__dict__.update(para_update) - return style - -class _rml_doc(object): - def __init__(self, node, localcontext=None, images=None, path='.', title=None): - if images is None: - images = {} - if localcontext is None: - localcontext = {} - self.localcontext = localcontext - self.etree = node - self.filename = self.etree.get('filename') - self.images = images - self.path = path - self.title = title - - def docinit(self, els): - from reportlab.lib.fonts import addMapping - from reportlab.pdfbase import pdfmetrics - from reportlab.pdfbase.ttfonts import TTFont - - for node in els: - for font in node.findall('registerFont'): - name = font.get('fontName').encode('ascii') - fname = font.get('fontFile').encode('ascii') - if name not in pdfmetrics._fonts: - pdfmetrics.registerFont(TTFont(name, fname)) - addMapping(name, 0, 0, name) #normal - addMapping(name, 0, 1, name) #italic - addMapping(name, 1, 0, name) #bold - addMapping(name, 1, 1, name) #italic and bold - - def setTTFontMapping(self,face, fontname, filename, mode='all'): - from reportlab.lib.fonts import addMapping - from reportlab.pdfbase import pdfmetrics - from reportlab.pdfbase.ttfonts import TTFont - - if fontname not in pdfmetrics._fonts: - pdfmetrics.registerFont(TTFont(fontname, filename)) - if mode == 'all': - addMapping(face, 0, 0, fontname) #normal - addMapping(face, 0, 1, fontname) #italic - addMapping(face, 1, 0, fontname) #bold - addMapping(face, 1, 1, fontname) #italic and bold - elif (mode== 'normal') or (mode == 'regular'): - addMapping(face, 0, 0, fontname) #normal - elif mode == 'italic': - addMapping(face, 0, 1, fontname) #italic - elif mode == 'bold': - addMapping(face, 1, 0, fontname) #bold - elif mode == 'bolditalic': - addMapping(face, 1, 1, fontname) #italic and bold - - def _textual_image(self, node): - rc = '' - for n in node: - rc +=( etree.tostring(n) or '') + n.tail - return base64.decodestring(node.tostring()) - - def _images(self, el): - result = {} - for node in el.findall('.//image'): - rc =( node.text or '') - result[node.get('name')] = base64.decodestring(rc) - return result - - def render(self, out): - el = self.etree.findall('.//docinit') - if el: - self.docinit(el) - - el = self.etree.findall('.//stylesheet') - self.styles = _rml_styles(el,self.localcontext) - - el = self.etree.findall('.//images') - if el: - self.images.update( self._images(el[0]) ) - - el = self.etree.findall('.//template') - if len(el): - pt_obj = _rml_template(self.localcontext, out, el[0], self, images=self.images, path=self.path, title=self.title) - el = utils._child_get(self.etree, self, 'story') - pt_obj.render(el) - else: - self.canvas = canvas.Canvas(out) - pd = self.etree.find('pageDrawing')[0] - pd_obj = _rml_canvas(self.canvas, self.localcontext, None, self, self.images, path=self.path, title=self.title) - pd_obj.render(pd) - - self.canvas.showPage() - self.canvas.save() - -class _rml_canvas(object): - def __init__(self, canvas, localcontext, doc_tmpl=None, doc=None, images=None, path='.', title=None): - if images is None: - images = {} - self.localcontext = localcontext - self.canvas = canvas - self.styles = doc.styles - self.doc_tmpl = doc_tmpl - self.doc = doc - self.images = images - self.path = path - self.title = title - if self.title: - self.canvas.setTitle(self.title) - - def _textual(self, node, x=0, y=0): - text = node.text and node.text.encode('utf-8') or '' - rc = utils._process_text(self, text) - for n in node: - if n.tag == 'seq': - from reportlab.lib.sequencer import getSequencer - seq = getSequencer() - rc += str(seq.next(n.get('id'))) - if n.tag == 'pageCount': - if x or y: - self.canvas.translate(x,y) - self.canvas.doForm('pageCount%s' % (self.canvas._storyCount,)) - if x or y: - self.canvas.translate(-x,-y) - if n.tag == 'pageNumber': - rc += str(self.canvas.getPageNumber()) - rc += utils._process_text(self, n.tail) - return rc.replace('\n','') - - def _drawString(self, node): - v = utils.attr_get(node, ['x','y']) - text=self._textual(node, **v) - text = utils.xml2str(text) - self.canvas.drawString(text=text, **v) - - def _drawCenteredString(self, node): - v = utils.attr_get(node, ['x','y']) - text=self._textual(node, **v) - text = utils.xml2str(text) - self.canvas.drawCentredString(text=text, **v) - - def _drawRightString(self, node): - v = utils.attr_get(node, ['x','y']) - text=self._textual(node, **v) - text = utils.xml2str(text) - self.canvas.drawRightString(text=text, **v) - - def _rect(self, node): - if node.get('round'): - self.canvas.roundRect(radius=utils.unit_get(node.get('round')), **utils.attr_get(node, ['x','y','width','height'], {'fill':'bool','stroke':'bool'})) - else: - self.canvas.rect(**utils.attr_get(node, ['x','y','width','height'], {'fill':'bool','stroke':'bool'})) - - def _ellipse(self, node): - x1 = utils.unit_get(node.get('x')) - x2 = utils.unit_get(node.get('width')) - y1 = utils.unit_get(node.get('y')) - y2 = utils.unit_get(node.get('height')) - - self.canvas.ellipse(x1,y1,x2,y2, **utils.attr_get(node, [], {'fill':'bool','stroke':'bool'})) - - def _curves(self, node): - line_str = node.text.split() - lines = [] - while len(line_str)>7: - self.canvas.bezier(*[utils.unit_get(l) for l in line_str[0:8]]) - line_str = line_str[8:] - - def _lines(self, node): - line_str = node.text.split() - lines = [] - while len(line_str)>3: - lines.append([utils.unit_get(l) for l in line_str[0:4]]) - line_str = line_str[4:] - self.canvas.lines(lines) - - def _grid(self, node): - xlist = [utils.unit_get(s) for s in node.get('xs').split(',')] - ylist = [utils.unit_get(s) for s in node.get('ys').split(',')] - - self.canvas.grid(xlist, ylist) - - def _translate(self, node): - dx = utils.unit_get(node.get('dx')) or 0 - dy = utils.unit_get(node.get('dy')) or 0 - self.canvas.translate(dx,dy) - - def _circle(self, node): - self.canvas.circle(x_cen=utils.unit_get(node.get('x')), y_cen=utils.unit_get(node.get('y')), r=utils.unit_get(node.get('radius')), **utils.attr_get(node, [], {'fill':'bool','stroke':'bool'})) - - def _place(self, node): - flows = _rml_flowable(self.doc, self.localcontext, images=self.images, path=self.path, title=self.title).render(node) - infos = utils.attr_get(node, ['x','y','width','height']) - - infos['y']+=infos['height'] - for flow in flows: - w,h = flow.wrap(infos['width'], infos['height']) - if w<=infos['width'] and h<=infos['height']: - infos['y']-=h - flow.drawOn(self.canvas,infos['x'],infos['y']) - infos['height']-=h - else: - raise ValueError("Not enough space") - - def _line_mode(self, node): - ljoin = {'round':1, 'mitered':0, 'bevelled':2} - lcap = {'default':0, 'round':1, 'square':2} - - if node.get('width'): - self.canvas.setLineWidth(utils.unit_get(node.get('width'))) - if node.get('join'): - self.canvas.setLineJoin(ljoin[node.get('join')]) - if node.get('cap'): - self.canvas.setLineCap(lcap[node.get('cap')]) - if node.get('miterLimit'): - self.canvas.setDash(utils.unit_get(node.get('miterLimit'))) - if node.get('dash'): - dashes = node.get('dash').split(',') - for x in range(len(dashes)): - dashes[x]=utils.unit_get(dashes[x]) - self.canvas.setDash(node.get('dash').split(',')) - - def _image(self, node): - import urllib - import urlparse - from reportlab.lib.utils import ImageReader - nfile = node.get('file') - if not nfile: - if node.get('name'): - image_data = self.images[node.get('name')] - _logger.debug("Image %s used", node.get('name')) - s = StringIO(image_data) - else: - newtext = node.text - if self.localcontext: - res = utils._regex.findall(newtext) - for key in res: - newtext = eval(key, {}, self.localcontext) or '' - image_data = None - if newtext: - image_data = base64.decodestring(newtext) - if image_data: - s = StringIO(image_data) - else: - _logger.debug("No image data!") - return False - else: - if nfile in self.images: - s = StringIO(self.images[nfile]) - else: - try: - up = urlparse.urlparse(str(nfile)) - except ValueError: - up = False - if up and up.scheme: - # RFC: do we really want to open external URLs? - # Are we safe from cross-site scripting or attacks? - _logger.debug("Retrieve image from %s", nfile) - u = urllib.urlopen(str(nfile)) - s = StringIO(u.read()) - else: - _logger.debug("Open image file %s ", nfile) - s = _open_image(nfile, path=self.path) - try: - img = ImageReader(s) - (sx,sy) = img.getSize() - _logger.debug("Image is %dx%d", sx, sy) - args = { 'x': 0.0, 'y': 0.0, 'mask': 'auto'} - for tag in ('width','height','x','y'): - if node.get(tag): - args[tag] = utils.unit_get(node.get(tag)) - if ('width' in args) and (not 'height' in args): - args['height'] = sy * args['width'] / sx - elif ('height' in args) and (not 'width' in args): - args['width'] = sx * args['height'] / sy - elif ('width' in args) and ('height' in args): - if (float(args['width'])/args['height'])>(float(sx)>sy): - args['width'] = sx * args['height'] / sy - else: - args['height'] = sy * args['width'] / sx - self.canvas.drawImage(img, **args) - finally: - s.close() -# self.canvas._doc.SaveToFile(self.canvas._filename, self.canvas) - - def _path(self, node): - self.path = self.canvas.beginPath() - self.path.moveTo(**utils.attr_get(node, ['x','y'])) - for n in utils._child_get(node, self): - if not n.text : - if n.tag=='moveto': - vals = utils.text_get(n).split() - self.path.moveTo(utils.unit_get(vals[0]), utils.unit_get(vals[1])) - elif n.tag=='curvesto': - vals = utils.text_get(n).split() - while len(vals)>5: - pos=[] - while len(pos)<6: - pos.append(utils.unit_get(vals.pop(0))) - self.path.curveTo(*pos) - elif n.text: - data = n.text.split() # Not sure if I must merge all TEXT_NODE ? - while len(data)>1: - x = utils.unit_get(data.pop(0)) - y = utils.unit_get(data.pop(0)) - self.path.lineTo(x,y) - if (not node.get('close')) or utils.bool_get(node.get('close')): - self.path.close() - self.canvas.drawPath(self.path, **utils.attr_get(node, [], {'fill':'bool','stroke':'bool'})) - - def setFont(self, node): - fontname = node.get('name') - if fontname not in pdfmetrics.getRegisteredFontNames()\ - or fontname not in pdfmetrics.standardFonts: - # let reportlab attempt to find it - try: - pdfmetrics.getFont(fontname) - except Exception: - _logger.debug('Could not locate font %s, substituting default: %s', - fontname, - self.canvas._fontname) - fontname = self.canvas._fontname - return self.canvas.setFont(fontname, utils.unit_get(node.get('size'))) - - def render(self, node): - tags = { - 'drawCentredString': self._drawCenteredString, - 'drawRightString': self._drawRightString, - 'drawString': self._drawString, - 'rect': self._rect, - 'ellipse': self._ellipse, - 'lines': self._lines, - 'grid': self._grid, - 'curves': self._curves, - 'fill': lambda node: self.canvas.setFillColor(color.get(node.get('color'))), - 'stroke': lambda node: self.canvas.setStrokeColor(color.get(node.get('color'))), - 'setFont': self.setFont , - 'place': self._place, - 'circle': self._circle, - 'lineMode': self._line_mode, - 'path': self._path, - 'rotate': lambda node: self.canvas.rotate(float(node.get('degrees'))), - 'translate': self._translate, - 'image': self._image - } - for n in utils._child_get(node, self): - if n.tag in tags: - tags[n.tag](n) - -class _rml_draw(object): - def __init__(self, localcontext, node, styles, images=None, path='.', title=None): - if images is None: - images = {} - self.localcontext = localcontext - self.node = node - self.styles = styles - self.canvas = None - self.images = images - self.path = path - self.canvas_title = title - - def render(self, canvas, doc): - canvas.saveState() - cnv = _rml_canvas(canvas, self.localcontext, doc, self.styles, images=self.images, path=self.path, title=self.canvas_title) - cnv.render(self.node) - canvas.restoreState() - -class _rml_Illustration(platypus.flowables.Flowable): - def __init__(self, node, localcontext, styles, self2): - self.localcontext = (localcontext or {}).copy() - self.node = node - self.styles = styles - self.width = utils.unit_get(node.get('width')) - self.height = utils.unit_get(node.get('height')) - self.self2 = self2 - def wrap(self, *args): - return self.width, self.height - def draw(self): - drw = _rml_draw(self.localcontext ,self.node,self.styles, images=self.self2.images, path=self.self2.path, title=self.self2.title) - drw.render(self.canv, None) - -class _rml_flowable(object): - def __init__(self, doc, localcontext, images=None, path='.', title=None): - if images is None: - images = {} - self.localcontext = localcontext - self.doc = doc - self.styles = doc.styles - self.images = images - self.path = path - self.title = title - - def _textual(self, node): - rc1 = utils._process_text(self, node.text or '') - for n in utils._child_get(node,self): - txt_n = copy.deepcopy(n) - for key in txt_n.attrib.keys(): - if key in ('rml_except', 'rml_loop', 'rml_tag'): - del txt_n.attrib[key] - if not n.tag == 'bullet': - txt_n.text = utils.xml2str(self._textual(n)) - txt_n.tail = n.tail and utils.xml2str(utils._process_text(self, n.tail.replace('\n',''))) or '' - rc1 += etree.tostring(txt_n) - return rc1 - - def _table(self, node): - children = utils._child_get(node,self,'tr') - if not children: - return None - length = 0 - colwidths = None - rowheights = None - data = [] - styles = [] - posy = 0 - for tr in children: - paraStyle = None - if tr.get('style'): - st = copy.deepcopy(self.styles.table_styles[tr.get('style')]) - for si in range(len(st._cmds)): - s = list(st._cmds[si]) - s[1] = (s[1][0],posy) - s[2] = (s[2][0],posy) - st._cmds[si] = tuple(s) - styles.append(st) - if tr.get('paraStyle'): - paraStyle = self.styles.styles[tr.get('paraStyle')] - data2 = [] - posx = 0 - for td in utils._child_get(tr, self,'td'): - if td.get('style'): - st = copy.deepcopy(self.styles.table_styles[td.get('style')]) - for s in st._cmds: - s[1][1] = posy - s[2][1] = posy - s[1][0] = posx - s[2][0] = posx - styles.append(st) - if td.get('paraStyle'): - # TODO: merge styles - paraStyle = self.styles.styles[td.get('paraStyle')] - posx += 1 - - flow = [] - for n in utils._child_get(td, self): - if n.tag == etree.Comment: - n.text = '' - continue - fl = self._flowable(n, extra_style=paraStyle) - if isinstance(fl,list): - flow += fl - else: - flow.append( fl ) - - if not len(flow): - flow = self._textual(td) - data2.append( flow ) - if len(data2)>length: - length=len(data2) - for ab in data: - while len(ab) tag: - # - we reset page number to 0 - # - we add an new PageCount flowable (relative to the current - # story number), but not for NumeredCanvas at is handle page - # count itself) - # NOTE: _rml_template render() method add a PageReset flowable at end - # of each story, so we're sure to pass here at least once per story. - if not isinstance(self.canv, NumberedCanvas): - self.handle_flowable([ PageCount(story_count=self.canv._storyCount) ]) - self.canv._pageCount = self.page - self.page = 0 - self.canv._flag = True - self.canv._pageNumber = 0 - self.canv._doPageReset = False - self.canv._storyCount += 1 - -class _rml_template(object): - def __init__(self, localcontext, out, node, doc, images=None, path='.', title=None): - if images is None: - images = {} - if not localcontext: - localcontext={'internal_header':True} - self.localcontext = localcontext - self.images= images - self.path = path - self.title = title - - pagesize_map = {'a4': A4, - 'us_letter': letter - } - pageSize = (841.8897637795275, 595.275590551181) - self.doc_tmpl = TinyDocTemplate(out, pagesize=pageSize, **utils.attr_get(node, ['leftMargin','rightMargin','topMargin','bottomMargin'], {'allowSplitting':'int','showBoundary':'bool','rotation':'int','title':'str','author':'str'})) - self.page_templates = [] - self.styles = doc.styles - self.doc = doc - self.image=[] - pts = node.findall('pageTemplate') - for pt in pts: - frames = [] - for frame_el in pt.findall('frame'): - frame = platypus.Frame( **(utils.attr_get(frame_el, ['x1','y1', 'width','height', 'leftPadding', 'rightPadding', 'bottomPadding', 'topPadding'], {'id':'str', 'showBoundary':'bool'})) ) - if utils.attr_get(frame_el, ['last']): - frame.lastFrame = True - frames.append( frame ) - try : - gr = pt.findall('pageGraphics')\ - or pt[1].findall('pageGraphics') - except Exception: # FIXME: be even more specific, perhaps? - gr='' - if len(gr): -# self.image=[ n for n in utils._child_get(gr[0], self) if n.tag=='image' or not self.localcontext] - drw = _rml_draw(self.localcontext,gr[0], self.doc, images=images, path=self.path, title=self.title) - self.page_templates.append( platypus.PageTemplate(frames=frames, onPage=drw.render, **utils.attr_get(pt, [], {'id':'str'}) )) - else: - drw = _rml_draw(self.localcontext,node,self.doc,title=self.title) - self.page_templates.append( platypus.PageTemplate(frames=frames,onPage=drw.render, **utils.attr_get(pt, [], {'id':'str'}) )) - self.doc_tmpl.addPageTemplates(self.page_templates) - - def render(self, node_stories): - if self.localcontext and not self.localcontext.get('internal_header',False): - del self.localcontext['internal_header'] - fis = [] - r = _rml_flowable(self.doc,self.localcontext, images=self.images, path=self.path, title=self.title) - story_cnt = 0 - for node_story in node_stories: - if story_cnt > 0: - fis.append(platypus.PageBreak()) - fis += r.render(node_story) - # Reset Page Number with new story tag - fis.append(PageReset()) - story_cnt += 1 - if self.localcontext and self.localcontext.get('internal_header',False): - self.doc_tmpl.afterFlowable(fis) - self.doc_tmpl.build(fis,canvasmaker=NumberedCanvas) - else: - self.doc_tmpl.build(fis) - -def parseNode(rml, localcontext=None, fout=None, images=None, path='.', title=None): - node = etree.XML(rml) - r = _rml_doc(node, localcontext, images, path, title=title) - #try to override some font mappings - try: - from customfonts import SetCustomFonts - SetCustomFonts(r) - except ImportError: - # means there is no custom fonts mapping in this system. - pass - except Exception: - _logger.warning('Cannot set font mapping', exc_info=True) - pass - fp = StringIO() - r.render(fp) - return fp.getvalue() - -def parseString(rml, localcontext=None, fout=None, images=None, path='.', title=None): - node = etree.XML(rml) - r = _rml_doc(node, localcontext, images, path, title=title) - - #try to override some font mappings - try: - from customfonts import SetCustomFonts - SetCustomFonts(r) - except Exception: - pass - - if fout: - fp = file(fout,'wb') - r.render(fp) - fp.close() - return fout - else: - fp = StringIO() - r.render(fp) - return fp.getvalue() - -def trml2pdf_help(): - print 'Usage: trml2pdf input.rml >output.pdf' - print 'Render the standard input (RML) and output a PDF file' - sys.exit(0) - -if __name__=="__main__": - if len(sys.argv)>1: - if sys.argv[1]=='--help': - trml2pdf_help() - print parseString(file(sys.argv[1], 'r').read()), - else: - print 'Usage: trml2pdf input.rml >output.pdf' - print 'Try \'trml2pdf --help\' for more information.' - -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: \ No newline at end of file diff --git a/ext/custom-addons/web_printscreen_zb/views/web_printscreen_zb.xml b/ext/custom-addons/web_printscreen_zb/views/web_printscreen_zb.xml deleted file mode 100644 index 0386b7d2..00000000 --- a/ext/custom-addons/web_printscreen_zb/views/web_printscreen_zb.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - -