<commit_before>/**
 * Code for all the controllers as well as the app controller
 */

jQuery(function($) {

    window.TenChordApp = Spine.Controller.create({
        el: $("#wrapper"),

        proxied: ["render", "confirmed"],

        events: {
            "click #next-btn": "next",
            "click #prev-btn": "prev",
            "click #confirm-guess": "confirm"
        },

        elements: {
            "#score-board": "scoreboard",
            "#question": "question",
            "#next-btn": "nextBtn",
            "#prev-btn": "prevBtn",
            "#confirm-guess": "confirmBtn",
            "#buttons a": "controlButtons"
        },

        init: function () {
            // create the note buttons
            this.notePicker = NotePicker.init();
            this.scoreboard = Scoreboard.init();
            ChordModel.bind("create", this.render);
            ChordModel.bind("update", this.confirmed);
            this.chord = OneChord.init();
            // show the first chord right away
            ChordModel.factory();
        },

        /**
         * next chord
         * if next present shown, else create new
         */
        next: function () {
            var next = this.chord.current.next();
            if (next) {
                this.render(next);
                return;
            } else {
                ChordModel.factory();
            }
        },

        /**
         * show the previous chord
         * not present case is impossible. So defensively throw an Error
         */
        prev: function () {
            var prev = this.chord.current.prev();
            if (prev) {
                this.render(prev);
                return;
            } else {
                throw new Error('Previous chord not found?!');
            }
        },

        /**
         * Render the chord on the screen
         * @param ChordModel record
         */
        render: function (chord) {
            this.chord.change(chord);
            this.updateButtons();
            this.notePicker.change(chord);
            return false;
        },

        /**
         * on click of the confirm/roll button
         * will be used to confirm the guess made by the user.
         * ..for both the attempts
         */
        confirm: function () {
            var guess = this.notePicker.getMarked("guessed");
            if (!guess[0]) {
                alert("Please select some notes by clicking on them");
                return;
            }
            this.chord.saveGuess(guess);
        },

        /**
         * Will be called after a guess has been confirmed.
         * Callback function of the update event of ChordModel
         */
        confirmed: function (chord) {
            var score = ScoreModel.find(chord.score_id);
            this.scoreboard.update(score);
            switch (chord.num_attempt) {
            case 2:
                // no more guesses allowed for this chord
                console.log("both guesses consumed");
                break;
            case 1:
                // 1 more guess to go
                console.log("1 more guess to go");
                break;
            case 0:
            default:
                return;
            }
            this.updateButtons();
            this.notePicker.updateStatuses(chord);
        },

        /**
         * Method to update the states of the previous, next and the roll
         * buttons for this chord
         * if its the first chord, hide the prev button
         * if its the last (10th) chord, hide the next button
         * if its a strike show the next button and hide roll
         */
        updateButtons: function () {
            // hide all buttons first
            this.controlButtons.hide();
            this.confirmBtn.show();
            var chord = this.chord.current;
            // if not last AND if all attempts consumed
            if (!chord.is_last() && !chord.can_guess()) {
                this.nextBtn.show();
            }
            // if not first, show "prev" button
            if (!chord.is_first()) {
                this.prevBtn.show();
            }
        }
    });

    window.OneChord = Spine.Controller.create({
        el: $("h2#question"),

        init: function () {

        },

        /**
         * Change the current chord
         */
        change: function (item) {
            this.current = item;
            this.render();
        },

        render: function () {
            this.el.text(this.current.name);
            var $list = $("#chord-list");
            $list.children().removeClass('active');
            // append to the chord list if its a new chord
            if (!$("#pk-"+this.current.pk).length) {
                var elements = $("#chordlistTemplate").tmpl(this.current);
                $list.append(elements[0]);
            } else {
                $("#pk-"+this.current.pk).addClass('active');
            }
        },

        saveGuess: function (guess) {
            this.current.evaluate(guess);
        }
    });

    window.NotePicker = Spine.Controller.create({
        el: $("ul#notes"),

        elements: {
            "#notes li": "button"
        },

        events: {
            "click #notes li": "toggleGuess"
        },

        proxied: ["toggleGuess", "onGuess"],

        NOTE_STATUS: {
            guessed: "guessed-note",
            correct: "correct-note",
            incorrect: "incorrect_note"
        },

        init: function () {
            this.render();
            ScoreModel.bind("update", this.onGuess);
        },

        render: function () {
            var html = '',
            n;
            for (var i in Notes.names) {
                n = Notes.names[i];
                html += '
' + n + '
';
            }
            this.el.append(html);
        },

        /**
         * Will mark and unmark the clicked note as guessed note
         */
        toggleGuess: function (event) {
            var $trgt = $(event.target);
            if (!$trgt.hasClass(this.NOTE_STATUS.correct)) {
                $(event.target).toggleClass(this.NOTE_STATUS.guessed);
            }
        },

        /**
         * Will clear all the guessed notes
         */
        clear: function () {
            var statuses = this.NOTE_STATUS;
            this.el.children().each(function () {
                $(this).removeClass(statuses.guessed + ' ' + statuses.correct + ' ' + statuses.incorrect);
            });
        },

        /**
         * When a chord is changed, the buttons will be
         * marked/unmarked accordingly
         */
        change: function (chord) {
            this.clear();
            this.updateStatuses(chord);
        },

        /**
         * Update the statuses of the notes everytime a chord is changed
         * or a guess is made
         * statuses = ('guesses', 'correct', 'incorrect')
         * @param Chord_Model chord
         */
        updateStatuses: function (chord) {
            // console.log(chord);
            if (chord.guess) {
                this.mark(chord.guess, 'guessed');
            }
            if (chord.correct) {
                this.mark(chord.correct, 'correct');
            }
        },

        /**
         * after the user makes a guess, this method will be
         * called as a callback of update event of the
         * ScoreModel object
         * Depending upon the correctness of the guesses, the
         * notes will be highlighted
         */
        onGuess: function (score) {
            // console.log(this.currentChord);
        },

        /**
         * will mark the note as guessed by the user
         * @param name - string - name of the note to be marked
         * @param status - string - status it is to be marked as
         */
        mark: function (notes, status) {
            if (typeof notes === 'string') {
                var name = notes,
                class_attr = this.NOTE_STATUS[status];
                $("#"+Notes.slugify(name)).addClass(class_attr);
            } else if (typeof notes === 'object') {
                for (var i = 0; i < notes.length; i++) {
                    this.mark(notes[i], status);
                }
            }
        },

        getMarked: function (status) {
            var marked = [],
            class_attr = this.NOTE_STATUS[status];
            this.el.children().filter("."+class_attr).each(function () {
                marked.push(Notes.unslugify($(this).attr('id')));
            });
            return marked;
        },

    });

    window.Scoreboard = Spine.Controller.create({
        el: $("#score-board>ul"),

        proxied: ["scoreChanged"],

        init: function () {
            this.render();
            ScoreModel.bind('change', this.scoreChanged);
        },

        render: function () {
            var html = '';
            for (var j = 0; j < 10; j++) {
                if (j === 0) {
                    html += '
';
                } else if (j === 9) {
                    html += '
'
                } else {
                    html += '
';
                }
                html += '
';
                var k = j === 9 ? 3 : 2;
                for (var i = 0; i < k; i++) {
                    html += '

';
                }
                html += '
';
                html += '

';
                html += '
';
            }
            this.el.append(html);
        },

        scoreChanged: function (event, score) {
            this.getScoreCard(score.chord_pk).children().filter('div').text(score.total);
        },

        /**
         * Method to update the ui with the score
         * @param ScoreModel score associated with the chord
         */
        update: function (score) {
            var scores = score.scores,
            attempt = scores.length,
            box_index = Scoreboard.getRollScoreBox(attempt, score.chord_pk),
            box = this.getScoreCard(score.chord_pk).children().filter('ul.chances').children().eq(box_index);
            // score for this roll only
            if (score.is_strike()) {
                var roll_score = 'X';
            } else if (score.is_spare()) {
                var roll_score = '/';
            } else {
                var roll_score = score.roll_score();
            }
            box.text(roll_score);
        },

        /**
         * Get the score card (block) for the current frame
         * @param int chord_pk primary key of the current chord
         * @return jQuery Object
         */
        getScoreCard: function (chord_pk) {
            return this.el.children().eq(chord_pk);
        }
    });

    window.Scoreboard.extend({

        /**
         * Get the correct li index to show the score for this roll
         * This is computed using the attempt number and total attempts
         * Method can be avoided if float: left used instead of float: right
         * @param int attempt the number of attempt [1,2,3]
         * @param int chord_pk primary key of the current chord
         * @return int index of the li element
         */
        getRollScoreBox: function (attempt, chord_pk) {
            var total_attempts = chord_pk === 9 ? 3 : 2;
            return Math.abs(attempt - total_attempts);
        },
    });

    window.App = TenChordApp.init();

});
<commit_msg>fix the bug to restrict making guesses even when all the attempts have been used<commit_after>/**
 * Code for all the controllers as well as the app controller
 */

jQuery(function($) {

    window.TenChordApp = Spine.Controller.create({
        el: $("#wrapper"),

        proxied: ["render", "confirmed"],

        events: {
            "click #next-btn": "next",
            "click #prev-btn": "prev",
            "click #confirm-guess": "confirm"
        },

        elements: {
            "#score-board": "scoreboard",
            "#question": "question",
            "#next-btn": "nextBtn",
            "#prev-btn": "prevBtn",
            "#confirm-guess": "confirmBtn",
            "#buttons a": "controlButtons"
        },

        init: function () {
            // create the note buttons
            this.notePicker = NotePicker.init();
            this.scoreboard = Scoreboard.init();
            ChordModel.bind("create", this.render);
            ChordModel.bind("update", this.confirmed);
            this.chord = OneChord.init();
            // show the first chord right away
            ChordModel.factory();
        },

        /**
         * next chord
         * if next present shown, else create new
         */
        next: function () {
            var next = this.chord.current.next();
            if (next) {
                this.render(next);
                return;
            } else {
                ChordModel.factory();
            }
        },

        /**
         * show the previous chord
         * not present case is impossible. So defensively throw an Error
         */
        prev: function () {
            var prev = this.chord.current.prev();
            if (prev) {
                this.render(prev);
                return;
            } else {
                throw new Error('Previous chord not found?!');
            }
        },

        /**
         * Render the chord on the screen
         * @param ChordModel record
         */
        render: function (chord) {
            this.chord.change(chord);
            this.updateButtons();
            this.notePicker.change(chord);
            return false;
        },

        /**
         * on click of the confirm/roll button
         * will be used to confirm the guess made by the user.
         * ..for both the attempts
         */
        confirm: function () {
            if (!this.chord.current.can_guess()) {
                return;
            }
            var guess = this.notePicker.getMarked("guessed");
            if (!guess[0]) {
                alert("Please select some notes by clicking on them");
                return;
            }
            this.chord.saveGuess(guess);
        },

        /**
         * Will be called after a guess has been confirmed.
         * Callback function of the update event of ChordModel
         */
        confirmed: function (chord) {
            var score = ScoreModel.find(chord.score_id);
            this.scoreboard.update(score);
            switch (chord.num_attempt) {
            case 2:
                // no more guesses allowed for this chord
                console.log("both guesses consumed");
                break;
            case 1:
                // 1 more guess to go
                console.log("1 more guess to go");
                break;
            case 0:
            default:
                return;
            }
            this.updateButtons();
            this.notePicker.updateStatuses(chord);
        },

        /**
         * Method to update the states of the previous, next and the roll
         * buttons for this chord
         * if its the first chord, hide the prev button
         * if its the last (10th) chord, hide the next button
         * if its a strike show the next button and hide roll
         */
        updateButtons: function () {
            // hide all buttons first
            this.controlButtons.hide();
            this.confirmBtn.show();
            var chord = this.chord.current;
            // if not last AND if all attempts consumed
            if (!chord.is_last() && !chord.can_guess()) {
                this.nextBtn.show();
            }
            // if not first, show "prev" button
            if (!chord.is_first()) {
                this.prevBtn.show();
            }
        }
    });

    window.OneChord = Spine.Controller.create({
        el: $("h2#question"),

        init: function () {

        },

        /**
         * Change the current chord
         */
        change: function (item) {
            this.current = item;
            this.render();
        },

        render: function () {
            this.el.text(this.current.name);
            var $list = $("#chord-list");
            $list.children().removeClass('active');
            // append to the chord list if its a new chord
            if (!$("#pk-"+this.current.pk).length) {
                var elements = $("#chordlistTemplate").tmpl(this.current);
                $list.append(elements[0]);
            } else {
                $("#pk-"+this.current.pk).addClass('active');
            }
        },

        saveGuess: function (guess) {
            this.current.evaluate(guess);
        }
    });

    window.NotePicker = Spine.Controller.create({
        el: $("ul#notes"),

        elements: {
            "#notes li": "button"
        },

        events: {
            "click #notes li": "toggleGuess"
        },

        proxied: ["toggleGuess", "onGuess"],

        NOTE_STATUS: {
            guessed: "guessed-note",
            correct: "correct-note",
            incorrect: "incorrect_note"
        },

        init: function () {
            this.render();
            ScoreModel.bind("update", this.onGuess);
        },

        render: function () {
            var html = '',
            n;
            for (var i in Notes.names) {
                n = Notes.names[i];
                html += '
' + n + '
';
            }
            this.el.append(html);
        },

        /**
         * Will mark and unmark the clicked note as guessed note
         */
        toggleGuess: function (event) {
            var $trgt = $(event.target);
            if (!$trgt.hasClass(this.NOTE_STATUS.correct)) {
                $(event.target).toggleClass(this.NOTE_STATUS.guessed);
            }
        },

        /**
         * Will clear all the guessed notes
         */
        clear: function () {
            var statuses = this.NOTE_STATUS;
            this.el.children().each(function () {
                $(this).removeClass(statuses.guessed + ' ' + statuses.correct + ' ' + statuses.incorrect);
            });
        },

        /**
         * When a chord is changed, the buttons will be
         * marked/unmarked accordingly
         */
        change: function (chord) {
            this.clear();
            this.updateStatuses(chord);
        },

        /**
         * Update the statuses of the notes everytime a chord is changed
         * or a guess is made
         * statuses = ('guesses', 'correct', 'incorrect')
         * @param Chord_Model chord
         */
        updateStatuses: function (chord) {
            // console.log(chord);
            if (chord.guess) {
                this.mark(chord.guess, 'guessed');
            }
            if (chord.correct) {
                this.mark(chord.correct, 'correct');
            }
        },

        /**
         * after the user makes a guess, this method will be
         * called as a callback of update event of the
         * ScoreModel object
         * Depending upon the correctness of the guesses, the
         * notes will be highlighted
         */
        onGuess: function (score) {
            // console.log(this.currentChord);
        },

        /**
         * will mark the note as guessed by the user
         * @param name - string - name of the note to be marked
         * @param status - string - status it is to be marked as
         */
        mark: function (notes, status) {
            if (typeof notes === 'string') {
                var name = notes,
                class_attr = this.NOTE_STATUS[status];
                $("#"+Notes.slugify(name)).addClass(class_attr);
            } else if (typeof notes === 'object') {
                for (var i = 0; i < notes.length; i++) {
                    this.mark(notes[i], status);
                }
            }
        },

        getMarked: function (status) {
            var marked = [],
            class_attr = this.NOTE_STATUS[status];
            this.el.children().filter("."+class_attr).each(function () {
                marked.push(Notes.unslugify($(this).attr('id')));
            });
            return marked;
        },

    });

    window.Scoreboard = Spine.Controller.create({
        el: $("#score-board>ul"),

        proxied: ["scoreChanged"],

        init: function () {
            this.render();
            ScoreModel.bind('change', this.scoreChanged);
        },

        render: function () {
            var html = '';
            for (var j = 0; j < 10; j++) {
                if (j === 0) {
                    html += '
';
                } else if (j === 9) {
                    html += '
'
                } else {
                    html += '
';
                }
                html += '
';
                var k = j === 9 ? 3 : 2;
                for (var i = 0; i < k; i++) {
                    html += '

';
                }
                html += '
';
                html += '

';
                html += '
';
            }
            this.el.append(html);
        },

        scoreChanged: function (event, score) {
            this.getScoreCard(score.chord_pk).children().filter('div').text(score.total);
        },

        /**
         * Method to update the ui with the score
         * @param ScoreModel score associated with the chord
         */
        update: function (score) {
            var scores = score.scores,
            attempt = scores.length,
            box_index = Scoreboard.getRollScoreBox(attempt, score.chord_pk),
            box = this.getScoreCard(score.chord_pk).children().filter('ul.chances').children().eq(box_index);
            // score for this roll only
            if (score.is_strike()) {
                var roll_score = 'X';
            } else if (score.is_spare()) {
                var roll_score = '/';
            } else {
                var roll_score = score.roll_score();
            }
            box.text(roll_score);
        },

        /**
         * Get the score card (block) for the current frame
         * @param int chord_pk primary key of the current chord
         * @return jQuery Object
         */
        getScoreCard: function (chord_pk) {
            return this.el.children().eq(chord_pk);
        }
    });

    window.Scoreboard.extend({

        /**
         * Get the correct li index to show the score for this roll
         * This is computed using the attempt number and total attempts
         * Method can be avoided if float: left used instead of float: right
         * @param int attempt the number of attempt [1,2,3]
         * @param int chord_pk primary key of the current chord
         * @return int index of the li element
         */
        getRollScoreBox: function (attempt, chord_pk) {
            var total_attempts = chord_pk === 9 ? 3 : 2;
            return Math.abs(attempt - total_attempts);
        },
    });

    window.App = TenChordApp.init();

});
<|endoftext|>


<commit_before>

/** Represents one poll in the voting app. */
var Poll = function(name, owner) {

    this.owner    = owner;
    this.name     = name;
    this.options  = [];
    this.numVotes = {};
    this.voters   = {};

};

Poll.prototype.getOwner = function() {
    return this.owner;
};

Poll.prototype.hasVoted = function(voterName) {
    return this.voters.hasOwnProperty(voterName);
};

Poll.prototype.addOption = function(name) {
    this.options.push(name);
    this.numVotes[name] = 0;
};

/** Sets the options for poll. Initializes also numVotes for each option to 0.*/
Poll.prototype.setOptions = function(options) {
    this.options = options;
    for (var i = 0; i < options.length; i++) {
        this.numVotes[options[i]] = 0;
    }
};

Poll.prototype.getVotes = function(option) {
    if (this.numVotes.hasOwnProperty(option)) {
        return this.numVotes[option];
    }

};

Poll.prototype.vote = function(voterName, option) {
    if (this.numVotes.hasOwnProperty(option)) {
        this.numVotes[option] += 1;
        this.voters[voterName] = true;
    }
};

module.exports = Poll;

<commit_msg>Added comments for functions.<commit_after><|endoftext|>


<commit_before>var util=require("util");
var irc=require("irc");
var axdcc=require("axdcc");
require("../webapp/Morgas/src/NodeJs/Morgas.NodeJs");
var XDCCPackage=require("../webapp/js/XDCCPackage");
var logger=require("../logger")("downloader");
var config=require("./configManager");
var CRCBuilder=µ.getModule("util.crc32").Builder;
var extractChecksum=/[\[\(]([0-9A-Z]{8})[\)\]]\./;
//*
var clients={};

var getClient=function(network)
{
	if(clients[network])return clients[network];
	else return clients[network]=new Promise(function(resolve,reject)
	{
		var cLogger=logger.child({network:network,nick:config.ircNick});
		cLogger.info("make new client for network %s with nick %s",network,config.ircNick);
		var client=new irc.Client(network, config.ircNick);
		client.logger=cLogger;
		client.on("error",function(err){cLogger.error({error:err})}); //general error logging
		var events=['motd','topic','part','kick','kill','message','notice','selfMessage','ping','pm', 'nick', 'action'];
		events.forEach(function(type)
		{
			client.on(type,function(msg)
			{
				cLogger.debug({args:arguments},network,type);
			})
		});
		var onError=function(err)
		{
			cLogger.error({error:err},"unable to create client for network %s made nick %s",network,config.ircNick);
			reject(err);
		};
		client.once("error",onError);
		client.once("registered",function()
		{
			client.removeListener("error",onError);
			cLogger.info("new client for network %s made nick %s",network,config.ircNick);
			resolve(client);
		});
	});
}
var joinChannel=function(channel)
{
	return function(client)
	{
		if(client.opt.channels.indexOf(channel) == -1)
		{
			client.logger.info("joining channel %s",channel);
			return new Promise(function(resolve,reject)
			{
				var onError=function(err)
				{
					client.logger.error({error:err},"unable to join Channel %s",channel);
					reject(err);
				};
				client.once("error",onError);
				client.join(channel,function(){
					client.removeListener("error",onError);
					client.logger.info("joined channel %s",channel);
					resolve(client)
				});
			});
		}
		else return client;
	};
}
var runningDownloads=new Map();

process.on("message",function(message)
{
	message=JSON.parse(message);
	logger.debug({message:message},"message recieved");
	switch (message.type)
	{
		case "download":
			var download=new XDCCPackage().fromJSON(message.data);
			var childLogger=logger.child({download:download});
			var activeDownload={
				abort:false,
				download:download,
				request:null,
				crcBuilder:null
			};
			runningDownloads.set(download.ID,activeDownload);
			logger.info("add download with ID %d",download.ID);
			var doContinue=function(data)
			{//check if download was aborted
				if(activeDownload.abort)return Promise.reject("abort");
				return data;
			}
			getClient(download.network).then(doContinue)
			.then(joinChannel(download.channel)).then(doContinue)
			.then(function(client)
			{
				return new Promise(function(resolve,reject){
					var request = new axdcc.Request(client, {
					    pack:download.packnumber,
					    nick:download.bot,
					    path:config.downloadDir,
					    resume:true, //TODO restart download when resume is not supported
					    progressInterval:1,
					    fileSuffix:""
					});
					activeDownload.request=request;

					request.on('connect',function(pack)
					{

						if(!download.name) download.name=pack.filename;
						if(pack.filename==download.name||pack.filename.trim()==download.name||pack.filename.replace(/_/g," ").trim()==download.name)
							download.message.text="connected";
						else
							download.message={type:"warning",text:"wrong filename: "+pack.filename};
						download.startTime=new Date();
						download.location=pack.location;
						childLogger.info({pack:pack,download:download},"connect");
						process.send(JSON.stringify(download));
					});
					if(config.checkCRC)
					{
						activeDownload.crcBuilder=new CRCBuilder(download.crc);
						request.on("data",function(data)
						{
							download.crc=activeDownload.crcBuilder.add(data).get();
						});
					}
					request.on('dlerror',function()
					{
						childLogger.error({args:arguments},"download error");
						reject(["download error",arguments]);
					});
					request.on('progress',function(pack,loaded)
					{
						download.progressValue=loaded;
						download.progressMax=pack.filesize;
						download.updateTime=new Date();
						childLogger.debug({pack:pack,download:download},"progess %d%%",(loaded/pack.filesize*100));
						process.send(JSON.stringify(download));
					});
					request.once('complete',function(pack)
					{
						resolve(pack);
					});
					request.emit("start");
					childLogger.info({download:download},"start");
				});
			}).then(function(pack)
			{
				download.progressValue=pack.filesize;
				download.progressMax=pack.filesize;
				download.state=XDCCPackage.states.DONE;
				download.message={type:"info",text:"complete"};
				if(activeDownload.crcBuilder)
				{
					var crc=activeDownload.crcBuilder.getFormatted();
					var match=download.name.match(extractChecksum);
					if(match)
					{
						if(match[1].toUpperCase()===crc) download.message.text+=" CRC: OK";
						else
						{
							download.message.type+="warning";
							download.message.text+=" CRC: DIFFERENT -> "+crc;
						}
					}
					else download.message.text+=" CRC: "+crc;
				}
				childLogger.info({pack:pack,download:download},"complete");
				process.send(JSON.stringify(download));
				runningDownloads.delete(download.ID);
				request.emit('kill');//cleanup
			},
			function(err)
			{
				runningDownloads.delete(download.ID);
				download.progressValue=download.progressMax=0;
				if(err==="abort")
				{
					childLogger.info({download:download},"abort download");
					download.state=XDCCPackage.states.DISABLED;
					download.message={type:"info",text:"aborted"};
				}
				else
				{
					download.state=XDCCPackage.states.FAILED;
					download.message={type:"error",text:util.inspect(err)};
					childLogger.error({error:err},"download failed");
				}
				process.send(JSON.stringify(download));
			}).catch(err=>childLogger.error({error:err},"error"));
			break;
		case "kill":
			if(runningDownloads.has(message.data))
			{
				var t=runningDownloads.get(message.data);
				t.abort=true;
				if(t.request) t.request.emit("cancel");
				var download=t.download;
				runningDownloads.delete(download.ID);
				download.state=XDCCPackage.states.DISABLED;
				download.progressValue=download.progressMax=0;
				download.message={type:"info",text:"aborted"};
				process.send(JSON.stringify(download));
				logger.info({download:download},"killed download");
			}
			else {
				logger.info("has no download with ID %d",message.data);
				process.send(JSON.stringify({
					ID:message.data,
					state:XDCCPackage.states.DISABLED,
					message:{type:"info",text:"not running"}
				}));
			}
			break;
		default:
			logger.error({message:message},"unknown message type %s",message.type);
	}
});<commit_msg>cleanNames<commit_after>var util=require("util");
var irc=require("irc");
var axdcc=require("axdcc");
require("../webapp/Morgas/src/NodeJs/Morgas.NodeJs");
var XDCCPackage=require("../webapp/js/XDCCPackage");
var logger=require("../logger")("downloader");
var config=require("./configManager");
var CRCBuilder=µ.getModule("util.crc32").Builder;
var extractChecksum=/[\[\(]([0-9A-Z]{8})[\)\]]\./;
//*
var clients={};

var getClient=function(network)
{
	if(clients[network])return clients[network];
	else return clients[network]=new Promise(function(resolve,reject)
	{
		var cLogger=logger.child({network:network,nick:config.ircNick});
		cLogger.info("make new client for network %s with nick %s",network,config.ircNick);
		var client=new irc.Client(network, config.ircNick);
		client.logger=cLogger;
		client.on("error",function(err){cLogger.error({error:err})}); //general error logging
		var events=['motd','topic','part','kick','kill','message','notice','selfMessage','ping','pm', 'nick', 'action'];
		events.forEach(function(type)
		{
			client.on(type,function(msg)
			{
				cLogger.debug({args:arguments},network,type);
			})
		});
		var onError=function(err)
		{
			cLogger.error({error:err},"unable to create client for network %s made nick %s",network,config.ircNick);
			reject(err);
		};
		client.once("error",onError);
		client.once("registered",function()
		{
			client.removeListener("error",onError);
			cLogger.info("new client for network %s made nick %s",network,config.ircNick);
			resolve(client);
		});
	});
}
var joinChannel=function(channel)
{
	return function(client)
	{
		if(client.opt.channels.indexOf(channel) == -1)
		{
			client.logger.info("joining channel %s",channel);
			return new Promise(function(resolve,reject)
			{
				var onError=function(err)
				{
					client.logger.error({error:err},"unable to join Channel %s",channel);
					reject(err);
				};
				client.once("error",onError);
				client.join(channel,function(){
					client.removeListener("error",onError);
					client.logger.info("joined channel %s",channel);
					resolve(client)
				});
			});
		}
		else return client;
	};
}
var runningDownloads=new Map();

var cleanName=function(name)
{
	if((name.indexOf("%20")!==-1&&name.indexOf(" ")===-1)||(name.indexOf("%5B")!==-1&&name.indexOf("[")===-1))
		name=decodeURIComponent(name);
	name=name.replace(/_/g," ");
	name=name.replace(/\.(?![^\.]+$)/g," ");
	return name;
};

process.on("message",function(message)
{
	message=JSON.parse(message);
	logger.debug({message:message},"message recieved");
	switch (message.type)
	{
		case "download":
			var download=new XDCCPackage().fromJSON(message.data);
			var childLogger=logger.child({download:download});
			var activeDownload={
				abort:false,
				download:download,
				request:null,
				crcBuilder:null
			};
			runningDownloads.set(download.ID,activeDownload);
			logger.info("add download with ID %d",download.ID);
			var doContinue=function(data)
			{//check if download was aborted
				if(activeDownload.abort)return Promise.reject("abort");
				return data;
			}
			getClient(download.network).then(doContinue)
			.then(joinChannel(download.channel)).then(doContinue)
			.then(function(client)
			{
				return new Promise(function(resolve,reject){
					var requestParam={
					    pack:download.packnumber,
					    nick:download.bot,
					    path:config.downloadDir,
					    resume:true, //TODO restart download when resume is not supported
					    progressInterval:1,
					    fileSuffix:""
					};
					if(config.cleanNames)
					{
						download.name=cleanName(download.name);
					    requestParam.filename=download.name;
					}
					var request = new axdcc.Request(client, requestParam);
					activeDownload.request=request;

					request.on('connect',function(pack)
					{

						if(!download.name) download.name=pack.filename;
						if(cleanName(pack.filename)===cleanName(download.name))
						{
							download.message.text="connected";
						}
						else
							download.message={type:"warning",text:"wrong filename: "+pack.filename};
						download.startTime=new Date();
						download.location=pack.location;
						childLogger.info({pack:pack,download:download},"connect");
						process.send(JSON.stringify(download));
					});
					if(config.checkCRC)
					{
						activeDownload.crcBuilder=new CRCBuilder(download.crc);
						request.on("data",function(data)
						{
							download.crc=activeDownload.crcBuilder.add(data).get();
						});
					}
					request.on('dlerror',function()
					{
						childLogger.error({args:arguments},"download error");
						reject(["download error",arguments]);
					});
					request.on('progress',function(pack,loaded)
					{
						download.progressValue=loaded;
						download.progressMax=pack.filesize;
						download.updateTime=new Date();
						childLogger.debug({pack:pack,download:download},"progess %d%%",(loaded/pack.filesize*100));
						process.send(JSON.stringify(download));
					});
					request.once('complete',function(pack)
					{
						resolve(pack);
					});
					request.emit("start");
					childLogger.info({download:download},"start");
				});
			}).then(function(pack)
			{
				download.progressValue=pack.filesize;
				download.progressMax=pack.filesize;
				download.state=XDCCPackage.states.DONE;
				download.message={type:"info",text:"complete"};
				if(activeDownload.crcBuilder)
				{
					var crc=activeDownload.crcBuilder.getFormatted();
					var match=download.name.match(extractChecksum);
					if(match)
					{
						if(match[1].toUpperCase()===crc) download.message.text+=" CRC: OK";
						else
						{
							download.message.type="warning";
							download.message.text+=" CRC: DIFFERENT -> "+crc;
						}
					}
					else download.message.text+=" CRC: "+crc;
				}
				childLogger.info({pack:pack,download:download},"complete");
				process.send(JSON.stringify(download));
				runningDownloads.delete(download.ID);
			},
			function(err)
			{
				runningDownloads.delete(download.ID);
				download.progressValue=download.progressMax=0;
				if(err==="abort")
				{
					childLogger.info({download:download},"abort download");
					download.state=XDCCPackage.states.DISABLED;
					download.message={type:"info",text:"aborted"};
				}
				else
				{
					download.state=XDCCPackage.states.FAILED;
					download.message={type:"error",text:util.inspect(err)};
					childLogger.error({error:err},"download failed");
				}
				process.send(JSON.stringify(download));
			}).catch(err=>childLogger.error({error:err},"error"));
			break;
		case "kill":
			if(runningDownloads.has(message.data))
			{
				var t=runningDownloads.get(message.data);
				t.abort=true;
				if(t.request) t.request.emit("cancel");
				var download=t.download;
				runningDownloads.delete(download.ID);
				download.state=XDCCPackage.states.DISABLED;
				download.progressValue=download.progressMax=0;
				download.message={type:"info",text:"aborted"};
				process.send(JSON.stringify(download));
				logger.info({download:download},"killed download");
			}
			else {
				logger.info("has no download with ID %d",message.data);
				process.send(JSON.stringify({
					ID:message.data,
					state:XDCCPackage.states.DISABLED,
					message:{type:"info",text:"not running"}
				}));
			}
			break;
		default:
			logger.error({message:message},"unknown message type %s",message.type);
	}
});<|endoftext|>


<commit_before>on.input.in = function() {
  cb( { out: typeof data === null ? 'null' : data.toString() });
};
<commit_msg>output()<commit_after>on.input.in = function() {
  output( { out: typeof data === null ? 'null' : data.toString() });
};
<|endoftext|>


<commit_before>module.exports = function(server) {

  var mongoose = server.mongoose
    , common   = server.common
    , errors   = server.errors
    , Schema   = mongoose.Schema
    , ObjectId = Schema.ObjectId
    , Mixed    = Schema.Types.Mixed
    , async    = require('async')
    , utils    = server.utils
    , _        = utils._
    , moment   = require('moment-timezone')
    ;

  var Bet = new Schema({
      user  : { type: String }
    , bet   : { type: String } // 1, X, or 2
    , points: { type: Number, default: 0 }
    /*
      - N being the number of participants
      - W being the number of winners for that prediction
      --> The gained points P are calculated by P = N / (W + 0,1 x N)
    */
  });

  var Game = module.exports = new Schema({
      time  : { type: Date }
    , teams : [ { type: String }]
    , score : [ { type: Number, default: 0 }]
    , group : { type: String }
    , bets  : [Bet]
  });

  Game.plugin(common.timestamps('created', 'updated'));

  /**
   * Methods.
   */
  Game.method({

    /*
     * Calculate every player's points.
     */
    calculatePoints: function(callback) {
      var self = this;

      // Winning bet.
      var win = (self.score[0] > self.score[1]) ? '1' : '2';
      if (self.score[0] === self.score[1])
        win = 'X';

      // Number of winning bets.
      var nbPlayers = self.bets.length;
      var nbWin = 0;
      _.each(self.bets, function(b) {
        if (b.bet === win)
          nbWin += 1;
      });

      // Calculate the points for everyone.
      self.bets = _.map(self.bets, function(b) {
        if (b.bet === win)
          b.points = nbPlayers / (nbWin + 0.1*nbPlayers);
        else
          b.points = 0;
        return b;
      });

      self.save(callback);
    }

  });

  /**
   * Static.
   */
  Game.static({

    findByDate: function(date, callback) {
      date = new Date(date);
      var dateStart = new Date(2014, 5, 12);
      if (date < dateStart)
        date = dateStart;
      var start = moment(date).tz('America/Fortaleza').startOf('day').format();
      var end = moment(date).tz('America/Fortaleza').endOf('day').format();
      this.find({time: {$gte: start, $lt: end}}, callback);
    },

    /**
     * Get groups playing at that time.
     */
    groupByDate: function(date, callback) {
      date = new Date(date);
      var start = new Date(moment(date).subtract('hours', 24).format());
      var end = date;
      this.find({time: {$gte: start, $lt: end}}, function(e, games) {
        if (e) return callback(e);
        var groups = _.map(games, function(g) { return g.group});
        callback(null, _.uniq(groups));
      });
    },

    updateScore: function(g, callback) {
      this.findOne({teams: g.teams}, function(e, gameDb) {
        if (e) return callback(e);
        if ( (g.score[0] !== gameDb.score[0]) || (g.score[1] !== gameDb.score[1])) {
          gameDb.score = g.score;
          gameDb.save(function(e, game) {
            if (e) return callback(e);
            game.calculatePoints(function(e) {
              callback(e, true);
            });
          });
        } else {
          callback(null, false);
        }
      });
    },

    getBetsPoints: function(date, callback) {
      date = new Date(date);
      var dateStart = new Date(2014, 5, 12);
      if (date < dateStart)
        date = dateStart;

      var self = this;
      var bets = {};
      var betsDay = {};
      // Get games until next day.
      self.find({time: {$lte: (moment(date).tz('America/Fortaleza').endOf('day').format())}}).sort('time').exec(function(e, games) {
        if (e) return callback(e);

        _.each(games, function(g) {
          // Sum the points.
          _.each(g.bets, function(b) {
            if (!bets[b.user])
              bets[b.user] = 0;
            bets[b.user] += b.points || 0;
          });

          // Export the bets of the day.
          if (moment(g.time).tz('America/Fortaleza').format('YYYY-MM-D') === moment(date).tz('America/Fortaleza').format('YYYY-MM-D')) {
            _.each(g.bets, function(b) {
              if (!betsDay[b.user])
                betsDay[b.user] = [];
              betsDay[b.user].push(b.bet);
            });
          }
        });
        var betsOut = [];

        self.getPointsBefore(date, function(e, pointsBefore, rankingBefore) {
          if (e) return callback(e);
          for (var i in bets) {
            betsOut.push({
                user: i
              , points: Math.round(bets[i] * 10) / 10
              , differencePoints: (Math.round( (bets[i] - pointsBefore[i]) * 10) / 10)
              , ranking: null
              , rankingBefore: rankingBefore[i]
              , bets: betsDay[i]
            });
          };
          betsOut = _.sortBy(betsOut, function(b) {return -b.points});

          var j = 0;
          for (var i = 0; i<betsOut.length; i++) {
            if (i===0 || betsOut[i].points !== betsOut[i-1].points) {
              j += 1;
            }
            betsOut[i].ranking = j;
          }

          for (var i = 0; i<betsOut.length; i++) {
            betsOut[i].differenceRanking = (betsOut[i].rankingBefore) ? (betsOut[i].rankingBefore - betsOut[i].ranking) : '';
          }

          callback(null, betsOut);
        });

      });
    },

    getPointsBefore: function(date, callback) {
      var self = this;
      var bets = {};
      var betsOrdered = [];
      var ranking = {};
      self.find({time: {$lt: date}}).sort('time').exec(function(e, games) {
        if (e) return callback(e);
        for (var i = 0; i<games.length-1; i++) {
          var g = games[i];
          _.each(g.bets, function(b) {
            if (!bets[b.user])
              bets[b.user] = 0;
            bets[b.user] += b.points || 0;
          });
        }
        for (var i in bets) {
          betsOrdered.push({
              user: i
            , points: Math.round(bets[i] * 10) / 10
          });
        }
        betsOrdered = _.sortBy(betsOrdered, function(b) {return -b.points});

        var j = 0;
        for (var i = 0; i<betsOrdered.length; i++) {
          if (i===0 || betsOrdered[i].points !== betsOrdered[i-1].points) {
            j += 1;
          }
          ranking[betsOrdered[i].user] = j;
        }

        callback(null, bets, ranking);
      });
    },

  });

  /**
   * Pre save.
   */
  Game.pre('save', function(next) {
    var self = this;

    if (this.isNew || this.isModified('score')) {
      // Recalculate the users scores.

      next();
    } else {
      next();
    }

  });

  /**
   * Create model.
   */
  mongoose.model('Game', Game);

}
<commit_msg>set back the get groups for 2 hours before<commit_after>module.exports = function(server) {

  var mongoose = server.mongoose
    , common   = server.common
    , errors   = server.errors
    , Schema   = mongoose.Schema
    , ObjectId = Schema.ObjectId
    , Mixed    = Schema.Types.Mixed
    , async    = require('async')
    , utils    = server.utils
    , _        = utils._
    , moment   = require('moment-timezone')
    ;

  var Bet = new Schema({
      user  : { type: String }
    , bet   : { type: String } // 1, X, or 2
    , points: { type: Number, default: 0 }
    /*
      - N being the number of participants
      - W being the number of winners for that prediction
      --> The gained points P are calculated by P = N / (W + 0,1 x N)
    */
  });

  var Game = module.exports = new Schema({
      time  : { type: Date }
    , teams : [ { type: String }]
    , score : [ { type: Number, default: 0 }]
    , group : { type: String }
    , bets  : [Bet]
  });

  Game.plugin(common.timestamps('created', 'updated'));

  /**
   * Methods.
   */
  Game.method({

    /*
     * Calculate every player's points.
     */
    calculatePoints: function(callback) {
      var self = this;

      // Winning bet.
      var win = (self.score[0] > self.score[1]) ? '1' : '2';
      if (self.score[0] === self.score[1])
        win = 'X';

      // Number of winning bets.
      var nbPlayers = self.bets.length;
      var nbWin = 0;
      _.each(self.bets, function(b) {
        if (b.bet === win)
          nbWin += 1;
      });

      // Calculate the points for everyone.
      self.bets = _.map(self.bets, function(b) {
        if (b.bet === win)
          b.points = nbPlayers / (nbWin + 0.1*nbPlayers);
        else
          b.points = 0;
        return b;
      });

      self.save(callback);
    }

  });

  /**
   * Static.
   */
  Game.static({

    findByDate: function(date, callback) {
      date = new Date(date);
      var dateStart = new Date(2014, 5, 12);
      if (date < dateStart)
        date = dateStart;
      var start = moment(date).tz('America/Fortaleza').startOf('day').format();
      var end = moment(date).tz('America/Fortaleza').endOf('day').format();
      this.find({time: {$gte: start, $lt: end}}, callback);
    },

    /**
     * Get groups playing at that time.
     */
    groupByDate: function(date, callback) {
      date = new Date(date);
      var start = new Date(moment(date).subtract('hours', 2).format());
      var end = date;
      this.find({time: {$gte: start, $lt: end}}, function(e, games) {
        if (e) return callback(e);
        var groups = _.map(games, function(g) { return g.group});
        callback(null, _.uniq(groups));
      });
    },

    updateScore: function(g, callback) {
      this.findOne({teams: g.teams}, function(e, gameDb) {
        if (e) return callback(e);
        if ( (g.score[0] !== gameDb.score[0]) || (g.score[1] !== gameDb.score[1])) {
          gameDb.score = g.score;
          gameDb.save(function(e, game) {
            if (e) return callback(e);
            game.calculatePoints(function(e) {
              callback(e, true);
            });
          });
        } else {
          callback(null, false);
        }
      });
    },

    getBetsPoints: function(date, callback) {
      date = new Date(date);
      var dateStart = new Date(2014, 5, 12);
      if (date < dateStart)
        date = dateStart;

      var self = this;
      var bets = {};
      var betsDay = {};
      // Get games until next day.
      self.find({time: {$lte: (moment(date).tz('America/Fortaleza').endOf('day').format())}}).sort('time').exec(function(e, games) {
        if (e) return callback(e);

        _.each(games, function(g) {
          // Sum the points.
          _.each(g.bets, function(b) {
            if (!bets[b.user])
              bets[b.user] = 0;
            bets[b.user] += b.points || 0;
          });

          // Export the bets of the day.
          if (moment(g.time).tz('America/Fortaleza').format('YYYY-MM-D') === moment(date).tz('America/Fortaleza').format('YYYY-MM-D')) {
            _.each(g.bets, function(b) {
              if (!betsDay[b.user])
                betsDay[b.user] = [];
              betsDay[b.user].push(b.bet);
            });
          }
        });
        var betsOut = [];

        self.getPointsBefore(date, function(e, pointsBefore, rankingBefore) {
          if (e) return callback(e);
          for (var i in bets) {
            betsOut.push({
                user: i
              , points: Math.round(bets[i] * 10) / 10
              , differencePoints: (Math.round( (bets[i] - pointsBefore[i]) * 10) / 10)
              , ranking: null
              , rankingBefore: rankingBefore[i]
              , bets: betsDay[i]
            });
          };
          betsOut = _.sortBy(betsOut, function(b) {return -b.points});

          var j = 0;
          for (var i = 0; i<betsOut.length; i++) {
            if (i===0 || betsOut[i].points !== betsOut[i-1].points) {
              j += 1;
            }
            betsOut[i].ranking = j;
          }

          for (var i = 0; i<betsOut.length; i++) {
            betsOut[i].differenceRanking = (betsOut[i].rankingBefore) ? (betsOut[i].rankingBefore - betsOut[i].ranking) : '';
          }

          callback(null, betsOut);
        });

      });
    },

    getPointsBefore: function(date, callback) {
      var self = this;
      var bets = {};
      var betsOrdered = [];
      var ranking = {};
      self.find({time: {$lt: date}}).sort('time').exec(function(e, games) {
        if (e) return callback(e);
        for (var i = 0; i<games.length-1; i++) {
          var g = games[i];
          _.each(g.bets, function(b) {
            if (!bets[b.user])
              bets[b.user] = 0;
            bets[b.user] += b.points || 0;
          });
        }
        for (var i in bets) {
          betsOrdered.push({
              user: i
            , points: Math.round(bets[i] * 10) / 10
          });
        }
        betsOrdered = _.sortBy(betsOrdered, function(b) {return -b.points});

        var j = 0;
        for (var i = 0; i<betsOrdered.length; i++) {
          if (i===0 || betsOrdered[i].points !== betsOrdered[i-1].points) {
            j += 1;
          }
          ranking[betsOrdered[i].user] = j;
        }

        callback(null, bets, ranking);
      });
    },

  });

  /**
   * Pre save.
   */
  Game.pre('save', function(next) {
    var self = this;

    if (this.isNew || this.isModified('score')) {
      // Recalculate the users scores.

      next();
    } else {
      next();
    }

  });

  /**
   * Create model.
   */
  mongoose.model('Game', Game);

}
<|endoftext|>


<commit_before>module.exports = {
  local : function (traces) {
    console.error("up");

    var count = 0;
    traces.on("request:start", function (trace) {
      console.log(trace.url);
    });

    traces.on("request:end", function (trace) {
      count++;
      console.error(trace.statusCode);
      if (count === 3) process.exit(0);
    });
  }
};
<commit_msg>shh eslint<commit_after>module.exports = {
  local : function (traces) {
    console.error("up");

    var count = 0;
    traces.on("request:start", function (trace) {
      console.log(trace.url);
    });

    traces.on("request:end", function (trace) {
      /*eslint no-process-exit:0 */
      count++;
      console.error(trace.statusCode);
      if (count === 3) process.exit(0);
    });
  }
};
<|endoftext|>


<commit_before>var init = {
    /*
     * Notice when (auto)depublish date is in the past
     * TODO: add timer, to check depublish date has passed during editing.
     *
     * @returns {undefined}
     */
    depublishTracking: function () {
        "use strict";

        var noticeID = 'dateDepublishNotice',
            msg = $('#datedepublish').data('notice');

        $('#datedepublish, #statusselect').on('change', function (){

            var status = $('#statusselect').val(),
                depublish = $('#datedepublish').val();

            // remove old notice
            $('.' + noticeID).remove();

            if (depublish === '') {
                return;
            }

            if (status === 'published' && moment(depublish + Bolt.conf('timezone.offset')) < moment()) {
                $('
' +
                    '<button type="button" class="close" data-dismiss="alert">×</button>' + msg + '
')
                    .hide()
                    .insertAfter('.depublish-group')
                    .slideDown('fast');
            }

        });

        // trigger on load
        $('#datedepublish').trigger('change');

    },

    /*
     * Bind file_edit_contents field
     *
     * @param {object} data
     * @returns {undefined}
     *
     * @fires "Bolt.File.Save.Start"
     * @fires "Bolt.File.Save.Done"
     * @fires "Bolt.File.Save.Fail"
     * @fires "Bolt.File.Save.Always"
     */
    bindEditFile: function (data) {
        "use strict";

        var editor;

        if (typeof CodeMirror !== 'undefined') {
            editor = CodeMirror.fromTextArea(document.getElementById('file_edit_contents'), {
                lineNumbers: true,
                autofocus: true,
                foldGutter: {
                    rangeFinder: CodeMirror.fold.indent
                },
                gutters: ["CodeMirror-linenumbers", "CodeMirror-foldgutter"],
                extraKeys: {
                    "Ctrl-Q": function (cm) {
                        cm.foldCode(
                            cm.getCursor(),
                            {
                                rangeFinder: CodeMirror.fold.indent,
                                minFoldSize: 3
                            }
                        );
                    },
                    "Tab": function (cm) {
                        if (cm.somethingSelected()) {
                            cm.indentSelection("add");
                        } else {
                            cm.replaceSelection(cm.getOption("indentWithTabs") ? "\t" :
                            Array(cm.getOption("indentUnit") + 1).join(" "), "end", "+input");
                        }
                    },
                    "Ctrl-S": function () {
                        $('#file_edit_save').click();
                    },
                    "Ctrl-H": "replaceAll"
                },
                tabSize: 4,
                indentUnit: 4,
                indentWithTabs: false,
                readOnly: data.readonly
            });
            var newheight = $(window).height() - 312;
            if (newheight < 200) {
                newheight = 200;
            }
            editor.setSize(null, newheight);
        }

        $('#file_edit_save').on('click', function (e) {
            Bolt.events.fire('Bolt.File.Save.Start');

            // Disable the form POST
            e.preventDefault();

            // Copy back to the textarea.
            if (editor) {
                editor.save();
            }

            var msgNotSaved = 'Not saved';

            // Disable the buttons, to indicate stuff is being done.
            $('#file_edit_save').addClass('disabled');
            $('#file_edit_save i').addClass('fa-spin fa-spinner');
            $('p.lastsaved').text(Bolt.data('editcontent.msg.saving'));

            var button = $(e.target);
            var postData = $('form[name="file_edit"]').serialize()
                + '&' + encodeURI(button.attr('name'))
                + '=' + encodeURI(button.attr('value'))
            ;
            $.post('?returnto=ajax', postData)
                .done(function (data) {
                    if (!data.ok) {
                        alert(data.msg);
                        Bolt.events.fire('Bolt.File.Save.Fail', data);
                    } else {
                        Bolt.events.fire('Bolt.File.Save.Done', data);
                    }
                    $('p.lastsaved').html(data.msg);
                })
                .fail(function () {
                    Bolt.events.fire('Bolt.File.Save.Fail');
                    alert(msgNotSaved);
                })
                .always(function () {
                    Bolt.events.fire('Bolt.File.Save.Always');

                    // Re-enable buttons
                    window.setTimeout(function () {
                        $('#file_edit_save').removeClass('disabled').blur();
                        $('#file_edit_save i').removeClass('fa-spin fa-spinner');
                    }, 300);
                });
        });
    },

    /*
     * Bind editlocale field
     *
     * @param {object} data
     * @returns {undefined}
     */
    bindEditLocale: function (data) {
        "use strict";

        var editor = CodeMirror.fromTextArea(document.getElementById('file_edit_contents'), {
            lineNumbers: true,
            autofocus: true,
            tabSize: 4,
            indentUnit: 4,
            indentWithTabs: false,
            readOnly: data.readonly
        });

        editor.setSize(null, $(window).height() - 276);
    },

    /*
     * Bind filebrowser
     */
    bindFileBrowser: function () {
        "use strict";

        $('#myTab a').click(function (e) {
            e.preventDefault();
            $(this).tab('show');
        });

        var getUrlParam = function (paramName) {
            var reParam = new RegExp('(?:[\?&]|&)' + paramName + '=([^&]+)', 'i'),
                match = window.location.search.match(reParam);

            return match && match.length > 1 ? match[1] : null;
        };
        var funcNum = getUrlParam('CKEditorFuncNum');

        $('a.filebrowserCallbackLink').bind('click', function (e) {
            e.preventDefault();
            var url = $(this).attr('href');
            window.opener.CKEDITOR.tools.callFunction(funcNum, url);
            window.close();
        });

        $('a.filebrowserCloseLink').bind('click', function () {
            window.close();
        });
    },

    bindCkFileSelect: function () {
        "use strict";

        var getUrlParam = function (paramName) {
            var reParam = new RegExp('(?:[\?&]|&)' + paramName + '=([^&]+)', 'i'),
                match = window.location.search.match(reParam);

            return match && match.length > 1 ? match[1] : null;
        };

        var funcNum = getUrlParam('CKEditorFuncNum');
        $('a.filebrowserCallbackLink').bind('click', function (event) {
            event.preventDefault();
            var url = $(this).attr('href');
            window.opener.CKEDITOR.tools.callFunction(funcNum, url);
            window.close();
        });
    },

    /*
     * Bind prefill
     */
    bindPrefill: function () {
        "use strict";

        var checkboxes = $('#form_contenttypes').find(':checkbox');

        $('#prefill_check_all').on('click', function () {
            // because jQuery is being retarded.
            // See: http://stackoverflow.com/questions/5907645/jquery-chrome-and-checkboxes-strange-behavior
            checkboxes.removeAttr('checked').trigger('click');
        });
        $('#prefill_uncheck_all').on('click', function () {
            checkboxes.removeAttr('checked');
        });
    },

    /**
     * Any link (or clickable -icon) with a class='confirm' gets a confirmation dialog.
     *
     * @returns {undefined}
     */
    confirmationDialogs: function () {
        "use strict";

        $('.confirm').on('click', function () {
            return confirm($(this).data('confirm'));
        });
    },

    /*
     * Smarter dropdowns/dropups based on viewport height.
     * Based on: https://github.com/twbs/bootstrap/issues/3637#issuecomment-9850709
     *
     * @returns {undefined}
     */
    dropDowns: function () {
        "use strict";

        $('[data-toggle="dropdown"]').each(function (index, item) {
            var mouseEvt;
            if (typeof event === 'undefined') {
                $(item).parent().click(function (e) {
                    mouseEvt = e;
                });
            } else {
                mouseEvt = event;
            }
            $(item).parent().on('show.bs.dropdown', function () {

                // Prevent breakage on old IE.
                if (typeof mouseEvt !== "undefined" && mouseEvt !== null) {
                    var self = $(this).find('[data-toggle="dropdown"]'),
                        menu = self.next('.dropdown-menu'),
                        mousey = mouseEvt.pageY + 20,
                        menuHeight = menu.height(),
                        menuVisY = $(window).height() - mousey + menuHeight, // Distance from the bottom of viewport
                        profilerHeight = 37; // The size of the Symfony Profiler Bar is 37px.

                    // The whole menu must fit when trying to 'dropup', but always prefer to 'dropdown' (= default).
                    if (mousey - menuHeight > 20 && menuVisY < profilerHeight) {
                        menu.css({
                            top: 'auto',
                            bottom: '100%'
                        });
                    }
                }
            });
        });
    },

    /*
     * Show 'dropzone' for jQuery file uploader.
     *
     * @returns {undefined}
     */
    dropZone: function () {
        "use strict";

        // @todo make it prettier, and distinguish between '.in' and '.hover'.
        $(document).bind('dragover', function (e) {
            var dropZone = $('.elm-dropzone'),
                timeout = window.dropZoneTimeout;
            if (!timeout) {
                dropZone.addClass('in');
            } else {
                clearTimeout(timeout);
            }
            if (e.target === dropZone[0]) {
                dropZone.addClass('hover');
            } else {
                dropZone.removeClass('hover');
            }
            window.dropZoneTimeout = setTimeout(function () {
                window.dropZoneTimeout = null;
                dropZone.removeClass('in hover');
            }, 100);
        });
    },

    /*
     * Initialize the Magnific popup shizzle. Fancybox is still here as a trigger, for backwards compatibility.
     */
    magnificPopup: function () {
        "use strict";

        $('.magnific, .fancybox').magnificPopup({
            type: 'image',
            gallery: {
                enabled: true
            },
            disableOn: 400,
            closeBtnInside: true,
            enableEscapeKey: true,
            mainClass: 'mfp-with-zoom',
            zoom: {
                enabled: true,
                duration: 300,
                easing: 'ease-in-out',
                opener: function (openerElement) {
                    return openerElement.parent().parent().find('img');
                }
            }
        });
    },

    /*
     * Initialize current status display setting focus on status select
     *
     * @returns {undefined}
     */
    focusStatusSelect: function () {
        "use strict";

        $('#lastsavedstatus').click(function (e) {
            e.preventDefault();
            $('a[href="#tab-meta"]').click();
            $('#statusselect').focus();
        });
    },

    /*
     * Toggle options for showing / hiding the password input on the logon screen.
     *
     * @returns {undefined}
     */
    passwordInput: function () {
        "use strict";

        $(".togglepass").on('click', function () {
            if ($(this).hasClass('show-password')) {
                $('input[name="password"]').attr('type', 'text');
                $('.togglepass.show-password').hide();
                $('.togglepass.hide-password').show();
            } else {
                $('input[name="password"]').attr('type', 'password');
                $('.togglepass.show-password').show();
                $('.togglepass.hide-password').hide();
            }
        });

        $('.login-forgot').bind('click', function () {
            $('.login-group, .password-group').hide();
            $('.reset-group').show();
        });

        $('.login-remembered').bind('click', function () {
            $('.login-group, .password-group').show();
            $('.reset-group').hide();
        });
    },

    /*
     * Initialize popovers.
     */
    popOvers: function () {
        "use strict";

        $('.info-pop').popover({
            trigger: 'hover',
            delay: {
                show: 500,
                hide: 200
            }
        });
    },

    /*
     * ?
     */
    sortables: function () {
        "use strict";

        $('tbody.sortable').sortable({
            items: 'tr',
            opacity: '0.5',
            axis: 'y',
            handle: '.sorthandle',
            update: function () {
                var serial = $(this).sortable('serialize');
                // Sorting request
                $.ajax({
                    url: $('#baseurl').attr('value') + 'content/sortcontent/' +
                        $(this).parent('table').data('contenttype'),
                    type: 'POST',
                    data: serial,
                    success: function () {
                        // Do nothing
                    }
                });
            }
        });
    }
};
<commit_msg>Fixed: "show" / "Hide" password toggle on log in screen.<commit_after>var init = {
    /*
     * Notice when (auto)depublish date is in the past
     * TODO: add timer, to check depublish date has passed during editing.
     *
     * @returns {undefined}
     */
    depublishTracking: function () {
        "use strict";

        var noticeID = 'dateDepublishNotice',
            msg = $('#datedepublish').data('notice');

        $('#datedepublish, #statusselect').on('change', function (){

            var status = $('#statusselect').val(),
                depublish = $('#datedepublish').val();

            // remove old notice
            $('.' + noticeID).remove();

            if (depublish === '') {
                return;
            }

            if (status === 'published' && moment(depublish + Bolt.conf('timezone.offset')) < moment()) {
                $('
' +
                    '<button type="button" class="close" data-dismiss="alert">×</button>' + msg + '
')
                    .hide()
                    .insertAfter('.depublish-group')
                    .slideDown('fast');
            }

        });

        // trigger on load
        $('#datedepublish').trigger('change');

    },

    /*
     * Bind file_edit_contents field
     *
     * @param {object} data
     * @returns {undefined}
     *
     * @fires "Bolt.File.Save.Start"
     * @fires "Bolt.File.Save.Done"
     * @fires "Bolt.File.Save.Fail"
     * @fires "Bolt.File.Save.Always"
     */
    bindEditFile: function (data) {
        "use strict";

        var editor;

        if (typeof CodeMirror !== 'undefined') {
            editor = CodeMirror.fromTextArea(document.getElementById('file_edit_contents'), {
                lineNumbers: true,
                autofocus: true,
                foldGutter: {
                    rangeFinder: CodeMirror.fold.indent
                },
                gutters: ["CodeMirror-linenumbers", "CodeMirror-foldgutter"],
                extraKeys: {
                    "Ctrl-Q": function (cm) {
                        cm.foldCode(
                            cm.getCursor(),
                            {
                                rangeFinder: CodeMirror.fold.indent,
                                minFoldSize: 3
                            }
                        );
                    },
                    "Tab": function (cm) {
                        if (cm.somethingSelected()) {
                            cm.indentSelection("add");
                        } else {
                            cm.replaceSelection(cm.getOption("indentWithTabs") ? "\t" :
                            Array(cm.getOption("indentUnit") + 1).join(" "), "end", "+input");
                        }
                    },
                    "Ctrl-S": function () {
                        $('#file_edit_save').click();
                    },
                    "Ctrl-H": "replaceAll"
                },
                tabSize: 4,
                indentUnit: 4,
                indentWithTabs: false,
                readOnly: data.readonly
            });
            var newheight = $(window).height() - 312;
            if (newheight < 200) {
                newheight = 200;
            }
            editor.setSize(null, newheight);
        }

        $('#file_edit_save').on('click', function (e) {
            Bolt.events.fire('Bolt.File.Save.Start');

            // Disable the form POST
            e.preventDefault();

            // Copy back to the textarea.
            if (editor) {
                editor.save();
            }

            var msgNotSaved = 'Not saved';

            // Disable the buttons, to indicate stuff is being done.
            $('#file_edit_save').addClass('disabled');
            $('#file_edit_save i').addClass('fa-spin fa-spinner');
            $('p.lastsaved').text(Bolt.data('editcontent.msg.saving'));

            var button = $(e.target);
            var postData = $('form[name="file_edit"]').serialize()
                + '&' + encodeURI(button.attr('name'))
                + '=' + encodeURI(button.attr('value'))
            ;
            $.post('?returnto=ajax', postData)
                .done(function (data) {
                    if (!data.ok) {
                        alert(data.msg);
                        Bolt.events.fire('Bolt.File.Save.Fail', data);
                    } else {
                        Bolt.events.fire('Bolt.File.Save.Done', data);
                    }
                    $('p.lastsaved').html(data.msg);
                })
                .fail(function () {
                    Bolt.events.fire('Bolt.File.Save.Fail');
                    alert(msgNotSaved);
                })
                .always(function () {
                    Bolt.events.fire('Bolt.File.Save.Always');

                    // Re-enable buttons
                    window.setTimeout(function () {
                        $('#file_edit_save').removeClass('disabled').blur();
                        $('#file_edit_save i').removeClass('fa-spin fa-spinner');
                    }, 300);
                });
        });
    },

    /*
     * Bind editlocale field
     *
     * @param {object} data
     * @returns {undefined}
     */
    bindEditLocale: function (data) {
        "use strict";

        var editor = CodeMirror.fromTextArea(document.getElementById('file_edit_contents'), {
            lineNumbers: true,
            autofocus: true,
            tabSize: 4,
            indentUnit: 4,
            indentWithTabs: false,
            readOnly: data.readonly
        });

        editor.setSize(null, $(window).height() - 276);
    },

    /*
     * Bind filebrowser
     */
    bindFileBrowser: function () {
        "use strict";

        $('#myTab a').click(function (e) {
            e.preventDefault();
            $(this).tab('show');
        });

        var getUrlParam = function (paramName) {
            var reParam = new RegExp('(?:[\?&]|&)' + paramName + '=([^&]+)', 'i'),
                match = window.location.search.match(reParam);

            return match && match.length > 1 ? match[1] : null;
        };
        var funcNum = getUrlParam('CKEditorFuncNum');

        $('a.filebrowserCallbackLink').bind('click', function (e) {
            e.preventDefault();
            var url = $(this).attr('href');
            window.opener.CKEDITOR.tools.callFunction(funcNum, url);
            window.close();
        });

        $('a.filebrowserCloseLink').bind('click', function () {
            window.close();
        });
    },

    bindCkFileSelect: function () {
        "use strict";

        var getUrlParam = function (paramName) {
            var reParam = new RegExp('(?:[\?&]|&)' + paramName + '=([^&]+)', 'i'),
                match = window.location.search.match(reParam);

            return match && match.length > 1 ? match[1] : null;
        };

        var funcNum = getUrlParam('CKEditorFuncNum');
        $('a.filebrowserCallbackLink').bind('click', function (event) {
            event.preventDefault();
            var url = $(this).attr('href');
            window.opener.CKEDITOR.tools.callFunction(funcNum, url);
            window.close();
        });
    },

    /*
     * Bind prefill
     */
    bindPrefill: function () {
        "use strict";

        var checkboxes = $('#form_contenttypes').find(':checkbox');

        $('#prefill_check_all').on('click', function () {
            // because jQuery is being retarded.
            // See: http://stackoverflow.com/questions/5907645/jquery-chrome-and-checkboxes-strange-behavior
            checkboxes.removeAttr('checked').trigger('click');
        });
        $('#prefill_uncheck_all').on('click', function () {
            checkboxes.removeAttr('checked');
        });
    },

    /**
     * Any link (or clickable -icon) with a class='confirm' gets a confirmation dialog.
     *
     * @returns {undefined}
     */
    confirmationDialogs: function () {
        "use strict";

        $('.confirm').on('click', function () {
            return confirm($(this).data('confirm'));
        });
    },

    /*
     * Smarter dropdowns/dropups based on viewport height.
     * Based on: https://github.com/twbs/bootstrap/issues/3637#issuecomment-9850709
     *
     * @returns {undefined}
     */
    dropDowns: function () {
        "use strict";

        $('[data-toggle="dropdown"]').each(function (index, item) {
            var mouseEvt;
            if (typeof event === 'undefined') {
                $(item).parent().click(function (e) {
                    mouseEvt = e;
                });
            } else {
                mouseEvt = event;
            }
            $(item).parent().on('show.bs.dropdown', function () {

                // Prevent breakage on old IE.
                if (typeof mouseEvt !== "undefined" && mouseEvt !== null) {
                    var self = $(this).find('[data-toggle="dropdown"]'),
                        menu = self.next('.dropdown-menu'),
                        mousey = mouseEvt.pageY + 20,
                        menuHeight = menu.height(),
                        menuVisY = $(window).height() - mousey + menuHeight, // Distance from the bottom of viewport
                        profilerHeight = 37; // The size of the Symfony Profiler Bar is 37px.

                    // The whole menu must fit when trying to 'dropup', but always prefer to 'dropdown' (= default).
                    if (mousey - menuHeight > 20 && menuVisY < profilerHeight) {
                        menu.css({
                            top: 'auto',
                            bottom: '100%'
                        });
                    }
                }
            });
        });
    },

    /*
     * Show 'dropzone' for jQuery file uploader.
     *
     * @returns {undefined}
     */
    dropZone: function () {
        "use strict";

        // @todo make it prettier, and distinguish between '.in' and '.hover'.
        $(document).bind('dragover', function (e) {
            var dropZone = $('.elm-dropzone'),
                timeout = window.dropZoneTimeout;
            if (!timeout) {
                dropZone.addClass('in');
            } else {
                clearTimeout(timeout);
            }
            if (e.target === dropZone[0]) {
                dropZone.addClass('hover');
            } else {
                dropZone.removeClass('hover');
            }
            window.dropZoneTimeout = setTimeout(function () {
                window.dropZoneTimeout = null;
                dropZone.removeClass('in hover');
            }, 100);
        });
    },

    /*
     * Initialize the Magnific popup shizzle. Fancybox is still here as a trigger, for backwards compatibility.
     */
    magnificPopup: function () {
        "use strict";

        $('.magnific, .fancybox').magnificPopup({
            type: 'image',
            gallery: {
                enabled: true
            },
            disableOn: 400,
            closeBtnInside: true,
            enableEscapeKey: true,
            mainClass: 'mfp-with-zoom',
            zoom: {
                enabled: true,
                duration: 300,
                easing: 'ease-in-out',
                opener: function (openerElement) {
                    return openerElement.parent().parent().find('img');
                }
            }
        });
    },

    /*
     * Initialize current status display setting focus on status select
     *
     * @returns {undefined}
     */
    focusStatusSelect: function () {
        "use strict";

        $('#lastsavedstatus').click(function (e) {
            e.preventDefault();
            $('a[href="#tab-meta"]').click();
            $('#statusselect').focus();
        });
    },

    /*
     * Toggle options for showing / hiding the password input on the logon screen.
     *
     * @returns {undefined}
     */
    passwordInput: function () {
        "use strict";

        $(".togglepass").on('click', function () {
            if ($(this).hasClass('show-password')) {
                $('input[name="user_login[password]"]').attr('type', 'text');
                $('.togglepass.show-password').hide();
                $('.togglepass.hide-password').show();
            } else {
                $('input[name="user_login[password]"]').attr('type', 'password');
                $('.togglepass.show-password').show();
                $('.togglepass.hide-password').hide();
            }
        });

        $('.login-forgot').bind('click', function () {
            $('.login-group, .password-group').hide();
            $('.reset-group').show();
        });

        $('.login-remembered').bind('click', function () {
            $('.login-group, .password-group').show();
            $('.reset-group').hide();
        });
    },

    /*
     * Initialize popovers.
     */
    popOvers: function () {
        "use strict";

        $('.info-pop').popover({
            trigger: 'hover',
            delay: {
                show: 500,
                hide: 200
            }
        });
    },

    /*
     * ?
     */
    sortables: function () {
        "use strict";

        $('tbody.sortable').sortable({
            items: 'tr',
            opacity: '0.5',
            axis: 'y',
            handle: '.sorthandle',
            update: function () {
                var serial = $(this).sortable('serialize');
                // Sorting request
                $.ajax({
                    url: $('#baseurl').attr('value') + 'content/sortcontent/' +
                        $(this).parent('table').data('contenttype'),
                    type: 'POST',
                    data: serial,
                    success: function () {
                        // Do nothing
                    }
                });
            }
        });
    }
};
<|endoftext|>


<commit_before><commit_msg>added moment to server<commit_after><|endoftext|>