On this page
Python 初始化配置
3.8 版的新Function。
Structures:
Functions:
预先配置(PyPreConfig
类型)存储在_PyRuntime.preconfig
中,而配置(PyConfig
类型)存储在PyInterpreterState.config
中。
另请参见初始化,完成和线程。
See also
PEP 587“ Python 初始化配置”。
PyWideStringList
PyWideStringList
wchar_t*
个字符串的列表。
如果* length 不为零,则 items *必须为非NULL
,并且所有字符串都必须为非NULL
。
Methods:
- PyStatus
PyWideStringList_Append
(PyWideStringList *list ,const wchar_t item *)- 将* item 附加到 list *。
必须预先初始化 Python 才能调用此函数。
- PyStatus
PyWideStringList_Insert
(PyWideStringList **list ,Py_ssize_t * index ,const wchar_t item *)- 将* item 插入 index 的 list *中。
如果* index 大于或等于 list 长度,则将 item 附加到 list *。
- index *必须大于或等于 0.
必须预先初始化 Python 才能调用此函数。
Structure fields:
Py_ssize_t
length
- List length.
wchar_t **
items
- List items.
PyStatus
PyStatus
- 用于存储初始化Function状态的结构:成功,错误或退出。
对于错误,它可以存储创建错误的 C 函数名称。
Structure fields:
int
exitcode
- 退出代码。参数传递给
exit()
。
- 退出代码。参数传递给
const char *
err_msg
- Error message.
const char *
func
- 产生错误的函数的名称可以为
NULL
。
- 产生错误的函数的名称可以为
创建状态的Function:
PyStatus
PyStatus_Ok
(无效)- Success.
PyStatus
PyStatus_Error
(const char ** err_msg *)- 带有消息的初始化错误。
PyStatus
PyStatus_NoMemory
(无效)- 内存分配失败(内存不足)。
PyStatus
PyStatus_Exit
(int 退出代码)- 使用指定的退出代码退出 Python。
处理状态的Function:
int
PyStatus_Exception
(PyStatus 状态)- 状态是错误还是退出?如果为 true,则必须处理异常;否则为 false。例如致电Py_ExitStatusException()。
int
PyStatus_IsError
(PyStatus 状态)- 结果是错误的吗?
int
PyStatus_IsExit
(PyStatus 状态)- 结果是否退出?
无效
Py_ExitStatusException
(PyStatus 状态)- 如果* status 是 Export,请致电
exit(exitcode)
。打印错误消息,如果 status *是错误,则使用非零退出代码退出。仅当PyStatus_Exception(status)
不为零时才必须调用。
- 如果* status 是 Export,请致电
Note
在内部,Python 使用设置PyStatus.func
的宏,而使用函数将状态func
设置为NULL
。
Example:
PyStatus alloc(void **ptr, size_t size)
{
*ptr = PyMem_RawMalloc(size);
if (*ptr == NULL) {
return PyStatus_NoMemory();
}
return PyStatus_Ok();
}
int main(int argc, char **argv)
{
void *ptr;
PyStatus status = alloc(&ptr, 16);
if (PyStatus_Exception(status)) {
Py_ExitStatusException(status);
}
PyMem_Free(ptr);
return 0;
}
PyPreConfig
PyPreConfig
- 用于预初始化 Python 的结构:
设置 Python 内存分配器
配置 LC_CTYPE 语言环境
设置 UTF-8 模式
初始化预配置的Function:
无效
PyPreConfig_InitPythonConfig
(PyPreConfig ** preconfig *)- 使用Python Configuration初始化预配置。
无效
PyPreConfig_InitIsolatedConfig
(PyPreConfig ** preconfig *)- 使用Isolated Configuration初始化预配置。
Structure fields:
int
allocator
- 内存分配器的名称:
PYMEM_ALLOCATOR_NOT_SET
(0
):不要更改内存分配器(使用默认值)PYMEM_ALLOCATOR_DEFAULT
(1
):默认内存分配器PYMEM_ALLOCATOR_DEBUG
(2
):具有调试钩子的默认内存分配器PYMEM_ALLOCATOR_MALLOC
(3
):强制使用malloc()
PYMEM_ALLOCATOR_MALLOC_DEBUG
(4
):pass调试钩子强制使用malloc()
PYMEM_ALLOCATOR_PYMALLOC
(5
): Python Pymalloc 内存分配器PYMEM_ALLOCATOR_PYMALLOC_DEBUG
(6
):Python Pymalloc 内存分配器带有调试钩子
如果使用--without-pymalloc
配置了 Python,则不支持PYMEM_ALLOCATOR_PYMALLOC
和PYMEM_ALLOCATOR_PYMALLOC_DEBUG
See Memory Management.
int
configure_locale
- 将 LC_CTYPE 语言环境设置为用户首选语言环境?如果等于 0,则将
coerce_c_locale
和coerce_c_locale_warn
设置为 0.
- 将 LC_CTYPE 语言环境设置为用户首选语言环境?如果等于 0,则将
int
coerce_c_locale
- 如果等于 2,则强制 C 语言环境;否则为 0.如果等于 1,则读取 LC_CTYPE 语言环境以决定是否应强制使用该语言环境。
int
coerce_c_locale_warn
- 如果非零,则在强制 C 语言环境的情况下发出警告。
int
dev_mode
- See PyConfig.dev_mode.
int
isolated
- See PyConfig.isolated.
int
legacy_windows_fs_encoding
(仅适用于 Windows *)- 如果非零,请禁用 UTF-8 模式,将 Python 文件系统编码设置为
mbcs
,将文件系统错误处理程序设置为replace
。
- 如果非零,请禁用 UTF-8 模式,将 Python 文件系统编码设置为
仅在 Windows 上可用。 #ifdef MS_WINDOWS
宏可用于 Windows 特定代码。
int
parse_argv
- 如果非零,则Py_PreInitializeFromArgs()和Py_PreInitializeFromBytesArgs()解析其
argv
参数的方式与常规 Python 解析命令行参数的方式相同:请参见命令行参数。
- 如果非零,则Py_PreInitializeFromArgs()和Py_PreInitializeFromBytesArgs()解析其
int
use_environment
int
utf8_mode
- 如果非零,请启用 UTF-8 模式。
使用 PyPreConfig 进行预初始化
用于预初始化 Python 的函数:
PyStatus
Py_PreInitialize
(const PyPreConfig ** preconfig *)- 从* preconfig *预配置中预初始化 Python。
PyStatus
Py_PreInitializeFromBytesArgs
(const PyPreConfig **preconfig ,int * argc ,char * const argv *)- 从* preconfig *预配置和命令行参数(字节字符串)预初始化 Python。
PyStatus
Py_PreInitializeFromArgs
(const PyPreConfig ** preconfig *,int * argc *,wchar_t * const * * argv *)- 从* preconfig *预配置和命令行参数(宽字符串)预初始化 Python。
调用方负责使用PyStatus_Exception()和Py_ExitStatusException()处理异常(错误或退出)。
对于Python Configuration(PyPreConfig_InitPythonConfig()),如果 Python 是使用命令行参数初始化的,则也必须传递命令行参数以对 Python 进行预初始化,因为它们会影响诸如编码之类的预配置。例如,-X utf8命令行选项启用 UTF-8 模式。
可以在Py_PreInitialize()之后和Py_InitializeFromConfig()之前调用PyMem_SetAllocator()
以安装自定义内存分配器。如果PyPreConfig.allocator设置为PYMEM_ALLOCATOR_NOT_SET
,则可以在Py_PreInitialize()之前调用它。
请勿在 Python 预初始化之前使用PyMem_RawMalloc()之类的 Python 内存分配函数,而直接调用malloc()
和free()
始终是安全的。不得在预初始化之前调用Py_DecodeLocale()。
使用预初始化启用 UTF-8 模式的示例:
PyStatus status;
PyPreConfig preconfig;
PyPreConfig_InitPythonConfig(&preconfig);
preconfig.utf8_mode = 1;
status = Py_PreInitialize(&preconfig);
if (PyStatus_Exception(status)) {
Py_ExitStatusException(status);
}
/* at this point, Python will speak UTF-8 */
Py_Initialize();
/* ... use Python API here ... */
Py_Finalize();
PyConfig
PyConfig
- 包含用于配置 Python 的大多数参数的结构。
Structure methods:
无效
PyConfig_InitPythonConfig
(PyConfig ** config *)- 使用Python Configuration初始化配置。
无效
PyConfig_InitIsolatedConfig
(PyConfig ** config *)- 使用Isolated Configuration初始化配置。
PyStatus
PyConfig_SetString
(PyConfig *config ,wchar_t * const config_str *,const wchar_t ** str *)- 将宽字符串* str *复制到
*config_str
。
- 将宽字符串* str *复制到
如果需要,请预先初始化 Python。
- PyStatus
PyConfig_SetBytesString
(PyConfig *config ,wchar_t * const config_str *,const char ** str *)- 使用
Py_DecodeLocale()
解码* str *并将结果设置为*config_str
。
- 使用
如果需要,请预先初始化 Python。
如果需要,请预先初始化 Python。
- PyStatus
PyConfig_SetBytesArgv
(PyConfig **config ,int * argc ,char * const argv *)- 设置命令行参数:使用Py_DecodeLocale()解码字节。
如果需要,请预先初始化 Python。
- PyStatus
PyConfig_SetWideStringList
(PyConfig *config ,PyWideStringList list *,Py_ssize_t * length *,wchar_t *** items *)- 将宽字符串列表* list 设置为 length 和 items *。
如果需要,请预先初始化 Python。
已经初始化的字段保持不变。
如果需要,请预先初始化 Python。
- 无效
PyConfig_Clear
(PyConfig ** config *)- 释放配置内存。
如果需要,大多数PyConfig
方法会预先初始化 Python。在这种情况下,Python 的预初始化配置基于PyConfig。如果调整了与PyPreConfig相同的配置字段,则必须在调用PyConfig方法之前设置它们:
此外,如果使用PyConfig_SetArgv()或PyConfig_SetBytesArgv(),则必须先调用此方法,然后再调用其他方法,因为预初始化配置取决于命令行参数(如果parse_argv
为非零)。
这些方法的调用者负责使用PyStatus_Exception()
和Py_ExitStatusException()
处理异常(错误或退出)。
Structure fields:
PyWideStringList
argv
- 命令行参数sys.argv。参见parse_argv来解析argv,就像常规 Python 解析 Python 命令行参数一样。如果argv为空,则添加一个空字符串以确保sys.argv始终存在且永不为空。
wchar_t *
base_exec_prefix
wchar_t *
base_executable
sys._base_executable
:__PYVENV_LAUNCHER__
环境变量值,或PyConfig.executable的副本。
wchar_t *
base_prefix
int
buffered_stdio
- 如果等于 0,则启用非缓冲模式,使 stdout 和 stderr 流变为非缓冲状态。
stdin 始终以缓冲模式打开。
int
bytes_warning
wchar_t *
check_hash_pycs_mode
- 控制基于散列的
.pyc
文件的验证行为(请参见 PEP 552):--check-hash-based-pycs命令行选项值。
- 控制基于散列的
有效值:always
,never
和default
。
默认值为:default
。
int
configure_c_stdio
- 如果非零,请配置 C 个标准流(
stdio
,stdout
,stdout
)。例如,在 Windows 上将其模式设置为O_BINARY
。
- 如果非零,请配置 C 个标准流(
int
dev_mode
- 开发模式:请参见-X dev。
int
dump_refs
- 如果非零,则转储所有在退出时仍然有效的对象。
需要 Python 的调试版本(必须定义Py_REF_DEBUG
宏)。
wchar_t *
exec_prefix
wchar_t *
executable
int
faulthandler
- 如果非零,请在启动时致电faulthandler.enable()。
wchar_t *
filesystem_encoding
- 文件系统编码sys.getfilesystemencoding()。
wchar_t *
filesystem_errors
- 文件系统编码错误sys.getfilesystemencodeerrors()。
未签名的长
hash_seed
int
use_hash_seed
- 随机哈希函数种子。
如果use_hash_seed为零,则在 Pythonstartup 上随机选择一个种子,而hash_seed被忽略。
- wchar_t *
home
- Python 主目录。
默认情况下从 PYTHONHOME环境变量值初始化。
int
import_time
- 如果不为零,则配置文件导入时间。
int
inspect
- 执行脚本或命令后进入交互模式。
int
install_signal_handlers
- 安装 signal 处理程序?
int
interactive
- Interactive mode.
int
isolated
- 如果大于 0,则启用隔离模式:
sys.path既不包含脚本的目录(从
argv[0]
或当前目录计算得出),也不包含用户的 site-packages 目录。Python REPL 不会导入readline,也不会在交互式提示上启用默认的 readline 配置。
int
legacy_windows_stdio
- 如果非零,则对sys.stdin,sys.stdout和sys.stderr使用io.FileIO而不是
io.WindowsConsoleIO
。
- 如果非零,则对sys.stdin,sys.stdout和sys.stderr使用io.FileIO而不是
仅在 Windows 上可用。 #ifdef MS_WINDOWS
宏可用于 Windows 特定代码。
- int
malloc_stats
- 如果非零,则在 Export 处将统计信息转储到Python Pymalloc 内存分配器上。
如果 Python 是使用--without-pymalloc
构建的,则忽略该选项。
- wchar_t *
pythonpath_env
- 模块搜索路径以用
DELIM
(os.path.pathsep
)分隔的字符串表示。
- 模块搜索路径以用
默认情况下从 PYTHONPATH环境变量值初始化。
PyWideStringList
module_search_paths
int
module_search_paths_set
- sys.path。如果module_search_paths_set等于 0,则module_search_paths被计算Path Configuration的函数覆盖。
int
optimization_level
- 编译优化级别:
0:窥孔优化器(并且
__debug__
设置为True
)1:删除 assert,将
__debug__
设置为False
2:删除文档字符串
int
parse_argv
int
parser_debug
- 如果非零,请打开解析器调试输出(仅针对 maven,取决于编译选项)。
int
pathconfig_warnings
- 如果等于 0,则在计算Path Configuration时禁止显示警告(仅限 Unix,Windows 不记录任何警告)。否则,警告将写入
stderr
。
- 如果等于 0,则在计算Path Configuration时禁止显示警告(仅限 Unix,Windows 不记录任何警告)。否则,警告将写入
wchar_t *
prefix
wchar_t *
program_name
- 程序名称。用于初始化executable,并用于早期错误消息。
wchar_t *
pycache_prefix
- sys.pycache_prefix:
.pyc
缓存前缀。
- sys.pycache_prefix:
如果NULL
,则sys.pycache_prefix设置为None
。
int
quiet
- 静音模式。例如,不要以交互方式显示版权和版本消息。
wchar_t *
run_command
python3 -c COMMAND
参数。由Py_RunMain()使用。
wchar_t *
run_filename
python3 FILENAME
参数。由Py_RunMain()使用。
wchar_t *
run_module
python3 -m MODULE
参数。由Py_RunMain()使用。
int
show_alloc_count
- 在 Export 处显示分配计数?
pass-X showalloccount命令行选项设置为 1.
需要定义COUNT_ALLOCS
宏的特殊 Python 构建。
- int
show_ref_count
- 显示退出时的总参考计数?
pass-X showrefcount命令行选项设置为 1.
需要 Python 的调试版本(必须定义Py_REF_DEBUG
宏)。
int
site_import
- 在启动时要导入site模块吗?
int
skip_source_first_line
- 跳过源代码的第一行?
wchar_t *
stdio_encoding
wchar_t *
stdio_errors
- sys.stdin,sys.stdout和sys.stderr的编码和编码错误。
int
tracemalloc
- 如果非零,请在启动时致电tracemalloc.start()。
int
use_environment
- 如果大于 0,请使用environment variables。
int
user_site_directory
- 如果非零,则将用户站点目录添加到sys.path。
int
verbose
- 如果非零,请启用详细模式。
PyWideStringList
warnoptions
- sys.warnoptions:warnings模块中用于构建警告过滤器的选项:最低到最高优先级。
warnings模块以相反的 Sequences 添加sys.warnoptions:最后的PyConfig.warnoptions项成为warnings.filters
的第一个项,第一个被检查(最高优先级)。
- int
write_bytecode
- 如果非零,则写入
.pyc
个文件。
- 如果非零,则写入
sys.dont_write_bytecode初始化为write_bytecode的取反值。
- PyWideStringList
xoptions
如果parse_argv
为非零值,则以与常规 Python 解析命令行参数相同的方式解析argv
参数,并从argv
中剥离 Python 参数:参见命令行参数。
可以解析xoptions
选项以设置其他选项:请参见-X选项。
使用 PyConfig 初始化
初始化 Python 的函数:
调用方负责使用PyStatus_Exception()和Py_ExitStatusException()处理异常(错误或退出)。
如果使用PyImport_FrozenModules
,PyImport_AppendInittab()
或PyImport_ExtendInittab()
,则必须在 Python 预初始化之后和 Python 初始化之前设置或调用它们。
设置程序名称的示例:
void init_python(void)
{
PyStatus status;
PyConfig config;
PyConfig_InitPythonConfig(&config);
/* Set the program name. Implicitly preinitialize Python. */
status = PyConfig_SetString(&config, &config.program_name,
L"/path/to/my_program");
if (PyStatus_Exception(status)) {
goto fail;
}
status = Py_InitializeFromConfig(&config);
if (PyStatus_Exception(status)) {
goto fail;
}
PyConfig_Clear(&config);
return;
fail:
PyConfig_Clear(&config);
Py_ExitStatusException(status);
}
更完整的示例,修改默认配置,读取配置,然后覆盖一些参数:
PyStatus init_python(const char *program_name)
{
PyStatus status;
PyConfig config;
PyConfig_InitPythonConfig(&config);
/* Set the program name before reading the configuration
(decode byte string from the locale encoding).
Implicitly preinitialize Python. */
status = PyConfig_SetBytesString(&config, &config.program_name,
program_name);
if (PyStatus_Exception(status)) {
goto done;
}
/* Read all configuration at once */
status = PyConfig_Read(&config);
if (PyStatus_Exception(status)) {
goto done;
}
/* Append our custom search path to sys.path */
status = PyWideStringList_Append(&config.module_search_paths,
L"/path/to/more/modules");
if (PyStatus_Exception(status)) {
goto done;
}
/* Override executable computed by PyConfig_Read() */
status = PyConfig_SetString(&config, &config.executable,
L"/path/to/my_executable");
if (PyStatus_Exception(status)) {
goto done;
}
status = Py_InitializeFromConfig(&config);
done:
PyConfig_Clear(&config);
return status;
}
Isolated Configuration
PyPreConfig_InitIsolatedConfig()和PyConfig_InitIsolatedConfig()函数创建一个配置以将 Python 与系统隔离。例如,将 Python 嵌入到应用程序中。
此配置将忽略全局配置变量,环境变量,命令行参数(未解析PyConfig.argv)和用户站点目录。 C 标准流(例如:stdout
)和 LC_CTYPE 语言环境保持不变。未安装 signal 处理程序。
配置文件仍与此配置一起使用。设置Path Configuration(“输出字段”)以忽略这些配置文件,并避免函数计算默认路径配置。
Python Configuration
PyPreConfig_InitPythonConfig()和PyConfig_InitPythonConfig()函数创建配置以构建自定义的 Python,其行为与常规 Python 相同。
环境变量和命令行参数用于配置 Python,而全局配置变量则被忽略。
此Function根据 LC_CTYPE 语言环境, PYTHONUTF8和 PYTHONCOERCECLOCALE环境变量启用 C 语言环境强制( PEP 538)和 UTF-8 模式( PEP 540)。
始终以隔离模式运行的定制 Python 的示例:
int main(int argc, char **argv)
{
PyStatus status;
PyConfig config;
PyConfig_InitPythonConfig(&config);
config.isolated = 1;
/* Decode command line arguments.
Implicitly preinitialize Python (in isolated mode). */
status = PyConfig_SetBytesArgv(&config, argc, argv);
if (PyStatus_Exception(status)) {
goto fail;
}
status = Py_InitializeFromConfig(&config);
if (PyStatus_Exception(status)) {
goto fail;
}
PyConfig_Clear(&config);
return Py_RunMain();
fail:
PyConfig_Clear(&config);
if (PyStatus_IsExit(status)) {
return status.exitcode;
}
/* Display the error message and exit the process with
non-zero exit code */
Py_ExitStatusException(status);
}
Path Configuration
PyConfig包含用于路径配置的多个字段:
路径配置 Importing:
-
当前工作目录:获取绝对路径
PATH
环境变量以获取程序的完整路径(来自PyConfig.program_name)__PYVENV_LAUNCHER__
环境变量(仅限 Windows)注册表中 HKEY_CURRENT_USER 和 HKEY_LOCAL_MACHINE(其中 X.Y 是 Python 版本)的“ SoftwarePythonPythonCoreCore.YPythonPath”下的应用程序路径。
路径配置输出字段:
如果未设置至少一个“输出字段”,Python 将计算路径配置以填充未设置的字段。如果module_search_paths_set等于 0,则module_search_paths被覆盖并且module_search_paths_set设置为 1.
pass显式设置上面列出的所有路径配置输出字段,可以完全忽略计算默认路径配置的Function。即使字符串不是空的,它也被视为已设置。如果将module_search_paths_set
设置为 1,则将module_search_paths
视为已设置。在这种情况下,路径配置 Importing 字段也将被忽略。
将pathconfig_warnings设置为 0 可在计算路径配置时禁止显示警告(仅 Unix,Windows 不记录任何警告)。
如果未设置base_prefix或base_exec_prefix字段,则它们分别从prefix和exec_prefix继承其值。
Py_RunMain()和Py_Main()修改sys.path:
如果设置了run_filename并且是包含
__main__.py
脚本的目录,则将run_filename放在sys.path之前。如果isolated为零:
如果设置了run_module,则将当前目录放在sys.path之前。如果无法读取当前目录,则不执行任何操作。
如果设置了run_filename,则将文件名的目录放在sys.path之前。
否则,在sys.path之前添加一个空字符串。
如果site_import非零,则site模块可以修改sys.path。如果user_site_directory非零并且用户的站点包目录存在,则site模块将用户的站点包目录追加到sys.path。
路径配置使用以下配置文件:
pyvenv.cfg
python._pth
(仅 Windows)pybuilddir.txt
(仅适用于 Unix)
__PYVENV_LAUNCHER__
环境变量用于设置PyConfig.base_executable
Py_RunMain()
- int
Py_RunMain
(void)- 执行在命令行或配置中指定的命令(PyConfig.run_command),脚本(PyConfig.run_filename)或模块(PyConfig.run_module)。
默认情况下,并且如果使用-i选项,请运行 REPL。
最后,完成 Python 处理并返回退出状态,该状态可以传递给exit()
函数。
有关始终使用Py_RunMain()在隔离模式下运行的定制 Python 的示例,请参见Python Configuration。
多阶段初始化专用临时 API
本部分是私有的临时 API,介绍了多阶段初始化,这是 PEP 432的核心Function:
“核心”初始化阶段,“裸机最低 Python”:
Builtin types;
在“主”初始化阶段,Python 已完全初始化:
安装并配置importlib;
安装 signal 处理程序;
完成sys模块初始化(例如:创建sys.stdout和sys.path);
启用可选Function,例如faulthandler和tracemalloc;
导入site模块;
etc.
私有临时 API:
PyConfig._init_main
:如果设置为 0,则Py_InitializeFromConfig()停止在“ Core”初始化阶段。PyStatus
_Py_InitializeMain
(无效)- 转到“主要”初始化阶段,完成 Python 初始化。
在“核心”阶段未导入任何模块,并且未配置importlib
模块:Path Configuration仅在“主”阶段适用。它可能允许在 Python 中自定义 Python 以覆盖或调整Path Configuration,可能安装自定义sys.meta_path导入程序或导入钩子等。
在 Core 阶段之后和 Main 阶段之前,可以计算 Python 中的Path Configuration,这是 PEP 432动机之一。
“核心”阶段定义不正确:在此阶段应该指定什么和不应该指定什么。该 API 被标记为私有和临时的:可以在设计适当的公共 API 之前随时修改甚至删除该 API。
在“ Core”和“ Main”初始化阶段之间运行 Python 代码的示例:
void init_python(void)
{
PyStatus status;
PyConfig config;
PyConfig_InitPythonConfig(&config);
config._init_main = 0;
/* ... customize 'config' configuration ... */
status = Py_InitializeFromConfig(&config);
PyConfig_Clear(&config);
if (PyStatus_Exception(status)) {
Py_ExitStatusException(status);
}
/* Use sys.stderr because sys.stdout is only created
by _Py_InitializeMain() */
int res = PyRun_SimpleString(
"import sys; "
"print('Run Python code before _Py_InitializeMain', "
"file=sys.stderr)");
if (res < 0) {
exit(1);
}
/* ... put more configuration code here ... */
status = _Py_InitializeMain();
if (PyStatus_Exception(status)) {
Py_ExitStatusException(status);
}
}