/*
     * This method processes a block of rows in a single invocation.
     *
     * The inputs are retrieved via arg_reader
     * The outputs are returned via arg_writer
     */
    virtual void processBlock(ServerInterface &srvInterface,
                              BlockReader &arg_reader,
                              BlockWriter &res_writer)
    {

        // While we have inputs to process
        do {
            if (arg_reader.getStringRef(0).isNull()) {
                res_writer.getStringRef().setNull();
            }
            else {

                string data = arg_reader.getStringRef(0).str();
                string path = arg_reader.getStringRef(1).str();
                ResponseInfo response = XMLFunctions::xpath(data, path, srvInterface);
                if ((int) response.size() < arg_reader.getIntRef(2)) {
                    res_writer.getStringRef().setNull();
                } else if ((int) response.size() > 0) {
                    res_writer.getStringRef().copy( response[arg_reader.getIntRef(2)-1]);
                } else {
                    res_writer.getStringRef().setNull();
                }
            }

            res_writer.next();
        } while (arg_reader.next());
    }
			virtual void processBlock(ServerInterface &srvInterface,
				            BlockReader &arg_reader,
					        BlockWriter &res_writer) {
				if (arg_reader.getNumCols() != 1)
					vt_report_error(0, "Function only accept 1 arguments, but %zu provided", arg_reader.getNumCols());

				// While we have inputs to process
				do {
					const vint num = arg_reader.getIntRef(0);

					// check for valid month number
					if (num > BILLION)
					vt_report_error(0, "ERROR: OUT OF RANGE");

					res_writer.getStringRef().copy(spell_out(num));
					res_writer.next();
				} while (arg_reader.next());					
			}
    /*
     * This method processes a block of rows in a single invocation.
     *
     * The inputs are retrieved via arg_reader
     * The outputs are returned via arg_writer
     */
    virtual void processBlock(ServerInterface &srvInterface,
                              BlockReader &arg_reader,
                              BlockWriter &res_writer)
    {
        // Basic error checking
        if (arg_reader.getNumCols() != 2)
            vt_report_error(0, "Function only accept 2 arguments, but %zu provided",
                            arg_reader.getNumCols());

        // While we have inputs to process
        do {
            // Get a copy of the input string
            const std::string& patternStr = arg_reader.getStringRef(0).str();
            const std::string& inStr = arg_reader.getStringRef(1).str();

            size_t m = patternStr.size();
            size_t n = inStr.size();
            size_t d[m+1][n+1];
            for (size_t i = 0; i <= m; ++i)
                d[i][0] = i; // the distance of any first string to an empty second string
            for (size_t j = 0; j <= n; ++j)
                d[0][j] = j; // the distance of any second string to an empty first string

            for (size_t j = 1; j <= n; ++j)
                for (size_t i = 1; i <= m; ++i)
                {
                    if (patternStr[i-1] == inStr[j-1])
                        d[i][j] = d[i-1][j-1];       // no operation required
                    else
                    {
                        d[i][j] = std::min(std::min(d[i-1][j] + 1,  // a deletion
                                                    d[i][j-1] + 1),  // an insertion
                                           d[i-1][j-1] + 1); // a substitution
                    }
                }

            res_writer.setInt(d[m][n]);
            res_writer.next();
        } while (arg_reader.next());
    }
    /*
     * This method processes a block of rows in a single invocation.
     *
     * The inputs are retrieved via arg_reader
     * The outputs are returned via arg_writer
     */
    virtual void processBlock(ServerInterface &srvInterface,
                              BlockReader &arg_reader,
                              BlockWriter &res_writer)
    {

        // While we have inputs to process
        do {
            if (arg_reader.getStringRef(0).isNull()) {
                res_writer.getStringRef().setNull();
            }
            else {

                string data = arg_reader.getStringRef(0).str();
                string style = arg_reader.getStringRef(1).str();
                res_writer.getStringRef().copy(
                    XMLFunctions::xslt(data, style, srvInterface)
                );
            }

            res_writer.next();
        } while (arg_reader.next());
    }
    /*
     * This method processes a block of rows in a single invocation.
     *
     * The inputs are retrieved via arg_reader
     * The outputs are returned via arg_writer
     */
    virtual void processBlock(ServerInterface &srvInterface,
                              BlockReader &arg_reader,
                              BlockWriter &res_writer)
    {
        // Basic error checking
        if (arg_reader.getNumCols() != 4)
            vt_report_error(0, "Function only accept 1 arguments, but %zu provided", 
                            arg_reader.getNumCols());
        
        // While we have inputs to process
        do {

            char curlresponse[1024]; 

            // Get a copy of the input string
            std::string  streetStr = arg_reader.getStringRef(0).str();
            std::string  cityStr = arg_reader.getStringRef(1).str();
            std::string  stateStr = arg_reader.getStringRef(2).str();
            std::string  zipStr = arg_reader.getStringRef(3).str();

	    // Replaces spaces with %20 for URLs
            for (size_t pos = streetStr.find(' '); 
		 pos != string::npos;
		 pos = streetStr.find(' ',pos)) 
	    {
	      	streetStr.replace(pos,1,"%20");
	    } 

  	     for (size_t pos = cityStr.find(' ');
                 pos != string::npos;
                 pos = cityStr.find(' ',pos))                         
            {
                cityStr.replace(pos,1,"%20");
            }

            // Build the URL 
            std::string URL = baseURL + "&streetAddress=" + streetStr;
            URL += "&city=" + cityStr;
            URL += "&state=" + stateStr;
            URL += "&zip=" + zipStr;

            if(curl) {
              curl_easy_setopt(curl, CURLOPT_URL, URL.c_str());
            }
    
	    // curl setup
            curl_easy_setopt(curl, CURLOPT_HEADER, 0);
            curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 0);
            curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
            curl_easy_setopt(curl, CURLOPT_WRITEDATA, &curlresponse );

	    // perform the webservice call	
            res = curl_easy_perform(curl);

            // parse webservice response to get the latitude and longitude data 
            std::vector<std::string> tokens;
            split(tokens,string(curlresponse),',');
            std::string latlong = tokens[3] + "," + tokens[4];

	    // copy data back to Vertica
            res_writer.getStringRef().copy(latlong);
            res_writer.next();
        } while (arg_reader.next());
    }