<commit_before>/**
 * Copyright 2018 The AMP HTML Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS-IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

const {URL} = require('url');

const punycode = require('punycode');

/** @type {string} */
const LTR_CHARS =
  'A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02B8\u0300-\u0590\u0800-\u1FFF' +
  '\u200E\u2C00-\uFB1C\uFE00-\uFE6F\uFEFD-\uFFFF';

/** @type {string} */
const RTL_CHARS =
  '\u0591-\u06EF\u06FA-\u07FF\u200F\uFB1D-\uFDFF\uFE70-\uFEFC';

/** @type {RegExp} */
const HAS_LTR_CHARS = new RegExp('[' + LTR_CHARS + ']');

/** @type {RegExp} */
const HAS_RTL_CHARS = new RegExp('[' + RTL_CHARS + ']');

/** @private {number} */
const MAX_DOMAIN_LABEL_LENGTH_ = 63;

/**
 * Constructs a curls domain following these instructions:
 * 1. Convert pub.com from IDN (punycode) to utf-8, if applicable.
 * 2. Replace every “-” with “--”.
 * 3. Replace each “.” with “-”.
 * 4. Convert back to IDN.
 *
 * Examples:
 *   'https://something.com/'    =>  'something-com'
 *   'https://SOMETHING.COM/'    =>  'something-com'
 *   'https://hello-world.com'  =>  'hello--world-com'
 *   'https://hello--world.com' =>  'hello----world-com'
 *
 * Fallback applies to the following cases:
 * - RFCs don’t permit a domain label to exceed 63 characters.
 * - RFCs don’t permit any domain label to contain a mix of right-to-left and
 *   left-to-right characters.
 * - If the origin domain contains no “.” character.
 *
 * Fallback Algorithm:
 * 1. Take the SHA256 of the punycode view of the domain.
 * 2. Base32 encode the resulting hash. Set the domain prefix to the resulting
 *    string.
 *
 * Also, this will only use the domain (hostname) from the passed URL to give output
 *
 * @param {string} url The complete publisher url.
 * @return {!Promise<string>} The curls encoded domain.
 * @private
 */
function createCurlsSubdomain(url) {
  // Get our domain from the passed url string
  const domain = new URL(url).hostname;
  if (isEligibleForHumanReadableCacheEncoding_(domain)) {
    const curlsEncoding = constructHumanReadableCurlsCacheDomain_(domain);
    if (curlsEncoding.length > MAX_DOMAIN_LABEL_LENGTH_) {
      return constructFallbackCurlsCacheDomain_(domain);
    } else {
      return Promise.resolve(curlsEncoding);
    }
  } else {
    return constructFallbackCurlsCacheDomain_(domain);
  }
}

/**
 * Determines whether the given domain can be validly encoded into a human
 * readable curls encoded cache domain.  A domain is eligible as long as:
 *   It does not exceed 63 characters
 *   It does not contain a mix of right-to-left and left-to-right characters
 *   It contains a dot character
 *
 * @param {string} domain The domain to validate
 * @return {boolean}
 * @private
 */
function isEligibleForHumanReadableCacheEncoding_(domain) {
  const unicode = punycode.toUnicode(domain);
  return domain.length <= MAX_DOMAIN_LABEL_LENGTH_ &&
    !(HAS_LTR_CHARS.test(unicode) &&
      HAS_RTL_CHARS.test(unicode)) &&
    domain.indexOf('.') != -1;
}

/**
 * Constructs a human readable curls encoded cache domain using the following
 * algorithm:
 *   Convert domain from punycode to utf-8 (if applicable)
 *   Replace every '-' with '--'
 *   Replace every '.' with '-'
 *   Convert back to punycode (if applicable)
 *
 * @param {string} domain The publisher domain
 * @return {string} The curls encoded domain
 * @private
 */
function constructHumanReadableCurlsCacheDomain_(domain) {
  domain = punycode.toUnicode(domain);
  domain = domain.split('-').join('--');
  domain = domain.split('.').join('-');
  return punycode.toASCII(domain).toLowerCase();
}

/**
 * Constructs a fallback curls encoded cache domain by taking the SHA256 of
 * the domain and base32 encoding it.
 *
 * @param {string} domain The publisher domain
 * @return {!Promise<string>}
 * @private
 */
function constructFallbackCurlsCacheDomain_(domain) {
  return sha256_(domain).then((digest) => encodeHexToBase32_(digest));
}

/**
 * @param {string} str The string to convert to sha256
 * @return {!Promise<string>}
 * @private
 */
function sha256_(str) {
  if (typeof window !== 'undefined') {
    // Transform the string into an arraybuffer.
    const buffer = new TextEncoder('utf-8').encode(str);
    return crypto.subtle.digest('SHA-256', buffer).then((hash) => {
      return hex_(hash);
    });
  } else {
    const buffer = Buffer.from(str, 'utf-8');
    const crypto = require('crypto');
    return new Promise((resolve) => {
      const sha256 = crypto.createHash('sha256').update(buffer).digest('hex');
      resolve(sha256);
    });
  }
}

/**
 * @param {string} buffer
 * @return {string}
 * @private
 */
function hex_(buffer) {
  let hexCodes = [];
  const view = new DataView(buffer);
  for (let i = 0; i < view.byteLength; i += 4) {
    // Using getUint32 reduces the number of iterations needed (we process 4 bytes each time)
    const value = view.getUint32(i);
    // toString(16) will give the hex representation of the number without padding
    const stringValue = value.toString(16);
    // Use concatenation and slice for padding
    const padding = '00000000';
    const paddedValue = (padding + stringValue).slice(-padding.length);
    hexCodes.push(paddedValue);
  }

  // Join all the hex strings into one
  return hexCodes.join('');
}

/**
 * Encodes a hex string in base 32 according to specs in RFC 4648 section 6:
 * https://tools.ietf.org/html/rfc4648
 *
 * @param {string} hexString the hex string
 * @return {string} The base32 encoded string
 * @private
 */
function encodeHexToBase32_(hexString) {
  const initialPadding = 'ffffffffff';
  const finalPadding = '000000';
  const paddedHexString = initialPadding + hexString + finalPadding;
  const encodedString = encode32_(paddedHexString);

  const bitsPerHexChar = 4;
  const bitsPerBase32Char = 5;
  const numInitialPaddingChars =
      initialPadding.length * bitsPerHexChar / bitsPerBase32Char;
  const numHexStringChars =
      Math.ceil(hexString.length * bitsPerHexChar / bitsPerBase32Char);

  const result = encodedString.substr(numInitialPaddingChars, numHexStringChars);
  return result;
}

/**
 * We use the base32 character encoding defined here:
 * https://tools.ietf.org/html/rfc4648#page-8
 *
 * @param {string} paddedHexString
 * @return {string} the base32 string
 * @private
 */
function encode32_(paddedHexString) {
  let bytes = [];
  paddedHexString.match(/.{1,2}/g).forEach((pair, i) => {
    bytes[i] = parseInt(pair, 16);
  });

  // Split into groups of 5 and convert to base32.
  const base32 = 'abcdefghijklmnopqrstuvwxyz234567';
  const leftover = bytes.length % 5;
  let quanta = Math.floor((bytes.length / 5));
  let parts = [];

  if (leftover != 0) {
    for (let i = 0; i < (5-leftover); i++) {
      bytes += '\x00';
    }
    quanta += 1;
  }

  for (let i = 0; i < quanta; i++) {
    parts.push(base32.charAt(bytes[i*5] >> 3));
    parts.push(base32.charAt(((bytes[i*5] & 0x07) << 2)
        | (bytes[i*5 + 1] >> 6)));
    parts.push(base32.charAt(((bytes[i*5 + 1] & 0x3F) >> 1)));
    parts.push(base32.charAt(((bytes[i*5 + 1] & 0x01) << 4)
        | (bytes[i*5 + 2] >> 4)));
    parts.push(base32.charAt(((bytes[i*5 + 2] & 0x0F) << 1)
        | (bytes[i*5 + 3] >> 7)));
    parts.push(base32.charAt(((bytes[i*5 + 3] & 0x7F) >> 2)));
    parts.push(base32.charAt(((bytes[i*5 + 3] & 0x03) << 3)
        | (bytes[i*5 + 4] >> 5)));
    parts.push(base32.charAt(((bytes[i*5 + 4] & 0x1F))));
  }

  let replace = 0;
  if (leftover == 1) replace = 6;
  else if (leftover == 2) replace = 4;
  else if (leftover == 3) replace = 3;
  else if (leftover == 4) replace = 1;

  for (let i = 0; i < replace; i++) parts.pop();
  for (let i = 0; i < replace; i++) parts.push('=');

  return parts.join('');
}

/** @module AmpCurlUrl */
module.exports = createCurlsSubdomain;
<commit_msg>Forgot a nit<commit_after>/**
 * Copyright 2018 The AMP HTML Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS-IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

const {URL} = require('url');

const punycode = require('punycode');

/** @type {string} */
const LTR_CHARS =
  'A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02B8\u0300-\u0590\u0800-\u1FFF' +
  '\u200E\u2C00-\uFB1C\uFE00-\uFE6F\uFEFD-\uFFFF';

/** @type {string} */
const RTL_CHARS =
  '\u0591-\u06EF\u06FA-\u07FF\u200F\uFB1D-\uFDFF\uFE70-\uFEFC';

/** @type {RegExp} */
const HAS_LTR_CHARS = new RegExp('[' + LTR_CHARS + ']');

/** @type {RegExp} */
const HAS_RTL_CHARS = new RegExp('[' + RTL_CHARS + ']');

/** @private {number} */
const MAX_DOMAIN_LABEL_LENGTH_ = 63;

/**
 * Constructs a curls domain following these instructions:
 * 1. Convert pub.com from IDN (punycode) to utf-8, if applicable.
 * 2. Replace every “-” with “--”.
 * 3. Replace each “.” with “-”.
 * 4. Convert back to IDN.
 *
 * Examples:
 *   'https://something.com/'    =>  'something-com'
 *   'https://SOMETHING.COM/'    =>  'something-com'
 *   'https://hello-world.com'  =>  'hello--world-com'
 *   'https://hello--world.com' =>  'hello----world-com'
 *
 * Fallback applies to the following cases:
 * - RFCs don’t permit a domain label to exceed 63 characters.
 * - RFCs don’t permit any domain label to contain a mix of right-to-left and
 *   left-to-right characters.
 * - If the origin domain contains no “.” character.
 *
 * Fallback Algorithm:
 * 1. Take the SHA256 of the punycode view of the domain.
 * 2. Base32 encode the resulting hash. Set the domain prefix to the resulting
 *    string.
 *
 * Also, this will only use the domain (hostname) from the passed URL to give output
 *
 * @param {string} url The complete publisher url.
 * @return {!Promise<string>} The curls encoded domain.
 * @private
 */
function createCurlsSubdomain(url) {
  // Get our domain from the passed url string
  const domain = new URL(url).hostname;
  if (isEligibleForHumanReadableCacheEncoding_(domain)) {
    const curlsEncoding = constructHumanReadableCurlsCacheDomain_(domain);
    if (curlsEncoding.length > MAX_DOMAIN_LABEL_LENGTH_) {
      return constructFallbackCurlsCacheDomain_(domain);
    } else {
      return Promise.resolve(curlsEncoding);
    }
  } else {
    return constructFallbackCurlsCacheDomain_(domain);
  }
}

/**
 * Determines whether the given domain can be validly encoded into a human
 * readable curls encoded cache domain.  A domain is eligible as long as:
 *   It does not exceed 63 characters
 *   It does not contain a mix of right-to-left and left-to-right characters
 *   It contains a dot character
 *
 * @param {string} domain The domain to validate
 * @return {boolean}
 * @private
 */
function isEligibleForHumanReadableCacheEncoding_(domain) {
  const unicode = punycode.toUnicode(domain);
  return domain.length <= MAX_DOMAIN_LABEL_LENGTH_ &&
    !(HAS_LTR_CHARS.test(unicode) &&
      HAS_RTL_CHARS.test(unicode)) &&
    domain.indexOf('.') != -1;
}

/**
 * Constructs a human readable curls encoded cache domain using the following
 * algorithm:
 *   Convert domain from punycode to utf-8 (if applicable)
 *   Replace every '-' with '--'
 *   Replace every '.' with '-'
 *   Convert back to punycode (if applicable)
 *
 * @param {string} domain The publisher domain
 * @return {string} The curls encoded domain
 * @private
 */
function constructHumanReadableCurlsCacheDomain_(domain) {
  domain = punycode.toUnicode(domain);
  domain = domain.split('-').join('--');
  domain = domain.split('.').join('-');
  return punycode.toASCII(domain).toLowerCase();
}

/**
 * Constructs a fallback curls encoded cache domain by taking the SHA256 of
 * the domain and base32 encoding it.
 *
 * @param {string} domain The publisher domain
 * @return {!Promise<string>}
 * @private
 */
function constructFallbackCurlsCacheDomain_(domain) {
  return sha256_(domain).then((digest) => encodeHexToBase32_(digest));
}

/**
 * @param {string} str The string to convert to sha256
 * @return {!Promise<string>}
 * @private
 */
function sha256_(str) {
  if (typeof window !== 'undefined') {
    // Transform the string into an arraybuffer.
    const buffer = new TextEncoder('utf-8').encode(str);
    return crypto.subtle.digest('SHA-256', buffer).then((hash) => {
      return hex_(hash);
    });
  } else {
    const buffer = Buffer.from(str, 'utf-8');
    const crypto = require('crypto');
    return new Promise((resolve) => {
      const sha256 = crypto.createHash('sha256').update(buffer).digest('hex');
      resolve(sha256);
    });
  }
}

/**
 * @param {string} buffer
 * @return {string}
 * @private
 */
function hex_(buffer) {
  let hexCodes = [];
  const view = new DataView(buffer);
  for (let i = 0; i < view.byteLength; i += 4) {
    // Using getUint32 reduces the number of iterations needed (we process 4 bytes each time)
    const value = view.getUint32(i);
    // toString(16) will give the hex representation of the number without padding
    const stringValue = value.toString(16);
    // Use concatenation and slice for padding
    const padding = '00000000';
    const paddedValue = (padding + stringValue).slice(-padding.length);
    hexCodes.push(paddedValue);
  }

  // Join all the hex strings into one
  return hexCodes.join('');
}

/**
 * Encodes a hex string in base 32 according to specs in RFC 4648 section 6:
 * https://tools.ietf.org/html/rfc4648
 *
 * @param {string} hexString the hex string
 * @return {string} the base32 encoded string
 * @private
 */
function encodeHexToBase32_(hexString) {
  const initialPadding = 'ffffffffff';
  const finalPadding = '000000';
  const paddedHexString = initialPadding + hexString + finalPadding;
  const encodedString = encode32_(paddedHexString);

  const bitsPerHexChar = 4;
  const bitsPerBase32Char = 5;
  const numInitialPaddingChars =
      initialPadding.length * bitsPerHexChar / bitsPerBase32Char;
  const numHexStringChars =
      Math.ceil(hexString.length * bitsPerHexChar / bitsPerBase32Char);

  const result = encodedString.substr(numInitialPaddingChars, numHexStringChars);
  return result;
}

/**
 * We use the base32 character encoding defined here:
 * https://tools.ietf.org/html/rfc4648#page-8
 *
 * @param {string} paddedHexString
 * @return {string} the base32 string
 * @private
 */
function encode32_(paddedHexString) {
  let bytes = [];
  paddedHexString.match(/.{1,2}/g).forEach((pair, i) => {
    bytes[i] = parseInt(pair, 16);
  });

  // Split into groups of 5 and convert to base32.
  const base32 = 'abcdefghijklmnopqrstuvwxyz234567';
  const leftover = bytes.length % 5;
  let quanta = Math.floor((bytes.length / 5));
  let parts = [];

  if (leftover != 0) {
    for (let i = 0; i < (5-leftover); i++) {
      bytes += '\x00';
    }
    quanta += 1;
  }

  for (let i = 0; i < quanta; i++) {
    parts.push(base32.charAt(bytes[i*5] >> 3));
    parts.push(base32.charAt(((bytes[i*5] & 0x07) << 2)
        | (bytes[i*5 + 1] >> 6)));
    parts.push(base32.charAt(((bytes[i*5 + 1] & 0x3F) >> 1)));
    parts.push(base32.charAt(((bytes[i*5 + 1] & 0x01) << 4)
        | (bytes[i*5 + 2] >> 4)));
    parts.push(base32.charAt(((bytes[i*5 + 2] & 0x0F) << 1)
        | (bytes[i*5 + 3] >> 7)));
    parts.push(base32.charAt(((bytes[i*5 + 3] & 0x7F) >> 2)));
    parts.push(base32.charAt(((bytes[i*5 + 3] & 0x03) << 3)
        | (bytes[i*5 + 4] >> 5)));
    parts.push(base32.charAt(((bytes[i*5 + 4] & 0x1F))));
  }

  let replace = 0;
  if (leftover == 1) replace = 6;
  else if (leftover == 2) replace = 4;
  else if (leftover == 3) replace = 3;
  else if (leftover == 4) replace = 1;

  for (let i = 0; i < replace; i++) parts.pop();
  for (let i = 0; i < replace; i++) parts.push('=');

  return parts.join('');
}

/** @module AmpCurlUrl */
module.exports = createCurlsSubdomain;
<|endoftext|>


<commit_before>/**
 * Template Plugin : Includes templates associated with a given file when said file is imported.
 *
 * Config:
 *    root:
 *      templates:
 *        Key value hash mapping file names to arrays of templates to include
 *
 *        Special Values:
 *          auto-include: Key value pair mapping a regular expression key to a series of values
 *              to insert. Matching groups in the regular expression may be replaced using $i notation.
 *
 *              Example: 'js/views/(.*)\\.js': ['templates/$1.handlebars']
 *
 * Mixins:
 *  The template plugin will mixin auto-include mappings per item, giving priority to the local version.
 *  File mappings will be mixed in but are executed within the scope of the mixin only. I.e. foo.js
 *  in the local file will not match file mappings for foo.js in a mixin.
 *
 */
var _ = require('underscore'),
    build = require('../build'),
    path = require('path');

module.exports = {
  mode: 'scripts',
  priority: 50,

  loadMixin: function(context, next, complete) {
    var mixinTemplates = context.loadedMixin.templates;
    if (mixinTemplates) {
      var templates = context.mixins.originalConfig.templates || {},
          configTemplates = _.clone(context.config.attributes.templates || templates),
          assigned = false;

      var value = mixinTemplates['auto-include'];
      if (value) {
        if (!_.has(templates, 'auto-include')) {
          configTemplates['auto-include'] = _.clone(value);
          assigned = true;
        } else {
          _.defaults(configTemplates['auto-include'], value);
          assigned = true;
        }
      }

      if (assigned) {
        context.config.attributes.templates = configTemplates;
      }
    }
    next(complete);
  },

  resourceList: function(context, next, complete) {
    var mixin = context.resource.mixin,
        attr = (mixin && mixin.parent) || context.config.attributes;

    next(function(err, ret) {
      if (err || !ret) {
        return complete(err);
      }

      function pushTemplates(templates) {
        _.each(templates, function(template) {
          ret.push({
            src: context.mixins.resolvePath(template, context.resource.mixin),
            name: template,
            template: true
          });
        });
      }

      var views = attr.templates || attr.views || {},
          resource = context.resource.originalSrc || context.resource.src || context.resource,
          mixinRoot = (context.resource.mixin && context.resource.mixin.root) || '';
      if (_.isString(resource) && resource.indexOf(mixinRoot) === 0) {
        resource = resource.substring(mixinRoot.length);
      }

      var deferComplete;
      if (build.filterResource(context.resource, context)) {
        pushTemplates(views[resource]);

        if (views['auto-include']) {
          var config = context.configCache['template-auto-include'];
          if (!config) {
            config = module.exports.generateMappings(views['auto-include']);
            context.configCache['template-auto-include'] = config;
          }

          var autoIncludes = [];
          _.each(config, function(mapping) {
            var remap = module.exports.remapFile(mapping, resource);
            if (remap) {
              autoIncludes.push.apply(autoIncludes, remap);
            }
          });
          if (autoIncludes.length) {
            deferComplete = true;

            context.fileUtil.fileList(autoIncludes, function(err, autoIncludes) {
              if (err) {
                return complete(err);
              }

              var watchDirs = [];
              autoIncludes = _.filter(autoIncludes, function(file) {
                if (file.enoent) {
                  watchDirs.push({watch: path.dirname(file.src)});
                } else {
                  return true;
                }
              });
              autoIncludes = _.map(autoIncludes, function(include) { return include.src || include; });

              pushTemplates(autoIncludes);
              ret.push.apply(ret, watchDirs);

              complete(undefined, ret);
            });
          }
        }
      }
      if (!deferComplete) {
        complete(undefined, ret);
      }
    });
  },

  resource: function(context, next, complete) {
    var resource = context.resource;

    if (resource.watch) {
      function generator(buildContext, callback) {
        callback(undefined, {data: '', noSeparator: true});
      }
      generator.sourceFile = resource.watch;
      complete(undefined, generator);
    } else {
      next(complete);
    }
  },

  generateMappings: function(autoInclude) {
    return _.map(autoInclude, function(templates, source) {
      if (!_.isArray(templates)) {
        templates = [templates];
      }
      return {regex: new RegExp(source), templates: templates};
    });
  },
  remapFile: function(mapping, resource) {
    var match;
    if (match = mapping.regex.exec(resource)) {
      return _.map(mapping.templates, function(template) {
        // Work in reverse so $10 takes priority over $1
        var i = match.length;
        while (i--) {
          template = template.replace('$' + i, match[i]);
        }
        return template;
      });
    }
  }
};
<commit_msg>Ignore missing directories on tempate auto-include<commit_after>/**
 * Template Plugin : Includes templates associated with a given file when said file is imported.
 *
 * Config:
 *    root:
 *      templates:
 *        Key value hash mapping file names to arrays of templates to include
 *
 *        Special Values:
 *          auto-include: Key value pair mapping a regular expression key to a series of values
 *              to insert. Matching groups in the regular expression may be replaced using $i notation.
 *
 *              Example: 'js/views/(.*)\\.js': ['templates/$1.handlebars']
 *
 * Mixins:
 *  The template plugin will mixin auto-include mappings per item, giving priority to the local version.
 *  File mappings will be mixed in but are executed within the scope of the mixin only. I.e. foo.js
 *  in the local file will not match file mappings for foo.js in a mixin.
 *
 */
var _ = require('underscore'),
    build = require('../build'),
    path = require('path');

module.exports = {
  mode: 'scripts',
  priority: 50,

  loadMixin: function(context, next, complete) {
    var mixinTemplates = context.loadedMixin.templates;
    if (mixinTemplates) {
      var templates = context.mixins.originalConfig.templates || {},
          configTemplates = _.clone(context.config.attributes.templates || templates),
          assigned = false;

      var value = mixinTemplates['auto-include'];
      if (value) {
        if (!_.has(templates, 'auto-include')) {
          configTemplates['auto-include'] = _.clone(value);
          assigned = true;
        } else {
          _.defaults(configTemplates['auto-include'], value);
          assigned = true;
        }
      }

      if (assigned) {
        context.config.attributes.templates = configTemplates;
      }
    }
    next(complete);
  },

  resourceList: function(context, next, complete) {
    var mixin = context.resource.mixin,
        attr = (mixin && mixin.parent) || context.config.attributes;

    next(function(err, ret) {
      if (err || !ret) {
        return complete(err);
      }

      function pushTemplates(templates) {
        _.each(templates, function(template) {
          ret.push({
            src: context.mixins.resolvePath(template, context.resource.mixin),
            name: template,
            template: true
          });
        });
      }

      var views = attr.templates || attr.views || {},
          resource = context.resource.originalSrc || context.resource.src || context.resource,
          mixinRoot = (context.resource.mixin && context.resource.mixin.root) || '';
      if (_.isString(resource) && resource.indexOf(mixinRoot) === 0) {
        resource = resource.substring(mixinRoot.length);
      }

      var deferComplete;
      if (build.filterResource(context.resource, context)) {
        pushTemplates(views[resource]);

        if (views['auto-include']) {
          var config = context.configCache['template-auto-include'];
          if (!config) {
            config = module.exports.generateMappings(views['auto-include']);
            context.configCache['template-auto-include'] = config;
          }

          var autoIncludes = [];
          _.each(config, function(mapping) {
            var remap = module.exports.remapFile(mapping, resource);
            if (remap) {
              autoIncludes.push.apply(autoIncludes, remap);
            }
          });
          if (autoIncludes.length) {
            deferComplete = true;

            context.fileUtil.fileList(autoIncludes, function(err, autoIncludes) {
              if (err) {
                return complete(err);
              }

              var watchDirs = [];
              autoIncludes = _.filter(autoIncludes, function(file) {
                if (file.enoent) {
                  watchDirs.push({watch: path.dirname(file.src)});
                } else {
                  return true;
                }
              });
              autoIncludes = _.map(autoIncludes, function(include) { return include.src || include; });

              pushTemplates(autoIncludes);
              ret.push.apply(ret, watchDirs);

              complete(undefined, ret);
            });
          }
        }
      }
      if (!deferComplete) {
        complete(undefined, ret);
      }
    });
  },

  resource: function(context, next, complete) {
    var resource = context.resource;

    if (resource.watch) {
      function generator(buildContext, callback) {
        // Ensure that the directory actually exists
        var path = context.fileUtil.resolvePath(resource.watch);
        context.fileUtil.stat(path, function(err, stat) {
          // Ignore any errors here
          var inputs = [];
          if (stat && stat.isDirectory()) {
            inputs.push(path);
          }
          callback(undefined, {inputs: inputs, data: '', noSeparator: true});
        });
      }
      complete(undefined, generator);
    } else {
      next(complete);
    }
  },

  generateMappings: function(autoInclude) {
    return _.map(autoInclude, function(templates, source) {
      if (!_.isArray(templates)) {
        templates = [templates];
      }
      return {regex: new RegExp(source), templates: templates};
    });
  },
  remapFile: function(mapping, resource) {
    var match;
    if (match = mapping.regex.exec(resource)) {
      return _.map(mapping.templates, function(template) {
        // Work in reverse so $10 takes priority over $1
        var i = match.length;
        while (i--) {
          template = template.replace('$' + i, match[i]);
        }
        return template;
      });
    }
  }
};
<|endoftext|>


<commit_before>// Grab the config env file if it's there
var config;

try{
    config = require('./config.env');
} catch(e) {
    config = {};
}

module.exports = function(){
    if(isEmpty(config)){
        //default values if configuration not present
        return {
            'databaseURL' : 'mongodb://localhost:27017/quindar'
        };
    } else {
        //values of NODE_ENV - 'staging', 'production', 'development'
        if(process.env.NODE_ENV) {
            return {
                'databaseURL' : config[process.env.NODE_ENV].databaseURL
            };
        } else { //return values for development environment in case NODE_ENV not set
            return {
                'databaseURL' : config.development.databaseURL
            };
        }
    }
};

function isEmpty(obj) {
    for(var key in obj) {
        if(obj.hasOwnProperty(key))
            return false;
    }
    return true;
}
<commit_msg>add comments for mongo connection url<commit_after>// Grab the config env file if it's there
var config;

try{
    config = require('./config.env');
} catch(e) {
    config = {};
}

module.exports = function(){
    if(isEmpty(config)){
        //default values if configuration not present
        return { // mongodb://<hostname>:<port>/<database-name>
            'databaseURL' : 'mongodb://localhost:27017/quindar'
        };
    } else {
        //values of NODE_ENV - 'staging', 'production', 'development'
        if(process.env.NODE_ENV) {
            return {
                'databaseURL' : config[process.env.NODE_ENV].databaseURL
            };
        } else { //return values for development environment in case NODE_ENV not set
            return {
                'databaseURL' : config.development.databaseURL
            };
        }
    }
};

function isEmpty(obj) {
    for(var key in obj) {
        if(obj.hasOwnProperty(key))
            return false;
    }
    return true;
}
<|endoftext|>


<commit_before>'use strict';

var _ = require('lodash');
var moment = require('moment');
var times = require('../times');
var levels = require('../levels');

function init(ctx) {
  var utils = require('../utils')(ctx);
  var firstPrefs = true;
  var lastStateNotification = null;

  var sensorState = {
    name: 'xdrip-js'
    , label: 'Sensor Status'
    , pluginType: 'pill-status'
  };

  sensorState.getPrefs = function getPrefs(sbx) {
    var prefs = {
      enableAlerts: sbx.extendedSettings.enableAlerts || false
      , warnBatV: sbx.extendedSettings.warnBatV || 300
      , stateNotifyIntrvl: sbx.extendedSettings.stateNotifyIntrvl || 0.5
    };

    if (firstPrefs) {
      firstPrefs = false;
      console.info('xdrip-js Prefs:', prefs);
    }

    return prefs;
  };

  sensorState.setProperties = function setProperties (sbx) {
    sbx.offerProperty('sensorState', function setProp ( ) {
      return sensorState.getStateString(sbx);
    });
  };

  sensorState.checkNotifications = function checkNotifications(sbx) {

    var info = sbx.properties.sensorState;

    if (info && info.notification) {
      var notification = _.extend({}, info.notification, {
        plugin: sensorState
        , debug: {
          stateString: info.lastStateString
        }
      });

      sbx.notifications.requestNotify(notification);
    }

  };

  sensorState.getStateString = function findLatestState(sbx) {
    var prefs = sensorState.getPrefs(sbx);

    var recentHours = 24;
    var recentMills = sbx.time - times.hours(recentHours).msecs;

    var result = {
      seenDevices: { }
      , latest: null
      , lastDevice: null
      , lastState: null
      , lastStateString: null
      , lastStateStringShort: null
      , lastSessionStart: null
      , lastStateTime: null
      , lastTxId: null
      , lastTxStatus: null
      , lastTxStatusString: null
      , lastTxStatusStringShort: null
      , lastTxActivation: null
      , lastMode: null
      , lastRssi: null
      , lastUnfiltered: null
      , lastFiltered: null
      , lastNoise: null
      , lastNoiseString: null
      , lastSlope: null
      , lastIntercept: null
      , lastCalType: null
      , lastCalibrationDate: null
      , lastBatteryTimestamp: null
      , lastVoltageA: null
      , lastVoltageB: null
      , lastTemperature: null
      , lastResistance: null
    };

    function toMoments (status) {
      return {
        when:  moment(status.mills)
        , timestamp: status.xdripjs && status.xdripjs.timestamp && moment(status.xdripjs.timestamp)
      };
    }

    function getDevice(status) {
      var uri = status.device || 'device';
      var device = result.seenDevices[uri];

      if (!device) {
        device = {
          name: utils.deviceName(uri)
          , uri: uri
        };

        result.seenDevices[uri] = device;
      }
      return device;
    }

    var recentData = _.chain(sbx.data.devicestatus)
      .filter(function (status) {
        return ('xdripjs' in status) && sbx.entryMills(status) <= sbx.time && sbx.entryMills(status) >= recentMills;
      })
      .value( );

    recentData = _.sortBy(recentData, 'xdripjs.timestamp');

    _.forEach(recentData, function eachStatus (status) {
      getDevice(status);

      var moments = toMoments(status);

      if (status.xdripjs && (!result.latest || moments.timestamp && moments.timestamp.isAfter(result.lastStateTime))) {
        result.latest = status;
        result.lastStateTime = moment(status.xdripjs.timestamp);
      }
    });

    var sendNotification = false;
    var sound = 'incoming';
    var message;
    var title;

    var sensorInfo = result.latest;

    result.level = levels.NONE;

    if (sensorInfo && sensorInfo.xdripjs) {

      if (sensorInfo.xdripjs.state != 0x6) {
        // Send warning notification for all states that are not 'OK'
        // but only send state notifications at interval preference
        if (!lastStateNotification || (lastStateNotification.state != sensorInfo.xdripjs.state) || !prefs.stateNotifyIntrvl || (moment().diff(lastStateNotification.timestamp, 'minutes') > (prefs.stateNotifyIntrvl*60))) {
          sendNotification = true;
          lastStateNotification = {
            timestamp: moment()
            , state: sensorInfo.xdripjs.state
          };
        }
        console.log('send state notification: ' + sendNotification + ' - ' + moment().diff(lastStateNotification, 'minutes'));

        message = 'G5 Sensor state: ' + sensorInfo.xdripjs.stateString;
        title = 'G5 Sensor state: ' + sensorInfo.xdripjs.stateString;

        if (sensorInfo.xdripjs.state == 0x7) {
          // If it is a calibration request, only use INFO
          result.level = levels.INFO;
        } else {
          result.level = levels.WARN;
        }
      }

      if (sensorInfo.xdripjs.voltagea && (sensorInfo.xdripjs.voltagea < prefs.warnBatV)) {
        sendNotification = true;
        message = 'G5 Battery A Low Voltage: ' + sensorInfo.xdripjs.voltagea;
        title = 'G5 Battery Low';
        result.level = levels.WARN;
      }

      if (sensorInfo.xdripjs.voltageb && (sensorInfo.xdripjs.voltageb < prefs.warnBatV)) {
        sendNotification = true;
        message = 'G5 Battery B Low Voltage: ' + sensorInfo.xdripjs.voltageb;
        title = 'G5 Battery Low';
        result.level = levels.WARN;
      }

      if (prefs.enableAlerts && sendNotification) {
        result.notification = {
          title: title
          , message: message
          , pushoverSound: sound
          , level: result.level
          , group: 'xDrip-js'
        };
      }

      result.lastState = sensorInfo.xdripjs.state;
      result.lastStateString = sensorInfo.xdripjs.stateString;
      result.lastStateStringShort = sensorInfo.xdripjs.stateStringShort;
      result.lastSessionStart = sensorInfo.xdripjs.sessionStart;
      result.lastTxId = sensorInfo.xdripjs.txId;
      result.lastTxStatus = sensorInfo.xdripjs.txStatus;
      result.lastTxStatusString = sensorInfo.xdripjs.txStatusString;
      result.lastTxStatusStringShort = sensorInfo.xdripjs.txStatusStringShort;
      result.lastTxActivation = sensorInfo.xdripjs.txActivation;
      result.lastMode = sensorInfo.xdripjs.mode;
      result.lastRssi = sensorInfo.xdripjs.rssi;
      result.lastUnfiltered = sensorInfo.xdripjs.unfiltered;
      result.lastFiltered = sensorInfo.xdripjs.filtered;
      result.lastNoise = sensorInfo.xdripjs.noise;
      result.lastNoiseString = sensorInfo.xdripjs.noiseString;
      result.lastSlope = Math.round(sensorInfo.xdripjs.slope * 100) / 100.0;
      result.lastIntercept = Math.round(sensorInfo.xdripjs.intercept * 100) / 100.0;
      result.lastCalType = sensorInfo.xdripjs.calType;
      result.lastCalibrationDate = sensorInfo.xdripjs.lastCalibrationDate;
      result.lastBatteryTimestamp = sensorInfo.xdripjs.batteryTimestamp;
      result.lastVoltageA = sensorInfo.xdripjs.voltagea;
      result.lastVoltageB = sensorInfo.xdripjs.voltageb;
      result.lastTemperature = sensorInfo.xdripjs.temperature;
      result.lastResistance = sensorInfo.xdripjs.resistance;
    }

    return result;
  };

  sensorState.updateVisualisation = function updateVisualisation (sbx) {

    var sensor = sbx.properties.sensorState;
    var sessionDuration = 'Unknown';
    var info = [];

    _.forIn(sensor.seenDevices, function seenDevice (device) {
      info.push( { label: 'Seen: ', value: device.name } );
    });

    info.push( { label: 'State Time: ', value: (sensor && sensor.lastStateTime && moment().diff(sensor.lastStateTime, 'minutes') + ' minutes ago') || 'Unknown' } );
    info.push( { label: 'Mode: ', value: (sensor && sensor.lastMode) || 'Unknown' } );
    info.push( { label: 'Status: ', value: (sensor && sensor.lastStateString) || 'Unknown' } );

    // session start is only valid if in a session
    if (sensor && sensor.lastSessionStart && (sensor.lastState != 0x1)) {
      let diffTime = moment().diff(moment(sensor.lastSessionStart));
      let duration = moment.duration(diffTime);

      sessionDuration = duration.days() + ' days ' + duration.hours() + ' hours';
    } else {
      sessionDuration = 'N/A';
    }

    info.push( { label: 'Session Age: ', value: sessionDuration } );
    info.push( { label: 'Tx ID: ', value: (sensor && sensor.lastTxId) || 'Unknown' } );
    info.push( { label: 'Tx Status: ', value: (sensor && sensor.lastTxStatusString) || 'Unknown' } );

    if (sensor) {
      if (sensor.lastTxActivation) {
        info.push( { label: 'Tx Age: ', value: moment().diff(moment(sensor.lastTxActivation), 'days') + ' days' } );
      }

      if (sensor.lastRssi) {
        info.push( { label: 'RSSI: ', value: sensor.lastRssi } );
      }

      if (sensor.lastUnfiltered) {
        info.push( { label: 'Unfiltered: ', value: sensor.lastUnfiltered } );
      }

      if (sensor.lastFiltered) {
        info.push( { label: 'Filtered: ', value: sensor.lastFiltered } );
      }

      if (sensor.lastNoiseString) {
        info.push( { label: 'Noise: ', value: sensor.lastNoiseString } );
      }

      if (sensor.lastSlope) {
        info.push( { label: 'Slope: ', value: sensor.lastSlope } );
      }

      if (sensor.lastIntercept) {
        info.push( { label: 'Intercept: ', value: sensor.lastIntercept } );
      }

      if (sensor.lastCalType) {
        info.push( { label: 'CalType: ', value: sensor.lastCalType } );
      }

      if (sensor.lastCalibrationDate) {
        info.push( { label: 'Calibration: ', value: moment().diff(moment(sensor.lastCalibrationDate), 'hours') + ' hours ago' } );
      }

      if (sensor.lastBatteryTimestamp) {
        info.push( { label: 'Battery: ', value: moment().diff(moment(sensor.lastBatteryTimestamp), 'minutes') + ' minutes ago' } );
      }

      if (sensor.lastVoltageA) {
        info.push( { label: 'VoltageA: ', value: sensor.lastVoltageA } );
      }

      if (sensor.lastVoltageB) {
        info.push( { label: 'VoltageB: ', value: sensor.lastVoltageB } );
      }

      if (sensor.lastTemperature) {
        info.push( { label: 'Temperature: ', value: sensor.lastTemperature } );
      }

      if (sensor.lastResistance) {
        info.push( { label: 'Resistance: ', value: sensor.lastResistance } );
      }

      var statusClass = null;
      if (sensor.level === levels.URGENT) {
        statusClass = 'urgent';
      } else if (sensor.level === levels.WARN) {
        statusClass = 'warn';
      } else if (sensor.level === levels.INFO) {
        // Still highlight even the 'INFO' events for now
        statusClass = 'warn';
      }

      sbx.pluginBase.updatePillText(sensorState, {
        value: (sensor && sensor.lastStateStringShort) || (sensor && sensor.lastStateString) || 'Unknown'
        , label: 'CGM'
        , info: info
        , pillClass: statusClass
      });
    }
  };

  return sensorState;
}

module.exports = init;

<commit_msg>Changed to consistently use CGM instead of Sensor of G5.<commit_after>'use strict';

var _ = require('lodash');
var moment = require('moment');
var times = require('../times');
var levels = require('../levels');

function init(ctx) {
  var utils = require('../utils')(ctx);
  var firstPrefs = true;
  var lastStateNotification = null;

  var sensorState = {
    name: 'xdrip-js'
    , label: 'CGM Status'
    , pluginType: 'pill-status'
  };

  sensorState.getPrefs = function getPrefs(sbx) {
    var prefs = {
      enableAlerts: sbx.extendedSettings.enableAlerts || false
      , warnBatV: sbx.extendedSettings.warnBatV || 300
      , stateNotifyIntrvl: sbx.extendedSettings.stateNotifyIntrvl || 0.5
    };

    if (firstPrefs) {
      firstPrefs = false;
      console.info('xdrip-js Prefs:', prefs);
    }

    return prefs;
  };

  sensorState.setProperties = function setProperties (sbx) {
    sbx.offerProperty('sensorState', function setProp ( ) {
      return sensorState.getStateString(sbx);
    });
  };

  sensorState.checkNotifications = function checkNotifications(sbx) {

    var info = sbx.properties.sensorState;

    if (info && info.notification) {
      var notification = _.extend({}, info.notification, {
        plugin: sensorState
        , debug: {
          stateString: info.lastStateString
        }
      });

      sbx.notifications.requestNotify(notification);
    }

  };

  sensorState.getStateString = function findLatestState(sbx) {
    var prefs = sensorState.getPrefs(sbx);

    var recentHours = 24;
    var recentMills = sbx.time - times.hours(recentHours).msecs;

    var result = {
      seenDevices: { }
      , latest: null
      , lastDevice: null
      , lastState: null
      , lastStateString: null
      , lastStateStringShort: null
      , lastSessionStart: null
      , lastStateTime: null
      , lastTxId: null
      , lastTxStatus: null
      , lastTxStatusString: null
      , lastTxStatusStringShort: null
      , lastTxActivation: null
      , lastMode: null
      , lastRssi: null
      , lastUnfiltered: null
      , lastFiltered: null
      , lastNoise: null
      , lastNoiseString: null
      , lastSlope: null
      , lastIntercept: null
      , lastCalType: null
      , lastCalibrationDate: null
      , lastBatteryTimestamp: null
      , lastVoltageA: null
      , lastVoltageB: null
      , lastTemperature: null
      , lastResistance: null
    };

    function toMoments (status) {
      return {
        when:  moment(status.mills)
        , timestamp: status.xdripjs && status.xdripjs.timestamp && moment(status.xdripjs.timestamp)
      };
    }

    function getDevice(status) {
      var uri = status.device || 'device';
      var device = result.seenDevices[uri];

      if (!device) {
        device = {
          name: utils.deviceName(uri)
          , uri: uri
        };

        result.seenDevices[uri] = device;
      }
      return device;
    }

    var recentData = _.chain(sbx.data.devicestatus)
      .filter(function (status) {
        return ('xdripjs' in status) && sbx.entryMills(status) <= sbx.time && sbx.entryMills(status) >= recentMills;
      })
      .value( );

    recentData = _.sortBy(recentData, 'xdripjs.timestamp');

    _.forEach(recentData, function eachStatus (status) {
      getDevice(status);

      var moments = toMoments(status);

      if (status.xdripjs && (!result.latest || moments.timestamp && moments.timestamp.isAfter(result.lastStateTime))) {
        result.latest = status;
        result.lastStateTime = moment(status.xdripjs.timestamp);
      }
    });

    var sendNotification = false;
    var sound = 'incoming';
    var message;
    var title;

    var sensorInfo = result.latest;

    result.level = levels.NONE;

    if (sensorInfo && sensorInfo.xdripjs) {

      if (sensorInfo.xdripjs.state != 0x6) {
        // Send warning notification for all states that are not 'OK'
        // but only send state notifications at interval preference
        if (!lastStateNotification || (lastStateNotification.state != sensorInfo.xdripjs.state) || !prefs.stateNotifyIntrvl || (moment().diff(lastStateNotification.timestamp, 'minutes') > (prefs.stateNotifyIntrvl*60))) {
          sendNotification = true;
          lastStateNotification = {
            timestamp: moment()
            , state: sensorInfo.xdripjs.state
          };
        }

        message = 'CGM state: ' + sensorInfo.xdripjs.stateString;
        title = 'CGM state: ' + sensorInfo.xdripjs.stateString;

        if (sensorInfo.xdripjs.state == 0x7) {
          // If it is a calibration request, only use INFO
          result.level = levels.INFO;
        } else {
          result.level = levels.WARN;
        }
      }

      if (sensorInfo.xdripjs.voltagea && (sensorInfo.xdripjs.voltagea < prefs.warnBatV)) {
        sendNotification = true;
        message = 'CGM Battery A Low Voltage: ' + sensorInfo.xdripjs.voltagea;
        title = 'CGM Battery Low';
        result.level = levels.WARN;
      }

      if (sensorInfo.xdripjs.voltageb && (sensorInfo.xdripjs.voltageb < prefs.warnBatV)) {
        sendNotification = true;
        message = 'CGM Battery B Low Voltage: ' + sensorInfo.xdripjs.voltageb;
        title = 'CGM Battery Low';
        result.level = levels.WARN;
      }

      if (prefs.enableAlerts && sendNotification) {
        result.notification = {
          title: title
          , message: message
          , pushoverSound: sound
          , level: result.level
          , group: 'xDrip-js'
        };
      }

      result.lastState = sensorInfo.xdripjs.state;
      result.lastStateString = sensorInfo.xdripjs.stateString;
      result.lastStateStringShort = sensorInfo.xdripjs.stateStringShort;
      result.lastSessionStart = sensorInfo.xdripjs.sessionStart;
      result.lastTxId = sensorInfo.xdripjs.txId;
      result.lastTxStatus = sensorInfo.xdripjs.txStatus;
      result.lastTxStatusString = sensorInfo.xdripjs.txStatusString;
      result.lastTxStatusStringShort = sensorInfo.xdripjs.txStatusStringShort;
      result.lastTxActivation = sensorInfo.xdripjs.txActivation;
      result.lastMode = sensorInfo.xdripjs.mode;
      result.lastRssi = sensorInfo.xdripjs.rssi;
      result.lastUnfiltered = sensorInfo.xdripjs.unfiltered;
      result.lastFiltered = sensorInfo.xdripjs.filtered;
      result.lastNoise = sensorInfo.xdripjs.noise;
      result.lastNoiseString = sensorInfo.xdripjs.noiseString;
      result.lastSlope = Math.round(sensorInfo.xdripjs.slope * 100) / 100.0;
      result.lastIntercept = Math.round(sensorInfo.xdripjs.intercept * 100) / 100.0;
      result.lastCalType = sensorInfo.xdripjs.calType;
      result.lastCalibrationDate = sensorInfo.xdripjs.lastCalibrationDate;
      result.lastBatteryTimestamp = sensorInfo.xdripjs.batteryTimestamp;
      result.lastVoltageA = sensorInfo.xdripjs.voltagea;
      result.lastVoltageB = sensorInfo.xdripjs.voltageb;
      result.lastTemperature = sensorInfo.xdripjs.temperature;
      result.lastResistance = sensorInfo.xdripjs.resistance;
    }

    return result;
  };

  sensorState.updateVisualisation = function updateVisualisation (sbx) {

    var sensor = sbx.properties.sensorState;
    var sessionDuration = 'Unknown';
    var info = [];

    _.forIn(sensor.seenDevices, function seenDevice (device) {
      info.push( { label: 'Seen: ', value: device.name } );
    });

    info.push( { label: 'State Time: ', value: (sensor && sensor.lastStateTime && moment().diff(sensor.lastStateTime, 'minutes') + ' minutes ago') || 'Unknown' } );
    info.push( { label: 'Mode: ', value: (sensor && sensor.lastMode) || 'Unknown' } );
    info.push( { label: 'Status: ', value: (sensor && sensor.lastStateString) || 'Unknown' } );

    // session start is only valid if in a session
    if (sensor && sensor.lastSessionStart && (sensor.lastState != 0x1)) {
      let diffTime = moment().diff(moment(sensor.lastSessionStart));
      let duration = moment.duration(diffTime);

      sessionDuration = duration.days() + ' days ' + duration.hours() + ' hours';
    } else {
      sessionDuration = 'N/A';
    }

    info.push( { label: 'Session Age: ', value: sessionDuration } );
    info.push( { label: 'Tx ID: ', value: (sensor && sensor.lastTxId) || 'Unknown' } );
    info.push( { label: 'Tx Status: ', value: (sensor && sensor.lastTxStatusString) || 'Unknown' } );

    if (sensor) {
      if (sensor.lastTxActivation) {
        info.push( { label: 'Tx Age: ', value: moment().diff(moment(sensor.lastTxActivation), 'days') + ' days' } );
      }

      if (sensor.lastRssi) {
        info.push( { label: 'RSSI: ', value: sensor.lastRssi } );
      }

      if (sensor.lastUnfiltered) {
        info.push( { label: 'Unfiltered: ', value: sensor.lastUnfiltered } );
      }

      if (sensor.lastFiltered) {
        info.push( { label: 'Filtered: ', value: sensor.lastFiltered } );
      }

      if (sensor.lastNoiseString) {
        info.push( { label: 'Noise: ', value: sensor.lastNoiseString } );
      }

      if (sensor.lastSlope) {
        info.push( { label: 'Slope: ', value: sensor.lastSlope } );
      }

      if (sensor.lastIntercept) {
        info.push( { label: 'Intercept: ', value: sensor.lastIntercept } );
      }

      if (sensor.lastCalType) {
        info.push( { label: 'CalType: ', value: sensor.lastCalType } );
      }

      if (sensor.lastCalibrationDate) {
        info.push( { label: 'Calibration: ', value: moment().diff(moment(sensor.lastCalibrationDate), 'hours') + ' hours ago' } );
      }

      if (sensor.lastBatteryTimestamp) {
        info.push( { label: 'Battery: ', value: moment().diff(moment(sensor.lastBatteryTimestamp), 'minutes') + ' minutes ago' } );
      }

      if (sensor.lastVoltageA) {
        info.push( { label: 'VoltageA: ', value: sensor.lastVoltageA } );
      }

      if (sensor.lastVoltageB) {
        info.push( { label: 'VoltageB: ', value: sensor.lastVoltageB } );
      }

      if (sensor.lastTemperature) {
        info.push( { label: 'Temperature: ', value: sensor.lastTemperature } );
      }

      if (sensor.lastResistance) {
        info.push( { label: 'Resistance: ', value: sensor.lastResistance } );
      }

      var statusClass = null;
      if (sensor.level === levels.URGENT) {
        statusClass = 'urgent';
      } else if (sensor.level === levels.WARN) {
        statusClass = 'warn';
      } else if (sensor.level === levels.INFO) {
        // Still highlight even the 'INFO' events for now
        statusClass = 'warn';
      }

      sbx.pluginBase.updatePillText(sensorState, {
        value: (sensor && sensor.lastStateStringShort) || (sensor && sensor.lastStateString) || 'Unknown'
        , label: 'CGM'
        , info: info
        , pillClass: statusClass
      });
    }
  };

  return sensorState;
}

module.exports = init;

<|endoftext|>


<commit_before>const Sequelize = require("sequelize");
const Op = Sequelize.Op;

const Feed = require("../models/feed");
const Article = require("../models/article");
const Hotlink = require("../models/hotlink");

const autodiscover = require("../util/autodiscover");
const parseFeed = require("../util/parser");
const language = require("../util/language");
const cheerio = require("cheerio");
const htmlparser2 = require('htmlparser2');

var striptags = require("striptags");

//set the maximum number of feeds to be processed at once
const feedCount = process.env.MAX_FEEDCOUNT || 10

//put the try/catch block into a higher function and then put the async/await functions of that function
const catchAsync = fn => {
  return (req, res, next) => {
    fn(req, res, next).catch(next);
  };
};

exports.getCrawl = catchAsync(async (req, res, next) => {
  try {
    //only get feeds with an errorCount lower than 25
    const feeds = await Feed.findAll({
      where: {
        active: true,
        errorCount: {
          [Op.lt]: 25
        }
      },
      order: [
        ['updatedAt', 'DESC']
      ],
      limit: feedCount
    });

    if (feeds.length > 0) {
      feeds.forEach(async function(feed) {
        //discover rssUrl
        const url = await autodiscover.discover(feed.url);

        //do not process undefined URLs
        if(typeof url !== "undefined") {
          try {
            const feeditem = await parseFeed.process(url);
            if (feeditem) {

              //process all feed posts
              feeditem.posts.forEach(function(post) {
                processArticle(feed, post);
              });

              //reset the feed count
              feed.update({
                errorCount: 0
              });
            }
          } catch (err) {
            console.log(err.stack.split("\n", 1).join("") + " - " + feed.url);
            //update the errorCount
            feed.update({
              errorCount: Sequelize.literal("errorCount + 1")
            });
          }
        } else {
          //update the errorCount
          feed.update({
            errorCount: Sequelize.literal("errorCount + 1")
          });
        }

      //touch updatedAt
      feed.changed('updatedAt', true);

      });
    }

    //destroy records older than two weeks
    Hotlink.destroy({
      where: {
        createdAt: {
          [Op.lte] : (new Date() -  14 * 24 * 60 * 60 * 1000)
        }
      }
    });

    return res.status(200).json("Crawling started.");
  } catch (err) {
    return next(err);
  }
});

async function processArticle(feed, post) {
  try {
    //try to find any existing article with the same link and post title
    const article = await Article.findOne({
      where: {
        [Op.or]: [
          {
            url: post.link
          },
          {
            subject: post.title
          }
        ],
        [Op.and]: {
          feedId: feed.id
        }
      }
    });

    //if none, add new article to the database
    if (!article) {
      //remove any script tags
      //dismiss "cheerio.load() expects a string" by converting to string

      //htmlparser2 has error-correcting mechanisms, which may be useful when parsing non-HTML content.
      const dom = htmlparser2.parseDocument(post.description);
      const $ = cheerio.load(dom, { _useHtmlParser2: true });

      //dismiss undefined errors
      if (typeof $ !== 'undefined') {
        $('script').remove();

        //execute hotlink feature by collecting all the links in each RSS post
        //https://github.com/passiomatic/coldsweat/issues/68#issuecomment-272963268
        $('a').each(function() {
          //find domain name for each link
          domain = (new URL(post.link));
          domain = domain.hostname;

          //fetch all urls referenced to other websites. Insert these into the hotlinks table
          if ($(this).attr('href')) {
            if (!$(this).attr('href').includes(domain)) {
              //only add http and https urls to database
              if ($(this).attr('href').indexOf("http://") == 0 || $(this).attr('href').indexOf("https://") == 0) {
                Hotlink.create({
                  url: $(this).attr('href')
                });
              }
            }
          }
        });

        //parse media RSS feeds: https://www.rssboard.org/media-rss
        if (post['media:group']) {
          postLink = post['media:group']['media:content']['@']['url'];
          postTitle = post['media:group']['media:title']['#'];
          postContent = post['media:group']['media:description']['#'];
          postContentStripped = striptags(post['media:group']['media:description']['#']);
          postLanguage = language.get(post['media:group']['media:description']['#']);
        } else {
          postLink = post.link;
          postTitle = post.title;
          postContent = $.html();
          postContentStripped = striptags($.html(), ["a", "img", "strong"]);
          postLanguage = language.get($.html());
        }

        //add article
        Article.create({
          feedId: feed.id,
          status: "unread",
          star_ind: 0,
          url: postLink,
          image_url: "",
          subject: postTitle || 'No title',
          content: postContent,
          contentStripped: postContentStripped,
          language: postLanguage,
          //contentSnippet: item.contentSnippet,
          //author: item.author,
          //default post.pubdate with new Date when empty
          published: post.pubdate || new Date()
        });
      }
    }
  } catch (err) {
    console.log(err);
  }
}
<commit_msg>Update crawl.js<commit_after>const Sequelize = require("sequelize");
const Op = Sequelize.Op;

const Feed = require("../models/feed");
const Article = require("../models/article");
const Hotlink = require("../models/hotlink");

const autodiscover = require("../util/autodiscover");
const parseFeed = require("../util/parser");
const language = require("../util/language");
const cheerio = require("cheerio");
const htmlparser2 = require('htmlparser2');

var striptags = require("striptags");

//set the maximum number of feeds to be processed at once
const feedCount = process.env.MAX_FEEDCOUNT || 100

//put the try/catch block into a higher function and then put the async/await functions of that function
const catchAsync = fn => {
  return (req, res, next) => {
    fn(req, res, next).catch(next);
  };
};

exports.getCrawl = catchAsync(async (req, res, next) => {
  try {
    //only get feeds with an errorCount lower than 25
    const feeds = await Feed.findAll({
      where: {
        active: true,
        errorCount: {
          [Op.lt]: 25
        }
      },
      order: [
        ['updatedAt', 'DESC']
      ],
      limit: feedCount
    });

    if (feeds.length > 0) {
      feeds.forEach(async function(feed) {
        //discover rssUrl
        const url = await autodiscover.discover(feed.url);

        //do not process undefined URLs
        if(typeof url !== "undefined") {
          try {
            const feeditem = await parseFeed.process(url);
            if (feeditem) {

              //process all feed posts
              feeditem.posts.forEach(function(post) {
                processArticle(feed, post);
              });

              //reset the feed count
              feed.update({
                errorCount: 0
              });
            }
          } catch (err) {
            console.log(err.stack.split("\n", 1).join("") + " - " + feed.url);
            //update the errorCount
            feed.update({
              errorCount: Sequelize.literal("errorCount + 1")
            });
          }
        } else {
          //update the errorCount
          feed.update({
            errorCount: Sequelize.literal("errorCount + 1")
          });
        }

      //touch updatedAt
      feed.changed('updatedAt', true);

      });
    }

    //destroy records older than two weeks
    Hotlink.destroy({
      where: {
        createdAt: {
          [Op.lte] : (new Date() -  14 * 24 * 60 * 60 * 1000)
        }
      }
    });

    return res.status(200).json("Crawling started.");
  } catch (err) {
    return next(err);
  }
});

async function processArticle(feed, post) {
  try {
    //try to find any existing article with the same link and post title
    const article = await Article.findOne({
      where: {
        [Op.or]: [
          {
            url: post.link
          },
          {
            subject: post.title
          }
        ],
        [Op.and]: {
          feedId: feed.id
        }
      }
    });

    //if none, add new article to the database
    if (!article) {
      //remove any script tags
      //dismiss "cheerio.load() expects a string" by converting to string

      //htmlparser2 has error-correcting mechanisms, which may be useful when parsing non-HTML content.
      const dom = htmlparser2.parseDocument(post.description);
      const $ = cheerio.load(dom, { _useHtmlParser2: true });

      //dismiss undefined errors
      if (typeof $ !== 'undefined') {
        $('script').remove();

        //execute hotlink feature by collecting all the links in each RSS post
        //https://github.com/passiomatic/coldsweat/issues/68#issuecomment-272963268
        $('a').each(function() {
          //find domain name for each link
          domain = (new URL(post.link));
          domain = domain.hostname;

          //fetch all urls referenced to other websites. Insert these into the hotlinks table
          if ($(this).attr('href')) {
            if (!$(this).attr('href').includes(domain)) {
              //only add http and https urls to database
              if ($(this).attr('href').indexOf("http://") == 0 || $(this).attr('href').indexOf("https://") == 0) {
                Hotlink.create({
                  url: $(this).attr('href')
                });
              }
            }
          }
        });

        //parse media RSS feeds: https://www.rssboard.org/media-rss
        if (post['media:group']) {
          postLink = post['media:group']['media:content']['@']['url'];
          postTitle = post['media:group']['media:title']['#'];
          postContent = post['media:group']['media:description']['#'];
          postContentStripped = striptags(post['media:group']['media:description']['#']);
          postLanguage = language.get(post['media:group']['media:description']['#']);
        } else {
          postLink = post.link;
          postTitle = post.title;
          postContent = $.html();
          postContentStripped = striptags($.html(), ["a", "img", "strong"]);
          postLanguage = language.get($.html());
        }

        //add article
        Article.create({
          feedId: feed.id,
          status: "unread",
          star_ind: 0,
          url: postLink,
          image_url: "",
          subject: postTitle || 'No title',
          content: postContent,
          contentStripped: postContentStripped,
          language: postLanguage,
          //contentSnippet: item.contentSnippet,
          //author: item.author,
          //default post.pubdate with new Date when empty
          published: post.pubdate || new Date()
        });
      }
    }
  } catch (err) {
    console.log(err);
  }
}
<|endoftext|>


<commit_before>import users from './users';
import documents from './documents';
import search from './search';
import roles from './roles';

export default {
  users,
  documents,
  search,
  roles,
};
<commit_msg>fix names<commit_after>import Users from './Users';
import Documents from './Documents';
import Search from './Search';
import Roles from './Roles';

export default {
  Users,
  Documents,
  Search,
  Roles,
};
<|endoftext|>


<commit_before>var router = require('express').Router();
var Note = require('../models/note');

router.post('/notes/', function(req, res) {
  var newNote = new Note({
    user: req.user,
    title: req.body.note.title,
    body_html: req.body.note.body_html
  });
  newNote.save(function(err) {
    if (err) { console.log('OHNOES!', err); }
    else { res.json({ note: newNote }); }
  });
});

// create some records with mongo cli like this:
// $ mongo
// > use caedence_net_development
// > db.notes.insert({ title: "Hello", body_html: "
World
", body_text: "World" })
// WriteResult({ "nInserted" : 1 })
// > db.notes.find()
// { "_id" : ObjectId("562473c0802fa33ca991217b"), "title" : "Hello", "body_html" : "
World
", "body_text" : "World" }
router.get('/notes/', function(req, res) {
  Note.find({ user: req.user }).then(function(notes) {
    res.json(notes);
  });
});

router.get('/notes/:id', function(req, res) {
  var id = req.params.id;
  var note = Note.findOne({ user: req.user, '_id': id }).then(function(note) {
    res.json(note);
  });
});

router.put('/notes/:id', function(req, res) {
  Note.findOne({ user: req.user, '_id': req.params.id }).then(function(note) {
    note.title = req.body.note.title;
    note.body_html = req.body.note.body_html;
    note.save().then(function() {
      res.json({ message: 'Successfully updated note', note: note });
    });
  });
});

router.delete('/notes/:id', function(req, res) {
  Note.findOne({ user: req.user, '_id': req.params.id }).then(function(note) {
    note.remove().then(function(){
      res.json({ message: 'Successfully deleted note.' });
    });
  });
});

module.exports = router;
<commit_msg>No need to quote _id object key.<commit_after>var router = require('express').Router();
var Note = require('../models/note');

router.post('/notes/', function(req, res) {
  var newNote = new Note({
    user: req.user,
    title: req.body.note.title,
    body_html: req.body.note.body_html
  });
  newNote.save(function(err) {
    if (err) { console.log('OHNOES!', err); }
    else { res.json({ note: newNote }); }
  });
});

// create some records with mongo cli like this:
// $ mongo
// > use caedence_net_development
// > db.notes.insert({ title: "Hello", body_html: "
World
", body_text: "World" })
// WriteResult({ "nInserted" : 1 })
// > db.notes.find()
// { "_id" : ObjectId("562473c0802fa33ca991217b"), "title" : "Hello", "body_html" : "
World
", "body_text" : "World" }
router.get('/notes/', function(req, res) {
  Note.find({ user: req.user }).then(function(notes) {
    res.json(notes);
  });
});

router.get('/notes/:id', function(req, res) {
  var id = req.params.id;
  var note = Note.findOne({ user: req.user, _id: id }).then(function(note) {
    res.json(note);
  });
});

router.put('/notes/:id', function(req, res) {
  Note.findOne({ user: req.user, _id: req.params.id }).then(function(note) {
    note.title = req.body.note.title;
    note.body_html = req.body.note.body_html;
    note.save().then(function() {
      res.json({ message: 'Successfully updated note', note: note });
    });
  });
});

router.delete('/notes/:id', function(req, res) {
  Note.findOne({ user: req.user, _id: req.params.id }).then(function(note) {
    note.remove().then(function(){
      res.json({ message: 'Successfully deleted note.' });
    });
  });
});

module.exports = router;
<|endoftext|>


<commit_before>var User = require('../models/user');
var jwt = require('jwt-simple');
var moment = require('moment');
var app = require("../../app");
var jwtTokenSecret = "YOUR_SECRET_STRING";

// ********************** local application methods ************************//

// cheking whether user logged in or not
exports.loggedin = function(req, res, next) {
    res.send(req.isAuthenticated() ? req.user : '0');
}

// logout function
exports.logout = function(req, res, next) {
    req.logout();
    res.status(200).send("");
}

// return the logged in user
exports.me = function(req, res) {
    res.json(req.user || null);
};

// user creation function
exports.create = function(req, res, next) {
    var user = new User(req.body);
    user.provider = 'local';

    // because we set our user.provider to local our models/user.js validation will always be true
    req.assert('name', 'You must enter a name').notEmpty();
    req.assert('email', 'You must enter a valid email address').isEmail();
    req.assert('password', 'Password must be between 8-20 characters long').len(8, 20);
    req.assert('username', 'Username cannot be more than 20 characters').len(1, 20);
    req.assert('confirmPassword', 'Passwords do not match').equals(req.body.password);

    var errors = req.validationErrors();
    if (errors) {
        return res.status(400).send(errors);
    }
    console.log(2);

    // Hard coded for now. Will address this with the user permissions system in v0.3.5
    user.roles = ['authenticated'];
    user.save(function(err) {
        if (err) {
            switch (err.code) {
                case 11000:
                    res.status(400).send([{
                        msg: 'Email already taken',
                        param: 'email'
                    }]);
                    break;
                case 11001:
                    res.status(400).send([{
                        msg: 'Username already taken',
                        param: 'username'
                    }]);
                    break;
                default:
                    var modelErrors = [];

                    if (err.errors) {

                        for (var x in err.errors) {
                            modelErrors.push({
                                param: x,
                                msg: err.errors[x].message,
                                value: err.errors[x].value
                            });
                        }

                        res.status(400).send(modelErrors);
                    }
            }

            return res.status(400);
        }
        // log in the user
        req.logIn(user, function(err) {
            if (err) return next(err);
            if (req.body.thirdparty) {
                var token = generateToken(user);
                res.send({
                    user: user,
                    token: token
                });
            } else {
                return res.redirect('/');
            }
        });
        res.status(200);
    });
}

// login the user externally
exports.doLogin = function(req, res) {
    if (req.body.thirdparty) {
        var token = generateToken(req.user);
        res.send({
            user: req.user,
            token: token
        });
    } else {
        res.send({
            user: req.user,
        });
    }
}

// ******************************** third party application methods *******************//

// function to generate token for _id of given user document
var generateToken = function(user) {
    var expires = moment().add(7, 'days').valueOf();
    var sec = Date.now().valueOf()
    var token = jwt.encode({
        iss: user._id,
        exp: expires
    }, jwtTokenSecret);

    return token;
};

// clear the token
var clearToken = function(req, done) {
    User.update({
        _id: req.body.id
    }, {
        token: {
            jwt: '',
            createdAt: ''
        }
    })
        .exec(function(err, user) {
            if (err) console.log(err);
            else {
                done(null, user);
            };

        });
};

// validate the user using jwt token
exports.requiresToken = function(req, res, next) {
    var decoded = jwt.decode(req.query.token, jwtTokenSecret);

    // time limit validation
    if (decoded.exp <= Date.now()) {
        res.end('Access token has expired', 400);
    }

    // user _id validation
    if (decoded.iss) {
        User
            .findOne({
                _id: decoded.iss
            })
            .exec(function(err, user) {
                if (err) return res.send(401, 'User is not authorized');
                if (!user) return res.send(401, 'User is not authorized');
                req.user = user;
                next();
            });

    } else return res.send(401, 'User is not authorized');

};

// function for log in function
exports.facebookLogin = function(req, res) {
    User.findOne({
        email: req.body.email
    }).exec(function(err, user) {
        if (user) {
            var token = generateToken(user);
            res.send({
                user: user,
                token: token
            });

        } else {
            var user = new User(req.body);
            user.provider = 'facebook';

            // Hard coded for now. Will address this with the user permissions system in v0.3.5
            user.roles = ['authenticated'];
            user.save(function(err) {
                if (err) {
                    switch (err.code) {
                        case 11000:
                            res.status(400).send([{
                                msg: 'Email already taken',
                                param: 'email'
                            }]);
                            break;
                        case 11001:
                            res.status(400).send([{
                                msg: 'Username already taken',
                                param: 'username'
                            }]);
                            break;
                        default:
                            var modelErrors = [];

                            if (err.errors) {

                                for (var x in err.errors) {
                                    modelErrors.push({
                                        param: x,
                                        msg: err.errors[x].message,
                                        value: err.errors[x].value
                                    });
                                }

                                res.status(400).send(modelErrors);
                            }
                    }

                    return res.status(400);
                }

                var token = generateToken(user);
                res.send({
                    user: user,
                    token: token
                });

            });
            res.status(200);

        }
    });

}

// logout for third party app
exports.signoutapp = function(req, res) {
    clearToken(req, function(err, user) {
        if (err) res.status(400).send(err);
        else {
            res.send({
                message: 'success'
            });
        }
    });
};
<commit_msg>return message changed<commit_after>var User = require('../models/user');
var jwt = require('jwt-simple');
var moment = require('moment');
var app = require("../../app");
var jwtTokenSecret = "YOUR_SECRET_STRING";

// ********************** local application methods ************************//

// cheking whether user logged in or not
exports.loggedin = function(req, res, next) {
    res.send(req.isAuthenticated() ? req.user : '0');
}

// logout function
exports.logout = function(req, res, next) {
    req.logout();
    res.status(200).send("");
}

// return the logged in user
exports.me = function(req, res) {
    res.json(req.user || null);
};

// user creation function
exports.create = function(req, res, next) {
    var user = new User(req.body);
    user.provider = 'local';

    // because we set our user.provider to local our models/user.js validation will always be true
    req.assert('name', 'You must enter a name').notEmpty();
    req.assert('email', 'You must enter a valid email address').isEmail();
    req.assert('password', 'Password must be between 8-20 characters long').len(8, 20);
    req.assert('username', 'Username cannot be more than 20 characters').len(1, 20);
    req.assert('confirmPassword', 'Passwords do not match').equals(req.body.password);

    var errors = req.validationErrors();
    if (errors) {
        return res.status(400).send(errors);
    }
    console.log(2);

    // Hard coded for now. Will address this with the user permissions system in v0.3.5
    user.roles = ['authenticated'];
    user.save(function(err) {
        if (err) {
            switch (err.code) {
                case 11000:
                    res.status(400).send([{
                        msg: 'Email already taken',
                        param: 'email'
                    }]);
                    break;
                case 11001:
                    res.status(400).send([{
                        msg: 'Username already taken',
                        param: 'username'
                    }]);
                    break;
                default:
                    var modelErrors = [];

                    if (err.errors) {

                        for (var x in err.errors) {
                            modelErrors.push({
                                param: x,
                                msg: err.errors[x].message,
                                value: err.errors[x].value
                            });
                        }

                        res.status(400).send(modelErrors);
                    }
            }

            return res.status(400);
        }
        // log in the user
        req.logIn(user, function(err) {
            if (err) return next(err);
            if (req.body.thirdparty) {
                var token = generateToken(user);
                res.send({
                    user: user,
                    token: token
                });
            } else {
                return res.redirect('/');
            }
        });
        res.status(200);
    });
}

// login the user externally
exports.doLogin = function(req, res) {
    if (req.body.thirdparty) {
        var token = generateToken(req.user);
        res.send({
            user: req.user,
            token: token
        });
    } else {
        res.send({
            user: req.user,
        });
    }
}

// ******************************** third party application methods *******************//

// function to generate token for _id of given user document
var generateToken = function(user) {
    var expires = moment().add(7, 'days').valueOf();
    var sec = Date.now().valueOf()
    var token = jwt.encode({
        iss: user._id,
        exp: expires
    }, jwtTokenSecret);

    return token;
};

// clear the token
var clearToken = function(req, done) {
    User.update({
        _id: req.body.id
    }, {
        token: {
            jwt: '',
            createdAt: ''
        }
    })
        .exec(function(err, user) {
            if (err) console.log(err);
            else {
                done(null, user);
            };

        });
};

// validate the user using jwt token
exports.requiresToken = function(req, res, next) {
    var decoded = jwt.decode(req.query.token, jwtTokenSecret);

    // time limit validation
    if (decoded.exp <= Date.now()) {
        res.end('Access token has expired', 400);
    }

    // user _id validation
    if (decoded.iss) {
        User
            .findOne({
                _id: decoded.iss
            })
            .exec(function(err, user) {
                if (err) return res.send(401, 'User is not authorized');
                if (!user) return res.status(401).send('User is not authorized');
                req.user = user;
                next();
            });

    } else return res.send(401, 'User is not authorized');

};

// function for log in function
exports.facebookLogin = function(req, res) {
    User.findOne({
        email: req.body.email
    }).exec(function(err, user) {
        if (user) {
            var token = generateToken(user);
            res.send({
                user: user,
                token: token
            });

        } else {
            var user = new User(req.body);
            user.provider = 'facebook';

            // Hard coded for now. Will address this with the user permissions system in v0.3.5
            user.roles = ['authenticated'];
            user.save(function(err) {
                if (err) {
                    switch (err.code) {
                        case 11000:
                            res.status(400).send([{
                                msg: 'Email already taken',
                                param: 'email'
                            }]);
                            break;
                        case 11001:
                            res.status(400).send([{
                                msg: 'Username already taken',
                                param: 'username'
                            }]);
                            break;
                        default:
                            var modelErrors = [];

                            if (err.errors) {

                                for (var x in err.errors) {
                                    modelErrors.push({
                                        param: x,
                                        msg: err.errors[x].message,
                                        value: err.errors[x].value
                                    });
                                }

                                res.status(400).send(modelErrors);
                            }
                    }

                    return res.status(400);
                }

                var token = generateToken(user);
                res.send({
                    user: user,
                    token: token
                });

            });
            res.status(200);

        }
    });

}

// logout for third party app
exports.signoutapp = function(req, res) {
    clearToken(req, function(err, user) {
        if (err) res.status(400).send(err);
        else {
            res.send({
                message: 'success'
            });
        }
    });
};
<|endoftext|>


<commit_before>var Sequelize = require('sequelize');
<<<<<<< HEAD

// AZUREWEBSITE IMPLEMENTATION
=======
>>>>>>> 6773e0a3fc553ddc8b4599d0bae7671d657f244d
var sequelize = new Sequelize("lionbase", "bc8fa3955e6d18", "83511e40", {
  host: 'us-cdbr-azure-west-a.cloudapp.net',
  define: {
    underscored: false,
    freezeTableName: false,
    syncOnAssociation: true,
    charset: 'utf8',
    collate: 'utf8_general_ci',
    classMethods: {method1: function() {}},
    instanceMethods: {method2: function() {}},
    timestamps: true
  }
});
                              //databasename user password
// var sequelize = new Sequelize("lionbase", "root", "zelda", {
//   host: 'localhost',
//   define: {
//     underscored: false,
//     freezeTableName: false,
//     syncOnAssociation: true,
//     charset: 'utf8',
//     collate: 'utf8_general_ci',
//     classMethods: {method1: function() {}},
//     instanceMethods: {method2: function() {}},
//     timestamps: true
//   }
// });

// LOCAL HOST IMPLEMENTATION
// var sequelize = new Sequelize("lionbase", "root", "zelda", {
//   host: 'localhost',
//   define: {
//     underscored: false,
//     freezeTableName: false,
//     syncOnAssociation: true,
//     charset: 'utf8',
//     collate: 'utf8_general_ci',
//     classMethods: {method1: function() {}},
//     instanceMethods: {method2: function() {}},
//     timestamps: true
//   }
// });

module.exports.Story = sequelize.define('Story', {
  by: Sequelize.STRING,
  id: {type: Sequelize.INTEGER, primarykey: true, unique: true},
  kids: Sequelize.TEXT,
  score: Sequelize.INTEGER,
  time: Sequelize.INTEGER,
  title: Sequelize.STRING,
  type: Sequelize.STRING,
  url: Sequelize.TEXT
});

module.exports.Comment = sequelize.define('Comment', {
  by: Sequelize.STRING,
  id: {type: Sequelize.INTEGER, primarykey: true, unique: true},
  kids: Sequelize.TEXT,
  parent: Sequelize.INTEGER,
  text: Sequelize.TEXT,
  time: Sequelize.INTEGER,
  type: Sequelize.STRING
});

// Could not find a job schema..

// module.exports.Job = sequelize.define('Job', {
//   by: Sequelize.STRING,
//   id: {type: Sequelize.INTEGER, primarykey: true},
//   kids: Sequelize.TEXT,
//   score: Sequelize.INTEGER,
//   time: Sequelize.INTEGER,
//   title: Sequelize.STRING,
//   url: Sequelize.STRING,
//   text: Sequelize.STRING,
//   type: Sequelize.STRING
// });

module.exports.Poll = sequelize.define('Poll', {
  by: Sequelize.STRING,
  id: {type: Sequelize.INTEGER, primarykey: true, unique: true},
  kids: Sequelize.TEXT,
  parts: Sequelize.TEXT,
  score: Sequelize.INTEGER,
  text: Sequelize.TEXT,
  time: Sequelize.INTEGER,
  title: Sequelize.STRING,
  type: Sequelize.STRING
});

module.exports.PollOption = sequelize.define('PollOption', {
  by: Sequelize.STRING,
  id: {type: Sequelize.INTEGER, primarykey: true, unique: true},
  kids: Sequelize.TEXT,
  parent: Sequelize.INTEGER,
  score: Sequelize.INTEGER,
  text: Sequelize.TEXT,
  time: Sequelize.INTEGER,
  type: Sequelize.STRING
});

module.exports.User = sequelize.define('User', {
  about: Sequelize.STRING,
  created: Sequelize.INTEGER,
  delay: Sequelize.INTEGER,
  id: {type: Sequelize.STRING, primarykey: true},
  karma: Sequelize.INTEGER,
  submitted: Sequelize.TEXT,
});

module.exports.create = function(itemName, items) {
  if (items.length > 1) {
    console.log("creating");
    console.log("length: " + items.length);

    for (var start = 0; start < items.length; start+=1000) {
      var end = start + 1000;

      if (end > items.length) {
        end = items.length;
      }

      var subItems = items.slice(start, end);

      itemName.bulkCreate(subItems)
        .success(function() {
          itemName.findAll()
            .success(function(addedItems) {
              console.log( "items created: " + addedItems.length );
            });
        });

    }

  }
};

////////////////////////////////////////////////
//Based on the Firebase structure, most data
//already exists in each table without the
//need to add additional relationships.
//However, here are some tradition relationships
//that we have identified for possible future
//use.
////////////////////////////////////////////////

// Story.hasOne(User, {foreignKey: 'id'});
// Story.hasMany(Comment, {as: 'Comments'});

// Poll.hasMany(PollOption, {as: 'PollOptions'});
// Poll.hasMany(Comment, {as: 'Comments'});

// User.hasMany(Comment, {as: 'Comments'});
// User.hasMany(Job, {as: 'Jobs'});
// User.hasMany(Poll, {as: 'Polls'});
// User.hasMany(PollOption, {as: 'PollOptions'});
// User.hasMany(Story, {as: 'Stories'});

<<<<<<< HEAD
sequelize.sync();

// RESETS THE ENTIRE DATABASE
=======
// module.exports.Story.sync();
// module.exports.Comment.sync();
// module.exports.Job.sync();
// module.exports.Poll.sync();
// module.exports.PollOption.sync();
// module.exports.User.sync();

sequelize.sync();

>>>>>>> 6773e0a3fc553ddc8b4599d0bae7671d657f244d
// sequelize
//   .sync({ force: true })
//   .complete(function(err) {
//     if (!!err) {
//       console.log('An error occured:', err);
//     } else {
//       console.log('Success!');
//     }
//   });<commit_msg>(refactor) removed merge conflicts<commit_after>var Sequelize = require('sequelize');

// AZUREWEBSITE IMPLEMENTATION
var sequelize = new Sequelize("lionbase", "bc8fa3955e6d18", "83511e40", {
  host: 'us-cdbr-azure-west-a.cloudapp.net',
  define: {
    underscored: false,
    freezeTableName: false,
    syncOnAssociation: true,
    charset: 'utf8',
    collate: 'utf8_general_ci',
    classMethods: {method1: function() {}},
    instanceMethods: {method2: function() {}},
    timestamps: true
  }
});
                              //databasename user password
// var sequelize = new Sequelize("lionbase", "root", "zelda", {
//   host: 'localhost',
//   define: {
//     underscored: false,
//     freezeTableName: false,
//     syncOnAssociation: true,
//     charset: 'utf8',
//     collate: 'utf8_general_ci',
//     classMethods: {method1: function() {}},
//     instanceMethods: {method2: function() {}},
//     timestamps: true
//   }
// });

// LOCAL HOST IMPLEMENTATION
// var sequelize = new Sequelize("lionbase", "root", "zelda", {
//   host: 'localhost',
//   define: {
//     underscored: false,
//     freezeTableName: false,
//     syncOnAssociation: true,
//     charset: 'utf8',
//     collate: 'utf8_general_ci',
//     classMethods: {method1: function() {}},
//     instanceMethods: {method2: function() {}},
//     timestamps: true
//   }
// });

module.exports.Story = sequelize.define('Story', {
  by: Sequelize.STRING,
  id: {type: Sequelize.INTEGER, primarykey: true, unique: true},
  kids: Sequelize.TEXT,
  score: Sequelize.INTEGER,
  time: Sequelize.INTEGER,
  title: Sequelize.STRING,
  type: Sequelize.STRING,
  url: Sequelize.TEXT
});

module.exports.Comment = sequelize.define('Comment', {
  by: Sequelize.STRING,
  id: {type: Sequelize.INTEGER, primarykey: true, unique: true},
  kids: Sequelize.TEXT,
  parent: Sequelize.INTEGER,
  text: Sequelize.TEXT,
  time: Sequelize.INTEGER,
  type: Sequelize.STRING
});

// Could not find a job schema..

// module.exports.Job = sequelize.define('Job', {
//   by: Sequelize.STRING,
//   id: {type: Sequelize.INTEGER, primarykey: true},
//   kids: Sequelize.TEXT,
//   score: Sequelize.INTEGER,
//   time: Sequelize.INTEGER,
//   title: Sequelize.STRING,
//   url: Sequelize.STRING,
//   text: Sequelize.STRING,
//   type: Sequelize.STRING
// });

module.exports.Poll = sequelize.define('Poll', {
  by: Sequelize.STRING,
  id: {type: Sequelize.INTEGER, primarykey: true, unique: true},
  kids: Sequelize.TEXT,
  parts: Sequelize.TEXT,
  score: Sequelize.INTEGER,
  text: Sequelize.TEXT,
  time: Sequelize.INTEGER,
  title: Sequelize.STRING,
  type: Sequelize.STRING
});

module.exports.PollOption = sequelize.define('PollOption', {
  by: Sequelize.STRING,
  id: {type: Sequelize.INTEGER, primarykey: true, unique: true},
  kids: Sequelize.TEXT,
  parent: Sequelize.INTEGER,
  score: Sequelize.INTEGER,
  text: Sequelize.TEXT,
  time: Sequelize.INTEGER,
  type: Sequelize.STRING
});

module.exports.User = sequelize.define('User', {
  about: Sequelize.STRING,
  created: Sequelize.INTEGER,
  delay: Sequelize.INTEGER,
  id: {type: Sequelize.STRING, primarykey: true},
  karma: Sequelize.INTEGER,
  submitted: Sequelize.TEXT,
});

module.exports.create = function(itemName, items) {
  if (items.length > 1) {
    console.log("creating");
    console.log("length: " + items.length);

    for (var start = 0; start < items.length; start+=1000) {
      var end = start + 1000;

      if (end > items.length) {
        end = items.length;
      }

      var subItems = items.slice(start, end);

      itemName.bulkCreate(subItems)
        .success(function() {
          itemName.findAll()
            .success(function(addedItems) {
              console.log( "items created: " + addedItems.length );
            });
        });

    }

  }
};

////////////////////////////////////////////////
//Based on the Firebase structure, most data
//already exists in each table without the
//need to add additional relationships.
//However, here are some tradition relationships
//that we have identified for possible future
//use.
////////////////////////////////////////////////

// Story.hasOne(User, {foreignKey: 'id'});
// Story.hasMany(Comment, {as: 'Comments'});

// Poll.hasMany(PollOption, {as: 'PollOptions'});
// Poll.hasMany(Comment, {as: 'Comments'});

// User.hasMany(Comment, {as: 'Comments'});
// User.hasMany(Job, {as: 'Jobs'});
// User.hasMany(Poll, {as: 'Polls'});
// User.hasMany(PollOption, {as: 'PollOptions'});
// User.hasMany(Story, {as: 'Stories'});

sequelize.sync();

// RESETS THE ENTIRE DATABASE
// sequelize
//   .sync({ force: true })
//   .complete(function(err) {
//     if (!!err) {
//       console.log('An error occured:', err);
//     } else {
//       console.log('Success!');
//     }
//   });<|endoftext|>