<commit_before>'use strict';

var MODULE_NAME = 'gmusic';
var MODULE_TYPE = 'backend';

var PlayMusic = require('playmusic');
var mkdirp = require('mkdirp');
var https = require('https');
var fs = require('fs');
var ffmpeg = require('fluent-ffmpeg');
var stream = require('stream');

var nodeplayerConfig = require('nodeplayer').config;
var coreConfig = nodeplayerConfig.getConfig();
var defaultConfig = require('./default-config.js');
var config = nodeplayerConfig.getConfig(MODULE_TYPE + '-' + MODULE_NAME, defaultConfig);

var player;
var logger;

var gmusicBackend = {};
gmusicBackend.name = MODULE_NAME;

// TODO: seeking
var encodeSong = function(origStream, seek, song, progCallback, errCallback) {
    var incompletePath = coreConfig.songCachePath + '/gmusic/incomplete/' + song.songID + '.opus';
    var incompleteStream = fs.createWriteStream(incompletePath, {flags: 'w'});
    var encodedPath = coreConfig.songCachePath + '/gmusic/' + song.songID + '.opus';

    var command = ffmpeg(origStream)
        .noVideo()
        //.inputFormat('mp3')
        //.inputOption('-ac 2')
        .audioCodec('libopus')
        .audioBitrate('192')
        .format('opus')
        .on('error', function(err) {
            logger.error('error while transcoding ' + song.songID + ': ' + err);
            if (fs.existsSync(incompletePath)) {
                fs.unlinkSync(incompletePath);
            }
            errCallback(song, err);
        });

    var opusStream = command.pipe(null, {end: true});
    opusStream.on('data', function(chunk) {
        incompleteStream.write(chunk, undefined, function() {
            progCallback(song, chunk.length, false);
        });
    });
    opusStream.on('end', function() {
        incompleteStream.end(undefined, undefined, function() {
            logger.verbose('transcoding ended for ' + song.songID);

            // TODO: we don't know if transcoding ended successfully or not,
            // and there might be a race condition between errCallback deleting
            // the file and us trying to move it to the songCache

            // atomically move result to encodedPath
            if (fs.existsSync(incompletePath)) {
                fs.renameSync(incompletePath, encodedPath);
                progCallback(song, 0, true);
            } else {
                progCallback(song, 0, false);
            }
        });
    });

    logger.verbose('transcoding ' + song.songID + '...');
    return function(err) {
        command.kill();
        logger.verbose('canceled preparing: ' + song.songID + ': ' + err);
        if (fs.existsSync(incompletePath)) {
            fs.unlinkSync(incompletePath);
        }
        errCallback(song, 'canceled preparing: ' + song.songID + ': ' + err);
    };
};

var gmusicDownload = function(song, progCallback, errCallback) {
    var req = null;
    var gmusicStream = new stream.PassThrough();

    var doDownload = function(streamUrl) {
        if (streamUrl) {
            logger.debug('downloading song ' + song.songID);

            req = https.request(streamUrl, function(res) {
                res.pipe(gmusicStream, {end: false});

                res.on('end', function() {
                    if (res.statusCode === 302) { // redirect
                        logger.debug('redirected. retrying with new URL');
                        res.unpipe();
                        doDownload(res.headers.location);
                    } else if (res.statusCode === 200) {
                        logger.debug('download finished');
                        gmusicStream.end();
                    } else {
                        gmusicStream.end();
                        logger.error('unknown status code ' + res.statusCode);
                        if (errCallback) {
                            errCallback(song, 'unknown status code ' + res.statusCode);
                        }
                    }
                });
            });
            req.on('error', function(e) {
                logger.error(e + ' while fetching! reconnecting in 5s...');
                setTimeout(function() {
                    gmusicBackend.init(function() {
                        logger.error('error while fetching! now reconnected to gmusic');
                        gmusicBackend.pm.getStreamUrl(song.songID, function(streamUrl) {
                            doDownload(streamUrl);
                        }, function(err) {
                            errCallback(song, err);
                        });
                    });
                }, 5000);
            });
            req.end();
        } else {
            gmusicBackend.pm.getStreamUrl(song.songID, function(streamUrl) {
                doDownload(streamUrl);
            }, function(err) {
                errCallback(song, err);
            });
        }
    };

    /*
    return function(err) {
        // TODO: this doesn't seem to work very well...
        if (command)
            command.kill();
        if (req)
            req.abort();

        if (fs.existsSync(filePath))
            fs.unlinkSync(filePath);
        if (fs.existsSync(incompleteFilePath))
            fs.unlinkSync(incompleteFilePath);

        logger.verbose('canceled preparing: ' + songID + ': ' + err);

        errCallback();
    };
    */

    doDownload();

    var cancelEncoding = encodeSong(gmusicStream, 0, song, progCallback, errCallback);
    return function(err) {
        if (req) {
            req.abort();
        }
        cancelEncoding(err);
    };
};

// cache song to disk.
// on success: progCallback must be called with true as argument
// on failure: errCallback must be called with error message
// returns a function that cancels preparing
gmusicBackend.prepareSong = function(song, progCallback, errCallback) {
    var filePath = coreConfig.songCachePath + '/gmusic/' + song.songID + '.opus';

    if (fs.existsSync(filePath)) {
        // true as first argument because there is song data
        progCallback(song, true, true);
    } else {
        return gmusicDownload(song, progCallback, errCallback);
    }
};

gmusicBackend.isPrepared = function(song) {
    var filePath = coreConfig.songCachePath + '/gmusic/' + song.songID + '.opus';
    return fs.existsSync(filePath);
};

// search for music from the backend
// on success: callback must be called with a list of song objects
// on failure: errCallback must be called with error message
gmusicBackend.search = function(query, callback, errCallback) {
    gmusicBackend.pm.search(query.terms, Math.min(100, coreConfig.searchResultCnt), function(data) {
        var songs;
        var results = {};
        results.songs = {};

        if (data.entries) {
            songs = data.entries.filter(function(entry) {
                return entry.type === '1'; // songs only, no albums/artists
            });

            for (var i = 0; i < songs.length; i++) {
                results.songs[songs[i].track.nid] = {
                    artist: songs[i].track.artist,
                    title: songs[i].track.title,
                    album: songs[i].track.album,
                    albumArt: null, // TODO: can we add this?
                    duration: songs[i].track.durationMillis,
                    songID: songs[i].track.nid,
                    score: songs[i].score,
                    backendName: MODULE_NAME,
                    format: 'opus'
                };
            }
        }

        callback(results);
    }, function(err) {
        errCallback('error while searching gmusic: ' + err);
    });
};

// called when partyplay is started to initialize the backend
// do any necessary initialization here
gmusicBackend.init = function(_player, _logger, callback) {
    player = _player;
    logger = _logger;

    mkdirp.sync(coreConfig.songCachePath + '/gmusic/incomplete');

    // initialize google play music backend
    gmusicBackend.pm = new PlayMusic();
    gmusicBackend.pm.init(config, callback);
};

module.exports = gmusicBackend;
<commit_msg>album art!<commit_after>'use strict';

var MODULE_NAME = 'gmusic';
var MODULE_TYPE = 'backend';

var PlayMusic = require('playmusic');
var mkdirp = require('mkdirp');
var https = require('https');
var fs = require('fs');
var ffmpeg = require('fluent-ffmpeg');
var stream = require('stream');

var nodeplayerConfig = require('nodeplayer').config;
var coreConfig = nodeplayerConfig.getConfig();
var defaultConfig = require('./default-config.js');
var config = nodeplayerConfig.getConfig(MODULE_TYPE + '-' + MODULE_NAME, defaultConfig);

var player;
var logger;

var gmusicBackend = {};
gmusicBackend.name = MODULE_NAME;

// TODO: seeking
var encodeSong = function(origStream, seek, song, progCallback, errCallback) {
    var incompletePath = coreConfig.songCachePath + '/gmusic/incomplete/' + song.songID + '.opus';
    var incompleteStream = fs.createWriteStream(incompletePath, {flags: 'w'});
    var encodedPath = coreConfig.songCachePath + '/gmusic/' + song.songID + '.opus';

    var command = ffmpeg(origStream)
        .noVideo()
        //.inputFormat('mp3')
        //.inputOption('-ac 2')
        .audioCodec('libopus')
        .audioBitrate('192')
        .format('opus')
        .on('error', function(err) {
            logger.error('error while transcoding ' + song.songID + ': ' + err);
            if (fs.existsSync(incompletePath)) {
                fs.unlinkSync(incompletePath);
            }
            errCallback(song, err);
        });

    var opusStream = command.pipe(null, {end: true});
    opusStream.on('data', function(chunk) {
        incompleteStream.write(chunk, undefined, function() {
            progCallback(song, chunk.length, false);
        });
    });
    opusStream.on('end', function() {
        incompleteStream.end(undefined, undefined, function() {
            logger.verbose('transcoding ended for ' + song.songID);

            // TODO: we don't know if transcoding ended successfully or not,
            // and there might be a race condition between errCallback deleting
            // the file and us trying to move it to the songCache

            // atomically move result to encodedPath
            if (fs.existsSync(incompletePath)) {
                fs.renameSync(incompletePath, encodedPath);
                progCallback(song, 0, true);
            } else {
                progCallback(song, 0, false);
            }
        });
    });

    logger.verbose('transcoding ' + song.songID + '...');
    return function(err) {
        command.kill();
        logger.verbose('canceled preparing: ' + song.songID + ': ' + err);
        if (fs.existsSync(incompletePath)) {
            fs.unlinkSync(incompletePath);
        }
        errCallback(song, 'canceled preparing: ' + song.songID + ': ' + err);
    };
};

var gmusicDownload = function(song, progCallback, errCallback) {
    var req = null;
    var gmusicStream = new stream.PassThrough();

    var doDownload = function(streamUrl) {
        if (streamUrl) {
            logger.debug('downloading song ' + song.songID);

            req = https.request(streamUrl, function(res) {
                res.pipe(gmusicStream, {end: false});

                res.on('end', function() {
                    if (res.statusCode === 302) { // redirect
                        logger.debug('redirected. retrying with new URL');
                        res.unpipe();
                        doDownload(res.headers.location);
                    } else if (res.statusCode === 200) {
                        logger.debug('download finished');
                        gmusicStream.end();
                    } else {
                        gmusicStream.end();
                        logger.error('unknown status code ' + res.statusCode);
                        if (errCallback) {
                            errCallback(song, 'unknown status code ' + res.statusCode);
                        }
                    }
                });
            });
            req.on('error', function(e) {
                logger.error(e + ' while fetching! reconnecting in 5s...');
                setTimeout(function() {
                    gmusicBackend.init(function() {
                        logger.error('error while fetching! now reconnected to gmusic');
                        gmusicBackend.pm.getStreamUrl(song.songID, function(streamUrl) {
                            doDownload(streamUrl);
                        }, function(err) {
                            errCallback(song, err);
                        });
                    });
                }, 5000);
            });
            req.end();
        } else {
            gmusicBackend.pm.getStreamUrl(song.songID, function(streamUrl) {
                doDownload(streamUrl);
            }, function(err) {
                errCallback(song, err);
            });
        }
    };

    /*
    return function(err) {
        // TODO: this doesn't seem to work very well...
        if (command)
            command.kill();
        if (req)
            req.abort();

        if (fs.existsSync(filePath))
            fs.unlinkSync(filePath);
        if (fs.existsSync(incompleteFilePath))
            fs.unlinkSync(incompleteFilePath);

        logger.verbose('canceled preparing: ' + songID + ': ' + err);

        errCallback();
    };
    */

    doDownload();

    var cancelEncoding = encodeSong(gmusicStream, 0, song, progCallback, errCallback);
    return function(err) {
        if (req) {
            req.abort();
        }
        cancelEncoding(err);
    };
};

// cache song to disk.
// on success: progCallback must be called with true as argument
// on failure: errCallback must be called with error message
// returns a function that cancels preparing
gmusicBackend.prepareSong = function(song, progCallback, errCallback) {
    var filePath = coreConfig.songCachePath + '/gmusic/' + song.songID + '.opus';

    if (fs.existsSync(filePath)) {
        // true as first argument because there is song data
        progCallback(song, true, true);
    } else {
        return gmusicDownload(song, progCallback, errCallback);
    }
};

gmusicBackend.isPrepared = function(song) {
    var filePath = coreConfig.songCachePath + '/gmusic/' + song.songID + '.opus';
    return fs.existsSync(filePath);
};

// search for music from the backend
// on success: callback must be called with a list of song objects
// on failure: errCallback must be called with error message
gmusicBackend.search = function(query, callback, errCallback) {
    gmusicBackend.pm.search(query.terms, Math.min(100, coreConfig.searchResultCnt), function(data) {
        var songs;
        var results = {};
        results.songs = {};

        if (data.entries) {
            songs = data.entries.filter(function(entry) {
                return entry.type === '1'; // songs only, no albums/artists
            });

            for (var i = 0; i < songs.length; i++) {
                results.songs[songs[i].track.nid] = {
                    artist: songs[i].track.artist,
                    title: songs[i].track.title,
                    album: songs[i].track.album,
                    albumArt: {
                        lq: songs[i].track.albumArtRef && songs[i].track.albumArtRef[0] ?
                            songs[i].track.albumArtRef[0].url + '=s60-e100-c' : null,
                        hq: songs[i].track.albumArtRef && songs[i].track.albumArtRef[0] ?
                            songs[i].track.albumArtRef[0].url : null
                    },
                    duration: songs[i].track.durationMillis,
                    songID: songs[i].track.nid,
                    score: songs[i].score,
                    backendName: MODULE_NAME,
                    format: 'opus'
                };
            }
        }

        callback(results);
    }, function(err) {
        errCallback('error while searching gmusic: ' + err);
    });
};

// called when partyplay is started to initialize the backend
// do any necessary initialization here
gmusicBackend.init = function(_player, _logger, callback) {
    player = _player;
    logger = _logger;

    mkdirp.sync(coreConfig.songCachePath + '/gmusic/incomplete');

    // initialize google play music backend
    gmusicBackend.pm = new PlayMusic();
    gmusicBackend.pm.init(config, callback);
};

module.exports = gmusicBackend;
<|endoftext|>


<commit_before>/**
 * Compute an isoline as a GeoJSON feature from a regular grid
 * Uses the Marching Squares algorithm, with code ported from
 * https://github.com/conveyal/r5/blob/master/src/main/java/com/conveyal/r5/analyst/IsochroneFeature.java
 * @author mattwigway
 */

import inside from 'turf-inside'
import point from 'turf-point'
import dbg from 'debug'

const debug = dbg('jsolines')

/** Create a JSON isoline. Surface is a (possibly typed) array, width and height are its width and height, and cutoff is the cutoff */
export default function jsolines ({surface, width, height, cutoff, project}) {
  // first, create the contour grid
  let contour = getContour({surface, width, height, cutoff})
  let cWidth = width - 1

  // javascript does not have boolean arrays. lame.
  let found = new Uint8Array((width - 1) * (height - 1))

  // DEBUG, comment out to save memory
  let indices = []

  // we'll sort out what shell goes with what hole in a bit
  let shells = []
  let holes = []

  // find a cell that has a line in it, then follow that line, keeping filled area to your
  // left. This lets us use winding direction to determine holes.
  for (let origy = 0; origy < height - 1; origy++) {
    for (let origx = 0; origx < width - 1; origx++) {
      if (found[origy * cWidth + origx] === 1) {
        continue
      }

      let idx = contour[origy * cWidth + origx]
      // continue if there is no line here or if it's a saddle, as we don't know which way the saddle goes
      if (idx === 0 || idx === 5 || idx === 10 || idx === 15) continue

      // huzzah! we have found a line, now follow it, keeping the filled area to our left,
      // which allows us to use the winding direction to determine what should be a shell and
      // what should be a hole
      let x = origx
      let y = origy

      let prevx = -1
      let prevy = -1
      let startx = -1
      let starty = -1

      // track winding direction
      let direction = 0

      let coords = []

      RING: while (true) {
        // make sure we're not traveling in circles
        // NB using index from _previous_ cell, we have not yet set an index for this cell
        if (found[y * cWidth + x] === 1) {
          console.log(`Ring crosses other ring (or possibly self) at ${x}, ${y} coming from case ${idx}`)
          console.log(`Last few indices: ${indices.slice(Math.max(0, indices.length - 10))}`)
          break RING
        }

        prevx = startx
        prevy = starty
        startx = x
        starty = y
        idx = contour[y * cWidth + x]

        indices.push(idx)

        // only mark as found if it's not a saddle because we expect to reach saddles twice.
        if (idx !== 5 && idx !== 10) {
          found[y * cWidth + x] = 1
        }

        // follow the loop
        switch (idx) {
          case 0:
            console.log('Ran off outside of ring')
            break RING
          case 1:
            x--
            break
          // NB: +y is down
          case 2:
            y++
            break
          case 3:
            x--
            break
          case 4:
            x++
            break
          case 5:
            // assume that saddle has // orientation (as opposed to \\). It doesn't
            // really matter if we're wrong, we'll just have two disjoint pieces where we should have
            // one, or vice versa
            if (prevy > y) {
              // came from bottom
              x++
            } else if (prevy < y) {
              // came from top
              x--
            } else {
              console.log('Entered case 5 saddle point from wrong direction!')
            }
            break
          case 6:
            y++
            break
          case 7:
            x--
            break
          case 8:
            y--
            break
          case 9:
            y--
            break
          case 10:
            if (prevx < x) {
              // came from left
              y++
            } else if (prevx > x) {
              // came from right
              y--
            } else {
              console.log('Entered case 10 saddle point from wrong direction.')
            }
            break
          case 11:
            y--
            break
          case 12:
            x++
            break
          case 13:
            x++
            break
          case 14:
            y++
            break
          case 15:
            console.log('Ran off inside of ring')
            break RING
        }

        // keep track of winding direction
        direction += (x - startx) * (y + starty)

        let topLeft = surface[y * width + x]
        let topRight = surface[y * width + x + 1]
        let botLeft = surface[(y + 1) * width + x]
        let botRight = surface[(y + 1) * width + x + 1]

        // do linear interpolation
        let coord
        if (startx < x) {
          // came from left
          let frac = (cutoff - topLeft) / (botLeft - topLeft)

          if (frac === Infinity) {
            debug(`segment fraction from left is Infinity at ${x}, ${y}; if this is at the edge of the query this is not totally unexpected.`)
            frac = 0.5
          }

          coord = [x, y + frac]
        } else if (startx > x) {
          // came from right
          let frac = (cutoff - topRight) / (botRight - topRight)

          if (frac === Infinity) {
            debug(`segment fraction from right is Infinity at ${x}, ${y}; if this is at the edge of the query this is not totally unexpected.`)
            frac = 0.5
          }

          coord = [x + 1, y + frac]
        } else if (starty > y) {
          // came from bottom
          let frac = (cutoff - botLeft) / (botRight - botLeft)

          if (frac === Infinity) {
            debug(`segment fraction from bottom is Infinity at ${x}, ${y}; if this is at the edge of the query this is not totally unexpected.`)
            frac = 0.5
          }

          coord = [x + frac, y + 1]
        } else if (starty < y) {
          // came from top
          let frac = (cutoff - topLeft) / (topRight - topLeft)

          if (frac === Infinity) {
            debug(`segment fraction from top is Infinity at ${x}, ${y}; if this is at the edge of the query this is not totally unexpected.`)
            frac = 0.5
          }

          coord = [x + frac, y + 1]
        } else {
          console.log(`Unexpected coordinate shift from ${startx}, ${starty} to ${x}, ${y}, discarding ring`)
          break RING
        }

        coords.push(project(coord))

        if (coords.length > 10000) {
          console.log('More than 10000 coordinates found in ring, skipping this ring')
          break RING
        }

        // we're back at the start of the ring
        if (x === origx && y === origy) {
          coords.push(coords[0]) // close the ring

          // make it a fully-fledged GeoJSON object
          let geom = {
            type: 'Feature',
            geometry: {
              type: 'Polygon',
              coordinates: [coords]
            }
          }

          // check winding direction
          // positive means counter clockwise, see http://stackoverflow.com/questions/1165647
          // NB +y is down so the signs are reversed from what would normally be expected
          if (direction > 0) shells.push(geom)
          else holes.push(geom)
          break RING
        }
      }
    }
  }

  // shell game time.
  // sort out shells and holes
  HOLES: for (let hole of holes) {
    for (let shell of shells) {
      // NB this is checking whether the first coordinate of the hole is inside the shell.
      // This is sufficient as shells don't overlap, and holes are guaranteed to be completely
      // contained by a single shell.
      if (inside(point(hole.geometry.coordinates[0][0]), shell)) {
        shell.geometry.coordinates.push(hole.geometry.coordinates[0])
        continue HOLES
      }
    }

    console.log('Did not find fitting shell for hole')
  }

  return {
    type: 'Feature',
    geometry: {
      type: 'MultiPolygon',
      coordinates: shells.map(s => s.geometry.coordinates)
    }
  }
}

/** Get a contouring grid. Exported for debug purposes, not generally used outside jsolines testing */
export function getContour ({surface, width, height, cutoff}) {
  let contour = new Uint8Array((width - 1) * (height - 1))

  // compute contour values for each cell
  for (let x = 0; x < width - 1; x++) {
    for (let y = 0; y < height - 1; y++) {
      let topLeft = surface[y * width + x] < cutoff
      let topRight = surface[y * width + x + 1] < cutoff
      let botLeft = surface[(y + 1) * width + x] < cutoff
      let botRight = surface[(y + 1) * width + x + 1] < cutoff

      // if we're at the edge of the area, set the outer sides to false, so that isochrones always close
      // even when they actually extend beyond the edges of the surface
      if (x === 0) topLeft = botLeft = false
      if (x === width - 2) topRight = botRight = false
      if (y === 0) topLeft = topRight = false
      if (y === height - 2) botRight = botLeft = false

      let idx = 0

      if (topLeft) idx |= 1 << 3
      if (topRight) idx |= 1 << 2
      if (botRight) idx |= 1 << 1
      if (botLeft) idx |= 1

      contour[y * (width - 1) + x] = idx
    }
  }

  return contour
}
<commit_msg>fix #2, sure enough it was an off-by-one error.<commit_after>/**
 * Compute an isoline as a GeoJSON feature from a regular grid
 * Uses the Marching Squares algorithm, with code ported from
 * https://github.com/conveyal/r5/blob/master/src/main/java/com/conveyal/r5/analyst/IsochroneFeature.java
 * @author mattwigway
 */

import inside from 'turf-inside'
import point from 'turf-point'
import dbg from 'debug'

const debug = dbg('jsolines')

/**
 * Create a JSON isoline. Surface is a (possibly typed) array, width and height are its width and height, and cutoff is the cutoff.
 * It is possible to disable linear interpolation for debug purposes by passing interpolation: false
 */
export default function jsolines ({surface, width, height, cutoff, project, interpolation = true}) {
  // first, create the contour grid
  let contour = getContour({surface, width, height, cutoff})
  let cWidth = width - 1

  // javascript does not have boolean arrays. lame.
  let found = new Uint8Array((width - 1) * (height - 1))

  // DEBUG, comment out to save memory
  let indices = []

  // we'll sort out what shell goes with what hole in a bit
  let shells = []
  let holes = []

  // find a cell that has a line in it, then follow that line, keeping filled area to your
  // left. This lets us use winding direction to determine holes.
  for (let origy = 0; origy < height - 1; origy++) {
    for (let origx = 0; origx < width - 1; origx++) {
      if (found[origy * cWidth + origx] === 1) {
        continue
      }

      let idx = contour[origy * cWidth + origx]
      // continue if there is no line here or if it's a saddle, as we don't know which way the saddle goes
      if (idx === 0 || idx === 5 || idx === 10 || idx === 15) continue

      // huzzah! we have found a line, now follow it, keeping the filled area to our left,
      // which allows us to use the winding direction to determine what should be a shell and
      // what should be a hole
      let x = origx
      let y = origy

      let prevx = -1
      let prevy = -1
      let startx = -1
      let starty = -1

      // track winding direction
      let direction = 0

      let coords = []

      RING: while (true) {
        // make sure we're not traveling in circles
        // NB using index from _previous_ cell, we have not yet set an index for this cell
        if (found[y * cWidth + x] === 1) {
          console.log(`Ring crosses other ring (or possibly self) at ${x}, ${y} coming from case ${idx}`)
          console.log(`Last few indices: ${indices.slice(Math.max(0, indices.length - 10))}`)
          break RING
        }

        prevx = startx
        prevy = starty
        startx = x
        starty = y
        idx = contour[y * cWidth + x]

        indices.push(idx)

        // only mark as found if it's not a saddle because we expect to reach saddles twice.
        if (idx !== 5 && idx !== 10) {
          found[y * cWidth + x] = 1
        }

        // follow the loop
        // we keep track of which contour cell we're in, and we always keep the filled area to our left.
        // thus we always indicate only which direction we exit the cell.
        switch (idx) {
          case 0:
            console.log('Ran off outside of ring')
            break RING
          case 1:
            x--
            break
          // NB: +y is down
          case 2:
            y++
            break
          case 3:
            x--
            break
          case 4:
            x++
            break
          case 5:
            // assume that saddle has // orientation (as opposed to \\). It doesn't
            // really matter if we're wrong, we'll just have two disjoint pieces where we should have
            // one, or vice versa
            if (prevy > y) {
              // came from bottom
              x++
            } else if (prevy < y) {
              // came from top
              x--
            } else {
              console.log('Entered case 5 saddle point from wrong direction!')
            }
            break
          case 6:
            y++
            break
          case 7:
            x--
            break
          case 8:
            y--
            break
          case 9:
            y--
            break
          case 10: // hex a
            if (prevx < x) {
              // came from left
              y++
            } else if (prevx > x) {
              // came from right
              y--
            } else {
              console.log('Entered case 10 saddle point from wrong direction.')
            }
            break
          case 11: // b
            y--
            break
          case 12: // c
            x++
            break
          case 13: // d
            x++
            break
          case 14: // e
            y++
            break
          case 15: // f
            console.log('Ran off inside of ring')
            break RING
        }

        // keep track of winding direction
        direction += (x - startx) * (y + starty)

        let topLeft = surface[y * width + x]
        let topRight = surface[y * width + x + 1]
        let botLeft = surface[(y + 1) * width + x]
        let botRight = surface[(y + 1) * width + x + 1]

        // do linear interpolation
        let coord
        if (startx < x) {
          // came from left
          let frac = interpolation ? (cutoff - topLeft) / (botLeft - topLeft) : 0.5

          if (frac === Infinity) {
            debug(`segment fraction from left is Infinity at ${x}, ${y}; if this is at the edge of the query this is not totally unexpected.`)
            frac = 0.5
          }

          coord = [x, y + frac]
        } else if (startx > x) {
          // came from right
          let frac = interpolation ? (cutoff - topRight) / (botRight - topRight) : 0.5

          if (frac === Infinity) {
            debug(`segment fraction from right is Infinity at ${x}, ${y}; if this is at the edge of the query this is not totally unexpected.`)
            frac = 0.5
          }

          coord = [x + 1, y + frac]
        } else if (starty > y) {
          // came from bottom
          let frac = interpolation ? (cutoff - botLeft) / (botRight - botLeft) : 0.5

          if (frac === Infinity) {
            debug(`segment fraction from bottom is Infinity at ${x}, ${y}; if this is at the edge of the query this is not totally unexpected.`)
            frac = 0.5
          }

          coord = [x + frac, y + 1]
        } else if (starty < y) {
          // came from top
          let frac = interpolation ? (cutoff - topLeft) / (topRight - topLeft) : 0.5

          if (frac === Infinity) {
            debug(`segment fraction from top is Infinity at ${x}, ${y}; if this is at the edge of the query this is not totally unexpected.`)
            frac = 0.5
          }

          coord = [x + frac, y]
        } else {
          console.log(`Unexpected coordinate shift from ${startx}, ${starty} to ${x}, ${y}, discarding ring`)
          break RING
        }

        coords.push(project(coord))

        if (coords.length > 10000) {
          console.log('More than 10000 coordinates found in ring, skipping this ring')
          break RING
        }

        // we're back at the start of the ring
        if (x === origx && y === origy) {
          coords.push(coords[0]) // close the ring

          // make it a fully-fledged GeoJSON object
          let geom = {
            type: 'Feature',
            geometry: {
              type: 'Polygon',
              coordinates: [coords]
            }
          }

          // check winding direction
          // positive means counter clockwise, see http://stackoverflow.com/questions/1165647
          // NB +y is down so the signs are reversed from what would normally be expected
          if (direction > 0) shells.push(geom)
          else holes.push(geom)
          break RING
        }
      }
    }
  }

  // shell game time.
  // sort out shells and holes
  HOLES: for (let hole of holes) {
    for (let shell of shells) {
      // NB this is checking whether the first coordinate of the hole is inside the shell.
      // This is sufficient as shells don't overlap, and holes are guaranteed to be completely
      // contained by a single shell.
      if (inside(point(hole.geometry.coordinates[0][0]), shell)) {
        shell.geometry.coordinates.push(hole.geometry.coordinates[0])
        continue HOLES
      }
    }

    console.log('Did not find fitting shell for hole')
  }

  return {
    type: 'Feature',
    geometry: {
      type: 'MultiPolygon',
      coordinates: shells.map(s => s.geometry.coordinates)
    }
  }
}

/** Get a contouring grid. Exported for debug purposes, not generally used outside jsolines testing */
export function getContour ({surface, width, height, cutoff}) {
  let contour = new Uint8Array((width - 1) * (height - 1))

  // compute contour values for each cell
  for (let x = 0; x < width - 1; x++) {
    for (let y = 0; y < height - 1; y++) {
      let topLeft = surface[y * width + x] < cutoff
      let topRight = surface[y * width + x + 1] < cutoff
      let botLeft = surface[(y + 1) * width + x] < cutoff
      let botRight = surface[(y + 1) * width + x + 1] < cutoff

      // if we're at the edge of the area, set the outer sides to false, so that isochrones always close
      // even when they actually extend beyond the edges of the surface
      if (x === 0) topLeft = botLeft = false
      if (x === width - 2) topRight = botRight = false
      if (y === 0) topLeft = topRight = false
      if (y === height - 2) botRight = botLeft = false

      let idx = 0

      if (topLeft) idx |= 1 << 3
      if (topRight) idx |= 1 << 2
      if (botRight) idx |= 1 << 1
      if (botLeft) idx |= 1

      contour[y * (width - 1) + x] = idx
    }
  }

  return contour
}
<|endoftext|>


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

var iMessage = {};

module.exports = iMessage;
<commit_msg>Basic functionality working<commit_after>var osa = require('osa');

var PHONE_REGEX = /'^\+\d{10}$'/;
var EMAIL_REGEX = /^\S+@\S+$/; // simple email regex

var noop = function(){};

var parse = function(input) {
    if(typeof(input) == 'undefined')
        return '';
    else if(typeof(input) == 'object')
        return input;
    else if(input.match(PHONE_REGEX) || input.match(EMAIL_REGEX))
        return { handle: input };
    else
        return { name: input };
    return '';
};

var iMessage = {};

iMessage.send = function(message, to, cb) {
    var recipient = parse(to);
    cb = cb || function(){};

    osa(function(message, recipient) {
        var Messages = Application('Messages');
        recipient = Messages.buddies.whose(recipient)[0];

        Messages.send(message, { to: recipient });

        return {
            name:   recipient.name(),
            handle: recipient.handle()
        };
    }, message, recipient, cb);
};

iMessage.getContact = function(input, cb) {
    var search = parse(input);
    cb = cb || function(){};

    osa(function(search) {
        var Messages = Application('Messages');
        found = Messages.buddies.whose(search)[0];

        return {
            name:   found.name(),
            handle: found.handle()
        };
    }, search, cb);
};

module.exports = iMessage;
<|endoftext|>


<commit_before><commit_msg>Implemented vue packages<commit_after><|endoftext|>


<commit_before>
/* global document */
/* eslint no-console: 0 */

var Ractive = require( 'ractive' )

var result = require( '../fixtures/template.html' )

var main = document.createElement( 'div' )

main.id = 'main'

document.body.appendChild( main )

var ractive = new Ractive( {
	el: '#main',
	template: result,
	data: {
		x: 'orange'
	}
} )

console.log( document.getElementById( 'main' ).innerHTML )
<commit_msg>Top line<commit_after>/* global document */
/* eslint no-console: 0 */

var Ractive = require( 'ractive' )

var result = require( '../fixtures/template.html' )

var main = document.createElement( 'div' )

main.id = 'main'

document.body.appendChild( main )

var ractive = new Ractive( {
	el: '#main',
	template: result,
	data: {
		x: 'orange'
	}
} )

console.log( document.getElementById( 'main' ).innerHTML )
<|endoftext|>


<commit_before>"use strict";

var Resource = require("resource-loader").Resource;

function pathWithoutFile(path) {
    var elements = path.split("/");
    elements.pop(); // remove filename
    return elements.join("/");
}

// Simple "wait for all" helper class
function WaitForAll(count, allDone) {
    var remaining = count;

    this.done = function() {
        remaining--;
        if (remaining === 0) {
            allDone();
        }
    };
}

module.exports = function (PIXI)
{
    return function (resource, next)
    {
        // skip if no data, its not json, or it isn't a pixi-packer manifest
        if (!resource.data || resource.type !== Resource.TYPE.JSON || !resource.data.meta || resource.data.meta.type !== "pixi-packer") {
            return next();
        }

        if (resource.data.meta.version > 1) {
            throw new Error("pixi-packer manifest version " + resource.data.meta.version + " not supported");
        }

        var loader = this;

        var loadOptions = {
            crossOrigin: resource.crossOrigin,
            loadType: Resource.LOAD_TYPE.IMAGE,
            parentResource: resource
        };

        var urlForManifest = resource.url.replace(loader.baseUrl, "");
        var route = pathWithoutFile(urlForManifest);

        var resolution = resource.data.resolution;

        if (resource.data.spritesheets.length && loader.progress === 100) {
            // This is a temporary workaround until a solution for https://github.com/englercj/resource-loader/pull/32 is found
            loader.progress = 0;
        }

        // Load all spritesheets
        var waiter = new WaitForAll(resource.data.spritesheets.length, next);
        resource.data.spritesheets.forEach(function(spritesheet) {
            var name = spritesheet.image;
            var imageUrl = route + "/" + spritesheet.image;
            PIXI.Texture.removeFromCache(name);
            PIXI.Texture.removeFromCache(imageUrl);
            PIXI.BaseTexture.removeFromCache(name);
            PIXI.BaseTexture.removeFromCache(imageUrl);
            loader.add(name, imageUrl, loadOptions, function (res) {
                res.texture.baseTexture.resolution = resolution;
                res.texture.baseTexture.update();
                res.textures = {};
                spritesheet.sprites.forEach(function(sprite) {
                    var frame = new PIXI.Rectangle(
                        sprite.position.x / resolution,
                        sprite.position.y / resolution,
                        sprite.dimension.w / resolution,
                        sprite.dimension.h / resolution
                    );

                    var crop;
                    if (Number(PIXI.VERSION.charAt(0)) >= 4) {
                        crop = new PIXI.Rectangle(
                            0,
                            0,
                            sprite.dimension.w / resolution,
                            sprite.dimension.h / resolution
                        );
                    } else {
                        crop = frame.clone();
                    }

                    var trim = null;

                    //  Check to see if the sprite is trimmed
                    if (sprite.trim) {
                        if (Number(PIXI.VERSION.charAt(0)) >= 4) {
                            trim = new PIXI.Rectangle(
                                sprite.trim.x / resolution,
                                sprite.trim.y / resolution,
                                sprite.trim.w / resolution,
                                sprite.trim.h / resolution
                            );

                            frame.width = sprite.trim.w / resolution;
                            frame.height = sprite.trim.h / resolution;
                        } else {
                            trim = new PIXI.Rectangle(
                                sprite.trim.x / resolution,
                                sprite.trim.y / resolution,
                                frame.width,
                                frame.height
                            );

                            crop.width = sprite.trim.w / resolution;
                            crop.height = sprite.trim.h / resolution;
                        }
                    }

                    res.textures[sprite.name] = new PIXI.Texture(res.texture.baseTexture, frame, crop, trim, false);

                    // lets also add the frame to pixi's global cache for fromFrame and fromImage functions
                    PIXI.utils.TextureCache[sprite.name] = res.textures[sprite.name];
                });
                waiter.done();
            });
        });
    };
};
<commit_msg>added check for old pixi versions<commit_after>"use strict";

var Resource = require("resource-loader").Resource;

function pathWithoutFile(path) {
    var elements = path.split("/");
    elements.pop(); // remove filename
    return elements.join("/");
}

// Simple "wait for all" helper class
function WaitForAll(count, allDone) {
    var remaining = count;

    this.done = function() {
        remaining--;
        if (remaining === 0) {
            allDone();
        }
    };
}

module.exports = function (PIXI)
{
    return function (resource, next)
    {
        // skip if no data, its not json, or it isn't a pixi-packer manifest
        if (!resource.data || resource.type !== Resource.TYPE.JSON || !resource.data.meta || resource.data.meta.type !== "pixi-packer") {
            return next();
        }

        if (resource.data.meta.version > 1) {
            throw new Error("pixi-packer manifest version " + resource.data.meta.version + " not supported");
        }

        var loader = this;

        var loadOptions = {
            crossOrigin: resource.crossOrigin,
            loadType: Resource.LOAD_TYPE.IMAGE,
            parentResource: resource
        };

        var urlForManifest = resource.url.replace(loader.baseUrl, "");
        var route = pathWithoutFile(urlForManifest);

        var resolution = resource.data.resolution;

        if (resource.data.spritesheets.length && loader.progress === 100) {
            // This is a temporary workaround until a solution for https://github.com/englercj/resource-loader/pull/32 is found
            loader.progress = 0;
        }

        // Load all spritesheets
        var waiter = new WaitForAll(resource.data.spritesheets.length, next);
        resource.data.spritesheets.forEach(function(spritesheet) {
            var name = spritesheet.image;
            var imageUrl = route + "/" + spritesheet.image;
            if( PIXI.Texture.removeFromCache) {
                PIXI.Texture.removeFromCache(name);
                PIXI.Texture.removeFromCache(imageUrl);
                PIXI.BaseTexture.removeFromCache(name);
                PIXI.BaseTexture.removeFromCache(imageUrl);
            }
            loader.add(name, imageUrl, loadOptions, function (res) {
                res.texture.baseTexture.resolution = resolution;
                res.texture.baseTexture.update();
                res.textures = {};
                spritesheet.sprites.forEach(function(sprite) {
                    var frame = new PIXI.Rectangle(
                        sprite.position.x / resolution,
                        sprite.position.y / resolution,
                        sprite.dimension.w / resolution,
                        sprite.dimension.h / resolution
                    );

                    var crop;
                    if (Number(PIXI.VERSION.charAt(0)) >= 4) {
                        crop = new PIXI.Rectangle(
                            0,
                            0,
                            sprite.dimension.w / resolution,
                            sprite.dimension.h / resolution
                        );
                    } else {
                        crop = frame.clone();
                    }

                    var trim = null;

                    //  Check to see if the sprite is trimmed
                    if (sprite.trim) {
                        if (Number(PIXI.VERSION.charAt(0)) >= 4) {
                            trim = new PIXI.Rectangle(
                                sprite.trim.x / resolution,
                                sprite.trim.y / resolution,
                                sprite.trim.w / resolution,
                                sprite.trim.h / resolution
                            );

                            frame.width = sprite.trim.w / resolution;
                            frame.height = sprite.trim.h / resolution;
                        } else {
                            trim = new PIXI.Rectangle(
                                sprite.trim.x / resolution,
                                sprite.trim.y / resolution,
                                frame.width,
                                frame.height
                            );

                            crop.width = sprite.trim.w / resolution;
                            crop.height = sprite.trim.h / resolution;
                        }
                    }

                    res.textures[sprite.name] = new PIXI.Texture(res.texture.baseTexture, frame, crop, trim, false);

                    // lets also add the frame to pixi's global cache for fromFrame and fromImage functions
                    PIXI.utils.TextureCache[sprite.name] = res.textures[sprite.name];
                });
                waiter.done();
            });
        });
    };
};
<|endoftext|>


<commit_before>var Trackr = require("trackr");
var _ = require("underscore");
var VText = require("virtual-dom/vnode/vtext");
var createElement = require('virtual-dom/create-element');
var diff = require('virtual-dom/diff');
var patch = require('virtual-dom/patch');
var matchesSelector = require("matches-selector");

function VTrackr(fn) {
	if (!(this instanceof VTrackr)) return new VTrackr(fn);

	this._tree = null;
	this._node = null;
	if (typeof fn === "function") this.render = fn;

	this.comp = Trackr.autorun(function(comp) {
		var newtree = this.render.call(this, comp),
			oldNode;

		if (typeof newtree === "string") {
			newtree = new VText(newtree);
		}

		if (this._node) {
			var oldNode = this._node;
			this._node = patch(oldNode, diff(this._tree, newtree));

			if (this._node !== oldNode && oldNode.parentNode) {
				oldNode.parentNode.replaceChild(this._node, oldNode);
			}
		}

		this._tree = newtree;
	}, this);
}

module.exports = VTrackr;
VTrackr.extend = require("backbone-extend-standalone");

_.extend(VTrackr.prototype, {
	type: "Widget",

	init: function() {
		return this._node = createElement(this._tree);
	},

	update: function(previous, node) {
		var prevtree = previous && previous._tree;
		if (!prevtree) return this.init();
		return this._node = patch(node, diff(prevtree, this._tree));
	},

	destroy: function(node) {
		this.comp.stop();
		this._node = null;
		this._tree = null;
	},

	paint: function(parent, before) {
		if (typeof parent === "string") parent = document.querySelector(parent);
		if (parent == null) throw new Error("Expecting a valid DOM element to attach in.");
		if (typeof before === "string") before = parent.querySelector(before);
		parent.insertBefore(this.init(), before);
		return this;
	},

	findAll: function(selector) {
		var matches = [],
			el = this._node;

		if (el) {
			if (el.nodeType === 1 && matchesSelector(el, selector)) matches.push(el);
			if (typeof el.querySelectorAll === "function") {
				matches.push.apply(matches, el.querySelectorAll(selector));
			}
		}

		return matches;
	},

	find: function(selector) {
		var el = this._node;

		if (el) {
			if (el.nodeType === 1 && matchesSelector(el, selector)) return el;
			if (typeof el.querySelector === "function") {
				return el.querySelector(selector);
			}
		}

		return null;
	}
});

// proxy a few computation methods
["invalidate","onInvalidate","stop"].forEach(function(method) {
	VTrackr.prototype[method] = function() {
		this.comp[method].apply(this.comp, arguments);
		return this;
	}
});
<commit_msg>fixed a few state bugs<commit_after>var Trackr = require("trackr");
var _ = require("underscore");
var VText = require("virtual-dom/vnode/vtext");
var createElement = require('virtual-dom/create-element');
var diff = require('virtual-dom/diff');
var patch = require('virtual-dom/patch');
var matchesSelector = require("matches-selector");

function VTrackr(fn) {
	if (!(this instanceof VTrackr)) return new VTrackr(fn);
	if (typeof fn === "function") this.render = fn;
	this.mount();
}

module.exports = VTrackr;
VTrackr.extend = require("backbone-extend-standalone");

_.extend(VTrackr.prototype, {
	type: "Widget",

	autorun: function(fn) {
		return Trackr.autorun(fn, this);
	},

	mount: function() {
		if (this.comp) this.stop();

		this.comp = this.autorun(function(comp) {
			var newtree = this.render.call(this, comp),
				oldNode;

			if (typeof newtree === "string") {
				newtree = new VText(newtree);
			}

			this._latestTree = newtree;
			if (this.node) this.updateNode();

			comp.onInvalidate(function() {
				if (comp.stopped) {
					this._latestTree = null;
					delete this.comp;
				}
			});
		});

		return this;
	},

	stop: function() {
		if (this.comp) this.comp.stop();
		return this;
	},

	updateNode: function() {
		// must have changed
		if (!this._latestTree) return this;

		// create a new node if none is set
		if (!this.node || !this._tree) {
			this.node = createElement(this._latestTree);
		}

		// otherwise patch and apply new tree
		else {
			var oldNode = this.node;
			this.node = patch(oldNode, diff(this._tree, this._latestTree));

			if (this.node !== oldNode && oldNode.parentNode) {
				oldNode.parentNode.replaceChild(this.node, oldNode);
			}
		}

		this._tree = this._latestTree;
		this._latestTree = null;

		return this;
	},

	init: function() {
		this.updateNode();
		return this.node;
	},

	update: function(previous, node) {
		var prevtree = previous && previous._tree;
		if (!prevtree || !node) return this.init();

		// basically, don't be switching trees without calling destroy
		if (this.node && this.node !== node) {
			throw new Error("This VTrackr was already initated with a different node.");
		}

		// update internal state and update the node
		this.node = node;
		if (!this._latestTree) this._latestTree = this._tree;
		this._tree = prevtree;
		this.updateNode();

		return this.node;
	},

	destroy: function(node) {
		this.stop();
		this.node = null;
		this._tree = null;
	},

	paint: function(parent, before) {
		if (typeof parent === "string") parent = document.querySelector(parent);
		if (parent == null) throw new Error("Expecting a valid DOM element to attach in.");
		if (typeof before === "string") before = parent.querySelector(before);
		parent.insertBefore(this.init(), before);
		return this;
	},

	findAll: function(selector) {
		var matches = [],
			el = this.node;

		if (el) {
			if (el.nodeType === 1 && matchesSelector(el, selector)) matches.push(el);
			if (typeof el.querySelectorAll === "function") {
				matches.push.apply(matches, el.querySelectorAll(selector));
			}
		}

		return matches;
	},

	find: function(selector) {
		var el = this.node;

		if (el) {
			if (el.nodeType === 1 && matchesSelector(el, selector)) return el;
			if (typeof el.querySelector === "function") {
				return el.querySelector(selector);
			}
		}

		return null;
	}
});

// proxy a few computation methods
["invalidate","onInvalidate"].forEach(function(method) {
	VTrackr.prototype[method] = function() {
		if (!this.comp) {
			throw new Error("Cannot run " + method + "(). This VTrackr is not mounted.");
		}

		this.comp[method].apply(this.comp, arguments);
		return this;
	}
});
<|endoftext|>


<commit_before>var memoryjs = require('./build/Release/memoryjs');
var processName = "chrome.exe";

// sync
var process = memoryjs.openProcess(processName);

// async
memoryjs.openProcess(processName, function (process) {
    console.log(JSON.stringify(process, null, 3));
    if (process.szExeFile) {
        console.log("Successfully opened handle on", processName);

        memoryjs.closeProcess(process.handle);
        console.log("Closed handle on", processName)
    } else {
        console.log("Unable to open handle on", processName);
    }
});

// sync
var processes = memoryjs.getProcesses();
console.log("\nGetting all processes (sync)\n---\n");
for (var i = 0; i < processes.length; i++) {
    console.log(processes[i].szExeFile);
}

// async
console.log("\nGetting all processes (async)\n---\n");
memoryjs.getProcesses(function(processes){
    for (var i = 0; i < processes.length; i++) {
        console.log(processes[i].szExeFile);
    }
});

/* process =
{ cntThreads: 14,
  cntUsage: 0,
  dwFlags: 0,
  dwSize: 304,
  szExeFile: 'chrome.exe',
  th32ProcessID: 10044,
  th32ParentProcessID: 5868 } */

// sync
console.log("\nGetting all modules (sync)\n---\n");
var modules = memoryjs.getModules(process.th32ProcessID);
for (var i = 0; i < modules.length; i++) {
    console.log(modules[i].szExePath);
}

// sync
console.log("\nGetting all modules (async)\n---\n");
memoryjs.getModules(process.th32ProcessID, function (modules) {
    for (var i = 0; i < modules.length; i++) {
        console.log(modules[i].szModule);
    }
});

// async
console.log("\nFinding module \"ntdll.dll\" (async)\n---\n");
memoryjs.findModule("ntdll.dll", process.th32ProcessID, function (module) {
    console.log(module.szModule);
});

// sync
console.log("\nFinding module \"ntdll.dll\" (sync)\n---\n");
console.log(memoryjs.findModule("ntdll.dll", process.th32ProcessID));

/* module =
{ dwSize: 568,
  GlblcntUsage: 65535,
  modBaseAddr: -1870135296,
  modBaseSize: 1839104,
  ProccntUsage: 65535,
  szExePath: 'C:\\WINDOWS\\SYSTEM32\\ntdll.dll',
  szModule: 'ntdll.dll',
  th32ModuleID: 5844 } */<commit_msg>updated example<commit_after>var memoryjs = require('./build/Release/memoryjs');
var processName = "chrome.exe";

// open a process (sync)
var process = memoryjs.openProcess(processName);

// open a process (async)
memoryjs.openProcess(processName, function (process) {
    console.log(JSON.stringify(process, null, 3));
    if (process.szExeFile) {
        console.log("Successfully opened handle on", processName);

        memoryjs.closeProcess(process.handle);
        console.log("Closed handle on", processName)
    } else {
        console.log("Unable to open handle on", processName);
    }
});

// get all processes (sync)
var processes = memoryjs.getProcesses();
console.log("\nGetting all processes (sync)\n---\n");
for (var i = 0; i < processes.length; i++) {
    console.log(processes[i].szExeFile);
}

// get all processes (async)
console.log("\nGetting all processes (async)\n---\n");
memoryjs.getProcesses(function(processes){
    for (var i = 0; i < processes.length; i++) {
        console.log(processes[i].szExeFile);
    }
});

/* process =
{ cntThreads: 14,
  cntUsage: 0,
  dwFlags: 0,
  dwSize: 304,
  szExeFile: 'chrome.exe',
  th32ProcessID: 10044,
  th32ParentProcessID: 5868 } */

// get all modules (sync)
console.log("\nGetting all modules (sync)\n---\n");
var modules = memoryjs.getModules(process.th32ProcessID);
for (var i = 0; i < modules.length; i++) {
    console.log(modules[i].szExePath);
}

// get all modules (async)
console.log("\nGetting all modules (async)\n---\n");
memoryjs.getModules(process.th32ProcessID, function (modules) {
    for (var i = 0; i < modules.length; i++) {
        console.log(modules[i].szModule);
    }
});

// find a module associated with a process (sync)
console.log("\nFinding module \"ntdll.dll\" (sync)\n---\n");
console.log(memoryjs.findModule("ntdll.dll", process.th32ProcessID));

// find a module associated with a process (async)
console.log("\nFinding module \"ntdll.dll\" (async)\n---\n");
memoryjs.findModule("ntdll.dll", process.th32ProcessID, function (module) {
    console.log(module.szModule);
});

/* module =
{ dwSize: 568,
  GlblcntUsage: 65535,
  modBaseAddr: -1870135296,
  modBaseSize: 1839104,
  ProccntUsage: 65535,
  szExePath: 'C:\\WINDOWS\\SYSTEM32\\ntdll.dll',
  szModule: 'ntdll.dll',
  th32ModuleID: 5844 } */<|endoftext|>


<commit_before>/**
 * index.js
 * OAuth 2.0 provider
 *
 * @author Amir Malik
 */

var EventEmitter = require('events').EventEmitter,
     querystring = require('querystring'),
      serializer = require('serializer'),
         connect = require('connect');

function OAuth2Provider(crypt_key, sign_key) {
  this.serializer = serializer.createSecureSerializer(crypt_key, sign_key);
}

OAuth2Provider.prototype = new EventEmitter();

OAuth2Provider.prototype.generateAccessToken = function(user_id, client_id, extra_data) {
  var out = {
    access_token: this.serializer.stringify([user_id, client_id, +new Date, extra_data]),
    refresh_token: null,
  };

  return out;
};

OAuth2Provider.prototype.login = function() {
  var self = this;

  return function(req, res, next) {
    var data, atok, user_id, client_id, grant_date, extra_data;

    if(req.query['access_token']) {
      atok = req.query['access_token'];
    } else if((req.headers['authorization'] || '').indexOf('Bearer ') == 0) {
      atok = req.headers['authorization'].replace('Bearer', '').trim();
    } else {
      return next();
    }

    try {
      data = self.serializer.parse(atok);
      user_id = data[0];
      client_id = data[1];
      grant_date = new Date(data[2]);
      extra_data = data[3];
    } catch(e) {
      res.writeHead(400);
      return res.end(e.message);
    }

    self.emit('access_token', req, {
      user_id: user_id,
      client_id: client_id,
      extra_data: extra_data,
      grant_date: grant_date
    }, next);
  };
};

OAuth2Provider.prototype.oauth = function() {
  var self = this;

  return function(req, res, next) {
    var uri = ~req.url.indexOf('?') ? req.url.substr(0, req.url.indexOf('?')) : req.url;

    if(req.method == 'GET' && '/oauth/authorize' == uri) {
      var    client_id = req.query.client_id,
          redirect_uri = req.query.redirect_uri;

      if(!client_id || !redirect_uri) {
        res.writeHead(400);
        return res.end('client_id and redirect_uri required');
      }

      // authorization form will be POSTed to same URL, so we'll have all params
      var authorize_url = req.url;

      self.emit('enforce_login', req, res, authorize_url, function(user_id) {
        // store user_id in an HMAC-protected encrypted query param
        authorize_url += '&' + querystring.stringify({x_user_id: self.serializer.stringify(user_id)});

        // user is logged in, render approval page
        self.emit('authorize_form', req, res, client_id, authorize_url);
      });

    } else if(req.method == 'POST' && '/oauth/authorize' == uri) {
      var     client_id = req.query.client_id,
           redirect_uri = req.query.redirect_uri,
          response_type = req.query.response_type || 'code',
                  state = req.query.state,
              x_user_id = req.query.x_user_id;

      var url = redirect_uri;

      switch(response_type) {
        case 'code': url += '?'; break;
        case 'token': url += '#'; break;
        default:
          res.writeHead(400);
          return res.end('invalid response_type requested');
      }

      if('allow' in req.body) {
        if('token' == response_type) {
          var user_id;

          try {
            user_id = self.serializer.parse(x_user_id);
          } catch(e) {
            console.error('allow/token error', e.stack);

            res.writeHead(500);
            return res.end(e.message);
          }

          self.emit('create_access_token', user_id, client_id, function(extra_data) {
            var atok = self.generateAccessToken(user_id, client_id, extra_data);

            if(self.listeners('save_access_token').length > 0)
              self.emit('save_access_token', user_id, client_id, atok);

            url += querystring.stringify(atok);

            res.writeHead(303, {Location: url});
            res.end();
          });
        } else {
          var code = serializer.randomString(128);

          self.emit('save_grant', req, client_id, code, function() {
            var extras = {
              code: code,
            };

            // pass back anti-CSRF opaque value
            if(state)
              extras['state'] = state;

            url += querystring.stringify(extras);

            res.writeHead(303, {Location: url});
            res.end();
          });
        }
      } else {
        url += querystring.stringify({error: 'access_denied'});

        res.writeHead(303, {Location: url});
        res.end();
      }

    } else if(req.method == 'POST' && '/oauth/access_token' == uri) {
      var     client_id = req.body.client_id,
          client_secret = req.body.client_secret,
           redirect_uri = req.body.redirect_uri,
                   code = req.body.code;

      self.emit('lookup_grant', client_id, client_secret, code, function(err, user_id) {
        if(err) {
          res.writeHead(400);
          return res.end(err.message);
        }

        res.writeHead(200, {'Content-type': 'application/json'});

        self.emit('create_access_token', user_id, client_id, function(extra_data) {
          var atok = self.generateAccessToken(user_id, client_id, extra_data);

          if(self.listeners('save_access_token').length > 0)
            self.emit('save_access_token', user_id, client_id, atok);

          res.end(JSON.stringify(self.generateAccessToken(user_id, client_id, extra_data)));
        });

        self.emit('remove_grant', user_id, client_id, code);
      });

    } else {
      return next();
    }
  };
};

exports.OAuth2Provider = OAuth2Provider;
<commit_msg>fixes '#23 removed requiring connect from index since it's never used.<commit_after>/**
 * index.js
 * OAuth 2.0 provider
 *
 * @author Amir Malik
 */

var EventEmitter = require('events').EventEmitter,
     querystring = require('querystring'),
      serializer = require('serializer');

function OAuth2Provider(crypt_key, sign_key) {
  this.serializer = serializer.createSecureSerializer(crypt_key, sign_key);
}

OAuth2Provider.prototype = new EventEmitter();

OAuth2Provider.prototype.generateAccessToken = function(user_id, client_id, extra_data) {
  var out = {
    access_token: this.serializer.stringify([user_id, client_id, +new Date, extra_data]),
    refresh_token: null,
  };

  return out;
};

OAuth2Provider.prototype.login = function() {
  var self = this;

  return function(req, res, next) {
    var data, atok, user_id, client_id, grant_date, extra_data;

    if(req.query['access_token']) {
      atok = req.query['access_token'];
    } else if((req.headers['authorization'] || '').indexOf('Bearer ') == 0) {
      atok = req.headers['authorization'].replace('Bearer', '').trim();
    } else {
      return next();
    }

    try {
      data = self.serializer.parse(atok);
      user_id = data[0];
      client_id = data[1];
      grant_date = new Date(data[2]);
      extra_data = data[3];
    } catch(e) {
      res.writeHead(400);
      return res.end(e.message);
    }

    self.emit('access_token', req, {
      user_id: user_id,
      client_id: client_id,
      extra_data: extra_data,
      grant_date: grant_date
    }, next);
  };
};

OAuth2Provider.prototype.oauth = function() {
  var self = this;

  return function(req, res, next) {
    var uri = ~req.url.indexOf('?') ? req.url.substr(0, req.url.indexOf('?')) : req.url;

    if(req.method == 'GET' && '/oauth/authorize' == uri) {
      var    client_id = req.query.client_id,
          redirect_uri = req.query.redirect_uri;

      if(!client_id || !redirect_uri) {
        res.writeHead(400);
        return res.end('client_id and redirect_uri required');
      }

      // authorization form will be POSTed to same URL, so we'll have all params
      var authorize_url = req.url;

      self.emit('enforce_login', req, res, authorize_url, function(user_id) {
        // store user_id in an HMAC-protected encrypted query param
        authorize_url += '&' + querystring.stringify({x_user_id: self.serializer.stringify(user_id)});

        // user is logged in, render approval page
        self.emit('authorize_form', req, res, client_id, authorize_url);
      });

    } else if(req.method == 'POST' && '/oauth/authorize' == uri) {
      var     client_id = req.query.client_id,
           redirect_uri = req.query.redirect_uri,
          response_type = req.query.response_type || 'code',
                  state = req.query.state,
              x_user_id = req.query.x_user_id;

      var url = redirect_uri;

      switch(response_type) {
        case 'code': url += '?'; break;
        case 'token': url += '#'; break;
        default:
          res.writeHead(400);
          return res.end('invalid response_type requested');
      }

      if('allow' in req.body) {
        if('token' == response_type) {
          var user_id;

          try {
            user_id = self.serializer.parse(x_user_id);
          } catch(e) {
            console.error('allow/token error', e.stack);

            res.writeHead(500);
            return res.end(e.message);
          }

          self.emit('create_access_token', user_id, client_id, function(extra_data) {
            var atok = self.generateAccessToken(user_id, client_id, extra_data);

            if(self.listeners('save_access_token').length > 0)
              self.emit('save_access_token', user_id, client_id, atok);

            url += querystring.stringify(atok);

            res.writeHead(303, {Location: url});
            res.end();
          });
        } else {
          var code = serializer.randomString(128);

          self.emit('save_grant', req, client_id, code, function() {
            var extras = {
              code: code,
            };

            // pass back anti-CSRF opaque value
            if(state)
              extras['state'] = state;

            url += querystring.stringify(extras);

            res.writeHead(303, {Location: url});
            res.end();
          });
        }
      } else {
        url += querystring.stringify({error: 'access_denied'});

        res.writeHead(303, {Location: url});
        res.end();
      }

    } else if(req.method == 'POST' && '/oauth/access_token' == uri) {
      var     client_id = req.body.client_id,
          client_secret = req.body.client_secret,
           redirect_uri = req.body.redirect_uri,
                   code = req.body.code;

      self.emit('lookup_grant', client_id, client_secret, code, function(err, user_id) {
        if(err) {
          res.writeHead(400);
          return res.end(err.message);
        }

        res.writeHead(200, {'Content-type': 'application/json'});

        self.emit('create_access_token', user_id, client_id, function(extra_data) {
          var atok = self.generateAccessToken(user_id, client_id, extra_data);

          if(self.listeners('save_access_token').length > 0)
            self.emit('save_access_token', user_id, client_id, atok);

          res.end(JSON.stringify(self.generateAccessToken(user_id, client_id, extra_data)));
        });

        self.emit('remove_grant', user_id, client_id, code);
      });

    } else {
      return next();
    }
  };
};

exports.OAuth2Provider = OAuth2Provider;
<|endoftext|>


<commit_before>'use strict';

var _ = require('lodash');
var path = require('path');
var spawn = require('child_process').spawn;
var gutil = require('gulp-util');
var through = require('through2');

var runnerjs = path.join(__dirname, 'runner.js');
var phantomcss = path.join(__dirname, 'node_modules', 'phantomcss');

var defaults = _.partialRight(_.assign, function(a, b) {
  return typeof a == 'undefined' ? b : a;
});

function spawnPhantom(args){
  var o = {
    stdio: 'inherit',
    cwd: process.cwd()
  };
  return spawn(require('phantomjs').path, args, o);
};

module.exports = function (opts) {

  if (_.isString(opts)) {
    var screenshotDir = opts;
    opts = {};
    opts.screenshots = screenshotDir;
  }

  opts = _.extend({
    screenshots: 'screenshots',
    results: 'results',
    viewportSize: [1280, 800],
    logLevel: 'error'
  }, opts || {});

  opts.phantomCSSPath = phantomcss;
  var tests = [];

  return through.obj(function (file, enc, cb) {
    tests.push( path.resolve(file.path) );
    cb(null, file);
  }, function(cb){
    var running = 0;
    tests.forEach(function(test) {
      opts.test = test;
      running++;

      spawnPhantom([
        runnerjs,
        JSON.stringify(opts)
      ])
      .on('exit', function(){
        running--;
        if (running === 0) { cb(); }
      });
    });
  });

};
<commit_msg>Remove unused defaults function<commit_after>'use strict';

var _ = require('lodash');
var path = require('path');
var spawn = require('child_process').spawn;
var gutil = require('gulp-util');
var through = require('through2');

var runnerjs = path.join(__dirname, 'runner.js');
var phantomcss = path.join(__dirname, 'node_modules', 'phantomcss');

function spawnPhantom(args){
  var o = {
    stdio: 'inherit',
    cwd: process.cwd()
  };
  return spawn(require('phantomjs').path, args, o);
};

module.exports = function (opts) {

  if (_.isString(opts)) {
    var screenshotDir = opts;
    opts = {};
    opts.screenshots = screenshotDir;
  }

  opts = _.extend({
    screenshots: 'screenshots',
    results: 'results',
    viewportSize: [1280, 800],
    logLevel: 'error'
  }, opts || {});

  opts.phantomCSSPath = phantomcss;
  var tests = [];

  return through.obj(function (file, enc, cb) {
    tests.push( path.resolve(file.path) );
    cb(null, file);
  }, function(cb){
    var running = 0;
    tests.forEach(function(test) {
      opts.test = test;
      running++;

      spawnPhantom([
        runnerjs,
        JSON.stringify(opts)
      ])
      .on('exit', function(){
        running--;
        if (running === 0) { cb(); }
      });
    });
  });

};
<|endoftext|>


<commit_before>// Defining helper functions
function info(message){
  console.log(message.blue);
}
function danger(message){
  console.log(message.red);
}
function warn(message){
  console.log(message.yellow.bold);
}
function success(message){
  console.log(message.green.bold);
}
function log(message){
  console.log(message);
}
function title(message){
  var title='';
  function getStars(messsage){
    var ret = '';
    for(var i=0; i<messsage.length+6; i++){
      ret+='*';
    }
    return ret;
  }
  title += getStars(message) + '\n';
  title += '** ' + message + ' **\n';
  title += getStars(message);
  return title;
}

// Requiring dependencies
require('colors');
var pkg = require('./package.json');
var express = require('express');
var cli = require('commander');
var open = require('open');
var fs = require('fs');
var jade = require('jade');

// Initializations
var app = express();
var tmp = '', stars = '', url='';
// Default options
var options = {
  port: process.env.PORT || 8080,
  dir: __dirname,
  browser: undefined
}

// Defining and parsing CLI options
cli.version(pkg.version)
.option('-d --dir <directory>','directory to serve (default: .)')
.option('-b --browser <browser name>','browser which open served directory')
.option('-p --port <port>','http port to serve to (default: 8080)')
.option('-r --remote','don\'t automatically lauch browser on  localhost (useful if running on _r_emote host)')
.parse(process.argv);

// Setting options
if (cli.port)       options.port = cli.port;
if (cli.dir)        options.dir = cli.dir;
if (cli.browser)    options.browser = cli.browser;
if (cli.remote)     options.remote = cli.remote;

// Logging CLI user friendly messages
info(title('autostatic-server v' + pkg.version))
info('* serving directory ' + options.dir);
info('* on port ' + options.port);
if(!options.remote) info('* via ' + (options.browser || 'your default') + ' browser');
info('**');

app.use(function(req,res,next){
  if (req.path==='/favicon.ico') log(req.path);
  else info(req.path);
  return next();
});
app.use(express.static(options.dir));

app.use(function(req,res,next){
  var filePath = __dirname + req.path;
  require('fs').exists(filePath, function(exists){
    if(!exists)  return res.status(404).send();

    fs.stat(filePath, function(err,stats){
      if (err) return next(err);
      if (stats.isDirectory()) {
        fs.readdir(filePath,function(err,files){
          if (err) return next('Unable to read directory '+filePath);

          var linkedFiles = [];
          for(i in files){
            var relPath = filePath.split(__dirname).join('');
            var href = (relPath.length>1) ? relPath + '/' + files[i] : files[i];

            linkedFiles.push({
              name: files[i],
              href: href
            });
          }

          var relPath = filePath.split(__dirname).join('');
          // res.status(200).jsonp(files);
          var html = jade.renderFile(__dirname + '/index.jade',{
            parentHref: '../',
            dirname: relPath,
            files: linkedFiles
          });

          res.status(200).send(html);
        });
      }
    });
  });
});
app.use(function(err,req,res,next){
  info(res.status());
  danger('Server Error');
  console.error(err.message);
  console.log(err);
  console.error(err.stack);
  return res.status(500).jsonp(err);
});

var server = app.listen(options.port,function(){
  if (!cli.remote){
    url = 'http://localhost:' + options.port;
    open(url,options.browser).on('close',function(){
      warn('browser closed by client.');
      info('stopping server.');
      process.exit();
    })
  } else {
    url = 'http://' + server.address().address + ':' + options.port;
  }
  success('Server running... \nAccess to served static files at '+ url);

});
<commit_msg>Add -s --stop-on-close option<commit_after>// Defining helper functions
function info(message){
  console.log(message.blue);
}
function danger(message){
  console.log(message.red);
}
function warn(message){
  console.log(message.yellow.bold);
}
function success(message){
  console.log(message.green.bold);
}
function log(message){
  console.log(message);
}
function title(message){
  var title='';
  function getStars(messsage){
    var ret = '';
    for(var i=0; i<messsage.length+6; i++){
      ret+='*';
    }
    return ret;
  }
  title += getStars(message) + '\n';
  title += '** ' + message + ' **\n';
  title += getStars(message);
  return title;
}

// Requiring dependencies
require('colors');
var pkg = require('./package.json');
var express = require('express');
var cli = require('commander');
var open = require('open');
var fs = require('fs');
var jade = require('jade');

// Initializations
var app = express();
var tmp = '', stars = '', url='';
// Default options
var options = {
  port: process.env.PORT || 8080,
  dir: __dirname,
  browser: undefined
}

// Defining and parsing CLI options
cli.version(pkg.version)
.option('-d --dir <directory>','directory to serve (default: .)')
.option('-b --browser <browser name>','browser which open served directory')
.option('-p --port <port>','http port to serve to (default: 8080)')
.option('-r --remote','don\'t automatically lauch browser on  localhost (useful if running on _r_emote host)')
.option('-s --stopOnClose','automatically stop the server when user close the browser')
.parse(process.argv);

// Setting options
if (cli.port)       options.port = cli.port;
if (cli.dir)        options.dir = cli.dir;
if (cli.browser)    options.browser = cli.browser;
if (cli.remote)     options.remote = cli.remote;

// Logging CLI user friendly messages
info(title('autostatic-server v' + pkg.version))
info('* serving directory ' + options.dir);
info('* on port ' + options.port);
if(!options.remote) info('* via ' + (options.browser || 'your default') + ' browser');
info('**');

app.use(function(req,res,next){
  if (req.path==='/favicon.ico') log(req.path);
  else info(req.path);
  return next();
});
app.use(express.static(options.dir));

app.use(function(req,res,next){
  var filePath = __dirname + req.path;
  require('fs').exists(filePath, function(exists){
    if(!exists)  return res.status(404).send();

    fs.stat(filePath, function(err,stats){
      if (err) return next(err);
      if (stats.isDirectory()) {
        fs.readdir(filePath,function(err,files){
          if (err) return next('Unable to read directory '+filePath);

          var linkedFiles = [];
          for(i in files){
            var relPath = filePath.split(__dirname).join('');
            var href = (relPath.length>1) ? relPath + '/' + files[i] : files[i];

            linkedFiles.push({
              name: files[i],
              href: href
            });
          }

          var relPath = filePath.split(__dirname).join('');
          // res.status(200).jsonp(files);
          var html = jade.renderFile(__dirname + '/index.jade',{
            parentHref: '../',
            dirname: relPath,
            files: linkedFiles
          });

          res.status(200).send(html);
        });
      }
    });
  });
});
app.use(function(err,req,res,next){
  info(res.status());
  danger('Server Error');
  console.error(err.message);
  console.log(err);
  console.error(err.stack);
  return res.status(500).jsonp(err);
});

var server = app.listen(options.port,function(){
  if (!cli.remote){
    url = 'http://localhost:' + options.port;
    open(url,options.browser)
    .on('error',function(err){
      danger('Error');
      console.log(err);
    })
    .on('close',function(){
      warn('browser closed by client.');
      if(cli.stopOnClose){
        info('stopping server.');
        process.exit();
      }
    })
  } else {
    url = 'http://' + server.address().address + ':' + options.port;
  }
  success('Server running... \nAccess to served static files at '+ url);

});
<|endoftext|>


<commit_before><commit_msg>Complete 'Object create' challenge in 'Planet proto' tutorial<commit_after><|endoftext|>


<commit_before>/*
 * index.js : Node.js streaming-style computed values
 *
 * (C) 2013 Tristan Slominski
 */
"use strict";

var ComputedValueStream = require('computed-value-stream');

var computedValue = function computedProperty() {
  var computedValueStream = new ComputedValueStream();

  if ( arguments.length == 0) return computedValueStream;

  if ( arguments.length == 1 && typeof arguments[0] != 'function') {
    computedValueStream.write(arguments[0]);
    return computedValueStream;
  }

  // grab the function to calculate dependencies
  var callback = Array.prototype.pop.call(arguments);
  // copy arguments into references
  var observedStreams = Array.prototype.slice.call(arguments);
  // create space to hold latest values in closure
  var values = new Array(observedStreams.length);

  var createUpdateHandler = function createUpdateHandler(index) {
    return function(updatedValue) {
      values[index] = updatedValue;
      computedValueStream.write(callback.apply({}, values));
    };
  };

  for (var i = 0; i < observedStreams.length; i++) {
    var observedStream = observedStreams[i];
    values[i] = observedStream.value;
    observedStream.on('update', createUpdateHandler(i));
  }

  computedValueStream.write(callback.apply({}, values));
  return computedValueStream;
};

module.exports = computedValue;<commit_msg>consistent naming of computedValue function<commit_after>/*
 * index.js : Node.js streaming-style computed values
 *
 * (C) 2013 Tristan Slominski
 */
"use strict";

var ComputedValueStream = require('computed-value-stream');

var computedValue = function computedValue() {
  var computedValueStream = new ComputedValueStream();

  if ( arguments.length == 0) return computedValueStream;

  if ( arguments.length == 1 && typeof arguments[0] != 'function') {
    computedValueStream.write(arguments[0]);
    return computedValueStream;
  }

  // grab the function to calculate dependencies
  var callback = Array.prototype.pop.call(arguments);
  // copy arguments into references
  var observedStreams = Array.prototype.slice.call(arguments);
  // create space to hold latest values in closure
  var values = new Array(observedStreams.length);

  var createUpdateHandler = function createUpdateHandler(index) {
    return function(updatedValue) {
      values[index] = updatedValue;
      computedValueStream.write(callback.apply({}, values));
    };
  };

  for (var i = 0; i < observedStreams.length; i++) {
    var observedStream = observedStreams[i];
    values[i] = observedStream.value;
    observedStream.on('update', createUpdateHandler(i));
  }

  computedValueStream.write(callback.apply({}, values));
  return computedValueStream;
};

module.exports = computedValue;<|endoftext|>


<commit_before>var net = require('net')
var fs = require('fs')
var stream = require('stream')
var assert = require('assert')
var request = require('request')

var API_PATH = "/api/v0/"

module.exports = function(address) {
  assert(address, 'Must specify an address')

  function send(path, args, opts, cb) {
    if(typeof args === 'function') {
      cb = args;
      args = null;
    } else if(typeof opts === 'function') {
      cb = opts;
      opts = null;
    } else if(!cb) {
      cb = function(){}
    }

    if(!path)
      return cb('Must specify a command path')
    if(!typeof path === 'string')
      return cb('Command must be a string')
    //if(args != null && !Array.isArray(args) && !(args instanceof stream.Readable))
    //  return cb('Args must be an array or reable stream')
    if(opts != null && typeof opts !== 'object')
      return cb('Opts must be an object')
    if(!typeof cb === 'function')
      return cb('Callback must be a function')

    if(Array.isArray(path)) path = path.join('/')

    if(!opts) opts = {}
    if(Array.isArray(args)) opts.arg = args

    var req = request({
      uri: 'http://' + address + API_PATH + path,
      qs: opts,
      useQuerystring: true,
      method: 'POST'
    }, function(err, res, data) {
      if(err) {
        try {
          return cb(JSON.parse(err), null, res)
        } catch(e) {
          return cb(new Error(err), null, res)
        }
      }

      try {
        return cb(null, JSON.parse(data), res)
      } catch(e) {
        return cb(null, data, res)
      }
    })

    if(args instanceof stream.Readable) args.pipe(req)
    else if(Buffer.isBuffer(args)) req.end(args)

    return req
  }

  function add(file, cb) {
    var args

    // TODO: handle multiple files, directories (one we have multipart stream support in go daemon)

    if(typeof file === 'string') {
      args = fs.createReadStream(file)

    } else if(Buffer.isBuffer(file)) {
      args = file
    }

    send('add', args, function(err, data) {
      return cb(err, data)
    })
  }

  function cat(objects, cb) {
    if(!Array.isArray(objects)) objects = [objects]

    send('cat', objects, function(err, data) {
      return cb(err, data)
    })
  }

  return {
    send: send,
    add: add,
    cat: cat
  }
}
<commit_msg>Updated to use IPFS HTTP API<commit_after>var net = require('net');
var fs = require('fs');
var stream = require('stream');
var assert = require('assert');
var needle = require('needle');
var qs = require('querystring');

var API_PATH = "/api/v0/";

module.exports = function(address) {
  assert(address, 'Must specify an address');

  function send(path, args, opts, files, cb) {
    if(Array.isArray(path)) path = path.join('/');

    opts = opts || {};
    if(args && !Array.isArray(args)) args = [args];
    if(args) opts.arg = args;
    var query = qs.stringify(opts);

    var data = getFileArgs(files);

    var uri = 'http://' + address + API_PATH + path + '?' + query;

    needle.post(uri, data, {
      multipart: files != null,
      user_agent: '/node-ipfs-rpc/0.0.0/'
    }, function(err, res, data) {
      return cb(err, data);
    });
  }

  // TODO: build a multipart readable stream out of other readable streams
  function getFileArgs(files) {
    var output = {};

    if(!Array.isArray(files)) files = [files];

    for(var i in files) {
      var file = files[i];

      if(typeof file === 'string') {
        // TODO: get actual content type
        output[i] = {
          file: file,
          content_type: 'application/octet-stream'
        };

      } else if(Buffer.isBuffer(file)) {
        output[i] = {
          buffer: file,
          content_type: 'application/octet-stream'
        };
      }
    }

    return output;
  }

  function command(name) {
    return function(cb) {
      send(name, null, null, null, cb);
    }
  }

  function argCommand(name) {
    return function(arg, cb) {
      send(name, arg, null, null, cb);
    }
  }

  return {
    send: send,

    add: function(file, cb) {
      send('add', null, null, file, cb);
    },
    cat: argCommand('cat'),
    ls: argCommand('ls'),

    config: {
      get: argCommand('config'),
      set: function(key, value, cb) {
        send('config', [key, value], null, null, cb)
      },
      show: command('config/show')
    },

    update: {
      apply: command('update'),
      check: command('update/check'),
      log: command('update/log')
    },
    version: command('version'),
    commands: command('commands'),

    mount: function(ipfs, ipns, cb) {
      if(typeof ipfs === 'function') {
        cb = ipfs;
        ipfs = null;
      } else if(typeof ipns === 'function') {
        cb = ipns;
        ipns = null;
      }
      var opts = {};
      if(ipfs) opts.f = ipfs;
      if(ipns) opts.n = ipns;
      send('mount', null, opts, null, cb);
    },

    diag: {
      net: command('diag/net')
    },

    block: {
      get: argCommand('block/get'),
      put: function(file, cb) {
        if(Array.isArray(file))
          return cb(null, new Error('block.put() only accepts 1 file'));
        send('block/put', null, null, file, cb);
      },
    },

    object: {
      get: argCommand('object/get'),
      put: function(file, encoding, cb) {
        if(typeof encoding === 'function')
            return cb(null, new Error('Must specify an object encoding ("json" or "protobuf")'))
        send('block/put', encoding, null, file, cb);
      },
      data: argCommand('object/data'),
      links: argCommand('object/links')
    }
  }
}
<|endoftext|>