<commit_before>var gamejs = "", modBlocking = true;
var tester = document.getElementsByTagName("script");
var i = 0, main_out_url = "http://agar.io/main_out.js", discovered_mainouturl = 0;
var W = '';
var Ja = '';

for (i=0; i<tester.length; i++ ){
	src = tester[i].src;
	if (src.substring(0, main_out_url.length ) == main_out_url) {
		discovered_mainouturl = src.replace("http://agar.io/","");
	}
}

if(discovered_mainouturl != 0) {
	httpGet(discovered_mainouturl, function(data) {
		gamejs = "window.agariomods = " + data.replace("socket open","socket open (agariomods.com mod in place)");
		offset = gamejs.search("..b..src");
		W = gamejs.substr(offset,1);
		offset = gamejs.search("..=\"poland;");
		Ja =  gamejs.substr(offset,2);
		agariomodsRuntimeInjection();
	});
}

// XMLHttp, because apparently raven is doing funky stuff with jQuery
function httpGet(theUrl, callback) {
    var xmlHttp = new XMLHttpRequest();
    xmlHttp.open("GET", theUrl, true);
    xmlHttp.send(null);
	xmlHttp.onreadystatechange = function() {
		if (xmlHttp.readyState == 4 && xmlHttp.status == 200) {
			callback(xmlHttp.responseText);
		}
	};
}
function agariomodsRuntimeInjection() {
	var tester = document.getElementsByTagName("html");
	var oldhtml = tester[0].innerHTML;
	var script = document.createElement("script");
	agariomodsRuntimePatches();
	script.innerHTML = gamejs;
	document.head.appendChild(script);
	agariomodsRuntimeHacks();
}
function agariomodsRuntimePatches() {
	//s
	gamejs = gamejs.replace(';reddit;',';reddit;electronoob;');
	gamejs = gamejs.replace(W + '[b]=new Image,'+W+'[b].src="skins/"+b+".png"',W +'[b]=new Image,'+W+'[b].crossOrigin = "Anonymous",'+W+'[b].src="skins/"+b+".png"');
	gamejs = gamejs.replace('b=this.name.toLowerCase();', 'b=this.name.toLowerCase();var agariomods="";if(b == "electronoob") {agariomods="http://agariomods.com/skins/electronoob.png";} else if (b.substring(0, 2) == "i/") {agariomods="http://i.imgur.com/"+this.name.substring(2)+".jpg";} else {agariomods="http://agar.io/skins/" + this.name.toLowerCase() + ".png";}');
	gamejs = gamejs.replace(W +'[b].src="skins/"+b+".png"',W+'[b].src=agariomods');
	gamejs = gamejs.replace("this._stroke&&b.strokeText(c,3,e-g/2);b.fillText(c,3,e-g/2)", "if (String(c).substring(0, 2) != \"i/\") {this._stroke&&b.strokeText(c,3,e-g/2);b.fillText(c,3,e-g/2)}");
	// lol raven
	gamejs = gamejs.replace("b=this.name.toLowerCase();", "b=this.name.toLowerCase(); if (b.substring(0, 2) == \"i/\") {" +Ja+ "+=b;} ;");
	gamejs = gamejs.replace('g.Raven&&g.Raven.config("https://2a85d1d3fb114384a2758cde7de2bef7@app.getsentry.com/43938",{release:"2",whitelistUrls:["agar.io/"]}).install();', "");
	//m
	gamejs = gamejs.replace("wa=!1", "wa=!0");
/*we have rolled back the mass mod because of the unfair advantage it offers, it's not cool to cheat!****/
/*	gamejs = gamejs.replace("(c||0==g.length&&(!this.isVirus||this.isAgitated)&&20<this.size)&&", ""); */

}
function agariomodsRuntimeHacks() {
	jQuery('#helloDialog').css({top: '-100px'});
	jQuery('#helloDialog').css({margin: '5px auto'});
	var nodeDiv = document.createElement("div");
	//
	$( document ).ready(function() {
	hd = document.getElementById("helloDialog");
	cachedhd = hd.innerHTML;
	hd.innerHTML = cachedhd.replace("Hello", "<astyle=\"position:absolute; padding-left:335px; top:-10px; z-index: -1; height:200px;\" href=\"https://www.reddit.com/r/Agario/\">");
	});
	//
	document.getElementById("nick").placeholder = "name or imgur i/[id]";
	$( document ).ready(function() {
	nh = document.getElementById("overlays");
	cachednh = nh.innerHTML;
	nh.innerHTML = cachednh.replace("
Type your nick or leave it empty:
", "Set name as i/D2yH9r8 for skins example.");
	});
	nodeDiv.id = "includedContent";
	nodeDiv.style.width = "640px"
	nodeDiv.style.backgroundColor = "#000000";
	nodeDiv.style.zIndex = 9999999999;
	nodeDiv.style.position = "relative";
	nodeDiv.style.padding = "5px";
	nodeDiv.style.left = "-170px";
	nodeDiv.style.borderRadius = "5px";
	nodeDiv.style.color = "#dddddd";
	nodeDiv.innerHTML = "
Version 1.7.3-reddit  Thank you to ayylmao and itchy for the kindness that you have showed us.
";
//
Our website, forum, and mumble.
";
nodeDiv.innerHTML += "
 Forum - We do not support cheaters, hacks, or mods which offer an unfair advantage. That is why we have rolled back our previous mod for showing everyone's mass.

1: upload pic to imgur.com, 2: get the id of img, 3: type i/ followed by the id. ex: i/rIWgY2u

Get your friends using this script and they can see your new avatar too!
";
	nodeDiv.innerHTML += "/r/Agario/ is the only offical agar.io subreddit!
connections steps";
	nodeDiv.innerHTML += "\

\

1: Get ip address from friend.
\

2: Put it in text box below.
\

3: Press the swirly icon next to it.
\

Note: Check with your friend to see whos #1 on the leaderboard
\

\

\
	Disable adblocking software! We finally tracked down an issue to adblocking software, Turns out that it breaks the game and our modifications in random and unexpected ways. Beside Zeach provides this game free and we all need to support him!\

\
	";
	jQuery('#region').parent().get(0).appendChild(document.createElement("br"));
	jQuery('#region').parent().get(0).appendChild(nodeDiv);
	var selector = jQuery('#region');
	var playBtn = jQuery('#playBtn');
	var nodeInput = document.createElement("input");
	var nodeSpan = document.createElement("span");
	var nodeBr = document.createElement("br");
	nodeSpan.className = "glyphicon glyphicon-refresh";
	nodeSpan.style.fontSize = "1.5em";
	nodeSpan.style.cssFloat = "left";
	nodeSpan.style.paddingTop = "5px";
	nodeSpan.style.paddingLeft = "15px";
	nodeSpan.addEventListener("click", function (e) {
	    if (modBlocking == false) {
                        //jQuery('#region').style.height = "0px";
                        jQuery('#region').hide();
                        //jQuery('#gamemode').style.height = "0px";
                        jQuery('#gamemode').hide();
	                      console.log ("clicked refresh");
				var oldregionval = jQuery('#region').val;
	                      jQuery('#region').val("EU-London");
       	               jQuery('#region').change();
       	               jQuery('#region').val("SG-Singapore");
			jQuery('#region').change();
			jQuery('#region').val(oldregionval);
			jQuery('#region').change();
			 jQuery('#gamemode').change();
			      //jQuery(this).fadeOut(100).fadeIn(100);
	    }
	});
	nodeInput.className = "form-control";
	nodeInput.id = "iphack"
	nodeInput.style.width = "85%";
	nodeInput.style.cssFloat = "left";
	nodeInput.style.cssClear = "right";
	nodeInput.style.border = "2px solid green";
	nodeInput.placeholder = "Alternative server ip:port here.";
	jQuery(playBtn).parent().get(0).appendChild(nodeBr);
	jQuery(playBtn).parent().get(0).appendChild(nodeInput);
	jQuery(playBtn).parent().get(0).appendChild(nodeSpan);
	jQuery('#iphack').change(function() {
	    if (jQuery('#iphack').val() == "") {
	        modBlocking = true;
	    }
	    modBlocking = false;
	});
	jQuery('#playBtn').off();
	$('.btn-needs-server').prop('disabled', false);
	jQuery('#playBtn').click(function() {
	    setNick(document.getElementById('nick').value);
	    return false;
	});

}

(function(window) {
    var WebSocket_original = window.WebSocket;
    window.WebSocket_original = WebSocket_original;
    var newWebSocket = 0;
    window.WebSocket = function(data) {
        if (modBlocking == true) {
            newWebSocket = new window.WebSocket_original(data);
		jQuery('#includedContent').html("Here is the IP address of the server you are connected to currently, pass it to your friends for team playing.
" + data.replace('ws://', '') + "
 ");
        } else {
            console.log("HAXXED: connecting to " + jQuery('#iphack').val() + "(ignoring: " + data + ")");
            newWebSocket = new window.WebSocket_original("ws://" + jQuery('#iphack').val());
		jQuery('#includedContent').html("
Connected to " +  jQuery('#iphack').val() + "

Check leaderboard with your friend to ensure you are both on the exact world on the sameserver.

If you cannot see the same people in the leaderboard as your friend, press the swirly icon next the ip box to try another world on the same game server.");

        }
        return newWebSocket;

    };
})(window);
<commit_msg>reddit<commit_after>var gamejs = "", modBlocking = true;
var tester = document.getElementsByTagName("script");
var i = 0, main_out_url = "http://agar.io/main_out.js", discovered_mainouturl = 0;
var W = '';
var Ja = '';

for (i=0; i<tester.length; i++ ){
	src = tester[i].src;
	if (src.substring(0, main_out_url.length ) == main_out_url) {
		discovered_mainouturl = src.replace("http://agar.io/","");
	}
}

if(discovered_mainouturl != 0) {
	httpGet(discovered_mainouturl, function(data) {
		gamejs = "window.agariomods = " + data.replace("socket open","socket open (agariomods.com mod in place)");
		offset = gamejs.search("..b..src");
		W = gamejs.substr(offset,1);
		offset = gamejs.search("..=\"poland;");
		Ja =  gamejs.substr(offset,2);
		agariomodsRuntimeInjection();
	});
}

// XMLHttp, because apparently raven is doing funky stuff with jQuery
function httpGet(theUrl, callback) {
    var xmlHttp = new XMLHttpRequest();
    xmlHttp.open("GET", theUrl, true);
    xmlHttp.send(null);
	xmlHttp.onreadystatechange = function() {
		if (xmlHttp.readyState == 4 && xmlHttp.status == 200) {
			callback(xmlHttp.responseText);
		}
	};
}
function agariomodsRuntimeInjection() {
	var tester = document.getElementsByTagName("html");
	var oldhtml = tester[0].innerHTML;
	var script = document.createElement("script");
	agariomodsRuntimePatches();
	script.innerHTML = gamejs;
	document.head.appendChild(script);
	agariomodsRuntimeHacks();
}
function agariomodsRuntimePatches() {
	//s
	gamejs = gamejs.replace(';reddit;',';reddit;electronoob;');
	gamejs = gamejs.replace(W + '[b]=new Image,'+W+'[b].src="skins/"+b+".png"',W +'[b]=new Image,'+W+'[b].crossOrigin = "Anonymous",'+W+'[b].src="skins/"+b+".png"');
	gamejs = gamejs.replace('b=this.name.toLowerCase();', 'b=this.name.toLowerCase();var agariomods="";if(b == "electronoob") {agariomods="http://agariomods.com/skins/electronoob.png";} else if (b.substring(0, 2) == "i/") {agariomods="http://i.imgur.com/"+this.name.substring(2)+".jpg";} else {agariomods="http://agar.io/skins/" + this.name.toLowerCase() + ".png";}');
	gamejs = gamejs.replace(W +'[b].src="skins/"+b+".png"',W+'[b].src=agariomods');
	gamejs = gamejs.replace("this._stroke&&b.strokeText(c,3,e-g/2);b.fillText(c,3,e-g/2)", "if (String(c).substring(0, 2) != \"i/\") {this._stroke&&b.strokeText(c,3,e-g/2);b.fillText(c,3,e-g/2)}");
	// lol raven
	gamejs = gamejs.replace("b=this.name.toLowerCase();", "b=this.name.toLowerCase(); if (b.substring(0, 2) == \"i/\") {" +Ja+ "+=b;} ;");
	gamejs = gamejs.replace('g.Raven&&g.Raven.config("https://2a85d1d3fb114384a2758cde7de2bef7@app.getsentry.com/43938",{release:"2",whitelistUrls:["agar.io/"]}).install();', "");
	//m
	gamejs = gamejs.replace("wa=!1", "wa=!0");
/*we have rolled back the mass mod because of the unfair advantage it offers, it's not cool to cheat!****/
/*	gamejs = gamejs.replace("(c||0==g.length&&(!this.isVirus||this.isAgitated)&&20<this.size)&&", ""); */

}
function agariomodsRuntimeHacks() {
	jQuery('#helloDialog').css({top: '-100px'});
	jQuery('#helloDialog').css({margin: '5px auto'});
	var nodeDiv = document.createElement("div");
	//
	$( document ).ready(function() {
	hd = document.getElementById("helloDialog");
	cachedhd = hd.innerHTML;
	hd.innerHTML = cachedhd.replace("Hello", "");
	});
	//
	document.getElementById("nick").placeholder = "name or imgur i/[id]";
	$( document ).ready(function() {
	nh = document.getElementById("overlays");
	cachednh = nh.innerHTML;
	nh.innerHTML = cachednh.replace("
Type your nick or leave it empty:
", "Set name as i/D2yH9r8 for skins example.");
	});
	nodeDiv.id = "includedContent";
	nodeDiv.style.width = "640px"
	nodeDiv.style.backgroundColor = "#000000";
	nodeDiv.style.zIndex = 9999999999;
	nodeDiv.style.position = "relative";
	nodeDiv.style.padding = "5px";
	nodeDiv.style.left = "-170px";
	nodeDiv.style.borderRadius = "5px";
	nodeDiv.style.color = "#dddddd";
	nodeDiv.innerHTML = "
Version 1.7.3-reddit  Thank you to ayylmao and itchy for the kindness that you have showed us.
";
//
Our website, forum, and mumble.
";
nodeDiv.innerHTML += "
 Forum - We do not support cheaters, hacks, or mods which offer an unfair advantage. That is why we have rolled back our previous mod for showing everyone's mass.

1: upload pic to imgur.com, 2: get the id of img, 3: type i/ followed by the id. ex: i/rIWgY2u

Get your friends using this script and they can see your new avatar too!
";
	nodeDiv.innerHTML += "/r/Agario/ is the only offical agar.io subreddit!
connections steps";
	nodeDiv.innerHTML += "\

\

1: Get ip address from friend.
\

2: Put it in text box below.
\

3: Press the swirly icon next to it.
\

Note: Check with your friend to see whos #1 on the leaderboard
\

\

\
	Disable adblocking software! We finally tracked down an issue to adblocking software, Turns out that it breaks the game and our modifications in random and unexpected ways. Beside Zeach provides this game free and we all need to support him!\

\
	";
	jQuery('#region').parent().get(0).appendChild(document.createElement("br"));
	jQuery('#region').parent().get(0).appendChild(nodeDiv);
	var selector = jQuery('#region');
	var playBtn = jQuery('#playBtn');
	var nodeInput = document.createElement("input");
	var nodeSpan = document.createElement("span");
	var nodeBr = document.createElement("br");
	nodeSpan.className = "glyphicon glyphicon-refresh";
	nodeSpan.style.fontSize = "1.5em";
	nodeSpan.style.cssFloat = "left";
	nodeSpan.style.paddingTop = "5px";
	nodeSpan.style.paddingLeft = "15px";
	nodeSpan.addEventListener("click", function (e) {
	    if (modBlocking == false) {
                        //jQuery('#region').style.height = "0px";
                        jQuery('#region').hide();
                        //jQuery('#gamemode').style.height = "0px";
                        jQuery('#gamemode').hide();
	                      console.log ("clicked refresh");
				var oldregionval = jQuery('#region').val;
	                      jQuery('#region').val("EU-London");
       	               jQuery('#region').change();
       	               jQuery('#region').val("SG-Singapore");
			jQuery('#region').change();
			jQuery('#region').val(oldregionval);
			jQuery('#region').change();
			 jQuery('#gamemode').change();
			      //jQuery(this).fadeOut(100).fadeIn(100);
	    }
	});
	nodeInput.className = "form-control";
	nodeInput.id = "iphack"
	nodeInput.style.width = "85%";
	nodeInput.style.cssFloat = "left";
	nodeInput.style.cssClear = "right";
	nodeInput.style.border = "2px solid green";
	nodeInput.placeholder = "Alternative server ip:port here.";
	jQuery(playBtn).parent().get(0).appendChild(nodeBr);
	jQuery(playBtn).parent().get(0).appendChild(nodeInput);
	jQuery(playBtn).parent().get(0).appendChild(nodeSpan);
	jQuery('#iphack').change(function() {
	    if (jQuery('#iphack').val() == "") {
	        modBlocking = true;
	    }
	    modBlocking = false;
	});
	jQuery('#playBtn').off();
	$('.btn-needs-server').prop('disabled', false);
	jQuery('#playBtn').click(function() {
	    setNick(document.getElementById('nick').value);
	    return false;
	});

}

(function(window) {
    var WebSocket_original = window.WebSocket;
    window.WebSocket_original = WebSocket_original;
    var newWebSocket = 0;
    window.WebSocket = function(data) {
        if (modBlocking == true) {
            newWebSocket = new window.WebSocket_original(data);
		jQuery('#includedContent').html("Here is the IP address of the server you are connected to currently, pass it to your friends for team playing.
" + data.replace('ws://', '') + "
 ");
        } else {
            console.log("HAXXED: connecting to " + jQuery('#iphack').val() + "(ignoring: " + data + ")");
            newWebSocket = new window.WebSocket_original("ws://" + jQuery('#iphack').val());
		jQuery('#includedContent').html("
Connected to " +  jQuery('#iphack').val() + "

Check leaderboard with your friend to ensure you are both on the exact world on the sameserver.

If you cannot see the same people in the leaderboard as your friend, press the swirly icon next the ip box to try another world on the same game server.");

        }
        return newWebSocket;

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


<commit_before>import React from "react";
import FormatedDate from "../common/formated-date";
import _ from "lodash";
const cx = require('classnames')

export default class FailureDetails extends React.Component {
  getStacktrace(failure) {
    let i = 0
    return _.map(failure.throwable.stackTrace, (el)=> {
      i++
      return (

          at {el.className}.{el.methodName}({el.fileName}:{el.lineNumber})

      )
    })
  }

  render() {
    let {failure, onClose} = this.props;
    let content = "";
    if (!!failure) {
      content = (

          <button className="btn btn-danger pull-right" onClick={onClose} style={{marginRight: 10}}></button>

Job

{failure.payload.className}

Queue

{failure.queue}

Time

<FormatedDate date={new Date(failure.failedAt)}/>

Exception

{failure.throwableString}

Message

{failure.error}

Stacktrace

{this.getStacktrace(failure)}

      )
    }

    return (

        {content}

    )
  }
}
<commit_msg>add job arguments to failure detail view<commit_after>import React from "react";
import FormatedDate from "../common/formated-date";
import _ from "lodash";
const cx = require('classnames')

export default class FailureDetails extends React.Component {
  getStacktrace(failure) {
    let i = 0
    return _.map(failure.throwable.stackTrace, (el)=> {
      i++
      return (

          at {el.className}.{el.methodName}({el.fileName}:{el.lineNumber})

      )
    })
  }

  render() {
    let {failure, onClose} = this.props;
    let content = "";
    if (!!failure) {
      content = (

          <button className="btn btn-danger pull-right" onClick={onClose} style={{marginRight: 10}}></button>

Job

{failure.payload.className}

Arguments

{failure.payload.args}

Queue

{failure.queue}

Time

<FormatedDate date={new Date(failure.failedAt)}/>

Exception

{failure.throwableString}

Message

{failure.error}

Stacktrace

{this.getStacktrace(failure)}

      )
    }

    return (

        {content}

    )
  }
}
<|endoftext|>


<commit_before>function getReviewersForFile(files, pullRequestUser, preferredReviewers) {
  var reviewerFiles = {};
  var fileReviewers = {};

  _.each(preferredReviewers, function (files, reviewer) {
    _.each(files, function (file) {
      fileReviewers[file] = fileReviewers[file] || [];
      fileReviewers[file].push(reviewer);
    });
  });

  _.each(files, function (file) {
    var reviewers = preferredReviewers[file.filename] || [];

    if (reviewers.length === 0) {
      var pattern = _.find(config.patterns, function (fileConf) {
        var patterns = fileConf.pattern;
        var usernames = fileConf.reviewers;

        var match = _.find(patterns.split(','), function (pattern) {
          //console.log(pattern, file.filename);
          return matchFilePath(pattern, file.filename);
        });

        // Reviewer for file cant be the same as the pull request sender
        if (match && (usernames.indexOf(pullRequestUser) === -1 || usernames.length > 1)) {
          return _.without(usernames, pullRequestUser);
        }
      });

      if (!pattern) {
        return;
      }

      reviewers = pattern.reviewers;

      var alreadyReviewing = _.intersection(
        reviewers,
        _.keys(reviewerFiles)
      );

      if (alreadyReviewing.length > 0) {
        reviewers = alreadyReviewing;
      }
    }

    var randomReviewer = reviewers[Math.floor(Math.random() * reviewers.length)];

    reviewerFiles[randomReviewer] = reviewerFiles[randomReviewer] || [];
    reviewerFiles[randomReviewer].push(file.filename);
  }, this);

  return reviewerFiles;
}

function getFileShaMap(files) {
  var fileShaMap = {};
  _.each(files, function (file) {
    fileShaMap[file.filename] = file.sha;
  });
  return fileShaMap;
}

function pullRequestOpened(eventData) {
  var pullRequestUser = eventData.pull_request.user.login;

  var files = getPullRequestFiles(eventData.number);
  var reviewerFiles = getReviewersForFile(files, pullRequestUser, {});
  var fileShaMap = getFileShaMap(files);

  if (_.keys(reviewerFiles).length > 0) {
    var message = 'Awesome work! Now just sit back and wait for Travis to pass and others to review your code.\n\n';
    message += '## Reviewers\n';

    _.each(reviewerFiles, function (files, reviewer) {
      message += '@' + reviewer + '\n';
      _.each(files, function (file) {
        message += '- ' + file + '\n';
      });
      message += '\n';
    });

    message += '\n### Review commands\n';
    message += '- accept: `pr_review OK`\n';
    message += '- add reviewer: `pr_review add [username]`\n';
    message += '- change reviewer: `pr_review change [old_username] [new_username]`\n';
    message += '- print status: `pr_review status`\n';

    createIssueComment(eventData.number, message);
    createStatus(
      eventData.pull_request.head.sha,
      'pending',
      eventData.pull_request.url,
      'Pull request review: ' + _.keys(reviewerFiles).join(', '),
      'pr_review'
    );
    saveData(eventData.number + ':waiting_review_from', JSON.stringify(reviewerFiles));
  }

  saveData(eventData.number + ':files', JSON.stringify(fileShaMap));
}

function pullRequestUpdated(eventData) {
  var pullRequestUser = eventData.pull_request.user.login;
  var files = getPullRequestFiles(eventData.number);
  var fileShaMapStr = loadData(eventData.number + ':files');
  var oldReviewersStr = loadData(eventData.number + ':waiting_review_from');
  var fileShaMap = {};
  var oldReviewers = {};

  try {
    fileShaMap = JSON.parse(fileShaMapStr);
  } catch(e) {}

  try {
    oldReviewers = JSON.parse(oldReviewersStr);
  } catch(e) {}

  files = _.filter(files, function (file) {
    if (fileShaMap[file.filename] !== file.sha) {
      fileShaMap[file.filename] = file.sha;
      return true;
    }
  });

  var reviewerFiles = getReviewersForFile(files, pullRequestUser, oldReviewers);

  if (_.keys(reviewerFiles).length > 0) {
    var message = 'Some of the files were updated.\n\n';
    message += '## Reviewers\n';
    _.each(reviewerFiles, function (files, reviewer) {
      message += '@' + reviewer + '\n';
      _.each(files, function (file) {
        message += '- ' + file + '\n';
      });
      message += '\n';
    });

    // Merge olds files back
    _.each(oldReviewers, function (files, reviewer) {
      reviewerFiles[reviewer] = reviewerFiles[reviewer] ? _.union(files, reviewerFiles[reviewer]) : files;
    });

    createIssueComment(eventData.number, message);

    createStatus(
      eventData.pull_request.head.sha,
      'pending',
      eventData.pull_request.url,
      'Pull request review: ' + _.keys(reviewerFiles).join(', '),
      'pr_review'
    );
    saveData(eventData.number + ':waiting_review_from', JSON.stringify(reviewerFiles));
  }

  saveData(eventData.number + ':files', JSON.stringify(fileShaMap));
}

function pullRequestComment(eventData) {
  var id = eventData.issue.number;
  var senderName = eventData.sender.login;
  var body = eventData.comment.body.trim();
  var cmd;

  _.each(body.split('\n'), function (message) {
    if (message.indexOf('pr_review') === 0) {
      cmd = _.filter(
        _.map(message.substring(10).split(' '), function (part) { return part.trim(); }),
        function (cmd) {
          return !!cdm;
        }
      );

      console.log('cdm ' + cmd.join(' '));

      switch(cmd[0].toLowerCase()) {
        case 'ok':
          var strData = loadData(id + ':waiting_review_from');
          if (strData) {
            try {
              var reviewerFiles = JSON.parse(strData);
              delete reviewerFiles[senderName];
              saveData(id + ':waiting_review_from', JSON.stringify(reviewerFiles));

              var prDetails = getPullRequestDetails(id);
              if (_.keys(reviewerFiles).length === 0) {
                createStatus(prDetails.head.sha, 'success', prDetails.url, 'Pull request review', 'pr_review');
                createIssueComment(id, "Review completed!");
              } else {
                createStatus(
                  prDetails.head.sha,
                  'pending',
                  prDetails.url,
                  'Pull request review: ' + _.keys(reviewerFiles).join(', '),
                  'pr_review'
                );
              }

            } catch(e) {}
          }
        break;
        case 'add':
          if (cmd[1]) {
            var newFiles = [];
            var strData = loadData(id + ':waiting_review_from');
            if (strData) {
              try {
                var reviewerFiles = JSON.parse(strData);

                if (cmd[2]) {
                  newFiles = _.filter(getPullRequestFiles(id), function (file) {
                    return matchFilePath(cmd[2], file.filename);
                  });
                }

                reviewerFiles[cmd[1]] = _.union(reviewerFiles[cmd[1]] || [], newFiles);
                saveData(id + ':waiting_review_from', JSON.stringify(reviewerFiles));
                if (_.keys(reviewerFiles).length > 0) {
                  var prDetails = getPullRequestDetails(id);
                  createStatus(
                    prDetails.head.sha,
                    'pending',
                    prDetails.url,
                    'Pull request review: ' + _.keys(reviewerFiles).join(', '),
                    'pr_review'
                  );
                }
              } catch(e) {}
            }
          }
        break;
        /*
        case 'remove':
          if (cmd[1]) {
            var strData = loadData(id + ':waiting_review_from');
            if (strData) {
              try {
                var reviewerFiles = JSON.parse(strData);
                delete reviewerFiles[cmd[1]];
                saveData(id + ':waiting_review_from', JSON.stringify(reviewerFiles));
              } catch(e) {}
            }
          }
        break;
        */
        case 'change':
          if (cmd[1] && cmd[2]) {
            var strData = loadData(id + ':waiting_review_from');
            if (strData) {
              try {
                var reviewerFiles = JSON.parse(strData);

                if (reviewerFiles[cmd[1]]) {
                  reviewerFiles[cmd[2]] = _.union(reviewerFiles[cmd[2]] || [], reviewerFiles[cmd[1]]);
                  delete reviewerFiles[cmd[1]];
                  saveData(id + ':waiting_review_from', JSON.stringify(reviewerFiles));
                }
              } catch(e) {}
            }
          }
        break;
        case 'reopen':
        var fakeEvent = {number: id, pull_request: getPullRequestDetails(id)};
        pullRequestOpened(fakeEvent);
        break;
        case 'status':
          var strData = loadData(id + ':waiting_review_from');
          if (strData) {
            try {
              var reviewerFiles = JSON.parse(strData);
              var message = 'Waiting review from\n\n';
              _.each(reviewerFiles, function (files, reviewer) {
                message += '@' + reviewer + '\n';
                _.each(files, function (file) {
                  message += '- ' + file + '\n';
                });
                message += '\n';
              });

              createIssueComment(id, message);

              if (_.keys(reviewerFiles).length === 0) {
                var prDetails = getPullRequestDetails(id);
                createStatus(prDetails.head.sha, 'success', prDetails.url, 'Pull request review', 'pr_review');
                createIssueComment(id, "Review completed!");
              } else {
                createStatus(
                  prDetails.head.sha,
                  'pending',
                  prDetails.url,
                  'Pull request review: ' + _.keys(reviewerFiles).join(', '),
                  'pr_review'
                );
              }

            } catch(e) {}
          }
        break;
      }
    }
  });
}

// Process hook data
if (eventType === 'pull_request' && eventData.action === 'opened') {
  pullRequestOpened(eventData);
} else if (eventType === 'issue_comment' && eventData.action === 'created' && eventData.issue.pull_request) {
  pullRequestComment(eventData);
} else if (eventType === 'pull_request' && eventData.action === 'synchronize') {
  pullRequestUpdated(eventData);
}
<commit_msg>Fix typo<commit_after>function getReviewersForFile(files, pullRequestUser, preferredReviewers) {
  var reviewerFiles = {};
  var fileReviewers = {};

  _.each(preferredReviewers, function (files, reviewer) {
    _.each(files, function (file) {
      fileReviewers[file] = fileReviewers[file] || [];
      fileReviewers[file].push(reviewer);
    });
  });

  _.each(files, function (file) {
    var reviewers = preferredReviewers[file.filename] || [];

    if (reviewers.length === 0) {
      var pattern = _.find(config.patterns, function (fileConf) {
        var patterns = fileConf.pattern;
        var usernames = fileConf.reviewers;

        var match = _.find(patterns.split(','), function (pattern) {
          //console.log(pattern, file.filename);
          return matchFilePath(pattern, file.filename);
        });

        // Reviewer for file cant be the same as the pull request sender
        if (match && (usernames.indexOf(pullRequestUser) === -1 || usernames.length > 1)) {
          return _.without(usernames, pullRequestUser);
        }
      });

      if (!pattern) {
        return;
      }

      reviewers = pattern.reviewers;

      var alreadyReviewing = _.intersection(
        reviewers,
        _.keys(reviewerFiles)
      );

      if (alreadyReviewing.length > 0) {
        reviewers = alreadyReviewing;
      }
    }

    var randomReviewer = reviewers[Math.floor(Math.random() * reviewers.length)];

    reviewerFiles[randomReviewer] = reviewerFiles[randomReviewer] || [];
    reviewerFiles[randomReviewer].push(file.filename);
  }, this);

  return reviewerFiles;
}

function getFileShaMap(files) {
  var fileShaMap = {};
  _.each(files, function (file) {
    fileShaMap[file.filename] = file.sha;
  });
  return fileShaMap;
}

function pullRequestOpened(eventData) {
  var pullRequestUser = eventData.pull_request.user.login;

  var files = getPullRequestFiles(eventData.number);
  var reviewerFiles = getReviewersForFile(files, pullRequestUser, {});
  var fileShaMap = getFileShaMap(files);

  if (_.keys(reviewerFiles).length > 0) {
    var message = 'Awesome work! Now just sit back and wait for Travis to pass and others to review your code.\n\n';
    message += '## Reviewers\n';

    _.each(reviewerFiles, function (files, reviewer) {
      message += '@' + reviewer + '\n';
      _.each(files, function (file) {
        message += '- ' + file + '\n';
      });
      message += '\n';
    });

    message += '\n### Review commands\n';
    message += '- accept: `pr_review OK`\n';
    message += '- add reviewer: `pr_review add [username]`\n';
    message += '- change reviewer: `pr_review change [old_username] [new_username]`\n';
    message += '- print status: `pr_review status`\n';

    createIssueComment(eventData.number, message);
    createStatus(
      eventData.pull_request.head.sha,
      'pending',
      eventData.pull_request.url,
      'Pull request review: ' + _.keys(reviewerFiles).join(', '),
      'pr_review'
    );
    saveData(eventData.number + ':waiting_review_from', JSON.stringify(reviewerFiles));
  }

  saveData(eventData.number + ':files', JSON.stringify(fileShaMap));
}

function pullRequestUpdated(eventData) {
  var pullRequestUser = eventData.pull_request.user.login;
  var files = getPullRequestFiles(eventData.number);
  var fileShaMapStr = loadData(eventData.number + ':files');
  var oldReviewersStr = loadData(eventData.number + ':waiting_review_from');
  var fileShaMap = {};
  var oldReviewers = {};

  try {
    fileShaMap = JSON.parse(fileShaMapStr);
  } catch(e) {}

  try {
    oldReviewers = JSON.parse(oldReviewersStr);
  } catch(e) {}

  files = _.filter(files, function (file) {
    if (fileShaMap[file.filename] !== file.sha) {
      fileShaMap[file.filename] = file.sha;
      return true;
    }
  });

  var reviewerFiles = getReviewersForFile(files, pullRequestUser, oldReviewers);

  if (_.keys(reviewerFiles).length > 0) {
    var message = 'Some of the files were updated.\n\n';
    message += '## Reviewers\n';
    _.each(reviewerFiles, function (files, reviewer) {
      message += '@' + reviewer + '\n';
      _.each(files, function (file) {
        message += '- ' + file + '\n';
      });
      message += '\n';
    });

    // Merge olds files back
    _.each(oldReviewers, function (files, reviewer) {
      reviewerFiles[reviewer] = reviewerFiles[reviewer] ? _.union(files, reviewerFiles[reviewer]) : files;
    });

    createIssueComment(eventData.number, message);

    createStatus(
      eventData.pull_request.head.sha,
      'pending',
      eventData.pull_request.url,
      'Pull request review: ' + _.keys(reviewerFiles).join(', '),
      'pr_review'
    );
    saveData(eventData.number + ':waiting_review_from', JSON.stringify(reviewerFiles));
  }

  saveData(eventData.number + ':files', JSON.stringify(fileShaMap));
}

function pullRequestComment(eventData) {
  var id = eventData.issue.number;
  var senderName = eventData.sender.login;
  var body = eventData.comment.body.trim();
  var cmd;

  _.each(body.split('\n'), function (message) {
    if (message.indexOf('pr_review') === 0) {
      cmd = _.filter(
        _.map(message.substring(10).split(' '), function (part) { return part.trim(); }),
        function (cmd) {
          return !!cmd;
        }
      );

      console.log('cdm ' + cmd.join(' '));

      switch(cmd[0].toLowerCase()) {
        case 'ok':
          var strData = loadData(id + ':waiting_review_from');
          if (strData) {
            try {
              var reviewerFiles = JSON.parse(strData);
              delete reviewerFiles[senderName];
              saveData(id + ':waiting_review_from', JSON.stringify(reviewerFiles));

              var prDetails = getPullRequestDetails(id);
              if (_.keys(reviewerFiles).length === 0) {
                createStatus(prDetails.head.sha, 'success', prDetails.url, 'Pull request review', 'pr_review');
                createIssueComment(id, "Review completed!");
              } else {
                createStatus(
                  prDetails.head.sha,
                  'pending',
                  prDetails.url,
                  'Pull request review: ' + _.keys(reviewerFiles).join(', '),
                  'pr_review'
                );
              }

            } catch(e) {}
          }
        break;
        case 'add':
          if (cmd[1]) {
            var newFiles = [];
            var strData = loadData(id + ':waiting_review_from');
            if (strData) {
              try {
                var reviewerFiles = JSON.parse(strData);

                if (cmd[2]) {
                  newFiles = _.filter(getPullRequestFiles(id), function (file) {
                    return matchFilePath(cmd[2], file.filename);
                  });
                }

                reviewerFiles[cmd[1]] = _.union(reviewerFiles[cmd[1]] || [], newFiles);
                saveData(id + ':waiting_review_from', JSON.stringify(reviewerFiles));
                if (_.keys(reviewerFiles).length > 0) {
                  var prDetails = getPullRequestDetails(id);
                  createStatus(
                    prDetails.head.sha,
                    'pending',
                    prDetails.url,
                    'Pull request review: ' + _.keys(reviewerFiles).join(', '),
                    'pr_review'
                  );
                }
              } catch(e) {}
            }
          }
        break;
        /*
        case 'remove':
          if (cmd[1]) {
            var strData = loadData(id + ':waiting_review_from');
            if (strData) {
              try {
                var reviewerFiles = JSON.parse(strData);
                delete reviewerFiles[cmd[1]];
                saveData(id + ':waiting_review_from', JSON.stringify(reviewerFiles));
              } catch(e) {}
            }
          }
        break;
        */
        case 'change':
          if (cmd[1] && cmd[2]) {
            var strData = loadData(id + ':waiting_review_from');
            if (strData) {
              try {
                var reviewerFiles = JSON.parse(strData);

                if (reviewerFiles[cmd[1]]) {
                  reviewerFiles[cmd[2]] = _.union(reviewerFiles[cmd[2]] || [], reviewerFiles[cmd[1]]);
                  delete reviewerFiles[cmd[1]];
                  saveData(id + ':waiting_review_from', JSON.stringify(reviewerFiles));
                }
              } catch(e) {}
            }
          }
        break;
        case 'reopen':
        var fakeEvent = {number: id, pull_request: getPullRequestDetails(id)};
        pullRequestOpened(fakeEvent);
        break;
        case 'status':
          var strData = loadData(id + ':waiting_review_from');
          if (strData) {
            try {
              var reviewerFiles = JSON.parse(strData);
              var message = 'Waiting review from\n\n';
              _.each(reviewerFiles, function (files, reviewer) {
                message += '@' + reviewer + '\n';
                _.each(files, function (file) {
                  message += '- ' + file + '\n';
                });
                message += '\n';
              });

              createIssueComment(id, message);

              if (_.keys(reviewerFiles).length === 0) {
                var prDetails = getPullRequestDetails(id);
                createStatus(prDetails.head.sha, 'success', prDetails.url, 'Pull request review', 'pr_review');
                createIssueComment(id, "Review completed!");
              } else {
                createStatus(
                  prDetails.head.sha,
                  'pending',
                  prDetails.url,
                  'Pull request review: ' + _.keys(reviewerFiles).join(', '),
                  'pr_review'
                );
              }

            } catch(e) {}
          }
        break;
      }
    }
  });
}

// Process hook data
if (eventType === 'pull_request' && eventData.action === 'opened') {
  pullRequestOpened(eventData);
} else if (eventType === 'issue_comment' && eventData.action === 'created' && eventData.issue.pull_request) {
  pullRequestComment(eventData);
} else if (eventType === 'pull_request' && eventData.action === 'synchronize') {
  pullRequestUpdated(eventData);
}
<|endoftext|>


<commit_before>$(document).ready(function($) {
    $("#content .contextual").prepend("New");
});
<commit_msg>Add some fugly javascript to pre-fill parent wiki page.<commit_after>$(document).ready(function($) {
    var newLink = $("New");
    $("#content .contextual").prepend(newLink);
    $(newLink).click(function() {
        var parent = $(this).parent();
        var form = $("<form></form>");
        form.append("<input type=\"text\">");
        $(form).submit(function(e) {
            e.preventDefault();
            var name = $($(form).children()[0]).val();
            var splitPath = window.location.pathname.split("/", 5);
            var wikiPath = "/" + splitPath[1] + "/" + splitPath[2] + "/"
                    + splitPath[3];
            var parentName = splitPath[4];
            var newPathname = "/" + name + "?parent=" + parentName;
            window.location.assign(wikiPath + newPathname);
            return false;
        });

        $(this).replaceWith(form);
        form.children("input").focus();
        return false;
    });
});
<|endoftext|>


<commit_before>// general css, css-only components, third-party libraries
import './css/app.sass'

// general polifils
import 'whatwg-fetch'
import 'promise-polyfill/dist/polyfill'
import 'core-js/stable'
import 'regenerator-runtime/runtime'
<commit_msg>core-js<commit_after>// general css, css-only components, third-party libraries
import './css/app.sass'

// general polifils
import 'core-js/stable'
import 'regenerator-runtime/runtime'

import 'whatwg-fetch'
import 'promise-polyfill/dist/polyfill'
<|endoftext|>


<commit_before>/* global jasmineImporter */
/* exported Jasmine */

const {Gio, GLib} = imports.gi;
const Lang = imports.lang;

var Jasmine = class Jasmine {
    constructor({jasmineCore} = {jasmineCore: jasmineImporter.jasmine}) {
        const jasmineCorePath = jasmineCore.__file__;
        this._jasmineCoreFile = Gio.File.new_for_path(jasmineCorePath);

        const jasmineRequire = jasmineCore.getJasmineRequireObj();
        this._jasmine = jasmineRequire.core(jasmineRequire);
        this.env = this._jasmine.getEnv();
        this._jasmineInterface = jasmineRequire.interface(this._jasmine, this.env);

        this.exclusions = [];
        this.specFiles = [];
        this._reportersCount = 0;
    }

    get version() {
        return this._jasmine.version;
    }

    addReporter(reporter) {
        reporter.jasmine_core_path = this._jasmineCoreFile.get_parent().get_path();
        this.env.addReporter(reporter);
        this._reportersCount++;
    }

    _addSpecFile(file) {
        const absolutePath = file.get_path();
        const shouldSkip = this.exclusions.some(pattern => {
            // Match globs against the absolute path
            if (GLib.pattern_match_simple(pattern, absolutePath))
                return true;
            // Also match if the string matches at the end
            if (GLib.pattern_match_simple(`*/${pattern}`, absolutePath))
                return true;
            // Also match if the string matches the path at the end
            return GLib.pattern_match_simple(`*/${pattern}`,
                file.get_parent().get_path());
        });
        if (shouldSkip)
            return;
        if (this.specFiles.indexOf(absolutePath) === -1)
            this.specFiles.push(absolutePath);
    }

    addSpecFiles(filePaths) {
        filePaths.forEach(filePath => {
            const file = Gio.File.new_for_path(filePath);
            const type = file.query_file_type(Gio.FileQueryInfoFlags.NONE, null);

            switch (type) {
            case Gio.FileType.REGULAR:
                this._addSpecFile(file);
                break;
            case Gio.FileType.DIRECTORY:
                recurseDirectory(file, this._addSpecFile.bind(this));
                break;
            default:
                // ignore
            }
        });
    }

    loadSpecs() {
        const oldSearchPath = imports.searchPath.slice();  // make a copy
        this.specFiles.forEach(function (file) {
            const modulePath = GLib.path_get_dirname(file);
            const moduleName = GLib.path_get_basename(file).slice(0, -3);  // .js
            imports.searchPath.unshift(modulePath);
            void imports[moduleName];
            imports.searchPath = oldSearchPath;
        });
    }

    execute(files) {
        if (files && files.length > 0)
            this.addSpecFiles(files);

        this.loadSpecs();
        this.env.execute();
    }

    // Install Jasmine API on the global object
    installAPI(global) {
        Lang.copyProperties(this._jasmineInterface, global);
    }
};

function recurseDirectory(directory, func) {
    const enumerator = directory.enumerate_children('standard::*',
        Gio.FileQueryInfoFlags.NONE, null);

    let info;
    while ((info = enumerator.next_file(null))) {
        // COMPAT: use the following on GLib >= 2.36:
        // let file = enumerator.get_child(info);
        // let filename = file.get_basename();
        const filename = info.get_name();
        const file = enumerator.get_container().get_child(filename);

        if (info.get_file_type() === Gio.FileType.DIRECTORY)
            recurseDirectory(file, func);
        else if (filename.endsWith('.js'))
            func(file);
    }
}
<commit_msg>Remove last usage of imports.lang<commit_after>/* global jasmineImporter */
/* exported Jasmine */

const {Gio, GLib} = imports.gi;

var Jasmine = class Jasmine {
    constructor({jasmineCore} = {jasmineCore: jasmineImporter.jasmine}) {
        const jasmineCorePath = jasmineCore.__file__;
        this._jasmineCoreFile = Gio.File.new_for_path(jasmineCorePath);

        const jasmineRequire = jasmineCore.getJasmineRequireObj();
        this._jasmine = jasmineRequire.core(jasmineRequire);
        this.env = this._jasmine.getEnv();
        this._jasmineInterface = jasmineRequire.interface(this._jasmine, this.env);

        this.exclusions = [];
        this.specFiles = [];
        this._reportersCount = 0;
    }

    get version() {
        return this._jasmine.version;
    }

    addReporter(reporter) {
        reporter.jasmine_core_path = this._jasmineCoreFile.get_parent().get_path();
        this.env.addReporter(reporter);
        this._reportersCount++;
    }

    _addSpecFile(file) {
        const absolutePath = file.get_path();
        const shouldSkip = this.exclusions.some(pattern => {
            // Match globs against the absolute path
            if (GLib.pattern_match_simple(pattern, absolutePath))
                return true;
            // Also match if the string matches at the end
            if (GLib.pattern_match_simple(`*/${pattern}`, absolutePath))
                return true;
            // Also match if the string matches the path at the end
            return GLib.pattern_match_simple(`*/${pattern}`,
                file.get_parent().get_path());
        });
        if (shouldSkip)
            return;
        if (this.specFiles.indexOf(absolutePath) === -1)
            this.specFiles.push(absolutePath);
    }

    addSpecFiles(filePaths) {
        filePaths.forEach(filePath => {
            const file = Gio.File.new_for_path(filePath);
            const type = file.query_file_type(Gio.FileQueryInfoFlags.NONE, null);

            switch (type) {
            case Gio.FileType.REGULAR:
                this._addSpecFile(file);
                break;
            case Gio.FileType.DIRECTORY:
                recurseDirectory(file, this._addSpecFile.bind(this));
                break;
            default:
                // ignore
            }
        });
    }

    loadSpecs() {
        const oldSearchPath = imports.searchPath.slice();  // make a copy
        this.specFiles.forEach(function (file) {
            const modulePath = GLib.path_get_dirname(file);
            const moduleName = GLib.path_get_basename(file).slice(0, -3);  // .js
            imports.searchPath.unshift(modulePath);
            void imports[moduleName];
            imports.searchPath = oldSearchPath;
        });
    }

    execute(files) {
        if (files && files.length > 0)
            this.addSpecFiles(files);

        this.loadSpecs();
        this.env.execute();
    }

    // Install Jasmine API on the global object
    installAPI(global) {
        Object.assign(global, this._jasmineInterface);
    }
};

function recurseDirectory(directory, func) {
    const enumerator = directory.enumerate_children('standard::*',
        Gio.FileQueryInfoFlags.NONE, null);

    let info;
    while ((info = enumerator.next_file(null))) {
        // COMPAT: use the following on GLib >= 2.36:
        // let file = enumerator.get_child(info);
        // let filename = file.get_basename();
        const filename = info.get_name();
        const file = enumerator.get_container().get_child(filename);

        if (info.get_file_type() === Gio.FileType.DIRECTORY)
            recurseDirectory(file, func);
        else if (filename.endsWith('.js'))
            func(file);
    }
}
<|endoftext|>


<commit_before>'use strict';

angular.module('emuwebApp')
  .directive('emuhierarchy', function (viewState, LevelService, HierarchyService) {
    return {
      template: '

',
      restrict: 'E',
      scope: {
      	path: '=', // This directive actually never writes back to path
	vertical: '='
      },
      replace: true,
      link: function postLink(scope, element, attrs) {

        //////////////////////
        // watches

	scope.$watch('path', function (newValue) {
		console.debug('Rendering due to path change: ', newValue);
		scope.render();
	}, false);

	scope.$watch('vertical', function (newValue) {
		console.debug('Rendering due to rotation: ', newValue);
		scope.render();
	}, false);

	scope.$watch('viewState.curLevelAttrDefs', function (newValue) {
		console.debug('Rendering due to attribute change: ', newValue);
		scope.render();
	}, true);

	/*
        // SIC deep watches are really expensive!!!! Should watch something else!!!!!!
        // With the advent of the $watch('path') above, this should have become obsolete
	scope.$watch('LevelService.data', function () {
          scope.render();
        }, true);
	*/

        //
        //////////////////////

	//////////////////////
	// helper functions

	/**
	 * Function to center node when clicked/dropped so node doesn't get lost when
	 * collapsing/moving with large amount of children.
	 */
	scope.centerNode = function (node) {
		var x = -node._x + width/2;
		var y = -node._y  + height/2;
		svg.transition()
			.duration(duration)
			.attr("transform", scope.getOrientatedTransform()+"translate(" + x + "," + y + ")");
		zoomListener.translate([x, y]);
	};

	/**
	 * The zoom function is called by the zoom listener, which listens for d3 zoom events and must be appended to the svg element
	 */
	scope.zoom = function () {
			svg.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")"+scope.getOrientatedTransform());
	};

	scope.getOrientatedTransform = function () {
		var transform = 'scale('+zoomListener.scale()+')';
		transform += 'translate('+zoomListener.translate()+')';
		if (scope.vertical) {
			transform += 'scale(-1,1),rotate(90)';
		} else {
			transform += 'rotate(0)';
		}
		return transform;
	};

	scope.getOrientatedNodeTransform = function (d) {
		if (scope.vertical) {
			return 'scale(-1,1)rotate(90)';
		} else {
			return 'scale(1,1)rotate(0)';
		}
	};

	scope.getNodeText = function (d) {
		var level = viewState.getCurAttrDef(HierarchyService.getLevelName(d.id));
		for (var i=0; i<d.labels.length; ++i) {
			if (d.labels[i].name === level) {
				return d.labels[i].value;
			}
		}
		console.debug ("Likely a bug: Did not find the label selected for display", "Selected level:", level, "Node: ", d);
		return "NO VALUE";
	};

	scope.getOrientatedTextAnchor = function (d) {
		if (scope.vertical) {
			return 'middle';
		} else {
			return 'begin';
		}
	};

	scope.getOrientatedTextX = function (d) {
		if (scope.vertical) {
			return 0;
		} else {
			return 10;
		}
	};

	scope.getOrientatedTextY = function (d) {
		if (scope.vertical) {
			return '1.45em';
		} else {
			return '0.35em';
		}
	};

	scope.getPath = function (d) {
		var controlX = d._fromX;
		var controlY = d._toY;

		return "M"+d._fromX+" "+d._fromY+"Q"+controlX+" "+controlY+" "+d._toX+" "+d._toY;
	};

	//
	/////////////////////////////

        /////////////////////////////
        // inital d3.js setup stuff

        var margin = {
            top: 0,
            right: 0,
            bottom: 0,
            left: 0
          },
          width = parseInt(d3.select(element[0]).style('width'), 10),
          width = width - margin.left - margin.right,
          height = parseInt(d3.select(element[0]).style('height'), 10),
          height = height - margin.top - margin.bottom,
          barHeight = 20,
          percent = d3.format('%'),
	  duration = 750;

	// scaleExtent limits the amount of zooming possible
	var zoomListener = d3.behavior.zoom().scaleExtent([0.5, 10]).on("zoom", scope.zoom);

        // Create the d3 element and position it based on margins
        var svg = d3.select(element[0])
          .append('svg')
          .attr('width', '100%')
          .attr('height', '100%')
	  .style('background-color', 'darkgrey')
	  .call(zoomListener)
          .append('g')
          .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')')
	  // Append a group which holds all nodes and which the zoom Listener can act upon.
	  .append('g');

	//
        /////////////////////////////

        /**
         *
         */
        scope.render = function () {
		// Set orientation
		svg.transition()
		  .duration(duration)
		  .attr('transform', scope.getOrientatedTransform());

		/////
		// Compute the new tree layout (first nodes and then links)
		//
		var nodes = [];

		// At the moment I have two different approaches to calculating the layout of a hierarchy
		//
		// The first is simpler and is used by first calling layoutNonItemLevel() for the bottom-most level (the one with time information)
		// and then calling layoutItemLevel() for all other levels. Unfortunately, it will in some cases render multiple nodes to the same
		// position (happens when they share the same set of children).
		//
		// The second one looks simpler in this file, because it is completely done in one function. But that function is actually quite
		// complex.
		//
		// It might be desirable to find some sort of collision detection for the first approach (which is commented out below)
		//

		/////
		// This is the aforementioned second approach
		HierarchyService.calculateWeightsBottomUp();
		//
		/////

		for (var i=0; i<HierarchyService.selectedPath.length; ++i) {

			/////
			// This is the aformentioned first approach
			/*
			if (i === 0) {
				HierarchyService.layoutNonItemLevel(HierarchyService.selectedPath[0], HierarchyService.selectedPath.length);
			} else {
				HierarchyService.layoutItemLevel(HierarchyService.selectedPath[i], HierarchyService.selectedPath.length-i);
			}
			*/
			//////

			nodes = nodes.concat(LevelService.getLevelDetails(HierarchyService.selectedPath[i]).level.items);
		}

		// Now layout links

		// We must only draw links that are part of the currently selected path.
		// We must therefore filter the links.
		//
		// What follows below is a very low-performance approach to filtering
		var links = [];
		var allLinks = LevelService.getData().links;
		for (var l=0; l<allLinks.length; ++l) {
			for (var i=0; i<HierarchyService.selectedPath.length-1; ++i) {
				var element = LevelService.getElementDetailsById(HierarchyService.selectedPath[i], allLinks[l].toID);
				if (element === null) {
					continue;
				}
				var parentElement = LevelService.getElementDetailsById(HierarchyService.selectedPath[i+1], allLinks[l].fromID);
				if (parentElement !== null) {
					links.push(allLinks[l]);
				}
			}
		}

		// Transform relative coordinates (_posInLevel and _depth) to actual coordinates (_x and _y)

		var offsetX = 25;

		var depthToX = function (depth) {
			var size = (scope.vertical) ? height : width;
			return offsetX + depth / scope.path.length * size;
		};

		var posInLevelToY = function (posInLevel) {
			var size = (scope.vertical) ? width : height;
			return posInLevel * size;
		};

		nodes.forEach(function (d) {
			d._x = depthToX(d._depth);
			d._y = posInLevelToY(d._posInLevel);
		});
		links.forEach(function (d) {
			d._fromX = depthToX(d._fromDepth);
			d._fromY = posInLevelToY(d._fromPosInLevel);
			d._toX = depthToX(d._toDepth);
			d._toY = posInLevelToY(d._toPosInLevel);
		});

		//////
		// Now that all actual coordinates have been calculated, we
		// update our SVG using d3js data joins
		//
		// For an introduction to the concept see
		// http://bost.ocks.org/mike/join/
		//

		//
		// Define the data set to be visualised

		var dataSet = svg.selectAll("g.node")
			.data(nodes, function (d) {
				return d.id;
			});

		var newNodes = dataSet.enter();
		var oldNodes = dataSet.exit();

		//
		// Add nodes that were previously not part of the svg.
		//
		// Any node will consist of an svg group ("g"), a circle, a
		// text and a second, invisible circle for mouseover handling.
		//
		// Note that properties that can be changed after the node is
		// added will be set further below

		newNodes = newNodes.append("g")		// append() will return a set of all appended elements
			.attr("class", "node")

			// event handlers
			//.call(dragListener)
			.on('click', function (d) {
				console.debug('Clicked node', d);
				scope.centerNode(d);
			})
			;

		newNodes.append("circle")
			.attr('class', 'nodeCircle')

			// Make circle invisible at first
			.attr('r', 0)

			// And then transition it to its normal size
			.transition()
			.duration(duration)
			.attr('r', 4.5)
			;

		newNodes.append("text")
			.attr('class', 'nodeText')
			;

		/*

		// phantom node to give us mouseover in a radius around it
		newNodes.append("circle")
			.attr('class', 'ghostCircle')
			.attr('r', 30)
			.attr('opacity', 0.2) // change this to zero to hide the target area
			.style('fill', 'red')
			.attr('pointer-events', 'mouseover')
			.on('mouseover', function (node) {
				console.debug(node);
				overCircle(node);
			})
			.on('mouseout', function (node) {
				outCircle(node);
			});

		*/

		//
		// Remove nodes that shall no longer be part of the svg

		// Transition exiting nodes to the origin
		oldNodes = oldNodes.transition()
			.duration(duration)
			.attr("transform", function (d) {
				return "translate(" + 0 + "," + 0 + ")";
			})
			.remove();

		oldNodes.select("text")
			.style("fill-opacity", 0);

		//
		// Set or update properties that are subject to change after
		// the node is added.

		dataSet.select('text')
			.attr ('x', scope.getOrientatedTextX )
			.attr ('y', scope.getOrientatedTextY )
			.attr('text-anchor', scope.getOrientatedTextAnchor )
			.attr('transform', scope.getOrientatedTextTransform )
			.text( scope.getNodeText )
			;

		// Change the circle fill depending on whether it has children and is collapsed
		dataSet.select("circle.nodeCircle")
			//.attr("r", 4.5)
			//.style("fill", function (d) {
			//	return d._children ? "lightsteelblue" : "#fff";
			//})
			;

		// Transition nodes to their new position.
		dataSet.transition()
			.duration(duration)
			.attr("transform", function (d) {
				return "translate(" + d._x + "," + d._y + ")"+scope.getOrientatedNodeTransform(d);
			});

		//
		//
		// Now we turn to visualising links
		var linkSet = svg.selectAll("path.link")
			.data(links, function (d) {
				// Form unique link ID
				return 's' + d.fromID + 't' + d.toID;
			});

		var newLinks = linkSet.enter();
		var oldLinks = linkSet.exit();

		newLinks.insert('path', 'g')
			.attr('class', 'link')
			.style('opacity', 0)
			.transition()
			.duration(duration)
			.style('opacity', 1)
			;

		oldLinks.transition()
			.duration(duration)
			.style('opacity', 0)
			.remove();

		// Transition links to their new position.
		linkSet.transition()
			.duration(duration)
			.attr("d", scope.getPath )
			.style('opacity', 1)
			;

		// Stash the old positions for transition.
		nodes.forEach(function (d) {
			d._x0 = d._x;
			d._y0 = d._y;
		});

	};

        /**
         * SIC... not being called
         */
        scope.resizeHierarchy = function () {
          console.log('###############')
          console.log(width)
        };
      }
    };
  });
<commit_msg>Adapted to function rename from fd27f0a7c79f71ae9a986b664a01799c95af595d<commit_after>'use strict';

angular.module('emuwebApp')
  .directive('emuhierarchy', function (viewState, LevelService, HierarchyService) {
    return {
      template: '

',
      restrict: 'E',
      scope: {
      	path: '=', // This directive actually never writes back to path
	vertical: '='
      },
      replace: true,
      link: function postLink(scope, element, attrs) {

        //////////////////////
        // watches

	scope.$watch('path', function (newValue) {
		console.debug('Rendering due to path change: ', newValue);
		scope.render();
	}, false);

	scope.$watch('vertical', function (newValue) {
		console.debug('Rendering due to rotation: ', newValue);
		scope.render();
	}, false);

	scope.$watch('viewState.curLevelAttrDefs', function (newValue) {
		console.debug('Rendering due to attribute change: ', newValue);
		scope.render();
	}, true);

	/*
        // SIC deep watches are really expensive!!!! Should watch something else!!!!!!
        // With the advent of the $watch('path') above, this should have become obsolete
	scope.$watch('LevelService.data', function () {
          scope.render();
        }, true);
	*/

        //
        //////////////////////

	//////////////////////
	// helper functions

	/**
	 * Function to center node when clicked/dropped so node doesn't get lost when
	 * collapsing/moving with large amount of children.
	 */
	scope.centerNode = function (node) {
		var x = -node._x + width/2;
		var y = -node._y  + height/2;
		svg.transition()
			.duration(duration)
			.attr("transform", scope.getOrientatedTransform()+"translate(" + x + "," + y + ")");
		zoomListener.translate([x, y]);
	};

	/**
	 * The zoom function is called by the zoom listener, which listens for d3 zoom events and must be appended to the svg element
	 */
	scope.zoom = function () {
			svg.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")"+scope.getOrientatedTransform());
	};

	scope.getOrientatedTransform = function () {
		var transform = 'scale('+zoomListener.scale()+')';
		transform += 'translate('+zoomListener.translate()+')';
		if (scope.vertical) {
			transform += 'scale(-1,1),rotate(90)';
		} else {
			transform += 'rotate(0)';
		}
		return transform;
	};

	scope.getOrientatedNodeTransform = function (d) {
		if (scope.vertical) {
			return 'scale(-1,1)rotate(90)';
		} else {
			return 'scale(1,1)rotate(0)';
		}
	};

	scope.getNodeText = function (d) {
		var level = viewState.getCurAttrDef(HierarchyService.getLevelName(d.id));
		for (var i=0; i<d.labels.length; ++i) {
			if (d.labels[i].name === level) {
				return d.labels[i].value;
			}
		}
		console.debug ("Likely a bug: Did not find the label selected for display", "Selected level:", level, "Node: ", d);
		return "NO VALUE";
	};

	scope.getOrientatedTextAnchor = function (d) {
		if (scope.vertical) {
			return 'middle';
		} else {
			return 'begin';
		}
	};

	scope.getOrientatedTextX = function (d) {
		if (scope.vertical) {
			return 0;
		} else {
			return 10;
		}
	};

	scope.getOrientatedTextY = function (d) {
		if (scope.vertical) {
			return '1.45em';
		} else {
			return '0.35em';
		}
	};

	scope.getPath = function (d) {
		var controlX = d._fromX;
		var controlY = d._toY;

		return "M"+d._fromX+" "+d._fromY+"Q"+controlX+" "+controlY+" "+d._toX+" "+d._toY;
	};

	//
	/////////////////////////////

        /////////////////////////////
        // inital d3.js setup stuff

        var margin = {
            top: 0,
            right: 0,
            bottom: 0,
            left: 0
          },
          width = parseInt(d3.select(element[0]).style('width'), 10),
          width = width - margin.left - margin.right,
          height = parseInt(d3.select(element[0]).style('height'), 10),
          height = height - margin.top - margin.bottom,
          barHeight = 20,
          percent = d3.format('%'),
	  duration = 750;

	// scaleExtent limits the amount of zooming possible
	var zoomListener = d3.behavior.zoom().scaleExtent([0.5, 10]).on("zoom", scope.zoom);

        // Create the d3 element and position it based on margins
        var svg = d3.select(element[0])
          .append('svg')
          .attr('width', '100%')
          .attr('height', '100%')
	  .style('background-color', 'darkgrey')
	  .call(zoomListener)
          .append('g')
          .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')')
	  // Append a group which holds all nodes and which the zoom Listener can act upon.
	  .append('g');

	//
        /////////////////////////////

        /**
         *
         */
        scope.render = function () {
		// Set orientation
		svg.transition()
		  .duration(duration)
		  .attr('transform', scope.getOrientatedTransform());

		/////
		// Compute the new tree layout (first nodes and then links)
		//
		var nodes = [];

		// At the moment I have two different approaches to calculating the layout of a hierarchy
		//
		// The first is simpler and is used by first calling layoutNonItemLevel() for the bottom-most level (the one with time information)
		// and then calling layoutItemLevel() for all other levels. Unfortunately, it will in some cases render multiple nodes to the same
		// position (happens when they share the same set of children).
		//
		// The second one looks simpler in this file, because it is completely done in one function. But that function is actually quite
		// complex.
		//
		// It might be desirable to find some sort of collision detection for the first approach (which is commented out below)
		//

		/////
		// This is the aforementioned second approach
		HierarchyService.calculateWeightsBottomUp();
		//
		/////

		for (var i=0; i<HierarchyService.selectedPath.length; ++i) {

			/////
			// This is the aformentioned first approach
			/*
			if (i === 0) {
				HierarchyService.layoutNonItemLevel(HierarchyService.selectedPath[0], HierarchyService.selectedPath.length);
			} else {
				HierarchyService.layoutItemLevel(HierarchyService.selectedPath[i], HierarchyService.selectedPath.length-i);
			}
			*/
			//////

			nodes = nodes.concat(LevelService.getLevelDetails(HierarchyService.selectedPath[i]).level.items);
		}

		// Now layout links

		// We must only draw links that are part of the currently selected path.
		// We must therefore filter the links.
		//
		// What follows below is a very low-performance approach to filtering
		var links = [];
		var allLinks = LevelService.getData().links;
		for (var l=0; l<allLinks.length; ++l) {
			for (var i=0; i<HierarchyService.selectedPath.length-1; ++i) {
				var element = LevelService.getItemFromLevelById(HierarchyService.selectedPath[i], allLinks[l].toID);
				if (element === null) {
					continue;
				}
				var parentElement = LevelService.getItemFromLevelById(HierarchyService.selectedPath[i+1], allLinks[l].fromID);
				if (parentElement !== null) {
					links.push(allLinks[l]);
				}
			}
		}

		// Transform relative coordinates (_posInLevel and _depth) to actual coordinates (_x and _y)

		var offsetX = 25;

		var depthToX = function (depth) {
			var size = (scope.vertical) ? height : width;
			return offsetX + depth / scope.path.length * size;
		};

		var posInLevelToY = function (posInLevel) {
			var size = (scope.vertical) ? width : height;
			return posInLevel * size;
		};

		nodes.forEach(function (d) {
			d._x = depthToX(d._depth);
			d._y = posInLevelToY(d._posInLevel);
		});
		links.forEach(function (d) {
			d._fromX = depthToX(d._fromDepth);
			d._fromY = posInLevelToY(d._fromPosInLevel);
			d._toX = depthToX(d._toDepth);
			d._toY = posInLevelToY(d._toPosInLevel);
		});

		//////
		// Now that all actual coordinates have been calculated, we
		// update our SVG using d3js data joins
		//
		// For an introduction to the concept see
		// http://bost.ocks.org/mike/join/
		//

		//
		// Define the data set to be visualised

		var dataSet = svg.selectAll("g.node")
			.data(nodes, function (d) {
				return d.id;
			});

		var newNodes = dataSet.enter();
		var oldNodes = dataSet.exit();

		//
		// Add nodes that were previously not part of the svg.
		//
		// Any node will consist of an svg group ("g"), a circle, a
		// text and a second, invisible circle for mouseover handling.
		//
		// Note that properties that can be changed after the node is
		// added will be set further below

		newNodes = newNodes.append("g")		// append() will return a set of all appended elements
			.attr("class", "node")

			// event handlers
			//.call(dragListener)
			.on('click', function (d) {
				console.debug('Clicked node', d);
				scope.centerNode(d);
			})
			;

		newNodes.append("circle")
			.attr('class', 'nodeCircle')

			// Make circle invisible at first
			.attr('r', 0)

			// And then transition it to its normal size
			.transition()
			.duration(duration)
			.attr('r', 4.5)
			;

		newNodes.append("text")
			.attr('class', 'nodeText')
			;

		/*

		// phantom node to give us mouseover in a radius around it
		newNodes.append("circle")
			.attr('class', 'ghostCircle')
			.attr('r', 30)
			.attr('opacity', 0.2) // change this to zero to hide the target area
			.style('fill', 'red')
			.attr('pointer-events', 'mouseover')
			.on('mouseover', function (node) {
				console.debug(node);
				overCircle(node);
			})
			.on('mouseout', function (node) {
				outCircle(node);
			});

		*/

		//
		// Remove nodes that shall no longer be part of the svg

		// Transition exiting nodes to the origin
		oldNodes = oldNodes.transition()
			.duration(duration)
			.attr("transform", function (d) {
				return "translate(" + 0 + "," + 0 + ")";
			})
			.remove();

		oldNodes.select("text")
			.style("fill-opacity", 0);

		//
		// Set or update properties that are subject to change after
		// the node is added.

		dataSet.select('text')
			.attr ('x', scope.getOrientatedTextX )
			.attr ('y', scope.getOrientatedTextY )
			.attr('text-anchor', scope.getOrientatedTextAnchor )
			.attr('transform', scope.getOrientatedTextTransform )
			.text( scope.getNodeText )
			;

		// Change the circle fill depending on whether it has children and is collapsed
		dataSet.select("circle.nodeCircle")
			//.attr("r", 4.5)
			//.style("fill", function (d) {
			//	return d._children ? "lightsteelblue" : "#fff";
			//})
			;

		// Transition nodes to their new position.
		dataSet.transition()
			.duration(duration)
			.attr("transform", function (d) {
				return "translate(" + d._x + "," + d._y + ")"+scope.getOrientatedNodeTransform(d);
			});

		//
		//
		// Now we turn to visualising links
		var linkSet = svg.selectAll("path.link")
			.data(links, function (d) {
				// Form unique link ID
				return 's' + d.fromID + 't' + d.toID;
			});

		var newLinks = linkSet.enter();
		var oldLinks = linkSet.exit();

		newLinks.insert('path', 'g')
			.attr('class', 'link')
			.style('opacity', 0)
			.transition()
			.duration(duration)
			.style('opacity', 1)
			;

		oldLinks.transition()
			.duration(duration)
			.style('opacity', 0)
			.remove();

		// Transition links to their new position.
		linkSet.transition()
			.duration(duration)
			.attr("d", scope.getPath )
			.style('opacity', 1)
			;

		// Stash the old positions for transition.
		nodes.forEach(function (d) {
			d._x0 = d._x;
			d._y0 = d._y;
		});

	};

        /**
         * SIC... not being called
         */
        scope.resizeHierarchy = function () {
          console.log('###############')
          console.log(width)
        };
      }
    };
  });
<|endoftext|>


<commit_before><commit_msg>plugin flash toFlash 에러 수정<commit_after><|endoftext|>


<commit_before>const needle = require("needle");
const cheerio = require("cheerio");
const dd = require("dotaconstants");
const allKeys = require("../../json/keys.json");
const torte = require("../../json/torte.json");
const keys = ["q", "w", "e", "d", "f"];
const fs = require("bluebird").promisifyAll(require("fs"));
const Watcher = require("../../classes/watcher");
const findHero = require("../../util/findHero");
const getBuffer = require("../../util/getBuffer");

var Canvas = require("canvas");
var Image = Canvas.Image;

async function getGuide(url) {
    return new Promise((resolve, reject) => {
        needle.get(url, (err, response, body) => {
            err ? reject(err) : resolve(body);
        });
    });
}

async function parseGuide(id) {
    return new Promise(async function(resolve, reject) {
        let url = `http://www.dota2.com/workshop/builds/view?embedded=workshop&publishedfileid=${id}`;
        let $;
        try {
            let page = await getGuide(url);
            $ = cheerio.load(page);
        } catch (err) {
            reject(err);
        }

        let sections = [];
        $(".itemBuildContainer").children().each((index, element) => {
            if ($(element).text().trim() != "") {
                let section = {
                    "name": $(element).text().trim(),
                    "items": []
                };

                $(element).parent().find(".itemBuildIconContainer").children().each((index, element) => {
                    section.items.push($(element).attr("itemname"));
                });

                if (section.items.length > 0) sections.push(section);
            }
        });

        let abilityBuild = new Array(25).fill("none");
        $("#skillBuildContent").children().each((index, element) => {
            let name = $(element).attr("abilityname");
            $(element).children().each((index, element) => {
                $(element).find(".skillSet").each((index, element) => {
                    abilityBuild[parseInt($(element).text()) - 1] = name;
                });
            });
        });

        let itemSummaries = [];
        $("#itemSummaryContent").children().each((index, element) => {
            itemSummaries.push({
                "item": $(element).find("div.itemImageSummary.itemIconWithTooltip").attr("itemname"),
                "description": $(element).find("div.itemSummaryText").text()
            });
        });

        let abilitySummaries = [];
        $("#abilitySummaryContent").children().each((index, element) => {
            abilitySummaries.push({
                "ability": $(element).find("img").attr("abilityname"),
                "description": $(element).find("div").text()
            });
        });

        resolve([
            sections,
            abilityBuild,
            itemSummaries,
            abilitySummaries
        ]);
    });
}

async function sleep(ms) {
    return new Promise((resolve) => setTimeout(resolve, ms));
}

async function drawBuildImage(grid, images) {
    return new Promise(async function(resolve, reject) {
        try {
            var canvas = new Canvas(1220, grid.length * 64);
            var ctx = canvas.getContext("2d");

            grid.forEach((row, y) => {
                row.forEach((element, x) => {
                    let img = new Image();
                    img.src = images[element.toString()];
                    ctx.drawImage(img, x * 64, y * 64, 64, 64);
                });
            });

            await sleep(250); // kek

            let buff = [];
            canvas.pngStream().on("data", (data) => {
                buff.push(data);
            }).on("end", () => {
                let data = Buffer.concat(buff);
                resolve(data);
            });
        } catch (err) {
            console.log(err);
            reject(err);
        }
    });
}

async function createBuildImage(hero, data) {
    return new Promise(async function(resolve, reject) {
        try {
            let abilities = data.filter((item) => item !== "none" && !item.startsWith("special_bonus")).filter((item, index, array) => array.indexOf(item) === index);
            let promises = abilities.map((a) => getBuffer(`http://cdn.dota2.com/${dd.abilities[a].img}`, `${__dirname}/../../images/abilities/${a}_md.png`));
            let buffers = await Promise.all(promises);

            let images = {};
            for (ability of abilities) {
                images[ability] = buffers[abilities.indexOf(ability)];
            }

            images["false"] = await fs.readFileAsync(`${__dirname}/../../images/grid/false.png`);
            images["true"] = await fs.readFileAsync(`${__dirname}/../../images/grid/true.png`);

            let ordered = new Array(abilities.length);
            abilities.forEach((abil) => {
                let key = allKeys[abil];
                if (keys.includes(key)) ordered[keys.indexOf(key)] = abil;
                if (key == "r") ordered[ordered.length - 1] = abil;
            });

            let grid = [];
            ordered.forEach((abil) => {
                let row = [abil];
                row.push(...data.map((element) => abil == element));
                grid.push(row);
            });

            let image = await drawBuildImage(grid, images);
            resolve(image);
        } catch (err) {
            console.log(err);
            reject(err);
        }
    });
}

async function generateMessage(hero, guide, sections, abilityBuild, itemSummaries, abilitySummaries) {
    return new Promise(async function(resolve, reject) {
        try {
            let buildImage = await createBuildImage(hero, abilityBuild);

            let contents = [{
                "embed": {
                    "title": guide.title,
                    "url": guide.link,
                    "fields": sections.map((section) => {
                        return {
                            "name": section.name,
                            "value": section.items.map((item) => dd.items[item].dname).join(", "),
                            "inline": true
                        };
                    }),
                    "image": {
                        "url": "attachment://test.png"
                    }
                }
            }];

            let items = itemSummaries.map((summ) => {
                return {
                    "name": dd.items[summ.item].dname,
                    "value": summ.description,
                    "inline": true
                };
            });

            let abils = abilitySummaries.map((summ) => {
                let abil = dd.abilities[summ.ability];
                return {
                    "name": abil ? abil.dname : "Special Thanks",
                    "value": summ.description,
                    "inline": true
                };
            });

            let things = [];
            things.push(...items);
            things.push(...abils);

            while (things.length) {
                contents.push({
                    "embed": {
                        "title": guide.title,
                        "url": guide.link,
                        "fields": things.splice(0, 3),
                        "image": {
                            "url": "attachment://test.png"
                        }
                    }
                });
            }

            resolve({
                "contents": contents,
                "file": {
                    "file": buildImage,
                    "name": "test.png"
                }
            });
        } catch (err) {
            reject(err);
        }
    });
}

async function exec(ctx) {
    let hero = findHero(ctx.options.join(" "));
    if (!hero) return ctx.failure(ctx.strings.get("bot_no_hero_error"));

    let guides = torte.filter((guide) => guide.hero == hero.local);
    if (!guides.length) return ctx.failure(ctx.strings.get("guide_no_guides"));

    let guide = guides[Math.floor(Math.random() * guides.length)];
    let backup = `${guide.title} ${guide.link}`;
    let msg;

    try {
        let guideData;
        let key = `listen:guidedata:${guide.id}`;
        let reply = await ctx.client.redis.getAsync(key);
        if (!reply) {
            guideData = await parseGuide(guide.id);
            await ctx.client.redis.setexAsync(key, 604800, JSON.stringify(guideData));
        } else {
            guideData = JSON.parse(reply);
        }

        msg = await generateMessage(hero, guide, ...guideData);
    } catch (err) {
        console.error(err);
        msg = backup;
    }

    try {
        let perms = ctx.guild.members.get(ctx.client.user.id).permission.has("manageMessages");
        let sent = await ctx.send({
            "embed": msg.contents[0].embed,
            "content": perms && "Use ◀ and ▶ to scroll between pages."
        }, msg.file);
        if (perms) ctx.client.watchers[sent.id] = new Watcher(ctx.client, sent, ctx.author.id, "p/n", msg.contents, 0);
        return Promise.resolve();
    } catch (err) {
        return ctx.send(backup);
    }
}

module.exports = {
    name: "guide",
    category: "static",
    typing: true,
    triviaCheat: true,
    exec
};
<commit_msg>remove guide command<commit_after><|endoftext|>


<commit_before>/**
 * Module dependencies
 */

var _ = require('lodash');
var utils = require('./lib/utils');
var hop = utils.object.hasOwnProperty;

/**
 * Build Select statements.
 *
 * Given a Waterline Query Object determine which select statements will be needed.
 */

var SelectBuilder = module.exports = function(schema, currentTable, queryObject, options) {

  this.schema = schema;
  this.currentTable = _.find(_.values(schema), {tableName: currentTable}).identity;
  this.escapeCharacter = '"';
  this.cast = false;

  if(options && hop(options, 'escapeCharacter')) {
    this.escapeCharacter = options.escapeCharacter;
  }

  if(options && hop(options, 'cast')) {
    this.cast = options.cast;
  }

  var queries = [];
  queries.push(this.buildSimpleSelect(queryObject));

  return {
    select: queries
  };
};

/**
 * Build a simple Select statement.
 */

SelectBuilder.prototype.buildSimpleSelect = function buildSimpleSelect(queryObject) {

  var self = this;

  // Check for aggregations
  var aggregations = this.processAggregates(queryObject);
  if(aggregations) {
    return aggregations;
  }

  // Escape table name
  var tableName = utils.escapeName(self.schema[self.currentTable].tableName, self.escapeCharacter);

  var selectKeys = [];
  var query = 'SELECT ';

  var attributes = queryObject.select || Object.keys(this.schema[this.currentTable].attributes);
  delete queryObject.select;

  attributes.forEach(function(key) {
    // Default schema to {} in case a raw DB column name is sent.  This shouldn't happen
    // after https://github.com/balderdashy/waterline/commit/687c869ad54f499018ab0b038d3de4435c96d1dd
    // but leaving here as a failsafe.
    var schema = self.schema[self.currentTable].attributes[key] || {};
    if(hop(schema, 'collection')) return;
    selectKeys.push({ table: self.currentTable, key: schema.columnName || key });
  });

  // Add any hasFK strategy joins to the main query
  _.keys(queryObject.instructions).forEach(function(attr) {

    var strategy = queryObject.instructions[attr].strategy.strategy;
    if(strategy !== 1) return;

    var population = queryObject.instructions[attr].instructions[0];

    // Handle hasFK
    var childAlias = _.find(_.values(self.schema), {tableName: population.child}).identity;
    _.keys(self.schema[childAlias].attributes).forEach(function(key) {
      var schema = self.schema[childAlias].attributes[key];
      if(hop(schema, 'collection')) return;
      selectKeys.push({ table: population.alias ? "__"+population.alias : population.child, key: key, alias: population.alias });
    });
  });

  // Add all the columns to be selected
  selectKeys.forEach(function(select) {

    // If there is an alias, set it in the select (used for hasFK associations)
    if(select.alias) {
      query += utils.escapeName(select.table, self.escapeCharacter) + '.' + utils.escapeName(select.key, self.escapeCharacter) + ' AS ' + self.escapeCharacter + select.alias + '___' + select.key + self.escapeCharacter + ', ';
    }
    else {
      query += utils.escapeName(select.table, self.escapeCharacter) + '.' + utils.escapeName(select.key, self.escapeCharacter) + ', ';
    }

  });

  // Remove the last comma
  query = query.slice(0, -2) + ' FROM ' + tableName + ' AS ' + utils.escapeName(self.currentTable, self.escapeCharacter) + ' ';

  return query;
};

/**
 * Aggregates
 *
 */

SelectBuilder.prototype.processAggregates = function processAggregates(criteria) {

  var self = this;

  if(!criteria.groupBy && !criteria.sum && !criteria.average && !criteria.min && !criteria.max) {
    return false;
  }

  // Error if groupBy is used and no calculations are given
  if(!criteria.sum && !criteria.average && !criteria.min && !criteria.max) {
    throw new Error('An aggregation was used but no calculations were given');
  }

  var query = 'SELECT ';
  var tableName = utils.escapeName(this.currentTable, this.escapeCharacter);

  // Append groupBy columns to select statement
  if(criteria.groupBy) {
    if(criteria.groupBy instanceof Array) {
      criteria.groupBy.forEach(function(opt) {
        query += tableName + '.' + utils.escapeName(opt, self.escapeCharacter) + ', ';
      });

    } else {
      query += tableName + '.' + utils.escapeName(criteria.groupBy, self.escapeCharacter) + ', ';
    }
  }

  // Handle SUM
  if (criteria.sum) {
    var sum = '';
    if(criteria.sum instanceof Array) {
      criteria.sum.forEach(function(opt) {
        sum = 'SUM(' + tableName + '.' + utils.escapeName(opt, self.escapeCharacter) + ')';
        if(self.cast) {
          sum = 'CAST(' + sum + ' AS float)';
        }
        query += sum + ' AS ' + opt + ', ';
      });

    } else {
      sum = 'SUM(' + tableName + '.' + utils.escapeName(criteria.sum, self.escapeCharacter) + ')';
      if(self.cast) {
        sum = 'CAST(' + sum + ' AS float)';
      }
      query += sum + ' AS ' + criteria.sum + ', ';
    }
  }

  // Handle AVG (casting to float to fix percision with trailing zeros)
  if (criteria.average) {
    var avg = '';
    if(criteria.average instanceof Array) {
      criteria.average.forEach(function(opt){
        avg = 'AVG(' + tableName + '.' + utils.escapeName(opt, self.escapeCharacter) + ')';
        if(self.cast) {
          avg = 'CAST( ' + avg + ' AS float)';
        }
        query +=  avg + ' AS ' + opt + ', ';
      });
    } else {
      avg = 'AVG(' + tableName + '.' + utils.escapeName(criteria.average, self.escapeCharacter) + ')';
      if(self.cast) {
        avg = 'CAST( ' + avg + ' AS float)';
      }
      query += avg + ' AS ' + criteria.average + ', ';
    }
  }

  // Handle MAX
  if (criteria.max) {
    var max = '';
    if(criteria.max instanceof Array) {
      criteria.max.forEach(function(opt){
        query += 'MAX(' + tableName + '.' + utils.escapeName(opt, self.escapeCharacter) + ') AS ' + opt + ', ';
      });

    } else {
      query += 'MAX(' + tableName + '.' + utils.escapeName(criteria.max, self.escapeCharacter) + ') AS ' + criteria.max + ', ';
    }
  }

  // Handle MIN
  if (criteria.min) {
    if(criteria.min instanceof Array) {
      criteria.min.forEach(function(opt){
        query += 'MIN(' + tableName + '.' + utils.escapeName(opt, self.escapeCharacter) + ') AS ' + opt + ', ';
      });

    } else {
      query += 'MIN(' + tableName + '.' + utils.escapeName(criteria.min, self.escapeCharacter) + ') AS ' + criteria.min + ', ';
    }
  }

  // trim trailing comma
  query = query.slice(0, -2) + ' ';

  // Add FROM clause
  query += 'FROM ' + utils.escapeName(self.schema[self.currentTable].tableName, self.escapeCharacter) + ' AS ' + tableName + ' ';
  return query;
};
<commit_msg>fix for custom columnNames in selects using the hasFK strategy<commit_after>/**
 * Module dependencies
 */

var _ = require('lodash');
var utils = require('./lib/utils');
var hop = utils.object.hasOwnProperty;

/**
 * Build Select statements.
 *
 * Given a Waterline Query Object determine which select statements will be needed.
 */

var SelectBuilder = module.exports = function(schema, currentTable, queryObject, options) {

  this.schema = schema;
  this.currentTable = _.find(_.values(schema), {tableName: currentTable}).identity;
  this.escapeCharacter = '"';
  this.cast = false;

  if(options && hop(options, 'escapeCharacter')) {
    this.escapeCharacter = options.escapeCharacter;
  }

  if(options && hop(options, 'cast')) {
    this.cast = options.cast;
  }

  var queries = [];
  queries.push(this.buildSimpleSelect(queryObject));

  return {
    select: queries
  };
};

/**
 * Build a simple Select statement.
 */

SelectBuilder.prototype.buildSimpleSelect = function buildSimpleSelect(queryObject) {

  var self = this;

  // Check for aggregations
  var aggregations = this.processAggregates(queryObject);
  if(aggregations) {
    return aggregations;
  }

  // Escape table name
  var tableName = utils.escapeName(self.schema[self.currentTable].tableName, self.escapeCharacter);

  var selectKeys = [];
  var query = 'SELECT ';

  var attributes = queryObject.select || Object.keys(this.schema[this.currentTable].attributes);
  delete queryObject.select;

  attributes.forEach(function(key) {
    // Default schema to {} in case a raw DB column name is sent.  This shouldn't happen
    // after https://github.com/balderdashy/waterline/commit/687c869ad54f499018ab0b038d3de4435c96d1dd
    // but leaving here as a failsafe.
    var schema = self.schema[self.currentTable].attributes[key] || {};
    if(hop(schema, 'collection')) return;
    selectKeys.push({ table: self.currentTable, key: schema.columnName || key });
  });

  // Add any hasFK strategy joins to the main query
  _.keys(queryObject.instructions).forEach(function(attr) {

    var strategy = queryObject.instructions[attr].strategy.strategy;
    if(strategy !== 1) return;

    var population = queryObject.instructions[attr].instructions[0];

    // Handle hasFK
    var childAlias = _.find(_.values(self.schema), {tableName: population.child}).identity;
    _.keys(self.schema[childAlias].attributes).forEach(function(key) {
      var schema = self.schema[childAlias].attributes[key];
      if(hop(schema, 'collection')) return;
      selectKeys.push({ table: population.alias ? "__"+population.alias : population.child, key: schema.columnName || key, alias: population.alias });
    });
  });

  // Add all the columns to be selected
  selectKeys.forEach(function(select) {

    // If there is an alias, set it in the select (used for hasFK associations)
    if(select.alias) {
      query += utils.escapeName(select.table, self.escapeCharacter) + '.' + utils.escapeName(select.key, self.escapeCharacter) + ' AS ' + self.escapeCharacter + select.alias + '___' + select.key + self.escapeCharacter + ', ';
    }
    else {
      query += utils.escapeName(select.table, self.escapeCharacter) + '.' + utils.escapeName(select.key, self.escapeCharacter) + ', ';
    }

  });

  // Remove the last comma
  query = query.slice(0, -2) + ' FROM ' + tableName + ' AS ' + utils.escapeName(self.currentTable, self.escapeCharacter) + ' ';

  return query;
};

/**
 * Aggregates
 *
 */

SelectBuilder.prototype.processAggregates = function processAggregates(criteria) {

  var self = this;

  if(!criteria.groupBy && !criteria.sum && !criteria.average && !criteria.min && !criteria.max) {
    return false;
  }

  // Error if groupBy is used and no calculations are given
  if(!criteria.sum && !criteria.average && !criteria.min && !criteria.max) {
    throw new Error('An aggregation was used but no calculations were given');
  }

  var query = 'SELECT ';
  var tableName = utils.escapeName(this.currentTable, this.escapeCharacter);

  // Append groupBy columns to select statement
  if(criteria.groupBy) {
    if(criteria.groupBy instanceof Array) {
      criteria.groupBy.forEach(function(opt) {
        query += tableName + '.' + utils.escapeName(opt, self.escapeCharacter) + ', ';
      });

    } else {
      query += tableName + '.' + utils.escapeName(criteria.groupBy, self.escapeCharacter) + ', ';
    }
  }

  // Handle SUM
  if (criteria.sum) {
    var sum = '';
    if(criteria.sum instanceof Array) {
      criteria.sum.forEach(function(opt) {
        sum = 'SUM(' + tableName + '.' + utils.escapeName(opt, self.escapeCharacter) + ')';
        if(self.cast) {
          sum = 'CAST(' + sum + ' AS float)';
        }
        query += sum + ' AS ' + opt + ', ';
      });

    } else {
      sum = 'SUM(' + tableName + '.' + utils.escapeName(criteria.sum, self.escapeCharacter) + ')';
      if(self.cast) {
        sum = 'CAST(' + sum + ' AS float)';
      }
      query += sum + ' AS ' + criteria.sum + ', ';
    }
  }

  // Handle AVG (casting to float to fix percision with trailing zeros)
  if (criteria.average) {
    var avg = '';
    if(criteria.average instanceof Array) {
      criteria.average.forEach(function(opt){
        avg = 'AVG(' + tableName + '.' + utils.escapeName(opt, self.escapeCharacter) + ')';
        if(self.cast) {
          avg = 'CAST( ' + avg + ' AS float)';
        }
        query +=  avg + ' AS ' + opt + ', ';
      });
    } else {
      avg = 'AVG(' + tableName + '.' + utils.escapeName(criteria.average, self.escapeCharacter) + ')';
      if(self.cast) {
        avg = 'CAST( ' + avg + ' AS float)';
      }
      query += avg + ' AS ' + criteria.average + ', ';
    }
  }

  // Handle MAX
  if (criteria.max) {
    var max = '';
    if(criteria.max instanceof Array) {
      criteria.max.forEach(function(opt){
        query += 'MAX(' + tableName + '.' + utils.escapeName(opt, self.escapeCharacter) + ') AS ' + opt + ', ';
      });

    } else {
      query += 'MAX(' + tableName + '.' + utils.escapeName(criteria.max, self.escapeCharacter) + ') AS ' + criteria.max + ', ';
    }
  }

  // Handle MIN
  if (criteria.min) {
    if(criteria.min instanceof Array) {
      criteria.min.forEach(function(opt){
        query += 'MIN(' + tableName + '.' + utils.escapeName(opt, self.escapeCharacter) + ') AS ' + opt + ', ';
      });

    } else {
      query += 'MIN(' + tableName + '.' + utils.escapeName(criteria.min, self.escapeCharacter) + ') AS ' + criteria.min + ', ';
    }
  }

  // trim trailing comma
  query = query.slice(0, -2) + ' ';

  // Add FROM clause
  query += 'FROM ' + utils.escapeName(self.schema[self.currentTable].tableName, self.escapeCharacter) + ' AS ' + tableName + ' ';
  return query;
};
<|endoftext|>


<commit_before>const merge = require("webpack-merge");
const path = require("path");
const base = require("./base");
const TerserPlugin = require("terser-webpack-plugin");

module.exports = merge(base, {
  mode: "production",
  output: {
    filename: "bundle.min.js",
  },
  devtool: false,
  performance: {
    maxEntrypointSize: 900000,
    maxAssetSize: 900000,
  },
  optimization: {
    minimizer: [
      new TerserPlugin({
        terserOptions: {
          output: {
            comments: false,
          },
        },
      }),
    ],
  },
});
<commit_msg>bundle.js<commit_after>const merge = require("webpack-merge");
const path = require("path");
const base = require("./base");
const TerserPlugin = require("terser-webpack-plugin");

module.exports = merge(base, {
  mode: "production",
  output: {
    filename: "bundle.js",
  },
  devtool: false,
  performance: {
    maxEntrypointSize: 900000,
    maxAssetSize: 900000,
  },
  optimization: {
    minimizer: [
      new TerserPlugin({
        terserOptions: {
          output: {
            comments: false,
          },
        },
      }),
    ],
  },
});
<|endoftext|>


<commit_before>/*
 * Copyright 2020 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * External dependencies
 */
import { shallowEqual } from 'react-pure-render';
import { useCallback, useRef } from 'react';
import { useContextSelector as useContextSelectorOrig } from 'use-context-selector';

export { createContext, useContext } from 'use-context-selector';

/**
 * This hook returns a part of the context value by selector.
 * It will trigger a re-render only if the selected value has changed.
 *
 * By default, a shallow equals of the selected context value is used to
 * determine if a re-render is needed.
 *
 * @param {import('react').Context} context
 * @param {function(Object):Object} selector Returns a fragment of the context
 * that the consumer is interested in.
 * @param {function(Object, Object):boolean} equalityFn Used to compare the
 * selected context value. If the context fragment has not changed, a re-render
 * will not be triggered. This is {shallowEqual} by default.
 * @return {Object} The selected context value fragment.
 */
export const useContextSelector = (
  context,
  selector,
  equalityFn = shallowEqual
) => {
  const ref = useRef();

  const equalityFnCallback = useCallback(
    (state) => {
      const selected = selector(state);
      if (equalityFn(ref.current, selected)) {
        return ref.current;
      }
      ref.current = selected;
      return selected;
    },
    [selector, equalityFn]
  );

  // Update the selector fn to memoize the selected value by [equalityFn].
  const patchedSelector = equalityFn ? equalityFnCallback : selector;
  return useContextSelectorOrig(context, patchedSelector);
};

export const identity = (state) => state;
<commit_msg>Remove unnecessary useCallback from useContextSelector (#2266)<commit_after>/*
 * Copyright 2020 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * External dependencies
 */
import { shallowEqual } from 'react-pure-render';
import { useRef } from 'react';
import { useContextSelector as useContextSelectorOrig } from 'use-context-selector';

export { createContext, useContext } from 'use-context-selector';

/**
 * This hook returns a part of the context value by selector.
 * It will trigger a re-render only if the selected value has changed.
 *
 * By default, a shallow equals of the selected context value is used to
 * determine if a re-render is needed.
 *
 * @param {import('react').Context} context
 * @param {function(Object):Object} selector Returns a fragment of the context
 * that the consumer is interested in.
 * @param {function(Object, Object):boolean} equalityFn Used to compare the
 * selected context value. If the context fragment has not changed, a re-render
 * will not be triggered. This is {shallowEqual} by default.
 * @return {Object} The selected context value fragment.
 */
export const useContextSelector = (
  context,
  selector,
  equalityFn = shallowEqual
) => {
  const ref = useRef();

  const equalityFnCallback = (state) => {
    const selected = selector(state);
    if (equalityFn(ref.current, selected)) {
      return ref.current;
    }
    ref.current = selected;
    return selected;
  };

  // Update the selector fn to memoize the selected value by [equalityFn].
  const patchedSelector = equalityFn ? equalityFnCallback : selector;
  return useContextSelectorOrig(context, patchedSelector);
};

export const identity = (state) => state;
<|endoftext|>