<commit_before>var express = require('express');
var bodyParser = require('body-parser');
var pg = require('pg');

var app = express();
app.use(bodyParser.json());

// Create link to Angular build directory
var distDir = __dirname + "/dist/";
app.use(express.static(distDir));

pg.defaults.ssl = true;

// Connect to the database before starting the application server
pg.connect(process.env.DATABASE_URL, function(err, client) {
    if (err) {
        console.log(err);
        process.exit(1);
    }

    console.log("Database connection ready");

    // Initialize the app
    var server = app.listen(process.env.PORT || 8080, function() {
        var port = server.address().port;
        console.log("App now running on port", port);
    });
});

app.get("/:id", function(req, res) {
    console.log("opening page for charging session (id = " + req.params.id + ")");
    res.sendfile('./src/index.html');
});

// REST API DEFINED BELOW

// Generic error handler used by all endpoints
function handleError(res, reason, message, code) {
    console.log("ERROR: " + reason);
    res.status(code || 500).json({"error": message});
}

/*
 * "/api/charging-session"
 *   GET: find all charging sessions
 *   POST: create a new charging session
 */
app.get("/api/charging-session", function(req, res) {
    console.log("find all charging sessions");
    pg.client.query('SELECT * FROM test', function(err, results) {
        if (err) {
            handleError(res, err.message, "failed to get charging sessions");
        }
        if (results.rows.length === 0) {
            handleError(res, err.message, "failed to get charging sessions", 404);
        }
        res.status(200).json(results);
    });
});

app.post("/api/charging-session", function(req, res) {
    console.log("create new charging session");
    res.status(200).json({"url": "https://ev-charging.herokuapp.com/qvn10hvg"});
});

/*
 * "/api/charging-session/:id"
 *   GET: find charging session by id
 *   PUT: update charging session by id
 *   DELETE: delete charging session by id
 */
app.get("/api/charging-session/:id", function(req, res) {
    console.log("find charging session by id");
    res.status(200).json();
});

app.put("/api/charging-session/:id", function(req, res) {
    console.log("update charging session by id");
    res.status(200).json();
});

app.delete("/api/charging-session/:id", function(req, res) {
    console.log("delete charging session by id");
    res.status(200).json();
});

/*
generateUniqueId() {
    return guid().substring(8);
}
*/
<commit_msg>debug request<commit_after>var express = require('express');
var bodyParser = require('body-parser');
var pg = require('pg');

var app = express();
app.use(bodyParser.json());

// Create link to Angular build directory
var distDir = __dirname + "/dist/";
app.use(express.static(distDir));

pg.defaults.ssl = true;

// Connect to the database before starting the application server
pg.connect(process.env.DATABASE_URL, function(err, client) {
    if (err) {
        console.log(err);
        process.exit(1);
    }

    console.log("database connection ready");

    // Initialize the app
    var server = app.listen(process.env.PORT || 8080, function() {
        var port = server.address().port;
        console.log("app now running on port " + port);
    });
});

app.get("/:id", function(req, res) {
    console.log("opening page for charging session (id = " + req.params.id + ")");
    res.sendfile('./src/index.html');
});

// REST API DEFINED BELOW

// Generic error handler used by all endpoints
function handleError(res, reason, message, code) {
    console.log("ERROR: " + reason);
    res.status(code || 500).json({"error": message});
}

/*
 * "/api/charging-session"
 *   GET: find all charging sessions
 *   POST: create a new charging session
 */
app.get("/api/charging-session", function(req, res) {
    console.log("find all charging sessions");
    client.query('SELECT * FROM test', function(err, results) {
        if (err) {
            handleError(res, err.message, "failed to get charging sessions");
        }
        if (results.rows.length === 0) {
            handleError(res, err.message, "failed to get charging sessions", 404);
        }
        res.status(200).json(results);
    });
});

app.post("/api/charging-session", function(req, res) {
    console.log("create new charging session");
    res.status(200).json({"url": "https://ev-charging.herokuapp.com/qvn10hvg"});
});

/*
 * "/api/charging-session/:id"
 *   GET: find charging session by id
 *   PUT: update charging session by id
 *   DELETE: delete charging session by id
 */
app.get("/api/charging-session/:id", function(req, res) {
    console.log("find charging session by id");
    res.status(200).json();
});

app.put("/api/charging-session/:id", function(req, res) {
    console.log("update charging session by id");
    res.status(200).json();
});

app.delete("/api/charging-session/:id", function(req, res) {
    console.log("delete charging session by id");
    res.status(200).json();
});

/*
generateUniqueId() {
    return guid().substring(8);
}
*/
<|endoftext|>


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

const fs = require('fs');
const path = require('path');
const rimraf = require('rimraf');
const webpack = require('webpack');
const env = require('node-env-file');
const createConfig = require(path.resolve(__dirname, '..', 'runtime', 'webpack-config'));
env(path.resolve(process.cwd(), '.env'), { raise: false });

const command = process.argv[process.argv.length - 1];

/*const exists = (p, throwError) => {
  const doesExist = fs.existsSync(path.resolve(appRootDir.get(), `${p}.js`)) || fs.existsSync(path.resolve(appRootDir.get(), p, 'index.js'));
  if (!doesExist && throwError) throw new Error(`${p} not found in your root dir!`);
  else if (!doesExist) console.log(`${p} not found in your root dir!`);
  return doesExist;
};

exists('server');
exists('app', true);

require('babel-register')({
  presets: [
    [require.resolve('babel-preset-env'), { targets: { node: true } }],
    require.resolve('babel-preset-stage-3'),
    require.resolve('babel-preset-react'),
  ],
  only: [
    path.resolve(__dirname, '..', 'tools'),
    path.resolve(__dirname, '..', 'src'),
    path.resolve(__dirname, '..', 'config'),
    path.resolve(appRootDir.get(), 'universally.config.js')
  ],
});*/

if (['start', 'build'].includes(command)) {
  process.env.NODE_ENV = 'production';
}

if (command === 'dev') {
  const notifier = require('node-notifier');

  const port = parseInt(process.env.PORT, 10);
  const devPort = port + 2;

  const compiler = webpack([
    createConfig({ target: 'node', mode: 'development', port, devPort, ssr: process.env.SSR != 'false' }),
    createConfig({ target: 'web', mode: 'development', port, devPort }),
  ]);
  compiler.compilers[0].watch({ aggregateTimeout: 300 }, (err, compilation) => {
    if (err) return console.log('[webpack] error:', err);
    const stats = compilation.stats || [compilation];
    console.log('[webpack] the following asset bundles were built:');
    stats.forEach((c) => console.log(c.toString()));
    notifier.notify('Ready');
  });
  var webpackDevServer = require('webpack-dev-server');
  var server = new webpackDevServer(compiler.compilers[1], {
    host: 'localhost',
    port: devPort,
    historyApiFallback: true,
    hot: true,
    stats: {
      colors: true,
      hash: false,
      version: false,
      timings: false,
      assets: false,
      chunks: false,
      modules: false,
      reasons: false,
      children: false,
      source: false,
      errors: true,
      errorDetails: true,
      warnings: false,
      publicPath: false
    },
  });
  server.listen(devPort);
} else if (command === 'build') {
  rimraf.sync(path.resolve(process.cwd(), 'build'));
  process.env.NODE_ENV = 'production';
  const compiler = webpack([
    createConfig({ target: 'node', mode: 'production' }),
    createConfig({ target: 'web', mode: 'production' })
  ]);
  compiler.run((err, compilation) => {
    if (err) return console.log('[webpack] error:', err);
    const stats = compilation.stats || [compilation];
    console.log('[webpack] the following asset bundles were built:');
    stats.forEach((c) => console.log(c.toString()));
    stats.forEach((c) => fs.writeFileSync(path.resolve(__dirname, `stats.json`), c.toJson()));
  });
} else if (command.indexOf('build:') === 0) {
  const target = command.split(':')[1];
  rimraf.sync(path.resolve(process.cwd(), 'build', target));
  process.env.NODE_ENV = 'production';
  const compiler = webpack([
    createConfig({ target: target, mode: 'production' })
  ]);
  compiler.run((err, compilation) => {
    if (err) return console.log('[webpack] error:', err);
    const stats = compilation.stats || [compilation];
    console.log('[webpack] the following asset bundles were built:');
    stats.forEach((c) => console.log(c.toString()));
    stats.forEach((c) => fs.writeFileSync(path.resolve(__dirname, `stats.json`), c.toJson()));
  });
} else if (command === 'start') {
  require(path.resolve(process.cwd(), 'build', 'node', 'main'))
}
<commit_msg>throw errors on build<commit_after>#!/usr/bin/env node

const fs = require('fs');
const path = require('path');
const rimraf = require('rimraf');
const webpack = require('webpack');
const env = require('node-env-file');
const createConfig = require(path.resolve(__dirname, '..', 'runtime', 'webpack-config'));
env(path.resolve(process.cwd(), '.env'), { raise: false });

const command = process.argv[process.argv.length - 1];

/*const exists = (p, throwError) => {
  const doesExist = fs.existsSync(path.resolve(appRootDir.get(), `${p}.js`)) || fs.existsSync(path.resolve(appRootDir.get(), p, 'index.js'));
  if (!doesExist && throwError) throw new Error(`${p} not found in your root dir!`);
  else if (!doesExist) console.log(`${p} not found in your root dir!`);
  return doesExist;
};

exists('server');
exists('app', true);

require('babel-register')({
  presets: [
    [require.resolve('babel-preset-env'), { targets: { node: true } }],
    require.resolve('babel-preset-stage-3'),
    require.resolve('babel-preset-react'),
  ],
  only: [
    path.resolve(__dirname, '..', 'tools'),
    path.resolve(__dirname, '..', 'src'),
    path.resolve(__dirname, '..', 'config'),
    path.resolve(appRootDir.get(), 'universally.config.js')
  ],
});*/

if (['start', 'build'].includes(command)) {
  process.env.NODE_ENV = 'production';
}

if (command === 'dev') {
  const notifier = require('node-notifier');

  const port = parseInt(process.env.PORT, 10);
  const devPort = port + 2;

  const compiler = webpack([
    createConfig({ target: 'node', mode: 'development', port, devPort, ssr: process.env.SSR != 'false' }),
    createConfig({ target: 'web', mode: 'development', port, devPort }),
  ]);
  compiler.compilers[0].watch({ aggregateTimeout: 300 }, (err, compilation) => {
    if (err) return console.log('[webpack] error:', err);
    const stats = compilation.stats || [compilation];
    console.log('[webpack] the following asset bundles were built:');
    stats.forEach((c) => console.log(c.toString()));
    notifier.notify('Ready');
  });
  var webpackDevServer = require('webpack-dev-server');
  var server = new webpackDevServer(compiler.compilers[1], {
    host: 'localhost',
    port: devPort,
    historyApiFallback: true,
    hot: true,
    stats: {
      colors: true,
      hash: false,
      version: false,
      timings: false,
      assets: false,
      chunks: false,
      modules: false,
      reasons: false,
      children: false,
      source: false,
      errors: true,
      errorDetails: true,
      warnings: false,
      publicPath: false
    },
  });
  server.listen(devPort);
} else if (command === 'build') {
  rimraf.sync(path.resolve(process.cwd(), 'build'));
  process.env.NODE_ENV = 'production';
  const compiler = webpack([
    createConfig({ target: 'node', mode: 'production' }),
    createConfig({ target: 'web', mode: 'production' })
  ]);
  compiler.run((err, compilation) => {
    if (err) throw err;
    const stats = compilation.stats || [compilation];
    console.log('[webpack] the following asset bundles were built:');
    stats.forEach((c) => fs.writeFileSync(path.resolve(__dirname, `stats.json`), c.toJson()));
    stats.forEach((c) => console.log(c.toString()));
  });
} else if (command.indexOf('build:') === 0) {
  const target = command.split(':')[1];
  rimraf.sync(path.resolve(process.cwd(), 'build', target));
  process.env.NODE_ENV = 'production';
  const compiler = webpack([
    createConfig({ target: target, mode: 'production' })
  ]);
  compiler.run((err, compilation) => {
    if (err) throw err;
    const stats = compilation.stats || [compilation];
    console.log('[webpack] the following asset bundles were built:');
    stats.forEach((c) => console.log(c.toString()));
    stats.forEach((c) => fs.writeFileSync(path.resolve(__dirname, `stats.json`), c.toJson()));
  });
} else if (command === 'start') {
  require(path.resolve(process.cwd(), 'build', 'node', 'main'))
}
<|endoftext|>


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

Elm.Debugger = null;
Elm.debuggerAttach = function(module) {
  return {
    make: function(runtime) {
      var wrappedModule = debugModule(module, runtime);
      Elm.Debugger = debuggerInit(wrappedModule, runtime);
      if (parent.window) {
        var dispatch = function(_) {
          parent.window.postMessage("elmDebuggerInit", window.location.origin);
        };
        if (parent.window.document.readyState === "complete") {
          dispatch();
        }
        else {
          parent.window.addEventListener("load", dispatch);
        }
      }
      return wrappedModule.moduleInstance;
    }
  };
};

function debugModule(module, runtime) {
  var programPaused = false;
  var recordedEvents = [];
  var asyncCallbacks = [];

  function wrapNotify(id, v) {
    var timestep = Date.now();

    if (programPaused) {
      // ignore notify because we are stepping
    }
    else {
      runtime.notify(id, v, timestep);
      recordEvent(id, v, timestep);
    }
  };

  function wrapRunDelayed(func, delayMs) {
    return safeSetTimeout(func, delayMs);
  };

  function safeSetTimeout(func, delayMs) {
    var timerId = setTimeout(func, delayMs);
    asyncCallbacks.push({ func:func, delayMs:delayMs, timerId:timerId });
    return timerId;
  }

  function recordEvent(id, v, timestep) {
    recordedEvents.push({ id:id, value:v, timestep:timestep });
  }

  function clearAsyncCallbacks() {
    asyncCallbacks.forEach(function(timer) {
      clearTimeout(timer.timerId);
    });
  }

  function clearRecordedEvents() {
    recordedEvents = [];
  }

  function getRecordedEventsLength() {
    return recordedEvents.length;
  }

  function getRecordedEventAt(i) {
    return recordedEvents[i];
  }

  function setPaused(v) {
    programPaused = v;
  }

  function getPaused() {
    return programPaused;
  }

  var wrappedRuntime = {
    notify: wrapNotify,
    runDelayed: wrapRunDelayed,
    node: runtime.node,
    display: runtime.display,
    id: runtime.id,
    addListener: runtime.addListener,
    inputs: runtime.inputs
  };

  var moduleInstance = module.make(wrappedRuntime);
  var moduleNodes = flattenNodes(wrappedRuntime.inputs);

  return {
    moduleInstance: moduleInstance,
    moduleNodes: moduleNodes,
    initialNodeValues: saveNodeValues(moduleNodes),
    initialAsyncCallbacks: asyncCallbacks.slice(),
    // API functions
    clearAsyncCallbacks: clearAsyncCallbacks,
    clearRecordedEvents: clearRecordedEvents,
    getRecordedEventsLength: getRecordedEventsLength,
    getRecordedEventAt: getRecordedEventAt,
    getPaused: getPaused,
    setPaused: setPaused,
    tracePath: tracePathInit(runtime)
  };
}

function debuggerInit(debugModule, runtime) {
  var Signal = Elm.Signal.make(runtime);

  var tracePathNode = A2(Signal.lift, debugModule.tracePath.graphicsUpdate, debugModule.moduleInstance.main);
  runtime.node.parentNode.appendChild(debugModule.tracePath.canvas);

  var eventCounter = 0;

  function resetProgram() {
    debugModule.clearAsyncCallbacks();
    restoreNodeValues(debugModule.moduleNodes, debugModule.initialNodeValues);
    redrawGraphics();
  }

  function restartProgram() {
    resetProgram();
    debugModule.clearRecordedEvents();
    debugModule.initialAsyncCallbacks.forEach(function(timer) {
      var func = timer.func;
      func();
    });
  }

  function stepTo(index) {
    if (!debugModule.getPaused()) {
      debugModule.setPaused(true);
      resetProgram();
    }

    if (index < 0 || index > getMaxSteps()) {
      throw "Index out of bounds: " + index;
    }

    if (index < eventCounter) {
      resetProgram();
      eventCounter = 0;
    }

    assert(index >= eventCounter, "index must be bad");
    while (eventCounter < index) {
      var nextEvent = debugModule.getRecordedEventAt(eventCounter);
      runtime.notify(nextEvent.id, nextEvent.value, nextEvent.timestep);

      eventCounter += 1;
    }
    assert(eventCounter == index, "while loop didn't work");
  }

  function getMaxSteps() {
    return debugModule.getRecordedEventsLength() - 1;
  }

  function doPlayback(eventList) {
    var x = eventList.shift();
    var time = x[2];
    runtime.notify(x[0], x[1], x[2]);

    if (eventList.length > 0) {
      var delta = eventList[0][2] - time;
      setTimeout(function() { doPlayback(eventList); }, delta);
    }
  }

  function redrawGraphics() {
    var graphicsNode = debugModule.moduleInstance.main.kids[0];
    graphicsNode.recv(Date.now(), true, debugModule.moduleInstance.main.id);
  }

  var elmDebugger = {
      reset: resetProgram,
      restart: restartProgram,
      getMaxSteps: getMaxSteps,
      stepTo: stepTo
  };

  return elmDebugger;
}

function Point(x, y) {
  this.x = x;
  this.y = y;

  this.translate = function(x, y) {
    return new Point(this.x + x, this.y + y);
  }

  this.equals = function(p) {
    return this.x == p.x && this.y == p.y;
  }
}

function tracePathInit(runtime) {
  var List = Elm.List.make(runtime);
  var tracePathCanvas = createCanvas();
  var tracePositions = {};

  function findPositions(currentScene) {
    var positions = {};
    function processElement(elem, offset) {
      if (elem.element.ctor == "Custom" && elem.element.type == "Collage")
      {
        List.map(F2(processForm)(offset))(elem.element.model.forms);
      }
      else if (elem.element.ctor == "Image" && elem.props.debugTracePathId)
      {
        positions[elem.props.debugTracePathId] = new Point(offset.x, offset.y);
      }
    }

    function processForm(offset, form) {
      if (form.form.ctor == "FElement")
      {
        processElement(form.form._0, offset.translate(form.x, -form.y));
      }
    }

    processElement(currentScene, new Point(0, 0));
    return positions;
  }

  function appendPositions(positions) {
    for (var id in positions) {
      var pos = positions[id];
      if (tracePositions.hasOwnProperty(id)) {
        var points = tracePositions[id];
        if (!pos.equals(points[points.length-1])) {
          points.push(pos);
        }
      }
      else {
        tracePositions[id] = [pos];
      }
    }
  }

  function graphicsUpdate(currentScene) {
    var ctx = tracePathCanvas.getContext('2d');
    ctx.clearRect(0, 0, tracePathCanvas.width, tracePathCanvas.height);

    ctx.save();
    ctx.translate(ctx.canvas.width/2, ctx.canvas.height/2);
    appendPositions(findPositions(currentScene));
    for (var id in tracePositions)
    {
      ctx.beginPath();
      var points = tracePositions[id];
      for (var i=0; i < points.length; i++)
      {
        var p = points[i];
        if (i == 0) {
          ctx.moveTo(p.x, p.y);
        }
        else {
          ctx.lineTo(p.x, p.y);
        }
      }
    }
    ctx.lineWidth = 1;
    ctx.strokeStyle = "black";
    ctx.stroke();

    ctx.restore();
  }

  function clearTraces() {
    tracePositions = {};
  }

  return {
    graphicsUpdate: graphicsUpdate,
    canvas: tracePathCanvas,
    clearTraces: clearTraces
  }
}

function createCanvas() {
  var c = document.createElement('canvas');
  c.width = window.innerWidth;
  c.height = window.innerHeight;
  c.style.position = "absolute";
  c.style.top = "0";
  c.style.left = "0";
  return c;
}

function assert(bool, msg) {
  if (!bool) {
    throw "Assertion error: " + msg;
  }
}

function saveNodeValues(allNodes) {
  var nodeValues = [];

  allNodes.forEach(function(node) {
    nodeValues.push({ value: node.value, id: node.id });
  });

  return nodeValues;
};

function restoreNodeValues(allNodes, nodeStates) {
  assert(allNodes.length == nodeStates.length, "saved program state has wrong length");
  for (var i=0; i < allNodes.length; i++) {
    var node = allNodes[i];
    var state = nodeStates[i];
    assert(node.id == state.id, "the nodes moved position");

    node.value = state.value;
  }
}

function flattenNodes(nodes) {
  var treeReduce = function(prev, cur, i, arr) {
    var flatKids = cur.kids.reduce(treeReduce, []);
    flatKids.push(cur);
    return prev.concat(flatKids);
  }

  return nodes.reduce(treeReduce, []);
};

}());
<commit_msg>Debugger: pause and continue.<commit_after>
(function() {
'use strict';

Elm.Debugger = null;
Elm.debuggerAttach = function(module) {
  return {
    make: function(runtime) {
      var wrappedModule = debugModule(module, runtime);
      Elm.Debugger = debuggerInit(wrappedModule, runtime);
      if (parent.window) {
        var dispatch = function(_) {
          parent.window.postMessage("elmDebuggerInit", window.location.origin);
        };
        if (parent.window.document.readyState === "complete") {
          dispatch();
        }
        else {
          parent.window.addEventListener("load", dispatch);
        }
      }
      return wrappedModule.moduleInstance;
    }
  };
};

function debugModule(module, runtime) {
  var programPaused = false;
  var recordedEvents = [];
  var asyncCallbacks = [];

  function wrapNotify(id, v) {
    var timestep = Date.now();

    if (programPaused) {
      // ignore async events generated while playing back
      // or user events while program is paused
    }
    else {
      runtime.notify(id, v, timestep);
      recordEvent(id, v, timestep);
    }
  };

  function wrapRunDelayed(func, delayMs) {
    var cbObj = { func:func, delayMs:delayMs, timerId:0, executed:false };
    var timerId = setTimeout(function() {
        cbObj.executed = true;
        func();
      }, delayMs);
    cbObj.timerId = timerId;
    asyncCallbacks.push(cbObj);
    return timerId;
  }

  function recordEvent(id, v, timestep) {
    recordedEvents.push({ id:id, value:v, timestep:timestep });
  }

  function clearAsyncCallbacks() {
    asyncCallbacks.forEach(function(timer) {
      if (!timer.executed) {
        clearTimeout(timer.timerId);
      }
    });
  }

  function clearRecordedEvents() {
    recordedEvents = [];
  }

  function getRecordedEventsLength() {
    return recordedEvents.length;
  }

  function getRecordedEventAt(i) {
    return recordedEvents[i];
  }

  function setPaused(v) {
    programPaused = v;
    if (programPaused) {
      clearAsyncCallbacks();
    }
    else {
      executeCallbacks(asyncCallbacks);
    }
  }

  function getPaused() {
    return programPaused;
  }

  var wrappedRuntime = {
    notify: wrapNotify,
    runDelayed: wrapRunDelayed,
    node: runtime.node,
    display: runtime.display,
    id: runtime.id,
    addListener: runtime.addListener,
    inputs: runtime.inputs
  };

  var moduleInstance = module.make(wrappedRuntime);
  var moduleNodes = flattenNodes(wrappedRuntime.inputs);

  return {
    moduleInstance: moduleInstance,
    moduleNodes: moduleNodes,
    initialNodeValues: saveNodeValues(moduleNodes),
    initialAsyncCallbacks: asyncCallbacks.slice(),
    // API functions
    clearAsyncCallbacks: clearAsyncCallbacks,
    clearRecordedEvents: clearRecordedEvents,
    getRecordedEventsLength: getRecordedEventsLength,
    getRecordedEventAt: getRecordedEventAt,
    getPaused: getPaused,
    setPaused: setPaused,
    tracePath: tracePathInit(runtime)
  };
}

function debuggerInit(debugModule, runtime) {
  var Signal = Elm.Signal.make(runtime);

  var tracePathNode = A2(Signal.lift, debugModule.tracePath.graphicsUpdate, debugModule.moduleInstance.main);
  runtime.node.parentNode.appendChild(debugModule.tracePath.canvas);

  var eventCounter = 0;

  function resetProgram() {
    debugModule.clearAsyncCallbacks();
    restoreNodeValues(debugModule.moduleNodes, debugModule.initialNodeValues);
    redrawGraphics();
  }

  function restartProgram() {
    resetProgram();
    debugModule.clearRecordedEvents();
    executeCallbacks(debugModule.initialAsyncCallbacks);
  }

  function pauseProgram() {
    debugModule.setPaused(true);
  }

  function continueProgram() {
    if (debugModule.getPaused())
    {
      debugModule.setPaused(false);
    }
  }

  function stepTo(index) {
    if (!debugModule.getPaused()) {
      debugModule.setPaused(true);
      resetProgram();
    }

    if (index < 0 || index > getMaxSteps()) {
      throw "Index out of bounds: " + index;
    }

    if (index < eventCounter) {
      resetProgram();
      eventCounter = 0;
    }

    assert(index >= eventCounter, "index must be bad");
    while (eventCounter < index) {
      var nextEvent = debugModule.getRecordedEventAt(eventCounter);
      runtime.notify(nextEvent.id, nextEvent.value, nextEvent.timestep);

      eventCounter += 1;
    }
    assert(eventCounter == index, "while loop didn't work");
  }

  function getMaxSteps() {
    return debugModule.getRecordedEventsLength() - 1;
  }

  function doPlayback(eventList) {
    var x = eventList.shift();
    var time = x[2];
    runtime.notify(x[0], x[1], x[2]);

    if (eventList.length > 0) {
      var delta = eventList[0][2] - time;
      setTimeout(function() { doPlayback(eventList); }, delta);
    }
  }

  function redrawGraphics() {
    var graphicsNode = debugModule.moduleInstance.main.kids[0];
    graphicsNode.recv(Date.now(), true, debugModule.moduleInstance.main.id);
  }

  var elmDebugger = {
      restart: restartProgram,
      pause: pauseProgram,
      kontinue: continueProgram,
      getMaxSteps: getMaxSteps,
      stepTo: stepTo
  };

  return elmDebugger;
}

function Point(x, y) {
  this.x = x;
  this.y = y;

  this.translate = function(x, y) {
    return new Point(this.x + x, this.y + y);
  }

  this.equals = function(p) {
    return this.x == p.x && this.y == p.y;
  }
}

function tracePathInit(runtime) {
  var List = Elm.List.make(runtime);
  var tracePathCanvas = createCanvas();
  var tracePositions = {};

  function findPositions(currentScene) {
    var positions = {};
    function processElement(elem, offset) {
      if (elem.element.ctor == "Custom" && elem.element.type == "Collage")
      {
        List.map(F2(processForm)(offset))(elem.element.model.forms);
      }
      else if (elem.element.ctor == "Image" && elem.props.debugTracePathId)
      {
        positions[elem.props.debugTracePathId] = new Point(offset.x, offset.y);
      }
    }

    function processForm(offset, form) {
      if (form.form.ctor == "FElement")
      {
        processElement(form.form._0, offset.translate(form.x, -form.y));
      }
    }

    processElement(currentScene, new Point(0, 0));
    return positions;
  }

  function appendPositions(positions) {
    for (var id in positions) {
      var pos = positions[id];
      if (tracePositions.hasOwnProperty(id)) {
        var points = tracePositions[id];
        if (!pos.equals(points[points.length-1])) {
          points.push(pos);
        }
      }
      else {
        tracePositions[id] = [pos];
      }
    }
  }

  function graphicsUpdate(currentScene) {
    var ctx = tracePathCanvas.getContext('2d');
    ctx.clearRect(0, 0, tracePathCanvas.width, tracePathCanvas.height);

    ctx.save();
    ctx.translate(ctx.canvas.width/2, ctx.canvas.height/2);
    appendPositions(findPositions(currentScene));
    for (var id in tracePositions)
    {
      ctx.beginPath();
      var points = tracePositions[id];
      for (var i=0; i < points.length; i++)
      {
        var p = points[i];
        if (i == 0) {
          ctx.moveTo(p.x, p.y);
        }
        else {
          ctx.lineTo(p.x, p.y);
        }
      }
    }
    ctx.lineWidth = 1;
    ctx.strokeStyle = "black";
    ctx.stroke();

    ctx.restore();
  }

  function clearTraces() {
    tracePositions = {};
  }

  return {
    graphicsUpdate: graphicsUpdate,
    canvas: tracePathCanvas,
    clearTraces: clearTraces
  }
}

function executeCallbacks(callbacks) {
  callbacks.forEach(function(timer) {
    if (!timer.executed) {
      var func = timer.func;
      func();
    }
  });
}

function createCanvas() {
  var c = document.createElement('canvas');
  c.width = window.innerWidth;
  c.height = window.innerHeight;
  c.style.position = "absolute";
  c.style.top = "0";
  c.style.left = "0";
  return c;
}

function assert(bool, msg) {
  if (!bool) {
    throw "Assertion error: " + msg;
  }
}

function saveNodeValues(allNodes) {
  var nodeValues = [];

  allNodes.forEach(function(node) {
    nodeValues.push({ value: node.value, id: node.id });
  });

  return nodeValues;
};

function restoreNodeValues(allNodes, nodeStates) {
  assert(allNodes.length == nodeStates.length, "saved program state has wrong length");
  for (var i=0; i < allNodes.length; i++) {
    var node = allNodes[i];
    var state = nodeStates[i];
    assert(node.id == state.id, "the nodes moved position");

    node.value = state.value;
  }
}

function flattenNodes(nodes) {
  var treeReduce = function(prev, cur, i, arr) {
    var flatKids = cur.kids.reduce(treeReduce, []);
    flatKids.push(cur);
    return prev.concat(flatKids);
  }

  return nodes.reduce(treeReduce, []);
};

}());
<|endoftext|>


<commit_before>const path = require('path');
const rread = require('readdir-recursive');
const EventEmitter = require('events');
const Collection = require('discord.js').Collection;
const Command = require('./Command');
const Category = require('./Category');

/** @extends EventEmitter */
class CommandHandler extends EventEmitter {
    /**
     * Loads Commands and handles messages.
     * @param {Framework} framework - The Akairo framework.
     * @param {Object} options - Options from framework.
     */
    constructor(framework, options = {}){
        super();

        /**
         * The Akairo framework.
         * @readonly
         * @type {Framework}
         */
        this.framework = framework;

        /**
         * Directory to commands.
         * @readonly
         * @type {string}
         */
        this.directory = path.resolve(options.commandDirectory);

        /**
         * Whether or not the built-in pre-message inhibitors are disabled.
         * @type {boolean}
         */
        this.preInhibDisabled = !!options.disablePreInhib;

        /**
         * Whether or not the built-in post-message inhibitors are disabled.
         * @type {boolean}
         */
        this.postInhibDisabled = !!options.disablePostInhib;

        /**
         * Gets the prefix.
         * @type {function}
         */
        this.prefix = typeof options.prefix === 'function' ? options.prefix : () => options.prefix;

        /**
         * Gets if mentions are allowed for prefixing.
         * @type {function}
         */
        this.allowMention = typeof options.allowMention === 'function' ? options.allowMention : () => options.allowMention;

        /**
         * Commands loaded, mapped by ID to Command.
         * @type {Collection.<string, Command>}
         */
        this.commands = new Collection();

        /**
         * Command categories, mapped by ID to Category.
         * @type {Collection.<string, Category>}
         */
        this.categories = new Collection();

        let filepaths = rread.fileSync(this.directory);
        filepaths.forEach(filepath => {
            this.load(filepath);
        });
    }

    /**
     * Loads a Command.
     * @param {string} filepath - Path to file.
     */
    load(filepath){
        let command = require(filepath);

        if (!(command instanceof Command)) return;
        if (this.commands.has(command.id)) throw new Error(`Command ${command.id} already loaded.`);

        command.filepath = filepath;
        command.framework = this.framework;
        command.client = this.framework.client;
        command.commandHandler = this;

        this.commands.set(command.id, command);

        if (!this.categories.has(command.category)) this.categories.set(command.category, new Category(command.category));
        let category = this.categories.get(command.category);
        command.category = category;
        category.set(command.id, command);
    }

    /**
     * Adds a Command.
     * @param {string} filename - Filename to lookup in the directory. A .js extension is assumed.
     */
    add(filename){
        let files = rread.fileSync(this.directory);
        let filepath = files.find(file => file.endsWith(`${filename}.js`));

        if (!filepath){
            throw new Error(`File ${filename} not found.`);
        }

        this.load(filepath);
    }

    /**
     * Removes a Command.
     * @param {string} id - ID of the Command.
     */
    remove(id){
        let command = this.commands.get(id);
        if (!command) throw new Error(`Command ${id} does not exist.`);

        delete require.cache[require.resolve(command.filepath)];
        this.commands.delete(command.id);

        command.category.delete(command.id);
    }

    /**
     * Reloads a Command.
     * @param {string} id - ID of the Command.
     */
    reload(id){
        let command = this.commands.get(id);
        if (!command) throw new Error(`Command ${id} does not exist.`);

        let filepath = command.filepath;

        delete require.cache[require.resolve(command.filepath)];
        this.commands.delete(command.id);

        command.category.delete(command.id);

        this.load(filepath);
    }

    /**
     * Finds a command by alias.
     * @param {string} name - Alias to find with.
     * @returns {Command}
     */
    findCommand(name){
        return this.commands.find(command => {
            return command.aliases.some(a => a.toLowerCase() === name.toLowerCase());
        });
    }

    /**
     * Finds a category by name.
     * @param {string} name - Name to find with.
     * @returns {Category}
     */
    findCategory(name){
        return this.categories.find(category => {
            return category.id.toLowerCase() === name.toLowerCase();
        });
    }

    /**
     * Handles a Message.
     * @param {Message} message - Message to handle.
     */
    handle(message){
        if (!this.preInhibDisabled){
            if (message.author.id !== this.framework.client.user.id && this.framework.client.selfbot) return this.emit('messageBlocked', message, 'notSelf');
            if (message.author.id === this.framework.client.user.id && !this.framework.client.selfbot) return this.emit('messageBlocked', message, 'client');
            if (message.author.bot) return this.emit('messageBlocked', message, 'bot');
        }

        this.framework.inhibitorHandler.testMessage(message).then(() => {
            let prefix = this.prefix(message);
            let allowMention = this.allowMention(message);
            prefix = prefix.toLowerCase();
            let start;

            if (message.content.toLowerCase().startsWith(prefix)){
                start = prefix;
            } else
            if (allowMention){
                let mentionRegex = new RegExp(`^<@!?${this.framework.client.user.id}>`);
                let mentioned = message.content.match(mentionRegex);

                if (mentioned){
                    start = mentioned[0];
                } else {
                    return this.emit('messageInvalid', message);
                }
            } else {
                return this.emit('messageInvalid', message);
            }

            let firstWord = message.content.replace(start, '').search(/\S/) + start.length;
            let name = message.content.slice(firstWord).split(' ')[0];
            let command = this.findCommand(name);

            if (!command) return this.emit('messageInvalid', message);
            if (!command.enabled) return this.emit('commandDisabled', message, command);

            if (!this.postInhibDisabled){
                if (command.ownerOnly && message.author.id !== this.framework.client.ownerID) return this.emit('commandBlocked', message, command, 'owner');
                if (command.channelRestriction === 'guild' && !message.guild) return this.emit('commandBlocked', message, command, 'guild');
                if (command.channelRestriction === 'dm' && message.guild) return this.emit('commandBlocked', message, command, 'dm');
            }

            this.framework.inhibitorHandler.testCommand(message, command).then(() => {
                let content = message.content.slice(message.content.indexOf(name) + name.length + 1);
                let args = command.parse(content);

                this.emit('commandStarted', message, command);
                let end = Promise.resolve(command.exec(message, args));

                end.then(() => {
                    this.emit('commandFinished', message, command);
                }).catch(err => {
                    this.emit('commandFinished', message, command);
                    throw err;
                });
            }).catch(reason => {
                this.emit('commandBlocked', message, command, reason);
            });
        }).catch(reason => {
            this.emit('messageBlocked', message, reason);
        });
    }
}

module.exports = CommandHandler;

/**
 * Emitted when a message is blocked by a pre-message inhibitor. The built-in inhibitors are 'notSelf' (for selfbots), 'client', and 'bot'.
 * @event CommandHandler#messageBlocked
 * @param {Message} message - Message sent.
 * @param {string} reason - Reason for the block.
 */

/**
 * Emitted when a message does not start with the prefix or match a command.
 * @event CommandHandler#messageInvalid
 * @param {Message} message - Message sent.
 */

/**
 * Emitted when a command is found disabled.
 * @event CommandHandler#commandDisabled
 * @param {Message} message - Message sent.
 * @param {Command} command - Command found.
 */

/**
 * Emitted when a command is blocked by a post-message inhibitor. The built-in inhibitors are 'owner', 'guild', and 'dm'.
 * @event CommandHandler#commandBlocked
 * @param {Message} message - Message sent.
 * @param {Command} command - Command blocked.
 * @param {string} reason - Reason for the block.
 */

/**
 * Emitted when a command starts execution.
 * @event CommandHandler#commandStarted
 * @param {Message} message - Message sent.
 * @param {Command} command - Command executed.
 */

/**
 * Emitted when a command finishes execution.
 * @event CommandHandler#commandFinished
 * @param {Message} message - Message sent.
 * @param {Command} command - Command executed.
 */
<commit_msg>1 line<commit_after>const path = require('path');
const rread = require('readdir-recursive');
const EventEmitter = require('events');
const Collection = require('discord.js').Collection;
const Command = require('./Command');
const Category = require('./Category');

/** @extends EventEmitter */
class CommandHandler extends EventEmitter {
    /**
     * Loads Commands and handles messages.
     * @param {Framework} framework - The Akairo framework.
     * @param {Object} options - Options from framework.
     */
    constructor(framework, options = {}){
        super();

        /**
         * The Akairo framework.
         * @readonly
         * @type {Framework}
         */
        this.framework = framework;

        /**
         * Directory to commands.
         * @readonly
         * @type {string}
         */
        this.directory = path.resolve(options.commandDirectory);

        /**
         * Whether or not the built-in pre-message inhibitors are disabled.
         * @type {boolean}
         */
        this.preInhibDisabled = !!options.disablePreInhib;

        /**
         * Whether or not the built-in post-message inhibitors are disabled.
         * @type {boolean}
         */
        this.postInhibDisabled = !!options.disablePostInhib;

        /**
         * Gets the prefix.
         * @type {function}
         */
        this.prefix = typeof options.prefix === 'function' ? options.prefix : () => options.prefix;

        /**
         * Gets if mentions are allowed for prefixing.
         * @type {function}
         */
        this.allowMention = typeof options.allowMention === 'function' ? options.allowMention : () => options.allowMention;

        /**
         * Commands loaded, mapped by ID to Command.
         * @type {Collection.<string, Command>}
         */
        this.commands = new Collection();

        /**
         * Command categories, mapped by ID to Category.
         * @type {Collection.<string, Category>}
         */
        this.categories = new Collection();

        let filepaths = rread.fileSync(this.directory);
        filepaths.forEach(filepath => {
            this.load(filepath);
        });
    }

    /**
     * Loads a Command.
     * @param {string} filepath - Path to file.
     */
    load(filepath){
        let command = require(filepath);

        if (!(command instanceof Command)) return;
        if (this.commands.has(command.id)) throw new Error(`Command ${command.id} already loaded.`);

        command.filepath = filepath;
        command.framework = this.framework;
        command.client = this.framework.client;
        command.commandHandler = this;

        this.commands.set(command.id, command);

        if (!this.categories.has(command.category)) this.categories.set(command.category, new Category(command.category));
        let category = this.categories.get(command.category);
        command.category = category;
        category.set(command.id, command);
    }

    /**
     * Adds a Command.
     * @param {string} filename - Filename to lookup in the directory. A .js extension is assumed.
     */
    add(filename){
        let files = rread.fileSync(this.directory);
        let filepath = files.find(file => file.endsWith(`${filename}.js`));

        if (!filepath){
            throw new Error(`File ${filename} not found.`);
        }

        this.load(filepath);
    }

    /**
     * Removes a Command.
     * @param {string} id - ID of the Command.
     */
    remove(id){
        let command = this.commands.get(id);
        if (!command) throw new Error(`Command ${id} does not exist.`);

        delete require.cache[require.resolve(command.filepath)];
        this.commands.delete(command.id);

        command.category.delete(command.id);
    }

    /**
     * Reloads a Command.
     * @param {string} id - ID of the Command.
     */
    reload(id){
        let command = this.commands.get(id);
        if (!command) throw new Error(`Command ${id} does not exist.`);

        let filepath = command.filepath;

        delete require.cache[require.resolve(command.filepath)];
        this.commands.delete(command.id);

        command.category.delete(command.id);

        this.load(filepath);
    }

    /**
     * Finds a command by alias.
     * @param {string} name - Alias to find with.
     * @returns {Command}
     */
    findCommand(name){
        return this.commands.find(command => {
            return command.aliases.some(a => a.toLowerCase() === name.toLowerCase());
        });
    }

    /**
     * Finds a category by name.
     * @param {string} name - Name to find with.
     * @returns {Category}
     */
    findCategory(name){
        return this.categories.find(category => {
            return category.id.toLowerCase() === name.toLowerCase();
        });
    }

    /**
     * Handles a Message.
     * @param {Message} message - Message to handle.
     */
    handle(message){
        if (!this.preInhibDisabled){
            if (message.author.id !== this.framework.client.user.id && this.framework.client.selfbot) return this.emit('messageBlocked', message, 'notSelf');
            if (message.author.id === this.framework.client.user.id && !this.framework.client.selfbot) return this.emit('messageBlocked', message, 'client');
            if (message.author.bot) return this.emit('messageBlocked', message, 'bot');
        }

        this.framework.inhibitorHandler.testMessage(message).then(() => {
            let prefix = this.prefix(message).toLowerCase();
            let allowMention = this.allowMention(message);
            let start;

            if (message.content.toLowerCase().startsWith(prefix)){
                start = prefix;
            } else
            if (allowMention){
                let mentionRegex = new RegExp(`^<@!?${this.framework.client.user.id}>`);
                let mentioned = message.content.match(mentionRegex);

                if (mentioned){
                    start = mentioned[0];
                } else {
                    return this.emit('messageInvalid', message);
                }
            } else {
                return this.emit('messageInvalid', message);
            }

            let firstWord = message.content.replace(start, '').search(/\S/) + start.length;
            let name = message.content.slice(firstWord).split(' ')[0];
            let command = this.findCommand(name);

            if (!command) return this.emit('messageInvalid', message);
            if (!command.enabled) return this.emit('commandDisabled', message, command);

            if (!this.postInhibDisabled){
                if (command.ownerOnly && message.author.id !== this.framework.client.ownerID) return this.emit('commandBlocked', message, command, 'owner');
                if (command.channelRestriction === 'guild' && !message.guild) return this.emit('commandBlocked', message, command, 'guild');
                if (command.channelRestriction === 'dm' && message.guild) return this.emit('commandBlocked', message, command, 'dm');
            }

            this.framework.inhibitorHandler.testCommand(message, command).then(() => {
                let content = message.content.slice(message.content.indexOf(name) + name.length + 1);
                let args = command.parse(content);

                this.emit('commandStarted', message, command);
                let end = Promise.resolve(command.exec(message, args));

                end.then(() => {
                    this.emit('commandFinished', message, command);
                }).catch(err => {
                    this.emit('commandFinished', message, command);
                    throw err;
                });
            }).catch(reason => {
                this.emit('commandBlocked', message, command, reason);
            });
        }).catch(reason => {
            this.emit('messageBlocked', message, reason);
        });
    }
}

module.exports = CommandHandler;

/**
 * Emitted when a message is blocked by a pre-message inhibitor. The built-in inhibitors are 'notSelf' (for selfbots), 'client', and 'bot'.
 * @event CommandHandler#messageBlocked
 * @param {Message} message - Message sent.
 * @param {string} reason - Reason for the block.
 */

/**
 * Emitted when a message does not start with the prefix or match a command.
 * @event CommandHandler#messageInvalid
 * @param {Message} message - Message sent.
 */

/**
 * Emitted when a command is found disabled.
 * @event CommandHandler#commandDisabled
 * @param {Message} message - Message sent.
 * @param {Command} command - Command found.
 */

/**
 * Emitted when a command is blocked by a post-message inhibitor. The built-in inhibitors are 'owner', 'guild', and 'dm'.
 * @event CommandHandler#commandBlocked
 * @param {Message} message - Message sent.
 * @param {Command} command - Command blocked.
 * @param {string} reason - Reason for the block.
 */

/**
 * Emitted when a command starts execution.
 * @event CommandHandler#commandStarted
 * @param {Message} message - Message sent.
 * @param {Command} command - Command executed.
 */

/**
 * Emitted when a command finishes execution.
 * @event CommandHandler#commandFinished
 * @param {Message} message - Message sent.
 * @param {Command} command - Command executed.
 */
<|endoftext|>


<commit_before>var path = require('path');
var webpack = require('webpack');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  devtool: 'source-map',
  entry: {
    app: './lib/index.js'
  },
  output: {
    filename: '[name].min.js',
    path: path.join(__dirname, 'dist'),
    publicPath: ''
  },
  plugins: [
    new webpack.optimize.OccurenceOrderPlugin(),
    new webpack.NoErrorsPlugin(),
    new webpack.DefinePlugin({
      'process.env': {
        'NODE_ENV': JSON.stringify('production')
      },
      '__DEVTOOLS__': false
    }),
    new webpack.optimize.UglifyJsPlugin({
      compressor: {
        warnings: false
      }
    }),
    new ExtractTextPlugin('app.css', { allChunks: true }),
    new HtmlWebpackPlugin({
      title: 'Redux React Router Async Example',
      filename: 'index.html',
      template: 'index.template.html',
      favicon: path.join(__dirname, 'assets/images/favicon.ico')
    })
  ],
  module: {
    loaders: [
      { test: /\.css$/, loader: ExtractTextPlugin.extract('style-loader', 'css-loader!cssnext-loader') },
      { test: /\.js$/, loaders: ['babel'], include: path.join(__dirname, 'lib') }
    ]
  },
  cssnext: {
    browsers: 'last 2 versions'
  }
};<commit_msg>No source maps for production bundle<commit_after>var path = require('path');
var webpack = require('webpack');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  entry: {
    app: './lib/index.js'
  },
  output: {
    filename: '[name].min.js',
    path: path.join(__dirname, 'dist'),
    publicPath: ''
  },
  plugins: [
    new webpack.optimize.OccurenceOrderPlugin(),
    new webpack.NoErrorsPlugin(),
    new webpack.DefinePlugin({
      'process.env': {
        'NODE_ENV': JSON.stringify('production')
      },
      '__DEVTOOLS__': false
    }),
    new webpack.optimize.UglifyJsPlugin({
      compressor: {
        warnings: false
      }
    }),
    new ExtractTextPlugin('app.css', { allChunks: true }),
    new HtmlWebpackPlugin({
      title: 'Redux React Router Async Example',
      filename: 'index.html',
      template: 'index.template.html',
      favicon: path.join(__dirname, 'assets/images/favicon.ico')
    })
  ],
  module: {
    loaders: [
      { test: /\.css$/, loader: ExtractTextPlugin.extract('style-loader', 'css-loader!cssnext-loader') },
      { test: /\.js$/, loaders: ['babel'], include: path.join(__dirname, 'lib') }
    ]
  },
  cssnext: {
    browsers: 'last 2 versions'
  }
};<|endoftext|>


<commit_before>function HelpManager() {
    /* Outlets */
    this.help = $("#help-input"); // The input where the user writes what he wants.
    this.helpButton = $("#help-button"); // The help button.
    this.helpDisplayer = $("#help-input-displayer"); // The div that contains all the help divs.
    this.resultsContainer = $("#help-results-container"); // Will contain the HTML results container.

    /* Variables */
    this.helpSubjects = [ // Subjects concerned by the help, check messages.json in _locales to get the localized values.
        "Headers",
        "Bold",
        "Italic",
        "BoldItalic",
        "OrderedLists",
        "UnorderedLists",
        "InlineStyleLinks",
        "ReferenceStyleLinks",
        "InlineStyleImages",
        "ReferenceStyleImages",
        "Code",
        "Blockquotes",
        "InlineHTML",
        "HorizontalRules",
        "LineBreaks",
        "Tables",
        "Question"
    ];

    /* Events */
    $(document).click($.proxy(function(e) {
        if ($(e.target).closest("#help-button").length && this.helpDisplayer.hasClass("hidden")) { // Click on the help button with the help input hidden.
            this.reset();
            this.helpDisplayer.removeClass("hidden"); // Show the help input.
            this.help.focus(); // Focus in the help input.
        } else if (!this.helpDisplayer.hasClass("hidden") && !$(e.target).closest("#help-input-displayer").length) { // The user doesn't click on the help input nor help results (with help displayed).
            this.resultsContainer.addClass("hidden"); // Hide the results container
            this.helpDisplayer.addClass("hidden"); // Hide the help input.
        }
    }, this));

    Mousetrap.bind(["ctrl+h"], $.proxy(function(e) { // Ctrl+h = display the help.
        this.helpButton.click();
        return false;
    }, this));

    this.help.keyup($.proxy(function(e){ // The user press echap, we quit the help.
        if (e.keyCode == 27) {
            this.helpButton.click();
        }
    }, this));
    this.help.on("input propertychange", $.proxy(function(e) { this.searchAnswers(); }, this)); // Launch the help when something is typed on the input.

    $("#result-switch-1, #result-switch-2, #result-switch-3").on("click", $.proxy(function(e) { // Makes a switch when the user clicks it.
        this.switch(e.target.id.substr(e.target.id.length - 1));
    }, this));
}

HelpManager.prototype = {
    constructor: HelpManager,

    /* Return the minimum length in the user language. */
    localizedMinLength: function() {
        switch (chrome.i18n.getUILanguage()) {
            case "zh_CN":
                return 2;
            default:
                return 3;
        }
    },

    /* Reset the help. */
    reset: function() {
        this.help.val(""); /* Empty the input with help */
        this.resetAnswerDivs(1); /* Doesn't show answers because there is nothing to search */
    },

    /* Reset the answers div startign at the parameter begin.
     * Begin: the first div to empty.
     */
    resetAnswerDivs: function(begin) {
        for (var i = begin; i <= 3; i++) { // i <= 3 because we only have 3 divs with help.
            if ($("#answer-" + i).html() === "") { // If the help div is empty.
                i = 3; // End of the loop.
            } else {
                /* Reset the div. */
                $("#answer-" + i).html("");
                $("#result-" + i).attr("class", "result");
                $("#example-" + i).html("");
            }
        }
    },

    /* Looks for help the user wants. */
    searchAnswers: function () {
        if (this.help.val().length === 0) { // Nothing in the input.
            this.resultsContainer.attr("class", "hidden"); // Hide the results container, there is nothing in it if there is nothing written in the help input.
            this.resetAnswerDivs(3);
        }
        else {
            if (this.help.val().length < this.localizedMinLength()) { // Less than three characters in the input, we're not showing help.
                this.resultsContainer.attr("class", "one-result no-result"); // We only show one div to encourage the user.
                this.resetAnswerDivs(2); // We reset the two other divs.
                switch (this.localizedMinLength() - this.help.val().length) {
                case 2:
                    $("#answer-1").html(chrome.i18n.getMessage("msgTwoMoreCharacters")); // Only one character, user has to give two more characters.
                    break;
                case 1:
                    $("#answer-1").html(chrome.i18n.getMessage("msgOneMoreCharacter")); // Only two characters, user has to give one more character.
                    break;
                }
            } else {
                var maxAnswers = 0; // Reset the number of answers that can be diplayed (max: 3)
                var loc = chrome.i18n; // Shortcut for the localized strings.
                var arr = this.helpSubjects; // Shortcut for the array of subjects.
                for (var i = 0; i < arr.length && maxAnswers < 3; i++) { // A line = a syntax, this loop runs through each line.
                    var j = 0;
                    var wordSearched = "help" + arr[i]; // Get the subhect of help.
                    while (loc.getMessage(wordSearched + j) !== "") { // A subject can have different words describing it, we are checking each of them.
                        if (loc.getMessage(wordSearched + j).toLowerCase().indexOf(this.help.val().toLowerCase()) > -1) { // Everything in lower case to help the condition.
                            var term = loc.getMessage(wordSearched + j); // What is searched.
                            var result = loc.getMessage(wordSearched + "Result"); // The result of the search.
                            var example = loc.getMessage(wordSearched + "Example"); // The example of the search.
                            var wordPos = loc.getMessage(wordSearched + j).toLowerCase().indexOf(this.help.val().toLowerCase());
                            $("#answer-" + (maxAnswers + 1)).html("
" + term.substring(0, wordPos) + "" + term.substr(wordPos, this.help.val().length) + "" + term.substring(wordPos + this.help.val().length) + "
" + result); // Put the answer in the appropriate div.
                            document.getElementById("example-" + (maxAnswers + 1)).innerHTML = example; // Put the answer in the appropriate div.
                            maxAnswers++; // We display 3 answers, e.g. if the user types "bol" we display the results for "bold" and "bold italic".
                            break;
                        }
                        j++; // We don't want to display many times the same thing if a subject has different words describing it.
                    }
                }
                switch (maxAnswers) {
                case 0: // Nothing found.
                    $("#answer-1").html(chrome.i18n.getMessage("msgNoHelpFound")); // Show that we have not find an answer.
                    this.resultsContainer.attr("class", "one-result no-result"); // We only show one resuult.
                    this.resetAnswerDivs(2); // We hide the two other divs.
                    break;
                case 1: // One answer found.
                    this.resultsContainer.attr("class", "one-result");
                    this.resetAnswerDivs(2);
                    break;
                case 2: // Two answers found.
                    this.resultsContainer.attr("class", "two-results");
                    this.resetAnswerDivs(3);
                    break;
                case 3: // Three answers found, maximum number possible at the same time.
                    this.resultsContainer.attr("class", "three-results");
                    break;
                }
            }
        }
        this.setResultsHeight(); // Depending on the answer, the size of each div will change.
    },

    /* Change the height of each answer div depending on the content. */
    setResultsHeight: function() {
        var totalHeight = 0;
        for (var i = 1; i <= 3; i++) {// Check all the results, depending on the number of results
            if ($("#answer-" + i).html() !== "") {
                $("#result-" + i).css("display", "block");
                if ($("#answer-" + i).outerHeight() >= $("#example-" + i).outerHeight())  { // The eight of the answer is bigger than the example.
                    $("#result-" + i).css("height", $("#answer-" + i).outerHeight() + "px"); // Set the div's height as the answer's height.
                } else {
                    $("#result-" + i).css("height", $("#example-" + i).outerHeight() + "px");
                }
                totalHeight += $("#result-" + i).outerHeight(); // Add the height of the current result to the total height
            }
            else {
                $("#result-" + i).css("height", 0);
                $("#result-" + i).css("display", "none");
            }
        }
        this.resultsContainer.css("height", totalHeight + "px"); // Set the resultContainer's height to be the total height.
    },

    /* Switch between example and result */
    switch: function(resultNumber) {
        $("#result-" + resultNumber).toggleClass("switched");
        this.help.focus();
    }
};
<commit_msg>getUILanguage in chinese return zh-CN<commit_after>function HelpManager() {
    /* Outlets */
    this.help = $("#help-input"); // The input where the user writes what he wants.
    this.helpButton = $("#help-button"); // The help button.
    this.helpDisplayer = $("#help-input-displayer"); // The div that contains all the help divs.
    this.resultsContainer = $("#help-results-container"); // Will contain the HTML results container.

    /* Variables */
    this.helpSubjects = [ // Subjects concerned by the help, check messages.json in _locales to get the localized values.
        "Headers",
        "Bold",
        "Italic",
        "BoldItalic",
        "OrderedLists",
        "UnorderedLists",
        "InlineStyleLinks",
        "ReferenceStyleLinks",
        "InlineStyleImages",
        "ReferenceStyleImages",
        "Code",
        "Blockquotes",
        "InlineHTML",
        "HorizontalRules",
        "LineBreaks",
        "Tables",
        "Question"
    ];

    /* Events */
    $(document).click($.proxy(function(e) {
        if ($(e.target).closest("#help-button").length && this.helpDisplayer.hasClass("hidden")) { // Click on the help button with the help input hidden.
            this.reset();
            this.helpDisplayer.removeClass("hidden"); // Show the help input.
            this.help.focus(); // Focus in the help input.
        } else if (!this.helpDisplayer.hasClass("hidden") && !$(e.target).closest("#help-input-displayer").length) { // The user doesn't click on the help input nor help results (with help displayed).
            this.resultsContainer.addClass("hidden"); // Hide the results container
            this.helpDisplayer.addClass("hidden"); // Hide the help input.
        }
    }, this));

    Mousetrap.bind(["ctrl+h"], $.proxy(function(e) { // Ctrl+h = display the help.
        this.helpButton.click();
        return false;
    }, this));

    this.help.keyup($.proxy(function(e){ // The user press echap, we quit the help.
        if (e.keyCode == 27) {
            this.helpButton.click();
        }
    }, this));
    this.help.on("input propertychange", $.proxy(function(e) { this.searchAnswers(); }, this)); // Launch the help when something is typed on the input.

    $("#result-switch-1, #result-switch-2, #result-switch-3").on("click", $.proxy(function(e) { // Makes a switch when the user clicks it.
        this.switch(e.target.id.substr(e.target.id.length - 1));
    }, this));
}

HelpManager.prototype = {
    constructor: HelpManager,

    /* Return the minimum length in the user language. */
    localizedMinLength: function() {
        switch (chrome.i18n.getUILanguage()) {
            case "zh-CN":
                return 2;
            default:
                return 3;
        }
    },

    /* Reset the help. */
    reset: function() {
        this.help.val(""); /* Empty the input with help */
        this.resetAnswerDivs(1); /* Doesn't show answers because there is nothing to search */
    },

    /* Reset the answers div startign at the parameter begin.
     * Begin: the first div to empty.
     */
    resetAnswerDivs: function(begin) {
        for (var i = begin; i <= 3; i++) { // i <= 3 because we only have 3 divs with help.
            if ($("#answer-" + i).html() === "") { // If the help div is empty.
                i = 3; // End of the loop.
            } else {
                /* Reset the div. */
                $("#answer-" + i).html("");
                $("#result-" + i).attr("class", "result");
                $("#example-" + i).html("");
            }
        }
    },

    /* Looks for help the user wants. */
    searchAnswers: function () {
        if (this.help.val().length === 0) { // Nothing in the input.
            this.resultsContainer.attr("class", "hidden"); // Hide the results container, there is nothing in it if there is nothing written in the help input.
            this.resetAnswerDivs(3);
        }
        else {
            if (this.help.val().length < this.localizedMinLength()) { // Less than three characters in the input, we're not showing help.
                this.resultsContainer.attr("class", "one-result no-result"); // We only show one div to encourage the user.
                this.resetAnswerDivs(2); // We reset the two other divs.
                switch (this.localizedMinLength() - this.help.val().length) {
                case 2:
                    $("#answer-1").html(chrome.i18n.getMessage("msgTwoMoreCharacters")); // Only one character, user has to give two more characters.
                    break;
                case 1:
                    $("#answer-1").html(chrome.i18n.getMessage("msgOneMoreCharacter")); // Only two characters, user has to give one more character.
                    break;
                }
            } else {
                var maxAnswers = 0; // Reset the number of answers that can be diplayed (max: 3)
                var loc = chrome.i18n; // Shortcut for the localized strings.
                var arr = this.helpSubjects; // Shortcut for the array of subjects.
                for (var i = 0; i < arr.length && maxAnswers < 3; i++) { // A line = a syntax, this loop runs through each line.
                    var j = 0;
                    var wordSearched = "help" + arr[i]; // Get the subhect of help.
                    while (loc.getMessage(wordSearched + j) !== "") { // A subject can have different words describing it, we are checking each of them.
                        if (loc.getMessage(wordSearched + j).toLowerCase().indexOf(this.help.val().toLowerCase()) > -1) { // Everything in lower case to help the condition.
                            var term = loc.getMessage(wordSearched + j); // What is searched.
                            var result = loc.getMessage(wordSearched + "Result"); // The result of the search.
                            var example = loc.getMessage(wordSearched + "Example"); // The example of the search.
                            var wordPos = loc.getMessage(wordSearched + j).toLowerCase().indexOf(this.help.val().toLowerCase());
                            $("#answer-" + (maxAnswers + 1)).html("
" + term.substring(0, wordPos) + "" + term.substr(wordPos, this.help.val().length) + "" + term.substring(wordPos + this.help.val().length) + "
" + result); // Put the answer in the appropriate div.
                            document.getElementById("example-" + (maxAnswers + 1)).innerHTML = example; // Put the answer in the appropriate div.
                            maxAnswers++; // We display 3 answers, e.g. if the user types "bol" we display the results for "bold" and "bold italic".
                            break;
                        }
                        j++; // We don't want to display many times the same thing if a subject has different words describing it.
                    }
                }
                switch (maxAnswers) {
                case 0: // Nothing found.
                    $("#answer-1").html(chrome.i18n.getMessage("msgNoHelpFound")); // Show that we have not find an answer.
                    this.resultsContainer.attr("class", "one-result no-result"); // We only show one resuult.
                    this.resetAnswerDivs(2); // We hide the two other divs.
                    break;
                case 1: // One answer found.
                    this.resultsContainer.attr("class", "one-result");
                    this.resetAnswerDivs(2);
                    break;
                case 2: // Two answers found.
                    this.resultsContainer.attr("class", "two-results");
                    this.resetAnswerDivs(3);
                    break;
                case 3: // Three answers found, maximum number possible at the same time.
                    this.resultsContainer.attr("class", "three-results");
                    break;
                }
            }
        }
        this.setResultsHeight(); // Depending on the answer, the size of each div will change.
    },

    /* Change the height of each answer div depending on the content. */
    setResultsHeight: function() {
        var totalHeight = 0;
        for (var i = 1; i <= 3; i++) {// Check all the results, depending on the number of results
            if ($("#answer-" + i).html() !== "") {
                $("#result-" + i).css("display", "block");
                if ($("#answer-" + i).outerHeight() >= $("#example-" + i).outerHeight())  { // The eight of the answer is bigger than the example.
                    $("#result-" + i).css("height", $("#answer-" + i).outerHeight() + "px"); // Set the div's height as the answer's height.
                } else {
                    $("#result-" + i).css("height", $("#example-" + i).outerHeight() + "px");
                }
                totalHeight += $("#result-" + i).outerHeight(); // Add the height of the current result to the total height
            }
            else {
                $("#result-" + i).css("height", 0);
                $("#result-" + i).css("display", "none");
            }
        }
        this.resultsContainer.css("height", totalHeight + "px"); // Set the resultContainer's height to be the total height.
    },

    /* Switch between example and result */
    switch: function(resultNumber) {
        $("#result-" + resultNumber).toggleClass("switched");
        this.help.focus();
    }
};
<|endoftext|>


<commit_before>/* eslint-disable */

var path = require("path");
var webpack = require("webpack");

module.exports = {
  entry: [
    "babel-polyfill",
    "./index"
  ],
  output: {
    path: path.join(__dirname, "dist"),
    filename: "bundle.js",
    publicPath: "/dist/"
  },
  plugins: [
    new webpack.optimize.OccurenceOrderPlugin(),
    new webpack.DefinePlugin({
      "process.env": {
        "NODE_ENV": JSON.stringify("production")
      }
    }),
    new webpack.optimize.UglifyJsPlugin({
      compressor: {
        warnings: false
      }
    })
  ],
  module: {
    loaders: [{
      test: /\.md$/,
      loader: "html-loader!markdown-loader?gfm=false"
    }, {
      test: /\.(js|jsx)$/,
      exclude: /node_modules/,
      loader: "babel-loader",
      query: {
        presets: ['es2015', 'react']
      }
    }, {
      test: /\.css$/,
      loader: "style-loader!css-loader"
    }, {
      test: /\.(png|jpg|gif)$/,
      loader: "url-loader?limit=8192"
    }, {
      test: /\.svg$/,
      loader: "url?limit=10000&mimetype=image/svg+xml"
    }]
  }
};
<commit_msg>Remove leading slash to ensure images load in production<commit_after>/* eslint-disable */

var path = require("path");
var webpack = require("webpack");

module.exports = {
  entry: [
    "babel-polyfill",
    "./index"
  ],
  output: {
    path: path.join(__dirname, "dist"),
    filename: "bundle.js",
    publicPath: "dist/"
  },
  plugins: [
    new webpack.optimize.OccurenceOrderPlugin(),
    new webpack.DefinePlugin({
      "process.env": {
        "NODE_ENV": JSON.stringify("production")
      }
    }),
    new webpack.optimize.UglifyJsPlugin({
      compressor: {
        warnings: false
      }
    })
  ],
  module: {
    loaders: [{
      test: /\.md$/,
      loader: "html-loader!markdown-loader?gfm=false"
    }, {
      test: /\.(js|jsx)$/,
      exclude: /node_modules/,
      loader: "babel-loader",
      query: {
        presets: ['es2015', 'react']
      }
    }, {
      test: /\.css$/,
      loader: "style-loader!css-loader"
    }, {
      test: /\.(png|jpg|gif)$/,
      loader: "url-loader?limit=8192"
    }, {
      test: /\.svg$/,
      loader: "url?limit=10000&mimetype=image/svg+xml"
    }]
  }
};
<|endoftext|>


<commit_before>/**
 * Created by Tartarus762 on 10/13/16.
 */
(function ($) {

    // Constructor for durationpicker 'class'
    var durationPicker = function (element, options) {
        this.settings = options;
        this.stages = get_stages(this.settings);
        this.template = generate_template(this.settings, this.stages);
        this.jqitem = $(this.template);
        this.jqchildren = this.jqitem.children();
        this.element = $(element);
        this.setup();
        this.resize();
        this.jqchildren.find(".durationpicker-duration").trigger('change');
        var _self = this;
    };

    durationPicker.prototype = {
        constructor: durationPicker,
        setup: function () {
            this.element.before(this.jqitem);
            this.element.hide();
            this.jqchildren.find(".durationpicker-duration").on('change', {ths: this}, function (ev) {
                var element = ev.data.ths.element;
                var value = "";
                $(this).parent().parent().find('input').each(function () {
                    var input = $(this);
                    var val = 0;
                    if (input.val() != null && input.val() != ""){
                        val = input.val();
                    }
                    value += val + input.next().text() + ",";
                });
                value = value.slice(0, -1);
                element.val(value);
            });
            $(".durationpicker-duration").trigger();
            window.addEventListener('resize', this.resize.bind(this));

        },
        resize: function() {
            if (!this.settings.responsive) {
                return
            }
            var padding = parseInt(this.jqitem.css('padding-left').split('px')[0]) + parseInt(this.jqitem.css('padding-right').split('px')[0]);
            var minwidth = padding;
            var minheight = padding;
            this.jqchildren.each(function () {
                var ths = $(this);
                minwidth = minwidth + ths.outerWidth();
                minheight = minheight + ths.outerHeight();
            });
            if (this.jqitem.parent().width() < minwidth) {
                this.jqchildren.each(function () {
                    var ths = $(this);
                    ths.css('display', 'block');
                });
                this.jqitem.css('height', minheight)
            }
            else {
                this.jqchildren.each(function () {
                    var ths = $(this);
                    ths.css('display', 'inline-block');
                });
            }
        },
        getitem: function () {
            return this.jqitem;
        },
        setvalues: function (values) {
            set_values(values, this)
            $(".durationpicker-duration").trigger();
        },
        disable: function () {
            this.jqchildren.children("input").each(function (index, item) {
                item.readOnly = true;
            });
        },
        enable: function () {
            this.jqchildren.children("input").each(function (index, item) {
                item.readOnly = false;
            });
        }
    };

    $.fn.durationPicker = function(options){
        if (options == undefined) {
            var settings = $.extend(true, {}, $.fn.durationPicker.defaults, options);
        }
        else {
            var settings = $.extend(true, {}, {classname: 'form-control', responsive: true, type:'number'}, options);
        }

        // return this.each(function () {
        return new durationPicker(this, settings);
        // })
    };

    function set_values(values, self){
        for (var value in Object.keys(values)){
            if (self.stages.indexOf(Object.keys(values)[value]) != -1){
                self.jqitem.find("#duration-" + (Object.keys(values)[value])).val(values[(Object.keys(values)[value])]);
            }
        }
    }

    function get_stages(settings){
        var stages = [];
        for (var key in Object.keys(settings)){
            if (['classname', 'responsive', 'type'].indexOf(Object.keys(settings)[key]) == -1) {
                stages.push(Object.keys(settings)[key]);
            }
        }
        return stages
    }

    function generate_template (settings, stages) {
        var html = '
';
        var type = settings.type;
        for (var item in stages){
            html += '
<input min="' + settings[stages[item]]['min'] + '" max="' + settings[stages[item]]['max'] + '" placeholder="0" type="' + type + '" id="duration-' + stages[item] + '" class="durationpicker-duration" >' + settings[stages[item]]['label'] + '
';
        }
        html += '
';

        return html
    }

    $.fn.durationPicker.defaults = {
        hours: {
        	label: "h",
        	min: 0,
        	max: 24
        },
        minutes: {
        	label: "m",
        	min: 0,
        	max: 59
        },
        seconds: {
        	label: "s",
        	min: 0,
        	max: 59
        },
        classname: 'form-control',
        type: 'number',
        responsive: true
    };

    $.fn.durationPicker.Constructor = durationPicker;

})(jQuery);
<commit_msg>Update duration-picker.js<commit_after>/**
 * Created by Tartarus762 on 10/13/16.
 */
(function ($) {

    // Constructor for durationpicker 'class'
    var durationPicker = function (element, options) {
        this.settings = options;
        this.stages = get_stages(this.settings);
        this.template = generate_template(this.settings, this.stages);
        this.jqitem = $(this.template);
        this.jqchildren = this.jqitem.children();
        this.element = $(element);
        this.setup();
        this.resize();
        this.jqchildren.find(".durationpicker-duration").trigger('change');
        var _self = this;
    };

    durationPicker.prototype = {
        constructor: durationPicker,
        setup: function () {
            this.element.before(this.jqitem);
            this.element.hide();
            this.jqchildren.find(".durationpicker-duration").on('change', {ths: this}, function (ev) {
                var element = ev.data.ths.element;
                var value = "";
                $(this).parent().parent().find('input').each(function () {
                    var input = $(this);
                    var val = 0;
                    if (input.val() != null && input.val() != ""){
                        val = input.val();
                    }
                    value += val + input.next().text() + ",";
                });
                value = value.slice(0, -1);
                element.val(value);
            });
            $(".durationpicker-duration").trigger('change');
            window.addEventListener('resize', this.resize.bind(this));

        },
        resize: function() {
            if (!this.settings.responsive) {
                return
            }
            var padding = parseInt(this.jqitem.css('padding-left').split('px')[0]) + parseInt(this.jqitem.css('padding-right').split('px')[0]);
            var minwidth = padding;
            var minheight = padding;
            this.jqchildren.each(function () {
                var ths = $(this);
                minwidth = minwidth + ths.outerWidth();
                minheight = minheight + ths.outerHeight();
            });
            if (this.jqitem.parent().width() < minwidth) {
                this.jqchildren.each(function () {
                    var ths = $(this);
                    ths.css('display', 'block');
                });
                this.jqitem.css('height', minheight)
            }
            else {
                this.jqchildren.each(function () {
                    var ths = $(this);
                    ths.css('display', 'inline-block');
                });
            }
        },
        getitem: function () {
            return this.jqitem;
        },
        setvalues: function (values) {
            set_values(values, this)
            $(".durationpicker-duration").trigger();
        },
        disable: function () {
            this.jqchildren.children("input").each(function (index, item) {
                item.readOnly = true;
            });
        },
        enable: function () {
            this.jqchildren.children("input").each(function (index, item) {
                item.readOnly = false;
            });
        }
    };

    $.fn.durationPicker = function(options){
        if (options == undefined) {
            var settings = $.extend(true, {}, $.fn.durationPicker.defaults, options);
        }
        else {
            var settings = $.extend(true, {}, {classname: 'form-control', responsive: true, type:'number'}, options);
        }

        // return this.each(function () {
        return new durationPicker(this, settings);
        // })
    };

    function set_values(values, self){
        for (var value in Object.keys(values)){
            if (self.stages.indexOf(Object.keys(values)[value]) != -1){
                self.jqitem.find("#duration-" + (Object.keys(values)[value])).val(values[(Object.keys(values)[value])]);
            }
        }
    }

    function get_stages(settings){
        var stages = [];
        for (var key in Object.keys(settings)){
            if (['classname', 'responsive', 'type'].indexOf(Object.keys(settings)[key]) == -1) {
                stages.push(Object.keys(settings)[key]);
            }
        }
        return stages
    }

    function generate_template (settings, stages) {
        var html = '
';
        var type = settings.type;
        for (var item in stages){
            html += '
<input min="' + settings[stages[item]]['min'] + '" max="' + settings[stages[item]]['max'] + '" placeholder="0" type="' + type + '" id="duration-' + stages[item] + '" class="durationpicker-duration" >' + settings[stages[item]]['label'] + '
';
        }
        html += '
';

        return html
    }

    $.fn.durationPicker.defaults = {
        hours: {
        	label: "h",
        	min: 0,
        	max: 24
        },
        minutes: {
        	label: "m",
        	min: 0,
        	max: 59
        },
        seconds: {
        	label: "s",
        	min: 0,
        	max: 59
        },
        classname: 'form-control',
        type: 'number',
        responsive: true
    };

    $.fn.durationPicker.Constructor = durationPicker;

})(jQuery);
<|endoftext|>


<commit_before>var net = require('net');
var rules = require('../lib/rules');
var util = require('../lib/util');
var handleUIReq = require('./webui/lib').handleRequest;
var handleWeinreReq = require('./weinre');
var config = require('../lib/config');

var localIpCache = util.localIpCache;
var WEBUI_PATH = config.WEBUI_PATH;
var PREVIEW_PATH_RE = config.PREVIEW_PATH_RE;
var webuiPathRe = util.escapeRegExp(WEBUI_PATH);
var REAL_WEBUI_HOST = new RegExp('^' + webuiPathRe + '(__([a-z\\d.-]+)(?:__(\\d{1,5}))?__/)');
var REAL_WEBUI_HOST_PARAM = /\?_whistleInternalHost_=(__([a-z\d.-]+)(?:__(\d{1,5}))?__)/;
var INTERNAL_APP = new RegExp('^' + webuiPathRe + '(log|weinre|cgi)(?:\\.(\\d{1,5}))?/');
var PLUGIN_RE = new RegExp('^' + webuiPathRe + 'whistle\\.([a-z\\d_-]+)/');

module.exports = function(req, res, next) {
  var config = this.config;
  var pluginMgr = this.pluginMgr;
  var fullUrl = util.getFullUrl(req);
  var host = util.parseHost(req.headers.host);
  var port = host[1] || (req.isHttps ? 443 : 80);
  var bypass;
  host = host[0];
  var transformPort, proxyUrl, isWeinre, isOthers, isInternal;
  var isWebUI = req.path.indexOf(WEBUI_PATH) === 0;
  if (isWebUI) {
    isWebUI = !config.pureProxy;
    if (isWebUI) {
      var existsRealHost = REAL_WEBUI_HOST.test(req.path);
      if (existsRealHost || REAL_WEBUI_HOST_PARAM.test(req.url)) {
        var realPath = RegExp.$1;
        var realPort = RegExp.$3;
        var realHost = RegExp.$2 + (realPort ? ':' + realPort : '');
        req.headers['x-whistle-real-host'] = realHost;
        req.url = req.url.replace(realPath, existsRealHost ? '' : '?');
        fullUrl = util.getFullUrl(req);
      }
      if (INTERNAL_APP.test(req.path)) {
        transformPort = RegExp.$2;
        isWeinre = RegExp.$1 === 'weinre';
        if (transformPort) {
          isOthers = proxyUrl = transformPort != config.port;
        } else {
          proxyUrl = false;
          transformPort = config.port;
        }
      } else if (PLUGIN_RE.test(req.path)) {
        proxyUrl = !pluginMgr.getPlugin(RegExp.$1 + ':');
      } else if (!req.headers[config.WEBUI_HEAD]) {
        isWebUI = false;
      }
      if (proxyUrl) {
        req.curUrl = fullUrl;
        rules.getHttpProxy(fullUrl, req, function() {
          proxyUrl = req.rules.proxy;
          if (proxyUrl) {
            isInternal = proxyUrl.isInternal;
            proxyUrl = proxyUrl.matcher;
          }
          if (proxyUrl) {
            proxyUrl = proxyUrl.substring(proxyUrl.indexOf('://') + 3);
          } else {
            proxyUrl = null;
          }
          handleNext();
        });
        return;
      }
    }
  } else {
    isWebUI = req.headers[config.WEBUI_HEAD];
    if (!isWebUI) {
      if (!(isWebUI = localIpCache.get(host))) {
        isWebUI = config.isLocalUIUrl(host);
        if (isWebUI ? net.isIP(host) : util.isLocalHost(host)) {
          isWebUI = util.isProxyPort(port);
        }
      }
    } else if (util.isProxyPort(port) && net.isIP(host)) {
      localIpCache.set(host, 1);
    }
    if (isWebUI) {
      if (req.path.indexOf('/_/') === 0) {
        bypass = '/_/';
      } else if (req.path.indexOf('/-/') === 0) {
        bypass = '/-/';
      }
      if (bypass) {
        req.url = req.url.replace(bypass, '/');
      }
      delete req.headers[config.INTERNAL_ID_HEADER];
    } else if (PREVIEW_PATH_RE.test(req.url)) {
      req.headers[config.INTERNAL_ID_HEADER] = config.INTERNAL_ID;
      req.url = '/preview.html?charset=' + RegExp.$1;
      isWebUI = true;
    }
  }
  handleNext();

  function handleNext() {
    // 后续有用到
    fullUrl = req.fullUrl = util.getFullUrl(req);
    if (bypass) {
      return next();
    }
    var localRule;
    req.curUrl = fullUrl;
    if (proxyUrl) {
      req.curUrl = 'http://' + proxyUrl;
      rules.resolveHost(req, function(err, ip) {
        if (err) {
          return next(err);
        }
        var colon = proxyUrl.indexOf(':');
        var proxyPort = colon === -1 ? 80 : proxyUrl.substring(colon + 1);
        req.headers.host = 'local.whistlejs.com';
        util.setClientId(req.headers, req.enable, req.disable, req.clientIp, isInternal);
        util.transformReq(req, res, proxyPort > 0 ? proxyPort : 80, ip, true);
      });
    } else if (isWebUI) {
      if (isOthers) {
        util.transformReq(req, res, transformPort);
      } else {
        req._hasRespond = true;
        req.url = req.url.replace(transformPort ? INTERNAL_APP : WEBUI_PATH, '/');
        if (isWeinre) {
          handleWeinreReq(req, res);
        } else {
          handleUIReq(req, res);
        }
      }
    } else if (localRule = rules.resolveLocalRule(req)) {
      req.url = localRule.url;
      if (localRule.realPort) {
        req.headers.host = '127.0.0.1:' + localRule.realPort;
        util.transformReq(req, res, localRule.realPort);
      } else {
        handleUIReq(req, res);
      }
    } else {
      next();
    }
  }
};

<commit_msg>refactor: refine code<commit_after>var net = require('net');
var rules = require('../lib/rules');
var util = require('../lib/util');
var handleUIReq = require('./webui/lib').handleRequest;
var handleWeinreReq = require('./weinre');
var config = require('../lib/config');

var localIpCache = util.localIpCache;
var WEBUI_PATH = config.WEBUI_PATH;
var PREVIEW_PATH_RE = config.PREVIEW_PATH_RE;
var webuiPathRe = util.escapeRegExp(WEBUI_PATH);
var REAL_WEBUI_HOST = new RegExp('^' + webuiPathRe + '(__([a-z\\d.-]+)(?:__(\\d{1,5}))?__/)');
var REAL_WEBUI_HOST_PARAM = /_whistleInternalHost_=(__([a-z\d.-]+)(?:__(\d{1,5}))?__)/;
var INTERNAL_APP = new RegExp('^' + webuiPathRe + '(log|weinre|cgi)(?:\\.(\\d{1,5}))?/');
var PLUGIN_RE = new RegExp('^' + webuiPathRe + 'whistle\\.([a-z\\d_-]+)/');

module.exports = function(req, res, next) {
  var config = this.config;
  var pluginMgr = this.pluginMgr;
  var fullUrl = util.getFullUrl(req);
  var host = util.parseHost(req.headers.host);
  var port = host[1] || (req.isHttps ? 443 : 80);
  var bypass;
  host = host[0];
  var transformPort, proxyUrl, isWeinre, isOthers, isInternal;
  var isWebUI = req.path.indexOf(WEBUI_PATH) === 0;
  if (isWebUI) {
    isWebUI = !config.pureProxy;
    if (isWebUI) {
      if (REAL_WEBUI_HOST.test(req.path) || REAL_WEBUI_HOST_PARAM.test(req.url)) {
        var realPath = RegExp.$1;
        var realPort = RegExp.$3;
        var realHost = RegExp.$2 + (realPort ? ':' + realPort : '');
        req.headers['x-whistle-real-host'] = realHost;
        req.url = req.url.replace(realPath, '');
        fullUrl = util.getFullUrl(req);
      }
      if (INTERNAL_APP.test(req.path)) {
        transformPort = RegExp.$2;
        isWeinre = RegExp.$1 === 'weinre';
        if (transformPort) {
          isOthers = proxyUrl = transformPort != config.port;
        } else {
          proxyUrl = false;
          transformPort = config.port;
        }
      } else if (PLUGIN_RE.test(req.path)) {
        proxyUrl = !pluginMgr.getPlugin(RegExp.$1 + ':');
      } else if (!req.headers[config.WEBUI_HEAD]) {
        isWebUI = false;
      }
      if (proxyUrl) {
        req.curUrl = fullUrl;
        rules.getHttpProxy(fullUrl, req, function() {
          proxyUrl = req.rules.proxy;
          if (proxyUrl) {
            isInternal = proxyUrl.isInternal;
            proxyUrl = proxyUrl.matcher;
          }
          if (proxyUrl) {
            proxyUrl = proxyUrl.substring(proxyUrl.indexOf('://') + 3);
          } else {
            proxyUrl = null;
          }
          handleNext();
        });
        return;
      }
    }
  } else {
    isWebUI = req.headers[config.WEBUI_HEAD];
    if (!isWebUI) {
      if (!(isWebUI = localIpCache.get(host))) {
        isWebUI = config.isLocalUIUrl(host);
        if (isWebUI ? net.isIP(host) : util.isLocalHost(host)) {
          isWebUI = util.isProxyPort(port);
        }
      }
    } else if (util.isProxyPort(port) && net.isIP(host)) {
      localIpCache.set(host, 1);
    }
    if (isWebUI) {
      if (req.path.indexOf('/_/') === 0) {
        bypass = '/_/';
      } else if (req.path.indexOf('/-/') === 0) {
        bypass = '/-/';
      }
      if (bypass) {
        req.url = req.url.replace(bypass, '/');
      }
      delete req.headers[config.INTERNAL_ID_HEADER];
    } else if (PREVIEW_PATH_RE.test(req.url)) {
      req.headers[config.INTERNAL_ID_HEADER] = config.INTERNAL_ID;
      req.url = '/preview.html?charset=' + RegExp.$1;
      isWebUI = true;
    }
  }
  handleNext();

  function handleNext() {
    // 后续有用到
    fullUrl = req.fullUrl = util.getFullUrl(req);
    if (bypass) {
      return next();
    }
    var localRule;
    req.curUrl = fullUrl;
    if (proxyUrl) {
      req.curUrl = 'http://' + proxyUrl;
      rules.resolveHost(req, function(err, ip) {
        if (err) {
          return next(err);
        }
        var colon = proxyUrl.indexOf(':');
        var proxyPort = colon === -1 ? 80 : proxyUrl.substring(colon + 1);
        req.headers.host = 'local.whistlejs.com';
        util.setClientId(req.headers, req.enable, req.disable, req.clientIp, isInternal);
        util.transformReq(req, res, proxyPort > 0 ? proxyPort : 80, ip, true);
      });
    } else if (isWebUI) {
      if (isOthers) {
        util.transformReq(req, res, transformPort);
      } else {
        req._hasRespond = true;
        req.url = req.url.replace(transformPort ? INTERNAL_APP : WEBUI_PATH, '/');
        if (isWeinre) {
          handleWeinreReq(req, res);
        } else {
          handleUIReq(req, res);
        }
      }
    } else if (localRule = rules.resolveLocalRule(req)) {
      req.url = localRule.url;
      if (localRule.realPort) {
        req.headers.host = '127.0.0.1:' + localRule.realPort;
        util.transformReq(req, res, localRule.realPort);
      } else {
        handleUIReq(req, res);
      }
    } else {
      next();
    }
  }
};

<|endoftext|>