<commit_before>/**
 * 每位工程师都有保持代码优雅的义务
 * Each engineer has a duty to keep the code elegant
**/

const request = require('superagent');
const debug = require('debug')('request');
const md5 = require('md5');
const AVPromise = require('./promise');
const Cache = require('./cache');
const AVError = require('./error');
const AV = require('./av');
const _ = require('underscore');

let getServerURLPromise;

// 服务器请求的节点 host
const API_HOST = {
  cn: 'https://api.leancloud.cn',
  us: 'https://us-api.leancloud.cn',
};

// 计算 X-LC-Sign 的签名方法
const sign = (key, isMasterKey) => {
  const now = new Date().getTime();
  const signature = md5(now + key);
  if (isMasterKey) {
    return `${signature},${now},master`;
  }
  return `${signature},${now}`;
};

const checkRouter = (router) => {
  const routerList = [
    'batch',
    'classes',
    'files',
    'date',
    'functions',
    'call',
    'login',
    'push',
    'search/select',
    'requestPasswordReset',
    'requestEmailVerify',
    'requestPasswordResetBySmsCode',
    'resetPasswordBySmsCode',
    'requestMobilePhoneVerify',
    'requestLoginSmsCode',
    'verifyMobilePhone',
    'requestSmsCode',
    'verifySmsCode',
    'users',
    'usersByMobilePhone',
    'cloudQuery',
    'qiniu',
    'fileTokens',
    'statuses',
    'bigquery',
    'search/select',
    'subscribe/statuses/count',
    'subscribe/statuses',
    'installations',
  ];

  if (routerList.indexOf(router) === -1 &&
    !(/users\/[^\/]+\/updatePassword/.test(router)) &&
    !(/users\/[^\/]+\/friendship\/[^\/]+/.test(router))
  ) {
    throw new Error(`Bad router: ${router}.`);
  }
};

const ajax = (method, resourceUrl, data, headers = {}, onprogress) => {
  debug(method, resourceUrl, data, headers);

  const promise = new AVPromise();
  const req = request(method, resourceUrl)
    .set(headers)
    .send(data)
    .end((err, res) => {
      if (res) {
        debug(res.status, res.body, res.text);
      }
      if (err) {
        if (res) {
          err.statusCode = res.status;
          err.responseText = res.text;
          err.response = res.body;
        }
        return promise.reject(err);
      }
      return promise.resolve(res.body, res.status, res);
    });
  if (onprogress) {
    req.on('progress', onprogress);
  }
  return promise;
};

const setHeaders = (sessionToken) => {
  const headers = {
    'X-LC-Id': AV.applicationId,
    'Content-Type': 'application/json;charset=UTF-8',
  };
  if (AV.masterKey && AV._useMasterKey) {
    headers['X-LC-Sign'] = sign(AV.masterKey, true);
  } else {
    headers['X-LC-Sign'] = sign(AV.applicationKey);
  }
  if (AV._config.applicationProduction !== null) {
    headers['X-LC-Prod'] = AV._config.applicationProduction;
  }
  if (!AV._config.isNode) {
    headers['X-LC-UA'] = `AV/${AV.version}`;
  } else {
    // LeanEngine need use AV._config.userAgent
    headers['User-Agent'] = AV._config.userAgent || `AV/${AV.version}; Node.js/${process.version}`;
  }

  const promise = new AVPromise();

  // Pass the session token
  if (sessionToken) {
    headers['X-LC-Session'] = sessionToken;
    promise.resolve(headers);
  } else if (!AV._config.disableCurrentUser) {
    AV.User.currentAsync().then((currentUser) => {
      if (currentUser && currentUser._sessionToken) {
        headers['X-LC-Session'] = currentUser._sessionToken;
      }
      promise.resolve(headers);
    });
  } else {
    promise.resolve(headers);
  }

  return promise;
};

const createApiUrl = (route, className, objectId, method, dataObject) => {
  // TODO: 兼容 AV.serverURL 旧方式设置 API Host，后续去掉
  if (AV.serverURL) {
    AV._config.APIServerURL = AV.serverURL;
    console.warn('Please use AV._config.APIServerURL to replace AV.serverURL, and it is an internal interface.');
  }

  let apiURL = AV._config.APIServerURL || API_HOST.cn;

  if (apiURL.charAt(apiURL.length - 1) !== '/') {
    apiURL += '/';
  }
  apiURL += `1.1/${route}`;
  if (className) {
    apiURL += `/${className}`;
  }
  if (objectId) {
    apiURL += `/${objectId}`;
  }
  if ((route === 'users' || route === 'classes') && dataObject) {
    apiURL += '?';
    if (dataObject._fetchWhenSave) {
      delete dataObject._fetchWhenSave;
      apiURL += '&new=true';
    }
    if (dataObject._where) {
      apiURL += `&where=${encodeURIComponent(JSON.stringify(dataObject._where))}`;
      delete dataObject._where;
    }
  }

  if (method.toLowerCase() === 'get') {
    if (apiURL.indexOf('?') === -1) {
      apiURL += '?';
    }
    for (const k in dataObject) {
      if (typeof dataObject[k] === 'object') {
        dataObject[k] = JSON.stringify(dataObject[k]);
      }
      apiURL += `&${k}=${encodeURIComponent(dataObject[k])}`;
    }
  }

  return apiURL;
};

const cacheServerURL = (serverURL, ttl) => {
  if (typeof ttl !== 'number') {
    ttl = 3600;
  }
  return Cache.setAsync('APIServerURL', serverURL, ttl * 1000);
};

// handle AV._request Error
const handleError = (res) => {
  const promise = new AVPromise();
  /**
    When API request need to redirect to the right location,
    can't use browser redirect by http status 307, as the reason of CORS,
    so API server response http status 410 and the param "location" for this case.
  */
  if (res.statusCode === 410) {
    cacheServerURL(res.response.api_server, res.response.ttl).then(() => {
      promise.resolve(res.response.location);
    }).catch((error) => {
      promise.reject(error);
    });
  } else {
    let errorJSON = { code: -1, error: res.responseText };
    if (res.response && res.response.code) {
      errorJSON = res.response;
    } else if (res.responseText) {
      try {
        errorJSON = JSON.parse(res.responseText);
      } catch (e) {
        // If we fail to parse the error text, that's okay.
      }
    }

    // Transform the error into an instance of AVError by trying to parse
    // the error string as JSON.
    const error = new AVError(errorJSON.code, errorJSON.error);
    promise.reject(error);
  }
  return promise;
};

const setServerUrl = (serverURL) => {
  AV._config.APIServerURL = `https://${serverURL}`;

  // 根据新 URL 重新设置区域
  const newRegion = _.findKey(API_HOST, item => item === AV._config.APIServerURL);
  if (newRegion) {
    AV._config.region = newRegion;
  }
};

const refreshServerUrlByRouter = () => {
  const url = `https://app-router.leancloud.cn/1/route?appId=${AV.applicationId}`;
  return ajax('get', url).then(servers => {
    if (servers.api_server) {
      setServerUrl(servers.api_server);
      return cacheServerURL(servers.api_server, servers.ttl);
    }
  }, error => {
    // bypass all non-4XX errors
    if (error.statusCode >= 400 && error.statusCode < 500) {
      throw error;
    }
  });
};

const setServerUrlByRegion = (region = 'cn') => {
  getServerURLPromise = new AVPromise();
  const promise = getServerURLPromise;
  // 如果用户在 init 之前设置了 APIServerURL，则跳过请求 router
  if (AV._config.APIServerURL) {
    promise.resolve();
    return;
  }
  // if not china server region, do not use router
  if (region === 'cn') {
    Cache.getAsync('APIServerURL').then((serverURL) => {
      if (serverURL) {
        setServerUrl(serverURL);
      } else {
        return refreshServerUrlByRouter();
      }
    }).then(() => {
      promise.resolve();
    }).catch((error) => {
      promise.reject(error);
    });
  } else {
    AV._config.region = region;
    AV._config.APIServerURL = API_HOST[region];
    promise.resolve();
  }
};

/**
 * route is classes, users, login, etc.
 * objectId is null if there is no associated objectId.
 * method is the http method for the REST API.
 * dataObject is the payload as an object, or null if there is none.
 * @ignore
 */
const AVRequest = (route, className, objectId, method, dataObject = {}, sessionToken) => {
  if (!AV.applicationId) {
    throw new Error('You must specify your applicationId using AV.init()');
  }

  if (!AV.applicationKey && !AV.masterKey) {
    throw new Error('You must specify a AppKey using AV.init()');
  }

  checkRouter(route);

  if (!getServerURLPromise) {
    return AVPromise.error(new Error('Not initialized'));
  }
  return getServerURLPromise.then(() => {
    const apiURL = createApiUrl(route, className, objectId, method, dataObject);
    return setHeaders(sessionToken).then(
      headers => ajax(method, apiURL, dataObject, headers)
        .then(
          null,
          res => handleError(res)
            .then(location => ajax(method, location, dataObject, headers))
        )
    );
  });
};

module.exports = {
  ajax,
  request: AVRequest,
  setServerUrlByRegion,
};
<commit_msg>Improve http request log (#348)<commit_after>/**
 * 每位工程师都有保持代码优雅的义务
 * Each engineer has a duty to keep the code elegant
**/

const request = require('superagent');
const debug = require('debug')('leancloud:request');
const md5 = require('md5');
const AVPromise = require('./promise');
const Cache = require('./cache');
const AVError = require('./error');
const AV = require('./av');
const _ = require('underscore');

let getServerURLPromise;

// 服务器请求的节点 host
const API_HOST = {
  cn: 'https://api.leancloud.cn',
  us: 'https://us-api.leancloud.cn',
};

// 计算 X-LC-Sign 的签名方法
const sign = (key, isMasterKey) => {
  const now = new Date().getTime();
  const signature = md5(now + key);
  if (isMasterKey) {
    return `${signature},${now},master`;
  }
  return `${signature},${now}`;
};

const checkRouter = (router) => {
  const routerList = [
    'batch',
    'classes',
    'files',
    'date',
    'functions',
    'call',
    'login',
    'push',
    'search/select',
    'requestPasswordReset',
    'requestEmailVerify',
    'requestPasswordResetBySmsCode',
    'resetPasswordBySmsCode',
    'requestMobilePhoneVerify',
    'requestLoginSmsCode',
    'verifyMobilePhone',
    'requestSmsCode',
    'verifySmsCode',
    'users',
    'usersByMobilePhone',
    'cloudQuery',
    'qiniu',
    'fileTokens',
    'statuses',
    'bigquery',
    'search/select',
    'subscribe/statuses/count',
    'subscribe/statuses',
    'installations',
  ];

  if (routerList.indexOf(router) === -1 &&
    !(/users\/[^\/]+\/updatePassword/.test(router)) &&
    !(/users\/[^\/]+\/friendship\/[^\/]+/.test(router))
  ) {
    throw new Error(`Bad router: ${router}.`);
  }
};

let requestsCount = 0;

const ajax = (method, resourceUrl, data, headers = {}, onprogress) => {
  const count = requestsCount++;

  debug(`request(${count})`, method, resourceUrl, data, headers);

  const promise = new AVPromise();
  const req = request(method, resourceUrl)
    .set(headers)
    .send(data)
    .end((err, res) => {
      if (res) {
        debug(`response(${count})`, res.status, res.body && res.text, res.header);
      }
      if (err) {
        if (res) {
          err.statusCode = res.status;
          err.responseText = res.text;
          err.response = res.body;
        }
        return promise.reject(err);
      }
      return promise.resolve(res.body, res.status, res);
    });
  if (onprogress) {
    req.on('progress', onprogress);
  }
  return promise;
};

const setHeaders = (sessionToken) => {
  const headers = {
    'X-LC-Id': AV.applicationId,
    'Content-Type': 'application/json;charset=UTF-8',
  };
  if (AV.masterKey && AV._useMasterKey) {
    headers['X-LC-Sign'] = sign(AV.masterKey, true);
  } else {
    headers['X-LC-Sign'] = sign(AV.applicationKey);
  }
  if (AV._config.applicationProduction !== null) {
    headers['X-LC-Prod'] = AV._config.applicationProduction;
  }
  if (!AV._config.isNode) {
    headers['X-LC-UA'] = `AV/${AV.version}`;
  } else {
    // LeanEngine need use AV._config.userAgent
    headers['User-Agent'] = AV._config.userAgent || `AV/${AV.version}; Node.js/${process.version}`;
  }

  const promise = new AVPromise();

  // Pass the session token
  if (sessionToken) {
    headers['X-LC-Session'] = sessionToken;
    promise.resolve(headers);
  } else if (!AV._config.disableCurrentUser) {
    AV.User.currentAsync().then((currentUser) => {
      if (currentUser && currentUser._sessionToken) {
        headers['X-LC-Session'] = currentUser._sessionToken;
      }
      promise.resolve(headers);
    });
  } else {
    promise.resolve(headers);
  }

  return promise;
};

const createApiUrl = (route, className, objectId, method, dataObject) => {
  // TODO: 兼容 AV.serverURL 旧方式设置 API Host，后续去掉
  if (AV.serverURL) {
    AV._config.APIServerURL = AV.serverURL;
    console.warn('Please use AV._config.APIServerURL to replace AV.serverURL, and it is an internal interface.');
  }

  let apiURL = AV._config.APIServerURL || API_HOST.cn;

  if (apiURL.charAt(apiURL.length - 1) !== '/') {
    apiURL += '/';
  }
  apiURL += `1.1/${route}`;
  if (className) {
    apiURL += `/${className}`;
  }
  if (objectId) {
    apiURL += `/${objectId}`;
  }
  if ((route === 'users' || route === 'classes') && dataObject) {
    apiURL += '?';
    if (dataObject._fetchWhenSave) {
      delete dataObject._fetchWhenSave;
      apiURL += '&new=true';
    }
    if (dataObject._where) {
      apiURL += `&where=${encodeURIComponent(JSON.stringify(dataObject._where))}`;
      delete dataObject._where;
    }
  }

  if (method.toLowerCase() === 'get') {
    if (apiURL.indexOf('?') === -1) {
      apiURL += '?';
    }
    for (const k in dataObject) {
      if (typeof dataObject[k] === 'object') {
        dataObject[k] = JSON.stringify(dataObject[k]);
      }
      apiURL += `&${k}=${encodeURIComponent(dataObject[k])}`;
    }
  }

  return apiURL;
};

const cacheServerURL = (serverURL, ttl) => {
  if (typeof ttl !== 'number') {
    ttl = 3600;
  }
  return Cache.setAsync('APIServerURL', serverURL, ttl * 1000);
};

// handle AV._request Error
const handleError = (res) => {
  const promise = new AVPromise();
  /**
    When API request need to redirect to the right location,
    can't use browser redirect by http status 307, as the reason of CORS,
    so API server response http status 410 and the param "location" for this case.
  */
  if (res.statusCode === 410) {
    cacheServerURL(res.response.api_server, res.response.ttl).then(() => {
      promise.resolve(res.response.location);
    }).catch((error) => {
      promise.reject(error);
    });
  } else {
    let errorJSON = { code: -1, error: res.responseText };
    if (res.response && res.response.code) {
      errorJSON = res.response;
    } else if (res.responseText) {
      try {
        errorJSON = JSON.parse(res.responseText);
      } catch (e) {
        // If we fail to parse the error text, that's okay.
      }
    }

    // Transform the error into an instance of AVError by trying to parse
    // the error string as JSON.
    const error = new AVError(errorJSON.code, errorJSON.error);
    promise.reject(error);
  }
  return promise;
};

const setServerUrl = (serverURL) => {
  AV._config.APIServerURL = `https://${serverURL}`;

  // 根据新 URL 重新设置区域
  const newRegion = _.findKey(API_HOST, item => item === AV._config.APIServerURL);
  if (newRegion) {
    AV._config.region = newRegion;
  }
};

const refreshServerUrlByRouter = () => {
  const url = `https://app-router.leancloud.cn/1/route?appId=${AV.applicationId}`;
  return ajax('get', url).then(servers => {
    if (servers.api_server) {
      setServerUrl(servers.api_server);
      return cacheServerURL(servers.api_server, servers.ttl);
    }
  }, error => {
    // bypass all non-4XX errors
    if (error.statusCode >= 400 && error.statusCode < 500) {
      throw error;
    }
  });
};

const setServerUrlByRegion = (region = 'cn') => {
  getServerURLPromise = new AVPromise();
  const promise = getServerURLPromise;
  // 如果用户在 init 之前设置了 APIServerURL，则跳过请求 router
  if (AV._config.APIServerURL) {
    promise.resolve();
    return;
  }
  // if not china server region, do not use router
  if (region === 'cn') {
    Cache.getAsync('APIServerURL').then((serverURL) => {
      if (serverURL) {
        setServerUrl(serverURL);
      } else {
        return refreshServerUrlByRouter();
      }
    }).then(() => {
      promise.resolve();
    }).catch((error) => {
      promise.reject(error);
    });
  } else {
    AV._config.region = region;
    AV._config.APIServerURL = API_HOST[region];
    promise.resolve();
  }
};

/**
 * route is classes, users, login, etc.
 * objectId is null if there is no associated objectId.
 * method is the http method for the REST API.
 * dataObject is the payload as an object, or null if there is none.
 * @ignore
 */
const AVRequest = (route, className, objectId, method, dataObject = {}, sessionToken) => {
  if (!AV.applicationId) {
    throw new Error('You must specify your applicationId using AV.init()');
  }

  if (!AV.applicationKey && !AV.masterKey) {
    throw new Error('You must specify a AppKey using AV.init()');
  }

  checkRouter(route);

  if (!getServerURLPromise) {
    return AVPromise.error(new Error('Not initialized'));
  }
  return getServerURLPromise.then(() => {
    const apiURL = createApiUrl(route, className, objectId, method, dataObject);
    return setHeaders(sessionToken).then(
      headers => ajax(method, apiURL, dataObject, headers)
        .then(
          null,
          res => handleError(res)
            .then(location => ajax(method, location, dataObject, headers))
        )
    );
  });
};

module.exports = {
  ajax,
  request: AVRequest,
  setServerUrlByRegion,
};
<|endoftext|>


<commit_before>var RateLimiter = require('./rateLimiter');
var Queue = require('./queue');
var Notifier = require('./notifier');
var _ = require('./utility');

/*
 * Rollbar - the interface to Rollbar
 *
 * @param options
 * @param api
 * @param logger
 */
function Rollbar(options, api, logger, telemeter, platform) {
  this.options = _.merge(options);
  this.logger = logger;
  Rollbar.rateLimiter.configureGlobal(this.options);
  Rollbar.rateLimiter.setPlatformOptions(platform, this.options);
  this.api = api;
  this.queue = new Queue(Rollbar.rateLimiter, api, logger, this.options);

  // This must happen before the Notifier is created
  var tracer = this.options.tracer || null;
  if (validateTracer(tracer)) {
    this.tracer = tracer;
    // set to a string for api response serialization
    this.options.tracer = 'opentracing-tracer-enabled';
    this.options._configuredOptions.tracer = 'opentracing-tracer-enabled';
  } else {
    this.tracer = null;
  }

  this.notifier = new Notifier(this.queue, this.options);
  this.telemeter = telemeter;
  setStackTraceLimit(options);
  this.lastError = null;
  this.lastErrorHash = 'none';
}

var defaultOptions = {
  maxItems: 0,
  itemsPerMinute: 60
};

Rollbar.rateLimiter = new RateLimiter(defaultOptions);

Rollbar.prototype.global = function (options) {
  Rollbar.rateLimiter.configureGlobal(options);
  return this;
};

Rollbar.prototype.configure = function (options, payloadData) {
  var oldOptions = this.options;
  var payload = {};
  if (payloadData) {
    payload = { payload: payloadData };
  }

  this.options = _.merge(oldOptions, options, payload);

  // This must happen before the Notifier is configured
  var tracer = this.options.tracer || null;
  if (validateTracer(tracer)) {
    this.tracer = tracer;
    // set to a string for api response serialization
    this.options.tracer = 'opentracing-tracer-enabled';
    this.options._configuredOptions.tracer = 'opentracing-tracer-enabled';
  } else {
    this.tracer = null;
  }

  this.notifier && this.notifier.configure(this.options);
  this.telemeter && this.telemeter.configure(this.options);
  setStackTraceLimit(options);
  this.global(this.options);

  if (validateTracer(options.tracer)) {
    this.tracer = options.tracer
  }

  return this;
};

Rollbar.prototype.log = function (item) {
  var level = this._defaultLogLevel();
  return this._log(level, item);
};

Rollbar.prototype.debug = function (item) {
  this._log('debug', item);
};

Rollbar.prototype.info = function (item) {
  this._log('info', item);
};

Rollbar.prototype.warn = function (item) {
  this._log('warning', item);
};

Rollbar.prototype.warning = function (item) {
  this._log('warning', item);
};

Rollbar.prototype.error = function (item) {
  this._log('error', item);
};

Rollbar.prototype.critical = function (item) {
  this._log('critical', item);
};

Rollbar.prototype.wait = function (callback) {
  this.queue.wait(callback);
};

Rollbar.prototype.captureEvent = function (type, metadata, level) {
  return this.telemeter && this.telemeter.captureEvent(type, metadata, level);
};

Rollbar.prototype.captureDomContentLoaded = function (ts) {
  return this.telemeter && this.telemeter.captureDomContentLoaded(ts);
};

Rollbar.prototype.captureLoad = function (ts) {
  return this.telemeter && this.telemeter.captureLoad(ts);
};

Rollbar.prototype.buildJsonPayload = function (item) {
  return this.api.buildJsonPayload(item);
};

Rollbar.prototype.sendJsonPayload = function (jsonPayload) {
  this.api.postJsonPayload(jsonPayload);
};

/* Internal */

Rollbar.prototype._log = function (defaultLevel, item) {
  var callback;
  if (item.callback) {
    callback = item.callback;
    delete item.callback;
  }
  if (this.options.ignoreDuplicateErrors && this._sameAsLastError(item)) {
    if (callback) {
      var error = new Error('ignored identical item');
      error.item = item;
      callback(error);
    }
    return;
  }
  try {
    this._addTracingInfo(item);
    item.level = item.level || defaultLevel;
    this.telemeter && this.telemeter._captureRollbarItem(item);
    item.telemetryEvents = (this.telemeter && this.telemeter.copyEvents()) || [];
    this.notifier.log(item, callback);
  } catch (e) {
    this.logger.error(e);
  }
};

Rollbar.prototype._defaultLogLevel = function () {
  return this.options.logLevel || 'debug';
};

Rollbar.prototype._sameAsLastError = function (item) {
  if (!item._isUncaught) {
    return false;
  }
  var itemHash = generateItemHash(item);
  if (this.lastErrorHash === itemHash) {
    return true;
  }
  this.lastError = item.err;
  this.lastErrorHash = itemHash;
  return false;
};

Rollbar.prototype._addTracingInfo = function (item) {
  // Tracer validation occurs in the constructor
  // or in the Rollbar.prototype.configure methods
  if (this.tracer) {
    // add rollbar occurrence uuid to span
    var span = this.tracer.scope().active();

    if (validateSpan(span)) {
      span.setTag('rollbar.error_uuid', item.uuid);
      span.setTag('rollbar.has_error', true);

      // add span ID & trace ID to occurrence
      var opentracingSpanId = span.context().toSpanId();
      var opentracingTraceId = span.context().toTraceId();

      if (item.custom) {
        item.custom.opentracing_span_id = opentracingSpanId;
        item.custom.opentracing_trace_id = opentracingTraceId;
      } else {
        item.custom = {
          opentracing_span_id: opentracingSpanId,
          opentracing_trace_id: opentracingTraceId
        };
      }
    }
  }
}

function generateItemHash(item) {
  var message = item.message || '';
  var stack = (item.err || {}).stack || String(item.err);
  return message + '::' + stack;
}

// Node.js, Chrome, Safari, and some other browsers support this property
// which globally sets the number of stack frames returned in an Error object.
// If a browser can't use it, no harm done.
function setStackTraceLimit(options) {
  if (options.stackTraceLimit) {
    Error.stackTraceLimit = options.stackTraceLimit;
  }
}

/**
 * Validate the Tracer object provided to the Client
 * is valid for our Opentracing use case.
 * @param {opentracer.Tracer} tracer
 */
function validateTracer(tracer) {
  if (!tracer) {
    return false;
  }

  if (!tracer.scope || typeof tracer.scope !== 'function') {
    return false;
  }

  var scope = tracer.scope();

  if (!scope || !scope.active || typeof scope.active !== 'function') {
    return false;
  }

  return true;
}

/**
 * Validate the Span object provided
 * @param {opentracer.Span} span
 */
function validateSpan(span) {
  if (!span || !span.context || typeof span.context !== 'function') {
    return false;
  }

  var spanContext = span.context();

  if (!spanContext
    || !spanContext.toSpanId
    || !spanContext.toTraceId
    || typeof spanContext.toSpanId !== 'function'
    || typeof spanContext.toTraceId !== 'function') {
    return false
  }

  return true;
}

module.exports = Rollbar;
<commit_msg>Add call to set error tag to true<commit_after>var RateLimiter = require('./rateLimiter');
var Queue = require('./queue');
var Notifier = require('./notifier');
var _ = require('./utility');

/*
 * Rollbar - the interface to Rollbar
 *
 * @param options
 * @param api
 * @param logger
 */
function Rollbar(options, api, logger, telemeter, platform) {
  this.options = _.merge(options);
  this.logger = logger;
  Rollbar.rateLimiter.configureGlobal(this.options);
  Rollbar.rateLimiter.setPlatformOptions(platform, this.options);
  this.api = api;
  this.queue = new Queue(Rollbar.rateLimiter, api, logger, this.options);

  // This must happen before the Notifier is created
  var tracer = this.options.tracer || null;
  if (validateTracer(tracer)) {
    this.tracer = tracer;
    // set to a string for api response serialization
    this.options.tracer = 'opentracing-tracer-enabled';
    this.options._configuredOptions.tracer = 'opentracing-tracer-enabled';
  } else {
    this.tracer = null;
  }

  this.notifier = new Notifier(this.queue, this.options);
  this.telemeter = telemeter;
  setStackTraceLimit(options);
  this.lastError = null;
  this.lastErrorHash = 'none';
}

var defaultOptions = {
  maxItems: 0,
  itemsPerMinute: 60
};

Rollbar.rateLimiter = new RateLimiter(defaultOptions);

Rollbar.prototype.global = function (options) {
  Rollbar.rateLimiter.configureGlobal(options);
  return this;
};

Rollbar.prototype.configure = function (options, payloadData) {
  var oldOptions = this.options;
  var payload = {};
  if (payloadData) {
    payload = { payload: payloadData };
  }

  this.options = _.merge(oldOptions, options, payload);

  // This must happen before the Notifier is configured
  var tracer = this.options.tracer || null;
  if (validateTracer(tracer)) {
    this.tracer = tracer;
    // set to a string for api response serialization
    this.options.tracer = 'opentracing-tracer-enabled';
    this.options._configuredOptions.tracer = 'opentracing-tracer-enabled';
  } else {
    this.tracer = null;
  }

  this.notifier && this.notifier.configure(this.options);
  this.telemeter && this.telemeter.configure(this.options);
  setStackTraceLimit(options);
  this.global(this.options);

  if (validateTracer(options.tracer)) {
    this.tracer = options.tracer
  }

  return this;
};

Rollbar.prototype.log = function (item) {
  var level = this._defaultLogLevel();
  return this._log(level, item);
};

Rollbar.prototype.debug = function (item) {
  this._log('debug', item);
};

Rollbar.prototype.info = function (item) {
  this._log('info', item);
};

Rollbar.prototype.warn = function (item) {
  this._log('warning', item);
};

Rollbar.prototype.warning = function (item) {
  this._log('warning', item);
};

Rollbar.prototype.error = function (item) {
  this._log('error', item);
};

Rollbar.prototype.critical = function (item) {
  this._log('critical', item);
};

Rollbar.prototype.wait = function (callback) {
  this.queue.wait(callback);
};

Rollbar.prototype.captureEvent = function (type, metadata, level) {
  return this.telemeter && this.telemeter.captureEvent(type, metadata, level);
};

Rollbar.prototype.captureDomContentLoaded = function (ts) {
  return this.telemeter && this.telemeter.captureDomContentLoaded(ts);
};

Rollbar.prototype.captureLoad = function (ts) {
  return this.telemeter && this.telemeter.captureLoad(ts);
};

Rollbar.prototype.buildJsonPayload = function (item) {
  return this.api.buildJsonPayload(item);
};

Rollbar.prototype.sendJsonPayload = function (jsonPayload) {
  this.api.postJsonPayload(jsonPayload);
};

/* Internal */

Rollbar.prototype._log = function (defaultLevel, item) {
  var callback;
  if (item.callback) {
    callback = item.callback;
    delete item.callback;
  }
  if (this.options.ignoreDuplicateErrors && this._sameAsLastError(item)) {
    if (callback) {
      var error = new Error('ignored identical item');
      error.item = item;
      callback(error);
    }
    return;
  }
  try {
    this._addTracingInfo(item);
    item.level = item.level || defaultLevel;
    this.telemeter && this.telemeter._captureRollbarItem(item);
    item.telemetryEvents = (this.telemeter && this.telemeter.copyEvents()) || [];
    this.notifier.log(item, callback);
  } catch (e) {
    this.logger.error(e);
  }
};

Rollbar.prototype._defaultLogLevel = function () {
  return this.options.logLevel || 'debug';
};

Rollbar.prototype._sameAsLastError = function (item) {
  if (!item._isUncaught) {
    return false;
  }
  var itemHash = generateItemHash(item);
  if (this.lastErrorHash === itemHash) {
    return true;
  }
  this.lastError = item.err;
  this.lastErrorHash = itemHash;
  return false;
};

Rollbar.prototype._addTracingInfo = function (item) {
  // Tracer validation occurs in the constructor
  // or in the Rollbar.prototype.configure methods
  if (this.tracer) {
    // add rollbar occurrence uuid to span
    var span = this.tracer.scope().active();

    if (validateSpan(span)) {
      span.setTag('rollbar.error_uuid', item.uuid);
      span.setTag('rollbar.has_error', true);
      span.setTag('error', true);

      // add span ID & trace ID to occurrence
      var opentracingSpanId = span.context().toSpanId();
      var opentracingTraceId = span.context().toTraceId();

      if (item.custom) {
        item.custom.opentracing_span_id = opentracingSpanId;
        item.custom.opentracing_trace_id = opentracingTraceId;
      } else {
        item.custom = {
          opentracing_span_id: opentracingSpanId,
          opentracing_trace_id: opentracingTraceId
        };
      }
    }
  }
}

function generateItemHash(item) {
  var message = item.message || '';
  var stack = (item.err || {}).stack || String(item.err);
  return message + '::' + stack;
}

// Node.js, Chrome, Safari, and some other browsers support this property
// which globally sets the number of stack frames returned in an Error object.
// If a browser can't use it, no harm done.
function setStackTraceLimit(options) {
  if (options.stackTraceLimit) {
    Error.stackTraceLimit = options.stackTraceLimit;
  }
}

/**
 * Validate the Tracer object provided to the Client
 * is valid for our Opentracing use case.
 * @param {opentracer.Tracer} tracer
 */
function validateTracer(tracer) {
  if (!tracer) {
    return false;
  }

  if (!tracer.scope || typeof tracer.scope !== 'function') {
    return false;
  }

  var scope = tracer.scope();

  if (!scope || !scope.active || typeof scope.active !== 'function') {
    return false;
  }

  return true;
}

/**
 * Validate the Span object provided
 * @param {opentracer.Span} span
 */
function validateSpan(span) {
  if (!span || !span.context || typeof span.context !== 'function') {
    return false;
  }

  var spanContext = span.context();

  if (!spanContext
    || !spanContext.toSpanId
    || !spanContext.toTraceId
    || typeof spanContext.toSpanId !== 'function'
    || typeof spanContext.toTraceId !== 'function') {
    return false
  }

  return true;
}

module.exports = Rollbar;
<|endoftext|>


<commit_before>function RSA ( options ) {
    options = options || {};

    this.key = null;
    this.result = null;

    this.reset(options);
}

function RSA_reset ( options ) {
    options = options || {};

    this.result = null;

    var key = options.key
    if ( key !== undefined ) {
        if ( key instanceof Array ) {
            var l = key.length;
            if ( l !== 2 && l !== 3 && l !== 8 )
                throw new SyntaxError("unexpected key type");

            var k = [];
            k[0] = new Modulus( key[0] );
            k[1] = new BigNumber( key[1] );
            if ( l > 2 ) {
                k[2] = new BigNumber( key[2] );
            }
            if ( l > 3 ) {
                k[3] = new Modulus( key[3] );
                k[4] = new Modulus( key[4] );
                k[5] = new BigNumber( key[5] );
                k[6] = new BigNumber( key[6] );
                k[7] = new BigNumber( key[7] );
            }

            this.key = k;
        }
        else {
            throw new TypeError("unexpected key type");
        }
    }

    return this;
}

function RSA_encrypt ( data ) {
    if ( !this.key )
        throw new IllegalStateError("no key is associated with the instance");

    if ( is_string(data) )
        data = string_to_bytes(data);

    if ( is_buffer(data) )
        data = new Uint8Array(data);

    var msg;
    if ( is_bytes(data) ) {
        msg = new BigNumber(data);
    }
    else if ( is_big_number(data) ) {
        msg = data;
    }
    else {
        throw new TypeError("unexpected data type");
    }

    if ( this.key[0].compare(msg) <= 0 )
        throw new RangeError("data too large");

    this.result = this.key[0].power( msg, this.key[1] ).toBytes();

    return this;
}

function RSA_decrypt ( data ) {
    if ( !this.key )
        throw new IllegalStateError("no key is associated with the instance");

    if ( this.key.length < 3 )
        throw new IllegalStateError("key isn't suitable for decription");

    if ( is_string(data) )
        data = string_to_bytes(data);

    if ( is_buffer(data) )
        data = new Uint8Array(data);

    var msg;
    if ( is_bytes(data) ) {
        msg = new BigNumber(data);
    }
    else if ( is_big_number(data) ) {
        msg = data;
    }
    else {
        throw new TypeError("unexpected data type");
    }

    if ( this.key[0].compare(msg) <= 0 )
        throw new RangeError("data too large");

    if ( this.key.length > 3 ) {
        var m = this.key[0],
            d = this.key[2],
            p = this.key[3],
            q = this.key[4],
            dp = this.key[5],
            dq = this.key[6],
            u = this.key[7];

        var x = p.power( msg, dp ),
            y = q.power( msg, dq );

        var t = x.subtract(y);
        while ( t.sign < 0 ) t = t.add(p);

        var h = p.reduce( u.multiply(t) );

        this.result = h.multiply(q).add(y).clamp(m.bitLength).toBytes();
    }
    else {
        var m = this.key[0],
            d = this.key[2];

        this.result = m.power( msg, d ).toBytes();
    }

    return this;
}

var RSA_prototype = RSA.prototype;
RSA_prototype.reset = RSA_reset;
RSA_prototype.encrypt = RSA_encrypt;
RSA_prototype.decrypt = RSA_decrypt;
<commit_msg>Fix RSA.decrypt: pad with zeros up to key length<commit_after>function RSA ( options ) {
    options = options || {};

    this.key = null;
    this.result = null;

    this.reset(options);
}

function RSA_reset ( options ) {
    options = options || {};

    this.result = null;

    var key = options.key
    if ( key !== undefined ) {
        if ( key instanceof Array ) {
            var l = key.length;
            if ( l !== 2 && l !== 3 && l !== 8 )
                throw new SyntaxError("unexpected key type");

            var k = [];
            k[0] = new Modulus( key[0] );
            k[1] = new BigNumber( key[1] );
            if ( l > 2 ) {
                k[2] = new BigNumber( key[2] );
            }
            if ( l > 3 ) {
                k[3] = new Modulus( key[3] );
                k[4] = new Modulus( key[4] );
                k[5] = new BigNumber( key[5] );
                k[6] = new BigNumber( key[6] );
                k[7] = new BigNumber( key[7] );
            }

            this.key = k;
        }
        else {
            throw new TypeError("unexpected key type");
        }
    }

    return this;
}

function RSA_encrypt ( data ) {
    if ( !this.key )
        throw new IllegalStateError("no key is associated with the instance");

    if ( is_string(data) )
        data = string_to_bytes(data);

    if ( is_buffer(data) )
        data = new Uint8Array(data);

    var msg;
    if ( is_bytes(data) ) {
        msg = new BigNumber(data);
    }
    else if ( is_big_number(data) ) {
        msg = data;
    }
    else {
        throw new TypeError("unexpected data type");
    }

    if ( this.key[0].compare(msg) <= 0 )
        throw new RangeError("data too large");

    this.result = this.key[0].power( msg, this.key[1] ).toBytes();

    return this;
}

function RSA_decrypt ( data ) {
    if ( !this.key )
        throw new IllegalStateError("no key is associated with the instance");

    if ( this.key.length < 3 )
        throw new IllegalStateError("key isn't suitable for decription");

    if ( is_string(data) )
        data = string_to_bytes(data);

    if ( is_buffer(data) )
        data = new Uint8Array(data);

    var msg;
    if ( is_bytes(data) ) {
        msg = new BigNumber(data);
    }
    else if ( is_big_number(data) ) {
        msg = data;
    }
    else {
        throw new TypeError("unexpected data type");
    }

    if ( this.key[0].compare(msg) <= 0 )
        throw new RangeError("data too large");

    var result;
    if ( this.key.length > 3 ) {
        var m = this.key[0],
            d = this.key[2],
            p = this.key[3],
            q = this.key[4],
            dp = this.key[5],
            dq = this.key[6],
            u = this.key[7];

        var x = p.power( msg, dp ),
            y = q.power( msg, dq );

        var t = x.subtract(y);
        while ( t.sign < 0 ) t = t.add(p);

        var h = p.reduce( u.multiply(t) );

        result = h.multiply(q).add(y).clamp(m.bitLength).toBytes();
    }
    else {
        var m = this.key[0],
            d = this.key[2];

        result = m.power( msg, d ).toBytes();
    }

    var bytelen = m.bitLength + 7 >> 3;
    if ( result.length < bytelen ) {
        var r = new Uint8Array(bytelen);
        r.set( result, bytelen - result.length );
        result = r;
    }

    this.result = result;

    return this;
}

var RSA_prototype = RSA.prototype;
RSA_prototype.reset = RSA_reset;
RSA_prototype.encrypt = RSA_encrypt;
RSA_prototype.decrypt = RSA_decrypt;
<|endoftext|>


<commit_before>import React from "react";
import { Icon, Button, Intent } from "@blueprintjs/core";
import {
  FileUploadField,
  TextareaField,
  EditableTextField,
  CheckboxField
} from "teselagen-react-components";
import { reduxForm, FieldArray } from "redux-form";
import { anyToJson } from "bio-parsers";
import { flatMap } from "lodash";
import axios from "axios";
import uniqid from "uniqid";

// import { Checkbox } from "material-ui";
// import {  } from "teselagen-react-components/lib/FormComponents";

export default {
  updateKeys: ["alignmentTool", "toggleFindTool"],
  itemProps: ({ alignmentTool = {}, toggleDropdown }) => {
    return {
      Icon: <Icon icon={"align-left"} />,
      // toggled: alignmentTool.isOpen,
      renderIconAbove: alignmentTool.isOpen,
      // onIconClick: toggleFindTool,
      Dropdown: AlignmentToolDropown,
      onIconClick: toggleDropdown,
      noDropdownIcon: true,
      tooltip: alignmentTool.isOpen
        ? "Hide Alignment Tool"
        : "Show Alignment Tool"
    };
  }
};

class AlignmentToolDropown extends React.Component {
  render() {
    const {
      savedAlignments = [],
      showCreateAlignmentDialog,
      sequenceData
    } = this.props;
    return (

        <Button
          intent={Intent.PRIMARY}
          onClick={() => {
            showCreateAlignmentDialog({
              ...this.props,
              initialValues: {
                addedSequences: [{ ...sequenceData, isTemplate: true }]
              }
            });
          }}
        >
          Create New Alignment
        </Button>

Saved Alignments:

        {!savedAlignments.length && (

 No Alignments

        )}
        {savedAlignments.map((savedAlignment, i) => {
          return
Saved Alignment {i}
;
        })}

    );
  }
}

const instance = axios.create({
  // timeout: 1000,
  // headers: getJ5AuthorizationHeaders()
});

class AlignmentTool extends React.Component {
  state = {
    templateSeqIndex: 0
  };
  sendSelectedDataToBackendForAlignment = async ({
    addedSequences,
    isPairwiseAlignment
  }) => {
    const {
      hideModal,
      /* onAlignmentSuccess, */ createNewAlignment,
      upsertAlignmentRun
    } = this.props;
    const { templateSeqIndex } = this.state;
    const addedSequencesToUse = array_move(addedSequences, templateSeqIndex, 0);
    hideModal();
    const alignmentId = uniqid();
    createNewAlignment({
      id: alignmentId,
      name: addedSequencesToUse[0].name + " Alignment"
    });
    //set the alignemnt to loading
    upsertAlignmentRun({
      id: alignmentId,
      loading: true
    });

    window.toastr.success("Alignment submitted.");
    const {
      data: { alignedSequences, pairwiseAlignments } = {}
    } = await instance.post(
      "http://localhost:3000/alignment/run",
      // "http://j5server.teselagen.com/alignment/run",
      {
        sequencesToAlign: addedSequencesToUse,
        isPairwiseAlignment
      }
    );
    if (!alignedSequences && !pairwiseAlignments)
      window.toastr.error("Error running sequence alignment!");
    //set the alignemnt to loading
    upsertAlignmentRun({
      id: alignmentId,
      pairwiseAlignments: pairwiseAlignments.map((alignedSequences, topIndex) => {
        return alignedSequences.map((alignmentData, innerIndex) => {
          return {
            sequenceData: addedSequencesToUse[innerIndex > 0 ? topIndex : 0],
            alignmentData
          };
        })
      }),
      alignmentTracks:
        alignedSequences &&
        alignedSequences.map((alignmentData, i) => {
          return {
            sequenceData: addedSequencesToUse[i],
            alignmentData
          };
        })
    });
  };

  handleFileUpload = (files, onChange) => {
    const { array } = this.props;
    flatMap(files, async file => {
      const results = await anyToJson(file.originalFileObj, {
        fileName: file.name
      });
      return results.forEach(result => {
        if (result.success) {
          array.push("addedSequences", result.parsedSequence);
          console.log(result.parsedSequence);
        } else {
          return window.toastr.warning("Error parsing file: ", file.name);
        }
      });
    });
    onChange([]);
  };
  renderAddSequence = ({ fields, templateSeqIndex }) => {
    const { handleSubmit } = this.props;

    const sequencesToAlign = fields.getAll() || [];
    return (

Or enter sequences in plain text format

          <AddYourOwnSeqForm
            addSeq={newSeq => {
              fields.push(newSeq);
            }}
          />

Sequences To Align:

          {!fields.getAll() &&
No sequences added yet.
}

            {sequencesToAlign.map((addedSeq, index) => {
              return (

 {
                    console.log("clickin");
                    console.log("index:", index);
                    this.setState({
                      templateSeqIndex: index
                    });
                  }}
                  style={{
                    borderBottom: "1px solid lightgrey",
                    paddingBottom: 4,
                    marginBottom: 4,
                    width: "100%",
                    justifyContent: "space-between",
                    alignItems: "center",
                    display: "flex"
                  }}
                  key={index}
                >

                    {addedSeq.name}{" "}

                      {" "}
                      ({addedSeq.sequence.length} bps)

                  {index === templateSeqIndex && (

                      template

                  )}

                  <Button
                    onClick={e => {
                      e.stopPropagation();
                      e.preventDefault();
                      fields.remove(index);
                      if (index === templateSeqIndex) {
                        this.setState({ templateSeqIndex: 0 });
                      }
                    }}
                  >
                    Remove
                  </Button>

              );
            })}

          <CheckboxField
            name="isPairwiseAlignment"
            label={

                Create Pairwise Alignment{" "}

                  Individually align each uploaded file against the template
                  sequence (instead of creating a single Multiple Sequence
                  Alignment)

            }
          />

          <Button
            style={{ marginTop: 15, float: "right" }}
            intent={Intent.PRIMARY}
            disabled={sequencesToAlign.length < 2}
            onClick={handleSubmit(this.sendSelectedDataToBackendForAlignment)}
          >
            Create alignment
          </Button>

    );
  };

  render() {
    const { selectFromSequenceLibraryHook } = this.props;
    const { templateSeqIndex } = this.state;
    return (

Upload files you'd like to align (.ab1, .fasta, .gb)

        <FileUploadField
          name="alignmentToolSequenceUpload"
          style={{ maxWidth: 400 }}
          beforeUpload={this.handleFileUpload}
        />
        {selectFromSequenceLibraryHook && (

Or Select from your sequence library

        )}

        <FieldArray
          name={`addedSequences`}
          templateSeqIndex={templateSeqIndex}
          component={this.renderAddSequence}
        />

    );
  }
}

export const AlignmentToolInner = reduxForm({
  form: "veAlignmentTool"
  // initialValues: {
  //   addedSequences: []
  // },
})(AlignmentTool);

const AddYourOwnSeqForm = reduxForm({
  form: "AddYourOwnSeqForm",
  validate: ({ name, sequence }) => {
    const errors = {};
    if (!name) {
      errors.name = "Required";
    }
    if (!sequence) {
      errors.sequence = "Required";
    }
    return errors;
  }
})(({ pristine, error, handleSubmit, reset, addSeq }) => {
  return (

      <EditableTextField
        style={{ maxWidth: 200 }}
        placeholder="Untitled Sequence"
        name="name"
      />
      <TextareaField
        style={{ maxWidth: 400 }}
        placeholder="AGTTGAGC"
        name="sequence"
      />
      <Button
        disabled={pristine || error}
        onClick={handleSubmit(vals => {
          reset();
          addSeq(vals);
        })}
      >
        Add
      </Button>

  );
});

function array_move(arr, old_index, new_index) {
  if (new_index >= arr.length) {
    let k = new_index - arr.length + 1;
    while (k--) {
      arr.push(undefined);
    }
  }
  arr.splice(new_index, 0, arr.splice(old_index, 1)[0]);
  return arr; // for testing
}
<commit_msg>changing alignmentTool server<commit_after>import React from "react";
import { Icon, Button, Intent } from "@blueprintjs/core";
import {
  FileUploadField,
  TextareaField,
  EditableTextField,
  CheckboxField
} from "teselagen-react-components";
import { reduxForm, FieldArray } from "redux-form";
import { anyToJson } from "bio-parsers";
import { flatMap } from "lodash";
import axios from "axios";
import uniqid from "uniqid";

// import { Checkbox } from "material-ui";
// import {  } from "teselagen-react-components/lib/FormComponents";

export default {
  updateKeys: ["alignmentTool", "toggleFindTool"],
  itemProps: ({ alignmentTool = {}, toggleDropdown }) => {
    return {
      Icon: <Icon icon={"align-left"} />,
      // toggled: alignmentTool.isOpen,
      renderIconAbove: alignmentTool.isOpen,
      // onIconClick: toggleFindTool,
      Dropdown: AlignmentToolDropown,
      onIconClick: toggleDropdown,
      noDropdownIcon: true,
      tooltip: alignmentTool.isOpen
        ? "Hide Alignment Tool"
        : "Show Alignment Tool"
    };
  }
};

class AlignmentToolDropown extends React.Component {
  render() {
    const {
      savedAlignments = [],
      showCreateAlignmentDialog,
      sequenceData
    } = this.props;
    return (

        <Button
          intent={Intent.PRIMARY}
          onClick={() => {
            showCreateAlignmentDialog({
              ...this.props,
              initialValues: {
                addedSequences: [{ ...sequenceData, isTemplate: true }]
              }
            });
          }}
        >
          Create New Alignment
        </Button>

Saved Alignments:

        {!savedAlignments.length && (

 No Alignments

        )}
        {savedAlignments.map((savedAlignment, i) => {
          return
Saved Alignment {i}
;
        })}

    );
  }
}

const instance = axios.create({
  // timeout: 1000,
  // headers: getJ5AuthorizationHeaders()
});

class AlignmentTool extends React.Component {
  state = {
    templateSeqIndex: 0
  };
  sendSelectedDataToBackendForAlignment = async ({
    addedSequences,
    isPairwiseAlignment
  }) => {
    const {
      hideModal,
      /* onAlignmentSuccess, */ createNewAlignment,
      upsertAlignmentRun
    } = this.props;
    const { templateSeqIndex } = this.state;
    const addedSequencesToUse = array_move(addedSequences, templateSeqIndex, 0);
    hideModal();
    const alignmentId = uniqid();
    createNewAlignment({
      id: alignmentId,
      name: addedSequencesToUse[0].name + " Alignment"
    });
    //set the alignemnt to loading
    upsertAlignmentRun({
      id: alignmentId,
      loading: true
    });

    window.toastr.success("Alignment submitted.");
    const {
      data: { alignedSequences, pairwiseAlignments } = {}
    } = await instance.post(
      // "http://localhost:3000/alignment/run",
      "http://j5server.teselagen.com/alignment/run",
      {
        sequencesToAlign: addedSequencesToUse,
        isPairwiseAlignment
      }
    );
    if (!alignedSequences && !pairwiseAlignments)
      window.toastr.error("Error running sequence alignment!");
    //set the alignemnt to loading
    upsertAlignmentRun({
      id: alignmentId,
      pairwiseAlignments: pairwiseAlignments.map(
        (alignedSequences, topIndex) => {
          return alignedSequences.map((alignmentData, innerIndex) => {
            return {
              sequenceData: addedSequencesToUse[innerIndex > 0 ? topIndex : 0],
              alignmentData
            };
          });
        }
      ),
      alignmentTracks:
        alignedSequences &&
        alignedSequences.map((alignmentData, i) => {
          return {
            sequenceData: addedSequencesToUse[i],
            alignmentData
          };
        })
    });
  };

  handleFileUpload = (files, onChange) => {
    const { array } = this.props;
    flatMap(files, async file => {
      const results = await anyToJson(file.originalFileObj, {
        fileName: file.name
      });
      return results.forEach(result => {
        if (result.success) {
          array.push("addedSequences", result.parsedSequence);
          console.log(result.parsedSequence);
        } else {
          return window.toastr.warning("Error parsing file: ", file.name);
        }
      });
    });
    onChange([]);
  };
  renderAddSequence = ({ fields, templateSeqIndex }) => {
    const { handleSubmit } = this.props;

    const sequencesToAlign = fields.getAll() || [];
    return (

Or enter sequences in plain text format

          <AddYourOwnSeqForm
            addSeq={newSeq => {
              fields.push(newSeq);
            }}
          />

Sequences To Align:

          {!fields.getAll() &&
No sequences added yet.
}

            {sequencesToAlign.map((addedSeq, index) => {
              return (

 {
                    console.log("clickin");
                    console.log("index:", index);
                    this.setState({
                      templateSeqIndex: index
                    });
                  }}
                  style={{
                    borderBottom: "1px solid lightgrey",
                    paddingBottom: 4,
                    marginBottom: 4,
                    width: "100%",
                    justifyContent: "space-between",
                    alignItems: "center",
                    display: "flex"
                  }}
                  key={index}
                >

                    {addedSeq.name}{" "}

                      {" "}
                      ({addedSeq.sequence.length} bps)

                  {index === templateSeqIndex && (

                      template

                  )}

                  <Button
                    onClick={e => {
                      e.stopPropagation();
                      e.preventDefault();
                      fields.remove(index);
                      if (index === templateSeqIndex) {
                        this.setState({ templateSeqIndex: 0 });
                      }
                    }}
                  >
                    Remove
                  </Button>

              );
            })}

          <CheckboxField
            name="isPairwiseAlignment"
            label={

                Create Pairwise Alignment{" "}

                  Individually align each uploaded file against the template
                  sequence (instead of creating a single Multiple Sequence
                  Alignment)

            }
          />

          <Button
            style={{ marginTop: 15, float: "right" }}
            intent={Intent.PRIMARY}
            disabled={sequencesToAlign.length < 2}
            onClick={handleSubmit(this.sendSelectedDataToBackendForAlignment)}
          >
            Create alignment
          </Button>

    );
  };

  render() {
    const { selectFromSequenceLibraryHook } = this.props;
    const { templateSeqIndex } = this.state;
    return (

Upload files you'd like to align (.ab1, .fasta, .gb)

        <FileUploadField
          name="alignmentToolSequenceUpload"
          style={{ maxWidth: 400 }}
          beforeUpload={this.handleFileUpload}
        />
        {selectFromSequenceLibraryHook && (

Or Select from your sequence library

        )}

        <FieldArray
          name={`addedSequences`}
          templateSeqIndex={templateSeqIndex}
          component={this.renderAddSequence}
        />

    );
  }
}

export const AlignmentToolInner = reduxForm({
  form: "veAlignmentTool"
  // initialValues: {
  //   addedSequences: []
  // },
})(AlignmentTool);

const AddYourOwnSeqForm = reduxForm({
  form: "AddYourOwnSeqForm",
  validate: ({ name, sequence }) => {
    const errors = {};
    if (!name) {
      errors.name = "Required";
    }
    if (!sequence) {
      errors.sequence = "Required";
    }
    return errors;
  }
})(({ pristine, error, handleSubmit, reset, addSeq }) => {
  return (

      <EditableTextField
        style={{ maxWidth: 200 }}
        placeholder="Untitled Sequence"
        name="name"
      />
      <TextareaField
        style={{ maxWidth: 400 }}
        placeholder="AGTTGAGC"
        name="sequence"
      />
      <Button
        disabled={pristine || error}
        onClick={handleSubmit(vals => {
          reset();
          addSeq(vals);
        })}
      >
        Add
      </Button>

  );
});

function array_move(arr, old_index, new_index) {
  if (new_index >= arr.length) {
    let k = new_index - arr.length + 1;
    while (k--) {
      arr.push(undefined);
    }
  }
  arr.splice(new_index, 0, arr.splice(old_index, 1)[0]);
  return arr; // for testing
}
<|endoftext|>


<commit_before>const { denodeify, is, g2b } = require('./utils');
const errors = require('./errors');

const Environment = require('./environment');
const Logger = require('./logger');
const Parser = require('./parser');
const exclude = require('./exclude');
const recurse = require('./recurse');
const sorter = require('./sorter');

const difference = require('lodash.difference'); // jshint ignore:line
const fs = require('fs');
const path = require('path'); // jshint ignore:line
const mkdir = denodeify(require('mkdirp'));
const safeWipe = require('safe-wipe');
const vfs = require('vinyl-fs');
const converter = require('sass-convert');
const pipe = require('multipipe'); // jshint ignore:line
const through = require('through2');

/**
 * @return {Stream}
 */
export function parseFilter(env = {}) {
  env = ensureEnvironment(env);

  let parser = new Parser(env, env.theme && env.theme.annotations);
  let filter = parser.stream();

  filter.promise
    .then(data => sorter(data));

  return filter;
}

/**
 * @return {Object}
 */
export function ensureEnvironment(config, onError = e => { throw e; }) {
  if (config instanceof Environment) {
    config.on('error', onError);
    return config;
  }

  let logger = config.logger || new Logger(config.verbose, process.env.SASSDOC_DEBUG);
  let env = new Environment(logger, config.strict);

  env.on('error', onError);
  env.load(config);
  env.postProcess();

  return env;
}

/**
 * Expose API.
 */
export { Environment, Logger, Parser, sorter, errors };

/**
 * @param {String} src
 * @param {Object} env
 * @see srcEnv
 */
export default function sassdoc(...args) {
  return srcEnv(documentize, stream)(...args); // jshint ignore:line

  /**
   * @return {Promise}
   */
  async function documentize(env) { // jshint ignore:line
    /* jshint ignore:start */

    let data = await baseDocumentize(env);

    try {
      await refresh(env);
      await theme(env);
      okay(env);
    } catch (err) {
      env.emit('error', err);
      throw err;
    }

    return data;

    /* jshint ignore:end */
  }

  /**
   * Safely wipe and re-create the destination dir.
   */
  function refresh(env) { // jshint ignore:line
    return safeWipe(env.dest, {
      force: true,
      parent: is.string(env.src) ? g2b(env.src) : null,
      silent: true,
    })
      .then(() => mkdir(env.dest))
      .then(() => {
        env.logger.log(`Folder "${env.dest}" successfully refreshed.`);
      })
      .catch(err => {
        // Friendly error for already existing directory.
        throw new errors.SassDocError(err.message);
      });
  }

  /**
   * Render theme with parsed data.
   */
  function theme(env) { // jshint ignore:line
    let promise = env.theme(env.dest, env);

    if (!is.promise(promise)) {
      let type = Object.prototype.toString.call(promise);
      throw new errors.Error(`Theme didn't return a promise, got ${type}.`);
    }

    return promise
      .then(() => {
        let themeName = env.themeName || 'anonymous';
        env.logger.log(`Theme "${themeName}" successfully rendered.`);
      });
  }

  /**
   * Pipe SassDoc to Vinyl files streams.
   *
   * @return {Stream}
   */
  function stream(env) {
    let filter = parseFilter(env);

    /* jshint ignore:start */

    let documentize = async () => {

      try {
        await refresh(env);
        await filter.promise;
        await theme(env);
        okay(env);
      } catch (err) {
        env.emit('error', err);
        throw err;
      }
    };

    filter
      .on('pipe', documentize)
      .on('error', err => env.emit('error', err))
      .resume(); // Drain.

    /* jshint ignore:end */

    filter.promise
      .then(data => {
        env.logger.log('SCSS files successfully parsed.');
        env.data = data;
      });

    return filter;
  }
}

/**
 * @param {String} src
 * @param {Object} env
 * @see srcEnv
 */
export function parse(...args) { // jshint ignore:line
  /* jshint ignore:start */

  return srcEnv(documentize, stream)(...args);

  async function documentize(env) {
    let data = await baseDocumentize(env);
    okay(env);

    return data;
  }

  /* jshint ignore:end */

  /**
   * Don't pass chuncks, but pass final data at the end.
   */
  function stream(env) { // jshint ignore:line
    let parse = parseFilter(env);

    let filter = through.obj((file, enc, cb) => cb(), function (cb) {
      parse.promise.then(data => {
        this.push(data);
        cb();
      }, cb);
    });

    return pipe(parse, filter);
  }
}

async function baseDocumentize(env) { // jshint ignore:line
  let filter = parseFilter(env);

  filter.promise
    .then(data => {
      env.logger.log(`Folder "${env.src}" successfully parsed.`);
      env.data = data;

      env.logger.debug(() => {
        fs.writeFile(
          'sassdoc-data.json',
          JSON.stringify(data, null, 2) + '\n'
        );

        return 'Dumping data to "sassdoc-data.json".';
      });
    });

  let streams = [ // jshint ignore:line
    vfs.src(env.src),
    recurse(),
    exclude(env.exclude || []),
    converter({ from: 'sass', to: 'scss' }),
    filter
  ];

  /* jshint ignore:start */

  let pipeline = () => {
    return new Promise((resolve, reject) => {
      pipe(...streams, err => {
        err ? reject(err) : resolve();
      })
      .resume(); // Drain.
    });
  };

  try {
    await pipeline();
  } catch (err) {
    env.emit('error', err);
    throw err;
  }

  return env.data;
}

/**
 * Return a function taking optional `src` string or array, and optional
 * `env` object (arguments are found by their type).
 *
 * If `src` is set, proxy to `documentize`, otherwise `stream`.
 *
 * Both functions will be passed the `env` object, which will have a
 * `src` key.
 */
function srcEnv(documentize, stream) {
  return function (...args) {
    let src = args.find(a => is.string(a) || is.array(a));
    let env = args.find(is.object);

    env = ensureEnvironment(env || {});

    env.logger.debug('process.argv:', () => JSON.stringify(process.argv));
    env.logger.debug('sassdoc version:', () => require('../package.json').version);
    env.logger.debug('node version:', () => process.version.substr(1));

    env.logger.debug('npm version:', () => {
      let prefix = path.resolve(process.execPath, '../../lib');
      let pkg = path.resolve(prefix, 'node_modules/npm/package.json');

      try {
        return require(pkg).version;
      } catch (e) {
        return 'unknown';
      }
    });

    env.logger.debug('platform:', () => process.platform);
    env.logger.debug('cwd:', () => process.cwd());

    env.src = src;
    env.dest = env.dest || 'sassdoc';

    env.logger.debug('env:', () => {
      let clone = {};

      difference(
        Object.getOwnPropertyNames(env),
        ['domain', '_events', '_maxListeners', 'logger']
      )
        .forEach(k => clone[k] = env[k]);

      return JSON.stringify(clone, null, 2);
    });

    let task = env.src ? documentize : stream;
    env.logger.debug('task:', () => task.name);

    return task(env);
  };
}

/**
 * Log success message.
 */
function okay(env) {
  env.logger.log('Process over. Everything okay!');
}
<commit_msg>Commenting, logical order<commit_after>const { denodeify, is, g2b } = require('./utils');

const Environment = require('./environment');
const Logger = require('./logger');
const Parser = require('./parser');
const errors = require('./errors');
const sorter = require('./sorter');
const exclude = require('./exclude');
const recurse = require('./recurse');

const fs = require('fs');
const path = require('path'); // jshint ignore:line
const difference = require('lodash.difference'); // jshint ignore:line
const mkdir = denodeify(require('mkdirp'));
const safeWipe = require('safe-wipe');
const vfs = require('vinyl-fs');
const converter = require('sass-convert');
const pipe = require('multipipe'); // jshint ignore:line
const through = require('through2');

/**
 * Expose lower API blocks.
 */
export { Environment, Logger, Parser, sorter, errors };

/**
 * Boostrap Parser and AnnotationsApi, execute parsing phase.
 * @return {Stream.Promise}
 */
export function parseFilter(env = {}) {
  env = ensureEnvironment(env);

  let parser = new Parser(env, env.theme && env.theme.annotations);
  let filter = parser.stream();

  filter.promise
    .then(data => sorter(data));

  return filter;
}

/**
 * Ensure a proper Environment Object and events.
 * @return {Object}
 */
export function ensureEnvironment(config, onError = e => { throw e; }) {
  if (config instanceof Environment) {
    config.on('error', onError);
    return config;
  }

  let logger = config.logger || new Logger(config.verbose, process.env.SASSDOC_DEBUG);
  let env = new Environment(logger, config.strict);

  env.on('error', onError);
  env.load(config);
  env.postProcess();

  return env;
}

/**
 * Default public API method.
 * @param {String | Array} src
 * @param {Object} env
 * @return {Promise | Stream}
 * @see srcEnv
 */
export default function sassdoc(...args) {
  return srcEnv(documentize, stream)(...args); // jshint ignore:line

  /**
   * Safely wipe and re-create the destination directory.
   * @return {Promise}
   */
  function refresh(env) { // jshint ignore:line
    return safeWipe(env.dest, {
      force: true,
      parent: is.string(env.src) ? g2b(env.src) : null,
      silent: true,
    })
      .then(() => mkdir(env.dest))
      .then(() => {
        env.logger.log(`Folder "${env.dest}" successfully refreshed.`);
      })
      .catch(err => {
        // Friendly error for already existing directory.
        throw new errors.SassDocError(err.message);
      });
  }

  /**
   * Render theme with parsed data context.
   * @return {Promise}
   */
  function theme(env) { // jshint ignore:line
    let promise = env.theme(env.dest, env);

    if (!is.promise(promise)) {
      let type = Object.prototype.toString.call(promise);
      throw new errors.Error(`Theme didn't return a promise, got ${type}.`);
    }

    return promise
      .then(() => {
        let themeName = env.themeName || 'anonymous';
        env.logger.log(`Theme "${themeName}" successfully rendered.`);
      });
  }

  /**
   * Execute full SassDoc sequence from a source directory.
   * @return {Promise}
   */
  async function documentize(env) { // jshint ignore:line
    /* jshint ignore:start */

    let data = await baseDocumentize(env);

    try {
      await refresh(env);
      await theme(env);
      okay(env);
    } catch (err) {
      env.emit('error', err);
      throw err;
    }

    return data;

    /* jshint ignore:end */
  }

  /**
   * Execute full SassDoc sequence from a Vinyl files stream.
   * @return {Stream}
   */
  function stream(env) {
    let filter = parseFilter(env);

    /* jshint ignore:start */

    let documentize = async () => {
      try {
        await refresh(env);
        await filter.promise;
        await theme(env);
        okay(env);
      } catch (err) {
        env.emit('error', err);
        throw err;
      }
    };

    filter
      .on('pipe', documentize)
      .on('error', err => env.emit('error', err))
      .resume(); // Drain.

    /* jshint ignore:end */

    filter.promise
      .then(data => {
        env.logger.log('SCSS files successfully parsed.');
        env.data = data;
      });

    return filter;
  }
}

/**
 * Parse and return data object.
 * @param {String | Array} src
 * @param {Object} env
 * @return {Promise | Stream}
 * @see srcEnv
 */
export function parse(...args) { // jshint ignore:line
  /* jshint ignore:start */

  return srcEnv(documentize, stream)(...args);

  /**
   * @return {Promise}
   */
  async function documentize(env) {
    let data = await baseDocumentize(env);
    okay(env);

    return data;
  }

  /* jshint ignore:end */

  /**
   * Don't pass files through, but pass final data at the end.
   * @return {Stream}
   */
  function stream(env) { // jshint ignore:line
    let parse = parseFilter(env);

    let filter = through.obj((file, enc, cb) => cb(), function (cb) {
      parse.promise.then(data => {
        this.push(data);
        cb();
      }, cb);
    });

    return pipe(parse, filter);
  }
}

/**
 * Source directory fetching and parsing.
 */
async function baseDocumentize(env) { // jshint ignore:line
  let filter = parseFilter(env);

  filter.promise
    .then(data => {
      env.logger.log(`Folder "${env.src}" successfully parsed.`);
      env.data = data;

      env.logger.debug(() => {
        fs.writeFile(
          'sassdoc-data.json',
          JSON.stringify(data, null, 2) + '\n'
        );

        return 'Dumping data to "sassdoc-data.json".';
      });
    });

  let streams = [ // jshint ignore:line
    vfs.src(env.src),
    recurse(),
    exclude(env.exclude || []),
    converter({ from: 'sass', to: 'scss' }),
    filter
  ];

  /* jshint ignore:start */

  let pipeline = () => {
    return new Promise((resolve, reject) => {
      pipe(...streams, err => {
        err ? reject(err) : resolve();
      })
      .resume(); // Drain.
    });
  };

  try {
    await pipeline();
  } catch (err) {
    env.emit('error', err);
    throw err;
  }

  return env.data;

  /* jshint ignore:end */
}

/**
 * Return a function taking optional `src` string or array, and optional
 * `env` object (arguments are found by their type).
 *
 * If `src` is set, proxy to `documentize`, otherwise `stream`.
 *
 * Both functions will be passed the `env` object, which will have a
 * `src` key.
 */
function srcEnv(documentize, stream) {
  return function (...args) {
    let src = args.find(a => is.string(a) || is.array(a));
    let env = args.find(is.object);

    env = ensureEnvironment(env || {});

    env.logger.debug('process.argv:', () => JSON.stringify(process.argv));
    env.logger.debug('sassdoc version:', () => require('../package.json').version);
    env.logger.debug('node version:', () => process.version.substr(1));

    env.logger.debug('npm version:', () => {
      let prefix = path.resolve(process.execPath, '../../lib');
      let pkg = path.resolve(prefix, 'node_modules/npm/package.json');

      try {
        return require(pkg).version;
      } catch (e) {
        return 'unknown';
      }
    });

    env.logger.debug('platform:', () => process.platform);
    env.logger.debug('cwd:', () => process.cwd());

    env.src = src;
    env.dest = env.dest || 'sassdoc';

    env.logger.debug('env:', () => {
      let clone = {};

      difference(
        Object.getOwnPropertyNames(env),
        ['domain', '_events', '_maxListeners', 'logger']
      )
        .forEach(k => clone[k] = env[k]);

      return JSON.stringify(clone, null, 2);
    });

    let task = env.src ? documentize : stream;
    env.logger.debug('task:', () => task.name);

    return task(env);
  };
}

/**
 * Log final success message.
 */
function okay(env) { // jshint ignore:line
  env.logger.log('Process over. Everything okay!');
}
<|endoftext|>


<commit_before>let utils = require('./utils');
let mkdir = utils.denodeify(require('mkdirp'));
let safeWipe = require('safe-wipe');
let vfs = require('vinyl-fs');
let glob2base = require('glob2base');
let Glob = require('glob').Glob;
let cfg = require('./cfg');
let Logger = require('./logger').default;
let Parser = require('./parser').default;
let sort = require('./sorter').default;
let recurse = require('./recurse').default;
let exclude = require('./exclude').default;
let converter = require('sass-convert');
let pipe = require('multipipe');

export default function sassdoc(src, dest, config = {}) {
  let logger = config.logger = config.logger || new Logger();
  config = cfg.post(config);

  return refresh(dest, {
    interactive: config.interactive || false,
    force: config.force || false,
    parent: g2b(src),
    silent: true,
  })

    .then(() => {
      logger.log(`Folder "${dest}" successfully refreshed.`);
      return parse(src, config);
    }, err => {
      // Friendly error for already existing directory
      throw new utils.SassDocError(err.message);
    })

    .then(data => {
      logger.log(`Folder "${src}" successfully parsed.`);
      config.data = data;

      let promise = config.theme(dest, config);

      if (promise && typeof promise.then === 'function') {
        return promise;
      }

      let type = Object.prototype.toString.call(promise);
      throw new Error(`Theme didn't return a promise, got ${type}.`);
    })

    .then(() => {
      if (config.themeName) {
        logger.log(`theme "${config.themeName}" successfully rendered.`);
      } else {
        logger.log('Anonymous theme successfully rendered.');
      }

      logger.log('Process over. Everything okay!');
    }, err => {
      let friendlyErrors = [
        utils.SassDocError,
        converter.BinaryError,
        converter.VersionError,
      ];

      if (friendlyErrors.indexOf(err.constructor) !== -1) {
        logger.error(err.message);
      } else {
        logger.error('stack' in err ? err.stack : err);
      }

      throw err;
    });
}

export function parse(src, config = {}) {
  config = cfg.post(config);

  let deferred = utils.defer();
  let parser = new Parser(config, config.theme && config.theme.annotations);
  let parseFilter = parser.stream();

  let stream = pipe(
    recurse(),
    exclude(config.exclude || []),
    converter({ from: 'sass', to: 'scss' }),
    parseFilter
  );

  vfs.src(src)
    .pipe(stream)
    .on('error', deferred.reject);

  parseFilter.promise
    .then(data => sort(data))
    .then(deferred.resolve, deferred.reject);

  return deferred.promise;
}

export function refresh(dest, config) {
  return safeWipe(dest, config)
    .then(() => mkdir(dest));
}

// Backward compability with v1.0 API.
/*global sassdoc: true */
export var documentize = sassdoc;

// Re-export, expose API.
export { Logger, Parser, sort, cfg };

/**
 * Get the base directory of given glob pattern (see `glob2base`).
 *
 * If it's an array, take the first one.
 *
 * @param {Array|String} src Glob pattern or array of glob patterns.
 * @return {String}
 */
function g2b(src) {
  return glob2base(new Glob([].concat(src)[0]));
}
<commit_msg>Allow verbose mode using the API<commit_after>let utils = require('./utils');
let mkdir = utils.denodeify(require('mkdirp'));
let safeWipe = require('safe-wipe');
let vfs = require('vinyl-fs');
let glob2base = require('glob2base');
let Glob = require('glob').Glob;
let cfg = require('./cfg');
let Logger = require('./logger').default;
let Parser = require('./parser').default;
let sort = require('./sorter').default;
let recurse = require('./recurse').default;
let exclude = require('./exclude').default;
let converter = require('sass-convert');
let pipe = require('multipipe');

export default function sassdoc(src, dest, config = {}) {
  let logger = config.logger = config.logger || new Logger(config.verbose);
  config = cfg.post(config);

  return refresh(dest, {
    interactive: config.interactive || false,
    force: config.force || false,
    parent: g2b(src),
    silent: true,
  })

    .then(() => {
      logger.log(`Folder "${dest}" successfully refreshed.`);
      return parse(src, config);
    }, err => {
      // Friendly error for already existing directory
      throw new utils.SassDocError(err.message);
    })

    .then(data => {
      logger.log(`Folder "${src}" successfully parsed.`);
      config.data = data;

      let promise = config.theme(dest, config);

      if (promise && typeof promise.then === 'function') {
        return promise;
      }

      let type = Object.prototype.toString.call(promise);
      throw new Error(`Theme didn't return a promise, got ${type}.`);
    })

    .then(() => {
      if (config.themeName) {
        logger.log(`theme "${config.themeName}" successfully rendered.`);
      } else {
        logger.log('Anonymous theme successfully rendered.');
      }

      logger.log('Process over. Everything okay!');
    }, err => {
      let friendlyErrors = [
        utils.SassDocError,
        converter.BinaryError,
        converter.VersionError,
      ];

      if (friendlyErrors.indexOf(err.constructor) !== -1) {
        logger.error(err.message);
      } else {
        logger.error('stack' in err ? err.stack : err);
      }

      throw err;
    });
}

export function parse(src, config = {}) {
  config = cfg.post(config);

  let deferred = utils.defer();
  let parser = new Parser(config, config.theme && config.theme.annotations);
  let parseFilter = parser.stream();

  let stream = pipe(
    recurse(),
    exclude(config.exclude || []),
    converter({ from: 'sass', to: 'scss' }),
    parseFilter
  );

  vfs.src(src)
    .pipe(stream)
    .on('error', deferred.reject);

  parseFilter.promise
    .then(data => sort(data))
    .then(deferred.resolve, deferred.reject);

  return deferred.promise;
}

export function refresh(dest, config) {
  return safeWipe(dest, config)
    .then(() => mkdir(dest));
}

// Backward compability with v1.0 API.
/*global sassdoc: true */
export var documentize = sassdoc;

// Re-export, expose API.
export { Logger, Parser, sort, cfg };

/**
 * Get the base directory of given glob pattern (see `glob2base`).
 *
 * If it's an array, take the first one.
 *
 * @param {Array|String} src Glob pattern or array of glob patterns.
 * @return {String}
 */
function g2b(src) {
  return glob2base(new Glob([].concat(src)[0]));
}
<|endoftext|>


<commit_before>const app = require('electron').app;

const CONFIG = require('./config');

let BrowserWindow;

module.exports = function (electron) {
  BrowserWindow = electron.BrowserWindow;

  return {
    openMainWindow,
    openLogInWindow,
    closeLogInWindow,
    activateWithNoOpenWindows,
  };
};

const MAIN_WINDOW = 'main';
const AUTH_WINDOW = 'auth';

const ICON = __dirname + '/../static/icon.png';

const isMac = process.platform === 'darwin';

let windows = {};

function openMainWindow() {
  if (!windows[MAIN_WINDOW])
    windows[MAIN_WINDOW] = createMainWindow();
}

function openLogInWindow(url) {
  windows[AUTH_WINDOW] = createLogInWindow(url);
}

function closeLogInWindow() {
  windows[AUTH_WINDOW].close();
}

function createWindow(windowName, url, width, height, icon) {
  const win = new BrowserWindow({
    title: app.getName(),
    width,
    height,
    icon,
    autoHideMenuBar: true,
    minWidth: 780,
    minHeight: 270,
    frame: isMac,
    titleBarStyle: 'hidden-inset',
  });

  if (isMac)
    app.dock.setIcon(icon);

  if (require('electron-is-dev'))
    win.openDevTools();

  win.loadURL(url);
  win.on('closed', onClosed.bind(null, windowName));

  return win;
}

function createMainWindow() {
  const url = 'file://' + __dirname + '/client/index.html';

  return createWindow(
    MAIN_WINDOW,
    url,
    CONFIG.MAIN_WINDOW.WIDTH,
    CONFIG.MAIN_WINDOW.HEIGHT,
    ICON
  );
}

function createLogInWindow(url) {
  return createWindow(
    AUTH_WINDOW,
    url,
    CONFIG.AUTH_WINDOW.WIDTH,
    CONFIG.AUTH_WINDOW.HEIGHT,
    ICON
  );
}

function activateWithNoOpenWindows() {
  if (!windows[MAIN_WINDOW]) {
    windows[MAIN_WINDOW] = createMainWindow();
  }
}

function onClosed(windowName) {
  // dereference the window
  windows[windowName] = null;
}
<commit_msg>Rename variable<commit_after>const app = require('electron').app;

const CONFIG = require('./config');

let BrowserWindow;

module.exports = function (electron) {
  BrowserWindow = electron.BrowserWindow;

  return {
    openMainWindow,
    openLogInWindow,
    closeLogInWindow,
    activateWithNoOpenWindows,
  };
};

const MAIN_WINDOW = 'main';
const AUTH_WINDOW = 'auth';

const ICON = __dirname + '/../static/icon.png';

const isMac = process.platform === 'darwin';

let windows = {};

function openMainWindow() {
  if (!windows[MAIN_WINDOW])
    windows[MAIN_WINDOW] = createMainWindow();
}

function openLogInWindow(url) {
  windows[AUTH_WINDOW] = createLogInWindow(url);
}

function closeLogInWindow() {
  windows[AUTH_WINDOW].close();
}

function createWindow(windowName, url, width, height, icon) {
  const _window = new BrowserWindow({
    title: app.getName(),
    width,
    height,
    icon,
    autoHideMenuBar: true,
    minWidth: 780,
    minHeight: 270,
    frame: isMac,
    titleBarStyle: 'hidden-inset',
  });

  if (isMac)
    app.dock.setIcon(icon);

  if (require('electron-is-dev'))
    _window.openDevTools();

  _window.loadURL(url);
  _window.on('closed', onClosed.bind(null, windowName));

  return _window;
}

function createMainWindow() {
  const url = 'file://' + __dirname + '/client/index.html';

  return createWindow(
    MAIN_WINDOW,
    url,
    CONFIG.MAIN_WINDOW.WIDTH,
    CONFIG.MAIN_WINDOW.HEIGHT,
    ICON
  );
}

function createLogInWindow(url) {
  return createWindow(
    AUTH_WINDOW,
    url,
    CONFIG.AUTH_WINDOW.WIDTH,
    CONFIG.AUTH_WINDOW.HEIGHT,
    ICON
  );
}

function activateWithNoOpenWindows() {
  if (!windows[MAIN_WINDOW]) {
    windows[MAIN_WINDOW] = createMainWindow();
  }
}

function onClosed(windowName) {
  // dereference the window
  windows[windowName] = null;
}
<|endoftext|>


<commit_before>;(function(global) {%output%})(this);
<commit_msg>Add copyright comment<commit_after>/* selector-engine v0.0.1 | (c) 2016 Perelandric | MIT License */
;(function(global) {%output%})(this);
<|endoftext|>