<commit_before>import d3 from 'd3';
import d3tip from 'd3-tip';
import dompurify from 'dompurify';
import { formatDateVerbose } from '../../modules/dates';

// Regexp for the label added to time shifted series
// (1 hour offset, 2 days offset, etc.)
const TIME_SHIFT_PATTERN = /\d+ \w+ offset/;

export function cleanColorInput(value) {
  // for superset series that should have the same color
  return String(value).trim()
    .toLowerCase()
    .split(', ')
    .filter(k => !TIME_SHIFT_PATTERN.test(k))
    .join(', ');
}

export function drawBarValues(svg, data, stacked, axisFormat) {
  const format = d3.format(axisFormat || '.3s');
  const countSeriesDisplayed = data.length;

  const totalStackedValues = stacked && data.length !== 0 ?
    data[0].values.map(function (bar, iBar) {
      const bars = data.map(series => series.values[iBar]);
      return d3.sum(bars, d => d.y);
    }) : [];

  const groupLabels = svg.select('g.nv-barsWrap').append('g');

  svg.selectAll('g.nv-group')
    .filter((d, i) => !stacked || i === countSeriesDisplayed - 1)
    .selectAll('rect')
    .each(function (d, index) {
      const rectObj = d3.select(this);
      if (rectObj.attr('class').includes('positive')) {
        const transformAttr = rectObj.attr('transform');
        const yPos = parseFloat(rectObj.attr('y'));
        const xPos = parseFloat(rectObj.attr('x'));
        const rectWidth = parseFloat(rectObj.attr('width'));
        const textEls = groupLabels.append('text')
          .attr('y', yPos - 5)
          .text(format(stacked ? totalStackedValues[index] : d.y))
          .attr('transform', transformAttr)
          .attr('class', 'bar-chart-label');
        const labelWidth = textEls.node().getBBox().width;
        textEls.attr('x', xPos + rectWidth / 2 - labelWidth / 2); // fine tune
      }
    });
}

// Custom sorted tooltip
// use a verbose formatter for times
export function generateRichLineTooltipContent(d, valueFormatter) {
  let tooltip = '';
  tooltip += "

"
    + `<strong class='x-value'>${formatDateVerbose(d.value)}</strong>`
    + '

';
  d.series.sort((a, b) => a.value >= b.value ? -1 : 1);
  d.series.forEach((series) => {
    tooltip += (
      `<tr class="${series.highlight ? 'emph' : ''}">` +
        `<td class='legend-color-guide' style="opacity: ${series.highlight ? '1' : '0.75'};"">` +
          '<div ' +
            `style="border: 2px solid ${series.highlight ? 'black' : 'transparent'}; background-color: ${series.color};"` +
          '>
' +
        '	' +
        `<td>${dompurify.sanitize(series.key)}</td>` +
        `<td>${valueFormatter(series.value)}</td>` +
      '
'
    );
  });
  tooltip += '

';
  return tooltip;
}

export function generateMultiLineTooltipContent(d, xFormatter, yFormatters) {
  const tooltipTitle = xFormatter(d.value);
  let tooltip = '';

  tooltip += "

"
    + `<strong class='x-value'>${tooltipTitle}</strong>`
    + '

';

  d.series.forEach((series, i) => {
    const yFormatter = yFormatters[i];
    tooltip += "
"
      + `<div style="background-color: ${series.color};"></div></td>`
      + `<td class='key'>${series.key}</td>`
      + `<td class='value'>${yFormatter(series.value)}</td></tr>`;
  });

  tooltip += '

';

  return tooltip;
}

function getLabel(stringOrObjectWithLabel) {
  return stringOrObjectWithLabel.label || stringOrObjectWithLabel;
}

function createHTMLRow(col1, col2) {
  return `<tr><td>${col1}</td><td>${col2}</td></tr>`;
}

export function generateBubbleTooltipContent({
  point,
  entity,
  xField,
  yField,
  sizeField,
  xFormatter,
  yFormatter,
  sizeFormatter,
}) {
  let s = '
';
  s += (
    `<tr><td style="color: ${point.color};">` +
      `<strong>${point[entity]}</strong> (${point.group})` +
    '
'
  );
  s += createHTMLRow(getLabel(xField), xFormatter(point.x));
  s += createHTMLRow(getLabel(yField), yFormatter(point.y));
  s += createHTMLRow(getLabel(sizeField), sizeFormatter(point.size));
  s += '
';
  return s;
}

export function hideTooltips() {
  const target = document.querySelector('.nvtooltip');
  if (target) {
    target.style.opacity = 0;
  }
}

export function wrapTooltip(chart, maxWidth) {
  const tooltipLayer = chart.useInteractiveGuideline && chart.useInteractiveGuideline() ?
    chart.interactiveLayer : chart;
  const tooltipGeneratorFunc = tooltipLayer.tooltip.contentGenerator();
  tooltipLayer.tooltip.contentGenerator((d) => {
    let tooltip = `<div style="max-width: ${maxWidth * 0.5}px">`;
    tooltip += tooltipGeneratorFunc(d);
    tooltip += '
';
    return tooltip;
  });
}

export function tipFactory(layer) {
  return d3tip()
    .attr('class', 'd3-tip')
    .direction('n')
    .offset([-5, 0])
    .html((d) => {
      if (!d) {
        return '';
      }
      const title = d[layer.titleColumn] && d[layer.titleColumn].length ?
        d[layer.titleColumn] + ' - ' + layer.name :
        layer.name;
      const body = Array.isArray(layer.descriptionColumns) ?
        layer.descriptionColumns.map(c => d[c]) : Object.values(d);
      return '
' + title + '

' +
        '
' + body.join(', ') + '
';
    });
}

export function getMaxLabelSize(svg, axisClass) {
  // axis class = .nv-y2  // second y axis on dual line chart
  // axis class = .nv-x  // x axis on time series line chart
  const tickTexts = svg.selectAll(`.${axisClass} g.tick text`);
  if (tickTexts.length > 0) {
    const lengths = tickTexts[0].map(text => text.getComputedTextLength());
    return Math.ceil(Math.max(...lengths));
  }
  return 0;
}

export function formatLabel(input, verboseMap = {}) {
  // The input for label may be a string or an array of string
  // When using the time shift feature, the label contains a '---' in the array
  const verboseLookup = s => verboseMap[s] || s;
  return (Array.isArray(input) && input.length)
    ? input.map(l => TIME_SHIFT_PATTERN.test(l) ? l : verboseLookup(l))
      .join(', ')
    : verboseLookup(input);
}

const MIN_BAR_WIDTH = 15;

export function computeBarChartWidth(data, stacked, maxWidth) {
  const barCount = stacked
    ? d3.max(data, d => d.values.length)
    : d3.sum(data, d => d.values.length);

  const barWidth = barCount * MIN_BAR_WIDTH;
  return Math.max(barWidth, maxWidth);
}

export function tryNumify(s) {
  // Attempts casting to Number, returns string when failing
  const n = Number(s);
  return Number.isNaN(n) ? s : n;
}

export function stringifyTimeRange(extent) {
  if (extent.some(d => d.toISOString === undefined)) {
    return null;
  }
  return extent.map(d => d.toISOString()
    .slice(0, -1))
    .join(' : ');
}

export function setAxisShowMaxMin(axis, showminmax) {
  if (axis && axis.showMaxMin && showminmax !== undefined) {
    axis.showMaxMin(showminmax);
  }
}
<commit_msg>do not convert value to lowercase when looking up color (#6384)<commit_after>import d3 from 'd3';
import d3tip from 'd3-tip';
import dompurify from 'dompurify';
import { formatDateVerbose } from '../../modules/dates';

// Regexp for the label added to time shifted series
// (1 hour offset, 2 days offset, etc.)
const TIME_SHIFT_PATTERN = /\d+ \w+ offset/;

export function cleanColorInput(value) {
  // for superset series that should have the same color
  return String(value).trim()
    .split(', ')
    .filter(k => !TIME_SHIFT_PATTERN.test(k))
    .join(', ');
}

export function drawBarValues(svg, data, stacked, axisFormat) {
  const format = d3.format(axisFormat || '.3s');
  const countSeriesDisplayed = data.length;

  const totalStackedValues = stacked && data.length !== 0 ?
    data[0].values.map(function (bar, iBar) {
      const bars = data.map(series => series.values[iBar]);
      return d3.sum(bars, d => d.y);
    }) : [];

  const groupLabels = svg.select('g.nv-barsWrap').append('g');

  svg.selectAll('g.nv-group')
    .filter((d, i) => !stacked || i === countSeriesDisplayed - 1)
    .selectAll('rect')
    .each(function (d, index) {
      const rectObj = d3.select(this);
      if (rectObj.attr('class').includes('positive')) {
        const transformAttr = rectObj.attr('transform');
        const yPos = parseFloat(rectObj.attr('y'));
        const xPos = parseFloat(rectObj.attr('x'));
        const rectWidth = parseFloat(rectObj.attr('width'));
        const textEls = groupLabels.append('text')
          .attr('y', yPos - 5)
          .text(format(stacked ? totalStackedValues[index] : d.y))
          .attr('transform', transformAttr)
          .attr('class', 'bar-chart-label');
        const labelWidth = textEls.node().getBBox().width;
        textEls.attr('x', xPos + rectWidth / 2 - labelWidth / 2); // fine tune
      }
    });
}

// Custom sorted tooltip
// use a verbose formatter for times
export function generateRichLineTooltipContent(d, valueFormatter) {
  let tooltip = '';
  tooltip += "

"
    + `<strong class='x-value'>${formatDateVerbose(d.value)}</strong>`
    + '

';
  d.series.sort((a, b) => a.value >= b.value ? -1 : 1);
  d.series.forEach((series) => {
    tooltip += (
      `<tr class="${series.highlight ? 'emph' : ''}">` +
        `<td class='legend-color-guide' style="opacity: ${series.highlight ? '1' : '0.75'};"">` +
          '<div ' +
            `style="border: 2px solid ${series.highlight ? 'black' : 'transparent'}; background-color: ${series.color};"` +
          '>
' +
        '	' +
        `<td>${dompurify.sanitize(series.key)}</td>` +
        `<td>${valueFormatter(series.value)}</td>` +
      '
'
    );
  });
  tooltip += '

';
  return tooltip;
}

export function generateMultiLineTooltipContent(d, xFormatter, yFormatters) {
  const tooltipTitle = xFormatter(d.value);
  let tooltip = '';

  tooltip += "

"
    + `<strong class='x-value'>${tooltipTitle}</strong>`
    + '

';

  d.series.forEach((series, i) => {
    const yFormatter = yFormatters[i];
    tooltip += "
"
      + `<div style="background-color: ${series.color};"></div></td>`
      + `<td class='key'>${series.key}</td>`
      + `<td class='value'>${yFormatter(series.value)}</td></tr>`;
  });

  tooltip += '

';

  return tooltip;
}

function getLabel(stringOrObjectWithLabel) {
  return stringOrObjectWithLabel.label || stringOrObjectWithLabel;
}

function createHTMLRow(col1, col2) {
  return `<tr><td>${col1}</td><td>${col2}</td></tr>`;
}

export function generateBubbleTooltipContent({
  point,
  entity,
  xField,
  yField,
  sizeField,
  xFormatter,
  yFormatter,
  sizeFormatter,
}) {
  let s = '
';
  s += (
    `<tr><td style="color: ${point.color};">` +
      `<strong>${point[entity]}</strong> (${point.group})` +
    '
'
  );
  s += createHTMLRow(getLabel(xField), xFormatter(point.x));
  s += createHTMLRow(getLabel(yField), yFormatter(point.y));
  s += createHTMLRow(getLabel(sizeField), sizeFormatter(point.size));
  s += '
';
  return s;
}

export function hideTooltips() {
  const target = document.querySelector('.nvtooltip');
  if (target) {
    target.style.opacity = 0;
  }
}

export function wrapTooltip(chart, maxWidth) {
  const tooltipLayer = chart.useInteractiveGuideline && chart.useInteractiveGuideline() ?
    chart.interactiveLayer : chart;
  const tooltipGeneratorFunc = tooltipLayer.tooltip.contentGenerator();
  tooltipLayer.tooltip.contentGenerator((d) => {
    let tooltip = `<div style="max-width: ${maxWidth * 0.5}px">`;
    tooltip += tooltipGeneratorFunc(d);
    tooltip += '
';
    return tooltip;
  });
}

export function tipFactory(layer) {
  return d3tip()
    .attr('class', 'd3-tip')
    .direction('n')
    .offset([-5, 0])
    .html((d) => {
      if (!d) {
        return '';
      }
      const title = d[layer.titleColumn] && d[layer.titleColumn].length ?
        d[layer.titleColumn] + ' - ' + layer.name :
        layer.name;
      const body = Array.isArray(layer.descriptionColumns) ?
        layer.descriptionColumns.map(c => d[c]) : Object.values(d);
      return '
' + title + '

' +
        '
' + body.join(', ') + '
';
    });
}

export function getMaxLabelSize(svg, axisClass) {
  // axis class = .nv-y2  // second y axis on dual line chart
  // axis class = .nv-x  // x axis on time series line chart
  const tickTexts = svg.selectAll(`.${axisClass} g.tick text`);
  if (tickTexts.length > 0) {
    const lengths = tickTexts[0].map(text => text.getComputedTextLength());
    return Math.ceil(Math.max(...lengths));
  }
  return 0;
}

export function formatLabel(input, verboseMap = {}) {
  // The input for label may be a string or an array of string
  // When using the time shift feature, the label contains a '---' in the array
  const verboseLookup = s => verboseMap[s] || s;
  return (Array.isArray(input) && input.length)
    ? input.map(l => TIME_SHIFT_PATTERN.test(l) ? l : verboseLookup(l))
      .join(', ')
    : verboseLookup(input);
}

const MIN_BAR_WIDTH = 15;

export function computeBarChartWidth(data, stacked, maxWidth) {
  const barCount = stacked
    ? d3.max(data, d => d.values.length)
    : d3.sum(data, d => d.values.length);

  const barWidth = barCount * MIN_BAR_WIDTH;
  return Math.max(barWidth, maxWidth);
}

export function tryNumify(s) {
  // Attempts casting to Number, returns string when failing
  const n = Number(s);
  return Number.isNaN(n) ? s : n;
}

export function stringifyTimeRange(extent) {
  if (extent.some(d => d.toISOString === undefined)) {
    return null;
  }
  return extent.map(d => d.toISOString()
    .slice(0, -1))
    .join(' : ');
}

export function setAxisShowMaxMin(axis, showminmax) {
  if (axis && axis.showMaxMin && showminmax !== undefined) {
    axis.showMaxMin(showminmax);
  }
}
<|endoftext|>


<commit_before>// This is a manifest file that'll be compiled into application.js, which will include all the files
// listed below.
//
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
// or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
//
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// compiled file.
//
// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
// about supported directives.
//
//= require jquery
//= require jquery-ui
//= require jquery_ujs
//= require elfproef_plan
//= require employees
<commit_msg>removed required employees.js file from application.js in test<commit_after>// This is a manifest file that'll be compiled into application.js, which will include all the files
// listed below.
//
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
// or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
//
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// compiled file.
//
// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
// about supported directives.
//
//= require jquery
//= require jquery-ui
//= require jquery_ujs
//= require elfproef_plan

<|endoftext|>


<commit_before><commit_msg>Update Question 3 Solution.js<commit_after><|endoftext|>


<commit_before>

module.exports = function(options) {

  /**
   * Imports
   */
  var gulp      = require('gulp');
  var mocha     = require('gulp-mocha');
  var istanbul  = require('gulp-istanbul');
  var $         = options.plugins;

  function runTests (argument) {
    return gulp.src(options.specFiles, {read: false})
      .pipe(mocha({reporter: 'nyan'})).on('error', options.errorHandler('Mocha')) // gulp-mocha needs filepaths so you can't have any plugins before it
      .pipe(istanbul.writeReports());
  }

  function setupCoverage () {
    return gulp.src('../dist/**/*.js')
      .pipe(istanbul())
      .pipe(istanbul.hookRequire());
  }

  gulp.task('setup-coverage', [], setupCoverage);

  gulp.task('test', ['scripts', 'setup-coverage'], runTests);

  gulp.task('test:auto', ['watchTests', 'test', 'setup-coverage'], function(){
    return gulp.watch(options.tmp + '/**/*.js', runTests);
  });
}<commit_msg>#18 - errorHandler to Coverage errors<commit_after>

module.exports = function(options) {

  /**
   * Imports
   */
  var gulp      = require('gulp');
  var mocha     = require('gulp-mocha');
  var istanbul  = require('gulp-istanbul');

  function runTests (argument) {
    return gulp.src(options.specFiles, {read: false})
      .pipe(mocha({reporter: 'nyan'})).on('error', options.errorHandler('Mocha')) // gulp-mocha needs filepaths so you can't have any plugins before it
      .pipe(istanbul.writeReports());
  }

  function setupCoverage () {
    return gulp.src('../dist/**/*.js')
      .pipe(istanbul())
      .pipe(istanbul.hookRequire()).on('error', options.errorHandler('Coverage'));
  }

  gulp.task('setup-coverage', [], setupCoverage);

  gulp.task('test', ['scripts', 'setup-coverage'], runTests);

  gulp.task('test:auto', ['watchTests', 'test', 'setup-coverage'], function(){
    return gulp.watch(options.tmp + '/**/*.js', runTests);
  });

}<|endoftext|>


<commit_before>import { Text, Morph, show } from "./index.js";
import { arr } from "lively.lang";
import { pt, Color } from "lively.graphics";

export class MenuItem extends Text {

  constructor({textString, action, props}) {
    super({
     fixedWidth: false, fixedHeight: false,
     fill: null,
     fontSize: 14,
     draggable: false,
     readOnly: true,
     nativeCursor: "pointer",
     textString,
     action,
     ...props});
  }

  get action() { return this.getProperty("action") }
  set action(value) { this.addValueChange("action", value); }

  get isMenuItem() { return true; }

  select() {
    this.fontColor = Color.white;
    this.fill = Color.blue;
  }

  deselect() {
    this.fill = Color.null;
    this.fontColor = Color.black;
  }

  onHoverIn(evt) {
    this.owner.itemMorphs.forEach(ea => ea !== this && ea.deselect());
    this.select();
  }

  onHoverOut(evt) {
    this.deselect();
  }

  onMouseDown(evt) {
    try {
      if (typeof this.action !== "function")
        throw new Error(`Menu item ${this.textString} as no executable action!`)
      this.action();
    } catch (err) {
      var w = this.world();
      if (w) w.logError(err);
      else console.error(err);
    }
  }
}

export class Menu extends Morph {

  static forItems(items, opts = {title: ""}) {
    return new this({...opts, title: opts.title, items});
  }

  constructor(props) {
    super({
      dropShadow: true,
      title: null,
      padding: 3,
      borderWidth: 1,
      borderColor: Color.gray,
      ...props
    });
    this.updateMorphs();
  }

  remove() {
     this.animate({
        opacity: 0,
        duration: 300,
        onFinish: () => super.remove()
      });
  }

  get title() { return this.getProperty("title") }
  set title(value) { this.addValueChange("title", value); }

  get items() { return this.getProperty("items") }
  set items(items) {
    items = items.map(this.ensureItem.bind(this));
    this.addValueChange("items", items);
  }

  get padding() { return this.getProperty("padding") }
  set padding(value) { this.addValueChange("padding", value); }

  get itemMorphs() {
    return this.submorphs.filter(ea => ea.isMenuItem);
  }

  ensureItem(item) {
    var invalid = ["invalid item", () => show("invalid item")];
    if (!item) return invalid;

    if (Array.isArray(item)) {
      var [name, exec] = item;
      if (typeof name !== "string" || typeof exec !== "function") return invalid;
      return item;
    }

    if (item.command) {
      var {command, showKeyShortcuts, target, alias, args} = item;
      if (!command || !target) return invalid;
      if (showKeyShortcuts === undefined) showKeyShortcuts = true;
      var keys = !showKeyShortcuts ?
          null :
          typeof showKeyShortcuts === "string" ?
            showKeyShortcuts :
            target.keysForCommand(command),
          descr = (alias || command) + (keys ? ` [${keys}]` : "");
      return [descr, () => target.execCommand(command, args)]
    }

    return invalid;
  }

  updateMorphs() {
    this.submorphs = [];
    var p = this.padding;
    var maxWidth = 0, pos = pt(p, p);

    if (this.title) {
      var title = this.addMorph(Text.makeLabel(this.title, {position: pos, fontSize: 16, draggable: false}));
      pos = title.bottomLeft;
      maxWidth = Math.max(title.width, maxWidth);
    }

    this.items.forEach(item => {
      var itemMorph = this.addMorph(new MenuItem({
           textString: item[0],
           action: item[1],
           props: {position: pos}
      }));
      pos = itemMorph.bottomLeft;
      maxWidth = Math.max(itemMorph.width + 6/*FIXME*/, maxWidth);
    });

    this.submorphs.forEach(ea => {
      ea.fit();
      ea.fixedWidth = true;
      ea.fixedHeight = true;
      ea.width = maxWidth;
    });

    this.extent = pt(maxWidth + 2*p, pos.y + p);
  }

}
<commit_msg>menu mprovements<commit_after>import { Text, Morph, show } from "./index.js";
import { arr, obj } from "lively.lang";
import { pt, Color } from "lively.graphics";

export class MenuItem extends Text {

  constructor({textString, action, props} = {}) {
    super({
      fixedWidth: false, fixedHeight: false,
      fill: null,
      fontSize: 14,
      draggable: false,
      readOnly: true,
      nativeCursor: "pointer",
      textString,
      action,
      ...obj.dissoc(props, ["selected"])
    });
    this.selected = props.hasOwnProperty("selected") ? props.selected : false;
  }

  get selected() { return this.getProperty("selected"); }
  set selected(value) {
    if (this.selected === value) return;
    this.addValueChange("selected", value);
    if (value) {
      this.fontColor = Color.white;
      this.fill = Color.blue;
    } else {
      this.fill = Color.null;
      this.fontColor = Color.black;
    }
  }

  get action() { return this.getProperty("action") }
  set action(value) { this.addValueChange("action", value); }

  get isMenuItem() { return true; }

  onHoverIn(evt) {
    this.owner.itemMorphs.forEach(ea => ea !== this && (ea.selected = false));
    this.selected = true;
  }

  onHoverOut(evt) {
    this.selected = false;
  }

  onMouseDown(evt) {
    try {
      if (typeof this.action !== "function")
        throw new Error(`Menu item ${this.textString} as no executable action!`)
      this.action();
    } catch (err) {
      var w = this.world();
      if (w) w.logError(err);
      else console.error(err);
    }
  }
}

export class Menu extends Morph {

  static forItems(items, opts = {title: ""}) {
    return new this({...opts, title: opts.title, items});
  }

  constructor(props) {
    super({
      dropShadow: true,
      title: null,
      padding: 3,
      borderWidth: 1,
      borderColor: Color.gray,
      ...props
    });
    this.updateMorphs();
  }

  remove() {
     this.animate({
        opacity: 0,
        duration: 300,
        onFinish: () => super.remove()
      });
  }

  get title() { return this.getProperty("title") }
  set title(value) { this.addValueChange("title", value); }

  get items() { return this.getProperty("items") }
  set items(items) {
    items = items.map(this.ensureItem.bind(this));
    this.addValueChange("items", items);
  }

  get padding() { return this.getProperty("padding") }
  set padding(value) { this.addValueChange("padding", value); }

  get itemMorphs() {
    return this.submorphs.filter(ea => ea.isMenuItem);
  }

  ensureItem(item) {
    var invalid = ["invalid item", () => show("invalid item")];
    if (!item) return invalid;

    if (Array.isArray(item)) {
      var [name, exec] = item;
      if (typeof name !== "string" || typeof exec !== "function") return invalid;
      return item;
    }

    if (item.command) {
      var {command, showKeyShortcuts, target, alias, args} = item;
      if (!command || !target) return invalid;
      if (showKeyShortcuts === undefined) showKeyShortcuts = true;
      var keys = !showKeyShortcuts ?
          null :
          typeof showKeyShortcuts === "string" ?
            showKeyShortcuts :
            target.keysForCommand(command),
          descr = (alias || command) + (keys ? ` [${keys}]` : "");
      return [descr, () => target.execCommand(command, args)]
    }

    return invalid;
  }

  updateMorphs() {
    this.submorphs = [];
    var p = this.padding;
    var maxWidth = 0, pos = pt(p, p);

    if (this.title) {
      var title = this.addMorph(Text.makeLabel(this.title, {position: pos, fontSize: 16, draggable: false}));
      pos = title.bottomLeft;
      maxWidth = Math.max(title.width, maxWidth);
    }

    this.items.forEach(item => {
      var itemMorph = this.addMorph(new MenuItem({
           textString: item[0],
           action: item[1],
           props: {position: pos}
      }));
      pos = itemMorph.bottomLeft;
      maxWidth = Math.max(itemMorph.width + 6/*FIXME*/, maxWidth);
    });

    this.submorphs.forEach(ea => {
      ea.fit();
      ea.fixedWidth = true;
      ea.fixedHeight = true;
      ea.width = maxWidth;
    });

    this.extent = pt(maxWidth + 2*p, pos.y + p);
  }

}
<|endoftext|>


<commit_before>// on new PR ->
// verify pr content matches username
// merge
// on merge ->
// rewrite index.html template
// push
// new gh-pages is launched

var request = require('request');

module.exports = function(pullreq, req) {
  var prNum = pullreq.number

  request(options, callback)

  var options = {
      url: 'https://api.github.com/repos/jlord/patchwork/pulls/' + prNum,
      headers: {
          'User-Agent': 'request',
          'Authorization': 'token ' + process.env['REPOROBOT_TOKEN']
      }
  }

  function callback(error, response, body) {
    if (error) console.log(error)
      if (!error && response.statusCode == 200) {
          var info = JSON.parse(body);
      }
  }

}<commit_msg>verifying pr content and commenting<commit_after>// on new PR ->
// verify pr content matches username
// merge
// on merge ->
// rewrite index.html template
// push
// new gh-pages is launched

var request = require('request')
var asciify = require('asciify')

var time = ""
var username = ""

module.exports = function(pullreq, req) {
  var prNum = pullreq.number
  console.log('https://api.github.com/repos/jlord/patchwork/pulls/' + prNum)

  var options = {
      url: 'https://api.github.com/repos/jlord/patchwork/pulls/' + prNum,
      json: true,
      headers: {
          'User-Agent': 'request',
          'Authorization': 'token ' + process.env['REPOROBOT_TOKEN']
      }
  }

  function getTime(error, response, body) {
    if (error) console.log(error)
      if (!error && response.statusCode == 200) {
          var info = body
          time = info.created_at
          username = info.user.login
          console.log(time, username)
          getFile(prNum)
      }
  }

  request(options, getTime)

  function getFile(prNum) {
    var options = {
        url: 'https://api.github.com/repos/jlord/patchwork/pulls/' + prNum + '/files',
        json: true,
        headers: {
            'User-Agent': 'request',
            'Authorization': 'token ' + process.env['REPOROBOT_TOKEN']
        }
    }

    request(options, function returnFiles(error, response, body) {
      if (error) console.log(error)
        if (!error && response.statusCode == 200) {
            var prInfo = body[0]
            // verifyContent(prInfo.patch)
            writeComment(prNum)
        }
    })
  }
}

function verifyPRContent(prInfo) {

}

function verifFilename(filename) {
  // add /contributors/ to filename
  if (filename.match('add-' + username + '.md')) {
    return true
  }
  else console.error("Filename did not match expected pattern")
  // what should I do when the filename is incorrect, create an issue
  // or change it for the user?
  // actually - verify that in the pr challange, that way you know
  // you'll get the right one eventually
}

function verifyContent(patch) {
  // pull out the actual pr content
  var patchArray = patch.split('@@')
  var patch = patchArray.pop()
  console.log(patch)
  // generate the expected content
  asciify(username, {font:'isometric2'}, function(err, res){
    console.log(res)
    if (res.match(patch)) console.log("true")
    else console.log("no match")
  })
}

function writeComment(prNum) {
  // /repos/:owner/:repo/issues/:number/comments

  var options = {
      url: 'https://api.github.com/repos/jlord/patchwork/issues/' + prNum + '/comments',
      headers: {
          'User-Agent': 'request',
          'Authorization': 'token ' + process.env['REPOROBOT_TOKEN']
      },
      json: {'body': 'Hello internet.'}
  }

  request.post(options, function done(error, response, body) {
    if (error) console.log(error)
    // console.log(response)
  })

}<|endoftext|>


<commit_before>var routing_wire_kinds = ["sp12h", "sp12v", "sp4h", "sp4v", "fb", "glb", "iosp4"];
var routing_spanonly = ["sp12h", "sp12v", "sp4h", "sp4v", "iosp4"];

// Get a simple index to identify a span in a tile, for drawing.
// Spans on the left or top are numbered 0..47 (span4) or 0..23 (span12).
// Span4 36..47 and span12 22..23 terminate, and new wires originate at
// the right or bottom, these are indexed as 48..59 (span4) or 24..25
// (span12). This is a bit different from the name normalisation normally
// used in project icestorm.
// There are extra span4 connections towards the vertical span4 on the
// column of tiles to the right. These wires are indexed 60..107.
// For IO tiles, the connections to logic tiles have the corresponding
// indexes 0..47. The io-to-io span4s are numbered 0-19, where 0-15 are
// the wires along the top or left, and 16-19 are the wires that originate
// in the IO cell on the bottom or right.
function span_index(span_name) {
    var idx;

    if (span_name.substr(0, 8) == "sp4_h_r_" ||
	span_name.substr(0, 8) == "sp4_v_b_") {
	idx = parseInt(span_name.substr(8));
	idx = (idx < 12 ? idx + 48 : (idx ^ 1) - 12);
    } else if (span_name.substr(0, 9) == "sp12_h_r_" ||
	       span_name.substr(0, 9) == "sp12_v_b_") {
	idx = parseInt(span_name.substr(9));
	idx = (idx < 2 ? idx + 24 : (idx ^ 1) - 2);
    } else if (span_name.substr(0, 8) == "sp4_h_l_" ||
	       span_name.substr(0, 8) == "sp4_v_t_") {
	idx = parseInt(span_name.substr(8));
    } else if (span_name.substr(0, 9) == "sp12_h_l_" ||
	       span_name.substr(0, 9) == "sp12_v_t_") {
	idx = parseInt(span_name.substr(9));
    } else if (span_name.substr(0, 10) == "sp4_r_v_b_") {
	idx = parseInt(span_name.substr(10)) + 60;
	if (idx >= 60+12)
	    idx ^= 1;
    } else if (span_name.substr(0, 13) == "span4_vert_t_" ||
	      span_name.substr(0, 13) == "span4_horz_l_") {
	idx = parseInt(span_name.substr(13));
    } else if (span_name.substr(0, 13) == "span4_vert_b_" ||
	      span_name.substr(0, 13) == "span4_horz_r_") {
	idx = parseInt(span_name.substr(13));
	idx = (idx < 4 ? idx + 16 : idx - 4);
    } else if (span_name.substr(0, 11) == "span4_horz_" ||
	       span_name.substr(0, 11) == "span4_vert_") {
	idx = parseInt(span_name.substr(11));
    } else if (span_name.substr(0, 12) == "span12_horz_" ||
	       span_name.substr(0, 12) == "span12_vert_") {
	idx = parseInt(span_name.substr(12));
    } else
	throw "Unable to convert net name '" + span_name + "' to in-tile span index";

    return idx;
}

function tile_net_initdata(kind, span_name) {
    var idx = span_index(span_name);
    return { kind: kind, index: idx };
}

function process_driven_net(net, kind, tile, x, y) {
    var netdata = tile.nets[net];
    if (routing_spanonly.indexOf(kind) >= 0) {
	var netnames = chipdb.nets[net].names;
	var first_active = -1;
	var last_active = -1;
	// Find the first and last tile within the active part of the net.
	// Let's utilise that net names are listed in tile order.
	for (var i = 0; i < netnames.length; ++i) {
	    var dbnet = netnames[i];
	    var x1 = dbnet.tile_x;
	    var y1 = dbnet.tile_y;
	    var active_idx = i;
	    if (x1 == x && y1 == y) {
		if (!(net in tile.nets))
		    tile.nets[net] = tile_net_initdata(kind, dbnet.name);
		// The extra connections to the left tiles of a vertical span4
		// are special. They are all at the "end" of the span, so will
		// not be marked active just because other parts are. But the
		// part of the span to the right, if any, _will_ need to me
		// marked active.
		if (dbnet.name.substr(0, 10) == "sp4_r_v_b") {
		    active_idx = -1;
		    for (var j = i+1; j < netnames.length; ++j) {
			if (netnames[j].tile_y == y) {
			    active_idx = j;
			    x1 = netnames[j].tile_x;
			    y1 = netnames[j].tile_y;
			    break;
			}
		    }
		}
	    }
	    // If the net is active in this tile, update first/last active
	    // as appropriate.
	    if (active_idx >= 0 && (net in g_tiles[y1][x1].nets)) {
		if (first_active < 0)
		    first_active = active_idx;
		last_active = active_idx;
	    }
	}
	// Mark active any part of the span that lies between two active
	// tiles. So we can draw the parts of spans that actively route
	// signals, and omit any non-used ends.
	for (var i = first_active; i <= last_active; ++i) {
	    var dbnet = netnames[i];
	    var x1 = dbnet.tile_x;
	    var y1 = dbnet.tile_y;
	    if (!(net in g_tiles[y1][x1].nets))
		g_tiles[y1][x1].nets[net] = tile_net_initdata(kind, dbnet.name);
	}
    }
}

function asc_postprocess(chipdb, ts, asc) {
    // Set active flag.
    var active_bitidx = chipdb.ramb_tile_bits.function['RamConfig.PowerUp'][0];
    // RAMB powerup flag is active-low in 1k device.
    var active_value = (chipdb.device.device == "8k" ? 1 : 0);
    for (var y = 0; y < chipdb.device.height; ++y) {
	if (!(y in ts))
	    continue;
	var ys = ts[y];
	for (var x = 0; x < chipdb.device.width; ++x) {
	    if (!(x in ys))
		continue;
	    var t = ys[x];
	    var typ = t.typ;
	    switch (typ) {
	    case "ramb":
		var powerup = get_bit(t.config_bits, active_bitidx);
		t.active = (powerup == active_value) ? true : false;
		break;
	    case "ramt":
		// Here we use that a ramt is one higher Y index, so processed after ramb.
		t.active = ts[y-1][x].active;
		break;
	    default:
		// Inactive by default; below we will change to active if the
		// tile is actively driving, or driven by, some net.
		t.active = false;
		break;
	    }

	    // Loop over buffers, looking for active signals.
	    var bs = chipdb.tiles[y][x].buffers;
	    var asc_bits = t.config_bits;
	    for (var i = 0; i < bs.length; ++i) {
		var dst_net = bs[i].dst_net;
		var bits = bs[i].config_bits;
		var config_word = 0;
		for (var j = 0; j < bits.length; ++j)
		    config_word |= (get_bit(asc_bits, bits[j]) << j);
		var src_net = bs[i].src_nets[config_word];
		if (src_net >= 0) {
		    var src_kind = chipdb.nets[src_net].kind;
		    var dst_kind = chipdb.nets[dst_net].kind;
		    var src_is_routing = routing_wire_kinds.indexOf(src_kind) >= 0;
		    var dst_is_routing = routing_wire_kinds.indexOf(dst_kind) >= 0;

		    // A tile is deemed active if it has a buffer driving a
		    // net, and which is not solely connecting one routing net
		    // another.
		    if (!(src_is_routing && dst_is_routing))
			t.active = true;

		    // ToDo: maybe process_driven_net() for all nets?
		    if (src_is_routing)
			process_driven_net(src_net, src_kind, t, x, y);
		    if (dst_is_routing)
			process_driven_net(dst_net, dst_kind, t, x, y);
		}
	    }
	}
    }
}
<commit_msg>Include routing switches when determining active nets.<commit_after>var routing_wire_kinds = ["sp12h", "sp12v", "sp4h", "sp4v", "fb", "glb", "iosp4"];
var routing_spanonly = ["sp12h", "sp12v", "sp4h", "sp4v", "iosp4"];

// Get a simple index to identify a span in a tile, for drawing.
// Spans on the left or top are numbered 0..47 (span4) or 0..23 (span12).
// Span4 36..47 and span12 22..23 terminate, and new wires originate at
// the right or bottom, these are indexed as 48..59 (span4) or 24..25
// (span12). This is a bit different from the name normalisation normally
// used in project icestorm.
// There are extra span4 connections towards the vertical span4 on the
// column of tiles to the right. These wires are indexed 60..107.
// For IO tiles, the connections to logic tiles have the corresponding
// indexes 0..47. The io-to-io span4s are numbered 0-19, where 0-15 are
// the wires along the top or left, and 16-19 are the wires that originate
// in the IO cell on the bottom or right.
function span_index(span_name) {
    var idx;

    if (span_name.substr(0, 8) == "sp4_h_r_" ||
	span_name.substr(0, 8) == "sp4_v_b_") {
	idx = parseInt(span_name.substr(8));
	idx = (idx < 12 ? idx + 48 : (idx ^ 1) - 12);
    } else if (span_name.substr(0, 9) == "sp12_h_r_" ||
	       span_name.substr(0, 9) == "sp12_v_b_") {
	idx = parseInt(span_name.substr(9));
	idx = (idx < 2 ? idx + 24 : (idx ^ 1) - 2);
    } else if (span_name.substr(0, 8) == "sp4_h_l_" ||
	       span_name.substr(0, 8) == "sp4_v_t_") {
	idx = parseInt(span_name.substr(8));
    } else if (span_name.substr(0, 9) == "sp12_h_l_" ||
	       span_name.substr(0, 9) == "sp12_v_t_") {
	idx = parseInt(span_name.substr(9));
    } else if (span_name.substr(0, 10) == "sp4_r_v_b_") {
	idx = parseInt(span_name.substr(10)) + 60;
	if (idx >= 60+12)
	    idx ^= 1;
    } else if (span_name.substr(0, 13) == "span4_vert_t_" ||
	      span_name.substr(0, 13) == "span4_horz_l_") {
	idx = parseInt(span_name.substr(13));
    } else if (span_name.substr(0, 13) == "span4_vert_b_" ||
	      span_name.substr(0, 13) == "span4_horz_r_") {
	idx = parseInt(span_name.substr(13));
	idx = (idx < 4 ? idx + 16 : idx - 4);
    } else if (span_name.substr(0, 11) == "span4_horz_" ||
	       span_name.substr(0, 11) == "span4_vert_") {
	idx = parseInt(span_name.substr(11));
    } else if (span_name.substr(0, 12) == "span12_horz_" ||
	       span_name.substr(0, 12) == "span12_vert_") {
	idx = parseInt(span_name.substr(12));
    } else
	throw "Unable to convert net name '" + span_name + "' to in-tile span index";

    return idx;
}

function tile_net_initdata(kind, span_name) {
    var idx = span_index(span_name);
    return { kind: kind, index: idx };
}

// Given a net that is driven in a tile, mark that tile's part of the net
// active, by inserting an entry in g_tiles[y][x].nets[net].
// In addition, traverse all tiles covered by the net, and similarly mark
// active any parts on tiles that connect two active parts.
function process_driven_net(net, kind, tile, x, y) {
    var netdata = tile.nets[net];
    if (routing_spanonly.indexOf(kind) >= 0) {
	var netnames = chipdb.nets[net].names;

	var first_active = -1;
	var last_active = -1;
	var first_active_r_v = -1;
	var last_active_r_v = -1;
	// Find the first and last tile within the active part of the net.
	// Let's utilise that net names are listed in tile order.
	for (var i = 0; i < netnames.length; ++i) {
	    var dbnet = netnames[i];
	    var x1 = dbnet.tile_x;
	    var y1 = dbnet.tile_y;
	    // Mark the net active in the tile in which it is driven.
	    if (x1 == x && y1 == y && !(net in tile.nets))
		tile.nets[net] = tile_net_initdata(kind, dbnet.name);

	    // If the net is active in this tile, update first/last active
	    // as appropriate.
	    if (net in g_tiles[y1][x1].nets) {
		// The extra connections to the left tiles of a vertical span4
		// are special. They are all at the "end" of the span, so will
		// not be marked active just because other parts are. But the
		// part of the span to the right, if any, _will_ need to me
		// marked active.
		if (dbnet.name.substr(0, 10) == "sp4_r_v_b_") {
		    for (var j = i+1; j < netnames.length; ++j) {
			if (netnames[j].tile_y == y) {
			    if (first_active_r_v < 0)
				first_active_r_v = j;
			    last_active_r_v = j;
			    break;
			}
		    }
		} else {
		    if (first_active < 0)
			first_active = i;
		    last_active = i;
		}
	    }
	}

	if (first_active_r_v >= 0 &&
	    (first_active >= 0 || last_active_r_v > first_active_r_v)) {
	    if (first_active < 0 || first_active_r_v < first_active)
		first_active = first_active_r_v;
	    if (last_active < 0 || last_active_r_v > last_active)
		last_active = last_active_r_v;
	}

	// Mark active any part of the span that lies between two active
	// tiles. So we can draw the parts of spans that actively route
	// signals, and omit any non-used ends.
	if (first_active >= 0) {
	    for (var i = first_active; i <= last_active; ++i) {
		var dbnet = netnames[i];
		var x1 = dbnet.tile_x;
		var y1 = dbnet.tile_y;
		if (!(net in g_tiles[y1][x1].nets))
		    g_tiles[y1][x1].nets[net] = tile_net_initdata(kind, dbnet.name);
	    }
	}
    }
}

function check_buffer_routing_driving(bs, asc_bits, t, x, y) {
    for (var i = 0; i < bs.length; ++i) {
	var dst_net = bs[i].dst_net;
	var bits = bs[i].config_bits;
	var config_word = 0;
	for (var j = 0; j < bits.length; ++j)
	    config_word |= (get_bit(asc_bits, bits[j]) << j);
	var src_net = bs[i].src_nets[config_word];
	if (src_net >= 0) {
	    var src_kind = chipdb.nets[src_net].kind;
	    var dst_kind = chipdb.nets[dst_net].kind;
	    var src_is_routing = routing_wire_kinds.indexOf(src_kind) >= 0;
	    var dst_is_routing = routing_wire_kinds.indexOf(dst_kind) >= 0;

	    // A tile is deemed active if it has a buffer driving a
	    // net, and which is not solely connecting one routing net
	    // another.
	    if (!(src_is_routing && dst_is_routing))
		t.active = true;

	    // ToDo: maybe process_driven_net() for all nets?
	    if (src_is_routing)
		process_driven_net(src_net, src_kind, t, x, y);
	    if (dst_is_routing)
		process_driven_net(dst_net, dst_kind, t, x, y);
	}
    }
}

function asc_postprocess(chipdb, ts, asc) {
    // Set active flag.
    var active_bitidx = chipdb.ramb_tile_bits.function['RamConfig.PowerUp'][0];
    // RAMB powerup flag is active-low in 1k device.
    var active_value = (chipdb.device.device == "8k" ? 1 : 0);
    for (var y = 0; y < chipdb.device.height; ++y) {
	if (!(y in ts))
	    continue;
	var ys = ts[y];
	for (var x = 0; x < chipdb.device.width; ++x) {
	    if (!(x in ys))
		continue;
	    var t = ys[x];
	    var typ = t.typ;
	    switch (typ) {
	    case "ramb":
		var powerup = get_bit(t.config_bits, active_bitidx);
		t.active = (powerup == active_value) ? true : false;
		break;
	    case "ramt":
		// Here we use that a ramt is one higher Y index, so processed after ramb.
		t.active = ts[y-1][x].active;
		break;
	    default:
		// Inactive by default; below we will change to active if the
		// tile is actively driving, or driven by, some net.
		t.active = false;
		break;
	    }

	    // Loop over buffers and routings, looking for active signals.
	    check_buffer_routing_driving(chipdb.tiles[y][x].buffers,
					 t.config_bits, t, x, y);
	    check_buffer_routing_driving(chipdb.tiles[y][x].routings,
					 t.config_bits, t, x, y);
	}
    }
}
<|endoftext|>


<commit_before>#!/usr/bin/env node
const { cli } = require('../../lib/index')
const cliScript = cli(process.argv, {
  description: 'Basic script description',
  params: ['p1', 'p2'],
  options: {
    a: 'description for a option',
    foo: 'description for foo option'
  },
  examples: 'some examples'
})

cliScript((options, p1, p2) => {
  console.log('OPTIONS', options)
  console.log('P1', p1)
  console.log('P2', p2)
})
<commit_msg>Update sandbox simple script<commit_after>#!/usr/bin/env node
const { cli, help } = require('../../lib/index')

help(main, {
  description: 'Basic script description',
  params: ['p1', 'p2'],
  options: {
    a: 'description for a option',
    foo: 'description for foo option'
  },
  examples: 'some examples'
})

function main (options, p1, p2) {
  console.log('OPTIONS', options)
  console.log('P1', p1)
  console.log('P2', p2)
}

cli({
  default: main
})
<|endoftext|>


<commit_before>feelings = new Mongo.Collection( "feelings" );

if (Meteor.isClient) {

  Tracker.autorun( function() { document.title = i18n( "appName" ); } );

  configInternationalization();

  var maxNumberOfContainers = 7;
  var backgroundPhotos = []

  function now() { return +(new Date()); }
  function rand() { return Math.round( Math.random() * 1000000 ); }

  Session.set( "Images", [] );
  Session.setDefault( "WordList", [] );

  Template.AddWordT.events( {
    'submit form' : function( evt, template ) {
      evt.preventDefault();

      var wordList = Session.get( "WordList" );
      var newWords = template.find(".search-query").value.split(/\s+/);
      _.each( newWords, function( newWord ) {
        var word = newWord.replace(",", "").trim();
        if( wordList.length < maxNumberOfContainers ) {
          if( _.contains( wordList, word.toLowerCase() ) == false ) {
            wordList.push( word.toLowerCase() );
            Session.set( "WordList", wordList );
          }
        }
      } );
    }
  } );

  function buildPlot() {

    d3.select("#demo").selectAll("#vs").remove();
    d3.select("#demo").append("div").attr("id", "vs");

    var modelArray = [];
    var strataArray = [];
    var list = [];

    for(var i = 0; i < maxNumberOfContainers; ++i) {
      list.push( { label : "" } );
    }

    _.each( list, function( word ) {
      strataArray.push( [ { initValue : 10 } ] );
    } );

    var divWidth = parseInt( d3.select("#plotDiv").style('width') ) - 30;
    var viewportWidth = divWidth;
    var chartX = 10;
    var chartY = 50;
    var chartWidth = viewportWidth - 2 * chartX;
    var settings = {
      width  : viewportWidth,
      height : 300,
      data:{
            model: list,
            strata: strataArray,
            stream:{
              provider:'none',
              refresh: 10000,
              now : 0
            },
          },
      sedimentation:{
        token:{
          size:{original:20,minimum:3}
        },
        aggregation:{height:180},
        suspension:{
          decay: { power : 1.005 }
        }
      },
      options:{
        layout:false
      },
      chart:{
        x: chartX,
        y: chartY,
        height : 280,
        width : chartWidth,
        type : "StackedAreaChart",
        wallColor : "rgba(230,230,230,0.5)",
        label : true,
        spacer : 1,
      }
    };

    scene = $("#vs").vs(settings).data('visualSedimentation');

  }

  Template.VisualSedimentationT.rendered = function() {
    buildPlot();

    Tracker.autorun( function() {
      observeData();
      updateLegend();
    } );
  };

  var backgroundHandler;
  function restartBackgroundLoop() {

    if( _.isUndefined( backgroundHandler ) == false ) {
      clearInterval( backgroundHandler );
    }

    backgroundHandler = setInterval( function() {

      if( _.isEmpty( backgroundPhotos ) ) {
        return;
      }

      backgroundPhotos = _.shuffle( backgroundPhotos );
      Session.set( "Image", backgroundPhotos.pop() );

    }, 20000 );
  }
  restartBackgroundLoop();

  setInterval( function() {
    var array = myPop();
    _.each(array, function( p ) {
      setTimeout( function() { scene.addToken( p ); }, rand() % 5000 );
    } );
  }, 5000 );

  function observeData() {
    var wordList = Session.get( "WordList" );
    Meteor.subscribe( "feelings", wordList, function() {
      feelings.find({}).observeChanges( {
        added : function( id, tweet ) {

          //
          // Twitter API appends RT @screen_name to retweets.
          // We want to ignore those as they are repeated over
          // and over as background
          //
          if( _.isUndefined( tweet.retweeted_status ) == false ) {
            return;
          }

          obj = buildBackgroundObject( tweet );
          if( _.isEqual( obj.type, "photo" ) == true &&
              backgroundPhotos.length < 1000 ) {
              backgroundPhotos.push( obj )  ;
          }

          var wordList = Session.get( "WordList" )
          var text = tweet.text.toLowerCase();
          _.each( wordList, function( word, idx ) {
            if( text.indexOf( word ) != -1 ) {
              myEnqueue( {
                tweet : tweet,
                size : 60 / maxNumberOfContainers,
                category : idx,
                callback : {
                  onclick : function( token ) {
                    var obj = buildBackgroundObject( token.myobj.m_userData.tweet );
                    Session.set( "Image", obj );
                    restartBackgroundLoop();
                  },
                  mouseover : function( token ) {
                  }
                }
              } );
            }
          } );
        }
      } ) ;
    } );
  }

  function updateLegend() {

    d3.select("svg").select("#legend").remove();

    var wordList = Session.get( "WordList" );
    var textNode = d3.select("svg").append("g").attr("id", "legend");
    var textXDelta = settings.chart.width / maxNumberOfContainers;
    var textX = settings.chart.x + textXDelta * 0.5;
    var textYA = settings.chart.y - 30;
    var textYB = settings.chart.y - 10;

    _.each( wordList, function( word, idx ) {
      textNode
        .append("g")
        .append("text")
        .attr( "font-size", 20)
        .attr( "font-family", "HelveticaNeue-Light")
        .attr( "font-weight", 300)
        .attr( "fill", "white")
        .attr( "text-anchor", "middle")
        .attr( "pointer-events", "all")
        .attr( "cursor", "pointer")
        .text( word )
        .on("click", function( d ) {
          var w = d3.select(this).text().toLowerCase();
          var wordList = Session.get( "WordList" );
          wordList = _.filter( wordList, function( word ) {
            return _.isEqual( word, w ) == false;
          } );
          Session.set( "WordList", wordList );
        } )
        .attr("transform", function() {
          if( idx % 2 == 0 ) {
            return "translate(" + textX + "," + textYA + ")"
          }
          return "translate(" + textX + "," + textYB + ")"
        });
      textX += textXDelta;
    } );
  }

}

if (Meteor.isServer) {
  Meteor.startup(function () {
    termsCollection = new Mongo.Collection( "commonTerms" );

    Meteor.publish( "feelings", function( words ) {

      var list = "";
      _.each( words, function( word ) {
        var query = {};
        var modfiers = {};
        var increment = {};
        query[ word ] = { $exists : true } ;

        var cursor = termsCollection.find( query );
        if( cursor.count() == 0 ) {
          var term = {};
          term[ word ] = 1;
          termsCollection.insert( term );
        } else {
          var array = cursor.fetch();
          increment[ word ] = +1;
          modfiers[ "$inc" ] = increment;
          termsCollection.update( { _id : array[ 0 ]._id }, modfiers );
        }

        list += word + " ";
      } );

      var query = {  $text : { $search : list }  };
      var options = {
        fields : {
          id_str : 1,
          text : 1,
          created_at : 1,
          "entities.media" : 1,
          "user.id_str" : 1,
          "user.profile_image_url_https" : 1,
          "retweeted_status.id_str" : 1
        }
      };
      return feelings.find( query, options );
    } );
  });
}
<commit_msg>Added screen_name<commit_after>feelings = new Mongo.Collection( "feelings" );

if (Meteor.isClient) {

  Tracker.autorun( function() { document.title = i18n( "appName" ); } );

  configInternationalization();

  var maxNumberOfContainers = 7;
  var backgroundPhotos = []

  function now() { return +(new Date()); }
  function rand() { return Math.round( Math.random() * 1000000 ); }

  Session.set( "Images", [] );
  Session.setDefault( "WordList", [] );

  Template.AddWordT.events( {
    'submit form' : function( evt, template ) {
      evt.preventDefault();

      var wordList = Session.get( "WordList" );
      var newWords = template.find(".search-query").value.split(/\s+/);
      _.each( newWords, function( newWord ) {
        var word = newWord.replace(",", "").trim();
        if( wordList.length < maxNumberOfContainers ) {
          if( _.contains( wordList, word.toLowerCase() ) == false ) {
            wordList.push( word.toLowerCase() );
            Session.set( "WordList", wordList );
          }
        }
      } );
    }
  } );

  function buildPlot() {

    d3.select("#demo").selectAll("#vs").remove();
    d3.select("#demo").append("div").attr("id", "vs");

    var modelArray = [];
    var strataArray = [];
    var list = [];

    for(var i = 0; i < maxNumberOfContainers; ++i) {
      list.push( { label : "" } );
    }

    _.each( list, function( word ) {
      strataArray.push( [ { initValue : 10 } ] );
    } );

    var divWidth = parseInt( d3.select("#plotDiv").style('width') ) - 30;
    var viewportWidth = divWidth;
    var chartX = 10;
    var chartY = 50;
    var chartWidth = viewportWidth - 2 * chartX;
    var settings = {
      width  : viewportWidth,
      height : 300,
      data:{
            model: list,
            strata: strataArray,
            stream:{
              provider:'none',
              refresh: 10000,
              now : 0
            },
          },
      sedimentation:{
        token:{
          size:{original:20,minimum:3}
        },
        aggregation:{height:180},
        suspension:{
          decay: { power : 1.005 }
        }
      },
      options:{
        layout:false
      },
      chart:{
        x: chartX,
        y: chartY,
        height : 280,
        width : chartWidth,
        type : "StackedAreaChart",
        wallColor : "rgba(230,230,230,0.5)",
        label : true,
        spacer : 1,
      }
    };

    scene = $("#vs").vs(settings).data('visualSedimentation');

  }

  Template.VisualSedimentationT.rendered = function() {
    buildPlot();

    Tracker.autorun( function() {
      observeData();
      updateLegend();
    } );
  };

  var backgroundHandler;
  function restartBackgroundLoop() {

    if( _.isUndefined( backgroundHandler ) == false ) {
      clearInterval( backgroundHandler );
    }

    backgroundHandler = setInterval( function() {

      if( _.isEmpty( backgroundPhotos ) ) {
        return;
      }

      backgroundPhotos = _.shuffle( backgroundPhotos );
      Session.set( "Image", backgroundPhotos.pop() );

    }, 20000 );
  }
  restartBackgroundLoop();

  setInterval( function() {
    var array = myPop();
    _.each(array, function( p ) {
      setTimeout( function() { scene.addToken( p ); }, rand() % 5000 );
    } );
  }, 5000 );

  function observeData() {
    var wordList = Session.get( "WordList" );
    Meteor.subscribe( "feelings", wordList, function() {
      feelings.find({}).observeChanges( {
        added : function( id, tweet ) {

          //
          // Twitter API appends RT @screen_name to retweets.
          // We want to ignore those as they are repeated over
          // and over as background
          //
          if( _.isUndefined( tweet.retweeted_status ) == false ) {
            return;
          }

          obj = buildBackgroundObject( tweet );
          if( _.isEqual( obj.type, "photo" ) == true &&
              backgroundPhotos.length < 1000 ) {
              backgroundPhotos.push( obj )  ;
          }

          var wordList = Session.get( "WordList" )
          var text = tweet.text.toLowerCase();
          _.each( wordList, function( word, idx ) {
            if( text.indexOf( word ) != -1 ) {
              myEnqueue( {
                tweet : tweet,
                size : 60 / maxNumberOfContainers,
                category : idx,
                callback : {
                  onclick : function( token ) {
                    var obj = buildBackgroundObject( token.myobj.m_userData.tweet );
                    Session.set( "Image", obj );
                    restartBackgroundLoop();
                  },
                  mouseover : function( token ) {
                  }
                }
              } );
            }
          } );
        }
      } ) ;
    } );
  }

  function updateLegend() {

    d3.select("svg").select("#legend").remove();

    var wordList = Session.get( "WordList" );
    var textNode = d3.select("svg").append("g").attr("id", "legend");
    var textXDelta = settings.chart.width / maxNumberOfContainers;
    var textX = settings.chart.x + textXDelta * 0.5;
    var textYA = settings.chart.y - 30;
    var textYB = settings.chart.y - 10;

    _.each( wordList, function( word, idx ) {
      textNode
        .append("g")
        .append("text")
        .attr( "font-size", 20)
        .attr( "font-family", "HelveticaNeue-Light")
        .attr( "font-weight", 300)
        .attr( "fill", "white")
        .attr( "text-anchor", "middle")
        .attr( "pointer-events", "all")
        .attr( "cursor", "pointer")
        .text( word )
        .on("click", function( d ) {
          var w = d3.select(this).text().toLowerCase();
          var wordList = Session.get( "WordList" );
          wordList = _.filter( wordList, function( word ) {
            return _.isEqual( word, w ) == false;
          } );
          Session.set( "WordList", wordList );
        } )
        .attr("transform", function() {
          if( idx % 2 == 0 ) {
            return "translate(" + textX + "," + textYA + ")"
          }
          return "translate(" + textX + "," + textYB + ")"
        });
      textX += textXDelta;
    } );
  }

}

if (Meteor.isServer) {
  Meteor.startup(function () {
    termsCollection = new Mongo.Collection( "commonTerms" );

    Meteor.publish( "feelings", function( words ) {

      var list = "";
      _.each( words, function( word ) {
        var query = {};
        var modfiers = {};
        var increment = {};
        query[ word ] = { $exists : true } ;

        var cursor = termsCollection.find( query );
        if( cursor.count() == 0 ) {
          var term = {};
          term[ word ] = 1;
          termsCollection.insert( term );
        } else {
          var array = cursor.fetch();
          increment[ word ] = +1;
          modfiers[ "$inc" ] = increment;
          termsCollection.update( { _id : array[ 0 ]._id }, modfiers );
        }

        list += word + " ";
      } );

      var query = {  $text : { $search : list }  };
      var options = {
        fields : {
          id_str : 1,
          text : 1,
          created_at : 1,
          "entities.media" : 1,
          "user.id_str" : 1,
          "user.screen_name" : 1
          "user.profile_image_url_https" : 1,
          "retweeted_status.id_str" : 1
        }
      };
      return feelings.find( query, options );
    } );
  });
}
<|endoftext|>


<commit_before>// https://stackoverflow.com/a/25359264
$.urlParam = function(name){
    var results = new RegExp('[\?&]' + name + '=([^&#]*)').exec(window.location.href);
    if (results==null) {
        return null;
    }
    return decodeURI(results[1]) || 0;
}

function get_node_color_for_jira_status(jira_status) {
    switch (jira_status) {
        case null          : return "grey";
        case "In Progress" : return "yellow";
        case "Resolved"    : return "DeepSkyBlue";
        case "Closed"      : return "grey";
        default            : return "white";        // Reported, Reopened
    }
}

var digraph;

function process_tickets(json) {
    var n_tickets = json.issues.length;
    //console.log(n_tickets);
    if (n_tickets == 0) {
        $('#progress').text("No tickets found !");
        return;
    }
    for(var i =0; i<n_tickets; i++) {
        var ticket = json.issues[i];
        var labels = ticket.fields.labels.filter(function (el) {
            return el.startsWith("Graph:");
        });
        if (labels.length == 0) {
            continue;
        }
        // Assume there is just 1 Graph label
        var label = labels[0].replace("Graph:", "").replace(/_/g, " ");

        var index = label.indexOf(":");
        if (index == -1) {
            pipeline_name = label.trim();
            run_name = ticket.fields.customfield_11130.value;
        } else {
            pipeline_name = label.substr(0, index).trim();
            run_name = label.substr(index+1).trim();
        }
        var matches;
        if (matches = ticket.fields.summary.match(/ batch \d+/)) {
            run_name += matches[0];
        }
        if (!(pipeline_name in pipelines)) {
            alert("Cannot find " + pipeline_name + " in the graph");
            continue;
        }

        var status_name = ticket.fields.status.name;
        var colour = get_node_color_for_jira_status(status_name);
        //console.log(pipeline_name, run_name, status_name, colour);
        pipelines[pipeline_name].push( [run_name,colour] );
    }

    for(pipeline_name in pipelines) {
        var runs = pipelines[pipeline_name];
        //console.log(runs);
        if (runs.length == 0) {
            continue;
        }
        var table_desc = '
';
        table_desc += '
' + pipeline_name + '

';
        var seen_colours = {};
        for(var i=0; i<runs.length; i++) {
            table_desc += '
' + runs[i][0] + '
';
            seen_colours[runs[i][1]] = 1;
        }
        table_desc += '
';
        var seen_colours_array = Object.keys(seen_colours);
        var background_colour = seen_colours_array.length == 1 ? seen_colours_array[0] : 'white';
        var node_desc = "\"" + pipeline_name + '" [fillcolor="' + background_colour + '", label=<' + table_desc + '>, shape="box", style="rounded,filled"];';
        //console.log(pipeline_name, node_desc);
        digraph += node_desc + "\n";
    }
    digraph += '}';
    //console.log("groups", pipelines);
    //console.log("digraph final");
    //console.log(digraph);
    d3.select("#graph").graphviz()
        .fade(false)
        .renderDot(digraph);
    $('#progressbar').fadeOut("normal", function() {
        $(this).remove();
    });
}

// fetch ticket status from REST API
var endpoint_ticket_list = 'https://www.ebi.ac.uk/panda/jira/rest/api/2/search/?jql=project=ENSCOMPARASW+AND+fixVersion="Release+__RELEASE__"+AND+component+IN+("Relco+tasks","Production+tasks")+AND+labels+IS+NOT+EMPTY+ORDER+BY+created+ASC,id+ASC';
var release = $.urlParam("release");
var pipelines = {};
$('#progress').text("Loading e" + release + " graph");
$.ajax({
    type: "GET",
    url: "compara_merged." + release + ".dot",
    dataType: "text",
    success: function(loaded_digraph) {
        //console.log("digraph:", loaded_digraph);
        digraph = loaded_digraph.replace(/\}\s?$/g, '');
        // All the strings are considered potential pipeline names
        var all_pipeline_names = digraph.match(/"[a-zA-Z][^"]*"/g);
        for(var j = 0; j < all_pipeline_names.length; j++){
            var this_name = all_pipeline_names[j].substr(1, all_pipeline_names[j].length-2)
            pipelines[this_name] = [];
        }
        //console.log(all_pipeline_names);
        $('#progress').text("Loading all e" + release + " tickets");
        $.ajax({
            type: "GET",
            url: endpoint_ticket_list.replace('__RELEASE__', release),
            success: process_tickets,
            error: function(jqXHR, status, error) {
                $('#progress').text("Error: " + error);
            },
        });
    }
});

<commit_msg>Show the error messages<commit_after>// https://stackoverflow.com/a/25359264
$.urlParam = function(name){
    var results = new RegExp('[\?&]' + name + '=([^&#]*)').exec(window.location.href);
    if (results==null) {
        return null;
    }
    return decodeURI(results[1]) || 0;
}

function get_node_color_for_jira_status(jira_status) {
    switch (jira_status) {
        case null          : return "grey";
        case "In Progress" : return "yellow";
        case "Resolved"    : return "DeepSkyBlue";
        case "Closed"      : return "grey";
        default            : return "white";        // Reported, Reopened
    }
}

var digraph;

function process_tickets(json) {
    var n_tickets = json.issues.length;
    //console.log(n_tickets);
    if (n_tickets == 0) {
        $('#progress').text("No tickets found !");
    }
    for(var i =0; i<n_tickets; i++) {
        var ticket = json.issues[i];
        var labels = ticket.fields.labels.filter(function (el) {
            return el.startsWith("Graph:");
        });
        if (labels.length == 0) {
            continue;
        }
        // Assume there is just 1 Graph label
        var label = labels[0].replace("Graph:", "").replace(/_/g, " ");

        var index = label.indexOf(":");
        if (index == -1) {
            pipeline_name = label.trim();
            run_name = ticket.fields.customfield_11130.value;
        } else {
            pipeline_name = label.substr(0, index).trim();
            run_name = label.substr(index+1).trim();
        }
        var matches;
        if (matches = ticket.fields.summary.match(/ batch \d+/)) {
            run_name += matches[0];
        }
        if (!(pipeline_name in pipelines)) {
            alert("Cannot find " + pipeline_name + " in the graph");
            continue;
        }

        var status_name = ticket.fields.status.name;
        var colour = get_node_color_for_jira_status(status_name);
        //console.log(pipeline_name, run_name, status_name, colour);
        pipelines[pipeline_name].push( [run_name,colour] );
    }

    for(pipeline_name in pipelines) {
        var runs = pipelines[pipeline_name];
        //console.log(runs);
        if (runs.length == 0) {
            continue;
        }
        var table_desc = '
';
        table_desc += '
' + pipeline_name + '

';
        var seen_colours = {};
        for(var i=0; i<runs.length; i++) {
            table_desc += '
' + runs[i][0] + '
';
            seen_colours[runs[i][1]] = 1;
        }
        table_desc += '
';
        var seen_colours_array = Object.keys(seen_colours);
        var background_colour = seen_colours_array.length == 1 ? seen_colours_array[0] : 'white';
        var node_desc = "\"" + pipeline_name + '" [fillcolor="' + background_colour + '", label=<' + table_desc + '>, shape="box", style="rounded,filled"];';
        //console.log(pipeline_name, node_desc);
        digraph += node_desc + "\n";
    }
    digraph += '}';
    //console.log("groups", pipelines);
    //console.log("digraph final");
    //console.log(digraph);
    d3.select("#graph").graphviz()
        .fade(false)
        .renderDot(digraph);
    if (n_tickets) {
        $('#progressbar').fadeOut("normal", function() {
            $(this).remove();
        });
    }
}

// fetch ticket status from REST API
var endpoint_ticket_list = 'https://www.ebi.ac.uk/panda/jira/rest/api/2/search/?jql=project=ENSCOMPARASW+AND+fixVersion="Release+__RELEASE__"+AND+component+IN+("Relco+tasks","Production+tasks")+AND+labels+IS+NOT+EMPTY+ORDER+BY+created+ASC,id+ASC';
var release = $.urlParam("release");
var pipelines = {};
$('#progress').text("Loading e" + release + " graph");
$.ajax({
    type: "GET",
    url: "compara_merged." + release + ".dot",
    dataType: "text",
    success: function(loaded_digraph) {
        //console.log("digraph:", loaded_digraph);
        digraph = loaded_digraph.replace(/\}\s?$/g, '');
        // All the strings are considered potential pipeline names
        var all_pipeline_names = digraph.match(/"[a-zA-Z][^"]*"/g);
        for(var j = 0; j < all_pipeline_names.length; j++){
            var this_name = all_pipeline_names[j].substr(1, all_pipeline_names[j].length-2)
            pipelines[this_name] = [];
        }
        //console.log(all_pipeline_names);
        $('#progress').text("Loading all e" + release + " tickets");
        $.ajax({
            type: "GET",
            url: endpoint_ticket_list.replace('__RELEASE__', release),
            success: process_tickets,
            error: function(jqXHR, status, error) {
                $('#progress').text("Error fetching the " + release + "tickets: " + error);
            },
        });
    },
    error: function(jqXHR, status, error) {
        $('#progress').text("Error fetching the " + release + ".dot file: " + error);
    }
});

<|endoftext|>


<commit_before>function WalkontableScrollbar() {
}

WalkontableScrollbar.prototype.init = function () {
  var that = this;

  //reference to instance
  this.$table = $(this.instance.wtTable.TABLE);

  //create elements
  this.slider = document.createElement('DIV');
  this.sliderStyle = this.slider.style;
  this.sliderStyle.position = 'absolute';
  this.sliderStyle.top = '0';
  this.sliderStyle.left = '0';
  this.sliderStyle.display = 'none';
  this.slider.className = 'dragdealer ' + this.type;

  this.handle = document.createElement('DIV');
  this.handleStyle = this.handle.style;
  this.handle.className = 'handle';

  this.slider.appendChild(this.handle);
  this.instance.wtTable.parent.appendChild(this.slider);

  var firstRun = true;
  this.dragTimeout = null;
  var dragDelta;
  var dragRender = function () {
    that.onScroll(dragDelta);
  };

  this.dragdealer = new Dragdealer(this.slider, {
    vertical: (this.type === 'vertical'),
    horizontal: (this.type === 'horizontal'),
    slide: false,
    speed: 100,
    animationCallback: function (x, y) {
      if (firstRun) {
        firstRun = false;
        return;
      }
      that.skipRefresh = true;
      dragDelta = that.type === 'vertical' ? y : x;
      if (that.dragTimeout === null) {
        that.dragTimeout = setInterval(dragRender, 100);
        dragRender();
      }
    },
    callback: function (x, y) {
      that.skipRefresh = false;
      clearInterval(that.dragTimeout);
      that.dragTimeout = null;
      dragDelta = that.type === 'vertical' ? y : x;
      that.onScroll(dragDelta);
    }
  });
  this.skipRefresh = false;
};

WalkontableScrollbar.prototype.onScroll = function (delta) {
  if (this.instance.drawn) {
    this.readSettings();
    if (this.total > this.visibleCount) {
      var newOffset = Math.round(this.handlePosition * this.total / this.sliderSize);

      if (delta === 1) {
        if (this.type === 'vertical') {
          this.instance.scrollVertical(Infinity).draw();
        }
        else {
          console.log("infiniti");
          this.instance.scrollHorizontal(Infinity).draw();
        }
      }
      else if (newOffset !== this.offset) { //is new offset different than old offset
        if (this.type === 'vertical') {
          this.instance.scrollVertical(newOffset - this.offset).draw();
        }
        else {
          this.instance.scrollHorizontal(newOffset - this.offset).draw();
        }
      }
      else {
        this.refresh();
      }
    }
  }
};

/**
 * Returns what part of the scroller should the handle take
 * @param viewportCount {Number} number of visible rows or columns
 * @param totalCount {Number} total number of rows or columns
 * @return {Number} 0..1
 */
WalkontableScrollbar.prototype.getHandleSizeRatio = function (viewportCount, totalCount) {
  if (!totalCount || viewportCount > totalCount) {
    return 1;
  }
  return viewportCount / totalCount;
};

WalkontableScrollbar.prototype.prepare = function () {
  if (this.skipRefresh) {
    return;
  }
  var ratio = this.getHandleSizeRatio(this.visibleCount, this.total);
  if (((ratio === 1 || isNaN(ratio)) && this.scrollMode === 'auto') || this.scrollMode === 'none') {
    //isNaN is needed because ratio equals NaN when totalRows/totalColumns equals 0
    this.visible = false;
  }
  else {
    this.visible = true;
  }
};

WalkontableScrollbar.prototype.refresh = function () {
  if (this.skipRefresh) {
    return;
  }
  else if (!this.visible) {
    this.sliderStyle.display = 'none';
    return;
  }

  var ratio
    , sliderSize
    , handleSize
    , handlePosition
    , visibleCount = this.visibleCount
    , tableOuterWidth = this.$table.outerWidth()
    , tableOuterHeight = this.$table.outerHeight()
    , tableWidth = this.instance.hasSetting('width') ? this.instance.getSetting('width') : tableOuterWidth
    , tableHeight = this.instance.hasSetting('height') ? this.instance.getSetting('height') : tableOuterHeight;

  if (!tableWidth) {
    //throw new Error("I could not compute table width. Is the <table> element attached to the DOM?");
    return;
  }
  if (!tableHeight) {
    //throw new Error("I could not compute table height. Is the <table> element attached to the DOM?");
    return;
  }

  if (this.instance.hasSetting('width') && this.instance.wtScroll.wtScrollbarV.visible) {
    tableWidth -= this.instance.getSetting('scrollbarWidth');
  }
  if (tableWidth > tableOuterWidth + this.instance.getSetting('scrollbarWidth')) {
    tableWidth = tableOuterWidth;
  }

  if (this.instance.hasSetting('height') && this.instance.wtScroll.wtScrollbarH.visible) {
    tableHeight -= this.instance.getSetting('scrollbarHeight');
  }
  if (tableHeight > tableOuterHeight + this.instance.getSetting('scrollbarHeight')) {
    tableHeight = tableOuterHeight;
  }

  if (this.type === 'vertical') {
    if (this.instance.wtTable.isLastRowIncomplete()) {
      visibleCount--;
    }

    sliderSize = tableHeight - 2; //2 is sliders border-width

    this.sliderStyle.top = this.$table.position().top + 'px';
    this.sliderStyle.left = tableWidth - 1 + 'px'; //1 is sliders border-width
    this.sliderStyle.height = sliderSize + 'px';
  }
  else { //horizontal
    if (this.instance.wtTable.isLastColumnIncomplete()) {
      visibleCount--;
    }

    sliderSize = tableWidth - 2; //2 is sliders border-width

    this.sliderStyle.left = this.$table.position().left + 'px';
    this.sliderStyle.top = tableHeight - 1 + 'px'; //1 is sliders border-width
    this.sliderStyle.width = sliderSize + 'px';
  }

  ratio = this.getHandleSizeRatio(visibleCount, this.total);
  handleSize = Math.round(sliderSize * ratio);
  if (handleSize < 10) {
    handleSize = 15;
  }

  handlePosition = Math.floor(sliderSize * (this.offset / this.total));
  if (handleSize + handlePosition > sliderSize) {
    handlePosition = sliderSize - handleSize;
  }

  if (this.type === 'vertical') {
    this.handleStyle.height = handleSize + 'px';
    this.handleStyle.top = handlePosition + 'px';

  }
  else { //horizontal
    this.handleStyle.width = handleSize + 'px';
    this.handleStyle.left = handlePosition + 'px';
  }

  this.sliderStyle.display = 'block';
};

///

var WalkontableVerticalScrollbar = function (instance) {
  this.instance = instance;
  this.type = 'vertical';
  this.init();
};

WalkontableVerticalScrollbar.prototype = new WalkontableScrollbar();

WalkontableVerticalScrollbar.prototype.readSettings = function () {
  this.scrollMode = this.instance.getSetting('scrollV');
  this.offset = this.instance.getSetting('offsetRow');
  this.total = this.instance.getSetting('totalRows');
  this.visibleCount = this.instance.wtTable.countVisibleRows();
  this.handlePosition = parseInt(this.handleStyle.top, 10);
  this.sliderSize = parseInt(this.sliderStyle.height, 10);
  this.fixedCount = this.instance.getSetting('fixedRowsTop');
};

///

var WalkontableHorizontalScrollbar = function (instance) {
  this.instance = instance;
  this.type = 'horizontal';
  this.init();
};

WalkontableHorizontalScrollbar.prototype = new WalkontableScrollbar();

WalkontableHorizontalScrollbar.prototype.readSettings = function () {
  this.scrollMode = this.instance.getSetting('scrollH');
  this.offset = this.instance.getSetting('offsetColumn');
  this.total = this.instance.getSetting('totalColumns');
  this.visibleCount = this.instance.wtTable.countVisibleColumns();
  this.handlePosition = parseInt(this.handleStyle.left, 10);
  this.sliderSize = parseInt(this.sliderStyle.width, 10);
  this.fixedCount = this.instance.getSetting('fixedColumnsLeft');
};<commit_msg>remove console.log<commit_after>function WalkontableScrollbar() {
}

WalkontableScrollbar.prototype.init = function () {
  var that = this;

  //reference to instance
  this.$table = $(this.instance.wtTable.TABLE);

  //create elements
  this.slider = document.createElement('DIV');
  this.sliderStyle = this.slider.style;
  this.sliderStyle.position = 'absolute';
  this.sliderStyle.top = '0';
  this.sliderStyle.left = '0';
  this.sliderStyle.display = 'none';
  this.slider.className = 'dragdealer ' + this.type;

  this.handle = document.createElement('DIV');
  this.handleStyle = this.handle.style;
  this.handle.className = 'handle';

  this.slider.appendChild(this.handle);
  this.instance.wtTable.parent.appendChild(this.slider);

  var firstRun = true;
  this.dragTimeout = null;
  var dragDelta;
  var dragRender = function () {
    that.onScroll(dragDelta);
  };

  this.dragdealer = new Dragdealer(this.slider, {
    vertical: (this.type === 'vertical'),
    horizontal: (this.type === 'horizontal'),
    slide: false,
    speed: 100,
    animationCallback: function (x, y) {
      if (firstRun) {
        firstRun = false;
        return;
      }
      that.skipRefresh = true;
      dragDelta = that.type === 'vertical' ? y : x;
      if (that.dragTimeout === null) {
        that.dragTimeout = setInterval(dragRender, 100);
        dragRender();
      }
    },
    callback: function (x, y) {
      that.skipRefresh = false;
      clearInterval(that.dragTimeout);
      that.dragTimeout = null;
      dragDelta = that.type === 'vertical' ? y : x;
      that.onScroll(dragDelta);
    }
  });
  this.skipRefresh = false;
};

WalkontableScrollbar.prototype.onScroll = function (delta) {
  if (this.instance.drawn) {
    this.readSettings();
    if (this.total > this.visibleCount) {
      var newOffset = Math.round(this.handlePosition * this.total / this.sliderSize);

      if (delta === 1) {
        if (this.type === 'vertical') {
          this.instance.scrollVertical(Infinity).draw();
        }
        else {
          this.instance.scrollHorizontal(Infinity).draw();
        }
      }
      else if (newOffset !== this.offset) { //is new offset different than old offset
        if (this.type === 'vertical') {
          this.instance.scrollVertical(newOffset - this.offset).draw();
        }
        else {
          this.instance.scrollHorizontal(newOffset - this.offset).draw();
        }
      }
      else {
        this.refresh();
      }
    }
  }
};

/**
 * Returns what part of the scroller should the handle take
 * @param viewportCount {Number} number of visible rows or columns
 * @param totalCount {Number} total number of rows or columns
 * @return {Number} 0..1
 */
WalkontableScrollbar.prototype.getHandleSizeRatio = function (viewportCount, totalCount) {
  if (!totalCount || viewportCount > totalCount) {
    return 1;
  }
  return viewportCount / totalCount;
};

WalkontableScrollbar.prototype.prepare = function () {
  if (this.skipRefresh) {
    return;
  }
  var ratio = this.getHandleSizeRatio(this.visibleCount, this.total);
  if (((ratio === 1 || isNaN(ratio)) && this.scrollMode === 'auto') || this.scrollMode === 'none') {
    //isNaN is needed because ratio equals NaN when totalRows/totalColumns equals 0
    this.visible = false;
  }
  else {
    this.visible = true;
  }
};

WalkontableScrollbar.prototype.refresh = function () {
  if (this.skipRefresh) {
    return;
  }
  else if (!this.visible) {
    this.sliderStyle.display = 'none';
    return;
  }

  var ratio
    , sliderSize
    , handleSize
    , handlePosition
    , visibleCount = this.visibleCount
    , tableOuterWidth = this.$table.outerWidth()
    , tableOuterHeight = this.$table.outerHeight()
    , tableWidth = this.instance.hasSetting('width') ? this.instance.getSetting('width') : tableOuterWidth
    , tableHeight = this.instance.hasSetting('height') ? this.instance.getSetting('height') : tableOuterHeight;

  if (!tableWidth) {
    //throw new Error("I could not compute table width. Is the <table> element attached to the DOM?");
    return;
  }
  if (!tableHeight) {
    //throw new Error("I could not compute table height. Is the <table> element attached to the DOM?");
    return;
  }

  if (this.instance.hasSetting('width') && this.instance.wtScroll.wtScrollbarV.visible) {
    tableWidth -= this.instance.getSetting('scrollbarWidth');
  }
  if (tableWidth > tableOuterWidth + this.instance.getSetting('scrollbarWidth')) {
    tableWidth = tableOuterWidth;
  }

  if (this.instance.hasSetting('height') && this.instance.wtScroll.wtScrollbarH.visible) {
    tableHeight -= this.instance.getSetting('scrollbarHeight');
  }
  if (tableHeight > tableOuterHeight + this.instance.getSetting('scrollbarHeight')) {
    tableHeight = tableOuterHeight;
  }

  if (this.type === 'vertical') {
    if (this.instance.wtTable.isLastRowIncomplete()) {
      visibleCount--;
    }

    sliderSize = tableHeight - 2; //2 is sliders border-width

    this.sliderStyle.top = this.$table.position().top + 'px';
    this.sliderStyle.left = tableWidth - 1 + 'px'; //1 is sliders border-width
    this.sliderStyle.height = sliderSize + 'px';
  }
  else { //horizontal
    if (this.instance.wtTable.isLastColumnIncomplete()) {
      visibleCount--;
    }

    sliderSize = tableWidth - 2; //2 is sliders border-width

    this.sliderStyle.left = this.$table.position().left + 'px';
    this.sliderStyle.top = tableHeight - 1 + 'px'; //1 is sliders border-width
    this.sliderStyle.width = sliderSize + 'px';
  }

  ratio = this.getHandleSizeRatio(visibleCount, this.total);
  handleSize = Math.round(sliderSize * ratio);
  if (handleSize < 10) {
    handleSize = 15;
  }

  handlePosition = Math.floor(sliderSize * (this.offset / this.total));
  if (handleSize + handlePosition > sliderSize) {
    handlePosition = sliderSize - handleSize;
  }

  if (this.type === 'vertical') {
    this.handleStyle.height = handleSize + 'px';
    this.handleStyle.top = handlePosition + 'px';

  }
  else { //horizontal
    this.handleStyle.width = handleSize + 'px';
    this.handleStyle.left = handlePosition + 'px';
  }

  this.sliderStyle.display = 'block';
};

///

var WalkontableVerticalScrollbar = function (instance) {
  this.instance = instance;
  this.type = 'vertical';
  this.init();
};

WalkontableVerticalScrollbar.prototype = new WalkontableScrollbar();

WalkontableVerticalScrollbar.prototype.readSettings = function () {
  this.scrollMode = this.instance.getSetting('scrollV');
  this.offset = this.instance.getSetting('offsetRow');
  this.total = this.instance.getSetting('totalRows');
  this.visibleCount = this.instance.wtTable.countVisibleRows();
  this.handlePosition = parseInt(this.handleStyle.top, 10);
  this.sliderSize = parseInt(this.sliderStyle.height, 10);
  this.fixedCount = this.instance.getSetting('fixedRowsTop');
};

///

var WalkontableHorizontalScrollbar = function (instance) {
  this.instance = instance;
  this.type = 'horizontal';
  this.init();
};

WalkontableHorizontalScrollbar.prototype = new WalkontableScrollbar();

WalkontableHorizontalScrollbar.prototype.readSettings = function () {
  this.scrollMode = this.instance.getSetting('scrollH');
  this.offset = this.instance.getSetting('offsetColumn');
  this.total = this.instance.getSetting('totalColumns');
  this.visibleCount = this.instance.wtTable.countVisibleColumns();
  this.handlePosition = parseInt(this.handleStyle.left, 10);
  this.sliderSize = parseInt(this.sliderStyle.width, 10);
  this.fixedCount = this.instance.getSetting('fixedColumnsLeft');
};<|endoftext|>


<commit_before><commit_msg>my first test<commit_after><|endoftext|>


<commit_before>$(() => {
    "use strict";

    const $items              = $('.content li');
    const $visited_items      = $items.filter('.v');
    const $next_items         = $items.filter('.n');
    const $message_box        = $('#message');
    const $percentage_box     = $('#percentage');
    const $btn_filter_visited = $('#filter_v');
    const $btn_filter_next    = $('#filter_n');
    const is_smartphone       = !$('.sidebar footer').is(':visible');

    // message
    $visited_items.hover(function() {
        const $t = $(this);

        $message_box.find('p').html($t.data('msg')).end()
                    .find('.date span').html($t.data('date')).end()
                    .show();
    },
    () => {
        $message_box.hide();
    });

    // percentage
    const percentage           = Math.floor($visited_items.length/$items.length * 100);
    const percentage_box_width = $percentage_box.width() + 17; // 余白があるので大きめの画像を取得
    const bg_color             = $.fmtColor($('body').css("background-color")).replace('#','');

    $percentage_box.html('' + $visited_items.length + '/' + $items.length)
                   .css('background-image', 'url("http://chart.apis.google.com/chart?cht=p&chd=t:' + percentage + ',' + (100 - percentage) + '&chs=' + percentage_box_width + 'x' + percentage_box_width + '&chco=' + bg_color + '")');

    // filter_visited
    $btn_filter_visited.on('click', function() {
        const $t  = $(this);
        const $li = $t.closest('li');

        if ($li.hasClass('on')) {
            $items.show();
            $li.removeClass('on')
               .find('i').attr('class', 'icon-check-empty');

        } else {
            $items.not($visited_items).hide();
            $li.addClass('on')
               .find('i').attr('class', 'icon-check');
            $('body').scrollTop(0);
        }
    })
    .on('mouseover', function() {
        const $t = $(this);

        if ($t.closest('li').hasClass('on')) {
            $t.find('i').attr('class', 'icon-check-empty');
        } else {
            $t.find('i').attr('class', 'icon-check');
        }
    })
    .on('mouseout', function() {
        const $t = $(this);

        if ($t.closest('li').hasClass('on')) {
            $t.find('i').attr('class', 'icon-check');
        } else {
            $t.find('i').attr('class', 'icon-check-empty');
        }
    });

    // smartphone
    if (is_smartphone) {
        $items.not($visited_items).hide();
        $('.sidebar footer').clone()
                            .addClass('pure-hidden-tablet')
                            .addClass('pure-hidden-desktop')
                            .appendTo($('.content'));
    }
});
<commit_msg>lint 通らなかったので修正する<commit_after>$(() => {
    "use strict";

    const $items = $('.content li');
    const $visited_items = $items.filter('.v');
    const $next_items = $items.filter('.n');
    const $message_box = $('#message');
    const $percentage_box = $('#percentage');
    const $btn_filter_visited = $('#filter_v');
    const $btn_filter_next = $('#filter_n');
    const is_smartphone = !$('.sidebar footer').is(':visible');

    // message
    $visited_items.hover(function() {
        const $t = $(this);

        $message_box.find('p').html($t.data('msg')).end()
                    .find('.date span').html($t.data('date')).end()
                    .show();
    },
    () => {
        $message_box.hide();
    });

    // percentage
    const percentage = Math.floor($visited_items.length/$items.length * 100);
    const percentage_box_width = $percentage_box.width() + 17; // 余白があるので大きめの画像を取得
    const bg_color = $.fmtColor($('body').css("background-color")).replace('#','');

    $percentage_box.html('' + $visited_items.length + '/' + $items.length)
                   .css('background-image', 'url("http://chart.apis.google.com/chart?cht=p&chd=t:' + percentage + ',' + (100 - percentage) + '&chs=' + percentage_box_width + 'x' + percentage_box_width + '&chco=' + bg_color + '")');

    // filter_visited
    $btn_filter_visited.on('click', function() {
        const $t = $(this);
        const $li = $t.closest('li');

        if ($li.hasClass('on')) {
            $items.show();
            $li.removeClass('on')
               .find('i').attr('class', 'icon-check-empty');

        } else {
            $items.not($visited_items).hide();
            $li.addClass('on')
               .find('i').attr('class', 'icon-check');
            $('body').scrollTop(0);
        }
    })
    .on('mouseover', function() {
        const $t = $(this);

        if ($t.closest('li').hasClass('on')) {
            $t.find('i').attr('class', 'icon-check-empty');
        } else {
            $t.find('i').attr('class', 'icon-check');
        }
    })
    .on('mouseout', function() {
        const $t = $(this);

        if ($t.closest('li').hasClass('on')) {
            $t.find('i').attr('class', 'icon-check');
        } else {
            $t.find('i').attr('class', 'icon-check-empty');
        }
    });

    // smartphone
    if (is_smartphone) {
        $items.not($visited_items).hide();
        $('.sidebar footer').clone()
                            .addClass('pure-hidden-tablet')
                            .addClass('pure-hidden-desktop')
                            .appendTo($('.content'));
    }
});
<|endoftext|>