<commit_before>Meteor.startup(function () {
  smtpServer = {
    username: 'alissonplus2@gmail.com',
    password: '$12345678',
    server:   'smtp.gmail.com',
    port: 465
  }

  process.env.MAIL_URL = 'smtp://' + encodeURIComponent(smtpServer.username) + ':' + encodeURIComponent(smtpServer.password) + '@' + encodeURIComponent(smtpServer.server) + ':' + smtpServer.port;

  // PERMISSIONS
  for(var i in collections){
    collections[i].allow({
      insert: function(userId, form){
        return false;
      },
      update: function(userId, form, fields, modifier){
        return false;
      },
      remove: function(userId, form){
        return false;
      }
    });
  }

  // PUBLICATIONS
  Meteor.publish('program', function() {
    return Program.find(
      {},
      {fields:
        {
          user_record:0,
          user_change:0,
          date_record:0,
          date_change:0
        }
      }
    );
  });

  Meteor.publish('musiclist', function() {
    return Musiclist.find({});
  });

  Meteor.publish('notify', function() {
    return Notify.find(
      {},
      {fields:
        {
          user_record:0,
          user_change:0,
          date_change:0
        }
      }
    );
  });

  Meteor.publish('poll', function() {
    return Poll.find(
      {},
      {fields:
        {
          user_record:0,
          user_change:0,
          date_change:0
        }
      }
    );
  });

  Meteor.publish('answer', function() {
    return Answer.find(
      {status:1},
      {fields:
        {
          user_record:0,
          user_change:0,
          date_record:0,
          date_change:0
        }
      }
    );
  });

  Meteor.publish('polluser', function() {
    return PollUser.find(
      {status:1},
      {fields:
        {
          date_record:0,
          date_change:0
        }
      }
    );
  });

  Meteor.publish('user', function() {
    return User.find(
      {},
      {fields:
        {
          user_record:0,
          user_change:0,
          date_record:0,
          date_change:0
        }
      }
    );
  });

  Meteor.publish('level', function() {
    return Level.find(
      {status:1},
      {fields:
        {
          user_record:0,
          user_change:0,
          date_record:0,
          date_change:0
        }
      }
    );
  });

  Meteor.publish('content', function() {
    return Content.find(
      {},
      {fields:
        {
          user_record:0,
          user_change:0,
          date_change:0
        }
      }
    );
  });

  Meteor.publish('vehicle', function() {
    return Vehicle.find(
      {},
      {fields:
        {
          user_record:0,
          user_change:0,
          date_change:0
        }
      }
    );
  });

  Meteor.publish('category', function() {
    return Category.find(
      {},
      {fields:
        {
          user_record:0,
          user_change:0,
          date_change:0
        }
      }
    );
  });

  Meteor.publish('categoryPagination', function(limit) {
    if (limit > Category.find().count()) {
      limit = 0;
    }

    return Category.find(
      {},
      {fields:
        {
          user_record:0,
          user_change:0,
          date_change:0
        }
      },
      { limit: limit }
    );
  });

  Meteor.publish('musiclistPagination', function(limit) {
    if (limit > Musiclist.find().count()) {
      limit = 0;
    }

    return Musiclist.find(
      {},
      { limit: limit }
    );
  });

  Meteor.publish('vehiclePagination', function(limit) {
    if (limit > Vehicle.find().count()) {
      limit = 0;
    }

    return Vehicle.find(
      {},
      {fields:
        {
          user_record:0,
          user_change:0,
          date_change:0
        }
      },
      { limit: limit }
    );
  });

  Meteor.publish('contentPagination', function(limit) {
    if (limit > Content.find().count()) {
      limit = 0;
    }

    return Content.find(
      {},
      {fields:
        {
          user_record:0,
          user_change:0,
          date_change:0
        }
      },
      { limit: limit }
    );
  });

  Meteor.publish('notifyPagination', function(limit) {
    if (limit > Notify.find().count()) {
      limit = 0;
    }

    return Notify.find(
      {},
      {fields:
        {
          user_record:0,
          user_change:0,
          date_change:0
        }
      },
      { limit: limit }
    );
  });

  Meteor.publish('pollPagination', function(limit) {
    if (limit > Poll.find().count()) {
      limit = 0;
    }

    return Poll.find(
      {},
      {fields:
        {
          user_record:0,
          user_change:0,
          date_change:0
        }
      },
      { limit: limit }
    );
  });

  Meteor.publish('userPagination', function(limit) {
    if (limit > User.find().count()) {
      limit = 0;
    }

    return User.find(
      {status:1},
      {fields:
        {
          user_record:0,
          user_change:0,
          date_change:0
        }
      },
      { limit: limit }
    );
  });

  Meteor.publish('programPagination', function(limit) {
    if (limit > Program.find().count()) {
      limit = 0;
    }

    return Program.find(
      {status:1},
      {fields:
        {
          user_record:0,
          user_change:0,
          date_record:0,
          date_change:0
        }
      },
      { limit: limit }
    );
  });
});<commit_msg>content<commit_after>Meteor.startup(function () {
  smtpServer = {
    username: 'alissonplus2@gmail.com',
    password: '$12345678',
    server:   'smtp.gmail.com',
    port: 465
  }

  process.env.MAIL_URL = 'smtp://' + encodeURIComponent(smtpServer.username) + ':' + encodeURIComponent(smtpServer.password) + '@' + encodeURIComponent(smtpServer.server) + ':' + smtpServer.port;

  // PERMISSIONS
  for(var i in collections){
    collections[i].allow({
      insert: function(userId, form){
        return false;
      },
      update: function(userId, form, fields, modifier){
        return false;
      },
      remove: function(userId, form){
        return false;
      }
    });
  }

  // PUBLICATIONS
  Meteor.publish('program', function() {
    return Program.find(
      {},
      {fields:
        {
          user_record:0,
          user_change:0,
          date_record:0,
          date_change:0
        }
      }
    );
  });

  Meteor.publish('musiclist', function() {
    return Musiclist.find({});
  });

  Meteor.publish('notify', function() {
    return Notify.find(
      {},
      {fields:
        {
          user_record:0,
          user_change:0,
          date_change:0
        }
      }
    );
  });

  Meteor.publish('poll', function() {
    return Poll.find(
      {},
      {fields:
        {
          user_record:0,
          user_change:0,
          date_change:0
        }
      }
    );
  });

  Meteor.publish('answer', function() {
    return Answer.find(
      {status:1},
      {fields:
        {
          user_record:0,
          user_change:0,
          date_record:0,
          date_change:0
        }
      }
    );
  });

  Meteor.publish('polluser', function() {
    return PollUser.find(
      {status:1},
      {fields:
        {
          date_record:0,
          date_change:0
        }
      }
    );
  });

  Meteor.publish('user', function() {
    return User.find(
      {},
      {fields:
        {
          user_record:0,
          user_change:0,
          date_record:0,
          date_change:0
        }
      }
    );
  });

  Meteor.publish('level', function() {
    return Level.find(
      {status:1},
      {fields:
        {
          user_record:0,
          user_change:0,
          date_record:0,
          date_change:0
        }
      }
    );
  });

  Meteor.publish('content', function() {
    return Content.find({});
  });

  Meteor.publish('vehicle', function() {
    return Vehicle.find(
      {},
      {fields:
        {
          user_record:0,
          user_change:0,
          date_change:0
        }
      }
    );
  });

  Meteor.publish('category', function() {
    return Category.find(
      {},
      {fields:
        {
          user_record:0,
          user_change:0,
          date_change:0
        }
      }
    );
  });

  Meteor.publish('categoryPagination', function(limit) {
    if (limit > Category.find().count()) {
      limit = 0;
    }

    return Category.find(
      {},
      {fields:
        {
          user_record:0,
          user_change:0,
          date_change:0
        }
      },
      { limit: limit }
    );
  });

  Meteor.publish('musiclistPagination', function(limit) {
    if (limit > Musiclist.find().count()) {
      limit = 0;
    }

    return Musiclist.find(
      {},
      { limit: limit }
    );
  });

  Meteor.publish('vehiclePagination', function(limit) {
    if (limit > Vehicle.find().count()) {
      limit = 0;
    }

    return Vehicle.find(
      {},
      {fields:
        {
          user_record:0,
          user_change:0,
          date_change:0
        }
      },
      { limit: limit }
    );
  });

  Meteor.publish('contentPagination', function(limit) {
    if (limit > Content.find().count()) {
      limit = 0;
    }

    return Content.find(
      {},
      {fields:
        {
          user_record:0,
          user_change:0,
          date_change:0
        }
      },
      { limit: limit }
    );
  });

  Meteor.publish('notifyPagination', function(limit) {
    if (limit > Notify.find().count()) {
      limit = 0;
    }

    return Notify.find(
      {},
      {fields:
        {
          user_record:0,
          user_change:0,
          date_change:0
        }
      },
      { limit: limit }
    );
  });

  Meteor.publish('pollPagination', function(limit) {
    if (limit > Poll.find().count()) {
      limit = 0;
    }

    return Poll.find(
      {},
      {fields:
        {
          user_record:0,
          user_change:0,
          date_change:0
        }
      },
      { limit: limit }
    );
  });

  Meteor.publish('userPagination', function(limit) {
    if (limit > User.find().count()) {
      limit = 0;
    }

    return User.find(
      {status:1},
      {fields:
        {
          user_record:0,
          user_change:0,
          date_change:0
        }
      },
      { limit: limit }
    );
  });

  Meteor.publish('programPagination', function(limit) {
    if (limit > Program.find().count()) {
      limit = 0;
    }

    return Program.find(
      {status:1},
      {fields:
        {
          user_record:0,
          user_change:0,
          date_record:0,
          date_change:0
        }
      },
      { limit: limit }
    );
  });
});<|endoftext|>


<commit_before>'use strict';

var Vue = require('vue'),
    MarkdownIt = require('markdown-it'),
    twemoji = require('twemoji');

var md = new MarkdownIt({
    breaks: true,
    linkify: true
}).use(require('markdown-it-emoji'))
.use(require('markdown-it-highlightjs'))
.use(require('markdown-it-checkbox'));

md.renderer.rules.emoji = function(token, idx) {
  return twemoji.parse(token[idx].content);
};

Vue.filter('markdown', function (value) {
    if (!value) return '';

    return md.render(value);
});

Vue.filter('prettyDateOffset', function (time) {
    var date = new Date(time),
        diff = (((new Date()).getTime() - date.getTime()) / 1000),
        day_diff = Math.floor(diff / 86400);

    if (isNaN(day_diff) || day_diff < 0)
        return;

    return day_diff === 0 && (
            diff < 60 && 'just now' ||
            diff < 120 && '1 minute ago' ||
            diff < 3600 && Math.floor( diff / 60 ) + ' minutes ago' ||
            diff < 7200 && '1 hour ago' ||
            diff < 86400 && Math.floor( diff / 3600 ) + ' hours ago') ||
        day_diff === 1 && 'Yesterday' ||
        day_diff < 7 && day_diff + ' days ago' ||
        day_diff < 31 && Math.ceil( day_diff / 7 ) + ' weeks ago' ||
        day_diff < 365 && Math.round( day_diff / 30 ) +  ' months ago' ||
                          Math.round( day_diff / 365 ) + ' years ago';
});
<commit_msg>Allow html in notes<commit_after>'use strict';

var Vue = require('vue'),
    twemoji = require('twemoji');

var md = require('markdown-it')({
    breaks: true,
    html: true,
    linkify: true
}).use(require('markdown-it-emoji'))
.use(require('markdown-it-highlightjs'))
.use(require('markdown-it-checkbox'));

md.renderer.rules.emoji = function(token, idx) {
  return twemoji.parse(token[idx].content);
};

Vue.filter('markdown', function (value) {
    if (!value) return '';

    return md.render(value);
});

Vue.filter('prettyDateOffset', function (time) {
    var date = new Date(time),
        diff = (((new Date()).getTime() - date.getTime()) / 1000),
        day_diff = Math.floor(diff / 86400);

    if (isNaN(day_diff) || day_diff < 0)
        return;

    return day_diff === 0 && (
            diff < 60 && 'just now' ||
            diff < 120 && '1 minute ago' ||
            diff < 3600 && Math.floor( diff / 60 ) + ' minutes ago' ||
            diff < 7200 && '1 hour ago' ||
            diff < 86400 && Math.floor( diff / 3600 ) + ' hours ago') ||
        day_diff === 1 && 'Yesterday' ||
        day_diff < 7 && day_diff + ' days ago' ||
        day_diff < 31 && Math.ceil( day_diff / 7 ) + ' weeks ago' ||
        day_diff < 365 && Math.round( day_diff / 30 ) +  ' months ago' ||
                          Math.round( day_diff / 365 ) + ' years ago';
});
<|endoftext|>


<commit_before>"use strict";

import * as config from "./config.js"

// https://hibbard.eu/how-to-center-an-html-element-using-javascript/
function center_elem(elem) {
    var w = document.documentElement.clientWidth,
        h = document.documentElement.clientHeight;
    elem.style.position = 'absolute';
    elem.style.left = (w - elem.offsetWidth) / 2 + 'px';
    elem.style.top = (h - elem.offsetHeight) / 2 + window.pageYOffset + 'px';
}

function main() {
    const queryString = window.location.search;
    const urlParams = new URLSearchParams(queryString)
    const state = urlParams.get("state")
    let url = new URL("https://slack.com/oauth/authorize")
    url.searchParams.set("scope", "identity.basic")
    url.searchParams.set("client_id", config.slack_client_id)
    url.searchParams.set("user_scope", "identify")
    url.searchParams.set("state", state)
    url.searchParams.set("redirect_uri", config.redirect_url)
    let link = document.createElement("a");
    link.href = url

    let img = document.createElement("img");
    img.src = "https://api.slack.com/img/sign_in_with_slack.png";
    img.alt = "Sign in with Slack";
    img.srcset = "https://platform.slack-edge.com/img/sign_in_with_slack.png 1x, https://platform.slack-edge.com/img/sign_in_with_slack@2x.png 2x"

    link.appendChild(img);
    document.body.appendChild(link);
    img.onload = function () {
        center_elem(this);
    }
}

main()
<commit_msg>Initiate Sign in with slack with v2 endpoint<commit_after>"use strict";

import * as config from "./config.js"

// https://hibbard.eu/how-to-center-an-html-element-using-javascript/
function center_elem(elem) {
    var w = document.documentElement.clientWidth,
        h = document.documentElement.clientHeight;
    elem.style.position = 'absolute';
    elem.style.left = (w - elem.offsetWidth) / 2 + 'px';
    elem.style.top = (h - elem.offsetHeight) / 2 + window.pageYOffset + 'px';
}

function main() {
    const queryString = window.location.search;
    const urlParams = new URLSearchParams(queryString)
    const state = urlParams.get("state")
    let url = new URL("https://slack.com/oauth/v2/authorize")
    url.searchParams.set("user_scope", "identity.basic")
    url.searchParams.set("client_id", config.slack_client_id)
    url.searchParams.set("state", state)
    url.searchParams.set("redirect_uri", config.redirect_url)
    let link = document.createElement("a");
    link.href = url

    let img = document.createElement("img");
    img.src = "https://api.slack.com/img/sign_in_with_slack.png";
    img.alt = "Sign in with Slack";
    img.srcset = "https://platform.slack-edge.com/img/sign_in_with_slack.png 1x, https://platform.slack-edge.com/img/sign_in_with_slack@2x.png 2x"

    link.appendChild(img);
    document.body.appendChild(link);
    img.onload = function () {
        center_elem(this);
    }
}

main()
<|endoftext|>


<commit_before>/*
 * == BSD2 LICENSE ==
 * Copyright (c) 2018, Tidepool Project
 *
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the associated License, which is identical to the BSD 2-Clause
 * License as published by the Open Source Initiative at opensource.org.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the License for more details.
 *
 * You should have received a copy of the License along with this program; if
 * not, you can obtain one from Tidepool Project at tidepool.org.
 * == BSD2 LICENSE ==
 */

import _ from 'lodash';

// import annotate from '../../eventAnnotations';
// import common from '../../commonFunctions';
import TZOUtil from '../../TimezoneOffsetUtil';
import structJs from '../../struct';

const struct = structJs();
const isBrowser = typeof window !== 'undefined';
const debug = isBrowser ? require('bows')('TrueMetrixDriver') : console.log;

const HEADER = 0xA0;

const COMMANDS = {
  WAKEUP: '(^)AF',
  IDENTIFY: '(I)9A',
  GET_SERIAL: '(Z1)DC',
  ACK: '(*)7B',
  GET_RESULTS: '(G)98',
  POWER_OFF: '(_)B0',
  GET_FIRMWARE_VERSION: '(V)A7',
  GET_METER_TIME: '(T)A5',
};

class TrueMetrix {
  constructor(cfg) {
    this.cfg = cfg;
    this.hidDevice = this.cfg.deviceComms;
  }

  static extractPacketIntoMessages(bytes) {
    const re = /\(([^)]*)\)(\w{2})/g;
    const str = String.fromCharCode.apply(null, bytes);
    let results;
    const messages = [];

    // eslint-disable-next-line no-cond-assign
    while ((results = re.exec(str)) !== null) {
      console.log('Found', results);

      if (results != null) {
        if (TrueMetrix.verifyChecksum(results[1], results[2])) {
          messages.push(results[1]);
        }
      }
    }
    return messages;
  }

  static buildPacket(command, cmdlength) {
    const datalen = cmdlength + 2; /* we use 2 bytes because we add 1 byte for
                                    the header and 1 byte for the length of
                                    the payload */
    const buf = new ArrayBuffer(datalen);
    const bytes = new Uint8Array(buf);
    if (cmdlength) {
      let ctr = 0;
      ctr += struct.pack(bytes, ctr, 'bb6z', HEADER, cmdlength, command);
      debug('Sending', ctr, 'bytes:', String.fromCharCode.apply(null, bytes));
    }
    return buf;
  }

  static verifyChecksum(frame, expected) {
    let checksum = 0;
    for (let i = 0; i < frame.length; ++i) {
      checksum += frame.charCodeAt(i);
    }
    checksum += 0x29 + 0x28; // add frame start and end characters back in

    let checkStr = _.toUpper(checksum.toString(16)).slice(-2);
    checkStr = checkStr.slice(-2);
    return checkStr === _.toUpper(expected);
  }

  static getAnnotations(annotation, data) {
    const annInfo = [];

    if (data.unreportedThreshold) {
      annInfo.push({
        code: 'bayer/smbg/unreported-hi-lo-threshold',
      });
    }
    if (annotation.indexOf('>') !== -1) {
      annInfo.push({
        code: 'bg/out-of-range',
        threshold: data.hiThreshold,
        value: 'high',
      });

      return annInfo;
    } else if (annotation.indexOf('<') !== -1) {
      annInfo.push({
        code: 'bg/out-of-range',
        threshold: data.lowThreshold,
        value: 'low',
      });

      return annInfo;
    }
    return null;
  }

  async getRecord(cmd) {
    let record = '';

    // eslint-disable-next-line no-await-in-loop, requests to devices are sequential
    record = await this.commandResponse(TrueMetrix.buildPacket(cmd, cmd.length));
    console.log('Record:', record);

    return record;
  }

  async commandResponse(commandpacket) {
    let message = '';

    await this.hidDevice.sendPromisified(commandpacket);

    let raw = [];
    let result;
    do {
      // eslint-disable-next-line no-await-in-loop, requests to devices are sequential
      result = this.hidDevice.receiveTimeout(2000);
      console.log('Result:', result);
      const length = result[0];

      if (result.length > 0 && length < 64) {
        console.log('Packet length:', length);
        raw = raw.concat(result.slice(1, length + 1));
      }
    } while (result.length > 0);

    // Only process if we get data
    if (raw.length > 0) {
      console.log('Packet:', String.fromCharCode.apply(null, raw));
      message = TrueMetrix.extractPacketIntoMessages(raw);
    }
    return message;
  }

  async getDeviceID() {
    let model;
    let serial;
    const results = [];
    results.push(await this.getRecord(COMMANDS.IDENTIFY));
    results.push(await this.getRecord(COMMANDS.GET_SERIAL));

    // TODO: look through array for i message and z message

    return `trueMetrix-${model}-${serial}`;
  }

  /*
  prepBGData(progress, data) {
    //build missing data.id
    data.id = data.model + '-' + data.serialNumber;
    this.cfg.builder.setDefaults({ deviceId: data.id});
    var dataToPost = [];
    if (data.bgmReadings.length > 0) {
      for (var i = 0; i < data.bgmReadings.length; ++i) {
        var datum = data.bgmReadings[i];
        if(datum.control === true) {
          debug('Discarding control');
          continue;
        }
        var smbg = this.cfg.builder.makeSMBG()
          .with_value(datum.glucose)
          .with_deviceTime(datum.displayTime)
          .with_timezoneOffset(datum.timezoneOffset)
          .with_conversionOffset(datum.conversionOffset)
          .with_time(datum.displayUtc)
          .with_units(datum.units)
          .set('index', datum.nrec)
          .done();
          if (datum.annotations) {
            _.each(datum.annotations, function(ann) {
              annotate.annotateEvent(smbg, ann);
            });
          }
        dataToPost.push(smbg);
      }
    } else {
      debug('Device has no records to upload');
      throw(new Error('Device has no records to upload'));
    }

    return dataToPost;
  };
  */
}

module.exports = (config) => {
  const cfg = _.clone(config);
  const driver = new TrueMetrix(cfg);

  // With no date & time settings changes available,
  // timezone is applied across-the-board
  cfg.tzoUtil = new TZOUtil(cfg.timezone, new Date().toISOString(), []);

  return {
    /* eslint no-param-reassign:
       [ "error", { "props": true, "ignorePropertyModificationsFor": ["data"] } ] */

    detect(deviceInfo, cb) {
      debug('no detect function needed', deviceInfo);
      cb(null, deviceInfo);
    },

    setup(deviceInfo, progress, cb) {
      debug('in setup!');
      progress(100);
      cb(null, { deviceInfo });
    },

    connect(progress, data, cb) {
      debug('in connect!');

      cfg.deviceComms.connect(data.deviceInfo, cb, (err) => {
        if (err) {
          return cb(err);
        }
        data.disconnect = false;
        progress(100);
        return cb(null, data);
      });
    },

    getConfigInfo(progress, data, cb) {
      debug('in getConfigInfo', data);

      (async () => {
        const throwAway = driver.hidDevice.receiveTimeout(2000);
        console.log('Flushing:', String.fromCharCode.apply(null, throwAway));

        await driver.getRecord(COMMANDS.WAKEUP);
        cfg.deviceInfo.deviceId = await driver.getDeviceID();
        [cfg.deviceInfo.firmwareVersion] = await driver.getRecord(COMMANDS.GET_FIRMWARE_VERSION);

        // TODO: parse time and check against server time
        const [meterTime] = await driver.getRecord(COMMANDS.GET_METER_TIME);
        console.log('Meter time:', meterTime);

        console.log('DeviceInfo:', cfg.deviceInfo);

        progress(100);
        data.connect = true;
        return cb(null, data);
      })().catch((error) => {
        debug('Error in getConfigInfo: ', error);
        cb(error, null);
      });
    },

    async fetchData(progress, data, cb) {
      debug('in fetchData', data);
      const glucose = await driver.getRecord(COMMANDS.GET_RESULTS);
      console.log('Glucose values:', glucose);
      cb(null, data);
    },

    processData(progress, data, cb) {
      progress(0);
      progress(100);
      cb(null, data);
    },

    uploadData(progress, data, cb) {
      /*

      var model = MODELS[data.model];
      if(model == null) {
        model = 'Unknown Bayer model';
      }
      debug('Detected as: ', model);

      progress(0);
      var sessionInfo = {
        deviceTags: ['bgm'],
        deviceManufacturers: ['Bayer'],
        deviceModel: model,
        deviceSerialNumber: data.serialNumber,
        deviceId: data.id,
        start: sundial.utcDateString(),
        timeProcessing: cfg.tzoUtil.type,
        tzName : cfg.timezone,
        version: cfg.version
      };

      cfg.api.upload.toPlatform(data.post_records, sessionInfo,
        progress, cfg.groupId, function (err, result) {
        progress(100);

        if (err) {
          debug(err);
          debug(result);
          return cb(err, data);
        } else {
          data.cleanup = true;
          return cb(null, data);
        }
      });
      */
      cb(null, data);
    },

    disconnect(progress, data, cb) {
      debug('in disconnect');
      cfg.deviceComms.removeListeners();
      // Due to an upstream bug in HIDAPI on Windoze, we have to send a command
      // to the device to ensure that the listeners are removed before we disconnect
      // For more details, see https://github.com/node-hid/node-hid/issues/61
      driver.hidDevice.send(TrueMetrix.buildPacket(
        COMMANDS.POWER_OFF,
        COMMANDS.POWER_OFF.length,
      ), () => {
        progress(100);
        cb(null, data);
      });
    },

    cleanup(progress, data, cb) {
      debug('in cleanup');
      if (!data.disconnect) {
        cfg.deviceComms.disconnect(data, () => {
          progress(100);
          data.cleanup = true;
          data.disconnect = true;
          cb(null, data);
        });
      } else {
        progress(100);
      }
    },
  };
};
<commit_msg>getting model number and deviceId successfully<commit_after>/*
 * == BSD2 LICENSE ==
 * Copyright (c) 2018, Tidepool Project
 *
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the associated License, which is identical to the BSD 2-Clause
 * License as published by the Open Source Initiative at opensource.org.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the License for more details.
 *
 * You should have received a copy of the License along with this program; if
 * not, you can obtain one from Tidepool Project at tidepool.org.
 * == BSD2 LICENSE ==
 */

import _ from 'lodash';

// import annotate from '../../eventAnnotations';
// import common from '../../commonFunctions';
import TZOUtil from '../../TimezoneOffsetUtil';
import structJs from '../../struct';

const struct = structJs();
const isBrowser = typeof window !== 'undefined';
const debug = isBrowser ? require('bows')('TrueMetrixDriver') : console.log;

const HEADER = 0xA0;

const COMMANDS = {
  WAKEUP: '(^)AF',
  IDENTIFY: '(I)9A',
  GET_SERIAL: '(Z1)DC',
  ACK: '(*)7B',
  GET_RESULTS: '(G)98',
  POWER_OFF: '(_)B0',
  GET_FIRMWARE_VERSION: '(V)A7',
  GET_METER_TIME: '(T)A5',
};

const TYPES = {
  MODEL: 'i',
  SERIAL: 'z1',
  GLUCOSE: 'g',
  TIME: 't',
  CHECKSUM: 'x', // TODO: verify checksum of multiple frames
};

const MODELS = {
  MR2: 'trueMetrix',
  RC2: 'trueMetrixGo',
};

class TrueMetrix {
  constructor(cfg) {
    this.cfg = cfg;
    this.hidDevice = this.cfg.deviceComms;
  }

  static extractPacketIntoMessages(bytes) {
    const re = /\(([^)]*)\)(\w{2})/g;
    const str = String.fromCharCode.apply(null, bytes);
    let results;
    const messages = [];

    // eslint-disable-next-line no-cond-assign
    while ((results = re.exec(str)) !== null) {
      console.log('Found', results);

      if (results != null) {
        if (TrueMetrix.verifyChecksum(results[1], results[2])) {
          messages.push(results[1]);
        }
      }
    }
    return messages;
  }

  static buildPacket(command, cmdlength) {
    const datalen = cmdlength + 2; /* we use 2 bytes because we add 1 byte for
                                    the header and 1 byte for the length of
                                    the payload */
    const buf = new ArrayBuffer(datalen);
    const bytes = new Uint8Array(buf);
    if (cmdlength) {
      let ctr = 0;
      ctr += struct.pack(bytes, ctr, 'bb6z', HEADER, cmdlength, command);
      debug('Sending', ctr, 'bytes:', String.fromCharCode.apply(null, bytes));
    }
    return buf;
  }

  static verifyChecksum(frame, expected) {
    let checksum = 0;
    for (let i = 0; i < frame.length; ++i) {
      checksum += frame.charCodeAt(i);
    }
    checksum += 0x29 + 0x28; // add frame start and end characters back in

    let checkStr = _.toUpper(checksum.toString(16)).slice(-2);
    checkStr = checkStr.slice(-2);
    return checkStr === _.toUpper(expected);
  }

  static getAnnotations(annotation, data) {
    const annInfo = [];

    if (data.unreportedThreshold) {
      annInfo.push({
        code: 'bayer/smbg/unreported-hi-lo-threshold',
      });
    }
    if (annotation.indexOf('>') !== -1) {
      annInfo.push({
        code: 'bg/out-of-range',
        threshold: data.hiThreshold,
        value: 'high',
      });

      return annInfo;
    } else if (annotation.indexOf('<') !== -1) {
      annInfo.push({
        code: 'bg/out-of-range',
        threshold: data.lowThreshold,
        value: 'low',
      });

      return annInfo;
    }
    return null;
  }

  async commandResponse(cmd) {
    let message = '';

    await this.hidDevice.sendPromisified(TrueMetrix.buildPacket(cmd, cmd.length));

    let raw = [];
    let result;
    do {
      // eslint-disable-next-line no-await-in-loop, requests to devices are sequential
      result = this.hidDevice.receiveTimeout(2000);
      console.log('Result:', result);
      const length = result[0];

      if (result.length > 0 && length < 64) {
        console.log('Packet length:', length);
        raw = raw.concat(result.slice(1, length + 1));
      }
    } while (result.length > 0);

    // Only process if we get data
    if (raw.length > 0) {
      console.log('Packet:', String.fromCharCode.apply(null, raw));
      message = TrueMetrix.extractPacketIntoMessages(raw);
    }
    console.log('Message:', message);
    return message;
  }

  static filterByType(results, type) {
    const filtered = _.filter(results, (result, index, self) =>
      result != null &&
      _.startsWith(result, type) && // check type
      self.indexOf(result) === index); // remove duplicates
    return _.map(filtered, element => element.slice(type.length));
  }

  async getModelAndDeviceId() {
    let results = await this.commandResponse(COMMANDS.IDENTIFY);
    if (!_.isArray(results)) {
      results = [];
    }
    results = results.concat(await this.commandResponse(COMMANDS.GET_SERIAL));

    const model = MODELS[TrueMetrix.filterByType(results, TYPES.MODEL)];
    const serial = TrueMetrix.filterByType(results, TYPES.SERIAL);

    if (model == null || serial == null) {
      throw Error('Failed to connect to device. Is it in the cradle?');
    } else {
      return {
        model,
        deviceId: `Trividia-${model}-${serial}`,
      };
    }
  }

  /*
  prepBGData(progress, data) {
    //build missing data.id
    data.id = data.model + '-' + data.serialNumber;
    this.cfg.builder.setDefaults({ deviceId: data.id});
    var dataToPost = [];
    if (data.bgmReadings.length > 0) {
      for (var i = 0; i < data.bgmReadings.length; ++i) {
        var datum = data.bgmReadings[i];
        if(datum.control === true) {
          debug('Discarding control');
          continue;
        }
        var smbg = this.cfg.builder.makeSMBG()
          .with_value(datum.glucose)
          .with_deviceTime(datum.displayTime)
          .with_timezoneOffset(datum.timezoneOffset)
          .with_conversionOffset(datum.conversionOffset)
          .with_time(datum.displayUtc)
          .with_units(datum.units)
          .set('index', datum.nrec)
          .done();
          if (datum.annotations) {
            _.each(datum.annotations, function(ann) {
              annotate.annotateEvent(smbg, ann);
            });
          }
        dataToPost.push(smbg);
      }
    } else {
      debug('Device has no records to upload');
      throw(new Error('Device has no records to upload'));
    }

    return dataToPost;
  };
  */
}

module.exports = (config) => {
  const cfg = _.clone(config);
  const driver = new TrueMetrix(cfg);

  // With no date & time settings changes available,
  // timezone is applied across-the-board
  cfg.tzoUtil = new TZOUtil(cfg.timezone, new Date().toISOString(), []);

  return {
    /* eslint no-param-reassign:
       [ "error", { "props": true, "ignorePropertyModificationsFor": ["data"] } ] */

    detect(deviceInfo, cb) {
      debug('no detect function needed', deviceInfo);
      cb(null, deviceInfo);
    },

    setup(deviceInfo, progress, cb) {
      debug('in setup!');
      progress(100);
      cb(null, { deviceInfo });
    },

    connect(progress, data, cb) {
      debug('in connect!');

      cfg.deviceComms.connect(data.deviceInfo, cb, (err) => {
        if (err) {
          return cb(err);
        }
        data.disconnect = false;
        progress(100);
        return cb(null, data);
      });
    },

    getConfigInfo(progress, data, cb) {
      debug('in getConfigInfo', data);

      (async () => {
        const throwAway = driver.hidDevice.receiveTimeout(2000);
        console.log('Flushing:', String.fromCharCode.apply(null, throwAway));

        await driver.commandResponse(COMMANDS.WAKEUP);
        _.assign(cfg.deviceInfo, await driver.getModelAndDeviceId());
        [cfg.deviceInfo.firmwareVersion] =
          await driver.commandResponse(COMMANDS.GET_FIRMWARE_VERSION);

        // TODO: parse time and check against server time
        const [meterTime] = await driver.commandResponse(COMMANDS.GET_METER_TIME);
        console.log('Meter time:', meterTime);

        console.log('DeviceInfo:', cfg.deviceInfo);

        progress(100);
        data.connect = true;
        return cb(null, data);
      })().catch((error) => {
        debug('Error in getConfigInfo: ', error);
        cb(error, null);
      });
    },

    async fetchData(progress, data, cb) {
      debug('in fetchData', data);
      const glucose = await driver.commandResponse(COMMANDS.GET_RESULTS);
      console.log('Glucose values:', glucose);
      cb(null, data);
    },

    processData(progress, data, cb) {
      progress(0);
      progress(100);
      cb(null, data);
    },

    uploadData(progress, data, cb) {
      /*

      var model = MODELS[data.model];
      if(model == null) {
        model = 'Unknown Bayer model';
      }
      debug('Detected as: ', model);

      progress(0);
      var sessionInfo = {
        deviceTags: ['bgm'],
        deviceManufacturers: ['Bayer'],
        deviceModel: model,
        deviceSerialNumber: data.serialNumber,
        deviceId: data.id,
        start: sundial.utcDateString(),
        timeProcessing: cfg.tzoUtil.type,
        tzName : cfg.timezone,
        version: cfg.version
      };

      cfg.api.upload.toPlatform(data.post_records, sessionInfo,
        progress, cfg.groupId, function (err, result) {
        progress(100);

        if (err) {
          debug(err);
          debug(result);
          return cb(err, data);
        } else {
          data.cleanup = true;
          return cb(null, data);
        }
      });
      */
      cb(null, data);
    },

    disconnect(progress, data, cb) {
      debug('in disconnect');
      cfg.deviceComms.removeListeners();
      // Due to an upstream bug in HIDAPI on Windoze, we have to send a command
      // to the device to ensure that the listeners are removed before we disconnect
      // For more details, see https://github.com/node-hid/node-hid/issues/61
      driver.hidDevice.send(TrueMetrix.buildPacket(
        COMMANDS.POWER_OFF,
        COMMANDS.POWER_OFF.length,
      ), () => {
        progress(100);
        cb(null, data);
      });
    },

    cleanup(progress, data, cb) {
      debug('in cleanup');
      if (!data.disconnect) {
        cfg.deviceComms.disconnect(data, () => {
          progress(100);
          data.cleanup = true;
          data.disconnect = true;
          cb(null, data);
        });
      } else {
        progress(100);
      }
    },
  };
};
<|endoftext|>


<commit_before>/*
 * == BSD2 LICENSE ==
 * Copyright (c) 2018, Tidepool Project
 *
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the associated License, which is identical to the BSD 2-Clause
 * License as published by the Open Source Initiative at opensource.org.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the License for more details.
 *
 * You should have received a copy of the License along with this program; if
 * not, you can obtain one from Tidepool Project at tidepool.org.
 * == BSD2 LICENSE ==
 */

var _ = require('lodash');
var async = require('async');
var sundial = require('sundial');
var crcCalculator = require('../../crc.js');
var struct = require('../../struct.js')();
var annotate = require('../../eventAnnotations');
var common = require('../../commonFunctions');

var TZOUtil = require('../../TimezoneOffsetUtil');

var isBrowser = typeof window !== 'undefined';
var debug = isBrowser ? require('bows')('TrueMetrixDriver') : debug;

module.exports = function (config) {
  var cfg = _.clone(config);
  var hidDevice = config.deviceComms;
  var messageBuffer = [];

  var HEADER = 0xA0;

  var COMMANDS = {
    WAKEUP : '(^)AF',
    IDENTIFY : '(I)9A',
  };

  // With no date & time settings changes available,
  // timezone is applied across-the-board
  cfg.tzoUtil = new TZOUtil(cfg.timezone, new Date().toISOString(), []);

  var extractPacketIntoMessage = function (bytes) {
    var str = String.fromCharCode.apply(null, bytes);
    var results = str.match(/\(([^)]*)\)(\w{2})/);
    console.log('Parsed:', results);

    if (results != null) {
      if (verifyChecksum(results[1], results[2])) {
        return results[1];
      }
    } else {
      return null;
    }
  };

  var buildPacket = function (command, cmdlength) {
    var datalen = cmdlength + 2; // we use 2 bytes because we add 1 byte for
                                 // the header and 1 byte for the length of
                                 // the payload
    var buf = new ArrayBuffer(datalen);
    var bytes = new Uint8Array(buf);
    var ctr = 0;
    if (cmdlength) {
      ctr += struct.pack(bytes, ctr, 'bb6z', HEADER, cmdlength, command);
    }
    return buf;
  };

  function verifyChecksum (frame, expected) {

    var checksum = 0;
    for (var i = 0; i < frame.length; ++i) {
      checksum += frame.charCodeAt(i);
    }
    checksum += 0x29 + 0x28; // add frame start and end characters back in

    var checkStr = _.toUpper(checksum.toString(16)).slice(-2);
    checkStr = checkStr.slice(-2);
    return checkStr === _.toUpper(expected);
  }

  function decodeMessage (message) {
    return message;
  }

  var getAnnotations = function (annotation, data){
    var annInfo = [];

    if (data.unreportedThreshold) {
      annInfo.push({
        code: 'bayer/smbg/unreported-hi-lo-threshold'
      });
    }
    if (annotation.indexOf('>') !== -1) {

      annInfo.push({
        code: 'bg/out-of-range',
        threshold: data.hiThreshold,
        value: 'high'
      });

      return annInfo;
    } else if (annotation.indexOf('<') !== -1) {

      annInfo.push({
        code: 'bg/out-of-range',
        threshold: data.lowThreshold,
        value: 'low'
      });

      return annInfo;
    } else {
      return null;
    }
  };

  var isControl = function(markers) {
    if(markers.indexOf('C') !== -1) {
      debug('Marking as control test');
      return true;
    } else {
      return false;
    }
  };

  var getOneRecord = function (cmd, data, callback) {
    var retry = 0;
    var robj = {};
    var error = false;

    async.doWhilst(
      function (whilstCb) {
        commandResponse(buildPacket(cmd, cmd.length), function (err, record) {
          if (err) {
            return whilstCb(err, null);
          } else {
            console.log('Record:', record);

            robj.valid = true; // TODO: return message instead
            return whilstCb(null);
          }
        });
      },
      function () { return (Object.getOwnPropertyNames(robj).length === 0) && !error; },
      function (err) {
        if (err) {
          error = true;
          debug('Failure trying to talk to device.');
          debug(err);
          return callback(err, null);
        } else {
          callback(null, robj);
        }
      }
    );
  };

  var commandResponse = function (commandpacket, callback) {
    hidDevice.send(commandpacket, function () {
      getASTMMessage(5000, 3, function(err, result) {
        if (err) {
          return callback(err, null);
        } else {
            var message = null;
            try {
              message = decodeMessage(result);
            } catch (err) {
              debug('Error:', err);
              return callback(err, null);
            }
            callback(null, message);
        }
      });
    });
  };

  var getASTMMessage = function (timeout, retries, cb) {

    var timedOut = false;

    var abortTimer = setTimeout(function () {
      debug('TIMEOUT');
      var e = new Error('Timeout error.');
      e.name = 'TIMEOUT';
      timedOut = true;
      return cb(e, null);
    }, timeout);

    var message;

    async.doWhilst(
      function (callback) {
        hidDevice.receive(function(raw) {
          try {
            var packet = new Uint8Array(raw);
            console.log('Packet:', common.bytes2hex(packet));
            message = extractPacketIntoMessage(packet);

            // Only process if we get data
            if ( packet.length === 0 ) {
              return callback(null, false);
            }

            clearTimeout(abortTimer);
            return callback(null, true);

          } catch (err) {
            debug('Error:', err);
            if (!timedOut) {
              return cb(err);
            }
          }
        });
      },
      function (valid) {
        return (valid !== true && !timedOut);
      },
      function (err) {
        return cb(err, message);
      });
  };

  var processReadings = function(readings) {
    _.each(readings, function(reading, index) {

    });
  };

  var prepBGData = function (progress, data) {
    //build missing data.id
    data.id = data.model + '-' + data.serialNumber;
    cfg.builder.setDefaults({ deviceId: data.id});
    var dataToPost = [];
    if (data.bgmReadings.length > 0) {
      for (var i = 0; i < data.bgmReadings.length; ++i) {
        var datum = data.bgmReadings[i];
        if(datum.control === true) {
          debug('Discarding control');
          continue;
        }
        var smbg = cfg.builder.makeSMBG()
          .with_value(datum.glucose)
          .with_deviceTime(datum.displayTime)
          .with_timezoneOffset(datum.timezoneOffset)
          .with_conversionOffset(datum.conversionOffset)
          .with_time(datum.displayUtc)
          .with_units(datum.units)
          .set('index', datum.nrec)
          .done();
          if (datum.annotations) {
            _.each(datum.annotations, function(ann) {
              annotate.annotateEvent(smbg, ann);
            });
          }
        dataToPost.push(smbg);
      }
    } else {
      debug('Device has no records to upload');
      throw(new Error('Device has no records to upload'));
    }

    return dataToPost;
  };

  return {
    detect: function(deviceInfo, cb){
      debug('no detect function needed', arguments);
      cb(null, deviceInfo);
    },

    setup: function (deviceInfo, progress, cb) {
      debug('in setup!');
      progress(100);
      cb(null, {deviceInfo: deviceInfo});
    },

    connect: function (progress, data, cb) {
      debug('in connect!');

      cfg.deviceComms.connect(data.deviceInfo, function(cb){}, function(err) {
        if (err) {
          return cb(err);
        }
        data.disconnect = false;
        progress(100);
        cb(null, data);
      });
    },

    getConfigInfo: function (progress, data, cb) {
      debug('in getConfigInfo', data);

      getOneRecord(COMMANDS.WAKEUP, data,  function (err, result) {

          getOneRecord(COMMANDS.IDENTIFY, data, function (err, result) {

            progress(100);

            if(!err){
                data.connect = true;
                _.assign(data, result);

                cb(null, data);
            } else {
                return cb(err,result);
            }
          });
      });
    },

    fetchData: function (progress, data, cb) {
      debug('in fetchData', data);
/*
      var recordType = null;
      var dataRecords = [];
      var error = false;

      async.whilst(
        // Get records from the meter until we get the Message Terminator Record (L)
        // The spec says that unless we get this, any preceding data should not be used.
        function () { return (recordType !== ASCII_CONTROL.EOT && recordType !== 'L' && !error); },
        function (callback) {
          getOneRecord(data, function (err, result) {
            if (err) {
              error = true;
            } else {
              recordType = result.recordType;
              // We only collect data records (R)
              if (recordType === 'R' && result.timestamp) {
                progress(100.0 * result.nrec / data.nrecs);
                dataRecords.push(result);
              }
            }
            return callback(err);
          });
        },
        function (err) {
          progress(100);
          if(err || error) {
            data.bgmReadings = [];
          } else {
            debug('fetchData', dataRecords);
            data.bgmReadings = dataRecords;
          }
          data.fetchData = true;
          cb(err, data);
        }
      );
      */
      cb(null,data);
    },

    processData: function (progress, data, cb) {
      /*
      //debug('in processData');
      progress(0);
      data.bg_data = processReadings(data.bgmReadings);
      try {
        data.post_records = prepBGData(progress, data);
        var ids = {};
        for (var i = 0; i < data.post_records.length; ++i) {
          delete data.post_records[i].index; // Remove index as Jaeb study uses logIndices instead
          var id = data.post_records[i].time + '|' + data.post_records[i].deviceId;
          if (ids[id]) {
            debug('duplicate! %s @ %d == %d', id, i, ids[id] - 1);
            debug(data.post_records[ids[id] - 1]);
            debug(data.post_records[i]);
          } else {
            ids[id] = i + 1;
          }
        }
        progress(100);
        data.processData = true;
        cb(null, data);
      }
      catch(err) {
        cb(new Error(err), null);
      }
      */
      cb(null, data);
    },

    uploadData: function (progress, data, cb) {
      /*

      var model = MODELS[data.model];
      if(model == null) {
        model = 'Unknown Bayer model';
      }
      debug('Detected as: ', model);

      progress(0);
      var sessionInfo = {
        deviceTags: ['bgm'],
        deviceManufacturers: ['Bayer'],
        deviceModel: model,
        deviceSerialNumber: data.serialNumber,
        deviceId: data.id,
        start: sundial.utcDateString(),
        timeProcessing: cfg.tzoUtil.type,
        tzName : cfg.timezone,
        version: cfg.version
      };

      cfg.api.upload.toPlatform(data.post_records, sessionInfo, progress, cfg.groupId, function (err, result) {
        progress(100);

        if (err) {
          debug(err);
          debug(result);
          return cb(err, data);
        } else {
          data.cleanup = true;
          return cb(null, data);
        }
      });
      */
      cb(null, data);

    },

    disconnect: function (progress, data, cb) {
      debug('in disconnect');
      cfg.deviceComms.removeListeners();
      // Due to an upstream bug in HIDAPI on Windoze, we have to send a command
      // to the device to ensure that the listeners are removed before we disconnect
      // For more details, see https://github.com/node-hid/node-hid/issues/61
      hidDevice.send(buildPacket(0x04,1), function(err, result) {
        progress(100);
        cb(null, data);
      });
    },

    cleanup: function (progress, data, cb) {
      debug('in cleanup');
      if(!data.disconnect){
          cfg.deviceComms.disconnect(data, function() {
              progress(100);
              data.cleanup = true;
              data.disconnect = true;
              cb(null, data);
          });
      } else {
        progress(100);
      }
    }
  };
};
<commit_msg>ES6-ifying True Metrix code<commit_after>/*
 * == BSD2 LICENSE ==
 * Copyright (c) 2018, Tidepool Project
 *
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the associated License, which is identical to the BSD 2-Clause
 * License as published by the Open Source Initiative at opensource.org.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the License for more details.
 *
 * You should have received a copy of the License along with this program; if
 * not, you can obtain one from Tidepool Project at tidepool.org.
 * == BSD2 LICENSE ==
 */

import _ from 'lodash';
import async from 'async';

import annotate from '../../eventAnnotations';
import common from '../../commonFunctions';
import TZOUtil from '../../TimezoneOffsetUtil';
import structJs from '../../struct';

const struct = structJs();
const isBrowser = typeof window !== 'undefined';
const debug = isBrowser ? require('bows')('TrueMetrixDriver') : debug;

const HEADER = 0xA0;

const COMMANDS = {
  WAKEUP: '(^)AF',
  IDENTIFY: '(I)9A',
};

class TrueMetrix {
  constructor(cfg) {
    this.cfg = cfg;
    const hidDevice = this.cfg.deviceComms;
  }

  extractPacketIntoMessage(bytes) {
    const str = String.fromCharCode.apply(null, bytes);
    const results = str.match(/\(([^)]*)\)(\w{2})/);
    console.log('Parsed:', results);

    if (results != null) {
      if (this.verifyChecksum(results[1], results[2])) {
        return results[1];
      }
    }
    return null;
  }

  static buildPacket(command, cmdlength) {
    const datalen = cmdlength + 2; /* we use 2 bytes because we add 1 byte for
                                    the header and 1 byte for the length of
                                    the payload */
    const buf = new ArrayBuffer(datalen);
    const bytes = new Uint8Array(buf);
    if (cmdlength) {
      let ctr = 0;
      ctr += struct.pack(bytes, ctr, 'bb6z', HEADER, cmdlength, command);
      debug('Sending', ctr, 'bytes');
    }
    return buf;
  }

  static verifyChecksum(frame, expected) {
    let checksum = 0;
    for (let i = 0; i < frame.length; ++i) {
      checksum += frame.charCodeAt(i);
    }
    checksum += 0x29 + 0x28; // add frame start and end characters back in

    let checkStr = _.toUpper(checksum.toString(16)).slice(-2);
    checkStr = checkStr.slice(-2);
    return checkStr === _.toUpper(expected);
  }

  static decodeMessage(message) {
    return message;
  }

  static getAnnotations(annotation, data) {
    const annInfo = [];

    if (data.unreportedThreshold) {
      annInfo.push({
        code: 'bayer/smbg/unreported-hi-lo-threshold',
      });
    }
    if (annotation.indexOf('>') !== -1) {
      annInfo.push({
        code: 'bg/out-of-range',
        threshold: data.hiThreshold,
        value: 'high',
      });

      return annInfo;
    } else if (annotation.indexOf('<') !== -1) {
      annInfo.push({
        code: 'bg/out-of-range',
        threshold: data.lowThreshold,
        value: 'low',
      });

      return annInfo;
    }
    return null;
  }

  static getOneRecord(cmd, data, callback) {
    let retry = 0;
    const robj = {};
    let error = false;

    async.doWhilst(
      (whilstCb) => {
        this.commandResponse(this.buildPacket(cmd, cmd.length), (err, record) => {
          if (err) {
            return whilstCb(err, null);
          }
          console.log('Record:', record);

          robj.valid = true; // TODO: return message instead
          return whilstCb(null);
        });
      },
      (Object.getOwnPropertyNames(robj).length === 0) && !error,
      (err) => {
        if (err) {
          error = true;
          debug('Failure trying to talk to device.');
          debug(err);
          return callback(err, null);
        }
        return callback(null, robj);
      }
    );
  }

  commandResponse(commandpacket, callback) {
    this.hidDevice.send(commandpacket, () => {
      this.getASTMMessage(5000, 3, (err, result) => {
        if (err) {
          return callback(err, null);
        }
        const message = this.decodeMessage(result);
        return callback(null, message);
      });
    });
  }

  getASTMMessage(timeout, retries, cb) {

    let timedOut = false;

    const abortTimer = setTimeout(() => {
      debug('TIMEOUT');
      const e = new Error('Timeout error.');
      e.name = 'TIMEOUT';
      timedOut = true;
      return cb(e, null);
    }, timeout);

    let message;

    async.doWhilst(
      (callback) => {
        this.hidDevice.receive((raw) => {
          try {
            const packet = new Uint8Array(raw);
            console.log('Packet:', common.bytes2hex(packet));
            message = this.extractPacketIntoMessage(packet);

            // Only process if we get data
            if (packet.length === 0) {
              return callback(null, false);
            }

            clearTimeout(abortTimer);
            return callback(null, true);
          } catch (err) {
            debug('Error:', err);
            if (!timedOut) {
              return cb(err);
            }
          }
        });
      },
      valid => (valid !== true && !timedOut),
      err => cb(err, message),
    );
  }

  processReadings(readings) {
    _.each(readings, (reading, index) => {

    });
  }

  prepBGData(progress, data) {
    //build missing data.id
    data.id = data.model + '-' + data.serialNumber;
    this.cfg.builder.setDefaults({ deviceId: data.id});
    var dataToPost = [];
    if (data.bgmReadings.length > 0) {
      for (var i = 0; i < data.bgmReadings.length; ++i) {
        var datum = data.bgmReadings[i];
        if(datum.control === true) {
          debug('Discarding control');
          continue;
        }
        var smbg = this.cfg.builder.makeSMBG()
          .with_value(datum.glucose)
          .with_deviceTime(datum.displayTime)
          .with_timezoneOffset(datum.timezoneOffset)
          .with_conversionOffset(datum.conversionOffset)
          .with_time(datum.displayUtc)
          .with_units(datum.units)
          .set('index', datum.nrec)
          .done();
          if (datum.annotations) {
            _.each(datum.annotations, function(ann) {
              annotate.annotateEvent(smbg, ann);
            });
          }
        dataToPost.push(smbg);
      }
    } else {
      debug('Device has no records to upload');
      throw(new Error('Device has no records to upload'));
    }

    return dataToPost;
  };

}

module.exports = (config) => {
  const cfg = _.clone(config);
  const driver = new TrueMetrix(cfg);

  // With no date & time settings changes available,
  // timezone is applied across-the-board
  cfg.tzoUtil = new TZOUtil(cfg.timezone, new Date().toISOString(), []);

  return {
    detect: function(deviceInfo, cb){
      debug('no detect function needed', arguments);
      cb(null, deviceInfo);
    },

    setup: function (deviceInfo, progress, cb) {
      debug('in setup!');
      progress(100);
      cb(null, {deviceInfo: deviceInfo});
    },

    connect: function (progress, data, cb) {
      debug('in connect!');

      cfg.deviceComms.connect(data.deviceInfo, function(cb){}, function(err) {
        if (err) {
          return cb(err);
        }
        data.disconnect = false;
        progress(100);
        cb(null, data);
      });
    },

    getConfigInfo: function (progress, data, cb) {
      debug('in getConfigInfo', data);

      driver.getOneRecord(COMMANDS.WAKEUP, data, (err, result) => {

        driver.getOneRecord(COMMANDS.IDENTIFY, data, (err, result) => {

            progress(100);

            if(!err){
                data.connect = true;
                _.assign(data, result);

                cb(null, data);
            } else {
                return cb(err,result);
            }
          });
      });
    },

    fetchData(progress, data, cb) {
      debug('in fetchData', data);
/*
      var recordType = null;
      var dataRecords = [];
      var error = false;

      async.whilst(
        // Get records from the meter until we get the Message Terminator Record (L)
        // The spec says that unless we get this, any preceding data should not be used.
        function () { return (recordType !== ASCII_CONTROL.EOT && recordType !== 'L' && !error); },
        function (callback) {
          getOneRecord(data, function (err, result) {
            if (err) {
              error = true;
            } else {
              recordType = result.recordType;
              // We only collect data records (R)
              if (recordType === 'R' && result.timestamp) {
                progress(100.0 * result.nrec / data.nrecs);
                dataRecords.push(result);
              }
            }
            return callback(err);
          });
        },
        function (err) {
          progress(100);
          if(err || error) {
            data.bgmReadings = [];
          } else {
            debug('fetchData', dataRecords);
            data.bgmReadings = dataRecords;
          }
          data.fetchData = true;
          cb(err, data);
        }
      );
      */
      cb(null,data);
    },

    processData(progress, data, cb) {
      /*
      //debug('in processData');
      progress(0);
      data.bg_data = processReadings(data.bgmReadings);
      try {
        data.post_records = prepBGData(progress, data);
        var ids = {};
        for (var i = 0; i < data.post_records.length; ++i) {
          delete data.post_records[i].index; // Remove index as Jaeb study uses logIndices instead
          var id = data.post_records[i].time + '|' + data.post_records[i].deviceId;
          if (ids[id]) {
            debug('duplicate! %s @ %d == %d', id, i, ids[id] - 1);
            debug(data.post_records[ids[id] - 1]);
            debug(data.post_records[i]);
          } else {
            ids[id] = i + 1;
          }
        }
        progress(100);
        data.processData = true;
        cb(null, data);
      }
      catch(err) {
        cb(new Error(err), null);
      }
      */
      cb(null, data);
    },

    uploadData(progress, data, cb) {
      /*

      var model = MODELS[data.model];
      if(model == null) {
        model = 'Unknown Bayer model';
      }
      debug('Detected as: ', model);

      progress(0);
      var sessionInfo = {
        deviceTags: ['bgm'],
        deviceManufacturers: ['Bayer'],
        deviceModel: model,
        deviceSerialNumber: data.serialNumber,
        deviceId: data.id,
        start: sundial.utcDateString(),
        timeProcessing: cfg.tzoUtil.type,
        tzName : cfg.timezone,
        version: cfg.version
      };

      cfg.api.upload.toPlatform(data.post_records, sessionInfo, progress, cfg.groupId, function (err, result) {
        progress(100);

        if (err) {
          debug(err);
          debug(result);
          return cb(err, data);
        } else {
          data.cleanup = true;
          return cb(null, data);
        }
      });
      */
      cb(null, data);

    },

    disconnect(progress, data, cb) {
      debug('in disconnect');
      cfg.deviceComms.removeListeners();
      // Due to an upstream bug in HIDAPI on Windoze, we have to send a command
      // to the device to ensure that the listeners are removed before we disconnect
      // For more details, see https://github.com/node-hid/node-hid/issues/61
      hidDevice.send(driver.buildPacket(0x04, 1), (err, result) => {
        progress(100);
        cb(null, data);
      });
    },

    cleanup(progress, data, cb) {
      debug('in cleanup');
      if (!data.disconnect) {
        cfg.deviceComms.disconnect(data, () => {
          progress(100);
          data.cleanup = true;
          data.disconnect = true;
          cb(null, data);
        });
      } else {
        progress(100);
      }
    },
  };
};
<|endoftext|>


<commit_before>/*!
 * Module dependencies.
 */

var _ = require('underscore'),
	keystone = require('../../'),
	util = require('util'),
	cloudinary = require('cloudinary'),
	utils = require('../utils'),
	super_ = require('../field');

/**
 * CloudinaryImages FieldType Constructor
 * @extends Field
 * @api public
 */

function cloudinaryimages(list, path, options) {
	this._format = true;
	// TODO: implement filtering, hard-coded as disabled for now
	options.nofilter = true;
	cloudinaryimages.super_.call(this, list, path, options);
};

/*!
 * Inherit from Field
 */

util.inherits(cloudinaryimages, super_);

/**
 * Registers the field on the List's Mongoose Schema.
 *
 * @api public
 */

cloudinaryimages.prototype.addToSchema = function() {

	var mongoose = keystone.mongoose;

	var field = this,
		schema = this.list.schema;

	var paths = this.paths = {
		upload: 		this._path.append('_upload'),
		action: 		this._path.append('_action')
	};

	var ImageSchema = new mongoose.Schema({
		public_id:		String,
		version:		Number,
		signature:		String,
		format:			String,
		resource_type:	String,
		url:			String,
		width:			Number,
		height:			Number,
		secure_url:		String
	});

	var src  = function(img, options) {
		if (keystone.get('cloudinary secure')) {
			options = options || {};
			options.secure = true;
		}
		return img.public_id ? cloudinary.url(img.public_id + '.' + img.format, options) : '';
	}

	ImageSchema.method('src', function(options) {
		return src(this, options);
	});

	ImageSchema.method('fit', function(width, height) {
		return src(this, { width: width, height: height, crop: 'fit' });
	});

	ImageSchema.method('limit', function(width, height) {
		return src(this, { width: width, height: height, crop: 'limit' });
	});

	ImageSchema.method('fill', function(width, height) {
		return src(this, { width: width, height: height, crop: 'fill', gravity: 'faces' });
	});

	ImageSchema.method('crop', function(width, height) {
		return src(this, { width: width, height: height, crop: 'crop', gravity: 'faces' });
	});

	ImageSchema.method('thumbnail', function(width, height) {
		return src(this, { width: width, height: height, crop: 'thumb', gravity: 'faces' });
	});

	schema.add(this._path.addTo({}, [ImageSchema]));

	field.underscoreMethod('delete', function(i) {
		// find the image at index i
		// if it exists, delete it like...
		// cloudinary.uploader.destroy(this.get(paths.public_id), function() {});
		// then remove it from the array using array.splice() (mongoose method w/ change tracking)
	});
}

/**
 * Formats the field value
 *
 * @api public
 */

cloudinaryimages.prototype.format = function(item) {
	return _.map(item.get(this.path), function(img) {
		return img.src();
	}).join(', ');
}

/**
 * Detects whether the field has been modified
 *
 * @api public
 */

cloudinaryimages.prototype.isModified = function(item) {
	return item.isModified(this.paths.url);
}

/**
 * Validates that a value for this field has been provided in a data object
 *
 * @api public
 */

cloudinaryimages.prototype.validateInput = function(data) {
	// TODO - how should image field input be validated?
	return true;
}

/**
 * Updates the value for this field in the item from a data object
 *
 * @api public
 */

cloudinaryimages.prototype.updateItem = function(item, data) {
	// TODO - direct updating of data (not via upload)
}

/**
 * Returns a callback that handles a standard form submission for the field
 *
 * Expected form parts are
 * - `field.paths.action` in `req.body` (`clear` or `delete`)
 * - `field.paths.upload` in `req.files` (uploads the image to cloudinary)
 *
 * @api public
 */

cloudinaryimages.prototype.getRequestHandler = function(item, req, callback) {

	var field = this;

	callback = callback || function() {};

	return function() {

		/*
		if (req.body) {
			var action = req.body[field.paths.action];

			if (/^(delete|reset)$/.test(action))
				field.apply(item, action);
		}
		*/

		if (req.files && req.files[field.paths.upload] && req.files[field.paths.upload].size) {

			var tp = keystone.get('cloudinary prefix') || '';

			if (tp.length)
				tp += '_';

			var uploadOptions = {
				tags: [tp + field.list.path + '_' + field.path, tp + field.list.path + '_' + field.path + '_' + item.id]
			}

			if (keystone.get('cloudinary prefix'))
				uploadOptions.tags.push(keystone.get('cloudinary prefix'));

			if (keystone.get('env') != 'production')
				uploadOptions.tags.push(tp + 'dev');

			cloudinary.uploader.upload(req.files[field.paths.upload].path, function(result) {
				if (result.error) {
					callback(result.error);
				} else {
					item.set(field.path, result);
					callback();
				}
			}, uploadOptions);

		} else {
			callback();
		}

	}

}

/**
 * Immediately handles a standard form submission for the field (see `getRequestHandler()`)
 *
 * @api public
 */

cloudinaryimages.prototype.handleRequest = function(item, req, callback) {
	this.getRequestHandler(item, req, callback)();
}

/*!
 * Export class
 */

exports = module.exports = cloudinaryimages;
<commit_msg>Updating cloudinaryImages to match new underscoreMethods syntax<commit_after>/*!
 * Module dependencies.
 */

var _ = require('underscore'),
	keystone = require('../../'),
	util = require('util'),
	cloudinary = require('cloudinary'),
	utils = require('../utils'),
	super_ = require('../field');

/**
 * CloudinaryImages FieldType Constructor
 * @extends Field
 * @api public
 */

function cloudinaryimages(list, path, options) {
	this._underscoreMethods = ['format'];
	// TODO: implement filtering, hard-coded as disabled for now
	options.nofilter = true;
	cloudinaryimages.super_.call(this, list, path, options);
};

/*!
 * Inherit from Field
 */

util.inherits(cloudinaryimages, super_);

/**
 * Registers the field on the List's Mongoose Schema.
 *
 * @api public
 */

cloudinaryimages.prototype.addToSchema = function() {

	var mongoose = keystone.mongoose;

	var field = this,
		schema = this.list.schema;

	var paths = this.paths = {
		upload: 		this._path.append('_upload'),
		action: 		this._path.append('_action')
	};

	var ImageSchema = new mongoose.Schema({
		public_id:		String,
		version:		Number,
		signature:		String,
		format:			String,
		resource_type:	String,
		url:			String,
		width:			Number,
		height:			Number,
		secure_url:		String
	});

	var src  = function(img, options) {
		if (keystone.get('cloudinary secure')) {
			options = options || {};
			options.secure = true;
		}
		return img.public_id ? cloudinary.url(img.public_id + '.' + img.format, options) : '';
	}

	ImageSchema.method('src', function(options) {
		return src(this, options);
	});

	ImageSchema.method('fit', function(width, height) {
		return src(this, { width: width, height: height, crop: 'fit' });
	});

	ImageSchema.method('limit', function(width, height) {
		return src(this, { width: width, height: height, crop: 'limit' });
	});

	ImageSchema.method('fill', function(width, height) {
		return src(this, { width: width, height: height, crop: 'fill', gravity: 'faces' });
	});

	ImageSchema.method('crop', function(width, height) {
		return src(this, { width: width, height: height, crop: 'crop', gravity: 'faces' });
	});

	ImageSchema.method('thumbnail', function(width, height) {
		return src(this, { width: width, height: height, crop: 'thumb', gravity: 'faces' });
	});

	schema.add(this._path.addTo({}, [ImageSchema]));

	field.underscoreMethod('delete', function(i) {
		// find the image at index i
		// if it exists, delete it like...
		// cloudinary.uploader.destroy(this.get(paths.public_id), function() {});
		// then remove it from the array using array.splice() (mongoose method w/ change tracking)
	});
}

/**
 * Formats the field value
 *
 * @api public
 */

cloudinaryimages.prototype.format = function(item) {
	return _.map(item.get(this.path), function(img) {
		return img.src();
	}).join(', ');
}

/**
 * Detects whether the field has been modified
 *
 * @api public
 */

cloudinaryimages.prototype.isModified = function(item) {
	return item.isModified(this.paths.url);
}

/**
 * Validates that a value for this field has been provided in a data object
 *
 * @api public
 */

cloudinaryimages.prototype.validateInput = function(data) {
	// TODO - how should image field input be validated?
	return true;
}

/**
 * Updates the value for this field in the item from a data object
 *
 * @api public
 */

cloudinaryimages.prototype.updateItem = function(item, data) {
	// TODO - direct updating of data (not via upload)
}

/**
 * Returns a callback that handles a standard form submission for the field
 *
 * Expected form parts are
 * - `field.paths.action` in `req.body` (`clear` or `delete`)
 * - `field.paths.upload` in `req.files` (uploads the image to cloudinary)
 *
 * @api public
 */

cloudinaryimages.prototype.getRequestHandler = function(item, req, callback) {

	var field = this;

	callback = callback || function() {};

	return function() {

		/*
		if (req.body) {
			var action = req.body[field.paths.action];

			if (/^(delete|reset)$/.test(action))
				field.apply(item, action);
		}
		*/

		if (req.files && req.files[field.paths.upload] && req.files[field.paths.upload].size) {

			var tp = keystone.get('cloudinary prefix') || '';

			if (tp.length)
				tp += '_';

			var uploadOptions = {
				tags: [tp + field.list.path + '_' + field.path, tp + field.list.path + '_' + field.path + '_' + item.id]
			}

			if (keystone.get('cloudinary prefix'))
				uploadOptions.tags.push(keystone.get('cloudinary prefix'));

			if (keystone.get('env') != 'production')
				uploadOptions.tags.push(tp + 'dev');

			cloudinary.uploader.upload(req.files[field.paths.upload].path, function(result) {
				if (result.error) {
					callback(result.error);
				} else {
					item.set(field.path, result);
					callback();
				}
			}, uploadOptions);

		} else {
			callback();
		}

	}

}

/**
 * Immediately handles a standard form submission for the field (see `getRequestHandler()`)
 *
 * @api public
 */

cloudinaryimages.prototype.handleRequest = function(item, req, callback) {
	this.getRequestHandler(item, req, callback)();
}

/*!
 * Export class
 */

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


<commit_before>"use strict";

const Utils = require("../core/Utils");

function initInterface(_interface, _options) {
  if (!_interface)
    throw new TypeError("Invalid interface");
  if (_options) _interface.initialize(_options);
  return _interface;
}

class IVoiceConnection {
  constructor(discordie, gw) {
    // todo: ssrc to user
    //discordie.Dispatcher.on(Events.VOICE_SPEAKING, e => {
    //  if (e.socket == voicews) this.emit("speaking", - bla - resolve ssrc)
    //});

    this._gatewaySocket = gw;

    if (!this.canStream)
      throw new Error("Failed to create IVoiceConnection");

    this._discordie = discordie;
    Utils.privatify(this);
  }
  dispose() {
    this._gatewaySocket = null;
  }
  get disposed() {
    return !!this._gatewaySocket;
  }
  get _voiceSocket() {
    if (!this._gatewaySocket) return null;
    return this._gatewaySocket.voiceSocket;
  }
  get canStream() {
    return this._voiceSocket && this._voiceSocket.canStream;
  }

  get channel() {
    if (!this._gatewaySocket) return null;
    return this._discordie.Channels.get(
      this._gatewaySocket.voiceState.channelId
    );
  }
  get guild() {
    if (!this._gatewaySocket) return null;
    return this._discordie.Guilds.get(
      this._gatewaySocket.voiceState.guildId
    );
  }

  createEncoderStream(options) {

  }
  createDecoderStream(options) {

  }
  getEncoder(options) {
    if (!this._voiceSocket) return null;
    return initInterface(this._voiceSocket.audioEncoder, options);
  }
  getDecoder(options) {
    if (!this._voiceSocket) return null;
    return initInterface(this._voiceSocket.audioDecoder, options);
  }

  disconnect() {
    if (!this._voiceSocket) return;
    this._voiceSocket.disconnect();
  }
}

module.exports = IVoiceConnection;
<commit_msg>Fix IVoiceConnection.disconnect()<commit_after>"use strict";

const Utils = require("../core/Utils");

function initInterface(_interface, _options) {
  if (!_interface)
    throw new TypeError("Invalid interface");
  if (_options) _interface.initialize(_options);
  return _interface;
}

class IVoiceConnection {
  constructor(discordie, gw) {
    // todo: ssrc to user
    //discordie.Dispatcher.on(Events.VOICE_SPEAKING, e => {
    //  if (e.socket == voicews) this.emit("speaking", - bla - resolve ssrc)
    //});

    this._gatewaySocket = gw;

    if (!this.canStream)
      throw new Error("Failed to create IVoiceConnection");

    this._discordie = discordie;
    Utils.privatify(this);
  }
  dispose() {
    this._gatewaySocket = null;
  }
  get disposed() {
    return !!this._gatewaySocket;
  }
  get _voiceSocket() {
    if (!this._gatewaySocket) return null;
    return this._gatewaySocket.voiceSocket;
  }
  get canStream() {
    return this._voiceSocket && this._voiceSocket.canStream;
  }

  get channel() {
    if (!this._gatewaySocket) return null;
    return this._discordie.Channels.get(
      this._gatewaySocket.voiceState.channelId
    );
  }
  get guild() {
    if (!this._gatewaySocket) return null;
    return this._discordie.Guilds.get(
      this._gatewaySocket.voiceState.guildId
    );
  }

  createEncoderStream(options) {

  }
  createDecoderStream(options) {

  }
  getEncoder(options) {
    if (!this._voiceSocket) return null;
    return initInterface(this._voiceSocket.audioEncoder, options);
  }
  getDecoder(options) {
    if (!this._voiceSocket) return null;
    return initInterface(this._voiceSocket.audioDecoder, options);
  }

  disconnect() {
    if (!this._gatewaySocket) return;
    this._gatewaySocket.disconnectVoice();
  }
}

module.exports = IVoiceConnection;
<|endoftext|>


<commit_before>var http = require('http')
  , express = require('express')
  , utils = require('../utils')
  , dispatch = require('../middleware/dispatch')
  , routeHelper = require('../helpers/route');

module.exports = function(env) {
  var self = this
    , app = express()
    , server = http.createServer(app)
    , env = env || process.env.NODE_ENV || 'development';

  this.__router.handler(function(controller, action) {
    return dispatch(self, controller, action);
  });
  this.__router.define(function(method, path, handler) {
    app[method](path, handler);
  });
  this.__router.assist(function(name, entry) {
    var placeholders = [];
    entry.keys.forEach(function(key) {
      if (!key.optional) { placeholders.push(key.name); }
    });

    self.helper(name + 'Path', routeHelper(entry.controller, entry.action, placeholders, true));
    self.helper(name + 'URL', routeHelper(entry.controller, entry.action, placeholders));
  });

  // Forward function calls from Locomotive to Express.  This allows Locomotive
  // to be used interchangably with Express.
  utils.forward(this, app, [ 'configure', 'get', 'set', 'enabled', 'disabled', 'enable', 'disable',
                             'use', 'engine' ]);
  this.express = app;
  this.router = app.router;
  this.mime = express.mime;
  // TODO: No need to create or expose server
  this.server = server;

  // Set the environment.  This syncs Express with the environment supplied to
  // the Locomotive CLI.
  this.set('env', env);

  // Setup Locals
  this.locals = app.locals;
}
<commit_msg>Remove creation of HTTP server in Express underlay.<commit_after>var http = require('http')
  , express = require('express')
  , utils = require('../utils')
  , dispatch = require('../middleware/dispatch')
  , routeHelper = require('../helpers/route');

module.exports = function(env) {
  var self = this
    , app = express()
    , env = env || process.env.NODE_ENV || 'development';

  // Configure the router.
  //
  // The router needs a handler (which dispatches requests to a controller
  // action), a mechanism to mount those handlers in the underlying Express app,
  // and routing assistance which declares route helpers.
  this.__router.handler(function(controller, action) {
    return dispatch(self, controller, action);
  });
  this.__router.define(function(method, path, handler) {
    app[method](path, handler);
  });
  this.__router.assist(function(name, entry) {
    var placeholders = [];
    entry.keys.forEach(function(key) {
      if (!key.optional) { placeholders.push(key.name); }
    });

    self.helper(name + 'Path', routeHelper(entry.controller, entry.action, placeholders, true));
    self.helper(name + 'URL', routeHelper(entry.controller, entry.action, placeholders));
  });

  // Forward function calls from Locomotive to Express.  This allows Locomotive
  // to be used interchangably with Express.
  utils.forward(this, app, [ 'configure',
                             'get', 'set',
                             'enabled', 'disabled',
                             'enable', 'disable',
                             'use', 'engine' ]);
  this.express = app;
  this.router = app.router;
  this.locals = app.locals;
  this.mime = express.mime;

  // Set the environment.  This syncs Express with the environment supplied to
  // the Locomotive CLI.
  this.set('env', env);
}
<|endoftext|>


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

function requirePrivilege(priv, opts) {
	opts = _.defaults(opts || {}, {
		assignProperty: 'auth',
		onAccessGranted: callNextMiddleware,
		onAccessDenied: sendAccessDenied,
	});

	function callNextMiddleware(req, res, next) {
		return next();
	}

	function sendAccessDenied(req, res, next) {
		return res.sendStatus(401);
	}

	function middleware(req, res, next) {
		if (req[opts.assignProperty] === undefined)
			throw new Error('auth info not found in request');

		var role = req[opts.assignProperty].role;
		if (!role)
			throw new Error('auth role could not be determined');

		var requiredPriv = priv instanceof Function ? priv(req) : priv;
		if (!requiredPriv)
			return opts.onAccessGranted(req, res, next);
		role.hasPrivilege(requiredPriv, function(err, hasPriv) {
			if (err) return next(err);
			hasPriv ? opts.onAccessGranted(req, res, next)
			        : opts.onAccessDenied(req, res, next);
		});
	};

	return middleware;
}

module.exports = requirePrivilege;
<commit_msg>Add support for async callbacks in requirePrivilege middleware<commit_after>var _ = require('lodash');

function requirePrivilege(priv, opts) {
	function callNextMiddleware(req, res, next) {
		return next();
	}

	function sendAccessDenied(req, res, next) {
		return res.sendStatus(401);
	}

	opts = _.defaults(opts || {}, {
		assignProperty: 'auth',
		onAccessGranted: callNextMiddleware,
		onAccessDenied: sendAccessDenied,
	});

	function resolvePrivilege(req, cb) {
		if (!_.isFunction(priv)) {
			return cb(null, priv);
		} else if (priv.length === 1) {
			try {
				var requiredPriv = priv(req);
				return cb(null, requiredPriv);
			} catch (err) { return cb(err); }
		} else {
			priv(req, cb);
		}
	}

	function middleware(req, res, next) {
		if (req[opts.assignProperty] === undefined)
			throw new Error('auth info not found in request');

		var role = req[opts.assignProperty].role;
		if (!role)
			throw new Error('auth role could not be determined');

		resolvePrivilege(req, function(err, requiredPriv) {
			if (err) return next(err);
			if (!requiredPriv)
				return opts.onAccessGranted(req, res, next);
			role.hasPrivilege(requiredPriv, function(err, hasPriv) {
				if (err) return next(err);
				hasPriv ? opts.onAccessGranted(req, res, next)
				        : opts.onAccessDenied(req, res, next);
			});
		});
	};

	return middleware;
}

module.exports = requirePrivilege;
<|endoftext|>


<commit_before>'use strict';

let logger = require('heimdalljs-logger')('ember-cli:installation-checker');
const fs = require('fs-extra');
const existsSync = require('exists-sync');
const path = require('path');
const SilentError = require('silent-error');

module.exports = InstallationChecker;

function InstallationChecker(options) {
  this.project = options.project;
}

/**
* Check if npm and bower installation directories are present,
* and raise an error message with instructions on how to proceed.
*
* If some of these package managers aren't being used in the project
* we just ignore them. Their usage is considered by checking the
* presence of your manifest files: package.json for npm and bower.json for bower.
*
* @method checkInstallations
*/
InstallationChecker.prototype.checkInstallations = function() {
  let commands = [];

  if (this.usingNpm() && this.npmDependenciesNotPresent()) {
    logger.info('npm dependencies not installed');
    commands.push('`npm install`');
  }
  if (this.usingBower() && this.bowerDependenciesNotPresent()) {
    logger.info('bower dependencies not installed');
    commands.push('`bower install`');
  }
  if (commands.length) {
    let commandText = commands.join(' and ');
    throw new SilentError(`No dependencies installed. Run ${commandText} to install missing dependencies.`);
  }
};

function hasDependencies(pkg) {
  return (pkg.dependencies && pkg.dependencies.length) ||
         (pkg.devDependencies && pkg.devDependencies.length);
}

function readJSON(path) {
  try {
    return fs.readJsonSync(path);
  } catch (e) {
    throw new SilentError(`InstallationChecker: Unable to parse: ${path}`);
  }
}

InstallationChecker.prototype.hasBowerDeps = function() {
  return hasDependencies(readJSON(path.join(this.project.root, 'bower.json')));
};

InstallationChecker.prototype.usingBower = function() {
  return existsSync(path.join(this.project.root, 'bower.json')) && this.hasBowerDeps();
};

InstallationChecker.prototype.bowerDependenciesNotPresent = function() {
  return !existsSync(this.project.bowerDirectory);
};

InstallationChecker.prototype.hasNpmDeps = function() {
  return hasDependencies(readJSON(path.join(this.project.root, 'package.json')));
};

InstallationChecker.prototype.usingNpm = function() {
  return existsSync(path.join(this.project.root, 'package.json')) && this.hasNpmDeps();
};

InstallationChecker.prototype.npmDependenciesNotPresent = function() {
  return !existsSync(this.project.nodeModulesPath);
};
<commit_msg>models/installation-checker: Convert to ES6 class<commit_after>'use strict';

let logger = require('heimdalljs-logger')('ember-cli:installation-checker');
const fs = require('fs-extra');
const existsSync = require('exists-sync');
const path = require('path');
const SilentError = require('silent-error');

class InstallationChecker {
  constructor(options) {
    this.project = options.project;
  }

  /**
  * Check if npm and bower installation directories are present,
  * and raise an error message with instructions on how to proceed.
  *
  * If some of these package managers aren't being used in the project
  * we just ignore them. Their usage is considered by checking the
  * presence of your manifest files: package.json for npm and bower.json for bower.
  *
  * @method checkInstallations
  */
  checkInstallations() {
    let commands = [];

    if (this.usingNpm() && this.npmDependenciesNotPresent()) {
      logger.info('npm dependencies not installed');
      commands.push('`npm install`');
    }
    if (this.usingBower() && this.bowerDependenciesNotPresent()) {
      logger.info('bower dependencies not installed');
      commands.push('`bower install`');
    }
    if (commands.length) {
      let commandText = commands.join(' and ');
      throw new SilentError(`No dependencies installed. Run ${commandText} to install missing dependencies.`);
    }
  }

  hasBowerDeps() {
    return hasDependencies(readJSON(path.join(this.project.root, 'bower.json')));
  }

  usingBower() {
    return existsSync(path.join(this.project.root, 'bower.json')) && this.hasBowerDeps();
  }

  bowerDependenciesNotPresent() {
    return !existsSync(this.project.bowerDirectory);
  }

  hasNpmDeps() {
    return hasDependencies(readJSON(path.join(this.project.root, 'package.json')));
  }

  usingNpm() {
    return existsSync(path.join(this.project.root, 'package.json')) && this.hasNpmDeps();
  }

  npmDependenciesNotPresent() {
    return !existsSync(this.project.nodeModulesPath);
  }
}

module.exports = InstallationChecker;

function hasDependencies(pkg) {
  return (pkg.dependencies && pkg.dependencies.length) ||
         (pkg.devDependencies && pkg.devDependencies.length);
}

function readJSON(path) {
  try {
    return fs.readJsonSync(path);
  } catch (e) {
    throw new SilentError(`InstallationChecker: Unable to parse: ${path}`);
  }
}

<|endoftext|>


<commit_before>var fs = require('fs'),
	mod = require('../../mod.js'),
	notice = mod.notice,
	util = mod.util,
	_conf = mod.conf,
	ProjConfig = mod.load('ProjConfig');

var _exampleRoot = mod.dirname+'/../template/',
	_projTpls = {},
	_projnameTestReg = /\{@projRoot\}/,
	_projnameReg = /\{@projRoot\}/g;

// 初始化所有的配置方案
fs.readdirSync(_exampleRoot).forEach(function(v){
	if (v == '..' || v=='.') return;

	var planRoot = _exampleRoot + v+'/',
		confFile = planRoot + _conf.MainConfigFile;

	if (!fs.existsSync(confFile)) {
		notice.warn('deploy', 'The plan('+v+') do not has projconf file');
		return;
	}

	_projTpls[v] = {};
	readDir(planRoot, '', _projTpls[v]);
});

// 必须检查 default是否存在
if (!_projTpls['default']) notice.error('Object Init', 'Do not has `default` plan');

function readDir(root, path, projTpl){
	fs.readdirSync(root).forEach(function(v){
		if (v == '..' || v=='.') return;

		if (fs.statSync(root+v).isFile()) {
			projTpl[path+v] = fs.readFileSync(root+v);
		} else {
			readDir(root+v+'/', path+v+'/', projTpl);
		}
	});
}

module.exports = function(projName, plan){
	var root = _conf.DocumentRoot + projName +'/',
		confFile = root+_conf.ProjConfigFile;
	if (!util.fileExists(confFile)) {

		if (!plan || !_projTpls[plan]) {
			notice.log('deploy', 'The plan('+plan+') switch to `default`');
			plan = _projTpls['default'];
		} else {
			plan = _projTpls[plan];
		}
		try {
			util.eachObject(plan, function(i, v){
				var cont = v.toString();
				if (_projnameTestReg.test(cont)) v = cont.replace(_projnameReg, projName);
				util.writeFile(root+i, v);
			});

			// 创建可能遗漏的目录
			var path = root+_conf.SourcePath;
			if (!fs.existsSync(path)) util.mkdirs(path);
			// path = root+_conf.DynamicDataPath;
			// if (!fs.existsSync(path)) util.mkdirs(path);

			// 初始化项目
			if (ProjConfig.reload(projName, true)) notice.log('Object Init', 'Object create success');
		} catch(err) {
			notice.error('', err);
		}
	} else {
		notice.warn('Object Init', 'Object is exists', root);
	}
};

<commit_msg>initProjConfig 复制文件前检查文件是否存在，防止发生不可恢复的文件丢失<commit_after>var fs = require('fs'),
	mod = require('../../mod.js'),
	notice = mod.notice,
	util = mod.util,
	_conf = mod.conf,
	ProjConfig = mod.load('ProjConfig');

var _exampleRoot = mod.dirname+'/../template/',
	_projTpls = {},
	_projnameTestReg = /\{@projRoot\}/,
	_projnameReg = /\{@projRoot\}/g;

// 初始化所有的配置方案
fs.readdirSync(_exampleRoot).forEach(function(v){
	if (v == '..' || v=='.') return;

	var planRoot = _exampleRoot + v+'/',
		confFile = planRoot + _conf.MainConfigFile;

	if (!fs.existsSync(confFile)) {
		notice.warn('Object Init', 'The plan('+v+') do not has projconf file');
		return;
	}

	_projTpls[v] = {};
	readDir(planRoot, '', _projTpls[v]);
});

// 必须检查 default是否存在
if (!_projTpls['default']) notice.error('Object Init', 'Do not has `default` plan');

function readDir(root, path, projTpl){
	fs.readdirSync(root).forEach(function(v){
		if (v == '..' || v=='.') return;

		if (fs.statSync(root+v).isFile()) {
			projTpl[path+v] = fs.readFileSync(root+v);
		} else {
			readDir(root+v+'/', path+v+'/', projTpl);
		}
	});
}

module.exports = function(projName, plan){
	var root = _conf.DocumentRoot + projName +'/',
		confFile = root+_conf.ProjConfigFile;
	if (!util.fileExists(confFile)) {

		if (!plan || !_projTpls[plan]) {
			notice.log('Object Init', 'The plan('+plan+') switch to `default`');
			plan = _projTpls['default'];
		} else {
			plan = _projTpls[plan];
		}
		try {
			util.eachObject(plan, function(i, v){
				var file = root+i;
				if (fs.existsSync(file)) {
					notice.warn('Object Init', 'The copying file is exists', file);
				} else {
					var cont = v.toString();
					if (_projnameTestReg.test(cont)) v = cont.replace(_projnameReg, projName);
					util.writeFile(file, v);
				}
			});

			// 创建可能遗漏的目录
			var path = root+_conf.SourcePath;
			if (!fs.existsSync(path)) util.mkdirs(path);
			// path = root+_conf.DynamicDataPath;
			// if (!fs.existsSync(path)) util.mkdirs(path);

			// 初始化项目
			if (ProjConfig.reload(projName, true)) notice.log('Object Init', 'Object create success');
		} catch(err) {
			notice.error('', err);
		}
	} else {
		notice.warn('Object Init', 'Object is exists', root);
	}
};

<|endoftext|>


<commit_before><commit_msg>Encoders dynamic to primary bank on selected channel<commit_after><|endoftext|>


<commit_before>import htmlToElement from 'html-to-element';
import { chaynsInfo } from '../chayns-info';
import ConsoleLogger from '../utils/console-logger';
import { getRelativeColor, mixColors } from '../utils/convert';
import { getUrlParameters } from '../utils/url-parameter';

const consoleLogger = new ConsoleLogger('(dynamic-styles.js)');

/**
 * Accept Arrays like
 *
 * [{
 *   selector: '.abc::before', styles: {
 *      prop1: 'value',
 *      prop2: 'value'
 *   }
 * }]
 *
 * @param classArray
 */
function addStyle(classArray) {
    let css = '';
    for (const cssClass of classArray) {
        let body = '';
        for (const style of Object.keys(cssClass.styles)) {
            body += `\n\t${style}:${cssClass.styles[style]};`;
        }
        if (body.length > 0) {
            css += `\n${cssClass.selector}{${body}\n}`;
        }
    }
    document.head.appendChild(htmlToElement(`<style type="text/css">${css}</style>`));
}

export async function setDynamicStyle() {
    try {
        const getColor = (percentage, opacity) => getRelativeColor(chaynsInfo.Color, percentage, opacity);

        const chaynsCss = htmlToElement(`<link rel="stylesheet" href="https://chayns-res.tobit.com/API/v3.1/css/chayns.min.css?color=${getColor(100).substr(1, 6)}">`);
        const fontAwesomeCss = htmlToElement('<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">');

        document.head.appendChild(chaynsCss);
        document.head.appendChild(fontAwesomeCss);

        const customBackgroundColor = getUrlParameters().backgroundcolor && !getUrlParameters().backgroundcolor.match(/[^0-9A-Fa-f]/g) && `#${getUrlParameters().backgroundcolor}`;

        // Body
        const colorModeBaseColors = {
            0: '#ffffff',
            1: '#1a1a1a',
        };
        addStyle([{
            selector: 'body',
            styles: {
                'background-color': customBackgroundColor || chaynsInfo.ColorMode === 2 ? '#ffffff' : mixColors(chaynsInfo.Color, colorModeBaseColors[chaynsInfo.ColorMode], 7)
            }
        }, {
            selector: 'h1',
            styles: {
                color: getColor(100)
            }
        }]);

        // Dialog
        addStyle([{
            selector: '.chaynsBtn',
            styles: {
                'background-color': getColor(100)
            }
        }, {
            selector: '.chaynsBtn:hover',
            styles: {
                'background-color': getColor(100, 0.6)
            }
        }]);

        // WaitCursor
        addStyle([{
            selector: '.ChaynsLoadingCursor > .loading-spinner-wrapper',
            styles: {
                'background-color': getColor(100, 0.25)
            }
        }, {
            selector: '.ChaynsLoadingCursor.with-text > .loading-spinner-wrapper',
            styles: {
                'background-color': `${getColor(25, 0.9)}!important`
            }
        }, {
            selector: '.loading-spinner',
            styles: {
                'border-color': `${getColor(100, 0.8)}!important`
            }
        }]);

        // .ChaynsCS-*
        addStyle([{
            selector: '.ChaynsCS-Border-30Pcnt',
            styles: {
                'border-color': getColor(30)
            }
        }, {
            selector: '.ChaynsCS-BgColor-20Pcnt',
            styles: {
                'background-color': `${getColor(20)}!important`
            }
        }, {
            selector: '.ChaynsCS-BgColor',
            styles: {
                'background-color': `${getColor(100)}!important`
            }
        }, {
            selector: '.ChaynsCS-Color',
            styles: {
                color: `${getColor(100)}!important`
            }
        }, {
            selector: '.ChaynsCS-Color-80Pcnt',
            styles: {
                color: `${getColor(80)}!important`
            }
        }]);
    } catch (e) {
        consoleLogger.error(e);
    }
}
<commit_msg>:bug: Fix backgroundColor does not working<commit_after>import htmlToElement from 'html-to-element';
import { chaynsInfo } from '../chayns-info';
import ConsoleLogger from '../utils/console-logger';
import { getRelativeColor, mixColors } from '../utils/convert';
import { getUrlParameters } from '../utils/url-parameter';

const consoleLogger = new ConsoleLogger('(dynamic-styles.js)');

/**
 * Accept Arrays like
 *
 * [{
 *   selector: '.abc::before', styles: {
 *      prop1: 'value',
 *      prop2: 'value'
 *   }
 * }]
 *
 * @param classArray
 */
function addStyle(classArray) {
    let css = '';
    for (const cssClass of classArray) {
        let body = '';
        for (const style of Object.keys(cssClass.styles)) {
            body += `\n\t${style}:${cssClass.styles[style]};`;
        }
        if (body.length > 0) {
            css += `\n${cssClass.selector}{${body}\n}`;
        }
    }
    document.head.appendChild(htmlToElement(`<style type="text/css">${css}</style>`));
}

export async function setDynamicStyle() {
    try {
        const getColor = (percentage, opacity) => getRelativeColor(chaynsInfo.Color, percentage, opacity);

        const chaynsCss = htmlToElement(`<link rel="stylesheet" href="https://chayns-res.tobit.com/API/v3.1/css/chayns.min.css?color=${getColor(100).substr(1, 6)}">`);
        const fontAwesomeCss = htmlToElement('<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">');

        document.head.appendChild(chaynsCss);
        document.head.appendChild(fontAwesomeCss);

        const customBackgroundColor = getUrlParameters().backgroundcolor && getUrlParameters().backgroundcolor.match(/^[0-9A-Fa-f]{3,8}$/g) && `#${getUrlParameters().backgroundcolor}`;

        // Body
        const colorModeBaseColors = {
            0: '#ffffff',
            1: '#1a1a1a',
        };
        addStyle([{
            selector: 'body',
            styles: {
                'background-color': customBackgroundColor || (chaynsInfo.ColorMode === 2 ? '#ffffff' : mixColors(chaynsInfo.Color, colorModeBaseColors[chaynsInfo.ColorMode], 7))
            }
        }, {
            selector: 'h1',
            styles: {
                color: getColor(100)
            }
        }]);

        // Dialog
        addStyle([{
            selector: '.chaynsBtn',
            styles: {
                'background-color': getColor(100)
            }
        }, {
            selector: '.chaynsBtn:hover',
            styles: {
                'background-color': getColor(100, 0.6)
            }
        }]);

        // WaitCursor
        addStyle([{
            selector: '.ChaynsLoadingCursor > .loading-spinner-wrapper',
            styles: {
                'background-color': getColor(100, 0.25)
            }
        }, {
            selector: '.ChaynsLoadingCursor.with-text > .loading-spinner-wrapper',
            styles: {
                'background-color': `${getColor(25, 0.9)}!important`
            }
        }, {
            selector: '.loading-spinner',
            styles: {
                'border-color': `${getColor(100, 0.8)}!important`
            }
        }]);

        // .ChaynsCS-*
        addStyle([{
            selector: '.ChaynsCS-Border-30Pcnt',
            styles: {
                'border-color': getColor(30)
            }
        }, {
            selector: '.ChaynsCS-BgColor-20Pcnt',
            styles: {
                'background-color': `${getColor(20)}!important`
            }
        }, {
            selector: '.ChaynsCS-BgColor',
            styles: {
                'background-color': `${getColor(100)}!important`
            }
        }, {
            selector: '.ChaynsCS-Color',
            styles: {
                color: `${getColor(100)}!important`
            }
        }, {
            selector: '.ChaynsCS-Color-80Pcnt',
            styles: {
                color: `${getColor(80)}!important`
            }
        }]);
    } catch (e) {
        consoleLogger.error(e);
    }
}
<|endoftext|>