<commit_before>var path = require('path');
var ndarray = require('ndarray');
var savePixels = require('save-pixels');
var exporters = {};

// Function to add new exporters
function addExporter(name, exporter) {
  exporters[name] = exporter;
}

// Helper to create exporters (could be a class for better abstraction)
function getPngExporter(ext) {
  /**
   * Generic exporter
   * @param {Object} options Options to export with
   * @param {Number} [options.quality] Quality of the exported item
   * @param {Function} cb Error-first callback to return binary image string to
   */
  return function pngExporterFn (options, cb) {
    var that = this;

    // Add the image to the data itself (easier via offsets)
    var data = this.data;
    var images = this.images;
    images.forEach(function getUrlPath (imageObj) {
      // Iterate over the image's data across its rows
      // setting the original data at that offset
      // [1, 2, 0, 0,
      //  3, 4, 0, 0,
      //  0, 0, 5, 0,
      //  0, 0, 0, 6]
      // Set [1, 2] at 0 + 0 * canvasRow.length (x offset + ((y + imageRow index) * canvasRow length))
      // Set [3, 4] at 0 + 1 * canvasRow.length (x offset + ((y + imageRow index) * canvasRow length))
      var img = imageObj.img;
      var imageXOffset = imageObj.x * 4;
      var canvasRowWidth = that.width * 4;
      var imageRowWidth = img.width * 4;
      var imgData = img.data;
      var imageYOffset = imageObj.y;
      var imageRowIndex = 0;
      var imageRowCount = img.height;
      for (; imageRowIndex < imageRowCount; imageRowIndex += 1) {
        // TODO: Use ndarray operations
        var subarray = imgData.subarray(imageRowIndex * imageRowWidth, (imageRowIndex + 1) * imageRowWidth);
        var offset = imageXOffset + ((imageYOffset + imageRowIndex) * canvasRowWidth);
        console.log(imageXOffset, imageYOffset, imageRowIndex, canvasRowWidth);
        data.set(subarray, offset);
      }
    });

    var fs = require('fs');
    savePixels(this.ndarray, 'png').pipe(fs.createWriteStream('tmp.png'));

    // // Collect our parameters
    // var params = that.params;
    // params.images = images;
    // params.options = options;

      // // Convert the pixels into an ndarray
      // // Taken from https://github.com/mikolalysenko/get-pixels/blob/2ac98645119244d6e52afcef5fe52cc9300fb27b/dom-pixels.js#L14
      // var pngNdarray = ndarray(decodedPixels, [params.height, params.width, 4],
      //                    [4 * params.width, 4, 1], 0),
      //     png = savePixels(pngNdarray, 'PNG');

      // // Pump the stream from png to a binary string (expected by spritesmith)
      // // TODO: We should be calling back with the stream =(
      // var retVal = '';
      // png.on('data', function (buffer) {
      //   retVal += buffer.toString('binary');
      // });
      // png.on('end', function () {
      //   cb(null, retVal);
      // });
  };
}

// Generate the png exporter
var pngExporter = getPngExporter('png');
addExporter('png', pngExporter);
addExporter('image/png', pngExporter);

// Export our exporters
module.exports = {
  exporters: exporters,
  addExporter: addExporter
};<commit_msg>Taking notes for performance/reusability<commit_after>var path = require('path');
var ndarray = require('ndarray');
var savePixels = require('save-pixels');
var exporters = {};

// Function to add new exporters
function addExporter(name, exporter) {
  exporters[name] = exporter;
}

// Helper to create exporters (could be a class for better abstraction)
function getPngExporter(ext) {
  /**
   * Generic exporter
   * @param {Object} options Options to export with
   * @param {Number} [options.quality] Quality of the exported item
   * @param {Function} cb Error-first callback to return binary image string to
   */
  return function pngExporterFn (options, cb) {
    var that = this;

    // Add the image to the data itself (easier via offsets)
    var data = this.data;
    var images = this.images;
    images.forEach(function getUrlPath (imageObj) {
      // Iterate over the image's data across its rows
      // setting the original data at that offset
      // [1, 2, 0, 0,
      //  3, 4, 0, 0,
      //  0, 0, 5, 0,
      //  0, 0, 0, 6]
      // Set [1, 2] at 0 + 0 * canvasRow.length (x offset + ((y + imageRow index) * canvasRow length))
      // Set [3, 4] at 0 + 1 * canvasRow.length (x offset + ((y + imageRow index) * canvasRow length))
      var img = imageObj.img;
      var imageXOffset = imageObj.x * 4;
      var canvasRowWidth = that.width * 4;
      var imageRowWidth = img.width * 4;
      var imgData = img.data;
      var imageYOffset = imageObj.y;
      var imageRowIndex = 0;
      var imageRowCount = img.height;
      for (; imageRowIndex < imageRowCount; imageRowIndex += 1) {
        // TODO: Use ndarray operations
        // TODO: or move to separate node module
        // TODO: It would be more space efficient to iterate over the indices and set each one
        var subarray = imgData.subarray(imageRowIndex * imageRowWidth, (imageRowIndex + 1) * imageRowWidth);
        var offset = imageXOffset + ((imageYOffset + imageRowIndex) * canvasRowWidth);
        data.set(subarray, offset);
      }
    });

    var fs = require('fs');
    savePixels(this.ndarray, 'png').pipe(fs.createWriteStream('tmp.png'));

    // // Collect our parameters
    // var params = that.params;
    // params.images = images;
    // params.options = options;

      // // Convert the pixels into an ndarray
      // // Taken from https://github.com/mikolalysenko/get-pixels/blob/2ac98645119244d6e52afcef5fe52cc9300fb27b/dom-pixels.js#L14
      // var pngNdarray = ndarray(decodedPixels, [params.height, params.width, 4],
      //                    [4 * params.width, 4, 1], 0),
      //     png = savePixels(pngNdarray, 'PNG');

      // // Pump the stream from png to a binary string (expected by spritesmith)
      // // TODO: We should be calling back with the stream =(
      // var retVal = '';
      // png.on('data', function (buffer) {
      //   retVal += buffer.toString('binary');
      // });
      // png.on('end', function () {
      //   cb(null, retVal);
      // });
  };
}

// Generate the png exporter
var pngExporter = getPngExporter('png');
addExporter('png', pngExporter);
addExporter('image/png', pngExporter);

// Export our exporters
module.exports = {
  exporters: exporters,
  addExporter: addExporter
};<|endoftext|>


<commit_before>const { SelfbotCommand } = require.main.exports
const { util,
  Gateway, Language } = require('klasa') // eslint-disable-line no-unused-vars
const { Collection,
  Message, Guild } = require('discord.js') // eslint-disable-line no-unused-vars

module.exports = class Tag extends SelfbotCommand {
  constructor (...args) {
    super(...args, {
      aliases: ['tags'],
      description: 'Show or modify tags.',
      usage: '[add|edit|del|get|list] [tagname:str{2,100}] [contents:str{2,2000}] [...]',
      usageDelim: ' ',
      extendedHelp: `-add tagname This is your new tag contents
-edit tagname This is new new edited contents
-del tagname
-get tagname
-list

\`action\` may be omitted for "edit", "get", and "list".`,
      subHelps: {
        add: {
          description: 'Add a new tag',
          usage: '<tagname:str{2,100}> <contents:str{2,2000}> [...]',
          extendedHelp: `Example:
(prefix)tag add tagname This is your new tag contents`,
        },
        edit: {
          description: 'Edit a tag',
          usage: '<tagname:str{2,100}> <contents:str{2,2000}> [...]',
          extendedHelp: `Examples:
(prefix)tag edit tagname This is new new edited contents
(prefix)tag tagname This is new new edited contents`,
        },
        del: {
          description: 'Delete a tag',
          usage: '<tagname:str{2,100}>',
          extendedHelp: `Example:
(prefix)tag del tagname`,
        },
        get: {
          description: 'Display a tag',
          usage: '<tagname:str{2,100}>',
          extendedHelp: `Examples:
(prefix)tag get tagname
(prefix)tag tagname`,
        },
        list: {
          description: 'List all tags',
          usage: '',
          extendedHelp: `Examples:
(prefix)tag list
(prefix)tags`,
        },
      },
    })

    /**
     * @type {Object}
     */
    this.schema = {
      contents: {
        type: 'String',
        default: null,
        array: false,
        min: 2,
        max: 2000,
      },
    }
  }

  /**
   * @param {SettingResolver} resolver The setting resolver thingy
   * @param {string} tag The tag name, I think?
   * @returns {Promise<string>}
   */
  async validate (resolver, tag) {
    return String(tag)
  }

  /**
   * @returns {Promise}
   */
  async init () {
    if (!this.client.settings.tags) await this.client.settings.add('tags', this.validate, this.schema)
    /**
     * @type {Gateway}
     */
    this.db = this.client.settings.tags
  }

  /**
   * @param {Message} msg The command message
   * @param {string[]} args The args passed to the command
   * @returns {Promise<Message>}
   */
  async run (msg, [action, tagname, ...contents]) {
    contents = contents[0] ? contents.join(' ') : null
    console.log({action, tagname, contents})
    if (!action) {
      if (tagname) {
        if (contents) action = 'edit'
        else action = 'get'
      } else {
        // If the first word is over 100 chars, then Klasa will parse it as `contents`.
        // Hence, having neither `action` nor `tagname`, but having `contents`.
        // "nani the fuck deska" - Evie, 2017
        if (contents) return msg.channel.send('nani the fuck deska', {code: true})
        else action = 'list'
      }
    }
    return msg.channel.send(await this[`${action}Run`](msg.language,
      tagname, contents, msg.guild))
  }

  /**
   * @param {string} tagname The tag name
   * @param {{returnTag: boolean}} options Options
   * @returns {boolean|{id: string, contents: string}}
   */
  exists (tagname, {returnTag} = {returnTag: false}) {
    const existingTag = this.db.getEntry(tagname)
    // @todo Simplify this, once I make sure this bug has been fixed
    // There seems to be a bug where defaults can sometimes include an 'id'
    const exists = 'id' in existingTag && existingTag.id === tagname
    if ('id' in existingTag && existingTag.id !== tagname) {
      // Debugging
      console.log(`For nonexistant tagname ${tagname}, the \`get\`ed existingTag has an 'id' attribute:`,
        existingTag)
    }
    if (returnTag && exists) return existingTag
    return exists
  }

  /**
   * @param {Language} lang The language object
   * @param {string} tagname The tag name
   * @returns {Promise<string>}
   */
  async getRun (lang, tagname) {
    const tag = this.exists(tagname, {returnTag: true})
    if (tag) return tag.contents
    return lang.get('COMMAND_TAG_DOESNT_EXIST', tagname)
  }

  /**
   * @param {Language} lang The language object
   * @param {string} tagname The tag name
   * @param {string} contents The contents of the new tag
   * @returns {Promise<string>}
   */
  async addRun (lang, tagname, contents) {
    if (this.exists(tagname)) return lang.get('COMMAND_TAG_ALREADY_EXISTS', tagname)
    if (!contents) return lang.get('COMMAND_TAG_CONTENT_REQUIRED')

    await this.db.createEntry(tagname, { contents })
    return lang.get('COMMAND_TAG_ADDED', tagname)
  }

  /**
   * @param {Language} lang The language object
   * @param {string} tagname The tag name
   * @param {string} contents The new contents of the tag
   * @param {Guild} guild The guild the message was sent in, if any
   * @returns {Promise<string>}
   */
  async editRun (lang, tagname, contents, guild) {
    if (!this.exists(tagname)) return lang.get('COMMAND_TAG_DOESNT_EXIST', tagname)
    if (!contents) return lang.get('COMMAND_TAG_CONTENT_REQUIRED')

    await this.db.updateOne(tagname, 'contents', contents, guild)
    return lang.get('COMMAND_TAG_EDITED', tagname)
  }

  /**
   * @param {Language} lang The language object
   * @param {string} tagname The tag name
   * @returns {Promise<string>}
   */
  async delRun (lang, tagname) {
    if (!this.exists(tagname)) return lang.get('COMMAND_TAG_DOESNT_EXIST', tagname)

    await this.db.deleteEntry(tagname)
    return lang.get('COMMAND_TAG_DELETED', tagname)
  }

  /**
   * @param {Language} lang The language object
   * @returns {Promise<string>}
   */
  async listRun (lang) {
    const nestedTags = Tag.parseAndSortDottedTags(this.db.cache.getKeys('tags'))
    // ;
    //   .map(tagname => tagname.split('.'))
    //   .sort((a, b) => {
    //     const len = Math.max(aArray.length, bArray.length)
    //     for (let i = 0; i < len; i++) {

    //     }
    //     return aArray.length === bArray.length
    //       ? a.localeCompare(b)
    //       : a.split('.').length - b.split('.').length
    //   })
    //   .join('\n')
    const tagStr = require('util').inspect(nestedTags)
    if (tagStr) return lang.get('COMMAND_TAG_LIST', util.codeBlock('', tagStr))
    return lang.get('COMMAND_TAG_NO_TAGS')
  }

  /**
   * Given a dotted array, parse it, generating a new collection with all the dotted tags parsed
   * @param {Array<string>} rawArray The array of tag names
   * @returns {Collection<string, (string|Collection<string, *>)>}
   */
  static parseAndSortDottedTags (rawArray) {
    const coll = new Collection([
      ['_root', []],
    ])
    for (const dottedTag of rawArray) {
      if (dottedTag.indexOf('.') === -1) coll.get('_root').push(dottedTag)
      const path = dottedTag.split('.')
      let tempPath = coll
      for (let i = 0; i < path.length - 1; i++) {
        tempPath.sort()
        if (typeof tempPath.get(path[i]) === 'undefined') tempPath.set(path[i], new Collection())
        tempPath = tempPath.get(path[i])
      }
      tempPath.set(path[path.length - 2], path[path.length - 1])
      tempPath.sort()
    }
    coll.get('_root').sort()
    return coll
  }
}
<commit_msg>Tag cmd update<commit_after>const { SelfbotCommand } = require.main.exports
const { util,
  Gateway, Language } = require('klasa') // eslint-disable-line no-unused-vars
const { Collection,
  Message, Guild } = require('discord.js') // eslint-disable-line no-unused-vars

module.exports = class Tag extends SelfbotCommand {
  constructor (...args) {
    super(...args, {
      aliases: ['tags'],
      description: 'Show or modify tags.',
      usage: '[add|edit|del|get|list] [tagname:str{2,100}] [contents:str{2,2000}] [...]',
      usageDelim: ' ',
      extendedHelp: `-add tagname This is your new tag contents
-edit tagname This is new new edited contents
-del tagname
-get tagname
-list

\`action\` may be omitted for "edit", "get", and "list".`,
      subHelps: {
        add: {
          description: 'Add a new tag',
          usage: '<tagname:str{2,100}> <contents:str{2,2000}> [...]',
          extendedHelp: `Example:
(prefix)tag add tagname This is your new tag contents`,
        },
        edit: {
          description: 'Edit a tag',
          usage: '<tagname:str{2,100}> <contents:str{2,2000}> [...]',
          extendedHelp: `Examples:
(prefix)tag edit tagname This is new new edited contents
(prefix)tag tagname This is new new edited contents`,
        },
        del: {
          description: 'Delete a tag',
          usage: '<tagname:str{2,100}>',
          extendedHelp: `Example:
(prefix)tag del tagname`,
        },
        get: {
          description: 'Display a tag',
          usage: '<tagname:str{2,100}>',
          extendedHelp: `Examples:
(prefix)tag get tagname
(prefix)tag tagname`,
        },
        list: {
          description: 'List all tags',
          usage: '',
          extendedHelp: `Examples:
(prefix)tag list
(prefix)tags`,
        },
      },
    })

    /**
     * @type {Object}
     */
    this.schema = {
      contents: {
        type: 'String',
        default: null,
        array: false,
        min: 2,
        max: 2000,
      },
    }
  }

  /**
   * @param {SettingResolver} resolver The setting resolver thingy
   * @param {string} tag The tag name, I think?
   * @returns {Promise<string>}
   */
  async validate (resolver, tag) {
    return String(tag)
  }

  /**
   * @returns {Promise}
   */
  async init () {
    if (!this.client.settings.tags) await this.client.settings.add('tags', this.validate, this.schema)
    /**
     * @type {Gateway}
     */
    this.db = this.client.settings.tags
  }

  /**
   * @param {Message} msg The command message
   * @param {string[]} args The args passed to the command
   * @returns {Promise<Message>}
   */
  async run (msg, [action, tagname, ...contents]) {
    contents = contents[0] ? contents.join(' ') : null
    console.log({action, tagname, contents})
    if (!action) {
      if (tagname) {
        action = contents ? 'edit' : 'get'
      } else if (contents) {
        // If the first word is over 100 chars, then Klasa will parse it as `contents`.
        // Hence, having neither `action` nor `tagname`, but having `contents`.
        // "nani the fuck deska" - Evie, 2017
        return msg.channel.send('nani the fuck deska', {code: true})
      } else {
        action = 'list'
      }
    }
    return msg.channel.send(await this[`${action}Run`](msg.language,
      tagname, contents, msg.guild))
  }

  /**
   * @param {string} tagname The tag name
   * @param {{returnTag: boolean}} options Options
   * @returns {boolean|{id: string, contents: string}}
   */
  exists (tagname, {returnTag} = {returnTag: false}) {
    const existingTag = this.db.getEntry(tagname)
    // @todo Simplify this, once I make sure this bug has been fixed
    // There seems to be a bug where defaults can sometimes include an 'id'
    const exists = 'id' in existingTag && existingTag.id === tagname
    if ('id' in existingTag && existingTag.id !== tagname) {
      // Debugging
      console.log(`For nonexistant tagname ${tagname}, the \`get\`ed existingTag has an 'id' attribute:`,
        existingTag)
    }
    if (returnTag && exists) return existingTag
    return exists
  }

  /**
   * @param {Language} lang The language object
   * @param {string} tagname The tag name
   * @returns {Promise<string>}
   */
  async getRun (lang, tagname) {
    const tag = this.exists(tagname, {returnTag: true})
    if (tag) return tag.contents
    return lang.get('COMMAND_TAG_DOESNT_EXIST', tagname)
  }

  /**
   * @param {Language} lang The language object
   * @param {string} tagname The tag name
   * @param {string} contents The contents of the new tag
   * @param {Guild} guild The guild the message was sent in, if any
   * @returns {Promise<string>}
   */
  async addRun (lang, tagname, contents, guild) {
    if (this.exists(tagname)) return lang.get('COMMAND_TAG_ALREADY_EXISTS', tagname)
    if (!contents) return lang.get('COMMAND_TAG_CONTENT_REQUIRED')

    await this.db.createEntry(tagname)
    await this.db.updateOne(tagname, 'contents', contents, guild)
    return lang.get('COMMAND_TAG_ADDED', tagname)
  }

  /**
   * @param {Language} lang The language object
   * @param {string} tagname The tag name
   * @param {string} contents The new contents of the tag
   * @param {Guild} guild The guild the message was sent in, if any
   * @returns {Promise<string>}
   */
  async editRun (lang, tagname, contents, guild) {
    if (!this.exists(tagname)) return lang.get('COMMAND_TAG_DOESNT_EXIST', tagname)
    if (!contents) return lang.get('COMMAND_TAG_CONTENT_REQUIRED')

    await this.db.updateOne(tagname, 'contents', contents, guild)
    return lang.get('COMMAND_TAG_EDITED', tagname)
  }

  /**
   * @param {Language} lang The language object
   * @param {string} tagname The tag name
   * @returns {Promise<string>}
   */
  async delRun (lang, tagname) {
    if (!this.exists(tagname)) return lang.get('COMMAND_TAG_DOESNT_EXIST', tagname)

    await this.db.deleteEntry(tagname)
    return lang.get('COMMAND_TAG_DELETED', tagname)
  }

  /**
   * @param {Language} lang The language object
   * @returns {Promise<string>}
   */
  async listRun (lang) {
    const nestedTags = Tag.parseAndSortDottedTags(this.db.cache.getKeys('tags'))
    // ;
    //   .map(tagname => tagname.split('.'))
    //   .sort((a, b) => {
    //     const len = Math.max(aArray.length, bArray.length)
    //     for (let i = 0; i < len; i++) {

    //     }
    //     return aArray.length === bArray.length
    //       ? a.localeCompare(b)
    //       : a.split('.').length - b.split('.').length
    //   })
    //   .join('\n')
    const tagStr = require('util').inspect(nestedTags)
    if (tagStr) return lang.get('COMMAND_TAG_LIST', util.codeBlock('', tagStr))
    return lang.get('COMMAND_TAG_NO_TAGS')
  }

  /**
   * Given a dotted array, parse it, generating a new collection with all the dotted tags parsed
   * @param {Array<string>} rawArray The array of tag names
   * @returns {Collection<string, (string|Collection<string, *>)>}
   */
  static parseAndSortDottedTags (rawArray) {
    const coll = new Collection([
      ['_root', []],
    ])
    for (const dottedTag of rawArray) {
      if (dottedTag.indexOf('.') === -1) coll.get('_root').push(dottedTag)
      const path = dottedTag.split('.')
      let tempPath = coll
      for (let i = 0; i < path.length - 1; i++) {
        tempPath.sort()
        if (typeof tempPath.get(path[i]) === 'undefined') tempPath.set(path[i], new Collection())
        tempPath = tempPath.get(path[i])
      }
      tempPath.set(path[path.length - 2], path[path.length - 1])
      tempPath.sort()
    }
    coll.get('_root').sort()
    return coll
  }
}
<|endoftext|>


<commit_before>import {axios, log, isRoot} from '../../utils'

export default {
  async init ({state, commit, dispatch}) {
    console.log('[INIT] Releases')

    try {
      const {data, status} = await axios.get('getLatestNyaa', { params: state.params })

      if (status === 200) {
        commit('set', {data})

        if (state.autoRefresh === true) dispatch('autoRefresh')
      } else if (status === 202) {
        log(`An error occurred while getting the latest releases. Retrying in 45 seconds.`)
        commit('setInfoSnackbar', 'Could not get the latest releases. Retrying in 45 seconds.', isRoot)
        setTimeout(() => {
          log(`Retrying to get latest releases.`)
          dispatch('init').catch(err => { void (err) })
        }, 45 * 1000)
      } else if (status === 204) {
        log('nyaa.si does not respond... Switching to nyaa.pantsu.cat.')

        commit('setChoice', 'pantsu')

        const {data, status} = await axios.get('getLatestNyaa', { params: state.params })

        if (status === 200) {
          commit('set', {data})

          if (state.autoRefresh === true) dispatch('autoRefresh')
        } else if (status === 202) {
          log(`An error occurred while getting the latest releases. Retrying in 45 seconds.`)
          commit('setInfoSnackbar', 'Could not get the latest releases. Retrying in 45 seconds.', isRoot)
          setTimeout(() => {
            log(`Retrying to get latest releases.`)
            dispatch('init').catch(err => { void (err) })
          }, 45 * 1000)
        } else if (status === 204) {
          log('nyaa.pantsu.cat does not respond... Switching to HorribleSubs.')

          commit('setChoice', 'si')

          const {data, status} = await axios.get(`getLatest.json?quality=${state.params.quality}`)

          if (status === 200) {
            commit('set', {data})

            if (state.autoRefresh === true) dispatch('autoRefresh')
          } else if (status === 202) {
            log(`An error occurred while getting the latest releases. Retrying in 45 seconds.`)
            commit('setInfoSnackbar', 'Could not get the latest releases. Retrying in 45 seconds.', isRoot)
            setTimeout(() => {
              log(`Retrying to get latest releases.`)
              dispatch('init').catch(err => { void (err) })
            }, 45 * 1000)
          } else if (status === 204) {
            log('HorribleSubs does not respond. Retrying with nyaa.si...')

            dispatch('init')
          }
        }
      }
    } catch (e) {
      log(`An error occurred while getting the latest releases. Retrying in 45 seconds.`)
      commit('setInfoSnackbar', 'Could not get the latest releases. Retrying in 45 seconds.', isRoot)
      setTimeout(() => {
        log(`Retrying to get latest releases.`)
        dispatch('init').catch(err => { void (err) })
      }, 45 * 1000)
    }
  },
  async refresh ({state, commit, dispatch}) {
    log(`Refreshing Releases...`)

    const retryLater = (backUp) => {
      log(`An error occurred while getting the latest releases. Retrying in 45 seconds.`)
      commit('setInfoSnackbar', 'Could not get the latest releases. Retrying in 45 seconds.', isRoot)

      backUp.length && commit('set', {old: backUp})

      setTimeout(() => {
        log(`Retrying to get latest releases.`)
        dispatch('refresh').catch(err => { void (err) })
      }, 45 * 1000)
    }

    const backUp = state.releases

    commit('empty')

    try {
      const {data, status} = await axios.get('getLatestNyaa', { params: state.params })

      if (status === 200) commit('set', {data})
      else if (status === 202) {
        retryLater(backUp)
      } else if (status === 204) {
        const {data, status} = await axios.get(`getLatest.json?quality=${state.params.quality}`)

        if (status === 200) commit('set', {data})
        else if (status === 202 || status === 204) {
          retryLater(backUp)
        }
      }
    } catch (e) {
      retryLater(backUp)
    }
  },
  async autoRefresh ({dispatch, commit, state}) {
    // Refresh releases every 30 minutes
    setTimeout(async () => {
      log(`Refreshing Releases...`)

      try {
        const {data} = await axios.get('getLatestNyaa', { params: state.params })

        if (data.length === 18) {
          commit('set', {data})
          dispatch('autoRefresh')
        } else {
          commit('setInfoSnackbar', 'Auto refresh releases failed... Attempting again in 30 minutes.', isRoot)

          dispatch('autoRefresh')
        }
      } catch (e) {
        commit('setInfoSnackbar', 'Auto refresh releases failed... Attempting again in 30 minutes.', isRoot)

        dispatch('autoRefresh')
      }
    }, 30 * 60 * 1000)
  }
}
<commit_msg>should retryLater only once<commit_after>import {axios, log, isRoot} from '../../utils'

export default {
  async init ({state, commit, dispatch}) {
    console.log('[INIT] Releases')

    try {
      const {data, status} = await axios.get('getLatestNyaa', { params: state.params })

      if (status === 200) {
        commit('set', {data})

        if (state.autoRefresh === true) dispatch('autoRefresh')
      } else if (status === 202) {
        log(`An error occurred while getting the latest releases. Retrying in 45 seconds.`)
        commit('setInfoSnackbar', 'Could not get the latest releases. Retrying in 45 seconds.', isRoot)
        setTimeout(() => {
          log(`Retrying to get latest releases.`)
          dispatch('init').catch(err => { void (err) })
        }, 45 * 1000)
      } else if (status === 204) {
        log('nyaa.si does not respond... Switching to nyaa.pantsu.cat.')

        commit('setChoice', 'pantsu')

        const {data, status} = await axios.get('getLatestNyaa', { params: state.params })

        if (status === 200) {
          commit('set', {data})

          if (state.autoRefresh === true) dispatch('autoRefresh')
        } else if (status === 202) {
          log(`An error occurred while getting the latest releases. Retrying in 45 seconds.`)
          commit('setInfoSnackbar', 'Could not get the latest releases. Retrying in 45 seconds.', isRoot)
          setTimeout(() => {
            log(`Retrying to get latest releases.`)
            dispatch('init').catch(err => { void (err) })
          }, 45 * 1000)
        } else if (status === 204) {
          log('nyaa.pantsu.cat does not respond... Switching to HorribleSubs.')

          commit('setChoice', 'si')

          const {data, status} = await axios.get(`getLatest.json?quality=${state.params.quality}`)

          if (status === 200) {
            commit('set', {data})

            if (state.autoRefresh === true) dispatch('autoRefresh')
          } else if (status === 202) {
            log(`An error occurred while getting the latest releases. Retrying in 45 seconds.`)
            commit('setInfoSnackbar', 'Could not get the latest releases. Retrying in 45 seconds.', isRoot)
            setTimeout(() => {
              log(`Retrying to get latest releases.`)
              dispatch('init').catch(err => { void (err) })
            }, 45 * 1000)
          } else if (status === 204) {
            log('HorribleSubs does not respond. Retrying with nyaa.si...')

            dispatch('init')
          }
        }
      }
    } catch (e) {
      log(`An error occurred while getting the latest releases. Retrying in 45 seconds.`)
      commit('setInfoSnackbar', 'Could not get the latest releases. Retrying in 45 seconds.', isRoot)
      setTimeout(() => {
        log(`Retrying to get latest releases.`)
        dispatch('init').catch(err => { void (err) })
      }, 45 * 1000)
    }
  },
  async refresh ({state, commit, dispatch}) {
    log(`Refreshing Releases...`)

    const retryLater = (backUp) => {
      if (!state.notLoaded) {
        log(`An error occurred while getting the latest releases. Retrying in 45 seconds.`)
        commit('setInfoSnackbar', 'Could not get the latest releases. Retrying in 45 seconds.', isRoot)

        backUp.length && commit('set', {old: backUp})

        setTimeout(() => {
          log(`Retrying to get latest releases.`)
          dispatch('refresh').catch(err => { void (err) })
        }, 45 * 1000)
      }
    }

    const backUp = state.releases

    commit('empty')

    try {
      const {data, status} = await axios.get('getLatestNyaa', { params: state.params })

      if (status === 200) commit('set', {data})
      else if (status === 202) {
        retryLater(backUp)
      } else if (status === 204) {
        const {data, status} = await axios.get(`getLatest.json?quality=${state.params.quality}`)

        if (status === 200) commit('set', {data})
        else if (status === 202 || status === 204) {
          retryLater(backUp)
        }
      }
    } catch (e) {
      retryLater(backUp)
    }
  },
  async autoRefresh ({dispatch, commit, state}) {
    // Refresh releases every 30 minutes
    setTimeout(async () => {
      log(`Refreshing Releases...`)

      try {
        const {data} = await axios.get('getLatestNyaa', { params: state.params })

        if (data.length === 18) {
          commit('set', {data})
          dispatch('autoRefresh')
        } else {
          commit('setInfoSnackbar', 'Auto refresh releases failed... Attempting again in 30 minutes.', isRoot)

          dispatch('autoRefresh')
        }
      } catch (e) {
        commit('setInfoSnackbar', 'Auto refresh releases failed... Attempting again in 30 minutes.', isRoot)

        dispatch('autoRefresh')
      }
    }, 30 * 60 * 1000)
  }
}
<|endoftext|>


<commit_before>
var fs = require('fs');

var clarify = function(string)
{
    first = string.indexOf(" ");

    while(first == 0)
    {
        string = string.replace(string[0], '');
        first  = string.indexOf("+");
    }

    return string
}

var padd = function(string)
{
    return clarify(string).split(' ').join('+');
}

var generateRandom = function(left, right)
{
    var newleft = (typeof left  == "undefined") ? 1     : left + 1 ;
    var isRange = (typeof right == "undefined") ? false : true ;

    if(isRange)
    {
        return Math.floor(Math.random() * (right - newleft + 1) + newleft);
    }
    else
    {
        if(newleft != 1)
        {
            return Math.floor(Math.random() * newleft);
        }
        else
        {
            return Math.random();
        }
    }
}

var triggersRandom = function(rand, xrange)
{
    var left      = (typeof xrange == "undefined") ? 10 : xrange ;
    var generated = generateRandom(left);

    for(var i=0; i<rand.length; i++)
    {
        if(i == generated)
        {
            return true;
        }
    }

    return false;
}

var getArrayKeys = function(arr)
{
    var keys = [];

    for(var key in arr)
    {
        keys.push(key);
    }

    return keys;
}

var getArrayValues = function(arr)
{
    var values = [];

    for(var val in arr)
    {
        values.push(arr[val]);
    }

    return values;
}

var in_array = function(needle, haystack)
{
    for(key in haystack)
    {
        if(haystack[key] == needle)
        {
            return true;
        }
    }

    return false;
}

var array_unique = function(arr)
{
    var a = [];
    var l = arr.length;

    for(var i=0; i<l; i++)
    {
        for(var j=i+1; j<l; j++)
        {
            if (arr[i] === arr[j])
            {
                j = ++i;
            }
        }
        a.push(arr[i]);
    }

    return a;
};

var chooseRandom = function(arr)
{
    var len  = arr.length;
    var rand = Math.random();

    return arr[Math.floor(rand*len)];
}

var getKey = function(apiKey)
{
    return chooseRandom(Config.api_keys[apiKey]);
}

var dlevenshtein = function(a, b)
{
	var i, j, cost;
	var d = new Array();

    if(a.length == 0 || b.length == 0) { return 0; }

    for(i=0; i<=a.length; i++)
    {
        d[i]    = new Array();
        d[i][0] = i;
    }

    for(j=0; j<=b.length; j++)
    {
        d[0][j] = j;
    }

    for(i=1; i<=a.length; i++)
    {
        for(j=1; j<=b.length; j++)
        {
            if(a.charAt(i-1) == b.charAt(j-1))
            {
                cost = 0;
            }
            else
            {
                cost = 1;
            }

            d[i][j] = Math.min(d[i-1][j] + 1, d[i][j-1] + 1, d[i-1][j-1] + cost);

            if(i > 1 && j > 1 && a.charAt(i - 1) == b.charAt(j-2) && a.charAt(i-2) == b.charAt(j-1))
            {
                d[i][j] = Math.min(d[i][j], d[i - 2][j - 2] + cost)
            }
        }
    }

    return d[a.length][b.length];
}

var computeDistance = function(string, toCmp)
{
    var len  = string.length;

    if(typeof toCmp == "string")
    {
        return (len*1.0 - dlevenshtein(string.toLowerCase(), toCmp.toLowerCase()))/len;
    }
    else
    {
        var rez = {};

        for(var i=0; i<toCmp.length; i++)
        {
            var arrtl = toCmp[i].toLowerCase();
            var itmtl = string.toLowerCase();
            var dist  = dlevenshtein(itmtl, arrtl);
            var prcnt = (len*1.0 - dist)/len;

            if(string == arrtl)
            {
                prcnt = 1.5;    // for the lulz
            }

            rez[i] = prcnt;
        }

        return rez;
    }
}

var closeEnough = function(string, toCmp, g, t)
{
    var len       = string.length;
    var get       = (typeof g == 'undefined') ? false : true;
    var threshold = (typeof t == 'undefined') ? 0.80  : t;

    if(typeof toCmp == "string")
    {
        var dist = (len*1.0 - dlevenshtein(string.toLowerCase(), toCmp.toLowerCase()))/len;

        if(dist >= threshold)
        {
            if(get){ return [toCmp, (toCmp == string)]; }
            return true;
        }

        return false;
    }
    else
    {
        for(var i=0; i<toCmp.length; i++)
        {
            var comp  = getFirstNWords(string.toLowerCase(), toCmp[i].toLowerCase().split(' ').length);
            var lcomp = comp.length;
            var dist  = dlevenshtein(comp, toCmp[i]);
            var conf  = (lcomp*1.0 - dist)/lcomp;

            if(conf >= threshold)
            {
                if(get){ return [toCmp[i], (toCmp[i] == comp)]; }
                return true;
            }
        }

        if(get){ return null; }
        return false;
    }
}

var getClosest = function(string, toCmp, threshold)
{
    var threshold = (typeof threshold == 'undefined') ? 0.80 : threshold;
    return closeEnough(string, toCmp, true, threshold);
}

var greet = function()
{
    var phrases = [
      "Yes, master?",
      "At your service",
      "Unleash my strength",
      "I'm here. As always",
      "By your command",
      "Ready to work!",
      "Yes, milord?",
      "More work?",
      "Ready for action",
      "Orders?",
      "What do you need?",
      "Say the word",
      "Aye, my lord",
      "Locked and loaded",
      "Aye, sir?",
      "I await your command",
      "Your honor?",
      "Command me!",
      "At once",
      "What ails you?",
      "Yes, my firend?",
      "Is my aid required?",
      "Do you require my aid?",
      "My powers are ready",
      "It's hammer time!",
      "I'm your robot",
      "I'm on the job",
      "You're interrupting my calculations!",
      "What is your wish?",
      "How may I serve?",
      "At your call",
      "You require my assistance?",
      "What is it now?",
      "Hmm?",
      "I'm coming through!",
      "I'm here, mortal",
      "What is it now, mortal",
      "Wattup",
      "Yo!",
      "I guess you found the Droid you were looking for",
      "01001000 01101001",
      "I'm ready and waiting",
      "Ah, at last",
      "I'm here",
      "Something need doing?"
    ];

    return chooseRandom(phrases);
}

var errorMessage = function()
{
    messages = ['(facepalm)', '(boom)', '(gtfo)', '(jackie)', '(troll)', '(dumb)', '(yodawg)'];
    return chooseRandom(messages) + ' ';
}

var quoteName = function(name)
{
    return '@"' + name + '" ';
}

var removeBad = function(string, bad)
{
    for(var i=0; i<bad.length; i++)
    {
        if(string.indexOf(bad[i]) == 0 )
        {
            string = string.replace(bad[i], "");
        }
    }

    return string;
}

var cut = function(a, b, from)
{
    from = from.split(a);
    from = from[1].split(b);

    return from[0];
}

var cutMultiple = function(a, b, from)
{
    var x   = from.split(a);
    var rez = [];
    var cnt = 0;

    for(var i=1; i<x.length; i++)
    {
        cut = x[i].split(b)[0]

        if(cut.length > 1 )
        {
            rez[cnt]  = cut;
            cnt      += 1;
        }
    }

    return rez;
}

var ucwords = function(str)
{
    return (str + '').replace(/^([a-z])|\s+([a-z])/g, function($1)
    {
        return $1.toUpperCase();
    });
}

var str_replace = function(a, b, from)
{
    if(a.length == b.length)
    {
        for(var i=0; i<a.length; i++)
        {
            from = from.replace(new RegExp(a[i], 'g'), b[i]);
        }
    }

    return from;
}

var getFirstNWords = function(message, integer)
{
    if(message.indexOf(" ") != -1)
    {
        tokens = message.split(' ');

        if(tokens.length < integer)
        {
            return message;
        }
        else
        {
            toReturn = [];

            for(var i = 0; i < integer; i++)
            {
                toReturn[i] = tokens[i];
            }

            return toReturn.join(' ');
        }
    }

    return message;
}

var it_has = function(it, has, number)
{
    if(it.indexOf(has) != -1)
    {
        if(typeof number == "boolean")
        {
            return it.indexOf(has);
        }

        return true;
    }

    if(typeof number == "boolean")
    {
        return it.indexOf(has);
    }

    return false;
}

var consoleLog = function(message)
{
    if (Config.printToConsole == true)
    {
        var d = new Date;
        var month = ("0" + (d.getMonth()+1).toString()).slice(-2);
        var day   = ("0" + d.getDate().toString()).slice(-2);
        var hours = ("0" + d.getHours().toString()).slice(-2);
        var mins  = ("0" + d.getMinutes().toString()).slice(-2);
        var secs  = ("0" + d.getSeconds().toString()).slice(-2);
        var msecs = ("0" + d.getMilliseconds().toString()).slice(-3);
        var year  = d.getFullYear().toString();

        console.log('<[' + month + '-' + day + '-' + year + ' ' + hours + ':' + mins + ':' + secs + '.' + msecs + ']>   ' + message);
    }
};

print = function(txt)
{
    console.log(txt);
}

var getFileExtension = function(name)
{
    var i = name.lastIndexOf('.');
    return (i < 0) ? '' : name.substr(i);
}

var getFilesFromDir = function(dir, done)
{
    var results = [];

    fs.readdir(dir, function(err, list)
    {
        if (err) { return done(err); }

        var pending = list.length;

        if (!pending) { return done(null, results); }

        list.forEach(function(file)
        {
            file = dir + '/' + file;

            fs.stat(file, function(err, stat)
            {
                if (stat && stat.isDirectory())
                {
                    getFilesFromDir(file, function(err, res)
                    {
                        results = results.concat(res);
                        if (!--pending) { done(null, results); }
                    });
                }
                else
                {
                    results.push(file);
                    if (!--pending) { done(null, results); }
                }
            });
        });
    });
};

exports.NedCaller          = /^([\@\!\#\$\~\%\/\\/]*)?/;
exports.NedName            = /([Nn][Ee][Dd][Dd]?([Dd]?[Aa][Rr][Dd])?( *[^A-Za-z0-9]* *)?)/;
exports.NedPMName          = /([Nn][Ee][Dd][Dd]?([Dd]?[Aa][Rr][Dd])?( *[^A-Za-z0-9]* *)? ?)?/;
exports.greet              = greet;
exports.cut                = cut;
exports.cutMultiple        = cutMultiple;
exports.padd               = padd;
exports.clarify            = clarify;
exports.quoteName          = quoteName;
exports.removeBad          = removeBad;
exports.getFirstNWords     = getFirstNWords;
exports.ucwords            = ucwords;
exports.str_replace        = str_replace;
exports.getFileExtension   = getFileExtension;
exports.chooseRandom       = chooseRandom;
exports.getKey             = getKey;
exports.errorMessage       = errorMessage;
exports.getArrayKeys       = getArrayKeys;
exports.getArrayValues     = getArrayValues;
exports.in_array           = in_array;
exports.array_unique       = array_unique;
exports.dlevenshtein       = dlevenshtein;
exports.computeDistance    = computeDistance;
exports.closeEnough        = closeEnough;
exports.getClosest         = getClosest;
exports.it_has             = it_has;
exports.consoleLog         = consoleLog;
exports.generateRandom     = generateRandom;
exports.triggersRandom     = triggersRandom;
exports.getFilesFromDir    = getFilesFromDir;

<commit_msg>Better readability for functin names<commit_after>var fs = require('fs');

var clarify = function(string)
              {
                  first = string.indexOf(" ");

                  while(first == 0)
                  {
                      string = string.replace(string[0], '');
                      first  = string.indexOf("+");
                  }

                  return string
              }

var padd = function(string)
           {
               return clarify(string).split(' ').join('+');
           }

var generateRandom = function(left, right)
                     {
                         var newleft = (typeof left  == "undefined") ? 1     : left + 1 ;
                         var isRange = (typeof right == "undefined") ? false : true ;

                         if(isRange)
                         {
                             return Math.floor(Math.random() * (right - newleft + 1) + newleft);
                         }
                         else
                         {
                             if(newleft != 1)
                             {
                                 return Math.floor(Math.random() * newleft);
                             }
                             else
                             {
                                 return Math.random();
                             }
                         }
                     }

var triggersRandom = function(rand, xrange)
                     {
                         var left      = (typeof xrange == "undefined") ? 10 : xrange ;
                         var generated = generateRandom(left);

                         for(var i=0; i<rand.length; i++)
                         {
                             if(i == generated)
                             {
                                 return true;
                             }
                         }

                         return false;
                     }

var getArrayKeys = function(arr)
                   {
                       var keys = [];

                       for(var key in arr)
                       {
                           keys.push(key);
                       }

                       return keys;
                   }

var getArrayValues = function(arr)
                     {
                         var values = [];

                         for(var val in arr)
                         {
                             values.push(arr[val]);
                         }

                         return values;
                     }

var in_array = function(needle, haystack)
               {
                   for(key in haystack)
                   {
                       if(haystack[key] == needle)
                       {
                           return true;
                       }
                   }

                   return false;
               }

var array_unique = function(arr)
                   {
                       var a = [];
                       var l = arr.length;

                       for(var i=0; i<l; i++)
                       {
                           for(var j=i+1; j<l; j++)
                           {
                               if (arr[i] === arr[j])
                               {
                                   j = ++i;
                               }
                           }
                           a.push(arr[i]);
                       }

                       return a;
                   };

var chooseRandom = function(arr)
                   {
                       var len  = arr.length;
                       var rand = Math.random();

                       return arr[Math.floor(rand*len)];
                   }

var getKey = function(apiKey)
             {
                 return chooseRandom(Config.api_keys[apiKey]);
             }

var dlevenshtein = function(a, b)
                   {
	                   var i, j, cost;
	                   var d = new Array();

                       if(a.length == 0 || b.length == 0) { return 0; }

                       for(i=0; i<=a.length; i++)
                       {
                           d[i]    = new Array();
                           d[i][0] = i;
                       }

                       for(j=0; j<=b.length; j++)
                       {
                           d[0][j] = j;
                       }

                       for(i=1; i<=a.length; i++)
                       {
                           for(j=1; j<=b.length; j++)
                           {
                               if(a.charAt(i-1) == b.charAt(j-1))
                               {
                                   cost = 0;
                               }
                               else
                               {
                                   cost = 1;
                               }

                               d[i][j] = Math.min(d[i-1][j] + 1, d[i][j-1] + 1, d[i-1][j-1] + cost);

                               if(i > 1 && j > 1 && a.charAt(i - 1) == b.charAt(j-2) && a.charAt(i-2) == b.charAt(j-1))
                               {
                                   d[i][j] = Math.min(d[i][j], d[i - 2][j - 2] + cost)
                               }
                           }
                       }

                       return d[a.length][b.length];
                   }

var computeDistance = function(string, toCmp)
                      {
                          var len  = string.length;

                          if(typeof toCmp == "string")
                          {
                              return (len*1.0 - dlevenshtein(string.toLowerCase(), toCmp.toLowerCase()))/len;
                          }
                          else
                          {
                              var rez = {};

                              for(var i=0; i<toCmp.length; i++)
                              {
                                  var arrtl = toCmp[i].toLowerCase();
                                  var itmtl = string.toLowerCase();
                                  var dist  = dlevenshtein(itmtl, arrtl);
                                  var prcnt = (len*1.0 - dist)/len;

                                  if(string == arrtl)
                                  {
                                      prcnt = 1.5;    // for the lulz
                                  }

                                  rez[i] = prcnt;
                              }

                              return rez;
                          }
}

var closeEnough = function(string, toCmp, g, t)
                  {
                      var len       = string.length;
                      var get       = (typeof g == 'undefined') ? false : true;
                      var threshold = (typeof t == 'undefined') ? 0.80  : t;

                      if(typeof toCmp == "string")
                      {
                          var dist = (len*1.0 - dlevenshtein(string.toLowerCase(), toCmp.toLowerCase()))/len;

                          if(dist >= threshold)
                          {
                              if(get){ return [toCmp, (toCmp == string)]; }
                              return true;
                          }

                          return false;
                      }
                      else
                      {
                          for(var i=0; i<toCmp.length; i++)
                          {
                              var comp  = getFirstNWords(string.toLowerCase(), toCmp[i].toLowerCase().split(' ').length);
                              var lcomp = comp.length;
                              var dist  = dlevenshtein(comp, toCmp[i]);
                              var conf  = (lcomp*1.0 - dist)/lcomp;

                              if(conf >= threshold)
                              {
                                  if(get){ return [toCmp[i], (toCmp[i] == comp)]; }
                                  return true;
                              }
                          }

                          if(get){ return null; }
                          return false;
                      }
                  }

var getClosest = function(string, toCmp, threshold)
                 {
                     var threshold = (typeof threshold == 'undefined') ? 0.80 : threshold;
                     return closeEnough(string, toCmp, true, threshold);
                 }

var greet = function()
            {
                var phrases = [
                               "Yes, master?",
                               "At your service",
                               "Unleash my strength",
                               "I'm here. As always",
                               "By your command",
                               "Ready to work!",
                               "Yes, milord?",
                               "More work?",
                               "Ready for action",
                               "Orders?",
                               "What do you need?",
                               "Say the word",
                               "Aye, my lord",
                               "Locked and loaded",
                               "Aye, sir?",
                               "I await your command",
                               "Your honor?",
                               "Command me!",
                               "At once",
                               "What ails you?",
                               "Yes, my firend?",
                               "Is my aid required?",
                               "Do you require my aid?",
                               "My powers are ready",
                               "It's hammer time!",
                               "I'm your robot",
                               "I'm on the job",
                               "You're interrupting my calculations!",
                               "What is your wish?",
                               "How may I serve?",
                               "At your call",
                               "You require my assistance?",
                               "What is it now?",
                               "Hmm?",
                               "I'm coming through!",
                               "I'm here, mortal",
                               "What is it now, mortal",
                               "Wattup",
                               "Yo!",
                               "I guess you found the Droid you were looking for",
                               "01001000 01101001",
                               "I'm ready and waiting",
                               "Ah, at last",
                               "I'm here",
                               "Something need doing?"
                ];

                return chooseRandom(phrases);
            }

var errorMessage = function()
                   {
                       messages = ['(facepalm)', '(boom)', '(gtfo)', '(jackie)', '(troll)', '(dumb)', '(yodawg)'];
                       return chooseRandom(messages) + ' ';
                   }

var quoteName = function(name)
                {
                    return '@"' + name + '" ';
                }

var removeBad = function(string, bad)
                {
                    for(var i=0; i<bad.length; i++)
                    {
                        if(string.indexOf(bad[i]) == 0 )
                        {
                            string = string.replace(bad[i], "");
                        }
                    }

                    return string;
                }

var cut = function(a, b, from)
          {
              from = from.split(a);
              from = from[1].split(b);

              return from[0];
          }

var cutMultiple = function(a, b, from)
                  {
                      var x   = from.split(a);
                      var rez = [];
                      var cnt = 0;

                      for(var i=1; i<x.length; i++)
                      {
                          cut = x[i].split(b)[0]

                          if(cut.length > 1 )
                          {
                              rez[cnt]  = cut;
                              cnt      += 1;
                          }
                      }

                      return rez;
                  }

var ucwords = function(str)
              {
                  return (str + '').replace(/^([a-z])|\s+([a-z])/g, function($1)
                  {
                      return $1.toUpperCase();
                  });
              }

var str_replace = function(a, b, from)
                  {
                      if(a.length == b.length)
                      {
                          for(var i=0; i<a.length; i++)
                          {
                              from = from.replace(new RegExp(a[i], 'g'), b[i]);
                          }
                      }

                      return from;
                  }

var getFirstNWords = function(message, integer)
                     {
                         if(message.indexOf(" ") != -1)
                         {
                             tokens = message.split(' ');

                             if(tokens.length < integer)
                             {
                                 return message;
                             }
                             else
                             {
                                 toReturn = [];

                                 for(var i = 0; i < integer; i++)
                                 {
                                     toReturn[i] = tokens[i];
                                 }

                                 return toReturn.join(' ');
                             }
                         }

                         return message;
                     }

var it_has = function(it, has, number)
             {
                 if(it.indexOf(has) != -1)
                 {
                     if(typeof number == "boolean")
                     {
                         return it.indexOf(has);
                     }

                     return true;
                 }

                 if(typeof number == "boolean")
                 {
                     return it.indexOf(has);
                 }

                 return false;
             }

var consoleLog = function(message)
                 {
                     if (Config.printToConsole == true)
                     {
                         var d = new Date;
                         var month = ("0" + (d.getMonth()+1).toString()).slice(-2);
                         var day   = ("0" + d.getDate().toString()).slice(-2);
                         var hours = ("0" + d.getHours().toString()).slice(-2);
                         var mins  = ("0" + d.getMinutes().toString()).slice(-2);
                         var secs  = ("0" + d.getSeconds().toString()).slice(-2);
                         var msecs = ("0" + d.getMilliseconds().toString()).slice(-3);
                         var year  = d.getFullYear().toString();

                         console.log('<[' + month + '-' + day + '-' + year + ' ' +
                                     hours + ':' + mins + ':' + secs + '.' + msecs +
                                     ']>   ' + message);
                     }
                 }

var getFileExtension = function(name)
                       {
                           var i = name.lastIndexOf('.');
                           return (i < 0) ? '' : name.substr(i);
                       }

var getFilesFromDir = function(dir, done)
                      {
                          var results = [];

                          fs.readdir(dir, function(err, list)
                          {
                              if (err) { return done(err); }

                              var pending = list.length;

                              if (!pending) { return done(null, results); }

                              list.forEach(function(file)
                              {
                                  file = dir + '/' + file;

                                  fs.stat(file, function(err, stat)
                                  {
                                      if (stat && stat.isDirectory())
                                      {
                                          getFilesFromDir(file, function(err, res)
                                          {
                                              results = results.concat(res);
                                              if (!--pending) { done(null, results); }
                                          });
                                      }
                                      else
                                      {
                                          results.push(file);
                                          if (!--pending) { done(null, results); }
                                      }
                                  });
                              });
                          });
                      };

print = function(txt)
        {
            console.log(txt);
        }

exports.NedCaller          = /^([\@\!\#\$\~\%\/\\/]*)?/;
exports.NedName            = /([Nn][Ee][Dd][Dd]?([Dd]?[Aa][Rr][Dd])?( *[^A-Za-z0-9]* *)?)/;
exports.NedPMName          = /([Nn][Ee][Dd][Dd]?([Dd]?[Aa][Rr][Dd])?( *[^A-Za-z0-9]* *)? ?)?/;
exports.greet              = greet;
exports.cut                = cut;
exports.cutMultiple        = cutMultiple;
exports.padd               = padd;
exports.clarify            = clarify;
exports.quoteName          = quoteName;
exports.removeBad          = removeBad;
exports.getFirstNWords     = getFirstNWords;
exports.ucwords            = ucwords;
exports.str_replace        = str_replace;
exports.getFileExtension   = getFileExtension;
exports.chooseRandom       = chooseRandom;
exports.getKey             = getKey;
exports.errorMessage       = errorMessage;
exports.getArrayKeys       = getArrayKeys;
exports.getArrayValues     = getArrayValues;
exports.in_array           = in_array;
exports.array_unique       = array_unique;
exports.dlevenshtein       = dlevenshtein;
exports.computeDistance    = computeDistance;
exports.closeEnough        = closeEnough;
exports.getClosest         = getClosest;
exports.it_has             = it_has;
exports.consoleLog         = consoleLog;
exports.generateRandom     = generateRandom;
exports.triggersRandom     = triggersRandom;
exports.getFilesFromDir    = getFilesFromDir;
<|endoftext|>


<commit_before>'use strict';

module.exports = function(grunt) {
  var inspect = require('util').inspect;
  var helpers = require('./helpers')(grunt),
    path = require('path'),
    changeCase = require('change-case'),
    processors = require('./processors'),
    array = require("array-extended");

  var Generator = function(source, filepath) {
    this.source = source;
    this.filepath = filepath;

    this.validations = [];
    this.uses = [];
    this.id = 0;

    this.classname = path.basename(filepath, path.extname(filepath));
    this.classname = changeCase.upperCaseFirst(changeCase.camelCase(this.classname));
  };

  Generator.prototype.run = function() {
    this.buildValidations();

    var uses = '';
    if (this.uses.length > 0) {
      uses = 'use ' + array.unique(this.uses).join(';\nuse ') + ';';
    }

    var data = {
      classname: this.classname,
      filepath: this.filepath,
      validations: this.validations.join('\n'),
      uses: uses,
    };
    return helpers.template('base', data);
  };

  Generator.prototype.buildValidations = function() {
    this.buildObject(this.source, 'data', 'valid');
  };

  Generator.prototype.buildObject = function(obj, objname, resname) {
    for (var name in obj) {
      var key = '\'' + name + '\'';

      // Object specific validations per key
      this.validations.push(helpers.template('pre-object-key', {
        object: objname,
        name: name,
        key: key,
      }));

      var omitPost = this.runProcessors(name, key, objname, resname, obj[name]);

      // Object specific validations per key
      if (!omitPost) {
        this.validations.push(helpers.template('post-object-key', {
          result: resname,
          name: name,
        }));
      }
    }
  };

  Generator.prototype.buildArray = function(name, arr, objname, resname) {
    var id = this.generateArrayId();

    this.validations.push(helpers.template('pre-array', {
      object: objname,
      result: resname,
      id: id,
    }));

    this.runProcessors(name, '$i' + id, objname, resname, arr.fields);

    this.validations.push(helpers.template('post-array'));
  };

  /*
func generateArray(e *emitter, varname, result string, fields []*field) error {
  for _, f := range fields {
    f.Key = fmt.Sprintf("$i%d", id)

    if err := generateField(e, f, varname, result); err != nil {
      return fmt.Errorf("generate field failed: %s", err)
    }
    if f.Kind != "Conditional" && f.Kind != "Array" {
      if err := generateValidations(e, f); err != nil {
        return fmt.Errorf("generate validators failed: %s", err)
      }

      if f.Kind != "Object" {
        e.emitf(`$%s[%s] = $value;`, result, f.Key)
      }
    }
    e.emitf("")
  }

  e.unindent()
  e.emitf("}")
  return nil
}
*/

  Generator.prototype.runProcessors = function(name, key, objname, resname, procs) {
    var runned = [], stored = [];

    // Check proccesors type
    if (!Array.isArray(procs)) {
      return this.runRecursive(name, key, objname, resname, procs);
    }

    for (var i = 0; i < procs.length; i++) {
      var proc = procs[i];

      if (Array.isArray(proc)) {
        // Extract advanced format
        args = proc[1];
        proc = proc[0];
      } else {
        // Extract the processor name & args in simple format
        var args = '';
        if (proc.indexOf(':') != -1) {
          var idx = proc.indexOf(':');
          args = proc.substring(idx + 1, proc.length);
          proc = proc.substring(0, idx);
        }
        args = args.split(',');
      }

      grunt.verbose.debug('Processing key [' + name + '] with processor [' +
          proc + '] with args: ' + grunt.log.wordlist(args))

      // Check if it exists
      if (!processors[proc]) {
        grunt.fatal('\n\tValidator processor not recognized: ' + proc +
          '\n\tin key: ' + name + '\n\tin file: ' + this.filepath);
      }

      // Run the processor
      try {
        var result = processors[proc](this, objname, name, key, args);
      } catch(e) {
        grunt.fatal('\n\t' + e + '\n\tin processor: ' + proc +
          '\n\twith args: ' + args +
          '\n\tin key: ' + name + '\n\tin file: ' + this.filepath);
      }

      // Processor dependencies
      if (result.requires) {
        for (var j = 0; j < result.requires.length; j++) {
          if (runned.indexOf(result.requires[j]) == -1) {
            grunt.fatal('\n\tprocessor [' + proc + '] needs [' + result.requires[j] +
                '] before to run correctly\n\tin key: ' + name +
                '\n\tin file: ' + this.filepath);
          }
        }
      }
      if (result.requiresStored) {
        for (var j = 0; j < result.requiresStored.length; j++) {
          if (stored.indexOf(result.requiresStored[j]) == -1) {
            grunt.fatal('\n\tprocessor [' + proc + '] needs stored value [' +
                result.requiresStored[j] + '] before to run correctly\n\tin key: ' +
                name + '\n\tin file: ' + this.filepath);
          }
        }
      }

      // Processor PHP dependencies
      if (result.uses) {
        this.uses = this.uses.concat(result.uses);
      }

      // Processor template
      if (result.template) {
        this.validations.push(helpers.template(result.template, result.data));
      }

      // Save stored values
      if (result.stored) {
        stored.push(result.stored);
      }

      runned.push(proc);
    }
  };

  Generator.prototype.runRecursive = function(name, key, objname, resname, procs) {
    if (typeof procs !== 'object') {
      grunt.fatal('\n\tproccessors should be an array or an object' +
        '\n\tin key: ' + name + '\n\tin file: ' + this.filepath);
    }

    if (procs.kind === 'object') {
      // Objects
      this.validations.push(helpers.template('object', {
        object: objname,
        result: resname,
        name: name,
        key: key,
      }));
      objname += '[\'' + name + '\']';
      resname += '[\'' + name + '\']';
      this.buildObject(procs.fields, objname, resname);
      return true;
    } else if (procs.kind === 'array') {
      // Arrays
      this.validations.push(helpers.template('array', {
        object: objname,
        result: resname,
        name: name,
        key: key,
      }));
      objname += '[\'' + name + '\']';
      resname += '[\'' + name + '\']';
      this.buildArray(name, procs, objname, resname);
      return true;
    }

    // Recursive field not recognized
    grunt.fatal('\n\tcollection kind not recognized: ' + procs.kind +
      '\n\tin key: ' + name + '\n\tin file: ' + this.filepath);
  };

  Generator.prototype.generateArrayId = function() {
    return this.id++;
  };

  return Generator;
};

<commit_msg>Indent code.<commit_after>'use strict';

module.exports = function(grunt) {
  var inspect = require('util').inspect;
  var helpers = require('./helpers')(grunt),
    path = require('path'),
    changeCase = require('change-case'),
    processors = require('./processors'),
    array = require("array-extended");

  var Generator = function(source, filepath) {
    this.source = source;
    this.filepath = filepath;

    this.validations = [];
    this.uses = [];
    this.id = 0;
    this.indent = 0;

    this.classname = path.basename(filepath, path.extname(filepath));
    this.classname = changeCase.upperCaseFirst(changeCase.camelCase(this.classname));
  };

  Generator.prototype.run = function() {
    this.buildValidations();

    var uses = '';
    if (this.uses.length > 0) {
      uses = 'use ' + array.unique(this.uses).join(';\nuse ') + ';';
    }

    var data = {
      classname: this.classname,
      filepath: this.filepath,
      validations: this.validations.join('\n'),
      uses: uses,
    };
    return helpers.template('base', data);
  };

  Generator.prototype.buildValidations = function() {
    this.buildObject(this.source, 'data', 'valid');
  };

  Generator.prototype.buildObject = function(obj, objname, resname) {
    for (var name in obj) {
      var key = '\'' + name + '\'';

      // Object specific validations per key
      this.outputBlock(helpers.template('pre-object-key', {
        object: objname,
        name: name,
        key: key,
      }));

      var omitPost = this.runProcessors(name, key, objname, resname, obj[name]);

      // Object specific validations per key
      if (!omitPost) {
        this.outputBlock(helpers.template('post-object-key', {
          result: resname,
          name: name,
        }));
      }
    }
  };

  Generator.prototype.buildArray = function(name, arr, objname, resname) {
    var id = this.generateArrayId();

    this.outputBlock(helpers.template('pre-array', {
      object: objname,
      result: resname,
      id: id,
    }));

    this.indent++;
    this.runProcessors(name, '$i' + id, objname, resname, arr.fields);
    this.indent--;

    this.outputBlock(helpers.template('post-array'));
  };

  Generator.prototype.runProcessors = function(name, key, objname, resname, procs) {
    var runned = [], stored = [];

    // Check proccesors type
    if (!Array.isArray(procs)) {
      return this.runRecursive(name, key, objname, resname, procs);
    }

    for (var i = 0; i < procs.length; i++) {
      var proc = procs[i];

      if (Array.isArray(proc)) {
        // Extract advanced format
        args = proc[1];
        proc = proc[0];
      } else {
        // Extract the processor name & args in simple format
        var args = '';
        if (proc.indexOf(':') != -1) {
          var idx = proc.indexOf(':');
          args = proc.substring(idx + 1, proc.length);
          proc = proc.substring(0, idx);
        }
        args = args.split(',');
      }

      grunt.verbose.debug('Processing key [' + name + '] with processor [' +
          proc + '] with args: ' + grunt.log.wordlist(args))

      // Check if it exists
      if (!processors[proc]) {
        grunt.fatal('\n\tValidator processor not recognized: ' + proc +
          '\n\tin key: ' + name + '\n\tin file: ' + this.filepath);
      }

      // Run the processor
      try {
        var result = processors[proc](this, objname, name, key, args);
      } catch(e) {
        grunt.fatal('\n\t' + e + '\n\tin processor: ' + proc +
          '\n\twith args: ' + args +
          '\n\tin key: ' + name + '\n\tin file: ' + this.filepath);
      }

      // Processor dependencies
      if (result.requires) {
        for (var j = 0; j < result.requires.length; j++) {
          if (runned.indexOf(result.requires[j]) == -1) {
            grunt.fatal('\n\tprocessor [' + proc + '] needs [' + result.requires[j] +
                '] before to run correctly\n\tin key: ' + name +
                '\n\tin file: ' + this.filepath);
          }
        }
      }
      if (result.requiresStored) {
        for (var j = 0; j < result.requiresStored.length; j++) {
          if (stored.indexOf(result.requiresStored[j]) == -1) {
            grunt.fatal('\n\tprocessor [' + proc + '] needs stored value [' +
                result.requiresStored[j] + '] before to run correctly\n\tin key: ' +
                name + '\n\tin file: ' + this.filepath);
          }
        }
      }

      // Processor PHP dependencies
      if (result.uses) {
        this.uses = this.uses.concat(result.uses);
      }

      // Processor template
      if (result.template) {
        this.outputBlock(helpers.template(result.template, result.data));
      }

      // Save stored values
      if (result.stored) {
        stored.push(result.stored);
      }

      runned.push(proc);
    }
  };

  Generator.prototype.runRecursive = function(name, key, objname, resname, procs) {
    if (typeof procs !== 'object') {
      grunt.fatal('\n\tproccessors should be an array or an object' +
        '\n\tin key: ' + name + '\n\tin file: ' + this.filepath);
    }

    if (procs.kind === 'object') {
      // Objects
      this.outputBlock(helpers.template('object', {
        object: objname,
        result: resname,
        name: name,
        key: key,
      }));
      objname += '[\'' + name + '\']';
      resname += '[\'' + name + '\']';
      this.buildObject(procs.fields, objname, resname);
      return true;
    } else if (procs.kind === 'array') {
      // Arrays
      this.outputBlock(helpers.template('array', {
        object: objname,
        result: resname,
        name: name,
        key: key,
      }));
      objname += '[\'' + name + '\']';
      resname += '[\'' + name + '\']';
      this.buildArray(name, procs, objname, resname);
      return true;
    }

    // Recursive field not recognized
    grunt.fatal('\n\tcollection kind not recognized: ' + procs.kind +
      '\n\tin key: ' + name + '\n\tin file: ' + this.filepath);
  };

  Generator.prototype.generateArrayId = function() {
    return this.id++;
  };

  Generator.prototype.outputBlock = function(block) {
    var prefix = grunt.util.repeat(this.indent, '  ');
    var lines = block.split('\n');
    for (var i = 0; i < lines.length; i++) {
      if (lines[i].length > 0) {
        lines[i] = prefix + lines[i];
      }
    }
    this.validations.push(lines.join('\n'));
  };

  return Generator;
};

<|endoftext|>


<commit_before>'use strict';
const BufferStreams = require('bufferstreams');
const spawn = require('child_process').spawn;
const REBLAME = /(?:^|\n)(\w+)(?:\s.+?)?\s+\((?:<(.+?)>|(.+?))\s+((?:@?\d+|\d+\D\d+\D\d+\s\d+\D\d+\D\d+)(?:\s+[+-]\d+)?)\s+(\d+)\)/gm;
const parseDate = require('./parse-date');

/**
 * 运行 git blame 命令
 *
 * @param   {Vinyl}   file      要检查blame信息的文件
 * @param   {Boolean} showEmail 是否使用后email代替用户名
 * @returns {Promise} 命令运行结果，Buffer
 */
function runBlame(file, showEmail) {
	return new Promise((resolve, reject) => {
		const args = ['blame', '-l', '-t', '-w', '-C', '-M'];
		if (showEmail) {
			args.push('--show-email');
		}
		if (file.contents) {
			args.push('--contents');
			args.push('-');
		}

		args.push('--');
		args.push(file.path);

		const blame = spawn('git', args, {
			cwd: file.cwd,
		});

		blame.stdin.on('error', reject);

		if (file.isBuffer()) {
			blame.stdin.write(file.contents);
			blame.stdin.end();
		} else if (file.isStream()) {
			file.contents.pipe(blame.stdin);
		}

		blame.stdout.pipe(new BufferStreams((err, buf) => {
			if (buf) {
				resolve(buf);
			} else if (err) {
				reject(err);
			}
		}));

		blame.on('error', reject);
		blame.on('close', reject);
	});
}

/**
 * 将git blame 命令运行结果转换为行号作为下标的数组
 *
 * @param {Buffer}   data git blame命令返回的buffer信息
 * @returns {Array}  数组，里面是每行代码的作者信息对象
 */
function getReaslt(data) {
	if (data && data.length) {
		const result = [];
		let match;
		data = data.toString();
		REBLAME.lastIndex = 0;

		while ((match = REBLAME.exec(data))) {
			const lineNumber = +match[5];
			const blame = result[lineNumber] = {
				hash: match[1],
				time: parseDate(match[4]),
			};
			if (match[2]) {
				blame.email = match[2];
			} else {
				blame.name = match[3];
			}
		}
		return result;
	}
}

/**
 * 运行 git blame 命令
 *
 * @param   {Vinyl}   file      要检查blame信息的文件
 * @param   {Boolean} showEmail 是否使用后email代替用户名
 * @returns {Promise} 命令运行结果，数组，里面是每行代码的作者信息对象
 */
function getFileBlame(file, showEmail) {
	return runBlame(file, showEmail).then(getReaslt);
}

module.exports = function(file) {
	return Promise.all([getFileBlame(file), getFileBlame(file, true)]).then(blame => {
		return blame[0].map((blameLine, index) => {
			if (blameLine) {
				blameLine = Object.assign(blameLine, blame[1][index]);
			}
			return blameLine;
		});
	});
};
<commit_msg>fix regexp of git blame<commit_after>'use strict';
const BufferStreams = require('bufferstreams');
const spawn = require('child_process').spawn;
const RE_BLAME = /(?:^|\n)\^?(\w+)(?:\s.+?)?\s+\((?:<(.+?)>|(.+?))\s+((?:@?\d+|\d+\D\d+\D\d+\s\d+\D\d+\D\d+)(?:\s+[+-]\d+)?)\s+(\d+)\)/gm;
const parseDate = require('./parse-date');

/**
 * 运行 git blame 命令
 *
 * @param   {Vinyl}   file      要检查blame信息的文件
 * @param   {Boolean} showEmail 是否使用后email代替用户名
 * @returns {Promise} 命令运行结果，Buffer
 */
function runBlame(file, showEmail) {
	return new Promise((resolve, reject) => {
		const args = ['blame', '-l', '-t', '-w', '-C', '-M'];
		if (showEmail) {
			args.push('--show-email');
		}
		if (file.contents) {
			args.push('--contents');
			args.push('-');
		}

		args.push('--');
		args.push(file.path);

		const blame = spawn('git', args, {
			cwd: file.cwd,
		});

		blame.stdin.on('error', reject);

		if (file.isBuffer()) {
			blame.stdin.write(file.contents);
			blame.stdin.end();
		} else if (file.isStream()) {
			file.contents.pipe(blame.stdin);
		}

		blame.stdout.pipe(new BufferStreams((err, buf) => {
			if (buf) {
				resolve(buf);
			} else if (err) {
				reject(err);
			}
		}));

		blame.on('error', reject);
		blame.on('close', reject);
	});
}

/**
 * 将git blame 命令运行结果转换为行号作为下标的数组
 *
 * @param {Buffer}   data git blame命令返回的buffer信息
 * @returns {Array}  数组，里面是每行代码的作者信息对象
 */
function getReaslt(data) {
	if (data && data.length) {
		const result = [];
		let match;
		data = data.toString();
		RE_BLAME.lastIndex = 0;

		while ((match = RE_BLAME.exec(data))) {
			const lineNumber = +match[5];
			const blame = result[lineNumber] = {
				hash: match[1],
				time: parseDate(match[4]),
			};
			if (match[2]) {
				blame.email = match[2];
			} else {
				blame.name = match[3];
			}
		}
		return result;
	}
}

/**
 * 运行 git blame 命令
 *
 * @param   {Vinyl}   file      要检查blame信息的文件
 * @param   {Boolean} showEmail 是否使用后email代替用户名
 * @returns {Promise} 命令运行结果，数组，里面是每行代码的作者信息对象
 */
function getFileBlame(file, showEmail) {
	return runBlame(file, showEmail).then(getReaslt);
}

module.exports = function(file) {
	return Promise.all([getFileBlame(file), getFileBlame(file, true)]).then(blame => {
		return blame[0].map((blameLine, index) => {
			if (blameLine) {
				blameLine = Object.assign(blameLine, blame[1][index]);
			}
			return blameLine;
		});
	});
};
<|endoftext|>


<commit_before>var config = require("../config/config.js");
var DataModel = require("../model/datamodel.js");

var google = require("googleapis");
var OAuth2Client = google.auth.OAuth2;
var calendar = google.calendar("v3");
var moment = require("moment");

//Class Declaration

function GoogleCal(){
    this.clientID = config.gcal.clientID;
    this.clientSecret = config.gcal.clientSecret;
    this.account = config.gcal.account;

    this.oauth2Client = new OAuth2Client(this.clientID,this.clientSecret)
    this.oauth2Client.credentials = {
        access_token:  config.gcal.access_token,
        refresh_token: config.gcal.refresh_token
    };
    this.oauth2Client.refreshAccessToken(this.authCheck);

    this.hostname = config.gcal.hostname;
    this.path = config.gcal.path;

    this.startDate = moment().startOf("day").toISOString();
	this.endDate = moment().endOf("day").toISOString();
    this.dateWords = ["mon","tue","tues","wed","thur","thurs","fri","sat","sun","monday","tuesday","wednesday","thursday","friday","saturday","yesterday","today","tonight","tomorrow"];

    this.input = {};

    this.output = [];
    this.outputCount = 0;
    this.outputLimit = 0;

    this.ircCallback = function(){};
};

module.exports = function(data){
    return new GoogleCal().set(data);
};

//Class Methods

GoogleCal.prototype = DataModel();

GoogleCal.prototype.authCheck = function(err){
    if (err){
        console.log("[Error] Problem Refreshing OAuth2 Tokens.")
    }
};

//IRC Methods

GoogleCal.prototype.ircRequest = function(Input){
    this.set({
        input: Input,
        ircCallback: Input.callback,
        outputLimit: this.setOutputLimit(Input)
    });
    this.ircRouteRequest(Input);
};

GoogleCal.prototype.ircRouteRequest = function(Input){
    var keyword = Input.method == "onduty" ? "on-call" : Input.method;
    var date = Input.targetDate !== "" ? Input.targetDate : false;
    var range = (Input.range === 0 ? 1 : Input.range);
    var callback = this.ircHandleResult.bind(this);
    var name = Input.users.length > 0 ? Input.users[0].name : "";
    var next = Input.contains("options","next");

    this.getEventsByDate(keyword,date,range,callback,name,next);
};

GoogleCal.prototype.ircHandleResult = function(err,events){
    if (err){
        this.ircHandleError(err);
    }else{
        var l = events.length
        if (l < 1){
            this.setOne("output","Hm, I couldn't find anything for that. Sorry :(");
            this.ircOutputResult();
        }else{
            this.ircEventsFromResult(events);
        }
    }
};

GoogleCal.prototype.ircEventsFromResult = function(events){
    events.forEach(assembleLine.bind(this));

    function assembleLine(elem,ind,arr){
        if (ind < this.outputLimit){
            if (elem.start.date && elem.start.date !== moment(elem.end.date).subtract(1,"days").format("YYYY-MM-DD")){
                this.setOne("output","["+moment(elem.start.date).format("ddd MM/DD")+" to "+moment(elem.end.date).subtract(1,"days").format("ddd MM/DD")+" | "+elem.summary+"]");
            }else{
                this.setOne("output","["+moment(elem.start.dateTime ? elem.start.dateTime : elem.start.date).format("ddd MM/DD")+" | "+elem.summary+"]");
            }
        }
    }
        this.ircOutputResult();
};

GoogleCal.prototype.ircNamesFromResult = function(err,events){
    if (err){
        this.ircHandleError(err);
    }else{
        for (u in config.users){
            var user = config.users[u];
            if (events[0].summary.indexOf(user.name) > -1){
                this.ircCallback(user.name);
            }
        }
    }
};

GoogleCal.prototype.ircHandleError = function(err){
    console.log(err,"Google Calendar API Request Error");
    this.setOne("output","Bad Google API Response :(");
    this.ircOutputResult();
};

GoogleCal.prototype.ircOutputResult = function(){
    this.ircCallback(this.output);
    this.output = [];
};

//IRC Helper Methods

GoogleCal.prototype.setOutputLimit = function(Input){
    return Input.range > 0 ? Input.range : (Input.method === "ooo" && Input.users.length < 1 ? 99 : 1);
}

//API Methods

GoogleCal.prototype.getEventsByDate = function(keyword,date,range,callback,name,next){
    if (keyword === "on-call"){
        if (name){
            this.getOnDutyByName(date,range,name,next,callback);
        }else{
            this.getOnDuty(date,range,next,callback);
        }
    }else if (keyword === "ooo"){
        if (name){
            this.getOOOByName(date,range,name,next,callback);
        }else{
            this.getOOO(date,range,next,callback);
        }
    }else if (keyword === "wfh"){
        if (name){
            this.getWFHByName(date,range,name,next,callback);
        }else{
            this.getWFH(date,range,next,callback);
        }
    }
};

GoogleCal.prototype.getOnDuty = function(date,range,next,callback){
    var r = this.getDateRange(date,range,"day",next);
    var apiCallback = this.filterResults.bind(this,"on-call","",r.startDate,r.endDate,callback)
    this.getEventsByRange(r.startDate,r.endDate,apiCallback)
};

GoogleCal.prototype.getOOO = function(date,range,next,callback){
    var r = this.getDateRange(date,range,"day",next);
    var apiCallback = this.filterResults.bind(this,"ooo","",r.startDate,r.endDate,callback)
    this.getEventsByRange(r.startDate,r.endDate,apiCallback)
};

GoogleCal.prototype.getWFH = function(date,range,next,callback){
    var r = this.getDateRange(date,range,"day",next);
    var apiCallback = this.filterResults.bind(this,"wfh","",r.startDate,r.endDate,callback)
    this.getEventsByRange(r.startDate,r.endDate,apiCallback)
};

GoogleCal.prototype.getOnDutyByName = function(date,range,name,next,callback){
    var r = this.getDateRange(date,range,"month",next);
    var apiCallback = this.filterResults.bind(this,"on-call",name,r.startDate,r.endDate,callback)
    this.getEventsByRange(r.startDate,r.endDate,apiCallback)
};

GoogleCal.prototype.getOOOByName = function(date,range,name,next,callback){
    var r = this.getDateRange(date,range,"month",next);
    var apiCallback = this.filterResults.bind(this,"ooo",name,r.startDate,r.endDate,callback)
    this.getEventsByRange(r.startDate,r.endDate,apiCallback)
};

GoogleCal.prototype.isOOO = function(name,callback){
    this.getOOOTodayByName(name,callback);
};

GoogleCal.prototype.getOOOTodayByName = function(name,callback){
    var r = this.getDateRange("today",1,"day",false);
    var apiCallback = this.filterResults.bind(this,"ooo",name,r.startDate,r.endDate,callback)
    this.getEventsByRange(r.startDate,r.endDate,apiCallback)
};

GoogleCal.prototype.getWFHByName = function(date,range,name,next,callback){
    var r = this.getDateRange(date,range,"month",next);
    var apiCallback = this.filterResults.bind(this,"wfh",name,r.startDate,r.endDate,callback)
    this.getEventsByRange(r.startDate,r.endDate,apiCallback)
};

GoogleCal.prototype.getEventsByRange = function(startDate,endDate,apiCallback){
    var query = {
        calendarId: this.account,
        auth: this.oauth2Client,
        timeMin: startDate,
        timeMax: endDate,
        orderBy: "startTime",
        singleEvents: true
    };
    this.calendarQuery(query,apiCallback);
};

GoogleCal.prototype.calendarQuery = function(query,apiCallback){
    calendar.events.list(query,apiCallback);
};

//API Helper Methods

GoogleCal.prototype.getDateRange = function(date,range,rangeUnit,next){
    var startDate =  moment().startOf("day").toISOString();
    var endDate = moment().endOf("day").toISOString();

    switch (date)
        {
        case "yesterday":
            startDate = this.changeDate("subtract",1,"days",startDate);
            break;
        case "today":
        case "tonight":
            break;
        case "tomorrow":
            startDate = this.changeDate("add",1,"days",startDate);
            break;
        default:
            if (moment(date,"MM/DD")._pf.charsLeftOver == 0){
                startDate = moment(date,"MM/DD").startOf("day").toISOString();
                //If Target Month is Before This Month, Advance to Next Year
                if (moment(startDate).isBefore(moment(),"month")){
                    startDate = moment(startDate).add(1,"year").toISOString();
                }
            }else if (moment(date,["MM/DD/YY","MM/DD/YYYY"])._pf.charsLeftOver == 0){
                startDate = moment(date,["MM/DD","MM/DD/YY","MM/DD/YYYY"]).startOf("day").toISOString();
            }else if (this.contains("dateWords",date)){
                startDate = this.toWeekday(date,next);
            }
            break;
        }
        endDate = moment(startDate).endOf(rangeUnit).add(range-1,rangeUnit).toISOString();

    return {"startDate":startDate,"endDate":endDate};
};

GoogleCal.prototype.changeDate = function(mode,amt,unit,target){
    return moment(target)[mode](amt,unit).toISOString();
};

GoogleCal.prototype.toWeekday = function(date,next){
    var weekday = moment().day(date).startOf("day").toISOString();
    var dayIsPast = moment(weekday).isBefore(moment(),"day");

    return (dayIsPast || !dayIsPast && next) ? moment(weekday).add(1,"week").toISOString() : weekday;
};

GoogleCal.prototype.filterResults = function(keyword,user,startDate,endDate,callback,error,results){
    if (error){
        if (error.code === 401){
            this.oauth2Client.refreshAccessToken(requeue.bind(this));
            function requeue(err,tokens){
                if (err){
                    callback(err);
                }else{
                    this.ircRequest(this.input);
                }
            }
        }else{
            callback(error);
        }
    }else{
        var events = [];
        results.items.forEach(filterForKeyword);

        function filterForKeyword(elem,index,arr){
            if (elem.summary.toLowerCase().indexOf(keyword) > -1){
                events.push(elem);
            }
        }
        for (i = events.length - 1; i>=0; i--){
            var e = events[i];
            //If Getting Cases for a Specific User, Remove all Events Not for that User
            if (user !== "" && e.summary.indexOf(user) == -1){
                events.splice(events.indexOf(e),1);
            //Multi-Day Event Filtering Fix... Future Events Get Incorrectly Returned by API
            }else if (e.start.date && moment(e.start.date).isAfter(endDate)){
                events.splice(events.indexOf(e),1);
            }
        }
        callback(null,events);
    }
};
<commit_msg>Requeue Failed OAuth Requests by Query<commit_after>var config = require("../config/config.js");
var DataModel = require("../model/datamodel.js");

var google = require("googleapis");
var OAuth2Client = google.auth.OAuth2;
var calendar = google.calendar("v3");
var moment = require("moment");

//Class Declaration

function GoogleCal(){
    this.clientID = config.gcal.clientID;
    this.clientSecret = config.gcal.clientSecret;
    this.account = config.gcal.account;

    this.oauth2Client = new OAuth2Client(this.clientID,this.clientSecret)
    this.oauth2Client.credentials = {
        access_token:  config.gcal.access_token,
        refresh_token: config.gcal.refresh_token
    };

    this.hostname = config.gcal.hostname;
    this.path = config.gcal.path;

    this.startDate = moment().startOf("day").toISOString();
	this.endDate = moment().endOf("day").toISOString();
    this.dateWords = ["mon","tue","tues","wed","thur","thurs","fri","sat","sun","monday","tuesday","wednesday","thursday","friday","saturday","yesterday","today","tonight","tomorrow"];

    this.query = {};
    this.apiCallback = function(){};

    this.output = [];
    this.outputCount = 0;
    this.outputLimit = 0;

    this.ircCallback = function(){};
};

module.exports = function(data){
    return new GoogleCal().set(data);
};

//Class Methods

GoogleCal.prototype = DataModel();

//IRC Methods

GoogleCal.prototype.ircRequest = function(Input){
    this.set({
        input: Input,
        ircCallback: Input.callback,
        outputLimit: this.setOutputLimit(Input)
    });
    this.ircRouteRequest(Input);
};

GoogleCal.prototype.ircRouteRequest = function(Input){
    var keyword = Input.method == "onduty" ? "on-call" : Input.method;
    var date = Input.targetDate !== "" ? Input.targetDate : false;
    var range = (Input.range === 0 ? 1 : Input.range);
    var callback = this.ircHandleResult.bind(this);
    var name = Input.users.length > 0 ? Input.users[0].name : "";
    var next = Input.contains("options","next");

    this.getEventsByDate(keyword,date,range,callback,name,next);
};

GoogleCal.prototype.ircHandleResult = function(err,events){
    if (err){
        this.ircHandleError(err);
    }else{
        var l = events.length
        if (l < 1){
            this.setOne("output","Hm, I couldn't find anything for that. Sorry :(");
            this.ircOutputResult();
        }else{
            this.ircEventsFromResult(events);
        }
    }
};

GoogleCal.prototype.ircEventsFromResult = function(events){
    events.forEach(assembleLine.bind(this));

    function assembleLine(elem,ind,arr){
        if (ind < this.outputLimit){
            if (elem.start.date && elem.start.date !== moment(elem.end.date).subtract(1,"days").format("YYYY-MM-DD")){
                this.setOne("output","["+moment(elem.start.date).format("ddd MM/DD")+" to "+moment(elem.end.date).subtract(1,"days").format("ddd MM/DD")+" | "+elem.summary+"]");
            }else{
                this.setOne("output","["+moment(elem.start.dateTime ? elem.start.dateTime : elem.start.date).format("ddd MM/DD")+" | "+elem.summary+"]");
            }
        }
    }
        this.ircOutputResult();
};

GoogleCal.prototype.ircNamesFromResult = function(err,events){
    if (err){
        this.ircHandleError(err);
    }else{
        for (u in config.users){
            var user = config.users[u];
            if (events[0].summary.indexOf(user.name) > -1){
                this.ircCallback(user.name);
            }
        }
    }
};

GoogleCal.prototype.ircHandleError = function(err){
    console.log(err,"Google Calendar API Request Error");
    this.setOne("output","Bad Google API Response :(");
    this.ircOutputResult();
};

GoogleCal.prototype.ircOutputResult = function(){
    this.ircCallback(this.output);
    this.output = [];
};

//IRC Helper Methods

GoogleCal.prototype.setOutputLimit = function(Input){
    return Input.range > 0 ? Input.range : (Input.method === "ooo" && Input.users.length < 1 ? 99 : 1);
}

//API Methods

GoogleCal.prototype.getEventsByDate = function(keyword,date,range,callback,name,next){
    if (keyword === "on-call"){
        if (name){
            this.getOnDutyByName(date,range,name,next,callback);
        }else{
            this.getOnDuty(date,range,next,callback);
        }
    }else if (keyword === "ooo"){
        if (name){
            this.getOOOByName(date,range,name,next,callback);
        }else{
            this.getOOO(date,range,next,callback);
        }
    }else if (keyword === "wfh"){
        if (name){
            this.getWFHByName(date,range,name,next,callback);
        }else{
            this.getWFH(date,range,next,callback);
        }
    }
};

GoogleCal.prototype.getOnDuty = function(date,range,next,callback){
    var r = this.getDateRange(date,range,"day",next);
    var apiCallback = this.filterResults.bind(this,"on-call","",r.startDate,r.endDate,callback)
    this.getEventsByRange(r.startDate,r.endDate,apiCallback)
};

GoogleCal.prototype.getOOO = function(date,range,next,callback){
    var r = this.getDateRange(date,range,"day",next);
    var apiCallback = this.filterResults.bind(this,"ooo","",r.startDate,r.endDate,callback)
    this.getEventsByRange(r.startDate,r.endDate,apiCallback)
};

GoogleCal.prototype.getWFH = function(date,range,next,callback){
    var r = this.getDateRange(date,range,"day",next);
    var apiCallback = this.filterResults.bind(this,"wfh","",r.startDate,r.endDate,callback)
    this.getEventsByRange(r.startDate,r.endDate,apiCallback)
};

GoogleCal.prototype.getOnDutyByName = function(date,range,name,next,callback){
    var r = this.getDateRange(date,range,"month",next);
    var apiCallback = this.filterResults.bind(this,"on-call",name,r.startDate,r.endDate,callback)
    this.getEventsByRange(r.startDate,r.endDate,apiCallback)
};

GoogleCal.prototype.getOOOByName = function(date,range,name,next,callback){
    var r = this.getDateRange(date,range,"month",next);
    var apiCallback = this.filterResults.bind(this,"ooo",name,r.startDate,r.endDate,callback)
    this.getEventsByRange(r.startDate,r.endDate,apiCallback)
};

GoogleCal.prototype.isOOO = function(name,callback){
    this.getOOOTodayByName(name,callback);
};

GoogleCal.prototype.getOOOTodayByName = function(name,callback){
    var r = this.getDateRange("today",1,"day",false);
    var apiCallback = this.filterResults.bind(this,"ooo",name,r.startDate,r.endDate,callback)
    this.getEventsByRange(r.startDate,r.endDate,apiCallback)
};

GoogleCal.prototype.getWFHByName = function(date,range,name,next,callback){
    var r = this.getDateRange(date,range,"month",next);
    var apiCallback = this.filterResults.bind(this,"wfh",name,r.startDate,r.endDate,callback)
    this.getEventsByRange(r.startDate,r.endDate,apiCallback)
};

GoogleCal.prototype.getEventsByRange = function(startDate,endDate,apiCallback){
    this.query = {
        calendarId: this.account,
        auth: this.oauth2Client,
        timeMin: startDate,
        timeMax: endDate,
        orderBy: "startTime",
        singleEvents: true
    };
    this.apiCallback = apiCallback;
    this.calendarQuery(this.query,this.apiCallback);
};

GoogleCal.prototype.calendarQuery = function(query,apiCallback){
    calendar.events.list(query,apiCallback);
};

//API Helper Methods

GoogleCal.prototype.getDateRange = function(date,range,rangeUnit,next){
    var startDate =  moment().startOf("day").toISOString();
    var endDate = moment().endOf("day").toISOString();

    switch (date)
        {
        case "yesterday":
            startDate = this.changeDate("subtract",1,"days",startDate);
            break;
        case "today":
        case "tonight":
            break;
        case "tomorrow":
            startDate = this.changeDate("add",1,"days",startDate);
            break;
        default:
            if (moment(date,"MM/DD")._pf.charsLeftOver == 0){
                startDate = moment(date,"MM/DD").startOf("day").toISOString();
                //If Target Month is Before This Month, Advance to Next Year
                if (moment(startDate).isBefore(moment(),"month")){
                    startDate = moment(startDate).add(1,"year").toISOString();
                }
            }else if (moment(date,["MM/DD/YY","MM/DD/YYYY"])._pf.charsLeftOver == 0){
                startDate = moment(date,["MM/DD","MM/DD/YY","MM/DD/YYYY"]).startOf("day").toISOString();
            }else if (this.contains("dateWords",date)){
                startDate = this.toWeekday(date,next);
            }
            break;
        }
        endDate = moment(startDate).endOf(rangeUnit).add(range-1,rangeUnit).toISOString();

    return {"startDate":startDate,"endDate":endDate};
};

GoogleCal.prototype.changeDate = function(mode,amt,unit,target){
    return moment(target)[mode](amt,unit).toISOString();
};

GoogleCal.prototype.toWeekday = function(date,next){
    var weekday = moment().day(date).startOf("day").toISOString();
    var dayIsPast = moment(weekday).isBefore(moment(),"day");

    return (dayIsPast || !dayIsPast && next) ? moment(weekday).add(1,"week").toISOString() : weekday;
};

GoogleCal.prototype.filterResults = function(keyword,user,startDate,endDate,callback,error,results){
    if (error){
        if (error.code === 401){
            this.oauth2Client.refreshAccessToken(requeue.bind(this));
            function requeue(err,tokens){
                if (err){
                    callback(err);
                }else{
                    this.calendarQuery(this.query,this.apiCallback);
                }
            }
        }else{
            callback(error);
        }
    }else{
        var events = [];
        results.items.forEach(filterForKeyword);

        function filterForKeyword(elem,index,arr){
            if (elem.summary.toLowerCase().indexOf(keyword) > -1){
                events.push(elem);
            }
        }
        for (i = events.length - 1; i>=0; i--){
            var e = events[i];
            //If Getting Cases for a Specific User, Remove all Events Not for that User
            if (user !== "" && e.summary.indexOf(user) == -1){
                events.splice(events.indexOf(e),1);
            //Multi-Day Event Filtering Fix... Future Events Get Incorrectly Returned by API
            }else if (e.start.date && moment(e.start.date).isAfter(endDate)){
                events.splice(events.indexOf(e),1);
            }
        }
        callback(null,events);
    }
};
<|endoftext|>