//----------------------------------------------------------------------------- // 描述: 数据包首部初始化 // 参数: // nSeqNumberA - 为0时表示自动增长,否则直接赋值 //----------------------------------------------------------------------------- void CUdpPacketHeader::Init(uint nActionCodeA, uint nSeqNumberA,uint nOrderA) { ZeroBuffer(this, sizeof(CUdpPacketHeader)); nProtoType = PP_UDP; //包的协议 nActionCode = nActionCodeA; //包的动作代码 //包的序列号 if (nSeqNumberA == 0) nSeqNumber = Tracker.GetAllocator().AllocId() + 1; else nSeqNumber = nSeqNumberA; nOrder = nOrderA; nUserIp = StringToIp(GetLocalIp()); //用户IP wUdpPort = TrackerServer.GetLocalPort(); //UDP端口 wTcpPort = PeerTcpServer.GetLocalPort(); //TCP端口 char * UserName = Tracker.GetstrUserName(); char * UserPassword = Tracker.GetstrUserPassword(); strcpy(strUserName,UserName); strcpy(strUserPassword,UserPassword); UpdateCheckSum(); }
uchar Ap_Connect() { int i ,j; int iApCount; int iRet; ST_WIFI_AP WifiAp; ST_WIFI_AP stWifiAps[20]; ST_WIFI_PARAM WifiParam; memset(&WifiAp, 0, sizeof(ST_WIFI_AP)); memset(&WifiParam, 0, sizeof(ST_WIFI_PARAM)); strcpy(WifiAp.Ssid, glSysCtrl.stAppWifiPara.Ssid); WifiAp.SecMode = glSysCtrl.stAppWifiPara.SecMode; WifiParam.DhcpEnable = glSysCtrl.stAppWifiPara.DhcpEnable; if (WifiParam.DhcpEnable == 0) //DHCP 关闭 { StringToIp(glSysCtrl.szLocalIp, WifiParam.Ip); StringToIp(glSysCtrl.szMaskIp, WifiParam.Mask); StringToIp(glSysCtrl.szGateIp, WifiParam.Gate); StringToIp(glSysCtrl.szDnsIp, WifiParam.Dns); } if(WifiAp.SecMode == 1) { strcpy(WifiParam.Wep, glSysCtrl.stAppWifiPara.Wep); } if(WifiAp.SecMode == 2 || WifiAp.SecMode == 3) { strcpy(WifiParam.Wpa, glSysCtrl.stAppWifiPara.Wpa); } for (i=0; i<5; i++) { iRet = WifiCheck(&WifiAp); if (iRet < 0) { iApCount = 15; iRet = WifiScanAps(&stWifiAps[0],iApCount); for (j= 0; j<iRet; j++) { if (memcmp(glSysCtrl.stAppWifiPara.Ssid, stWifiAps[j].Ssid,strlen(glSysCtrl.stAppWifiPara.Ssid)) == 0) { break; } } if (j != iRet && memcmp(glSysCtrl.stAppWifiPara.Ssid, stWifiAps[j].Ssid,strlen(glSysCtrl.stAppWifiPara.Ssid)) == 0 ) { iRet = WifiConnectAp(&stWifiAps[j],&WifiParam); if (iRet != 0) { return -1; } break; } else continue; } } while (1) { iRet = WifiCheck(&WifiAp); if (iRet > 0) { break; } else if(iRet == 0) { continue; } else { return iRet; } } return 0; }
//登陆WIFI 热点 int WifiApLogin(void) { int iRet; uchar ucTempBuf[20]; ST_WIFI_AP WifiAp; ST_WIFI_PARAM WifiParam; memset(&WifiAp, 0, sizeof(ST_WIFI_AP)); memset(&WifiParam, 0, sizeof(ST_WIFI_PARAM)); strcpy(WifiAp.Ssid, glSysCtrl.stAppWifiPara.Ssid); WifiAp.SecMode = glSysCtrl.stAppWifiPara.SecMode; WifiParam.DhcpEnable = glSysCtrl.stAppWifiPara.DhcpEnable; if (WifiParam.DhcpEnable == 0) //DHCP 关闭 { memset(ucTempBuf, 0, sizeof(ucTempBuf)); StringToIp(glSysCtrl.szLocalIp, WifiParam.Ip); StringToIp(glSysCtrl.szMaskIp, WifiParam.Mask); StringToIp(glSysCtrl.szGateIp, WifiParam.Gate); StringToIp(glSysCtrl.szDnsIp, WifiParam.Dns); } if(WifiAp.SecMode == 1) { strcpy(WifiParam.Wep, glSysCtrl.stAppWifiPara.Wep); } if(WifiAp.SecMode == 2 || WifiAp.SecMode == 3) { strcpy(WifiParam.Wpa, glSysCtrl.stAppWifiPara.Wpa); } iRet = WifiCheck(&WifiAp); if(iRet > 0) { return 0; } iRet = WifiConnectAp(&WifiAp, &WifiParam); if(iRet != 0) { return iRet; } while (1) { iRet = WifiCheck(&WifiAp); if (iRet > 0) { break; } else if(iRet == 0) { continue; } else { return iRet; } } if(glSysCtrl.stAppWifiPara.DhcpEnable) { NetDevGet(12, glSysCtrl.szLocalIp, glSysCtrl.szMaskIp, glSysCtrl.szGateIp, glSysCtrl.szDnsIp); } glConnectFlag = 1; return 0; }
void NetworkPanel::OnSendCommandClick(wxCommandEvent& event) { wxPropertyGridPage* pg=m_PropCommand->GetPage(0); wxPropertyGridIterator it; u_char* pCommandData=new u_char[1024]; memset(pCommandData,0,1024); memcpy(pCommandData,"CMD_DATA",8); u_int32_t nCommandSize=1024; memcpy(pCommandData+8,&nCommandSize,4); bool bIPSet=false; bool bSendCommand=false; for ( it = pg->GetIterator(); !it.AtEnd(); it++ ) { wxPGProperty* p = *it; if(!p->HasFlag(wxPG_PROP_MODIFIED)) continue; memcpy(pCommandData+12,&g_nNetCommandNum,4); //Номер командного блока (Относительно момента инициализации камеры) g_nNetCommandNum++; u_int16_t nData=(u_int16_t)(u_int32_t)p->GetClientData(); wxAny val=p->GetValue(); switch(nData) { case 0x8024: //Остановить считывание кадров { if(val.As<bool>()) { memcpy(pCommandData+16,&nData,2); p->SetValue(false); bSendCommand=true; } else bSendCommand=false; } break; //2 байта целое case 0x0010: //Установить время экспозиции case 0x2110: //Установить смещение уровня черного в АЦП { memcpy(pCommandData+16,&nData,2); u_int16_t wVal=val.As<int>(); memcpy(pCommandData+18,&wVal,2); bSendCommand=true; } break; case 0x1011: //Установить количество строк интегрирования { memcpy(pCommandData+16,&nData,2); u_char btVal=(u_char)val.As<int>(); if(nData==0x1011) { switch(btVal) { case 0: btVal=4; break; case 1: btVal=16; break; case 2: btVal=32; break; case 3: btVal=64; break; case 4: btVal=96; break; } p->SetValue(""); } memcpy(pCommandData+18,&btVal,1); bSendCommand=true; } break; case 0x8124: //Запустить считывание кадров { memcpy(pCommandData+16,&nData,2); u_int32_t dwVal=val.As<int>(); memcpy(pCommandData+20,&dwVal,4); bSendCommand=true; } break; //2 байта 8.8 case 0x2010: //Установить аналоговое усиление в АЦП case 0x8240: //Установить EM-усиление case 0x1010: //Установить скорость вертикального переноса { memcpy(pCommandData+16,&nData,2); float fVal=val.As<float>(); u_int16_t wVal=(u_int16_t)(fVal*256); memcpy(pCommandData+18,&wVal,2); bSendCommand=true; } break; case 0x4012: //Задать темп считывания { memcpy(pCommandData+16,&nData,2); u_char btData=p->GetChoiceSelection(); memcpy(pCommandData+18,&btData,1); p->SetValue(""); bSendCommand=true; } break; case 0x8011: //Выбрать выход матрицы с EM-усилением case 0x8022: //Выключить камеру case 0x8016: //Включить охлаждение { u_int16_t wData=p->GetChoiceSelection()==0?nData:nData+0x100; memcpy(pCommandData+16,&wData,2); p->SetValue(""); bSendCommand=true; } break; case 0x6010: //Задать координаты начала фрагмента case 0x6110: //Задать размер фрагмента { memcpy(pCommandData+16,&nData,2); wxPoint pointVal=val.As<wxPoint>(); u_int16_t wVal=(u_int16_t)pointVal.x; memcpy(pCommandData+18,&wVal,2); wVal=(u_int16_t)pointVal.y; memcpy(pCommandData+20,&wVal,2); bSendCommand=true; } break; case 0x9212: //Установить величину биннинга { memcpy(pCommandData+16,&nData,2); wxPoint pointVal=val.As<wxPoint>(); u_char cVal=(u_char)pointVal.x; memcpy(pCommandData+18,&cVal,1); cVal=(u_char)pointVal.y; memcpy(pCommandData+19,&cVal,1); bSendCommand=true; } break; case 0x8080: //Установить новые IP-адреса { if(!bIPSet) { memcpy(pCommandData+16,&nData,2); wxPGProperty* pIPProp=pg->GetProperty("IP-адрес камеры"); wxString sVal=pIPProp->GetDisplayedString(); u_char pIP[4],pIPr[4]; if(StringToIp(sVal,pIPr)) { pIP[3]=pIPr[0]; pIP[2]=pIPr[1]; pIP[1]=pIPr[2]; pIP[0]=pIPr[3]; } memcpy(pCommandData+18+2,pIP,4); u_int16_t wVal=(u_int16_t)pg->GetPropertyValueAsInt("Порт камеры (в. п.)"); memcpy(pCommandData+18+14,&wVal,2); // pIPProp=pg->GetProperty("IP-адрес СУ-С"); // sVal=pIPProp->GetDisplayedString(); // StringToIp(sVal,pIP); // memcpy(pCommandData+28,pIP,4); // wVal=(u_int16_t)pg->GetPropertyValueAsInt("Порт СУ-С"); // memcpy(pCommandData+32,&wVal,2); // pIPProp=pg->GetProperty("IP-адрес техн. ПКВИ"); // sVal=pIPProp->GetDisplayedString(); // StringToIp(sVal,pIP); // memcpy(pCommandData+36,pIP,4); wVal=(u_int16_t)pg->GetPropertyValueAsInt("Порт камеры (н. п.)"); memcpy(pCommandData+18+22,&wVal,2); bIPSet=true; bSendCommand=true; } else bSendCommand=false; } break; case 0x0080: //Сообщить состояние if(val.As<bool>()) { memcpy(pCommandData+16,&nData,2); p->SetValue(false); bSendCommand=true; } else bSendCommand=false; break; } if(bSendCommand) g_pFrame->SendCommand(pCommandData); p->SetModifiedStatus(false); pg->RefreshProperty(p); } delete pCommandData; }
int HandleNetoidLkup(Command *comm, int argc, char **argv) { CacheTableInfo *cacheInfo; CacheTableEntry *cacheHandle; char fn[] = "HandleNetoidLkup():"; unsigned long pkey; RealmIP realmip; RealmSubnet realmsub; char *sphone = 0, *url = 0, *tg = 0; int shmId, i; char *regid, *port; char *realmNamei, lkupip=0; PhoNode phonode = { 0 }; int release_lock = 0; /* Lookup in the LUS's cache and VPNS's cache */ if (argc < 1) { /* Here we prompt the user for the rest of the * information */ HandleCommandUsage(comm, argc, argv); return -xleInsuffArgs; } tg = url = sphone = argv[0]; if ((shmId = CacheAttach()) == -1) { CLIPRINTF((stdout, "Unable to attach to GIS cache\n")); } else if (argc == 1) { InitCfgFromCfgParms(lsMem->cfgParms); realmip.ipaddress = StringToIp(sphone); realmip.realmId = 0; lkupip = (realmip.ipaddress? 1 : 0); CacheGetLocks(regCache, LOCK_WRITE, LOCK_BLOCK); release_lock = 1; cacheInfo = CacheGet(phoneCache, sphone); if (cacheInfo) { CLIPRINTF((stdout, "Phone Match:\n")); PrintInfoEntry(stdout, &cacheInfo->data); } cacheInfo = CacheGet(vpnPhoneCache, sphone); if (cacheInfo) { CLIPRINTF((stdout, "Vpn Phone Match:\n")); PrintInfoEntry(stdout, &cacheInfo->data); } /* do a reg-id lookup */ memset(&phonode, 0, sizeof(PhoNode)); strncpy(phonode.regid, sphone, REG_ID_LEN); cacheInfo = CacheGet(regidCache, &phonode); if (cacheInfo) { CLIPRINTF((stdout, "Reg Id Match:\n")); PrintInfoEntry(stdout, &cacheInfo->data); /* Print some information relevent only to the * regid cache entry */ fprintf(stdout, "\tNo of ports configured = %d \n\t[", cacheInfo->data.ncfgports); for (i=0; i<MAX_IEDGE_PORTS; i++) { if (BITA_TEST(cacheInfo->data.cfgports, i)) { fprintf(stdout, " %d", i); } } fprintf(stdout, " ]\n\n"); } /* do a url lookup */ cacheInfo = CacheGet(uriCache, url); if (cacheInfo) { CLIPRINTF((stdout, "Url Match:\n")); PrintInfoEntry(stdout, &cacheInfo->data); } // h323id cache cacheInfo = CacheGet(h323idCache, sphone); if (cacheInfo) { CLIPRINTF((stdout, "H323 ID Match:\n")); PrintInfoEntry(stdout, &cacheInfo->data); } /* do a tg lookup */ cacheInfo = CacheGet(tgCache, tg); if (cacheInfo) { CLIPRINTF((stdout, "TG Match:\n")); PrintInfoEntry(stdout, &cacheInfo->data); } } else if (argc == 2) { InitCfgFromCfgParms(lsMem->cfgParms); CacheGetLocks(regCache, LOCK_WRITE, LOCK_BLOCK); release_lock = 1; /* Do a reg-id uport lkup also, in the end */ strncpy(phonode.regid, argv[0], REG_ID_LEN); phonode.uport = atoi(argv[1]); cacheInfo = CacheGet(regCache, &phonode); if (cacheInfo) { CLIPRINTF((stdout, "Reg Id/Uport Match:\n")); PrintInfoEntry(stdout, &cacheInfo->data); } /* Look up this ip address in our cache */ realmip.ipaddress = StringToIp(argv[0]); realmip.realmId = realmNameToRealmId(argv[1]); if (realmip.ipaddress && realmip.realmId) { lkupip = 1; } } if (lkupip) { cacheInfo = CacheGet(ipCache, &realmip); if (cacheInfo) { CLIPRINTF((stdout, "IP/Realm Match:\n")); PrintInfoEntry(stdout, &cacheInfo->data); /* Print some information relevent only to the * ip cache entry */ fprintf(stdout, "\tNo of ports registered = %d \n\t[", cacheInfo->data.nports); for (i=0; i<MAX_IEDGE_PORTS; i++) { if (BITA_TEST(cacheInfo->data.ports, i)) { fprintf(stdout, " %d", i); } } fprintf(stdout, " ]\n\n"); } // Also lookup in subnets realmsub.subnetip = realmip.ipaddress; realmsub.realmId = realmip.realmId; cacheInfo = GetIedgeLongestMatch(&realmsub); if (cacheInfo) { CLIPRINTF((stdout, "Longest Match:\n")); PrintInfoEntry(stdout, &cacheInfo->data); } } if(release_lock) { CacheReleaseLocks(regCache); } CacheDetach(); return xleOk; }
int LoadParaTerm(void) { XINREF pf; char str[100]; int i; struct hostent *mast_host; struct in_addr *sin_addr; DebugPrint(0, " load param term..."); DebugPrint(0, " sizeof(term)=%d\r\n",sizeof(para_term_tG)); LoadDefParaTerm(); if(getuciConfigvar("sn",str) == 0) { PrintLog(0,"SN:%s\n",str); ParaTermG.deviceid[0] = str[0]-0x30; ParaTermG.deviceid[1] = str[1]-0x30; ParaTermG.deviceid[2] = str[2]-0x30; ParaTermG.deviceid[3] = str[3]-0x30; ParaTermG.deviceid[4] = str[4]-0x30; ParaTermG.deviceid[5] = str[5]-0x30; ParaTermG.deviceid[6] = str[6]-0x30; ParaTermG.deviceid[7] = str[7]-0x30; } if(getuciConfigvar("firststart",str) == 0) { ParaTermG.first_start = str[0]-0x30; } if(getuciConfigvar("musicmonth",str) == 0) { ParaTermG.Musicmonth = str[0]-0x30; } if(getuciConfigvar("master_addr",str) == 0) { PrintLog(0,"master_addr:%s\n",str); mast_host = gethostbyname(str); if(mast_host != NULL) { PrintLog(0,"Master IP Address :%s\n",inet_ntoa(*((struct in_addr *)mast_host->h_addr))); PrintLog(0,"Master HostName :%s\n",mast_host->h_name); sin_addr = (struct in_addr *)mast_host->h_addr; memcpy(ParaTermG.svraddr.net.ip,&sin_addr->s_addr,4); //ParaTermG.svraddr.net.ip[0] = sin_addr->s_addr.s_b1; //ParaTermG.svraddr.net.ip[1] = sin_addr->s_addr.s_b2; //ParaTermG.svraddr.net.ip[2] = sin_addr->s_addr.s_b3; //ParaTermG.svraddr.net.ip[3] = sin_addr->S_un_b.s_b4; } } if(getuciConfigvar("master_port",str) == 0) { PrintLog(0,"master_port:%s\n",str); ParaTermG.svraddr.net.port = atoi(str); } PrintLog(0,"music_volume:%s\n",str); if(getuciConfigvar("music_volume",str) == 0) { PrintLog(0,"music_volume:%s\n",str); ParaTermG.music_volume = atoi(str); setvolume(ParaTermG.music_volume); } else { PrintLog(0,"music_volume:%s\n",str); ParaTermG.music_volume = 20; setvolume(ParaTermG.music_volume); } sprintf(str,"ParaTermG.device_code = %s\n",ParaTermG.device_code); load_hardinfo(); pf = XinOpen(PARAM_SAVE_PATH "/term.xin", 'r'); if(NULL == pf) { pf = XinOpen(PARAM_BAK_PATH "/term.xin", 'r'); if(NULL == pf) { DebugPrint(0, "no file\n"); // SaveParaTerm(); return 1; } } /*读主站IP*/ ParaTermG.svraddr.net.chn = XinReadInt(pf, "svraddrflag",0x04);//读上行连接方式 if(XinReadString(pf, "svraddrIp", str, 24) > 0) { StringToIp(str, ParaTermG.svraddr.net.ip); } ParaTermG.svraddr.net.port = XinReadInt(pf, "svrport", 8300); /*读主站2IP*/ ParaTermG.svraddr_1.net.chn = XinReadInt(pf, "svraddrflag1",0x04);//读上行连接方式 if(XinReadString(pf, "svraddrIp1", str, 24) > 0) { StringToIp(str, ParaTermG.svraddr_1.net.ip); } ParaTermG.svraddr_1.net.port = XinReadInt(pf, "svrport1", 9001); /*读主站3IP*/ ParaTermG.svraddr_2.net.chn = XinReadInt(pf, "svraddrflag2",0x04);//读上行连接方式 if(XinReadString(pf, "svraddrIp2", str, 24) > 0) { StringToIp(str, ParaTermG.svraddr_2.net.ip); } ParaTermG.svraddr_2.net.port = XinReadInt(pf, "svrport2", 9001); /*读网关地址*/ if(XinReadString(pf, "gateaddr", str, 24) > 0) { StringToIp(str, ParaTermG.gate_addr.net.ip); } /*by ydl add 2011-03-21*/ ParaTermG.gate_addr.net.port = XinReadInt(pf, "gateport", 9001); /*读短信中心号码*/ //XinReadHex(pf, "smsaddr", str,16); int rtn; rtn = XinReadHex(pf, "smsaddr", (unsigned char *)str, 8); if (rtn != -1) { sms_phone_tonormal(rtn, (unsigned char *)str, ParaTermG.sms_addr); } XinReadString(pf, "apn", ParaTermG.apn,16); /*by ydl modify 2011-05-15*/ XinReadString( pf, "cdmausr", ParaTermG.cdma_usr,32 ); XinReadString(pf, "cdmapwd", ParaTermG.cdma_pwd, 32); XinReadHex(pf, "norpwd", ParaTermG.nor_pwd, 3);//普通密码 XinReadHex(pf, "compwd", ParaTermG.com_pwd, 3);//设置密码 XinReadHex(pf, "admpwd", ParaTermG.adm_pwd,3);//管理员密码 /*默认振铃次数*/ ParaTermG.search_device = XinReadInt( pf, "search_device", 0); /*任务开始时间*/ ParaTermG.task_starthour = XinReadInt(pf, "taskstarthour", 0x01); /*任务执行间隔*/ ParaTermG.task_startdev = XinReadInt(pf, "taskstartdev", 0x01);//间隔一小时 /*默认载波中继方式*/ ParaTermG.plc_route_type = XinReadInt( pf, "plcroutetype", 0x00);//自动中继 /*默认线损阀值*/ XinReadHex( pf, "gatelinewaste",ParaTermG.gate_linewaste, 2);// 1表示0.1% /*重点用户数据上传时间*///保存为BCD码例如,如果是12点,则保存的是12而不是0x12 ParaTermG.hour_upimpdata = XinReadInt( pf, "hourupimpdata", 0xFF);//不主动上传 /*日冻结上传时间*/ ParaTermG.hour_updaydata = XinReadInt( pf, "hourupdaydata", 0xFF);//不主动上传 /*告警使能控制字*/ ParaTermG.alarm_flag = XinReadInt( pf, "alarmflag", 0);//不告警 /*级联从终端地址*/ //XinReadHex(pf, "cascadeaddr", ParaTermG.cascade_addr, 16); unsigned char tmpbuf[16]; XinReadHex(pf, "cascadeaddr", tmpbuf, 16); Cascade_AddrChange(tmpbuf, ParaTermG.cascade_addr,1); //加载注册信息 ParaTermG.reg.autoflag = XinReadInt( pf, "AutoFlag", 0x01); //检查注册码是不是本机使用的 XinReadString(pf,"RegeCode",ParaTermG.reg.register_code,13); char tempregcode[13]; MakeRegisteCode(tempregcode); if(strcmp(ParaTermG.reg.register_code,tempregcode) == 0) //注册验证成功 { ParaTermG.reg.autoflag = 1; } else { ParaTermG.reg.autoflag = 0; } ParaTermG.reg.autoflag = 1; /*级联标记*/ ParaTermG.cascade_flag = XinReadInt( pf, "cascadeflag", 1);//默认为主集中器,且不允许级联 /*月末数据抄收开始时间*/ ParaTermG.day_read_mondata = XinReadInt( pf, "dayreadmondata", 0x01);//一号开始冻结 /*月末数据抄收开始时间*/ ParaTermG.hour_read_mondata = XinReadInt( pf, "hourreadmondata", 0x01);// 1点 /*月冻结上传开始时间*/ ParaTermG.day_up_mondata = XinReadInt( pf, "dayupmondata", 0x03); // 3号 ParaTermG.hour_up_mondata = XinReadInt( pf, "hourupmondata", 0x05);//5点上传 // printf("day_mont=%d,hour_mont=%d",ParaTermG.day_read_mondata,ParaTermG.hour_read_mondata); // printf("day_up_mont=%d,hour_up_mont=%d",ParaTermG.day_up_mondata,ParaTermG.hour_up_mondata); XinReadHex(pf,"peibian_addr",tmpbuf,4); Cascade_AddrChange(tmpbuf,ParaTermG.peibian_addr,0); XinReadHex(pf, "ct", ParaTermG.ct, 2);//配变CT for(i=0;i<MAX_485PORT;i++){ sprintf((char *)tmpbuf,"baud%d",i); ParaTermG.port[i].baud = XinReadInt(pf, (char *)tmpbuf, 4); //默认为1200 sprintf((char *)tmpbuf,"databits%d",i); ParaTermG.port[i].databits = XinReadInt(pf, (char *)tmpbuf, 8);//默认为8 sprintf((char *)tmpbuf,"stopbits%d",i); ParaTermG.port[i].stopbits = XinReadInt(pf, (char *)tmpbuf, 1);//默认为1 sprintf((char *)tmpbuf,"parity%d",i); ParaTermG.port[i].parity = XinReadInt(pf, (char *)tmpbuf, 1);//校验位 sprintf((char *)tmpbuf,"func%d",i); ParaTermG.port[i].func= XinReadInt(pf, (char *)tmpbuf, i);//端口功能 } DebugPrint(0, "ok\n"); XinClose(pf); return 0; }