<commit_before>import {HTML5Video, Log, Events} from 'clappr'
import shaka from 'shaka-player'

const SEND_STATS_AT = 30 * 1000
const AUTO = -1

export default class DashShakaPlayback extends HTML5Video {
  get name() {return 'dash_shaka_playback'}

  get shakaVersion() {return shaka.player.Player.version}

  get levels() { return this._levels }

  set currentLevel(id) {
    this._currentLevelId = id
    var isAuto = this._currentLevelId === AUTO

    this._player.configure({enableAdaptation: !isAuto})
    this.trigger(Events.PLAYBACK_LEVEL_SWITCH_START)
    !isAuto && this.selectVideoTrack(this._currentLevelId)
  }
  get currentLevel() { return this._currentLevelId || AUTO }

  constructor(options) {
    super(options)
    this._readyToPlay = false
    this._levels = []

    var checkIfIsReady = (fn) => {
      return (arg) => {
        if (this._readyToPlay) return fn(arg)
      }
    }

    this.enableTextTrack = checkIfIsReady((enable) => this._player.enableTextTrack(enable))
    this.textTracks = checkIfIsReady(() => this._player.getTextTracks())
    this.selectTextTrack = checkIfIsReady((id) => this._player.selectTextTrack(id))
    this.audioTracks = checkIfIsReady(() => this._player.getAudioTracks())
    this.selectAudioTrack = checkIfIsReady((id) => this._player.selectAudioTrack(id))
    this.videoTracks = checkIfIsReady(() => this._player.getVideoTracks())
    this.selectVideoTrack = checkIfIsReady((id) => this._player.selectVideoTrack(id))

    this.getPlaybackType = checkIfIsReady(() => (this._player.isLive()?'live':'vod'))
  }

  play() {
    !this._player && this._setup()

    if (!this._readyToPlay) {
      this.once(Events.PLAYBACK_READY, this.play)
      return
    }
    super.play()
  }

  // skipping ready event on video tag in favor of ready on shaka
  ready() {}

  // skipping error handling on video tag in favor of error on shaka
  error(event) { Log.error('an error was raised by the video tag', event, this.el.error)}

  isHighDefinitionInUse() { return !!this.highDefinition }

  stop() {
    clearInterval(this.sendStatsId)
    this.trigger(Events.PLAYBACK_STOP, this.name)
    this._sendStats()
    this._player.unload()
    this._player = null
    this._readyToPlay = false
  }

  destroy() {
    clearInterval(this.sendStatsId)
    this._player.destroy().
      then(() => this._destroy()).
      catch(() => {
        this._destroy()
        Log.error('shaka could not be destroyed')
      })
  }

  _setup() {
    this._player = this._createPlayer()

    var playerLoaded = this._player.load(new shaka.player.DashVideoSource(this.options.src))
    playerLoaded.then(() => this._loaded())
      .catch((e) => this._setupError(e))
  }

  _createPlayer() {
    var player = new shaka.player.Player(this.el)
    player.addEventListener('bufferingStart', () => this._bufferingHandler())
    player.addEventListener('bufferingEnd', () => this._bufferingFullHandler())
    player.addEventListener('error', (e) => this._error(e))
    player.addEventListener('adaptation', () => this._onAdaptation())
    return player
  }

  _loaded() {
    this._ready()
    this._startToSendStats()
    this._levels = this.videoTracks().map((videoTrack) => { return {id: videoTrack.id, label: `${videoTrack.height}p`}})
    this.trigger(Events.PLAYBACK_LEVELS_AVAILABLE, this.levels)
  }

  _startToSendStats() {
    this.sendStatsId = setInterval(() => this._sendStats(), SEND_STATS_AT)
  }

  _sendStats() {this.trigger(Events.PLAYBACK_STATS_ADD, this._player.getStats())}

  _setupError(e) { this._error({detail: `shaka could not be setup: ${e}`}) }

  _bufferingHandler() { this.trigger(Events.PLAYBACK_BUFFERING, this.name) }

  _bufferingFullHandler() { this.trigger(Events.PLAYBACK_BUFFERFULL, this.name) }

  _error(error) {
    Log.error('an error was raised by shaka player', error.detail)
    this.trigger(Events.PLAYBACK_ERROR, error.detail, this.name)
  }

  _onAdaptation(event) {
    if (!!event.size) return

    Log.debug('an adaptation has happened:', event)
    this.highDefinition = (event.size.height >= 720)
    this.trigger(Events.PLAYBACK_HIGHDEFINITIONUPDATE, this.highDefinition)
    this.trigger(Events.PLAYBACK_BITRATE, {bitrate: event.size.height})
    (this._levels.length > 0) && this.trigger(Events.PLAYBACK_LEVEL_SWITCH_END)
  }

  _destroy() {
    super.destroy()
    this._readyToPlay = false
    Log.debug('shaka was destroyed')
  }

  _ready() {
    this._readyToPlay = true
    super.ready()
  }
}

DashShakaPlayback.canPlay = (resource, mimeType = '') => {
  shaka.polyfill.installAll()

  if (!shaka.player.Player.isBrowserSupported()) {
    Log.debug('This browser does not support this video')
    return false
  }

  var resourceParts = resource.split('?')[0].match(/.*\.(.*)$/) || []
  return ("mpd" === resourceParts[1]) || mimeType.indexOf('application/dash+xml') > -1
}

<commit_msg>only stops the player on unload sucess<commit_after>import {HTML5Video, Log, Events} from 'clappr'
import shaka from 'shaka-player'

const SEND_STATS_AT = 30 * 1000
const AUTO = -1

export default class DashShakaPlayback extends HTML5Video {
  get name() {return 'dash_shaka_playback'}

  get shakaVersion() {return shaka.player.Player.version}

  get levels() { return this._levels }

  set currentLevel(id) {
    this._currentLevelId = id
    var isAuto = this._currentLevelId === AUTO

    this._player.configure({enableAdaptation: !isAuto})
    this.trigger(Events.PLAYBACK_LEVEL_SWITCH_START)
    !isAuto && this.selectVideoTrack(this._currentLevelId)
  }
  get currentLevel() { return this._currentLevelId || AUTO }

  constructor(options) {
    super(options)
    this._readyToPlay = false
    this._levels = []

    var checkIfIsReady = (fn) => {
      return (arg) => {
        if (this._readyToPlay) return fn(arg)
      }
    }

    this.enableTextTrack = checkIfIsReady((enable) => this._player.enableTextTrack(enable))
    this.textTracks = checkIfIsReady(() => this._player.getTextTracks())
    this.selectTextTrack = checkIfIsReady((id) => this._player.selectTextTrack(id))
    this.audioTracks = checkIfIsReady(() => this._player.getAudioTracks())
    this.selectAudioTrack = checkIfIsReady((id) => this._player.selectAudioTrack(id))
    this.videoTracks = checkIfIsReady(() => this._player.getVideoTracks())
    this.selectVideoTrack = checkIfIsReady((id) => this._player.selectVideoTrack(id))

    this.getPlaybackType = checkIfIsReady(() => (this._player.isLive()?'live':'vod'))
  }

  play() {
    !this._player && this._setup()

    if (!this._readyToPlay) {
      this.once(Events.PLAYBACK_READY, this.play)
      return
    }
    super.play()
  }

  // skipping ready event on video tag in favor of ready on shaka
  ready() {}

  // skipping error handling on video tag in favor of error on shaka
  error(event) { Log.error('an error was raised by the video tag', event, this.el.error)}

  isHighDefinitionInUse() { return !!this.highDefinition }

  stop() {
    clearInterval(this.sendStatsId)
    this.trigger(Events.PLAYBACK_STOP, this.name)
    this._sendStats()

    this._player.unload().
      then(() => {
        this._player = null
        this._readyToPlay = false
      }).
      catch(() => { Log.error('shaka could not be unloaded') })
  }

  destroy() {
    clearInterval(this.sendStatsId)

    this._player.destroy().
      then(() => this._destroy()).
      catch(() => {
        this._destroy()
        Log.error('shaka could not be destroyed')
      })
  }

  _setup() {
    this._player = this._createPlayer()

    var playerLoaded = this._player.load(new shaka.player.DashVideoSource(this.options.src))
    playerLoaded.then(() => this._loaded())
      .catch((e) => this._setupError(e))
  }

  _createPlayer() {
    var player = new shaka.player.Player(this.el)
    player.addEventListener('bufferingStart', () => this._bufferingHandler())
    player.addEventListener('bufferingEnd', () => this._bufferingFullHandler())
    player.addEventListener('error', (e) => this._error(e))
    player.addEventListener('adaptation', () => this._onAdaptation())
    return player
  }

  _loaded() {
    this._ready()
    this._startToSendStats()
    this._levels = this.videoTracks().map((videoTrack) => { return {id: videoTrack.id, label: `${videoTrack.height}p`}})
    this.trigger(Events.PLAYBACK_LEVELS_AVAILABLE, this.levels)
  }

  _startToSendStats() {
    this.sendStatsId = setInterval(() => this._sendStats(), SEND_STATS_AT)
  }

  _sendStats() {this.trigger(Events.PLAYBACK_STATS_ADD, this._player.getStats())}

  _setupError(e) { this._error({detail: `shaka could not be setup: ${e}`}) }

  _bufferingHandler() { this.trigger(Events.PLAYBACK_BUFFERING, this.name) }

  _bufferingFullHandler() { this.trigger(Events.PLAYBACK_BUFFERFULL, this.name) }

  _error(error) {
    Log.error('an error was raised by shaka player', error.detail)
    this.trigger(Events.PLAYBACK_ERROR, error.detail, this.name)
  }

  _onAdaptation(event) {
    if (!!event.size) return

    Log.debug('an adaptation has happened:', event)
    this.highDefinition = (event.size.height >= 720)
    this.trigger(Events.PLAYBACK_HIGHDEFINITIONUPDATE, this.highDefinition)
    this.trigger(Events.PLAYBACK_BITRATE, {bitrate: event.size.height})
    (this._levels.length > 0) && this.trigger(Events.PLAYBACK_LEVEL_SWITCH_END)
  }

  _destroy() {
    super.destroy()
    this._readyToPlay = false
    Log.debug('shaka was destroyed')
  }

  _ready() {
    this._readyToPlay = true
    super.ready()
  }
}

DashShakaPlayback.canPlay = (resource, mimeType = '') => {
  shaka.polyfill.installAll()

  if (!shaka.player.Player.isBrowserSupported()) {
    Log.debug('This browser does not support this video')
    return false
  }

  var resourceParts = resource.split('?')[0].match(/.*\.(.*)$/) || []
  return ('mpd' === resourceParts[1]) || mimeType.indexOf('application/dash+xml') > -1
}

<|endoftext|>


<commit_before>var Joi = require('joi'),
    Hapi = require('hapi'),
    exec = require('child_process').exec,
    path = require('path'),
    fs = require('fs');

var GITHUB_TOKEN = process.env.GITHUB_TOKEN;
var DOCKER_USER = process.env.DOCKER_USER;

// Create a server with a host and port
var server = new Hapi.Server('0.0.0.0', process.env.port || 8080);

// Add the route
server.route({
  method: 'POST',
  path: '/docker-build',
  handler: function (request, reply) {
    // console.log(body);

    var body = request.payload,
        repository_url = body.repository.ssh_url,
        repository_name = body.repository.name,
        cwd = process.cwd();

    // if (body.hook.config.secret != GITHUB_TOKEN)
    var timecode = +(new Date());

    var workDir = path.join(cwd, 'tmp', ''+timecode);

    var cleanup = function (cb) {
      exec('rm -Rf '+workDir, cb);
    }

    exec('git clone ' + repository_url + ' '+workDir, function (error, stdout, stderr) {
      if (error) {
        console.error('Failed to clone repository');
        console.error(error);
        cleanup();
      } else {
        exec('cd ' + workDir + ';  docker build -t '+DOCKER_USER+'/'+repository_name+' .', function (error, stdout, stderr) {
          if (error) {
            console.error('Failed to build docker image');
            console.error(error);
            cleanup();
          } else {
            exec('cd ' + workDir + ';  docker push', function (error, stdout, stderr) {
              if (error) {
                console.error('Failed to publish docker image');
                console.error(error);
                cleanup();
              } else {
                exec('cd ' + workDir + ';  docker push', function (err, stdout, stderr) {
                  cleanup();
                });
              }
            });
          }
        });
      }
    });
    reply('Build Away');
  },
  config: {}
});

// server.route({
//   method: '*',
//   path: '/*',
//   handler: function(request, reply) {
//      reply('The page was not found').code(404);
//   }
// });

// Start the server
server.start();<commit_msg>Work with dockers style.<commit_after>var Joi = require('joi'),
    Hapi = require('hapi'),
    exec = require('child_process').exec,
    path = require('path'),
    fs = require('fs');

var GITHUB_TOKEN = process.env.GITHUB_TOKEN;
var DOCKER_USER = process.env.DOCKER_USER;

// Create a server with a host and port
var server = new Hapi.Server('0.0.0.0', process.env.port || 8080);

// Add the route
server.route({
  method: 'POST',
  path: '/docker-build',
  handler: function (request, reply) {
    // console.log(body);

    var body = request.payload,
        repository_url = body.repository.ssh_url,
        repository_name = body.repository.name.toLowerCase(),
        cwd = process.cwd();

    // if (body.hook.config.secret != GITHUB_TOKEN)
    var timecode = +(new Date());

    var workDir = path.join(cwd, 'tmp', ''+timecode);

    var cleanup = function (cb) {
      exec('rm -Rf '+workDir, cb);
    }

    exec('git clone ' + repository_url + ' '+workDir, function (error, stdout, stderr) {
      if (error) {
        console.error('Failed to clone repository');
        console.error(error);
        cleanup();
      } else {
        exec('cd ' + workDir + ';  docker build -t '+DOCKER_USER+'/'+repository_name+' .', function (error, stdout, stderr) {
          if (error) {
            console.error('Failed to build docker image');
            console.error(error);
            cleanup();
          } else {
            exec('cd ' + workDir + ';  docker push', function (error, stdout, stderr) {
              if (error) {
                console.error('Failed to publish docker image');
                console.error(error);
                cleanup();
              } else {
                exec('cd ' + workDir + ';  docker push', function (err, stdout, stderr) {
                  cleanup();
                });
              }
            });
          }
        });
      }
    });
    reply('Build Away');
  },
  config: {}
});

// server.route({
//   method: '*',
//   path: '/*',
//   handler: function(request, reply) {
//      reply('The page was not found').code(404);
//   }
// });

// Start the server
server.start();<|endoftext|>


<commit_before>import BSON from 'bson'
import FS from 'fs-extra'
import { promisifyAll } from 'bluebird'
import _ from 'lodash'

import Recipe from './recipe-model'

const bson = new BSON()

const fs = promisifyAll(FS)

const readData = async () => {
  const file = await fs.readFileAsync('./data/reciperecords.bson')
  const data = []
  let cur = 0
  while (true) {
    try {
      cur = bson.deserializeStream(file, cur, 1, data, data.length)
    } catch (e) {
      break
    }
  }
  console.log(`converted ${data.length} recipes`)

  let recipes = _.uniqWith(data.filter(datum => datum.stage !== -1).map(datum => new Recipe(datum)), (a, b) => _.isEqual(a.identity, b.identity))
  console.log('unique recipes', recipes.length)

  const recipesOrigin = _.clone(recipes)

  recipes = _.groupBy(recipes, 'recipeId')

  // check itemId
  _.each(recipes, (group) => {
    const itemId = group[0].itemId
    if (!group.every(recipe => recipe.itemId === itemId)) {
      console.log('itemId error', group[0].recipeId)
    }
  })

  let count = 0
  // check cost
  _.forEach(recipes, (group) => {
    const stages = _.groupBy(group, 'stage')
    _.forEach(stages, (stage) => {
      const cost = stage[0].cost
      if (!stage.every(recipe => _.isEqual(recipe.cost, cost))) {
        console.log('cost error', stage[0].recipeId, stage[0].itemId, stage[0].stage)
      }
    })

    const recipeCount = (stages[0] || []).length
    const recipeId = _.get(stages, '0.0.recipeId') || _.get(stages, '1.0.recipeId')
    if (!_.every(stages, stage => stage.length === recipeCount)) {
      console.log('stage count not equal', recipeId, _.map(stages, (stage = []) => stage.length))
      count += 1
    }
  })

  console.log('insufficient records', count)
  const final = {}

  Object.keys(recipes).forEach((group) => {
    final[group] = _.groupBy(recipes[group], 'stage')
  })

  console.log('all records', Object.keys(final).length)
  console.log('by itemId', Object.keys(_.groupBy(recipesOrigin, 'itemId')).length)

  await fs.outputJson('./data/reciperecords.json', final)
}

const main = async () => {
  try {
    await readData()
  } catch (e) {
    console.error(e.stack)
  }
}

main()
<commit_msg>print itemName<commit_after>import BSON from 'bson'
import FS from 'fs-extra'
import { promisifyAll } from 'bluebird'
import _ from 'lodash'

import Recipe from './recipe-model'

const bson = new BSON()

const fs = promisifyAll(FS)

const readData = async () => {
  const file = await fs.readFileAsync('./data/reciperecords.bson')
  const data = []
  let cur = 0
  while (true) {
    try {
      cur = bson.deserializeStream(file, cur, 1, data, data.length)
    } catch (e) {
      break
    }
  }
  console.log(`converted ${data.length} recipes`)

  let recipes = _.uniqWith(data.filter(datum => datum.stage !== -1).map(datum => new Recipe(datum)), (a, b) => _.isEqual(a.identity, b.identity))
  console.log('unique recipes', recipes.length)

  const recipesOrigin = _.clone(recipes)

  recipes = _.groupBy(recipes, 'recipeId')

  // check itemId
  _.each(recipes, (group) => {
    const itemId = group[0].itemId
    if (!group.every(recipe => recipe.itemId === itemId)) {
      console.log('itemId error', group[0].recipeId)
    }
  })

  let count = 0
  // check cost
  _.forEach(recipes, (group) => {
    const stages = _.groupBy(group, 'stage')
    _.forEach(stages, (stage) => {
      const cost = stage[0].cost
      if (!stage.every(recipe => _.isEqual(recipe.cost, cost))) {
        console.log('cost error', stage[0].recipeId, stage[0].itemId, stage[0].stage)
      }
    })

    const recipeCount = (stages[0] || []).length
    const recipeId = _.get(stages, '0.0.recipeId') || _.get(stages, '1.0.recipeId') || _.get(stages, '2.0.recipeId')
    const itemName = _.get(stages, '0.0.itemName') || _.get(stages, '1.0.itemName') || _.get(stages, '2.0.itemName')
    if (!_.every(stages, stage => stage.length === recipeCount)) {
      console.log('stage count not equal', recipeId, itemName, _.map(stages, (stage = []) => stage.length))
      count += 1
    }
  })

  console.log('insufficient records', count)
  const final = {}

  Object.keys(recipes).forEach((group) => {
    final[group] = _.groupBy(recipes[group], 'stage')
  })

  console.log('all records', Object.keys(final).length)
  console.log('by itemId', Object.keys(_.groupBy(recipesOrigin, 'itemId')).length)

  await fs.outputJson('./data/reciperecords.json', final)
}

const main = async () => {
  try {
    await readData()
  } catch (e) {
    console.error(e.stack)
  }
}

main()
<|endoftext|>


<commit_before>#!/usr/bin/env node
'use strict';

var fs = require('fs');
var os = require('os');
var path = require('path');
var resolve = require('resolve').sync;
var spawn = require('child_process').spawn;
var glob = require("glob");
var async = require("async");

var VERSION = require('./package.json').version;
var LOCATION = __filename;

function errorFromExitCode(exitCode) {
  return new Error('clang-format exited with exit code ' + exitCode + '.');
}

/**
 * Start a child process running the native clang-format binary.
 * @param file a Vinyl virtual file reference
 * @param enc the encoding to use for reading stdout
 * @param style valid argument to clang-format's '-style' flag
 * @param done callback invoked when the child process terminates
 * @returns {stream.Readable} the formatted code as a Readable stream
 */
function clangFormat(file, enc, style, done) {
  var args = ['-style=' + style, file.path];
  var result = spawnClangFormat(args, done, ['ignore', 'pipe', process.stderr]);
  if (result) { // must be ChildProcess
    result.stdout.setEncoding(enc);
    return result.stdout;
  } else {
    // We shouldn't be able to reach this line, because it's not possible to
    // set the --glob arg in this function.
    throw new Error('Can\'t get output stream when --glob flag is set');
  }
}

/**
 * Spawn the clang-format binary with given arguments.
 */
function spawnClangFormat(args, done, stdio) {
  // WARNING: This function's interface should stay stable across versions for the cross-version
  // loading below to work.
  if (args.indexOf('-version') !== -1 || args.indexOf('--version') !== -1) {
    // Print our version.
    // This makes it impossible to format files called '-version' or '--version'. That's a feature.
    // minimist & Co don't support single dash args, which we need to match binary clang-format.
    console.log('clang-format NPM version', VERSION, 'at', LOCATION);
    // To be consistent with other code paths, we use setImmediate to call `done` asynchronously.
    setImmediate(done);
    return;
  }
  var nativeBinary;
  if (os.platform() === 'win32') {
    nativeBinary = __dirname + '/bin/win32/clang-format.exe';
  } else {
    nativeBinary = __dirname + '/bin/' + os.platform() + "_" + os.arch() + '/clang-format';
  }
  if (!fs.existsSync(nativeBinary)) {
    message = "This module doesn't bundle the clang-format executable for your platform. " +
              "(" + os.platform() + "_" + os.arch() + ")\n" +
              "Consider installing it with your native package manager instead.\n";
    setImmediate(done.bind(new Error(message)));
    return;
  }

  // extract glob, if present
  var filesGlob = args.filter(function(arg){return arg.indexOf('--glob=') === 0;})
                    .map(function(arg){return arg.replace('--glob=', '');})
                    .shift();

  if (filesGlob) {
    // remove glob from arg list
    args = args.filter(function(arg){return arg.indexOf('--glob=') === -1;});

    glob(filesGlob, function(err, files) {
      if (err) {
        done(err);
        return;
      }

      // split file array into chunks of 30
      var i,j, chunks = [], chunkSize = 30;
      for (i=0,j=files.length; i<j; i+=chunkSize) {
          chunks.push( files.slice(i,i+chunkSize));
      }

      // launch a new process for each chunk
      async.series(
          chunks.map(function(chunk) {
            return function(callback) {
              var clangFormatProcess = spawn(nativeBinary, args.concat(chunk), {stdio: stdio});
              clangFormatProcess.on('close', function(exit) {
                if (exit !== 0)
                  callback(errorFromExitCode(exit));
                else
                  callback();
              });
            };
          }),
          function(err) {
            if (err) {
              done(err);
              return;
            }
            console.log('\n');
            console.log('ran clang-format on', files.length, files.length === 1 ? 'file' : 'files');
            done();
          });
    });
  } else {
    var clangFormatProcess = spawn(nativeBinary, args, {stdio: stdio});
    clangFormatProcess.on('close', function(exit) {
      if (exit) done(errorFromExitCode(exit));
      else done();
    });
    return clangFormatProcess;
  }
}

function main() {
  // Find clang-format in node_modules of the project of the .js file, or cwd.
  var nonDashArgs = process.argv.filter(function(arg, idx) { return idx > 1 && arg[0] != '-' });
  // Using the last file makes it less likely to collide with clang-format's argument parsing.
  var lastFileArg = nonDashArgs[nonDashArgs.length - 1];
  var basedir = lastFileArg ? path.dirname(lastFileArg) :  // relative to the last .js file given.
                    process.cwd();                         // or relative to the cwd()
  var resolvedClangFormat;
  var clangFormatLocation;
  try {
    clangFormatLocation = resolve('clang-format', {basedir: basedir});
    resolvedClangFormat = require(clangFormatLocation);
  } catch (e) {
    // Ignore and use the clang-format that came with this package.
  }
  var actualSpawnFn;
  if (!resolvedClangFormat) {
    actualSpawnFn = spawnClangFormat;
  } else if (resolvedClangFormat.spawnClangFormat) {
    actualSpawnFn = resolvedClangFormat.spawnClangFormat;
  } else {
    throw new Error('Incompatible clang-format loaded from ' + clangFormatLocation);
  }
  // Run clang-format.
  try {
    // Pass all arguments to clang-format, including e.g. -version etc.
    actualSpawnFn(process.argv.slice(2), process.exit, 'inherit');
  } catch (e) {
    process.stdout.write(e.message);
    process.exit(1);
  }
}

module.exports = clangFormat;
module.exports.version = VERSION;
module.exports.location = LOCATION;
module.exports.spawnClangFormat = spawnClangFormat;

if (require.main === module) main();
<commit_msg>Print the output of `clang-format --version`, too.<commit_after>#!/usr/bin/env node
'use strict';

var fs = require('fs');
var os = require('os');
var path = require('path');
var resolve = require('resolve').sync;
var spawn = require('child_process').spawn;
var glob = require('glob');
var async = require('async');

var VERSION = require('./package.json').version;
var LOCATION = __filename;

function errorFromExitCode(exitCode) {
  return new Error('clang-format exited with exit code ' + exitCode + '.');
}

/**
 * Start a child process running the native clang-format binary.
 * @param file a Vinyl virtual file reference
 * @param enc the encoding to use for reading stdout
 * @param style valid argument to clang-format's '-style' flag
 * @param done callback invoked when the child process terminates
 * @returns {stream.Readable} the formatted code as a Readable stream
 */
function clangFormat(file, enc, style, done) {
  var args = ['-style=' + style, file.path];
  var result = spawnClangFormat(args, done, ['ignore', 'pipe', process.stderr]);
  if (result) {  // must be ChildProcess
    result.stdout.setEncoding(enc);
    return result.stdout;
  } else {
    // We shouldn't be able to reach this line, because it's not possible to
    // set the --glob arg in this function.
    throw new Error('Can\'t get output stream when --glob flag is set');
  }
}

/**
 * Spawn the clang-format binary with given arguments.
 */
function spawnClangFormat(args, done, stdio) {
  // WARNING: This function's interface should stay stable across versions for the cross-version
  // loading below to work.
  var nativeBinary;
  if (os.platform() === 'win32') {
    nativeBinary = __dirname + '/bin/win32/clang-format.exe';
  } else {
    nativeBinary = __dirname + '/bin/' + os.platform() + '_' + os.arch() + '/clang-format';
  }
  if (!fs.existsSync(nativeBinary)) {
    message = 'This module doesn\'t bundle the clang-format executable for your platform. ' +
        '(' + os.platform() + '_' + os.arch() + ')\n' +
        'Consider installing it with your native package manager instead.\n';
    setImmediate(done.bind(new Error(message)));
    return;
  }
  if (args.indexOf('-version') !== -1 || args.indexOf('--version') !== -1) {
    // Print our version.
    // This makes it impossible to format files called '-version' or '--version'. That's a feature.
    // minimist & Co don't support single dash args, which we need to match binary clang-format.
    console.log('clang-format NPM version', VERSION, 'at', LOCATION);
    args = ['--version'];
  }

  // extract glob, if present
  var filesGlob = args.filter(function(arg) {
                        return arg.indexOf('--glob=') === 0;
                      })
                      .map(function(arg) {
                        return arg.replace('--glob=', '');
                      })
                      .shift();

  if (filesGlob) {
    // remove glob from arg list
    args = args.filter(function(arg) {
      return arg.indexOf('--glob=') === -1;
    });

    glob(filesGlob, function(err, files) {
      if (err) {
        done(err);
        return;
      }

      // split file array into chunks of 30
      var i, j, chunks = [], chunkSize = 30;
      for (i = 0, j = files.length; i < j; i += chunkSize) {
        chunks.push(files.slice(i, i + chunkSize));
      }

      // launch a new process for each chunk
      async.series(
          chunks.map(function(chunk) {
            return function(callback) {
              var clangFormatProcess = spawn(nativeBinary, args.concat(chunk), {stdio: stdio});
              clangFormatProcess.on('close', function(exit) {
                if (exit !== 0)
                  callback(errorFromExitCode(exit));
                else
                  callback();
              });
            };
          }),
          function(err) {
            if (err) {
              done(err);
              return;
            }
            console.log('\n');
            console.log('ran clang-format on', files.length, files.length === 1 ? 'file' : 'files');
            done();
          });
    });
  } else {
    var clangFormatProcess = spawn(nativeBinary, args, {stdio: stdio});
    clangFormatProcess.on('close', function(exit) {
      if (exit) {
        done(errorFromExitCode(exit));
      } else {
        done();
      }
    });
    return clangFormatProcess;
  }
}

function main() {
  // Find clang-format in node_modules of the project of the .js file, or cwd.
  var nonDashArgs = process.argv.filter(function(arg, idx) {
    return idx > 1 && arg[0] != '-';
  });
  // Using the last file makes it less likely to collide with clang-format's argument parsing.
  var lastFileArg = nonDashArgs[nonDashArgs.length - 1];
  var basedir = lastFileArg ? path.dirname(lastFileArg) :  // relative to the last .js file given.
      process.cwd();                                       // or relative to the cwd()
  var resolvedClangFormat;
  var clangFormatLocation;
  try {
    clangFormatLocation = resolve('clang-format', {basedir: basedir});
    resolvedClangFormat = require(clangFormatLocation);
  } catch (e) {
    // Ignore and use the clang-format that came with this package.
  }
  var actualSpawnFn;
  if (!resolvedClangFormat) {
    actualSpawnFn = spawnClangFormat;
  } else if (resolvedClangFormat.spawnClangFormat) {
    actualSpawnFn = resolvedClangFormat.spawnClangFormat;
  } else {
    throw new Error('Incompatible clang-format loaded from ' + clangFormatLocation);
  }
  // Run clang-format.
  try {
    // Pass all arguments to clang-format, including e.g. -version etc.
    actualSpawnFn(process.argv.slice(2), process.exit, 'inherit');
  } catch (e) {
    process.stdout.write(e.message);
    process.exit(1);
  }
}

module.exports = clangFormat;
module.exports.version = VERSION;
module.exports.location = LOCATION;
module.exports.spawnClangFormat = spawnClangFormat;

if (require.main === module) main();
<|endoftext|>


<commit_before>var through2 = require('through2');
var gutil = require('gulp-util');

const PLUGIN_NAME = 'gulp-handlebars';

module.exports = function(opts) {
  'use strict';

  opts = opts || {};
  var compilerOptions = opts.compilerOptions || {};
  var handlebars = opts.handlebars || require('handlebars');

  return through2.obj(function(file, enc, callback) {
    if (file.isNull()) {
      return callback(null, file);
    }

    if (file.isStream()) {
      this.emit('error', new gutil.PluginError(PLUGIN_NAME, 'Streaming not supported'));
      return callback();
    }

    var contents = file.contents.toString();
    var compiled = null;
    var defaultCompiler = function(contents, options) {
      var ast = handlebars.parse(contents);
      // Preprocess AST before compiling
      if (opts.processAST) {
        // processAST may return new AST or change it in place
        ast = opts.processAST(ast) || ast;
      }
      return handlebars.precompile(ast, options).toString();
    };
    // defaultCompiler used to render any handlebars templates
    // `opts.compiler` allows third party to override the internal compiler
    var compiler = (opts.compiler && typeof opts.compiler === 'function') ? opts.compiler : defaultCompiler;
    try {
      compiled = compiler(contents, compilerOptions);
    }
    catch (err) {
      this.emit('error', new gutil.PluginError(PLUGIN_NAME, err, {
        fileName: file.path
      }));
      return callback();
    }

    file.contents = new Buffer(compiled);
    file.path = gutil.replaceExtension(file.path, '.js');

    // Options that take effect when used with gulp-define-module
    file.defineModuleOptions = {
      require: {
        Handlebars: 'handlebars'
      },
      context: {
        handlebars: 'Handlebars.template(<%= contents %>)'
      },
      wrapper: '<%= handlebars %>'
    };

    callback(null, file);
  });
};
<commit_msg>remove the truthy check on `compiler` and use type check only<commit_after>var through2 = require('through2');
var gutil = require('gulp-util');

const PLUGIN_NAME = 'gulp-handlebars';

module.exports = function(opts) {
  'use strict';

  opts = opts || {};
  var compilerOptions = opts.compilerOptions || {};
  var handlebars = opts.handlebars || require('handlebars');

  return through2.obj(function(file, enc, callback) {
    if (file.isNull()) {
      return callback(null, file);
    }

    if (file.isStream()) {
      this.emit('error', new gutil.PluginError(PLUGIN_NAME, 'Streaming not supported'));
      return callback();
    }

    var contents = file.contents.toString();
    var compiled = null;
    var defaultCompiler = function(contents, options) {
      var ast = handlebars.parse(contents);
      // Preprocess AST before compiling
      if (opts.processAST) {
        // processAST may return new AST or change it in place
        ast = opts.processAST(ast) || ast;
      }
      return handlebars.precompile(ast, options).toString();
    };
    // defaultCompiler used to render any handlebars templates
    // `opts.compiler` allows third party to override the internal compiler
    var compiler = (typeof opts.compiler === 'function') ? opts.compiler : defaultCompiler;
    try {
      compiled = compiler(contents, compilerOptions);
    }
    catch (err) {
      this.emit('error', new gutil.PluginError(PLUGIN_NAME, err, {
        fileName: file.path
      }));
      return callback();
    }

    file.contents = new Buffer(compiled);
    file.path = gutil.replaceExtension(file.path, '.js');

    // Options that take effect when used with gulp-define-module
    file.defineModuleOptions = {
      require: {
        Handlebars: 'handlebars'
      },
      context: {
        handlebars: 'Handlebars.template(<%= contents %>)'
      },
      wrapper: '<%= handlebars %>'
    };

    callback(null, file);
  });
};
<|endoftext|>


<commit_before>'use strict';

var React = require('react-native');
var {
  View,
  StyleSheet,
  PanResponder,
  Animated
} = React;

var Overlay         = require('react-native-overlay');
var screen          = require('Dimensions').get('window');

var styles = StyleSheet.create({

  wrapper: {
    flex: 1,
    backgroundColor: "white"
  }

});

var Modal = React.createClass({

  propTypes: {
    isOpen: React.PropTypes.bool,
    swipeToClose: React.PropTypes.bool,
    swipeThreshold: React.PropTypes.number,
    onClosed: React.PropTypes.func,
    onOpened: React.PropTypes.func,
    onClosingState: React.PropTypes.func
  },

  getDefaultProps: function () {
    return {
      isOpen: false,
      swipeToClose: true,
      swipeThreshold: 50,
      aboveStatusBar: true
    };
  },

  getInitialState: function () {
    return {
      position: new Animated.Value(screen.height),
      isAnimateClose: false,
      isAnimateOpen: false,
      swipeToClose: false
    };
  },

  animateOpen: function() {
    if (this.state.isAnimateClose) {
      this.state.animClose.stop();
      this.state.isAnimateClose = false;
    }

    this.state.isAnimateOpen = true;
    this.state.animOpen = Animated.spring(
      this.state.position,
      {
        toValue: 0,
        friction: 8
      }
    );
    this.state.animOpen.start(() => {
      this.state.isAnimateOpen = false;
      if (this.props.onOpened) this.props.onOpened();
    });
  },

  animateClose: function() {
    if (this.state.isAnimateOpen) {
      this.state.animOpen.stop();
      this.state.isAnimateOpen = false;
    }

    this.state.isAnimateClose = true;
    this.state.animClose = Animated.spring(
      this.state.position,
      {
        toValue: screen.height,
        friction: 10
      }
    );
    this.state.animClose.start(() => {
      this.state.isAnimateClose = false;
      this.setState({});
      if (this.props.onClosed) this.props.onClosed();
    });
  },

  createPanResponder: function() {
    var closingState = false;

    var onPanRelease = (evt, state) => {
      if (state.dy > this.props.swipeThreshold)
        this.animateClose();
      else
        this.animateOpen();
    };

    var animEvt = Animated.event([null, {dy: this.state.position}]);

    var onPanMove = (evt, state) => {
      var newClosingState = (state.dy > this.props.swipeThreshold) ? true : false;

      if (state.dy < 0) return;
      if (newClosingState != closingState && this.props.onClosingState)
        this.props.onClosingState(newClosingState);
      closingState = newClosingState;

      animEvt(evt, state);
    };

    this.state.pan = PanResponder.create({
      onStartShouldSetPanResponder: () => true,
      onMoveShouldSetPanResponder: () => true,
      onPanResponderMove: onPanMove,
      onPanResponderRelease: onPanRelease,
      onPanResponderTerminate: onPanRelease,
    });
  },

  componentWillReceiveProps: function(props) {
    if (props.isOpen && !this.state.isAnimateOpen) {
      this.animateOpen();
    }
    else if (!props.isOpen && !this.state.isAnimateClose)
      this.animateClose();

    if (props.swipeToClose != this.state.swipeToClose) {
      this.state.swipeToClose = props.swipeToClose;
      if (props.swipeToClose)
        this.createPanResponder();
      else
        this.state.pan = null;
    }
  },

  render: function() {
    var visible  = this.props.isOpen || this.state.isAnimateOpen || this.state.isAnimateClose;
    var pan = this.state.pan ? this.state.pan.panHandlers : {};

    return (
      <Overlay isVisible={visible} aboveStatusBar={this.props.aboveStatusBar}>
        <Animated.View style={[styles.wrapper, this.props.style, {transform: [{translateY: this.state.position}]} ]} {...pan}>
          {this.props.children}
        </Animated.View>
      </Overlay>
    );
  }

});

module.exports = Modal;<commit_msg>open / close methods added, isOpen property no longer available position feature added backdrop feature added code refactored bug fixes<commit_after>'use strict';

var React = require('react-native');
var {
  View,
  StyleSheet,
  PanResponder,
  Animated,
  TouchableWithoutFeedback
} = React;

var Overlay         = require('react-native-overlay');
var screen          = require('Dimensions').get('window');

var styles = StyleSheet.create({

  wrapper: {
    backgroundColor: "white",
    position: "absolute",
    height: screen.height,
    width: screen.width
  },

  backdrop: {
    position: "absolute",
    top: 0,
    bottom: 0,
    left: 0,
    right: 0,
    height: screen.height,
    width: screen.width
  }

});

var Modal = React.createClass({

  propTypes: {
    swipeToClose: React.PropTypes.bool,
    swipeThreshold: React.PropTypes.number,
    onClosed: React.PropTypes.func,
    onOpened: React.PropTypes.func,
    onClosingState: React.PropTypes.func,
    position: React.PropTypes.string,
    backdrop: React.PropTypes.bool,
    backdropOpacity: React.PropTypes.number,
    backdropColor: React.PropTypes.string,
    backdropContent: React.PropTypes.element
  },

  getDefaultProps: function () {
    return {
      isOpen: false,
      swipeToClose: true,
      swipeThreshold: 50,
      aboveStatusBar: true,
      position: "center",
      backdrop: true,
      backdropOpacity: 0.5,
      backdropColor: "black",
      backdropContent: null
    };
  },

  getInitialState: function () {
    return {
      position: new Animated.Value(screen.height),
      backdropOpacity: new Animated.Value(0),
      isAnimateClose: false,
      isAnimateOpen: false,
      swipeToClose: false,
      height: screen.height,
      width: screen.width
    };
  },

  componentDidMount: function() {
    if (this.props.swipeToClose)
      this.createPanResponder();
  },

  /****************** ANIMATIONS **********************/

  /*
   * Open animation for the backdrop, will fade in
   */
  animateBackdropOpen: function() {
    if (this.state.isAnimateBackdrop) {
      this.state.animBackdrop.stop();
      this.state.isAnimateBackdrop = false;
    }

    this.state.isAnimateBackdrop = true;
    this.state.animBackdrop = Animated.timing(
      this.state.backdropOpacity,
      {
        toValue: 1
      }
    );
    this.state.animBackdrop.start(() => {
      this.state.isAnimateBackdrop = false;
    });
  },

  /*
   * Close animation for the backdrop, will fade out
   */
  animateBackdropClose: function() {
    if (this.state.isAnimateBackdrop) {
      this.state.animBackdrop.stop();
      this.state.isAnimateBackdrop = false;
    }

    this.state.isAnimateBackdrop = true;
    this.state.animBackdrop = Animated.timing(
      this.state.backdropOpacity,
      {
        toValue: 0
      }
    );
    this.state.animBackdrop.start(() => {
      this.state.isAnimateBackdrop = false;
    });
  },

  /*
   * Open animation for the modal, will move up
   */
  animateOpen: function() {
    if (this.state.isAnimateClose) {
      this.state.animClose.stop();
      this.state.isAnimateClose = false;
    }

    // Backdrop fadeIn
    if (this.props.backdrop)
      this.animateBackdropOpen();

    // Detecting modal position
    this.state.positionDest = 0;
    if (this.props.position == "bottom") {
      this.state.positionDest = screen.height - this.state.height;
    }
    else if (this.props.position == "center") {
      this.state.positionDest = screen.height / 2 - this.state.height / 2;
    }

    this.state.isAnimateOpen = true;
    this.state.animOpen = Animated.spring(
      this.state.position,
      {
        toValue: this.state.positionDest,
        friction: 8
      }
    );
    this.state.animOpen.start(() => {
      this.state.isAnimateOpen = false;
      if (this.props.onOpened) this.props.onOpened();
    });
  },

  /*
   * Close animation for the modal, will move down
   */
  animateClose: function() {
    if (this.state.isAnimateOpen) {
      this.state.animOpen.stop();
      this.state.isAnimateOpen = false;
    }

    // Backdrop fadeout
    if (this.props.backdrop)
      this.animateBackdropClose();

    this.state.isAnimateClose = true;
    this.state.animClose = Animated.timing(
      this.state.position,
      {
        toValue: screen.height,
        duration: 400
      }
    );
    this.state.animClose.start(() => {
      this.state.isAnimateClose = false;
      this.setState({});
      if (this.props.onClosed) this.props.onClosed();
    });
  },

  /*
   * Create the pan responder to detect gesture
   * Only used if swipeToClose is enabled
   */
  createPanResponder: function() {
    var closingState = false;

    var onPanRelease = (evt, state) => {
      if (state.dy > this.props.swipeThreshold)
        this.animateClose();
      else
        this.animateOpen();
    };

    var animEvt = Animated.event([null, {customY: this.state.position}]);

    var onPanMove = (evt, state) => {
      var newClosingState = (state.dy > this.props.swipeThreshold) ? true : false;
      if (state.dy < 0) return;
      if (newClosingState != closingState && this.props.onClosingState)
        this.props.onClosingState(newClosingState);
      closingState = newClosingState;
      state.customY = state.dy + this.state.positionDest;

      animEvt(evt, state);
    };

    this.state.pan = PanResponder.create({
      onStartShouldSetPanResponder: () => true,
      onMoveShouldSetPanResponder: () => true,
      onPanResponderMove: onPanMove,
      onPanResponderRelease: onPanRelease,
      onPanResponderTerminate: onPanRelease,
    });
  },

  /*
   * Event called when the modal view layout is calculated
   */
  onViewLayout: function(evt) {
    this.state.height = evt.nativeEvent.layout.height;
    this.state.width = evt.nativeEvent.layout.width;
    if (this.onViewLayoutCalculated) this.onViewLayoutCalculated();
  },

  /*
   * Render the backdrop element
   */
  renderBackdrop: function() {
    var backdrop  = [];

    if (this.props.backdrop) {
      backdrop = (
        <TouchableWithoutFeedback onPress={this.animateClose}>
          <Animated.View style={[styles.backdrop, {opacity: this.state.backdropOpacity}]}>
            <View style={[styles.backdrop, {backgroundColor:this.props.backdropColor, opacity: this.props.backdropOpacity}]}/>
            {this.props.backdropContent || []}
          </Animated.View>
        </TouchableWithoutFeedback>
      );
    }

    return backdrop;
  },

  /*
   * Render the component
   */
  render: function() {
    var visible   = this.state.isAnimateOpen || this.state.isAnimateClose;
    var pan       = this.state.pan ? this.state.pan.panHandlers : {};
    var offsetX   = (screen.width - this.state.width) / 2;
    var backdrop  = this.renderBackdrop();

    return (
      <Overlay isVisible={visible} aboveStatusBar={this.props.aboveStatusBar}>
        {backdrop}
        <Animated.View
         onLayout={this.onViewLayout}
         style={[styles.wrapper, this.props.style, {transform: [{translateY: this.state.position}, {translateX: offsetX}]} ]}
         {...pan}>
          {this.props.children}
        </Animated.View>
      </Overlay>
    );
  },

  /****************** PUBLIC METHODS **********************/

  open: function() {
    if (!this.state.isAnimateOpen) {
      this.onViewLayoutCalculated = () => {
        this.setState({});
        this.animateOpen();
      };
      this.setState({isAnimateOpen : true});
    }
  },

  close: function() {
    if (!this.state.isAnimateClose) {
      this.animateClose();
    }
  }

});

module.exports = Modal;<|endoftext|>


<commit_before>// inspired by https://github.com/NYTimes/Emphasis

var crypto = require('crypto')
  , sbd = require('sbd')
  , uuid = require('uuid')
  , levenshtein = require('fast-levenshtein');

var citeable = exports.citeable = ['P', 'LI', 'DD', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'FIGCAPTION', 'CAPTION', 'ASIDE'];

/**
 * From a block element, generate a Key
 * - Break block element text content into Sentences
 * - Take first and last Sentences
 * - Sometimes the same. Thats ok.
 * - First character from the first three words of each sentence
 * - Each 6 char key refers to specific block element
 */
var createKey = exports.createKey = function($el) {
  var key = '';
  var len = 6;
  var txt = ($el.textContent || '').replace(/[^a-z\. ]+/gi, '').trim();

  if (txt && txt.length>1) {
    var lines = sbd.sentences(txt)
          .map(function(x) {return x.trim();})
          .filter(function(x) {return x;});

    if (lines.length) {
      var first = lines[0].match(/\S+/g).slice(0, (len/2));
      var last = lines[lines.length-1].match(/\S+/g).slice(0, (len/2));
      var k = first.concat(last);

      var max = (k.length > len) ? len : k.length;

      for (var i=0; i < max; i++) {
        key += k[i].substring(0, 1);
      }
    }
  }

  return key;
};

var createHash = exports.createHash = function($el, algorithm) {
  algorithm = algorithm || 'sha1';
  return crypto.createHash(algorithm).update($el.textContent.trim(), 'utf8').digest('hex'); //TODO textContent.replace(/\s+/g, ' ') ??
};

var getScope = exports.getScope = function(range) {
  var $scope = range.commonAncestorContainer;
  if ($scope.nodeType === Node.TEXT_NODE) {
    $scope = $scope.parentElement; //get closest Element
  };

  // TODO generalize to list of supported block elements
  // get closest citeable element
  while (!~citeable.indexOf($scope.tagName)) {
    $scope = $scope.parentElement;
    if ($scope.tagName === 'HTML') {
      return;
    }
  }
  return $scope;
};

var getOffsets = exports.getOffsets = function(range, $scope) {

  var startTextNode, endTextNode;
  if (range.startContainer.nodeType === Node.TEXT_NODE) {
    startTextNode = range.startContainer;
  } else {
    for (var i=0; i < range.startContainer.childNodes.length; i++) {
      if (range.startContainer.childNodes[i].nodeType === Node.TEXT_NODE) {
        startTextNode = range.startContainer.childNodes[i];
        break;
      }
    }
  }

  if (range.endContainer.nodeType === Node.TEXT_NODE) {
    endTextNode = range.endContainer;
  } else {
    for (var j=0; j < range.endContainer.childNodes.length; j++) {
      if (range.endContainer.childNodes[j].nodeType === Node.TEXT_NODE) {
        endTextNode = range.endContainer.childNodes[j];
        break;
      }
    }
  }

  var node, indStartTextNode, indEndTextNode, ind=0, textNodes = [];
  var it = document.createNodeIterator($scope, NodeFilter.SHOW_TEXT);
  while (node = it.nextNode()) {
    textNodes.push(node);
    if (node === startTextNode) {
      indStartTextNode = ind;
    }
    if (node === endTextNode) {
      indEndTextNode = ind;
      break;
    }
    ind++;
  }

  var startOffset = textNodes.slice(0, indStartTextNode).reduce(function(a, b){
    return a + b.textContent.trim().length;
  }, 0);

  if (range.startOffset !== undefined) {
    startOffset += range.startOffset - (startTextNode.textContent.length - startTextNode.textContent.replace(/^\s+/, '').length); //we substract the effect of having trimmed the textContent
  }

  var endOffset = textNodes.slice(0, indEndTextNode).reduce(function(a, b){
    return a + b.textContent.trim().length;
  }, 0);
  if (range.endOffset !== undefined) {
    endOffset += range.endOffset - (endTextNode.textContent.length - endTextNode.textContent.replace(/^\s+/, '').length); //we substract the effect of having trimmed the textContent;
  }

  return {startOffset: startOffset, endOffset: endOffset};
};

var serializeRange = exports.serializeRange = function(range, $scope) {
  var $scope = $scope || getScope(range);
  if (!$scope) return;

  var offsets = getOffsets(range, $scope);

  return {
    $scope: $scope,
    sha1: createHash($scope),
    key: createKey($scope),
    startOffset: offsets.startOffset,
    endOffset: offsets.endOffset,
    text: range.toString().trim()
  };
};

//key:start-end
exports.serializeSelection = function() {
  var selection = window.getSelection();
  var range;
  if (!selection.isCollapsed) {
    range = selection.getRangeAt(0);
  } else {
    return;
  }

  return serializeRange(range);
};

var rangeFromOffsets = exports.rangeFromOffsets = function($scope, startOffset, endOffset) {
  var node;
  var it = document.createNodeIterator($scope, NodeFilter.SHOW_TEXT);
  var acc = 0;
  var startNode, endNode, relStartOffset, relEndOffset;
  var textContent;

  while (node = it.nextNode()) {
    textContent = node.textContent.trim();
    if (relStartOffset === undefined && ((acc + textContent.length) >= startOffset)) {
      startNode = node;
      relStartOffset = startOffset - acc + (startNode.textContent.length - startNode.textContent.replace(/^\s+/, '').length); //we add back the effect of having trimmed the textContent;
    }
    if (relEndOffset === undefined && ((acc + textContent.length) >= endOffset)) {
      endNode = node;
      relEndOffset = endOffset-acc + (endNode.textContent.length - endNode.textContent.replace(/^\s+/, '').length); //we add back the effect of having trimmed the textContent;
      break;
    }
    acc += textContent.length;
  }

  var range = document.createRange();
  range.setStart(startNode, relStartOffset);
  range.setEnd(endNode, relEndOffset);

  return range;
};

exports.findKey = function(target, candidates) {
  var x = {index: undefined, value: undefined, lev: undefined};

  for (var i=0; i < candidates.length; i++) {
    if (target === candidates[i]) {
      return {index: i, value: candidates[i], lev: 0};
    } else { //look for 1st closest Match
      var ls = levenshtein.get(target.slice(0, 3), candidates[i].slice(0, 3));
      var le = levenshtein.get(target.slice(-3), candidates[i].slice(-3));
      var lev = ls+le;
      if (lev < 3 && ((x.lev === undefined) || (lev < x.lev)) ) {
        x.index = i;
        x.value = candidates[i];
        x.lev = lev;
      }
    }
  }

  return x;
};

exports.addIdentifiers = function($doc) {
  Array.prototype.forEach.call($doc.body.getElementsByTagName('*'), function($el) {
    $el.setAttribute('data-id', uuid.v1());
    $el.setAttribute('data-hash', createHash($el));
    if (~citeable.indexOf($el.tagName)) {
      $el.setAttribute('data-key', createKey($el));
    }
  });
  return $doc;
};

exports.getChildOffsets = function($parent, $child) {
  var startTextNode;
  if ($child.nodeType === Node.TEXT_NODE) {
    startTextNode = $child;
  } else {
    for (var i = 0; i < $child.childNodes.length; i++) {
      if ($child.childNodes[i].nodeType === Node.TEXT_NODE) {
        startTextNode = $child.childNodes[i];
        break;
      }
    }
  }

  var node, indStartTextNode, ind = 0, textNodes = [];
  var it = document.createNodeIterator($parent, NodeFilter.SHOW_TEXT);
  while (node = it.nextNode()) {
    textNodes.push(node);
    if (node === startTextNode) {
      indStartTextNode = ind;
      break;
    }
    ind++;
  }

  var startOffset = textNodes.slice(0, indStartTextNode).reduce(function(a, b) {
    return a + b.textContent.trim().length;
  }, 0);

  var endOffset = textNodes.slice(0, indStartTextNode + 1).reduce(function(a, b) {
    return a + b.textContent.trim().length;
  }, 0);

  return { startOffset: startOffset, endOffset: endOffset };
};

exports.getSerializationsFromText = function($scope, text) {
  text = text.trim();
  var re = new RegExp(text, 'ig');
  var textNode;
  var textContent = '';
  var it = document.createNodeIterator($scope, NodeFilter.SHOW_TEXT);
  while (textNode = it.nextNode()) {
    textContent += textNode.textContent.trim();
  }

  var result;
  var matchIndexes = [];
  while ((result = re.exec(textContent)) !== null) {
    matchIndexes.push(result.index);
  }

  return matchIndexes.map(function(index) {
    return serializeRange(rangeFromOffsets($scope, index, index + text.length), $scope);
  });
};
<commit_msg>instead of using a citable whitelist, use a blacklist<commit_after>// inspired by https://github.com/NYTimes/Emphasis

var crypto = require('crypto')
  , sbd = require('sbd')
  , uuid = require('uuid')
  , levenshtein = require('fast-levenshtein');

var notCiteable = ['SCRIPT', 'STYLE', 'NOSCRIPT'];

/**
 * From a block element, generate a Key
 * - Break block element text content into Sentences
 * - Take first and last Sentences
 * - Sometimes the same. Thats ok.
 * - First character from the first three words of each sentence
 * - Each 6 char key refers to specific block element
 */
var createKey = exports.createKey = function($el) {
  var key = '';
  var len = 6;
  var txt = ($el.textContent || '').replace(/[^a-z\. ]+/gi, '').trim();

  if (txt && txt.length>1) {
    var lines = sbd.sentences(txt)
      .map(function(x) {return x.trim();})
      .filter(function(x) {return x;});

    if (lines.length) {
      var first = lines[0].match(/\S+/g).slice(0, (len/2));
      var last = lines[lines.length-1].match(/\S+/g).slice(0, (len/2));
      var k = first.concat(last);

      var max = (k.length > len) ? len : k.length;

      for (var i=0; i < max; i++) {
        key += k[i].substring(0, 1);
      }
    }
  }

  return key;
};

var createHash = exports.createHash = function($el, algorithm) {
  algorithm = algorithm || 'sha1';
  return crypto.createHash(algorithm).update($el.textContent.trim(), 'utf8').digest('hex'); //TODO textContent.replace(/\s+/g, ' ') ??
};

var getScope = exports.getScope = function(range) {
  var $scope = range.commonAncestorContainer;
  if ($scope.nodeType === Node.TEXT_NODE) {
    $scope = $scope.parentElement; //get closest Element
  }

  // get closest citeable element
  while (~notCiteable.indexOf($scope.tagName)) {
    $scope = $scope.parentElement;
    if ($scope.tagName === 'HTML') {
      return;
    }
  }
  return $scope;
};

var getOffsets = exports.getOffsets = function(range, $scope) {

  var startTextNode, endTextNode;
  if (range.startContainer.nodeType === Node.TEXT_NODE) {
    startTextNode = range.startContainer;
  } else {
    for (var i=0; i < range.startContainer.childNodes.length; i++) {
      if (range.startContainer.childNodes[i].nodeType === Node.TEXT_NODE) {
        startTextNode = range.startContainer.childNodes[i];
        break;
      }
    }
  }

  if (range.endContainer.nodeType === Node.TEXT_NODE) {
    endTextNode = range.endContainer;
  } else {
    for (var j=0; j < range.endContainer.childNodes.length; j++) {
      if (range.endContainer.childNodes[j].nodeType === Node.TEXT_NODE) {
        endTextNode = range.endContainer.childNodes[j];
        break;
      }
    }
  }

  var node, indStartTextNode, indEndTextNode, ind=0, textNodes = [];
  var it = document.createNodeIterator($scope, NodeFilter.SHOW_TEXT);
  while (node = it.nextNode()) {
    textNodes.push(node);
    if (node === startTextNode) {
      indStartTextNode = ind;
    }
    if (node === endTextNode) {
      indEndTextNode = ind;
      break;
    }
    ind++;
  }

  var startOffset = textNodes.slice(0, indStartTextNode).reduce(function(a, b){
    return a + b.textContent.trim().length;
  }, 0);

  if (range.startOffset !== undefined) {
    startOffset += range.startOffset - (startTextNode.textContent.length - startTextNode.textContent.replace(/^\s+/, '').length); //we substract the effect of having trimmed the textContent
  }

  var endOffset = textNodes.slice(0, indEndTextNode).reduce(function(a, b){
    return a + b.textContent.trim().length;
  }, 0);
  if (range.endOffset !== undefined) {
    endOffset += range.endOffset - (endTextNode.textContent.length - endTextNode.textContent.replace(/^\s+/, '').length); //we substract the effect of having trimmed the textContent;
  }

  return {startOffset: startOffset, endOffset: endOffset};
};

var serializeRange = exports.serializeRange = function(range, $scope) {
  var $scope = $scope || getScope(range);
  if (!$scope) return;

  var offsets = getOffsets(range, $scope);

  return {
    $scope: $scope,
    sha1: createHash($scope),
    key: createKey($scope),
    startOffset: offsets.startOffset,
    endOffset: offsets.endOffset,
    text: range.toString().trim()
  };
};

//key:start-end
exports.serializeSelection = function() {
  var selection = window.getSelection();
  var range;
  if (!selection.isCollapsed) {
    range = selection.getRangeAt(0);
  } else {
    return;
  }

  return serializeRange(range);
};

var rangeFromOffsets = exports.rangeFromOffsets = function($scope, startOffset, endOffset) {
  var node;
  var it = document.createNodeIterator($scope, NodeFilter.SHOW_TEXT);
  var acc = 0;
  var startNode, endNode, relStartOffset, relEndOffset;
  var textContent;

  while (node = it.nextNode()) {
    textContent = node.textContent.trim();
    if (relStartOffset === undefined && ((acc + textContent.length) >= startOffset)) {
      startNode = node;
      relStartOffset = startOffset - acc + (startNode.textContent.length - startNode.textContent.replace(/^\s+/, '').length); //we add back the effect of having trimmed the textContent;
    }
    if (relEndOffset === undefined && ((acc + textContent.length) >= endOffset)) {
      endNode = node;
      relEndOffset = endOffset-acc + (endNode.textContent.length - endNode.textContent.replace(/^\s+/, '').length); //we add back the effect of having trimmed the textContent;
      break;
    }
    acc += textContent.length;
  }

  var range = document.createRange();
  range.setStart(startNode, relStartOffset);
  range.setEnd(endNode, relEndOffset);

  return range;
};

exports.findKey = function(target, candidates) {
  var x = {index: undefined, value: undefined, lev: undefined};

  for (var i=0; i < candidates.length; i++) {
    if (target === candidates[i]) {
      return {index: i, value: candidates[i], lev: 0};
    } else { //look for 1st closest Match
      var ls = levenshtein.get(target.slice(0, 3), candidates[i].slice(0, 3));
      var le = levenshtein.get(target.slice(-3), candidates[i].slice(-3));
      var lev = ls+le;
      if (lev < 3 && ((x.lev === undefined) || (lev < x.lev)) ) {
        x.index = i;
        x.value = candidates[i];
        x.lev = lev;
      }
    }
  }

  return x;
};

exports.addIdentifiers = function($doc) {
  Array.prototype.forEach.call($doc.body.getElementsByTagName('*'), function($el) {
    $el.setAttribute('data-id', uuid.v1());
    $el.setAttribute('data-hash', createHash($el));
    if (~citeable.indexOf($el.tagName)) {
      $el.setAttribute('data-key', createKey($el));
    }
  });
  return $doc;
};

exports.getChildOffsets = function($parent, $child) {
  var startTextNode;
  if ($child.nodeType === Node.TEXT_NODE) {
    startTextNode = $child;
  } else {
    for (var i = 0; i < $child.childNodes.length; i++) {
      if ($child.childNodes[i].nodeType === Node.TEXT_NODE) {
        startTextNode = $child.childNodes[i];
        break;
      }
    }
  }

  var node, indStartTextNode, ind = 0, textNodes = [];
  var it = document.createNodeIterator($parent, NodeFilter.SHOW_TEXT);
  while (node = it.nextNode()) {
    textNodes.push(node);
    if (node === startTextNode) {
      indStartTextNode = ind;
      break;
    }
    ind++;
  }

  var startOffset = textNodes.slice(0, indStartTextNode).reduce(function(a, b) {
    return a + b.textContent.trim().length;
  }, 0);

  var endOffset = textNodes.slice(0, indStartTextNode + 1).reduce(function(a, b) {
    return a + b.textContent.trim().length;
  }, 0);

  return { startOffset: startOffset, endOffset: endOffset };
};

exports.getSerializationsFromText = function($scope, text) {
  text = text.trim();
  var re = new RegExp(text, 'ig');
  var textNode;
  var textContent = '';
  var it = document.createNodeIterator($scope, NodeFilter.SHOW_TEXT);
  while (textNode = it.nextNode()) {
    textContent += textNode.textContent.trim();
  }

  var result;
  var matchIndexes = [];
  while ((result = re.exec(textContent)) !== null) {
    matchIndexes.push(result.index);
  }

  return matchIndexes.map(function(index) {
    return serializeRange(rangeFromOffsets($scope, index, index + text.length), $scope);
  });
};
<|endoftext|>


<commit_before>// Started as a PDF.js example file, originally licensed public domain

var fs = require('fs'),
    util = require('util'),
    dsv = require('d3-dsv'),
    path = require('path');

global.DOMParser = require('./lib/domparsermock.js').DOMParserMock;

var pdfjsLib = require('pdfjs-dist');

var filePath = __dirname + '/test/data/';

function processFiling(pdfPath) {
    var data = new Uint8Array(fs.readFileSync(pdfPath));

    var tables = [];

    var ignoreRest = false;

    return pdfjsLib.getDocument(data).then(function(doc) {
        var numPages = doc.numPages;

        var lastPromise; // will be used to chain promises

        var loadPage = function(pageNum) {
            return doc.getPage(pageNum).then(function(page) {
                var viewport = page.getViewport(1.0 /* scale */ );

                return page.getTextContent().then(function(content) {
                    var boldFont = '';

                    var styleKeys = Object.keys(content.styles);
                    styleKeys.forEach(function (styleKey) {
                        if (content.styles[styleKey].fontFamily == 'sans-serif' &&
                            content.styles[styleKey].descent < -0.295) {
                            boldFont = styleKey;
                        }
                    });

                    var ignorePage = false;
                    var rowY = 0;

                    content.items.sort(function (a,b) {
                        if (a.transform[4]-b.transform[4] !== 0) {
                            return a.transform[4]-b.transform[4];
                        }
                        else {
                            return a.transform[5]-b.transform[5];
                        }
                    }).forEach(function (item,i) {
                        if (item.str.indexOf('Data Revised') !== -1) {
                            ignorePage = true;
                        }

                        if (!ignorePage && !ignoreRest) {
                            if (item.height == 14) {
                                if (item.str == 'Filer\'s Information') {
                                    ignorePage = true;
                                }
                                else if (item.str == 'Summary of Contents') {
                                    ignoreRest = true;
                                }
                                else if (item.str.trim().length > 2) {
                                    var headerParts = item.str.split('. ');
                                    var part = null,
                                        name = null;

                                    if (headerParts.length > 1) {
                                        part = parseInt(headerParts[0]);
                                        name = headerParts.slice(1).join('. ');
                                    }
                                    else {
                                        name = item.str;
                                    }

                                    tables.push({
                                        part: part,
                                        name: name,
                                        cols: [],
                                        rows: []
                                    });
                                }
                            }
                            else if (item.height == 10) {
                                var curTable = tables[tables.length-1];

                                if (item.fontName == boldFont) {
                                    if (item.str == 'PART' || (item.str == '#' && curTable.cols.length > 1)) {
                                        curTable.cols = [];
                                    }

                                    var append = true;

                                    curTable.cols.forEach(function (col) {
                                        if (col.x == item.transform[5]) {
                                            col.name += ' ' + item.str;
                                            col.slug = col.name.toLowerCase().replace(/[ ,]+/g,'-');
                                            append = false;
                                        }
                                    });

                                    if (append) {
                                        curTable.cols.push({
                                            name: item.str,
                                            slug: item.str.toLowerCase().replace(/[ ,]+/g,'-'),
                                            x: item.transform[5],
                                            y: item.transform[4]
                                        });
                                    }
                                }
                                else {
                                    curTable.cols.forEach(function (col,i2) {
                                        if (col.x == item.transform[5]) {
                                            if (i2 === 0 && item.transform[4]-rowY > 12) {
                                                curTable.rows.push({});
                                                rowY = item.transform[4];
                                            }
                                            var curRow = curTable.rows[curTable.rows.length-1];

                                            if (col.slug in curRow) {
                                                if (col.slug !== '#') {
                                                    curRow[col.slug] += ' ';
                                                }
                                                curRow[col.slug] += item.str;
                                            }
                                            else {
                                                curRow[col.slug] = item.str;
                                            }
                                        }
                                    });
                                }
                            }
                        }
                    });

                });
            });
        };

        lastPromise = loadPage(2);
        for (var i = 3; i <= numPages-4; i++) {
            lastPromise = lastPromise.then(loadPage.bind(null, i));
        }
        return lastPromise;
    }).then(function() {
        var fileName = path.basename(pdfPath,'.pdf');

        return new Promise(function (resolve,reject) {
            tables.forEach(function (table) {
                var csvFile = filePath + table.name.toLowerCase().replace(/[ ,']+/g,'-') + '.csv';

                table.rows.forEach(function (row) {
                    row.file = fileName;
                });

                if (table.cols.length > 0) {
                    fs.appendFileSync(csvFile,dsv.csvFormat(table.rows,['file'].concat(table.cols.map(function (col) {
                        return col.slug;
                    })))+'\n');
                }
            });

            resolve();
        });
    });
}

var files = fs.readdirSync(filePath).filter(function (file) {
    return file.indexOf('.pdf') !== -1;
});

var filingPromise = processFiling(filePath + files[0]);
for (var pos = 1; pos < files.length; pos++) {
    filingPromise = filingPromise.then(processFiling.bind(null,filePath + files[pos]));
}
filingPromise.then(function () {
    console.log('done');
});
<commit_msg>WIP - Fixes for D4D hack<commit_after>// Started as a PDF.js example file, originally licensed public domain

var fs = require('fs'),
    util = require('util'),
    dsv = require('d3-dsv'),
    path = require('path');

global.DOMParser = require('./lib/domparsermock.js').DOMParserMock;

var pdfjsLib = require('pdfjs-dist');

var filePath = __dirname + '/test/data/';

function processFiling(pdfPath, includeHeader) {
    var data = new Uint8Array(fs.readFileSync(pdfPath));

    var tables = [];

    var ignoreRest = false;

    return pdfjsLib.getDocument(data).then(function(doc) {
        var numPages = doc.numPages;

        var lastPromise; // will be used to chain promises

        var loadPage = function(pageNum) {
            return doc.getPage(pageNum).then(function(page) {
                var viewport = page.getViewport(1.0 /* scale */ );

                return page.getTextContent().then(function(content) {
                    var boldFont = '';

                    var styleKeys = Object.keys(content.styles);
                    styleKeys.forEach(function (styleKey) {
                        if (content.styles[styleKey].fontFamily == 'sans-serif' &&
                            content.styles[styleKey].descent < -0.295) {
                            boldFont = styleKey;
                        }
                    });

                    var ignorePage = false;
                    var rowY = 0;

                    content.items.sort(function (a,b) {
                        if (a.transform[4]-b.transform[4] !== 0) {
                            return a.transform[4]-b.transform[4];
                        }
                        else {
                            return a.transform[5]-b.transform[5];
                        }
                    }).forEach(function (item,i) {
                        if (item.str.indexOf('Data Revised') !== -1) {
                            ignorePage = true;
                        }

                        if (!ignorePage && !ignoreRest) {
                            if (item.height == 14) {
                                if (item.str == 'Filer\'s Information') {
                                    ignorePage = true;
                                }
                                else if (item.str == 'Summary of Contents') {
                                    ignoreRest = true;
                                }
                                else if (item.str.trim().length > 2) {
                                    var headerParts = item.str.split('. ');
                                    var part = null,
                                        name = null;

                                    if (headerParts.length > 1) {
                                        part = parseInt(headerParts[0]);
                                        name = headerParts.slice(1).join('. ');
                                    }
                                    else {
                                        name = item.str;
                                    }

                                    tables.push({
                                        part: part,
                                        name: name,
                                        cols: [],
                                        rows: []
                                    });
                                }
                            }
                            else if (item.height == 10) {
                                var curTable = tables[tables.length-1];
                                if (curTable) {

                                    if (item.fontName == boldFont) {
                                        if (item.str == 'PART' || (item.str == '#' && curTable.cols.length > 1)) {
                                            curTable.cols = [];
                                        }

                                        var append = true;

                                        curTable.cols.forEach(function (col) {
                                            if (col.x == item.transform[5]) {
                                                col.name += ' ' + item.str;
                                                col.slug = col.name.toLowerCase().replace(/[ ,]+/g, '-');
                                                append = false;
                                            }
                                        });

                                        if (append) {
                                            curTable.cols.push({
                                                name: item.str,
                                                slug: item.str.toLowerCase().replace(/[ ,]+/g, '-'),
                                                x: item.transform[5],
                                                y: item.transform[4]
                                            });
                                        }
                                    }
                                    else {
                                        curTable.cols.forEach(function (col, i2) {
                                            if (col.x == item.transform[5]) {
                                                if (i2 === 0 && item.transform[4] - rowY > 12) {
                                                    curTable.rows.push({});
                                                    rowY = item.transform[4];
                                                }
                                                var curRow = curTable.rows[curTable.rows.length - 1];

                                                if (col.slug in curRow) {
                                                    if (col.slug !== '#') {
                                                        curRow[col.slug] += ' ';
                                                    }
                                                    curRow[col.slug] += item.str;
                                                }
                                                else {
                                                    curRow[col.slug] = item.str;
                                                }
                                            }
                                        });
                                    }
                                }
                            }
                        }
                    });

                });
            });
        };

        lastPromise = loadPage(2);
        for (var i = 3; i <= numPages-4; i++) {
            lastPromise = lastPromise.then(loadPage.bind(null, i));
        }
        return lastPromise;
    }).then(function() {
        var fileName = path.basename(pdfPath,'.pdf');

        return new Promise(function (resolve, reject) {
            tables.forEach(function (table) {
                var csvFile = filePath + table.name.toLowerCase().replace(/[ ,']+/g,'-') + '.csv';

                table.rows.forEach(function (row) {
                    row.file = fileName;
                });

                if (table.cols.length > 0) {
                    var columns = ['file'].concat(table.cols.map(function (col) {
                        return col.slug;
                    }));
                    if (includeHeader) {
                        fs.appendFileSync(csvFile, dsv.csvFormat(table.rows, columns) + '\n');
                    } else {
                        fs.appendFileSync(csvFile, dsv.csvFormat(table.rows, columns) + '\n');
                    }
                }
            });

            resolve();
        });
    });
}

var files = fs.readdirSync(filePath).filter(function (file) {
    return file.indexOf('.pdf') !== -1;
});

var filingPromise = processFiling(filePath + files[0], true).catch();
for (var pos = 1; pos < files.length; pos++) {
    filingPromise = filingPromise
        .then(processFiling.bind(null, filePath + files[pos], false), function(reason) { console.log(reason) });
}
filingPromise.then(function () {
    console.log('done');
});
<|endoftext|>


<commit_before>
var through = require('through'),
    fs      = require('fs'),
    path    = require('path');

module.exports = function (options) {

  if (typeof options === 'undefined') {
    options = {};
  }

  if (typeof options.path === 'undefined') {
    options.path = 'tsconfig.json';
  }

  if (typeof options.indent === 'undefined') {
    options.indent = 2;
  }

  if (typeof options.absolute === 'undefined') {
    options.absolute = false;
  }

  if (typeof options.newline_eof === 'undefined') {
    options.newline_eof = false;
  }

  if (typeof options.relative_dir === 'undefined') {
    options.relative_dir = '.';
  }

  if (typeof options.posix === 'undefined') {
    options.posix = false;
  }

  var readConfig = function (callback) {
    fs.readFile(options.path, function (err, data) {
      if (err) {
        callback(err, null)
      } else {
        try {
          callback(null, JSON.parse(data));
        } catch (err) {
          callback(err, null);
        }
      }
    });
  };

  var writeConfig = function (config, callback) {
    try {
      var data = JSON.stringify(config, null, options.indent);
    } catch (err) {
      callback(err);
      return;
    }
    if (options.newline_eof) {
      data += "\n";
    }
    fs.writeFile(options.path, data, callback);
  };

  var files = [];

  var handle = function (file) {
    var filePath = file.path;
    if (options.absolute) {
      filePath = path.resolve(filePath);
    } else {
      filePath = path.relative(options.relative_dir, filePath);
    }
    if (options.posix) {
      filePath = path.posix.normalize(filePath);
    }
    files.push(filePath);
    this.emit('data', file);
  };

  var end = function () {
    var _this = this;
    readConfig(function (err, config) {
      if (err) { throw err; }
      config.files = files.sort();
      writeConfig(config, function (err) {
        if (err) { throw err; }
        _this.emit('end');
      });
    });
  };

  return through(handle, end);
};
<commit_msg>improve default value handling<commit_after>
var through = require('through'),
    fs      = require('fs'),
    path    = require('path');

var defaults = {
  path:         'tsconfig.json',
  index:        2,
  newline_eof:  2,
  absolute:     false,
  relative_dir: '.',
  posix:        false
};

module.exports = function (options) {

  if (typeof options === 'undefined') {
    options = {};
  }

  Object.keys(defaults).forEach(function (key) {
    if (typeof options[key] !== 'undefined') {
      options[key] = defaults[key];
    }
  });

  var readConfig = function (callback) {
    fs.readFile(options.path, function (err, data) {
      if (err) {
        callback(err, null)
      } else {
        try {
          callback(null, JSON.parse(data));
        } catch (err) {
          callback(err, null);
        }
      }
    });
  };

  var writeConfig = function (config, callback) {
    try {
      var data = JSON.stringify(config, null, options.indent);
    } catch (err) {
      callback(err);
      return;
    }
    if (options.newline_eof) {
      data += "\n";
    }
    fs.writeFile(options.path, data, callback);
  };

  var files = [];

  var handle = function (file) {
    var filePath = file.path;
    if (options.absolute) {
      filePath = path.resolve(filePath);
    } else {
      filePath = path.relative(options.relative_dir, filePath);
    }
    if (options.posix) {
      filePath = path.posix.normalize(filePath);
    }
    files.push(filePath);
    this.emit('data', file);
  };

  var end = function () {
    var _this = this;
    readConfig(function (err, config) {
      if (err) { throw err; }
      config.files = files.sort();
      writeConfig(config, function (err) {
        if (err) { throw err; }
        _this.emit('end');
      });
    });
  };

  return through(handle, end);
};
<|endoftext|>


<commit_before>(function() {
  'use strict';

  /**
  * @var {Number} the interval to gather the sensor output in seconds.
  * Defaults to 5 minutes (300).
  */
  var interval = process.env.SENSOR_INTERVAL || 5*60;
  var resinDeviceUuid = process.env.RESIN_DEVICE_UUID;
  var firebaseUrl = process.env.FIREBASE_URL;
  var sensorType = process.env.SENSOR_TYPE || 22;
  var sensorPin = process.env.SENSOR_PIN || 4;
  var firebaseSecret = process.env.FIREBASE_SECRET;

  if (!firebaseSecret) {
      console.error('FIREBASE_SECRET is needed');
  }

  var FirebaseClient = require('firebase-client');
  var sensorLib = require('node-dht-sensor');
  var moment = require('moment');

  var firebase = new FirebaseClient({
      url: firebaseUrl,
      auth: firebaseSecret
  });

  var sensor = {
    initialize: function() {
      return sensorLib.initialize(sensorType, sensorPin);
    },
    read: function() {
      var readout = sensorLib.read();
      var temperature = readout.temperature.toFixed(2);
      var humidity = readout.humidity.toFixed(2);

      console.log(moment().format(), 'Temperature: ' + temperature + 'C, ' +
      'humidity: ' + humidity + '%');

      var path = '/' + [deviceName, 'readings'].join('/');
      firebase
          .push(path, {
              temperature: temperature,
              humidity: humidity,
              timestamp: Firebase.ServerValue.TIMESTAMP
          })
          .then(function() {
              console.log('Written data to firebase');
          })
          .fail(function(err) {
              console.error(err);
          });

      setTimeout(function() {
        sensor.read();
      }, interval * 1000);
    }
  };

  if (sensor.initialize()) {
    sensor.read();
  } else {
    console.error('Failed to initialize sensor');
  }
})();
<commit_msg>cast to int<commit_after>(function() {
  'use strict';

  /**
  * @var {Number} the interval to gather the sensor output in seconds.
  * Defaults to 5 minutes (300).
  */
  var interval = process.env.SENSOR_INTERVAL || 5*60;
  var resinDeviceUuid = process.env.RESIN_DEVICE_UUID;
  var firebaseUrl = process.env.FIREBASE_URL;
  var sensorType = process.env.SENSOR_TYPE || 22;
  var sensorPin = process.env.SENSOR_PIN || 4;
  var firebaseSecret = process.env.FIREBASE_SECRET;

  if (!firebaseSecret) {
      console.error('FIREBASE_SECRET is needed');
  }

  var FirebaseClient = require('firebase-client');
  var sensorLib = require('node-dht-sensor');
  var moment = require('moment');

  var firebase = new FirebaseClient({
      url: firebaseUrl,
      auth: firebaseSecret
  });

  var sensor = {
    initialize: function() {
      return sensorLib.initialize(+sensorType, +sensorPin);
    },
    read: function() {
      var readout = sensorLib.read();
      var temperature = readout.temperature.toFixed(2);
      var humidity = readout.humidity.toFixed(2);

      console.log(moment().format(), 'Temperature: ' + temperature + 'C, ' +
      'humidity: ' + humidity + '%');

      var path = '/' + [deviceName, 'readings'].join('/');
      firebase
          .push(path, {
              temperature: temperature,
              humidity: humidity,
              timestamp: Firebase.ServerValue.TIMESTAMP
          })
          .then(function() {
              console.log('Written data to firebase');
          })
          .fail(function(err) {
              console.error(err);
          });

      setTimeout(function() {
        sensor.read();
      }, interval * 1000);
    }
  };

  if (sensor.initialize()) {
    sensor.read();
  } else {
    console.error('Failed to initialize sensor');
  }
})();
<|endoftext|>


<commit_before>'use strict';

const Listener  = require('./class/listener.js');
const Event     = require('./class/event.js');
const validator = require('./helper/validator.js');
const global    = new WeakMap();

/**
 * Remove an event listener
 *
 * @param {Listener} listener
 * @param {Function} listener.callback
 *
 * @returns {Boolean}
 */
function filterRemoveEvent(listener) {
	return listener.callback !== this;
}

/**
 * Remove an expression listener
 *
 * @param {Listener} listener
 * @param {RegExp} listener.identifier
 * @param {Function} listener.callback
 *
 * @returns {Boolean}
 */
function filterRemoveExpression(listener) {
	return !(listener.identifier.toString() === this.identifier.toString() && (typeof this.callback === 'undefined' || listener.callback === this.callback));
}

/**
 * Sort listener array
 *
 * @param {Object} a
 * @param {int} a.timestamp
 * @param {Object} b
 * @param {int} b.timestamp
 *
 * @returns {Number}
 */
function sortListener(a, b) {
	return a.timestamp - b.timestamp;
}

/**
 * Return a listeners callback
 *
 * @param {Listener} listener
 * @param {Function} listener.callback
 *
 * @returns {Function}
 */
function mapListener(listener) {
	return listener.callback;
}

/**
 * Apply an event + optional details to a listener
 *
 * @param {Function} callback
 * @param {Event} event
 * @param {Object[]=} details
 */
function applyEvent(callback, event, details) {
	callback.apply(this, Array.prototype.concat(event, details));
}

/**
 * Subscribe an event listener
 *
 * @param {String} name
 * @param {Function} callback
 * @param {Boolean=} prepend
 * @param {Number=} limit
 */
function subscribeEvent(name, callback, prepend, limit) {
	(this.events[name] = this.events[name] || []).push(new Listener(this, name, callback, prepend, limit));
}

/**
 * Unregister an event listener
 *
 * @param {String} name
 * @param {Function} callback
 */
function unsubscribeEvent(name, callback) {
	if(this.events[name]) {
		if(callback) {
			this.events[name] = this.events[name].filter(filterRemoveEvent, callback);
		} else {
			this.events[name].length = 0;
		}
	}
}

/**
 * Subscribe an expression listener
 *
 * @param {RegExp} expression
 * @param {Function} callback
 * @param {Boolean=} prepend
 * @param {Number=} limit
 */
function subscribeExpression(expression, callback, prepend, limit) {
	this.expressions.push(new Listener(this, expression, callback, prepend, limit));
}

/**
 * Unsubscribe an expression listener
 *
 * @param {RegExp} expression
 * @param {Function} callback
 */
function unsubscribeExpression(expression, callback) {
	this.expressions = this.expressions.filter(filterRemoveExpression, { identifier: expression, callback: callback });
}

/**
 * Retrieve all listeners for a certain event
 *
 * @param {String} name
 *
 * @returns {Object[]}
 */
function retrieveListener(name) {
	let listener;

	if(validator.isString(name)) {
		let storage  = global.get(this);

		listener = storage.events[name] ? storage.events[name].slice() : [];

		storage.expressions.forEach((expression) => {
			if(expression.identifier.test(name)) {
				listener.push(expression);
			}
		});

		listener.sort(sortListener);
	}

	return listener || [];
}

class Emitter {
	/**
	 * Emitter constructor
	 */
	constructor() {
		global.set(this, { timestamp: +new Date(), events: {}, expressions: [] });
	}

	/**
	 * Subscribe an event listener
	 *
	 * @param {String|RegExp|Object[]} identifier
	 * @param {Function} callback
	 * @param {Boolean=} prepend
	 * @param {Number=} limit
	 *
	 * @returns {Emitter}
	 */
	on(identifier, callback, prepend, limit) {
		if(validator.isIdentifier(identifier) && validator.isCallback(callback)) {
			let storage = global.get(this);

			if(validator.isString(identifier)) {
				subscribeEvent.call(storage, identifier, callback, prepend, limit);
			}

			if(validator.isExpression(identifier)) {
				subscribeExpression.call(storage, identifier, callback, prepend, limit);
			}

			if(validator.isArray(identifier)) {
				identifier.forEach((identifier) => {
					this.on(identifier, callback, prepend, limit);
				});
			}
		}

		return this;
	}

	/**
	 * Subscribe a once only event listener
	 *
	 * @param {String|RegExp|Object[]} identifier
	 * @param {Function} callback
	 * @param {Boolean=} prepend
	 *
	 * @returns {Emitter}
	 */
	once(identifier, callback, prepend) {
		return this.on(identifier, callback, prepend, 1);
	}

	/**
	 * Subscribe a limited event listener
	 *
	 * @param {String|RegExp|Object[]} identifier
	 * @param {Number} limit
	 * @param {Function} callback
	 * @param {Boolean=} prepend
	 *
	 * @returns {Emitter}
	 */
	limit(identifier, limit, callback, prepend) {
		return this.on(identifier, callback, prepend, limit);
	}

	/**
	 * Unsubscribe an event listener
	 *
	 * @param {String|RegExp|Object[]} identifier
	 * @param {Function=} callback
	 *
	 * @returns {Emitter}
	 */
	off(identifier, callback) {
		if(validator.isIdentifier(identifier) && (validator.isCallback(callback) || typeof callback === 'undefined')) {
			let storage = global.get(this);

			if(validator.isString(identifier)) {
				unsubscribeEvent.call(storage, identifier, callback)
			}

			if(validator.isExpression(identifier)) {
				unsubscribeExpression.call(storage, identifier, callback);
			}

			if(validator.isArray(identifier)) {
				identifier.forEach((identifier) => {
					this.off(identifier, callback);
				});
			}
		}

		return this;
	}

	/**
	 * Emit an event
	 *
	 * @param {String} name
	 * @param {...*} details
	 *
	 * @returns {Emitter}
	 */
	emit(name, ...details) {
		let listener = retrieveListener.call(this, name);

		if(listener.length) {
			let event = new Event(name, this);

			listener.some((listener) => {
				applyEvent.call(this, listener.callback, event, details)

				if(listener.remaining && !(listener.remaining -= 1)) {
					this.off(listener.identifier, listener.callback);
				}

				return event.isCanceled;
			});
		}

		return this;
	}

	/**
	 * Retrieve all listeners for a certain event
	 *
	 * @param {String} name
	 *
	 * @returns {Object[]}
	 */
	listener(name) {
		return retrieveListener.call(this, name).map(mapListener);
	}
}

module.exports = Emitter;<commit_msg>add global events<commit_after>'use strict';

const Listener  = require('./class/listener.js');
const Event     = require('./class/event.js');
const validator = require('./helper/validator.js');
const weakmap   = new WeakMap();

/**
 * Remove an event listener
 *
 * @param {Listener} listener
 * @param {Function} listener.callback
 *
 * @returns {Boolean}
 */
function filterRemoveEvent(listener) {
	return listener.callback !== this;
}

/**
 * Remove an expression listener
 *
 * @param {Listener} listener
 * @param {RegExp} listener.identifier
 * @param {Function} listener.callback
 *
 * @returns {Boolean}
 */
function filterRemoveExpression(listener) {
	return !(listener.identifier.toString() === this.identifier.toString() && (typeof this.callback === 'undefined' || listener.callback === this.callback));
}

/**
 * Sort listener array
 *
 * @param {Object} a
 * @param {int} a.timestamp
 * @param {Object} b
 * @param {int} b.timestamp
 *
 * @returns {Number}
 */
function sortListener(a, b) {
	return a.timestamp - b.timestamp;
}

/**
 * Return a listeners callback
 *
 * @param {Listener} listener
 * @param {Function} listener.callback
 *
 * @returns {Function}
 */
function mapListener(listener) {
	return listener.callback;
}

/**
 * Apply an event + optional details to a listener
 *
 * @param {Function} callback
 * @param {Event} event
 * @param {Object[]=} details
 */
function applyEvent(callback, event, details) {
	callback.apply(this, Array.prototype.concat(event, details));
}

/**
 * Subscribe an event listener
 *
 * @param {String} name
 * @param {Function} callback
 * @param {Boolean=} prepend
 * @param {Number=} limit
 */
function subscribeEvent(name, callback, prepend, limit) {
	(this.events[name] = this.events[name] || []).push(new Listener(this, name, callback, prepend, limit));
}

/**
 * Unregister an event listener
 *
 * @param {String} name
 * @param {Function} callback
 */
function unsubscribeEvent(name, callback) {
	if(this.events[name]) {
		if(callback) {
			this.events[name] = this.events[name].filter(filterRemoveEvent, callback);
		} else {
			this.events[name].length = 0;
		}
	}
}

/**
 * Subscribe an expression listener
 *
 * @param {RegExp} expression
 * @param {Function} callback
 * @param {Boolean=} prepend
 * @param {Number=} limit
 */
function subscribeExpression(expression, callback, prepend, limit) {
	this.expressions.push(new Listener(this, expression, callback, prepend, limit));
}

/**
 * Unsubscribe an expression listener
 *
 * @param {RegExp} expression
 * @param {Function} callback
 */
function unsubscribeExpression(expression, callback) {
	this.expressions = this.expressions.filter(filterRemoveExpression, { identifier: expression, callback: callback });
}

/**
 * Retrieve all listeners for a certain event
 *
 * @param {String} name
 * @param {Boolean=} isGlobal
 *
 * @returns {Object[]}
 */
function retrieveListener(name, isGlobal) {
	let listener;

	if(validator.isString(name)) {
		let storage  = weakmap.get(this);

		listener = storage.events[name] ? storage.events[name].slice() : [];

		if(isGlobal !== true) {
			listener = listener.concat(retrieveListener.call(global, name, true));
		}

		storage.expressions.forEach((expression) => {
			if(expression.identifier.test(name)) {
				listener.push(expression);
			}
		});

		listener.sort(sortListener);
	}

	return listener || [];
}

class Emitter {
	/**
	 * Emitter constructor
	 */
	constructor() {
		weakmap.set(this, { timestamp: +new Date(), events: {}, expressions: [] });
	}

	/**
	 * Subscribe an event listener
	 *
	 * @param {String|RegExp|Object[]} identifier
	 * @param {Function} callback
	 * @param {Boolean=} prepend
	 * @param {Number=} limit
	 *
	 * @returns {Emitter}
	 */
	on(identifier, callback, prepend, limit) {
		if(validator.isIdentifier(identifier) && validator.isCallback(callback)) {
			let storage = weakmap.get(this);

			if(validator.isString(identifier)) {
				subscribeEvent.call(storage, identifier, callback, prepend, limit);
			}

			if(validator.isExpression(identifier)) {
				subscribeExpression.call(storage, identifier, callback, prepend, limit);
			}

			if(validator.isArray(identifier)) {
				identifier.forEach((identifier) => {
					this.on(identifier, callback, prepend, limit);
				});
			}
		}

		return this;
	}

	/**
	 * Subscribe a once only event listener
	 *
	 * @param {String|RegExp|Object[]} identifier
	 * @param {Function} callback
	 * @param {Boolean=} prepend
	 *
	 * @returns {Emitter}
	 */
	once(identifier, callback, prepend) {
		return this.on(identifier, callback, prepend, 1);
	}

	/**
	 * Subscribe a limited event listener
	 *
	 * @param {String|RegExp|Object[]} identifier
	 * @param {Number} limit
	 * @param {Function} callback
	 * @param {Boolean=} prepend
	 *
	 * @returns {Emitter}
	 */
	limit(identifier, limit, callback, prepend) {
		return this.on(identifier, callback, prepend, limit);
	}

	/**
	 * Unsubscribe an event listener
	 *
	 * @param {String|RegExp|Object[]} identifier
	 * @param {Function=} callback
	 *
	 * @returns {Emitter}
	 */
	off(identifier, callback) {
		if(validator.isIdentifier(identifier) && (validator.isCallback(callback) || typeof callback === 'undefined')) {
			let storage = weakmap.get(this);

			if(validator.isString(identifier)) {
				unsubscribeEvent.call(storage, identifier, callback)
			}

			if(validator.isExpression(identifier)) {
				unsubscribeExpression.call(storage, identifier, callback);
			}

			if(validator.isArray(identifier)) {
				identifier.forEach((identifier) => {
					this.off(identifier, callback);
				});
			}
		}

		return this;
	}

	/**
	 * Emit an event
	 *
	 * @param {String} name
	 * @param {...*} details
	 *
	 * @returns {Emitter}
	 */
	emit(name, ...details) {
		let listener = retrieveListener.call(this, name);

		if(listener.length) {
			let event = new Event(name, this);

			listener.some((listener) => {
				applyEvent.call(this, listener.callback, event, details)

				if(listener.remaining && !(listener.remaining -= 1)) {
					this.off(listener.identifier, listener.callback);
				}

				return event.isCanceled;
			});
		}

		return this;
	}

	/**
	 * Retrieve all listeners for a certain event
	 *
	 * @param {String} name
	 *
	 * @returns {Object[]}
	 */
	listener(name) {
		return retrieveListener.call(this, name).map(mapListener);
	}
}

const global = new Emitter();

Emitter.on       = global.on;
Emitter.once     = global.once;
Emitter.limit    = global.limit;
Emitter.off      = global.off;
Emitter.listener = global.listener;

module.exports = Emitter;<|endoftext|>