<commit_before>#! /usr/bin/env node

var program = require("commander");
var prompt = require("cli-prompt");
var fs = require("fs");

var ImpConfig = require("../lib/impConfig.js");
var impConfig = new ImpConfig();

var imp;

program.parse(process.argv);

// The config settings we'll eventually write
var config = {
  apiKey: null,
  modelId: null,
  modelName: null,
  deviceFile: null,
  agentFile: null,
  devices: []
}

function apiKeyPrompt(apiKey, next) {
  var promptText = "Dev Tools Api-Key";
  if (apiKey) {
    promptText += " (" + apiKey + "): ";
  } else {
    promptText += ": ";
  }

  prompt(promptText, function(val) {
    if (apiKey && !val) val = apiKey;
    impConfig.setLocal("apiKey", val);

    imp = impConfig.createImpWithConfig();
    imp.getDevices({ "device_id" : "garbage" }, function(err, data) {
      if (err) {
        // clear API Key, and try again
        imp.apiKey = null;
        console.log("ERROR: Invalid Api-Key..");
        apiKeyPrompt(apiKey, next);
        return;
      }

      // set API Key, and move on to next
      config.apiKey = val;
      next();
    });
  });
}

function modelPrompt(next) {
  prompt("Model Id or Name: ", function(val) {
    if (!val) {
      modelPrompt(next);
      return;
    }

    // try to get model by id
    imp.getModel(val, function(err, data) {
      if (!err) {
        prompt("Found a matching model '" + data.model.name + "', use this (y): ", function(confirm) {
          if (confirm && confirm.toLowerCase()[0] != "y") {
            modelPrompt(next);
            return;
          }

          config.modelId = data.model.id;
          config.modelName = data.model.name;
          next();
          return;
        });
      } else {

        // an error means no model_id match was found
        imp.getModels({ "name": val }, function(err, data) {
          if (err) {
            console.log("Something went horribly wrong!");
            return;
          }

          // see if we found a matching result
          var foundMatch = false;
          for(var i = 0; i < data.models.length; i++) {
            if(data.models[i].name.toLowerCase() == val.toLowerCase()) {
              foundMatch = true;
              break;
            }
          }
          if (foundMatch) {
            prompt("Found a matching model '" + data.models[i].name + "', use this (y): ", function(confirm){
              if (confirm && confirm.toLowerCase()[0] != "y") {
                modelPrompt(next);
                return;
              }

              config.modelId = data.models[i].id;
              config.modelName = data.models[i].name;
              next();
              return;
            });
          } else {
            prompt("Create new model '" + val + "' (y): ", function(confirm) {
              if (confirm && confirm.toLowerCase()[0] != "y") {
                modelPrompt(next);
                return;
              }

              config.modelName = val;
              next();
              return;
            });
          }
        });
      }
    });
  });
}

function getDevices(next) {
  if (config.modelId == null) {
    next();
    return;
  }

  imp.getDevices({ "model_id": config.modelId }, function(err, data) {
    if (err) {
      console.log("Warning: Could not fetch devices assigned to '" + config.modelName + "'..");
      next();
    }

    for(var i = 0; i < data.devices.length; i++) {
      if (data.devices[i].model_id == config.modelId) {
        config.devices.push(data.devices[i].id);
      }
    }

    var devices = config.devices.length == 1 ? "device" : "devices"
    console.log("Info: Found " + config.devices.length + " " + devices + " associated with '" + config.modelName + "'");
    next();
  });
}

function fileNamePrompt(next) {
  var baseFileName = config.modelName.split(" ").join("_").toLowerCase();
  var defaultDeviceFileName = baseFileName + ".device.nut";
  var defaultAgentFileName = baseFileName + ".agent.nut";

  prompt("Device code file (" + defaultDeviceFileName + "): ", function(deviceFile) {
    if (!deviceFile) deviceFile = defaultDeviceFileName;
    config.deviceFile = deviceFile;
    prompt("Agent code file (" + defaultAgentFileName + "): ", function(agentFile) {
      if (!agentFile) agentFile = defaultAgentFileName;
      config.agentFile = agentFile;

      next();
    });
  });
}

function finalize() {
  var deviceCode = "";
  var agentCode = "";

  if (config.modelId != null) {
    imp.getModelRevisions(config.modelId, null, function(err, data) {
      if (err) {
        console.log("ERROR: Could not fetch code revisions");
        return;
      }

      if (data.revisions.length > 0) {
        imp.getModelRevision(config.modelId, data.revisions[0].version, function(err, data) {
          if (err) {
            console.log("ERROR: Could not fetch code revisions");
            return;
          }

          deviceCode = data.revision.device_code;
          agentCode = data.revision.agent_code;

         fs.writeFile(config.deviceFile, deviceCode);
         fs.writeFile(config.agentFile, agentCode);

          for (var idx in config) {
            impConfig.setLocal(idx, config[idx]);
          }
          impConfig.saveLocalConfig(function(err) {
            if (err) {
              console.log("ERROR: " + err);
              return;
            }

            console.log("Success! To add devices run:");
            console.log("   imp devices -a <deviceId>");
          });
        });
      }
    });
  } else {
    imp.createModel(config.modelName, function(err, data) {
      if (err) {
        console.log("ERROR: Could not create model");
        return;
      }

      config.modelId = data.model.id;

      fs.writeFile(config.deviceFile, deviceCode);
      fs.writeFile(config.agentFile, agentCode);

      impConfig.saveLocalConfig(function(err) {
        if (err) {
          console.log("ERROR: " + err);
          return;
        }

        console.log("Success! To add devices run:");
        console.log("   imp devices -a <deviceId>");
      });
    });
  }
}

impConfig.init(null, function() {
  // Make sure this folder doesn't already have a config file
  if (this.getLocalConfig()) {
    console.log("ERROR: .impconfig already exists.");
    return;
  }

  apiKeyPrompt(this.get("apiKey"), function() {
    modelPrompt(function() {
      getDevices(function() {
        fileNamePrompt(function() {
          finalize();
        });
      });
    });
  });
}.bind(impConfig));
<commit_msg>Updated imp-init to use new impConfig methods<commit_after>#! /usr/bin/env node

var program = require("commander");
var prompt = require("cli-prompt");
var fs = require("fs");

var ImpConfig = require("../lib/impConfig.js");
var config = new ImpConfig();

var imp;

program.parse(process.argv);

function apiKeyPrompt(apiKey, next) {
  var promptText = "Dev Tools Api-Key";
  if (apiKey) {
    promptText += " (" + apiKey + "): ";
  } else {
    promptText += ": ";
  }

  prompt(promptText, function(val) {
    if (apiKey && !val) val = apiKey;
    config.setLocal("apiKey", val);

    imp = config.createImpWithConfig();
    imp.getDevices({ "device_id" : "garbage" }, function(err, data) {
      if (err) {
        // clear API Key, and try again
        imp.apiKey = null;
        console.log("ERROR: Invalid Api-Key..");
        apiKeyPrompt(apiKey, next);
        return;
      }

      next();
    });
  });
}

function modelPrompt(next) {
  prompt("Model Id or Name: ", function(val) {
    if (!val) {
      modelPrompt(next);
      return;
    }

    // try to get model by id
    imp.getModel(val, function(err, data) {
      if (!err) {
        prompt("Found a matching model '" + data.model.name + "', use this (y): ", function(confirm) {
          if (confirm && confirm.toLowerCase()[0] != "y") {
            modelPrompt(next);
            return;
          }

          config.setLocal("modelId", data.model.id);
          config.setLocal("modelName", data.model.name);
          next();
          return;
        });
      } else {

        // an error means no model_id match was found
        imp.getModels({ "name": val }, function(err, data) {
          if (err) {
            console.log("Something went horribly wrong!");
            return;
          }

          // see if we found a matching result
          var foundMatch = false;
          for(var i = 0; i < data.models.length; i++) {
            if(data.models[i].name.toLowerCase() == val.toLowerCase()) {
              foundMatch = true;
              break;
            }
          }
          if (foundMatch) {
            prompt("Found a matching model '" + data.models[i].name + "', use this (y): ", function(confirm){
              if (confirm && confirm.toLowerCase()[0] != "y") {
                modelPrompt(next);
                return;
              }

              config.setLocal("modelId", data.models[i].id);
              config.setLocal("modelName", data.models[i].name);
              next();
              return;
            });
          } else {
            prompt("Create new model '" + val + "' (y): ", function(confirm) {
              if (confirm && confirm.toLowerCase()[0] != "y") {
                modelPrompt(next);
                return;
              }

              config.setLocal("modelName", val);
              next();
              return;
            });
          }
        });
      }
    });
  });
}

function getDevices(next) {
  var modelId = config.getLocal("modelId");
  var modelName = config.getLocal("modelName");
  if (modelId == null) {
    next();
    return;
  }

  imp.getDevices({ "model_id": modelId }, function(err, data) {
    if (err) {
      console.log("Warning: Could not fetch devices assigned to '" + modelName + "'..");
      next();
    }

    var devices = [];
    for(var i = 0; i < data.devices.length; i++) {
      if (data.devices[i].model_id == modelId) {
        devices.push(data.devices[i].id);
      }
    }

    config.setLocal("devices", devices);

    var devicesText = devices.length == 1 ? "device" : "devices"
    console.log("Info: Found " + devices.length + " " + devicesText + " associated with '" + modelName + "'");
    next();
  });
}

function fileNamePrompt(next) {
  var modelName = config.getLocal("modelName");

  var baseFileName = modelName.split(" ").join("_").toLowerCase();
  var defaultDeviceFileName = baseFileName + ".device.nut";
  var defaultAgentFileName = baseFileName + ".agent.nut";

  prompt("Device code file (" + defaultDeviceFileName + "): ", function(deviceFile) {
    if (!deviceFile) deviceFile = defaultDeviceFileName;
    config.setLocal("deviceFile", deviceFile);
    prompt("Agent code file (" + defaultAgentFileName + "): ", function(agentFile) {
      if (!agentFile) agentFile = defaultAgentFileName;
      config.setLocal("agentFile", agentFile);

      next();
    });
  });
}

function finalize() {
  var deviceCode = "";
  var agentCode = "";

  var modelId = config.getLocal("modelId");
  var modelName = config.getLocal("modelName");
  var agentFile = config.getLocal("agentFile");
  var deviceFile = config.getLocal("deviceFile");

  if (modelId != null) {
    imp.getModelRevisions(modelId, null, function(err, data) {
      if (err) {
        console.log("ERROR: Could not fetch code revisions");
        return;
      }

      if (data.revisions.length > 0) {
        imp.getModelRevision(modelId, data.revisions[0].version, function(err, data) {
          if (err) {
            console.log("ERROR: Could not fetch code revisions");
            return;
          }

          deviceCode = data.revision.device_code;
          agentCode = data.revision.agent_code;

         fs.writeFile(deviceFile, deviceCode);
         fs.writeFile(agentFile, agentCode);

          config.saveLocalConfig(function(err) {
            if (err) {
              console.log("ERROR: " + err);
              return;
            }

            console.log("Success! To add devices run:");
            console.log("   imp devices -a <deviceId>");
          });
        });
      }
    });
  } else {
    imp.createModel(modelName, function(err, data) {
      if (err) {
        console.log("ERROR: Could not create model");
        return;
      }

      config.setLocal("modelId", data.model.id);

      fs.writeFile(deviceFile, deviceCode);
      fs.writeFile(agentFile, agentCode);

      config.saveLocalConfig(function(err) {
        if (err) {
          console.log("ERROR: " + err);
          return;
        }

        console.log("Success! To add devices run:");
        console.log("   imp devices -a <deviceId>");
      });
    });
  }
}

config.init(null, function() {
  // Make sure this folder doesn't already have a config file
  if (this.getLocalConfig()) {
    console.log("ERROR: .impconfig already exists.");
    return;
  }

  apiKeyPrompt(this.get("apiKey"), function() {
    modelPrompt(function() {
      getDevices(function() {
        fileNamePrompt(function() {
          finalize();
        });
      });
    });
  });
}.bind(config));
<|endoftext|>


<commit_before>'use strict'

import crossSpawn from 'cross-spawn-async'

const parseStdioOption = (value) => {
  let ignoreStdout = false
  let ignoreStderr = false
  if (value === 'ignore') {
    ignoreStdout = true
    ignoreStderr = true
  } else if (Array.isArray(value)) {
    ignoreStdout = (value[1] === 'ignore')
    ignoreStderr = (value[1] === 'ignore')
  }
  return [ignoreStdout, ignoreStderr]
}

export default (cmd, args, options = {}) => new Promise((resolve, reject) => {
  const proc = crossSpawn(cmd, args, options)
  let stdout = null
  let stderr = null
  const [ignoreStdout, ignoreStderr] = parseStdioOption(options.stdio)
  if (!ignoreStdout) {
    stdout = []
    proc.stdout.on('data', (data) => { stdout.push(data) })
  }
  if (!ignoreStderr) {
    stderr = []
    proc.stderr.on('data', (data) => { stderr.push(data) })
  }
  proc.once('close', (code) => {
    if (code !== 0) {
      const err = new Error(`Exited with status ${code}`)
      err.exitStatus = code
      if (!ignoreStderr) {
        err.stderr = Buffer.concat(stderr)
      }
      reject(err)
    } else {
      resolve(ignoreStdout ? null : Buffer.concat(stdout))
    }
  })
})
<commit_msg>Support stdio inherit<commit_after>'use strict'

import crossSpawn from 'cross-spawn-async'

const shouldIgnore = (value) => (value === 'ignore' || value === 'inherit')

const parseStdioOption = (value) => {
  let ignoreStdout = false
  let ignoreStderr = false
  if (shouldIgnore(value)) {
    ignoreStdout = true
    ignoreStderr = true
  } else if (Array.isArray(value)) {
    ignoreStdout = shouldIgnore(value[1])
    ignoreStderr = shouldIgnore(value[2])
  }
  return [ignoreStdout, ignoreStderr]
}

export default (cmd, args, options = {}) => new Promise((resolve, reject) => {
  const proc = crossSpawn(cmd, args, options)
  let stdout = null
  let stderr = null
  const [ignoreStdout, ignoreStderr] = parseStdioOption(options.stdio)
  if (!ignoreStdout) {
    stdout = []
    proc.stdout.on('data', (data) => { stdout.push(data) })
  }
  if (!ignoreStderr) {
    stderr = []
    proc.stderr.on('data', (data) => { stderr.push(data) })
  }
  proc.once('close', (code) => {
    if (code !== 0) {
      const err = new Error(`Exited with status ${code}`)
      err.exitStatus = code
      if (!ignoreStderr) {
        err.stderr = Buffer.concat(stderr)
      }
      reject(err)
    } else {
      resolve(ignoreStdout ? null : Buffer.concat(stdout))
    }
  })
})
<|endoftext|>


<commit_before>/**
 * esdoc-plugin-extends-replace -- Provides support for replacing an ES6 classes extends target which is useful for
 * architectures where the target is indirectly imported. An example architecture is backbone-es6
 * (https://github.com/typhonjs/backbone-es6) where the main access point is a composed class, `Backbone`. In this case
 * developers import Backbone as such:
 *
 * ```
 * import Backbone from 'backbone';
 *
 * export default class MyCustomView extends Backbone.View {}
 * ```
 *
 * ESDoc has no visibility into the composed Backbone instance which occurs at runtime nor is there relevant data
 * to link `Backbone.View` to the actual implementing class / file in the bare source code which is parsed by ESDoc. In
 * this example case JSPM / SystemJS is used to manage the backbone-es6 dependency. To support end to end documentation
 * it's necessary to replace `Backbone.View` with
 * `<ProjectRootPath>/jspm_packages/github/typhonjs/backbone-es6@master/src/View.js`.
 *
 * `esdoc-plugin-extends-replace` can be used independently of JSPM / SystemJS, but the sample below from
 * `backbone-parse-es6-demo` shows the `esdoc.json` file that uses `esdoc-plugin-extends-replace` and
 * `esdoc-plugin-jspm`.
 *
 * Please refer to this repo that is using this plugin to generate end to end documentation:
 * https://github.com/typhonjs/backbone-parse-es6-demo
 *
 * This is the esdoc.json configuration file for the above repo:
 * {
 *    "title": "backbone-parse-es6-demo",
 *    "source": "src",
 *    "destination": "docs",
 *    "plugins":
 *    [
 *       {
 *          "name": "esdoc-plugin-jspm"
 *       },
 *
 *       {
 *          "name": "esdoc-plugin-extends-replace",
 *          "option":
 *          {
 *             "replace":
 *             {
 *                "Backbone.Collection": "backbone-parse-es6@master/src/ParseCollection",
 *                "Backbone.Events": "backbone-es6@master/src/Events",
 *                "Backbone.History": "backbone-es6@master/src/History",
 *                "Backbone.Model": "backbone-parse-es6@master/src/ParseModel",
 *                "Backbone.Router": "backbone-es6@master/src/Router",
 *                "Backbone.View": "backbone-es6@master/src/View"
 *             }
 *          }
 *       }
 *    ]
 * }
 *
 * In the `option.replace` object hash the left hand is a text string to search for in `extends` tags available for
 * modification in `onHandleTag`. Presently it's just a bare string checked by `indexOf`. In the future it may be
 * upgraded to regex matching. On the right hand side is the partial path & name of the class to replace matched extend
 * targets. In `onHandleTag` all tags are first processed storing the `longname` tag for the class path in question.
 * Then a second pass is made replacing any classes `extends` tags that match the left hand side with the `longname` of
 * the class found on the right hand side.
 *
 * Of course it should be noted that currently the parsing is very basic and there will be clashes if one uses just
 * the class name. It's recommended to use a partial path including the JSPM module name as shown above. Please take
 * note of the semver / version number or `@master` for a dependency pulling directly from the master branch of
 * a repository.
 */

var option;
var reverseLookup = {};

// ESDoc plugin callbacks -------------------------------------------------------------------------------------------

/**
 * Stores the option data from the plugin configuration and provides empty defaults as necessary.
 *
 * @param {object}   ev - Event from ESDoc containing data field.
 */
exports.onStart = function(ev)
{
   option = ev.data.option || {};
   option.replace = option.replace || {};

   for (var regex in option.replace)
   {
      reverseLookup[option.replace[regex]] = '';
   }
};

/**
 * Replaces class `extends` tag entries with the `longname` of classes found in a first pass.
 *
 * @param {object}   ev - Event from ESDoc containing data field
 */
exports.onHandleTag = function(ev)
{
   // Perform first pass through all tags matching the `longname` of a class with the `option.replace` right
   // hand side / class path & name partial.
   for (var cntr = 0; cntr < ev.data.tag.length; cntr++)
   {
      var tag = ev.data.tag[cntr];

      if (tag.kind && tag.longname && tag.kind === 'class')
      {
         for (var classpath in reverseLookup)
         {
            if (tag.longname.indexOf(classpath) >= 0)
            {
               reverseLookup[classpath] = tag.longname;
            }
         }
      }
   }

   // Perform a second pass through all tags replacing class `extends` entries that match the left hand side of
   // `option.replace` data with the `longname` of the class from the first pass above.
   for (cntr = 0; cntr < ev.data.tag.length; cntr++)
   {
      tag = ev.data.tag[cntr];

      if (tag.kind && tag.extends && tag.kind === 'class')
      {
         for (var cntr2 = 0; cntr2 < tag.extends.length; cntr2++)
         {
            var extendsTag = tag.extends[cntr2];

            for (var replace in option.replace)
            {
               if (extendsTag.indexOf(replace) >= 0)
               {
                  tag.extends[cntr2] = reverseLookup[option.replace[replace]];
               }
            }
         }
      }
   }
};<commit_msg>Initial commit<commit_after>/**
 * esdoc-plugin-extends-replace -- Provides support for replacing an ES6 classes extends target which is useful for
 * architectures where the target is indirectly imported. An example architecture is backbone-es6
 * (https://github.com/typhonjs/backbone-es6) where the main access point is a composed class, `Backbone`. In this case
 * developers import Backbone as such:
 *
 * ```
 * import Backbone from 'backbone';
 *
 * export default class MyCustomView extends Backbone.View {}
 * ```
 *
 * ESDoc has no visibility into the composed Backbone instance which occurs at runtime nor is there relevant data
 * to link `Backbone.View` to the actual implementing class / file in the bare source code which is parsed by ESDoc. In
 * this example case JSPM / SystemJS is used to manage the backbone-es6 dependency. To support end to end documentation
 * it's necessary to replace `Backbone.View` with
 * `<ProjectRootPath>/jspm_packages/github/typhonjs/backbone-es6@master/src/View.js`.
 *
 * `esdoc-plugin-extends-replace` can be used independently of JSPM / SystemJS, but the sample below from
 * `backbone-parse-es6-demo` shows the `esdoc.json` file that uses `esdoc-plugin-extends-replace` and
 * `esdoc-plugin-jspm`.
 *
 * Please refer to this repo that is using this plugin to generate end to end documentation:
 * https://github.com/typhonjs/backbone-parse-es6-demo
 *
 * ```
 * This is the esdoc.json configuration file for the above repo:
 * {
 *    "title": "backbone-parse-es6-demo",
 *    "source": "src",
 *    "destination": "docs",
 *    "plugins":
 *    [
 *       {
 *          "name": "esdoc-plugin-jspm"
 *       },
 *
 *       {
 *          "name": "esdoc-plugin-extends-replace",
 *          "option":
 *          {
 *             "replace":
 *             {
 *                "Backbone.Collection": "backbone-parse-es6@master/src/ParseCollection",
 *                "Backbone.Events": "backbone-es6@master/src/Events",
 *                "Backbone.History": "backbone-es6@master/src/History",
 *                "Backbone.Model": "backbone-parse-es6@master/src/ParseModel",
 *                "Backbone.Router": "backbone-es6@master/src/Router",
 *                "Backbone.View": "backbone-es6@master/src/View"
 *             }
 *          }
 *       }
 *    ]
 * }
 *```
 *
 * In the `option.replace` object hash the left hand is a text string to search for in `extends` tags available for
 * modification in `onHandleTag`. Presently it's just a bare string checked by `indexOf`. In the future it may be
 * upgraded to regex matching. On the right hand side is the partial path & name of the class to replace matched extend
 * targets. In `onHandleTag` all tags are first processed storing the `longname` tag for the class path in question.
 * Then a second pass is made replacing any classes `extends` tags that match the left hand side with the `longname` of
 * the class found on the right hand side.
 *
 * Of course it should be noted that currently the parsing is very basic and there will be clashes if one uses just
 * the class name. It's recommended to use a partial path including the JSPM module name as shown above. Please take
 * note of the semver / version number or `@master` for a dependency pulling directly from the master branch of
 * a repository.
 */

var option;
var reverseLookup = {};

// ESDoc plugin callbacks -------------------------------------------------------------------------------------------

/**
 * Stores the option data from the plugin configuration and provides empty defaults as necessary.
 *
 * @param {object}   ev - Event from ESDoc containing data field.
 */
exports.onStart = function(ev)
{
   option = ev.data.option || {};
   option.replace = option.replace || {};

   for (var regex in option.replace)
   {
      reverseLookup[option.replace[regex]] = '';
   }
};

/**
 * Replaces class `extends` tag entries with the `longname` of classes found in a first pass.
 *
 * @param {object}   ev - Event from ESDoc containing data field
 */
exports.onHandleTag = function(ev)
{
   // Perform first pass through all tags matching the `longname` of a class with the `option.replace` right
   // hand side / class path & name partial.
   for (var cntr = 0; cntr < ev.data.tag.length; cntr++)
   {
      var tag = ev.data.tag[cntr];

      if (tag.kind && tag.longname && tag.kind === 'class')
      {
         for (var classpath in reverseLookup)
         {
            if (tag.longname.indexOf(classpath) >= 0)
            {
               reverseLookup[classpath] = tag.longname;
            }
         }
      }
   }

   // Perform a second pass through all tags replacing class `extends` entries that match the left hand side of
   // `option.replace` data with the `longname` of the class from the first pass above.
   for (cntr = 0; cntr < ev.data.tag.length; cntr++)
   {
      tag = ev.data.tag[cntr];

      if (tag.kind && tag.extends && tag.kind === 'class')
      {
         for (var cntr2 = 0; cntr2 < tag.extends.length; cntr2++)
         {
            var extendsTag = tag.extends[cntr2];

            for (var replace in option.replace)
            {
               if (extendsTag.indexOf(replace) >= 0)
               {
                  tag.extends[cntr2] = reverseLookup[option.replace[replace]];
               }
            }
         }
      }
   }
};<|endoftext|>


<commit_before>#! /bin/sh
':' // ; export MAX_MEM="--max-old-space-size=150"; exec "$(command -v node || command -v nodejs)" --harmony "${NODE_OPTIONS:-$MAX_MEM}" "$0" "$@"
'use strict'
/*
 * See the NOTICE.txt file distributed with this work for additional information
 * regarding copyright ownership.
 * Sematext licenses logagent-js to you under
 * the Apache License, Version 2.0 (the "License"); you may
 * not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
var consoleLogger = require('../lib/util/logger.js')
var StatsPrinter = require('../lib/core/printStats.js')
var LogAnalyzer = require('../lib/parser/parser.js')
var mkpath = require('mkpath')
process.setMaxListeners(0)
var co = require('co')
var moduleAlias = {
  command: '../lib/plugins/input/command.js',
  sql: '../lib/plugins/output-filter/sql.js',
  grep: '../lib/plugins/input-filter/grep.js',
  'input-tcp': '../lib/plugins/input/tcp.js',
  elasticsearch: '../lib/plugins/output/elasticsearch.js'
}
function LaCli (options) {
  this.eventEmitter = require('../lib/core/logEventEmitter.js')
  this.eventEmitter.on('error', function (err) {
    consoleLogger.error(err)
  })
  this.logseneDiskBufferDir = null
  this.fileManager = null
  this.la = null
  this.throng = null
  this.argv = options || require('../lib/core/cliArgs.js')
  this.globPattern = this.argv.glob || process.env.GLOB_PATTERN
  this.logseneToken = this.argv.index || process.env.LOGSENE_TOKEN
  this.loggers = {}
  this.WORKERS = process.env.WEB_CONCURRENCY || 1
  this.removeAnsiColor = /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g
  this.laStats = StatsPrinter
  this.initState()
}
LaCli.prototype.initFilter = function (type, filterFunctions) {
  consoleLogger.log('init filter: ' + type)
  this[type] = []
  for (var i = 0; i < filterFunctions.length; i++) {
    try {
      var filterName = filterFunctions[i].name || filterFunctions[i].module || 'plugin #' + i
      var ff = null
      if (typeof filterFunctions[i].module === 'function') {
        ff = filterFunctions[i].module
        filterName = String(filterFunctions[i].name || 'plugin #' + i)
      } else {
        ff = require(moduleAlias[filterFunctions[i].module] || filterFunctions[i].module)
      }
      var filter = {
        func: ff,
        config: filterFunctions[i].config || {}
      }
      this[type].push(filter)
      consoleLogger.log('load ' + type + ': ' + i + ' ' + filterName)
    } catch (err) {
      consoleLogger.error('Error loading plugin: ' + i + ' ' + (filterName || 'undefined') + ' ' + err.message)
    }
  }
}
LaCli.prototype.initPlugins = function (plugins) {
  consoleLogger.log('init plugins')
  var eventEmitter = require('../lib/core/logEventEmitter')
  this.plugins = []
  plugins.forEach(function (plugin) {
    var pluginName = plugin.module || plugin
    consoleLogger.log(pluginName)
    try {
      var Plugin = require(moduleAlias[pluginName] || pluginName)
      // be compatible with plugins accessing config.configFile property
      if (plugin.config) {
        plugin.config.configFile = plugin.globalConfig
      }
      var p = new Plugin(plugin.config || this.argv, eventEmitter)
      this.plugins.push(p)
      p.start()
    } catch (err) {
      consoleLogger.error('Error loading plugin: ' + (moduleAlias[pluginName] || pluginName) + ' ' + err.stack)
    }
  }.bind(this))
}

LaCli.prototype.loadPlugins = function (configFile) {
  var plugins = [
    '../lib/plugins/input/stdin',
    '../lib/plugins/output/stdout'
  ]
  // load 3rd paty modules
  if (configFile && configFile.input) {
    var inputSections = Object.keys(configFile.input)
    inputSections.forEach(function (key) {
      consoleLogger.log('add ' + (configFile.input[key].module || key) + ' to plugin list')
      if (configFile.input[key].module) {
        plugins.push({
          module: moduleAlias[configFile.input[key].module] || configFile.input[key].module,
          config: configFile.input[key],
          globalConfig: configFile
        })
      }
      /*if (configFile.input[key].module) {
        consoleLogger.log('add ' + configFile.input[key].module + ' to plugin list')
        plugins.push(moduleAlias[configFile.input[key].module] || configFile.input[key].module)
      }*/
    })
  }
  // load input filters
  var inputFilter = []
  if (configFile && configFile.inputFilter) {
    var inputFilterSections = Object.keys(configFile.inputFilter)
    inputFilterSections.forEach(function (key) {
      if (configFile.inputFilter[key].module) {
        inputFilter.push(configFile.inputFilter[key])
      }
    })
  }
  this.initFilter('inputFilter', inputFilter)

  // load output plugins
  if (configFile && configFile.output) {
    var outputSections = Object.keys(configFile.output)
    outputSections.forEach(function (key) {
      if (configFile.output[key].module) {
        plugins.push({
          module: moduleAlias[configFile.output[key].module] || configFile.output[key].module,
          config: configFile.output[key],
          globalConfig: configFile
        })
      }
    })
  }
  // load output filters
  var outputFilter = []
  if (configFile && configFile.outputFilter) {
    var outputFilterSections = Object.keys(configFile.outputFilter)
    outputFilterSections.forEach(function (key) {
      if (configFile.outputFilter[key].module) {
        outputFilter.push(configFile.outputFilter[key])
      }
    })
  }
  this.initFilter('outputFilter', outputFilter)

  this.argv.stdinExitEnabled = true
  if (this.argv.udp) {
    plugins.push('../lib/plugins/input/syslog')
    this.argv.stdinExitEnabled = false
  }
  if (this.argv.heroku) {
    plugins.push('../lib/plugins/input/heroku')
    this.argv.stdinExitEnabled = false
  }
  if (this.argv.cfhttp) {
    plugins.push('../lib/plugins/input/cloudfoundry')
    this.argv.stdinExitEnabled = false
  }
  if (this.argv.index || this.argv.elasticsearchUrl || this.argv.indices) {
    plugins.push('../lib/plugins/output/elasticsearch')
  }
  if (this.argv.rtailPort) {
    plugins.push('../lib/plugins/output/rtail')
  }
  if ((this.argv.args && this.argv.args.length > 0) || this.argv.glob) {
    plugins.push('../lib/plugins/input/files')
    this.argv.stdinExitEnabled = false
  }

  if (!configFile) {
    return plugins
  }

  return plugins
}

LaCli.prototype.initState = function () {
  var self = this
  var eventEmitter = self.eventEmitter
  var plugins = self.loadPlugins(this.argv.configFile)
  self.initPlugins(plugins)

  self.logseneDiskBufferDir = self.argv['diskBufferDir'] || process.env.LOGSENE_TMP_DIR || require('os').tmpdir()
  mkpath(self.logseneDiskBufferDir, function (err) {
    if (err) {
      console.error('ERROR: create diskBufferDir (' + self.logseneDiskBufferDir + '): ' + err.message)
    }
  })

  this.la = new LogAnalyzer(self.argv.patternFiles, {}, function laReadyCb (lp) {
    if (self.argv.patterns && (self.argv.patterns instanceof Array)) {
      lp.patterns = self.argv.patterns.concat(lp.patterns)
    }
    var jsonConfigured = (self.argv.configFile !== undefined &&
      self.argv.configFile.parser !== undefined &&
      self.argv.configFile.parser.json !== undefined)
    if (jsonConfigured) {
      lp.cfg.json = self.argv.configFile.parser.json
    }
    if (self.argv.includeOriginalLine !== undefined) {
      lp.cfg.originalLine = self.argv.includeOriginalLine
    }
    self.cli()
  })
  self.eventEmitter.once('input.stdin.end', function endOnStdinEof (line, context) {
    self.terminateRequest = true
    self.terminateReason = 'stdin closed'
  })

  self.tid = setInterval(function () {
    if (self.terminateRequest && Date.now() - self.lastParsedTS > 1500) {
      self.terminate(self.terminateReason)
      clearInterval(self.tid)
    }
  }, 1000)
  self.tid.unref()

  self.eventEmitter.on('data.raw', function parseRaw (line, context) {
    self.lastParsedTS = Date.now()
    var trimmedLine = line
    if (line && Buffer.byteLength(line, 'utf8') > self.argv.maxLogSize) {
      var cutMsg = new Buffer(self.argv.maxLogSize)
      cutMsg.write(line)
      trimmedLine = cutMsg.toString()
    }
    self.laStats.bytes = self.laStats.bytes + Buffer.byteLength(line, 'utf8')
    self.laStats.count++
    co(function * processInput () {
      for (var i = 0; i < self.inputFilter.length; i++) {
        trimmedLine = yield function (callback) {
          self.inputFilter[i].func(context.sourceName || self.argv.sourceName, self.inputFilter[i].config, trimmedLine, callback)
        }
      }
    }).then(function () {
      if (!trimmedLine) {
        return
      }
      self.la.parseLine(
        trimmedLine.replace(self.removeAnsiColor, ''),
        context.sourceName || self.argv.sourceName,
        function parserCb (err, data) {
          if (err && !data) {
            consoleLogger.error('error during parsing: ' + err.stack)
          }
          if (data) {
            var filteredData = data
            co(function * () {
              for (var i = 0; i < self.outputFilter.length; i++) {
                filteredData = yield function (callback) {
                  self.outputFilter[i].func(context, self.outputFilter[i].config, eventEmitter, filteredData, callback)
                }
              }
            }).then(function () {
              if (!filteredData) {
                return
              }
              if (context.enrichEvent) {
                Object.keys(context.enrichEvent).forEach(function (key) {
                  data[key] = context.enrichEvent[key]
                })
              }
              if (context.filter) {
                filteredData = context.filter(data, context)
              }
              if (filteredData) {
                self.eventEmitter.parsedEvent(filteredData, context)
              }
            }, function (e) {
              // consoleLogger.error(e.stack)
            })
          }
        })
    }, function (e) {
      // consoleLogger.error(e.stack)
    })
  })

  process.once('SIGINT', function () { self.terminate('SIGINT') })
  process.once('SIGQUIT', function () { self.terminate('SIGQUIT') })
  process.once('SIGTERM', function () { self.terminate('SIGTERM') })
  process.once('beforeExit', self.terminate)
}

LaCli.prototype.log = function (err, data) {
  if (err && (!data)) {
    this.laStats.emptyLines++
    return
  }
  if (!data) {
    return
  }
  if (this.argv.tokenMapper) {
    var tokenForSource = this.argv.tokenMapper.findToken([data.logSource]) || this.argv.index
    if (tokenForSource) {
      this.logToLogsene(tokenForSource, data['_type'] || 'logs', data)
    }
  } else {
    if (this.argv.index) {
      this.logToLogsene(this.argv.index, data['_type'] || 'logs', data)
    }
  }
}

LaCli.prototype.parseLine = function (line, sourceName, cbf) {
  if (!line && cbf) {
    return cbf(new Error('empty line passed to parseLine()'))
  }
  var trimmedLine = line
  var bufLength = Buffer.byteLength(line, 'utf8')
  if (line && bufLength > this.argv.maxLogSize) {
    var cutMsg = new Buffer(this.argv.maxLogSize)
    cutMsg.write(line)
    trimmedLine = cutMsg.toString()
  }
  this.laStats.bytes = this.laStats.bytes + bufLength
  this.laStats.count++
  this.la.parseLine(
    trimmedLine.replace(this.removeAnsiColor, ''),
    this.argv.sourceName || sourceName,
    cbf || this.log.bind(this))
}

LaCli.prototype.parseChunks = function (chunk, enc, callback) {
  this.parseLine(chunk.toString())
  callback()
}

LaCli.prototype.terminate = function (reason) {
  consoleLogger.log('terminate reason: ' + reason)
  if (this.argv.heroku && reason !== 'exitWorker') {
    return
  }
  if (this.argv.suppress) {
    this.laStats.printStats()
  }
  var terminateCounter = this.plugins.length
  function callBackWithATimeout (callback, timeout) {
    var run, timer
    run = function () {
      if (timer) {
        clearTimeout(timer)
        timer = null
        callback.apply(this, arguments)
      }
    }
    timer = setTimeout(run, timeout, 'timeout')
    return run
  }
  this.plugins.forEach(function pluginStop (p) {
    if (p.stop) {
      try {
        p.stop(callBackWithATimeout(function () {
          terminateCounter--
          if (terminateCounter === 0) {
            setTimeout(process.exit, 5000)
          }
        }, 10 * 1000 * 60))
      } catch (err) {
        consoleLogger.error('Error stopping plugin ' + err)
      }
    } else {
      terminateCounter--
      if (terminateCounter === 0) {
        setTimeout(process.exit, 5000)
      }
    }
  })
  if (!/stdin/.test(reason)) {
    setTimeout(process.exit, 10000)
  }
}

LaCli.prototype.cli = function () {
  if (this.argv.printStats || this.argv.verbose) {
    setInterval(this.laStats.printStats.bind(this.laStats), ((Number(this.argv.printStats)) || 60) * 1000).unref()
    this.laStats.printStats()
  }
}

if (require.main === module) {
  var logagent = new LaCli()
  if (logagent) {
    consoleLogger.log('Logagent initialized')
  }
} else {
  module.exports = LaCli
}
<commit_msg>fix termination on stdin close<commit_after>#! /bin/sh
':' // ; export MAX_MEM="--max-old-space-size=150"; exec "$(command -v node || command -v nodejs)" --harmony "${NODE_OPTIONS:-$MAX_MEM}" "$0" "$@"
'use strict'
/*
 * See the NOTICE.txt file distributed with this work for additional information
 * regarding copyright ownership.
 * Sematext licenses logagent-js to you under
 * the Apache License, Version 2.0 (the "License"); you may
 * not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
var consoleLogger = require('../lib/util/logger.js')
var StatsPrinter = require('../lib/core/printStats.js')
var LogAnalyzer = require('../lib/parser/parser.js')
var mkpath = require('mkpath')
process.setMaxListeners(0)
var co = require('co')
var moduleAlias = {
  command: '../lib/plugins/input/command.js',
  sql: '../lib/plugins/output-filter/sql.js',
  grep: '../lib/plugins/input-filter/grep.js',
  'input-tcp': '../lib/plugins/input/tcp.js',
  elasticsearch: '../lib/plugins/output/elasticsearch.js'
}
function LaCli (options) {
  this.eventEmitter = require('../lib/core/logEventEmitter.js')
  this.eventEmitter.on('error', function (err) {
    consoleLogger.error(err)
  })
  this.logseneDiskBufferDir = null
  this.fileManager = null
  this.la = null
  this.throng = null
  this.argv = options || require('../lib/core/cliArgs.js')
  this.globPattern = this.argv.glob || process.env.GLOB_PATTERN
  this.logseneToken = this.argv.index || process.env.LOGSENE_TOKEN
  this.loggers = {}
  this.WORKERS = process.env.WEB_CONCURRENCY || 1
  this.removeAnsiColor = /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g
  this.laStats = StatsPrinter
  this.initState()
}
LaCli.prototype.initFilter = function (type, filterFunctions) {
  consoleLogger.log('init filter: ' + type)
  this[type] = []
  for (var i = 0; i < filterFunctions.length; i++) {
    try {
      var filterName = filterFunctions[i].name || filterFunctions[i].module || 'plugin #' + i
      var ff = null
      if (typeof filterFunctions[i].module === 'function') {
        ff = filterFunctions[i].module
        filterName = String(filterFunctions[i].name || 'plugin #' + i)
      } else {
        ff = require(moduleAlias[filterFunctions[i].module] || filterFunctions[i].module)
      }
      var filter = {
        func: ff,
        config: filterFunctions[i].config || {}
      }
      this[type].push(filter)
      consoleLogger.log('load ' + type + ': ' + i + ' ' + filterName)
    } catch (err) {
      consoleLogger.error('Error loading plugin: ' + i + ' ' + (filterName || 'undefined') + ' ' + err.message)
    }
  }
}
LaCli.prototype.initPlugins = function (plugins) {
  consoleLogger.log('init plugins')
  var eventEmitter = require('../lib/core/logEventEmitter')
  this.plugins = []
  plugins.forEach(function (plugin) {
    var pluginName = plugin.module || plugin
    consoleLogger.log(pluginName)
    try {
      var Plugin = require(moduleAlias[pluginName] || pluginName)
      // be compatible with plugins accessing config.configFile property
      if (plugin.config) {
        plugin.config.configFile = plugin.globalConfig
      }
      var p = new Plugin(plugin.config || this.argv, eventEmitter)
      this.plugins.push(p)
      p.start()
    } catch (err) {
      consoleLogger.error('Error loading plugin: ' + (moduleAlias[pluginName] || pluginName) + ' ' + err.stack)
    }
  }.bind(this))
}

LaCli.prototype.loadPlugins = function (configFile) {
  var plugins = [
    '../lib/plugins/input/stdin',
    '../lib/plugins/output/stdout'
  ]
  // load 3rd paty modules
  if (configFile && configFile.input) {
    var inputSections = Object.keys(configFile.input)
    inputSections.forEach(function (key) {
      consoleLogger.log('add ' + (configFile.input[key].module || key) + ' to plugin list')
      if (configFile.input[key].module) {
        plugins.push({
          module: moduleAlias[configFile.input[key].module] || configFile.input[key].module,
          config: configFile.input[key],
          globalConfig: configFile
        })
      }
      /* if (configFile.input[key].module) {
        consoleLogger.log('add ' + configFile.input[key].module + ' to plugin list')
        plugins.push(moduleAlias[configFile.input[key].module] || configFile.input[key].module)
      } */
    })
  }
  // load input filters
  var inputFilter = []
  if (configFile && configFile.inputFilter) {
    var inputFilterSections = Object.keys(configFile.inputFilter)
    inputFilterSections.forEach(function (key) {
      if (configFile.inputFilter[key].module) {
        inputFilter.push(configFile.inputFilter[key])
      }
    })
  }
  this.initFilter('inputFilter', inputFilter)

  // load output plugins
  if (configFile && configFile.output) {
    var outputSections = Object.keys(configFile.output)
    outputSections.forEach(function (key) {
      if (configFile.output[key].module) {
        plugins.push({
          module: moduleAlias[configFile.output[key].module] || configFile.output[key].module,
          config: configFile.output[key],
          globalConfig: configFile
        })
      }
    })
  }
  // load output filters
  var outputFilter = []
  if (configFile && configFile.outputFilter) {
    var outputFilterSections = Object.keys(configFile.outputFilter)
    outputFilterSections.forEach(function (key) {
      if (configFile.outputFilter[key].module) {
        outputFilter.push(configFile.outputFilter[key])
      }
    })
  }
  this.initFilter('outputFilter', outputFilter)
  if (plugins.length === 2) {
    // only stdin/stdout are used and process can terminate
    // when stdin gets closed
    this.argv.stdinExitEnabled = true
  }

  if (this.argv.udp) {
    plugins.push('../lib/plugins/input/syslog')
    this.argv.stdinExitEnabled = false
  }
  if (this.argv.heroku) {
    plugins.push('../lib/plugins/input/heroku')
    this.argv.stdinExitEnabled = false
  }
  if (this.argv.cfhttp) {
    plugins.push('../lib/plugins/input/cloudfoundry')
    this.argv.stdinExitEnabled = false
  }
  if (this.argv.index || this.argv.elasticsearchUrl || this.argv.indices) {
    plugins.push('../lib/plugins/output/elasticsearch')
  }
  if (this.argv.rtailPort) {
    plugins.push('../lib/plugins/output/rtail')
  }
  if ((this.argv.args && this.argv.args.length > 0) || this.argv.glob) {
    plugins.push('../lib/plugins/input/files')
    this.argv.stdinExitEnabled = false
  }

  if (!configFile) {
    return plugins
  }

  return plugins
}

LaCli.prototype.initState = function () {
  var self = this
  var eventEmitter = self.eventEmitter
  var plugins = self.loadPlugins(this.argv.configFile)
  self.initPlugins(plugins)

  self.logseneDiskBufferDir = self.argv['diskBufferDir'] || process.env.LOGSENE_TMP_DIR || require('os').tmpdir()
  mkpath(self.logseneDiskBufferDir, function (err) {
    if (err) {
      console.error('ERROR: create diskBufferDir (' + self.logseneDiskBufferDir + '): ' + err.message)
    }
  })

  this.la = new LogAnalyzer(self.argv.patternFiles, {}, function laReadyCb (lp) {
    if (self.argv.patterns && (self.argv.patterns instanceof Array)) {
      lp.patterns = self.argv.patterns.concat(lp.patterns)
    }
    var jsonConfigured = (self.argv.configFile !== undefined &&
      self.argv.configFile.parser !== undefined &&
      self.argv.configFile.parser.json !== undefined)
    if (jsonConfigured) {
      lp.cfg.json = self.argv.configFile.parser.json
    }
    if (self.argv.includeOriginalLine !== undefined) {
      lp.cfg.originalLine = self.argv.includeOriginalLine
    }
    self.cli()
  })
  self.eventEmitter.once('input.stdin.end', function endOnStdinEof (line, context) {
    self.terminateRequest = true
    self.terminateReason = 'stdin closed'
  })

  self.tid = setInterval(function () {
    if (self.terminateRequest && Date.now() - self.lastParsedTS > 1500) {
      self.terminate(self.terminateReason)
      clearInterval(self.tid)
    }
  }, 1000)
  self.tid.unref()

  self.eventEmitter.on('data.raw', function parseRaw (line, context) {
    self.lastParsedTS = Date.now()
    var trimmedLine = line
    if (line && Buffer.byteLength(line, 'utf8') > self.argv.maxLogSize) {
      var cutMsg = new Buffer(self.argv.maxLogSize)
      cutMsg.write(line)
      trimmedLine = cutMsg.toString()
    }
    self.laStats.bytes = self.laStats.bytes + Buffer.byteLength(line, 'utf8')
    self.laStats.count++
    co(function * processInput () {
      for (var i = 0; i < self.inputFilter.length; i++) {
        trimmedLine = yield function (callback) {
          self.inputFilter[i].func(context.sourceName || self.argv.sourceName, self.inputFilter[i].config, trimmedLine, callback)
        }
      }
    }).then(function () {
      if (!trimmedLine) {
        return
      }
      self.la.parseLine(
        trimmedLine.replace(self.removeAnsiColor, ''),
        context.sourceName || self.argv.sourceName,
        function parserCb (err, data) {
          if (err && !data) {
            consoleLogger.error('error during parsing: ' + err.stack)
          }
          if (data) {
            var filteredData = data
            co(function * () {
              for (var i = 0; i < self.outputFilter.length; i++) {
                filteredData = yield function (callback) {
                  self.outputFilter[i].func(context, self.outputFilter[i].config, eventEmitter, filteredData, callback)
                }
              }
            }).then(function () {
              if (!filteredData) {
                return
              }
              if (context.enrichEvent) {
                Object.keys(context.enrichEvent).forEach(function (key) {
                  data[key] = context.enrichEvent[key]
                })
              }
              if (context.filter) {
                filteredData = context.filter(data, context)
              }
              if (filteredData) {
                self.eventEmitter.parsedEvent(filteredData, context)
              }
            }, function (e) {
              // consoleLogger.error(e.stack)
            })
          }
        })
    }, function (e) {
      // consoleLogger.error(e.stack)
    })
  })

  process.once('SIGINT', function () { self.terminate('SIGINT') })
  process.once('SIGQUIT', function () { self.terminate('SIGQUIT') })
  process.once('SIGTERM', function () { self.terminate('SIGTERM') })
  process.once('beforeExit', self.terminate)
}

LaCli.prototype.log = function (err, data) {
  if (err && (!data)) {
    this.laStats.emptyLines++
    return
  }
  if (!data) {
    return
  }
  if (this.argv.tokenMapper) {
    var tokenForSource = this.argv.tokenMapper.findToken([data.logSource]) || this.argv.index
    if (tokenForSource) {
      this.logToLogsene(tokenForSource, data['_type'] || 'logs', data)
    }
  } else {
    if (this.argv.index) {
      this.logToLogsene(this.argv.index, data['_type'] || 'logs', data)
    }
  }
}

LaCli.prototype.parseLine = function (line, sourceName, cbf) {
  if (!line && cbf) {
    return cbf(new Error('empty line passed to parseLine()'))
  }
  var trimmedLine = line
  var bufLength = Buffer.byteLength(line, 'utf8')
  if (line && bufLength > this.argv.maxLogSize) {
    var cutMsg = new Buffer(this.argv.maxLogSize)
    cutMsg.write(line)
    trimmedLine = cutMsg.toString()
  }
  this.laStats.bytes = this.laStats.bytes + bufLength
  this.laStats.count++
  this.la.parseLine(
    trimmedLine.replace(this.removeAnsiColor, ''),
    this.argv.sourceName || sourceName,
    cbf || this.log.bind(this))
}

LaCli.prototype.parseChunks = function (chunk, enc, callback) {
  this.parseLine(chunk.toString())
  callback()
}

LaCli.prototype.terminate = function (reason) {
  consoleLogger.log('terminate reason: ' + reason)
  if (this.argv.heroku && reason !== 'exitWorker') {
    return
  }
  if (this.argv.suppress) {
    this.laStats.printStats()
  }
  var terminateCounter = this.plugins.length
  function callBackWithATimeout (callback, timeout) {
    var run, timer
    run = function () {
      if (timer) {
        clearTimeout(timer)
        timer = null
        callback.apply(this, arguments)
      }
    }
    timer = setTimeout(run, timeout, 'timeout')
    return run
  }
  this.plugins.forEach(function pluginStop (p) {
    if (p.stop) {
      try {
        p.stop(callBackWithATimeout(function () {
          terminateCounter--
          if (terminateCounter === 0) {
            setTimeout(process.exit, 5000)
          }
        }, 10 * 1000 * 60))
      } catch (err) {
        consoleLogger.error('Error stopping plugin ' + err)
      }
    } else {
      terminateCounter--
      if (terminateCounter === 0) {
        setTimeout(process.exit, 5000)
      }
    }
  })
  if (!/stdin/.test(reason)) {
    setTimeout(process.exit, 10000)
  }
}

LaCli.prototype.cli = function () {
  if (this.argv.printStats || this.argv.verbose) {
    setInterval(this.laStats.printStats.bind(this.laStats), ((Number(this.argv.printStats)) || 60) * 1000).unref()
    this.laStats.printStats()
  }
}

if (require.main === module) {
  var logagent = new LaCli()
  if (logagent) {
    consoleLogger.log('Logagent initialized')
  }
} else {
  module.exports = LaCli
}
<|endoftext|>


<commit_before>var replaceBase64Images = require('./replaceBase64Images');
var crypto = require('crypto');

var plugin = function(mail, done) {
  if (!mail || !mail.data || !mail.data.html) {
    return done();
  }

  mail.resolveContent(mail.data, 'html', function(err, html) {
    if (err) return done(err);

    var attachments = {};

    html = replaceBase64Images(html, function(mimeType, base64) {
      if (attachments[base64]) return attachments[base64].cid;

      var randomCid = crypto.randomBytes(8).toString('hex');

      attachments[base64] = {
        contentType: mimeType,
        cid: randomCid,
        content: base64,
        encoding: 'base64',
        contentDisposition: 'inline'
      };
      return randomCid;
    });

    mail.data.html = html;

    if (!mail.data.attachments) mail.data.attachments = [];

    Object.keys(attachments).forEach(function(cid) {
      mail.data.attachments.push(attachments[cid]);
    });

    done();
  });
};

module.exports = plugin;
<commit_msg>add ability to set CID prefix which might be useful for  email parsing, usage: smtpTransport.use('compile', inlineBase64({ cidPrefix: 'cidPrefix_' }));<commit_after>var replaceBase64Images = require('./replaceBase64Images');
var crypto = require('crypto');

var plugin = function(options) {
  options = options || {};
  return function(mail, done) {
    if (!mail || !mail.data || !mail.data.html) {
      return done();
    }

    mail.resolveContent(mail.data, 'html', function(err, html) {
      if (err) return done(err);

      var attachments = {};

      html = replaceBase64Images(html, function(mimeType, base64) {
        if (attachments[base64]) return attachments[base64].cid;

        var randomCid = (options.cidPrefix || '') + crypto.randomBytes(8).toString('hex');

        attachments[base64] = {
          contentType: mimeType,
          cid: randomCid,
          content: base64,
          encoding: 'base64',
          contentDisposition: 'inline'
        };
        return randomCid;
      });

      mail.data.html = html;

      if (!mail.data.attachments) mail.data.attachments = [];

      Object.keys(attachments).forEach(function(cid) {
        mail.data.attachments.push(attachments[cid]);
      });

      done();
    });
  }
};

module.exports = plugin;
<|endoftext|>


<commit_before>import _set from "lodash/set"

let request = require("request-promise");
let cheerio = require("cheerio");

let config = {
    server: {
        host: "https://us.battle.net",
        region: "en"
    },
    general: {
        debug: false
    }
}

// -- private functions

function debug (message) {
    if (config.general.debug) return console.log(message);
}

function query_topic (forumName, topicID) {
    let options = {
        uri: `${config.server.host}/forums/${config.server.region}/${forumName}/topic/${topicID}`,
        transform: cheerio.load
    };

    debug(`querying ${options.uri}`);

    return query_topic_functions(request(options).catch(debug));
}

function query_topic_functions (requestPromise) {
    return {
        data: () => {
            return requestPromise.then(($) => {
                result = $("section.Topic").data("topic");
                // console.log($("section.Topic > div.Topic-content > div.TopicPost").html());
            });
        }
    }
}

// -- exported functions

export function set (name, value) {
    _set(config, name, value);
}

export function query (name, value) {
    return {
        topic: query_topic
    };
}
<commit_msg>Post function now available<commit_after>import _set from "lodash/set"

let request = require("request-promise");
let cheerio = require("cheerio");

let config = {
    server: {
        host: "https://us.battle.net",
        region: "en"
    },
    general: {
        debug: true
    }
}

// -- private functions

function debug (message) {
    if (config.general.debug) return console.log(message);
}

function query_topic_request_resphandlr (response) {
    debug(`resp statuscode ${response.statusCode}`);

    if (response.statusCode == 302) {
        throw new Error("The requested topic couldn't be found. Please check your forum_name and topic_id.");
    }

    if (response.statusCode != 200) {
        throw new Error(`The server returned HTTP status code ${response.statusCode} instead of 200, aborting`);
    }

    return cheerio.load(response.body);
}

function query_topic (forumName, topicID) {
    let options = {
        uri: `${config.server.host}/forums/${config.server.region}/${forumName}/topic/${topicID}`,
        followRedirect: false,
        resolveWithFullResponse: true
    };

    debug(`qury ${options.uri}`);

    return query_topic_functions(request(options).then(query_topic_request_resphandlr).then($ => {
        let pages = $("section.Topic div.Topic-container div.Topic-pagination--header a.Pagination-button--ordinal").length;

        if (pages > 1) {
            let requestPromises = [];

            for (let i = 2; i < pages + 1; i++) {
                let newOptions = options;

                if (options.uri.indexOf("?")) {
                    newOptions.uri = options.uri.split("?")[0] + `?page=${i}`;
                } else {
                    newOptions.uri = options.uri + `?page=${i}`
                }

                requestPromises.push(new Promise((resolve, reject) => {
                    debug(`qury ${newOptions.uri}`);
                    return request(newOptions).then(query_topic_request_resphandlr).then(resolve);
                }));
            }

            return Promise.all(requestPromises).then(values => {
                values.unshift($); // Add the first page to the result

                return values;
            });
        } else {
            return [$];
        }
    }));
}

function query_topic_functions (requestPromise) {
    return {
        data: () => {
            return requestPromise.then(pages => {
                return pages[0]("section.Topic").data("topic");
            });
        },
        posts: () => {
            return requestPromise.then(pages => {
                let posts = [];

                Array.prototype.forEach.call(pages, ($, pageIndex) => {
                    $("section.Topic > div.Topic-content > div.TopicPost").each((index, post) => {
                        let lastEditTime, createTime;

                        $("div.TopicPost-content > div.TopicPost-body > div.TopicPost-details > div.Timestamp-details > a", post).each((i, t) => {
                            if ($(t).text().trim() == "(Edited)") {
                                lastEditTime = $(t).data("tooltip-content");
                            } else {
                                createTime = $(t).data("tooltip-content");
                            }
                        });

                        posts.push({
                            id: $(post).data("topic-post").id,
                            position: pageIndex * 20 + index + 1,
                            info: $(post).data("topic-post"),
                            attributes: $(post).data("topic"),
                            create_time: createTime,
                            lastEditTime: lastEditTime,
                            isBlizzardPost: $(post).hasClass("TopicPost--blizzard"),
                            url: config.server.host + $("div.TopicPost-content > div.TopicPost-body > div.TopicPost-details span.Dropdown-item", post).data("clipboard-text"),
                            content: $("div.TopicPost-content > div.TopicPost-body div.TopicPost-bodyContent", post).html()
                        });
                    });
                });

                return posts;
            });
        }
    }
}

// -- exported functions

export function set (name, value) {
    _set(config, name, value);
}

export function query (name, value) {
    return {
        topic: query_topic
    };
}

query().topic("bnet",16716831607).posts().then((info) => {
    debug(info)
})<|endoftext|>


<commit_before>#!/usr/bin/env node

/**
 * Set the title.
 */

process.title = 'node-gyp'

/**
 * Module dependencies.
 */

var gyp = require('../lib/node-gyp')
  , inspect = require('util').inspect
  , ansi = require('ansi')
  , cursor = ansi(process.stdout)

/**
 * Process and execute the selected command.
 */

var prog = gyp()
prog.parseArgv(process.argv)

/**
 * Set up logging handlers.
 */

prog.on('info', function () {
  cursor.fg.green().write('info ')
        .fg.grey().write(arguments[0] + ' ')
        .reset()
  for (var i=1, l=arguments.length; i<l; i++) {
    cursor.write(arguments[i] + ' ')
  }
  cursor.write('\n')
})

if (prog.opts.verbose) {
  prog.on('verbose', function () {
    cursor.fg.blue().write('verbose ')
          .fg.grey().write(arguments[0] + ' ')
          .reset()
    for (var i=1, l=arguments.length; i<l; i++) {
      cursor.write(inspect(arguments[i]) + ' ')
    }
    cursor.write('\n')
  })
}

prog.on('spawn', function (command, args, proc) {
  cursor.fg.magenta().write('spawn ')
        .fg.grey().write(command + ' ')
        .reset().write(args.join(' ') + '\n')

  proc.stdout.pipe(process.stdout, { end: false })
  proc.stderr.pipe(process.stderr, { end: false })
})

/**
 * Process and execute the selected command.
 */

if (!prog.command) {
  return prog.usageAndExit()
}

prog.commands[prog.command](prog.argv, function (err) {
  if (err) throw err
})

<commit_msg>Use inspect() on the 'spawn' event args.<commit_after>#!/usr/bin/env node

/**
 * Set the title.
 */

process.title = 'node-gyp'

/**
 * Module dependencies.
 */

var gyp = require('../lib/node-gyp')
  , inspect = require('util').inspect
  , ansi = require('ansi')
  , cursor = ansi(process.stdout)

/**
 * Process and execute the selected command.
 */

var prog = gyp()
prog.parseArgv(process.argv)

/**
 * Set up logging handlers.
 */

prog.on('info', function () {
  cursor.fg.green().write('info ')
        .fg.grey().write(arguments[0] + ' ')
        .reset()
  for (var i=1, l=arguments.length; i<l; i++) {
    cursor.write(arguments[i] + ' ')
  }
  cursor.write('\n')
})

if (prog.opts.verbose) {
  prog.on('verbose', function () {
    cursor.fg.blue().write('verbose ')
          .fg.grey().write(arguments[0] + ' ')
          .reset()
    for (var i=1, l=arguments.length; i<l; i++) {
      cursor.write(inspect(arguments[i]) + ' ')
    }
    cursor.write('\n')
  })
}

prog.on('spawn', function (command, args, proc) {
  cursor.fg.magenta().write('spawn ')
        .fg.grey().write(command + ' ')
        .reset().write(inspect(args) + '\n')

  proc.stdout.pipe(process.stdout, { end: false })
  proc.stderr.pipe(process.stderr, { end: false })
})

/**
 * Process and execute the selected command.
 */

if (!prog.command) {
  return prog.usageAndExit()
}

prog.commands[prog.command](prog.argv, function (err) {
  if (err) throw err
})

<|endoftext|>


<commit_before>const Client = require('castv2-client').Client
const EventEmitter = require('events')
const debug = require('debug')('Device')
const utils = require('./utils')

// Supported Apps
const Youtube = require('../apps/youtube/Youtube')
const DefaultMediaReceiver = require('../apps/default/DefaultMediaReceiver')

const SUPPORTED_APPS = {
  [Youtube.APP_ID]: Youtube,
  [DefaultMediaReceiver.APP_ID]: DefaultMediaReceiver
}
const SUPPORTED_APP_IDS = Object.keys(SUPPORTED_APPS)

/**
 * Device
 * @param {Object} opts               Options
 * @param {String} opts.name          name
 * @param {String} opts.friendlyName  Friendly name
 * @param {String} opts.host          IP address
 */
class Device extends EventEmitter {
  constructor (opts) {
    super()
    this.name = opts.name
    this.friendlyName = opts.friendlyName
    this.host = opts.host

    this.client = null
  }

  _connect (callback) {
    // Use a fresh client
    // TODO: reconsider reusing the client
    if (this.client) this.client.close()

    this.client = new Client()

    // TODO: might be useful for callback?
    this.client.on('error', (err) => {
      debug('Error: %s', err.message)
      this.client.close()
    })

    debug('Connecting to device: ' + this.host)

    this.client.connect(this.host, () => {
      debug('Connected')
      this.emit('connected')

      callback()
    })
  }

  _launch (app, callback) {
    if (!this.client) return

    debug('Launching app...')

    this.client.getSessions((err, sessions) => {
      if (err) return callback(err)

      const filtered = sessions.filter((session) => {
        return (app)
          ? session.appId === app.APP_ID
          : SUPPORTED_APP_IDS.includes(session.appId)
      })
      const session = filtered.shift()

      if (session) {
        app = app || SUPPORTED_APPS[session.appId]
        this.client.join(session, app, callback)
      } else if (app) {
        this.client.launch(app, callback)
      } else {
        callback(new Error('no session started'))
      }
    })
  }

  _playYoutube (link, callback) {
    this._launch(Youtube, (err, player) => {
      if (err) return callback(err)

      this._onLaunch(player)

      this.player.load(link, (err, status) => {
        callback(err, status)
      })
    })
  }

  _playMedia (media, opts, callback) {
    this._launch(DefaultMediaReceiver, (err, player) => {
      if (err) return callback(err)

      this._onLaunch(player)

      this.player.load(media, opts, (err, status) => {
        callback(err, status)
      })
    })
  }

  _onLaunch (player) {
    this.player = player

    this.player.on('status', (status) => {
      debug('PlayerState = %s', status.playerState)
      this.emit('status', status)

      // Emit 'finished'
      if (status.playerState === 'IDLE' && status.idleReason === 'FINISHED') {
        this.emit('finished')
      }
    })
  }

  play (resource, opts, callback) {
    // Handle optional parameters
    if (typeof opts === 'function') {
      callback = opts
      opts = {}
    }
    if (!opts) opts = {}
    if (!callback) callback = noop

    this._connect(() => {
      // Identify resource
      resource = resource.v || resource

      const videoId = utils.getYoutubeId(resource)
      if (videoId) {
        this._playYoutube(videoId, callback)
      } else {
        this._playMedia(resource, opts, callback)
      }
    })
  }

  _tryJoin (callback) {
    // We are already connected
    if (this.client) return callback()

    this._connect(() => {
      this._launch(null, (err, player) => {
        if (err) return callback(err)

        this._onLaunch(player)

        callback()
      })
    })
  }

  getStatus (callback) {
    this._tryJoin((err) => {
      if (err) return callback(err)

      this.player.getStatus(callback)
    })
  }

  seekTo (newCurrentTime, callback) {
    this._tryJoin((err) => {
      if (err) return callback(err)

      this.player.seek(newCurrentTime, callback)
    })
  }

  seek (seconds, callback) {
    this._tryJoin((err) => {
      if (err) return callback(err)

      this.getStatus((err, status) => {
        if (err) return callback(err)
        const newCurrentTime = status.currentTime + seconds
       this.seekTo(newCurrentTime, callback)
      })
    })
  }

  pause (callback) {
    this._tryJoin((err) => {
      if (err) return callback(err)

      this.player.pause(callback)
    })
  }

  unpause (callback) {
    this._tryJoin((err) => {
      if (err) return callback(err)

      this.player.play(callback)
    })
  }

  resume (callback) {
    this._tryJoin((err) => {
      if (err) return callback(err)

      this.unpause(callback)
    })
  }

  setVolume (volume, callback) {
    this._tryJoin((err) => {
      if (err) return callback(err)

      this.client.setVolume({ level: volume }, callback)
    })
  }

  stop (callback) {
    this._tryJoin((err) => {
      if (err) return callback(err)

      this.player.stop(callback)
    })
  }

  setVolumeMuted (muted, callback) {
    this._tryJoin((err) => {
      if (err) return callback(err)

      this.client.setVolume({ muted: muted }, callback)
    })
  }

  subtitlesOff (callback) {
    this._tryJoin((err) => {
      if (err) return callback(err)

      this.player.media.sessionRequest({
        type: 'EDIT_TRACKS_INFO',
        activeTrackIds: []
      }, callback)
    })
  }

  changeSubtitles (subId, callback) {
    this._tryJoin((err) => {
      if (err) return callback(err)

      this.player.media.sessionRequest({
        type: 'EDIT_TRACKS_INFO',
        activeTrackIds: [subId]
      }, callback)
    })
  }

  changeSubtitlesSize (fontScale, callback) {
    this._tryJoin((err) => {
      if (err) return callback(err)

      if (!this.player.subtitlesStyle) return callback(new Error('Subtitle styles not defined'))

      this.player.subtitlesStyle.fontScale = fontScale
      this.player.media.sessionRequest({
        type: 'EDIT_TRACKS_INFO',
        textTrackStyle: this.player.subtitlesStyle
      }, callback)
    })
  }

  close (callback) {
    if (!callback) callback = noop

    if (!this.client) return

    this.client.stop(this.player, () => {
      this.client.close()
      this.client = null
      debug('Device closed')

      callback()
    })
  }
}

function noop () {}

module.exports = Device
<commit_msg>Add noop callbacks<commit_after>const Client = require('castv2-client').Client
const EventEmitter = require('events')
const debug = require('debug')('Device')
const utils = require('./utils')

// Supported Apps
const Youtube = require('../apps/youtube/Youtube')
const DefaultMediaReceiver = require('../apps/default/DefaultMediaReceiver')

const SUPPORTED_APPS = {
  [Youtube.APP_ID]: Youtube,
  [DefaultMediaReceiver.APP_ID]: DefaultMediaReceiver
}
const SUPPORTED_APP_IDS = Object.keys(SUPPORTED_APPS)

/**
 * Device
 * @param {Object} opts               Options
 * @param {String} opts.name          name
 * @param {String} opts.friendlyName  Friendly name
 * @param {String} opts.host          IP address
 */
class Device extends EventEmitter {
  constructor (opts) {
    super()
    this.name = opts.name
    this.friendlyName = opts.friendlyName
    this.host = opts.host

    this.client = null
  }

  _connect (callback) {
    // Use a fresh client
    // TODO: reconsider reusing the client
    if (this.client) this.client.close()

    this.client = new Client()

    // TODO: might be useful for callback?
    this.client.on('error', (err) => {
      debug('Error: %s', err.message)
      this.client.close()
    })

    debug('Connecting to device: ' + this.host)

    this.client.connect(this.host, () => {
      debug('Connected')
      this.emit('connected')

      callback()
    })
  }

  _launch (app, callback) {
    if (!this.client) return

    debug('Launching app...')

    this.client.getSessions((err, sessions) => {
      if (err) return callback(err)

      const filtered = sessions.filter((session) => {
        return (app)
          ? session.appId === app.APP_ID
          : SUPPORTED_APP_IDS.includes(session.appId)
      })
      const session = filtered.shift()

      if (session) {
        app = app || SUPPORTED_APPS[session.appId]
        this.client.join(session, app, callback)
      } else if (app) {
        this.client.launch(app, callback)
      } else {
        callback(new Error('no session started'))
      }
    })
  }

  _playYoutube (link, callback) {
    this._launch(Youtube, (err, player) => {
      if (err) return callback(err)

      this._onLaunch(player)

      this.player.load(link, (err, status) => {
        callback(err, status)
      })
    })
  }

  _playMedia (media, opts, callback) {
    this._launch(DefaultMediaReceiver, (err, player) => {
      if (err) return callback(err)

      this._onLaunch(player)

      this.player.load(media, opts, (err, status) => {
        callback(err, status)
      })
    })
  }

  _onLaunch (player) {
    this.player = player

    this.player.on('status', (status) => {
      debug('PlayerState = %s', status.playerState)
      this.emit('status', status)

      // Emit 'finished'
      if (status.playerState === 'IDLE' && status.idleReason === 'FINISHED') {
        this.emit('finished')
      }
    })
  }

  play (resource, opts, callback) {
    // Handle optional parameters
    if (typeof opts === 'function') {
      callback = opts
      opts = {}
    }
    if (!opts) opts = {}
    if (!callback) callback = noop

    this._connect(() => {
      // Identify resource
      resource = resource.v || resource

      const videoId = utils.getYoutubeId(resource)
      if (videoId) {
        this._playYoutube(videoId, callback)
      } else {
        this._playMedia(resource, opts, callback)
      }
    })
  }

  _tryJoin (callback) {
    // We are already connected
    if (this.client) return callback()

    this._connect(() => {
      this._launch(null, (err, player) => {
        if (err) return callback(err)

        this._onLaunch(player)

        callback()
      })
    })
  }

  getStatus (callback) {
    if (!callback) callback = noop

    this._tryJoin((err) => {
      if (err) return callback(err)

      this.player.getStatus(callback)
    })
  }

  seekTo (newCurrentTime, callback) {
    if (!callback) callback = noop

    this._tryJoin((err) => {
      if (err) return callback(err)

      this.player.seek(newCurrentTime, callback)
    })
  }

  seek (seconds, callback) {
    if (!callback) callback = noop

    this._tryJoin((err) => {
      if (err) return callback(err)

      this.getStatus((err, status) => {
        if (err) return callback(err)
        const newCurrentTime = status.currentTime + seconds
       this.seekTo(newCurrentTime, callback)
      })
    })
  }

  pause (callback) {
    if (!callback) callback = noop

    this._tryJoin((err) => {
      if (err) return callback(err)

      this.player.pause(callback)
    })
  }

  unpause (callback) {
    if (!callback) callback = noop

    this._tryJoin((err) => {
      if (err) return callback(err)

      this.player.play(callback)
    })
  }

  resume (callback) {
    if (!callback) callback = noop

    this._tryJoin((err) => {
      if (err) return callback(err)

      this.unpause(callback)
    })
  }

  setVolume (volume, callback) {
    if (!callback) callback = noop

    this._tryJoin((err) => {
      if (err) return callback(err)

      this.client.setVolume({ level: volume }, callback)
    })
  }

  stop (callback) {
    if (!callback) callback = noop

    this._tryJoin((err) => {
      if (err) return callback(err)

      this.player.stop(callback)
    })
  }

  setVolumeMuted (muted, callback) {
    if (!callback) callback = noop

    this._tryJoin((err) => {
      if (err) return callback(err)

      this.client.setVolume({ muted: muted }, callback)
    })
  }

  subtitlesOff (callback) {
    if (!callback) callback = noop

    this._tryJoin((err) => {
      if (err) return callback(err)

      this.player.media.sessionRequest({
        type: 'EDIT_TRACKS_INFO',
        activeTrackIds: []
      }, callback)
    })
  }

  changeSubtitles (subId, callback) {
    if (!callback) callback = noop

    this._tryJoin((err) => {
      if (err) return callback(err)

      this.player.media.sessionRequest({
        type: 'EDIT_TRACKS_INFO',
        activeTrackIds: [subId]
      }, callback)
    })
  }

  changeSubtitlesSize (fontScale, callback) {
    if (!callback) callback = noop

    this._tryJoin((err) => {
      if (err) return callback(err)

      if (!this.player.subtitlesStyle) return callback(new Error('Subtitle styles not defined'))

      this.player.subtitlesStyle.fontScale = fontScale
      this.player.media.sessionRequest({
        type: 'EDIT_TRACKS_INFO',
        textTrackStyle: this.player.subtitlesStyle
      }, callback)
    })
  }

  close (callback) {
    if (!callback) callback = noop

    if (!this.client) return

    this.client.stop(this.player, () => {
      this.client.close()
      this.client = null
      debug('Device closed')

      callback()
    })
  }
}

function noop () {}

module.exports = Device
<|endoftext|>


<commit_before>var ImagePreloader = require('./ImagePreloader/');
var Overlay = require('./Overlay/');

function QueryLoader(element, options) {
    'use strict';
    this.element = element;
    this.options = options;
    this.done = false;
    this.maxTimeout = null;

    //The default options
    this.defaultOptions = {
        onComplete: function() {},
        backgroundColor: "#000",
        barColor: "#fff",
        overlayId: 'qLoverlay',
        barHeight: 1,
        percentage: false,
        deepSearch: true,
        minimumTime: 300,
        maxTime: 10000,
        fadeOutTime: 1000
    };

    //children
    this.overlay = null;
    this.preloader = null;

    if (element !== null) {
        this.init();
    }
}

QueryLoader.prototype.init = function () {
    'use strict';
    this.extend(this.options, this.defaultOptions);

    if (typeof this.element !== "undefined") {
        this.createOverlay();
        this.createPreloader();
        this.startMaxTimeout();
    }
};

QueryLoader.prototype.extend = function (base, adding) {
    'use strict';
    if (typeof base === "undefined") {
        base = {};
    }

    for (var property in adding) {
        if (adding.hasOwnProperty(property)) {
            base[property] = adding[property];
        }
    }

    return base;
};

QueryLoader.prototype.startMaxTimeout = function () {
    "use strict";
    this.maxTimeout = window.setTimeout(this.doneLoading.bind(this), this.options.maxTime);
};

QueryLoader.prototype.createOverlay = function () {
    'use strict';
    this.overlay = new Overlay(this.element);
    this.overlay.init();
};

QueryLoader.prototype.createPreloader = function () {
    'use strict';
    this.preloader = new ImagePreloader(this);

    this.preloader.findAndPreload(this.element);
};

QueryLoader.prototype.updateProgress = function (done, total) {
    "use strict";
    this.overlay.updateProgress(((done / total) * 100), this.options.minimumTime);

    if (done === total && this.done === false) {
        window.clearTimeout(this.maxTimeout);
        window.setTimeout(this.doneLoading.bind(this), this.options.minimumTime);
    }
};

QueryLoader.prototype.doneLoading = function () {
    "use strict";
    window.clearTimeout(this.maxTimeout);
    this.done = true;
    this.overlay.element.style.opacity = 0;
};

module.exports = QueryLoader;<commit_msg>onComplete callback<commit_after>var ImagePreloader = require('./ImagePreloader/');
var Overlay = require('./Overlay/');

function QueryLoader(element, options) {
    'use strict';
    this.element = element;
    this.options = options;
    this.done = false;
    this.maxTimeout = null;

    //The default options
    this.defaultOptions = {
        onComplete: function() {},
        backgroundColor: "#000",
        barColor: "#fff",
        overlayId: 'qLoverlay',
        barHeight: 1,
        percentage: false,
        deepSearch: true,
        minimumTime: 300,
        maxTime: 10000,
        fadeOutTime: 1000
    };

    //children
    this.overlay = null;
    this.preloader = null;

    if (element !== null) {
        this.init();
    }
}

QueryLoader.prototype.init = function () {
    'use strict';
    this.extend(this.options, this.defaultOptions);

    if (typeof this.element !== "undefined") {
        this.createOverlay();
        this.createPreloader();
        this.startMaxTimeout();
    }
};

QueryLoader.prototype.extend = function (base, adding) {
    'use strict';
    if (typeof base === "undefined") {
        base = {};
    }

    for (var property in adding) {
        if (adding.hasOwnProperty(property)) {
            base[property] = adding[property];
        }
    }

    return base;
};

QueryLoader.prototype.startMaxTimeout = function () {
    "use strict";
    this.maxTimeout = window.setTimeout(this.doneLoading.bind(this), this.options.maxTime);
};

QueryLoader.prototype.createOverlay = function () {
    'use strict';
    this.overlay = new Overlay(this.element);
    this.overlay.init();
};

QueryLoader.prototype.createPreloader = function () {
    'use strict';
    this.preloader = new ImagePreloader(this);

    this.preloader.findAndPreload(this.element);
};

QueryLoader.prototype.updateProgress = function (done, total) {
    "use strict";
    this.overlay.updateProgress(((done / total) * 100), this.options.minimumTime);

    if (done === total && this.done === false) {
        window.clearTimeout(this.maxTimeout);
        window.setTimeout(this.doneLoading.bind(this), this.options.minimumTime);
    }
};

QueryLoader.prototype.doneLoading = function () {
    "use strict";
    window.clearTimeout(this.maxTimeout);
    this.done = true;

    this.overlay.element.style.opacity = 0;

    window.setTimeout(this.options.onComplete, this.options.fadeOutTime);
};

module.exports = QueryLoader;<|endoftext|>


<commit_before>import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import { Form, Label, Input } from 'semantic-ui-react';

class FormInput extends Component {
  componentWillReceiveProps(nextProps) {
    const {
      input: { value, onChange },
      meta: { visited },
      defaultValue
    } = nextProps;
    if (!value && !visited && defaultValue) onChange(defaultValue);
  }

  render() {
    const {
      input,
      meta: { error, touched },
      readOnly,
      width,
      label,
      defaultValue,
      required,
      ...rest
    } = this.props;

    const hasError = touched && Boolean(error);

    if (readOnly) {
      return {input.value};
    }

    return (
      <Form.Field error={hasError} width={width || 10} required={required}>
        {label && {label}}
        <Input {...input} {...rest} />

        {hasError && {error}}
      </Form.Field>
    );
  }
}

export default FormInput;
<commit_msg>allow for configuration of error position<commit_after>import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import { Form, Label, Input } from 'semantic-ui-react';

class FormInput extends Component {
  componentWillReceiveProps(nextProps) {
    const {
      input: { value, onChange },
      meta: { visited },
      defaultValue
    } = nextProps;
    if (!value && !visited && defaultValue) onChange(defaultValue);
  }

  render() {
    const {
      input,
      meta: { error, touched },
      readOnly,
      width,
      label,
      defaultValue,
      required,
      errorPosition,
      ...rest
    } = this.props;

    const hasError = touched && Boolean(error);

    if (readOnly) {
      return {input.value.toLocaleString()};
    }

    return (
      <Form.Field error={hasError} width={width || 10} required={required}>
        {label && {label}}
        <Input {...input} {...rest} value={input.value || ''} />

        {hasError && (
           25 ? 0 : 5
                  }
                : {}
            }
          >
            {error}

        )}
      </Form.Field>
    );
  }
}

export default FormInput;
<|endoftext|>


<commit_before>/*
 * Copyright 2016 Pascal Mainini
 * Licensed under MIT license, see included file LICENSE or
 * http://opensource.org/licenses/MIT
 */

/**
 * This module implements the direct "algorithm" which simply passes a single
 * or multiple modexps directly to the server without any blinding or checking.
 * Functions in this module should not be called directly, instead calls should
 * be made via FamodulusClient-object.
 * @see famodulus-client/client
 * @module famodulus-client/direct
 */

'use strict';

var util = require('./util.js');

/**
 * Directly calculate a single modexp on the server.
 * Required options are 'server' with the full path to the famodulus modexp-API and 'brief',
 * indicating if a brief response is desired.
 * @param {String} base - Base of the modexp
 * @param {String} exponent - Exponent of the modexp
 * @param {String} modulus - Modulus of the modexp
 * @param {Object} options - Options, requires 'server' and 'brief'
 * @returns {Promise} A promise to the remote modexp calculation.
 */
function direct (base, exponent, modulus, options) {
  return util.request({brief: options.brief, modexps: [{b: base, e: exponent, m: modulus}]}, options.server).then(result => result[0]);
}

/**
 * Directly calculate one or multiple modexp(s) on the server.
 * Required options are 'server' with the full path to the famodulus modexp-API and 'brief',
 * indicating if a brief response is desired.
 * @param {Object[]} modexps - An Array with modexps in the form {b:'base', e:'exponent', m:'modulus'} (values may be undefined)
 * @param {Object} defaults - An Object with properties 'base', 'exponent' and 'modulus' to be used as default if omitted in any modexp (values may be undefined)
 * @param {Object} options - Options, requires 'server' and 'brief'
 * @returns {Promise} A promise to the remote modexp calculation.
 */
function directs (modexps, defaults, options) {
  return util.request({brief: options.brief, b: defaults.base, e: defaults.exponent, m: defaults.modulus, modexps: modexps}, options.server);
}

module.exports = {direct: direct, directs: directs};
<commit_msg>documentation<commit_after>/*
 * Copyright 2016 Pascal Mainini
 * Licensed under MIT license, see included file LICENSE or
 * http://opensource.org/licenses/MIT
 */

/**
 * This module implements the direct "algorithm" which simply passes a single
 * or multiple modexps directly to the server without any blinding or checking.
 * Functions in this module should not be called directly, instead calls should
 * be made via FamodulusClient-object.
 * @see famodulus-client/client
 * @module famodulus-client/direct
 */

'use strict';

var util = require('./util.js');

/**
 * Directly calculate a single modexp on the server.
 * Required options are 'server' with the full path to the famodulus modexp-API and 'brief',
 * indicating if a brief response is desired.
 * @param {String} base - Base of the modexp (hexadecimal)
 * @param {String} exponent - Exponent of the modexp (hexadecimal)
 * @param {String} modulus - Modulus of the modexp (hexadecimal)
 * @param {Object} options - Options, requires 'server' and 'brief'
 * @returns {Promise} A promise to the remote modexp calculation.
 */
function direct (base, exponent, modulus, options) {
  return util.request({brief: options.brief, modexps: [{b: base, e: exponent, m: modulus}]}, options.server).then(result => result[0]);
}

/**
 * Directly calculate one or multiple modexp(s) on the server.
 * Required options are 'server' with the full path to the famodulus modexp-API and 'brief',
 * indicating if a brief response is desired.
 * @param {Object[]} modexps - An Array with modexps in the form {b:'base', e:'exponent', m:'modulus'} (values are hexadecimal and may be undefined)
 * @param {Object} defaults - An Object with properties 'base', 'exponent' and 'modulus' to be used as default if omitted in any modexp (values are hexadecimal and may be undefined)
 * @param {Object} options - Options, requires 'server' and 'brief'
 * @returns {Promise} A promise to the remote modexp calculation.
 */
function directs (modexps, defaults, options) {
  return util.request({brief: options.brief, b: defaults.base, e: defaults.exponent, m: defaults.modulus, modexps: modexps}, options.server);
}

module.exports = {direct: direct, directs: directs};
<|endoftext|>


<commit_before>import RynoObject from "./object";
import RynoArray from "./array";
import Model from "./model";
import * as util from "./util";

export default Object.assign({Object: RynoObject, Array: RynoArray, Model}, util);
<commit_msg>Makes Array.A helper available on Ryno object.<commit_after>import RynoObject from "./object";
import RynoArray from "./array";
import Model from "./model";
import * as util from "./util";

export default Object.assign({Object: RynoObject, Array: RynoArray, A: RynoArray.A, Model}, util);
<|endoftext|>