<commit_before>// define namespace to prevent loading js files multiple times
var pepdb = pepdb || {};

$.ajaxSetup ({
    cache: false
});

var isFirstLoad = function(namesp, jsFile) {
  var isFirst = namesp.firstLoad === undefined;
  namesp.firstLoad = false;

  return isFirst;
};

function stopTableSorting(e) {
    if (!e) var e = window.event;
    e.cancelBubble = true;
    if (e.stopPropagation) e.stopPropagation();
}

/* get url parameter "name" or return "" if does not exist */
function urlParam(name){
  var result = new RegExp('[\\?&]' + name + '=([^&#]*)').exec(window.location.href);
  return result && unescape(result[1]) || "";
}

$(document).ready(function(){
  function baseDir(){
    var url = document.location.pathname.split('/')[1];
    if (url == "pepdb"){
      return '/'+url;
    }else{
      return '';
    }
  };

  var url = baseDir();
  var formAll = ["#all_lib", "#all_sel", "#all_ds", "#c_all_lib", "#r_all_lib", "#all_motl"];
  var propSelect = ['#l', '#s', '#ds', '#c', '#ts', '#tt', '#tc', '#ss', '#st', '#sc'];
  var propInput = ['#seq', '#blos', '#pl', '#sr', '#ralt', '#ragt', '#relt', '#regt', '#dlt', '#dgt'];
  var species = ['#ss', '#ts'];
  var tissue = ['#st', '#tt'];
  var cell = ['#sc', '#tc'];

  $('.optbut').button();
  $('#navigation').menu();
  $('.editlink').button();
  $('.deletelink').button();

  $('#clear-button').click(function(){
    $('body').load(window.location.pathname);
  });

  $.each(formAll, function(index, value){
    $(value).click(function(){
      var marked = this.checked;
      $(this).closest('fieldset').find(':checkbox').each(function(){
        $(this).prop('checked', marked);
      });
    });
  });

  $('#comp-library input:checkbox').click(function(){
    var checkedLibs = [];
    $(this).closest('fieldset').find(':checkbox').each(function(){
      var elemVal = $(this).attr('value');
      if(this.checked && elemVal != "all_lib"){
        checkedLibs.push(elemVal);
      }
    });
    $('#comp-selection').load(url+'/checklist',{checkedElem: checkedLibs, allElem: 'c_all_sel', allElemVal: 'all_sel', selector: 'sel', sec: 'c_', elemName: 'sels[]' }, function(){
        $.getScript(url+"/script/checkbox.js");
      } );
  });

  $('#ref-library input:checkbox').click(function(){
    var checkedLibs = [];
    $(this).closest('fieldset').find(':checkbox').each(function(){
      var elemVal = $(this).attr('value');
      if(this.checked && elemVal != "all_lib"){
        checkedLibs.push(elemVal);
      }
    });
    $('#ref-selection').load(url+'/checklist',{checkedElem: checkedLibs, allElem: 'r_all_sel', allElemVal: 'all_sel', selector: 'sel', sec: 'r_', elemName: 'sels[]' }, function(){
        $.getScript(url+"/script/checkbox.js");
      } );
  });

  $('#motif-list input:radio').click(function(){
    if($('#motifs').is(':visible')){
      $('#motifs').toggle();
    }
    var checkedList = $(this).val();
    $.get('mot-checklist', {checkedElem: checkedList},function(data){
      $('#motifs').html(data);
      $.getScript(url+"/script/initshowtable.js", function(){
        $('#motifs').toggle();
      });

    });
  });

   $('#compdata').submit(function(){
    if($('#comppepresults').is(':visible')){
      $('#comppepresults').toggle();
    }
    if($('.loading').is(':hidden')){
      $('.loading').toggle();
    }
    $('#infos').html("");
    $.ajax({
      data: $(this).serialize(),
      type: $(this).attr('method'),
      url: $(this).attr('action'),
      success: function(response){
        $('#comppepresults').html(response);
        $.getScript(url+'/script/initshowtable.js', function(){
          $('#comppepresults').toggle();
          $('.loading').toggle();
        });
      }
    });
    return false;
  });

   $('#motsearch').submit(function(){
    if($('#motresults').is(':visible')){
      $('#motresults').toggle();
    }
    if($('.loading').is(':hidden')){
      $('.loading').toggle();
    }
    $.ajax({
      data: $(this).serialize(),
      type: $(this).attr('method'),
      url: $(this).attr('action'),
      success: function(response){
        $('#motresults').html(response);
        $.getScript(url+'/script/accinit.js', function(){
          $('#motresults').toggle();
          $('.loading').toggle();
        });
      }
    });
    return false;
  });

  $('#cl-search').submit(function(){
    if($('#clpepresults').is(':visible')){
      $('#clpepresults').toggle();
    }
    if($('#clsearch').is(':visible')){
      $('#clsearch').toggle();
    }
    $('#clpepresults').html("");
    $('#clsearchpeps').html("");
    $.ajax({
      data: $(this).serialize(),
      type: $(this).attr('method'),
      url: $(this).attr('action'),
      success: function(response){
        $('#clpepresults').html(response);
        $.getScript(url+'/script/tableinit.js', function(){
          $('#clpepresults').toggle();
        });
      }
    });
    return false;
  });

    $('#datatype').change(function(){
      var selected = $(this).children("option:selected").text();
      if(selected == "sequencing dataset"){
        selected = "dataset";
      }
      if(selected == "motif list"){
        selected = "motif";
      }
      $("#dataform").load(url+'/add'+ selected, function(){
        var boxNames = ['#dlibname', '#dselname', '#ddsname', '#dspecies'];

        $.each(boxNames, function(index, value){
          $(value).prop('selectedIndex', -1);
        });

        $('#dspecies').change(function(){
          var valSel = $(this).children("option:selected").text();
          $.get(url+'/formdrop', {columnname: "tissue", selected1: valSel, table:"targets", where1:"species", boxID:"dtissue"}, function(data){
            $('#dtissue').html(data);
            $('#dtissue').prop('selectedIndex', -1);
            $('#dcell').html('');
          });
        });
        $('#dtissue').change(function(){
          var valSel1 = $('#dspecies').children("option:selected").text();
          var valSel2 = $(this).children("option:selected").text();
          $.get(url+'/formdrop', {columnname: "cell", selected1: valSel1, selected2: valSel2,table:"targets", where2:"tissue", where1:"species",boxID:"dcell"}, function(data){
            $('#dcell').html(data);
          });
        });
        $('#dlibname').change(function(){
          var valSel = $(this).children("option:selected").text();
          $.get(url+'/formdrop', {columnname: "selection_name", selected1: valSel, table:"selections", where1:"library_name", boxID:"dselname"}, function(data){
            $('#dselname').html(data);
            $('#dselname').prop('selectedIndex', -1);
            $('#ddsname').prop('selectedIndex', -1);
          });
        });
        $('#dselname').change(function(){
          var valSel1 = $('#dlibname').children("option:selected").text();
          var valSel2 = $(this).children("option:selected").text();
          $.get(url+'/formdrop', {columnname: "dataset_name", selected1: valSel1, selected2: valSel2, table:"sequencing_datasets", where1:"library_name", where2:"selection_name",boxID:"dselname"}, function(data){
            $('#ddsname').html(data);
            $('#ddsname').prop('selectedIndex', -1);
          });
        });
      });
    });

    $.each(propSelect, function(index, value){
      var paramName = $(value).attr('name');
      if(urlParam(paramName) == ""){
        $(value).prop('selectedIndex', -1);
      }
      $(value).on('beforeunload', function(){
        if ($(this).attr('selectedIndex') == -1){
          $(this).prop('name', '');
        }
        });
      });

    $('#edittype').change(function(){
      var selected = $(this).children("option:selected").val();
      $.get(url+'/editdrop', {table:selected}, function(data){
        $('#elementselection').html(data);
        $.getScript(url+'/script/dropbox.js');
      });
    });

   $('#propsearch').submit(function(){
    if($('#propresults').is(':visible')){
      $('#propresults').toggle();
    }
    if($('.loading').is(':hidden')){
      $('.loading').toggle();
    }
    $.ajax({
      data: $(this).serialize(),
      type: $(this).attr('method'),
      url: $(this).attr('action'),
      success: function(response){
        $('#propresults').html(response);
        $.getScript(url+'/script/initshowtable.js', function(){
          $('#propresults').toggle();
          $('.loading').toggle();
        });
      }
    });
    return false;
  });
    $.each(species, function(index, value){
      $(value).change(function(){
        var valSel = $(this).children("option:selected").text();
        $.get(url+'/formdrop', {columnname: "tissue", selected1: valSel, table:"targets", where1:"species", boxID:tissue[index].substring(1)}, function(data){
          $(tissue[index]).html(data);
          $(tissue[index]).prop('selectedIndex', -1);
          $(cell[index]).html('');
        });
      });
    });

    $.each(tissue, function(index, value){
      $(value).change(function(){
        var valSel1 = $(species[index]).children("option:selected").text();
        var valSel2 = $(this).children("option:selected").text();
        $.get(url+'/formdrop', {columnname: "cell", selected1: valSel1, selected2: valSel2,table:"targets", where2:"tissue", where1:"species",boxID:cell[index].substring(1)}, function(data){
          $(cell[index]).html(data);
        });
      });

    });

    $('#l').change(function(){
      var valSel = $(this).children("option:selected").text();
      $.get(url+'/formdrop', {columnname: "selection_name", selected1: valSel, table:"selections", where1:"library_name", boxID:"s"}, function(data){
        $('#s').html(data);
        $('#s').prop('selectedIndex', -1);
        $('#ds').prop('selectedIndex', -1);
      });
    });
    $('#s').change(function(){
      var valSel1 = $(this).children("option:selected").text();
      $.get(url+'/formdrop', {columnname: "dataset_name", selected1: valSel1,table:"sequencing_datasets", where1:"selection_name",boxID:"ds"}, function(data){
        $('#ds').html(data);
        $('#ds').prop('selectedIndex', -1);
      });
    });

   $('#compclsub').submit(function(){
    if($('#compclresults').is(':visible')){
      $('#compclresults').toggle();
    }
    if($('.loading').is(':hidden')){
      $('.loading').toggle();
    }
    $.ajax({
      data: $(this).serialize(),
      type: $(this).attr('method'),
      url: $(this).attr('action'),
      error: function(response,error1,error2){
        $.get(url+'/error', {error:error2},function(response){
          $('#compclresults').html(response);
          $('#compclresults').toggle();
          $('.loading').toggle();
        });
      },
      success: function(response){
        $('#compclresults').html(response);
          $.getScript(url+'/script/initshowtable.js', function(){
            $('#compclresults').toggle();
            $('.loading').toggle();
          });
    }
  });
    return false;
  });

    $('#type').change(function(){
      if ($(this).val() == "complete sequence"){
        $('#blossum').show();
        $('#wchelp').hide();
        $('#bshelp').show();
      } else if ($(this).val() == "wildcard sequence"){
        $('#blossum').hide();
        $('#wchelp').show();
        $('#bshelp').hide();
      } else {
        $('#blossum').hide();
        $('#wchelp').hide();
        $('#bshelp').hide();

      }
    });
    $('#wcicon').tooltip({
      content: function(callback){
        callback($(this).prop('title').replace(/\|/g, '
'));
      }
    });
    $('#bsicon').tooltip({
      content: function(callback){
        callback($(this).prop('title').replace(/\|/g, '
'));
      }
    });

    $('.editlink').click(function(e){
      e.preventDefault();
      var link = $(this).attr('href');
      $.get(link, function(response){
        $('#editusers').html(response);
      });
    })

    /* -----------jsTree configuration------------------- */
    $('#clusterlist').bind("loaded.jstree", function(){
     var opennode = document.location.pathname.split("/").pop();
     $('#' + opennode).parents(".jstree-closed").each(function(){
        $('#clusterlist').jstree("open_node", this, false, true);
      });
    });

    $('#clusterlist').bind('before.jstree', function(event,data){
      switch(data.plugin){
        case 'ui':
          if(!data.inst.is_leaf(data.args[0])){
            return false;
          }
          break;
        default:
          break;
      }
    })
      .jstree( {"themeroller": {"item_leaf": false,
                                "item_clsd": false,
                                "item_open":false  },
                "plugins" : ["html_data",  "themeroller"],})
      .delegate("a", "click", function(event, data){
        if($('#clusterlist_sel').is(':visible')){
          $('#clusterlist_sel').toggle();
        }
        if($('#clusterlist_pep').is(':visible')){
          $('#clusterlist_pep').html("");
        }
        var cluster = $(this).attr('href').split('/')[2];
        $.get(url+'/cluster-infos',{selCl:cluster}, function(data){
          $('#clusterlist_sel').html(data);
          $.getScript(url+'/script/initshowtable.js', function(){
            $('#clusterlist_sel').toggle();
          });
        });
        return false;
     } );

    $('#disp-res').bind("loaded.jstree", function(){
     var opennode = document.location.pathname.split("/").pop();
     $('#' + opennode).parents(".jstree-closed").each(function(){
        $('#disp-res').jstree("open_node", this, false, true);
      });
    });

    $('#disp-res').bind('before.jstree', function(event,data){
      switch(data.plugin){
        case 'ui':
          if(!data.inst.is_leaf(data.args[0])){
            return false;
          }
          break;
        default:
          break;
      }
    })
      .jstree( {"plugins" : ["html_data", "ui", "themeroller"],
                "item_leaf": false, })
      .delegate("a", "click", function(event, data){
     } );

});
<commit_msg>added rudimentary error handling for search functions<commit_after>// define namespace to prevent loading js files multiple times
var pepdb = pepdb || {};

$.ajaxSetup ({
    cache: false
});

var isFirstLoad = function(namesp, jsFile) {
  var isFirst = namesp.firstLoad === undefined;
  namesp.firstLoad = false;

  return isFirst;
};

function stopTableSorting(e) {
    if (!e) var e = window.event;
    e.cancelBubble = true;
    if (e.stopPropagation) e.stopPropagation();
}

/* get url parameter "name" or return "" if does not exist */
function urlParam(name){
  var result = new RegExp('[\\?&]' + name + '=([^&#]*)').exec(window.location.href);
  return result && unescape(result[1]) || "";
}

$(document).ready(function(){
  function baseDir(){
    var url = document.location.pathname.split('/')[1];
    if (url == "pepdb"){
      return '/'+url;
    }else{
      return '';
    }
  };

  var url = baseDir();
  var formAll = ["#all_lib", "#all_sel", "#all_ds", "#c_all_lib", "#r_all_lib", "#all_motl"];
  var propSelect = ['#l', '#s', '#ds', '#c', '#ts', '#tt', '#tc', '#ss', '#st', '#sc'];
  var propInput = ['#seq', '#blos', '#pl', '#sr', '#ralt', '#ragt', '#relt', '#regt', '#dlt', '#dgt'];
  var species = ['#ss', '#ts'];
  var tissue = ['#st', '#tt'];
  var cell = ['#sc', '#tc'];

  $('.optbut').button();
  $('#navigation').menu();
  $('.editlink').button();
  $('.deletelink').button();

  $('#clear-button').click(function(){
    $('body').load(window.location.pathname);
  });

  $.each(formAll, function(index, value){
    $(value).click(function(){
      var marked = this.checked;
      $(this).closest('fieldset').find(':checkbox').each(function(){
        $(this).prop('checked', marked);
      });
    });
  });

  $('#comp-library input:checkbox').click(function(){
    var checkedLibs = [];
    $(this).closest('fieldset').find(':checkbox').each(function(){
      var elemVal = $(this).attr('value');
      if(this.checked && elemVal != "all_lib"){
        checkedLibs.push(elemVal);
      }
    });
    $('#comp-selection').load(url+'/checklist',{checkedElem: checkedLibs, allElem: 'c_all_sel', allElemVal: 'all_sel', selector: 'sel', sec: 'c_', elemName: 'sels[]' }, function(){
        $.getScript(url+"/script/checkbox.js");
      } );
  });

  $('#ref-library input:checkbox').click(function(){
    var checkedLibs = [];
    $(this).closest('fieldset').find(':checkbox').each(function(){
      var elemVal = $(this).attr('value');
      if(this.checked && elemVal != "all_lib"){
        checkedLibs.push(elemVal);
      }
    });
    $('#ref-selection').load(url+'/checklist',{checkedElem: checkedLibs, allElem: 'r_all_sel', allElemVal: 'all_sel', selector: 'sel', sec: 'r_', elemName: 'sels[]' }, function(){
        $.getScript(url+"/script/checkbox.js");
      } );
  });

  $('#motif-list input:radio').click(function(){
    if($('#motifs').is(':visible')){
      $('#motifs').toggle();
    }
    var checkedList = $(this).val();
    $.get('mot-checklist', {checkedElem: checkedList},function(data){
      $('#motifs').html(data);
      $.getScript(url+"/script/initshowtable.js", function(){
        $('#motifs').toggle();
      });

    });
  });

   $('#compdata').submit(function(){
    if($('#comppepresults').is(':visible')){
      $('#comppepresults').toggle();
    }
    if($('.loading').is(':hidden')){
      $('.loading').toggle();
    }
    $('#infos').html("");
    $.ajax({
      data: $(this).serialize(),
      type: $(this).attr('method'),
      url: $(this).attr('action'),
      error: function(response,error1,error2){
        $.get(url+'/error', {error:error2},function(response){
          $('#comppepresults').html(response);
          $('#comppepresults').toggle();
          $('.loading').toggle();
        });
      },
      success: function(response){
        $('#comppepresults').html(response);
        $.getScript(url+'/script/initshowtable.js', function(){
          $('#comppepresults').toggle();
          $('.loading').toggle();
        });
      }
    });
    return false;
  });

   $('#motsearch').submit(function(){
    if($('#motresults').is(':visible')){
      $('#motresults').toggle();
    }
    if($('.loading').is(':hidden')){
      $('.loading').toggle();
    }
    $.ajax({
      data: $(this).serialize(),
      type: $(this).attr('method'),
      url: $(this).attr('action'),
      error: function(response,error1,error2){
        $.get(url+'/error', {error:error2},function(response){
          $('#motresults').html(response);
          $('#motresults').toggle();
          $('.loading').toggle();
        });
      },

      success: function(response){
        $('#motresults').html(response);
        $.getScript(url+'/script/accinit.js', function(){
          $('#motresults').toggle();
          $('.loading').toggle();
        });
      }
    });
    return false;
  });

  $('#cl-search').submit(function(){
    if($('#clpepresults').is(':visible')){
      $('#clpepresults').toggle();
    }
    if($('#clsearch').is(':visible')){
      $('#clsearch').toggle();
    }
    $('#clpepresults').html("");
    $('#clsearchpeps').html("");
    $.ajax({
      data: $(this).serialize(),
      type: $(this).attr('method'),
      url: $(this).attr('action'),
      error: function(response,error1,error2){
        $.get(url+'/error', {error:error2},function(response){
          $('#clpepresults').html(response);
          $('#clpepresults').toggle();
          $('.loading').toggle();
        });
      },
      success: function(response){
        $('#clpepresults').html(response);
        $.getScript(url+'/script/tableinit.js', function(){
          $('#clpepresults').toggle();
        });
      }
    });
    return false;
  });

    $('#datatype').change(function(){
      var selected = $(this).children("option:selected").text();
      if(selected == "sequencing dataset"){
        selected = "dataset";
      }
      if(selected == "motif list"){
        selected = "motif";
      }
      $("#dataform").load(url+'/add'+ selected, function(){
        var boxNames = ['#dlibname', '#dselname', '#ddsname', '#dspecies'];

        $.each(boxNames, function(index, value){
          $(value).prop('selectedIndex', -1);
        });

        $('#dspecies').change(function(){
          var valSel = $(this).children("option:selected").text();
          $.get(url+'/formdrop', {columnname: "tissue", selected1: valSel, table:"targets", where1:"species", boxID:"dtissue"}, function(data){
            $('#dtissue').html(data);
            $('#dtissue').prop('selectedIndex', -1);
            $('#dcell').html('');
          });
        });
        $('#dtissue').change(function(){
          var valSel1 = $('#dspecies').children("option:selected").text();
          var valSel2 = $(this).children("option:selected").text();
          $.get(url+'/formdrop', {columnname: "cell", selected1: valSel1, selected2: valSel2,table:"targets", where2:"tissue", where1:"species",boxID:"dcell"}, function(data){
            $('#dcell').html(data);
          });
        });
        $('#dlibname').change(function(){
          var valSel = $(this).children("option:selected").text();
          $.get(url+'/formdrop', {columnname: "selection_name", selected1: valSel, table:"selections", where1:"library_name", boxID:"dselname"}, function(data){
            $('#dselname').html(data);
            $('#dselname').prop('selectedIndex', -1);
            $('#ddsname').prop('selectedIndex', -1);
          });
        });
        $('#dselname').change(function(){
          var valSel1 = $('#dlibname').children("option:selected").text();
          var valSel2 = $(this).children("option:selected").text();
          $.get(url+'/formdrop', {columnname: "dataset_name", selected1: valSel1, selected2: valSel2, table:"sequencing_datasets", where1:"library_name", where2:"selection_name",boxID:"dselname"}, function(data){
            $('#ddsname').html(data);
            $('#ddsname').prop('selectedIndex', -1);
          });
        });
      });
    });

    $.each(propSelect, function(index, value){
      var paramName = $(value).attr('name');
      if(urlParam(paramName) == ""){
        $(value).prop('selectedIndex', -1);
      }
      $(value).on('beforeunload', function(){
        if ($(this).attr('selectedIndex') == -1){
          $(this).prop('name', '');
        }
        });
      });

    $('#edittype').change(function(){
      var selected = $(this).children("option:selected").val();
      $.get(url+'/editdrop', {table:selected}, function(data){
        $('#elementselection').html(data);
        $.getScript(url+'/script/dropbox.js');
      });
    });

   $('#propsearch').submit(function(){
    if($('#propresults').is(':visible')){
      $('#propresults').toggle();
    }
    if($('.loading').is(':hidden')){
      $('.loading').toggle();
    }
    $.ajax({
      data: $(this).serialize(),
      type: $(this).attr('method'),
      url: $(this).attr('action'),
      error: function(response,error1,error2){
        $.get(url+'/error', {error:error2},function(response){
          $('#propresults').html(response);
          $('#propresults').toggle();
          $('.loading').toggle();
        });
      },
      success: function(response){
        $('#propresults').html(response);
        $.getScript(url+'/script/initshowtable.js', function(){
          $('#propresults').toggle();
          $('.loading').toggle();
        });
      }
    });
    return false;
  });
    $.each(species, function(index, value){
      $(value).change(function(){
        var valSel = $(this).children("option:selected").text();
        $.get(url+'/formdrop', {columnname: "tissue", selected1: valSel, table:"targets", where1:"species", boxID:tissue[index].substring(1)}, function(data){
          $(tissue[index]).html(data);
          $(tissue[index]).prop('selectedIndex', -1);
          $(cell[index]).html('');
        });
      });
    });

    $.each(tissue, function(index, value){
      $(value).change(function(){
        var valSel1 = $(species[index]).children("option:selected").text();
        var valSel2 = $(this).children("option:selected").text();
        $.get(url+'/formdrop', {columnname: "cell", selected1: valSel1, selected2: valSel2,table:"targets", where2:"tissue", where1:"species",boxID:cell[index].substring(1)}, function(data){
          $(cell[index]).html(data);
        });
      });

    });

    $('#l').change(function(){
      var valSel = $(this).children("option:selected").text();
      $.get(url+'/formdrop', {columnname: "selection_name", selected1: valSel, table:"selections", where1:"library_name", boxID:"s"}, function(data){
        $('#s').html(data);
        $('#s').prop('selectedIndex', -1);
        $('#ds').prop('selectedIndex', -1);
      });
    });
    $('#s').change(function(){
      var valSel1 = $(this).children("option:selected").text();
      $.get(url+'/formdrop', {columnname: "dataset_name", selected1: valSel1,table:"sequencing_datasets", where1:"selection_name",boxID:"ds"}, function(data){
        $('#ds').html(data);
        $('#ds').prop('selectedIndex', -1);
      });
    });

   $('#compclsub').submit(function(){
    if($('#compclresults').is(':visible')){
      $('#compclresults').toggle();
    }
    if($('.loading').is(':hidden')){
      $('.loading').toggle();
    }
    $.ajax({
      data: $(this).serialize(),
      type: $(this).attr('method'),
      url: $(this).attr('action'),
      error: function(response,error1,error2){
        $.get(url+'/error', {error:error2},function(response){
          $('#compclresults').html(response);
          $('#compclresults').toggle();
          $('.loading').toggle();
        });
      },
      success: function(response){
        $('#compclresults').html(response);
          $.getScript(url+'/script/initshowtable.js', function(){
            $('#compclresults').toggle();
            $('.loading').toggle();
          });
    }
  });
    return false;
  });

    $('#type').change(function(){
      if ($(this).val() == "complete sequence"){
        $('#blossum').show();
        $('#wchelp').hide();
        $('#bshelp').show();
      } else if ($(this).val() == "wildcard sequence"){
        $('#blossum').hide();
        $('#wchelp').show();
        $('#bshelp').hide();
      } else {
        $('#blossum').hide();
        $('#wchelp').hide();
        $('#bshelp').hide();

      }
    });
    $('#wcicon').tooltip({
      content: function(callback){
        callback($(this).prop('title').replace(/\|/g, '
'));
      }
    });
    $('#bsicon').tooltip({
      content: function(callback){
        callback($(this).prop('title').replace(/\|/g, '
'));
      }
    });

    $('.editlink').click(function(e){
      e.preventDefault();
      var link = $(this).attr('href');
      $.get(link, function(response){
        $('#editusers').html(response);
      });
    })

    /* -----------jsTree configuration------------------- */
    $('#clusterlist').bind("loaded.jstree", function(){
     var opennode = document.location.pathname.split("/").pop();
     $('#' + opennode).parents(".jstree-closed").each(function(){
        $('#clusterlist').jstree("open_node", this, false, true);
      });
    });

    $('#clusterlist').bind('before.jstree', function(event,data){
      switch(data.plugin){
        case 'ui':
          if(!data.inst.is_leaf(data.args[0])){
            return false;
          }
          break;
        default:
          break;
      }
    })
      .jstree( {"themeroller": {"item_leaf": false,
                                "item_clsd": false,
                                "item_open":false  },
                "plugins" : ["html_data",  "themeroller"],})
      .delegate("a", "click", function(event, data){
        if($('#clusterlist_sel').is(':visible')){
          $('#clusterlist_sel').toggle();
        }
        if($('#clusterlist_pep').is(':visible')){
          $('#clusterlist_pep').html("");
        }
        var cluster = $(this).attr('href').split('/')[2];
        $.get(url+'/cluster-infos',{selCl:cluster}, function(data){
          $('#clusterlist_sel').html(data);
          $.getScript(url+'/script/initshowtable.js', function(){
            $('#clusterlist_sel').toggle();
          });
        });
        return false;
     } );

    $('#disp-res').bind("loaded.jstree", function(){
     var opennode = document.location.pathname.split("/").pop();
     $('#' + opennode).parents(".jstree-closed").each(function(){
        $('#disp-res').jstree("open_node", this, false, true);
      });
    });

    $('#disp-res').bind('before.jstree', function(event,data){
      switch(data.plugin){
        case 'ui':
          if(!data.inst.is_leaf(data.args[0])){
            return false;
          }
          break;
        default:
          break;
      }
    })
      .jstree( {"plugins" : ["html_data", "ui", "themeroller"],
                "item_leaf": false, })
      .delegate("a", "click", function(event, data){
     } );

});
<|endoftext|>


<commit_before>(function() {
  module( 'Axon: Simple Tests' );
  var Property = axon.Property;
  var DerivedProperty = axon.DerivedProperty;
  var ObservableArray = axon.ObservableArray;
  var log = axon.log;
  var PropertySet = axon.PropertySet;

  test( 'Simple tests', function() {

    var person = new axon.PropertySet( {name: 'larry', age: '100'} );
    equal( person.name, 'larry', 'name should be larry and accessible through es5 get' );

    person.name = 'susan';
    equal( person.name, 'susan', 'name should be susan after es5 set' );

    var ageLinkCalls = 0;
    person.ageProperty.link( function( age ) {ageLinkCalls++;} );
    person.age = person.age + 1;
    person.age = person.age + 2;
    person.age = person.age + 3;
    equal( ageLinkCalls, 4, 'should have received one call for each set, plus one on link' );

    person.reset();
    equal( person.name, 'larry', 'should have reset to the initial name' );

    var myValue = '';
    person.multilink( ['name', 'age'], function( name, age ) {
      myValue = name + '/' + age;
    } );
    person.name = '123';
    person.age = 456;
    equal( myValue, '123/456', 'multilink should get both values' );
  } );

  test( 'Test once', function() {
    var count = 0;
    var p = new Property( 1 );
    p.once( function( newVal, oldVal ) {
      count++;
    } );

    p.value = 2;
    p.value = 3;
    p.value = 4;
    equal( count, 1, 'Listener added with once is only called back one time' );
  } );

  test( 'Test observable array', function() {
    var array = new ObservableArray( ['a', 'b', 'c'] );
    var dChecker = function( item ) {
      equal( item, 'd' );
    };
    array.addItemAddedListener( dChecker );
    array.add( 'd' );

    array.removeItemAddedListener( dChecker );
    array.reset();
    equal( array.get( 0 ), 'a' );
    equal( array.get( 1 ), 'b' );
    equal( array.get( 2 ), 'c' );
    equal( array.length, 3 );
  } );

  test( 'Test events', function() {
    var person = new axon.PropertySet( {name: 'larry', age: '100'} );
    var count = 0;
    var listener = function( person ) {
      count = count + 1;
    };
    person.on( 'reset-all', listener );

    person.trigger( 'reset-all' );
    person.trigger( 'reset-all' );
    person.trigger( 'reset-all' );

    equal( count, 3, 'Trigger calls on' );

    //Unregister the listener
    person.off( 'reset-all', listener );

    //Triggering more events shouldn't call back because we have removed the listener
    person.trigger( 'reset-all' );
    person.trigger( 'reset-all' );
    person.trigger( 'reset-all' );

    equal( count, 3, 'Triggering more events should not call back because we have removed the listener' );

    var planetName = '?';
    var planetRadius = '?';
    person.on( 'planet-discovered', function( name, radius ) {
      planetName = name;
      planetRadius = radius;
    } );

    person.trigger( 'planet-discovered', 'pluto', 12345 );

    equal( planetName, 'pluto', 'argument should pass through event' );
    equal( planetRadius, 12345, 'argument should pass through event' );

    var name = person.name;
    person.once( 'name-changed', function( newName ) {
      name = newName;
    } );

    person.trigger( 'name-changed', 'Alice' );
    person.trigger( 'name-changed', 'Bob' );
    person.trigger( 'name-changed', 'Charlie' );

    equal( name, 'Alice', 'function added with once should only be called once' );

    var x = 0;
    var listener = function() {
      x = 999;
    };
    var handle = person.once( 'say-hello', listener );
    person.off( 'say-hello', handle );
    person.trigger( 'say-hello' );
    equal( x, 0, 'Function added with once should be removable' );
  } );

  test( 'Test unlink', function() {
    var p = new Property( 1 );
    var a = function( a ) {};
    var b = function( b ) {};
    var c = function( c ) {};
    p.link( a );
    p.link( b );
    p.link( c );
    equal( p._observers.length, 3, 'should have 3 observers now' );
    p.unlink( b );
    equal( p._observers[0], a, 'should have removed b' );
    equal( p._observers[1], c, 'should have removed b' );
    equal( p._observers.length, 2, 'should have removed an item' );
  } );

  test( 'Test stale values in DerivedProperty', function() {
    var a = new Property( 1 );
    var b = new Property( 2 );
    var c = new DerivedProperty( [a, b], function( a, b ) {return a + b;} );
    a.value = 7;
    equal( c.value, 9 );
  } );

  test( 'Test Property.multilink', function() {
    var a = new Property( 1 );
    var b = new Property( 2 );
    var callbacks = 0;
    Property.multilink( [a, b], function( a, b ) {
      callbacks++;
      equal( a, 1, 'first value should pass through' );
      equal( b, 2, 'second value should pass through' );
    } );
    equal( callbacks, 1, 'should have called back to a multilink' );
  } );

  test( 'Test Property.lazyMultilink', function() {
    var a = new Property( 1 );
    var b = new Property( 2 );
    var callbacks = 0;
    Property.lazyMultilink( [a, b], function( a, b ) {
      callbacks++;
      equal( a, 1 );
      equal( b, 2 );
    } );
    equal( callbacks, 0, 'shouldnt call back to a lazy multilink' );
  } );
})();
<commit_msg>Added unit tests for DerivedProperty.detach, see #37<commit_after>(function() {
  module( 'Axon: Simple Tests' );
  var Property = axon.Property;
  var DerivedProperty = axon.DerivedProperty;
  var ObservableArray = axon.ObservableArray;
  var log = axon.log;
  var PropertySet = axon.PropertySet;

  test( 'Simple tests', function() {

    var person = new axon.PropertySet( {name: 'larry', age: '100'} );
    equal( person.name, 'larry', 'name should be larry and accessible through es5 get' );

    person.name = 'susan';
    equal( person.name, 'susan', 'name should be susan after es5 set' );

    var ageLinkCalls = 0;
    person.ageProperty.link( function( age ) {ageLinkCalls++;} );
    person.age = person.age + 1;
    person.age = person.age + 2;
    person.age = person.age + 3;
    equal( ageLinkCalls, 4, 'should have received one call for each set, plus one on link' );

    person.reset();
    equal( person.name, 'larry', 'should have reset to the initial name' );

    var myValue = '';
    person.multilink( ['name', 'age'], function( name, age ) {
      myValue = name + '/' + age;
    } );
    person.name = '123';
    person.age = 456;
    equal( myValue, '123/456', 'multilink should get both values' );
  } );

  test( 'Test once', function() {
    var count = 0;
    var p = new Property( 1 );
    p.once( function( newVal, oldVal ) {
      count++;
    } );

    p.value = 2;
    p.value = 3;
    p.value = 4;
    equal( count, 1, 'Listener added with once is only called back one time' );
  } );

  test( 'Test observable array', function() {
    var array = new ObservableArray( ['a', 'b', 'c'] );
    var dChecker = function( item ) {
      equal( item, 'd' );
    };
    array.addItemAddedListener( dChecker );
    array.add( 'd' );

    array.removeItemAddedListener( dChecker );
    array.reset();
    equal( array.get( 0 ), 'a' );
    equal( array.get( 1 ), 'b' );
    equal( array.get( 2 ), 'c' );
    equal( array.length, 3 );
  } );

  test( 'Test events', function() {
    var person = new axon.PropertySet( {name: 'larry', age: '100'} );
    var count = 0;
    var listener = function( person ) {
      count = count + 1;
    };
    person.on( 'reset-all', listener );

    person.trigger( 'reset-all' );
    person.trigger( 'reset-all' );
    person.trigger( 'reset-all' );

    equal( count, 3, 'Trigger calls on' );

    //Unregister the listener
    person.off( 'reset-all', listener );

    //Triggering more events shouldn't call back because we have removed the listener
    person.trigger( 'reset-all' );
    person.trigger( 'reset-all' );
    person.trigger( 'reset-all' );

    equal( count, 3, 'Triggering more events should not call back because we have removed the listener' );

    var planetName = '?';
    var planetRadius = '?';
    person.on( 'planet-discovered', function( name, radius ) {
      planetName = name;
      planetRadius = radius;
    } );

    person.trigger( 'planet-discovered', 'pluto', 12345 );

    equal( planetName, 'pluto', 'argument should pass through event' );
    equal( planetRadius, 12345, 'argument should pass through event' );

    var name = person.name;
    person.once( 'name-changed', function( newName ) {
      name = newName;
    } );

    person.trigger( 'name-changed', 'Alice' );
    person.trigger( 'name-changed', 'Bob' );
    person.trigger( 'name-changed', 'Charlie' );

    equal( name, 'Alice', 'function added with once should only be called once' );

    var x = 0;
    var listener = function() {
      x = 999;
    };
    var handle = person.once( 'say-hello', listener );
    person.off( 'say-hello', handle );
    person.trigger( 'say-hello' );
    equal( x, 0, 'Function added with once should be removable' );
  } );

  test( 'Test unlink', function() {
    var p = new Property( 1 );
    var a = function( a ) {};
    var b = function( b ) {};
    var c = function( c ) {};
    p.link( a );
    p.link( b );
    p.link( c );
    equal( p._observers.length, 3, 'should have 3 observers now' );
    p.unlink( b );
    equal( p._observers[0], a, 'should have removed b' );
    equal( p._observers[1], c, 'should have removed b' );
    equal( p._observers.length, 2, 'should have removed an item' );
  } );

  test( 'Test stale values in DerivedProperty', function() {
    var a = new Property( 1 );
    var b = new Property( 2 );
    var c = new DerivedProperty( [a, b], function( a, b ) {return a + b;} );
    a.value = 7;
    equal( c.value, 9 );
  } );

  test( 'Test Property.multilink', function() {
    var a = new Property( 1 );
    var b = new Property( 2 );
    var callbacks = 0;
    Property.multilink( [a, b], function( a, b ) {
      callbacks++;
      equal( a, 1, 'first value should pass through' );
      equal( b, 2, 'second value should pass through' );
    } );
    equal( callbacks, 1, 'should have called back to a multilink' );
  } );

  test( 'Test Property.lazyMultilink', function() {
    var a = new Property( 1 );
    var b = new Property( 2 );
    var callbacks = 0;
    Property.lazyMultilink( [a, b], function( a, b ) {
      callbacks++;
      equal( a, 1 );
      equal( b, 2 );
    } );
    equal( callbacks, 0, 'shouldnt call back to a lazy multilink' );
  } );

  test( 'Test DerivedProperty.detach', function() {

    var widthProperty = new Property( 2 );
    var heightProperty = new Property( 3 );
    var areaProperty = new DerivedProperty( [ widthProperty, heightProperty ],
      function( width, height ) { return width * height; } );
    areaProperty.link( function( area ) { console.log( 'area = ' + area ); } );

    equal( widthProperty._observers.length, 1 );
    equal( heightProperty._observers.length, 1 );
    equal( areaProperty.dependencies.length, 2 );
    equal( areaProperty.dependencyListeners.length, 2 );

    areaProperty.detach();

    equal( widthProperty._observers.length, 0 );
    equal( heightProperty._observers.length, 0 );
    equal( heightProperty._observers.length, 0 );

    equal( areaProperty.dependencies.length, 0 );
    equal( areaProperty.dependencyListeners.length, 0 );

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


<commit_before>(() => {
  let jokesArray = JSON.parse(localStorage.getItem('jokes'));

  // Fetch joke count from API endpoint
  async function fetchCount() {
    const url = 'https://api.icndb.com/jokes/count';
    const { value } = await (await fetch(url)).json();
    return value;
  }

  // use API endpoint to fetch the jokes and store it in an array
  // use count as a default parameter to store value from fetchCount()
  async function fetchJokes(count = fetchCount()) {
    const url = `https://api.icndb.com/jokes/random/${await count}`; // Await value provided by fetchCount()

    const { value } = await (await fetch(url)).json(); // Get response object and parse it to JSON

    jokesArray = value.map(({ joke }) => joke); // load jokesArray with the response object

    return localStorage.setItem('jokes', JSON.stringify(jokesArray)); // Set localStorage with jokesArray as the return
  }

  if (jokesArray === null) {
    fetchJokes();
  }

  const jokeDispenser = (() => {
    let counter = 0; //start counter at position 0 of jokesArray
    function _change(position) {
      counter += position;
    }
    return {
      nextJoke: () => {
        _change(1);
        counter %= jokesArray.length; // start from 0 if we get to the end of the array
        return jokesArray[counter];
      },
      prevJoke: () => {
        if (counter === 0) {
          counter = jokesArray.length; // place our counter at the end of the array
        }
        _change(-1);
        return jokesArray[counter];
      }
    };
  })();

  // pass selected joke to print on html element
  function printJoke(joke) {
    document.querySelector('.joke-text p').textContent = joke;
  }

  // Listen to event handlers for prev and next buttons and passes jokesArray as an argument
  const jokeContainer = document.querySelector('.joke-container');
  jokeContainer.addEventListener('click', event => {
    if (event.target.value === 'Next') {
      printJoke(jokeDispenser.prevJoke(jokesArray));
    } else if (event.target.value === 'Prev') {
      printJoke(jokeDispenser.nextJoke(jokesArray));
    }
  });
})();
<commit_msg>update index.js<commit_after>(() => {
  let jokesArray = JSON.parse(localStorage.getItem('jokes'));

  // Fetch joke count from API endpoint
  async function fetchCount() {
    const url = 'https://api.icndb.com/jokes/count';
    const { value } = await (await fetch(url)).json();
    return value;
  }

  // use API endpoint to fetch the jokes and store it in an array
  // use count as a default parameter to store value from fetchCount()
  async function fetchJokes(count = fetchCount(), printJoke) {
    const url = `https://api.icndb.com/jokes/random/${await count}`; // Await value provided by fetchCount()

    const { value } = await (await fetch(url)).json(); // Get response object and parse it to JSON

    jokesArray = value.map(({ joke }) => joke); // load jokesArray with the response object

    return localStorage.setItem('jokes', JSON.stringify(jokesArray)); // Set localStorage with jokesArray as the return
  }

  if (jokesArray === null) {
    fetchJokes().then(() => {
      printJoke(jokesArray[0]);
    });
  } else {
    printJoke(jokesArray[0]);
  }

  const jokeDispenser = (() => {
    let counter = 0; //start counter at position 0 of jokesArray
    function _change(position) {
      counter += position;
    }
    return {
      nextJoke: () => {
        _change(1);
        counter %= jokesArray.length; // start from 0 if we get to the end of the array
        return jokesArray[counter];
      },
      prevJoke: () => {
        if (counter === 0) {
          counter = jokesArray.length; // place our counter at the end of the array
        }
        _change(-1);
        return jokesArray[counter];
      }
    };
  })();

  // pass selected joke to print on html element
  function printJoke(joke) {
    document.querySelector('.joke-text p').textContent = joke;
  }

  // Listen to event handlers for prev and next buttons and passes jokesArray as an argument
  const jokeContainer = document.querySelector('.joke-container');
  jokeContainer.addEventListener('click', event => {
    if (event.target.value === 'Next') {
      printJoke(jokeDispenser.prevJoke(jokesArray));
    } else if (event.target.value === 'Prev') {
      printJoke(jokeDispenser.nextJoke(jokesArray));
    }
  });
})();
<|endoftext|>


<commit_before>import Microcosm from '../../../src/microcosm'

describe('Generator Middleware', function () {

  it('processes actions sequentially', function () {
    expect.assertions(1)

    let stepper = n => n + 1
    let repo = new Microcosm()

    function range (start, end) {
      return function * (repo) {
        let value = start

        while (value < end) {
          value = yield repo.push(stepper, value)
        }
      }
    }

    repo.push(range, 0, 3).onDone(result => {
      expect(result).toEqual(3)
    })
  })

  it('throws if yielding a non-action value', function () {
    expect.assertions(1)

    let repo = new Microcosm()
    let step = n => n

    function test () {
      return function * (repo) {
        yield repo.push(step, 1)
        yield true
      }
    }

    expect(() => repo.push(test)).toThrow("Iteration of generator expected an Action")
  })

  it('a rejected step halts the chain', function () {
    expect.assertions(1)

    let stepper = n => n + 1
    let repo = new Microcosm()

    let sequence = repo.push(function () {
      return function * (repo) {
        yield repo.push(stepper, 0)
        yield repo.append(stepper).reject('Failure')
        yield repo.push(stepper)
      }
    })

    sequence.onDone(function () {
      throw new Error('Sequence should not have completed')
    })

    sequence.onError(result => {
      expect(result).toEqual('Failure')
    })
  })

  it('a cancelled step halts the chain', function () {
    expect.assertions(1)

    let stepper = n => n + 1
    let repo = new Microcosm()

    let sequence = repo.push(function () {
      return function * (repo) {
        yield repo.push(stepper, 0)
        yield repo.append(stepper).cancel('Cancelled')
        yield repo.push(stepper)
      }
    })

    sequence.onDone(function () {
      throw new Error('Sequence should not have resolved')
    })

    sequence.onError(function () {
      throw new Error('Sequence should not have rejected')
    })

    sequence.onCancel(result => {
      expect(result).toEqual('Cancelled')
    })
  })

  it('waits for an async action to finish before moving on', function () {
    let stepper = n => n + 1
    let repo = new Microcosm()

    function sleep (time) {
      return action => {
        setTimeout(() => action.resolve(true), time)
      }
    }

    return repo.push(function () {
      return function * (repo) {
        yield repo.push(sleep, 100)
        yield repo.push(sleep, 100)
      }
    }).onDone(function (payload) {
      expect(payload).toEqual(true)
    })
  })

  it('waits for an async sequences', function () {
    let stepper = n => n + 1
    let repo = new Microcosm()

    function sleep (time) {
      return action => {
        setTimeout(() => action.resolve(true), time)
      }
    }

    function dream (time) {
      return function * (repo) {
        yield repo.push(sleep, time)
        yield repo.push(sleep, time)
      }
    }

    return repo.push(function () {
      return function * (repo) {
        yield repo.push(dream, 100)
        yield repo.push(dream, 100)
      }
    }).onDone(function (payload) {
      expect(payload).toEqual(true)
    })
  })

  it('multiple async sequence pushes do not step on eachother', function () {
    let stepper = n => n + 1
    let repo = new Microcosm()

    function sleep (time) {
      return action => {
        setTimeout(() => action.resolve(true), time)
      }
    }

    function dream (time) {
      return function * (repo) {
        yield repo.push(sleep, time)
        yield repo.push(sleep, time)
      }
    }

    function dream100 () {
      return function * (repo) {
        yield repo.push(dream, 100)
        yield repo.push(dream, 100)
      }
    }

    return Promise.all([ repo.push(dream100), repo.push(dream100) ])
  })

  it('history.wait() works with generators', async function () {
    let repo = new Microcosm()

    function sleep (time) {
      return action => {
        setTimeout(() => action.resolve(true), time)
      }
    }

    function dream (time) {
      return function * (repo) {
        yield repo.push(sleep, time)
        yield repo.push(sleep, time)
        yield repo.push(sleep, time)
      }
    }

    repo.push(dream, 100)

    await repo.history.wait()
  })

  it('can push new actions during history.wait() while processing a generator', async function () {
    let repo = new Microcosm()

    repo.addDomain('test', {
      register () {
        return {
          'test': n => n
        }
      }
    })

    function sleep (time) {
      return action => {
        setTimeout(() => action.resolve(true), time)
      }
    }

    function dream (time) {
      return function * (repo) {
        yield repo.push(sleep, time)
        yield repo.push(sleep, time)
        yield repo.push(sleep, time)
      }
    }

    repo.push(dream, 100)

    await repo.history.wait()

    repo.push('test', 1)
    repo.push('test', 2)
  })

})
<commit_msg>Remove obscure generator test<commit_after>import Microcosm from '../../../src/microcosm'

describe('Generator Middleware', function () {

  it('processes actions sequentially', function () {
    expect.assertions(1)

    let stepper = n => n + 1
    let repo = new Microcosm()

    function range (start, end) {
      return function * (repo) {
        let value = start

        while (value < end) {
          value = yield repo.push(stepper, value)
        }
      }
    }

    repo.push(range, 0, 3).onDone(result => {
      expect(result).toEqual(3)
    })
  })

  it('throws if yielding a non-action value', function () {
    expect.assertions(1)

    let repo = new Microcosm()
    let step = n => n

    function test () {
      return function * (repo) {
        yield repo.push(step, 1)
        yield true
      }
    }

    expect(() => repo.push(test)).toThrow("Iteration of generator expected an Action")
  })

  it('a rejected step halts the chain', function () {
    expect.assertions(1)

    let stepper = n => n + 1
    let repo = new Microcosm()

    let sequence = repo.push(function () {
      return function * (repo) {
        yield repo.push(stepper, 0)
        yield repo.append(stepper).reject('Failure')
        yield repo.push(stepper)
      }
    })

    sequence.onDone(function () {
      throw new Error('Sequence should not have completed')
    })

    sequence.onError(result => {
      expect(result).toEqual('Failure')
    })
  })

  it('a cancelled step halts the chain', function () {
    expect.assertions(1)

    let stepper = n => n + 1
    let repo = new Microcosm()

    let sequence = repo.push(function () {
      return function * (repo) {
        yield repo.push(stepper, 0)
        yield repo.append(stepper).cancel('Cancelled')
        yield repo.push(stepper)
      }
    })

    sequence.onDone(function () {
      throw new Error('Sequence should not have resolved')
    })

    sequence.onError(function () {
      throw new Error('Sequence should not have rejected')
    })

    sequence.onCancel(result => {
      expect(result).toEqual('Cancelled')
    })
  })

  it('waits for an async action to finish before moving on', function () {
    let stepper = n => n + 1
    let repo = new Microcosm()

    function sleep (time) {
      return action => {
        setTimeout(() => action.resolve(true), time)
      }
    }

    return repo.push(function () {
      return function * (repo) {
        yield repo.push(sleep, 100)
        yield repo.push(sleep, 100)
      }
    }).onDone(function (payload) {
      expect(payload).toEqual(true)
    })
  })

  it('waits for an async sequences', function () {
    let stepper = n => n + 1
    let repo = new Microcosm()

    function sleep (time) {
      return action => {
        setTimeout(() => action.resolve(true), time)
      }
    }

    function dream (time) {
      return function * (repo) {
        yield repo.push(sleep, time)
        yield repo.push(sleep, time)
      }
    }

    return repo.push(function () {
      return function * (repo) {
        yield repo.push(dream, 100)
        yield repo.push(dream, 100)
      }
    }).onDone(function (payload) {
      expect(payload).toEqual(true)
    })
  })

  it('multiple async sequence pushes do not step on eachother', function () {
    let stepper = n => n + 1
    let repo = new Microcosm()

    function sleep (time) {
      return action => {
        setTimeout(() => action.resolve(true), time)
      }
    }

    function dream (time) {
      return function * (repo) {
        yield repo.push(sleep, time)
        yield repo.push(sleep, time)
      }
    }

    function dream100 () {
      return function * (repo) {
        yield repo.push(dream, 100)
        yield repo.push(dream, 100)
      }
    }

    return Promise.all([ repo.push(dream100), repo.push(dream100) ])
  })

  it('history.wait() works with generators', async function () {
    let repo = new Microcosm()

    function sleep (time) {
      return action => {
        setTimeout(() => action.resolve(true), time)
      }
    }

    function dream (time) {
      return function * (repo) {
        yield repo.push(sleep, time)
        yield repo.push(sleep, time)
        yield repo.push(sleep, time)
      }
    }

    repo.push(dream, 100)

    await repo.history.wait()
  })

})
<|endoftext|>


<commit_before>/**
    @external Viz
    @see https://github.com/d3plus/d3plus-viz#Viz
*/
import {nest} from "d3-collection";
import * as d3 from "d3-selection";
import {accessor, assign, configPrep, constant, elem} from "d3plus-common";
import {Circle, Path} from "d3plus-shape";
import {TextBox} from "d3plus-text";
import {Viz} from "d3plus-viz";

const tau = Math.PI * 2;

/**
    @class Radar
    @extends Plot
    @desc Creates a radar visualization based on an array of data.
*/
export default class Radar extends Viz {

  /**
      @memberof LinePlot
      @desc Invoked when creating a new class instance, and overrides any default parameters inherited from Plot.
      @private
  */
  constructor() {
    super();
    this._discrete = "x";
    this._levels = 6;

    this._on.mouseenter = () => {};
    this._on["mouseleave.shape"] = () => {
      this.hover(false);
    };
    const defaultMouseMove = this._on["mousemove.shape"];
    this._on["mousemove.shape"] = (d, i) => {
      defaultMouseMove(d, i);
      const id = this._id(d, i);

      this.hover((h, x) => this._x(h, x) === id);
    };

    this._radarPadding = 100;

    this._shape = constant("Path");
    this._shapeConfig = assign(this._shapeConfig, {
      Circle: {
        r: accessor("r", 0),
        fill: constant("none"),
        stroke: constant("#CCC"),
        strokeWidth: constant(1)
      },
      Path: {
        fillOpacity: 0.7
      }
    });
    this._xConfig = {
      height: 0
    };
    this._value = accessor("value");
    this._x = accessor("x");
    this._y = accessor("y");
  }

  /**
      Extends the draw behavior of the abstract Plot class.
      @private
  */
  _draw(callback) {
    const height = this._height - this._margin.top - this._margin.bottom,
          width = this._width - this._margin.left - this._margin.right;

    const radius = (Math.min(height, width) - this._radarPadding) / 2,
          transform = `translate(${width / 2}, ${height / 2})`;

    const maxValue = Math.max(...this._data.map((d, i) => this._value(d, i))),
          nestedAxisData = nest()
        .key(this._y)
        .entries(this._data),
          nestedGroupData = nest()
        .key(this._x)
        .entries(this._data);

    const circularAxis = Array.from(Array(this._levels).keys()).map(d => ({
      id: d,
      r: radius * ((d + 1) / this._levels)
    }));

    this._shapes.push(
      new Circle()
        .data(circularAxis)
        .select(
          elem("g.d3plus-Radar-radial-circles", {
            parent: this._select,
            enter: {transform},
            update: {transform}
          }).node()
        )
        .config(configPrep.bind(this)(this._shapeConfig, "shape", "Circle"))
        .render()
    );

    const totalAxis = nestedAxisData.length;
    const polarAxis = nestedAxisData
      .map((d, i) => {
        const angle = tau / totalAxis * i;
        return {
          id: d.key,
          angle: 360 - 360 / totalAxis * i,
          quadrant: parseInt(360 - 360 / totalAxis * i / 90, 10) % 4 + 1,
          x: radius * Math.cos(angle),
          y: radius * Math.sin(angle)
        };
      })
      .sort((a, b) => a.key - b.key);

    this._shapes.push(
      new TextBox()
        .data(polarAxis)
        .rotate(
          d => d.angle < 90 || d.angle > 270 ? -d.angle : -d.angle + 180
        )
        .rotateAnchor([0, 0])
        .textAnchor(d => [1, 4].includes(d.quadrant) ? "start" : "end")
        .height(14)
        .text(d => d.id)
        .x(d => d.x)
        .y(d => d.y)
        .select(
          elem("g.d3plus-Radar-text", {
            parent: this._select,
            enter: {transform},
            update: {transform}
          }).node()
        )
        .render()
    );

    d3.selectAll("g.d3plus-Radar-text text")
      .data(polarAxis)
      .attr("x", d => d.x < 0 ? -10 : 10)
      .attr("y", 5);

    this._shapes.push(
      new Path()
        .data(polarAxis)
        .d(d => `M${0},${0} ${-d.x},${-d.y}`)
        .select(
          elem("g.d3plus-Radar-axis", {
            parent: this._select,
            enter: {transform},
            update: {transform}
          }).node()
        )
        .config(this._shapeConfig.Circle)
        .render()
    );

    const groupData = nestedGroupData.map(h => {
      const q = h.values.map((d, i) => {
        const angle = tau / totalAxis * i,
              r = this._value(d, i) / maxValue * radius;
        return {
          x: r * Math.cos(angle),
          y: r * Math.sin(angle)
        };
      });

      const d = `M ${q[0].x} ${q[0].y} ${q
        .map(l => `L ${l.x} ${l.y}`)
        .join(" ")}`;

      return {id: h.key, d};
    });

    this._shapes.push(
      new Path()
        .data(groupData)
        .d(d => d.d)
        .select(
          elem("g.d3plus-Radar-items", {
            parent: this._select,
            enter: {transform},
            update: {transform}
          }).node()
        )
        .config(configPrep.bind(this)(this._shapeConfig, "shape", "Path"))
        .render()
    );

    super._draw(callback);

    return this;
  }

  /**
      @memberof Radar
      @desc If *value* is specified, sets the hover method to the specified function and returns the current class instance.
      @param {Function} [*value*]
      @chainable
   */
  hover(_) {
    this._hover = _;
    this._shapes.forEach(s => s.hover(_));
    if (this._legend) this._legendClass.hover(_);

    return this;
  }

  /**
      @memberof Radar
      @desc If *value* is specified, sets the padding of the chart and returns the current class instance. If *value* is not specified, returns the current radarPadding. By default, the radarPadding is 100.
      @param {Number} [*value* = 100]
      @chainable
  */
  radarPadding(_) {
    return arguments.length
      ? (this._radarPadding = _, this)
      : this._radarPadding;
  }

  /**
      @memberof Radar
      @desc If *value* is specified, sets the value accessor to the specified function or number and returns the current class instance. If *value* is not specified, returns the current value accessor.
      @param {Function|String} *value*
      @example
function value(d) {
  return d.value;
}
  */
  value(_) {
    return arguments.length
      ? (this._value = typeof _ === "function" ? _ : accessor(_), this)
      : this._value;
  }

  /**
      @memberof Plot
      @desc Sets the x accessor to the specified function or number. If *value* is not specified, returns the current x accessor.
      @param {Function|Number} *value*
      @chainable
  */
  x(_) {
    if (arguments.length) {
      if (typeof _ === "function") this._x = _;
      else {
        this._x = accessor(_);
        if (!this._aggs[_] && this._discrete === "x") {
          this._aggs[_] = a => {
            const v = Array.from(new Set(a));
            return v.length === 1 ? v[0] : v;
          };
        }
      }
      return this;
    }
    else return this._x;
  }

  /**
      @memberof Plot
      @desc Sets the y accessor to the specified function or number. If *value* is not specified, returns the current y accessor.
      @param {Function|Number} *value*
      @chainable
  */
  y(_) {
    if (arguments.length) {
      if (typeof _ === "function") this._y = _;
      else {
        this._y = accessor(_);
        if (!this._aggs[_] && this._discrete === "y") {
          this._aggs[_] = a => {
            const v = Array.from(new Set(a));
            return v.length === 1 ? v[0] : v;
          };
        }
      }
      return this;
    }
    else return this._y;
  }
}
<commit_msg>adds style using axisConfig<commit_after>/**
    @external Viz
    @see https://github.com/d3plus/d3plus-viz#Viz
*/
import {nest} from "d3-collection";
import * as d3 from "d3-selection";
import {accessor, assign, configPrep, constant, elem} from "d3plus-common";
import {Circle, Path} from "d3plus-shape";
import {TextBox} from "d3plus-text";
import {Viz} from "d3plus-viz";

const tau = Math.PI * 2;

/**
    @class Radar
    @extends Plot
    @desc Creates a radar visualization based on an array of data.
*/
export default class Radar extends Viz {

  /**
      @memberof Radar
      @desc Invoked when creating a new class instance, and overrides any default parameters inherited from Plot.
      @private
  */
  constructor() {
    super();

    this._axisConfig = {
      fill: constant("none"),
      stroke: constant("#CCC"),
      strokeWidth: constant(1)
    };
    this._hover = true;
    this._levels = 6;

    this._radarPadding = 100;

    this._shape = constant("Path");
    this._shapeConfig = assign(this._shapeConfig, {
      Circle: {
        r: accessor("r", 0)
      },
      Path: {}
    });
    this._value = accessor("value");
    this._x = accessor("x");
    this._y = accessor("y");
  }

  /**
      Extends the draw behavior of the abstract Plot class.
      @private
  */
  _draw(callback) {
    super._draw(callback);
    const height = this._height - this._margin.top - this._margin.bottom,
          width = this._width - this._margin.left - this._margin.right;

    const radius = (Math.min(height, width) - this._radarPadding) / 2,
          transform = `translate(${width / 2}, ${height / 2})`;

    const maxValue = Math.max(...this._data.map((d, i) => this._value(d, i))),
          nestedAxisData = nest()
        .key(this._y)
        .entries(this._data),
          nestedGroupData = nest()
        .key(this._x)
        .entries(this._data);

    const circularAxis = Array.from(Array(this._levels).keys()).map(d => ({
      id: d,
      r: radius * ((d + 1) / this._levels)
    }));

    new Circle()
      .data(circularAxis)
      .select(
        elem("g.d3plus-Radar-radial-circles", {
          parent: this._select,
          enter: {transform},
          update: {transform}
        }).node()
      )
      .config(configPrep.bind(this)(this._shapeConfig, "shape", "Circle"))
      .config(this._axisConfig)
      .render();

    const totalAxis = nestedAxisData.length;
    const polarAxis = nestedAxisData
      .map((d, i) => {
        const angle = tau / totalAxis * i;
        return {
          id: d.key,
          angle: 360 - 360 / totalAxis * i,
          quadrant: parseInt(360 - 360 / totalAxis * i / 90, 10) % 4 + 1,
          x: radius * Math.cos(angle),
          y: radius * Math.sin(angle)
        };
      })
      .sort((a, b) => a.key - b.key);

    /* new TextBox()
        .data(polarAxis)
        .rotate(
          d => d.angle < 90 || d.angle > 270 ? -d.angle : -d.angle + 180
        )
        .rotateAnchor([0, 0])
        .textAnchor(d => [1, 4].includes(d.quadrant) ? "start" : "end")
        .height(14)
        .text(d => d.id)
        .x(d => d.x)
        .y(d => d.y)
        .select(
          elem("g.d3plus-Radar-text", {
            parent: this._select,
            enter: {transform},
            update: {transform}
          }).node()
        )
        .render()
    ;*/

    /*  d3.selectAll("g.d3plus-Radar-text text")
      .data(polarAxis)
      .attr("x", d => d.x < 0 ? -10 : 10)
      .attr("y", 5);
*/
    new Circle()
      .data(polarAxis)
      .rotate(d => d.angle < 90 || d.angle > 270 ? -d.angle : -d.angle + 180)
      .r(10)
      .x(d => d.x)
      .y(d => d.y)
      .label(d => d.id)
      .labelBounds(() => ({x: 15, y: -15, width: 80, height: 30}))
      .labelConfig({
        // rotateAnchor: [0, 0],
        fontColor: "black",
        verticalAlign: "middle",
        x: d => d.x
      })
      .select(
        elem("g.d3plus-Radar-text", {
          parent: this._select,
          enter: {transform},
          update: {transform}
        }).node()
      )
      .textAnchor(d => [1, 4].includes(d.quadrant) ? "start" : "end")
      // .rotate(-60)
      .render();

    new Path()
      .data(polarAxis)
      .d(d => `M${0},${0} ${-d.x},${-d.y}`)
      .select(
        elem("g.d3plus-Radar-axis", {
          parent: this._select,
          enter: {transform},
          update: {transform}
        }).node()
      )
      .config(this._axisConfig)
      .render();

    const groupData = nestedGroupData.map(h => {
      const q = h.values.map((d, i) => {
        const angle = tau / totalAxis * i,
              r = this._value(d, i) / maxValue * radius;
        return {
          x: r * Math.cos(angle),
          y: r * Math.sin(angle)
        };
      });

      const d = `M ${q[0].x} ${q[0].y} ${q
        .map(l => `L ${l.x} ${l.y}`)
        .join(" ")}`;

      return {id: h.key, d};
    });

    this._shapes.push(
      new Path()
        .data(groupData)
        .d(d => d.d)
        .select(
          elem("g.d3plus-Radar-items", {
            parent: this._select,
            enter: {transform},
            update: {transform}
          }).node()
        )
        .config(configPrep.bind(this)(this._shapeConfig, "shape", "Path"))
        .render()
    );

    return this;
  }

  /**
      @memberof Radar
      @desc If *value* is specified, sets the padding of the chart and returns the current class instance. If *value* is not specified, returns the current radarPadding. By default, the radarPadding is 100.
      @param {Number} [*value* = 100]
      @chainable
  */
  radarPadding(_) {
    return arguments.length
      ? (this._radarPadding = _, this)
      : this._radarPadding;
  }

  /**
      @memberof Radar
      @desc If *value* is specified, sets the value accessor to the specified function or number and returns the current class instance. If *value* is not specified, returns the current value accessor.
      @param {Function|String} *value*
      @example
function value(d) {
  return d.value;
}
  */
  value(_) {
    return arguments.length
      ? (this._value = typeof _ === "function" ? _ : accessor(_), this)
      : this._value;
  }

  /**
      @memberof Plot
      @desc Sets the x accessor to the specified function or number. If *value* is not specified, returns the current x accessor.
      @param {Function|Number} *value*
      @chainable
  */
  x(_) {
    if (arguments.length) {
      if (typeof _ === "function") this._x = _;
      else {
        this._x = accessor(_);
        if (!this._aggs[_] && this._discrete === "x") {
          this._aggs[_] = a => {
            const v = Array.from(new Set(a));
            return v.length === 1 ? v[0] : v;
          };
        }
      }
      return this;
    }
    else return this._x;
  }

  /**
      @memberof Plot
      @desc Sets the y accessor to the specified function or number. If *value* is not specified, returns the current y accessor.
      @param {Function|Number} *value*
      @chainable
  */
  y(_) {
    if (arguments.length) {
      if (typeof _ === "function") this._y = _;
      else {
        this._y = accessor(_);
        if (!this._aggs[_] && this._discrete === "y") {
          this._aggs[_] = a => {
            const v = Array.from(new Set(a));
            return v.length === 1 ? v[0] : v;
          };
        }
      }
      return this;
    }
    else return this._y;
  }

  hover(_) {
    this._hover = _;
    this._shapes.forEach(s => s.hover(_));
    if (this._legend) this._legendClass.hover(_);

    return this;
  }
}
<|endoftext|>


<commit_before>var _ = require('lodash')
var transform = require('./transform.js')

function Autohead(data) {
  if (!data) data = {}
  this.keymap = data.keymap || {angle: ['Q', 'W', 'E', 'A', 'S', 'D']}
  this.on = {angle: [false, false, false, false, false, false]}
  this.end = 0
}

Autohead.prototype.compute = function(keys, start, offset, container) {
  var self = this

  var check = function(i) {
    return self.keymap.angle[i] in keys & !self.any()
  }
  var pressed = function(i) {
    return self.keymap.angle[i] in keys
  }
 var released = !(pressed(0) || pressed(1) || pressed(2)  || pressed(3) || pressed(4) || pressed(5))

  var rad = function(a) {
    return a * Math.PI / 180
  }

  var height = 8

  if (check(0)) {
    if (container.contains(start.position())) {
      self.on.angle[0] = true
      self.end = {
        position: [height * Math.cos(rad(start.angle() + 210)), height * Math.sin(rad(start.angle() + 210))],
        angle: start.angle() - 60
      }
      self.end.position[0] += offset.position()[0]
      self.end.position[1] += offset.position()[1]
    }
  }

  if (check(1)) {
    if (container.contains(start.position())) {
      self.on.angle[1] = true
      self.end = {
        position: [height * Math.cos(rad(start.angle() - 90)), height * Math.sin(rad(start.angle() - 90))],
        angle: start.angle()
      }
      self.end.position[0] += offset.position()[0]
      self.end.position[1] += offset.position()[1]
    }
  }

  if (check(2)) {
    if (container.contains(start.position())) {
      self.on.angle[2] = true
      self.end = {
        position: [height * Math.cos(rad(start.angle() - 30)), height * Math.sin(rad(start.angle() - 30))],
        angle: start.angle() + 60
      }
      self.end.position[0] += offset.position()[0]
      self.end.position[1] += offset.position()[1]
    }
  }

  if (check(3)) {
    if (container.contains(start.position())) {
      self.on.angle[3] = true
      self.end = {
        position: [height * Math.cos(rad(start.angle() - 210)), height * Math.sin(rad(start.angle() - 210))],
        angle: start.angle() - 120
      }
      self.end.position[0] += offset.position()[0]
      self.end.position[1] += offset.position()[1]
    }
  }

  if (check(4)) {
    if (container.contains(start.position())) {
      self.on.angle[4] = true
      self.end = {
        position: [height * Math.cos(rad(start.angle() - 270)), height * Math.sin(rad(start.angle() - 270))],
        angle: start.angle() - 180
      }
      self.end.position[0] += offset.position()[0]
      self.end.position[1] += offset.position()[1]
    } else {
      self.on.angle[4] = true
      var rad = (start.angle() - 180) * Math.PI / 180
      self.end = {
        position: [start.position()[0] + 0.5 * Math.sin(rad), start.position()[1] - 0.5 * Math.cos(rad)],
        angle: start.angle() - 180
      }
    }
  }

  if (check(5)) {
    if (container.contains(start.position())) {
      self.on.angle[5] = true
      self.end = {
        position: [height * Math.cos(rad(start.angle() + 30)), height * Math.sin(rad(start.angle() + 30))],
        angle: start.angle() + 120
      }
      self.end.position[0] += offset.position()[0]
      self.end.position[1] += offset.position()[1]
    }
  }

  var rad = start.angle() * Math.PI / 180
  var forward = {position: [0.75 * Math.sin(rad), 0.75 * -Math.cos(rad)]}

  if (self.end) {
    var distance = start.distance(self.end)
    if (distance.position || distance.angle) {
      return self.delta(start, self.end)
    } else {
      if (released) self.reset()
      self.end = 0
      return forward
    }
  } else {
      if (released) self.reset()
      return forward
  }

}

Autohead.prototype.reset = function() {
  var self = this
  _.range(6).forEach(function (i) {
    self.on.angle[i] = false
  })
}

Autohead.prototype.any = function() {
  var self = this
  return _.any(self.on.angle)
}

Autohead.prototype.delta = function(start, end) {

  var x = (end.position[0] - start.position()[0])
  var y = (end.position[1] - start.position()[1])
  var s = end.angle - start.angle()

  var speed = {position: 1.0, angle: 10.0}

  var distance = start.distance(end)

  if (distance.position > speed.position) {
    x = x/distance.position
    y = y/distance.position
    if (distance.angle > speed.angle) {
      speed.position = speed.angle * distance.position / distance.angle
    }
  } else {
    speed.position = 1
  }

  if (distance.angle > speed.angle) {
    s = s/distance.angle
  } else {
    speed.angle = 1
  }

  return {position: [x * speed.position, y * speed.position], angle: s * speed.angle}

}

module.exports = Autohead<commit_msg>Clean up delta<commit_after>var _ = require('lodash')
var transform = require('./transform.js')

function Autohead(data) {
  if (!data) data = {}
  this.speed = data.speed || {position: 1, angle: 10}
  this.keymap = data.keymap || {angle: ['Q', 'W', 'E', 'A', 'S', 'D']}
  this.on = {angle: [false, false, false, false, false, false]}
  this.end = 0
}

Autohead.prototype.compute = function(keys, start, offset, container) {
  var self = this

  var check = function(i) {
    return self.keymap.angle[i] in keys & !self.any()
  }
  var pressed = function(i) {
    return self.keymap.angle[i] in keys
  }
 var released = !(pressed(0) || pressed(1) || pressed(2)  || pressed(3) || pressed(4) || pressed(5))

  var rad = function(a) {
    return a * Math.PI / 180
  }

  var height = 8

  if (check(0)) {
    if (container.contains(start.position())) {
      self.on.angle[0] = true
      self.end = {
        position: [height * Math.cos(rad(start.angle() + 210)), height * Math.sin(rad(start.angle() + 210))],
        angle: start.angle() - 60
      }
      self.end.position[0] += offset.position()[0]
      self.end.position[1] += offset.position()[1]
    }
  }

  if (check(1)) {
    if (container.contains(start.position())) {
      self.on.angle[1] = true
      self.end = {
        position: [height * Math.cos(rad(start.angle() - 90)), height * Math.sin(rad(start.angle() - 90))],
        angle: start.angle()
      }
      self.end.position[0] += offset.position()[0]
      self.end.position[1] += offset.position()[1]
    }
  }

  if (check(2)) {
    if (container.contains(start.position())) {
      self.on.angle[2] = true
      self.end = {
        position: [height * Math.cos(rad(start.angle() - 30)), height * Math.sin(rad(start.angle() - 30))],
        angle: start.angle() + 60
      }
      self.end.position[0] += offset.position()[0]
      self.end.position[1] += offset.position()[1]
    }
  }

  if (check(3)) {
    if (container.contains(start.position())) {
      self.on.angle[3] = true
      self.end = {
        position: [height * Math.cos(rad(start.angle() - 210)), height * Math.sin(rad(start.angle() - 210))],
        angle: start.angle() - 120
      }
      self.end.position[0] += offset.position()[0]
      self.end.position[1] += offset.position()[1]
    }
  }

  if (check(4)) {
    if (container.contains(start.position())) {
      self.on.angle[4] = true
      self.end = {
        position: [height * Math.cos(rad(start.angle() - 270)), height * Math.sin(rad(start.angle() - 270))],
        angle: start.angle() - 180
      }
      self.end.position[0] += offset.position()[0]
      self.end.position[1] += offset.position()[1]
    } else {
      self.on.angle[4] = true
      var rad = (start.angle() - 180) * Math.PI / 180
      self.end = {
        position: [start.position()[0] + 0.5 * Math.sin(rad), start.position()[1] - 0.5 * Math.cos(rad)],
        angle: start.angle() - 180
      }
    }
  }

  if (check(5)) {
    if (container.contains(start.position())) {
      self.on.angle[5] = true
      self.end = {
        position: [height * Math.cos(rad(start.angle() + 30)), height * Math.sin(rad(start.angle() + 30))],
        angle: start.angle() + 120
      }
      self.end.position[0] += offset.position()[0]
      self.end.position[1] += offset.position()[1]
    }
  }

  var rad = start.angle() * Math.PI / 180
  var forward = {position: [0.75 * Math.sin(rad), 0.75 * -Math.cos(rad)]}

  if (self.end) {
    var distance = start.distance(self.end)
    if (distance.position || distance.angle) {
      return self.delta(start, self.end)
    } else {
      if (released) self.reset()
      self.end = 0
      return forward
    }
  } else {
      if (released) self.reset()
      return forward
  }

}

Autohead.prototype.reset = function() {
  var self = this
  _.range(6).forEach(function (i) {
    self.on.angle[i] = false
  })
}

Autohead.prototype.any = function() {
  var self = this
  return _.any(self.on.angle)
}

Autohead.prototype.delta = function(start, end) {

  var speed = this.speed
  var scale = {position: 1, angle: 1}

  var diff = start.difference(end)
  var dist = start.distance(end)

  if (dist.position > speed.position) {
    diff.position[0] = diff.position[0] / dist.position
    diff.position[1] = diff.position[1] / dist.position
    scale.position = speed.position
    if (dist.angle > speed.angle) scale.position = speed.angle * dist.position / dist.angle
  }

  if (dist.angle > speed.angle) {
    diff.angle = diff.angle / dist.angle
    scale.angle = speed.angle
  }

  return {
    position: [
      diff.position[0] * scale.position,
      diff.position[1] * scale.position
    ],
    angle: diff.angle * scale.angle
  }
}

module.exports = Autohead<|endoftext|>


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

'use strict';

var macros = require('../macros')
var whois;

if (macros.UNIT_TESTS) {
	whois = require('./tests/mockWhois')
}
else {
	whois = require('whois')
}

var he = require('he');
var _ = require('lodash');
var domutils = require('domutils');
var async = require('async')

var pointer = require('../pointer');
var BaseParser = require('./baseParser').BaseParser;
var collegeNamesDB = require('../databases/collegeNamesDB');

function CollegeNamesParser() {
	BaseParser.prototype.constructor.apply(this, arguments);

	this.name = 'CollegeNamesParser';

	this.requiredAttrs = [
		"title",
		"host"
	];

}

//prototype constructor
CollegeNamesParser.prototype = Object.create(BaseParser.prototype);
CollegeNamesParser.prototype.constructor = CollegeNamesParser;

CollegeNamesParser.prototype.getDatabase = function (pageData) {
	return collegeNamesDB;
};

//callback here is pageData (stuff to store in db), and metadata (stuff dont store in db)
CollegeNamesParser.prototype.parse = function (pageData, callback) {

	this.getTitle(pageData.dbData.url, function (err, title) {
		if (err) {
			console.log('college names parse error', err);
			return callback(err)
		}
		pageData.setData('title', title);
		pageData.setData('host', pageData.dbData.url);
		callback()

	}.bind(this))
};

CollegeNamesParser.prototype.standardizeNames = function (startStrip, endStrip, title) {

	//remove stuff from the beginning
	startStrip.forEach(function (str) {
		if (title.toLowerCase().indexOf(str) === 0) {
			title = title.substr(str.length);
		}
	}.bind(this));

	//remove stuff from the end
	endStrip.forEach(function (str) {

		var index = title.toLowerCase().indexOf(str);
		if (index === title.length - str.length && index > -1) {
			title = title.substr(0, title.length - str.length);
		}
	}.bind(this));

	// standardize the case
	title = this.toTitleCase(title);

	return title.trim();
}

CollegeNamesParser.prototype.hitPage = function (host, callback) {

	console.log('firing request to ', host)

	pointer.request('http://' + host, null, function (error, dom) {
		if (error) {
			console.log('REQUESTS ERROR:', host, error);

			if (error.code == 'ENOTFOUND' || error.code == 'ETIMEDOUT' || error.code == 'ECONNRESET') {
				if (host.indexOf('www.') === 0) {
					return callback('not found with www.');
				}
				else {
					return this.hitPage('www.' + host, callback);
				}
			}

			return callback(error);
		}
		else {

			//find the title
			var elements = domutils.getElementsByTagName('title', dom);
			if (elements.length === 0) {
				console.log('ERROR: ', host, 'has no title??');
				return callback('no title');
			}
			else if (elements.length === 1) {

				//get the text from the title element
				var title = domutils.getText(elements[0]).trim();
				if (title.length < 2) {
					console.log('empty title', host, title);
					return callback('empty title');
				}
				title = he.decode(title);

				//strip off any description from the end
				title = title.match(/[\w\d\s&]+/i);
				if (!title) {
					console.log('ERROR: title match failed,', host);
					return callback('title match failed')
				}

				title = title[0].trim();
				if (title.length < 2) {
					console.log('empty title2', host, title);
					return callback('empty title2');
				}

				title = this.standardizeNames(['welcome to'], ['home'], title);

				if (title.length === 0) {
					console.log('Warning: zero title after processing', host);
					return callback('zero title after processing')
				}

				callback(null, title);
			}
		}
	}.bind(this));
};

CollegeNamesParser.prototype.hitWhois = function (host, callback) {

	//each domain has a different format and would probably need a different regex
	//this one works for edu and ca, but warn if find a different one
	var hostSplitByDot = host.split('.')
	if (!_(['ca', 'edu']).includes(hostSplitByDot[hostSplitByDot.length - 1])) {
		console.log('Warning, unknown domain ' + host)
	}

	// try calling apiMethod 3 times, waiting 200 ms between each retry
	async.retry({
			times: 30,
			interval: 500 + parseInt(Math.random() * 1000)
		},
		function (callback) {
			whois.lookup(host, function (err, data) {
				callback(err, data)
			}.bind(this))
		}.bind(this),
		function (err, data) {
			if (err) {

				console.log('ERROR whois error', err, host);
				return callback('whois error');
			}

			var match = data.match(/Registrant:\n[\w\d\s&:']+?(\n)/i);

			if (!match) {
				console.log('ERROR: whois regex fail', data, host);
				return callback('whois error');
			}

			var name = match[0].replace('Registrant:', '').trim()

			name = this.standardizeNames(['name:'], [], name);

			if (name.length < 2) {
				console.log('Error: ')
				return callback('whois error');
			}

			callback(null, name);

		}.bind(this));
}

//hits database, and if not in db, hits page and adds it to db
CollegeNamesParser.prototype.getTitle = function (host, callback) {
	if (host === 'neu.edu') {
		return callback(null, "Northeastern University")
	}

	this.hitWhois(host, callback);

}

CollegeNamesParser.prototype.go = function () {

};

CollegeNamesParser.prototype.CollegeNamesParser = CollegeNamesParser;
module.exports = new CollegeNamesParser();

if (require.main === module) {
	module.exports.go();
}
<commit_msg>added a comment about college name parser[ci skip].<commit_after>/*
 * Copyright (c) 2017 Ryan Hughes
 *
 * This file is part of CoursePro.
 *
 * CoursePro is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License
 * version 3 as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

 // The point of this file is to get the name of a college from the hostname of their domain
 // Eg neu.edu -> Northeastern University
 // Couple different ways to do this
 // 1. There is a data dump for 7000 Universities created in 2013 that has many colleges in it.
 //     This was found here https://inventory.data.gov/dataset/032e19b4-5a90-41dc-83ff-6e4cd234f565/resource/38625c3d-5388-4c16-a30f-d105432553a4
 //     and is rehosted here: https://github.com/ryanhugh/coursepro/blob/master/docs/universities%20in%202013.csv
 //     This file, however, sometimes lists different colleges in the same University on the spreadsheet. Probably want manually investigate if there is > 1 row that lists a given domain
 //     Might be able to find the minimum overlap in the college name
 // 2. Hit whois. This has been suprisingly unreliable over the last couple years. Sometimes the whois server switches, etc.
 // 3. Hit the website and inspect the https certificate.
 // 4. Hit the website and find the <title> in the html. This is the least reliable of all of them.
 // Once have a name for a given college, can store forever because it is not going to change.

'use strict';

var macros = require('../macros')
var whois;

if (macros.UNIT_TESTS) {
	whois = require('./tests/mockWhois')
}
else {
	whois = require('whois')
}

var he = require('he');
var _ = require('lodash');
var domutils = require('domutils');
var async = require('async')

var pointer = require('../pointer');
var BaseParser = require('./baseParser').BaseParser;
var collegeNamesDB = require('../databases/collegeNamesDB');

function CollegeNamesParser() {
	BaseParser.prototype.constructor.apply(this, arguments);

	this.name = 'CollegeNamesParser';

	this.requiredAttrs = [
		"title",
		"host"
	];

}

//prototype constructor
CollegeNamesParser.prototype = Object.create(BaseParser.prototype);
CollegeNamesParser.prototype.constructor = CollegeNamesParser;

CollegeNamesParser.prototype.getDatabase = function (pageData) {
	return collegeNamesDB;
};

//callback here is pageData (stuff to store in db), and metadata (stuff dont store in db)
CollegeNamesParser.prototype.parse = function (pageData, callback) {

	this.getTitle(pageData.dbData.url, function (err, title) {
		if (err) {
			console.log('college names parse error', err);
			return callback(err)
		}
		pageData.setData('title', title);
		pageData.setData('host', pageData.dbData.url);
		callback()

	}.bind(this))
};

CollegeNamesParser.prototype.standardizeNames = function (startStrip, endStrip, title) {

	//remove stuff from the beginning
	startStrip.forEach(function (str) {
		if (title.toLowerCase().indexOf(str) === 0) {
			title = title.substr(str.length);
		}
	}.bind(this));

	//remove stuff from the end
	endStrip.forEach(function (str) {

		var index = title.toLowerCase().indexOf(str);
		if (index === title.length - str.length && index > -1) {
			title = title.substr(0, title.length - str.length);
		}
	}.bind(this));

	// standardize the case
	title = this.toTitleCase(title);

	return title.trim();
}

CollegeNamesParser.prototype.hitPage = function (host, callback) {

	console.log('firing request to ', host)

	pointer.request('http://' + host, null, function (error, dom) {
		if (error) {
			console.log('REQUESTS ERROR:', host, error);

			if (error.code == 'ENOTFOUND' || error.code == 'ETIMEDOUT' || error.code == 'ECONNRESET') {
				if (host.indexOf('www.') === 0) {
					return callback('not found with www.');
				}
				else {
					return this.hitPage('www.' + host, callback);
				}
			}

			return callback(error);
		}
		else {

			//find the title
			var elements = domutils.getElementsByTagName('title', dom);
			if (elements.length === 0) {
				console.log('ERROR: ', host, 'has no title??');
				return callback('no title');
			}
			else if (elements.length === 1) {

				//get the text from the title element
				var title = domutils.getText(elements[0]).trim();
				if (title.length < 2) {
					console.log('empty title', host, title);
					return callback('empty title');
				}
				title = he.decode(title);

				//strip off any description from the end
				title = title.match(/[\w\d\s&]+/i);
				if (!title) {
					console.log('ERROR: title match failed,', host);
					return callback('title match failed')
				}

				title = title[0].trim();
				if (title.length < 2) {
					console.log('empty title2', host, title);
					return callback('empty title2');
				}

				title = this.standardizeNames(['welcome to'], ['home'], title);

				if (title.length === 0) {
					console.log('Warning: zero title after processing', host);
					return callback('zero title after processing')
				}

				callback(null, title);
			}
		}
	}.bind(this));
};

CollegeNamesParser.prototype.hitWhois = function (host, callback) {

	//each domain has a different format and would probably need a different regex
	//this one works for edu and ca, but warn if find a different one
	var hostSplitByDot = host.split('.')
	if (!_(['ca', 'edu']).includes(hostSplitByDot[hostSplitByDot.length - 1])) {
		console.log('Warning, unknown domain ' + host)
	}

	// try calling apiMethod 3 times, waiting 200 ms between each retry
	async.retry({
			times: 30,
			interval: 500 + parseInt(Math.random() * 1000)
		},
		function (callback) {
			whois.lookup(host, function (err, data) {
				callback(err, data)
			}.bind(this))
		}.bind(this),
		function (err, data) {
			if (err) {

				console.log('ERROR whois error', err, host);
				return callback('whois error');
			}

			var match = data.match(/Registrant:\n[\w\d\s&:']+?(\n)/i);

			if (!match) {
				console.log('ERROR: whois regex fail', data, host);
				return callback('whois error');
			}

			var name = match[0].replace('Registrant:', '').trim()

			name = this.standardizeNames(['name:'], [], name);

			if (name.length < 2) {
				console.log('Error: ')
				return callback('whois error');
			}

			callback(null, name);

		}.bind(this));
}

//hits database, and if not in db, hits page and adds it to db
CollegeNamesParser.prototype.getTitle = function (host, callback) {
	if (host === 'neu.edu') {
		return callback(null, "Northeastern University")
	}

	this.hitWhois(host, callback);

}

CollegeNamesParser.prototype.go = function () {

};

CollegeNamesParser.prototype.CollegeNamesParser = CollegeNamesParser;
module.exports = new CollegeNamesParser();

if (require.main === module) {
	module.exports.go();
}
<|endoftext|>


<commit_before>var fs = require('fs')
var path = require('path')
var mapboxgl = require('mapbox-gl')
var Layers = require('mapbox-gl-layers')
var ready = require('./ready')
var insertCss = require('./insert-css')
var renderProperties = require('./render-properties')

// default is the 'rem-web-demo' API token in the devseed account
mapboxgl.accessToken = process.env.MapboxAccessToken || 'pk.eyJ1IjoiZGV2c2VlZCIsImEiOiJjaW14d2w2MW8wM2tndXJra2locWczMGR2In0._7KBuOaYm9R1rK3K6hdJlQ'

// setup the document
ready(function () {
  insertCss()

  // stick a container div into the document if there isn't one already
  if (!document.querySelector('#rem-map')) {
    var container = document.createElement('div')
    container.id = 'rem-map'
    container.style.position = 'absolute'
    container.style.top = container.style.bottom = 0
    container.style.width = '100%'
    document.body.appendChild(container)
  }

  // boot up the map
  var map = new mapboxgl.Map({
    container: 'rem-map',
    style: 'mapbox://styles/devseed/cin0qcvll0016b7kqh7mc5y2c'
  })
  window.map = map
  map.on('style.load', function () { onLoad(map) })
})

function onLoad (map) {
  map.addControl(new mapboxgl.Navigation({ position: 'bottom-right' }))
  var satLayers = map.getStyle().layers
    .map((layer) => layer.id)
    .filter((id) => id.startsWith('satellite'))
  map.addControl(new Layers({
    layers: { 'Satellite Layer': satLayers }
  }))

  var popup
  map.on('mousemove', function (e) {
    var features = map.queryRenderedFeatures(e.point, {
      radius: 7,
      layers: [
        'lv-transformer',
        'mv-transformer',
        'lv-generator',
        'mv-generator',
        'lv-network',
        'mv-network'
      ]
    })
    // Change the cursor style as a UI indicator.
    map.getCanvas().style.cursor = (features.length) ? 'pointer' : ''
    if (!features.length) {
      if (popup) { popup.remove() }
      popup = null
      return
    }

    if (!popup) {
      popup = new mapboxgl.Popup({ closeButton: false, closeOnClick: false })
      popup.addTo(map)
    }

    popup.setLngLat(e.lngLat).setDOMContent(renderProperties(features))
  })
}
<commit_msg>Add toggles for model and estimated customer location<commit_after>var fs = require('fs')
var path = require('path')
var mapboxgl = require('mapbox-gl')
var Layers = require('mapbox-gl-layers')
var ready = require('./ready')
var insertCss = require('./insert-css')
var renderProperties = require('./render-properties')

// default is the 'rem-web-demo' API token in the devseed account
mapboxgl.accessToken = process.env.MapboxAccessToken || 'pk.eyJ1IjoiZGV2c2VlZCIsImEiOiJjaW14d2w2MW8wM2tndXJra2locWczMGR2In0._7KBuOaYm9R1rK3K6hdJlQ'

// setup the document
ready(function () {
  insertCss()

  // stick a container div into the document if there isn't one already
  if (!document.querySelector('#rem-map')) {
    var container = document.createElement('div')
    container.id = 'rem-map'
    container.style.position = 'absolute'
    container.style.top = container.style.bottom = 0
    container.style.width = '100%'
    document.body.appendChild(container)
  }

  // boot up the map
  var map = new mapboxgl.Map({
    container: 'rem-map',
    style: 'mapbox://styles/devseed/cin0qcvll0016b7kqh7mc5y2c'
  })
  window.map = map
  map.on('style.load', function () { onLoad(map) })
})

var modelLayers = [
  'lv-transformer',
  'mv-transformer',
  'lv-generator',
  'mv-generator',
  'lv-network',
  'mv-network'
]
modelLayers = modelLayers.map((x) => 'ug-' + x)
  .concat(modelLayers.map((x) => 'ext-' + x))

function onLoad (map) {
  map.addControl(new mapboxgl.Navigation({ position: 'bottom-right' }))
  var satLayers = map.getStyle().layers
    .map((layer) => layer.id)
    .filter((id) => id.startsWith('satellite'))
  map.addControl(new Layers({
    layers: {
      'Satellite Layer': satLayers,
      'Customer Locations': [ 'customers-non-electrified', 'customers-electrified' ],
      'REM Output': modelLayers.concat(['rem-customers'])
    }
  }))

  var popup
  map.on('mousemove', function (e) {
    var features = map.queryRenderedFeatures(e.point, {
      radius: 7,
      layers: modelLayers
    })
    // Change the cursor style as a UI indicator.
    map.getCanvas().style.cursor = (features.length) ? 'pointer' : ''
    if (!features.length) {
      if (popup) { popup.remove() }
      popup = null
      return
    }

    if (!popup) {
      popup = new mapboxgl.Popup({ closeButton: false, closeOnClick: false })
      popup.addTo(map)
    }

    popup.setLngLat(e.lngLat).setDOMContent(renderProperties(features))
  })
}
<|endoftext|>