<commit_before>// TODO Performance improvements in here could be very important.

var EmailService = {

  startMergeTemplate: function(template) {
    try {
      MergeTemplateService.validate(template);
      EmailService.validate(template.mergeData.data);
    }
    catch(e) {
      log(e);
      throw e;
    }

    log('Starting merge template ' + template.id);
    var ss = Utility.getSpreadsheet();
    var sheet = ss.getSheetByName(template.mergeData.sheet);
    var range = sheet.getDataRange();
    var header = HeaderService.get(template.mergeData.sheet, template.mergeData.headerRow);
    var sendHelper;

    if (template.mergeData.conditional == null) {
      sendHelper = EmailService.sendHelper;
    }
    else {
      sendHelper = EmailService.conditionalSendHelper;
    }

    for (var i = parseInt(template.mergeData.headerRow); i < range.getNumRows(); i++) {
      var row = range.offset(i, 0, 1, range.getNumColumns());

      try {
        // We only timestamp when the email successfully sends.
        if (sendHelper(header, row.getDisplayValues()[0], template)) {
          var timestampName = template.mergeData.timestampColumn.replace(/(<<|>>)/g, '');
          var timeCell = row.getCell(1, header.indexOf(timestampName) + 1);

          var currentDate = new Date();
          var datetime = (currentDate.getMonth() + 1) + '/' +
                  currentDate.getDate() + '/' +
                  currentDate.getFullYear() + ' ' +
                  currentDate.getHours() + ':' +
                  currentDate.getMinutes() + ':' +
                  currentDate.getSeconds();

          timeCell.setValue(datetime);
        }
      }
      catch (e) {
        log(e);
      }
    }

    log('Ending merge template...');
  },

  /**
   * Sends a test email to the current user.
   *
   * @param  {string} sheetName The name of the Sheet to send from.
   * @param  {string} headerRow The 1-based row the header is in.
   * @param  {string} subject The whack-whacked subject.
   * @param  {string} body The whack whacked body.
   */
  sendTest: function(sheetName, headerRow, subject, body) {
    log('Sending test email');
    var ss = Utility.getSpreadsheet();
    var sheet = ss.getSheetByName(sheetName);
    var range = sheet.getDataRange();
    var header = HeaderService.get(sheetName, headerRow);
    var row = range.offset(parseInt(headerRow), 0, 1, range.getNumColumns()).getDisplayValues()[0];

    var combinedObj = {};
    for (var j = 0; j < header.length; j++) {
      combinedObj[header[j]] = row[j];
    }

    // Convert <<>> tags to actual text.
    var subject = EmailService.replaceTags(subject, combinedObj);
    var body = EmailService.replaceTags(body, combinedObj);

    EmailService.send(Session.getActiveUser().getEmail(), subject, body);
  },

  send: function(to, subject, body, cc, bcc) {
    var htmlEmail = HtmlService.createTemplateFromFile('email-template');
    htmlEmail.id = Utility.getSpreadsheet().getId();
    htmlEmail.bodyArray = body.split('\n');

    log('Sending email to ' + JSON.stringify({
      to: to,
      cc: cc,
      bcc: bcc
    }));
    GmailApp.sendEmail(to, subject, body, {
      htmlBody: htmlEmail.evaluate().getContent(),
      cc: cc,
      bcc: bcc
    });
  },

  /**
   * Validates the supplied MergeData.data. This can be found in MergeTemplate.mergeData.data. This is specifically
   * for mail merge.
   * Note, this throws errors if the data is invalid.
   *
   * @param  {Object} data The data payload containing to, subject and body.
   */
  validate: function(data) {
    if (data == null) {
      throw new Error('MergeTemplate.mergeData.data is null');
    }
    if (data.to == null) {
      throw new Error('MergeTemplate.mergeData.data.to is null');
    }
    if (data.subject == null) {
      throw new Error('MergeTemplate.mergeData.data.subject is null');
    }
    if (data.body == null) {
      throw new Error('MergeTemplate.mergeData.data.body is null');
    }
  },

  /******* Private / utility functions *******/

  /**
   * Sends an email based upon a MergeTemplate. Whack whacks are swapped out.
   * Handles to, subject and body fields.
   *
   * @param {String[]} headerRow An array of header values.
   * @param {String[]} row An array of row values.
   * @param {Object} template The MergeTemplate used to send the email. See the client-side object for info.
   * @return {Boolean} true if the email was sent, false otherwise.
   */
  sendHelper: function(headerRow, row, template) {

    var combinedObj = {};
    for (var j = 0; j < headerRow.length; j++) {
      combinedObj[headerRow[j]] = row[j];
    }

    // Convert <<>> tags to actual text.
    var to = EmailService.replaceTags(template.mergeData.data.to, combinedObj);
    var subject = EmailService.replaceTags(template.mergeData.data.subject, combinedObj);
    var body = EmailService.replaceTags(template.mergeData.data.body, combinedObj);
    var cc;
    var bcc;

    if (template.mergeData.data.cc != null) {
      cc = EmailService.replaceTags(template.mergeData.data.cc, combinedObj);;
    }
    if (template.mergeData.data.bcc != null) {
      bcc = EmailService.replaceTags(template.mergeData.data.bcc, combinedObj);;
    }

    EmailService.send(to, subject, body, cc, bcc);

    return true;
  },

  /**
   * Sends an email based upon a MergeTemplate. Tags are swapped out.
   * Handles to, subject, body, conditional and timestampColumn fields.
   *
   * @param {String[]} headerRow An array of header values.
   * @param {String[]} row An array of row values.
   * @param {Object} template The MergeTemplate used to send the email. See the client-side Object for info.
   * @return {Boolean} true if the email was sent, false otherwise.
   */
  conditionalSendHelper: function(headerRow, row, template) {
    var combinedObj = {};
    for (var j = 0; j < headerRow.length; j++) {
      combinedObj[headerRow[j]] = row[j];
    }

    // Convert <<>> tags to actual text.
    var to = EmailService.replaceTags(template.mergeData.data.to, combinedObj);
    var subject = EmailService.replaceTags(template.mergeData.data.subject, combinedObj);
    var body = EmailService.replaceTags(template.mergeData.data.body, combinedObj);
    var sendColumn = EmailService.replaceTags(template.mergeData.conditional, combinedObj);
    var cc;
    var bcc;

    if (template.mergeData.data.cc != null) {
      cc = EmailService.replaceTags(template.mergeData.data.cc, combinedObj);;
    }
    if (template.mergeData.data.bcc != null) {
      bcc = EmailService.replaceTags(template.mergeData.data.bcc, combinedObj);;
    }

    if (sendColumn.toLowerCase() == 'true') {
      EmailService.send(to, subject, body, cc, bcc);

      return true;
    }

    return false;
  },

  /**
   * This function replaces  all instances of <<tags>> with the data in headerToData.
   *
   * @param {string} text The string that contains the tags.
   * @param {Object} headerToData A key-value pair where the key is a column name and the value is the data in the
   * column.
   * @return {string} The text with all tags replaced with data.
   */
  replaceTags: function(text, headerToData) {
    var dataText = text.replace(/<<.*?>>/g, function(match, offset, string) {
      var columnName = match.slice(2, match.length - 2);
      return headerToData[columnName];
    });

    return dataText;
  }
};
<commit_msg>Added a requirement for emails to have a to field.<commit_after>// TODO Performance improvements in here could be very important.

var EmailService = {

  startMergeTemplate: function(template) {
    try {
      MergeTemplateService.validate(template);
      EmailService.validate(template.mergeData.data);
    }
    catch(e) {
      log(e);
      throw e;
    }

    log('Starting merge template ' + template.id);
    var ss = Utility.getSpreadsheet();
    var sheet = ss.getSheetByName(template.mergeData.sheet);
    var range = sheet.getDataRange();
    var header = HeaderService.get(template.mergeData.sheet, template.mergeData.headerRow);
    var sendHelper;

    if (template.mergeData.conditional == null) {
      sendHelper = EmailService.sendHelper;
    }
    else {
      sendHelper = EmailService.conditionalSendHelper;
    }

    for (var i = parseInt(template.mergeData.headerRow); i < range.getNumRows(); i++) {
      var row = range.offset(i, 0, 1, range.getNumColumns());

      try {
        // We only timestamp when the email successfully sends.
        if (sendHelper(header, row.getDisplayValues()[0], template)) {
          var timestampName = template.mergeData.timestampColumn.replace(/(<<|>>)/g, '');
          var timeCell = row.getCell(1, header.indexOf(timestampName) + 1);

          var currentDate = new Date();
          var datetime = (currentDate.getMonth() + 1) + '/' +
                  currentDate.getDate() + '/' +
                  currentDate.getFullYear() + ' ' +
                  currentDate.getHours() + ':' +
                  currentDate.getMinutes() + ':' +
                  currentDate.getSeconds();

          timeCell.setValue(datetime);
        }
      }
      catch (e) {
        log(e);
      }
    }

    log('Ending merge template...');
  },

  /**
   * Sends a test email to the current user.
   *
   * @param  {string} sheetName The name of the Sheet to send from.
   * @param  {string} headerRow The 1-based row the header is in.
   * @param  {string} subject The whack-whacked subject.
   * @param  {string} body The whack whacked body.
   */
  sendTest: function(sheetName, headerRow, subject, body) {
    log('Sending test email');
    var ss = Utility.getSpreadsheet();
    var sheet = ss.getSheetByName(sheetName);
    var range = sheet.getDataRange();
    var header = HeaderService.get(sheetName, headerRow);
    var row = range.offset(parseInt(headerRow), 0, 1, range.getNumColumns()).getDisplayValues()[0];

    var combinedObj = {};
    for (var j = 0; j < header.length; j++) {
      combinedObj[header[j]] = row[j];
    }

    // Convert <<>> tags to actual text.
    var subject = EmailService.replaceTags(subject, combinedObj);
    var body = EmailService.replaceTags(body, combinedObj);

    EmailService.send(Session.getActiveUser().getEmail(), subject, body);
  },

  send: function(to, subject, body, cc, bcc) {
    if (to === '' || to == null) {
      return;
    }

    var htmlEmail = HtmlService.createTemplateFromFile('email-template');
    htmlEmail.id = Utility.getSpreadsheet().getId();
    htmlEmail.bodyArray = body.split('\n');

    log('Sending email to ' + JSON.stringify({
      to: to,
      cc: cc,
      bcc: bcc
    }));
    GmailApp.sendEmail(to, subject, body, {
      htmlBody: htmlEmail.evaluate().getContent(),
      cc: cc,
      bcc: bcc
    });
  },

  /**
   * Validates the supplied MergeData.data. This can be found in MergeTemplate.mergeData.data. This is specifically
   * for mail merge.
   * Note, this throws errors if the data is invalid.
   *
   * @param  {Object} data The data payload containing to, subject and body.
   */
  validate: function(data) {
    if (data == null) {
      throw new Error('MergeTemplate.mergeData.data is null');
    }
    if (data.to == null) {
      throw new Error('MergeTemplate.mergeData.data.to is null');
    }
    if (data.subject == null) {
      throw new Error('MergeTemplate.mergeData.data.subject is null');
    }
    if (data.body == null) {
      throw new Error('MergeTemplate.mergeData.data.body is null');
    }
  },

  /******* Private / utility functions *******/

  /**
   * Sends an email based upon a MergeTemplate. Whack whacks are swapped out.
   * Handles to, subject and body fields.
   *
   * @param {String[]} headerRow An array of header values.
   * @param {String[]} row An array of row values.
   * @param {Object} template The MergeTemplate used to send the email. See the client-side object for info.
   * @return {Boolean} true if the email was sent, false otherwise.
   */
  sendHelper: function(headerRow, row, template) {

    var combinedObj = {};
    for (var j = 0; j < headerRow.length; j++) {
      combinedObj[headerRow[j]] = row[j];
    }

    // Convert <<>> tags to actual text.
    var to = EmailService.replaceTags(template.mergeData.data.to, combinedObj);
    var subject = EmailService.replaceTags(template.mergeData.data.subject, combinedObj);
    var body = EmailService.replaceTags(template.mergeData.data.body, combinedObj);
    var cc;
    var bcc;

    if (template.mergeData.data.cc != null) {
      cc = EmailService.replaceTags(template.mergeData.data.cc, combinedObj);;
    }
    if (template.mergeData.data.bcc != null) {
      bcc = EmailService.replaceTags(template.mergeData.data.bcc, combinedObj);;
    }

    EmailService.send(to, subject, body, cc, bcc);

    return true;
  },

  /**
   * Sends an email based upon a MergeTemplate. Tags are swapped out.
   * Handles to, subject, body, conditional and timestampColumn fields.
   *
   * @param {String[]} headerRow An array of header values.
   * @param {String[]} row An array of row values.
   * @param {Object} template The MergeTemplate used to send the email. See the client-side Object for info.
   * @return {Boolean} true if the email was sent, false otherwise.
   */
  conditionalSendHelper: function(headerRow, row, template) {
    var combinedObj = {};
    for (var j = 0; j < headerRow.length; j++) {
      combinedObj[headerRow[j]] = row[j];
    }

    // Convert <<>> tags to actual text.
    var to = EmailService.replaceTags(template.mergeData.data.to, combinedObj);
    var subject = EmailService.replaceTags(template.mergeData.data.subject, combinedObj);
    var body = EmailService.replaceTags(template.mergeData.data.body, combinedObj);
    var sendColumn = EmailService.replaceTags(template.mergeData.conditional, combinedObj);
    var cc;
    var bcc;

    if (template.mergeData.data.cc != null) {
      cc = EmailService.replaceTags(template.mergeData.data.cc, combinedObj);;
    }
    if (template.mergeData.data.bcc != null) {
      bcc = EmailService.replaceTags(template.mergeData.data.bcc, combinedObj);;
    }

    if (sendColumn.toLowerCase() == 'true') {
      EmailService.send(to, subject, body, cc, bcc);

      return true;
    }

    return false;
  },

  /**
   * This function replaces  all instances of <<tags>> with the data in headerToData.
   *
   * @param {string} text The string that contains the tags.
   * @param {Object} headerToData A key-value pair where the key is a column name and the value is the data in the
   * column.
   * @return {string} The text with all tags replaced with data.
   */
  replaceTags: function(text, headerToData) {
    var dataText = text.replace(/<<.*?>>/g, function(match, offset, string) {
      var columnName = match.slice(2, match.length - 2);
      return headerToData[columnName];
    });

    return dataText;
  }
};
<|endoftext|>


<commit_before>
var http = require('http')
var url = require('url')
var qs = require('qs')

module.exports = {
  oauth1: (port) => new Promise((resolve) => {
    var callback
    var server = http.createServer()
    server.on('request', (req, res) => {
      if (/^\/request_url/.test(req.url)) {
        callback = decodeURIComponent(/oauth_callback="(.+?)"/.exec(req.headers.authorization)[1])
        res.writeHead(200, {'content-type': 'application/x-www-form-urlencoded'})
        res.end(qs.stringify({oauth_token: 'token', oauth_token_secret: 'secret'}))
      }
      else if (/^\/authorize_url/.test(req.url)) {
        var location = callback + '?' + qs.stringify({
          oauth_token: 'token', oauth_verifier: 'verifier'})
        res.writeHead(302, {location})
        res.end()
      }
      else if (/^\/access_url/.test(req.url)) {
        res.writeHead(200, {'content-type': 'application/json'})
        res.end(JSON.stringify({
          oauth_token: 'token', oauth_token_secret: 'secret'
        }))
      }
    })
    server.listen(port, () => resolve(server))
  }),
  oauth2: (port) => new Promise((resolve) => {
    var server = http.createServer()
    server.on('request', (req, res) => {
      if (/^\/authorize_url/.test(req.url)) {
        var parsed = url.parse(req.url, false)
        var query = qs.parse(parsed.query)
        var location = query.redirect_uri + '?' + qs.stringify({code: 'code'})
        res.writeHead(302, {location})
        res.end()
      }
      else if (/^\/access_url/.test(req.url)) {
        res.writeHead(200, {'content-type': 'application/json'})
        res.end(JSON.stringify({
          access_token: 'token', refresh_token: 'refresh', expires_in: 3600
        }))
      }
    })
    server.listen(port, () => resolve(server))
  }),
}
<commit_msg>Add test hooks to the provider<commit_after>
var http = require('http')
var url = require('url')
var qs = require('qs')

var buffer = (req, done) => {
  var data = ''
  req.on('data', (chunk) => data += chunk)
  req.on('end', () => done(qs.parse(data)))
}
var parse = (req) => {
  var parsed = url.parse(req.url, false)
  var query = qs.parse(parsed.query)
  return {query}
}

var oauth1 = (port) => new Promise((resolve) => {
  var callback
  var server = http.createServer()
  server.on('request', (req, res) => {
    if (/^\/request_url/.test(req.url)) {
      callback = decodeURIComponent(/oauth_callback="(.+?)"/.exec(req.headers.authorization)[1])
      buffer(req, (form) => {
        oauth1.request({form})
        res.writeHead(200, {'content-type': 'application/x-www-form-urlencoded'})
        res.end(qs.stringify({oauth_token: 'token', oauth_token_secret: 'secret'}))
      })
    }
    else if (/^\/authorize_url/.test(req.url)) {
      var location = callback + '?' +
        qs.stringify({oauth_token: 'token', oauth_verifier: 'verifier'})
      var {query} = parse(req)
      oauth1.authorize({query})
      res.writeHead(302, {location})
      res.end()
    }
    else if (/^\/access_url/.test(req.url)) {
      buffer(req, (form) => {
        oauth1.access({form})
        res.writeHead(200, {'content-type': 'application/json'})
        res.end(JSON.stringify({
          oauth_token: 'token', oauth_token_secret: 'secret'
        }))
      })
    }
  })
  server.listen(port, () => resolve(server))
})

var oauth2 = (port) => new Promise((resolve) => {
  var server = http.createServer()
  server.on('request', (req, res) => {
    if (/^\/authorize_url/.test(req.url)) {
      var {query} = parse(req)
      oauth2.authorize({query})
      var location = query.redirect_uri + '?' + qs.stringify({code: 'code'})
      res.writeHead(302, {location})
      res.end()
    }
    else if (/^\/access_url/.test(req.url)) {
      buffer(req, (form) => {
        oauth2.access({form})
        res.writeHead(200, {'content-type': 'application/json'})
        res.end(JSON.stringify({
          access_token: 'token', refresh_token: 'refresh', expires_in: 3600
        }))
      })
    }
  })
  server.listen(port, () => resolve(server))
})

oauth1.request = () => {}
oauth1.authorize = () => {}
oauth1.access = () => {}
oauth2.authorize = () => {}
oauth2.access = () => {}

module.exports = {oauth1, oauth2}
<|endoftext|>


<commit_before>var _ = require('underscore');
var slack = require('./slacker');
var jira = require('jira');
var slackbot = require('node-slackbot');
var JiraApi = require('jira').JiraApi;
var q = require('q');

/**
 * Slackbot to integrate JIRA.
 *
 * The main thing it does right now is auto-expand links, but since we are bringing in the JIRA plugin, there is more it can do
 *
 * See config-example.js for configuration
 *
 * To run:  node config-XXX.js   (where XXX is the name of your config
 *
 * See:
 * https://www.npmjs.com/package/node-slackbot
 * https://www.npmjs.com/package/jira
 */
var Bot = function (config) {
  var self = this;
  this.config = _.defaults(config, {
    bot_name: "JIRABot",
    emoji: ":jira:",
    post: true
  });
  this.slacker = new slack.Slacker({
    token: this.config.token
  });
  return this;
};

function getBaseUrl(prjName, config) {
  var configUrl;
  if (config.jira_urls[prjName]) {
    configUrl = config.jira_urls[prjName].url;
  } else {
    configUrl = config.jira_urls["DEFAULT"].url;
  }
  return configUrl;
}

function generateMsg(configUrl, issue) {
  return ':jira: <' + configUrl + issue.key + '|*' + issue.key + '*>';
}

function generateAttachement(configUrl, issue){
  var attachment = {};

  attachment.fallback = issue.key + ' - ' + issue.fields.summary;
  attachment.title = issue.key + ' - ' + issue.fields.summary;
  attachment.title_link = configUrl + issue.key;
  attachment.fields = [
    {
      "title": "Priority",
      "value": issue.fields.priority.name,
      "short": true
    },
    {
      "title": "Assignee",
      "value": issue.fields.assignee && issue.fields.assignee.displayName,
      "short": true
    },
    {
      "title": "Status",
      "value": issue.fields.status.name,
      "short": true
    },
  ];
  if(issue.fields.duedate){
    attachment.fields.push({
        "title": "Due",
        "value": issue.fields.duedate,
        "short": true
      });
  }

  switch(issue.fields.status.name){
    case "Closed":
      attachment.color = "good";
      break;
    default:
      attachment.color = "warning";
  }
  attachment.text = " ";
  attachment.text = issue.fields.description;

  return attachment;
}

function doSearch(splits, self, apis, requests) {
  var prjName = splits.shift();
  var configUrl = getBaseUrl(prjName, self.config);
  var jiraApi = apis[prjName];
  if (jiraApi == null) {
    //explicit urls that don't have jira credentials will be marked by NONE.  If we don't have a
    // key at all, then we are using the DEFAULT, so see if it has credentials
    jiraApi = apis["DEFAULT"];
  }//https://jira.lucidworks.com/browse/WEB-1059?jql=text%20~%20%22grant%22
  var chan = self.config.search_output_chan;
  var def = q.defer();
  requests.push(def.promise);
  var searchString = "text ~ \"" + splits.join(" ") + "\"";
  console.log("Search for: " + searchString + " Output to: " + chan);
  var optional = {"maxResults": 10};
  try {
    jiraApi.searchJira(searchString, optional, function (error, body) {
      //console.log(body);
      if (body && body.total > 0) {
        var fullMsg = "Total hits: " + body.total + " for " + searchString + "\n";
        _.each(body.issues, function (item) {
          console.log(item.key);
          fullMsg += generateMsg(configUrl, item);
          fullMsg += ' - "' + (item.fields.summary || item.key) + '"';
          fullMsg += "\n";
        });
        /*if (self.config.verbose) {
          console.log(fullMsg);
        }*/

        var req = {"channel": chan, "text": fullMsg, "type": "search"};
        def.resolve(req)
      } else {
        console.log(error);
        var req = {"channel": null, "text": "There was an error executing your search: " + error, "type": "error"};
        def.resolve(req);
      }
    });
  } catch (e) {
    var req = {"channel": null, "text": "There was an error executing your search: " + e, "type": "error"};
    def.resolve(req);
  }

}

Bot.prototype.run = function () {
  var self = this,
      verbose = self.config.verbose,
      bot = new slackbot(this.config.token),
      pattern = "(?:\\W|^)((";
  var apis = {};
  _.each(self.config.jira_urls, function (value, key, obj) {

    if (value.jira) {
      console.log("Creating API for:");
      console.log(key);
      console.log(value);
      apis[key] = new JiraApi(
          value.jira.protocol,
          value.jira.host,
          value.jira.port,
          value.jira.user,
          value.jira.password,
          value.jira.version,
          value.jira.strictSSL,
          value.jira.oauth
      );
    } else {
      apis[key] = "NONE";//put in a placeholder in the map for explicitly declared JIRA urls that don't have JIRA credentials so that we can know when to use the default
    }
  });
  var prjNames = "";
  _.each(self.config.projects, function (prj, index, list) {
    pattern += prj;
    prjNames += prj;
    if (index != list.length - 1) {
      pattern += "|";
      prjNames += "|";
    }
  });
  pattern += ")-\\d+)(\\+)?(?:(?=\\W)|$)";
  if (verbose) {
    console.log("Pattern is: " + pattern);
  }
  bot.use(function (message, cb) {
    if ('message' == message.type && message.text != null && message.subtype != "bot_message") {
      var requests = [];
      if (message.text.indexOf("@" + self.config.bot_name) == 0) {
        // @JIRABot search [URL KEY] [channel name] 'text to search'
        var text = message.text;
        var splits = text.split(/\s+/)
        //discard the mention of the bot and search
        splits.shift();
        var command = splits.shift();
        if (command == self.config.search_cmd) {
          doSearch(splits, self, apis, requests);
        }
      }
      else {
        var regexp = new RegExp(pattern, "g"),
            match, def;
        while (match = regexp.exec(message.text)) {
          if (verbose) {
            console.log("Match:");
            console.log(message);
            console.log(match);
          }
          // PROJECT-XXXX is the first capturing group, e.g. ((PROJECT)-\d+)
          var j = match[1].trim(),
          // PROJECT is the second capturing group
              prjName = match[2],
          // if the PROJECT-XXX is followed by a +, then we include
          // issue details in the response message:
              expandInfo = !!match[3];
          // pass-in a defered and the jira issue number,
          // then execute immediately...
          // we need this closure to capture the _current_ values...
          // (this is async...)
          if (self.config.showDetailsByDefault){
            expandInfo = true;
          }
          var jiraApi = apis[prjName];
          if (jiraApi == null) {
            //explicit urls that don't have jira credentials will be marked by NONE.  If we don't have a
            // key at all, then we are using the DEFAULT, so see if it has credentials
            jiraApi = apis["DEFAULT"];
          }
          if (verbose) {
            console.log(jiraApi);
          }
          try {
            if (jiraApi && jiraApi != "NONE") {
              (function (def, jira) {
                requests.push(def.promise);
                jiraApi.findIssue(jira, function (error, issue) {
                  if (verbose) {
                    console.log("JIRA: " + jira);
                  }
                  var msg;
                  var attachments = [];

                  if (issue && self.config.post == true) {
                    var configUrl = getBaseUrl(prjName, self.config);
                    msg = generateMsg(configUrl, issue);

                    if (self.config.showIssueDetails && expandInfo) {
                      attachments.push(generateAttachement(configUrl, issue));
                      var req = {"channel": message.channel, "attachments": attachments, "text": " "};
                    }else{
                      var req = {"channel": message.channel, "text": msg};
                    }

                  } else {
                    msg = ':exclamation:' + jira + ' - _' + error + '_';
                  }
                  if (verbose) {
                    console.log(msg);
                  }

                  def.resolve(req);
                });
              })(q.defer(), j);
            } else {
              (function (def, jira) {
                requests.push(def.promise);
                var configUrl = getBaseUrl(prjName, self.config);
                var msg = generateMsg(configUrl, {key: jira});
                var req = {"channel": message.channel, "text": msg};
                def.resolve(req);
              })(q.defer(), j);
            }
          } catch (e) {
            var channel;
            if (self.config.error_channel) {
              channel = self.config.error_channel;
            } else {
              channel = message.channel;
            }
            var theMsg = "There was an error in handling the request for: " + message.text + " Error: " + e;
            self.slacker.send('chat.postMessage', {
              channel: channel,
              parse: "all",
              text: theMsg,
              username: self.config.bot_name,
              unfurl_links: false,
              link_names: 1,
              icon_emoji: self.config.emoji
            });
          }
        }
      }
      if (requests.length > 0) {
        q.all(requests).then(function (messages) {
          _.forEach(messages, function (theRequest) {
            if (verbose) {
              console.log("Message:");
              console.log(theRequest);
            }
            var chan = null;
            if (!theRequest.channel) {
              chan = message.channel;
            } else {
              if (theRequest.channel == "this"){
                chan = message.channel;
              } else {
                chan = theRequest.channel;
              }
            }
            self.slacker.send('chat.postMessage', {
              channel: chan,
              parse: "all",
              text: theRequest.text,
              attachments: JSON.stringify(theRequest.attachments),
              username: self.config.bot_name,
              unfurl_links: false,
              link_names: 1,
              icon_emoji: self.config.emoji
            });
          });
        })
      }
      cb();
    }
  });
  bot.connect(self.config.verbose);
};

exports = module.exports.Bot = Bot;
<commit_msg>Fix positional arguments for JiraApi<commit_after>var _ = require('underscore');
var slack = require('./slacker');
var jira = require('jira');
var slackbot = require('node-slackbot');
var JiraApi = require('jira').JiraApi;
var q = require('q');

/**
 * Slackbot to integrate JIRA.
 *
 * The main thing it does right now is auto-expand links, but since we are bringing in the JIRA plugin, there is more it can do
 *
 * See config-example.js for configuration
 *
 * To run:  node config-XXX.js   (where XXX is the name of your config
 *
 * See:
 * https://www.npmjs.com/package/node-slackbot
 * https://www.npmjs.com/package/jira
 */
var Bot = function (config) {
  var self = this;
  this.config = _.defaults(config, {
    bot_name: "JIRABot",
    emoji: ":jira:",
    post: true
  });
  this.slacker = new slack.Slacker({
    token: this.config.token
  });
  return this;
};

function getBaseUrl(prjName, config) {
  var configUrl;
  if (config.jira_urls[prjName]) {
    configUrl = config.jira_urls[prjName].url;
  } else {
    configUrl = config.jira_urls["DEFAULT"].url;
  }
  return configUrl;
}

function generateMsg(configUrl, issue) {
  return ':jira: <' + configUrl + issue.key + '|*' + issue.key + '*>';
}

function generateAttachement(configUrl, issue){
  var attachment = {};

  attachment.fallback = issue.key + ' - ' + issue.fields.summary;
  attachment.title = issue.key + ' - ' + issue.fields.summary;
  attachment.title_link = configUrl + issue.key;
  attachment.fields = [
    {
      "title": "Priority",
      "value": issue.fields.priority.name,
      "short": true
    },
    {
      "title": "Assignee",
      "value": issue.fields.assignee && issue.fields.assignee.displayName,
      "short": true
    },
    {
      "title": "Status",
      "value": issue.fields.status.name,
      "short": true
    },
  ];
  if(issue.fields.duedate){
    attachment.fields.push({
        "title": "Due",
        "value": issue.fields.duedate,
        "short": true
      });
  }

  switch(issue.fields.status.name){
    case "Closed":
      attachment.color = "good";
      break;
    default:
      attachment.color = "warning";
  }
  attachment.text = " ";
  attachment.text = issue.fields.description;

  return attachment;
}

function doSearch(splits, self, apis, requests) {
  var prjName = splits.shift();
  var configUrl = getBaseUrl(prjName, self.config);
  var jiraApi = apis[prjName];
  if (jiraApi == null) {
    //explicit urls that don't have jira credentials will be marked by NONE.  If we don't have a
    // key at all, then we are using the DEFAULT, so see if it has credentials
    jiraApi = apis["DEFAULT"];
  }//https://jira.lucidworks.com/browse/WEB-1059?jql=text%20~%20%22grant%22
  var chan = self.config.search_output_chan;
  var def = q.defer();
  requests.push(def.promise);
  var searchString = "text ~ \"" + splits.join(" ") + "\"";
  console.log("Search for: " + searchString + " Output to: " + chan);
  var optional = {"maxResults": 10};
  try {
    jiraApi.searchJira(searchString, optional, function (error, body) {
      //console.log(body);
      if (body && body.total > 0) {
        var fullMsg = "Total hits: " + body.total + " for " + searchString + "\n";
        _.each(body.issues, function (item) {
          console.log(item.key);
          fullMsg += generateMsg(configUrl, item);
          fullMsg += ' - "' + (item.fields.summary || item.key) + '"';
          fullMsg += "\n";
        });
        /*if (self.config.verbose) {
          console.log(fullMsg);
        }*/

        var req = {"channel": chan, "text": fullMsg, "type": "search"};
        def.resolve(req)
      } else {
        console.log(error);
        var req = {"channel": null, "text": "There was an error executing your search: " + error, "type": "error"};
        def.resolve(req);
      }
    });
  } catch (e) {
    var req = {"channel": null, "text": "There was an error executing your search: " + e, "type": "error"};
    def.resolve(req);
  }

}

Bot.prototype.run = function () {
  var self = this,
      verbose = self.config.verbose,
      bot = new slackbot(this.config.token),
      pattern = "(?:\\W|^)((";
  var apis = {};
  _.each(self.config.jira_urls, function (value, key, obj) {

    if (value.jira) {
      console.log("Creating API for:");
      console.log(key);
      console.log(value);
      apis[key] = new JiraApi(
          value.jira.protocol,
          value.jira.host,
          value.jira.port,
          value.jira.user,
          value.jira.password,
          value.jira.version,
          value.jira.verbose,
          value.jira.strictSSL,
          value.jira.oauth
      );
    } else {
      apis[key] = "NONE";//put in a placeholder in the map for explicitly declared JIRA urls that don't have JIRA credentials so that we can know when to use the default
    }
  });
  var prjNames = "";
  _.each(self.config.projects, function (prj, index, list) {
    pattern += prj;
    prjNames += prj;
    if (index != list.length - 1) {
      pattern += "|";
      prjNames += "|";
    }
  });
  pattern += ")-\\d+)(\\+)?(?:(?=\\W)|$)";
  if (verbose) {
    console.log("Pattern is: " + pattern);
  }
  bot.use(function (message, cb) {
    if ('message' == message.type && message.text != null && message.subtype != "bot_message") {
      var requests = [];
      if (message.text.indexOf("@" + self.config.bot_name) == 0) {
        // @JIRABot search [URL KEY] [channel name] 'text to search'
        var text = message.text;
        var splits = text.split(/\s+/)
        //discard the mention of the bot and search
        splits.shift();
        var command = splits.shift();
        if (command == self.config.search_cmd) {
          doSearch(splits, self, apis, requests);
        }
      }
      else {
        var regexp = new RegExp(pattern, "g"),
            match, def;
        while (match = regexp.exec(message.text)) {
          if (verbose) {
            console.log("Match:");
            console.log(message);
            console.log(match);
          }
          // PROJECT-XXXX is the first capturing group, e.g. ((PROJECT)-\d+)
          var j = match[1].trim(),
          // PROJECT is the second capturing group
              prjName = match[2],
          // if the PROJECT-XXX is followed by a +, then we include
          // issue details in the response message:
              expandInfo = !!match[3];
          // pass-in a defered and the jira issue number,
          // then execute immediately...
          // we need this closure to capture the _current_ values...
          // (this is async...)
          if (self.config.showDetailsByDefault){
            expandInfo = true;
          }
          var jiraApi = apis[prjName];
          if (jiraApi == null) {
            //explicit urls that don't have jira credentials will be marked by NONE.  If we don't have a
            // key at all, then we are using the DEFAULT, so see if it has credentials
            jiraApi = apis["DEFAULT"];
          }
          if (verbose) {
            console.log(jiraApi);
          }
          try {
            if (jiraApi && jiraApi != "NONE") {
              (function (def, jira) {
                requests.push(def.promise);
                jiraApi.findIssue(jira, function (error, issue) {
                  if (verbose) {
                    console.log("JIRA: " + jira);
                  }
                  var msg;
                  var attachments = [];

                  if (issue && self.config.post == true) {
                    var configUrl = getBaseUrl(prjName, self.config);
                    msg = generateMsg(configUrl, issue);

                    if (self.config.showIssueDetails && expandInfo) {
                      attachments.push(generateAttachement(configUrl, issue));
                      var req = {"channel": message.channel, "attachments": attachments, "text": " "};
                    }else{
                      var req = {"channel": message.channel, "text": msg};
                    }

                  } else {
                    msg = ':exclamation:' + jira + ' - _' + error + '_';
                  }
                  if (verbose) {
                    console.log(msg);
                  }

                  def.resolve(req);
                });
              })(q.defer(), j);
            } else {
              (function (def, jira) {
                requests.push(def.promise);
                var configUrl = getBaseUrl(prjName, self.config);
                var msg = generateMsg(configUrl, {key: jira});
                var req = {"channel": message.channel, "text": msg};
                def.resolve(req);
              })(q.defer(), j);
            }
          } catch (e) {
            var channel;
            if (self.config.error_channel) {
              channel = self.config.error_channel;
            } else {
              channel = message.channel;
            }
            var theMsg = "There was an error in handling the request for: " + message.text + " Error: " + e;
            self.slacker.send('chat.postMessage', {
              channel: channel,
              parse: "all",
              text: theMsg,
              username: self.config.bot_name,
              unfurl_links: false,
              link_names: 1,
              icon_emoji: self.config.emoji
            });
          }
        }
      }
      if (requests.length > 0) {
        q.all(requests).then(function (messages) {
          _.forEach(messages, function (theRequest) {
            if (verbose) {
              console.log("Message:");
              console.log(theRequest);
            }
            var chan = null;
            if (!theRequest.channel) {
              chan = message.channel;
            } else {
              if (theRequest.channel == "this"){
                chan = message.channel;
              } else {
                chan = theRequest.channel;
              }
            }
            self.slacker.send('chat.postMessage', {
              channel: chan,
              parse: "all",
              text: theRequest.text,
              attachments: JSON.stringify(theRequest.attachments),
              username: self.config.bot_name,
              unfurl_links: false,
              link_names: 1,
              icon_emoji: self.config.emoji
            });
          });
        })
      }
      cb();
    }
  });
  bot.connect(self.config.verbose);
};

exports = module.exports.Bot = Bot;
<|endoftext|>


<commit_before>/* @flow */

import React from 'react';
import Relay from 'react-relay';

import Pagination from '@ncigdc/components/Pagination';
import Showing from '@ncigdc/components/Pagination/Showing';
import AddToCartButtonAll from '@ncigdc/components/AddToCartButtonAll';
import { Row } from '@ncigdc/uikit/Flex';
import TableActions from '@ncigdc/components/TableActions';

import { Tr, Th } from '@ncigdc/uikit/Table';

import FileTr from './FileTr';

import type { TTableProps } from './types';

const styles = {
  table: {
    width: '100%',
    borderCollapse: 'collapse',
    borderSpacing: 0,
  },
};

export const FileTableComponent = (props: TTableProps) => {
  const prefix = 'files';

  return (

      <Row style={{ backgroundColor: 'white', padding: '1rem', justifyContent: 'space-between' }}>
        <Showing
          docType="files"
          prefix={prefix}
          params={props.relay.route.params}
          total={props.hits.total}
        />
        <TableActions
          prefix={prefix}
          total={props.hits.total}
          sortKey="files_sort"
          endpoint={`${API}/files`}
          downloadable={props.downloadable}
          downloadFields={[
            'file_id',
            'file_name',
            'cases.project.project_id',
            'data_category',
            'data_format',
            'file_size',
          ]}
          sortOptions={[
            {
              id: 'file_id',
              name: 'File UUID',
            },
            {
              id: 'submitter_id',
              name: 'File Submitter ID',
            },
            {
              id: 'access',
              name: 'Access',
            },
            {
              id: 'file_name',
              name: 'File Name',
            },
            {
              id: 'cases.project.project_id',
              name: 'Project',
            },
            {
              id: 'data_category',
              name: 'Data Category',
            },
            {
              id: 'data_format',
              name: 'Data Format',
            },
            {
              id: 'file_size',
              name: 'Size',
            },
          ]}
        />
      </Row>

                <AddToCartButtonAll
                  edges={props.hits.edges.map(e => e.node)}
                  total={props.hits.total}
                />

              Access
              Name
              Cases
              Projects
              Category
              Format
              Size

            {props.hits.edges.map((e, i) => (
              <FileTr node={e.node} key={e.node.id} index={i} />
          ))}

      <Pagination prefix={prefix} params={props.relay.route.params} total={props.hits.total} />

  );
};

export const FileTableQuery = {
  fragments: {
    hits: () => Relay.QL`
      fragment on FileConnection {
        total
        edges {
          node {
            id
            file_id
            file_name
            file_size
            access
            data_category
            data_format
            cases {
              hits(first: 99) {
                edges {
                  node {
                    project {
                      project_id
                    }
                  }
                }
              }
            }
          }
        }
      }
    `,
  },
};

const FileTable = Relay.createContainer(
  FileTableComponent,
  FileTableQuery
);

export default FileTable;
<commit_msg>🐛 add total back for file table<commit_after>/* @flow */

import React from 'react';
import Relay from 'react-relay';

import Pagination from '@ncigdc/components/Pagination';
import Showing from '@ncigdc/components/Pagination/Showing';
import AddToCartButtonAll from '@ncigdc/components/AddToCartButtonAll';
import { Row } from '@ncigdc/uikit/Flex';
import TableActions from '@ncigdc/components/TableActions';

import { Tr, Th } from '@ncigdc/uikit/Table';

import FileTr from './FileTr';

import type { TTableProps } from './types';

const styles = {
  table: {
    width: '100%',
    borderCollapse: 'collapse',
    borderSpacing: 0,
  },
};

export const FileTableComponent = (props: TTableProps) => {
  const prefix = 'files';

  return (

      <Row style={{ backgroundColor: 'white', padding: '1rem', justifyContent: 'space-between' }}>
        <Showing
          docType="files"
          prefix={prefix}
          params={props.relay.route.params}
          total={props.hits.total}
        />
        <TableActions
          prefix={prefix}
          total={props.hits.total}
          sortKey="files_sort"
          endpoint={`${API}/files`}
          downloadable={props.downloadable}
          downloadFields={[
            'file_id',
            'file_name',
            'cases.project.project_id',
            'data_category',
            'data_format',
            'file_size',
          ]}
          sortOptions={[
            {
              id: 'file_id',
              name: 'File UUID',
            },
            {
              id: 'submitter_id',
              name: 'File Submitter ID',
            },
            {
              id: 'access',
              name: 'Access',
            },
            {
              id: 'file_name',
              name: 'File Name',
            },
            {
              id: 'cases.project.project_id',
              name: 'Project',
            },
            {
              id: 'data_category',
              name: 'Data Category',
            },
            {
              id: 'data_format',
              name: 'Data Format',
            },
            {
              id: 'file_size',
              name: 'Size',
            },
          ]}
        />
      </Row>

                <AddToCartButtonAll
                  edges={props.hits.edges.map(e => e.node)}
                  total={props.hits.total}
                />

              Access
              Name
              Cases
              Projects
              Category
              Format
              Size

            {props.hits.edges.map((e, i) => (
              <FileTr node={e.node} key={e.node.id} index={i} />
          ))}

      <Pagination prefix={prefix} params={props.relay.route.params} total={props.hits.total} />

  );
};

export const FileTableQuery = {
  fragments: {
    hits: () => Relay.QL`
      fragment on FileConnection {
        total
        edges {
          node {
            id
            file_id
            file_name
            file_size
            access
            data_category
            data_format
            cases {
              hits(first: 99) {
                total
                edges {
                  node {
                    project {
                      project_id
                    }
                  }
                }
              }
            }
          }
        }
      }
    `,
  },
};

const FileTable = Relay.createContainer(
  FileTableComponent,
  FileTableQuery
);

export default FileTable;
<|endoftext|>


<commit_before>
Template.chartDisplay.onCreated(function() {
	this.myChart = new ReactiveVar(new Chartist.Line()); // setting mychart as a variable of the template, so that i can reference it to update it later.

	query = {"recordDate": Session.get("todayDate")};
	myUUID = this.data.deviceUUID;
	Session.setPersistent(myUUID+"query", query);
	// console.log(myUUID);
	Meteor.call('publishCollection',myUUID, function(error, result){
	});
	//using package to check if collection exist
	if(!Mongo.Collection.get(this.data.deviceUUID)){
		SensorDatabase = new Meteor.Collection(myUUID);
	}else{
		SensorDatabase = Mongo.Collection.get(myUUID);
	}
	Tracker.autorun(function () {
	  Meteor.subscribe(myUUID, Session.get(myUUID+"query"));
	});

	// console.log(SensorDatabase.find().fetch());
});

Template.chartDisplay.helpers({

	getDb: function(){
		// console.log(Images.find());
		console.log(SensorDatabase.find().fetch());
		return SensorDatabase.find();
	},
	getCurrent: function(sensorType){
		return Session.get("RTData" + sensorType);
	},
	setDate: function(){
		var timeCheck = new Date();
		var curr_date = timeCheck.getDate();
		var curr_month = timeCheck.getMonth() + 1;
		var curr_year = timeCheck.getFullYear();
		var yearMonthDay = curr_year + '-' +
		                   curr_month + '-' +
		                   curr_date;
		Session.set("todayDate", yearMonthDay);
	},
	setSensorType: function(sensorType){
		// console.log("my sensor type is " + sensorType);
		var timeObj; // time stamp from the db
		var numData;
		var interval;
		var dataArr;
		var timeArr = [];// the time array that will be used to plot the graph
		var currentDoc;
		if(sensorType === "Ambient Temperature") {
			currentDoc = SensorDatabase.find({"SensorType":"ambTemp"}).fetch();//if i don't put .fetch, it returns me the full collection.0
		}else if(sensorType === "Humidity") {
			currentDoc = SensorDatabase.find({"SensorType":"HDCHumidity"}).fetch();//if i don't put .fetch, it returns me the full collection.0
		}else if(sensorType === "Light") {
			currentDoc = SensorDatabase.find({"SensorType":"lux"}).fetch();
		}else if(sensorType === "Battery Temperature") {
			currentDoc = SensorDatabase.find({"SensorType":"battTemp"}).fetch();
		}else if(sensorType === "Air pressure") {
			currentDoc = SensorDatabase.find({"SensorType":"airPressure"}).fetch();
		}else if(sensorType === "Battery Voltage") {
			currentDoc = SensorDatabase.find({"SensorType":"battLvl"}).fetch();
		}else if(sensorType === "gyroX") {
			currentDoc = SensorDatabase.find({"SensorType":"gyroX"}).fetch();
		}else if(sensorType === "gyroY") {
			currentDoc = SensorDatabase.find({"SensorType":"gyroY"}).fetch();
		}else if(sensorType === "gyroZ") {
			currentDoc = SensorDatabase.find({"SensorType":"gyroZ"}).fetch();
		}else if(sensorType === "accX") {
			currentDoc = SensorDatabase.find({"SensorType":"accX"}).fetch();
		}else if(sensorType === "accY") {
			currentDoc = SensorDatabase.find({"SensorType":"accY"}).fetch();
		}else if(sensorType === "accZ") {
			currentDoc = SensorDatabase.find({"SensorType":"accZ"}).fetch();
		}
		// console.log(currentDoc);
		// console.log(sensorType);
		if(currentDoc.length !== 0) {
			// console.log(currentDoc.length);
			interval = currentDoc[0].interval;
			timeObj = new Date(currentDoc[0].timestamp);
			dataArr = currentDoc[0].SensorData;
			numData = currentDoc[0].numData;
			Session.setPersistent("RTData"+sensorType, dataArr[dataArr.length-1]);
			Session.setPersistent("Unit"+sensorType, currentDoc[0].unit);
		}
		// console.log(dataObjArr);
		Session.setPersistent(sensorType+'CurrData', dataArr);
		//console.log(Session.get(sensorType+'CurrData'));
		// console.log("number of data is " + numData);
		// console.log(timeObj.getHours() + ":" + timeObj.getMinutes());
		for (var i=0; i<numData; i++){
			timeObj.setSeconds(timeObj.getSeconds() + interval);
			timeArr.push(timeObj.getHours() + ":" + timeObj.getMinutes());
		}
		Session.setPersistent(sensorType+'time', timeArr);
		// console.log("time in seSetnsorType" + Session.get('time'));
	},
	updateChart: function(sensorType) {
		var t = Session.get(sensorType+'time');
	 	var s = Session.get(sensorType+'CurrData');
	 	// console.log("t is " + t);
	 	// console.log("s is " + s);
		var data = {
		  // A labels array that can contain any sort of values
		  labels: t,
		  // Our series array that contains series objects or in this case series data arrays
		  series: [
		    s
		  ]
		};
		if(s === undefined) {
			console.log("still fetching data from collection");

		}else{
			Template.instance().myChart.get().update(data);
		}

	},
	//this function is needed because somehow the chartist doesn't play well with spaces in id.
	removeSpace: function(string) {
		return string.replace(/\s+/g, '');
	},
	getUnit: function(sensorType){
		return Session.get("Unit"+sensorType);
	}
});

Template.chartDisplay.onRendered(function(){
	var t = Session.get(this.data.sensorType+'time');
 	var s = Session.get(this.data.sensorType+'CurrData');
	var data = {
	  // A labels array that can contain any sort of values
	  labels: [0,1,2,3,4],
	  // Our series array that contains series objects or in this case series data arrays
	  series: [
	    [0, 0, 0, 0, 0]
	  ]
	};
	var options = {
	  // Don't draw the line chart points
	  showPoint: false,
	  // Disable line smoothing
	  lineSmooth: true,
	  // X-Axis specific configuration
	  updateOnData : true,
	  axisX: {
	    // We can disable the grid for this axis
	    showGrid: true,
	    // and also don't show the label
	    showLabel: true,
	    //this function below allows us to skip labels for the x axis such that we do not display every domination and cluster the x-axis
	    labelInterpolationFnc: function skipLabels(value, index) {
	      return index % 60  === 0 ? value : null;
	    }
	  },
	  // Y-Axis specific configuration
	  axisY: {
	    // Lets offset the chart a bit from the labels
	    offset: 60,
	    // The label interpolation function enables you to modify the values
	    // used for the labels on each axis. Here we are converting the
	    // values into million pound.
	    labelInterpolationFnc: function(value) {
	      return value;
	    }
	  }
	};
	var currid = '#'+this.data.sensorType.replace(/\s+/g, '');
	Template.instance().myChart.set(new Chartist.Line(currid, data, options));

});<commit_msg>bug fixes<commit_after>
Template.chartDisplay.onCreated(function() {
	this.myChart = new ReactiveVar(new Chartist.Line()); // setting mychart as a variable of the template, so that i can reference it to update it later.

	query = {"recordDate": Session.get("todayDate")};
	myUUID = this.data.deviceUUID;
	Session.setPersistent(myUUID+"query", query);
	// console.log(myUUID);
	Meteor.call('publishCollection',myUUID, function(error, result){
	});
	//using package to check if collection exist
	if(!Mongo.Collection.get(this.data.deviceUUID)){
		SensorDatabase = new Meteor.Collection(myUUID);
	}else{
		SensorDatabase = Mongo.Collection.get(myUUID);
	}
	Tracker.autorun(function () {
	  Meteor.subscribe(myUUID, Session.get(myUUID+"query"));
	});

	// console.log(SensorDatabase.find().fetch());
});

Template.chartDisplay.helpers({

	getDb: function(){
		// console.log(Images.find());
		console.log(SensorDatabase.find().fetch());
		return SensorDatabase.find();
	},
	getCurrent: function(sensorType){
		return Session.get("RTData" + sensorType);
	},
	setDate: function(){
		var timeCheck = new Date("2015-07-29T10:06:55.531Z");
		var curr_date = timeCheck.getDate();
		var curr_month = timeCheck.getMonth() + 1;
		var curr_year = timeCheck.getFullYear();
		var yearMonthDay = curr_year + '-' +
		                   curr_month + '-' +
		                   curr_date;
		Session.set("todayDate", yearMonthDay);
	},
	setSensorType: function(sensorType){
		// console.log("my sensor type is " + sensorType);
		var timeObj; // time stamp from the db
		var numData;
		var interval;
		var dataArr;
		var timeArr = [];// the time array that will be used to plot the graph
		var currentDoc;
		if(sensorType === "Ambient Temperature") {
			currentDoc = SensorDatabase.find({"SensorType":"ambTemp"}).fetch();//if i don't put .fetch, it returns me the full collection.0
		}else if(sensorType === "Humidity") {
			currentDoc = SensorDatabase.find({"SensorType":"HDCHumidity"}).fetch();//if i don't put .fetch, it returns me the full collection.0
		}else if(sensorType === "Light") {
			currentDoc = SensorDatabase.find({"SensorType":"lux"}).fetch();
		}else if(sensorType === "Battery Temperature") {
			currentDoc = SensorDatabase.find({"SensorType":"battTemp"}).fetch();
		}else if(sensorType === "Air pressure") {
			currentDoc = SensorDatabase.find({"SensorType":"airPressure"}).fetch();
		}else if(sensorType === "Battery Voltage") {
			currentDoc = SensorDatabase.find({"SensorType":"battLvl"}).fetch();
		}else if(sensorType === "gyroX") {
			currentDoc = SensorDatabase.find({"SensorType":"gyroX"}).fetch();
		}else if(sensorType === "gyroY") {
			currentDoc = SensorDatabase.find({"SensorType":"gyroY"}).fetch();
		}else if(sensorType === "gyroZ") {
			currentDoc = SensorDatabase.find({"SensorType":"gyroZ"}).fetch();
		}else if(sensorType === "accX") {
			currentDoc = SensorDatabase.find({"SensorType":"accX"}).fetch();
		}else if(sensorType === "accY") {
			currentDoc = SensorDatabase.find({"SensorType":"accY"}).fetch();
		}else if(sensorType === "accZ") {
			currentDoc = SensorDatabase.find({"SensorType":"accZ"}).fetch();
		}
		// console.log(currentDoc);
		// console.log(sensorType);
		if(currentDoc.length !== 0) {
			// console.log(currentDoc.length);
			interval = currentDoc[0].interval;
			timeObj = new Date(currentDoc[0].timestamp);
			dataArr = currentDoc[0].SensorData;
			numData = currentDoc[0].numData;
			Session.setPersistent("RTData"+sensorType, dataArr[dataArr.length-1]);
			Session.setPersistent("Unit"+sensorType, currentDoc[0].unit);
		}
		// console.log(dataObjArr);
		Session.setPersistent(sensorType+'CurrData', dataArr);
		//console.log(Session.get(sensorType+'CurrData'));
		// console.log("number of data is " + numData);
		// console.log(timeObj.getHours() + ":" + timeObj.getMinutes());
		for (var i=0; i<numData; i++){
			timeObj.setSeconds(timeObj.getSeconds() + interval);
			timeArr.push(timeObj.getHours() + ":" + timeObj.getMinutes());
		}
		Session.setPersistent(sensorType+'time', timeArr);
		// console.log("time in seSetnsorType" + Session.get('time'));
	},
	updateChart: function(sensorType) {
		var t = Session.get(sensorType+'time');
	 	var s = Session.get(sensorType+'CurrData');
	 	// console.log("t is " + t);
	 	// console.log("s is " + s);
		var data = {
		  // A labels array that can contain any sort of values
		  labels: t,
		  // Our series array that contains series objects or in this case series data arrays
		  series: [
		    s
		  ]
		};
		if(s === undefined) {
			console.log("still fetching data from collection");

		}else{
			Template.instance().myChart.get().update(data);
		}

	},
	//this function is needed because somehow the chartist doesn't play well with spaces in id.
	removeSpace: function(string) {
		return string.replace(/\s+/g, '');
	},
	getUnit: function(sensorType){
		return Session.get("Unit"+sensorType);
	}
});

Template.chartDisplay.onRendered(function(){
	var t = Session.get(this.data.sensorType+'time');
 	var s = Session.get(this.data.sensorType+'CurrData');
	var data = {
	  // A labels array that can contain any sort of values
	  labels: [0,1,2,3,4],
	  // Our series array that contains series objects or in this case series data arrays
	  series: [
	    [0, 0, 0, 0, 0]
	  ]
	};
	var options = {
	  // Don't draw the line chart points
	  showPoint: false,
	  // Disable line smoothing
	  lineSmooth: true,
	  // X-Axis specific configuration
	  updateOnData : true,
	  axisX: {
	    // We can disable the grid for this axis
	    showGrid: true,
	    // and also don't show the label
	    showLabel: true,
	    //this function below allows us to skip labels for the x axis such that we do not display every domination and cluster the x-axis
	    labelInterpolationFnc: function skipLabels(value, index) {
	      return index % 60  === 0 ? value : null;
	    }
	  },
	  // Y-Axis specific configuration
	  axisY: {
	    // Lets offset the chart a bit from the labels
	    offset: 60,
	    // The label interpolation function enables you to modify the values
	    // used for the labels on each axis. Here we are converting the
	    // values into million pound.
	    labelInterpolationFnc: function(value) {
	      return value;
	    }
	  }
	};
	var currid = '#'+this.data.sensorType.replace(/\s+/g, '');
	Template.instance().myChart.set(new Chartist.Line(currid, data, options));

});<|endoftext|>


<commit_before>var toIntegerOrInfinity = require('../internals/to-integer-or-infinity');
var toString = require('../internals/to-string');
var requireObjectCoercible = require('../internals/require-object-coercible');

// `String.prototype.codePointAt` methods implementation
var createMethod = function (CONVERT_TO_STRING) {
  return function ($this, pos) {
    var S = toString(requireObjectCoercible($this));
    var position = toIntegerOrInfinity(pos);
    var size = S.length;
    var first, second;
    if (position < 0 || position >= size) return CONVERT_TO_STRING ? '' : undefined;
    first = S.charCodeAt(position);
    return first < 0xD800 || first > 0xDBFF || position + 1 === size
      || (second = S.charCodeAt(position + 1)) < 0xDC00 || second > 0xDFFF
        ? CONVERT_TO_STRING ? S.charAt(position) : first
        : CONVERT_TO_STRING ? S.slice(position, position + 2) : (first - 0xD800 << 10) + (second - 0xDC00) + 0x10000;
  };
};

module.exports = {
  // `String.prototype.codePointAt` method
  // https://tc39.es/ecma262/#sec-string.prototype.codepointat
  codeAt: createMethod(false),
  // `String.prototype.at` method
  // https://github.com/mathiasbynens/String.prototype.at
  charAt: createMethod(true)
};
<commit_msg>remove an obsolete comment<commit_after>var toIntegerOrInfinity = require('../internals/to-integer-or-infinity');
var toString = require('../internals/to-string');
var requireObjectCoercible = require('../internals/require-object-coercible');

var createMethod = function (CONVERT_TO_STRING) {
  return function ($this, pos) {
    var S = toString(requireObjectCoercible($this));
    var position = toIntegerOrInfinity(pos);
    var size = S.length;
    var first, second;
    if (position < 0 || position >= size) return CONVERT_TO_STRING ? '' : undefined;
    first = S.charCodeAt(position);
    return first < 0xD800 || first > 0xDBFF || position + 1 === size
      || (second = S.charCodeAt(position + 1)) < 0xDC00 || second > 0xDFFF
        ? CONVERT_TO_STRING ? S.charAt(position) : first
        : CONVERT_TO_STRING ? S.slice(position, position + 2) : (first - 0xD800 << 10) + (second - 0xDC00) + 0x10000;
  };
};

module.exports = {
  // `String.prototype.codePointAt` method
  // https://tc39.es/ecma262/#sec-string.prototype.codepointat
  codeAt: createMethod(false),
  // `String.prototype.at` method
  // https://github.com/mathiasbynens/String.prototype.at
  charAt: createMethod(true)
};
<|endoftext|>


<commit_before>(function(factory) {

	'use strict';

	if (typeof define === 'function' && define.amd) {

		// AMD. Register as an anonymous module.
		define(['jquery'], factory);

	} else {

		// Browser globals
		factory(jQuery);

	}

}(function($) {

	'use strict';

	var defaults = {
		clearOnFail: false
	};

	// The prototype for ajaxQueue instances.
	var qPrototype = {

		add: function(request) {

			// Create a new Deferred for this request and add it into the
			// queue.
			this.queue.push(getDfd.call(this, request));

			return this;

		}

	};

	// Create a Deferred object for this request. We need to store a
	// Deferred for this request in the queue so if additional requests
	// come in, they will not be run until the Deferred we are creating
	// right now is finished. This is what enables the requests to run
	// in order.
	var getDfd = function(request) {

		return $.Deferred(function(dfd) {

			var queuedDfd;
			var qLen = this.queue.length;

			if (qLen) {

				// Get the Deferred for the previous queued request.
				queuedDfd = this.queue[qLen - 1];

				// When the previous queued request is finished, run this one.
				$.when(queuedDfd).always(function() {

					// Remove the previous queued Deferred.
					this.queue.shift();

					processRequest.call(this, request, dfd);

				}.bind(this));

			} else {

				// This is the first request for this queue, so
				// immediately run the request.

				processRequest.call(this, request, dfd);

			}

		}.bind(this));

	};

	// Run the request and resolve/reject its queued Deferred when done.
	var processRequest = function(request, dfd) {

		request()
			// Resolve so the next request in line will run.
			.done(dfd.resolve)
			.fail(function() {

				if (this.options.clearOnFail) {

					// Clear out the queue.
					this.queue.length = 0;

				}

				// Reject the requests queued Deferred.
				dfd.reject();

			}.bind(this));

	};

	var ajaxQueue = function(options) {

		// Create a new ajaxQueue instance. The prototype of each instance
		// points to the same object (qPrototype).
		var q = Object.create(qPrototype);

		// Create an array that will store Deferreds representing the status
		// of each request that is added via the .add() method.
		q.queue = [];

		q.options = $.extend(true, {}, defaults, options);

		// Return the new instance.
		return q;

	};

	// Add this utility to the jQuery namespace.
	$.extend({
		ajaxQueue: ajaxQueue
	});

}));<commit_msg>Add Browserify support to UMD wrapper<commit_after>(function(factory) {

	'use strict';

	if (typeof define === 'function' && define.amd) {

		// AMD. Register as an anonymous module.
		define(['jquery'], factory);

	} else if (typeof exports === 'object') {

		// Node/CommonJS style for Browserify
		module.exports = factory(require('jquery'));

	} else {

		// Browser globals
		factory(jQuery);

	}

}(function($) {

	'use strict';

	var defaults = {
		clearOnFail: false
	};

	// The prototype for ajaxQueue instances.
	var qPrototype = {

		add: function(request) {

			// Create a new Deferred for this request and add it into the
			// queue.
			this.queue.push(getDfd.call(this, request));

			return this;

		}

	};

	// Create a Deferred object for this request. We need to store a
	// Deferred for this request in the queue so if additional requests
	// come in, they will not be run until the Deferred we are creating
	// right now is finished. This is what enables the requests to run
	// in order.
	var getDfd = function(request) {

		return $.Deferred(function(dfd) {

			var queuedDfd;
			var qLen = this.queue.length;

			if (qLen) {

				// Get the Deferred for the previous queued request.
				queuedDfd = this.queue[qLen - 1];

				// When the previous queued request is finished, run this one.
				$.when(queuedDfd).always(function() {

					// Remove the previous queued Deferred.
					this.queue.shift();

					processRequest.call(this, request, dfd);

				}.bind(this));

			} else {

				// This is the first request for this queue, so
				// immediately run the request.

				processRequest.call(this, request, dfd);

			}

		}.bind(this));

	};

	// Run the request and resolve/reject its queued Deferred when done.
	var processRequest = function(request, dfd) {

		request()
			// Resolve so the next request in line will run.
			.done(dfd.resolve)
			.fail(function() {

				if (this.options.clearOnFail) {

					// Clear out the queue.
					this.queue.length = 0;

				}

				// Reject the requests queued Deferred.
				dfd.reject();

			}.bind(this));

	};

	var ajaxQueue = function(options) {

		// Create a new ajaxQueue instance. The prototype of each instance
		// points to the same object (qPrototype).
		var q = Object.create(qPrototype);

		// Create an array that will store Deferreds representing the status
		// of each request that is added via the .add() method.
		q.queue = [];

		q.options = $.extend(true, {}, defaults, options);

		// Return the new instance.
		return q;

	};

	// Add this utility to the jQuery namespace.
	$.extend({
		ajaxQueue: ajaxQueue
	});

}));
<|endoftext|>


<commit_before>import React from 'react'
import Button from '../Button'
import './styles.scss'
import _debounce from 'lodash/debounce'

/**
 * SearchBox
 */
class SearchBox extends React.Component {

  constructor(props) {
    super(props)
    this.state = {
      inputValue: ''
    }

    this.liveSearch = _debounce(this.liveSearch, props.debounce)
  }

  updateValue = evt => {
    this.setState({inputValue: evt.target.value})
  }

  liveSearch = () => {
    const value = this.state.inputValue
    if (value && value.length >= this.props.minInputLength) {
      this.props.onSearch(value)
    }
  }

  explicitSearch = () => {
    const value = this.state.inputValue
    this.props.onSearch(value)
  }

  keyDownHandler = evt => {
    if (this.props.liveSearch) {
      this.liveSearch()
    } else if (evt.key === 'Enter') {
      this.explicitSearch()
    }
  }

  render() {
    return (

            <input
              type="text"
              className="form-control"
              onKeyDown={this.keyDownHandler}
              placeholder={this.props.placeholder}
              value={this.state.inputValue}
              onChange={this.updateValue}
             />

              <Button
                type="button"
                onClick={this.explicitSearch}
                icon="glyphicon-search"
              />

    )
  }
}

SearchBox.defaultProps = {
  debounce: 200,
  minInputLength: 3
}

SearchBox.propTypes = {
  /**
   * Function that will be triggered. The input value will be passed as argument.
   */
  onSearch: React.PropTypes.func.isRequired,
  /**
   * Placeholder of the input field.
   */
  placeholder: React.PropTypes.string,
  /**
   * If true, the `onSearch` function will be triggered on the fly.
   */
  liveSearch: React.PropTypes.bool,
  /**
   * Amount of milli seconds before the next search will be invoked. The default is set to `200`.
   * Can be used to reduce the amount of search requests in the live search.
   * This property is only considered if the `liveSearch` property is set to true.
   */
  debounce: React.PropTypes.number,
  /**
   * Amount of minimum characters before the search starts. The default is set to `3`.
   * This property is only considered if the `liveSearch` property is set to true.
   */
  minInputLength: React.PropTypes.number
}

export default SearchBox
<commit_msg>refactor(tocco-ui): call the onSearch function also if the value is empty<commit_after>import React from 'react'
import Button from '../Button'
import './styles.scss'
import _debounce from 'lodash/debounce'

/**
 * SearchBox
 */
class SearchBox extends React.Component {

  constructor(props) {
    super(props)
    this.state = {
      inputValue: ''
    }

    this.liveSearch = _debounce(this.liveSearch, props.debounce)
  }

  updateValue = evt => {
    this.setState({inputValue: evt.target.value})
  }

  liveSearch = () => {
    const value = this.state.inputValue
    if (value.length === 0 || value.length >= this.props.minInputLength) {
      this.props.onSearch(value)
    }
  }

  explicitSearch = () => {
    const value = this.state.inputValue
    this.props.onSearch(value)
  }

  keyDownHandler = evt => {
    if (this.props.liveSearch) {
      this.liveSearch()
    } else if (evt.key === 'Enter') {
      this.explicitSearch()
    }
  }

  render() {
    return (

            <input
              type="text"
              className="form-control"
              onKeyDown={this.keyDownHandler}
              placeholder={this.props.placeholder}
              value={this.state.inputValue}
              onChange={this.updateValue}
             />

              <Button
                type="button"
                onClick={this.explicitSearch}
                icon="glyphicon-search"
              />

    )
  }
}

SearchBox.defaultProps = {
  debounce: 200,
  minInputLength: 3
}

SearchBox.propTypes = {
  /**
   * Function that will be triggered. The input value will be passed as argument.
   */
  onSearch: React.PropTypes.func.isRequired,
  /**
   * Placeholder of the input field.
   */
  placeholder: React.PropTypes.string,
  /**
   * If true, the `onSearch` function will be triggered on the fly.
   */
  liveSearch: React.PropTypes.bool,
  /**
   * Amount of milli seconds before the next search will be invoked. The default is set to `200`.
   * Can be used to reduce the amount of search requests in the live search.
   * This property is only considered if the `liveSearch` property is set to true.
   */
  debounce: React.PropTypes.number,
  /**
   * Amount of minimum characters before the search starts. The default is set to `3`.
   * This property is only considered if the `liveSearch` property is set to true.
   */
  minInputLength: React.PropTypes.number
}

export default SearchBox
<|endoftext|>


<commit_before>$(document).ready(function() {

    //Landing Page Display
    // $("#login-page-buttons").click(function() {
    //     // $("#logout-button").show();
    //     $("#login-button-text").hide();
    //     $('#login-complete').show();
    //   });
    // $("#login-page-buttons").click(function() {
    //     // $("#logout-button").show();
    //     $("#login-button-text").hide();
    //     $('#login-complete').show();
    //   });

    ////////////Login / Register Helper Fucntions

    var handleError = function handleError(error, data, optional_alert) {
      if (error) {
        console.error(error);
        if(optional_alert){
          optional_alert();
        }
        throw error;
      } else {
        console.log(data);
      }
    };

    var form2object = function(form) {
        var data = {};
        $(form).find('input').each(function(index, element) {
            var type = $(this).attr('type');
            if ($(this).attr('name') && type !== 'submit' && type !== 'hidden') {
                data[$(this).attr('name')] = $(this).val();
            }
        });
        return data;
    };

    var wrap = function wrap(root, formData) {
        var wrapper = {};
        wrapper[root] = formData;
        return wrapper;
    };

    /////////////////////Register and Login/Logout Click Handlers

    ////Register

    $('#reg-form').on('submit', function(e) {
        e.preventDefault();
        var credentials = form2object(this);
        console.log(credentials);
        bucketList_api.signup(credentials, function(err, data) {
            handleError(err, data, function() {
                alert("Invalid credentials");
             });
            // $('.register').hide();
            $('#reg-popup').modal('hide');
            $('.modal-backdrop').remove();
            // $('#login_form').css('margin', '0px auto');

        });

    });

    // Login
    $('#login-form').on('submit', function(e) {
        var credentials = form2object(this);
        bucketList_api.login(credentials, function(err, data) {
            handleError(err, data, function() {
                alert("Invalid credentials");
            });
            $('#login-popup').modal('hide');
            $('.modal-backdrop').remove();
            $('#logout-button-text').show();
        });
        e.preventDefault();
    });

    // Logout
    $('#logout-button-text').on('click', function(e) {
        bucketList_api.logout(function(err, data) {
            handleError(err, data);
            console.log("logged out");
            $('#logout-button-text').hide();
        });
        e.preventDefault();
    });
    $('#show-activity-list').on('click', function(e){
        e.preventDefault();
        bucketList_api.showList(function(err, data){
            handleError(err,data);
            data.title.forEach(function(id){
              $('#activity-table tr:last').after('
' + id +  '	' + id + '
');
            });
        });
    });

});
<commit_msg>PG Updating to pull.<commit_after>$(document).ready(function() {

    //Landing Page Display
    // $("#login-page-buttons").click(function() {
    //     // $("#logout-button").show();
    //     $("#login-button-text").hide();
    //     $('#login-complete').show();
    //   });
    // $("#login-page-buttons").click(function() {
    //     // $("#logout-button").show();
    //     $("#login-button-text").hide();
    //     $('#login-complete').show();
    //   });

    ////////////Login / Register Helper Fucntions

    var handleError = function handleError(error, data, optional_alert) {
        if (error) {
            console.error(error);
            if (optional_alert) {
                optional_alert();
            }
            throw error;
        } else {
            console.log(data);
        }
    };

    var form2object = function(form) {
        var data = {};
        $(form).find('input').each(function(index, element) {
            var type = $(this).attr('type');
            if ($(this).attr('name') && type !== 'submit' && type !== 'hidden') {
                data[$(this).attr('name')] = $(this).val();
            }
        });
        return data;
    };

    var wrap = function wrap(root, formData) {
        var wrapper = {};
        wrapper[root] = formData;
        return wrapper;
    };

    /////////////////////Register and Login/Logout Click Handlers

    ////Register

    $('#reg-form').on('submit', function(e) {
        e.preventDefault();
        var credentials = form2object(this);
        console.log(credentials);
        bucketList_api.signup(credentials, function(err, data) {
            handleError(err, data, function() {
                alert("Invalid credentials");
             });
            // $('.register').hide();
            $('#reg-popup').modal('hide');
            $('.modal-backdrop').remove();
            });
            $('.register').hide();
            // $('#login_form').css('margin', '0px auto');

        });

    });

    // Login
    $('#login-form').on('submit', function(e) {
        var credentials = form2object(this);
        bucketList_api.login(credentials, function(err, data) {
            handleError(err, data, function() {
                alert("Invalid credentials");
            });
            $('#login-popup').modal('hide');
            $('.modal-backdrop').remove();
            $('#logout-button-text').show();
        });
        e.preventDefault();
    });

    // Logout
    $('#logout-button-text').on('click', function(e) {
        bucketList_api.logout(function(err, data) {
            handleError(err, data);
            console.log("logged out");
            $('#logout-button-text').hide();
        });
        e.preventDefault();
    });
    $('#show-activity-list').on('click', function(e){
        e.preventDefault();
        bucketList_api.showList(function(err, data){
            handleError(err,data);
            data.title.forEach(function(id){
              $('#activity-table tr:last').after('
' + id +  '	' + id + '
');
            });
        });

});
<|endoftext|>


<commit_before>//Power is connected to pin4 (5V), ground is pin6, tx (output) is pin 8,
// rx (input) is pin10
var emic
var SerialPort = require('serialport').SerialPort;
console.log('Successfully loaded SerialPort module');

var serialPort = new SerialPort('/dev/ttyAMA0', {
	baudRate: 9600
});
console.log('Successfully initialised /dev/ttyAMA0');

serialPort.on('open', function () {
	console.log('Port is open')
	serialPort.on('data', function(msg) {
		console.log(msg.toString('ascii'));
	});
	serialPort.write(':SHello World to all\r');
});

emic.speak = function (data) {
	data = data.toString('ascii');
	if (data.length > 1000) {
		console.log('Error: Message exceeds the character limit');
	} else {
		serialPort.write(':S'+ data + '\r');
	};
};

emic.demo = function (id) {
	id = id.toString('ascii');
	if (id == '0' || id == '1' || id == '2') {
		serialPort.write(':D' + id + '\r');
	} else {
		console.log('Error: Invalid Command');
	};
};

emic.stopNow = function () {
	serialPort.write(':X\r');
}

emic.pause = function () {
	serialPort.write(':Z\r');
};

emic.voice = function (id) {
	var idN = id.parseInt();
	if (idN >= 0 && idN <= 8) {
		id.toString('ascii');
		serialPort.write(':N' + id + '\r');
	} else {
		console.log('Error: Invalid Command');
	};
};

emic.volume = function (level) {
	var levelN = id.parseInt();
	if (levelN >= -48 && levelN <= 18) {
		level = level.toString('ascii');
		serialPort.write(':V' + level + '\r');
	} else {
		console.log('Error: Invalid Command');
	};
};

emic.rate = function (wpm) {
	var wpmN = wpm.parseInt();
	if (wpmN >= 75 && wpmN <= 600) {
		wpm = wpm.toString('ascii');
		serialPort.write(':W' + wpm + '\r');
	} else {
		console.log('Error: Invalid Command');
	};
};

emic.parser = function (id) {
	id = id.toString('ascii');
	if (parser == '0' || parser == '1' || parser == '2') {
		serialPort.write(':P' + id + '\r');
	} else {
		console.log('Error: Invalid Command');
	};
};

emic.revert = function () {
	serialPort.write(':R\r');
};

emic.callCurrentSettings = function () {
	serialPort.write(':C\r');
};

emic.callVersionInfo = function () {
	serialPort.write(':I\r');
};

emic.callCommands = function () {
	serialPort.write(':I\r');
};

/*function writeLog(logFile, output){
	var logf = new File(logFile);
	logf.writeln(output);
	logf.close()*/

module.exports = emic;

<commit_msg>Update<commit_after>//Power is connected to pin4 (5V), ground is pin6, tx (output) is pin 8,
// rx (input) is pin10
var SerialPort = require('serialport').SerialPort;
console.log('Successfully loaded SerialPort module');

var serialPort = new SerialPort('/dev/ttyAMA0', {
	baudRate: 9600
});
console.log('Successfully initialised /dev/ttyAMA0');

serialPort.on('open', function () {
	console.log('Port is open')
	serialPort.on('data', function(msg) {
		console.log(msg.toString('ascii'));
	});
	serialPort.write(':SHello World to all\r');
});

var emic = (function() {

emic.speak = function (data) {
	data = data.toString('ascii');
	if (data.length > 1000) {
		console.log('Error: Message exceeds the character limit');
	} else {
		serialPort.write(':S'+ data + '\r');
	};
};

emic.demo = function (id) {
	id = id.toString('ascii');
	if (id == '0' || id == '1' || id == '2') {
		serialPort.write(':D' + id + '\r');
	} else {
		console.log('Error: Invalid Command');
	};
};

emic.stopNow = function () {
	serialPort.write(':X\r');
}

emic.pause = function () {
	serialPort.write(':Z\r');
};

emic.voice = function (id) {
	var idN = id.parseInt();
	if (idN >= 0 && idN <= 8) {
		id.toString('ascii');
		serialPort.write(':N' + id + '\r');
	} else {
		console.log('Error: Invalid Command');
	};
};

emic.volume = function (level) {
	var levelN = id.parseInt();
	if (levelN >= -48 && levelN <= 18) {
		level = level.toString('ascii');
		serialPort.write(':V' + level + '\r');
	} else {
		console.log('Error: Invalid Command');
	};
};

emic.rate = function (wpm) {
	var wpmN = wpm.parseInt();
	if (wpmN >= 75 && wpmN <= 600) {
		wpm = wpm.toString('ascii');
		serialPort.write(':W' + wpm + '\r');
	} else {
		console.log('Error: Invalid Command');
	};
};

emic.parser = function (id) {
	id = id.toString('ascii');
	if (parser == '0' || parser == '1' || parser == '2') {
		serialPort.write(':P' + id + '\r');
	} else {
		console.log('Error: Invalid Command');
	};
};

emic.revert = function () {
	serialPort.write(':R\r');
};

emic.callCurrentSettings = function () {
	serialPort.write(':C\r');
};

emic.callVersionInfo = function () {
	serialPort.write(':I\r');
};

emic.callCommands = function () {
	serialPort.write(':I\r');
};
});

/*function writeLog(logFile, output){
	var logf = new File(logFile);
	logf.writeln(output);
	logf.close()*/

module.exports = emic;

<|endoftext|>


<commit_before>/*******************************************************************************
 * Copyright (c) 2014, 2016  IBM Corporation, Carnegie Mellon University and others
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *******************************************************************************/

$hulop.fp = (function(){
  try {

    function createStyle(text) {
      return  new ol.style.Style({
        'image' : new ol.style.Circle({
          'fill' : new ol.style.Fill({
            'color' : 'rgba(55, 200, 150, 0.5)'
          }),
          'stroke' : new ol.style.Stroke({
            'width' : 1,
            'color' : 'rgba(55, 200, 150, 0.8)'
          }),
          'radius' : 7
        }),
        'text' : new ol.style.Text({
          'font' : '12px helvetica,sans-serif',
          'text' : text,
          'fill' : new ol.style.Fill({
            'color' : '#000'
          }),
          'stroke' : new ol.style.Stroke({
            'color' : '#fff',
            'width' : 2
          })
        })
      });
    }

    var vectorSource = new ol.source.Vector({
      'projection' : 'EPSG:4326'
    });
    var vectorLayer;
    var styleCache = {
      '*' : createStyle('*')
    };

    function showFingerprints(fps) {
      try {
        if (fps.length == 0) {
          vectorSource.clear();
          return;
        } else if (!vectorLayer) {
          vectorLayer = new ol.layer.Vector({
            'source' : vectorSource,
            'style' : function(f) {
              var text = f.get('name');
              return styleCache[text] || createStyle(text);
            },
            'zIndex' : 105
          });
          $hulop.map.getMap().addLayer(vectorLayer);
        }

        var ids = {};
        fps.forEach(function(fp) {
          if (isNaN(fp.lat + fp.lng)) {
            return;
          }
          var id = fp.lat + ':' + fp.lng + ':' + fp.count;
          ids[id] = true;
          if (!vectorSource.getFeatureById(id)) {
            var f = new ol.Feature({
              'geometry' : new ol.geom.Point(ol.proj.transform([fp.lng, fp.lat], 'EPSG:4326', 'EPSG:3857')),
              'name' : `${fp.count}`
            });
            f.setId(id);
            vectorSource.addFeature(f);
          }
        });
        vectorSource.forEachFeature(function (f) {
          ids[f.getId()] || vectorSource.removeFeature(f);
        });
      } catch(e) {
        console.error(e);
        //alert(e.message);
      }
    }

    return {
      'showFingerprints' : showFingerprints
    };
  } catch(e) {
    //alert(e.message);
  }
})();
<commit_msg>Check error before create feature<commit_after>/*******************************************************************************
 * Copyright (c) 2014, 2016  IBM Corporation, Carnegie Mellon University and others
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *******************************************************************************/

$hulop.fp = (function(){
  try {

    function createStyle(text) {
      return  new ol.style.Style({
        'image' : new ol.style.Circle({
          'fill' : new ol.style.Fill({
            'color' : 'rgba(55, 200, 150, 0.5)'
          }),
          'stroke' : new ol.style.Stroke({
            'width' : 1,
            'color' : 'rgba(55, 200, 150, 0.8)'
          }),
          'radius' : 7
        }),
        'text' : new ol.style.Text({
          'font' : '12px helvetica,sans-serif',
          'text' : text,
          'fill' : new ol.style.Fill({
            'color' : '#000'
          }),
          'stroke' : new ol.style.Stroke({
            'color' : '#fff',
            'width' : 2
          })
        })
      });
    }

    var vectorSource = new ol.source.Vector({
      'projection' : 'EPSG:4326'
    });
    var vectorLayer;
    var styleCache = {
      '*' : createStyle('*')
    };

    function showFingerprints(fps) {
      try {
        if (fps.length == 0) {
          vectorSource.clear();
          return;
        } else if (!vectorLayer) {
          vectorLayer = new ol.layer.Vector({
            'source' : vectorSource,
            'style' : function(f) {
              var text = f.get('name');
              return styleCache[text] || createStyle(text);
            },
            'zIndex' : 105
          });
          $hulop.map.getMap().addLayer(vectorLayer);
        }

        var ids = {};
        fps.forEach(function(fp) {
          var id = fp.lat + ':' + fp.lng + ':' + fp.count;
          if (!vectorSource.getFeatureById(id)) {
            if (isNaN(fp.lat + fp.lng)) {
              return;
            }
            var f = new ol.Feature({
              'geometry' : new ol.geom.Point(ol.proj.transform([fp.lng, fp.lat], 'EPSG:4326', 'EPSG:3857')),
              'name' : `${fp.count}`
            });
            f.setId(id);
            vectorSource.addFeature(f);
          }
          ids[id] = true;
        });
        vectorSource.forEachFeature(function (f) {
          ids[f.getId()] || vectorSource.removeFeature(f);
        });
      } catch(e) {
        //console.error(e);
        //alert(e.message);
      }
    }

    return {
      'showFingerprints' : showFingerprints
    };
  } catch(e) {
    //alert(e.message);
  }
})();
<|endoftext|>


<commit_before>import * as Keycloak from "keycloak-js"
import Settings from "settings"

// Client-side Keycloak init options are defined in the dictionary by the server
const { realm, url, clientId } = Settings.keycloakConfiguration
export const initOptions = { realm, url, clientId, onLoad: "login-required" }

export const keycloak = Keycloak(initOptions)
<commit_msg>NCI-Agency/anet#2314: Change import<commit_after>// Keycloak initialization in browser context
import Keycloak from "keycloak-js"
import Settings from "settings"

// Client-side Keycloak init options are defined in the dictionary by the server
const { realm, url, clientId } = Settings.keycloakConfiguration
export const initOptions = { realm, url, clientId, onLoad: "login-required" }

export const keycloak = Keycloak(initOptions)
<|endoftext|>


<commit_before>const _ = require('lodash');

//Apply hover styling to a collection of nodes
function updateStyling(style, matchedNodes) {

  matchedNodes.filter(node => !node.isParent()).forEach(node => {
    applySearchStyle(node, style);
  });
}

//Determine if a regex pattern is valid
function validateRegex(pattern) {
  var parts = pattern.split('/'),
    regex = pattern,
    options = "";
  if (parts.length > 1) {
    regex = parts[1];
    options = parts[2];
  }
  try {
    let regexObj = new RegExp(regex, options);
    return regexObj;
  }
  catch (e) {
    return null;
  }
}

function applySearchStyle(eles, style) {
  eles.style(style);
}

//Search for nodes that match an entered query
function searchNodes(query, cy) {
  const isBlank = _.isString(query) ? !!_.trim(query) : false;
  const isRegularExp = _.startsWith(query, 'regex:') && validateRegex(query.substring(6));
  const isExact = _.startsWith(query, 'exact:');

  let nodes = cy.nodes();

  //Get all child nodes
  const allChildNodes = nodes.map(node => node.data('compoundCollapse.collapsedCollection'));

  //Add all child nodes to the main node search list
  allChildNodes.forEach(collection => nodes = nodes.union(collection));

  let matched;

  //Search based on regular expression
  if (isRegularExp) {
    let regexObject = validateRegex(query.substring(6));
    matched = nodes.filter(node => node.data('label').match(regexObject));
  }
  //Search for an exact match
  else if (isExact) {
    let trimmedValue = query.substring(6).toUpperCase();
    matched = nodes.filter(node => node.data('label').toUpperCase() == trimmedValue);
  }
  //Search for a partial match
  else {
    let caseInsensitiveValue = query.toUpperCase();
    matched = nodes.filter(node => node.data('label').toUpperCase().includes(caseInsensitiveValue));
  }

  //Define highlighting style
  const searchStyle = {
    'overlay-color': 'yellow',
    'overlay-padding': 0,
    'overlay-opacity': 0.5
  };

  const baseStyle = {
    'overlay-color': '#000',
    'overlay-padding': 0,
    'overlay-opacity': '0'
  };

  //Remove all search styling
  applySearchStyle(cy.nodes(), baseStyle);

  //Apply styling
  if (matched.length > 0 && isBlank) {

    //Animate zoom and fit
    cy.animate({
      fit: {
        eles: cy.elements(),
        padding: 100
      }
    },
      {
        duration: 700
      });

    updateStyling(searchStyle, matched, cy);
  }
}

module.exports = searchNodes;<commit_msg>Minor Format Changes<commit_after>const _ = require('lodash');

//Apply hover styling to a collection of nodes
function updateStyling(style, matchedNodes) {

  matchedNodes.filter(node => !node.isParent()).forEach(node => {
    applySearchStyle(node, style);
  });
}

//Determine if a regex pattern is valid
function validateRegex(pattern) {
  var parts = pattern.split('/'),
    regex = pattern,
    options = "";
  if (parts.length > 1) {
    regex = parts[1];
    options = parts[2];
  }
  try {
    let regexObj = new RegExp(regex, options);
    return regexObj;
  }
  catch (e) {
    return null;
  }
}

function applySearchStyle(eles, style) {
  eles.style(style);
}

//Search for nodes that match an entered query
function searchNodes(query, cy) {
  const isBlank = _.isString(query) ? !!_.trim(query) : false;
  const isRegularExp = _.startsWith(query, 'regex:') && validateRegex(query.substring(6));
  const isExact = _.startsWith(query, 'exact:');

  let nodes = cy.nodes();

  //Get all child nodes
  const allChildNodes = nodes.map(node => node.data('compoundCollapse.collapsedCollection'));

  //Add all child nodes to the main node search list
  allChildNodes.forEach(collection => nodes = nodes.union(collection));

  let matched;

  //Search based on regular expression
  if (isRegularExp) {
    let regexObject = validateRegex(query.substring(6));
    matched = nodes.filter(node => node.data('label').match(regexObject));
  }
  //Search for an exact match
  else if (isExact) {
    let trimmedValue = query.substring(6).toUpperCase();
    matched = nodes.filter(node => node.data('label').toUpperCase() == trimmedValue);
  }
  //Search for a partial match
  else {
    let caseInsensitiveValue = query.toUpperCase();
    matched = nodes.filter(node => node.data('label').toUpperCase().includes(caseInsensitiveValue));
  }

  //Define highlighting style
  const searchStyle = {
    'overlay-color': 'yellow',
    'overlay-padding': 0,
    'overlay-opacity': 0.5
  };

  const baseStyle = {
    'overlay-color': '#000',
    'overlay-padding': 0,
    'overlay-opacity': '0'
  };

  //Remove all search styling
  applySearchStyle(cy.nodes(), baseStyle);

  //Apply styling
  if (matched.length > 0 && isBlank) {

    //Animate zoom and fit
    cy.animate({
      fit: { eles: cy.elements(),padding: 100
      }},{ duration: 700 });

    updateStyling(searchStyle, matched, cy);
  }
}

module.exports = searchNodes;<|endoftext|>