static bool each_result(const as_val * val, void * udata)
{
	if ( !val ) {
		return false;
	}

	PyObject * py_results = NULL;
	py_results = (PyObject *) udata;
	PyObject * py_result = NULL;

	as_error err;

	PyGILState_STATE gstate;
	gstate = PyGILState_Ensure();

	val_to_pyobject(&err, val, &py_result);

	if ( py_result ) {
		PyList_Append(py_results, py_result);
		Py_DECREF(py_result);
	}

	PyGILState_Release(gstate);

	return true;
}
static bool each_result(const as_val * val, void * udata)
{
	bool rval = true;

	if ( !val ) {
		return false;
	}

	// Extract callback user-data
	LocalData * data = (LocalData *) udata;
	as_error * err = &data->error;
	PyObject * py_callback = data->callback;

	// Python Function Arguments and Result Value
	PyObject * py_arglist = NULL;
	PyObject * py_result  = NULL;
	PyObject * py_return = NULL;

	// Lock Python State
	PyGILState_STATE gstate;
	gstate = PyGILState_Ensure();

	// Convert as_val to a Python Object
	val_to_pyobject(err, val, &py_result);

	// Build Python Function Arguments
	py_arglist = PyTuple_New(1);
	PyTuple_SetItem(py_arglist, 0, py_result);

	// Invoke Python Callback
	py_return = PyEval_CallObject(py_callback, py_arglist);

	// Release Python Function Arguments
	Py_DECREF(py_arglist);
	// handle return value
	if ( py_return == NULL ) {
		// an exception was raised, handle it (someday)
		// for now, we bail from the loop
		as_error_update(err, AEROSPIKE_ERR_PARAM, "Callback function contains an error");
		rval = true;
	}
	else if (  PyBool_Check(py_return) ) {
		if ( Py_False == py_return ) {
			rval = false;
		}
		else {
			rval = true;
		}
		Py_DECREF(py_return);
	}
	else {
		rval = true;
		Py_DECREF(py_return);
	}

	// Release Python State
	PyGILState_Release(gstate);

	return rval;
}
static bool each_result(const as_val * val, void * udata)
{
	if ( !val ) {
		return false;
	}

	// Extract callback user-data
	LocalData * data = (LocalData *) udata;
	as_error * err = &data->error;
	PyObject * py_callback = data->callback;

	// Python Function Arguments and Result Value
	PyObject * py_arglist = NULL; 
	PyObject * py_result = NULL;

	// Lock Python State
	PyGILState_STATE gstate;
	gstate = PyGILState_Ensure();

	// Convert as_val to a Python Object
	val_to_pyobject(err, val, &py_result);

	// Build Python Function Arguments
	py_arglist = PyTuple_New(1);
	PyTuple_SetItem(py_arglist, 0, py_result);

	// Invoke Python Callback
	PyEval_CallObject(py_callback, py_arglist);

	// Release Python Function Arguments
	Py_DECREF(py_arglist);

	// TODO: handle return value

	// Release Python State
	PyGILState_Release(gstate);

	return true;
}
/**
 *******************************************************************************************************
 * This function applies a registered udf module on a particular record.
 *
 * @param self                  AerospikeClient object
 * @param py_key                The key under which to store the record.
 * @param py_module             The module name.
 * @param py_function           The UDF function to be applied on a record.
 * @param py_arglist            The arguments to the UDF function
 * @param py_policy             The optional policy parameters
 *
 * Returns the result of UDF function.
 *******************************************************************************************************
 */
PyObject * AerospikeClient_Apply_Invoke(
    AerospikeClient * self,
    PyObject * py_key, PyObject * py_module, PyObject * py_function,
    PyObject * py_arglist, PyObject * py_policy)
{
    // Python Return Value
    PyObject * py_result = NULL;

    // Aerospike Client Arguments
    as_error err;
    as_policy_apply apply_policy;
    as_policy_apply * apply_policy_p = NULL;
    as_key key;
    char * module = NULL;
    char * function = NULL;
    as_list * arglist = NULL;
    as_val * result = NULL;

    PyObject * py_umodule   = NULL;
    PyObject * py_ufunction = NULL;

    // Initialisation flags
    bool key_initialised = false;

    // Initialize error
    as_error_init(&err);

    if( !PyList_Check(py_arglist) ) {
        PyErr_SetString(PyExc_TypeError, "expected UDF method arguments in a 'list'");
        return NULL;
    }

    if (!self || !self->as) {
        as_error_update(&err, AEROSPIKE_ERR_PARAM, "Invalid aerospike object");
        goto CLEANUP;
    }

    if (!self->is_conn_16) {
        as_error_update(&err, AEROSPIKE_ERR_CLUSTER, "No connection to aerospike cluster");
        goto CLEANUP;
    }

    // Convert python key object to as_key
    pyobject_to_key(&err, py_key, &key);
    if ( err.code != AEROSPIKE_OK ) {
        goto CLEANUP;
    }
    // Key is initialiased successfully
    key_initialised = true;

    // Convert python list to as_list
    pyobject_to_list(self, &err, py_arglist, &arglist, NULL, -1);
    if ( err.code != AEROSPIKE_OK ) {
        goto CLEANUP;
    }

    // Convert python policy object to as_policy_apply
    pyobject_to_policy_apply(&err, py_policy, &apply_policy, &apply_policy_p,
                             &self->as->config.policies.apply);
    if ( err.code != AEROSPIKE_OK ) {
        goto CLEANUP;
    }

    if ( PyUnicode_Check(py_module) ) {
        py_umodule = PyUnicode_AsUTF8String(py_module);
        module = PyStr_AsString(py_umodule);
    }
    else if ( PyStr_Check(py_module) ) {
        module = PyStr_AsString(py_module);
    }
    else {
        as_error_update(&err, AEROSPIKE_ERR_CLIENT, "udf module argument must be a string or unicode string");
        goto CLEANUP;
    }

    if ( PyUnicode_Check(py_function) ) {
        py_ufunction = PyUnicode_AsUTF8String(py_function);
        function = PyStr_AsString(py_ufunction);
    }
    else if ( PyStr_Check(py_function) ) {
        function = PyStr_AsString(py_function);
    }
    else {
        as_error_update(&err, AEROSPIKE_ERR_CLIENT, "function name must be a string or unicode string");
        goto CLEANUP;
    }

    // Invoke operation
    aerospike_key_apply(self->as, &err, apply_policy_p, &key, module, function, arglist, &result);

    if ( err.code == AEROSPIKE_OK ) {
        val_to_pyobject(&err, result, &py_result);
    } else {
        as_error_update(&err, err.code, NULL);
    }

CLEANUP:

    if (py_umodule) {
        Py_DECREF(py_umodule);
    }

    if (py_ufunction) {
        Py_DECREF(py_ufunction);
    }

    if (key_initialised == true) {
        // Destroy the key if it is initialised successfully.
        as_key_destroy(&key);
    }
    as_list_destroy(arglist);
    as_val_destroy(result);

    if ( err.code != AEROSPIKE_OK ) {
        PyObject * py_err = NULL;
        error_to_pyobject(&err, &py_err);
        PyObject *exception_type = raise_exception(&err);
        if(PyObject_HasAttrString(exception_type, "key")) {
            PyObject_SetAttrString(exception_type, "key", py_key);
        }
        if(PyObject_HasAttrString(exception_type, "bin")) {
            PyObject_SetAttrString(exception_type, "bin", Py_None);
        }
        if(PyObject_HasAttrString(exception_type, "module")) {
            PyObject_SetAttrString(exception_type, "module", py_module);
        }
        if(PyObject_HasAttrString(exception_type, "func")) {
            PyObject_SetAttrString(exception_type, "func", py_function);
        }
        PyErr_SetObject(exception_type, py_err);
        Py_DECREF(py_err);
        return NULL;
    }

    return py_result;
}
/**
 ********************************************************************************************************
 * Get an object from the map.
 *
 * @param self                  AerospikeLMap object
 * @param args                  The args is a tuple object containing an argument
 *                              list passed from Python to a C function
 * @param kwds                  Dictionary of keywords
 * 
 * Returns that entry with key,value pair.
 * In case of error,appropriate exceptions will be raised.
 ********************************************************************************************************
 */
PyObject * AerospikeLMap_Get(AerospikeLMap * self, PyObject * args, PyObject * kwds)
{
	PyObject* py_map_key = NULL;
	PyObject* py_policy = NULL;
	as_policy_apply apply_policy;
	as_policy_apply* apply_policy_p = NULL;
	as_val * map_key = NULL;
	as_val* map_key_value = NULL;

	as_static_pool static_pool;
	memset(&static_pool, 0, sizeof(static_pool));

	as_error err;
	as_error_init(&err);

	static char * kwlist[] = {"key", "policy", NULL};

	// Python Function Argument Parsing
	if ( PyArg_ParseTupleAndKeywords(args, kwds, "O|O:get", kwlist, 
				&py_map_key, &py_policy) == false ) {
		return NULL;
	}

	if (!self || !self->client->as) {
		as_error_update(&err, AEROSPIKE_ERR_PARAM, "Invalid aerospike object");
		goto CLEANUP;
	}
	if (!self->client->is_conn_16) {
		as_error_update(&err, AEROSPIKE_ERR_CLUSTER, "No connection to aerospike cluster");
		goto CLEANUP;
	}

	// Convert python policy object to as_policy_apply
	pyobject_to_policy_apply(&err, py_policy, &apply_policy, &apply_policy_p,
			&self->client->as->config.policies.apply);
	if ( err.code != AEROSPIKE_OK ) {
		goto CLEANUP;
	}

	pyobject_to_val(&err, py_map_key, &map_key, &static_pool, SERIALIZER_PYTHON);
	if (err.code != AEROSPIKE_OK) {
		goto CLEANUP;
	}

	aerospike_lmap_get(self->client->as, &err, apply_policy_p, &self->key,
			&self->lmap, map_key, &map_key_value);

	if (err.code != AEROSPIKE_OK) {
		as_error_update(&err, err.code, NULL);
		goto CLEANUP;
	}

	PyObject * py_map_val = NULL;
	val_to_pyobject(&err, map_key_value, &py_map_val);

CLEANUP:

	if (map_key) {
		as_val_destroy(map_key);
	}

	if (map_key_value) {
		as_val_destroy(map_key_value);
	}

	if ( err.code != AEROSPIKE_OK ) {
		PyObject * py_err = NULL, *py_key = NULL;
		PyObject *exception_type = raise_exception(&err);
		error_to_pyobject(&err, &py_err);
		if(PyObject_HasAttrString(exception_type, "key")) {
			key_to_pyobject(&err, &self->key, &py_key);
			PyObject_SetAttrString(exception_type, "key", py_key);
			Py_DECREF(py_key);
		} 
		if(PyObject_HasAttrString(exception_type, "bin")) {
			PyObject *py_bins = PyString_FromString((char *)&self->bin_name);
			PyObject_SetAttrString(exception_type, "bin", py_bins);
			Py_DECREF(py_bins);
		}
		PyErr_SetObject(exception_type, py_err);
		Py_DECREF(py_err);
		return NULL;
	}
	return py_map_val;
}