<commit_before>// Define module using Universal Module Definition pattern
// https://github.com/umdjs/umd/blob/master/returnExports.js

(function (root, factory) {
  if (typeof define === 'function' && define.amd) {
    // AMD. Register as an anonymous module.
    define(['d3', 'vega', 'vegalite', 'lodash', 'visgen', 'visrank'],factory);
  } else if (typeof exports === 'object') {
    // Node. Does not work with strict CommonJS, but
    // only CommonJS-like environments that support module.exports,
    // like Node.
    module.exports = factory(
      require('d3'),
      require('vega'),
      require('vegalite'),
      require('lodash'),
      require('visgen'),
      require('visrank')
    );
  } else {
    // Browser globals (root is window)
    factory(root.d3, root.vg, root.vl, root._, root.vgn, root.visrank);
  }
}(this, function(d3, vg, vl, _, vgn, visrank){
  var schema, col_indices;

  var HEIGHT_OFFSET = 60, MAX_HEIGHT = 500, MAX_WIDTH = 500;

  var CONFIG = {
    showTable: false,

    genAggr: true,
    genBin: true,
    genTypeCasting: true,

    omitTranpose: true,
    omitDotPlotWithExtraEncoding: true,
    omitAggrWithAllDimsOnFacets: true
  }

  var keys = vg.keys;

  function getVLType(data_type){
    // return vegalite's data type
    var typeMap = {
      "categorical": "O",
      "geographic": "G",
      "quantitative": "Q",
      "datetime": "T",
      "count": "Q"
    };
    return typeMap[data_type];
  }

  function init(){
    // d3.select("#toggle-presets").on("click", function(){
    //   var hide = d3.select("#presets").classed("hide")
    //   d3.select("#presets").classed("hide", !hide);
    // });

    d3.select("#toggle-config").on("click", function(){
      var hide = d3.select("#config").classed("hide")
      d3.select("#config").classed("hide", !hide);
    });

    var configs = d3.select("#config").selectAll("div.cfg")
      .data(vl.keys(CONFIG))
      .enter().append("div").attr("class", "cfg")
        .append("label");

    configs.append("input").attr("type","checkbox").attr("class","cfg-check")
      .attr("checked", function(d){ return CONFIG[d];})
      .on("change", updateSelectedFields);

    configs.append("span").attr("class","label config").text(function(d){return d;});

    loadSchema();
  }

  function getConfig(){
    var config = {};
    d3.select("#config").selectAll("div.cfg input.cfg-check")
      .each(function(d){
        config[d] = d3.select(this).node().checked;
      });

    console.log("config", config);
    return config;
  }

  // ----- load schema -----
  function loadSchema(){
    //TODO: use amd-plugin to load json, csv
    d3.json("data/birdstrikes/birdstrikes-schema.json", function(_schema) {
      //TODO: remove this line after updating csv.
      schema = _(_schema).filter(function(d){ return !d.disabled;})
        .sortBy('field_name')
        .sortBy(function(col){
          return getVLType(col.data_type) !== "Q" ? 0 :
            col.data_type === "count" ? 2 : 1 ;
        })
        .map(function(col, i){
          col.key = col['field_name'].replace(/(: )/g, "__").replace(/[\/ ]/g,"_").replace(/[()]/g, "");
          col.index = i; //add index
          return col;
        })
        .value();

      col_indices = _.reduce(schema, function(result, col, i){ result[col] = i; return result;}, {});

      console.log('schema keys', _.pluck(schema,'key').sort());
      console.log('data_types', _(schema).pluck('data_type').uniq().value());
      loadData();
    });
  }

  function updateSelectedFields(){
    var selectedColIndices = [];

    d3.selectAll("#datacols input.datacol").each(function(d, i){
      var selected = d3.select(this).node().checked;
      if(selected){
        selectedColIndices.push(d.index);
      }
    });

    renderMain(selectedColIndices);
  }

  function loadData(){
    // TODO: use other lib to load csv as columns?
    // TODO: regenerate csv with all columns
    d3.json("data/birdstrikes.json", function(data) {
      self.data = data;
      console.log("keys", vg.keys(data[0]));
      renderColumns();
    });
  }

  function renderColumns(){
    var datacols = d3.select("#datacols").selectAll("div")
      .data(schema).enter().append("div").append("label");

    datacols.append("input").attr("type","checkbox").attr("class","datacol")
      .on("change", updateSelectedFields);

    datacols.append("span").attr("class","type").text(function(d){
      return "["+getVLType(d.data_type)+"] ";
    });

    datacols.append("span").attr("class","name").html(function(d){
      return d.field_name;
    });

    // -----  Assume User Selection here -----

    // 0:O "Aircraft: Airline/Operator"
    // 1:O "Aircraft: Make/Model"
    // 2:O "Airport: Name"
    // 3:Q "Cost: Other"
    // 4:Q "Cost: Repair"
    // 5:Q "Cost: Total $"
    // 6:O "Effect: Amount of damage"
    // 7:T "Flight Date"
    // 8:# "Number of Strikes"
    // 9:G "Origin State"
    // 10:Q "Speed (IAS) in knots"
    // 11:O "When: Phase of flight"
    // 12:O "When: Time of day"
    // 13:O "Wildlife: Size"
    // 14:O "Wildlife: Species"

    // var colIndicesSet = [
    //   [6,5,4], //CxQxQ -- good except some bar + size
    //   [6,11,5], //CxCxQ
    //   [6,8], //Cx#
    //   [2,3], //C(Big)xQ
    //   [6, 10], //CxQ
    //   [6,8,5], //Cx#xG
    //   [10], //Q
    //   // [4,5], //QxQ
    //   // [7,8], //Dx#
    //   // [11,12,13], //OxOxO //FIXME
    //   //// [6,5,10] //CxQxQ //TODO: speed might be problematic
    // ];

    // var control = d3.select("#control");

    // var dsel = control.append("select")
    //   .attr("class", "data")
    //   .style("width", "300px")
    //   .on("change", function(){
    //     var index = this.options[this.selectedIndex].value;
    //     render(colIndicesSet[index])
    //   })
    //   .selectAll("option").data(colIndicesSet)
    //   .enter().append("option")
    //     .attr("value", function(d, i){ return i;})
    //     .attr("selected", function(d,i){ return i==0? true : undefined;})
    //     .text(function(d, i){ return getTitle(d);});

    // render(colIndicesSet[0])
  }

  function fieldDetailHtml(v){
    return "" +
      "" +
      (v.aggr ? v.aggr : "") +
      (v.bin ? " bin " : "") +
      "" +
      "" +
      (v.name || "") +
      "" +
      " ("+ v.type + ")";
  }

  function encodingDetails(enc, div){
    div.append("div").html("marktype: "+enc.marktype()+"");
    enc.forEach(function(k, v){
      div.append("div").html(k+": "+fieldDetailHtml(v, vl.dataTypeNames[v.type]))
    });
  }

  function getTitle(colIndices){
    var cols = colIndices.map(function(i){ return schema[i];});

    return cols.map(function(col){
      return col['field_name'] + " [" + col['data_type'][0] +"]";
    }).join(",");
  }

  function getChartsByFieldSet(fields) {
    var config = getConfig();
    var aggr = vgn.genAggregate([], fields, config);
    var chartsByFieldset = aggr.map(function (fields) {
      var encodings = vgn.generateCharts(fields, config,
        {
          dataUrl: "data/birdstrikes.json",
          viewport: [460, 460]
        }, true
      ).map(function (e) { //add score
          var score = visrank.encodingScore(e);
          e.score = score.score;
          e.scoreFeatures = score.features;
          return e;
        });

      var diff = vgn.getDistanceTable(encodings),
        clusters = vgn.cluster(encodings, 2.5)
          .map(function (cluster) {
            return cluster.sort(function (i, j) {
              return encodings[j].score - encodings[i].score;
            });
          })
          .sort(function (c1, c2) {
            return encodings[c2[0]].score - encodings[c1[0]].score;
          });

      //console.log("clusters", clusters);

      return {
        fields: fields,
        encodings: encodings,
        diff: diff,
        clusters: clusters
      };

    })
    return chartsByFieldset;
  }

  function renderMain(selectedColIndices){
    if(selectedColIndices.length === 0) return;

    var selectedCols = selectedColIndices.map(function(i){ return schema[i];}),
      selectedColNames = _.pluck(selectedCols, 'field_name'),
      selectedColTypes = _.pluck(selectedCols, 'data_type');

    // ----- Generate Charts -----
    //TODO(kanitw): change schema format to match
    var fields = selectedCols.map(function(col){
      if(col.data_type == "count"){
        return {aggr: "count", type:"Q"};
      }
      var type = getVLType(col.data_type), f;
      switch(type){

        case "Q":
          f = {name: col.key, type: "Q", _aggr:"*"}
          return f;
        case "O":
        default:
          return {name: col.key, type:"O"};
      }
    });

    console.log('fields', JSON.stringify(fields));

    var chartsByFieldSet = getChartsByFieldSet(fields);

    d3.select("#aggr").selectAll("*").remove();
    d3.select("#vis").selectAll("*").remove();
    d3.select("#selected-fields").selectAll("*").remove();

    var aggrTable = d3.select("#aggr").selectAll("div.fieldset");

    var enter = aggrTable.data(chartsByFieldSet).enter()
      .append("div").attr("class", "fieldset");

    // data fields
    enter.append("div").attr("class", "datafields")
      .selectAll("div.datafield").data(function(d){return d.fields;})
      .enter().append("div").attr("class", "datafield")
      .html(fieldDetailHtml);

    // top vis
    enter.append("div").attr("class","topvis")
      .each(renderTopVis);

    enter.append("div").attr("class", "select")
      .append("a").attr("href","#").text("expand")
        .on('click', function(d){
          renderEncodingVariations(d)
        });

    // console.log("chartsByFieldset", chartsByFieldset);
    // chartsByFieldset.forEach(renderCharts);
  }

  var topVisId = 0; //HACK

  function renderTopVis(charts){
    var container = d3.select(this),
      clusters = charts.clusters,
      encodings = charts.encodings;

    if(clusters.length == 0 || clusters[0].length===0) return;

    var id = "topvis-" + (topVisId++);

    var topIdx = clusters[0][0],
      encoding = vl.Encoding.parseJSON(encodings[topIdx]),
      stats = vl.getStats(data),
      spec = vl.toVegaSpec(encoding, stats);

    console.log(JSON.stringify(spec, null, "  "));

    appendVis(container, encoding, spec, id);
  }

  function appendVis(container, encoding, spec, id){
    container.append("div").attr("id", id)
      .style({
        "height": Math.min(+spec.height + HEIGHT_OFFSET, MAX_HEIGHT) + "px",
        "max-width": MAX_WIDTH+"px",
        "overflow": "scroll"
      });

    if (spec){
      vg.parse.spec(spec, function (vgChart) {
        var vis = vgChart({el: '#' + id});
        vis.update();
        vis.on("mouseover", function(event, item) {
          console.log(item);
        });
      });
    }

    container.append("input").attr({"readonly":1, value: encoding.toShorthand(), class:"shorthand"})
      .style("font-size", "12px");
  }

  function renderEncodingVariations(charts, groupId) {
    var encodings = charts.encodings,
      diff = charts.diff,
      clusters = charts.clusters;

    var dataFields = d3.select("#selected-fields"),
      content = d3.select("#vis");

    content.selectAll("*").remove();
    dataFields.selectAll("*").remove();

    dataFields.selectAll("div.datafield").data(charts.fields)
      .enter().append("div").attr("class", "datafield")
      .html(fieldDetailHtml);

    var visIdCounter=0;

    if(CONFIG.showTable){
      renderDistanceTable(content, diff);
    }

    clusters.forEach(function (clusterIndices) {
      var cluster = clusterIndices.map(function (i) {
        var e = encodings[i],
          encoding = vl.Encoding.parseJSON(e),
          spec = vl.toVegaSpec(encoding, data);
        return {
          encodingJson: e,
          encoding: encoding,
          spec: spec,
          i: i
        };
      });

      var clusterHeight = cluster.reduce(function (h, c) {
        var nh = Math.min(+c.spec.height + HEIGHT_OFFSET, MAX_HEIGHT)+120;
        return nh > h ? nh : h;
      }, 0)

      var chartGroupDiv = content.append("div")
        .attr("id", "group")
        .attr("class", "row")
        .style({
          "background-color": "#fcfcfc",
          "overflow-x": "scroll",
          "overflow-y": "hidden",
          "margin-bottom": "20px",
          "white-space": "nowrap",
          "height": clusterHeight + "px"
        });

      cluster.forEach(function (o, i) {
        if(CONFIG.showOnlyClusterTop && i>0) return;
        // console.log('chart', chart, chart.toShorthand());
        var encodingJson = o.encodingJson,
          i = o.i,
          id = 'vis-' + groupId + "-" + (visIdCounter++),
          encoding = o.encoding,
          spec = o.spec;

        var chartDiv = chartGroupDiv.append("div")
          .style({
            "display": "inline-block",
            "margin-right": "10px",
            "vertical-align": "top"
          })
        var detail = chartDiv.append("div").text("id:"+i+", score:"+encodingJson.score).append("div");
        encodingDetails(encoding, detail);

        appendVis(chartDiv, encoding, spec, id);
      });
    })
  }

  function renderDistanceTable(content, diff) {
    var table = content.append("table");
    var headerRow = table.append("tr").attr("class", "header-row");
    headerRow.append("th");
    headerRow.selectAll("th.item-col").data(diff)
      .enter().append("th").attr("class", "item-col")
      .append("b").text(function (d, i) {
        return "" + i;
      });

    var rows = table.selectAll("tr.item-row")
      .data(diff)
      .enter().append("tr").attr("class", "item-row");

    rows.append("td").append("b").text(function (d, i) {
      return i;
    });
    rows.selectAll("td.item-cell")
      .data(_.identity)
      .enter().append("td").attr("class", "item-cell")
      .style("text-align", "center")
      .style("border", "1px solid #ddd")
      .text(function (d) {
        return d ? d3.format('.2')(d) : "-";
      });
  }

  init();
}));<commit_msg>Fix show stopping bug<commit_after>// Define module using Universal Module Definition pattern
// https://github.com/umdjs/umd/blob/master/returnExports.js

(function (root, factory) {
  if (typeof define === 'function' && define.amd) {
    // AMD. Register as an anonymous module.
    define(['d3', 'vega', 'vegalite', 'lodash', 'visgen', 'visrank'],factory);
  } else if (typeof exports === 'object') {
    // Node. Does not work with strict CommonJS, but
    // only CommonJS-like environments that support module.exports,
    // like Node.
    module.exports = factory(
      require('d3'),
      require('vega'),
      require('vegalite'),
      require('lodash'),
      require('visgen'),
      require('visrank')
    );
  } else {
    // Browser globals (root is window)
    factory(root.d3, root.vg, root.vl, root._, root.vgn, root.visrank);
  }
}(this, function(d3, vg, vl, _, vgn, visrank){
  var schema, col_indices;

  var HEIGHT_OFFSET = 60, MAX_HEIGHT = 500, MAX_WIDTH = 500;

  var CONFIG = {
    showTable: false,

    genAggr: true,
    genBin: true,
    genTypeCasting: true,

    omitTranpose: true,
    omitDotPlotWithExtraEncoding: true,
    omitAggrWithAllDimsOnFacets: true
  }

  var keys = vg.keys;

  function getVLType(data_type){
    // return vegalite's data type
    var typeMap = {
      "categorical": "O",
      "geographic": "G",
      "quantitative": "Q",
      "datetime": "T",
      "count": "Q"
    };
    return typeMap[data_type];
  }

  function init(){
    // d3.select("#toggle-presets").on("click", function(){
    //   var hide = d3.select("#presets").classed("hide")
    //   d3.select("#presets").classed("hide", !hide);
    // });

    d3.select("#toggle-config").on("click", function(){
      var hide = d3.select("#config").classed("hide")
      d3.select("#config").classed("hide", !hide);
    });

    var configs = d3.select("#config").selectAll("div.cfg")
      .data(vl.keys(CONFIG))
      .enter().append("div").attr("class", "cfg")
        .append("label");

    configs.append("input").attr("type","checkbox").attr("class","cfg-check")
      .attr("checked", function(d){ return CONFIG[d];})
      .on("change", updateSelectedFields);

    configs.append("span").attr("class","label config").text(function(d){return d;});

    loadSchema();
  }

  function getConfig(){
    var config = {};
    d3.select("#config").selectAll("div.cfg input.cfg-check")
      .each(function(d){
        config[d] = d3.select(this).node().checked;
      });

    console.log("config", config);
    return config;
  }

  // ----- load schema -----
  function loadSchema(){
    //TODO: use amd-plugin to load json, csv
    d3.json("data/birdstrikes/birdstrikes-schema.json", function(_schema) {
      //TODO: remove this line after updating csv.
      schema = _(_schema).filter(function(d){ return !d.disabled;})
        .sortBy('field_name')
        .sortBy(function(col){
          return getVLType(col.data_type) !== "Q" ? 0 :
            col.data_type === "count" ? 2 : 1 ;
        })
        .map(function(col, i){
          col.key = col['field_name'].replace(/(: )/g, "__").replace(/[\/ ]/g,"_").replace(/[()]/g, "");
          col.index = i; //add index
          return col;
        })
        .value();

      col_indices = _.reduce(schema, function(result, col, i){ result[col] = i; return result;}, {});

      console.log('schema keys', _.pluck(schema,'key').sort());
      console.log('data_types', _(schema).pluck('data_type').uniq().value());
      loadData();
    });
  }

  function updateSelectedFields(){
    var selectedColIndices = [];

    d3.selectAll("#datacols input.datacol").each(function(d, i){
      var selected = d3.select(this).node().checked;
      if(selected){
        selectedColIndices.push(d.index);
      }
    });

    renderMain(selectedColIndices);
  }

  function loadData(){
    // TODO: use other lib to load csv as columns?
    // TODO: regenerate csv with all columns
    d3.json("data/birdstrikes.json", function(data) {
      self.data = data;
      console.log("keys", vg.keys(data[0]));
      renderColumns();
    });
  }

  function renderColumns(){
    var datacols = d3.select("#datacols").selectAll("div")
      .data(schema).enter().append("div").append("label");

    datacols.append("input").attr("type","checkbox").attr("class","datacol")
      .on("change", updateSelectedFields);

    datacols.append("span").attr("class","type").text(function(d){
      return "["+getVLType(d.data_type)+"] ";
    });

    datacols.append("span").attr("class","name").html(function(d){
      return d.field_name;
    });

    // -----  Assume User Selection here -----

    // 0:O "Aircraft: Airline/Operator"
    // 1:O "Aircraft: Make/Model"
    // 2:O "Airport: Name"
    // 3:Q "Cost: Other"
    // 4:Q "Cost: Repair"
    // 5:Q "Cost: Total $"
    // 6:O "Effect: Amount of damage"
    // 7:T "Flight Date"
    // 8:# "Number of Strikes"
    // 9:G "Origin State"
    // 10:Q "Speed (IAS) in knots"
    // 11:O "When: Phase of flight"
    // 12:O "When: Time of day"
    // 13:O "Wildlife: Size"
    // 14:O "Wildlife: Species"

    // var colIndicesSet = [
    //   [6,5,4], //CxQxQ -- good except some bar + size
    //   [6,11,5], //CxCxQ
    //   [6,8], //Cx#
    //   [2,3], //C(Big)xQ
    //   [6, 10], //CxQ
    //   [6,8,5], //Cx#xG
    //   [10], //Q
    //   // [4,5], //QxQ
    //   // [7,8], //Dx#
    //   // [11,12,13], //OxOxO //FIXME
    //   //// [6,5,10] //CxQxQ //TODO: speed might be problematic
    // ];

    // var control = d3.select("#control");

    // var dsel = control.append("select")
    //   .attr("class", "data")
    //   .style("width", "300px")
    //   .on("change", function(){
    //     var index = this.options[this.selectedIndex].value;
    //     render(colIndicesSet[index])
    //   })
    //   .selectAll("option").data(colIndicesSet)
    //   .enter().append("option")
    //     .attr("value", function(d, i){ return i;})
    //     .attr("selected", function(d,i){ return i==0? true : undefined;})
    //     .text(function(d, i){ return getTitle(d);});

    // render(colIndicesSet[0])
  }

  function fieldDetailHtml(v){
    return "" +
      "" +
      (v.aggr ? v.aggr : "") +
      (v.bin ? " bin " : "") +
      "" +
      "" +
      (v.name || "") +
      "" +
      " ("+ v.type + ")";
  }

  function encodingDetails(enc, div){
    div.append("div").html("marktype: "+enc.marktype()+"");
    enc.forEach(function(k, v){
      div.append("div").html(k+": "+fieldDetailHtml(v, vl.dataTypeNames[v.type]))
    });
  }

  function getTitle(colIndices){
    var cols = colIndices.map(function(i){ return schema[i];});

    return cols.map(function(col){
      return col['field_name'] + " [" + col['data_type'][0] +"]";
    }).join(",");
  }

  function getChartsByFieldSet(fields) {
    var config = getConfig();
    var aggr = vgn.genAggregate([], fields, config);
    var chartsByFieldset = aggr.map(function (fields) {
      var encodings = vgn.generateCharts(fields, config,
        {
          dataUrl: "data/birdstrikes.json",
          viewport: [460, 460]
        }, true
      ).map(function (e) { //add score
          var score = visrank.encodingScore(e);
          e.score = score.score;
          e.scoreFeatures = score.features;
          return e;
        });

      var diff = vgn.getDistanceTable(encodings),
        clusters = vgn.cluster(encodings, 2.5)
          .map(function (cluster) {
            return cluster.sort(function (i, j) {
              return encodings[j].score - encodings[i].score;
            });
          })
          .sort(function (c1, c2) {
            return encodings[c2[0]].score - encodings[c1[0]].score;
          });

      //console.log("clusters", clusters);

      return {
        fields: fields,
        encodings: encodings,
        diff: diff,
        clusters: clusters
      };

    })
    return chartsByFieldset;
  }

  function renderMain(selectedColIndices){
    if(selectedColIndices.length === 0) return;

    var selectedCols = selectedColIndices.map(function(i){ return schema[i];}),
      selectedColNames = _.pluck(selectedCols, 'field_name'),
      selectedColTypes = _.pluck(selectedCols, 'data_type');

    // ----- Generate Charts -----
    //TODO(kanitw): change schema format to match
    var fields = selectedCols.map(function(col){
      if(col.data_type == "count"){
        return {aggr: "count", type:"Q"};
      }
      var type = getVLType(col.data_type), f;
      switch(type){

        case "Q":
          f = {name: col.key, type: "Q", _aggr:"*"}
          return f;
        case "O":
        default:
          return {name: col.key, type:"O"};
      }
    });

    console.log('fields', JSON.stringify(fields));

    var chartsByFieldSet = getChartsByFieldSet(fields);

    d3.select("#aggr").selectAll("*").remove();
    d3.select("#vis").selectAll("*").remove();
    d3.select("#selected-fields").selectAll("*").remove();

    var aggrTable = d3.select("#aggr").selectAll("div.fieldset");

    var enter = aggrTable.data(chartsByFieldSet).enter()
      .append("div").attr("class", "fieldset");

    // data fields
    enter.append("div").attr("class", "datafields")
      .selectAll("div.datafield").data(function(d){return d.fields;})
      .enter().append("div").attr("class", "datafield")
      .html(fieldDetailHtml);

    // top vis
    enter.append("div").attr("class","topvis")
      .each(renderTopVis);

    enter.append("div").attr("class", "select")
      .append("a").attr("href","#").text("expand")
        .on('click', function(d){
          renderEncodingVariations(d)
        });

    // console.log("chartsByFieldset", chartsByFieldset);
    // chartsByFieldset.forEach(renderCharts);
  }

  var topVisId = 0; //HACK

  function renderTopVis(charts){
    var container = d3.select(this),
      clusters = charts.clusters,
      encodings = charts.encodings;

    if(clusters.length == 0 || clusters[0].length===0) return;

    var id = "topvis-" + (topVisId++);

    var topIdx = clusters[0][0],
      encoding = vl.Encoding.parseJSON(encodings[topIdx]),
      stats = vl.getStats(data),
      spec = vl.toVegaSpec(encoding, stats);

    console.log(JSON.stringify(spec, null, "  "));

    appendVis(container, encoding, spec, id);
  }

  function appendVis(container, encoding, spec, id){
    container.append("div").attr("id", id)
      .style({
        "height": Math.min(+spec.height + HEIGHT_OFFSET, MAX_HEIGHT) + "px",
        "max-width": MAX_WIDTH+"px",
        "overflow": "scroll"
      });

    if (spec){
      vg.parse.spec(spec, function (vgChart) {
        var vis = vgChart({el: '#' + id});
        vis.update();
        vis.on("mouseover", function(event, item) {
          console.log(item);
        });
      });
    }

    container.append("input").attr({"readonly":1, value: encoding.toShorthand(), class:"shorthand"})
      .style("font-size", "12px");
  }

  function renderEncodingVariations(charts, groupId) {
    var encodings = charts.encodings,
      diff = charts.diff,
      clusters = charts.clusters;

    var dataFields = d3.select("#selected-fields"),
      content = d3.select("#vis");

    content.selectAll("*").remove();
    dataFields.selectAll("*").remove();

    dataFields.selectAll("div.datafield").data(charts.fields)
      .enter().append("div").attr("class", "datafield")
      .html(fieldDetailHtml);

    var visIdCounter=0;

    if(CONFIG.showTable){
      renderDistanceTable(content, diff);
    }

    clusters.forEach(function (clusterIndices) {
      var cluster = clusterIndices.map(function (i) {
        var e = encodings[i],
          encoding = vl.Encoding.parseJSON(e),
          stats = vl.getStats(data),
          spec = vl.toVegaSpec(encoding, stats);
        return {
          encodingJson: e,
          encoding: encoding,
          spec: spec,
          i: i
        };
      });

      var clusterHeight = cluster.reduce(function (h, c) {
        var nh = Math.min(+c.spec.height + HEIGHT_OFFSET, MAX_HEIGHT)+120;
        return nh > h ? nh : h;
      }, 0)

      var chartGroupDiv = content.append("div")
        .attr("id", "group")
        .attr("class", "row")
        .style({
          "background-color": "#fcfcfc",
          "overflow-x": "scroll",
          "overflow-y": "hidden",
          "margin-bottom": "20px",
          "white-space": "nowrap",
          "height": clusterHeight + "px"
        });

      cluster.forEach(function (o, i) {
        if(CONFIG.showOnlyClusterTop && i>0) return;
        // console.log('chart', chart, chart.toShorthand());
        var encodingJson = o.encodingJson,
          i = o.i,
          id = 'vis-' + groupId + "-" + (visIdCounter++),
          encoding = o.encoding,
          spec = o.spec;

        var chartDiv = chartGroupDiv.append("div")
          .style({
            "display": "inline-block",
            "margin-right": "10px",
            "vertical-align": "top"
          })
        var detail = chartDiv.append("div").text("id:"+i+", score:"+encodingJson.score).append("div");
        encodingDetails(encoding, detail);

        appendVis(chartDiv, encoding, spec, id);
      });
    })
  }

  function renderDistanceTable(content, diff) {
    var table = content.append("table");
    var headerRow = table.append("tr").attr("class", "header-row");
    headerRow.append("th");
    headerRow.selectAll("th.item-col").data(diff)
      .enter().append("th").attr("class", "item-col")
      .append("b").text(function (d, i) {
        return "" + i;
      });

    var rows = table.selectAll("tr.item-row")
      .data(diff)
      .enter().append("tr").attr("class", "item-row");

    rows.append("td").append("b").text(function (d, i) {
      return i;
    });
    rows.selectAll("td.item-cell")
      .data(_.identity)
      .enter().append("td").attr("class", "item-cell")
      .style("text-align", "center")
      .style("border", "1px solid #ddd")
      .text(function (d) {
        return d ? d3.format('.2')(d) : "-";
      });
  }

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


<commit_before>// https://secure.tibia.com/community/?subtopic=characters&name=Illja+Mythus
// https://secure.tibia.com/community/?subtopic=characters&name=Himmelh%FCpferin

'use strict';

const elCharacters = document.getElementById('characters');

// Enhance the character info page.
if (elCharacters) {

	let currentTable;
	function $table(header, callback) {
		const tables = document.querySelectorAll('table');
		let result;
		each(tables, function(table) {
			if (table.querySelector('td').textContent == header) {
				result = table;
				return result;
			}
		});
		if (result) {
			currentTable = result;
			callback(currentTable);
		}
	}

	function $cell(header, callback) {
		const cells = currentTable.querySelectorAll('td');
		let nextCell;
		let text;
		each(cells, function(cell, index) {
			if (cell.textContent == (header + ':')) {
				nextCell = cells[++index];
				text = nextCell.textContent;
				return false; // break
			}
		});
		if (nextCell && callback) {
			const result = callback(nextCell, text);
			if (result != null) {
				nextCell.innerHTML = result;
			}
		}
		// This is a quick hack to make sure an `HTMLElement` is always returned.
		return nextCell || new Option;
	}

	function fetchOnlineCharacters(url) {
		return new Promise(function(resolve, reject) {
			const xhr = new XMLHttpRequest();
			xhr.open('get', url);
			xhr.timeout = XHR_TIMEOUT;
			xhr.onload = function() {
				if (this.status == 200) {
					resolve(this.responseText);
				} else {
					reject();
				}
			};
			xhr.onerror = function() {
				reject();
			};
			xhr.send();
		});
	}

	// Extract character names, levels, and vocations from HTML soup of the form:
	// https://secure.tibia.com/community/?subtopic=worlds&order=level_desc&world=Xantera
	function parseOnlineCharacters(html) {
		const regex = /([^<]+)<\/a><\/td>([0-9]+)<\/td>([^<]+)<\/td><\/tr>/g;
		const map = {};
		let match;
		while ((match = regex.exec(html))) {
			const name = decodeHTML(match[1]);
			const level = Number(match[2]);
			// Track vocation too, in case it changed since the character logged in.
			const vocation = decodeHTML(match[3]);
			map[name] = {
				'level': level,
				'vocation': vocation
			};
		}
		return map;
	}

	// Store a reference to all the player killers in the death list, for later.
	let killerAnchors;
	$table('Character Deaths', function(table) {
		killerAnchors = table.querySelectorAll('a');
	});

	// Improve the character information table.
	$table('Character Information', function() {

		let charCell;
		let charName;
		let charNameEncoded;
		$cell('Name', function(element, text) {
			// Account for “Foo, will be deleted at Oct 1 2012, 17:00:00 CEST”.
			charCell = element;
			charName = normalizeSpaces(text.match('^[^,]+')[0].trim());
			charNameEncoded = encode(charName);
			charCell.onclick = function(event) {
				const target = event.target;
				if (target.matches('.mths-tibia-character-name')) {
					const selection = window.getSelection();
					const range = new Range();
					range.selectNodeContents(target);
					selection.removeAllRanges();
					selection.addRange(range);
				}
			};
			return strip`${ charName }
				${ ' ' }(
					PvP history,${ ' ' }
					online time,${ ' ' }
					experience history
				)`;
		});
		charCell.querySelector('a').focus();

		// Normalize the URL in the address bar.
		const param = charNameEncoded.replace(/[^\x20-\x7E]/g, function(symbol) {
			return '%' + symbol.charCodeAt().toString(16).toUpperCase();
		});
		const queryString = `?subtopic=characters&name=${ param }`;
		if (!location.search.includes(queryString)) {
			history.replaceState({}, charName, queryString);
		}

		// Store a reference to the vocation cell, for later.
		let vocation;
		let vocationCell;
		$cell('Vocation', function(element, text) {
			vocationCell = element;
			vocation = normalizeSpaces(text);
		});

		// Is the character married?
		$cell('Married to').classList.add('mths-tibia-block-links');

		// Get the character’s world name.
		let world;
		$cell('World', function(element, text) {
			world = text;
			element.classList.add('mths-tibia-block-links');
			return strip`${ text }`;
		});

		// Store a reference to the level cell, for later.
		let level;
		let levelCell;
		$cell('Level', function(element, text) {
			level = Number(text);
			levelCell = element;
		});

		fetchOnlineCharacters(strip`
			/community/?subtopic=worlds&order=level_desc&world=${ encode(world) }
		`).then(parseOnlineCharacters).then(function(map) {
			const entry = map[charName];
			// Update the level if it changed since the character’s last login.
			if (entry) {
				document.querySelector('.mths-tibia-character-name')
					.classList.add('mths-tibia-online');
				const delta = entry.level - level;
				if (delta) {
					levelCell.textContent = entry.level + ' (' + (delta < 0 ? '' : '+') +
						delta + ' since last login)';
					levelCell.classList.add('mths-tibia-online');
				}
				// Update the vocation if it changed since the character’s last login.
				if (vocation != entry.vocation) {
					vocationCell.textContent = entry.vocation;
					vocationCell.classList.add('mths-tibia-online');
				}
			}
			// Highlight online characters in the death list.
			each(killerAnchors, function(anchor) {
				const name = anchor.textContent.replace(/\xA0/g, ' ');
				const entry = map[name];
				if (entry) {
					anchor.classList.add('mths-tibia-online');
				}
			});
		});

		// Get the former world name (if any).
		$cell('Former World', function(element, text) {
			element.classList.add('mths-tibia-block-links');
			return strip`${ text }`;
		});

		// Link to the house detail page.
		$cell('House', function(element, text) {
			const city = text.match(/\(([^\)]+)\)\x20is/)[1];
			const houseName = text.match(/^(.+)\x20\([^\)]+\)\x20is/)[1];
			const houseID = TIBIA_BUILDINGS.houses[city][houseName];
			element.classList.add('mths-tibia-block-links');
			return strip`${ text }`;
		});

		// Append `onlyshowonline` query string parameter to the guild URL.
		// This one cell contains U+00A0 instead of a regular U+0020 space for some
		// reason.
		$cell('Guild\xA0membership', function(element, text) {
			const anchor = element.querySelector('a');
			anchor.protocol = 'https://';
			anchor.host = 'secure.tibia.com';
			anchor.search = anchor.search.replace(
				'&page=view',
				`&page=view&world=${ world }`
			) + '&onlyshowonline=0';
		});
	});

	// Handle other characters on the account.
	$table('Characters', function(table) {
		const cells = table.querySelectorAll('td[width]:first-child');
		each(cells, function(cell) {
			const text = cell.textContent;
			const charName = text.match(/^\d+\.(?:\xA0|\x20)(.*)/)[1];
			cell.classList.add('mths-tibia-block-links');
			// `<nobr>`… I know! But that’s what they’re using:
			cell.innerHTML = strip`<nobr>${ text }</nobr>`;
		});
	});

	// Make the character search form perform a clean GET.
	each(
		document.querySelectorAll(
			'form[action="http://www.tibia.com/community/?subtopic=characters"]'
		),
		function(form) {
			form.method = 'get';
			const button = form.querySelector('input[name="Submit"]');
			if (button) {
				button.type = 'submit';
				button.removeAttribute('name');
			}
		}
	);

}
<commit_msg>Update code as per recent site update<commit_after>// https://secure.tibia.com/community/?subtopic=characters&name=Illja+Mythus
// https://secure.tibia.com/community/?subtopic=characters&name=Himmelh%FCpferin

'use strict';

const elCharacters = document.getElementById('characters');

// Enhance the character info page.
if (elCharacters) {

	let currentTable;
	function $table(header, callback) {
		const tables = document.querySelectorAll('table');
		let result;
		each(tables, function(table) {
			if (table.querySelector('td').textContent == header) {
				result = table;
				return result;
			}
		});
		if (result) {
			currentTable = result;
			callback(currentTable);
		}
	}

	function $cell(header, callback) {
		const cells = currentTable.querySelectorAll('td');
		let nextCell;
		let text;
		each(cells, function(cell, index) {
			if (cell.textContent == (header + ':')) {
				nextCell = cells[++index];
				text = nextCell.textContent;
				return false; // break
			}
		});
		if (nextCell && callback) {
			const result = callback(nextCell, text);
			if (result != null) {
				nextCell.innerHTML = result;
			}
		}
		// This is a quick hack to make sure an `HTMLElement` is always returned.
		return nextCell || new Option;
	}

	function fetchOnlineCharacters(url) {
		return new Promise(function(resolve, reject) {
			const xhr = new XMLHttpRequest();
			xhr.open('get', url);
			xhr.timeout = XHR_TIMEOUT;
			xhr.onload = function() {
				if (this.status == 200) {
					resolve(this.responseText);
				} else {
					reject();
				}
			};
			xhr.onerror = function() {
				reject();
			};
			xhr.send();
		});
	}

	// Extract character names, levels, and vocations from HTML soup of the form:
	// https://secure.tibia.com/community/?subtopic=worlds&order=level_desc&world=Xantera
	function parseOnlineCharacters(html) {
		const regex = /([^<]+)<\/a><\/td>([0-9]+)<\/td>([^<]+)<\/td><\/tr>/g;
		const map = {};
		let match;
		while ((match = regex.exec(html))) {
			const name = decodeHTML(match[1]);
			const level = Number(match[2]);
			// Track vocation too, in case it changed since the character logged in.
			const vocation = decodeHTML(match[3]);
			map[name] = {
				'level': level,
				'vocation': vocation
			};
		}
		return map;
	}

	// Store a reference to all the player killers in the death list, for later.
	let killerAnchors;
	$table('Character Deaths', function(table) {
		killerAnchors = table.querySelectorAll('a');
	});

	// Improve the character information table.
	$table('Character Information', function() {

		let charCell;
		let charName;
		let charNameEncoded;
		$cell('Name', function(element, text) {
			// Account for “Foo, will be deleted at Oct 1 2012, 17:00:00 CEST”.
			charCell = element;
			charName = normalizeSpaces(text.match('^[^,]+')[0].trim());
			charNameEncoded = encode(charName);
			charCell.onclick = function(event) {
				const target = event.target;
				if (target.matches('.mths-tibia-character-name')) {
					const selection = window.getSelection();
					const range = new Range();
					range.selectNodeContents(target);
					selection.removeAllRanges();
					selection.addRange(range);
				}
			};
			return strip`${ charName }
				${ ' ' }(
					PvP history,${ ' ' }
					online time,${ ' ' }
					experience history
				)`;
		});
		charCell.querySelector('a').focus();

		// Normalize the URL in the address bar.
		const param = charNameEncoded.replace(/[^\x20-\x7E]/g, function(symbol) {
			return '%' + symbol.charCodeAt().toString(16).toUpperCase();
		});
		const queryString = `?subtopic=characters&name=${ param }`;
		if (!location.search.includes(queryString)) {
			history.replaceState({}, charName, queryString);
		}

		// Store a reference to the vocation cell, for later.
		let vocation;
		let vocationCell;
		$cell('Vocation', function(element, text) {
			vocationCell = element;
			vocation = normalizeSpaces(text);
		});

		// Is the character married?
		$cell('Married to').classList.add('mths-tibia-block-links');

		// Get the character’s world name.
		let world;
		$cell('World', function(element, text) {
			world = text;
			element.classList.add('mths-tibia-block-links');
			return strip`${ text }`;
		});

		// Store a reference to the level cell, for later.
		let level;
		let levelCell;
		$cell('Level', function(element, text) {
			level = Number(text);
			levelCell = element;
		});

		fetchOnlineCharacters(strip`
			/community/?subtopic=worlds&order=level_desc&world=${ encode(world) }
		`).then(parseOnlineCharacters).then(function(map) {
			const entry = map[charName];
			// Update the level if it changed since the character’s last login.
			if (entry) {
				document.querySelector('.mths-tibia-character-name')
					.classList.add('mths-tibia-online');
				const delta = entry.level - level;
				if (delta) {
					levelCell.textContent = entry.level + ' (' + (delta < 0 ? '' : '+') +
						delta + ' since last login)';
					levelCell.classList.add('mths-tibia-online');
				}
				// Update the vocation if it changed since the character’s last login.
				if (vocation != entry.vocation) {
					vocationCell.textContent = entry.vocation;
					vocationCell.classList.add('mths-tibia-online');
				}
			}
			// Highlight online characters in the death list.
			each(killerAnchors, function(anchor) {
				const name = anchor.textContent.replace(/\xA0/g, ' ');
				const entry = map[name];
				if (entry) {
					anchor.classList.add('mths-tibia-online');
				}
			});
		});

		// Get the former world name (if any).
		$cell('Former World', function(element, text) {
			element.classList.add('mths-tibia-block-links');
			return strip`${ text }`;
		});

		// Link to the house detail page.
		$cell('House', function(element, text) {
			const city = text.match(/\(([^\)]+)\)\x20is/)[1];
			const houseName = text.match(/^(.+)\x20\([^\)]+\)\x20is/)[1];
			const houseID = TIBIA_BUILDINGS.houses[city][houseName];
			element.classList.add('mths-tibia-block-links');
			return strip`${ text }`;
		});

		// Append `onlyshowonline` query string parameter to the guild URL.
		// This one cell contains U+00A0 instead of a regular U+0020 space for some
		// reason.
		$cell('Guild\xA0membership', function(element, text) {
			const anchor = element.querySelector('a');
			anchor.protocol = 'https://';
			anchor.host = 'secure.tibia.com';
			anchor.search = anchor.search.replace(
				'&page=view',
				`&page=view&world=${ world }`
			) + '&onlyshowonline=0';
		});
	});

	// Handle other characters on the account.
	$table('Characters', function(table) {
		const cells = table.querySelectorAll('td[width]:first-child');
		each(cells, function(cell) {
			const text = cell.textContent;
			const charName = text.match(/^\d+\.(?:\xA0|\x20)(.*)/)[1];
			cell.classList.add('mths-tibia-block-links');
			// `<nobr>`… I know! But that’s what they’re using:
			cell.innerHTML = strip`<nobr>${ text }</nobr>`;
		});
	});

	// Make the character search form perform a clean GET.
	each(
		document.querySelectorAll(
			'form[action="https://secure.tibia.com/community/?subtopic=characters"]'
		),
		function(form) {
			form.method = 'get';
			const button = form.querySelector('input[name="Submit"]');
			if (button) {
				button.type = 'submit';
				button.removeAttribute('name');
			}
		}
	);

}
<|endoftext|>


<commit_before>class AbstractComponent {
  constructor(props) {
    if (new.target === AbstractComponent) {
      throw new TypeError("Cannot construct AbstractComponent instances directly");
    }
    if (!props.container) {
      throw new ComponentException('Required value are missing');
    }

    this.ctx = props.container.context;
    this.x = props.x || 0;
    this.y = props.y || 0;
    this.color = props.color || 'black';
  }
}

class ObjectComponent extends AbstractComponent {
  constructor(props) {
    super(props);
    if (!props.width || !props.height) {
      throw new ComponentException('Size are required value');
    }

    this.width = props.width;
    this.height = props.height;
    this.halfWidth = this.width * 0.5;
    this.halfHeight = this.height * 0.5;
    this.centerX = this.x + this.halfWidth;
    this.centerY = this.y + this.halfHeight;
    this.sizeY = this.y + this.height;
    this.sizeX = this.x + this.width;
  }

  update() {
    this.ctx.fillStyle = this.color;
    this.ctx.fillRect(this.x, this.y, this.width, this.height);
  }
}

class TextComponent extends AbstractComponent {
  constructor(props) {
    super(props);
    this.text = '';
    if (!props.size) {
      throw new ComponentException('Size are required value');
    }

    this.size = props.size;
  }

  update() {
    this.ctx.font = `${this.size} Consolas`;
    this.ctx.fillStyle = this.color;
    this.ctx.fillText(this.text, this.x, this.y);
  }
}
<commit_msg>testing font<commit_after>class AbstractComponent {
  constructor(props) {
    if (new.target === AbstractComponent) {
      throw new TypeError("Cannot construct AbstractComponent instances directly");
    }
    if (!props.container) {
      throw new ComponentException('Required value are missing');
    }

    this.ctx = props.container.context;
    this.x = props.x || 0;
    this.y = props.y || 0;
    this.color = props.color || 'black';
  }
}

class ObjectComponent extends AbstractComponent {
  constructor(props) {
    super(props);
    if (!props.width || !props.height) {
      throw new ComponentException('Size are required value');
    }

    this.width = props.width;
    this.height = props.height;
    this.halfWidth = this.width * 0.5;
    this.halfHeight = this.height * 0.5;
    this.centerX = this.x + this.halfWidth;
    this.centerY = this.y + this.halfHeight;
    this.sizeY = this.y + this.height;
    this.sizeX = this.x + this.width;
  }

  update() {
    this.ctx.fillStyle = this.color;
    this.ctx.fillRect(this.x, this.y, this.width, this.height);
  }
}

class TextComponent extends AbstractComponent {
  constructor(props) {
    super(props);
    this.text = '';
    if (!props.size) {
      throw new ComponentException('Size are required value');
    }

    this.size = props.size;
  }

  update() {
    this.ctx.font = `${this.size} Arial`;
    this.ctx.fillStyle = this.color;
    this.ctx.fillText(this.text, this.x, this.y);
  }
}
<|endoftext|>


<commit_before>var DEBUG = 0;

// AJAX setup
var AJAX_SETUP = {
	timeout: 9000,
	cache: false, // this little sentence killed a lot of little bugs that was actually one big bug
}

// Loops & intervals
var BACKGROUND_LOOP = 30000; // 30s
var BACKGROUND_LOOP_OFFLINE = 3000; // 3s, respond quickly when we get back online
var PAGE_LOOP = 10000; // 10s

// Update stuff at every X intervals
var UPDATE_OFFICE_INTERVAL = 1; // recommended: 1
var UPDATE_SERVANT_INTERVAL = 20; // recommended: 20
var UPDATE_MEETINGS_INTERVAL = 20; // recommended: 20
var UPDATE_COFFEE_INTERVAL = 1; // recommended: 1
var UPDATE_HOURS_INTERVAL = 60; // recommended: 60
var UPDATE_CANTINAS_INTERVAL = 60; // recommended: 60
var UPDATE_BUS_INTERVAL = 2; // recommended: 1
var UPDATE_NEWS_INTERVAL = 20; // recommended: 20

// Meme detection
var urlExists = function(url) {
	try {
	    var http = new XMLHttpRequest();
	    http.open('HEAD', url, false);
	    http.send();
	    return http.status!=404;
	}
	catch (e) {
		return false;
	}
	finally {
		// do nothing
	}
}
var MEME_AMOUNT = 0;
var __counter__ = 1;
while (urlExists('meme/'+__counter__+'.jpg')) {
	MEME_AMOUNT++;
	__counter__++;
}

// OS detection
var OPERATING_SYSTEM = "Unknown";
if (navigator.appVersion.indexOf("Win")!==-1) OPERATING_SYSTEM="Windows";
else if (navigator.appVersion.indexOf("Linux")!==-1) OPERATING_SYSTEM="Linux";
else if (navigator.appVersion.indexOf("X11")!==-1) OPERATING_SYSTEM="UNIX";
else if (navigator.appVersion.indexOf("Mac")!==-1) {
	OPERATING_SYSTEM = "Old Mac";
	if (navigator.appVersion.indexOf("10_7")!==-1||navigator.appVersion.indexOf("10_8")!==-1) {
		OPERATING_SYSTEM = "Mac";
	}
}
else {
	console.log('WARNING: Potentially unsupported operating system');
}

// Browser detection
var BROWSER = "Unknown";
if (navigator.userAgent.indexOf('Chrome') != -1 && navigator.userAgent.indexOf('OPR') == -1)
	BROWSER = "Chrome";
else if (navigator.userAgent.indexOf('OPR') != -1)
	BROWSER = "Opera";
else
	console.log('WARNING: Potentially unsupported browser');

// Production detection
if (BROWSER == 'Chrome')
	if (typeof chrome.i18n != 'undefined')
		if (chrome.i18n.getMessage('@@extension_id') === 'hfgffimlnajpbenfpaofmmffcdmgkllf')
			DEBUG = 0;
else if (BROWSER == 'Opera')
	if (typeof chrome.i18n != 'undefined')
		if (chrome.i18n.getMessage('@@extension_id') === 'npnpbddfcaibgnegafofkmffmbmflelj')
			DEBUG = 0;
<commit_msg>constants: debug on<commit_after>var DEBUG = 1;

// AJAX setup
var AJAX_SETUP = {
	timeout: 9000,
	cache: false, // this little sentence killed a lot of little bugs that was actually one big bug
}

// Loops & intervals
var BACKGROUND_LOOP = 30000; // 30s
var BACKGROUND_LOOP_OFFLINE = 3000; // 3s, respond quickly when we get back online
var PAGE_LOOP = 10000; // 10s

// Update stuff at every X intervals
var UPDATE_OFFICE_INTERVAL = 1; // recommended: 1
var UPDATE_SERVANT_INTERVAL = 20; // recommended: 20
var UPDATE_MEETINGS_INTERVAL = 20; // recommended: 20
var UPDATE_COFFEE_INTERVAL = 1; // recommended: 1
var UPDATE_HOURS_INTERVAL = 60; // recommended: 60
var UPDATE_CANTINAS_INTERVAL = 60; // recommended: 60
var UPDATE_BUS_INTERVAL = 2; // recommended: 1
var UPDATE_NEWS_INTERVAL = 20; // recommended: 20

// Meme detection
var urlExists = function(url) {
	try {
	    var http = new XMLHttpRequest();
	    http.open('HEAD', url, false);
	    http.send();
	    return http.status!=404;
	}
	catch (e) {
		return false;
	}
	finally {
		// do nothing
	}
}
var MEME_AMOUNT = 0;
var __counter__ = 1;
while (urlExists('meme/'+__counter__+'.jpg')) {
	MEME_AMOUNT++;
	__counter__++;
}

// OS detection
var OPERATING_SYSTEM = "Unknown";
if (navigator.appVersion.indexOf("Win")!==-1) OPERATING_SYSTEM="Windows";
else if (navigator.appVersion.indexOf("Linux")!==-1) OPERATING_SYSTEM="Linux";
else if (navigator.appVersion.indexOf("X11")!==-1) OPERATING_SYSTEM="UNIX";
else if (navigator.appVersion.indexOf("Mac")!==-1) {
	OPERATING_SYSTEM = "Old Mac";
	if (navigator.appVersion.indexOf("10_7")!==-1||navigator.appVersion.indexOf("10_8")!==-1) {
		OPERATING_SYSTEM = "Mac";
	}
}
else {
	console.log('WARNING: Potentially unsupported operating system');
}

// Browser detection
var BROWSER = "Unknown";
if (navigator.userAgent.indexOf('Chrome') != -1 && navigator.userAgent.indexOf('OPR') == -1)
	BROWSER = "Chrome";
else if (navigator.userAgent.indexOf('OPR') != -1)
	BROWSER = "Opera";
else
	console.log('WARNING: Potentially unsupported browser');

// Production detection
if (BROWSER == 'Chrome')
	if (typeof chrome.i18n != 'undefined')
		if (chrome.i18n.getMessage('@@extension_id') === 'hfgffimlnajpbenfpaofmmffcdmgkllf')
			DEBUG = 0;
else if (BROWSER == 'Opera')
	if (typeof chrome.i18n != 'undefined')
		if (chrome.i18n.getMessage('@@extension_id') === 'npnpbddfcaibgnegafofkmffmbmflelj')
			DEBUG = 0;
<|endoftext|>


<commit_before>"use strict";

var DEBUG = 0;

// Production detection
if (Browser.inProduction()) {
	DEBUG = 0;
}

// Logging setup
console.lolg = function() {
	// Console logging that only happens in debug mode
	// The name "lolg" is a tribute to Lorents Odin Lervik Gravås
	if (DEBUG) {
		console.log.apply(console, arguments);
	}
};

// Loops & intervals
var BACKGROUND_LOOP = 60000; // 60s
var BACKGROUND_LOOP_DEBUG = 5000; // 5s, respond fairly quickly for us developers
var PAGE_LOOP = 10000; // 10s
var PAGE_LOOP_DEBUG = 5000; // 5s
var ONLINE_MESSAGE = '\nNow online, run mainloop\n';
var OFFLINE_MESSAGE = '\nNow offline, stop execution\n';

// Update stuff at every X intervals
var UPDATE_OFFICE_INTERVAL = 1; // recommended: 1
var UPDATE_SERVANT_INTERVAL = 20; // recommended: 20
var UPDATE_MEETINGS_INTERVAL = 20; // recommended: 20
var UPDATE_COFFEE_INTERVAL = 1; // recommended: 1
var UPDATE_HOURS_INTERVAL = 60; // recommended: 60
var UPDATE_CANTINAS_INTERVAL = 60; // recommended: 60
var UPDATE_BUS_INTERVAL = 2; // recommended: 1
var UPDATE_NEWS_INTERVAL = 20; // recommended: 20

// Meme detection
var urlExists = function(url) {
	try {
	    var http = new XMLHttpRequest();
	    http.open('HEAD', url, false);
	    http.send();
	    return http.status!=404;
	}
	catch (e) {
		return false;
	}
}
var MEME_AMOUNT = 0;
var __counter__ = 1;
while (urlExists('meme/'+__counter__+'.png')) {
	MEME_AMOUNT++;
	__counter__++;
}
<commit_msg>constants: enabled debug<commit_after>"use strict";

var DEBUG = 1;

// Production detection
if (Browser.inProduction()) {
	DEBUG = 0;
}

// Logging setup
console.lolg = function() {
	// Console logging that only happens in debug mode
	// The name "lolg" is a tribute to Lorents Odin Lervik Gravås
	if (DEBUG) {
		console.log.apply(console, arguments);
	}
};

// Loops & intervals
var BACKGROUND_LOOP = 60000; // 60s
var BACKGROUND_LOOP_DEBUG = 5000; // 5s, respond fairly quickly for us developers
var PAGE_LOOP = 10000; // 10s
var PAGE_LOOP_DEBUG = 5000; // 5s
var ONLINE_MESSAGE = '\nNow online, run mainloop\n';
var OFFLINE_MESSAGE = '\nNow offline, stop execution\n';

// Update stuff at every X intervals
var UPDATE_OFFICE_INTERVAL = 1; // recommended: 1
var UPDATE_SERVANT_INTERVAL = 20; // recommended: 20
var UPDATE_MEETINGS_INTERVAL = 20; // recommended: 20
var UPDATE_COFFEE_INTERVAL = 1; // recommended: 1
var UPDATE_HOURS_INTERVAL = 60; // recommended: 60
var UPDATE_CANTINAS_INTERVAL = 60; // recommended: 60
var UPDATE_BUS_INTERVAL = 2; // recommended: 1
var UPDATE_NEWS_INTERVAL = 20; // recommended: 20

// Meme detection
var urlExists = function(url) {
	try {
	    var http = new XMLHttpRequest();
	    http.open('HEAD', url, false);
	    http.send();
	    return http.status!=404;
	}
	catch (e) {
		return false;
	}
}
var MEME_AMOUNT = 0;
var __counter__ = 1;
while (urlExists('meme/'+__counter__+'.png')) {
	MEME_AMOUNT++;
	__counter__++;
}
<|endoftext|>


<commit_before>function Node(value, color, level, isRedBlack, svg) {

    this.svg = svg;
    this.circleObject;
    this.textObject;
    this.lineObject;
    this.x;
    this.y;

    this.leftNode = null;
    this.rightNode = null;
    this.alreadyDrawn = false;
    this.level = level;
    this.isRedBlack = isRedBlack;

    if (color == "red") {
        this.backgroundColor = "pink";
    }
    else {
        this.backgroundColor = "lightgray";
    }
    this.borderColor = color;
    this.textColor = this.borderColor;
    this.textValue = value;
}

Node.prototype.rescale = function (x, y, r, parent) {
    if (parent != null) {
        var alpha = Math.atan2(y - parent.y, x - parent.x);
        var coords1 = this.getLineCoords(x, y, alpha, r, false);
        var coords2 = this.getLineCoords(parent.x, parent.y, alpha, r, true);

        d3.select("#line-" + this.textValue)
            .transition()
            .attr("x1", coords1[0])
            .attr("y1", coords1[1])
            .attr("x2", coords2[0])
            .attr("y2", coords2[1])
    }

    d3.select("#circle-" + this.textValue)
        .transition()
        .attr("cx", x)
        .attr("cy", y);

    d3.select("#text-" + this.textValue)
        .transition()
        .attr("x", x - r / 1.8)
        .attr("y", y + r / 2.8);

    this.x = x;
    this.y = y;
}

var tooltips = [];

Node.prototype.draw = function (x, y, r, parent) {

    var val = parseInt(this.textValue);
    tooltips[val] = this.getToolTip(x, y, r);
    if (!this.alreadyDrawn) {

        if (parent != null) {
            var alpha = Math.atan2(y - parent.y, x - parent.x);
            var coords1 = this.getLineCoords(x, y, alpha, r, false);
            var coords2 = this.getLineCoords(parent.x, parent.y, alpha, r, true);

            this.lineObject = this.svg.append("line")
                .attr("id", "line-" + this.textValue)
                .attr("x1", coords1[0])
                .attr("y1", coords1[1])
                .attr("x2", coords2[0])
                .attr("y2", coords2[1])
                .attr("stroke-width", 2)
                .attr("stroke", "black");
        }

        this.circleObject = this.svg.append("circle")
            .attr("id", "circle-" + this.textValue)
            .attr("cx", x)
            .attr("cy", y)
            .attr("fill", this.backgroundColor)
            .attr("stroke", this.borderColor)
            .attr("r", 0)
            .on("mouseover", function () {
                return tooltips[val].style("visibility", "visible");
            })
            .on("mouseout", function () {
                return tooltips[val].style("visibility", "hidden");
            })
            .transition()
            .attr("r", r)
            .transition()
            .attr("stroke-width", r / 20)

        this.textObject = this.svg.append("text")
            .attr("id", "text-" + this.textValue)
            .attr("x", x - r / 1.8)
            .attr("y", y + r / 2.8)
            .attr("font-size", 0)
            .on("mouseover", function () {
                return tooltips[val].style("visibility", "visible");
            })
            .on("mouseout", function () {
                return tooltips[val].style("visibility", "hidden");
            })
            .transition()
            .attr("fill", this.textColor)
            .attr("font-size", r)
            .text(this.textValue);

        this.alreadyDrawn = true;
    }

    this.x = x;
    this.y = y;
};

Node.prototype.getToolTip = function (x, y, r) {

    var name = "circle-tooltip-" + this.textValue;
    if (d3.select(name) != null) {
        d3.select(name).remove();
    }

    var svgRect = document.getElementById("svg-canvas").getBoundingClientRect();

    return d3.select("body")
        .append(name)
        .style("position", "absolute")
        .style("z-index", "100")
        .style("top", svgRect.top + (y - r * 2) + "px")
        .style("left", svgRect.left + (x + r * 2) + "px")
        .style("background-color", "rgba(220, 220, 220, 0.85)")
        .style("border-radius", "8px")
        .style("border", "1px solid black")
        .style("padding", "5px 15px")
        .style("visibility", "hidden")
        .html(this.getInfo());
}

Node.prototype.getLineCoords = function (x, y, alpha, r, isParent) {

    if (isParent) {
        x += Math.cos(alpha) * r;
        y += Math.sin(alpha) * r;
    }
    else {
        x -= Math.cos(alpha) * r;
        y -= Math.sin(alpha) * r;
    }

    return [x, y];
}

Node.prototype.getInfo = function () {

    var info = "Key: " + this.textValue + "
Left child: ";
    if (this.leftNode != null) info += "" + this.leftNode.textValue + "";
    else info += "not present";
    info += "
Right child: ";
    if (this.rightNode != null) info += "" + this.rightNode.textValue + "";
    else info += "not present";
    if (this.isRedBlack) {
        info += "
Color: " + this.borderColor;
    }

    return info;
}<commit_msg>updated tree node info<commit_after>function Node(value, color, level, isRedBlack, svg) {

    this.svg = svg;
    this.circleObject;
    this.textObject;
    this.lineObject;
    this.x;
    this.y;

    this.leftNode = null;
    this.rightNode = null;
    this.alreadyDrawn = false;
    this.level = level;
    this.isRedBlack = isRedBlack;

    if (color == "red") {
        this.backgroundColor = "pink";
    }
    else {
        this.backgroundColor = "lightgray";
    }
    this.borderColor = color;
    this.textColor = this.borderColor;
    this.textValue = value;
}

Node.prototype.rescale = function (x, y, r, parent) {
    if (parent != null) {
        var alpha = Math.atan2(y - parent.y, x - parent.x);
        var coords1 = this.getLineCoords(x, y, alpha, r, false);
        var coords2 = this.getLineCoords(parent.x, parent.y, alpha, r, true);

        d3.select("#line-" + this.textValue)
            .transition()
            .attr("x1", coords1[0])
            .attr("y1", coords1[1])
            .attr("x2", coords2[0])
            .attr("y2", coords2[1])
    }

    d3.select("#circle-" + this.textValue)
        .transition()
        .attr("cx", x)
        .attr("cy", y);

    d3.select("#text-" + this.textValue)
        .transition()
        .attr("x", x - r / 1.8)
        .attr("y", y + r / 2.8);

    this.x = x;
    this.y = y;
}

var tooltips = [];

Node.prototype.draw = function (x, y, r, parent) {

    var val = parseInt(this.textValue);
    tooltips[val] = this.getToolTip(x, y, r);
    if (!this.alreadyDrawn) {

        if (parent != null) {
            var alpha = Math.atan2(y - parent.y, x - parent.x);
            var coords1 = this.getLineCoords(x, y, alpha, r, false);
            var coords2 = this.getLineCoords(parent.x, parent.y, alpha, r, true);

            this.lineObject = this.svg.append("line")
                .attr("id", "line-" + this.textValue)
                .attr("x1", coords1[0])
                .attr("y1", coords1[1])
                .attr("x2", coords2[0])
                .attr("y2", coords2[1])
                .attr("stroke-width", 2)
                .attr("stroke", "black");
        }

        this.circleObject = this.svg.append("circle")
            .attr("id", "circle-" + this.textValue)
            .attr("cx", x)
            .attr("cy", y)
            .attr("fill", this.backgroundColor)
            .attr("stroke", this.borderColor)
            .attr("r", 0)
            .on("mouseover", function () {
                return tooltips[val].style("visibility", "visible");
            })
            .on("mouseout", function () {
                return tooltips[val].style("visibility", "hidden");
            })
            .transition()
            .attr("r", r)
            .transition()
            .attr("stroke-width", r / 20)

        this.textObject = this.svg.append("text")
            .attr("id", "text-" + this.textValue)
            .attr("x", x - r / 1.8)
            .attr("y", y + r / 2.8)
            .attr("font-size", 0)
            .style("cursor", "default")
            .on("mouseover", function () {
                return tooltips[val].style("visibility", "visible");
            })
            .on("mouseout", function () {
                return tooltips[val].style("visibility", "hidden");
            })
            .transition()
            .attr("fill", this.textColor)
            .attr("font-size", r)
            .text(this.textValue);

        this.alreadyDrawn = true;
    }

    this.x = x;
    this.y = y;
};

Node.prototype.getToolTip = function (x, y, r) {

    var name = "circle-tooltip-" + this.textValue;
    if (d3.select(name) != null) {
        d3.select(name).remove();
    }

    var svgRect = document.getElementById("svg-canvas").getBoundingClientRect();

    return d3.select("body")
        .append(name)
        .style("position", "absolute")
        .style("z-index", "100")
        .style("top", svgRect.top + (y - r * 2) + "px")
        .style("left", svgRect.left + (x + r * 2) + "px")
        .style("background-color", "rgba(220, 220, 220, 0.85)")
        .style("border-radius", "8px")
        .style("border", "1px solid black")
        .style("padding", "5px 15px")
        .style("visibility", "hidden")
        .html(this.getInfo());
}

Node.prototype.getLineCoords = function (x, y, alpha, r, isParent) {

    if (isParent) {
        x += Math.cos(alpha) * r;
        y += Math.sin(alpha) * r;
    }
    else {
        x -= Math.cos(alpha) * r;
        y -= Math.sin(alpha) * r;
    }

    return [x, y];
}

Node.prototype.getInfo = function () {

    var info = "";
    if (this.level != undefined && this.level == 0) {
        info += "Root Node";
    }
    else if (this.leftNode == null && this.rightNode == null) {
        info += "Leaf Node";
    }
    info += "Key: " + this.textValue;

    if (this.leftNode != null || this.rightNode != null) {
        info += "
Left child: ";
        if (this.leftNode != null) info += "" + this.leftNode.textValue + "";
        else info += "not present";
        info += "
Right child: ";
        if (this.rightNode != null) info += "" + this.rightNode.textValue + "";
        else info += "not present";
    }
    else {

    }
    if (this.isRedBlack) {
        info += "
Color: " + this.borderColor;
    }

    return info;
}<|endoftext|>


<commit_before>/*global State */

/**
 * Find the shortest path on a CPU using cellular automata (slow!).
 * @param {number} w width
 * @param {number} h height
 * @param {Uint8Array} maze
 * @param {HTMLCanvasElement} [canvas] for drawing progress
 */
function CpuSolver(w, h, maze, canvas) {
    this.w = w;
    this.h = h;
    this.ctx = canvas == null ? null : canvas.getContext('2d');
    this.fore = new Uint32Array(w * h);
    this.done = false;
    this.cancelled = false;
    this.age = 0;
    this.reset(maze);
}

/**
 * Swap the foreground and background buffers.
 * @returns {CpuSolver} this
 */
CpuSolver.prototype.swap = function() {
    var tmp = this.fore;
    this.fore = this.back;
    this.back = tmp;
    return this;
};

/**
 * @param {number} x
 * @param {number} y
 * @returns {number} the state at (x, y) on the foreground buffer
 */
CpuSolver.prototype.get = function(x, y) {
    if (x >= 0 && x < this.w && y >= 0 && y < this.h) {
        return this.fore[y * this.w + x];
    } else {
        return State.WALL;
    }
};

/**
 * Sets the state on the background buffer.
 * @param {number} x
 * @param {number} y
 * @param {number} value
 * @returns {number} value
 */
CpuSolver.prototype.set = function(x, y, value) {
    this.back[y * this.w + x] = value;
    return value;
};

/**
 * Set a new maze to solve, resetting the solver.
 * @param {Uint8Array} maze
 * @returns {CpuSolver} this
 */
CpuSolver.prototype.reset = function(maze) {
    this.back = new Uint8Array(maze);
    this.set(0, 0, State.BEGIN);
    this.set(this.w - 1, this.h - 1, State.END);
    this.swap();
    this.done = false;
    this.cancelled = false;
    this.age = 0;
    return this;
};

/**
 * Take one or more steps towards the solution.
 * @param {number} [n] the number of steps to take
 * @returns {CpuSolver} this
 */
CpuSolver.prototype.step = function(n) {
    n = n || 1;
    var states = [null, null, null, null];
    while (n-- > 0 && !this.done) {
        this.age++;
        var changes = 0;
        for (var y = 0; y < this.h; y++) {
            for (var x = 0; x < this.w; x++) {
                states[0] = this.get(x + 0, y + -1); // N
                states[1] = this.get(x + 1, y +  0); // E
                states[2] = this.get(x + 0, y +  1); // S
                states[3] = this.get(x +-1, y +  0); // W
                var current = this.get(x, y),
                    next = State.next(current, states);
                if (current !== next) changes++;
                this.set(x, y, next);
            }
        }
        this.swap();
        if (changes === 0) this.done = true;
    }
    return this;
};

/**
 * Draw the current solution state to the canvas.
 * @returns {CpuSolver} this
 */
CpuSolver.prototype.draw = function() {
    if (this.ctx == null) return this;
    var w = this.w, h = this.h, ctx = this.ctx,
        sx = Math.floor(ctx.canvas.width / w),
        sy = Math.floor(ctx.canvas.height / h);
    for (var y = 0; y < this.h; y++) {
        for (var x = 0; x < this.w; x++) {
            ctx.fillStyle = State.color(this.get(x, y));
            ctx.fillRect(sx * x, sy * y, sx, sy);
        }
    }
    return this;
};

/**
 * Animate the solution using requestAnimationFrame.
 * @param {Function} [callback]
 */
CpuSolver.prototype.animate = function(callback) {
    var _this = this;
    window.requestAnimationFrame(function() {
        if (!_this.done && !_this.cancelled) {
            _this.step(1).draw();
            _this.animate(callback);
        } else {
            if (!_this.cancelled && callback != null) callback();
            _this.cancelled = false;
        }
    });
    return this;
};

/**
 * Stop animation without calling the callback.
 * @returns {CpuSolver} this
 */
CpuSolver.prototype.cancel = function() {
    this.cancelled = true;
    return this;
};
<commit_msg>Fix docstring.<commit_after>/*global State */

/**
 * Find the shortest path on the CPU using cellular automata (slow!).
 * @param {number} w width
 * @param {number} h height
 * @param {Uint8Array} maze
 * @param {HTMLCanvasElement} [canvas] for drawing progress
 */
function CpuSolver(w, h, maze, canvas) {
    this.w = w;
    this.h = h;
    this.ctx = canvas == null ? null : canvas.getContext('2d');
    this.fore = new Uint32Array(w * h);
    this.done = false;
    this.cancelled = false;
    this.age = 0;
    this.reset(maze);
}

/**
 * Swap the foreground and background buffers.
 * @returns {CpuSolver} this
 */
CpuSolver.prototype.swap = function() {
    var tmp = this.fore;
    this.fore = this.back;
    this.back = tmp;
    return this;
};

/**
 * @param {number} x
 * @param {number} y
 * @returns {number} the state at (x, y) on the foreground buffer
 */
CpuSolver.prototype.get = function(x, y) {
    if (x >= 0 && x < this.w && y >= 0 && y < this.h) {
        return this.fore[y * this.w + x];
    } else {
        return State.WALL;
    }
};

/**
 * Sets the state on the background buffer.
 * @param {number} x
 * @param {number} y
 * @param {number} value
 * @returns {number} value
 */
CpuSolver.prototype.set = function(x, y, value) {
    this.back[y * this.w + x] = value;
    return value;
};

/**
 * Set a new maze to solve, resetting the solver.
 * @param {Uint8Array} maze
 * @returns {CpuSolver} this
 */
CpuSolver.prototype.reset = function(maze) {
    this.back = new Uint8Array(maze);
    this.set(0, 0, State.BEGIN);
    this.set(this.w - 1, this.h - 1, State.END);
    this.swap();
    this.done = false;
    this.cancelled = false;
    this.age = 0;
    return this;
};

/**
 * Take one or more steps towards the solution.
 * @param {number} [n] the number of steps to take
 * @returns {CpuSolver} this
 */
CpuSolver.prototype.step = function(n) {
    n = n || 1;
    var states = [null, null, null, null];
    while (n-- > 0 && !this.done) {
        this.age++;
        var changes = 0;
        for (var y = 0; y < this.h; y++) {
            for (var x = 0; x < this.w; x++) {
                states[0] = this.get(x + 0, y + -1); // N
                states[1] = this.get(x + 1, y +  0); // E
                states[2] = this.get(x + 0, y +  1); // S
                states[3] = this.get(x +-1, y +  0); // W
                var current = this.get(x, y),
                    next = State.next(current, states);
                if (current !== next) changes++;
                this.set(x, y, next);
            }
        }
        this.swap();
        if (changes === 0) this.done = true;
    }
    return this;
};

/**
 * Draw the current solution state to the canvas.
 * @returns {CpuSolver} this
 */
CpuSolver.prototype.draw = function() {
    if (this.ctx == null) return this;
    var w = this.w, h = this.h, ctx = this.ctx,
        sx = Math.floor(ctx.canvas.width / w),
        sy = Math.floor(ctx.canvas.height / h);
    for (var y = 0; y < this.h; y++) {
        for (var x = 0; x < this.w; x++) {
            ctx.fillStyle = State.color(this.get(x, y));
            ctx.fillRect(sx * x, sy * y, sx, sy);
        }
    }
    return this;
};

/**
 * Animate the solution using requestAnimationFrame.
 * @param {Function} [callback]
 */
CpuSolver.prototype.animate = function(callback) {
    var _this = this;
    window.requestAnimationFrame(function() {
        if (!_this.done && !_this.cancelled) {
            _this.step(1).draw();
            _this.animate(callback);
        } else {
            if (!_this.cancelled && callback != null) callback();
            _this.cancelled = false;
        }
    });
    return this;
};

/**
 * Stop animation without calling the callback.
 * @returns {CpuSolver} this
 */
CpuSolver.prototype.cancel = function() {
    this.cancelled = true;
    return this;
};
<|endoftext|>


<commit_before>import { parse } from "url"
import makeFetchHappen from "make-fetch-happen"
import cheerio from "cheerio"
const fetch = makeFetchHappen.defaults({
  cacheManager: ".cache/", // path where cache will be written (and read)
})

const KlassName = process.argv[2]

fetch(
  "https://developers.google.com/maps/documentation/javascript/3.exp/reference"
)
  .then(it => it.text())
  .then(it => cheerio.load(it))
  .then($ => {
    const $content = $(`#${KlassName}`).parent()
    return contentToJS(KlassName, $, $content)
  })
  .then(it => process.stdout.write(JSON.stringify(it)))
  .catch(error => {
    console.error(error)
    process.exit(1)
  })

function contentToJS(KlassName, $, $content) {
  const constructor = $content
    .find(`#${KlassName}`)
    .next()
    .find("code")
    .text()

  const $constructorTable = $content.find(
    `[summary="class ${KlassName} - Constructor"]`
  )
  const [, constructorArgs] = $constructorTable
    .find(`tr > td > code`)
    .text()
    .match(/\S+\((.*)\)/)

  const $methodsTable = $content.find(
    `[summary="class ${KlassName} - Methods"]`
  )
  const methods = $methodsTable
    .find("tbody > tr")
    .map((i, tr) => {
      const $tr = $(tr)
      const [, name, args] = $tr
        .find("td:first-child")
        .text()
        .replace("\n", "")
        .match(/(\S+)\((.*)\)/)

      return {
        name,
        args,
        returns: $tr.find("td:nth-child(2) > div > code").text(),
        returnsDesc: $tr.find("td:nth-child(2) > div.desc").text(),
      }
    })
    .get()

  const $eventsTable = $content.find(`[summary="class ${KlassName} - Events"]`)
  const events = $eventsTable
    .find("tbody > tr")
    .map((i, tr) => {
      const $tr = $(tr)
      const name = $tr.find("td:first-child").text()

      return {
        name,
        args: $tr.find("td:nth-child(2) > div > code").text(),
        returnsDesc: $tr.find("td:nth-child(2) > div.desc").text(),
      }
    })
    .get()

  return {
    constructor: {
      name: constructor,
      args: constructorArgs,
    },
    methods,
    events,
  }
}
<commit_msg>chore(tx): turn `returnsDesc` to markdown<commit_after>import { parse } from "url"
import toMarkdown from "to-markdown"
import makeFetchHappen from "make-fetch-happen"
import cheerio from "cheerio"
const fetch = makeFetchHappen.defaults({
  cacheManager: ".cache/", // path where cache will be written (and read)
})

const KlassName = process.argv[2]

fetch(
  "https://developers.google.com/maps/documentation/javascript/3.exp/reference"
)
  .then(it => it.text())
  .then(it => cheerio.load(it))
  .then($ => {
    const $content = $(`#${KlassName}`).parent()
    return contentToJS(KlassName, $, $content)
  })
  .then(it => process.stdout.write(JSON.stringify(it)))
  .catch(error => {
    console.error(error)
    process.exit(1)
  })

function contentToJS(KlassName, $, $content) {
  const constructor = $content
    .find(`#${KlassName}`)
    .next()
    .find("code")
    .text()

  const $constructorTable = $content.find(
    `[summary="class ${KlassName} - Constructor"]`
  )
  const [, constructorArgs] = $constructorTable
    .find(`tr > td > code`)
    .text()
    .match(/\S+\((.*)\)/)

  const $methodsTable = $content.find(
    `[summary="class ${KlassName} - Methods"]`
  )
  const methods = $methodsTable
    .find("tbody > tr")
    .map((i, tr) => {
      const $tr = $(tr)
      const [, name, args] = $tr
        .find("td:first-child")
        .text()
        .replace("\n", "")
        .match(/(\S+)\((.*)\)/)

      const returnsDesc = toMarkdown(
        $tr.find("td:nth-child(2) > div.desc").html()
      )

      return {
        name,
        args,
        returns: $tr.find("td:nth-child(2) > div > code").text(),
        returnsDesc,
      }
    })
    .get()

  const $eventsTable = $content.find(`[summary="class ${KlassName} - Events"]`)
  const events = $eventsTable
    .find("tbody > tr")
    .map((i, tr) => {
      const $tr = $(tr)
      const name = $tr.find("td:first-child").text()

      return {
        name,
        args: $tr.find("td:nth-child(2) > div > code").text(),
        returnsDesc: $tr.find("td:nth-child(2) > div.desc").text(),
      }
    })
    .get()

  return {
    constructor: {
      name: constructor,
      args: constructorArgs,
    },
    methods,
    events,
  }
}
<|endoftext|>


<commit_before>module.exports = function(sails) {

	/**
	 * Module dependencies.
	 */

	var interpret	= require('./interpreter/interpret')(sails),
		getVerb		= require('./interpreter/getVerb');

	/**
	 * Fired after a socket is connected
	 */

	return function onConnect (socket) {
		sails.log.verbose('A socket.io client ('+ socket.id + ') connected successfully!');

		// Legacy support of `message`
		mapRoute('message');

		// Verb support
		mapRoute('get');
		mapRoute('post');
		mapRoute('put');
		mapRoute('delete');

		// Map a socket message to the router
		function mapRoute (messageName) {
			socket.on(messageName, function (socketReq, callback) {

				sails.log.verbose('Routing message over socket: ', socketReq);

				callback = callback || function noCallback(body, status) {
					sails.log.error('No callback specified!');
				};

				var verb = getVerb(socketReq, messageName);

				// Translate socket.io message to an Express-looking request
				interpret(socketReq, callback, socket, verb, function requestBuilt (err, request) {

					// If interpretation fails, log the error and do nothing
					if (err) {
						sails.log.error(err);
						return;
					}

					// Route socket.io request
					sails.emit('router:request', request.req, request.res);
				});

			});
		}
	};

};
<commit_msg>stub for customizable socket connection logic<commit_after>module.exports = function(sails) {

	/**
	 * Module dependencies.
	 */

	var interpret	= require('./interpreter/interpret')(sails),
		getVerb		= require('./interpreter/getVerb');

	/**
	 * Fired after a socket is connected
	 */

	return function onConnect (socket) {
		sails.log.verbose('A socket.io client ('+ socket.id + ') connected successfully!');

		// Legacy support of `message`
		mapRoute('message');

		// Verb support
		mapRoute('get');
		mapRoute('post');
		mapRoute('put');
		mapRoute('delete');

		// TODO: configurable custom connection logic here
		// (default to noop function)

		// Map a socket message to the router
		function mapRoute (messageName) {
			socket.on(messageName, function (socketReq, callback) {

				sails.log.verbose('Routing message over socket: ', socketReq);

				callback = callback || function noCallback(body, status) {
					sails.log.error('No callback specified!');
				};

				var verb = getVerb(socketReq, messageName);

				// Translate socket.io message to an Express-looking request
				interpret(socketReq, callback, socket, verb, function requestBuilt (err, request) {

					// If interpretation fails, log the error and do nothing
					if (err) {
						sails.log.error(err);
						return;
					}

					// Route socket.io request
					sails.emit('router:request', request.req, request.res);
				});

			});
		}
	};

};
<|endoftext|>


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

const Base = require('../Base.es6.js');
const memos = require('./memos.es6.js');
const MemoBuilder = require('../memo/MemoBuilder.es6.js');
const Memo = require('../memo/Memo.es6.js');

class LocalFilesRunner extends Base {
  configure(argv) {
    this.files = argv.files;
  }

  run() {
    // TODO: Do something more robust?
    if (this.running) throw new Error('LocalFilesRunner already running');
    this.logger.log('Running');

    this.running = true;

    return this.createPipeline().runAll(this.files).then(function() {
      console.log('!!!!!!!!!!!!!!!!!!!!!! runAll(files).then() arguments:', arguments);
      // this.running = false;
    });
  }

  createPipeline() {
    const parseWebIDL = memos.parseWebIDL();
    const readFile = memos.readFile();
    const dropCPreprocessorDirectives = memos.dropCPreprocessorDirectives();

    const builder = new MemoBuilder();

    return builder.start()
      .forEach()
        .then(readFile)
        .then(dropCPreprocessorDirectives)
        .then(new Memo({
          f: function(idlStr) {
            const ret = idlStr.replace(/[ ]*[|&][ ]*/g, '');
            console.info('Drop amps');
            console.info(ret);
            return ret;
          },
        }))
        .then(parseWebIDL)
        .keep()
        .build();
  }
}

module.exports = LocalFilesRunner;
<commit_msg>Drop extra preprocessing in LocalFilesRunner; had been used for debugging<commit_after>/**
 * @license
 * Copyright 2016 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
'use strict';

const Base = require('../Base.es6.js');
const memos = require('./memos.es6.js');
const MemoBuilder = require('../memo/MemoBuilder.es6.js');
const Memo = require('../memo/Memo.es6.js');

class LocalFilesRunner extends Base {
  configure(argv) {
    this.files = argv.files;
  }

  run() {
    // TODO: Do something more robust?
    if (this.running) throw new Error('LocalFilesRunner already running');
    this.logger.log('Running');

    this.running = true;

    return this.createPipeline().runAll(this.files).then(function() {
      console.log('!!!!!!!!!!!!!!!!!!!!!! runAll(files).then() arguments:', arguments);
      // this.running = false;
    });
  }

  createPipeline() {
    const parseWebIDL = memos.parseWebIDL();
    const readFile = memos.readFile();

    const builder = new MemoBuilder();

    return builder.start()
      .forEach()
        .then(readFile)
        .then(parseWebIDL)
        .keep()
        .build();
  }
}

module.exports = LocalFilesRunner;
<|endoftext|>


<commit_before>import Vue from 'vue';
import Popper from 'popper.js';
import event from '../base/utils/event';

export default {
    name: 'u-popper',
    props: {
        placement: {
            type: String, default: 'bottom-start',
            validator: (value) => /^(top|bottom|left|right)(-start|-end)?$/.test(value),
        },
        trigger: { type: String, default: 'click', validator: (value) => ['click', 'hover', 'right-click', 'double-click', 'manual'].includes(value) },
        reference: Object,
        open: { type: Boolean, default: false },
        offset: { type: Number, default: 0 },
        escapeWithReference: { type: Boolean, default: false },
        hoverDelay: { type: Number, default: 0 },
        boundariesElement: { default: 'scrollParent' },
        arrowElement: { type: String, default: '[u-arrow]' },
        appendTo: { type: String, default: 'body', validator: (value) => ['body', 'reference'].includes(value) },
        options: {
            type: Object,
            default() {
                return {
                    modifiers: {},
                };
            },
        },
        disabled: { type: Boolean, default: false },
    },
    data() {
        return {
            currentOpen: this.open,
        };
    },
    watch: {
        open(value) {
            this.currentOpen = value;
        },
        currentOpen(value) {
            // 不直接用样式的显隐，而用popper的create和destroy，popper有可能是从不同的地方触发的，reference对象会变
            value ? this.createPopper() : this.destroyPopper();
        },
    },
    render() {
        return this.$slots.default && this.$slots.default[0];
    },
    mounted() {
        // 创建VNode
        /* eslint-disable consistent-this */
        const parentVM = this;
        this.childVM = new Vue({
            name: 'u-popper-child',
            render(h) { return parentVM.$slots.popper && parentVM.$slots.popper[0]; },
        });
        this.childVM.parentVM = parentVM;
        this.childVM.$mount();

        const referenceEl = this.$el;
        const popperEl = this.childVM.$el;

        // 绑定事件
        const offEvents = this.offEvents = [];
        if (this.trigger === 'click')
            offEvents.push(event.on(referenceEl, 'click', () => this.toggle()));
        else if (this.trigger === 'hover') {
            offEvents.push(event.on(referenceEl, 'mouseenter', () => {
                setTimeout(() => this.toggle(true), this.hoverDelay);
            }));
            offEvents.push(event.on(document, 'mouseover', (e) => {
                !referenceEl.contains(e.target) && !popperEl.contains(e.target) && this.toggle(false);
            }));
        } else if (this.trigger === 'double-click')
            offEvents.push(event.on(referenceEl, 'dblclick', () => this.toggle()));
        else if (this.trigger === 'right-click') {
            offEvents.push(event.on(referenceEl, 'contextmenu', (e) => {
                e.preventDefault();
                this.toggle();
            }));
        }
        offEvents.push(event.on(document, 'click', (e) => {
            !referenceEl.contains(e.target) && !popperEl.contains(e.target) && this.toggle(false);
        }));
    },
    updated() {
        this.childVM.$forceUpdate();
    },
    destroyed() {
        this.destroyPopper();

        // 取消绑定事件
        this.offEvents.forEach((off) => off());

        this.childVM && this.childVM.destroy && this.childVM.destroy();
        this.childVM = undefined;
    },
    methods: {
        getOptions() {
            const options = Object.assign({}, this.options, {
                placement: this.placement,
            });

            options.modifiers.offset = this.offset;
            options.escapeWithReference = this.escapeWithReference;

            options.modifiers.arrow = { element: this.arrowElement };
            options.modifiers.preventOverflow = { boundariesElement: this.boundariesElement };

            return options;
        },
        createPopper() {
            const referenceEl = this.$el;
            const popperEl = this.childVM.$el;
            if (this.appendTo === 'body')
                document.body.appendChild(popperEl);
            else if (this.appendTo === 'reference')
                referenceEl.appendChild(popperEl);

            const options = this.getOptions();
            this.popper = new Popper(referenceEl, popperEl, options);
        },
        update() {
            this.popper.update();
        },
        destroyPopper() {
            const referenceEl = this.$el;
            const popperEl = this.childVM.$el;
            if (this.appendTo === 'body')
                popperEl.parentElement === document.body && document.body.removeChild(popperEl);
            else if (this.appendTo === 'reference')
                popperEl.parentElement === referenceEl && referenceEl.removeChild(popperEl);

            this.popper && this.popper.destroy();
            this.popper = undefined;
        },
        toggle(open) {
            if (this.disabled)
                return;

            if (typeof open !== 'boolean')
                open = !this.currentOpen;

            const oldOpen = this.currentOpen;

            this.$emit('before-toggle', {
                preventDefault: () => open = oldOpen,
            });

            if (open === oldOpen)
                return;

            this.currentOpen = open;
            this.$emit('update:open', open);
            this.$emit('toggle', {
                open,
            });
        },
    },
};
<commit_msg>:bug: Fix u-popper destroy instance no update method error<commit_after>import Vue from 'vue';
import Popper from 'popper.js';
import event from '../base/utils/event';

export default {
    name: 'u-popper',
    props: {
        placement: {
            type: String, default: 'bottom-start',
            validator: (value) => /^(top|bottom|left|right)(-start|-end)?$/.test(value),
        },
        trigger: { type: String, default: 'click', validator: (value) => ['click', 'hover', 'right-click', 'double-click', 'manual'].includes(value) },
        reference: Object,
        open: { type: Boolean, default: false },
        offset: { type: Number, default: 0 },
        escapeWithReference: { type: Boolean, default: false },
        hoverDelay: { type: Number, default: 0 },
        boundariesElement: { default: 'scrollParent' },
        arrowElement: { type: String, default: '[u-arrow]' },
        appendTo: { type: String, default: 'body', validator: (value) => ['body', 'reference'].includes(value) },
        options: {
            type: Object,
            default() {
                return {
                    modifiers: {},
                };
            },
        },
        disabled: { type: Boolean, default: false },
    },
    data() {
        return {
            currentOpen: this.open,
        };
    },
    watch: {
        open(value) {
            this.currentOpen = value;
        },
        currentOpen(value) {
            // 不直接用样式的显隐，而用popper的create和destroy，popper有可能是从不同的地方触发的，reference对象会变
            value ? this.createPopper() : this.destroyPopper();
        },
    },
    render() {
        return this.$slots.default && this.$slots.default[0];
    },
    mounted() {
        // 创建VNode
        /* eslint-disable consistent-this */
        const parentVM = this;
        this.childVM = new Vue({
            name: 'u-popper-child',
            render(h) { return parentVM.$slots.popper && parentVM.$slots.popper[0]; },
        });
        this.childVM.parentVM = parentVM;
        this.childVM.$mount();

        const referenceEl = this.$el;
        const popperEl = this.childVM.$el;

        // 绑定事件
        const offEvents = this.offEvents = [];
        if (this.trigger === 'click')
            offEvents.push(event.on(referenceEl, 'click', () => this.toggle()));
        else if (this.trigger === 'hover') {
            offEvents.push(event.on(referenceEl, 'mouseenter', () => {
                setTimeout(() => this.toggle(true), this.hoverDelay);
            }));
            offEvents.push(event.on(document, 'mouseover', (e) => {
                !referenceEl.contains(e.target) && !popperEl.contains(e.target) && this.toggle(false);
            }));
        } else if (this.trigger === 'double-click')
            offEvents.push(event.on(referenceEl, 'dblclick', () => this.toggle()));
        else if (this.trigger === 'right-click') {
            offEvents.push(event.on(referenceEl, 'contextmenu', (e) => {
                e.preventDefault();
                this.toggle();
            }));
        }
        offEvents.push(event.on(document, 'click', (e) => {
            !referenceEl.contains(e.target) && !popperEl.contains(e.target) && this.toggle(false);
        }));
    },
    updated() {
        this.childVM.$forceUpdate();
    },
    destroyed() {
        this.destroyPopper();

        // 取消绑定事件
        this.offEvents.forEach((off) => off());

        this.childVM && this.childVM.destroy && this.childVM.destroy();
        this.childVM = undefined;
    },
    methods: {
        getOptions() {
            const options = Object.assign({}, this.options, {
                placement: this.placement,
            });

            options.modifiers.offset = this.offset;
            options.escapeWithReference = this.escapeWithReference;

            options.modifiers.arrow = { element: this.arrowElement };
            options.modifiers.preventOverflow = { boundariesElement: this.boundariesElement };

            return options;
        },
        createPopper() {
            const referenceEl = this.$el;
            const popperEl = this.childVM.$el;
            if (this.appendTo === 'body')
                document.body.appendChild(popperEl);
            else if (this.appendTo === 'reference')
                referenceEl.appendChild(popperEl);

            const options = this.getOptions();
            this.popper = new Popper(referenceEl, popperEl, options);
        },
        update() {
            if (this.popper)
                this.popper.update();
        },
        destroyPopper() {
            const referenceEl = this.$el;
            const popperEl = this.childVM.$el;
            if (this.appendTo === 'body')
                popperEl.parentElement === document.body && document.body.removeChild(popperEl);
            else if (this.appendTo === 'reference')
                popperEl.parentElement === referenceEl && referenceEl.removeChild(popperEl);

            this.popper && this.popper.destroy();
            this.popper = undefined;
        },
        toggle(open) {
            if (this.disabled)
                return;

            if (typeof open !== 'boolean')
                open = !this.currentOpen;

            const oldOpen = this.currentOpen;

            this.$emit('before-toggle', {
                preventDefault: () => open = oldOpen,
            });

            if (open === oldOpen)
                return;

            this.currentOpen = open;
            this.$emit('update:open', open);
            this.$emit('toggle', {
                open,
            });
        },
    },
};
<|endoftext|>