<commit_before>/*eslint no-invalid-this: 0*/
/*
 * Maintains a lookup of connected IRC clients. These connections are transient
 * and may be closed for a variety of reasons.
 */
"use strict";
var stats = require("../config/stats");
var log = require("../logging").get("ClientPool");
var Promise = require("bluebird");

const RECONNECT_TIME_MS = 1000;

function ClientPool(ircBridge) {
    this._ircBridge = ircBridge;
    // The list of bot clients on servers (not specific users)
    this._botClients = {
        // server_domain: BridgedClient
    };

    // list of virtual users on servers
    this._virtualClients = {
        // server_domain: {
        //    nicks: {
        //      <nickname>: BridgedClient
        //    },
        //    userIds: {
        //      <user_id>: BridgedClient
        //    }
        // }
    }
}

ClientPool.prototype.killAllClients = function() {
    var domainList = Object.keys(this._virtualClients);
    var killList = domainList.map((domain) => {
        let clients = Object.keys(this._virtualClients[domain].nicks).map(
            (nick) => this._virtualClients[domain].nicks[nick]
        );

        clients = clients.concat(
            Object.keys(this._virtualClients[domain].userIds).map(
                (userId) => this._virtualClients[domain].userIds[userId]
            )
        );

        clients.push(this._botClients[domain]);

        return clients.filter((c) => c !== undefined);
    }).reduce((a, b) => {return a.concat(b)});

    // console.log('Clients to kill ', killList.map((c)=>c.nick));

    return Promise.all(
        killList.map(
            (client) => client.kill()
        )
    );
}

ClientPool.prototype.setBot = function(server, client) {
    this._botClients[server.domain] = client;
};

ClientPool.prototype.getBot = function(server) {
    return this._botClients[server.domain];
};

ClientPool.prototype.createIrcClient = function(ircClientConfig, matrixUser, isBot) {
    var bridgedClient = this._ircBridge.createBridgedClient(
        ircClientConfig, matrixUser, isBot
    );
    var server = bridgedClient.server;

    if (this._virtualClients[server.domain] === undefined) {
        this._virtualClients[server.domain] = {
            nicks: Object.create(null),
            userIds: Object.create(null)
        };
    }
    if (isBot) {
        this._botClients[server.domain] = bridgedClient;
    }

    // add event listeners
    bridgedClient.on("client-connected", this._onClientConnected.bind(this));
    bridgedClient.on("client-disconnected", this._onClientDisconnected.bind(this));
    bridgedClient.on("nick-change", this._onNickChange.bind(this));
    bridgedClient.on("join-error", this._onJoinError.bind(this));

    // store the bridged client immediately in the pool even though it isn't
    // connected yet, else we could spawn 2 clients for a single user if this
    // function is called quickly.
    this._virtualClients[server.domain].userIds[bridgedClient.userId] = bridgedClient;

    // Does this server have a max clients limit? If so, check if the limit is
    // reached and start cycling based on oldest time.
    this._checkClientLimit(server);
    return bridgedClient;
};

ClientPool.prototype.getBridgedClientByUserId = function(server, userId) {
    if (!this._virtualClients[server.domain]) {
        return undefined;
    }
    var cli = this._virtualClients[server.domain].userIds[userId];
    if (!cli || cli.isDead()) {
        return undefined;
    }
    return cli;
};

ClientPool.prototype.getBridgedClientByNick = function(server, nick) {
    var bot = this.getBot(server);
    if (bot && bot.nick === nick) {
        return bot;
    }

    if (!this._virtualClients[server.domain]) {
        return undefined;
    }
    var cli = this._virtualClients[server.domain].nicks[nick];
    if (!cli || cli.isDead()) {
        return undefined;
    }
    return cli;
};

ClientPool.prototype.getBridgedClientsForUserId = function(userId) {
    var domainList = Object.keys(this._virtualClients);
    var clientList = [];
    domainList.forEach((domain) => {
        var cli = this._virtualClients[domain].userIds[userId];
        if (cli && !cli.isDead()) {
            clientList.push(cli);
        }
    });
    return clientList;
};

ClientPool.prototype._checkClientLimit = function(server) {
    if (server.getMaxClients() === 0) {
        return;
    }

    var numConnections = this._getNumberOfConnections(server);
    this._sendConnectionMetric(server);

    if (numConnections < server.getMaxClients()) {
        // under the limit, we're good for now.
        log.debug(
            "%s active connections on %s",
            numConnections, server.domain
        );
        return;
    }

    log.debug(
        "%s active connections on %s (limit %s)",
        numConnections, server.domain, server.getMaxClients()
    );

    // find the oldest client to kill.
    var oldest = null;
    Object.keys(this._virtualClients[server.domain].nicks).forEach((nick) => {
        var client = this._virtualClients[server.domain].nicks[nick];
        if (!client) {
            // possible since undefined/null values can be present from culled entries
            return;
        }
        if (client.isBot) {
            return; // don't ever kick the bot off.
        }
        if (oldest === null) {
            oldest = client;
            return;
        }
        if (client.getLastActionTs() < oldest.getLastActionTs()) {
            oldest = client;
        }
    });
    if (!oldest) {
        return;
    }
    // disconnect and remove mappings.
    this._removeBridgedClient(oldest);
    oldest.disconnect("Client limit exceeded: " + server.getMaxClients()).done(
    function() {
        log.info("Client limit exceeded: Disconnected %s on %s.",
            oldest.nick, oldest.server.domain);
    },
    function(e) {
        log.error("Error when disconnecting %s on server %s: %s",
            oldest.nick, oldest.server.domain, JSON.stringify(e));
    });
};

ClientPool.prototype._getNumberOfConnections = function(server) {
    if (!server || !this._virtualClients[server.domain]) { return 0; }

    var connectedNickMap = this._virtualClients[server.domain].nicks;

    var numConnectedNicks = Object.keys(connectedNickMap).filter(function(nick) {
        return Boolean(connectedNickMap[nick]); // remove 'undefined' values
    }).length;

    return numConnectedNicks;
};

ClientPool.prototype._sendConnectionMetric = function(server) {
    stats.ircClients(server.domain, this._getNumberOfConnections(server));
};

ClientPool.prototype._removeBridgedClient = function(bridgedClient) {
    var server = bridgedClient.server;
    this._virtualClients[server.domain].userIds[bridgedClient.userId] = undefined;
    this._virtualClients[server.domain].nicks[bridgedClient.nick] = undefined;

    if (bridgedClient.isBot) {
        this._botClients[server.domain] = undefined;
    }
};

ClientPool.prototype._onClientConnected = function(bridgedClient) {
    var server = bridgedClient.server;
    var oldNick = bridgedClient.nick;
    var actualNick = bridgedClient.unsafeClient.nick;

    // assign a nick to this client
    this._virtualClients[server.domain].nicks[actualNick] = bridgedClient;

    // informative logging
    if (oldNick !== actualNick) {
        log.debug("Connected with nick '%s' instead of desired nick '%s'",
            actualNick, oldNick);
    }
};

ClientPool.prototype._onClientDisconnected = function(bridgedClient) {
    this._removeBridgedClient(bridgedClient);
    this._sendConnectionMetric(bridgedClient.server);

    if (bridgedClient.explicitDisconnect) {
        // don't reconnect users which explicitly disconnected e.g. client
        // cycling, idle timeouts, leaving rooms, etc.
        return;
    }
    // Reconnect this user
    log.debug(
        "onClientDisconnected: <%s> Reconnecting %s@%s in %sms",
        bridgedClient._id, bridgedClient.nick, bridgedClient.server.domain, RECONNECT_TIME_MS
    );
    // change the client config to use the current nick rather than the desired nick. This
    // makes sure that the client attempts to reconnect with the *SAME* nick, and also draws
    // from the latest !nick change, as the client config here may be very very old.
    var cliConfig = bridgedClient.getClientConfig();
    cliConfig.setDesiredNick(bridgedClient.nick);

    var cli = this.createIrcClient(
        cliConfig, bridgedClient.matrixUser, bridgedClient.isBot
    );
    var chanList = bridgedClient.chanList;
    var self = this;
    // remove ref to the disconnected client so it can be GC'd. If we don't do this,
    // the timeout below holds it in a closure, preventing it from being GC'd.
    bridgedClient = undefined;
    setTimeout(function() {
        cli.connect().then(function() {
            log.info(
                "<%s> Reconnected %s@%s", cli._id, cli.nick, cli.server.domain
            );
            if (chanList.length > 0) {
                log.info("<%s> Rejoining %s channels", cli._id, chanList.length);
                chanList.forEach(function(c) {
                    cli.joinChannel(c);
                });
            }
            self._sendConnectionMetric(cli.server);
        }, function(e) {
            log.error(
                "<%s> Failed to reconnect %s@%s", cli._id, cli.nick, cli.server.domain
            );
        });
    }, RECONNECT_TIME_MS);
};

ClientPool.prototype._onNickChange = function(bridgedClient, oldNick, newNick) {
    this._virtualClients[bridgedClient.server.domain].nicks[oldNick] = undefined;
    this._virtualClients[bridgedClient.server.domain].nicks[newNick] = bridgedClient;
};

ClientPool.prototype._onJoinError = Promise.coroutine(function*(bridgedClient, chan, err) {
    var errorsThatShouldKick = [
        "err_bannedfromchan", // they aren't allowed in channels they are banned on.
        "err_inviteonlychan", // they aren't allowed in invite only channels
        "err_channelisfull", // they aren't allowed in if the channel is full
        "err_badchannelkey" // they aren't allowed in channels with a bad key
    ];
    if (errorsThatShouldKick.indexOf(err) === -1) {
        return;
    }
    if (!bridgedClient.userId || bridgedClient.isBot) {
        return; // the bot itself can get these join errors
    }
    // TODO: this is a bit evil, no one in their right mind would expect
    // the client pool to be kicking matrix users from a room :(
    log.info(`Kicking ${bridgedClient.userId} from room due to ${err}`);
    let matrixRooms = yield this._ircBridge.getStore().getMatrixRoomsForChannel(
        bridgedClient.server, chan
    );
    let promises = matrixRooms.map((room) => {
        return this._ircBridge.getAppServiceBridge().getIntent().kick(
            room.getId(), bridgedClient.userId, `IRC error on ${chan}: ${err}`
        );
    });
    yield Promise.all(promises);
});

module.exports = ClientPool;
<commit_msg>Filter out null clients when killing clients in pool<commit_after>/*eslint no-invalid-this: 0*/
/*
 * Maintains a lookup of connected IRC clients. These connections are transient
 * and may be closed for a variety of reasons.
 */
"use strict";
var stats = require("../config/stats");
var log = require("../logging").get("ClientPool");
var Promise = require("bluebird");

const RECONNECT_TIME_MS = 1000;

function ClientPool(ircBridge) {
    this._ircBridge = ircBridge;
    // The list of bot clients on servers (not specific users)
    this._botClients = {
        // server_domain: BridgedClient
    };

    // list of virtual users on servers
    this._virtualClients = {
        // server_domain: {
        //    nicks: {
        //      <nickname>: BridgedClient
        //    },
        //    userIds: {
        //      <user_id>: BridgedClient
        //    }
        // }
    }
}

ClientPool.prototype.killAllClients = function() {
    var domainList = Object.keys(this._virtualClients);
    var killList = domainList.map((domain) => {
        let clients = Object.keys(this._virtualClients[domain].nicks).map(
            (nick) => this._virtualClients[domain].nicks[nick]
        );

        clients = clients.concat(
            Object.keys(this._virtualClients[domain].userIds).map(
                (userId) => this._virtualClients[domain].userIds[userId]
            )
        );

        clients.push(this._botClients[domain]);

        return clients.filter((c) => Boolean(c));
    }).reduce((a, b) => {return a.concat(b)});

    // console.log('Clients to kill ', killList.map((c)=>c.nick));

    return Promise.all(
        killList.map(
            (client) => client.kill()
        )
    );
}

ClientPool.prototype.setBot = function(server, client) {
    this._botClients[server.domain] = client;
};

ClientPool.prototype.getBot = function(server) {
    return this._botClients[server.domain];
};

ClientPool.prototype.createIrcClient = function(ircClientConfig, matrixUser, isBot) {
    var bridgedClient = this._ircBridge.createBridgedClient(
        ircClientConfig, matrixUser, isBot
    );
    var server = bridgedClient.server;

    if (this._virtualClients[server.domain] === undefined) {
        this._virtualClients[server.domain] = {
            nicks: Object.create(null),
            userIds: Object.create(null)
        };
    }
    if (isBot) {
        this._botClients[server.domain] = bridgedClient;
    }

    // add event listeners
    bridgedClient.on("client-connected", this._onClientConnected.bind(this));
    bridgedClient.on("client-disconnected", this._onClientDisconnected.bind(this));
    bridgedClient.on("nick-change", this._onNickChange.bind(this));
    bridgedClient.on("join-error", this._onJoinError.bind(this));

    // store the bridged client immediately in the pool even though it isn't
    // connected yet, else we could spawn 2 clients for a single user if this
    // function is called quickly.
    this._virtualClients[server.domain].userIds[bridgedClient.userId] = bridgedClient;

    // Does this server have a max clients limit? If so, check if the limit is
    // reached and start cycling based on oldest time.
    this._checkClientLimit(server);
    return bridgedClient;
};

ClientPool.prototype.getBridgedClientByUserId = function(server, userId) {
    if (!this._virtualClients[server.domain]) {
        return undefined;
    }
    var cli = this._virtualClients[server.domain].userIds[userId];
    if (!cli || cli.isDead()) {
        return undefined;
    }
    return cli;
};

ClientPool.prototype.getBridgedClientByNick = function(server, nick) {
    var bot = this.getBot(server);
    if (bot && bot.nick === nick) {
        return bot;
    }

    if (!this._virtualClients[server.domain]) {
        return undefined;
    }
    var cli = this._virtualClients[server.domain].nicks[nick];
    if (!cli || cli.isDead()) {
        return undefined;
    }
    return cli;
};

ClientPool.prototype.getBridgedClientsForUserId = function(userId) {
    var domainList = Object.keys(this._virtualClients);
    var clientList = [];
    domainList.forEach((domain) => {
        var cli = this._virtualClients[domain].userIds[userId];
        if (cli && !cli.isDead()) {
            clientList.push(cli);
        }
    });
    return clientList;
};

ClientPool.prototype._checkClientLimit = function(server) {
    if (server.getMaxClients() === 0) {
        return;
    }

    var numConnections = this._getNumberOfConnections(server);
    this._sendConnectionMetric(server);

    if (numConnections < server.getMaxClients()) {
        // under the limit, we're good for now.
        log.debug(
            "%s active connections on %s",
            numConnections, server.domain
        );
        return;
    }

    log.debug(
        "%s active connections on %s (limit %s)",
        numConnections, server.domain, server.getMaxClients()
    );

    // find the oldest client to kill.
    var oldest = null;
    Object.keys(this._virtualClients[server.domain].nicks).forEach((nick) => {
        var client = this._virtualClients[server.domain].nicks[nick];
        if (!client) {
            // possible since undefined/null values can be present from culled entries
            return;
        }
        if (client.isBot) {
            return; // don't ever kick the bot off.
        }
        if (oldest === null) {
            oldest = client;
            return;
        }
        if (client.getLastActionTs() < oldest.getLastActionTs()) {
            oldest = client;
        }
    });
    if (!oldest) {
        return;
    }
    // disconnect and remove mappings.
    this._removeBridgedClient(oldest);
    oldest.disconnect("Client limit exceeded: " + server.getMaxClients()).done(
    function() {
        log.info("Client limit exceeded: Disconnected %s on %s.",
            oldest.nick, oldest.server.domain);
    },
    function(e) {
        log.error("Error when disconnecting %s on server %s: %s",
            oldest.nick, oldest.server.domain, JSON.stringify(e));
    });
};

ClientPool.prototype._getNumberOfConnections = function(server) {
    if (!server || !this._virtualClients[server.domain]) { return 0; }

    var connectedNickMap = this._virtualClients[server.domain].nicks;

    var numConnectedNicks = Object.keys(connectedNickMap).filter(function(nick) {
        return Boolean(connectedNickMap[nick]); // remove 'undefined' values
    }).length;

    return numConnectedNicks;
};

ClientPool.prototype._sendConnectionMetric = function(server) {
    stats.ircClients(server.domain, this._getNumberOfConnections(server));
};

ClientPool.prototype._removeBridgedClient = function(bridgedClient) {
    var server = bridgedClient.server;
    this._virtualClients[server.domain].userIds[bridgedClient.userId] = undefined;
    this._virtualClients[server.domain].nicks[bridgedClient.nick] = undefined;

    if (bridgedClient.isBot) {
        this._botClients[server.domain] = undefined;
    }
};

ClientPool.prototype._onClientConnected = function(bridgedClient) {
    var server = bridgedClient.server;
    var oldNick = bridgedClient.nick;
    var actualNick = bridgedClient.unsafeClient.nick;

    // assign a nick to this client
    this._virtualClients[server.domain].nicks[actualNick] = bridgedClient;

    // informative logging
    if (oldNick !== actualNick) {
        log.debug("Connected with nick '%s' instead of desired nick '%s'",
            actualNick, oldNick);
    }
};

ClientPool.prototype._onClientDisconnected = function(bridgedClient) {
    this._removeBridgedClient(bridgedClient);
    this._sendConnectionMetric(bridgedClient.server);

    if (bridgedClient.explicitDisconnect) {
        // don't reconnect users which explicitly disconnected e.g. client
        // cycling, idle timeouts, leaving rooms, etc.
        return;
    }
    // Reconnect this user
    log.debug(
        "onClientDisconnected: <%s> Reconnecting %s@%s in %sms",
        bridgedClient._id, bridgedClient.nick, bridgedClient.server.domain, RECONNECT_TIME_MS
    );
    // change the client config to use the current nick rather than the desired nick. This
    // makes sure that the client attempts to reconnect with the *SAME* nick, and also draws
    // from the latest !nick change, as the client config here may be very very old.
    var cliConfig = bridgedClient.getClientConfig();
    cliConfig.setDesiredNick(bridgedClient.nick);

    var cli = this.createIrcClient(
        cliConfig, bridgedClient.matrixUser, bridgedClient.isBot
    );
    var chanList = bridgedClient.chanList;
    var self = this;
    // remove ref to the disconnected client so it can be GC'd. If we don't do this,
    // the timeout below holds it in a closure, preventing it from being GC'd.
    bridgedClient = undefined;
    setTimeout(function() {
        cli.connect().then(function() {
            log.info(
                "<%s> Reconnected %s@%s", cli._id, cli.nick, cli.server.domain
            );
            if (chanList.length > 0) {
                log.info("<%s> Rejoining %s channels", cli._id, chanList.length);
                chanList.forEach(function(c) {
                    cli.joinChannel(c);
                });
            }
            self._sendConnectionMetric(cli.server);
        }, function(e) {
            log.error(
                "<%s> Failed to reconnect %s@%s", cli._id, cli.nick, cli.server.domain
            );
        });
    }, RECONNECT_TIME_MS);
};

ClientPool.prototype._onNickChange = function(bridgedClient, oldNick, newNick) {
    this._virtualClients[bridgedClient.server.domain].nicks[oldNick] = undefined;
    this._virtualClients[bridgedClient.server.domain].nicks[newNick] = bridgedClient;
};

ClientPool.prototype._onJoinError = Promise.coroutine(function*(bridgedClient, chan, err) {
    var errorsThatShouldKick = [
        "err_bannedfromchan", // they aren't allowed in channels they are banned on.
        "err_inviteonlychan", // they aren't allowed in invite only channels
        "err_channelisfull", // they aren't allowed in if the channel is full
        "err_badchannelkey" // they aren't allowed in channels with a bad key
    ];
    if (errorsThatShouldKick.indexOf(err) === -1) {
        return;
    }
    if (!bridgedClient.userId || bridgedClient.isBot) {
        return; // the bot itself can get these join errors
    }
    // TODO: this is a bit evil, no one in their right mind would expect
    // the client pool to be kicking matrix users from a room :(
    log.info(`Kicking ${bridgedClient.userId} from room due to ${err}`);
    let matrixRooms = yield this._ircBridge.getStore().getMatrixRoomsForChannel(
        bridgedClient.server, chan
    );
    let promises = matrixRooms.map((room) => {
        return this._ircBridge.getAppServiceBridge().getIntent().kick(
            room.getId(), bridgedClient.userId, `IRC error on ${chan}: ${err}`
        );
    });
    yield Promise.all(promises);
});

module.exports = ClientPool;
<|endoftext|>


<commit_before>var Media = function(data) {
    this.id = data.id;
    this.type = data.type;
    this.lastdiff = 0;

    switch(this.type) {
        case "yt":
            this.initYouTube();
            break;
        case "vi":
            this.initVimeo();
            break;
        case "dm":
            this.initDailymotion();
            break;
        case "sc":
            this.initSoundcloud();
            break;
        case "li":
            this.initLivestream();
            break;
        case "tw":
            this.initTwitch();
            break;
        case "rt":
            this.initRTMP();
            break;
        default:
            break;
    }
}

Media.prototype.initYouTube = function() {
    this.removeOld();
    this.player = new YT.Player("ytapiplayer", {
        height: VHEIGHT,
        width: VWIDTH,
        videoId: this.id,
        playerVars: {
            "autoplay": 1,
            "controls": 1,
        },
        events: {
            onPlayerReady: function() {
                socket.emit("playerReady");
            },
            onStateChange: function(ev) {
                if(LEADER && ev.data == YT.PlayerState.ENDED) {
                    socket.emit("playNext");
                }
            }
        }
    });
    $("#ytapiplayer").css("border", "none");

    this.load = function(data) {
        if(this.player.loadVideoById) {
            this.player.loadVideoById(data.id, data.currentTime);
            this.id = data.id;
        }
    }

    this.pause = function() {
        this.player.pauseVideo();
    }

    this.play = function() {
        this.player.playVideo();
    }

    this.getTime = function(callback) {
        callback(this.player.getCurrentTime());
    }

    this.seek = function(time) {
        this.player.seekTo(time, true);
    }
}

Media.prototype.initVimeo = function() {
    var iframe = $("<iframe/>").insertBefore($("#ytapiplayer"));
    $("#ytapiplayer").remove();
    iframe.attr("id", "ytapiplayer");
    iframe.attr("width", VWIDTH);
    iframe.attr("height", VHEIGHT);
    iframe.attr("src", "http://player.vimeo.com/video/"+this.id+"?api=1&player_id=ytapiplayer");
    iframe.attr("webkitAllowFullScreen", "");
    iframe.attr("mozallowfullscreen", "");
    iframe.attr("allowFullScreen", "");
    iframe.css("border", "none");

    this.player = $f(iframe[0]);
    $f(iframe[0]).addEvent("ready", function() {
        this.player = $f(iframe[0]);
        this.player.api("play");

        this.player.addEvent("finish", function() {
            if(LEADER) {
                socket.emit("playNext");
            }
        });
    }.bind(this));

    this.load = function(data) {
        this.id = data.id;
        this.initVimeo();
    }

    this.pause = function() {
        this.player.api("pause");
    }

    this.play = function() {
        this.player.api("play");
    }

    this.getTime = function(callback) {
        this.player.api("getCurrentTime", callback);
    }

    this.seek = function(time) {
        this.player.api("seekTo", time);
    }
}

Media.prototype.initDailymotion = function() {
    this.removeOld();
    this.player = DM.player("ytapiplayer", {
        video: this.id,
        width: parseInt(VWIDTH),
        height: parseInt(VHEIGHT),
        params: {autoplay: 1}
    });

    this.player.addEventListener("ended", function(e) {
        if(LEADER) {
            socket.emit("playNext");
        }
    });

    this.load = function(data) {
        this.id = data.id;
        this.player.api("load", data.id);
    }

    this.pause = function() {
        this.player.api("pause");
    }

    this.play = function() {
        this.player.api("play");
    }

    this.getTime = function(callback) {
        callback(this.player.currentTime);
    }

    this.seek = function(seconds) {
        this.player.api("seek", seconds);
    }
}

Media.prototype.initSoundcloud = function() {
    unfixSoundcloudShit();
    var iframe = $("<iframe/>").insertBefore($("#ytapiplayer"));
    $("#ytapiplayer").remove();

    iframe.attr("id", "ytapiplayer");
    iframe.attr("src", "https://w.soundcloud.com/player/?url=" + this.id);
    iframe.css("width", "100%").attr("height", "166");
    iframe.css("border", "none");

    this.player = SC.Widget("ytapiplayer");
    this.player.load(this.id, {auto_play: true});

    this.player.bind(SC.Widget.Events.FINISH, function() {
        if(LEADER) {
            socket.emit("playNext");
        }
    });

    this.load = function(data) {
        this.id = data.id;
        this.player.load(data.id, {auto_play: true});
    }

    this.pause = function() {
        this.player.pause();
    }

    this.play = function() {
        this.player.play();
    }

    this.getTime = function(callback) {
        this.player.getPosition(function(pos) {
            callback(pos / 1000);
        });
    }

    this.seek = function(seconds) {
        this.player.seekTo(seconds * 1000);
    }
}

Media.prototype.initLivestream = function() {
    this.removeOld();
    var flashvars = {channel: this.id};
    var params = {AllowScriptAccess: "always"};
    swfobject.embedSWF("http://cdn.livestream.com/chromelessPlayer/v20/playerapi.swf", "ytapiplayer", VWIDTH, VHEIGHT, "9.0.0", "expressInstall.swf", flashvars, params);

    this.load = function(data) {
        this.id = data.id;
        this.initLivestream();
    }

    this.pause = function() { }

    this.play = function() { }

    this.getTime = function() { }

    this.seek = function() { }
}

Media.prototype.initTwitch = function() {
    this.removeOld();
    var url = "http://www.twitch.tv/widgets/live_embed_player.swf?channel="+this.id;
    var params = {
        allowFullScreen:"true",
        allowScriptAccess:"always",
        allowNetworking:"all",
        movie:"http://www.twitch.tv/widgets/live_embed_player.swf",
        id: "live_embed_player_flash",
        flashvars:"hostname=www.twitch.tv&channel="+this.id+"&auto_play=true&start_volume=100"
    };
    swfobject.embedSWF( url, "ytapiplayer", VWIDTH, VHEIGHT, "8", null, null, params, {} );

    this.load = function(data) {
        this.id = data.id;
        this.initTwitch();
    }

    this.pause = function() { }

    this.play = function() { }

    this.getTime = function() { }

    this.seek = function() { }
}

Media.prototype.initRTMP = function() {
    this.removeOld();
    var url = "http://fpdownload.adobe.com/strobe/FlashMediaPlayback_101.swf";
    var src = encodeURIComponent(this.id);
    var params = {
            allowFullScreen:"true",
            allowScriptAccess:"always",
            allowNetworking:"all",
            wMode:"direct",
            movie:"http://fpdownload.adobe.com/strobe/FlashMediaPlayback_101.swf",
            flashvars:"src="+src+"&streamType=live&autoPlay=true"
        };
        swfobject.embedSWF(url, "ytapiplayer", VWIDTH, VHEIGHT, "8", null, null, params, {} );

    this.load = function(data) {
        this.id = data.id;
        this.initTwitch();
    }

    this.pause = function() { }

    this.play = function() { }

    this.getTime = function() { }

    this.seek = function() { }
}

Media.prototype.update = function(data) {
    if(data.id != this.id) {
        if(data.currentTime < 0) {
            data.currentTime = 0;
        }
        this.load(data);
    }
    if(data.paused) {
        this.pause();
    }
    this.getTime(function(seconds) {
        var time = data.currentTime;
        if(readCookie("sync_compensate")) {
            var diff = time - seconds;
            if(diff > 0) {
                diff = diff > 5 ? 5 : diff;
                time += diff;
                diff = (diff + this.lastdiff) / 2 || 0;
                this.lastdiff = diff;
            }
        }
        if(Math.abs(data.currentTime - seconds) > SYNC_THRESHOLD) {
            if(!LEADER) {
                this.seek(time);
            }
        }
    }.bind(this));
}

Media.prototype.removeOld = function() {
    var old = $("#ytapiplayer");
    var placeholder = $("<div/>").insertBefore(old);
    old.remove();
    placeholder.attr("id", "ytapiplayer");
}
<commit_msg>Improve buffer compensation<commit_after>var Media = function(data) {
    this.id = data.id;
    this.type = data.type;
    this.diff = 0;

    switch(this.type) {
        case "yt":
            this.initYouTube();
            break;
        case "vi":
            this.initVimeo();
            break;
        case "dm":
            this.initDailymotion();
            break;
        case "sc":
            this.initSoundcloud();
            break;
        case "li":
            this.initLivestream();
            break;
        case "tw":
            this.initTwitch();
            break;
        case "rt":
            this.initRTMP();
            break;
        default:
            break;
    }
}

Media.prototype.initYouTube = function() {
    this.removeOld();
    this.player = new YT.Player("ytapiplayer", {
        height: VHEIGHT,
        width: VWIDTH,
        videoId: this.id,
        playerVars: {
            "autoplay": 1,
            "controls": 1,
        },
        events: {
            onPlayerReady: function() {
                socket.emit("playerReady");
            },
            onStateChange: function(ev) {
                if(LEADER && ev.data == YT.PlayerState.ENDED) {
                    socket.emit("playNext");
                }
            }
        }
    });
    $("#ytapiplayer").css("border", "none");

    this.load = function(data) {
        if(this.player.loadVideoById) {
            this.player.loadVideoById(data.id, data.currentTime);
            this.id = data.id;
        }
    }

    this.pause = function() {
        this.player.pauseVideo();
    }

    this.play = function() {
        this.player.playVideo();
    }

    this.getTime = function(callback) {
        callback(this.player.getCurrentTime());
    }

    this.seek = function(time) {
        this.player.seekTo(time, true);
    }
}

Media.prototype.initVimeo = function() {
    var iframe = $("<iframe/>").insertBefore($("#ytapiplayer"));
    $("#ytapiplayer").remove();
    iframe.attr("id", "ytapiplayer");
    iframe.attr("width", VWIDTH);
    iframe.attr("height", VHEIGHT);
    iframe.attr("src", "http://player.vimeo.com/video/"+this.id+"?api=1&player_id=ytapiplayer");
    iframe.attr("webkitAllowFullScreen", "");
    iframe.attr("mozallowfullscreen", "");
    iframe.attr("allowFullScreen", "");
    iframe.css("border", "none");

    this.player = $f(iframe[0]);
    $f(iframe[0]).addEvent("ready", function() {
        this.player = $f(iframe[0]);
        this.player.api("play");

        this.player.addEvent("finish", function() {
            if(LEADER) {
                socket.emit("playNext");
            }
        });
    }.bind(this));

    this.load = function(data) {
        this.id = data.id;
        this.initVimeo();
    }

    this.pause = function() {
        this.player.api("pause");
    }

    this.play = function() {
        this.player.api("play");
    }

    this.getTime = function(callback) {
        this.player.api("getCurrentTime", callback);
    }

    this.seek = function(time) {
        this.player.api("seekTo", time);
    }
}

Media.prototype.initDailymotion = function() {
    this.removeOld();
    this.player = DM.player("ytapiplayer", {
        video: this.id,
        width: parseInt(VWIDTH),
        height: parseInt(VHEIGHT),
        params: {autoplay: 1}
    });

    this.player.addEventListener("ended", function(e) {
        if(LEADER) {
            socket.emit("playNext");
        }
    });

    this.load = function(data) {
        this.id = data.id;
        this.player.api("load", data.id);
    }

    this.pause = function() {
        this.player.api("pause");
    }

    this.play = function() {
        this.player.api("play");
    }

    this.getTime = function(callback) {
        callback(this.player.currentTime);
    }

    this.seek = function(seconds) {
        this.player.api("seek", seconds);
    }
}

Media.prototype.initSoundcloud = function() {
    unfixSoundcloudShit();
    var iframe = $("<iframe/>").insertBefore($("#ytapiplayer"));
    $("#ytapiplayer").remove();

    iframe.attr("id", "ytapiplayer");
    iframe.attr("src", "https://w.soundcloud.com/player/?url=" + this.id);
    iframe.css("width", "100%").attr("height", "166");
    iframe.css("border", "none");

    this.player = SC.Widget("ytapiplayer");
    this.player.load(this.id, {auto_play: true});

    this.player.bind(SC.Widget.Events.FINISH, function() {
        if(LEADER) {
            socket.emit("playNext");
        }
    });

    this.load = function(data) {
        this.id = data.id;
        this.player.load(data.id, {auto_play: true});
    }

    this.pause = function() {
        this.player.pause();
    }

    this.play = function() {
        this.player.play();
    }

    this.getTime = function(callback) {
        this.player.getPosition(function(pos) {
            callback(pos / 1000);
        });
    }

    this.seek = function(seconds) {
        this.player.seekTo(seconds * 1000);
    }
}

Media.prototype.initLivestream = function() {
    this.removeOld();
    var flashvars = {channel: this.id};
    var params = {AllowScriptAccess: "always"};
    swfobject.embedSWF("http://cdn.livestream.com/chromelessPlayer/v20/playerapi.swf", "ytapiplayer", VWIDTH, VHEIGHT, "9.0.0", "expressInstall.swf", flashvars, params);

    this.load = function(data) {
        this.id = data.id;
        this.initLivestream();
    }

    this.pause = function() { }

    this.play = function() { }

    this.getTime = function() { }

    this.seek = function() { }
}

Media.prototype.initTwitch = function() {
    this.removeOld();
    var url = "http://www.twitch.tv/widgets/live_embed_player.swf?channel="+this.id;
    var params = {
        allowFullScreen:"true",
        allowScriptAccess:"always",
        allowNetworking:"all",
        movie:"http://www.twitch.tv/widgets/live_embed_player.swf",
        id: "live_embed_player_flash",
        flashvars:"hostname=www.twitch.tv&channel="+this.id+"&auto_play=true&start_volume=100"
    };
    swfobject.embedSWF( url, "ytapiplayer", VWIDTH, VHEIGHT, "8", null, null, params, {} );

    this.load = function(data) {
        this.id = data.id;
        this.initTwitch();
    }

    this.pause = function() { }

    this.play = function() { }

    this.getTime = function() { }

    this.seek = function() { }
}

Media.prototype.initRTMP = function() {
    this.removeOld();
    var url = "http://fpdownload.adobe.com/strobe/FlashMediaPlayback_101.swf";
    var src = encodeURIComponent(this.id);
    var params = {
            allowFullScreen:"true",
            allowScriptAccess:"always",
            allowNetworking:"all",
            wMode:"direct",
            movie:"http://fpdownload.adobe.com/strobe/FlashMediaPlayback_101.swf",
            flashvars:"src="+src+"&streamType=live&autoPlay=true"
        };
        swfobject.embedSWF(url, "ytapiplayer", VWIDTH, VHEIGHT, "8", null, null, params, {} );

    this.load = function(data) {
        this.id = data.id;
        this.initTwitch();
    }

    this.pause = function() { }

    this.play = function() { }

    this.getTime = function() { }

    this.seek = function() { }
}

Media.prototype.update = function(data) {
    console.log(parseInt(data.currentTime / 60), parseInt(data.currentTime % 60));
    if(data.id != this.id) {
        if(data.currentTime < 0) {
            data.currentTime = 0;
        }
        this.load(data);
    }
    if(data.paused) {
        this.pause();
    }
    if(LEADER) {
        return;
    }
    this.getTime(function(seconds) {
        var time = data.currentTime;
        var diff = time - seconds || time;

        var a = SYNC_THRESHOLD + 1;
        // If 2 updates in a row have lag, compensate for buffering
        if(diff >= a && diff <= 6 && this.diff >= a && this.diff <= 6) {
            this.seek(time + diff);
        }
        else if(diff < -2 || diff >= SYNC_THRESHOLD) {
            if(diff < 0) {
                this.seek(time + 0.5);
            }
            else {
                this.seek(time);
            }
        }
        this.diff = diff;
    }.bind(this));
}

Media.prototype.removeOld = function() {
    var old = $("#ytapiplayer");
    var placeholder = $("<div/>").insertBefore(old);
    old.remove();
    placeholder.attr("id", "ytapiplayer");
}
<|endoftext|>


<commit_before>'use strict';

var common              = require('./common');
var NIL                 = common.NIL;
var YAMLException       = require('./exception');
var DEFAULT_FULL_SCHEMA = require('./schema/default_full');
var DEFAULT_SAFE_SCHEMA = require('./schema/default_safe');

var _hasOwnProperty = Object.prototype.hasOwnProperty;

var CHAR_TAB                  = 0x09; /* Tab */
var CHAR_LINE_FEED            = 0x0A; /* LF */
var CHAR_CARRIAGE_RETURN      = 0x0D; /* CR */
var CHAR_SPACE                = 0x20; /* Space */
var CHAR_EXCLAMATION          = 0x21; /* ! */
var CHAR_DOUBLE_QUOTE         = 0x22; /* " */
var CHAR_SHARP                = 0x23; /* # */
var CHAR_PERCENT              = 0x25; /* % */
var CHAR_AMPERSAND            = 0x26; /* & */
var CHAR_SINGLE_QUOTE         = 0x27; /* ' */
var CHAR_ASTERISK             = 0x2A; /* * */
var CHAR_COMMA                = 0x2C; /* , */
var CHAR_MINUS                = 0x2D; /* - */
var CHAR_COLON                = 0x3A; /* : */
var CHAR_GREATER_THAN         = 0x3E; /* > */
var CHAR_QUESTION             = 0x3F; /* ? */
var CHAR_COMMERCIAL_AT        = 0x40; /* @ */
var CHAR_LEFT_SQUARE_BRACKET  = 0x5B; /* [ */
var CHAR_RIGHT_SQUARE_BRACKET = 0x5D; /* ] */
var CHAR_GRAVE_ACCENT         = 0x60; /* ` */
var CHAR_LEFT_CURLY_BRACKET   = 0x7B; /* { */
var CHAR_VERTICAL_LINE        = 0x7C; /* | */
var CHAR_RIGHT_CURLY_BRACKET  = 0x7D; /* } */

var ESCAPE_SEQUENCES = {};

ESCAPE_SEQUENCES[0x00]   = '\\0';
ESCAPE_SEQUENCES[0x07]   = '\\a';
ESCAPE_SEQUENCES[0x08]   = '\\b';
ESCAPE_SEQUENCES[0x09]   = '\\t';
ESCAPE_SEQUENCES[0x0A]   = '\\n';
ESCAPE_SEQUENCES[0x0B]   = '\\v';
ESCAPE_SEQUENCES[0x0C]   = '\\f';
ESCAPE_SEQUENCES[0x0D]   = '\\r';
ESCAPE_SEQUENCES[0x1B]   = '\\e';
ESCAPE_SEQUENCES[0x22]   = '\\"';
ESCAPE_SEQUENCES[0x5C]   = '\\\\';
ESCAPE_SEQUENCES[0x85]   = '\\N';
ESCAPE_SEQUENCES[0xA0]   = '\\_';
ESCAPE_SEQUENCES[0x2028] = '\\L';
ESCAPE_SEQUENCES[0x2029] = '\\P';

var DEPRECATED_BOOLEANS_SYNTAX = [
  'y', 'Y', 'yes', 'Yes', 'YES', 'on', 'On', 'ON',
  'n', 'N', 'no', 'No', 'NO', 'off', 'Off', 'OFF'
];

function kindOf(object) {
  var kind = typeof object;

  if (null === object) {
    return 'null';
  } else if ('number' === kind) {
    return 0 === object % 1 ? 'integer' : 'float';
  } else if ('object' === kind && Array.isArray(object)) {
    return 'array';
  } else {
    return kind;
  }
}

function compileStyleMap(schema, map) {
  var result, keys, index, length, tag, style, type;

  if (null === map) {
    return {};
  }

  result = {};
  keys = Object.keys(map);

  for (index = 0, length = keys.length; index < length; index += 1) {
    tag = keys[index];
    style = String(map[tag]);

    if ('!!' === tag.slice(0, 2)) {
      tag = 'tag:yaml.org,2002:' + tag.slice(2);
    }

    type = schema.compiledTypeMap[tag];

    if (type && type.dumper) {
      if (_hasOwnProperty.call(type.dumper.styleAliases, style)) {
        style = type.dumper.styleAliases[style];
      }
    }

    result[tag] = style;
  }

  return result;
}

function encodeHex(character) {
  var string, handle, length;

  string = character.toString(16).toUpperCase();

  if (character <= 0xFF) {
    handle = 'x';
    length = 2;
  } else if (character <= 0xFFFF) {
    handle = 'u';
    length = 4;
  } else if (character <= 0xFFFFFFFF) {
    handle = 'U';
    length = 8;
  } else {
    throw new YAMLException('code point within a string may not be greater than 0xFFFFFFFF');
  }

  return '\\' + handle + common.repeat('0', length - string.length) + string;
}

function dump(input, options) {
  options = options || {};

  var schema      = options['schema'] || DEFAULT_FULL_SCHEMA,
      indent      = Math.max(1, (options['indent'] || 2)),
      skipInvalid = options['skipInvalid'] || false,
      flowLevel   = (common.isNothing(options['flowLevel']) ? -1 : options['flowLevel']),
      styleMap    = compileStyleMap(schema, options['styles'] || null),

      implicitTypes = schema.compiledImplicit,
      explicitTypes = schema.compiledExplicit,

      kind,
      tag,
      result;

  function generateNextLine(level) {
    return '\n' + common.repeat(' ', indent * level);
  }

  function testImplicitResolving(object) {
    var index, length, type;

    for (index = 0, length = implicitTypes.length; index < length; index += 1) {
      type = implicitTypes[index];

      if (null !== type.loader &&
          NIL !== type.loader.resolver(object, false)) {
        return true;
      }
    }

    return false;
  }

  function writeScalar(object) {
    var isQuoted, checkpoint, position, length, character;

    result = '';
    isQuoted = false;
    checkpoint = 0;

    // Ensure compatibility with YAML 1.0/1.1 loaders.
    // TODO: This check should be moved into boolean type definition.
    if (-1 !== DEPRECATED_BOOLEANS_SYNTAX.indexOf(object)) {
      isQuoted = true;
    }

    if (0          === object.length ||
        CHAR_SPACE === object.charCodeAt(0) ||
        CHAR_SPACE === object.charCodeAt(object.length - 1)) {
      isQuoted = true;
    }

    for (position = 0, length = object.length; position < length; position += 1) {
      character = object.charCodeAt(position);

      if (!isQuoted) {
        if (CHAR_TAB                  === character ||
            CHAR_LINE_FEED            === character ||
            CHAR_CARRIAGE_RETURN      === character ||
            CHAR_COMMA                === character ||
            CHAR_LEFT_SQUARE_BRACKET  === character ||
            CHAR_RIGHT_SQUARE_BRACKET === character ||
            CHAR_LEFT_CURLY_BRACKET   === character ||
            CHAR_RIGHT_CURLY_BRACKET  === character ||
            CHAR_SHARP                === character ||
            CHAR_AMPERSAND            === character ||
            CHAR_ASTERISK             === character ||
            CHAR_EXCLAMATION          === character ||
            CHAR_VERTICAL_LINE        === character ||
            CHAR_GREATER_THAN         === character ||
            CHAR_SINGLE_QUOTE         === character ||
            CHAR_DOUBLE_QUOTE         === character ||
            CHAR_PERCENT              === character ||
            CHAR_COMMERCIAL_AT        === character ||
            CHAR_GRAVE_ACCENT         === character ||
            CHAR_QUESTION             === character ||
            CHAR_COLON                === character ||
            CHAR_MINUS                === character) {
          isQuoted = true;
        }
      }

      if (ESCAPE_SEQUENCES[character] ||
          !((0x00020 <= character && character <= 0x00007E) ||
            (0x00085 === character)                         ||
            (0x000A0 <= character && character <= 0x00D7FF) ||
            (0x0E000 <= character && character <= 0x00FFFD) ||
            (0x10000 <= character && character <= 0x10FFFF))) {
        result += object.slice(checkpoint, position);
        result += ESCAPE_SEQUENCES[character] || encodeHex(character);
        checkpoint = position + 1;
        isQuoted = true;
      }
    }

    if (checkpoint < position) {
      result += object.slice(checkpoint, position);
    }

    if (!isQuoted && testImplicitResolving(result)) {
      isQuoted = true;
    }

    if (isQuoted) {
      result = '"' + result + '"';
    }
  }

  function writeFlowSequence(level, object) {
    var _result = '',
        _tag    = tag,
        index,
        length;

    for (index = 0, length = object.length; index < length; index += 1) {
      // Write only valid elements.
      if (writeNode(level, object[index], false, false)) {
        if (0 !== index) {
          _result += ', ';
        }
        _result += result;
      }
    }

    tag = _tag;
    result = '[' + _result + ']';
  }

  function writeBlockSequence(level, object, compact) {
    var _result = '',
        _tag    = tag,
        index,
        length;

    for (index = 0, length = object.length; index < length; index += 1) {
      // Write only valid elements.
      if (writeNode(level + 1, object[index], true, true)) {
        if (!compact || 0 !== index) {
          _result += generateNextLine(level);
        }
        _result += '- ' + result;
      }
    }

    tag = _tag;
    result = _result || '[]'; // Empty sequence if no valid values.
  }

  function writeFlowMapping(level, object) {
    var _result       = '',
        _tag          = tag,
        objectKeyList = Object.keys(object),
        index,
        length,
        objectKey,
        objectValue,
        pairBuffer;

    for (index = 0, length = objectKeyList.length; index < length; index += 1) {
      pairBuffer = '';

      if (0 !== index) {
        pairBuffer += ', ';
      }

      objectKey = objectKeyList[index];
      objectValue = object[objectKey];

      if (!writeNode(level, objectKey, false, false)) {
        continue; // Skip this pair because of invalid key;
      }

      if (result.length > 1024) {
        pairBuffer += '? ';
      }

      pairBuffer += result + ': ';

      if (!writeNode(level, objectValue, false, false)) {
        continue; // Skip this pair because of invalid value.
      }

      pairBuffer += result;

      // Both key and value are valid.
      _result += pairBuffer;
    }

    tag = _tag;
    result = '{' + _result + '}';
  }

  function writeBlockMapping(level, object, compact) {
    var _result       = '',
        _tag          = tag,
        objectKeyList = Object.keys(object),
        index,
        length,
        objectKey,
        objectValue,
        explicitPair,
        pairBuffer;

    for (index = 0, length = objectKeyList.length; index < length; index += 1) {
      pairBuffer = '';

      if (!compact || 0 !== index) {
        pairBuffer += generateNextLine(level);
      }

      objectKey = objectKeyList[index];
      objectValue = object[objectKey];

      if (!writeNode(level + 1, objectKey, true, true)) {
        continue; // Skip this pair because of invalid key.
      }

      explicitPair = (null !== tag && '?' !== tag && result.length <= 1024);

      if (explicitPair) {
        pairBuffer += '? ';
      }

      pairBuffer += result;

      if (explicitPair) {
        pairBuffer += generateNextLine(level);
      }

      if (!writeNode(level + 1, objectValue, true, explicitPair)) {
        continue; // Skip this pair because of invalid value.
      }

      pairBuffer += ': ' + result;

      // Both key and value are valid.
      _result += pairBuffer;
    }

    tag = _tag;
    result = _result || '{}'; // Empty mapping if no valid pairs.
  }

  function detectType(object, explicit) {
    var _result, typeList, index, length, type, style;

    typeList = explicit ? explicitTypes : implicitTypes;
    kind = kindOf(object);

    for (index = 0, length = typeList.length; index < length; index += 1) {
      type = typeList[index];

      if ((null !== type.dumper) &&
          (null === type.dumper.kind       || kind === type.dumper.kind) &&
          (null === type.dumper.instanceOf || object instanceof type.dumper.instanceOf) &&
          (null === type.dumper.predicate  || type.dumper.predicate(object))) {
        tag = explicit ? type.tag : '?';

        if (null !== type.dumper.representer) {
          style = styleMap[type.tag] || type.dumper.defaultStyle;

          if ('function' === typeof type.dumper.representer) {
            _result = type.dumper.representer(object, style);
          } else if (_hasOwnProperty.call(type.dumper.representer, style)) {
            _result = type.dumper.representer[style](object, style);
          } else {
            throw new YAMLException('!<' + type.tag + '> tag resolver accepts not "' + style + '" style');
          }

          if (NIL !== _result) {
            kind = kindOf(_result);
            result = _result;
          } else {
            if (explicit) {
              throw new YAMLException('cannot represent an object of !<' + type.tag + '> type');
            } else {
              continue;
            }
          }
        }

        return true;
      }
    }

    return false;
  }

  // Serializes `object` and writes it to global `result`.
  // Returns true on success, or false on invalid object.
  //
  function writeNode(level, object, block, compact) {
    tag = null;
    result = object;

    if (!detectType(object, false)) {
      detectType(object, true);
    }

    if (block) {
      block = (0 > flowLevel || flowLevel > level);
    }

    if ((null !== tag && '?' !== tag) || (2 !== indent && level > 0)) {
      compact = false;
    }

    if ('object' === kind) {
      if (block && (0 !== Object.keys(result).length)) {
        writeBlockMapping(level, result, compact);
      } else {
        writeFlowMapping(level, result);
      }
    } else if ('array' === kind) {
      if (block && (0 !== result.length)) {
        writeBlockSequence(level, result, compact);
      } else {
        writeFlowSequence(level, result);
      }
    } else if ('string' === kind) {
      if ('?' !== tag) {
        writeScalar(result);
      }
    } else if (skipInvalid) {
      return false;
    } else {
      throw new YAMLException('unacceptabe kind of an object to dump (' + kind + ')');
    }

    if (null !== tag && '?' !== tag) {
      result = '!<' + tag + '> ' + result;
    }
    return true;
  }

  if (writeNode(0, input, true, true)) {
    return result + '\n';
  } else {
    return '';
  }
}

function safeDump(input, options) {
  return dump(input, common.extend({ schema: DEFAULT_SAFE_SCHEMA }, options));
}

module.exports.dump     = dump;
module.exports.safeDump = safeDump;
<commit_msg>Moved dumper states/functions to upper level<commit_after>'use strict';

var common              = require('./common');
var NIL                 = common.NIL;
var YAMLException       = require('./exception');
var DEFAULT_FULL_SCHEMA = require('./schema/default_full');
var DEFAULT_SAFE_SCHEMA = require('./schema/default_safe');

var _hasOwnProperty = Object.prototype.hasOwnProperty;

var CHAR_TAB                  = 0x09; /* Tab */
var CHAR_LINE_FEED            = 0x0A; /* LF */
var CHAR_CARRIAGE_RETURN      = 0x0D; /* CR */
var CHAR_SPACE                = 0x20; /* Space */
var CHAR_EXCLAMATION          = 0x21; /* ! */
var CHAR_DOUBLE_QUOTE         = 0x22; /* " */
var CHAR_SHARP                = 0x23; /* # */
var CHAR_PERCENT              = 0x25; /* % */
var CHAR_AMPERSAND            = 0x26; /* & */
var CHAR_SINGLE_QUOTE         = 0x27; /* ' */
var CHAR_ASTERISK             = 0x2A; /* * */
var CHAR_COMMA                = 0x2C; /* , */
var CHAR_MINUS                = 0x2D; /* - */
var CHAR_COLON                = 0x3A; /* : */
var CHAR_GREATER_THAN         = 0x3E; /* > */
var CHAR_QUESTION             = 0x3F; /* ? */
var CHAR_COMMERCIAL_AT        = 0x40; /* @ */
var CHAR_LEFT_SQUARE_BRACKET  = 0x5B; /* [ */
var CHAR_RIGHT_SQUARE_BRACKET = 0x5D; /* ] */
var CHAR_GRAVE_ACCENT         = 0x60; /* ` */
var CHAR_LEFT_CURLY_BRACKET   = 0x7B; /* { */
var CHAR_VERTICAL_LINE        = 0x7C; /* | */
var CHAR_RIGHT_CURLY_BRACKET  = 0x7D; /* } */

var ESCAPE_SEQUENCES = {};

ESCAPE_SEQUENCES[0x00]   = '\\0';
ESCAPE_SEQUENCES[0x07]   = '\\a';
ESCAPE_SEQUENCES[0x08]   = '\\b';
ESCAPE_SEQUENCES[0x09]   = '\\t';
ESCAPE_SEQUENCES[0x0A]   = '\\n';
ESCAPE_SEQUENCES[0x0B]   = '\\v';
ESCAPE_SEQUENCES[0x0C]   = '\\f';
ESCAPE_SEQUENCES[0x0D]   = '\\r';
ESCAPE_SEQUENCES[0x1B]   = '\\e';
ESCAPE_SEQUENCES[0x22]   = '\\"';
ESCAPE_SEQUENCES[0x5C]   = '\\\\';
ESCAPE_SEQUENCES[0x85]   = '\\N';
ESCAPE_SEQUENCES[0xA0]   = '\\_';
ESCAPE_SEQUENCES[0x2028] = '\\L';
ESCAPE_SEQUENCES[0x2029] = '\\P';

var DEPRECATED_BOOLEANS_SYNTAX = [
  'y', 'Y', 'yes', 'Yes', 'YES', 'on', 'On', 'ON',
  'n', 'N', 'no', 'No', 'NO', 'off', 'Off', 'OFF'
];

function kindOf(object) {
  var kind = typeof object;

  if (null === object) {
    return 'null';
  } else if ('number' === kind) {
    return 0 === object % 1 ? 'integer' : 'float';
  } else if ('object' === kind && Array.isArray(object)) {
    return 'array';
  } else {
    return kind;
  }
}

function compileStyleMap(schema, map) {
  var result, keys, index, length, tag, style, type;

  if (null === map) {
    return {};
  }

  result = {};
  keys = Object.keys(map);

  for (index = 0, length = keys.length; index < length; index += 1) {
    tag = keys[index];
    style = String(map[tag]);

    if ('!!' === tag.slice(0, 2)) {
      tag = 'tag:yaml.org,2002:' + tag.slice(2);
    }

    type = schema.compiledTypeMap[tag];

    if (type && type.dumper) {
      if (_hasOwnProperty.call(type.dumper.styleAliases, style)) {
        style = type.dumper.styleAliases[style];
      }
    }

    result[tag] = style;
  }

  return result;
}

function encodeHex(character) {
  var string, handle, length;

  string = character.toString(16).toUpperCase();

  if (character <= 0xFF) {
    handle = 'x';
    length = 2;
  } else if (character <= 0xFFFF) {
    handle = 'u';
    length = 4;
  } else if (character <= 0xFFFFFFFF) {
    handle = 'U';
    length = 8;
  } else {
    throw new YAMLException('code point within a string may not be greater than 0xFFFFFFFF');
  }

  return '\\' + handle + common.repeat('0', length - string.length) + string;
}

function State(options) {
  this.schema      = options['schema'] || DEFAULT_FULL_SCHEMA;
  this.indent      = Math.max(1, (options['indent'] || 2));
  this.skipInvalid = options['skipInvalid'] || false;
  this.flowLevel   = (common.isNothing(options['flowLevel']) ? -1 : options['flowLevel']);
  this.styleMap    = compileStyleMap(this.schema, options['styles'] || null);

  this.implicitTypes = this.schema.compiledImplicit;
  this.explicitTypes = this.schema.compiledExplicit;

  this.kind = null;
  this.tag = null;
  this.result = '';
}

function generateNextLine(state, level) {
  return '\n' + common.repeat(' ', state.indent * level);
}

function testImplicitResolving(state, object) {
  var index, length, type;

  for (index = 0, length = state.implicitTypes.length; index < length; index += 1) {
    type = state.implicitTypes[index];

    if (null !== type.loader &&
        NIL !== type.loader.resolver(object, false)) {
      return true;
    }
  }

  return false;
}

function writeScalar(state, object) {
  var isQuoted, checkpoint, position, length, character;

  state.result = '';
  isQuoted = false;
  checkpoint = 0;

  // Ensure compatibility with YAML 1.0/1.1 loaders.
  // TODO: This check should be moved into boolean type definition.
  if (-1 !== DEPRECATED_BOOLEANS_SYNTAX.indexOf(object)) {
    isQuoted = true;
  }

  if (0          === object.length ||
      CHAR_SPACE === object.charCodeAt(0) ||
      CHAR_SPACE === object.charCodeAt(object.length - 1)) {
    isQuoted = true;
  }

  for (position = 0, length = object.length; position < length; position += 1) {
    character = object.charCodeAt(position);

    if (!isQuoted) {
      if (CHAR_TAB                  === character ||
          CHAR_LINE_FEED            === character ||
          CHAR_CARRIAGE_RETURN      === character ||
          CHAR_COMMA                === character ||
          CHAR_LEFT_SQUARE_BRACKET  === character ||
          CHAR_RIGHT_SQUARE_BRACKET === character ||
          CHAR_LEFT_CURLY_BRACKET   === character ||
          CHAR_RIGHT_CURLY_BRACKET  === character ||
          CHAR_SHARP                === character ||
          CHAR_AMPERSAND            === character ||
          CHAR_ASTERISK             === character ||
          CHAR_EXCLAMATION          === character ||
          CHAR_VERTICAL_LINE        === character ||
          CHAR_GREATER_THAN         === character ||
          CHAR_SINGLE_QUOTE         === character ||
          CHAR_DOUBLE_QUOTE         === character ||
          CHAR_PERCENT              === character ||
          CHAR_COMMERCIAL_AT        === character ||
          CHAR_GRAVE_ACCENT         === character ||
          CHAR_QUESTION             === character ||
          CHAR_COLON                === character ||
          CHAR_MINUS                === character) {
        isQuoted = true;
      }
    }

    if (ESCAPE_SEQUENCES[character] ||
        !((0x00020 <= character && character <= 0x00007E) ||
          (0x00085 === character)                         ||
          (0x000A0 <= character && character <= 0x00D7FF) ||
          (0x0E000 <= character && character <= 0x00FFFD) ||
          (0x10000 <= character && character <= 0x10FFFF))) {
      state.result += object.slice(checkpoint, position);
      state.result += ESCAPE_SEQUENCES[character] || encodeHex(character);
      checkpoint = position + 1;
      isQuoted = true;
    }
  }

  if (checkpoint < position) {
    state.result += object.slice(checkpoint, position);
  }

  if (!isQuoted && testImplicitResolving(state, state.result)) {
    isQuoted = true;
  }

  if (isQuoted) {
    state.result = '"' + state.result + '"';
  }
}

function writeFlowSequence(state, level, object) {
  var _result = '',
      _tag    = state.tag,
      index,
      length;

  for (index = 0, length = object.length; index < length; index += 1) {
    // Write only valid elements.
    if (writeNode(state, level, object[index], false, false)) {
      if (0 !== index) {
        _result += ', ';
      }
      _result += state.result;
    }
  }

  state.tag = _tag;
  state.result = '[' + _result + ']';
}

function writeBlockSequence(state, level, object, compact) {
  var _result = '',
      _tag    = state.tag,
      index,
      length;

  for (index = 0, length = object.length; index < length; index += 1) {
    // Write only valid elements.
    if (writeNode(state, level + 1, object[index], true, true)) {
      if (!compact || 0 !== index) {
        _result += generateNextLine(state, level);
      }
      _result += '- ' + state.result;
    }
  }

  state.tag = _tag;
  state.result = _result || '[]'; // Empty sequence if no valid values.
}

function writeFlowMapping(state, level, object) {
  var _result       = '',
      _tag          = state.tag,
      objectKeyList = Object.keys(object),
      index,
      length,
      objectKey,
      objectValue,
      pairBuffer;

  for (index = 0, length = objectKeyList.length; index < length; index += 1) {
    pairBuffer = '';

    if (0 !== index) {
      pairBuffer += ', ';
    }

    objectKey = objectKeyList[index];
    objectValue = object[objectKey];

    if (!writeNode(state, level, objectKey, false, false)) {
      continue; // Skip this pair because of invalid key;
    }

    if (state.result.length > 1024) {
      pairBuffer += '? ';
    }

    pairBuffer += state.result + ': ';

    if (!writeNode(state, level, objectValue, false, false)) {
      continue; // Skip this pair because of invalid value.
    }

    pairBuffer += state.result;

    // Both key and value are valid.
    _result += pairBuffer;
  }

  state.tag = _tag;
  state.result = '{' + _result + '}';
}

function writeBlockMapping(state, level, object, compact) {
  var _result       = '',
      _tag          = state.tag,
      objectKeyList = Object.keys(object),
      index,
      length,
      objectKey,
      objectValue,
      explicitPair,
      pairBuffer;

  for (index = 0, length = objectKeyList.length; index < length; index += 1) {
    pairBuffer = '';

    if (!compact || 0 !== index) {
      pairBuffer += generateNextLine(state, level);
    }

    objectKey = objectKeyList[index];
    objectValue = object[objectKey];

    if (!writeNode(state, level + 1, objectKey, true, true)) {
      continue; // Skip this pair because of invalid key.
    }

    explicitPair = (null !== state.tag && '?' !== state.tag && state.result.length <= 1024);

    if (explicitPair) {
      pairBuffer += '? ';
    }

    pairBuffer += state.result;

    if (explicitPair) {
      pairBuffer += generateNextLine(state, level);
    }

    if (!writeNode(state, level + 1, objectValue, true, explicitPair)) {
      continue; // Skip this pair because of invalid value.
    }

    pairBuffer += ': ' + state.result;

    // Both key and value are valid.
    _result += pairBuffer;
  }

  state.tag = _tag;
  state.result = _result || '{}'; // Empty mapping if no valid pairs.
}

function detectType(state, object, explicit) {
  var _result, typeList, index, length, type, style;

  typeList = explicit ? state.explicitTypes : state.implicitTypes;
  state.kind = kindOf(object);

  for (index = 0, length = typeList.length; index < length; index += 1) {
    type = typeList[index];

    if ((null !== type.dumper) &&
        (null === type.dumper.kind       || state.kind === type.dumper.kind) &&
        (null === type.dumper.instanceOf || object instanceof type.dumper.instanceOf) &&
        (null === type.dumper.predicate  || type.dumper.predicate(object))) {
      state.tag = explicit ? type.tag : '?';

      if (null !== type.dumper.representer) {
        style = state.styleMap[type.tag] || type.dumper.defaultStyle;

        if ('function' === typeof type.dumper.representer) {
          _result = type.dumper.representer(object, style);
        } else if (_hasOwnProperty.call(type.dumper.representer, style)) {
          _result = type.dumper.representer[style](object, style);
        } else {
          throw new YAMLException('!<' + type.tag + '> tag resolver accepts not "' + style + '" style');
        }

        if (NIL !== _result) {
          state.kind = kindOf(_result);
          state.result = _result;
        } else {
          if (explicit) {
            throw new YAMLException('cannot represent an object of !<' + type.tag + '> type');
          } else {
            continue;
          }
        }
      }

      return true;
    }
  }

  return false;
}

// Serializes `object` and writes it to global `result`.
// Returns true on success, or false on invalid object.
//
function writeNode(state, level, object, block, compact) {
  state.tag = null;
  state.result = object;

  if (!detectType(state, object, false)) {
    detectType(state, object, true);
  }

  if (block) {
    block = (0 > state.flowLevel || state.flowLevel > level);
  }

  if ((null !== state.tag && '?' !== state.tag) || (2 !== state.indent && level > 0)) {
    compact = false;
  }

  if ('object' === state.kind) {
    if (block && (0 !== Object.keys(state.result).length)) {
      writeBlockMapping(state, level, state.result, compact);
    } else {
      writeFlowMapping(state, level, state.result);
    }
  } else if ('array' === state.kind) {
    if (block && (0 !== state.result.length)) {
      writeBlockSequence(state, level, state.result, compact);
    } else {
      writeFlowSequence(state, level, state.result);
    }
  } else if ('string' === state.kind) {
    if ('?' !== state.tag) {
      writeScalar(state, state.result);
    }
  } else if (state.skipInvalid) {
    return false;
  } else {
    throw new YAMLException('unacceptabe kind of an object to dump (' + state.kind + ')');
  }

  if (null !== state.tag && '?' !== state.tag) {
    state.result = '!<' + state.tag + '> ' + state.result;
  }
  return true;
}

function dump(input, options) {
  options = options || {};

  var state = new State(options);

  if (writeNode(state, 0, input, true, true)) {
    return state.result + '\n';
  } else {
    return '';
  }
}

function safeDump(input, options) {
  return dump(input, common.extend({ schema: DEFAULT_SAFE_SCHEMA }, options));
}

module.exports.dump     = dump;
module.exports.safeDump = safeDump;
<|endoftext|>


<commit_before>angular.module('citizen-engagement.newIssueCtrl', [])

        .controller('IssueTypesListCtrl',
                function ($scope, $http, apiUrl) {
                    $scope.loadIssueTypes = function () {
                        $http.get(apiUrl + '/issueTypes').success(function (issueTypes) {
                            $scope.issueTypes = issueTypes;
                            console.log(issueTypes);

                            index = 0;

                            while (index < issueTypes.length)
                            {
                                console.log(issueTypes[index].name);
                                $scope.currentIssueType = issueTypes[index].name;
                                index++;
                            }

                            console.log("test injection map");

                            console.log("Fin code test injection map");
                        });
                    };
                    $scope.loadIssueTypes();

                });
.controller("takePicture", function(CameraService, $http, qimgUrl, qimgToken) {
// take the picture
    CameraService.getPicture({
        quality: 75,
        targetWidth: 400,
        targetHeight: 300,
// return base64-encoded data instead of a file
        destinationType: Camera.DestinationType.DATA_URL}).then(function(imageData) {
// upload the image
    $http({
        method: "POST",
        url: qimgUrl + "/images",
        headers: {
        Authorization: "Bearer " + qimgToken
    },data: {
        data: imageData
    }
    }).success(function(data) {
    var imageUrl = data.url;
    // do something with imageUrl
    });
});
<commit_msg>oups retification du tir<commit_after>angular.module('citizen-engagement.newIssueCtrl', [])

        .controller('IssueTypesListCtrl',
                function ($scope, $http, apiUrl) {
                    $scope.loadIssueTypes = function () {
                        $http.get(apiUrl + '/issueTypes').success(function (issueTypes) {
                            $scope.issueTypes = issueTypes;
                            console.log(issueTypes);

                            index = 0;

                            while (index < issueTypes.length)
                            {
                                console.log(issueTypes[index].name);
                                $scope.currentIssueType = issueTypes[index].name;
                                index++;
                            }

                            console.log("test injection map");

                            console.log("Fin code test injection map");
                        });
                    };
                    $scope.loadIssueTypes();

                });

<|endoftext|>


<commit_before>/**
 *  class Juice.Response
 *
 *  A class representing state about the response to a request. Its internal
 *  fields closely resemble those of a JSGI response.
 **/

var Response = exports.Response = function Response( ctx ) {
  this.ctx = ctx;
  this.headers = {};
}

/**
 *  Juice.Response#status -> Number
 *
 *  HTTP status code for the response. If it 0 or not present then the default
 *  for the request will be used (usually 200, but might be different for
 *  special cases)
 **/

/**
 *  Juice.Response#body -> Array
 *
 *  Content of the response. If this is set then Juice's default rendinger of
 *  a template or JSON will be by-passed.
 **/

/**
 *  Juice.Response#headers -> Object
 *
 *  HTTP response headers. When merging, if a header is present already, its
 *  default value will not be used (i.e. the default value is not appeended to
 *  the existing header.)
 **/

/**
 *  Juice.Response#file -> String
 *
 *  Name of a file to send as the content of the response. If this field is
 *  present then [[Juice.Response#body]] will be ignored as will the default
 *  template rendering.
 *
 *  If there is no `last-modified` or `content-type` headers then they will be
 *  populated.
 **/

/**
 *  Juice.Response#template -> String
 *
 *  Override the default template to be rendered for this response.
 *
 *  If [[Juice.Response#body]] or [[Juice.Response#file]] are set then this
 *  field will be ignored.
 **/

/**
 *  Juice.Response#merge( defaults ) -> Juice.Response
 *  - defaults (Object): defaults to merge in.
 *
 *  Merge the default status, headers and body into the current state of the
 *  response. If any fields are already present (and truthful) they will be
 *  used. Otherwise the appropriate field from `defaults` is used.
 *
 *  Returns `this`;
 **/
Response.prototype.merge = function( defs ) {
  if ( !this.status ) this.status = defs.status;
  if ( !this.body ) this.body = defs.body;

  if ( typeof this.headers != "object" ) {
    // A bit of a sanity check
    throw new TypeError("Juice.Response#headers must be an object");
  }
  else {
    // Merge headers in
    for ( var h in defs.headers ) {
      if ( h in this.headers == false )
        this.headers[ h ] = defs.headers[ h ];
    }
  }

  return this;
}

Response.prototype.redirect = function( url, code ) {
  // TODO: should we call this.ctx.absUrlFor( url ) here?
  this.headers[ 'location' ] = this.ctx.absUrlFor( url );
  if ( code !== undefined ) this.status = code;
}

/**
 *  Juice.Response#reset( ) -> undefined
 *
 *  Reset the internal state of the response.
 **/
Response.prototype.reset = function() {
  for (var i in this) {
    if (i != "ctx" && this.hasOwnProperty(i)) delete this[i];
  }
  this.headers = {}
}
<commit_msg>Response#redirect defaults to status of 302<commit_after>/**
 *  class Juice.Response
 *
 *  A class representing state about the response to a request. Its internal
 *  fields closely resemble those of a JSGI response.
 **/

var Response = exports.Response = function Response( ctx ) {
  // Make it non-enumerable to avoid trivial loops
  Object.defineProperty(this, "ctx", { value: ctx, enumerable: false });
  this.headers = {};
}

/**
 *  Juice.Response#status -> Number
 *
 *  HTTP status code for the response. If it 0 or not present then the default
 *  for the request will be used (usually 200, but might be different for
 *  special cases)
 **/

/**
 *  Juice.Response#body -> Array
 *
 *  Content of the response. If this is set then Juice's default rendinger of
 *  a template or JSON will be by-passed.
 **/

/**
 *  Juice.Response#headers -> Object
 *
 *  HTTP response headers. When merging, if a header is present already, its
 *  default value will not be used (i.e. the default value is not appeended to
 *  the existing header.)
 **/

/**
 *  Juice.Response#file -> String
 *
 *  Name of a file to send as the content of the response. If this field is
 *  present then [[Juice.Response#body]] will be ignored as will the default
 *  template rendering.
 *
 *  If there is no `last-modified` or `content-type` headers then they will be
 *  populated.
 **/

/**
 *  Juice.Response#template -> String
 *
 *  Override the default template to be rendered for this response.
 *
 *  If [[Juice.Response#body]] or [[Juice.Response#file]] are set then this
 *  field will be ignored.
 **/

/**
 *  Juice.Response#merge( defaults ) -> Juice.Response
 *  - defaults (Object): defaults to merge in.
 *
 *  Merge the default status, headers and body into the current state of the
 *  response. If any fields are already present (and truthful) they will be
 *  used. Otherwise the appropriate field from `defaults` is used.
 *
 *  Returns `this`;
 **/
Response.prototype.merge = function( defs ) {
  if ( !this.status ) this.status = defs.status;
  if ( !this.body ) this.body = defs.body;

  if ( typeof this.headers != "object" ) {
    // A bit of a sanity check
    throw new TypeError("Juice.Response#headers must be an object");
  }
  else {
    // Merge headers in
    for ( var h in defs.headers ) {
      if ( h in this.headers == false )
        this.headers[ h ] = defs.headers[ h ];
    }
  }

  return this;
}

/**
 *  Juice.Response#redirect( url[, code=302 ] ) -> undefined
 *  - url (String): URL to redirect to.
 *  - code (Number): HTTP status code to set
 *
 *  `url` should be an absolute URL (as required by the HTTP spec). To achieve
 *  this it will be passed through [[Juice.Context#absUrlFor]], which will
 *  leave things that look like absolute URLs already unaltered.
 **/
Response.prototype.redirect = function( url, code ) {
  this.headers[ 'location' ] = this.ctx.absUrlFor( url );
  if ( code === undefined ) code = 302;
  this.status = code;
}

/**
 *  Juice.Response#reset( ) -> undefined
 *
 *  Reset the internal state of the response.
 **/
Response.prototype.reset = function() {
  for (var i in this) {
    if (i != "ctx" && this.hasOwnProperty(i)) delete this[i];
  }
  this.headers = {}
}
<|endoftext|>


<commit_before>require.config({
	shim: {
		'bootstrap': ['jquery'],
		'fullpage': ['jquery'],
		'jquery_qrcode': ['jquery'],
		'bootstrapValidator':['bootstrap'],
  		'slimScroll':['jquery']
    },
    paths: {
        jquery: '/jquery/dist/jquery.min',
        jscharts: '/scripts/jscharts',
        bootstrap:'/bootstrap/dist/js/bootstrap.min',
        fullpage:'/fullpage.js/jquery.fullPage',
        socketio:'/socket.io/socket.io',
        slimScroll:"/slimScroll/jquery.slimscroll.min",
        jquery_qrcode:'/jquery-qrcode/jquery.qrcode.min',
        bootstrapValidator:'/bootstrapvalidator/dist/js/bootstrapValidator.min',
    }
});

require(['jquery','socketio','jscharts','bootstrap','fullpage','jquery_qrcode','slimScroll'], function($,io) {

	$(function () {

		var ctm_data=null;
		var start_dati=false;
		var cur_yd_data=[];
		var yd_count=0;
		$('#loading_Modal').modal('show');

		var students=[];
		 // students=students.slice(0,index).concat(students.slice(index+1,students.length));

		function fullpagebuild () {
			// body...

			$('#fullpage').fullpage({
				anchors: ['page_login', 'page_beginanswer'],
				css3:true,
				paddingTop:"2px",
				loopHorizontal:false,
				// fixedElements:"#ctl_panel",
				controlArrowColor:"rgba(0,0,0,0)",
				scrollOverflow:true,
				// sectionsColor: ['#fff', 'gray', '#7BAABE', '#f90'],
				afterSlideLoad:function (anchorLink,	index,	slideIndex) {
					// console.log(anchorLink,	index,	slideIndex);
					if(getCurtmid()!=-1){
						da_cur_ti();
					}

				},
				afterLoad:function (anchorLink, index) {
					$("#navbar-nav>.active").removeClass("active");
					$("#navbar-nav>li>a[href=#"+anchorLink+"]").parent().addClass("active");
					console.log(anchorLink);
					if(getCurtmid()!=-1 && start_dati){
						da_cur_ti();
					}
					switch(anchorLink){
						case "page_login":
							// $(document).attr('title','学生二维码登录');
							$("#navbar").show(0);

							break;
						case "page_beginanswer":
							// $(document).attr('title','开始答题');
							$("#navbar").hide(0);

							break;
						default:

							break;
					}
					$(document).attr('title',$("#navbar-nav>.active").text());

				}
			});

		}
		fullpagebuild ();
		var socket = io.connect();

		socket.on('connecting', function(e) {
	           	console.log("正在连接。。。",e);
	        });

		socket.on('connect', function(e) {
	            console.log("连接成功", e);

	            setTimeout(function  () {

	            		socket.emit('teacher_login');
				$('#loading_Modal').modal('hide');

				socket.on("xs_dl",function (index,name,num) {
					students.push({name:name,num:num,serverindex:index});
					var xs_len=students.length;
					$("#xs_len").text(xs_len);
					var newli=$("");
					newli.text(name);
					newli.attr("id","xsli_"+num);
					$("#logined_users_box").append(	          $("
").append(newli)	);
				});

				socket.on("xs_xx",function (index,name,num) {
					students=students.slice(0,index).concat(students.slice(index+1,students.length));
					var xs_len=students.length;
					$("#xs_len").text(xs_len);
					$("#xsli_"+num).remove();
				});

	            },1000);

	        });

		socket.on('disconnect', function(e) {
	           	console.log("断开连接",e);
	        });

		socket.on('connect_failed', function(e) {
	           	console.log("连接失败",e);
	        });

		socket.on('error', function(e) {
	           	console.log("错误发生",e);
	        });

		socket.on('message', function(e) {
	           	console.log("message：",e);
	        });

		socket.on('anything', function(e) {
	           	console.log("anything:",e);
	        });

		socket.on('test', function(e) {
	           	console.log("test:",e);
	        });

		socket.on('tm_data', function(tm_data) {
	           	ctm_data=tm_data;

	           	console.log(ctm_data);
	           	var container=$("#tmlist_wraper");
	           	container.children().remove();
	           	ctm_data.forEach(function (item) {

	           		var slide=$("
");
	           		slide.addClass("slide");
	           		var tmbox=$("
");
	           		tmbox.addClass("tmbox");

	           		var content=$("
");
	           		content.text(item.content);

	           		var xxbox=$("
");
	           		item.answer.forEach(function (item) {
	           			var xx=$("
");
	           			xx.text(item.xx)
	           			// xx.attr("is_right")
	           			xxbox.append(xx);
	           		});

	           		tmbox.append(content).append(xxbox);
	           		slide.append(tmbox).appendTo(container);

	           	});

	           	$.fn.fullpage.destroy("all")
	           	fullpagebuild ();
	           	$('#loading_Modal').modal('hide');
	           	$.fn.fullpage.moveTo("page_beginanswer");
	           	start_dati=true;
	           	//da_cur_ti ();

	        });

		socket.on('yd_data', function(num,xx_index) {
	        yd_count++;
	        cur_yd_data.push({num:num,xx_index:xx_index});
	        var p=(yd_count/$("#logined_users_box").children().length)*100;
	        console.log( p);
	        $("#p_yd").css("width",p+"%");
	        if(p>=100){
	        	$("#btn_yd").click();
	        }
	    });

		socket.on('loginFaild', function(e) {
	           	alert("错误!\n"+e);
	           	$("body").remove();
	       });

		$("ul[aria-labelledby=dropdownMenu2]>li").click(function () {
			console.log($(this).text());
			$("#p_group").val($(this).text());
		});

		$("#btn_yd").click(function () {
			var text=$(this).text();
			if(text=="停止应答"){
				socket.emit("stop_yd",getCurtmid());
				console.log(cur_yd_data);

				$('#yd_result_content').text("正在计算应答数据中。。。");

				var xxdata= ctm_data[getCurtmid()].answer;

				var data=cur_yd_data;

				var myData=[];								//这是定义好的将会传给插件的数据，暂时上空数据

				xxdata.forEach(function (item) {
					item.yd=0;
				})

				data.forEach(function (item) {				//用选项数据 和应答数据填充
					var i=item.xx_index;
					xxdata[i].yd++;
					// console.log(xxdata[i].yd);
					// body...									//这里写转换代码
				});

				xxdata.forEach(function (item) {
					myData.push([		item.xx,		item.yd	]);
				});

				// var myData = new Array(['是', 2], ['不是', 1], ['不确定', 3]);			要把数据封装成这这种格式
				var colors = ['#AF0202', '#EC7A00', '#FCD200', '#81C714','#AF0202', '#EC7A00', '#FCD200', '#81C714'].slice(0,xxdata.length);
				var myChart = new JSChart('yd_result_content', 'bar');
				myChart.setDataArray(myData);
				myChart.colorizeBars(colors);
				myChart.setTitle('选项结果矩形图');
				myChart.setTitleColor('#8E8E8E');
				myChart.setAxisNameX('');
				myChart.setAxisNameY('%');
				myChart.setAxisColor('#C4C4C4');
				myChart.setAxisNameFontSize(16);
				myChart.setAxisNameColor('#999');
				myChart.setAxisValuesColor('#7E7E7E');
				myChart.setBarValuesColor('#7E7E7E');
				myChart.setAxisPaddingTop(60);
				myChart.setAxisPaddingRight(140);
				myChart.setAxisPaddingLeft(150);
				myChart.setAxisPaddingBottom(40);
				myChart.setTextPaddingLeft(105);
				myChart.setTitleFontSize(11);
				myChart.setBarBorderWidth(1);
				myChart.setBarBorderColor('#C4C4C4');
				myChart.setBarSpacingRatio(50);
				myChart.setGrid(false);
				myChart.setSize(580, 321);
				myChart.setBackgroundImage('/images/chart_bg.jpg');
				setTimeout(function() {
					myChart.draw();
				},30);

				$('#yd_result').modal('show');

				$("#btn_yd").text("下一题");

				var time_end=3;

				$("#btn_yd_next").text(time_end+" 秒后开始下一题，点击取消自动");
				var  tid=setInterval(function(argument) {
					time_end--;
					$("#btn_yd_next").text(time_end+" 秒后开始下一题，点击取消自动");

					if(time_end==0){
						clearInterval(tid);
						$("#btn_yd_next").text("下一题");
						//$("#btn_yd").removeAttr("disabled");
						//socket.emit("start_yd",getCurtmid());

							 if($("#btn_yd").text()=="下一题")
								$("#btn_yd").click();

								// da_cur_ti ();

					}

				},1000);

				$("#btn_yd_next").unbind( "click" );
				$("#btn_yd_next").click(function  () {
					clearInterval(tid);
					$("#btn_yd_next").unbind( "click" );
					$("#btn_yd_next").text("下一题");
					$("#btn_yd_next").click(function  () {

						if($("#btn_yd").text()=="下一题")
								$("#btn_yd").click();

					});

				});

			}else if(text=="下一题"){
				$.fn.fullpage.moveSlideRight();
				$('#yd_result').modal('hide');
				$("#p_yd").css("width","0%");

				// da_cur_ti ();
			}
		});

		$("#btn_beginanswer").click(function () {
			$("#ctl_panel").show();
			$("#tip_content").text("正在加载题目数据。。。");
			$('#loading_Modal').modal('show');
			// $('#fullpage').fullpage.moveTo("page_beginanswer");
			socket.emit("get_tm_data","default");

			//return false;
		});

		var xsdlurl=window.location.protocol+"//"+window.location.host+"/xs.html";
		$('#login_bincode').qrcode(xsdlurl);
		console.log(xsdlurl);

		function da_cur_ti () {
					if(start_dati) {
						$("#p_tm").width(100*(getCurtmid()+1)/ ctm_data.length+"%");
						cur_yd_data=[];
						var time_end=1;
						console.log(getCurtmid ());
						$("#btn_yd").attr("disabled","disabled");
						$("#btn_yd").text(time_end+" 秒后开始应答");
						var  tid=setInterval(function(argument) {
							time_end--;
							$("#btn_yd").text(time_end+" 秒后开始应答");

							if(time_end==0){
								clearInterval(tid);
								$("#btn_yd").text("停止应答");
								$("#btn_yd").removeAttr("disabled");
								socket.emit("start_yd",getCurtmid());
								yd_count=0;

							}

						},1000);
					}
		}

		function getCurtmid () {
			var r=/#page_beginanswer\/?(\d*)/.exec(location.hash);
			if(r) {
				if(r[1]!="") {
					return +r[1];
				}else{
					return 0;
				}
			}else{
				return -1;
			}
		}

	});

});

<commit_msg>meihua<commit_after>require.config({
	shim: {
		'bootstrap': ['jquery'],
		'fullpage': ['jquery'],
		'jquery_qrcode': ['jquery'],
		'bootstrapValidator':['bootstrap'],
  		'slimScroll':['jquery']
    },
    paths: {
        jquery: '/jquery/dist/jquery.min',
        jscharts: '/scripts/jscharts',
        bootstrap:'/bootstrap/dist/js/bootstrap.min',
        fullpage:'/fullpage.js/jquery.fullPage',
        socketio:'/socket.io/socket.io',
        slimScroll:"/slimScroll/jquery.slimscroll.min",
        jquery_qrcode:'/jquery-qrcode/jquery.qrcode.min',
        bootstrapValidator:'/bootstrapvalidator/dist/js/bootstrapValidator.min',
    }
});

require(['jquery','socketio','jscharts','bootstrap','fullpage','jquery_qrcode','slimScroll'], function($,io) {

	$(function () {

		var ctm_data=null;
		var start_dati=false;
		var cur_yd_data=[];
		var yd_count=0;
		$('#loading_Modal').modal('show');

		var students=[];
		 // students=students.slice(0,index).concat(students.slice(index+1,students.length));

		function fullpagebuild () {
			// body...

			$('#fullpage').fullpage({
				anchors: ['page_login', 'page_beginanswer'],
				css3:true,
				paddingTop:"2px",
				loopHorizontal:false,
				// fixedElements:"#ctl_panel",
				controlArrowColor:"rgba(0,0,0,0)",
				scrollOverflow:true,
				// sectionsColor: ['#fff', 'gray', '#7BAABE', '#f90'],
				afterSlideLoad:function (anchorLink,	index,	slideIndex) {
					// console.log(anchorLink,	index,	slideIndex);
					if(getCurtmid()!=-1){
						da_cur_ti();
					}

				},
				afterLoad:function (anchorLink, index) {
					$("#navbar-nav>.active").removeClass("active");
					$("#navbar-nav>li>a[href=#"+anchorLink+"]").parent().addClass("active");
					console.log(anchorLink);
					if(getCurtmid()!=-1 && start_dati){
						da_cur_ti();
					}
					switch(anchorLink){
						case "page_login":
							// $(document).attr('title','学生二维码登录');
							$("#navbar").show(0);

							break;
						case "page_beginanswer":
							// $(document).attr('title','开始答题');
							$("#navbar").hide(0);

							break;
						default:

							break;
					}
					$(document).attr('title',$("#navbar-nav>.active").text());

				}
			});

		}
		fullpagebuild ();
		var socket = io.connect();

		socket.on('connecting', function(e) {
	           	console.log("正在连接。。。",e);
	        });

		socket.on('connect', function(e) {
	            console.log("连接成功", e);

	            setTimeout(function  () {

	            		socket.emit('teacher_login');
				$('#loading_Modal').modal('hide');

				socket.on("xs_dl",function (index,name,num) {
					students.push({name:name,num:num,serverindex:index});
					var xs_len=students.length;
					$("#xs_len").text(xs_len);
					var newli=$("");
					newli.text(name);
					newli.attr("id","xsli_"+num);
					$("#logined_users_box").append(	          $("
").append(newli)	);
				});

				socket.on("xs_xx",function (index,name,num) {
					students=students.slice(0,index).concat(students.slice(index+1,students.length));
					var xs_len=students.length;
					$("#xs_len").text(xs_len);
					$("#xsli_"+num).remove();
				});

	            },1000);

	        });

		socket.on('disconnect', function(e) {
	           	console.log("断开连接",e);
	        });

		socket.on('connect_failed', function(e) {
	           	console.log("连接失败",e);
	        });

		socket.on('error', function(e) {
	           	console.log("错误发生",e);
	        });

		socket.on('message', function(e) {
	           	console.log("message：",e);
	        });

		socket.on('anything', function(e) {
	           	console.log("anything:",e);
	        });

		socket.on('test', function(e) {
	           	console.log("test:",e);
	        });

		socket.on('tm_data', function(tm_data) {
	           	ctm_data=tm_data;

	           	console.log(ctm_data);
	           	var container=$("#tmlist_wraper");
	           	container.children().remove();
	           	ctm_data.forEach(function (item) {

	           		var slide=$("
");
	           		slide.addClass("slide");
	           		var tmbox=$("
");
	           		tmbox.addClass("tmbox");

	           		var content=$("
");
	           		content.text(item.content);

	           		var xxbox=$("
");
	           		item.answer.forEach(function (item) {
	           			var xx=$("
");
	           			xx.text(item.xx)
	           			// xx.attr("is_right")
	           			xxbox.append(xx);
	           		});

	           		tmbox.append(content).append(xxbox);
	           		slide.append(tmbox).appendTo(container);

	           	});

	           	$.fn.fullpage.destroy("all")
	           	fullpagebuild ();
	           	$('#loading_Modal').modal('hide');
	           	$.fn.fullpage.moveTo("page_beginanswer");
	           	start_dati=true;
	           	//da_cur_ti ();

	        });

		socket.on('yd_data', function(num,xx_index) {
	        yd_count++;
	        cur_yd_data.push({num:num,xx_index:xx_index});
	        var p=(yd_count/$("#logined_users_box").children().length)*100;
	        console.log( p);
	        $("#p_yd").css("width",p+"%");
	        if(p>=100){
	        	$("#btn_yd").click();
	        }
	    });

		socket.on('loginFaild', function(e) {
	           	alert("错误!\n"+e);
	           	$("body").remove();
	       });

		$("ul[aria-labelledby=dropdownMenu2]>li").click(function () {
			console.log($(this).text());
			$("#p_group").val($(this).text());
		});

		$("#btn_yd").click(function () {
			var text=$(this).text();
			if(text=="停止应答"){
				socket.emit("stop_yd",getCurtmid());
				console.log(cur_yd_data);

				$('#yd_result_content').text("正在计算应答数据中。。。");

				var xxdata= ctm_data[getCurtmid()].answer;

				var data=cur_yd_data;

				var myData=[];								//这是定义好的将会传给插件的数据，暂时上空数据

				xxdata.forEach(function (item) {
					item.yd=0;
				})

				data.forEach(function (item) {				//用选项数据 和应答数据填充
					var i=item.xx_index;
					xxdata[i].yd++;
					// console.log(xxdata[i].yd);
					// body...									//这里写转换代码
				});

				xxdata.forEach(function (item) {
					myData.push([		item.xx,		item.yd	]);
				});

				// var myData = new Array(['是', 2], ['不是', 1], ['不确定', 3]);			要把数据封装成这这种格式
				var colors = ['#AF0202', '#EC7A00', '#FCD200', '#81C714','#AF0202', '#EC7A00', '#FCD200', '#81C714'].slice(0,xxdata.length);
				var myChart = new JSChart('yd_result_content', 'bar');
				myChart.setDataArray(myData);
				myChart.colorizeBars(colors);
				myChart.setTitle('选项结果矩形图');
				myChart.setTitleColor('#8E8E8E');
				myChart.setAxisNameX('');
				myChart.setAxisNameY('%');
				myChart.setAxisColor('#C4C4C4');
				myChart.setAxisNameFontSize(16);
				myChart.setAxisNameColor('#999');
				myChart.setAxisValuesColor('#7E7E7E');
				myChart.setBarValuesColor('#7E7E7E');
				myChart.setAxisPaddingTop(60);
				myChart.setAxisPaddingRight(140);
				myChart.setAxisPaddingLeft(150);
				myChart.setAxisPaddingBottom(40);
				myChart.setTextPaddingLeft(105);
				myChart.setTitleFontSize(11);
				myChart.setBarBorderWidth(1);
				myChart.setBarBorderColor('#C4C4C4');
				myChart.setBarSpacingRatio(50);
				myChart.setGrid(false);
				myChart.setSize(580, 321);
				myChart.setBackgroundImage('/images/chart_bg.jpg');
				setTimeout(function() {
					myChart.draw();
				},30);

				$('#yd_result').modal('show');

				$("#btn_yd").text("下一题");

				var time_end=2;

				$("#btn_yd_next").text(time_end+" 秒后开始下一题，点击取消自动");
				var  tid=setInterval(function(argument) {
					time_end--;
					$("#btn_yd_next").text(time_end+" 秒后开始下一题，点击取消自动");

					if(time_end==0){
						clearInterval(tid);
						$("#btn_yd_next").text("下一题");
						//$("#btn_yd").removeAttr("disabled");
						//socket.emit("start_yd",getCurtmid());

							 if($("#btn_yd").text()=="下一题")
								$("#btn_yd").click();

								// da_cur_ti ();

					}

				},1000);

				$("#btn_yd_next").unbind( "click" );
				$("#btn_yd_next").click(function  () {
					clearInterval(tid);
					$("#btn_yd_next").unbind( "click" );
					$("#btn_yd_next").text("下一题");
					$("#btn_yd_next").click(function  () {

						if($("#btn_yd").text()=="下一题")
								$("#btn_yd").click();

					});

				});

			}else if(text=="下一题"){
				$.fn.fullpage.moveSlideRight();
				$('#yd_result').modal('hide');
				$("#p_yd").css("width","0%");

				// da_cur_ti ();
			}
		});

		$("#btn_beginanswer").click(function () {
			$("#ctl_panel").show();
			$("#tip_content").text("正在加载题目数据。。。");
			$('#loading_Modal').modal('show');
			// $('#fullpage').fullpage.moveTo("page_beginanswer");
			socket.emit("get_tm_data","default");

			//return false;
		});

		var xsdlurl=window.location.protocol+"//"+window.location.host+"/xs.html";
		$('#login_bincode').qrcode(xsdlurl);
		console.log(xsdlurl);

		function da_cur_ti () {
					if(start_dati) {
						$("#p_tm").width(100*(getCurtmid()+1)/ ctm_data.length+"%");
						cur_yd_data=[];
						var time_end=0;
						console.log(getCurtmid ());
						$("#btn_yd").attr("disabled","disabled");
						$("#btn_yd").text(time_end+" 秒后开始应答");
						var  tid=setInterval(function(argument) {

							$("#btn_yd").text(time_end+" 秒后开始应答");
							time_end--;

							if(time_end<=0){
								clearInterval(tid);
								$("#btn_yd").text("停止应答");
								$("#btn_yd").removeAttr("disabled");
								socket.emit("start_yd",getCurtmid());
								yd_count=0;

							}

						},1000);
					}
		}

		function getCurtmid () {
			var r=/#page_beginanswer\/?(\d*)/.exec(location.hash);
			if(r) {
				if(r[1]!="") {
					return +r[1];
				}else{
					return 0;
				}
			}else{
				return -1;
			}
		}

	});

});

<|endoftext|>