manisandro/gImageReader

Segfault on Alpine (OpenCL, Tesseract issue?)

Closed this issue · 3 comments

I've compiled gImageReader on Alpine Linux, but it segfaults on startup. I am not sure if this an issue with gImagereader or the opencl and tesseract packages on Alpine, but maybe you can give me a hint on who to bug about this :D

Console output:

[DS] Profile file not available (tesseract_opencl_profile_devices.dat); performing profiling.

[DS] Device: "�`S4T" (OpenCL) evaluation...
OpenCL error code is -33 at when populateGPUEnv::getDeviceInfo(TYPE) .
OpenCL error code is -33 at when populateGPUEnv::getDeviceInfo(PLATFORM) .
OpenCL error code is -33 at when populateGPUEnv::createContext .
OpenCL error code is -34 at when populateGPUEnv::createCommandQueue .
OpenCL error code is -33 at when clGetDeviceInfo .
OpenCL error code is -34 at when clCreateProgramWithSource .
OpenCL error code is -44 at when clCreateKernel composeRGBPixel .
OpenCL error code is -48 at when clSetKernelArg .
OpenCL error code is -48 at when clSetKernelArg .
OpenCL error code is -48 at when clSetKernelArg .
OpenCL error code is -48 at when clSetKernelArg .
OpenCL error code is -48 at when clSetKernelArg .
OpenCL error code is -36 at when clEnqueueNDRangeKernel .
OpenCL error code is -36 at when clEnqueueMapBuffer outputCl .
OpenCL error code is -34 at when clCreateBuffer imageBuffer .
OpenCL error code is -33 at when clCreateBuffer imageBuffer .
OpenCL error code is -34 at when clCreateBuffer histogramBuffer .
OpenCL error code is -34 at when clCreateBuffer tmpHistogramBuffer .
OpenCL error code is -34 at when clCreateBuffer atomicSyncBuffer .
OpenCL error code is -44 at when clCreateKernel kernel_HistogramRectAllChannels .
OpenCL error code is -44 at when clCreateKernel kernel_HistogramRectAllChannelsReduction .
OpenCL error code is -36 at when clEnqueueMapBuffer tmpHistogramBuffer .

First I thought this is an issue with opencl showing no devices, but clinfo on my gentoo notebook shows also 0 devices, with gIamgeReader functioning without issue.

I've compiled with debug symbols and this is the racetrack:

#0 __cp_end () at src/thread/x86_64/syscall_cp.s:29
#1 0x00007f54371f85fc in __syscall_cp_c (nr=271, u=,
#2 0x00007f54371ea503 in ppoll (fds=, n=,
#3 0x00007f5435b0db79 in qt_safe_poll(pollfd*, unsigned long, timespec const*)
#4 0x00007f5435a89d50 in ?? () from /usr/lib/libQt5Core.so.5
#5 0x00007f5435a8a87e in ?? () from /usr/lib/libQt5Core.so.5
#6 0x00005616ff98da90 in MainWindow::signalHandlerExec (signal=11,
#7 0x00005616ff98d5c4 in MainWindow::signalHandler (signal=11)
#8
#9 0x00007f54370cb59b in tesseract::OpenclDevice::HistogramRectOCL(void*, int, int, int, int, int, int, int, int*) () from /usr/lib/libtesseract.so.5
#10 0x00007f54370ccb68 in ?? () from /usr/lib/libtesseract.so.5
#11 0x00007f54370cdc75 in tesseract::OpenclDevice::getDeviceSelection() ()
#12 0x00007f54370ce299 in tesseract::OpenclDevice::InitOpenclRunEnv_DeviceSelection(int) () from /usr/lib/libtesseract.so.5
#13 0x00007f54370ce2fb in tesseract::OpenclDevice::InitEnv() ()
#14 0x00007f5436f83de0 in tesseract::TessBaseAPI::Init(char const*, int, char const*, tesseract::OcrEngineMode, char**, int, std::vector<std::__cxx11::basic_string<char, std::char_traits, std::allocator >, std::allocator<std::__cxx11::basic_string<char, std::char_traits, std::allocator > > > const*, std::vector<std::__cxx11::basic_string<char, std::char_traits, std::allocator >, std::allocator<std::__cxx11::basic_string<char, std::char_traits, std::allocator > > > const*, bool, bool ()(char const, std::vector<char, std::allocator >)) () from /usr/lib/libtesseract.so.5
#15 0x00007f5436f84023 in tesseract::TessBaseAPI::Init(char const
, char const*, tesseract::OcrEngineMode, char**, int, std::vector<std::__cxx11::basic_string<char, std::char_traits, std::allocator >, std::allocator<std::__cxx11::basic_string<char, std::char_traits, std::allocator > > > const*, std::vector<std::__cxx11::basic_string<char, std::char_traits, std::allocator >, std::allocator<std::_cxx11::basic_string<char, std::char_traits, std::allocator > > > const*, bool) ()
#16 0x00005616ff958371 in tesseract::TessBaseAPI::Init (this=0x7ffd66bf3840,
#17 0x00005616ff94fd9b in Config::tessdataLocation (
#18 0x00005616ff94f38e in Config::setDataLocations (this=0x7f542f402660, idx=0)
#19 0x00005616ff963bfb in QtPrivate::FunctorCall<QtPrivate::IndexesList<0>, QtPrivate::List, void, void (Config::)(int)>::call (
#20 0x00005616ff962fb6 in QtPrivate::FunctionPointer<void (Config::
)(int)>::call<QtPrivate::List, void> (
#21 0x00005616ff96264b in QtPrivate::QSlotObject<void (Config::*)(int), QtPrivate::List, void>::impl (which=1, this
=0x7f542f29b2d0, r=0x7f542f402660,
#22 0x00007f5435afae1c in ?? () from /usr/lib/libQt5Core.so.5
#23 0x00007f54363f3732 in QComboBox::currentIndexChanged(int) ()
#24 0x00007f54363f470c in ?? () from /usr/lib/libQt5Widgets.so.5
#25 0x00007f54363f703a in ?? () from /usr/lib/libQt5Widgets.so.5
#26 0x00007f54363f724e in QComboBox::setCurrentIndex(int) ()
#27 0x00005616ff949a44 in ComboSetting::ComboSetting (this=0x7f542f682cf0,
#28 0x00005616ff94dd9a in Config::Config (this=0x7f542f402660,
#29 0x00005616ff98e6e3 in MainWindow::MainWindow (this=0x7f54306e7310,
#30 0x00005616ffa59ec5 in main (argc=1, argv=0x7ffd66bf42d8)

Thread 8 (LWP 6085 "Thread (pooled)"):
#0 __cp_end () at src/thread/x86_64/syscall_cp.s:29
#1 0x00007f54371f85fc in __syscall_cp_c (nr=202, u=, v=, w=, x=, y=, z=0) at src/thread/pthread_cancel.c:33
#2 0x00007f54371f7b2e in __futex4_cp (to=, val=2, op=128, addr=0x7f542f7fd744) at src/thread/__timedwait.c:24
#3 __timedwait_cp (addr=addr@entry=0x7f542f7fd744, val=val@entry=2, clk=clk@entry=1, at=at@entry=0x7f542f7fd798, priv=128, priv@entry=1) at src/thread/__timedwait.c:52
#4 0x00007f54371f8994 in __pthread_cond_timedwait (c=0x7f542fc505b8, m=0x7f542fc50590, ts=0x7f542f7fd798) at src/thread/pthread_cond_timedwait.c:100
#5 0x00007f54359a1991 in ?? () from /usr/lib/libQt5Core.so.5
#6 0x00007f54359a16e7 in QWaitCondition::wait(QMutex*, QDeadlineTimer) () from /usr/lib/libQt5Core.so.5
#7 0x00007f543599f96a in ?? () from /usr/lib/libQt5Core.so.5
#8 0x00007f543599c9db in ?? () from /usr/lib/libQt5Core.so.5
#9 0x00007f54371f932e in start (p=0x7f542f7fd930) at src/thread/pthread_create.c:207
#10 0x00007f54371fb944 in __clone () at src/thread/x86_64/clone.s:22

Thread 7 (LWP 6084 "Thread (pooled)"):
#0 __cp_end () at src/thread/x86_64/syscall_cp.s:29
#1 0x00007f54371f85fc in __syscall_cp_c (nr=202, u=, v=, w=, x=, y=, z=0) at src/thread/pthread_cancel.c:33
#2 0x00007f54371f7b2e in __futex4_cp (to=, val=2, op=128, addr=0x7f542f820744) at src/thread/__timedwait.c:24
#3 __timedwait_cp (addr=addr@entry=0x7f542f820744, val=val@entry=2, clk=clk@entry=1, at=at@entry=0x7f542f820798, priv=128, priv@entry=1) at src/thread/__timedwait.c:52
#4 0x00007f54371f8994 in __pthread_cond_timedwait (c=0x7f542fc50238, m=0x7f542fc50210, ts=0x7f542f820798) at src/thread/pthread_cond_timedwait.c:100
#5 0x00007f54359a1991 in ?? () from /usr/lib/libQt5Core.so.5
#6 0x00007f54359a16e7 in QWaitCondition::wait(QMutex*, QDeadlineTimer) () from /usr/lib/libQt5Core.so.5
#7 0x00007f543599f96a in ?? () from /usr/lib/libQt5Core.so.5
#8 0x00007f543599c9db in ?? () from /usr/lib/libQt5Core.so.5
#9 0x00007f54371f932e in start (p=0x7f542f820930) at src/thread/pthread_create.c:207
#10 0x00007f54371fb944 in __clone () at src/thread/x86_64/clone.s:22

Thread 6 (LWP 6083 "Thread (pooled)"):
#0 __cp_end () at src/thread/x86_64/syscall_cp.s:29
#1 0x00007f54371f85fc in __syscall_cp_c (nr=202, u=, v=, w=, x=, y=, z=0) at src/thread/pthread_cancel.c:33
#2 0x00007f54371f7b2e in __futex4_cp (to=, val=2, op=128, addr=0x7f542f843744) at src/thread/__timedwait.c:24
#3 __timedwait_cp (addr=addr@entry=0x7f542f843744, val=val@entry=2, clk=clk@entry=1, at=at@entry=0x7f542f843798, priv=128, priv@entry=1) at src/thread/__timedwait.c:52
#4 0x00007f54371f8994 in __pthread_cond_timedwait (c=0x7f542fc50158, m=0x7f542fc50130, ts=0x7f542f843798) at src/thread/pthread_cond_timedwait.c:100
#5 0x00007f54359a1991 in ?? () from /usr/lib/libQt5Core.so.5
#6 0x00007f54359a16e7 in QWaitCondition::wait(QMutex*, QDeadlineTimer) () from /usr/lib/libQt5Core.so.5
#7 0x00007f543599f96a in ?? () from /usr/lib/libQt5Core.so.5
#8 0x00007f543599c9db in ?? () from /usr/lib/libQt5Core.so.5
#9 0x00007f54371f932e in start (p=0x7f542f843930) at src/thread/pthread_create.c:207
#10 0x00007f54371fb944 in __clone () at src/thread/x86_64/clone.s:22

Thread 5 (LWP 6082 "Thread (pooled)"):
#0 __cp_end () at src/thread/x86_64/syscall_cp.s:29
#1 0x00007f54371f85fc in __syscall_cp_c (nr=202, u=, v=, w=, x=, y=, z=0) at src/thread/pthread_cancel.c:33
#2 0x00007f54371f7b2e in __futex4_cp (to=, val=2, op=128, addr=0x7f542f866744) at src/thread/__timedwait.c:24
#3 __timedwait_cp (addr=addr@entry=0x7f542f866744, val=val@entry=2, clk=clk@entry=1, at=at@entry=0x7f542f866798, priv=128, priv@entry=1) at src/thread/__timedwait.c:52
#4 0x00007f54371f8994 in __pthread_cond_timedwait (c=0x7f542fc50078, m=0x7f542fc50050, ts=0x7f542f866798) at src/thread/pthread_cond_timedwait.c:100
#5 0x00007f54359a1991 in ?? () from /usr/lib/libQt5Core.so.5
#6 0x00007f54359a16e7 in QWaitCondition::wait(QMutex*, QDeadlineTimer) () from /usr/lib/libQt5Core.so.5
#7 0x00007f543599f96a in ?? () from /usr/lib/libQt5Core.so.5
#8 0x00007f543599c9db in ?? () from /usr/lib/libQt5Core.so.5
#9 0x00007f54371f932e in start (p=0x7f542f866930) at src/thread/pthread_create.c:207
#10 0x00007f54371fb944 in __clone () at src/thread/x86_64/clone.s:22

Thread 4 (LWP 6081 "WaylandEventThr"):
#0 __cp_end () at src/thread/x86_64/syscall_cp.s:29
#1 0x00007f54371f85fc in __syscall_cp_c (nr=7, u=, v=, w=, x=, y=, z=0) at src/thread/pthread_cancel.c:33
#2 0x00007f54371ea4c1 in poll (fds=, n=, timeout=) at src/select/poll.c:9
#3 0x00007f5431a7b0a0 in ?? () from /usr/lib/libQt5WaylandClient.so.5
#4 0x00007f543599c9db in ?? () from /usr/lib/libQt5Core.so.5
#5 0x00007f54371f932e in start (p=0x7f54319a1950) at src/thread/pthread_create.c:207
#6 0x00007f54371fb944 in __clone () at src/thread/x86_64/clone.s:22

Thread 3 (LWP 6080 "WaylandEventThr"):
#0 __cp_end () at src/thread/x86_64/syscall_cp.s:29
#1 0x00007f54371f85fc in __syscall_cp_c (nr=202, u=, v=, w=, x=, y=, z=0) at src/thread/pthread_cancel.c:33
#2 0x00007f54371f7b2e in __futex4_cp (to=, val=2, op=128, addr=0x7f54319c4754) at src/thread/__timedwait.c:24
#3 __timedwait_cp (addr=addr@entry=0x7f54319c4754, val=val@entry=2, clk=clk@entry=1, at=at@entry=0x0, priv=128, priv@entry=1) at src/thread/__timedwait.c:52
#4 0x00007f54371f8994 in __pthread_cond_timedwait (c=0x7f543396d3b8, m=0x7f543396d390, ts=0x0) at src/thread/pthread_cond_timedwait.c:100
#5 0x00007f54359a199c in ?? () from /usr/lib/libQt5Core.so.5
#6 0x00007f54359a16e7 in QWaitCondition::wait(QMutex*, QDeadlineTimer) () from /usr/lib/libQt5Core.so.5
#7 0x00007f5431a7b05e in ?? () from /usr/lib/libQt5WaylandClient.so.5
#8 0x00007f543599c9db in ?? () from /usr/lib/libQt5Core.so.5
#9 0x00007f54371f932e in start (p=0x7f54319c4950) at src/thread/pthread_create.c:207
#10 0x00007f54371fb944 in __clone () at src/thread/x86_64/clone.s:22

Thread 2 (LWP 6079 "QDBusConnection"):
#0 __cp_end () at src/thread/x86_64/syscall_cp.s:29
#1 0x00007f54371f85fc in __syscall_cp_c (nr=7, u=, v=, w=, x=, y=, z=0) at src/thread/pthread_cancel.c:33
#2 0x00007f54371ea4c1 in poll (fds=, n=, timeout=) at src/select/poll.c:9
#3 0x00007f5434d704a0 in ?? () from /usr/lib/libglib-2.0.so.0
#4 0x00007f5434d0d47e in g_main_context_iteration () from /usr/lib/libglib-2.0.so.0
#5 0x00007f5435b10540 in QEventDispatcherGlib::processEvents(QFlags<QEventLoop:
#6 0x00007f5435ad6321 in QEventLoop::exec(QFlagsQEventLoop::ProcessEventsFlag) () from /usr/lib/libQt5Core.so.5
#7 0x00007f543599b9e1 in QThread::exec() () from /usr/lib/libQt5Core.so.5
#8 0x00007f5436815a9d in ?? () from /usr/lib/libQt5DBus.so.5
#9 0x00007f543599c9db in ?? () from /usr/lib/libQt5Core.so.5
#10 0x00007f54371f932e in start (p=0x7f5431b48950) at src/thread/pthread_create.c:207
#11 0x00007f54371fb944 in __clone () at src/thread/x86_64/clone.s:22

Thread 1 (LWP 6078 "gimagereader-qt"):
#0 __cp_end () at src/thread/x86_64/syscall_cp.s:29
#1 0x00007f54371f85fc in __syscall_cp_c (nr=271, u=, v=, w=, x=, y=, z=0) at src/thread/pthread_cancel.c:33
#2 0x00007f54371ea503 in ppoll (fds=, n=, to=, mask=) at src/select/ppoll.c:24
#3 0x00007f5435b0db79 in qt_safe_poll(pollfd*, unsigned long, timespec const*) () from /usr/lib/libQt5Core.so.5
#4 0x00007f5435a89d50 in ?? () from /usr/lib/libQt5Core.so.5
#5 0x00007f5435a8a87e in ?? () from /usr/lib/libQt5Core.so.5
#6 0x00005616ff98da90 in MainWindow::signalHandlerExec (signal=11, tesseractCrash=false) at /home/chris/Downloads/gimagereader-3.4.2/qt/src/MainWindow.cc:95
#7 0x00005616ff98d5c4 in MainWindow::signalHandler (signal=11) at /home/chris/Downloads/gimagereader-3.4.2/qt/src/MainWindow.cc:64
#8
#9 0x00007f54370cb59b in tesseract::OpenclDevice::HistogramRectOCL(void*, int, int, int, int, int, int, int, int*) () from /usr/lib/libtesseract.so.5
#10 0x00007f54370ccb68 in ?? () from /usr/lib/libtesseract.so.5
#11 0x00007f54370cdc75 in tesseract::OpenclDevice::getDeviceSelection() () from /usr/lib/libtesseract.so.5
#12 0x00007f54370ce299 in tesseract::OpenclDevice::InitOpenclRunEnv_DeviceSelection(int) () from /usr/lib/libtesseract.so.5
#13 0x00007f54370ce2fb in tesseract::OpenclDevice::InitEnv() () from /usr/lib/libtesseract.so.5
#14 0x00007f5436f83de0 in tesseract::TessBaseAPI::Init(char const*, int, char const*, tesseract::OcrEngineMode, char**, int, std::vector<std::__cxx11::basic_string<char, std::char_traits, std::allocator >, std::allocator<std::__cxx11::basic_string<char, std::char_traits, std::allocator > > > const*, std::vector<std::__cxx11::basic_string<char, std::char_traits, std::allocator >, std::allocator<std::__cxx11::basic_string<char, std::char_traits, std::allocator > > > const*, bool, bool ()(char const, std::vector<char, std::allocator >)) () from /usr/lib/libtesseract.so.5
#15 0x00007f5436f84023 in tesseract::TessBaseAPI::Init(char const
, char const*, tesseract::OcrEngineMode, char**, int, std::vector<std::__cxx11::basic_string<char, std::char_traits, std::allocator >, std::allocator<std::__cxx11::basic_string<char, std::char_traits, std::allocator > > > const*, std::vector<std::__cxx11::basic_string<char, std::char_traits, std::allocator >, std::allocator<std::_cxx11::basic_string<char, std::char_traits, std::allocator > > > const*, bool) () from /usr/lib/libtesseract.so.5
#16 0x00005616ff958371 in tesseract::TessBaseAPI::Init (this=0x7ffd66bf3840, datapath=0x0, language=0x0) at /usr/include/tesseract/baseapi.h:215
#17 0x00005616ff94fd9b in Config::tessdataLocation (location=Config::SystemLocation) at /home/chris/Downloads/gimagereader-3.4.2/qt/src/Config.cc:241
#18 0x00005616ff94f38e in Config::setDataLocations (this=0x7f542f402660, idx=0) at /home/chris/Downloads/gimagereader-3.4.2/qt/src/Config.cc:181
#19 0x00005616ff963bfb in QtPrivate::FunctorCall<QtPrivate::IndexesList<0>, QtPrivate::List, void, void (Config::)(int)>::call (f=(void (Config::)(Config * const, int)) 0x5616ff94f31c Config::setDataLocations(int), o=0x7f542f402660, arg=0x7ffd66bf3b38) at /usr/include/qt5/QtCore/qobjectdefs_impl.h:152
#20 0x00005616ff962fb6 in QtPrivate::FunctionPointer<void (Config::)(int)>::call<QtPrivate::List, void> (f=(void (Config::)(Config * const, int)) 0x5616ff94f31c Config::setDataLocations(int), o=0x7f542f402660, arg=0x7ffd66bf3b38) at /usr/include/qt5/QtCore/qobjectdefs_impl.h:185
#21 0x00005616ff96264b in QtPrivate::QSlotObject<void (Config::*)(int), QtPrivate::List, void>::impl (which=1, this
=0x7f542f29b2d0, r=0x7f542f402660, a=0x7ffd66bf3b38, ret=0x0) at /usr/include/qt5/QtCore/qobjectdefs_impl.h:418
#22 0x00007f5435afae1c in ?? () from /usr/lib/libQt5Core.so.5
#23 0x00007f54363f3732 in QComboBox::currentIndexChanged(int) () from /usr/lib/libQt5Widgets.so.5
#24 0x00007f54363f470c in ?? () from /usr/lib/libQt5Widgets.so.5
#25 0x00007f54363f703a in ?? () from /usr/lib/libQt5Widgets.so.5
#26 0x00007f54363f724e in QComboBox::setCurrentIndex(int) () from /usr/lib/libQt5Widgets.so.5
#27 0x00005616ff949a44 in ComboSetting::ComboSetting (this=0x7f542f682cf0, key=..., combo=0x7f542f3603e0, defaultIndex=0) at /home/chris/Downloads/gimagereader-3.4.2/qt/src/ConfigSettings.hh:177
#28 0x00005616ff94dd9a in Config::Config (this=0x7f542f402660, parent=0x7f54306e7310) at /home/chris/Downloads/gimagereader-3.4.2/qt/src/Config.cc:92
#29 0x00005616ff98e6e3 in MainWindow::MainWindow (this=0x7f54306e7310, files=...) at /home/chris/Downloads/gimagereader-3.4.2/qt/src/MainWindow.cc:139
#30 0x00005616ffa59ec5 in main (argc=1, argv=0x7ffd66bf42d8) at /home/chris/Downloads/gimagereader-3.4.2/qt/src/main.cc:98

clinfo:

Number of platforms 1
Platform Name rusticl
Platform Vendor Mesa/X.org
Platform Version OpenCL 3.0
Platform Profile FULL_PROFILE
Platform Extensions cl_khr_byte_addressable_store cl_khr_create_command_queue cl_khr_expect_assume cl_khr_extended_versioning cl_khr_icd cl_khr_il_program cl_khr_spirv_no_integer_wrap_decoration
Platform Extensions with Version cl_khr_byte_addressable_store 0x400000 (1.0.0)
cl_khr_create_command_queue 0x400000 (1.0.0)
cl_khr_expect_assume 0x400000 (1.0.0)
cl_khr_extended_versioning 0x400000 (1.0.0)
cl_khr_icd 0x400000 (1.0.0)
cl_khr_il_program 0x400000 (1.0.0)
cl_khr_spirv_no_integer_wrap_decoration 0x400000 (1.0.0)
Platform Numeric Version 0xc00000 (3.0.0)
Platform Extensions function suffix MESA
Platform Host timer resolution 1ns

Platform Name rusticl
Number of devices 0

NULL platform behavior
clGetPlatformInfo(NULL, CL_PLATFORM_NAME, ...) No platform
clGetDeviceIDs(NULL, CL_DEVICE_TYPE_ALL, ...) No platform
clCreateContext(NULL, ...) [default] No platform
clCreateContext(NULL, ...) [other] <error: no devices in non-default plaforms>
clCreateContextFromType(NULL, CL_DEVICE_TYPE_DEFAULT) No devices found in platform
clCreateContextFromType(NULL, CL_DEVICE_TYPE_CPU) No devices found in platform
clCreateContextFromType(NULL, CL_DEVICE_TYPE_GPU) No devices found in platform
clCreateContextFromType(NULL, CL_DEVICE_TYPE_ACCELERATOR) No devices found in platform
clCreateContextFromType(NULL, CL_DEVICE_TYPE_CUSTOM) No devices found in platform
clCreateContextFromType(NULL, CL_DEVICE_TYPE_ALL) No devices found in platform

ICD loader properties
ICD loader Name Khronos OpenCL ICD Loaderns
ICD loader Vendor Khronos Groupns
ICD loader Version 3.0.6ns
ICD loader Profile OpenCL 3.0ns

The relevant frame is

#9 0x00007f54370cb59b in tesseract::OpenclDevice::HistogramRectOCL(void*, int, int, int, int, int, int, int, int*) () from /usr/lib/libtesseract.so.5

So yes, this is a tesseract crash. If you can also reproduce it with the command line tesseract executable, please file a bug to tesseract.

Righto, I'll inquire elsewhere. Thanks.