<commit_before>module.exports = (db, mongoose) => {
  let docSchema = new mongoose.Schema({
    subject: {type: 'String', index: true, required: true},
    time: {type: 'String', index: true, required: true}, // Eg. s12, w15, y16 (i.e. for speciman paper)
    type: {type: 'String', index: true, required: true}, // Eg. qp, ms, sp, sm etc.
    paper: {type: 'Number', index: true, required: true},
    variant: {type: 'Number', index: true, required: true},
    doc: {type: Buffer, required: true},
    fileType: {type: 'String', default: 'pdf', required: true},
    numPages: {type: 'Number', required: true},
  })
  let indexSchema = new mongoose.Schema({
    doc: {type: 'ObjectId', required: true},
    page: {type: 'Number', required: true}, // starts from 0
    content: {type: 'String', required: true},
    sspdfCache: {type: 'Object', default: null}
  })
  let feedbackSchema = new mongoose.Schema({
    time: {type: 'Number', index: true, required: true},
    ip: {type: 'String', required: true},
    email: {type: 'String', index: true, required: false, validate: {
      validator: v => {
        return typeof v === 'string' && (v === '' || /.+@.+\..+/i.test(v)) && v.length <= 5000
      },
      message: 'Check your email address for typos'
    }},
    text: {type: 'String', required: [true, 'Feedback content required'], validate: {
      validator: v => {
        return typeof v === 'string' && (v.length > 0 && v.length <= 5000)
      },
      message: 'Your feedback must not be empty, and it must not contain more than 5000 characters'
    }},
    search: {type: 'String', required: false, validate: {
      validator: v => {
        return (v === null) || (typeof v === 'string' && v.length > 0 && v.length <= 5000)
      }
    }}
  })
  let requestRecordSchema = new mongoose.Schema({
    ip: {type: 'String', index: true, required: true},
    time: {type: 'Number', index: true, required: true},
    requestType: {type: 'String', index: true},
    search: {type: 'String', default: null},
    targetId: {type: 'ObjectId', default: null},
    targetPage: {type: 'Number', default: null}
  })
  let PastPaperIndex
  let PastPaperDoc
  let PastPaperFeedback
  let PastPaperRequestRecord
  indexSchema.static('search', query => new Promise((resolve, reject) => {
    query = query.replace(/["'\+\-]/g, '')
    let aggreArray
    let queryPerfixMatch = query.match(/^(\d{4})\s+(.+)$/)
    if (queryPerfixMatch) {
      aggreArray = [{$match: {$text: {$search: queryPerfixMatch[2]}}}]
    } else {
      aggreArray = [{$match: {$text: {$search: query}}}]
    }
    aggreArray.push({$sort: {mgScore: {$meta: 'textScore'}}})
    aggreArray.push({$lookup: {from: 'pastpaperdocs', localField: 'doc', foreignField: '_id', as: 'doc'}})
    aggreArray.push({$project: {tDoc: {$arrayElemAt: ['$doc', 0]}, _id: true, doc: true, content: true, page: true}})
    // aggreArray.push({$project: {'tDoc.doc': false, 'doc': false}})
    if (queryPerfixMatch) {
      aggreArray.push({$match: {'tDoc.subject': queryPerfixMatch[1]}})
    }
    aggreArray.push({$limit: 30})
    PastPaperIndex.aggregate(aggreArray).then(res => {
      resolve(res.map(mgDoc => (mgDoc.tDoc ? {
        doc: Object.assign(mgDoc.tDoc, {doc: null}),
        index: {
          _id: mgDoc._id,
          content: mgDoc.content,
          page: mgDoc.page,
          doc: mgDoc.tDoc._id
        }
      } : null)).filter(x => x !== null))
    }, reject)
  }))
  indexSchema.index({content: 'text'})
  docSchema.index({subject: true, time: true, paper: true, variant: true})
  try {
    PastPaperIndex = db.model('pastPaperIndex', indexSchema)
  } catch (e) {
    PastPaperIndex = db.model('pastPaperIndex')
  }
  try {
    PastPaperDoc = db.model('pastPaperDoc', docSchema)
  } catch (e) {
    PastPaperDoc = db.model('pastPaperDoc')
  }
  try {
    PastPaperFeedback = db.model('pastPaperFeedback', feedbackSchema)
  } catch (e) {
    PastPaperFeedback = db.model('pastPaperFeedback')
  }
  try {
    PastPaperRequestRecord = db.model('pastPaperRequestRecord', requestRecordSchema)
  } catch (e) {
    PastPaperRequestRecord = db.model('pastPaperRequestRecord')
  }
  return {PastPaperDoc, PastPaperIndex, PastPaperFeedback, PastPaperRequestRecord}
}
<commit_msg>Older mongodb compatibility<commit_after>module.exports = (db, mongoose) => {
  let docSchema = new mongoose.Schema({
    subject: {type: 'String', index: true, required: true},
    time: {type: 'String', index: true, required: true}, // Eg. s12, w15, y16 (i.e. for speciman paper)
    type: {type: 'String', index: true, required: true}, // Eg. qp, ms, sp, sm etc.
    paper: {type: 'Number', index: true, required: true},
    variant: {type: 'Number', index: true, required: true},
    doc: {type: Buffer, required: true},
    fileType: {type: 'String', default: 'pdf', required: true},
    numPages: {type: 'Number', required: true},
  })
  let indexSchema = new mongoose.Schema({
    doc: {type: 'ObjectId', required: true},
    page: {type: 'Number', required: true}, // starts from 0
    content: {type: 'String', required: true},
    sspdfCache: {type: 'Object', default: null}
  })
  let feedbackSchema = new mongoose.Schema({
    time: {type: 'Number', index: true, required: true},
    ip: {type: 'String', required: true},
    email: {type: 'String', index: true, required: false, validate: {
      validator: v => {
        return typeof v === 'string' && (v === '' || /.+@.+\..+/i.test(v)) && v.length <= 5000
      },
      message: 'Check your email address for typos'
    }},
    text: {type: 'String', required: [true, 'Feedback content required'], validate: {
      validator: v => {
        return typeof v === 'string' && (v.length > 0 && v.length <= 5000)
      },
      message: 'Your feedback must not be empty, and it must not contain more than 5000 characters'
    }},
    search: {type: 'String', required: false, validate: {
      validator: v => {
        return (v === null) || (typeof v === 'string' && v.length > 0 && v.length <= 5000)
      }
    }}
  })
  let requestRecordSchema = new mongoose.Schema({
    ip: {type: 'String', index: true, required: true},
    time: {type: 'Number', index: true, required: true},
    requestType: {type: 'String', index: true},
    search: {type: 'String', default: null},
    targetId: {type: 'ObjectId', default: null},
    targetPage: {type: 'Number', default: null}
  })
  let PastPaperIndex
  let PastPaperDoc
  let PastPaperFeedback
  let PastPaperRequestRecord
  indexSchema.static('search', query => new Promise((resolve, reject) => {
    query = query.replace(/["'\+\-]/g, '')
    let aggreArray
    let queryPerfixMatch = query.match(/^(\d{4})\s+(.+)$/)
    if (queryPerfixMatch) {
      aggreArray = [{$match: {$text: {$search: queryPerfixMatch[2]}}}]
    } else {
      aggreArray = [{$match: {$text: {$search: query}}}]
    }
    aggreArray.push({$sort: {mgScore: {$meta: 'textScore'}}})
    aggreArray.push({$lookup: {from: 'pastpaperdocs', localField: 'doc', foreignField: '_id', as: 'doc'}})
    aggreArray.push({$project: {tDoc: {$arrayElemAt: ['$doc', 0]}, _id: true, doc: undefined, content: true, page: true}})
    aggreArray.push({$addFields: {'tDoc.doc': undefined}})
    if (queryPerfixMatch) {
      aggreArray.push({$match: {'tDoc.subject': queryPerfixMatch[1]}})
    }
    aggreArray.push({$limit: 30})
    PastPaperIndex.aggregate(aggreArray).then(res => {
      resolve(res.map(mgDoc => (mgDoc.tDoc ? {
        doc: mgDoc.tDoc,
        index: {
          _id: mgDoc._id,
          content: mgDoc.content,
          page: mgDoc.page,
          doc: mgDoc.tDoc._id
        }
      } : null)).filter(x => x !== null))
    }, reject)
  }))
  indexSchema.index({content: 'text'})
  docSchema.index({subject: true, time: true, paper: true, variant: true})
  try {
    PastPaperIndex = db.model('pastPaperIndex', indexSchema)
  } catch (e) {
    PastPaperIndex = db.model('pastPaperIndex')
  }
  try {
    PastPaperDoc = db.model('pastPaperDoc', docSchema)
  } catch (e) {
    PastPaperDoc = db.model('pastPaperDoc')
  }
  try {
    PastPaperFeedback = db.model('pastPaperFeedback', feedbackSchema)
  } catch (e) {
    PastPaperFeedback = db.model('pastPaperFeedback')
  }
  try {
    PastPaperRequestRecord = db.model('pastPaperRequestRecord', requestRecordSchema)
  } catch (e) {
    PastPaperRequestRecord = db.model('pastPaperRequestRecord')
  }
  return {PastPaperDoc, PastPaperIndex, PastPaperFeedback, PastPaperRequestRecord}
}
<|endoftext|>


<commit_before>const http = require('http');
const url = require('url');

const routes = {};
const middleware = [];
let logger = false;
let gotoNext = true;

function useLogger(option) {
  logger = option;
}

function isValidRoute(request) {
  const validMethods = [
    'POST',
    'GET',
    'PUT',
    'PATCH',
    'DELETE',
  ];

  if (typeof routes[request] !== 'object') {
    return false;
  }
  if (validMethods.indexOf(routes[request].method) === -1) {
    return false;
  }

  // const controller = routes[pathname].controller.split('@');
  // const controllerFile = controller[0];
  // const controllerHandler = controller[1];

  return true;
}

function next() {
  gotoNext = true;
}

function onRequest(req, res) {
  const method = req.method;
  const parsedUrl = url.parse(req.url, true);
  const pathname = parsedUrl.pathname;
  const request = `${method} ${pathname}`;

  if (isValidRoute(request)) {
    middleware.forEach(function (f) {
      if (gotoNext) {
        gotoNext = false;
        f(req, res, next);
      }
    });

    if(!gotoNext) {
      return false;
    }

    if (logger) {
      const date = new Date();
      console.log(`[${date.getHours()}:${date.getMinutes()}:${date.getSeconds()}] ` +
                  `${method} ${parsedUrl.path}`);
    }
    res.writeHead(200);
    req.query = parsedUrl.query;
    routes[request].controller(req, res);
    res.end();
  } else {
    res.writeHead(500);
    res.end('Invalid route.');
  }
}

function route(method_, path_, controller_) {
  method_ = method_.toUpperCase();

  routes[`${method_} ${path_}`] = {
    path: path_,
    method: method_,
    controller: controller_,
  };
}

function use(f) {
  middleware.push(f);
}

function start(port = 8080) {
  http.createServer(onRequest).listen(port);
}

exports = module.exports = onRequest;
exports.start = start;
exports.route = route;
exports.useLogger = useLogger;
exports.use = use;
<commit_msg>Middleware tweaked<commit_after>const http = require('http');
const url = require('url');

const routes = {};
const middleware = [];
let logger = false;
let gotoNext = true;

function useLogger(option) {
  logger = option;
}

function isValidRoute(request) {
  const validMethods = [
    'POST',
    'GET',
    'PUT',
    'PATCH',
    'DELETE',
  ];

  if (typeof routes[request] !== 'object') {
    return false;
  }
  if (validMethods.indexOf(routes[request].method) === -1) {
    return false;
  }

  // const controller = routes[pathname].controller.split('@');
  // const controllerFile = controller[0];
  // const controllerHandler = controller[1];

  return true;
}

function next() {
  gotoNext = true;
}

function onRequest(req, res) {
  const method = req.method;
  const parsedUrl = url.parse(req.url, true);
  const pathname = parsedUrl.pathname;
  const request = `${method} ${pathname}`;

  if (isValidRoute(request)) {
    middleware.forEach(function (f) {
      if (gotoNext) {
        gotoNext = false;
        f(req, res, next);
      } else {
        return;
      }
    });

    if (!gotoNext) {
      return false;
    }

    if (logger) {
      const date = new Date();
      console.log(`[${date.getHours()}:${date.getMinutes()}:${date.getSeconds()}] ` +
                  `${method} ${parsedUrl.path}`);
    }

    res.writeHead(200);
    req.query = parsedUrl.query;
    routes[request].controller(req, res);
    res.end();
  } else {
    res.writeHead(500);
    res.end('Invalid route.');
  }
}

function route(method_, path_, controller_) {
  method_ = method_.toUpperCase();

  routes[`${method_} ${path_}`] = {
    path: path_,
    method: method_,
    controller: controller_,
  };
}

function use(f) {
  middleware.push(f);
}

function start(port = 8080) {
  http.createServer(onRequest).listen(port);
}

exports = module.exports = onRequest;
exports.start = start;
exports.route = route;
exports.useLogger = useLogger;
exports.use = use;
<|endoftext|>


<commit_before>
window.addEvent('domready', function() {

	var output = $('output'),
		container = $('container');

	// Element.Delegation setup
	$('container').addEvent('click:relay(.item)', function(){

		// Check whether it is a new div or not with the Element:hasClass method
		var message = this.hasClass('new') ? 'new div clicked!' : 'div clicked!';
		output.set('text', message);

		(function(){ // clear the message after 500 ms
			output.set('text', '');
		}).delay(500);

	});

	// Add new divs
	$('addDiv').addEvent('click', function(){
		container.grab(new Element('div.item.new'), 'top');
	});

});
<commit_msg>Fix Element.Delegation demo when clicking multiple boxes quickly after each other<commit_after>
window.addEvent('domready', function() {

	var output = $('output'),
		container = $('container'),
		timer;

	// Element.Delegation setup
	$('container').addEvent('click:relay(.item)', function(){

		// Check whether it is a new div or not with the Element:hasClass method
		var message = this.hasClass('new') ? 'new div clicked!' : 'div clicked!';
		output.set('text', message);

		clearTimeout(timer);
		timer = (function(){ // clear the message after 1000 ms
			output.set('text', '');
		}).delay(1000);

	});

	// Add new divs
	$('addDiv').addEvent('click', function(){
		container.grab(new Element('div.item.new'), 'top');
	});

});
<|endoftext|>


<commit_before>
function escape_regexp(str) {
  return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
}

function replace_all(find, replace, str) {
  return str.replace(new RegExp(escape_regexp(find), 'g'), replace);
}

function init_log() {
    function scroll_down($el) {
        $el.scrollTop($el[0].scrollHeight);
    }

    function read_log() {
        var $el = $("#log-content");
        var mode = $el.data("mode");
        if(mode != "tail") {
            return;
        }
        var filename = $el.data("filename");

        $.get("/log/read", {"filename": filename}, function (resp) {
            // only scroll down if the scroll is already at the bottom.
            if(($el.scrollTop() + $el.innerHeight()) >= $el[0].scrollHeight) {
                $el.append(resp);
                scroll_down($el);
            } else {
                $el.append(resp);
            }
        });
    }

    function exit_search_mode() {
        var $el = $("#log-content");
        $el.data("mode", "tail");
        var $controls = $("#log").find(".controls");
        $controls.find(".mode-text").text("Tail mode (Press s to search)");
        $controls.find(".status-text").hide();

        $.get("/log/read_tail", {"filename": $el.data("filename")}, function (resp) {
            $el.text(resp);
            scroll_down($el);
            $("#search-input").val("").blur();
        });
    }

    $("#scroll-down-btn").click(function() {
        scroll_down($el);
    });

    $("#search-form").submit(function(e) {
        e.preventDefault();

        var val = $("#search-input").val();
        if(!val) return;

        var $el = $("#log-content");
        var filename = $el.data("filename");
        var params = {
            "filename": filename,
            "text": val
        };

        $el.data("mode", "search");
        $("#log").find(".controls .mode-text").text("Search mode (Press enter for next, escape to exit)");

        $.get("/log/search", params, function (resp) {
            var $log = $("#log");
            $log.find(".controls .status-text").hide();
            $el.find(".found-text").removeClass("found-text");

            var $status = $log.find(".controls .status-text");

            if(resp.position == -1) {
                $status.text("EOF Reached.");
            } else {
                var matched_text = '' + params['text'] + '';
                var found_text = '' + params["text"] + '';
                var content_before = resp.content.slice(0, resp.buffer_pos);
                var content_after = resp.content.slice(resp.buffer_pos + params["text"].length);
                content_before = replace_all(params["text"], matched_text, content_before);
                content_after = replace_all(params["text"], matched_text, content_after);
                resp.content = content_before + found_text + content_after;
                $el.html(resp.content);
                $status.text("Position " + resp.position + " of " + resp.filesize + ".");
            }

            $status.show();
        });
    });

    $(document).keyup(function(e) {
        var mode = $el.data("mode");
        if(mode != "search" && e.which == 83) {
            $("#search-input").focus();
        }
        // Exit search mode if escape is pressed.
        else if(mode == "search" && e.which == 27) {
            exit_search_mode();
        }
    });

    setInterval(read_log, 1000);
    var $el = $("#log-content");
    scroll_down($el);
}

function init_updater() {
    function update() {
        $.ajax({
            url: location.href,
            cache: false,
            dataType: "html",
            success: function(resp){
                $("#content").html(resp);
            }
        });
    }

    setInterval(update, 3000);
}

$(document).ready(function() {
    if($("#log").length == 0) {
        init_updater();
    } else {
        init_log();
    }
});<commit_msg>Escape any HTML tag in the log search response.<commit_after>
function escape_regexp(str) {
  return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
}

function replace_all(find, replace, str) {
  return str.replace(new RegExp(escape_regexp(find), 'g'), replace);
}

function init_log() {
    function scroll_down($el) {
        $el.scrollTop($el[0].scrollHeight);
    }

    function read_log() {
        var $el = $("#log-content");
        var mode = $el.data("mode");
        if(mode != "tail") {
            return;
        }
        var filename = $el.data("filename");

        $.get("/log/read", {"filename": filename}, function (resp) {
            // only scroll down if the scroll is already at the bottom.
            if(($el.scrollTop() + $el.innerHeight()) >= $el[0].scrollHeight) {
                $el.append(resp);
                scroll_down($el);
            } else {
                $el.append(resp);
            }
        });
    }

    function exit_search_mode() {
        var $el = $("#log-content");
        $el.data("mode", "tail");
        var $controls = $("#log").find(".controls");
        $controls.find(".mode-text").text("Tail mode (Press s to search)");
        $controls.find(".status-text").hide();

        $.get("/log/read_tail", {"filename": $el.data("filename")}, function (resp) {
            $el.text(resp);
            scroll_down($el);
            $("#search-input").val("").blur();
        });
    }

    $("#scroll-down-btn").click(function() {
        scroll_down($el);
    });

    $("#search-form").submit(function(e) {
        e.preventDefault();

        var val = $("#search-input").val();
        if(!val) return;

        var $el = $("#log-content");
        var filename = $el.data("filename");
        var params = {
            "filename": filename,
            "text": val
        };

        $el.data("mode", "search");
        $("#log").find(".controls .mode-text").text("Search mode (Press enter for next, escape to exit)");

        $.get("/log/search", params, function (resp) {
            var $log = $("#log");
            $log.find(".controls .status-text").hide();
            $el.find(".found-text").removeClass("found-text");

            var $status = $log.find(".controls .status-text");

            if(resp.position == -1) {
                $status.text("EOF Reached.");
            } else {
                resp.content = $('
').text(resp.content).html();
                var matched_text = '' + params['text'] + '';
                var found_text = '' + params["text"] + '';
                var content_before = resp.content.slice(0, resp.buffer_pos);
                var content_after = resp.content.slice(resp.buffer_pos + params["text"].length);
                content_before = replace_all(params["text"], matched_text, content_before);
                content_after = replace_all(params["text"], matched_text, content_after);
                resp.content = content_before + found_text + content_after;
                $el.html(resp.content);
                $status.text("Position " + resp.position + " of " + resp.filesize + ".");
            }

            $status.show();
        });
    });

    $(document).keyup(function(e) {
        var mode = $el.data("mode");
        if(mode != "search" && e.which == 83) {
            $("#search-input").focus();
        }
        // Exit search mode if escape is pressed.
        else if(mode == "search" && e.which == 27) {
            exit_search_mode();
        }
    });

    setInterval(read_log, 1000);
    var $el = $("#log-content");
    scroll_down($el);
}

function init_updater() {
    function update() {
        $.ajax({
            url: location.href,
            cache: false,
            dataType: "html",
            success: function(resp){
                $("#content").html(resp);
            }
        });
    }

    setInterval(update, 3000);
}

$(document).ready(function() {
    if($("#log").length == 0) {
        init_updater();
    } else {
        init_log();
    }
});
<|endoftext|>


<commit_before>$(function(){
    var publicBodyPrefilled = $("#search-public_bodies").length === 0;

    loggedInCallback = function(data){
        $("#user_data_form").html("
"+data.name+" "+data.last_name+"
"+
                    "
"+data.email+"
");
    };

    var letter_start = $('#letter_start').text();
    var letter_end = $('#letter_end').text();

    var activateMessage = function(){
        $("#public-body").removeClass("active");
        $("#step-message").slideDown()
            .removeClass("hidden")
            .parent().addClass("active");
    };

    $(".foirequest input").keydown(function(e){
        if(e.keyCode === 13){
            e.preventDefault();
        }
    });

    var publicBodyChosen = function(){
        Froide.app.publicBodyChosen($(".foirequest input[name='public_body']:checked").val(),
                                    publicBodyPrefilled);
        activateMessage();
    };

    $(".foirequest input[name='public_body']").live("change", function(e){
        if ($("#option-newpublicbody").attr("checked")){
            $("#new-public_body").slideDown();
        } else {
            $("#new-public_body").slideUp();
        }
        publicBodyChosen();
    });

    $("#review-button").click(function(){
        Froide.app.performReview();
    });

    $("form.foirequest").submit(function(e){
        $("#send-request-button").attr("disabled", "disabled");
    });

    if (publicBodyPrefilled){
        publicBodyChosen();
    }
    if($("#search-public_bodies").length === 1 && $("#search-public_bodies").val() !== ""){
        Froide.app.performPublicBodySearch();
    }
    if($(".foirequest input[name='public_body']:checked").length > 0){
        publicBodyChosen();
    }
    if ($("#option-newpublicbody").attr("checked")){
        $("#new-public_body").slideDown();
    }
});
<commit_msg>Extract activating message into function<commit_after>$(function(){
    var publicBodyPrefilled = $("#search-public_bodies").length === 0;

    loggedInCallback = function(data){
        $("#user_data_form").html("
"+data.name+" "+data.last_name+"
"+
                    "
"+data.email+"
");
    };

    var letter_start = $('#letter_start').text();
    var letter_end = $('#letter_end').text();

    $(".foirequest input").keydown(function(e){
        if(e.keyCode === 13){
            e.preventDefault();
        }
    });

    var publicBodyChosen = function(){
        Froide.app.publicBodyChosen($(".foirequest input[name='public_body']:checked").val(),
                                    publicBodyPrefilled);
        Froide.app.activateMessage();
    };

    $(".foirequest input[name='public_body']").live("change", function(e){
        if ($("#option-newpublicbody").attr("checked")){
            $("#new-public_body").slideDown();
        } else {
            $("#new-public_body").slideUp();
        }
        publicBodyChosen();
    });

    $("#review-button").click(function(){
        Froide.app.performReview();
    });

    $("form.foirequest").submit(function(e){
        $("#send-request-button").attr("disabled", "disabled");
    });

    if (publicBodyPrefilled){
        publicBodyChosen();
    }
    if($("#search-public_bodies").length === 1 && $("#search-public_bodies").val() !== ""){
        Froide.app.performPublicBodySearch();
    }
    if($(".foirequest input[name='public_body']:checked").length > 0){
        publicBodyChosen();
    }
    if ($("#option-newpublicbody").attr("checked")){
        $("#new-public_body").slideDown();
    }
});
<|endoftext|>


<commit_before>const _ = require('lodash');
const $ = require('jquery');
const async = require('async');

const Period = require('./Period');
const Schedule = require('./Schedule');
const Calendar = require('./Calendar');

class BellTimer {
    constructor(cookieManager, requestManager) {
        this.cookieManager = cookieManager;
        this.requestManager = requestManager;

        this.debug = function() {};
        this.devMode = false;
        this.startTime = 0;
        this.timeScale = 1;

        var devModeCookie = this.cookieManager.get('dev_mode');
        if (devModeCookie) {
            this.enableDevMode(devModeCookie.startDate, devModeCookie.scale);
        }
    }

    loadCustomCourses() {
        var courses = this.cookieManager.get('courses');

        // Make sure there is at least one section, otherwise it will infinite loop
        var foundSection = false;
        for (let id in courses) {
            var course = courses[id];
            if (course.sections.length) {
                foundSection = true;
                break;
            }
        }
        if (!foundSection)
            courses = {
                'none': {
                    name: 'No sections',
                    sections: [
                        ['Wednesday', [0, 0],
                            [24, 0]
                        ]
                    ]
                }
            };

        var week = {
            Sun: {
                name: 'Sunday'
            },
            Mon: {
                name: 'Monday'
            },
            Tue: {
                name: 'Tuesday'
            },
            Wed: {
                name: 'Wednesday'
            },
            Thu: {
                name: 'Thursday'
            },
            Fri: {
                name: 'Friday'
            },
            Sat: {
                name: 'Saturday'
            }
        };
        var special = {};
        var schedules = {};

        var periods = {};

        for (let id in courses) {
            var course = courses[id];
            var name = course.name;
            var sections = course.sections;

            for (let section of sections) {
                var [day, start, end] = section;
                if (!periods[day])
                    periods[day] = [];

                periods[day].push(new Period({
                    hour: start[0],
                    min: start[1]
                }, name));
                periods[day].push(new Period({
                    hour: end[0],
                    min: end[1]
                }, 'Free'));
            }
        }

        for (var day in week) {
            day = week[day].name;
            schedules[day] = new Schedule(day, day, periods[day] || []);
        }

        var calendar = new Calendar(week, special, schedules, this.cookieManager.get('periods'));

        this.setCorrection(0);
        this.calendar = calendar;
    }

    async reloadData() {
        var dataSource = this.cookieManager.get('source', 'lahs');
        if (dataSource == 'custom') {
            this.source = dataSource;
            return this.loadCustomCourses();
        }

        var [sources, version, correction, schedules, calendar] = await Promise.all([
            this.requestManager.get('/api/sources/names'),
            this.requestManager.get('/api/version'),
            this.requestManager.get(`/api/data/${dataSource}/correction`, '0'),
            this.requestManager.get(`/api/data/${dataSource}/schedules`),
            this.requestManager.get(`/api/data/${dataSource}/calendar`)
        ]);

        if (sources.indexOf(dataSource) < 0) {
            this.cookieManager.remove('source');
            return this.reloadData();
        }

        this.source = dataSource;

        if (this.version && this.version != version)
        // Give IndexedDB time to write (TODO: make more robust)
            setTimeout(() => $(window)[0].location.reload(), 1000);
        else
            this.version = version;

        this.setCorrection(parseInt(correction));

        var parseSchedules = require('./ScheduleParser');
        var parseCalendar = require('./CalendarParser');

        schedules = parseSchedules(schedules, this.cookieManager.get('periods'));
        calendar = parseCalendar(calendar, schedules);

        return this.calendar = calendar;
    }

    async initialize() {
        return Promise.all([
            this.reloadData(),
            this.initializeTimesync()
        ]);
    }

    async initializeTimesync() {
        if (typeof timesync == 'undefined') {
            this.ts = Date;
            console.warn('Timesync not found');
            return this.ts;
        }

        var ts = timesync.create({
            server: this.requestManager.host + '/timesync',
            interval: 4 * 60 * 1000
        });

        ts.on('change', offset =>
            this.debug('Timesync offset: ' + offset));

        this.ts = ts;

        return new Promise((resolve, reject) =>
            ts.on('sync', _.once(() => resolve(ts))));
    }

    setCorrection(correction) {
        this.correction = correction;
    }

    getCorrection() {
        return this.correction;
    }

    enableDevMode(startDate, scale) {
        console.warn('You are in Developer Mode, at ' + scale + 'x speed! Disable with `bellTimer.disableDevMode()`')

        this.devMode = true;
        this.startTime = new Date(startDate).getTime();
        this.devModeStartTime = Date.now();
        this.timeScale = scale;

        this.cookieManager.set('dev_mode', {
            enabled: this.devMode,
            startDate: startDate,
            scale: scale
        });
    }

    disableDevMode() {
        this.devMode = false;
        this.cookieManager.remove('dev_mode');
    }

    getDate() {
        if (this.devMode)
            return new Date((this.startTime + ((Date.now() - this.devModeStartTime) * this.timeScale) + this.correction));
        return new Date(this.ts.now() + this.correction);
    }

    getTimeRemainingMs() {
        var date = this.getDate();
        return this.getNextPeriod().timestamp.getTime() - date.getTime();
    }

    getTimeRemainingString() {
        var date = this.getDate();
        var displayTimeNumber = function(time) {
            time = Math.ceil(time / 1000) * 1000
            var hours = Math.floor(time / 1000 / 60 / 60);
            var seconds = Math.floor(time / 1000 % 60).toString();
            if (seconds.length < 2)
                seconds = '0' + seconds;
            var minutes = Math.floor(time / 1000 / 60 % 60).toString();
            if (minutes.length < 2 && hours)
                minutes = '0' + minutes;
            return (hours < 1) ? minutes + ':' + seconds : hours + ':' + minutes + ':' + seconds;
        };
        return displayTimeNumber(this.getTimeRemainingMs());
    }

    getProportionElapsed() {
        var date = this.getDate();

        var currentPeriodStart = this.getCurrentPeriod().timestamp.getTime();
        var nextPeriodStart = this.getNextPeriod().timestamp.getTime();

        var totalTime = nextPeriodStart - currentPeriodStart;
        var elapsedTime = date.getTime() - currentPeriodStart;

        return elapsedTime / totalTime;
    }

    getNextPeriod() {
        var date = this.getDate();
        var period = this.calendar.getSchedule(date).getNextPeriod(date);
        while (!period) {
            date = new Date(date.getFullYear(), date.getMonth(), date.getDate() + 1, 0, 0, 0, 0);
            period = this.calendar.getSchedule(date).getFirstPeriod(date);
        }
        return period;
    }
    getPreviousPeriod() {
        var date = this.getDate();
        var period = this.calendar.getSchedule(date).getPreviousPeriod(date);
        while (!period) {
            date = new Date(date.getFullYear(), date.getMonth(), date.getDate() - 1, 0, 0, 0, 0);
            period = this.calendar.getSchedule(date).getLastPeriod(date);
        }
        return period;
    }

    getCurrentPeriod() {
        var date = this.getDate();
        var period = this.calendar.getSchedule(date).getCurrentPeriod(date);
        while (!period) {
            date = new Date(date.getFullYear(), date.getMonth(), date.getDate() - 1, 23, 59, 59, 999);
            period = this.calendar.getSchedule(date).getCurrentPeriod(date);
        }
        return period;
    }

    getCurrentPeriodNumber() {
        var date = this.getDate();
        return this.calendar.getSchedule(date).getCurrentPeriodIndex(date);
    }

    getCompletedPeriods() {
        var date = this.getDate();
        var completedPeriods = [];
        var schedule = this.getCurrentSchedule();
        for (var i = 0; i < this.getCurrentPeriodNumber(); i++)
            completedPeriods.push(schedule.getPeriodByIndex(i, date));
        return completedPeriods;
    }

    getFuturePeriods() {
        var date = this.getDate();
        var futurePeriods = [];
        var schedule = this.getCurrentSchedule();
        for (var i = this.getCurrentPeriodNumber() + 1; i < schedule.length; i++)
            futurePeriods.push(schedule.getPeriodByIndex(i, date));
        return futurePeriods;
    }

    getCurrentSchedule(date) {
        if (!date) date = this.getDate();
        return this.calendar.getSchedule(date);
    }
}

module.exports = BellTimer;<commit_msg>Separate loading and requesting<commit_after>const _ = require('lodash')
const $ = require('jquery')
const async = require('async')

const Period = require('./Period')
const Schedule = require('./Schedule')
const Calendar = require('./Calendar')

class BellTimer {
  constructor (cookieManager, requestManager) {
    this.cookieManager = cookieManager
    this.requestManager = requestManager

    this.debug = function () {}
    this.devMode = false
    this.startTime = 0
    this.timeScale = 1

    var devModeCookie = this.cookieManager.get('dev_mode')
    if (devModeCookie) {
      this.enableDevMode(devModeCookie.startDate, devModeCookie.scale)
    }
  }

  loadCustomCourses () {
    var courses = this.cookieManager.get('courses')

        // Make sure there is at least one section, otherwise it will infinite loop
    var foundSection = false
    for (let id in courses) {
      var course = courses[id]
      if (course.sections.length) {
        foundSection = true
        break
      }
    }
    if (!foundSection) {
      courses = {
        'none': {
          name: 'No sections',
          sections: [
            ['Wednesday', [0, 0],
                            [24, 0]
            ]
          ]
        }
      }
    }

    var week = {
      Sun: {
        name: 'Sunday'
      },
      Mon: {
        name: 'Monday'
      },
      Tue: {
        name: 'Tuesday'
      },
      Wed: {
        name: 'Wednesday'
      },
      Thu: {
        name: 'Thursday'
      },
      Fri: {
        name: 'Friday'
      },
      Sat: {
        name: 'Saturday'
      }
    }
    var special = {}
    var schedules = {}

    var periods = {}

    for (let id in courses) {
      var course = courses[id]
      var name = course.name
      var sections = course.sections

      for (let section of sections) {
        var [day, start, end] = section
        if (!periods[day]) { periods[day] = [] }

        periods[day].push(new Period({
          hour: start[0],
          min: start[1]
        }, name))
        periods[day].push(new Period({
          hour: end[0],
          min: end[1]
        }, 'Free'))
      }
    }

    for (var day in week) {
      day = week[day].name
      schedules[day] = new Schedule(day, day, periods[day] || [])
    }

    var calendar = new Calendar(week, special, schedules, this.cookieManager.get('periods'))

    this.setCorrection(0)
    this.calendar = calendar
  }

  loadData (dataSource, sources, version, correction, schedules, calendar) {
    if (sources.indexOf(dataSource) < 0) {
      this.cookieManager.remove('source')
      return this.loadData(dataSource, sources, version, correction, schedules, calendar)
    }

    this.source = dataSource

    if (this.version && this.version != version) {
      // Give IndexedDB time to write (TODO: make more robust)
      setTimeout(() => $(window)[0].location.reload(), 1000)
    } else { this.version = version }

    this.setCorrection(parseInt(correction))

    var parseSchedules = require('./ScheduleParser')
    var parseCalendar = require('./CalendarParser')

    schedules = parseSchedules(schedules, this.cookieManager.get('periods'))
    calendar = parseCalendar(calendar, schedules)

    this.calendar = calendar
  }

  async reloadData () {
    var dataSource = this.cookieManager.get('source', 'lahs')
    if (dataSource === 'custom') {
      this.source = dataSource
      return this.loadCustomCourses()
    }

    var [sources, version, correction, schedules, calendar] = await Promise.all([
      this.requestManager.get('/api/sources/names'),
      this.requestManager.get('/api/version'),
      this.requestManager.get(`/api/data/${dataSource}/correction`, '0'),
      this.requestManager.get(`/api/data/${dataSource}/schedules`),
      this.requestManager.get(`/api/data/${dataSource}/calendar`)
    ])

    return this.loadData(dataSource, sources, version, correction, schedules, calendar)
  }

  async initialize () {
    return Promise.all([
      this.reloadData(),
      this.initializeTimesync()
    ])
  }

  async initializeTimesync () {
    if (typeof timesync === 'undefined') {
      this.ts = Date
      console.warn('Timesync not found')
      return this.ts
    }

    var ts = timesync.create({
      server: this.requestManager.host + '/timesync',
      interval: 4 * 60 * 1000
    })

    ts.on('change', offset =>
            this.debug('Timesync offset: ' + offset))

    this.ts = ts

    return new Promise((resolve, reject) =>
            ts.on('sync', _.once(() => resolve(ts))))
  }

  setCorrection (correction) {
    this.correction = correction
  }

  getCorrection () {
    return this.correction
  }

  enableDevMode (startDate, scale) {
    console.warn('You are in Developer Mode, at ' + scale + 'x speed! Disable with `bellTimer.disableDevMode()`')

    this.devMode = true
    this.startTime = new Date(startDate).getTime()
    this.devModeStartTime = Date.now()
    this.timeScale = scale

    this.cookieManager.set('dev_mode', {
      enabled: this.devMode,
      startDate: startDate,
      scale: scale
    })
  }

  disableDevMode () {
    this.devMode = false
    this.cookieManager.remove('dev_mode')
  }

  getDate () {
    if (this.devMode) {
      return new Date((this.startTime + ((Date.now() - this.devModeStartTime) * this.timeScale) + this.correction))
    }
    if (!this.ts) { this.ts = Date }
    return new Date(this.ts.now() + this.correction)
  }

  getTimeRemainingMs () {
    var date = this.getDate()
    return this.getNextPeriod().timestamp.getTime() - date.getTime()
  }

  getTimeRemainingString () {
    var date = this.getDate()
    var displayTimeNumber = function (time) {
      time = Math.ceil(time / 1000) * 1000
      var hours = Math.floor(time / 1000 / 60 / 60)
      var seconds = Math.floor(time / 1000 % 60).toString()
      if (seconds.length < 2) { seconds = '0' + seconds }
      var minutes = Math.floor(time / 1000 / 60 % 60).toString()
      if (minutes.length < 2 && hours) { minutes = '0' + minutes }
      return (hours < 1) ? minutes + ':' + seconds : hours + ':' + minutes + ':' + seconds
    }
    return displayTimeNumber(this.getTimeRemainingMs())
  }

  getProportionElapsed () {
    var date = this.getDate()

    var currentPeriodStart = this.getCurrentPeriod().timestamp.getTime()
    var nextPeriodStart = this.getNextPeriod().timestamp.getTime()

    var totalTime = nextPeriodStart - currentPeriodStart
    var elapsedTime = date.getTime() - currentPeriodStart

    return elapsedTime / totalTime
  }

  getNextPeriod () {
    var date = this.getDate()
    var period = this.calendar.getSchedule(date).getNextPeriod(date)
    while (!period) {
      date = new Date(date.getFullYear(), date.getMonth(), date.getDate() + 1, 0, 0, 0, 0)
      period = this.calendar.getSchedule(date).getFirstPeriod(date)
    }
    return period
  }
  getPreviousPeriod () {
    var date = this.getDate()
    var period = this.calendar.getSchedule(date).getPreviousPeriod(date)
    while (!period) {
      date = new Date(date.getFullYear(), date.getMonth(), date.getDate() - 1, 0, 0, 0, 0)
      period = this.calendar.getSchedule(date).getLastPeriod(date)
    }
    return period
  }

  getCurrentPeriod () {
    var date = this.getDate()
    var period = this.calendar.getSchedule(date).getCurrentPeriod(date)
    while (!period) {
      date = new Date(date.getFullYear(), date.getMonth(), date.getDate() - 1, 23, 59, 59, 999)
      period = this.calendar.getSchedule(date).getCurrentPeriod(date)
    }
    return period
  }

  getCurrentPeriodNumber () {
    var date = this.getDate()
    return this.calendar.getSchedule(date).getCurrentPeriodIndex(date)
  }

  getCompletedPeriods () {
    var date = this.getDate()
    var completedPeriods = []
    var schedule = this.getCurrentSchedule()
    for (var i = 0; i < this.getCurrentPeriodNumber(); i++) { completedPeriods.push(schedule.getPeriodByIndex(i, date)) }
    return completedPeriods
  }

  getFuturePeriods () {
    var date = this.getDate()
    var futurePeriods = []
    var schedule = this.getCurrentSchedule()
    for (var i = this.getCurrentPeriodNumber() + 1; i < schedule.length; i++) { futurePeriods.push(schedule.getPeriodByIndex(i, date)) }
    return futurePeriods
  }

  getCurrentSchedule (date) {
    if (!date) date = this.getDate()
    return this.calendar.getSchedule(date)
  }
}

module.exports = BellTimer
<|endoftext|>


<commit_before>export default function bootstrap({
  supportedLocales,
  defaultLocale,
  currentLocale,
  parentLocale,
  application,
  configuration,
  legacyLocalization,
  legacyLocalizationFallback,
  localeFiles,
}) {
  const ctx = window.L20n.getContext();
  // The L20n context (ctx) should only call linkResource once per file.
  // We need to:
  //    * Strip out the locale from the path string (map)
  //    * Remove duplicates (reduce)
  //    * link each resource against a locale (forEach)
  localeFiles.map((path) => {
    let trimmed = path;
    supportedLocales.forEach((locale) => {
      trimmed = trimmed.replace(new RegExp('/' + locale + '/'), '/');
    });

    const index = trimmed.lastIndexOf('/');
    const basePath = trimmed.substring(0, index);
    const file = trimmed.substring(index + 1, trimmed.length);
    return {
      base: basePath,
      file: file,
    };
  })
  .reduce((p, c) => {
    if (p.some((pathInfo) => {
      return pathInfo.base === c.base && pathInfo.file === c.file;
    })) {
      return p;
    }

    return p.concat(c);
  }, [])
  .forEach((pathInfo) => {
    ctx.linkResource((locale) => {
      return [pathInfo.base, locale, pathInfo.file].join('/');
    });
  });
  ctx.registerLocales(defaultLocale, supportedLocales);
  ctx.requestLocales(currentLocale);
  window.localeContext = ctx;

  ctx.ready(() => {
    window.require([application].concat(configuration), (Application, appConfig) => {
      let completed = false;

      const req = (requires) => {
        require(requires.concat('dojo/domReady!'), () => {
          if (completed) {
            return;
          }

          let results = moment.locale(parentLocale);

          // moment will return the set culture if successful, otherwise it returns the currently set culture.
          // Check to see if the culture set failed, and attept to use the specific culture instead
          if (results !== parentLocale) {
            results = moment.locale(currentLocale);
            if (results !== currentLocale) {
              console.error(`Failed to set the culture for moment.js, culture set to ${results}`); // eslint-disable-line
            }
          }
          const instance = new Application(appConfig);
          instance.localeContext = ctx;
          instance.activate();
          instance.init();
          instance.run();
          completed = true;
        });
      };

      require.on('error', () => {
        console.log('Error loading localization, falling back to "en"'); // eslint-disable-line
        req(legacyLocalizationFallback);
      });

      req(legacyLocalization);
    });
  });
}
<commit_msg>INFORCRM-12458: Provide a current locale context and a 'default' locale context.<commit_after>export default function bootstrap({
  supportedLocales,
  defaultLocale,
  currentLocale,
  parentLocale,
  application,
  configuration,
  legacyLocalization,
  legacyLocalizationFallback,
  localeFiles,
}) {
  const ctx = window.L20n.getContext();
  const defaultCtx = window.L20n.getContext();

  // The L20n context (ctx) should only call linkResource once per file.
  // We need to:
  //    * Strip out the locale from the path string (map)
  //    * Remove duplicates (reduce)
  //    * link each resource against a locale (forEach)
  localeFiles.map((path) => {
    let trimmed = path;
    supportedLocales.forEach((locale) => {
      trimmed = trimmed.replace(new RegExp('/' + locale + '/'), '/');
    });

    const index = trimmed.lastIndexOf('/');
    const basePath = trimmed.substring(0, index);
    const file = trimmed.substring(index + 1, trimmed.length);
    return {
      base: basePath,
      file: file,
    };
  })
  .reduce((p, c) => {
    if (p.some((pathInfo) => {
      return pathInfo.base === c.base && pathInfo.file === c.file;
    })) {
      return p;
    }

    return p.concat(c);
  }, [])
  .forEach((pathInfo) => {
    [ctx, defaultCtx].forEach((context) => {
      context.linkResource((locale) => {
        return [pathInfo.base, locale, pathInfo.file].join('/');
      });
    });
  });

  ctx.registerLocales(defaultLocale, supportedLocales);
  ctx.requestLocales(currentLocale);
  defaultCtx.registerLocales(defaultLocale);
  defaultCtx.requestLocales(defaultLocale);

  window.localeContext = ctx;
  window.defaultLocaleContext = defaultCtx;

  Promise.all([new Promise((resolve) => {
    ctx.ready(() => resolve(true));
  }), new Promise((resolve) => {
    defaultCtx.ready(() => resolve(true));
  })]).then(() => {
    window.require([application].concat(configuration), (Application, appConfig) => {
      let completed = false;

      const req = (requires) => {
        require(requires.concat('dojo/domReady!'), () => {
          if (completed) {
            return;
          }

          let results = moment.locale(parentLocale);

          // moment will return the set culture if successful, otherwise it returns the currently set culture.
          // Check to see if the culture set failed, and attept to use the specific culture instead
          if (results !== parentLocale) {
            results = moment.locale(currentLocale);
            if (results !== currentLocale) {
              console.error(`Failed to set the culture for moment.js, culture set to ${results}`); // eslint-disable-line
            }
          }
          const instance = new Application(appConfig);
          instance.localeContext = ctx;
          instance.activate();
          instance.init();
          instance.run();
          completed = true;
        });
      };

      require.on('error', () => {
        console.log('Error loading localization, falling back to "en"'); // eslint-disable-line
        req(legacyLocalizationFallback);
      });

      req(legacyLocalization);
    });
  });
}
<|endoftext|>


<commit_before>// Streaming logs
var pushstream = new PushStream({
  host: window.location.hostname,
  port: 443,
  useSSL: true,
  modes: "eventsource",
  urlPrefixEventsource: "/__/sub",
  channelsByArgument: true,
  channelsArgument: "id"
});
pushstream.onmessage = function(data,id,channel) {
  // console.log(data);

  // Check that this channel matches the active channel
  if(document.getElementById('active-channel') && document.getElementById('active-channel').value == data.channel) {
    var html = data.html;
    var autoScroll = (window.innerHeight + window.scrollY) >= document.body.offsetHeight;
    var line = document.createElement('div');
    line.innerHTML = html;

    // Format the timestamp in the display timezone
    var timestamp = line.querySelector("time").attributes['datetime'].value;
    var displayTime = moment(timestamp).utcOffset(document.getElementById('tz-offset').value).format("hh:mm");
    line.querySelector(".dt-published a").innerText = displayTime;

    document.getElementById('log-lines').appendChild(line.childNodes[0]);
    // Auto-scroll if the window is already scrolled to the bottom
    if(autoScroll) {
      window.scrollTo(0,document.body.scrollHeight);
    }
    if(window.check_alert) {
      check_alert(data);
    }
  } else {
    channel_activity(data.channel, data.type);
  }
}
pushstream.addChannel('chat');
pushstream.connect();

// Channel unread indicators
function channel_activity(channel, type) {
  var tab = document.querySelector('li.channel[data-channel="'+channel+'"]');
  if(tab && type == 'message') {
    tab.classList.add('activity');
  }

  var channels = Cookies.getJSON('unread');
  if(channels == "undefined") {
    channels = {};
  }
  if(typeof channels[channel] == 'undefined' || channels[channel] == 'read') {
    channels[channel] = 'unread';
    Cookies.set('unread', channels);
  }
}

function channel_unread(channel) {
  var channels = Cookies.getJSON('unread');
  return channels && channels[channel] == 'unread';
}

function channel_read(channel) {
  var channels = Cookies.getJSON('unread');
  if(channels) {
    channels[channel] = 'read';
  }
  Cookies.set('unread', channels);
  var tab = document.querySelector('li.channel[data-channel="'+channel+'"]');
  if(tab) {
    tab.classList.remove('activity');
  }
}<commit_msg>fix streaming<commit_after>// Streaming logs
var pushstream = new PushStream({
  host: window.location.hostname,
  port: 443,
  useSSL: true,
  modes: "eventsource",
  urlPrefixEventsource: "/__/sub",
  channelsByArgument: true,
  channelsArgument: "id"
});
pushstream.onmessage = function(data,id,channel) {
  // console.log(data);

  // Check that this channel matches the active channel
  if(document.getElementById('active-channel') && document.getElementById('active-channel').value == data.channel) {
    var html = data.html;
    var autoScroll = (window.innerHeight + window.scrollY) >= document.body.offsetHeight;
    var line = document.createElement('div');
    line.innerHTML = html;

    // Format the timestamp in the display timezone
    var timestamp = line.querySelector("time").attributes['datetime'].value;
    var displayTime = moment(timestamp).utcOffset(document.getElementById('tz-offset').value).format("hh:mm");
    line.querySelector("time a").innerText = displayTime;

    document.getElementById('log-lines').appendChild(line.childNodes[0]);
    // Auto-scroll if the window is already scrolled to the bottom
    if(autoScroll) {
      window.scrollTo(0,document.body.scrollHeight);
    }
    if(window.check_alert) {
      check_alert(data);
    }
  } else {
    channel_activity(data.channel, data.type);
  }
}
pushstream.addChannel('chat');
pushstream.connect();

// Channel unread indicators
function channel_activity(channel, type) {
  var tab = document.querySelector('li.channel[data-channel="'+channel+'"]');
  if(tab && type == 'message') {
    tab.classList.add('activity');
  }

  var channels = Cookies.getJSON('unread');
  if(channels == "undefined") {
    channels = {};
  }
  if(typeof channels[channel] == 'undefined' || channels[channel] == 'read') {
    channels[channel] = 'unread';
    Cookies.set('unread', channels);
  }
}

function channel_unread(channel) {
  var channels = Cookies.getJSON('unread');
  return channels && channels[channel] == 'unread';
}

function channel_read(channel) {
  var channels = Cookies.getJSON('unread');
  if(channels) {
    channels[channel] = 'read';
  }
  Cookies.set('unread', channels);
  var tab = document.querySelector('li.channel[data-channel="'+channel+'"]');
  if(tab) {
    tab.classList.remove('activity');
  }
}<|endoftext|>


<commit_before>//read more at : http://jsfiddle.net/ganarajpr/LQGE2/
'use strict';
var widgetConfig = function($routeProvider){ $routeProvider.when( '/', { controller: 'DemoController', templateUrl: 'widgetTemplate' } ) };
var WidgetApp = angular.module( 'DemoApp', ['ngCookies'] ).config( widgetConfig );

WidgetApp.controller('DemoController', function($scope, $location, $routeParams, $http, $cookieStore, $timeout ){
    $scope["widgets"] = $http.get(jsRoutes.controllers.DemosController.listWidgetForDemoUser( $scope["userId"] ).url ).then(function(data){
        var searchWidgetId = $cookieStore.get("widgetId");
        var cachedWidget = $( data.data ).filter(function(index,value){ return value.id == searchWidgetId })[0];

        // return the cached widget or couchbase.
        var selectedWidget = angular.isDefined(cachedWidget) ? cachedWidget : $.grep(data.data, function(item,index){ return item.productName == "Couchbase"});
        selectedWidget =  selectedWidget.length > 0  ? selectedWidget[0] : null; // remove array from JQuery

        $scope.completedWT = false;
        $.receiveMessage(function (e) {
                console.log(["demo got the message", e]);

                var data = JSON.parse(e.data);
                console.dir(data);
                // installation finished
                if (data.status.instanceIsAvailable) {
                    // if not already shown, display customized overlay
                    if (!$scope.completedWT) {
                        $scope.completedWT = true;
                        $scope.$showWT();
                    }
                } else { // reset flag
                    $scope.completedWT = false;
                }
            },
            function (origin) {
                return true;
            }
        ); // support for different domains

        // if no cached widget and no couchbase default to 0.
        $scope.menuClick(selectedWidget == null ? data.data[0] : selectedWidget );
        return data.data;
    } );
    $scope.menuClick = function( widget ){
        $scope.selectedWidget = widget;
        $cookieStore.put("widgetId",widget.id);
    };

    $scope.demoSort = function ( widget ){
        return widget.productName == "Couchbase" ? 0 : 1;
    };

    /////////////// Walkthrough!
    var walkthroughChecker = null;
    $scope.hideWT = true; // default
    $scope.$showWT = function(){
        $scope.hideWT = false;
        $(".walkthrough" ).fadeIn();
    };

    $scope.$hideWT = function(){
        $scope.hideWT = true;
        $(".walkthrough" ).fadeOut();
    };

    $scope.dismissWalkthrough = function () {
        $cookieStore.put("dismissWT", true);
        $scope.$hideWT();
        $scope.completedWT = false;
    };

    $scope.shouldShowWalkthrough = function(){
        var dismissWTCookieValue = $cookieStore.get("dismissWT");
        return  !angular.isDefined(dismissWTCookieValue) || dismissWTCookieValue.toString() != "true";
    };

    $scope.checkWalkthrough = function(){
        if ( !$scope.shouldShowWalkthrough() ){
            $scope.dismissWalkthrough();
            clearInterval(walkthroughChecker);
        }
    };

    if ( $scope.shouldShowWalkthrough() ){
        $timeout(function(){
            $scope.$showWT();
        walkthroughChecker = setInterval( function(){  $scope.checkWalkthrough(); $scope.$apply() }, 1000 );
        }, 2000);
    }else{
        $scope.$hideWT();
    }
});

<commit_msg>show overlay when links are ready<commit_after>//read more at : http://jsfiddle.net/ganarajpr/LQGE2/
'use strict';
var widgetConfig = function($routeProvider){ $routeProvider.when( '/', { controller: 'DemoController', templateUrl: 'widgetTemplate' } ) };
var WidgetApp = angular.module( 'DemoApp', ['ngCookies'] ).config( widgetConfig );

WidgetApp.controller('DemoController', function($scope, $location, $routeParams, $http, $cookieStore, $timeout ){
    $scope["widgets"] = $http.get(jsRoutes.controllers.DemosController.listWidgetForDemoUser( $scope["userId"] ).url ).then(function(data){
        var searchWidgetId = $cookieStore.get("widgetId");
        var cachedWidget = $( data.data ).filter(function(index,value){ return value.id == searchWidgetId })[0];

        // return the cached widget or couchbase.
        var selectedWidget = angular.isDefined(cachedWidget) ? cachedWidget : $.grep(data.data, function(item,index){ return item.productName == "Couchbase"});
        selectedWidget =  selectedWidget.length > 0  ? selectedWidget[0] : null; // remove array from JQuery

        $scope.completedWT = false;
        $.receiveMessage(function (e) {
                console.log(["demo got the message", e]);

                var data = JSON.parse(e.data);
                console.dir(data);
                // installation finished
                if (data.status.instanceIsAvailable) {
                    $scope.$showWT(true);
                    // if not already shown, display customized overlay
                    /*if (!$scope.completedWT) {
                        $scope.completedWT = true;
                        $scope.$showWT();
                    }*/
                } /*else { // reset flag
                    $scope.completedWT = false;
                }*/
            },
            function (origin) {
                return true;
            }
        ); // support for different domains

        // if no cached widget and no couchbase default to 0.
        $scope.menuClick(selectedWidget == null ? data.data[0] : selectedWidget );
        return data.data;
    } );
    $scope.menuClick = function( widget ){
        $scope.selectedWidget = widget;
        $cookieStore.put("widgetId",widget.id);
    };

    $scope.demoSort = function ( widget ){
        return widget.productName == "Couchbase" ? 0 : 1;
    };

    /////////////// Walkthrough!
    var walkthroughChecker = null;
    $scope.hideWT = true; // default
    $scope.$showWT = function(completed){
        $scope.hideWT = false;
        !!completed && ($scope.completedWT = true);
        $(".walkthrough" ).fadeIn();
    };

    $scope.$hideWT = function(){
        $scope.hideWT = true;
        $(".walkthrough" ).fadeOut();
    };

    $scope.dismissWalkthrough = function () {
        $cookieStore.put("dismissWT", true);
        $scope.$hideWT();
        $scope.completedWT = false;
    };

    $scope.shouldShowWalkthrough = function(){
        var dismissWTCookieValue = $cookieStore.get("dismissWT");
        return  !angular.isDefined(dismissWTCookieValue) || dismissWTCookieValue.toString() != "true";
    };

    $scope.checkWalkthrough = function(){
        if ( !$scope.shouldShowWalkthrough() ){
            $scope.dismissWalkthrough();
            clearInterval(walkthroughChecker);
        }
    };

    if ( $scope.shouldShowWalkthrough() ){
        $timeout(function(){
            $scope.$showWT();
        walkthroughChecker = setInterval( function(){  $scope.checkWalkthrough(); $scope.$apply() }, 1000 );
        }, 2000);
    }else{
        $scope.$hideWT();
    }
});

<|endoftext|>


<commit_before>// ==UserScript==
// @name         Firefox Focus Fix
// @namespace    http://tinygiant.io
// @version      1.0.0.0
// @description  Fixes the recent change implemented by Firefox which places the caret at the end of the text on focus instead of the beginning
// @author       @TinyGiant
// @include      /^https?:\/\/\w*.?(stackexchange.com|stackoverflow.com|serverfault.com|superuser.com|askubuntu.com|stackapps.com|mathoverflow.net)\/q(uestions)?\/\d+/
// @grant        none
// ==/UserScript==

document.body.appendChild(document.createElement('script')).textContent = `(function() {
    const oldfocus = HTMLElement.prototype.focus;

    HTMLElement.prototype.focus = function() {
        oldfocus.call(this);
        if (this.selectionEnd === this.selectionStart)
            this.selectionEnd = 0;
    };
})()`;
<commit_msg>Restrict effects to .wmd-input elements only<commit_after>// ==UserScript==
// @name         Firefox Focus Fix
// @namespace    http://tinygiant.io
// @version      1.0.0.1
// @description  Fixes the recent change implemented by Firefox which places the caret at the end of the text on focus instead of the beginning
// @author       @TinyGiant
// @include      /^https?:\/\/\w*.?(stackexchange.com|stackoverflow.com|serverfault.com|superuser.com|askubuntu.com|stackapps.com|mathoverflow.net)\/q(uestions)?\/\d+/
// @grant        none
// ==/UserScript==

document.body.appendChild(document.createElement('script')).textContent = `(function() {
    const oldfocus = HTMLElement.prototype.focus;

    HTMLElement.prototype.focus = function() {
        oldfocus.call(this);
        if (/wmd-input/.test(this.className))
            if (this.selectionEnd === this.selectionStart)
                this.selectionEnd = 0;
    };
})()`;
<|endoftext|>


<commit_before>'use strict'

const PLUGINS_RE = /^(?:@babel\/|babel-)plugin-.+$/
const PRESETS_RE = /^@babel\/preset-.+$/

const NODE_ENV = process.env.NODE_ENV || 'development'
const __PROD__ = NODE_ENV === 'production'
const __TEST__ = NODE_ENV === 'test'

const configs = {
  '@babel/plugin-proposal-decorators': {
    legacy: true,
  },
  '@babel/plugin-proposal-pipeline-operator': {
    proposal: 'minimal',
  },
  '@babel/preset-env'(pkg) {
    return {
      debug: !__TEST__,

      // disabled until https://github.com/babel/babel/issues/8323 is resolved
      // loose: true,

      shippedProposals: true,
      targets: (() => {
        let node = (pkg.engines || {}).node
        if (node !== undefined) {
          const trimChars = '^=>~'
          while (trimChars.includes(node[0])) {
            node = node.slice(1)
          }
        }
        return { browsers: pkg.browserslist, node }
      })(),
    }
  },
}

const getConfig = (key, ...args) => {
  const config = configs[key]
  return config === undefined ? {} : typeof config === 'function' ? config(...args) : config
}

// some plugins must be used in a specific order
const pluginsOrder = ['@babel/plugin-proposal-decorators', '@babel/plugin-proposal-class-properties']

module.exports = function (pkg, plugins, presets) {
  plugins === undefined && (plugins = {})
  presets === undefined && (presets = {})

  Object.keys(pkg.devDependencies || {}).forEach(name => {
    if (!(name in presets) && PLUGINS_RE.test(name)) {
      plugins[name] = getConfig(name, pkg)
    } else if (!(name in presets) && PRESETS_RE.test(name)) {
      presets[name] = getConfig(name, pkg)
    }
  })

  return {
    comments: !__PROD__,
    ignore: __PROD__ ? [/\.spec\.js$/] : undefined,
    plugins: Object.keys(plugins)
      .map(plugin => [plugin, plugins[plugin]])
      .sort(([a], [b]) => {
        const oA = pluginsOrder.indexOf(a)
        const oB = pluginsOrder.indexOf(b)
        return oA !== -1 && oB !== -1 ? oA - oB : a < b ? -1 : 1
      }),
    presets: Object.keys(presets).map(preset => [preset, presets[preset]]),
  }
}
<commit_msg>feat(babel-config): use top level targets option<commit_after>'use strict'

const PLUGINS_RE = /^(?:@babel\/|babel-)plugin-.+$/
const PRESETS_RE = /^@babel\/preset-.+$/

const NODE_ENV = process.env.NODE_ENV || 'development'
const __PROD__ = NODE_ENV === 'production'
const __TEST__ = NODE_ENV === 'test'

const configs = {
  '@babel/plugin-proposal-decorators': {
    legacy: true,
  },
  '@babel/plugin-proposal-pipeline-operator': {
    proposal: 'minimal',
  },
  '@babel/preset-env': {
    debug: !__TEST__,

    // disabled until https://github.com/babel/babel/issues/8323 is resolved
    // loose: true,

    shippedProposals: true,
  },
}

const getConfig = (key, ...args) => {
  const config = configs[key]
  return config === undefined ? {} : typeof config === 'function' ? config(...args) : config
}

// some plugins must be used in a specific order
const pluginsOrder = ['@babel/plugin-proposal-decorators', '@babel/plugin-proposal-class-properties']

module.exports = function (pkg, plugins, presets) {
  plugins === undefined && (plugins = {})
  presets === undefined && (presets = {})

  Object.keys(pkg.devDependencies || {}).forEach(name => {
    if (!(name in presets) && PLUGINS_RE.test(name)) {
      plugins[name] = getConfig(name, pkg)
    } else if (!(name in presets) && PRESETS_RE.test(name)) {
      presets[name] = getConfig(name, pkg)
    }
  })

  return {
    comments: !__PROD__,
    ignore: __PROD__ ? [/\.spec\.js$/] : undefined,
    plugins: Object.keys(plugins)
      .map(plugin => [plugin, plugins[plugin]])
      .sort(([a], [b]) => {
        const oA = pluginsOrder.indexOf(a)
        const oB = pluginsOrder.indexOf(b)
        return oA !== -1 && oB !== -1 ? oA - oB : a < b ? -1 : 1
      }),
    presets: Object.keys(presets).map(preset => [preset, presets[preset]]),
    targets: (() => {
      let node = (pkg.engines || {}).node
      if (node !== undefined) {
        const trimChars = '^=>~'
        while (trimChars.includes(node[0])) {
          node = node.slice(1)
        }
      }
      return { browsers: pkg.browserslist, node }
    })(),
  }
}
<|endoftext|>


<commit_before>(function() {
    var CONST_NUMBER_OF_COMPONENTS = 5; // how many components to show in the report

    // FIXME: don't use hard coded months, move to using 'last' bug number
    var months = ["2016-06-01", "2016-07-01", "2016-08-01", "2016-09-01", "2016-10-01",
         "2016-11-01", "2016-12-01"];

    var result = { bugs: [] };

    var completed = 0;

    // base bugzilla API query
    var baseAPIRequest = "https://bugzilla.mozilla.org/rest/bug?include_fields=id,priority,product,component&chfield=[Bug%20creation]&f1=flagtypes.name&f2=component&f3=component&o1=notequals&o2=notequals&o3=notequals&resolution=---&v1=needinfo%3F&v2=general&v3=untriaged&limit=10000";

    var reportDetailRequest = "https://bugzilla.mozilla.org/buglist.cgi?chfield=[Bug%20creation]&chfieldfrom=2016-06-01&chfieldto=Now&f1=flagtypes.name&f2=component&f3=component&limit=0&o1=notequals&o2=notequals&o3=notequals&resolution=---&v1=needinfo%3F&v2=general&v3=untriaged";

    // convenience method for making links
    function buglistLink(value, product, component, priority) {
        priority = priority || null;
        var productEncoded = encodeURIComponent(product);
        var componentEncoded = encodeURIComponent(component);
        var url = `${reportDetailRequest}&product=${productEncoded}&component=${componentEncoded}`;
        if (priority) {
            url = `${url}&priority=${priority}`;
        }
        var link = `<a target="_blank" href="${url}">${value}</a>`;
        return link;
    }

    var tmp = document.querySelector('.tmp');
    var tableOuter = document.querySelector('table thead');

    if (!fetch) {
        view.innerHTML = "Your browser does not support the fetch standard, which is needed to load this page.";
        return;
    }

    // This fetches all the open bugs in Firefox related components opened since June 1st, 2016
    // which don't have a pending needinfo, and are not in the general and untriaged components
    // this does not include security filtered bugs

    months.forEach(function(month, i) {
        var next;

        // get the month bins for the request
        if (i < (months.length - 1)) {
            next = months[i + 1];
        } else {
            next = 'NOW';
        }

        fetch(baseAPIRequest
                + "&product=Core&product=Firefox&product=Firefox%20for%20Android&product=Firefox%20for%20iOS&product=Toolkit&chfieldfrom="
                + month + "&chfieldto=" + next)
            .then(function(response) { // $DEITY, I can't wait for await
                if (response.ok) {
                    response.json()
                    .then(function(data) {
                        completed ++;
                        console.log("completed", completed);
                        Array.prototype.push.apply(result.bugs, data.bugs); // call push on each result.bugs
                        if (completed === months.length) {
                            console.log("all fetched!");
                            process(result);
                            setLastRunDate();
                        }
                    });
                }
            });
    });

    function process(result) {

        // stuff to collect results into
        var data = {};
        var report = {};
        var reportRows = '';
        var reportTable = '';
        var all = { '--': 0, P1: 0, P2: 0, P3: 0, P4: 0, P5: 0, total: 0 };
        var top = { '--': 0, P1: 0, P2: 0, P3: 0, P4: 0, P5: 0, total: 0 };

        // count bugs by product, component, and priority
        result.bugs.forEach((bug, i) => {
            if (!data[bug.product]) {
                data[bug.product] = {}; // add new product
            }
            if (!data[bug.product][bug.component]) {
                data[bug.product][bug.component] = { // add new component
                    total: 0,
                    '--': 0,
                    P1: 0,
                    P2: 0,
                    P3: 0,
                    P4: 0,
                    P5: 0
                }
            }
            data[bug.product][bug.component].total ++;
            all.total ++;
            data[bug.product][bug.component][bug.priority] ++;
            all[bug.priority] ++;
        });

        // generate a report by product of the components sorted
        // by the most untriaged bugs, descending
        Object.keys(data).forEach(product => {
            var list = [];
            Object.keys(data[product]).forEach(component => {
               list.push({component: component, untriaged: data[product][component]['--']});
            });
            report[product] = list.sort((a, b) => {
                return b.untriaged - a.untriaged; // sort in descending order
            });
        });

        // print the top five untriaged components in each product
        // and hey, lookit those ES6 format strings!
        Object.keys(report).forEach(product => {
            reportRows = reportRows + `<tbody>`;
            report[product].slice(0, CONST_NUMBER_OF_COMPONENTS).forEach(item => { // use Array().slice to get the top components
                var component = item.component;
                reportRows = reportRows + `

                    ${product}: ${component}
                    ${buglistLink(data[product][component]['--'], product, component,'--')}
                    ${buglistLink(data[product][component].P1, product, component, 'P1')}
                    ${buglistLink(data[product][component].P2, product, component, 'P2')}
                    ${buglistLink(data[product][component].P3, product, component, 'P3')}
                    ${buglistLink(data[product][component].P4, product, component, 'P4')}
                    ${buglistLink(data[product][component].P5, product, component, 'P5')}
                    ${buglistLink(data[product][component].total, product, component)}

`;
                // add to top components total
                top['--'] += data[product][component]['--'];
                top.P1 += data[product][component].P1;
                top.P2 += data[product][component].P2;
                top.P3 += data[product][component].P3;
                top.P4 += data[product][component].P4;
                top.P5 += data[product][component].P5;
                top.total += data[product][component].total;
            });
            reportRows = reportRows + `</tbody>`;
        });

        // glue it all together
        reportTable = `${reportRows}

                        All Components
                        ${all['--']}
                        ${all.P1}
                        ${all.P2}
                        ${all.P3}
                        ${all.P4}
                        ${all.P5}
                        ${all.total}

                        Top Components
                        ${top['--']}
                        ${top.P1}
                        ${top.P2}
                        ${top.P3}
                        ${top.P4}
                        ${top.P5}
                        ${top.total}

`;

        // put the report in the document
        tmp.remove();
        tableOuter.insertAdjacentHTML('afterend', reportTable);

    }

    function setLastRunDate() {
        document.querySelector('.updated p').insertAdjacentText('afterbegin', `Last updated at ${new Date().toTimeString()}; reload page to update.`);
    }
})();

<commit_msg>Use the last and limit parameters to fetch batches of bugs. This is slower, but does not necessitate making changes to the app going forward.<commit_after>(function() {
    var CONST_NUMBER_OF_COMPONENTS = 5; // how many components to show in the report
    var result = { bugs: [] };
    var limit = sizeOfResult = 500;
    var completed = 0;

    // base bugzilla API query
    var baseAPIRequest = "https://bugzilla.mozilla.org/rest/bug?include_fields=id,priority,product,component&chfield=[Bug%20creation]&f1=flagtypes.name&f2=component&f3=component&f4=bug_id&o1=notequals&o2=notequals&o3=notequals&o4=greaterthan&resolution=---&v1=needinfo%3F&v2=general&v3=untriaged&limit=" + limit;

    var reportDetailRequest = "https://bugzilla.mozilla.org/buglist.cgi?chfield=[Bug%20creation]&chfieldfrom=2016-06-01&chfieldto=Now&f1=flagtypes.name&f2=component&f3=component&limit=0&o1=notequals&o2=notequals&o3=notequals&resolution=---&v1=needinfo%3F&v2=general&v3=untriaged";

    // convenience method for making links
    function buglistLink(value, product, component, priority) {
        priority = priority || null;
        var productEncoded = encodeURIComponent(product);
        var componentEncoded = encodeURIComponent(component);
        var url = `${reportDetailRequest}&product=${productEncoded}&component=${componentEncoded}`;
        if (priority) {
            url = `${url}&priority=${priority}`;
        }
        var link = `<a target="_blank" href="${url}">${value}</a>`;
        return link;
    }

    var tmp = document.querySelector('.tmp');
    var tableOuter = document.querySelector('table thead');

    if (!fetch) {
        view.innerHTML = "Your browser does not support the fetch standard, which is needed to load this page.";
        return;
    }

    // This recursively fetches all the open bugs in Firefox related components opened since June 1st, 2016
    // which don't have a pending needinfo, and are not in the general and untriaged components
    // this does not include security filtered bugs

    function getBugs(last) {
        var newLast;
        fetch(baseAPIRequest
            + "&product=Core&product=Firefox&product=Firefox%20for%20Android&product=Firefox%20for%20iOS&product=Toolkit&chfieldfrom="
            + "2016-06-01&chfieldto=NOW&v4=" + last)
            .then(function(response) { // $DEITY, I can't wait for await
                if (response.ok) {
                    response.json()
                    .then(function(data) {
                        newLast = data.bugs[data.bugs.length - 1].id;
                        /*
                            There are two ways we can fall out of this recursion: if the total
                            number of bugs is evenly divisible by limit (edge case) then we'll
                            err on fetching a result set twice, but not adding it, or if the number
                            of bugs in the batch returned is less than the limit, we'll add the last
                            batch and stop
                        */
                        if (newLast != last) {
                            completed ++;
                            console.log("completed", completed, "fetches");
                            Array.prototype.push.apply(result.bugs, data.bugs); // call push on each result.bugs
                            if (data.bugs.length === limit) {
                                console.log("calling again with last", newLast);
                                getBugs(newLast); // recursively call using the id of the last bug in the results as last
                            } else {
                                console.log("less bugs than limit");
                                complete();
                            }
                        } else {
                            console.log("edge case");
                            complete();
                        }
                    });
                }
            });
    }

    function complete() {
        console.log("all fetched!");
        process(result);
        setLastRunDate();
    }

    function process(result) {

        // stuff to collect results into
        var data = {};
        var report = {};
        var reportRows = '';
        var reportTable = '';
        var all = { '--': 0, P1: 0, P2: 0, P3: 0, P4: 0, P5: 0, total: 0 };
        var top = { '--': 0, P1: 0, P2: 0, P3: 0, P4: 0, P5: 0, total: 0 };

        // count bugs by product, component, and priority
        result.bugs.forEach((bug, i) => {
            if (!data[bug.product]) {
                data[bug.product] = {}; // add new product
            }
            if (!data[bug.product][bug.component]) {
                data[bug.product][bug.component] = { // add new component
                    total: 0,
                    '--': 0,
                    P1: 0,
                    P2: 0,
                    P3: 0,
                    P4: 0,
                    P5: 0
                }
            }
            data[bug.product][bug.component].total ++;
            all.total ++;
            data[bug.product][bug.component][bug.priority] ++;
            all[bug.priority] ++;
        });

        // generate a report by product of the components sorted
        // by the most untriaged bugs, descending
        Object.keys(data).forEach(product => {
            var list = [];
            Object.keys(data[product]).forEach(component => {
               list.push({component: component, untriaged: data[product][component]['--']});
            });
            report[product] = list.sort((a, b) => {
                return b.untriaged - a.untriaged; // sort in descending order
            });
        });

        // print the top five untriaged components in each product
        // and hey, lookit those ES6 format strings!
        Object.keys(report).forEach(product => {
            reportRows = reportRows + `<tbody>`;
            report[product].slice(0, CONST_NUMBER_OF_COMPONENTS).forEach(item => { // use Array().slice to get the top components
                var component = item.component;
                reportRows = reportRows + `

                    ${product}: ${component}
                    ${buglistLink(data[product][component]['--'], product, component,'--')}
                    ${buglistLink(data[product][component].P1, product, component, 'P1')}
                    ${buglistLink(data[product][component].P2, product, component, 'P2')}
                    ${buglistLink(data[product][component].P3, product, component, 'P3')}
                    ${buglistLink(data[product][component].P4, product, component, 'P4')}
                    ${buglistLink(data[product][component].P5, product, component, 'P5')}
                    ${buglistLink(data[product][component].total, product, component)}

`;
                // add to top components total
                top['--'] += data[product][component]['--'];
                top.P1 += data[product][component].P1;
                top.P2 += data[product][component].P2;
                top.P3 += data[product][component].P3;
                top.P4 += data[product][component].P4;
                top.P5 += data[product][component].P5;
                top.total += data[product][component].total;
            });
            reportRows = reportRows + `</tbody>`;
        });

        // glue it all together
        reportTable = `${reportRows}

                        All Components
                        ${all['--']}
                        ${all.P1}
                        ${all.P2}
                        ${all.P3}
                        ${all.P4}
                        ${all.P5}
                        ${all.total}

                        Top Components
                        ${top['--']}
                        ${top.P1}
                        ${top.P2}
                        ${top.P3}
                        ${top.P4}
                        ${top.P5}
                        ${top.total}

`;

        // put the report in the document
        tmp.remove();
        tableOuter.insertAdjacentHTML('afterend', reportTable);

    }

    function setLastRunDate() {
        document.querySelector('.updated p').insertAdjacentText('afterbegin', `Last updated at ${new Date().toTimeString()}; reload page to update.`);
    }

    getBugs(0);

})();

<|endoftext|>


<commit_before>Date.prototype.toDateInputValue = (function() {
    var local = new Date(this);
    local.setMinutes(this.getMinutes() - this.getTimezoneOffset());
    return local.toJSON().slice(0,10);
});

var mainObj = function() {
	console.log("It works!");
	$("input[name=startingat]").val((new Date()).toDateInputValue());

	$("#deleteModal").on('show.bs.modal',
		function(e)
		{
	    	$("button[name=deleteConfirm]").attr("data-id", $(e.relatedTarget).data('id'));
		}
	);

	$(document).on('click', "button[name=deleteConfirm]",
		function(e)
		{
			var id = $(this).attr("data-id");
			console.log("Delete id " + id);

			$.ajax({
				type: "GET",
				dataType: "json",
				url: "/Admonitus/ctl/Reminder/delete/" + id
			});

			$("#remindersList").find("tr[id=" + id + "]").remove();
		}
	);

	$("#reminderForm").submit(function(e) {
		e.preventDefault();

		var request = {
			"frequency": $("input[name=frequency]:checked").val(),
			"text": $("input[name=text]").val(),
			"startingat": $("input[name=startingat]").val()
		}
		$.ajax({
			type : "POST",
			dataType : "json",
			url : "/Admonitus/ctl/Reminder/add",
			data : request
		});
	});

	$.ajax({
		type : "GET",
		dataType : "json",
		url : "/Admonitus/ctl/Reminder/get",
		success : function(data) {

			$.each(data, function(index, entry) {
				newrow = $("#template").clone();
				newrow.find("td.number").text(index + 1);
				newrow.find("td.text").text(entry['text']);
				newrow.find("button[name=deleteButton]").attr('data-id', entry['id']);
				newrow.attr("id", entry['id']);

				switch (entry['frequency']) {
				case 0:
					newrow.find("td.frequency").text(
							"One-time	"
									+ new Date(entry['datestart'])
											.format('d:M:Y'));
					break;
				case 1:
					newrow.find("td.frequency").text(
							"Daily		"
									+ new Date(entry['datestart'])
											.format('d:M:Y'));
					break;
				case 2:
					newrow.find("td.frequency").text(
							"Weekly	"
									+ new Date(entry['datestart'])
											.format('d:M:Y'));
					break;
				case 3:
					newrow.find("td.frequency").text(
							"Monthly	"
									+ new Date(entry['datestart'])
											.format('d:M:Y'));
					break;
				default:
					newrow.find("td.frequency").text(
							"Invalid	"
									+ new Date(entry['datestart'])
											.format('d:M:Y'));

				}

				newrow.show();
				$("#remindersList").append(newrow);
			});

		}

	});
}

$("document").ready(mainObj);
<commit_msg>Clean up conversion of frequency to human readable name<commit_after>Date.prototype.toDateInputValue = (function() {
    var local = new Date(this);
    local.setMinutes(this.getMinutes() - this.getTimezoneOffset());
    return local.toJSON().slice(0,10);
});

var admonitus = {};
admonitus.transFreqNoToName = function(num)
{
	switch (num)
	{
	case 0:
		return "One-time";
	case 1:
		return "Daily";
	case 2:
		return "Weekly";
	case 3:
		return "Monthly";
	default:
		return "Invalid";
	}
}

var mainObj = function() {
	console.log("It works!");
	$("input[name=startingat]").val((new Date()).toDateInputValue());

	$("#deleteModal").on('show.bs.modal',
		function(e)
		{
	    	$("button[name=deleteConfirm]").attr("data-id", $(e.relatedTarget).data('id'));
		}
	);

	$(document).on('click', "button[name=deleteConfirm]",
		function(e)
		{
			var id = $(this).attr("data-id");
			console.log("Delete id " + id);

			$.ajax({
				type: "GET",
				dataType: "json",
				url: "/Admonitus/ctl/Reminder/delete/" + id
			});

			$("#remindersList").find("tr[id=" + id + "]").remove();
		}
	);

	$("#reminderForm").submit(function(e) {
		e.preventDefault();

		var request = {
			"frequency": $("input[name=frequency]:checked").val(),
			"text": $("input[name=text]").val(),
			"startingat": $("input[name=startingat]").val()
		}
		$.ajax({
			type : "POST",
			dataType : "json",
			url : "/Admonitus/ctl/Reminder/add",
			data : request
		});
	});

	$.ajax({
		type : "GET",
		dataType : "json",
		url : "/Admonitus/ctl/Reminder/get",
		success : function(data) {

			$.each(data, function(index, entry) {
				newrow = $("#template").clone();
				newrow.find("td.number").text(index + 1);
				newrow.find("td.text").text(entry['text']);
				newrow.find("button[name=deleteButton]").attr('data-id', entry['id']);
				newrow.attr("id", entry['id']);

				newrow.find("td.frequency").text(
					admonitus.transFreqNoToName(entry['frequency'])
					+ new Date(entry['datestart']).format('d-M-Y')
				);

				newrow.show();
				$("#remindersList").append(newrow);
			});

		}

	});
}

$("document").ready(mainObj);
<|endoftext|>