<commit_before>import frontMatter from 'front-matter';
import walkHtml from 'hastml';
import { decode as decodeEntities } from 'he';
import HighlightJS from 'highlight.js';
import MarkdownIt from './jsx-friendly-markdown-it';

import formatImport from './formatters/import';
import formatModule from './formatters/module';
import formatStatic from './formatters/static';
import formatEscape from './formatters/js-escape';
import StringReplacementCache from './string-replacement-cache';

const ASSIGNMENT_EXPRESSION_PREFIX = 'mclAssignmentBeginI';
const ASSIGNMENT_EXPRESSION_SUFFIX = 'IEnd';
const ASSIGNMENT_EXPRESSION_REGEXP = (
  // Assignment Expression IDs are 55 lower-case characters long
  `${ASSIGNMENT_EXPRESSION_PREFIX}[a-z]{55}${ASSIGNMENT_EXPRESSION_SUFFIX}`
);
const ASSIGNMENT_EXPRESSION_COMMENT_REGEXP = (
  `{/\\*(${ASSIGNMENT_EXPRESSION_REGEXP})\\*/}`
);

const DEFAULT_CONFIGURATION = {
  implicitlyImportReact: true,
  passElementProps: false,
  markdownItPlugins: []
};

export default (source, config) => {
  // First, we handle the configuration and front-matter

  config = Object.assign({}, DEFAULT_CONFIGURATION, config);

  const invalidStatics = ['propTypes'];
  const imports = [];

  // Import React and PropTypes unless we've been asked otherwise
  if (config.implicitlyImportReact) {
    imports.push(formatImport('React', 'react'));
    imports.push(formatImport('PropTypes', 'prop-types'));
  }

  // Pull out imports & front-matter
  const { body: markdown, attributes: { imports: importMap, ...staticAttributes } } = frontMatter(source);

  // Add additional imports
  if (importMap) {
    Object.keys(importMap).forEach((name) => {
      imports.push(formatImport(name, importMap[name]));
    });
  }

  // Disallow passing `defaultProps` if we're passing our own
  if (config.passElementProps) {
    invalidStatics.push('defaultProps');
  }

  // Add additional statics
  const statics = Object.keys(staticAttributes).map((attribute) => {
    if (invalidStatics.indexOf(attribute) !== -1) {
      throw new Error(`You can't supply a \`${attribute}\` static! That name is reserved.`);
    }

    return formatStatic(attribute, staticAttributes[attribute]);
  });

  // Now, we start processing the markdown itself

  // Hold onto JSX properties and assignment expressions before converting
  let offsetForPropertyReplacements = 0;
  let markdownSansJsxProperties = markdown;

  const jsxPropertyCache = new StringReplacementCache(
    /[\w]+={[^}]*}\s*}?|{\s*\.\.\.[^}]*}/g
  );

  // Find all opening or void HTML tags
  walkHtml(
    markdown,
    (match, tagFragment, offset, string, tag) => {
      // Once we get a tag which is closing
      if (typeof tag.closeIndex === 'number') {
        // Replace any assignment expressions within its opening tag
        const startIndex = tag.openIndex + offsetForPropertyReplacements;
        const endIndex = (
          typeof tag.contentIndex === 'number'
            ? tag.contentIndex
            : tag.closeIndex
        ) + offsetForPropertyReplacements;

        const tagWithNoReplacements = markdownSansJsxProperties.slice(startIndex, endIndex);
        const tagWithPropertyReplacements = jsxPropertyCache.load(tagWithNoReplacements);

        markdownSansJsxProperties = markdownSansJsxProperties.slice(0, startIndex) + tagWithPropertyReplacements + markdownSansJsxProperties.slice(endIndex);

        offsetForPropertyReplacements += tagWithPropertyReplacements.length - tagWithNoReplacements.length;
      }
    }
  );

  // Replace all remaining double-brace assignment expressions with comments
  const assignmentExpressionCache = new StringReplacementCache(
    /{({\s*(?:<.*?>|.*?)\s*})}/g,
    (match, value) => value,
    (identityHash) => `${ASSIGNMENT_EXPRESSION_PREFIX}${identityHash}${ASSIGNMENT_EXPRESSION_SUFFIX}`
  );

  const markdownSansAssignments = assignmentExpressionCache.load(markdownSansJsxProperties);

  // Configure Markdown renderer, highlight code snippets, and post-process
  let renderer = new MarkdownIt()
    .configure('commonmark')
    .enable(['smartquotes'])
    .set({
      // We need explicit line breaks
      breaks: true,
      typographer: config.typographer,
      highlight(code, languageHint) {
        let highlightedContent;

        HighlightJS.configure({ tabReplace: '  ' });

        // Try highlighting with a given hint
        if (languageHint && HighlightJS.getLanguage(languageHint)) {
          try {
            highlightedContent = HighlightJS.highlight(languageHint, code).value;
          } catch (err) {} // eslint-disable-line no-empty
        }

        // Highlight without a hint
        if (!highlightedContent) {
          try {
            highlightedContent = HighlightJS.highlightAuto(code).value;
          } catch (err) {} // eslint-disable-line no-empty
        }

        return highlightedContent
          .replace(/\n/g, '
');
      }
    });

  // Load MarkdownIt plugins
  if (config.markdownItPlugins && Array.isArray(config.markdownItPlugins)) {
    renderer = config.markdownItPlugins
      .reduce(
        (markdownRenderer, pluginDefinition) => (
          markdownRenderer.use(...(
            Array.isArray(pluginDefinition)
              ? pluginDefinition
              : [pluginDefinition]
          ))
        ),
        renderer
      );
  }

  // Render markdown to HTML, and replace assignment expressions with comments
  const html = (
    renderer.render(markdownSansAssignments) || ''
  ).replace(
    new RegExp(ASSIGNMENT_EXPRESSION_REGEXP, 'g'),
    ''
  );

  // Collect all the HTML tags and their positions
  const htmlOffsets = [0];

  walkHtml(
    html,
    (match, tagFragment, offset) => {
      if (tagFragment[0] === '<') {
        htmlOffsets.push(offset);
      } else { // ∴ tagFragment[tagFragment.length - 1] === '>'
        htmlOffsets.push(offset + tagFragment.length);
      }
    }
  );

  // Here, we collect all the positions at which SGML tags begin or end
  let jsx = htmlOffsets
    .map((offset, index, array) => {
      let fragment = html.slice(offset, array[index + 1]);

      // Then we check, for each of them, whether they are a tag or a text node
      if (fragment[0] === '<' || fragment[fragment.length - 1] === '>') {
        // If they're tags, we check whether they're a comment,
        if (fragment.slice(0, 4) === ''
  ).replace(
    new RegExp(ASSIGNMENT_EXPRESSION_REGEXP, 'g'),
    ''
  );

  // Collect all the HTML tags and their positions
  const htmlOffsets = [0];

  walkHtml(
    html,
    (match, tagFragment, offset) => {
      if (tagFragment[0] === '<') {
        // Push the offset of opening tags...
        htmlOffsets.push(offset);
      } else { // ∴ tagFragment[tagFragment.length - 1] === '>'
        // ...and the end offset of closing tags
        htmlOffsets.push(offset + tagFragment.length);
      }
    }
  );

  // Here, we collect all the positions at which HTML tags begin or end
  let jsx = htmlOffsets
    .map((offset, index, array) => {
      let fragment = html.slice(offset, array[index + 1]);

      // Then we check, for each of them, whether they are a tag or a text node
      if (fragment[0] === '<' || fragment[fragment.length - 1] === '>') {
        // If they're tags, we check whether they're a comment,
        if (fragment.slice(0, 4) === '


<commit_before>var _utils = require('../utils'),
    _cache = require('../cache'),
    _regex = require('../regex'),
    _array = require('./array'),
    _nodeType = require('../nodeType'),
    _supports = require('../supports'),

    _selectorBlackList = ['.', '#', '', ' '];

var _isMatch = (function(matchSelector) {
    if (matchSelector) {
        return function(elem, selector) {
            return matchSelector.call(elem, selector);
        };
    }

    return function(elem, selector) {
        var nodes = elem.parentNode.querySelectorAll(selector),
            idx = nodes.length;
        while (idx--) {
            if (nodes[idx] === elem) {
                return true;
            }
        }
        return false;
    };
}(_supports.matchesSelector));

var _find = function(selector, context) {
    var idx = 0,
        length = context.length || 1,
        result = [];

    // Early return if the selector is bad
    if (_selectorBlackList.indexOf(selector) > -1) { return result; }

    var method = _determineMethod(selector);
    for (; idx < length; idx++) {
        var ret = _findWithQuery(selector, context[idx], method);
        if (ret) { result.push(ret); }
    }

    return _array.unique(_.flatten(result));
};

var _determineMethod = function(selector) {
    var method = _cache.selector.get(selector);
    if (method) { return method; }

    if (_regex.selector.isStrictId(selector)) {
        method = 'getElementById';
    } else if (_regex.selector.isClass(selector)) {
        method = 'getElementsByClassName';
    } else if (_regex.selector.isTag(selector)) {
        method = 'getElementsByTagName';
    } else {
        method = 'querySelectorAll';
    }

    _cache.selector.set(selector, method);
    return method;
};

var _findWithQuery = function(selector, context, method) {
    context = context || document;

    // TODO: What to do if ">" child selector is used @ index = 0;

    var nodeType;
    // Early return if context is not an element or document
    if ((nodeType = context.nodeType) !== _nodeType.ELEMENT && nodeType !== _nodeType.DOCUMENT) { return; }

    var query = context[method](selector);
    if (!query.length) { return; }
    return _array.slice(query);
};

var _filter = function(arr, qualifier) {
    // Early return, no qualifier. Everything matches
    if (!qualifier) { return arr; }

    // Function
    if (_.isFunction(qualifier)) {
        return _.filter(arr, qualifier);
    }

    // Element
    if (qualifier.nodeType) {
        return _.filter(arr, function(elem) {
            return (elem === qualifier);
        });
    }

    // Selector
    if (_.isString(qualifier)) {
        return _.filter(arr, function(elem) {
            return elem.nodeType === 1 && _isMatch(elem, qualifier);
        });
    }

    // Array qualifier
    return _.filter(arr, function(elem) {
        return arr.indexOf(qualifier) > -1;
    });
};

module.exports = {
    find: _find,
    is: _isMatch,
    filter: _filter,

    fn: {
        has: function(target) {
            // TODO: Has
            /*var i,
                targets = jQuery( target, this ),
                len = targets.length;

            return this.filter(function() {
                for ( i = 0; i < len; i++ ) {
                    if ( jQuery.contains( this, targets[i] ) ) {
                        return true;
                    }
                }
            });*/
        },

        is: Overload()
                .args(String).use(function(selector) {
                    return D(
                        _.every(this, function(elem) {
                            return _isMatch(elem, selector);
                        })
                    );
                })
                .args(Function).use(function(iterator) {
                    // TODO: Internal "every"
                    return D(
                        _.every(this, iterator)
                    );
                })
                .expose(),

        not: function() {},

        find: Overload()
                .args(String)
                .use(function(selector) {

                    return _utils.merge(D(), _find(selector, this));

                }).expose(),

        filter: Overload()
                    .args(String)
                    .use(function(selector) {
                        return this.is(selector);
                    })
                    .args(Function)
                    .use(function(checker) {
                        var result = [],
                            idx = this.length;

                        while (idx--) {
                            if (checker(this[idx])) { result.unshift(this[idx]); }
                        }

                        return D(result);
                    })
                    .expose()
    }
};
<commit_msg>Fixed .is() return values<commit_after>var _utils = require('../utils'),
    _cache = require('../cache'),
    _regex = require('../regex'),
    _array = require('./array'),
    _nodeType = require('../nodeType'),
    _supports = require('../supports'),

    _selectorBlackList = ['.', '#', '', ' '];

var _isMatch = (function(matchSelector) {
    if (matchSelector) {
        return function(elem, selector) {
            return matchSelector.call(elem, selector);
        };
    }

    return function(elem, selector) {
        var nodes = elem.parentNode.querySelectorAll(selector),
            idx = nodes.length;
        while (idx--) {
            if (nodes[idx] === elem) {
                return true;
            }
        }
        return false;
    };
}(_supports.matchesSelector));

var _find = function(selector, context) {
    var idx = 0,
        length = context.length || 1,
        result = [];

    // Early return if the selector is bad
    if (_selectorBlackList.indexOf(selector) > -1) { return result; }

    var method = _determineMethod(selector);
    for (; idx < length; idx++) {
        var ret = _findWithQuery(selector, context[idx], method);
        if (ret) { result.push(ret); }
    }

    return _array.unique(_.flatten(result));
};

var _determineMethod = function(selector) {
    var method = _cache.selector.get(selector);
    if (method) { return method; }

    if (_regex.selector.isStrictId(selector)) {
        method = 'getElementById';
    } else if (_regex.selector.isClass(selector)) {
        method = 'getElementsByClassName';
    } else if (_regex.selector.isTag(selector)) {
        method = 'getElementsByTagName';
    } else {
        method = 'querySelectorAll';
    }

    _cache.selector.set(selector, method);
    return method;
};

var _findWithQuery = function(selector, context, method) {
    context = context || document;

    // TODO: What to do if ">" child selector is used @ index = 0;

    var nodeType;
    // Early return if context is not an element or document
    if ((nodeType = context.nodeType) !== _nodeType.ELEMENT && nodeType !== _nodeType.DOCUMENT) { return; }

    var query = context[method](selector);
    if (!query.length) { return; }
    return _array.slice(query);
};

var _filter = function(arr, qualifier) {
    // Early return, no qualifier. Everything matches
    if (!qualifier) { return arr; }

    // Function
    if (_.isFunction(qualifier)) {
        return _.filter(arr, qualifier);
    }

    // Element
    if (qualifier.nodeType) {
        return _.filter(arr, function(elem) {
            return (elem === qualifier);
        });
    }

    // Selector
    if (_.isString(qualifier)) {
        return _.filter(arr, function(elem) {
            return elem.nodeType === 1 && _isMatch(elem, qualifier);
        });
    }

    // Array qualifier
    return _.filter(arr, function(elem) {
        return arr.indexOf(qualifier) > -1;
    });
};

module.exports = {
    find: _find,
    is: _isMatch,
    filter: _filter,

    fn: {
        has: function(target) {
            // TODO: Has
            /*var i,
                targets = jQuery( target, this ),
                len = targets.length;

            return this.filter(function() {
                for ( i = 0; i < len; i++ ) {
                    if ( jQuery.contains( this, targets[i] ) ) {
                        return true;
                    }
                }
            });*/
        },

        is: Overload()
                .args(String).use(function(selector) {
                    return _.any(this, function(elem) {
                        return _isMatch(elem, selector);
                    });
                })
                .args(Function).use(function(iterator) {
                    // TODO: Internal "every"
                    return _.any(this, iterator);
                })
                .expose(),

        not: function() {},

        find: Overload()
                .args(String)
                .use(function(selector) {

                    return _utils.merge(D(), _find(selector, this));

                }).expose(),

        filter: Overload()
                    .args(String)
                    .use(function(selector) {
                        return this.is(selector);
                    })
                    .args(Function)
                    .use(function(checker) {
                        var result = [],
                            idx = this.length;

                        while (idx--) {
                            if (checker(this[idx])) { result.unshift(this[idx]); }
                        }

                        return D(result);
                    })
                    .expose()
    }
};
<|endoftext|>


<commit_before>// Chart plotting functions

import * as util from './utils/timechart'
import * as marker from './markers/timechart'

export default class TimeChart {
  constructor(d3, elementId, weekHook) {
    // Get div dimensions
    let footBB = d3.select('.footer').node().getBoundingClientRect(),
        chartBB = d3.select('#' + elementId).node().getBoundingClientRect()

    let divWidth = chartBB.width,
        divHeight = window.innerHeight - chartBB.top - footBB.height

    divHeight = Math.max(300, divHeight)

    // Create blank chart
    let margin = {
      top: 10, right: 50, bottom: 70, left: 40
    },
        width = divWidth - margin.left - margin.right,
        height = divHeight - margin.top - margin.bottom

    // Initialize scales and stuff
    let xScale = d3.scaleLinear()
        .range([0, width]),
        yScale = d3.scaleLinear()
        .range([height, 0]),
        xScaleDate = d3.scaleTime()
        .range([0, width])

    // Add svg
    let svg = d3.select('#' + elementId).append('svg')
        .attr('width', width + margin.left + margin.right)
        .attr('height', height + margin.top + margin.bottom)
        .append('g')
        .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')')

    // Add tooltip
    this.tooltip = d3.select('body').append('div')
      .attr('id', 'chart-tooltip')
      .style('display', 'none')

    // Save variables
    this.d3 = d3
    this.svg = svg
    this.xScale = xScale
    this.yScale = yScale
    this.xScaleDate = xScaleDate
    this.height = height
    this.width = width
    this.weekHook = weekHook

    // Add axes
    this.setupAxes()

    // Add marker primitives
    this.timerect = new marker.TimeRect(this)

    // Add overlays and other mouse interaction items
    this.setupOverlay()

    this.baseline = new marker.Baseline(this)
    this.actual = new marker.Actual(this)
    this.predictions = []
  }

  /**
   * Setup axes
   */
  setupAxes() {
    let svg = this.svg,
        d3 = this.d3,
        width = this.width,
        height = this.height

    let infoTooltip = d3.select('#info-tooltip')

    svg.append('g')
      .attr('class', 'axis axis-x')
      .attr('transform', 'translate(0,' + height + ')')

    svg.append('g')
      .attr('class', 'axis axis-x-date')
      .attr('transform', 'translate(0,' + (height + 25) + ')')
      .append('text')
      .attr('class', 'title')
      .attr('text-anchor', 'middle')
      .attr('transform', 'translate(' + width / 2 + ',' + 40 + ')')
      .text('Epidemic Week')
      .style('cursor', 'pointer')
      .on('mouseover', function() {
        infoTooltip
          .style('display', null)
      })
      .on('mouseout', function() {
        infoTooltip
          .style('display', 'none')
      })
      .on('mousemove', function() {
        infoTooltip
          .style('top', (event.clientY - 20) + 'px')
          .style('left', (event.clientX + 20) + 'px')
          .html('Description

Click to know more') // TODO: Add description
      })
      .on('click', function() {
        window.open('#', '_blank') // TODO: Add link
      })

    svg.append('g')
      .attr('class', 'axis axis-y')
      .append('text')
      .attr('class', 'title')
      .attr('transform', 'translate(-40 ,' + height / 2 + ') rotate(-90)')
      .attr('dy', '.71em')
      .style('text-anchor', 'middle')
      .text('Weighted ILI (%)')
      .style('cursor', 'pointer')
      .on('mouseover', function() {
        infoTooltip
          .style('display', null)
      })
      .on('mouseout', function() {
        infoTooltip
          .style('display', 'none')
      })
      .on('mousemove', function() {
        infoTooltip
          .style('top', event.clientY + 'px')
          .style('left', (event.clientX + 20) + 'px')
          .html('Description

Click to know more') // TODO: Add description
      })
      .on('click', function() {
        window.open('#', '_blank') // TODO: Add link
      })
  }

  /**
   * Setup overlay for mouse events
   */
  setupOverlay() {
    let svg = this.svg,
        height = this.height,
        width = this.width,
        tooltip = this.tooltip

    // Add vertical line
    let line = svg.append('line')
        .attr('class', 'hover-line')
        .attr('x1', 0)
        .attr('y1', 0)
        .attr('x2', 0)
        .attr('y2', height)
        .style('display', 'none')

    // Get bounding box
    let bb = svg.node().getBoundingClientRect()

    svg.append('rect')
      .attr('class', 'overlay')
      .attr('height', height)
      .attr('width', width)
      .on('mouseover', () => {
        line.style('display', null)
        tooltip.style('display', null)
      })
      .on('mouseout', () => {
        line.style('display', 'none')
        tooltip.style('display', 'none')
      })
  }

  // plot data
  plot(data) {
    let d3 = this.d3,
        svg = this.svg,
        xScale = this.xScale,
        yScale = this.yScale,
        xScaleDate = this.xScaleDate,
        tooltip = this.tooltip,
        weekHook = this.weekHook

    // Reset scales and axes
    yScale.domain([0, util.getYMax(data)])
    // Assuming actual data has all the weeks
    let weeks = data.actual.map(d => d.week % 100)
    xScale.domain([0, weeks.length - 1])

    // Setup a scale for ticks
    let xScalePoint = d3.scalePoint()
        .domain(weeks)
        .range([0, this.width])

    // Week domain scale for easy mapping
    let xScaleWeek = (d) => xScale(weeks.indexOf(Math.floor(d))) + d % 1

    // Week to date parser
    let dateParser = d3.timeParse('%Y-%U')
    xScaleDate.domain(d3.extent(data.actual.map(d => {
      let formattedDate = Math.floor(d.week / 100) + '-' + d.week % 100
      return dateParser(formattedDate)
    })))

    let xAxis = d3.axisBottom(xScalePoint)
        .tickValues(xScalePoint.domain().filter((d, i) => !(i % 2)))

    let xAxisDate = d3.axisBottom(xScaleDate)
        .ticks(d3.timeMonth)
        .tickFormat(d3.timeFormat('%b %y'))

    let yAxis = d3.axisLeft(yScale)

    svg.select('.axis-x')
      .transition().duration(200).call(xAxis)

    svg.select('.axis-x-date')
      .transition().duration(200).call(xAxisDate)

    svg.select('.axis-y')
      .transition().duration(200).call(yAxis)

    // Save
    this.weeks = weeks
    this.xScaleWeek = xScaleWeek

    // Set pointer for week data (start with last)
    this.weekIdx = data.actual.length - 1
    this.weekHook({
      idx: this.weekIdx,
      name: this.weeks[this.weekIdx]
    })

    // Update markers with data
    this.timerect.plot(this, data.actual)
    this.baseline.plot(this, data.baseline)
    this.actual.plot(this, data.actual)

    // Reset history lines
    if (this.history) this.history.clear()
    this.history = new marker.HistoricalLines(this)
    this.history.plot(this, data.history)

    // Reset predictions
    this.predictions.map(p => p.clear())
    this.predictions = []
    let colors = d3.schemeCategory10 // TODO: handle more than 10 colors

    data.models.forEach((m, idx) => {
      let predMarker = new marker.Prediction(this, m.id, colors[idx])
      predMarker.plot(this, m.predictions, data.actual)
      predMarker.hideMarkers()
      this.predictions.push(predMarker)
    })

    this.legend = new marker.Legend(this, (pid, hide) => {
      let pred = this.predictions.filter(p => p.id == pid)[0]
      pred.legendHidden = hide
      if (hide) {
        pred.hideMarkers()
      } else {
        pred.showMarkers()
      }
    })

    let that = this
    // Add mouse move and click events
    let bb = svg.node().getBoundingClientRect()
    d3.select('.overlay')
      .on('mousemove', function() {
        let mouse = d3.mouse(this)
        // Snap x to nearest tick
        let index = Math.round(xScale.invert(mouse[0]))
        let snappedX = xScale(index)
        d3.select('.hover-line')
          .transition()
          .duration(50)
          .attr('x1', snappedX)
          .attr('x2', snappedX)

        tooltip
          .style('top', (event.clientY + 20) + 'px')
          .style('left', (event.clientX + 20) + 'px')
          .html(util.tooltipText(that, index, mouse[1]))
      })
      .on('click', function() {
        let idx = Math.round(xScale.invert(d3.mouse(this)[0]))
        weekHook({
          idx: idx,
          name: weeks[idx]
        })
      })
  }

  /**
   * Update marker position
   */
  update(idx) {
    // Change self index
    this.weekIdx = idx
    this.timerect.update(idx)

    this.predictions.forEach(p => {
      p.update(idx)
    })

    this.legend.update(this.predictions)
  }

  // External interaction functions
  // ------------------------------

  /**
   * Return next week idx and name for vuex store
   */
  getNextWeekData() {
    let nextIdx = Math.min(this.weeks.length - 1, this.weekIdx + 1)
    return {
      idx: nextIdx,
      name: this.weeks[nextIdx]
    }
  }

  /**
   * Return preview week idx and name for vuex store
   */
  getPreviousWeekData() {
    let previousIdx = Math.max(0, this.weekIdx - 1)
    return {
      idx: previousIdx,
      name: this.weeks[previousIdx]
    }
  }
}
<commit_msg>Mobile view tick density fix<commit_after>// Chart plotting functions

import * as util from './utils/timechart'
import * as marker from './markers/timechart'

export default class TimeChart {
  constructor(d3, elementId, weekHook) {
    // Get div dimensions
    let footBB = d3.select('.footer').node().getBoundingClientRect(),
        chartBB = d3.select('#' + elementId).node().getBoundingClientRect()

    let divWidth = chartBB.width,
        divHeight = window.innerHeight - chartBB.top - footBB.height

    divHeight = Math.max(300, divHeight)

    // Create blank chart
    let margin = {
      top: 10, right: 50, bottom: 70, left: 40
    },
        width = divWidth - margin.left - margin.right,
        height = divHeight - margin.top - margin.bottom

    // Initialize scales and stuff
    let xScale = d3.scaleLinear()
        .range([0, width]),
        yScale = d3.scaleLinear()
        .range([height, 0]),
        xScaleDate = d3.scaleTime()
        .range([0, width])

    // Add svg
    let svg = d3.select('#' + elementId).append('svg')
        .attr('width', width + margin.left + margin.right)
        .attr('height', height + margin.top + margin.bottom)
        .append('g')
        .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')')

    // Add tooltip
    this.tooltip = d3.select('body').append('div')
      .attr('id', 'chart-tooltip')
      .style('display', 'none')

    // Save variables
    this.d3 = d3
    this.svg = svg
    this.xScale = xScale
    this.yScale = yScale
    this.xScaleDate = xScaleDate
    this.height = height
    this.width = width
    this.weekHook = weekHook

    // Add axes
    this.setupAxes()

    // Add marker primitives
    this.timerect = new marker.TimeRect(this)

    // Add overlays and other mouse interaction items
    this.setupOverlay()

    this.baseline = new marker.Baseline(this)
    this.actual = new marker.Actual(this)
    this.predictions = []
  }

  /**
   * Setup axes
   */
  setupAxes() {
    let svg = this.svg,
        d3 = this.d3,
        width = this.width,
        height = this.height

    let infoTooltip = d3.select('#info-tooltip')

    svg.append('g')
      .attr('class', 'axis axis-x')
      .attr('transform', 'translate(0,' + height + ')')

    svg.append('g')
      .attr('class', 'axis axis-x-date')
      .attr('transform', 'translate(0,' + (height + 25) + ')')
      .append('text')
      .attr('class', 'title')
      .attr('text-anchor', 'middle')
      .attr('transform', 'translate(' + width / 2 + ',' + 40 + ')')
      .text('Epidemic Week')
      .style('cursor', 'pointer')
      .on('mouseover', function() {
        infoTooltip
          .style('display', null)
      })
      .on('mouseout', function() {
        infoTooltip
          .style('display', 'none')
      })
      .on('mousemove', function() {
        infoTooltip
          .style('top', (event.clientY - 20) + 'px')
          .style('left', (event.clientX + 20) + 'px')
          .html('Description

Click to know more') // TODO: Add description
      })
      .on('click', function() {
        window.open('#', '_blank') // TODO: Add link
      })

    svg.append('g')
      .attr('class', 'axis axis-y')
      .append('text')
      .attr('class', 'title')
      .attr('transform', 'translate(-40 ,' + height / 2 + ') rotate(-90)')
      .attr('dy', '.71em')
      .style('text-anchor', 'middle')
      .text('Weighted ILI (%)')
      .style('cursor', 'pointer')
      .on('mouseover', function() {
        infoTooltip
          .style('display', null)
      })
      .on('mouseout', function() {
        infoTooltip
          .style('display', 'none')
      })
      .on('mousemove', function() {
        infoTooltip
          .style('top', event.clientY + 'px')
          .style('left', (event.clientX + 20) + 'px')
          .html('Description

Click to know more') // TODO: Add description
      })
      .on('click', function() {
        window.open('#', '_blank') // TODO: Add link
      })
  }

  /**
   * Setup overlay for mouse events
   */
  setupOverlay() {
    let svg = this.svg,
        height = this.height,
        width = this.width,
        tooltip = this.tooltip

    // Add vertical line
    let line = svg.append('line')
        .attr('class', 'hover-line')
        .attr('x1', 0)
        .attr('y1', 0)
        .attr('x2', 0)
        .attr('y2', height)
        .style('display', 'none')

    // Get bounding box
    let bb = svg.node().getBoundingClientRect()

    svg.append('rect')
      .attr('class', 'overlay')
      .attr('height', height)
      .attr('width', width)
      .on('mouseover', () => {
        line.style('display', null)
        tooltip.style('display', null)
      })
      .on('mouseout', () => {
        line.style('display', 'none')
        tooltip.style('display', 'none')
      })
  }

  // plot data
  plot(data) {
    let d3 = this.d3,
        svg = this.svg,
        xScale = this.xScale,
        yScale = this.yScale,
        xScaleDate = this.xScaleDate,
        tooltip = this.tooltip,
        weekHook = this.weekHook

    // Reset scales and axes
    yScale.domain([0, util.getYMax(data)])
    // Assuming actual data has all the weeks
    let weeks = data.actual.map(d => d.week % 100)
    xScale.domain([0, weeks.length - 1])

    // Setup a scale for ticks
    let xScalePoint = d3.scalePoint()
        .domain(weeks)
        .range([0, this.width])

    // Week domain scale for easy mapping
    let xScaleWeek = (d) => xScale(weeks.indexOf(Math.floor(d))) + d % 1

    // Week to date parser
    let dateParser = d3.timeParse('%Y-%U')
    xScaleDate.domain(d3.extent(data.actual.map(d => {
      let formattedDate = Math.floor(d.week / 100) + '-' + d.week % 100
      return dateParser(formattedDate)
    })))

    let xAxis = d3.axisBottom(xScalePoint)
        .tickValues(xScalePoint.domain().filter((d, i) => !(i % 2)))

    let xAxisDate = d3.axisBottom(xScaleDate)
        .ticks(d3.timeMonth)
        .tickFormat(d3.timeFormat('%b %y'))

    // Mobile view fix
    if (this.width < 420) {
      xAxisDate.ticks(2)
      xAxis.tickValues(xScalePoint.domain().filter((d, i) => !(i % 10)))
    }

    let yAxis = d3.axisLeft(yScale)

    svg.select('.axis-x')
      .transition().duration(200).call(xAxis)

    svg.select('.axis-x-date')
      .transition().duration(200).call(xAxisDate)

    svg.select('.axis-y')
      .transition().duration(200).call(yAxis)

    // Save
    this.weeks = weeks
    this.xScaleWeek = xScaleWeek

    // Set pointer for week data (start with last)
    this.weekIdx = data.actual.length - 1
    this.weekHook({
      idx: this.weekIdx,
      name: this.weeks[this.weekIdx]
    })

    // Update markers with data
    this.timerect.plot(this, data.actual)
    this.baseline.plot(this, data.baseline)
    this.actual.plot(this, data.actual)

    // Reset history lines
    if (this.history) this.history.clear()
    this.history = new marker.HistoricalLines(this)
    this.history.plot(this, data.history)

    // Reset predictions
    this.predictions.map(p => p.clear())
    this.predictions = []
    let colors = d3.schemeCategory10 // TODO: handle more than 10 colors

    data.models.forEach((m, idx) => {
      let predMarker = new marker.Prediction(this, m.id, colors[idx])
      predMarker.plot(this, m.predictions, data.actual)
      predMarker.hideMarkers()
      this.predictions.push(predMarker)
    })

    this.legend = new marker.Legend(this, (pid, hide) => {
      let pred = this.predictions.filter(p => p.id == pid)[0]
      pred.legendHidden = hide
      if (hide) {
        pred.hideMarkers()
      } else {
        pred.showMarkers()
      }
    })

    let that = this
    // Add mouse move and click events
    let bb = svg.node().getBoundingClientRect()
    d3.select('.overlay')
      .on('mousemove', function() {
        let mouse = d3.mouse(this)
        // Snap x to nearest tick
        let index = Math.round(xScale.invert(mouse[0]))
        let snappedX = xScale(index)
        d3.select('.hover-line')
          .transition()
          .duration(50)
          .attr('x1', snappedX)
          .attr('x2', snappedX)

        tooltip
          .style('top', (event.clientY + 20) + 'px')
          .style('left', (event.clientX + 20) + 'px')
          .html(util.tooltipText(that, index, mouse[1]))
      })
      .on('click', function() {
        let idx = Math.round(xScale.invert(d3.mouse(this)[0]))
        weekHook({
          idx: idx,
          name: weeks[idx]
        })
      })
  }

  /**
   * Update marker position
   */
  update(idx) {
    // Change self index
    this.weekIdx = idx
    this.timerect.update(idx)

    this.predictions.forEach(p => {
      p.update(idx)
    })

    this.legend.update(this.predictions)
  }

  // External interaction functions
  // ------------------------------

  /**
   * Return next week idx and name for vuex store
   */
  getNextWeekData() {
    let nextIdx = Math.min(this.weeks.length - 1, this.weekIdx + 1)
    return {
      idx: nextIdx,
      name: this.weeks[nextIdx]
    }
  }

  /**
   * Return preview week idx and name for vuex store
   */
  getPreviousWeekData() {
    let previousIdx = Math.max(0, this.weekIdx - 1)
    return {
      idx: previousIdx,
      name: this.weeks[previousIdx]
    }
  }
}
<|endoftext|>


<commit_before>var app = require('electron').app;  // Module to control application life.
var BrowserWindow = require('electron').BrowserWindow;  // Module to create native browser window.
// var crashReporter = require('electron').crashReporter;
var path = require("path")

var program = require("commander")
  .option("-d, --dev-tools", "Open Dev Tools on start up")
  .option("-r, --hard-reloading", "Open Dev Tools on start up")
  .parse(process.argv)

// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the javascript object is GCed.
var mainWindow = null;

// Quit when all windows are closed.
app.on('window-all-closed', function() {
  if (process.platform != 'darwin') {
    app.quit();
  }
});

// Live reloading
let options = {};
if (program.hardReload) {
    options['electron'] = require('electron-prebuilt');
}
require('electron-reload')(path.resolve(__dirname, '../dist'), options);

// This method will be called when Electron has done everything
// initialization and ready for creating browser windows.
app.on('ready', function() {
  app.commandLine.appendSwitch('js-flags', '--harmony_iteration');
  app.commandLine.appendSwitch('js-flags', '--harmony_symbols');
  app.commandLine.appendSwitch('js-flags', '--harmony_observation');
  app.commandLine.appendSwitch('js-flags', '--harmony_scoping');
  app.commandLine.appendSwitch('js-flags', '--harmony_modules');
  app.commandLine.appendSwitch('js-flags', '--harmony_proxies');
  app.commandLine.appendSwitch('js-flags', '--harmony_collections');
  app.commandLine.appendSwitch('js-flags', '--harmony_generators');
  app.commandLine.appendSwitch('js-flags', '--harmony_arrow_functions');

  // Create the browser window.
  mainWindow = new BrowserWindow({width: 1000, height: 600 });
  mainWindow.setMenu(null);

  // and load the index.html of the app.
  mainWindow.loadURL('file://' + path.resolve(__dirname, '../public/index.html'));

  // Open the devtools.
  program.devTools && mainWindow.openDevTools({detached:true});

  // Emitted when the window is closed.
  mainWindow.on('closed', function(){
    // Dereference the window object, usually you would store windows
    // in an array if your app supports multi windows, this is the time
    // when you should delete the corresponding element.
    mainWindow = null;
  })
});
<commit_msg>Fix typo<commit_after>var app = require('electron').app;  // Module to control application life.
var BrowserWindow = require('electron').BrowserWindow;  // Module to create native browser window.
// var crashReporter = require('electron').crashReporter;
var path = require("path")

var program = require("commander")
  .option("-d, --dev-tools", "Open Dev Tools on start up")
  .option("-r, --hard-reloading", "Open Dev Tools on start up")
  .parse(process.argv)

// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the javascript object is GCed.
var mainWindow = null;

// Quit when all windows are closed.
app.on('window-all-closed', function() {
  if (process.platform != 'darwin') {
    app.quit();
  }
});

// Live reloading
let options = {};
if (program.hardReloading) {
    options['electron'] = require('electron-prebuilt');
}
require('electron-reload')(path.resolve(__dirname, '../dist'), options);

// This method will be called when Electron has done everything
// initialization and ready for creating browser windows.
app.on('ready', function() {
  app.commandLine.appendSwitch('js-flags', '--harmony_iteration');
  app.commandLine.appendSwitch('js-flags', '--harmony_symbols');
  app.commandLine.appendSwitch('js-flags', '--harmony_observation');
  app.commandLine.appendSwitch('js-flags', '--harmony_scoping');
  app.commandLine.appendSwitch('js-flags', '--harmony_modules');
  app.commandLine.appendSwitch('js-flags', '--harmony_proxies');
  app.commandLine.appendSwitch('js-flags', '--harmony_collections');
  app.commandLine.appendSwitch('js-flags', '--harmony_generators');
  app.commandLine.appendSwitch('js-flags', '--harmony_arrow_functions');

  // Create the browser window.
  mainWindow = new BrowserWindow({width: 1000, height: 600 });
  mainWindow.setMenu(null);

  // and load the index.html of the app.
  mainWindow.loadURL('file://' + path.resolve(__dirname, '../public/index.html'));

  // Open the devtools.
  program.devTools && mainWindow.openDevTools({detached:true});

  // Emitted when the window is closed.
  mainWindow.on('closed', function(){
    // Dereference the window object, usually you would store windows
    // in an array if your app supports multi windows, this is the time
    // when you should delete the corresponding element.
    mainWindow = null;
  })
});
<|endoftext|>


<commit_before>this.data = document.body.innerHTML;
this.uri = document.location.href;

if(/^\
(.*)\n?\<\/pre\>$/.test(this.data)){
  // console.log("JSONView: data is wrapped in
...
, stripping HTML...");
  this.data = this.data.replace(/<(?:.|\s)*?>/g, ''); //Aggressively strip HTML.
}

var json_regex = /^\s*([\[\{].*[\}\]])\s*$/; // Ghetto, but it works
var jsonp_regex = /^[\s\u200B\uFEFF]*([\w$\[\]\.]+)[\s\u200B\uFEFF]*\([\s\u200B\uFEFF]*([\[{][\s\S]*[\]}])[\s\u200B\uFEFF]*\);?[\s\u200B\uFEFF]*$/;
var jsonp_regex2 = /([\[\{][\s\S]*[\]\}])\)/; // more liberal support... this allows us to pass the jsonp.json & jsonp2.json tests
var is_json = json_regex.test(this.data);
var is_jsonp = jsonp_regex.test(this.data);
// console.log("JSONView: is_json="+is_json+" is_jsonp="+is_jsonp);

if(is_json || is_jsonp){
  /*
   * The JSONFormatter helper object. This contains two major functions, jsonToHTML and errorPage,
   * each of which returns an HTML document.
   */
  function JSONFormatter() { }

  JSONFormatter.prototype = {
    /**
     * Encode a string to be used in HTML
     */
    htmlEncode: function(t) {
      return t !== null ? t.toString().replace(/&/g,"&").replace(/"/g,""").replace(/</g,"<").replace(/>/g,">") : '';
    },

    /**
     * Completely escape a json string
     */
    jsString: function(s) {
      // Slice off the surrounding quotes
      s = JSON.stringify(s).slice(1, -1);
      return this.htmlEncode(s);
    },

    /**
     * Is this a valid "bare" property name?
     */
    isBareProp: function(prop) {
      return /^[A-Za-z_$][A-Za-z0-9_\-$]*$/.test(prop);
    },

    /**
     * Surround value with a span, including the given className
     */
    decorateWithSpan: function(value, className) {
      return '' + this.htmlEncode(value) + '';
    },

    // Convert a basic JSON datatype (number, string, boolean, null, object, array) into an HTML fragment.
    valueToHTML: function(value, path) {
      var valueType = typeof value;

      if (value === null) {
        return this.decorateWithSpan('null', 'null');
      }
      else if (Array.isArray(value)) {
        return this.arrayToHTML(value, path);
      }
      else if (valueType == 'object') {
        return this.objectToHTML(value, path);
      }
      else if (valueType == 'number') {
        return this.decorateWithSpan(value, 'num');
      }
      else if (valueType == 'string') {
        if (/^(http|https|file):\/\/[^\s]+$/i.test(value)) {
          return '"' + this.jsString(value) + '"';
        } else {
          return '"' + this.jsString(value) + '"';
        }
      }
      else if (valueType == 'boolean') {
        return this.decorateWithSpan(value, 'bool');
      }

      return '';
    },

    // Convert an array into an HTML fragment
    arrayToHTML: function(json, path) {
      if (json.length === 0) {
        return '[ ]';
      }

      var output = '';
      for (var i = 0; i < json.length; i++) {
        var subPath = path + '[' + i + ']';
        output += '
' + this.valueToHTML(json[i], subPath);
        if (i < json.length - 1) {
          output += ',';
        }
        output += '
';
      }
      return '[
' + output + '
]';
    },

    // Convert a JSON object to an HTML fragment
    objectToHTML: function(json, path) {
      var numProps = Object.keys(json).length;
      if (numProps === 0) {
        return '{ }';
      }

      var output = '';
      for (var prop in json) {
        var subPath = '';
        var escapedProp = JSON.stringify(prop).slice(1, -1);
        var bare = this.isBareProp(prop);
        if (bare) {
          subPath = path + '.' + escapedProp;
        } else {
          escapedProp = '"' + escapedProp + '"';
        }
        output += '
"' + this.jsString(prop) +
          '": ' + this.valueToHTML(json[prop], subPath);
        if (numProps > 1) {
          output += ',';
        }
        output += '
';
        numProps--;
      }

      return '{
' + output + '
}';
    },

    // Convert a whole JSON value / JSONP response into a formatted HTML document
    jsonToHTML: function(json, callback, uri) {
      var output = '
' + this.valueToHTML(json, '<root>') + '
';
      if (callback) {
        output = '
' + callback + '(
' + output + '
)
';
      }
      return this.toHTML(output, uri);
    },

    // Clean up a JSON parsing error message
    massageError: function(error) {
      var message = error.message.replace(/^JSON.parse: /, '').replace(/of the JSON data/, '');
      var parts = /line (\d+) column (\d+)/.exec(message);

      return {
        message: this.htmlEncode(message),
        line: +parts[1],
        column: +parts[2]
      };
    },

    highlightError: function(data, lineNum, columnNum) {
      if (!lineNum || !columnNum) {
        return this.htmlEncode(data);
      }

      var lines = data.match(/^.*((\r\n|\n|\r)|$)/gm);

      var output = '';
      for (var i = 0; i < lines.length; i++) {
        var line = lines[i];

        if (i == lineNum - 1) {
          output += '';
          output += this.htmlEncode(line.substring(0, columnNum - 1)) + '' + this.htmlEncode(line[columnNum - 1]) + '' + this.htmlEncode(line.substring(columnNum));
          output += '';
        } else {
          output += this.htmlEncode(line);
        }
      }

      return output;
    },

    // Produce an error document for when parsing fails.
    errorPage: function(error, data, uri) {
      // Escape unicode nulls
      data = data.replace("\u0000","\uFFFD");

      var errorInfo = this.massageError(error);

      var output = '
' + _('errorParsing');
      if (errorInfo.message) {
        output += '
' + errorInfo.message + '
';
      }
      output += '

' + this.highlightError(data, errorInfo.line, errorInfo.column) + '
';
      return this.toHTML(output, uri + ' - Error');
    },

    // Wrap the HTML fragment in a full document. Used by jsonToHTML and errorPage.
    toHTML: function(content, title) {
      return '<!DOCTYPE html>\n' +
        '<meta charset="UTF-8"><title>' + this.htmlEncode(title) + '</title>' +
        '<link rel="stylesheet" type="text/css" href="' + safari.extension.baseURI + "default.css" + '">' +
        '' +
        content +
        '';
    }
  };

  // Sanitize & output -- all magic from JSONView Firefox
  this.jsonFormatter = new JSONFormatter();

  // This regex attempts to match a JSONP structure:
  //    * Any amount of whitespace (including unicode nonbreaking spaces) between the start of the file and the callback name
  //    * Callback name (any valid JavaScript function name according to ECMA-262 Edition 3 spec)
  //    * Any amount of whitespace (including unicode nonbreaking spaces)
  //    * Open parentheses
  //    * Any amount of whitespace (including unicode nonbreaking spaces)
  //    * Either { or [, the only two valid characters to start a JSON string.
  //    * Any character, any number of times
  //    * Either } or ], the only two valid closing characters of a JSON string.
  //    * Any amount of whitespace (including unicode nonbreaking spaces)
  //    * A closing parenthesis, an optional semicolon, and any amount of whitespace (including unicode nonbreaking spaces) until the end of the file.
  // This will miss anything that has comments, or more than one callback, or requires modification before use.
  var outputDoc = '';
  // text = text.match(jsonp_regex)[1];
  var cleanData = '',
      callback = '';

  var callback_results = jsonp_regex.exec(this.data);
  if( callback_results && callback_results.length == 3 ){
    // console.log("THIS IS JSONp");
    callback = callback_results[1];
    cleanData = callback_results[2];
  } else {
    // console.log("Vanilla JSON");
    cleanData = this.data;
  }
  // console.log(cleanData);

  // Covert, and catch exceptions on failure
  try {
    // var jsonObj = this.nativeJSON.decode(cleanData);
    var jsonObj = JSON.parse(cleanData);
    if ( jsonObj ) {
      outputDoc = this.jsonFormatter.jsonToHTML(jsonObj, callback, this.uri);
    } else {
      throw "There was no object!";
    }
  } catch(e) {
    // console.log(e);
    outputDoc = this.jsonFormatter.errorPage(e, this.data, this.uri);
  }
  // document.body.innerHTML = outputDoc;
  document.documentElement.innerHTML = outputDoc;

  //////////////////////////////////
  ////////BEGINS DEFAULT.JS/////////
  //////////////////////////////////

  // Click handler for collapsing and expanding objects and arrays
  function collapse(evt) {
    var collapser = evt.target;

    while (collapser && (!collapser.classList || !collapser.classList.contains('collapser'))) {
      collapser = collapser.nextSibling;
    }
    if (!collapser || !collapser.classList || !collapser.classList.contains('collapser')) {
      return;
    }

    evt.stopPropagation();

    collapser.classList.toggle('collapsed');

    var collapsible = collapser;
    while (collapsible && (!collapsible.classList || !collapsible.classList.contains('collapsible'))) {
      collapsible = collapsible.nextSibling;
    }
    collapsible.classList.toggle('collapsed');
  }

  /*
   * Collapses the whole json using keyboard
   * TODO: Add a navigator support for each of the elements
   */
  function collapseAll(evt) {
    var inputList;

    // Ignore anything paired with a modifier key. See https://github.com/bhollis/jsonview/issues/69
    if (evt.ctrlKey || evt.shiftKey || evt.altKey || evt.metaKey) {
      return;
    }

    if (evt.keyCode === 37) {  // Collapses the json on left arrow key up
      inputList = document.querySelectorAll('.collapsible, .collapser');
      for (var i = 0; i < inputList.length; i++) {
        if (inputList[i].parentNode.id != 'json') {
          inputList[i].classList.add('collapsed');
        }
      }
      evt.preventDefault();
    } else if (evt.keyCode === 39) { // Expands the json on right arrow key up
      inputList = document.querySelectorAll('.collapsed');
      for (var i = 0; i < inputList.length; i++) {
        inputList[i].classList.remove('collapsed');
      }
      evt.preventDefault();
    }
  }

  // collapse with event delegation
  document.addEventListener('click', collapse, false);
  document.addEventListener('keyup', collapseAll, false);

  //////////////////////////////////
  /////////ENDS DEFAULT.JS//////////
  //////////////////////////////////

  /**
  * Converts the markup to DOM nodes
  *
  * @private
  * @param {string|Markup} value The node
  * @return {Node}
  */
  function toDOM(value) {
    var wrapper = createElement('div');
    wrapper.innerHTML = ''+value;

    // trim extraneous whitespace
    trimWhitespace(wrapper);

    // eliminate wrapper for single nodes
    if (wrapper.childNodes.length === 1) {
      return wrapper.firstChild;
    }

    // create a document fragment to hold elements
    var frag = createElement('');
    while (wrapper.firstChild) {
      frag.appendChild(wrapper.firstChild);
    }
    return frag;
  }

}else {
  // console.log("JSONView: this is not json, not formatting.");
}
<commit_msg>fix html tags not showing<commit_after>this.data = document.body.innerHTML;
this.uri = document.location.href;

if(/^\
(.*)\n?\<\/pre\>$/.test(this.data)){
  // console.log("JSONView: data is wrapped in
...
, stripping HTML...");
  this.data = this.data.replace(/<(?:.|\s)*?>/g, ''); //Aggressively strip HTML.
}

var json_regex = /^\s*([\[\{].*[\}\]])\s*$/; // Ghetto, but it works
var jsonp_regex = /^[\s\u200B\uFEFF]*([\w$\[\]\.]+)[\s\u200B\uFEFF]*\([\s\u200B\uFEFF]*([\[{][\s\S]*[\]}])[\s\u200B\uFEFF]*\);?[\s\u200B\uFEFF]*$/;
var jsonp_regex2 = /([\[\{][\s\S]*[\]\}])\)/; // more liberal support... this allows us to pass the jsonp.json & jsonp2.json tests
var is_json = json_regex.test(this.data);
var is_jsonp = jsonp_regex.test(this.data);
// console.log("JSONView: is_json="+is_json+" is_jsonp="+is_jsonp);

if(is_json || is_jsonp){
  /*
   * The JSONFormatter helper object. This contains two major functions, jsonToHTML and errorPage,
   * each of which returns an HTML document.
   */
  function JSONFormatter() { }

  JSONFormatter.prototype = {
    /**
     * Completely escape a json string
     */
    jsString: function(s) {
      // Slice off the surrounding quotes
      s = JSON.stringify(s).slice(1, -1);
      return s;
    },

    /**
     * Is this a valid "bare" property name?
     */
    isBareProp: function(prop) {
      return /^[A-Za-z_$][A-Za-z0-9_\-$]*$/.test(prop);
    },

    /**
     * Surround value with a span, including the given className
     */
    decorateWithSpan: function(value, className) {
      return '' + value + '';
    },

    // Convert a basic JSON datatype (number, string, boolean, null, object, array) into an HTML fragment.
    valueToHTML: function(value, path) {
      var valueType = typeof value;

      if (value === null) {
        return this.decorateWithSpan('null', 'null');
      }
      else if (Array.isArray(value)) {
        return this.arrayToHTML(value, path);
      }
      else if (valueType == 'object') {
        return this.objectToHTML(value, path);
      }
      else if (valueType == 'number') {
        return this.decorateWithSpan(value, 'num');
      }
      else if (valueType == 'string') {
        if (/^(http|https|file):\/\/[^\s]+$/i.test(value)) {
          return '"' + this.jsString(value) + '"';
        } else {
          return '"' + this.jsString(value) + '"';
        }
      }
      else if (valueType == 'boolean') {
        return this.decorateWithSpan(value, 'bool');
      }

      return '';
    },

    // Convert an array into an HTML fragment
    arrayToHTML: function(json, path) {
      if (json.length === 0) {
        return '[ ]';
      }

      var output = '';
      for (var i = 0; i < json.length; i++) {
        var subPath = path + '[' + i + ']';
        output += '
' + this.valueToHTML(json[i], subPath);
        if (i < json.length - 1) {
          output += ',';
        }
        output += '
';
      }
      return '[
' + output + '
]';
    },

    // Convert a JSON object to an HTML fragment
    objectToHTML: function(json, path) {
      var numProps = Object.keys(json).length;
      if (numProps === 0) {
        return '{ }';
      }

      var output = '';
      for (var prop in json) {
        var subPath = '';
        var escapedProp = JSON.stringify(prop).slice(1, -1);
        var bare = this.isBareProp(prop);
        if (bare) {
          subPath = path + '.' + escapedProp;
        } else {
          escapedProp = '"' + escapedProp + '"';
        }
        output += '
"' + this.jsString(prop) +
          '": ' + this.valueToHTML(json[prop], subPath);
        if (numProps > 1) {
          output += ',';
        }
        output += '
';
        numProps--;
      }

      return '{
' + output + '
}';
    },

    // Convert a whole JSON value / JSONP response into a formatted HTML document
    jsonToHTML: function(json, callback, uri) {
      var output = '
' + this.valueToHTML(json, '<root>') + '
';
      if (callback) {
        output = '
' + callback + '(
' + output + '
)
';
      }
      return this.toHTML(output, uri);
    },

    // Clean up a JSON parsing error message
    massageError: function(error) {
      var message = error.message.replace(/^JSON.parse: /, '').replace(/of the JSON data/, '');
      var parts = /line (\d+) column (\d+)/.exec(message);

      return {
        message: message,
        line: +parts[1],
        column: +parts[2]
      };
    },

    highlightError: function(data, lineNum, columnNum) {
      if (!lineNum || !columnNum) {
        return data;
      }

      var lines = data.match(/^.*((\r\n|\n|\r)|$)/gm);

      var output = '';
      for (var i = 0; i < lines.length; i++) {
        var line = lines[i];

        if (i == lineNum - 1) {
          output += '';
          output += line.substring(0, columnNum - 1) + '' + line[columnNum - 1] + '' + line.substring(columnNum);
          output += '';
        } else {
          output += line;
        }
      }

      return output;
    },

    // Produce an error document for when parsing fails.
    errorPage: function(error, data, uri) {
      // Escape unicode nulls
      data = data.replace("\u0000","\uFFFD");

      var errorInfo = this.massageError(error);

      var output = '
' + _('errorParsing');
      if (errorInfo.message) {
        output += '
' + errorInfo.message + '
';
      }
      output += '

' + this.highlightError(data, errorInfo.line, errorInfo.column) + '
';
      return this.toHTML(output, uri + ' - Error');
    },

    // Wrap the HTML fragment in a full document. Used by jsonToHTML and errorPage.
    toHTML: function(content, title) {
      return '<!DOCTYPE html>\n' +
        '<meta charset="UTF-8"><title>' + title + '</title>' +
        '<link rel="stylesheet" type="text/css" href="' + safari.extension.baseURI + "default.css" + '">' +
        '' +
        content +
        '';
    }
  };

  // Sanitize & output -- all magic from JSONView Firefox
  this.jsonFormatter = new JSONFormatter();

  // This regex attempts to match a JSONP structure:
  //    * Any amount of whitespace (including unicode nonbreaking spaces) between the start of the file and the callback name
  //    * Callback name (any valid JavaScript function name according to ECMA-262 Edition 3 spec)
  //    * Any amount of whitespace (including unicode nonbreaking spaces)
  //    * Open parentheses
  //    * Any amount of whitespace (including unicode nonbreaking spaces)
  //    * Either { or [, the only two valid characters to start a JSON string.
  //    * Any character, any number of times
  //    * Either } or ], the only two valid closing characters of a JSON string.
  //    * Any amount of whitespace (including unicode nonbreaking spaces)
  //    * A closing parenthesis, an optional semicolon, and any amount of whitespace (including unicode nonbreaking spaces) until the end of the file.
  // This will miss anything that has comments, or more than one callback, or requires modification before use.
  var outputDoc = '';
  // text = text.match(jsonp_regex)[1];
  var cleanData = '',
      callback = '';

  var callback_results = jsonp_regex.exec(this.data);
  if( callback_results && callback_results.length == 3 ){
    // console.log("THIS IS JSONp");
    callback = callback_results[1];
    cleanData = callback_results[2];
  } else {
    // console.log("Vanilla JSON");
    cleanData = this.data;
  }
  // console.log(cleanData);

  // Covert, and catch exceptions on failure
  try {
    // var jsonObj = this.nativeJSON.decode(cleanData);
    var jsonObj = JSON.parse(cleanData);
    if ( jsonObj ) {
      outputDoc = this.jsonFormatter.jsonToHTML(jsonObj, callback, this.uri);
    } else {
      throw "There was no object!";
    }
  } catch(e) {
    // console.log(e);
    outputDoc = this.jsonFormatter.errorPage(e, this.data, this.uri);
  }
  // document.body.innerHTML = outputDoc;
  document.documentElement.innerHTML = outputDoc;

  //////////////////////////////////
  ////////BEGINS DEFAULT.JS/////////
  //////////////////////////////////

  // Click handler for collapsing and expanding objects and arrays
  function collapse(evt) {
    var collapser = evt.target;

    while (collapser && (!collapser.classList || !collapser.classList.contains('collapser'))) {
      collapser = collapser.nextSibling;
    }
    if (!collapser || !collapser.classList || !collapser.classList.contains('collapser')) {
      return;
    }

    evt.stopPropagation();

    collapser.classList.toggle('collapsed');

    var collapsible = collapser;
    while (collapsible && (!collapsible.classList || !collapsible.classList.contains('collapsible'))) {
      collapsible = collapsible.nextSibling;
    }
    collapsible.classList.toggle('collapsed');
  }

  /*
   * Collapses the whole json using keyboard
   * TODO: Add a navigator support for each of the elements
   */
  function collapseAll(evt) {
    var inputList;

    // Ignore anything paired with a modifier key. See https://github.com/bhollis/jsonview/issues/69
    if (evt.ctrlKey || evt.shiftKey || evt.altKey || evt.metaKey) {
      return;
    }

    if (evt.keyCode === 37) {  // Collapses the json on left arrow key up
      inputList = document.querySelectorAll('.collapsible, .collapser');
      for (var i = 0; i < inputList.length; i++) {
        if (inputList[i].parentNode.id != 'json') {
          inputList[i].classList.add('collapsed');
        }
      }
      evt.preventDefault();
    } else if (evt.keyCode === 39) { // Expands the json on right arrow key up
      inputList = document.querySelectorAll('.collapsed');
      for (var i = 0; i < inputList.length; i++) {
        inputList[i].classList.remove('collapsed');
      }
      evt.preventDefault();
    }
  }

  // collapse with event delegation
  document.addEventListener('click', collapse, false);
  document.addEventListener('keyup', collapseAll, false);

  //////////////////////////////////
  /////////ENDS DEFAULT.JS//////////
  //////////////////////////////////

  /**
  * Converts the markup to DOM nodes
  *
  * @private
  * @param {string|Markup} value The node
  * @return {Node}
  */
  function toDOM(value) {
    var wrapper = createElement('div');
    wrapper.innerHTML = ''+value;

    // trim extraneous whitespace
    trimWhitespace(wrapper);

    // eliminate wrapper for single nodes
    if (wrapper.childNodes.length === 1) {
      return wrapper.firstChild;
    }

    // create a document fragment to hold elements
    var frag = createElement('');
    while (wrapper.firstChild) {
      frag.appendChild(wrapper.firstChild);
    }
    return frag;
  }

}else {
  // console.log("JSONView: this is not json, not formatting.");
}
<|endoftext|>


<commit_before>
import gulp       from 'gulp'
import gutil      from 'gulp-util'
import program    from 'commander'
import co         from 'co'
import fs         from 'fs'
import promisify  from 'es6-promisify'
import merge      from 'merge-stream'
import map        from 'map-stream'
import endpoint   from 'endpoint'
import Throat     from 'throat'
import { cpus }   from 'os'
import { spawn }  from 'child_process'
import { join }   from 'path'

import BemusePack from './bemuse-pack'

let bail = error => setTimeout(() => { throw error })

program
.version(require('../package.json').version)
.usage('[options] <directory> <output.bemuse>')
.parse(process.argv)

if (program.args.length === 2) {
  packIntoBemuse(program.args[0], program.args[1].replace(/\.bemuse$/i, ''))
  .then(() => gutil.log('converted successfully'), bail)
} else {
  console.error('Error: 2 arguments expected')
  program.outputHelp()
}

function packIntoBemuse(dir, out) {
  return co(function*() {

    let stat = yield promisify(fs.stat)(dir)
    if (!stat.isDirectory()) throw new Error('Not a directory: ' + dir)

    let path = (...components) => join(dir, ...components)
    let src = (pattern, options={ }) =>
                gulp.src(path(pattern),
                  Object.assign({ nocase: true, base: dir }, options))

    let files = merge(
      src('*.{bms,bme,bml,pms}')
        .pipe(tagType('bms')),
      src('*.mp3')
        .pipe(tagType('sound')),
      src('*.{wav,ogg}', { read: false })
        .pipe(convertAudio())
        .pipe(tagType('sound'))
    )

    let stream = merge(files)
      .pipe(bemusePack(out))

    yield waitStream(stream)

  })
}

function tagType(type) {
  return map(function(file, cb) {
    file.assetType = type
    cb(null, file)
  })
}

function waitStream(stream) {
  return new Promise((resolve, reject) => {
    stream.on('end', resolve)
    stream.on('error', reject)
  })
}

function convertAudio() {
  let throat = new Throat(cpus().length || 1)
  return map(function(file, callback) {
    let path = file.path
    let oldName = file.relative
    file.path = file.path.replace(/\.\w+$/, '.mp3')
    let log = gutil.log.bind(gutil, '[convertAudio]',
                oldName, '->', file.relative)
    throat(() => new Promise(function(resolve, reject) {
      let sox = spawn('sox', [path, '-t', 'mp3', '-'])
      sox.stdin.end()
      sox.stderr.on('data', x => process.stderr.write(x))
      sox.stdout.pipe(endpoint(function(err, buffer) {
        if (err) {
          log('ERROR!')
          return reject(err)
        }
        log('OK')
        file.contents = buffer
        resolve(file)
      }))
    }))
    .then(
      result => callback(null, result),
      error => callback(error)
    )
  })
}

function bemusePack(out) {
  let result = new BemusePack(out)
  return map(function(file, callback) {
    result.add(file)
    callback()
  })
  .on('end', function() {
    result.write().catch(bail)
  })
}
<commit_msg>chore(bemusepack): rename type "sound" to "snd"<commit_after>
import gulp       from 'gulp'
import gutil      from 'gulp-util'
import program    from 'commander'
import co         from 'co'
import fs         from 'fs'
import promisify  from 'es6-promisify'
import merge      from 'merge-stream'
import map        from 'map-stream'
import endpoint   from 'endpoint'
import Throat     from 'throat'
import { cpus }   from 'os'
import { spawn }  from 'child_process'
import { join }   from 'path'

import BemusePack from './bemuse-pack'

let bail = error => setTimeout(() => { throw error })

program
.version(require('../package.json').version)
.usage('[options] <directory> <output.bemuse>')
.parse(process.argv)

if (program.args.length === 2) {
  packIntoBemuse(program.args[0], program.args[1].replace(/\.bemuse$/i, ''))
  .then(() => gutil.log('converted successfully'), bail)
} else {
  console.error('Error: 2 arguments expected')
  program.outputHelp()
}

function packIntoBemuse(dir, out) {
  return co(function*() {

    let stat = yield promisify(fs.stat)(dir)
    if (!stat.isDirectory()) throw new Error('Not a directory: ' + dir)

    let path = (...components) => join(dir, ...components)
    let src = (pattern, options={ }) =>
                gulp.src(path(pattern),
                  Object.assign({ nocase: true, base: dir }, options))

    let files = merge(
      src('*.{bms,bme,bml,pms}')
        .pipe(tagType('bms')),
      src('*.mp3')
        .pipe(tagType('snd')),
      src('*.{wav,ogg}', { read: false })
        .pipe(convertAudio())
        .pipe(tagType('snd'))
    )

    let stream = merge(files)
      .pipe(bemusePack(out))

    yield waitStream(stream)

  })
}

function tagType(type) {
  return map(function(file, cb) {
    file.assetType = type
    cb(null, file)
  })
}

function waitStream(stream) {
  return new Promise((resolve, reject) => {
    stream.on('end', resolve)
    stream.on('error', reject)
  })
}

function convertAudio() {
  let throat = new Throat(cpus().length || 1)
  return map(function(file, callback) {
    let path = file.path
    let oldName = file.relative
    file.path = file.path.replace(/\.\w+$/, '.mp3')
    let log = gutil.log.bind(gutil, '[convertAudio]',
                oldName, '->', file.relative)
    throat(() => new Promise(function(resolve, reject) {
      let sox = spawn('sox', [path, '-t', 'mp3', '-'])
      sox.stdin.end()
      sox.stderr.on('data', x => process.stderr.write(x))
      sox.stdout.pipe(endpoint(function(err, buffer) {
        if (err) {
          log('ERROR!')
          return reject(err)
        }
        log('OK')
        file.contents = buffer
        resolve(file)
      }))
    }))
    .then(
      result => callback(null, result),
      error => callback(error)
    )
  })
}

function bemusePack(out) {
  let result = new BemusePack(out)
  return map(function(file, callback) {
    result.add(file)
    callback()
  })
  .on('end', function() {
    result.write().catch(bail)
  })
}
<|endoftext|>


<commit_before>'use strict';

const Codec = require('../codec');

const bknHash = function (skey, init_str = 5381) {
    let hash_str = init_str;
    skey.split('').forEach(ch => {
        hash_str += (hash_str << 5) + ch.charCodeAt();
    });
    hash_str = hash_str & 2147483647;
    return hash_str;
};

module.exports = {
    loginPrepare: 'https://ui.ptlogin2.qq.com/cgi-bin/login?daid=164&target=self&style=16&mibao_css=m_webqq&appid=501004106&enable_qlogin=0&no_verifyimg=1&s_url=http%3A%2F%2Fw.qq.com%2Fproxy.html&f_url=loginerroralert&strong_login=1&login_state=10&t=20131024001',
    get qrcode() {
        return `https://ssl.ptlogin2.qq.com/ptqrshow?appid=501004106&e=0&l=M&s=5&d=72&v=4&t=${Date.now()}`;
    },
    getPtqrloginURL(qrsig) {
        const decoded = Codec.decodeQrsig(qrsig);
        return `https://ssl.ptlogin2.qq.com/ptqrlogin?ptqrtoken=${decoded}&webqq_type=10&remember_uin=1&login2qq=1&aid=501004106&u1=http%3A%2F%2Fw.qq.com%2Fproxy.html%3Flogin2qq%3D1%26webqq_type%3D10&ptredirect=0&ptlang=2052&daid=164&from_ui=1&pttype=1&dumy=&fp=loginerroralert&action=0-0-123332&mibao_css=m_webqq&t=undefined&g=1&js_type=0&js_ver=10141&login_sig=&pt_randsalt=0`;
    },
    getVfwebqqURL: ptwebqq => `https://s.web2.qq.com/api/getvfwebqq?ptwebqq=${ptwebqq}&clientid=53999199&psessionid=&t=${Date.now()}`,
    login2: 'https://d1.web2.qq.com/channel/login2',
    originD1: 'https://d1.web2.qq.com',
    originS2: 'https://s.web2.qq.com',
    referer151105: 'https://d1.web2.qq.com/proxy.html?v=20151105001&callback=1&id=2',
    refererc151105: 'https://d1.web2.qq.com/cfproxy.html?v=20151105001&callback=1',
    referer130916: 'https://s.web2.qq.com/proxy.html?v=20130916001&callback=1&id=1',
    recentList: 'https://d1.web2.qq.com/channel/get_recent_list2',
    selfInfo: `https://s.web2.qq.com/api/get_self_info2?t=${Date.now()}`,
    poll: 'https://d1.web2.qq.com/channel/poll2',
    buddyMsg: 'https://d1.web2.qq.com/channel/send_buddy_msg2',
    groupMsg: 'https://d1.web2.qq.com/channel/send_qun_msg2',
    discuMsg: 'https://d1.web2.qq.com/channel/send_discu_msg2',
    getBuddy: 'https://s.web2.qq.com/api/get_user_friends2',
    onlineBuddies: (vfwebqq, psessionid) => `https://d1.web2.qq.com/channel/get_online_buddies2?vfwebqq=${vfwebqq}&clientid=53999199&psessionid=${psessionid}&t=${Date.now()}`,
    buddyInfo: (uin, vfwebqq, psessionid) => `https://s.web2.qq.com/api/get_friend_info2?tuin=${uin}&vfwebqq=${vfwebqq}&clientid=53999199&psessionid=${psessionid}&t=${Date.now()}`,
    buddyQQID: (uin, vfwebqq) => `https://s.web2.qq.com/api/get_friend_uin2?tuid=${uin}&type=1&vfwebqq=${vfwebqq}&t=${Date.now()}`,
    getDiscu: (vfwebqq, psessionid) => `https://s.web2.qq.com/api/get_discus_list?clientid=53999199&psessionid=${psessionid}&vfwebqq=${vfwebqq}&t=${Date.now()}`,
    discuInfo: (discuss_id, psessionid, vfwebqq) => `https://d1.web2.qq.com/channel/get_discu_info?did=${discuss_id}&psessionid=${psessionid}&vfwebqq=${vfwebqq}&clientid=53999199&t=${Date.now()}`,
    getGroup: 'https://s.web2.qq.com/api/get_group_name_list_mask2',
    groupInfo: (group_code, vfwebqq) => `https://s.web2.qq.com/api/get_group_info_ext2?gcode=${group_code}&vfwebqq=${vfwebqq}&t=${Date.now()}`,
    // 获取好友qq号码
    buddyGroupInfo: (skey) => `https://qun.qq.com/cgi-bin/qun_mgr/get_friend_list?bkn=${bknHash(skey)}`,
    refererQun: 'https://qun.qq.com/member.html'
};
<commit_msg>url: update ptqrlogin url, close #30<commit_after>'use strict';

const Codec = require('../codec');

const bknHash = function (skey, init_str = 5381) {
    let hash_str = init_str;
    skey.split('').forEach(ch => {
        hash_str += (hash_str << 5) + ch.charCodeAt();
    });
    hash_str = hash_str & 2147483647;
    return hash_str;
};

module.exports = {
    loginPrepare: 'https://ui.ptlogin2.qq.com/cgi-bin/login?daid=164&target=self&style=16&mibao_css=m_webqq&appid=501004106&enable_qlogin=0&no_verifyimg=1&s_url=http%3A%2F%2Fw.qq.com%2Fproxy.html&f_url=loginerroralert&strong_login=1&login_state=10&t=20131024001',
    get qrcode() {
        return `https://ssl.ptlogin2.qq.com/ptqrshow?appid=501004106&e=0&l=M&s=5&d=72&v=4&t=${Date.now()}`;
    },
    getPtqrloginURL(qrsig) {
        const decoded = Codec.decodeQrsig(qrsig);
        return `https://ssl.ptlogin2.qq.com/ptqrlogin?ptqrtoken=${decoded}&webqq_type=10&remember_uin=1&login2qq=1&aid=501004106&u1=http%3A%2F%2Fw.qq.com%2Fproxy.html%3Flogin2qq%3D1%26webqq_type%3D10&ptredirect=0&ptlang=2052&daid=164&from_ui=1&pttype=1&dumy=&fp=loginerroralert&action=0-0-12038&mibao_css=m_webqq&t=undefined&g=1&js_type=0&js_ver=10203&login_sig=&pt_randsalt=2`;
    },
    getVfwebqqURL: ptwebqq => `https://s.web2.qq.com/api/getvfwebqq?ptwebqq=${ptwebqq}&clientid=53999199&psessionid=&t=${Date.now()}`,
    login2: 'https://d1.web2.qq.com/channel/login2',
    originD1: 'https://d1.web2.qq.com',
    originS2: 'https://s.web2.qq.com',
    referer151105: 'https://d1.web2.qq.com/proxy.html?v=20151105001&callback=1&id=2',
    refererc151105: 'https://d1.web2.qq.com/cfproxy.html?v=20151105001&callback=1',
    referer130916: 'https://s.web2.qq.com/proxy.html?v=20130916001&callback=1&id=1',
    recentList: 'https://d1.web2.qq.com/channel/get_recent_list2',
    selfInfo: `https://s.web2.qq.com/api/get_self_info2?t=${Date.now()}`,
    poll: 'https://d1.web2.qq.com/channel/poll2',
    buddyMsg: 'https://d1.web2.qq.com/channel/send_buddy_msg2',
    groupMsg: 'https://d1.web2.qq.com/channel/send_qun_msg2',
    discuMsg: 'https://d1.web2.qq.com/channel/send_discu_msg2',
    getBuddy: 'https://s.web2.qq.com/api/get_user_friends2',
    onlineBuddies: (vfwebqq, psessionid) => `https://d1.web2.qq.com/channel/get_online_buddies2?vfwebqq=${vfwebqq}&clientid=53999199&psessionid=${psessionid}&t=${Date.now()}`,
    buddyInfo: (uin, vfwebqq, psessionid) => `https://s.web2.qq.com/api/get_friend_info2?tuin=${uin}&vfwebqq=${vfwebqq}&clientid=53999199&psessionid=${psessionid}&t=${Date.now()}`,
    buddyQQID: (uin, vfwebqq) => `https://s.web2.qq.com/api/get_friend_uin2?tuid=${uin}&type=1&vfwebqq=${vfwebqq}&t=${Date.now()}`,
    getDiscu: (vfwebqq, psessionid) => `https://s.web2.qq.com/api/get_discus_list?clientid=53999199&psessionid=${psessionid}&vfwebqq=${vfwebqq}&t=${Date.now()}`,
    discuInfo: (discuss_id, psessionid, vfwebqq) => `https://d1.web2.qq.com/channel/get_discu_info?did=${discuss_id}&psessionid=${psessionid}&vfwebqq=${vfwebqq}&clientid=53999199&t=${Date.now()}`,
    getGroup: 'https://s.web2.qq.com/api/get_group_name_list_mask2',
    groupInfo: (group_code, vfwebqq) => `https://s.web2.qq.com/api/get_group_info_ext2?gcode=${group_code}&vfwebqq=${vfwebqq}&t=${Date.now()}`,
    // 获取好友qq号码
    buddyGroupInfo: (skey) => `https://qun.qq.com/cgi-bin/qun_mgr/get_friend_list?bkn=${bknHash(skey)}`,
    refererQun: 'https://qun.qq.com/member.html'
};
<|endoftext|>


<commit_before>var sprites = {};
var spritesArray = [];

//sprite object constructor
function Sprite(x, y, value) {
    this.x = x;
    this.y = y;
    this.direction = 0;
    spritesArray.push(this);

    //updates both x and y
    this.updateLocation = function () {
        this.element.style.left = (originOffsetX + this.x) + "px";
        this.element.style.top = (originOffsetY - this.y) + "px";
    };

    //updates only x
    this.updateX = function () {
        this.element.style.left = (originOffsetX + this.x) + "px";
    };

    //updates only y
    this.updateY = function () {
        this.element.style.top = (originOffsetY - this.y) + "px";
    };

    this.updateRotation = function () {
        //by default turns clockwise, added "-" to make it turn counterclockwise like in geometry
        this.element.style.transform = "rotate(" + (this.direction * -1) + "deg)";
    };

    //hack of a hack of a solution, but still works. Regex checks if value is an html tag
    var valueIsHtmlTag = (/<(br|basefont|hr|input|source|frame|param|area|meta|!--|col|link|option|base|img|wbr|!DOCTYPE).*?>|<(a|abbr|acronym|address|applet|article|aside|audio|b|bdi|bdo|big|blockquote|body|button|canvas|caption|center|cite|code|colgroup|command|datalist|dd|del|details|dfn|dialog|dir|div|dl|dt|em|embed|fieldset|figcaption|figure|font|footer|form|frameset|head|header|hgroup|h1|h2|h3|h4|h5|h6|html|i|iframe|ins|kbd|keygen|label|legend|li|map|mark|menu|meter|nav|noframes|noscript|object|ol|optgroup|output|p|pre|progress|q|rp|rt|ruby|s|samp|script|section|select|small|span|strike|strong|style|sub|summary|sup|table|tbody|td|textarea|tfoot|th|thead|time|title|tr|track|tt|u|ul|var|video).*?<\/\2>/i.test(value));

    if (valueIsHtmlTag) {
        //if value is an html tag name
        var containingDiv = document.createElement("div");
        containingDiv.innerHTML = value;
        this.element = containingDiv.firstChild;
        this.updateLocation();
        document.body.appendChild(containingDiv);
    } else if (value === undefined) {
        console.error("Please enter a value for the new sprite(3rd argument)")
    } else {
        //value is not html or error so custom sprite, use value as img src
        this.element = document.createElement("img");
        this.element.src = value;
        this.updateLocation();
        document.body.appendChild(this.element);
    }

    this.goTo = function () {
        if (arguments[1]) {
            //two arguments provided, the arguments are expected to be x and y respectively. go to this x and y position
            this.x = arguments[0];
            this.y = arguments[1];
            this.updateLocation();
        } else if (arguments[0]) {
            //only one argument provided, expected to be sprite. go to that sprites position
            var spriteToGoTo = arguments[0];
            this.x = spriteToGoTo.x;
            this.y = spriteToGoTo.y;
            this.updateLocation();
        }
    };

    //sets the x of the sprite
    this.setXTo = function (newX) {
        this.x = newX;
        this.updateX();
    };

    //sets the y of the sprite
    this.setYTo = function (newY) {
        this.y = newY;
        this.updateY();
    };

    //changes the x of the sprite by an amount
    this.changeXBy = function (deltaX) {
        this.x += deltaX;
        this.updateX();
    };

    //changes the x of the sprite by an amount
    this.changeYBy = function (deltaY) {
        this.y += deltaY;
        this.updateY();
    };

    this.turn = function (degrees) {
        this.direction += degrees;
        this.updateRotation();
    };

    this.pointInDirection = function (direction) {
        this.direction = direction;
        this.updateRotation();
    };

    this.move = function (amount) {
        var deltaX = Math.cos(this.direction * Math.PI / 180) * amount;
        var deltaY = Math.sin(this.direction * Math.PI / 180) * amount;
        this.x += deltaX;
        this.y += deltaY;
        this.updateLocation();
    };

    this.distanceTo = function () {
        if (arguments[1]) {
            //if two arguments are provided the two arguments must be x, y coordinates
            return calculateDistance(this.x, this.y, arguments[0], arguments[1]);
        } else {
            //if only one argument, argument must be a sprite
            return calculateDistance(this.x, this.y, arguments[0].x, arguments[0].y)
        }
    }
}

function calculateDistance(x1, y1, x2, y2) {
    //simple pythagorean theorem to find distance between points
    return Math.sqrt(((x1 - x2) * (x1 - x2)) + ((y1 - y2) * (y1 - y2)))
}

function repeat(times, callback) {
    for (var i = 0; i < times; i++) {
        callback();
    }
}

function wait(seconds, callback) {
    setTimeout(callback, seconds);
}

//use of forever is slow and not recommended, use while loop instead
function forever(callback) {
    return setInterval(function () {
        callback();
    }, 1);
}

function stop(intervalToStop) {
    clearInterval(intervalToStop);
}

function ask(text) {
    return prompt(text);
}

var whenPageLoads = function () {
};

var originOffsetX;
var originOffsetY;
var maxX;
var maxY;
window.onload = function () {
    originOffsetX = window.innerWidth / 2;
    originOffsetY = window.innerHeight / 2;
    maxX = originOffsetX;
    maxY = originOffsetY;
    whenPageLoads();
};

window.onresize = function () {
    originOffsetX = window.innerWidth / 2;
    originOffsetY = window.innerHeight / 2;
    maxX = originOffsetX;
    maxY = originOffsetY;
    /*
     for(var sprite in sprites){
     sprites[sprite].updateLocation();
     }
     */
    for (var sprite of spritesArray) {
        sprite.updateLocation();
    }
};<commit_msg>Now sprites don't need to be added to an object, they can be saved to any varaible<commit_after>var spritesArray = [];

//sprite object constructor
function Sprite(x, y, value) {
    this.x = x;
    this.y = y;
    this.direction = 0;
    spritesArray.push(this);

    //updates both x and y
    this.updateLocation = function () {
        this.element.style.left = (originOffsetX + this.x) + "px";
        this.element.style.top = (originOffsetY - this.y) + "px";
    };

    //updates only x
    this.updateX = function () {
        this.element.style.left = (originOffsetX + this.x) + "px";
    };

    //updates only y
    this.updateY = function () {
        this.element.style.top = (originOffsetY - this.y) + "px";
    };

    this.updateRotation = function () {
        //by default turns clockwise, added "-" to make it turn counterclockwise like in geometry
        this.element.style.transform = "rotate(" + (this.direction * -1) + "deg)";
    };

    //hack of a hack of a solution, but still works. Regex checks if value is an html tag
    var valueIsHtmlTag = (/<(br|basefont|hr|input|source|frame|param|area|meta|!--|col|link|option|base|img|wbr|!DOCTYPE).*?>|<(a|abbr|acronym|address|applet|article|aside|audio|b|bdi|bdo|big|blockquote|body|button|canvas|caption|center|cite|code|colgroup|command|datalist|dd|del|details|dfn|dialog|dir|div|dl|dt|em|embed|fieldset|figcaption|figure|font|footer|form|frameset|head|header|hgroup|h1|h2|h3|h4|h5|h6|html|i|iframe|ins|kbd|keygen|label|legend|li|map|mark|menu|meter|nav|noframes|noscript|object|ol|optgroup|output|p|pre|progress|q|rp|rt|ruby|s|samp|script|section|select|small|span|strike|strong|style|sub|summary|sup|table|tbody|td|textarea|tfoot|th|thead|time|title|tr|track|tt|u|ul|var|video).*?<\/\2>/i.test(value));

    if (valueIsHtmlTag) {
        //if value is an html tag name
        var containingDiv = document.createElement("div");
        containingDiv.innerHTML = value;
        this.element = containingDiv.firstChild;
        this.updateLocation();
        document.body.appendChild(containingDiv);
    } else if (value === undefined) {
        console.error("Please enter a value for the new sprite(3rd argument)")
    } else {
        //value is not html or error so custom sprite, use value as img src
        this.element = document.createElement("img");
        this.element.src = value;
        this.updateLocation();
        document.body.appendChild(this.element);
    }

    this.goTo = function () {
        if (arguments[1]) {
            //two arguments provided, the arguments are expected to be x and y respectively. go to this x and y position
            this.x = arguments[0];
            this.y = arguments[1];
            this.updateLocation();
        } else if (arguments[0]) {
            //only one argument provided, expected to be sprite. go to that sprites position
            var spriteToGoTo = arguments[0];
            this.x = spriteToGoTo.x;
            this.y = spriteToGoTo.y;
            this.updateLocation();
        }
    };

    //sets the x of the sprite
    this.setXTo = function (newX) {
        this.x = newX;
        this.updateX();
    };

    //sets the y of the sprite
    this.setYTo = function (newY) {
        this.y = newY;
        this.updateY();
    };

    //changes the x of the sprite by an amount
    this.changeXBy = function (deltaX) {
        this.x += deltaX;
        this.updateX();
    };

    //changes the x of the sprite by an amount
    this.changeYBy = function (deltaY) {
        this.y += deltaY;
        this.updateY();
    };

    this.turn = function (degrees) {
        this.direction += degrees;
        this.updateRotation();
    };

    this.pointInDirection = function (direction) {
        this.direction = direction;
        this.updateRotation();
    };

    this.move = function (amount) {
        var deltaX = Math.cos(this.direction * Math.PI / 180) * amount;
        var deltaY = Math.sin(this.direction * Math.PI / 180) * amount;
        this.x += deltaX;
        this.y += deltaY;
        this.updateLocation();
    };

    this.distanceTo = function () {
        if (arguments[1]) {
            //if two arguments are provided the two arguments must be x, y coordinates
            return calculateDistance(this.x, this.y, arguments[0], arguments[1]);
        } else {
            //if only one argument, argument must be a sprite
            return calculateDistance(this.x, this.y, arguments[0].x, arguments[0].y)
        }
    }

    return this;
}

function calculateDistance(x1, y1, x2, y2) {
    //simple pythagorean theorem to find distance between points
    return Math.sqrt(((x1 - x2) * (x1 - x2)) + ((y1 - y2) * (y1 - y2)))
}

function repeat(times, callback) {
    for (var i = 0; i < times; i++) {
        callback();
    }
}

function wait(seconds, callback) {
    setTimeout(callback, seconds);
}

//use of forever is slow and not recommended, use while loop instead
function forever(callback) {
    return setInterval(function () {
        callback();
    }, 1);
}

function stop(intervalToStop) {
    clearInterval(intervalToStop);
}

function ask(text) {
    return prompt(text);
}

var whenPageLoads = function () {
};

var originOffsetX;
var originOffsetY;
var maxX;
var maxY;
window.onload = function () {
    originOffsetX = window.innerWidth / 2;
    originOffsetY = window.innerHeight / 2;
    maxX = originOffsetX;
    maxY = originOffsetY;
    whenPageLoads();
};

window.onresize = function () {
    originOffsetX = window.innerWidth / 2;
    originOffsetY = window.innerHeight / 2;
    maxX = originOffsetX;
    maxY = originOffsetY;
    /*
     for(var sprite in sprites){
     sprites[sprite].updateLocation();
     }
     */
    for (var sprite of spritesArray) {
        sprite.updateLocation();
    }
};<|endoftext|>


<commit_before>import { distance } from './aim';

function inside(source, targetMin, targetMax) {
  if (source >= targetMin && source <= targetMax) return 0;
  else if (source > targetMin) return -1;
  else return 1;
}

export function corners(source, target) {
  source = { left: source.pageX, top: source.pageY };
  target = target.getBoundingClientRect();

  let ver, hor;

  hor = inside(source.left, target.left, target.left + target.width);
  ver = inside(source.top, target.top, target.top + target.height);

  if (hor === -1 && ver === -1) return ['top-right', 'bottom-left'];
  if (hor === -1 && ver === 0) return ['top-right', 'bottom-right'];
  if (hor === -1 && ver === 1) return ['top-left', 'bottom-right'];

  if (hor === 0 && ver === -1) return ['bottom-right', 'bottom-left'];
  if (hor === 0 && ver === 0) return [];
  if (hor === 0 && ver === 1) return ['top-left', 'top-right'];

  if (hor === 1 && ver === -1) return ['bottom-right', 'top-left'];
  if (hor === 1 && ver === 0) return ['bottom-left', 'top-left'];
  if (hor === 1 && ver === 1) return ['bottom-left', 'top-right'];
}

export function boundaries(corners, source, target) {
  target = target.getBoundingClientRect();

  if (!source) return [];
  else if (source instanceof Event) {
    source = {
      left: source.pageX,
      top: source.pageY
    };
  } else if (source.x) {
    source = {
      left: source.x,
      top: source.y
    };
  }

  const dist = distance({ x: target.left + target.width / 2, y: target.top + target.height / 2 }, { x: source.left, y: source.top });
  const tolerance = Math.round(dist / 10);
  const position = {
    left: target.left - tolerance,
    top: target.top - tolerance,
    width: target.width + tolerance * 2,
    height: target.height + tolerance * 2
  };

  var doc = document.documentElement;
  var left = (window.pageXOffset || doc.scrollLeft) - (doc.clientLeft || 0);
  var top = (window.pageYOffset || doc.scrollTop)  - (doc.clientTop || 0);

  let first = true;
  let positions = [];
  corners.forEach(corner => {
    switch (corner) {
    case 'top-right':
      if (first) positions.push({ x: target.left + target.width + left, y: target.top + top });
      positions.push({ x: position.left + position.width + left, y: position.top + top });
      if (!first) positions.push({ x: target.left + target.width + left, y: target.top + top });
      break;
    case 'top-left':
      if (first) positions.push({ x: target.left + left, y: target.top + top });
      positions.push({ x: position.left + left, y: position.top + top });
      if (!first) positions.push({ x: target.left + left, y: target.top + top });
      break;
    case 'bottom-right':
      if (first) positions.push({ x: target.left + target.width + left, y: target.top + target.height + top });
      positions.push({ x: position.left + position.width + left, y: position.top + position.height + top });
      if (!first) positions.push({ x: target.left + target.width + left, y: target.top + target.height + top });
      break;
    case 'bottom-left':
      if (first) positions.push({ x: target.left + left, y: target.top + target.height + top });
      positions.push({ x: position.left + left, y: position.top + position.height + top });
      if (!first) positions.push({ x: target.left + left, y: target.top + target.height + top });
      break;
    }
    if (first) {
      positions.push({ x: source.left, y: source.top });
    }
    first = false;
  });

  return positions;
}

export default corners;
<commit_msg>Made tolerance more accurate<commit_after>import { distance, bullseye } from './aim';

function inside(source, targetMin, targetMax) {
  if (source >= targetMin && source <= targetMax) return 0;
  else if (source > targetMin) return -1;
  else return 1;
}

export function corners(source, target) {
  source = { left: source.pageX, top: source.pageY };
  target = target.getBoundingClientRect();

  let ver, hor;

  hor = inside(source.left, target.left, target.left + target.width);
  ver = inside(source.top, target.top, target.top + target.height);

  if (hor === -1 && ver === -1) return ['top-right', 'bottom-left'];
  if (hor === -1 && ver === 0) return ['top-right', 'bottom-right'];
  if (hor === -1 && ver === 1) return ['top-left', 'bottom-right'];

  if (hor === 0 && ver === -1) return ['bottom-right', 'bottom-left'];
  if (hor === 0 && ver === 0) return [];
  if (hor === 0 && ver === 1) return ['top-left', 'top-right'];

  if (hor === 1 && ver === -1) return ['bottom-right', 'top-left'];
  if (hor === 1 && ver === 0) return ['bottom-left', 'top-left'];
  if (hor === 1 && ver === 1) return ['bottom-left', 'top-right'];
}

export function boundaries(corners, source, target, adjustment = false) {
  if (target instanceof HTMLElement || target instanceof SVGElement) {
    target = target.getBoundingClientRect();
  }

  if (!source) return [];
  else if (source instanceof Event) {
    source = {
      left: source.pageX,
      top: source.pageY
    };
  } else if (source.x) {
    source = {
      left: source.x,
      top: source.y
    };
  }

  let tolerance = adjustment !== false ? Math.round(adjustment / 15) : 0;
  const position = {
    left: target.left - tolerance,
    top: target.top - tolerance,
    width: target.width + tolerance * 2,
    height: target.height + tolerance * 2
  };

  var doc = document.documentElement;
  var left = (window.pageXOffset || doc.scrollLeft) - (doc.clientLeft || 0);
  var top = (window.pageYOffset || doc.scrollTop)  - (doc.clientTop || 0);

  let first = true;
  let positions = [];
  corners.forEach(corner => {
    switch (corner) {
    case 'top-right':
      if (first) positions.push({ x: target.left + target.width + left, y: target.top + top });
      positions.push({ x: position.left + position.width + left, y: position.top + top });
      if (!first) positions.push({ x: target.left + target.width + left, y: target.top + top });
      break;
    case 'top-left':
      if (first) positions.push({ x: target.left + left, y: target.top + top });
      positions.push({ x: position.left + left, y: position.top + top });
      if (!first) positions.push({ x: target.left + left, y: target.top + top });
      break;
    case 'bottom-right':
      if (first) positions.push({ x: target.left + target.width + left, y: target.top + target.height + top });
      positions.push({ x: position.left + position.width + left, y: position.top + position.height + top });
      if (!first) positions.push({ x: target.left + target.width + left, y: target.top + target.height + top });
      break;
    case 'bottom-left':
      if (first) positions.push({ x: target.left + left, y: target.top + target.height + top });
      positions.push({ x: position.left + left, y: position.top + position.height + top });
      if (!first) positions.push({ x: target.left + left, y: target.top + target.height + top });
      break;
    }
    if (first) {
      positions.push({ x: source.left, y: source.top });
    }
    first = false;
  });

  if (adjustment === false) {
    const be = bullseye(corners, positions, { x: source.left, y: source.top });
    if (be) {
      const dist = Math.round(distance({ x: source.left, y: source.top }, be));
      return boundaries(corners, source, target, dist);
    }
  }

  return positions;
}

export default corners;
<|endoftext|>