<commit_before>'use strict';

import StaticRenderer from './StaticRenderer';
import React, {
  Component,
  ListView,
  PropTypes,
  StyleSheet,
  Text,
  TextInput,
  View
} from 'react-native';

class AutoComplete extends Component {
  static propTypes = {
    ...TextInput.propTypes,
    /**
     * These styles will be applied to the container which
     * surrounds the autocomplete component.
     */
    containerStyle: View.propTypes.style,
    /**
     * Assign an array of data objects which should be rendered
     * acording to the enterd text.
     */
    data: PropTypes.array,
    /**
     * These style will be applied to the result list view.
     */
    listStyle: ListView.propTypes.style,
    /**
     * `renderItem` will be called to render the data objects
     * which will be displayed in the result view below the
     * text input.
     */
    renderItem: PropTypes.func
  };

  static defaultProps = {
    data: [],
    defaultValue: '',
    renderItem: rowData => <Text>{rowData}</Text>
  };

  constructor(props) {
    super(props);
    const ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
    this.state = {
      dataSource: ds.cloneWithRows(props.data),
      showResults: false
    };
  }

  /**
   * Proxy `blur()` to autocomplete's text input.
   */
  blur() {
    const { textInput } = this.refs;
    textInput && textInput.blur();
  }

  /**
   * Proxy `focus()` to autocomplete's text input.
   */
  focus() {
    const { textInput } = this.refs;
    textInput && textInput.focus();
  }

  componentWillReceiveProps(nextProps) {
    const dataSource = this.state.dataSource.cloneWithRows(nextProps.data);
    this._showResults(dataSource.getRowCount() > 0);
    this.setState({dataSource});
  }

  _renderItems() {
    const { listStyle, renderItem } = this.props;
    const { dataSource } = this.state;
    const itemIds = dataSource.rowIdentities[0];
    const items = [];

    for (let itemIdx = 0; itemIdx < itemIds.length; itemIdx++) {
      const shouldUpdateItem = dataSource.rowShouldUpdate(0, itemIdx);
      items.push(
        <StaticRenderer
          key={`i_${itemIds[itemIdx]}`}
          shouldUpdate={shouldUpdateItem}
          render={renderItem.bind(null, dataSource.getRowData(0, itemIdx))}
        />
      );
    }

    return (
      <View style={[styles.list, listStyle]}>
        {items}
      </View>
    );
  }

  _showResults(show) {
    const { showResults } = this.state;
    if (!showResults && show) {
      this.setState({showResults: true});
    } else if (showResults && !show) {
      this.setState({showResults: false});
    }
  }

  render() {
    const { showResults } = this.state;
    const { containerStyle, onEndEditing, style, ...props } = this.props;
    return (
      <View style={[styles.container, containerStyle]}>
        <TextInput
          style={[styles.input, style]}
          ref="textInput"
          onEndEditing={e =>
            this._showResults(false) || (onEndEditing && onEndEditing(e))
          }
          {...props}
        />
        {showResults && this._renderItems()}
      </View>
    );
  }
}

const border = {
  borderColor: '#b9b9b9',
  borderRadius: 1,
  borderWidth: 1
};

const styles = StyleSheet.create({
  container: {
    flex: 1
  },
  input: {
    ...border,
    backgroundColor: 'white',
    borderBottomWidth: 0,
    height: 40,
    margin: 10,
    marginBottom: 0,
    paddingLeft: 3,
  },
  list: {
    ...border,
    backgroundColor: 'white',
    borderTopWidth: 0,
    margin: 10,
    marginTop: 0,
  }
});

export default AutoComplete;
<commit_msg>Update data comment<commit_after>'use strict';

import StaticRenderer from './StaticRenderer';
import React, {
  Component,
  ListView,
  PropTypes,
  StyleSheet,
  Text,
  TextInput,
  View
} from 'react-native';

class AutoComplete extends Component {
  static propTypes = {
    ...TextInput.propTypes,
    /**
     * These styles will be applied to the container which
     * surrounds the autocomplete component.
     */
    containerStyle: View.propTypes.style,
    /**
     * Assign an array of data objects which should be
     * rendered in respect to the entered text.
     */
    data: PropTypes.array,
    /**
     * These style will be applied to the result list view.
     */
    listStyle: ListView.propTypes.style,
    /**
     * `renderItem` will be called to render the data objects
     * which will be displayed in the result view below the
     * text input.
     */
    renderItem: PropTypes.func
  };

  static defaultProps = {
    data: [],
    defaultValue: '',
    renderItem: rowData => <Text>{rowData}</Text>
  };

  constructor(props) {
    super(props);
    const ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
    this.state = {
      dataSource: ds.cloneWithRows(props.data),
      showResults: false
    };
  }

  /**
   * Proxy `blur()` to autocomplete's text input.
   */
  blur() {
    const { textInput } = this.refs;
    textInput && textInput.blur();
  }

  /**
   * Proxy `focus()` to autocomplete's text input.
   */
  focus() {
    const { textInput } = this.refs;
    textInput && textInput.focus();
  }

  componentWillReceiveProps(nextProps) {
    const dataSource = this.state.dataSource.cloneWithRows(nextProps.data);
    this._showResults(dataSource.getRowCount() > 0);
    this.setState({dataSource});
  }

  _renderItems() {
    const { listStyle, renderItem } = this.props;
    const { dataSource } = this.state;
    const itemIds = dataSource.rowIdentities[0];
    const items = [];

    for (let itemIdx = 0; itemIdx < itemIds.length; itemIdx++) {
      const shouldUpdateItem = dataSource.rowShouldUpdate(0, itemIdx);
      items.push(
        <StaticRenderer
          key={`i_${itemIds[itemIdx]}`}
          shouldUpdate={shouldUpdateItem}
          render={renderItem.bind(null, dataSource.getRowData(0, itemIdx))}
        />
      );
    }

    return (
      <View style={[styles.list, listStyle]}>
        {items}
      </View>
    );
  }

  _showResults(show) {
    const { showResults } = this.state;
    if (!showResults && show) {
      this.setState({showResults: true});
    } else if (showResults && !show) {
      this.setState({showResults: false});
    }
  }

  render() {
    const { showResults } = this.state;
    const { containerStyle, onEndEditing, style, ...props } = this.props;
    return (
      <View style={[styles.container, containerStyle]}>
        <TextInput
          style={[styles.input, style]}
          ref="textInput"
          onEndEditing={e =>
            this._showResults(false) || (onEndEditing && onEndEditing(e))
          }
          {...props}
        />
        {showResults && this._renderItems()}
      </View>
    );
  }
}

const border = {
  borderColor: '#b9b9b9',
  borderRadius: 1,
  borderWidth: 1
};

const styles = StyleSheet.create({
  container: {
    flex: 1
  },
  input: {
    ...border,
    backgroundColor: 'white',
    borderBottomWidth: 0,
    height: 40,
    margin: 10,
    marginBottom: 0,
    paddingLeft: 3,
  },
  list: {
    ...border,
    backgroundColor: 'white',
    borderTopWidth: 0,
    margin: 10,
    marginTop: 0,
  }
});

export default AutoComplete;
<|endoftext|>


<commit_before>var scrollToAnchor = require('scroll-to-anchor')
var documentReady = require('document-ready')
var nanolocation = require('nanolocation')
var nanotiming = require('nanotiming')
var nanorouter = require('nanorouter')
var nanomorph = require('nanomorph')
var nanoquery = require('nanoquery')
var nanohref = require('nanohref')
var nanoraf = require('nanoraf')
var nanobus = require('nanobus')
var assert = require('assert')
var xtend = require('xtend')

module.exports = Choo

var HISTORY_OBJECT = {}

function Choo (opts) {
  if (!(this instanceof Choo)) return new Choo(opts)
  opts = opts || {}

  assert.equal(typeof opts, 'object', 'choo: opts should be type object')

  var self = this

  // define events used by choo
  this._events = {
    DOMCONTENTLOADED: 'DOMContentLoaded',
    DOMTITLECHANGE: 'DOMTitleChange',
    REPLACESTATE: 'replaceState',
    PUSHSTATE: 'pushState',
    NAVIGATE: 'navigate',
    POPSTATE: 'popState',
    RENDER: 'render'
  }

  // properties for internal use only
  this._historyEnabled = opts.history === undefined ? true : opts.history
  this._hrefEnabled = opts.href === undefined ? true : opts.href
  this._hasWindow = typeof window !== 'undefined'
  this._createLocation = nanolocation
  this._loaded = false
  this._tree = null

  // properties that are part of the API
  this.router = nanorouter({ curry: true })
  this.emitter = nanobus('choo.emit')
  this.state = { events: this._events }

  // listen for title changes; available even when calling .toString()
  if (this._hasWindow) this.state.title = document.title
  this.emitter.prependListener(this._events.DOMTITLECHANGE, function (title) {
    assert.equal(typeof title, 'string', 'events.DOMTitleChange: title should be type string')
    self.state.title = title
    if (self._hasWindow) document.title = title
  })
}

Choo.prototype.route = function (route, handler) {
  assert.equal(typeof route, 'string', 'choo.route: route should be type string')
  assert.equal(typeof handler, 'function', 'choo.handler: route should be type function')

  var self = this
  this.router.on(route, function (params) {
    return function () {
      self.state.params = params
      self.state.route = route
      var routeTiming = nanotiming("choo.route('" + route + "')")
      var res = handler(self.state, function (eventName, data) {
        self.emitter.emit(eventName, data)
      })
      routeTiming()
      return res
    }
  })
}

Choo.prototype.use = function (cb) {
  assert.equal(typeof cb, 'function', 'choo.use: cb should be type function')
  var msg = 'choo.use'
  msg = cb.storeName ? msg + '(' + cb.storeName + ')' : msg
  var endTiming = nanotiming(msg)
  cb(this.state, this.emitter, this)
  endTiming()
}

Choo.prototype.start = function () {
  assert.equal(typeof window, 'object', 'choo.start: window was not found. .start() must be called in a browser, use .toString() if running in Node')

  var self = this
  if (this._historyEnabled) {
    this.emitter.prependListener(this._events.NAVIGATE, function () {
      self.state.query = nanoquery(window.location.search)
      if (self._loaded) {
        self.emitter.emit(self._events.RENDER)
        setTimeout(scrollToAnchor.bind(null, window.location.hash), 0)
      }
    })

    this.emitter.prependListener(this._events.POPSTATE, function () {
      self.emitter.emit(self._events.NAVIGATE)
    })

    this.emitter.prependListener(this._events.PUSHSTATE, function (href) {
      assert.equal(typeof href, 'string', 'events.pushState: href should be type string')
      window.history.pushState(HISTORY_OBJECT, null, href)
      self.emitter.emit(self._events.NAVIGATE)
    })

    this.emitter.prependListener(this._events.REPLACESTATE, function (href) {
      assert.equal(typeof href, 'string', 'events.replaceState: href should be type string')
      window.history.replaceState(HISTORY_OBJECT, null, href)
      self.emitter.emit(self._events.NAVIGATE)
    })

    window.onpopstate = function () {
      self.emitter.emit(self._events.POPSTATE)
    }

    if (self._hrefEnabled) {
      nanohref(function (location) {
        var href = location.href
        var currHref = window.location.href
        if (href === currHref) return
        self.emitter.emit(self._events.PUSHSTATE, href)
      })
    }
  }

  this.state.href = this._createLocation()
  this._tree = this.router(this.state.href)
  this.state.query = nanoquery(window.location.search)
  assert.ok(this._tree, 'choo.start: no valid DOM node returned for location ' + this.state.href)

  this.emitter.prependListener(self._events.RENDER, nanoraf(function () {
    var renderTiming = nanotiming('choo.render')

    self.state.href = self._createLocation()
    var newTree = self.router(self.state.href)
    assert.ok(newTree, 'choo.render: no valid DOM node returned for location ' + self.state.href)

    assert.equal(self._tree.nodeName, newTree.nodeName, 'choo.render: The target node <' +
      self._tree.nodeName.toLowerCase() + '> is not the same type as the new node <' +
      newTree.nodeName.toLowerCase() + '>.')

    var morphTiming = nanotiming('choo.morph')
    nanomorph(self._tree, newTree)
    morphTiming()

    renderTiming()
  }))

  documentReady(function () {
    self.emitter.emit(self._events.DOMCONTENTLOADED)
    self._loaded = true
  })

  return this._tree
}

Choo.prototype.mount = function mount (selector) {
  assert.equal(typeof window, 'object', 'choo.mount: window was not found. .mount() must be called in a browser, use .toString() if running in Node')
  assert.equal(typeof selector, 'string', 'choo.mount: selector should be type string')

  var self = this

  documentReady(function () {
    var renderTiming = nanotiming('choo.render')
    var newTree = self.start()

    self._tree = document.querySelector(selector)
    assert.ok(self._tree, 'choo.mount: could not query selector: ' + selector)
    assert.equal(self._tree.nodeName, newTree.nodeName, 'choo.mount: The target node <' +
      self._tree.nodeName.toLowerCase() + '> is not the same type as the new node <' +
      newTree.nodeName.toLowerCase() + '>.')

    var morphTiming = nanotiming('choo.morph')
    nanomorph(self._tree, newTree)
    morphTiming()

    renderTiming()
  })
}

Choo.prototype.toString = function (location, state) {
  this.state = xtend(this.state, state || {})

  assert.notEqual(typeof window, 'object', 'choo.mount: window was found. .toString() must be called in Node, use .start() or .mount() if running in the browser')
  assert.equal(typeof location, 'string', 'choo.toString: location should be type string')
  assert.equal(typeof this.state, 'object', 'choo.toString: state should be type object')

  this.state.href = location.replace(/\?.+$/, '')
  this.state.query = nanoquery(location)
  var html = this.router(location)
  assert.ok(html, 'choo.toString: no valid value returned for the route ' + location)
  return html.toString()
}
<commit_msg>Populate state.query before calling router (#575)<commit_after>var scrollToAnchor = require('scroll-to-anchor')
var documentReady = require('document-ready')
var nanolocation = require('nanolocation')
var nanotiming = require('nanotiming')
var nanorouter = require('nanorouter')
var nanomorph = require('nanomorph')
var nanoquery = require('nanoquery')
var nanohref = require('nanohref')
var nanoraf = require('nanoraf')
var nanobus = require('nanobus')
var assert = require('assert')
var xtend = require('xtend')

module.exports = Choo

var HISTORY_OBJECT = {}

function Choo (opts) {
  if (!(this instanceof Choo)) return new Choo(opts)
  opts = opts || {}

  assert.equal(typeof opts, 'object', 'choo: opts should be type object')

  var self = this

  // define events used by choo
  this._events = {
    DOMCONTENTLOADED: 'DOMContentLoaded',
    DOMTITLECHANGE: 'DOMTitleChange',
    REPLACESTATE: 'replaceState',
    PUSHSTATE: 'pushState',
    NAVIGATE: 'navigate',
    POPSTATE: 'popState',
    RENDER: 'render'
  }

  // properties for internal use only
  this._historyEnabled = opts.history === undefined ? true : opts.history
  this._hrefEnabled = opts.href === undefined ? true : opts.href
  this._hasWindow = typeof window !== 'undefined'
  this._createLocation = nanolocation
  this._loaded = false
  this._tree = null

  // properties that are part of the API
  this.router = nanorouter({ curry: true })
  this.emitter = nanobus('choo.emit')
  this.state = { events: this._events }

  // listen for title changes; available even when calling .toString()
  if (this._hasWindow) this.state.title = document.title
  this.emitter.prependListener(this._events.DOMTITLECHANGE, function (title) {
    assert.equal(typeof title, 'string', 'events.DOMTitleChange: title should be type string')
    self.state.title = title
    if (self._hasWindow) document.title = title
  })
}

Choo.prototype.route = function (route, handler) {
  assert.equal(typeof route, 'string', 'choo.route: route should be type string')
  assert.equal(typeof handler, 'function', 'choo.handler: route should be type function')

  var self = this
  this.router.on(route, function (params) {
    return function () {
      self.state.params = params
      self.state.route = route
      var routeTiming = nanotiming("choo.route('" + route + "')")
      var res = handler(self.state, function (eventName, data) {
        self.emitter.emit(eventName, data)
      })
      routeTiming()
      return res
    }
  })
}

Choo.prototype.use = function (cb) {
  assert.equal(typeof cb, 'function', 'choo.use: cb should be type function')
  var msg = 'choo.use'
  msg = cb.storeName ? msg + '(' + cb.storeName + ')' : msg
  var endTiming = nanotiming(msg)
  cb(this.state, this.emitter, this)
  endTiming()
}

Choo.prototype.start = function () {
  assert.equal(typeof window, 'object', 'choo.start: window was not found. .start() must be called in a browser, use .toString() if running in Node')

  var self = this
  if (this._historyEnabled) {
    this.emitter.prependListener(this._events.NAVIGATE, function () {
      self.state.query = nanoquery(window.location.search)
      if (self._loaded) {
        self.emitter.emit(self._events.RENDER)
        setTimeout(scrollToAnchor.bind(null, window.location.hash), 0)
      }
    })

    this.emitter.prependListener(this._events.POPSTATE, function () {
      self.emitter.emit(self._events.NAVIGATE)
    })

    this.emitter.prependListener(this._events.PUSHSTATE, function (href) {
      assert.equal(typeof href, 'string', 'events.pushState: href should be type string')
      window.history.pushState(HISTORY_OBJECT, null, href)
      self.emitter.emit(self._events.NAVIGATE)
    })

    this.emitter.prependListener(this._events.REPLACESTATE, function (href) {
      assert.equal(typeof href, 'string', 'events.replaceState: href should be type string')
      window.history.replaceState(HISTORY_OBJECT, null, href)
      self.emitter.emit(self._events.NAVIGATE)
    })

    window.onpopstate = function () {
      self.emitter.emit(self._events.POPSTATE)
    }

    if (self._hrefEnabled) {
      nanohref(function (location) {
        var href = location.href
        var currHref = window.location.href
        if (href === currHref) return
        self.emitter.emit(self._events.PUSHSTATE, href)
      })
    }
  }

  this.state.href = this._createLocation()
  this.state.query = nanoquery(window.location.search)
  this._tree = this.router(this.state.href)
  assert.ok(this._tree, 'choo.start: no valid DOM node returned for location ' + this.state.href)

  this.emitter.prependListener(self._events.RENDER, nanoraf(function () {
    var renderTiming = nanotiming('choo.render')

    self.state.href = self._createLocation()
    var newTree = self.router(self.state.href)
    assert.ok(newTree, 'choo.render: no valid DOM node returned for location ' + self.state.href)

    assert.equal(self._tree.nodeName, newTree.nodeName, 'choo.render: The target node <' +
      self._tree.nodeName.toLowerCase() + '> is not the same type as the new node <' +
      newTree.nodeName.toLowerCase() + '>.')

    var morphTiming = nanotiming('choo.morph')
    nanomorph(self._tree, newTree)
    morphTiming()

    renderTiming()
  }))

  documentReady(function () {
    self.emitter.emit(self._events.DOMCONTENTLOADED)
    self._loaded = true
  })

  return this._tree
}

Choo.prototype.mount = function mount (selector) {
  assert.equal(typeof window, 'object', 'choo.mount: window was not found. .mount() must be called in a browser, use .toString() if running in Node')
  assert.equal(typeof selector, 'string', 'choo.mount: selector should be type string')

  var self = this

  documentReady(function () {
    var renderTiming = nanotiming('choo.render')
    var newTree = self.start()

    self._tree = document.querySelector(selector)
    assert.ok(self._tree, 'choo.mount: could not query selector: ' + selector)
    assert.equal(self._tree.nodeName, newTree.nodeName, 'choo.mount: The target node <' +
      self._tree.nodeName.toLowerCase() + '> is not the same type as the new node <' +
      newTree.nodeName.toLowerCase() + '>.')

    var morphTiming = nanotiming('choo.morph')
    nanomorph(self._tree, newTree)
    morphTiming()

    renderTiming()
  })
}

Choo.prototype.toString = function (location, state) {
  this.state = xtend(this.state, state || {})

  assert.notEqual(typeof window, 'object', 'choo.mount: window was found. .toString() must be called in Node, use .start() or .mount() if running in the browser')
  assert.equal(typeof location, 'string', 'choo.toString: location should be type string')
  assert.equal(typeof this.state, 'object', 'choo.toString: state should be type object')

  this.state.href = location.replace(/\?.+$/, '')
  this.state.query = nanoquery(location)
  var html = this.router(location)
  assert.ok(html, 'choo.toString: no valid value returned for the route ' + location)
  return html.toString()
}
<|endoftext|>


<commit_before>/**
 * Google Universal Analytics
 */

var analytics = {
    init: function(GoogleAnalyticsID){
        (function (i, s, o, g, r, a, m) {
            i['GoogleAnalyticsObject'] = r;
            i[r] = i[r] || function () {
                    (i[r].q = i[r].q || []).push(arguments)
                }, i[r].l = 1 * new Date();
            a = s.createElement(o),
                m = s.getElementsByTagName(o)[0];
            a.async = 1;
            a.src = g;
            m.parentNode.insertBefore(a, m)
        })(window, document, 'script', '//www.google-analytics.com/analytics.js', 'ga');

        ga('create', GoogleAnalyticsID, 'auto');
    },

    pageview: function(path){
        ga('send', 'pageview', path);
    }
}<commit_msg>Exports<commit_after>/**
 * Google Universal Analytics
 */

var analytics = {
    init: function(GoogleAnalyticsID){
        (function (i, s, o, g, r, a, m) {
            i['GoogleAnalyticsObject'] = r;
            i[r] = i[r] || function () {
                    (i[r].q = i[r].q || []).push(arguments)
                }, i[r].l = 1 * new Date();
            a = s.createElement(o),
                m = s.getElementsByTagName(o)[0];
            a.async = 1;
            a.src = g;
            m.parentNode.insertBefore(a, m)
        })(window, document, 'script', '//www.google-analytics.com/analytics.js', 'ga');

        ga('create', GoogleAnalyticsID, 'auto');
    },

    pageview: function(path){
        ga('send', 'pageview', path);
    }
};

module.exports = analytics;<|endoftext|>


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

const program = require('commander');
const fs = require('fs');
const os = require('os');
const async = require('async');
const child_process = require('child_process');
const logger = require('./logger.js');
const plist = require('plist');

program
  .version('0.1.0')
  .description('Incident response tool for iPhone or iPad')
  .option('-o, --output [directory]', 'Set output directory')
  .option('-v, --verbose', 'Display verbose output')

program
  .command('collect')
  .description('Collect IR artifacts from iPhone or iPad')
  .option('-b, --backup', 'Backup iOS device')
  .option('--syslog-timeout <ms>', 'Optional timeout for how long to collect syslong, e.g. 86400 to collect for a day')
  .action(function(options) {
      collectArtifacts(options);
  });

program
  .command('process')
  .description('Process collected artifacts')
  .action(function() {
    processArtifacts();
  });

program
  .command('report')
  .description('Generate iOS IR report')
  .action(function() {
    generateReport();
  });

program.parse(process.argv);

// if program was called with no arguments, show help.
if (program.args.length === 0) program.help();

function setWorkingDirectory (userOutputDir, udid, currentEpoch) {
  let wd = ""
  if (userOutputDir) {
    wd = userOutputDir;
  } else {
    wd = __dirname;
  }

  // need to move away from "/" and start using path.sep
  const wd_udid = wd + "/" + udid;
  const wd_udid_epoch = wd_udid + '/' + currentEpoch;

  if (!fs.existsSync(wd_udid)){
    fs.mkdirSync(wd_udid);
  }

  if (!fs.existsSync(wd_udid_epoch)){
    fs.mkdirSync(wd_udid_epoch);
  }

  if (!fs.existsSync(wd_udid_epoch + '/artifacts')){
    fs.mkdirSync(wd_udid_epoch + '/artifacts');
  }

  logger.info("output directory set to %s", wd_udid_epoch);
  return(wd_udid_epoch);
}

function collectArtifacts(options) {
  // let's first get the UDID...if we can't do this successfully, we have a problem
  getUDID(function (error, udid) {
    if (error) {
      return logger.error(error);
    }

    // no error getting UDID so time to fetch data
    // first we'll setup the working directory, saving data in unique dir each time based on epoch time
    const currentEpoch = new Date().getTime();
    const wd = setWorkingDirectory(program.output, udid, currentEpoch);

    const idevicesyslog = getDeviceSyslog(udid, wd, options.syslogTimeout);

    async.parallel({
      backup: function(callback) {
        if (options.backup) {
          doDeviceBackup(udid, wd, callback);
        } else {
          logger.info("Skipping device backup");
          // this callback() iw critical so async.parallel can returm
          callback();
        }
      },
      deviceInfo: function(callback) {
        getDeviceInfo(udid, wd, callback);
      },
      installedApps: function(callback) {
        getInstalledApps(udid, wd, callback);
      },
      provisioningProfiles: function(callback) {
        listProvisioningProfiles(udid, wd, callback);
      },
      crashReports: function(callback) {
        getCrashReports(udid, wd, callback);
      }
    }, function(err, results) {
      //handle any errors from extraction functions
      if(options.syslogTimeout === undefined) {
        logger.info("completed all extraction functions so we'll now kill deviceSyslog");
        idevicesyslog.kill('SIGINT');
      } else {
        logger.info("waiting %d ms for syslog to execute", options.syslogTimeout);
      };
    });

  });
};

function getUDID (callback) {
  var retval = '';
  const udid = child_process.spawn('idevice_id', ['-l']);

  udid.stdout.on('data', (chunk) => {
    // FIXME: if idevice_id fires the data event more than once the this would overwrite
    // retval which is likley problematic
    retval = chunk;
  });

  udid.on('close', code => {
    /*
    Unfortunately idevice_id returns a 0 in all situations I checked
    which differs from how ideviceinfo works. If you call idevice_id with
    an invalid parameter or no device is attached, it still returns a 0.
    I'm going to keep this return code != 0 in here for now in case they fix
    in the future. The work around is to test the length for retval and if it is
    41, then we have a UDID returned!
    */
    if (retval.length === 41) {
      // found a valid udid so return null error and uuid value
      // first let's make this a string and trim any newlines
      const udid_str = String.fromCharCode.apply(null, retval);
      logger.info("Authorized iDevice found, UDID: %s", udid_str.trim());
      callback(null, udid_str.trim());
    } else {
      // encountered some sort of error. If 0 len then no device attached, otherwise something else
      if (retval.length === 0) {
        return callback(new Error("No authorized iDevice found. Plug in and authorize a device first."));
      } else {
        return callback(new Error(retval));
      };
    };
  });
};

function getDeviceSyslog(udid, wd, syslogTimeout) {

  const file_name = 'syslog.txt';
  const file = fs.createWriteStream(wd + '/artifacts/' + file_name);

  let userTimeout = 0;
  // check to see if user specified a timeout
  if (syslogTimeout) {
    // syslog timeout was specified so run with that user setting
    // FIX: add check to make sure syslogTimeout is an int or catch the conversion error
    userTimeout = Number(syslogTimeout);
  };

  // execFile maxBuffer is set to 200k but I've overode it here to 5MB. I'll probably
  // need to change this call to exec or fork, need to research a little more
  // originally chose execFile so I could control the timeout...but we could also do
  // that in the calling function if we wanted.
  const opts = {
    timeout: userTimeout,
    maxBuffer: 5000*1024
  };

  // call idevicesyslog binary
  const idevicesyslog = child_process.execFile('idevicesyslog', [], opts );

  logger.info("capturing device syslog...");

  // on data events, write chunks to file
  idevicesyslog.stdout.on('data', (chunk) => {
    file.write(chunk);
  });

  // after Stream ends, close the file, inform user of saved file
  idevicesyslog.stdout.on('end', () => {
    file.end();
    logger.debug("in getDeviceSyslog, end event fired");
  });

  idevicesyslog.on('close', function(code) {
    if (code != 0) {
      logger.error("idevicesyslog returned error code " + code);
      // return callback(new Error('idevicesyslog returned error code ' + code));
    } else {
      logger.debug("in getDeviceSyslog, close event triggered without error");
      logger.info('iOS Device syslog saved');
      // callback(null, idevicesyslog);
    }
  });

  // for syslog, we call back immediately and return the childProcess so the calling program
  // has control over deciding when to kill the process. Could be immediately after other
  // extraction is complete or after a timeout value
  //callback(null, idevicesyslog);
  return(idevicesyslog);
};

function getDeviceInfo(udid, wd, callback) {

  const file_name = 'ideviceinfo.txt';
  const file = fs.createWriteStream(wd + '/artifacts/' + file_name);

  // call ideviceinfo binary
  const ideviceinfo = child_process.spawn('ideviceinfo', []);

  // on data events, write chunks to file
  ideviceinfo.stdout.on('data', (chunk) => {
    file.write(chunk);
  });

  // after Stream ends, close the file, inform user of saved file
  ideviceinfo.stdout.on('end', () => {
    file.end();
    logger.info('iOS Device info saved');
    callback(null, ideviceinfo);
  });

  // should this event be on exit or on close?
  // per documentation, not all Streams emit a close event
  // https://nodejs.org/api/stream.html#stream_event_close
  ideviceinfo.on('close', function(code) {
    if (code != 0) {
      return callback(new Error('Error: ideviceinfo returned error code ' + code));
    }
  });
};

function getInstalledApps(udid, wd, callback) {

  const file_name = 'installed-apps.xml';
  const file = fs.createWriteStream(wd + '/artifacts/' + file_name);

  // call ideviceinstaller binary
  const ideviceinstaller = child_process.spawn('ideviceinstaller', ['--list-apps', '-o','list_all', '-o', 'xml']);

  // on data events, write chunks to file
  ideviceinstaller.stdout.on('data', (chunk) => {
    file.write(chunk);
  });

  // after Stream ends, close the file, inform user of saved file
  ideviceinstaller.stdout.on('end', () => {
    file.end();
    logger.info('iOS Device installed apps saved');
    callback(null, ideviceinstaller);
  });

  ideviceinstaller.on('close', function(code) {
    if (code != 0) {
      callback(new Error('ideviceinstaller returned error code ' + code));
    }
  });
};

function listProvisioningProfiles(udid, wd, callback) {

  const file_name = 'provisioning-profiles.txt';
  const file = fs.createWriteStream(wd + '/artifacts/' + file_name);

  // call ideviceprovision binary
  const ideviceprovision = child_process.spawn('ideviceprovision', ['list']);

  // on data events, write chunks to file
  ideviceprovision.stdout.on('data', (chunk) => {
    file.write(chunk);
  });

  // after Stream ends, close the file, inform user of saved file
  ideviceprovision.stdout.on('end', () => {
    file.end();
    logger.info('Installed provisioning profiles saved');
    callback(null, ideviceprovision);
  });

  ideviceprovision.on('close', function(code) {
    if (code != 0) {
      callback(new Error('ideviceprovision returned error code ' + code));
    }
  });
};

function getCrashReports(udid, wd, callback) {

  // idevicecrashreport writes multiple files vs. returning to stdout
  // creating a directory to store this data and putting stdout into log file
  const wd_crashreports = wd + '/artifacts/crash_reports/';
  if (!fs.existsSync(wd_crashreports)){
    fs.mkdirSync(wd_crashreports);
  }

  const file_name = 'crashlogs.txt';
  const file = fs.createWriteStream(wd_crashreports + file_name);

  // call ideviceprovision binary
  const idevicecrashreport = child_process.spawn('idevicecrashreport', ['--extract', '--keep', wd_crashreports]);

  // on data events, write chunks to file
  idevicecrashreport.stdout.on('data', (chunk) => {
    file.write(chunk);
  });

  // after Stream ends, close the file, inform user of saved file
  idevicecrashreport.stdout.on('end', () => {
    file.end();
    logger.info('Crash reports and log saved');
    callback(null, idevicecrashreport);
  });

  idevicecrashreport.on('close', function(code) {
    if (code != 0) {
      callback(new Error('idevicecrashreport returned error code ' + code));
    }
  });
};

function doDeviceBackup(udid, wd, callback) {
  // idevicebackup2 backup --full .
  // idevicebackup2 writes many files and directories vs. returning to stdout
  // creating a directory to store this data and putting stdout into log file
  const wd_backup = wd + '/artifacts/backup/';
  if (!fs.existsSync(wd_backup)){
    fs.mkdirSync(wd_backup);
  }

  const file_name = 'backup_log.txt';
  const file = fs.createWriteStream(wd_backup + file_name);

  // call ideviceprovision binary
  const idevicebackup2 = child_process.spawn('idevicebackup2', ['backup', '--full', wd_backup]);

  // on data events, write chunks to file
  idevicebackup2.stdout.on('data', (chunk) => {
    file.write(chunk);
  });

  // after Stream ends, close the file, inform user of saved file
  idevicebackup2.stdout.on('end', () => {
    file.end();
    logger.info('Device backup and log saved');
    callback(null, idevicebackup2);
  });

  idevicebackup2.on('close', function(code) {
    if (code != 0) {
      callback(new Error('idevicebackup2 returned error code ' + code));
    }
  });
};

function processArtifacts () {
  logger.info("process artifacts");
}

function generateReport () {
  // hack for experimenting
  const installedApps = "/Users/hiro/Desktop/ios-triage/993aa52471a3e6ea117eb619927d74f3aa7511bf/1484346254360/artifacts/installed-apps.xml";

  // read and parse plist file
  const obj = plist.parse(fs.readFileSync(installedApps, 'utf8'));
  // console.log(JSON.stringify(obj));

  for (let prop in obj) {
    const app = obj[prop];
    for(let attrib in app) {
      console.log("app." + attrib + " = " + app[attrib]);
    };
  };
};

<commit_msg>processing basic properties of installed apps in object<commit_after>#!/usr/bin/env node
'use strict';

const program = require('commander');
const fs = require('fs');
const os = require('os');
const async = require('async');
const child_process = require('child_process');
const logger = require('./logger.js');
const plist = require('plist');

program
  .version('0.1.0')
  .description('Incident response tool for iPhone or iPad')
  .option('-o, --output [directory]', 'Set output directory')
  .option('-v, --verbose', 'Display verbose output')

program
  .command('collect')
  .description('Collect IR artifacts from iPhone or iPad')
  .option('-b, --backup', 'Backup iOS device')
  .option('--syslog-timeout <ms>', 'Optional timeout for how long to collect syslong, e.g. 86400 to collect for a day')
  .action(function(options) {
      collectArtifacts(options);
  });

program
  .command('process')
  .description('Process collected artifacts')
  .action(function() {
    processArtifacts();
  });

program
  .command('report')
  .description('Generate iOS IR report')
  .action(function() {
    generateReport();
  });

program.parse(process.argv);

// if program was called with no arguments, show help.
if (program.args.length === 0) program.help();

function setWorkingDirectory (userOutputDir, udid, currentEpoch) {
  let wd = ""
  if (userOutputDir) {
    wd = userOutputDir;
  } else {
    wd = __dirname;
  }

  // need to move away from "/" and start using path.sep
  const wd_udid = wd + "/" + udid;
  const wd_udid_epoch = wd_udid + '/' + currentEpoch;

  if (!fs.existsSync(wd_udid)){
    fs.mkdirSync(wd_udid);
  }

  if (!fs.existsSync(wd_udid_epoch)){
    fs.mkdirSync(wd_udid_epoch);
  }

  if (!fs.existsSync(wd_udid_epoch + '/artifacts')){
    fs.mkdirSync(wd_udid_epoch + '/artifacts');
  }

  logger.info("output directory set to %s", wd_udid_epoch);
  return(wd_udid_epoch);
}

function collectArtifacts(options) {
  // let's first get the UDID...if we can't do this successfully, we have a problem
  getUDID(function (error, udid) {
    if (error) {
      return logger.error(error);
    }

    // no error getting UDID so time to fetch data
    // first we'll setup the working directory, saving data in unique dir each time based on epoch time
    const currentEpoch = new Date().getTime();
    const wd = setWorkingDirectory(program.output, udid, currentEpoch);

    const idevicesyslog = getDeviceSyslog(udid, wd, options.syslogTimeout);

    async.parallel({
      backup: function(callback) {
        if (options.backup) {
          doDeviceBackup(udid, wd, callback);
        } else {
          logger.info("Skipping device backup");
          // this callback() iw critical so async.parallel can returm
          callback();
        }
      },
      deviceInfo: function(callback) {
        getDeviceInfo(udid, wd, callback);
      },
      installedApps: function(callback) {
        getInstalledApps(udid, wd, callback);
      },
      provisioningProfiles: function(callback) {
        listProvisioningProfiles(udid, wd, callback);
      },
      crashReports: function(callback) {
        getCrashReports(udid, wd, callback);
      }
    }, function(err, results) {
      //handle any errors from extraction functions
      if(options.syslogTimeout === undefined) {
        logger.info("completed all extraction functions so we'll now kill deviceSyslog");
        idevicesyslog.kill('SIGINT');
      } else {
        logger.info("waiting %d ms for syslog to execute", options.syslogTimeout);
      };
    });

  });
};

function getUDID (callback) {
  var retval = '';
  const udid = child_process.spawn('idevice_id', ['-l']);

  udid.stdout.on('data', (chunk) => {
    // FIXME: if idevice_id fires the data event more than once the this would overwrite
    // retval which is likley problematic
    retval = chunk;
  });

  udid.on('close', code => {
    /*
    Unfortunately idevice_id returns a 0 in all situations I checked
    which differs from how ideviceinfo works. If you call idevice_id with
    an invalid parameter or no device is attached, it still returns a 0.
    I'm going to keep this return code != 0 in here for now in case they fix
    in the future. The work around is to test the length for retval and if it is
    41, then we have a UDID returned!
    */
    if (retval.length === 41) {
      // found a valid udid so return null error and uuid value
      // first let's make this a string and trim any newlines
      const udid_str = String.fromCharCode.apply(null, retval);
      logger.info("Authorized iDevice found, UDID: %s", udid_str.trim());
      callback(null, udid_str.trim());
    } else {
      // encountered some sort of error. If 0 len then no device attached, otherwise something else
      if (retval.length === 0) {
        return callback(new Error("No authorized iDevice found. Plug in and authorize a device first."));
      } else {
        return callback(new Error(retval));
      };
    };
  });
};

function getDeviceSyslog(udid, wd, syslogTimeout) {

  const file_name = 'syslog.txt';
  const file = fs.createWriteStream(wd + '/artifacts/' + file_name);

  let userTimeout = 0;
  // check to see if user specified a timeout
  if (syslogTimeout) {
    // syslog timeout was specified so run with that user setting
    // FIX: add check to make sure syslogTimeout is an int or catch the conversion error
    userTimeout = Number(syslogTimeout);
  };

  // execFile maxBuffer is set to 200k but I've overode it here to 5MB. I'll probably
  // need to change this call to exec or fork, need to research a little more
  // originally chose execFile so I could control the timeout...but we could also do
  // that in the calling function if we wanted.
  const opts = {
    timeout: userTimeout,
    maxBuffer: 5000*1024
  };

  // call idevicesyslog binary
  const idevicesyslog = child_process.execFile('idevicesyslog', [], opts );

  logger.info("capturing device syslog...");

  // on data events, write chunks to file
  idevicesyslog.stdout.on('data', (chunk) => {
    file.write(chunk);
  });

  // after Stream ends, close the file, inform user of saved file
  idevicesyslog.stdout.on('end', () => {
    file.end();
    logger.debug("in getDeviceSyslog, end event fired");
  });

  idevicesyslog.on('close', function(code) {
    if (code != 0) {
      logger.error("idevicesyslog returned error code " + code);
      // return callback(new Error('idevicesyslog returned error code ' + code));
    } else {
      logger.debug("in getDeviceSyslog, close event triggered without error");
      logger.info('iOS Device syslog saved');
      // callback(null, idevicesyslog);
    }
  });

  // for syslog, we call back immediately and return the childProcess so the calling program
  // has control over deciding when to kill the process. Could be immediately after other
  // extraction is complete or after a timeout value
  //callback(null, idevicesyslog);
  return(idevicesyslog);
};

function getDeviceInfo(udid, wd, callback) {

  const file_name = 'ideviceinfo.txt';
  const file = fs.createWriteStream(wd + '/artifacts/' + file_name);

  // call ideviceinfo binary
  const ideviceinfo = child_process.spawn('ideviceinfo', []);

  // on data events, write chunks to file
  ideviceinfo.stdout.on('data', (chunk) => {
    file.write(chunk);
  });

  // after Stream ends, close the file, inform user of saved file
  ideviceinfo.stdout.on('end', () => {
    file.end();
    logger.info('iOS Device info saved');
    callback(null, ideviceinfo);
  });

  // should this event be on exit or on close?
  // per documentation, not all Streams emit a close event
  // https://nodejs.org/api/stream.html#stream_event_close
  ideviceinfo.on('close', function(code) {
    if (code != 0) {
      return callback(new Error('Error: ideviceinfo returned error code ' + code));
    }
  });
};

function getInstalledApps(udid, wd, callback) {

  const file_name = 'installed-apps.xml';
  const file = fs.createWriteStream(wd + '/artifacts/' + file_name);

  // call ideviceinstaller binary
  const ideviceinstaller = child_process.spawn('ideviceinstaller', ['--list-apps', '-o','list_all', '-o', 'xml']);

  // on data events, write chunks to file
  ideviceinstaller.stdout.on('data', (chunk) => {
    file.write(chunk);
  });

  // after Stream ends, close the file, inform user of saved file
  ideviceinstaller.stdout.on('end', () => {
    file.end();
    logger.info('iOS Device installed apps saved');
    callback(null, ideviceinstaller);
  });

  ideviceinstaller.on('close', function(code) {
    if (code != 0) {
      callback(new Error('ideviceinstaller returned error code ' + code));
    }
  });
};

function listProvisioningProfiles(udid, wd, callback) {

  const file_name = 'provisioning-profiles.txt';
  const file = fs.createWriteStream(wd + '/artifacts/' + file_name);

  // call ideviceprovision binary
  const ideviceprovision = child_process.spawn('ideviceprovision', ['list']);

  // on data events, write chunks to file
  ideviceprovision.stdout.on('data', (chunk) => {
    file.write(chunk);
  });

  // after Stream ends, close the file, inform user of saved file
  ideviceprovision.stdout.on('end', () => {
    file.end();
    logger.info('Installed provisioning profiles saved');
    callback(null, ideviceprovision);
  });

  ideviceprovision.on('close', function(code) {
    if (code != 0) {
      callback(new Error('ideviceprovision returned error code ' + code));
    }
  });
};

function getCrashReports(udid, wd, callback) {

  // idevicecrashreport writes multiple files vs. returning to stdout
  // creating a directory to store this data and putting stdout into log file
  const wd_crashreports = wd + '/artifacts/crash_reports/';
  if (!fs.existsSync(wd_crashreports)){
    fs.mkdirSync(wd_crashreports);
  }

  const file_name = 'crashlogs.txt';
  const file = fs.createWriteStream(wd_crashreports + file_name);

  // call ideviceprovision binary
  const idevicecrashreport = child_process.spawn('idevicecrashreport', ['--extract', '--keep', wd_crashreports]);

  // on data events, write chunks to file
  idevicecrashreport.stdout.on('data', (chunk) => {
    file.write(chunk);
  });

  // after Stream ends, close the file, inform user of saved file
  idevicecrashreport.stdout.on('end', () => {
    file.end();
    logger.info('Crash reports and log saved');
    callback(null, idevicecrashreport);
  });

  idevicecrashreport.on('close', function(code) {
    if (code != 0) {
      callback(new Error('idevicecrashreport returned error code ' + code));
    }
  });
};

function doDeviceBackup(udid, wd, callback) {
  // idevicebackup2 backup --full .
  // idevicebackup2 writes many files and directories vs. returning to stdout
  // creating a directory to store this data and putting stdout into log file
  const wd_backup = wd + '/artifacts/backup/';
  if (!fs.existsSync(wd_backup)){
    fs.mkdirSync(wd_backup);
  }

  const file_name = 'backup_log.txt';
  const file = fs.createWriteStream(wd_backup + file_name);

  // call ideviceprovision binary
  const idevicebackup2 = child_process.spawn('idevicebackup2', ['backup', '--full', wd_backup]);

  // on data events, write chunks to file
  idevicebackup2.stdout.on('data', (chunk) => {
    file.write(chunk);
  });

  // after Stream ends, close the file, inform user of saved file
  idevicebackup2.stdout.on('end', () => {
    file.end();
    logger.info('Device backup and log saved');
    callback(null, idevicebackup2);
  });

  idevicebackup2.on('close', function(code) {
    if (code != 0) {
      callback(new Error('idevicebackup2 returned error code ' + code));
    }
  });
};

function processArtifacts () {
  logger.info("process artifacts");
}

function generateReport () {
  // hack for experimenting
  const installedAppsXML = "/Users/hiro/Desktop/ios-triage/993aa52471a3e6ea117eb619927d74f3aa7511bf/1484346254360/artifacts/installed-apps.xml";

  // read and parse plist file
  const obj = plist.parse(fs.readFileSync(installedAppsXML, 'utf8'));
  // console.log(JSON.stringify(obj));

  // setup object to represent installedApps
  const installedApps = {};
  installedApps.apps = [];

  for (let prop in obj) {
    // every prop in array is properties for an app
    const app = obj[prop];
    let appInfo = {}; //object to store individual app properties in
    for(let attrib in app) {
      switch(attrib) {
        case "CFBundleName":
          appInfo.name = app[attrib];
          break;
        case "CFBundleVersion":
          appInfo.version = app[attrib];
          break;
        case "CFBundleIdentifier":
          appInfo.bundleIdentifier = app[attrib];
          break;
        case "SignerIdentity":
          appInfo.signerIdentity = app[attrib];
          break;
        case "ApplicationType":
          appInfo.applicationType = app[attrib];
          break;
        default:
          // otherwise ignore property for now
          break;
      };
    // now push current appInfo into installedApps.apps array
      installedApps.apps.push(appInfo);
    };
    logger.debug("moving to next app");
  };
  console.log(JSON.stringify(installedApps));
};

<|endoftext|>


<commit_before>var program = require('commander');

program
  .option('-f, --force', 'force installation')
  .parse(process.argv);

var pkgs = program.args;

if (!pkgs.length) {
  console.error('packages required');
  process.exit(1);
}

console.log();
if (program.force) console.log('  force: install');
pkgs.forEach(function(pkg){
  console.log('  install : %s', pkg);
});
console.log();
<commit_msg>1.0.1<commit_after><|endoftext|>


<commit_before>'use strict';

var request = require('request');
var OAuth   = require('oauth-1.0a');
var crypto  = require('crypto');
var promise = require('bluebird');
var _url    = require('url');

module.exports = WooCommerceAPI;

/**
 * WooCommerce REST API wrapper
 *
 * @param {Object} opt
 */
function WooCommerceAPI(opt) {
  if (!(this instanceof WooCommerceAPI)) {
    return new WooCommerceAPI(opt);
  }

  opt = opt || {};

  if (!(opt.url)) {
    throw new Error('url is required');
  }

  if (!(opt.consumerKey)) {
    throw new Error('consumerKey is required');
  }

  if (!(opt.consumerSecret)) {
    throw new Error('consumerSecret is required');
  }

  this.classVersion = '1.4.0';
  this._setDefaultsOptions(opt);
}

/**
 * Set default options
 *
 * @param {Object} opt
 */
WooCommerceAPI.prototype._setDefaultsOptions = function(opt) {
  this.url             = opt.url;
  this.wpAPI           = opt.wpAPI || false;
  this.wpAPIPrefix     = opt.wpAPIPrefix || 'wp-json';
  this.version         = opt.version || 'v3';
  this.isSsl           = /^https/i.test(this.url);
  this.consumerKey     = opt.consumerKey;
  this.consumerSecret  = opt.consumerSecret;
  this.verifySsl       = false === opt.verifySsl ? false : true;
  this.encoding        = opt.encoding || 'utf8';
  this.queryStringAuth = opt.queryStringAuth || false;
  this.port            = opt.port || '';
  this.timeout         = opt.timeout;
};

/**
 * Normalize query string for oAuth
 *
 * @param  {string} url
 * @return {string}
 */
WooCommerceAPI.prototype._normalizeQueryString = function(url) {
  // Exit if don't find query string
  if (-1 === url.indexOf('?')) {
    return url;
  }

  var query       = _url.parse(url, true).query;
  var params      = [];
  var queryString = '';

  for (var p in query) {
    params.push(p);
  }
  params.sort();

  for (var i in params) {
    if (queryString.length) {
      queryString += '&';
    }

    queryString += encodeURIComponent(params[i]).replace('%5B', '[')
      .replace('%5D', ']');
    queryString += '=';
    queryString += encodeURIComponent(query[params[i]]);
  }

  return url.split('?')[0] + '?' + queryString;
};

/**
 * Get URL
 *
 * @param  {String} endpoint
 *
 * @return {String}
 */
WooCommerceAPI.prototype._getUrl = function(endpoint) {
  var url = '/' === this.url.slice(-1) ? this.url : this.url + '/';
  var api = this.wpAPI ? this.wpAPIPrefix + '/' : 'wc-api/';

  url = url + api + this.version + '/' + endpoint;

  // Include port.
  if ('' !== this.port) {
    var hostname = _url.parse(url, true).hostname;
    url = url.replace(hostname, hostname + ':' + this.port);
  }

  if (!this.isSsl) {
    return this._normalizeQueryString(url);
  }

  return url;
};

/**
 * Get OAuth
 *
 * @return {Object}
 */
WooCommerceAPI.prototype._getOAuth = function() {
  var data = {
    consumer: {
      key: this.consumerKey,
      secret: this.consumerSecret
    },
    signature_method: 'HMAC-SHA256',
    hash_function: function(base_string, key) {
        return crypto.createHmac('sha256', key).update(base_string)
          .digest('base64');
    }
  };

  if (-1 < [ 'v1', 'v2' ].indexOf(this.version)) {
    data.last_ampersand = false;
  }

  return new OAuth(data);
};

/**
 * Do requests
 *
 * @param  {String}   method
 * @param  {String}   endpoint
 * @param  {Object}   data
 * @param  {Function} callback
 *
 * @return {Object}
 */
WooCommerceAPI.prototype._request = function(method, endpoint, data, callback) {
  var url = this._getUrl(endpoint);

  var params = {
    url: url,
    method: method,
    encoding: this.encoding,
    timeout: this.timeout,
    headers: {
      'User-Agent': 'WooCommerce API Client-Node.js/' + this.classVersion,
      'Content-Type': 'application/json',
      'Accept': 'application/json'
    }
  };

  if (this.isSsl) {
    if (this.queryStringAuth) {
      params.qs = {
        consumer_key: this.consumerKey,
        consumer_secret: this.consumerSecret
      };
    } else {
      params.auth = {
        user: this.consumerKey,
        pass: this.consumerSecret
      };
    }

    if (!this.verifySsl) {
      params.strictSSL = false;
    }
  } else {
    params.qs = this._getOAuth().authorize({
      url: url,
      method: method
    });
  }

  if (data) {
    params.body = JSON.stringify(data);
  }

  if (!callback) {
    return request(params);
  }

  return request(params, callback);
};

/**
 * GET requests
 *
 * @param  {String}   endpoint
 * @param  {Function} callback
 *
 * @return {Object}
 */
WooCommerceAPI.prototype.get = function(endpoint, callback) {
  return this._request('GET', endpoint, null, callback);
};

/**
 * POST requests
 *
 * @param  {String}   endpoint
 * @param  {Object}   data
 * @param  {Function} callback
 *
 * @return {Object}
 */
WooCommerceAPI.prototype.post = function(endpoint, data, callback) {
  return this._request('POST', endpoint, data, callback);
};

/**
 * PUT requests
 *
 * @param  {String}   endpoint
 * @param  {Object}   data
 * @param  {Function} callback
 *
 * @return {Object}
 */
WooCommerceAPI.prototype.put = function(endpoint, data, callback) {
  return this._request('PUT', endpoint, data, callback);
};

/**
 * DELETE requests
 *
 * @param  {String}   endpoint
 * @param  {Function} callback
 *
 * @return {Object}
 */
WooCommerceAPI.prototype.delete = function(endpoint, callback) {
  return this._request('DELETE', endpoint, null, callback);
};

/**
 * OPTIONS requests
 *
 * @param  {String}   endpoint
 * @param  {Function} callback
 *
 * @return {Object}
 */
WooCommerceAPI.prototype.options = function(endpoint, callback) {
  return this._request('OPTIONS', endpoint, null, callback);
};

/**
 * Promifying all requests exposing new methods
 * named [method]Async like in getAsync()
 */
promise.promisifyAll(WooCommerceAPI.prototype);
<commit_msg>Fixed WordPress 4.7 compatibility, closes #48<commit_after>'use strict';

var request = require('request');
var OAuth   = require('oauth-1.0a');
var crypto  = require('crypto');
var promise = require('bluebird');
var _url    = require('url');

module.exports = WooCommerceAPI;

/**
 * WooCommerce REST API wrapper
 *
 * @param {Object} opt
 */
function WooCommerceAPI(opt) {
  if (!(this instanceof WooCommerceAPI)) {
    return new WooCommerceAPI(opt);
  }

  opt = opt || {};

  if (!(opt.url)) {
    throw new Error('url is required');
  }

  if (!(opt.consumerKey)) {
    throw new Error('consumerKey is required');
  }

  if (!(opt.consumerSecret)) {
    throw new Error('consumerSecret is required');
  }

  this.classVersion = '1.4.0';
  this._setDefaultsOptions(opt);
}

/**
 * Set default options
 *
 * @param {Object} opt
 */
WooCommerceAPI.prototype._setDefaultsOptions = function(opt) {
  this.url             = opt.url;
  this.wpAPI           = opt.wpAPI || false;
  this.wpAPIPrefix     = opt.wpAPIPrefix || 'wp-json';
  this.version         = opt.version || 'v3';
  this.isSsl           = /^https/i.test(this.url);
  this.consumerKey     = opt.consumerKey;
  this.consumerSecret  = opt.consumerSecret;
  this.verifySsl       = false === opt.verifySsl ? false : true;
  this.encoding        = opt.encoding || 'utf8';
  this.queryStringAuth = opt.queryStringAuth || false;
  this.port            = opt.port || '';
  this.timeout         = opt.timeout;
};

/**
 * Normalize query string for oAuth
 *
 * @param  {string} url
 * @return {string}
 */
WooCommerceAPI.prototype._normalizeQueryString = function(url) {
  // Exit if don't find query string
  if (-1 === url.indexOf('?')) {
    return url;
  }

  var query       = _url.parse(url, true).query;
  var params      = [];
  var queryString = '';

  for (var p in query) {
    params.push(p);
  }
  params.sort();

  for (var i in params) {
    if (queryString.length) {
      queryString += '&';
    }

    queryString += encodeURIComponent(params[i]).replace('%5B', '[')
      .replace('%5D', ']');
    queryString += '=';
    queryString += encodeURIComponent(query[params[i]]);
  }

  return url.split('?')[0] + '?' + queryString;
};

/**
 * Get URL
 *
 * @param  {String} endpoint
 *
 * @return {String}
 */
WooCommerceAPI.prototype._getUrl = function(endpoint) {
  var url = '/' === this.url.slice(-1) ? this.url : this.url + '/';
  var api = this.wpAPI ? this.wpAPIPrefix + '/' : 'wc-api/';

  url = url + api + this.version + '/' + endpoint;

  // Include port.
  if ('' !== this.port) {
    var hostname = _url.parse(url, true).hostname;
    url = url.replace(hostname, hostname + ':' + this.port);
  }

  if (!this.isSsl) {
    return this._normalizeQueryString(url);
  }

  return url;
};

/**
 * Get OAuth
 *
 * @return {Object}
 */
WooCommerceAPI.prototype._getOAuth = function() {
  var data = {
    consumer: {
      key: this.consumerKey,
      secret: this.consumerSecret
    },
    signature_method: 'HMAC-SHA256',
    hash_function: function(base_string, key) {
        return crypto.createHmac('sha256', key).update(base_string)
          .digest('base64');
    }
  };

  if (-1 < [ 'v1', 'v2' ].indexOf(this.version)) {
    data.last_ampersand = false;
  }

  return new OAuth(data);
};

/**
 * Do requests
 *
 * @param  {String}   method
 * @param  {String}   endpoint
 * @param  {Object}   data
 * @param  {Function} callback
 *
 * @return {Object}
 */
WooCommerceAPI.prototype._request = function(method, endpoint, data, callback) {
  var url = this._getUrl(endpoint);

  var params = {
    url: url,
    method: method,
    encoding: this.encoding,
    timeout: this.timeout,
    headers: {
      'User-Agent': 'WooCommerce API Client-Node.js/' + this.classVersion,
      'Accept': 'application/json'
    }
  };

  if (this.isSsl) {
    if (this.queryStringAuth) {
      params.qs = {
        consumer_key: this.consumerKey,
        consumer_secret: this.consumerSecret
      };
    } else {
      params.auth = {
        user: this.consumerKey,
        pass: this.consumerSecret
      };
    }

    if (!this.verifySsl) {
      params.strictSSL = false;
    }
  } else {
    params.qs = this._getOAuth().authorize({
      url: url,
      method: method
    });
  }

  if (data) {
    params.headers['Content-Type'] = 'application/json;charset=utf-8';
    params.body = JSON.stringify(data);
  }

  if (!callback) {
    return request(params);
  }

  return request(params, callback);
};

/**
 * GET requests
 *
 * @param  {String}   endpoint
 * @param  {Function} callback
 *
 * @return {Object}
 */
WooCommerceAPI.prototype.get = function(endpoint, callback) {
  return this._request('GET', endpoint, null, callback);
};

/**
 * POST requests
 *
 * @param  {String}   endpoint
 * @param  {Object}   data
 * @param  {Function} callback
 *
 * @return {Object}
 */
WooCommerceAPI.prototype.post = function(endpoint, data, callback) {
  return this._request('POST', endpoint, data, callback);
};

/**
 * PUT requests
 *
 * @param  {String}   endpoint
 * @param  {Object}   data
 * @param  {Function} callback
 *
 * @return {Object}
 */
WooCommerceAPI.prototype.put = function(endpoint, data, callback) {
  return this._request('PUT', endpoint, data, callback);
};

/**
 * DELETE requests
 *
 * @param  {String}   endpoint
 * @param  {Function} callback
 *
 * @return {Object}
 */
WooCommerceAPI.prototype.delete = function(endpoint, callback) {
  return this._request('DELETE', endpoint, null, callback);
};

/**
 * OPTIONS requests
 *
 * @param  {String}   endpoint
 * @param  {Function} callback
 *
 * @return {Object}
 */
WooCommerceAPI.prototype.options = function(endpoint, callback) {
  return this._request('OPTIONS', endpoint, null, callback);
};

/**
 * Promifying all requests exposing new methods
 * named [method]Async like in getAsync()
 */
promise.promisifyAll(WooCommerceAPI.prototype);
<|endoftext|>


<commit_before>var Vec2;
if (typeof require !== 'undefined') {
  Vec2 = require('vec2');
} else if (window !== 'undefined') {
  Vec2 = window.Vec2;
}

Touch.prototype = new Vec2()

function Touch () {
  //browsers optimise properties set in the contructor.
  this.force = 0   ; this.event = null ; this.target = null;
  this.start = true; this.end   = false; this.type = 'init'
}

// should not be called by user.
// only browser should move touches.
Touch.prototype._update = function (e, ev) {
  ev = ev || e
  this.force  = (
    e.force || e.webkitForce ||
    Math.min((1 + ev.ctrlKey + ev.altKey + ev.shiftKey) / 3, 1)
  )

  this.event  = ev
  this.id     = e.identifier != null ? e.identifier : -1
  this.target = e.target
  this.type   = ev.type
  this.end = /(end|up)$/.test(this.type)
  this.set(e.clientX, e.clientY)

  if(this.end) {
    this.change()
    this.observers = [] //deregister listeners
  }
  return this
}

function vectorTouch(el, handler, opts) {

  if('function' === typeof el)
    handler = el, el = document.documentElement, opts = handler || {}

  var touches = []

  function each(iter) {
    return function (ev) {
      [].forEach.call(ev.changedTouches,  function (e) { iter(e, ev) })
      if(opts.preventDefault)
        ev.preventDefault()
    }
  }

  var touchStart = each(function (e, ev) {
    handler(touches[e.identifier] = new Touch()._update(e, ev), touches)
  })

  var touchMove = each(function (e, ev) {
    touches[e.identifier]._update(e, ev)
  })

  var touchEnd = each(function (e, ev) {
    touches[e.identifier]._update(e, ev)
    delete touches[e.identifier]
  })

  el.addEventListener('touchstart',    touchStart)
  el.addEventListener('touchmove',     touchMove)
  el.addEventListener('touchend',      touchEnd)
  el.addEventListener('MozTouchStart', touchStart)
  el.addEventListener('MozTouchMove',  touchMove)
  el.addEventListener('MozTouchEnd',   touchEnd)

  if(opts.mouse !== false) {
    var down = false
    el.addEventListener('mousedown', function (ev) {
      down = true
      handler(touches[-1] = new Touch()._update(ev), touches)
    })
    el.addEventListener('mousemove', function (ev) {
      if(!down) return
      touches[-1]._update(ev)
    })
    el.addEventListener('mouseup',   function (ev) {
      down = false
      touches[-1]._update(ev)
      delete touches[-1]
    })
  }
}

if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
  module.exports = vectorTouch;
}

if (typeof window !== 'undefined') {
  window.vectorTouch = vectorTouch;
}
<commit_msg>remove mozilla events (works with normal touch events nowadays) <commit_after>var Vec2;
if (typeof require !== 'undefined') {
  Vec2 = require('vec2');
} else if (window !== 'undefined') {
  Vec2 = window.Vec2;
}

Touch.prototype = new Vec2()

function Touch () {
  //browsers optimise properties set in the contructor.
  this.force = 0   ; this.event = null ; this.target = null;
  this.start = true; this.end   = false; this.type = 'init'
}

// should not be called by user.
// only browser should move touches.
Touch.prototype._update = function (e, ev) {
  ev = ev || e
  this.force  = (
    e.force || e.webkitForce ||
    Math.min((1 + ev.ctrlKey + ev.altKey + ev.shiftKey) / 3, 1)
  )

  this.event  = ev
  this.id     = e.identifier != null ? e.identifier : -1
  this.target = e.target
  this.type   = ev.type
  this.end = /(end|up)$/.test(this.type)
  this.set(e.clientX, e.clientY)

  if(this.end) {
    this.change()
    this.observers = [] //deregister listeners
  }
  return this
}

function vectorTouch(el, handler, opts) {

  if('function' === typeof el)
    handler = el, el = document.documentElement, opts = handler || {}

  var touches = []

  function each(iter) {
    return function (ev) {
      [].forEach.call(ev.changedTouches,  function (e) { iter(e, ev) })
      if(opts.preventDefault)
        ev.preventDefault()
    }
  }

  var touchStart = each(function (e, ev) {
    handler(touches[e.identifier] = new Touch()._update(e, ev), touches)
  })

  var touchMove = each(function (e, ev) {
    touches[e.identifier]._update(e, ev)
  })

  var touchEnd = each(function (e, ev) {
    touches[e.identifier]._update(e, ev)
    delete touches[e.identifier]
  })

  el.addEventListener('touchstart',    touchStart)
  el.addEventListener('touchmove',     touchMove)
  el.addEventListener('touchend',      touchEnd)

  if(opts.mouse !== false) {
    var down = false
    el.addEventListener('mousedown', function (ev) {
      down = true
      handler(touches[-1] = new Touch()._update(ev), touches)
    })
    el.addEventListener('mousemove', function (ev) {
      if(!down) return
      touches[-1]._update(ev)
    })
    el.addEventListener('mouseup',   function (ev) {
      down = false
      touches[-1]._update(ev)
      delete touches[-1]
    })
  }
}

if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
  module.exports = vectorTouch;
}

if (typeof window !== 'undefined') {
  window.vectorTouch = vectorTouch;
}
<|endoftext|>


<commit_before>'use strict';
var fs = require('fs');
var path = require('path');
var Readable = require('stream').Readable;
var glob = require('glob');
var dargs = require('dargs');
var mkdirp = require('mkdirp');
var rimraf = require('rimraf');
var md5Hex = require('md5-hex');
var spawn = require('win-spawn');
var gutil = require('gulp-util');
var assign = require('object-assign');
var convert = require('convert-source-map');
var eachAsync = require('each-async');
var osTmpdir = require('os-tmpdir');
var pathExists = require('path-exists');

var logger = require('./logger');
var utils = require('./utils');

var emitErr = utils.emitErr;
var uniqueIntermediateDirectory = utils.uniqueIntermediateDirectory;

function gulpRubySass (source, options) {
	var cwd = process.cwd();
	var defaults = {
		tempDir: osTmpdir(),
		verbose: false,
		sourcemap: false,
		emitCompileError: false
	};

	options = assign(defaults, options);
	options.update = true;

	var stream = new Readable({objectMode: true});
	stream._read = function () {}; 	// redundant but necessary

	// alert user that `container` is deprecated
	if (options.container) {
		gutil.log(gutil.colors.yellow(
			'The container option has been deprecated. Simultanious tasks work automatically now!\n' +
		  'This will become an error in gulp-ruby-sass 2.0'
	  ));
	}

	// error if user tries to watch their files with the Sass gem
	if (options.watch || options.poll) {
		emitErr(stream, '`watch` and `poll` are not valid options for gulp-ruby-sass. Use `gulp.watch` to rebuild your files on change.');
	}

	// error if user tries to pass a Sass option to sourcemap
	if (typeof options.sourcemap !== 'boolean') {
		emitErr(stream, 'The sourcemap option must be true or false. See the readme for instructions on using Sass sourcemaps with gulp.');
	}

	options.sourcemap = options.sourcemap === true ? 'file' : 'none';

	// create temporary directory path for the task using current working
	// directory, source and options
	var intermediateDir = uniqueIntermediateDirectory(options.tempDir, source);
	var base;
	var dest;

	// directory source
	if (path.extname(source) === '') {
		base = path.join(cwd, source);
		dest = intermediateDir;
	}

	// single file source
	else {
		base = path.join(cwd, path.dirname(source));
		dest = path.join(
			intermediateDir,
			gutil.replaceExtension(path.basename(source), '.css')
		);

		// sass's single file compilation doesn't create a destination directory, so
		// we have to ourselves
		mkdirp(intermediateDir);
	}

	var compileMapping = source + ':' + dest;

	// TODO: implement glob file source

	var args = dargs(options, [
		'bundleExec',
		'watch',
		'poll',
		'tempDir',
		'verbose',
		'emitCompileError',
		'container'
	]).concat(compileMapping);

	var command;

	if (options.bundleExec) {
		command = 'bundle';
		args.unshift('exec', 'sass');
	} else {
		command = 'sass';
	}

	// plugin logging
	if (options.verbose) {
		logger.verbose(command, args);
	}

	var sass = spawn(command, args);

	sass.stdout.setEncoding('utf8');
	sass.stderr.setEncoding('utf8');

	sass.stdout.on('data', function (data) {
		logger.stdout(stream, intermediateDir, data);
	});

	sass.stderr.on('data', function (data) {
		logger.stderr(stream, intermediateDir, data);
	});

	sass.on('error', function (err) {
		logger.error(stream, err);
	});

	sass.on('close', function (code) {
		if (options.emitCompileError && code !== 0) {
			emitErr(stream, 'Sass compilation failed. See console output for more information.');
		}

		glob(path.join(intermediateDir, '**', '*'), function (err, files) {
			if (err) {
				emitErr(stream, err);
			}

			eachAsync(files, function (file, i, next) {
				if (fs.statSync(file).isDirectory() || path.extname(file) === '.map') {
					next();
					return;
				}

				fs.readFile(file, function (err, data) {
					if (err) {
						emitErr(stream, err);
						next();
						return;
					}

					// rewrite file paths so gulp thinks the file came from cwd, not the
					// intermediate directory
					var vinylFile = new gutil.File({
						cwd: cwd,
						base: base,
						path: file.replace(intermediateDir, base)
					});

					// sourcemap integration
					// if we are managing sourcemaps and a sourcemap exists
					if (options.sourcemap === 'file' && pathExists.sync(file + '.map')) {

						// remove sourcemap comment; gulp-sourcemaps will add it back in
						data = new Buffer( convert.removeMapFileComments(data.toString()) );
						var sourcemapObject = JSON.parse(fs.readFileSync(file + '.map', 'utf8'));

						// create relative paths for sources
						sourcemapObject.sources = sourcemapObject.sources.map(function (sourcemapPath) {
							var absoluteSourcemapPath = decodeURI(path.resolve(
								'/',
								sourcemapPath.replace('file:///', '')
							));
							return path.relative(base, absoluteSourcemapPath);
						});

						vinylFile.sourceMap = sourcemapObject;
					}

					vinylFile.contents = data;
					stream.push(vinylFile);
					next();
					return;
				});
			}, function () {
				// cleanup previously generated files for next run
				// TODO: This kills caching. Keeping will push files through that are not in
				// the current gulp.src. We need to decide whether to use a Sass style caching
				// strategy, or a gulp style strategy, and what each would look like.
				rimraf(intermediateDir, function () {
					stream.push(null);
				});
			});
		});
	});

	return stream;
}

gulpRubySass.logError = function logError(err) {
  var message = new gutil.PluginError('gulp-ruby-sass', err);
  process.stderr.write(message + '\n');
  this.emit('end');
};

module.exports = gulpRubySass;
<commit_msg>Remove defaults var, just assign directly<commit_after>'use strict';
var fs = require('fs');
var path = require('path');
var Readable = require('stream').Readable;
var glob = require('glob');
var dargs = require('dargs');
var mkdirp = require('mkdirp');
var rimraf = require('rimraf');
var md5Hex = require('md5-hex');
var spawn = require('win-spawn');
var gutil = require('gulp-util');
var assign = require('object-assign');
var convert = require('convert-source-map');
var eachAsync = require('each-async');
var osTmpdir = require('os-tmpdir');
var pathExists = require('path-exists');

var logger = require('./logger');
var utils = require('./utils');

var emitErr = utils.emitErr;
var uniqueIntermediateDirectory = utils.uniqueIntermediateDirectory;

function gulpRubySass (source, options) {
	var cwd = process.cwd();

	options = assign({
		tempDir: osTmpdir(),
		verbose: false,
		sourcemap: false,
		emitCompileError: false
	}, options);

	options.update = true;

	var stream = new Readable({objectMode: true});
	stream._read = function () {}; 	// redundant but necessary

	// alert user that `container` is deprecated
	if (options.container) {
		gutil.log(gutil.colors.yellow(
			'The container option has been deprecated. Simultanious tasks work automatically now!\n' +
		  'This will become an error in gulp-ruby-sass 2.0'
	  ));
	}

	// error if user tries to watch their files with the Sass gem
	if (options.watch || options.poll) {
		emitErr(stream, '`watch` and `poll` are not valid options for gulp-ruby-sass. Use `gulp.watch` to rebuild your files on change.');
	}

	// error if user tries to pass a Sass option to sourcemap
	if (typeof options.sourcemap !== 'boolean') {
		emitErr(stream, 'The sourcemap option must be true or false. See the readme for instructions on using Sass sourcemaps with gulp.');
	}

	options.sourcemap = options.sourcemap === true ? 'file' : 'none';

	// create temporary directory path for the task using current working
	// directory, source and options
	var intermediateDir = uniqueIntermediateDirectory(options.tempDir, source);
	var base;
	var dest;

	// directory source
	if (path.extname(source) === '') {
		base = path.join(cwd, source);
		dest = intermediateDir;
	}

	// single file source
	else {
		base = path.join(cwd, path.dirname(source));
		dest = path.join(
			intermediateDir,
			gutil.replaceExtension(path.basename(source), '.css')
		);

		// sass's single file compilation doesn't create a destination directory, so
		// we have to ourselves
		mkdirp(intermediateDir);
	}

	var compileMapping = source + ':' + dest;

	// TODO: implement glob file source

	var args = dargs(options, [
		'bundleExec',
		'watch',
		'poll',
		'tempDir',
		'verbose',
		'emitCompileError',
		'container'
	]).concat(compileMapping);

	var command;

	if (options.bundleExec) {
		command = 'bundle';
		args.unshift('exec', 'sass');
	} else {
		command = 'sass';
	}

	// plugin logging
	if (options.verbose) {
		logger.verbose(command, args);
	}

	var sass = spawn(command, args);

	sass.stdout.setEncoding('utf8');
	sass.stderr.setEncoding('utf8');

	sass.stdout.on('data', function (data) {
		logger.stdout(stream, intermediateDir, data);
	});

	sass.stderr.on('data', function (data) {
		logger.stderr(stream, intermediateDir, data);
	});

	sass.on('error', function (err) {
		logger.error(stream, err);
	});

	sass.on('close', function (code) {
		if (options.emitCompileError && code !== 0) {
			emitErr(stream, 'Sass compilation failed. See console output for more information.');
		}

		glob(path.join(intermediateDir, '**', '*'), function (err, files) {
			if (err) {
				emitErr(stream, err);
			}

			eachAsync(files, function (file, i, next) {
				if (fs.statSync(file).isDirectory() || path.extname(file) === '.map') {
					next();
					return;
				}

				fs.readFile(file, function (err, data) {
					if (err) {
						emitErr(stream, err);
						next();
						return;
					}

					// rewrite file paths so gulp thinks the file came from cwd, not the
					// intermediate directory
					var vinylFile = new gutil.File({
						cwd: cwd,
						base: base,
						path: file.replace(intermediateDir, base)
					});

					// sourcemap integration
					// if we are managing sourcemaps and a sourcemap exists
					if (options.sourcemap === 'file' && pathExists.sync(file + '.map')) {

						// remove sourcemap comment; gulp-sourcemaps will add it back in
						data = new Buffer( convert.removeMapFileComments(data.toString()) );
						var sourcemapObject = JSON.parse(fs.readFileSync(file + '.map', 'utf8'));

						// create relative paths for sources
						sourcemapObject.sources = sourcemapObject.sources.map(function (sourcemapPath) {
							var absoluteSourcemapPath = decodeURI(path.resolve(
								'/',
								sourcemapPath.replace('file:///', '')
							));
							return path.relative(base, absoluteSourcemapPath);
						});

						vinylFile.sourceMap = sourcemapObject;
					}

					vinylFile.contents = data;
					stream.push(vinylFile);
					next();
					return;
				});
			}, function () {
				// cleanup previously generated files for next run
				// TODO: This kills caching. Keeping will push files through that are not in
				// the current gulp.src. We need to decide whether to use a Sass style caching
				// strategy, or a gulp style strategy, and what each would look like.
				rimraf(intermediateDir, function () {
					stream.push(null);
				});
			});
		});
	});

	return stream;
}

gulpRubySass.logError = function logError(err) {
  var message = new gutil.PluginError('gulp-ruby-sass', err);
  process.stderr.write(message + '\n');
  this.emit('end');
};

module.exports = gulpRubySass;
<|endoftext|>


<commit_before>exports.fullRoots = function (index, result) {
  if (index & 1) throw new Error('You can only look up roots for depth(0) blocks')
  if (!result) result = []

  index /= 2

  var offset = 0
  var factor = 1

  while (true) {
    if (!index) return result
    while (factor * 2 <= index) factor *= 2
    result.push(offset + factor - 1)
    offset = offset + 2 * factor
    index -= factor
    factor = 1
  }
}

exports.depth = function (index) {
  var depth = 0

  index += 1
  while (!(index & 1)) {
    depth++
    index = rightShift(index)
  }

  return depth
}

exports.sibling = function (index, depth) {
  if (!depth) depth = exports.depth(index)
  var offset = exports.offset(index, depth)

  return exports.index(depth, offset & 1 ? offset - 1 : offset + 1)
}

exports.parent = function (index, depth) {
  if (!depth) depth = exports.depth(index)
  var offset = exports.offset(index, depth)

  return exports.index(depth + 1, rightShift(offset))
}

exports.leftChild = function (index, depth) {
  if (!(index & 1)) return -1
  if (!depth) depth = exports.depth(index)
  return exports.index(depth - 1, exports.offset(index, depth) * 2)
}

exports.rightChild = function (index, depth) {
  if (!(index & 1)) return -1
  if (!depth) depth = exports.depth(index)
  return exports.index(depth - 1, 1 + (exports.offset(index, depth) * 2))
}

exports.children = function (index, depth) {
  if (!(index & 1)) return null

  if (!depth) depth = exports.depth(index)
  var offset = exports.offset(index, depth) * 2

  return [
    exports.index(depth - 1, offset),
    exports.index(depth - 1, offset + 1)
  ]
}

exports.leftSpan = function (index, depth) {
  if (!(index & 1)) return index
  if (!depth) depth = exports.depth(index)
  return exports.offset(index, depth) * twoPow(depth + 1)
}

exports.rightSpan = function (index, depth) {
  if (!(index & 1)) return index
  if (!depth) depth = exports.depth(index)
  return (exports.offset(index, depth) + 1) * twoPow(depth + 1) - 2
}

exports.count = function (index, depth) {
  if (!(index & 1)) return 1
  if (!depth) depth = exports.depth(index)
  return twoPow(depth + 1) - 1
}

exports.spans = function (index, depth) {
  if (!(index & 1)) return [index, index]
  if (!depth) depth = exports.depth(index)

  var offset = exports.offset(index, depth)
  var width = twoPow(depth + 1)

  return [offset * width, (offset + 1) * width - 2]
}

exports.index = function (depth, offset) {
  return (1 + 2 * offset) * twoPow(depth) - 1
}

exports.offset = function (index, depth) {
  if (!(index & 1)) return index / 2
  if (!depth) depth = exports.depth(index)

  return ((index + 1) / twoPow(depth) - 1) / 2
}

exports.iterator = function (index) {
  var ite = new Iterator()
  ite.seek(index || 0)
  return ite
}

function twoPow (n) {
  return n < 31 ? 1 << n : ((1 << 30) * (1 << (n - 30)))
}

function rightShift (n) {
  return (n - (n & 1)) / 2
}

function Iterator (index) {
  this.index = 0
  this.offset = 0
  this.factor = 0
}

Iterator.prototype.seek = function (index) {
  this.index = index
  if (this.index & 1) {
    this.offset = exports.offset(index)
    this.factor = twoPow(exports.depth(index) + 1)
  } else {
    this.offset = index / 2
    this.factor = 2
  }
}

Iterator.prototype.isLeft = function () {
  return (this.offset & 1) === 0
}

Iterator.prototype.isRight = function () {
  return (this.offset & 1) === 1
}

Iterator.prototype.contains = function (index) {
  return index > this.index
    ? index < (this.index + this.factor / 2)
    : index < this.index
      ? index > (this.index - this.factor / 2)
      : true
}

Iterator.prototype.prev = function () {
  if (!this.offset) return this.index
  this.offset--
  this.index -= this.factor
  return this.index
}

Iterator.prototype.next = function () {
  this.offset++
  this.index += this.factor
  return this.index
}

Iterator.prototype.sibling = function () {
  return this.isLeft() ? this.next() : this.prev()
}

Iterator.prototype.parent = function () {
  if (this.offset & 1) {
    this.index -= this.factor / 2
    this.offset = (this.offset - 1) / 2
  } else {
    this.index += this.factor / 2
    this.offset /= 2
  }
  this.factor *= 2
  return this.index
}

Iterator.prototype.leftSpan = function () {
  this.index = this.index - this.factor / 2 + 1
  this.offset = this.index / 2
  this.factor = 2
  return this.index
}

Iterator.prototype.rightSpan = function () {
  this.index = this.index + this.factor / 2 - 1
  this.offset = this.index / 2
  this.factor = 2
  return this.index
}

Iterator.prototype.leftChild = function () {
  if (this.factor === 2) return this.index
  this.factor /= 2
  this.index -= this.factor / 2
  this.offset *= 2
  return this.index
}

Iterator.prototype.rightChild = function () {
  if (this.factor === 2) return this.index
  this.factor /= 2
  this.index += this.factor / 2
  this.offset = 2 * this.offset + 1
  return this.index
}
<commit_msg>remove unused arg from constructor<commit_after>exports.fullRoots = function (index, result) {
  if (index & 1) throw new Error('You can only look up roots for depth(0) blocks')
  if (!result) result = []

  index /= 2

  var offset = 0
  var factor = 1

  while (true) {
    if (!index) return result
    while (factor * 2 <= index) factor *= 2
    result.push(offset + factor - 1)
    offset = offset + 2 * factor
    index -= factor
    factor = 1
  }
}

exports.depth = function (index) {
  var depth = 0

  index += 1
  while (!(index & 1)) {
    depth++
    index = rightShift(index)
  }

  return depth
}

exports.sibling = function (index, depth) {
  if (!depth) depth = exports.depth(index)
  var offset = exports.offset(index, depth)

  return exports.index(depth, offset & 1 ? offset - 1 : offset + 1)
}

exports.parent = function (index, depth) {
  if (!depth) depth = exports.depth(index)
  var offset = exports.offset(index, depth)

  return exports.index(depth + 1, rightShift(offset))
}

exports.leftChild = function (index, depth) {
  if (!(index & 1)) return -1
  if (!depth) depth = exports.depth(index)
  return exports.index(depth - 1, exports.offset(index, depth) * 2)
}

exports.rightChild = function (index, depth) {
  if (!(index & 1)) return -1
  if (!depth) depth = exports.depth(index)
  return exports.index(depth - 1, 1 + (exports.offset(index, depth) * 2))
}

exports.children = function (index, depth) {
  if (!(index & 1)) return null

  if (!depth) depth = exports.depth(index)
  var offset = exports.offset(index, depth) * 2

  return [
    exports.index(depth - 1, offset),
    exports.index(depth - 1, offset + 1)
  ]
}

exports.leftSpan = function (index, depth) {
  if (!(index & 1)) return index
  if (!depth) depth = exports.depth(index)
  return exports.offset(index, depth) * twoPow(depth + 1)
}

exports.rightSpan = function (index, depth) {
  if (!(index & 1)) return index
  if (!depth) depth = exports.depth(index)
  return (exports.offset(index, depth) + 1) * twoPow(depth + 1) - 2
}

exports.count = function (index, depth) {
  if (!(index & 1)) return 1
  if (!depth) depth = exports.depth(index)
  return twoPow(depth + 1) - 1
}

exports.spans = function (index, depth) {
  if (!(index & 1)) return [index, index]
  if (!depth) depth = exports.depth(index)

  var offset = exports.offset(index, depth)
  var width = twoPow(depth + 1)

  return [offset * width, (offset + 1) * width - 2]
}

exports.index = function (depth, offset) {
  return (1 + 2 * offset) * twoPow(depth) - 1
}

exports.offset = function (index, depth) {
  if (!(index & 1)) return index / 2
  if (!depth) depth = exports.depth(index)

  return ((index + 1) / twoPow(depth) - 1) / 2
}

exports.iterator = function (index) {
  var ite = new Iterator()
  ite.seek(index || 0)
  return ite
}

function twoPow (n) {
  return n < 31 ? 1 << n : ((1 << 30) * (1 << (n - 30)))
}

function rightShift (n) {
  return (n - (n & 1)) / 2
}

function Iterator () {
  this.index = 0
  this.offset = 0
  this.factor = 0
}

Iterator.prototype.seek = function (index) {
  this.index = index
  if (this.index & 1) {
    this.offset = exports.offset(index)
    this.factor = twoPow(exports.depth(index) + 1)
  } else {
    this.offset = index / 2
    this.factor = 2
  }
}

Iterator.prototype.isLeft = function () {
  return (this.offset & 1) === 0
}

Iterator.prototype.isRight = function () {
  return (this.offset & 1) === 1
}

Iterator.prototype.contains = function (index) {
  return index > this.index
    ? index < (this.index + this.factor / 2)
    : index < this.index
      ? index > (this.index - this.factor / 2)
      : true
}

Iterator.prototype.prev = function () {
  if (!this.offset) return this.index
  this.offset--
  this.index -= this.factor
  return this.index
}

Iterator.prototype.next = function () {
  this.offset++
  this.index += this.factor
  return this.index
}

Iterator.prototype.sibling = function () {
  return this.isLeft() ? this.next() : this.prev()
}

Iterator.prototype.parent = function () {
  if (this.offset & 1) {
    this.index -= this.factor / 2
    this.offset = (this.offset - 1) / 2
  } else {
    this.index += this.factor / 2
    this.offset /= 2
  }
  this.factor *= 2
  return this.index
}

Iterator.prototype.leftSpan = function () {
  this.index = this.index - this.factor / 2 + 1
  this.offset = this.index / 2
  this.factor = 2
  return this.index
}

Iterator.prototype.rightSpan = function () {
  this.index = this.index + this.factor / 2 - 1
  this.offset = this.index / 2
  this.factor = 2
  return this.index
}

Iterator.prototype.leftChild = function () {
  if (this.factor === 2) return this.index
  this.factor /= 2
  this.index -= this.factor / 2
  this.offset *= 2
  return this.index
}

Iterator.prototype.rightChild = function () {
  if (this.factor === 2) return this.index
  this.factor /= 2
  this.index += this.factor / 2
  this.offset = 2 * this.offset + 1
  return this.index
}
<|endoftext|>