<commit_before>var fs = require('fs');
var path = require('path');
var mkdirp = require('mkdirp');
var binaryDumpTreeUtils = require('../../lib/binaryDumpTree.js');
var encodeQuadNameToBinary = require('../../lib/binaryQuadName.js').encodeQuadNameToBinary;

module.exports = createQuadFS;

var saveThreshold = 32 * 1024;

function createQuadFS(quadFSDir) {
  var positionsDir = makeQuadDir('positions');
  var labelsDir = makeQuadDir('labels');

  var treeRoot = {
    selfByteLength: 0,
    childrenByteLength: 0
  };

  var api = {
    saveTreeIndex: saveTreeIndex,
    appendQuad: appendQuad,
  };

  return api;

  function saveTreeIndex(root) {
    var uint32Array = binaryDumpTreeUtils.binaryEncodeTree(root);
    // 4 int 32 for left/top/right/bottom
    // + binary tree itself
    // + terminal nodes index.
    var terminalNodeNames = flush()
    var bufferSize = (4 + uint32Array.length + terminalNodeNames.length) * 4;

    var treeBuffer = Buffer.alloc(bufferSize);

    // offset 0 to 4 * 4 - store root quad dimensions (left/top/right/bottom)
    var offset = 0;
    treeBuffer.writeInt32LE(root.rect.left, offset); offset += 4;
    treeBuffer.writeInt32LE(root.rect.top, offset); offset += 4;
    treeBuffer.writeInt32LE(root.rect.right, offset); offset += 4;
    treeBuffer.writeInt32LE(root.rect.bottom, offset); offset += 4;

    // reminder of the file is binary encoded index of children.
    var i = 0;
    for (i = 0; i < uint32Array.length; ++i) {
      treeBuffer.writeUInt32LE(uint32Array[i], offset);
      offset += 4;
    }

    // write down terminal nodes (nodes too small to have individual files)
    for (i = 0; i < terminalNodeNames.length; ++i) {
      var binaryName = toBinaryEncodedName(terminalNodeNames[i]);
      treeBuffer.writeUInt32LE(binaryName, offset);
      offset += 4;
    }
    fs.writeFileSync(path.join(quadFSDir, 'tree.bin'), treeBuffer);
  }

  function appendQuad(quadName, buffer, labels) {
    var quad = createQuad(quadName, buffer, labels);
    saveQuadIfNeeded(quad);
  }

  function createQuad(quadName, buffer, labels) {
    var quad = treeRoot;
    var byteLength = buffer.byteLength;

    quad.childrenByteLength += byteLength;

    for (var i = 1; i < quadName.length; ++i) {
      var quadId = quadName[i];
      var child = quad[quadId]
      if (!child) {
        child = {
          childrenByteLength: byteLength,
          selfByteLength: 0
        };

        quad[quadId] = child;
      } else {
        child.childrenByteLength += byteLength;
      }

      quad = child;
      saveQuadIfNeeded(child)
    }

    quad.selfByteLength = byteLength;
    quad.name = quadName;
    quad.buffer = buffer;
    quad.labels = labels;

    return quad;
  }

  function saveQuadIfNeeded(quad) {
    var buffer = quad.buffer;
    if (!buffer) return;

    if (buffer.byteLength >= saveThreshold || quad.childrenByteLength >= saveThreshold) {
      saveQuad(quad);
    }
  }

  function saveQuad(quad) {
    var positionsFileName = path.join(positionsDir, quad.name + '.bin');

    console.log('saving ' + positionsFileName);
    fs.writeFileSync(positionsFileName, quad.buffer);

    var labelsFileName = path.join(labelsDir, quad.name + '.json');
    console.log('saving ' + labelsFileName);
    fs.writeFileSync(labelsFileName, JSON.stringify(quad.labels), 'utf8');

    // release memory
    quad.buffer = null;
    quad.labels = null;
  }

  function flush() {
    var terminalLayers = [];

    collectTerminalLayersAndFlushLeaves(treeRoot);

    terminalLayers.forEach(storeTerminalQuad);

    return terminalLayers;

    function storeTerminalQuad(quad) {
      quad.buffer = serializeBuffersSubtree(quad);
      quad.labels = serializeLabelsSubtree(quad);
      saveQuad(quad);
    }

    function serializeLabelsSubtree(quad) {
      var result = Object.create(null);

      appendLabels(quad);

      return result;

      function appendLabels(quad) {
        result[quad.name] = quad.labels;
        for (var i = 0; i < 4; ++i) {
          if (quad[i]) appendLabels(quad[i]);
        }
      }
    }

    function serializeBuffersSubtree(quad) {
      var childrenCount = getChildrenCount(quad)
      // The head of the buffer contains offsets information.
      // Count of children (including self) - 4 bytes,
      // [
      // tuple:
      //   - encodedBinary quad name - 4 bytes,
      //   - offset where quad buffer is written - 4 bytes
      // ...
      // ],
      // giant blob of buffers concatenated together. To find buffer's size
      // just substruct its offset from the previous offset.
      var indexLength = childrenCount * 2 * 4;
      var result = new Buffer(4 + indexLength + quad.childrenByteLength)

      result.writeInt32LE(indexLength, 0); // how big is the index.

      var currentIndexOffset = 4;
      var currentBufferOffset = indexLength + 4;

      writeAtOffset(quad);

      return result;

      function writeAtOffset(quad) {
        var encodedName = encodeQuadNameToBinary(quad.name);

        result.writeInt32LE(encodedName, currentIndexOffset); currentIndexOffset += 4;
        result.writeInt32LE(currentBufferOffset, currentIndexOffset); currentIndexOffset += 4;

        quad.buffer.copy(result, currentBufferOffset); // store this quad into destination
        currentBufferOffset += quad.buffer.byteLength;

        for (var i = 0; i < 4; ++i) {
          if (quad[i]) writeAtOffset(quad[i]);
        }
      }
    }

    function getChildrenCount(quad) {
      var count = 1;
      for (var i = 0; i < 4; ++i) {
        if(quad[i]) count += getChildrenCount(quad[i]);
      }

      return count;
    }

    function collectTerminalLayersAndFlushLeaves(startFrom) {
      var i;
      var hasChildren = false;

      for (i = 0; i < 4; ++i) {
        if (startFrom[i]) {
          hasChildren = true;
          break;
        }
      }

      if (startFrom.buffer && !hasChildren) {
        // it's a leaf.
        saveQuad(startFrom);
        return;
      } else if (startFrom.buffer) {
        terminalLayers.push(startFrom);
        return;
      }

      for (i = 0; i < 4; ++i) {
        if (startFrom[i]) collectTerminalLayersAndFlushLeaves(startFrom[i]);
      }
    }
  }

  function makeQuadDir(name) {
    var dirName = path.join(quadFSDir, name);
    mkdirp.sync(dirName);

    return dirName
  }
}

function toBinaryEncodedName(quad) {
  return encodeQuadNameToBinary(quad.name);
}
<commit_msg>More checks for saving quads<commit_after>var fs = require('fs');
var path = require('path');
var mkdirp = require('mkdirp');
var binaryDumpTreeUtils = require('../../lib/binaryDumpTree.js');
var encodeQuadNameToBinary = require('../../lib/binaryQuadName.js').encodeQuadNameToBinary;

module.exports = createQuadFS;

var saveThreshold = 32 * 1024;

function createQuadFS(quadFSDir) {
  var positionsDir = makeQuadDir('positions');
  var labelsDir = makeQuadDir('labels');

  var treeRoot = {
    selfByteLength: 0,
    childrenByteLength: 0
  };

  var api = {
    saveTreeIndex: saveTreeIndex,
    appendQuad: appendQuad,
  };

  return api;

  function saveTreeIndex(root) {
    var uint32Array = binaryDumpTreeUtils.binaryEncodeTree(root);
    // 4 int 32 for left/top/right/bottom
    // + binary tree itself
    // + terminal nodes index.
    var terminalNodeNames = flush()
    var bufferSize = (4 + uint32Array.length + terminalNodeNames.length) * 4;

    var treeBuffer = Buffer.alloc(bufferSize);

    // offset 0 to 4 * 4 - store root quad dimensions (left/top/right/bottom)
    var offset = 0;
    treeBuffer.writeInt32LE(root.rect.left, offset); offset += 4;
    treeBuffer.writeInt32LE(root.rect.top, offset); offset += 4;
    treeBuffer.writeInt32LE(root.rect.right, offset); offset += 4;
    treeBuffer.writeInt32LE(root.rect.bottom, offset); offset += 4;

    // reminder of the file is binary encoded index of children.
    var i = 0;
    for (i = 0; i < uint32Array.length; ++i) {
      treeBuffer.writeUInt32LE(uint32Array[i], offset);
      offset += 4;
    }

    // write down terminal nodes (nodes too small to have individual files)
    for (i = 0; i < terminalNodeNames.length; ++i) {
      var binaryName = toBinaryEncodedName(terminalNodeNames[i]);
      treeBuffer.writeUInt32LE(binaryName, offset);
      offset += 4;
    }
    fs.writeFileSync(path.join(quadFSDir, 'tree.bin'), treeBuffer);
  }

  function appendQuad(quadName, buffer, labels) {
    var quad = createQuad(quadName, buffer, labels);
    saveQuadIfNeeded(quad);
  }

  function createQuad(quadName, buffer, labels) {
    var quad = treeRoot;
    var byteLength = buffer.byteLength;

    quad.childrenByteLength += byteLength;
    saveQuadIfNeeded(quad);

    for (var i = 1; i < quadName.length; ++i) {
      var quadId = quadName[i];
      var child = quad[quadId]
      if (!child) {
        child = {
          childrenByteLength: byteLength,
          selfByteLength: 0
        };

        quad[quadId] = child;
      } else {
        child.childrenByteLength += byteLength;
      }

      quad = child;
      saveQuadIfNeeded(child);
    }

    quad.selfByteLength = byteLength;
    quad.name = quadName;
    quad.buffer = buffer;
    quad.labels = labels;

    return quad;
  }

  function saveQuadIfNeeded(quad) {
    var buffer = quad.buffer;
    if (!buffer) return;

    if (buffer.byteLength >= saveThreshold || quad.childrenByteLength >= saveThreshold) {
      saveQuad(quad);
    }
  }

  function saveQuad(quad) {
    var positionsFileName = path.join(positionsDir, quad.name + '.bin');

    console.log('saving ' + positionsFileName);
    fs.writeFileSync(positionsFileName, quad.buffer);

    var labelsFileName = path.join(labelsDir, quad.name + '.json');
    console.log('saving ' + labelsFileName);
    fs.writeFileSync(labelsFileName, JSON.stringify(quad.labels), 'utf8');

    // release memory
    quad.buffer = null;
    quad.labels = null;
  }

  function flush() {
    var terminalLayers = [];

    collectTerminalLayersAndFlushLeaves(treeRoot);

    terminalLayers.forEach(storeTerminalQuad);

    return terminalLayers;

    function storeTerminalQuad(quad) {
      quad.buffer = serializeBuffersSubtree(quad);
      quad.labels = serializeLabelsSubtree(quad);
      saveQuad(quad);
    }

    function serializeLabelsSubtree(quad) {
      var result = Object.create(null);

      appendLabels(quad);

      return result;

      function appendLabels(quad) {
        result[quad.name] = quad.labels;
        for (var i = 0; i < 4; ++i) {
          if (quad[i]) appendLabels(quad[i]);
        }
      }
    }

    function serializeBuffersSubtree(quad) {
      var childrenCount = getChildrenCount(quad)
      // The head of the buffer contains offsets information.
      // Count of children (including self) - 4 bytes,
      // [
      // tuple:
      //   - encodedBinary quad name - 4 bytes,
      //   - offset where quad buffer is written - 4 bytes
      // ...
      // ],
      // giant blob of buffers concatenated together. To find buffer's size
      // just substruct its offset from the previous offset.
      var indexLength = childrenCount * 2 * 4;
      var result = new Buffer(4 + indexLength + quad.childrenByteLength)

      result.writeInt32LE(indexLength, 0); // how big is the index.

      var currentIndexOffset = 4;
      var currentBufferOffset = indexLength + 4;

      writeAtOffset(quad);

      return result;

      function writeAtOffset(quad) {
        var encodedName = encodeQuadNameToBinary(quad.name);

        result.writeInt32LE(encodedName, currentIndexOffset); currentIndexOffset += 4;
        result.writeInt32LE(currentBufferOffset, currentIndexOffset); currentIndexOffset += 4;

        if (quad.buffer === null) debugger;
        quad.buffer.copy(result, currentBufferOffset); // store this quad into destination
        currentBufferOffset += quad.buffer.byteLength;

        for (var i = 0; i < 4; ++i) {
          if (quad[i]) writeAtOffset(quad[i]);
        }
      }
    }

    function getChildrenCount(quad) {
      var count = 1;
      for (var i = 0; i < 4; ++i) {
        if(quad[i]) count += getChildrenCount(quad[i]);
      }

      return count;
    }

    function collectTerminalLayersAndFlushLeaves(startFrom) {
      var i;
      var hasChildren = false;

      for (i = 0; i < 4; ++i) {
        if (startFrom[i]) {
          hasChildren = true;
          break;
        }
      }

      if (startFrom.buffer && !hasChildren) {
        // it's a leaf.
        saveQuad(startFrom);
        return;
      } else if (startFrom.buffer) {
        terminalLayers.push(startFrom);
        return;
      }

      for (i = 0; i < 4; ++i) {
        if (startFrom[i]) collectTerminalLayersAndFlushLeaves(startFrom[i]);
      }
    }
  }

  function makeQuadDir(name) {
    var dirName = path.join(quadFSDir, name);
    mkdirp.sync(dirName);

    return dirName
  }
}

function toBinaryEncodedName(quad) {
  return encodeQuadNameToBinary(quad.name);
}
<|endoftext|>


<commit_before>var _ = require('underscore');

var browsers = [];

function addBrowser(browserName, platform, version){
  browsers.push({
    browserName : browserName,
    platform : platform,
    version : version
  });
}

var defaultFF = [5, 10, 20, 30, 40, 46, //'dev',
                    'beta'],
    defaultChrome = [26, 36, 51, 'dev', 'beta'];

addBrowser('internet explorer', 'Windows 10', 11);
addBrowser('MicrosoftEdge', 'Windows 10', '13.10586');
defaultChrome.forEach(addBrowser.bind(this, 'chrome', 'Windows 10'));
_.difference(defaultFF,[46, 'dev']) //these fail on sauce labs due to sauce labs bugs
  .forEach(addBrowser.bind(this, 'firefox', 'Windows 10'));

[8, 9, 10, 11].forEach(addBrowser.bind(this, 'internet explorer', 'Windows 7'));
_.difference(defaultChrome,[36])    //TODO: fix Chrome 36 on Windows 7, which consistently fails for unknown reason
  .forEach(addBrowser.bind(this, 'chrome', 'Windows 7'));
[11, 12].forEach(addBrowser.bind(this, 'opera', 'Windows 7'));
defaultFF.forEach(addBrowser.bind(this, 'firefox', 'Windows 7'));
addBrowser('safari', 'Windows 7', 5);

addBrowser('internet explorer', 'Windows XP', 8);
[26, 36, 49].forEach(addBrowser.bind(this, 'chrome', 'Windows XP'));
[
  //11,   //TODO: opera 11 on Windows XP always timing out. probable sauce labs platform bug
  12].forEach(addBrowser.bind(this, 'opera', 'Windows XP'));
[ 4, 10, 20, 30, 40, 45 ].forEach(addBrowser.bind(this, 'firefox', 'Windows XP'));

_.difference(defaultChrome,[26])  //chrome 26 not supported on OS X 10.11
  .forEach(addBrowser.bind(this, 'chrome', 'OS X 10.11'));
defaultFF.forEach(addBrowser.bind(this, 'firefox', 'OS X 10.11'));
addBrowser('safari', 'OS X 10.11', 9);

_.difference(defaultChrome,[26,36]) //chrome 36 and 26 not supported on OS X 10.10
  .forEach(addBrowser.bind(this, 'chrome', 'OS X 10.10'));
[32,
  //42,     //FIXME: Firefox 42 times out
  44].forEach(addBrowser.bind(this, 'firefox', 'OS X 10.10'));
addBrowser('safari', 'OS X 10.10', 8);

_.difference(defaultChrome,[26])
 .forEach(addBrowser.bind(this, 'chrome', 'OS X 10.9'));
defaultFF.forEach(addBrowser.bind(this, 'firefox', 'OS X 10.9'));
addBrowser('safari', 'OS X 10.9', 7);

[27,
  //30, //Chrome 30 not supported
  40, 49].forEach(addBrowser.bind(this, 'chrome', 'OS X 10.8'));
defaultFF.forEach(addBrowser.bind(this, 'firefox', 'OS X 10.8'));
addBrowser('safari', 'OS X 10.8', 6);

[26, 30, 40, 48].forEach(addBrowser.bind(this, 'chrome', 'Linux'));
[4, 10, 20, 30, 40, 45].forEach(addBrowser.bind(this, 'firefox', 'Linux'));
addBrowser('opera', 'Linux', 12);

['9.4','9.3','9.2','9.1','9.0','8.4','8.3','8.2','8.1','8.0'].forEach(function(version){
  browsers.push({
    "appiumVersion": "1.5.3",
    "deviceName": "iPhone 6 Simulator",
    "deviceOrientation": "portrait",
    "platformVersion": version,
    "platformName": "iOS",
    "browserName": "Safari"
  });
});

/*
['5.1','5.0','4.4','4.3','4.2'].forEach(function(version){
  browsers.push({
    "appiumVersion": "1.5.3",
    "deviceName":"Android Emulator",
    "deviceType":"phone",
    "deviceOrientation": "portrait",
    "browserName": "Browser",
    "platformVersion": version,
    "platformName":"Android"
  });
});
*/

module.exports = browsers;
<commit_msg>Added support for Firefox 47. Tested and works.<commit_after>var _ = require('underscore');

var browsers = [];

function addBrowser(browserName, platform, version){
  browsers.push({
    browserName : browserName,
    platform : platform,
    version : version
  });
}

var defaultFF = [5, 10, 20, 30, 40, 46, 47 ],
    defaultChrome = [26, 36, 51, 'dev', 'beta'];

addBrowser('internet explorer', 'Windows 10', 11);
addBrowser('MicrosoftEdge', 'Windows 10', '13.10586');
defaultChrome.forEach(addBrowser.bind(this, 'chrome', 'Windows 10'));
_.difference(defaultFF,[46, 47, 'dev']) //these fail on sauce labs due to sauce labs bugs
  .forEach(addBrowser.bind(this, 'firefox', 'Windows 10'));

[8, 9, 10, 11].forEach(addBrowser.bind(this, 'internet explorer', 'Windows 7'));
_.difference(defaultChrome,[36])    //TODO: fix Chrome 36 on Windows 7, which consistently fails for unknown reason
  .forEach(addBrowser.bind(this, 'chrome', 'Windows 7'));
[11, 12].forEach(addBrowser.bind(this, 'opera', 'Windows 7'));
defaultFF.forEach(addBrowser.bind(this, 'firefox', 'Windows 7'));
addBrowser('safari', 'Windows 7', 5);

addBrowser('internet explorer', 'Windows XP', 8);
[26, 36, 49].forEach(addBrowser.bind(this, 'chrome', 'Windows XP'));
[
  //11,   //TODO: opera 11 on Windows XP always timing out. probable sauce labs platform bug
  12].forEach(addBrowser.bind(this, 'opera', 'Windows XP'));
[ 4, 10, 20, 30, 40, 45 ].forEach(addBrowser.bind(this, 'firefox', 'Windows XP'));

_.difference(defaultChrome,[26])  //chrome 26 not supported on OS X 10.11
  .forEach(addBrowser.bind(this, 'chrome', 'OS X 10.11'));
defaultFF.forEach(addBrowser.bind(this, 'firefox', 'OS X 10.11'));
addBrowser('safari', 'OS X 10.11', 9);

_.difference(defaultChrome,[26,36]) //chrome 36 and 26 not supported on OS X 10.10
  .forEach(addBrowser.bind(this, 'chrome', 'OS X 10.10'));
[32,
  //42,     //FIXME: Firefox 42 times out
  44].forEach(addBrowser.bind(this, 'firefox', 'OS X 10.10'));
addBrowser('safari', 'OS X 10.10', 8);

_.difference(defaultChrome,[26])
 .forEach(addBrowser.bind(this, 'chrome', 'OS X 10.9'));
defaultFF.forEach(addBrowser.bind(this, 'firefox', 'OS X 10.9'));
addBrowser('safari', 'OS X 10.9', 7);

[27,
  //30, //Chrome 30 not supported
  40, 49].forEach(addBrowser.bind(this, 'chrome', 'OS X 10.8'));
defaultFF.forEach(addBrowser.bind(this, 'firefox', 'OS X 10.8'));
addBrowser('safari', 'OS X 10.8', 6);

[26, 30, 40, 48].forEach(addBrowser.bind(this, 'chrome', 'Linux'));
[4, 10, 20, 30, 40, 45].forEach(addBrowser.bind(this, 'firefox', 'Linux'));
addBrowser('opera', 'Linux', 12);

['9.4','9.3','9.2','9.1','9.0','8.4','8.3','8.2','8.1','8.0'].forEach(function(version){
  browsers.push({
    "appiumVersion": "1.5.3",
    "deviceName": "iPhone 6 Simulator",
    "deviceOrientation": "portrait",
    "platformVersion": version,
    "platformName": "iOS",
    "browserName": "Safari"
  });
});

/*
['5.1','5.0','4.4','4.3','4.2'].forEach(function(version){
  browsers.push({
    "appiumVersion": "1.5.3",
    "deviceName":"Android Emulator",
    "deviceType":"phone",
    "deviceOrientation": "portrait",
    "browserName": "Browser",
    "platformVersion": version,
    "platformName":"Android"
  });
});
*/

module.exports = browsers;
<|endoftext|>


<commit_before>window.addEventListener("load",function() { // Wait for the window to finish loading

var Q = window.Q = Quintus()                // Create a new engine instance
    .include("Sprites, Scenes, Input, 2D, Anim, Touch, UI") // Load any needed modules
    .setup("myGame")                        // Bind Quintus to the canvas with ID "myGame"
    .controls()                             // Add in default controls (keyboard, buttons)
    .touch();                               // Add in touch support (for the UI)

    /*
    ... Actual game code goes here ...
    */

});
<commit_msg>Starting to add some, very basic, game logic<commit_after>window.addEventListener("load",function() { // Wait for the window to finish loading

var Q = window.Q = Quintus()                // Create a new engine instance
    .include("Sprites, Scenes, Input, 2D, Anim, Touch, UI") // Load any needed modules
    .setup("myGame")                        // Bind Quintus to the canvas with ID "myGame"
    .controls()                             // Add in default controls (keyboard, buttons)
    .touch();                               // Add in touch support (for the UI)

    /*
    ... Actual game code goes here ...
    */

    Q.Class.extend("MyClass", {
       init: function() { console.log("MyClass instance created"); },
       doIt: function() { alert("Doin it!"); }
    });

    var myInstance = new Q.MyClass(); // MyClass instance created

    myInstance.doIt(); // Doin it!

    console.log(myInstance.className); // 'MyClass'
    console.log(myInstance instanceof Q.Class); // true
    console.log(myInstance instanceof Q.MyClass); // true
});

<|endoftext|>


<commit_before>// This file is ES5; it's loaded before Babel.
require('babel/register')({
  extensions: ['.desktop.js', '.es6', '.es', '.jsx', '.js']
})

const menubar = require('menubar')
const ipc = require('ipc')
const Window = require('./window')

const mb = menubar({
  index: `file://${__dirname}/../renderer/launcher.html`,
  width: 200, height: 250,
  preloadWindow: true,
  icon: 'Icon.png'
})

const trackerWindow = new Window('tracker', {
  width: 500, height: 300,
  resizable: false,
  fullscreen: false,
  frame: false
})

const mainWindow = new Window('index', {
  width: 1600, height: 1200, openDevTools: true
})

mb.on('ready', () => {
  require('../../react-native/react/native/notifications').init()
})

ipc.on('showMain', () => { mainWindow.show() })
ipc.on('showTracker', () => { trackerWindow.show() })
<commit_msg>Fix gap left in status bar on OS X after quit<commit_after>// This file is ES5; it's loaded before Babel.
require('babel/register')({
  extensions: ['.desktop.js', '.es6', '.es', '.jsx', '.js']
})

const menubar = require('menubar')
const ipc = require('ipc')
const Window = require('./window')

const mb = menubar({
  index: `file://${__dirname}/../renderer/launcher.html`,
  width: 200, height: 250,
  preloadWindow: true,
  icon: 'Icon.png'
})

const trackerWindow = new Window('tracker', {
  width: 500, height: 300,
  resizable: false,
  fullscreen: false,
  frame: false
})

const mainWindow = new Window('index', {
  width: 1600, height: 1200, openDevTools: true
})

mb.on('ready', () => {
  require('../../react-native/react/native/notifications').init()
})

// Work around an OS X bug that leaves a gap in the status bar if you exit
// without removing your status bar icon.
if (process.platform === 'darwin') {
  mb.app.on('quit', () => { mb.tray.destroy() })
}

ipc.on('showMain', () => { mainWindow.show() })
ipc.on('showTracker', () => { trackerWindow.show() })
<|endoftext|>


<commit_before>/*
for each li
	color = find span color --- this.text
	url = find main prod image -- this.url
	category Swatch Color Button = matching color.url
end

on click
*/

var colorBtnSrc = {};

$("span:contains('Color')").parents().eq(2).find('.productAttributeValue li').each( function (){

	var listings = $(this);
		prodColor = $(this).find('.name').text();
	console.log(prodColor);

	$.when(
		$(this).find('label').click()
	)
	.then( function() {
		colorBtnSrc[prodColor] = $(this).parents().find('.ProductThumbImage a').attr('href');
console.log(colorBtnSrc[prodColor])
	});
console.log(colorBtnSrc[prodColor])
})

//$("span:contains('Color')").parents().eq(2).find('.productAttributeValue li').removeClass('selectedValue').find('.radio span').removeClass('checked');
//$("span:contains('Color')").parents().eq(2).find('.productAttributeValue li').eq(2).addClass('selectedValue').find('.radio span').addClass('checked');

$("span:contains('Color')").parents().eq(2).find('.productAttributeValue li').eq(2).find('label').click();

<commit_msg>Building into ajax<commit_after>/*
for each li
	color = find span color --- this.text
	url = find main prod image -- this.url
	category Swatch Color Button = matching color.url
end

on click
*/

var colorBtnSrc = {};

$("span:contains('Color')").parents().eq(2).find('.productAttributeValue li').each( function (){

	var listings = $(this);
		prodColor = $(this).find('.name').text();
	console.log(prodColor);

	$.when(
		$(this).find('label').click()
	)
	.then( function() {
		colorBtnSrc[prodColor] = $(this).parents().find('.ProductThumbImage a').attr('href');
console.log(colorBtnSrc[prodColor])
	});
console.log(colorBtnSrc[prodColor])
})

//$("span:contains('Color')").parents().eq(2).find('.productAttributeValue li').removeClass('selectedValue').find('.radio span').removeClass('checked');
//$("span:contains('Color')").parents().eq(2).find('.productAttributeValue li').eq(2).addClass('selectedValue').find('.radio span').addClass('checked');

$("span:contains('Color')").parents().eq(2).find('.productAttributeValue li').eq(2).find('label').click();

	$(".Options").each(function checkForOptionSwatches(url) {
		var productListing = $(this).closest('em.p-price').html() ;
			productLink = $(this).parent().parent().find('div.ProductImage a').attr('href');
		var	$this = $(this);
		function getOptionSwatches() {
			return $.ajax({
		            url: productLink,
		            type: 'GET',
		            dataType: 'html',
		            //async: false
		    });
		}
		getOptionSwatches()
			.done(function(data) {

	                result = data;
    				var productPage = result;
						$productPageProcessing = $( productPage ).find("span:contains('Color')").parents().eq(2).find('.productAttributeValue li');

				var colorBtnSrc = {};

				$productPageProcessing.each( function (){

					var listings = $(this);
						prodColor = $(this).find('.name').text();
					console.log(prodColor);

					$.when(
						$(this).find('label').click()
					)
					.then( function() {
						colorBtnSrc[prodColor] = $(this).parents().find('.ProductThumbImage a').attr('href');
				console.log(colorBtnSrc[prodColor])
					});
				console.log(colorBtnSrc[prodColor])
				})

			    }).fail(function() {
			    	return;
			    });
			}
	    );

<|endoftext|>


<commit_before>import Path from 'path'
import fs from 'fs'
import child_process from 'child_process'
import { Map } from 'immutable'
import http from 'http'
import url from 'url'
import * as constants from '../constants/helper.js'

export const checkSiaPath = () => new Promise((resolve, reject) => {
	fs.stat(Path.resolve(SiaAPI.config.attr('siac').path, './siac'), (err) => {
		 if (!err) {
			resolve()
		 } else {
			reject(err)
		 }
	})
})

export const initPlugin = () => checkSiaPath().catch(() => {
	// config.path doesn't exist. Prompt the user for siac's location
	if (!SiaAPI.config.attr('siac')) {
		SiaAPI.config.attr('siac', { path: '' })
	}
	SiaAPI.showError({ title: 'Siac not found', content: 'Sia-UI couldn\'t locate siac. Please navigate to siac.' })
	const siacPath = SiaAPI.openFile({
		title: 'Please locate siac.',
		properties: ['openFile'],
		defaultPath: Path.join('..', SiaAPI.config.attr('siac').path || './' ),
		filters: [{ name: 'siac', extensions: ['*'] }],
	})
	SiaAPI.config.attr('siac', { path: Path.dirname(siacPath[0]) })
	SiaAPI.config.save()
})

export const commandType = function(commandString, specialArray) {
	//Cleans string and sees if any subarray in array starts with the string when split.
	const args = commandString.replace(/\s*\s/g, ' ').trim().split(' ')
	if (args[0] === './siac' || args[0] === 'siac') {
		args.shift()
	}

	//Can't do a simple match because commands can be passed additional arguments.
	return specialArray.findIndex( (command) =>
		command.reduce((matches, argument, i) =>
			(matches && argument === args[i]),
		true) && commandString.indexOf('-h') === -1 //Also covers --help.
		//Don't show a password prompt if user is looking for help.
	)
}

export const spawnCommand = function(commandStr, actions, newid) {
	//Create new command object. Id doesn't need to be unique, just can't be the same for adjacent commands.

	//We set the command first so the user sees exactly what they type. (Minus leading and trailing spaces, double spaces, etc.)
	let commandString = commandStr.replace(/\s*\s/g, ' ').trim()
	const newCommand = Map({ command: commandString, result: '', id: newid, stat: 'running' })
	actions.addCommand(newCommand)

	//Remove surrounding whitespace and leading siac command.
	if (commandString.startsWith('siac')) {
		commandString = commandString.slice(4).trim()
	} else if (commandString.startsWith('./siac')) {
		commandString = commandString.slice(6).trim()
	}

	//Add address flag to siac.
	let args = commandString.split(' ')
	if (args.indexOf('-a') === -1 && args.indexOf('--address') === -1 && SiaAPI.config.attr('address')) {
		args = args.concat([ '-a', SiaAPI.config.attr('address') ])
	}

	const siac = child_process.spawn('./siac', args, { cwd: SiaAPI.config.attr('siac').path })

	//Update the UI when the process receives new ouput.
	const consumeChunk = function(chunk) {
		const chunkTrimmed = chunk.toString().replace(/stty: stdin isn't a terminal\n/g, '')
		actions.updateCommand(newCommand.get('command'), newCommand.get('id'), chunkTrimmed)
	}
	siac.stdout.on('data', consumeChunk)
	siac.stderr.on('data', consumeChunk)

	let closed = false
	const streamClosed = function() {
		if (!closed) {
			actions.endCommand(newCommand.get('command'), newCommand.get('id'))
			closed = true
		}
	}

	siac.on('error', () => {
		streamClosed()
	})
	siac.on('close', () => {
		streamClosed()
	})

	//If window is small auto close command overview so we can see the return value.
	if (document.getElementsByClassName('command-history-list')[0].offsetHeight < 180) {
		actions.hideCommandOverview()
	}

	return siac
}

export const httpCommand = function(commandStr, actions, newid) {
	let commandString = commandStr
	const originalCommand = commandStr.replace(/\s*\s/g, ' ').trim()

	//Remove surrounding whitespace and leading siac command.
	if (commandString.startsWith('siac')) {
		commandString = commandString.slice(4).trim()
	} else if (commandString.startsWith('./siac')) {
		commandString = commandString.slice(6).trim()
	}

	//Parse arguments.
	const args = commandString.split(' ')

	//Add address flag to siac.
	let siaAddr = url.parse('http://localhost:9980')

	if (args.indexOf('-a') === -1 && args.indexOf('--address') === -1) {
		if (SiaAPI.config.attr('address')) {
			//Load default address.
			siaAddr = url.parse('http://' + SiaAPI.config.attr('address'))
		}
	} else {
		//Parse address flag.
		let index = args.indexOf('-a')
		if  (index === -1) {
			index = args.indexOf('--address')

		}
		if (index < args.length-1) {
			siaAddr = url.parse('http://' + args[index+1])
		}
		args.splice(index, 2)
		commandString = args.join(' ')
	}

	let apiURL = ''
	switch (commandString) {
	case 'wallet unlock':
		apiURL = '/wallet/unlock'
		break

	case 'wallet load seed':
		apiURL = '/wallet/seed'
		break

	default:
		return spawnCommand(commandString, actions).stdin
	}

	//Spawn new command if we are good to go.
	const newCommand = Map({ command: originalCommand, result: '', id: newid, stat: 'running' })
	actions.addCommand(newCommand)

	//Update the UI when the process receives new ouput.
	const consumeChunk = function(chunk) {
		let newChunk = chunk
		if (chunk.toString().trim() === '{"Success":true}') {
			newChunk = 'Success'
		}
		actions.updateCommand(newCommand.get('command'), newCommand.get('id'), newChunk)
	}

	let closed = false
	const streamClosed = function() {
		if (!closed) {
			actions.endCommand(newCommand.get('command'), newCommand.get('id'))
			closed = true
		}
	}

	//If window is small auto close command overview so we can see the return value.
	if (document.getElementsByClassName('command-history-list')[0].offsetHeight < 180) {
		actions.hideCommandOverview()
	}

	const options = {
		hostname: siaAddr.hostname,
		port: siaAddr.port,
		path: apiURL,
		method: 'POST',
		headers: {
			'User-Agent': 'Sia-Agent',
			'Content-Type': 'application/x-www-form-urlencoded',
		},
	}
	const req = http.request(options, (res) => {
		res.on('data', consumeChunk)
		res.on('end', streamClosed)
	})
	req.on('error', (e) => {
		consumeChunk(e.message)
		streamClosed()
	})
	return req
}

export const commandInputHelper = function(e, actions, currentCommand, showCommandOverview, newid) {
	//These commands need a password prompt or other special handling.
	const specialCommands = [ ['wallet', 'load', 'seed'], ['wallet', 'unlock'], ['help'], ['?'] ]

	const eventTarget = e.target
	//Enter button.
	if (e.keyCode === 13) {

		//Check if command is special.
		switch ( commandType(currentCommand, specialCommands) ) {
		case constants.REGULAR_COMMAND: //Regular command.
			spawnCommand(currentCommand, actions, newid) //Spawn command defined in index.js.
			break

		case constants.WALLET_UNLOCK: //wallet unlock
		case constants.WALLET_SEED: //wallet load seed
			actions.showWalletPrompt()
			break

		case constants.HELP: //help
			const text = 'help'
		case constants.HELP_QMARK: //?
			const newText = text || '?'
			if (showCommandOverview) {
				actions.hideCommandOverview()
			} else {
				actions.showCommandOverview()
			}

			//The command log won't actually show a help command but we still want to be able to select it in the command history.
			const newCommand = Map({ command: newText, result: '', id: newid })
			actions.addCommand(newCommand)
			actions.endCommand(newCommand.get('command'), newCommand.get('id'))
			break

		default:
			break
		}
	 } else if (e.keyCode === 38) {
		//Up arrow.
		actions.loadPrevCommand(eventTarget.value)
		setTimeout( () => {
			eventTarget.setSelectionRange(eventTarget.value.length, eventTarget.value.length)
		}, 0)
	} else if (e.keyCode === 40) {
		//Down arrow.
		actions.loadNextCommand(eventTarget.value)
		setTimeout(() => {
			eventTarget.setSelectionRange(eventTarget.value.length, eventTarget.value.length)
		}, 0)
	}
}
<commit_msg>use a default path for siac, next to siad<commit_after>import Path from 'path'
import fs from 'fs'
import child_process from 'child_process'
import { Map } from 'immutable'
import http from 'http'
import url from 'url'
import * as constants from '../constants/helper.js'

export const checkSiaPath = () => new Promise((resolve, reject) => {
	fs.stat(Path.join(SiaAPI.config.attr('siad').path, process.platform === 'win32' ? './siac.exe' : './siac'), (err) => {
		 if (!err) {
			resolve()
		 } else {
			reject(err)
		 }
	})
})

export const initPlugin = () => checkSiaPath().catch(() => {
	// config.path doesn't exist. Prompt the user for siac's location
	SiaAPI.showError({ title: 'Siac not found', content: 'Sia-UI couldn\'t locate siac. Please navigate to siac.' })
	const siacPath = SiaAPI.openFile({
		title: 'Please locate siac.',
		properties: ['openFile'],
		defaultPath: Path.join('..', SiaAPI.config.attr('siac').path || './' ),
		filters: [{ name: 'siac', extensions: ['*'] }],
	})
	SiaAPI.config.attr('siac', { path: Path.dirname(siacPath[0]) })
	SiaAPI.config.save()
})

export const commandType = function(commandString, specialArray) {
	//Cleans string and sees if any subarray in array starts with the string when split.
	const args = commandString.replace(/\s*\s/g, ' ').trim().split(' ')
	if (args[0] === './siac' || args[0] === 'siac') {
		args.shift()
	}

	//Can't do a simple match because commands can be passed additional arguments.
	return specialArray.findIndex( (command) =>
		command.reduce((matches, argument, i) =>
			(matches && argument === args[i]),
		true) && commandString.indexOf('-h') === -1 //Also covers --help.
		//Don't show a password prompt if user is looking for help.
	)
}

export const spawnCommand = function(commandStr, actions, newid) {
	//Create new command object. Id doesn't need to be unique, just can't be the same for adjacent commands.

	//We set the command first so the user sees exactly what they type. (Minus leading and trailing spaces, double spaces, etc.)
	let commandString = commandStr.replace(/\s*\s/g, ' ').trim()
	const newCommand = Map({ command: commandString, result: '', id: newid, stat: 'running' })
	actions.addCommand(newCommand)

	//Remove surrounding whitespace and leading siac command.
	if (commandString.startsWith('siac')) {
		commandString = commandString.slice(4).trim()
	} else if (commandString.startsWith('./siac')) {
		commandString = commandString.slice(6).trim()
	}

	//Add address flag to siac.
	let args = commandString.split(' ')
	if (args.indexOf('-a') === -1 && args.indexOf('--address') === -1 && SiaAPI.config.attr('address')) {
		args = args.concat([ '-a', SiaAPI.config.attr('address') ])
	}

	const siac = child_process.spawn('./siac', args, { cwd: SiaAPI.config.attr('siac').path })

	//Update the UI when the process receives new ouput.
	const consumeChunk = function(chunk) {
		const chunkTrimmed = chunk.toString().replace(/stty: stdin isn't a terminal\n/g, '')
		actions.updateCommand(newCommand.get('command'), newCommand.get('id'), chunkTrimmed)
	}
	siac.stdout.on('data', consumeChunk)
	siac.stderr.on('data', consumeChunk)

	let closed = false
	const streamClosed = function() {
		if (!closed) {
			actions.endCommand(newCommand.get('command'), newCommand.get('id'))
			closed = true
		}
	}

	siac.on('error', () => {
		streamClosed()
	})
	siac.on('close', () => {
		streamClosed()
	})

	//If window is small auto close command overview so we can see the return value.
	if (document.getElementsByClassName('command-history-list')[0].offsetHeight < 180) {
		actions.hideCommandOverview()
	}

	return siac
}

export const httpCommand = function(commandStr, actions, newid) {
	let commandString = commandStr
	const originalCommand = commandStr.replace(/\s*\s/g, ' ').trim()

	//Remove surrounding whitespace and leading siac command.
	if (commandString.startsWith('siac')) {
		commandString = commandString.slice(4).trim()
	} else if (commandString.startsWith('./siac')) {
		commandString = commandString.slice(6).trim()
	}

	//Parse arguments.
	const args = commandString.split(' ')

	//Add address flag to siac.
	let siaAddr = url.parse('http://localhost:9980')

	if (args.indexOf('-a') === -1 && args.indexOf('--address') === -1) {
		if (SiaAPI.config.attr('address')) {
			//Load default address.
			siaAddr = url.parse('http://' + SiaAPI.config.attr('address'))
		}
	} else {
		//Parse address flag.
		let index = args.indexOf('-a')
		if  (index === -1) {
			index = args.indexOf('--address')

		}
		if (index < args.length-1) {
			siaAddr = url.parse('http://' + args[index+1])
		}
		args.splice(index, 2)
		commandString = args.join(' ')
	}

	let apiURL = ''
	switch (commandString) {
	case 'wallet unlock':
		apiURL = '/wallet/unlock'
		break

	case 'wallet load seed':
		apiURL = '/wallet/seed'
		break

	default:
		return spawnCommand(commandString, actions).stdin
	}

	//Spawn new command if we are good to go.
	const newCommand = Map({ command: originalCommand, result: '', id: newid, stat: 'running' })
	actions.addCommand(newCommand)

	//Update the UI when the process receives new ouput.
	const consumeChunk = function(chunk) {
		let newChunk = chunk
		if (chunk.toString().trim() === '{"Success":true}') {
			newChunk = 'Success'
		}
		actions.updateCommand(newCommand.get('command'), newCommand.get('id'), newChunk)
	}

	let closed = false
	const streamClosed = function() {
		if (!closed) {
			actions.endCommand(newCommand.get('command'), newCommand.get('id'))
			closed = true
		}
	}

	//If window is small auto close command overview so we can see the return value.
	if (document.getElementsByClassName('command-history-list')[0].offsetHeight < 180) {
		actions.hideCommandOverview()
	}

	const options = {
		hostname: siaAddr.hostname,
		port: siaAddr.port,
		path: apiURL,
		method: 'POST',
		headers: {
			'User-Agent': 'Sia-Agent',
			'Content-Type': 'application/x-www-form-urlencoded',
		},
	}
	const req = http.request(options, (res) => {
		res.on('data', consumeChunk)
		res.on('end', streamClosed)
	})
	req.on('error', (e) => {
		consumeChunk(e.message)
		streamClosed()
	})
	return req
}

export const commandInputHelper = function(e, actions, currentCommand, showCommandOverview, newid) {
	//These commands need a password prompt or other special handling.
	const specialCommands = [ ['wallet', 'load', 'seed'], ['wallet', 'unlock'], ['help'], ['?'] ]

	const eventTarget = e.target
	//Enter button.
	if (e.keyCode === 13) {

		//Check if command is special.
		switch ( commandType(currentCommand, specialCommands) ) {
		case constants.REGULAR_COMMAND: //Regular command.
			spawnCommand(currentCommand, actions, newid) //Spawn command defined in index.js.
			break

		case constants.WALLET_UNLOCK: //wallet unlock
		case constants.WALLET_SEED: //wallet load seed
			actions.showWalletPrompt()
			break

		case constants.HELP: //help
			const text = 'help'
		case constants.HELP_QMARK: //?
			const newText = text || '?'
			if (showCommandOverview) {
				actions.hideCommandOverview()
			} else {
				actions.showCommandOverview()
			}

			//The command log won't actually show a help command but we still want to be able to select it in the command history.
			const newCommand = Map({ command: newText, result: '', id: newid })
			actions.addCommand(newCommand)
			actions.endCommand(newCommand.get('command'), newCommand.get('id'))
			break

		default:
			break
		}
	 } else if (e.keyCode === 38) {
		//Up arrow.
		actions.loadPrevCommand(eventTarget.value)
		setTimeout( () => {
			eventTarget.setSelectionRange(eventTarget.value.length, eventTarget.value.length)
		}, 0)
	} else if (e.keyCode === 40) {
		//Down arrow.
		actions.loadNextCommand(eventTarget.value)
		setTimeout(() => {
			eventTarget.setSelectionRange(eventTarget.value.length, eventTarget.value.length)
		}, 0)
	}
}
<|endoftext|>


<commit_before>exports.names = ['.blacklist'];
exports.hidden = true;
exports.enabled = true;
exports.matchStart = false;
exports.handler = function (data) {
    if (data.from.role > 1) {

        media = bot.getMedia();

        logger.warning('[BLACKLIST] ' + data.from.username + ' blacklisted ' + media.title);

        var userData = {
            type: 'blacklist',
            details: 'Blacklisted ' + media.title + ' CID ' + media.id + ' by ' + data.from.username,
            user_id: bot.getDJ().id,
            mod_user_id: data.from.id
        };
        Karma.create(userData);

        Song.update({is_banned: 1}, {where: {id: media.id}});
        bot.sendChat("The song " + media.title + " has been blacklisted.");

        bot.moderateForceSkip();
        //bot.moderateDeleteChat(data.id);
    }
};

<commit_msg>Update blacklist.js<commit_after>exports.names = ['!blacklist'];
exports.hidden = true;
exports.enabled = true;
exports.matchStart = false;
exports.handler = function (data) {
    if (data.from.role > 1) {

        media = bot.getMedia();

        logger.warning('[BLACKLIST] ' + data.from.username + ' blacklisted ' + media.title);

        var userData = {
            type: 'blacklist',
            details: 'Blacklisted ' + media.title + ' CID ' + media.id + ' by ' + data.from.username,
            user_id: bot.getDJ().id,
            mod_user_id: data.from.id
        };
        Karma.create(userData);

        Song.update({is_banned: 1}, {where: {id: media.id}});
        bot.sendChat("The song " + media.title + " has been blacklisted.");

        bot.moderateForceSkip();
        //bot.moderateDeleteChat(data.id);
    }
};

<|endoftext|>


<commit_before>var fs = require('fs');
var url = require('url');
var path = require('path');
var request = require('request');
var crypto = require('crypto');

command = Bones.Command.extend();

command.description = 'export project';
command.usage = '<project> <export>';

command.options['format'] = {
    'title': 'format=[format]',
    'description': 'Export format (png|pdf|svg|mbtiles).'
};

command.options['bbox'] = {
    'title': 'bbox=[bbox]',
    'description': 'Comma separated coordinates of bounding box to export.'
};

command.options['minzoom'] = {
    'title': 'minzoom=[zoom]',
    'description': 'MBTiles: minimum zoom level to export.'
};

command.options['maxzoom'] = {
    'title': 'maxzoom=[zoom]',
    'description': 'MBTiles: maximum zoom level to export.'
};

command.options['width'] = {
    'title': 'width=[width]',
    'description': 'Image: image width in pixels.',
    'default': 400
};

command.options['height'] = {
    'title': 'height=[height]',
    'description': 'Image: image height in pixels.',
    'default': 400
};

command.options['url'] = {
    'title': 'url=[url]',
    'description': 'URL to PUT updates to.'
};

command.options['log'] = {
    'title': 'log',
    'description': 'Write crash logs to destination directory.'
};

command.prototype.initialize = function(plugin, callback) {
    var opts = plugin.config;
    if (process.env.tilemillConfig)
        _(opts).extend(JSON.parse(process.env.tilemillConfig));
    opts.files = path.resolve(opts.files);
    opts.project = plugin.argv._[1];
    opts.filepath = path.resolve(plugin.argv._[2]);
    callback = callback || function() {};
    this.opts = opts;

    // Write crash log
    if (opts.log) {
        process.on('uncaughtException', function(err) {
            fs.writeFileSync(opts.filepath + '.crashlog', err.stack || err.toString());
            process.exit(1);
        });
    }

    // Validation.
    if (!opts.project || !opts.filepath) return plugin.help();
    if (!path.existsSync(path.dirname(opts.filepath)))
        return this.error(new Error('Export path does not exist: ' + path.dirname(opts.filepath)));

    // Format.
    if (!opts.format) opts.format = path.extname(opts.filepath).split('.').pop();
    if (!_(['pdf', 'svg', 'png', 'mbtiles', 'upload']).include(opts.format))
        return this.error(new Error('Invalid format: ' + opts.format));

    // Convert string params into numbers.
    if (!_(opts.bbox).isUndefined())
        opts.bbox = _(opts.bbox.split(',')).map(parseFloat);
    if (!_(opts.minzoom).isUndefined())
        opts.minzoom = parseInt(opts.minzoom, 10);
    if (!_(opts.maxzoom).isUndefined())
        opts.maxzoom = parseInt(opts.maxzoom, 10);
    if (!_(opts.width).isUndefined())
        opts.width = parseInt(opts.width, 10);
    if (!_(opts.height).isUndefined())
        opts.height = parseInt(opts.height, 10);

    // Rename the output filepath using a random hash if file already exists.
    if (path.existsSync(opts.filepath) && opts.format !== 'upload') {
        var hash = crypto.createHash('md5')
            .update(+new Date + '')
            .digest('hex')
            .substring(0, 6);
        var ext = path.extname(opts.filepath);
        opts.filepath = opts.filepath.replace(ext, '_' + hash + ext);

        // Update filename in TileMill.
        this.put({ filename: path.basename(opts.filepath), status: 'processing' });
    }

    // Set process title.
    process.title = 'tm-' + path.basename(opts.filepath);

    // Catch SIGINT.
    process.on('SIGINT', function () {
        console.log('Got SIGINT. Run "kill ' + process.pid + '" to terminate.');
    });
    process.on('SIGUSR1', process.exit);

    // Load project, localize and call export function.
    (new models.Project({id: plugin.argv._[1] })).fetch({
        success: function(model, resp) {
            model.localize(resp, function(err) {
                if (err) return this.error(err);
                model.mml = _(model.mml).extend({
                    name: model.mml.name || model.id,
                    version: model.mml.version || '1.0.0',
                    minzoom: !_(opts.minzoom).isUndefined() ? opts.minzoom : model.get('minzoom'),
                    maxzoom: !_(opts.maxzoom).isUndefined() ? opts.maxzoom : model.get('maxzoom'),
                    bounds: !_(opts.bbox).isUndefined() ? opts.bbox : model.get('bounds')
                });

                // Unset map center for now given that it may be outside
                // overridden bounds provided.
                if (model.mml.center) delete model.mml.center;

                this[opts.format](model, callback);
            }.bind(this));
        }.bind(this),
        error: function(model, resp) {
            this.error(resp);
        }.bind(this)
    });
};

command.prototype.error = function(err) {
    this.put({
        status: 'error',
        error: err.toString(),
        updated: +new Date()
    });
    console.error(err.toString());
};

command.prototype.put = function(data, callback) {
    callback = callback || function() {};
    if (!this.opts.url) return callback();
    request.put({
        uri: this.opts.url,
        headers: {
            'Host': url.parse(this.opts.url).host,
            'Cookie': 'bones.token=token'
        },
        json: _(data).extend({'bones.token': 'token'})
    }, callback);
};

command.prototype.png =
command.prototype.svg =
command.prototype.pdf = function(project, callback) {
    var mapnik = require('mapnik');
    var sm = new (require('sphericalmercator'))();
    var map = new mapnik.Map(this.opts.width, this.opts.height);

    map.fromStringSync(project.xml, {
        strict: false,
        base: path.join(this.opts.files, 'project', project.id) + '/'
    });
    map.bufferSize = this.opts.bufferSize;
    map.extent = sm.convert(project.mml.bounds, '900913');
    try {
        map.renderFileSync(this.opts.filepath, { format: this.opts.format });
        this.put({
            status: 'complete',
            progress: 1,
            updated: +new Date()
        }, process.exit);
    } catch(err) {
        this.error(err);
    }
};

command.prototype.mbtiles = function (project, callback) {
    var tilelive = require('tilelive');
    require('mbtiles').registerProtocols(tilelive);
    require('tilelive-mapnik').registerProtocols(tilelive);

    var uri = {
        protocol: 'mapnik:',
        slashes: true,
        xml: project.xml,
        mml: project.mml,
        pathname: path.join(this.opts.files, 'project', project.id, project.id + '.xml'),
        query: { bufferSize: this.opts.bufferSize }
    };
    tilelive.load(uri, function(err, source) {
        if (err) throw err;
        tilelive.load('mbtiles://' + this.opts.filepath, function(err, sink) {
            if (err) throw err;
            sink.startWriting(function(err) {
                if (err) throw err;
                sink.putInfo(project.mml, function(err) {
                    if (err) throw err;
                    var copy = tilelive.copy({
                        source: source,
                        sink: sink,
                        bbox: project.mml.bounds,
                        minZoom: project.mml.minzoom,
                        maxZoom: project.mml.maxzoom,
                        concurrency: 100,
                        tiles: true,
                        grids: !!project.mml.interactivity
                    });

                    var timeout = setInterval(function progress() {
                        var progress = (copy.copied + copy.failed) / copy.total;
                        var remaining = Math.floor((Date.now() - copy.started) * (1 / progress));
                        this.put({
                            status: progress < 1 ? 'processing' : 'complete',
                            progress: progress,
                            remaining: remaining,
                            updated: +new Date(),
                        });
                    }.bind(this), 5000);
                    copy.on('warning', function(err) {
                        console.log(err);
                    }.bind(this));
                    copy.on('finished', function() {
                        clearTimeout(timeout);
                        this.put({
                            status: 'complete',
                            progress: 1,
                            updated: +new Date()
                        }, process.exit);
                    }.bind(this));
                    copy.on('error', function(err) {
                        clearTimeout(timeout);
                        this.error(err);
                    }.bind(this));
                }.bind(this));
            }.bind(this));
        }.bind(this));
    }.bind(this));
};

command.prototype.upload = function (project, callback) {
    var hash = crypto.createHash('md5')
        .update(+new Date + '')
        .digest('hex')
        .substring(0, 6);
    var policyEndpoint = url.format({
        protocol: 'http:',
        host: this.opts.mapboxHost || 'tiles.mapbox.com',
        pathname: '/v2/'+ hash + '/upload.json'
    });

    request.get({
        uri: policyEndpoint,
        headers: {
            'Host': url.parse(policyEndpoint).host,
        }
    }, _(function(err, resp, body) {
        if (err) return this.error(err);
        if (resp.statusCode !== 200) return this.error(
            new Error('MapBox Hosting is not available. Status '
                      + resp.statusCode + '.'));

        try {
            var uploadArgs = JSON.parse(body);
        } catch (e) {
            this.error(new Error('Failed to parse policy from MapBox Hosting.'));
        }

        var options = {
            uri: 'http://' + uploadArgs.bucket + '.s3.amazonaws.com/',
            headers: { 'X_FILE_NAME': path.basename(this.opts.filepath) },
            multipart: []
        };

        // Remove keys used for UI purposes in frameup but not sent to S3.
        delete uploadArgs.bucket;
        delete uploadArgs.filename;

        _(uploadArgs).each(function(arg, key) {
            options.multipart.push({
                'content-disposition': 'form-data; name="' + key + '"',
                'body': arg
            });
        });

        // Add the file using base64 to work around request stringifying everything.
        options.multipart.push({
            'content-disposition': 'form-data; name="file"; filename="' +
                path.basename(this.opts.filepath) + '"',
            'content-type': 'application/octet-stream',
            'body': fs.readFileSync(this.opts.filepath)
        });

        request.post(options, _(function(err, resp, body) {
            if (err) return this.error(err);
            if (resp.statusCode !== 303) return this.error(
                new Error('Upload to MapBox Hosting failed with status ' +
                          resp.statusCode + '.'));

            this.put({
                status: 'complete',
                progress: 1,
                url: resp.headers.location.split('?')[0],
                updated: +new Date()
            }, process.exit);

        }).bind(this));
    }).bind(this));
};
<commit_msg>Unfinished streaming file uploads.<commit_after>var fs = require('fs');
var url = require('url');
var path = require('path');
var request = require('request');
var crypto = require('crypto');

command = Bones.Command.extend();

command.description = 'export project';
command.usage = '<project> <export>';

command.options['format'] = {
    'title': 'format=[format]',
    'description': 'Export format (png|pdf|svg|mbtiles).'
};

command.options['bbox'] = {
    'title': 'bbox=[bbox]',
    'description': 'Comma separated coordinates of bounding box to export.'
};

command.options['minzoom'] = {
    'title': 'minzoom=[zoom]',
    'description': 'MBTiles: minimum zoom level to export.'
};

command.options['maxzoom'] = {
    'title': 'maxzoom=[zoom]',
    'description': 'MBTiles: maximum zoom level to export.'
};

command.options['width'] = {
    'title': 'width=[width]',
    'description': 'Image: image width in pixels.',
    'default': 400
};

command.options['height'] = {
    'title': 'height=[height]',
    'description': 'Image: image height in pixels.',
    'default': 400
};

command.options['url'] = {
    'title': 'url=[url]',
    'description': 'URL to PUT updates to.'
};

command.options['log'] = {
    'title': 'log',
    'description': 'Write crash logs to destination directory.'
};

command.prototype.initialize = function(plugin, callback) {
    var opts = plugin.config;
    if (process.env.tilemillConfig)
        _(opts).extend(JSON.parse(process.env.tilemillConfig));
    opts.files = path.resolve(opts.files);
    opts.project = plugin.argv._[1];
    opts.filepath = path.resolve(plugin.argv._[2]);
    callback = callback || function() {};
    this.opts = opts;

    // Write crash log
    if (opts.log) {
        process.on('uncaughtException', function(err) {
            fs.writeFileSync(opts.filepath + '.crashlog', err.stack || err.toString());
            process.exit(1);
        });
    }

    // Validation.
    if (!opts.project || !opts.filepath) return plugin.help();
    if (!path.existsSync(path.dirname(opts.filepath)))
        return this.error(new Error('Export path does not exist: ' + path.dirname(opts.filepath)));

    // Format.
    if (!opts.format) opts.format = path.extname(opts.filepath).split('.').pop();
    if (!_(['pdf', 'svg', 'png', 'mbtiles', 'upload']).include(opts.format))
        return this.error(new Error('Invalid format: ' + opts.format));

    // Convert string params into numbers.
    if (!_(opts.bbox).isUndefined())
        opts.bbox = _(opts.bbox.split(',')).map(parseFloat);
    if (!_(opts.minzoom).isUndefined())
        opts.minzoom = parseInt(opts.minzoom, 10);
    if (!_(opts.maxzoom).isUndefined())
        opts.maxzoom = parseInt(opts.maxzoom, 10);
    if (!_(opts.width).isUndefined())
        opts.width = parseInt(opts.width, 10);
    if (!_(opts.height).isUndefined())
        opts.height = parseInt(opts.height, 10);

    // Rename the output filepath using a random hash if file already exists.
    if (path.existsSync(opts.filepath) && opts.format !== 'upload') {
        var hash = crypto.createHash('md5')
            .update(+new Date + '')
            .digest('hex')
            .substring(0, 6);
        var ext = path.extname(opts.filepath);
        opts.filepath = opts.filepath.replace(ext, '_' + hash + ext);

        // Update filename in TileMill.
        this.put({ filename: path.basename(opts.filepath), status: 'processing' });
    }

    // Set process title.
    process.title = 'tm-' + path.basename(opts.filepath);

    // Catch SIGINT.
    process.on('SIGINT', function () {
        console.log('Got SIGINT. Run "kill ' + process.pid + '" to terminate.');
    });
    process.on('SIGUSR1', process.exit);

    // Load project, localize and call export function.
    (new models.Project({id: plugin.argv._[1] })).fetch({
        success: function(model, resp) {
            model.localize(resp, function(err) {
                if (err) return this.error(err);
                model.mml = _(model.mml).extend({
                    name: model.mml.name || model.id,
                    version: model.mml.version || '1.0.0',
                    minzoom: !_(opts.minzoom).isUndefined() ? opts.minzoom : model.get('minzoom'),
                    maxzoom: !_(opts.maxzoom).isUndefined() ? opts.maxzoom : model.get('maxzoom'),
                    bounds: !_(opts.bbox).isUndefined() ? opts.bbox : model.get('bounds')
                });

                // Unset map center for now given that it may be outside
                // overridden bounds provided.
                if (model.mml.center) delete model.mml.center;

                this[opts.format](model, callback);
            }.bind(this));
        }.bind(this),
        error: function(model, resp) {
            this.error(resp);
        }.bind(this)
    });
};

command.prototype.error = function(err) {
    this.put({
        status: 'error',
        error: err.toString(),
        updated: +new Date()
    });
    console.error(err.toString());
};

command.prototype.put = function(data, callback) {
    callback = callback || function() {};
    if (!this.opts.url) return callback();
    request.put({
        uri: this.opts.url,
        headers: {
            'Host': url.parse(this.opts.url).host,
            'Cookie': 'bones.token=token'
        },
        json: _(data).extend({'bones.token': 'token'})
    }, callback);
};

command.prototype.png =
command.prototype.svg =
command.prototype.pdf = function(project, callback) {
    var mapnik = require('mapnik');
    var sm = new (require('sphericalmercator'))();
    var map = new mapnik.Map(this.opts.width, this.opts.height);

    map.fromStringSync(project.xml, {
        strict: false,
        base: path.join(this.opts.files, 'project', project.id) + '/'
    });
    map.bufferSize = this.opts.bufferSize;
    map.extent = sm.convert(project.mml.bounds, '900913');
    try {
        map.renderFileSync(this.opts.filepath, { format: this.opts.format });
        this.put({
            status: 'complete',
            progress: 1,
            updated: +new Date()
        }, process.exit);
    } catch(err) {
        this.error(err);
    }
};

command.prototype.mbtiles = function (project, callback) {
    var tilelive = require('tilelive');
    require('mbtiles').registerProtocols(tilelive);
    require('tilelive-mapnik').registerProtocols(tilelive);

    var uri = {
        protocol: 'mapnik:',
        slashes: true,
        xml: project.xml,
        mml: project.mml,
        pathname: path.join(this.opts.files, 'project', project.id, project.id + '.xml'),
        query: { bufferSize: this.opts.bufferSize }
    };
    tilelive.load(uri, function(err, source) {
        if (err) throw err;
        tilelive.load('mbtiles://' + this.opts.filepath, function(err, sink) {
            if (err) throw err;
            sink.startWriting(function(err) {
                if (err) throw err;
                sink.putInfo(project.mml, function(err) {
                    if (err) throw err;
                    var copy = tilelive.copy({
                        source: source,
                        sink: sink,
                        bbox: project.mml.bounds,
                        minZoom: project.mml.minzoom,
                        maxZoom: project.mml.maxzoom,
                        concurrency: 100,
                        tiles: true,
                        grids: !!project.mml.interactivity
                    });

                    var timeout = setInterval(function progress() {
                        var progress = (copy.copied + copy.failed) / copy.total;
                        var remaining = Math.floor((Date.now() - copy.started) * (1 / progress));
                        this.put({
                            status: progress < 1 ? 'processing' : 'complete',
                            progress: progress,
                            remaining: remaining,
                            updated: +new Date(),
                        });
                    }.bind(this), 5000);
                    copy.on('warning', function(err) {
                        console.log(err);
                    }.bind(this));
                    copy.on('finished', function() {
                        clearTimeout(timeout);
                        this.put({
                            status: 'complete',
                            progress: 1,
                            updated: +new Date()
                        }, process.exit);
                    }.bind(this));
                    copy.on('error', function(err) {
                        clearTimeout(timeout);
                        this.error(err);
                    }.bind(this));
                }.bind(this));
            }.bind(this));
        }.bind(this));
    }.bind(this));
};

command.prototype.upload = function (project, callback) {
    var hash = crypto.createHash('md5')
        .update(+new Date + '')
        .digest('hex')
        .substring(0, 6);
    var policyEndpoint = url.format({
        protocol: 'http:',
        host: this.opts.mapboxHost || 'tiles.mapbox.com',
        pathname: '/v2/'+ hash + '/upload.json'
    });

    request.get({
        uri: policyEndpoint,
        headers: {
            'Host': url.parse(policyEndpoint).host,
        }
    }, _(function(err, resp, body) {
        if (err) return this.error(err);
        if (resp.statusCode !== 200) return this.error(
            new Error('MapBox Hosting is not available. Status '
                      + resp.statusCode + '.'));

        try {
            var uploadArgs = JSON.parse(body);
        } catch (e) {
            this.error(new Error('Failed to parse policy from MapBox Hosting.'));
        }

        var tmpPath = '/tmp/' + path.basename(this.opts.filepath) + '.post';
        var dest = fs.createWriteStream(tmpPath);

        var body = '--frontier\r\n';
        body += 'Content-Disposition: form-data; name="file"; filename="gdp.mbtiles"\r\n'
        body += 'Content-Type: application/octet-stream\r\n\r\n';
        dest.write(body, 'ascii');

        var source = fs.createReadStream(this.opts.filepath);
        source.on('end', function() {
            dest.end('\r\n--frontier--', 'ascii');
        });
        source.pipe(dest, {end: false});

        var options = {
            uri: 'http://localhost:3000/',
            host: 'localhost',
            port: '3000',
            path: '/',
            method:'POST',
            headers: {
                'Content-Type': 'multipart/form-data; boundary=frontier',
            }
        };

        dest.on('close', function() {
            // File has been closed. Time to upload.
            var source = fs.createReadStream(tmpPath);
            var dest = request.post(options);
            source.pipe(dest);
            console.log('uploading');
        });

    }).bind(this));
};
<|endoftext|>


<commit_before>const matchinfo = require("./matchinfo");
const resolve_dota_id = require("../util/resolve_dota_id");

function send_message(message, client, helper, acc_id) {

}

module.exports = (message, client, helper) => {
    message.channel.sendTyping().then(() => {
        let check = message.content.split(" ")[1];
        if (check && check == "with") {
            let queries = [resolve_dota_id(message, message.author.id)];
            for (ping in message.mentions) {
                queries.push(resolve_dota_id(message, message.mentions[ping].id));
            }

            Promise.all(queries).then(results => {
                helper.log(message, `lastmatch: ${results.join(", ")}`);
                client.mika.getPlayerMatches(results[0], {
                    "limit": 1,
                    "included_account_id": results.slice(1)
                }).then(match => {
                    if (match) {
                        let match_id = match[0].match_id;
                        message.content = `matchinfo ${match_id}`;
                        matchinfo(message, client, helper);
                    }
                }).catch(err => {
                    helper.log(message, err);
                    message.channel.createMessage("Something went wrong.");
                });
            }).catch(err => {
                if (err.err) {
                    message.channel.createMessage(err.text);
                    helper.log(message, err.text);
                    helper.log(message, err.err);
                } else {
                    message.channel.createMessage(err.text);
                }
            })
        } else {
            resolve_dota_id(message).then(acc_id => {
                helper.log(message, `lastmatch: ${acc_id}`);

                client.redis.get(`lastmatch:${acc_id}`, (err, res) => {
                    if (err) helper.log(message, err);
                    if (res) {
                        message.content = `matchinfo ${res}`;
                        matchinfo(message, client, helper);
                    } else {
                        client.mika.getPlayerMatches(acc_id, {
                            "limit": "1"
                        }).then(match => {
                            if (match) {
                                let match_id = match[0].match_id;
                                message.content = `matchinfo ${match_id}`;
                                matchinfo(message, client, helper);
                                client.redis.set(`lastmatch:${acc_id}`, match_id, (err) => {
                                    if (err) helper.log(err);
                                    client.redis.expire(`lastmatch:${acc_id}`, 1800);
                                });
                            } else {
                                message.channel.createMessage("Couldn't find this player on Opendota!");
                            }
                        });
                    }
                });
            }).catch(err => {
                console.log(err)
                if (err.err) {
                    message.channel.createMessage(err.text);
                    helper.log(message, err.text);
                    helper.log(message, err.err);
                } else if (err) {
                    message.channel.createMessage(err);
                } else {
                    message.channel.createMessage("Something went wrong.");
                }
            });
        }
    });
};
<commit_msg>better error handling?<commit_after>const matchinfo = require("./matchinfo");
const resolve_dota_id = require("../util/resolve_dota_id");

function send_message(message, client, helper, acc_id) {

}

module.exports = (message, client, helper) => {
    message.channel.sendTyping().then(() => {
        let check = message.content.split(" ")[1];
        if (check && check == "with") {
            let queries = [resolve_dota_id(message, message.author.id)];
            for (ping in message.mentions) {
                queries.push(resolve_dota_id(message, message.mentions[ping].id));
            }

            Promise.all(queries).then(results => {
                helper.log(message, `lastmatch: ${results.join(", ")}`);
                client.mika.getPlayerMatches(results[0], {
                    "limit": 1,
                    "included_account_id": results.slice(1)
                }).then(match => {
                    if (match) {
                        let match_id = match[0].match_id;
                        message.content = `matchinfo ${match_id}`;
                        matchinfo(message, client, helper);
                    }
                }).catch(err => {
                    helper.log(message, err);
                    message.channel.createMessage("Something went wrong.");
                });
            }).catch(err => {
                if (err.err) {
                    message.channel.createMessage(err.text);
                    helper.log(message, err.text);
                    helper.log(message, err.err);
                } else {
                    message.channel.createMessage(err.text);
                }
            })
        } else {
            resolve_dota_id(message).then(acc_id => {
                helper.log(message, `lastmatch: ${acc_id}`);

                client.redis.get(`lastmatch:${acc_id}`, (err, res) => {
                    if (err) helper.log(message, err);
                    if (res) {
                        message.content = `matchinfo ${res}`;
                        matchinfo(message, client, helper);
                    } else {
                        client.mika.getPlayerMatches(acc_id, {
                            "limit": "1"
                        }).then(match => {
                            if (match) {
                                let match_id = match[0].match_id;
                                message.content = `matchinfo ${match_id}`;
                                matchinfo(message, client, helper);
                                client.redis.set(`lastmatch:${acc_id}`, match_id, (err) => {
                                    if (err) helper.log(err);
                                    client.redis.expire(`lastmatch:${acc_id}`, 1800);
                                });
                            } else {
                                message.channel.createMessage("Couldn't find this player on Opendota!");
                            }
                        });
                    }
                });
            }).catch(err => {
                console.log(err)
                if (err.err) {
                    message.channel.createMessage(err.text);
                    helper.log(message, err.text);
                    helper.log(message, err.err);
                } else if (err.text) {
                    message.channel.createMessage(err.text);
                    helper.log(message, err.text);
                } else {
                    message.channel.createMessage("Something went wrong.");
                    helper.log(message, err);
                }
            });
        }
    });
};
<|endoftext|>


<commit_before>'use strict';
const Feats = require('../src/feats').Feats;
const meetsPrerequisites = require('../src/feats').meetsPrerequisites;
const util = require('util');

exports.command = (rooms, items, players, npcs, Commands) => {
  return (args, player) => {
    const playerFeats = player.getFeats() || {};

    let ownFeats = [];
    let availableFeats = [];

    for (let feat in Feats) {
      const available = meetsPrerequisites(player, Feats[feat]);
      const owned = Feats[feat].name in playerFeats;

      if (available && !owned) { availableFeats.push(Feats[feat]); }
      if (owned) { ownFeats.push(Feats[feat]); }
    }

    if (!availableFeats.length && !ownFeats.length) {
      player.say('You are perfectly normal.');
      return;
    }

    player.say('')

    if (ownFeats.length) {
      player.say('<bold>Your mutations:</bold>');
      player.say('')
      ownFeats.forEach(feat => {
        player.say('<cyan>' + feat.name + '</cyan>');
        player.say('<yellow>' + feat.description + '</yellow>');
        player.say('');
      });
    }

    if (availableFeats.length) {
      player.say('<bold><red>Potential mutations:</red></bold>');
      player.say('')
      ownFeats.forEach(feat => {
        player.say('<magenta><bold>   ' + feat.name + '</bold></magenta>');
        player.say('<yellow>' + feat.description + '</yellow>');
        player.say('<yellow>Type: ' + feat.type.toUpperCase() + '</yellow>');
        player.say('');
      });
    }

  };
};
<commit_msg>Cleanup and fix mutations bug - only showed own feats.<commit_after>'use strict';
const Feats = require('../src/feats').Feats;
const meetsPrerequisites = require('../src/feats').meetsPrerequisites;
const util = require('util');

exports.command = (rooms, items, players, npcs, Commands) => {
  return (args, player) => {
    const playerFeats = player.getFeats() || {};

    let ownFeats = [];
    let availableFeats = [];

    for (let feat in Feats) {
      const available = meetsPrerequisites(player, Feats[feat]);
      const owned = Feats[feat].name in playerFeats;
      util.log(feat);
      util.log(owned);
      util.log(available);

      if (owned) { ownFeats.push(Feats[feat]); }
      else if (available) { availableFeats.push(Feats[feat]); }
    }

    if (!availableFeats.length && !ownFeats.length) {
      player.say('You are perfectly normal.');
      return;
    }

    player.say('')

    if (ownFeats.length) {
      player.say('<bold>Your mutations:</bold>');
      player.say('')
      ownFeats.forEach(feat => {
        player.say('<cyan>' + feat.name + '</cyan>');
        player.say('<yellow>' + feat.description + '</yellow>');
        player.say('');
      });
    }

    if (availableFeats.length) {
      player.say('<bold><red>Potential mutations:</red></bold>');
      player.say('')
      availableFeats.forEach(feat => {
        player.say('<magenta><bold>   ' + feat.name + '</bold></magenta>');
        player.say('<yellow>' + feat.description + '</yellow>');
        player.say('<yellow>Type: ' + feat.type.toUpperCase() + '</yellow>');
        player.say('');
      });
    }

  };
};
<|endoftext|>


<commit_before>import BulkMessage from 'telegram-api/types/BulkMessage';
import Message from 'telegram-api/types/Message';

import FeedParser from 'feedparser';
import request from 'request';

import {read, write} from '../utils/files';

export default function subscribe(bot) {
  const users = read('users');
  const feeds = read('feeds');
  let {time} = read('time');

  time = new Date(time);

  const refresh = () => {
    return new Promise((resolve, reject) => {
      for (let feed of feeds) {
        const req = request(feed.url);
        req.setHeader('user-agent', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10)');
        req.setHeader('accept', 'text/html,application/xhtml+xml');

        const parser = new FeedParser();

        req.on('response', res => res.pipe(parser));
        req.on('error', reject);

        let posts = [];

        parser.on('data', function listener(post) {
          const date = new Date(post.date);

          console.log(post.title);
          if (date < time) {
            parser.removeListener('data', listener);

            time = new Date();
            write('time', {time});

            resolve(posts);
            return;
          }
          posts.push(post);
        });

        parser.on('error', reject);
      }
    });
  };

  const cb = function(posts) {
    for (let post of posts) {
      const msg = new BulkMessage().text(post.title + '\n' + post.link)
                                   .to(users);
      bot.send(msg);
    }
  };

  refresh().then(cb);
  setInterval(refresh.bind(null, cb), 1000 * 60 * 5);

  const success = new Message().text('You\'ve been successfuly subscribed!');
  const duplicate = new Message().text('You are already subscribed!');
  bot.command('subscribe', message => {
    if (users.indexOf(message.chat.id) > -1) {
      bot.send(duplicate.to(message.chat.id));
      return;
    }

    users.push(message.chat.id);
    write('users', users);

    bot.send(success.to(message.chat.id));
  });

  const no = new Message().text('You are not subscribed at all!');
  const unsubscribed = new Message().text('You\'ve been unsubscribed.');
  bot.command('unsubscribe', message => {
    const index = users.indexOf(message.chat.id);
    if (index === -1) {
      bot.send(no.to(message.chat.id));
    } else {
      users.splice(index, 1);
      write('users', users);
      bot.send(unsubscribed.to(message.chat.id));
    }
  });
}
<commit_msg>Move log<commit_after>import BulkMessage from 'telegram-api/types/BulkMessage';
import Message from 'telegram-api/types/Message';

import FeedParser from 'feedparser';
import request from 'request';

import {read, write} from '../utils/files';

export default function subscribe(bot) {
  const users = read('users');
  const feeds = read('feeds');
  let {time} = read('time');

  time = new Date(time);

  const refresh = () => {
    return new Promise((resolve, reject) => {
      for (let feed of feeds) {
        const req = request(feed.url);
        req.setHeader('user-agent', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10)');
        req.setHeader('accept', 'text/html,application/xhtml+xml');

        const parser = new FeedParser();

        req.on('response', res => res.pipe(parser));
        req.on('error', reject);

        let posts = [];

        parser.on('data', function listener(post) {
          const date = new Date(post.date);

          if (date < time) {
            parser.removeListener('data', listener);

            time = new Date();
            write('time', {time});

            resolve(posts);
            return;
          }
          console.log(post.title);
          posts.push(post);
        });

        parser.on('error', reject);
      }
    });
  };

  const cb = function(posts) {
    for (let post of posts) {
      const msg = new BulkMessage().text(post.title + '\n' + post.link)
                                   .to(users);
      bot.send(msg);
    }
  };

  refresh().then(cb);
  setInterval(refresh.bind(null, cb), 1000 * 60 * 5);

  const success = new Message().text('You\'ve been successfuly subscribed!');
  const duplicate = new Message().text('You are already subscribed!');
  bot.command('subscribe', message => {
    if (users.indexOf(message.chat.id) > -1) {
      bot.send(duplicate.to(message.chat.id));
      return;
    }

    users.push(message.chat.id);
    write('users', users);

    bot.send(success.to(message.chat.id));
  });

  const no = new Message().text('You are not subscribed at all!');
  const unsubscribed = new Message().text('You\'ve been unsubscribed.');
  bot.command('unsubscribe', message => {
    const index = users.indexOf(message.chat.id);
    if (index === -1) {
      bot.send(no.to(message.chat.id));
    } else {
      users.splice(index, 1);
      write('users', users);
      bot.send(unsubscribed.to(message.chat.id));
    }
  });
}
<|endoftext|>


<commit_before>/* Use The Force, Grapher
    - Renders your current search result set as a force directed graph
    - Built using D3
*/

// Change Navigation
$('#btn-display-graph').addClass('navigation-on');
$('#btn-display-list').removeClass('navigation-on');

// Show & Hide Pile View
$('#pile-results').hide('fast', function() {
    $('#form-pile-results').hide('fast');
    //$('.pile-speed').hide('fast');
    //$('#footer').hide('fast');
    //$('#sidebar').hide('fast');
    $('#pile-graph').hide().delay(1000).show();
});

// Determine & Set Height
var available_height = $(window).height() - ($('#header').height() + $('.sub-navigation').height());
var available_width = $("#content-view").width();

$('#pile-graph-canvas').height(available_height);
$('#pile-graph-canvas').width(available_width);
$("#pile-graph-canvas-svg").attr('height', available_height).height(available_height);

return {
    draw: function(graph) {
        var width = available_width;
        var height = available_height;
        var force = d3.layout.force()
                    .charge(-300)
                    .linkDistance(100)
                    .gravity(0.02)
                    .size([width, height]);

        var svg = d3.select("#pile-graph-canvas-svg");
        $("#pile-graph-canvas-svg").empty();

        var color = d3.scale.category20();

        var tooltip = d3.select("body")
            .append("div")
            .style("position", "absolute")
            .style("z-index", "10")
            .style("visibility", "hidden")
            .text("a simple tooltip");

        force
            .nodes(graph.nodes)
            .links(graph.links)
            .start();

        var link = svg.selectAll(".link")
            .data(graph.links)
            .enter().append("line")
            .style("stroke", "#000")
            .style("stroke-width", function(d) { return Math.sqrt(3*d.value); });

        var node = svg.selectAll(".node")
              .data(graph.nodes)
              .enter().append("g")
              .attr("class", "node")
              .call(force.drag);

        node.append("circle")
            .attr("r", 8)
            .style("fill", function(d) { return color("#3a6b8c"); })

        node.append("text")
            .attr("x", 12)
            .attr("dy", "0.35em")
            .style("opacity", "0.3")
            .text(function(d) { return d.email; });

        link.append("text").attr("x", 12).attr("dy", ".35em").text(function(d) { return d.type; })

        node.on("click", function(d, m, q) {
            // d.attr("toggled", !d.attr("toggled"));
            // d.style("color", "#f00");
            if (mailpile.graphselected.indexOf(d["email"]) < 0) {
                d3.select(node[q][m]).selectAll("circle").style("fill", "#4b7945");
                mailpile.graphselected.push(d["email"]);
            } else {
                mailpile.graphselected.pop(d["email"]);
                d3.select(node[q][m]).selectAll("circle").style("fill", "#3a6b8c");
            }
            mailpile.graph_actionbuttons();
        });
        node.on("mouseover", function(d, m, q) {
            d3.select(node[q][m]).selectAll("text").style("opacity", "1");
        });
        node.on("mouseout", function(d, m, q) {
            d3.select(node[q][m]).selectAll("text").style("opacity", "0.2");
        });

        force.on("tick", function() {
            node.attr("transform", function(d) {
                if (d.x < 0) { d.x = 0; }
                if (d.y < 0) { d.y = 0; }
                if (d.x > width) { d.x = width; }
                if (d.y > height) { d.y = height; }
                return "translate(" + d.x + "," + d.y + ")";
            });
            link.attr("x1", function(d) { return d.source.x; })
                .attr("y1", function(d) { return d.source.y; })
                .attr("x2", function(d) { return d.target.x; })
                .attr("y2", function(d) { return d.target.y; });
        });
    }
}
<commit_msg>Forcegrapher working more nicely (#547)<commit_after>/* Use The Force, Grapher
    - Renders your current search result set as a force directed graph
    - Built using D3
*/

return {
    draw: function(graph) {
        // Determine & Set Height
        var available_height = $(window).height() - ($('#header').height() + $('.sub-navigation').height());
        var available_width = $("#content-view").width();

        $('#pile-graph-canvas').height(available_height);
        $('#pile-graph-canvas').width(available_width);
        $("#pile-graph-canvas-svg").attr('height', available_height).height(available_height);

        var width = available_width;
        var height = available_height;
        var force = d3.layout.force()
                    .charge(-300)
                    .linkDistance(100)
                    .size([width, height]);

        var svg = d3.select("#pile-graph-canvas-svg");
        $("#pile-graph-canvas-svg").empty();

        var color = d3.scale.category20();

        var tooltip = d3.select("body")
            .append("div")
            .style("position", "absolute")
            .style("z-index", "10")
            .style("visibility", "hidden")
            .text("a simple tooltip");

        force
            .nodes(graph.nodes)
            .links(graph.links)
            .start();

        var link = svg.selectAll(".link")
            .data(graph.links)
            .enter().append("line")
            .style("stroke", "#000")
            .style("stroke-width", function(d) { return Math.sqrt(3*d.value); });

        var node = svg.selectAll(".node")
              .data(graph.nodes)
              .enter().append("g")
              .attr("class", "node")
              .call(force.drag);

        node.append("circle")
            .attr("r", 8)
            .style("fill", function(d) { return color("#3a6b8c"); })

        node.append("text")
            .attr("x", 12)
            .attr("dy", "0.35em")
            .style("opacity", "0.3")
            .text(function(d) { return d.email; });

        link.append("text").attr("x", 12).attr("dy", ".35em").text(function(d) { return d.type; })

        node.on("click", function(d, m, q) {
            // d.attr("toggled", !d.attr("toggled"));
            // d.style("color", "#f00");
            if (mailpile.graphselected.indexOf(d["email"]) < 0) {
                d3.select(node[q][m]).selectAll("circle").style("fill", "#4b7945");
                mailpile.graphselected.push(d["email"]);
            } else {
                mailpile.graphselected.pop(d["email"]);
                d3.select(node[q][m]).selectAll("circle").style("fill", "#3a6b8c");
            }
            mailpile.graph_actionbuttons();
        });
        node.on("mouseover", function(d, m, q) {
            d3.select(node[q][m]).selectAll("text").style("opacity", "1");
        });
        node.on("mouseout", function(d, m, q) {
            d3.select(node[q][m]).selectAll("text").style("opacity", "0.2");
        });

        force.on("tick", function() {
            node.attr("transform", function(d) {
                if (d.x < 0) { d.x = 0; }
                if (d.y < 0) { d.y = 0; }
                if (d.x > width) { d.x = width; }
                if (d.y > height) { d.y = height; }
                return "translate(" + d.x + "," + d.y + ")";
            });
            link.attr("x1", function(d) { return d.source.x; })
                .attr("y1", function(d) { return d.source.y; })
                .attr("x2", function(d) { return d.target.x; })
                .attr("y2", function(d) { return d.target.y; });
        });
    }
}
<|endoftext|>


<commit_before>'use strict';
angular.module('main')
.controller('MappyCtrl', function ($rootScope, $state, $log, Geolocation, opinions) {

  // Note that 'mappyCtrl' is also established in the routing in main.js.
  var mappyCtrl = this;
  mappyCtrl.thing = {};

  // Getting the threeoneones resolved in the main abstract controller.
  mappyCtrl.threeOneOneMarkers = $rootScope.threeoneones;
  // Set arbitrary ids for opinion markers
  mappyCtrl.opinionMarkers = opinions;

  // Defaults.
  mappyCtrl.zoom = 12;
  mappyCtrl.boston = { // This object is formatted to imitate the coords object from the geolocator.
    coords: {
      latitude: 42.4,
      longitude: -71.1
    }
  };

  var initializeMap = function (position) {
    //\\
    // $log.log('initializeMap position -> ', position);

    // Create the Google Map
    mappyCtrl.map = {
      center: {
        latitude: position.coords.latitude,
        longitude: position.coords.longitude
      },
      zoom: mappyCtrl.zoom,
      // control: {},
      // styles: mappyStyle,
      // markers: get311Markers(),
      options: {scrollwheel: false},
      disableDefaultUI: false,
      markersEvents311: {
        click: function(marker, eventName, model) {
          $log.log('Click marker');
          $log.log('model.id: ' + model.id);
          // var stateable = 'main.complaintDetail({complaintId: "' + model.id + '"})';
          $state.go('main.complaintDetailMappy', {complaintId: model.id});
          // mappyCtrl.map.infoIcon = model.icon;
          // mappyCtrl.map.infoDescription = model.description;
          // mappyCtrl.map.infoAddress = model.address;
        }
      },
      markersEventsOpinions: {
        click: function(marker, eventName, model) {
          $log.log('Click marker');
          var keyable = model.$id; // the angularfire key/id thingey (NOT model.id)
          $log.log('key: ' + keyable);
          // var stateable = 'main.opinionDetail({opinionId: "' + keyable + '"})';
          $state.go('main.opinionDetailMappy', {opinionId: keyable});
          // mappyCtrl.map.infoIcon = 'main/assets/images/snowflake-icon.png';
          // mappyCtrl.map.infoDescription = model.text;
          // mappyCtrl.map.infoAddress = model.location.address;
        }
      }
    };
  };

  var getLocation = function () {
    Geolocation.get()
      .then(function (position) { // Success.
        // return position
        initializeMap(position);
      },
      function (err) { // Error. Possibly/probably because it wasn't allowed.
        $log.log("Shit! (Maybe geolocation wasn't allowed?).\nError: ", err);

        // so we'll use Boston instead of current loc
        initializeMap(mappyCtrl.boston);
      });
  };
  getLocation();

  // var get311Markers = function () {
  //   ThreeOneOne.get311(complainables.GRIPES)
  //     .then(function got311 (markers) {
  //       $log.log(markers);

  //       // mappyCtrl.threeOneOneMarkers = markers;

  //       // This will check for availability of current location and then initialize the map with either the current loc or with default Boston.
  //       getLocation();
  //       // return markers;
  //     }, function failedGetting311 (err) {
  //       $log.log("Errrrrororrrr...", err);
  //     });
  // };

  // get311Markers();

});
<commit_msg>disable default map ui<commit_after>'use strict';
angular.module('main')
.controller('MappyCtrl', function ($rootScope, $state, $log, Geolocation, opinions) {

  // Note that 'mappyCtrl' is also established in the routing in main.js.
  var mappyCtrl = this;
  mappyCtrl.thing = {};

  // Getting the threeoneones resolved in the main abstract controller.
  mappyCtrl.threeOneOneMarkers = $rootScope.threeoneones;
  // Set arbitrary ids for opinion markers
  mappyCtrl.opinionMarkers = opinions;

  // Defaults.
  mappyCtrl.zoom = 12;
  mappyCtrl.boston = { // This object is formatted to imitate the coords object from the geolocator.
    coords: {
      latitude: 42.4,
      longitude: -71.1
    }
  };

  var initializeMap = function (position) {
    //\\
    // $log.log('initializeMap position -> ', position);

    // Create the Google Map
    mappyCtrl.map = {
      center: {
        latitude: position.coords.latitude,
        longitude: position.coords.longitude
      },
      zoom: mappyCtrl.zoom,
      // control: {},
      // styles: mappyStyle,
      // markers: get311Markers(),
      options: {scrollwheel: false},
      disableDefaultUI: true,
      markersEvents311: {
        click: function(marker, eventName, model) {
          $log.log('Click marker');
          $log.log('model.id: ' + model.id);
          // var stateable = 'main.complaintDetail({complaintId: "' + model.id + '"})';
          $state.go('main.complaintDetailMappy', {complaintId: model.id});
          // mappyCtrl.map.infoIcon = model.icon;
          // mappyCtrl.map.infoDescription = model.description;
          // mappyCtrl.map.infoAddress = model.address;
        }
      },
      markersEventsOpinions: {
        click: function(marker, eventName, model) {
          $log.log('Click marker');
          var keyable = model.$id; // the angularfire key/id thingey (NOT model.id)
          $log.log('key: ' + keyable);
          // var stateable = 'main.opinionDetail({opinionId: "' + keyable + '"})';
          $state.go('main.opinionDetailMappy', {opinionId: keyable});
          // mappyCtrl.map.infoIcon = 'main/assets/images/snowflake-icon.png';
          // mappyCtrl.map.infoDescription = model.text;
          // mappyCtrl.map.infoAddress = model.location.address;
        }
      }
    };
  };

  var getLocation = function () {
    Geolocation.get()
      .then(function (position) { // Success.
        // return position
        initializeMap(position);
      },
      function (err) { // Error. Possibly/probably because it wasn't allowed.
        $log.log("Shit! (Maybe geolocation wasn't allowed?).\nError: ", err);

        // so we'll use Boston instead of current loc
        initializeMap(mappyCtrl.boston);
      });
  };
  getLocation();

  // var get311Markers = function () {
  //   ThreeOneOne.get311(complainables.GRIPES)
  //     .then(function got311 (markers) {
  //       $log.log(markers);

  //       // mappyCtrl.threeOneOneMarkers = markers;

  //       // This will check for availability of current location and then initialize the map with either the current loc or with default Boston.
  //       getLocation();
  //       // return markers;
  //     }, function failedGetting311 (err) {
  //       $log.log("Errrrrororrrr...", err);
  //     });
  // };

  // get311Markers();

});
<|endoftext|>