<commit_before>/**
 * Countable is a script to allow for live paragraph-, word- and character-
 * counting on an HTML element.
 *
 * @author   Sacha Schmid (<https://github.com/RadLikeWhoa>)
 * @version  2.1.1
 * @license  MIT
 * @see      <http://radlikewhoa.github.io/Countable/>
 */

/**
 * Note: For the purpose of this internal documentation, arguments of the type
 * {Nodes} are to be interpreted as either {NodeList} or {Element}.
 */

;(function (global) {
  'use strict'

  /**
   * @private
   *
   * `_liveElements` holds all elements that have the live-counting
   * functionality bound to them.
   */

  var _liveElements = []

  /**
   * `ucs2decode` function from the punycode.js library.
   *
   * Creates an array containing the decimal code points of each Unicode
   * character in the string. While JavaScript uses UCS-2 internally, this
   * function will convert a pair of surrogate halves (each of which UCS-2
   * exposes as separate characters) into a single code point, matching
   * UTF-16.
   *
   * @see     <http://goo.gl/8M09r>
   * @see     <http://goo.gl/u4UUC>
   *
   * @param   {String}  string   The Unicode input string (UCS-2).
   *
   * @return  {Array}   The new array of code points.
   */

  function _decode (string) {
    var output = []
    var counter = 0
    var length = string.length
    var value
    var extra

    while (counter < length) {
      value = string.charCodeAt(counter++)

      if (value >= 0xD800 && value <= 0xDBFF && counter < length) {
        // High surrogate, and there is a next character.
        extra = string.charCodeAt(counter++)

        if ((extra & 0xFC00) == 0xDC00) {
          // Low surrogate.
          output.push(((value & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000)
        } else {
          // unmatched surrogate; only append this code unit, in case the next
          // code unit is the high surrogate of a surrogate pair
          output.push(value, extra)
          counter--
        }
      } else {
        output.push(value)
      }
    }

    return output
  }

  /**
   * `_validateArguments` validates the arguments given to each function call.
   * Errors are logged to the console as warnings, but Countable fails
   * silently.
   *
   * @private
   *
   * @param   {Nodes}     elements  The (collection of) element(s) to
   *                                validate.
   *
   * @param   {Function}  callback  The callback function to validate.
   *
   * @return  {Boolean}   Returns whether all arguments are vaild.
   */

  function _validateArguments (elements, callback) {
    var nodes = Object.prototype.toString.call(elements)
    var elementsValid = (nodes === '[object NodeList]' || nodes === '[object HTMLCollection]') || elements.nodeType === 1
    var callbackValid = typeof callback === 'function'

    if (!elementsValid) console.warn('Countable: Not a valid target')
    if (!callbackValid) console.warn('Countable: Not a valid callback function')

    return elementsValid && callbackValid
  }

  /**
   * `_count` trims an element's value, optionally strips HTML tags and counts
   * paragraphs, sentences, words, characters and characters plus spaces.
   *
   * @private
   *
   * @param   {Element}  element  The element whose value is to be counted.
   *
   * @param   {Object}   options  The options to use for the counting.
   *
   * @return  {Object}   The object containing the number of paragraphs,
   *                     sentences, words, characters and characters plus
   *                     spaces.
   */

  function _count (element, options) {
    var original = '' + ('value' in element ? element.value : element.textContent)

    /**
     * The initial implementation to allow for HTML tags stripping was created
     * @craniumslows while the current one was created by @Rob--W.
     *
     * @see <http://goo.gl/Exmlr>
     * @see <http://goo.gl/gFQQh>
     */

    if (options.stripTags) original = original.replace(/<\/?[a-z][^>]*>/gi, '')
    if (options.ignoreZeroWidth) original = original.replace(/[\u200B]+/, '')

    var trimmed = original.trim()

    /**
     * Most of the performance improvements are based on the works of @epmatsw.
     *
     * @see <http://goo.gl/SWOLB>
     */

    return {
      paragraphs: trimmed ? (trimmed.match(options.hardReturns ? /\n{2,}/g : /\n+/g) || []).length + 1 : 0,
      sentences: trimmed ? (trimmed.match(/[.?!…]+./g) || []).length + 1 : 0,
      words: trimmed ? (trimmed.replace(/['";:,.?¿\-!¡]+/g, '').match(/\S+/g) || []).length : 0,
      characters: trimmed ? _decode(trimmed.replace(/\s/g, '')).length : 0,
      all: _decode(!options.ignoreReturns ? original : original.replace(/[\n\r]/g, '')).length
    }
  }

  /**
   * `_loop` is a helper function to iterate over a collection, e.g. a NodeList
   * or an Array. The callback receives the current element as the single
   * parameter.
   *
   * @private
   *
   * @param  {Array}     which     The collection to iterate over.
   *
   * @param  {Function}  callback  The callback function to call on each
   *                               iteration.
   */

  function _loop (which, callback) {
    var len = which.length

    if (typeof len !== 'undefined') {
      while (len--) {
        callback(which[len])
      }
    } else {
      callback(which)
    }
  }

  /**
   * This is the main object that will later be exposed to other scripts. It
   * holds all the public methods that can be used to enable the Countable
   * functionality.
   *
   * Some methods accept an optional options parameter. This includes the
   * following options.
   *
   * {Boolean}  hardReturns      Use two returns to seperate a paragraph
   *                             instead of one. (default: false)
   * {Boolean}  stripTags        Strip HTML tags before counting the values.
   *                             (default: false)
   * {Boolean}  ignoreReturns    Ignore returns when calculating the `all`
   *                             property. (default: false)
   * {Boolean}  ignoreZeroWidth  Ignore zero-width space characters. (default:
   *                             true)
   */

  var Countable = {

    /**
     * The `on` method binds the counting handler to all given elements. The
     * event is either `oninput` or `onkeydown`, based on the capabilities of
     * the browser.
     *
     * @param   {Nodes}     elements   All elements that should receive the
     *                                 Countable functionality.
     *
     * @param   {Function}  callback   The callback to fire whenever the
     *                                 element's value changes. The callback is
     *                                 called with the relevant element bound
     *                                 to `this` and the counted values as the
     *                                 single parameter.
     *
     * @param   {Object}    [options]  An object to modify Countable's
     *                                 behaviour.
     *
     * @return  {Object}    Returns the Countable object to allow for chaining.
     */

    on: function (elements, callback, options) {
      if (!_validateArguments(elements, callback)) return

      var options = options || {}

      _loop(elements, function (element) {
        var handler = function () {
          callback.call(element, _count(element, options))
        }

        _liveElements.push({ element: element, handler: handler })

        handler()

        element.addEventListener('input', handler)
      })

      return this
    },

    /**
     * The `off` method removes the Countable functionality from all given
     * elements.
     *
     * @param   {Nodes}   elements  All elements whose Countable functionality
     *                              should be unbound.
     *
     * @return  {Object}  Returns the Countable object to allow for chaining.
     */

    off: function (elements) {
      if (!_validateArguments(elements, function () {})) return

      _loop(elements, function (element) {
        var liveElement = _liveElements.filter(function (el) { return el.element === element })[0]

        if (!liveElement) return

        element.removeEventListener('input', liveElement.handler)
        _liveElements = _liveElements.filter(function (el) { return el.element !== element })
      })

      return this
    },

    /**
     * The `count` method works mostly like the `live` method, but no events are
     * bound, the functionality is only executed once.
     *
     * @param   {Nodes}     elements   All elements that should receive the
     *                                 Countable functionality.
     *
     * @param   {Function}  callback   The callback to fire whenever the
     *                                 element's value changes. The callback is
     *                                 called with the relevant element bound
     *                                 to `this` and the counted values as the
     *                                 single parameter.
     *
     * @param   {Object}    [options]  An object to modify Countable's
     *                                 behaviour.
     *
     * @return  {Object}    Returns the Countable object to allow for chaining.
     */

    count: function (elements, callback, options) {
      if (!_validateArguments(elements, callback)) return

      var options = options || {}

      _loop(elements, function (element) {
        callback.call(element, _count(element, options))
      })

      return this
    },

    /**
     * The `enabled` method checks if the live-counting functionality is bound
     * to an element.
     *
     * @param   {Element}  element  A single Element.
     *
     * @return  {Boolean}  A boolean value representing whether Countable
     *                     functionality is bound to the given element.
     */

    enabled: function (element) {
      return _liveElements.filter(function (el) { return el.element === element }).length > 0
    }

  }

  /**
   * Expose Countable depending on the module system used across the
   * application. (Node / CommonJS, AMD, global)
   */

  if (typeof exports === 'object') {
    module.exports = Countable
  } else if (typeof define === 'function' && define.amd) {
    define(function () { return Countable })
  } else {
    global.Countable = Countable
  }
}(this));
<commit_msg>Update variable naming<commit_after>/**
 * Countable is a script to allow for live paragraph-, word- and character-
 * counting on an HTML element.
 *
 * @author   Sacha Schmid (<https://github.com/RadLikeWhoa>)
 * @version  2.1.1
 * @license  MIT
 * @see      <http://radlikewhoa.github.io/Countable/>
 */

/**
 * Note: For the purpose of this internal documentation, arguments of the type
 * {Nodes} are to be interpreted as either {NodeList} or {Element}.
 */

;(function (global) {
  'use strict'

  /**
   * @private
   *
   * `liveElements` holds all elements that have the live-counting
   * functionality bound to them.
   */

  var liveElements = []

  /**
   * `ucs2decode` function from the punycode.js library.
   *
   * Creates an array containing the decimal code points of each Unicode
   * character in the string. While JavaScript uses UCS-2 internally, this
   * function will convert a pair of surrogate halves (each of which UCS-2
   * exposes as separate characters) into a single code point, matching
   * UTF-16.
   *
   * @see     <http://goo.gl/8M09r>
   * @see     <http://goo.gl/u4UUC>
   *
   * @param   {String}  string   The Unicode input string (UCS-2).
   *
   * @return  {Array}   The new array of code points.
   */

  function decode (string) {
    var output = []
    var counter = 0
    var length = string.length
    var value
    var extra

    while (counter < length) {
      value = string.charCodeAt(counter++)

      if (value >= 0xD800 && value <= 0xDBFF && counter < length) {
        // High surrogate, and there is a next character.
        extra = string.charCodeAt(counter++)

        if ((extra & 0xFC00) == 0xDC00) {
          // Low surrogate.
          output.push(((value & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000)
        } else {
          // unmatched surrogate; only append this code unit, in case the next
          // code unit is the high surrogate of a surrogate pair
          output.push(value, extra)
          counter--
        }
      } else {
        output.push(value)
      }
    }

    return output
  }

  /**
   * `validateArguments` validates the arguments given to each function call.
   * Errors are logged to the console as warnings, but Countable fails
   * silently.
   *
   * @private
   *
   * @param   {Nodes}     elements  The (collection of) element(s) to
   *                                validate.
   *
   * @param   {Function}  callback  The callback function to validate.
   *
   * @return  {Boolean}   Returns whether all arguments are vaild.
   */

  function validateArguments (elements, callback) {
    var nodes = Object.prototype.toString.call(elements)
    var elementsValid = (nodes === '[object NodeList]' || nodes === '[object HTMLCollection]') || elements.nodeType === 1
    var callbackValid = typeof callback === 'function'

    if (!elementsValid) console.warn('Countable: Not a valid target')
    if (!callbackValid) console.warn('Countable: Not a valid callback function')

    return elementsValid && callbackValid
  }

  /**
   * `count` trims an element's value, optionally strips HTML tags and counts
   * paragraphs, sentences, words, characters and characters plus spaces.
   *
   * @private
   *
   * @param   {Element}  element  The element whose value is to be counted.
   *
   * @param   {Object}   options  The options to use for the counting.
   *
   * @return  {Object}   The object containing the number of paragraphs,
   *                     sentences, words, characters and characters plus
   *                     spaces.
   */

  function count (element, options) {
    var original = '' + ('value' in element ? element.value : element.textContent)

    /**
     * The initial implementation to allow for HTML tags stripping was created
     * @craniumslows while the current one was created by @Rob--W.
     *
     * @see <http://goo.gl/Exmlr>
     * @see <http://goo.gl/gFQQh>
     */

    if (options.stripTags) original = original.replace(/<\/?[a-z][^>]*>/gi, '')
    if (options.ignoreZeroWidth) original = original.replace(/[\u200B]+/, '')

    var trimmed = original.trim()

    /**
     * Most of the performance improvements are based on the works of @epmatsw.
     *
     * @see <http://goo.gl/SWOLB>
     */

    return {
      paragraphs: trimmed ? (trimmed.match(options.hardReturns ? /\n{2,}/g : /\n+/g) || []).length + 1 : 0,
      sentences: trimmed ? (trimmed.match(/[.?!…]+./g) || []).length + 1 : 0,
      words: trimmed ? (trimmed.replace(/['";:,.?¿\-!¡]+/g, '').match(/\S+/g) || []).length : 0,
      characters: trimmed ? decode(trimmed.replace(/\s/g, '')).length : 0,
      all: decode(!options.ignoreReturns ? original : original.replace(/[\n\r]/g, '')).length
    }
  }

  /**
   * `loop` is a helper function to iterate over a collection, e.g. a NodeList
   * or an Array. The callback receives the current element as the single
   * parameter.
   *
   * @private
   *
   * @param  {Array}     which     The collection to iterate over.
   *
   * @param  {Function}  callback  The callback function to call on each
   *                               iteration.
   */

  function loop (which, callback) {
    var len = which.length

    if (typeof len !== 'undefined') {
      while (len--) {
        callback(which[len])
      }
    } else {
      callback(which)
    }
  }

  /**
   * This is the main object that will later be exposed to other scripts. It
   * holds all the public methods that can be used to enable the Countable
   * functionality.
   *
   * Some methods accept an optional options parameter. This includes the
   * following options.
   *
   * {Boolean}  hardReturns      Use two returns to seperate a paragraph
   *                             instead of one. (default: false)
   * {Boolean}  stripTags        Strip HTML tags before counting the values.
   *                             (default: false)
   * {Boolean}  ignoreReturns    Ignore returns when calculating the `all`
   *                             property. (default: false)
   * {Boolean}  ignoreZeroWidth  Ignore zero-width space characters. (default:
   *                             true)
   */

  var Countable = {

    /**
     * The `on` method binds the counting handler to all given elements. The
     * event is either `oninput` or `onkeydown`, based on the capabilities of
     * the browser.
     *
     * @param   {Nodes}     elements   All elements that should receive the
     *                                 Countable functionality.
     *
     * @param   {Function}  callback   The callback to fire whenever the
     *                                 element's value changes. The callback is
     *                                 called with the relevant element bound
     *                                 to `this` and the counted values as the
     *                                 single parameter.
     *
     * @param   {Object}    [options]  An object to modify Countable's
     *                                 behaviour.
     *
     * @return  {Object}    Returns the Countable object to allow for chaining.
     */

    on: function (elements, callback, options) {
      if (!validateArguments(elements, callback)) return

      var options = options || {}

      loop(elements, function (element) {
        var handler = function () {
          callback.call(element, count(element, options))
        }

        liveElements.push({ element: element, handler: handler })

        handler()

        element.addEventListener('input', handler)
      })

      return this
    },

    /**
     * The `off` method removes the Countable functionality from all given
     * elements.
     *
     * @param   {Nodes}   elements  All elements whose Countable functionality
     *                              should be unbound.
     *
     * @return  {Object}  Returns the Countable object to allow for chaining.
     */

    off: function (elements) {
      if (!validateArguments(elements, function () {})) return

      loop(elements, function (element) {
        var liveElement = liveElements.filter(function (el) { return el.element === element })[0]

        if (!liveElement) return

        element.removeEventListener('input', liveElement.handler)
        liveElements = liveElements.filter(function (el) { return el.element !== element })
      })

      return this
    },

    /**
     * The `count` method works mostly like the `live` method, but no events are
     * bound, the functionality is only executed once.
     *
     * @param   {Nodes}     elements   All elements that should receive the
     *                                 Countable functionality.
     *
     * @param   {Function}  callback   The callback to fire whenever the
     *                                 element's value changes. The callback is
     *                                 called with the relevant element bound
     *                                 to `this` and the counted values as the
     *                                 single parameter.
     *
     * @param   {Object}    [options]  An object to modify Countable's
     *                                 behaviour.
     *
     * @return  {Object}    Returns the Countable object to allow for chaining.
     */

    count: function (elements, callback, options) {
      if (!validateArguments(elements, callback)) return

      var options = options || {}

      loop(elements, function (element) {
        callback.call(element, count(element, options))
      })

      return this
    },

    /**
     * The `enabled` method checks if the live-counting functionality is bound
     * to an element.
     *
     * @param   {Element}  element  A single Element.
     *
     * @return  {Boolean}  A boolean value representing whether Countable
     *                     functionality is bound to the given element.
     */

    enabled: function (element) {
      return liveElements.filter(function (el) { return el.element === element }).length > 0
    }

  }

  /**
   * Expose Countable depending on the module system used across the
   * application. (Node / CommonJS, AMD, global)
   */

  if (typeof exports === 'object') {
    module.exports = Countable
  } else if (typeof define === 'function' && define.amd) {
    define(function () { return Countable })
  } else {
    global.Countable = Countable
  }
}(this));
<|endoftext|>


<commit_before>// @flow
import { createSelector } from 'reselect';
import {
  makeSelectClaimForUri,
  selectClaimsByUri,
  makeSelectClaimsInChannelForCurrentPageState,
  makeSelectClaimIsNsfw,
  makeSelectRecommendedContentForUri,
  makeSelectMediaTypeForUri,
  selectBlockedChannels,
  parseURI,
} from 'lbry-redux';
import { selectAllCostInfoByUri } from 'lbryinc';
import { selectShowMatureContent } from 'redux/selectors/settings';

const RECENT_HISTORY_AMOUNT = 10;
const HISTORY_ITEMS_PER_PAGE = 50;

export const selectState = (state: any) => state.content || {};

export const selectPlayingUri = createSelector(
  selectState,
  state => state.playingUri
);

export const makeSelectIsPlaying = (uri: string) =>
  createSelector(
    selectPlayingUri,
    playingUri => playingUri === uri
  );

export const makeSelectContentPositionForUri = (uri: string) =>
  createSelector(
    selectState,
    makeSelectClaimForUri(uri),
    (state, claim) => {
      if (!claim) {
        return null;
      }
      const outpoint = `${claim.txid}:${claim.nout}`;
      const id = claim.claim_id;
      return state.positions[id] ? state.positions[id][outpoint] : null;
    }
  );

export const selectHistory = createSelector(
  selectState,
  state => state.history || []
);

export const selectHistoryPageCount = createSelector(
  selectHistory,
  history => Math.ceil(history.length / HISTORY_ITEMS_PER_PAGE)
);

export const makeSelectHistoryForPage = (page: number) =>
  createSelector(
    selectHistory,
    selectClaimsByUri,
    (history, claimsByUri) => {
      const left = page * HISTORY_ITEMS_PER_PAGE;
      const historyItemsForPage = history.slice(left, left + HISTORY_ITEMS_PER_PAGE);
      return historyItemsForPage;
    }
  );

export const makeSelectHistoryForUri = (uri: string) =>
  createSelector(
    selectHistory,
    history => history.find(i => i.uri === uri)
  );

export const makeSelectHasVisitedUri = (uri: string) =>
  createSelector(
    makeSelectHistoryForUri(uri),
    history => Boolean(history)
  );

export const makeSelectNextUnplayedRecommended = (uri: string) =>
  createSelector(
    makeSelectRecommendedContentForUri(uri),
    selectHistory,
    selectClaimsByUri,
    selectAllCostInfoByUri,
    selectBlockedChannels,
    (
      recommendedForUri: Array<string>,
      history: Array<{ uri: string }>,
      claimsByUri: { [string]: ?Claim },
      costInfoByUri: { [string]: { cost: 0 | string } },
      blockedChannels: Array<string>
    ) => {
      if (recommendedForUri) {
        // Make sure we don't autoplay paid content, channels, or content from blocked channels
        for (let i = 0; i < recommendedForUri.length; i++) {
          const recommendedUri = recommendedForUri[i];
          const claim = claimsByUri[recommendedUri];

          if (!claim) {
            continue;
          }

          const { isChannel } = parseURI(recommendedUri);
          if (isChannel) {
            continue;
          }

          const costInfo = costInfoByUri[recommendedUri];
          if (!costInfo || costInfo.cost !== 0) {
            continue;
          }

          // We already check if it's a channel above
          // $FlowFixMe
          const isVideo = claim.value && claim.value.stream_type === 'video';
          // $FlowFixMe
          const isAudio = claim.value && claim.value.stream_type === 'audio';
          if (!isVideo && !isAudio) {
            continue;
          }

          const channel = claim && claim.signing_channel;
          if (channel && blockedChannels.some(blockedUri => blockedUri === channel.permanent_url)) {
            continue;
          }

          if (!history.some(item => item.uri === recommendedForUri[i])) {
            return recommendedForUri[i];
          }
        }
      }
    }
  );

export const selectRecentHistory = createSelector(
  selectHistory,
  history => {
    return history.slice(0, RECENT_HISTORY_AMOUNT);
  }
);

export const makeSelectCategoryListUris = (uris: ?Array<string>, channel: string) =>
  createSelector(
    makeSelectClaimsInChannelForCurrentPageState(channel),
    channelClaims => {
      if (uris) return uris;

      if (channelClaims) {
        const CATEGORY_LIST_SIZE = 10;
        return channelClaims.slice(0, CATEGORY_LIST_SIZE).map(({ name, claim_id: claimId }) => `${name}#${claimId}`);
      }

      return null;
    }
  );

export const makeSelectShouldObscurePreview = (uri: string) =>
  createSelector(
    selectShowMatureContent,
    makeSelectClaimIsNsfw(uri),
    (showMatureContent, isClaimMature) => {
      return isClaimMature && !showMatureContent;
    }
  );

export const makeSelectCanAutoplay = (uri: string) =>
  createSelector(
    makeSelectMediaTypeForUri(uri),
    mediaType => {
      const canAutoPlay = ['audio', 'video', 'image', 'text', 'document'].includes(mediaType);
      return canAutoPlay;
    }
  );

export const makeSelectIsText = (uri: string) =>
  createSelector(
    makeSelectMediaTypeForUri(uri),
    mediaType => {
      const isText = ['text', 'document'].includes(mediaType);
      return isText;
    }
  );
<commit_msg>Add script files to the list of human readable files<commit_after>// @flow
import { createSelector } from 'reselect';
import {
  makeSelectClaimForUri,
  selectClaimsByUri,
  makeSelectClaimsInChannelForCurrentPageState,
  makeSelectClaimIsNsfw,
  makeSelectRecommendedContentForUri,
  makeSelectMediaTypeForUri,
  selectBlockedChannels,
  parseURI,
} from 'lbry-redux';
import { selectAllCostInfoByUri } from 'lbryinc';
import { selectShowMatureContent } from 'redux/selectors/settings';

const RECENT_HISTORY_AMOUNT = 10;
const HISTORY_ITEMS_PER_PAGE = 50;

export const selectState = (state: any) => state.content || {};

export const selectPlayingUri = createSelector(
  selectState,
  state => state.playingUri
);

export const makeSelectIsPlaying = (uri: string) =>
  createSelector(
    selectPlayingUri,
    playingUri => playingUri === uri
  );

export const makeSelectContentPositionForUri = (uri: string) =>
  createSelector(
    selectState,
    makeSelectClaimForUri(uri),
    (state, claim) => {
      if (!claim) {
        return null;
      }
      const outpoint = `${claim.txid}:${claim.nout}`;
      const id = claim.claim_id;
      return state.positions[id] ? state.positions[id][outpoint] : null;
    }
  );

export const selectHistory = createSelector(
  selectState,
  state => state.history || []
);

export const selectHistoryPageCount = createSelector(
  selectHistory,
  history => Math.ceil(history.length / HISTORY_ITEMS_PER_PAGE)
);

export const makeSelectHistoryForPage = (page: number) =>
  createSelector(
    selectHistory,
    selectClaimsByUri,
    (history, claimsByUri) => {
      const left = page * HISTORY_ITEMS_PER_PAGE;
      const historyItemsForPage = history.slice(left, left + HISTORY_ITEMS_PER_PAGE);
      return historyItemsForPage;
    }
  );

export const makeSelectHistoryForUri = (uri: string) =>
  createSelector(
    selectHistory,
    history => history.find(i => i.uri === uri)
  );

export const makeSelectHasVisitedUri = (uri: string) =>
  createSelector(
    makeSelectHistoryForUri(uri),
    history => Boolean(history)
  );

export const makeSelectNextUnplayedRecommended = (uri: string) =>
  createSelector(
    makeSelectRecommendedContentForUri(uri),
    selectHistory,
    selectClaimsByUri,
    selectAllCostInfoByUri,
    selectBlockedChannels,
    (
      recommendedForUri: Array<string>,
      history: Array<{ uri: string }>,
      claimsByUri: { [string]: ?Claim },
      costInfoByUri: { [string]: { cost: 0 | string } },
      blockedChannels: Array<string>
    ) => {
      if (recommendedForUri) {
        // Make sure we don't autoplay paid content, channels, or content from blocked channels
        for (let i = 0; i < recommendedForUri.length; i++) {
          const recommendedUri = recommendedForUri[i];
          const claim = claimsByUri[recommendedUri];

          if (!claim) {
            continue;
          }

          const { isChannel } = parseURI(recommendedUri);
          if (isChannel) {
            continue;
          }

          const costInfo = costInfoByUri[recommendedUri];
          if (!costInfo || costInfo.cost !== 0) {
            continue;
          }

          // We already check if it's a channel above
          // $FlowFixMe
          const isVideo = claim.value && claim.value.stream_type === 'video';
          // $FlowFixMe
          const isAudio = claim.value && claim.value.stream_type === 'audio';
          if (!isVideo && !isAudio) {
            continue;
          }

          const channel = claim && claim.signing_channel;
          if (channel && blockedChannels.some(blockedUri => blockedUri === channel.permanent_url)) {
            continue;
          }

          if (!history.some(item => item.uri === recommendedForUri[i])) {
            return recommendedForUri[i];
          }
        }
      }
    }
  );

export const selectRecentHistory = createSelector(
  selectHistory,
  history => {
    return history.slice(0, RECENT_HISTORY_AMOUNT);
  }
);

export const makeSelectCategoryListUris = (uris: ?Array<string>, channel: string) =>
  createSelector(
    makeSelectClaimsInChannelForCurrentPageState(channel),
    channelClaims => {
      if (uris) return uris;

      if (channelClaims) {
        const CATEGORY_LIST_SIZE = 10;
        return channelClaims.slice(0, CATEGORY_LIST_SIZE).map(({ name, claim_id: claimId }) => `${name}#${claimId}`);
      }

      return null;
    }
  );

export const makeSelectShouldObscurePreview = (uri: string) =>
  createSelector(
    selectShowMatureContent,
    makeSelectClaimIsNsfw(uri),
    (showMatureContent, isClaimMature) => {
      return isClaimMature && !showMatureContent;
    }
  );

export const makeSelectCanAutoplay = (uri: string) =>
  createSelector(
    makeSelectMediaTypeForUri(uri),
    mediaType => {
      const canAutoPlay = ['audio', 'video', 'image', 'text', 'document'].includes(mediaType);
      return canAutoPlay;
    }
  );

export const makeSelectIsText = (uri: string) =>
  createSelector(
    makeSelectMediaTypeForUri(uri),
    mediaType => {
      const isText = ['document', 'script'].includes(mediaType);
      return isText;
    }
  );
<|endoftext|>


<commit_before>
angular.module('sliderDemo1', ['ngMaterial'])

.controller('AppCtrl', function($scope) {

  $scope.color = {
    red: Math.floor(Math.random() * 255),
    green: Math.floor(Math.random() * 255),
    blue: Math.floor(Math.random() * 255)
  };

  $scope.rating1 = $scope.rating2 = $scope.rating3 = 3;
  $scope.disabled1 = 0;
  $scope.disabled2 = 70;

});
<commit_msg>update(demos): update slider discrete demos<commit_after>
angular.module('sliderDemo1', ['ngMaterial'])

.controller('AppCtrl', function($scope) {

  $scope.color = {
    red: Math.floor(Math.random() * 255),
    green: Math.floor(Math.random() * 255),
    blue: Math.floor(Math.random() * 255)
  };

  $scope.rating1 = 3;
  $scope.rating2 = 2;
  $scope.rating3 = 4;

  $scope.disabled1 = 0;
  $scope.disabled2 = 70;

});
<|endoftext|>


<commit_before>'use strict';
/**********************
 * Badges by a weeb for weebs *
 **********************/

function badgeImg(link, name) {
	return '';
}

exports.commands = {
	badge: 'badges',
	badges: function (target, room, user) {
		let parts = target.split(',');
		let cmd = parts[0].trim().toLowerCase();
		let userid, targetUser;
		let selectedBadge;
		let userBadges;
		let output = '';
		switch (cmd) {
		case 'set':
			if (!this.can('lock')) return false;
			if (parts.length !== 3) return this.errorReply("Correct command: `/badges set, user, badgeName`");
			userid = toId(parts[1].trim());
			targetUser = Users.getExact(userid);
			userBadges = Db('userBadges').get(userid);
			selectedBadge = parts[2].trim();
			if (!Db('badgeData').has(selectedBadge)) return this.errorReply("This badge does not exist, please check /badges list");
			if (!Db('userBadges').has(userid)) userBadges = [];
			userBadges = userBadges.filter(b => b !== selectedBadge);
			userBadges.push(selectedBadge);
			Db('userBadges').set(toId(userid), userBadges);
			if (Users.get(targetUser)) Users.get(userid).popup('|modal||html|ATTENTION!
 You have received a badge from ' + Chat.escapeHTML(user.name) + ': ');
			this.logModCommand(user.name + " gave the badge '" + selectedBadge + "' badge to " + userid + ".");
			this.sendReply("The '" + selectedBadge + "' badge was given to '" + userid + "'.");
			break;
		case 'create':
			if (!this.can('ban')) return false;
			if (parts.length !== 4) return this.errorReply("Correct command: `/badges create, badge name, description, image`.");
			let badgeName = Chat.escapeHTML(parts[1].trim());
			let description = Chat.escapeHTML(parts[2].trim());
			let img = parts[3].trim();
			if (Db('badgeData').has(badgeName)) return this.errorReply('This badge already exists.');
			Db('badgeData').set(badgeName, [description, img]);
			this.logModCommand(user.name + " created the badge '" + badgeName + ".");
			this.sendReply("The badge '" + badgeName + "' was successfully created.");
			break;
		case 'list':
			if (!this.runBroadcast()) return;
			output = '
';
			Object.keys(Db('badgeData').object()).forEach(badge => {
				let badgeData = Db('badgeData').get(badge);
				output += '
' + badgeImg(badgeData[1], badge) + '	 ' + badge + '	 ' + badgeData[0] + '
';
			});
			output += '
';
			this.sendReply('|html|
' + output + '
');
			break;
		case 'info':
			if (!this.runBroadcast()) return;
			if (!parts[1]) return this.errorReply("Invalid command. Valid commands are `/badges list`, `/badges info, badgeName`, `/badges set, user, badgeName` and `/badges take, user, badgeName`.");
			selectedBadge = parts[1].trim();
			if (!Db('badgeData').has(selectedBadge)) return this.errorReply("This badge does not exist, please check /badges list");
			let badgeData = Db('badgeData').get(selectedBadge);
			this.sendReplyBox(badgeImg(badgeData[1], selectedBadge) + selectedBadge + ': ' + badgeData[0]);
			break;
		case 'take':
			if (!this.can('lock')) return false;
			if (parts.length !== 3) return this.errorReply("Correct command: `/badges take, user, badgeName`");
			userid = toId(parts[1].trim());
			if (!Db('userBadges').has(userid)) return this.errorReply("This user doesn't have any badges.");
			userBadges = Db('userBadges').get(userid);
			selectedBadge = parts[2].trim();
			userBadges = userBadges.filter(b => b !== selectedBadge);
			Db('userBadges').set(toId(userid), userBadges);
			this.logModCommand(user.name + " took the badge '" + selectedBadge + "' badge from " + userid + ".");
			this.sendReply("The '" + selectedBadge + "' badge was taken from '" + userid + "'.");
			break;
		case 'delete':
			if (!this.can('ban')) return false;
			if (parts.length !== 2) return this.errorReply("Correct command: `/badges deleteall, badgeName`");
			selectedBadge = parts[1].trim();
			if (!Db('badgeData').has(selectedBadge)) return this.errorReply("This badge does not exist, please check /badges list");
			Db('badgeData').delete(selectedBadge);
			let badgeUserObject = Db('userBadges').object();
			let users = Object.keys(badgeUserObject);
			users.forEach(u => Db('userBadges').set(u, (badgeUserObject[u].filter(b => b !== selectedBadge))));
			this.sendReply("The badge with the name '" + selectedBadge + "' deleted.");
			this.logModCommand(user.name + " removed the badge '" + selectedBadge + ".");
			break;
		case 'user':
			if (!this.runBroadcast()) return;
			userid = toId(parts[1].trim());
			if (!Db('userBadges').has(userid)) return this.errorReply("This user doesn't have any badges.");
			output = '
';
			let usersBadges = Db('userBadges').get(userid);
			for(let i in usersBadges) {
				let badgeData = Db('badgeData').get(usersBadges[i]);
				output += '
' + badgeImg(badgeData[1], usersBadges[i]) + '	 ' + usersBadges[i] + '	 ' + badgeData[0] + '
';
			}
			/*Object.keys(Db('userBadges').get(userid)).forEach(badge =>
				let badgeData = Db('badgeData').get(badge);
				output += '
' + badgeImg(badgeData2[1], badge) + '	 ' + badge + '	 ' + badgeData2[0] + '
';
			});*/
			output += '
';
			this.sendReply('|html|
' + output + '
');
			break;
		default:
			return this.errorReply("Invalid command. Valid commands are `/badges list`, `/badges info, badgeName`, `/badges set, user, badgeName` and `/badges take, user, badgeName`" +
			 "`/badges create, name, description, img`.");
		}
	},
	badgeshelp: ["Valid commands are `/badges list`, `/badges info, badgeName`, `/badges set, user, badgeName` and `/badges take, user, badgeName`."],
};
<commit_msg>fix /badges user when no target is specified (#3)<commit_after>'use strict';
/**********************
 * Badges by a weeb for weebs *
 **********************/

function badgeImg(link, name) {
	return '';
}

exports.commands = {
	badge: 'badges',
	badges: function (target, room, user) {
		let parts = target.split(',');
		let cmd = parts[0].trim().toLowerCase();
		let userid, targetUser;
		let selectedBadge;
		let userBadges;
		let output = '';
		switch (cmd) {
		case 'set':
			if (!this.can('lock')) return false;
			if (parts.length !== 3) return this.errorReply("Correct command: `/badges set, user, badgeName`");
			userid = toId(parts[1].trim());
			targetUser = Users.getExact(userid);
			userBadges = Db('userBadges').get(userid);
			selectedBadge = parts[2].trim();
			if (!Db('badgeData').has(selectedBadge)) return this.errorReply("This badge does not exist, please check /badges list");
			if (!Db('userBadges').has(userid)) userBadges = [];
			userBadges = userBadges.filter(b => b !== selectedBadge);
			userBadges.push(selectedBadge);
			Db('userBadges').set(toId(userid), userBadges);
			if (Users.get(targetUser)) Users.get(userid).popup('|modal||html|ATTENTION!
 You have received a badge from ' + Chat.escapeHTML(user.name) + ': ');
			this.logModCommand(user.name + " gave the badge '" + selectedBadge + "' badge to " + userid + ".");
			this.sendReply("The '" + selectedBadge + "' badge was given to '" + userid + "'.");
			break;
		case 'create':
			if (!this.can('ban')) return false;
			if (parts.length !== 4) return this.errorReply("Correct command: `/badges create, badge name, description, image`.");
			let badgeName = Chat.escapeHTML(parts[1].trim());
			let description = Chat.escapeHTML(parts[2].trim());
			let img = parts[3].trim();
			if (Db('badgeData').has(badgeName)) return this.errorReply('This badge already exists.');
			Db('badgeData').set(badgeName, [description, img]);
			this.logModCommand(user.name + " created the badge '" + badgeName + ".");
			this.sendReply("The badge '" + badgeName + "' was successfully created.");
			break;
		case 'list':
			if (!this.runBroadcast()) return;
			output = '
';
			Object.keys(Db('badgeData').object()).forEach(badge => {
				let badgeData = Db('badgeData').get(badge);
				output += '
' + badgeImg(badgeData[1], badge) + '	 ' + badge + '	 ' + badgeData[0] + '
';
			});
			output += '
';
			this.sendReply('|html|
' + output + '
');
			break;
		case 'info':
			if (!this.runBroadcast()) return;
			if (!parts[1]) return this.errorReply("Invalid command. Valid commands are `/badges list`, `/badges info, badgeName`, `/badges set, user, badgeName` and `/badges take, user, badgeName`.");
			selectedBadge = parts[1].trim();
			if (!Db('badgeData').has(selectedBadge)) return this.errorReply("This badge does not exist, please check /badges list");
			let badgeData = Db('badgeData').get(selectedBadge);
			this.sendReplyBox(badgeImg(badgeData[1], selectedBadge) + selectedBadge + ': ' + badgeData[0]);
			break;
		case 'take':
			if (!this.can('lock')) return false;
			if (parts.length !== 3) return this.errorReply("Correct command: `/badges take, user, badgeName`");
			userid = toId(parts[1].trim());
			if (!Db('userBadges').has(userid)) return this.errorReply("This user doesn't have any badges.");
			userBadges = Db('userBadges').get(userid);
			selectedBadge = parts[2].trim();
			userBadges = userBadges.filter(b => b !== selectedBadge);
			Db('userBadges').set(toId(userid), userBadges);
			this.logModCommand(user.name + " took the badge '" + selectedBadge + "' badge from " + userid + ".");
			this.sendReply("The '" + selectedBadge + "' badge was taken from '" + userid + "'.");
			break;
		case 'delete':
			if (!this.can('ban')) return false;
			if (parts.length !== 2) return this.errorReply("Correct command: `/badges deleteall, badgeName`");
			selectedBadge = parts[1].trim();
			if (!Db('badgeData').has(selectedBadge)) return this.errorReply("This badge does not exist, please check /badges list");
			Db('badgeData').delete(selectedBadge);
			let badgeUserObject = Db('userBadges').object();
			let users = Object.keys(badgeUserObject);
			users.forEach(u => Db('userBadges').set(u, (badgeUserObject[u].filter(b => b !== selectedBadge))));
			this.sendReply("The badge with the name '" + selectedBadge + "' deleted.");
			this.logModCommand(user.name + " removed the badge '" + selectedBadge + ".");
			break;
		case 'user':
			if (!target) return this.errorReply('No target user was specified.');

			if (!this.runBroadcast()) return;
			userid = toId(parts[1].trim());
			if (!Db('userBadges').has(userid)) return this.errorReply("This user doesn't have any badges.");
			output = '
';
			let usersBadges = Db('userBadges').get(userid);
			for(let i in usersBadges) {
				let badgeData = Db('badgeData').get(usersBadges[i]);
				output += '
' + badgeImg(badgeData[1], usersBadges[i]) + '	 ' + usersBadges[i] + '	 ' + badgeData[0] + '
';
			}
			/*Object.keys(Db('userBadges').get(userid)).forEach(badge =>
				let badgeData = Db('badgeData').get(badge);
				output += '
' + badgeImg(badgeData2[1], badge) + '	 ' + badge + '	 ' + badgeData2[0] + '
';
			});*/
			output += '
';
			this.sendReply('|html|
' + output + '
');

			break;
		default:
			return this.errorReply("Invalid command. Valid commands are `/badges list`, `/badges info, badgeName`, `/badges set, user, badgeName` and `/badges take, user, badgeName`" +
			 "`/badges create, name, description, img`.");
		}
	},
	badgeshelp: ["Valid commands are `/badges list`, `/badges info, badgeName`, `/badges set, user, badgeName` and `/badges take, user, badgeName`."],
};
<|endoftext|>


<commit_before>
var fs = require('fs');
var parseXml = require('xml2js').parseString;
var moment = require('moment');
const dateFormat = 'YYYY-MM-DDTHH:mm:ss';
const dateFormatOutput = 'YYYY-MM-DD';

	var parseDirectory = function (destinationFolder) {

	//console.log(facturaArray)
	// body...
	var facturaArray = [];
	var index = 0;

	var files = fs.readdir(destinationFolder,function (err,files){

	index = files.length;
	if (!err)
		files.forEach( (fileName)=>{
			if(fileName.endsWith('.DS_Store'))
  			{
  				index = index - 1;
  			}
  			else
  			{
  				readFile(destinationFolder +'/'+ fileName,addFactura);
  			}

		});
	else
		throw err;
	});

	function addFactura(factura)
	{
		facturaArray.push(factura);
		if(facturaArray.length === index ) next();

	}

	function next()
	{
		console.log('Termine');

		var filter = filterFacturas(facturaArray);

		var sorted = sortFacturas(filter);

		var lineArray =  [];

		for (var i = sorted.length - 1; i >= 0; i--) {
			lineArray.push(createLineFactura(sorted[i]));
		}

		var stream = fs.createWriteStream('output.txt');

		stream.once('open',function(fd)
		{

			for (var i = lineArray.length - 1; i >= 0; i--) {
				stream.write(lineArray[i]+'\n');
			}

			stream.end()

		});

	}

}

function readFile(fileName, cb)
{

	fs.readFile(fileName,'utf-8', (err, data) => {
  		if (err) throw err;

  		parseXml(data, (err,result)=>{

  		if (err){
  		console.log(err);
  		return;
  		}

  			var fac =createFactura(result,fileName);
  			cb(fac);
  			return fac;

  		});

	});
}

function createLineFactura(factura)
{
	var dateOutput = moment(factura.date).format(dateFormatOutput);
	var line = `${factura.tipoDeComprobante},${dateOutput},${factura.rfcEmisor},${factura.rfcReceptor},"${factura.nombreEmisor}","${factura.concepto}",${factura.totalRetencionIsr},${factura.totalRetencionIva},${factura.totalTrasladoIva},${factura.subtotal},${factura.total}`;
	//var line = `${factura.tipoDeComprobante},${dateOutput},${factura.rfcEmisor},${factura.rfcReceptor},"${factura.nombreEmisor}","${factura.concepto}",${factura.subtotal},${factura.total}`;

	return line;
}

function filterFacturas(facturaArray)
{
	var filter = facturaArray.filter((elem,index,self   )=> self.findIndex ((t)=>  {return t.uuid === elem.uuid  }) === index)
	return filter;
}

function sortFacturas(facturaArray)
{
	return facturaArray.sort((a,b)=>{

			if(a.date==b.date) return 0;

			if(a.date>b.date) return 1;

			if(a.date<b.date) return -1	;

		});
}

function createFactura( facturaObject, fileName)
{
	var factura = new Factura();
	try
	{
		factura.fileName = fileName;
		var tipoDeComprobante = facturaObject['cfdi:Comprobante']['$'].tipoDeComprobante;
		var subtotal =  parseFloat(facturaObject['cfdi:Comprobante']['$'].subTotal);
		var total = parseFloat(facturaObject['cfdi:Comprobante']['$'].total);
		var fecha = facturaObject['cfdi:Comprobante']['$'].fecha;
		var emisor = facturaObject['cfdi:Comprobante']['cfdi:Emisor'][0]['$']['nombre'];
		var rfcEmisor = facturaObject['cfdi:Comprobante']['cfdi:Emisor'][0]['$']['rfc'];
		var rfcReceptor = facturaObject['cfdi:Comprobante']['cfdi:Receptor'][0]['$']['rfc'];
		var UUID = facturaObject['cfdi:Comprobante']['cfdi:Complemento'][0]['tfd:TimbreFiscalDigital'][0]['$']['UUID']
		var concepto = facturaObject['cfdi:Comprobante']['cfdi:Conceptos'][0]['cfdi:Concepto'][0]['$']['descripcion'];
		var retencionesObject = facturaObject['cfdi:Comprobante']['cfdi:Impuestos'][0]['cfdi:Retenciones'][0]['cfdi:Retencion'];
		var trasladosObject = facturaObject['cfdi:Comprobante']['cfdi:Impuestos'][0]['cfdi:Traslados'][0]['cfdi:Traslado'];
		var totalRetencionIva = 0;
		var totalRetencionIsr = 0;
		var totalTrasladoIva = 0
		var index = 0 ;
		for( ; index < retencionesObject.length ; index++){
			var ret = retencionesObject[index];
			if (ret['$']['impuesto'].toLocaleLowerCase()==='iva') totalRetencionIva =  ret['$']['importe'];
			if (ret['$']['impuesto'].toLocaleLowerCase()==='isr') totalRetencionIsr =  ret['$']['importe'];
		}
		index = 0 ;
		for( ; index < trasladosObject.length ; index++){
			var tra = trasladosObject[index];
			if (tra['$']['impuesto'].toLocaleLowerCase()==='iva') totalTrasladoIva =  tra['$']['importe'];
		}

		factura.tipoDeComprobante = tipoDeComprobante;
		factura.fecha = fecha;
		factura.total = total;
		factura.subtotal = subtotal;
		factura.rfcEmisor = rfcEmisor;
		factura.nombreEmisor = emisor;
		factura.rfcReceptor = rfcReceptor;
		factura.uuid = UUID;
		factura.date = moment(factura.fecha , dateFormat);
		factura.concepto = concepto;
		factura.totalTrasladoIva = totalTrasladoIva;
		factura.totalRetencionIva = totalRetencionIva ;
		factura.totalRetencionIsr = totalRetencionIsr;

	} catch (err)
	{
		factura.err = true;
		factura.errMessage= err;
	}
	finally
	{
		return factura;
	}
}

function Factura()
{
	var
	 err,
	 errMessage,
	 rfcEmisor,
	 nombreEmisor,
	 rfcReceptor,
	 fileName,
	 fecha,
	 date,
	 isIngreso,
	 uuid,
	 iva,
	 isr,
	 subtotal,
	 tipoDeComprobante,
	 concepto,
	 totalRetencionIva,
	 totalRetencionIsr,
	 totalTrasladoIva,
	 total = undefined;

	 function getYear(){

	 };
}

exports.parseDirectory = parseDirectory;
<commit_msg>Adding impuestos<commit_after>
var fs = require('fs');
var parseXml = require('xml2js').parseString;
var moment = require('moment');
const dateFormat = 'YYYY-MM-DDTHH:mm:ss';
const dateFormatOutput = 'YYYY-MM-DD';

	var parseDirectory = function (destinationFolder) {

	//console.log(facturaArray)
	// body...
	var facturaArray = [];
	var index = 0;

	var files = fs.readdir(destinationFolder,function (err,files){

	index = files.length;
	if (!err)
		files.forEach( (fileName)=>{
			if(fileName.endsWith('.DS_Store'))
  			{
  				index = index - 1;
  			}
  			else
  			{
  				readFile(destinationFolder +'/'+ fileName,addFactura);
  			}

		});
	else
		throw err;
	});

	function addFactura(factura)
	{
		facturaArray.push(factura);
		if(facturaArray.length === index ) next();

	}

	function next()
	{
		console.log('Termine');

		var filter = filterFacturas(facturaArray);

		var sorted = sortFacturas(filter);

		var lineArray =  [];

		for (var i = sorted.length - 1; i >= 0; i--) {
			lineArray.push(createLineFactura(sorted[i]));
		}

		var stream = fs.createWriteStream('output.txt');

		stream.once('open',function(fd)
		{

			for (var i = lineArray.length - 1; i >= 0; i--) {
				stream.write(lineArray[i]+'\n');
			}

			stream.end()

		});

	}

}

function readFile(fileName, cb)
{

	fs.readFile(fileName,'utf-8', (err, data) => {
  		if (err) throw err;

  		parseXml(data, (err,result)=>{

  		if (err){
  		console.log(err);
  		return;
  		}

  			var fac =createFactura(result,fileName);
  			cb(fac);
  			return fac;

  		});

	});
}

function createLineFactura(factura)
{
	var dateOutput = moment(factura.date).format(dateFormatOutput);
	var line = `${factura.uuid},${dateOutput},${factura.rfcEmisor},${factura.rfcReceptor},"${factura.nombreEmisor}","${factura.concepto}",${factura.totalRetencionIsr},${factura.totalRetencionIva},${factura.totalTrasladoIva},${factura.subtotal},${factura.total}`;
	//var line = `${factura.tipoDeComprobante},${dateOutput},${factura.rfcEmisor},${factura.rfcReceptor},"${factura.nombreEmisor}","${factura.concepto}",${factura.subtotal},${factura.total}`;

	return line;
}

function filterFacturas(facturaArray)
{
	var filter = facturaArray.filter((elem,index,self   )=> self.findIndex ((t)=>  {return t.uuid === elem.uuid  }) === index)
	return filter;
}

function sortFacturas(facturaArray)
{
	return facturaArray.sort((a,b)=>{

			if(a.date==b.date) return 0;

			if(a.date>b.date) return 1;

			if(a.date<b.date) return -1	;

		});
}

function createFactura( facturaObject, fileName)
{
	var factura = new Factura();
	try
	{
		factura.fileName = fileName;
		var tipoDeComprobante = facturaObject['cfdi:Comprobante']['$'].tipoDeComprobante;
		var subtotal =  parseFloat(facturaObject['cfdi:Comprobante']['$'].subTotal);
		var total = parseFloat(facturaObject['cfdi:Comprobante']['$'].total);
		var fecha = facturaObject['cfdi:Comprobante']['$'].fecha;
		var emisor = facturaObject['cfdi:Comprobante']['cfdi:Emisor'][0]['$']['nombre'];
		var rfcEmisor = facturaObject['cfdi:Comprobante']['cfdi:Emisor'][0]['$']['rfc'];
		var rfcReceptor = facturaObject['cfdi:Comprobante']['cfdi:Receptor'][0]['$']['rfc'];
		var UUID = facturaObject['cfdi:Comprobante']['cfdi:Complemento'][0]['tfd:TimbreFiscalDigital'][0]['$']['UUID']
		var concepto = facturaObject['cfdi:Comprobante']['cfdi:Conceptos'][0]['cfdi:Concepto'][0]['$']['descripcion'];

		var totalRetencionIva = 0;
		var totalRetencionIsr = 0;
		var totalTrasladoIva = 0
		var index = 0 ;

		try
		{
			var retencionesObject = facturaObject['cfdi:Comprobante']['cfdi:Impuestos'][0]['cfdi:Retenciones'][0]['cfdi:Retencion'];
			for( ; index < retencionesObject.length ; index++){
				var ret = retencionesObject[index];
				if (ret['$']['impuesto'].toLocaleLowerCase()==='iva') totalRetencionIva =  ret['$']['importe'];
				if (ret['$']['impuesto'].toLocaleLowerCase()==='isr') totalRetencionIsr =  ret['$']['importe'];
			}
		} catch( err )
		{

		}

		index = 0 ;

		try {
			var trasladosObject = facturaObject['cfdi:Comprobante']['cfdi:Impuestos'][0]['cfdi:Traslados'][0]['cfdi:Traslado'];
			for( ; index < trasladosObject.length ; index++){
				var tra = trasladosObject[index];
				if (tra['$']['impuesto'].toLocaleLowerCase()==='iva') totalTrasladoIva =  tra['$']['importe'];
			}
		} catch( err ) {}

		factura.tipoDeComprobante = tipoDeComprobante;
		factura.fecha = fecha;
		factura.total = total;
		factura.subtotal = subtotal;
		factura.rfcEmisor = rfcEmisor;
		factura.nombreEmisor = emisor;
		factura.rfcReceptor = rfcReceptor;
		factura.uuid = UUID;
		factura.date = moment(factura.fecha , dateFormat);
		factura.concepto = concepto;
		factura.totalTrasladoIva = totalTrasladoIva;
		factura.totalRetencionIva = totalRetencionIva ;
		factura.totalRetencionIsr = totalRetencionIsr;

	} catch (err)
	{
		factura.err = true;
		factura.errMessage= err;
	}
	finally
	{
		return factura;
	}
}

function Factura()
{
	var
	 err,
	 errMessage,
	 rfcEmisor,
	 nombreEmisor,
	 rfcReceptor,
	 fileName,
	 fecha,
	 date,
	 isIngreso,
	 uuid,
	 iva,
	 isr,
	 subtotal,
	 tipoDeComprobante,
	 concepto,
	 totalRetencionIva,
	 totalRetencionIsr,
	 totalTrasladoIva,
	 total = undefined;

	 function getYear(){

	 };
}

exports.parseDirectory = parseDirectory;
<|endoftext|>


<commit_before>'use strict';

var calnav = (function() {

  var nav = $('.navcals');

  var renderCal = function(cal, level) {
    var input = document.createElement('input');
    input.type = 'checkbox';
    input.checked = 'checked';
    $(input).on('change', function(e) {
      var active = $(this).is(":checked");
      var l = $(this).parent('label');
      l.toggleClass('active', active);

      // Apply to calendar
      $('#calendar').fullCalendar((active ? 'add' : 'remove') + 'EventSource', l.data('url'))
    })

    var label = document.createElement('label');
    var $label = $(label);
    $label.append(input).append(cal.name);
    $label.data('id', cal.id);
    $label.data('slug', cal.slug);
    $label.data('url', cal.url);
    $label.addClass('level--' + level);
    $label.addClass('active');
    nav.append($label);
  };

  var active = function() {
    var list = [];
    for (var cal in calendars) {
      if (calendars.hasOwnProperty(cal)) {
        var c = calendars[cal];
        if (c.active)
          list.push(c.slug);
      }
    }
    return list.length ? list : ['all'];
  };

  var toggle = function(e) {
    e.stopPropagation();
    var $target = $(e.target);
    if ($target.hasClass('level--1')) {
      $target.toggleClass('active');
      nav.find('.level--0[data-parent="' + $target.data('cal') + '"]').toggle();
    }
  };

  var change = function(e) {
    e.stopPropagation();
    var $target = $(e.target);
    var $label = $target.closest('label');
    var id = $label.data('cal');
    var activate = $target.is(":checked");
    var parent = calendars[calendars[id].parent_id];
    if(!parent) return;
    console.log('change', id)

    // Apply to calendar
    if (activate) {
      calendars[id].active = true;
      $('#calendar').fullCalendar('addEventSource', calendars[id]);
      $label.addClass('active');
      $label.find('.checkbox').css('border-color', $label.data('color'));
      $label.find('.checkbox').css('background', $label.data('color'));
    } else {
      calendars[id].active = false;
      $('#calendar').fullCalendar('removeEventSource', calendars[id].url);
      $label.removeClass('active');
      $label.find('.checkbox').css('border-color', '');
      $label.find('.checkbox').css('background', '');
    }

    // Toggle year eventsource
    var activeSiblings = 0;
    for (var cal in calendars) {
      if (calendars.hasOwnProperty(cal)) {
        var c = calendars[cal];
        if (c.parent_id === calendars[id].parent_id && c.active)
          activeSiblings++;
      }
    }
    if (activate && activeSiblings === 1) {
      $('#calendar').fullCalendar('addEventSource', parent);
    } else if (!activate && !activeSiblings) {
      $('#calendar').fullCalendar('removeEventSource', parent.url);
    }
  };

  var init = function(e) {

    // Toggle by year
    nav.on('click', toggle);

    // Toggle visibility
    nav.find('input').on('change', change);

  };

  return {
    init: init,
    active: active
  };
})();
<commit_msg>Fixed enable/disable for root calendars, fixed #66<commit_after>'use strict';

var calnav = (function() {

  var nav = $('.navcals');

  var renderCal = function(cal, level) {
    var input = document.createElement('input');
    input.type = 'checkbox';
    input.checked = 'checked';
    $(input).on('change', function(e) {
      var active = $(this).is(":checked");
      var l = $(this).parent('label');
      l.toggleClass('active', active);

      // Apply to calendar
      $('#calendar').fullCalendar((active ? 'add' : 'remove') + 'EventSource', l.data('url'))
    })

    var label = document.createElement('label');
    var $label = $(label);
    $label.append(input).append(cal.name);
    $label.data('id', cal.id);
    $label.data('slug', cal.slug);
    $label.data('url', cal.url);
    $label.addClass('level--' + level);
    $label.addClass('active');
    nav.append($label);
  };

  var active = function() {
    var list = [];
    for (var cal in calendars) {
      if (calendars.hasOwnProperty(cal)) {
        var c = calendars[cal];
        if (c.active)
          list.push(c.slug);
      }
    }
    return list.length ? list : ['all'];
  };

  var toggle = function(e) {
    e.stopPropagation();
    var $target = $(e.target);
    if ($target.hasClass('level--1')) {
      $target.toggleClass('active');
      nav.find('.level--0[data-parent="' + $target.data('cal') + '"]').toggle();
    }
  };

  var change = function(e) {
    e.stopPropagation();
    var $target = $(e.target);
    var $label = $target.closest('label');
    var id = $label.data('cal');
    var activate = $target.is(":checked");
    var parent = calendars[calendars[id].parent_id];

    console.log('change', id)

    // Apply to calendar
    if (activate) {
      calendars[id].active = true;
      $('#calendar').fullCalendar('addEventSource', calendars[id]);
      $label.addClass('active');
      $label.find('.checkbox').css('border-color', $label.data('color'));
      $label.find('.checkbox').css('background', $label.data('color'));
    } else {
      calendars[id].active = false;
      $('#calendar').fullCalendar('removeEventSource', calendars[id].url);
      $label.removeClass('active');
      $label.find('.checkbox').css('border-color', '');
      $label.find('.checkbox').css('background', '');
    }

      if (!parent) return;

    // Toggle year eventsource
    var activeSiblings = 0;
    for (var cal in calendars) {
        if (calendars.hasOwnProperty(cal)) {
        var c = calendars[cal];
        if (c.parent_id === calendars[id].parent_id && c.active)
          activeSiblings++;
      }
    }
    if (activate && activeSiblings === 1) {
      $('#calendar').fullCalendar('addEventSource', parent);
    } else if (!activate && !activeSiblings) {
      $('#calendar').fullCalendar('removeEventSource', parent.url);
    }
  };

  var init = function(e) {

    // Toggle by year
    nav.on('click', toggle);

    // Toggle visibility
    nav.find('input').on('change', change);

  };

  return {
    init: init,
    active: active
  };
})();
<|endoftext|>


<commit_before>module("baidu.json.stringify测试");

test("stringify函数输入符合Json要求的对象", function(){
	var obj = {a:1,b:'test',c:true,d:3.12345,e:false,f:null,g:[1,2,3],h:{aa:1,bb:2}}; //输入为Json对象
	var s = baidu.json.stringify(obj);
	equals(s, "{\"a\":1,\"b\":\"test\",\"c\":true,\"d\":3.12345,\"e\":false,\"f\":null,\"g\":[1,2,3],\"h\":{\"aa\":1,\"bb\":2}}");

	var arraytest = [{location:'beijing',company:'baidu',money:10.012,people:10},{location:'shanghai',company:'baidu',money:10.51,people:2}]; //输入为Json数组
	s = baidu.json.stringify(arraytest);
	equals(s, "[{\"location\":\"beijing\",\"company\":\"baidu\",\"money\":10.012,\"people\":10},{\"location\":\"shanghai\",\"company\":\"baidu\",\"money\":10.51,\"people\":2}]");
});

test("输入为number", function(){
	var n = 3.14;
	var s = baidu.json.stringify(n);
	equals(s, "3.14");
});

test("输入为Date", function(){
	var date = "2010/12/01 12:34:45";
	var myDate = new Date(date);
	var s = baidu.json.stringify(myDate);
	equals(s, "\"2010-12-01T12:34:45\"");
});

test("输入为string", function(){
	var n = 'baidu Online';
	var s = baidu.json.stringify(n);
	equals(s, "\"baidu Online\"");
	var k = '\x1c';
	var s = baidu.json.stringify(k);
	equals(s, "\"\\u001c\"");
});

test("输入为null", function(){
	var n = null;
	var s = baidu.json.stringify(n);
	equals(s, "null");
});

test("输入为undefined", function(){
	var n = void(0);
	var s = baidu.json.stringify(n);
	equals(s, "undefined");
});

test("输入为boolean", function(){
	var n = true;
	var s = baidu.json.stringify(n);
	equals(s, "true");

	n = false;
	s = baidu.json.stringify(n);
	equals(s, "false");
});

test("输入的对象当中包含了function", function(){
	var obj = {a:1,b:'test',c:true,d:3.12345,e:false,f:null,g:[1,2,3],h:{aa:1,bb:2}}; //输入的对象当中包含了function
	obj.fn1 = function(x){
		alert(x);
	}
	obj.fn2 = function(x, y){
		if(x>y)
			return 1;
		return 2;
	}

	var s = baidu.json.stringify(obj);
	equals(s, "{\"a\":1,\"b\":\"test\",\"c\":true,\"d\":3.12345,\"e\":false,\"f\":null,\"g\":[1,2,3],\"h\":{\"aa\":1,\"bb\":2}}");
});

document.write('<script type="text/javascript" src="../../../test/tools/br/import.php?f=baidu.browser.ie"></script>');
test("hasOwnProperty", function(){
  var object = {
    "hasOwnProperty" : null,
    "constructor" : null,
    "isPrototypeOf" : null,
    "propertyIsEnumerable" : null,
    "toLocaleString" : null,
    "valueOf" : null,
    "toString" : null
  };

  if(baidu.browser.ie && baidu.browser.ie <= 8){
    equals(baidu.json.stringify(object), '{}');
  }else{
    equals(baidu.json.stringify(object), '{"hasOwnProperty":null,"constructor":null,"isPrototypeOf":null,"propertyIsEnumerable":null,"toLocaleString":null,"valueOf":null,"toString":null}');
  }
});

//describe("baidu.json.stringify测试",{
//
//    "stringify函数输入符合Json要求的对象":function() {
//        var obj = {a:1,b:'test',c:true,d:3.12345,e:false,f:null,g:[1,2,3],h:{aa:1,bb:2}};  //输入为Json对象
//        var s = baidu.json.stringify(obj);
//        value_of(s).should_be("{\"a\":1,\"b\":\"test\",\"c\":true,\"d\":3.12345,\"e\":false,\"f\":null,\"g\":[1,2,3],\"h\":{\"aa\":1,\"bb\":2}}");
//
//        var arraytest = [{location:'beijing',company:'baidu',money:10.012,people:10},{location:'shanghai',company:'baidu',money:10.51,people:2}];  //输入为Json数组
//        s = baidu.json.stringify(arraytest);
//        value_of(s).should_be("[{\"location\":\"beijing\",\"company\":\"baidu\",\"money\":10.012,\"people\":10},{\"location\":\"shanghai\",\"company\":\"baidu\",\"money\":10.51,\"people\":2}]");
//    },
//    "输入为number":function() {
//        var n = 3.14;  //输入为number
//        var s = baidu.json.stringify(n);
//        value_of(s).should_be("3.14");
//    },
//    "输入为string":function() {
//        var n = 'baidu Online';  //输入为string
//        //alert(n);
//        var s = baidu.json.stringify(n);
//        //alert("string"+s);
//        value_of(s).should_be("\"baidu Online\"");
//    },
//    "输入为null":function() {
//        var n = null;  //输入为null
//        var s = baidu.json.stringify(n);
//        value_of(s).should_be("null");
//    },
//    "输入为undefined":function() {
//        var n = void(0);  //输入为undefined
//        var s = baidu.json.stringify(n);
//        value_of(s).should_be("undefined");
//    },
//    "输入为boolean":function() {
//        var n = true;  //输入为boolean
//        var s = baidu.json.stringify(n);
//        value_of(s).should_be("true");
//
//        n = false;  //输入为boolean
//        s = baidu.json.stringify(n);
//        value_of(s).should_be("false");
//
//    },
//    "输入的对象当中包含了function":function() {
//        var obj = {a:1,b:'test',c:true,d:3.12345,e:false,f:null,g:[1,2,3],h:{aa:1,bb:2}}; //输入的对象当中包含了function
//        obj.fn1 = function (x) {alert(x); };
//        obj.fn2 = function(x,y) {
//        	if (x > y)
//        		return 1;
//        	return 2;
//        }
//        var s = baidu.json.stringify(obj);
//        value_of(s).should_be("{\"a\":1,\"b\":\"test\",\"c\":true,\"d\":3.12345,\"e\":false,\"f\":null,\"g\":[1,2,3],\"h\":{\"aa\":1,\"bb\":2}}");
//    }
//});
<commit_msg>更新用例的引入使用<commit_after>module("baidu.json.stringify测试");

test(
		"stringify函数输入符合Json要求的对象",
		function() {
			var obj = {
				a : 1,
				b : 'test',
				c : true,
				d : 3.12345,
				e : false,
				f : null,
				g : [ 1, 2, 3 ],
				h : {
					aa : 1,
					bb : 2
				}
			}; // 输入为Json对象
			var s = baidu.json.stringify(obj);
			equals(
					s,
					"{\"a\":1,\"b\":\"test\",\"c\":true,\"d\":3.12345,\"e\":false,\"f\":null,\"g\":[1,2,3],\"h\":{\"aa\":1,\"bb\":2}}");

			var arraytest = [ {
				location : 'beijing',
				company : 'baidu',
				money : 10.012,
				people : 10
			}, {
				location : 'shanghai',
				company : 'baidu',
				money : 10.51,
				people : 2
			} ]; // 输入为Json数组
			s = baidu.json.stringify(arraytest);
			equals(
					s,
					"[{\"location\":\"beijing\",\"company\":\"baidu\",\"money\":10.012,\"people\":10},{\"location\":\"shanghai\",\"company\":\"baidu\",\"money\":10.51,\"people\":2}]");
		});

test("输入为number", function() {
	var n = 3.14;
	var s = baidu.json.stringify(n);
	equals(s, "3.14");
});

test("输入为Date", function() {
	var date = "2010/12/01 12:34:45";
	var myDate = new Date(date);
	var s = baidu.json.stringify(myDate);
	equals(s, "\"2010-12-01T12:34:45\"");
});

test("输入为string", function() {
	var n = 'baidu Online';
	var s = baidu.json.stringify(n);
	equals(s, "\"baidu Online\"");
	var k = '\x1c';
	var s = baidu.json.stringify(k);
	equals(s, "\"\\u001c\"");
});

test("输入为null", function() {
	var n = null;
	var s = baidu.json.stringify(n);
	equals(s, "null");
});

test("输入为undefined", function() {
	var n = void (0);
	var s = baidu.json.stringify(n);
	equals(s, "undefined");
});

test("输入为boolean", function() {
	var n = true;
	var s = baidu.json.stringify(n);
	equals(s, "true");

	n = false;
	s = baidu.json.stringify(n);
	equals(s, "false");
});

test(
		"输入的对象当中包含了function",
		function() {
			var obj = {
				a : 1,
				b : 'test',
				c : true,
				d : 3.12345,
				e : false,
				f : null,
				g : [ 1, 2, 3 ],
				h : {
					aa : 1,
					bb : 2
				}
			}; // 输入的对象当中包含了function
			obj.fn1 = function(x) {
				alert(x);
			}
			obj.fn2 = function(x, y) {
				if (x > y)
					return 1;
				return 2;
			}

			var s = baidu.json.stringify(obj);
			equals(
					s,
					"{\"a\":1,\"b\":\"test\",\"c\":true,\"d\":3.12345,\"e\":false,\"f\":null,\"g\":[1,2,3],\"h\":{\"aa\":1,\"bb\":2}}");
		});

test("hasOwnProperty", function() {
	var object = {
		"hasOwnProperty" : null,
		"constructor" : null,
		"isPrototypeOf" : null,
		"propertyIsEnumerable" : null,
		"toLocaleString" : null,
		"valueOf" : null,
		"toString" : null
	};

	if (ua.browser.ie && ua.browser.ie <= 8) {
		equals(baidu.json.stringify(object), '{}');
	} else {
		equals(baidu.json.stringify(object), '{"hasOwnProperty":null,'
				+ '"constructor":null,"isPrototypeOf":null,'
				+ '"propertyIsEnumerable":null,"toLocaleString":null,'
				+ '"valueOf":null,"toString":null}');
	}
});<|endoftext|>


<commit_before>// eslint-disable import/no-mutable-exports
import progress from 'nprogress'

class Transformers {
  constructor() {
    this.map = {}
  }

  set(k, v) {
    this.map[k] = v
  }

  get(k) {
    return this.map[k]
  }
}

const transformers = new Transformers()

async function loadBabel() {
  if (!transformers.get('babel')) {
    progress.start()
    const [babel, VuePreset] = await Promise.all([
      import(/* webpackChunkName: "babel-stuffs" */ 'babel-standalone'),
      import(/* webpackChunkName: "babel-stuffs" */ 'babel-preset-vue')
    ])
    transformers.set('babel', babel)
    transformers.set('VuePreset', VuePreset)
    progress.done()
  }
}

async function loadPug() {
  if (!transformers.get('pug')) {
    progress.start()
    const res = await Promise.all([
      import('browserified-pug'),
      import(/* webpackChunkName: "codemirror-mode-pug" */ 'codemirror/mode/pug/pug')
    ])
    transformers.set('pug', res[0])
    progress.done()
  }
}

async function loadMarkdown() {
  if (!transformers.get('markdown')) {
    progress.start()
    const [marked] = await Promise.all([
      import('marked3'),
      import('codemirror/mode/markdown/markdown')
    ])
    transformers.set('markdown', marked)
    progress.done()
  }
}

export { loadBabel, loadPug, loadMarkdown, transformers }
<commit_msg>fix transformers<commit_after>// eslint-disable import/no-mutable-exports
import progress from 'nprogress'

class Transformers {
  constructor() {
    this.map = {}
  }

  set(k, v) {
    this.map[k] = v
  }

  get(k) {
    return this.map[k]
  }
}

const transformers = new Transformers()

async function loadBabel() {
  if (!transformers.get('babel')) {
    progress.start()
    const [babel, VuePreset] = await Promise.all([
      import(/* webpackChunkName: "babel-stuffs" */ 'babel-standalone'),
      import(/* webpackChunkName: "babel-stuffs" */ 'babel-preset-vue/dist/babel-preset-vue') // use umd bundle since we don't want to parse `require`
    ])
    transformers.set('babel', babel)
    transformers.set('VuePreset', VuePreset)
    progress.done()
  }
}

async function loadPug() {
  if (!transformers.get('pug')) {
    progress.start()
    const res = await Promise.all([
      import('browserified-pug'),
      import(/* webpackChunkName: "codemirror-mode-pug" */ 'codemirror/mode/pug/pug')
    ])
    transformers.set('pug', res[0])
    progress.done()
  }
}

async function loadMarkdown() {
  if (!transformers.get('markdown')) {
    progress.start()
    const [marked] = await Promise.all([
      import('marked3').then(m => m.default),
      import('codemirror/mode/markdown/markdown')
    ])
    transformers.set('markdown', marked)
    progress.done()
  }
}

export { loadBabel, loadPug, loadMarkdown, transformers }
<|endoftext|>


<commit_before>document.getElementById("id_bussiness_version").innerHTML = "Bussiness version: 2018.11.26.4";

var canvas = document.getElementById("id_canvas");
canvas.addEventListener("touchstart", on_touch_start);
canvas.addEventListener("touchmove", on_touch_move);

var canvas_bounding_rect = canvas.getBoundingClientRect();

var last_pos = {x: 0, y : 0};
//-------------------------------------------
function on_touch_start(e)
{
	e.preventDefault();

	for (var i = 0; i < e.changedTouches.length; i++){
		var context = canvas.getContext("2d");
		context.beginPath();
		context.arc(e.changedTouches[i].pageX - canvas_bounding_rect.left,
					e.changedTouches[i].pageY - canvas_bounding_rect.top,
					10,
					0,
					2 * Math.PI);
		context.stroke();
		last_pos.x = e.changedTouches[i].pageX;
		last_pos.y = e.changedTouches[i].pageY;

	}
}
//-------------------------------------------
function on_touch_move(e)
{
	e.preventDefault();

	for (var i = 0; i < e.changedTouches.length; i++){
		var context = canvas.getContext("2d");
		context.beginPath();
		context.moveTo(last_pos.x - canvas_bounding_rect.left, last_pos.y - canvas_bounding_rect.top);
		context.lineTo(e.changedTouches[i].pageX - canvas_bounding_rect.left,
						e.changedTouches[i].pageY - canvas_bounding_rect.top);

		context.arc(e.changedTouches[i].pageX - canvas_bounding_rect.left,
					e.changedTouches[i].pageY - canvas_bounding_rect.top,
					10,
					0,
					2 * Math.PI);
		context.stroke();
	}
}
//-------------------------------------------<commit_msg>Update touch.js<commit_after>document.getElementById("id_bussiness_version").innerHTML = "Bussiness version: 2018.11.26.5";

var canvas = document.getElementById("id_canvas");
canvas.addEventListener("touchstart", on_touch_start);
canvas.addEventListener("touchmove", on_touch_move);

var canvas_bounding_rect = canvas.getBoundingClientRect();

var last_pos = {x: 0, y : 0};
//-------------------------------------------
function on_touch_start(e)
{
	e.preventDefault();

	for (var i = 0; i < e.changedTouches.length; i++){
		var context = canvas.getContext("2d");
		context.beginPath();
		context.arc(e.changedTouches[i].pageX - canvas_bounding_rect.left,
					e.changedTouches[i].pageY - canvas_bounding_rect.top,
					10,
					0,
					2 * Math.PI);
		context.stroke();
		last_pos.x = e.changedTouches[i].pageX;
		last_pos.y = e.changedTouches[i].pageY;

	}
}
//-------------------------------------------
function on_touch_move(e)
{
	e.preventDefault();

	for (var i = 0; i < e.changedTouches.length; i++){
		var context = canvas.getContext("2d");
		context.beginPath();
		context.moveTo(last_pos.x - canvas_bounding_rect.left, last_pos.y - canvas_bounding_rect.top);
		context.lineTo(e.changedTouches[i].pageX - canvas_bounding_rect.left,
						e.changedTouches[i].pageY - canvas_bounding_rect.top);

		context.arc(e.changedTouches[i].pageX - canvas_bounding_rect.left,
					e.changedTouches[i].pageY - canvas_bounding_rect.top,
					10,
					0,
					2 * Math.PI);
		context.stroke();
		last_pos.x = e.changedTouches[i].pageX;
		last_pos.y = e.changedTouches[i].pageY;
	}
}
//-------------------------------------------<|endoftext|>


<commit_before>import { assign, uniq, range, last, isFunction, property, sortBy } from "lodash";
import Helpers from "./helpers";
import Collection from "./collection";
import Scale from "./scale";

export default {
  /**
   * Returns an array of formatted data
   * @param {Object} props: the props object
   * @returns {Array} an array of data
   */
  getData(props) {
    let data;
    if (props.data) {
      if (props.data.length < 1) {
        return [];
      } else {
        data = this.formatData(props.data, props);
      }
    } else {
      data = this.formatData(this.generateData(props), props);
    }
    return this.addEventKeys(props, data);
  },

  /**
   * Returns generated data for a given axis based on domain and sample from props
   * @param {Object} props: the props object
   * @param {String} axis: the current axis
   * @returns {Array} an array of data
   */
  generateDataArray(props, axis) {
    const propsDomain = props.domain && Array.isArray(props.domain) ?
      props.domain : props.domain && props.domain[axis];
    const domain = propsDomain || Scale.getBaseScale(props, axis).domain();
    const samples = props.samples || 1;
    const domainMax = Math.max(...domain);
    const domainMin = Math.min(...domain);
    const step = (domainMax - domainMin) / samples;
    const values = range(domainMin, domainMax, step);
    return last(values) === domainMax ? values : values.concat(domainMax);
  },

  /**
   * Returns generated x and y data based on domain and sample from props
   * @param {Object} props: the props object
   * @returns {Array} an array of data
   */
  generateData(props) {
    const xValues = this.generateDataArray(props, "x");
    const yValues = this.generateDataArray(props, "y");
    const values = xValues.map((x, i) => {
      return { x, y: yValues[i] };
    });
    return values;
  },

  /**
   * Returns formatted data. Data accessors are applied, and string values are replaced.
   * @param {Array} dataset: the original domain
   * @param {Object} props: the props object
   * @param {Object} stringMap: a mapping of string values to numeric values
   * @returns {Array} the formatted data
   */
  formatData(dataset, props, stringMap) {
    if (!Array.isArray(dataset)) {
      return [];
    }
    stringMap = stringMap || {
      x: this.createStringMap(props, "x"),
      y: this.createStringMap(props, "y")
    };
    const accessor = {
      x: Helpers.createAccessor(props.x !== undefined ? props.x : "x"),
      y: Helpers.createAccessor(props.y !== undefined ? props.y : "y"),
      y0: Helpers.createAccessor(props.y0 !== undefined ? props.y0 : "y0")
    };
    const data = dataset.map((datum, index) => {
      const evaluatedX = datum._x !== undefined ? datum._x : accessor.x(datum);
      const evaluatedY = datum._y !== undefined ? datum._y : accessor.y(datum);
      const y0 = datum._y0 !== undefined ? datum._y0 : accessor.y0(datum);
      const x = evaluatedX !== undefined ? evaluatedX : index;
      const y = evaluatedY !== undefined ? evaluatedY : datum;
      return assign(
          { x, y, y0 },
          datum,
          { _x: x, _y: y, _y0: y0 },
          // map string data to numeric values, and add names
          typeof x === "string" ? { _x: stringMap.x[x], xName: x } : {},
          typeof y === "string" ? { _y: stringMap.y[y], yName: y } : {},
          typeof y0 === "string" ? { _y0: stringMap.y[y0], yName: y0 } : {}
        );
    });

    const sortedData = this.sortData(data, props.sortKey);

    return this.cleanData(sortedData, props);
  },

  /**
   * Returns sorted data. If no sort keys are provided, data is returned unaltered.
   * Sort key should correspond to the `iteratees` argument in lodash `sortBy` function.
   * @param {Array} dataset: the original dataset
   * @param {mixed} sortKey: the sort key. Type is whatever lodash permits for `sortBy`
   * @returns {Array} the sorted data
   */
  sortData(dataset, sortKey) {
    if (!sortKey) {
      return dataset;
    }

    // Ensures previous VictoryLine api for sortKey prop stays consistent
    if (sortKey === "x" || sortKey === "y") {
      sortKey = `_${sortKey}`;
    }

    return sortBy(dataset, sortKey);
  },

  /**
   * Returns the cleaned data. Some scale types break when certain data is supplied.
   * This method will remove data points that break certain scales. So far this method
   * only removes zeroes for log scales
   * @param {Array} dataset: the original domain
   * @param {Object} props: the props object
   * @returns {Array} the cleaned data
   */
  cleanData(dataset, props) {
    const scaleType = {
      x: Scale.getScaleType(props, "x"),
      y: Scale.getScaleType(props, "y")
    };
    if (scaleType.x !== "log" && scaleType.y !== "log") {
      return dataset;
    }
    const rules = (datum, axis) => {
      return scaleType[axis] === "log" ? datum[`_${axis}`] !== 0 : true;
    };
    return dataset.filter((datum) => {
      return rules(datum, "x") && rules(datum, "y") && rules(datum, "y0");
    });
  },

  // Returns a data accessor given an eventKey prop
  getEventKey(key) {
    // creates a data accessor function
    // given a property key, path, array index, or null for identity.
    if (isFunction(key)) {
      return key;
    } else if (key === null || typeof key === "undefined") {
      return () => undefined;
    }
    // otherwise, assume it is an array index, property key or path (_.property handles all three)
    return property(key);
  },

  // Returns data with an eventKey prop added to each datum
  addEventKeys(props, data) {
    const eventKeyAccessor = this.getEventKey(props.eventKey);
    return data.map((datum, index) => {
      const eventKey = datum.eventKey || eventKeyAccessor(datum) || index;
      return assign({ eventKey }, datum);
    });
  },

  /**
   * Returns an object mapping string data to numeric data
   * @param {Object} props: the props object
   * @param {String} axis: the current axis
   * @returns {Object} an object mapping string data to numeric data
   */
  createStringMap(props, axis) {
    const stringsFromAxes = this.getStringsFromAxes(props, axis);
    const stringsFromCategories = this.getStringsFromCategories(props, axis);
    const stringsFromData = this.getStringsFromData(props, axis);

    const allStrings = uniq([...stringsFromAxes, ...stringsFromCategories, ...stringsFromData]);
    return allStrings.length === 0 ? null :
      allStrings.reduce((memo, string, index) => {
        memo[string] = index + 1;
        return memo;
      }, {});
  },

  /**
   * Returns an array of strings from data
   * @param {Object} props: the props object
   * @param {String} axis: the current axis
   * @returns {Array} an array of strings
   */
  getStringsFromData(props, axis) {
    if (!Array.isArray(props.data)) {
      return [];
    }
    const key = typeof props[axis] === "undefined" ? axis : props[axis];
    const accessor = Helpers.createAccessor(key);
    const dataStrings = (props.data)
        .map((datum) => accessor(datum))
        .filter((datum) => typeof datum === "string");
    // return a unique set of strings
    return dataStrings.reduce((prev, curr) => {
      if (typeof curr !== "undefined" && curr !== null && prev.indexOf(curr) === -1) {
        prev.push(curr);
      }
      return prev;
    }, []);
  },

  /**
   * Returns an array of strings from axis tickValues for a given axis
   * @param {Object} props: the props object
   * @param {String} axis: the current axis
   * @returns {Array} an array of strings
   */
  getStringsFromAxes(props, axis) {
    if (!props.tickValues || (!Array.isArray(props.tickValues) && !props.tickValues[axis])) {
      return [];
    }
    const tickValueArray = props.tickValues[axis] || props.tickValues;
    return tickValueArray.filter((val) => typeof val === "string");
  },

  /**
   * Returns an array of strings from categories for a given axis
   * @param {Object} props: the props object
   * @param {String} axis: the current axis
   * @returns {Array} an array of strings
   */
  getStringsFromCategories(props, axis) {
    if (!props.categories) {
      return [];
    }
    const categories = this.getCategories(props, axis);
    const categoryStrings = categories && categories.filter((val) => typeof val === "string");
    return categoryStrings ? Collection.removeUndefined(categoryStrings) : [];
  },

  /**
   * Returns an array of categories for a given axis
   * @param {Object} props: the props object
   * @param {String} axis: the current axis
   * @returns {Array} an array of categories
   */
  getCategories(props, axis) {
    return props.categories && !Array.isArray(props.categories) ?
      props.categories[axis] : props.categories;
  }
};
<commit_msg>don't return undefined keys<commit_after>import { assign, uniq, range, last, isFunction, property, sortBy } from "lodash";
import Helpers from "./helpers";
import Collection from "./collection";
import Scale from "./scale";

export default {
  /**
   * Returns an array of formatted data
   * @param {Object} props: the props object
   * @returns {Array} an array of data
   */
  getData(props) {
    let data;
    if (props.data) {
      if (props.data.length < 1) {
        return [];
      } else {
        data = this.formatData(props.data, props);
      }
    } else {
      data = this.formatData(this.generateData(props), props);
    }
    return this.addEventKeys(props, data);
  },

  /**
   * Returns generated data for a given axis based on domain and sample from props
   * @param {Object} props: the props object
   * @param {String} axis: the current axis
   * @returns {Array} an array of data
   */
  generateDataArray(props, axis) {
    const propsDomain = props.domain && Array.isArray(props.domain) ?
      props.domain : props.domain && props.domain[axis];
    const domain = propsDomain || Scale.getBaseScale(props, axis).domain();
    const samples = props.samples || 1;
    const domainMax = Math.max(...domain);
    const domainMin = Math.min(...domain);
    const step = (domainMax - domainMin) / samples;
    const values = range(domainMin, domainMax, step);
    return last(values) === domainMax ? values : values.concat(domainMax);
  },

  /**
   * Returns generated x and y data based on domain and sample from props
   * @param {Object} props: the props object
   * @returns {Array} an array of data
   */
  generateData(props) {
    const xValues = this.generateDataArray(props, "x");
    const yValues = this.generateDataArray(props, "y");
    const values = xValues.map((x, i) => {
      return { x, y: yValues[i] };
    });
    return values;
  },

  /**
   * Returns formatted data. Data accessors are applied, and string values are replaced.
   * @param {Array} dataset: the original domain
   * @param {Object} props: the props object
   * @param {Object} stringMap: a mapping of string values to numeric values
   * @returns {Array} the formatted data
   */
  formatData(dataset, props, stringMap) {
    if (!Array.isArray(dataset)) {
      return [];
    }
    stringMap = stringMap || {
      x: this.createStringMap(props, "x"),
      y: this.createStringMap(props, "y")
    };
    const accessor = {
      x: Helpers.createAccessor(props.x !== undefined ? props.x : "x"),
      y: Helpers.createAccessor(props.y !== undefined ? props.y : "y"),
      y0: Helpers.createAccessor(props.y0 !== undefined ? props.y0 : "y0")
    };
    const data = dataset.map((datum, index) => {
      const evaluatedX = datum._x !== undefined ? datum._x : accessor.x(datum);
      const evaluatedY = datum._y !== undefined ? datum._y : accessor.y(datum);
      const y0 = datum._y0 !== undefined ? datum._y0 : accessor.y0(datum);
      const x = evaluatedX !== undefined ? evaluatedX : index;
      const y = evaluatedY !== undefined ? evaluatedY : datum;
      const originalValues = y0 === undefined ? { x, y } : { x, y, y0 };
      const privateValues = y0 === undefined ? { _x: x, _y: y } : { _x: x, _y: y, _y0: y0 };
      return assign(
          originalValues, datum, privateValues,
          // map string data to numeric values, and add names
          typeof x === "string" ? { _x: stringMap.x[x], xName: x } : {},
          typeof y === "string" ? { _y: stringMap.y[y], yName: y } : {},
          typeof y0 === "string" ? { _y0: stringMap.y[y0], yName: y0 } : {}
        );
    });

    const sortedData = this.sortData(data, props.sortKey);

    return this.cleanData(sortedData, props);
  },

  /**
   * Returns sorted data. If no sort keys are provided, data is returned unaltered.
   * Sort key should correspond to the `iteratees` argument in lodash `sortBy` function.
   * @param {Array} dataset: the original dataset
   * @param {mixed} sortKey: the sort key. Type is whatever lodash permits for `sortBy`
   * @returns {Array} the sorted data
   */
  sortData(dataset, sortKey) {
    if (!sortKey) {
      return dataset;
    }

    // Ensures previous VictoryLine api for sortKey prop stays consistent
    if (sortKey === "x" || sortKey === "y") {
      sortKey = `_${sortKey}`;
    }

    return sortBy(dataset, sortKey);
  },

  /**
   * Returns the cleaned data. Some scale types break when certain data is supplied.
   * This method will remove data points that break certain scales. So far this method
   * only removes zeroes for log scales
   * @param {Array} dataset: the original domain
   * @param {Object} props: the props object
   * @returns {Array} the cleaned data
   */
  cleanData(dataset, props) {
    const scaleType = {
      x: Scale.getScaleType(props, "x"),
      y: Scale.getScaleType(props, "y")
    };
    if (scaleType.x !== "log" && scaleType.y !== "log") {
      return dataset;
    }
    const rules = (datum, axis) => {
      return scaleType[axis] === "log" ? datum[`_${axis}`] !== 0 : true;
    };
    return dataset.filter((datum) => {
      return rules(datum, "x") && rules(datum, "y") && rules(datum, "y0");
    });
  },

  // Returns a data accessor given an eventKey prop
  getEventKey(key) {
    // creates a data accessor function
    // given a property key, path, array index, or null for identity.
    if (isFunction(key)) {
      return key;
    } else if (key === null || typeof key === "undefined") {
      return () => undefined;
    }
    // otherwise, assume it is an array index, property key or path (_.property handles all three)
    return property(key);
  },

  // Returns data with an eventKey prop added to each datum
  addEventKeys(props, data) {
    const eventKeyAccessor = this.getEventKey(props.eventKey);
    return data.map((datum, index) => {
      const eventKey = datum.eventKey || eventKeyAccessor(datum) || index;
      return assign({ eventKey }, datum);
    });
  },

  /**
   * Returns an object mapping string data to numeric data
   * @param {Object} props: the props object
   * @param {String} axis: the current axis
   * @returns {Object} an object mapping string data to numeric data
   */
  createStringMap(props, axis) {
    const stringsFromAxes = this.getStringsFromAxes(props, axis);
    const stringsFromCategories = this.getStringsFromCategories(props, axis);
    const stringsFromData = this.getStringsFromData(props, axis);

    const allStrings = uniq([...stringsFromAxes, ...stringsFromCategories, ...stringsFromData]);
    return allStrings.length === 0 ? null :
      allStrings.reduce((memo, string, index) => {
        memo[string] = index + 1;
        return memo;
      }, {});
  },

  /**
   * Returns an array of strings from data
   * @param {Object} props: the props object
   * @param {String} axis: the current axis
   * @returns {Array} an array of strings
   */
  getStringsFromData(props, axis) {
    if (!Array.isArray(props.data)) {
      return [];
    }
    const key = typeof props[axis] === "undefined" ? axis : props[axis];
    const accessor = Helpers.createAccessor(key);
    const dataStrings = (props.data)
        .map((datum) => accessor(datum))
        .filter((datum) => typeof datum === "string");
    // return a unique set of strings
    return dataStrings.reduce((prev, curr) => {
      if (typeof curr !== "undefined" && curr !== null && prev.indexOf(curr) === -1) {
        prev.push(curr);
      }
      return prev;
    }, []);
  },

  /**
   * Returns an array of strings from axis tickValues for a given axis
   * @param {Object} props: the props object
   * @param {String} axis: the current axis
   * @returns {Array} an array of strings
   */
  getStringsFromAxes(props, axis) {
    if (!props.tickValues || (!Array.isArray(props.tickValues) && !props.tickValues[axis])) {
      return [];
    }
    const tickValueArray = props.tickValues[axis] || props.tickValues;
    return tickValueArray.filter((val) => typeof val === "string");
  },

  /**
   * Returns an array of strings from categories for a given axis
   * @param {Object} props: the props object
   * @param {String} axis: the current axis
   * @returns {Array} an array of strings
   */
  getStringsFromCategories(props, axis) {
    if (!props.categories) {
      return [];
    }
    const categories = this.getCategories(props, axis);
    const categoryStrings = categories && categories.filter((val) => typeof val === "string");
    return categoryStrings ? Collection.removeUndefined(categoryStrings) : [];
  },

  /**
   * Returns an array of categories for a given axis
   * @param {Object} props: the props object
   * @param {String} axis: the current axis
   * @returns {Array} an array of categories
   */
  getCategories(props, axis) {
    return props.categories && !Array.isArray(props.categories) ?
      props.categories[axis] : props.categories;
  }
};
<|endoftext|>