text:
/**
 * Client module
 *
 * This module contains the factory method for creating Client classes, and the
 * method calling code for all types of methods.
 *
 * For example, to create a client and call a method on it:
 *
 * var proto_obj = grpc.load(proto_file_path);
 * var Client = proto_obj.package.subpackage.ServiceName;
 * var client = new Client(server_address, client_credentials);
 * var call = client.unaryMethod(arguments, callback);
 *
 * @module
 */

'use strict';

var _ = require('lodash');
var arguejs = require('arguejs');

var grpc = require('./grpc_extension');

var common = require('./common');

var Metadata = require('./metadata');

var EventEmitter = require('events').EventEmitter;

var stream = require('stream');

var Readable = stream.Readable;
var Writable = stream.Writable;
var Duplex = stream.Duplex;
var util = require('util');
var version = require('../../../package.json').version;

util.inherits(ClientWritableStream, Writable);

/**
 * A stream that the client can write to. Used for calls that are streaming from
 * the client side.
 * @constructor
 * @param {grpc.Call} call The call object to send data with
 * @param {function(*):Buffer=} serialize Serialization function for writes.
 */
function ClientWritableStream(call, serialize) {
  Writable.call(this, {objectMode: true});
  this.call = call;
  this.serialize = common.wrapIgnoreNull(serialize);
  this.on('finish', function() {
    var batch = {};
    batch[grpc.opType.SEND_CLOSE_FROM_CLIENT] = true;
    call.startBatch(batch, function() {});
  });
}

/**
 * Attempt to write the given chunk. Calls the callback when done. This is an
 * implementation of a method needed for implementing stream.Writable.
 * @access private
 * @param {Buffer} chunk The chunk to write
 * @param {string} encoding Used to pass write flags
 * @param {function(Error=)} callback Called when the write is complete
 */
function _write(chunk, encoding, callback) {
  /* jshint validthis: true */
  var batch = {};
  var message;
  try {
    message = this.serialize(chunk);
  } catch (e) {
    /* Sending this error to the server and emitting it immediately on the
       client may put the call in a slightly weird state on the client side,
       but passing an object that causes a serialization failure is a misuse
       of the API anyway, so that's OK. The primary purpose here is to give the
       programmer a useful error and to stop the stream properly */
    this.call.cancelWithStatus(grpc.status.INTERNAL, "Serialization failure");
    callback(e);
  }
  if (_.isFinite(encoding)) {
    /* Attach the encoding if it is a finite number. This is the closest we
     * can get to checking that it is valid flags */
    message.grpcWriteFlags = encoding;
  }
  batch[grpc.opType.SEND_MESSAGE] = message;
  this.call.startBatch(batch, function(err, event) {
    if (err) {
      // Something has gone wrong. Stop writing by failing to call callback
      return;
    }
    callback();
  });
}

ClientWritableStream.prototype._write = _write;

util.inherits(ClientReadableStream, Readable);

/**
 * A stream that the client can read from. Used for calls that are streaming
 * from the server side.
 * @constructor
 * @param {grpc.Call} call The call object to read data with
 * @param {function(Buffer):*=} deserialize Deserialization function for reads
 */
function ClientReadableStream(call, deserialize) {
  Readable.call(this, {objectMode: true});
  this.call = call;
  this.finished = false;
  this.reading = false;
  this.deserialize = common.wrapIgnoreNull(deserialize);
  /* Status generated from reading messages from the server. Overrides the
   * status from the server if not OK */
  this.read_status = null;
  /* Status received from the server. */
  this.received_status = null;
}

/**
 * Called when all messages from the server have been processed. The status
 * parameter indicates that the call should end with that status. status
 * defaults to OK if not provided.
 * @param {Object!} status The status that the call should end with
 */
function _readsDone(status) {
  /* jshint validthis: true */
  if (!status) {
    status = {code: grpc.status.OK, details: 'OK'};
  }
  if (status.code !== grpc.status.OK) {
    this.call.cancelWithStatus(status.code, status.details);
  }
  this.finished = true;
  this.read_status = status;
  this._emitStatusIfDone();
}

ClientReadableStream.prototype._readsDone = _readsDone;

/**
 * Called to indicate that we have received a status from the server.
 */
function _receiveStatus(status) {
  /* jshint validthis: true */
  this.received_status = status;
  this._emitStatusIfDone();
}

ClientReadableStream.prototype._receiveStatus = _receiveStatus;

/**
 * If we have both processed all incoming messages and received the status from
 * the server, emit the status. Otherwise, do nothing.
 */
function _emitStatusIfDone() {
  /* jshint validthis: true */
  var status;
  if (this.read_status && this.received_status) {
    if (this.read_status.code !== grpc.status.OK) {
      status = this.read_status;
    } else {
      status = this.received_status;
    }
    if (status.code === grpc.status.OK) {
      this.push(null);
    } else {
      var error = new Error(status.details);
      error.code = status.code;
      error.metadata = status.metadata;
      this.emit('error', error);
    }
    this.emit('status', status);
  }
}

ClientReadableStream.prototype._emitStatusIfDone = _emitStatusIfDone;

/**
 * Read the next object from the stream.
 * @access private
 * @param {*} size Ignored because we use objectMode=true
 */
function _read(size) {
  /* jshint validthis: true */
  var self = this;
  /**
   * Callback to be called when a READ event is received. Pushes the data onto
   * the read queue and starts reading again if applicable
   * @param {grpc.Event} event READ event object
   */
  function readCallback(err, event) {
    if (err) {
      // Something has gone wrong. Stop reading and wait for status
      self.finished = true;
      self._readsDone();
      return;
    }
    var data = event.read;
    var deserialized;
    try {
      deserialized = self.deserialize(data);
    } catch (e) {
      self._readsDone({code: grpc.status.INTERNAL,
                       details: 'Failed to parse server response'});
      return;
    }
    if (data === null) {
      self._readsDone();
      return;
    }
    if (self.push(deserialized) && data !== null) {
      var read_batch = {};
      read_batch[grpc.opType.RECV_MESSAGE] = true;
      self.call.startBatch(read_batch, readCallback);
    } else {
      self.reading = false;
    }
  }
  if (self.finished) {
    self.push(null);
  } else {
    if (!self.reading) {
      self.reading = true;
      var read_batch = {};
      read_batch[grpc.opType.RECV_MESSAGE] = true;
      self.call.startBatch(read_batch, readCallback);
    }
  }
}

ClientReadableStream.prototype._read = _read;

util.inherits(ClientDuplexStream, Duplex);

/**
 * A stream that the client can read from or write to. Used for calls with
 * duplex streaming.
 * @constructor
 * @param {grpc.Call} call Call object to proxy
 * @param {function(*):Buffer=} serialize Serialization function for requests
 * @param {function(Buffer):*=} deserialize Deserialization function for
 *     responses
 */
function ClientDuplexStream(call, serialize, deserialize) {
  Duplex.call(this, {objectMode: true});
  this.serialize = common.wrapIgnoreNull(serialize);
  this.deserialize = common.wrapIgnoreNull(deserialize);
  this.call = call;
  /* Status generated from reading messages from the server. Overrides the
   * status from the server if not OK */
  this.read_status = null;
  /* Status received from the server. */
  this.received_status = null;
  this.on('finish', function() {
    var batch = {};
    batch[grpc.opType.SEND_CLOSE_FROM_CLIENT] = true;
    call.startBatch(batch, function() {});
  });
}

ClientDuplexStream.prototype._readsDone = _readsDone;
ClientDuplexStream.prototype._receiveStatus = _receiveStatus;
ClientDuplexStream.prototype._emitStatusIfDone = _emitStatusIfDone;
ClientDuplexStream.prototype._read = _read;
ClientDuplexStream.prototype._write = _write;

/**
 * Cancel the ongoing call
 */
function cancel() {
  /* jshint validthis: true */
  this.call.cancel();
}

ClientReadableStream.prototype.cancel = cancel;
ClientWritableStream.prototype.cancel = cancel;
ClientDuplexStream.prototype.cancel = cancel;

/**
 * Get the endpoint this call/stream is connected to.
 * @return {string} The URI of the endpoint
 */
function getPeer() {
  /* jshint validthis: true */
  return this.call.getPeer();
}

ClientReadableStream.prototype.getPeer = getPeer;
ClientWritableStream.prototype.getPeer = getPeer;
ClientDuplexStream.prototype.getPeer = getPeer;

/**
 * Get a call object built with the provided options. Keys for options are
 * 'deadline', which takes a date or number, and 'host', which takes a string
 * and overrides the hostname to connect to.
 * @param {Object} options Options map.
 */
function getCall(channel, method, options) {
  var deadline;
  var host;
  var parent;
  var propagate_flags;
  var credentials;
  if (options) {
    deadline = options.deadline;
    host = options.host;
    parent = _.get(options, 'parent.call');
    propagate_flags = options.propagate_flags;
    credentials = options.credentials;
  }
  if (deadline === undefined) {
    deadline = Infinity;
  }
  var call = new grpc.Call(channel, method, deadline, host,
                           parent, propagate_flags);
  if (credentials) {
    call.setCredentials(credentials);
  }
  return call;
}

/**
 * Get a function that can make unary requests to the specified method.
 * @param {string} method The name of the method to request
 * @param {function(*):Buffer} serialize The serialization function for inputs
 * @param {function(Buffer)} deserialize The deserialization function for
 *     outputs
 * @return {Function} makeUnaryRequest
 */
function makeUnaryRequestFunction(method, serialize, deserialize) {
  /**
   * Make a unary request with this method on the given channel with the given
   * argument, callback, etc.
   * @this {Client} Client object. Must have a channel member.
   * @param {*} argument The argument to the call. Should be serializable with
   *     serialize
   * @param {Metadata=} metadata Metadata to add to the call
   * @param {Object=} options Options map
   * @param {function(?Error, value=)} callback The callback to for when the
   *     response is received
   * @return {EventEmitter} An event emitter for stream related events
   */
  function makeUnaryRequest(argument, metadata, options, callback) {
    /* jshint validthis: true */
    /* While the arguments are listed in the function signature, those variables
     * are not used directly. Instead, ArgueJS processes the arguments
     * object. This allows for simple handling of optional arguments in the
     * middle of the argument list, and also provides type checking. */
    var args = arguejs({argument: null, metadata: [Metadata, new Metadata()],
                        options: [Object], callback: Function}, arguments);
    var emitter = new EventEmitter();
    var call = getCall(this.$channel, method, args.options);
    metadata = args.metadata.clone();
    emitter.cancel = function cancel() {
      call.cancel();
    };
    emitter.getPeer = function getPeer() {
      return call.getPeer();
    };
    var client_batch = {};
    var message = serialize(args.argument);
    if (args.options) {
      message.grpcWriteFlags = args.options.flags;
    }

    client_batch[grpc.opType.SEND_INITIAL_METADATA] =
        metadata._getCoreRepresentation();
    client_batch[grpc.opType.SEND_MESSAGE] = message;
    client_batch[grpc.opType.SEND_CLOSE_FROM_CLIENT] = true;
    client_batch[grpc.opType.RECV_INITIAL_METADATA] = true;
    client_batch[grpc.opType.RECV_MESSAGE] = true;
    client_batch[grpc.opType.RECV_STATUS_ON_CLIENT] = true;
    call.startBatch(client_batch, function(err, response) {
      response.status.metadata = Metadata._fromCoreRepresentation(
          response.status.metadata);
      var status = response.status;
      var error;
      var deserialized;
      emitter.emit('metadata', Metadata._fromCoreRepresentation(
          response.metadata));
      if (status.code === grpc.status.OK) {
        if (err) {
          // Got a batch error, but OK status. Something went wrong
          args.callback(err);
          return;
        } else {
          try {
            deserialized = deserialize(response.read);
          } catch (e) {
            /* Change status to indicate bad server response. This will result
             * in passing an error to the callback */
            status = {
              code: grpc.status.INTERNAL,
              details: 'Failed to parse server response'
            };
          }
        }
      }
      if (status.code !== grpc.status.OK) {
        error = new Error(status.details);
        error.code = status.code;
        error.metadata = status.metadata;
        args.callback(error);
      } else {
        args.callback(null, deserialized);
      }
      emitter.emit('status', status);
    });
    return emitter;
  }
  return makeUnaryRequest;
}

/**
 * Get a function that can make client stream requests to the specified method.
 * @param {string} method The name of the method to request
 * @param {function(*):Buffer} serialize The serialization function for inputs
 * @param {function(Buffer)} deserialize The deserialization function for
 *     outputs
 * @return {Function} makeClientStreamRequest
 */
function makeClientStreamRequestFunction(method, serialize, deserialize) {
  /**
   * Make a client stream request with this method on the given channel with the
   * given callback, etc.
   * @this {Client} Client object. Must have a channel member.
   * @param {Metadata=} metadata Array of metadata key/value pairs to add to the
   *     call
   * @param {Object=} options Options map
   * @param {function(?Error, value=)} callback The callback to for when the
   *     response is received
   * @return {EventEmitter} An event emitter for stream related events
   */
  function makeClientStreamRequest(metadata, options, callback) {
    /* jshint validthis: true */
    /* While the arguments are listed in the function signature, those variables
     * are not used directly. Instead, ArgueJS processes the arguments
     * object. This allows for simple handling of optional arguments in the
     * middle of the argument list, and also provides type checking. */
    var args = arguejs({metadata: [Metadata, new Metadata()],
                        options: [Object], callback: Function}, arguments);
    var call = getCall(this.$channel, method, args.options);
    metadata = args.metadata.clone();
    var stream = new ClientWritableStream(call, serialize);
    var metadata_batch = {};
    metadata_batch[grpc.opType.SEND_INITIAL_METADATA] =
        metadata._getCoreRepresentation();
    metadata_batch[grpc.opType.RECV_INITIAL_METADATA] = true;
    call.startBatch(metadata_batch, function(err, response) {
      if (err) {
        // The call has stopped for some reason. A non-OK status will arrive
        // in the other batch.
        return;
      }
      stream.emit('metadata', Metadata._fromCoreRepresentation(
          response.metadata));
    });
    var client_batch = {};
    client_batch[grpc.opType.RECV_MESSAGE] = true;
    client_batch[grpc.opType.RECV_STATUS_ON_CLIENT] = true;
    call.startBatch(client_batch, function(err, response) {
      response.status.metadata = Metadata._fromCoreRepresentation(
          response.status.metadata);
      var status = response.status;
      var error;
      var deserialized;
      if (status.code === grpc.status.OK) {
        if (err) {
          // Got a batch error, but OK status. Something went wrong
          args.callback(err);
          return;
        } else {
          try {
            deserialized = deserialize(response.read);
          } catch (e) {
            /* Change status to indicate bad server response. This will result
             * in passing an error to the callback */
            status = {
              code: grpc.status.INTERNAL,
              details: 'Failed to parse server response'
            };
          }
        }
      }
      if (status.code !== grpc.status.OK) {
        error = new Error(response.status.details);
        error.code = status.code;
        error.metadata = status.metadata;
        args.callback(error);
      } else {
        args.callback(null, deserialized);
      }
      stream.emit('status', status);
    });
    return stream;
  }
  return makeClientStreamRequest;
}

/**
 * Get a function that can make server stream requests to the specified method.
 * @param {string} method The name of the method to request
 * @param {function(*):Buffer} serialize The serialization function for inputs
 * @param {function(Buffer)} deserialize The deserialization function for
 *     outputs
 * @return {Function} makeServerStreamRequest
 */
function makeServerStreamRequestFunction(method, serialize, deserialize) {
  /**
   * Make a server stream request with this method on the given channel with the
   * given argument, etc.
   * @this {SurfaceClient} Client object. Must have a channel member.
   * @param {*} argument The argument to the call. Should be serializable with
   *     serialize
   * @param {Metadata=} metadata Array of metadata key/value pairs to add to the
   *     call
   * @param {Object} options Options map
   * @return {EventEmitter} An event emitter for stream related events
   */
  function makeServerStreamRequest(argument, metadata, options) {
    /* jshint validthis: true */
    /* While the arguments are listed in the function signature, those variables
     * are not used directly. Instead, ArgueJS processes the arguments
     * object. */
    var args = arguejs({argument: null, metadata: [Metadata, new Metadata()],
                        options: [Object]}, arguments);
    var call = getCall(this.$channel, method, args.options);
    metadata = args.metadata.clone();
    var stream = new ClientReadableStream(call, deserialize);
    var start_batch = {};
    var message = serialize(args.argument);
    if (args.options) {
      message.grpcWriteFlags = args.options.flags;
    }
    start_batch[grpc.opType.SEND_INITIAL_METADATA] =
        metadata._getCoreRepresentation();
    start_batch[grpc.opType.RECV_INITIAL_METADATA] = true;
    start_batch[grpc.opType.SEND_MESSAGE] = message;
    start_batch[grpc.opType.SEND_CLOSE_FROM_CLIENT] = true;
    call.startBatch(start_batch, function(err, response) {
      if (err) {
        // The call has stopped for some reason. A non-OK status will arrive
        // in the other batch.
        return;
      }
      stream.emit('metadata', Metadata._fromCoreRepresentation(
          response.metadata));
    });
    var status_batch = {};
    status_batch[grpc.opType.RECV_STATUS_ON_CLIENT] = true;
    call.startBatch(status_batch, function(err, response) {
      if (err) {
        stream.emit('error', err);
        return;
      }
      response.status.metadata = Metadata._fromCoreRepresentation(
          response.status.metadata);
      stream._receiveStatus(response.status);
    });
    return stream;
  }
  return makeServerStreamRequest;
}

/**
 * Get a function that can make bidirectional stream requests to the specified
 * method.
 * @param {string} method The name of the method to request
 * @param {function(*):Buffer} serialize The serialization function for inputs
 * @param {function(Buffer)} deserialize The deserialization function for
 *     outputs
 * @return {Function} makeBidiStreamRequest
 */
function makeBidiStreamRequestFunction(method, serialize, deserialize) {
  /**
   * Make a bidirectional stream request with this method on the given channel.
   * @this {SurfaceClient} Client object. Must have a channel member.
   * @param {Metadata=} metadata Array of metadata key/value pairs to add to the
   *     call
   * @param {Options} options Options map
   * @return {EventEmitter} An event emitter for stream related events
   */
  function makeBidiStreamRequest(metadata, options) {
    /* jshint validthis: true */
    /* While the arguments are listed in the function signature, those variables
     * are not used directly. Instead, ArgueJS processes the arguments
     * object. */
    var args = arguejs({metadata: [Metadata, new Metadata()],
                        options: [Object]}, arguments);
    var call = getCall(this.$channel, method, args.options);
    metadata = args.metadata.clone();
    var stream = new ClientDuplexStream(call, serialize, deserialize);
    var start_batch = {};
    start_batch[grpc.opType.SEND_INITIAL_METADATA] =
        metadata._getCoreRepresentation();
    start_batch[grpc.opType.RECV_INITIAL_METADATA] = true;
    call.startBatch(start_batch, function(err, response) {
      if (err) {
        // The call has stopped for some reason. A non-OK status will arrive
        // in the other batch.
        return;
      }
      stream.emit('metadata', Metadata._fromCoreRepresentation(
          response.metadata));
    });
    var status_batch = {};
    status_batch[grpc.opType.RECV_STATUS_ON_CLIENT] = true;
    call.startBatch(status_batch, function(err, response) {
      if (err) {
        stream.emit('error', err);
        return;
      }
      response.status.metadata = Metadata._fromCoreRepresentation(
          response.status.metadata);
      stream._receiveStatus(response.status);
    });
    return stream;
  }
  return makeBidiStreamRequest;
}

/**
 * Map with short names for each of the requester maker functions. Used in
 * makeClientConstructor
 */
var requester_makers = {
  unary: makeUnaryRequestFunction,
  server_stream: makeServerStreamRequestFunction,
  client_stream: makeClientStreamRequestFunction,
  bidi: makeBidiStreamRequestFunction
};

function getDefaultValues(metadata, options) {
  var res = {};
  res.metadata = metadata || new Metadata();
  res.options = options || {};
  return res;
}

/**
 * Map with wrappers for each type of requester function to make it use the old
 * argument order with optional arguments after the callback.
 */
var deprecated_request_wrap = {
  unary: function(makeUnaryRequest) {
    return function makeWrappedUnaryRequest(argument, callback,
                                            metadata, options) {
      /* jshint validthis: true */
      var opt_args = getDefaultValues(metadata, metadata);
      return makeUnaryRequest.call(this, argument, opt_args.metadata,
                                   opt_args.options, callback);
    };
  },
  client_stream: function(makeServerStreamRequest) {
    return function makeWrappedClientStreamRequest(callback, metadata,
                                                   options) {
      /* jshint validthis: true */
      var opt_args = getDefaultValues(metadata, options);
      return makeServerStreamRequest.call(this, opt_args.metadata,
                                          opt_args.options, callback);
    };
  },
  server_stream: _.identity,
  bidi: _.identity
};

/**
 * Creates a constructor for a client with the given methods. The methods object
 * maps method name to an object with the following keys:
 * path: The path on the server for accessing the method. For example, for
 *     protocol buffers, we use "/service_name/method_name"
 * requestStream: bool indicating whether the client sends a stream
 * resonseStream: bool indicating whether the server sends a stream
 * requestSerialize: function to serialize request objects
 * responseDeserialize: function to deserialize response objects
 * @param {Object} methods An object mapping method names to method attributes
 * @param {string} serviceName The fully qualified name of the service
 * @param {Object} class_options An options object. Currently only uses the key
 *     deprecatedArgumentOrder, a boolean that Indicates that the old argument
 *     order should be used for methods, with optional arguments at the end
 *     instead of the callback at the end. Defaults to false. This option is
 *     only a temporary stopgap measure to smooth an API breakage.
 *     It is deprecated, and new code should not use it.
 * @return {function(string, Object)} New client constructor
 */
exports.makeClientConstructor = function(methods, serviceName,
                                         class_options) {
  if (!class_options) {
    class_options = {};
  }
  /**
   * Create a client with the given methods
   * @constructor
   * @param {string} address The address of the server to connect to
   * @param {grpc.Credentials} credentials Credentials to use to connect
   *     to the server
   * @param {Object} options Options to pass to the underlying channel
   */
  function Client(address, credentials, options) {
    if (!options) {
      options = {};
    }
    /* Append the grpc-node user agent string after the application user agent
     * string, and put the combination at the beginning of the user agent string
     */
    if (options['grpc.primary_user_agent']) {
      options['grpc.primary_user_agent'] += ' ';
    } else {
      options['grpc.primary_user_agent'] = '';
    }
    options['grpc.primary_user_agent'] += 'grpc-node/' + version;
    /* Private fields use $ as a prefix instead of _ because it is an invalid
     * prefix of a method name */
    this.$channel = new grpc.Channel(address, credentials, options);
  }

  _.each(methods, function(attrs, name) {
    var method_type;
    if (_.startsWith(name, '$')) {
      throw new Error('Method names cannot start with $');
    }
    if (attrs.requestStream) {
      if (attrs.responseStream) {
        method_type = 'bidi';
      } else {
        method_type = 'client_stream';
      }
    } else {
      if (attrs.responseStream) {
        method_type = 'server_stream';
      } else {
        method_type = 'unary';
      }
    }
    var serialize = attrs.requestSerialize;
    var deserialize = attrs.responseDeserialize;
    var method_func = requester_makers[method_type](
        attrs.path, serialize, deserialize);
    if (class_options.deprecatedArgumentOrder) {
      Client.prototype[name] = deprecated_request_wrap(method_func);
    } else {
      Client.prototype[name] = method_func;
    }
    // Associate all provided attributes with the method
    _.assign(Client.prototype[name], attrs);
  });

  return Client;
};

/**
 * Return the underlying channel object for the specified client
 * @param {Client} client
 * @return {Channel} The channel
 */
exports.getClientChannel = function(client) {
  return client.$channel;
};

/**
 * Wait for the client to be ready. The callback will be called when the
 * client has successfully connected to the server, and it will be called
 * with an error if the attempt to connect to the server has unrecoverablly
 * failed or if the deadline expires. This function will make the channel
 * start connecting if it has not already done so.
 * @param {Client} client The client to wait on
 * @param {(Date|Number)} deadline When to stop waiting for a connection. Pass
 *     Infinity to wait forever.
 * @param {function(Error)} callback The callback to call when done attempting
 *     to connect.
 */
exports.waitForClientReady = function(client, deadline, callback) {
  var checkState = function(err) {
    if (err) {
      callback(new Error('Failed to connect before the deadline'));
      return;
    }
    var new_state = client.$channel.getConnectivityState(true);
    if (new_state === grpc.connectivityState.READY) {
      callback();
    } else if (new_state === grpc.connectivityState.FATAL_FAILURE) {
      callback(new Error('Failed to connect to server'));
    } else {
      client.$channel.watchConnectivityState(new_state, deadline, checkState);
    }
  };
  checkState();
};

/**
 * Creates a constructor for clients for the given service
 * @param {ProtoBuf.Reflect.Service} service The service to generate a client
 *     for
 * @param {Object=} options Options to apply to the client
 * @return {function(string, Object)} New client constructor
 */
exports.makeProtobufClientConstructor =  function(service, options) {
  var method_attrs = common.getProtobufServiceAttrs(service, options);
  var deprecatedArgumentOrder = false;
  if (options) {
    deprecatedArgumentOrder = options.deprecatedArgumentOrder;
  }
  var Client = exports.makeClientConstructor(
      method_attrs, common.fullyQualifiedName(service),
      deprecatedArgumentOrder);
  Client.service = service;
  Client.service.grpc_options = options;
  return Client;
};

/**
 * Map of status code names to status codes
 */
exports.status = grpc.status;

/**
 * See docs for client.callError
 */
exports.callError = grpc.callError;


text:
title: New games and tutorials 👾
---

A few new games have been added to the [showcase](/showcase):
- [Flappy Bird](https://github.com/tiagopog/flappy_bird) by [Tiago Guedes](https://github.com/tiagopog)
- [Tetris](https://github.com/Nakilon/rbtris) by [Victor Maslov](https://github.com/Nakilon)

Also, [Mario Visic](https://github.com/mariovisic) is out with a new tutorial on [collision detection](https://www.youtube.com/watch?v=e3B8m4vBzB0).

redpajama_set_name: RedPajamaGithub


text:
package systems;

import com.artemis.Aspect;
import com.artemis.ComponentMapper;
import com.artemis.Entity;
import com.artemis.annotations.Mapper;
import com.artemis.systems.EntityProcessingSystem;

import components.ColorAnimation;
import components.Sprite;

public class ColorAnimationSystem extends EntityProcessingSystem {

    @Mapper
    ComponentMapper<ColorAnimation> cam;
    @Mapper
    ComponentMapper<Sprite> sm;

    @SuppressWarnings("unchecked")
    public ColorAnimationSystem() {
        super(Aspect.getAspectForAll(ColorAnimation.class, Sprite.class));
    }

    @Override
    protected void process(Entity entity) {
        ColorAnimation c = cam.get(entity);
        Sprite sprite = sm.get(entity);

        if (c.alphaAnimate) {

            sprite.a += c.alphaSpeed * world.delta;

            if (sprite.a > c.alphaMax) {
                sprite.a = c.alphaMax;
                if (c.repeat) {
                    c.alphaSpeed = -c.alphaSpeed;
                } else {
                    c.alphaAnimate = false;
                }
            } else if (sprite.a < c.alphaMin) {
                sprite.a = c.alphaMin;
                if (c.repeat) {
                    c.alphaSpeed = -c.alphaSpeed;
                } else {
                    c.alphaAnimate = false;
                }
            }

            if (c.redAnimate) {
                sprite.r += c.redSpeed * world.delta;
                if (sprite.r > c.redMax) {
                    sprite.r = c.redMax;
                    if (c.repeat) {
                        c.redSpeed = -c.redSpeed;
                    }
                } else {
                    c.redAnimate = false;
                }
            } else if (sprite.r < c.redMin) {
                sprite.r = c.redMin;
                if (c.repeat) {
                    c.redSpeed = -c.redSpeed;
                } else {
                    c.redAnimate = false;
                }
            }
        }
        if (c.greenAnimate) {
            sprite.g += c.greenSpeed * world.delta;

            if (sprite.g > c.greenMax) {
                sprite.g = c.greenMax;
                if (c.repeat) {
                    c.greenSpeed = -c.greenSpeed;
                } else {
                    c.greenAnimate = false;
                }
            } else if (sprite.g < c.greenMin) {
                sprite.g = c.greenMin;
                if (c.repeat) {
                    c.greenSpeed = -c.greenSpeed;
                } else {
                    c.greenAnimate = false;
                }
            }
        }

        if (c.blueAnimate) {
            sprite.b += c.blueSpeed * world.delta;

            if (sprite.b > c.blueMax) {
                sprite.b = c.blueMax;
                if (c.repeat) {
                    c.blueSpeed = -c.blueSpeed;
                } else {
                    c.blueAnimate = false;
                }
            } else if (sprite.b < c.blueMin) {
                sprite.b = c.blueMin;
                if (c.repeat) {
                    c.blueSpeed = -c.blueSpeed;
                } else {
                    c.blueAnimate = false;
                }
            }
        }
    }
}


text:
module Gitlactica
  module GitHub
    module Auth
      extend self

      def authenticatable?
        !(username.empty? && password.empty?)
      end

      def username
        @username ||= details.fetch('username', '')
      end

      def password
        @password ||= details.fetch('password', '')
      end

      private

      def details
        @details ||= Config.auth.fetch('github', {})
      end
    end
  end
end


text:
// Copyright 2019 The Oppia Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/**
 * @fileoverview A data service that stores the current interaction id.
 */

// TODO(sll): Add validation.
angular.module('oppia').factory('StateInteractionIdService', [
  'StatePropertyService', function(StatePropertyService) {
    var child = Object.create(StatePropertyService);
    child.setterMethodKey = 'saveInteractionId';
    return child;
  }
]);


text:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>com.github.groupon.monsoon</groupId>
        <artifactId>monsoon-collectors</artifactId>
        <version>2.4-SNAPSHOT</version>
    </parent>
    <artifactId>monsoon-collector-http</artifactId>
    <packaging>jar</packaging>
    <name>Mon-soon collector: HTTP</name>
    <url>https://github.com/groupon/monsoon</url>

    <scm>
        <connection>scm:git:github.com:groupon/monsoon.git</connection>
        <developerConnection>scm:git:github.com:groupon/monsoon.git</developerConnection>
        <url>https://github.com/groupon/monsoon</url>
        <tag>HEAD</tag>
    </scm>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.build.targetJdk>1.8</project.build.targetJdk>
    </properties>

    <dependencies>
        <dependency>
            <groupId>joda-time</groupId>
            <artifactId>joda-time</artifactId>
            <version>2.8</version>
        </dependency>
        <dependency>
           <groupId>org.apache.httpcomponents</groupId>
           <artifactId>httpasyncclient</artifactId>
           <version>4.1.1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpcore-nio</artifactId>
            <version>4.4.4</version>
        </dependency>
        <dependency>
            <groupId>com.google.code.gson</groupId>
            <artifactId>gson</artifactId>
            <version>2.4</version>
        </dependency>
        <dependency>
            <groupId>org.mock-server</groupId>
            <artifactId>mockserver-netty</artifactId>
            <version>3.10.4</version>
	    <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>javax.servlet</groupId>
                    <artifactId>javax.servlet-api</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <!-- Optional dep for mock-server -->
            <groupId>javassist</groupId>
            <artifactId>javassist</artifactId>
            <version>3.12.1.GA</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <finalName>${project.artifactId}</finalName>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.2</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <compilerReuseStrategy>alwaysNew</compilerReuseStrategy>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-javadoc-plugin</artifactId>
                <version>2.10.3</version>
                <configuration>
                    <source>1.8</source>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <version>2.6</version>
                <configuration>
                    <archive>
                        <index>true</index>
                    </archive>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>


text:
'use strict';

// https://developers.google.com/gmail/xoauth2_protocol

/**
 * @help Enables XOAUTH2 capability
 * @help Implementation difference
 * @help SASL-IR enabled and used while Gmail does not
 * @help Valid login info:
 * @help   Username: testuser
 * @help   Access Token: testtoken
 */

module.exports = function(server) {
    // Register capability, usable for non authenticated users
    server.registerCapability('AUTH=XOAUTH2', function(connection) {
        return connection.state == 'Not Authenticated';
    });

    server.setCommandHandler('AUTHENTICATE XOAUTH2', function(connection, parsed, data, callback) {

        // Not allowed if already logged in
        if (connection.state != 'Not Authenticated') {
            connection.send({
                tag: parsed.tag,
                command: 'BAD',
                attributes:[
                    {type: 'TEXT', value: 'Already authenticated, identity change not allowed'}
                ]
            }, 'AUTHENTICATE XOAUTH2 FAILED', parsed, data);
            return callback();
        }

        if (!server.capabilities['SASL-IR'] || !server.capabilities['SASL-IR'](connection)) {
            connection.send({
                tag: parsed.tag,
                command: 'BAD',
                attributes:[
                    {type: 'TEXT', value: 'SASL-IR must be enabled to support XOAUTH2'}
                ]
            }, 'AUTHENTICATE XOAUTH2 FAILED', parsed, data);
            return callback();
        }

        if (parsed.attributes.length != 1 ||
            !parsed.attributes[0] ||
            ['STRING', 'ATOM'].indexOf(parsed.attributes[0].type) < 0
            ) {
            connection.send({
                tag: parsed.tag,
                command: 'NO',
                attributes:[
                    {type: 'TEXT', value: 'Invalid SASL argument'}
                ]
            }, 'AUTHENTICATE XOAUTH2 FAILED', parsed, data);
            return callback();
        }

        var parts = new Buffer(parsed.attributes[0].value, 'base64').toString('utf-8').split('\x01'),
            username = (parts[0] || '').substr(5),
            accessToken = (parts[1] || '').substr(12);

        if (parts.length != 4 ||
            !parts[0].match(/^user\=/) ||
            !parts[1].match(/^auth\=Bearer /) ||
            !user ||  // Must be present
            !accessToken ||  // Must be present
            parts[2] ||  // Must be empty
            parts[3] // Must be empty
            ) {

            connection.send({
                tag: parsed.tag,
                command: 'NO',
                attributes:[
                    {type: 'TEXT', value: 'Invalid SASL argument.'}
                ]
            }, 'AUTHENTICATE XOAUTH2 FAILED', parsed, data);
            return callback();
        }

        connection.storage.user_get(username, function(err, user) {
            if (err || user == null) {
                connection.send({
                    tag: parsed.tag,
                    command: 'NO',
                    attributes:[
                        {type: 'TEXT', value: 'Invalid credentials'}
                    ]
                }, 'AUTHENTICATE XOAUTH2 FAILED', parsed, data);
                return callback();
            } else {
                if (!user || !user.xoauth2 || user.xoauth2.accessToken != accessToken) {
                    connection.send({
                        tag: '+',
                        attributes:[
                            {type: 'ATOM', value: new Buffer(JSON.stringify({
                                'status':'400',
                                'schemes':'Bearer',
                                'scope':'https://mail.google.com/'
                            })).toString('base64')}
                        ]
                    }, 'AUTHENTICATE XOAUTH2 FAILED', parsed, data);

                    // wait for response
                    connection.inputHandler = function() {
                        connection.inputHandler = false;
                        connection.send({
                            tag: parsed.tag,
                            command: 'NO',
                            attributes:[
                                {type: 'TEXT', value: 'SASL authentication failed'}
                            ]
                        }, 'AUTHENTICATE XOAUTH2 FAILED', parsed, data);
                    };
                } else {
                    connection.state = 'Authenticated';
                    connection.user = user;
					connection.onAuthenticated(user);

                    connection.send({
                        tag: parsed.tag,
                        command: 'OK',
                        attributes:[
                            {type: 'TEXT', value: 'User logged in'}
                        ]
                    }, 'AUTHENTICATE XOAUTH2 SUCCESS', parsed, data);

                }
                return callback();
            }
        });
    });
};


text:
Assignment: ARP
===============

.. epigraph::

    The world is a jungle in general, and the networking game contributes many
    animals.

    --David C. Plummer [#]_

Overview
--------

This assignment is part of the :doc:`/teaching/Networking-With-Xinu` track for
professors that are :doc:`teaching with Xinu </teaching/index>` and it is
intended to be completed in groups of two or three.

Preparation
-----------

A new tar-ball is provided with a solution to the previous assignment.
If your solution is similar to the one presented, you may choose to
continue on with it; but it is suggested that you untar the new project
files in a fresh working directory: ``tar xvzf``

Address Resolution Protocol
---------------------------

Standard 37 of the :rfc:`Internet Official Protocol Standards <5000>` is the
:wikipedia:`Address Resolution Protocol`. In this assignment students will build
the Address Resolution Protocol into Embedded Xinu.

Upon completion of the assignment the students' implementation should:

Required Assignment Parts
-------------------------

-  add and remove ARP table entries
-  send, receive and process ARP requests
-  have ARP entries time out and be removed
-  lookup MAC address from table (given an IP) and return it to help
   fill in packets before sending them

Optional Assignment Parts
-------------------------

-  shell integration: add an **arp** command to the shell

   -  options for: adding entry, removing entry, sending request and
      clearing the table

If you choose not to implement the optional assignment parts then
placing test case code within the shell's 'test' command will allow you
to run one or more tests on your implementation at run-time. Optional
portions to an assignment may be required portions of a later
assignment.

Student Outcomes
----------------

Upon completion of this assignment students should understand the key
role this protocol plays in the overall networking architecture. Each
student should be able to understand what an Internet Protocol address
is and how the protocol uses this address to acquire a MAC address for
the network packet before it can proceed through the system and be sent
out over the network.

Potential References
--------------------

- :rfc:`826`
- :wikipedia:`Address Resolution Protocol`

Notes
-----
.. [#] :rfc:`826`


text:
enum {
    M_FIELD_PTARMCHAN_HEIGHT,
    M_FIELD_PTARMCHAN_BINDEX,
    M_FIELD_PTARMCHAN_MINEDHASH,
    //
    M_FIELD_PTARMCHAN_MAX,
};

enum {
    M_FIELD_SEARCHOUTPOINT_HEIGHT,
    M_FIELD_SEARCHOUTPOINT_TX,
    //
    M_FIELD_SEARCHOUTPOINT_MAX
};

static JNIEnv *env;
static JavaVM *jvm;

//GlobalRef
static jclass hash_cls;
static jclass arraylist_cls;
static jclass system_cls;
static jobject ptarm_obj;

static jmethodID ptarm_method[METHOD_PTARM_MAX];
static jmethodID arraylist_ctor_method;
static jmethodID arraylist_add_method;
static jmethodID list_get_method;
static jmethodID list_size_method;
static jmethodID system_exit_method;
static jfieldID ptarmcls_field[M_FIELD_PTARMCHAN_MAX];
static jfieldID searchoutpoint_field[M_FIELD_SEARCHOUTPOINT_MAX];

static bool mExceptionHappen;

static jbyteArray buf2jbarray(const btcj_buf_t *buf);
static btcj_buf_t* jbarray2buf(jbyteArray jbarray);
static jobject bufs2list(const btcj_buf_t *bufs);
static btcj_buf_t* list2bufs(jobject list);
static inline void _check_exception(JNIEnv *env, const char *pFuncName, int Line);

const struct {
    const char *name;
    const char *sig;
} kMethod[METHOD_PTARM_MAX] = {
    // METHOD_PTARM_SPV_START,
    { "spv_start", "(Ljava/lang/String;)I" },
    // METHOD_PTARM_SETCREATIONHASH,
    { "setCreationHash", "([B)V" },
    // METHOD_PTARM_GETBLOCKCOUNT,
    { "getBlockCount", "([B)I" },
    // METHOD_PTARM_GETGENESISBLOCKHASH,
    { "getGenesisBlockHash", "()[B" },
    // METHOD_PTARM_GETCONFIRMATION,
    { "getTxConfirmation", "([BI[BJ)I" },
    // METHOD_PTARM_GETSHORTCHANNELPARAM,
    { "getShortChannelParam", "([B)Lco/nayuta/lightning/ShortChannelParam;" },
    // // METHOD_PTARM_GETTXIDFROMSHORTCHANNELID,
    // { "getTxidFromShortChannelId", "(J)[B" },
    // METHOD_PTARM_SEARCHOUTPOINT,
    { "searchOutPoint", "(I[BI)Lco/nayuta/lightning/SearchOutPointResult;" },
    // METHOD_PTARM_SEARCHVOUT,
    { "searchVout", "(ILjava/util/List;)Ljava/util/List;" },
    // METHOD_PTARM_SIGNRAWTX,
    { "signRawTx", "(J[B)[B" },
    // METHOD_PTARM_SENDRAWTX,
    { "sendRawTx", "([B)[B" },
    // METHOD_PTARM_CHECKBROADCAST,
    { "checkBroadcast", "([B[B)Z" },
    // METHOD_PTARM_CHECKUNSPENT,
    { "checkUnspent", "([B[BI)I" },
    // METHOD_PTARM_GETNEWADDRESS,
    { "getNewAddress", "()Ljava/lang/String;" },
    // METHOD_PTARM_ESTIMATEFEE,
    { "estimateFee", "()J" },
    // METHOD_PTARM_SETCHANNEL,
    { "setChannel", "([BJ[BI[B[BI)Z" },
    // METHOD_PTARM_DELCHANNEL,
    { "delChannel", "([B)V" },
    // // METHOD_PTARM_SETCOMMITTXID,
    // { "setCommitTxid", "([BIILorg/bitcoinj/core/Sha256Hash;)V" },
    // METHOD_PTARM_GETBALANCE,
    { "getBalance", "()J" },
    // METHOD_PTARM_EMPTYWALLET,
    { "emptyWallet", "(Ljava/lang/String;)[B" },
    // METHOD_PARAM_EXIT
    { NULL, NULL },
    // METHOD_PTARM_REMOVESUSPENDBLOCK
    { "removeSuspendBlock", "()V" },
};

const struct {
    const char *name;
    const char *sig;
} kField[M_FIELD_PTARMCHAN_MAX] = {
    // M_FIELD_PTARMCHAN_HEIGHT,
    { "height", "I" },
    // M_FIELD_PTARMCHAN_BINDEX,
    { "bIndex", "I" },
    // M_FIELD_PTARMCHAN_MINEDHASH,
    { "minedHash", "[B" },
}, kFieldSearchOutpoint[M_FIELD_SEARCHOUTPOINT_MAX] = {
    // M_FIELD_SEARCHOUTPOINT_HEIGHT,
    { "height", "I" },
    // M_FIELD_SEARCHOUTPOINT_TX,
    { "tx", "[B" },
};

//-----------------------------------------------------------------------------
bool btcj_init(btc_block_chain_t Gen)
{
    mExceptionHappen = false;
    jclass cls;
    char optjar[PATH_MAX];
    snprintf(optjar, sizeof(optjar),
             "-Djava.class.path=%s/jar/bitcoinj-ptarmigan.jar",
             ptarmd_execpath_get());
    LOGD("optjar=%s\n", optjar);

    JavaVMOption opt[9];
    // .classファイルを配置するディレクトリか、.jarファイルのパスを指定する
    opt[0].optionString = optjar;
    // https://stackoverflow.com/questions/14544991/how-to-configure-slf4j-simple
    opt[1].optionString = "-Dorg.slf4j.simpleLogger.defaultLogLevel=warn";
    opt[2].optionString = "-Dorg.slf4j.simpleLogger.log.co.nayuta.lightning=debug";
    opt[3].optionString = "-Dorg.slf4j.simpleLogger.showDateTime=true";
    opt[4].optionString = "-Dorg.slf4j.simpleLogger.dateTimeFormat=yyyy-MM-dd'T'HH:mm:ssZ";
    opt[5].optionString = "-DsimpleLogger.showThreadName=false";
    opt[6].optionString = "-DsimpleLogger.showLogName=false";
    opt[7].optionString = "-Dorg.slf4j.simpleLogger.showShortLogName=true";
    opt[8].optionString = "-Dorg.slf4j.simpleLogger.logFile=System.out";
    //
    JavaVMInitArgs vm_args = {
        .version = JNI_VERSION_1_8,
        .options = opt,
        .nOptions = ARRAY_SIZE(opt)
    };
    // JVM初期化
    LOGD("JNI_CreateJavaVM\n");
    int ret = JNI_CreateJavaVM(&jvm, (void**)&env, (void*)&vm_args);
    if (ret != JNI_OK) {
        // jvm.dllへのパスが通っていない場合など
        LOGD("btcj_init() Error: JNI_CreateJavaVM() = %d\n", ret);
        return false;
    }

    //
    system_cls = (*env)->FindClass(env, "java/lang/System");
    if (system_cls == NULL) {
        LOGE("fail: FindClass()\n");
        return false;
    }
    system_exit_method = (*env)->GetStaticMethodID(env, system_cls, "exit", "(I)V");
    if (system_exit_method == NULL) {
        LOGE("fail: GetMethodID()\n");
        return false;
    }

    LOGD("Class: Ptarmigan\n");

    // クラス検索
    cls = (*env)->FindClass(env, "co/nayuta/lightning/Ptarmigan");
    if (cls == NULL) {
        LOGE("fail: FindClass()\n");
        return false;
    }

    // コンストラクタ呼び出し
    LOGD("call ctor\n");
    jmethodID method = (*env)->GetMethodID(env, cls, "<init>", "()V");
    if ((*env)->ExceptionCheck(env) || (method == NULL)) {
        LOGE("fail: ctor\n");
        return false;
    }
    jobject obj = (*env)->NewObject(env, cls, method);
    if (obj == NULL) {
        LOGE("fail: NewObject\n");
        return false;
    }
    ptarm_obj = (jobject)(*env)->NewGlobalRef(env, obj);
    (*env)->DeleteLocalRef(env, obj);
    //
    LOGD("get methods\n");
    for (size_t lp = 0; lp < ARRAY_SIZE(kMethod); lp++) {
        if (kMethod[lp].name != NULL) {
            ptarm_method[lp] = (*env)->GetMethodID(
                                   env, cls,
                                   kMethod[lp].name,
                                   kMethod[lp].sig);
            if (ptarm_method[lp] == NULL) {
                LOGE("fail: get method id(%s)\n", kMethod[lp].name);
                return false;
            }
        }
    }

    LOGD("Class: ShortChannelParam\n");
    cls = (*env)->FindClass(env, "co/nayuta/lightning/ShortChannelParam");
    if (cls == NULL) {
        LOGE("fail: FindClass()\n");
        return false;
    }
    //field
    //  btcj_get_short_channel_param
    LOGD("get fields\n");
    for (size_t lp = 0; lp < ARRAY_SIZE(kField); lp++) {
        ptarmcls_field[lp] = (*env)->GetFieldID(
                                 env, cls,
                                 kField[lp].name,
                                 kField[lp].sig);
        if (ptarmcls_field[lp] == NULL) {
            LOGE("fail: get field id(%s)\n", kField[lp].name);
            return false;
        }
    }

    LOGD("Class: SearchOutPointResult\n");
    cls = (*env)->FindClass(env, "co/nayuta/lightning/SearchOutPointResult");
    if (cls == NULL) {
        LOGE("fail: FindClass()\n");
        return false;
    }
    LOGD("get fields\n");
    for (size_t lp = 0; lp < ARRAY_SIZE(kFieldSearchOutpoint); lp++) {
        searchoutpoint_field[lp] = (*env)->GetFieldID(
                                       env, cls,
                                       kFieldSearchOutpoint[lp].name,
                                       kFieldSearchOutpoint[lp].sig);
        if (searchoutpoint_field[lp] == NULL) {
            LOGE("fail: get field id(%s)\n", kFieldSearchOutpoint[lp].name);
            return false;
        }
    }

    //ArrayList
    cls = (*env)->FindClass(env, "Ljava/util/ArrayList;");
    if (cls == NULL) {
        LOGE("fail: FindClass()\n");
        return false;
    }
    arraylist_cls = (jclass)(*env)->NewGlobalRef(env, cls);
    (*env)->DeleteLocalRef(env, cls);
    arraylist_ctor_method = (*env)->GetMethodID(env, arraylist_cls, "<init>", "()V");
    if (arraylist_ctor_method == NULL) {
        LOGE("fail: GetMethodID()\n");
        return false;
    }
    arraylist_add_method = (*env)->GetMethodID(env, arraylist_cls, "add", "(Ljava/lang/Object;)Z");
    if (arraylist_add_method == NULL) {
        LOGE("fail: GetMethodID()\n");
        return false;
    }

    //List
    cls = (*env)->FindClass(env, "Ljava/util/List;");
    if (cls == NULL) {
        LOGE("fail: FindClass()\n");
        return false;
    }
    list_get_method = (*env)->GetMethodID(env, cls, "get", "(I)Ljava/lang/Object;");
    if (list_get_method == NULL) {
        LOGE("fail: GetMethodID()\n");
        return false;
    }
    list_size_method = (*env)->GetMethodID(env, cls, "size", "()I");
    if (list_size_method == NULL) {
        LOGE("fail: GetMethodID()\n");
        return false;
    }

    //
    (*env)->DeleteLocalRef(env, cls);

    LOGD("SPV start\n");
    ret = btcj_spv_start(Gen);
    switch (ret) {
    case BTCJ_INI_SPV_START_OK:
        LOGD("OK!\n");
        break;
    case BTCJ_INI_SPV_START_FILE:
        fprintf(stderr, "SPV file already locked.\n");
        fprintf(stderr, "Maybe, another ptarmd is started or file unlock processing.\n");
        fprintf(stderr, "If no other ptarmd, please wait a while and start.\n");
        LOGE("fail: wallet file already locked\n");
        break;
    case BTCJ_INI_SPV_START_BJ:
        fprintf(stderr, "Failed to start SPV.\n");
        fprintf(stderr, "Please wait a while and start.\n");
        LOGE("fail: bitcoinj cannot start\n");
        break;
    case BTCJ_INI_SPV_START_ERR:
    default:
        fprintf(stderr, "Sorry, failed to start SPV.\n");
        LOGE("fail: SPV\n");
        btcj_release();
    }

    LOGD("END: %d\n", ret);
    return (ret == BTCJ_INI_SPV_START_OK);
}
//-----------------------------------------------------------------------------
bool btcj_release(void)
{
    if (env != NULL) {
        (*env)->DeleteGlobalRef(env, ptarm_obj);
        (*env)->DeleteGlobalRef(env, arraylist_cls);
        (*env)->DeleteGlobalRef(env, hash_cls);

        //待ち状態になるためコメントアウト
        // if(jvm != NULL) {
        //     (*jvm)->DestroyJavaVM(jvm);
        //     jvm = NULL;
        // }
        env = NULL;
    }
    //
    return true;
}
//-----------------------------------------------------------------------------
bool btcj_exception_happen(void)
{
    return mExceptionHappen;
}
//-----------------------------------------------------------------------------
int btcj_spv_start(btc_block_chain_t Gen)
{
    LOGD("\n");
    const char *p_chain_name;
    const btc_block_param_t *p_chain = btc_block_get_param_from_chain(Gen);
    if (p_chain != NULL) {
        p_chain_name = btc_block_get_real_chainname(p_chain->chain_name);
    } else {
        LOGE("fail: unknown genesis block hash\n");
        assert(0);
        return false;
    }
    jstring param = (*env)->NewStringUTF(env, p_chain_name);
    jint ret = (*env)->CallIntMethod(env, ptarm_obj, ptarm_method[METHOD_PTARM_SPV_START], param);
    check_exception(env);
    LOGD("ret=%d\n", ret);
    (*env)->DeleteLocalRef(env, param);
    //
    return ret;
}
//-----------------------------------------------------------------------------
void btcj_setcreationhash(const uint8_t *pHash)
{
    LOGD("\n");
    const btcj_buf_t buf = { (CONST_CAST uint8_t *)pHash, BTC_SZ_HASH256 };
    jbyteArray array = buf2jbarray(&buf);
    (*env)->CallVoidMethod(env, ptarm_obj, ptarm_method[METHOD_PTARM_SETCREATIONHASH], array);
    check_exception(env);
    //
    (*env)->DeleteLocalRef(env, array);
}
//-----------------------------------------------------------------------------
int32_t btcj_getblockcount(uint8_t *pHash)
{
    jbyteArray array;
    if (pHash != NULL) {
        array = (*env)->NewByteArray(env, BTC_SZ_HASH256);
    } else {
        array = NULL;
    }
    jint ret = (*env)->CallIntMethod(env, ptarm_obj, ptarm_method[METHOD_PTARM_GETBLOCKCOUNT], array);
    check_exception(env);
    if (pHash != NULL) {
        (*env)->GetByteArrayRegion(env, array, 0, BTC_SZ_HASH256, (jbyte *)pHash);
        (*env)->DeleteLocalRef(env, array);
    }
    return ret;
}
//-----------------------------------------------------------------------------
bool btcj_getgenesisblockhash(uint8_t *pHash)
{
    jbyteArray hash_obj = (*env)->CallObjectMethod(env, ptarm_obj, ptarm_method[METHOD_PTARM_GETGENESISBLOCKHASH]);
    check_exception(env);
    btcj_buf_t *bytes = jbarray2buf(hash_obj);
    memcpy(pHash, bytes->buf, bytes->len);
    //
    (*env)->DeleteLocalRef(env, hash_obj);
    UTL_DBG_FREE(bytes->buf);
    //
    return true;
}
//-----------------------------------------------------------------------------
uint32_t btcj_gettxconfirm(const uint8_t *pTxid, int voutIndex, const uint8_t *pVoutWitProg, uint64_t amount)
{
    LOGD("txid=");
    TXIDD(pTxid);

    const btcj_buf_t buf = { (CONST_CAST uint8_t *)pTxid, BTC_SZ_TXID };
    jobject txHash = buf2jbarray(&buf);
    const btcj_buf_t buf_wit = { (CONST_CAST uint8_t *)pVoutWitProg, BTC_SZ_WITPROG_P2WSH };
    jobject witProg = buf2jbarray(&buf_wit);
    jint ret = (*env)->CallIntMethod(env, ptarm_obj, ptarm_method[METHOD_PTARM_GETCONFIRMATION],
                                     txHash, voutIndex, witProg, amount);
    check_exception(env);
    LOGD("ret=%" PRIu32 "\n", ret);
    //
    (*env)->DeleteLocalRef(env, witProg);
    (*env)->DeleteLocalRef(env, txHash);
    //
    return ret;
}
//-----------------------------------------------------------------------------
bool btcj_get_short_channel_param(const uint8_t *pPeerId, int32_t *pHeight, int32_t *pbIndex, uint8_t *pMinedHash)
{
    const btcj_buf_t buf = { (CONST_CAST uint8_t *)pPeerId, BTC_SZ_PUBKEY };
    jbyteArray barray = buf2jbarray(&buf);
    jobject param_obj = (*env)->CallObjectMethod(env, ptarm_obj, ptarm_method[METHOD_PTARM_GETSHORTCHANNELPARAM], barray);
    check_exception(env);
    //
    if (param_obj != NULL) {
        *pHeight = (*env)->GetIntField(env, param_obj, ptarmcls_field[M_FIELD_PTARMCHAN_HEIGHT]);
        *pbIndex = (*env)->GetIntField(env, param_obj, ptarmcls_field[M_FIELD_PTARMCHAN_BINDEX]);
        jbyteArray hash_obj = (*env)->GetObjectField(env, param_obj, ptarmcls_field[M_FIELD_PTARMCHAN_MINEDHASH]);
        if (hash_obj != NULL) {
            btcj_buf_t *bytes = jbarray2buf(hash_obj);
            memcpy(pMinedHash, bytes->buf, bytes->len);
            UTL_DBG_FREE(bytes->buf);
            LOGD("minedHash: ");
            TXIDD(pMinedHash);
        } else {
            LOGE("fail: blockHash field\n");
        }

        if (hash_obj != NULL) {
            (*env)->DeleteLocalRef(env, hash_obj);
        }
        (*env)->DeleteLocalRef(env, param_obj);
    }
    return param_obj != NULL;
}
//-----------------------------------------------------------------------------
// bool btcj_gettxid_from_short_channel(uint64_t ShortChannelId, uint8_t **ppTxid)
// {
//     jbyteArray hash_obj = (*env)->CallObjectMethod(
//                              env, ptarm_obj,
//                              ptarm_method[METHOD_PTARM_GETTXIDFROMSHORTCHANNELID],
//                              ShortChannelId);
//     check_exception(env);
//     if (hash_obj != NULL) {
//         btcj_buf_t *p_hash = jbarray2buf(hash_obj);
//         *ppTxid = p_hash->buf;
//         LOGD("success\n");
//     } else {
//         LOGE("fail: txid\n");
//     }
//     return hash_obj != NULL;
// }
//-----------------------------------------------------------------------------
bool btcj_search_outpoint(btcj_buf_t **ppTx, uint32_t *pMined, uint32_t Blks, const uint8_t *pTxid, uint32_t VIndex)
{
    const btcj_buf_t buf = { (CONST_CAST uint8_t *)pTxid, BTC_SZ_TXID };
    jobject txHash = buf2jbarray(&buf);
    jobject param_obj = (*env)->CallObjectMethod(
                          env, ptarm_obj,
                          ptarm_method[METHOD_PTARM_SEARCHOUTPOINT],
                          Blks, txHash, VIndex);
    check_exception(env);
    //
    bool ret = false;
    if (param_obj != NULL) {
        *pMined = (*env)->GetIntField(
                      env, param_obj,
                      searchoutpoint_field[M_FIELD_SEARCHOUTPOINT_HEIGHT]);
        jbyteArray hash_obj = (*env)->GetObjectField(
                                  env, param_obj,
                                  searchoutpoint_field[M_FIELD_SEARCHOUTPOINT_TX]);
        if (hash_obj != NULL) {
            *ppTx = jbarray2buf(hash_obj);
            ret = true;
            (*env)->DeleteLocalRef(env, hash_obj);
            LOGD("success\n");
        } else {
            LOGE("fail\n");
        }
    } else {
        LOGE("fail\n");
    }
    //
    (*env)->DeleteLocalRef(env, txHash);
    //
    return ret;
}
//-----------------------------------------------------------------------------
bool btcj_search_vout(btcj_buf_t **ppTxBuf, uint32_t Blks, const btcj_buf_t *pVout)
{
    LOGD("ppTxBuf=%p, Blks=%d, pVout=%p\n", ppTxBuf, (int)Blks, pVout);

    jobject vout = bufs2list(pVout);
    LOGD(" vout=%p\n", vout);
    jobject list = (*env)->CallObjectMethod(env, ptarm_obj, ptarm_method[METHOD_PTARM_SEARCHVOUT], Blks, vout);
    check_exception(env);
    LOGD(" list=%p\n", list);
    if (ppTxBuf != NULL) {
        *ppTxBuf = list2bufs(list);
        LOGD("success\n");
    } else {
        LOGE("fail\n");
    }
    //
    (*env)->DeleteLocalRef(env, vout);
    (*env)->DeleteLocalRef(env, list);
    //
    return true;
}
//-----------------------------------------------------------------------------
bool btcj_signraw_tx(uint64_t Amount, const btcj_buf_t *pScriptPubKey, btcj_buf_t **ppTxData)
{
    LOGD("amount=%" PRIu64 ", scriptPubKey=", Amount);
    DUMPD(pScriptPubKey->buf, pScriptPubKey->len);

    jbyteArray pubKey = buf2jbarray(pScriptPubKey);
    jbyteArray ret = (*env)->CallObjectMethod(env, ptarm_obj, ptarm_method[METHOD_PTARM_SIGNRAWTX], (jlong)Amount, pubKey);
    check_exception(env);
    if (ret != NULL) {
        *ppTxData = jbarray2buf(ret);
        LOGD("success\n");
    } else {
        LOGE("fail\n");
    }
    //
    (*env)->DeleteLocalRef(env, pubKey);
    (*env)->DeleteLocalRef(env, ret);
    //
    return ret != NULL;
}
//-----------------------------------------------------------------------------
bool btcj_sendraw_tx(uint8_t *pTxid, int *pCode, const btcj_buf_t *pTxData)
{
    (void)pCode;

    LOGD("rawtx=");
    DUMPD(pTxData->buf, pTxData->len);
    bool ret;
    jbyteArray array = buf2jbarray(pTxData);
    jbyteArray hash_obj = (*env)->CallObjectMethod(env, ptarm_obj, ptarm_method[METHOD_PTARM_SENDRAWTX], array);
    check_exception(env);
    if (hash_obj != NULL) {
        btcj_buf_t *hash = jbarray2buf(hash_obj);
        memcpy(pTxid, hash->buf, hash->len);
        UTL_DBG_FREE(hash->buf);
        ret = true;
        LOGD("success\n");
    } else {
        ret = false;
        LOGE("fail\n");
    }
    //
    (*env)->DeleteLocalRef(env, array);
    (*env)->DeleteLocalRef(env, hash_obj);
    //
    return ret;
}
//-----------------------------------------------------------------------------
bool btcj_is_tx_broadcasted(const uint8_t *pPeerId, const uint8_t *pTxid)
{
    const btcj_buf_t buf_id = { (CONST_CAST uint8_t *)pPeerId, BTC_SZ_PUBKEY };
    jbyteArray peer_id = buf2jbarray(&buf_id);
    const btcj_buf_t buf_hash = { (CONST_CAST uint8_t *)pTxid, BTC_SZ_TXID };
    jobject txHash = buf2jbarray(&buf_hash);
    jboolean ret = (*env)->CallBooleanMethod(env, ptarm_obj, ptarm_method[METHOD_PTARM_CHECKBROADCAST], peer_id, txHash);
    check_exception(env);
    LOGD("result=%d\n", ret);
    //
    (*env)->DeleteLocalRef(env, peer_id);
    (*env)->DeleteLocalRef(env, txHash);
    //
    return ret;
}
//-----------------------------------------------------------------------------
bool btcj_check_unspent(const uint8_t *pPeerId, bool *pUnspent, const uint8_t *pTxid, uint32_t VIndex)
{
    jbyteArray peer_id;
    if (pPeerId != NULL) {
        const btcj_buf_t buf = { (CONST_CAST uint8_t *)pPeerId, BTC_SZ_PUBKEY };
        peer_id = buf2jbarray(&buf);
    } else {
        peer_id = NULL;
    }
    const btcj_buf_t buf = { (CONST_CAST uint8_t *)pTxid, BTC_SZ_TXID };
    jobject txHash = buf2jbarray(&buf);
    jint retval = (*env)->CallIntMethod(env, ptarm_obj, ptarm_method[METHOD_PTARM_CHECKUNSPENT], peer_id, txHash, VIndex);
    check_exception(env);
    LOGD("result=%d\n", retval);
    //
    bool ret;
    switch (retval) {
    case M_CHECKUNSPENT_UNSPENT:
        ret = true;
        *pUnspent = true;
        break;
    case M_CHECKUNSPENT_SPENT:
        ret = true;
        *pUnspent = false;
        break;
    case M_CHECKUNSPENT_FAIL:
    default:
        ret = false;
        break;
    }
    //
    (*env)->DeleteLocalRef(env, peer_id);
    (*env)->DeleteLocalRef(env, txHash);
    //
    return ret;
}
//-----------------------------------------------------------------------------
bool btcj_getnewaddress(char *pAddr)
{
    jstring addr_str = (*env)->CallObjectMethod(env, ptarm_obj, ptarm_method[METHOD_PTARM_GETNEWADDRESS]);
    check_exception(env);
    if (addr_str != NULL) {
        const char *cs = (*env)->GetStringUTFChars(env, addr_str, JNI_FALSE);
        LOGD("addr=%s\n", cs);
        strcpy(pAddr, cs);
        //
        (*env)->ReleaseStringUTFChars(env, addr_str, cs);
        (*env)->DeleteLocalRef(env, addr_str);
    }
    //
    return addr_str != NULL;
}
//-----------------------------------------------------------------------------
bool btcj_estimatefee(uint64_t *pFeeSatoshi, int Blks)
{
//ToDo: FIX: Dynamic fee
    (void)Blks;
    jlong ret = (*env)->CallLongMethod(env, ptarm_obj, ptarm_method[METHOD_PTARM_ESTIMATEFEE]);
    check_exception(env);
    *pFeeSatoshi = ret;
    //
    return true;
}
//-----------------------------------------------------------------------------
bool btcj_set_channel(
    const uint8_t *pPeerId,
    uint64_t ShortChannelId,
    const uint8_t *pFundingTxid,
    int FundingIndex,
    const uint8_t *pScriptPubKey,
    const uint8_t *pMinedHash,
    uint32_t LastConfirm)
{
    btcj_buf_t peer_id = { (CONST_CAST uint8_t *)pPeerId, BTC_SZ_PUBKEY };
    jbyteArray aryPeer = buf2jbarray(&peer_id);
    jlong sci = ShortChannelId;
    jint last_confirm = (jint)LastConfirm;

    const btcj_buf_t buf = { (CONST_CAST uint8_t *)pFundingTxid, BTC_SZ_TXID };
    jobject txHash = buf2jbarray(&buf);

    btcj_buf_t script_pubkey = { (CONST_CAST uint8_t *)pScriptPubKey, BTC_SZ_HASH256 };
    jbyteArray aryScriptPubKey = buf2jbarray(&script_pubkey);

    const btcj_buf_t bufmined = { (CONST_CAST uint8_t *)pMinedHash, BTC_SZ_HASH256 };
    jobject blkhash = buf2jbarray(&bufmined);

    LOGD("sci=%016" PRIx64 "\n", sci);
    jboolean ret = (*env)->CallBooleanMethod(env, ptarm_obj, ptarm_method[METHOD_PTARM_SETCHANNEL],
                           aryPeer, sci, txHash, FundingIndex, aryScriptPubKey,
                           blkhash, last_confirm);
    LOGD("called: ret=%d\n", ret);
    check_exception(env);
    //
    (*env)->DeleteLocalRef(env, blkhash);
    (*env)->DeleteLocalRef(env, aryScriptPubKey);
    (*env)->DeleteLocalRef(env, txHash);
    (*env)->DeleteLocalRef(env, aryPeer);
    return ret;
}
//-----------------------------------------------------------------------------
void btcj_del_channel(const uint8_t *pPeerId)
{
    const btcj_buf_t buf = { (CONST_CAST uint8_t *)pPeerId, BTC_SZ_PUBKEY };
    jbyteArray barray = buf2jbarray(&buf);
    (*env)->CallVoidMethod(env, ptarm_obj, ptarm_method[METHOD_PTARM_DELCHANNEL], barray);
    check_exception(env);
    //
    (*env)->DeleteLocalRef(env, barray);
}
//-----------------------------------------------------------------------------
// void btcj_set_committxid(const uint8_t *peerId, )
// {
// }
//-----------------------------------------------------------------------------
bool btcj_getbalance(uint64_t *pAmount)
{
    jlong ret = (*env)->CallLongMethod(env, ptarm_obj, ptarm_method[METHOD_PTARM_GETBALANCE]);
    check_exception(env);
    *pAmount = ret;
    //
    return true;
}
//-----------------------------------------------------------------------------
bool btcj_emptywallet(const char *pAddr, uint8_t *pTxid)
{
    bool ret;
    jstring addr = (*env)->NewStringUTF(env, pAddr);
    jbyteArray hash_obj = (*env)->CallObjectMethod(env, ptarm_obj, ptarm_method[METHOD_PTARM_EMPTYWALLET], addr);
    check_exception(env);
    if (hash_obj != NULL) {
        btcj_buf_t *hash = jbarray2buf(hash_obj);
        memcpy(pTxid, hash->buf, hash->len);
        UTL_DBG_FREE(hash->buf);
        ret = true;
        (*env)->DeleteLocalRef(env, hash_obj);
    } else {
        ret = false;
    }
    //
    (*env)->DeleteLocalRef(env, addr);
    //
    return ret;
}
//-----------------------------------------------------------------------------
void btcj_exit(void)
{
    (*env)->CallStaticVoidMethod(env, system_cls, system_exit_method, 0);
    check_exception(env);
}
//-----------------------------------------------------------------------------
void btcj_remove_suspend_block(void)
{
    (*env)->CallVoidMethod(env, ptarm_obj, ptarm_method[METHOD_PTARM_REMOVESUSPENDBLOCK]);
    check_exception(env);
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
static jbyteArray buf2jbarray(const btcj_buf_t *buf)
{
    jbyteArray array = (*env)->NewByteArray(env, buf->len);
    (*env)->SetByteArrayRegion(env, array, 0, buf->len, (const jbyte *)buf->buf);
    return array;
}

static btcj_buf_t* jbarray2buf(jbyteArray jbarray)
{
    jsize size = (*env)->GetArrayLength(env, jbarray);
    btcj_buf_t *buf = UTL_DBG_MALLOC(sizeof(btcj_buf_t));
    buf->len = size;
    buf->buf = UTL_DBG_MALLOC(size);
    (*env)->GetByteArrayRegion(env, jbarray, 0, size, (jbyte *)buf->buf);
    return buf;
}

static jobject bufs2list(const btcj_buf_t *bufs)
{
    jobject list = (*env)->NewObject(env, arraylist_cls, arraylist_ctor_method);
    btcj_buf_t *p = (btcj_buf_t*)bufs->buf;
    int num = bufs->len / sizeof(btcj_buf_t*);
    //
    for (int i = 0; i < num; i++) {
        jbyteArray ba = buf2jbarray((p + i));
        (*env)->CallBooleanMethod(env, list, arraylist_add_method, ba);
        check_exception(env);
        (*env)->DeleteLocalRef(env, ba);
    }
    return list;
}

static btcj_buf_t* list2bufs(jobject list)
{
    jint size = (*env)->CallIntMethod(env, list, list_size_method);
    btcj_buf_t *bufs = UTL_DBG_MALLOC(sizeof(btcj_buf_t));
    bufs->len = sizeof(btcj_buf_t*)*size;
    bufs->buf = UTL_DBG_MALLOC(bufs->len);
    //
    for (int i = 0; i < size; i++) {
        jbyteArray ba = (*env)->CallObjectMethod(env, list, list_get_method, (jint)i);
        check_exception(env);
        ((btcj_buf_t**)bufs->buf)[i] = jbarray2buf(ba);
        (*env)->DeleteLocalRef(env, ba);
    }
    return bufs;
}

static inline void _check_exception(JNIEnv *env, const char *pFuncName, int Line)
{
    if ((*env)->ExceptionCheck(env)) {
        LOGE("fail: exception(%s(): %d)!!\n", pFuncName, Line);
        (*env)->ExceptionClear(env);
        //abort();
        mExceptionHappen = true;
    }
}


text:
using System.Collections.Generic;
using PactNet.Comparers;
using PactNet.Matchers;

namespace PactNet.Mocks.MockHttpService.Comparers
{
    internal interface IHttpBodyComparer
    {
        ComparisonResult Compare(dynamic expected, dynamic actual, IDictionary<string, IMatcher> matchingRules);
    }
}


text: Da mantenere fino a quando la directory non contiene file.


text:
package com.android.camera;

import java.io.File;
import java.io.FileOutputStream;

import android.annotation.TargetApi;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.location.Location;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.os.StatFs;
import android.provider.MediaStore.Images;
import android.provider.MediaStore.Images.ImageColumns;
import android.provider.MediaStore.MediaColumns;
import android.util.Log;

import com.android.camera.data.LocalData;
import com.android.camera.exif.ExifInterface;
import com.android.camera.util.ApiHelper;

public class Storage {
    private static final String TAG = "CameraStorage";

    public static final String DCIM =
            Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM).toString();

    public static final String DIRECTORY = DCIM + "/Camera";
    public static final String JPEG_POSTFIX = ".jpg";

    // Match the code in MediaProvider.computeBucketValues().
    public static final String BUCKET_ID =
            String.valueOf(DIRECTORY.toLowerCase().hashCode());

    public static final long UNAVAILABLE = -1L;
    public static final long PREPARING = -2L;
    public static final long UNKNOWN_SIZE = -3L;
    public static final long LOW_STORAGE_THRESHOLD_BYTES = 50000000;

    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
    private static void setImageSize(ContentValues values, int width, int height) {
        // The two fields are available since ICS but got published in JB
        if (ApiHelper.HAS_MEDIA_COLUMNS_WIDTH_AND_HEIGHT) {
            values.put(MediaColumns.WIDTH, width);
            values.put(MediaColumns.HEIGHT, height);
        }
    }

    public static void writeFile(String path, byte[] jpeg, ExifInterface exif) {
        if (exif != null) {
            try {
                exif.writeExif(jpeg, path);
            } catch (Exception e) {
                Log.e(TAG, "Failed to write data", e);
            }
        } else {
            writeFile(path, jpeg);
        }
    }

    public static void writeFile(String path, byte[] data) {
        FileOutputStream out = null;
        try {
            out = new FileOutputStream(path);
            out.write(data);
        } catch (Exception e) {
            Log.e(TAG, "Failed to write data", e);
        } finally {
            try {
                out.close();
            } catch (Exception e) {
                Log.e(TAG, "Failed to close file after write", e);
            }
        }
    }

    // Save the image and add it to the MediaStore.
    public static Uri addImage(ContentResolver resolver, String title, long date,
            Location location, int orientation, ExifInterface exif, byte[] jpeg, int width,
            int height) {

        return addImage(resolver, title, date, location, orientation, exif, jpeg, width, height,
                LocalData.MIME_TYPE_JPEG);
    }

    // Save the image with a given mimeType and add it the MediaStore.
    public static Uri addImage(ContentResolver resolver, String title, long date,
            Location location, int orientation, ExifInterface exif, byte[] jpeg, int width,
            int height, String mimeType) {

        String path = generateFilepath(title);
        writeFile(path, jpeg, exif);
        return addImage(resolver, title, date, location, orientation,
                jpeg.length, path, width, height, mimeType);
    }

    // Get a ContentValues object for the given photo data
    public static ContentValues getContentValuesForData(String title,
            long date, Location location, int orientation, int jpegLength,
            String path, int width, int height, String mimeType) {

        ContentValues values = new ContentValues(11);
        values.put(ImageColumns.TITLE, title);
        values.put(ImageColumns.DISPLAY_NAME, title + JPEG_POSTFIX);
        values.put(ImageColumns.DATE_TAKEN, date);
        values.put(ImageColumns.MIME_TYPE, mimeType);
        // Clockwise rotation in degrees. 0, 90, 180, or 270.
        values.put(ImageColumns.ORIENTATION, orientation);
        values.put(ImageColumns.DATA, path);
        values.put(ImageColumns.SIZE, jpegLength);

        setImageSize(values, width, height);

        if (location != null) {
            values.put(ImageColumns.LATITUDE, location.getLatitude());
            values.put(ImageColumns.LONGITUDE, location.getLongitude());
        }
        return values;
    }

    // Add the image to media store.
    public static Uri addImage(ContentResolver resolver, String title,
            long date, Location location, int orientation, int jpegLength,
            String path, int width, int height, String mimeType) {
        // Insert into MediaStore.
        ContentValues values =
                getContentValuesForData(title, date, location, orientation, jpegLength, path,
                        width, height, mimeType);

         return insertImage(resolver, values);
    }

    // Overwrites the file and updates the MediaStore, or inserts the image if
    // one does not already exist.
    public static void updateImage(Uri imageUri, ContentResolver resolver, String title, long date,
            Location location, int orientation, ExifInterface exif, byte[] jpeg, int width,
            int height, String mimeType) {
        String path = generateFilepath(title);
        writeFile(path, jpeg, exif);
        updateImage(imageUri, resolver, title, date, location, orientation, jpeg.length, path,
                width, height, mimeType);
    }

    // Updates the image values in MediaStore, or inserts the image if one does
    // not already exist.
    public static void updateImage(Uri imageUri, ContentResolver resolver, String title,
            long date, Location location, int orientation, int jpegLength,
            String path, int width, int height, String mimeType) {

        ContentValues values =
                getContentValuesForData(title, date, location, orientation, jpegLength, path,
                        width, height, mimeType);

        // Update the MediaStore
        int rowsModified = resolver.update(imageUri, values, null, null);

        if (rowsModified == 0) {
            // If no prior row existed, insert a new one.
            Log.w(TAG, "updateImage called with no prior image at uri: " + imageUri);
            insertImage(resolver, values);
        } else if (rowsModified != 1) {
            // This should never happen
            throw new IllegalStateException("Bad number of rows (" + rowsModified
                    + ") updated for uri: " + imageUri);
        }
    }

    public static void deleteImage(ContentResolver resolver, Uri uri) {
        try {
            resolver.delete(uri, null, null);
        } catch (Throwable th) {
            Log.e(TAG, "Failed to delete image: " + uri);
        }
    }

    public static String generateFilepath(String title) {
        return DIRECTORY + '/' + title + ".jpg";
    }

    public static long getAvailableSpace() {
        String state = Environment.getExternalStorageState();
        Log.d(TAG, "External storage state=" + state);
        if (Environment.MEDIA_CHECKING.equals(state)) {
            return PREPARING;
        }
        if (!Environment.MEDIA_MOUNTED.equals(state)) {
            return UNAVAILABLE;
        }

        File dir = new File(DIRECTORY);
        dir.mkdirs();
        if (!dir.isDirectory() || !dir.canWrite()) {
            return UNAVAILABLE;
        }

        try {
            StatFs stat = new StatFs(DIRECTORY);
            return stat.getAvailableBlocks() * (long) stat.getBlockSize();
        } catch (Exception e) {
            Log.i(TAG, "Fail to access external storage", e);
        }
        return UNKNOWN_SIZE;
    }

    /**
     * OSX requires plugged-in USB storage to have path /DCIM/NNNAAAAA to be
     * imported. This is a temporary fix for bug#1655552.
     */
    public static void ensureOSXCompatible() {
        File nnnAAAAA = new File(DCIM, "100ANDRO");
        if (!(nnnAAAAA.exists() || nnnAAAAA.mkdirs())) {
            Log.e(TAG, "Failed to create " + nnnAAAAA.getPath());
        }
    }

    private static Uri insertImage(ContentResolver resolver, ContentValues values) {
        Uri uri = null;
        try {
            uri = resolver.insert(Images.Media.EXTERNAL_CONTENT_URI, values);
        } catch (Throwable th)  {
            // This can happen when the external volume is already mounted, but
            // MediaScanner has not notify MediaProvider to add that volume.
            // The picture is still safe and MediaScanner will find it and
            // insert it into MediaProvider. The only problem is that the user
            // cannot click the thumbnail to review the picture.
            Log.e(TAG, "Failed to write MediaStore" + th);
        }
        return uri;
    }
}


text:
"""Parser for the plugin database.

SQLite database path:
# TODO: add database path
SQLite database Name: the_plugin.db
"""

from dfdatetime import posix_time as dfdatetime_posix_time

from plaso.containers import time_events
from plaso.lib import eventdata
from plaso.parsers import sqlite
from plaso.parsers.sqlite_plugins import interface

class ThePluginUsersEventData(events.EventData):
  """the plugin users event data.

  TODO: add type and description of attributes
  Attributes:
    advertiser_account_type (int): TODO
    analytics_type (int): TODO
    bio_entities (bytes): TODO
    business_profile_state (int): TODO
    could_be_stale (int): TODO
    description (str): TODO
    device_following (int): TODO
    extended_profile_fields (bytes): TODO
    favorites_count (int): TODO
    followers_count (int): TODO
    followers_count_fast (int): TODO
    followers_count_normal (int): TODO
    following (int): TODO
    following_count (int): TODO
    has_collections (int): TODO
    has_extended_profile_fields (int): TODO
    id (int): TODO
    is_lifeline_institution (int): TODO
    is_translator (int): TODO
    location (str): TODO
    media_count (int): TODO
    name (str): TODO
    pinned_tweet_id (int): TODO
    profile_banner_url (str): TODO
    profile_image_url (str): TODO
    profile_link_color_hex_triplet (int): TODO
    protected (int): TODO
    screen_name (str): TODO
    statuses_count (int): TODO
    structured_location (bytes): TODO
    url (str): TODO
    url_entities (bytes): TODO
    verified (int): TODO
  """

  DATA_TYPE = u'the:plugin:'

  def __init__(self):
    """Initializes event data."""
    super(ThePluginUsersEventData, self).__init__(data_type=self.DATA_TYPE)
    self.advertiser_account_type = None
    self.analytics_type = None
    self.bio_entities = None
    self.business_profile_state = None
    self.could_be_stale = None
    self.description = None
    self.device_following = None
    self.extended_profile_fields = None
    self.favorites_count = None
    self.followers_count = None
    self.followers_count_fast = None
    self.followers_count_normal = None
    self.following = None
    self.following_count = None
    self.has_collections = None
    self.has_extended_profile_fields = None
    self.id = None
    self.is_lifeline_institution = None
    self.is_translator = None
    self.location = None
    self.media_count = None
    self.name = None
    self.pinned_tweet_id = None
    self.profile_banner_url = None
    self.profile_image_url = None
    self.profile_link_color_hex_triplet = None
    self.protected = None
    self.screen_name = None
    self.statuses_count = None
    self.structured_location = None
    self.url = None
    self.url_entities = None
    self.verified = None

class ThePluginStatusesEventData(events.EventData):
  """the plugin statuses event data.

  TODO: add type and description of attributes
  Attributes:
    card (bytes): TODO
    card_users (bytes): TODO
    card_version (int): TODO
    entities (bytes): TODO
    extra_scribe_item (bytes): TODO
    favorite_count (int): TODO
    favorited (int): TODO
    full_text_length (int): TODO
    geotag (bytes): TODO
    id (int): TODO
    include_in_profile_timeline (int): TODO
    in_reply_to_status_id (int): TODO
    in_reply_to_username (str): TODO
    is_lifeline_alert (int): TODO
    is_possibly_sensitive_appealable (int): TODO
    is_truncated (int): TODO
    lang (str): TODO
    possibly_sensitive (int): TODO
    preview_length (int): TODO
    primary_card_type (int): TODO
    quoted_status_id (int): TODO
    retweet_count (int): TODO
    retweeted_status_id (int): TODO
    source (str): TODO
    supplmental_language (str): TODO
    text (str): TODO
    user_id (int): TODO
    withheld_in_countries (str): TODO
    withheld_scope (str): TODO
  """

  DATA_TYPE = u'the:plugin:'

  def __init__(self):
    """Initializes event data."""
    super(ThePluginStatusesEventData, self).__init__(data_type=self.DATA_TYPE)
    self.card = None
    self.card_users = None
    self.card_version = None
    self.entities = None
    self.extra_scribe_item = None
    self.favorite_count = None
    self.favorited = None
    self.full_text_length = None
    self.geotag = None
    self.id = None
    self.include_in_profile_timeline = None
    self.in_reply_to_status_id = None
    self.in_reply_to_username = None
    self.is_lifeline_alert = None
    self.is_possibly_sensitive_appealable = None
    self.is_truncated = None
    self.lang = None
    self.possibly_sensitive = None
    self.preview_length = None
    self.primary_card_type = None
    self.quoted_status_id = None
    self.retweet_count = None
    self.retweeted_status_id = None
    self.source = None
    self.supplmental_language = None
    self.text = None
    self.user_id = None
    self.withheld_in_countries = None
    self.withheld_scope = None

class ThePluginPlugin(interface.SQLitePlugin):
  """Parser for ThePlugin"""

  NAME = u'the_plugin'
  DESCRIPTION = u'Parser for ThePlugin'

  QUERIES = [((u'select * from users)'), u'ParseUsersRow'), ((
      u'select * from users)'), u'ParseStatusesRow')]

  REQUIRED_TABLES = frozenset([
      u'Lists', u'ListsShadow', u'MyRetweets', u'Statuses', u'StatusesShadow',
      u'Users', u'UsersShadow'
  ])

  def ParseUsersRow(self, parser_mediator, row, query=None, **unused_kwargs):
    """Parses a contact row from the database.

    Args:
      parser_mediator (ParserMediator): mediates interactions between parsers
          and other components, such as storage and dfvfs.
      row (sqlite3.Row): row resulting from Query.
      Query (Optional[str]): Query.
    """
    # Note that pysqlite does not accept a Unicode string in row['string'] and
    # will raise "IndexError: Index must be int or string".

    event_data = ThePluginEventData()
    event_data.advertiser_account_type = row['advertiserAccountType']
    event_data.analytics_type = row['analyticsType']
    event_data.bio_entities = row['bioEntities']
    event_data.business_profile_state = row['businessProfileState']
    event_data.could_be_stale = row['couldBeStale']
    event_data.description = row['description']
    event_data.device_following = row['deviceFollowing']
    event_data.extended_profile_fields = row['extendedProfileFields']
    event_data.favorites_count = row['favoritesCount']
    event_data.followers_count = row['followersCount']
    event_data.followers_count_fast = row['followersCountFast']
    event_data.followers_count_normal = row['followersCountNormal']
    event_data.following = row['following']
    event_data.following_count = row['followingCount']
    event_data.has_collections = row['hasCollections']
    event_data.has_extended_profile_fields = row['hasExtendedProfileFields']
    event_data.id = row['id']
    event_data.is_lifeline_institution = row['isLifelineInstitution']
    event_data.is_translator = row['isTranslator']
    event_data.location = row['location']
    event_data.media_count = row['mediaCount']
    event_data.name = row['name']
    event_data.pinned_tweet_id = row['pinnedTweetId']
    event_data.profile_banner_url = row['profileBannerUrl']
    event_data.profile_image_url = row['profileImageUrl']
    event_data.profile_link_color_hex_triplet = row[
        'profileLinkColorHexTriplet']
    event_data.protected = row['protected']
    event_data.screen_name = row['screenName']
    event_data.statuses_count = row['statusesCount']
    event_data.structured_location = row['structuredLocation']
    event_data.url = row['url']
    event_data.url_entities = row['urlEntities']
    event_data.verified = row['verified']

    timestamp = row['createdDate']
    if timestamp:
      # Convert the floating point value to an integer.
      timestamp = int(timestamp)
      date_time = dfdatetime_posix_time.PosixTime(timestamp=timestamp)
      # TODO: Add correct time field for None value.  Example: eventdata.EventTimestamp.UPDATE_TIME
      event = time_events.DateTimeValuesEvent(date_time, None)
      parser_mediator.ProduceEventWithEventData(event, event_data)

    timestamp = row['updatedAt']
    if timestamp:
      # Convert the floating point value to an integer.
      timestamp = int(timestamp)
      date_time = dfdatetime_posix_time.PosixTime(timestamp=timestamp)
      # TODO: Add correct time field for None value.  Example: eventdata.EventTimestamp.UPDATE_TIME
      event = time_events.DateTimeValuesEvent(date_time, None)
      parser_mediator.ProduceEventWithEventData(event, event_data)

  def ParseStatusesRow(self, parser_mediator, row, query=None, **unused_kwargs):
    """Parses a contact row from the database.

    Args:
      parser_mediator (ParserMediator): mediates interactions between parsers
          and other components, such as storage and dfvfs.
      row (sqlite3.Row): row resulting from Query.
      Query (Optional[str]): Query.
    """
    # Note that pysqlite does not accept a Unicode string in row['string'] and
    # will raise "IndexError: Index must be int or string".

    event_data = ThePluginEventData()
    event_data.card = row['card']
    event_data.card_users = row['cardUsers']
    event_data.card_version = row['cardVersion']
    event_data.entities = row['entities']
    event_data.extra_scribe_item = row['extraScribeItem']
    event_data.favorite_count = row['favoriteCount']
    event_data.favorited = row['favorited']
    event_data.full_text_length = row['fullTextLength']
    event_data.geotag = row['geotag']
    event_data.id = row['id']
    event_data.include_in_profile_timeline = row['includeInProfileTimeline']
    event_data.in_reply_to_status_id = row['inReplyToStatusId']
    event_data.in_reply_to_username = row['inReplyToUsername']
    event_data.is_lifeline_alert = row['isLifelineAlert']
    event_data.is_possibly_sensitive_appealable = row[
        'isPossiblySensitiveAppealable']
    event_data.is_truncated = row['isTruncated']
    event_data.lang = row['lang']
    event_data.possibly_sensitive = row['possiblySensitive']
    event_data.preview_length = row['previewLength']
    event_data.primary_card_type = row['primaryCardType']
    event_data.quoted_status_id = row['quotedStatusId']
    event_data.retweet_count = row['retweetCount']
    event_data.retweeted_status_id = row['retweetedStatusId']
    event_data.source = row['source']
    event_data.supplmental_language = row['supplmentalLanguage']
    event_data.text = row['text']
    event_data.user_id = row['userId']
    event_data.withheld_in_countries = row['withheldInCountries']
    event_data.withheld_scope = row['withheldScope']

    timestamp = row['date']
    if timestamp:
      # Convert the floating point value to an integer.
      timestamp = int(timestamp)
      date_time = dfdatetime_posix_time.PosixTime(timestamp=timestamp)
      # TODO: Add correct time field for None value.  Example: eventdata.EventTimestamp.UPDATE_TIME
      event = time_events.DateTimeValuesEvent(date_time, None)
      parser_mediator.ProduceEventWithEventData(event, event_data)

    timestamp = row['updatedAt']
    if timestamp:
      # Convert the floating point value to an integer.
      timestamp = int(timestamp)
      date_time = dfdatetime_posix_time.PosixTime(timestamp=timestamp)
      # TODO: Add correct time field for None value.  Example: eventdata.EventTimestamp.UPDATE_TIME
      event = time_events.DateTimeValuesEvent(date_time, None)
      parser_mediator.ProduceEventWithEventData(event, event_data)

sqlite.SQLiteParser.RegisterPlugin(ThePluginPlugin)


text:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
		 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<groupId>org.test</groupId>
	<artifactId>bom</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>pom</packaging>
	<name>test-dependencies-bom</name>
	<url>http://myorg.org</url>

	<properties>
		<commons-cli.version>1.3</commons-cli.version>
		<junit.version>3.8.1</junit.version>
	</properties>

	<modules>
		<module>test-dependencies</module>
	</modules>
</project>


text:
import Vue from 'vue';
import collapsibleComponent from '~/registry/components/collapsible_container.vue';
import store from '~/registry/stores';
import { repoPropsData } from '../mock_data';

describe('collapsible registry container', () => {
  let vm;
  let Component;

  beforeEach(() => {
    Component = Vue.extend(collapsibleComponent);
    vm = new Component({
      store,
      propsData: {
        repo: repoPropsData,
      },
    }).$mount();
  });

  afterEach(() => {
    vm.$destroy();
  });

  describe('toggle', () => {
    it('should be closed by default', () => {
      expect(vm.$el.querySelector('.container-image-tags')).toBe(null);
      expect(vm.$el.querySelector('.container-image-head i').className).toEqual('fa fa-chevron-right');
    });

    it('should be open when user clicks on closed repo', (done) => {
      vm.$el.querySelector('.js-toggle-repo').click();
      Vue.nextTick(() => {
        expect(vm.$el.querySelector('.container-image-tags')).toBeDefined();
        expect(vm.$el.querySelector('.container-image-head i').className).toEqual('fa fa-chevron-up');
        done();
      });
    });

    it('should be closed when the user clicks on an opened repo', (done) => {
      vm.$el.querySelector('.js-toggle-repo').click();

      Vue.nextTick(() => {
        vm.$el.querySelector('.js-toggle-repo').click();
        Vue.nextTick(() => {
          expect(vm.$el.querySelector('.container-image-tags')).toBe(null);
          expect(vm.$el.querySelector('.container-image-head i').className).toEqual('fa fa-chevron-right');
          done();
        });
      });
    });
  });

  describe('delete repo', () => {
    it('should be possible to delete a repo', () => {
      expect(vm.$el.querySelector('.js-remove-repo')).toBeDefined();
    });
  });
});


text:
package com.taobao;

import com.alibaba.fastjson.serializer.JSONSerializer;
import com.alibaba.fastjson.serializer.PropertyFilter;
import com.alibaba.fastjson.serializer.SerializeWriter;
import com.taobao.serial.SimplePropertyFilter;

/**
 *
 * @create 2014年4月14日 下午8:24:37
 * @author cunhan.fch
 * @version
 */
public class Test {

    /**
     * @param args
     */
    public static void main(String[] args) {
      Lable layout=new Lable();
      AllStyle fs=new AllStyle();
      fs.setAlign(5);
      fs.setLines(3);
      fs.setWidth(80);
      fs.setHeight(100);
      fs.setFontSize(300);
      fs.setBackgroundColor("#FFFFFF");
      layout.setStyleBinding(fs);

    SerializeWriter sw=new SerializeWriter();
    JSONSerializer serialize=new JSONSerializer(sw);
    serialize.getPropertyFilters().add(new SimplePropertyFilter());
    serialize.write(layout);

       System.out.println(sw.toString());
    }

}


text:
<?php
namespace Concrete\Core\Permission\Access\Entity;

use Loader;
use PermissionAccess;
use URL;
use Config;
use UserInfo;
use User;
use Concrete\Core\Conversation\Message\Message;
use Concrete\Core\Permission\Access\ConversationAccess;

class ConversationMessageAuthorEntity extends Entity
{

    public function getAccessEntityUsers(PermissionAccess $pa)
    {
        $message = $pa->getPermissionObject();
        if (is_object($message) && ($message instanceof Message)) {
            return UserInfo::getByID($message->getConversationMessageUserID());
        }
    }

    public function validate(PermissionAccess $pae)
    {
        if ($pae instanceof ConversationAccess) {
            $message = $pae->getPermissionObject();
        }

        if ($message instanceof Message) {
            $u = new User();
            return $u->getUserID() == $message->getConversationMessageUserID();
        }

        return false;
    }

    public function getAccessEntityTypeLinkHTML()
    {
        $html = '' . tc(
                'PermissionAccessEntityTypeName',
                'Message Author'
            ) . '';
        return $html;
    }

    public static function getAccessEntitiesForUser($user)
    {
        $entities = array();
        $db = Loader::db();
        if ($user->isRegistered()) {
            $pae = static::getOrCreate();
            $r = $db->GetOne('select cnvMessageID from ConversationMessages where uID = ?', array($user->getUserID()));
            if ($r > 0) {
                $entities[] = $pae;
            }
        }
        return $entities;
    }

    public static function getOrCreate()
    {
        $db = Loader::db();
        $petID = $db->GetOne('select petID from PermissionAccessEntityTypes where petHandle = \'conversation_message_author\'');
        $peID = $db->GetOne(
            'select peID from PermissionAccessEntities where petID = ?',
            array($petID)
        );
        if (!$peID) {
            $db->Execute("insert into PermissionAccessEntities (petID) values(?)", array($petID));
            $peID = $db->Insert_ID();
            Config::save('concrete.misc.access_entity_updated', time());
        }
        return \Concrete\Core\Permission\Access\Entity\Entity::getByID($peID);
    }

    public function load()
    {
        $db = Loader::db();
        $this->label = t('Message Author');
    }

}