1
0
Fork 0
forked from suyu/suyu

hle: cleaned up log messages

This commit is contained in:
bunnei 2014-05-29 23:26:58 -04:00
parent b0bad47c0e
commit c404d22036
8 changed files with 49 additions and 45 deletions

View file

@ -55,7 +55,7 @@ inline void Read(T &var, const u32 addr) {
break; break;
default: default:
ERROR_LOG(HLE, "unknown ConfigMem::Read%d @ 0x%08X", sizeof(var) * 8, addr); ERROR_LOG(HLE, "unknown addr=0x%08X", addr);
} }
} }

View file

@ -18,7 +18,7 @@ static std::vector<ModuleDef> g_module_db;
const FunctionDef* GetSVCInfo(u32 opcode) { const FunctionDef* GetSVCInfo(u32 opcode) {
u32 func_num = opcode & 0xFFFFFF; // 8 bits u32 func_num = opcode & 0xFFFFFF; // 8 bits
if (func_num > 0xFF) { if (func_num > 0xFF) {
ERROR_LOG(HLE,"Unknown SVC: 0x%02X", func_num); ERROR_LOG(HLE,"unknown svc=0x%02X", func_num);
return NULL; return NULL;
} }
return &g_module_db[0].func_table[func_num]; return &g_module_db[0].func_table[func_num];
@ -33,7 +33,7 @@ void CallSVC(u32 opcode) {
if (info->func) { if (info->func) {
info->func(); info->func();
} else { } else {
ERROR_LOG(HLE, "Unimplemented SVC function %s(..)", info->name.c_str()); ERROR_LOG(HLE, "unimplemented SVC function %s(..)", info->name.c_str());
} }
} }
@ -43,7 +43,7 @@ void EatCycles(u32 cycles) {
void ReSchedule(const char *reason) { void ReSchedule(const char *reason) {
#ifdef _DEBUG #ifdef _DEBUG
_dbg_assert_msg_(HLE, reason != 0 && strlen(reason) < 256, "ReSchedule: Invalid or too long reason."); _dbg_assert_msg_(HLE, reason != 0 && strlen(reason) < 256, "Reschedule: Invalid or too long reason.");
#endif #endif
// TODO: ImplementMe // TODO: ImplementMe
} }

View file

@ -17,7 +17,7 @@ namespace APT_U {
void Initialize(Service::Interface* self) { void Initialize(Service::Interface* self) {
u32* cmd_buff = Service::GetCommandBuffer(); u32* cmd_buff = Service::GetCommandBuffer();
DEBUG_LOG(KERNEL, "APT_U::Initialize called"); DEBUG_LOG(KERNEL, "called");
cmd_buff[3] = Kernel::CreateEvent(RESETTYPE_ONESHOT); // APT menu event handle cmd_buff[3] = Kernel::CreateEvent(RESETTYPE_ONESHOT); // APT menu event handle
cmd_buff[4] = Kernel::CreateEvent(RESETTYPE_ONESHOT); // APT pause event handle cmd_buff[4] = Kernel::CreateEvent(RESETTYPE_ONESHOT); // APT pause event handle
@ -33,14 +33,14 @@ void GetLockHandle(Service::Interface* self) {
u32 flags = cmd_buff[1]; // TODO(bunnei): Figure out the purpose of the flag field u32 flags = cmd_buff[1]; // TODO(bunnei): Figure out the purpose of the flag field
cmd_buff[1] = 0; // No error cmd_buff[1] = 0; // No error
cmd_buff[5] = Kernel::CreateMutex(false); cmd_buff[5] = Kernel::CreateMutex(false);
DEBUG_LOG(KERNEL, "APT_U::GetLockHandle called handle=0x%08X", cmd_buff[5]); DEBUG_LOG(KERNEL, "called handle=0x%08X", cmd_buff[5]);
} }
void Enable(Service::Interface* self) { void Enable(Service::Interface* self) {
u32* cmd_buff = Service::GetCommandBuffer(); u32* cmd_buff = Service::GetCommandBuffer();
u32 unk = cmd_buff[1]; // TODO(bunnei): What is this field used for? u32 unk = cmd_buff[1]; // TODO(bunnei): What is this field used for?
cmd_buff[1] = 0; // No error cmd_buff[1] = 0; // No error
ERROR_LOG(KERNEL, "(UNIMPEMENTED) APT_U::Enable called unk=0x%08X", unk); ERROR_LOG(KERNEL, "(UNIMPEMENTED) called unk=0x%08X", unk);
} }
void InquireNotification(Service::Interface* self) { void InquireNotification(Service::Interface* self) {
@ -48,7 +48,7 @@ void InquireNotification(Service::Interface* self) {
u32 app_id = cmd_buff[2]; u32 app_id = cmd_buff[2];
cmd_buff[1] = 0; // No error cmd_buff[1] = 0; // No error
cmd_buff[3] = 0; // Signal type cmd_buff[3] = 0; // Signal type
ERROR_LOG(KERNEL, "(UNIMPEMENTED) APT_U::InquireNotification called app_id=0x%08X", app_id); ERROR_LOG(KERNEL, "(UNIMPEMENTED) called app_id=0x%08X", app_id);
} }
const Interface::FunctionInfo FunctionTable[] = { const Interface::FunctionInfo FunctionTable[] = {

View file

@ -92,7 +92,7 @@ void ReadHWRegs(Service::Interface* self) {
break; break;
default: default:
ERROR_LOG(GSP, "ReadHWRegs unknown register read at address %08X", reg_addr); ERROR_LOG(GSP, "unknown register read at address %08X", reg_addr);
} }
} }
@ -117,7 +117,7 @@ void TriggerCmdReqQueue(Service::Interface* self) {
break; break;
default: default:
ERROR_LOG(GSP, "TriggerCmdReqQueue unknown command 0x%08X", cmd_buff[0]); ERROR_LOG(GSP, "unknown command 0x%08X", cmd_buff[0]);
} }
GX_FinishCommand(g_thread_id); GX_FinishCommand(g_thread_id);

View file

@ -12,6 +12,8 @@
#include "core/hle/service/apt.h" #include "core/hle/service/apt.h"
#include "core/hle/service/gsp.h" #include "core/hle/service/gsp.h"
#include "core/hle/service/hid.h" #include "core/hle/service/hid.h"
#include "core/hle/service/ndm.h"
#include "core/hle/service/pt.h"
#include "core/hle/service/srv.h" #include "core/hle/service/srv.h"
#include "core/hle/kernel/kernel.h" #include "core/hle/kernel/kernel.h"
@ -72,14 +74,16 @@ void Init() {
g_manager->AddService(new APT_U::Interface); g_manager->AddService(new APT_U::Interface);
g_manager->AddService(new GSP_GPU::Interface); g_manager->AddService(new GSP_GPU::Interface);
g_manager->AddService(new HID_User::Interface); g_manager->AddService(new HID_User::Interface);
g_manager->AddService(new NDM_U::Interface);
g_manager->AddService(new PT_A::Interface);
NOTICE_LOG(HLE, "Services initialized OK"); NOTICE_LOG(HLE, "initialized OK");
} }
/// Shutdown ServiceManager /// Shutdown ServiceManager
void Shutdown() { void Shutdown() {
delete g_manager; delete g_manager;
NOTICE_LOG(HLE, "Services shutdown OK"); NOTICE_LOG(HLE, "shutdown OK");
} }

View file

@ -15,14 +15,14 @@ namespace SRV {
Handle g_mutex = 0; Handle g_mutex = 0;
void Initialize(Service::Interface* self) { void Initialize(Service::Interface* self) {
DEBUG_LOG(OSHLE, "SRV::Initialize called"); DEBUG_LOG(OSHLE, "called");
if (!g_mutex) { if (!g_mutex) {
g_mutex = Kernel::CreateMutex(false); g_mutex = Kernel::CreateMutex(false);
} }
} }
void GetProcSemaphore(Service::Interface* self) { void GetProcSemaphore(Service::Interface* self) {
DEBUG_LOG(OSHLE, "SRV::GetProcSemaphore called"); DEBUG_LOG(OSHLE, "called");
// Get process semaphore? // Get process semaphore?
u32* cmd_buff = Service::GetCommandBuffer(); u32* cmd_buff = Service::GetCommandBuffer();
cmd_buff[1] = 0; // No error cmd_buff[1] = 0; // No error
@ -36,7 +36,7 @@ void GetServiceHandle(Service::Interface* self) {
std::string port_name = std::string((const char*)&cmd_buff[1], 0, Service::kMaxPortSize); std::string port_name = std::string((const char*)&cmd_buff[1], 0, Service::kMaxPortSize);
Service::Interface* service = Service::g_manager->FetchFromPortName(port_name); Service::Interface* service = Service::g_manager->FetchFromPortName(port_name);
DEBUG_LOG(OSHLE, "SRV::Sync - GetHandle - port: %s, handle: 0x%08X", port_name.c_str(), DEBUG_LOG(OSHLE, "called port=%s, handle=0x%08X", port_name.c_str(),
service->GetHandle()); service->GetHandle());
if (NULL != service) { if (NULL != service) {

View file

@ -37,7 +37,7 @@ enum MapMemoryPermission {
Result ControlMemory(void* _outaddr, u32 operation, u32 addr0, u32 addr1, u32 size, u32 permissions) { Result ControlMemory(void* _outaddr, u32 operation, u32 addr0, u32 addr1, u32 size, u32 permissions) {
u32 virtual_address = 0x00000000; u32 virtual_address = 0x00000000;
DEBUG_LOG(SVC, "ControlMemory called operation=0x%08X, addr0=0x%08X, addr1=0x%08X, size=%08X, permissions=0x%08X", DEBUG_LOG(SVC,"called operation=0x%08X, addr0=0x%08X, addr1=0x%08X, size=%08X, permissions=0x%08X",
operation, addr0, addr1, size, permissions); operation, addr0, addr1, size, permissions);
switch (operation) { switch (operation) {
@ -54,7 +54,7 @@ Result ControlMemory(void* _outaddr, u32 operation, u32 addr0, u32 addr1, u32 si
// Unknown ControlMemory operation // Unknown ControlMemory operation
default: default:
ERROR_LOG(SVC, "ControlMemory unknown operation=0x%08X", operation); ERROR_LOG(SVC, "unknown operation=0x%08X", operation);
} }
Core::g_app_core->SetReg(1, virtual_address); Core::g_app_core->SetReg(1, virtual_address);
@ -64,7 +64,7 @@ Result ControlMemory(void* _outaddr, u32 operation, u32 addr0, u32 addr1, u32 si
/// Maps a memory block to specified address /// Maps a memory block to specified address
Result MapMemoryBlock(Handle memblock, u32 addr, u32 mypermissions, u32 otherpermission) { Result MapMemoryBlock(Handle memblock, u32 addr, u32 mypermissions, u32 otherpermission) {
DEBUG_LOG(SVC, "MapMemoryBlock called memblock=0x08X, addr=0x%08X, mypermissions=0x%08X, otherpermission=%d", DEBUG_LOG(SVC, "called memblock=0x08X, addr=0x%08X, mypermissions=0x%08X, otherpermission=%d",
memblock, addr, mypermissions, otherpermission); memblock, addr, mypermissions, otherpermission);
switch (mypermissions) { switch (mypermissions) {
case MEMORY_PERMISSION_NORMAL: case MEMORY_PERMISSION_NORMAL:
@ -73,7 +73,7 @@ Result MapMemoryBlock(Handle memblock, u32 addr, u32 mypermissions, u32 otherper
Memory::MapBlock_Shared(memblock, addr, mypermissions); Memory::MapBlock_Shared(memblock, addr, mypermissions);
break; break;
default: default:
ERROR_LOG(OSHLE, "MapMemoryBlock unknown permissions=0x%08X", mypermissions); ERROR_LOG(OSHLE, "unknown permissions=0x%08X", mypermissions);
} }
return 0; return 0;
} }
@ -81,8 +81,8 @@ Result MapMemoryBlock(Handle memblock, u32 addr, u32 mypermissions, u32 otherper
/// Connect to an OS service given the port name, returns the handle to the port to out /// Connect to an OS service given the port name, returns the handle to the port to out
Result ConnectToPort(void* _out, const char* port_name) { Result ConnectToPort(void* _out, const char* port_name) {
Service::Interface* service = Service::g_manager->FetchFromPortName(port_name); Service::Interface* service = Service::g_manager->FetchFromPortName(port_name);
DEBUG_LOG(SVC, "ConnectToPort called port_name=%s", port_name); DEBUG_LOG(SVC, "called port_name=%s", port_name);
_assert_msg_(KERNEL, service, "ConnectToPort called, but service is not implemented!"); _assert_msg_(KERNEL, service, "called, but service is not implemented!");
Core::g_app_core->SetReg(1, service->GetHandle()); Core::g_app_core->SetReg(1, service->GetHandle());
return 0; return 0;
} }
@ -92,8 +92,8 @@ Result SendSyncRequest(Handle handle) {
bool wait = false; bool wait = false;
Kernel::Object* object = Kernel::g_object_pool.GetFast<Kernel::Object>(handle); Kernel::Object* object = Kernel::g_object_pool.GetFast<Kernel::Object>(handle);
DEBUG_LOG(SVC, "SendSyncRequest called handle=0x%08X", handle); DEBUG_LOG(SVC, "called handle=0x%08X", handle);
_assert_msg_(KERNEL, object, "SendSyncRequest called, but kernel object is NULL!"); _assert_msg_(KERNEL, object, "called, but kernel object is NULL!");
Result res = object->SyncRequest(&wait); Result res = object->SyncRequest(&wait);
if (wait) { if (wait) {
@ -106,7 +106,7 @@ Result SendSyncRequest(Handle handle) {
/// Close a handle /// Close a handle
Result CloseHandle(Handle handle) { Result CloseHandle(Handle handle) {
// ImplementMe // ImplementMe
ERROR_LOG(SVC, "(UNIMPLEMENTED) CloseHandle called handle=0x%08X", handle); ERROR_LOG(SVC, "(UNIMPLEMENTED) called handle=0x%08X", handle);
return 0; return 0;
} }
@ -117,9 +117,9 @@ Result WaitSynchronization1(Handle handle, s64 nano_seconds) {
Kernel::Object* object = Kernel::g_object_pool.GetFast<Kernel::Object>(handle); Kernel::Object* object = Kernel::g_object_pool.GetFast<Kernel::Object>(handle);
DEBUG_LOG(SVC, "WaitSynchronization1 called handle=0x%08X, nanoseconds=%d", handle, DEBUG_LOG(SVC, "called handle=0x%08X, nanoseconds=%d", handle,
nano_seconds); nano_seconds);
_assert_msg_(KERNEL, object, "WaitSynchronization1 called, but kernel object is NULL!"); _assert_msg_(KERNEL, object, "called, but kernel object is NULL!");
Result res = object->WaitSynchronization(&wait); Result res = object->WaitSynchronization(&wait);
@ -139,7 +139,7 @@ Result WaitSynchronizationN(void* _out, void* _handles, u32 handle_count, u32 wa
Handle* handles = (Handle*)_handles; Handle* handles = (Handle*)_handles;
bool unlock_all = true; bool unlock_all = true;
DEBUG_LOG(SVC, "WaitSynchronizationN called handle_count=%d, wait_all=%s, nanoseconds=%d", DEBUG_LOG(SVC, "called handle_count=%d, wait_all=%s, nanoseconds=%d",
handle_count, (wait_all ? "true" : "false"), nano_seconds); handle_count, (wait_all ? "true" : "false"), nano_seconds);
// Iterate through each handle, synchronize kernel object // Iterate through each handle, synchronize kernel object
@ -147,7 +147,7 @@ Result WaitSynchronizationN(void* _out, void* _handles, u32 handle_count, u32 wa
bool wait = false; bool wait = false;
Kernel::Object* object = Kernel::g_object_pool.GetFast<Kernel::Object>(handles[i]); // 0 handle Kernel::Object* object = Kernel::g_object_pool.GetFast<Kernel::Object>(handles[i]); // 0 handle
_assert_msg_(KERNEL, object, "WaitSynchronizationN called handle=0x%08X, but kernel object " _assert_msg_(KERNEL, object, "called handle=0x%08X, but kernel object "
"is NULL!", handles[i]); "is NULL!", handles[i]);
DEBUG_LOG(SVC, "\thandle[%d] = 0x%08X", i, handles[i]); DEBUG_LOG(SVC, "\thandle[%d] = 0x%08X", i, handles[i]);
@ -176,14 +176,14 @@ Result WaitSynchronizationN(void* _out, void* _handles, u32 handle_count, u32 wa
/// Create an address arbiter (to allocate access to shared resources) /// Create an address arbiter (to allocate access to shared resources)
Result CreateAddressArbiter(void* arbiter) { Result CreateAddressArbiter(void* arbiter) {
ERROR_LOG(SVC, "(UNIMPLEMENTED) CreateAddressArbiter called"); ERROR_LOG(SVC, "(UNIMPLEMENTED) called");
Core::g_app_core->SetReg(1, 0xFABBDADD); Core::g_app_core->SetReg(1, 0xFABBDADD);
return 0; return 0;
} }
/// Arbitrate address /// Arbitrate address
Result ArbitrateAddress(Handle arbiter, u32 addr, u32 _type, u32 value, s64 nanoseconds) { Result ArbitrateAddress(Handle arbiter, u32 addr, u32 _type, u32 value, s64 nanoseconds) {
ERROR_LOG(SVC, "(UNIMPLEMENTED) ArbitrateAddress called"); ERROR_LOG(SVC, "(UNIMPLEMENTED) called");
ArbitrationType type = (ArbitrationType)_type; ArbitrationType type = (ArbitrationType)_type;
Memory::Write32(addr, type); Memory::Write32(addr, type);
return 0; return 0;
@ -199,14 +199,15 @@ Result GetResourceLimit(void* resource_limit, Handle process) {
// With regards to proceess values: // With regards to proceess values:
// 0xFFFF8001 is a handle alias for the current KProcess, and 0xFFFF8000 is a handle alias for // 0xFFFF8001 is a handle alias for the current KProcess, and 0xFFFF8000 is a handle alias for
// the current KThread. // the current KThread.
ERROR_LOG(SVC, "(UNIMPLEMENTED) GetResourceLimit called process=0x%08X", process); ERROR_LOG(SVC, "(UNIMPLEMENTED) called process=0x%08X", process);
Core::g_app_core->SetReg(1, 0xDEADBEEF); Core::g_app_core->SetReg(1, 0xDEADBEEF);
return 0; return 0;
} }
/// Get resource limit current values /// Get resource limit current values
Result GetResourceLimitCurrentValues(void* _values, Handle resource_limit, void* names, s32 name_count) { Result GetResourceLimitCurrentValues(void* _values, Handle resource_limit, void* names,
ERROR_LOG(SVC, "(UNIMPLEMENTED) GetResourceLimitCurrentValues called resource_limit=%08X, names=%s, name_count=%d", s32 name_count) {
ERROR_LOG(SVC, "(UNIMPLEMENTED) called resource_limit=%08X, names=%s, name_count=%d",
resource_limit, names, name_count); resource_limit, names, name_count);
Memory::Write32(Core::g_app_core->GetReg(0), 0); // Normmatt: Set used memory to 0 for now Memory::Write32(Core::g_app_core->GetReg(0), 0); // Normmatt: Set used memory to 0 for now
return 0; return 0;
@ -229,7 +230,7 @@ Result CreateThread(u32 priority, u32 entry_point, u32 arg, u32 stack_top, u32 p
Core::g_app_core->SetReg(1, thread); Core::g_app_core->SetReg(1, thread);
DEBUG_LOG(SVC, "CreateThread called entrypoint=0x%08X (%s), arg=0x%08X, stacktop=0x%08X, " DEBUG_LOG(SVC, "called entrypoint=0x%08X (%s), arg=0x%08X, stacktop=0x%08X, "
"threadpriority=0x%08X, processorid=0x%08X : created handle=0x%08X", entry_point, "threadpriority=0x%08X, processorid=0x%08X : created handle=0x%08X", entry_point,
name.c_str(), arg, stack_top, priority, processor_id, thread); name.c_str(), arg, stack_top, priority, processor_id, thread);
@ -240,28 +241,28 @@ Result CreateThread(u32 priority, u32 entry_point, u32 arg, u32 stack_top, u32 p
Result CreateMutex(void* _mutex, u32 initial_locked) { Result CreateMutex(void* _mutex, u32 initial_locked) {
Handle mutex = Kernel::CreateMutex((initial_locked != 0)); Handle mutex = Kernel::CreateMutex((initial_locked != 0));
Core::g_app_core->SetReg(1, mutex); Core::g_app_core->SetReg(1, mutex);
DEBUG_LOG(SVC, "CreateMutex called initial_locked=%s : created handle=0x%08X", DEBUG_LOG(SVC, "called initial_locked=%s : created handle=0x%08X",
initial_locked ? "true" : "false", mutex); initial_locked ? "true" : "false", mutex);
return 0; return 0;
} }
/// Release a mutex /// Release a mutex
Result ReleaseMutex(Handle handle) { Result ReleaseMutex(Handle handle) {
DEBUG_LOG(SVC, "ReleaseMutex called handle=0x%08X", handle); DEBUG_LOG(SVC, "called handle=0x%08X", handle);
_assert_msg_(KERNEL, handle, "ReleaseMutex called, but handle is NULL!"); _assert_msg_(KERNEL, handle, "called, but handle is NULL!");
Kernel::ReleaseMutex(handle); Kernel::ReleaseMutex(handle);
return 0; return 0;
} }
/// Get current thread ID /// Get current thread ID
Result GetThreadId(void* thread_id, u32 thread) { Result GetThreadId(void* thread_id, u32 thread) {
ERROR_LOG(SVC, "(UNIMPLEMENTED) GetThreadId called thread=0x%08X", thread); ERROR_LOG(SVC, "(UNIMPLEMENTED) called thread=0x%08X", thread);
return 0; return 0;
} }
/// Query memory /// Query memory
Result QueryMemory(void *_info, void *_out, u32 addr) { Result QueryMemory(void *_info, void *_out, u32 addr) {
ERROR_LOG(SVC, "(UNIMPLEMENTED) QueryMemory called addr=0x%08X", addr); ERROR_LOG(SVC, "(UNIMPLEMENTED) called addr=0x%08X", addr);
return 0; return 0;
} }
@ -269,7 +270,7 @@ Result QueryMemory(void *_info, void *_out, u32 addr) {
Result CreateEvent(void* _event, u32 reset_type) { Result CreateEvent(void* _event, u32 reset_type) {
Handle evt = Kernel::CreateEvent((ResetType)reset_type); Handle evt = Kernel::CreateEvent((ResetType)reset_type);
Core::g_app_core->SetReg(1, evt); Core::g_app_core->SetReg(1, evt);
DEBUG_LOG(SVC, "CreateEvent called reset_type=0x%08X : created handle=0x%08X", DEBUG_LOG(SVC, "called reset_type=0x%08X : created handle=0x%08X",
reset_type, evt); reset_type, evt);
return 0; return 0;
} }
@ -277,14 +278,14 @@ Result CreateEvent(void* _event, u32 reset_type) {
/// Duplicates a kernel handle /// Duplicates a kernel handle
Result DuplicateHandle(void* _out, Handle handle) { Result DuplicateHandle(void* _out, Handle handle) {
Handle* out = (Handle*)_out; Handle* out = (Handle*)_out;
ERROR_LOG(SVC, "(UNIMPLEMENTED) DuplicateHandle called handle=0x%08X", handle); ERROR_LOG(SVC, "(UNIMPLEMENTED) called handle=0x%08X", handle);
return 0; return 0;
} }
/// Clears an event /// Clears an event
Result ClearEvent(Handle evt) { Result ClearEvent(Handle evt) {
Result res = Kernel::ClearEvent(evt); Result res = Kernel::ClearEvent(evt);
DEBUG_LOG(SVC, "ClearEvent called event=0x%08X", evt); DEBUG_LOG(SVC, "called event=0x%08X", evt);
return res; return res;
} }

View file

@ -86,7 +86,7 @@ inline void _Read(T &var, const u32 addr) {
var = *((const T*)&g_vram[vaddr & VRAM_MASK]); var = *((const T*)&g_vram[vaddr & VRAM_MASK]);
} else { } else {
//_assert_msg_(MEMMAP, false, "unknown Read%d @ 0x%08X", sizeof(var) * 8, vaddr); ERROR_LOG(MEMMAP, "unknown Read%d @ 0x%08X", sizeof(var) * 8, vaddr);
} }
} }
@ -136,8 +136,7 @@ inline void _Write(u32 addr, const T data) {
// Error out... // Error out...
} else { } else {
_assert_msg_(MEMMAP, false, "unknown Write%d 0x%08X @ 0x%08X", sizeof(data) * 8, ERROR_LOG(MEMMAP, "unknown Write%d 0x%08X @ 0x%08X", sizeof(data) * 8, data, vaddr);
data, vaddr);
} }
} }