<commit_before>const slapp = require('./slapp.js').get();
const HashMap = require('hashmap');
const request = require('request');
const fs = require('fs');
var kv = require('beepboop-persist')();

var github = require('./github.js')
function _(obj){
  var str = JSON.stringify(obj, null, 4);
  console.log(str);
}
var buffer =[];
// Archiving feature state
var isArchiving = false;

/**
 * This function that handles the module behaviour when the server is about to restart
 */
function handle_restart(){
  keys = msgMap.keys();
  keys.forEach(function(key){
    var array = msgMap.get(key);
    if(array.length)
      archive_push(key);
  })
}
/**
 * This function receives a message and store it in a hashmap that will be pushed to the github archive
 * @param {object} msg the message sent by slapp that is meant to be archived
 */
function receive(msg){
  if(isArchiving){
    slapp.client.channels.info({token:msg.meta.bot_token,channel:msg.body.event.channel}, (err, resultChannel) => {
      slapp.client.users.info({token:msg.meta.bot_token,user:msg.body.event.user}, (uerr, resultUser) => {
        var timeStamp = new Date(msg.body.event.ts * 1000)
        var obj = {user:resultUser.user.name,
                    ts:timeStamp,
                    text:msg.body.event.text,
                    channel:resultChannel.channel.name};
        archive_push(obj);
      });
    });
  }
}
// Sets the handler for the slash command
slapp.command('/archivetogit','(.*)', (msg, text, value)  => {
  slapp.client.users.info({token:msg.meta.bot_token,user:msg.body.user_id}, (err, data) => {
    if( data.user.is_admin){
      if(!text)
        msg.respond("Options for /archivetogit: \n" +
                    "\`start\` starts the archiving to git. (Github token must be initialized first using /github)\n" +
                    "\`stop \` stops the archiving to git.\n" );
      else if(text == 'start')
        archive_start(msg);
      else if(text == 'stop')
        archive_stop(msg);
      else {
        msg.respond("Please use /archivetogit to print the available options.");
      }
    }
    else {
      msg.respond("Sorry, you're not an admin.");
    }
  })
})

function start(){
  isArchiving=true;
}
/**
 * This function starts the message archiving if a github token is specified
 * @param {object} msg the message received from slapp following the user command
 */
function archive_start(msg){
  if(github.getToken()!=''){
    if(!isArchiving){
  		isArchiving=true;
  	msg.respond("Archiving started.");
  	}
  	else {
  		msg.respond("Archiving is already in progress.");
  	}
  }else{
    msg.respond("Please set the github token first.");
  }
}
/**
 * This function stops the message archiving
 * @param {object} msg the message received from slapp following the user command
 */
function archive_stop(msg){
  if(isArchiving){
		isArchiving=false;
		msg.respond("Archiving stopped.");
	}
	else {
		msg.respond("Archiving is already stoped.");
	}
}
/**
 * This function pushes the message from the buffer to github
 */
function archive_push(obj){
  _('ARCHIVE PUSH buffer:');
  _(buffer);
  var channelPageName = obj.channel + '.md';
  github.get().repos.getContent({
   owner:'NeuroTechX',
   repo:'ntx_slack_archive',
   path:''},function(err,result){
    var found = false;
    for (var i = 0; i < result.length && !found; i++) {
      if (result[i].name === channelPageName) {
        found = true;
      }
    }
    if(found)
      editPage(obj);
    else {
      createPage(obj);
    }
  });
}
/**
 * This function edits the github page specified by pageName adding values to it
 * @param {string} obj the data to push
 */
// function editPage(obj){
//   var filePath = "https://raw.githubusercontent.com/NeuroTechX/ntx_slack_archive/master/"+obj.channel+'.md';
//   var propertiesObject = {access_token:github.getToken()};
// 	request.get({url:filePath, qs:propertiesObject}, function (fileerror, fileresponse, fileBody) {
//   	if (!fileerror && fileresponse.statusCode == 200) {
//
//       var quotedText = obj.text.replace(/([\n\r])/g, '\n\n> $1');
//       fileBody+= ""+formatDate(obj.ts)+"\n\n **"+ obj.user +"**" + " :\n\n >" + quotedText + "\n\n";
//
// 			//fs.writeFile("slack-links.md", fileBody, {encoding: 'base64'}, function(err){console.log("error encoding the file to b64")});
//       var content = Buffer.from(fileBody, 'ascii');
//       var b64content = content.toString('base64');
// 			var blobPath = "https://api.github.com/repos/NeuroTechX/ntx_slack_archive/contents/"+obj.channel+'.md';
//       var options = {
//         url: blobPath,
//         headers: {
//           'User-Agent': 'Edubot-GitHub-App'
//         },
//         qs:propertiesObject
//       };
// 			request.get(options, function (bloberror, blobresponse, blobBody) {
// 	    	if (!bloberror && blobresponse.statusCode == 200) {
//           var shaStr = JSON.parse(blobBody).sha;
//           //("Sha str")
// 					github.get().repos.updateFile({
// 						owner:"NeuroTechX",
// 						repo:"ntx_slack_archive",
// 						path:obj.channel+'.md',
// 						message:"Edubot Push",
// 						content:b64content,
// 						sha: shaStr
// 					}, function(err, res) {
//             buffer = [];
//           });
//         }
// 			});
//   	}
// 	});
// }
function editPage(obj){
  github.get().repos.getContent({
      owner:"NeuroTechX",
      repo:"ntx_slack_archive",
      path:obj.channel+'.md',
    },
    function(err,res){
    	if (!err) {
        var taggedUsers = obj.text.match(/([<][@][U][A-Za-z0-9]+[>])/g);
        if(taggedUsers){
          var taggedUsersIds = taggedUsers.slice();
          for(var i=0;i<taggedUsersIds.length;i++){
            taggedUsersIds[i].replace(/(<|@|>)/g,'');
          }
          var ps = [];
          for(var i=0;i<taggedUsersIds.length;i++){
            ps.push(getUserInfoPromise(taggedUsersIds[i]));
          }
          Promise.all(ps).then(function(results){
            for(var i=0;i<taggedUsers.length;i++){
              obj.text.replace(taggedUsers[i],results[i]);
            }
          });
        }
        var quotedText = obj.text.replace(/([\n\r])/g, '\n\n> $1');
        var b64fileBody = res.content;
        var bufBody = new Buffer(b64fileBody, 'base64')
        var fileBody = bufBody.toString();
        fileBody+= ""+formatDate(obj.ts)+"\n\n **"+ obj.user +"**" + " :\n\n >" + quotedText + "\n\n";
        var content = Buffer.from(fileBody, 'ascii');
        var b64content = content.toString('base64');
        var shaStr = res.sha;
    		github.get().repos.updateFile({
    			owner:"NeuroTechX",
    			repo:"ntx_slack_archive",
    			path:obj.channel+'.md',
    			message:"Edubot Push",
    			content:b64content,
    			sha: shaStr
    		}, function(err, res) {
        });
    	}
	});
}
/**
 * This function formats the timestamp to a user friendly format
 * @param {timestamp} ts the time stamp to format
 */
function formatDate(ts){
  return ts.toLocaleDateString("en-US") + " " + ts.toLocaleTimeString(["en-US"], {hour: '2-digit', minute:'2-digit'});
}
/**
 * This function creates a github archiving page
 * @param {string} obj data to push
 */
function createPage(obj){
      var fileBody = "######"+obj.channel+"\n\n";
      var quotedText = obj.text.replace(/([\n\r])/g, '\n\n> $1');
			fileBody+= ""+formatDate(obj.ts)+"\n\n **"+ obj.user +"**" + " :\n\n >" + quotedText + "\n\n";

      var content = Buffer.from(fileBody, 'ascii');
      var b64content = content.toString('base64');

      github.get().repos.createFile({
        owner:"NeuroTechX",
        repo:"ntx_slack_archive",
        path:obj.channel+'.md',
        message:"Edubot Push",
        content:b64content
      }, function(err, res) {
      });
}
function getUserInfoPromise(uid){
  return new Promise(function(resolve, reject) {
    kv.get("bot_token",function(err,bToken){
      if(err)
        _("error while loading bot token");
      else if(!err && result){
        slapp.client.users.info({token:bToken,user:uid}, (err, data) => {
          if(err)
            reject(err);
          else
            resolve(data.user.name);
        });
      }
    });
  });
}
module.exports = {
  receive:receive,
  handle_restart:handle_restart,
  start:start
}
<commit_msg>bToken<commit_after>const slapp = require('./slapp.js').get();
const HashMap = require('hashmap');
const request = require('request');
const fs = require('fs');
var kv = require('beepboop-persist')();

var github = require('./github.js')
function _(obj){
  var str = JSON.stringify(obj, null, 4);
  console.log(str);
}
var buffer =[];
// Archiving feature state
var isArchiving = false;

/**
 * This function that handles the module behaviour when the server is about to restart
 */
function handle_restart(){
  keys = msgMap.keys();
  keys.forEach(function(key){
    var array = msgMap.get(key);
    if(array.length)
      archive_push(key);
  })
}
/**
 * This function receives a message and store it in a hashmap that will be pushed to the github archive
 * @param {object} msg the message sent by slapp that is meant to be archived
 */
function receive(msg){
  if(isArchiving){
    slapp.client.channels.info({token:msg.meta.bot_token,channel:msg.body.event.channel}, (err, resultChannel) => {
      slapp.client.users.info({token:msg.meta.bot_token,user:msg.body.event.user}, (uerr, resultUser) => {
        var timeStamp = new Date(msg.body.event.ts * 1000)
        var obj = {user:resultUser.user.name,
                    ts:timeStamp,
                    text:msg.body.event.text,
                    channel:resultChannel.channel.name};
        archive_push(obj);
      });
    });
  }
}
// Sets the handler for the slash command
slapp.command('/archivetogit','(.*)', (msg, text, value)  => {
  slapp.client.users.info({token:msg.meta.bot_token,user:msg.body.user_id}, (err, data) => {
    if( data.user.is_admin){
      if(!text)
        msg.respond("Options for /archivetogit: \n" +
                    "\`start\` starts the archiving to git. (Github token must be initialized first using /github)\n" +
                    "\`stop \` stops the archiving to git.\n" );
      else if(text == 'start')
        archive_start(msg);
      else if(text == 'stop')
        archive_stop(msg);
      else {
        msg.respond("Please use /archivetogit to print the available options.");
      }
    }
    else {
      msg.respond("Sorry, you're not an admin.");
    }
  })
})

function start(){
  isArchiving=true;
}
/**
 * This function starts the message archiving if a github token is specified
 * @param {object} msg the message received from slapp following the user command
 */
function archive_start(msg){
  if(github.getToken()!=''){
    if(!isArchiving){
  		isArchiving=true;
  	msg.respond("Archiving started.");
  	}
  	else {
  		msg.respond("Archiving is already in progress.");
  	}
  }else{
    msg.respond("Please set the github token first.");
  }
}
/**
 * This function stops the message archiving
 * @param {object} msg the message received from slapp following the user command
 */
function archive_stop(msg){
  if(isArchiving){
		isArchiving=false;
		msg.respond("Archiving stopped.");
	}
	else {
		msg.respond("Archiving is already stoped.");
	}
}
/**
 * This function pushes the message from the buffer to github
 */
function archive_push(obj){
  _('ARCHIVE PUSH buffer:');
  _(buffer);
  var channelPageName = obj.channel + '.md';
  github.get().repos.getContent({
   owner:'NeuroTechX',
   repo:'ntx_slack_archive',
   path:''},function(err,result){
    var found = false;
    for (var i = 0; i < result.length && !found; i++) {
      if (result[i].name === channelPageName) {
        found = true;
      }
    }
    if(found)
      editPage(obj);
    else {
      createPage(obj);
    }
  });
}
/**
 * This function edits the github page specified by pageName adding values to it
 * @param {string} obj the data to push
 */
// function editPage(obj){
//   var filePath = "https://raw.githubusercontent.com/NeuroTechX/ntx_slack_archive/master/"+obj.channel+'.md';
//   var propertiesObject = {access_token:github.getToken()};
// 	request.get({url:filePath, qs:propertiesObject}, function (fileerror, fileresponse, fileBody) {
//   	if (!fileerror && fileresponse.statusCode == 200) {
//
//       var quotedText = obj.text.replace(/([\n\r])/g, '\n\n> $1');
//       fileBody+= ""+formatDate(obj.ts)+"\n\n **"+ obj.user +"**" + " :\n\n >" + quotedText + "\n\n";
//
// 			//fs.writeFile("slack-links.md", fileBody, {encoding: 'base64'}, function(err){console.log("error encoding the file to b64")});
//       var content = Buffer.from(fileBody, 'ascii');
//       var b64content = content.toString('base64');
// 			var blobPath = "https://api.github.com/repos/NeuroTechX/ntx_slack_archive/contents/"+obj.channel+'.md';
//       var options = {
//         url: blobPath,
//         headers: {
//           'User-Agent': 'Edubot-GitHub-App'
//         },
//         qs:propertiesObject
//       };
// 			request.get(options, function (bloberror, blobresponse, blobBody) {
// 	    	if (!bloberror && blobresponse.statusCode == 200) {
//           var shaStr = JSON.parse(blobBody).sha;
//           //("Sha str")
// 					github.get().repos.updateFile({
// 						owner:"NeuroTechX",
// 						repo:"ntx_slack_archive",
// 						path:obj.channel+'.md',
// 						message:"Edubot Push",
// 						content:b64content,
// 						sha: shaStr
// 					}, function(err, res) {
//             buffer = [];
//           });
//         }
// 			});
//   	}
// 	});
// }
function editPage(obj){
  github.get().repos.getContent({
      owner:"NeuroTechX",
      repo:"ntx_slack_archive",
      path:obj.channel+'.md',
    },
    function(err,res){
    	if (!err) {
        var taggedUsers = obj.text.match(/([<][@][U][A-Za-z0-9]+[>])/g);
        if(taggedUsers){
          var taggedUsersIds = taggedUsers.slice();
          for(var i=0;i<taggedUsersIds.length;i++){
            taggedUsersIds[i].replace(/(<|@|>)/g,'');
          }
          var ps = [];
          for(var i=0;i<taggedUsersIds.length;i++){
            ps.push(getUserInfoPromise(taggedUsersIds[i]));
          }
          Promise.all(ps).then(function(results){
            for(var i=0;i<taggedUsers.length;i++){
              obj.text.replace(taggedUsers[i],results[i]);
            }
          });
        }
        var quotedText = obj.text.replace(/([\n\r])/g, '\n\n> $1');
        var b64fileBody = res.content;
        var bufBody = new Buffer(b64fileBody, 'base64')
        var fileBody = bufBody.toString();
        fileBody+= ""+formatDate(obj.ts)+"\n\n **"+ obj.user +"**" + " :\n\n >" + quotedText + "\n\n";
        var content = Buffer.from(fileBody, 'ascii');
        var b64content = content.toString('base64');
        var shaStr = res.sha;
    		github.get().repos.updateFile({
    			owner:"NeuroTechX",
    			repo:"ntx_slack_archive",
    			path:obj.channel+'.md',
    			message:"Edubot Push",
    			content:b64content,
    			sha: shaStr
    		}, function(err, res) {
        });
    	}
	});
}
/**
 * This function formats the timestamp to a user friendly format
 * @param {timestamp} ts the time stamp to format
 */
function formatDate(ts){
  return ts.toLocaleDateString("en-US") + " " + ts.toLocaleTimeString(["en-US"], {hour: '2-digit', minute:'2-digit'});
}
/**
 * This function creates a github archiving page
 * @param {string} obj data to push
 */
function createPage(obj){
      var fileBody = "######"+obj.channel+"\n\n";
      var quotedText = obj.text.replace(/([\n\r])/g, '\n\n> $1');
			fileBody+= ""+formatDate(obj.ts)+"\n\n **"+ obj.user +"**" + " :\n\n >" + quotedText + "\n\n";

      var content = Buffer.from(fileBody, 'ascii');
      var b64content = content.toString('base64');

      github.get().repos.createFile({
        owner:"NeuroTechX",
        repo:"ntx_slack_archive",
        path:obj.channel+'.md',
        message:"Edubot Push",
        content:b64content
      }, function(err, res) {
      });
}
function getUserInfoPromise(uid){
  return new Promise(function(resolve, reject) {
    kv.get("bot_token",function(err,bToken){
      if(err)
        _("error while loading bot token");
      else if(!err && bToken){
        slapp.client.users.info({token:bToken,user:uid}, (err, data) => {
          if(err)
            reject(err);
          else
            resolve(data.user.name);
        });
      }
    });
  });
}
module.exports = {
  receive:receive,
  handle_restart:handle_restart,
  start:start
}
<|endoftext|>


<commit_before>import EventEmitter2 from 'eventemitter2';
import * as events from './events';
import PluginError from './plugin-error';
import merge from 'merge';
import { defaults as _defaults, allowedEncodings } from './defaults';

export default class Client {
  constructor(defaults) {
    const encodingIsInvalid = () => defaults &&
      typeof defaults.encoding !== 'undefined' &&
      allowedEncodings.indexOf(defaults.encoding) === -1;

    if (encodingIsInvalid()) {
      throw new Error(`${defaults.encoding} is not an allowed encoding value.`);
    }

    this.defaults = merge.recursive(true, this._getDefaults(), defaults);

    if (this.defaults.url) {
      this.defaults.sep = this.defaults.url[this.defaults.url.length - 1] === '/' ? '' : '/';
    }

    this.eventEmitter = new EventEmitter2();
    this._plugins = [];
  }

  _getDefaults() {
    return _defaults;
  }

  _callPluginMethod(method, mutableArgIdx, earlyExit, ...args) {
    let i = 0;

    const shouldContinue = () => (earlyExit ? args[mutableArgIdx] : true);

    while (i < this._plugins.length && shouldContinue()) {
      if (this._plugins[i][method]) {
        args[mutableArgIdx] = this._plugins[i][method](...args);
      }
      i += 1;
    }

    return args[mutableArgIdx];
  }

  _callOnStarts(request) {
    return this._callPluginMethod('onStart', 0, true, request);
  }

  _callOnSuccesses(request, response) {
    return this._callPluginMethod('onSuccess', 1, false, request, response);
  }

  _callOnFails(request, response) {
    return this._callPluginMethod('onFail', 1, false, request, response);
  }

  _callOnErrors(request, response) {
    return this._callPluginMethod('onError', 1, false, request, response);
  }

  _addHelpers(helpers) {
    if (helpers) {
      Object.keys(helpers).forEach((key) => {
        this[key] = helpers[key];
      });
    }
  }

  _getRequest(path, options) {
    let fullPath = path;
    if (this.defaults && this.defaults.url) {
      fullPath = `${this.defaults.url}${this.defaults.sep}${path}`;
    }

    return new Request(fullPath, options);
  }

  fetch(path, options) {
    let request;
    let onStartError;

    if (path instanceof Request) {
      request = path;
    } else {
      try {
        request = this._callOnStarts(request);
      } catch (err) {
        request = this._getRequest(path, options);
        this.eventEmitter.emit(events.REQUEST_START, request);
        onStartError = err;
      }
    }

    let fetchPromise;
    if (request && !onStartError) {
      fetchPromise = fetch(request)
        .then(response => {
          let mutatedResponse;
          if (response.status >= 400) {
            mutatedResponse = this._callOnFails(request, response);
            this.eventEmitter.emit(events.REQUEST_FAILURE, request, mutatedResponse);
          } else {
            mutatedResponse = this._callOnSuccesses(request, response);
            this.eventEmitter.emit(events.REQUEST_SUCCESS, request, mutatedResponse);
          }

          return mutatedResponse;
        })
        .catch(err => {
          const mutatedError = this._callOnErrors(request, err);
          this.eventEmitter.emit(events.REQUEST_ERROR, request, mutatedError);
          throw mutatedError;
        });
    } else {
      const err = onStartError || new PluginError();
      fetchPromise = Promise.reject(err);
    }

    return fetchPromise;
  }

  addPlugin(plugin) {
    plugin.client = this;
    this._plugins.push(plugin);
    this._addHelpers(plugin.helpers);
    if (plugin.onAddPlugin) {
      plugin.onAddPlugin.call(this);
    }
  }

  removePlugin(name) {
    let i = 0;
    for (i; i < this._plugins.length; i++) {
      if (this._plugins[i].name === name) {
        this._plugins.splice(i, 1);
        i -= 1;
      }
    }
  }

  on(event, cb) {
    this.eventEmitter.on(event, cb);
  }

  /* ---- HELPERS ---- */

  _formAppendArrayOrObject(formObject, data, key) {
    if (Array.isArray(data)) {
      data.forEach((val) => {
        if (typeof(val) === 'object') {
          this._formAppendArrayOrObject(formObject, val, `${key}[]`);
        } else {
          formObject.append(`${key}[]`, val);
        }
      });
    } else {
      Object.keys(data).forEach(val => {
        if (typeof(data[val]) === 'object') {
          this._formAppendArrayOrObject(formObject, data[val], `${key}[${val}]`);
        } else {
          formObject.append(`${key}[${val}]`, data[val]);
        }
      });
    }
  }

  _encodeForm(body, formObject) {
    Object.keys(body).forEach((val) => {
      if (typeof(body[val]) === 'object') {
        this._formAppendArrayOrObject(formObject, body[val], `${val}`);
      } else {
        formObject.append(val, body[val]);
      }
    });

    return formObject;
  }

  _getEncodingTypeFromContentType(contentType) {
    let encodingType = false;
    if (contentType) {
      if (contentType.match(/text\/.+/i)) {
        encodingType = 'text';
      } else {
        switch (contentType) {
          case 'application/json':
            encodingType = 'json';
            break;
          case 'multipart/form-data':
            encodingType = 'form-data';
            break;
          case 'application/x-www-form-urlencoded':
            encodingType = 'x-www-form-urlencoded';
            break;
          default:
        }
      }
    }

    return encodingType;
  }

  _encode(body, contentType) {
    let _body = body;
    let _contentType = contentType;

    let encodingType = this._getEncodingTypeFromContentType(_contentType);
    encodingType = encodingType || this.defaults.encoding;

    if (_body instanceof FormData || _body instanceof URLSearchParams) {
      return { body: _body, contentType: false };
    }

    let formObject;
    switch (encodingType) {
      case 'json':
        _body = JSON.stringify(_body);
        _contentType = 'application/json';
        break;
      case 'text':
        _contentType = _contentType || 'text/plain';
        break;
      case 'form-data':
        formObject = new FormData();
        _body = this._encodeForm(_body, formObject);
        _contentType = undefined;
        break;
      case 'x-www-form-urlencoded':
        formObject = new URLSearchParams();
        _body = this._encodeForm(_body, formObject);
        _contentType = undefined;
        break;
      default:
    }

    return { body: _body, contentType: _contentType };
  }

  _buildOptionsWithBody(method, body, options) {
    let _options = { ...this.defaults[method] };
    _options = merge.recursive(true, _options, options);

    const { body: encodedBody, contentType } = this._encode(body, _options.headers['Content-Type']);
    if (contentType === false) {
      delete _options.headers['Content-Type'];
    } else {
      _options.headers['Content-Type'] = contentType;
    }

    _options.body = encodedBody;
    return _options;
  }

  get(path, body, options) {
    const _options = options || {};
    let queryString = '';

    if (body && Object.keys(body).length) {
      const urlSearchParams = new URLSearchParams();
      this._encodeForm(body, urlSearchParams);
      queryString = `?${urlSearchParams.toString()}`;
    }

    _options.method = 'GET';
    return this.fetch(path + queryString, _options);
  }

  post(path, body, options) {
    const _options = this._buildOptionsWithBody('post', body, options);
    _options.method = 'POST';
    return this.fetch(path, _options);
  }

  put(path, body, options) {
    const _options = this._buildOptionsWithBody('put', body, options);
    _options.method = 'PUT';
    return this.fetch(path, _options);
  }

  patch(path, body, options) {
    const _options = this._buildOptionsWithBody('patch', body, options);
    _options.method = 'PATCH';
    return this.fetch(path, _options);
  }

  delete(path, options) {
    const _options = options || {};
    _options.method = 'DELETE';
    return this.fetch(path, _options);
  }
}
<commit_msg>Fix fetch method<commit_after>import EventEmitter2 from 'eventemitter2';
import * as events from './events';
import PluginError from './plugin-error';
import merge from 'merge';
import { defaults as _defaults, allowedEncodings } from './defaults';

export default class Client {
  constructor(defaults) {
    const encodingIsInvalid = () => defaults &&
      typeof defaults.encoding !== 'undefined' &&
      allowedEncodings.indexOf(defaults.encoding) === -1;

    if (encodingIsInvalid()) {
      throw new Error(`${defaults.encoding} is not an allowed encoding value.`);
    }

    this.defaults = merge.recursive(true, this._getDefaults(), defaults);

    if (this.defaults.url) {
      this.defaults.sep = this.defaults.url[this.defaults.url.length - 1] === '/' ? '' : '/';
    }

    this.eventEmitter = new EventEmitter2();
    this._plugins = [];
  }

  _getDefaults() {
    return _defaults;
  }

  _callPluginMethod(method, mutableArgIdx, earlyExit, ...args) {
    let i = 0;

    const shouldContinue = () => (earlyExit ? args[mutableArgIdx] : true);

    while (i < this._plugins.length && shouldContinue()) {
      if (this._plugins[i][method]) {
        args[mutableArgIdx] = this._plugins[i][method](...args);
      }
      i += 1;
    }

    return args[mutableArgIdx];
  }

  _callOnStarts(request) {
    return this._callPluginMethod('onStart', 0, true, request);
  }

  _callOnSuccesses(request, response) {
    return this._callPluginMethod('onSuccess', 1, false, request, response);
  }

  _callOnFails(request, response) {
    return this._callPluginMethod('onFail', 1, false, request, response);
  }

  _callOnErrors(request, response) {
    return this._callPluginMethod('onError', 1, false, request, response);
  }

  _addHelpers(helpers) {
    if (helpers) {
      Object.keys(helpers).forEach((key) => {
        this[key] = helpers[key];
      });
    }
  }

  _getRequest(path, options) {
    let fullPath = path;
    if (this.defaults && this.defaults.url) {
      fullPath = `${this.defaults.url}${this.defaults.sep}${path}`;
    }

    return new Request(fullPath, options);
  }

  fetch(path, options) {
    let request;
    let onStartError;

    if (path instanceof Request) {
      request = path;
    } else {
      try {
        request = this._getRequest(path, options);
        request = this._callOnStarts(request);
        this.eventEmitter.emit(events.REQUEST_START, request);
      } catch (err) {
        onStartError = err;
      }
    }

    let fetchPromise;
    if (request && !onStartError) {
      fetchPromise = fetch(request)
        .then(response => {
          let mutatedResponse;
          if (response.status >= 400) {
            mutatedResponse = this._callOnFails(request, response);
            this.eventEmitter.emit(events.REQUEST_FAILURE, request, mutatedResponse);
          } else {
            mutatedResponse = this._callOnSuccesses(request, response);
            this.eventEmitter.emit(events.REQUEST_SUCCESS, request, mutatedResponse);
          }

          return mutatedResponse;
        })
        .catch(err => {
          const mutatedError = this._callOnErrors(request, err);
          this.eventEmitter.emit(events.REQUEST_ERROR, request, mutatedError);
          throw mutatedError;
        });
    } else {
      const err = onStartError || new PluginError();
      fetchPromise = Promise.reject(err);
    }

    return fetchPromise;
  }

  addPlugin(plugin) {
    plugin.client = this;
    this._plugins.push(plugin);
    this._addHelpers(plugin.helpers);
    if (plugin.onAddPlugin) {
      plugin.onAddPlugin.call(this);
    }
  }

  removePlugin(name) {
    let i = 0;
    for (i; i < this._plugins.length; i++) {
      if (this._plugins[i].name === name) {
        this._plugins.splice(i, 1);
        i -= 1;
      }
    }
  }

  on(event, cb) {
    this.eventEmitter.on(event, cb);
  }

  /* ---- HELPERS ---- */

  _formAppendArrayOrObject(formObject, data, key) {
    if (Array.isArray(data)) {
      data.forEach((val) => {
        if (typeof(val) === 'object') {
          this._formAppendArrayOrObject(formObject, val, `${key}[]`);
        } else {
          formObject.append(`${key}[]`, val);
        }
      });
    } else {
      Object.keys(data).forEach(val => {
        if (typeof(data[val]) === 'object') {
          this._formAppendArrayOrObject(formObject, data[val], `${key}[${val}]`);
        } else {
          formObject.append(`${key}[${val}]`, data[val]);
        }
      });
    }
  }

  _encodeForm(body, formObject) {
    Object.keys(body).forEach((val) => {
      if (typeof(body[val]) === 'object') {
        this._formAppendArrayOrObject(formObject, body[val], `${val}`);
      } else {
        formObject.append(val, body[val]);
      }
    });

    return formObject;
  }

  _getEncodingTypeFromContentType(contentType) {
    let encodingType = false;
    if (contentType) {
      if (contentType.match(/text\/.+/i)) {
        encodingType = 'text';
      } else {
        switch (contentType) {
          case 'application/json':
            encodingType = 'json';
            break;
          case 'multipart/form-data':
            encodingType = 'form-data';
            break;
          case 'application/x-www-form-urlencoded':
            encodingType = 'x-www-form-urlencoded';
            break;
          default:
        }
      }
    }

    return encodingType;
  }

  _encode(body, contentType) {
    let _body = body;
    let _contentType = contentType;

    let encodingType = this._getEncodingTypeFromContentType(_contentType);
    encodingType = encodingType || this.defaults.encoding;

    if (_body instanceof FormData || _body instanceof URLSearchParams) {
      return { body: _body, contentType: false };
    }

    let formObject;
    switch (encodingType) {
      case 'json':
        _body = JSON.stringify(_body);
        _contentType = 'application/json';
        break;
      case 'text':
        _contentType = _contentType || 'text/plain';
        break;
      case 'form-data':
        formObject = new FormData();
        _body = this._encodeForm(_body, formObject);
        _contentType = undefined;
        break;
      case 'x-www-form-urlencoded':
        formObject = new URLSearchParams();
        _body = this._encodeForm(_body, formObject);
        _contentType = undefined;
        break;
      default:
    }

    return { body: _body, contentType: _contentType };
  }

  _buildOptionsWithBody(method, body, options) {
    let _options = { ...this.defaults[method] };
    _options = merge.recursive(true, _options, options);

    const { body: encodedBody, contentType } = this._encode(body, _options.headers['Content-Type']);
    if (contentType === false) {
      delete _options.headers['Content-Type'];
    } else {
      _options.headers['Content-Type'] = contentType;
    }

    _options.body = encodedBody;
    return _options;
  }

  get(path, body, options) {
    const _options = options || {};
    let queryString = '';

    if (body && Object.keys(body).length) {
      const urlSearchParams = new URLSearchParams();
      this._encodeForm(body, urlSearchParams);
      queryString = `?${urlSearchParams.toString()}`;
    }

    _options.method = 'GET';
    return this.fetch(path + queryString, _options);
  }

  post(path, body, options) {
    const _options = this._buildOptionsWithBody('post', body, options);
    _options.method = 'POST';
    return this.fetch(path, _options);
  }

  put(path, body, options) {
    const _options = this._buildOptionsWithBody('put', body, options);
    _options.method = 'PUT';
    return this.fetch(path, _options);
  }

  patch(path, body, options) {
    const _options = this._buildOptionsWithBody('patch', body, options);
    _options.method = 'PATCH';
    return this.fetch(path, _options);
  }

  delete(path, options) {
    const _options = options || {};
    _options.method = 'DELETE';
    return this.fetch(path, _options);
  }
}
<|endoftext|>


<commit_before>import React from 'react';
import Avatar from '../avatar';
import style from './style';
import moment from 'moment';
import _ from 'lodash';

const formatTime = (value) => {
	if (!value) {
		return '';
	}
	return moment(value).format('HH:mm');
};

// TODO reuse rendering of user name from message component

const Topic = (props) => {
	let className = `topic ${style.topic}`;
	if (props.selected) className += ` ${style.topic_selected}`;

	const msg = props.last_message || props.message || {};
	const user = msg.user;
	const unread = props.unread ? `${props.unread > 10 ? '10+' : props.unread} new` : '';

	const onClick = (e) => {
		e.preventDefault();
		if (_.isFunction(props.onSelect)) {
			props.onSelect(props.thread);
		}
	};

	return (

			{user && user.avatar ? <Avatar source={user.avatar} size={props.avatarSize} name={user.name}/> : null}
			<div className={`header ${style.header}`}>
				{props.topic}
				{unread ? <span className={`unread ${style.unread}`}>{unread} : null}

			<div className={`body ${style.body}`}>{msg.body}

				{user && user.name ? {user.name} : null}
				{` at ${formatTime(props.updated_at)}`}

	);
};

const ThreadList = (props) => {
	const items = props.threads.map(t => {
		return <Topic key={t.id} thread={t} {...t} onSelect={props.onSelect}/>;
	});
	return (
		<div className={`topic_list ${style.topic_list}`}>
			{items}

	);
};

export default ThreadList;
export { ThreadList };
<commit_msg>fixed avatar rendering in thread topic component<commit_after>import React from 'react';
import Avatar from '../avatar';
import style from './style';
import moment from 'moment';
import _ from 'lodash';

const formatTime = (value) => {
	if (!value) {
		return '';
	}
	return moment(value).format('HH:mm');
};

// TODO reuse rendering of user name from message component

const Topic = (props) => {
	let className = `topic ${style.topic}`;
	if (props.selected) className += ` ${style.topic_selected}`;

	const msg = props.last_message || props.message || {};
	const user = msg.user;
	const unread = props.unread ? `${props.unread > 10 ? '10+' : props.unread} new` : '';
	const avatarURL = user ? user.avatar_url || user.avatar : null;

	const onClick = (e) => {
		e.preventDefault();
		if (_.isFunction(props.onSelect)) {
			props.onSelect(props.thread);
		}
	};

	return (

			{avatarURL ? <Avatar source={avatarURL} size={props.avatarSize} name={user.name}/> : null}
			<div className={`header ${style.header}`}>
				{props.topic}
				{unread ? <span className={`unread ${style.unread}`}>{unread} : null}

			<div className={`body ${style.body}`}>{msg.body}

				{user && user.name ? {user.name} : null}
				{` at ${formatTime(props.updated_at)}`}

	);
};

const ThreadList = (props) => {
	const items = props.threads.map(t => {
		return <Topic key={t.id} thread={t} {...t} onSelect={props.onSelect}/>;
	});
	return (
		<div className={`topic_list ${style.topic_list}`}>
			{items}

	);
};

export default ThreadList;
export { ThreadList };
<|endoftext|>


<commit_before>var NATIVE_BIND = require('../internals/function-bind-native');

var FunctionPrototype = Function.prototype;
var call = FunctionPrototype.call;
var uncurryThisWithBind = NATIVE_BIND && FunctionPrototype.bind.bind(call, call);

module.exports = function (fn) {
  return NATIVE_BIND ? uncurryThisWithBind(fn) : function () {
    return call.apply(fn, arguments);
  };
};
<commit_msg>minor optimization<commit_after>var NATIVE_BIND = require('../internals/function-bind-native');

var FunctionPrototype = Function.prototype;
var call = FunctionPrototype.call;
var uncurryThisWithBind = NATIVE_BIND && FunctionPrototype.bind.bind(call, call);

module.exports = NATIVE_BIND ? uncurryThisWithBind : function (fn) {
  return function () {
    return call.apply(fn, arguments);
  };
};
<|endoftext|>


<commit_before>var EventEmitter = require('events').EventEmitter;
var util = require('util');
var _ = require('lodash');
var MiddlewareHandler = require('middleware-handler');
var MiddlewareStream = require('./middlewarestream');
var IrcCommandHandler = require('./commands/').CommandHandler;
var Connection = require('./connection');
var NetworkInfo = require('./networkinfo');
var User = require('./user');
var Channel = require('./channel');

function IrcClient() {
    EventEmitter.call(this);

    // Provides middleware hooks for either raw IRC commands or the easier to use parsed commands
    this.raw_middleware = new MiddlewareHandler();
    this.parsed_middleware = new MiddlewareHandler();

    this.request_extra_caps = [];
}

util.inherits(IrcClient, EventEmitter);

module.exports = IrcClient;

IrcClient.prototype._applyDefaultOptions = function(user_options) {
    var defaults = {
        nick: 'ircbot',
        username: 'ircbot',
        gecos: 'ircbot',
        encoding: 'utf8'
    };

    var props = Object.keys(defaults);
    for (var i = 0; i < props.length; i++) {
        if (typeof user_options[props[i]] === 'undefined') {
            user_options[ props[ i ] ] = defaults[ props[ i ] ];
        }
    }

    return user_options;
};

IrcClient.prototype.requestCap = function(cap) {
    this.request_extra_caps = this.request_extra_caps.concat(cap);
};

IrcClient.prototype.use = function(middleware_fn) {
    middleware_fn(this, this.raw_middleware, this.parsed_middleware);
    return this;
};

IrcClient.prototype.connect = function(options) {
    var client = this;

    this.options = options;
    this._applyDefaultOptions(this.options);

    if (this.connection && this.connection.connected) {
        this.connection.end();
    }

    this.connection = new Connection(options);
    this.network = new NetworkInfo();
    this.user = new User({
        nick: options.nick,
        username: options.username,
        gecos: options.gecos
    });

    this.command_handler = new IrcCommandHandler(this.connection, this.network);
    this.command_handler.requestExtraCaps(this.request_extra_caps);

    client.addCommandHandlerListeners();

    // Proxy some connection events onto this client
    ['reconnecting', 'close'].forEach(function(event_name) {
        client.connection.on(event_name, function() {
            var args = Array.prototype.slice.call(arguments);
            client.emit.apply(client, [event_name].concat(args));
        });
    });

    this.connection.on('socket connected', function() {
        client.emit('socket connected');
        client.registerToNetwork();
    });

    // IRC command routing
    this.connection
        .pipe(new MiddlewareStream(this.raw_middleware, this))
        .pipe(this.command_handler);

    // Proxy the command handler events onto the client object, with some added sugar
    this.proxyIrcEvents();

    // Everything is setup and prepared, start connecting
    this.connection.connect();
};

// Proxy the command handler events onto the client object, with some added sugar
// Events are handled in order:
// 1. Received from the command handler
// 2. Checked if any extra properties/methods are to be added to the event + re-emitted
// 3. Routed through middleware
// 4. Emitted from the client instance
IrcClient.prototype.proxyIrcEvents = function() {
    var client = this;

    this.command_handler.on('all', function(event_name, event_arg) {
        // Add a reply() function to selected message events
        if (['privmsg', 'notice', 'action'].indexOf(event_name) > -1) {
            event_arg.reply = function(message) {
                var dest = event_arg.target === client.user.nick ?
                    event_arg.nick :
                    event_arg.target;

                client.say(dest, message);
            };

            // These events with .reply() function are all messages. Emit it separately
            // TODO: Should this consider a notice a message?
            client.command_handler.emit('message', _.extend({type: event_name}, event_arg));
        }

        client.parsed_middleware.handle([event_name, event_arg, client], function(err) {
            if (err) {
                //console.error('Middleware error', err.stack);
                return;
            }

            client.emit(event_name, event_arg);
        });
    });
};

IrcClient.prototype.addCommandHandlerListeners = function() {
    var client = this;
    var commands = this.command_handler;

    commands.on('nick', function(event) {
        if (client.user.nick === event.nick) {
            client.user.nick = event.new_nick;
        }
    });

    commands.on('registered', function(event) {
        client.emit('connected', event);
        client.user.nick = event.nick;
        client.connection.registeredSuccessfully();
    });

    // Don't let IRC ERROR command kill the node.js process if unhandled
    commands.on('error', function(event) {
    });
};

IrcClient.prototype.registerToNetwork = function() {
    var webirc = this.options.webirc;

    if (webirc) {
        this.raw('WEBIRC', webirc.password, 'kiwiIRC', webirc.hostname, webirc.address);
    }

    this.raw('CAP LS');

    if (this.options.password) {
        this.raw('PASS', this.options.password);
    }

    this.raw('NICK', this.user.nick);
    this.raw('USER', this.user.username, 0, '*', this.user.gecos);
};

Object.defineProperty(IrcClient.prototype, 'connected', {
    enumerable: true,
    get: function() {
        return this.connection && this.connection.connected;
    }
});

/**
 * Client API
 */
IrcClient.prototype.raw = function(input) {
    this.connection.write(this.rawString.apply(this, arguments));
};

IrcClient.prototype.rawString = function(input) {
    var args;

    if (input.constructor === Array) {
        args = input;
    } else {
        args = Array.prototype.slice.call(arguments, 0);
    }

    args = args.filter(function(item) {
        return (typeof item === 'number' || typeof item === 'string');
    });

    if (args.length > 1 && args[args.length - 1].indexOf(' ') > -1) {
        args[args.length - 1] = ':' + args[args.length - 1];
    }

    return args.join(' ');
};

IrcClient.prototype.quit = function(message) {
    this.connection.end(this.rawString('QUIT', message));
};

IrcClient.prototype.changeNick = function(nick) {
    this.raw('NICK', nick);
};

IrcClient.prototype.say = function(target, message) {
    var that = this;

    // Maximum length of target + message we can send to the IRC server is 500 characters
    // but we need to leave extra room for the sender prefix so the entire message can
    // be sent from the IRCd to the target without being truncated.
    var blocks = truncateString(message, 350);

    blocks.forEach(function(block) {
        that.raw('PRIVMSG', target, block);
    });
};

IrcClient.prototype.notice = function(target, message) {
    var that = this;

    // Maximum length of target + message we can send to the IRC server is 500 characters
    // but we need to leave extra room for the sender prefix so the entire message can
    // be sent from the IRCd to the target without being truncated.
    var blocks = truncateString(message, 350);

    blocks.forEach(function(block) {
        that.raw('NOTICE', target, block);
    });
};

IrcClient.prototype.join = function(channel, key) {
    var raw = ['JOIN', channel];
    if (key) {
        raw.push(key);
    }
    this.raw(raw);
};

IrcClient.prototype.part = function(channel, message) {
    var raw = ['PART', channel];
    if (message) {
        raw.push(message);
    }
    this.raw(raw);
};

IrcClient.prototype.ctcpRequest = function(target, type /*, paramN*/) {
    var params = Array.prototype.slice.call(arguments, 2);
    this.raw(
        'PRIVMSG',
        target,
        String.fromCharCode(1) + type.toUpperCase(),
        params.join(' ') + String.fromCharCode(1)
    );
};

IrcClient.prototype.ctcpResponse = function(target, type /*, paramN*/) {
    var params = Array.prototype.slice.call(arguments, 2);
    this.raw(
        'NOTICE',
        target,
        String.fromCharCode(1) + type.toUpperCase(),
        params.join(' ') + String.fromCharCode(1)
    );
};

IrcClient.prototype.whois = function(target, cb) {
    var client = this;

    this.on('whois', function onWhois(event) {
        if (event.nick.toLowerCase() === target.toLowerCase()) {
            client.removeListener('whois', onWhois);
            cb(event);
        }
    });

    this.raw('WHOIS', target);
};

IrcClient.prototype.channel = function(channel_name) {
    return new Channel(this, channel_name);
};

IrcClient.prototype.match = function(match_regex, cb, message_type) {
    var client = this;

    var onMessage = function(event) {
        if (event.message.match(match_regex)) {
            cb(event);
        }
    };

    this.on(message_type || 'message', onMessage);

    return {
        stop: function() {
            client.removeListener(message_type || 'message', onMessage);
        }
    };
};

IrcClient.prototype.matchNotice = function(match_regex, cb) {
    return this.match(match_regex, cb, 'notice');
};
IrcClient.prototype.matchMessage = function(match_regex, cb) {
    return this.match(match_regex, cb, 'privmsg');
};
IrcClient.prototype.matchAction = function(match_regex, cb) {
    return this.match(match_regex, cb, 'action');
};

/**
 * Truncate a string into blocks of a set size
 */
function truncateString(str, block_size) {
    block_size = block_size || 350;

    var blocks = [];
    var current_pos;

    for (current_pos = 0; current_pos < str.length; current_pos = current_pos + block_size) {
        blocks.push(str.substr(current_pos, block_size));
    }

    return blocks;
}
<commit_msg>Add action overload<commit_after>var EventEmitter = require('events').EventEmitter;
var util = require('util');
var _ = require('lodash');
var MiddlewareHandler = require('middleware-handler');
var MiddlewareStream = require('./middlewarestream');
var IrcCommandHandler = require('./commands/').CommandHandler;
var Connection = require('./connection');
var NetworkInfo = require('./networkinfo');
var User = require('./user');
var Channel = require('./channel');

function IrcClient() {
    EventEmitter.call(this);

    // Provides middleware hooks for either raw IRC commands or the easier to use parsed commands
    this.raw_middleware = new MiddlewareHandler();
    this.parsed_middleware = new MiddlewareHandler();

    this.request_extra_caps = [];
}

util.inherits(IrcClient, EventEmitter);

module.exports = IrcClient;

IrcClient.prototype._applyDefaultOptions = function(user_options) {
    var defaults = {
        nick: 'ircbot',
        username: 'ircbot',
        gecos: 'ircbot',
        encoding: 'utf8'
    };

    var props = Object.keys(defaults);
    for (var i = 0; i < props.length; i++) {
        if (typeof user_options[props[i]] === 'undefined') {
            user_options[ props[ i ] ] = defaults[ props[ i ] ];
        }
    }

    return user_options;
};

IrcClient.prototype.requestCap = function(cap) {
    this.request_extra_caps = this.request_extra_caps.concat(cap);
};

IrcClient.prototype.use = function(middleware_fn) {
    middleware_fn(this, this.raw_middleware, this.parsed_middleware);
    return this;
};

IrcClient.prototype.connect = function(options) {
    var client = this;

    this.options = options;
    this._applyDefaultOptions(this.options);

    if (this.connection && this.connection.connected) {
        this.connection.end();
    }

    this.connection = new Connection(options);
    this.network = new NetworkInfo();
    this.user = new User({
        nick: options.nick,
        username: options.username,
        gecos: options.gecos
    });

    this.command_handler = new IrcCommandHandler(this.connection, this.network);
    this.command_handler.requestExtraCaps(this.request_extra_caps);

    client.addCommandHandlerListeners();

    // Proxy some connection events onto this client
    ['reconnecting', 'close'].forEach(function(event_name) {
        client.connection.on(event_name, function() {
            var args = Array.prototype.slice.call(arguments);
            client.emit.apply(client, [event_name].concat(args));
        });
    });

    this.connection.on('socket connected', function() {
        client.emit('socket connected');
        client.registerToNetwork();
    });

    // IRC command routing
    this.connection
        .pipe(new MiddlewareStream(this.raw_middleware, this))
        .pipe(this.command_handler);

    // Proxy the command handler events onto the client object, with some added sugar
    this.proxyIrcEvents();

    // Everything is setup and prepared, start connecting
    this.connection.connect();
};

// Proxy the command handler events onto the client object, with some added sugar
// Events are handled in order:
// 1. Received from the command handler
// 2. Checked if any extra properties/methods are to be added to the event + re-emitted
// 3. Routed through middleware
// 4. Emitted from the client instance
IrcClient.prototype.proxyIrcEvents = function() {
    var client = this;

    this.command_handler.on('all', function(event_name, event_arg) {
        // Add a reply() function to selected message events
        if (['privmsg', 'notice', 'action'].indexOf(event_name) > -1) {
            event_arg.reply = function(message) {
                var dest = event_arg.target === client.user.nick ?
                    event_arg.nick :
                    event_arg.target;

                client.say(dest, message);
            };

            // These events with .reply() function are all messages. Emit it separately
            // TODO: Should this consider a notice a message?
            client.command_handler.emit('message', _.extend({type: event_name}, event_arg));
        }

        client.parsed_middleware.handle([event_name, event_arg, client], function(err) {
            if (err) {
                //console.error('Middleware error', err.stack);
                return;
            }

            client.emit(event_name, event_arg);
        });
    });
};

IrcClient.prototype.addCommandHandlerListeners = function() {
    var client = this;
    var commands = this.command_handler;

    commands.on('nick', function(event) {
        if (client.user.nick === event.nick) {
            client.user.nick = event.new_nick;
        }
    });

    commands.on('registered', function(event) {
        client.emit('connected', event);
        client.user.nick = event.nick;
        client.connection.registeredSuccessfully();
    });

    // Don't let IRC ERROR command kill the node.js process if unhandled
    commands.on('error', function(event) {
    });
};

IrcClient.prototype.registerToNetwork = function() {
    var webirc = this.options.webirc;

    if (webirc) {
        this.raw('WEBIRC', webirc.password, 'kiwiIRC', webirc.hostname, webirc.address);
    }

    this.raw('CAP LS');

    if (this.options.password) {
        this.raw('PASS', this.options.password);
    }

    this.raw('NICK', this.user.nick);
    this.raw('USER', this.user.username, 0, '*', this.user.gecos);
};

Object.defineProperty(IrcClient.prototype, 'connected', {
    enumerable: true,
    get: function() {
        return this.connection && this.connection.connected;
    }
});

/**
 * Client API
 */
IrcClient.prototype.raw = function(input) {
    this.connection.write(this.rawString.apply(this, arguments));
};

IrcClient.prototype.rawString = function(input) {
    var args;

    if (input.constructor === Array) {
        args = input;
    } else {
        args = Array.prototype.slice.call(arguments, 0);
    }

    args = args.filter(function(item) {
        return (typeof item === 'number' || typeof item === 'string');
    });

    if (args.length > 1 && args[args.length - 1].indexOf(' ') > -1) {
        args[args.length - 1] = ':' + args[args.length - 1];
    }

    return args.join(' ');
};

IrcClient.prototype.quit = function(message) {
    this.connection.end(this.rawString('QUIT', message));
};

IrcClient.prototype.changeNick = function(nick) {
    this.raw('NICK', nick);
};

IrcClient.prototype.say = function(target, message) {
    var that = this;

    // Maximum length of target + message we can send to the IRC server is 500 characters
    // but we need to leave extra room for the sender prefix so the entire message can
    // be sent from the IRCd to the target without being truncated.
    var blocks = truncateString(message, 350);

    blocks.forEach(function(block) {
        that.raw('PRIVMSG', target, block);
    });
};

IrcClient.prototype.notice = function(target, message) {
    var that = this;

    // Maximum length of target + message we can send to the IRC server is 500 characters
    // but we need to leave extra room for the sender prefix so the entire message can
    // be sent from the IRCd to the target without being truncated.
    var blocks = truncateString(message, 350);

    blocks.forEach(function(block) {
        that.raw('NOTICE', target, block);
    });
};

IrcClient.prototype.join = function(channel, key) {
    var raw = ['JOIN', channel];
    if (key) {
        raw.push(key);
    }
    this.raw(raw);
};

IrcClient.prototype.part = function(channel, message) {
    var raw = ['PART', channel];
    if (message) {
        raw.push(message);
    }
    this.raw(raw);
};

IrcClient.prototype.ctcpRequest = function(target, type /*, paramN*/) {
    var params = Array.prototype.slice.call(arguments, 2);
    this.raw(
        'PRIVMSG',
        target,
        String.fromCharCode(1) + type.toUpperCase(),
        params.join(' ') + String.fromCharCode(1)
    );
};

IrcClient.prototype.ctcpResponse = function(target, type /*, paramN*/) {
    var params = Array.prototype.slice.call(arguments, 2);
    this.raw(
        'NOTICE',
        target,
        String.fromCharCode(1) + type.toUpperCase(),
        params.join(' ') + String.fromCharCode(1)
    );
};

IrcClient.prototype.action = function(target, message) {
    this.ctcpRequest(target, 'ACTION', message);
};

IrcClient.prototype.whois = function(target, cb) {
    var client = this;

    this.on('whois', function onWhois(event) {
        if (event.nick.toLowerCase() === target.toLowerCase()) {
            client.removeListener('whois', onWhois);
            cb(event);
        }
    });

    this.raw('WHOIS', target);
};

IrcClient.prototype.channel = function(channel_name) {
    return new Channel(this, channel_name);
};

IrcClient.prototype.match = function(match_regex, cb, message_type) {
    var client = this;

    var onMessage = function(event) {
        if (event.message.match(match_regex)) {
            cb(event);
        }
    };

    this.on(message_type || 'message', onMessage);

    return {
        stop: function() {
            client.removeListener(message_type || 'message', onMessage);
        }
    };
};

IrcClient.prototype.matchNotice = function(match_regex, cb) {
    return this.match(match_regex, cb, 'notice');
};
IrcClient.prototype.matchMessage = function(match_regex, cb) {
    return this.match(match_regex, cb, 'privmsg');
};
IrcClient.prototype.matchAction = function(match_regex, cb) {
    return this.match(match_regex, cb, 'action');
};

/**
 * Truncate a string into blocks of a set size
 */
function truncateString(str, block_size) {
    block_size = block_size || 350;

    var blocks = [];
    var current_pos;

    for (current_pos = 0; current_pos < str.length; current_pos = current_pos + block_size) {
        blocks.push(str.substr(current_pos, block_size));
    }

    return blocks;
}
<|endoftext|>


<commit_before>'use strict';

const computationsDatabaseSyncer =
  require('./services/computations-database-syncer.js');
const cloneDeep = require('lodash/cloneDeep');
const coinstacCommon = require('coinstac-common');
const coinstacComputationRegistry = require('coinstac-computation-registry');
const logger = require('./services/logger.js');
const mkdirp = require('mkdirp');
const os = require('os');
const path = require('path');
const pify = require('pify');
const pouchDbAdapterLevelDB = require('pouchdb-adapter-leveldb');
const pouchDBAdapterMemory = require('pouchdb-adapter-memory');
const url = require('url');
const dbmap = require('/coins/config/dbmap.json');

const BASE_PATH = path.join(os.tmpdir(), 'coinstac-server-core');
const DB_REGISTRY_DEFAULTS = {
  isRemote: true,
  localStores: null,
  pouchConfig: {},
  remote: {
    db: {
      auth: dbmap.coinstac ? `${dbmap.coinstac.user}:${dbmap.coinstac.password}` : '',
      protocol: 'http',
      hostname: 'localhost',
      port: 5984,
    },
  },
  remoteStoresSyncOut: null,
  verbose: true,
};
const mkdirpAsync = pify(mkdirp);

/**
 * COINSTAC Server.
 * @module
 * @class
 *
 * @property {Object} config Passed configuration
 * @property {(ComputationRegistry|null)} computationRegistry
 * @property {(DBRegistry|null)} dbRegistry
 * @property {winston.Logger} logger
 * @property {(RemotePipelineRunnerPool|null)} remotePipelineRunnerPool
 */
class CoinstacServer {
  /**
   * @param {Object} config
   * @param {(string|Object[])} [config.seed] Whether or not to seed the database.
   * This only seeds if no documents exist in the `consortia` database. Pass
   * JSON as a string or a collection of document objects.
   * @param {string} [config.dbUrl] Database URL.
   * @param {boolean} [config.inMemory=false] Use an in-memory database using
   * instead of writing to disk.
   * @param {string} [config.logLevel=info] Logger level for winston's console
   * transport.
   */
  constructor(config) {
    if (typeof config !== 'object') {
      throw new Error('Expected configuration object');
    }

    this.config = config;

    this.computationRegistry = null;
    this.dbRegistry = null;
    this.remotePipelineRunnerPool = null;

    this.logger = logger;
    this.logger.level = this.config.logLevel || 'info';
  }

  /**
   * Get configured ComputationRegistry.
   * @private
   *
   * @returns {Promise<ComputationRegistry>}
   */
  getComputationRegistry() {
    this.logger.info('Initializing computation registry...');

    return mkdirpAsync(CoinstacServer.COMPUTATIONS_PATH)
      .then(() => coinstacComputationRegistry.factory({
        path: CoinstacServer.COMPUTATIONS_PATH,
      }))
      .then((computationRegistry) => {
        this.logger.info('Computation registry initialized');
        return computationRegistry;
      });
  }

  /**
   * Get configured DBRegistry.
   * @private
   *
   * @returns {Promise<DBRegistry>}
   */
  getDBRegistry() {
    // Unfortunately necessary for sinon spying
    const dbRegistryFactory = coinstacCommon.services.dbRegistry;
    const dbRegistryOptions = cloneDeep(DB_REGISTRY_DEFAULTS);

    this.logger.info('Initializing DB registry...');

    if (this.config.dbUrl) {
      dbRegistryOptions.remote.db = url.parse(this.config.dbUrl);
    }

    if (this.config.inMemory) {
      dbRegistryFactory.DBRegistry.Pouchy.plugin(pouchDBAdapterMemory);
      dbRegistryOptions.pouchConfig.adapter = 'memory';
    } else {
      dbRegistryFactory.DBRegistry.Pouchy.plugin(pouchDbAdapterLevelDB);
      dbRegistryOptions.pouchConfig.adapter = 'leveldb';
    }

    dbRegistryOptions.path = CoinstacServer.DB_PATH;

    const factoryProxy = () => {
      const dbRegistry = dbRegistryFactory(dbRegistryOptions);
      this.logger.info('DB registry initialized');
      return dbRegistry;
    };

    return this.config.inMemory ?
      Promise.resolve(factoryProxy()) :
      mkdirpAsync(CoinstacServer.DB_PATH).then(factoryProxy);
  }

  /**
   * Get configured remote pipeline runner pool.
   * @private
   *
   * @returns {Promise<RemotePipelineRunnerPool>}
   */
  getRemotePipelineRunnerPool() {
    if (!this.computationRegistry) {
      return Promise.reject(new Error('Expected ComputationRegistry'));
    } else if (!this.dbRegistry) {
      return Promise.reject(new Error('Expected DBRegistry'));
    }

    const RemotePipelineRunnerPool =
      coinstacCommon.models.pipeline.runner.pool.RemotePipelineRunnerPool;

    const pool = new RemotePipelineRunnerPool({
      computationRegistry: this.computationRegistry,
      dbRegistry: this.dbRegistry,
    });

    pool.events.on('computation:complete', runId => this.logger.verbose(
      'RemotePipelineRunnerPool.events [computation:complete]',
      `Run id: ${runId}`
    ));
    pool.events.on('ready', () => this.logger.verbose(
      'RemotePipelineRunnerPool.events [ready]'
    ));
    pool.events.on('listener:created', dbName => this.logger.verbose(
      'RemotePipelineRunnerPool.events [listener:created]', `DB name: ${dbName}`
    ));
    pool.events.on('queue:start', runId => this.logger.verbose(
      'RemotePipelineRunnerPool.events [queue:start]', `Run id: ${runId}`
    ));
    pool.events.on('queue:end', runId => this.logger.verbose(
      'RemotePipelineRunnerPool.events [queue:end]', `Run id: ${runId}`
    ));
    pool.events.on('pipeline:inProgress', () => this.logger.verbose(
      'RemotePipelineRunnerPool.events [pipeline:inProgress]'
    ));
    pool.events.on('run:end', compResult => this.logger.verbose(
      'RemotePipelineRunnerPool.events [run:end]',
      'Computation result:',
      compResult
    ));
    pool.events.on('computation:complete', runId => this.logger.verbose(
      'RemotePipelineRunnerPool.events [computation:complete]',
      `Run id: ${runId}`
    ));
    pool.events.on('computation:markedComplete', runId => this.logger.verbose(
      'RemotePipelineRunnerPool.events [computation:markedComplete]',
      `Run id: ${runId}`
    ));
    pool.events.on('error', error => this.logger.error(
      'RemotePipelineRunnerPool.events [error]', error
    ));
    pool.events.on('run:start', result => this.logger.verbose(
      'RemotePipelineRunnerPool.events [run:start]', 'Result:', result
    ));

    this.logger.info('initializing RemotePipelineRunnerPool...');

    return pool.init().then(
      () => {
        this.logger.info('RemotePipelineRunnerPool ready');
        return pool;
      },

      // TODO: Move error logging to handler?
      error => {
        this.logger.error(
          'RemotePipelineRunnerPool initialization failed',
          error
        );
        throw error;
      }
    );
  }

  /**
   * Maybe seed the consortia database.
   * @private
   *
   * @returns {Promise<boolean>}
   */
  maybeSeedConsortia() {
    const Consortium = coinstacCommon.models.Consortium;
    const seed = this.config.seed;
    let seedDocs;

    if (!this.dbRegistry) {
      return Promise.reject(new Error('Seeding consortia requires DBRegistry'));
    }

    if (seed && typeof seed === 'string') {
      try {
        seedDocs = JSON.parse(seed);
      } catch (error) {
        return Promise.reject(error);
      }
    } else {
      seedDocs = seed;
    }

    if (!seedDocs || !Array.isArray(seedDocs) || !seedDocs.length) {
      return Promise.resolve(false);
    }

    this.logger.info('Seeding consortia database...');

    this.dbRegistry.get('consortia')
      .bulkDocs(seedDocs.map(seedDoc => new Consortium(seedDoc).serialize()))
      .then(() => {
        this.logger.info('Seeded consortia database');
        return true;
      });
  }

  /**
   * Start server.
   *
   * @returns {Promise}
   */
  start() {
    this.logger.info('Starting server...');

    return Promise.all([this.getComputationRegistry(), this.getDBRegistry()])
      .then(([computationRegistry, dbRegistry]) => {
        this.computationRegistry = computationRegistry;
        this.dbRegistry = dbRegistry;

        return Promise.all([
          coinstacCommon.utils.getSyncedDatabase(dbRegistry, 'computations'),
          computationRegistry.all(),
        ]);
      })
      .then(([computationDatabase, decentralizedComputations]) => Promise.all([
        this.getRemotePipelineRunnerPool(),
        this.maybeSeedConsortia(),
        computationsDatabaseSyncer.sync(
          computationDatabase,
          decentralizedComputations
        ),
      ]))
      .then(([remotePipelineRunnerPool]) => {
        this.remotePipelineRunnerPool = remotePipelineRunnerPool;
        this.logger.info('Server ready');
        return remotePipelineRunnerPool;
      });
  }

  /**
   * Stop server.
   *
   * @returns {Promise}
   */
  stop() {
    const responses = [];

    this.logger.info('Stopping server...');

    if (this.computationRegistry) {
      this.computationRegistry = null;
    }

    if (this.dbRegistry) {
      this.logger.info('destroying DBRegistry...');
      responses.push(this.dbRegistry.destroy());
      this.dbRegistry = null;
    }

    if (this.remotePipelineRunnerPool) {
      this.logger.info('destroying RemotePipelineRunnerPool...');

      if (
        this.remotePipelineRunnerPool.isInitialized ||
        this.remotePipelineRunnerPool.isInitializing
      ) {
        responses.push(this.remotePipelineRunnerPool.destroy());
      } else {
        this.remotePipelineRunnerPool.events.removeAllListeners();
      }

      this.remotePipelineRunnerPool = null;
    }

    return Promise.all(responses);
  }
}

/**
 * Database path.
 *
 * @const {string}
 */
CoinstacServer.DB_PATH = path.join(BASE_PATH, 'dbs');

/**
 * Computations path.
 *
 * @const {string}
 */
CoinstacServer.COMPUTATIONS_PATH = path.join(BASE_PATH, 'computations');

module.exports = CoinstacServer;
<commit_msg>Make pool init happen in series.<commit_after>'use strict';

const computationsDatabaseSyncer =
  require('./services/computations-database-syncer.js');
const cloneDeep = require('lodash/cloneDeep');
const coinstacCommon = require('coinstac-common');
const coinstacComputationRegistry = require('coinstac-computation-registry');
const logger = require('./services/logger.js');
const mkdirp = require('mkdirp');
const os = require('os');
const path = require('path');
const pify = require('pify');
const pouchDbAdapterLevelDB = require('pouchdb-adapter-leveldb');
const pouchDBAdapterMemory = require('pouchdb-adapter-memory');
const url = require('url');
const dbmap = require('/coins/config/dbmap.json');

const BASE_PATH = path.join(os.tmpdir(), 'coinstac-server-core');
const DB_REGISTRY_DEFAULTS = {
  isRemote: true,
  localStores: null,
  pouchConfig: {},
  remote: {
    db: {
      auth: dbmap.coinstac ? `${dbmap.coinstac.user}:${dbmap.coinstac.password}` : '',
      protocol: 'http',
      hostname: 'localhost',
      port: 5984,
    },
  },
  remoteStoresSyncOut: null,
  verbose: true,
};
const mkdirpAsync = pify(mkdirp);

/**
 * COINSTAC Server.
 * @module
 * @class
 *
 * @property {Object} config Passed configuration
 * @property {(ComputationRegistry|null)} computationRegistry
 * @property {(DBRegistry|null)} dbRegistry
 * @property {winston.Logger} logger
 * @property {(RemotePipelineRunnerPool|null)} remotePipelineRunnerPool
 */
class CoinstacServer {
  /**
   * @param {Object} config
   * @param {(string|Object[])} [config.seed] Whether or not to seed the database.
   * This only seeds if no documents exist in the `consortia` database. Pass
   * JSON as a string or a collection of document objects.
   * @param {string} [config.dbUrl] Database URL.
   * @param {boolean} [config.inMemory=false] Use an in-memory database using
   * instead of writing to disk.
   * @param {string} [config.logLevel=info] Logger level for winston's console
   * transport.
   */
  constructor(config) {
    if (typeof config !== 'object') {
      throw new Error('Expected configuration object');
    }

    this.config = config;

    this.computationRegistry = null;
    this.dbRegistry = null;
    this.remotePipelineRunnerPool = null;

    this.logger = logger;
    this.logger.level = this.config.logLevel || 'info';
  }

  /**
   * Get configured ComputationRegistry.
   * @private
   *
   * @returns {Promise<ComputationRegistry>}
   */
  getComputationRegistry() {
    this.logger.info('Initializing computation registry...');

    return mkdirpAsync(CoinstacServer.COMPUTATIONS_PATH)
      .then(() => coinstacComputationRegistry.factory({
        path: CoinstacServer.COMPUTATIONS_PATH,
      }))
      .then((computationRegistry) => {
        this.logger.info('Computation registry initialized');
        return computationRegistry;
      });
  }

  /**
   * Get configured DBRegistry.
   * @private
   *
   * @returns {Promise<DBRegistry>}
   */
  getDBRegistry() {
    // Unfortunately necessary for sinon spying
    const dbRegistryFactory = coinstacCommon.services.dbRegistry;
    const dbRegistryOptions = cloneDeep(DB_REGISTRY_DEFAULTS);

    this.logger.info('Initializing DB registry...');

    if (this.config.dbUrl) {
      dbRegistryOptions.remote.db = url.parse(this.config.dbUrl);
    }

    if (this.config.inMemory) {
      dbRegistryFactory.DBRegistry.Pouchy.plugin(pouchDBAdapterMemory);
      dbRegistryOptions.pouchConfig.adapter = 'memory';
    } else {
      dbRegistryFactory.DBRegistry.Pouchy.plugin(pouchDbAdapterLevelDB);
      dbRegistryOptions.pouchConfig.adapter = 'leveldb';
    }

    dbRegistryOptions.path = CoinstacServer.DB_PATH;

    const factoryProxy = () => {
      const dbRegistry = dbRegistryFactory(dbRegistryOptions);
      this.logger.info('DB registry initialized');
      return dbRegistry;
    };

    return this.config.inMemory ?
      Promise.resolve(factoryProxy()) :
      mkdirpAsync(CoinstacServer.DB_PATH).then(factoryProxy);
  }

  /**
   * Get configured remote pipeline runner pool.
   * @private
   *
   * @returns {Promise<RemotePipelineRunnerPool>}
   */
  getRemotePipelineRunnerPool() {
    if (!this.computationRegistry) {
      return Promise.reject(new Error('Expected ComputationRegistry'));
    } else if (!this.dbRegistry) {
      return Promise.reject(new Error('Expected DBRegistry'));
    }

    const RemotePipelineRunnerPool =
      coinstacCommon.models.pipeline.runner.pool.RemotePipelineRunnerPool;

    const pool = new RemotePipelineRunnerPool({
      computationRegistry: this.computationRegistry,
      dbRegistry: this.dbRegistry,
    });

    pool.events.on('computation:complete', runId => this.logger.verbose(
      'RemotePipelineRunnerPool.events [computation:complete]',
      `Run id: ${runId}`
    ));
    pool.events.on('ready', () => this.logger.verbose(
      'RemotePipelineRunnerPool.events [ready]'
    ));
    pool.events.on('listener:created', dbName => this.logger.verbose(
      'RemotePipelineRunnerPool.events [listener:created]', `DB name: ${dbName}`
    ));
    pool.events.on('queue:start', runId => this.logger.verbose(
      'RemotePipelineRunnerPool.events [queue:start]', `Run id: ${runId}`
    ));
    pool.events.on('queue:end', runId => this.logger.verbose(
      'RemotePipelineRunnerPool.events [queue:end]', `Run id: ${runId}`
    ));
    pool.events.on('pipeline:inProgress', () => this.logger.verbose(
      'RemotePipelineRunnerPool.events [pipeline:inProgress]'
    ));
    pool.events.on('run:end', compResult => this.logger.verbose(
      'RemotePipelineRunnerPool.events [run:end]',
      'Computation result:',
      compResult
    ));
    pool.events.on('computation:complete', runId => this.logger.verbose(
      'RemotePipelineRunnerPool.events [computation:complete]',
      `Run id: ${runId}`
    ));
    pool.events.on('computation:markedComplete', runId => this.logger.verbose(
      'RemotePipelineRunnerPool.events [computation:markedComplete]',
      `Run id: ${runId}`
    ));
    pool.events.on('error', error => this.logger.error(
      'RemotePipelineRunnerPool.events [error]', error
    ));
    pool.events.on('run:start', result => this.logger.verbose(
      'RemotePipelineRunnerPool.events [run:start]', 'Result:', result
    ));

    this.logger.info('initializing RemotePipelineRunnerPool...');

    return pool.init().then(
      () => {
        this.logger.info('RemotePipelineRunnerPool ready');
        return pool;
      },

      // TODO: Move error logging to handler?
      error => {
        this.logger.error(
          'RemotePipelineRunnerPool initialization failed',
          error
        );
        throw error;
      }
    );
  }

  /**
   * Maybe seed the consortia database.
   * @private
   *
   * @returns {Promise<boolean>}
   */
  maybeSeedConsortia() {
    const Consortium = coinstacCommon.models.Consortium;
    const seed = this.config.seed;
    let seedDocs;

    if (!this.dbRegistry) {
      return Promise.reject(new Error('Seeding consortia requires DBRegistry'));
    }

    if (seed && typeof seed === 'string') {
      try {
        seedDocs = JSON.parse(seed);
      } catch (error) {
        return Promise.reject(error);
      }
    } else {
      seedDocs = seed;
    }

    if (!seedDocs || !Array.isArray(seedDocs) || !seedDocs.length) {
      return Promise.resolve(false);
    }

    this.logger.info('Seeding consortia database...');

    this.dbRegistry.get('consortia')
      .bulkDocs(seedDocs.map(seedDoc => new Consortium(seedDoc).serialize()))
      .then(() => {
        this.logger.info('Seeded consortia database');
        return true;
      });
  }

  /**
   * Start server.
   *
   * @returns {Promise}
   */
  start() {
    this.logger.info('Starting server...');

    return Promise.all([this.getComputationRegistry(), this.getDBRegistry()])
      .then(([computationRegistry, dbRegistry]) => {
        this.computationRegistry = computationRegistry;
        this.dbRegistry = dbRegistry;

        return Promise.all([
          coinstacCommon.utils.getSyncedDatabase(dbRegistry, 'computations'),
          computationRegistry.all(),
        ]);
      })
      .then(([computationDatabase, decentralizedComputations]) => Promise.all([
        computationDatabase,
        decentralizedComputations,
        this.getRemotePipelineRunnerPool(),
      ]))
      .then(([
        computationDatabase,
        decentralizedComputations,
        remotePipelineRunnerPool,
      ]) => Promise.all([
        remotePipelineRunnerPool,
        this.maybeSeedConsortia(),
        computationsDatabaseSyncer.sync(
          computationDatabase,
          decentralizedComputations
        ),
      ]))
      .then(([remotePipelineRunnerPool]) => {
        this.remotePipelineRunnerPool = remotePipelineRunnerPool;
        this.logger.info('Server ready');
        return remotePipelineRunnerPool;
      });
  }

  /**
   * Stop server.
   *
   * @returns {Promise}
   */
  stop() {
    const responses = [];

    this.logger.info('Stopping server...');

    if (this.computationRegistry) {
      this.computationRegistry = null;
    }

    if (this.dbRegistry) {
      this.logger.info('destroying DBRegistry...');
      responses.push(this.dbRegistry.destroy());
      this.dbRegistry = null;
    }

    if (this.remotePipelineRunnerPool) {
      this.logger.info('destroying RemotePipelineRunnerPool...');

      if (
        this.remotePipelineRunnerPool.isInitialized ||
        this.remotePipelineRunnerPool.isInitializing
      ) {
        responses.push(this.remotePipelineRunnerPool.destroy());
      } else {
        this.remotePipelineRunnerPool.events.removeAllListeners();
      }

      this.remotePipelineRunnerPool = null;
    }

    return Promise.all(responses);
  }
}

/**
 * Database path.
 *
 * @const {string}
 */
CoinstacServer.DB_PATH = path.join(BASE_PATH, 'dbs');

/**
 * Computations path.
 *
 * @const {string}
 */
CoinstacServer.COMPUTATIONS_PATH = path.join(BASE_PATH, 'computations');

module.exports = CoinstacServer;
<|endoftext|>


<commit_before>const uid = require('uuid/v4');
const { getSchedFormat, schedFormat, slotFormat } = require('./format');
exports.syncSchedules = async (s, d) => {
    try {
        const rmisjs = require('../../index')(s);
        const er14 = await rmisjs.integration.er14.process();
        let r = d;
        let bb = [];
        for (let i of r) {
            for (let j of i.interval) {
                let data = getSchedFormat({
                    scheduleDate: j.date,
                    muCode: s.er14.muCode,
                    needFIO: false
                });
                let schedules = await er14.getScheduleInfo(data);
                let rmIds = [];
                let count = 0;
                if (schedules.scheduleInfo) {
                    schedules = schedules.scheduleInfo.schedule;
                    for (let k of schedules) {
                        if (k.docCode === i.snils) {
                            let slots = (Array.isArray(k.slot)) ? k.slot : new Array(k.slot);
                            for (let l of slots) {
                                for (let tp of j.timePeriod) {
                                    let from = l.timeInterval.timeStart;
                                    let to = l.timeInterval.timeFinish;
                                    let lfrom = tp.from.replace(/\.000\+09:00/g, 'Z');
                                    let lto = tp.to.replace(/\.000\+09:00/g, 'Z');
                                    if (from === lfrom && to === lto) {
                                        rmIds.push(j.timePeriod.indexOf(tp));
                                    }
                                }
                            }
                        }
                    }
                    for (let k of rmIds) {
                        j.timePeriod.splice(k, 1);
                    }
                }
                if (j.timePeriod.length > 0) {
                    let d = {
                        scheduleDate: j.date,
                        muCode: s.er14.muCode,
                        deptCode: i.department.code,
                        roomNumber: i.room,
                        docCode: i.snils,
                        specCode: (Array.isArray(i.speciality)) ? i.speciality[0] : i.speciality,
                        positionCode: (Array.isArray(i.position)) ? i.position[0] : i.position
                    };
                    let u = schedFormat(d);
                    j.timePeriod.forEach(k => {
                        let ts = {
                            timeStart: k.from.replace(/\+09:00/g, 'Z'),
                            timeFinish: k.to.replace(/\+09:00/g, 'Z'),
                            slotType: 2,
                            GUID: uid(),
                            SlotState: 1
                        };
                        u = u + slotFormat(ts);
                    });
                    let rr = await er14.updateSchedule({ $xml: u });
                    bb.push(rr);
                }
            }
        }
        return bb;
    } catch (e) { return e; }
};
<commit_msg>0.4.2<commit_after>const uid = require('uuid/v4');
const { getSchedFormat, schedFormat, slotFormat } = require('./format');
exports.syncSchedules = async (s, d) => {
    try {
        const rmisjs = require('../../index')(s);
        const er14 = await rmisjs.integration.er14.process();
        let r = d;
        let bb = [];
        for (let i of r) {
            for (let j of i.interval) {
                let data = getSchedFormat({
                    scheduleDate: j.date,
                    muCode: s.er14.muCode,
                    needFIO: false
                });
                let schedules = await er14.getScheduleInfo(data);
                let rmIds = [];
                let count = 0;
                if (schedules.scheduleInfo) {
                    schedules = schedules.scheduleInfo.schedule;
                    schedules = (Array.isArray(schedules)) ? schedules : new Array(schedules);
                    for (let k of schedules) {
                        if (k.docCode === i.snils) {
                            let slots = (Array.isArray(k.slot)) ? k.slot : new Array(k.slot);
                            for (let l of slots) {
                                for (let tp of j.timePeriod) {
                                    let from = l.timeInterval.timeStart;
                                    let to = l.timeInterval.timeFinish;
                                    let lfrom = tp.from.replace(/\.000\+09:00/g, 'Z');
                                    let lto = tp.to.replace(/\.000\+09:00/g, 'Z');
                                    if (from === lfrom && to === lto) {
                                        rmIds.push(j.timePeriod.indexOf(tp));
                                    }
                                }
                            }
                        }
                    }
                    for (let k of rmIds) {
                        j.timePeriod.splice(k, 1);
                    }
                }
                if (j.timePeriod.length > 0) {
                    let d = {
                        scheduleDate: j.date,
                        muCode: s.er14.muCode,
                        deptCode: i.department.code,
                        roomNumber: i.room,
                        docCode: i.snils,
                        specCode: (Array.isArray(i.speciality)) ? i.speciality[0] : i.speciality,
                        positionCode: (Array.isArray(i.position)) ? i.position[0] : i.position
                    };
                    let u = schedFormat(d);
                    j.timePeriod.forEach(k => {
                        let ts = {
                            timeStart: k.from.replace(/\+09:00/g, 'Z'),
                            timeFinish: k.to.replace(/\+09:00/g, 'Z'),
                            slotType: 2,
                            GUID: uid(),
                            SlotState: 1
                        };
                        u = u + slotFormat(ts);
                    });
                    let rr = await er14.updateSchedule({ $xml: u });
                    bb.push(rr);
                }
            }
        }
        return bb;
    } catch (e) { return e; }
};
<|endoftext|>