|
|
@ -1,284 +1,236 @@ |
|
|
|
# -*- coding: utf-8 -*- |
|
|
|
|
|
|
|
# This file is under GNU Affero General Public License 3.0 |
|
|
|
# see LICENSE.txt |
|
|
|
# |
|
|
|
# For more debugging, export DISTUTILS_DEBUG=True |
|
|
|
|
|
|
|
from __future__ import print_function |
|
|
|
|
|
|
|
import sys |
|
|
|
from sys import argv |
|
|
|
|
|
|
|
import os |
|
|
|
from os import environ |
|
|
|
from os.path import dirname, exists, join |
|
|
|
from os.path import join |
|
|
|
import platform |
|
|
|
|
|
|
|
from setuptools import setup, Extension |
|
|
|
from glob import glob |
|
|
|
import sysconfig |
|
|
|
|
|
|
|
if sys.platform == 'winnt': |
|
|
|
if sys.version_info[0] >= 3: |
|
|
|
import winreg |
|
|
|
else: |
|
|
|
import _winreg as winreg |
|
|
|
|
|
|
|
|
|
|
|
from setuptools.command.build_ext import build_ext |
|
|
|
|
|
|
|
verboseLevel = 0 |
|
|
|
|
|
|
|
if sys.version_info[0] < 3: |
|
|
|
FileNotFoundError = EnvironmentError |
|
|
|
|
|
|
|
def find(fname, pathlist): |
|
|
|
for path in pathlist: |
|
|
|
cand_fname = join(path, fname) |
|
|
|
if exists(cand_fname): |
|
|
|
return path |
|
|
|
raise FileNotFoundError(fname) |
|
|
|
|
|
|
|
def append_once(lst, element): |
|
|
|
if element not in lst: |
|
|
|
lst.append(element) |
|
|
|
|
|
|
|
def extend_once(lst, elements): |
|
|
|
for element in elements: |
|
|
|
if element not in lst: |
|
|
|
lst.append(element) |
|
|
|
|
|
|
|
def getPythonLibver(): |
|
|
|
g = sysconfig.get_config_vars() |
|
|
|
sent = [] |
|
|
|
for template in ( |
|
|
|
'{cmd}{py_version_nodot}{abiflags}', |
|
|
|
'{cmd}{py_version_nodot}', |
|
|
|
'{cmd}{py_version_major}', |
|
|
|
'{cmd}{py_version_major}{abiflags}', |
|
|
|
'{cmd}' |
|
|
|
): |
|
|
|
val = template.format( |
|
|
|
cmd = g['PYTHON'], |
|
|
|
py_version_nodot = g['py_version_nodot'], |
|
|
|
py_version_major = sys.version_info[0], |
|
|
|
abiflags = g.get('ABIFLAGS', ''), |
|
|
|
) |
|
|
|
if val not in sent: |
|
|
|
yield val |
|
|
|
sent.append(val) |
|
|
|
|
|
|
|
def pEpLog(*msg): |
|
|
|
if verboseLevel > 0: |
|
|
|
import inspect |
|
|
|
msgstr = '' |
|
|
|
separator = ' ' |
|
|
|
for m in msg: |
|
|
|
msgstr += str(m) |
|
|
|
msgstr += separator |
|
|
|
func = inspect.currentframe().f_back.f_code |
|
|
|
print(func.co_filename + " : " + func.co_name + " : " + msgstr) |
|
|
|
|
|
|
|
class BuildExtCommand(build_ext): |
|
|
|
|
|
|
|
# default_pyver = next( getPythonLibver() ) |
|
|
|
user_options = build_ext.user_options + [ |
|
|
|
# ('boost-python=', None, 'Boost Python version to use (e.g. \'python34\')'), |
|
|
|
('local', None, 'Use local pEp install in HOME/USERPROFILE'), |
|
|
|
('with-pEp-engine=', None, 'Path to pEp Engine source'), |
|
|
|
('with-pEp-libadapter=', None, 'Path to pEp C++ Adapter Library source'), |
|
|
|
('with-boost=', None, 'Path to Boost install prefix'), |
|
|
|
('with-asn1c-share=', None, 'Path to installed ASN1C share directory'), |
|
|
|
('local', None, 'Use local pEp install in HOME/USERPROFILE for libs/includes'), |
|
|
|
('prefix=', None, 'Use local pEp install in prefix for libs/includes'), |
|
|
|
] |
|
|
|
|
|
|
|
def windowsGetInstallLocation(): |
|
|
|
def initialize_options(self): |
|
|
|
pEpLog("called") |
|
|
|
build_ext.initialize_options(self) |
|
|
|
self.local = None != environ.get('PER_USER_DIRECTORY') |
|
|
|
self.prefix = getattr(self, "prefix=", None) |
|
|
|
|
|
|
|
def windowsGetInstallLocation(self): |
|
|
|
pEpLog("called") |
|
|
|
# Note: should be installed to 'C:\Program Files (x86)' while a 32-bit distro |
|
|
|
# TODO: Try desktop adapter location first, then COM server |
|
|
|
# FIXME: This is wrong, we should chase the COM server, not the Outlook Plugin (even if they're in the same place) |
|
|
|
REG_PATH = "Software\\Microsoft\\Office\\Outlook\\Addins\\pEp" |
|
|
|
reg_path = "Software\\Microsoft\\Office\\Outlook\\Addins\\pEp" |
|
|
|
KeyName = 'FileName' |
|
|
|
regKey = None |
|
|
|
pEpLog("Registry Lookup:", reg_path, KeyName) |
|
|
|
try: |
|
|
|
regKey = winreg.OpenKey( |
|
|
|
winreg.HKEY_LOCAL_MACHINE, REG_PATH, 0, winreg.KEY_READ) |
|
|
|
regKey = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, reg_path, 0, winreg.KEY_READ) |
|
|
|
# Keys: Description, FileName, FriendlyName, LoadBehavior |
|
|
|
com_server, regtype = winreg.QueryValueEx(regKey, 'FileName') |
|
|
|
com_server, regtype = winreg.QueryValueEx(regKey, KeyName) |
|
|
|
winreg.CloseKey(regKey) |
|
|
|
except WindowsError: |
|
|
|
pEpLog("Unknown Error") |
|
|
|
com_server = None |
|
|
|
finally: |
|
|
|
if winreg: |
|
|
|
winreg.CloseKey(regKey) |
|
|
|
# <install-base>\\bin\\COM_Server.exe |
|
|
|
dirname = os.path.dirname |
|
|
|
return dirname( dirname( com_server ) ) |
|
|
|
|
|
|
|
def initialize_options(self): |
|
|
|
build_ext.initialize_options(self) |
|
|
|
# self.boost_python = BuildExtCommand.default_pyver |
|
|
|
self.local = None != environ.get('PER_USER_DIRECTORY') |
|
|
|
self.with_pEp_engine = None |
|
|
|
self.with_pEp_libadapter = None |
|
|
|
self.with_boost = None |
|
|
|
self.with_asn1c_share = None |
|
|
|
ret = dirname(dirname(com_server)) |
|
|
|
pEpLog("Value:", ret) |
|
|
|
return ret |
|
|
|
|
|
|
|
def get_build_info_winnt(self): |
|
|
|
home = environ.get('PER_USER_DIRECTORY') or environ.get('USERPROFILE') |
|
|
|
sys_root = environ.get('SystemRoot') |
|
|
|
profile_root = environ.get('AppData') |
|
|
|
local_root = environ.get('LocalAppData') |
|
|
|
inst_prefix = self.windowsGetInstallLocation() |
|
|
|
sys_includes = [ |
|
|
|
join(inst_prefix, 'include'), |
|
|
|
join(profile_root, 'pEp', 'include'), |
|
|
|
join(local_root, 'pEp', 'include'), |
|
|
|
join(sys_root, 'pEp', 'include'), |
|
|
|
] |
|
|
|
sys_libdirs = [ |
|
|
|
join(inst_prefix, 'bin'), |
|
|
|
join(profile_root, 'pEp', 'bin'), |
|
|
|
join(local_root, 'pEp', 'bin'), |
|
|
|
join(sys_root, 'pEp', 'bin'), |
|
|
|
] |
|
|
|
libs = [ |
|
|
|
'pEpEngine', |
|
|
|
'boost_python37-mt', |
|
|
|
'boost_locale-mt' |
|
|
|
] |
|
|
|
return (home, sys_includes, sys_libdirs, libs) |
|
|
|
|
|
|
|
def get_build_info_darwin(self): |
|
|
|
home = environ.get('PER_USER_DIRECTORY') or environ.get('HOME') |
|
|
|
sys_includes = [ |
|
|
|
'/opt/local/include', |
|
|
|
'/usr/local/include', |
|
|
|
'/Library/Frameworks/PrettyEasyPrivacy.framework/Versions/A/include', |
|
|
|
'/usr/include', |
|
|
|
] |
|
|
|
sys_libdirs = [ |
|
|
|
'/opt/local/lib', |
|
|
|
'/usr/local/lib', |
|
|
|
'/Library/Frameworks/PrettyEasyPrivacy.framework/Versions/A/lib', |
|
|
|
'/usr/lib', |
|
|
|
] |
|
|
|
libs = [ |
|
|
|
'pEpEngine', |
|
|
|
'boost_python37-mt', |
|
|
|
'boost_locale-mt' |
|
|
|
] |
|
|
|
return (home, sys_includes, sys_libdirs, libs) |
|
|
|
|
|
|
|
def get_build_info_linux(self): |
|
|
|
home = environ.get('PER_USER_DIRECTORY') or environ.get('HOME') |
|
|
|
sys_includes = [ |
|
|
|
'/usr/local/include', |
|
|
|
'/usr/include', |
|
|
|
] |
|
|
|
sys_libdirs = [ |
|
|
|
'/usr/local/lib', |
|
|
|
'/usr/lib', |
|
|
|
'/usr/lib/{}-linux-gnu'.format(platform.machine()) |
|
|
|
] |
|
|
|
libs = [ |
|
|
|
'pEpEngine', |
|
|
|
'boost_python3', |
|
|
|
'boost_locale' |
|
|
|
] |
|
|
|
return (home, sys_includes, sys_libdirs, libs) |
|
|
|
|
|
|
|
def finalize_options(self): |
|
|
|
pEpLog("called") |
|
|
|
build_ext.finalize_options(self) |
|
|
|
|
|
|
|
# normalize paths given by user (expand tilde etc.) |
|
|
|
for with_option in ('pEp_engine', 'pEp_libadapter', 'boost', 'asn1c_share'): |
|
|
|
w_opt = 'with_' + with_option |
|
|
|
w_val = getattr(self, w_opt) |
|
|
|
if w_val != None: |
|
|
|
setattr(self, w_opt, os.path.normpath(w_val)) |
|
|
|
|
|
|
|
if sys.platform == 'darwin': |
|
|
|
HOME = environ.get('PER_USER_DIRECTORY') or environ.get('HOME') |
|
|
|
PEPLIBNAME = 'libpEpEngine.dylib' |
|
|
|
LIBPEPA = 'libpEpAdapter.a' |
|
|
|
BOOSTLIBNAME = 'libboost_{boost_python:s}-mt.dylib' |
|
|
|
SYS_INCLUDES = [ |
|
|
|
'/opt/local/include', # we prefer MacPorts over Homebrew (but support both) |
|
|
|
'/usr/local/include', |
|
|
|
'/Library/Frameworks/PrettyEasyPrivacy.framework/Versions/A/include', |
|
|
|
join(environ["HOME"], 'include'), |
|
|
|
'/usr/include', |
|
|
|
] |
|
|
|
SYS_SHARES = [ |
|
|
|
'/opt/local/share', |
|
|
|
'/usr/local/share', |
|
|
|
'/Library/Frameworks/PrettyEasyPrivacy.framework/Versions/A/share', |
|
|
|
join(environ["HOME"], 'share'), |
|
|
|
'/usr/share', |
|
|
|
] |
|
|
|
SYS_LIB_PREFIXES = [ |
|
|
|
'/opt/local/lib', |
|
|
|
'/usr/local/lib', |
|
|
|
'/Library/Frameworks/PrettyEasyPrivacy.framework/Versions/A/lib', |
|
|
|
join(environ["HOME"], 'lib'), |
|
|
|
'/usr/lib', |
|
|
|
] |
|
|
|
elif sys.platform == 'winnt': |
|
|
|
HOME = environ.get('PER_USER_DIRECTORY') or environ.get('USERPROFILE') |
|
|
|
SYS_ROOT = environ.get('SystemRoot') |
|
|
|
PROFILE_ROOT = environ.get('AppData') |
|
|
|
LOCAL_ROOT = environ.get('LocalAppData') |
|
|
|
INST_PREFIX = windowsGetInstallLocation() |
|
|
|
PEPLIBNAME = 'pEpEngine.dll' |
|
|
|
LIBPEPA = 'libpEpAdapter.a' |
|
|
|
BOOSTLIBNAME = 'boost_{boost_python:s}-mt.dll' |
|
|
|
SYS_INCLUDES = [ |
|
|
|
join(INST_PREFIX, 'include'), |
|
|
|
join(PROFILE_ROOT, 'pEp', 'include'), |
|
|
|
join(LOCAL_ROOT, 'pEp', 'include'), |
|
|
|
join(SYS_ROOT, 'pEp', 'include'), |
|
|
|
] |
|
|
|
SYS_SHARES = [ |
|
|
|
join(INST_PREFIX, 'share'), |
|
|
|
join(PROFILE_ROOT, 'pEp', 'share'), |
|
|
|
join(LOCAL_ROOT, 'pEp', 'share'), |
|
|
|
join(SYS_ROOT, 'pEp', 'share'), |
|
|
|
] |
|
|
|
SYS_LIB_PREFIXES = [ |
|
|
|
join(INST_PREFIX, 'bin'), |
|
|
|
join(PROFILE_ROOT, 'pEp', 'bin'), |
|
|
|
join(LOCAL_ROOT, 'pEp', 'bin'), |
|
|
|
join(SYS_ROOT, 'pEp', 'bin'), |
|
|
|
] |
|
|
|
pEpLog("verbose: ", self.verbose) |
|
|
|
pEpLog("local: ", self.local) |
|
|
|
pEpLog("prefix: ", self.prefix) |
|
|
|
pEpLog("sys.platform: ", sys.platform) |
|
|
|
|
|
|
|
global verboseLevel |
|
|
|
verboseLevel = self.verbose |
|
|
|
|
|
|
|
# get build information for platform |
|
|
|
if sys.platform == 'winnt': |
|
|
|
build_info = self.get_build_info_winnt() |
|
|
|
elif sys.platform == 'darwin': |
|
|
|
build_info = self.get_build_info_darwin() |
|
|
|
elif sys.platform == 'linux': |
|
|
|
build_info = self.get_build_info_linux() |
|
|
|
else: |
|
|
|
HOME = environ.get('PER_USER_DIRECTORY') or environ.get('HOME') |
|
|
|
PEPLIBNAME = 'pEpEngine.so' |
|
|
|
LIBPEPA = 'libpEpAdapter.a' |
|
|
|
BOOSTLIBNAME = 'boost_{boost_python:s}-mt.so' |
|
|
|
SYS_INCLUDES = ['/usr/local/pEp/include', '/usr/local/include', '/usr/include'] |
|
|
|
SYS_SHARES = ['/usr/local/pEp/share', '/usr/local/share', '/usr/share'] |
|
|
|
SYS_LIB_PREFIXES = ['/usr/local/pEp/bin', '/usr/local/bin', '/usr/bin'] |
|
|
|
|
|
|
|
use_local_incl = (self.local or os.path.isfile( |
|
|
|
join(HOME, 'include', 'pEp', 'pEpEngine.h')) ) |
|
|
|
use_local_lib = (self.local or os.path.isfile( |
|
|
|
join(HOME, 'lib', PEPLIBNAME)) ) |
|
|
|
|
|
|
|
INCLUDES = [ join(HOME, 'include') ] if use_local_incl else [] |
|
|
|
INCLUDES.extend(SYS_INCLUDES) |
|
|
|
SHARES = [ join(HOME, 'share') ] if use_local_incl else [] |
|
|
|
SHARES.extend(SYS_SHARES) |
|
|
|
LIBS = [ join(HOME, 'lib') ] if use_local_lib else [] |
|
|
|
LIBS.extend(SYS_LIB_PREFIXES) |
|
|
|
|
|
|
|
if not self.with_pEp_engine: |
|
|
|
ENGINE_INC = find( join('pEp', 'pEpEngine.h'), INCLUDES ) |
|
|
|
ENGINE_LIB = find( PEPLIBNAME, LIBS ) |
|
|
|
else: |
|
|
|
if exists( join(self.with_pEp_engine, 'include', 'pEp') ): |
|
|
|
ENGINE_INC = find( join('pEp', 'pEpEngine.h'), (join(self.with_pEp_engine, 'include'),) ) |
|
|
|
ENGINE_LIB = find( PEPLIBNAME, (join(self.with_pEp_engine, 'lib'),) ) |
|
|
|
else: |
|
|
|
ENGINE_INC = find( 'pEpEngine.h', (join(self.with_pEp_engine, 'src'),) ) |
|
|
|
ENGINE_LIB = find( PEPLIBNAME, (join(self.with_pEp_engine, 'src'),) ) |
|
|
|
|
|
|
|
if not self.with_pEp_libadapter: |
|
|
|
LIBPEPA_INC = find( join('pEp', 'Adapter.hh'), INCLUDES ) |
|
|
|
LIBPEPA_LIB = find( LIBPEPA, LIBS ) |
|
|
|
else: |
|
|
|
if exists( join(self.with_pEp_libadapter, 'include', 'pEp') ): |
|
|
|
LIBPEPA_INC = find( join('pEp', 'Adapter.hh'), (join(self.with_pEp_libadapter, 'include'),) ) |
|
|
|
LIBPEPA_LIB = find( LIBPEPA, (join(self.with_pEp_libadapter, 'lib'),) ) |
|
|
|
else: |
|
|
|
LIBPEPA_INC = find( 'Adapter.hh', (join(self.with_pEp_libadapter, 'src'),) ) |
|
|
|
LIBPEPA_LIB = find( LIBPEPA, (join(self.with_pEp_libadapter, 'src'),) ) |
|
|
|
|
|
|
|
if not self.with_boost: |
|
|
|
BOOST_INC = find( join('boost', 'system', 'config.hpp'), INCLUDES ) |
|
|
|
BOOST_LIB = None |
|
|
|
e_ = None |
|
|
|
for py in getPythonLibver(): |
|
|
|
f = BOOSTLIBNAME.format(boost_python=py) |
|
|
|
try: |
|
|
|
BOOST_LIB = find( f, LIBS ) |
|
|
|
break |
|
|
|
except Exception as e: |
|
|
|
if self.verbose: |
|
|
|
print("Not found: " + f) |
|
|
|
e_ = e if e_ is None else e_ |
|
|
|
if BOOST_LIB is None: |
|
|
|
raise e_ |
|
|
|
else: |
|
|
|
raise NotImplementedError("Building from Boost source not implemented yet") # FIXME |
|
|
|
# BOOST_INC = find( join('boost', 'system', 'config.hpp'), (self.with_boost,) ) |
|
|
|
# BOOST_LIB = find( BOOSTLIBNAME, (self.with_boost,) ) |
|
|
|
|
|
|
|
if not self.with_asn1c_share: |
|
|
|
ASN1C_INC = find( join('asn1c', 'asn_system.h'), SHARES ) |
|
|
|
else: |
|
|
|
ASN1C_INC = find( join('asn1c', 'asn_system.h'), (self.with_asn1c_share,) ) |
|
|
|
|
|
|
|
if self.verbose: |
|
|
|
print('ENGINE_INC=%s' % ENGINE_INC) |
|
|
|
print('ENGINE_LIB=%s' % ENGINE_LIB) |
|
|
|
print('LIBPEPA_INC=%s' % LIBPEPA_INC) |
|
|
|
print('LIBPEPA_LIB=%s' % LIBPEPA_LIB) |
|
|
|
print('BOOST_INC=%s' % BOOST_INC) |
|
|
|
print('BOOST_LIB=%s' % BOOST_LIB) |
|
|
|
print('ASN1C_INC=%s' % ASN1C_INC) |
|
|
|
pEpLog("Platform not supported:" + sys.platform) |
|
|
|
exit() |
|
|
|
|
|
|
|
(home, sys_includes, sys_libdirs, libs) = build_info |
|
|
|
|
|
|
|
# Build the Includes -I and Library paths -L |
|
|
|
# Start empty |
|
|
|
includes = [] |
|
|
|
libdirs = [] |
|
|
|
|
|
|
|
# Append home-dir |
|
|
|
if self.local: |
|
|
|
pEpLog("local mode") |
|
|
|
home_include=[ join(home, 'include') ] |
|
|
|
home_libdirs=[ join(home, 'lib') ] |
|
|
|
includes += home_include |
|
|
|
libdirs += home_libdirs |
|
|
|
|
|
|
|
# Append prefix-dir |
|
|
|
if self.prefix: |
|
|
|
pEpLog("using prefix=",self.prefix) |
|
|
|
prefix_include=[ join(self.prefix, 'include') ] |
|
|
|
prefix_libdirs=[ join(self.prefix, 'lib') ] |
|
|
|
includes += prefix_include |
|
|
|
libdirs += prefix_libdirs |
|
|
|
|
|
|
|
# Append default system dirs |
|
|
|
includes += sys_includes |
|
|
|
libdirs += sys_libdirs |
|
|
|
|
|
|
|
# Compile flags |
|
|
|
compile_flags = ['-std=c++14'] |
|
|
|
if self.debug: |
|
|
|
pEpLog("debug mode") |
|
|
|
compile_flags += ['-O0', '-g', '-UNDEBUG'] |
|
|
|
|
|
|
|
# Apply the build information |
|
|
|
global module_pEp |
|
|
|
extend_once( module_pEp.include_dirs, [ENGINE_INC, LIBPEPA_INC, BOOST_INC, ASN1C_INC] ) |
|
|
|
extend_once( module_pEp.library_dirs, [ENGINE_LIB, LIBPEPA_LIB, BOOST_LIB] ) |
|
|
|
extend_once( module_pEp.libraries, ['pEpEngine', 'boost_python37-mt', 'boost_locale-mt'] ) |
|
|
|
module_pEp.include_dirs = includes |
|
|
|
module_pEp.library_dirs = libdirs |
|
|
|
module_pEp.libraries = libs |
|
|
|
module_pEp.extra_compile_args = compile_flags |
|
|
|
|
|
|
|
if self.debug: |
|
|
|
module_pEp.extra_compile_args = ['-O0', '-g', '-UNDEBUG', '-std=c++14'] |
|
|
|
else: |
|
|
|
module_pEp.extra_compile_args = ['-std=c++14'] # FIXME |
|
|
|
pEpLog("Include Dirs:", module_pEp.include_dirs) |
|
|
|
pEpLog("Libs Dirs:", module_pEp.library_dirs) |
|
|
|
pEpLog("Libraries:", module_pEp.libraries) |
|
|
|
pEpLog("Compile flags:", module_pEp.extra_compile_args) |
|
|
|
|
|
|
|
def run(self): |
|
|
|
build_ext.run(self) |
|
|
|
|
|
|
|
|
|
|
|
# module_pEp global is referenced in BuildExtCommand |
|
|
|
module_pEp = Extension('pEp', |
|
|
|
sources = glob('src/*.cc'), |
|
|
|
libraries = ['pEpEngine'], |
|
|
|
# extra_compile_args = compile_args, |
|
|
|
# include_dirs = [ENGINE_INC, BOOST_INC, ASN1C_INC], |
|
|
|
# library_dirs = [ENGINE_LIB, BOOST_LIB], |
|
|
|
) |
|
|
|
if sys.platform == 'winnt': |
|
|
|
if sys.version_info[0] >= 3: |
|
|
|
import winreg |
|
|
|
else: |
|
|
|
import _winreg as winreg |
|
|
|
|
|
|
|
if sys.version_info[0] < 3: |
|
|
|
FileNotFoundError = EnvironmentError |
|
|
|
|
|
|
|
|
|
|
|
module_pEp = Extension( |
|
|
|
'pEp', |
|
|
|
sources = glob('src/*.cc'), |
|
|
|
) |
|
|
|
|
|
|
|
# "MAIN" Function |
|
|
|
setup( |
|
|
|
name='pEp', |
|
|
|
version='2.0', |
|
|
|
description='p≡p for Python', |
|
|
|
author="Volker Birk", |
|
|
|
author_email="vb@pep-project.org", |
|
|
|
ext_modules=[module_pEp,], |
|
|
|
maintainer="Heck", |
|
|
|
maintainer_email="heck@pep.foundation", |
|
|
|
ext_modules=[module_pEp], |
|
|
|
cmdclass={ |
|
|
|
'build_ext': BuildExtCommand, |
|
|
|
}, |
|
|
|