<commit_before>/*
WHAT: SublimeText-like Fuzzy Search

USAGE:
  require('fuzzysort').single('fs', 'Fuzzy Search')
  // {score: 0.1, highlighted: 'Fuzzy Search'}

  require('fuzzysort').single('test', 'test')
  // {score: 0, highlighted}

  require('fuzzysort').single('doesnt exist', 'target')
  // {}
*/

;(function() {
  var fuzzysort = {

    noMatchLimit: 100, // if there's no match for a span this long, give up
    highlightMatches: true,
    highlightOpen: '',
    highlightClose: '',
    limit: null, // don't return more results than this

    single: (search, target) => {
      const lowerSearch = search.toLowerCase()
      const searchLength = lowerSearch.length
      const searchCode = lowerSearch.charCodeAt(0)
      const result = fuzzysort.info(lowerSearch, searchLength, searchCode, target)
      if(result === null) return null

      if(fuzzysort.highlightMatches) {
        result.highlighted = fuzzysort.highlight(result)
      }
      return result
    },

    go: (search, targets) => {
      if(search === '') {const a=[];a.total=0;return a}
      const lowerSearch = search.toLowerCase()
      const searchLength = lowerSearch.length
      const searchCode = lowerSearch.charCodeAt(0)
      var i = targets.length-1
      const results = []
      var resultsLen = 0
      for(; i>=0; i-=1) {
        const result = fuzzysort.info(lowerSearch, searchLength, searchCode, targets[i])
        if(result) results[resultsLen++] = result
      }

      const len = results.length
      results.sort(compareResults)
      // quickSortResults(results, 0, len)

      results.total = len
      if(fuzzysort.limit!==null && len > fuzzysort.limit) {
        results.length = fuzzysort.limit
      }
      if(fuzzysort.highlightMatches) {
        for (i = results.length - 1; i >= 0; i--) {
          const result = results[i]
          result.highlighted = fuzzysort.highlight(result)
        }
      }

      return results
    },

    goAsync: (search, targets) => {
      var canceled = false
      const p = new Promise((resolve, reject) => {
        if(search === '') {const a=[];a.total=0;return resolve(a)}
        var i = targets.length-1
        const results = []
        var resultsLen = 0
        const itemsPerCheck = 1000
        const lowerSearch = search.toLowerCase()
        const searchLength = lowerSearch.length
        const searchCode = lowerSearch.charCodeAt(0)
        function step() {
          if(canceled) return reject('canceled')

          const startMs = Date.now()

          for(; i>=0; i-=1) {
            const result = fuzzysort.info(lowerSearch, searchLength, searchCode, targets[i])
            if(result) results[resultsLen++] = result

            if(i%itemsPerCheck===0) {
              if(Date.now() - startMs >= 12) {
                ;(typeof setImmediate !== 'undefined')?setImmediate(step):setTimeout(step)
                return
              }
            }
          }

          const len = results.length
          results.sort(compareResults)
          // quickSortResults(results, 0, len)

          results.total = len
          if(fuzzysort.limit!==null && len > fuzzysort.limit) {
            results.length = fuzzysort.limit
          }
          if(fuzzysort.highlightMatches) {
            for (i = results.length - 1; i >= 0; i--) {
              const result = results[i]
              result.highlighted = fuzzysort.highlight(result)
            }
          }

          resolve(results)
        }

        if(typeof setImmediate !== 'undefined') {
          setImmediate(step)
        } else {
          step()
        }
        // step() // This speeds up the browser a lot. setTimeout is slow
        // // ;(typeof setImmediate !== 'undefined')?setImmediate(step):setTimeout(step)
      })
      p.cancel = () => {
        canceled = true
      }
      return p
    },

    info: (lowerSearch, searchLength, searchCode, target) => {
      var searchI = 0 // where we at
      var targetI = 0 // where you at

      var noMatchCount = 0 // how long since we've seen a match
      var matches // target indexes
      var matchesLen = 1

      const lowerTarget = target.toLowerCase()
      const targetLength = target.length
      var targetCode = lowerTarget.charCodeAt(0)

      // very basic fuzzy match; to remove targets with no match ASAP
      // walk through search and target. find sequential matches.
      // if all chars aren't found then exit
      while(true) {
        const isMatch = searchCode === targetCode

        if(isMatch) {
          if(matches === undefined) {
            matches = [targetI]
            // matchesLen = 1
          } else {
            matches[matchesLen++] = targetI
          }

          searchI += 1
          if(searchI === searchLength) break
          searchCode = lowerSearch.charCodeAt(searchI)
          noMatchCount = 0
        } else {
          noMatchCount += 1
          if(noMatchCount >= fuzzysort.noMatchLimit) return null
        }

        targetI += 1
        if(targetI === targetLength) return null
        targetCode = lowerTarget.charCodeAt(targetI)
      }

      // Let's try a more advanced and strict test to improve the score
      // only count it as a match if it's consecutive or a beginning character!
      // we use information about previous matches to skip around here and improve performance

      var strictSuccess = false
      var strictMatches
      var strictMatchesLen = 1

      var wasUpper = null
      var wasWord = false
      var isConsec = false

      searchI = 0
      noMatchCount = 0

      if(matches[0]>0) {
        // skip and backfill history
        targetI = matches[0]
        const targetCode = target.charCodeAt(targetI-1)
        wasUpper = targetCode>=65&&targetCode<=90
        wasWord = wasUpper || targetCode>=97&&targetCode<=122 || targetCode>=48&&targetCode<=57
      } else {
        targetI = 0
      }

      while(true) {

        if (targetI >= targetLength) {
          // We failed to find a good spot for the search char, go back to the previous search char and force it forward
          if (searchI <= 0) break
          searchI -= 1

          const lastMatch = strictMatches[--strictMatchesLen]
          targetI = lastMatch + 1

          isConsec = false
          // backfill history
          const targetCode = target.charCodeAt(targetI-1)
          wasUpper = targetCode>=65&&targetCode<=90
          wasWord = wasUpper || targetCode>=97&&targetCode<=122 || targetCode>=48&&targetCode<=57
          continue
        }

        const lowerTargetCode = lowerTarget.charCodeAt(targetI)
        if(!isConsec) {
          const targetCode = target.charCodeAt(targetI)
          const isUpper = targetCode>=65&&targetCode<=90
          const isWord = lowerTargetCode>=97&&lowerTargetCode<=122 || lowerTargetCode>=48&&lowerTargetCode<=57
          const isBeginning = isUpper && !wasUpper || !wasWord || !isWord
          wasUpper = isUpper
          wasWord = isWord
          if (!isBeginning) {
            targetI += 1
            continue
          }
        }

        const isMatch = lowerSearch.charCodeAt(searchI) === lowerTargetCode

        if(isMatch) {
          if(strictMatches === undefined) {
            strictMatches = [targetI]
            // strictMatchesLen = 1
          } else {
            strictMatches[strictMatchesLen++] = targetI
          }

          searchI += 1
          if(searchI === searchLength) {
            strictSuccess = true
            break
          }

          targetI += 1
          isConsec = true
          const wouldSkipAhead = matches[searchI] > targetI
          if(wouldSkipAhead) {
            const nextMatchIsNextTarget = matches[searchI] === targetI
            if(!nextMatchIsNextTarget) {
              // skip and backfill history
              targetI = matches[searchI]
              isConsec = false
              const targetCode = target.charCodeAt(targetI-1)
              wasUpper = targetCode>=65&&targetCode<=90
              wasWord = wasUpper || targetCode>=97&&targetCode<=122 || targetCode>=48&&targetCode<=57
            }
          }

          noMatchCount = 0
        } else {
          noMatchCount += 1
          if(noMatchCount >= fuzzysort.noMatchLimit) break
          isConsec = false
          targetI += 1
        }

      }

      const ret = {}

      // tally up the score & keep track of matches for highlighting later
      ret.score = 0
      var lastTargetI = -1
      const theMatches = strictSuccess ? strictMatches : matches
      for(const targetI of theMatches) {
        // score only goes up if they not consecutive
        if(lastTargetI !== targetI - 1) ret.score += targetI

        lastTargetI = targetI
      }
      if(!strictSuccess) ret.score *= 1000
      ret.score += targetLength - searchLength

      if(fuzzysort.highlightMatches) {
        ret.target = target
        ret.theMatches = strictSuccess ? strictMatches : matches
      }

      return ret
    },

    highlight: (result) => {
      var highlighted = ''
      var matchesIndex = 0
      var opened = false
      const target = result.target
      const targetLength = target.length
      const theMatches = result.theMatches
      for(var i=0; i<targetLength; i++) {
        if(theMatches[matchesIndex] === i) {
          matchesIndex += 1
          if(!opened) {
            highlighted += fuzzysort.highlightOpen
            opened = true
          }

          if(matchesIndex === theMatches.length) {
            highlighted += `${target[i]}${fuzzysort.highlightClose}${target.substr(i+1)}`
            break
          }
        } else {
          if(opened) {
            highlighted += fuzzysort.highlightClose
            opened = false
          }
        }
        highlighted += target[i]
      }

      return highlighted
    }
  }

  function quickSortPartition(results, left, right) {
    const cmp = results[right-1].score
    var minEnd = left
    var maxEnd = left
    for (; maxEnd < right-1; maxEnd += 1) {
      if (results[maxEnd].score <= cmp) {
        swap(results, maxEnd, minEnd)
        minEnd += 1
      }
    }
    swap(results, minEnd, right-1)
    return minEnd
  }

  function swap(results, i, j) {
    const temp = results[i]
    results[i] = results[j]
    results[j] = temp
  }

  function quickSortResults(results, left, right) {
    if (left < right) {
      var p = quickSortPartition(results, left, right)
      quickSortResults(results, left, p)
      quickSortResults(results, p + 1, right)
    }
  }

  function compareResults(a,b) {
    return a.score - b.score
  }

  // Export fuzzysort
    if(typeof module !== 'undefined' && module.exports) {
      module.exports = fuzzysort
    } else if(typeof window !== 'undefined') {
      window.fuzzysort = fuzzysort
    }
})()

<commit_msg>micro optimization<commit_after>/*
WHAT: SublimeText-like Fuzzy Search

USAGE:
  require('fuzzysort').single('fs', 'Fuzzy Search')
  // {score: 0.1, highlighted: 'Fuzzy Search'}

  require('fuzzysort').single('test', 'test')
  // {score: 0, highlighted}

  require('fuzzysort').single('doesnt exist', 'target')
  // {}
*/

;(function() {
  var fuzzysort = {

    noMatchLimit: 100, // if there's no match for a span this long, give up
    highlightMatches: true,
    highlightOpen: '',
    highlightClose: '',
    limit: null, // don't return more results than this

    single: (search, target) => {
      const lowerSearch = search.toLowerCase()
      const searchLength = lowerSearch.length
      const searchCode = lowerSearch.charCodeAt(0)
      const result = fuzzysort.info(lowerSearch, searchLength, searchCode, target)
      if(result === null) return null

      if(fuzzysort.highlightMatches) {
        result.highlighted = fuzzysort.highlight(result)
      }
      return result
    },

    go: (search, targets) => {
      if(search === '') {const a=[];a.total=0;return a}
      const lowerSearch = search.toLowerCase()
      const searchLength = lowerSearch.length
      const searchCode = lowerSearch.charCodeAt(0)
      var i = targets.length-1
      const results = []
      var resultsLen = 0
      for(; i>=0; i-=1) {
        const result = fuzzysort.info(lowerSearch, searchLength, searchCode, targets[i])
        if(result) results[resultsLen++] = result
      }

      results.sort(compareResults)
      // quickSortResults(results, 0, resultsLen)

      results.total = resultsLen
      if(fuzzysort.limit!==null && resultsLen > fuzzysort.limit) {
        results.length = fuzzysort.limit
      }
      if(fuzzysort.highlightMatches) {
        for (i = results.length - 1; i >= 0; i--) {
          const result = results[i]
          result.highlighted = fuzzysort.highlight(result)
        }
      }

      return results
    },

    goAsync: (search, targets) => {
      var canceled = false
      const p = new Promise((resolve, reject) => {
        if(search === '') {const a=[];a.total=0;return resolve(a)}
        var i = targets.length-1
        const results = []
        var resultsLen = 0
        const itemsPerCheck = 1000
        const lowerSearch = search.toLowerCase()
        const searchLength = lowerSearch.length
        const searchCode = lowerSearch.charCodeAt(0)
        function step() {
          if(canceled) return reject('canceled')

          const startMs = Date.now()

          for(; i>=0; i-=1) {
            const result = fuzzysort.info(lowerSearch, searchLength, searchCode, targets[i])
            if(result) results[resultsLen++] = result

            if(i%itemsPerCheck===0) {
              if(Date.now() - startMs >= 12) {
                ;(typeof setImmediate !== 'undefined')?setImmediate(step):setTimeout(step)
                return
              }
            }
          }

          results.sort(compareResults)
          // quickSortResults(results, 0, resultsLen)

          results.total = resultsLen
          if(fuzzysort.limit!==null && resultsLen > fuzzysort.limit) {
            results.length = fuzzysort.limit
          }
          if(fuzzysort.highlightMatches) {
            for (i = results.length - 1; i >= 0; i--) {
              const result = results[i]
              result.highlighted = fuzzysort.highlight(result)
            }
          }

          resolve(results)
        }

        if(typeof setImmediate !== 'undefined') {
          setImmediate(step)
        } else {
          step()
        }
        // step() // This speeds up the browser a lot. setTimeout is slow
        // // ;(typeof setImmediate !== 'undefined')?setImmediate(step):setTimeout(step)
      })
      p.cancel = () => {
        canceled = true
      }
      return p
    },

    info: (lowerSearch, searchLength, searchCode, target) => {
      var searchI = 0 // where we at
      var targetI = 0 // where you at

      var noMatchCount = 0 // how long since we've seen a match
      var matches // target indexes
      var matchesLen = 1

      const lowerTarget = target.toLowerCase()
      const targetLength = target.length
      var targetCode = lowerTarget.charCodeAt(0)

      // very basic fuzzy match; to remove targets with no match ASAP
      // walk through search and target. find sequential matches.
      // if all chars aren't found then exit
      while(true) {
        const isMatch = searchCode === targetCode

        if(isMatch) {
          if(matches === undefined) {
            matches = [targetI]
            // matchesLen = 1
          } else {
            matches[matchesLen++] = targetI
          }

          searchI += 1
          if(searchI === searchLength) break
          searchCode = lowerSearch.charCodeAt(searchI)
          noMatchCount = 0
        } else {
          noMatchCount += 1
          if(noMatchCount >= fuzzysort.noMatchLimit) return null
        }

        targetI += 1
        if(targetI === targetLength) return null
        targetCode = lowerTarget.charCodeAt(targetI)
      }

      // Let's try a more advanced and strict test to improve the score
      // only count it as a match if it's consecutive or a beginning character!
      // we use information about previous matches to skip around here and improve performance

      var strictSuccess = false
      var strictMatches
      var strictMatchesLen = 1

      var wasUpper = null
      var wasWord = false
      var isConsec = false

      searchI = 0
      noMatchCount = 0

      if(matches[0]>0) {
        // skip and backfill history
        targetI = matches[0]
        const targetCode = target.charCodeAt(targetI-1)
        wasUpper = targetCode>=65&&targetCode<=90
        wasWord = wasUpper || targetCode>=97&&targetCode<=122 || targetCode>=48&&targetCode<=57
      } else {
        targetI = 0
      }

      while(true) {

        if (targetI >= targetLength) {
          // We failed to find a good spot for the search char, go back to the previous search char and force it forward
          if (searchI <= 0) break
          searchI -= 1

          const lastMatch = strictMatches[--strictMatchesLen]
          targetI = lastMatch + 1

          isConsec = false
          // backfill history
          const targetCode = target.charCodeAt(targetI-1)
          wasUpper = targetCode>=65&&targetCode<=90
          wasWord = wasUpper || targetCode>=97&&targetCode<=122 || targetCode>=48&&targetCode<=57
          continue
        }

        const lowerTargetCode = lowerTarget.charCodeAt(targetI)
        if(!isConsec) {
          const targetCode = target.charCodeAt(targetI)
          const isUpper = targetCode>=65&&targetCode<=90
          const isWord = lowerTargetCode>=97&&lowerTargetCode<=122 || lowerTargetCode>=48&&lowerTargetCode<=57
          const isBeginning = isUpper && !wasUpper || !wasWord || !isWord
          wasUpper = isUpper
          wasWord = isWord
          if (!isBeginning) {
            targetI += 1
            continue
          }
        }

        const isMatch = lowerSearch.charCodeAt(searchI) === lowerTargetCode

        if(isMatch) {
          if(strictMatches === undefined) {
            strictMatches = [targetI]
            // strictMatchesLen = 1
          } else {
            strictMatches[strictMatchesLen++] = targetI
          }

          searchI += 1
          if(searchI === searchLength) {
            strictSuccess = true
            break
          }

          targetI += 1
          isConsec = true
          const wouldSkipAhead = matches[searchI] > targetI
          if(wouldSkipAhead) {
            const nextMatchIsNextTarget = matches[searchI] === targetI
            if(!nextMatchIsNextTarget) {
              // skip and backfill history
              targetI = matches[searchI]
              isConsec = false
              const targetCode = target.charCodeAt(targetI-1)
              wasUpper = targetCode>=65&&targetCode<=90
              wasWord = wasUpper || targetCode>=97&&targetCode<=122 || targetCode>=48&&targetCode<=57
            }
          }

          noMatchCount = 0
        } else {
          noMatchCount += 1
          if(noMatchCount >= fuzzysort.noMatchLimit) break
          isConsec = false
          targetI += 1
        }

      }

      const ret = {}

      // tally up the score & keep track of matches for highlighting later
      ret.score = 0
      var lastTargetI = -1
      const theMatches = strictSuccess ? strictMatches : matches
      for(const targetI of theMatches) {
        // score only goes up if they not consecutive
        if(lastTargetI !== targetI - 1) ret.score += targetI

        lastTargetI = targetI
      }
      if(!strictSuccess) ret.score *= 1000
      ret.score += targetLength - searchLength

      if(fuzzysort.highlightMatches) {
        ret.target = target
        ret.theMatches = strictSuccess ? strictMatches : matches
      }

      return ret
    },

    highlight: (result) => {
      var highlighted = ''
      var matchesIndex = 0
      var opened = false
      const target = result.target
      const targetLength = target.length
      const theMatches = result.theMatches
      for(var i=0; i<targetLength; i++) {
        if(theMatches[matchesIndex] === i) {
          matchesIndex += 1
          if(!opened) {
            highlighted += fuzzysort.highlightOpen
            opened = true
          }

          if(matchesIndex === theMatches.length) {
            highlighted += `${target[i]}${fuzzysort.highlightClose}${target.substr(i+1)}`
            break
          }
        } else {
          if(opened) {
            highlighted += fuzzysort.highlightClose
            opened = false
          }
        }
        highlighted += target[i]
      }

      return highlighted
    }
  }

  function quickSortPartition(results, left, right) {
    const cmp = results[right-1].score
    var minEnd = left
    var maxEnd = left
    for (; maxEnd < right-1; maxEnd += 1) {
      if (results[maxEnd].score <= cmp) {
        swap(results, maxEnd, minEnd)
        minEnd += 1
      }
    }
    swap(results, minEnd, right-1)
    return minEnd
  }

  function swap(results, i, j) {
    const temp = results[i]
    results[i] = results[j]
    results[j] = temp
  }

  function quickSortResults(results, left, right) {
    if (left < right) {
      var p = quickSortPartition(results, left, right)
      quickSortResults(results, left, p)
      quickSortResults(results, p + 1, right)
    }
  }

  function compareResults(a,b) {
    return a.score - b.score
  }

  // Export fuzzysort
    if(typeof module !== 'undefined' && module.exports) {
      module.exports = fuzzysort
    } else if(typeof window !== 'undefined') {
      window.fuzzysort = fuzzysort
    }
})()

<|endoftext|>


<commit_before>/**
 * @file log command
 * @author Sankarsan Kampa (a.k.a k3rn31p4nic)
 * @license MIT
 */

exports.exec = async (Bastion, message) => {
  try {
    let guildSettings = await Bastion.db.get(`SELECT log FROM guildSettings WHERE guildID=${message.guild.id}`);

    let color, logStats;
    if (guildSettings.log) {
      await Bastion.db.run(`UPDATE guildSettings SET log=null WHERE guildID=${message.guild.id}`);
      color = Bastion.colors.RED;
      logStats = Bastion.strings.info(message.guild.language, 'disableServerLog', message.author.tag);
    }
    else {
      await Bastion.db.run(`UPDATE guildSettings SET log=${message.channel.id} WHERE guildID=${message.guild.id}`);
      color = Bastion.colors.GREEN;
      logStats = Bastion.strings.info(message.guild.language, 'enableServerLog', message.author.tag);
    }

    message.channel.send({
      embed: {
        color: color,
        description: logStats
      }
    }).catch(e => {
      Bastion.log.error(e);
    });
  }
  catch (e) {
    Bastion.log.error(e);
  }
};

exports.config = {
  aliases: [],
  enabled: true
};

exports.help = {
  name: 'log',
  botPermission: '',
  userTextPermission: 'MANAGE_GUILD',
  userVoicePermission: '',
  usage: 'log',
  example: []
};
<commit_msg>Implemented new DB - log command<commit_after>/**
 * @file log command
 * @author Sankarsan Kampa (a.k.a k3rn31p4nic)
 * @license MIT
 */

exports.exec = async (Bastion, message) => {
  try {
    let guildModel = await Bastion.database.models.guild.findOne({
      attributes: [ 'serverLog' ],
      where: {
        guildID: message.guild.id
      }
    });

    let color, logStats;
    if (guildModel.dataValues.serverLog) {
      await Bastion.database.models.guild.update({
        serverLog: null
      },
      {
        where: {
          guildID: message.guild.id
        },
        fields: [ 'serverLog' ]
      });
      color = Bastion.colors.RED;
      logStats = Bastion.strings.info(message.guild.language, 'disableServerLog', message.author.tag);
    }
    else {
      await Bastion.database.models.guild.update({
        serverLog: message.channel.id
      },
      {
        where: {
          guildID: message.guild.id
        },
        fields: [ 'serverLog' ]
      });
      color = Bastion.colors.GREEN;
      logStats = Bastion.strings.info(message.guild.language, 'enableServerLog', message.author.tag);
    }

    message.channel.send({
      embed: {
        color: color,
        description: logStats
      }
    }).catch(e => {
      Bastion.log.error(e);
    });
  }
  catch (e) {
    Bastion.log.error(e);
  }
};

exports.config = {
  aliases: [],
  enabled: true
};

exports.help = {
  name: 'log',
  botPermission: '',
  userTextPermission: 'MANAGE_GUILD',
  userVoicePermission: '',
  usage: 'log',
  example: []
};
<|endoftext|>


<commit_before>var fs = require('fs'),
    request = require('request'),
    debug = require('debug')('http-downloader');
function HttpDownloader(infoLogFunction, debugLogFunction) {
  this._info = infoLogFunction || console.log;
  this._debug = debugLogFunction || function () { };
  this.assumeDownloadedIfExistsAndSizeMatches = true;
}

HttpDownloader.prototype = {
  download: function (url, target) {
    if (this._request) {
      throw new Error('Already downloading.');
    }
    this._errored = false;
    var result = this._createResultPromise();
    this._url = url;
    this._target = target;
    this._tempTarget = target + '.part';
    var self = this;
    this._info('Start download of "' + url + '"');
    this._request = request.get(this._url, { timeout: 30000 })
      .on('response', function (response) {
        self._response = response;
        self._handleResponse();
      })
      .on('error', function (e) {
        self._reject('Download failed: ' + (e || 'unknown error'));
      });
    return result;
  },
  abort: function () {
    if (this._request) {
      self._errored = true;
      this._request.abort();
      this._clear();
    }
  },
  _handleResponse: function () {
    this._downloadSize = parseInt(this._response.headers['content-length']);
    if (this._alreadyDownloaded()) {
      this._request.destroy();
      return this._resolve(this._target);
    }
    if (fs.existsSync(this._target)) {
      fs.unlinkSync(this._target);
    }
    this._statusSuffix = '% of ' + this._humanSize(this._downloadSize);
    this._bindOnResponsedata();
    this._bindOnResponseEnd();
    this._bindOnResponseError();
  },
  _bindOnResponsedata: function () {
    this._lastData = new Date();
    this._written = 0;
    var self = this;
    this._response.on('data', function (data) {
      self._lastData = new Date();
      self._errored = false;
      self._debug('writing ' + data.length + ' bytes to ' + self._tempTarget);
      fs.appendFileSync(self._tempTarget, data);
      self._updateStatus(data);
    });
  },
  _updateStatus: function (data) {
    this._written += data.length;
    var perc = Math.round((100 * this._written) / this._downloadSize);
    if (perc != this._lastPerc) {
      this._writeStatus(perc + this._statusSuffix);
      this._lastPerc = perc;
    }
  },
  _writeStatus: function (msg) {
    this._clearStatus();
    process.stdout.write(msg);
  },
  _bindOnResponseEnd: function () {
    var self = this;
    this._response.on('end', function () {
      if (self._errored) {
        return;
      }
      self._clearStatus();
      self._rename(self._tempTarget, self._target);
      self._clear();
    });
  },
  _rename: function (src, dst, attempts) {
    try {
      debug('attempt rename of temp file');
      fs.renameSync(src, dst)
      this._clearStatus();
      this._info('-> download complete!');
      this._resolve(dst)
    } catch (e) {
      debug('rename error:', e);
      if (attempts > 99) {
        this._reject(['Unable to rename "', src, '" to "', ds, '": ', e].join(''));
      } else {
        var self = this;
        setTimeout(function () {
          self._rename(src, dst, attempts++);
        }, 100);
      }
    }
  },
  _bindOnResponseError: function () {
    var self = this;
    this._response.on('error', function (err) {
      self._errored = true;
      self._handleDownloadError(err);
    });
  },
  _handleDownloadError: function (err) {
    this._reject([
      'Download of "',
      this._url,
      '" failed: \n',
      this._errorStringFor(err)
    ]);
  },
  _errorStringFor: function (err) {
    if (!err) {
      return 'Unknown error';
    }
    if (typeof (err.toString) === 'function') {
      return err.toString();
    }
    return '' + err;
  },
  _clearStatus: function () {
    process.stdout.write('\r               \r');
  },
  _humanSize: function (size) {
    var suffixes = ['b', 'kb', 'mb', 'tb', 'pb'];
    for (var i = 0; i < suffixes.length - 1; i++) {
      if (size < 1024) {
        return size.toFixed(2) + suffixes[i];
      }
      size /= 1024;
    }
    return size.toFixed(2) + suffixes[suffixes.length - 1];
  },
  _createResultPromise: function () {
    var self = this;
    return new Promise(function (resolve, reject) {
      self._resolveFunction = resolve;
      self._rejectFunction = reject;
    });
  },
  _resolve: function (data) {
    debug('resolving final promise!');
    this._resolveFunction(data);
  },
  _reject: function (data) {
    debug('rejecting final promise!');
    this._rejectFunction(data);
  },
  _clear: function () {
    var self = this;
    ['_request', '_response', '_downloadSize', '_lastPerc',
      '_resolveFunction', '_rejectFunction', '_lastData', '_statusSuffix'
    ].forEach(function (prop) {
      self[prop] = undefined;
    });
  },
  _alreadyDownloaded: function () {
    if (!this.assumeDownloadedIfExistsAndSizeMatches) {
      return false;
    }
    if (!fs.existsSync(this._target)) {
      return false;
    }
    var lstat = fs.lstatSync(this._target);
    return lstat.size === this._downloadSize;
  }
}

module.exports = HttpDownloader;
<commit_msg>feat: allow suppressing download progress via SUPPRESS_DOWNLOAD_PROGRESS environment variable<commit_after>var fs = require('fs'),
    request = require('request'),
    debug = require('debug')('http-downloader');
function HttpDownloader(infoLogFunction, debugLogFunction) {
  this._info = infoLogFunction || console.log;
  this._debug = debugLogFunction || function () { };
  this.assumeDownloadedIfExistsAndSizeMatches = true;
}

HttpDownloader.prototype = {
  download: function (url, target) {
    if (this._request) {
      throw new Error('Already downloading.');
    }
    this._errored = false;
    var result = this._createResultPromise();
    this._url = url;
    this._target = target;
    this._tempTarget = target + '.part';
    var self = this;
    this._info('Start download of "' + url + '"');
    this._request = request.get(this._url, { timeout: 30000 })
      .on('response', function (response) {
        self._response = response;
        self._handleResponse();
      })
      .on('error', function (e) {
        self._reject('Download failed: ' + (e || 'unknown error'));
      });
    return result;
  },
  abort: function () {
    if (this._request) {
      self._errored = true;
      this._request.abort();
      this._clear();
    }
  },
  _handleResponse: function () {
    this._downloadSize = parseInt(this._response.headers['content-length']);
    if (this._alreadyDownloaded()) {
      this._request.destroy();
      return this._resolve(this._target);
    }
    if (fs.existsSync(this._target)) {
      fs.unlinkSync(this._target);
    }
    this._statusSuffix = '% of ' + this._humanSize(this._downloadSize);
    this._bindOnResponsedata();
    this._bindOnResponseEnd();
    this._bindOnResponseError();
  },
  _bindOnResponsedata: function () {
    this._lastData = new Date();
    this._written = 0;
    var self = this;
    this._response.on('data', function (data) {
      self._lastData = new Date();
      self._errored = false;
      self._debug('writing ' + data.length + ' bytes to ' + self._tempTarget);
      fs.appendFileSync(self._tempTarget, data);
      self._updateStatus(data);
    });
  },
  _updateStatus: function (data) {
    if (process.env.SUPPRESS_DOWNLOAD_PROGRESS) {
      return;
    }
    this._written += data.length;
    var perc = Math.round((100 * this._written) / this._downloadSize);
    if (perc != this._lastPerc) {
      this._writeStatus(perc + this._statusSuffix);
      this._lastPerc = perc;
    }
  },
  _writeStatus: function (msg) {
    this._clearStatus();
    process.stdout.write(msg);
  },
  _bindOnResponseEnd: function () {
    var self = this;
    this._response.on('end', function () {
      if (self._errored) {
        return;
      }
      self._clearStatus();
      self._rename(self._tempTarget, self._target);
      self._clear();
    });
  },
  _rename: function (src, dst, attempts) {
    try {
      debug('attempt rename of temp file');
      fs.renameSync(src, dst)
      this._clearStatus();
      this._info('-> download complete!');
      this._resolve(dst)
    } catch (e) {
      debug('rename error:', e);
      if (attempts > 99) {
        this._reject(['Unable to rename "', src, '" to "', ds, '": ', e].join(''));
      } else {
        var self = this;
        setTimeout(function () {
          self._rename(src, dst, attempts++);
        }, 100);
      }
    }
  },
  _bindOnResponseError: function () {
    var self = this;
    this._response.on('error', function (err) {
      self._errored = true;
      self._handleDownloadError(err);
    });
  },
  _handleDownloadError: function (err) {
    this._reject([
      'Download of "',
      this._url,
      '" failed: \n',
      this._errorStringFor(err)
    ]);
  },
  _errorStringFor: function (err) {
    if (!err) {
      return 'Unknown error';
    }
    if (typeof (err.toString) === 'function') {
      return err.toString();
    }
    return '' + err;
  },
  _clearStatus: function () {
    process.stdout.write('\r               \r');
  },
  _humanSize: function (size) {
    var suffixes = ['b', 'kb', 'mb', 'tb', 'pb'];
    for (var i = 0; i < suffixes.length - 1; i++) {
      if (size < 1024) {
        return size.toFixed(2) + suffixes[i];
      }
      size /= 1024;
    }
    return size.toFixed(2) + suffixes[suffixes.length - 1];
  },
  _createResultPromise: function () {
    var self = this;
    return new Promise(function (resolve, reject) {
      self._resolveFunction = resolve;
      self._rejectFunction = reject;
    });
  },
  _resolve: function (data) {
    debug('resolving final promise!');
    this._resolveFunction(data);
  },
  _reject: function (data) {
    debug('rejecting final promise!');
    this._rejectFunction(data);
  },
  _clear: function () {
    var self = this;
    ['_request', '_response', '_downloadSize', '_lastPerc',
      '_resolveFunction', '_rejectFunction', '_lastData', '_statusSuffix'
    ].forEach(function (prop) {
      self[prop] = undefined;
    });
  },
  _alreadyDownloaded: function () {
    if (!this.assumeDownloadedIfExistsAndSizeMatches) {
      return false;
    }
    if (!fs.existsSync(this._target)) {
      return false;
    }
    var lstat = fs.lstatSync(this._target);
    return lstat.size === this._downloadSize;
  }
}

module.exports = HttpDownloader;
<|endoftext|>


<commit_before>/* global jest:false, test:false, expect:false, describe:false */

jest.mock('tus-js-client')
jest.mock('purest')
jest.mock('../../src/server/helpers/oauth-state', () => {
  return {
    generateState: () => 'some-cool-nice-encrytpion',
    addToState: () => 'some-cool-nice-encrytpion',
    getFromState: (state, key) => {
      if (state === 'state-with-invalid-instance-url') {
        return 'http://localhost:3452'
      }

      if (state === 'state-with-older-version' && key === 'clientVersion') {
        return '@uppy/companion-client=1.0.1'
      }

      if (state === 'state-with-newer-version' && key === 'clientVersion') {
        return '@uppy/companion-client=1.0.3'
      }

      if (state === 'state-with-newer-version-old-style' && key === 'clientVersion') {
        return 'companion-client:1.0.2'
      }

      return 'http://localhost:3020'
    }
  }
})

const request = require('supertest')
const tokenService = require('../../src/server/helpers/jwt')
const { authServer } = require('../mockserver')
const authData = {
  dropbox: 'token value',
  drive: 'token value'
}
const token = tokenService.generateToken(authData, process.env.COMPANION_SECRET)
const OAUTH_STATE = 'some-cool-nice-encrytpion'

describe('set i-am header', () => {
  test('set i-am header in response', () => {
    return request(authServer)
      .get('/dropbox/list/')
      .set('uppy-auth-token', token)
      .expect(200)
      .then((res) => expect(res.header['i-am']).toBe('http://localhost:3020'))
  })
})

describe('list provider files', () => {
  test('list files for dropbox', () => {
    return request(authServer)
      .get('/dropbox/list/')
      .set('uppy-auth-token', token)
      .expect(200)
      .then((res) => expect(res.body.username).toBe('foo@bar.com'))
  })

  test('list files for google drive', () => {
    return request(authServer)
      .get('/drive/list/')
      .set('uppy-auth-token', token)
      .expect(200)
      .then((res) => expect(res.body.username).toBe('ife@bala.com'))
  })
})

describe('validate upload data', () => {
  test('invalid upload protocol gets rejected', () => {
    return request(authServer)
      .post('/drive/get/README.md')
      .set('uppy-auth-token', token)
      .set('Content-Type', 'application/json')
      .send({
        endpoint: 'http://master.tus.io/files',
        protocol: 'tusInvalid'
      })
      .expect(400)
      .then((res) => expect(res.body.error).toBe('unsupported protocol specified'))
  })

  test('invalid upload fieldname gets rejected', () => {
    return request(authServer)
      .post('/drive/get/README.md')
      .set('uppy-auth-token', token)
      .set('Content-Type', 'application/json')
      .send({
        endpoint: 'http://master.tus.io/files',
        protocol: 'tus',
        fieldname: 390
      })
      .expect(400)
      .then((res) => expect(res.body.error).toBe('fieldname must be a string'))
  })

  test('invalid upload metadata gets rejected', () => {
    return request(authServer)
      .post('/drive/get/README.md')
      .set('uppy-auth-token', token)
      .set('Content-Type', 'application/json')
      .send({
        endpoint: 'http://master.tus.io/files',
        protocol: 'tus',
        metadata: 'I am a string instead of object'
      })
      .expect(400)
      .then((res) => expect(res.body.error).toBe('metadata must be an object'))
  })

  test('invalid upload headers get rejected', () => {
    return request(authServer)
      .post('/drive/get/README.md')
      .set('uppy-auth-token', token)
      .set('Content-Type', 'application/json')
      .send({
        endpoint: 'http://master.tus.io/files',
        protocol: 'tus',
        headers: 'I am a string instead of object'
      })
      .expect(400)
      .then((res) => expect(res.body.error).toBe('headers must be an object'))
  })

  test('invalid upload HTTP Method gets rejected', () => {
    return request(authServer)
      .post('/drive/get/README.md')
      .set('uppy-auth-token', token)
      .set('Content-Type', 'application/json')
      .send({
        endpoint: 'http://master.tus.io/files',
        protocol: 'tus',
        httpMethod: 'DELETE'
      })
      .expect(400)
      .then((res) => expect(res.body.error).toBe('unsupported HTTP METHOD specified'))
  })

  test('valid upload data is allowed - tus', () => {
    return request(authServer)
      .post('/drive/get/README.md')
      .set('uppy-auth-token', token)
      .set('Content-Type', 'application/json')
      .send({
        endpoint: 'http://master.tus.io/files',
        protocol: 'tus',
        httpMethod: 'POST',
        headers: {
          customheader: 'header value'
        },
        metadata: {
          mymetadata: 'matadata value'
        },
        fieldname: 'uploadField'
      })
      .expect(200)
  })

  test('valid upload data is allowed - s3-multipart', () => {
    return request(authServer)
      .post('/drive/get/README.md')
      .set('uppy-auth-token', token)
      .set('Content-Type', 'application/json')
      .send({
        endpoint: 'http://master.tus.io/files',
        protocol: 's3-multipart',
        httpMethod: 'PUT',
        headers: {
          customheader: 'header value'
        },
        metadata: {
          mymetadata: 'matadata value'
        },
        fieldname: 'uploadField'
      })
      .expect(200)
  })
})

describe('download provdier file', () => {
  test('specified file gets downloaded from provider', () => {
    return request(authServer)
      .post('/drive/get/README.md')
      .set('uppy-auth-token', token)
      .set('Content-Type', 'application/json')
      .send({
        endpoint: 'http://master.tus.io/files',
        protocol: 'tus'
      })
      .expect(200)
      .then((res) => expect(res.body.token).toBeTruthy())
  })
})

describe('test authentication', () => {
  test('authentication callback redirects to send-token url', () => {
    return request(authServer)
      .get('/drive/callback')
      .expect(302)
      .expect((res) => {
        expect(res.header.location).toContain('http://localhost:3020/drive/send-token?uppyAuthToken=')
      })
  })

  test('the token gets sent via cookie and html', () => {
    // see mock ../../src/server/helpers/oauth-state above for state values
    return request(authServer)
      .get(`/dropbox/send-token?uppyAuthToken=${token}&state=state-with-newer-version`)
      .expect(200)
      .expect((res) => {
        const authToken = res.header['set-cookie'][0].split(';')[0].split('uppyAuthToken--dropbox=')[1]
        expect(authToken).toEqual(token)
        const body = `
    <!DOCTYPE html>

        <meta charset="utf-8" />

    `
        expect(res.text).toBe(body)
      })
  })

  test('the token gets to older clients without stringify', () => {
    // see mock ../../src/server/helpers/oauth-state above for state values
    return request(authServer)
      .get(`/drive/send-token?uppyAuthToken=${token}&state=state-with-older-version`)
      .expect(200)
      .expect((res) => {
        const body = `
    <!DOCTYPE html>

        <meta charset="utf-8" />

    `
        expect(res.text).toBe(body)
      })
  })

  test('the token gets sent to newer clients with old version style', () => {
    // see mock ../../src/server/helpers/oauth-state above for state values
    return request(authServer)
      .get(`/drive/send-token?uppyAuthToken=${token}&state=state-with-newer-version-old-style`)
      .expect(200)
      .expect((res) => {
        const body = `
    <!DOCTYPE html>

        <meta charset="utf-8" />

    `
        expect(res.text).toBe(body)
      })
  })

  test('logout provider', () => {
    return request(authServer)
      .get('/drive/logout/')
      .set('uppy-auth-token', token)
      .expect(200)
      .then((res) => expect(res.body.ok).toBe(true))
  })
})

describe('connect to provider', () => {
  test('connect to dropbox via grant.js endpoint', () => {
    return request(authServer)
      .get('/dropbox/connect?foo=bar')
      .set('uppy-auth-token', token)
      .expect(302)
      .expect('Location', `http://localhost:3020/connect/dropbox?state=${OAUTH_STATE}`)
  })

  test('connect to drive via grant.js endpoint', () => {
    return request(authServer)
      .get('/drive/connect?foo=bar')
      .set('uppy-auth-token', token)
      .expect(302)
      .expect('Location', `http://localhost:3020/connect/google?state=${OAUTH_STATE}`)
  })
})

describe('handle oauth redirect', () => {
  test('redirect to a valid uppy instance', () => {
    return request(authServer)
      .get(`/dropbox/redirect?state=${OAUTH_STATE}`)
      .set('uppy-auth-token', token)
      .expect(302)
      .expect('Location', `http://localhost:3020/connect/dropbox/callback?state=${OAUTH_STATE}`)
  })

  test('do not redirect to invalid uppy instances', () => {
    const state = 'state-with-invalid-instance-url' // see mock ../../src/server/helpers/oauth-state above
    return request(authServer)
      .get(`/dropbox/redirect?state=${state}`)
      .set('uppy-auth-token', token)
      .expect(400)
  })
})
<commit_msg>test: use random urls to avoid confusion<commit_after>/* global jest:false, test:false, expect:false, describe:false */

jest.mock('tus-js-client')
jest.mock('purest')
jest.mock('../../src/server/helpers/oauth-state', () => {
  return {
    generateState: () => 'some-cool-nice-encrytpion',
    addToState: () => 'some-cool-nice-encrytpion',
    getFromState: (state, key) => {
      if (state === 'state-with-invalid-instance-url') {
        return 'http://localhost:3452'
      }

      if (state === 'state-with-older-version' && key === 'clientVersion') {
        return '@uppy/companion-client=1.0.1'
      }

      if (state === 'state-with-newer-version' && key === 'clientVersion') {
        return '@uppy/companion-client=1.0.3'
      }

      if (state === 'state-with-newer-version-old-style' && key === 'clientVersion') {
        return 'companion-client:1.0.2'
      }

      return 'http://localhost:3020'
    }
  }
})

const request = require('supertest')
const tokenService = require('../../src/server/helpers/jwt')
const { authServer } = require('../mockserver')
const authData = {
  dropbox: 'token value',
  drive: 'token value'
}
const token = tokenService.generateToken(authData, process.env.COMPANION_SECRET)
const OAUTH_STATE = 'some-cool-nice-encrytpion'

describe('set i-am header', () => {
  test('set i-am header in response', () => {
    return request(authServer)
      .get('/dropbox/list/')
      .set('uppy-auth-token', token)
      .expect(200)
      .then((res) => expect(res.header['i-am']).toBe('http://localhost:3020'))
  })
})

describe('list provider files', () => {
  test('list files for dropbox', () => {
    return request(authServer)
      .get('/dropbox/list/')
      .set('uppy-auth-token', token)
      .expect(200)
      .then((res) => expect(res.body.username).toBe('foo@bar.com'))
  })

  test('list files for google drive', () => {
    return request(authServer)
      .get('/drive/list/')
      .set('uppy-auth-token', token)
      .expect(200)
      .then((res) => expect(res.body.username).toBe('ife@bala.com'))
  })
})

describe('validate upload data', () => {
  test('invalid upload protocol gets rejected', () => {
    return request(authServer)
      .post('/drive/get/README.md')
      .set('uppy-auth-token', token)
      .set('Content-Type', 'application/json')
      .send({
        endpoint: 'http://url.myendpoint.com/files',
        protocol: 'tusInvalid'
      })
      .expect(400)
      .then((res) => expect(res.body.error).toBe('unsupported protocol specified'))
  })

  test('invalid upload fieldname gets rejected', () => {
    return request(authServer)
      .post('/drive/get/README.md')
      .set('uppy-auth-token', token)
      .set('Content-Type', 'application/json')
      .send({
        endpoint: 'http://url.myendpoint.com/files',
        protocol: 'tus',
        fieldname: 390
      })
      .expect(400)
      .then((res) => expect(res.body.error).toBe('fieldname must be a string'))
  })

  test('invalid upload metadata gets rejected', () => {
    return request(authServer)
      .post('/drive/get/README.md')
      .set('uppy-auth-token', token)
      .set('Content-Type', 'application/json')
      .send({
        endpoint: 'http://url.myendpoint.com/files',
        protocol: 'tus',
        metadata: 'I am a string instead of object'
      })
      .expect(400)
      .then((res) => expect(res.body.error).toBe('metadata must be an object'))
  })

  test('invalid upload headers get rejected', () => {
    return request(authServer)
      .post('/drive/get/README.md')
      .set('uppy-auth-token', token)
      .set('Content-Type', 'application/json')
      .send({
        endpoint: 'http://url.myendpoint.com/files',
        protocol: 'tus',
        headers: 'I am a string instead of object'
      })
      .expect(400)
      .then((res) => expect(res.body.error).toBe('headers must be an object'))
  })

  test('invalid upload HTTP Method gets rejected', () => {
    return request(authServer)
      .post('/drive/get/README.md')
      .set('uppy-auth-token', token)
      .set('Content-Type', 'application/json')
      .send({
        endpoint: 'http://url.myendpoint.com/files',
        protocol: 'tus',
        httpMethod: 'DELETE'
      })
      .expect(400)
      .then((res) => expect(res.body.error).toBe('unsupported HTTP METHOD specified'))
  })

  test('valid upload data is allowed - tus', () => {
    return request(authServer)
      .post('/drive/get/README.md')
      .set('uppy-auth-token', token)
      .set('Content-Type', 'application/json')
      .send({
        endpoint: 'http://url.myendpoint.com/files',
        protocol: 'tus',
        httpMethod: 'POST',
        headers: {
          customheader: 'header value'
        },
        metadata: {
          mymetadata: 'matadata value'
        },
        fieldname: 'uploadField'
      })
      .expect(200)
  })

  test('valid upload data is allowed - s3-multipart', () => {
    return request(authServer)
      .post('/drive/get/README.md')
      .set('uppy-auth-token', token)
      .set('Content-Type', 'application/json')
      .send({
        endpoint: 'http://url.myendpoint.com/files',
        protocol: 's3-multipart',
        httpMethod: 'PUT',
        headers: {
          customheader: 'header value'
        },
        metadata: {
          mymetadata: 'matadata value'
        },
        fieldname: 'uploadField'
      })
      .expect(200)
  })
})

describe('download provdier file', () => {
  test('specified file gets downloaded from provider', () => {
    return request(authServer)
      .post('/drive/get/README.md')
      .set('uppy-auth-token', token)
      .set('Content-Type', 'application/json')
      .send({
        endpoint: 'http://master.tus.io/files',
        protocol: 'tus'
      })
      .expect(200)
      .then((res) => expect(res.body.token).toBeTruthy())
  })
})

describe('test authentication', () => {
  test('authentication callback redirects to send-token url', () => {
    return request(authServer)
      .get('/drive/callback')
      .expect(302)
      .expect((res) => {
        expect(res.header.location).toContain('http://localhost:3020/drive/send-token?uppyAuthToken=')
      })
  })

  test('the token gets sent via cookie and html', () => {
    // see mock ../../src/server/helpers/oauth-state above for state values
    return request(authServer)
      .get(`/dropbox/send-token?uppyAuthToken=${token}&state=state-with-newer-version`)
      .expect(200)
      .expect((res) => {
        const authToken = res.header['set-cookie'][0].split(';')[0].split('uppyAuthToken--dropbox=')[1]
        expect(authToken).toEqual(token)
        const body = `
    <!DOCTYPE html>

        <meta charset="utf-8" />

    `
        expect(res.text).toBe(body)
      })
  })

  test('the token gets to older clients without stringify', () => {
    // see mock ../../src/server/helpers/oauth-state above for state values
    return request(authServer)
      .get(`/drive/send-token?uppyAuthToken=${token}&state=state-with-older-version`)
      .expect(200)
      .expect((res) => {
        const body = `
    <!DOCTYPE html>

        <meta charset="utf-8" />

    `
        expect(res.text).toBe(body)
      })
  })

  test('the token gets sent to newer clients with old version style', () => {
    // see mock ../../src/server/helpers/oauth-state above for state values
    return request(authServer)
      .get(`/drive/send-token?uppyAuthToken=${token}&state=state-with-newer-version-old-style`)
      .expect(200)
      .expect((res) => {
        const body = `
    <!DOCTYPE html>

        <meta charset="utf-8" />

    `
        expect(res.text).toBe(body)
      })
  })

  test('logout provider', () => {
    return request(authServer)
      .get('/drive/logout/')
      .set('uppy-auth-token', token)
      .expect(200)
      .then((res) => expect(res.body.ok).toBe(true))
  })
})

describe('connect to provider', () => {
  test('connect to dropbox via grant.js endpoint', () => {
    return request(authServer)
      .get('/dropbox/connect?foo=bar')
      .set('uppy-auth-token', token)
      .expect(302)
      .expect('Location', `http://localhost:3020/connect/dropbox?state=${OAUTH_STATE}`)
  })

  test('connect to drive via grant.js endpoint', () => {
    return request(authServer)
      .get('/drive/connect?foo=bar')
      .set('uppy-auth-token', token)
      .expect(302)
      .expect('Location', `http://localhost:3020/connect/google?state=${OAUTH_STATE}`)
  })
})

describe('handle oauth redirect', () => {
  test('redirect to a valid uppy instance', () => {
    return request(authServer)
      .get(`/dropbox/redirect?state=${OAUTH_STATE}`)
      .set('uppy-auth-token', token)
      .expect(302)
      .expect('Location', `http://localhost:3020/connect/dropbox/callback?state=${OAUTH_STATE}`)
  })

  test('do not redirect to invalid uppy instances', () => {
    const state = 'state-with-invalid-instance-url' // see mock ../../src/server/helpers/oauth-state above
    return request(authServer)
      .get(`/dropbox/redirect?state=${state}`)
      .set('uppy-auth-token', token)
      .expect(400)
  })
})
<|endoftext|>


<commit_before>var Profile = function() {
	//Constructor
};

Profile.prototype = {
	https: require('https'),
	api_key: global.config.get('hackthis_api'),
	handle: function(from, chan, message) {
		var irc = global.irc;

		var matches;
		if (matches = message.match(/^!([\S]*)( (.*))?$/i)) {
			if (matches[1] === "profile") {
				var user = matches[2] || from;
				user = user.trim();

				var req = this.https.request('https://api.hackthis.co.uk/?api_key='+this.api_key+'&method=user.getInfo&user='+user, function(res) {
					res.on('data', function(d) {
						var obj = {};
						// Get the result and turn it into a JSON object.
						try {
							obj = JSON.parse(d);
						} catch (e) {
							console.log("\033[33m[HackThis API]\033[0m " + e);
						}
						if (obj.data) {
							// Return the string.
							var result = obj.data.user + " | Score: " + obj.data.score + " | Posts: " + obj.data.posts + " | Consecutive: " + obj.data.consecutive;
							irc.client.say(chan, result);
						} else {
							irc.client.say(chan, "User not found");
						}
					});
				});
				req.end();

				req.on('error', function(e) {
					irc.client.say(chan, "Errm there's be an error");
				});
			}
		}
	}
};

module.exports = new Profile();
<commit_msg>Fixed profiles to take advantage of WeChall API<commit_after>var Profile = function() {
	//Constructor
};

Profile.prototype = {
	https: require('https'),
	api_key: global.config.get('hackthis_api'),
	handle: function(from, chan, message) {
		var irc = global.irc;

		var matches;
		if (matches = message.match(/^!([\S]*)( (.*))?$/i)) {
			if (matches[1] === "profile") {
				var user = matches[2] || from;
				user = user.trim();
				var self = this;

				var req = this.https.request('https://www.hackthis.co.uk/wechall/userscore.php?authkey='+this.api_key+'&username='+user, function(res) {
					res.setEncoding('utf8');
					var body = '';
					res.on('data', function(chunk) {
						body += chunk;
					});

					res.on('end', function(){
						if (body != 0) {
							data = body.split(":");
							// Return the string.
							var result = data[0] + " | Rank: " + data[1] + " | Score: " + self.addCommas(data[2]) + " | Levels: " + data[4] + '/' + data[5];
							irc.client.say(chan, result);
						} else {
							irc.client.say(chan, "User not found");
						}
					});
				});
				req.end();

				req.on('error', function(e) {
					irc.client.say(chan, "Errm there's be an error");
				});
			}
		}
	},
	addCommas: function(nStr) {
	    nStr += '';
	    x = nStr.split('.');
	    x1 = x[0];
	    x2 = x.length > 1 ? '.' + x[1] : '';
	    var rgx = /(\d+)(\d{3})/;
	    while (rgx.test(x1)) {
	            x1 = x1.replace(rgx, '$1' + ',' + '$2');
	    }
	    return x1 + x2;
	}
};

module.exports = new Profile();
<|endoftext|>


<commit_before>import {
  parseListAccess,
  parseFieldAccess,
  validateListAccessControl,
  validateFieldAccessControl,
} from '../lib/access-control.js';
describe('Access control package tests', () => {
  test('parseListAccess', () => {
    const statics = [true, false]; // type StaticAccess = boolean;
    const imperatives = [() => true, () => false]; // type ImperativeAccess = AccessInput => boolean;
    const where = { name: 'foo' }; // GraphQLWhere
    const whereFn = () => where; // (AccessInput => GraphQLWhere)
    const declaratives = [where, whereFn]; // type DeclarativeAccess = GraphQLWhere | (AccessInput => GraphQLWhere);

    // StaticAccess | ImperativeAccess are valid defaults
    [...statics, ...imperatives].forEach(defaultAccess => {
      expect(parseListAccess({ defaultAccess })).toEqual({
        create: defaultAccess,
        read: defaultAccess,
        update: defaultAccess,
        delete: defaultAccess,
      });
    });

    // Non-function declaratives and other misc values are not value inputs for defaultAccess
    [{ read: where }, 10].forEach(defaultAccess => {
      expect(() => parseListAccess({ defaultAccess })).toThrow(Error);
    });

    // StaticAccess | ImperativeAccess are valid access modes, and should override the defaults
    [...statics, ...imperatives].forEach(defaultAccess => {
      [...statics, ...imperatives].forEach(access => {
        expect(parseListAccess({ defaultAccess, access })).toEqual({
          create: access,
          read: access,
          update: access,
          delete: access,
        });
      });
    });

    // StaticAccess | ImperativeAccess | DeclarativeAccess are valid per-operation access modes
    [...statics, ...imperatives].forEach(defaultAccess => {
      // NOTE: create is handled differently below
      ['read', 'update', 'delete'].forEach(operation => {
        [...statics, ...imperatives, ...declaratives].forEach(opAccess => {
          const access = { [operation]: opAccess };
          expect(parseListAccess({ defaultAccess, access })).toEqual({
            create: defaultAccess,
            read: defaultAccess,
            update: defaultAccess,
            delete: defaultAccess,
            // Override the specific operation we are trying
            ...{ [operation]: opAccess },
          });
        });
      });

      // Misc values are not valid per-operation access modes
      expect(() => parseListAccess({ defaultAccess, access: { read: 10 } })).toThrow(Error);
    });

    // StaticAccess | ImperativeAccess are valid per-operation access modes (create)
    [...statics, ...imperatives].forEach(defaultAccess => {
      [...statics, ...imperatives].forEach(opAccess => {
        const access = { create: opAccess };
        expect(parseListAccess({ defaultAccess, access })).toEqual({
          create: opAccess,
          read: defaultAccess,
          update: defaultAccess,
          delete: defaultAccess,
        });
      });

      // DeclarativeAccess | Misc values are not valid per-operation access modes (create)
      [where, 10].forEach(opAccess => {
        expect(() => parseListAccess({ defaultAccess, access: { create: opAccess } })).toThrow(
          Error
        );
      });
    });

    // access as an object with bad fields or bad type
    expect(() => parseListAccess({ access: { a: 1 } })).toThrow(Error);
    expect(() => parseListAccess({ access: 10 })).toThrow(Error);
  });

  test('parseFieldAccess', () => {
    const statics = [true, false]; // type StaticAccess = boolean;
    const imperatives = [() => true, () => false]; // type ImperativeAccess = AccessInput => boolean;

    // StaticAccess | ImperativeAccess are valid defaults
    [...statics, ...imperatives].forEach(defaultAccess => {
      expect(parseFieldAccess({ defaultAccess })).toEqual({
        create: defaultAccess,
        read: defaultAccess,
        update: defaultAccess,
      });
    });

    // Objects and other misc values are not value inputs for defaultAccess
    [{ a: 1 }, 10].forEach(defaultAccess => {
      expect(() => parseListAccess({ defaultAccess })).toThrow(Error);
    });

    // StaticAccess | ImperativeAccess are valid access modes, and should override the defaults
    [...statics, ...imperatives].forEach(defaultAccess => {
      [...statics, ...imperatives].forEach(access => {
        expect(parseFieldAccess({ defaultAccess, access })).toEqual({
          create: access,
          read: access,
          update: access,
        });
      });
    });

    // StaticAccess | ImperativeAccess are valid per-operation access modes
    [...statics, ...imperatives].forEach(defaultAccess => {
      ['create', 'read', 'update'].forEach(operation => {
        [...statics, ...imperatives].forEach(opAccess => {
          const access = { [operation]: opAccess };
          expect(parseFieldAccess({ defaultAccess, access })).toEqual({
            create: defaultAccess,
            read: defaultAccess,
            update: defaultAccess,
            // Override the specific operation we are trying
            ...{ [operation]: opAccess },
          });
        });

        // Misc values are not valid per-operation access modes
        expect(() => parseFieldAccess({ defaultAccess, access: { [operation]: 10 } })).toThrow(
          Error
        );
      });
    });

    expect(() => parseFieldAccess({ access: { a: 1 } })).toThrow(Error);
    expect(() => parseFieldAccess({ access: 10 })).toThrow(Error);
  });

  test('validateListAccessControl', () => {
    let operation = 'read';
    const access = { [operation]: true };

    // Test the static case: returning a boolean
    expect(validateListAccessControl({ access: { [operation]: true }, operation })).toBe(true);
    expect(validateListAccessControl({ access: { [operation]: false }, operation })).toBe(false);
    expect(() => validateListAccessControl({ access: { [operation]: 10 }, operation })).toThrow(
      Error
    );

    [{}, { item: {} }].forEach(authentication => {
      operation = 'read';

      // Boolean function
      access[operation] = () => true;
      expect(
        validateListAccessControl({
          access: { [operation]: () => true },
          operation,
          authentication,
        })
      ).toBe(true);
      expect(
        validateListAccessControl({
          access: { [operation]: () => false },
          operation,
          authentication,
        })
      ).toBe(false);
      // Object function
      expect(
        validateListAccessControl({
          access: { [operation]: () => ({ a: 1 }) },
          operation,
          authentication,
        })
      ).toEqual({ a: 1 });

      // Object function with create operation
      operation = 'create';
      expect(() =>
        validateListAccessControl({
          access: { [operation]: () => ({ a: 1 }) },
          operation,
          authentication,
        })
      ).toThrow(Error);

      // Number function
      expect(() =>
        validateListAccessControl({ access: { [operation]: () => 10 }, operation, authentication })
      ).toThrow(Error);
    });
  });

  test('validateFieldAccessControl', () => {
    const operation = 'read';
    // Test the StaticAccess case: returning a boolean
    expect(validateFieldAccessControl({ access: { [operation]: true }, operation })).toBe(true);
    expect(validateFieldAccessControl({ access: { [operation]: false }, operation })).toBe(false);
    expect(() => validateFieldAccessControl({ access: { [operation]: 10 }, operation })).toThrow(
      Error
    );

    [{}, { item: {} }].forEach(authentication => {
      // Test the ImperativeAccess case: a function which should return boolean
      expect(
        validateFieldAccessControl({
          access: { [operation]: () => true },
          operation,
          authentication,
        })
      ).toBe(true);

      expect(
        validateFieldAccessControl({
          access: { [operation]: () => false },
          operation,
          authentication,
        })
      ).toBe(false);

      expect(() =>
        validateFieldAccessControl({ access: { [operation]: () => 10 }, operation, authentication })
      ).toThrow(Error);
    });
  });
});
<commit_msg>Import from the package index.js<commit_after>import {
  parseListAccess,
  parseFieldAccess,
  validateListAccessControl,
  validateFieldAccessControl,
} from '../';
describe('Access control package tests', () => {
  test('parseListAccess', () => {
    const statics = [true, false]; // type StaticAccess = boolean;
    const imperatives = [() => true, () => false]; // type ImperativeAccess = AccessInput => boolean;
    const where = { name: 'foo' }; // GraphQLWhere
    const whereFn = () => where; // (AccessInput => GraphQLWhere)
    const declaratives = [where, whereFn]; // type DeclarativeAccess = GraphQLWhere | (AccessInput => GraphQLWhere);

    // StaticAccess | ImperativeAccess are valid defaults
    [...statics, ...imperatives].forEach(defaultAccess => {
      expect(parseListAccess({ defaultAccess })).toEqual({
        create: defaultAccess,
        read: defaultAccess,
        update: defaultAccess,
        delete: defaultAccess,
      });
    });

    // Non-function declaratives and other misc values are not value inputs for defaultAccess
    [{ read: where }, 10].forEach(defaultAccess => {
      expect(() => parseListAccess({ defaultAccess })).toThrow(Error);
    });

    // StaticAccess | ImperativeAccess are valid access modes, and should override the defaults
    [...statics, ...imperatives].forEach(defaultAccess => {
      [...statics, ...imperatives].forEach(access => {
        expect(parseListAccess({ defaultAccess, access })).toEqual({
          create: access,
          read: access,
          update: access,
          delete: access,
        });
      });
    });

    // StaticAccess | ImperativeAccess | DeclarativeAccess are valid per-operation access modes
    [...statics, ...imperatives].forEach(defaultAccess => {
      // NOTE: create is handled differently below
      ['read', 'update', 'delete'].forEach(operation => {
        [...statics, ...imperatives, ...declaratives].forEach(opAccess => {
          const access = { [operation]: opAccess };
          expect(parseListAccess({ defaultAccess, access })).toEqual({
            create: defaultAccess,
            read: defaultAccess,
            update: defaultAccess,
            delete: defaultAccess,
            // Override the specific operation we are trying
            ...{ [operation]: opAccess },
          });
        });
      });

      // Misc values are not valid per-operation access modes
      expect(() => parseListAccess({ defaultAccess, access: { read: 10 } })).toThrow(Error);
    });

    // StaticAccess | ImperativeAccess are valid per-operation access modes (create)
    [...statics, ...imperatives].forEach(defaultAccess => {
      [...statics, ...imperatives].forEach(opAccess => {
        const access = { create: opAccess };
        expect(parseListAccess({ defaultAccess, access })).toEqual({
          create: opAccess,
          read: defaultAccess,
          update: defaultAccess,
          delete: defaultAccess,
        });
      });

      // DeclarativeAccess | Misc values are not valid per-operation access modes (create)
      [where, 10].forEach(opAccess => {
        expect(() => parseListAccess({ defaultAccess, access: { create: opAccess } })).toThrow(
          Error
        );
      });
    });

    // access as an object with bad fields or bad type
    expect(() => parseListAccess({ access: { a: 1 } })).toThrow(Error);
    expect(() => parseListAccess({ access: 10 })).toThrow(Error);
  });

  test('parseFieldAccess', () => {
    const statics = [true, false]; // type StaticAccess = boolean;
    const imperatives = [() => true, () => false]; // type ImperativeAccess = AccessInput => boolean;

    // StaticAccess | ImperativeAccess are valid defaults
    [...statics, ...imperatives].forEach(defaultAccess => {
      expect(parseFieldAccess({ defaultAccess })).toEqual({
        create: defaultAccess,
        read: defaultAccess,
        update: defaultAccess,
      });
    });

    // Objects and other misc values are not value inputs for defaultAccess
    [{ a: 1 }, 10].forEach(defaultAccess => {
      expect(() => parseListAccess({ defaultAccess })).toThrow(Error);
    });

    // StaticAccess | ImperativeAccess are valid access modes, and should override the defaults
    [...statics, ...imperatives].forEach(defaultAccess => {
      [...statics, ...imperatives].forEach(access => {
        expect(parseFieldAccess({ defaultAccess, access })).toEqual({
          create: access,
          read: access,
          update: access,
        });
      });
    });

    // StaticAccess | ImperativeAccess are valid per-operation access modes
    [...statics, ...imperatives].forEach(defaultAccess => {
      ['create', 'read', 'update'].forEach(operation => {
        [...statics, ...imperatives].forEach(opAccess => {
          const access = { [operation]: opAccess };
          expect(parseFieldAccess({ defaultAccess, access })).toEqual({
            create: defaultAccess,
            read: defaultAccess,
            update: defaultAccess,
            // Override the specific operation we are trying
            ...{ [operation]: opAccess },
          });
        });

        // Misc values are not valid per-operation access modes
        expect(() => parseFieldAccess({ defaultAccess, access: { [operation]: 10 } })).toThrow(
          Error
        );
      });
    });

    expect(() => parseFieldAccess({ access: { a: 1 } })).toThrow(Error);
    expect(() => parseFieldAccess({ access: 10 })).toThrow(Error);
  });

  test('validateListAccessControl', () => {
    let operation = 'read';
    const access = { [operation]: true };

    // Test the static case: returning a boolean
    expect(validateListAccessControl({ access: { [operation]: true }, operation })).toBe(true);
    expect(validateListAccessControl({ access: { [operation]: false }, operation })).toBe(false);
    expect(() => validateListAccessControl({ access: { [operation]: 10 }, operation })).toThrow(
      Error
    );

    [{}, { item: {} }].forEach(authentication => {
      operation = 'read';

      // Boolean function
      access[operation] = () => true;
      expect(
        validateListAccessControl({
          access: { [operation]: () => true },
          operation,
          authentication,
        })
      ).toBe(true);
      expect(
        validateListAccessControl({
          access: { [operation]: () => false },
          operation,
          authentication,
        })
      ).toBe(false);
      // Object function
      expect(
        validateListAccessControl({
          access: { [operation]: () => ({ a: 1 }) },
          operation,
          authentication,
        })
      ).toEqual({ a: 1 });

      // Object function with create operation
      operation = 'create';
      expect(() =>
        validateListAccessControl({
          access: { [operation]: () => ({ a: 1 }) },
          operation,
          authentication,
        })
      ).toThrow(Error);

      // Number function
      expect(() =>
        validateListAccessControl({ access: { [operation]: () => 10 }, operation, authentication })
      ).toThrow(Error);
    });
  });

  test('validateFieldAccessControl', () => {
    const operation = 'read';
    // Test the StaticAccess case: returning a boolean
    expect(validateFieldAccessControl({ access: { [operation]: true }, operation })).toBe(true);
    expect(validateFieldAccessControl({ access: { [operation]: false }, operation })).toBe(false);
    expect(() => validateFieldAccessControl({ access: { [operation]: 10 }, operation })).toThrow(
      Error
    );

    [{}, { item: {} }].forEach(authentication => {
      // Test the ImperativeAccess case: a function which should return boolean
      expect(
        validateFieldAccessControl({
          access: { [operation]: () => true },
          operation,
          authentication,
        })
      ).toBe(true);

      expect(
        validateFieldAccessControl({
          access: { [operation]: () => false },
          operation,
          authentication,
        })
      ).toBe(false);

      expect(() =>
        validateFieldAccessControl({ access: { [operation]: () => 10 }, operation, authentication })
      ).toThrow(Error);
    });
  });
});
<|endoftext|>


<commit_before><commit_msg>Fix garbage collector leak v2<commit_after><|endoftext|>


<commit_before>import definitions from "./definitions";

export default function ({ types: t }) {
  const RUNTIME_MODULE_NAME = "babel-runtime";

  function has(obj, key) {
    return Object.prototype.hasOwnProperty.call(obj, key);
  }

  let HELPER_BLACKLIST = ["interopRequireWildcard", "interopRequireDefault"];

  return {
    pre(file) {
      file.set("helperGenerator", function (name) {
        if (HELPER_BLACKLIST.indexOf(name) < 0) {
          return file.addImport(`${RUNTIME_MODULE_NAME}/helpers/${name}`, "default", name);
        }
      });

      this.setDynamic("regeneratorIdentifier", function () {
        return file.addImport(`${RUNTIME_MODULE_NAME}/regenerator`, "default", "regeneratorRuntime");
      });
    },

    visitor: {
      ReferencedIdentifier(path, state) {
        if (state.opts.regenerator === false) return;

        let { node, parent, scope } = path;

        if (node.name === "regeneratorRuntime") {
          path.replaceWith(state.get("regeneratorIdentifier"));
          return;
        }

        if (state.opts.polyfill === false) return;

        if (t.isMemberExpression(parent)) return;
        if (!has(definitions.builtins, node.name)) return;
        if (scope.getBindingIdentifier(node.name)) return;

        // Symbol() -> _core.Symbol(); new Promise -> new _core.Promise
        path.replaceWith(state.addImport(
          `${RUNTIME_MODULE_NAME}/core-js/${definitions.builtins[node.name]}`,
          "default",
          node.name
        ));
      },

      // arr[Symbol.iterator]() -> _core.$for.getIterator(arr)
      CallExpression(path, state) {
        if (state.opts.polyfill === false) return;

        // we can't compile this
        if (path.node.arguments.length) return;

        let callee = path.node.callee;
        if (!t.isMemberExpression(callee)) return;
        if (!callee.computed) return;
        if (!path.get("callee.property").matchesPattern("Symbol.iterator")) return;

        path.replaceWith(t.callExpression(
          state.addImport(
            `${RUNTIME_MODULE_NAME}/core-js/get-iterator`,
            "default",
            "getIterator"
          ),
          [callee.object]
        ));
      },

      // Symbol.iterator in arr -> core.$for.isIterable(arr)
      BinaryExpression(path, state) {
        if (state.opts.polyfill === false) return;

        if (path.node.operator !== "in") return;
        if (!path.get("left").matchesPattern("Symbol.iterator")) return;

        path.replaceWith(t.callExpression(
          state.addImport(
            `${RUNTIME_MODULE_NAME}/core-js/is-iterable`,
            "default",
            "isIterable"
          ),
          [path.node.right]
        ));
      },

      // Array.from -> _core.Array.from
      MemberExpression: {
        enter(path, state) {
          if (state.opts.polyfill === false) return;
          if (!path.isReferenced()) return;

          let { node } = path;
          let obj = node.object;
          let prop = node.property;

          if (!t.isReferenced(obj, node)) return;
          if (node.computed) return;
          if (!has(definitions.methods, obj.name)) return;

          let methods = definitions.methods[obj.name];
          if (!has(methods, prop.name)) return;

          // doesn't reference the global
          if (path.scope.getBindingIdentifier(obj.name)) return;

          // special case Object.defineProperty to not use core-js when using string keys
          if (obj.name === "Object" && prop.name === "defineProperty" && path.parentPath.isCallExpression()) {
            let call = path.parentPath.node;
            if (call.arguments.length === 3 && t.isLiteral(call.arguments[1])) return;
          }

          path.replaceWith(state.addImport(
            `${RUNTIME_MODULE_NAME}/core-js/${methods[prop.name]}`,
            "default",
            `${obj.name}$${prop.name}`
          ));
        },

        exit(path, state) {
          if (state.opts.polyfill === false) return;
          if (!path.isReferenced()) return;

          let { node } = path;
          let obj = node.object;

          if (!has(definitions.builtins, obj.name)) return;
          if (path.scope.getBindingIdentifier(obj.name)) return;

          path.replaceWith(t.memberExpression(
            state.addImport(
              `${RUNTIME_MODULE_NAME}/core-js/${definitions.builtins[obj.name]}`,
              "default",
              obj.name
            ),
            node.property,
            node.computed
          ));
        }
      }
    }
  };
}

export { definitions };
<commit_msg>Ensure regenerator option for babel-plugin-transform-runtime doesn't cancel out core-js polyfill<commit_after>import definitions from "./definitions";

export default function ({ types: t }) {
  const RUNTIME_MODULE_NAME = "babel-runtime";

  function has(obj, key) {
    return Object.prototype.hasOwnProperty.call(obj, key);
  }

  let HELPER_BLACKLIST = ["interopRequireWildcard", "interopRequireDefault"];

  return {
    pre(file) {
      file.set("helperGenerator", function (name) {
        if (HELPER_BLACKLIST.indexOf(name) < 0) {
          return file.addImport(`${RUNTIME_MODULE_NAME}/helpers/${name}`, "default", name);
        }
      });

      this.setDynamic("regeneratorIdentifier", function () {
        return file.addImport(`${RUNTIME_MODULE_NAME}/regenerator`, "default", "regeneratorRuntime");
      });
    },

    visitor: {
      ReferencedIdentifier(path, state) {
        let { node, parent, scope } = path;

        if (node.name === "regeneratorRuntime" && state.opts.regenerator !== false) {
          path.replaceWith(state.get("regeneratorIdentifier"));
          return;
        }

        if (state.opts.polyfill === false) return;

        if (t.isMemberExpression(parent)) return;
        if (!has(definitions.builtins, node.name)) return;
        if (scope.getBindingIdentifier(node.name)) return;

        // Symbol() -> _core.Symbol(); new Promise -> new _core.Promise
        path.replaceWith(state.addImport(
          `${RUNTIME_MODULE_NAME}/core-js/${definitions.builtins[node.name]}`,
          "default",
          node.name
        ));
      },

      // arr[Symbol.iterator]() -> _core.$for.getIterator(arr)
      CallExpression(path, state) {
        if (state.opts.polyfill === false) return;

        // we can't compile this
        if (path.node.arguments.length) return;

        let callee = path.node.callee;
        if (!t.isMemberExpression(callee)) return;
        if (!callee.computed) return;
        if (!path.get("callee.property").matchesPattern("Symbol.iterator")) return;

        path.replaceWith(t.callExpression(
          state.addImport(
            `${RUNTIME_MODULE_NAME}/core-js/get-iterator`,
            "default",
            "getIterator"
          ),
          [callee.object]
        ));
      },

      // Symbol.iterator in arr -> core.$for.isIterable(arr)
      BinaryExpression(path, state) {
        if (state.opts.polyfill === false) return;

        if (path.node.operator !== "in") return;
        if (!path.get("left").matchesPattern("Symbol.iterator")) return;

        path.replaceWith(t.callExpression(
          state.addImport(
            `${RUNTIME_MODULE_NAME}/core-js/is-iterable`,
            "default",
            "isIterable"
          ),
          [path.node.right]
        ));
      },

      // Array.from -> _core.Array.from
      MemberExpression: {
        enter(path, state) {
          if (state.opts.polyfill === false) return;
          if (!path.isReferenced()) return;

          let { node } = path;
          let obj = node.object;
          let prop = node.property;

          if (!t.isReferenced(obj, node)) return;
          if (node.computed) return;
          if (!has(definitions.methods, obj.name)) return;

          let methods = definitions.methods[obj.name];
          if (!has(methods, prop.name)) return;

          // doesn't reference the global
          if (path.scope.getBindingIdentifier(obj.name)) return;

          // special case Object.defineProperty to not use core-js when using string keys
          if (obj.name === "Object" && prop.name === "defineProperty" && path.parentPath.isCallExpression()) {
            let call = path.parentPath.node;
            if (call.arguments.length === 3 && t.isLiteral(call.arguments[1])) return;
          }

          path.replaceWith(state.addImport(
            `${RUNTIME_MODULE_NAME}/core-js/${methods[prop.name]}`,
            "default",
            `${obj.name}$${prop.name}`
          ));
        },

        exit(path, state) {
          if (state.opts.polyfill === false) return;
          if (!path.isReferenced()) return;

          let { node } = path;
          let obj = node.object;

          if (!has(definitions.builtins, obj.name)) return;
          if (path.scope.getBindingIdentifier(obj.name)) return;

          path.replaceWith(t.memberExpression(
            state.addImport(
              `${RUNTIME_MODULE_NAME}/core-js/${definitions.builtins[obj.name]}`,
              "default",
              obj.name
            ),
            node.property,
            node.computed
          ));
        }
      }
    }
  };
}

export { definitions };
<|endoftext|>


<commit_before>import {
  h,
  render,
  define,
  props,
  withComponent,
  withPreact,
  css,
  spacingSizes,
  hasNativeShadowDomSupport,
  supportsCSSVars,
  colorContrast,
  rgb2hex,
} from '@bolt/core';

import PubSub from 'pubsub-js';
import upperCamelCase from 'uppercamelcase';
import * as Icons from '@bolt/components-icons';
import styles from './icon.scss';

const backgroundStyles = [
  'circle',
  'square',
];

const colors = [
  'teal',
  'blue',
];

@define
export class BoltIcon extends withPreact(withComponent()) {
  static is = 'bolt-icon';

  static props = {
    name: props.string,
    size: props.string,
    background: props.string,
    color: props.string,

    // programatically spell out the contrast color that needs to get used
    contrastColor: props.string,
  }

  state = {
    primaryColor: null,
    secondaryColor: null,
  }

  constructor() {
    super();
    this.useShadow = hasNativeShadowDomSupport;
    this.useCssVars = supportsCSSVars;
  }

  connectedCallback() {
    const elem = this;

    // listen for page changes to decide when colors need to get recalculated
    if (!this.useCssVars) {
      const checkIfColorChanged = function (msg, data) {
        /**
         * The container with the class change contains this particular icon element so
         * we should double-check the color contrast values.
         */
        if (data.target.contains(elem)) {
          const recalculatedSecondaryColor = colorContrast(
            rgb2hex(window.getComputedStyle(elem).getPropertyValue('color')),
          );

          elem.setAttribute('contrast-color', recalculatedSecondaryColor);
          elem.state.secondaryColor = recalculatedSecondaryColor;
        }
      };

      const colorObserver = PubSub.subscribe('component.icon', checkIfColorChanged);
    }
  }

  render({ props, state }) {
    const { size, name, color, background, contrastColor } = this.props;

    const classes = css(
      'c-bolt-icon',
      size && spacingSizes[size] && spacingSizes[size] !== '' ? `c-bolt-icon--${size}` : '',
      name ? `c-bolt-icon--${name}` : '',
      color && colors.includes(color) ? `c-bolt-icon--${color}` : '',
    );

    const backgroundClasses = css(
      'c-bolt-icon__background-shape',
      background && backgroundStyles.includes(background) ? `c-bolt-icon__background-shape--${background}` : '',
    );

    const iconClasses = css(
      'c-bolt-icon__icon',
    );

    const Icon = name ? upperCamelCase(name) : '';
    const IconTag = Icons[Icon];

    const iconSize = size && spacingSizes[size] ?
      spacingSizes[size].replace('rem', '') * (16 / 2) :
      spacingSizes.medium.replace('rem', '') * (16 / 2);

    if (supportsCSSVars) {
      this.state.primaryColor = 'var(--bolt-theme-icon, currentColor)';
      this.state.secondaryColor = 'var(--bolt-theme-background, #fff)';
    } else {
      this.state.primaryColor = 'currentColor';
      this.state.primaryColorComputed = rgb2hex(window.getComputedStyle(this).getPropertyValue('color'));

      if (contrastColor) {
        this.state.secondaryColor = contrastColor;
      } else {
        this.state.secondaryColor = colorContrast(this.state.primaryColorComputed);
      }
    }

    return (

        {this.useShadow &&

        }
        <IconTag
          className={iconClasses}
          size={iconSize}
          bgColor={this.state.primaryColor}
          fgColor={this.state.secondaryColor}
        />

        {background && size === 'xlarge' &&

        }

    );
  }
}

/**
 * If CSS Vars are unsupported, listen for class changes on the page to selectively
 * decide when to check to see if an icon component's color should change.
 */
const observedElements = [];

// Observe body + children for changes, but only once.
if (!supportsCSSVars && !observedElements.includes(document.body)) {
  observedElements.push(document.body);

  const observer = new MutationObserver((mutations) => {
    mutations.forEach((mutation) => {
      if (mutation.attributeName === 'class') {
        // publish a topic asyncronously
        PubSub.publish('component.icon', { event: 'color-change', target: mutation.target });
      }
    });
  });

  // Attach the mutation observer to the body to listen for className changes
  observer.observe(document.body, {
    attributes: true,
    attributeFilter: [
      'class',
    ],
    attributeOldValue: false,
    childList: false,
    subtree: true,
  });
}
<commit_msg>fix: add check for `contains` method to prevent error from getting thrown in IE11 (#566)<commit_after>import {
  h,
  render,
  define,
  props,
  withComponent,
  withPreact,
  css,
  spacingSizes,
  hasNativeShadowDomSupport,
  supportsCSSVars,
  colorContrast,
  rgb2hex,
} from '@bolt/core';

import PubSub from 'pubsub-js';
import upperCamelCase from 'uppercamelcase';
import * as Icons from '@bolt/components-icons';
import styles from './icon.scss';

const backgroundStyles = [
  'circle',
  'square',
];

const colors = [
  'teal',
  'blue',
];

@define
export class BoltIcon extends withPreact(withComponent()) {
  static is = 'bolt-icon';

  static props = {
    name: props.string,
    size: props.string,
    background: props.string,
    color: props.string,

    // programatically spell out the contrast color that needs to get used
    contrastColor: props.string,
  }

  state = {
    primaryColor: null,
    secondaryColor: null,
  }

  constructor() {
    super();
    this.useShadow = hasNativeShadowDomSupport;
    this.useCssVars = supportsCSSVars;
  }

  connectedCallback() {
    const elem = this;

    // listen for page changes to decide when colors need to get recalculated
    if (!this.useCssVars) {
      const checkIfColorChanged = function (msg, data) {
        /**
         * The container with the class change contains this particular icon element so
         * we should double-check the color contrast values.
         */
        if (data.target.contains) {
          if (data.target.contains(elem)) {
            const recalculatedSecondaryColor = colorContrast(
              rgb2hex(window.getComputedStyle(elem).getPropertyValue('color')),
            );

            elem.setAttribute('contrast-color', recalculatedSecondaryColor);
            elem.state.secondaryColor = recalculatedSecondaryColor;
          }
        }
      };

      const colorObserver = PubSub.subscribe('component.icon', checkIfColorChanged);
    }
  }

  render({ props, state }) {
    const { size, name, color, background, contrastColor } = this.props;

    const classes = css(
      'c-bolt-icon',
      size && spacingSizes[size] && spacingSizes[size] !== '' ? `c-bolt-icon--${size}` : '',
      name ? `c-bolt-icon--${name}` : '',
      color && colors.includes(color) ? `c-bolt-icon--${color}` : '',
    );

    const backgroundClasses = css(
      'c-bolt-icon__background-shape',
      background && backgroundStyles.includes(background) ? `c-bolt-icon__background-shape--${background}` : '',
    );

    const iconClasses = css(
      'c-bolt-icon__icon',
    );

    const Icon = name ? upperCamelCase(name) : '';
    const IconTag = Icons[Icon];

    const iconSize = size && spacingSizes[size] ?
      spacingSizes[size].replace('rem', '') * (16 / 2) :
      spacingSizes.medium.replace('rem', '') * (16 / 2);

    if (supportsCSSVars) {
      this.state.primaryColor = 'var(--bolt-theme-icon, currentColor)';
      this.state.secondaryColor = 'var(--bolt-theme-background, #fff)';
    } else {
      this.state.primaryColor = 'currentColor';
      this.state.primaryColorComputed = rgb2hex(window.getComputedStyle(this).getPropertyValue('color'));

      if (contrastColor) {
        this.state.secondaryColor = contrastColor;
      } else {
        this.state.secondaryColor = colorContrast(this.state.primaryColorComputed);
      }
    }

    return (

        {this.useShadow &&

        }
        <IconTag
          className={iconClasses}
          size={iconSize}
          bgColor={this.state.primaryColor}
          fgColor={this.state.secondaryColor}
        />

        {background && size === 'xlarge' &&

        }

    );
  }
}

/**
 * If CSS Vars are unsupported, listen for class changes on the page to selectively
 * decide when to check to see if an icon component's color should change.
 */
const observedElements = [];

// Observe body + children for changes, but only once.
if (!supportsCSSVars && !observedElements.includes(document.body)) {
  observedElements.push(document.body);

  const observer = new MutationObserver((mutations) => {
    mutations.forEach((mutation) => {
      if (mutation.attributeName === 'class') {
        // publish a topic asyncronously
        PubSub.publish('component.icon', { event: 'color-change', target: mutation.target });
      }
    });
  });

  // Attach the mutation observer to the body to listen for className changes
  observer.observe(document.body, {
    attributes: true,
    attributeFilter: [
      'class',
    ],
    attributeOldValue: false,
    childList: false,
    subtree: true,
  });
}
<|endoftext|>


<commit_before>/**
@module ember
@submodule ember-runtime
*/
import {
  Mixin,
  run
} from 'ember-metal';
import {
  FACTORY_FOR,
  LOOKUP_FACTORY
} from 'container';

/**
  ContainerProxyMixin is used to provide public access to specific
  container functionality.

  @class ContainerProxyMixin
  @private
*/
export default Mixin.create({
  /**
   The container stores state.

   @private
   @property {Ember.Container} __container__
   */
  __container__: null,

  /**
   Returns an object that can be used to provide an owner to a
   manually created instance.

   Example:

   ```
   let owner = Ember.getOwner(this);

   User.create(
     owner.ownerInjection(),
     { username: 'rwjblue' }
   )
   ```

   @public
   @method ownerInjection
   @return {Object}
  */
  ownerInjection() {
    return this.__container__.ownerInjection();
  },

  /**
   Given a fullName return a corresponding instance.

   The default behaviour is for lookup to return a singleton instance.
   The singleton is scoped to the container, allowing multiple containers
   to all have their own locally scoped singletons.

   ```javascript
   let registry = new Registry();
   let container = registry.container();

   registry.register('api:twitter', Twitter);

   let twitter = container.lookup('api:twitter');

   twitter instanceof Twitter; // => true

   // by default the container will return singletons
   let twitter2 = container.lookup('api:twitter');
   twitter2 instanceof Twitter; // => true

   twitter === twitter2; //=> true
   ```

   If singletons are not wanted an optional flag can be provided at lookup.

   ```javascript
   let registry = new Registry();
   let container = registry.container();

   registry.register('api:twitter', Twitter);

   let twitter = container.lookup('api:twitter', { singleton: false });
   let twitter2 = container.lookup('api:twitter', { singleton: false });

   twitter === twitter2; //=> false
   ```

   @public
   @method lookup
   @param {String} fullName
   @param {Object} options
   @return {any}
   */
  lookup(fullName, options) {
    return this.__container__.lookup(fullName, options);
  },

  /**
   Given a fullName return the corresponding factory.

   @private
   @method _lookupFactory
   @param {String} fullName
   @return {any}
   */
  _lookupFactory(fullName, options) {
    return this.__container__.lookupFactory(fullName, options);
  },

  [FACTORY_FOR]() {
    return this.__container__[FACTORY_FOR](...arguments);
  },

  [LOOKUP_FACTORY]() {
    return this.__container__[LOOKUP_FACTORY](...arguments);
  },

  /**
   Given a name and a source path, resolve the fullName

   @private
   @method _resolveLocalLookupName
   @param {String} fullName
   @param {String} source
   @return {String}
   */
  _resolveLocalLookupName(name, source) {
    return this.__container__.registry.expandLocalLookup(`component:${name}`, {
      source
    });
  },

  /**
   @private
   */
  willDestroy() {
    this._super(...arguments);

    if (this.__container__) {
      run(this.__container__, 'destroy');
    }
  },

  factoryFor(fullName, options = {}) {
    return this.__container__.factoryFor(fullName, options);
  }
});
<commit_msg>[FEATURE factory-for] Only expose factoryFor w/ FF<commit_after>/**
@module ember
@submodule ember-runtime
*/
import {
  Mixin,
  run
} from 'ember-metal';
import {
  FACTORY_FOR,
  LOOKUP_FACTORY
} from 'container';
import { isFeatureEnabled } from 'ember-metal';

/**
  ContainerProxyMixin is used to provide public access to specific
  container functionality.

  @class ContainerProxyMixin
  @private
*/
let containerProxyMixin = {
  /**
   The container stores state.

   @private
   @property {Ember.Container} __container__
   */
  __container__: null,

  /**
   Returns an object that can be used to provide an owner to a
   manually created instance.

   Example:

   ```
   let owner = Ember.getOwner(this);

   User.create(
     owner.ownerInjection(),
     { username: 'rwjblue' }
   )
   ```

   @public
   @method ownerInjection
   @return {Object}
  */
  ownerInjection() {
    return this.__container__.ownerInjection();
  },

  /**
   Given a fullName return a corresponding instance.

   The default behaviour is for lookup to return a singleton instance.
   The singleton is scoped to the container, allowing multiple containers
   to all have their own locally scoped singletons.

   ```javascript
   let registry = new Registry();
   let container = registry.container();

   registry.register('api:twitter', Twitter);

   let twitter = container.lookup('api:twitter');

   twitter instanceof Twitter; // => true

   // by default the container will return singletons
   let twitter2 = container.lookup('api:twitter');
   twitter2 instanceof Twitter; // => true

   twitter === twitter2; //=> true
   ```

   If singletons are not wanted an optional flag can be provided at lookup.

   ```javascript
   let registry = new Registry();
   let container = registry.container();

   registry.register('api:twitter', Twitter);

   let twitter = container.lookup('api:twitter', { singleton: false });
   let twitter2 = container.lookup('api:twitter', { singleton: false });

   twitter === twitter2; //=> false
   ```

   @public
   @method lookup
   @param {String} fullName
   @param {Object} options
   @return {any}
   */
  lookup(fullName, options) {
    return this.__container__.lookup(fullName, options);
  },

  /**
   Given a fullName return the corresponding factory.

   @private
   @method _lookupFactory
   @param {String} fullName
   @return {any}
   */
  _lookupFactory(fullName, options) {
    return this.__container__.lookupFactory(fullName, options);
  },

  [FACTORY_FOR]() {
    return this.__container__[FACTORY_FOR](...arguments);
  },

  [LOOKUP_FACTORY]() {
    return this.__container__[LOOKUP_FACTORY](...arguments);
  },

  /**
   Given a name and a source path, resolve the fullName

   @private
   @method _resolveLocalLookupName
   @param {String} fullName
   @param {String} source
   @return {String}
   */
  _resolveLocalLookupName(name, source) {
    return this.__container__.registry.expandLocalLookup(`component:${name}`, {
      source
    });
  },

  /**
   @private
   */
  willDestroy() {
    this._super(...arguments);

    if (this.__container__) {
      run(this.__container__, 'destroy');
    }
  }
};

if (isFeatureEnabled('ember-factory-for')) {
  containerProxyMixin.factoryFor = function ContainerProxyMixin_factoryFor(fullName, options = {}) {
    return this.__container__.factoryFor(fullName, options);
  };
}

export default Mixin.create(containerProxyMixin);
<|endoftext|>