<commit_before>/**
 * Creates an instance of OptionSelectorsCustom
 * @constructor
 * @param {Object} data The options for this class
 */
Shopify.OptionSelectorsCustom = function(data) {
  this.data      = data;
  this.elem      = document.getElementById(this.data.element);
  this.template  = Handlebars.compile(this.data.template);
  this.product   = new Shopify.Product(this.data.product);
  this.callback  = this.data.callback;
  this.history   = this.data.enableHistory && new Shopify.OptionSelectorsCustom.HistoryState(this);
  this.selectors = {};

  this.hideOriginalSelector();
  this.buildSelectors();

  if (Shopify.urlParam('variant')) {
    this.selectFromParams();
  } else {
    this.selectInitials();
  }
};

/**
 * Hides the original selector element
 */
Shopify.OptionSelectorsCustom.prototype.hideOriginalSelector = function() {
  this.elem.style.display = 'none';
};

/**
 * Handles updating the selectors
 * Fires the callback, fires change event, update shistory
 * @param {Object} variant The variant object
 * @params {Object} selector The selector object
 * @params {Object} e The mouse event from clicking
 */
Shopify.OptionSelectorsCustom.prototype.updateSelectors = function(e) {
  // Get the variant by grabbing the selected values for all selectors and fire callback
  var variant = this.product.getVariant(this.selectedValues());
  this.callback(variant, e);

  // Select the variant ID from the original dropdown
  this.elem.value = variant.id;

  var event;
  if (/Edge\/|Trident\/|MSIE /.test(window.navigator.userAgent)) {
    // IE
    event = document.createEvent('Event');
    event.initEvent('change', false, true);
  } else {
    // Normal browsers
    event = new Event('change');
  }

  // Dispatch the change event
  this.elem.dispatchEvent(event);

  // Update history if enabled
  if (this.history) {
    this.history.onSelection(variant);
  }
};

/**
 * Creates a listener event for our custom selectors
 * @param {(object|string)} item The selector item to target
 */
Shopify.OptionSelectorsCustom.prototype.createSelectorListener = function(item) {
  var self     = this;
  var selector = typeof item == 'string' ? this.selectors[item] : item;
  var children = selector.element().children;

  /**
   * Closure callback for click event
   * @param {Object} e The mouse event from clicking
   */
  var clickCallback = function(e) {
    // Clear current selection for this selector and make new selection base on node
    selector.clearSelection();
    selector.makeSelection(this);
    self.updateSelectors(selector, e);
  };

  // Loop all children of selector and add click event to them
  for (var i = 0; i < children.length; i++) {
    children[i].addEventListener('click', clickCallback);
  }
};

/**
 * Handles building the selectors
 */
Shopify.OptionSelectorsCustom.prototype.buildSelectors = function() {
  // Loop over all option names for the product
  var optionNames = this.product.optionNames();
  for (var i = 0; i < optionNames.length; i++) {
    // Create a new single option selector with data it needs
    var singleSelector = new Shopify.SingleOptionSelectorCustom({
      option: {
        id: 'product_option'+(i + 1),
        name: optionNames[i],
        values: this.product.optionValues(i)
      },
      template: this.template,
      selectedClass: this.data.selectedClass,
      product: this.product
    });

    /*
    * Add the selector to our registry,
    * Inject it's markup into the document,
    * Create a listener for the selector
    */
    this.selectors[singleSelector.id] = singleSelector;
    this.elem.insertAdjacentHTML('beforebegin', singleSelector.buildSelector());
    this.createSelectorListener(singleSelector.id);
  }
};

/**
 * Selects the first item in each selector
 */
Shopify.OptionSelectorsCustom.prototype.selectInitials = function() {
  for (var optionID in this.selectors) {
    this.selectors[optionID].clearSelection();
    this.selectors[optionID].makeSelection(0);
  }

  this.updateSelectors();
};

/**
 * Grabs the selected values of all selectors
 * @returns {Array} the selected values
 */
Shopify.OptionSelectorsCustom.prototype.selectedValues = function() {
  var selected = [];
  for (var optionID in this.selectors) {
    var selection = this.selectors[optionID].currentSelection();
    if (selection) {
      // We have a selection, get it's value
      selected.push(selection.getAttribute('data-value'));
    }
  }

  return selected;
};

/**
 * Selects options based on URL param
 */
Shopify.OptionSelectorsCustom.prototype.selectFromParams = function() {
  var id = Shopify.urlParam('variant');
  if (id) {
    // Get the variant by ID
    var variant = this.product.getVariantById(id);

    // Loop over the options to find matches
    for (var i = 0; i < variant.options.length; i++) {
      var selector = this.selectors['product_option'+(i + 1)];
      var children = selector.element().children;

      for (var x = 0; x < children.length; x++) {
        if (children[x].getAttribute('data-value') == variant.options[i]) {
          // Found, make the selection
          selector.makeSelection(children[x]);
        }
      }
    }

    // Update the selectors (callbacks, etc)
    this.updateSelectors();
  }
};

/**
 * Creates and instance of SingleOptionSelectorCustom
 * @constructor
 * @param {Object} data The options for this class
 */
Shopify.SingleOptionSelectorCustom = function(data) {
  this.name           = data.option.name;
  this.values         = data.option.values;
  this.id             = data.option.id;
  this.template       = data.template;
  this.selectedClass = data.selectedClass;
  this.product        = data.product;
};

/**
 * Builds the selector by compiling the Handlebar template
 */
Shopify.SingleOptionSelectorCustom.prototype.buildSelector = function() {
  return this.template({ option_id: this.id, option_name: this.name, option_values: this.values });
};

/**
 * Returns the element object for this selector
 * @returns {Object} The element's object
 */
Shopify.SingleOptionSelectorCustom.prototype.element = function() {
  return document.getElementById(this.id);
};

/**
 * Grabs the current selection for this selector
 * @returns {Object} The current selected object
 */
Shopify.SingleOptionSelectorCustom.prototype.currentSelection = function() {
  return this.element().querySelector('.'+this.selectedClass);
};

/**
 * Clears any selection
 */
Shopify.SingleOptionSelectorCustom.prototype.clearSelection = function() {
  var currentlySelected = this.element().querySelector('.'+this.selectedClass);
  if (currentlySelected) {
    // Regex replace the selected class to remove spaces (looks cleaner)
    var regex = new RegExp('(?:^|\s)'+this.selectedClass+'(?!\S)', 'gi');
    currentlySelected.className = currentlySelected.className.replace(regex, '');
  }
};

/**
 * Make a selection
 * @param {(Object|Number)} The child to select
*/
Shopify.SingleOptionSelectorCustom.prototype.makeSelection = function(child) {
  if (typeof child == 'number') {
    child = this.element().children[child];
  }

  child.className += this.selectedClass;
};

/**
 * Handles setting new variant in history and URL
 * @constructor
 * @parma {Object} klass The instance of OptionSelectorsCustom
 */
Shopify.OptionSelectorsCustom.HistoryState = function(klass) {
  // Determins if history state is supported
  this.supported = window.history && window.history.replaceState;
};

/**
 * Fires on selection of an option to set the new state
 * @param {Object} variant The variant object
 */
Shopify.OptionSelectorsCustom.HistoryState.prototype.onSelection = function(variant) {
  if (this.supported) {
    Shopify.setParam('variant', variant.id);
  }
};
<commit_msg>Re-added selector to variant with mouse<commit_after>/**
 * Creates an instance of OptionSelectorsCustom
 * @constructor
 * @param {Object} data The options for this class
 */
Shopify.OptionSelectorsCustom = function(data) {
  this.data      = data;
  this.elem      = document.getElementById(this.data.element);
  this.template  = Handlebars.compile(this.data.template);
  this.product   = new Shopify.Product(this.data.product);
  this.callback  = this.data.callback;
  this.history   = this.data.enableHistory && new Shopify.OptionSelectorsCustom.HistoryState(this);
  this.selectors = {};

  this.hideOriginalSelector();
  this.buildSelectors();

  if (Shopify.urlParam('variant')) {
    this.selectFromParams();
  } else {
    this.selectInitials();
  }
};

/**
 * Hides the original selector element
 */
Shopify.OptionSelectorsCustom.prototype.hideOriginalSelector = function() {
  this.elem.style.display = 'none';
};

/**
 * Handles updating the selectors
 * Fires the callback, fires change event, update shistory
 * @param {Object} variant The variant object
 * @params {Object} selector The selector object
 * @params {Object} e The mouse event from clicking
 */
Shopify.OptionSelectorsCustom.prototype.updateSelectors = function(selector, e) {
  // Get the variant by grabbing the selected values for all selectors and fire callback
  var variant = this.product.getVariant(this.selectedValues());
  this.callback(variant, selector, e);

  // Select the variant ID from the original dropdown
  this.elem.value = variant.id;

  var event;
  if (/Edge\/|Trident\/|MSIE /.test(window.navigator.userAgent)) {
    // IE
    event = document.createEvent('Event');
    event.initEvent('change', false, true);
  } else {
    // Normal browsers
    event = new Event('change');
  }

  // Dispatch the change event
  this.elem.dispatchEvent(event);

  // Update history if enabled
  if (this.history) {
    this.history.onSelection(variant);
  }
};

/**
 * Creates a listener event for our custom selectors
 * @param {(object|string)} item The selector item to target
 */
Shopify.OptionSelectorsCustom.prototype.createSelectorListener = function(item) {
  var self     = this;
  var selector = typeof item == 'string' ? this.selectors[item] : item;
  var children = selector.element().children;

  /**
   * Closure callback for click event
   * @param {Object} e The mouse event from clicking
   */
  var clickCallback = function(e) {
    // Clear current selection for this selector and make new selection base on node
    selector.clearSelection();
    selector.makeSelection(this);
    self.updateSelectors(selector, e);
  };

  // Loop all children of selector and add click event to them
  for (var i = 0; i < children.length; i++) {
    children[i].addEventListener('click', clickCallback);
  }
};

/**
 * Handles building the selectors
 */
Shopify.OptionSelectorsCustom.prototype.buildSelectors = function() {
  // Loop over all option names for the product
  var optionNames = this.product.optionNames();
  for (var i = 0; i < optionNames.length; i++) {
    // Create a new single option selector with data it needs
    var singleSelector = new Shopify.SingleOptionSelectorCustom({
      option: {
        id: 'product_option'+(i + 1),
        name: optionNames[i],
        values: this.product.optionValues(i)
      },
      template: this.template,
      selectedClass: this.data.selectedClass,
      product: this.product
    });

    /*
    * Add the selector to our registry,
    * Inject it's markup into the document,
    * Create a listener for the selector
    */
    this.selectors[singleSelector.id] = singleSelector;
    this.elem.insertAdjacentHTML('beforebegin', singleSelector.buildSelector());
    this.createSelectorListener(singleSelector.id);
  }
};

/**
 * Selects the first item in each selector
 */
Shopify.OptionSelectorsCustom.prototype.selectInitials = function() {
  for (var optionID in this.selectors) {
    this.selectors[optionID].clearSelection();
    this.selectors[optionID].makeSelection(0);
  }

  this.updateSelectors();
};

/**
 * Grabs the selected values of all selectors
 * @returns {Array} the selected values
 */
Shopify.OptionSelectorsCustom.prototype.selectedValues = function() {
  var selected = [];
  for (var optionID in this.selectors) {
    var selection = this.selectors[optionID].currentSelection();
    if (selection) {
      // We have a selection, get it's value
      selected.push(selection.getAttribute('data-value'));
    }
  }

  return selected;
};

/**
 * Selects options based on URL param
 */
Shopify.OptionSelectorsCustom.prototype.selectFromParams = function() {
  var id = Shopify.urlParam('variant');
  if (id) {
    // Get the variant by ID
    var variant = this.product.getVariantById(id);

    // Loop over the options to find matches
    for (var i = 0; i < variant.options.length; i++) {
      var selector = this.selectors['product_option'+(i + 1)];
      var children = selector.element().children;

      for (var x = 0; x < children.length; x++) {
        if (children[x].getAttribute('data-value') == variant.options[i]) {
          // Found, make the selection
          selector.makeSelection(children[x]);
        }
      }
    }

    // Update the selectors (callbacks, etc)
    this.updateSelectors();
  }
};

/**
 * Creates and instance of SingleOptionSelectorCustom
 * @constructor
 * @param {Object} data The options for this class
 */
Shopify.SingleOptionSelectorCustom = function(data) {
  this.name           = data.option.name;
  this.values         = data.option.values;
  this.id             = data.option.id;
  this.template       = data.template;
  this.selectedClass = data.selectedClass;
  this.product        = data.product;
};

/**
 * Builds the selector by compiling the Handlebar template
 */
Shopify.SingleOptionSelectorCustom.prototype.buildSelector = function() {
  return this.template({ option_id: this.id, option_name: this.name, option_values: this.values });
};

/**
 * Returns the element object for this selector
 * @returns {Object} The element's object
 */
Shopify.SingleOptionSelectorCustom.prototype.element = function() {
  return document.getElementById(this.id);
};

/**
 * Grabs the current selection for this selector
 * @returns {Object} The current selected object
 */
Shopify.SingleOptionSelectorCustom.prototype.currentSelection = function() {
  return this.element().querySelector('.'+this.selectedClass);
};

/**
 * Clears any selection
 */
Shopify.SingleOptionSelectorCustom.prototype.clearSelection = function() {
  var currentlySelected = this.element().querySelector('.'+this.selectedClass);
  if (currentlySelected) {
    // Regex replace the selected class to remove spaces (looks cleaner)
    var regex = new RegExp('(?:^|\s)'+this.selectedClass+'(?!\S)', 'gi');
    currentlySelected.className = currentlySelected.className.replace(regex, '');
  }
};

/**
 * Make a selection
 * @param {(Object|Number)} The child to select
*/
Shopify.SingleOptionSelectorCustom.prototype.makeSelection = function(child) {
  if (typeof child == 'number') {
    child = this.element().children[child];
  }

  child.className += this.selectedClass;
};

/**
 * Handles setting new variant in history and URL
 * @constructor
 * @parma {Object} klass The instance of OptionSelectorsCustom
 */
Shopify.OptionSelectorsCustom.HistoryState = function(klass) {
  // Determins if history state is supported
  this.supported = window.history && window.history.replaceState;
};

/**
 * Fires on selection of an option to set the new state
 * @param {Object} variant The variant object
 */
Shopify.OptionSelectorsCustom.HistoryState.prototype.onSelection = function(variant) {
  if (this.supported) {
    Shopify.setParam('variant', variant.id);
  }
};
<|endoftext|>


<commit_before>'use strict';
var util = require('util');

var i = 0;
var defaultLevels = {
    trace: {name: 'trace', num: i++, color: 'whiteBright', lineFormat: '[#mod:#line <#func>] #msg'},
    debug: {name: 'debug', num: i++, color: 'cyanBright'},
    info: {name: 'info', num: i++, color: 'greenBright'},
    warn: {name: 'warn', num: i++, color: 'yellowBright'},
    error: {name: 'error', num: i++, color: 'redBright', isError: true, lineFormat: '#all'}
};

var ContraLogLevel = function (options) {
    this.name = options.name;
    this.num = options.num;
    this.isError = options.isError;
    this.stream = options.isError ? console.error : console.log;
    this.color = options.color || ( options.isError ? 'red': 'white');
    this.lineFormat = options.lineFormat;
};

var ContraLogLevels = function (loggingLevels) {
    var self = this;
    loggingLevels = loggingLevels || defaultLevels;
    var levelNums = {};
    Object.keys(loggingLevels).forEach(function(levelName){
        var level = loggingLevels[levelName];
        if(level.name != levelName){
            throw new Error(util.format('Level Name Mismatch: %s vs %s', levelName, level.name) );
        }
        if(self[levelName]){
            throw new Error(util.format('Level Name Conflict: %s', levelName) );
        }
        if(levelNums[level.num]){
            throw new Error(util.format('Level Num Conflict: %s %d', levelName, level.num) );
        }
        self[levelName] = new ContraLogLevel(level);
    });
};

module.exports = ContraLogLevels;<commit_msg>Making cl.error() actually print the error.<commit_after>'use strict';
var util = require('util');

var i = 0;
var defaultLevels = {
    trace: {name: 'trace', num: i++, color: 'whiteBright', lineFormat: '[#mod:#line <#func>] #msg'},
    debug: {name: 'debug', num: i++, color: 'cyanBright'},
    info: {name: 'info', num: i++, color: 'greenBright'},
    warn: {name: 'warn', num: i++, color: 'yellowBright'},
    error: {name: 'error', num: i++, color: 'redBright', isError: true, lineFormat: '[#mod:#line <#func>] #msg\n[#file:#line:#col]'}
};

var ContraLogLevel = function (options) {
    this.name = options.name;
    this.num = options.num;
    this.isError = options.isError;
    this.stream = options.isError ? console.error : console.log;
    this.color = options.color || ( options.isError ? 'red': 'white');
    this.lineFormat = options.lineFormat;
};

var ContraLogLevels = function (loggingLevels) {
    var self = this;
    loggingLevels = loggingLevels || defaultLevels;
    var levelNums = {};
    Object.keys(loggingLevels).forEach(function(levelName){
        var level = loggingLevels[levelName];
        if(level.name != levelName){
            throw new Error(util.format('Level Name Mismatch: %s vs %s', levelName, level.name) );
        }
        if(self[levelName]){
            throw new Error(util.format('Level Name Conflict: %s', levelName) );
        }
        if(levelNums[level.num]){
            throw new Error(util.format('Level Num Conflict: %s %d', levelName, level.num) );
        }
        self[levelName] = new ContraLogLevel(level);
    });
};

module.exports = ContraLogLevels;<|endoftext|>


<commit_before>import React, {PropTypes, PureComponent} from 'react'
import _ from 'lodash'
import classnames from 'classnames'
import lastValues from 'shared/parsing/lastValues'

import {SMALL_CELL_HEIGHT} from 'shared/graphs/helpers'
import {SINGLE_STAT_TEXT} from 'src/dashboards/constants/gaugeColors'
import {isBackgroundLight} from 'shared/constants/colorOperations'

const darkText = '#292933'
const lightText = '#ffffff'

class SingleStat extends PureComponent {
  render() {
    const {data, cellHeight, isFetchingInitially, colors, suffix} = this.props

    // If data for this graph is being fetched for the first time, show a graph-wide spinner.
    if (isFetchingInitially) {
      return (

      )
    }

    const lastValue = lastValues(data)[1]

    const precision = 100.0
    const roundedValue = Math.round(+lastValue * precision) / precision
    let bgColor = null
    let textColor = null
    let className = 'single-stat'

    if (colors && colors.length > 0) {
      className = 'single-stat single-stat--colored'
      const sortedColors = _.sortBy(colors, color => Number(color.value))
      const nearestCrossedThreshold = sortedColors
        .filter(color => lastValue > color.value)
        .pop()

      const colorizeText = _.some(colors, {type: SINGLE_STAT_TEXT})

      if (colorizeText) {
        textColor = nearestCrossedThreshold
          ? nearestCrossedThreshold.hex
          : '#292933'
      } else {
        bgColor = nearestCrossedThreshold
          ? nearestCrossedThreshold.hex
          : '#292933'
        textColor = isBackgroundLight(bgColor) ? darkText : lightText
      }
    }

    return (

          {roundedValue}
          {suffix}

    )
  }
}

const {arrayOf, bool, number, shape, string} = PropTypes

SingleStat.propTypes = {
  data: arrayOf(shape()).isRequired,
  isFetchingInitially: bool,
  cellHeight: number,
  colors: arrayOf(
    shape({
      type: string.isRequired,
      hex: string.isRequired,
      id: string.isRequired,
      name: string.isRequired,
      value: string.isRequired,
    }).isRequired
  ),
  suffix: string.isRequired,
}

export default SingleStat
<commit_msg>Do not require suffix in single stat graph<commit_after>import React, {PropTypes, PureComponent} from 'react'
import _ from 'lodash'
import classnames from 'classnames'
import lastValues from 'shared/parsing/lastValues'

import {SMALL_CELL_HEIGHT} from 'shared/graphs/helpers'
import {SINGLE_STAT_TEXT} from 'src/dashboards/constants/gaugeColors'
import {isBackgroundLight} from 'shared/constants/colorOperations'

const darkText = '#292933'
const lightText = '#ffffff'

class SingleStat extends PureComponent {
  render() {
    const {data, cellHeight, isFetchingInitially, colors, suffix} = this.props

    // If data for this graph is being fetched for the first time, show a graph-wide spinner.
    if (isFetchingInitially) {
      return (

      )
    }

    const lastValue = lastValues(data)[1]

    const precision = 100.0
    const roundedValue = Math.round(+lastValue * precision) / precision
    let bgColor = null
    let textColor = null
    let className = 'single-stat'

    if (colors && colors.length > 0) {
      className = 'single-stat single-stat--colored'
      const sortedColors = _.sortBy(colors, color => Number(color.value))
      const nearestCrossedThreshold = sortedColors
        .filter(color => lastValue > color.value)
        .pop()

      const colorizeText = _.some(colors, {type: SINGLE_STAT_TEXT})

      if (colorizeText) {
        textColor = nearestCrossedThreshold
          ? nearestCrossedThreshold.hex
          : '#292933'
      } else {
        bgColor = nearestCrossedThreshold
          ? nearestCrossedThreshold.hex
          : '#292933'
        textColor = isBackgroundLight(bgColor) ? darkText : lightText
      }
    }

    return (

          {roundedValue}
          {suffix}

    )
  }
}

const {arrayOf, bool, number, shape, string} = PropTypes

SingleStat.propTypes = {
  data: arrayOf(shape()).isRequired,
  isFetchingInitially: bool,
  cellHeight: number,
  colors: arrayOf(
    shape({
      type: string.isRequired,
      hex: string.isRequired,
      id: string.isRequired,
      name: string.isRequired,
      value: string.isRequired,
    }).isRequired
  ),
  suffix: string,
}

export default SingleStat
<|endoftext|>


<commit_before>import warning from 'warning';
import invariant from 'invariant';
import { createClass, createElement, isValidElement, PropTypes } from 'react';
import { component, components, history, location, routes } from './PropTypes';
import { createRoutes } from './RouteUtils';
import matchRoutes from './matchRoutes';
import runTransitionHooks from './runTransitionHooks';
import getComponents from './getComponents';
import getRouteParams from './getRouteParams';

import NavigationMixin from './NavigationMixin';
import ScrollManagementMixin from './ScrollManagementMixin';
import ActiveMixin from './ActiveMixin';

var { arrayOf, func, object } = PropTypes;

import qs from 'qs';

function stringifyQuery(query) {
  return qs.stringify(query, { arrayFormat: 'brackets' });
}

function parseQueryString(queryString) {
  return qs.parse(queryString);
}

var Router = createClass({

  mixins: [ NavigationMixin, ScrollManagementMixin, ActiveMixin ],

  statics: {

    run(routes, location, callback, prevState=null) {
      matchRoutes(routes, location, function (error, nextState) {
        if (error || nextState == null) {
          callback(error, null);
        } else {
          nextState.location = location;
          runTransitionHooks(prevState, nextState, function (error, redirectInfo) {
            if (error || redirectInfo) {
              callback(error, null, redirectInfo);
            } else {
              getComponents(nextState, function (error, components) {
                if (error) {
                  callback(error);
                } else {
                  nextState.components = components;
                  callback(null, nextState);
                }
              });
            }
          });
        }
      });
    }

  },

  childContextTypes: {
    router: object
  },

  getChildContext() {
    return {
      router: this
    };
  },

  propTypes: {
    createElement: func,
    parseQueryString: func,
    stringifyQuery: func,
    onError: func,
    onUpdate: func,
    routes,
    // Routes may also be given as children (JSX)
    children: routes,

    // Client-side
    history,

    // Server-side
    location
  },

  getDefaultProps() {
    return {
      createElement,
      parseQueryString,
      stringifyQuery
    };
  },

  getInitialState() {
    return {
      isTransitioning: false,
      location: null,
      routes: null,
      params: null,
      components: null
    };
  },

  updateLocation(location) {
    if (!location.query)
      location.query = this.props.parseQueryString(location.search.substring(1));

    this.setState({
      isTransitioning: true
    });

    Router.run(this.routes, location, (error, state, redirectInfo) => {
      if (error) {
        this.handleError(error);
      } else if (redirectInfo) {
        var { pathname, query, state } = redirectInfo;
        this.replaceWith(pathname, query, state);
      } else if (state == null) {
        warning(
          false,
          'Location "%s" did not match any routes',
          location.pathname + location.search
        );
      } else {
        this.setState(state, this.props.onUpdate);
      }

      this.setState({
        isTransitioning: false
      });
    }, this.state);
  },

  updateHistory(history) {
    if (this._unlisten) {
      this._unlisten();
      this._unlisten = null;
    }

    if (history)
      this._unlisten = history.listen(this.updateLocation);
  },

  handleError(error) {
    if (this.props.onError) {
      this.props.onError.call(this, error);
    } else {
      // Throw errors by default so we don't silently swallow them!
      throw error; // This error probably originated in getChildRoutes or getComponents.
    }
  },

  componentWillMount() {
    var { routes, children, history, location } = this.props;

    invariant(
      routes || children,
      '<Router>s need routes. Try using <Router routes> or ' +
      'passing your routes as nested <Route> children'
    );

    this.routes = createRoutes(routes || children);

    if (history) {
      this.updateHistory(history);
    } else if (location) {
      this.updateLocation(location);
    }
  },

  componentWillReceiveProps(nextProps) {
    // TODO
  },

  componentWillUnmount() {
    if (this._unlisten)
      this._unlisten();
  },

  createPath(pathname, query) {
    var { stringifyQuery } = this.props;

    var queryString;
    if (query == null || (queryString = stringifyQuery(query)) === '')
      return pathname;

    return pathname + (pathname.indexOf('?') === -1 ? '?' : '&') + queryString;
  },

  createElement(component, props) {
    return typeof component === 'function' ? this.props.createElement(component, props) : null;
  },

  render() {
    var { routes, params, components } = this.state;
    var element = null;

    if (components) {
      element = components.reduceRight((element, components, index) => {
        if (components == null)
          return element; // Don't create new children; use the grandchildren.

        var route = routes[index];
        var routeParams = getRouteParams(route, params);
        var props = Object.assign({}, this.state, { route, routeParams });

        if (isValidElement(element)) {
          props.children = element;
        } else if (element) {
          // In render, do var { header, sidebar } = this.props;
          Object.assign(props, element);
        }

        if (typeof components === 'object') {
          var elements = {};

          for (var key in components)
            if (components.hasOwnProperty(key))
              elements[key] = this.createElement(components[key], props);

          return elements;
        }

        return this.createElement(components, props);
      }, element);
    }

    invariant(
      element === null || element === false || isValidElement(element),
      'The root route must render a single element'
    );

    return element;
  }

});

export default Router;
<commit_msg>Allow string values as <Route component><commit_after>import warning from 'warning';
import invariant from 'invariant';
import { createClass, createElement, isValidElement, PropTypes } from 'react';
import { component, components, history, location, routes } from './PropTypes';
import { createRoutes } from './RouteUtils';
import matchRoutes from './matchRoutes';
import runTransitionHooks from './runTransitionHooks';
import getComponents from './getComponents';
import getRouteParams from './getRouteParams';

import NavigationMixin from './NavigationMixin';
import ScrollManagementMixin from './ScrollManagementMixin';
import ActiveMixin from './ActiveMixin';

var { arrayOf, func, object } = PropTypes;

import qs from 'qs';

function stringifyQuery(query) {
  return qs.stringify(query, { arrayFormat: 'brackets' });
}

function parseQueryString(queryString) {
  return qs.parse(queryString);
}

var Router = createClass({

  mixins: [ NavigationMixin, ScrollManagementMixin, ActiveMixin ],

  statics: {

    run(routes, location, callback, prevState=null) {
      matchRoutes(routes, location, function (error, nextState) {
        if (error || nextState == null) {
          callback(error, null);
        } else {
          nextState.location = location;
          runTransitionHooks(prevState, nextState, function (error, redirectInfo) {
            if (error || redirectInfo) {
              callback(error, null, redirectInfo);
            } else {
              getComponents(nextState, function (error, components) {
                if (error) {
                  callback(error);
                } else {
                  nextState.components = components;
                  callback(null, nextState);
                }
              });
            }
          });
        }
      });
    }

  },

  childContextTypes: {
    router: object
  },

  getChildContext() {
    return {
      router: this
    };
  },

  propTypes: {
    createElement: func,
    parseQueryString: func,
    stringifyQuery: func,
    onError: func,
    onUpdate: func,
    routes,
    // Routes may also be given as children (JSX)
    children: routes,

    // Client-side
    history,

    // Server-side
    location
  },

  getDefaultProps() {
    return {
      createElement,
      parseQueryString,
      stringifyQuery
    };
  },

  getInitialState() {
    return {
      isTransitioning: false,
      location: null,
      routes: null,
      params: null,
      components: null
    };
  },

  updateLocation(location) {
    if (!location.query)
      location.query = this.props.parseQueryString(location.search.substring(1));

    this.setState({
      isTransitioning: true
    });

    Router.run(this.routes, location, (error, state, redirectInfo) => {
      if (error) {
        this.handleError(error);
      } else if (redirectInfo) {
        var { pathname, query, state } = redirectInfo;
        this.replaceWith(pathname, query, state);
      } else if (state == null) {
        warning(
          false,
          'Location "%s" did not match any routes',
          location.pathname + location.search
        );
      } else {
        this.setState(state, this.props.onUpdate);
      }

      this.setState({
        isTransitioning: false
      });
    }, this.state);
  },

  updateHistory(history) {
    if (this._unlisten) {
      this._unlisten();
      this._unlisten = null;
    }

    if (history)
      this._unlisten = history.listen(this.updateLocation);
  },

  handleError(error) {
    if (this.props.onError) {
      this.props.onError.call(this, error);
    } else {
      // Throw errors by default so we don't silently swallow them!
      throw error; // This error probably originated in getChildRoutes or getComponents.
    }
  },

  componentWillMount() {
    var { routes, children, history, location } = this.props;

    invariant(
      routes || children,
      '<Router>s need routes. Try using <Router routes> or ' +
      'passing your routes as nested <Route> children'
    );

    this.routes = createRoutes(routes || children);

    if (history) {
      this.updateHistory(history);
    } else if (location) {
      this.updateLocation(location);
    }
  },

  componentWillReceiveProps(nextProps) {
    // TODO
  },

  componentWillUnmount() {
    if (this._unlisten)
      this._unlisten();
  },

  createPath(pathname, query) {
    var { stringifyQuery } = this.props;

    var queryString;
    if (query == null || (queryString = stringifyQuery(query)) === '')
      return pathname;

    return pathname + (pathname.indexOf('?') === -1 ? '?' : '&') + queryString;
  },

  createElement(component, props) {
    return component ? this.props.createElement(component, props) : null;
  },

  render() {
    var { routes, params, components } = this.state;
    var element = null;

    if (components) {
      element = components.reduceRight((element, components, index) => {
        if (components == null)
          return element; // Don't create new children; use the grandchildren.

        var route = routes[index];
        var routeParams = getRouteParams(route, params);
        var props = Object.assign({}, this.state, { route, routeParams });

        if (isValidElement(element)) {
          props.children = element;
        } else if (element) {
          // In render, do var { header, sidebar } = this.props;
          Object.assign(props, element);
        }

        if (typeof components === 'object') {
          var elements = {};

          for (var key in components)
            if (components.hasOwnProperty(key))
              elements[key] = this.createElement(components[key], props);

          return elements;
        }

        return this.createElement(components, props);
      }, element);
    }

    invariant(
      element === null || element === false || isValidElement(element),
      'The root route must render a single element'
    );

    return element;
  }

});

export default Router;
<|endoftext|>


<commit_before>+function summaryDisplay(){
    function loadSummary(s){
        DisplayWindow.setVisibility(false);
        var params = s.params;
        var _env = {
            mode: {name: 'Summary', slug: 'summary'},
            state: state,
            lga: lga,
            sector: Sectors.pluck(params.sector) || overviewObj
        };
        var bcValues = prepBreadcrumbValues(_env,
                        "state lga mode sector subsector indicator".split(" "),
                        {state:state,lga:lga});
        NMIS.Breadcrumb.clear();
    	NMIS.Breadcrumb.setLevels(bcValues);
    	NMIS.LocalNav.markActive(["mode:summary", "sector:" + _env.sector.slug]);
        NMIS.LocalNav.iterate(function(sectionType, buttonName, a){
            var env = _.extend({}, _env);
            env[sectionType] = buttonName;
            a.attr('href', NMIS.urlFor(env));
        });
        (function displayConditionalContent(sector){
            var cc = $('#conditional-content').hide();
            cc.find('>div').hide();
            cc.find('>div.lga.'+sector.slug).show();
            cc.show();
        })(_env.sector);
    }
    dashboard = $.sammy(function(){
        this.get("/nmis~/:state/:lga/summary/?", loadSummary);
        this.get("/nmis~/:state/:lga/summary/:sector/?", loadSummary);
        this.get("/nmis~/:state/:lga/summary/:sector/:subsector/?", loadSummary);
        this.get("/nmis~/:state/:lga/summary/:sector/:subsector/:indicator/?", loadSummary);
    });
}()
<commit_msg>not breaking when sammy finds window.location.hash<commit_after>+function summaryDisplay(){
    function loadSummary(s){
        DisplayWindow.setVisibility(false);
        var params = s.params;
        var _env = {
            mode: {name: 'Summary', slug: 'summary'},
            state: state,
            lga: lga,
            sector: Sectors.pluck(params.sector) || overviewObj
        };
        var bcValues = prepBreadcrumbValues(_env,
                        "state lga mode sector subsector indicator".split(" "),
                        {state:state,lga:lga});
        NMIS.Breadcrumb.clear();
    	NMIS.Breadcrumb.setLevels(bcValues);
    	NMIS.LocalNav.markActive(["mode:summary", "sector:" + _env.sector.slug]);
        NMIS.LocalNav.iterate(function(sectionType, buttonName, a){
            var env = _.extend({}, _env);
            env[sectionType] = buttonName;
            a.attr('href', NMIS.urlFor(env));
        });
        (function displayConditionalContent(sector){
            var cc = $('#conditional-content').hide();
            cc.find('>div').hide();
            cc.find('>div.lga.'+sector.slug).show();
            cc.show();
        })(_env.sector);
    }
    dashboard.get("/nmis~/:state/:lga/summary/?(#.*)?", loadSummary);
    dashboard.get("/nmis~/:state/:lga/summary/:sector/?(#.*)?", loadSummary);
    dashboard.get("/nmis~/:state/:lga/summary/:sector/:subsector/?(#.*)?", loadSummary);
    dashboard.get("/nmis~/:state/:lga/summary/:sector/:subsector/:indicator/?(#.*)?", loadSummary);
}()
<|endoftext|>


<commit_before>export {default} from './src/CheckBox.vue'
<commit_msg>[fix] fix Checkbox component typo<commit_after>export {default} from './src/Checkbox.vue'
<|endoftext|>


<commit_before>import 'babel-polyfill'
import Vue from 'vue'
import App from './App.vue'
import router from './router.js'
import cookie from 'cookie'
import store from './store'
import 'timeago.js'
import 'normalize.css'
import '../public/css/bootstrap.vue.min.css'
import '../public/css/icomoon.css'
import 'github-markdown-css'
import './app.scss'

Vue.config.debug = true

Vue.http.interceptors.push(function (request, next) {
    if (cookie.parse(document.cookie)['XSRF-TOKEN']) {
        request.headers.set('X-XSRF-TOKEN', cookie.parse(document.cookie)['XSRF-TOKEN'])
    }
    next(response => {
        if (response.status !== 200) {
            if (response.data.message) {
                store.commit('ERROR', {
                    message:   response.data.message,
                    timeoutId: setTimeout(() => {
                        store.commit('CLEAR_ERROR')
                        store.commit('CLEAR_ERROR_TIMER')
                    }, 3000)
                })
            } else {
                // 通常为 500 错误
                store.commit('ERROR', {
                    message:   '服务器开小差了',
                    timeoutId: setTimeout(() => {
                        store.commit('CLEAR_ERROR')
                        store.commit('CLEAR_ERROR_TIMER')
                    }, 3000)
                })
            }
            // TODO 处理错误的页面跳转问题
        }
        // TODO 手机无限重定向问题
        if (response.status === 401) {
            if (!['/auth/login', '/auth/register', '/posts/recent'].includes(response.url)) {
                store.commit('OFFLINE')
            }
        }
    })
})

new Vue({
    router: router,
    store,
    render: h => h(App)
}).$mount('#app')
<commit_msg>[vue] fix null of response.data problem<commit_after>import 'babel-polyfill'
import Vue from 'vue'
import App from './App.vue'
import router from './router.js'
import cookie from 'cookie'
import store from './store'
import 'timeago.js'
import 'normalize.css'
import '../public/css/bootstrap.vue.min.css'
import '../public/css/icomoon.css'
import 'github-markdown-css'
import './app.scss'

Vue.config.debug = true

Vue.http.interceptors.push(function (request, next) {
    if (cookie.parse(document.cookie)['XSRF-TOKEN']) {
        request.headers.set('X-XSRF-TOKEN', cookie.parse(document.cookie)['XSRF-TOKEN'])
    }
    next(response => {
        if (response.status !== 200) {
            if (response.data !== null && response.data.message) {
                store.commit('ERROR', {
                    message:   response.data.message,
                    timeoutId: setTimeout(() => {
                        store.commit('CLEAR_ERROR')
                        store.commit('CLEAR_ERROR_TIMER')
                    }, 3000)
                })
            } else {
                // 通常为 500 错误
                store.commit('ERROR', {
                    message:   '服务器开小差了',
                    timeoutId: setTimeout(() => {
                        store.commit('CLEAR_ERROR')
                        store.commit('CLEAR_ERROR_TIMER')
                    }, 3000)
                })
            }
            // TODO 处理错误的页面跳转问题
        }
        // TODO 手机无限重定向问题
        if (response.status === 401) {
            if (!['/auth/login', '/auth/register', '/posts/recent'].includes(response.url)) {
                store.commit('OFFLINE')
            }
        }
    })
})

new Vue({
    router: router,
    store,
    render: h => h(App)
}).$mount('#app')
<|endoftext|>


<commit_before>var BBC_NEWS_URL = 'http://polling.bbc.co.uk/news/latest_breaking_news?audience=Domestic';
var GDN_NEWS_URL = 'https://api.nextgen.guardianapps.co.uk/news-alert/alerts';
var REU_NEWS_URL = 'http://uk.reuters.com/assets/breakingNews?view=json';
var request = require( 'request' );

var bot = require( '..' );

var poll = function () {
	request( BBC_NEWS_URL, function ( err, res, body ) {
		console.log('bbc');
		var data = JSON.parse( body );
		if ( data.html !== '' ) {
			bot.fireEvents( 'rawnews:bbc', data.html );
		}
		setTimeout( poll, data.pollPeriod );
	} );
	request( GDN_NEWS_URL, function ( err, res, body ) {
		console.log('gdn');
		var data = JSON.parse( body );
		if ( err ) { throw err; }
		bot.fireEvents( 'rawnews:gdn', data.collections );
	} );
	request( REU_NEWS_URL, function ( err, res, body ) {
		console.log('reu');
		var data;
		try {
			data = JSON.parse( body );
		} catch ( e ) {
			// reuters send "" not "{}" on no-news
			if ( e instanceof SyntaxError ) {
				return false;
			}
			throw e;
		}
		if ( err ) { throw err; }
		bot.fireEvents( 'rawnews:reuters', data );
		console.log( 'REU', data );
	} );
};

poll();
<commit_msg>Handle bad upstream news<commit_after>var BBC_NEWS_URL = 'http://polling.bbc.co.uk/news/latest_breaking_news?audience=Domestic';
var GDN_NEWS_URL = 'https://api.nextgen.guardianapps.co.uk/news-alert/alerts';
var REU_NEWS_URL = 'http://uk.reuters.com/assets/breakingNews?view=json';
var request = require( 'request' );

var bot = require( '..' );

var poll = function () {
	request( BBC_NEWS_URL, function ( err, res, body ) {
		if ( err ) { throw err; }
		console.log('bbc');
		var data;
		try {
			data = JSON.parse( body );
		} catch ( e ) {
			if ( e instanceof SyntaxError ) {
				bot.shout( bot.config.irc.control, 'bbc news feed playing up' );
				console.log( body, res );
				return;
			} else {
				throw e;
			}
		}
		if ( data.html !== '' ) {
			bot.fireEvents( 'rawnews:bbc', data.html );
		}
		setTimeout( poll, data.pollPeriod ? data.pollPeriod : 30000 );
	} ); request( GDN_NEWS_URL, function ( err, res, body ) { console.log('gdn');
		if ( err ) { throw err; }
		var data;
		try {
			data = JSON.parse( body );
		} catch ( e ) {
			if ( e instanceof SyntaxError ) {
				bot.shout( bot.config.irc.control, 'guardian feed playing up' );
				console.log( body, res );
				return;
			} else {
				throw e;
			}
		}
		if ( err ) { throw err; }
		bot.fireEvents( 'rawnews:gdn', data.collections );
	} );
	request( REU_NEWS_URL, function ( err, res, body ) {
		if ( err ) { throw err; }
		console.log('reu');
		var data;
		try {
			data = JSON.parse( body );
		} catch ( e ) {
			// reuters send "" not "{}" on no-news
			if ( e instanceof SyntaxError ) {
				return false;
			}
			throw e;
		}
		if ( err ) { throw err; }
		bot.fireEvents( 'rawnews:reuters', data );
		console.log( 'REU', data );
	} );
};

poll();
<|endoftext|>


<commit_before>var _; //globals

describe("About Applying What We Have Learnt", function() {

  var products;

  beforeEach(function () {
    products = [
       { name: "Sonoma", ingredients: ["artichoke", "sundried tomatoes", "mushrooms"], containsNuts: false },
       { name: "Pizza Primavera", ingredients: ["roma", "sundried tomatoes", "goats cheese", "rosemary"], containsNuts: false },
       { name: "South Of The Border", ingredients: ["black beans", "jalapenos", "mushrooms"], containsNuts: false },
       { name: "Blue Moon", ingredients: ["blue cheese", "garlic", "walnuts"], containsNuts: true },
       { name: "Taste Of Athens", ingredients: ["spinach", "kalamata olives", "sesame seeds"], containsNuts: true }
    ];
  });

  /*********************************************************************************/

  it("given I'm allergic to nuts and hate mushrooms, it should find a pizza I can eat (imperative)", function () {

    var i,j,hasMushrooms, productsICanEat = [];

    for (i = 0; i < products.length; i+=1) {
        if (products[i].containsNuts === false) {
            hasMushrooms = false;
            for (j = 0; j < products[i].ingredients.length; j+=1) {
               if (products[i].ingredients[j] === "mushrooms") {
                  hasMushrooms = true;
               }
            }
            if (!hasMushrooms) productsICanEat.push(products[i]);
        }
    }

    expect(productsICanEat.length).toBe(1);
  });

  it("given I'm allergic to nuts and hate mushrooms, it should find a pizza I can eat (functional)", function () {

      var productsICanEat = [];

      /* solve using filter() & all() / any() */
      var productsICanEat = _.filter(products, function(obj){
        return !obj.containsNuts && _.every(obj.ingredients, function(val){
          return val !== "mushrooms";
        })
      });

      expect(productsICanEat.length).toBe(1);
  });

  /*********************************************************************************/

  it("should add all the natural numbers below 1000 that are multiples of 3 or 5 (imperative)", function () {

    var sum = 0;
    for(var i=1; i<1000; i+=1) {
      if (i % 3 === 0 || i % 5 === 0) {
        sum += i;
      }
    }

    expect(sum).toBe(233168);
  });

  it("should add all the natural numbers below 1000 that are multiples of 3 or 5 (functional)", function () {

    var sum = 233168;    /* try chaining range() and reduce() */

    expect(233168).toBe(_.reduce(_.range(1, 1000), function(memo, num){
      return memo + ((num % 3 === 0 || num % 5 === 0)? num : 0);
      // return memo + num;
    }, 0));
  });

  /*********************************************************************************/
   it("should count the ingredient occurrence (imperative)", function () {
    var ingredientCount = { "{ingredient name}": 0 };

    for (i = 0; i < products.length; i+=1) {
        for (j = 0; j < products[i].ingredients.length; j+=1) {
            ingredientCount[products[i].ingredients[j]] = (ingredientCount[products[i].ingredients[j]] || 0) + 1;
        }
    }

    expect(ingredientCount['mushrooms']).toBe(2);
  });

  it("should count the ingredient occurrence (functional)", function () {
    var ingredientCount = { "{ingredient name}": 0 };

    /* chain() together map(), flatten() and reduce() */
    // _.map(products,_.flatten);

    // ingredientCount = _.chain(products)
    //   .map(function(product){return product.ingredients})
    //   .flatten()
    //   .reduce(function(counts, ingredient){
    //     counts[ingredient] = (counts[ingredient] || 0) + 1;
    //     return counts;
    //   },{})
    //   .value()

    _.chain(products)
      .map(function(product){return product.ingredients})
      .flatten()
      .reduce(function(null, ingredient){
        ingredientCount[ingredient] = (ingredientCount[ingredient] || 0) + 1;
      })
      .value()

    expect(ingredientCount['mushrooms']).toBe(2);
  });

  /*********************************************************************************/
  /* UNCOMMENT FOR EXTRA CREDIT */

  it("should find the largest prime factor of a composite number", function () {

  });

  it("should find the largest palindrome made from the product of two 3 digit numbers", function () {

  });

  it("should find the smallest number divisible by each of the numbers 1 to 20", function () {

  });

  it("should find the difference between the sum of the squares and the square of the sums", function () {

  });

  it("should find the 10001st prime", function () {

  });

});
<commit_msg>aboutApplyingWhatWeHaveLearnt<commit_after>var _; //globals

describe("About Applying What We Have Learnt", function() {

  var products;

  beforeEach(function () {
    products = [
       { name: "Sonoma", ingredients: ["artichoke", "sundried tomatoes", "mushrooms"], containsNuts: false },
       { name: "Pizza Primavera", ingredients: ["roma", "sundried tomatoes", "goats cheese", "rosemary"], containsNuts: false },
       { name: "South Of The Border", ingredients: ["black beans", "jalapenos", "mushrooms"], containsNuts: false },
       { name: "Blue Moon", ingredients: ["blue cheese", "garlic", "walnuts"], containsNuts: true },
       { name: "Taste Of Athens", ingredients: ["spinach", "kalamata olives", "sesame seeds"], containsNuts: true }
    ];
  });

  /*********************************************************************************/

  it("given I'm allergic to nuts and hate mushrooms, it should find a pizza I can eat (imperative)", function () {

    var i,j,hasMushrooms, productsICanEat = [];

    for (i = 0; i < products.length; i+=1) {
        if (products[i].containsNuts === false) {
            hasMushrooms = false;
            for (j = 0; j < products[i].ingredients.length; j+=1) {
               if (products[i].ingredients[j] === "mushrooms") {
                  hasMushrooms = true;
               }
            }
            if (!hasMushrooms) productsICanEat.push(products[i]);
        }
    }

    expect(productsICanEat.length).toBe(1);
  });

  it("given I'm allergic to nuts and hate mushrooms, it should find a pizza I can eat (functional)", function () {

      var productsICanEat = [];

      /* solve using filter() & all() / any() */
      var productsICanEat = _.filter(products, function(obj){
        return !obj.containsNuts && _.every(obj.ingredients, function(val){
          return val !== "mushrooms";
        })
      });

      expect(productsICanEat.length).toBe(1);
  });

  /*********************************************************************************/

  it("should add all the natural numbers below 1000 that are multiples of 3 or 5 (imperative)", function () {

    var sum = 0;
    for(var i=1; i<1000; i+=1) {
      if (i % 3 === 0 || i % 5 === 0) {
        sum += i;
      }
    }

    expect(sum).toBe(233168);
  });

  it("should add all the natural numbers below 1000 that are multiples of 3 or 5 (functional)", function () {

    var sum = 233168;    /* try chaining range() and reduce() */

    expect(233168).toBe(_.reduce(_.range(1, 1000), function(memo, num){
      return memo + ((num % 3 === 0 || num % 5 === 0)? num : 0);
      // return memo + num;
    }, 0));
  });

  /*********************************************************************************/
   it("should count the ingredient occurrence (imperative)", function () {
    var ingredientCount = { "{ingredient name}": 0 };

    for (i = 0; i < products.length; i+=1) {
        for (j = 0; j < products[i].ingredients.length; j+=1) {
            ingredientCount[products[i].ingredients[j]] = (ingredientCount[products[i].ingredients[j]] || 0) + 1;
        }
    }

    expect(ingredientCount['mushrooms']).toBe(2);
  });

  it("should count the ingredient occurrence (functional)", function () {
    var ingredientCount = { "{ingredient name}": 0 };

    /* chain() together map(), flatten() and reduce() */
    // _.map(products,_.flatten);

    // ingredientCount = _.chain(products)
    //   .map(function(product){return product.ingredients})
    //   .flatten()
    //   .reduce(function(counts, ingredient){
    //     counts[ingredient] = (counts[ingredient] || 0) + 1;
    //     return counts;
    //   },{})
    //   .value()

    _.chain(products)
      .map(function(product){return product.ingredients})
      .flatten()
      .reduce(function(undefined, ingredient){
        ingredientCount[ingredient] = (ingredientCount[ingredient] || 0) + 1;
      })
      .value()

    expect(ingredientCount['mushrooms']).toBe(2);
  });

  /*********************************************************************************/
  /* UNCOMMENT FOR EXTRA CREDIT */

  it("should find the largest prime factor of a composite number", function () {
    // while not equal to composite number add to product array and pass divided num
    var findLargePrime = function(num){
      var productArr = [];
      var run = true;
      var orgNum = num;
      var i = 2;
      while(run){
        if(num % i === 0){
          console.log('hit');
          productArr.push(i);
          num = num / i;
            run = _.reduce(productArr, function(memo, num){
              return memo * num;
            }, 1) === orgNum ? false : true;
        }else{
          i++;
        }
      }
      return _.last(productArr);
    };
    // if equal then return last number of an array

    expect(findLargePrime(25)).toBe(5);

  });

  it("should find the largest palindrome made from the product of two 3 digit numbers", function () {

    var findLargePalindrome = function(){
      var max = 1;
      var factor1 = 1;
      var factor2 = 1;
      for(var i = 999; i > 99; i--){
        for(var j = 999; j > 99; j--){
          var product = i * j;
          if(product.toString().split("").reverse().join("") === product.toString() && max < product){
            max = product;
            factor1 = i;
            factor2 = j;
          }
        }
      }
      console.log(factor1, factor2);
      return max;
    }

    expect(findLargePalindrome()).toBe(906609);

  });

  it("should find the smallest number divisible by each of the numbers 1 to 20", function () {
    var smallestNumDiv = function(num){
      var numbers = _.range(2,num + 1);
      var result = 1;
      var gcd = function(a, b){
        var found = false;
        var gcdNum = 1;
        var j = Math.min(a, b);
        var k = j;
        while(!found && j > 1){
          if(a % j === 0 && b % j === 0){
            found = true;
            gcdNum = j;
          }else{
            j--;
          }
        }
        return gcdNum;
      }
      for(var i = 0; i < numbers.length; i++){
        result = result * numbers[i] / gcd(numbers[i], result);
      }
      return result;
    };

    expect(smallestNumDiv(20)).toBe(232792560);

  });

  it("should find the difference between the sum of the squares and the square of the sums", function () {
    var findDiffSquare = function(arr){
      var sumSquare = 0;
      var squareSum = 0;
      _.each(arr,function(value){
        sumSquare += value * value;
      });
      _.each(arr,function(value){
        squareSum += value;
      });
      return Math.abs(squareSum * squareSum - sumSquare);
    }

    expect(findDiffSquare([1, 2, 3])).toBe(22);

  });

  it("should find the 10001st prime", function () {
    var findPrime = function(orderNum){
      var primeArr = [];
      var i = 2;
      while(primeArr.length !== orderNum){
        var j = 0
        var found = false;
        while(primeArr.length > j && !found){
          if(i % primeArr[j] === 0){
            found = true;
          }else{
            j++;
          }
        }
        if(!found){
          primeArr.push(i)
        }else{
          i++;
        }
      }
      return _.last(primeArr);
    }

    expect(findPrime(10001)).toBe(104743);

  });

});
<|endoftext|>


<commit_before>var Class = require('../../utils/Class');
var BaseSound = require('../BaseSound');
//  Phaser.Sound.WebAudioSound
// TODO support webkitAudioContext implementation differences
// https://developer.mozilla.org/en-US/docs/Web/API/Web_Audio_API/Porting_webkitAudioContext_code_to_standards_based_AudioContext
var WebAudioSound = new Class({
    Extends: BaseSound,
    initialize: function WebAudioSound(manager, key, config) {
        if (config === void 0) { config = {}; }
        /**
         * [description]
         *
         * @private
         * @property {AudioBuffer} audioBuffer
         */
        this.audioBuffer = manager.game.cache.audio.get(key);
        if (!this.audioBuffer) {
            console.error('No audio loaded in cache with key: \'' + key + '\'!');
            return;
        }
        /**
         * [description]
         *
         * @private
         * @property {AudioBufferSourceNode} source
         */
        this.source = null;
        /**
         * [description]
         *
         * @private
         * @property {AudioBufferSourceNode} loopSource
         */
        this.loopSource = null;
        /**
         * [description]
         *
         * @private
         * @property {GainNode} muteNode
         */
        this.muteNode = manager.context.createGain();
        /**
         * [description]
         *
         * @private
         * @property {GainNode} volumeNode
         */
        this.volumeNode = manager.context.createGain();
        /**
         * The time the previous playback started at based on
         * BaseAudioContext.currentTime value.
         *
         * @private
         * @property {number} startTime
         */
        this.startTime = 0;
        /**
         * An array where we keep track of all rate updates during playback.
         *
         * @private
         * @property {{ time: number, rate: number }[]} rateUpdates
         */
        this.rateUpdates = [];
        /**
         * Used for keeping track when sound source playback has ended
         * so it's state can be updated accordingly.
         *
         * @private
         * @property {boolean} hasEnded
         */
        this.hasEnded = false;
        this.muteNode.connect(this.volumeNode);
        this.volumeNode.connect(manager.destination);
        this.duration = this.audioBuffer.duration;
        this.totalDuration = this.audioBuffer.duration;
        BaseSound.call(this, manager, key, config);
    },
    play: function (markerName, config) {
        if (!BaseSound.prototype.play.call(this, markerName, config)) {
            return null;
        }
        //  \/\/\/ isPlaying = true, isPaused = false \/\/\/
        this.stopAndRemoveBufferSource();
        this.createAndStartBufferSource();
        return this;
    },
    pause: function () {
        if (!BaseSound.prototype.pause.call(this)) {
            return false;
        }
        //  \/\/\/ isPlaying = false, isPaused = true \/\/\/
        this.currentConfig.seek = this.getCurrentTime(); // Equivalent to setting paused time
        this.stopAndRemoveBufferSource();
        return true;
    },
    resume: function () {
        if (!BaseSound.prototype.resume.call(this)) {
            return false;
        }
        //  \/\/\/ isPlaying = true, isPaused = false \/\/\/
        this.createAndStartBufferSource();
        return true;
    },
    stop: function () {
        if (!BaseSound.prototype.stop.call(this)) {
            return false;
        }
        //  \/\/\/ isPlaying = false, isPaused = false \/\/\/
        this.stopAndRemoveBufferSource();
        return true;
    },
    /**
     * Used internally to do what the name says.
     *
     * @private
     */
    // TODO add delay param
    createAndStartBufferSource: function () {
        var seek = this.currentConfig.seek;
        var offset = (this.currentMarker ? this.currentMarker.start : 0) + seek;
        var duration = this.duration - seek;
        this.startTime = this.manager.context.currentTime - seek;
        this.source = this.manager.context.createBufferSource();
        this.source.buffer = this.audioBuffer;
        this.source.connect(this.muteNode);
        this.source.onended = function (ev) {
            if (ev.target === this.source) {
                // sound ended
                this.hasEnded = true;
            }
            // else was stopped
        }.bind(this);
        this.applyConfig();
        this.source.start(0, Math.max(0, offset), Math.max(0, duration));
        this.resetConfig();
    },
    /**
     * Used internally to do what the name says.
     *
     * @private
     */
    stopAndRemoveBufferSource: function () {
        if (this.source) {
            this.source.stop();
            this.source = null;
        }
        this.startTime = 0;
    },
    /**
     * @protected
     */
    applyConfig: function () {
        this.rateUpdates.length = 0;
        this.rateUpdates.push({
            time: 0,
            rate: 1
        });
        BaseSound.prototype.applyConfig.call(this);
    },
    /**
     * Update method called on every game step.
     *
     * @param {number} time - The current timestamp as generated by the Request Animation Frame or SetTimeout.
     * @param {number} delta - The delta time elapsed since the last frame.
     */
    update: function (time, delta) {
        if (this.hasEnded) {
            this.hasEnded = false;
            this.stop();
        }
    },
    destroy: function () {
        BaseSound.prototype.destroy.call(this);
        this.audioBuffer = null;
        this.stopAndRemoveBufferSource();
        this.muteNode.disconnect();
        this.muteNode = null;
        this.volumeNode.disconnect();
        this.volumeNode = null;
        this.rateUpdates = null;
    },
    /**
     * @private
     */
    setRate: function () {
        BaseSound.prototype.setRate.call(this);
        if (this.source) {
            this.source.playbackRate.setValueAtTime(this.totalRate, 0);
        }
        if (this.isPlaying) {
            this.rateUpdates.push({
                time: this.manager.context.currentTime - this.startTime,
                rate: this.totalRate
            });
        }
    },
    /**
     * @private
     */
    getCurrentTime: function () {
        var currentTime = 0;
        for (var i = 0; i < this.rateUpdates.length; i++) {
            var nextTime = void 0;
            if (i < this.rateUpdates.length - 1) {
                nextTime = this.rateUpdates[i + 1].time;
            }
            else {
                nextTime = this.manager.context.currentTime - this.startTime;
            }
            currentTime += (nextTime - this.rateUpdates[i].time) * this.rateUpdates[i].rate;
        }
        return currentTime;
    }
});
/**
 * Mute setting.
 * @property {boolean} mute
 */
Object.defineProperty(WebAudioSound.prototype, 'mute', {
    get: function () {
        return this.muteNode.gain.value === 0;
    },
    set: function (value) {
        this.currentConfig.mute = value;
        this.muteNode.gain.setValueAtTime(value ? 0 : 1, 0);
    }
});
/**
 * Volume setting.
 * @property {number} volume
 */
Object.defineProperty(WebAudioSound.prototype, 'volume', {
    get: function () {
        return this.volumeNode.gain.value;
    },
    set: function (value) {
        this.currentConfig.volume = value;
        this.volumeNode.gain.setValueAtTime(value, 0);
    }
});
/**
 * Playback rate.
 * @property {number} rate
 */
Object.defineProperty(WebAudioSound.prototype, 'rate', {
    get: function () {
        return this.currentConfig.rate;
    },
    set: function (value) {
        this.currentConfig.rate = value;
        this.setRate();
    }
});
/**
 * Detuning of sound.
 * @property {number} detune
 */
Object.defineProperty(WebAudioSound.prototype, 'detune', {
    get: function () {
        return this.currentConfig.detune;
    },
    set: function (value) {
        this.currentConfig.detune = value;
        this.setRate();
    }
});
/**
 * Current position of playing sound.
 * @property {number} seek
 */
Object.defineProperty(WebAudioSound.prototype, 'seek', {
    get: function () {
        if (this.isPlaying) {
            return this.getCurrentTime();
        }
        else if (this.isPaused) {
            return this.currentConfig.seek;
        }
        else {
            return 0;
        }
    },
    set: function (value) {
        if (this.isPlaying || this.isPaused) {
            value = Math.min(Math.max(0, value), this.duration);
            this.currentConfig.seek = value;
        }
        if (this.isPlaying) {
            this.stopAndRemoveBufferSource();
            this.createAndStartBufferSource();
        }
    }
});
/**
 * Property indicating whether or not
 * the sound or current sound marker will loop.
 *
 * @property {boolean} loop
 */
Object.defineProperty(WebAudioSound.prototype, 'loop', {
    get: function () {
    },
    set: function (value) {
    }
});
module.exports = WebAudioSound;
<commit_msg>Returning config value when getting loop property<commit_after>var Class = require('../../utils/Class');
var BaseSound = require('../BaseSound');
//  Phaser.Sound.WebAudioSound
// TODO support webkitAudioContext implementation differences
// https://developer.mozilla.org/en-US/docs/Web/API/Web_Audio_API/Porting_webkitAudioContext_code_to_standards_based_AudioContext
var WebAudioSound = new Class({
    Extends: BaseSound,
    initialize: function WebAudioSound(manager, key, config) {
        if (config === void 0) { config = {}; }
        /**
         * [description]
         *
         * @private
         * @property {AudioBuffer} audioBuffer
         */
        this.audioBuffer = manager.game.cache.audio.get(key);
        if (!this.audioBuffer) {
            console.error('No audio loaded in cache with key: \'' + key + '\'!');
            return;
        }
        /**
         * [description]
         *
         * @private
         * @property {AudioBufferSourceNode} source
         */
        this.source = null;
        /**
         * [description]
         *
         * @private
         * @property {AudioBufferSourceNode} loopSource
         */
        this.loopSource = null;
        /**
         * [description]
         *
         * @private
         * @property {GainNode} muteNode
         */
        this.muteNode = manager.context.createGain();
        /**
         * [description]
         *
         * @private
         * @property {GainNode} volumeNode
         */
        this.volumeNode = manager.context.createGain();
        /**
         * The time the previous playback started at based on
         * BaseAudioContext.currentTime value.
         *
         * @private
         * @property {number} startTime
         */
        this.startTime = 0;
        /**
         * An array where we keep track of all rate updates during playback.
         *
         * @private
         * @property {{ time: number, rate: number }[]} rateUpdates
         */
        this.rateUpdates = [];
        /**
         * Used for keeping track when sound source playback has ended
         * so it's state can be updated accordingly.
         *
         * @private
         * @property {boolean} hasEnded
         */
        this.hasEnded = false;
        this.muteNode.connect(this.volumeNode);
        this.volumeNode.connect(manager.destination);
        this.duration = this.audioBuffer.duration;
        this.totalDuration = this.audioBuffer.duration;
        BaseSound.call(this, manager, key, config);
    },
    play: function (markerName, config) {
        if (!BaseSound.prototype.play.call(this, markerName, config)) {
            return null;
        }
        //  \/\/\/ isPlaying = true, isPaused = false \/\/\/
        this.stopAndRemoveBufferSource();
        this.createAndStartBufferSource();
        return this;
    },
    pause: function () {
        if (!BaseSound.prototype.pause.call(this)) {
            return false;
        }
        //  \/\/\/ isPlaying = false, isPaused = true \/\/\/
        this.currentConfig.seek = this.getCurrentTime(); // Equivalent to setting paused time
        this.stopAndRemoveBufferSource();
        return true;
    },
    resume: function () {
        if (!BaseSound.prototype.resume.call(this)) {
            return false;
        }
        //  \/\/\/ isPlaying = true, isPaused = false \/\/\/
        this.createAndStartBufferSource();
        return true;
    },
    stop: function () {
        if (!BaseSound.prototype.stop.call(this)) {
            return false;
        }
        //  \/\/\/ isPlaying = false, isPaused = false \/\/\/
        this.stopAndRemoveBufferSource();
        return true;
    },
    /**
     * Used internally to do what the name says.
     *
     * @private
     */
    // TODO add delay param
    createAndStartBufferSource: function () {
        var seek = this.currentConfig.seek;
        var offset = (this.currentMarker ? this.currentMarker.start : 0) + seek;
        var duration = this.duration - seek;
        this.startTime = this.manager.context.currentTime - seek;
        this.source = this.manager.context.createBufferSource();
        this.source.buffer = this.audioBuffer;
        this.source.connect(this.muteNode);
        this.source.onended = function (ev) {
            if (ev.target === this.source) {
                // sound ended
                this.hasEnded = true;
            }
            // else was stopped
        }.bind(this);
        this.applyConfig();
        this.source.start(0, Math.max(0, offset), Math.max(0, duration));
        this.resetConfig();
    },
    /**
     * Used internally to do what the name says.
     *
     * @private
     */
    stopAndRemoveBufferSource: function () {
        if (this.source) {
            this.source.stop();
            this.source = null;
        }
        this.startTime = 0;
    },
    /**
     * @protected
     */
    applyConfig: function () {
        this.rateUpdates.length = 0;
        this.rateUpdates.push({
            time: 0,
            rate: 1
        });
        BaseSound.prototype.applyConfig.call(this);
    },
    /**
     * Update method called on every game step.
     *
     * @param {number} time - The current timestamp as generated by the Request Animation Frame or SetTimeout.
     * @param {number} delta - The delta time elapsed since the last frame.
     */
    update: function (time, delta) {
        if (this.hasEnded) {
            this.hasEnded = false;
            this.stop();
        }
    },
    destroy: function () {
        BaseSound.prototype.destroy.call(this);
        this.audioBuffer = null;
        this.stopAndRemoveBufferSource();
        this.muteNode.disconnect();
        this.muteNode = null;
        this.volumeNode.disconnect();
        this.volumeNode = null;
        this.rateUpdates = null;
    },
    /**
     * @private
     */
    setRate: function () {
        BaseSound.prototype.setRate.call(this);
        if (this.source) {
            this.source.playbackRate.setValueAtTime(this.totalRate, 0);
        }
        if (this.isPlaying) {
            this.rateUpdates.push({
                time: this.manager.context.currentTime - this.startTime,
                rate: this.totalRate
            });
        }
    },
    /**
     * @private
     */
    getCurrentTime: function () {
        var currentTime = 0;
        for (var i = 0; i < this.rateUpdates.length; i++) {
            var nextTime = void 0;
            if (i < this.rateUpdates.length - 1) {
                nextTime = this.rateUpdates[i + 1].time;
            }
            else {
                nextTime = this.manager.context.currentTime - this.startTime;
            }
            currentTime += (nextTime - this.rateUpdates[i].time) * this.rateUpdates[i].rate;
        }
        return currentTime;
    }
});
/**
 * Mute setting.
 * @property {boolean} mute
 */
Object.defineProperty(WebAudioSound.prototype, 'mute', {
    get: function () {
        return this.muteNode.gain.value === 0;
    },
    set: function (value) {
        this.currentConfig.mute = value;
        this.muteNode.gain.setValueAtTime(value ? 0 : 1, 0);
    }
});
/**
 * Volume setting.
 * @property {number} volume
 */
Object.defineProperty(WebAudioSound.prototype, 'volume', {
    get: function () {
        return this.volumeNode.gain.value;
    },
    set: function (value) {
        this.currentConfig.volume = value;
        this.volumeNode.gain.setValueAtTime(value, 0);
    }
});
/**
 * Playback rate.
 * @property {number} rate
 */
Object.defineProperty(WebAudioSound.prototype, 'rate', {
    get: function () {
        return this.currentConfig.rate;
    },
    set: function (value) {
        this.currentConfig.rate = value;
        this.setRate();
    }
});
/**
 * Detuning of sound.
 * @property {number} detune
 */
Object.defineProperty(WebAudioSound.prototype, 'detune', {
    get: function () {
        return this.currentConfig.detune;
    },
    set: function (value) {
        this.currentConfig.detune = value;
        this.setRate();
    }
});
/**
 * Current position of playing sound.
 * @property {number} seek
 */
Object.defineProperty(WebAudioSound.prototype, 'seek', {
    get: function () {
        if (this.isPlaying) {
            return this.getCurrentTime();
        }
        else if (this.isPaused) {
            return this.currentConfig.seek;
        }
        else {
            return 0;
        }
    },
    set: function (value) {
        if (this.isPlaying || this.isPaused) {
            value = Math.min(Math.max(0, value), this.duration);
            this.currentConfig.seek = value;
        }
        if (this.isPlaying) {
            this.stopAndRemoveBufferSource();
            this.createAndStartBufferSource();
        }
    }
});
/**
 * Property indicating whether or not
 * the sound or current sound marker will loop.
 *
 * @property {boolean} loop
 */
Object.defineProperty(WebAudioSound.prototype, 'loop', {
    get: function () {
        return this.currentConfig.loop;
    },
    set: function (value) {
    }
});
module.exports = WebAudioSound;
<|endoftext|>


<commit_before>/*
Copyright 2016 OpenMarket Ltd

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

import marked from 'marked';

// marked only applies the default options on the high
// level marked() interface, so we do it here.
const marked_options = Object.assign({}, {
    renderer: new marked.Renderer(),
    gfm: true,
    tables: true,
    breaks: true,
    pedantic: false,
    sanitize: true,
    smartLists: true,
    smartypants: false,
}, marked.defaults);

const real_parser = new marked.Parser(marked_options);

/**
 * Class that wraps marked, adding the ability to see whether
 * a given message actually uses any markdown syntax or whether
 * it's plain text.
 */
export default class Markdown {
    constructor(input) {
        const lexer = new marked.Lexer(marked_options);
        this.tokens = lexer.lex(input);
    }

    _copyTokens() {
        // copy tokens (the parser modifies it's input arg)
        const tokens_copy = this.tokens.slice();
        // it also has a 'links' property, because this is javascript
        // and why wouldn't you have an array that also has properties?
        return Object.assign(tokens_copy, this.tokens);
    }

    isPlainText() {
        // we determine if the message requires markdown by
        // running the parser on the tokens with a dummy
        // rendered and seeing if any of the renderer's
        // functions are called other than those noted below.
        // In case you were wondering, no we can't just examine
        // the tokens because the tokens we have are only the
        // output of the *first* tokenizer: any line-based
        // markdown is processed by marked within Parser by
        // the 'inline lexer'...
        let is_plain = true;

        function setNotPlain() {
            is_plain = false;
        }

        const dummyRenderer = {};
        for (const k of Object.keys(marked.Renderer.prototype)) {
            dummyRenderer[k] = setNotPlain;
        }
        // text and paragraph are just text
        dummyRenderer.text = function(t){return t;}
        dummyRenderer.paragraph = function(t){return t;}

        // ignore links where text is just the url:
        // this ignores plain URLs that markdown has
        // detected whilst preserving markdown syntax links
        dummyRenderer.link = function(href, title, text) {
            if (text != href) {
                is_plain = false;
            }
        }

        const dummyOptions = {};
        Object.assign(dummyOptions, marked_options, {
            renderer: dummyRenderer,
        });
        const dummyParser = new marked.Parser(dummyOptions);
        dummyParser.parse(this._copyTokens());

        return is_plain;
    }

    toHTML() {
        return real_parser.parse(this._copyTokens());
    }
}
<commit_msg>Disable link detection, as per comment<commit_after>/*
Copyright 2016 OpenMarket Ltd

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

import marked from 'marked';

// replace the default link renderer function
// to prevent marked from turning plain URLs
// into links, because tits algorithm is fairly
// poor, so let's send plain URLs rather than
// badly linkified ones (the linkifier Vector
// uses on message display is way better, eg.
// handles URLs with closing parens at the end).
const renderer = new marked.Renderer();
renderer.link = function(href, title, text) {
    if (text == href) {
        return href;
    }
    return marked.Renderer.prototype.apply(this, arguments);
}

// marked only applies the default options on the high
// level marked() interface, so we do it here.
const marked_options = Object.assign({}, marked.defaults, {
    renderer: renderer,
    gfm: true,
    tables: true,
    breaks: true,
    pedantic: false,
    sanitize: true,
    smartLists: true,
    smartypants: false,
});

const real_parser = new marked.Parser(marked_options);

/**
 * Class that wraps marked, adding the ability to see whether
 * a given message actually uses any markdown syntax or whether
 * it's plain text.
 */
export default class Markdown {
    constructor(input) {
        const lexer = new marked.Lexer(marked_options);
        this.tokens = lexer.lex(input);
    }

    _copyTokens() {
        // copy tokens (the parser modifies it's input arg)
        const tokens_copy = this.tokens.slice();
        // it also has a 'links' property, because this is javascript
        // and why wouldn't you have an array that also has properties?
        return Object.assign(tokens_copy, this.tokens);
    }

    isPlainText() {
        // we determine if the message requires markdown by
        // running the parser on the tokens with a dummy
        // rendered and seeing if any of the renderer's
        // functions are called other than those noted below.
        // In case you were wondering, no we can't just examine
        // the tokens because the tokens we have are only the
        // output of the *first* tokenizer: any line-based
        // markdown is processed by marked within Parser by
        // the 'inline lexer'...
        let is_plain = true;

        function setNotPlain() {
            is_plain = false;
        }

        const dummyRenderer = {};
        for (const k of Object.keys(marked.Renderer.prototype)) {
            dummyRenderer[k] = setNotPlain;
        }
        // text and paragraph are just text
        dummyRenderer.text = function(t){return t;}
        dummyRenderer.paragraph = function(t){return t;}

        // ignore links where text is just the url:
        // this ignores plain URLs that markdown has
        // detected whilst preserving markdown syntax links
        dummyRenderer.link = function(href, title, text) {
            if (text != href) {
                is_plain = false;
            }
        }

        const dummyOptions = {};
        Object.assign(dummyOptions, marked_options, {
            renderer: dummyRenderer,
        });
        const dummyParser = new marked.Parser(dummyOptions);
        dummyParser.parse(this._copyTokens());

        return is_plain;
    }

    toHTML() {
        return real_parser.parse(this._copyTokens());
    }
}
<|endoftext|>