summaryrefslogtreecommitdiff
path: root/src/modules/plugins/newplugins.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/modules/plugins/newplugins.cpp')
-rw-r--r--src/modules/plugins/newplugins.cpp146
1 files changed, 69 insertions, 77 deletions
diff --git a/src/modules/plugins/newplugins.cpp b/src/modules/plugins/newplugins.cpp
index 07270ffb84..a9264bcca9 100644
--- a/src/modules/plugins/newplugins.cpp
+++ b/src/modules/plugins/newplugins.cpp
@@ -34,7 +34,7 @@ extern bool bModulesLoadedFired;
static int sttComparePluginsByName(const pluginEntry* p1, const pluginEntry* p2)
{
- return lstrcmp(p1->pluginname, p2->pluginname);
+ return mir_tstrcmp(p1->pluginname, p2->pluginname);
}
LIST<pluginEntry>
@@ -63,7 +63,7 @@ static pluginEntry *pluginList_freeimg, *pluginList_crshdmp, *serviceModePlugin
int equalUUID(const MUUID& u1, const MUUID& u2)
{
- return memcmp(&u1, &u2, sizeof(MUUID))?0:1;
+ return memcmp(&u1, &u2, sizeof(MUUID)) ? 0 : 1;
}
bool hasMuuid(const MUUID* p, const MUUID& uuid)
@@ -71,8 +71,8 @@ bool hasMuuid(const MUUID* p, const MUUID& uuid)
if (p == NULL)
return false;
- for (int i=0; !equalUUID(miid_last, p[i]); i++)
- if ( equalUUID(uuid, p[i]))
+ for (int i = 0; !equalUUID(miid_last, p[i]); i++)
+ if (equalUUID(uuid, p[i]))
return true;
return false;
@@ -91,22 +91,22 @@ bool hasMuuid(const BASIC_PLUGIN_INFO& bpi, const MUUID& uuid)
static const MUUID pluginBannedList[] =
{
- {0x9d6c3213, 0x02b4, 0x4fe1, { 0x92, 0xe6, 0x52, 0x6d, 0xe2, 0x4f, 0x8d, 0x65 }}, // old chat
- {0x240a91dc, 0x9464, 0x457a, { 0x97, 0x87, 0xff, 0x1e, 0xa8, 0x8e, 0x77, 0xe3 }}, // old clist
- {0x657fe89b, 0xd121, 0x40c2, { 0x8a, 0xc9, 0xb9, 0xfa, 0x57, 0x55, 0xb3, 0x0c }}, // old srmm
- {0x112f7d30, 0xcd19, 0x4c74, { 0xa0, 0x3b, 0xbf, 0xbb, 0x76, 0xb7, 0x5b, 0xc4 }}, // extraicons
- {0x72765a6f, 0xb017, 0x42f1, { 0xb3, 0x0f, 0x5e, 0x09, 0x41, 0x27, 0x3a, 0x3f }}, // flashavatars
- {0x1394a3ab, 0x2585, 0x4196, { 0x8f, 0x72, 0x0e, 0xae, 0xc2, 0x45, 0x0e, 0x11 }}, // db3x
- {0x28ff9b91, 0x3e4d, 0x4f1c, { 0xb4, 0x7c, 0xc6, 0x41, 0xb0, 0x37, 0xff, 0x40 }}, // dbx_mmap_sa
- {0x28f45248, 0x8c9c, 0x4bee, { 0x93, 0x07, 0x7b, 0xcf, 0x3e, 0x12, 0xbf, 0x99 }}, // dbx_tree
- {0x4c4a27cf, 0x5e64, 0x4242, { 0xa3, 0x32, 0xb9, 0x8b, 0x08, 0x24, 0x3e, 0x89 }}, // metacontacts
- {0x9c448c61, 0xfc3f, 0x42f9, { 0xb9, 0xf0, 0x4a, 0x30, 0xe1, 0xcf, 0x86, 0x71 }}, // skypekit based skype
- {0x49c2cf54, 0x7898, 0x44de, { 0xbe, 0x3a, 0x6d, 0x2e, 0x4e, 0xf9, 0x00, 0x79 }} // firstrun
+ { 0x9d6c3213, 0x02b4, 0x4fe1, { 0x92, 0xe6, 0x52, 0x6d, 0xe2, 0x4f, 0x8d, 0x65 } }, // old chat
+ { 0x240a91dc, 0x9464, 0x457a, { 0x97, 0x87, 0xff, 0x1e, 0xa8, 0x8e, 0x77, 0xe3 } }, // old clist
+ { 0x657fe89b, 0xd121, 0x40c2, { 0x8a, 0xc9, 0xb9, 0xfa, 0x57, 0x55, 0xb3, 0x0c } }, // old srmm
+ { 0x112f7d30, 0xcd19, 0x4c74, { 0xa0, 0x3b, 0xbf, 0xbb, 0x76, 0xb7, 0x5b, 0xc4 } }, // extraicons
+ { 0x72765a6f, 0xb017, 0x42f1, { 0xb3, 0x0f, 0x5e, 0x09, 0x41, 0x27, 0x3a, 0x3f } }, // flashavatars
+ { 0x1394a3ab, 0x2585, 0x4196, { 0x8f, 0x72, 0x0e, 0xae, 0xc2, 0x45, 0x0e, 0x11 } }, // db3x
+ { 0x28ff9b91, 0x3e4d, 0x4f1c, { 0xb4, 0x7c, 0xc6, 0x41, 0xb0, 0x37, 0xff, 0x40 } }, // dbx_mmap_sa
+ { 0x28f45248, 0x8c9c, 0x4bee, { 0x93, 0x07, 0x7b, 0xcf, 0x3e, 0x12, 0xbf, 0x99 } }, // dbx_tree
+ { 0x4c4a27cf, 0x5e64, 0x4242, { 0xa3, 0x32, 0xb9, 0x8b, 0x08, 0x24, 0x3e, 0x89 } }, // metacontacts
+ { 0x9c448c61, 0xfc3f, 0x42f9, { 0xb9, 0xf0, 0x4a, 0x30, 0xe1, 0xcf, 0x86, 0x71 } }, // skypekit based skype
+ { 0x49c2cf54, 0x7898, 0x44de, { 0xbe, 0x3a, 0x6d, 0x2e, 0x4e, 0xf9, 0x00, 0x79 } } // firstrun
};
static bool isPluginBanned(const MUUID& u1)
{
- for (int i=0; i < SIZEOF(pluginBannedList); i++)
+ for (int i = 0; i < SIZEOF(pluginBannedList); i++)
if (equalUUID(pluginBannedList[i], u1))
return true;
@@ -118,25 +118,25 @@ static bool isPluginBanned(const MUUID& u1)
static MuuidReplacement pluginDefault[] =
{
- { MIID_UIUSERINFO, _T("stduserinfo"), NULL }, // 0
- { MIID_SRURL, _T("stdurl"), NULL }, // 1
- { MIID_SREMAIL, _T("stdemail"), NULL }, // 2
- { MIID_SRAUTH, _T("stdauth"), NULL }, // 3
- { MIID_SRFILE, _T("stdfile"), NULL }, // 4
- { MIID_UIHELP, _T("stdhelp"), NULL }, // 5
- { MIID_UIHISTORY, _T("stduihist"), NULL }, // 6
- { MIID_IDLE, _T("stdidle"), NULL }, // 7
- { MIID_AUTOAWAY, _T("stdautoaway"), NULL }, // 8
- { MIID_USERONLINE, _T("stduseronline"), NULL }, // 9
- { MIID_SRAWAY, _T("stdaway"), NULL }, // 10
- { MIID_CLIST, _T("stdclist"), NULL }, // 11
- { MIID_CHAT, _T("stdchat"), NULL }, // 12
- { MIID_SRMM, _T("stdmsg"), NULL } // 13
+ { MIID_UIUSERINFO, _T("stduserinfo"), NULL }, // 0
+ { MIID_SRURL, _T("stdurl"), NULL }, // 1
+ { MIID_SREMAIL, _T("stdemail"), NULL }, // 2
+ { MIID_SRAUTH, _T("stdauth"), NULL }, // 3
+ { MIID_SRFILE, _T("stdfile"), NULL }, // 4
+ { MIID_UIHELP, _T("stdhelp"), NULL }, // 5
+ { MIID_UIHISTORY, _T("stduihist"), NULL }, // 6
+ { MIID_IDLE, _T("stdidle"), NULL }, // 7
+ { MIID_AUTOAWAY, _T("stdautoaway"), NULL }, // 8
+ { MIID_USERONLINE, _T("stduseronline"), NULL }, // 9
+ { MIID_SRAWAY, _T("stdaway"), NULL }, // 10
+ { MIID_CLIST, _T("stdclist"), NULL }, // 11
+ { MIID_CHAT, _T("stdchat"), NULL }, // 12
+ { MIID_SRMM, _T("stdmsg"), NULL } // 13
};
int getDefaultPluginIdx(const MUUID& muuid)
{
- for (int i=0; i < SIZEOF(pluginDefault); i++)
+ for (int i = 0; i < SIZEOF(pluginDefault); i++)
if (equalUUID(muuid, pluginDefault[i].uuid))
return i;
@@ -171,7 +171,7 @@ char* GetPluginNameByInstance(HINSTANCE hInstance)
if (pluginList.getCount() == 0)
return NULL;
- for (int i=0; i < pluginList.getCount(); i++) {
+ for (int i = 0; i < pluginList.getCount(); i++) {
pluginEntry *p = pluginList[i];
if (p->bpi.pluginInfo && p->bpi.hInst == hInstance)
return p->bpi.pluginInfo->shortName;
@@ -184,7 +184,7 @@ int GetPluginLangByInstance(HINSTANCE hInstance)
if (pluginList.getCount() == 0)
return NULL;
- for (int i=0; i < pluginList.getCount(); i++) {
+ for (int i = 0; i < pluginList.getCount(); i++) {
pluginEntry *p = pluginList[i];
if (p->bpi.pluginInfo && p->bpi.hInst == hInstance)
return p->hLangpack;
@@ -194,12 +194,12 @@ int GetPluginLangByInstance(HINSTANCE hInstance)
int GetPluginFakeId(const MUUID &uuid, int hLangpack)
{
- for (int i=0; i < pluginList.getCount(); i++) {
+ for (int i = 0; i < pluginList.getCount(); i++) {
pluginEntry *p = pluginList[i];
if (!p->bpi.hInst)
continue;
- if ( equalUUID(p->bpi.pluginInfo->uuid, uuid))
+ if (equalUUID(p->bpi.pluginInfo->uuid, uuid))
return p->hLangpack = (hLangpack) ? hLangpack : --sttFakeID;
}
@@ -238,7 +238,7 @@ static int checkPI(BASIC_PLUGIN_INFO* bpi, PLUGININFOEX* pi)
return FALSE;
if (pi->shortName == NULL || pi->description == NULL || pi->author == NULL ||
- pi->authorEmail == NULL || pi->copyright == NULL || pi->homepage == NULL)
+ pi->authorEmail == NULL || pi->copyright == NULL || pi->homepage == NULL)
return FALSE;
return TRUE;
@@ -253,9 +253,9 @@ int checkAPI(TCHAR* plugin, BASIC_PLUGIN_INFO* bpi, DWORD mirandaVersion, int ch
return 0;
// loaded, check for exports
- bpi->Load = (Miranda_Plugin_Load) GetProcAddress(h, "Load");
- bpi->Unload = (Miranda_Plugin_Unload) GetProcAddress(h, "Unload");
- bpi->InfoEx = (Miranda_Plugin_InfoEx) GetProcAddress(h, "MirandaPluginInfoEx");
+ bpi->Load = (Miranda_Plugin_Load)GetProcAddress(h, "Load");
+ bpi->Unload = (Miranda_Plugin_Unload)GetProcAddress(h, "Unload");
+ bpi->InfoEx = (Miranda_Plugin_InfoEx)GetProcAddress(h, "MirandaPluginInfoEx");
// if they were present
if (!bpi->Load || !bpi->Unload || !bpi->InfoEx) {
@@ -264,7 +264,7 @@ LBL_Error:
return 0;
}
- bpi->Interfaces = (MUUID*) GetProcAddress(h, "MirandaInterfaces");
+ bpi->Interfaces = (MUUID*)GetProcAddress(h, "MirandaInterfaces");
if (bpi->Interfaces == NULL) {
typedef MUUID * (__cdecl * Miranda_Plugin_Interfaces) (void);
Miranda_Plugin_Interfaces pFunc = (Miranda_Plugin_Interfaces)GetProcAddress(h, "MirandaPluginInterfaces");
@@ -286,10 +286,10 @@ LBL_Ok:
// check clist ?
if (checkTypeAPI == CHECKAPI_CLIST) {
- bpi->clistlink = (CList_Initialise) GetProcAddress(h, "CListInitialise");
+ bpi->clistlink = (CList_Initialise)GetProcAddress(h, "CListInitialise");
if (pi->flags & UNICODE_AWARE)
- if (bpi->clistlink)
- goto LBL_Ok;
+ if (bpi->clistlink)
+ goto LBL_Ok;
}
goto LBL_Error;
@@ -323,7 +323,7 @@ void Plugin_Uninit(pluginEntry *p)
int Plugin_UnloadDyn(pluginEntry *p)
{
if (p->bpi.hInst) {
- if ( CallPluginEventHook(p->bpi.hInst, hOkToExitEvent, 0, 0) != 0)
+ if (CallPluginEventHook(p->bpi.hInst, hOkToExitEvent, 0, 0) != 0)
return FALSE;
KillModuleSubclassing(p->bpi.hInst);
@@ -354,7 +354,7 @@ int Plugin_UnloadDyn(pluginEntry *p)
// mark default plugins to be loaded
if (!(p->pclass & PCLASS_CORE))
- for (int i=0; i < SIZEOF(pluginDefault); i++)
+ for (int i = 0; i < SIZEOF(pluginDefault); i++)
if (pluginDefault[i].pImpl == p)
pluginDefault[i].pImpl = NULL;
@@ -365,7 +365,7 @@ int Plugin_UnloadDyn(pluginEntry *p)
static int valid_library_name(TCHAR *name)
{
TCHAR *dot = _tcsrchr(name, '.');
- if (dot != NULL && lstrcmpi(dot + 1, _T("dll")) == 0)
+ if (dot != NULL && mir_tstrcmpi(dot + 1, _T("dll")) == 0)
if (dot[4] == 0)
return 1;
@@ -390,8 +390,7 @@ void enumPlugins(SCAN_PLUGINS_CALLBACK cb, WPARAM wParam, LPARAM lParam)
do {
if (!(ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && valid_library_name(ffd.cFileName))
cb(&ffd, exe, wParam, lParam);
- }
- while (FindNextFile(hFind, &ffd));
+ } while (FindNextFile(hFind, &ffd));
FindClose(hFind);
} //if
}
@@ -410,7 +409,7 @@ pluginEntry* OpenPlugin(TCHAR *tszFileName, TCHAR *dir, TCHAR *path)
// map dll into the memory and check its exports
bool bIsPlugin = false;
- mir_ptr<MUUID> pIds( GetPluginInterfaces(tszFullPath, bIsPlugin));
+ mir_ptr<MUUID> pIds(GetPluginInterfaces(tszFullPath, bIsPlugin));
if (!bIsPlugin) {
p->pclass |= PCLASS_FAILED; // piece of shit
return p;
@@ -420,7 +419,7 @@ pluginEntry* OpenPlugin(TCHAR *tszFileName, TCHAR *dir, TCHAR *path)
bool bIsDb = hasMuuid(pIds, miid_database);
if (bIsDb || hasMuuid(pIds, miid_crypto)) {
BASIC_PLUGIN_INFO bpi;
- if ( checkAPI(tszFullPath, &bpi, mirandaVersion, CHECKAPI_NONE)) {
+ if (checkAPI(tszFullPath, &bpi, mirandaVersion, CHECKAPI_NONE)) {
// plugin is valid
p->pclass |= ((bIsDb ? PCLASS_DB : PCLASS_CRYPT) | PCLASS_BASICAPI);
// copy the dblink stuff
@@ -435,19 +434,19 @@ pluginEntry* OpenPlugin(TCHAR *tszFileName, TCHAR *dir, TCHAR *path)
else p->pclass |= PCLASS_FAILED;
}
// plugin declared that it's a contact list. mark it for the future load
- else if ( hasMuuid(pIds, miid_clist)) {
+ else if (hasMuuid(pIds, miid_clist)) {
// keep a note of this plugin for later
clistPlugins.insert(p);
p->pclass |= PCLASS_CLIST;
}
// plugin declared that it's a service mode plugin.
// load it for a profile manager's window
- else if ( hasMuuid(pIds, miid_servicemode)) {
+ else if (hasMuuid(pIds, miid_servicemode)) {
BASIC_PLUGIN_INFO bpi;
if (checkAPI(tszFullPath, &bpi, mirandaVersion, CHECKAPI_NONE)) {
p->pclass |= (PCLASS_OK | PCLASS_BASICAPI);
p->bpi = bpi;
- if ( hasMuuid(bpi, miid_servicemode)) {
+ if (hasMuuid(bpi, miid_servicemode)) {
p->pclass |= (PCLASS_SERVICE);
servicePlugins.insert(p);
}
@@ -461,18 +460,13 @@ pluginEntry* OpenPlugin(TCHAR *tszFileName, TCHAR *dir, TCHAR *path)
void SetPluginOnWhiteList(const TCHAR* pluginname, int allow)
{
- char plugName[MAX_PATH];
- strncpy(plugName, StrConvA(pluginname), SIZEOF(plugName));
- strlwr(plugName);
- db_set_b(NULL, PLUGINDISABLELIST, plugName, allow == 0);
+ db_set_b(NULL, PLUGINDISABLELIST, _strlwr(_T2A(pluginname)), allow == 0);
}
// returns 1 if the plugin should be enabled within this profile, filename is always lower case
int isPluginOnWhiteList(const TCHAR* pluginname)
{
- char* pluginnameA = _strlwr(mir_t2a(pluginname));
- int rc = db_get_b(NULL, PLUGINDISABLELIST, pluginnameA, 0);
- mir_free(pluginnameA);
+ int rc = db_get_b(NULL, PLUGINDISABLELIST, _strlwr(_T2A(pluginname)), 0);
if (rc != 0 && askAboutIgnoredPlugins) {
TCHAR buf[256];
mir_sntprintf(buf, SIZEOF(buf), TranslateT("'%s' is disabled, re-enable?"), pluginname);
@@ -493,7 +487,6 @@ bool TryLoadPlugin(pluginEntry *p, bool bDynamic)
if (slice)
*slice = 0;
- CharLower(p->pluginname);
if (!(p->pclass & (PCLASS_LOADED | PCLASS_DB | PCLASS_CLIST))) {
if (!bDynamic && !isPluginOnWhiteList(p->pluginname))
return false;
@@ -512,8 +505,8 @@ bool TryLoadPlugin(pluginEntry *p, bool bDynamic)
if (p->bpi.Interfaces) {
MUUID *piface = p->bpi.Interfaces;
- for (int i=0; !equalUUID(miid_last, piface[i]); i++) {
- int idx = getDefaultPluginIdx( piface[i] );
+ for (int i = 0; !equalUUID(miid_last, piface[i]); i++) {
+ int idx = getDefaultPluginIdx(piface[i]);
if (idx != -1 && pluginDefault[idx].pImpl) {
if (!bDynamic) { // this place is already occupied, skip & disable
SetPluginOnWhiteList(p->pluginname, 0);
@@ -534,7 +527,7 @@ bool TryLoadPlugin(pluginEntry *p, bool bDynamic)
p->pclass |= PCLASS_LOADED;
if (p->bpi.Interfaces) {
MUUID *piface = p->bpi.Interfaces;
- for (int i=0; !equalUUID(miid_last, piface[i]); i++) {
+ for (int i = 0; !equalUUID(miid_last, piface[i]); i++) {
int idx = getDefaultPluginIdx(piface[i]);
if (idx != -1)
pluginDefault[idx].pImpl = p;
@@ -603,21 +596,20 @@ static bool loadClistModule(TCHAR* exe, pluginEntry *p)
static pluginEntry* getCListModule(TCHAR *exe, TCHAR *slice)
{
- for (int i=0; i < clistPlugins.getCount(); i++) {
+ for (int i = 0; i < clistPlugins.getCount(); i++) {
pluginEntry *p = clistPlugins[i];
mir_sntprintf(slice, &exe[MAX_PATH] - slice, _T("\\Plugins\\%s"), p->pluginname);
- CharLower(p->pluginname);
if (!isPluginOnWhiteList(p->pluginname))
continue;
- if ( loadClistModule(exe, p))
+ if (loadClistModule(exe, p))
return p;
}
MuuidReplacement& stdClist = pluginDefault[11];
- if ( LoadCorePlugin(stdClist)) {
+ if (LoadCorePlugin(stdClist)) {
mir_sntprintf(slice, &exe[MAX_PATH] - slice, _T("\\Core\\%s.dll"), stdClist.stdplugname);
- if ( loadClistModule(exe, stdClist.pImpl))
+ if (loadClistModule(exe, stdClist.pImpl))
return stdClist.pImpl;
}
@@ -626,7 +618,7 @@ static pluginEntry* getCListModule(TCHAR *exe, TCHAR *slice)
int UnloadPlugin(TCHAR* buf, int bufLen)
{
- for (int i = pluginList.getCount()-1; i >= 0; i--) {
+ for (int i = pluginList.getCount() - 1; i >= 0; i--) {
pluginEntry *p = pluginList[i];
if (!_tcsicmp(p->pluginname, buf)) {
GetModuleFileName(p->bpi.hInst, buf, bufLen);
@@ -668,12 +660,12 @@ static int LaunchServicePlugin(pluginEntry *p)
int LoadDefaultServiceModePlugin()
{
- LPCTSTR param = CmdLine_GetOption( _T("svc"));
+ LPCTSTR param = CmdLine_GetOption(_T("svc"));
if (param == NULL || *param == 0)
return SERVICE_CONTINUE;
size_t cbLen = _tcslen(param);
- for (int i=0; i < servicePlugins.getCount(); i++) {
+ for (int i = 0; i < servicePlugins.getCount(); i++) {
pluginEntry *p = servicePlugins[i];
if (!_tcsnicmp(p->pluginname, param, cbLen)) {
int res = LaunchServicePlugin(p);
@@ -771,7 +763,7 @@ int LoadNewPluginsModule(void)
if (clistPlugins.getCount())
MessageBox(NULL, TranslateT("Unable to start any of the installed contact list plugins, I even ignored your preferences for which contact list couldn't load any."), _T("Miranda NG"), MB_OK | MB_ICONERROR);
else
- MessageBox(NULL, TranslateT("Can't find a contact list plugin! You need StdClist or any other contact list plugin.") , _T("Miranda NG"), MB_OK | MB_ICONERROR);
+ MessageBox(NULL, TranslateT("Can't find a contact list plugin! You need StdClist or any other contact list plugin."), _T("Miranda NG"), MB_OK | MB_ICONERROR);
return 1;
}
@@ -800,10 +792,10 @@ static BOOL scanPluginsDir(WIN32_FIND_DATA *fd, TCHAR *path, WPARAM, LPARAM)
{
pluginEntry *p = OpenPlugin(fd->cFileName, _T("Plugins"), path);
if (!(p->pclass & PCLASS_FAILED)) {
- if (pluginList_freeimg == NULL && lstrcmpi(fd->cFileName, _T("advaimg.dll")) == 0)
+ if (pluginList_freeimg == NULL && mir_tstrcmpi(fd->cFileName, _T("advaimg.dll")) == 0)
pluginList_freeimg = p;
- if (pluginList_crshdmp == NULL && lstrcmpi(fd->cFileName, _T("crashdumper.dll")) == 0) {
+ if (pluginList_crshdmp == NULL && mir_tstrcmpi(fd->cFileName, _T("crashdumper.dll")) == 0) {
pluginList_crshdmp = p;
p->pclass |= PCLASS_LAST;
}
@@ -855,7 +847,7 @@ void UnloadNewPluginsModule(void)
UnloadPluginOptions();
// unload everything but the DB
- for (int i = pluginList.getCount()-1; i >= 0; i--) {
+ for (int i = pluginList.getCount() - 1; i >= 0; i--) {
pluginEntry *p = pluginList[i];
if (!(p->pclass & (PCLASS_DB | PCLASS_CRYPT)) && p != pluginList_crshdmp)
Plugin_Uninit(p);
@@ -866,7 +858,7 @@ void UnloadNewPluginsModule(void)
UnloadDatabase();
- for (int k = pluginList.getCount()-1; k >= 0; k--) {
+ for (int k = pluginList.getCount() - 1; k >= 0; k--) {
pluginEntry *p = pluginList[k];
Plugin_Uninit(p);
}