<commit_before>var bt       = require("bittorrent");
var benc     = require("benc");
var config   = require("config");
var fs       = require("fs");
var logger   = require("logger").get("core");
var rss      = require("rss");
var session  = bt.session;
var timer    = require("timer");

function saveTorrent(torrent) {
    var torrentsPath = getTorrentsPath();
    var file         = fs.combine(torrentsPath, torrent.infoHash + ".torrent");

    if(fs.fileExists(file)) {
        return;
    }

    var info = torrent.getTorrentInfo();

    if(!info) {
        return;
    }

    var creator = new bt.TorrentCreator(info);
    var entry   = creator.generate();
    var buffer  = benc.encode(entry);

    // Save the actual metadata
    fs.writeBuffer(file, buffer);
    logger.info("Saved torrent file for '" + info.name + "' to " + file);
}

session.on("torrent.removed", function(e) {
    var torrentsPath = getTorrentsPath();

    var torrentFile  = fs.combine(torrentsPath, e.infoHash + ".torrent");
    var resumeFile   = fs.combine(torrentsPath, e.infoHash + ".resume");
    var metadataFile = fs.combine(torrentsPath, e.infoHash + ".metadata");

    if(fs.fileExists(torrentFile)) {
        fs.deleteFile(torrentFile);
    }

    if(fs.fileExists(resumeFile)) {
        fs.deleteFile(resumeFile);
    }

    if(fs.fileExists(metadataFile)) {
        fs.deleteFile(metadataFile);
    }
});

session.on("torrent.metadataReceived", function(e) {
    if(!e.torrent.isValid) {
        logger.error("Received metadata for an invalid torrent.");
        return;
    }

    saveTorrent(e.torrent);
});

session.on("torrent.add", function(e) {
    if(e.error) {
        logger.error("Could not add torrent (code " + e.error.code + "): " +
                     e.error.message);
        return;
    }

    // Add any metadata to the torrent
    var metadata = e.params.metadata || {};

    if(!metadata["options"]) {
        // Add any default options to the metadata
        var defaultOptions = config.get("bittorrent.defaultOptions") || {};

        var options = {
            seedRatio: (defaultOptions["seedRatio"] || 2.0),
            seedTime: (defaultOptions["seedTime"] || 0),
            seedAction: (defaultOptions["seedAction"] || "pause")
        };

        metadata["options"] = options;
    }

    var keys = Object.keys(metadata);

    for(var i = 0; i < keys.length; i++) {
        e.torrent.metadata(keys[i], metadata[keys[i]]);
    }
});

session.on("torrent.added", function(e) {
    if(!e.torrent.isValid) {
        logger.error("Invalid torrent added.");
        return;
    }

    saveTorrent(e.torrent);
});

session.on("torrent.checked", function(e) {
    var torrent = e.torrent;

    if(torrent.metadata("_pauseAfterRecheck")) {
        torrent.pause();
        torrent.metadata("_pauseAfterRecheck", false);
    }

    logger.debug("Torrent '" + e.torrent.infoHash + "' hash checked.");
});

session.on("torrent.hashUpdated", function(e) {
    /*
    On migrating metadata
    ---------------------
    When we add a torrent URL (with eg. tags), the info hash
    is not known at the time. We store each metadata object
    in a std::map keyed by the info hash.

    When libtorrent receives the torrent file and gets the correct
    info hash, it sends us this alert.

    We have a special key handler for "_migrate" which takes the
    old info hash as a value, and then moves the metadata from
    the old info hash to the new info hash.

    It is a bit of a hack, but works.
    */

    e.torrent.metadata("_migrate", e.oldInfoHash);
});

session.on("torrent.stateUpdate", function(e) {
    for(var i = 0; i < e.status.length; i++) {
        var status = e.status[i];

        // Only check our seed goal if the torrent is finished
        // and not paused.
        if(!status.isFinished || status.isPaused) {
            return;
        }

        var torrent = status.torrent;
        var options = torrent.metadata("options") || {};

        var goalRatio = options.seedOverride ? (options.seedRatio || 2.0) : 2.0;
        var goalTime  = options.seedOverride ? (options.goalTime  ||   0) :   0;

        if(status.ratio >= parseFloat(goalRatio)
            || (goalTime > 0 && status.seedingTime > goalTime)) {

            logger.info("Torrent " + status.name + " reached its seed goal.");

            var action = (options.seedAction || "pause");

            switch(action) {
                case "pause":
                    torrent.autoManaged = false;
                    torrent.pause();
                    break;

                case "remove":
                    session.removeTorrent(torrent);
                    break;
            }
        }
    }
});

function getTorrentsPath() {
    var statePath = config.getString("bittorrent.statePath") || "state";
    var torrentsPath = fs.combine(statePath, "torrents");

    if(!fs.directoryExists(torrentsPath)) {
        fs.createDirectories(torrentsPath);
    }

    return torrentsPath;
}

function loadState() {
    var statePath = config.getString("bittorrent.statePath") || "state";

    if(!fs.directoryExists(statePath)) {
        logger.info("Creating state path: " + statePath);
        fs.createDirectories(statePath);
    }

    var stateFile = fs.combine(statePath, ".session_state");

    if(!fs.fileExists(stateFile)) {
        logger.info("No previous session state to load.");
        return;
    }

    var data = fs.readBuffer(stateFile);
    var decoded = benc.decode(data);

    // load session state
    session.loadState(decoded);
    logger.info("Loaded session state from '" + stateFile + "'");
}

function loadTorrents() {
    var torrentsPath = getTorrentsPath();
    var files = fs.getFiles(torrentsPath);

    for(var i = 0; i < files.length; i++) {
        var file = files[i];
        if(!file.endsWith(".torrent")) { continue; }

        var params = bt.AddTorrentParams.getDefault();
        params.torrent = new bt.TorrentInfo(file);

        // Load metadata file
        var metadataFile = file.replace(/\.torrent/i, ".metadata");

        if(fs.fileExists(metadataFile)) {
            var data = fs.readText(metadataFile);
            params.metadata = JSON.parse(data);
        }

        // Load resume file
        var resumeFile = file.replace(/\.torrent$/i, ".resume");

        if(fs.fileExists(resumeFile)) {
            params.resumeData = fs.readBuffer(resumeFile);
        }

        session.addTorrent(params);
        logger.info("Torrent '" + params.torrent.name + "' added.");
    }
}

function load() {
    // Set up listen port for BitTorrent communication
    var listenPort = (config.get("bittorrent.listenPort") || 6881);
    if(isNaN(listenPort)) {
        logger.warn("Invalid listen port specified. Using default (6881).");
        listenPort = 6881;
    }

    session.listenOn([listenPort, listenPort]);

    // Load country database
    var geoIp = config.getString("bittorrent.geoIpFile");

    if(geoIp) {
        logger.info("Loading GeoIP database " + geoIp);
        session.loadCountryDb(geoIp);
    }

    // Add DHT routers.
    var routers = config.get("bittorrent.dht.routers") || [];
    for(var i = 0; i < routers.length; i++) {
        session.addDhtRouter(routers[i][0], routers[i][1]);
    }

    // Enable DHT
    if(config.get("bittorrent.dht.enabled")) {
        logger.info("Enabling DHT.");
        session.startDht();
    }

    // Enable LSD
    if(config.get("bittorrent.lsd.enabled")) {
        logger.info("Enabling LSD.");
        session.startLsd();
    }

    // Enable NatPmp
    if(config.get("bittorrent.natpmp.enabled")) {
        logger.info("Enabling NATPMP.");
        session.startNatPmp();
    }

    // Enable UPnP
    if(config.get("bittorrent.upnp.enabled")) {
        logger.info("Enabling UPnP.");
        session.startUpnp();
    }

    // Load session settings
    var settings = session.getSettings();
    settings.connectionsLimit = (config.get("bittorrent.connectionsLimit") || settings.connectionsLimit);
    settings.downloadRateLimit = (config.get("bittorrent.downloadRateLimit") || settings.downloadRateLimit);
    settings.mixedModeAlgorithm = (config.get("bittorrent.mixedModeAlgorithm") || settings.mixedModeAlgorithm);
    settings.rateLimitIpOverhead = (config.get("bittorrent.rateLimitIpOverhead") || settings.rateLimitIpOverhead);
    settings.rateLimitUtp = (config.get("bittorrent.rateLimitUtp") || settings.rateLimitUtp);
    settings.uploadRateLimit = (config.get("bittorrent.uploadRateLimit") || settings.uploadRateLimit);

    // Advanced settings
    var allowMultipleConnectionsPerIp = config.get("bittorrent.allowMultipleConnectionsPerIp");
    if(typeof allowMultipleConnectionsPerIp !== "undefined") { settings.allowMultipleConnectionsPerIp = allowMultipleConnectionsPerIp; }

    var anonymousMode = config.get("bittorrent.anonymousMode");
    if(typeof anonymousMode !== "undefined") { settings.anonymousMode = anonymousMode; }

    var enableUtp = config.get("bittorrent.utp.enabled");
    if(typeof enableUtp !== "undefined") { enableUtp = true; }
    settings.enableOutgoingUtp = enableUtp;
    settings.enableIncomingUtp = enableUtp;

    settings.halfOpenLimit = (config.get("bittorrent.halfOpenLimit") || settings.halfOpenLimit);

    session.setSettings(settings);

    logger.info("Loaded session settings.");

    loadState();
    loadTorrents();

    rss.load();
    require("plugins").load();

    // Post torrent updates each tick of the timer.
    timer.tick(function() { session.postTorrentUpdates(); });
}

function saveState() {
    var statePath = config.getString("bittorrent.statePath") || "state";
    var stateFile = fs.combine(statePath, ".session_state");

    var entry  = session.saveState();
    var buffer = benc.encode(entry);

    fs.writeBuffer(stateFile, buffer);
    logger.info("Saved session state to '" + stateFile + "'");
}

function saveTorrents() {
    session.pause();

    var torrentsPath = getTorrentsPath();
    var num          = 0;
    var torrents     = session.getTorrents();

    for(var i = 0; i < torrents.length; i++) {
        var t = torrents[i];
        if(!t.isValid) { continue; }

        var s = t.getStatus();

        if(!s.hasMetadata) { continue; }
        if(!s.needSaveResume) { continue; }

        num += 1;
        t.saveResumeData();
    }

    logger.info("Saving resume data for " + num + " torrent(s)");

    while(num > 0) {
        var a = session.waitForAlert(10 * 1000);
        if(!a) { continue; }

        var alerts = session.getAlerts();

        for(var i = 0; i < alerts.length; i++) {
            var alert = alerts[i];

            if(alert == null) {
                continue;
            }

            if(alert.name === "torrent_paused_alert") {
                continue;
            }

            if(alert.name === "save_resume_data_failed_alert") {
                num -= 1;
                continue;
            }

            if(alert.name !== "save_resume_data_alert") {
                continue;
            }

            num -= 1;

            if(!alert.resumeData) {
                logger.info("No resume data for torrent.");
                continue;
            }

            var buffer = benc.encode(alert.resumeData);
            var resumeFile = fs.combine(torrentsPath, alert.torrent.infoHash + ".resume");
            var data = alert.torrent.metadata();

            if(data) {
                var metadataFile = fs.combine(torrentsPath, alert.torrent.infoHash + ".metadata");
                fs.writeText(metadataFile, JSON.stringify(data));
            }

            fs.writeBuffer(resumeFile, buffer);
            logger.info("Saved resume data for '" + alert.torrent.getTorrentInfo().name + "'");
        }
    }
}

function saveConfig() {
    // This will move the hadouken.json file we loaded *this*
    // session to hadouken.json.old, and save our current config
    // as hadouken.json. Safeguarding against failures.

    if(fs.fileExists(__CONFIG__)) {
        var old = fs.combine(__CONFIG_PATH__, "hadouken.json.old");
        fs.rename(__CONFIG__, old);
        logger.info("Configuration backed up.");
    }

    var data = JSON.stringify(config.get(), null, "  ");
    fs.writeText(__CONFIG__, data);
}

function unload() {
    rss.unload();

    saveState();
    saveTorrents();
    saveConfig();
}

exports.load = load;
exports.unload = unload;
<commit_msg>Fix seed ratio by removing seedOverride check<commit_after>var bt       = require("bittorrent");
var benc     = require("benc");
var config   = require("config");
var fs       = require("fs");
var logger   = require("logger").get("core");
var rss      = require("rss");
var session  = bt.session;
var timer    = require("timer");

function saveTorrent(torrent) {
    var torrentsPath = getTorrentsPath();
    var file         = fs.combine(torrentsPath, torrent.infoHash + ".torrent");

    if(fs.fileExists(file)) {
        return;
    }

    var info = torrent.getTorrentInfo();

    if(!info) {
        return;
    }

    var creator = new bt.TorrentCreator(info);
    var entry   = creator.generate();
    var buffer  = benc.encode(entry);

    // Save the actual metadata
    fs.writeBuffer(file, buffer);
    logger.info("Saved torrent file for '" + info.name + "' to " + file);
}

session.on("torrent.removed", function(e) {
    var torrentsPath = getTorrentsPath();

    var torrentFile  = fs.combine(torrentsPath, e.infoHash + ".torrent");
    var resumeFile   = fs.combine(torrentsPath, e.infoHash + ".resume");
    var metadataFile = fs.combine(torrentsPath, e.infoHash + ".metadata");

    if(fs.fileExists(torrentFile)) {
        fs.deleteFile(torrentFile);
    }

    if(fs.fileExists(resumeFile)) {
        fs.deleteFile(resumeFile);
    }

    if(fs.fileExists(metadataFile)) {
        fs.deleteFile(metadataFile);
    }
});

session.on("torrent.metadataReceived", function(e) {
    if(!e.torrent.isValid) {
        logger.error("Received metadata for an invalid torrent.");
        return;
    }

    saveTorrent(e.torrent);
});

session.on("torrent.add", function(e) {
    if(e.error) {
        logger.error("Could not add torrent (code " + e.error.code + "): " +
                     e.error.message);
        return;
    }

    // Add any metadata to the torrent
    var metadata = e.params.metadata || {};

    if(!metadata["options"]) {
        // Add any default options to the metadata
        var defaultOptions = config.get("bittorrent.defaultOptions") || {};

        var options = {
            seedRatio: (defaultOptions["seedRatio"] || 2.0),
            seedTime: (defaultOptions["seedTime"] || 0),
            seedAction: (defaultOptions["seedAction"] || "pause")
        };

        metadata["options"] = options;

        logger.debug("Torrent '' assigned Seed Ratio: " + options.seedRatio + "%, Seed Time: " + options.seedTime + "minutes , Seed Action: " + options.seedAction);
    }

    var keys = Object.keys(metadata);

    for(var i = 0; i < keys.length; i++) {
        e.torrent.metadata(keys[i], metadata[keys[i]]);
    }
});

session.on("torrent.added", function(e) {
    if(!e.torrent.isValid) {
        logger.error("Invalid torrent added.");
        return;
    }

    saveTorrent(e.torrent);
});

session.on("torrent.checked", function(e) {
    var torrent = e.torrent;

    if(torrent.metadata("_pauseAfterRecheck")) {
        torrent.pause();
        torrent.metadata("_pauseAfterRecheck", false);
    }

    logger.debug("Torrent '" + e.torrent.infoHash + "' hash checked.");
});

session.on("torrent.hashUpdated", function(e) {
    /*
    On migrating metadata
    ---------------------
    When we add a torrent URL (with eg. tags), the info hash
    is not known at the time. We store each metadata object
    in a std::map keyed by the info hash.

    When libtorrent receives the torrent file and gets the correct
    info hash, it sends us this alert.

    We have a special key handler for "_migrate" which takes the
    old info hash as a value, and then moves the metadata from
    the old info hash to the new info hash.

    It is a bit of a hack, but works.
    */

    e.torrent.metadata("_migrate", e.oldInfoHash);
});

session.on("torrent.stateUpdate", function(e) {
    for(var i = 0; i < e.status.length; i++) {
        var status = e.status[i];

        // Only check our seed goal if the torrent is finished
        // and not paused.
        if(!status.isFinished || status.isPaused) {
            return;
        }

        var torrent = status.torrent;
        var options = torrent.metadata("options") || {};

        var goalRatio = options.seedRatio || 2.0;
        var goalTime  = options.goalTime || 0;

        if(status.ratio >= parseFloat(goalRatio)
            || (goalTime > 0 && status.seedingTime > goalTime)) {

            logger.info("Torrent '" + status.name + "' reached its seed goal of " + (status.ratio >= parseFloat(goalRatio) ? (goalRatio + "%") : (goalTime + "minutes")));

            var action = (options.seedAction || "pause");

            switch(action) {
                case "pause":
                    torrent.autoManaged = false;
                    torrent.pause();
                    break;

                case "remove":
                    session.removeTorrent(torrent);
                    break;
            }
        }
    }
});

function getTorrentsPath() {
    var statePath = config.getString("bittorrent.statePath") || "state";
    var torrentsPath = fs.combine(statePath, "torrents");

    if(!fs.directoryExists(torrentsPath)) {
        fs.createDirectories(torrentsPath);
    }

    return torrentsPath;
}

function loadState() {
    var statePath = config.getString("bittorrent.statePath") || "state";

    if(!fs.directoryExists(statePath)) {
        logger.info("Creating state path: " + statePath);
        fs.createDirectories(statePath);
    }

    var stateFile = fs.combine(statePath, ".session_state");

    if(!fs.fileExists(stateFile)) {
        logger.info("No previous session state to load.");
        return;
    }

    var data = fs.readBuffer(stateFile);
    var decoded = benc.decode(data);

    // load session state
    session.loadState(decoded);
    logger.info("Loaded session state from '" + stateFile + "'");
}

function loadTorrents() {
    var torrentsPath = getTorrentsPath();
    var files = fs.getFiles(torrentsPath);

    for(var i = 0; i < files.length; i++) {
        var file = files[i];
        if(!file.endsWith(".torrent")) { continue; }

        var params = bt.AddTorrentParams.getDefault();
        params.torrent = new bt.TorrentInfo(file);

        // Load metadata file
        var metadataFile = file.replace(/\.torrent/i, ".metadata");

        if(fs.fileExists(metadataFile)) {
            var data = fs.readText(metadataFile);
            params.metadata = JSON.parse(data);
        }

        // Load resume file
        var resumeFile = file.replace(/\.torrent$/i, ".resume");

        if(fs.fileExists(resumeFile)) {
            params.resumeData = fs.readBuffer(resumeFile);
        }

        session.addTorrent(params);
        logger.info("Torrent '" + params.torrent.name + "' added.");
    }
}

function load() {
    // Set up listen port for BitTorrent communication
    var listenPort = (config.get("bittorrent.listenPort") || 6881);
    if(isNaN(listenPort)) {
        logger.warn("Invalid listen port specified. Using default (6881).");
        listenPort = 6881;
    }

    session.listenOn([listenPort, listenPort]);

    // Load country database
    var geoIp = config.getString("bittorrent.geoIpFile");

    if(geoIp) {
        logger.info("Loading GeoIP database " + geoIp);
        session.loadCountryDb(geoIp);
    }

    // Add DHT routers.
    var routers = config.get("bittorrent.dht.routers") || [];
    for(var i = 0; i < routers.length; i++) {
        session.addDhtRouter(routers[i][0], routers[i][1]);
    }

    // Enable DHT
    if(config.get("bittorrent.dht.enabled")) {
        logger.info("Enabling DHT.");
        session.startDht();
    }

    // Enable LSD
    if(config.get("bittorrent.lsd.enabled")) {
        logger.info("Enabling LSD.");
        session.startLsd();
    }

    // Enable NatPmp
    if(config.get("bittorrent.natpmp.enabled")) {
        logger.info("Enabling NATPMP.");
        session.startNatPmp();
    }

    // Enable UPnP
    if(config.get("bittorrent.upnp.enabled")) {
        logger.info("Enabling UPnP.");
        session.startUpnp();
    }

    // Load session settings
    var settings = session.getSettings();
    settings.connectionsLimit = (config.get("bittorrent.connectionsLimit") || settings.connectionsLimit);
    settings.downloadRateLimit = (config.get("bittorrent.downloadRateLimit") || settings.downloadRateLimit);
    settings.mixedModeAlgorithm = (config.get("bittorrent.mixedModeAlgorithm") || settings.mixedModeAlgorithm);
    settings.rateLimitIpOverhead = (config.get("bittorrent.rateLimitIpOverhead") || settings.rateLimitIpOverhead);
    settings.rateLimitUtp = (config.get("bittorrent.rateLimitUtp") || settings.rateLimitUtp);
    settings.uploadRateLimit = (config.get("bittorrent.uploadRateLimit") || settings.uploadRateLimit);

    // Advanced settings
    var allowMultipleConnectionsPerIp = config.get("bittorrent.allowMultipleConnectionsPerIp");
    if(typeof allowMultipleConnectionsPerIp !== "undefined") { settings.allowMultipleConnectionsPerIp = allowMultipleConnectionsPerIp; }

    var anonymousMode = config.get("bittorrent.anonymousMode");
    if(typeof anonymousMode !== "undefined") { settings.anonymousMode = anonymousMode; }

    var enableUtp = config.get("bittorrent.utp.enabled");
    if(typeof enableUtp !== "undefined") { enableUtp = true; }
    settings.enableOutgoingUtp = enableUtp;
    settings.enableIncomingUtp = enableUtp;

    settings.halfOpenLimit = (config.get("bittorrent.halfOpenLimit") || settings.halfOpenLimit);

    session.setSettings(settings);

    logger.info("Loaded session settings.");

    loadState();
    loadTorrents();

    rss.load();
    require("plugins").load();

    // Post torrent updates each tick of the timer.
    timer.tick(function() { session.postTorrentUpdates(); });
}

function saveState() {
    var statePath = config.getString("bittorrent.statePath") || "state";
    var stateFile = fs.combine(statePath, ".session_state");

    var entry  = session.saveState();
    var buffer = benc.encode(entry);

    fs.writeBuffer(stateFile, buffer);
    logger.info("Saved session state to '" + stateFile + "'");
}

function saveTorrents() {
    session.pause();

    var torrentsPath = getTorrentsPath();
    var num          = 0;
    var torrents     = session.getTorrents();

    for(var i = 0; i < torrents.length; i++) {
        var t = torrents[i];
        if(!t.isValid) { continue; }

        var s = t.getStatus();

        if(!s.hasMetadata) { continue; }
        if(!s.needSaveResume) { continue; }

        num += 1;
        t.saveResumeData();
    }

    logger.info("Saving resume data for " + num + " torrent(s)");

    while(num > 0) {
        var a = session.waitForAlert(10 * 1000);
        if(!a) { continue; }

        var alerts = session.getAlerts();

        for(var i = 0; i < alerts.length; i++) {
            var alert = alerts[i];

            if(alert == null) {
                continue;
            }

            if(alert.name === "torrent_paused_alert") {
                continue;
            }

            if(alert.name === "save_resume_data_failed_alert") {
                num -= 1;
                continue;
            }

            if(alert.name !== "save_resume_data_alert") {
                continue;
            }

            num -= 1;

            if(!alert.resumeData) {
                logger.info("No resume data for torrent.");
                continue;
            }

            var buffer = benc.encode(alert.resumeData);
            var resumeFile = fs.combine(torrentsPath, alert.torrent.infoHash + ".resume");
            var data = alert.torrent.metadata();

            if(data) {
                var metadataFile = fs.combine(torrentsPath, alert.torrent.infoHash + ".metadata");
                fs.writeText(metadataFile, JSON.stringify(data));
            }

            fs.writeBuffer(resumeFile, buffer);
            logger.info("Saved resume data for '" + alert.torrent.getTorrentInfo().name + "'");
        }
    }
}

function saveConfig() {
    // This will move the hadouken.json file we loaded *this*
    // session to hadouken.json.old, and save our current config
    // as hadouken.json. Safeguarding against failures.

    if(fs.fileExists(__CONFIG__)) {
        var old = fs.combine(__CONFIG_PATH__, "hadouken.json.old");
        fs.rename(__CONFIG__, old);
        logger.info("Configuration backed up.");
    }

    var data = JSON.stringify(config.get(), null, "  ");
    fs.writeText(__CONFIG__, data);
}

function unload() {
    rss.unload();

    saveState();
    saveTorrents();
    saveConfig();
}

exports.load = load;
exports.unload = unload;
<|endoftext|>


<commit_before>var ds = window.ds || {}
ds.models = ds.models || {}
ds.models.data = ds.models.data || {}
ds.models.transform = ds.models.transform || {}
ds.edit = ds.edit || {}
ds.edit.properties = ds.edit.properties || {}
ds.templates = ds.templates || {}
ds.templates.edit = ds.templates.edit || {}
ds.templates.edit.properties = ds.templates.edit.properties || {}

/**
 * Helper function to (potentially) render a template with a given
 * context object. If the string does not contain any handlebars tags,
 * it will be returned as-is.
 */
ds.render_template = function(str, context) {
  if (str == null) {
    return str
  }
  if (str.indexOf('{{') == -1) {
    return str
  } else {
    var template = Handlebars.compile(str)
    return template(context)
  }
}

/**
 * Yo dawg, I heard you like objects, so I put some objects in your
 * objects...
 */
ds.extend = function() {
  var target = {}
  for (var i in arguments) {
    var source = arguments[i]
    for (var key in source) {
      if (source.hasOwnProperty(key)) {
        target[key] = source[key]
      }
    }
  }
  return target
}
<commit_msg>remove some namespace decls we don't need anymore<commit_after>var ds = window.ds || {}
ds.models = ds.models || {}
ds.models.data = ds.models.data || {}
ds.models.transform = ds.models.transform || {}
ds.edit = ds.edit || {}
ds.edit.properties = ds.edit.properties || {}

/**
 * Helper function to (potentially) render a template with a given
 * context object. If the string does not contain any handlebars tags,
 * it will be returned as-is.
 */
ds.render_template = function(str, context) {
  if (str == null) {
    return str
  }
  if (str.indexOf('{{') == -1) {
    return str
  } else {
    var template = Handlebars.compile(str)
    return template(context)
  }
}

/**
 * Yo dawg, I heard you like objects, so I put some objects in your
 * objects...
 */
ds.extend = function() {
  var target = {}
  for (var i in arguments) {
    var source = arguments[i]
    for (var key in source) {
      if (source.hasOwnProperty(key)) {
        target[key] = source[key]
      }
    }
  }
  return target
}
<|endoftext|>


<commit_before>var ds = window.ds || {};
ds.models = ds.models || {};

ds.render_template = function(str, context) {
  if (str == null) {
    return str;
  }
  if (str.indexOf('{{') == -1) {
    return str;
  } else {
    var template = Handlebars.compile(str);
    return template(context);
  }
}

ds.rebind_properties = function(target, source) {
  var i = 1,
      n = arguments.length,
      property;
  while (++i < n) {
    var name = arguments[i];
    ds_rebind_property(target, source, name);
  }
}

function ds_rebind_property(target, source, name) {
  Object.defineProperty(target, name, {
    get: function() {
      return source[name];
    }
  });
}
<commit_msg>Initialize ds.models.data<commit_after>var ds = window.ds || {};
ds.models = ds.models || {};
ds.models.data = ds.models.data || {};

ds.render_template = function(str, context) {
  if (str == null) {
    return str;
  }
  if (str.indexOf('{{') == -1) {
    return str;
  } else {
    var template = Handlebars.compile(str);
    return template(context);
  }
}

ds.rebind_properties = function(target, source) {
  var i = 1,
      n = arguments.length,
      property;
  while (++i < n) {
    var name = arguments[i];
    ds_rebind_property(target, source, name);
  }
}

function ds_rebind_property(target, source, name) {
  Object.defineProperty(target, name, {
    get: function() {
      return source[name];
    }
  });
}
<|endoftext|>


<commit_before>const _ = require('lodash');
const qs = require('query-string');
const mustache = require('mustache');
const messages = require('./messages');

const handleError = (err) => {
    console.error(JSON.stringify(err.originalError.response.data));
}

const MOVIE_DETAIL_TEMPLATE = `{{title_long}}
Casts : {{casts}}
Rating : {{rating}}

{{description_full}}
`;

const MOVIE_MORE_TEXT = `{{year}}
{{genres}}
{{mpa_rating}}`

class Handler {
    constructor(lineClient, ytsClient) {
        this.lineClient = lineClient;
        this.ytsClient = ytsClient;
    }

    handleRequest(payload) {
        payload.events.forEach(event => {
            this.handleEvent(event);
        });
    }

    handleEvent(event) {
        const type = event.type;
        switch (type) {
            case 'message':
                this.handleMessageEvent(event);
                break;

            case 'postback':
                this.handlePostbackEvent(event);
                break;

            default:
                console.log(`Unknown type ${type}`);
                break;
        }
    }

    handleMessageEvent(event) {
        const type = event.message.type;
        switch (type) {
            case 'text':
                this.handleTextMessage(event.replyToken, event.source, event.message.text);
                break;

            default:
                console.log(`unhandled message type ${type}`);
                break;
        }
    }

    handleTextMessage(replyToken, source, text) {
        const token = text.split(' ');
        const keyword = token[0].toLowerCase();
        const term = token.slice(1, token.length).join(' ');
        switch (keyword) {
            case 'search':
                this.ytsClient.searchMovie(term)
                    .then(result => {
                        if (result.movie_count == 0) {
                            return this.lineClient.replyMessage(replyToken, {
                                type: 'text',
                                text: `Sorry, ${term} is not found on our database`,
                            })
                            .catch(handleError)
                        };

                        const carrouselMessage = result.movies.map(movie => {
                            const actions = [
                                {
                                    type: 'uri',
                                    label: 'Watch Trailer',
                                    uri: `https://www.youtube.com/watch?v=${movie.yt_trailer_code}`
                                },
                                {
                                    type: 'postback',
                                    label: 'Details',
                                    data: qs.stringify({
                                        keyword: 'movie-detail',
                                        data: {
                                            movieId: movie.id
                                        }
                                    })
                                }
                            ]
                            return {
                                thumbnailImageUrl: movie.large_cover_image,
                                title: movie.title,
                                text: _.truncate(movie.summary, {length: 50, separator: /\W/}),
                                actions,
                            }
                        });

                        const message = {
                            type: 'template',
                            altText: `Search result for ${term}`,
                            template: {
                                type: 'carousel',
                                columns: carrouselMessage
                            }
                        };

                        return this.lineClient.replyMessage(replyToken, message).catch(err => {

                        })
                    })
                    .catch(handleError);
                break;
            default:
                console.log(`unknown keyword ${keyword}`);
                break;
        }
    }

    handlePostbackEvent(event) {
        const postbackData = event.postback.data;
        this.handlePostback(event.replyToken, event.source, postbackData);
    }

    handlePostback(replyToken, source, data) {
        const parsedData = qs.parse(data);
        console.log(parsedData);
        switch (parsedData.keyword) {
            case 'movie-detail':
                this.ytsClient.getMovie(parsedData.data.movieId)
                    .then(result => {
                        const movie = result.movie;
                        const movieImageMessage = messages.imageMessage(movie.large_cover_image, movie.small_cover_image);
                        const movieDetailTextMessage = messages.textMessage(mustache.render(MOVIE_DETAIL_TEMPLATE, {
                            title_long: movie.title_long,
                            casts: (movie.cast || []).map(cast => cast.name).join(', '),
                            rating: movie.rating,
                            description_full: movie.description_full
                        }));
                        const watchAction = messages.actionUriTemplate("Watch Now", movie.url);
                        const similarAction = messages.actionPostbackTemplate("Simillar", qs.stringify({
                            keyword: 'suggestion',
                            data: {
                                movieId: movie.id,
                            },
                        }));
                        const buttonMessage = messages.buttonTemplate(undefined, movie.title, mustache.render(MOVIE_MORE_TEXT, {
                            year: movie.year,
                            genres: (movie.genres || []).join(', '),
                            mpa_rating: movie.mpa_rating
                        }), [watchAction, similarAction]);

                        this.lineClient.replyMessage(replyToken, [movieImageMessage, movieDetailTextMessage, buttonMessage]);
                    })
                    .catch(handleError)
                break;

            default:
                break;
        }
    }
}

module.exports = Handler;<commit_msg>postback detail data<commit_after>const _ = require('lodash');
const qs = require('query-string');
const mustache = require('mustache');
const messages = require('./messages');

const handleError = (err) => {
    console.error(JSON.stringify(err.originalError.response.data));
}

const MOVIE_DETAIL_TEMPLATE = `{{title_long}}
Casts : {{casts}}
Rating : {{rating}}

{{description_full}}
`;

const MOVIE_MORE_TEXT = `{{year}}
{{genres}}
{{mpa_rating}}`

class Handler {
    constructor(lineClient, ytsClient) {
        this.lineClient = lineClient;
        this.ytsClient = ytsClient;
    }

    handleRequest(payload) {
        payload.events.forEach(event => {
            this.handleEvent(event);
        });
    }

    handleEvent(event) {
        const type = event.type;
        switch (type) {
            case 'message':
                this.handleMessageEvent(event);
                break;

            case 'postback':
                this.handlePostbackEvent(event);
                break;

            default:
                console.log(`Unknown type ${type}`);
                break;
        }
    }

    handleMessageEvent(event) {
        const type = event.message.type;
        switch (type) {
            case 'text':
                this.handleTextMessage(event.replyToken, event.source, event.message.text);
                break;

            default:
                console.log(`unhandled message type ${type}`);
                break;
        }
    }

    handleTextMessage(replyToken, source, text) {
        const token = text.split(' ');
        const keyword = token[0].toLowerCase();
        const term = token.slice(1, token.length).join(' ');
        switch (keyword) {
            case 'search':
                this.ytsClient.searchMovie(term)
                    .then(result => {
                        if (result.movie_count == 0) {
                            return this.lineClient.replyMessage(replyToken, {
                                type: 'text',
                                text: `Sorry, ${term} is not found on our database`,
                            })
                            .catch(handleError)
                        };

                        const carrouselMessage = result.movies.map(movie => {
                            const actions = [
                                {
                                    type: 'uri',
                                    label: 'Watch Trailer',
                                    uri: `https://www.youtube.com/watch?v=${movie.yt_trailer_code}`
                                },
                                {
                                    type: 'postback',
                                    label: 'Details',
                                    data: qs.stringify({
                                        keyword: 'movie-detail',
                                        data: {
                                            movieId: movie.id
                                        }
                                    })
                                }
                            ]
                            return {
                                thumbnailImageUrl: movie.large_cover_image,
                                title: movie.title,
                                text: _.truncate(movie.summary, {length: 50, separator: /\W/}),
                                actions,
                            }
                        });

                        const message = {
                            type: 'template',
                            altText: `Search result for ${term}`,
                            template: {
                                type: 'carousel',
                                columns: carrouselMessage
                            }
                        };

                        return this.lineClient.replyMessage(replyToken, message).catch(err => {

                        })
                    })
                    .catch(handleError);
                break;
            default:
                console.log(`unknown keyword ${keyword}`);
                break;
        }
    }

    handlePostbackEvent(event) {
        const postbackData = event.postback.data;
        this.handlePostback(event.replyToken, event.source, postbackData);
    }

    handlePostback(replyToken, source, data) {
        const parsedData = qs.parse(data);
        switch (parsedData.keyword) {
            case 'movie-detail':
                console.log(parsedData.data);
                this.ytsClient.getMovie(parsedData.data.movieId)
                    .then(result => {
                        const movie = result.movie;
                        const movieImageMessage = messages.imageMessage(movie.large_cover_image, movie.small_cover_image);
                        const movieDetailTextMessage = messages.textMessage(mustache.render(MOVIE_DETAIL_TEMPLATE, {
                            title_long: movie.title_long,
                            casts: (movie.cast || []).map(cast => cast.name).join(', '),
                            rating: movie.rating,
                            description_full: movie.description_full
                        }));
                        const watchAction = messages.actionUriTemplate("Watch Now", movie.url);
                        const similarAction = messages.actionPostbackTemplate("Simillar", qs.stringify({
                            keyword: 'suggestion',
                            data: {
                                movieId: movie.id,
                            },
                        }));
                        const buttonMessage = messages.buttonTemplate(undefined, movie.title, mustache.render(MOVIE_MORE_TEXT, {
                            year: movie.year,
                            genres: (movie.genres || []).join(', '),
                            mpa_rating: movie.mpa_rating
                        }), [watchAction, similarAction]);

                        this.lineClient.replyMessage(replyToken, [movieImageMessage, movieDetailTextMessage, buttonMessage]);
                    })
                    .catch(handleError)
                break;

            default:
                break;
        }
    }
}

module.exports = Handler;<|endoftext|>


<commit_before>
// sfw_calendar.js

(function _init()
{
   if ((!("SFW" in window) && setTimeout(_init,100))
       || SFW.delay_init("sfw_calendar",_init, "table"))
      return;

   if (!SFW.derive(_calendar, "calendar", "table"))
      return;

   function _calendar(base, doc, caller, data)
   {
      SFW.types["table"].call(this,base,doc,caller,data);
   }

   _calendar.prototype.child_finished = function(child, cancelled)
   {
      SFW.base.prototype.child_finished.call(this, child, cancelled);
      this.replot();
   };

   _calendar.prototype.process_day_click = function(t, did)
   {
      var url = this.get_data_value("on_day_click");
      if (url)
      {
         url += "=" + did;
         empty_el(this.host());
         SFW.open_interaction(SFW.stage, url, this, {caldoc:this.xmldoc(),did:did});
      }
   };

   _calendar.prototype.process_month_jump = function(month)
   {
      var url = SFW.update_location_arg("mdate", month);
      if (url)
         window.location = url;

      return false;
   };

   _calendar.prototype.process = function (e,t)
   {
      var did, tag, mon, top = this.top();

      if (e.type!="click")
         return true;

      // Don't disturb the arguments array:
      var tel = t;
      while (tel && tel!=top)
      {
         if (tel.nodeType==1 && (tag=tel.tagName.toLowerCase()))
         {
            if (tag=="td" && (did=tel.getAttribute("data-date")))
               return this.process_day_click(tel, did);
            if (tag=="button" && (mon=tel.getAttribute("data-jump")))
               return this.process_month_jump(mon);
         }

         tel = tel.parentNode;
      }

      return this.call_super_event("table", "process", arguments);
   };

})();
<commit_msg>Changed the how the calendar constructor calls its base class constructor.<commit_after>
// sfw_calendar.js

(function _init()
{
   if ((!("SFW" in window) && setTimeout(_init,100))
       || SFW.delay_init("sfw_calendar",_init, "table"))
      return;

   if (!SFW.derive(_calendar, "calendar", "table"))
      return;

   function _calendar(base, doc, caller, data)
   {
      SFW.types["table"].call(this,base,doc,caller,data);
   }

   _calendar.prototype.child_finished = function(child, cancelled)
   {
      SFW.types["table"].prototype.child_finished.call(this,child,cancelled);
      this.replot();
   };

   _calendar.prototype.process_day_click = function(t, did)
   {
      var url = this.get_data_value("on_day_click");
      if (url)
      {
         url += "=" + did;
         empty_el(this.host());
         SFW.open_interaction(SFW.stage, url, this, {caldoc:this.xmldoc(),did:did});
      }
   };

   _calendar.prototype.process_month_jump = function(month)
   {
      var url = SFW.update_location_arg("mdate", month);
      if (url)
         window.location = url;

      return false;
   };

   _calendar.prototype.process = function (e,t)
   {
      var did, tag, mon, top = this.top();

      if (e.type!="click")
         return true;

      // Don't disturb the arguments array:
      var tel = t;
      while (tel && tel!=top)
      {
         if (tel.nodeType==1 && (tag=tel.tagName.toLowerCase()))
         {
            if (tag=="td" && (did=tel.getAttribute("data-date")))
               return this.process_day_click(tel, did);
            if (tag=="button" && (mon=tel.getAttribute("data-jump")))
               return this.process_month_jump(mon);
         }

         tel = tel.parentNode;
      }

      return this.call_super_event("table", "process", arguments);
   };

})();
<|endoftext|>


<commit_before>'use strict';

function button_click(button_id){
    if(core_menu_open){
        return;
    }

    // Set button color and value.
    let element = document.getElementById(button_id);
    element.style.background = colors[button_values[button_id]];
    element.value = core_storage_data['display'][button_values[button_id]];

    let loop_counter = 19;
    // If this is first button of button pair.
    if(selected_button[0] === -1){
        // Reset other buttons that haven't been matched yet.
        do{
            if(button_values[loop_counter] > -1
              && loop_counter !== button_id){
                element = document.getElementById(loop_counter);
                element.style.background = colors['default'];
                element.value = ' ';
            }
        }while(loop_counter--);

        // Store button information.
        selected_button = [
          button_values[button_id],
          button_id,
        ];

        // Disable this button to prevent reclicks.
        document.getElementById(button_id).disabled = true;

        return;
    }

    element = document.getElementById('attempted-matches');
    element.innerHTML = Number.parseInt(
      element.innerHTML,
      10
    ) + 1;

    // If value of this button matches the value of the previously selected button.
    if(selected_button[0] === button_values[button_id]){
        // Set button values to -1 to prevent them from being reset.
        button_values[button_id] = -1;
        button_values[selected_button[1]] = -1;

        audio_start({
          'id': 'boop',
        });
    }

    // Check if there are any enabled buttons left.
    let buttons_remain = false;
    do{
        let disabled = button_values[loop_counter] < 0;
        document.getElementById(loop_counter).disabled = disabled;

        if(!disabled){
            buttons_remain = true;
        }
    }while(loop_counter--);

    selected_button = [
      -1,
      -1,
    ];

    // If not, end game.
    if(!buttons_remain){
        stop();
    }
}

function decisecond(){
    if(core_mode === 0){
        stop();
        return;
    }

    time = core_round({
      'decimals': 1,
      'number': Number.parseFloat(time) + .1,
    });
    core_elements['time'].innerHTML = time;
}

function start(){
    document.getElementById('attempted-matches').innerHTML = 0;

    // Generate button pairs.
    let loop_counter = 19;
    let tempinfo = [
      -1,-1,-1,-1,-1,
      -1,-1,-1,-1,-1,
      -1,-1,-1,-1,-1,
      -1,-1,-1,-1,-1,
    ];
    let temp = 0;
    do{
        let element = document.getElementById(loop_counter);
        element.disabled = false;
        element.style.background = colors['default'];
        element.value = ' ';

        do{
            temp = core_random_integer({
              'max': 20,
            });
        }while(tempinfo[temp] != -1);

        tempinfo[temp] = Math.floor(temp / 2);
        button_values[loop_counter] = Math.floor(temp / 2);
    }while(loop_counter--);

    time = 0;
    core_elements['time'].innerHTML = time;

    core_mode = 1;
    core_interval_modify({
      'id': 'interval',
      'interval': 100,
      'todo': decisecond,
    });
}

function stop(){
    core_interval_pause_all();
    core_mode = 0;

    // Disable all game-div buttons.
    let loop_counter = 19;
    do{
        document.getElementById(loop_counter).disabled = true;
    }while(loop_counter--);

    // Blank out button values.
    button_values = [
      -1,-1,-1,-1,-1,
      -1,-1,-1,-1,-1,
      -1,-1,-1,-1,-1,
      -1,-1,-1,-1,-1,
    ];
    selected_button = [
      -1,
      -1,
    ];
}
<commit_msg>added core_number_format() usage<commit_after>'use strict';

function button_click(button_id){
    if(core_menu_open){
        return;
    }

    // Set button color and value.
    let element = document.getElementById(button_id);
    element.style.background = colors[button_values[button_id]];
    element.value = core_storage_data['display'][button_values[button_id]];

    let loop_counter = 19;
    // If this is first button of button pair.
    if(selected_button[0] === -1){
        // Reset other buttons that haven't been matched yet.
        do{
            if(button_values[loop_counter] > -1
              && loop_counter !== button_id){
                element = document.getElementById(loop_counter);
                element.style.background = colors['default'];
                element.value = ' ';
            }
        }while(loop_counter--);

        // Store button information.
        selected_button = [
          button_values[button_id],
          button_id,
        ];

        // Disable this button to prevent reclicks.
        document.getElementById(button_id).disabled = true;

        return;
    }

    element = document.getElementById('attempted-matches');
    element.innerHTML = Number.parseInt(
      element.innerHTML,
      10
    ) + 1;

    // If value of this button matches the value of the previously selected button.
    if(selected_button[0] === button_values[button_id]){
        // Set button values to -1 to prevent them from being reset.
        button_values[button_id] = -1;
        button_values[selected_button[1]] = -1;

        audio_start({
          'id': 'boop',
        });
    }

    // Check if there are any enabled buttons left.
    let buttons_remain = false;
    do{
        let disabled = button_values[loop_counter] < 0;
        document.getElementById(loop_counter).disabled = disabled;

        if(!disabled){
            buttons_remain = true;
        }
    }while(loop_counter--);

    selected_button = [
      -1,
      -1,
    ];

    // If not, end game.
    if(!buttons_remain){
        stop();
    }
}

function decisecond(){
    if(core_mode === 0){
        stop();
        return;
    }

    time = core_round({
      'decimals': 1,
      'number': Number.parseFloat(time) + .1,
    });
    core_elements['time'].innerHTML = core_number_format({
      'decimals-min': 1,
      'number': time,
    });
}

function start(){
    document.getElementById('attempted-matches').innerHTML = 0;

    // Generate button pairs.
    let loop_counter = 19;
    let tempinfo = [
      -1,-1,-1,-1,-1,
      -1,-1,-1,-1,-1,
      -1,-1,-1,-1,-1,
      -1,-1,-1,-1,-1,
    ];
    let temp = 0;
    do{
        let element = document.getElementById(loop_counter);
        element.disabled = false;
        element.style.background = colors['default'];
        element.value = ' ';

        do{
            temp = core_random_integer({
              'max': 20,
            });
        }while(tempinfo[temp] != -1);

        tempinfo[temp] = Math.floor(temp / 2);
        button_values[loop_counter] = Math.floor(temp / 2);
    }while(loop_counter--);

    time = 0;
    core_elements['time'].innerHTML = time;

    core_mode = 1;
    core_interval_modify({
      'id': 'interval',
      'interval': 100,
      'todo': decisecond,
    });
}

function stop(){
    core_interval_pause_all();
    core_mode = 0;

    // Disable all game-div buttons.
    let loop_counter = 19;
    do{
        document.getElementById(loop_counter).disabled = true;
    }while(loop_counter--);

    // Blank out button values.
    button_values = [
      -1,-1,-1,-1,-1,
      -1,-1,-1,-1,-1,
      -1,-1,-1,-1,-1,
      -1,-1,-1,-1,-1,
    ];
    selected_button = [
      -1,
      -1,
    ];
}
<|endoftext|>


<commit_before>'use strict';

// Required args: type
function alter_workers(args){
    args = core_args({
      'args': args,
      'defaults': {
        'amount': 1,
      },
    });

    if(daylight_passed > 0
      || args['amount'] > resources['people']['unemployed']){
        return;
    }

    if(resources[args['type']]['workers'] > 0
      || args['amount'] > 0){
        const multiplier = resource_defaults[args['type']]['multiplier'] || 1;

        resources['people']['unemployed'] -= args['amount'];
        resources[args['type']]['bonus'] += args['amount'] * multiplier;
        resources[args['type']]['workers'] += args['amount'];

    }else{
        resources[args['type']]['workers'] = 0;
    }

    document.getElementById(args['type'] + '-bonus').textContent =
      (resources[args['type']]['bonus'] > 0 ? '+' : '') + resources[args['type']]['bonus'];
    document.getElementById(args['type'] + '-workers').textContent = resources[args['type']]['workers'];

    document.getElementById('unemployed-workers').textContent = resources['people']['unemployed'];
}

function day(){
    core_storage_save();

    if(daylight_passed < core_storage_data['day-events']){
        if(daylight_passed === 0){
            document.getElementById('day').textContent = '';
            document.getElementById('start-day').textContent = '';
        }

        let output = '';

        const event = Math.random();
        let event_result = 0;

        // No event.
        if(event < .72){
            output = '-----';

        // Food event.
        }else if(event < .78){
            event_result = core_random_integer({
              'max': 2,
            }) + 1;

            if(core_random_boolean()){
                resources['food']['amount'] -= event_result;

                if(resources['food']['amount'] < 0){
                    resources['gold']['amount'] += resources['food']['amount'] * 2;
                    resources['food']['amount'] = 0;
                }

                output = 'Bugs! -';

            }else{
                resources['food']['amount'] += event_result;
                output = 'Rain! +';
            }
            output += event_result + ' Food';

        // Gold event.
        }else if(event < .84){
            event_result = core_random_integer({
              'max': 2,
            }) + 1;

            if(core_random_boolean()){
                resources['gold']['amount'] -= event_result;
                output = 'Thieves! -';

            }else{
                resources['gold']['amount'] += event_result;
                output = 'Mining! +';
            }

            output += event_result + ' Gold';

        // Stone event.
        }else if(event < .9){
            event_result = core_random_integer({
              'max': 2,
            }) + 1;

            if(core_random_boolean()){
                resources['stone']['amount'] -= event_result;

                if(resources['stone']['amount'] < 0){
                    resources['gold']['amount'] += resources['stone']['amount'] * 2;
                    resources['gold']['stone'] = 0;
                }

                output = 'Repair! -';

            }else{
                resources['stone']['amount'] += event_result;
                output = 'Mining! +';
            }
            output += event_result + ' Stone';

        // Population event.
        }else if(event < .96){
            if(core_random_boolean()){
                if(resources['people']['amount'] > 0){
                    resources['people']['amount'] -= 1;
                    delete_people(0);
                }
                output = 'Sickness! -';

            }else{
                resources['people']['amount'] += 1;
                resources['people']['unemployed'] += 1;
                output = 'Recruitment! +';
            }

            output += '1 Population';

        // Other events.
        }else if(event < .99){
            event_result = core_random_integer({
              'max': 2,
            });
            if(event_result === 0){
                output = 'Battle Event (NYI)';

            }else{
                output = 'Other Event (NYI)';
            }

        // Daily resource bonus event.
        }else{
            event_result = core_random_integer({
              'max': 4,
            });

            if(event_result === 0){
                output = 'Seeds! +1 Food/day';
                resources['food']['bonus'] += 1;

            }else if(event_result === 1){
                output = 'Veins! +1 Gold/day';
                resources['gold']['bonus'] += 1;

            }else if(event_result === 2){
                output = 'Popularity! +1 Population/day';
                resources['people']['bonus'] += 1;

            }else{
                output = 'Rocks! +1 Stone/day';
                resources['stone']['bonus'] += 1;

            }
        }

        document.getElementById('day').innerHTML += output + '
';
        daylight_passed += 1;

        if(daylight_passed < core_storage_data['day-events']){
            core_interval_modify({
              'clear': 'clearTimeout',
              'id': 'day',
              'interval': core_storage_data['day-event-duration'],
              'set': 'setTimeout',
              'todo': day,
            });
        }
    }

    if(daylight_passed >= core_storage_data['day-events']){
        daylight_passed = 0;

        for(const resource in resources){
            resources[resource]['amount'] += resources[resource]['bonus'];
        }
        resources['people']['unemployed'] += resources['people']['bonus'];

        if(resources['food']['amount'] + resources['food']['bonus'] < 0){
            delete_people(resources['people']['amount'] - 1);
            resources['people']['amount'] -=
              resources['people']['amount']
              - (resources['food']['amount'] + resources['food']['bonus']);

            if(resources['people']['amount'] < 0){
                resources['people']['amount'] = 0;
            }

            resources['food']['amount'] = 0;
            resources['food']['bonus'] = 0;
        }

        document.getElementById('start-day').innerHTML = resources['people']['amount'] > 0
          ? start_new_day
          : 'Your castle has fallen.
<input onclick=new_game() type=button value="Start Over">';
    }

    resources['food']['bonus'] = resources['food']['workers'] * 2 - resources['people']['amount'];

    for(const resource in resources){
        document.getElementById(resource).textContent = resources[resource]['amount'];
        document.getElementById(resource + '-bonus').textContent = (resources[resource]['bonus'] > 0 ? '+' : '') + resources[resource]['bonus'];
    }
    document.getElementById('unemployed-workers').textContent = resources['people']['unemployed'];
}

function delete_people(count){
    do{
        if(resources['people']['unemployed'] > 0){
            resources['people']['unemployed'] -= 1;

        }else if(resources['people']['workers'] > 0){
            resources['people']['bonus'] -= 1;
            resources['people']['workers'] -= 1;

            document.getElementById('people-bonus').textContent = resources['people']['workers'];
            document.getElementById('people-workers').textContent = resources['people']['workers'];

        }else if(resources['stone']['workers'] > 0){
            resources['stone']['bonus'] -= 1;
            resources['stone']['workers'] -= 1;

            document.getElementById('stone-bonus').textContent = resources['stone']['workers'];
            document.getElementById('stone-workers').textContent = resources['stone']['workers'];

        }else if(resources['gold']['workers'] > 0){
            resources['gold']['bonus'] -= 1;
            resources['gold']['workers'] -= 1;

            document.getElementById('gold-bonus').textContent = resources['gold']['workers'];
            document.getElementById('gold-workers').textContent = resources['gold']['workers'];

        }else{
            resources['food']['workers'] -= 1;
            document.getElementById('food-workers').textContent = resources['food']['workers'];
        }
    }while(count--);
}

function new_game(){
    daylight_passed = 0;

    let tbody = '';
    for(const resource in resource_defaults){
        resources[resource] = resources[resource] || {};

        resources[resource]['amount'] = resource_defaults[resource]['amount'] || 0;
        resources[resource]['bonus'] = resource_defaults[resource]['bonus'] || 0;
        resources[resource]['workers'] = resource_defaults[resource]['workers'] || 0;

        tbody += '
' + resource
          + '' + resources[resource]['amount']
          + '' + resources[resource]['bonus']
          + '<input onclick="alter_workers({type:\'' + resource + '\',})" type=button value=+>'
            + ' ' + resources[resource]['workers'] + ' '
            + '<input onclick="alter_workers({amount:-1,type:\'' + resource + '\',})" type=button value=—>';
    }

    resources['people']['unemployed'] = resources['people']['amount'];

    document.getElementById('day').textContent = '';
    document.getElementById('start-day').innerHTML = start_new_day;
    document.getElementById('tbody').innerHTML = tbody;

    document.getElementById('unemployed-workers').textContent = resources['people']['unemployed'];
}
<commit_msg>improved formatting<commit_after>'use strict';

// Required args: type
function alter_workers(args){
    args = core_args({
      'args': args,
      'defaults': {
        'amount': 1,
      },
    });

    if(daylight_passed > 0
      || args['amount'] > resources['people']['unemployed']){
        return;
    }

    if(resources[args['type']]['workers'] > 0
      || args['amount'] > 0){
        const multiplier = resource_defaults[args['type']]['multiplier'] || 1;

        resources['people']['unemployed'] -= args['amount'];
        resources[args['type']]['bonus'] += args['amount'] * multiplier;
        resources[args['type']]['workers'] += args['amount'];

    }else{
        resources[args['type']]['workers'] = 0;
    }

    document.getElementById(args['type'] + '-bonus').textContent =
      (resources[args['type']]['bonus'] > 0 ? '+' : '') + resources[args['type']]['bonus'];
    document.getElementById(args['type'] + '-workers').textContent = resources[args['type']]['workers'];

    document.getElementById('unemployed-workers').textContent = resources['people']['unemployed'];
}

function day(){
    core_storage_save();

    if(daylight_passed < core_storage_data['day-events']){
        if(daylight_passed === 0){
            document.getElementById('day').textContent = '';
            document.getElementById('start-day').textContent = '';
        }

        const event = Math.random();
        let event_result = 0;
        let output = '';

        // No event.
        if(event < .72){
            output = '-----';

        // Food event.
        }else if(event < .78){
            event_result = core_random_integer({
              'max': 2,
            }) + 1;

            if(core_random_boolean()){
                output = 'Bugs! -';
                resources['food']['amount'] -= event_result;

                if(resources['food']['amount'] < 0){
                    resources['gold']['amount'] += resources['food']['amount'] * 2;
                    resources['food']['amount'] = 0;
                }

            }else{
                output = 'Rain! +';
                resources['food']['amount'] += event_result;
            }

            output += event_result + ' Food';

        // Gold event.
        }else if(event < .84){
            event_result = core_random_integer({
              'max': 2,
            }) + 1;

            if(core_random_boolean()){
                output = 'Thieves! -';
                resources['gold']['amount'] -= event_result;

            }else{
                output = 'Mining! +';
                resources['gold']['amount'] += event_result;
            }

            output += event_result + ' Gold';

        // Stone event.
        }else if(event < .9){
            event_result = core_random_integer({
              'max': 2,
            }) + 1;

            if(core_random_boolean()){
                output = 'Repair! -';
                resources['stone']['amount'] -= event_result;

                if(resources['stone']['amount'] < 0){
                    resources['gold']['amount'] += resources['stone']['amount'] * 2;
                    resources['gold']['stone'] = 0;
                }

            }else{
                resources['stone']['amount'] += event_result;
                output = 'Mining! +';
            }

            output += event_result + ' Stone';

        // Population event.
        }else if(event < .96){
            if(core_random_boolean()){
                output = 'Sickness! -';
                if(resources['people']['amount'] > 0){
                    resources['people']['amount'] -= 1;
                    delete_people(0);
                }

            }else{
                output = 'Recruitment! +';
                resources['people']['amount'] += 1;
                resources['people']['unemployed'] += 1;
            }

            output += '1 Population';

        // Other events.
        }else if(event < .99){
            event_result = core_random_integer({
              'max': 2,
            });

            if(event_result === 0){
                output = 'Battle Event (TODO)';

            }else{
                output = 'Other Event (TODO)';
            }

        // Daily resource bonus event.
        }else{
            event_result = core_random_integer({
              'max': 4,
            });

            if(event_result === 0){
                output = 'Seeds! +1 Food/day';
                resources['food']['bonus'] += 1;

            }else if(event_result === 1){
                output = 'Veins! +1 Gold/day';
                resources['gold']['bonus'] += 1;

            }else if(event_result === 2){
                output = 'Popularity! +1 Population/day';
                resources['people']['bonus'] += 1;

            }else{
                output = 'Rocks! +1 Stone/day';
                resources['stone']['bonus'] += 1;
            }
        }

        document.getElementById('day').innerHTML += output + '
';
        daylight_passed += 1;

        if(daylight_passed < core_storage_data['day-events']){
            core_interval_modify({
              'clear': 'clearTimeout',
              'id': 'day',
              'interval': core_storage_data['day-event-duration'],
              'set': 'setTimeout',
              'todo': day,
            });
        }
    }

    if(daylight_passed >= core_storage_data['day-events']){
        daylight_passed = 0;

        for(const resource in resources){
            resources[resource]['amount'] += resources[resource]['bonus'];
        }
        resources['people']['unemployed'] += resources['people']['bonus'];

        if(resources['food']['amount'] + resources['food']['bonus'] < 0){
            delete_people(resources['people']['amount'] - 1);
            resources['people']['amount'] -=
              resources['people']['amount'] - (resources['food']['amount'] + resources['food']['bonus']);

            if(resources['people']['amount'] < 0){
                resources['people']['amount'] = 0;
            }

            resources['food']['amount'] = 0;
            resources['food']['bonus'] = 0;
        }

        document.getElementById('start-day').innerHTML = resources['people']['amount'] > 0
          ? start_new_day
          : 'Your castle has fallen.
<input onclick=new_game() type=button value="Start Over">';
    }

    resources['food']['bonus'] = resources['food']['workers'] * 2 - resources['people']['amount'];

    for(const resource in resources){
        document.getElementById(resource).textContent = resources[resource]['amount'];
        document.getElementById(resource + '-bonus').textContent = (resources[resource]['bonus'] > 0 ? '+' : '') + resources[resource]['bonus'];
    }
    document.getElementById('unemployed-workers').textContent = resources['people']['unemployed'];
}

function delete_people(count){
    do{
        if(resources['people']['unemployed'] > 0){
            resources['people']['unemployed'] -= 1;

        }else if(resources['people']['workers'] > 0){
            resources['people']['bonus'] -= 1;
            resources['people']['workers'] -= 1;

            document.getElementById('people-bonus').textContent = resources['people']['workers'];
            document.getElementById('people-workers').textContent = resources['people']['workers'];

        }else if(resources['stone']['workers'] > 0){
            resources['stone']['bonus'] -= 1;
            resources['stone']['workers'] -= 1;

            document.getElementById('stone-bonus').textContent = resources['stone']['workers'];
            document.getElementById('stone-workers').textContent = resources['stone']['workers'];

        }else if(resources['gold']['workers'] > 0){
            resources['gold']['bonus'] -= 1;
            resources['gold']['workers'] -= 1;

            document.getElementById('gold-bonus').textContent = resources['gold']['workers'];
            document.getElementById('gold-workers').textContent = resources['gold']['workers'];

        }else{
            resources['food']['workers'] -= 1;
            document.getElementById('food-workers').textContent = resources['food']['workers'];
        }
    }while(count--);
}

function new_game(){
    daylight_passed = 0;

    let tbody = '';
    for(const resource in resource_defaults){
        resources[resource] = resources[resource] || {};

        resources[resource]['amount'] = resource_defaults[resource]['amount'] || 0;
        resources[resource]['bonus'] = resource_defaults[resource]['bonus'] || 0;
        resources[resource]['workers'] = resource_defaults[resource]['workers'] || 0;

        tbody += '
' + resource
          + '' + resources[resource]['amount']
          + '' + resources[resource]['bonus']
          + '<input onclick="alter_workers({type:\'' + resource + '\',})" type=button value=+>'
            + ' ' + resources[resource]['workers'] + ' '
            + '<input onclick="alter_workers({amount:-1,type:\'' + resource + '\',})" type=button value=—>';
    }

    document.getElementById('day').textContent = '';
    document.getElementById('start-day').innerHTML = start_new_day;
    document.getElementById('tbody').innerHTML = tbody;

    resources['people']['unemployed'] = resources['people']['amount'];
    document.getElementById('unemployed-workers').textContent = resources['people']['unemployed'];
}
<|endoftext|>


<commit_before>/**
 *
 * Drop v4.1.0
 * Simple, mobile-friendly dropdown menus by Chris Ferdinandi.
 * http://github.com/cferdinandi/drop
 *
 * Free to use under the MIT License.
 * http://gomakethings.com/mit/
 *
 */

(function (root, factory) {
	if ( typeof define === 'function' && define.amd ) {
		define(factory);
	} else if ( typeof exports === 'object' ) {
		module.exports = factory;
	} else {
		root.drop = factory(root);
	}
})(this, function (root) {

	'use strict';

	//
	// Variables
	//

	var exports = {}; // Object for public APIs
	var supports = !!document.querySelector && !!root.addEventListener; // Feature test

	// Default settings
	var defaults = {
		toggleSelector: '.dropdown',
		contentSelector: '.dropdown-menu',
		toggleActiveClass: 'active',
		contentActiveClass: 'active',
		initClass: 'js-drop',
		callbackBefore: function () {},
		callbackAfter: function () {}
	};

	//
	// Methods
	//

	/**
	 * Merge defaults with user options
	 * @private
	 * @param {Object} defaults Default settings
	 * @param {Object} options User options
	 * @returns {Object} Merged values of defaults and options
	 */
	var extend = function ( defaults, options ) {
		for ( var key in options ) {
			if (Object.prototype.hasOwnProperty.call(options, key)) {
				defaults[key] = options[key];
			}
		}
		return defaults;
	};

	/**
	 * A simple forEach() implementation for Arrays, Objects and NodeLists
	 * @private
	 * @param {Array|Object|NodeList} collection Collection of items to iterate
	 * @param {Function} callback Callback function for each iteration
	 * @param {Array|Object|NodeList} scope Object/NodeList/Array that forEach is iterating over (aka `this`)
	 */
	var forEach = function (collection, callback, scope) {
		if (Object.prototype.toString.call(collection) === '[object Object]') {
			for (var prop in collection) {
				if (Object.prototype.hasOwnProperty.call(collection, prop)) {
					callback.call(scope, collection[prop], prop, collection);
				}
			}
		} else {
			for (var i = 0, len = collection.length; i < len; i++) {
				callback.call(scope, collection[i], i, collection);
			}
		}
	};

	/**
	 * Get siblings of an element
	 * @private
	 * @param  {Element} elem
	 * @return {Array}
	 */
	var getSiblings = function (elem) {
		var siblings = [];
		var sibling = elem.parentNode.firstChild;
		var skipMe = elem;
		for ( ; sibling; sibling = sibling.nextSibling ) {
			if ( sibling.nodeType == 1 && sibling != elem ) {
				siblings.push( sibling );
			}
		}
		return siblings;
	};

	/**
	 * Toggle a dropdown menu
	 * @public
	 * @param  {Element} toggle Element that triggered the expand or collapse
	 * @param  {Object} settings
	 * @param  {Event} event
	 */
	exports.toggleDrop = function ( toggle, settings, event ) {

		// Selectors and variables
		settings = extend( defaults, settings || {} ); // Merge user options with defaults
		var toggleMenu = toggle.nextElementSibling;
		var toggleParent = toggle.parentNode;
		var toggleSiblings = getSiblings(toggleParent);

		// Prevent defaults
		if ( event ) {
			event.stopPropagation();
			event.preventDefault();
		}

		settings.callbackBefore( toggle ); // Run callbacks before drop toggle

		// Add/remove '.active' class from dropdown item
		toggle.classList.toggle( settings.toggleActiveClass );
		toggleMenu.classList.toggle( settings.toggleActiveClass );
		toggleParent.classList.toggle( settings.toggleActiveClass );

		// For each toggle, remove the active class
		forEach(toggleSiblings, function (sibling) {
			var siblingContent = sibling.children;
			sibling.classList.remove( settings.toggleActiveClass );
			forEach(siblingContent, function (content) {
				content.classList.remove( settings.contentActiveClass );
			});
		});

		settings.callbackAfter( toggle ); // Run callbacks after drop toggle

	};

	/**
	 * Close all dropdown menus
	 * @private
	 * @param  {Object} settings
	 */
	var closeDrops = function ( settings ) {

		// Selectors and variables
		var dropToggle = document.querySelectorAll(settings.toggleSelector + ' > a.' + settings.toggleActiveClass);
		var dropWrapper = document.querySelectorAll(settings.toggleSelector + '.' + settings.toggleActiveClass);
		var dropContent = document.querySelectorAll(settings.contentSelector + '.' + settings.contentActiveClass);

		if ( dropToggle.length > 0 || dropWrapper.length > 0 || dropContent > 0 ) {

			settings.callbackBefore(); // Run callbacks before drop close

			// For each dropdown toggle, remove '.active' class
			forEach(dropToggle, function (toggle) {
				toggle.classList.remove( settings.toggleActiveClass );
			});

			// For each dropdown toggle wrapper, remove '.active' class
			forEach(dropWrapper, function (wrapper) {
				wrapper.classList.remove( settings.toggleActiveClass );
			});

			// For each dropdown content area, remove '.active' class
			forEach(dropContent, function (content) {
				content.classList.remove( settings.contentActiveClass );
			});

			settings.callbackAfter(); // Run callbacks after drop close

		}

	};

	/**
	 * Don't close dropdown menus when clicking on content within them
	 * @private
	 * @param  {Event} event
	 */
	var handleDropdownClick = function ( event ) {
		event.stopPropagation();
	};

	/**
	 * Initialize Smooth Scroll
	 * @public
	 * @param {Object} options User settings
	 */
	exports.init = function ( options ) {

		// feature test
		if ( !supports ) return;

		// Selectors and variables
		var settings = extend( defaults, options || {} ); // Merge user options with defaults
		var dropToggle = document.querySelectorAll(settings.toggleSelector + ' > a');
		var dropWrapper = document.querySelectorAll(settings.toggleSelector);
		var dropContent = document.querySelectorAll(settings.contentSelector);

		// Add class to HTML element to activate conditional CSS
		document.documentElement.classList.add( settings.initClass );

		// When body is clicked, close all dropdowns
		document.addEventListener('click', closeDrops.bind( null, settings ), false);

		// When a toggle is clicked, show/hide dropdown menu
		forEach(dropToggle, function (toggle) {
			toggle.addEventListener('click', exports.toggleDrop.bind( null, toggle, settings ), false);
		});

		// When dropdown menu content is clicked, don't close the menu
		forEach(dropContent, function (content) {
			content.addEventListener('click', handleDropdownClick, false);
		});

	};

	//
	// Public APIs
	//

	return exports;

});<commit_msg>Typo fixes<commit_after>/**
 *
 * Drop v4.1.0
 * Simple, mobile-friendly dropdown menus by Chris Ferdinandi.
 * http://github.com/cferdinandi/drop
 *
 * Free to use under the MIT License.
 * http://gomakethings.com/mit/
 *
 */

(function (root, factory) {
	if ( typeof define === 'function' && define.amd ) {
		define(factory);
	} else if ( typeof exports === 'object' ) {
		module.exports = factory;
	} else {
		root.drop = factory(root);
	}
})(this, function (root) {

	'use strict';

	//
	// Variables
	//

	var exports = {}; // Object for public APIs
	var supports = !!document.querySelector && !!root.addEventListener; // Feature test

	// Default settings
	var defaults = {
		toggleSelector: '.dropdown',
		contentSelector: '.dropdown-menu',
		toggleActiveClass: 'active',
		contentActiveClass: 'active',
		initClass: 'js-drop',
		callbackBefore: function () {},
		callbackAfter: function () {}
	};

	//
	// Methods
	//

	/**
	 * Merge defaults with user options
	 * @private
	 * @param {Object} defaults Default settings
	 * @param {Object} options User options
	 * @returns {Object} Merged values of defaults and options
	 */
	var extend = function ( defaults, options ) {
		for ( var key in options ) {
			if (Object.prototype.hasOwnProperty.call(options, key)) {
				defaults[key] = options[key];
			}
		}
		return defaults;
	};

	/**
	 * A simple forEach() implementation for Arrays, Objects and NodeLists
	 * @private
	 * @param {Array|Object|NodeList} collection Collection of items to iterate
	 * @param {Function} callback Callback function for each iteration
	 * @param {Array|Object|NodeList} scope Object/NodeList/Array that forEach is iterating over (aka `this`)
	 */
	var forEach = function (collection, callback, scope) {
		if (Object.prototype.toString.call(collection) === '[object Object]') {
			for (var prop in collection) {
				if (Object.prototype.hasOwnProperty.call(collection, prop)) {
					callback.call(scope, collection[prop], prop, collection);
				}
			}
		} else {
			for (var i = 0, len = collection.length; i < len; i++) {
				callback.call(scope, collection[i], i, collection);
			}
		}
	};

	/**
	 * Get siblings of an element
	 * @private
	 * @param  {Element} elem
	 * @return {NodeList}
	 */
	var getSiblings = function (elem) {
		var siblings = [];
		var sibling = elem.parentNode.firstChild;
		var skipMe = elem;
		for ( ; sibling; sibling = sibling.nextSibling ) {
			if ( sibling.nodeType == 1 && sibling != elem ) {
				siblings.push( sibling );
			}
		}
		return siblings;
	};

	/**
	 * Toggle a dropdown menu
	 * @public
	 * @param  {Element} toggle Element that triggered the expand or collapse
	 * @param  {Object} settings
	 * @param  {Event} event
	 */
	exports.toggleDrop = function ( toggle, settings, event ) {

		// Selectors and variables
		settings = extend( defaults, settings || {} ); // Merge user options with defaults
		var toggleMenu = toggle.nextElementSibling;
		var toggleParent = toggle.parentNode;
		var toggleSiblings = getSiblings(toggleParent);

		// Prevent defaults
		if ( event ) {
			event.stopPropagation();
			event.preventDefault();
		}

		settings.callbackBefore( toggle ); // Run callbacks before drop toggle

		// Add/remove '.active' class from dropdown item
		toggle.classList.toggle( settings.toggleActiveClass );
		toggleMenu.classList.toggle( settings.toggleActiveClass );
		toggleParent.classList.toggle( settings.toggleActiveClass );

		// For each toggle, remove the active class
		forEach(toggleSiblings, function (sibling) {
			var siblingContent = sibling.children;
			sibling.classList.remove( settings.toggleActiveClass );
			forEach(siblingContent, function (content) {
				content.classList.remove( settings.contentActiveClass );
			});
		});

		settings.callbackAfter( toggle ); // Run callbacks after drop toggle

	};

	/**
	 * Close all dropdown menus
	 * @private
	 * @param  {Object} settings
	 */
	var closeDrops = function ( settings ) {

		// Selectors and variables
		var dropToggle = document.querySelectorAll(settings.toggleSelector + ' > a.' + settings.toggleActiveClass);
		var dropWrapper = document.querySelectorAll(settings.toggleSelector + '.' + settings.toggleActiveClass);
		var dropContent = document.querySelectorAll(settings.contentSelector + '.' + settings.contentActiveClass);

		if ( dropToggle.length > 0 || dropWrapper.length > 0 || dropContent > 0 ) {

			settings.callbackBefore(); // Run callbacks before drop close

			// For each dropdown toggle, remove '.active' class
			forEach(dropToggle, function (toggle) {
				toggle.classList.remove( settings.toggleActiveClass );
			});

			// For each dropdown toggle wrapper, remove '.active' class
			forEach(dropWrapper, function (wrapper) {
				wrapper.classList.remove( settings.toggleActiveClass );
			});

			// For each dropdown content area, remove '.active' class
			forEach(dropContent, function (content) {
				content.classList.remove( settings.contentActiveClass );
			});

			settings.callbackAfter(); // Run callbacks after drop close

		}

	};

	/**
	 * Don't close dropdown menus when clicking on content within them
	 * @private
	 * @param  {Event} event
	 */
	var handleDropdownClick = function ( event ) {
		event.stopPropagation();
	};

	/**
	 * Initialize Drop
	 * @public
	 * @param {Object} options User settings
	 */
	exports.init = function ( options ) {

		// feature test
		if ( !supports ) return;

		// Selectors and variables
		var settings = extend( defaults, options || {} ); // Merge user options with defaults
		var dropToggle = document.querySelectorAll(settings.toggleSelector + ' > a');
		var dropWrapper = document.querySelectorAll(settings.toggleSelector);
		var dropContent = document.querySelectorAll(settings.contentSelector);

		// Add class to HTML element to activate conditional CSS
		document.documentElement.classList.add( settings.initClass );

		// When body is clicked, close all dropdowns
		document.addEventListener('click', closeDrops.bind( null, settings ), false);

		// When a toggle is clicked, show/hide dropdown menu
		forEach(dropToggle, function (toggle) {
			toggle.addEventListener('click', exports.toggleDrop.bind( null, toggle, settings ), false);
		});

		// When dropdown menu content is clicked, don't close the menu
		forEach(dropContent, function (content) {
			content.addEventListener('click', handleDropdownClick, false);
		});

	};

	//
	// Public APIs
	//

	return exports;

});<|endoftext|>


<commit_before>function nedface() {
    var image = document.getElementById('myImage');
    if (image.src.match("https://isaiahpatton.github.io/ned/imgs/ned.gif")) {
        image.src = "http://isaiahpatton.github.io/ned/imgs/ned.jpg";
    } else {
        image.src = "http://isaiahpatton.github.io/ned/imgs/ned.gif";
    }
}
<commit_msg>Update face.js<commit_after>function nedface() {
    var image = document.getElementById('myImage');
    if (image.src.match("http://isaiahpatton.github.io/ned/imgs/ned.gif")) {
        image.src = "http://isaiahpatton.github.io/ned/imgs/ned.jpg";
    } else {
        image.src = "http://isaiahpatton.github.io/ned/imgs/ned.gif";
    }
}
<|endoftext|>


<commit_before>// Check for the various File API support.
if (window.File && window.FileReader && window.FileList && window.Blob) {

  var load_vimrc = function (file, callback) {
    var reader = new FileReader();
    // TODO: select file encoding
    reader.onload = callback;

    reader.readAsText(file, 'UTF-8');
  };

  $('#vimrc_upload').on('change', function (e) {
    var input = $(this);
    file = input.prop('files')[0];

    load_vimrc(file, function (e) {
      var vimrc_text = e.target.result;

      vim_power = scouter(vimrc_text);
      show_scouter(vim_power);
    });
  });

} else {
  var upload_nav = $('#upload_nav');
  upload_nav.addClass('disabled');
  upload_nav.children('a').attr('data-toggle', '');
}
<commit_msg>file local scope<commit_after>(function () {

  // Check for the various File API support.
  if (window.File && window.FileReader && window.FileList && window.Blob) {

    var load_vimrc = function (file, callback) {
      var reader = new FileReader();
      // TODO: select file encoding
      reader.onload = callback;

      reader.readAsText(file, 'UTF-8');
    };

    $('#vimrc_upload').on('change', function (e) {
      var input = $(this);
      file = input.prop('files')[0];

      load_vimrc(file, function (e) {
        var vimrc_text = e.target.result;

        vim_power = scouter(vimrc_text);
        show_scouter(vim_power);
      });
    });

  } else {
    var upload_nav = $('#upload_nav');
    upload_nav.addClass('disabled');
    upload_nav.children('a').attr('data-toggle', '');
  }

})();
<|endoftext|>


<commit_before>(function () {
	var canvas = document.getElementById('game-canvas'),
		canvasContext = canvas.getContext('2d'),
		fps = 30,
		ball,
		paddle,
		bricks = [],
		// position of the mouse in the canvas, taking in account the scroll
		// and position of the canvas in the page
		mouseX,
		mouseY;

	const PADDLE_WIDTH = 100;
	const PADDLE_THICKNESS = 10;
	const BALL_RADIUS = 10;

	const BRICK_WIDTH = 50;
	const BRICK_HEIGHT = 25;
	const BRICK_STATE_ACTIVE = 1;
	const BRICK_STATE_INACTIVE = 2;

	const DEBUG = true;

	setInterval(updateAll, 1000 / fps);

	canvas.addEventListener('mousemove', mouseMovedEvent);

	/* Ball Class */
	var Ball = function (x, y, speedX, speedY) {
		this.x  = this.originalX = x;
		this.y = this.originalY = y;
		this.speedX = this.originalSpeedX = speedX;
		this.speedY = this.originalSpeedY = speedY;
	};

	Ball.prototype.updatePosition = function () {
		this.x += this.speedX;
		this.y += this.speedY;

		// This deals with the screen's edges
		if (this.x - BALL_RADIUS < 0 || this.x + BALL_RADIUS > canvas.width) {
			this.speedX *= -1;
		}
		if (this.y - BALL_RADIUS < 0) {
			this.speedY *= -1;
		}
		if (this.y + BALL_RADIUS > canvas.height) {
			this.reset();
		}

		if (this.y + BALL_RADIUS > paddle.y &&
			this.y - BALL_RADIUS < paddle.y + PADDLE_THICKNESS &&
			this.x  + BALL_RADIUS > paddle.x &&
			this.x - BALL_RADIUS < paddle.x + PADDLE_WIDTH
		) {
			this.speedY *= -1;

			var centerPaddleX = paddle.x + PADDLE_WIDTH / 2,
				distFromPaddleCenter = ball.x - centerPaddleX;

			this.speedX = distFromPaddleCenter * 0.35;
		}

	};

	Ball.prototype.reset = function () {
		this.x  = this.originalX;
		this.y = this.originalY;
		this.speedX = this.originalSpeedX;
		this.speedY = this.originalSpeedY;
	};

	Ball.prototype.draw = function () {
		drawCircle(this.x, this.y, BALL_RADIUS, 'white');
	};
	/* End Ball Class */

	/* Paddle Class */
	var Paddle = function (x, y) {
		this.x = x;
		this.y = y;
	}

	Paddle.prototype.updatePosition = function (x) {
		this.x = x;
	};

	Paddle.prototype.draw = function () {
		drawRectangle(this.x, this.y, PADDLE_WIDTH, PADDLE_THICKNESS, 'white');
	};
	/* End Paddle Class */

	/* Brick Class */
	var Brick = function (x, y, destructible) {
		this.x = x;
		this.y = y;
		this.state = BRICK_STATE_ACTIVE;
		this.destructible = destructible;
	}

	Brick.prototype.draw = function () {
		drawRectangle(this.x, this.y, BRICK_WIDTH, BRICK_HEIGHT, 'red');
	};
	/* End Brick Class */

	ball = new Ball(canvas.width / 2, canvas.height / 2, 5, 7);
	paddle = new Paddle((canvas.width - PADDLE_WIDTH) / 2, canvas.height - 100);
	bricks.push(new Brick(100, 100, true));

	/**
	 * EVENT FOR THE MOUSE
	 */
	function mouseMovedEvent (e) {
		var rect = canvas.getBoundingClientRect(),
			root = document.documentElement;

			mouseX = e.clientX - rect.left - root.scrollLeft;
			mouseY = e.clientY- rect.top - root.scrollTop;

		if (mouseX > PADDLE_WIDTH / 2 && mouseX < canvas.width - PADDLE_WIDTH / 2) {
			paddle.updatePosition(
				Math.min(
					Math.max(
						0,
						mouseX - PADDLE_WIDTH / 2
					),
					canvas.width - PADDLE_WIDTH / 2
				)
			);
		}
	}

	function moveAll () {
		ball.updatePosition();
	}

	/**
	 * Methods to draw stuff
	 */
	function drawRectangle (x, y, width, height, color) {
		canvasContext.fillStyle = color;
		canvasContext.fillRect(x, y, width, height);
	}

	function drawCircle (x, y, radius, color) {
		canvasContext.fillStyle = color;
		canvasContext.beginPath();
		canvasContext.arc(x, y, radius, 0, Math.PI * 2, true);
		canvasContext.fill();
	}

	function drawText (text, x, y, color) {
		canvasContext.fillStyle = color;
		canvasContext.fillText(text, x, y);
	}

	function drawAll () {
		drawRectangle(0, 0, canvas.width, canvas.height, 'black');
		ball.draw();
		paddle.draw();

		for (var b in bricks) {
			bricks[b].draw();
		}

		if (DEBUG) {
			drawText('(' + mouseX + ', ' + mouseY + ')', mouseX, mouseY, 'white');
		}
	}

	function updateAll () {
		moveAll();
		drawAll();
	}
})();
<commit_msg>draw the bricks only if they are active<commit_after>(function () {
	var canvas = document.getElementById('game-canvas'),
		canvasContext = canvas.getContext('2d'),
		fps = 30,
		ball,
		paddle,
		bricks = [],
		// position of the mouse in the canvas, taking in account the scroll
		// and position of the canvas in the page
		mouseX,
		mouseY;

	const PADDLE_WIDTH = 100;
	const PADDLE_THICKNESS = 10;
	const BALL_RADIUS = 10;

	const BRICK_WIDTH = 50;
	const BRICK_HEIGHT = 25;
	const BRICK_STATE_ACTIVE = 1;
	const BRICK_STATE_INACTIVE = 2;

	const DEBUG = true;

	setInterval(updateAll, 1000 / fps);

	canvas.addEventListener('mousemove', mouseMovedEvent);

	/* Ball Class */
	var Ball = function (x, y, speedX, speedY) {
		this.x  = this.originalX = x;
		this.y = this.originalY = y;
		this.speedX = this.originalSpeedX = speedX;
		this.speedY = this.originalSpeedY = speedY;
	};

	Ball.prototype.updatePosition = function () {
		this.x += this.speedX;
		this.y += this.speedY;

		// This deals with the screen's edges
		if (this.x - BALL_RADIUS < 0 || this.x + BALL_RADIUS > canvas.width) {
			this.speedX *= -1;
		}
		if (this.y - BALL_RADIUS < 0) {
			this.speedY *= -1;
		}
		if (this.y + BALL_RADIUS > canvas.height) {
			this.reset();
		}

		if (this.y + BALL_RADIUS > paddle.y &&
			this.y - BALL_RADIUS < paddle.y + PADDLE_THICKNESS &&
			this.x  + BALL_RADIUS > paddle.x &&
			this.x - BALL_RADIUS < paddle.x + PADDLE_WIDTH
		) {
			this.speedY *= -1;

			var centerPaddleX = paddle.x + PADDLE_WIDTH / 2,
				distFromPaddleCenter = ball.x - centerPaddleX;

			this.speedX = distFromPaddleCenter * 0.35;
		}

	};

	Ball.prototype.reset = function () {
		this.x  = this.originalX;
		this.y = this.originalY;
		this.speedX = this.originalSpeedX;
		this.speedY = this.originalSpeedY;
	};

	Ball.prototype.draw = function () {
		drawCircle(this.x, this.y, BALL_RADIUS, 'white');
	};
	/* End Ball Class */

	/* Paddle Class */
	var Paddle = function (x, y) {
		this.x = x;
		this.y = y;
	}

	Paddle.prototype.updatePosition = function (x) {
		this.x = x;
	};

	Paddle.prototype.draw = function () {
		drawRectangle(this.x, this.y, PADDLE_WIDTH, PADDLE_THICKNESS, 'white');
	};
	/* End Paddle Class */

	/* Brick Class */
	var Brick = function (x, y, destructible) {
		this.x = x;
		this.y = y;
		this.state = BRICK_STATE_ACTIVE;
		this.destructible = destructible;
	}

	Brick.prototype.draw = function () {
		drawRectangle(this.x, this.y, BRICK_WIDTH, BRICK_HEIGHT, 'red');
	};
	/* End Brick Class */

	ball = new Ball(canvas.width / 2, canvas.height / 2, 5, 7);
	paddle = new Paddle((canvas.width - PADDLE_WIDTH) / 2, canvas.height - 100);
	bricks.push(new Brick(100, 100, true));

	/**
	 * EVENT FOR THE MOUSE
	 */
	function mouseMovedEvent (e) {
		var rect = canvas.getBoundingClientRect(),
			root = document.documentElement;

			mouseX = e.clientX - rect.left - root.scrollLeft;
			mouseY = e.clientY- rect.top - root.scrollTop;

		if (mouseX > PADDLE_WIDTH / 2 && mouseX < canvas.width - PADDLE_WIDTH / 2) {
			paddle.updatePosition(
				Math.min(
					Math.max(
						0,
						mouseX - PADDLE_WIDTH / 2
					),
					canvas.width - PADDLE_WIDTH / 2
				)
			);
		}
	}

	function moveAll () {
		ball.updatePosition();
	}

	/**
	 * Methods to draw stuff
	 */
	function drawRectangle (x, y, width, height, color) {
		canvasContext.fillStyle = color;
		canvasContext.fillRect(x, y, width, height);
	}

	function drawCircle (x, y, radius, color) {
		canvasContext.fillStyle = color;
		canvasContext.beginPath();
		canvasContext.arc(x, y, radius, 0, Math.PI * 2, true);
		canvasContext.fill();
	}

	function drawText (text, x, y, color) {
		canvasContext.fillStyle = color;
		canvasContext.fillText(text, x, y);
	}

	function drawAll () {
		drawRectangle(0, 0, canvas.width, canvas.height, 'black');
		ball.draw();
		paddle.draw();

		for (var b in bricks) {
			if (bricks[b].state == BRICK_STATE_ACTIVE) {
				bricks[b].draw();
			}
		}

		if (DEBUG) {
			drawText('(' + mouseX + ', ' + mouseY + ')', mouseX, mouseY, 'white');
		}
	}

	function updateAll () {
		moveAll();
		drawAll();
	}
})();
<|endoftext|>


<commit_before>		//初始化引擎
		init(30,"mylegend",320,480,main,LEvent.INIT);
		//进度条显示层，背景层，方块绘制层，预览层
		var loadingLayer,backLayer,graphicsLayer,nextLayer;
		//存放图片对象的属性
		var imglist = {};
		//图片数据
		var imgData = new Array(
			{name:"backImage",path:"./image/backImage.png"},
			{name:"block1",path:"./image/block1.png"},
			{name:"block2",path:"./image/block2.png"},
			{name:"block3",path:"./image/block3.png"},
			{name:"block4",path:"./image/block4.png"}
			);
		//用于生成方块
		var box;
		//方块坐标数组初始化
		var map;
		var nodelist;
		var bitmapdataList;
		//方块区域起始位置
		var START_X1=15,START_Y1=20,START_X2=228,START_Y2=65;
		//预览方块和当前方块
		var nextBox,nowBox;
		var pointBox ={x:0,y:0};
		var speed=15,speedIndex=0,speedMax=15;
		//控制单元
		var myKey = {
			keyControl:null,
			step:1,
			stepindex:0,
			isTouchDown:false,
			touchX:0,
			touchY:0,
			touchMove:false
		};
		//main函数
		function main(){
			map =[
				[0,0,0,0,0,0,0,0,0,0],
				[0,0,0,0,0,0,0,0,0,0],
				[0,0,0,0,0,0,0,0,0,0],
				[0,0,0,0,0,0,0,0,0,0],
				[0,0,0,0,0,0,0,0,0,0],
				[0,0,0,0,0,0,0,0,0,0],
				[0,0,0,0,0,0,0,0,0,0],
				[0,0,0,0,0,0,0,0,0,0],
				[0,0,0,0,0,0,0,0,0,0],
				[0,0,0,0,0,0,0,0,0,0],
				[0,0,0,0,0,0,0,0,0,0],
				[0,0,0,0,0,0,0,0,0,0],
				[0,0,0,0,0,0,0,0,0,0],
				[0,0,0,0,0,0,0,0,0,0],
				[0,0,0,0,0,0,0,0,0,0],
				[0,0,0,0,0,0,0,0,0,0],
				[0,0,0,0,0,0,0,0,0,0],
				[0,0,0,0,0,0,0,0,0,0],
				[0,0,0,0,0,0,0,0,0,0],
				[0,0,0,0,0,0,0,0,0,0]
			];
			box = new Box();
			//背景层初始化
			backLayer = new LSprite();
			//在背景层描绘背景
			backLayer.graphics.drawRect(2,"brown",[0,0,350,480],true,"black");
			addChild(backLayer);
			//进度条显示层初始化
			loadingLayer = new LoadingSample1();
			backLayer.addChild(loadingLayer);
			//利用LLoadManage类：进度条的读取与显示
			LLoadManage.load(
				imgData,
				function(progress){
					loadingLayer.setProgress(progress);
			    },
			    function(result){
			    	imglist = result;
					backLayer.removeChild(loadingLayer);
					loadingLayer= null;
					gameInit();
			    }
			);
			//gameInit();
		}
<commit_msg>游戏标题画面初始化<commit_after>		//初始化引擎
		init(30,"mylegend",320,480,main,LEvent.INIT);
		//进度条显示层，背景层，方块绘制层，预览层
		var loadingLayer,backLayer,graphicsLayer,nextLayer;
		//存放图片对象的属性
		var imglist = {};
		//图片数据
		var imgData = new Array(
			{name:"backImage",path:"./image/backImage.png"},
			{name:"block1",path:"./image/block1.png"},
			{name:"block2",path:"./image/block2.png"},
			{name:"block3",path:"./image/block3.png"},
			{name:"block4",path:"./image/block4.png"}
			);
		//用于生成方块
		var box;
		//方块坐标数组初始化
		var map;
		var nodelist;
		var bitmapdataList;
		//方块区域起始位置
		var START_X1=15,START_Y1=20,START_X2=228,START_Y2=65;
		//预览方块和当前方块
		var nextBox,nowBox;
		var pointBox ={x:0,y:0};
		var speed=15,speedIndex=0,speedMax=15;
		//控制单元
		var myKey = {
			keyControl:null,
			step:1,
			stepindex:0,
			isTouchDown:false,
			touchX:0,
			touchY:0,
			touchMove:false
		};
		//main函数
		function main(){
			map =[
				[0,0,0,0,0,0,0,0,0,0],
				[0,0,0,0,0,0,0,0,0,0],
				[0,0,0,0,0,0,0,0,0,0],
				[0,0,0,0,0,0,0,0,0,0],
				[0,0,0,0,0,0,0,0,0,0],
				[0,0,0,0,0,0,0,0,0,0],
				[0,0,0,0,0,0,0,0,0,0],
				[0,0,0,0,0,0,0,0,0,0],
				[0,0,0,0,0,0,0,0,0,0],
				[0,0,0,0,0,0,0,0,0,0],
				[0,0,0,0,0,0,0,0,0,0],
				[0,0,0,0,0,0,0,0,0,0],
				[0,0,0,0,0,0,0,0,0,0],
				[0,0,0,0,0,0,0,0,0,0],
				[0,0,0,0,0,0,0,0,0,0],
				[0,0,0,0,0,0,0,0,0,0],
				[0,0,0,0,0,0,0,0,0,0],
				[0,0,0,0,0,0,0,0,0,0],
				[0,0,0,0,0,0,0,0,0,0],
				[0,0,0,0,0,0,0,0,0,0]
			];
			box = new Box();
			//背景层初始化
			backLayer = new LSprite();
			//在背景层描绘背景
			backLayer.graphics.drawRect(2,"brown",[0,0,350,480],true,"black");
			addChild(backLayer);
			//进度条显示层初始化
			loadingLayer = new LoadingSample1();
			backLayer.addChild(loadingLayer);
			//利用LLoadManage类：进度条的读取与显示
			LLoadManage.load(
				imgData,
				function(progress){
					loadingLayer.setProgress(progress);
			    },
			    function(result){
			    	imglist = result;
					backLayer.removeChild(loadingLayer);
					loadingLayer= null;
					gameInit();
			    }
			);
			//gameInit();
		}
		//游戏标题画面初始化
		function gameInit(){
			//显示游戏标题
			var title = new LTextField();
			title.x = 100;
			title.y = 100;
			title.text = "俄罗斯方块";
			title.size = 30;
			title.color ="white";
			backLayer.addChild(title);
			//提示信息
			backLayer.graphics.drawRect(1,"white",[50,250,250,30]);
			var infoText = new LTextField();
			infoText.x = 75;
			infoText.y = 250;
			infoText.size = 25;
			infoText.text = "点击页面开始游戏";
			infoText.color = "white";
			backLayer.addChild(infoText);
			//添加鼠标点击事件侦听
			infoText.addEventListener(LMouseEvent.MOUSE_UP,gameStart);
		}

<|endoftext|>