//-------------------------------------------------------
 // String Operations
 //-------------------------------------------------------
 /// <summary>
 /// Asynchronously append bin string values to existing record bin values.
 /// Create listener, call asynchronous append and return task monitor.
 /// <para>
 /// The policy specifies the transaction timeout, record expiration and how the transaction is
 /// handled when the record already exists.
 /// This call only works for string values. 
 /// </para>
 /// </summary>
 /// <param name="policy">write configuration parameters, pass in null for defaults</param>
 /// <param name="token">cancellation token</param>
 /// <param name="key">unique record identifier</param>
 /// <param name="bins">array of bin name/value pairs</param>
 /// <exception cref="AerospikeException">if queue is full</exception>
 public Task Append(WritePolicy policy, CancellationToken token, Key key, params Bin[] bins)
 {
     WriteListenerAdapter listener = new WriteListenerAdapter(token);
     Append(policy, listener, key, bins);
     return listener.Task;
 }
 //-------------------------------------------------------
 // Touch Operations
 //-------------------------------------------------------
 /// <summary>
 /// Asynchronously create record if it does not already exist.
 /// Create listener, call asynchronous touch and return task monitor.
 /// If the record exists, the record's time to expiration will be reset to the policy's 
 /// expiration.
 /// </summary>
 /// <param name="policy">write configuration parameters, pass in null for defaults</param>
 /// <param name="token">cancellation token</param>
 /// <param name="key">unique record identifier</param>
 /// <exception cref="AerospikeException">if queue is full</exception>
 public Task Touch(WritePolicy policy, CancellationToken token, Key key)
 {
     WriteListenerAdapter listener = new WriteListenerAdapter(token);
     Touch(policy, listener, key);
     return listener.Task;
 }