<commit_before>'use strict';

var self = nexecConfig;
module.exports = self;

var async = require('async');
var _ = require('underscore');

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

function nexecConfig(params, callback) {
  var bag = {
    apiAdapter: params.apiAdapter,
    config: params.config,
    releaseVersion: params.releaseVersion,
    isSwarmClusterInitialized: params.isSwarmClusterInitialized,
    name: params.name,
    registry: params.registry,
    envs: '',
    mounts: '',
    runCommand: '',
    serviceUserTokenEnv: 'SERVICE_USER_TOKEN',
    serviceUserToken: ''
  };

  bag.who = util.format('nexecConfig|%s', self.name);
  logger.info(bag.who, 'Starting');

  async.series([
      _checkInputParams.bind(null, bag),
      _getServiceUserToken.bind(null, bag),
      _getAPISystemIntegration.bind(null, bag),
      _getMsgSystemIntegration.bind(null, bag),
      _generateImage.bind(null, bag),
      _generateEnvs.bind(null, bag),
      _generateMounts.bind(null, bag),
      _generateRunCommandOnebox.bind(null, bag),
      _generateRunCommandCluster.bind(null, bag)
    ],
    function (err) {
      logger.info(bag.who, 'Completed');
      if (err)
        callback(err);
      callback(null, bag.config, bag.runCommand);
    }
  );
}

function _checkInputParams(bag, next) {
  var who = bag.who + '|' + _checkInputParams.name;
  logger.verbose(who, 'Inside');

  bag.config.replicas = bag.config.replicas;
  bag.config.serviceName = bag.name;

  return next();
}

function _getServiceUserToken(bag, next) {
  var who = bag.who + '|' + _getServiceUserToken.name;
  logger.verbose(who, 'Inside');

  envHandler.get(bag.serviceUserTokenEnv,
    function (err, value) {
      if (err)
        return next(
          new ActErr(who, ActErr.OperationFailed,
            'Cannot get env: ' + bag.serviceUserTokenEnv)
        );

      if (_.isEmpty(value))
        return next(
          new ActErr(who, ActErr.OperationFailed,
            'No serviceUserToken found.')
        );

      bag.serviceUserToken = value;

      return next();
    }
  );
}

function _getAPISystemIntegration(bag, next) {
  var who = bag.who + '|' + _getAPISystemIntegration.name;
  logger.verbose(who, 'Inside');

  var query = 'name=api&masterName=url';
  bag.apiAdapter.getSystemIntegrations(query,
    function (err, systemIntegrations) {
      if (err)
        return next(
          new ActErr(who, ActErr.OperationFailed,
            'Failed to get system integrations: ' + util.inspect(err))
        );

      if (!systemIntegrations.length)
        return next(
          new ActErr(who, ActErr.OperationFailed,
            'No api systemIntegration found.')
        );

      bag.apiSystemIntegration = _.first(systemIntegrations);

      return next();
    }
  );
}

function _getMsgSystemIntegration(bag, next) {
  var who = bag.who + '|' + _getAPISystemIntegration.name;
  logger.verbose(who, 'Inside');

  var query = 'name=msg&masterName=rabbitmqCreds';
  bag.apiAdapter.getSystemIntegrations(query,
    function (err, systemIntegrations) {
      if (err)
        return next(
          new ActErr(who, ActErr.OperationFailed,
            'Failed to get system integrations: ' + util.inspect(err))
        );

      if (!systemIntegrations.length)
        return next(
          new ActErr(who, ActErr.OperationFailed,
            'No api systemIntegration found.')
        );

      bag.msgSystemIntegration = _.first(systemIntegrations);

      return next();
    }
  );
}

function _generateImage(bag, next) {
  var who = bag.who + '|' + _generateImage.name;
  logger.verbose(who, 'Inside');

  bag.config.image = util.format('%s/%s:%s',
    bag.registry, bag.config.serviceName, bag.releaseVersion);

  return next();
}

function _generateEnvs(bag, next) {
  var who = bag.who + '|' + _generateEnvs.name;
  logger.verbose(who, 'Inside');

  var apiUrl = bag.apiSystemIntegration.data &&
    bag.apiSystemIntegration.data.url;

  if (!apiUrl)
    return next(
      new ActErr(who, ActErr.OperationFailed,
        'No apiUrl found.')
    );

  var amqpUrlRoot = bag.msgSystemIntegration.data &&
    bag.msgSystemIntegration.data.amqpUrlRoot;

  if (!amqpUrlRoot)
    return next(
      new ActErr(who, ActErr.OperationFailed,
        'No amqpUrlRoot found.')
    );

  var amqpDefaultExchange = bag.msgSystemIntegration.data &&
    bag.msgSystemIntegration.data.amqpDefaultExchange;

  if (!amqpDefaultExchange)
    return next(
      new ActErr(who, ActErr.OperationFailed,
        'No amqpDefaultExchange found.')
    );

  var envs = '';
  envs = util.format('%s -e %s=%s',
    envs, 'SHIPPABLE_API_TOKEN', bag.serviceUserToken);
  envs = util.format('%s -e %s=%s',
    envs, 'SHIPPABLE_API_URL', apiUrl);
  envs = util.format('%s -e %s=%s',
    envs, 'SHIPPABLE_ROOT_AMQP_URL', amqpUrlRoot);
  envs = util.format('%s -e %s=%s',
    envs, 'SHIPPABLE_AMQP_DEFAULT_EXCHANGE', amqpDefaultExchange);

  bag.envs = envs;
  return next();
}

function _generateMounts(bag, next) {
  var who = bag.who + '|' + _generateMounts.name;
  logger.verbose(who, 'Inside');

  bag.mounts = '';
  return next();
}

function _generateRunCommandOnebox(bag, next) {
  if (bag.isSwarmClusterInitialized) return next();

  var who = bag.who + '|' + _generateRunCommandOnebox.name;
  logger.verbose(who, 'Inside');

  var opts = ' --network=host' +
    ' --privileged=true';

  var runCommand = util.format('docker run -d ' +
    ' %s %s %s --name %s %s',
    bag.envs,
    bag.mounts,
    opts,
    bag.config.serviceName,
    bag.config.image);

  bag.runCommand = runCommand;
  return next();
}

function _generateRunCommandCluster(bag, next) {
  if (!bag.isSwarmClusterInitialized) return next();

  var who = bag.who + '|' + _generateRunCommandCluster.name;
  logger.verbose(who, 'Inside');

  var replicas = util.format(' --replicas %s', bag.config.replicas);
  if (bag.replicas === 'global')
    replicas = ' --mode global';

  var opts = ' --network ingress' +
    ' --with-registry-auth' +
    ' --endpoint-mode vip';

  var runCommand = util.format('docker service create ' +
    ' %s %s --name %s %s',
    bag.envs,
    opts,
    replicas,
    bag.config.serviceName,
    bag.config.image
  );

  bag.runCommand = runCommand;
  return next();
}
<commit_msg>#674; fix nexec swarm command.<commit_after>'use strict';

var self = nexecConfig;
module.exports = self;

var async = require('async');
var _ = require('underscore');

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

function nexecConfig(params, callback) {
  var bag = {
    apiAdapter: params.apiAdapter,
    config: params.config,
    releaseVersion: params.releaseVersion,
    isSwarmClusterInitialized: params.isSwarmClusterInitialized,
    name: params.name,
    registry: params.registry,
    envs: '',
    mounts: '',
    runCommand: '',
    serviceUserTokenEnv: 'SERVICE_USER_TOKEN',
    serviceUserToken: ''
  };

  bag.who = util.format('nexecConfig|%s', self.name);
  logger.info(bag.who, 'Starting');

  async.series([
      _checkInputParams.bind(null, bag),
      _getServiceUserToken.bind(null, bag),
      _getAPISystemIntegration.bind(null, bag),
      _getMsgSystemIntegration.bind(null, bag),
      _generateImage.bind(null, bag),
      _generateEnvs.bind(null, bag),
      _generateMounts.bind(null, bag),
      _generateRunCommandOnebox.bind(null, bag),
      _generateRunCommandCluster.bind(null, bag)
    ],
    function (err) {
      logger.info(bag.who, 'Completed');
      if (err)
        callback(err);
      callback(null, bag.config, bag.runCommand);
    }
  );
}

function _checkInputParams(bag, next) {
  var who = bag.who + '|' + _checkInputParams.name;
  logger.verbose(who, 'Inside');

  bag.config.replicas = bag.config.replicas;
  bag.config.serviceName = bag.name;

  return next();
}

function _getServiceUserToken(bag, next) {
  var who = bag.who + '|' + _getServiceUserToken.name;
  logger.verbose(who, 'Inside');

  envHandler.get(bag.serviceUserTokenEnv,
    function (err, value) {
      if (err)
        return next(
          new ActErr(who, ActErr.OperationFailed,
            'Cannot get env: ' + bag.serviceUserTokenEnv)
        );

      if (_.isEmpty(value))
        return next(
          new ActErr(who, ActErr.OperationFailed,
            'No serviceUserToken found.')
        );

      bag.serviceUserToken = value;

      return next();
    }
  );
}

function _getAPISystemIntegration(bag, next) {
  var who = bag.who + '|' + _getAPISystemIntegration.name;
  logger.verbose(who, 'Inside');

  var query = 'name=api&masterName=url';
  bag.apiAdapter.getSystemIntegrations(query,
    function (err, systemIntegrations) {
      if (err)
        return next(
          new ActErr(who, ActErr.OperationFailed,
            'Failed to get system integrations: ' + util.inspect(err))
        );

      if (!systemIntegrations.length)
        return next(
          new ActErr(who, ActErr.OperationFailed,
            'No api systemIntegration found.')
        );

      bag.apiSystemIntegration = _.first(systemIntegrations);

      return next();
    }
  );
}

function _getMsgSystemIntegration(bag, next) {
  var who = bag.who + '|' + _getAPISystemIntegration.name;
  logger.verbose(who, 'Inside');

  var query = 'name=msg&masterName=rabbitmqCreds';
  bag.apiAdapter.getSystemIntegrations(query,
    function (err, systemIntegrations) {
      if (err)
        return next(
          new ActErr(who, ActErr.OperationFailed,
            'Failed to get system integrations: ' + util.inspect(err))
        );

      if (!systemIntegrations.length)
        return next(
          new ActErr(who, ActErr.OperationFailed,
            'No api systemIntegration found.')
        );

      bag.msgSystemIntegration = _.first(systemIntegrations);

      return next();
    }
  );
}

function _generateImage(bag, next) {
  var who = bag.who + '|' + _generateImage.name;
  logger.verbose(who, 'Inside');

  bag.config.image = util.format('%s/%s:%s',
    bag.registry, bag.config.serviceName, bag.releaseVersion);

  return next();
}

function _generateEnvs(bag, next) {
  var who = bag.who + '|' + _generateEnvs.name;
  logger.verbose(who, 'Inside');

  var apiUrl = bag.apiSystemIntegration.data &&
    bag.apiSystemIntegration.data.url;

  if (!apiUrl)
    return next(
      new ActErr(who, ActErr.OperationFailed,
        'No apiUrl found.')
    );

  var amqpUrlRoot = bag.msgSystemIntegration.data &&
    bag.msgSystemIntegration.data.amqpUrlRoot;

  if (!amqpUrlRoot)
    return next(
      new ActErr(who, ActErr.OperationFailed,
        'No amqpUrlRoot found.')
    );

  var amqpDefaultExchange = bag.msgSystemIntegration.data &&
    bag.msgSystemIntegration.data.amqpDefaultExchange;

  if (!amqpDefaultExchange)
    return next(
      new ActErr(who, ActErr.OperationFailed,
        'No amqpDefaultExchange found.')
    );

  var envs = '';
  envs = util.format('%s -e %s=%s',
    envs, 'SHIPPABLE_API_TOKEN', bag.serviceUserToken);
  envs = util.format('%s -e %s=%s',
    envs, 'SHIPPABLE_API_URL', apiUrl);
  envs = util.format('%s -e %s=%s',
    envs, 'SHIPPABLE_ROOT_AMQP_URL', amqpUrlRoot);
  envs = util.format('%s -e %s=%s',
    envs, 'SHIPPABLE_AMQP_DEFAULT_EXCHANGE', amqpDefaultExchange);

  bag.envs = envs;
  return next();
}

function _generateMounts(bag, next) {
  var who = bag.who + '|' + _generateMounts.name;
  logger.verbose(who, 'Inside');

  bag.mounts = '';
  return next();
}

function _generateRunCommandOnebox(bag, next) {
  if (bag.isSwarmClusterInitialized) return next();

  var who = bag.who + '|' + _generateRunCommandOnebox.name;
  logger.verbose(who, 'Inside');

  var opts = ' --network=host' +
    ' --privileged=true';

  var runCommand = util.format('docker run -d ' +
    ' %s %s %s --name %s %s',
    bag.envs,
    bag.mounts,
    opts,
    bag.config.serviceName,
    bag.config.image);

  bag.runCommand = runCommand;
  return next();
}

function _generateRunCommandCluster(bag, next) {
  if (!bag.isSwarmClusterInitialized) return next();

  var who = bag.who + '|' + _generateRunCommandCluster.name;
  logger.verbose(who, 'Inside');

  var replicas = util.format(' --replicas %s', bag.config.replicas);
  if (bag.replicas === 'global')
    replicas = ' --mode global';

  var opts = ' --network ingress' +
    ' --with-registry-auth' +
    ' --endpoint-mode vip';

  var runCommand = util.format('docker service create ' +
    ' %s %s %s --name %s %s',
    bag.envs,
    opts,
    replicas,
    bag.config.serviceName,
    bag.config.image
  );

  bag.runCommand = runCommand;
  return next();
}
<|endoftext|>


<commit_before>/**
 * @license
 * Copyright (C) 2011 The Libphonenumber Authors
 *
 * 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 String constants of region codes for testing.
 * @author Nikolaos Trogkanis
 */

goog.provide('i18n.phonenumbers.RegionCode');

/**
 * Enum containing string constants of region codes for easier testing.
 *
 * @enum {string}
 */
i18n.phonenumbers.RegionCode = {
  // Region code for global networks (e.g. +800 numbers).
  UN001: '001',
  AD: 'AD',
  AO: 'AO',
  AQ: 'AQ',
  AR: 'AR',
  AU: 'AU',
  BR: 'BR',
  BS: 'BS',
  BY: 'BY',
  CA: 'CA',
  CN: 'CN',
  CS: 'CS',
  DE: 'DE',
  GB: 'GB',
  IT: 'IT',
  JP: 'JP',
  KR: 'KR',
  MX: 'MX',
  NZ: 'NZ',
  PL: 'PL',
  RE: 'RE',
  SG: 'SG',
  US: 'US',
  YT: 'YT',
  ZW: 'ZW',
  // Official code for the unknown region.
  ZZ: 'ZZ'
};
<commit_msg>JS: Remove errornous svn:executable property from source code file.<commit_after>/**
 * @license
 * Copyright (C) 2011 The Libphonenumber Authors
 *
 * 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 String constants of region codes for testing.
 * @author Nikolaos Trogkanis
 */

goog.provide('i18n.phonenumbers.RegionCode');

/**
 * Enum containing string constants of region codes for easier testing.
 *
 * @enum {string}
 */
i18n.phonenumbers.RegionCode = {
  // Region code for global networks (e.g. +800 numbers).
  UN001: '001',
  AD: 'AD',
  AO: 'AO',
  AQ: 'AQ',
  AR: 'AR',
  AU: 'AU',
  BR: 'BR',
  BS: 'BS',
  BY: 'BY',
  CA: 'CA',
  CN: 'CN',
  CS: 'CS',
  DE: 'DE',
  GB: 'GB',
  IT: 'IT',
  JP: 'JP',
  KR: 'KR',
  MX: 'MX',
  NZ: 'NZ',
  PL: 'PL',
  RE: 'RE',
  SG: 'SG',
  US: 'US',
  YT: 'YT',
  ZW: 'ZW',
  // Official code for the unknown region.
  ZZ: 'ZZ'
};
<|endoftext|>


<commit_before>var should = require('should');
var sinon = require('sinon');
var assert = require('assert');
var setup = require('./../mocks/setup');

setup.makeSuite('add data service', function() {

  var dataService = require('./../../src/services/data');
  var projectService = require('./../../src/services/project');
  var elasticData = require('./../../src/elastic/data');

  beforeEach(function(done) {
    projectService.ensureCollection({
      projectName: 'test',
      collectionName: 'city'
    }, function(err, res) {
      assert.equal(err, null);
      done();
    });
  });

  it('should add documents (batch) successfully', function(done) {
    var doc = {
      rating: 6,
      name: 'Berlin'
    };

    var spy = sinon.spy(elasticData, 'addDocuments');
    dataService.addDocumentsAsync({
      projectName: 'test',
      collectionName: 'city',
      body: [doc, doc, doc, doc],
    })
    .then(function(res) {
      //assert.equal(err, null);
      assert.equal(res.items.length, 4);
      assert(spy.calledOnce);
      assert(spy.calledWithMatch({index: 'test'}));
      assert(spy.calledWithMatch({type: 'city'}));
      done();
    });
  });

  it('should add all documents with configuration successfully', function(done) {
    var doc = {
      rating: 6,
      name: 'Berlin'
    };

    var spy = sinon.spy(dataService, 'addDocuments');
    dataService.addAllDocuments({
      projectName: 'test',
      collectionName: 'city',
      body: [doc, doc],
    }, function(err, res) {
      assert.equal(err, null);
      assert(spy.calledOnce);
      assert(spy.firstCall.calledWithMatch({projectName: 'test'}));
      assert(spy.firstCall.calledWithMatch({collectionName: 'city'}));

      dataService.addDocuments.restore();
      done();
    });
  });

  it('should add more documents successfully', function(done) {
    var doc = {
      rating: 6,
      name: 'France'
    };

    var data = {
      projectName: 'test',
      collectionName: 'city',
      batchSize: 4,
      body: [doc, doc, doc, doc, doc, doc, doc, doc, doc, doc],
    }

    var spy = sinon.spy(dataService, 'addDocuments');
    dataService.addAllDocuments(data, function(err, res) {
      assert.equal(err, null);
      assert.equal(spy.callCount, 3);
      assert(spy.firstCall.calledWithMatch({projectName: 'test'}));
      assert(spy.firstCall.calledWithMatch({collectionName: 'city'}));
      assert(spy.firstCall.calledWith(sinon.match({collectionName: 'city'})));
      dataService.addDocuments.restore();
      done();
    })
  });

  it('should add document successfully', function(done) {

    var spy = sinon.spy(elasticData, 'addDocument');
    dataService.addDocumentAsync({
      projectName: 'test',
      collectionName: 'city',
      body: {rating: 5, name: 'Berlin', id: 5},
    }).then(function(res) {
      //assert.equal(err, null);
      assert.equal(spy.callCount, 1);
      assert(spy.firstCall.calledWithMatch({index: 'test'}));
      assert(spy.firstCall.calledWithMatch({type: 'city'}));
      assert(spy.firstCall.calledWithMatch({id: 5}));
      assert(spy.firstCall.calledWith(sinon.match({type: 'city'})));
      elasticData.addDocument.restore();
      done();
    });
  });

  it('should get document successfully', function(done) {

    var spy = sinon.spy(elasticData, 'getDocument');
    dataService.getDocument({
      projectName: 'test',
      collectionName: 'city',
      id: 5
    }, function(err, res) {
      assert.equal(err, null);
      assert.equal(spy.callCount, 1);
      assert(spy.firstCall.calledWithMatch({index: 'test'}));
      assert(spy.firstCall.calledWithMatch({type: 'city'}));
      assert(spy.firstCall.calledWithMatch({id: 5}));
      elasticData.getDocument.restore();
      done();
    });
  });
});
<commit_msg>fix test<commit_after>var should = require('should');
var sinon = require('sinon');
var assert = require('assert');
var setup = require('./../mocks/setup');

setup.makeSuite('add data service', function() {

  var dataService = require('./../../src/services/data');
  var projectService = require('./../../src/services/project');
  var elasticData = require('./../../src/elastic/data');

  beforeEach(function(done) {
    projectService.ensureCollection({
      projectName: 'test',
      collectionName: 'city'
    }, function(err, res) {
      assert.equal(err, null);
      done();
    });
  });

  it('should add documents (batch) successfully', function(done) {
    var doc = {
      rating: 6,
      name: 'Berlin'
    };

    var spy = sinon.spy(elasticData, 'addDocuments');
    dataService.addDocumentsAsync({
      projectName: 'test',
      collectionName: 'city',
      body: [doc, doc, doc, doc],
    })
    .then(function(res) {
      //assert.equal(err, null);
      //assert.equal(res.items.length, 4);
      assert.equal(res.ids.length, 4);
      assert(spy.calledOnce);
      assert(spy.calledWithMatch({index: 'test'}));
      assert(spy.calledWithMatch({type: 'city'}));
      done();
    });
  });

  it('should add all documents with configuration successfully', function(done) {
    var doc = {
      rating: 6,
      name: 'Berlin'
    };

    var spy = sinon.spy(dataService, 'addDocuments');
    dataService.addAllDocuments({
      projectName: 'test',
      collectionName: 'city',
      body: [doc, doc],
    }, function(err, res) {
      assert.equal(err, null);
      assert(spy.calledOnce);
      assert(spy.firstCall.calledWithMatch({projectName: 'test'}));
      assert(spy.firstCall.calledWithMatch({collectionName: 'city'}));

      dataService.addDocuments.restore();
      done();
    });
  });

  it('should add more documents successfully', function(done) {
    var doc = {
      rating: 6,
      name: 'France'
    };

    var data = {
      projectName: 'test',
      collectionName: 'city',
      batchSize: 4,
      body: [doc, doc, doc, doc, doc, doc, doc, doc, doc, doc],
    }

    var spy = sinon.spy(dataService, 'addDocuments');
    dataService.addAllDocuments(data, function(err, res) {
      assert.equal(err, null);
      assert.equal(spy.callCount, 3);
      assert(spy.firstCall.calledWithMatch({projectName: 'test'}));
      assert(spy.firstCall.calledWithMatch({collectionName: 'city'}));
      assert(spy.firstCall.calledWith(sinon.match({collectionName: 'city'})));
      dataService.addDocuments.restore();
      done();
    })
  });

  it('should add document successfully', function(done) {

    var spy = sinon.spy(elasticData, 'addDocument');
    dataService.addDocumentAsync({
      projectName: 'test',
      collectionName: 'city',
      body: {rating: 5, name: 'Berlin', id: 5},
    }).then(function(res) {
      //assert.equal(err, null);
      assert.equal(spy.callCount, 1);
      assert(spy.firstCall.calledWithMatch({index: 'test'}));
      assert(spy.firstCall.calledWithMatch({type: 'city'}));
      assert(spy.firstCall.calledWithMatch({id: 5}));
      assert(spy.firstCall.calledWith(sinon.match({type: 'city'})));
      elasticData.addDocument.restore();
      done();
    });
  });

  it('should get document successfully', function(done) {

    var spy = sinon.spy(elasticData, 'getDocument');
    dataService.getDocument({
      projectName: 'test',
      collectionName: 'city',
      id: 5
    }, function(err, res) {
      assert.equal(err, null);
      assert.equal(spy.callCount, 1);
      assert(spy.firstCall.calledWithMatch({index: 'test'}));
      assert(spy.firstCall.calledWithMatch({type: 'city'}));
      assert(spy.firstCall.calledWithMatch({id: 5}));
      elasticData.getDocument.restore();
      done();
    });
  });
});
<|endoftext|>


<commit_before>const Mocha = require("mocha");
const chai = require("chai");
const path = require("path");
const { Web3Shim, InterfaceAdapter } = require("@truffle/interface-adapter");
const Config = require("@truffle/config");
const Contracts = require("@truffle/workflow-compile/new");
const Resolver = require("@truffle/resolver");
const TestRunner = require("./testing/testrunner");
const TestResolver = require("./testing/testresolver");
const TestSource = require("./testing/testsource");
const SolidityTest = require("./testing/soliditytest");
const expect = require("@truffle/expect");
const Migrate = require("@truffle/migrate");
const Profiler = require("@truffle/compile-solidity/profiler");
const originalrequire = require("original-require");

chai.use(require("./assertions"));

const Test = {
  run: async function(options) {
    expect.options(options, [
      "contracts_directory",
      "contracts_build_directory",
      "migrations_directory",
      "test_files",
      "network",
      "network_id",
      "provider"
    ]);

    const config = Config.default().merge(options);

    config.test_files = config.test_files.map(testFile => {
      return path.resolve(testFile);
    });

    const interfaceAdapter = new InterfaceAdapter();

    // `accounts` will be populated before each contract() invocation
    // and passed to it so tests don't have to call it themselves.
    const web3 = new Web3Shim({
      provider: config.provider,
      networkType: config.networks[config.network].type
    });

    // Override console.warn() because web3 outputs gross errors to it.
    // e.g., https://github.com/ethereum/web3.js/blob/master/lib/web3/allevents.js#L61
    // Output looks like this during tests: https://gist.github.com/tcoulter/1988349d1ec65ce6b958
    const warn = config.logger.warn;
    config.logger.warn = message => {
      if (message === "cannot find event for log") {
        return;
      } else {
        if (warn) warn.apply(console, arguments);
      }
    };

    const mocha = this.createMocha(config);

    const jsTests = config.test_files.filter(file => {
      return path.extname(file) !== ".sol";
    });

    const solTests = config.test_files.filter(file => {
      return path.extname(file) === ".sol";
    });

    // Add Javascript tests because there's nothing we need to do with them.
    // Solidity tests will be handled later.
    jsTests.forEach(file => {
      // There's an idiosyncracy in Mocha where the same file can't be run twice
      // unless we delete the `require` cache.
      // https://github.com/mochajs/mocha/issues/995
      delete originalrequire.cache[file];

      mocha.addFile(file);
    });

    const accounts = await this.getAccounts(web3, interfaceAdapter);

    if (!config.resolver) config.resolver = new Resolver(config);

    const testSource = new TestSource(config);
    const testResolver = new TestResolver(
      config.resolver,
      testSource,
      config.contracts_build_directory
    );
    testResolver.cache_on = false;

    const { compilations } = await this.compileContractsWithTestFilesIfNeeded(
      solTests,
      config,
      testResolver
    );

    const testContracts = solTests.map(testFilePath => {
      return testResolver.require(testFilePath);
    });

    const runner = new TestRunner(config);

    await this.performInitialDeploy(config, testResolver);

    await this.defineSolidityTests(
      mocha,
      testContracts,
      compilations.solc.sourceIndexes,
      runner
    );

    await this.setJSTestGlobals(
      web3,
      interfaceAdapter,
      accounts,
      testResolver,
      runner
    );

    // Finally, run mocha.
    process.on("unhandledRejection", reason => {
      throw reason;
    });

    return new Promise(resolve => {
      mocha.run(failures => {
        config.logger.warn = warn;

        resolve(failures);
      });
    });
  },

  createMocha: function(config) {
    // Allow people to specify config.mocha in their config.
    var mochaConfig = config.mocha || {};

    // If the command line overrides color usage, use that.
    if (config.colors != null) {
      mochaConfig.useColors = config.colors;
    }

    // Default to true if configuration isn't set anywhere.
    if (mochaConfig.useColors == null) {
      mochaConfig.useColors = true;
    }

    var mocha = new Mocha(mochaConfig);

    return mocha;
  },

  getAccounts: function(web3, interfaceAdapter) {
    return web3.eth.getAccounts();
  },

  compileContractsWithTestFilesIfNeeded: async function(
    solidityTestFiles,
    config,
    testResolver
  ) {
    const updated =
      (await Profiler.updated(config.with({ resolver: testResolver }))) || [];

    const compileConfig = config.with({
      all: config.compileAll === true,
      files: updated.concat(solidityTestFiles),
      resolver: testResolver,
      quiet: config.quiet,
      quietWrite: true
    });

    // Compile project contracts and test contracts
    const { contracts, compilations } = await Contracts.compile(compileConfig);

    await Contracts.save(compileConfig, contracts);

    return {
      contracts,
      compilations
    };
  },

  performInitialDeploy: function(config, resolver) {
    const migrateConfig = config.with({
      reset: true,
      resolver: resolver,
      quiet: true
    });
    return Migrate.run(migrateConfig);
  },

  defineSolidityTests: function(mocha, contracts, dependencyPaths, runner) {
    return new Promise(resolve => {
      contracts.forEach(contract => {
        SolidityTest.define(contract, dependencyPaths, runner, mocha);
      });

      resolve();
    });
  },

  setJSTestGlobals: function(
    web3,
    interfaceAdapter,
    accounts,
    testResolver,
    runner
  ) {
    return new Promise(function(accept) {
      global.interfaceAdapter = interfaceAdapter;
      global.web3 = web3;
      global.assert = chai.assert;
      global.expect = chai.expect;
      global.artifacts = {
        require: import_path => testResolver.require(import_path)
      };

      const template = function(tests) {
        this.timeout(runner.TEST_TIMEOUT);

        before("prepare suite", function(done) {
          this.timeout(runner.BEFORE_TIMEOUT);
          runner.initialize(done);
        });

        beforeEach("before test", function(done) {
          runner.startTest(this, done);
        });

        afterEach("after test", function(done) {
          runner.endTest(this, done);
        });

        tests(accounts);
      };

      global.contract = function(name, tests) {
        Mocha.describe("Contract: " + name, function() {
          template.bind(this, tests)();
        });
      };

      global.contract.only = function(name, tests) {
        Mocha.describe.only("Contract: " + name, function() {
          template.bind(this, tests)();
        });
      };

      global.contract.skip = function(name, tests) {
        Mocha.describe.skip("Contract: " + name, function() {
          template.bind(this, tests)();
        });
      };

      accept();
    });
  }
};

module.exports = Test;
<commit_msg>default to plain ol web3.js when no networkType specified during testing (core/lib/testing)<commit_after>const Mocha = require("mocha");
const chai = require("chai");
const path = require("path");
const { Web3Shim, InterfaceAdapter } = require("@truffle/interface-adapter");
const Config = require("@truffle/config");
const Contracts = require("@truffle/workflow-compile/new");
const Resolver = require("@truffle/resolver");
const TestRunner = require("./testing/testrunner");
const TestResolver = require("./testing/testresolver");
const TestSource = require("./testing/testsource");
const SolidityTest = require("./testing/soliditytest");
const expect = require("@truffle/expect");
const Migrate = require("@truffle/migrate");
const Profiler = require("@truffle/compile-solidity/profiler");
const originalrequire = require("original-require");

chai.use(require("./assertions"));

const Test = {
  run: async function(options) {
    expect.options(options, [
      "contracts_directory",
      "contracts_build_directory",
      "migrations_directory",
      "test_files",
      "network",
      "network_id",
      "provider"
    ]);

    const config = Config.default().merge(options);

    config.test_files = config.test_files.map(testFile => {
      return path.resolve(testFile);
    });

    const interfaceAdapter = new InterfaceAdapter();

    // `accounts` will be populated before each contract() invocation
    // and passed to it so tests don't have to call it themselves.
    const web3 = new Web3Shim({
      provider: config.provider,
      networkType: config.networks[config.network].type
        ? config.networks[config.network].type
        : "web3js"
    });

    // Override console.warn() because web3 outputs gross errors to it.
    // e.g., https://github.com/ethereum/web3.js/blob/master/lib/web3/allevents.js#L61
    // Output looks like this during tests: https://gist.github.com/tcoulter/1988349d1ec65ce6b958
    const warn = config.logger.warn;
    config.logger.warn = message => {
      if (message === "cannot find event for log") {
        return;
      } else {
        if (warn) warn.apply(console, arguments);
      }
    };

    const mocha = this.createMocha(config);

    const jsTests = config.test_files.filter(file => {
      return path.extname(file) !== ".sol";
    });

    const solTests = config.test_files.filter(file => {
      return path.extname(file) === ".sol";
    });

    // Add Javascript tests because there's nothing we need to do with them.
    // Solidity tests will be handled later.
    jsTests.forEach(file => {
      // There's an idiosyncracy in Mocha where the same file can't be run twice
      // unless we delete the `require` cache.
      // https://github.com/mochajs/mocha/issues/995
      delete originalrequire.cache[file];

      mocha.addFile(file);
    });

    const accounts = await this.getAccounts(web3, interfaceAdapter);

    if (!config.resolver) config.resolver = new Resolver(config);

    const testSource = new TestSource(config);
    const testResolver = new TestResolver(
      config.resolver,
      testSource,
      config.contracts_build_directory
    );
    testResolver.cache_on = false;

    const { compilations } = await this.compileContractsWithTestFilesIfNeeded(
      solTests,
      config,
      testResolver
    );

    const testContracts = solTests.map(testFilePath => {
      return testResolver.require(testFilePath);
    });

    const runner = new TestRunner(config);

    await this.performInitialDeploy(config, testResolver);

    await this.defineSolidityTests(
      mocha,
      testContracts,
      compilations.solc.sourceIndexes,
      runner
    );

    await this.setJSTestGlobals(
      web3,
      interfaceAdapter,
      accounts,
      testResolver,
      runner
    );

    // Finally, run mocha.
    process.on("unhandledRejection", reason => {
      throw reason;
    });

    return new Promise(resolve => {
      mocha.run(failures => {
        config.logger.warn = warn;

        resolve(failures);
      });
    });
  },

  createMocha: function(config) {
    // Allow people to specify config.mocha in their config.
    var mochaConfig = config.mocha || {};

    // If the command line overrides color usage, use that.
    if (config.colors != null) {
      mochaConfig.useColors = config.colors;
    }

    // Default to true if configuration isn't set anywhere.
    if (mochaConfig.useColors == null) {
      mochaConfig.useColors = true;
    }

    var mocha = new Mocha(mochaConfig);

    return mocha;
  },

  getAccounts: function(web3, interfaceAdapter) {
    return web3.eth.getAccounts();
  },

  compileContractsWithTestFilesIfNeeded: async function(
    solidityTestFiles,
    config,
    testResolver
  ) {
    const updated =
      (await Profiler.updated(config.with({ resolver: testResolver }))) || [];

    const compileConfig = config.with({
      all: config.compileAll === true,
      files: updated.concat(solidityTestFiles),
      resolver: testResolver,
      quiet: config.quiet,
      quietWrite: true
    });

    // Compile project contracts and test contracts
    const { contracts, compilations } = await Contracts.compile(compileConfig);

    await Contracts.save(compileConfig, contracts);

    return {
      contracts,
      compilations
    };
  },

  performInitialDeploy: function(config, resolver) {
    const migrateConfig = config.with({
      reset: true,
      resolver: resolver,
      quiet: true
    });
    return Migrate.run(migrateConfig);
  },

  defineSolidityTests: function(mocha, contracts, dependencyPaths, runner) {
    return new Promise(resolve => {
      contracts.forEach(contract => {
        SolidityTest.define(contract, dependencyPaths, runner, mocha);
      });

      resolve();
    });
  },

  setJSTestGlobals: function(
    web3,
    interfaceAdapter,
    accounts,
    testResolver,
    runner
  ) {
    return new Promise(function(accept) {
      global.interfaceAdapter = interfaceAdapter;
      global.web3 = web3;
      global.assert = chai.assert;
      global.expect = chai.expect;
      global.artifacts = {
        require: import_path => testResolver.require(import_path)
      };

      const template = function(tests) {
        this.timeout(runner.TEST_TIMEOUT);

        before("prepare suite", function(done) {
          this.timeout(runner.BEFORE_TIMEOUT);
          runner.initialize(done);
        });

        beforeEach("before test", function(done) {
          runner.startTest(this, done);
        });

        afterEach("after test", function(done) {
          runner.endTest(this, done);
        });

        tests(accounts);
      };

      global.contract = function(name, tests) {
        Mocha.describe("Contract: " + name, function() {
          template.bind(this, tests)();
        });
      };

      global.contract.only = function(name, tests) {
        Mocha.describe.only("Contract: " + name, function() {
          template.bind(this, tests)();
        });
      };

      global.contract.skip = function(name, tests) {
        Mocha.describe.skip("Contract: " + name, function() {
          template.bind(this, tests)();
        });
      };

      accept();
    });
  }
};

module.exports = Test;
<|endoftext|>


<commit_before>import Stream from "stream";
import _ from 'lodash';
import {Parser} from "binary-parser";
import AuroraConstants from './AuroraConstants';

export default class AuroraCmdTransformBinary extends Stream.Transform {

    static defaultOptions = {
        dataType: AuroraConstants.DataTypes.UINT8,
        parseType: undefined,
        parseTypeLength: undefined
    };

    constructor(options) {

        super();

        this.options = _.defaultsDeep(options, AuroraCmdTransformBinary.defaultOptions);

        if (typeof this.options.parseType == 'undefined') {

            this.options.parseType = this._getParseTypeFromDataType(this.options.dataType);
        }

        if (typeof this.options.parseTypeLength == 'undefined') {

            this.options.parseTypeLength = this._getParseTypeLengthFromDataType(this.options.dataType);
        }

        this.parser = new Parser();

        this.leftoverBuffer = null;
        this.hasData = false;

        this.parser.array('values', {
            type: this.options.parseType,
            readUntil: 'eof',
            formatter: function(values) {
                console.log('parse', values);
                return values.join(',');
            }
        });
    }

    _transform(respChunk, encoding, done) {

        console.log('chunk', respChunk);

        if (Buffer.isBuffer(this.leftoverBuffer)){

            respChunk = Buffer.concat([this.leftoverBuffer, respChunk], this.leftoverBuffer.length + respChunk.length);
            this.leftoverBuffer = null;
        }

        if (respChunk.length < this.options.parseTypeLength) {

            this.leftoverBuffer = respChunk;
            done();
            return;
        }

        this.hasData = true;

        const numBytesLeftover = respChunk.length % this.options.parseTypeLength;

        console.log('bytes leftover', numBytesLeftover);

        if (numBytesLeftover) {

            this.push((this.hasData ? ',' : '') + this.parser.parse(respChunk.slice(0, -numBytesLeftover)));
            this.leftoverBuffer = respChunk.slice(-numBytesLeftover);
        }
        else {
            this.push((this.hasData ? ',' : '') + this.parser.parse(respChunk));
        }

        done();
    }

    _flush(done) {

        if (this.leftoverBuffer) {
            console.log("Unparsed binary buffer: ", this.leftoverBuffer);
        }

        this.hasData = false;

        done();
    }

    _getParseTypeFromDataType(dataType) {

        switch(dataType){

            case AuroraConstants.DataTypes.INT8 :
                return 'int8';

            case AuroraConstants.DataTypes.UINT16 :
                return 'uint16le';

            case AuroraConstants.DataTypes.INT16 :
                return 'int16le';

            case AuroraConstants.DataTypes.UINT32 :
            case AuroraConstants.DataTypes.STR :
            case AuroraConstants.DataTypes.PTR :

                return 'uint32le';

            case AuroraConstants.DataTypes.INT32 :
                return 'int32le';

            case AuroraConstants.DataTypes.UINT8 :
            case AuroraConstants.DataTypes.CHAR :
            default:
                return 'uint8';

        }
    }

    _getParseTypeLengthFromDataType(dataType) {

        switch(dataType){

            case AuroraConstants.DataTypes.UINT16 :
            case AuroraConstants.DataTypes.INT16 :
                return 2;

            case AuroraConstants.DataTypes.UINT32 :
            case AuroraConstants.DataTypes.STR :
            case AuroraConstants.DataTypes.PTR :
            case AuroraConstants.DataTypes.INT32 :
                return 4;

            case AuroraConstants.DataTypes.UINT8 :
            case AuroraConstants.DataTypes.CHAR :
            case AuroraConstants.DataTypes.INT8 :
            default:
                return 1;

        }
    }

}<commit_msg>Added Float data type to binary parser.<commit_after>import Stream from "stream";
import _ from 'lodash';
import {Parser} from "binary-parser";
import AuroraConstants from './AuroraConstants';

export default class AuroraCmdTransformBinary extends Stream.Transform {

    static defaultOptions = {
        dataType: AuroraConstants.DataTypes.UINT8,
        parseType: undefined,
        parseTypeLength: undefined
    };

    constructor(options) {

        super();

        this.options = _.defaultsDeep(options, AuroraCmdTransformBinary.defaultOptions);

        if (typeof this.options.parseType == 'undefined') {

            this.options.parseType = this._getParseTypeFromDataType(this.options.dataType);
        }

        if (typeof this.options.parseTypeLength == 'undefined') {

            this.options.parseTypeLength = this._getParseTypeLengthFromDataType(this.options.dataType);
        }

        this.parser = new Parser();

        this.leftoverBuffer = null;
        this.hasData = false;

        this.parser.array('values', {
            type: this.options.parseType,
            readUntil: 'eof',
            formatter: function(values) {
                console.log('parse', values).join(',');
                return values.join(',');
            }
        });
    }

    _transform(respChunk, encoding, done) {

        console.log('chunk', respChunk);

        if (Buffer.isBuffer(this.leftoverBuffer)){

            respChunk = Buffer.concat([this.leftoverBuffer, respChunk], this.leftoverBuffer.length + respChunk.length);
            this.leftoverBuffer = null;
        }

        if (respChunk.length < this.options.parseTypeLength) {

            this.leftoverBuffer = respChunk;
            done();
            return;
        }

        this.hasData = true;

        const numBytesLeftover = respChunk.length % this.options.parseTypeLength;

        console.log('bytes leftover', numBytesLeftover);

        if (numBytesLeftover) {

            this.push((this.hasData ? ',' : '') + this.parser.parse(respChunk.slice(0, -numBytesLeftover)));
            this.leftoverBuffer = respChunk.slice(-numBytesLeftover);
        }
        else {
            this.push((this.hasData ? ',' : '') + this.parser.parse(respChunk));
        }

        done();
    }

    _flush(done) {

        if (this.leftoverBuffer) {
            console.log("Unparsed binary buffer: ", this.leftoverBuffer);
        }

        this.hasData = false;

        done();
    }

    _getParseTypeFromDataType(dataType) {

        switch(dataType){

            case AuroraConstants.DataTypes.INT8 :
                return 'int8';

            case AuroraConstants.DataTypes.UINT16 :
                return 'uint16le';

            case AuroraConstants.DataTypes.INT16 :
                return 'int16le';

            case AuroraConstants.DataTypes.FLOAT :
                return 'floatle';

            case AuroraConstants.DataTypes.UINT32 :
            case AuroraConstants.DataTypes.STR :
            case AuroraConstants.DataTypes.PTR :

                return 'uint32le';

            case AuroraConstants.DataTypes.INT32 :
                return 'int32le';

            case AuroraConstants.DataTypes.UINT8 :
            case AuroraConstants.DataTypes.CHAR :
            default:
                return 'uint8';

        }
    }

    _getParseTypeLengthFromDataType(dataType) {

        switch(dataType){

            case AuroraConstants.DataTypes.UINT16 :
            case AuroraConstants.DataTypes.INT16 :
                return 2;

            case AuroraConstants.DataTypes.UINT32 :
            case AuroraConstants.DataTypes.FLOAT :
            case AuroraConstants.DataTypes.STR :
            case AuroraConstants.DataTypes.PTR :
            case AuroraConstants.DataTypes.INT32 :
                return 4;

            case AuroraConstants.DataTypes.UINT8 :
            case AuroraConstants.DataTypes.CHAR :
            case AuroraConstants.DataTypes.INT8 :
            default:
                return 1;

        }
    }

}<|endoftext|>


<commit_before>/**
 * @class 关注
 */
var _ = require('underscore'),
	Promise = require('bluebird'),
	User = require('../models/user'),
	Followship = require('../models/followship'),
	Followships = Followship.Set,
	errors = require('../lib/errors');

module.exports = function (app) {
	/**
	 * POST /api/followship/following
	 * @method 用户的关注列表
	 * @param {Number} followid 被关注者ID
	 * @return {JSON}
	 */
	app.get('/api/followship/following', function (req, res, next) {
		if (!req.user) return next(errors[21301]);
		req.query = _.omit(req.query, ['userid']);
		req.user.following().fetch()
			.then(function (collection) {
				// relations fetching not enough
				return Followships.forge().set(collection.models)
					.fetch({ req: req, self: true });
			}).then(function (following) {
				next({ following: following });
			}).catch(next);
	});

	/**
	 * POST /api/followship/followers
	 * @method 用户的粉丝列表
	 * @param {Number} userid 关注者ID
	 * @return {JSON}
	 */
	app.get('/api/followship/followers', function (req, res, next) {
		if (!req.user) return next(errors[21301]);
		req.query = _.omit(req.query, ['followid']);
		req.user.followers().fetch()
			.then(function (collection) {
				return Followships.forge().set(collection.models)
					.fetch({ req: req, self: true });
			}).then(function (followers) {
				next({ followers: followers });
			}).catch(next);
	});

	/**
	 * POST /api/followship/follow
	 * @method 关注用户
	 * @param {Number} followid 被关注者ID
	 * @param {String} remark 备注名
	 * @return {JSON}
	 */
	app.post('/api/followship/follow', function (req, res, next) {
		var user = req.user;
		if (!user) return next(errors[21301]);
		req.body['userid'] = user.id;
		User.forge({
			id: req.body['followid']
		}).fetch()
			.then(function (user) {
				if (!user) throw errors[20003];
				return Followship.forge(
						_.pick(req.body, ['userid', 'followid', 'remark'])
					).save()
					.catch(function () {
						throw errors[20506];
					});
			}).then(function () {
				next({ msg: 'Followee followed' });
			}).catch(next);
	});

	/**
	 * POST /api/followship/unfollow
	 * @method 取消关注
	 * @param {Number} followid 被关注者ID
	 * @return {JSON}
	 */
	app.post('/api/followship/unfollow', function (req, res, next) {
		var user = req.user;
		if (!user) return next(errors[21301]);
		req.body['userid'] = user.id;
		Followship.forge(
				_.pick(req.body, ['userid', 'followid'])
			).fetch()
			.then(function (followship) {
				if (!followship) throw errors[20603];
				return followship.destroy();
			}).then(function () {
				next({ msg: 'Followee unfollowed' });
			}).catch(next);
	});

	/**
	 * POST /api/followship/remark
	 * @method 修改备注
	 * @param {Number} followid 粉丝ID
	 * @param {String} remark 备注名
	 * @return {JSON}
	 */
	app.post('/api/followship/remark', function (req, res, next) {
		var user = req.user;
		if (!user) return next(errors[21301]);
		req.body['userid'] = user.id;
		Followship.forge(
				_.pick(req.body, ['userid', 'followid'])
			).fetch()
			.then(function (followship) {
				if (!followship) throw errors[20603];
				return followship.set(
					_.pick(req.body, 'remark')
				).save();
			}).then(function () {
				next({ msg: 'Followee remarked' });
			}).catch(next);
	});
};
<commit_msg>修正注释<commit_after>/**
 * @class 关注
 */
var _ = require('underscore'),
	Promise = require('bluebird'),
	User = require('../models/user'),
	Followship = require('../models/followship'),
	Followships = Followship.Set,
	errors = require('../lib/errors');

module.exports = function (app) {
	/**
	 * GET /api/followship/following
	 * @method 用户的关注列表
	 * @param {Number} followid 被关注者ID
	 * @return {JSON}
	 */
	app.get('/api/followship/following', function (req, res, next) {
		if (!req.user) return next(errors[21301]);
		req.query = _.omit(req.query, ['userid']);
		req.user.following().fetch()
			.then(function (collection) {
				// relations fetching not enough
				return Followships.forge().set(collection.models)
					.fetch({ req: req, self: true });
			}).then(function (following) {
				next({ following: following });
			}).catch(next);
	});

	/**
	 * GET /api/followship/followers
	 * @method 用户的粉丝列表
	 * @param {Number} userid 关注者ID
	 * @return {JSON}
	 */
	app.get('/api/followship/followers', function (req, res, next) {
		if (!req.user) return next(errors[21301]);
		req.query = _.omit(req.query, ['followid']);
		req.user.followers().fetch()
			.then(function (collection) {
				return Followships.forge().set(collection.models)
					.fetch({ req: req, self: true });
			}).then(function (followers) {
				next({ followers: followers });
			}).catch(next);
	});

	/**
	 * POST /api/followship/follow
	 * @method 关注用户
	 * @param {Number} followid 被关注者ID
	 * @param {String} remark 备注名
	 * @return {JSON}
	 */
	app.post('/api/followship/follow', function (req, res, next) {
		var user = req.user;
		if (!user) return next(errors[21301]);
		req.body['userid'] = user.id;
		User.forge({
			id: req.body['followid']
		}).fetch()
			.then(function (user) {
				if (!user) throw errors[20003];
				return Followship.forge(
						_.pick(req.body, ['userid', 'followid', 'remark'])
					).save()
					.catch(function () {
						throw errors[20506];
					});
			}).then(function () {
				next({ msg: 'Followee followed' });
			}).catch(next);
	});

	/**
	 * POST /api/followship/unfollow
	 * @method 取消关注
	 * @param {Number} followid 被关注者ID
	 * @return {JSON}
	 */
	app.post('/api/followship/unfollow', function (req, res, next) {
		var user = req.user;
		if (!user) return next(errors[21301]);
		req.body['userid'] = user.id;
		Followship.forge(
				_.pick(req.body, ['userid', 'followid'])
			).fetch()
			.then(function (followship) {
				if (!followship) throw errors[20603];
				return followship.destroy();
			}).then(function () {
				next({ msg: 'Followee unfollowed' });
			}).catch(next);
	});

	/**
	 * POST /api/followship/remark
	 * @method 修改备注
	 * @param {Number} followid 粉丝ID
	 * @param {String} remark 备注名
	 * @return {JSON}
	 */
	app.post('/api/followship/remark', function (req, res, next) {
		var user = req.user;
		if (!user) return next(errors[21301]);
		req.body['userid'] = user.id;
		Followship.forge(
				_.pick(req.body, ['userid', 'followid'])
			).fetch()
			.then(function (followship) {
				if (!followship) throw errors[20603];
				return followship.set(
					_.pick(req.body, 'remark')
				).save();
			}).then(function () {
				next({ msg: 'Followee remarked' });
			}).catch(next);
	});
};
<|endoftext|>


<commit_before>'use strict';

//  ---------------------------------------------------------------------------

const Exchange = require ('./base/Exchange');
const { ExchangeError, ArgumentsRequired } = require ('./base/errors');

//  ---------------------------------------------------------------------------

module.exports = class gemini extends Exchange {
    describe () {
        return this.deepExtend (super.describe (), {
            'id': 'gemini',
            'name': 'Gemini',
            'countries': [ 'US' ],
            'rateLimit': 1500, // 200 for private API
            'version': 'v1',
            'has': {
                'fetchDepositAddress': false,
                'createDepositAddress': true,
                'CORS': false,
                'fetchBidsAsks': false,
                'fetchTickers': false,
                'fetchMyTrades': true,
                'fetchOrder': true,
                'fetchOrders': false,
                'fetchOpenOrders': true,
                'fetchClosedOrders': false,
                'createMarketOrder': false,
                'withdraw': true,
                'fetchTransactions': true,
                'fetchWithdrawals': false,
                'fetchDeposits': false,
            },
            'urls': {
                'logo': 'https://user-images.githubusercontent.com/1294454/27816857-ce7be644-6096-11e7-82d6-3c257263229c.jpg',
                'api': 'https://api.gemini.com',
                'www': 'https://gemini.com',
                'doc': [
                    'https://docs.gemini.com/rest-api',
                    'https://docs.sandbox.gemini.com',
                ],
                'test': 'https://api.sandbox.gemini.com',
                'fees': [
                    'https://gemini.com/fee-schedule/',
                    'https://gemini.com/transfer-fees/',
                ],
            },
            'api': {
                'public': {
                    'get': [
                        'symbols',
                        'pubticker/{symbol}',
                        'book/{symbol}',
                        'trades/{symbol}',
                        'auction/{symbol}',
                        'auction/{symbol}/history',
                    ],
                },
                'private': {
                    'post': [
                        'order/new',
                        'order/cancel',
                        'order/cancel/session',
                        'order/cancel/all',
                        'order/status',
                        'orders',
                        'mytrades',
                        'tradevolume',
                        'transfers',
                        'balances',
                        'deposit/{currency}/newAddress',
                        'withdraw/{currency}',
                        'heartbeat',
                        'transfers',
                    ],
                },
            },
            'fees': {
                'trading': {
                    'taker': 0.0025,
                    'maker': 0.0025,
                },
            },
        });
    }

    async fetchMarkets (params = {}) {
        let markets = await this.publicGetSymbols ();
        let result = [];
        for (let p = 0; p < markets.length; p++) {
            let id = markets[p];
            let market = id;
            let uppercase = market.toUpperCase ();
            let base = uppercase.slice (0, 3);
            let quote = uppercase.slice (3, 6);
            let symbol = base + '/' + quote;
            result.push ({
                'id': id,
                'symbol': symbol,
                'base': base,
                'quote': quote,
                'info': market,
            });
        }
        return result;
    }

    async fetchOrderBook (symbol, limit = undefined, params = {}) {
        await this.loadMarkets ();
        const request = {
            'symbol': this.marketId (symbol),
        };
        if (limit !== undefined) {
            request['limit_bids'] = limit;
            request['limit_asks'] = limit;
        }
        const response = await this.publicGetBookSymbol (this.extend (request, params));
        return this.parseOrderBook (response, undefined, 'bids', 'asks', 'price', 'amount');
    }

    async fetchTicker (symbol, params = {}) {
        await this.loadMarkets ();
        let market = this.market (symbol);
        let ticker = await this.publicGetPubtickerSymbol (this.extend ({
            'symbol': market['id'],
        }, params));
        let timestamp = ticker['volume']['timestamp'];
        let baseVolume = market['base'];
        let quoteVolume = market['quote'];
        let last = this.safeFloat (ticker, 'last');
        return {
            'symbol': symbol,
            'timestamp': timestamp,
            'datetime': this.iso8601 (timestamp),
            'high': undefined,
            'low': undefined,
            'bid': this.safeFloat (ticker, 'bid'),
            'bidVolume': undefined,
            'ask': this.safeFloat (ticker, 'ask'),
            'askVolume': undefined,
            'vwap': undefined,
            'open': undefined,
            'close': last,
            'last': last,
            'previousClose': undefined,
            'change': undefined,
            'percentage': undefined,
            'average': undefined,
            'baseVolume': parseFloat (ticker['volume'][baseVolume]),
            'quoteVolume': parseFloat (ticker['volume'][quoteVolume]),
            'info': ticker,
        };
    }

    parseTrade (trade, market) {
        let timestamp = trade['timestampms'];
        let order = undefined;
        if ('order_id' in trade)
            order = trade['order_id'].toString ();
        let fee = this.safeFloat (trade, 'fee_amount');
        if (fee !== undefined) {
            let currency = this.safeString (trade, 'fee_currency');
            if (currency !== undefined) {
                if (currency in this.currencies_by_id)
                    currency = this.currencies_by_id[currency]['code'];
                currency = this.commonCurrencyCode (currency);
            }
            fee = {
                'cost': this.safeFloat (trade, 'fee_amount'),
                'currency': currency,
            };
        }
        let price = this.safeFloat (trade, 'price');
        let amount = this.safeFloat (trade, 'amount');
        return {
            'id': trade['tid'].toString (),
            'order': order,
            'info': trade,
            'timestamp': timestamp,
            'datetime': this.iso8601 (timestamp),
            'symbol': market['symbol'],
            'type': undefined,
            'side': trade['type'].toLowerCase (),
            'price': price,
            'cost': price * amount,
            'amount': amount,
            'fee': fee,
        };
    }

    async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) {
        await this.loadMarkets ();
        let market = this.market (symbol);
        let response = await this.publicGetTradesSymbol (this.extend ({
            'symbol': market['id'],
        }, params));
        return this.parseTrades (response, market, since, limit);
    }

    async fetchBalance (params = {}) {
        await this.loadMarkets ();
        let balances = await this.privatePostBalances ();
        let result = { 'info': balances };
        for (let b = 0; b < balances.length; b++) {
            let balance = balances[b];
            let currency = balance['currency'];
            let account = {
                'free': parseFloat (balance['available']),
                'used': 0.0,
                'total': parseFloat (balance['amount']),
            };
            account['used'] = account['total'] - account['free'];
            result[currency] = account;
        }
        return this.parseBalance (result);
    }

    parseOrder (order, market = undefined) {
        let timestamp = order['timestampms'];
        let amount = this.safeFloat (order, 'original_amount');
        let remaining = this.safeFloat (order, 'remaining_amount');
        let filled = this.safeFloat (order, 'executed_amount');
        let status = 'closed';
        if (order['is_live']) {
            status = 'open';
        }
        if (order['is_cancelled']) {
            status = 'canceled';
        }
        let price = this.safeFloat (order, 'price');
        let average = this.safeFloat (order, 'avg_execution_price');
        if (average !== 0.0) {
            price = average; // prefer filling (execution) price over the submitted price
        }
        let cost = undefined;
        if (filled !== undefined) {
            if (average !== undefined) {
                cost = filled * average;
            }
        }
        let type = this.safeString (order, 'type');
        if (type === 'exchange limit') {
            type = 'limit';
        } else if (type === 'market buy' || type === 'market sell') {
            type = 'market';
        } else {
            type = order['type'];
        }
        let fee = undefined;
        let symbol = undefined;
        if (market === undefined) {
            let marketId = this.safeString (order, 'symbol');
            if (marketId in this.markets_by_id) {
                market = this.markets_by_id[marketId];
            }
        }
        if (market !== undefined) {
            symbol = market['symbol'];
        }
        return {
            'id': order['order_id'],
            'info': order,
            'timestamp': timestamp,
            'datetime': this.iso8601 (timestamp),
            'lastTradeTimestamp': undefined,
            'status': status,
            'symbol': symbol,
            'type': type,
            'side': order['side'].toLowerCase (),
            'price': price,
            'average': average,
            'cost': cost,
            'amount': amount,
            'filled': filled,
            'remaining': remaining,
            'fee': fee,
        };
    }

    async fetchOrder (id, symbol = undefined, params = {}) {
        await this.loadMarkets ();
        let response = await this.privatePostOrderStatus (this.extend ({
            'order_id': id,
        }, params));
        return this.parseOrder (response);
    }

    async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
        await this.loadMarkets ();
        let response = await this.privatePostOrders (params);
        let orders = this.parseOrders (response, undefined, since, limit);
        if (symbol !== undefined) {
            let market = this.market (symbol); // throws on non-existent symbol
            orders = this.filterBySymbol (orders, market['symbol']);
        }
        return orders;
    }

    async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
        await this.loadMarkets ();
        if (type === 'market')
            throw new ExchangeError (this.id + ' allows limit orders only');
        let nonce = this.nonce ();
        let order = {
            'client_order_id': nonce.toString (),
            'symbol': this.marketId (symbol),
            'amount': amount.toString (),
            'price': price.toString (),
            'side': side,
            'type': 'exchange limit', // gemini allows limit orders only
        };
        let response = await this.privatePostOrderNew (this.extend (order, params));
        return {
            'info': response,
            'id': response['order_id'],
        };
    }

    async cancelOrder (id, symbol = undefined, params = {}) {
        await this.loadMarkets ();
        return await this.privatePostOrderCancel ({ 'order_id': id });
    }

    async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) {
        if (symbol === undefined)
            throw new ArgumentsRequired (this.id + ' fetchMyTrades requires a symbol argument');
        await this.loadMarkets ();
        let market = this.market (symbol);
        let request = {
            'symbol': market['id'],
        };
        if (limit !== undefined)
            request['limit_trades'] = limit;
        if (since !== undefined)
            request['timestamp'] = parseInt (since / 1000);
        let response = await this.privatePostMytrades (this.extend (request, params));
        return this.parseTrades (response, market, since, limit);
    }

    async withdraw (code, amount, address, tag = undefined, params = {}) {
        this.checkAddress (address);
        await this.loadMarkets ();
        let currency = this.currency (code);
        let response = await this.privatePostWithdrawCurrency (this.extend ({
            'currency': currency['id'],
            'amount': amount,
            'address': address,
        }, params));
        return {
            'info': response,
            'id': this.safeString (response, 'txHash'),
        };
    }

    nonce () {
        return this.milliseconds ();
    }

    async fetchTransactions (code = undefined, since = undefined, limit = undefined, params = {}) {
        await this.loadMarkets ();
        let request = {};
        let response = await this.privatePostTransfers (this.extend (request, params));
        return this.parseTransactions (response);
    }

    parseTransaction (transaction, currency = undefined) {
        let timestamp = this.safeInteger (transaction, 'timestampms');
        let code = undefined;
        if (currency === undefined) {
            let currencyId = this.safeString (transaction, 'currency');
            if (currencyId in this.currencies_by_id) {
                currency = this.currencies_by_id[currencyId];
            }
        }
        if (currency !== undefined) {
            code = currency['code'];
        }
        let type = this.safeString (transaction, 'type');
        if (type !== undefined) {
            type = type.toLowerCase ();
        }
        let status = 'pending';
        // When deposits show as Advanced or Complete they are available for trading.
        if (transaction['status'])
            status = 'ok';
        return {
            'info': transaction,
            'id': this.safeString (transaction, 'eid'),
            'txid': this.safeString (transaction, 'txHash'),
            'timestamp': timestamp,
            'datetime': this.iso8601 (timestamp),
            'address': undefined, // or is it defined?
            'tag': undefined, // or is it defined?
            'type': type, // direction of the transaction, ('deposit' | 'withdraw')
            'amount': this.safeFloat (transaction, 'amount'),
            'currency': code,
            'status': status,
            'updated': undefined,
            'fee': {
                'cost': undefined,
                'rate': undefined,
            },
        };
    }

    sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
        let url = '/' + this.version + '/' + this.implodeParams (path, params);
        let query = this.omit (params, this.extractParams (path));
        if (api === 'public') {
            if (Object.keys (query).length)
                url += '?' + this.urlencode (query);
        } else {
            this.checkRequiredCredentials ();
            let nonce = this.nonce ();
            let request = this.extend ({
                'request': url,
                'nonce': nonce,
            }, query);
            let payload = this.json (request);
            payload = this.stringToBase64 (this.encode (payload));
            let signature = this.hmac (payload, this.encode (this.secret), 'sha384');
            headers = {
                'Content-Type': 'text/plain',
                'X-GEMINI-APIKEY': this.apiKey,
                'X-GEMINI-PAYLOAD': this.decode (payload),
                'X-GEMINI-SIGNATURE': signature,
            };
        }
        url = this.urls['api'] + url;
        return { 'url': url, 'method': method, 'body': body, 'headers': headers };
    }

    async request (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
        let response = await this.fetch2 (path, api, method, params, headers, body);
        if ('result' in response)
            if (response['result'] === 'error')
                throw new ExchangeError (this.id + ' ' + this.json (response));
        return response;
    }

    async createDepositAddress (code, params = {}) {
        await this.loadMarkets ();
        let currency = this.currency (code);
        let response = await this.privatePostDepositCurrencyNewAddress (this.extend ({
            'currency': currency['id'],
        }, params));
        let address = this.safeString (response, 'address');
        this.checkAddress (address);
        return {
            'currency': code,
            'address': address,
            'tag': undefined,
            'info': response,
        };
    }
};
<commit_msg>[gemini] updated fees (again)<commit_after>'use strict';

//  ---------------------------------------------------------------------------

const Exchange = require ('./base/Exchange');
const { ExchangeError, ArgumentsRequired } = require ('./base/errors');

//  ---------------------------------------------------------------------------

module.exports = class gemini extends Exchange {
    describe () {
        return this.deepExtend (super.describe (), {
            'id': 'gemini',
            'name': 'Gemini',
            'countries': [ 'US' ],
            'rateLimit': 1500, // 200 for private API
            'version': 'v1',
            'has': {
                'fetchDepositAddress': false,
                'createDepositAddress': true,
                'CORS': false,
                'fetchBidsAsks': false,
                'fetchTickers': false,
                'fetchMyTrades': true,
                'fetchOrder': true,
                'fetchOrders': false,
                'fetchOpenOrders': true,
                'fetchClosedOrders': false,
                'createMarketOrder': false,
                'withdraw': true,
                'fetchTransactions': true,
                'fetchWithdrawals': false,
                'fetchDeposits': false,
            },
            'urls': {
                'logo': 'https://user-images.githubusercontent.com/1294454/27816857-ce7be644-6096-11e7-82d6-3c257263229c.jpg',
                'api': 'https://api.gemini.com',
                'www': 'https://gemini.com',
                'doc': [
                    'https://docs.gemini.com/rest-api',
                    'https://docs.sandbox.gemini.com',
                ],
                'test': 'https://api.sandbox.gemini.com',
                'fees': [
                    'https://gemini.com/fee-schedule/',
                    'https://gemini.com/transfer-fees/',
                ],
            },
            'api': {
                'public': {
                    'get': [
                        'symbols',
                        'pubticker/{symbol}',
                        'book/{symbol}',
                        'trades/{symbol}',
                        'auction/{symbol}',
                        'auction/{symbol}/history',
                    ],
                },
                'private': {
                    'post': [
                        'order/new',
                        'order/cancel',
                        'order/cancel/session',
                        'order/cancel/all',
                        'order/status',
                        'orders',
                        'mytrades',
                        'tradevolume',
                        'transfers',
                        'balances',
                        'deposit/{currency}/newAddress',
                        'withdraw/{currency}',
                        'heartbeat',
                        'transfers',
                    ],
                },
            },
            'fees': {
                'trading': {
                    'taker': 0.01,
                    'maker': 0.01,
                },
            },
        });
    }

    async fetchMarkets (params = {}) {
        let markets = await this.publicGetSymbols ();
        let result = [];
        for (let p = 0; p < markets.length; p++) {
            let id = markets[p];
            let market = id;
            let uppercase = market.toUpperCase ();
            let base = uppercase.slice (0, 3);
            let quote = uppercase.slice (3, 6);
            let symbol = base + '/' + quote;
            result.push ({
                'id': id,
                'symbol': symbol,
                'base': base,
                'quote': quote,
                'info': market,
            });
        }
        return result;
    }

    async fetchOrderBook (symbol, limit = undefined, params = {}) {
        await this.loadMarkets ();
        const request = {
            'symbol': this.marketId (symbol),
        };
        if (limit !== undefined) {
            request['limit_bids'] = limit;
            request['limit_asks'] = limit;
        }
        const response = await this.publicGetBookSymbol (this.extend (request, params));
        return this.parseOrderBook (response, undefined, 'bids', 'asks', 'price', 'amount');
    }

    async fetchTicker (symbol, params = {}) {
        await this.loadMarkets ();
        let market = this.market (symbol);
        let ticker = await this.publicGetPubtickerSymbol (this.extend ({
            'symbol': market['id'],
        }, params));
        let timestamp = ticker['volume']['timestamp'];
        let baseVolume = market['base'];
        let quoteVolume = market['quote'];
        let last = this.safeFloat (ticker, 'last');
        return {
            'symbol': symbol,
            'timestamp': timestamp,
            'datetime': this.iso8601 (timestamp),
            'high': undefined,
            'low': undefined,
            'bid': this.safeFloat (ticker, 'bid'),
            'bidVolume': undefined,
            'ask': this.safeFloat (ticker, 'ask'),
            'askVolume': undefined,
            'vwap': undefined,
            'open': undefined,
            'close': last,
            'last': last,
            'previousClose': undefined,
            'change': undefined,
            'percentage': undefined,
            'average': undefined,
            'baseVolume': parseFloat (ticker['volume'][baseVolume]),
            'quoteVolume': parseFloat (ticker['volume'][quoteVolume]),
            'info': ticker,
        };
    }

    parseTrade (trade, market) {
        let timestamp = trade['timestampms'];
        let order = undefined;
        if ('order_id' in trade)
            order = trade['order_id'].toString ();
        let fee = this.safeFloat (trade, 'fee_amount');
        if (fee !== undefined) {
            let currency = this.safeString (trade, 'fee_currency');
            if (currency !== undefined) {
                if (currency in this.currencies_by_id)
                    currency = this.currencies_by_id[currency]['code'];
                currency = this.commonCurrencyCode (currency);
            }
            fee = {
                'cost': this.safeFloat (trade, 'fee_amount'),
                'currency': currency,
            };
        }
        let price = this.safeFloat (trade, 'price');
        let amount = this.safeFloat (trade, 'amount');
        return {
            'id': trade['tid'].toString (),
            'order': order,
            'info': trade,
            'timestamp': timestamp,
            'datetime': this.iso8601 (timestamp),
            'symbol': market['symbol'],
            'type': undefined,
            'side': trade['type'].toLowerCase (),
            'price': price,
            'cost': price * amount,
            'amount': amount,
            'fee': fee,
        };
    }

    async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) {
        await this.loadMarkets ();
        let market = this.market (symbol);
        let response = await this.publicGetTradesSymbol (this.extend ({
            'symbol': market['id'],
        }, params));
        return this.parseTrades (response, market, since, limit);
    }

    async fetchBalance (params = {}) {
        await this.loadMarkets ();
        let balances = await this.privatePostBalances ();
        let result = { 'info': balances };
        for (let b = 0; b < balances.length; b++) {
            let balance = balances[b];
            let currency = balance['currency'];
            let account = {
                'free': parseFloat (balance['available']),
                'used': 0.0,
                'total': parseFloat (balance['amount']),
            };
            account['used'] = account['total'] - account['free'];
            result[currency] = account;
        }
        return this.parseBalance (result);
    }

    parseOrder (order, market = undefined) {
        let timestamp = order['timestampms'];
        let amount = this.safeFloat (order, 'original_amount');
        let remaining = this.safeFloat (order, 'remaining_amount');
        let filled = this.safeFloat (order, 'executed_amount');
        let status = 'closed';
        if (order['is_live']) {
            status = 'open';
        }
        if (order['is_cancelled']) {
            status = 'canceled';
        }
        let price = this.safeFloat (order, 'price');
        let average = this.safeFloat (order, 'avg_execution_price');
        if (average !== 0.0) {
            price = average; // prefer filling (execution) price over the submitted price
        }
        let cost = undefined;
        if (filled !== undefined) {
            if (average !== undefined) {
                cost = filled * average;
            }
        }
        let type = this.safeString (order, 'type');
        if (type === 'exchange limit') {
            type = 'limit';
        } else if (type === 'market buy' || type === 'market sell') {
            type = 'market';
        } else {
            type = order['type'];
        }
        let fee = undefined;
        let symbol = undefined;
        if (market === undefined) {
            let marketId = this.safeString (order, 'symbol');
            if (marketId in this.markets_by_id) {
                market = this.markets_by_id[marketId];
            }
        }
        if (market !== undefined) {
            symbol = market['symbol'];
        }
        return {
            'id': order['order_id'],
            'info': order,
            'timestamp': timestamp,
            'datetime': this.iso8601 (timestamp),
            'lastTradeTimestamp': undefined,
            'status': status,
            'symbol': symbol,
            'type': type,
            'side': order['side'].toLowerCase (),
            'price': price,
            'average': average,
            'cost': cost,
            'amount': amount,
            'filled': filled,
            'remaining': remaining,
            'fee': fee,
        };
    }

    async fetchOrder (id, symbol = undefined, params = {}) {
        await this.loadMarkets ();
        let response = await this.privatePostOrderStatus (this.extend ({
            'order_id': id,
        }, params));
        return this.parseOrder (response);
    }

    async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
        await this.loadMarkets ();
        let response = await this.privatePostOrders (params);
        let orders = this.parseOrders (response, undefined, since, limit);
        if (symbol !== undefined) {
            let market = this.market (symbol); // throws on non-existent symbol
            orders = this.filterBySymbol (orders, market['symbol']);
        }
        return orders;
    }

    async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
        await this.loadMarkets ();
        if (type === 'market')
            throw new ExchangeError (this.id + ' allows limit orders only');
        let nonce = this.nonce ();
        let order = {
            'client_order_id': nonce.toString (),
            'symbol': this.marketId (symbol),
            'amount': amount.toString (),
            'price': price.toString (),
            'side': side,
            'type': 'exchange limit', // gemini allows limit orders only
        };
        let response = await this.privatePostOrderNew (this.extend (order, params));
        return {
            'info': response,
            'id': response['order_id'],
        };
    }

    async cancelOrder (id, symbol = undefined, params = {}) {
        await this.loadMarkets ();
        return await this.privatePostOrderCancel ({ 'order_id': id });
    }

    async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) {
        if (symbol === undefined)
            throw new ArgumentsRequired (this.id + ' fetchMyTrades requires a symbol argument');
        await this.loadMarkets ();
        let market = this.market (symbol);
        let request = {
            'symbol': market['id'],
        };
        if (limit !== undefined)
            request['limit_trades'] = limit;
        if (since !== undefined)
            request['timestamp'] = parseInt (since / 1000);
        let response = await this.privatePostMytrades (this.extend (request, params));
        return this.parseTrades (response, market, since, limit);
    }

    async withdraw (code, amount, address, tag = undefined, params = {}) {
        this.checkAddress (address);
        await this.loadMarkets ();
        let currency = this.currency (code);
        let response = await this.privatePostWithdrawCurrency (this.extend ({
            'currency': currency['id'],
            'amount': amount,
            'address': address,
        }, params));
        return {
            'info': response,
            'id': this.safeString (response, 'txHash'),
        };
    }

    nonce () {
        return this.milliseconds ();
    }

    async fetchTransactions (code = undefined, since = undefined, limit = undefined, params = {}) {
        await this.loadMarkets ();
        let request = {};
        let response = await this.privatePostTransfers (this.extend (request, params));
        return this.parseTransactions (response);
    }

    parseTransaction (transaction, currency = undefined) {
        let timestamp = this.safeInteger (transaction, 'timestampms');
        let code = undefined;
        if (currency === undefined) {
            let currencyId = this.safeString (transaction, 'currency');
            if (currencyId in this.currencies_by_id) {
                currency = this.currencies_by_id[currencyId];
            }
        }
        if (currency !== undefined) {
            code = currency['code'];
        }
        let type = this.safeString (transaction, 'type');
        if (type !== undefined) {
            type = type.toLowerCase ();
        }
        let status = 'pending';
        // When deposits show as Advanced or Complete they are available for trading.
        if (transaction['status'])
            status = 'ok';
        return {
            'info': transaction,
            'id': this.safeString (transaction, 'eid'),
            'txid': this.safeString (transaction, 'txHash'),
            'timestamp': timestamp,
            'datetime': this.iso8601 (timestamp),
            'address': undefined, // or is it defined?
            'tag': undefined, // or is it defined?
            'type': type, // direction of the transaction, ('deposit' | 'withdraw')
            'amount': this.safeFloat (transaction, 'amount'),
            'currency': code,
            'status': status,
            'updated': undefined,
            'fee': {
                'cost': undefined,
                'rate': undefined,
            },
        };
    }

    sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
        let url = '/' + this.version + '/' + this.implodeParams (path, params);
        let query = this.omit (params, this.extractParams (path));
        if (api === 'public') {
            if (Object.keys (query).length)
                url += '?' + this.urlencode (query);
        } else {
            this.checkRequiredCredentials ();
            let nonce = this.nonce ();
            let request = this.extend ({
                'request': url,
                'nonce': nonce,
            }, query);
            let payload = this.json (request);
            payload = this.stringToBase64 (this.encode (payload));
            let signature = this.hmac (payload, this.encode (this.secret), 'sha384');
            headers = {
                'Content-Type': 'text/plain',
                'X-GEMINI-APIKEY': this.apiKey,
                'X-GEMINI-PAYLOAD': this.decode (payload),
                'X-GEMINI-SIGNATURE': signature,
            };
        }
        url = this.urls['api'] + url;
        return { 'url': url, 'method': method, 'body': body, 'headers': headers };
    }

    async request (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
        let response = await this.fetch2 (path, api, method, params, headers, body);
        if ('result' in response)
            if (response['result'] === 'error')
                throw new ExchangeError (this.id + ' ' + this.json (response));
        return response;
    }

    async createDepositAddress (code, params = {}) {
        await this.loadMarkets ();
        let currency = this.currency (code);
        let response = await this.privatePostDepositCurrencyNewAddress (this.extend ({
            'currency': currency['id'],
        }, params));
        let address = this.safeString (response, 'address');
        this.checkAddress (address);
        return {
            'currency': code,
            'address': address,
            'tag': undefined,
            'info': response,
        };
    }
};
<|endoftext|>


<commit_before>/**
 * The gulp file configures the gulp build setup
 * Run "gulp build" to built project and compile CoffeeScript
 * Run "gulp test" to run Mocha unit tests and Istanbul coverage tests
 * Run "gulp" to clean, build, test and watch for changes during development
 */

/* Require the node modules */
var gulp    = require('gulp');
var coffee  = require('gulp-coffee');
var lint    = require('gulp-coffeelint');
var clean   = require('gulp-clean');
var footer  = require('gulp-footer');
var size    = require('gulp-size');
var mocha   = require('gulp-mocha');
var istanbul= require('gulp-istanbul');
var watch   = require('gulp-watch');
//var uglify  = require('gulp-uglify'); // Uncomment here and below to minify js

require('coffee-script/register');

var footerTxt = "\/* (C) Alicia Sykes <alicia@aliciasykes.com> 2015           " +
    "*\\\r\n\\* MIT License. Read full license at: https:\/\/goo.gl\/IL4lQJ *\/";

/* Delete the files currently in finished directory */
gulp.task('clean', function (cb) {
    return gulp.src('./index.js', {read: false})
        .pipe(clean());
});

/* Lint, compile and minify CoffeeScript */
gulp.task('build', ['clean'],  function(){
    return gulp.src('./src/**/*.coffee')
        .pipe(lint())
        .pipe(lint.reporter())
        .pipe(coffee())
        //.pipe(uglify()) // Uncomment to minify JS
        .pipe(footer(footerTxt))
        .pipe(size())
        .pipe(gulp.dest('./'))
});

/* Run unit tests and generate coverage report */
gulp.task('test', function (cb) {
    gulp.src(['./index.js'])
        .pipe(istanbul())
        .pipe(istanbul.hookRequire())
        .on('finish', function () {
            gulp.src('./test/**/*.coffee', {read: false})
                .pipe(mocha({
                    reporter: 'nyan'
                }))
                .pipe(istanbul.writeReports({dir: './test', reporters: ['text-summary', 'lcov']}))
                //.pipe(istanbul.enforceThresholds({ thresholds: { global: 90 } }))
                .on('end', cb);
        });
});

/* Watch for changes and refresh */
gulp.task('watch', function(){
    gulp.watch('./src/**/*.coffee', ['test-after-build']);
    gulp.watch('./test/**/*.coffee', ['test']);
});

/* Don't test, until it has built, to avoid file not found errors */
gulp.task('test-after-build',['build'],function(){
    gulp.start('test')
});

/* Defualt gulp task, deletes old files, compiles source files and runs tests */
gulp.task('default', ['test-after-build', 'watch']);<commit_msg>Small adjustment to spacings<commit_after>/**
 * The gulp file configures the gulp build setup
 * Run "gulp build" to built project and compile CoffeeScript
 * Run "gulp test" to run Mocha unit tests and Istanbul coverage tests
 * Run "gulp" to clean, build, test and watch for changes during development
 */

/* Require the node modules */
var gulp    = require('gulp');
var coffee  = require('gulp-coffee');
var lint    = require('gulp-coffeelint');
var clean   = require('gulp-clean');
var footer  = require('gulp-footer');
var size    = require('gulp-size');
var mocha   = require('gulp-mocha');
var istanbul= require('gulp-istanbul');
var watch   = require('gulp-watch');
//var uglify  = require('gulp-uglify'); // Uncomment here and below to minify js

require('coffee-script/register');

var footerTxt = "\/* (C) Alicia Sykes <alicia@aliciasykes.com> 2015           " +
    "*\\\r\n\\* MIT License. Read full license at: https:\/\/goo.gl\/IL4lQJ *\/";

/* Delete the files currently in finished directory */
gulp.task('clean', function (cb) {
    return gulp.src('./index.js', {read: false})
        .pipe(clean());
});

/* Lint, compile and minify CoffeeScript */
gulp.task('build', ['clean'],  function(){
    return gulp.src('./src/**/*.coffee')
        .pipe(lint())
        .pipe(lint.reporter())
        .pipe(coffee())
        //.pipe(uglify()) // Uncomment to minify JS
        .pipe(footer(footerTxt))
        .pipe(size())
        .pipe(gulp.dest('./'))
});

/* Run unit tests and generate coverage report */
gulp.task('test', function (cb) {
    gulp.src(['./index.js'])
        .pipe(istanbul())
        .pipe(istanbul.hookRequire())
        .on('finish', function () {
            gulp.src('./test/**/*.coffee', {read: false})
                .pipe(mocha({ reporter: 'nyan' }))
                .pipe(istanbul.writeReports({reporters: ['text-summary', 'lcov']}))
                //.pipe(istanbul.enforceThresholds({ thresholds: { global: 90 } }))
                .on('end', cb);
        });
});

/* Watch for changes and refresh */
gulp.task('watch', function(){
    gulp.watch('./src/**/*.coffee', ['test-after-build']);
    gulp.watch('./test/**/*.coffee', ['test']);
});

/* Don't test, until it has built, to avoid file not found errors */
gulp.task('test-after-build',['build'],function(){
    gulp.start('test')
});

/* Defualt gulp task, deletes old files, compiles source files and runs tests */
gulp.task('default', ['test-after-build', 'watch']);<|endoftext|>