<commit_before>#!/usr/bin/env node

/**
 * @fileOverview Read a csv file with cable number and change details and apply them to mongoDB.
 * @author Dong Liu
 */

var csv = require('csv');

var fs = require('fs');
var path = require('path');
var mongoose = require('mongoose');
var Cable = require('../model/request.js').Cable;
var MultiChange = require('../model/request.js').MultiChange;
var program = require('commander');

var inputPath;
var realPath;
var db;
var line = 0;
var changes = [];
var parser;
var properties = [];

program.version('0.0.1')
  .option('-d, --dryrun', 'dry run')
  .arguments('<source>')
  .action(function (source) {
    inputPath = source;
  });

program.parse(process.argv);

if (inputPath === undefined) {
  console.error('need the input source csv file path!');
  process.exit(1);
}

realPath = path.resolve(process.cwd(), inputPath);

if (!fs.existsSync(realPath)) {
  console.error(realPath + ' does not exist.');
  console.error('Please input a valid csv file path.');
  process.exit(1);
}

mongoose.connect('mongodb://localhost/cable_frib');
db = mongoose.connection;
db.on('error', console.error.bind(console, 'connection error:'));
db.once('open', function () {
  console.log('db connected');
});

function splitTags(s) {
  return s ? s.replace(/^(?:\s*,?)+/, '').replace(/(?:\s*,?)*$/, '').split(/\s*[,;]\s*/) : [];
}

function updateCable(change, i) {
  console.log('processing change ' + i);
  Cable.findOne({
    number: change[0]
  }).exec(function (err, cable) {
    if (err) {
      console.error(err);
    } else {
      if (!cable) {
        console.error('cannot find cable with id ' + change[0]);
        return;
      }

      var update = {};
      var updates = [];
      var conditionSatisfied = true;

      properties.forEach(function (p, index) {
        var currentValue = cable.get(p);
        switch (p) {
        case 'basic.tags':
          currentValue = currentValue ? currentValue.join() : '';
          break;
        case 'status':
          change[2 * index + 1] = parseInt(change[2 * index + 1]);
          change[2 * index + 2] = parseInt(change[2 * index + 2]);
        }

        if (change[2 * index + 1] === '_whatever_' || currentValue === change[2 * index + 1]) {
          if (change[2 * index + 2] !== currentValue) {
            if ([undefined, null, ''].indexOf(change[2 * index + 2]) !== -1 && [undefined, null, ''].indexOf(currentValue) !== -1) {
              // do nothing
            } else {
              if (p === 'basic.tags') {
                update[p] = splitTags(change[2 * index + 2]);
              } else {
                update[p] = change[2 * index + 2];
              }
              updates.push({
                property: p,
                oldValue: cable.get(p),
                newValue: update[p]
              });
            }
          }
        } else {
          console.log('cable ' + cable.number + ' ' + p + ' is ' + cable.get(p) + ', expect ' + change[2 * index + 1]);
          if (p === 'status') {
            conditionSatisfied = false;
          }
        }
      });
      var multiChange;
      if (conditionSatisfied && updates.length > 0) {
        multiChange = new MultiChange({
          cableName: cable.number,
          updates: updates,
          updatedBy: 'system',
          updatedOn: Date.now()
        });
      }
      if (multiChange) {
        update.updatedOn = Date.now();
        update.updatedBy = 'system';
        update.$inc = {
          __v: 1
        };
        if (program.dryrun) {
          console.log('cable ' + cable.number + ' will be updated with ' + JSON.stringify(update, null, 2));
        } else {
          multiChange.save(function (err1, c) {
            if (err) {
              console.error(err1);
            } else {
              update.$push = {
                changeHistory: c._id
              };
              cable.update(update, {
                new: true
              }, function (err2) {
                if (err2) {
                  console.error(err2);
                } else {
                  console.log('cable ' + cable.number + ' was updated with ' + JSON.stringify(update, null, 2));
                }
              });
            }
          });
        }
      } else {
        console.error('no changes for cable ' + cable.number);
      }
    }
  });

}

parser = csv.parse({
  trim: true
});

parser.on('readable', function () {
  var record = parser.read();
  var i;

  while (record) {
    line += 1;
    console.log('read ' + line + ' lines ...');
    if (line === 1) {
      if (record[0] !== 'number') {
        console.log('the first column should be number');
        process.exit(1);
      }
      for (i = 1; i < record.length; i += 1) {
        if (i % 2 === 1) {
          // empty columns
          if (record[i].length === 0) {
            break;
          }
          properties.push(record[i]);
        }
      }
    } else if (record[0].length === 9) {
      changes.push(record);
    }
    record = parser.read();
  }
});

parser.on('error', function (err) {
  console.log(err.message);
});

parser.on('finish', function () {
  console.log('Finished parsing the csv file at ' + Date.now());
  console.log('Starting to apply changes.');
  changes.forEach(function (change, index) {
    updateCable(change, index);
  });
});

fs.createReadStream(realPath).pipe(parser);

// keep running until the user interrupts
process.stdin.resume();
<commit_msg>Fix typo for error variable in callback<commit_after>#!/usr/bin/env node

/**
 * @fileOverview Read a csv file with cable number and change details and apply them to mongoDB.
 * @author Dong Liu
 */

var csv = require('csv');

var fs = require('fs');
var path = require('path');
var mongoose = require('mongoose');
var Cable = require('../model/request.js').Cable;
var MultiChange = require('../model/request.js').MultiChange;
var program = require('commander');

var inputPath;
var realPath;
var db;
var line = 0;
var changes = [];
var parser;
var properties = [];

program.version('0.0.1')
  .option('-d, --dryrun', 'dry run')
  .arguments('<source>')
  .action(function (source) {
    inputPath = source;
  });

program.parse(process.argv);

if (inputPath === undefined) {
  console.error('need the input source csv file path!');
  process.exit(1);
}

realPath = path.resolve(process.cwd(), inputPath);

if (!fs.existsSync(realPath)) {
  console.error(realPath + ' does not exist.');
  console.error('Please input a valid csv file path.');
  process.exit(1);
}

mongoose.connect('mongodb://localhost/cable_frib');
db = mongoose.connection;
db.on('error', console.error.bind(console, 'connection error:'));
db.once('open', function () {
  console.log('db connected');
});

function splitTags(s) {
  return s ? s.replace(/^(?:\s*,?)+/, '').replace(/(?:\s*,?)*$/, '').split(/\s*[,;]\s*/) : [];
}

function updateCable(change, i) {
  console.log('processing change ' + i);
  Cable.findOne({
    number: change[0]
  }).exec(function (err, cable) {
    if (err) {
      console.error(err);
    } else {
      if (!cable) {
        console.error('cannot find cable with id ' + change[0]);
        return;
      }

      var update = {};
      var updates = [];
      var conditionSatisfied = true;

      properties.forEach(function (p, index) {
        var currentValue = cable.get(p);
        switch (p) {
        case 'basic.tags':
          currentValue = currentValue ? currentValue.join() : '';
          break;
        case 'status':
          change[2 * index + 1] = parseInt(change[2 * index + 1]);
          change[2 * index + 2] = parseInt(change[2 * index + 2]);
        }

        if (change[2 * index + 1] === '_whatever_' || currentValue === change[2 * index + 1]) {
          if (change[2 * index + 2] !== currentValue) {
            if ([undefined, null, ''].indexOf(change[2 * index + 2]) !== -1 && [undefined, null, ''].indexOf(currentValue) !== -1) {
              // do nothing
            } else {
              if (p === 'basic.tags') {
                update[p] = splitTags(change[2 * index + 2]);
              } else {
                update[p] = change[2 * index + 2];
              }
              updates.push({
                property: p,
                oldValue: cable.get(p),
                newValue: update[p]
              });
            }
          }
        } else {
          console.log('cable ' + cable.number + ' ' + p + ' is ' + cable.get(p) + ', expect ' + change[2 * index + 1]);
          if (p === 'status') {
            conditionSatisfied = false;
          }
        }
      });
      var multiChange;
      if (conditionSatisfied && updates.length > 0) {
        multiChange = new MultiChange({
          cableName: cable.number,
          updates: updates,
          updatedBy: 'system',
          updatedOn: Date.now()
        });
      }
      if (multiChange) {
        update.updatedOn = Date.now();
        update.updatedBy = 'system';
        update.$inc = {
          __v: 1
        };
        if (program.dryrun) {
          console.log('cable ' + cable.number + ' will be updated with ' + JSON.stringify(update, null, 2));
        } else {
          multiChange.save(function (err1, c) {
            if (err1) {
              console.error(err1);
            } else {
              update.$push = {
                changeHistory: c._id
              };
              cable.update(update, {
                new: true
              }, function (err2) {
                if (err2) {
                  console.error(err2);
                } else {
                  console.log('cable ' + cable.number + ' was updated with ' + JSON.stringify(update, null, 2));
                }
              });
            }
          });
        }
      } else {
        console.error('no changes for cable ' + cable.number);
      }
    }
  });

}

parser = csv.parse({
  trim: true
});

parser.on('readable', function () {
  var record = parser.read();
  var i;

  while (record) {
    line += 1;
    console.log('read ' + line + ' lines ...');
    if (line === 1) {
      if (record[0] !== 'number') {
        console.log('the first column should be number');
        process.exit(1);
      }
      for (i = 1; i < record.length; i += 1) {
        if (i % 2 === 1) {
          // empty columns
          if (record[i].length === 0) {
            break;
          }
          properties.push(record[i]);
        }
      }
    } else if (record[0].length === 9) {
      changes.push(record);
    }
    record = parser.read();
  }
});

parser.on('error', function (err) {
  console.log(err.message);
});

parser.on('finish', function () {
  console.log('Finished parsing the csv file at ' + Date.now());
  console.log('Starting to apply changes.');
  changes.forEach(function (change, index) {
    updateCable(change, index);
  });
});

fs.createReadStream(realPath).pipe(parser);

// keep running until the user interrupts
process.stdin.resume();
<|endoftext|>


<commit_before>'use strict';

/**
 * A Transformer for retreiving cover-image-urls from
 * the DBC moreinfo service.
 *
 * The transformer can take a list of pids and returns
 * an object containing pids and coverurl-size-types and coverurls.
 *
 * request:
 *   { "pids": ["pid1", "pid2", .... , "pid_n" ] }
 *
 * response:
 *   {
 *     "pid1": [ "coverUrlFull": "URL", "coverUrl42": "URL", ... ],
 *     "pid2": [ ... ]
 *   }
 */

import genericTransformer from '../genericTransformer.js';
import moreInfoClient from '../services/MoreInfo/client';
import _ from 'lodash';
import {log} from '../utils.js';

/**
 * Splits a PID into: type, agencyid and localid.
 * This functionality is needed as long as moreinfo
 * can not accept pids as identifiers.
 */
function pidSplitter(pid) {
  let pid_array = pid.split(':');
  if (pid_array.length !== 2) {
    throw new Error('Illegal pid: ' + pid);
  }
  let id = {};
  id.localid = pid_array[1];
  let agency_type = pid_array[0].split('-');
  if (agency_type.length !== 2) {
    throw new Error('Illegal agency/type in pid: ' + pid);
  }
  id.agency = agency_type[0];
  id.type = agency_type[1];
  return id;
}

/**
 * Returns a String representing an identifier given a libraryCode and a localIdentifier.
 * Used for lookup in the state-object.
 */
function id2parameter(libCode, localId) {
  return libCode + ':' + localId;
}

/**
 * Retrieves a PID from a state-object, given a libraryCode and a localIdentifier.
 * The state-object must be contain key-values where the keys are constructed
 * from id2parameter with the libraryCode and localIdentifier. The values are the PIDs.
 *
 * This function is needed as long as more-info does not take PIDs as identifiers.
 */
function getPid(libCode, localId, state) {
  let stateId = id2parameter(libCode, localId);
  let pid = state[stateId];
  return pid;
}

/**
 * A const object for looking up image-sizes as returned from moreinfo.
 */
const IMAGE_SIZES = {
  detail_42: 'coverUrl42',
  detail_117: 'coverUrl117',
  detail_207: 'coverUrl207',
  detail_500: 'coverUrl500',
  thumbnail: 'coverUrlThumbnail',
  detail: 'coverUrlFull'
};

/**
 * Detects the value from requestStatus.statusEnum.
 * If the value is an error/errorcode of some kind, or if the property
 * can not be found in the response, an error will be thrown.
 */
function errorCodeInResponse(response) {
  if (!_.has(response, 'requestStatus.statusEnum')) {
    throw {
      name: 'MalformedResponse',
      message: 'Malformed Response. No requestStatus.statusEnum.',
      response: response,
      stack: new Error().stack
    };
  }
  if (response.requestStatus.statusEnum !== 'ok') {
    throw {
      name: 'ErrorResponse',
      message: 'Error returned in response.',
      response: response,
      stack: new Error().stack
    };
  }
}

/**
 * Finds the list of identifierInformation, or throws
 * an error if the property cannot be found or the length is 0.
 */
function getIdentifierInformationList(response) {
  if (!_.has(response, 'identifierInformation')) {
    throw {
      name: 'MalformedResponse',
      message: 'Malformed response. No identifierInformation.',
      response: response,
      stack: new Error().stack
    };
  }

  if (response.identifierInformation.length === 0) {
    throw {
      name: 'EmptyResponse',
      message: 'No identifiers were returned in the response.',
      response: response,
      stack: new Error().stack
    };
  }

  return response.identifierInformation;
}

/**
 * Tests whether the identifierInformation contains any cover-images.
 * Returns true if any cover-images are contained. False otherwise.
 */
function doIdentifierInformationContainsCoverImages(idInfo) {
  let res = true;
  if (!_.has(idInfo, 'identifierKnown')
    || !idInfo.identifierKnown === true
    || !_.has(idInfo, 'coverImage')
    || idInfo.coverImage.length === 0) {
    // no identifierKnown attribute. should this be the same as 'identifier not known'?
    if (_.has(idInfo, 'identifier.localIdentifier') && _.has(idInfo, 'identifier.libraryCode')) {
      let pid = id2parameter(idInfo.identifier.libraryCode, idInfo.identifier.localIdentifier);
      log.info('Could not find covers for identifier: ' + pid);
    } else { // eslint-disable-line brace-style
      log.info('Could not find covers for unknown identifier: ' + JSON.stringify(idInfo, null, 4));
    }
    res = false;
  }
  return res;
}

/**
 * Returns an object containing { "coverUrlxxx": "URL" }
 * where "coverUrlxxx is one of the values in IMAGE_SIZES
 * and "URL" is the coverImageUrl returned from moreinfo.
 */
function getImageSizeAndUrl(x) {
  let res = {};
  if (_.has(x, 'attributes.imageSize') && _.has(x, '$value')) {
    let is = IMAGE_SIZES[x.attributes.imageSize];
    res[is] = x.$value.replace('http:', '');
  }
  return res;
}

/**
 * Retrieves the cover-urls and image-size from the identifierInformation.
 * Returns the pid and a list of coverimage-urls and imageSizes according to IMAGE_SIZES.
 */
function getCoverUrlsFromIdentifierInformation(idInfo, state) {

  if (!doIdentifierInformationContainsCoverImages(idInfo)) {
    return {};
  }

  let pid = getPid(idInfo.identifier.libraryCode, idInfo.identifier.localIdentifier, state);
  let imageUrlsList = idInfo.coverImage.map(x => getImageSizeAndUrl(x));
  let imageUrls = imageUrlsList.reduce(_.extend, {});

  return {pid: pid, urls: imageUrls};
}

/**
 * Writes out the error to log, and returns an error envelope
 */
function handleError(e) {
  let errorEnvelope = {
    statusCode: 500,
    error: 'Internal server error'
  };

  try {
    log.error('ERROR: [' + e.name + '] : ' + e.message);
    log.error('Response: ' + JSON.stringify(e.response, null, 0));
    log.error(e.stack);
    log.error('******** END ERROR');
  } catch (err) { // eslint-disable-line brace-style
    // We dont care about an error here!
  }
  return errorEnvelope;
}

export function moreInfoRequest(request, context) { // eslint-disable-line no-unused-vars
  let pids = request[0].pids;
  let params = {};
  let state = {};
  params.identifier = pids.map(pid => {
    let pid_obj = pidSplitter(pid);
    let identifier = {};
    identifier.localIdentifier = pid_obj.localid;
    identifier.libraryCode = pid_obj.agency;
    state[id2parameter(identifier.libraryCode, identifier.localIdentifier)] = pid;
    return identifier;
  });

  return {transformedRequest: params, state: state};
}

export function moreInfoResponse(response, context, state) { // eslint-disable-line no-unused-vars
  return new Promise((request, resolve) => {

    // The below should probably be converted to some kind of tests:
    //
    // response.identifierInformation = [];
    // delete response.identifierInformation;
    // delete response.requestStatus.statusEnum;
    // response.identifierInformation[0].identifierKnown = false;
    // delete response.identifierInformation[0].identifier.localIdentifier;
    // delete response.identifierInformation[0].coverImage;
    // response.identifierInformation[0].coverImage = [];
    // console.log('RESP: ' + JSON.stringify(response, null, 4));

    try {
      errorCodeInResponse(response);

      let identifierInformation = getIdentifierInformationList(response);

      let data = {};
      identifierInformation.forEach((idInfo) => {
        let {pid: pid, urls: Z} = getCoverUrlsFromIdentifierInformation(idInfo, state);
        data[pid] = Z;
      });
      let envelope = {
        statusCode: 200,
        data: data
      };
      return resolve(envelope);
    } catch (e) { // eslint-disable-line brace-style
      let errorEnvelope = handleError(e);
      resolve(errorEnvelope);
    }
  });
}

export function moreInfoFunc(context) {
  let neoContext = context.libdata.config.provider.services.moreinfo;
  let client = moreInfoClient(neoContext);

  return function (request, local_context, state) { // eslint-disable-line no-unused-vars
    return {response: client.getMoreInfoResultNeo(request), state: state};
  };
}

export default function moreInfoTransformer() {

  return genericTransformer(moreInfoRequest,
                            moreInfoResponse,
                            moreInfoFunc);
}
<commit_msg>fixed trailing whitespaces<commit_after>'use strict';

/**
 * A Transformer for retreiving cover-image-urls from
 * the DBC moreinfo service.
 *
 * The transformer can take a list of pids and returns
 * an object containing pids and coverurl-size-types and coverurls.
 *
 * request:
 *   { "pids": ["pid1", "pid2", .... , "pid_n" ] }
 *
 * response:
 *   {
 *     "pid1": [ "coverUrlFull": "URL", "coverUrl42": "URL", ... ],
 *     "pid2": [ ... ]
 *   }
 */

import genericTransformer from '../genericTransformer.js';
import moreInfoClient from '../services/MoreInfo/client';
import _ from 'lodash';
import {log} from '../utils.js';

/**
 * Splits a PID into: type, agencyid and localid.
 * This functionality is needed as long as moreinfo
 * can not accept pids as identifiers.
 */
function pidSplitter(pid) {
  let pid_array = pid.split(':');
  if (pid_array.length !== 2) {
    throw new Error('Illegal pid: ' + pid);
  }
  let id = {};
  id.localid = pid_array[1];
  let agency_type = pid_array[0].split('-');
  if (agency_type.length !== 2) {
    throw new Error('Illegal agency/type in pid: ' + pid);
  }
  id.agency = agency_type[0];
  id.type = agency_type[1];
  return id;
}

/**
 * Returns a String representing an identifier given a libraryCode and a localIdentifier.
 * Used for lookup in the state-object.
 */
function id2parameter(libCode, localId) {
  return libCode + ':' + localId;
}

/**
 * Retrieves a PID from a state-object, given a libraryCode and a localIdentifier.
 * The state-object must be contain key-values where the keys are constructed
 * from id2parameter with the libraryCode and localIdentifier. The values are the PIDs.
 *
 * This function is needed as long as more-info does not take PIDs as identifiers.
 */
function getPid(libCode, localId, state) {
  let stateId = id2parameter(libCode, localId);
  let pid = state[stateId];
  return pid;
}

/**
 * A const object for looking up image-sizes as returned from moreinfo.
 */
const IMAGE_SIZES = {
  detail_42: 'coverUrl42',
  detail_117: 'coverUrl117',
  detail_207: 'coverUrl207',
  detail_500: 'coverUrl500',
  thumbnail: 'coverUrlThumbnail',
  detail: 'coverUrlFull'
};

/**
 * Detects the value from requestStatus.statusEnum.
 * If the value is an error/errorcode of some kind, or if the property
 * can not be found in the response, an error will be thrown.
 */
function errorCodeInResponse(response) {
  if (!_.has(response, 'requestStatus.statusEnum')) {
    throw {
      name: 'MalformedResponse',
      message: 'Malformed Response. No requestStatus.statusEnum.',
      response: response,
      stack: new Error().stack
    };
  }
  if (response.requestStatus.statusEnum !== 'ok') {
    throw {
      name: 'ErrorResponse',
      message: 'Error returned in response.',
      response: response,
      stack: new Error().stack
    };
  }
}

/**
 * Finds the list of identifierInformation, or throws
 * an error if the property cannot be found or the length is 0.
 */
function getIdentifierInformationList(response) {
  if (!_.has(response, 'identifierInformation')) {
    throw {
      name: 'MalformedResponse',
      message: 'Malformed response. No identifierInformation.',
      response: response,
      stack: new Error().stack
    };
  }

  if (response.identifierInformation.length === 0) {
    throw {
      name: 'EmptyResponse',
      message: 'No identifiers were returned in the response.',
      response: response,
      stack: new Error().stack
    };
  }

  return response.identifierInformation;
}

/**
 * Tests whether the identifierInformation contains any cover-images.
 * Returns true if any cover-images are contained. False otherwise.
 */
function doIdentifierInformationContainsCoverImages(idInfo) {
  let res = true;
  if (!_.has(idInfo, 'identifierKnown')
    || !idInfo.identifierKnown === true
    || !_.has(idInfo, 'coverImage')
    || idInfo.coverImage.length === 0) {
    // no identifierKnown attribute. should this be the same as 'identifier not known'?
    if (_.has(idInfo, 'identifier.localIdentifier') && _.has(idInfo, 'identifier.libraryCode')) {
      let pid = id2parameter(idInfo.identifier.libraryCode, idInfo.identifier.localIdentifier);
      log.info('Could not find covers for identifier: ' + pid);
    } else { // eslint-disable-line brace-style
      log.info('Could not find covers for unknown identifier: ' + JSON.stringify(idInfo, null, 4));
    }
    res = false;
  }
  return res;
}

/**
 * Returns an object containing { "coverUrlxxx": "URL" }
 * where "coverUrlxxx is one of the values in IMAGE_SIZES
 * and "URL" is the coverImageUrl returned from moreinfo.
 */
function getImageSizeAndUrl(x) {
  let res = {};
  if (_.has(x, 'attributes.imageSize') && _.has(x, '$value')) {
    let is = IMAGE_SIZES[x.attributes.imageSize];
    res[is] = x.$value.replace('http:', '');
  }
  return res;
}

/**
 * Retrieves the cover-urls and image-size from the identifierInformation.
 * Returns the pid and a list of coverimage-urls and imageSizes according to IMAGE_SIZES.
 */
function getCoverUrlsFromIdentifierInformation(idInfo, state) {

  if (!doIdentifierInformationContainsCoverImages(idInfo)) {
    return {};
  }

  let pid = getPid(idInfo.identifier.libraryCode, idInfo.identifier.localIdentifier, state);
  let imageUrlsList = idInfo.coverImage.map(x => getImageSizeAndUrl(x));
  let imageUrls = imageUrlsList.reduce(_.extend, {});

  return {pid: pid, urls: imageUrls};
}

/**
 * Writes out the error to log, and returns an error envelope
 */
function handleError(e) {
  let errorEnvelope = {
    statusCode: 500,
    error: 'Internal server error'
  };

  try {
    log.error('ERROR: [' + e.name + '] : ' + e.message);
    log.error('Response: ' + JSON.stringify(e.response, null, 0));
    log.error(e.stack);
    log.error('******** END ERROR');
  } catch (err) { // eslint-disable-line brace-style
    // We dont care about an error here!
  }
  return errorEnvelope;
}

export function moreInfoRequest(request, context) { // eslint-disable-line no-unused-vars
  let pids = request[0].pids;
  let params = {};
  let state = {};
  params.identifier = pids.map(pid => {
    let pid_obj = pidSplitter(pid);
    let identifier = {};
    identifier.localIdentifier = pid_obj.localid;
    identifier.libraryCode = pid_obj.agency;
    state[id2parameter(identifier.libraryCode, identifier.localIdentifier)] = pid;
    return identifier;
  });

  return {transformedRequest: params, state: state};
}

export function moreInfoResponse(response, context, state) { // eslint-disable-line no-unused-vars
  return new Promise((request, resolve) => {

    // The below should probably be converted to some kind of tests:
    //
    // response.identifierInformation = [];
    // delete response.identifierInformation;
    // delete response.requestStatus.statusEnum;
    // response.identifierInformation[0].identifierKnown = false;
    // delete response.identifierInformation[0].identifier.localIdentifier;
    // delete response.identifierInformation[0].coverImage;
    // response.identifierInformation[0].coverImage = [];
    // console.log('RESP: ' + JSON.stringify(response, null, 4));

    try {
      errorCodeInResponse(response);

      let identifierInformation = getIdentifierInformationList(response);

      let data = {};
      identifierInformation.forEach((idInfo) => {
        let {pid: pid, urls: Z} = getCoverUrlsFromIdentifierInformation(idInfo, state);
        data[pid] = Z;
      });
      let envelope = {
        statusCode: 200,
        data: data
      };
      return resolve(envelope);
    } catch (e) { // eslint-disable-line brace-style
      let errorEnvelope = handleError(e);
      resolve(errorEnvelope);
    }
  });
}

export function moreInfoFunc(context) {
  let neoContext = context.libdata.config.provider.services.moreinfo;
  let client = moreInfoClient(neoContext);

  return function (request, local_context, state) { // eslint-disable-line no-unused-vars
    return {response: client.getMoreInfoResultNeo(request), state: state};
  };
}

export default function moreInfoTransformer() {

  return genericTransformer(moreInfoRequest,
                            moreInfoResponse,
                            moreInfoFunc);
}
<|endoftext|>


<commit_before>var sendPage;
$(function() {
  sendPage = function() {
    function ready() {
      callback(false);
      initialize();
      toggle();
      $("#send [name^=transaction_type]").on("change", toggle);
      $("#send [data-toggle=tab]").on("shown.bs.tab", toggle);
    }
    function init(options) {
      return options ? 2 == options.at && ("" === $("#send-balance .pay_to").val() && ($("#send-balance .pay_to").val(options.address).change(), $("#send-balance .pay_to").data("address", options.address))) : $("#send-balance .pay_to").val($("#send-balance .pay_to").data("address")).change(), true;
    }
    function callback(active) {
      if (void 0 === active) {
        active = $(".show-coin-control .btn-cons").hasClass("active");
      }
      $("#coincontrol").toggle(active);
    }
    function onSuccess() {
      if ($("#coincontrol").is(":visible")) {
        var r20 = 0;
        var errorClass = 0;
        for (;errorClass < recipients;errorClass++) {
          r20 += unit.parse($("#amount" + errorClass).val());
        }
        bridge.updateCoinControlAmount(r20);
      }
    }
    function color(source, type, data, name, to, text, el, key) {
      if ($("#coincontrol").is(":visible")) {
        $("#coincontrol_auto").toggle(0 === source);
        $("#coincontrol_labels").toggle(source > 0);
        if (source > 0) {
          $("#coincontrol_quantity").text(source);
          $("#coincontrol_amount").text(unit.format(type));
          $("#coincontrol_fee").text(unit.format(data));
          $("#coincontrol_afterfee").text(unit.format(name));
          $("#coincontrol_bytes").text("~" + to).css("color", to > 1E4 ? "red" : null);
          $("#coincontrol_priority").text(text).css("color", 0 == text.indexOf("low") ? "red" : null);
          $("#coincontrol_low").text(el).toggle(key).css("color", "yes" == el ? "red" : null);
          $("#coincontrol_change").text(unit.format(key)).toggle(key);
          $("label[for='coincontrol_low'],label[for='coincontrol_change']").toggle(key);
        } else {
          $("#coincontrol_quantity").text("");
          $("#coincontrol_amount").text("");
          $("#coincontrol_fee").text("");
          $("#coincontrol_afterfee").text("");
          $("#coincontrol_bytes").text("");
          $("#coincontrol_priority").text("");
          $("#coincontrol_low").text("");
          $("#coincontrol_change").text("");
        }
      }
    }
    function parent() {
      return $("div.recipient").length;
    }
    function initialize() {
      $("#recipients").append(((0 == parent() ? "" : "
") + s.replace(/recipient-template/g, "recipient[count]")).replace(/\[count\]/g, ++num));
      $("#recipient" + num.toString() + " [data-title]").tooltip();
      $("#amount" + num.toString()).on("keydown", unit.keydown).on("paste", unit.paste);
      bridge.userAction(["clearRecipients"]);
    }
    function draw(time, value, v, hour) {
      reset();
      $("#recipient" + num.toString() + " .pay_to").val(time).change();
      $("#recipient" + num.toString() + " .pay_to_label").val(value).change();
      $("#recipient" + num.toString() + " .amount").val(hour).change();
      $("#recipient" + num.toString() + " .narration").val(v).change();
      $("[href=#send]").click();
    }
    function reset() {
      $("#recipients").html("");
      $("#send-balance .amount").val("0").change();
      initialize();
      init();
    }
    function setup(element) {
      if (parent() <= 1) {
        reset();
      } else {
        element = $(element);
        if (0 == element.next("hr").remove().length) {
          element.prev("hr").remove();
        }
        element.remove();
        $("#tooltip").remove();
      }
    }
      function resetGlobalVariables() {
          validateAddressResultBool = undefined;
          sendCoinsResultBool = undefined;
          addRecipientResultBool = undefined;
      }

      function sendCoinsClicked() {
          resetGlobalVariables();
          update();
      }

    function update(sendCoinsResult, validateAddressResult, addRecipientResult) {
      function check() {
        var context = $(this).find(".pay_to");
        var jElm = $(this).find(".amount");
          if (typeof validateAddressResult === 'undefined' && typeof addRecipientResult === 'undefined') {
              bridge.validateAddress(context.val());
              return
          }

          if (validateAddressResult !== 'undefined') {
              if (validateAddressResult === false) {
                  resetGlobalVariables();
              }
          }

          if (validateAddressResult && typeof addRecipientResult === 'undefined') {
              bridge.addRecipient(context.val(), $(this).find(".pay_to_label").val(), $(this).find(".narration").val(), unit.parse(jElm.val(), $(this).find(".unit").val()), datas, $("#ring_size").val());
              return
          }

          if (typeof validateAddressResult === 'undefined' || typeof addRecipientResult === 'undefined') {
              return
          }

        if (tag = tag && invalid(context, validateAddressResult), 0 != unit.parse(jElm.val()) || (invalid(jElm) || (tag = false)), !tag || !addRecipientResult) {
          return false;
        }
      }
      var datas = load();
      var tag = true;
      if (typeof validateAddressResult === 'undefined') {
        bridge.userAction(["clearRecipients"]);
      }
      if ($("#send-balance").is(":visible")) {
        $("#send-balance").each(check);
      } else {
        $("div.recipient").each(check);
      }
      if (tag) {
          console.log(validateAddressResult, addRecipientResult, sendCoinsResult);
          if (typeof validateAddressResult === 'undefined' || typeof addRecipientResult === 'undefined') {
              //wait for the results of these two to come back from C++ then to move forward to send coins
              return;
          }

          if (typeof validateAddressResult !== 'undefined' && typeof addRecipientResult !== 'undefined' && typeof sendCoinsResult === 'undefined') {
              bridge.sendCoins($("#coincontrol").is(":visible"), $("#change_address").val())
              return;
          }

          if (typeof sendCoinsResult !== 'undefined') {
              resetGlobalVariables();
          }

        if (sendCoinsResult) {
          reset();
        }
      }
    }
    function toggle(e) {
      var toggle = $("#send-main").is(":visible");
      var OPEN = $("[name=transaction_type_from]:checked").val();
        console.log('OPEN');
        console.log(OPEN)
      if (e) {
        if (e.target !== $("input#to_account_public")[0]) {
          if (e.target !== $("input#to_account_private")[0]) {
            $("input[name=transaction_type_to][value=" + (toggle ? OPEN : "public" === OPEN ? "private" : "public") + "]").prop("checked", true);
          }
        }
      }
      var a = $("[name=transaction_type_to  ]:checked").val();
      var ok = load();
      $("#spend_spec").toggle("public" === OPEN);
      $("#spend_spectre").toggle("private" === OPEN);
      $("#to_spec").toggle("public" === a);
      $("#to_spectre").toggle("private" === a);
      $("#to_balance").toggle(!toggle);
      $(".show-coin-control").toggle(ok < 1);
      sendPage.toggleCoinControl(ok < 0);
      var active = $(".show-advanced-controls .btn-cons").hasClass("active");
      $(".advanced_controls").toggle(active);
      $("#tx_ringsize,#suggest_ring_size").toggle((!bridge.info.options || 1 != bridge.info.options.AutoRingSize) && (ok > 1 && active));
      $("#add_recipient").toggle($("#send-main").is(":visible") && active);

      if ("private" === OPEN) {
        $("#tx_ringsize").show();
      } else {
        $("#tx_ringsize").hide();
      }

      if (!active) {
        if (!toggle) {
          init();
        }
      }
    }
    function load() {
      var arrayLike = "public" === $("[name=transaction_type_from]:checked").val();
      var value = "public" === $("[name=transaction_type_to  ]:checked").val();
      return arrayLike ? +!value : 2 + value;
    }
    var s = $("#recipient-template")[0].outerHTML;
    var num = 0;
    return $("#recipient-template").remove(), {
      init: ready,
      initSendBalance: init,
      toggleCoinControl: callback,
      addRecipient: initialize,
      addRecipientDetail: draw,
      clearRecipients: reset,
      removeRecipient: setup,
      sendCoins: sendCoinsClicked,
      update: update,
      updateCoinControl: onSuccess,
      updateCoinControlInfo: color,
      changeTransactionType: toggle
    };
  }();
  sendPage.init();
});
<commit_msg>Fix if narration is undefined (private<>public transfer), addRecipient was never called on QT bridge (QT 5.9.6)<commit_after>var sendPage;
$(function() {
  sendPage = function() {
    function ready() {
      callback(false);
      initialize();
      toggle();
      $("#send [name^=transaction_type]").on("change", toggle);
      $("#send [data-toggle=tab]").on("shown.bs.tab", toggle);
    }
    function init(options) {
      return options ? 2 == options.at && ("" === $("#send-balance .pay_to").val() && ($("#send-balance .pay_to").val(options.address).change(), $("#send-balance .pay_to").data("address", options.address))) : $("#send-balance .pay_to").val($("#send-balance .pay_to").data("address")).change(), true;
    }
    function callback(active) {
      if (void 0 === active) {
        active = $(".show-coin-control .btn-cons").hasClass("active");
      }
      $("#coincontrol").toggle(active);
    }
    function onSuccess() {
      if ($("#coincontrol").is(":visible")) {
        var r20 = 0;
        var errorClass = 0;
        for (;errorClass < recipients;errorClass++) {
          r20 += unit.parse($("#amount" + errorClass).val());
        }
        bridge.updateCoinControlAmount(r20);
      }
    }
    function color(source, type, data, name, to, text, el, key) {
      if ($("#coincontrol").is(":visible")) {
        $("#coincontrol_auto").toggle(0 === source);
        $("#coincontrol_labels").toggle(source > 0);
        if (source > 0) {
          $("#coincontrol_quantity").text(source);
          $("#coincontrol_amount").text(unit.format(type));
          $("#coincontrol_fee").text(unit.format(data));
          $("#coincontrol_afterfee").text(unit.format(name));
          $("#coincontrol_bytes").text("~" + to).css("color", to > 1E4 ? "red" : null);
          $("#coincontrol_priority").text(text).css("color", 0 == text.indexOf("low") ? "red" : null);
          $("#coincontrol_low").text(el).toggle(key).css("color", "yes" == el ? "red" : null);
          $("#coincontrol_change").text(unit.format(key)).toggle(key);
          $("label[for='coincontrol_low'],label[for='coincontrol_change']").toggle(key);
        } else {
          $("#coincontrol_quantity").text("");
          $("#coincontrol_amount").text("");
          $("#coincontrol_fee").text("");
          $("#coincontrol_afterfee").text("");
          $("#coincontrol_bytes").text("");
          $("#coincontrol_priority").text("");
          $("#coincontrol_low").text("");
          $("#coincontrol_change").text("");
        }
      }
    }
    function parent() {
      return $("div.recipient").length;
    }
    function initialize() {
      $("#recipients").append(((0 == parent() ? "" : "
") + s.replace(/recipient-template/g, "recipient[count]")).replace(/\[count\]/g, ++num));
      $("#recipient" + num.toString() + " [data-title]").tooltip();
      $("#amount" + num.toString()).on("keydown", unit.keydown).on("paste", unit.paste);
      bridge.userAction(["clearRecipients"]);
    }
    function draw(time, value, v, hour) {
      reset();
      $("#recipient" + num.toString() + " .pay_to").val(time).change();
      $("#recipient" + num.toString() + " .pay_to_label").val(value).change();
      $("#recipient" + num.toString() + " .amount").val(hour).change();
      $("#recipient" + num.toString() + " .narration").val(v).change();
      $("[href=#send]").click();
    }
    function reset() {
      $("#recipients").html("");
      $("#send-balance .amount").val("0").change();
      initialize();
      init();
    }
    function setup(element) {
      if (parent() <= 1) {
        reset();
      } else {
        element = $(element);
        if (0 == element.next("hr").remove().length) {
          element.prev("hr").remove();
        }
        element.remove();
        $("#tooltip").remove();
      }
    }
      function resetGlobalVariables() {
          validateAddressResultBool = undefined;
          sendCoinsResultBool = undefined;
          addRecipientResultBool = undefined;
      }

      function sendCoinsClicked() {
          resetGlobalVariables();
          update();
      }

    function update(sendCoinsResult, validateAddressResult, addRecipientResult) {
      function check() {
        var context = $(this).find(".pay_to");
        var jElm = $(this).find(".amount");
          if (typeof validateAddressResult === 'undefined' && typeof addRecipientResult === 'undefined') {
              bridge.validateAddress(context.val());
              return
          }

          if (validateAddressResult !== 'undefined') {
              if (validateAddressResult === false) {
                  resetGlobalVariables();
              }
          }

          if (validateAddressResult && typeof addRecipientResult === 'undefined') {
              var narration = $(this).find(".narration").val();
              // Fix if narration is undefined, addRecipient was never called on QT bridge (QT 5.9.6)
              if (typeof narration === 'undefined') {
                  narration = "";
              }
              bridge.addRecipient(context.val(), $(this).find(".pay_to_label").val(), narration, unit.parse(jElm.val(), $(this).find(".unit").val()), datas, $("#ring_size").val());
              return
          }

          if (typeof validateAddressResult === 'undefined' || typeof addRecipientResult === 'undefined') {
              return
          }

        if (tag = tag && invalid(context, validateAddressResult), 0 != unit.parse(jElm.val()) || (invalid(jElm) || (tag = false)), !tag || !addRecipientResult) {
          return false;
        }
      }
      var datas = load();
      var tag = true;
      if (typeof validateAddressResult === 'undefined') {
        bridge.userAction(["clearRecipients"]);
      }
      if ($("#send-balance").is(":visible")) {
        $("#send-balance").each(check);
      } else {
        $("div.recipient").each(check);
      }
      if (tag) {
          console.log(validateAddressResult, addRecipientResult, sendCoinsResult);
          if (typeof validateAddressResult === 'undefined' || typeof addRecipientResult === 'undefined') {
              //wait for the results of these two to come back from C++ then to move forward to send coins
              return;
          }

          if (typeof validateAddressResult !== 'undefined' && typeof addRecipientResult !== 'undefined' && typeof sendCoinsResult === 'undefined') {
              bridge.sendCoins($("#coincontrol").is(":visible"), $("#change_address").val())
              return;
          }

          if (typeof sendCoinsResult !== 'undefined') {
              resetGlobalVariables();
          }

        if (sendCoinsResult) {
          reset();
        }
      }
    }
    function toggle(e) {
      var toggle = $("#send-main").is(":visible");
      var OPEN = $("[name=transaction_type_from]:checked").val();
        console.log('OPEN');
        console.log(OPEN)
      if (e) {
        if (e.target !== $("input#to_account_public")[0]) {
          if (e.target !== $("input#to_account_private")[0]) {
            $("input[name=transaction_type_to][value=" + (toggle ? OPEN : "public" === OPEN ? "private" : "public") + "]").prop("checked", true);
          }
        }
      }
      var a = $("[name=transaction_type_to  ]:checked").val();
      var ok = load();
      $("#spend_spec").toggle("public" === OPEN);
      $("#spend_spectre").toggle("private" === OPEN);
      $("#to_spec").toggle("public" === a);
      $("#to_spectre").toggle("private" === a);
      $("#to_balance").toggle(!toggle);
      $(".show-coin-control").toggle(ok < 1);
      sendPage.toggleCoinControl(ok < 0);
      var active = $(".show-advanced-controls .btn-cons").hasClass("active");
      $(".advanced_controls").toggle(active);
      $("#tx_ringsize,#suggest_ring_size").toggle((!bridge.info.options || 1 != bridge.info.options.AutoRingSize) && (ok > 1 && active));
      $("#add_recipient").toggle($("#send-main").is(":visible") && active);

      if ("private" === OPEN) {
        $("#tx_ringsize").show();
      } else {
        $("#tx_ringsize").hide();
      }

      if (!active) {
        if (!toggle) {
          init();
        }
      }
    }
    function load() {
      var arrayLike = "public" === $("[name=transaction_type_from]:checked").val();
      var value = "public" === $("[name=transaction_type_to  ]:checked").val();
      return arrayLike ? +!value : 2 + value;
    }
    var s = $("#recipient-template")[0].outerHTML;
    var num = 0;
    return $("#recipient-template").remove(), {
      init: ready,
      initSendBalance: init,
      toggleCoinControl: callback,
      addRecipient: initialize,
      addRecipientDetail: draw,
      clearRecipients: reset,
      removeRecipient: setup,
      sendCoins: sendCoinsClicked,
      update: update,
      updateCoinControl: onSuccess,
      updateCoinControlInfo: color,
      changeTransactionType: toggle
    };
  }();
  sendPage.init();
});
<|endoftext|>


<commit_before>import Request from 'request'
import Api from './Api'

const BrowserWindow = window.require('electron').remote.BrowserWindow
const loginUrl = 'https://www.facebook.com/v2.6/dialog/oauth?redirect_uri=fb464891386855067%3A%2F%2Fauthorize%2F&state=%7B%22challenge%22%3A%22q1WMwhvSfbWHvd8xz5PT6lk6eoA%253D%22%2C%22com.facebook.sdk_client_state%22%3Atrue%2C%223_method%22%3A%22sfvc_auth%22%7D&scope=user_birthday%2Cuser_photos%2Cuser_education_history%2Cemail%2Cuser_relationship_details%2Cuser_friends%2Cuser_work_history%2Cuser_likes&response_type=token%2Csigned_request&default_audience=friends&return_scopes=true&auth_type=rerequest&client_id=464891386855067&ret=login&sdk=ios'

let fbAuthData = {}
let callback

var tinderLogin = function () {
  Api.authorize(function (error, response) {
    callback(error, response)
    if (error) { return console.log(error) }
    localStorage.tinderToken = Api.getAuthToken()
    localStorage.name = response.user.full_name
    localStorage.smallPhoto = response.user.photos[0].processedFiles[3].url
    localStorage.userId = response.user._id
  })
}

var checkForToken = function (loginWindow, interval, callback) {
  var url = loginWindow.getURL()
  if (url.indexOf('https://m.facebook.com/v2.6/dialog/oauth/confirm') > -1) {
    loginWindow.webContents.executeJavaScript("unescape(document.getElementsByTagName('script')[0].innerHTML)", false,
      function (result) {
        clearInterval(interval)
        loginWindow.close()
        getFBToken(result)
      })
  }
}

var getFBToken = function (result) {
  var tokenPattern = /access_token=(.*)&/
  var expirationPattern = /expires_in=(.*)/
  var token = result.match(tokenPattern)[1]
  var expiration = parseInt(result.match(expirationPattern)[1])
  fbAuthData['access_token'] = token
  localStorage.fbToken = fbAuthData['access_token']
  var now = Date.now()
  var expiryTime = new Date(now + (1000 * expiration))
  localStorage.fbTokenExpiresAt = expiryTime
  getFBUserId(fbAuthData['access_token'])
}

var getFBUserId = function (token) {
  var graphUrl = 'https://graph.facebook.com/me?access_token=' + token
  Request.get(graphUrl, {json: true}, (error, response, body) => {
    if (error) { return console.log(error) }
    localStorage.tinderAsks = JSON.stringify(body)
    fbAuthData['fb_id'] = body.id
    localStorage.fbUserId = fbAuthData['fb_id']
    tinderLogin()
  })
}

export default class FBLoginHelper {
  static startLogin (clear, cb) {
    callback = cb
    var userAgent = 'Mozilla/5.0 (Linux U en-gb KFTHWI Build/JDQ39) AppleWebKit/535.19 (KHTML, like Gecko) Silk/3.16 Safari/535.19'
    var win = new BrowserWindow({
      width: 700,
      height: 600,
      show: false,
      webPreferences: {
        nodeIntegration: false
      }
    })

    if (clear) {
      localStorage.clear()
      win.webContents.session.clearCache(() => {})
      win.webContents.session.clearStorageData()
    }

    win.setMenu(null)
    win.loadURL(loginUrl, { 'userAgent': userAgent })
    win.show()

    var interval = setInterval(function () {
      console.log('checking...')
      if (win) checkForToken(win, interval)
    }, 500)

    win.on('closed', function () {
      win = null
    })
  }
}
<commit_msg>FB login issue fixed #1<commit_after>import Request from 'request'
import Api from './Api'

const BrowserWindow = window.require('electron').remote.BrowserWindow
const loginUrl = 'https://m.facebook.com/v2.8/dialog/oauth?auth_type=rerequest&client_id=464891386855067&default_audience=friends&display=touch&e2e=%7B%22init%22:1947351.737793%7D&fbapp_pres=0&redirect_uri=fb464891386855067://authorize/&response_type=token,signed_request&return_scopes=true&scope=user_birthday,user_photos,user_education_history,email,user_relationship_details,user_friends,user_work_history,user_likes&sdk=ios&sdk_version=4.20.2&state=%7B%22challenge%22:%22wt7ktcsTn66e3eXP5hkB6OiZHG0%253D%22,%220_auth_logger_id%22:%22A5AA6F71-41B8-4D04-9896-7E6A2FC26295%22,%22com.facebook.sdk_client_state%22:true,%223_method%22:%22sfvc_auth%22%7D&sfvc=1'

let fbAuthData = {}
let callback

var tinderLogin = function () {
  Api.authorize(function (error, response) {
    callback(error, response)
    if (error) { return console.log(error) }
    localStorage.tinderToken = Api.getAuthToken()
    localStorage.name = response.user.full_name
    localStorage.smallPhoto = response.user.photos[0].processedFiles[3].url
    localStorage.userId = response.user._id
  })
}

var checkForToken = function (loginWindow, interval, callback) {
  var url = loginWindow.getURL()
  if (url.indexOf('https://m.facebook.com/v2.8/dialog/oauth/confirm') > -1) {
    loginWindow.webContents.executeJavaScript("unescape(document.getElementsByTagName('script')[0].innerHTML)", false,
      function (result) {
        clearInterval(interval)
        loginWindow.close()
        getFBToken(result)
      })
  }
}

var getFBToken = function (result) {
  var tokenPattern = /access_token=(.*)&/
  var expirationPattern = /expires_in=(.*)/
  var token = result.match(tokenPattern)[1]
  var expiration = parseInt(result.match(expirationPattern)[1])
  fbAuthData['access_token'] = token
  localStorage.fbToken = fbAuthData['access_token']
  var now = Date.now()
  var expiryTime = new Date(now + (1000 * expiration))
  localStorage.fbTokenExpiresAt = expiryTime
  getFBUserId(fbAuthData['access_token'])
}

var getFBUserId = function (token) {
  var graphUrl = 'https://graph.facebook.com/me?access_token=' + token
  Request.get(graphUrl, {json: true}, (error, response, body) => {
    if (error) { return console.log(error) }
    localStorage.tinderAsks = JSON.stringify(body)
    fbAuthData['fb_id'] = body.id
    localStorage.fbUserId = fbAuthData['fb_id']
    tinderLogin()
  })
}

export default class FBLoginHelper {
  static startLogin (clear, cb) {
    callback = cb
    var userAgent = 'Mozilla/5.0 (Linux U en-gb KFTHWI Build/JDQ39) AppleWebKit/535.19 (KHTML, like Gecko) Silk/3.16 Safari/535.19'
    var win = new BrowserWindow({
      width: 700,
      height: 600,
      show: false,
      webPreferences: {
        nodeIntegration: false
      }
    })

    if (clear) {
      localStorage.clear()
      win.webContents.session.clearCache(() => {})
      win.webContents.session.clearStorageData()
    }

    win.setMenu(null)
    win.loadURL(loginUrl, { 'userAgent': userAgent })
    win.show()

    var interval = setInterval(function () {
      console.log('checking...')
      if (win) checkForToken(win, interval)
    }, 500)

    win.on('closed', function () {
      win = null
    })
  }
}
<|endoftext|>


<commit_before>import React from 'react'
import {Table} from 'antd'
import './HomeView.scss'
import {IndexLink, Link} from 'react-router'
class HomeView extends React.Component {
    constructor(props) {
        // props.project = [{
        //     key: '1',
        //     name: '胡彦斌',
        //     age: 32,
        //     address: '西湖区湖底公园1号'
        // }, {
        //     key: '2',
        //     name: '胡彦祖',
        //     age: 42,
        //     address: '西湖区湖底公园1号'
        // }];
        super(props);
        this.state = {
            columns: [
                {
                    title: 'ID',
                    dataIndex: 'project_id',
                    key: 'project_id',
                },
                {
                    title: '项目名称',
                    dataIndex: 'project_name',
                    key: 'project_name',
                }, {
                    title: '代理前缀',
                    dataIndex: 'proxy_url',
                    key: 'proxy_url',
                },
                {
                    title: '状态',
                    dataIndex: 'open_proxy',
                    key: 'open_proxy',
                    render: text => {
                        return text === 1 ? '开启' : '关闭'
                    }
                }
                ,
                {
                    title: '操作', dataIndex: '', render: (item) => {
                    return (

                            删除
                            <Link to={{pathname: '/project/edit/' + item.project_id}} activeClassName='route--active'>
                                    修改
                                </Link>
                            复制
                            查看接口

                    )
                }
                },
            ]
        };
        // this.state = {project: dataSource};
    }

    render() {
        return (

项目列表

                                <Link className="btn btn-info" to='/project/add' activeClassName='route--active'>
                                    添加项目
                                </Link>

        )
    }

    componentWillMount() {
        this.props.loadProjectList();
    }
}
HomeView.propTypes = {
    loadProjectList: React.PropTypes.func.isRequired,
    increment: React.PropTypes.func.isRequired
}
HomeView.defaultProps = {
    columns: [],
    // project: dataSource
    delete: function() {
        alert(2)
    },
    copy(){
    },
    show(){
    },
    edit(){
    }
}
// HomeView.propTypes = {
//     project:
// }
export default HomeView
<commit_msg>添加项目页<commit_after>import React from 'react'
import {Table} from 'antd'
import './HomeView.scss'
import {IndexLink, Link} from 'react-router'
class HomeView extends React.Component {
    constructor(props) {
        // props.project = [{
        //     key: '1',
        //     name: '胡彦斌',
        //     age: 32,
        //     address: '西湖区湖底公园1号'
        // }, {
        //     key: '2',
        //     name: '胡彦祖',
        //     age: 42,
        //     address: '西湖区湖底公园1号'
        // }];
        super(props);
        this.state = {
            columns: [
                {
                    title: 'ID',
                    dataIndex: 'project_id',
                    key: 'project_id',
                },
                {
                    title: '项目名称',
                    dataIndex: 'project_name',
                    key: 'project_name',
                }, {
                    title: '代理前缀',
                    dataIndex: 'proxy_url',
                    key: 'proxy_url',
                },
                {
                    title: '状态',
                    dataIndex: 'open_proxy',
                    key: 'open_proxy',
                    render: text => {
                        return text === 1 ? '开启' : '关闭'
                    }
                },
                {
                    title: '操作', dataIndex: '', render: (item) => {
                    return (

                            删除
                            <Link to={{pathname: '/project/edit/' + item.project_id}} activeClassName='route--active'>
                                    修改
                                </Link>
                            复制
                            查看接口

                    )
                }
                },
            ]
        };
        // this.state = {project: dataSource};
    }

    render() {
        return (

项目列表

                                <Link className="btn btn-info" to='/project/add' activeClassName='route--active'>
                                    添加项目
                                </Link>

        )
    }

    componentWillMount() {
        this.props.loadProjectList();
    }
}
HomeView.propTypes = {
    loadProjectList: React.PropTypes.func.isRequired,
    increment: React.PropTypes.func.isRequired
}
HomeView.defaultProps = {
    columns: [],
    // project: dataSource
    delete: function() {
        alert(2)
    },
    copy(){
    },
    show(){
    },
    edit(){
    }
}
// HomeView.propTypes = {
//     project:
// }
export default HomeView
<|endoftext|>


<commit_before>const auth = require('@feathersjs/authentication');
const globalHooks = require('../../../hooks');

// TODO: after hook for get that checks access.
// TODO: rethink security, due to no schoolId we can't restrict anything.

const restrictToUserOrRole = (hook) => {
	const userService = hook.app.service('users');
	return userService.find({
		query: {
			_id: hook.params.account.userId,
			$populate: 'roles',
		},
	}).then((res) => {
		let access = false;
		res.data[0].roles.forEach((role) => {
			if (role.name === 'superhero' || role.name === 'teacher' || role.name === 'administrator') {
				access = true;
			}
		});
		if (access) {
			return hook;
		}

		hook.params.query.userId = hook.params.account.userId;
		return hook;
	});
};

const addDates = (hook) => {
	if (hook.data.parentConsents && hook.data.parentConsents.length) {
		const parentConsent = hook.data.parentConsents[0];
		if ('privacyConsent' in parentConsent && !('dateOfPrivacyConsent' in parentConsent)) {
			parentConsent.dateOfPrivacyConsent = Date.now();
		}
		if ('termsOfUseConsent' in parentConsent && !('dateOftermsOfUseConsent' in parentConsent)) {
			parentConsent.dateOfTermsOfUseConsent = Date.now();
		}
	}
	if (hook.data.userConsent) {
		const { userConsent } = hook.data;
		if ('privacyConsent' in userConsent && !('dateOfPrivacyConsent' in userConsent)) {
			userConsent.dateOfPrivacyConsent = Date.now();
		}
		if ('termsOfUseConsent' in userConsent && !('dateOfTermsOfUseConsent' in userConsent)) {
			userConsent.dateOfTermsOfUseConsent = Date.now();
		}
	}
};

const mapInObjectToArray = (context) => {
	if (!context.params.query) {
		context.params.query = {};
	}
	if (!context.params.query.userId) {
		context.params.query.userId = {};
		context.params.query.userId.$in = [];
	} else if ( !Array.isArray(context.params.query.userId.$in)) {
		context.params.query.userId.$in = Object.values(context.params.query.userId.$in);
	}
	return context;
};

const checkExisting = hook => hook.app.service('consents').find({ query: { userId: hook.data.userId } })
	.then((consents) => {
		if (consents.data.length > 0) {
			// merge existing consent with submitted one, submitted data is primary and overwrites databse
			hook.data = Object.assign(consents.data[0], hook.data);
			return hook.app.service('consents').remove(consents.data[0]._id).then(() => hook);
		}
		return hook;
	}).catch(err => Promise.reject(err));

const userHasOneRole = (user, roles) => {
	if (!(roles instanceof Array)) {
		roles = [roles];
	}
	const value = user.roles.some(role => roles.includes(role.name));
	return value;
};

const accessCheck = (consent, app) => {
	let access = true;
	let requiresParentConsent = true;
	let user;
	let patchFirstlogin = false;

	return app.service('users').get((consent.userId), { query: { $populate: 'roles' } })
		// eslint-disable-next-line consistent-return
		.then((response) => {
			user = response;
			if (userHasOneRole(user, ['demoTeacher', 'demoStudent'])) {
				requiresParentConsent = false;
				patchFirstlogin = true;
				return Promise.resolve();
			}

			if (userHasOneRole(user, ['teacher', 'administrator', 'expert'])) {
				const userConsent = consent.userConsent || {};
				requiresParentConsent = false;
				if (!(userConsent.privacyConsent && userConsent.termsOfUseConsent)) {
					access = false;
					return Promise.resolve();
				}
				patchFirstlogin = true;

				return Promise.resolve();
			}

			if (!user.birthday) {
				access = false;
				requiresParentConsent = false;
				return Promise.resolve();
			}
			const { age } = user;

			if (age < 16) {
				const parentConsent = (consent.parentConsents || [])[0] || {};
				// check parent consents
				if (!(parentConsent.privacyConsent && parentConsent.termsOfUseConsent)) {
					access = false;
					return Promise.resolve();
				}
			}
			if (age > 13) {
				// check user consents
				const userConsent = consent.userConsent || {};
				if (!(userConsent.privacyConsent && userConsent.termsOfUseConsent)) {
					access = false;
					if ((user.preferences || {}).firstLogin) {
						return Promise.resolve();
					}
				}
			}
			if (age > 15) {
				requiresParentConsent = false;
			}
		})
		.then(() => {
			if (patchFirstlogin === true && !(user.preferences || {}).firstLogin) {
				const updatedPreferences = user.preferences || {};
				updatedPreferences.firstLogin = true;
				return app.service('users').patch(user._id, { preferences: updatedPreferences });
			}
			return Promise.resolve();
		})
		.then(() => {
			if (access && !(user.preferences || {}).firstLogin) {
				access = false;
			}
		})
		.then(() => {
			consent.access = access;
			consent.requiresParentConsent = requiresParentConsent;
			return consent;
		})
		.catch(err => Promise.reject(err));
};

const decorateConsent = hook => accessCheck(hook.result, hook.app)
	.then((consent) => {
		hook.result = (hook.result.constructor.name === 'model') ? hook.result.toObject() : hook.result;
		hook.result = consent;
	}).then(() => Promise.resolve(hook));

const decorateConsents = (hook) => {
	hook.result = (hook.result.constructor.name === 'model') ? hook.result.toObject() : hook.result;
	const consentPromises = (hook.result.data || [])
		.map(consent => accessCheck(consent, hook.app)
			.then(result => result));

	return Promise.all(consentPromises).then((users) => {
		hook.result.data = users;
		return Promise.resolve(hook);
	});
};

// this method is currently duplicated in AdminUsers service
const getConsentStatus = (consent) => {
	const isUserConsent = (c = {}) => {
		const uC = c.userConsent;
		return uC && uC.privacyConsent && uC.termsOfUseConsent;
	};

	const isNOTparentConsent = (c = {}) => {
		const pCs = c.parentConsents || [];
		return pCs.length === 0 || !(pCs.some(pC => pC.privacyConsent && pC.termsOfUseConsent));
	};

	if (consent.requiresParentConsent) {
		if (isNOTparentConsent(consent)) {
			return 'missing';
		}

		if (isUserConsent(consent)) {
			return 'ok';
		}
		return 'parentsAgreed';
	}

	if (isUserConsent(consent)) {
		return 'ok';
	}

	return 'missing';
};

const addConsentStatus = (hook) => {
	if (hook.result) {
		hook.result.consentStatus = getConsentStatus(hook.result);
	}
};

const addConsentsStatus = (hook) => {
	if (hook.result.data) {
		hook.result.data.forEach((consent) => {
			consent.consentStatus = getConsentStatus(consent);
		});
	}
};

exports.before = {
	all: [],
	find: [
		auth.hooks.authenticate('jwt'),
		globalHooks.ifNotLocal(restrictToUserOrRole),
		mapInObjectToArray,
	],
	get: [auth.hooks.authenticate('jwt')],
	create: [addDates, checkExisting],
	update: [auth.hooks.authenticate('jwt'), addDates],
	patch: [auth.hooks.authenticate('jwt'), addDates],
	remove: [auth.hooks.authenticate('jwt')],
};

exports.after = {
	all: [],
	find: [decorateConsents, addConsentsStatus],
	get: [decorateConsent, addConsentStatus],
	create: [],
	update: [],
	patch: [],
	remove: [],
};
<commit_msg>linter<commit_after>const auth = require('@feathersjs/authentication');
const globalHooks = require('../../../hooks');

// TODO: after hook for get that checks access.
// TODO: rethink security, due to no schoolId we can't restrict anything.

const restrictToUserOrRole = (hook) => {
	const userService = hook.app.service('users');
	return userService.find({
		query: {
			_id: hook.params.account.userId,
			$populate: 'roles',
		},
	}).then((res) => {
		let access = false;
		res.data[0].roles.forEach((role) => {
			if (role.name === 'superhero' || role.name === 'teacher' || role.name === 'administrator') {
				access = true;
			}
		});
		if (access) {
			return hook;
		}

		hook.params.query.userId = hook.params.account.userId;
		return hook;
	});
};

const addDates = (hook) => {
	if (hook.data.parentConsents && hook.data.parentConsents.length) {
		const parentConsent = hook.data.parentConsents[0];
		if ('privacyConsent' in parentConsent && !('dateOfPrivacyConsent' in parentConsent)) {
			parentConsent.dateOfPrivacyConsent = Date.now();
		}
		if ('termsOfUseConsent' in parentConsent && !('dateOftermsOfUseConsent' in parentConsent)) {
			parentConsent.dateOfTermsOfUseConsent = Date.now();
		}
	}
	if (hook.data.userConsent) {
		const { userConsent } = hook.data;
		if ('privacyConsent' in userConsent && !('dateOfPrivacyConsent' in userConsent)) {
			userConsent.dateOfPrivacyConsent = Date.now();
		}
		if ('termsOfUseConsent' in userConsent && !('dateOfTermsOfUseConsent' in userConsent)) {
			userConsent.dateOfTermsOfUseConsent = Date.now();
		}
	}
};

const mapInObjectToArray = (context) => {
	if (!context.params.query) {
		context.params.query = {};
	}
	if (!context.params.query.userId) {
		context.params.query.userId = {};
		context.params.query.userId.$in = [];
	} else if (!Array.isArray(context.params.query.userId.$in)) {
		context.params.query.userId.$in = Object.values(context.params.query.userId.$in);
	}
	return context;
};

const checkExisting = hook => hook.app.service('consents').find({ query: { userId: hook.data.userId } })
	.then((consents) => {
		if (consents.data.length > 0) {
			// merge existing consent with submitted one, submitted data is primary and overwrites databse
			hook.data = Object.assign(consents.data[0], hook.data);
			return hook.app.service('consents').remove(consents.data[0]._id).then(() => hook);
		}
		return hook;
	}).catch(err => Promise.reject(err));

const userHasOneRole = (user, roles) => {
	if (!(roles instanceof Array)) {
		roles = [roles];
	}
	const value = user.roles.some(role => roles.includes(role.name));
	return value;
};

const accessCheck = (consent, app) => {
	let access = true;
	let requiresParentConsent = true;
	let user;
	let patchFirstlogin = false;

	return app.service('users').get((consent.userId), { query: { $populate: 'roles' } })
		// eslint-disable-next-line consistent-return
		.then((response) => {
			user = response;
			if (userHasOneRole(user, ['demoTeacher', 'demoStudent'])) {
				requiresParentConsent = false;
				patchFirstlogin = true;
				return Promise.resolve();
			}

			if (userHasOneRole(user, ['teacher', 'administrator', 'expert'])) {
				const userConsent = consent.userConsent || {};
				requiresParentConsent = false;
				if (!(userConsent.privacyConsent && userConsent.termsOfUseConsent)) {
					access = false;
					return Promise.resolve();
				}
				patchFirstlogin = true;

				return Promise.resolve();
			}

			if (!user.birthday) {
				access = false;
				requiresParentConsent = false;
				return Promise.resolve();
			}
			const { age } = user;

			if (age < 16) {
				const parentConsent = (consent.parentConsents || [])[0] || {};
				// check parent consents
				if (!(parentConsent.privacyConsent && parentConsent.termsOfUseConsent)) {
					access = false;
					return Promise.resolve();
				}
			}
			if (age > 13) {
				// check user consents
				const userConsent = consent.userConsent || {};
				if (!(userConsent.privacyConsent && userConsent.termsOfUseConsent)) {
					access = false;
					if ((user.preferences || {}).firstLogin) {
						return Promise.resolve();
					}
				}
			}
			if (age > 15) {
				requiresParentConsent = false;
			}
		})
		.then(() => {
			if (patchFirstlogin === true && !(user.preferences || {}).firstLogin) {
				const updatedPreferences = user.preferences || {};
				updatedPreferences.firstLogin = true;
				return app.service('users').patch(user._id, { preferences: updatedPreferences });
			}
			return Promise.resolve();
		})
		.then(() => {
			if (access && !(user.preferences || {}).firstLogin) {
				access = false;
			}
		})
		.then(() => {
			consent.access = access;
			consent.requiresParentConsent = requiresParentConsent;
			return consent;
		})
		.catch(err => Promise.reject(err));
};

const decorateConsent = hook => accessCheck(hook.result, hook.app)
	.then((consent) => {
		hook.result = (hook.result.constructor.name === 'model') ? hook.result.toObject() : hook.result;
		hook.result = consent;
	}).then(() => Promise.resolve(hook));

const decorateConsents = (hook) => {
	hook.result = (hook.result.constructor.name === 'model') ? hook.result.toObject() : hook.result;
	const consentPromises = (hook.result.data || [])
		.map(consent => accessCheck(consent, hook.app)
			.then(result => result));

	return Promise.all(consentPromises).then((users) => {
		hook.result.data = users;
		return Promise.resolve(hook);
	});
};

// this method is currently duplicated in AdminUsers service
const getConsentStatus = (consent) => {
	const isUserConsent = (c = {}) => {
		const uC = c.userConsent;
		return uC && uC.privacyConsent && uC.termsOfUseConsent;
	};

	const isNOTparentConsent = (c = {}) => {
		const pCs = c.parentConsents || [];
		return pCs.length === 0 || !(pCs.some(pC => pC.privacyConsent && pC.termsOfUseConsent));
	};

	if (consent.requiresParentConsent) {
		if (isNOTparentConsent(consent)) {
			return 'missing';
		}

		if (isUserConsent(consent)) {
			return 'ok';
		}
		return 'parentsAgreed';
	}

	if (isUserConsent(consent)) {
		return 'ok';
	}

	return 'missing';
};

const addConsentStatus = (hook) => {
	if (hook.result) {
		hook.result.consentStatus = getConsentStatus(hook.result);
	}
};

const addConsentsStatus = (hook) => {
	if (hook.result.data) {
		hook.result.data.forEach((consent) => {
			consent.consentStatus = getConsentStatus(consent);
		});
	}
};

exports.before = {
	all: [],
	find: [
		auth.hooks.authenticate('jwt'),
		globalHooks.ifNotLocal(restrictToUserOrRole),
		mapInObjectToArray,
	],
	get: [auth.hooks.authenticate('jwt')],
	create: [addDates, checkExisting],
	update: [auth.hooks.authenticate('jwt'), addDates],
	patch: [auth.hooks.authenticate('jwt'), addDates],
	remove: [auth.hooks.authenticate('jwt')],
};

exports.after = {
	all: [],
	find: [decorateConsents, addConsentsStatus],
	get: [decorateConsent, addConsentStatus],
	create: [],
	update: [],
	patch: [],
	remove: [],
};
<|endoftext|>


<commit_before>import external from './../externalModules.js';

export const COLOR_MAP_ID = 'BrushColorMap';
const colormap = external.cornerstone.colors.getColormap(COLOR_MAP_ID);

colormap.setNumberOfColors(20);
colormap.setColor(0, [255, 255, 255, 0]);
colormap.setColor(1, [230, 25, 75, 255]);
colormap.setColor(2, [60, 180, 175, 255]);
colormap.setColor(3, [255, 225, 25, 255]);
colormap.setColor(4, [0, 130, 200, 255]);
colormap.setColor(5, [245, 130, 48, 255]);
colormap.setColor(6, [145, 30, 180, 255]);
colormap.setColor(7, [70, 240, 240, 255]);
colormap.setColor(8, [240, 50, 230, 255]);
colormap.setColor(9, [210, 245, 60, 255]);
colormap.setColor(10, [250, 190, 190, 255]);
colormap.setColor(11, [0, 128, 128, 255]);
colormap.setColor(12, [230, 190, 255, 255]);
colormap.setColor(13, [170, 110, 40, 255]);
colormap.setColor(14, [255, 250, 200, 255]);
colormap.setColor(15, [128, 0, 0, 255]);
colormap.setColor(16, [170, 255, 195, 255]);
colormap.setColor(17, [128, 128, 0, 255]);
colormap.setColor(18, [255, 215, 180, 255]);
colormap.setColor(19, [0, 0, 128, 255]);

/**
 * Sets the brush color map to something other than the default
 *
 * @param  {Array} colors An array of 4D [red, green, blue, alpha] arrays.
 */
export function setBrushColorMap (colors) {
  const colormap = external.cornerstone.colors.getColormap(COLOR_MAP_ID);

  colormap.setNumberOfColors(colors.length);

  for (let i = 0; i < colors.length; i++) {
    colormap.setColor(i, colors[i]);
  }
}
<commit_msg>Fixed issues with tests<commit_after>import external from '../externalModules.js';

const { cornerstone } = external;

export const COLOR_MAP_ID = 'BrushColorMap';
const colormap = cornerstone.colors.getColormap(COLOR_MAP_ID);

colormap.setNumberOfColors(20);
colormap.setColor(0, [255, 255, 255, 0]);
colormap.setColor(1, [230, 25, 75, 255]);
colormap.setColor(2, [60, 180, 175, 255]);
colormap.setColor(3, [255, 225, 25, 255]);
colormap.setColor(4, [0, 130, 200, 255]);
colormap.setColor(5, [245, 130, 48, 255]);
colormap.setColor(6, [145, 30, 180, 255]);
colormap.setColor(7, [70, 240, 240, 255]);
colormap.setColor(8, [240, 50, 230, 255]);
colormap.setColor(9, [210, 245, 60, 255]);
colormap.setColor(10, [250, 190, 190, 255]);
colormap.setColor(11, [0, 128, 128, 255]);
colormap.setColor(12, [230, 190, 255, 255]);
colormap.setColor(13, [170, 110, 40, 255]);
colormap.setColor(14, [255, 250, 200, 255]);
colormap.setColor(15, [128, 0, 0, 255]);
colormap.setColor(16, [170, 255, 195, 255]);
colormap.setColor(17, [128, 128, 0, 255]);
colormap.setColor(18, [255, 215, 180, 255]);
colormap.setColor(19, [0, 0, 128, 255]);

/**
 * Sets the brush color map to something other than the default
 *
 * @param  {Array} colors An array of 4D [red, green, blue, alpha] arrays.
 */
export function setBrushColorMap (colors) {
  const colormap = external.cornerstone.colors.getColormap(COLOR_MAP_ID);

  colormap.setNumberOfColors(colors.length);

  for (let i = 0; i < colors.length; i++) {
    colormap.setColor(i, colors[i]);
  }
}
<|endoftext|>


<commit_before>/**
* Copyright 2012-2020, Plotly, Inc.
* All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

'use strict';

var hovertemplateAttrs = require('../../plots/template_attributes').hovertemplateAttrs;
var texttemplateAttrs = require('../../plots/template_attributes').texttemplateAttrs;
var scatterGeoAttrs = require('../scattergeo/attributes');
var scatterAttrs = require('../scatter/attributes');
var mapboxAttrs = require('../../plots/mapbox/layout_attributes');
var baseAttrs = require('../../plots/attributes');
var colorScaleAttrs = require('../../components/colorscale/attributes');

var extendFlat = require('../../lib/extend').extendFlat;
var overrideAll = require('../../plot_api/edit_types').overrideAll;

var lineAttrs = scatterGeoAttrs.line;
var markerAttrs = scatterGeoAttrs.marker;

module.exports = overrideAll({
    lon: scatterGeoAttrs.lon,
    lat: scatterGeoAttrs.lat,

    // locations
    // locationmode

    mode: extendFlat({}, scatterAttrs.mode, {
        dflt: 'markers',
        description: [
            'Determines the drawing mode for this scatter trace.',
            'If the provided `mode` includes *text* then the `text` elements',
            'appear at the coordinates. Otherwise, the `text` elements',
            'appear on hover.'
        ].join(' ')
    }),

    text: extendFlat({}, scatterAttrs.text, {
        description: [
            'Sets text elements associated with each (lon,lat) pair',
            'If a single string, the same string appears over',
            'all the data points.',
            'If an array of string, the items are mapped in order to the',
            'this trace\'s (lon,lat) coordinates.',
            'If trace `hoverinfo` contains a *text* flag and *hovertext* is not set,',
            'these elements will be seen in the hover labels.'
        ].join(' ')
    }),
    texttemplate: texttemplateAttrs({editType: 'plot'}, {
        keys: ['lat', 'lon', 'text']
    }),
    hovertext: extendFlat({}, scatterAttrs.hovertext, {
        description: [
            'Sets hover text elements associated with each (lon,lat) pair',
            'If a single string, the same string appears over',
            'all the data points.',
            'If an array of string, the items are mapped in order to the',
            'this trace\'s (lon,lat) coordinates.',
            'To be seen, trace `hoverinfo` must contain a *text* flag.'
        ].join(' ')
    }),

    line: {
        color: lineAttrs.color,
        width: lineAttrs.width

        // TODO
        // dash: dash
    },

    connectgaps: scatterAttrs.connectgaps,

    marker: extendFlat({
        symbol: {
            valType: 'string',
            dflt: 'circle',
            role: 'style',
            arrayOk: true,
            description: [
                'Sets the marker symbol.',
                'Full list: https://www.mapbox.com/maki-icons/',
                'Note that the array `marker.color` and `marker.size`',
                'are only available for *circle* symbols.'
            ].join(' ')
        },
        angle: {
            valType: 'number',
            dflt: null,
            role: 'style',
            arrayOk: true,
            description: [
                'Sets the marker angle.'
            ].join(' ')
        },
        allowoverlap: {
            valType: 'boolean',
            dflt: false,
            role: 'style',
            arrayOk: false,
            description: [
                'Flag to allow symbols to overlap'
            ].join(' ')
        },
        opacity: markerAttrs.opacity,
        size: markerAttrs.size,
        sizeref: markerAttrs.sizeref,
        sizemin: markerAttrs.sizemin,
        sizemode: markerAttrs.sizemode
    },
        colorScaleAttrs('marker')
        // line
    ),

    fill: scatterGeoAttrs.fill,
    fillcolor: scatterAttrs.fillcolor,

    textfont: mapboxAttrs.layers.symbol.textfont,
    textposition: mapboxAttrs.layers.symbol.textposition,

    below: {
        valType: 'string',
        role: 'info',
        description: [
            'Determines if this scattermapbox trace\'s layers are to be inserted',
            'before the layer with the specified ID.',
            'By default, scattermapbox layers are inserted',
            'above all the base layers.',
            'To place the scattermapbox layers above every other layer, set `below` to *\'\'*.'
        ].join(' ')
    },

    selected: {
        marker: scatterAttrs.selected.marker
    },
    unselected: {
        marker: scatterAttrs.unselected.marker
    },

    hoverinfo: extendFlat({}, baseAttrs.hoverinfo, {
        flags: ['lon', 'lat', 'text', 'name']
    }),
    hovertemplate: hovertemplateAttrs(),
}, 'calc', 'nested');
<commit_msg>removing arrayOk from boolean attribute<commit_after>/**
* Copyright 2012-2020, Plotly, Inc.
* All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

'use strict';

var hovertemplateAttrs = require('../../plots/template_attributes').hovertemplateAttrs;
var texttemplateAttrs = require('../../plots/template_attributes').texttemplateAttrs;
var scatterGeoAttrs = require('../scattergeo/attributes');
var scatterAttrs = require('../scatter/attributes');
var mapboxAttrs = require('../../plots/mapbox/layout_attributes');
var baseAttrs = require('../../plots/attributes');
var colorScaleAttrs = require('../../components/colorscale/attributes');

var extendFlat = require('../../lib/extend').extendFlat;
var overrideAll = require('../../plot_api/edit_types').overrideAll;

var lineAttrs = scatterGeoAttrs.line;
var markerAttrs = scatterGeoAttrs.marker;

module.exports = overrideAll({
    lon: scatterGeoAttrs.lon,
    lat: scatterGeoAttrs.lat,

    // locations
    // locationmode

    mode: extendFlat({}, scatterAttrs.mode, {
        dflt: 'markers',
        description: [
            'Determines the drawing mode for this scatter trace.',
            'If the provided `mode` includes *text* then the `text` elements',
            'appear at the coordinates. Otherwise, the `text` elements',
            'appear on hover.'
        ].join(' ')
    }),

    text: extendFlat({}, scatterAttrs.text, {
        description: [
            'Sets text elements associated with each (lon,lat) pair',
            'If a single string, the same string appears over',
            'all the data points.',
            'If an array of string, the items are mapped in order to the',
            'this trace\'s (lon,lat) coordinates.',
            'If trace `hoverinfo` contains a *text* flag and *hovertext* is not set,',
            'these elements will be seen in the hover labels.'
        ].join(' ')
    }),
    texttemplate: texttemplateAttrs({editType: 'plot'}, {
        keys: ['lat', 'lon', 'text']
    }),
    hovertext: extendFlat({}, scatterAttrs.hovertext, {
        description: [
            'Sets hover text elements associated with each (lon,lat) pair',
            'If a single string, the same string appears over',
            'all the data points.',
            'If an array of string, the items are mapped in order to the',
            'this trace\'s (lon,lat) coordinates.',
            'To be seen, trace `hoverinfo` must contain a *text* flag.'
        ].join(' ')
    }),

    line: {
        color: lineAttrs.color,
        width: lineAttrs.width

        // TODO
        // dash: dash
    },

    connectgaps: scatterAttrs.connectgaps,

    marker: extendFlat({
        symbol: {
            valType: 'string',
            dflt: 'circle',
            role: 'style',
            arrayOk: true,
            description: [
                'Sets the marker symbol.',
                'Full list: https://www.mapbox.com/maki-icons/',
                'Note that the array `marker.color` and `marker.size`',
                'are only available for *circle* symbols.'
            ].join(' ')
        },
        angle: {
            valType: 'number',
            dflt: null,
            role: 'style',
            arrayOk: true,
            description: [
                'Sets the marker angle.'
            ].join(' ')
        },
        allowoverlap: {
            valType: 'boolean',
            dflt: false,
            role: 'style',
            description: [
                'Flag to allow symbols to overlap'
            ].join(' ')
        },
        opacity: markerAttrs.opacity,
        size: markerAttrs.size,
        sizeref: markerAttrs.sizeref,
        sizemin: markerAttrs.sizemin,
        sizemode: markerAttrs.sizemode
    },
        colorScaleAttrs('marker')
        // line
    ),

    fill: scatterGeoAttrs.fill,
    fillcolor: scatterAttrs.fillcolor,

    textfont: mapboxAttrs.layers.symbol.textfont,
    textposition: mapboxAttrs.layers.symbol.textposition,

    below: {
        valType: 'string',
        role: 'info',
        description: [
            'Determines if this scattermapbox trace\'s layers are to be inserted',
            'before the layer with the specified ID.',
            'By default, scattermapbox layers are inserted',
            'above all the base layers.',
            'To place the scattermapbox layers above every other layer, set `below` to *\'\'*.'
        ].join(' ')
    },

    selected: {
        marker: scatterAttrs.selected.marker
    },
    unselected: {
        marker: scatterAttrs.unselected.marker
    },

    hoverinfo: extendFlat({}, baseAttrs.hoverinfo, {
        flags: ['lon', 'lat', 'text', 'name']
    }),
    hovertemplate: hovertemplateAttrs(),
}, 'calc', 'nested');
<|endoftext|>


<commit_before>import request from 'superagent';
import Transport from './Transport';
import PromiseMaker from '../PromiseMaker';
import {CLIENT_STATES, CLIENT_EVENTS} from '../Constants';

/**
 * The long polling transport protocol
 */
export default class LongPollingTransport extends Transport {
  static supportsKeepAlive = false;

  constructor(connection) {
    super('longPolling', connection);
  }

  /**
   * Initiates th' long pollin' transport protocol fer th' current connection.
   * @returns {Promise} That resolves once th' long pollin' transport has started successfully 'n has begun pollin'.
   */

  _queryData(current) {
    return current
        .query({clientProtocol: 1.5})
        .query({connectionToken: this._connection._connectionToken})
        .query({transport: 'longPolling'})
        .query({connectionData: this._connection._data || ''});
  }

  start() {
    if(this._pollTimeoutId) {
      throw new Error('A polling session has already been initialized. Call `stop()` before attempting to `start()` again.');
    }
    this._logger.info(`*${this.constructor.name}* starting...`);
    this._connection._reconnectTries = 0;
    this._connection._reconnectTimeoutId = null;
    return this._connect()
      //.then(this._startConnection.bind(this))
      .then(() => this._client.state = CLIENT_STATES.connected)
      .then(this._poll.bind(this));
  }

  /**
   * Initiates th' long pollin' transport protocol fer th' current connection.
   * @returns {Promise} that resolves once th' long pollin' transport has started successfully 'n has begun pollin'.
   */
  _connect() {
    const url = this._client.config.url + '/connect';
    this._logger.info(`Connecting to ${url}`);
    this._current = request
      .post(url);
    this._current = this._queryData(this._current);
    return this._current
      .use(PromiseMaker)
      .promise()
      .then(this._processMessages.bind(this));
  }

  _startConnection() {
    this._current = request
      .post(this._client.config.url + '/start');
    this._current = this._queryData(this._current);
    return this._current
      .use(PromiseMaker)
      .promise();
  }

  /**
   * Initiates a poll to th' ship 'n hold th' poll open 'til th' ship be able to send new information.
   * @returns {Promise} That resolves if th' client must reconnect due to bad connection.
   * Else, th' method be called recursively after it recieves new information from th' ship.
   */
  _poll() {
    const poll = () => {
      const {messageId, groupsToken, shouldReconnect} = this._lastMessages;
      this._current = request
        .post(this._client.config.url + '/poll');
      this._current = this._queryData(this._current);
      if(groupsToken) {
        this._current = this._current
          .send({messageId, groupsToken});
      } else {
        this._current = this._current
          .send({messageId});
      }
      this._current = this._current
        .end((err, res) => {
          if(err && shouldReconnect) {
            return this._reconnect()
              .then(this._poll);
          }
          if(res) {
            if(this._client.state === CLIENT_STATES.reconnecting) {
              this._client.state = CLIENT_STATES.connected;
              this._client.emit(CLIENT_EVENTS.onReconnected);
            }
            this._processMessages(res.body);
          }
          if(!this._connection._transport._abortRequest) {
            this._poll();
          }
        });

    };
    this._currentTimeoutId = setTimeout(poll.bind(this), 250);
  }

  /**
   * Initiates th' long pollin' transport protocol fer th' current connection.
   *  @params {data} data contains th' information that th' client wishes to send to th' ship.
   *  @returns {Promise} that resolves once th' message has be sent..
   */
  _send(data) {
    return request
      .post(this._client.config.url + '/send')
      .query({connectionToken: this._connection._connectionToken})
      .query({transport: 'longPolling'})
      .send(`data=${JSON.stringify(data)}`)
      .set('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8')
      .use(PromiseMaker)
      .promise();
  }

  /**
   * Initiates a reconnection to th' ship in th' case that th' connection be too slow or be lost completely.
   *  @returns {Promise} that resolves once th' client has be successfully reconnected.
   */
  _reconnect() {
    const url = this._client.config.url + '/connect';
    this._connection.client.emit(CLIENT_EVENTS.onReconnecting);
    this._connection.client.state = CLIENT_STATES.reconnecting;
    this._logger.info(`Attempting to reconnect to ${url}`);
    this._connection._reconnectTries++;
    this._current = request
      .post(url);
    this._current = this._queryData(this._current);
    return this._current
      .use(PromiseMaker)
      .promise()
      .then(this._processMessages.bind(this));
  }

  stop() {
    clearTimeout(this._currentTimeoutId);
    this._connection._transport._abortRequest = true;
    if(this._current) {
      this._current.abort();
    }
    this._client.emit(CLIENT_EVENTS.onDisconnecting);
    this._logger.info(`Disconnecting from ${this._client.config.url}.`);
    this._client.state = CLIENT_STATES.disconnected;
    this._client.emit(CLIENT_EVENTS.onDisconnected);
    this._logger.info('Successfully disconnected.');
  }
}
<commit_msg>Began implementing reconnection timeout for longpolling. Tests pass. Addition towards issue #7<commit_after>import request from 'superagent';
import Transport from './Transport';
import PromiseMaker from '../PromiseMaker';
import {CLIENT_STATES, CLIENT_EVENTS} from '../Constants';

/**
 * The long polling transport protocol
 */
export default class LongPollingTransport extends Transport {
  static supportsKeepAlive = false;

  constructor(connection) {
    super('longPolling', connection);
    this._maxReconnectedTimeout = 3600000;
  }

  /**
   * Initiates th' long pollin' transport protocol fer th' current connection.
   * @returns {Promise} That resolves once th' long pollin' transport has started successfully 'n has begun pollin'.
   */

  _queryData(current) {
    return current
        .query({clientProtocol: 1.5})
        .query({connectionToken: this._connection._connectionToken})
        .query({transport: 'longPolling'})
        .query({connectionData: this._connection._data || ''});
  }

  start() {
    if(this._pollTimeoutId) {
      throw new Error('A polling session has already been initialized. Call `stop()` before attempting to `start()` again.');
    }
    this._logger.info(`*${this.constructor.name}* starting...`);
    return this._connect()
      //.then(this._startConnection.bind(this))
      .then(() => {
        this._client.state = CLIENT_STATES.connected;
        this._reconnectTries = 0;
        this._reconnectTimeoutId = null;
      })
      .then(this._poll.bind(this));
  }

  /**
   * Initiates th' long pollin' transport protocol fer th' current connection.
   * @returns {Promise} that resolves once th' long pollin' transport has started successfully 'n has begun pollin'.
   */
  _connect() {
    const url = this._client.config.url + '/connect';
    this._logger.info(`Connecting to ${url}`);
    this._current = request
      .post(url);
    this._current = this._queryData(this._current);
    return this._current
      .use(PromiseMaker)
      .promise()
      .then(this._processMessages.bind(this));
  }

  _startConnection() {
    this._current = request
      .post(this._client.config.url + '/start');
    this._current = this._queryData(this._current);
    return this._current
      .use(PromiseMaker)
      .promise();
  }

  /**
   * Initiates a poll to th' ship 'n hold th' poll open 'til th' ship be able to send new information.
   * @returns {Promise} That resolves if th' client must reconnect due to bad connection.
   * Else, th' method be called recursively after it recieves new information from th' ship.
   */
  _poll() {
    const poll = () => {
      const {messageId, groupsToken, shouldReconnect} = this._lastMessages;
      this._current = request
        .post(this._client.config.url + '/poll');
      this._current = this._queryData(this._current);
      if(groupsToken) {
        this._current = this._current
          .send({messageId, groupsToken});
      } else {
        this._current = this._current
          .send({messageId});
      }
      this._current = this._current
        .end((err, res) => {
          if(err && shouldReconnect) {
            return this._reconnect()
            //return setTimeout(_reconnect(), Math.min(1000 * (Math.pow(2, this._reconnectTries) - 1), this._maxReconnectedTimeout))
              .then(this._poll);
          }
          if(res) {
            if(this._client.state === CLIENT_STATES.reconnecting) {
              this._client.state = CLIENT_STATES.connected;
              this._client.emit(CLIENT_EVENTS.onReconnected);
              this._reconnectTries = 0;
            }
            this._processMessages(res.body);
          }
          if(!this._connection._transport._abortRequest) {
            this._poll();
          }
        });

    };
    this._currentTimeoutId = setTimeout(poll.bind(this), 250);
  }

  /**
   * Initiates th' long pollin' transport protocol fer th' current connection.
   *  @params {data} data contains th' information that th' client wishes to send to th' ship.
   *  @returns {Promise} that resolves once th' message has be sent..
   */
  _send(data) {
    return request
      .post(this._client.config.url + '/send')
      .query({connectionToken: this._connection._connectionToken})
      .query({transport: 'longPolling'})
      .send(`data=${JSON.stringify(data)}`)
      .set('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8')
      .use(PromiseMaker)
      .promise();
  }

  /**
   * Initiates a reconnection to th' ship in th' case that th' connection be too slow or be lost completely.
   *  @returns {Promise} that resolves once th' client has be successfully reconnected.
   */
  _reconnect() {
    const url = this._client.config.url + '/connect';
    this._connection.client.emit(CLIENT_EVENTS.onReconnecting);
    this._connection.client.state = CLIENT_STATES.reconnecting;
    this._logger.info(`Attempting to reconnect to ${url}`);
    this._reconnectTries++;
    this._current = request
      .post(url);
    this._current = this._queryData(this._current);
    return this._current
      .use(PromiseMaker)
      .promise()
      .then(this._processMessages.bind(this));
  }

  stop() {
    clearTimeout(this._currentTimeoutId);
    clearTimeout(this._reconnectTimeoutId);
    this._connection._transport._abortRequest = true;
    if(this._current) {
      this._current.abort();
    }
    this._client.emit(CLIENT_EVENTS.onDisconnecting);
    this._logger.info(`Disconnecting from ${this._client.config.url}.`);
    this._client.state = CLIENT_STATES.disconnected;
    this._client.emit(CLIENT_EVENTS.onDisconnected);
    this._logger.info('Successfully disconnected.');
  }
}
<|endoftext|>