<commit_before>// ==UserScript==
// @name         A Mining Game: Fix minor issues
// @namespace    https://github.com/Phylogenesis/
// @version      0.2.4
// @description  Fixes some minor issues with the chat system and allows manual saving by clicking on the button in the top right
// @author       Luke Jones
// @include      /^http://trugul\.com/(index\.php)?$/
// @grant        none
// @downloadURL  https://github.com/Phylogenesis/greasemonkey/raw/master/AMGFixes.user.js
// ==/UserScript==

(function ($) {
    var AGame = {
        client:     undefined,
        username:   undefined,
        lastSubmit: undefined,
    };

    function updateRanks() {
        $.ajax({
            url:     'http://trugul.com/highscores/',
            async:   true,
            success: function (data) {
                var matches = /You are ranked #(\d+)/.exec(data);
                var rank = 'N/A'

                if (matches.length > 0) {
                    rank = matches[1];
                }

                $('#leaderboardRanking span.mainRank').text(rank);
            }
        });

        $.ajax({
            url:     'http://trugul.com/highscores/?order=prestige',
            async:   true,
            success: function (data) {
                var matches = /You are ranked #(\d+)/.exec(data);
                var rank = 'N/A'

                if (matches.length > 0) {
                    rank = matches[1];
                }

                $('#leaderboardRanking span.prestigeRank').text(rank);
            }
        });
    };

    $(document).on(
        'click',
        'div.tabs a',
        function () {
            setTimeout(
                function () {
                    if ($('div.chat-room-message-container:visible').length > 0) {
                        $('div.chat-room-message-container').scrollTop($('div.chat-room-message-container')[0].scrollHeight);
                        $('body').css('padding-bottom', $('div.popout').outerHeight() + 'px');
                    } else {
                        $('body').css('padding-bottom', '20px');
                    }
                },
                100
            );
        }
    );

    $(document).on(
        'click',
        'ul.navbar-right a',
        function (e) {
            if (AGame.client) {
                AGame.client.emit('save');
            }

            e.preventDefault();
        }
    );

    setTimeout(function () {
        AGame.client   = io('http://5.189.137.117:469');
        AGame.username = $('#playerName').text();

        AGame.client.on(
            'gameVars',
            function (data) {
                var lastSubmit = data.gameVars.lastSubmit;

                if (AGame.lastSubmit !== lastSubmit) {
                    AGame.lastSubmit = lastSubmit;
                    updateRanks();
                }
            }
        );

        $('#quickdetails tr').prepend('Ranking……	');

        $('#leaderboardRanking').css({
            textAlign: 'center',
            padding:   0
        });

        $('#leaderboardRanking b').css({
            display:      'block',
            borderBottom: '1px solid white',
            lineHeight:   '18px'
        });

        $('#leaderboardRanking span').css({
            display:    'inline-block',
            width:      '50px',
            cursor:     'pointer',
            lineHeight: '19px'
        });

        $('span.mainRank').css({
            borderRight:            '1px solid white',
            borderBottomLeftRadius: '5px'
        });

        $('span.prestigeRank').css({
            borderBottomRightRadius: '5px'
        });

        $('#leaderboardRanking span').hover(
            function () { $(this).css('background-color', '#8b8'); },
            function () { $(this).css('background-color', ''); }
        );

        $('span.mainRank').click(function () {
            window.open('http://trugul.com/highscores/?user=' + AGame.username)
        });

        $('span.prestigeRank').click(function () {
            window.open('http://trugul.com/highscores/?order=prestige&user=' + AGame.username)
        });
    }, 5000);
})(jQuery);

<commit_msg>Update AMGFixes.user.js<commit_after>// ==UserScript==
// @name         A Mining Game: Fix minor issues
// @namespace    https://github.com/Phylogenesis/
// @version      0.2.5
// @description  Fixes some minor issues with the chat system and allows manual saving by clicking on the button in the top right
// @author       Luke Jones
// @include      /^http://trugul\.com/(index\.php)?$/
// @grant        none
// @downloadURL  https://github.com/Phylogenesis/greasemonkey/raw/master/AMGFixes.user.js
// ==/UserScript==

(function ($) {
    var AGame = {
        client:     undefined,
        username:   undefined,
        lastSubmit: undefined,
    };

    function updateRanks() {
        $.ajax({
            url:     'http://trugul.com/highscores/',
            async:   true,
            success: function (data) {
                var matches = /You are ranked #(\d+)/.exec(data);
                var rank = 'N/A'

                if (matches.length > 0) {
                    rank = matches[1];
                }

                $('#leaderboardRanking span.mainRank').text(rank);
            }
        });

        $.ajax({
            url:     'http://trugul.com/highscores/?order=prestige',
            async:   true,
            success: function (data) {
                var matches = /You are ranked #(\d+)/.exec(data);
                var rank = 'N/A'

                if (matches.length > 0) {
                    rank = matches[1];
                }

                $('#leaderboardRanking span.prestigeRank').text(rank);
            }
        });
    };

    $(document).on(
        'click',
        'div.tabs a',
        function () {
            setTimeout(
                function () {
                    if ($('div.chat-room-message-container:visible').length > 0) {
                        $('div.chat-room-message-container').scrollTop($('div.chat-room-message-container')[0].scrollHeight);
                        $('body').css('padding-bottom', $('div.popout').outerHeight() + 'px');
                    } else {
                        $('body').css('padding-bottom', '20px');
                    }
                },
                100
            );
        }
    );

    $(document).on(
        'click',
        'ul.navbar-right a',
        function (e) {
            if (AGame.client) {
                AGame.client.emit('save');
            }

            e.preventDefault();
        }
    );

    setTimeout(function () {
        AGame.client   = io('http://5.189.137.117:469');
        AGame.username = $('#playerName').text();

        AGame.client.on(
            'gameVars',
            function (data) {
                var lastSubmit = data.gameVars.lastSubmit;

                if (AGame.lastSubmit !== lastSubmit) {
                    AGame.lastSubmit = lastSubmit;
                    updateRanks();
                }
            }
        );

        $('#quickdetails tr').prepend('Ranking……	');

        $('#leaderboardRanking').css({
            textAlign: 'center',
            padding:   0
        });

        $('#leaderboardRanking b').css({
            display:      'block',
            borderBottom: '1px solid white',
            lineHeight:   '18px'
        });

        $('#leaderboardRanking span').css({
            display:    'inline-block',
            width:      '50px',
            cursor:     'pointer',
            lineHeight: '19px'
        });

        $('span.mainRank').css({
            borderRight:            '1px solid white',
            borderBottomLeftRadius: '5px'
        });

        $('span.prestigeRank').css({
            borderBottomRightRadius: '5px'
        });

        $('#leaderboardRanking span').hover(
            function () {
                $(this).css('background-color', '#8b8');
                $('#leaderboardRanking b').text($(this).data('order'));
            },
            function () {
                $(this).css('background-color', '');
                $('#leaderboardRanking b').text('Ranking');
            }
        );

        $('span.mainRank').click(function () {
            window.open('http://trugul.com/highscores/?user=' + AGame.username)
        });

        $('span.prestigeRank').click(function () {
            window.open('http://trugul.com/highscores/?order=prestige&user=' + AGame.username)
        });
    }, 5000);
})(jQuery);

<|endoftext|>


<commit_before>
 /**
 * PHP functions in javascript
 **/

 // String Manipulation functions

  var str,
      str1,
      str2,
      variable;

  function isset(str){

        if (typeof str !== undefined){

            return true ;
        }
        else {

        return false ;
        }

  }

  function empty(variable) {

   if (variable === ''){

        return true ;

   }
   else {

    return false ;
   }
  }

  // return the length of str
  function strlen(str) {

       return str.length ;
  }

  // search for str2 in str1
  function stristr(str1,str2){

   // check if str2 exist in str1
   if( str1.indexOf(str2) !== -1) {

    return true ;

   }

   else{

    return false ;

   }

  }

  // to lower case

  function strtolower(str){

     var str =  str.toLowerCase() ;

     return str ;
  }

  // to upper case

  function strtoupper(str){

     var str =  str.toUpperCase() ;

     return str ;
  }

<commit_msg>Adding explode<commit_after>
 /**
 * PHP functions in javascript
 **/

 // String Manipulation functions

  var str,
      str1,
      str2,
      variable;

  function isset(str){

        if (typeof str !== undefined){

            return true ;
        }
        else {

        return false ;
        }

  }

  function empty(variable) {

   if (variable === ''){

        return true ;

   }
   else {

    return false ;
   }
  }

  // return the length of str
  function strlen(str) {

       return str.length ;
  }

  // search for str2 in str1
  function stristr(str1,str2){

   // check if str2 exist in str1
   if( str1.indexOf(str2) !== -1) {

    return true ;

   }

   else{

    return false ;

   }

  }

  // to lower case

  function strtolower(str){

     var str =  str.toLowerCase() ;

     return str ;
  }

  // to upper case

  function strtoupper(str){

     var str =  str.toUpperCase() ;

     return str ;
  }

  function explode(pattern,str){

  }

<|endoftext|>


<commit_before>/*globals extend: false */
"use strict";

var PERSIST_DATABASES = false;

function uuid() {
  var S4 = function() {
    return Math.floor(Math.random() * 0x10000).toString(16);
  };

  return (
    S4() + S4() + "-" +
      S4() + "-" +
      S4() + "-" +
      S4() + "-" +
      S4() + S4() + S4()
  );
}

function makeDocs(start, end, templateDoc) {
  var templateDocSrc = templateDoc ? JSON.stringify(templateDoc) : "{}";
  if (end === undefined) {
    end = start;
    start = 0;
  }
  var docs = [];
  for (var i = start; i < end; i++) {
    /*jshint evil:true */
    var newDoc = eval("(" + templateDocSrc + ")");
    newDoc._id = (i).toString();
    newDoc.integer = i;
    newDoc.string = (i).toString();
    docs.push(newDoc);
  }
  return docs;
}

function makeBlob(data, type) {
  if (typeof module !== 'undefined' && module.exports) {
    return new Buffer(data);
  } else {
    return new Blob([data], {type: type});
  }
}

function readBlob(blob, callback) {
  if (typeof module !== 'undefined' && module.exports) {
    callback(blob.toString());
  } else {
    var reader = new FileReader();
    reader.onloadend = function(e) {
      callback(this.result);
    };
    reader.readAsBinaryString(blob);
  }
}

function openTestDB(name, callback) {
  new Pouch(name, function(err, db) {
    if (err) {
      console.error(err);
      ok(false, 'failed to open database');
      return start();
    }
    callback.apply(this, arguments);
  });
}

function initTestDB(name, callback) {
  // ignore errors, the database might not exist
  Pouch.destroy(name, function(err) {
    if (err && err.status !== 404 && err.statusText !== 'timeout') {
      console.error(err);
      ok(false, 'failed to open database');
      return start();
    }
    openTestDB(name, callback);
  });
}

function initDBPair(local, remote, callback) {
  initTestDB(local, function(err, localDb) {
    initTestDB(remote, function(err, remoteDb) {
      callback(localDb, remoteDb);
    });
  });
}

var testId = uuid();

function generateAdapterUrl(id) {
  var opt = id.split('-');
  if (opt[0] === 'local') {
    return 'testdb_' + testId + '_' + opt[1];
  }
  if (opt[0] === 'http') {
    return (typeof module !== 'undefined' && module.exports) ?
      'http://localhost:5984/testdb_' + testId + '_' + opt[1] :
      'http://localhost:2020/testdb_' + testId + '_' + opt[1];
  }
}

function putAfter(db, doc, prevRev, callback){
  var newDoc = extend({}, doc);
  newDoc._revisions = {
    start: +newDoc._rev.split('-')[0],
    ids: [
      newDoc._rev.split('-')[1],
      prevRev.split('-')[1]
    ]
  };
  db.put(newDoc, {new_edits: false}, callback);
}

if (typeof module !== 'undefined' && module.exports) {
  Pouch = require('../src/pouch.js');
  module.exports = {
    makeDocs: makeDocs,
    makeBlob: makeBlob,
    readBlob: readBlob,
    initTestDB: initTestDB,
    initDBPair: initDBPair,
    openTestDB: openTestDB,
    generateAdapterUrl: generateAdapterUrl,
    putAfter: putAfter,
    PERSIST_DATABASES: PERSIST_DATABASES
  };
}
<commit_msg>(#499) - set PERSIST_DATABASES true in the test suite<commit_after>/*globals extend: false */
"use strict";

var PERSIST_DATABASES = true;

function uuid() {
  var S4 = function() {
    return Math.floor(Math.random() * 0x10000).toString(16);
  };

  return (
    S4() + S4() + "-" +
      S4() + "-" +
      S4() + "-" +
      S4() + "-" +
      S4() + S4() + S4()
  );
}

function makeDocs(start, end, templateDoc) {
  var templateDocSrc = templateDoc ? JSON.stringify(templateDoc) : "{}";
  if (end === undefined) {
    end = start;
    start = 0;
  }
  var docs = [];
  for (var i = start; i < end; i++) {
    /*jshint evil:true */
    var newDoc = eval("(" + templateDocSrc + ")");
    newDoc._id = (i).toString();
    newDoc.integer = i;
    newDoc.string = (i).toString();
    docs.push(newDoc);
  }
  return docs;
}

function makeBlob(data, type) {
  if (typeof module !== 'undefined' && module.exports) {
    return new Buffer(data);
  } else {
    return new Blob([data], {type: type});
  }
}

function readBlob(blob, callback) {
  if (typeof module !== 'undefined' && module.exports) {
    callback(blob.toString());
  } else {
    var reader = new FileReader();
    reader.onloadend = function(e) {
      callback(this.result);
    };
    reader.readAsBinaryString(blob);
  }
}

function openTestDB(name, callback) {
  new Pouch(name, function(err, db) {
    if (err) {
      console.error(err);
      ok(false, 'failed to open database');
      return start();
    }
    callback.apply(this, arguments);
  });
}

function initTestDB(name, callback) {
  // ignore errors, the database might not exist
  Pouch.destroy(name, function(err) {
    if (err && err.status !== 404 && err.statusText !== 'timeout') {
      console.error(err);
      ok(false, 'failed to open database');
      return start();
    }
    openTestDB(name, callback);
  });
}

function initDBPair(local, remote, callback) {
  initTestDB(local, function(err, localDb) {
    initTestDB(remote, function(err, remoteDb) {
      callback(localDb, remoteDb);
    });
  });
}

var testId = uuid();

function generateAdapterUrl(id) {
  var opt = id.split('-');
  if (opt[0] === 'local') {
    return 'testdb_' + testId + '_' + opt[1];
  }
  if (opt[0] === 'http') {
    return (typeof module !== 'undefined' && module.exports) ?
      'http://localhost:5984/testdb_' + testId + '_' + opt[1] :
      'http://localhost:2020/testdb_' + testId + '_' + opt[1];
  }
}

function putAfter(db, doc, prevRev, callback){
  var newDoc = extend({}, doc);
  newDoc._revisions = {
    start: +newDoc._rev.split('-')[0],
    ids: [
      newDoc._rev.split('-')[1],
      prevRev.split('-')[1]
    ]
  };
  db.put(newDoc, {new_edits: false}, callback);
}

if (typeof module !== 'undefined' && module.exports) {
  Pouch = require('../src/pouch.js');
  module.exports = {
    makeDocs: makeDocs,
    makeBlob: makeBlob,
    readBlob: readBlob,
    initTestDB: initTestDB,
    initDBPair: initDBPair,
    openTestDB: openTestDB,
    generateAdapterUrl: generateAdapterUrl,
    putAfter: putAfter,
    PERSIST_DATABASES: PERSIST_DATABASES
  };
}
<|endoftext|>


<commit_before>// Given nodes, make circles(dots) and force simulation)
function d3_nodesToDots(authors_nodes, pubs_nodes,keywords_nodes, author_links){
	var R1 = 450,
		R2 = 500;
	pubs_nodes = addDotPosition(R1,R2,pubs_nodes);

	var authorLines = d3.select("#visKate")
		.append("g")
		.selectAll(".authorLinks")
		.data(author_links)
		.enter().append('line')
		 .attr('marker-end', 'url()')
		.attr("stroke", "#9ad5fe")
		.attr('stroke-opacity', 0.5);

	var authorDots = d3.select("#visKate")
    	.append("g")
    	.selectAll(".author_circles")
		.data(authors_nodes)
    	.enter().append("circle")
    		.attr("r", function(d){return authorNodeRadius(d); })
    		.attr("id", function(d){return d.id+"g"})
    		.attr("class", "authorDots")
    		.style("fill", "#9ad5fe");

	d3.select("#visKate")
  		.append('marker')
  		.attr('id', 'arrowhead')
  		.attr('refX', 6+15) // Controls the shift of the arrow head along the path
  		.attr('refY', 2)
  		.attr('markerWidth', 6)
 		.attr('markerHeight', 4)
  		.attr('orient', 'auto')
  		.style('fill', '#9ad5fe')
 		.append('path')
    	.attr('d', 'M 0,0 V 4 L6,2 Z');

    var pubsByYear = d3.nest()
    	.key(function(d){return d.year})
    	.rollup(function(v){return v.length;})
    	.entries(pubs_nodes);

    var pie = d3.pie()
    	.startAngle(-90 * Math.PI/180)
    	.endAngle(-90 * Math.PI/180 + 2*Math.PI)
    	.value(function(d) { return d.value; })
    	.padAngle(.01)
    	.sort(null)

    var yearArc = d3.arc()
    	.innerRadius(R2+5)
    	.outerRadius(R2+10);

 	var yearPie = d3.select("#visKate").append("g").selectAll(".yearArc")
    	.data(pie(pubsByYear))
    	.enter().append("path")
    		.attr("class", "yearArc")
    		.attr("id", function(d,i) { return "yearArc"+i; }) //Unique id for each slice
			.attr("d", yearArc)
 			.style('fill', 'white')
 			.style('opacity', function(d,i){return (11-i)/11;});

	var yearLabels = d3.select("#visKate").append("g").selectAll(".yearLabel")
		.data(pubsByYear)
		.enter().append("text")
		.attr("class", "yearLabel")
		.attr("dy", -5)
		.append("textPath")
			.attr("xlink:href", function(d,i){return "#yearArc"+i;})
			.attr("style","font-size:12px;")
			.attr("fill", "white")
			.attr("opacity", 0.5)
			.text(function(d){return d.key;});

 	var pubDots = d3.select("#visKate")
		.append("g")
		.selectAll(".pub_circles")
		.data(pubs_nodes)
		.enter().append("circle")
			.attr("r", 7)
			.attr("id", function(d){return d.id+"g";})
			.attr("class", "pubDots")
			.style("fill", function(d) { return venue_color(d.conference); });

    var keywordDots = d3.select("#visKate")
    	.append("g")
		.selectAll(".keyword_circles")
		.data(keywords_nodes)
		.enter().append("g")
			.attr('class', 'keyNodes')
			.attr("id", function(d){return d.id+"g";})

	keywordDots.append("circle")
			.attr("r",  function(d){return Math.floor((d.pubs.length/10)+6); })
			.style("fill", "NavajoWhite")
			.attr("class", "keyCircles")
			.style("opacity", 0.5);

	var keyLabels = keywordDots.append("text")
			.text(function(d){return d.name})
			.style("fill", "NavajoWhite")
			.style('opacity',  function(d){return (d.pubs.length/10)+0.5;})
			.style("font-size", function(d){return (d.pubs.length/10)+13 + "px"; })
   			.attr("id", function(d){return d.id+"g_l";})
   			.attr("dy", ".35em")
   			.attr("text-anchor", "middle")
   			.style("visibility", "hidden");

	var simulation = d3.forceSimulation()
            .force("link", d3.forceLink().id(function(d) { return d.id }))
			.force('charge', d3.forceManyBody());

	simulation.nodes(authors_nodes)
		.force("x", d3.forceX().strength(.19))
		.force("y", d3.forceY().strength(.19))
		.on("tick", ticked);

	simulation.force("link")
		.links(author_links);

	d3.forceSimulation(pubs_nodes)
		.on("tick", ticked)

	d3.forceSimulation(keywords_nodes)
		.force("charge",  d3.forceManyBody())
		.force("r", d3.forceRadial(700))
		.force("x", d3.forceX())
		.force("y", d3.forceY())
		.on("tick", ticked);

	function ticked(e){
		authorDots.attr("cx", function(d){ return d.x;})
			.attr("cy", function(d){ return d.y;});
		pubDots.attr("cx", function(d){ return d.x;})
			.attr("cy", function(d){ return d.y;});
		keywordDots.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });

		authorLines
        	.attr("x1", function(d) { return d.source.x; })
    		.attr("y1", function(d) { return d.source.y; })
            .attr("x2", function(d) { return d.target.x; })
            .attr("y2", function(d) { return d.target.y; });
		}
d3.timer(function(elapsed) {
	 	var delta = (Date.now() - start);
    	pubDots.attr("transform", "rotate(" + delta * 1/2000 + ")");
    	yearPie.attr("transform", "rotate(" + delta * 1/2000 + ")");
    	// keywordDots.attr("transform", function(d) {
//       		return "translate("+(d.x+Math.cos(delta))+","+(d.y+Math.sin(delta))+")";});
// 		keyLabels.attr("transform", function(d) {
//       		return "rotate(" + -delta * 1/3000 + ")";});
    });
	return {
        authorDots: authorDots,
        pubDots: pubDots,
        keywordDots: keywordDots,
        authorLines:authorLines,
		keyLabels:keyLabels
    };
}
function getNodes(pubs, authorIDs, keyIDs){
	var authors_dict = [];
	var authors_link_dict = [];
	var pubNodes = [];
	var keyword_dict =[];
	var keyword_dict_authors =[];
	var authorLinks = [];
			for (var p = 0; p<pubs.length; p++){
				authors_project = pubs[p].Authors.split(",");

				var authorList_pub = [];

				for (var a = 0; a<authors_project.length;  a++){
					var author = authors_project[a].trim();
					if (a == 0){var source_author = author;};
					if (!(author in authors_dict)){
						authors_dict[author] = ["p"+pubs[p].ID];
					}else{
						authors_dict[author].push("p"+pubs[p].ID);
					}
					authorList_pub.push(authorIDs[author]);

					for (var aa = a+1; aa<authors_project.length; aa++){
						var author2 = authors_project[aa].trim();
						if (!(author in authors_link_dict)){
							authors_link_dict[author] = {}
							authors_link_dict[author][author2] = 1;
						}else{
							if(!(author2 in authors_link_dict[author])){
								authors_link_dict[author][author2] = 1;
							}else{
								authors_link_dict[author][author2] +=1;
							}
						}
						if (!(author2 in authors_link_dict)){
							authors_link_dict[author2] = {}
							authors_link_dict[author2][author] = 1;
						}else{
							if(!(author in authors_link_dict[author2])){
								authors_link_dict[author2][author] = 1;
							}else{
								authors_link_dict[author2][author] += 1;
							}
						}
					}

				}

				keywords_project = pubs[p].Keywords.split(";");
				var keyList_pub = [];
				for (var a = 0; a<keywords_project.length;  a++){
					keyword = keywords_project[a].trim();
					if (keyword != "Fabrication"){
					if (!(keyword in keyword_dict)){
						keyword_dict[keyword] = ["p"+pubs[p].ID];
						keyword_dict_authors[keyword] = authorList_pub;
					}else{
						keyword_dict[keyword].push("p"+pubs[p].ID);
						keyword_dict_authors[keyword].push(...authorList_pub);
					}
					keyList_pub.push(keyIDs[keyword]);
					}
				}

				//append pub node
				if (pubs[p].Year <= 2009){
					pubYear = "<2009";
				}else{pubYear = pubs[p].Year;}
				var c= pubs[p].Conference;
				if(c == "ACM CHI EA"){
					c = "ACM CHI";
				}
				else if(c == "ACM SCF" || c == "ACM SCA" || c == "ACM SGP"){
					// ACM SCF, ACM SCA, ACM SGP
					c = "ACM Symposium";
				}
				else if(c == "ACM VRST" || c == "COMPUTER AND GRAPHICS" ||
						c == "IOPScience" || c == "IEEE Pervasive Computing" ||
						c == "IEEE COMPUTER GRAPHICS AND APPLICATIONS" ||
						c == "CEA" || c == "NIME" || c == "IEEE TVCG"){
					// ACM VRST, COMPUTER AND GRAPHICS, IOPScience, IEEE Pervasive Computing, IEEE COMPUTER GRAPHICS AND APPLICATIONS, CEA, NIME
					c = "Others";
				}
				pubNodes.push({id: "p"+pubs[p].ID, authors: authorList_pub,  keys: keyList_pub, conference:c, year:pubYear});
		}

	var authorList = Object.keys(authors_dict)

	// generate author nodes
	var authorNodes = [];
	var linksTest = [];
	var tempdict = {};
	for (var a = 0; a <authorList.length; a++){
		authorNodes.push({id: authorIDs[authorList[a]],name:authorList[a], pubs:authors_dict[authorList[a]]})
		var list = authors_link_dict[authorList[a]];
		linksSorted = Object.keys(list).sort(function(a,b){return list[b]-list[a]})

		tempdict[authorIDs[authorList[a]]] = [];
		for (var j = 0; j<Math.min(1,linksSorted.length); j++){
			if (linksTest.indexOf(authorIDs[authorList[a]]+authorIDs[linksSorted[j]])==-1 && linksTest.indexOf(authorIDs[linksSorted[j]]+authorIDs[authorList[a]])==-1){
				linksTest.push(authorIDs[authorList[a]]+authorIDs[linksSorted[j]]);
				}
			tempdict[authorIDs[authorList[a]]].push(authorIDs[linksSorted[j]]);
			authorLinks.push({'source': authorIDs[authorList[a]], 'target':authorIDs[linksSorted[j]]});
		}
			}

	var keyList = Object.keys(keyword_dict);
	var keyNodes = [];
	for(var k = 0; k< keyList.length; k++){
		if (keyword_dict[keyList[k]].length >1){
			keyNodes.push({id: keyIDs[keyList[k]], name: keyList[k], pubs:keyword_dict[keyList[k]], authors:keyword_dict_authors[keyList[k]]});
			}
	}
	return{
		authorNodes :authorNodes,
		pubNodes: pubNodes,
		keyNodes: keyNodes,
		authorLinks : authorLinks
		};
}
function getSourceTargetDict(authorLinks){
	var targetDict = {};
	var sourceDict = {};

	for (var i = 0; i <authorLinks.length; i++){
		var s = authorLinks[i].source.id;
		var t = authorLinks[i].target.id;

		targetDict[s] = t;
		if (!(t in sourceDict)){
			sourceDict[t] = [s];
		}else{
			sourceDict[t].push(s);
		}
		if (!(s in sourceDict)){
			sourceDict[s] = [];
		}
	}
	return {
		targetDict : targetDict,
		sourceDict : sourceDict
	}
}
function addDotPosition(R1, R2, nodes){
    	var thetas = [];
    	for (var n = 0; n<nodes.length; n++){
    		thetas.push(n*2*Math.PI/nodes.length+Math.PI);
    	}
		var dists = [R1+(R2-R1)/4, R1+3*(R2-R1)/4]
    	for (var n = 0; n<nodes.length; n++){
    		theta = thetas[n];
    		dist = dists[n%2];
    		var x =  dist * Math.cos(theta);
			var y =  dist * Math.sin(theta);
			nodes[n].x = x;
			nodes[n].y = y;
    	}
	return nodes;

    }
function authorNodeRadius(node){
	return Math.floor((node.pubs.length/2)+6)
}
	<commit_msg>JS updated<commit_after>// Given nodes, make circles(dots) and force simulation)
function d3_nodesToDots(authors_nodes, pubs_nodes,keywords_nodes, author_links){
	var R1 = 450,
		R2 = 500;
	pubs_nodes = addDotPosition(R1,R2,pubs_nodes);

	var authorLines = d3.select("#visKate")
		.append("g")
		.selectAll(".authorLinks")
		.data(author_links)
		.enter().append('line')
		 .attr('marker-end', 'url()')
		.attr("stroke", "#9ad5fe")
		.attr('stroke-opacity', 0.5);

	var authorDots = d3.select("#visKate")
    	.append("g")
    	.selectAll(".author_circles")
		.data(authors_nodes)
    	.enter().append("circle")
    		.attr("r", function(d){return authorNodeRadius(d); })
    		.attr("id", function(d){return d.id+"g"})
    		.attr("class", "authorDots")
    		.style("fill", "#9ad5fe");

	d3.select("#visKate")
  		.append('marker')
  		.attr('id', 'arrowhead')
  		.attr('refX', 6+15) // Controls the shift of the arrow head along the path
  		.attr('refY', 2)
  		.attr('markerWidth', 6)
 		.attr('markerHeight', 4)
  		.attr('orient', 'auto')
  		.style('fill', '#9ad5fe')
 		.append('path')
    	.attr('d', 'M 0,0 V 4 L6,2 Z');

    var pubsByYear = d3.nest()
    	.key(function(d){return d.year})
    	.rollup(function(v){return v.length;})
    	.entries(pubs_nodes);

    var pie = d3.pie()
    	.startAngle(-90 * Math.PI/180)
    	.endAngle(-90 * Math.PI/180 + 2*Math.PI)
    	.value(function(d) { return d.value; })
    	.padAngle(.01)
    	.sort(null)

    var yearArc = d3.arc()
    	.innerRadius(R2+5)
    	.outerRadius(R2+10);

 	var yearPie = d3.select("#visKate").append("g").selectAll(".yearArc")
    	.data(pie(pubsByYear))
    	.enter().append("path")
    		.attr("class", "yearArc")
    		.attr("id", function(d,i) { return "yearArc"+i; }) //Unique id for each slice
			.attr("d", yearArc)
 			.style('fill', 'white')
 			.style('opacity', function(d,i){return (11-i)/11;});

	var yearLabels = d3.select("#visKate").append("g").selectAll(".yearLabel")
		.data(pubsByYear)
		.enter().append("text")
		.attr("class", "yearLabel")
		.attr("dy", -5)
		.append("textPath")
			.attr("xlink:href", function(d,i){return "#yearArc"+i;})
			.attr("style","font-size:12px;")
			.attr("fill", "white")
			.attr("opacity", 0.5)
			.text(function(d){return d.key;});

 	var pubDots = d3.select("#visKate")
		.append("g")
		.selectAll(".pub_circles")
		.data(pubs_nodes)
		.enter().append("circle")
			.attr("r", 7)
			.attr("id", function(d){return d.id+"g";})
			.attr("class", "pubDots")
			.style("fill", function(d) { return venue_color(d.conference); });

    var keywordDots = d3.select("#visKate")
    	.append("g")
		.selectAll(".keyword_circles")
		.data(keywords_nodes)
		.enter().append("g")
			.attr('class', 'keyNodes')
			.attr("id", function(d){return d.id+"g";})

	keywordDots.append("circle")
			.attr("r",  function(d){return Math.floor((d.pubs.length/10)+6); })
			.style("fill", "NavajoWhite")
			.attr("class", "keyCircles")
			.style("opacity", 0.5);

	var keyLabels = keywordDots.append("text")
			.text(function(d){return d.name})
			.style("fill", "NavajoWhite")
			.style('opacity',  function(d){return (d.pubs.length/10)+0.5;})
			.style("font-size", function(d){return (d.pubs.length/10)+13 + "px"; })
   			.attr("id", function(d){return d.id+"g_l";})
   			.attr("dy", ".35em")
   			.attr("text-anchor", "middle")
   			.style("visibility", "hidden");

	var simulation = d3.forceSimulation()
            .force("link", d3.forceLink().id(function(d) { return d.id }))
			.force('charge', d3.forceManyBody());

	simulation.nodes(authors_nodes)
		.force("x", d3.forceX().strength(.19))
		.force("y", d3.forceY().strength(.19))
		.on("tick", ticked);

	simulation.force("link")
		.links(author_links);

	d3.forceSimulation(pubs_nodes)
		.on("tick", ticked)

	d3.forceSimulation(keywords_nodes)
		.force("charge",  d3.forceManyBody())
		.force("r", d3.forceRadial(700))
		.force("x", d3.forceX())
		.force("y", d3.forceY())
		.on("tick", ticked);

	function ticked(e){
		authorDots.attr("cx", function(d){ return d.x;})
			.attr("cy", function(d){ return d.y;});
		pubDots.attr("cx", function(d){ return d.x;})
			.attr("cy", function(d){ return d.y;});
		keywordDots.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });

		authorLines
        	.attr("x1", function(d) { return d.source.x; })
    		.attr("y1", function(d) { return d.source.y; })
            .attr("x2", function(d) { return d.target.x; })
            .attr("y2", function(d) { return d.target.y; });
		}
d3.timer(function(elapsed) {
	 	var delta = (Date.now() - start);
    	pubDots.attr("transform", "rotate(" + delta * 1/2000 + ")");
    	yearPie.attr("transform", "rotate(" + delta * 1/2000 + ")");
    	// keywordDots.attr("transform", function(d) {
//       		return "translate("+(d.x+Math.cos(delta))+","+(d.y+Math.sin(delta))+")";});
// 		keyLabels.attr("transform", function(d) {
//       		return "rotate(" + -delta * 1/3000 + ")";});
    });
	return {
        authorDots: authorDots,
        pubDots: pubDots,
        keywordDots: keywordDots,
        authorLines:authorLines,
		keyLabels:keyLabels
    };
}
function getNodes(pubs, authorIDs, keyIDs){
	var authors_dict = [];
	var authors_link_dict = [];
	var pubNodes = [];
	var keyword_dict =[];
	var keyword_dict_authors =[];
	var authorLinks = [];
			for (var p = 0; p<pubs.length; p++){
				authors_project = pubs[p].Authors.split(",");

				var authorList_pub = [];

				for (var a = 0; a<authors_project.length;  a++){
					var author = authors_project[a].trim();
					if (a == 0){var source_author = author;};
					if (!(author in authors_dict)){
						authors_dict[author] = ["p"+pubs[p].ID];
					}else{
						authors_dict[author].push("p"+pubs[p].ID);
					}
					authorList_pub.push(authorIDs[author]);

					for (var aa = a+1; aa<authors_project.length; aa++){
						var author2 = authors_project[aa].trim();
						if (!(author in authors_link_dict)){
							authors_link_dict[author] = {}
							authors_link_dict[author][author2] = 1;
						}else{
							if(!(author2 in authors_link_dict[author])){
								authors_link_dict[author][author2] = 1;
							}else{
								authors_link_dict[author][author2] +=1;
							}
						}
						if (!(author2 in authors_link_dict)){
							authors_link_dict[author2] = {}
							authors_link_dict[author2][author] = 1;
						}else{
							if(!(author in authors_link_dict[author2])){
								authors_link_dict[author2][author] = 1;
							}else{
								authors_link_dict[author2][author] += 1;
							}
						}
					}

				}

				keywords_project = pubs[p].Keywords.split(";");
				var keyList_pub = [];
				for (var a = 0; a<keywords_project.length;  a++){
					keyword = keywords_project[a].trim();
					if (keyword != "Fabrication"){
					if (!(keyword in keyword_dict)){
						keyword_dict[keyword] = ["p"+pubs[p].ID];
						keyword_dict_authors[keyword] = authorList_pub;
					}else{
						keyword_dict[keyword].push("p"+pubs[p].ID);
						keyword_dict_authors[keyword].push(...authorList_pub);
					}
					keyList_pub.push(keyIDs[keyword]);
					}
				}

				//append pub node
				if (pubs[p].Year <= 2009){
					pubYear = "<2009";
				}else{pubYear = pubs[p].Year;}
				var c= pubs[p].Conference;
				if(c == "ACM CHI EA"){
					c = "ACM CHI";
				}
				else if(c == "ACM SCF" || c == "ACM SCA" || c == "ACM SGP"){
					// ACM SCF, ACM SCA, ACM SGP
					c = "ACM Symposium";
				}
				else if(c == "ACM VRST" || c == "COMPUTER AND GRAPHICS" ||
						c == "IOPScience" || c == "IEEE Pervasive Computing" ||
						c == "IEEE COMPUTER GRAPHICS AND APPLICATIONS" ||
						c == "CEA" || c == "NIME" || c == "IEEE TVCG"){
					// ACM VRST, COMPUTER AND GRAPHICS, IOPScience, IEEE Pervasive Computing, IEEE COMPUTER GRAPHICS AND APPLICATIONS, CEA, NIME
					c = "Others";
				}
				pubNodes.push({id: "p"+pubs[p].ID, authors: authorList_pub,  keys: keyList_pub, conference:c, year:pubYear});
		}

	var authorList = Object.keys(authors_dict)

	// generate author nodes
	var authorNodes = [];
	var linksTest = [];
	var tempdict = {};
	for (var a = 0; a <authorList.length; a++){
		authorNodes.push({id: authorIDs[authorList[a]],name:authorList[a], pubs:authors_dict[authorList[a]]})
		var list = authors_link_dict[authorList[a]];
		linksSorted = Object.keys(list).sort(function(a,b){return list[b]-list[a]})

		tempdict[authorIDs[authorList[a]]] = [];
		for (var j = 0; j<Math.min(1,linksSorted.length); j++){
			if (linksTest.indexOf(authorIDs[authorList[a]]+authorIDs[linksSorted[j]])==-1 && linksTest.indexOf(authorIDs[linksSorted[j]]+authorIDs[authorList[a]])==-1){
				linksTest.push(authorIDs[authorList[a]]+authorIDs[linksSorted[j]]);
				}
			tempdict[authorIDs[authorList[a]]].push(authorIDs[linksSorted[j]]);
			authorLinks.push({'source': authorIDs[authorList[a]], 'target':authorIDs[linksSorted[j]]});
		}
			}

	var keyList = Object.keys(keyword_dict);
	var keyNodes = [];
	for(var k = 0; k< keyList.length; k++){
		if (keyword_dict[keyList[k]].length >1){
			keyNodes.push({id: keyIDs[keyList[k]], name: keyList[k], pubs:keyword_dict[keyList[k]], authors:keyword_dict_authors[keyList[k]]});
			}
	}
	return{
		authorNodes :authorNodes,
		pubNodes: pubNodes,
		keyNodes: keyNodes,
		authorLinks : authorLinks
		};
}
function getSourceTargetDict(authorLinks){
	var targetDict = {};
	var sourceDict = {};

	for (var i = 0; i <authorLinks.length; i++){
		var s = authorLinks[i].source.id;
		var t = authorLinks[i].target.id;

		targetDict[s] = t;
		if (!(t in sourceDict)){
			sourceDict[t] = [s];
		}else{
			sourceDict[t].push(s);
		}
		if (!(s in sourceDict)){
			sourceDict[s] = [];
		}
	}
	return {
		targetDict : targetDict,
		sourceDict : sourceDict
	}
}
function addDotPosition(R1, R2, nodes){
    	var thetas = [];
    	for (var n = 0; n<nodes.length; n++){
    		thetas.push(n*2*Math.PI/nodes.length+Math.PI);
    	}
		var dists = [R1+(R2-R1)/4, R1+3*(R2-R1)/4]
    	for (var n = 0; n<nodes.length; n++){
    		theta = thetas[n];
    		dist = dists[n%2];
    		var x =  dist * Math.cos(theta);
			var y =  dist * Math.sin(theta);
			nodes[n].x = x;
			nodes[n].y = y;
    	}
	return nodes;

    }
function authorNodeRadius(node){
	return Math.floor((node.pubs.length/2)+6)
}
	<|endoftext|>


<commit_before>var modeRef = firebase.database().ref('mode');
modeRef.on('value', function (v) {
    var modes = v.val();
    for (mode in modes) {
        if (modes.hasOwnProperty(mode)) {
            $("#" + mode).toggleClass("inactive", !modes[mode]);
            if (mode == "chyron") {
                if (modes[mode] == "single") {
                    $("#chyronSingle").css("opacity", 1);
                    $("#chyronLeft").css("opacity", 0);
                    $("#chyronRight").css("opacity", 0);
                    $("#chyron").find(".logo").css("opacity", 0);
                } else {
                    $("#chyronSingle").css("opacity", 0);
                    $("#chyronLeft").css("opacity", 1);
                    $("#chyronRight").css("opacity", 1);
                    $("#chyron").find(".logo").css("opacity", 1);
                }
            }
        }
    }
});

var sets;
// Gatherer card images are low-res and blocky and ugly, so if we can, we want to use magiccards.info images.
// We need to translate from what Gatherer calls the set to what magiccards.info calls the set, though.
var gathererToMagiccardsInfo = [];
$.get("https://api.magicthegathering.io/v1/sets",
    function(data) {
        data.sets = _.sortBy(data.sets, function (x) {
            return (x.type == "promo" ? "p" : "") + x.releaseDate;
        });
        sets = _.map(data.sets, function (x) {
            return x.code;
        });

        gathererToMagiccardsInfo = _.object(
            sets,
            // If there's no magicCardsInfoCode, give up and return the normal code; fixes Kaladesh.
            _.map(data.sets, function(x) { return x.magicCardsInfoCode || x.code; }));
    });

function fillFeaturedCard(cardName, featuredCardSelector) {
    if (cardName != "") {
        // exact match on the name, because autocomplete in director.html should have
        // put an exact name there for us
        $.get("https://api.magicthegathering.io/v1/cards?name=\"" + cardName + "\"",
            function (data) {
                if (data.cards && data.cards.length > 0) {
                    data.cards = _.sortBy(data.cards, function (c) {
                        return sets.indexOf(c.set);
                    });
                    var card = data.cards[0];
                    var imageUrl = card.imageUrl;
                    if (card.set && card.number) {
                        // not all cards have a number (e.g. LEA Lightning Bolt)
                        imageUrl = ("http://magiccards.info/scans/en/" + gathererToMagiccardsInfo[card.set]
                                    + "/" + card.number + ".jpg").toLowerCase();
                    }
                    var setReq = Promise.resolve(null);
                    if (card.set) {
                        setReq = $.get("https://api.magicthegathering.io/v1/sets/" + card.set);
                    }
                    var img = $(featuredCardSelector).find(".img");
                    img.attr("src", imageUrl);
                    img.one("load", function () {
                        setReq.done(function (data) {
                            $(featuredCardSelector).find(".rarityAndSet").text(
                                card.rarity + ", " + card.setName +
                                (data && data.set ? " (" + data.set.releaseDate.substring(0, 4) + ")" : ""));
                            $(featuredCardSelector).removeClass("offscreen");
                        })
                    });
                    img.on("error", function () {
                        if ($(this).attr("src") != card.imageUrl) {
                            // fall back to Gatherer if we unexpectedly have to
                            $(this).attr("src", card.imageUrl)
                        } else {
                            // Gatherer failed too, sandwich time
                            $(this).attr("src", "back.jpg");
                        }
                    });
                }
            });
    } else {
        $(featuredCardSelector).addClass("offscreen");
        $(featuredCardSelector).find(".img").off("load");
        $(featuredCardSelector).find(".img").off("error");
    }
}

function updateValue(elt, newValue, toggleOnZero) {
    if (!elt.text() || elt.text() != newValue) {
        var event;
        var duration;
        if (elt.css("transition-duration") != "0s") {
            event = "transitionend";
            duration = elt.css("transition-duration");
        } else if (elt.css("animation-duration") != "0s") {
            event = "animationend";
            duration = elt.css("animation-duration");
        }
        if (event) {
            duration = parseFloat(duration.substring(0, duration.length - 1)) * 1000;
            elt.off(event);
            elt.addClass("updating");
            var fallback;
            var update = function () {
                elt.text(newValue == "inf" ? "∞" : newValue);
                elt.removeClass("updating");
                elt.off(event);
                if (toggleOnZero) {
                    elt.toggle(newValue == "inf" || !!parseInt(newValue));
                }
                clearTimeout(fallback);
            };
            fallback = setTimeout(update, duration);
            elt.on(event, update);
        } else {
            elt.text(newValue);
        }
    }
}

// Update life totals, with debouncing
var updateP1Numbers = _.debounce(function(v) {
    updateValue($(".p1.life"), v.val().life);
    updateValue($(".p1.poison"), v.val().poison, true);
    if (v.val().gamewins > 0) {
        updateValue($(".p1.wins"), v.val().gamewins);
    } else {
        $(".p1.wins").text(v.val().gamewins);
    }
}, 1000);

var updateP2Numbers = _.debounce(function(v) {
    updateValue($(".p2.life"), v.val().life);
    updateValue($(".p2.poison"), v.val().poison, true);
    if (v.val().gamewins > 0) {
        updateValue($(".p2.wins"), v.val().gamewins);
    } else {
        $(".p2.wins").text(v.val().gamewins);
    }
}, 1000);

firebase.database().ref('player1').on('value', function (v) {
    updateP1Numbers(v);
    $(".p1.name").text(v.val().name);
    $(".p1.deck").text(v.val().deck);
    fillFeaturedCard(v.val().featuredcard, ".p1.featuredcard");
});
firebase.database().ref('p1deck').on('value', function (v) {
    var handElt = $(".p1.hand");
    fillHand(handElt, v.val());
    fillDeck($(".p1.sideboard"), v.val(), true);
});
firebase.database().ref('player2').on('value', function (v) {
    updateP2Numbers(v);
    $(".p2.name").text(v.val().name);
    $(".p2.deck").text(v.val().deck);
    fillFeaturedCard(v.val().featuredcard, ".p2.featuredcard");
});
firebase.database().ref('p2deck').on('value', function (v) {
    var handElt = $(".p2.hand");
    fillHand(handElt, v.val());
    fillDeck($(".p2.sideboard"), v.val(), true);
});
firebase.database().ref('chyron').on('value', function (v) {
    var single = $("#chyronSingle");
    single.text(v.val().single);
    single.removeData("Emoji");
    single.Emoji({path: 'https://rodrigopolo.github.io/jqueryemoji/img/apple72/'});
    $("#chyronLeft").text(v.val().left);
    $("#chyronRight").text(v.val().right);
});
<commit_msg>emojify decknames<commit_after>var modeRef = firebase.database().ref('mode');
modeRef.on('value', function (v) {
    var modes = v.val();
    for (mode in modes) {
        if (modes.hasOwnProperty(mode)) {
            $("#" + mode).toggleClass("inactive", !modes[mode]);
            if (mode == "chyron") {
                if (modes[mode] == "single") {
                    $("#chyronSingle").css("opacity", 1);
                    $("#chyronLeft").css("opacity", 0);
                    $("#chyronRight").css("opacity", 0);
                    $("#chyron").find(".logo").css("opacity", 0);
                } else {
                    $("#chyronSingle").css("opacity", 0);
                    $("#chyronLeft").css("opacity", 1);
                    $("#chyronRight").css("opacity", 1);
                    $("#chyron").find(".logo").css("opacity", 1);
                }
            }
        }
    }
});

var sets;
// Gatherer card images are low-res and blocky and ugly, so if we can, we want to use magiccards.info images.
// We need to translate from what Gatherer calls the set to what magiccards.info calls the set, though.
var gathererToMagiccardsInfo = [];
$.get("https://api.magicthegathering.io/v1/sets",
    function(data) {
        data.sets = _.sortBy(data.sets, function (x) {
            return (x.type == "promo" ? "p" : "") + x.releaseDate;
        });
        sets = _.map(data.sets, function (x) {
            return x.code;
        });

        gathererToMagiccardsInfo = _.object(
            sets,
            // If there's no magicCardsInfoCode, give up and return the normal code; fixes Kaladesh.
            _.map(data.sets, function(x) { return x.magicCardsInfoCode || x.code; }));
    });

function fillFeaturedCard(cardName, featuredCardSelector) {
    if (cardName != "") {
        // exact match on the name, because autocomplete in director.html should have
        // put an exact name there for us
        $.get("https://api.magicthegathering.io/v1/cards?name=\"" + cardName + "\"",
            function (data) {
                if (data.cards && data.cards.length > 0) {
                    data.cards = _.sortBy(data.cards, function (c) {
                        return sets.indexOf(c.set);
                    });
                    var card = data.cards[0];
                    var imageUrl = card.imageUrl;
                    if (card.set && card.number) {
                        // not all cards have a number (e.g. LEA Lightning Bolt)
                        imageUrl = ("http://magiccards.info/scans/en/" + gathererToMagiccardsInfo[card.set]
                                    + "/" + card.number + ".jpg").toLowerCase();
                    }
                    var setReq = Promise.resolve(null);
                    if (card.set) {
                        setReq = $.get("https://api.magicthegathering.io/v1/sets/" + card.set);
                    }
                    var img = $(featuredCardSelector).find(".img");
                    img.attr("src", imageUrl);
                    img.one("load", function () {
                        setReq.done(function (data) {
                            $(featuredCardSelector).find(".rarityAndSet").text(
                                card.rarity + ", " + card.setName +
                                (data && data.set ? " (" + data.set.releaseDate.substring(0, 4) + ")" : ""));
                            $(featuredCardSelector).removeClass("offscreen");
                        })
                    });
                    img.on("error", function () {
                        if ($(this).attr("src") != card.imageUrl) {
                            // fall back to Gatherer if we unexpectedly have to
                            $(this).attr("src", card.imageUrl)
                        } else {
                            // Gatherer failed too, sandwich time
                            $(this).attr("src", "back.jpg");
                        }
                    });
                }
            });
    } else {
        $(featuredCardSelector).addClass("offscreen");
        $(featuredCardSelector).find(".img").off("load");
        $(featuredCardSelector).find(".img").off("error");
    }
}

function updateValue(elt, newValue, toggleOnZero) {
    if (!elt.text() || elt.text() != newValue) {
        var event;
        var duration;
        if (elt.css("transition-duration") != "0s") {
            event = "transitionend";
            duration = elt.css("transition-duration");
        } else if (elt.css("animation-duration") != "0s") {
            event = "animationend";
            duration = elt.css("animation-duration");
        }
        if (event) {
            duration = parseFloat(duration.substring(0, duration.length - 1)) * 1000;
            elt.off(event);
            elt.addClass("updating");
            var fallback;
            var update = function () {
                elt.text(newValue == "inf" ? "∞" : newValue);
                elt.removeClass("updating");
                elt.off(event);
                if (toggleOnZero) {
                    elt.toggle(newValue == "inf" || !!parseInt(newValue));
                }
                clearTimeout(fallback);
            };
            fallback = setTimeout(update, duration);
            elt.on(event, update);
        } else {
            elt.text(newValue);
        }
    }
}

// Update life totals, with debouncing
var updateP1Numbers = _.debounce(function(v) {
    updateValue($(".p1.life"), v.val().life);
    updateValue($(".p1.poison"), v.val().poison, true);
    if (v.val().gamewins > 0) {
        updateValue($(".p1.wins"), v.val().gamewins);
    } else {
        $(".p1.wins").text(v.val().gamewins);
    }
}, 1000);

var updateP2Numbers = _.debounce(function(v) {
    updateValue($(".p2.life"), v.val().life);
    updateValue($(".p2.poison"), v.val().poison, true);
    if (v.val().gamewins > 0) {
        updateValue($(".p2.wins"), v.val().gamewins);
    } else {
        $(".p2.wins").text(v.val().gamewins);
    }
}, 1000);

firebase.database().ref('player1').on('value', function (v) {
    updateP1Numbers(v);
    $(".p1.name").text(v.val().name);
    var deck = $(".p1.deck");
    deck.text(v.val().deck);
    deck.removeData("Emoji");
    deck.Emoji({path: 'https://rodrigopolo.github.io/jqueryemoji/img/apple72/'});
    fillFeaturedCard(v.val().featuredcard, ".p1.featuredcard");
});
firebase.database().ref('p1deck').on('value', function (v) {
    var handElt = $(".p1.hand");
    fillHand(handElt, v.val());
    fillDeck($(".p1.sideboard"), v.val(), true);
});
firebase.database().ref('player2').on('value', function (v) {
    updateP2Numbers(v);
    $(".p2.name").text(v.val().name);
    var deck = $(".p2.deck");
    deck.text(v.val().deck);
    deck.removeData("Emoji");
    deck.Emoji({path: 'https://rodrigopolo.github.io/jqueryemoji/img/apple72/'});
    fillFeaturedCard(v.val().featuredcard, ".p2.featuredcard");
});
firebase.database().ref('p2deck').on('value', function (v) {
    var handElt = $(".p2.hand");
    fillHand(handElt, v.val());
    fillDeck($(".p2.sideboard"), v.val(), true);
});
firebase.database().ref('chyron').on('value', function (v) {
    var single = $("#chyronSingle");
    single.text(v.val().single);
    single.removeData("Emoji");
    single.Emoji({path: 'https://rodrigopolo.github.io/jqueryemoji/img/apple72/'});
    $("#chyronLeft").text(v.val().left);
    $("#chyronRight").text(v.val().right);
});
<|endoftext|>


<commit_before>var Platform = require('../../sys/Platform');
var Window = require('../../sys/Window');
var Program = require('../../p3d/Program');
var Mat4 = require('../../math/Mat4');
var Vec3 = require('../../math/Vec3');
var material = require('./BasicMateria.js');
var createIcosahedron = require('../../utils/primitive-icosahedron');
var toFlatGeometry = require('../../utils/geom-to-flat-geometry');
var computeNormals = require('../../utils/geom-compute-normals');
var subdivide = require('../../utils/geom-subdivide-camtull-clark');
var triangulate = require('../../utils/geom-triangulate');
var SimplexNoise = require('simplex-noise');
var simplex = new SimplexNoise(Math.random);
var R = require('ramda');
var clone = require('clone');

var VERT_SRC = '\
attribute vec4 aPosition; \
attribute vec3 aNormal; \
varying vec4 vColor; \
uniform mat4 uProjectionMatrix;\
uniform mat4 uViewMatrix;\
uniform mat4 uModelMatrix;\
void main() { \
    gl_Position = uProjectionMatrix * uViewMatrix * uModelMatrix * aPosition; \
    vColor = vec4(aNormal * 0.5 + 0.5, 1.0); \
} \
';

var FRAG_SRC = '\
varying vec4 vColor; \
void main() { \
    gl_FragColor = vColor; \
} \
';

if (Platform.isBrowser) {
    FRAG_SRC = 'precision highp float; \n' + FRAG_SRC;
}

Window.create({
    settings: {
        type: '3d',
        width: 800,
        height: 600
    },
    init: function() {
        var ctx = this.getContext();

        this.model = Mat4.create();
        this.projection = Mat4.perspective(Mat4.create(), 45, this.getAspectRatio(), 0.001, 10.0);
        this.view = Mat4.lookAt([], [3, 2, 2], [0, 0, 0], [0, 1, 0]);

        this.program = ctx.createProgram(VERT_SRC, FRAG_SRC);
        ctx.bindProgram(this.program);
        var g = createIcosahedron(2);
        g = subdivide(g);
        g = subdivide(g);
        g = subdivide(g);
        g = subdivide(g);
        g = triangulate(g);
        g = toFlatGeometry(g);
        g.normals = computeNormals(g);

        this.baseGeometry = g;
        this.positions = clone(g.positions);
        var positionArray   = this.positionArray  = new Float32Array(R.flatten(g.positions));
        var positionBuffer  = this.positionBuffer = ctx.createBuffer(ctx.ARRAY_BUFFER, positionArray, ctx.DYNAMIC_DRAW);
        var normalArray     = this.normalArray    = new Float32Array(R.flatten(g.normals));
        var normalBuffer    = this.normalBuffer   = ctx.createBuffer(ctx.ARRAY_BUFFER, normalArray, ctx.DYNAMIC_DRAW);
        var indexBuffer     = this.indexBuffer    = ctx.createBuffer(ctx.ELEMENT_ARRAY_BUFFER, new Uint16Array(R.flatten(g.cells)), ctx.STATIC_DRAW);
        var attributes = [
            { buffer: positionBuffer, location: ctx.ATTRIB_POSITION, size: 3 },
            { buffer: normalBuffer, location: ctx.ATTRIB_NORMAL, size: 3 }
        ];
        this.vao = ctx.createVertexArray(attributes, indexBuffer);
    },
    time: 0,
    prevTime: Date.now(),
    update: function() {
        var gl = this.getContext().getGL();
        gl.finish();

        console.log('--');
        console.time('update');
        var now = Date.now();
        this.time += (now - this.prevTime)/1000;
        this.prevTime = now;

        var time = this.time;
        var basePositions = this.baseGeometry.positions;
        var baseNormals = this.baseGeometry.normals;
        var positions = this.positions;
        var noiseFrequency = 2;
        var noiseScale = 0.75;
        console.time('noise');
        for(var i = 0, len = basePositions.length; i<len; i++) {
            var p = basePositions[i];
            var f = simplex.noise3D(p[0] * noiseFrequency + time, p[1] * noiseFrequency, p[2] * noiseFrequency)
            Vec3.set(positions[i], p);
            Vec3.scale(positions[i], 1 + noiseScale * f);
        }
        console.timeEnd('noise');

        console.time('normals');
        var normals = computeNormals({ cells: this.baseGeometry.cells, positions: this.positions });
        console.timeEnd('normals');

        console.time('flatten');
        this.positionArray.set(R.flatten(positions));
        this.normalArray.set(R.flatten(normals));
        console.timeEnd('flatten');

        gl.finish();
        console.time('buffer');
        this.positionBuffer.bufferData(this.positionArray);
        this.normalBuffer.bufferData(this.normalArray);
        gl.finish();
        console.timeEnd('buffer');
        console.timeEnd('update');
    },
    draw: function() {
        this.update();

        var ctx = this.getContext();
        ctx.setClearColor(0.2, 0.2, 0.2, 1);
        ctx.clear(ctx.COLOR_BIT | ctx.DEPTH_BIT);
        ctx.setDepthTest(true);

        var speed = 0.2;

        ctx.setViewMatrix(Mat4.lookAt9(this.view,
                Math.cos(speed * this.time * Math.PI) * 5,
                Math.sin(speed * this.time * 0.5) * 0,
                Math.sin(speed * this.time * Math.PI) * 5,
                0,0,0,0,1,0
            )
        );

        ctx.bindTexture(this.tex, 0);

        ctx.setProjectionMatrix(this.projection);
        ctx.setViewMatrix(this.view);
        ctx.setModelMatrix(this.model);
        ctx.bindVertexArray(this.vao);

        ctx.bindProgram(this.program);
        //would that be too much to do manually?
        this.program.setUniform('uProjectionMatrix', ctx.getProjectionMatrix());
        this.program.setUniform('uViewMatrix', ctx.getViewMatrix());
        this.program.setUniform('uModelMatrix', ctx.getModelMatrix());
        ctx.drawElements(ctx.TRIANGLES, this.vao.getIndexBuffer().getLength(), 0);
    }
})
<commit_msg>06-pex-ctx-00 DynamicNoise manual flattening <commit_after>var Platform = require('../../sys/Platform');
var Window = require('../../sys/Window');
var Program = require('../../p3d/Program');
var Mat4 = require('../../math/Mat4');
var Vec3 = require('../../math/Vec3');
var material = require('./BasicMateria.js');
var createIcosahedron = require('../../utils/primitive-icosahedron');
var toFlatGeometry = require('../../utils/geom-to-flat-geometry');
var computeNormals = require('../../utils/geom-compute-normals');
var subdivide = require('../../utils/geom-subdivide-camtull-clark');
var triangulate = require('../../utils/geom-triangulate');
var SimplexNoise = require('simplex-noise');
var simplex = new SimplexNoise(Math.random);
var R = require('ramda');
var clone = require('clone');

var VERT_SRC = '\
attribute vec4 aPosition; \
attribute vec3 aNormal; \
varying vec4 vColor; \
uniform mat4 uProjectionMatrix;\
uniform mat4 uViewMatrix;\
uniform mat4 uModelMatrix;\
void main() { \
    gl_Position = uProjectionMatrix * uViewMatrix * uModelMatrix * aPosition; \
    vColor = vec4(aNormal * 0.5 + 0.5, 1.0); \
} \
';

var FRAG_SRC = '\
varying vec4 vColor; \
void main() { \
    gl_FragColor = vColor; \
} \
';

if (Platform.isBrowser) {
    FRAG_SRC = 'precision highp float; \n' + FRAG_SRC;
}

Window.create({
    settings: {
        type: '3d',
        width: 800,
        height: 600
    },
    init: function() {
        var ctx = this.getContext();

        this.model = Mat4.create();
        this.projection = Mat4.perspective(Mat4.create(), 45, this.getAspectRatio(), 0.001, 10.0);
        this.view = Mat4.lookAt([], [3, 2, 2], [0, 0, 0], [0, 1, 0]);

        this.program = ctx.createProgram(VERT_SRC, FRAG_SRC);
        ctx.bindProgram(this.program);
        var g = createIcosahedron(2);
        g = subdivide(g);
        g = subdivide(g);
        g = subdivide(g);
        g = subdivide(g);
        g = triangulate(g);
        g = toFlatGeometry(g);
        g.normals = computeNormals(g);

        this.baseGeometry = g;
        this.positions = clone(g.positions);
        var positionArray   = this.positionArray  = new Float32Array(R.flatten(g.positions));
        var positionBuffer  = this.positionBuffer = ctx.createBuffer(ctx.ARRAY_BUFFER, positionArray, ctx.DYNAMIC_DRAW);
        var normalArray     = this.normalArray    = new Float32Array(R.flatten(g.normals));
        var normalBuffer    = this.normalBuffer   = ctx.createBuffer(ctx.ARRAY_BUFFER, normalArray, ctx.DYNAMIC_DRAW);
        var indexBuffer     = this.indexBuffer    = ctx.createBuffer(ctx.ELEMENT_ARRAY_BUFFER, new Uint16Array(R.flatten(g.cells)), ctx.STATIC_DRAW);
        var attributes = [
            { buffer: positionBuffer, location: ctx.ATTRIB_POSITION, size: 3 },
            { buffer: normalBuffer, location: ctx.ATTRIB_NORMAL, size: 3 }
        ];
        this.vao = ctx.createVertexArray(attributes, indexBuffer);
    },
    time: 0,
    prevTime: Date.now(),
    update: function() {
        var gl = this.getContext().getGL();
        gl.finish();

        console.log('--');
        console.time('update');
        var now = Date.now();
        this.time += (now - this.prevTime)/1000;
        this.prevTime = now;

        var time = this.time;
        var basePositions = this.baseGeometry.positions;
        var baseNormals = this.baseGeometry.normals;
        var positions = this.positions;
        var noiseFrequency = 2;
        var noiseScale = 0.75;
        console.time('noise');
        for(var i = 0, len = basePositions.length; i<len; i++) {
            var p = basePositions[i];
            var f = simplex.noise3D(p[0] * noiseFrequency + time, p[1] * noiseFrequency, p[2] * noiseFrequency)
            Vec3.set(positions[i], p);
            Vec3.scale(positions[i], 1 + noiseScale * f);
        }
        console.timeEnd('noise');

        console.time('normals');
        var normals = computeNormals({ cells: this.baseGeometry.cells, positions: this.positions });
        console.timeEnd('normals');

        console.time('flatten');
        //R.flatten = 20ms
        //this.positionArray.set(R.flatten(positions));
        //this.normalArray.set(R.flatten(normals));

        //for loop = 1-2ms
        for(var i=0, len=positions.length; i<len; i++) {
            this.positionArray[i*3  ] = positions[i][0];
            this.positionArray[i*3+1] = positions[i][1];
            this.positionArray[i*3+2] = positions[i][2];
        }
        for(var i=0, len=normals.length; i<len; i++) {
            this.normalArray[i*3  ] = normals[i][0];
            this.normalArray[i*3+1] = normals[i][1];
            this.normalArray[i*3+2] = normals[i][2];
        }
        console.timeEnd('flatten');

        gl.finish();
        console.time('buffer');
        this.positionBuffer.bufferData(this.positionArray);
        this.normalBuffer.bufferData(this.normalArray);
        gl.finish();
        console.timeEnd('buffer');
        console.timeEnd('update');
    },
    draw: function() {
        this.update();

        var ctx = this.getContext();
        ctx.setClearColor(0.2, 0.2, 0.2, 1);
        ctx.clear(ctx.COLOR_BIT | ctx.DEPTH_BIT);
        ctx.setDepthTest(true);

        var speed = 0.2;

        ctx.setViewMatrix(Mat4.lookAt9(this.view,
                Math.cos(speed * this.time * Math.PI) * 5,
                Math.sin(speed * this.time * 0.5) * 0,
                Math.sin(speed * this.time * Math.PI) * 5,
                0,0,0,0,1,0
            )
        );

        ctx.bindTexture(this.tex, 0);

        ctx.setProjectionMatrix(this.projection);
        ctx.setViewMatrix(this.view);
        ctx.setModelMatrix(this.model);
        ctx.bindVertexArray(this.vao);

        ctx.bindProgram(this.program);
        //would that be too much to do manually?
        this.program.setUniform('uProjectionMatrix', ctx.getProjectionMatrix());
        this.program.setUniform('uViewMatrix', ctx.getViewMatrix());
        this.program.setUniform('uModelMatrix', ctx.getModelMatrix());
        ctx.drawElements(ctx.TRIANGLES, this.vao.getIndexBuffer().getLength(), 0);
    }
})
<|endoftext|>


<commit_before>// this is to transform the Fishes.json and gnis_places.json into
// individual fish species files.
// it runs under node.js
// it will not overwrite any existing files

var fs = require('fs');

var fishes = require('./Fishes.json');

var places = require('../gnis_places.json');

// loop through the species and write out each file
var species = fishes.forEach(function(f) {
	var filename = 'species/' + f.CommonName.toLowerCase().replace(/ +/, '_') + '.json';
	fs.exists(filename, function(exists) {
		if (exists) {
			console.log('skipping', f.CommonName);
			return;
		}
		// illegal to catch herring, skip this family
		if (f.Family == 7) {
			console.log('skipping herring family species', f.CommonName);
			return;
		}
		fs.writeFile(
			filename,
			'[\n' + JSON.stringify(
				{
					"_comment": "This file was generated by a script and has not been reviewed for accuracy. Please remove this comment after reviewing.",
					"state": "Virginia",
					"agency": "Department of Game and Inland Fisheries",
					"date_effective": "2013-07-01",
					"date_expires": "2014-06-30",
					"schema": "",
					"schema_version": "1.0a",
					"documentation": "",
					"species": {
						"name": f.CommonName,
						"taxonomy": f.ScientificName,
						"bova_id": parseInt(f.BOVA),
						"images": [	],
						"aliases": f.OtherNames.split(', '),
						"identification": getIdentificationString(f.Family, f.Identification)
					},
					"limits": {}, // TODO: placeholder, limits are not available in the data source yet
					"best_fishing": parseBestFishing(f.BestFishingNarrative),
					"fishing_techniques": f.Fishing
				}, null, "\t") + '\n]\n',
			function(error) {
				if (error) { console.log('error', f.CommonName); console.log(error); }
				else { console.log('saved', f.CommonName); }
			}
		);
	});
});

function parseBestFishing(str) {
	var str = str.replace(/\\n/,' ');
	var obj = {
		// this is a new field, to save the full best fishing text for convenience
		"description": str,
		"lakes": {},
		"rivers": {}
	};

	var riverIndex = str.indexOf("Rivers:");
	if (riverIndex == -1) riverIndex = str.indexOf("Rivers and Streams:");
	var lakeIndex = str.indexOf("Lakes:");

	var parseInternal = function(prop, marker, otherMarker, altMarker, altOtherMarker) {
		var index1 = str.indexOf(marker);
		if (index1 == -1 && altMarker) {
			index1 = str.indexOf(altMarker);
			marker = altMarker;
		}
		var index2 = str.indexOf(otherMarker);
		if (index2 == -1 && altOtherMarker) {
			index2 = str.indexOf(altOtherMarker);
			otherMarker = altOtherMarker;
		}
		// TODO: comment field of place object
		if (index1 != -1) {
			var end = index2 > index1 ? index2 : str.length;
			var list = str.substring(index1 + marker.length, end);
			list.split(',').forEach(function(i) {
				i.split(/\band\b/).forEach(function(j) {
					j.split('/').forEach(function(k) {
						k.split(';').forEach(function(m) {
							var name = m.replace('.', '').trim();
							if (name && name.length > 1) {
								obj[prop][name] = lookupGnis(name, prop);
							}
						});
					});
				});
			});
		}
	}

	parseInternal("lakes", "Lakes:", "Rivers:", null, "Rivers and Streams:");
	parseInternal("rivers", "Rivers:", "Lakes:", "Rivers and Streams:", null);

	return obj;
}

function getIdentificationString(family, identification) {
	// from fish_families.json, easier to just hardcode it
	var families = {
		1: "Sunfish",
		2: "Striped Bass",
		3: "Perch",
		4: "Pike",
		5: "Trout",
		6: "Catfish"
	};

	var fam = families[family];
	if (fam == undefined) return identification;
	return fam + ' family. ' + identification;
}

var _lookupGnisCache = {};
function lookupGnis(name, type, contains) {
	var cached;
	if (cached = _lookupGnisCache[type + "/" + name])
		return cached;

	// some cleanup
	name = name.replace(/(\bthe\b|\btidal\b|\bmainstem\b|\(.*|\))/,'').trim();
	// type is 'rivers' or 'lakes'
	var obj = { "gnis_id": null };
	var classes = [];
	var names = [];
	if (type == 'rivers') {
		classes = ['Stream'];
		names = [ name, name + ' River', name + ' Creek' ];
	} else if (type == 'lakes') {
		classes = ['Reservoir', 'Lake'];
		names = [ name, name + ' Lake', 'Lake ' + name, name + ' Reservoir', name + ' Lake (historical)' ];
	} else return obj;

	var matches = places.filter(function(p) {
		if (!contains) {
			return classes.indexOf(p.feature_class) != -1 &&
				names.indexOf(p.feature_name) != -1;
		} else {
			return classes.indexOf(p.feature_class) != -1 &&
				p.feature_name.indexOf(name) != -1;
		}
	});

	if (matches.length == 0) {
		// no exact matches, try contains match
		if (!contains) return lookupGnis(name, type, true);
		console.log('GNIS: No match for', name);
	} else if (matches.length == 1 || !contains) {
		// multiple exact match results considered equivalent
		obj.gnis_id = matches[0].feature_id;
		// new fields
		obj.latitude = matches[0].prim_lat_dec;
		obj.longitude = matches[0].prim_long_dec;
	} else {
		console.log('GNIS: Found', matches.length, 'matches for', name);
		matches.forEach(function (m) {
			console.log('*', m.feature_name, '/', m.prim_lat_dec, ',', m.prim_long_dec);
		});
	}

	_lookupGnisCache[type + "/" + name] = obj;
	return obj;
}<commit_msg>Comments and cleanup.<commit_after>// this is to transform the Fishes.json and gnis_places.json into
// individual fish species files.
// it runs under node.js
// it will not overwrite any existing files

var fs = require('fs');

var fishes = require('./Fishes.json');

var places = require('../gnis_places.json');

// loop through the species and write out each file
var species = fishes.forEach(function(f) {
	var filename = 'species/' + f.CommonName.toLowerCase().replace(/ +/, '_') + '.json';
	fs.exists(filename, function(exists) {
		if (exists) {
			console.log('skipping', f.CommonName);
			return;
		}
		// illegal to catch herring, skip this family
		if (f.Family == 7) {
			console.log('skipping herring family species', f.CommonName);
			return;
		}
		fs.writeFile(
			filename,
			'[\n' + JSON.stringify(
				{
					"_comment": "This file was generated by a script and has not been reviewed for accuracy. Please remove this comment after reviewing.",
					"state": "Virginia",
					"agency": "Department of Game and Inland Fisheries",
					"date_effective": "2013-07-01",
					"date_expires": "2014-06-30",
					"schema": "",
					"schema_version": "1.0a",
					"documentation": "",
					"species": {
						"name": f.CommonName,
						"taxonomy": f.ScientificName,
						"bova_id": parseInt(f.BOVA),
						"images": [	],
						"aliases": f.OtherNames.split(', '),
						"identification": getIdentificationString(f.Family, f.Identification)
					},
					"limits": {}, // TODO: placeholder, limits are not available in the data source yet
					"best_fishing": parseBestFishing(f.BestFishingNarrative),
					"fishing_techniques": f.Fishing
				}, null, "\t") + '\n]\n',
			function(error) {
				if (error) { console.log('error', f.CommonName); console.log(error); }
				else { console.log('saved', f.CommonName); }
			}
		);
	});
});

// parse a 'BestFishingNarrative' string to extract place names.
// returns a 'best_fishing' object with lakes and rivers populated.
function parseBestFishing(str) {
	var str = str.replace(/\\n/,' ');
	var obj = {
		// this is a new field, to save the full best fishing text for convenience
		"description": str,
		"lakes": {},
		"rivers": {}
	};

	// this function parses either rivers or lakes depending on what is passed
	// supports alternate marker text because sometimes the rivers start with
	// 'Rivers:' and sometimes 'Rivers and Streams:'
	var parseInternal = function(prop, marker, otherMarker, altMarker, altOtherMarker) {
		// this is the start index of the section we want
		var index1 = str.indexOf(marker);
		if (index1 == -1 && altMarker) {
			index1 = str.indexOf(altMarker);
			marker = altMarker;
		}
		// this is the start index of the other section, so we know where to stop
		var index2 = str.indexOf(otherMarker);
		if (index2 == -1 && altOtherMarker) {
			index2 = str.indexOf(altOtherMarker);
			otherMarker = altOtherMarker;
		}
		// TODO: comment field of place object
		if (index1 != -1) {
			// determine the end of our list
			var end = index2 > index1 ? index2 : str.length;
			// get the text minus the initial marker
			var list = str.substring(index1 + marker.length, end);
			// successively split until we have a single place name
			list.split(',').forEach(function(i) {
				i.split(/\band\b/).forEach(function(j) {
					j.split('/').forEach(function(k) {
						k.split(';').forEach(function(m) {
							var name = m.replace('.', '').trim();
							if (name && name.length > 1) {
								// populate the object with the GNIS lookup result
								obj[prop][name] = lookupGnis(name, prop);
							}
						});
					});
				});
			});
		}
	}

	// now we actually call the parsing function with different parameters
	parseInternal("lakes", "Lakes:", "Rivers:", null, "Rivers and Streams:");
	parseInternal("rivers", "Rivers:", "Lakes:", "Rivers and Streams:", null);

	return obj;
}

// get the identification string we need - if the family is known we prepend it
function getIdentificationString(family, identification) {
	// from fish_families.json, easier to just hardcode it
	var families = {
		1: "Sunfish",
		2: "Striped Bass",
		3: "Perch",
		4: "Pike",
		5: "Trout",
		6: "Catfish"
	};

	var fam = families[family];
	if (fam == undefined) return identification;
	return fam + ' family. ' + identification;
}

var _lookupGnisCache = {};
// look up a place name in GNIS and return a place object
// optionally, do a contains, rather than exact, match
// also cache it if it's already been done
function lookupGnis(name, type, contains) {
	var cached;
	if (cached = _lookupGnisCache[type + "/" + name])
		return cached;

	// some cleanup
	name = name.replace(/(\bthe\b|\btidal\b|\bmainstem\b|\(.*|\))/,'').trim();
	// type is 'rivers' or 'lakes'
	// populate the basic object and then some matches to do
	var obj = { "gnis_id": null };
	var classes = [];
	var names = [];
	if (type == 'rivers') {
		classes = ['Stream'];
		names = [ name, name + ' River', name + ' Creek' ];
	} else if (type == 'lakes') {
		classes = ['Reservoir', 'Lake'];
		names = [ name, name + ' Lake', 'Lake ' + name, name + ' Reservoir', name + ' Lake (historical)' ];
	} else return obj;

	// do the filter and handle the results
	var matches = places.filter(function(p) {
		if (!contains) {
			return classes.indexOf(p.feature_class) != -1 &&
				names.indexOf(p.feature_name) != -1;
		} else {
			return classes.indexOf(p.feature_class) != -1 &&
				p.feature_name.indexOf(name) != -1;
		}
	});

	if (matches.length == 0) {
		// no exact matches, try contains match
		if (!contains) return lookupGnis(name, type, true);
		console.log('GNIS: No match for', name);
	} else if (matches.length == 1 || !contains) {
		// multiple exact match results considered equivalent
		obj.gnis_id = matches[0].feature_id;
		// new fields
		obj.latitude = matches[0].prim_lat_dec;
		obj.longitude = matches[0].prim_long_dec;
	} else {
		// do not add ambiguous places, this only happens on contains matches
		console.log('GNIS: Found', matches.length, 'matches for', name);
		matches.forEach(function (m) {
			console.log('*', m.feature_name, '/', m.prim_lat_dec, ',', m.prim_long_dec);
		});
	}

	_lookupGnisCache[type + "/" + name] = obj;
	return obj;
}<|endoftext|>


<commit_before>var self = this;

define([
	"intern!object",
	"intern/chai!assert",
	"require",
	"src/qunit-desktop-notifications"
], function ( registerSuite, assert, require, qunit, qunitDesktopNotifications ) {
	registerSuite({
		name: "Smoke test",
		"QUnitDesktopNotifications is created.": function () {
			assert.equal( typeof self.QUnitDesktopNotifications, "object", "OK" );
		},
		"QUnitDesktopNotifications is exposed as window property.": function () {
			if ( typeof window !== "undefined" ) {
				assert.equal( typeof window.QUnitDesktopNotifications, "object", "OK" );
			} else {
				this.skip( "Browser context required, but missing." );
			}
		}
	});
});<commit_msg>Tests: smoke test for checking if library is exposed as global property<commit_after>var self = this;

define([
	"intern!object",
	"intern/chai!assert",
	"require",
	"src/qunit-desktop-notifications"
], function ( registerSuite, assert, require, qunit ) {
	registerSuite({
		name: "Smoke test",
		"QUnitDesktopNotifications is created.": function () {
			/** Smoke test checking if QUnitDesktopNotifications is executed without syntax errors */
			assert.equal( typeof self.QUnitDesktopNotifications, "object", "OK" );
		},
		"QUnitDesktopNotifications is exposed as window property.": function () {
			/** Smoke test checking kind of the same as the previous test, but with browser context. */
			if ( typeof window !== "undefined" ) {
				assert.equal( typeof window.QUnitDesktopNotifications, "object", "OK" );
			} else {
				this.skip( "Browser context required, but missing." );
			}
		}
	});
});<|endoftext|>