<commit_before>'use strict'

const {type} = require('message-type')
const canvasApi = require('../canvasApi')
const Promise = require('bluebird')
const cl = require('../azureStorage')
const config = require('../server/init/configuration')
require('colors')

const csvVol = config.secure.azure.csvBlobName
const msgVol = config.secure.azure.msgBlobName
const csvDir = config.secure.localFile.csvDir
const lmsDatabase = config.secure.azure.databaseName
const lmsCollection = config.secure.azure.collectionName

function _connectoToAzure () {
  return cl.cloudGetDatabase(lmsDatabase)
.then(() => cl.cloudGetCollection(lmsDatabase, lmsCollection))
.then(() => console.log('Connected to database: ' + lmsDatabase + ' , Collection: ' + lmsCollection + ' successfully:'))
.then(() => cl.cloudCreateContainer(csvVol))
.then(() => console.log('Created: ' + csvVol))
.then(() => cl.cloudCreateContainer(msgVol))
.then(() => console.log('Created: ' + msgVol))
.catch(error => Error(error))
}

_connectoToAzure()

function _handleError (err, sisCourseCode) {
  let eCode = err.statusCode
  if (eCode === 404) {
    console.warn('Course does not exist in canvas, skipping, '.red + sisCourseCode.red)
    return Promise.resolve('Course does not exist in canvas')
  }

  if (eCode >= 400) { // Besides course not in Canvas, Probably an other type of problem with canvas.....
    console.warn('Canvas is not accessable, Invalid token or other Canvas related errors..... '.red + sisCourseCode.red)
  } else { // It is an error and unrelated to the Canvas HTTP requests, probably IO errors
    console.warn('Other error..... '.red + sisCourseCode.red)
  }

  return Promise.reject(err)
}

function _createCsvFile (msg, sisCourseCode) {
  let d = Date.now()
  let header = 'course_id,user_id,role,status\n'
  let msgtype = msg._desc.userType
  let csvFileName = 'enrollments.' + msgtype + '.' + sisCourseCode + '.' + d + '.csv'
  let msgFileName = 'enrollments.' + msgtype + '.' + sisCourseCode + '.' + d + '.msg'
  let csvString = ''

  if (msg.member && msg.member.length > 0) {
    let csvArray = msg.member.map(user => {
      return {
        course_id: sisCourseCode,
        user_id: user,
        role: msgtype,
        status: 'active'
      }
    })
    csvArray.forEach(csvRow => {
      csvString = csvString + `${csvRow.course_id},${csvRow.user_id},${csvRow.role},${csvRow.status}
`
    })
  }

  let csvData = header + csvString
  console.info('\nGoing to open file: ' + csvFileName + ' ' + msgFileName)
  let messageText = JSON.stringify(msg, null, 4)
  return cl.cloudStoreTextToFile(csvFileName, csvVol, csvData)
  .then(result => { console.info(result); return cl.cloudStoreTextToFile(msgFileName, msgVol, messageText) })
  .then(() => cl.cloudgetFile(csvFileName, csvVol, csvDir))
  .then(result => { console.info(result); return {csvContent: csvData, csvFileName: csvDir + result.name} })
  .catch(error => { console.error(error); return Promise.reject(error) })
}

function _process (msg) {
  let course = null
  let termin = null
  let year = null
  let ladok = null
  let sisCourseCode = null
  let myRe = null
  let myArray = []
  let msgtype = msg._desc.userType

  if (msgtype === type.students) { // ladok2.kurser.DM.2517.registrerade_20162.1
    myRe = /^(\w+).(\w+).(\w+).(\w+).(\w+)_(\d\d)(\d\d)(\d).(\d+)/g
    myArray = myRe.exec(msg.ug1Name)
    if (myArray != null) {
      let courseInOne = 3
      let courseInTwo = 4
      let terminIn = 8
      let yearIn = 7
      let ladokIn = 9
      course = myArray[courseInOne] + myArray[courseInTwo]
      termin = myArray[terminIn] === 1 ? 'HT' : 'VT'
      year = myArray[yearIn]
      ladok = myArray[ladokIn]
      sisCourseCode = course + termin + year + ladok
    } else { // failed to parse course
      console.warn('\nCourse code not parsable from ug1Name structure: ' + msg.ug1Name)
      return Promise.resolve('Key parse error, Student')
    }
  }

  if (msgtype === type.teachers || msgtype === type.assistants) { // edu.courses.AE.AE2302.20162.1.teachers edu.courses.DD.DD1310.20162.1.assistants
    myRe = /^edu.courses.(\w+).(\w+).(\d\d)(\d\d)(\d).(\d).(\w+)$/g
    myArray = myRe.exec(msg.ug1Name)
    if (myArray != null) {
      let courseIn = 2
      let terminIn = 5
      let yearIn = 4
      let ladokIn = 6
      course = myArray[courseIn]
      termin = myArray[terminIn] === 1 ? 'HT' : 'VT'
      year = myArray[yearIn]
      ladok = myArray[ladokIn]
      sisCourseCode = course + termin + year + ladok
    } else { // failed to parse course
      console.warn('\nCourse code not parsable from ug1Name structure: ' + msg.ug1Name)
      return Promise.resolve('Key parse error, Teacher or Assistant')
    }
  }

  console.info(`In _process ${sisCourseCode}, processing for ${msgtype}`)

  // return canvasApi.findCourse(sisCourseCode)
  return Promise.resolve('gurka')
    .then(() => _createCsvFile(msg, sisCourseCode))
    .then(csvObject => {
      console.log('FileName: ', csvObject.csvFileName)
      return csvObject.csvFileName
    })
    .then(fileName => canvasApi.sendCsvFile(fileName))
    .then(canvasReturnValue => {
      let document = {id: sisCourseCode, msg: msg, resp: canvasReturnValue}
      let collectionUrl = `dbs/${lmsDatabase}/colls/${lmsCollection}`
      return cl.cloudCreateDocument(document, collectionUrl)
    })
    .catch(error => _handleError(error, sisCourseCode))
}

module.exports = function (msg) {
  console.info('\nProcessing for msg..... ' + msg.ug1Name)
  var msgtype = msg._desc.userType
  if (msg._desc && (msgtype === type.students || msgtype === type.teachers || msgtype === type.assistants)) {
    return _process(msg)
  } else {
    console.warn('\nThis is something else than students, teacher, assistant, we can probably wait with this until the students is handled', JSON.stringify(msg, null, 4))
    return Promise.resolve('Unknown flag: ' + msgtype)
  }
}
<commit_msg>removed debug mode<commit_after>'use strict'

const {type} = require('message-type')
const canvasApi = require('../canvasApi')
const Promise = require('bluebird')
const cl = require('../azureStorage')
const config = require('../server/init/configuration')
require('colors')

const csvVol = config.secure.azure.csvBlobName
const msgVol = config.secure.azure.msgBlobName
const csvDir = config.secure.localFile.csvDir
const lmsDatabase = config.secure.azure.databaseName
const lmsCollection = config.secure.azure.collectionName

function _connectoToAzure () {
  return cl.cloudGetDatabase(lmsDatabase)
.then(() => cl.cloudGetCollection(lmsDatabase, lmsCollection))
.then(() => console.log('Connected to database: ' + lmsDatabase + ' , Collection: ' + lmsCollection + ' successfully:'))
.then(() => cl.cloudCreateContainer(csvVol))
.then(() => console.log('Created: ' + csvVol))
.then(() => cl.cloudCreateContainer(msgVol))
.then(() => console.log('Created: ' + msgVol))
.catch(error => Error(error))
}

_connectoToAzure()

function _handleError (err, sisCourseCode) {
  let eCode = err.statusCode
  if (eCode === 404) {
    console.warn('Course does not exist in canvas, skipping, '.red + sisCourseCode.red)
    return Promise.resolve('Course does not exist in canvas')
  }

  if (eCode >= 400) { // Besides course not in Canvas, Probably an other type of problem with canvas.....
    console.warn('Canvas is not accessable, Invalid token or other Canvas related errors..... '.red + sisCourseCode.red)
  } else { // It is an error and unrelated to the Canvas HTTP requests, probably IO errors
    console.warn('Other error..... '.red + sisCourseCode.red)
  }

  return Promise.reject(err)
}

function _createCsvFile (msg, sisCourseCode) {
  let d = Date.now()
  let header = 'course_id,user_id,role,status\n'
  let msgtype = msg._desc.userType
  let csvFileName = 'enrollments.' + msgtype + '.' + sisCourseCode + '.' + d + '.csv'
  let msgFileName = 'enrollments.' + msgtype + '.' + sisCourseCode + '.' + d + '.msg'
  let csvString = ''

  if (msg.member && msg.member.length > 0) {
    let csvArray = msg.member.map(user => {
      return {
        course_id: sisCourseCode,
        user_id: user,
        role: msgtype,
        status: 'active'
      }
    })
    csvArray.forEach(csvRow => {
      csvString = csvString + `${csvRow.course_id},${csvRow.user_id},${csvRow.role},${csvRow.status}
`
    })
  }

  let csvData = header + csvString
  console.info('\nGoing to open file: ' + csvFileName + ' ' + msgFileName)
  let messageText = JSON.stringify(msg, null, 4)
  return cl.cloudStoreTextToFile(csvFileName, csvVol, csvData)
  .then(result => { console.info(result); return cl.cloudStoreTextToFile(msgFileName, msgVol, messageText) })
  .then(() => cl.cloudgetFile(csvFileName, csvVol, csvDir))
  .then(result => { console.info(result); return {csvContent: csvData, csvFileName: csvDir + result.name} })
  .catch(error => { console.error(error); return Promise.reject(error) })
}

function _process (msg) {
  let course = null
  let termin = null
  let year = null
  let ladok = null
  let sisCourseCode = null
  let myRe = null
  let myArray = []
  let msgtype = msg._desc.userType

  if (msgtype === type.students) { // ladok2.kurser.DM.2517.registrerade_20162.1
    myRe = /^(\w+).(\w+).(\w+).(\w+).(\w+)_(\d\d)(\d\d)(\d).(\d+)/g
    myArray = myRe.exec(msg.ug1Name)
    if (myArray != null) {
      let courseInOne = 3
      let courseInTwo = 4
      let terminIn = 8
      let yearIn = 7
      let ladokIn = 9
      course = myArray[courseInOne] + myArray[courseInTwo]
      termin = myArray[terminIn] === 1 ? 'HT' : 'VT'
      year = myArray[yearIn]
      ladok = myArray[ladokIn]
      sisCourseCode = course + termin + year + ladok
    } else { // failed to parse course
      console.warn('\nCourse code not parsable from ug1Name structure: ' + msg.ug1Name)
      return Promise.resolve('Key parse error, Student')
    }
  }

  if (msgtype === type.teachers || msgtype === type.assistants) { // edu.courses.AE.AE2302.20162.1.teachers edu.courses.DD.DD1310.20162.1.assistants
    myRe = /^edu.courses.(\w+).(\w+).(\d\d)(\d\d)(\d).(\d).(\w+)$/g
    myArray = myRe.exec(msg.ug1Name)
    if (myArray != null) {
      let courseIn = 2
      let terminIn = 5
      let yearIn = 4
      let ladokIn = 6
      course = myArray[courseIn]
      termin = myArray[terminIn] === 1 ? 'HT' : 'VT'
      year = myArray[yearIn]
      ladok = myArray[ladokIn]
      sisCourseCode = course + termin + year + ladok
    } else { // failed to parse course
      console.warn('\nCourse code not parsable from ug1Name structure: ' + msg.ug1Name)
      return Promise.resolve('Key parse error, Teacher or Assistant')
    }
  }

  console.info(`In _process ${sisCourseCode}, processing for ${msgtype}`)

  return canvasApi.findCourse(sisCourseCode)
    .then(() => _createCsvFile(msg, sisCourseCode))
    .then(csvObject => {
      console.log('FileName: ', csvObject.csvFileName)
      return csvObject.csvFileName
    })
    .then(fileName => canvasApi.sendCsvFile(fileName))
    .then(canvasReturnValue => {
      let document = {id: sisCourseCode, msg: msg, resp: canvasReturnValue}
      let collectionUrl = `dbs/${lmsDatabase}/colls/${lmsCollection}`
      return cl.cloudCreateDocument(document, collectionUrl)
    })
    .catch(error => _handleError(error, sisCourseCode))
}

module.exports = function (msg) {
  console.info('\nProcessing for msg..... ' + msg.ug1Name)
  var msgtype = msg._desc.userType
  if (msg._desc && (msgtype === type.students || msgtype === type.teachers || msgtype === type.assistants)) {
    return _process(msg)
  } else {
    console.warn('\nThis is something else than students, teacher, assistant, we can probably wait with this until the students is handled', JSON.stringify(msg, null, 4))
    return Promise.resolve('Unknown flag: ' + msgtype)
  }
}
<|endoftext|>


<commit_before>$(window).on("load", function() {
    nodecg.sendMessage("loaded", "champ-select");
    var $teamInfo = {
        "blue": {"name": $("#blue-team-name"), "score": $("#blue-team-score"), "form": $("#blue-team-form")},
        "red": {"name": $("#red-team-name"), "score": $("#red-team-score"), "form": $("#red-team-form")}
    };
    var $teamRoster = {
        "blue": {
            "top": $("#blue-team-top"),
            "jungle": $("#blue-team-jungle"),
            "mid": $("#blue-team-mid"),
            "adc": $("#blue-team-adc"),
            "support": $("#blue-team-support")
        },
        "red": {
            "top": $("#red-team-top"),
            "jungle": $("#red-team-jungle"),
            "mid": $("#red-team-mid"),
            "adc": $("#red-team-adc"),
            "support": $("#red-team-support")
        }
    };
    var $teamBans = {
        "blue": {"ban1": $("#blue-team-ban1"), "ban2": $("#blue-team-ban2"), "ban3": $("#blue-team-ban3")},
        "red": {"ban1": $("#red-team-ban1"), "ban2": $("#red-team-ban2"), "ban3": $("#red-team-ban3")}
    };

    /** REPLICANTS **/
    var casters = nodecg.Replicant("casters")
        .on("change", function(oldVal, newVal) {
            var string = "SHOUTCASTERS: " + newVal[0];
            if (newVal[1] != "") {
                string += (" & " + newVal[1])
            }
            $("#casters").text(string);
        });

    var updateTeam = function() {
        if (!comingUpReplicant.value) { // If the coming up replicant hasn't loaded yet, return.
            return
        }
        $.each(teamReplicant.value[comingUpReplicant.value["next_game"]], function(team, value) { // For each team...
            $.each(value["info"], function (key, value) { // For each of the team info...
                if (["tag", "position"].indexOf(key) !== -1) { // If value isn't used in this scene...
                    return
                }
                if (value != $teamInfo[team][key].text()) { // If value has changed...
                    var changeTeamInfo = new TimelineLite(); // Animate the changing of the value.
                    changeTeamInfo
                        .to($teamInfo[team][key], 0.5, { // Fade out.
                            opacity: 0.0
                        })
                        .call(function() { // Update text.
                            $teamInfo[team][key].text(value);
                        })
                        .to($teamInfo[team][key], 0.5, { // Fade in.
                            opacity: 1.0
                        });
                }
            });
            $.each(value["roster"], function(position, value) { // For each player name...
                if (value != $teamRoster[team][position].text()) { // If value has changed...
                    var changeTeamRoster = new TimelineLite(); // Animate the changing of the value.
                    changeTeamRoster
                        .to($teamRoster[team][position], 0.5, { // Fade in.
                            opacity: 0.0
                        })
                        .call(function() { // Update text.
                            $teamRoster[team][position].text(value);
                        })
                        .to($teamRoster[team][position], 0.5, { // Fade in.
                            opacity: 1.0
                        });
                }
            });
        });
    };
    var teamReplicant = nodecg.Replicant("team-data")
        .on("change", function(oldVal, newVal) { // On change...
            updateTeam()
        });
    var comingUpReplicant = nodecg.Replicant("coming-up")
        .on("change", function(oldVal, newVal) { // On change...
            updateTeam()
        });

    var champsReplicant = nodecg.Replicant("champ-select")
        .on("change", function(oldVal, newVal) { // If the champs variable changes...
            $.each(newVal, function(team, value) {
                $.each(value["bans"], function(key, value) {
                    if (value["name"] != $teamBans[team][key].text()) {
                        var changeBan = new TimelineLite();
                        changeBan
                            .to($teamBans[team][key], 0.5, { // Fade out.
                                opacity: 0.0
                            })
                            .call(function() { // Update text.
                                $teamBans[team][key].text(value["name"]);
                            })
                            .to($teamBans[team][key], 0.5, { // Fade in.
                                opacity: 1.0
                            });
                    }
                });
            });
        });

    /** BOTTOM CHAMP INFO **/
    var $champInfo = $("#champ-info");

    nodecg.listenFor("champ-picked", function(value) {
        $champInfo.queue(function(next) {
            var changeStats = new TimelineLite();
            changeStats
                .to($champInfo, 0.5, {
                    opacity: 0.0
                })
                .call(function() {
                    $("#champ-info-data").text(value["info"]["pickrate"] + "\n" + value["info"]["banrate"] + "\n" + value["info"]["winrate"]);
                })
                .to($champInfo, 0.5, {
                    opacity: 1.0
                });
            setTimeout(function() {
                next();
            }, 15000);
        });
    });
	nodecg.listenFor("champ-picked-clear", function() {
		$champInfo.clearQueue().css("opacity", 0.0);
	});

    /** POLL **/

    var $poll = $("#poll");
    var $pollBar = {"blue": $("#poll-bar-blue"), "red": $("#poll-bar-red")};
    var $pollValues = {"blue": $("#poll-blue-percent"), "red": $("#poll-red-percent")};
	var currTotal = 0;

    var strawpollReplicant = nodecg.Replicant("strawpoll")
        .on("change", function(oldVal, newVal) {
            if (isNaN(newVal[0])) {
                console.log(newVal)
            } // If undefined, return as we don't need to do anything - default is 0% 0%.
            else {
                var total = newVal[0] + newVal[1];
				if (currTotal == total) { return } // Dont do math if it's the same.
                if (total == 0) {
                    total = 1
                } // Set total to 1 if it's 0 so we don't get divide by zero errors.
                var percentage = [Math.round((newVal[0] / total) * 100), Math.round((newVal[1] / total) * 100)];
                $pollBar["blue"].animate({width: percentage[0] + "%"});
                $pollBar["red"].animate({width: percentage[1] + "%"});
                $pollValues["blue"].text(percentage[0] + "%");
                $pollValues["red"].text(percentage[1] + "%");
            }
        });

    nodecg.listenFor("strawpoll-start", function(data) {
		nodecg.sendMessage("champ-picked-clear");
        $("#poll-url").text("strawpoll.me/" + data);
        $poll.animate({opacity: 1.0}, 500);
    });

    nodecg.listenFor("strawpoll-stop", function() {
        $poll.animate({opacity: 0.0}, 500)
    });
});
<commit_msg>Fix bug causing old result to show on poll.<commit_after>$(window).on("load", function() {
    nodecg.sendMessage("loaded", "champ-select");
    var $teamInfo = {
        "blue": {"name": $("#blue-team-name"), "score": $("#blue-team-score"), "form": $("#blue-team-form")},
        "red": {"name": $("#red-team-name"), "score": $("#red-team-score"), "form": $("#red-team-form")}
    };
    var $teamRoster = {
        "blue": {
            "top": $("#blue-team-top"),
            "jungle": $("#blue-team-jungle"),
            "mid": $("#blue-team-mid"),
            "adc": $("#blue-team-adc"),
            "support": $("#blue-team-support")
        },
        "red": {
            "top": $("#red-team-top"),
            "jungle": $("#red-team-jungle"),
            "mid": $("#red-team-mid"),
            "adc": $("#red-team-adc"),
            "support": $("#red-team-support")
        }
    };
    var $teamBans = {
        "blue": {"ban1": $("#blue-team-ban1"), "ban2": $("#blue-team-ban2"), "ban3": $("#blue-team-ban3")},
        "red": {"ban1": $("#red-team-ban1"), "ban2": $("#red-team-ban2"), "ban3": $("#red-team-ban3")}
    };

    /** REPLICANTS **/
    var casters = nodecg.Replicant("casters")
        .on("change", function(oldVal, newVal) {
            var string = "SHOUTCASTERS: " + newVal[0];
            if (newVal[1] != "") {
                string += (" & " + newVal[1])
            }
            $("#casters").text(string);
        });

    var updateTeam = function() {
        if (!comingUpReplicant.value) { // If the coming up replicant hasn't loaded yet, return.
            return
        }
        $.each(teamReplicant.value[comingUpReplicant.value["next_game"]], function(team, value) { // For each team...
            $.each(value["info"], function (key, value) { // For each of the team info...
                if (["tag", "position"].indexOf(key) !== -1) { // If value isn't used in this scene...
                    return
                }
                if (value != $teamInfo[team][key].text()) { // If value has changed...
                    var changeTeamInfo = new TimelineLite(); // Animate the changing of the value.
                    changeTeamInfo
                        .to($teamInfo[team][key], 0.5, { // Fade out.
                            opacity: 0.0
                        })
                        .call(function() { // Update text.
                            $teamInfo[team][key].text(value);
                        })
                        .to($teamInfo[team][key], 0.5, { // Fade in.
                            opacity: 1.0
                        });
                }
            });
            $.each(value["roster"], function(position, value) { // For each player name...
                if (value != $teamRoster[team][position].text()) { // If value has changed...
                    var changeTeamRoster = new TimelineLite(); // Animate the changing of the value.
                    changeTeamRoster
                        .to($teamRoster[team][position], 0.5, { // Fade in.
                            opacity: 0.0
                        })
                        .call(function() { // Update text.
                            $teamRoster[team][position].text(value);
                        })
                        .to($teamRoster[team][position], 0.5, { // Fade in.
                            opacity: 1.0
                        });
                }
            });
        });
    };
    var teamReplicant = nodecg.Replicant("team-data")
        .on("change", function(oldVal, newVal) { // On change...
            updateTeam()
        });
    var comingUpReplicant = nodecg.Replicant("coming-up")
        .on("change", function(oldVal, newVal) { // On change...
            updateTeam()
        });

    var champsReplicant = nodecg.Replicant("champ-select")
        .on("change", function(oldVal, newVal) { // If the champs variable changes...
            $.each(newVal, function(team, value) {
                $.each(value["bans"], function(key, value) {
                    if (value["name"] != $teamBans[team][key].text()) {
                        var changeBan = new TimelineLite();
                        changeBan
                            .to($teamBans[team][key], 0.5, { // Fade out.
                                opacity: 0.0
                            })
                            .call(function() { // Update text.
                                $teamBans[team][key].text(value["name"]);
                            })
                            .to($teamBans[team][key], 0.5, { // Fade in.
                                opacity: 1.0
                            });
                    }
                });
            });
        });

    /** BOTTOM CHAMP INFO **/
    var $champInfo = $("#champ-info");

    nodecg.listenFor("champ-picked", function(value) {
        $champInfo.queue(function(next) {
            var changeStats = new TimelineLite();
            changeStats
                .to($champInfo, 0.5, {
                    opacity: 0.0
                })
                .call(function() {
                    $("#champ-info-data").text(value["info"]["pickrate"] + "\n" + value["info"]["banrate"] + "\n" + value["info"]["winrate"]);
                })
                .to($champInfo, 0.5, {
                    opacity: 1.0
                });
            setTimeout(function() {
                next();
            }, 15000);
        });
    });
	nodecg.listenFor("champ-picked-clear", function() {
		$champInfo.clearQueue().css("opacity", 0.0);
	});

    /** POLL **/

    var $poll = $("#poll");
    var $pollBar = {"blue": $("#poll-bar-blue"), "red": $("#poll-bar-red")};
    var $pollValues = {"blue": $("#poll-blue-percent"), "red": $("#poll-red-percent")};
	var currTotal = 0;

    var strawpollReplicant = nodecg.Replicant("strawpoll")
        .on("change", function(oldVal, newVal) {
            if (isNaN(newVal[0])) {
                console.log(newVal)
            } // If undefined, return as we don't need to do anything - default is 0% 0%.
            else {
                var total = newVal[0] + newVal[1];
				if (currTotal == total) { return } // Dont do math if it's the same.
                if (total == 0) {
                    total = 1
                } // Set total to 1 if it's 0 so we don't get divide by zero errors.
                var percentage = [Math.round((newVal[0] / total) * 100), Math.round((newVal[1] / total) * 100)];
                $pollBar["blue"].animate({width: percentage[0] + "%"});
                $pollBar["red"].animate({width: percentage[1] + "%"});
                $pollValues["blue"].text(percentage[0] + "%");
                $pollValues["red"].text(percentage[1] + "%");
            }
        });

    nodecg.listenFor("strawpoll-start", function(data) {
		currTotal = 0;
		nodecg.sendMessage("champ-picked-clear");
        $("#poll-url").text("strawpoll.me/" + data);
        $poll.animate({opacity: 1.0}, 500);
    });

    nodecg.listenFor("strawpoll-stop", function() {
        $poll.animate({opacity: 0.0}, 500)
    });
});
<|endoftext|>


<commit_before>"use strict";
$(document).ready(function() {
    $('#fullpage').fullpage();
});
<commit_msg>Ajout du menu de navigation<commit_after>"use strict";
$(document).ready(function() {
    $('#fullpage').fullpage({
    	navigation : true
    });
});
<|endoftext|>


<commit_before>const revealEl = document.createElement('DIV');
const classes = [
  'etc-details__cell-concealer',
  'etc-details__cell-revealer'
];
const html = [
  'Read More<button class="etc-details__cell-concealer-button">+</button>',
  'Read Less<button class="etc-details__cell-concealer-button">-</button>'
];

function clickFunction (e) {
  const hiddenClass = 'etc-details__cell-free-content--hidden';
  const textEl = e.target.parentElement.querySelector('.etc-details__cell-free-content');
  const textElConcealed = textEl.classList.contains(hiddenClass);

  e.target.innerHTML = html[textElConcealed ? 1 : 0];
  e.target.className = classes[textElConcealed ? 1 : 0];

  if (textElConcealed) {
    textEl.classList.remove(hiddenClass);
  } else {
    textEl.classList.add(hiddenClass);
  }
}

function initRevealer () {
  revealEl.className = classes[0];
  revealEl.innerHTML = html[0];

  Array.from(document.querySelectorAll('.etc-details__cell-free')).forEach((e) => {
    if (e.offsetHeight > 200) {
      const content = e.querySelector('.etc-details__cell-free-content');
      content.classList.add('etc-details__cell-free-content--hidden');
      const clone = revealEl.cloneNode(true);
      clone.onclick = clickFunction;
      e.appendChild(clone);
    }
  });
}

initRevealer();
<commit_msg>tracking for read more and read less<commit_after>const revealEl = document.createElement('DIV');
const classes = [
  'etc-details__cell-concealer',
  'etc-details__cell-revealer'
];
const html = [
  'Read More<button class="etc-details__cell-concealer-button">+</button>',
  'Read Less<button class="etc-details__cell-concealer-button">-</button>'
];

function clickFunction (e) {
  const hiddenClass = 'etc-details__cell-free-content--hidden';
  const textEl = e.target.parentElement.querySelector('.etc-details__cell-free-content');
  const textElConcealed = textEl.classList.contains(hiddenClass);

  e.target.innerHTML = html[textElConcealed ? 1 : 0];
  e.target.className = classes[textElConcealed ? 1 : 0];

  if (textElConcealed) {
    textEl.classList.remove(hiddenClass);
    e.target.setAttribute('data-tracking-collections', 'read less');
  } else {
    textEl.classList.add(hiddenClass);
    e.target.setAttribute('data-tracking-collections', 'read more');
  }
}

function initRevealer () {
  revealEl.className = classes[0];
  revealEl.innerHTML = html[0];
  revealEl.setAttribute('data-tracking-collections', 'read more');

  Array.from(document.querySelectorAll('.etc-details__cell-free')).forEach((e) => {
    if (e.offsetHeight > 200) {
      const content = e.querySelector('.etc-details__cell-free-content');
      content.classList.add('etc-details__cell-free-content--hidden');
      const clone = revealEl.cloneNode(true);
      clone.onclick = clickFunction;
      e.appendChild(clone);
    }
  });
}

initRevealer();
<|endoftext|>


<commit_before>var request = require('request');
var cheerio = require('cheerio');

var url = process.argv[2];

exports.query = function(url, errorHandler, okHandler) {
    request.get(url, function(err, resp, body) {
        if (err) {
            errorHandler(err);
            return;
        }

        if (resp.statusCode == 200) {
            $ = cheerio.load(body);

            $('head').remove();
            $('script').remove();
            $('textarea').remove();
            $('select').remove();
            $('input').remove();
            $('font').remove();
            $('style').remove();
            $('center').remove();
            $('form').remove();

            var elements = $('*');
            elements.removeAttr('class');
            elements.removeAttr('style');
            elements.removeAttr('bgcolor');

            var simple = makeSimple($('body')[0]);

            // var tagfreq = {};
            // for (var i = 0; i < elements.length; i++) {
            //     var elem = elements[i];
            //     if (!tagfreq[elem.name])
            //         tagfreq[elem.name] = 1;
            //     else
            //         tagfreq[elem.name]++;
            //     }

            //console.log(tagfreq);
            console.log(elements);
            //okHandler(elements.html());
            okHandler(JSON.stringify(simple, null, " "));
            }
        });
    }

var makeSimple = function(elem) {
    var simple = { }

    if (elem.type == "tag") {
        simple.tag = elem.name;
        if (notEmpty(elem.attribs)) simple.attribs = elem.attribs;
        var kids = simplifyKids(elem.children);
        if (kids && kids.length) {
            if (kids.length == 1 && kids[0].text) {
                simple.text = kids[0].text;
            }
            else {
                simple.children = kids;
            }
        }
    }
    else if (elem.type == "text") {
        var trimmed = elem.data.trim();
        if (trimmed) simple.text = trimmed;
    }
    // else {
    //     simple.unkown = elem;
    // }

    return simple;
}

var simplifyKids = function(kids) {
    var simpleKids = [];
    if (kids) {
        kids.forEach(function(kid) {
            if (kid) {
                var simpleKid = makeSimple(kid);
                if (notEmpty(simpleKid)) simpleKids.push(simpleKid);
            }
        });
    }
    return simpleKids;
}

var notEmpty = function(obj) {
    return Object.keys(obj).length > 0
}

<commit_msg>trim json<commit_after>var request = require('request');
var cheerio = require('cheerio');

var url = process.argv[2];

exports.query = function(url, errorHandler, okHandler) {
    request.get(url, function(err, resp, body) {
        if (err) {
            errorHandler(err);
            return;
        }

        if (resp.statusCode == 200) {
            $ = cheerio.load(body);

            $('head').remove();
            $('script').remove();
            $('textarea').remove();
            $('select').remove();
            $('input').remove();
            $('font').remove();
            $('style').remove();
            $('center').remove();
            $('form').remove();

            var elements = $('*');
            elements.removeAttr('class');
            elements.removeAttr('style');
            elements.removeAttr('bgcolor');

            var simple = makeSimple($('body')[0]);

            // var tagfreq = {};
            // for (var i = 0; i < elements.length; i++) {
            //     var elem = elements[i];
            //     if (!tagfreq[elem.name])
            //         tagfreq[elem.name] = 1;
            //     else
            //         tagfreq[elem.name]++;
            //     }

            //console.log(tagfreq);
            //console.log(elements);
            //okHandler(elements.html());
            okHandler(JSON.stringify(simple, null, " "));
            }
        });
    }

var makeSimple = function(elem) {
    var simple = { }

    if (elem.type == "tag") {

        if (notEmpty(elem.attribs)) simple[elem.name] = elem.attribs;
        else simple[elem.name] = {};

        var kids = simplifyKids(elem.children);
        if (kids && kids.length) {
            if (kids.length == 1 && kids[0].text) {
                simple[elem.name].text = kids[0].text;
            }
            else {
                simple[elem.name].children = kids;
            }
        }
    }
    else if (elem.type == "text") {
        var trimmed = elem.data.trim();
        if (trimmed) simple.text = trimmed;
    }
    else if (elem.type == "comment") {
        var trimmed = elem.data.trim();
        if (trimmed) simple.comment = trimmed;
    }
    else {
        var unkown = {}
        unkown[elem.type] = elem;
        console.log(unkown);
    }

    return simple;
}

var simplifyKids = function(kids) {
    var simpleKids = [];
    if (kids) {
        kids.forEach(function(kid) {
            if (kid) {
                var simpleKid = makeSimple(kid);
                if (notEmpty(simpleKid)) simpleKids.push(simpleKid);
            }
        });
    }
    return simpleKids;
}

var notEmpty = function(obj) {
    return Object.keys(obj).length > 0
}

<|endoftext|>


<commit_before>/*    Copyright 2020 Firewalla Inc
 *
 *    This program is free software: you can redistribute it and/or  modify
 *    it under the terms of the GNU Affero General Public License, version 3,
 *    as published by the Free Software Foundation.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU Affero General Public License for more details.
 *
 *    You should have received a copy of the GNU Affero General Public License
 *    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
'use strict';

const log = require("../net2/logger.js")(__filename);
const rclient = require('../util/redis_manager.js').getRedisClient();
const sem = require('../sensor/SensorEventManager.js').getInstance();
const Block = require('./Block.js');
const DNSTool = require('../net2/DNSTool.js')
const dnsTool = new DNSTool()
const IntelTool = require('../net2/IntelTool');
const intelTool = new IntelTool();
const _ = require('lodash');
const fc = require('../net2/config.js');
const featureName = 'smart_block';
let instance = null

class BlockManager {
    constructor() {
        if (instance == null) {
            instance = this;
            const refreshInterval = 15 * 60; // 15 mins
            sem.once('IPTABLES_READY', async () => {
                if (fc.isFeatureOn(featureName)) {
                    this.scheduleId = setInterval(() => {
                        this.scheduleRefreshBlockLevel();
                    }, refreshInterval * 1000)
                }
                fc.onFeature(featureName, async (feature, status) => {
                    if (feature !== featureName) {
                        return
                    }
                    await this.reenforcePolicies();
                    if (status) {
                        this.scheduleId = setInterval(() => {
                            this.scheduleRefreshBlockLevel();
                        }, refreshInterval * 1000)
                    } else {
                        clearInterval(this.scheduleId);
                    }
                })
            })
        }
        return instance
    }
    async reenforcePolicies() {
        const PolicyManager2 = require('../alarm/PolicyManager2.js');
        const pm2 = new PolicyManager2();
        log.info('smart block enabled, re-enforce policies');
        const policies = await pm2.loadActivePoliciesAsync();
        policies.map((policy) => {
            pm2.tryPolicyEnforcement(policy, 'reenforce', policy);
        })
    }
    ipBlockInfoKey(ip) {
        return `ip:block:info:${ip}`
    }
    domainBlockInfoKey(domain) {
        return `domain:block:info:${domain}`
    }
    categoryDomainBlockInfoKey(domain) {
        return `category:block:info:${domain}`
    }
    getCategoryIpMapping(category) {
        return `rdns:category:${category}`
    }
    async getPureCategoryIps(category, categoryIps, domain) {
        if (!fc.isFeatureOn(featureName)) {
            return categoryIps;
        }
        const pureCategoryIps = [], mixupCategoryIps = [], mixupIpInfos = [];
        try {
            const now = new Date();
            for (const categoryIp of categoryIps) {
                let pure = true;
                let mixupDomain;
                let mixupCategory;
                const domains = await dnsTool.getAllDns(categoryIp);
                for (const domain of domains) {
                    mixupDomain = domain;
                    const ips = await dnsTool.getIPsByDomain(domain);
                    for (const ip of ips) {
                        const intel = (await intelTool.getIntel(ip)) || {};
                        mixupCategory = intel.category;
                        pure = pure && intel.category == category;
                        if (!pure) break;
                    }
                    if (!pure) break;
                }
                if (pure) {
                    pureCategoryIps.push(categoryIp)
                } else {
                    mixupCategoryIps.push(categoryIp);
                    mixupIpInfos.push({
                        ip: categoryIp,
                        mixupDomain: mixupDomain,
                        mixupCategory: mixupCategory
                    })
                }
            }
            const categoryIpMappingKey = this.getCategoryIpMapping(category);
            mixupCategoryIps.length > 0 && await rclient.sremAsync(categoryIpMappingKey, mixupCategoryIps);
            pureCategoryIps.length > 0 && await rclient.saddAsync(categoryIpMappingKey, pureCategoryIps);
            await rclient.setAsync(this.categoryDomainBlockInfoKey(domain), JSON.stringify({
                pureCategoryIps: pureCategoryIps,
                mixupIpInfos: mixupIpInfos
            }))
        } catch (e) {
            log.info("get pure category ips failed", e)
        }
        return pureCategoryIps;
    }
    async applyNewDomain(ip, domain) {
        await this.updateIpBlockInfo(ip, domain, 'newDomain')
    }
    async scheduleRefreshBlockLevel() {
        const ipBlockKeys = await rclient.keysAsync("ip:block:info:*");
        log.info('schedule refresh block level for these ips:', ipBlockKeys)
        ipBlockKeys.map(async (key) => {
            let ipBlockInfo = JSON.parse(await rclient.getAsync(key));
            const { targetDomains, ip, blockLevel, blockSet } = ipBlockInfo;
            const allDomains = await dnsTool.getAllDns(ip);
            const sharedDomains = _.differenceWith(allDomains, targetDomains, (a, b) => {
                return this.domainCovered(b, a);
            });
            if (sharedDomains.length == 0 && blockLevel == 'domain') {
                Block.block(ip, blockSet)
            }
            if (sharedDomains.length > 0 && blockLevel == 'ip') {
                Block.unblock(ip, blockSet);
            }
            ipBlockInfo.ts = new Date() / 1000;
            ipBlockInfo.sharedDomains = sharedDomains;
            ipBlockInfo.allDomains = allDomains;
            await rclient.setAsync(key, JSON.stringify(ipBlockInfo));
        })
    }
    async updateIpBlockInfo(ip, domain, action, blockSet = 'block_domain_set') {
        let ipBlockInfo = {
            blockSet: blockSet,
            ip: ip,
            targetDomains: [],
            sharedDomains: [],
            allDomains: [],
            ts: new Date() / 1000
        }
        if (!fc.isFeatureOn(featureName)) {
            ipBlockInfo.blockLevel = 'ip';
        } else {
            const key = this.ipBlockInfoKey(ip);
            const exist = (await rclient.existsAsync(key) == 1);
            if (exist) {
                ipBlockInfo = JSON.parse(await rclient.getAsync(key));
            }
            switch (action) {
                case 'block': {
                    // if the ip shared with other domain, should not apply ip level block
                    // if a.com and b.com share ip and one of them block, it should be domain level
                    // if both block, should update to ip level
                    !ipBlockInfo.targetDomains.includes(domain) && ipBlockInfo.targetDomains.push(domain);
                    const allDomains = await dnsTool.getAllDns(ip);
                    const sharedDomains = _.differenceWith(allDomains, ipBlockInfo.targetDomains, (a, b) => {
                        return this.domainCovered(b, a);
                    });
                    sharedDomains.length > 0 && log.info(`${ipBlockInfo.targetDomains.join(',')} ip ${ip} shared with domains ${sharedDomains.join(',')}`)
                    if (sharedDomains.length == 0) {
                        ipBlockInfo.blockLevel = 'ip';
                    } else {
                        ipBlockInfo.blockLevel = 'domain';
                    }
                    ipBlockInfo.sharedDomains = sharedDomains;
                    ipBlockInfo.allDomains = allDomains;
                    ipBlockInfo.ts = new Date() / 1000;
                    await rclient.setAsync(key, JSON.stringify(ipBlockInfo));
                    break;
                }
                case 'unblock': {
                    !ipBlockInfo.sharedDomains.includes(domain) && ipBlockInfo.sharedDomains.push(domain);
                    ipBlockInfo.targetDomains = _.filter(ipBlockInfo.targetDomains, (a) => {
                        return a != domain;
                    })
                    if (ipBlockInfo.targetDomains.length == 0) {
                        await rclient.delAsync(key);
                    } else {
                        ipBlockInfo.ts = new Date() / 1000;
                        ipBlockInfo.blockLevel = 'domain';
                        await rclient.setAsync(key, JSON.stringify(ipBlockInfo));
                    }
                    break;
                }
                case 'newDomain': {
                    if (exist) {
                        // it is old ip and new domain
                        const { blockSet, targetDomains } = ipBlockInfo;
                        const alreayExistInTargetDomains = _.find(targetDomains, (targetDomain) => {
                            return this.domainCovered(targetDomain, domain);
                        })
                        if (!alreayExistInTargetDomains) {
                            if (ipBlockInfo.blockLevel == 'ip') {
                                log.info('ip block level change when new doamin comming', ip, domain)
                                ipBlockInfo.blockLevel = 'domain';
                                Block.unblock(ip, blockSet);
                            }
                            ipBlockInfo.sharedDomains.push(domain);
                            ipBlockInfo.allDomains = await dnsTool.getAllDns(ip);
                            ipBlockInfo.ts = new Date() / 1000;
                            await rclient.setAsync(key, JSON.stringify(ipBlockInfo));
                        }
                    }
                    break;
                }
            }
        }
        await this.updateDomainBlockInfo(domain, ipBlockInfo);
        return ipBlockInfo;
    }
    async updateDomainBlockInfo(domain, ipBlockInfo) {
        const key = this.domainBlockInfoKey(domain);
        let domainBlockInfo = await rclient.getAsync(key);
        try {
            domainBlockInfo = JSON.parse(domainBlockInfo);
        } catch (err) {
            domainBlockInfo = {};
        }
        domainBlockInfo[ipBlockInfo.ip] = ipBlockInfo;
        await rclient.setAsync(key, domainBlockInfo);
    }
    domainCovered(blockDomain, otherDomain) {
        // a.b.com covred x.a.b.com
        if (!otherDomain) return true;
        if (blockDomain.startsWith('*.')) blockDomain = blockDomain.substring(2)
        if (otherDomain.startsWith('*.')) otherDomain = otherDomain.substring(2)
        const h1Sections = blockDomain.split('.').reverse();
        const h2Sections = otherDomain.split('.').reverse();
        for (let i = 0; i < h1Sections.length; i++) {
            if (h1Sections[i] !== h2Sections[i])
                return false;
        }
        return true;
    }
}

module.exports = BlockManager
<commit_msg>update<commit_after>/*    Copyright 2020 Firewalla Inc
 *
 *    This program is free software: you can redistribute it and/or  modify
 *    it under the terms of the GNU Affero General Public License, version 3,
 *    as published by the Free Software Foundation.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU Affero General Public License for more details.
 *
 *    You should have received a copy of the GNU Affero General Public License
 *    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
'use strict';

const log = require("../net2/logger.js")(__filename);
const rclient = require('../util/redis_manager.js').getRedisClient();
const sem = require('../sensor/SensorEventManager.js').getInstance();
const Block = require('./Block.js');
const DNSTool = require('../net2/DNSTool.js')
const dnsTool = new DNSTool()
const IntelTool = require('../net2/IntelTool');
const intelTool = new IntelTool();
const _ = require('lodash');
const fc = require('../net2/config.js');
const featureName = 'smart_block';
let instance = null

class BlockManager {
    constructor() {
        if (instance == null) {
            instance = this;
            const refreshInterval = 15 * 60; // 15 mins
            sem.once('IPTABLES_READY', async () => {
                if (fc.isFeatureOn(featureName)) {
                    this.scheduleId = setInterval(() => {
                        this.scheduleRefreshBlockLevel();
                    }, refreshInterval * 1000)
                }
                fc.onFeature(featureName, async (feature, status) => {
                    if (feature !== featureName) {
                        return
                    }
                    await this.reenforcePolicies();
                    if (status) {
                        this.scheduleId = setInterval(() => {
                            this.scheduleRefreshBlockLevel();
                        }, refreshInterval * 1000)
                    } else {
                        clearInterval(this.scheduleId);
                    }
                })
            })
        }
        return instance
    }
    async reenforcePolicies() {
        const PolicyManager2 = require('../alarm/PolicyManager2.js');
        const pm2 = new PolicyManager2();
        log.info('smart block enabled, re-enforce policies');
        const policies = await pm2.loadActivePoliciesAsync();
        policies.map((policy) => {
            pm2.tryPolicyEnforcement(policy, 'reenforce', policy);
        })
    }
    ipBlockInfoKey(ip) {
        return `ip:block:info:${ip}`
    }
    domainBlockInfoKey(domain) {
        return `domain:block:info:${domain}`
    }
    categoryDomainBlockInfoKey(domain) {
        return `category:block:info:${domain}`
    }
    getCategoryIpMapping(category) {
        return `rdns:category:${category}`
    }
    async getPureCategoryIps(category, categoryIps, domain) {
        if (!fc.isFeatureOn(featureName)) {
            return categoryIps;
        }
        const pureCategoryIps = [], mixupCategoryIps = [], mixupIpInfos = [];
        try {
            const now = new Date();
            for (const categoryIp of categoryIps) {
                let pure = true;
                let mixupDomain;
                let mixupCategory;
                const domains = await dnsTool.getAllDns(categoryIp);
                for (const domain of domains) {
                    mixupDomain = domain;
                    const ips = await dnsTool.getIPsByDomain(domain);
                    for (const ip of ips) {
                        const intel = (await intelTool.getIntel(ip)) || {};
                        mixupCategory = intel.category;
                        pure = pure && intel.category == category;
                        if (!pure) break;
                    }
                    if (!pure) break;
                }
                if (pure) {
                    pureCategoryIps.push(categoryIp)
                } else {
                    mixupCategoryIps.push(categoryIp);
                    mixupIpInfos.push({
                        ip: categoryIp,
                        mixupDomain: mixupDomain,
                        mixupCategory: mixupCategory
                    })
                }
            }
            const categoryIpMappingKey = this.getCategoryIpMapping(category);
            mixupCategoryIps.length > 0 && await rclient.sremAsync(categoryIpMappingKey, mixupCategoryIps);
            pureCategoryIps.length > 0 && await rclient.saddAsync(categoryIpMappingKey, pureCategoryIps);
            await rclient.setAsync(this.categoryDomainBlockInfoKey(domain), JSON.stringify({
                pureCategoryIps: pureCategoryIps,
                mixupIpInfos: mixupIpInfos
            }))
        } catch (e) {
            log.info("get pure category ips failed", e)
        }
        return pureCategoryIps;
    }
    async applyNewDomain(ip, domain) {
        await this.updateIpBlockInfo(ip, domain, 'newDomain')
    }
    async scheduleRefreshBlockLevel() {
        const ipBlockKeys = await rclient.keysAsync("ip:block:info:*");
        log.info('schedule refresh block level for these ips:', ipBlockKeys)
        ipBlockKeys.map(async (key) => {
            let ipBlockInfo = JSON.parse(await rclient.getAsync(key));
            const { targetDomains, ip, blockLevel, blockSet } = ipBlockInfo;
            const allDomains = await dnsTool.getAllDns(ip);
            const sharedDomains = _.differenceWith(allDomains, targetDomains, (a, b) => {
                return this.domainCovered(b, a);
            });
            if (sharedDomains.length == 0 && blockLevel == 'domain') {
                Block.block(ip, blockSet)
            }
            if (sharedDomains.length > 0 && blockLevel == 'ip') {
                Block.unblock(ip, blockSet);
            }
            ipBlockInfo.ts = new Date() / 1000;
            ipBlockInfo.sharedDomains = sharedDomains;
            ipBlockInfo.allDomains = allDomains;
            await rclient.setAsync(key, JSON.stringify(ipBlockInfo));
        })
    }
    async updateIpBlockInfo(ip, domain, action, blockSet = 'block_domain_set') {
        let ipBlockInfo = {
            blockSet: blockSet,
            ip: ip,
            targetDomains: [],
            sharedDomains: [],
            allDomains: [],
            ts: new Date() / 1000
        }
        if (!fc.isFeatureOn(featureName)) {
            ipBlockInfo.blockLevel = 'ip';
        } else {
            const key = this.ipBlockInfoKey(ip);
            const exist = (await rclient.existsAsync(key) == 1);
            if (exist) {
                ipBlockInfo = JSON.parse(await rclient.getAsync(key));
            }
            switch (action) {
                case 'block': {
                    // if the ip shared with other domain, should not apply ip level block
                    // if a.com and b.com share ip and one of them block, it should be domain level
                    // if both block, should update to ip level
                    !ipBlockInfo.targetDomains.includes(domain) && ipBlockInfo.targetDomains.push(domain);
                    const allDomains = await dnsTool.getAllDns(ip);
                    const sharedDomains = _.differenceWith(allDomains, ipBlockInfo.targetDomains, (a, b) => {
                        return this.domainCovered(b, a);
                    });
                    sharedDomains.length > 0 && log.info(`${ipBlockInfo.targetDomains.join(',')} ip ${ip} shared with domains ${sharedDomains.join(',')}`)
                    if (sharedDomains.length == 0) {
                        ipBlockInfo.blockLevel = 'ip';
                    } else {
                        ipBlockInfo.blockLevel = 'domain';
                    }
                    ipBlockInfo.sharedDomains = sharedDomains;
                    ipBlockInfo.allDomains = allDomains;
                    ipBlockInfo.ts = new Date() / 1000;
                    await rclient.setAsync(key, JSON.stringify(ipBlockInfo));
                    break;
                }
                case 'unblock': {
                    !ipBlockInfo.sharedDomains.includes(domain) && ipBlockInfo.sharedDomains.push(domain);
                    ipBlockInfo.targetDomains = _.filter(ipBlockInfo.targetDomains, (a) => {
                        return a != domain;
                    })
                    if (ipBlockInfo.targetDomains.length == 0) {
                        await rclient.delAsync(key);
                    } else {
                        ipBlockInfo.ts = new Date() / 1000;
                        ipBlockInfo.blockLevel = 'domain';
                        await rclient.setAsync(key, JSON.stringify(ipBlockInfo));
                    }
                    break;
                }
                case 'newDomain': {
                    if (exist) {
                        // it is old ip and new domain
                        const { blockSet, targetDomains } = ipBlockInfo;
                        const alreayExistInTargetDomains = _.find(targetDomains, (targetDomain) => {
                            return this.domainCovered(targetDomain, domain);
                        })
                        if (!alreayExistInTargetDomains) {
                            if (ipBlockInfo.blockLevel == 'ip') {
                                log.info('ip block level change when new doamin comming', ip, domain)
                                ipBlockInfo.blockLevel = 'domain';
                                Block.unblock(ip, blockSet);
                            }
                            ipBlockInfo.sharedDomains.push(domain);
                            ipBlockInfo.allDomains = await dnsTool.getAllDns(ip);
                            ipBlockInfo.ts = new Date() / 1000;
                            await rclient.setAsync(key, JSON.stringify(ipBlockInfo));
                        }
                    }
                    break;
                }
            }
        }
        await this.updateDomainBlockInfo(domain, ipBlockInfo);
        return ipBlockInfo;
    }
    async updateDomainBlockInfo(domain, ipBlockInfo) {
        const key = this.domainBlockInfoKey(domain);
        let domainBlockInfo = await rclient.getAsync(key);
        try {
            domainBlockInfo = JSON.parse(domainBlockInfo);
        } catch (err) {
            domainBlockInfo = {};
        }
        domainBlockInfo[ipBlockInfo.ip] = ipBlockInfo;
        await rclient.setAsync(key, JSON.stringify(domainBlockInfo));
    }
    domainCovered(blockDomain, otherDomain) {
        // a.b.com covred x.a.b.com
        if (!otherDomain) return true;
        if (blockDomain.startsWith('*.')) blockDomain = blockDomain.substring(2)
        if (otherDomain.startsWith('*.')) otherDomain = otherDomain.substring(2)
        const h1Sections = blockDomain.split('.').reverse();
        const h2Sections = otherDomain.split('.').reverse();
        for (let i = 0; i < h1Sections.length; i++) {
            if (h1Sections[i] !== h2Sections[i])
                return false;
        }
        return true;
    }
}

module.exports = BlockManager
<|endoftext|>


<commit_before>// Amara, universalsubtitles.org
//
// Copyright (C) 2013 Participatory Culture Foundation
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see
// http://www.gnu.org/licenses/agpl-3.0.html.

var angular = angular || null;
var SubtitleListItemController = SubtitleListItemController || null;

(function($) {

    var directives = angular.module('amara.SubtitleEditor.directives', []);

    directives.directive('saveSessionButton', function(SubtitleStorage) {
        return {
            link: function link(scope, elm, attrs) {
                scope.canSave = '';
            }
        };
    });
    directives.directive('subtitleEditor', function(SubtitleStorage) {
        return {
            compile: function compile(elm, attrs, transclude) {
                return {
                    post: function post(scope, elm, attrs) {

                        $(elm).on('keydown', function(e) {

                            var video = angular.element($('#video').get(0)).scope();

                            // Tab without shift, toggle play / pause.
                            if (e.keyCode === 9 && !e.shiftKey) {
                                e.preventDefault();
                                video.togglePlay();
                            }

                        });

                    }
                };
            }
        };
    });
    directives.directive('subtitleList', function(SubtitleStorage, SubtitleListFinder, $timeout) {

        var activeTextArea,
            isEditable,
            rootEl,
            selectedController,
            selectedScope,
            value;

        function onSubtitleItemSelected(elm) {
            /**
             * Receives the li.subtitle-list-item to be edited.
             * Will put any previously edited ones in display mode,
             * mark this one as being edited, creating the textarea for
             * editing.
             */
            // make sure this works if the event was trigger in the
            // originating li or any descendants

            elm = $(elm).hasClass('subtitle-list-item') ?
                      elm : $(elm).parents('.subtitle-list-item');

            var controller = angular.element(elm).controller();
            var scope = angular.element(elm).scope();

            // make sure the user clicked on the list item
            if (controller instanceof SubtitleListItemController) {
                if (selectedScope) {
                    selectedScope.finishEditingMode(activeTextArea.val());
                    selectedScope.$digest();
                }
                activeTextArea = $('textarea', elm);
                selectedScope = scope;

                activeTextArea.val(selectedScope.startEditingMode());
                selectedScope.$digest();

                activeTextArea.focus();
                activeTextArea.autosize();
            }
        }
        function onSubtitleTextKeyDown(e) {
            /*
             * When a key is down, check to see if we need to do something:
             *
             * Enter / return: finish editing current sub and focus on the next one.
             * Shift + Enter / return: enter a newline in the current subtitle.
             * Tab: send the event to the video controller for playback control.
             * Shift + Tab: send the event to the video controller for playback control.
             * Any other key: do nothing.
             */

            var nextSubtitle;

            var $currentSubtitle = $(e.currentTarget).parent();

            // Enter / return without shift.
            if (e.keyCode === 13 && !e.shiftKey) {

                // Prevent an additional newline from being added to the next subtitle.
                e.preventDefault();

                // If canAddAndRemove is true and this is the last subtitle in the set,
                // save the current subtitle and create a new subtitle at the end.
                if (selectedScope.canAddAndRemove) {
                    if ($currentSubtitle.next().length === 0) {

                        // Save the current subtitle.
                        selectedScope.finishEditingMode(activeTextArea.val());

                        // Passing true as the last argument indicates that we want
                        // to select this subtitle after it is created.
                        selectedScope.addSubtitle(null, {}, '', true);

                        // Apply the current scope.
                        selectedScope.$apply();

                    }
                }

                // Set the next subtitle to be the one after this.
                nextSubtitle = $currentSubtitle.next().get(0);

            }

            // Tab without shift.
            if (e.keyCode === 9 && !e.shiftKey) {

                // We're letting this event bubble up to the subtitleEditor directive
                // where it will trigger the appropriate video method.

                // Keep the cursor in the current subtitle.
                e.preventDefault();

            }

            // Tab with shift.
            if (e.keyCode === 9 && e.shiftKey) {

                // Keep the cursor in the current subtitle.
                e.preventDefault();

                // Set the next subtitle to be the one before this.
                nextSubtitle = $currentSubtitle.prev().get(0);

            }

            if (nextSubtitle) {

                // Select the next element.
                onSubtitleItemSelected(nextSubtitle);

                // Focus on the active textarea.
                activeTextArea.focus();

            }
        }
        function onSubtitleTextKeyUp(e) {

            // Save the content to the DFXP wrapper.
            selectedScope.parser.content(selectedScope.subtitle, activeTextArea.val());

            // Cache the value for a negligible performance boost.
            value = activeTextArea.val();

            selectedScope.empty = value === '';
            selectedScope.characterCount = value.length;

            selectedScope.$root.$emit('subtitleKeyUp', {
                parser: selectedScope.parser,
                subtitles: $(selectedScope.subtitles)
            });

            selectedScope.$digest();

        }

        return {
            compile: function compile(elm, attrs, transclude) {
                rootEl = elm;
                return {
                    post: function post(scope, elm, attrs) {

                        scope.getSubtitles(attrs.languageCode, attrs.versionNumber);

                        isEditable = attrs.editable === 'true';
                        scope.canAddAndRemove = attrs.canAddAndRemove === 'true';

                        if (isEditable) {
                            $(elm).click(function(e) {
                                onSubtitleItemSelected(e.srcElement || e.target);
                            });
                            $(elm).on('keydown', 'textarea', onSubtitleTextKeyDown);
                            $(elm).on('keyup', 'textarea', onSubtitleTextKeyUp);

                            // In order to catch an <esc> key sequence, we need to catch
                            // the keycode on the document, not the list. Also, keyup must
                            // be used instead of keydown.
                            $(document).on('keyup', function(e) {
                                if (e.keyCode === 27) {
                                    selectedScope.finishEditingMode(activeTextArea.val());
                                    selectedScope.$digest();
                                }
                            });

                            // Create a custom event handler to select a subtitle.
                            //
                            // See the subtitleListItem directive below. This gets called
                            // if a subtitleListItem is created and its index matches the
                            // focus index that is set when adding the new subtitle from the
                            // controller.
                            $(elm).on('selectFocusedSubtitle', function() {

                                var $subtitle = $('li', elm).eq(scope.focusIndex);

                                // Select the subtitle.
                                //
                                // We have to timeout here, otherwise we'll try to select
                                // the new subtitle before it's been added to DOM.
                                $timeout(function() {
                                    onSubtitleItemSelected($subtitle.get(0));
                                });

                            });
                        }
                        scope.setVideoID(attrs.videoId);
                        scope.setLanguageCode(attrs.languageCode);
                        SubtitleListFinder.register(attrs.subtitleList, elm,
                            angular.element(elm).controller(), scope);
                    }
                };
            }
        };
    });
    directives.directive('subtitleListItem', function() {
        return {
            compile: function compile(elm, attrs, transclude) {
                return {
                    post: function post(scope, elm, attrs) {

                        // If we need to focus this subtitle.
                        if (scope.getSubtitleIndex() === scope.$parent.focusIndex) {

                            // Trigger the custom event selectFocusedSubtitle on the UL,
                            // which was bound in the subtitleList directive above.
                            $(elm).parent().trigger('selectFocusedSubtitle');

                        }

                    }
                };
            }
        };
    });

})(window.AmarajQuery);
<commit_msg>Don't finish editing subtitle if no subtitle is selected, on escape keypress.<commit_after>// Amara, universalsubtitles.org
//
// Copyright (C) 2013 Participatory Culture Foundation
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see
// http://www.gnu.org/licenses/agpl-3.0.html.

var angular = angular || null;
var SubtitleListItemController = SubtitleListItemController || null;

(function($) {

    var directives = angular.module('amara.SubtitleEditor.directives', []);

    directives.directive('saveSessionButton', function(SubtitleStorage) {
        return {
            link: function link(scope, elm, attrs) {
                scope.canSave = '';
            }
        };
    });
    directives.directive('subtitleEditor', function(SubtitleStorage) {
        return {
            compile: function compile(elm, attrs, transclude) {
                return {
                    post: function post(scope, elm, attrs) {

                        $(elm).on('keydown', function(e) {

                            var video = angular.element($('#video').get(0)).scope();

                            // Tab without shift, toggle play / pause.
                            if (e.keyCode === 9 && !e.shiftKey) {
                                e.preventDefault();
                                video.togglePlay();
                            }

                        });

                    }
                };
            }
        };
    });
    directives.directive('subtitleList', function(SubtitleStorage, SubtitleListFinder, $timeout) {

        var activeTextArea,
            isEditable,
            rootEl,
            selectedController,
            selectedScope,
            value;

        function onSubtitleItemSelected(elm) {
            /**
             * Receives the li.subtitle-list-item to be edited.
             * Will put any previously edited ones in display mode,
             * mark this one as being edited, creating the textarea for
             * editing.
             */
            // make sure this works if the event was trigger in the
            // originating li or any descendants

            elm = $(elm).hasClass('subtitle-list-item') ?
                      elm : $(elm).parents('.subtitle-list-item');

            var controller = angular.element(elm).controller();
            var scope = angular.element(elm).scope();

            // make sure the user clicked on the list item
            if (controller instanceof SubtitleListItemController) {
                if (selectedScope) {
                    selectedScope.finishEditingMode(activeTextArea.val());
                    selectedScope.$digest();
                }
                activeTextArea = $('textarea', elm);
                selectedScope = scope;

                activeTextArea.val(selectedScope.startEditingMode());
                selectedScope.$digest();

                activeTextArea.focus();
                activeTextArea.autosize();
            }
        }
        function onSubtitleTextKeyDown(e) {
            /*
             * When a key is down, check to see if we need to do something:
             *
             * Enter / return: finish editing current sub and focus on the next one.
             * Shift + Enter / return: enter a newline in the current subtitle.
             * Tab: send the event to the video controller for playback control.
             * Shift + Tab: send the event to the video controller for playback control.
             * Any other key: do nothing.
             */

            var nextSubtitle;

            var $currentSubtitle = $(e.currentTarget).parent();

            // Enter / return without shift.
            if (e.keyCode === 13 && !e.shiftKey) {

                // Prevent an additional newline from being added to the next subtitle.
                e.preventDefault();

                // If canAddAndRemove is true and this is the last subtitle in the set,
                // save the current subtitle and create a new subtitle at the end.
                if (selectedScope.canAddAndRemove) {
                    if ($currentSubtitle.next().length === 0) {

                        // Save the current subtitle.
                        selectedScope.finishEditingMode(activeTextArea.val());

                        // Passing true as the last argument indicates that we want
                        // to select this subtitle after it is created.
                        selectedScope.addSubtitle(null, {}, '', true);

                        // Apply the current scope.
                        selectedScope.$apply();

                    }
                }

                // Set the next subtitle to be the one after this.
                nextSubtitle = $currentSubtitle.next().get(0);

            }

            // Tab without shift.
            if (e.keyCode === 9 && !e.shiftKey) {

                // We're letting this event bubble up to the subtitleEditor directive
                // where it will trigger the appropriate video method.

                // Keep the cursor in the current subtitle.
                e.preventDefault();

            }

            // Tab with shift.
            if (e.keyCode === 9 && e.shiftKey) {

                // Keep the cursor in the current subtitle.
                e.preventDefault();

                // Set the next subtitle to be the one before this.
                nextSubtitle = $currentSubtitle.prev().get(0);

            }

            if (nextSubtitle) {

                // Select the next element.
                onSubtitleItemSelected(nextSubtitle);

                // Focus on the active textarea.
                activeTextArea.focus();

            }
        }
        function onSubtitleTextKeyUp(e) {

            // Save the content to the DFXP wrapper.
            selectedScope.parser.content(selectedScope.subtitle, activeTextArea.val());

            // Cache the value for a negligible performance boost.
            value = activeTextArea.val();

            selectedScope.empty = value === '';
            selectedScope.characterCount = value.length;

            selectedScope.$root.$emit('subtitleKeyUp', {
                parser: selectedScope.parser,
                subtitles: $(selectedScope.subtitles)
            });

            selectedScope.$digest();

        }

        return {
            compile: function compile(elm, attrs, transclude) {
                rootEl = elm;
                return {
                    post: function post(scope, elm, attrs) {

                        scope.getSubtitles(attrs.languageCode, attrs.versionNumber);

                        isEditable = attrs.editable === 'true';
                        scope.canAddAndRemove = attrs.canAddAndRemove === 'true';

                        if (isEditable) {
                            $(elm).click(function(e) {
                                onSubtitleItemSelected(e.srcElement || e.target);
                            });
                            $(elm).on('keydown', 'textarea', onSubtitleTextKeyDown);
                            $(elm).on('keyup', 'textarea', onSubtitleTextKeyUp);

                            // In order to catch an <esc> key sequence, we need to catch
                            // the keycode on the document, not the list. Also, keyup must
                            // be used instead of keydown.
                            $(document).on('keyup', function(e) {
                                if (e.keyCode === 27) {
                                    if (selectedScope) {
                                        selectedScope.finishEditingMode(activeTextArea.val());
                                        selectedScope.$digest();
                                    }
                                }
                            });

                            // Create a custom event handler to select a subtitle.
                            //
                            // See the subtitleListItem directive below. This gets called
                            // if a subtitleListItem is created and its index matches the
                            // focus index that is set when adding the new subtitle from the
                            // controller.
                            $(elm).on('selectFocusedSubtitle', function() {

                                var $subtitle = $('li', elm).eq(scope.focusIndex);

                                // Select the subtitle.
                                //
                                // We have to timeout here, otherwise we'll try to select
                                // the new subtitle before it's been added to DOM.
                                $timeout(function() {
                                    onSubtitleItemSelected($subtitle.get(0));
                                });

                            });
                        }
                        scope.setVideoID(attrs.videoId);
                        scope.setLanguageCode(attrs.languageCode);
                        SubtitleListFinder.register(attrs.subtitleList, elm,
                            angular.element(elm).controller(), scope);
                    }
                };
            }
        };
    });
    directives.directive('subtitleListItem', function() {
        return {
            compile: function compile(elm, attrs, transclude) {
                return {
                    post: function post(scope, elm, attrs) {

                        // If we need to focus this subtitle.
                        if (scope.getSubtitleIndex() === scope.$parent.focusIndex) {

                            // Trigger the custom event selectFocusedSubtitle on the UL,
                            // which was bound in the subtitleList directive above.
                            $(elm).parent().trigger('selectFocusedSubtitle');

                        }

                    }
                };
            }
        };
    });

})(window.AmarajQuery);
<|endoftext|>


<commit_before>// ==UserScript==
// @name         Legend Express Agar.io Extension
// @namespace    Legend Express Agario Mod
// @version      1.7
// @description  Agario Mod - Legend,Ogario,Kitty,Old Skins,Animated Skins,Language Packs,Manual User Scripts,Chat,60++ Macros/Hotkeys(Tricksplit,Doublesplit,Quick Feeding,Popsplit,Auto Coins,Freeze Cell Macro,Auto respawn)
// @homepage     https://www.legendmod.ml
// @author       Jimboy3100
// @license      MIT
// @icon         https://legendmod.ml/banners/CropedImage128.gif
// @match        https://agar.io/*
// @match        https://play.google.com/*
// @downloadURL  https://legendmod.ml/LMexpress/LMexpress.user.js
// @updateURL    https://legendmod.ml/LMexpress/LMexpress.user.js
// @run-at       document-start
// @grant        GM_xmlhttpRequest
// @connect      hslo.io
// @connect	 agartool.io
// @connect	 imasters.org.ru
// @connect	 cdn.ogario.ovh
// @connect      deltav4.glitch.me
// @connect      legendmod.ml
// ==/UserScript==

// Legend Mod by Jimboy3100
/*MIT License*/

function getVersion() {
    var request = new XMLHttpRequest();
    request.open('GET', 'https://raw.githubusercontent.com/jimboy3100/jimboy3100.github.io/master/VERSION.txt', false);
    request.send(null);

    if (request.status === 200) {
        return request.responseText.replace(/^\s+|\s+$/g, '');
    }
    else
    {
        return (new Date()).getTime();
    }
}

var version = getVersion();

// Check location
if (location.host === "agar.io" && location.pathname === "/") {
    var url = window.location.href;
    localStorage.setItem("url", url);
    location.href = "https://agar.io/legendmod" + location.hash;
    return;
}
var modVersion = GM_info.script.version;
// Inject Legend
function inject(page) {
    var page = page.replace("", "" + "");
    return page;
}
document.documentElement.innerHTML = "";
var LMdetails;
var mode = location.pathname.slice(1);
var modwebsite;
switch (mode) {
    case 'normal':
        modwebsite = 'https://agar.io';
        Htmlscript(modwebsite);
        break;
    case 'hslo':
        modwebsite = 'https://hslo.io/install.user.js';
        Userscript(modwebsite);
        break;
    case 'agartool':
        modwebsite = 'https://www.agartool.io/agartool.user.js';
        Userscript(modwebsite);
        break;
    case 'vanilla':
        modwebsite = 'http://imasters.org.ru/agar/js/vanilla.user.js';
        Userscript(modwebsite);
        break;
    case 'ogario':
        modwebsite = 'https://cdn.ogario.ovh/v4/beta/ogario.v4.user.js';
        Userscript(modwebsite);
        break;
    case 'delta':
        modwebsite = 'https://deltav4.glitch.me/v4/index.html';
        Htmlscript(modwebsite);
        break;
    case 'neo':
        modwebsite = 'https://legendmod.ml/LMexpress/LMexpress.html?' + version;
        Htmlscript(modwebsite);
		setTimeout(function() {
			modwebsite = 'https://legendmod.ml/ExampleScripts/Neoprivate.js';
			Userscript(modwebsite);
		}, 5000);
	break;
    case 'mobile':
        modwebsite = 'https://legendmod.ml/LMexpress/LMexpress.html';
        Htmlscript(modwebsite);
		setTimeout(function() {
			modwebsite = 'https://legendmod.ml/ExampleScripts/gamepad.user.js';
			Userscript(modwebsite);
		}, 5000);
	break;
    case 'legendmod': default:
        modwebsite = 'https://legendmod.ml/LMexpress/LMexpress.html?' + version;
        Htmlscript(modwebsite);
        break;
}

function Htmlscript(modwebsite) {
    LMdetails = GM_xmlhttpRequest({
        method: "GET",
        url: modwebsite,
        synchronous: false,
        onload: function(legend) {
            var doc = inject(legend.responseText);
            document.open();
            document.write(doc);
            setTimeout(function() {
                window.history.pushState(null, null, "/");
            }, 2000);
            document.close();
        }
    });
}

function Userscript(modwebsite) {
    LMdetails = GM_xmlhttpRequest({
        method: "GET",
        url: modwebsite,
        onload: function(e) {
            new Function(['GM_info, GM_xmlhttpRequest'], e.responseText)(GM_info, GM_xmlhttpRequest);
        }
    });
}

if (location.host == "play.google.com") {
    window.close();
}

function getParameterByName(name, url) {
    if (!url) url = window.location.href;
    name = name.replace(/[\[\]]/g, "\\$&");
    var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"),
        results = regex.exec(url);
    if (!results) return null;
    if (!results[2]) return '';
    return decodeURIComponent(results[2].replace(/\+/g, " "));
}
<commit_msg>Update LMexpress.user.js<commit_after>// ==UserScript==
// @name         Legend Express Agar.io Extension
// @namespace    Legend Express Agario Mod
// @version      1.7
// @description  Agario Mod - Legend,Ogario,Kitty,Old Skins,Animated Skins,Language Packs,Manual User Scripts,Chat,60++ Macros/Hotkeys(Tricksplit,Doublesplit,Quick Feeding,Popsplit,Auto Coins,Freeze Cell Macro,Auto respawn)
// @homepage     https://www.legendmod.ml
// @author       Jimboy3100
// @license      MIT
// @icon         https://legendmod.ml/banners/CropedImage128.gif
// @match        https://agar.io/*
// @match        https://play.google.com/*
// @downloadURL  https://legendmod.ml/LMexpress/LMexpress.user.js
// @updateURL    https://legendmod.ml/LMexpress/LMexpress.user.js
// @run-at       document-start
// @grant        GM_xmlhttpRequest
// @connect      hslo.io
// @connect	 agartool.io
// @connect	 imasters.org.ru
// @connect	 cdn.ogario.ovh
// @connect      deltav4.glitch.me
// @connect      legendmod.ml
// ==/UserScript==

// Legend Mod by Jimboy3100
/*MIT License*/

function getVersion() {
    try
    {
        var request = new XMLHttpRequest();
        request.open('GET', 'https://raw.githubusercontent.com/jimboy3100/jimboy3100.github.io/master/VERSION.txt', false);
        request.send(null);

        if (request.status === 200)
            return request.responseText.replace(/^\s+|\s+$/g, '');
    } catch (e) {}

    return (new Date()).getTime();
}

var version = getVersion();

// Check location
if (location.host === "agar.io" && location.pathname === "/") {
    var url = window.location.href;
    localStorage.setItem("url", url);
    location.href = "https://agar.io/legendmod" + location.hash;
    return;
}
var modVersion = GM_info.script.version;
// Inject Legend
function inject(page) {
    var page = page.replace("", "" + "");
    return page;
}
document.documentElement.innerHTML = "";
var LMdetails;
var mode = location.pathname.slice(1);
var modwebsite;
switch (mode) {
    case 'normal':
        modwebsite = 'https://agar.io';
        Htmlscript(modwebsite);
        break;
    case 'hslo':
        modwebsite = 'https://hslo.io/install.user.js';
        Userscript(modwebsite);
        break;
    case 'agartool':
        modwebsite = 'https://www.agartool.io/agartool.user.js';
        Userscript(modwebsite);
        break;
    case 'vanilla':
        modwebsite = 'http://imasters.org.ru/agar/js/vanilla.user.js';
        Userscript(modwebsite);
        break;
    case 'ogario':
        modwebsite = 'https://cdn.ogario.ovh/v4/beta/ogario.v4.user.js';
        Userscript(modwebsite);
        break;
    case 'delta':
        modwebsite = 'https://deltav4.glitch.me/v4/index.html';
        Htmlscript(modwebsite);
        break;
    case 'neo':
        modwebsite = 'https://legendmod.ml/LMexpress/LMexpress.html?' + version;
        Htmlscript(modwebsite);
		setTimeout(function() {
			modwebsite = 'https://legendmod.ml/ExampleScripts/Neoprivate.js';
			Userscript(modwebsite);
		}, 5000);
	break;
    case 'mobile':
        modwebsite = 'https://legendmod.ml/LMexpress/LMexpress.html';
        Htmlscript(modwebsite);
		setTimeout(function() {
			modwebsite = 'https://legendmod.ml/ExampleScripts/gamepad.user.js';
			Userscript(modwebsite);
		}, 5000);
	break;
    case 'legendmod': default:
        modwebsite = 'https://legendmod.ml/LMexpress/LMexpress.html?' + version;
        Htmlscript(modwebsite);
        break;
}

function Htmlscript(modwebsite) {
    LMdetails = GM_xmlhttpRequest({
        method: "GET",
        url: modwebsite,
        synchronous: false,
        onload: function(legend) {
            var doc = inject(legend.responseText);
            document.open();
            document.write(doc);
            setTimeout(function() {
                window.history.pushState(null, null, "/");
            }, 2000);
            document.close();
        }
    });
}

function Userscript(modwebsite) {
    LMdetails = GM_xmlhttpRequest({
        method: "GET",
        url: modwebsite,
        onload: function(e) {
            new Function(['GM_info, GM_xmlhttpRequest'], e.responseText)(GM_info, GM_xmlhttpRequest);
        }
    });
}

if (location.host == "play.google.com") {
    window.close();
}

function getParameterByName(name, url) {
    if (!url) url = window.location.href;
    name = name.replace(/[\[\]]/g, "\\$&");
    var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"),
        results = regex.exec(url);
    if (!results) return null;
    if (!results[2]) return '';
    return decodeURIComponent(results[2].replace(/\+/g, " "));
}
<|endoftext|>


<commit_before>import Bullet from '../sprites/Bullet';
import direction from './direction';
import config from '../../setup/config';

export default class Weapon {
    constructor(player, game) {
        this.game = game;
        this.player = player;
        this.nextShotAt = Date.now() + config.game.weapons.fireball.shotDelay;

        this.bullets = game.add.group();
        this.bullets.enableBody = true;
        this.bullets.physicsBodyType = Phaser.Physics.ARCADE;

        this.weapon = 'fireball';

    }

    shoot(overwriteDirection = null) {
        if (this.nextShotAt > Date.now()) {
            return;
        }

        var shootDirection = (overwriteDirection) ? overwriteDirection : this.player.direction;

        this.nextShotAt = Date.now() + config.game.weapons.fireball.shotDelay;

        this.player.loadTexture('player_shoot', 0, true);
        this.game.time.events.add(Phaser.Timer.SECOND * 0.2, this.player.stopShooting, this.player);

        var bullet = new Bullet(this.game, this.player.body.center.x, this.player.body.center.y, this.weapon);
        bullet.setTeam(this.player.team);
        bullet.setShooter(this.player);
        bullet.animations.add(this.weapon, Phaser.Animation.generateFrameNames(this.weapon + '_000', 1, 6), 60, true);
        bullet.animations.play(this.weapon);
        bullet.anchor.setTo(0.5, 0.5);

        if (shootDirection === direction.BOTTOM) {
            bullet.body.velocity.y = config.game.weapons[this.weapon].bulletSpeed;
            bullet.angle = 180;
        } else if (shootDirection === direction.TOP) {
            bullet.angle = 0;
            bullet.body.velocity.y = -config.game.weapons[this.weapon].bulletSpeed;
        } else if (shootDirection === direction.RIGHT) {
            bullet.angle = 90;
            bullet.body.velocity.x = config.game.weapons[this.weapon].bulletSpeed;
        } else if (shootDirection === direction.LEFT) {
            bullet.angle = -90;
            bullet.body.velocity.x = -config.game.weapons[this.weapon].bulletSpeed;
        }

        this.bullets.add(bullet);

        eventSystem().emit('bullet.shoot', {
           bullet: bullet
       });
    }
}
<commit_msg>show current Weapon in statusbar<commit_after>import Bullet from '../sprites/Bullet';
import direction from './direction';
import config from '../../setup/config';

export default class Weapon {
    constructor(player, game) {
        this.game = game;
        this.player = player;
        this.nextShotAt = Date.now() + config.game.weapons.fireball.shotDelay;
        this.weapon = 'fireball';

        this.currentWeapon();
    }

    currentWeapon() {
      this.weaponSprite = this.game.add.sprite(30, 20, this.weapon);
      this.weaponSprite.animations.add(this.weapon, Phaser.Animation.generateFrameNames(this.weapon + '_000', 1, 6), 60, true);
      this.weaponSprite.animations.play(this.weapon);
      this.weaponSprite.anchor.setTo(0.5, 0.5);
      this.weaponSprite.angle = 90;
      this.weaponSprite.scale.x = 0.7;
      this.weaponSprite.scale.y = 0.7;
      this.weaponSprite.fixedToCamera = true;
    }

    shoot(overwriteDirection = null) {
        if (this.nextShotAt > Date.now()) {
            return;
        }

        var shootDirection = (overwriteDirection) ? overwriteDirection : this.player.direction;

        this.nextShotAt = Date.now() + config.game.weapons.fireball.shotDelay;

        this.player.loadTexture('player_shoot', 0, true);
        this.game.time.events.add(Phaser.Timer.SECOND * 0.2, this.player.stopShooting, this.player);

        var bullet = new Bullet(this.game, this.player.body.center.x, this.player.body.center.y, this.weapon);
        bullet.setTeam(this.player.team);
        bullet.setShooter(this.player);
        bullet.animations.add(this.weapon, Phaser.Animation.generateFrameNames(this.weapon + '_000', 1, 6), 60, true);
        bullet.animations.play(this.weapon);
        bullet.anchor.setTo(0.5, 0.5);

        if (shootDirection === direction.BOTTOM) {
            bullet.body.velocity.y = config.game.weapons[this.weapon].bulletSpeed;
            bullet.angle = 180;
        } else if (shootDirection === direction.TOP) {
            bullet.angle = 0;
            bullet.body.velocity.y = -config.game.weapons[this.weapon].bulletSpeed;
        } else if (shootDirection === direction.RIGHT) {
            bullet.angle = 90;
            bullet.body.velocity.x = config.game.weapons[this.weapon].bulletSpeed;
        } else if (shootDirection === direction.LEFT) {
            bullet.angle = -90;
            bullet.body.velocity.x = -config.game.weapons[this.weapon].bulletSpeed;
        }

        eventSystem().emit('bullet.shoot', {
           bullet: bullet
       });
    }
}
<|endoftext|>


<commit_before>import Settings      from '../stores/settings';
import Translations  from '../translations';
/**
 *
 */
export default function() {
	return {
		getInitialState() {
			return {
				locale: Settings.getLocale(),
				translations: Translations
			}
		},

		onLocaleChange() {
			this.setState({ locale: Settings.getLocale() });
		},

		componentDidMount() {
			Settings.addChangeListener(this.onLocaleChange);
		},

		componentWillUnmount() {
			Settings.removeChangeListener(this.onLocaleChange);
		},

		locale(id) {
			if(!this.state.translations[id]) {
				return id;
			}

			// If text is not translated to that language then return ID
			// to more easily notice missing translation
			if(this.state.translations[id][this.state.locale] === '') {
				return id;
			}

			return this.state.translations[id][this.state.locale];
		}
	}
}
<commit_msg>fix #258 in production mode, development mode will still return ID<commit_after>import Settings      from '../stores/settings';
import Translations  from '../translations';
/**
 *
 */
export default function() {
	return {
		getInitialState() {
			return {
				locale: Settings.getLocale(),
				translations: Translations
			}
		},

		onLocaleChange() {
			this.setState({ locale: Settings.getLocale() });
		},

		componentDidMount() {
			Settings.addChangeListener(this.onLocaleChange);
		},

		componentWillUnmount() {
			Settings.removeChangeListener(this.onLocaleChange);
		},

		locale(id) {
			// If translation for text is not found return ID
			// this fixes localization if text is localized twice for some reason
			if(!this.state.translations[id]) {
				return id;
			}

			// If translation is undefined or empty
			if(!this.state.translations[id][this.state.locale] ||
				this.state.translations[id][this.state.locale] === '') {

				// In production mode return english translation
				if(process.NODE_ENV === 'production') {
					return this.state.translations[id]['en'];
				}

				// In development return ID
				return id;
			}

			return this.state.translations[id][this.state.locale];
		}
	}
}
<|endoftext|>