void XMLRPC::getBuffer(dBuffer & _buffer) { char* buff; int buffsize; XMLRPC_REQUEST_OUTPUT_OPTIONS opt = XMLRPC_RequestGetOutputOptions(xmlrpc_request); opt->version = xmlrpc_version_1_0; opt->xml_elem_opts.encoding = encoding_utf_8; opt->xml_elem_opts.escaping = xml_elem_markup_escaping; // Skip this call, since we did a get we uses a ref to the actual opt struct anyway. // using set here would cause a "Source and destination overlap in memcpy" (valgrind) // unless we do a copy of opt and feed set with it. //XMLRPC_RequestSetOutputOptions(xmlrpc_request, opt); buff = XMLRPC_REQUEST_ToXML(xmlrpc_request, &buffsize); if (!buff) { return; } #if BTG_EXTERNALIZATION_DEBUG BTG_NOTICE(logWrapper(), "Serialized command to " << buff); #endif // BTG_EXTERNALIZATION_DEBUG _buffer.erase(); _buffer.addBytes(reinterpret_cast<t_byteCP>(buff), buffsize); free(buff); reset(); }
/* with the exception of the registration calls, most everything in main * only needs to be written once per server. */ int main(int argc, char **argv) { XMLRPC_SERVER server; XMLRPC_REQUEST request=0; XMLRPC_REQUEST response; /* create a new server object */ server = XMLRPC_ServerCreate(); /* Register public methods with the server */ XMLRPC_ServerRegisterMethod(server, "hello", hello_callback); /* Now, let's get the client's request from stdin.... */ { char filebuf[4096]; // not that intelligent. sue me. int len = fread(filebuf, sizeof(char), sizeof(filebuf)-1, stdin); if(len) { filebuf[len] = 0; // parse the xml into a request structure request = XMLRPC_REQUEST_FromXML((const char*)filebuf, len, NULL); } } if(!request) { fprintf(stderr, "bogus xmlrpc request\n"); return 1; } /* create a response struct */ response = XMLRPC_RequestNew(); XMLRPC_RequestSetRequestType(response, xmlrpc_request_response); /* call server method with client request and assign the response to our response struct */ XMLRPC_RequestSetData(response, XMLRPC_ServerCallMethod(server, request, NULL)); /* be courteous. reply in same vocabulary/manner as the request. */ XMLRPC_RequestSetOutputOptions(response, XMLRPC_RequestGetOutputOptions(request) ); /* serialize server response as XML */ if(1) { char *outBuf = XMLRPC_REQUEST_ToXML(response, 0); if(outBuf) { printf(outBuf); free(outBuf); } } // cleanup. null safe. XMLRPC_RequestFree(request, 1); XMLRPC_RequestFree(response, 1); XMLRPC_ServerDestroy(server); return 0; }
void LLXMLRPCTransaction::Impl::init(XMLRPC_REQUEST request, bool useGzip) { { try { mCurlEasyRequestStateMachinePtr = new AICurlEasyRequestStateMachine(false); } catch(AICurlNoEasyHandle const& error) { llwarns << "Failed to initialize LLXMLRPCTransaction: " << error.what() << llendl; setStatus(StatusOtherError, "No curl easy handle"); return; } AICurlEasyRequest_wat curlEasyRequest_w(*mCurlEasyRequestStateMachinePtr->mCurlEasyRequest); curlEasyRequest_w->setWriteCallback(&curlDownloadCallback, (void*)this); BOOL vefifySSLCert = !gSavedSettings.getBOOL("NoVerifySSLCert"); curlEasyRequest_w->setopt(CURLOPT_SSL_VERIFYPEER, vefifySSLCert); curlEasyRequest_w->setopt(CURLOPT_SSL_VERIFYHOST, vefifySSLCert ? 2 : 0); // Be a little impatient about establishing connections. curlEasyRequest_w->setopt(CURLOPT_CONNECTTIMEOUT, 40L); /* Setting the DNS cache timeout to -1 disables it completely. This might help with bug #503 */ curlEasyRequest_w->setopt(CURLOPT_DNS_CACHE_TIMEOUT, -1L); curlEasyRequest_w->addHeader("Content-Type: text/xml"); if (useGzip) { curlEasyRequest_w->setoptString(CURLOPT_ENCODING, ""); } int requestTextSize; char* requestText = XMLRPC_REQUEST_ToXML(request, &requestTextSize); if (requestText) { curlEasyRequest_w->setPost(new AIXMLRPCData(requestText), requestTextSize); } else { setStatus(StatusOtherError); } curlEasyRequest_w->finalizeRequest(mURI); } if (mStatus == LLXMLRPCTransaction::StatusNotStarted) // It could be LLXMLRPCTransaction::StatusOtherError. { mCurlEasyRequestStateMachinePtr->run(boost::bind(&LLXMLRPCTransaction::Impl::curlEasyRequestCallback, this, _1)); setStatus(LLXMLRPCTransaction::StatusStarted); } else { // This deletes the statemachine immediately. mCurlEasyRequestStateMachinePtr->kill(); mCurlEasyRequestStateMachinePtr = NULL; } }
/*virtual*/ U32 get_body(LLChannelDescriptors const& channels, buffer_ptr_t& buffer) { int requestTextSize; mRequestText = XMLRPC_REQUEST_ToXML(mRequest, &requestTextSize); if (!mRequestText) throw AICurlNoBody("XMLRPC_REQUEST_ToXML returned NULL."); LLBufferStream ostream(channels, buffer.get()); ostream.write(mRequestText, requestTextSize); ostream << std::flush; // Always flush a LLBufferStream when done writing to it. return requestTextSize; }
void LLXMLRPCTransaction::Impl::init(XMLRPC_REQUEST request, bool useGzip) { if (!mCurlRequest) { mCurlRequest = new LLCurlEasyRequest(); } mErrorCert = NULL; if (gSavedSettings.getBOOL("BrowserProxyEnabled")) { mProxyAddress = gSavedSettings.getString("BrowserProxyAddress"); S32 port = gSavedSettings.getS32 ( "BrowserProxyPort" ); // tell curl about the settings mCurlRequest->setoptString(CURLOPT_PROXY, mProxyAddress); mCurlRequest->setopt(CURLOPT_PROXYPORT, port); mCurlRequest->setopt(CURLOPT_PROXYTYPE, CURLPROXY_HTTP); } // mCurlRequest->setopt(CURLOPT_VERBOSE, 1); // usefull for debugging mCurlRequest->setopt(CURLOPT_NOSIGNAL, 1); mCurlRequest->setWriteCallback(&curlDownloadCallback, (void*)this); BOOL vefifySSLCert = !gSavedSettings.getBOOL("NoVerifySSLCert"); mCertStore = gSavedSettings.getString("CertStore"); mCurlRequest->setopt(CURLOPT_SSL_VERIFYPEER, vefifySSLCert); mCurlRequest->setopt(CURLOPT_SSL_VERIFYHOST, vefifySSLCert ? 2 : 0); // Be a little impatient about establishing connections. mCurlRequest->setopt(CURLOPT_CONNECTTIMEOUT, 40L); mCurlRequest->setSSLCtxCallback(_sslCtxFunction, (void *)this); /* Setting the DNS cache timeout to -1 disables it completely. This might help with bug #503 */ mCurlRequest->setopt(CURLOPT_DNS_CACHE_TIMEOUT, -1); mCurlRequest->slist_append("Content-Type: text/xml"); if (useGzip) { mCurlRequest->setoptString(CURLOPT_ENCODING, ""); } mRequestText = XMLRPC_REQUEST_ToXML(request, &mRequestTextSize); if (mRequestText) { mCurlRequest->setoptString(CURLOPT_POSTFIELDS, mRequestText); mCurlRequest->setopt(CURLOPT_POSTFIELDSIZE, mRequestTextSize); } else { setStatus(StatusOtherError); } mCurlRequest->sendRequest(mURI); }
int uhRPCHandler(UrlHandlerParam* param) { XMLRPC_REQUEST request=NULL; XMLRPC_REQUEST response=NULL; STRUCT_XMLRPC_REQUEST_INPUT_OPTIONS in_opts; char *encoding = 0; int output = 0; char *outBuf = NULL; in_opts.xml_elem_opts.encoding = utf8_get_encoding_id_from_string(encoding); if (param->hs->request.payloadSize > 0) { request = XMLRPC_REQUEST_FromXML(param->hs->request.pucPayload, param->hs->request.payloadSize, &in_opts); /* create a response struct */ response = XMLRPC_RequestNew(); XMLRPC_RequestSetRequestType(response, xmlrpc_request_response); /* call server method with client request and assign the response to our response struct */ XMLRPC_RequestSetData(response, XMLRPC_ServerCallMethod(xml_rpm_server_obj, request, NULL)); if(output == 0 || output == 2) { /* serialize server response as XML */ outBuf = XMLRPC_REQUEST_ToXML(response, 0); } if (outBuf) { //Copy the response into the output buffer strcpy(param->pucBuffer,outBuf); param->dataBytes = strlen(outBuf); param->fileType=HTTPFILETYPE_XML; //Clean up the request and response objects, along with the //buffer which was created by the XML-RPC engine. if(request) XMLRPC_RequestFree(request, 1); if(response) XMLRPC_RequestFree(response, 1); if (outBuf) free(outBuf); return (FLAG_DATA_RAW); } } //Clean up the request and response objects, along with the //buffer which was created by the XML-RPC engine. if(request) XMLRPC_RequestFree(request, 1); if(response) XMLRPC_RequestFree(response, 1); if (outBuf) free(outBuf); return (FLAG_DATA_RAW); }
void LLXMLRPCTransaction::Impl::init(XMLRPC_REQUEST request, bool useGzip) { if (!mCurlRequest) { mCurlRequest = new LLCurlEasyRequest(); } if(!mCurlRequest->isValid()) { llwarns << "mCurlRequest is invalid." << llendl ; delete mCurlRequest ; mCurlRequest = NULL ; return ; } mErrorCert = NULL; // mCurlRequest->setopt(CURLOPT_VERBOSE, 1); // useful for debugging mCurlRequest->setopt(CURLOPT_NOSIGNAL, 1); mCurlRequest->setWriteCallback(&curlDownloadCallback, (void*)this); BOOL vefifySSLCert = !gSavedSettings.getBOOL("NoVerifySSLCert"); mCertStore = gSavedSettings.getString("CertStore"); mCurlRequest->setopt(CURLOPT_SSL_VERIFYPEER, vefifySSLCert); mCurlRequest->setopt(CURLOPT_SSL_VERIFYHOST, vefifySSLCert ? 2 : 0); // Be a little impatient about establishing connections. mCurlRequest->setopt(CURLOPT_CONNECTTIMEOUT, 40L); mCurlRequest->setSSLCtxCallback(_sslCtxFunction, (void *)this); /* Setting the DNS cache timeout to -1 disables it completely. This might help with bug #503 */ mCurlRequest->setopt(CURLOPT_DNS_CACHE_TIMEOUT, -1); mCurlRequest->slist_append("Content-Type: text/xml"); if (useGzip) { mCurlRequest->setoptString(CURLOPT_ENCODING, ""); } mRequestText = XMLRPC_REQUEST_ToXML(request, &mRequestTextSize); if (mRequestText) { mCurlRequest->setoptString(CURLOPT_POSTFIELDS, mRequestText); mCurlRequest->setopt(CURLOPT_POSTFIELDSIZE, mRequestTextSize); } else { setStatus(StatusOtherError); } mCurlRequest->sendRequest(mURI); }
void LLXMLRPCTransaction::Impl::init(XMLRPC_REQUEST request, bool useGzip) { mCurl = curl_easy_init(); if (gSavedSettings.getBOOL("BrowserProxyEnabled")) { mProxyAddress = gSavedSettings.getString("BrowserProxyAddress"); S32 port = gSavedSettings.getS32 ( "BrowserProxyPort" ); // tell curl about the settings curl_easy_setopt(mCurl, CURLOPT_PROXY, mProxyAddress.c_str()); curl_easy_setopt(mCurl, CURLOPT_PROXYPORT, (long) port); curl_easy_setopt(mCurl, CURLOPT_PROXYTYPE, (long) CURLPROXY_HTTP); }; // curl_easy_setopt(mCurl, CURLOPT_VERBOSE, 1L); // usefull for debugging curl_easy_setopt(mCurl, CURLOPT_NOSIGNAL, 1L); curl_easy_setopt(mCurl, CURLOPT_WRITEFUNCTION, &curlDownloadCallback); curl_easy_setopt(mCurl, CURLOPT_WRITEDATA, this); curl_easy_setopt(mCurl, CURLOPT_ERRORBUFFER, &mCurlErrorBuffer); curl_easy_setopt(mCurl, CURLOPT_CAINFO, gDirUtilp->getCAFile().c_str()); curl_easy_setopt(mCurl, CURLOPT_SSL_VERIFYPEER, (long) gVerifySSLCert); curl_easy_setopt(mCurl, CURLOPT_SSL_VERIFYHOST, gVerifySSLCert? 2L : 0L); // Be a little impatient about establishing connections. curl_easy_setopt(mCurl, CURLOPT_CONNECTTIMEOUT, 40L); /* Setting the DNS cache timeout to -1 disables it completely. This might help with bug #503 */ curl_easy_setopt(mCurl, CURLOPT_DNS_CACHE_TIMEOUT, -1L); mHeaders = curl_slist_append(mHeaders, "Content-Type: text/xml"); curl_easy_setopt(mCurl, CURLOPT_URL, mURI.c_str()); curl_easy_setopt(mCurl, CURLOPT_HTTPHEADER, mHeaders); if (useGzip) { curl_easy_setopt(mCurl, CURLOPT_ENCODING, ""); } mRequestText = XMLRPC_REQUEST_ToXML(request, &mRequestTextSize); if (mRequestText) { curl_easy_setopt(mCurl, CURLOPT_POSTFIELDS, mRequestText); curl_easy_setopt(mCurl, CURLOPT_POSTFIELDSIZE, (long) mRequestTextSize); } else { setStatus(StatusOtherError); } mCurlMulti = curl_multi_init(); curl_multi_add_handle(mCurlMulti, mCurl); }
std::string XMLRPC::dumpData() const { char*buff; int buffsize; std::string s; buff = XMLRPC_REQUEST_ToXML(xmlrpc_request, &buffsize); if(!buff) return s; s = buff; free(buff); return s; }
t_int XMLRPC::getBufferSize() { /* Since the caller want's to know the size of the data getBuffer() might return * we have to render the object to XML to get the size */ char* buff; int buffsize; buff = XMLRPC_REQUEST_ToXML(xmlrpc_request, &buffsize); if(!buff) { return 0; } free(buff); return buffsize; }
/* with the exception of the registration calls, most everything in main * only needs to be written once per server. */ char* clientCallback( char* filebuf ) { XMLRPC_SERVER server; XMLRPC_REQUEST request, response; /* create a new server object */ server = XMLRPC_ServerCreate( ); /* Register public methods with the server */ XMLRPC_ServerRegisterMethod( server, "start", x_startCallback ); XMLRPC_ServerRegisterMethod( server, "stop", x_stopCallback ); XMLRPC_ServerRegisterMethod( server, "rm", x_rmCallback ); XMLRPC_ServerRegisterMethod( server, "mkdir", x_mkdirCallback ); XMLRPC_ServerRegisterMethod( server, "execute", x_executeCallback ); XMLRPC_ServerRegisterMethod( server, "checkcore", x_checkCoreCallback ); XMLRPC_ServerRegisterMethod( server, "listTests", x_listTestsCallback ); XMLRPC_ServerRegisterMethod( server, "runTests", x_runTestsCallback ); XMLRPC_ServerRegisterMethod( server, "listMachines", x_listMachinesCallback ); XMLRPC_ServerRegisterMethod( server, "getConfig", x_getConfigCallback ); XMLRPC_ServerRegisterMethod( server, "setConfig", x_setConfigCallback ); /* Now, let's get the client's request from stdin.... * This will be read from a socket */ { /* char filebuf[4096]; // not that intelligent. sue me. int len = fread( filebuf, sizeof( char ), sizeof( filebuf ) - 1, if( len ) { filebuf[len] = 0; stdin ); */ // parse the xml into a request structure request = XMLRPC_REQUEST_FromXML( ( const char * )filebuf, strlen(filebuf), NULL ); // } } if( !request ) { fprintf( stderr, "bogus xmlrpc request\n" ); return 0; } /* * The interesting part is below */ /* create a response struct */ response = XMLRPC_RequestNew( ); XMLRPC_RequestSetRequestType( response, xmlrpc_request_response ); /* call server method with client request and assign the response to our response struct */ XMLRPC_RequestSetData( response, XMLRPC_ServerCallMethod( server, request, NULL ) ); /* be courteous. reply in same vocabulary/manner as the request. */ XMLRPC_RequestSetOutputOptions( response, XMLRPC_RequestGetOutputOptions ( request ) ); /* serialize server response as XML */ char *outBuf = XMLRPC_REQUEST_ToXML( response, 0 ); if( outBuf ) { printf( outBuf ); } // cleanup. null safe. XMLRPC_RequestFree( request, 1 ); XMLRPC_RequestFree( response, 1 ); XMLRPC_ServerDestroy( server ); return outBuf; }
void LLXMLRPCTransaction::Impl::init(XMLRPC_REQUEST request, bool useGzip) { if (!mCurlRequest) { mCurlRequest = new LLCurlEasyRequest(); } if (gSavedSettings.getBOOL("XMLRPCProxyEnabled")) { mProxyAddress = gSavedSettings.getString("XMLRPCProxyAddress"); S32 port = gSavedSettings.getS32 ( "XMLRPCProxyPort" ); // tell curl about the settings mCurlRequest->setoptString(CURLOPT_PROXY, mProxyAddress); mCurlRequest->setopt(CURLOPT_PROXYPORT, port); mCurlRequest->setopt(CURLOPT_PROXYTYPE, CURLPROXY_HTTP); } else if (LLSocks::getInstance()->isHttpProxyEnabled()) { std::string address = LLSocks::getInstance()->getHTTPProxy().getIPString(); U16 port = LLSocks::getInstance()->getHTTPProxy().getPort(); mCurlRequest->setoptString(CURLOPT_PROXY, address.c_str()); mCurlRequest->setopt(CURLOPT_PROXYPORT, port); if (LLSocks::getInstance()->getHttpProxyType() == LLPROXY_SOCKS) { mCurlRequest->setopt(CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5); if(LLSocks::getInstance()->getSelectedAuthMethod()==METHOD_PASSWORD) mCurlRequest->setoptString(CURLOPT_PROXYUSERPWD,LLSocks::getInstance()->getProxyUserPwd()); } else { mCurlRequest->setopt(CURLOPT_PROXYTYPE, CURLPROXY_HTTP); } } // mCurlRequest->setopt(CURLOPT_VERBOSE, 1); // usefull for debugging mCurlRequest->setopt(CURLOPT_NOSIGNAL, 1); mCurlRequest->setWriteCallback(&curlDownloadCallback, (void*)this); BOOL vefifySSLCert = !gSavedSettings.getBOOL("NoVerifySSLCert"); mCurlRequest->setopt(CURLOPT_SSL_VERIFYPEER, vefifySSLCert); mCurlRequest->setopt(CURLOPT_SSL_VERIFYHOST, vefifySSLCert ? 2 : 0); // Be a little impatient about establishing connections. mCurlRequest->setopt(CURLOPT_CONNECTTIMEOUT, 40L); /* Setting the DNS cache timeout to -1 disables it completely. This might help with bug #503 */ mCurlRequest->setopt(CURLOPT_DNS_CACHE_TIMEOUT, -1); mCurlRequest->slist_append("Content-Type: text/xml"); if (useGzip) { mCurlRequest->setoptString(CURLOPT_ENCODING, ""); } mRequestText = XMLRPC_REQUEST_ToXML(request, &mRequestTextSize); if (mRequestText) { mCurlRequest->setoptString(CURLOPT_POSTFIELDS, mRequestText); mCurlRequest->setopt(CURLOPT_POSTFIELDSIZE, mRequestTextSize); } else { setStatus(StatusOtherError); } mCurlRequest->sendRequest(mURI); }
int main(int argc, char **argv) { int i; XMLRPC_SERVER server; XMLRPC_REQUEST xRequest=0; XMLRPC_REQUEST response; STRUCT_XMLRPC_REQUEST_OUTPUT_OPTIONS call_options; /* args */ int verbosity = 0; int version = 0; int escaping = 0; int output = 0; char *methodName = "method_TestNormal"; char *encoding = 0; /* for every argument (after the program name) */ for(i=1; i<argc; i++) { char* arg = argv[i]; if(*arg == '-') { char* key = arg + 1; char* val = argv[i+1]; if(key && (!strcmp(key, "help") || !strcmp(key, "-help"))) { print_help(); return 0; } if(key && val) { if(!strcmp(key, "verbosity")) { if(!strcmp(val, "pretty")) { verbosity = 0; } else if(!strcmp(val, "none")) { verbosity = 1; } else if(!strcmp(val, "newlines")) { verbosity = 2; } } else if(!strcmp(key, "version")) { if(!strcmp(val, "xmlrpc")) { version = 0; } else if(!strcmp(val, "simple")) { version = 1; } } else if(!strcmp(key, "escaping")) { if(!strcmp(val, "markup")) { escaping |= xml_elem_markup_escaping ; } else if(!strcmp(val, "cdata")) { escaping |= xml_elem_cdata_escaping; } else if(!strcmp(val, "non-ascii")) { escaping |= xml_elem_non_ascii_escaping; } else if(!strcmp(val, "non-print")) { escaping |= xml_elem_non_print_escaping; } } else if(!strcmp(key, "encoding")) { encoding = val; } else if(!strcmp(key, "output")) { if(!strcmp(val, "response")) { output = 0; } else if(!strcmp(val, "xRequest")) { output = 1; } else if(!strcmp(val, "both")) { output = 2; } } else if(!strcmp(key, "method")) { methodName = val; } i++; } } } /* create a new server object */ server = XMLRPC_ServerCreate(); XMLRPC_ServerRegisterMethod(server, "validator1.arrayOfStructsTest", validator1_arrayOfStructsTest); XMLRPC_ServerRegisterMethod(server, "validator1.countTheEntities", validator1_countTheEntities); XMLRPC_ServerRegisterMethod(server, "validator1.easyStructTest", validator1_easyStructTest); XMLRPC_ServerRegisterMethod(server, "validator1.echoStructTest", validator1_echoStructTest); XMLRPC_ServerRegisterMethod(server, "validator1.manyTypesTest", validator1_manyTypesTest); XMLRPC_ServerRegisterMethod(server, "validator1.moderateSizeArrayCheck", validator1_moderateSizeArrayCheck); XMLRPC_ServerRegisterMethod(server, "validator1.nestedStructTest", validator1_nestedStructTest); XMLRPC_ServerRegisterMethod(server, "validator1.simpleStructReturnTest", validator1_simpleStructReturnTest); /* Now, let's get the client's xRequest from stdin.... */ { char* filebuf[1024 * 100]; int len = fread(filebuf, sizeof(char), sizeof(filebuf)-1, stdin); if(len) { filebuf[len] = 0; xRequest = XMLRPC_REQUEST_FromXML((const char*)filebuf, len, NULL); } } if(!xRequest) { fprintf(stderr, "bogus xmlrpc xRequest\n"); return 1; } /* create a response struct */ response = XMLRPC_RequestNew(); XMLRPC_RequestSetRequestType(response, xmlrpc_request_response); /* Set various xml output options. Or we could just use defaults. */ call_options.xml_elem_opts.verbosity = verbosity == 1 ? xml_elem_no_white_space : (verbosity == 2 ? xml_elem_newlines_only : xml_elem_pretty); call_options.xml_elem_opts.escaping = escaping; call_options.version = (version == 1) ? xmlrpc_version_simple : xmlrpc_version_1_0; call_options.xml_elem_opts.encoding = encoding; XMLRPC_RequestSetOutputOptions(response, &call_options); /* call server method with client xRequest and assign the response to our response struct */ XMLRPC_RequestSetData(response, XMLRPC_ServerCallMethod(server, xRequest, NULL)); if(output == 1 || output == 2) { /* serialize client request as XML */ char *outBuf; XMLRPC_RequestSetOutputOptions(xRequest, &call_options); outBuf = XMLRPC_REQUEST_ToXML(xRequest, 0); if(outBuf) { printf("%s\n\n --- \n\n", outBuf); free(outBuf); } } if(output == 0 || output == 2) { /* serialize server response as XML */ char *outBuf = XMLRPC_REQUEST_ToXML(response, 0); if(outBuf) { printf(outBuf); free(outBuf); } } if(xRequest) { /* Free xRequest */ XMLRPC_RequestFree(xRequest, 1); } if(response) { /* free response */ XMLRPC_RequestFree(response, 1); } if(server) { XMLRPC_ServerDestroy(server); } return 0; }