<commit_before>var DEFAULT_PORT = 1337;
var DEFAULT_URI = 'mongodb://127.0.0.1:27017';

var express = require('express')
  , path = require('path')
  , app = express()
  , http = require('http').Server(app)
  , mongoDB = require('./lib/mongo')
  , io = require('socket.io')(http)
  , ObjectId = require('mongoose').Types.ObjectId
  , mongoURI = null;

function MongoConsole(port, uri) {
  mongoURI = uri ? uri : DEFAULT_URI;
  port = port || DEFAULT_PORT;

  // Start the web server
  http.listen(port, function(){
    console.log("MongoConsole server listening on port " + port);
  });
}

app.configure(function() {
  app.use(express.static(path.join(__dirname, 'public')));
  app.use(express.bodyParser());
  app.use(app.router);
});

app.get('/', function(req, res) {
  res.render('index.html');
});

app.get('/settings', function(req, res) {
  res.sendfile(__dirname + '/public/settings.html');
});

io.on('connection', function(socket) {

  // Start a new connection to mongoDB instance per mongoconsole connection
  socket.mongo = new mongoDB(mongoURI);

  socket.on('disconnect', function() {
  });
  socket.on('add', function(msg) {
    addEntry(msg, socket);
  });
  socket.on('edit', function(msg) {
    editEntry(msg, socket);
  });
  socket.on('delete', function(msg) {
    deleteEntry(msg, socket);
  });
  socket.on('entries', function(msg) {
    getEntries(msg, socket);
  });
  socket.on('collections', function(msg) {
    getCollections(socket);
  });
  socket.on('databases', function(msg) {
    getDatabases(msg, socket);
  });
  socket.on('switch_db', function(msg) {
    switchDB(msg, socket);
  });
  socket.on('stats', function(msg) {
    getStats(socket);
  });
  socket.on('new_collection', function(msg) {
    addCollection(msg, socket);
  });
  socket.on('drop_collection', function(msg) {
    deleteCollection(msg, socket);
  })
  socket.on('settings', function(msg) {
    getSettings(socket);
  });
  socket.on('error', function(err) {
    console.log("ERR: ", err);
    socket.emit('err', {err:"Connection Error"});
  });
});

/* WebSocket Request Helper Functions */
function addEntry(msg, socket) {
  socket.mongo.add(msg.entry, msg.collection, function(err, result) {
    if(err) {
      console.log('MONGO ADD ERR: ', err);
      socket.emit('err', {err:"Add Error: " + err});
    }
    else {
      socket.emit('success', {ok:'Successfully added doc(s) to ' + msg.collection + ' collection.'});
      getEntries({collection:msg.collection, action:'display'}, socket);
    }
  });
}

function editEntry(msg, socket) {
  socket.mongo.update({_id: new ObjectId(msg.id)}, msg.json, msg.collection, function(err, result){
    if(err) {
      console.log('MONGO UPDATE ERR: ', err);
      socket.emit('err', {err:"Update Error: " + err});
    }
  });
}

function deleteEntry(msg, socket) {
  socket.mongo.remove({_id: new ObjectId(msg.id)}, msg.collection, function(err, result) {
    if(err) {
      console.log('MONGO DEL ERR: ', err);
      socket.emit('err', {err:"Delete Error: " + err});
    }
    if(result === 0) {
      socket.emit('err', {err:"Error removing doc " + msg.id + " from " + msg.collection + " collection"});
    }
  });
}

function getEntries(msg, socket) {
  socket.mongo.findAll(msg.collection, function(err, results) {
    if(!err) {
      socket.emit('entries', {action:msg.action, results:results});
    }
    else {
      console.log('MONGO FIND ERR: ', err);
      socket.emit('err', {err:"Fetch Error: " + err});
    }
  });
}

function getCollections(socket) {
  socket.mongo.getCollectionNames(function(err, results) {
    if(!err) {
      var collections = [];
      for(var i = 0; i < results.length; i++) {
        collections[i] = results[i].name.split(/\.(.+)?/)[1];
      }
      socket.emit('collections', collections);
    }
    else {
      console.log('MONGO GET COLLECTIONS ERR: ', err);
    }
  });
}

function getDatabases(msg, socket) {
  socket.mongo.getDatabaseNames(function(err, results) {
    if(!err) {
      socket.emit('databases', results);
    }
    else {
      console.log('MONGO GET DBs ERR: ', err);
    }
  });
}

function switchDB(msg, socket) {
  socket.mongo.switchDB(msg.dbName, function(err) {
    if(err){
      console.log('ERR switching to DB ' + msg.dbName + ': ' + err);
    }
    else {
      getCollections(socket);
    }
  });
}

function getStats(socket) {
  socket.mongo.stats(function(err, result){
    if(err) {
      console.log('MONGO GET STATS ERR: ', err);
    }
    socket.emit('stats', result);
  });
}

function addCollection(msg, socket) {
  socket.mongo.createCollection(msg.name, function(err, result) {
    if(err) {
      socket.emit('err', {err:"Error creating collection: " + err});
    }
    else {
      socket.emit('success', {ok:"Created " + msg.name + " collection"});
      getCollections(socket);
      broadcastCollectionUpdate(socket);
    }
  });
}

function deleteCollection(msg, socket) {
  socket.mongo.deleteCollection(msg.name, function(err, result) {
    if(err) {
      socket.emit('err', {err:"Error removing collection: " + err});
    }
    else {
      socket.emit('success', {ok:"Dropped " + msg.name + " collection"});
      getCollections(socket);
      broadcastCollectionUpdate(socket);
    }
  });
}

function getSettings(socket) {
  //TODO
}

function broadcastCollectionUpdate(socket) {
  socket.mongo.getCollectionNames(function(err, results) {
    if(!err) {
      var collections = [];
      for(var i = 0; i < results.length; i++) {
        collections[i] = results[i].name.split(/\.(.+)?/)[1];
      }
      io.emit('collections', collections);
    }
    else {
      console.log('MONGO GET COLLECTIONS ERR: ', err);
    }
  });
}

module.exports = MongoConsole;<commit_msg>added function for bulk upload<commit_after>var DEFAULT_PORT = 1337;
var DEFAULT_URI = 'mongodb://127.0.0.1:27017';

var express = require('express')
  , path = require('path')
  , app = express()
  , http = require('http').Server(app)
  , mongoDB = require('./lib/mongo')
  , io = require('socket.io')(http)
  , ObjectId = require('mongoose').Types.ObjectId
  , mongoURI = null;

function MongoConsole(port, uri) {
  mongoURI = uri ? uri : DEFAULT_URI;
  port = port || DEFAULT_PORT;

  // Start the web server
  http.listen(port, function(){
    console.log("MongoConsole server listening on port " + port);
  });
}

app.configure(function() {
  app.use(express.static(path.join(__dirname, 'public')));
  app.use(express.bodyParser());
  app.use(app.router);
});

app.get('/', function(req, res) {
  res.render('index.html');
});

app.get('/settings', function(req, res) {
  res.sendfile(__dirname + '/public/settings.html');
});

io.on('connection', function(socket) {

  // Start a new connection to mongoDB instance per mongoconsole connection
  socket.mongo = new mongoDB(mongoURI);

  socket.on('disconnect', function() {
  });
  socket.on('add', function(msg) {
    if(msg.multi === true)
      addBulk(msg, socket);
    else
      addEntry(msg, socket);
  });
  socket.on('edit', function(msg) {
    editEntry(msg, socket);
  });
  socket.on('delete', function(msg) {
    deleteEntry(msg, socket);
  });
  socket.on('entries', function(msg) {
    getEntries(msg, socket);
  });
  socket.on('collections', function(msg) {
    getCollections(socket);
  });
  socket.on('databases', function(msg) {
    getDatabases(msg, socket);
  });
  socket.on('switch_db', function(msg) {
    switchDB(msg, socket);
  });
  socket.on('stats', function(msg) {
    getStats(socket);
  });
  socket.on('new_collection', function(msg) {
    addCollection(msg, socket);
  });
  socket.on('drop_collection', function(msg) {
    deleteCollection(msg, socket);
  })
  socket.on('settings', function(msg) {
    getSettings(socket);
  });
  socket.on('error', function(err) {
    console.log("ERR: ", err);
    socket.emit('err', {err:"Connection Error"});
  });
});

/* WebSocket Request Helper Functions */
function addEntry(msg, socket) {
  socket.mongo.add(msg.entry, msg.collection, function(err, result) {
    if(err) {
      console.log('MONGO ADD ERR: ', err);
      socket.emit('err', {err:"Add Error: " + err});
    }
    else {
      socket.emit('success', {ok:'Successfully added doc to ' + msg.collection + ' collection.'});
      getEntries({collection:msg.collection, action:'display'}, socket);
    }
  });
}

function addBulk(msg, socket) {
  var entries = msg.entries;
  var numAdded = 0;
  var numProcessed = 0;
  var numEntries = entries.length;

  // Add each entry
  entries.forEach(function(doc) {
    socket.mongo.add(doc, msg.collection, function(err, result) {
      numProcessed++;
      if(err) {
        console.log('MONGO ADD ERR: ', err);
      }
      else {
        numAdded++;
      }
      // if this is the last entry, send back a success
      if(numProcessed == numEntries) {
        socket.emit('success', {ok:'Added ' + numAdded + ' of ' + numProcessed + ' docs to ' + msg.collection + ' collection.'});
        getEntries({collection:msg.collection, action:'display'}, socket);
      }
    });
  });
}

function editEntry(msg, socket) {
  socket.mongo.update({_id: new ObjectId(msg.id)}, msg.json, msg.collection, function(err, result){
    if(err) {
      console.log('MONGO UPDATE ERR: ', err);
      socket.emit('err', {err:"Update Error: " + err});
    }
  });
}

function deleteEntry(msg, socket) {
  socket.mongo.remove({_id: new ObjectId(msg.id)}, msg.collection, function(err, result) {
    if(err) {
      console.log('MONGO DEL ERR: ', err);
      socket.emit('err', {err:"Delete Error: " + err});
    }
    if(result === 0) {
      socket.emit('err', {err:"Error removing doc " + msg.id + " from " + msg.collection + " collection"});
    }
  });
}

function getEntries(msg, socket) {
  socket.mongo.findAll(msg.collection, function(err, results) {
    if(!err) {
      socket.emit('entries', {action:msg.action, results:results});
    }
    else {
      console.log('MONGO FIND ERR: ', err);
      socket.emit('err', {err:"Fetch Error: " + err});
    }
  });
}

function getCollections(socket) {
  socket.mongo.getCollectionNames(function(err, results) {
    if(!err) {
      var collections = [];
      for(var i = 0; i < results.length; i++) {
        collections[i] = results[i].name.split(/\.(.+)?/)[1];
      }
      socket.emit('collections', collections);
    }
    else {
      console.log('MONGO GET COLLECTIONS ERR: ', err);
    }
  });
}

function getDatabases(msg, socket) {
  socket.mongo.getDatabaseNames(function(err, results) {
    if(!err) {
      socket.emit('databases', results);
    }
    else {
      console.log('MONGO GET DBs ERR: ', err);
    }
  });
}

function switchDB(msg, socket) {
  socket.mongo.switchDB(msg.dbName, function(err) {
    if(err){
      console.log('ERR switching to DB ' + msg.dbName + ': ' + err);
    }
    else {
      getCollections(socket);
    }
  });
}

function getStats(socket) {
  socket.mongo.stats(function(err, result){
    if(err) {
      console.log('MONGO GET STATS ERR: ', err);
    }
    socket.emit('stats', result);
  });
}

function addCollection(msg, socket) {
  socket.mongo.createCollection(msg.name, function(err, result) {
    if(err) {
      socket.emit('err', {err:"Error creating collection: " + err});
    }
    else {
      socket.emit('success', {ok:"Created " + msg.name + " collection"});
      getCollections(socket);
      broadcastCollectionUpdate(socket);
    }
  });
}

function deleteCollection(msg, socket) {
  socket.mongo.deleteCollection(msg.name, function(err, result) {
    if(err) {
      socket.emit('err', {err:"Error removing collection: " + err});
    }
    else {
      socket.emit('success', {ok:"Dropped " + msg.name + " collection"});
      getCollections(socket);
      broadcastCollectionUpdate(socket);
    }
  });
}

function getSettings(socket) {
  //TODO
}

function broadcastCollectionUpdate(socket) {
  socket.mongo.getCollectionNames(function(err, results) {
    if(!err) {
      var collections = [];
      for(var i = 0; i < results.length; i++) {
        collections[i] = results[i].name.split(/\.(.+)?/)[1];
      }
      io.emit('collections', collections);
    }
    else {
      console.log('MONGO GET COLLECTIONS ERR: ', err);
    }
  });
}

module.exports = MongoConsole;<|endoftext|>


<commit_before>/*
 *  eXide - web-based XQuery IDE
 *
 *  Copyright (C) 2011 Wolfgang Meier
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
define("ace/mode/xquery_highlight_rules", function(require, exports, module) {

var oop = require("../lib/oop");
var lang = require("../lib/lang");
var TextHighlightRules = require("ace/mode/text_highlight_rules").TextHighlightRules;

var XQueryHighlightRules = function() {

  var keywords = lang.arrayToMap(
    ("return|for|let|where|order|by|declare|function|variable|xquery|version|option|namespace|import|module|" +
     "switch|default|try|catch|group|tumbling|sliding|window|start|end|at|only|" +
     "if|then|else|as|and|or|typeswitch|case|ascending|descending|empty|in|count|updating|insert|delete|replace|value|node|attribute|into|of|with").split("|")
    );

    // regexp must not have capturing parentheses
    // regexps are ordered -> the first match is used

    this.$rules = {
        start : [ {
            token : "text",
            regex : "<\\!\\[CDATA\\[",
            next : "cdata"
        }, {
            token : "xml_pe",
            regex : "<\\?.*?\\?>"
        }, {
            token : "comment",
            regex : "<\\!--",
            next : "comment"
    }, {
      token : "comment",
      regex : "\\(:",
      next : "comment"
        }, {
            token : "text", // opening tag
            regex : "<\\/?",
            next : "tag"
        }, {
            token : "constant", // number
            regex : "[+-]?\\d+(?:(?:\\.\\d*)?(?:[eE][+-]?\\d+)?)?\\b"
    }, {
            token : "variable", // variable
            regex : "\\$[a-zA-Z_][a-zA-Z0-9_\\-:]*\\b"
    }, {
      token: "string",
      regex : '".*?"'
    }, {
      token: "string",
      regex : "'.*?'"
        }, {
            token : "text",
            regex : "\\s+"
        }, {
            token: "support.function",
            regex: "\\w[\\w+_\\-:]+(?=\\()"
        }, {
            token: "keyword.operator",
            regex: "\\*|=|<|>|\\-|\\+|and|or|eq|ne|lt|gt"
        }, {
            token: "lparen",
            regex: "[[({]"
        }, {
            token: "rparen",
            regex: "[\\])}]"
        }, {
      token : function(value) {
            if (keywords[value])
                return "keyword";
            else
                return "identifier";
      },
      regex : "[a-zA-Z_$][a-zA-Z0-9_$]*\\b"
    } ],

        tag : [ {
            token : "text",
            regex : ">",
            next : "start"
        }, {
            token : "keyword",
            regex : "[-_a-zA-Z0-9:]+"
        }, {
            token : "text",
            regex : "\\s+"
        }, {
            token : "string",
            regex : '".*?"'
        }, {
            token : "string",
            regex : "'.*?'"
        } ],

        cdata : [ {
            token : "text",
            regex : "\\]\\]>",
            next : "start"
        }, {
            token : "text",
            regex : "\\s+"
        }, {
            token : "text",
            regex : "(?:[^\\]]|\\](?!\\]>))+"
        } ],

        comment : [ {
            token : "comment",
            regex : ".*?-->",
            next : "start"
        }, {
      token: "comment",
      regex : ".*:\\)",
      next : "start"
        }, {
            token : "comment",
            regex : ".+"
    } ]
    };
};

oop.inherits(XQueryHighlightRules, TextHighlightRules);

exports.XQueryHighlightRules = XQueryHighlightRules;
});
<commit_msg>Add new keywords.<commit_after>/*
 *  eXide - web-based XQuery IDE
 *
 *  Copyright (C) 2011 Wolfgang Meier
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
define("ace/mode/xquery_highlight_rules", function(require, exports, module) {

var oop = require("../lib/oop");
var lang = require("../lib/lang");
var TextHighlightRules = require("ace/mode/text_highlight_rules").TextHighlightRules;

var XQueryHighlightRules = function() {

  var keywords = lang.arrayToMap(
    ("return|for|let|where|order|by|declare|function|variable|xquery|version|option|namespace|import|module|" +
     "switch|default|try|catch|group|tumbling|sliding|window|start|end|at|only|" +
     "if|then|else|as|and|or|typeswitch|case|ascending|descending|empty|in|count|updating|insert|delete|replace|value|node|attribute|text|element|into|of|with").split("|")
    );

    // regexp must not have capturing parentheses
    // regexps are ordered -> the first match is used

    this.$rules = {
        start : [ {
            token : "text",
            regex : "<\\!\\[CDATA\\[",
            next : "cdata"
        }, {
            token : "xml_pe",
            regex : "<\\?.*?\\?>"
        }, {
            token : "comment",
            regex : "<\\!--",
            next : "comment"
    }, {
      token : "comment",
      regex : "\\(:",
      next : "comment"
        }, {
            token : "text", // opening tag
            regex : "<\\/?",
            next : "tag"
        }, {
            token : "constant", // number
            regex : "[+-]?\\d+(?:(?:\\.\\d*)?(?:[eE][+-]?\\d+)?)?\\b"
    }, {
            token : "variable", // variable
            regex : "\\$[a-zA-Z_][a-zA-Z0-9_\\-:]*\\b"
    }, {
      token: "string",
      regex : '".*?"'
    }, {
      token: "string",
      regex : "'.*?'"
        }, {
            token : "text",
            regex : "\\s+"
        }, {
            token: "support.function",
            regex: "\\w[\\w+_\\-:]+(?=\\()"
        }, {
            token: "keyword.operator",
            regex: "\\*|=|<|>|\\-|\\+|and|or|eq|ne|lt|gt"
        }, {
            token: "lparen",
            regex: "[[({]"
        }, {
            token: "rparen",
            regex: "[\\])}]"
        }, {
      token : function(value) {
            if (keywords[value])
                return "keyword";
            else
                return "identifier";
      },
      regex : "[a-zA-Z_$][a-zA-Z0-9_$]*\\b"
    } ],

        tag : [ {
            token : "text",
            regex : ">",
            next : "start"
        }, {
            token : "keyword",
            regex : "[-_a-zA-Z0-9:]+"
        }, {
            token : "text",
            regex : "\\s+"
        }, {
            token : "string",
            regex : '".*?"'
        }, {
            token : "string",
            regex : "'.*?'"
        } ],

        cdata : [ {
            token : "text",
            regex : "\\]\\]>",
            next : "start"
        }, {
            token : "text",
            regex : "\\s+"
        }, {
            token : "text",
            regex : "(?:[^\\]]|\\](?!\\]>))+"
        } ],

        comment : [ {
            token : "comment",
            regex : ".*?-->",
            next : "start"
        }, {
      token: "comment",
      regex : ".*:\\)",
      next : "start"
        }, {
            token : "comment",
            regex : ".+"
    } ]
    };
};

oop.inherits(XQueryHighlightRules, TextHighlightRules);

exports.XQueryHighlightRules = XQueryHighlightRules;
});
<|endoftext|>


<commit_before>// ==UserScript==
// @name         Vola Admin/IP Tools
// @version      47.1
// @description  Does a bunch of stuff for mods.
// @namespace    https://volafile.org
// @icon         https://volafile.org/favicon.ico
// @author       topkuk productions
// @match        https://volafile.org/r/*
// @require      https://greasemonkey.github.io/gm4-polyfill/gm4-polyfill.js
// @require      https://cdn.rawgit.com/RealDolos/volascripts/51b76c05be26adca7b4a4897115f67f10d9df668/dry.js
// @run-at       document-start
// @grant        none
// ==/UserScript==

/* global dry, GM */

dry.once("dom", () => {
  "use strict";

  const IS_BAN = /^\S+ (?:banned|muted|hellbanned|unbanned|un-muted|timed-in)\b/;

  function adjustBanPart(p, users, ips) {
    const {value} = p;
    let slash = value.indexOf(" / ");
    if (slash < 0) {
      slash = value.length;
    }
    const pre = value.slice(0, slash).replace("did nothing to", "did-nothing-to");
    const post = value.slice(slash);
    const pieces = pre.split(/ /g);
    let idx = 1;
    while (idx < pieces.length) {
      if (!pieces[idx++].endsWith(",")) {
        break;
      }
    }
    const pusers = pieces.slice(idx).map(u => {
      u = u.replace(/(?:[()]|,$)/g, "").trim();
      if (/^\d+\.\d+\.\d+\.\d+$/.test(u)) {
        ips.push(u);
        return null;
      }
      if (u) {
        users.push(u);
      }
      return u;
    }).filter(e => e).sort();

    if (!pusers.length) {
      pusers.push("some cuck");
    }

    p.value = `${pieces.slice(0, idx).join(" ").replace("did-nothing-to", "did nothing to")} ${pusers.join(", ")}${post}`;
  }

  function $e(tag, attrs, text) {
    let rv = document.createElement(tag);
    attrs = attrs || {};
    for (let a in attrs) {
        rv.setAttribute(a, attrs[a]);
    }
    if (text) {
        rv.textContent = text;
    }
    return rv;
  }

  const $ = (sel, el) => (el || document).querySelector(sel);

  console.log(
    "running", GM.info.script.name, GM.info.script.version, dry.version);

  const style = $e("style", {id: "iptools-style"}, `
body[noipspls] a.username > span:not([class]),
body[noipspls] a.username > span[class=""],
body[noipspls] .tag_key_ip {
  display: none;
}
.username.ban {
  display: inline-block;
}
@-moz-document url-prefix() {
.username.ban {
  display: inline;
}
}
.username.ban {
  vertical-align: top;
  color: white !important;
  font-size: 50%;
  padding: 0;
  opacity: 0.4;
}
.username.ban:hover {
  opacity: 1;
}
.username.ban icon-hammer {
  padding: 0;
}
.icon-untick {
  margin: 0 !important;
}
.untick-button {
  position: relative;
  z-index: 150;
  font-size: 18px;
  padding-bottom: 1px;
  margin-right: 1ex;
}
`);
  document.body.appendChild(style);
  let state = localStorage.getItem("noipspls") !== "false";
  if (state !== false) {
    state = true;
  }
  const update = () => {
    if (state) {
      document.body.setAttribute("noipspls", "true");
    }
    else {
      document.body.removeAttribute("noipspls");
    }
    localStorage.setItem("noipspls", state.toString());
    if (dry.exts) {
      dry.exts.chat.scrollState.bottom();
    }
  };
  const toggle = () => {
    state = !state;
    update();
  };
  update();

  const btn = document.createElement("a");
  btn.textContent = "IP";
  btn.style.padding = "0 1ex";
  const uc = document.querySelector("#user_count_icon");
  uc.parentElement.insertBefore(btn, uc.nextSibling);
  btn.addEventListener("click", toggle);

  const roomqueue = new Map();
  let resolving = false;
  const resolve_rooms = async () => {
    if (resolving) {
      return;
    }
    resolving = true;
    try {
      while (roomqueue.size) {
        const [room, elems] = roomqueue[Symbol.iterator]().next().value;
        try {
          let res = await dry.unsafeWindow.Volafile.makeAPIRequest("getRoomConfig", {
            room
          });
          for (const el of elems) {
            el.textContent = res.name;
          }
        }
        catch (ex) {
          console.error(ex);
        }
        roomqueue.delete(room);
      }
    }
    finally {
      resolving = false;
    }
  };

  dry.replaceEarly("chat", "showMessage",
    function(orig, nick, message, options, data, ...args) {
      try {
        if (nick === "Log" && options.staff && !options.profile && !(data && data.ip)) {
          const users = [];
          const ips = [];
          if (message[0].type === "url" && message[0].href === "/reports") {
            if (message[1].value.startsWith(" / BLACKLIST ")) {
              adjustBanPart(message[4], users, ips);
            }
            else {
              const [, p] = message;
              const m = p.value.match(/ \((\d+\.\d+\.\d+\.\d+)\)/);
              if (m) {
                p.value = p.value.replace(m[0], "");
                ips.push(m[1]);
              }
            }
          }
          else {
            for (const p of message) {
              if (p.type !== "text") {
                continue;
              }
              if (!IS_BAN.test(p.value)) {
                continue;
              }

              adjustBanPart(p, users, ips);
            }
          }
          if (users.length) {
            options.profile = users.sort().join(" user:");
            options.unprofile = true;
          }
          if (ips.length) {
            if (!data) {
              data = new dry.unsafeWindow.Object();
            }
            data.ip = ips.join(" ip:");
          }
        }
      }
      catch (ex) {
        console.error(ex);
      }
      const msg = orig(...[nick, message, options, data].concat(args));
      try {
        if (options.unprofile && msg.nick_elem) {
          const newnick = document.createElement("a");
          if (msg.ip_elem) {
            msg.ip_elem.parentElement.removeChild(msg.ip_elem);
          }
          newnick.textContent = msg.nick_elem.textContent;
          if (msg.ip_elem) {
            newnick.appendChild(msg.ip_elem);
          }
          newnick.className = msg.nick_elem.className;
          msg.nick_elem.parentElement.replaceChild(newnick, msg.nick_elem);
          msg.nick_elem = newnick;
          msg.elem.classList.remove("profile");
        }
        if (msg && (msg.ip_elem || msg.options.profile)) {
          msg.ban_elem = document.createElement("span");
          const hammer = document.createElement("i");
          hammer.setAttribute("class", "chat_message_icon icon-hammer");
          msg.ban_elem.appendChild(hammer);
          msg.ban_elem.setAttribute("class", "username clickable ban");
          msg.ban_elem.addEventListener("click", msg.showBanWindow.bind(msg));
          msg.nick_elem.appendChild(msg.ban_elem);
        }
        if (msg && nick === "Log" && msg.elem) {
          for (const el of msg.elem.children) {
            if (!el.textContent.startsWith("#")) {
              continue;
            }
            let m = /https:\/\/volafile.org\/r\/(.+)$/.exec(el.href);
            if (m) {
              const l = roomqueue.get(m[1]);
              if (!l) {
                roomqueue.set(m[1], [el]);
              }
              else {
                l.push(el);
              }
            }
          }
        }
      }
      catch (ex) {
        console.error(ex);
      }
      finally {
        resolve_rooms().catch(console.error);
      }
      return msg;
    });

  new class extends dry.Commands {
    ip() {
      toggle();
      return true;
    }
  }();

  function nukeRoom() {
    dry.exts.ui.showQuestion({
      title: "Disable this room",
      text: "Are you sure you want to disable this room?",
      positive: "Disable",
      negative: "Abort"
    }, res => {
      if (!res) {
        return;
      }
      dry.exts.connection.call("editInfo", {
        name: "closed",
        motd: "",
        disabled: true
      });
    });
  }

  dry.replaceEarly("ui", "showContextMenu", function(orig, el, options) {
    try {
      if (options && options.dedupe === "admin_contextmenu" && dry.exts.admin.isAdmin) {
        options.buttons.push({
          icon: "icon-rules",
          text: "Nuke Room",
          admin: true,
          click: nukeRoom
        });
      }
      if (options && options.dedupe === "room_contextmenu" && dry.exts.admin.isAdmin) {
        const idx = options.buttons.findIndex(e => e.text === "Copy URL");
        if (idx >= 0) {
          options.buttons.splice(idx, 1);
        }
      }
    }
    catch (ex) {
      console.error("ex", ex);
    }
    return orig(el, options);
  });

  // fixup ban templates
  for (const b of Object.values(window._templates.bans)) {
    b.lock = b.locked = false;
     if (b.upload && b.hours <= 24) {
       b.upload = false;
     }
  }

  const doet = Symbol("doet");
  const cont = $("#upload_container");
  const button = $e("label", {
    "for": "untick-button",
    "id": "untick-button",
    "class": "button untick-button",
    "title": "Untick all!"
  });
  button.appendChild($e("span", {
    "class": "icon-minus"
  }));
  button.addEventListener("click", () => dry.exts.adminButtons.untickAll(doet));
  cont.insertBefore(button, cont.firstChild);

  dry.replaceEarly("adminButtons", "untickAll", function(orig, kek) {
    if (kek !== doet) {
      return;
    }
    return orig();
  });
});
<commit_msg>compat<commit_after>// ==UserScript==
// @name         Vola Admin/IP Tools
// @version      48
// @description  Does a bunch of stuff for mods.
// @namespace    https://volafile.org
// @icon         https://volafile.org/favicon.ico
// @author       topkuk productions
// @match        https://volafile.org/r/*
// @require      https://greasemonkey.github.io/gm4-polyfill/gm4-polyfill.js
// @require      https://cdn.rawgit.com/RealDolos/volascripts/51b76c05be26adca7b4a4897115f67f10d9df668/dry.js
// @run-at       document-start
// @grant        none
// ==/UserScript==

/* global dry, GM */

dry.once("dom", () => {
  "use strict";

  const IS_BAN = /^\S+ (?:banned|muted|hellbanned|unbanned|un-muted|timed-in)\b/;

  function adjustBanPart(p, users, ips) {
    const {value} = p;
    let slash = value.indexOf(" / ");
    if (slash < 0) {
      slash = value.length;
    }
    const pre = value.slice(0, slash).replace("did nothing to", "did-nothing-to");
    const post = value.slice(slash);
    const pieces = pre.split(/ /g);
    let idx = 1;
    while (idx < pieces.length) {
      if (!pieces[idx++].endsWith(",")) {
        break;
      }
    }
    const pusers = pieces.slice(idx).map(u => {
      u = u.replace(/(?:[()]|,$)/g, "").trim();
      if (/^\d+\.\d+\.\d+\.\d+$/.test(u)) {
        ips.push(u);
        return null;
      }
      if (u) {
        users.push(u);
      }
      return u;
    }).filter(e => e).sort();

    if (!pusers.length) {
      pusers.push("some cuck");
    }

    p.value = `${pieces.slice(0, idx).join(" ").replace("did-nothing-to", "did nothing to")} ${pusers.join(", ")}${post}`;
  }

  function $e(tag, attrs, text) {
    let rv = document.createElement(tag);
    attrs = attrs || {};
    for (let a in attrs) {
        rv.setAttribute(a, attrs[a]);
    }
    if (text) {
        rv.textContent = text;
    }
    return rv;
  }

  const $ = (sel, el) => (el || document).querySelector(sel);

  console.log(
    "running", GM.info.script.name, GM.info.script.version, dry.version);

  const style = $e("style", {id: "iptools-style"}, `
body[noipspls] a.username > span:not([class]),
body[noipspls] a.username > span[class=""],
body[noipspls] .tag_key_ip {
  display: none;
}
.username.ban {
  display: inline-block;
}
@-moz-document url-prefix() {
.username.ban {
  display: inline;
}
}
.username.ban {
  vertical-align: top;
  color: white !important;
  font-size: 50%;
  padding: 0;
  opacity: 0.4;
}
.username.ban:hover {
  opacity: 1;
}
.username.ban icon-hammer {
  padding: 0;
}
.icon-untick {
  margin: 0 !important;
}
.untick-button {
  position: relative;
  z-index: 150;
  font-size: 18px;
  padding-bottom: 1px;
  margin-right: 1ex;
}
`);
  document.body.appendChild(style);
  let state = localStorage.getItem("noipspls") !== "false";
  if (state !== false) {
    state = true;
  }
  const update = () => {
    if (state) {
      document.body.setAttribute("noipspls", "true");
    }
    else {
      document.body.removeAttribute("noipspls");
    }
    localStorage.setItem("noipspls", state.toString());
    if (dry.exts) {
      dry.exts.chat.scrollState.bottom();
    }
  };
  const toggle = () => {
    state = !state;
    update();
  };
  update();

  const btn = document.createElement("a");
  btn.textContent = "IP";
  btn.style.padding = "0 1ex";
  const uc = document.querySelector("#user_count_icon");
  uc.parentElement.insertBefore(btn, uc.nextSibling);
  btn.addEventListener("click", toggle);

  const roomqueue = new Map();
  let resolving = false;
  const resolve_rooms = async () => {
    if (resolving) {
      return;
    }
    resolving = true;
    try {
      while (roomqueue.size) {
        const [room, elems] = roomqueue[Symbol.iterator]().next().value;
        try {
          let res = await dry.unsafeWindow.Volafile.makeAPIRequest("getRoomConfig", {
            room
          });
          for (const el of elems) {
            el.textContent = res.name;
          }
        }
        catch (ex) {
          console.error(ex);
        }
        roomqueue.delete(room);
      }
    }
    finally {
      resolving = false;
    }
  };

  dry.replaceEarly("chat", "showMessage",
    function(orig, nick, message, options, data, ...args) {
      try {
        if (nick === "Log" && options.staff && !options.profile && !(data && data.ip)) {
          const users = [];
          const ips = [];
          if (message[0].type === "url" && message[0].href === "/reports") {
            if (message[1].value.startsWith(" / BLACKLIST ")) {
              adjustBanPart(message[4], users, ips);
            }
            else {
              const [, p] = message;
              const m = p.value.match(/ \((\d+\.\d+\.\d+\.\d+)\)/);
              if (m) {
                p.value = p.value.replace(m[0], "");
                ips.push(m[1]);
              }
            }
          }
          else {
            for (const p of message) {
              if (p.type !== "text") {
                continue;
              }
              if (!IS_BAN.test(p.value)) {
                continue;
              }

              adjustBanPart(p, users, ips);
            }
          }
          if (users.length) {
            options.profile = users.sort().join(" user:");
            options.unprofile = true;
          }
          if (ips.length) {
            if (!data) {
              data = new dry.unsafeWindow.Object();
            }
            data.ip = ips.join(" ip:");
          }
        }
      }
      catch (ex) {
        console.error(ex);
      }
      const msg = orig(...[nick, message, options, data].concat(args));
      try {
        if (options.unprofile && msg.nick_elem) {
          const newnick = document.createElement("a");
          if (msg.ip_elem) {
            msg.ip_elem.parentElement.removeChild(msg.ip_elem);
          }
          newnick.textContent = msg.nick_elem.textContent;
          if (msg.ip_elem) {
            newnick.appendChild(msg.ip_elem);
          }
          newnick.className = msg.nick_elem.className;
          msg.nick_elem.parentElement.replaceChild(newnick, msg.nick_elem);
          msg.nick_elem = newnick;
          msg.elem.classList.remove("profile");
        }
        if (msg && (msg.ip_elem || msg.options.profile)) {
          msg.ban_elem = document.createElement("span");
          const hammer = document.createElement("i");
          hammer.setAttribute("class", "chat_message_icon icon-hammer");
          msg.ban_elem.appendChild(hammer);
          msg.ban_elem.setAttribute("class", "username clickable ban");
          msg.ban_elem.addEventListener("click", msg.showBanWindow.bind(msg));
          msg.nick_elem.appendChild(msg.ban_elem);
        }
        if (msg && nick === "Log" && msg.elem) {
          for (const el of msg.elem.children) {
            if (!el.textContent.startsWith("#")) {
              continue;
            }
            let m = /https:\/\/volafile.org\/r\/(.+)$/.exec(el.href);
            if (m) {
              const l = roomqueue.get(m[1]);
              if (!l) {
                roomqueue.set(m[1], [el]);
              }
              else {
                l.push(el);
              }
            }
          }
        }
      }
      catch (ex) {
        console.error(ex);
      }
      finally {
        resolve_rooms().catch(console.error);
      }
      return msg;
    });

  new class extends dry.Commands {
    ip() {
      toggle();
      return true;
    }
  }();

  function nukeRoom() {
    dry.exts.ui.showQuestion({
      title: "Disable this room",
      text: "Are you sure you want to disable this room?",
      positive: "Disable",
      negative: "Abort"
    }, res => {
      if (!res) {
        return;
      }
      dry.unsafeWindow.Volafile.setRoomConfig({
        name: "closed",
        motd: "closed",
        disabled: true
      });
    });
  }

  dry.replaceEarly("ui", "showContextMenu", function(orig, el, options) {
    try {
      if (options && options.dedupe === "admin_contextmenu" && dry.exts.user.info.admin) {
        options.buttons.push({
          icon: "icon-rules",
          text: "Nuke Room",
          admin: true,
          click: nukeRoom
        });
      }
      if (options && options.dedupe === "room_contextmenu" && dry.exts.user.info.admin) {
        const idx = options.buttons.findIndex(e => e.text === "Copy URL");
        if (idx >= 0) {
          options.buttons.splice(idx, 1);
        }
      }
    }
    catch (ex) {
      console.error("ex", ex);
    }
    return orig(el, options);
  });

  // fixup ban templates
  for (const b of Object.values(window._templates.bans)) {
    b.lock = b.locked = false;
     if (b.upload && b.hours <= 24) {
       b.upload = false;
     }
  }

  const doet = Symbol("doet");
  const cont = $("#upload_container");
  const button = $e("label", {
    "for": "untick-button",
    "id": "untick-button",
    "class": "button untick-button",
    "title": "Untick all!"
  });
  button.appendChild($e("span", {
    "class": "icon-minus"
  }));
  button.addEventListener("click", () => dry.exts.adminButtons.untickAll(doet));
  cont.insertBefore(button, cont.firstChild);

  dry.replaceEarly("adminButtons", "untickAll", function(orig, kek) {
    if (kek !== doet) {
      return;
    }
    return orig();
  });
});
<|endoftext|>


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

module.exports = function(req, res) {
	var query = req.list.model.find();
	async.series({
		count: function(next) {
			query.count(next);
		},
		items: function(next) {
			query.find();
			query.limit(Number(req.query.limit) || 100);
			query.skip(Number(req.query.skip) || 0);
			query.exec(next);
		}
	}, function(err, results) {
		if (err) return res.apiError('database error', err);
		return res.json({
			results: results.items.map(function (item) {
				return req.list.getData(item);
			}),
			count: results.count
		});
	});
};
<commit_msg>Implementing select query parameter for api/:list/get endpoint<commit_after>var async = require('async');

module.exports = function(req, res) {
	var query = req.list.model.find();
	async.series({
		count: function(next) {
			query.count(next);
		},
		items: function(next) {
			query.find();
			query.limit(Number(req.query.limit) || 100);
			query.skip(Number(req.query.skip) || 0);
			query.exec(next);
		}
	}, function(err, results) {
		if (err) return res.apiError('database error', err);
		return res.json({
			results: results.items.map(function (item) {
				return req.list.getData(item, req.query.select);
			}),
			count: results.count
		});
	});
};
<|endoftext|>


<commit_before>var c = {log:function(){}};
if (typeof console != 'undefined' && typeof console.log != 'undefined')
	c = console;

var ui = {
	alert: function(msg) {
		var ul = $('#gb-errors ul');
		ul.html('');
		ul.append('
An error occured
');
		ul.append('

');
		$('#gb-errors ul li.msg').text(msg);
		$('#gb-errors').slideDown("fast");
	},

	hideAlert: function() {
		$('#gb-errors').slideUp("fast");
	}
};

var http = {
	postForm: function(kw) {
		kw.data = http.toFormParams(kw.data);
		return http.post(kw);
	},

	post: function(kw) {
		kw.type = "post";
		c.log(kw.type, kw.url, kw.data);
		return $.ajax(kw);
	},

	toFormParams: function(params) {
		if (typeof params == 'object')
			for (var k in params)
				http._flattenComplexFormParams(params, k, params[k]);
		return params;
	},

	_flattenComplexFormParams: function(params, k, v) {
		if (typeof v == 'object') {
			for (var x in v) {
				var k2 = k+'['+x+']';
				var v2 = v[x];
				if (!http._flattenComplexFormParams(params, k2, v2))
					params[k2] = v2;
			}
			delete(params[k]);
			return true;
		}
		return false;
	}
};
<commit_msg>"console" is prefered before "c" for logging in JS<commit_after>if(typeof console=='undefined')console={};
if(typeof console.log=='undefined')console.log=function(){};
var c = console;

var ui = {
	alert: function(msg) {
		var ul = $('#gb-errors ul');
		ul.html('');
		ul.append('
An error occured
');
		ul.append('

');
		$('#gb-errors ul li.msg').text(msg);
		$('#gb-errors').slideDown("fast");
	},

	hideAlert: function() {
		$('#gb-errors').slideUp("fast");
	}
};

var http = {
	postForm: function(kw) {
		kw.data = http.toFormParams(kw.data);
		return http.post(kw);
	},

	post: function(kw) {
		kw.type = "post";
		c.log(kw.type, kw.url, kw.data);
		return $.ajax(kw);
	},

	toFormParams: function(params) {
		if (typeof params == 'object')
			for (var k in params)
				http._flattenComplexFormParams(params, k, params[k]);
		return params;
	},

	_flattenComplexFormParams: function(params, k, v) {
		if (typeof v == 'object') {
			for (var x in v) {
				var k2 = k+'['+x+']';
				var v2 = v[x];
				if (!http._flattenComplexFormParams(params, k2, v2))
					params[k2] = v2;
			}
			delete(params[k]);
			return true;
		}
		return false;
	}
};
<|endoftext|>


<commit_before>var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
var request = require("request");
var redis = require("redis");
var scale = require("./scale.js");

//Setup Redis
client = redis.createClient();
client.on("error", function (err) {
    console.log("Error " + err);
});

//var connectedServers = {}
var serverQueue = []

http.listen(3000, function(){
    console.log('listening on *:3000');
});

//Returns the IP of the next server in the round-robin
function nextServer(){
    var ip = serverQueue.shift();
    serverQueue.push(ip);
    return ip;
}

var cpuUsages = []
var time = 0;
var recordingInterval = 1000 * 10;
var endtime = 7440000;
var training = false;
var recording = false;
var ended = false;
var keyPrefix = training ? "training:" : "testing:";

//Clear data from previous runs
client.keys(keyPrefix + "*", function(err, keys){
    keys.forEach(function(key){
        client.del(key);
    });
    console.log("Flushed Keys");
});

var requests = 0;
var serverResponses = {};

function startRecordingUsage() {
    scale.emitTrainingData(client, io);
    var recordUsage = setInterval(function(){
        if(!ended){
            var count = cpuUsages.length;
            if(count == 0){
                return;
            }

            var sum = 0;
            while(cpuUsages.length > 0){
                sum += cpuUsages.pop();
            }

            var average = sum / count;

            console.log(JSON.stringify({ip: "Average",
            usage: average.toString()}));

            io.emit('cpu-ip', JSON.stringify({ip: "Average",
            usage: average.toString()}));

            time += recordingInterval;

            client.set(keyPrefix + time, average, redis.print);
            client.set(keyPrefix + "requests:" + time, requests);
            scale.scale(client, time + (1000 * 10), io);

            for (var server in serverResponses) {
                if (serverResponses.hasOwnProperty(server)) {
                    client.set(keyPrefix + "responses:" + server + ":" + time, serverResponses[server])
                }
            }

            scale.emitTestData(client, time, io);

            requests = 0;
            serverResponses = {};

            if(time > endtime){
                ended = true;
            }

        }

    }, recordingInterval);
}

function removeFromServerList(ip){
    var index = serverQueue.indexOf(ip);
    if(index > -1){
        serverQueue.splice(index, 1);
    }
}

io.on('connection', function(socket){
    console.log(socket.request.connection._peername.address);
    var ip = socket.request.connection._peername.address;

    socket.on('cpu-usage', function(msg){
        if(serverQueue.indexOf(ip) === -1){
            serverQueue.push(ip);
        }

        if(recording){
            cpuUsages.push(msg);
        }
    });

    socket.on('shutdown', function(){
        console.log('Shutdown Request Received');
        removeFromServerList(ip);
        socket.emit('shutdown-complete', "");
    });

    socket.on('disconnect', function(){
        //Call again incase of unexpected shutdown
        removeFromServerList(ip);
    });
});

app.get('/', function(req, res){
    if(!recording){
        recording = true;
        startRecordingUsage();
    }

    requests++;

    var server = nextServer();
    request("http://" + server + ":3005" , function(error, response, body) {
        res.write("You were served by " + server + "\n")
        res.end(body);

        if(serverResponses[server] === undefined){
            serverResponses[server] = 1;
        }
        else {
            serverResponses[server]++;
        }
    });
});
<commit_msg>Added initial scaling<commit_after>var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
var request = require("request");
var redis = require("redis");
var scale = require("./scale.js");

//Setup Redis
client = redis.createClient();
client.on("error", function (err) {
    console.log("Error " + err);
});

//var connectedServers = {}
var serverQueue = []

http.listen(3000, function(){
    console.log('listening on *:3000');
});

//Returns the IP of the next server in the round-robin
function nextServer(){
    var ip = serverQueue.shift();
    serverQueue.push(ip);
    return ip;
}

var cpuUsages = []
var time = 0;
var recordingInterval = 1000 * 10;
var endtime = 7440000;
var training = false;
var recording = false;
var ended = false;
var keyPrefix = training ? "training:" : "testing:";

//Clear data from previous runs
client.keys(keyPrefix + "*", function(err, keys){
    keys.forEach(function(key){
        client.del(key);
    });
    console.log("Flushed Keys");
});

var requests = 0;
var serverResponses = {};

function startRecordingUsage() {
    scale.emitTrainingData(client, io);
    scale.scale(client, 1000 * 10, io);
    var recordUsage = setInterval(function(){
        if(!ended){
            var count = cpuUsages.length;
            if(count == 0){
                return;
            }

            var sum = 0;
            while(cpuUsages.length > 0){
                sum += cpuUsages.pop();
            }

            var average = sum / count;

            console.log(JSON.stringify({ip: "Average",
            usage: average.toString()}));

            io.emit('cpu-ip', JSON.stringify({ip: "Average",
            usage: average.toString()}));

            time += recordingInterval;

            client.set(keyPrefix + time, average, redis.print);
            client.set(keyPrefix + "requests:" + time, requests);
            scale.scale(client, time + (1000 * 10), io);

            for (var server in serverResponses) {
                if (serverResponses.hasOwnProperty(server)) {
                    client.set(keyPrefix + "responses:" + server + ":" + time, serverResponses[server])
                }
            }

            scale.emitTestData(client, time, io);

            requests = 0;
            serverResponses = {};

            if(time > endtime){
                ended = true;
            }

        }

    }, recordingInterval);
}

function removeFromServerList(ip){
    var index = serverQueue.indexOf(ip);
    if(index > -1){
        serverQueue.splice(index, 1);
    }
}

io.on('connection', function(socket){
    console.log(socket.request.connection._peername.address);
    var ip = socket.request.connection._peername.address;

    socket.on('cpu-usage', function(msg){
        if(serverQueue.indexOf(ip) === -1){
            serverQueue.push(ip);
        }

        if(recording){
            cpuUsages.push(msg);
        }
    });

    socket.on('shutdown', function(){
        console.log('Shutdown Request Received');
        removeFromServerList(ip);
        socket.emit('shutdown-complete', "");
    });

    socket.on('disconnect', function(){
        //Call again incase of unexpected shutdown
        removeFromServerList(ip);
    });
});

app.get('/', function(req, res){
    if(!recording){
        recording = true;
        startRecordingUsage();
    }

    requests++;

    var server = nextServer();
    request("http://" + server + ":3005" , function(error, response, body) {
        res.write("You were served by " + server + "\n")
        res.end(body);

        if(serverResponses[server] === undefined){
            serverResponses[server] = 1;
        }
        else {
            serverResponses[server]++;
        }
    });
});
<|endoftext|>


<commit_before>/* Timetable for Trains Module */

/* Magic Mirror
 * Module: UK National Rail
 *
 * By Nick Wootton
 * based on SwissTransport module by Benjamin Angst http://www.beny.ch
 * MIT Licensed.
 */

Module.register("MMM-UKNationalRail", {

    // Define module defaults
    defaults: {
        updateInterval: 5 * 60 * 1000, // Update every 5 minutes.
        animationSpeed: 2000,
        fade: true,
        fadePoint: 0.25, // Start on 1/4th of the list.
        initialLoadDelay: 0, // start delay seconds.

        apiBase: 'https://transportapi.com/v3/uk/train/station/',

        stationCode: '', // CRS code for station
        app_key: '', // TransportAPI App Key
        app_id: '', // TransportAPI App ID

        called_at: '',
        calling_at: '',
        darwin: '',
        destination: '',
        from_offset: '',
        operator: '',
        origin: '',
        service: '',
        to_offset: '',
        train_status: '',
        type: '',

        maxResults: 5, //Maximum number of results to display
        showOrigin: false, //Show origin of train
        showPlatform: true, //Show departure platform of train
        showActualDeparture: true, //Show real-time departure time

        debug: false
    },

    // Define required scripts.
    getStyles: function() {
        return ["trains.css", "font-awesome.css"];
    },

    // Define required scripts.
    getScripts: function() {
        return ["moment.js", this.file('titleCase.js')];
    },

    //Define header for module.
    getHeader: function() {
        return this.config.header;
    },

    // Define start sequence.
    start: function() {
        Log.info("Starting module: " + this.name);

        // Set locale.
        moment.locale(config.language);

        this.trains = {};
        this.loaded = false;
        this.scheduleUpdate(this.config.initialLoadDelay);

        this.updateTimer = null;

        this.url = encodeURI(this.config.apiBase + this.config.stationCode + '/live.json' + this.getParams());

        if (this.config.debug) {
            Log.warn('URL Request is: ' + this.url);
        }

        this.updateTrainInfo(this);
    },

    // updateTrainInfo
    updateTrainInfo: function(self) {
        self.sendSocketNotification('GET_TRAININFO', { 'url': this.url });
    },

    // Override dom generator.
    getDom: function() {
        var wrapper = document.createElement("div");

        if (this.config.stationCode === "") {
            wrapper.innerHTML = "Please set the Station Code: " + this.stationCode + ".";
            wrapper.className = "dimmed light small";
            return wrapper;
        }

        if (this.config.app_id === "") {
            wrapper.innerHTML = "Please set the application ID: " + this.app_id + ".";
            wrapper.className = "dimmed light small";
            return wrapper;
        }

        if (this.config.app_key === "") {
            wrapper.innerHTML = "Please set the application key: " + this.app_key + ".";
            wrapper.className = "dimmed light small";
            return wrapper;
        }

        if (!this.loaded) {
            wrapper.innerHTML = "Loading trains ...";
            wrapper.className = "dimmed light small";
            return wrapper;
        }

        //Dump train data
        if (this.config.debug) {
            Log.info(this.trains);
        }

        // *** Start Building Table
        var table = document.createElement("table");
        table.className = "small";

        if (this.trains.stationName !== null) {
            this.config.header = this.trains.stationName;
        }

        //With data returned
        if (this.trains.data.length > 0) {
            for (var t in this.trains.data) {
                var myTrain = this.trains.data[t];

                //Create row for data item
                var row = document.createElement("tr");
                table.appendChild(row);

                //If platform is required, create first table cell
                if (this.config.showPlatform) {
                    if (myTrain.platform) {
                        platform = myTrain.platform;
                    } else {
                        platform = '-';
                    }

                    var trainPlatformCell = document.createElement("td");
                    trainPlatformCell.innerHTML = " " + platform + " ";
                    trainPlatformCell.className = "platform";
                    row.appendChild(trainPlatformCell);
                }

                //Train destination cell
                var trainDestCell = document.createElement("td");
                trainDestCell.innerHTML = myTrain.destination;
                trainDestCell.className = "bright dest";
                row.appendChild(trainDestCell);

                //If required train origin cell
                if (this.config.showOrigin) {
                    var trainOriginCell = document.createElement("td");
                    trainOriginCell.innerHTML = myTrain.origin;
                    trainOriginCell.className = "trainOrigin";
                    row.appendChild(trainOriginCell);
                }

                //Timetabled departure time
                var plannedDepCell = document.createElement("td");
                plannedDepCell.innerHTML = myTrain.plannedDeparture;
                plannedDepCell.className = "timeTabled";
                row.appendChild(plannedDepCell);

                //If required, live departure time
                if (this.config.showActualDeparture) {
                    var actualDepCell = document.createElement("td");
                    actualDepCell.innerHTML = "(" + myTrain.actualDeparture + ")";
                    actualDepCell.className = "actualTime";
                    row.appendChild(actualDepCell);
                }

                //Train status cell
                var statusCell = document.createElement("td");
                statusCell.innerHTML = " " + titleCase(myTrain.status) + " ";

                if (myTrain.status == "ON TIME") {
                    statusCell.className = "bright nonews status";
                } else if (myTrain.status == "LATE") {
                    statusCell.className = "bright late status";
                } else if (myTrain.status == "EARLY") {
                    statusCell.className = "bright early status";
                } else if (myTrain.status == "CANCELLED") {
                    statusCell.className = "late status";
                } else if (myTrain.status == "ARRIVED") {
                    statusCell.className = "early status";
                } else if (myTrain.status == "REINSTATEMENT" || myTrain.status == "STARTS HERE") {
                    statusCell.className = "goodnews status";
                } else if (myTrain.status == "NO REPORT" || myTrain.status == "OFF ROUTE") {
                    statusCell.className = "nonews status";
                } else {
                    statusCell.className = "nonews status";
                }

                row.appendChild(statusCell);

                if (this.config.fade && this.config.fadePoint < 1) {
                    if (this.config.fadePoint < 0) {
                        this.config.fadePoint = 0;
                    }
                    var startingPoint = this.trains.length * this.config.fadePoint;
                    var steps = this.trains.length - startingPoint;
                    if (t >= startingPoint) {
                        var currentStep = t - startingPoint;
                        row.style.opacity = 1 - (1 / steps * currentStep);
                    }
                }
            }
        } else {
            var row1 = document.createElement("tr");
            table.appendChild(row1);

            var messageCell = document.createElement("td");
            messageCell.innerHTML = " " + this.trains.message + " ";
            messageCell.className = "bright";
            row1.appendChild(messageCell);

            var row2 = document.createElement("tr");
            table.appendChild(row2);

            var timeCell = document.createElement("td");
            timeCell.innerHTML = " " + this.trains.timestamp + " ";
            timeCell.className = "bright";
            row2.appendChild(timeCell);
        }

        wrapper.appendChild(table);
        // *** End building results table

        return wrapper;
    },

    /* processTrains(data)
     * Uses the received data to set the various values.
     *
     * argument data object - Weather information received form openweather.org.
     */
    processTrains: function(data) {

        //Check we have data back from API
        if (typeof data !== 'undefined' && data !== null) {

            //define object to hold train info
            this.trains = {};
            //Define array of departure data
            this.trains.data = [];
            //Define timestamp of current data
            this.trains.timestamp = new Date();
            //Define message holder
            this.trains.message = null;

            //Figure out Station Name
            //Define empty name
            var stationName = "";

            if (typeof data.station_name !== 'undefined' && data.station_name !== null) {
                //Populate with stop name returned by TransportAPI info
                stationName = data.station_name;
            } else {
                //Default
                stationName = "Departures";
            }
            //Set value
            this.trains.stationName = stationName;

            //Check we have route info
            if (typeof data.departures !== 'undefined' && data.departures !== null) {

                //... and some departures
				if (typeof data.departures.all !== 'undefined' && data.departures.all !== null) {

                    //.. and actual departures
                    if (data.departures.all.length > 0) {

                        //Figure out how long the results are
                        var counter = 0;
                        if (this.config.maxResults > data.departures.all.length) {
                            counter = data.departures.all.length;
                        } else {
                            counter = this.config.maxResults;
                        }

                        for (var i = 0; i < counter; i++) {

                            var thisTrain = data.departures.all[i];

                            this.trains.data.push({
                                plannedDeparture: thisTrain.aimed_departure_time,
                                actualDeparture: thisTrain.expected_departure_time,
                                status: thisTrain.status,
                                origin: thisTrain.origin_name,
                                destination: thisTrain.destination_name,
                                leavesIn: thisTrain.best_arrival_estimate_mins,
                                platform: thisTrain.platform
                            });
                        }
                    } else {
                        //No departures info returned - set message
                        this.trains.message = "No departure info found";
                        if (this.config.debug) {
                            Log.error("=======LEVEL 4=========");
                            Log.error(this.trains);
                            Log.error("^^^^^^^^^^^^^^^^^^^^^^^");
                        }
                    }
                } else {
                    //No departures info returned - set message
                    this.trains.message = "No departures scheduled";
                    if (this.config.debug) {
                        Log.error("=======LEVEL 3=========");
                        Log.error(this.trains);
                        Log.error("^^^^^^^^^^^^^^^^^^^^^^^");
                    }
                }
            } else {
                //No info returned - set message
                this.trains.message = "No info about the station returned";
                if (this.config.debug) {
                    Log.error("=======LEVEL 2=========");
                    Log.error(this.trains);
                    Log.error("^^^^^^^^^^^^^^^^^^^^^^^");
                }
            }

        } else {
            //No data returned - set message
            this.trains.message = "No data returned";
            if (this.config.debug) {
                Log.error("=======LEVEL 1=========");
                Log.error(this.trains);
                Log.error("^^^^^^^^^^^^^^^^^^^^^^^");
            }
        }

        this.loaded = true;
        this.updateDom(this.config.animationSpeed);
    },

    /* getParams(compliments)
     * Generates an url with api parameters based on the config.
     *
     * return String - URL params.
     */
    getParams: function() {
        var params = "?";
        params += "app_id=" + this.config.app_id;
        params += "&app_key=" + this.config.app_key;

        if (this.config.called_at.length > 0) {
            params += "&called_at=" + this.config.called_at;
        }

        if (this.config.calling_at.length > 0) {
            params += "&calling_at=" + this.config.calling_at;
        }

        if (this.config.darwin) {
            params += "&darwin=" + this.config.darwin;
        }

        if (this.config.destination.length > 0) {
            params += "&destination=" + this.config.destination;
        }

        if (this.config.from_offset.length > 0) {
            params += "&from_offset=" + this.config.from_offset;
        }

        if (this.config.operator.length > 0) {
            params += "&operator=" + this.config.operator;
        }

        if (this.config.origin.length > 0) {
            params += "&origin=" + this.config.origin;
        }

        if (this.config.service.length > 0) {
            params += "&service=" + this.config.service;
        }

        if (this.config.to_offset.length > 0) {
            params += "&to_offset=" + this.config.to_offset;
        }

        if (this.config.train_status.length > 0) {
            params += "&train_status=" + this.config.train_status;
        }

        if (this.config.type.length > 0) {
            params += "&type=" + this.config.type;
        }

        if (this.config.debug) {
            Log.warn(params);
        }

        return params;
    },

    /* scheduleUpdate()
     * Schedule next update.
     *
     * argument delay number - Milliseconds before next update. If empty, this.config.updateInterval is used.
     */
    scheduleUpdate: function(delay) {
        var nextLoad = this.config.updateInterval;
        if (typeof delay !== "undefined" && delay >= 0) {
            nextLoad = delay;
        }

        var self = this;
        clearTimeout(this.updateTimer);
        this.updateTimer = setTimeout(function() {
            self.updateTrainInfo(self);
        }, nextLoad);
    },

    // Process data returned
    socketNotificationReceived: function(notification, payload) {

        if (notification === 'TRAIN_DATA' && payload.url === this.url) {
            this.processTrains(payload.data);
            this.scheduleUpdate(this.config.updateInterval);
        }
    }

});
<commit_msg>Ensuring 'darwin' default value is false.<commit_after>/* Timetable for Trains Module */

/* Magic Mirror
 * Module: UK National Rail
 *
 * By Nick Wootton
 * based on SwissTransport module by Benjamin Angst http://www.beny.ch
 * MIT Licensed.
 */

Module.register("MMM-UKNationalRail", {

    // Define module defaults
    defaults: {
        updateInterval: 5 * 60 * 1000, // Update every 5 minutes.
        animationSpeed: 2000,
        fade: true,
        fadePoint: 0.25, // Start on 1/4th of the list.
        initialLoadDelay: 0, // start delay seconds.

        apiBase: 'https://transportapi.com/v3/uk/train/station/',

        stationCode: '', // CRS code for station
        app_key: '', // TransportAPI App Key
        app_id: '', // TransportAPI App ID

        called_at: '',
        calling_at: '',
        darwin: false,
        destination: '',
        from_offset: '',
        operator: '',
        origin: '',
        service: '',
        to_offset: '',
        train_status: '',
        type: '',

        maxResults: 5, //Maximum number of results to display
        showOrigin: false, //Show origin of train
        showPlatform: true, //Show departure platform of train
        showActualDeparture: true, //Show real-time departure time

        debug: false
    },

    // Define required scripts.
    getStyles: function() {
        return ["trains.css", "font-awesome.css"];
    },

    // Define required scripts.
    getScripts: function() {
        return ["moment.js", this.file('titleCase.js')];
    },

    //Define header for module.
    getHeader: function() {
        return this.config.header;
    },

    // Define start sequence.
    start: function() {
        Log.info("Starting module: " + this.name);

        // Set locale.
        moment.locale(config.language);

        this.trains = {};
        this.loaded = false;
        this.scheduleUpdate(this.config.initialLoadDelay);

        this.updateTimer = null;

        this.url = encodeURI(this.config.apiBase + this.config.stationCode + '/live.json' + this.getParams());

        if (this.config.debug) {
            Log.warn('URL Request is: ' + this.url);
        }

        this.updateTrainInfo(this);
    },

    // updateTrainInfo
    updateTrainInfo: function(self) {
        self.sendSocketNotification('GET_TRAININFO', { 'url': this.url });
    },

    // Override dom generator.
    getDom: function() {
        var wrapper = document.createElement("div");

        if (this.config.stationCode === "") {
            wrapper.innerHTML = "Please set the Station Code: " + this.stationCode + ".";
            wrapper.className = "dimmed light small";
            return wrapper;
        }

        if (this.config.app_id === "") {
            wrapper.innerHTML = "Please set the application ID: " + this.app_id + ".";
            wrapper.className = "dimmed light small";
            return wrapper;
        }

        if (this.config.app_key === "") {
            wrapper.innerHTML = "Please set the application key: " + this.app_key + ".";
            wrapper.className = "dimmed light small";
            return wrapper;
        }

        if (!this.loaded) {
            wrapper.innerHTML = "Loading trains ...";
            wrapper.className = "dimmed light small";
            return wrapper;
        }

        //Dump train data
        if (this.config.debug) {
            Log.info(this.trains);
        }

        // *** Start Building Table
        var table = document.createElement("table");
        table.className = "small";

        if (this.trains.stationName !== null) {
            this.config.header = this.trains.stationName;
        }

        //With data returned
        if (this.trains.data.length > 0) {
            for (var t in this.trains.data) {
                var myTrain = this.trains.data[t];

                //Create row for data item
                var row = document.createElement("tr");
                table.appendChild(row);

                //If platform is required, create first table cell
                if (this.config.showPlatform) {
                    if (myTrain.platform) {
                        platform = myTrain.platform;
                    } else {
                        platform = '-';
                    }

                    var trainPlatformCell = document.createElement("td");
                    trainPlatformCell.innerHTML = " " + platform + " ";
                    trainPlatformCell.className = "platform";
                    row.appendChild(trainPlatformCell);
                }

                //Train destination cell
                var trainDestCell = document.createElement("td");
                trainDestCell.innerHTML = myTrain.destination;
                trainDestCell.className = "bright dest";
                row.appendChild(trainDestCell);

                //If required train origin cell
                if (this.config.showOrigin) {
                    var trainOriginCell = document.createElement("td");
                    trainOriginCell.innerHTML = myTrain.origin;
                    trainOriginCell.className = "trainOrigin";
                    row.appendChild(trainOriginCell);
                }

                //Timetabled departure time
                var plannedDepCell = document.createElement("td");
                plannedDepCell.innerHTML = myTrain.plannedDeparture;
                plannedDepCell.className = "timeTabled";
                row.appendChild(plannedDepCell);

                //If required, live departure time
                if (this.config.showActualDeparture) {
                    var actualDepCell = document.createElement("td");
                    actualDepCell.innerHTML = "(" + myTrain.actualDeparture + ")";
                    actualDepCell.className = "actualTime";
                    row.appendChild(actualDepCell);
                }

                //Train status cell
                var statusCell = document.createElement("td");
                statusCell.innerHTML = " " + titleCase(myTrain.status) + " ";

                if (myTrain.status == "ON TIME") {
                    statusCell.className = "bright nonews status";
                } else if (myTrain.status == "LATE") {
                    statusCell.className = "bright late status";
                } else if (myTrain.status == "EARLY") {
                    statusCell.className = "bright early status";
                } else if (myTrain.status == "CANCELLED") {
                    statusCell.className = "late status";
                } else if (myTrain.status == "ARRIVED") {
                    statusCell.className = "early status";
                } else if (myTrain.status == "REINSTATEMENT" || myTrain.status == "STARTS HERE") {
                    statusCell.className = "goodnews status";
                } else if (myTrain.status == "NO REPORT" || myTrain.status == "OFF ROUTE") {
                    statusCell.className = "nonews status";
                } else {
                    statusCell.className = "nonews status";
                }

                row.appendChild(statusCell);

                if (this.config.fade && this.config.fadePoint < 1) {
                    if (this.config.fadePoint < 0) {
                        this.config.fadePoint = 0;
                    }
                    var startingPoint = this.trains.length * this.config.fadePoint;
                    var steps = this.trains.length - startingPoint;
                    if (t >= startingPoint) {
                        var currentStep = t - startingPoint;
                        row.style.opacity = 1 - (1 / steps * currentStep);
                    }
                }
            }
        } else {
            var row1 = document.createElement("tr");
            table.appendChild(row1);

            var messageCell = document.createElement("td");
            messageCell.innerHTML = " " + this.trains.message + " ";
            messageCell.className = "bright";
            row1.appendChild(messageCell);

            var row2 = document.createElement("tr");
            table.appendChild(row2);

            var timeCell = document.createElement("td");
            timeCell.innerHTML = " " + this.trains.timestamp + " ";
            timeCell.className = "bright";
            row2.appendChild(timeCell);
        }

        wrapper.appendChild(table);
        // *** End building results table

        return wrapper;
    },

    /* processTrains(data)
     * Uses the received data to set the various values.
     *
     * argument data object - Weather information received form openweather.org.
     */
    processTrains: function(data) {

        //Check we have data back from API
        if (typeof data !== 'undefined' && data !== null) {

            //define object to hold train info
            this.trains = {};
            //Define array of departure data
            this.trains.data = [];
            //Define timestamp of current data
            this.trains.timestamp = new Date();
            //Define message holder
            this.trains.message = null;

            //Figure out Station Name
            //Define empty name
            var stationName = "";

            if (typeof data.station_name !== 'undefined' && data.station_name !== null) {
                //Populate with stop name returned by TransportAPI info
                stationName = data.station_name;
            } else {
                //Default
                stationName = "Departures";
            }
            //Set value
            this.trains.stationName = stationName;

            //Check we have route info
            if (typeof data.departures !== 'undefined' && data.departures !== null) {

                //... and some departures
				if (typeof data.departures.all !== 'undefined' && data.departures.all !== null) {

                    //.. and actual departures
                    if (data.departures.all.length > 0) {

                        //Figure out how long the results are
                        var counter = 0;
                        if (this.config.maxResults > data.departures.all.length) {
                            counter = data.departures.all.length;
                        } else {
                            counter = this.config.maxResults;
                        }

                        for (var i = 0; i < counter; i++) {

                            var thisTrain = data.departures.all[i];

                            this.trains.data.push({
                                plannedDeparture: thisTrain.aimed_departure_time,
                                actualDeparture: thisTrain.expected_departure_time,
                                status: thisTrain.status,
                                origin: thisTrain.origin_name,
                                destination: thisTrain.destination_name,
                                leavesIn: thisTrain.best_arrival_estimate_mins,
                                platform: thisTrain.platform
                            });
                        }
                    } else {
                        //No departures info returned - set message
                        this.trains.message = "No departure info found";
                        if (this.config.debug) {
                            Log.error("=======LEVEL 4=========");
                            Log.error(this.trains);
                            Log.error("^^^^^^^^^^^^^^^^^^^^^^^");
                        }
                    }
                } else {
                    //No departures info returned - set message
                    this.trains.message = "No departures scheduled";
                    if (this.config.debug) {
                        Log.error("=======LEVEL 3=========");
                        Log.error(this.trains);
                        Log.error("^^^^^^^^^^^^^^^^^^^^^^^");
                    }
                }
            } else {
                //No info returned - set message
                this.trains.message = "No info about the station returned";
                if (this.config.debug) {
                    Log.error("=======LEVEL 2=========");
                    Log.error(this.trains);
                    Log.error("^^^^^^^^^^^^^^^^^^^^^^^");
                }
            }

        } else {
            //No data returned - set message
            this.trains.message = "No data returned";
            if (this.config.debug) {
                Log.error("=======LEVEL 1=========");
                Log.error(this.trains);
                Log.error("^^^^^^^^^^^^^^^^^^^^^^^");
            }
        }

        this.loaded = true;
        this.updateDom(this.config.animationSpeed);
    },

    /* getParams(compliments)
     * Generates an url with api parameters based on the config.
     *
     * return String - URL params.
     */
    getParams: function() {
        var params = "?";
        params += "app_id=" + this.config.app_id;
        params += "&app_key=" + this.config.app_key;

        if (this.config.called_at.length > 0) {
            params += "&called_at=" + this.config.called_at;
        }

        if (this.config.calling_at.length > 0) {
            params += "&calling_at=" + this.config.calling_at;
        }

        if (this.config.darwin) {
            params += "&darwin=" + this.config.darwin;
        }

        if (this.config.destination.length > 0) {
            params += "&destination=" + this.config.destination;
        }

        if (this.config.from_offset.length > 0) {
            params += "&from_offset=" + this.config.from_offset;
        }

        if (this.config.operator.length > 0) {
            params += "&operator=" + this.config.operator;
        }

        if (this.config.origin.length > 0) {
            params += "&origin=" + this.config.origin;
        }

        if (this.config.service.length > 0) {
            params += "&service=" + this.config.service;
        }

        if (this.config.to_offset.length > 0) {
            params += "&to_offset=" + this.config.to_offset;
        }

        if (this.config.train_status.length > 0) {
            params += "&train_status=" + this.config.train_status;
        }

        if (this.config.type.length > 0) {
            params += "&type=" + this.config.type;
        }

        if (this.config.debug) {
            Log.warn(params);
        }

        return params;
    },

    /* scheduleUpdate()
     * Schedule next update.
     *
     * argument delay number - Milliseconds before next update. If empty, this.config.updateInterval is used.
     */
    scheduleUpdate: function(delay) {
        var nextLoad = this.config.updateInterval;
        if (typeof delay !== "undefined" && delay >= 0) {
            nextLoad = delay;
        }

        var self = this;
        clearTimeout(this.updateTimer);
        this.updateTimer = setTimeout(function() {
            self.updateTrainInfo(self);
        }, nextLoad);
    },

    // Process data returned
    socketNotificationReceived: function(notification, payload) {

        if (notification === 'TRAIN_DATA' && payload.url === this.url) {
            this.processTrains(payload.data);
            this.scheduleUpdate(this.config.updateInterval);
        }
    }

});
<|endoftext|>


<commit_before>/*
 * Run in: http://adventofcode.com/day/9/input
 */

;(function () {
  let input = document.querySelector('pre').textContent.slice(0, -1)

  console.log('Day09/first:', first(input))
  console.log('Day09/second:', second(input))

  function first (input) {
    return getRouteDistances(input)[0]
  }

  function second (input) {
    return getRouteDistances(input).pop()
  }

  function getRouteDistances (input) {
    let extractor = /(\w+) to (\w+) = (\d+)/
    let distances = input.split('\n').map(l => l.match(extractor))

    let destinies = Array.from(distances.reduce((a, b) => {
      return a.add(b[1]).add(b[2])
    }, new Set()))

    let permutations = permute(destinies)

    distances = distances.reduce((a, b) => {
      a[b[1] + ',' + b[2]] = +b[3]
      return a
    }, {})

    return permutations.map(el => {
      return el.reduce((a, b, i, arr) => {
        return a + (
          distances[b + ',' + arr[i + 1]] ||
          distances[arr[i + 1] + ',' + b] ||
          0)
      }, 0)
    }).sort((a, b) => a > b)
  }

  function permute (arr) {
    return arr.length <= 2
      ? [ arr.slice(), arr.slice().reverse() ]
      : arr.map((el, i, arr) => {
        let cp = arr.slice()
        let cu = cp.splice(i, 1)
        return permute(cp).map(el => el.concat(cu))
      }).reduce((a, b) => a.concat(b), [])
  }
}())
<commit_msg>More use of ES2015 to day09<commit_after>/*
 * Run in: http://adventofcode.com/day/9/input
 */

;(function () {
  let input = document.querySelector('pre').textContent.slice(0, -1)

  console.log('Day09/first:', first(input))
  console.log('Day09/second:', second(input))

  function first (input) {
    return getRouteDistances(input)[0]
  }

  function second (input) {
    return getRouteDistances(input).pop()
  }

  function getRouteDistances (input) {
    const extractor = /(\w+) to (\w+) = (\d+)/
    let distances = input.split('\n').map(l => l.match(extractor))

    let destinies = Array.from(distances.reduce((a, b) => {
      return a.add(b[1]).add(b[2])
    }, new Set()))

    let permutations = permute(destinies)

    distances = distances.reduce((a, b) => {
      a[`${b[1]},${b[2]}`] = +b[3]
      return a
    }, {})

    return permutations.map(el => {
      return el.reduce((a, b, i, arr) => {
        return a + (
          distances[`${b},${arr[i + 1]}`] ||
          distances[`${arr[i + 1]},${b}`] ||
          0)
      }, 0)
    }).sort((a, b) => a > b)
  }

  function permute (arr) {
    return arr.length - 2 &&
      [].concat(...arr.map((el, i, arr) => {
        let cp = arr.slice()
        let cu = cp.splice(i, 1)
        return permute(cp).map(el => cu.concat(el))
      })) ||
      [ arr.slice(), arr.slice().reverse() ]
  }
}())
<|endoftext|>


<commit_before>var IncomingCallBack = require('../constructors/callback');
var NameSpace = require('../constructors/namespace');
var routeController = require('./routeController');

var core;

var incomingCallbacks = {};
var outgoingCallbacks = {};
var nameSpaces = {};

var executionController = {

    initialize: function(samsaaraCore) {
        core = samsaaraCore;

        nameSpaces.core = new NameSpace('core', {});
        nameSpaces.internal = new NameSpace('internal', {
            callItBack: callItBack,
            callItBackError: callItBackError
        });
    },

    // Outgoing Execution

    execute: function(channel, route, executorArray, namespaceName, funcName, args) {

        var packet = {
            func: funcName,
            ns: namespaceName || 'core',
            args: args
        };

        if (typeof args[args.length - 1] === 'function') {
            packet.args = Array.prototype.slice.call(args);
            createCallBack(packet.args.pop(), executorArray, packet);
        }

        routeController.routeOutgoingPacket(channel, route, packet);
    },

    executeRaw: function(channel, route, executorArray, packet, callBack) {

        if (typeof callBack === 'function') {
            createCallBack(callBack, executorArray, packet);
        }

        routeController.routeOutgoingPacket(channel, route, packet);
    },

    // Incoming Execution

    executeFunction: function(executor, context, incomingPacket, callBackGenerator) {

        var functionName = incomingPacket.func;
        var namespaceName = incomingPacket.ns || 'core';
        var namespace = this.nameSpace(namespaceName);
        var namespaceMethods;
        var messageArgs;
        var theCallBack;
        var callbackID;

        if (namespace !== undefined) {

            namespaceMethods = namespace.methods;

            if (typeof namespaceMethods[functionName] === 'function') {

                messageArgs = incomingPacket.args || [];

                callBackGenerator = callBackGenerator || generateOutgoingCallBackClosure;
                callbackID = incomingPacket.callBack;

                if (typeof callbackID === 'string' && callbackID.match(/^([a-zA-Z0-9\.]+)$/)) {
                    theCallBack = outgoingCallbacks[callbackID] = callBackGenerator(callbackID, executor);
                    messageArgs.push(theCallBack);
                }

                namespaceMethods[functionName].apply(context, messageArgs);

            } else {
                console.error('Samsaara Method Execution ERROR: Call by:', executor.id, ':', functionName, 'is not an exposed Samsaara Object that can be executed.');
            }

        } else {
            console.error('Samsaara Method Execution ERROR: Call by:', executor.id, ':', namespaceName, 'is not valid namespace.');
        }
    },

    // Exported to Core

    createNamespace: function(namespaceName, methods) {
        var nameSpace = null;

        if (namespaceName !== 'core' && namespaceName !== 'internal') {
            nameSpace = new NameSpace(namespaceName, methods);
            nameSpaces[namespaceName] = nameSpace;
        }

        return core;
    },

    nameSpace: function(namespaceName) {
        return nameSpaces[namespaceName];
    },

    expose: function(set) {
        this.nameSpace('core').expose(set);
        return core;
    }
};

// a method to process a packet for multiple executors
// args is initially an arguments object
function processPacket(executorArray, packet, args) {

    if (typeof args[args.length - 1] === 'function') {
        args = Array.prototype.slice.call(args);
        createCallBack(args.pop(), executorArray, packet);
    }

    packet.args = args;

    return packet;
}

// Incoming CallBack Generator
// Creates an expected Callback method, whose index is sent to clients.
// The callback will expect a certain number of processes/clients to execute before getting deleted/set to undefined.
function createCallBack(theCallBack, executorArray, packet) {
    var incomingCallback = new IncomingCallBack(theCallBack, executorArray, destroyCallBack);
    var callbackID = incomingCallback.callbackID;

    incomingCallbacks[callbackID] = incomingCallback;
    packet.callBack = callbackID;

    // console.log('EXECUTING', theCallBack, executorArray, packet, incomingCallback);

    return incomingCallback;
}

function destroyCallBack(callbackID) {
    incomingCallbacks[callbackID] = undefined;
}

// Outgoing CallBack Generator
// Returns a function to send a message answering a callBack request sent from the client
function generateOutgoingCallBackClosure(callbackID, executor) {

    var theCallBack = function() {
        var args = Array.prototype.slice.call(arguments),
            packet = {
                ns: 'internal',
                func: 'callItBack',
                args: [callbackID, args]
            },
            aCallBack;

        if (typeof args[args.length - 1] !== 'function') {
            executor.executeRaw(packet);
        } else {
            aCallBack = args.pop();
            executor.executeRaw(packet, aCallBack);
        }

        delete outgoingCallbacks[callbackID];
    };

    return theCallBack;
}

// Exposed CallBack Execution Method
// Allows the client to execute an indexed method that was stored for callback
function callItBack(callbackID, args) {

    var executor = this;
    var executorID = executor.id;
    var theCallBack = incomingCallbacks[callbackID];

    if (theCallBack !== undefined && args instanceof Array) {

        if (typeof arguments[arguments.length - 1] === 'function') {
            args.push(arguments[arguments.length - 1]);
        }

        theCallBack.executeCallBack(executorID, executor, args);
    }
}

// Exposed CallBack Execution Error Method
// Allows the client to execute an indexed method that was stored for callback
function callItBackError(callbackID, args) {

    var executor = this;
    var executorID = executor.id;
    var theCallBack = incomingCallbacks[callbackID];

    if (theCallBack !== undefined) {
        theCallBack.callBackError(executorID, executor, args);
    }
}

module.exports = executionController;
<commit_msg>Cleanup<commit_after>var IncomingCallBack = require('../constructors/callback');
var NameSpace = require('../constructors/namespace');
var routeController = require('./routeController');

var core;

var incomingCallbacks = {};
var outgoingCallbacks = {};
var nameSpaces = {};

var executionController = {

    initialize: function(samsaaraCore) {
        core = samsaaraCore;

        nameSpaces.core = new NameSpace('core', {});
        nameSpaces.internal = new NameSpace('internal', {
            callItBack: callItBack,
            callItBackError: callItBackError
        });
    },

    // Outgoing Execution

    execute: function(channel, route, executorArray, namespaceName, funcName, args) {

        var packet = {
            func: funcName,
            ns: namespaceName || 'core',
            args: args
        };

        if (typeof args[args.length - 1] === 'function') {
            packet.args = Array.prototype.slice.call(args);
            createCallBack(packet.args.pop(), executorArray, packet);
        }

        routeController.routeOutgoingPacket(channel, route, packet);
    },

    executeRaw: function(channel, route, executorArray, packet, callBack) {

        if (typeof callBack === 'function') {
            createCallBack(callBack, executorArray, packet);
        }

        routeController.routeOutgoingPacket(channel, route, packet);
    },

    // Incoming Execution

    executeFunction: function(executor, context, incomingPacket, callBackGenerator) {

        var functionName = incomingPacket.func;
        var namespaceName = incomingPacket.ns || 'core';
        var namespace = this.nameSpace(namespaceName);
        var namespaceMethods;
        var messageArgs;
        var theCallBack;
        var callbackID;

        if (namespace !== undefined) {

            namespaceMethods = namespace.methods;

            if (typeof namespaceMethods[functionName] === 'function') {

                messageArgs = incomingPacket.args || [];

                callBackGenerator = callBackGenerator || generateOutgoingCallBackClosure;
                callbackID = incomingPacket.callBack;

                if (typeof callbackID === 'string' && callbackID.match(/^([a-zA-Z0-9\.]+)$/)) {
                    theCallBack = outgoingCallbacks[callbackID] = callBackGenerator(callbackID, executor);
                    messageArgs.push(theCallBack);
                }

                namespaceMethods[functionName].apply(context, messageArgs);

            } else {
                console.error('Samsaara Method Execution ERROR: Call by:', executor.id, ':', functionName, 'is not an exposed Samsaara Object that can be executed.');
            }

        } else {
            console.error('Samsaara Method Execution ERROR: Call by:', executor.id, ':', namespaceName, 'is not valid namespace.');
        }
    },

    // Exported to Core

    createNamespace: function(namespaceName, methods) {

        var nameSpace = null;

        if (namespaceName !== 'core' && namespaceName !== 'internal') {
            nameSpace = new NameSpace(namespaceName, methods);
            nameSpaces[namespaceName] = nameSpace;
        }

        return core;
    },

    nameSpace: function(namespaceName) {
        return nameSpaces[namespaceName];
    },

    expose: function(set) {
        this.nameSpace('core').expose(set);
        return core;
    }
};

// a method to process a packet for multiple executors
// args is initially an arguments object
function processPacket(executorArray, packet, args) {

    if (typeof args[args.length - 1] === 'function') {
        args = Array.prototype.slice.call(args);
        createCallBack(args.pop(), executorArray, packet);
    }

    packet.args = args;

    return packet;
}

// Incoming CallBack Generator
// Creates an expected Callback method, whose index is sent to clients.
// The callback will expect a certain number of processes/clients to execute before getting deleted/set to undefined.
function createCallBack(theCallBack, executorArray, packet) {

    var incomingCallback = new IncomingCallBack(theCallBack, executorArray, destroyCallBack);
    var callbackID = incomingCallback.callbackID;

    incomingCallbacks[callbackID] = incomingCallback;
    packet.callBack = callbackID;

    return incomingCallback;
}

function destroyCallBack(callbackID) {
    incomingCallbacks[callbackID] = undefined;
}

// Outgoing CallBack Generator
// Returns a function to send a message answering a callBack request sent from the client
function generateOutgoingCallBackClosure(callbackID, executor) {

    var theCallBack = function() {
        var args = Array.prototype.slice.call(arguments),
            packet = {
                ns: 'internal',
                func: 'callItBack',
                args: [callbackID, args]
            },
            aCallBack;

        if (typeof args[args.length - 1] !== 'function') {
            executor.executeRaw(packet);
        } else {
            aCallBack = args.pop();
            executor.executeRaw(packet, aCallBack);
        }

        delete outgoingCallbacks[callbackID];
    };

    return theCallBack;
}

// Exposed CallBack Execution Method
// Allows the client to execute an indexed method that was stored for callback
function callItBack(callbackID, args) {

    var executor = this;
    var executorID = executor.id;
    var theCallBack = incomingCallbacks[callbackID];

    if (theCallBack !== undefined && args instanceof Array) {

        if (typeof arguments[arguments.length - 1] === 'function') {
            args.push(arguments[arguments.length - 1]);
        }

        theCallBack.executeCallBack(executorID, executor, args);
    }
}

// Exposed CallBack Execution Error Method
// Allows the client to execute an indexed method that was stored for callback
function callItBackError(callbackID, args) {

    var executor = this;
    var executorID = executor.id;
    var theCallBack = incomingCallbacks[callbackID];

    if (theCallBack !== undefined) {
        theCallBack.callBackError(executorID, executor, args);
    }
}

module.exports = executionController;
<|endoftext|>