<commit_before>function HTMLActuator() {
  this.tileContainer    = document.querySelector(".tile-container");
  this.scoreContainer   = document.querySelector(".score-container");
  this.bestContainer    = document.querySelector(".best-container");
  this.messageContainer = document.querySelector(".game-message");

  this.score = 0;
}

HTMLActuator.prototype.actuate = function (grid, metadata) {
  var self = this;

  window.requestAnimationFrame(function () {
    self.clearContainer(self.tileContainer);

    grid.cells.forEach(function (column) {
      column.forEach(function (cell) {
        if (cell) {
          self.addTile(cell);
        }
      });
    });

    self.updateScore(metadata.score);
    self.updateBestScore(metadata.bestScore);

    if (metadata.terminated) {
      if (metadata.over) {
        self.message(false); // You lose
      } else if (metadata.won) {
        self.message(true); // You win!
      }
    }

  });
};

// Continues the game (both restart and keep playing)
HTMLActuator.prototype.continue = function () {
  this.clearMessage();
};

HTMLActuator.prototype.clearContainer = function (container) {
  while (container.firstChild) {
    container.removeChild(container.firstChild);
  }
};

HTMLActuator.prototype.addTile = function (tile) {
  var self = this;

  var wrapper   = document.createElement("div");
  var inner     = document.createElement("div");
  var position  = tile.previousPosition || { x: tile.x, y: tile.y };
  var positionClass = this.positionClass(position);

  // We can't use classlist because it somehow glitches when replacing classes
  var classes = ["tile", "tile-" + tile.value, positionClass];

  if (tile.value > 2048) classes.push("tile-super");

  this.applyClasses(wrapper, classes);

  var outputtext = new Array();
  outputtext[0] = "";
  outputtext[1] = "electron";
  outputtext[2] = "electron neutrino";
  outputtext[3] = "muon";
  outputtext[4] = "muon neutrino";
  outputtext[5] = "tau";
  outputtext[6] = "tau neutrino";
  outputtext[7] = "gluon";
  outputtext[8] = "photon";
  outputtext[9] = "Z boson";
  outputtext[10] = "W boson";
  outputtext[11] = "Higgs Boson";

  inner.classList.add("tile-inner");
  inner.textContent = outputtext[(Math.log(tile.value) / Math.LN2)] || '';

  if (tile.previousPosition) {
    // Make sure that the tile gets rendered in the previous position first
    window.requestAnimationFrame(function () {
      classes[2] = self.positionClass({ x: tile.x, y: tile.y });
      self.applyClasses(wrapper, classes); // Update the position
    });
  } else if (tile.mergedFrom) {
    classes.push("tile-merged");
    this.applyClasses(wrapper, classes);

    // Render the tiles that merged
    tile.mergedFrom.forEach(function (merged) {
      self.addTile(merged);
    });
  } else {
    classes.push("tile-new");
    this.applyClasses(wrapper, classes);
  }

  // Add the inner part of the tile to the wrapper
  wrapper.appendChild(inner);

  // Put the tile on the board
  this.tileContainer.appendChild(wrapper);
};

HTMLActuator.prototype.applyClasses = function (element, classes) {
  element.setAttribute("class", classes.join(" "));
};

HTMLActuator.prototype.normalizePosition = function (position) {
  return { x: position.x + 1, y: position.y + 1 };
};

HTMLActuator.prototype.positionClass = function (position) {
  position = this.normalizePosition(position);
  return "tile-position-" + position.x + "-" + position.y;
};

HTMLActuator.prototype.updateScore = function (score) {
  this.clearContainer(this.scoreContainer);

  var difference = score - this.score;
  this.score = score;

  this.scoreContainer.textContent = this.score + " GeV";

  if (difference > 0) {
    var addition = document.createElement("div");
    addition.classList.add("score-addition");
    addition.textContent = "+" + difference;

    this.scoreContainer.appendChild(addition);
  }
};

HTMLActuator.prototype.updateBestScore = function (bestScore) {
  this.bestContainer.textContent = bestScore + " GeV";
};

HTMLActuator.prototype.message = function (won) {
  var type    = won ? "game-won" : "game-over";
  var message = won ? "Wow! You are next year's Nobelist!" : "Er... LHC breaks down......";

  this.messageContainer.classList.add(type);
  this.messageContainer.getElementsByTagName("p")[0].textContent = message;
};

HTMLActuator.prototype.clearMessage = function () {
  // IE only takes one value to remove at a time.
  this.messageContainer.classList.remove("game-won");
  this.messageContainer.classList.remove("game-over");
};
<commit_msg>Update html_actuator.js<commit_after>function HTMLActuator() {
  this.tileContainer    = document.querySelector(".tile-container");
  this.scoreContainer   = document.querySelector(".score-container");
  this.bestContainer    = document.querySelector(".best-container");
  this.messageContainer = document.querySelector(".game-message");

  this.score = 0;
}

HTMLActuator.prototype.actuate = function (grid, metadata) {
  var self = this;

  window.requestAnimationFrame(function () {
    self.clearContainer(self.tileContainer);

    grid.cells.forEach(function (column) {
      column.forEach(function (cell) {
        if (cell) {
          self.addTile(cell);
        }
      });
    });

    self.updateScore(metadata.score);
    self.updateBestScore(metadata.bestScore);

    if (metadata.terminated) {
      if (metadata.over) {
        self.message(false); // You lose
      } else if (metadata.won) {
        self.message(true); // You win!
      }
    }

  });
};

// Continues the game (both restart and keep playing)
HTMLActuator.prototype.continue = function () {
  this.clearMessage();
};

HTMLActuator.prototype.clearContainer = function (container) {
  while (container.firstChild) {
    container.removeChild(container.firstChild);
  }
};

HTMLActuator.prototype.addTile = function (tile) {
  var self = this;

  var wrapper   = document.createElement("div");
  var inner     = document.createElement("div");
  var position  = tile.previousPosition || { x: tile.x, y: tile.y };
  var positionClass = this.positionClass(position);

  // We can't use classlist because it somehow glitches when replacing classes
  var classes = ["tile", "tile-" + tile.value, positionClass];

  if (tile.value > 2048) classes.push("tile-super");

  this.applyClasses(wrapper, classes);

  var outputtext = new Array();
  outputtext[0] = "";
  outputtext[1] = "electron";
  outputtext[2] = "electron neutrino";
  outputtext[3] = "muon";
  outputtext[4] = "muon neutrino";
  outputtext[5] = "tau";
  outputtext[6] = "tau neutrino";
  outputtext[7] = "gluon";
  outputtext[8] = "photon";
  outputtext[9] = "Z boson";
  outputtext[10] = "W boson";
  outputtext[11] = "Higgs Boson";

  inner.classList.add("tile-inner");
  inner.textContent = outputtext[(Math.log(tile.value) / Math.LN2)] || '';

  if (tile.previousPosition) {
    // Make sure that the tile gets rendered in the previous position first
    window.requestAnimationFrame(function () {
      classes[2] = self.positionClass({ x: tile.x, y: tile.y });
      self.applyClasses(wrapper, classes); // Update the position
    });
  } else if (tile.mergedFrom) {
    classes.push("tile-merged");
    this.applyClasses(wrapper, classes);

    // Render the tiles that merged
    tile.mergedFrom.forEach(function (merged) {
      self.addTile(merged);
    });
  } else {
    classes.push("tile-new");
    this.applyClasses(wrapper, classes);
  }

  // Add the inner part of the tile to the wrapper
  wrapper.appendChild(inner);

  // Put the tile on the board
  this.tileContainer.appendChild(wrapper);
};

HTMLActuator.prototype.applyClasses = function (element, classes) {
  element.setAttribute("class", classes.join(" "));
};

HTMLActuator.prototype.normalizePosition = function (position) {
  return { x: position.x + 1, y: position.y + 1 };
};

HTMLActuator.prototype.positionClass = function (position) {
  position = this.normalizePosition(position);
  return "tile-position-" + position.x + "-" + position.y;
};

HTMLActuator.prototype.updateScore = function (score) {
  this.clearContainer(this.scoreContainer);

  var difference = score - this.score;
  this.score = score;

  this.scoreContainer.textContent = this.score + " GeV";

  if (difference > 0) {
    var addition = document.createElement("div");
    addition.classList.add("score-addition");
    addition.textContent = "+" + difference;

    this.scoreContainer.appendChild(addition);
  }
};

HTMLActuator.prototype.updateBestScore = function (bestScore) {
  this.bestContainer.textContent = bestScore + " GeV";
};

HTMLActuator.prototype.message = function (won) {
  var type    = won ? "game-won" : "game-over";
  var message = won ? "You'll get a Nobel Prize!" : "Er... LHC breaks down......";

  this.messageContainer.classList.add(type);
  this.messageContainer.getElementsByTagName("p")[0].textContent = message;
};

HTMLActuator.prototype.clearMessage = function () {
  // IE only takes one value to remove at a time.
  this.messageContainer.classList.remove("game-won");
  this.messageContainer.classList.remove("game-over");
};
<|endoftext|>


<commit_before>var socks = require('socksv5');
var url = require('url');
var net = require('net');
var extend = require('util')._extend;
var EventEmitter = require('events').EventEmitter;
var hparser = require('hparser');
var dispatch = require('./https');
var util = require('./util');
var rules = require('./rules');
var socketMgr = require('./socket-mgr');
var rulesUtil = require('./rules/util');
var pluginMgr = require('./plugins');
var config = require('./config');

var LOCALHOST = '127.0.0.1';
var TUNNEL_HOST_RE = /^[^:\/]+\.[^:\/]+:\d+$/;
var STATUS_CODES = require('http').STATUS_CODES || {};
var getRawHeaderNames = hparser.getRawHeaderNames;
var formatHeaders = hparser.formatHeaders;
var getRawHeaders = hparser.getRawHeaders;

function tunnelProxy(server, proxy) {
  server.on('connect', function(req, reqSocket, head) {//ws, wss, https proxy
    var tunnelUrl = req.fullUrl = util.setProtocol(TUNNEL_HOST_RE.test(req.url) ? req.url : req.headers.host, true);
    var options;
    var parseUrl = function (_url, port) {
      _url = _url || tunnelUrl;
      options = req.options = url.parse(_url);
      options.port = options.port || port || 443;
      return options;
    };
    parseUrl();
    tunnelUrl = req.fullUrl = 'tunnel://' + options.host;
    proxy.emit('_request', tunnelUrl);
    var resSocket, responsed, reqEmitter, data, rulesMgr, res;
    req.isTunnel = true;
    reqSocket.clientIp = req.clientIp = util.getClientIp(req);
    req.reqId = reqSocket.reqId = util.getReqId();
    var hostname = options.hostname;
    var policy = req.headers[config.WHISTLE_POLICY_HEADER];
    var useTunnelPolicy = policy == 'tunnel';
    var isLocalUIUrl = !useTunnelPolicy && (config.isLocalUIUrl(hostname) || config.isPluginUrl(hostname));
    var _rules = req.rules = isLocalUIUrl ? {} : rules.initRules(req);
    rules.resolveRulesFile(req, function() {
      var plugin = pluginMgr.resolveWhistlePlugins(req);
      pluginMgr.getTunnelRules(req, function(_rulesMgr) {
        if (_rulesMgr) {
          rulesMgr = _rulesMgr;
          util.mergeRules(req, rulesMgr.resolveRules(tunnelUrl));
          plugin = pluginMgr.getPluginByRuleUrl(util.rule.getUrl(_rules.rule));
        }
        var filter = req.filter;
        var disable = req.disable;
        abortIfUnavailable(reqSocket);
        if (req.headers[config.WEBUI_HEAD]) {
          return reqSocket.destroy();
        }
        if (!useTunnelPolicy && (policy === 'intercept' || isLocalUIUrl || ((filter.https || filter.intercept
            || rulesUtil.properties.get('interceptHttpsConnects')) && !disable.intercept && !disable.https))) {
          dispatch(reqSocket, hostname, function(_resSocket) {
            resSocket = _resSocket;
          });
          sendEstablished();
          return;
        }
        pluginMgr.postStats(req);
        reqEmitter = new EventEmitter();
        var headers = req.headers;
        var reqData = {
          ip: req.clientIp,
          port: reqSocket.remotePort,
          method: util.toUpperCase(req.method) || 'CONNECT',
          httpVersion: req.httpVersion || '1.1',
          headers: headers
        };
        var resData = {headers: {}};
        data = reqEmitter.data = {
          id: req.reqId,
          url: options.host,
          startTime: Date.now(),
          rules: _rules,
          req: reqData,
          res: resData,
          isHttps: true,
          rulesHeaders: req.rulesHeaders
        };
        var cId = headers['x-whistle-composer-id'];
        if (cId) {
          data.cId = cId;
          delete headers['x-whistle-composer-id'];
        }
        if (!filter.hide) {
          proxy.emit('request', reqEmitter);
        }

        if (req.enable.abort || filter.abort || disable.tunnel) {
          return reqSocket.destroy();
        }

        var statusCode = util.getMatcherValue(_rules.statusCode);
        if (statusCode) {
          if (statusCode == 200) {
            resSocket = util.getEmptyRes();
            var reqDelay = util.getMatcherValue(_rules.reqDelay);
            data.requestTime = data.dnsTime = Date.now();
            if (reqDelay > 0) {
              setTimeout(handleConnect, reqDelay);
            } else {
              handleConnect();
            }
            return;
          }
          return sendEstablished(statusCode);
        }

        pluginMgr.loadPlugin(plugin, function() {
          var tunnelPort, proxyUrl;
          if(plugin) {
            tunnelPort = plugin.ports && plugin.ports.tunnelPort;
            if (!tunnelPort) {
              return emitError(new Error('No plugin.tunnelServer'));
            }
            proxyUrl = 'proxy://127.0.0.1:' + tunnelPort;
            pluginMgr.addRuleHeaders(req, _rules);
          }

          var realUrl = _rules.rule && _rules.rule.url.replace('https:', 'tunnel:');
          if (/^tunnel:\/\//.test(realUrl) && realUrl != tunnelUrl) {
            tunnelUrl = realUrl;
            data.realUrl = realUrl.replace('tunnel://', '');
            parseUrl();
          }

          rules.getProxy(tunnelUrl, proxyUrl ? null : req, function(err, hostIp, hostPort) {
            if (!proxyUrl) {
              proxyUrl = _rules.proxy ? _rules.proxy.matcher : null;
            }

            if (proxyUrl) {
              var isSocks = /^socks:\/\//.test(proxyUrl);
              var _url = 'http:' + util.removeProtocol(proxyUrl);
              data.proxy = true;
              resolveHost(_url, function(ip) {
                options = parseUrl(_url, isSocks ? 1080 : 80);
                var isProxyPort = options.port == config.port;
                if (isProxyPort && util.isLocalAddress(ip)) {
                  return emitError(new Error('Unable to proxy to itself'));
                }
                var onConnect = function(proxySocket, _res) {
                  resSocket = proxySocket;
                  res = _res;
                  handleConnect();
                  abortIfUnavailable(resSocket);
                };
                var dstOptions = url.parse(tunnelUrl);
                dstOptions.proxyHost = ip;
                dstOptions.proxyPort = parseInt(options.port, 10);
                resData.port = dstOptions.port = dstOptions.port || 443;
                dstOptions.host = dstOptions.hostname;
                var _headers = extend({}, headers);
                pluginMgr.addRuleHeaders(req, _rules, _headers);
                _headers.host = dstOptions.hostname + ':' + (dstOptions.port || 443);
                util.parseRuleJson(_rules.reqHeaders, function(reqHeaders) {
                  dstOptions.headers = extend(headers, reqHeaders);
                  if (disable.clientIp || disable.clientIP) {
                    delete headers[config.CLIENT_IP_HEAD];
                  } else {
                    var forwardedFor = util.getMatcherValue(_rules.forwardedFor);
                    if (forwardedFor) {
                      headers[config.CLIENT_IP_HEAD] = forwardedFor;
                    }
                  }
                  var delReqHeaders = util.parseDeleteProperties(req).reqHeaders;
                  Object.keys(delReqHeaders).forEach(function(name) {
                    delete headers[name];
                  });
                  if (isSocks) {
                    dstOptions.proxyPort = options.port || 1080;
                    dstOptions.localDNS = false;
                    dstOptions.auths = config.getAuths(options);
                  } else {
                    dstOptions.proxyPort = options.port || 80;
                    dstOptions.proxyAuth = options.auth;
                    if (isProxyPort) {
                      _headers[config.WEBUI_HEAD] = 1;
                    }
                  }
                  var netMgr = isSocks ? socks : config;
                  var reqDelay = util.getMatcherValue(_rules.reqDelay);
                  if (reqDelay > 0) {
                    setTimeout(function() {
                      netMgr.connect(dstOptions, onConnect).on('error', emitError);
                    }, reqDelay);
                  } else {
                    netMgr.connect(dstOptions, onConnect).on('error', emitError);
                  }
                });
              });
            } else {
              tunnel(hostIp, hostPort);
            }
          });
        });

        function tunnel(hostIp, hostPort) {
          resolveHost(tunnelUrl, function(ip, port) {
            if (port) {
              resData.ip = ip + ':' + port;
              resData.port = port;
            } else {
              resData.ip = ip;
              resData.port = port = options.port;
            }
            resSocket = net.connect(port, ip, handleConnect);
            abortIfUnavailable(resSocket);
          }, hostIp, hostPort);
        }

        function handleConnect() {
          reqSocket.headers = headers;
          reqSocket.fullUrl = tunnelUrl;
          reqSocket.useTunnelPolicy = useTunnelPolicy;
          socketMgr.handleConnect(reqSocket, resSocket);
          var resDelay = util.getMatcherValue(_rules.resDelay);
          if (resDelay > 0) {
            setTimeout(sendEstablished, resDelay);
          } else {
            sendEstablished();
          }
        }

        function resolveHost(url, callback, hostIp, hostPort) {
          var hostHandler = function(err, ip, port, host) {
            if (host) {
              _rules.host = host;
            }
            data.requestTime = data.dnsTime = Date.now();
            resData.ip = ip || LOCALHOST;
            reqEmitter.emit('send', data);
            err ? emitError(err) : callback(ip, port);
          };
          if (hostIp) {
            hostHandler(null, hostIp, hostPort);
          } else {
            rules.resolveHost(url, hostHandler, rulesMgr, req.rulesFileMgr, req.headerRulesMgr);
          }
        }

        function abortIfUnavailable(socket) {
          socket.on('error', emitError).on('close', emitError);
        }

        function sendEstablished(code) {
          if (res) {
            code = res.statusCode;
          } else {
            code = code || 200;
            res = {
              statusCode: code,
              headers: {
                'proxy-agent': config.name
              },
              rawHeaders: ['proxy-agent', 'Proxy-Agent']
            };
          }
          var resHeaders = res.headers;
          delete req.whistlePlugins;
          pluginMgr.getResRules(req, res, function() {
            var reqRules = req.rules;
            util.parseRuleJson(reqRules.resHeaders, function(newResHeaders) {
              extend(resHeaders, newResHeaders);
              var responseFor = util.getMatcherValue(reqRules.responseFor);
              if (responseFor) {
                resHeaders['x-whistle-response-for'] = responseFor;
              }
              var delResHeaders = util.parseDeleteProperties(req).resHeaders;
              Object.keys(delResHeaders).forEach(function(name) {
                delete resHeaders[name];
              });
              if (!resHeaders['proxy-agent']) {
                resHeaders['proxy-agent'] = config.name;
                res.rawHeaders = res.rawHeaders || [];
                res.rawHeaders.push('proxy-agent', 'Proxy-Agent');
              }
              var message = code == 200 ? 'Connection Established' : (STATUS_CODES[code] || 'unknown');
              var statusLine = ['HTTP/1.1', code, message].join(' ');
              var rawHeaderNames = getRawHeaderNames(res.rawHeaders) || {};
              var rawData = [statusLine, getRawHeaders(formatHeaders(resHeaders, rawHeaderNames))].join('\r\n') + '\r\n\r\n';
              if (code && code != 200) {
                reqSocket.end(rawData);
              } else {
                reqSocket.write(rawData);
              }
              if (reqEmitter) {
                responsed = true;
                data.responseTime = data.endTime = Date.now();
                reqData.rawHeaderNames = rawHeaderNames;
                resData.statusCode = code || 200;
                resData.headers = resHeaders;
                reqEmitter.emit('response', data);
                reqEmitter.emit('end', data);
              }
            });
          });
          return reqSocket;
        }

        function emitError(err) {
          if (responsed) {
            return;
          }
          responsed = true;
          resSocket && resSocket.destroy();
          reqSocket.destroy();
          if (!reqEmitter) {
            return;
          }
          data.responseTime = data.endTime = Date.now();

          if (!resData.ip) {
            resData.ip = LOCALHOST;
          }

          if (!err) {
            err = new Error('Aborted');
            data.reqError = true;
            resData.statusCode ='aborted';
            reqData.body = util.getErrorStack(err);
            reqEmitter.emit('abort', data);
          } else {
            data.resError = true;
            resData.statusCode = resData.statusCode || 502;
            resData.body = util.getErrorStack(err);
            util.emitError(reqEmitter, data);
          }
        }
      });
    });
  });

  return server;
}

module.exports = tunnelProxy;
<commit_msg>refactor: Tunnel proxy headers<commit_after>var socks = require('socksv5');
var url = require('url');
var net = require('net');
var extend = require('util')._extend;
var EventEmitter = require('events').EventEmitter;
var hparser = require('hparser');
var dispatch = require('./https');
var util = require('./util');
var rules = require('./rules');
var socketMgr = require('./socket-mgr');
var rulesUtil = require('./rules/util');
var pluginMgr = require('./plugins');
var config = require('./config');

var LOCALHOST = '127.0.0.1';
var TUNNEL_HOST_RE = /^[^:\/]+\.[^:\/]+:\d+$/;
var STATUS_CODES = require('http').STATUS_CODES || {};
var getRawHeaderNames = hparser.getRawHeaderNames;
var formatHeaders = hparser.formatHeaders;
var getRawHeaders = hparser.getRawHeaders;

function tunnelProxy(server, proxy) {
  server.on('connect', function(req, reqSocket, head) {//ws, wss, https proxy
    var tunnelUrl = req.fullUrl = util.setProtocol(TUNNEL_HOST_RE.test(req.url) ? req.url : req.headers.host, true);
    var options;
    var parseUrl = function (_url, port) {
      _url = _url || tunnelUrl;
      options = req.options = url.parse(_url);
      options.port = options.port || port || 443;
      return options;
    };
    parseUrl();
    tunnelUrl = req.fullUrl = 'tunnel://' + options.host;
    proxy.emit('_request', tunnelUrl);
    var resSocket, responsed, reqEmitter, data, rulesMgr, res;
    req.isTunnel = true;
    reqSocket.clientIp = req.clientIp = util.getClientIp(req);
    req.reqId = reqSocket.reqId = util.getReqId();
    var hostname = options.hostname;
    var policy = req.headers[config.WHISTLE_POLICY_HEADER];
    var useTunnelPolicy = policy == 'tunnel';
    var isLocalUIUrl = !useTunnelPolicy && (config.isLocalUIUrl(hostname) || config.isPluginUrl(hostname));
    var _rules = req.rules = isLocalUIUrl ? {} : rules.initRules(req);
    rules.resolveRulesFile(req, function() {
      var plugin = pluginMgr.resolveWhistlePlugins(req);
      pluginMgr.getTunnelRules(req, function(_rulesMgr) {
        if (_rulesMgr) {
          rulesMgr = _rulesMgr;
          util.mergeRules(req, rulesMgr.resolveRules(tunnelUrl));
          plugin = pluginMgr.getPluginByRuleUrl(util.rule.getUrl(_rules.rule));
        }
        var filter = req.filter;
        var disable = req.disable;
        abortIfUnavailable(reqSocket);
        if (req.headers[config.WEBUI_HEAD]) {
          return reqSocket.destroy();
        }
        if (!useTunnelPolicy && (policy === 'intercept' || isLocalUIUrl || ((filter.https || filter.intercept
            || rulesUtil.properties.get('interceptHttpsConnects')) && !disable.intercept && !disable.https))) {
          dispatch(reqSocket, hostname, function(_resSocket) {
            resSocket = _resSocket;
          });
          sendEstablished();
          return;
        }
        pluginMgr.postStats(req);
        reqEmitter = new EventEmitter();
        var headers = req.headers;
        var reqRawHeaderNames = getRawHeaderNames(req.rawHeaders) || {};
        var reqData = {
          ip: req.clientIp,
          port: reqSocket.remotePort,
          method: util.toUpperCase(req.method) || 'CONNECT',
          httpVersion: req.httpVersion || '1.1',
          headers: headers,
          rawHeaderNames: reqRawHeaderNames
        };
        var resData = {headers: {}};
        data = reqEmitter.data = {
          id: req.reqId,
          url: options.host,
          startTime: Date.now(),
          rules: _rules,
          req: reqData,
          res: resData,
          isHttps: true,
          rulesHeaders: req.rulesHeaders
        };
        var cId = headers['x-whistle-composer-id'];
        if (cId) {
          data.cId = cId;
          delete headers['x-whistle-composer-id'];
        }
        if (!filter.hide) {
          proxy.emit('request', reqEmitter);
        }

        if (req.enable.abort || filter.abort || disable.tunnel) {
          return reqSocket.destroy();
        }

        var statusCode = util.getMatcherValue(_rules.statusCode);
        if (statusCode) {
          if (statusCode == 200) {
            resSocket = util.getEmptyRes();
            var reqDelay = util.getMatcherValue(_rules.reqDelay);
            data.requestTime = data.dnsTime = Date.now();
            if (reqDelay > 0) {
              setTimeout(handleConnect, reqDelay);
            } else {
              handleConnect();
            }
            return;
          }
          return sendEstablished(statusCode);
        }

        pluginMgr.loadPlugin(plugin, function() {
          var tunnelPort, proxyUrl;
          if(plugin) {
            tunnelPort = plugin.ports && plugin.ports.tunnelPort;
            if (!tunnelPort) {
              return emitError(new Error('No plugin.tunnelServer'));
            }
            proxyUrl = 'proxy://127.0.0.1:' + tunnelPort;
            pluginMgr.addRuleHeaders(req, _rules);
          }

          var realUrl = _rules.rule && _rules.rule.url.replace('https:', 'tunnel:');
          if (/^tunnel:\/\//.test(realUrl) && realUrl != tunnelUrl) {
            tunnelUrl = realUrl;
            data.realUrl = realUrl.replace('tunnel://', '');
            parseUrl();
          }

          rules.getProxy(tunnelUrl, proxyUrl ? null : req, function(err, hostIp, hostPort) {
            if (!proxyUrl) {
              proxyUrl = _rules.proxy ? _rules.proxy.matcher : null;
            }

            if (proxyUrl) {
              var isSocks = /^socks:\/\//.test(proxyUrl);
              var _url = 'http:' + util.removeProtocol(proxyUrl);
              data.proxy = true;
              resolveHost(_url, function(ip) {
                options = parseUrl(_url, isSocks ? 1080 : 80);
                var isProxyPort = options.port == config.port;
                if (isProxyPort && util.isLocalAddress(ip)) {
                  return emitError(new Error('Unable to proxy to itself'));
                }
                var onConnect = function(proxySocket, _res) {
                  resSocket = proxySocket;
                  res = _res;
                  handleConnect();
                  abortIfUnavailable(resSocket);
                };
                var dstOptions = url.parse(tunnelUrl);
                dstOptions.proxyHost = ip;
                dstOptions.proxyPort = parseInt(options.port, 10);
                resData.port = dstOptions.port = dstOptions.port || 443;
                dstOptions.host = dstOptions.hostname;
                var _headers = extend({}, headers);
                pluginMgr.addRuleHeaders(req, _rules, _headers);
                _headers.host = dstOptions.hostname + ':' + (dstOptions.port || 443);
                util.parseRuleJson(_rules.reqHeaders, function(reqHeaders) {
                  extend(headers, reqHeaders);
                  if (disable.clientIp || disable.clientIP) {
                    delete headers[config.CLIENT_IP_HEAD];
                  } else {
                    var forwardedFor = util.getMatcherValue(_rules.forwardedFor);
                    if (forwardedFor) {
                      headers[config.CLIENT_IP_HEAD] = forwardedFor;
                    }
                  }
                  var delReqHeaders = util.parseDeleteProperties(req).reqHeaders;
                  Object.keys(delReqHeaders).forEach(function(name) {
                    delete headers[name];
                  });
                  dstOptions.headers = formatHeaders(headers, reqRawHeaderNames);
                  if (isSocks) {
                    dstOptions.proxyPort = options.port || 1080;
                    dstOptions.localDNS = false;
                    dstOptions.auths = config.getAuths(options);
                  } else {
                    dstOptions.proxyPort = options.port || 80;
                    dstOptions.proxyAuth = options.auth;
                    if (isProxyPort) {
                      _headers[config.WEBUI_HEAD] = 1;
                    }
                  }
                  var netMgr = isSocks ? socks : config;
                  var reqDelay = util.getMatcherValue(_rules.reqDelay);
                  if (reqDelay > 0) {
                    setTimeout(function() {
                      netMgr.connect(dstOptions, onConnect).on('error', emitError);
                    }, reqDelay);
                  } else {
                    netMgr.connect(dstOptions, onConnect).on('error', emitError);
                  }
                });
              });
            } else {
              tunnel(hostIp, hostPort);
            }
          });
        });

        function tunnel(hostIp, hostPort) {
          resolveHost(tunnelUrl, function(ip, port) {
            if (port) {
              resData.ip = ip + ':' + port;
              resData.port = port;
            } else {
              resData.ip = ip;
              resData.port = port = options.port;
            }
            resSocket = net.connect(port, ip, handleConnect);
            abortIfUnavailable(resSocket);
          }, hostIp, hostPort);
        }

        function handleConnect() {
          reqSocket.headers = headers;
          reqSocket.fullUrl = tunnelUrl;
          reqSocket.useTunnelPolicy = useTunnelPolicy;
          socketMgr.handleConnect(reqSocket, resSocket);
          var resDelay = util.getMatcherValue(_rules.resDelay);
          if (resDelay > 0) {
            setTimeout(sendEstablished, resDelay);
          } else {
            sendEstablished();
          }
        }

        function resolveHost(url, callback, hostIp, hostPort) {
          var hostHandler = function(err, ip, port, host) {
            if (host) {
              _rules.host = host;
            }
            data.requestTime = data.dnsTime = Date.now();
            resData.ip = ip || LOCALHOST;
            reqEmitter.emit('send', data);
            err ? emitError(err) : callback(ip, port);
          };
          if (hostIp) {
            hostHandler(null, hostIp, hostPort);
          } else {
            rules.resolveHost(url, hostHandler, rulesMgr, req.rulesFileMgr, req.headerRulesMgr);
          }
        }

        function abortIfUnavailable(socket) {
          socket.on('error', emitError).on('close', emitError);
        }

        function sendEstablished(code) {
          if (res) {
            code = res.statusCode;
          } else {
            code = code || 200;
            res = {
              statusCode: code,
              headers: {
                'proxy-agent': config.name
              },
              rawHeaders: ['proxy-agent', 'Proxy-Agent']
            };
          }
          var resHeaders = res.headers;
          delete req.whistlePlugins;
          pluginMgr.getResRules(req, res, function() {
            var reqRules = req.rules;
            util.parseRuleJson(reqRules.resHeaders, function(newResHeaders) {
              extend(resHeaders, newResHeaders);
              var responseFor = util.getMatcherValue(reqRules.responseFor);
              if (responseFor) {
                resHeaders['x-whistle-response-for'] = responseFor;
              }
              var delResHeaders = util.parseDeleteProperties(req).resHeaders;
              Object.keys(delResHeaders).forEach(function(name) {
                delete resHeaders[name];
              });
              if (!resHeaders['proxy-agent']) {
                resHeaders['proxy-agent'] = config.name;
                res.rawHeaders = res.rawHeaders || [];
                res.rawHeaders.push('proxy-agent', 'Proxy-Agent');
              }
              var message = code == 200 ? 'Connection Established' : (STATUS_CODES[code] || 'unknown');
              var statusLine = ['HTTP/1.1', code, message].join(' ');
              var rawHeaderNames = getRawHeaderNames(res.rawHeaders) || {};
              var rawData = [statusLine, getRawHeaders(formatHeaders(resHeaders, rawHeaderNames))].join('\r\n') + '\r\n\r\n';
              if (code && code != 200) {
                reqSocket.end(rawData);
              } else {
                reqSocket.write(rawData);
              }
              if (reqEmitter) {
                responsed = true;
                data.responseTime = data.endTime = Date.now();
                resData.rawHeaderNames = rawHeaderNames;
                resData.statusCode = code || 200;
                resData.headers = resHeaders;
                reqEmitter.emit('response', data);
                reqEmitter.emit('end', data);
              }
            });
          });
          return reqSocket;
        }

        function emitError(err) {
          if (responsed) {
            return;
          }
          responsed = true;
          resSocket && resSocket.destroy();
          reqSocket.destroy();
          if (!reqEmitter) {
            return;
          }
          data.responseTime = data.endTime = Date.now();

          if (!resData.ip) {
            resData.ip = LOCALHOST;
          }

          if (!err) {
            err = new Error('Aborted');
            data.reqError = true;
            resData.statusCode ='aborted';
            reqData.body = util.getErrorStack(err);
            reqEmitter.emit('abort', data);
          } else {
            data.resError = true;
            resData.statusCode = resData.statusCode || 502;
            resData.body = util.getErrorStack(err);
            util.emitError(reqEmitter, data);
          }
        }
      });
    });
  });

  return server;
}

module.exports = tunnelProxy;
<|endoftext|>


<commit_before>// ==UserScript==
// @author      Robert Slifka (github @rslifka)
// @connect     docs.google.com
// @connect     rslifka.github.io
// @copyright   2017-2018, Robert Slifka (https://github.com/rslifka/fate_of_all_fools)
// @description Enhancements to the Destiny Item Manager
// @grant       GM_addStyle
// @grant       GM_getResourceText
// @grant       GM_getValue
// @grant       GM_log
// @grant       GM_setValue
// @grant       GM_xmlhttpRequest
// @homepage    https://github.com/rslifka/fate_of_all_fools
// @license     MIT; https://raw.githubusercontent.com/rslifka/fate_of_all_fools/master/LICENSE.txt
// @match       https://*.destinyitemmanager.com/*
// @name        Fate of All Fools
// @require     https://rslifka.github.io/fate_of_all_fools/fateOfAllFools.js
// @resource    fateOfAllFoolsCSS https://rslifka.github.io/fate_of_all_fools/fateOfAllFools.css
// @run-at      document-start
// @supportURL  https://github.com/rslifka/fate_of_all_fools/issues
// @version     488
// ==/UserScript==
<commit_msg>AUTO-CREATED Release Artifact v489 c/o Travis<commit_after>// ==UserScript==
// @author      Robert Slifka (github @rslifka)
// @connect     docs.google.com
// @connect     rslifka.github.io
// @copyright   2017-2018, Robert Slifka (https://github.com/rslifka/fate_of_all_fools)
// @description Enhancements to the Destiny Item Manager
// @grant       GM_addStyle
// @grant       GM_getResourceText
// @grant       GM_getValue
// @grant       GM_log
// @grant       GM_setValue
// @grant       GM_xmlhttpRequest
// @homepage    https://github.com/rslifka/fate_of_all_fools
// @license     MIT; https://raw.githubusercontent.com/rslifka/fate_of_all_fools/master/LICENSE.txt
// @match       https://*.destinyitemmanager.com/*
// @name        Fate of All Fools
// @require     https://rslifka.github.io/fate_of_all_fools/fateOfAllFools.js
// @resource    fateOfAllFoolsCSS https://rslifka.github.io/fate_of_all_fools/fateOfAllFools.css
// @run-at      document-start
// @supportURL  https://github.com/rslifka/fate_of_all_fools/issues
// @version     489
// ==/UserScript==
<|endoftext|>


<commit_before>// Copyright (c) 2015 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

module.exports.timestamp = function (assert, value) {
    assert.ok(typeof value === 'number');
    assert.ok(value.toString().length === 13);
};

// Sets the first time it's seen then validates the rest of the time
module.exports.checkId = function (idStore, idKey) {
    return function (assert, id, key) {
        if (!idStore[idKey]) {
            idStore[idKey] = id;
            return;
        }

        assert.equals(id, idStore[idKey], "idKey: " + idKey + " key: " + key);
    };
};

module.exports.validateSpans =
function validateSpans(assert, actual, expected) {
    // Spans may be received in a different order than in the fixture, so we
    // need to find a way to identify them in order to check their contents.
    // Unfortunately since the ids are randomly generated we can't use those.
    // So we base an id off the contents and then validate.

    var actualById = {};
    var expectedById = {};

    function mapSpanToUniqueId(item) {
        return item.name + item.endpoint.ipv4 + item.endpoint.port +
            item.annotations.reduce(function (str, item) {
                return str + item.value;
            }, "");
    }

    actual.forEach(function (item) {
        actualById[mapSpanToUniqueId(item)] = item;
    });

    expected.forEach(function (item) {
        expectedById[mapSpanToUniqueId(item)] = item;
    });

    module.exports.validate(assert, actualById, expectedById);
};

module.exports.validate = function validate(assert, actual, expected) {
    Object.keys(expected).forEach(function (key) {
        var actualValue = actual[key];
        var expectedValue = expected[key];

        if (Buffer.isBuffer(actualValue)) {
            actualValue = actualValue.toString('hex');
        }

        if (typeof expectedValue === 'function') {
            return expectedValue(assert, actualValue, key);
        }

        if (typeof expectedValue === 'object') {
            return validate(assert, actualValue, expectedValue);
        }

        assert.equals(actualValue, expectedValue, "key: " + key);
    });
};

<commit_msg>test/lib/simple_validators: improve<commit_after>// Copyright (c) 2015 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

module.exports.timestamp = function (assert, value) {
    assert.ok(typeof value === 'number');
    assert.ok(value.toString().length === 13);
};

// Sets the first time it's seen then validates the rest of the time
module.exports.checkId = function (idStore, idKey) {
    return function (assert, id, key) {
        if (!idStore[idKey]) {
            idStore[idKey] = id;
            return;
        }

        assert.equals(id, idStore[idKey], "idKey: " + idKey + " key: " + key);
    };
};

module.exports.validateSpans =
function validateSpans(assert, actual, expected) {
    // Spans may be received in a different order than in the fixture, so we
    // need to find a way to identify them in order to check their contents.
    // Unfortunately since the ids are randomly generated we can't use those.
    // So we base an id off the contents and then validate.

    var actualById = {};
    var expectedById = {};

    function mapSpanToUniqueId(item) {
        return item.name + item.endpoint.ipv4 + item.endpoint.port +
            item.annotations.reduce(function (str, item) {
                return str + item.value;
            }, "");
    }

    actual.forEach(function (item) {
        actualById[mapSpanToUniqueId(item)] = item;
    });

    expected.forEach(function (item) {
        expectedById[mapSpanToUniqueId(item)] = item;
    });

    validate(assert, actualById, expectedById);
};

module.exports.validate = validate;
module.exports.validate1 = validate1;

function validate(assert, actual, expected, prefix) {
    if (prefix) {
        prefix += '.';
    } else {
        prefix = '';
    }
    Object.keys(expected).forEach(function each(key) {
        validate1(assert,
            prefix + key,
            actual && actual[key],
            expected && expected[key]);
    });
}

function validate1(assert, desc, actual, expected) {
    if (Buffer.isBuffer(actual)) {
        actual = actual.toString('hex');
    }

    if (typeof expected === 'function') {
        return expected(assert, actual, desc);
    }

    if (typeof expected === 'object') {
        return validate(assert, actual, expected, desc);
    }

    assert.equals(actual, expected, desc);
}
<|endoftext|>


<commit_before>(function($){
  var jsonpID = 0;

  function empty() {}

  $.ajaxJSONP = function(options){
    var jsonpString = 'jsonp' + ++jsonpID,
        script = document.createElement('script');
    window[jsonpString] = options.success;
    script.src = options.url.replace(/callback=\?/, 'callback=' + jsonpString);
    $('head').append(script);
  };

  $.ajax = function(options){
    // { type, url, data, success, dataType, contentType }
    options = options || {};

    if (options.url && /=\?/.test(options.url))
      return $.ajaxJSONP(options);

    var data = options.data,
        callback = options.success || empty,
        errback = options.error || empty,
        mime = mimeTypes[options.dataType],
        content = options.contentType,
        xhr = new XMLHttpRequest();

    xhr.onreadystatechange = function(){
      if (xhr.readyState == 4) {
        if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 0) {
          if (mime == 'application/json') {
            var result, error = false;
            try {
              result = JSON.parse(xhr.responseText);
            } catch (e) {
              error = e;
            }
            if (error) errback(xhr, 'parsererror', error);
            else callback(result, 'success', xhr);
          } else callback(xhr.responseText, 'success', xhr);
        } else {
          errback(xhr, 'error');
        }
      }
    };

    xhr.open(options.type || 'GET', options.url || window.location, true);
    if (mime) xhr.setRequestHeader('Accept', mime);
    if (data instanceof Object) data = JSON.stringify(data), content = content || 'application/json';
    if (content) xhr.setRequestHeader('Content-Type', content);
    xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
    xhr.send(data);
  };

  var mimeTypes = $.ajax.mimeTypes = {
    json: 'application/json',
    xml:  'application/xml',
    html: 'text/html',
    text: 'text/plain'
  };

  $.get = function(url, success){ $.ajax({ url: url, success: success }) };
  $.post = function(url, data, success, dataType){
    if (data instanceof Function) dataType = dataType || success, success = data, data = null;
    $.ajax({ type: 'POST', url: url, data: data, success: success, dataType: dataType });
  };
  $.getJSON = function(url, success){ $.ajax({ url: url, success: success, dataType: 'json' }) };

  $.fn.load = function(url, success){
    if (!this.length) return this;
    var self = this, parts = url.split(/\s/), selector;
    if (parts.length > 1) url = parts[0], selector = parts[1];
    $.get(url, function(response){
      self.html(selector ?
        $(document.createElement('div')).html(response).find(selector).html()
        : response);
      success && success();
    });
    return this;
  };
})(Zepto);
<commit_msg>Some small optimizations in $.ajaxJSONP. Make sure not to overwrite @johannburkard’s changes from commit 09cdbc4e1cd0b14b5aa63f67fbb4233b8542a557.<commit_after>(function($){
  var jsonpID = 0;

  function empty() {}

  $.ajaxJSONP = function(options){
    var jsonpString = 'jsonp' + ++jsonpID,
        script = document.createElement('script');
    window[jsonpString] = function(data){
      options.success(data);
      delete window.jsonpString;
    };
    script.src = options.url.replace(/=\?/, '=' + jsonpString);
    $('head').append(script);
  };

  $.ajax = function(options){
    // { type, url, data, success, dataType, contentType }
    options = options || {};

    if (options.url && /=\?/.test(options.url))
      return $.ajaxJSONP(options);

    var data = options.data,
        callback = options.success || empty,
        errback = options.error || empty,
        mime = mimeTypes[options.dataType],
        content = options.contentType,
        xhr = new XMLHttpRequest();

    xhr.onreadystatechange = function(){
      if (xhr.readyState == 4) {
        if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 0) {
          if (mime == 'application/json') {
            var result, error = false;
            try {
              result = JSON.parse(xhr.responseText);
            } catch (e) {
              error = e;
            }
            if (error) errback(xhr, 'parsererror', error);
            else callback(result, 'success', xhr);
          } else callback(xhr.responseText, 'success', xhr);
        } else {
          errback(xhr, 'error');
        }
      }
    };

    xhr.open(options.type || 'GET', options.url || window.location, true);
    if (mime) xhr.setRequestHeader('Accept', mime);
    if (data instanceof Object) data = JSON.stringify(data), content = content || 'application/json';
    if (content) xhr.setRequestHeader('Content-Type', content);
    xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
    xhr.send(data);
  };

  var mimeTypes = $.ajax.mimeTypes = {
    json: 'application/json',
    xml:  'application/xml',
    html: 'text/html',
    text: 'text/plain'
  };

  $.get = function(url, success){ $.ajax({ url: url, success: success }) };
  $.post = function(url, data, success, dataType){
    if (data instanceof Function) dataType = dataType || success, success = data, data = null;
    $.ajax({ type: 'POST', url: url, data: data, success: success, dataType: dataType });
  };
  $.getJSON = function(url, success){ $.ajax({ url: url, success: success, dataType: 'json' }) };

  $.fn.load = function(url, success){
    if (!this.length) return this;
    var self = this, parts = url.split(/\s/), selector;
    if (parts.length > 1) url = parts[0], selector = parts[1];
    $.get(url, function(response){
      self.html(selector ?
        $(document.createElement('div')).html(response).find(selector).html()
        : response);
      success && success();
    });
    return this;
  };
})(Zepto);
<|endoftext|>


<commit_before>// ==UserScript==
// @author      Robert Slifka (github @rslifka)
// @connect     docs.google.com
// @connect     rslifka.github.io
// @copyright   2017-2018, Robert Slifka (https://github.com/rslifka/fate_of_all_fools)
// @description Enhancements to the Destiny Item Manager
// @grant       GM_addStyle
// @grant       GM_getResourceText
// @grant       GM_getValue
// @grant       GM_log
// @grant       GM_setValue
// @grant       GM_xmlhttpRequest
// @homepage    https://github.com/rslifka/fate_of_all_fools
// @license     MIT; https://raw.githubusercontent.com/rslifka/fate_of_all_fools/master/LICENSE.txt
// @match       https://*.destinyitemmanager.com/*
// @name        Fate of All Fools
// @require     https://rslifka.github.io/fate_of_all_fools/fateOfAllFools.js
// @resource    fateOfAllFoolsCSS https://rslifka.github.io/fate_of_all_fools/fateOfAllFools.css
// @run-at      document-start
// @supportURL  https://github.com/rslifka/fate_of_all_fools/issues
// @version     203
// ==/UserScript==
<commit_msg>AUTO-CREATED Release Artifact v204 c/o Travis<commit_after>// ==UserScript==
// @author      Robert Slifka (github @rslifka)
// @connect     docs.google.com
// @connect     rslifka.github.io
// @copyright   2017-2018, Robert Slifka (https://github.com/rslifka/fate_of_all_fools)
// @description Enhancements to the Destiny Item Manager
// @grant       GM_addStyle
// @grant       GM_getResourceText
// @grant       GM_getValue
// @grant       GM_log
// @grant       GM_setValue
// @grant       GM_xmlhttpRequest
// @homepage    https://github.com/rslifka/fate_of_all_fools
// @license     MIT; https://raw.githubusercontent.com/rslifka/fate_of_all_fools/master/LICENSE.txt
// @match       https://*.destinyitemmanager.com/*
// @name        Fate of All Fools
// @require     https://rslifka.github.io/fate_of_all_fools/fateOfAllFools.js
// @resource    fateOfAllFoolsCSS https://rslifka.github.io/fate_of_all_fools/fateOfAllFools.css
// @run-at      document-start
// @supportURL  https://github.com/rslifka/fate_of_all_fools/issues
// @version     204
// ==/UserScript==
<|endoftext|>


<commit_before>iD.ui.Success = function(context) {
    var event = d3.dispatch('cancel'),
        changeset;

    function success(selection) {
        var message = (changeset.comment || t('success.edited_osm')).substring(0, 130) +
            ' ' + context.connection().changesetURL(changeset.id);

        var header = selection.append('div')
            .attr('class', 'header fillL');

        header.append('button')
            .attr('class', 'fr')
            .append('span')
            .attr('class', 'icon close')
            .on('click', function() { event.cancel(success) });

        header.append('h3')
            .text(t('success.just_edited'));

        var body = selection.append('div')
            .attr('class', 'body save-success');

        body.append('p')
            .html(t('success.help_html'));

        var changesetURL = context.connection().changesetURL(changeset.id);

        body.append('a')
            .attr('class', 'button col12 osm')
            .attr('target', '_blank')
            .attr('href', changesetURL)
            .text(t('success.view_on_osm'));

        var sharing = {
            facebook: 'https://facebook.com/sharer/sharer.php?u=' + encodeURIComponent(changesetURL),
            twitter: 'https://twitter.com/intent/tweet?source=webclient&text=' + encodeURIComponent(message),
            google: 'https://plus.google.com/share?url=' + encodeURIComponent(changesetURL)
        };

        body.selectAll('.button.social')
            .data(d3.entries(sharing))
            .enter().append('a')
            .attr('class', function(d) { return 'button social col4 ' + d.key; })
            .attr('target', '_blank')
            .attr('href', function(d) { return d.value; })
            .call(bootstrap.tooltip()
                .title(function(d) { return t('success.' + d.key); })
                .placement('bottom'));
    }

    success.changeset = function(_) {
        if (!arguments.length) return changeset;
        changeset = _;
        return success;
    };

    return d3.rebind(success, event, 'on');
};
<commit_msg>Prevent 'zoom in to edit' from showing up during save success, closes #1792<commit_after>iD.ui.Success = function(context) {
    var event = d3.dispatch('cancel'),
        changeset;

    function success(selection) {
        var message = (changeset.comment || t('success.edited_osm')).substring(0, 130) +
            ' ' + context.connection().changesetURL(changeset.id);

        var header = selection.append('div')
            .attr('class', 'header fillL');

        header.append('button')
            .attr('class', 'fr')
            .append('span')
            .attr('class', 'icon close')
            .on('click', function() { event.cancel(success) });

        header.append('h3')
            .text(t('success.just_edited'));

        var body = selection.append('div')
            .attr('class', 'body save-success fillL');

        body.append('p')
            .html(t('success.help_html'));

        var changesetURL = context.connection().changesetURL(changeset.id);

        body.append('a')
            .attr('class', 'button col12 osm')
            .attr('target', '_blank')
            .attr('href', changesetURL)
            .text(t('success.view_on_osm'));

        var sharing = {
            facebook: 'https://facebook.com/sharer/sharer.php?u=' + encodeURIComponent(changesetURL),
            twitter: 'https://twitter.com/intent/tweet?source=webclient&text=' + encodeURIComponent(message),
            google: 'https://plus.google.com/share?url=' + encodeURIComponent(changesetURL)
        };

        body.selectAll('.button.social')
            .data(d3.entries(sharing))
            .enter().append('a')
            .attr('class', function(d) { return 'button social col4 ' + d.key; })
            .attr('target', '_blank')
            .attr('href', function(d) { return d.value; })
            .call(bootstrap.tooltip()
                .title(function(d) { return t('success.' + d.key); })
                .placement('bottom'));
    }

    success.changeset = function(_) {
        if (!arguments.length) return changeset;
        changeset = _;
        return success;
    };

    return d3.rebind(success, event, 'on');
};
<|endoftext|>


<commit_before>define([
	'ractive',
	'config/defaults/options',
	'config/config'
], function (
	Ractive,
	defaults,
	config
) {

	'use strict';

	return function () {

		var Child, ractive, fixture = document.getElementById( 'qunit-fixture' );

		function configureRactive () {
			Child = void 0;
			ractive = void 0;
		}

		function testConfiguration ( target, compare, noTargetDefaults ) {

			console.log( 'config', config );

			config.forEach( itemConfig => {

				var name = itemConfig.name || itemConfig,
					actual = target,
					expected = compare.prototype;

				if ( expected && ( name in expected ) ) {
					ok( name in actual, 'has ' + name);
				}

				if ( expected ) {
					if ( !config.registries[ name ] && name !== 'template' ) { // TODO template is a special case... this should probably be handled differently
						deepEqual( actual[ name ], expected[ name ], 'compare ' + name );
					}
				}
			});
		}

		test( 'base Ractive', t => {
			t.deepEqual( Ractive.defaults, Ractive.prototype, 'defaults aliases prototype' );

			for( let key in defaults ) {
				t.ok( Ractive.defaults.hasOwnProperty( key ), 'has default ' + key )
			}
		});

		module( 'Extend Ractive', {
			setup: function () {
				configureRactive();
				Child = () => {};
				Child.defaults = {};
				config.extend( Ractive, Child, {} );
			}
		} );

		module( 'Configure Instance', {
			setup: function () {
				configureRactive();
				ractive = new Ractive();
			}
		} );

		test( 'ractive instance', t => {
			console.group( 'here' );
			console.dir( ractive );
			console.dir( Ractive );
			testConfiguration( ractive, Ractive, true );
			console.groupEnd();
		});

		module( 'Configure Instance', { setup: configureRactive } );

		test( 'find registry configuration', t => {
			var adaptor1 = {}, adaptor2 = {},
				parent = new Ractive( { adaptors: { foo: adaptor1 } } ),
				ractive = new Ractive( { adaptors: { bar: adaptor2 } } );

			ractive._parent = parent;

			t.equal( config.registries.adaptors.find( ractive, 'foo' ), adaptor1 );
			t.equal( config.registries.adaptors.find( ractive, 'bar' ), adaptor2 );
		});

		module( 'options' );

		if ( Ractive.magic ) {
			test( 'are passed to init with correct values ', t => {
				expect( 2 );

				var Component = Ractive.extend({
					init: function ( options ) {
						t.equal( options.foo, 'bar' );
						t.ok( options.magic );
					}
				});

				var ractive = new Component({
					el: fixture,
					foo: 'bar',
					magic: true
				});
			});
		}
	};
});
<commit_msg>remove console logs<commit_after>define([
	'ractive',
	'config/defaults/options',
	'config/config'
], function (
	Ractive,
	defaults,
	config
) {

	'use strict';

	return function () {

		var Child, ractive, fixture = document.getElementById( 'qunit-fixture' );

		function configureRactive () {
			Child = void 0;
			ractive = void 0;
		}

		function testConfiguration ( target, compare, noTargetDefaults ) {

			config.forEach( itemConfig => {

				var name = itemConfig.name || itemConfig,
					actual = target,
					expected = compare.prototype;

				if ( expected && ( name in expected ) ) {
					ok( name in actual, 'has ' + name);
				}

				if ( expected ) {
					if ( !config.registries[ name ] && name !== 'template' ) { // TODO template is a special case... this should probably be handled differently
						deepEqual( actual[ name ], expected[ name ], 'compare ' + name );
					}
				}
			});
		}

		test( 'base Ractive', t => {
			t.deepEqual( Ractive.defaults, Ractive.prototype, 'defaults aliases prototype' );

			for( let key in defaults ) {
				t.ok( Ractive.defaults.hasOwnProperty( key ), 'has default ' + key )
			}
		});

		module( 'Extend Ractive', {
			setup: function () {
				configureRactive();
				Child = () => {};
				Child.defaults = {};
				config.extend( Ractive, Child, {} );
			}
		} );

		module( 'Configure Instance', {
			setup: function () {
				configureRactive();
				ractive = new Ractive();
			}
		} );

		test( 'ractive instance', t => {
			testConfiguration( ractive, Ractive, true );
		});

		module( 'Configure Instance', { setup: configureRactive } );

		test( 'find registry configuration', t => {
			var adaptor1 = {}, adaptor2 = {},
				parent = new Ractive( { adaptors: { foo: adaptor1 } } ),
				ractive = new Ractive( { adaptors: { bar: adaptor2 } } );

			ractive._parent = parent;

			t.equal( config.registries.adaptors.find( ractive, 'foo' ), adaptor1 );
			t.equal( config.registries.adaptors.find( ractive, 'bar' ), adaptor2 );
		});

		module( 'options' );

		if ( Ractive.magic ) {
			test( 'are passed to init with correct values ', t => {
				expect( 2 );

				var Component = Ractive.extend({
					init: function ( options ) {
						t.equal( options.foo, 'bar' );
						t.ok( options.magic );
					}
				});

				var ractive = new Component({
					el: fixture,
					foo: 'bar',
					magic: true
				});
			});
		}
	};
});
<|endoftext|>


<commit_before>/*
 *  Copyright 2011 Rackspace
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 */

var fs = require('fs');
var path = require('path');
var util = require('util');

var _ = require('underscore');
var async = require('async');
var sqlite3 = require('sqlite3').verbose();

var settings = require('../settings');
var utils = require('../utils');
var events = require('./events');
var log = require('../log');

var EVENTS = events.EVENT_TYPES;

var db;

var INTEGRITY_ERROR = 19;

var SCHEMA = ["CREATE TABLE IF NOT EXISTS events (project VARCHAR(40) NOT NULL, " +
  "user varchar(40) NOT NULL, " +
  "time TIMESTAMP NOT NULL, " +
  "related_api VARCHAR(40) NOT NULL, " +
  "id TEXT, " +
  "points INTEGER, " +
  "event TEXT, " +
  "url TEXT, " +
  "title TEXT, UNIQUE(project, id, user, related_api, event));",

  // TODO: we're storing "ok" and "err" in health. fix that
  "CREATE TABLE IF NOT EXISTS metrics (project VARCHAR(40) NOT NULL," +
  "service_name VARCHAR(40) PRIMARY KEY, " +
  "time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, "+
  "healthy BOOL NOT NULL, " +
  "ttl TINYINT NOT NULL, " +
  "ip VARCHAR(20) NOT NULL, " +
  "services TEXT NOT NULL);",

  "CREATE TABLE IF NOT EXISTS multipliers (event VARCHAR(40) PRIMARY KEY NOT NULL, "+
  "value TINYINT NOT NULL);",

  "CREATE TABLE IF NOT EXISTS devops_urls (id INTEGER PRIMARY KEY NOT NULL, "+
  "project VARCHAR(60) NOT NULL, " +
  "url VARCHAR(1024) NOT NULL, " +
  "data TEXT, " +
  "UNIQUE(project), CHECK(project <> ''));",

  "CREATE TABLE IF NOT EXISTS alias_display (id INTEGER PRIMARY KEY, " +
  "display_name VARCHAR(40) NOT NULL, UNIQUE(display_name));",

  "CREATE TABLE IF NOT EXISTS aliases (alias_display_id REFERENCES alias_display(id) NOT NULL," +
  "alias TEXT NOT NULL, related_api VARCHAR(40) NOT NULL, "+
  "UNIQUE(alias, related_api), UNIQUE(alias, alias_display_id), UNIQUE(related_api, alias_display_id));"
];
// TODO: back up aliases before changing schemas

// a wrapper (ORM le sigh) for interacting with sqlite3
module.exports = new utils.make_class({
  init: function(){
    var self = this;
    var _path = path.join(__dirname, '..', 'db.sqlite');
    self.db = new sqlite3.Database(_path);
    self.db.on('trace', function(event){
      log.debug(event.toString());
    });
  },
  create_tables: function(cb){
    var self = this;
    var queries = [];
    // create schema if needed
    _.each(SCHEMA, function(create_table){
      queries.push(_.bind(self.db.run, self.db, create_table));
    });
    // update multipliers
    _.each(events.EVENT_TYPES, function(event){
      queries.push(_.bind(self.db.run, self.db,
        "INSERT OR REPLACE INTO multipliers (event, value) VALUES (?, ?)",
        event.name, event.multiplier)
      );
    });
    async.series(queries, function(err, results){
      if (err){
        utils.die(err);
      }
      cb(err, results);
    });
  },
  squelch_integrity_error: function (cb) {
    var self = this;
    return function (err, result) {
      if (err && err.errno === INTEGRITY_ERROR) {
        err = null;
      }
      if (cb) {
        cb(err, result);
      }
    };
  },
  get_last_v1_time: function(project, cb){
    var self = this;

    self.db.get("SELECT max(time) as date FROM events where project=? and related_api=?;",
      [project, events.RELATED_APIS.version_one],
      function(err, results){
        return cb(err, new Date(results ? results.date : null));
      });
  },
  add_event: function(event, project, cb){
    var self = this;
    var details;
    var score;

    if (!event.user){
      log.log("No user for event. Not inserting.", event);
      return cb();
    }
    self.db.run("INSERT INTO events(project, user, time, points, related_api, id, event, url, title) " +
      "values (?, ?, ?, ?, ?, ?, ?, ?, ?);",
      [project, event.user, event.date, event.points, event.related_api, event.id,
      event.event.name, event.url, event.title], self.squelch_integrity_error(cb));
  },
  // TODO: this is kinda stupid, figure out how to do it the right way
  add_multiple_events: function(events, project, cb){
    var self = this;
    var values = [];

    _.each(events, function(event){
      self.add_event(event, project);
    });
  },
  get_highscores: function(project, start, end, cb){
    var self = this;
    var query = "SELECT COALESCE((SELECT display_name from alias_display where "+
      "id=aliases.alias_display_id), user) as name, user, "+
      "sum(points * (SELECT value FROM multipliers WHERE event=events.event)) as score from events " +
      "LEFT OUTER JOIN aliases on user=alias and events.related_api=aliases.related_api ";
    var args = [];
    var where = "";
    if (start){
      start = Date.parse(start);
      where += " time>=? AND ";
      args.push(start);
    }
    if (end){
      end = Date.parse(end);
      where += ' time<? AND ';
      args.push(end);
    }
    if (project){
      where += " project=? ";
      args.push(project);
    }

    if (where.length > 0){
      query += " where " + where;
    }

    query += " group by name order by score desc;";

    self.db.all(query, args, cb);
  },
  get_highscore_breakdown: function(project, start, end, user, cb){
    var self = this;
    var query = "SELECT COALESCE((SELECT display_name from alias_display where "+
      "id=aliases.alias_display_id), user) as name, "+
      "user, time, events.related_api, (SELECT value FROM multipliers WHERE event=events.event) as multiplier, " +
      "points * (SELECT value FROM multipliers WHERE event=events.event) as score, points, "+
      "event, url, title, id from events outer left join aliases on user=alias " +
      "and events.related_api=aliases.related_api ";
    var args = [];
    var where = "";
    if (start){
      where += " time>=? AND ";
      args.push(Date.parse(start));
    }
    if (end){
      where += " time<? AND ";
      args.push(Date.parse(end));
    }
    if (user) {
      where += " name=? AND ";
      args.push(user);
    }
    if (project){
      where += " project=? ";
      args.push(project);
    }

    if (where.length > 0){
      query += " where " + where;
    }

    query += " order by time desc;";

    self.db.all(query, args, cb);

  },
  get_aliases: function(display_name, cb){
    var self = this;
    self.db.all("SELECT * FROM aliases WHERE alias_display_id="+
      "(SELECT id FROM alias_display WHERE display_name=?);", display_name, cb);
  },
  get_db: function () {
    var self = this;
    return self.db;
  },
  add_alias: function(alias, display_name, related_api, alias_display_id, cb){
    var self = this;
    var db_ops = [];

    if (!events.RELATED_APIS[related_api]){
      return cb(new Error('use the enum'+related_api));
    }

    if (!display_name || display_name.length <= 0) {
      return cb(new Error("No display name!"));
    }

    if (alias_display_id) {
      db_ops.push(function (cb) {
        self.db.run("UPDATE alias_display SET display_name = ? WHERE id = ?",
          [display_name, alias_display_id], self.squelch_integrity_error(cb));
      });
    }
    else {
      db_ops.push(function (cb) {
        self.db.run("INSERT INTO alias_display (display_name) VALUES (?);",
          [display_name], self.squelch_integrity_error(cb));
      });
    }

    db_ops.push(function (cb) {
      self.db.run("INSERT OR REPLACE INTO aliases(alias, related_api, alias_display_id) "+
        "VALUES(?, ?, COALESCE(?, (SELECT id FROM alias_display WHERE alias_display.display_name=?)));",
      [alias, related_api, alias_display_id || null, display_name], self.squelch_integrity_error(cb));
    });

    async.series(db_ops, cb);
  },
  delete_alias: function(related_api, alias_display_id, cb){
    var self = this;
    self.db.run("DELETE FROM aliases WHERE alias_display_id =? AND related_api = ?;",
      alias_display_id, related_api, cb
    );
  },
  add_service_stat: function(project, ip, host_data, cb){
    var self = this;
    self.db.run("INSERT OR REPLACE INTO metrics (project, service_name, healthy, ttl, ip, time, services) " +
      "VALUES (?, ?, ?, ?, ?, ?, ?);", [ project, host_data.name, host_data.healthy,
      host_data.ttl, ip, host_data.timestamp, JSON.stringify(host_data.services)],
      self.squelch_integrity_error(cb));
  },
  get_service_stats: function(project, cb){
    var self = this;
    var now = new Date().valueOf();
    return self.db.all("SELECT * FROM metrics where project=?;", project, function(err, results){
      _.each(results, function(row){
        row.services = JSON.parse(row.services);
        if (now - row.time > (row.ttl * 1000)) {
          row.healthy = false;
          _.each(row.services, function (service) {
            service.error_msg = "TTL expired! Also, " + (service.error_msg || "... nothing.");
            service.healthy = false;
          });
        }
      });
      cb(err, results);
    });
  },
  has_service_stats: function(project, cb){
    var self = this;
    return self.db.get("SELECT count(1) > 0 AS has_metric FROM metrics WHERE project=? LIMIT 1;",
      project, function(err, result){
      if (result.has_metric > 0) {
        return cb(err, true);
      }
      return cb(err, false);
    });
  },
  get_pr_close_user: function(id, api, cb){
    var self = this;
    return self.db.get('SELECT user FROM events WHERE id=? AND related_api=? AND event=?;',
        id, api, EVENTS.closed.name, cb);
  },
  get_devops: function (project, cb) {
    var self = this;
    if (project === undefined) {
      return self.db.all("SELECT * FROM devops;", cb);
    }
    else {
      return self.db.get("SELECT * FROM devops WHERE project = ?;", [project], cb);
    }
  },
  add_devops: function (project, url, data, cb) {
    var self = this;
    return self.db.run("INSERT INTO devops(project, url, data) VALUES (?, ?);", [project, url, data], self.squelch_integrity_error(cb));
  },
  update_devops: function (id, project, url, data, cb) {
    var self = this;
    return self.db.run("UPDATE devops SET (project = ?, url = ?, data = ? WHERE id = ?;", [project, url, data, id], self.squelch_integrity_error(cb));
  }
})();
<commit_msg>Fix table name. Forgot a ?<commit_after>/*
 *  Copyright 2011 Rackspace
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 */

var fs = require('fs');
var path = require('path');
var util = require('util');

var _ = require('underscore');
var async = require('async');
var sqlite3 = require('sqlite3').verbose();

var settings = require('../settings');
var utils = require('../utils');
var events = require('./events');
var log = require('../log');

var EVENTS = events.EVENT_TYPES;

var db;

var INTEGRITY_ERROR = 19;

var SCHEMA = ["CREATE TABLE IF NOT EXISTS events (project VARCHAR(40) NOT NULL, " +
  "user varchar(40) NOT NULL, " +
  "time TIMESTAMP NOT NULL, " +
  "related_api VARCHAR(40) NOT NULL, " +
  "id TEXT, " +
  "points INTEGER, " +
  "event TEXT, " +
  "url TEXT, " +
  "title TEXT, UNIQUE(project, id, user, related_api, event));",

  // TODO: we're storing "ok" and "err" in health. fix that
  "CREATE TABLE IF NOT EXISTS metrics (project VARCHAR(40) NOT NULL," +
  "service_name VARCHAR(40) PRIMARY KEY, " +
  "time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, "+
  "healthy BOOL NOT NULL, " +
  "ttl TINYINT NOT NULL, " +
  "ip VARCHAR(20) NOT NULL, " +
  "services TEXT NOT NULL);",

  "CREATE TABLE IF NOT EXISTS multipliers (event VARCHAR(40) PRIMARY KEY NOT NULL, "+
  "value TINYINT NOT NULL);",

  "CREATE TABLE IF NOT EXISTS devops (id INTEGER PRIMARY KEY NOT NULL, "+
  "project VARCHAR(60) NOT NULL, " +
  "url VARCHAR(1024) NOT NULL, " +
  "data TEXT, " +
  "UNIQUE(project), CHECK(project <> ''));",

  "CREATE TABLE IF NOT EXISTS alias_display (id INTEGER PRIMARY KEY, " +
  "display_name VARCHAR(40) NOT NULL, UNIQUE(display_name));",

  "CREATE TABLE IF NOT EXISTS aliases (alias_display_id REFERENCES alias_display(id) NOT NULL," +
  "alias TEXT NOT NULL, related_api VARCHAR(40) NOT NULL, "+
  "UNIQUE(alias, related_api), UNIQUE(alias, alias_display_id), UNIQUE(related_api, alias_display_id));"
];
// TODO: back up aliases before changing schemas

// a wrapper (ORM le sigh) for interacting with sqlite3
module.exports = new utils.make_class({
  init: function(){
    var self = this;
    var _path = path.join(__dirname, '..', 'db.sqlite');
    self.db = new sqlite3.Database(_path);
    self.db.on('trace', function(event){
      log.debug(event.toString());
    });
  },
  create_tables: function(cb){
    var self = this;
    var queries = [];
    // create schema if needed
    _.each(SCHEMA, function(create_table){
      queries.push(_.bind(self.db.run, self.db, create_table));
    });
    // update multipliers
    _.each(events.EVENT_TYPES, function(event){
      queries.push(_.bind(self.db.run, self.db,
        "INSERT OR REPLACE INTO multipliers (event, value) VALUES (?, ?)",
        event.name, event.multiplier)
      );
    });
    async.series(queries, function(err, results){
      if (err){
        utils.die(err);
      }
      cb(err, results);
    });
  },
  squelch_integrity_error: function (cb) {
    var self = this;
    return function (err, result) {
      if (err && err.errno === INTEGRITY_ERROR) {
        err = null;
      }
      if (cb) {
        cb(err, result);
      }
    };
  },
  get_last_v1_time: function(project, cb){
    var self = this;

    self.db.get("SELECT max(time) as date FROM events where project=? and related_api=?;",
      [project, events.RELATED_APIS.version_one],
      function(err, results){
        return cb(err, new Date(results ? results.date : null));
      });
  },
  add_event: function(event, project, cb){
    var self = this;
    var details;
    var score;

    if (!event.user){
      log.log("No user for event. Not inserting.", event);
      return cb();
    }
    self.db.run("INSERT INTO events(project, user, time, points, related_api, id, event, url, title) " +
      "values (?, ?, ?, ?, ?, ?, ?, ?, ?);",
      [project, event.user, event.date, event.points, event.related_api, event.id,
      event.event.name, event.url, event.title], self.squelch_integrity_error(cb));
  },
  // TODO: this is kinda stupid, figure out how to do it the right way
  add_multiple_events: function(events, project, cb){
    var self = this;
    var values = [];

    _.each(events, function(event){
      self.add_event(event, project);
    });
  },
  get_highscores: function(project, start, end, cb){
    var self = this;
    var query = "SELECT COALESCE((SELECT display_name from alias_display where "+
      "id=aliases.alias_display_id), user) as name, user, "+
      "sum(points * (SELECT value FROM multipliers WHERE event=events.event)) as score from events " +
      "LEFT OUTER JOIN aliases on user=alias and events.related_api=aliases.related_api ";
    var args = [];
    var where = "";
    if (start){
      start = Date.parse(start);
      where += " time>=? AND ";
      args.push(start);
    }
    if (end){
      end = Date.parse(end);
      where += ' time<? AND ';
      args.push(end);
    }
    if (project){
      where += " project=? ";
      args.push(project);
    }

    if (where.length > 0){
      query += " where " + where;
    }

    query += " group by name order by score desc;";

    self.db.all(query, args, cb);
  },
  get_highscore_breakdown: function(project, start, end, user, cb){
    var self = this;
    var query = "SELECT COALESCE((SELECT display_name from alias_display where "+
      "id=aliases.alias_display_id), user) as name, "+
      "user, time, events.related_api, (SELECT value FROM multipliers WHERE event=events.event) as multiplier, " +
      "points * (SELECT value FROM multipliers WHERE event=events.event) as score, points, "+
      "event, url, title, id from events outer left join aliases on user=alias " +
      "and events.related_api=aliases.related_api ";
    var args = [];
    var where = "";
    if (start){
      where += " time>=? AND ";
      args.push(Date.parse(start));
    }
    if (end){
      where += " time<? AND ";
      args.push(Date.parse(end));
    }
    if (user) {
      where += " name=? AND ";
      args.push(user);
    }
    if (project){
      where += " project=? ";
      args.push(project);
    }

    if (where.length > 0){
      query += " where " + where;
    }

    query += " order by time desc;";

    self.db.all(query, args, cb);

  },
  get_aliases: function(display_name, cb){
    var self = this;
    self.db.all("SELECT * FROM aliases WHERE alias_display_id="+
      "(SELECT id FROM alias_display WHERE display_name=?);", display_name, cb);
  },
  get_db: function () {
    var self = this;
    return self.db;
  },
  add_alias: function(alias, display_name, related_api, alias_display_id, cb){
    var self = this;
    var db_ops = [];

    if (!events.RELATED_APIS[related_api]){
      return cb(new Error('use the enum'+related_api));
    }

    if (!display_name || display_name.length <= 0) {
      return cb(new Error("No display name!"));
    }

    if (alias_display_id) {
      db_ops.push(function (cb) {
        self.db.run("UPDATE alias_display SET display_name = ? WHERE id = ?",
          [display_name, alias_display_id], self.squelch_integrity_error(cb));
      });
    }
    else {
      db_ops.push(function (cb) {
        self.db.run("INSERT INTO alias_display (display_name) VALUES (?);",
          [display_name], self.squelch_integrity_error(cb));
      });
    }

    db_ops.push(function (cb) {
      self.db.run("INSERT OR REPLACE INTO aliases(alias, related_api, alias_display_id) "+
        "VALUES(?, ?, COALESCE(?, (SELECT id FROM alias_display WHERE alias_display.display_name=?)));",
      [alias, related_api, alias_display_id || null, display_name], self.squelch_integrity_error(cb));
    });

    async.series(db_ops, cb);
  },
  delete_alias: function(related_api, alias_display_id, cb){
    var self = this;
    self.db.run("DELETE FROM aliases WHERE alias_display_id =? AND related_api = ?;",
      alias_display_id, related_api, cb
    );
  },
  add_service_stat: function(project, ip, host_data, cb){
    var self = this;
    self.db.run("INSERT OR REPLACE INTO metrics (project, service_name, healthy, ttl, ip, time, services) " +
      "VALUES (?, ?, ?, ?, ?, ?, ?);", [ project, host_data.name, host_data.healthy,
      host_data.ttl, ip, host_data.timestamp, JSON.stringify(host_data.services)],
      self.squelch_integrity_error(cb));
  },
  get_service_stats: function(project, cb){
    var self = this;
    var now = new Date().valueOf();
    return self.db.all("SELECT * FROM metrics where project=?;", project, function(err, results){
      _.each(results, function(row){
        row.services = JSON.parse(row.services);
        if (now - row.time > (row.ttl * 1000)) {
          row.healthy = false;
          _.each(row.services, function (service) {
            service.error_msg = "TTL expired! Also, " + (service.error_msg || "... nothing.");
            service.healthy = false;
          });
        }
      });
      cb(err, results);
    });
  },
  has_service_stats: function(project, cb){
    var self = this;
    return self.db.get("SELECT count(1) > 0 AS has_metric FROM metrics WHERE project=? LIMIT 1;",
      project, function(err, result){
      if (result.has_metric > 0) {
        return cb(err, true);
      }
      return cb(err, false);
    });
  },
  get_pr_close_user: function(id, api, cb){
    var self = this;
    return self.db.get('SELECT user FROM events WHERE id=? AND related_api=? AND event=?;',
        id, api, EVENTS.closed.name, cb);
  },
  get_devops: function (project, cb) {
    var self = this;
    if (project === undefined) {
      return self.db.all("SELECT * FROM devops;", cb);
    }
    else {
      return self.db.get("SELECT * FROM devops WHERE project = ?;", [project], cb);
    }
  },
  add_devops: function (project, url, data, cb) {
    var self = this;
    return self.db.run("INSERT INTO devops(project, url, data) VALUES (?, ?, ?);", [project, url, data], self.squelch_integrity_error(cb));
  },
  update_devops: function (id, project, url, data, cb) {
    var self = this;
    return self.db.run("UPDATE devops SET (project = ?, url = ?, data = ? WHERE id = ?;", [project, url, data, id], self.squelch_integrity_error(cb));
  }
})();
<|endoftext|>


<commit_before>import { TopicObserver } from "./topic-observer";

export class AppClient extends TopicObserver {

    /**
     *
     * @param {MqttClient} mqttClient
     * @param httpClient
     */
    constructor(mqttClient, httpClient) {

        // call super
        super();

        // mqtt client
        this.mqttClient = mqttClient;
        this.event_observer = null;

        // register observer
        this.event_observer = (event) => this.eventHandler(event);
        this.mqttClient.observe(this.event_observer);

        // http client
        this.httpClient = httpClient;

        // initialize
        this.ambulances = undefined;
        this.hospitals = undefined;
        this.bases = undefined;
        this.calls = undefined;

    }

    disconnect() {

        // return if not connected
        if (!this.mqttClient.isConnected)
            return;

        // remove observer
        this.mqttClient.remove(this.event_observer);
        this.event_observer = null;

        // connect to client
        this.mqttClient.disconnect();

    }

    /**
     *
     * @param {MqttEvent} event
     */
    eventHandler(event) {

        console.log(event);

        if (event.event === 'messageReceived') {

            const topic = event.object.destinationName;
            const payload = JSON.parse(event.object.payloadString);

            console.log(topic);
            console.log(payload);

            // broadcast
            this.broadcast(topic, {topic: topic, payload: payload});

        }

    }

    subscribe(filter, fn, options) {
        options = options || {};
        this.mqttClient.subscribe(filter, options);
        this.observe(filter, fn)
    }

    unsubscribe(filter, fn, options) {
        options = options || {};
        this.mqttClient.unsubscribe(filter, options);
        this.remove(filter, fn)
    }

    publish(topic, payload, qos, retained) {
        this.mqttClient.publish(topic, payload, qos, retained);
    }

    updateAmbulance(message) {
        const ambulance = message.payload;
        this.ambulances[ambulance.id] = ambulance;
    }

    updateHospital(message) {
        const hospital = message.payload;
        this.hospitals[hospital.id] = hospital;
    }

    updateCall(message) {
        const call = message.payload;
        this.call[call.id] = call;
    }

    updateAmbulanceCallStatus(message) {

        const status = message.payload;

        // get ambulance and call ids
        const topic = message.topic.split('/');
        // const ambulance_id = topic[1];
        const call_id = topic[3];

        if ( !this.calls.hasOwnProperty(call_id) && status !== 'C' ) {

            // retrieve call from api
            this.httpClient.get('call/' + call_id + '/')
                .then( (call) => {

                    // update call
                    this.calls[call.id] = call;

                    // subscribe
                    this.subscribe('call/' + call.id + '/data', this.updateCall);

            });

        }

    }

    retrieveAmbulances() {

        // initialized if needed
        if (typeof this.ambulances === 'undefined')
            this.ambulances = {};

        // retrieve ambulances
        this.httpClient.get('ambulance/')
            .then( (response) => {

                // console.log(response.data);

                // Update ambulances
                response.data.forEach( (ambulance) => {

                    // update ambulance
                    this.ambulances[ambulance.id] = ambulance;

                    // subscribe
                    // TODO: check if already subscribed
                    this.subscribe('ambulance/' + ambulance.id + '/data',
                        this.updateAmbulance);
                    this.subscribe('ambulance/' + ambulance.id + '/call/+/status',
                        this.updateAmbulanceCallStatus);

                });

            })
            .catch( (error) => {
                console.log('retrieveAmbulance: ' + error);
            });

    }

    retrieveHospitals() {

        // initialized if needed
        if (typeof this.hospitals === 'undefined')
            this.hospitals = {};

        // retrieve ambulances
        this.httpClient.get('hospital/')
            .then( (response) => {

                // Update hospitals
                response.data.forEach( (hospital) => {

                    // update hospital
                    this.hospitals[hospital.id] = hospital;

                    // subscribe
                    // TODO: check if already subscribed
                    this.subscribe('hospital/' + hospital.id + '/data', this.updateHospital);

                });

            })
            .catch( (error) => {
                console.log('retrieveHospital: ' + error);
            });

    }

    retrieveCalls() {

        // initialized if needed
        if (typeof this.calls === 'undefined')
            this.calls = {};

        // retrieve ambulances
        this.httpClient.get('call/')
            .then( (response) => {

                // Update calls
                response.data.forEach( (call) => {

                    // update call
                    this.calls[call.id] = call;

                    // subscribe
                    // TODO: check if already subscribed
                    this.subscribe('call/' + call.id + '/data', this.updateCall);

                });

            })
            .catch( (error) => {
                console.log('retrievecall: ' + error);
            });

    }

    retrieveBases() {

        // initialized if needed
        if (typeof this.bases === 'undefined')
            this.bases = {};

        // retrieve ambulances
        this.httpClient.get('location/Base/')
            .then( (response) => {

                // Update bases
                response.data.forEach( (base) => {

                    // update base
                    this.bases[base.id] = base;

                });

            })
            .catch( (error) => {
                console.log('retrieveBase: ' + error);
            });

    }

}
<commit_msg>Javascript Client testing.<commit_after>import { TopicObserver } from "./topic-observer";

export class AppClient extends TopicObserver {

    /**
     *
     * @param {MqttClient} mqttClient
     * @param httpClient
     */
    constructor(mqttClient, httpClient) {

        // call super
        super();

        // mqtt client
        this.mqttClient = mqttClient;
        this.event_observer = null;

        // register observer
        this.event_observer = (event) => this.eventHandler(event);
        this.mqttClient.observe(this.event_observer);

        // http client
        this.httpClient = httpClient;

        // initialize
        this.ambulances = undefined;
        this.hospitals = undefined;
        this.bases = undefined;
        this.calls = undefined;

    }

    disconnect() {

        // return if not connected
        if (!this.mqttClient.isConnected)
            return;

        // remove observer
        this.mqttClient.remove(this.event_observer);
        this.event_observer = null;

        // connect to client
        this.mqttClient.disconnect();

    }

    /**
     *
     * @param {MqttEvent} event
     */
    eventHandler(event) {

        console.log(event);

        if (event.event === 'messageReceived') {

            const topic = event.object.destinationName;
            let payload;

            try {
                payload = JSON.parse(event.object.payloadString);
            } catch(e) {
                console.log(e);
                payload = event.object.payloadString;
            }

            console.log(topic);
            console.log(payload);

            // broadcast
            this.broadcast(topic, {topic: topic, payload: payload});

        }

    }

    subscribe(filter, fn, options) {
        options = options || {};
        this.mqttClient.subscribe(filter, options);
        this.observe(filter, fn)
    }

    unsubscribe(filter, fn, options) {
        options = options || {};
        this.mqttClient.unsubscribe(filter, options);
        this.remove(filter, fn)
    }

    publish(topic, payload, qos, retained) {
        this.mqttClient.publish(topic, payload, qos, retained);
    }

    updateAmbulance(message) {
        const ambulance = message.payload;
        this.ambulances[ambulance.id] = ambulance;
    }

    updateHospital(message) {
        const hospital = message.payload;
        this.hospitals[hospital.id] = hospital;
    }

    updateCall(message) {
        const call = message.payload;
        this.call[call.id] = call;
    }

    updateAmbulanceCallStatus(message) {

        const status = message.payload;

        // get ambulance and call ids
        const topic = message.topic.split('/');
        // const ambulance_id = topic[1];
        const call_id = topic[3];

        if ( !this.calls.hasOwnProperty(call_id) && status !== 'C' ) {

            // retrieve call from api
            this.httpClient.get('call/' + call_id + '/')
                .then( (call) => {

                    // update call
                    this.calls[call.id] = call;

                    // subscribe
                    this.subscribe('call/' + call.id + '/data', this.updateCall);

            });

        }

    }

    retrieveAmbulances() {

        // initialized if needed
        if (typeof this.ambulances === 'undefined')
            this.ambulances = {};

        // retrieve ambulances
        this.httpClient.get('ambulance/')
            .then( (response) => {

                // console.log(response.data);

                // Update ambulances
                response.data.forEach( (ambulance) => {

                    // update ambulance
                    this.ambulances[ambulance.id] = ambulance;

                    // subscribe
                    // TODO: check if already subscribed
                    this.subscribe('ambulance/' + ambulance.id + '/data',
                        this.updateAmbulance);
                    this.subscribe('ambulance/' + ambulance.id + '/call/+/status',
                        this.updateAmbulanceCallStatus);

                });

            })
            .catch( (error) => {
                console.log('retrieveAmbulance: ' + error);
            });

    }

    retrieveHospitals() {

        // initialized if needed
        if (typeof this.hospitals === 'undefined')
            this.hospitals = {};

        // retrieve ambulances
        this.httpClient.get('hospital/')
            .then( (response) => {

                // Update hospitals
                response.data.forEach( (hospital) => {

                    // update hospital
                    this.hospitals[hospital.id] = hospital;

                    // subscribe
                    // TODO: check if already subscribed
                    this.subscribe('hospital/' + hospital.id + '/data', this.updateHospital);

                });

            })
            .catch( (error) => {
                console.log('retrieveHospital: ' + error);
            });

    }

    retrieveCalls() {

        // initialized if needed
        if (typeof this.calls === 'undefined')
            this.calls = {};

        // retrieve ambulances
        this.httpClient.get('call/')
            .then( (response) => {

                // Update calls
                response.data.forEach( (call) => {

                    // update call
                    this.calls[call.id] = call;

                    // subscribe
                    // TODO: check if already subscribed
                    this.subscribe('call/' + call.id + '/data', this.updateCall);

                });

            })
            .catch( (error) => {
                console.log('retrievecall: ' + error);
            });

    }

    retrieveBases() {

        // initialized if needed
        if (typeof this.bases === 'undefined')
            this.bases = {};

        // retrieve ambulances
        this.httpClient.get('location/Base/')
            .then( (response) => {

                // Update bases
                response.data.forEach( (base) => {

                    // update base
                    this.bases[base.id] = base;

                });

            })
            .catch( (error) => {
                console.log('retrieveBase: ' + error);
            });

    }

}
<|endoftext|>


<commit_before>// ==UserScript==
// @author      rslifka
// @connect     docs.google.com
// @connect     rslifka.github.io
// @copyright   2018, Robert Slifka (https://github.com/rslifka/fate_of_all_fools)
// @description Enhancements to the Destiny Item Manager
// @grant       GM_addStyle
// @grant       GM_getResourceText
// @grant       GM_getValue
// @grant       GM_log
// @grant       GM_setValue
// @grant       GM_xmlhttpRequest
// @homepageURL https://github.com/rslifka/fate_of_all_fools
// @license     MIT; https://raw.githubusercontent.com/rslifka/fate_of_all_fools/master/LICENSE.txt
// @match       https://*.destinyitemmanager.com/*
// @name        FateOfAllFools - DIM Customization
// @require     https://rslifka.github.io/fate_of_all_fools/fateOfAllFools.js
// @resource    fateOfAllFoolsCSS https://rslifka.github.io/fate_of_all_fools/fateOfAllFools.css
// @run-at      document-start
// @supportURL  https://github.com/rslifka/fate_of_all_fools/issues
// @updateURL   https://openuserjs.org/meta/rslifka/FateOfAllFools_-_DIM_Customization.meta.js
// @version     600
// ==/UserScript==
<commit_msg>AUTO-CREATED Release Artifact v601 c/o Travis<commit_after>// ==UserScript==
// @author      rslifka
// @connect     docs.google.com
// @connect     rslifka.github.io
// @copyright   2018, Robert Slifka (https://github.com/rslifka/fate_of_all_fools)
// @description Enhancements to the Destiny Item Manager
// @grant       GM_addStyle
// @grant       GM_getResourceText
// @grant       GM_getValue
// @grant       GM_log
// @grant       GM_setValue
// @grant       GM_xmlhttpRequest
// @homepageURL https://github.com/rslifka/fate_of_all_fools
// @license     MIT; https://raw.githubusercontent.com/rslifka/fate_of_all_fools/master/LICENSE.txt
// @match       https://*.destinyitemmanager.com/*
// @name        FateOfAllFools - DIM Customization
// @require     https://rslifka.github.io/fate_of_all_fools/fateOfAllFools.js
// @resource    fateOfAllFoolsCSS https://rslifka.github.io/fate_of_all_fools/fateOfAllFools.css
// @run-at      document-start
// @supportURL  https://github.com/rslifka/fate_of_all_fools/issues
// @updateURL   https://openuserjs.org/meta/rslifka/FateOfAllFools_-_DIM_Customization.meta.js
// @version     601
// ==/UserScript==
<|endoftext|>