void tst_QHostAddress::constructor_QString() { QFETCH(QString, address); QFETCH(bool, ok); QFETCH(int, protocol); QHostAddress hostAddr(address); if (address == "0.0.0.0" || address == "::") { QVERIFY(ok); } else { QVERIFY(hostAddr.isNull() != ok); } if (ok) QTEST(hostAddr.toString(), "resAddr"); if ( protocol == 4 ) { QVERIFY( hostAddr.protocol() == QAbstractSocket::IPv4Protocol || hostAddr.protocol() == QAbstractSocket::UnknownNetworkLayerProtocol ); QVERIFY( hostAddr.protocol() != QAbstractSocket::IPv6Protocol ); } else if ( protocol == 6 ) { QVERIFY( hostAddr.protocol() != QAbstractSocket::IPv4Protocol && hostAddr.protocol() != QAbstractSocket::UnknownNetworkLayerProtocol ); QVERIFY( hostAddr.protocol() == QAbstractSocket::IPv6Protocol ); } else { QVERIFY( hostAddr.isNull() ); QVERIFY( hostAddr.protocol() == QAbstractSocket::UnknownNetworkLayerProtocol ); } }
/* * 不用指定端口 * 如果openOnIP指定了,则会将套接字绑定到该端口和IP地址 * */ bool RobotSocket::findValidPort(int startPort, const char *openOnIP) { //char localhost[maxHostNameLen()]; for (int i=0; i+startPort < 65000; ++i) { bzero(&mySin, sizeof(mySin)); setIPString(); if (openOnIP != NULL) { if (!hostAddr(openOnIP, mySin.sin_addr)) { return(false); } else { //printf("Opening on %s\n", openOnIP); } } else { mySin.sin_addr.s_addr=htonl(INADDR_ANY); } mySin.sin_family=AF_INET; mySin.sin_port=hostToNetOrder(startPort+i); if (bind(myFD, (struct sockaddr *)&mySin, sizeof(mySin)) == 0) break; } return(true); }
void CNetworkClient::run() { while(1) { { QMutexLocker lock( &m_mutex ); QHostAddress hostAddr( m_ip ); if ( !m_socket->isOpen () || !(m_socket->state() == QAbstractSocket::ConnectedState) ) { m_socket->connectToHost( hostAddr, m_port ); if ( !m_socket->waitForConnected( m_timeout ) ) { return; } } write(); read(); } MilliSleep( m_sleepTime ); { // how to exit 100% safe, this is not the way to go for sure QMutexLocker lock( &m_mutex ); if ( dropConnection() ) { m_socket->disconnectFromHost(); break; } } } }
bool ArSocket::connectTo(const char *host, int port) { char localhost[100]; // maxHostNameLen()]; if (myFD < 0) return(false); if (!host) { if (gethostname(localhost, sizeof(localhost)) == 1) { myErrorStr="Failure to locate host '"; myErrorStr+=localhost; myErrorStr+="'"; perror("gethostname"); return(false); } host=localhost; } bzero(&mySin, sizeof(mySin)); if (!hostAddr(host, mySin.sin_addr)) return(false); setIPString(); mySin.sin_family=AF_INET; mySin.sin_port=hostToNetOrder(port); return(connectTo(&mySin)); }
void CNetworkConnection::connectToHost(IPv4_ENDPOINT oAddress) { QHostAddress hostAddr(oAddress.ip); m_oAddress = oAddress; m_bInitiated = true; m_bConnected = false; m_tConnected = time(0); Q_ASSERT(m_pInput == 0); Q_ASSERT(m_pOutput == 0); m_pInput = new QByteArray(); m_pOutput = new QByteArray(); Q_ASSERT(m_pSocket == 0); m_pSocket = new QTcpSocket(); initializeSocket(); //m_pSocket->connectToHost(hostAddr, m_oAddress.port); QTcpSocket::connectToHost(hostAddr, m_oAddress.port); /*qDebug() << "connectToHost - object dump"; m_pSocket->dumpObjectInfo(); dumpObjectInfo(); qDebug() << "--- end of dump ---";*/ }
AREXPORT bool ArSocket::connectTo(const char *host, int port) { char localhost[MAXGETHOSTSTRUCT]; if (myFD < 0) return(false); if (!host) { if (gethostname(localhost, sizeof(localhost)) == 1) { myErrorStr="Failure to locate host '"; myErrorStr+=localhost; myErrorStr+="'"; perror("gethostname"); return(false); } host=localhost; } memset(&mySin, 0, sizeof(mySin)); if (!hostAddr(host, mySin.sin_addr)) return(false); setIPString(); mySin.sin_family=AF_INET; mySin.sin_port=hostToNetOrder(port); return(connectTo(&mySin)); }
/** @return false and set error code and description string on failure */ bool ArSocket::connectTo(const char *host, int port) { char localhost[maxHostNameLen()]; myError = NoErr; myErrorStr.clear(); if (myFD < 0) return(false); if (!host) { if (gethostname(localhost, sizeof(localhost)) == 1) { myErrorStr="Failure to locate host '"; myErrorStr+=localhost; myErrorStr+="'"; perror("gethostname"); return(false); } host=localhost; } char useHost[1024]; int usePort; separateHost(host, port, useHost, sizeof(useHost), &usePort); bzero(&mySin, sizeof(mySin)); if (!hostAddr(useHost, mySin.sin_addr)) return(false); setRawIPString(); mySin.sin_family=AF_INET; mySin.sin_port=hostToNetOrder(usePort); return(connectTo(&mySin)); }
void CNetwork::AcquireLocalAddress(QString& sHeader) { CEndPoint hostAddr(sHeader + ":0"); if(!hostAddr.isNull()) { m_oAddress.setAddress(sHeader); } }
void CNetwork::acquireLocalAddress(QString& sHeader) { CEndPoint hostAddr(sHeader, m_oAddress.port()); if(hostAddr.isValid()) { if( hostAddr != m_oAddress ) { m_oAddress = hostAddr; emit localAddressChanged(); } } }
bool ArSocket::findValidPort(int startPort, const char *openOnIP) { // char localhost[100]; // maxHostNameLen()]; /* if (gethostname(localhost, sizeof(localhost)) == 1) { myErrorStr="Failure to locate localhost"; perror("gethostname"); return(false); } */ for (int i=0; i+startPort < 65000; ++i) { bzero(&mySin, sizeof(mySin)); /* if (!hostAddr(localhost, mySin.sin_addr) && !hostAddr("localhost", mySin.sin_addr)) return(false); */ setIPString(); if (openOnIP != NULL) { if (!hostAddr(openOnIP, mySin.sin_addr)) { ArLog::log(ArLog::Normal, "Couldn't find ip of %s to open udp on", openOnIP); return(false); } else { //printf("Opening on %s\n", openOnIP); } } else { mySin.sin_addr.s_addr=htonl(INADDR_ANY); } mySin.sin_family=AF_INET; mySin.sin_port=hostToNetOrder(startPort+i); if (bind(myFD, (struct sockaddr *)&mySin, sizeof(mySin)) == 0) break; } return(true); }
/** @return false on failure */ AREXPORT bool ArSocket::findValidPort(int startPort, const char *openOnIP) { /* char localhost[MAXGETHOSTSTRUCT]; if (gethostname(localhost, sizeof(localhost)) == 1) { myErrorStr="Failure to locate localhost"; ArLog::logErrorFromOS(ArLog::Normal, "ArSocket::findValidPort: gethostname failed"); return(false); } */ for (int i=0; i+startPort < 65000; ++i) { memset(&mySin, 0, sizeof(mySin)); /* if (!hostAddr(localhost, mySin.sin_addr)) return(false); */ setRawIPString(); if (openOnIP != NULL) { if (!hostAddr(openOnIP, mySin.sin_addr)) { ArLog::log(ArLog::Normal, "Couldn't find ip of %s to open on", openOnIP); return(false); } else { //printf("Opening on %s\n", openOnIP); } } else { mySin.sin_addr.s_addr=htonl(INADDR_ANY); } mySin.sin_family=AF_INET; //mySin.sin_addr.s_addr=htonl(INADDR_ANY); mySin.sin_port=hostToNetOrder(startPort+i); if (bind(myFD, (struct sockaddr *)&mySin, sizeof(mySin)) == 0) break; } return(true); }
/** @return false and set error code and description string on failure */ AREXPORT bool ArSocket::connectTo(const char *host, int port) { char localhost[MAXGETHOSTSTRUCT]; myError = NoErr; myErrorStr.clear(); if (myFD == INVALID_SOCKET) return(false); if (!host) { if (gethostname(localhost, sizeof(localhost)) == 1) { myErrorStr="Failure to locate host '"; myErrorStr+=localhost; myErrorStr+="'"; myError = ConBadHost; ArLog::logErrorFromOS(ArLog::Normal, "ArSocket::connectTo: gethostname failed"); return(false); } host=localhost; } char useHost[1024]; int usePort; separateHost(host, port, useHost, sizeof(useHost), &usePort); //myHost = ((host != NULL) ? host : ""); //myPort = port; myHost = useHost; myPort = usePort; memset(&mySin, 0, sizeof(mySin)); if (!hostAddr(useHost, mySin.sin_addr)) { myError = ConBadHost; return(false); } setRawIPString(); mySin.sin_family=AF_INET; mySin.sin_port=hostToNetOrder(usePort); return(connectTo(&mySin)); }
/*! Returns the raw form of this QNetworkCookie. The QByteArray returned by this function is suitable for an HTTP header, either in a server response (the Set-Cookie header) or the client request (the Cookie header). You can choose from one of two formats, using \a form. \sa parseCookies() */ QByteArray QNetworkCookie::toRawForm(RawForm form) const { QByteArray result; if (d->name.isEmpty()) return result; // not a valid cookie result = d->name; result += '='; result += d->value; if (form == Full) { // same as above, but encoding everything back if (isSecure()) result += "; secure"; if (isHttpOnly()) result += "; HttpOnly"; if (!isSessionCookie()) { result += "; expires="; result += QLocale::c().toString(d->expirationDate.toUTC(), QLatin1String("ddd, dd-MMM-yyyy hh:mm:ss 'GMT")).toLatin1(); } if (!d->domain.isEmpty()) { result += "; domain="; if (d->domain.startsWith(QLatin1Char('.'))) { result += '.'; result += QUrl::toAce(d->domain.mid(1)); } else { QHostAddress hostAddr(d->domain); if (hostAddr.protocol() == QAbstractSocket::IPv6Protocol) { result += '['; result += d->domain.toUtf8(); result += ']'; } else { result += QUrl::toAce(d->domain); } } } if (!d->path.isEmpty()) { result += "; path="; result += d->path.toUtf8(); } } return result; }
/** @return false and set error code and description string on failure */ bool ArSocket::connect(const char *host, int port, Type type, const char *openOnIP) { char localhost[maxHostNameLen()]; myError=NoErr; myErrorStr.clear(); if (!host) { if (gethostname(localhost, sizeof(localhost)) == 1) { myError=ConBadHost; myErrorStr="Failure to locate host '"; myErrorStr+=localhost; myErrorStr+="'"; perror("gethostname"); return(false); } host=localhost; } bzero(&mySin, sizeof(mySin)); // MPL taking out this next code line from the if since it makes // everything we can't resolve try to connect to localhost // && !hostAddr("localhost", mySin.sin_addr)) char useHost[1024]; int usePort; separateHost(host, port, useHost, sizeof(useHost), &usePort); if (!hostAddr(useHost, mySin.sin_addr)) return(false); setRawIPString(); mySin.sin_family=AF_INET; mySin.sin_port=hostToNetOrder(usePort); if ((type == TCP) && ((myFD=socket(AF_INET, SOCK_STREAM, 0)) < 0)) { myError=NetFail; myErrorStr="Failure to make TCP socket"; perror("socket"); return(false); } else if ((type == UDP) && ((myFD=socket(AF_INET, SOCK_DGRAM, 0)) < 0)) { myError=NetFail; myErrorStr="Failure to make UDP socket"; perror("socket"); return(false); } ArUtil::setFileCloseOnExec(myFD); if (openOnIP != NULL) { struct sockaddr_in outSin; if (!hostAddr(openOnIP, outSin.sin_addr)) { myError = NameLookup; myErrorStr = "Name lookup failed"; ArLog::log(ArLog::Normal, "Couldn't find ip of %s to open on", openOnIP); return(false); } outSin.sin_family=AF_INET; outSin.sin_port=hostToNetOrder(0); if (bind(myFD, (struct sockaddr *)&outSin, sizeof(outSin)) < 0) { ArLog::log(ArLog::Normal, "Failure to bind socket to port %d", 0); perror("socket"); return(false); } } myType=type; if (::connect(myFD, (struct sockaddr *)&mySin, sizeof(struct sockaddr_in)) < 0) { myErrorStr="Failure to connect socket"; switch (errno) { case ECONNREFUSED: myError=ConRefused; myErrorStr+="; Connection refused"; break; case ENETUNREACH: myError=ConNoRoute; myErrorStr+="; No route to host"; break; default: myError=NetFail; break; } //perror("connect"); ::close(myFD); myFD = -1; return(false); } return(true); }
AREXPORT bool ArSocket::open(int port, Type type, const char *openOnIP) { int ret; char localhost[MAXGETHOSTSTRUCT]; if ((type == TCP) && ((myFD=socket(AF_INET, SOCK_STREAM, 0)) < 0)) { ret=WSAGetLastError(); myErrorStr="Failure to make TCP socket"; perror("socket"); return(false); } else if ((type == UDP) && ((myFD=socket(AF_INET, SOCK_DGRAM, 0)) < 0)) { myErrorStr="Failure to make UDP socket"; perror("socket"); return(false); } /* MPL this is useless withw hat I Took out below if (gethostname(localhost, sizeof(localhost)) == 1) { myErrorStr="Failure to locate localhost"; perror("gethostname"); return(false); } */ memset(&mySin, 0, sizeof(mySin)); /* MPL took this out since it was just overriding it with the INADDR_ANY anyways and it could cause slowdowns if a machine wasn't configured so lookups are quick if (!hostAddr(localhost, mySin.sin_addr)) return(false); */ setIPString(); if (openOnIP != NULL) { if (!hostAddr(openOnIP, mySin.sin_addr)) { ArLog::log(ArLog::Normal, "Couldn't find ip of %s to open on", openOnIP); return(false); } else { //printf("Opening on %s\n", openOnIP); } } else { mySin.sin_addr.s_addr=htonl(INADDR_ANY); } mySin.sin_family=AF_INET; mySin.sin_port=hostToNetOrder(port); myType=type; if ((ret=bind(myFD, (struct sockaddr *)&mySin, sizeof(mySin))) < 0) { myErrorStr="Failure to bind socket to port "; sprintf(localhost, "%d", port); myErrorStr+=localhost; perror("socket"); return(false); } if ((type == TCP) && (listen(myFD, 5) < 0)) { myErrorStr="Failure to listen on socket"; perror("listen"); return(false); } return(true); }
AREXPORT bool ArSocket::connect(const char *host, int port, Type type) { char localhost[MAXGETHOSTSTRUCT]; init(); if (!host) { if (gethostname(localhost, sizeof(localhost)) == 1) { myError=ConBadHost; myErrorStr="Failure to locate host '"; myErrorStr+=localhost; myErrorStr+="'"; perror("gethostname"); return(false); } host=localhost; } memset(&mySin, 0, sizeof(mySin)); if ((mySin.sin_addr.s_addr = inet_addr(host)) == INADDR_NONE) { if (!hostAddr(host, mySin.sin_addr)) { setIPString(); myError = ConBadHost; myErrorStr = "Could not find the address of '"; myErrorStr += host; myErrorStr += "'"; return(false); } } mySin.sin_family=AF_INET; mySin.sin_port=hostToNetOrder(port); if ((type == TCP) && ((myFD=socket(AF_INET, SOCK_STREAM, 0)) < 0)) { myError=NetFail; myErrorStr="Failure to make TCP socket"; perror("socket"); return(false); } else if ((type == UDP) && ((myFD=socket(AF_INET, SOCK_DGRAM, 0)) < 0)) { myError=NetFail; myErrorStr="Failure to make UDP socket"; perror("socket"); return(0); } myType=type; if (::connect(myFD, (struct sockaddr *)&mySin, sizeof(struct sockaddr_in)) < 0) { char buff[10]; int err=WSAGetLastError(); sprintf(buff, "%d", err); myErrorStr="Failure to connect socket"; myErrorStr+=buff; switch (err) { case WSAEADDRNOTAVAIL: myError=ConBadHost; break; case WSAECONNREFUSED: myError=ConRefused; break; case WSAENETUNREACH: myError=ConNoRoute; break; default: myError=NetFail; break; } //perror("connect"); ::shutdown(myFD, SD_BOTH); closesocket(myFD); myFD = -1; return(0); } return(1); }
/** @return false and set error code and description string on failure */ AREXPORT bool ArSocket::connect(const char *host, int port, Type type, const char *openOnIP) { char localhost[MAXGETHOSTSTRUCT]; myError = NoErr; myErrorStr.clear(); init(); if (!host) { if (gethostname(localhost, sizeof(localhost)) == 1) { myError=ConBadHost; myErrorStr="Failure to locate host '"; myErrorStr+=localhost; myErrorStr+="'"; ArLog::logErrorFromOS(ArLog::Normal, "ArSocket::connect: gethostname failed"); return(false); } host=localhost; } char useHost[1024]; int usePort; separateHost(host, port, useHost, sizeof(useHost), &usePort); memset(&mySin, 0, sizeof(mySin)); if ((mySin.sin_addr.s_addr = inet_addr(useHost)) == INADDR_NONE) { if (!hostAddr(host, mySin.sin_addr)) { setRawIPString(); myError = ConBadHost; myErrorStr = "Could not find the address of '"; myErrorStr += host; myErrorStr += "'"; return(false); } } mySin.sin_family=AF_INET; mySin.sin_port=hostToNetOrder(usePort); // WSA_FLAG_OVERLAPPED allows concurrent calls to select, read and send on the same socket, // which could happen occasionally. If OVERLAPPED is not enabled in this situation, calls can // hang mysteriously. // This flag is also required for all non-blocking sockets on Windows NT 4.0 (according to MS // Knowlege Base article Q179942) if ((type == TCP) && ((myFD=WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED)) < 0)) { myError=NetFail; myErrorStr="Failure to make TCP socket"; ArLog::logErrorFromOS(ArLog::Normal, "ArSocket::connect: could not make tcp socket"); return(false); } else if ((type == UDP) && ((myFD=WSASocket(AF_INET, SOCK_DGRAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED)) < 0)) { myError=NetFail; myErrorStr="Failure to make UDP socket"; ArLog::logErrorFromOS(ArLog::Normal, "ArSocket::connect: could not make udp socket"); return(0); } myType = type; myHost = ((host != NULL) ? host : ""); myPort = port; if (::connect(myFD, (struct sockaddr *)&mySin, sizeof(struct sockaddr_in)) < 0) { char buff[10]; int err=WSAGetLastError(); sprintf(buff, "%d", err); myErrorStr="Failure to connect socket"; myErrorStr+=buff; switch (err) { case WSAEADDRNOTAVAIL: myError=ConBadHost; break; case WSAECONNREFUSED: myError=ConRefused; break; case WSAENETUNREACH: myError=ConNoRoute; break; default: myError=NetFail; break; } ArLog::logErrorFromOS(ArLog::Verbose, "ArSocket::connect: Failure to connect"); ::shutdown(myFD, SD_BOTH); closesocket(myFD); myFD = INVALID_SOCKET; return(0); } return(1); }
/* * 作为服务器套接字 * 完成套接字的穿件,绑定 * * */ bool RobotSocket::open(int port, Type type, const char *openOnIP) { int ret; char localhost[maxHostNameLen()]; if ((type == TCP) && ((myFD=socket(AF_INET, SOCK_STREAM, 0)) < 0)) { myErrorStr="[socket]创建TCP套接字失败"; perror(myErrorStr.c_str()); return(false); } else if ((type == UDP) && ((myFD=socket(AF_INET, SOCK_DGRAM, 0)) < 0)) { myErrorStr="[socket]创建UDP套接字失败"; perror(myErrorStr.c_str()); return(false); } myType=type; bzero(&mySin, sizeof(mySin)); if (openOnIP != NULL) { if (!hostAddr(openOnIP, mySin.sin_addr)) { /*不能查找到此IP主机*/ return(false); } else { /*成功*/ } } else { mySin.sin_addr.s_addr = htonl(INADDR_ANY); //任意分配本机有的IP,任务交给内核 } setIPString(); mySin.sin_family = AF_INET; mySin.sin_port = hostToNetOrder(port); if ((ret=bind(myFD, (struct sockaddr *)&mySin, sizeof(mySin))) < 0) { myErrorStr="[bind]绑定失败"; sprintf(localhost, "%d", port); myErrorStr+=localhost; perror(myErrorStr.c_str()); return(false); } if ((type == TCP) && (listen(myFD, 5) < 0)) { myErrorStr="[listen]绑定失败"; perror(myErrorStr.c_str()); return(false); } return(true); }
/** @return false and set error code and description string on failure */ bool ArSocket::open(int port, Type type, const char *openOnIP) { int ret; char localhost[maxHostNameLen()]; myError=NoErr; myErrorStr.clear(); if ((type == TCP) && ((myFD=socket(AF_INET, SOCK_STREAM, 0)) < 0)) { myErrorStr="Failure to make TCP socket"; perror("socket"); return(false); } else if ((type == UDP) && ((myFD=socket(AF_INET, SOCK_DGRAM, 0)) < 0)) { myErrorStr="Failure to make UDP socket"; perror("socket"); return(false); } ArUtil::setFileCloseOnExec(myFD); setLinger(0); setReuseAddress(); myType=type; /* MPL removed this since with what I Took out down below months ago if (gethostname(localhost, sizeof(localhost)) == 1) { myErrorStr="Failure to locate localhost"; perror("gethostname"); return(false); } */ bzero(&mySin, sizeof(mySin)); /* MPL took this out since it was just overriding it with the INADDR_ANY anyways and it could cause slowdowns if a machine wasn't configured so lookups are quick if (!hostAddr(localhost, mySin.sin_addr) && !hostAddr("localhost", mySin.sin_addr)) return(false); */ if (openOnIP != NULL) { if (!hostAddr(openOnIP, mySin.sin_addr)) { ArLog::log(ArLog::Normal, "Couldn't find ip of %s to open on", openOnIP); myError = NameLookup; myErrorStr = "Name lookup failed"; return(false); } else { //printf("Opening on %s\n", openOnIP); } } else { mySin.sin_addr.s_addr=htonl(INADDR_ANY); } setRawIPString(); mySin.sin_family=AF_INET; mySin.sin_port=hostToNetOrder(port); if ((ret=bind(myFD, (struct sockaddr *)&mySin, sizeof(mySin))) < 0) { myError = NetFail; myErrorStr="Failure to bind socket to port "; sprintf(localhost, "%d", port); myErrorStr+=localhost; perror("socket"); return(false); } if ((type == TCP) && (listen(myFD, 5) < 0)) { myError = NetFail; myErrorStr="Failure to listen on socket"; perror("listen"); return(false); } return(true); }
bool ArSocket::connect(const char *host, int port, Type type) { char localhost[100]; // maxHostNameLen()]; if (!host) { if (gethostname(localhost, sizeof(localhost)) == 1) { myError=ConBadHost; myErrorStr="Failure to locate host '"; myErrorStr+=localhost; myErrorStr+="'"; perror("gethostname"); return(false); } host=localhost; } bzero(&mySin, sizeof(mySin)); // MPL taking out this next code line from the if since it makes // everything we can't resolve try to connect to localhost // && !hostAddr("localhost", mySin.sin_addr)) if (!hostAddr(host, mySin.sin_addr)) return(false); setIPString(); mySin.sin_family=AF_INET; mySin.sin_port=hostToNetOrder(port); if ((type == TCP) && ((myFD=socket(AF_INET, SOCK_STREAM, 0)) < 0)) { myError=NetFail; myErrorStr="Failure to make TCP socket"; perror("socket"); return(false); } else if ((type == UDP) && ((myFD=socket(AF_INET, SOCK_DGRAM, 0)) < 0)) { myError=NetFail; myErrorStr="Failure to make UDP socket"; perror("socket"); return(false); } myType=type; if (::connect(myFD, (struct sockaddr *)&mySin, sizeof(struct sockaddr_in)) < 0) { myErrorStr="Failure to connect socket"; switch (errno) { case ECONNREFUSED: myError=ConRefused; myErrorStr+="; Connection refused"; break; case ENETUNREACH: myError=ConNoRoute; myErrorStr+="; No route to host"; break; default: myError=NetFail; break; } //perror("connect"); ::close(myFD); myFD = -1; return(false); } return(true); }