<commit_before>define([
  './var/doc'
], function (doc) {
  function baseInfo() {
    var currentScript = doc.currentScript,
      filePathRgx = /^(.*[\\\/])/;
    //script injection when using BASE tag is now supported
    baseInfo.head = doc.head || doc.getElementsByTagName('head')[0];
    baseInfo.baseElement = doc.getElementsByTagName('base')[0];

    if (baseInfo.baseElement) {
      baseInfo.head = baseInfo.baseElement.parentNode;
    }

    //phantomjs does not provide the "currentScript" property in global document object
    if (currentScript) {
      baseInfo.baseUrl = currentScript.getAttribute('base') || currentScript.src.match(filePathRgx)[1];
      baseInfo.baseGlobal = currentScript.getAttribute('global');
    } else {
      baseInfo.baseUrl = '';
    }
  }

  baseInfo();

  return baseInfo;
});<commit_msg>quick change to trigger a hook<commit_after>define([
  './var/doc'
], function (doc) {
  function baseInfo() {
    var currentScript = doc.currentScript,
      filePathRgx = /^(.*[\\\/])/;
    //script injection when using BASE tag is now supported
    baseInfo.head = doc.head || doc.getElementsByTagName('head')[0];
    baseInfo.baseElement = doc.getElementsByTagName('base')[0];

    if (baseInfo.baseElement) {
      baseInfo.head = baseInfo.baseElement.parentNode;
    }

    //phantomjs does not provide the "currentScript" property in global document object
    if (currentScript) {
      baseInfo.baseUrl = currentScript.getAttribute('base') || currentScript.src.match(filePathRgx)[1];
      baseInfo.baseGlobal = currentScript.getAttribute('global');
    } else {
      baseInfo.baseUrl = '';
    }
  }
  baseInfo();
  return baseInfo;
});<|endoftext|>


<commit_before>jQuery.fn.extend({
	text: function( text ) {
		if ( typeof text !== "object" && text != null )
			return this.empty().append( (this[0] && this[0].ownerDocument || document).createTextNode( text ) );

		var ret = "";

		jQuery.each( text || this, function(){
			jQuery.each( this.childNodes, function(){
				if ( this.nodeType != 8 )
					ret += this.nodeType != 1 ?
						this.nodeValue :
						jQuery.fn.text( [ this ] );
			});
		});

		return ret;
	},

	wrapAll: function( html ) {
		if ( this[0] ) {
			// The elements to wrap the target around
			var wrap = jQuery( html, this[0].ownerDocument ).clone();

			if ( this[0].parentNode )
				wrap.insertBefore( this[0] );

			wrap.map(function(){
				var elem = this;

				while ( elem.firstChild )
					elem = elem.firstChild;

				return elem;
			}).append(this);
		}

		return this;
	},

	wrapInner: function( html ) {
		return this.each(function(){
			jQuery( this ).contents().wrapAll( html );
		});
	},

	wrap: function( html ) {
		return this.each(function(){
			jQuery( this ).wrapAll( html );
		});
	},

	append: function() {
		return this.domManip(arguments, true, function(elem){
			if (this.nodeType == 1)
				this.appendChild( elem );
		});
	},

	prepend: function() {
		return this.domManip(arguments, true, function(elem){
			if (this.nodeType == 1)
				this.insertBefore( elem, this.firstChild );
		});
	},

	before: function() {
		return this.domManip(arguments, false, function(elem){
			this.parentNode.insertBefore( elem, this );
		});
	},

	after: function() {
		return this.domManip(arguments, false, function(elem){
			this.parentNode.insertBefore( elem, this.nextSibling );
		});
	},

	clone: function( events ) {
		// Do the clone
		var ret = this.map(function(){
			if ( !jQuery.support.noCloneEvent && !jQuery.isXMLDoc(this) ) {
				// IE copies events bound via attachEvent when
				// using cloneNode. Calling detachEvent on the
				// clone will also remove the events from the orignal
				// In order to get around this, we use innerHTML.
				// Unfortunately, this means some modifications to
				// attributes in IE that are actually only stored
				// as properties will not be copied (such as the
				// the name attribute on an input).
				var html = this.outerHTML, ownerDocument = this.ownerDocument;
				if ( !html ) {
					var div = ownerDocument.createElement("div");
					div.appendChild( this.cloneNode(true) );
					html = div.innerHTML;
				}

				return jQuery.clean([html.replace(/ jQuery\d+="(?:\d+|null)"/g, "").replace(/^\s*/, "")], ownerDocument)[0];
			} else
				return this.cloneNode(true);
		});

		// Copy the events from the original to the clone
		if ( events === true ) {
			var orig = this.find("*").andSelf(), i = 0;

			ret.find("*").andSelf().each(function(){
				if ( this.nodeName !== orig[i].nodeName )
					return;

				var events = jQuery.data( orig[i], "events" );

				for ( var type in events ) {
					for ( var handler in events[ type ] ) {
						jQuery.event.add( this, type, events[ type ][ handler ], events[ type ][ handler ].data );
					}
				}

				i++;
			});
		}

		// Return the cloned set
		return ret;
	},

	html: function( value ) {
		return value === undefined ?
			(this[0] ?
				this[0].innerHTML.replace(/ jQuery\d+="(?:\d+|null)"/g, "") :
				null) :
			this.empty().append( value );
	},

	replaceWith: function( value ) {
		return this.after( value ).remove();
	},

	domManip: function( args, table, callback ) {
		if ( this[0] ) {
			var fragment = (this[0].ownerDocument || this[0]).createDocumentFragment(),
				scripts = jQuery.clean( args, (this[0].ownerDocument || this[0]), fragment ),
				first = fragment.firstChild;

			if ( first )
				for ( var i = 0, l = this.length; i < l; i++ )
					callback.call( root(this[i], first), this.length > 1 || i > 0 ?
							fragment.cloneNode(true) : fragment );

			if ( scripts )
				jQuery.each( scripts, evalScript );
		}

		return this;

		function root( elem, cur ) {
			return table && jQuery.nodeName(elem, "table") && jQuery.nodeName(cur, "tr") ?
				(elem.getElementsByTagName("tbody")[0] ||
				elem.appendChild(elem.ownerDocument.createElement("tbody"))) :
				elem;
		}
	}
});

jQuery.each({
	appendTo: "append",
	prependTo: "prepend",
	insertBefore: "before",
	insertAfter: "after",
	replaceAll: "replaceWith"
}, function(name, original){
	jQuery.fn[ name ] = function( selector ) {
		var ret = [], insert = jQuery( selector );

		for ( var i = 0, l = insert.length; i < l; i++ ) {
			var elems = (i > 0 ? this.clone(true) : this).get();
			jQuery.fn[ original ].apply( jQuery(insert[i]), elems );
			ret = ret.concat( elems );
		}

		return this.pushStack( ret, name, selector );
	};
});

jQuery.each({
	remove: function( selector ) {
		if ( !selector || jQuery.multiFilter( selector, [ this ] ).length ) {
			if ( this.nodeType === 1 ) {
				cleanData( jQuery("*", this).add(this) );
			}

			if ( this.parentNode ) {
				this.parentNode.removeChild( this );
			}
		}
	},

	empty: function() {
		// Remove element nodes and prevent memory leaks
		if ( this.nodeType === 1 ) {
			cleanData( jQuery("*", this) );
		}

		// Remove any remaining nodes
		while ( this.firstChild ) {
			this.removeChild( this.firstChild );
		}
	}
}, function(name, fn){
	jQuery.fn[ name ] = function(){
		return this.each( fn, arguments );
	};
});

jQuery.extend({
	clean: function( elems, context, fragment ) {
		context = context || document;

		// !context.createElement fails in IE with an error but returns typeof 'object'
		if ( typeof context.createElement === "undefined" )
			context = context.ownerDocument || context[0] && context[0].ownerDocument || document;

		// If a single string is passed in and it's a single tag
		// just do a createElement and skip the rest
		if ( !fragment && elems.length === 1 && typeof elems[0] === "string" ) {
			var match = /^<(\w+)\s*\/?>$/.exec(elems[0]);
			if ( match )
				return [ context.createElement( match[1] ) ];
		}

		var ret = [], scripts = [], div = context.createElement("div");

		jQuery.each(elems, function(i, elem){
			if ( typeof elem === "number" )
				elem += '';

			if ( !elem )
				return;

			// Convert html string into DOM nodes
			if ( typeof elem === "string" ) {
				// Fix "XHTML"-style tags in all browsers
				elem = elem.replace(/(<(\w+)[^>]*?)\/>/g, function(all, front, tag){
					return tag.match(/^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i) ?
						all :
						front + "></" + tag + ">";
				});

				// Trim whitespace, otherwise indexOf won't work as expected
				var tags = elem.replace(/^\s+/, "").substring(0, 10).toLowerCase();

				var wrap =
					// option or optgroup
					!tags.indexOf("<opt") &&
					[ 1, "<select multiple='multiple'>", "</select>" ] ||

					!tags.indexOf("<leg") &&
					[ 1, "<fieldset>", "</fieldset>" ] ||

					tags.match(/^<(thead|tbody|tfoot|colg|cap)/) &&
					[ 1, "
", "
" ] ||

					!tags.indexOf("<tr") &&
					[ 2, "

", "

" ] ||

				 	//
 matched above
					(!tags.indexOf("<td") || !tags.indexOf("<th")) &&
					[ 3, "

", "

" ] ||

					!tags.indexOf("<col") &&
					[ 2, "

<colgroup>", "</colgroup>
" ] ||

					// IE can't serialize <link> and


<commit_before>var rinlinejQuery = / jQuery\d+="(?:\d+|null)"/g,
	rleadingWhitespace = /^\s+/,
	rxhtmlTag = /(<([\w:]+)[^>]*?)\/>/g,
	rselfClosing = /^(?:abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i,
	rtagName = /<([\w:]+)/,
	rtbody = /<tbody/i,
	rhtml = /<|&\w+;/,
	fcloseTag = function(all, front, tag){
		return rselfClosing.test(tag) ?
			all :
			front + "></" + tag + ">";
	},
	wrapMap = {
		option: [ 1, "<select multiple='multiple'>", "</select>" ],
		legend: [ 1, "<fieldset>", "</fieldset>" ],
		thead: [ 1, "
", "
" ],
		tr: [ 2, "

", "

" ],
		td: [ 3, "

", "

" ],
		col: [ 2, "

<colgroup>", "</colgroup>
" ],
		area: [ 1, "<map>", "</map>" ],
		_default: [ 0, "", "" ]
	};

wrapMap.optgroup = wrapMap.option;
wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
wrapMap.th = wrapMap.td;

// IE can't serialize <link> and


<commit_before>/**
 * The Behavior module defines the behavior triggered in response to the Editable.JS
 * events (see {{#crossLink "Editable"}}{{/crossLink}}).
 * The behavior can be overwritten by a user with Editable.init() or on
 * Editable.add() per element.
 *
 * @module core
 * @submodule behavior
 */

var behavior = (function() {
  /**
    * Singleton for the behavior module.
    * Provides default behavior of the Editable.JS API.
    *
    * @class Behavior
    * @static
    */
  return {
    focus: function(element) {
      log('Default focus behavior');
      content.normalizeSpaces(element);
      content.removeEmptyTags(element);
    },

    blur: function(element) {
      log('Default blur behavior');
      content.normalizeTags(element);
      content.cleanInternals(element);
    },

    flow: function(element, action) {
      log('Default flow behavior');
    },

    selection: function(element, selection) {
      if (selection) {
        log('Default selection behavior');
      } else {
        log('Default selection empty behavior');
      }
    },

    cursor: function(element, cursor) {
      if (cursor) {
        log('Default cursor behavior');
      } else {
        log('Default cursor empty behavior');
      }
    },

    newline: function(element, cursor) {
      log(cursor);
      log('Default newline behavior');

      var atTheEnd = cursor.isAtTheEnd();
      var br = document.createElement('br');
      cursor.insertBefore(br);

      if(atTheEnd) {
        log('at the end');

        var noWidthSpace = document.createTextNode('\u200B');
        cursor.insertAfter(noWidthSpace);

        // var trailingBr = document.createElement('br');
        // trailingBr.setAttribute('type', '-editablejs');
        // cursor.insertAfter(trailingBr);

      } else {
        log('not at the end');
      }

      cursor.update();
    },

    insert: function(element, direction, cursor) {
      log('Default insert ' + direction + ' behavior');
      var parent = element.parentNode;
      var newElement = element.cloneNode(false);
      if(newElement.id) newElement.removeAttribute('id');

      switch(direction) {
      case 'before':
        parent.insertBefore(newElement, element);
        element.focus();
        break;
      case 'after':
        parent.insertBefore(newElement, element.nextSibling);
        newElement.focus();
        break;
      }
    },

    split: function(element, before, after, cursor) {
      var parent = element.parentNode;
      var newStart = after.firstChild;
      parent.insertBefore(before, element);
      parent.replaceChild(after, element);
      newStart.focus();
    },

    merge: function(element, direction, cursor) {
      log('Default merge ' + direction + ' behavior');
      var container, merger, fragment, chunks, i, newChild;

      switch(direction) {
      case 'before':
        container = element.previousElementSibling;
        merger = element;
        break;
      case 'after':
        container = element;
        merger = element.nextElementSibling;
        break;
      }

      if(!(container && container.getAttribute('contenteditable') &&
          merger && merger.getAttribute('contenteditable')))
        return;

      if(container.childNodes.length > 0)
        cursor.moveAtTheEnd(container.lastChild);
      else
        cursor.moveAtTheBeginning(container);
      cursor.update();

      fragment = document.createDocumentFragment();
      chunks = merger.childNodes;
      for(i = 0; i < chunks.length; i++) {
        fragment.appendChild(chunks[i].cloneNode(true));
      }
      newChild = container.appendChild(fragment);

      merger.parentNode.removeChild(merger);
    },

    empty: function(element) {
      log('Default empty behavior');
    },

    'switch': function(element, direction, cursor) {
      console.log('Default switch behavior');
    },

    move: function(element, selection, direction) {
      log('Default move behavior');
    },

    clipboard: function(element, selection, action) {
      log('Default clipboard behavior');
    }
  };
})();
<commit_msg>Draft default behavior for switch: move to adjacents<commit_after>/**
 * The Behavior module defines the behavior triggered in response to the Editable.JS
 * events (see {{#crossLink "Editable"}}{{/crossLink}}).
 * The behavior can be overwritten by a user with Editable.init() or on
 * Editable.add() per element.
 *
 * @module core
 * @submodule behavior
 */

var behavior = (function() {
  /**
    * Singleton for the behavior module.
    * Provides default behavior of the Editable.JS API.
    *
    * @class Behavior
    * @static
    */
  return {
    focus: function(element) {
      log('Default focus behavior');
      content.normalizeSpaces(element);
      content.removeEmptyTags(element);
    },

    blur: function(element) {
      log('Default blur behavior');
      content.normalizeTags(element);
      content.cleanInternals(element);
    },

    flow: function(element, action) {
      log('Default flow behavior');
    },

    selection: function(element, selection) {
      if (selection) {
        log('Default selection behavior');
      } else {
        log('Default selection empty behavior');
      }
    },

    cursor: function(element, cursor) {
      if (cursor) {
        log('Default cursor behavior');
      } else {
        log('Default cursor empty behavior');
      }
    },

    newline: function(element, cursor) {
      log(cursor);
      log('Default newline behavior');

      var atTheEnd = cursor.isAtTheEnd();
      var br = document.createElement('br');
      cursor.insertBefore(br);

      if(atTheEnd) {
        log('at the end');

        var noWidthSpace = document.createTextNode('\u200B');
        cursor.insertAfter(noWidthSpace);

        // var trailingBr = document.createElement('br');
        // trailingBr.setAttribute('type', '-editablejs');
        // cursor.insertAfter(trailingBr);

      } else {
        log('not at the end');
      }

      cursor.update();
    },

    insert: function(element, direction, cursor) {
      log('Default insert ' + direction + ' behavior');
      var parent = element.parentNode;
      var newElement = element.cloneNode(false);
      if(newElement.id) newElement.removeAttribute('id');

      switch(direction) {
      case 'before':
        parent.insertBefore(newElement, element);
        element.focus();
        break;
      case 'after':
        parent.insertBefore(newElement, element.nextSibling);
        newElement.focus();
        break;
      }
    },

    split: function(element, before, after, cursor) {
      var parent = element.parentNode;
      var newStart = after.firstChild;
      parent.insertBefore(before, element);
      parent.replaceChild(after, element);
      newStart.focus();
    },

    merge: function(element, direction, cursor) {
      log('Default merge ' + direction + ' behavior');
      var container, merger, fragment, chunks, i, newChild;

      switch(direction) {
      case 'before':
        container = element.previousElementSibling;
        merger = element;
        break;
      case 'after':
        container = element;
        merger = element.nextElementSibling;
        break;
      }

      if(!(container && container.getAttribute('contenteditable') &&
          merger && merger.getAttribute('contenteditable')))
        return;

      if(container.childNodes.length > 0)
        cursor.moveAtTheEnd(container.lastChild);
      else
        cursor.moveAtTheBeginning(container);
      cursor.update();

      fragment = document.createDocumentFragment();
      chunks = merger.childNodes;
      for(i = 0; i < chunks.length; i++) {
        fragment.appendChild(chunks[i].cloneNode(true));
      }
      newChild = container.appendChild(fragment);

      merger.parentNode.removeChild(merger);
    },

    empty: function(element) {
      log('Default empty behavior');
    },

    'switch': function(element, direction, cursor) {
      console.log('Default switch behavior');

      var next, previous;

      switch(direction) {
      case 'before':
        previous = block.previous(element);
        if(previous) {
          cursor.moveAtTheEnd(previous);
          cursor.update();
        }
        break;
      case 'after':
        next = block.next(element);
        if(next) {
          cursor.moveAtTheBeginning(next);
          cursor.update();
        }
        break;
      }
    },

    move: function(element, selection, direction) {
      log('Default move behavior');
    },

    clipboard: function(element, selection, action) {
      log('Default clipboard behavior');
    }
  };
})();
<|endoftext|>


<commit_before>// Import the engine it self
import * as v from 'engine/index';

// Import features you want to use
/* import 'engine/accessibility/enable'; */
/* import 'engine/interaction/enable'; */
/* import 'engine/extract/enable'; */
/* import 'engine/scene/coa/enable'; */
import 'engine/scene/graphics/enable';
/* import 'engine/scene/map/enable'; */
/* import 'engine/scene/mesh/enable'; */
/* import 'engine/scene/particles/enable'; */
import 'engine/scene/sprites/enable';
/* import 'engine/scene/text/enable'; */
/* import 'engine/tween/enable'; */

// Scenes
import Preloader from 'game/preloader/Preloader';
import Test from 'game/test/Sprite';

v.preload('media/04b03.fnt');

v.scene_tree.init({
    application: {
        name: 'Voltar',
        preloader: Preloader,
        main_scene: Test,
    },
    display: {
        view: 'game',
        container: 'container',

        width: 256,
        height: 256,
        resolution: 1,

        background_color: 0x00AAC9,

        antialias: false,
        pixel_snap: true,
        scale_mode: 'nearest',

        FPS: 60,

        stretch_mode: 'viewport',
        stretch_aspect: 'keep',
    },
});
<commit_msg>Import settings converted from godot project<commit_after>// Import the engine it self
import * as v from 'engine/index';

// Import features you want to use
/* import 'engine/accessibility/enable'; */
/* import 'engine/interaction/enable'; */
/* import 'engine/extract/enable'; */
/* import 'engine/scene/coa/enable'; */
import 'engine/scene/graphics/enable';
/* import 'engine/scene/map/enable'; */
/* import 'engine/scene/mesh/enable'; */
/* import 'engine/scene/particles/enable'; */
import 'engine/scene/sprites/enable';
/* import 'engine/scene/text/enable'; */
/* import 'engine/tween/enable'; */

// Scenes
import Preloader from 'game/preloader/Preloader';
import Test from 'game/test/Sprite';

import Settings from 'project.json';

v.preload('media/04b03.fnt');

v.scene_tree.init(
    v.utils.deep_merge(Settings, {
        application: {
            preloader: Preloader,
            main_scene: Test,
        },
    })
);
<|endoftext|>


<commit_before>import cn from 'classnames';
import PropTypes from 'prop-types';
import React, { cloneElement } from 'react';

import SlideDownTransition from './SlideDownTransition';
import { elementType }from './util/PropTypes';

class StaticContainer extends React.Component {
  shouldComponentUpdate = ({ shouldUpdate }) => !!shouldUpdate
  render = () => this.props.children;
}

class Popup extends React.Component {
  static propTypes = {
    open: PropTypes.bool,
    dropUp: PropTypes.bool,
    onEntering: PropTypes.func,
    onEntered: PropTypes.func,
    transition: elementType
  };

  static defaultProps = {
    open: false,
    transition: SlideDownTransition,
  };

  render() {
    let { className, dropUp, open, transition: Transition, ...props } = this.props

    let child = React.Children.only(this.props.children)

    return (
      <Transition
        {...props}
        in={open}
        dropUp={dropUp}
        className={cn(className, 'rw-popup-container')}
      >
        <StaticContainer shouldUpdate={open}>
          {cloneElement(child, {
            className: cn(child.props.className, 'rw-popup')
          })}
        </StaticContainer>
      </Transition>
    )
  }
}

export default Popup
<commit_msg>don't break RHL<commit_after>import cn from 'classnames';
import PropTypes from 'prop-types';
import React, { cloneElement } from 'react';

import SlideDownTransition from './SlideDownTransition';
import { elementType }from './util/PropTypes';

class StaticContainer extends React.Component {
  shouldComponentUpdate({ shouldUpdate }) { return !!shouldUpdate; }
  render() { return this.props.children; }
}

class Popup extends React.Component {
  static propTypes = {
    open: PropTypes.bool,
    dropUp: PropTypes.bool,
    onEntering: PropTypes.func,
    onEntered: PropTypes.func,
    transition: elementType
  };

  static defaultProps = {
    open: false,
    transition: SlideDownTransition,
  };

  render() {
    let { className, dropUp, open, transition: Transition, ...props } = this.props

    let child = React.Children.only(this.props.children)

    return (
      <Transition
        {...props}
        in={open}
        dropUp={dropUp}
        className={cn(className, 'rw-popup-container')}
      >
        <StaticContainer shouldUpdate={open}>
          {cloneElement(child, {
            className: cn(child.props.className, 'rw-popup')
          })}
        </StaticContainer>
      </Transition>
    )
  }
}

export default Popup
<|endoftext|>


<commit_before>export const getSubscription = () => ({
    url: 'payments/subscription',
    method: 'get'
});

export const deleteSubscription = () => ({
    url: 'payments/subscription',
    method: 'delete'
});

export const queryInvoices = ({ Page, PageSize, Owner, State, Type }) => ({
    url: 'payments/invoices',
    method: 'get',
    params: { Page, PageSize, Owner, State, Type }
});

export const queryPlans = (Currency, Cycle) => ({
    url: 'payments/plans',
    method: 'get',
    params: { Currency, Cycle }
});

export const getInvoice = (invoiceID) => ({
    url: `payments/invoices/${invoiceID}`,
    method: 'get',
    output: 'arrayBuffer'
});

export const checkInvoice = (invoiceID, GiftCode) => ({
    url: `payments/invoices/${invoiceID}/check`,
    method: 'put',
    data: { GiftCode }
});

export const queryPaymentMethods = () => ({
    url: 'payments/methods',
    method: 'get'
});

export const setPaymentMethod = (data) => ({
    url: 'payments/methods',
    method: 'post',
    data
});

export const deletePaymentMethod = (methodID) => ({
    url: `payments/methods/${methodID}`,
    method: 'delete'
});

export const createBitcoinPayment = (Amount, Currency) => ({
    url: 'payments/bcinfo',
    method: 'post',
    data: { Amount, Currency }
});

export const createPayPalPayment = (Amount, Currency) => ({
    url: 'payments/paypal',
    method: 'post',
    data: { Amount, Currency }
});

export const payInvoice = (invoiceID, data) => ({
    url: `payments/invoices/${invoiceID}`,
    method: 'post',
    data
});

export const getPaymentMethodStatus = () => ({
    url: 'payments/status',
    method: 'get'
});

export const donate = (data) => ({
    url: 'payments/donate',
    method: 'post',
    data
});
<commit_msg>Add route to buy credit<commit_after>export const getSubscription = () => ({
    url: 'payments/subscription',
    method: 'get'
});

export const deleteSubscription = () => ({
    url: 'payments/subscription',
    method: 'delete'
});

export const queryInvoices = ({ Page, PageSize, Owner, State, Type }) => ({
    url: 'payments/invoices',
    method: 'get',
    params: { Page, PageSize, Owner, State, Type }
});

export const queryPlans = (Currency, Cycle) => ({
    url: 'payments/plans',
    method: 'get',
    params: { Currency, Cycle }
});

export const getInvoice = (invoiceID) => ({
    url: `payments/invoices/${invoiceID}`,
    method: 'get',
    output: 'arrayBuffer'
});

export const checkInvoice = (invoiceID, GiftCode) => ({
    url: `payments/invoices/${invoiceID}/check`,
    method: 'put',
    data: { GiftCode }
});

export const queryPaymentMethods = () => ({
    url: 'payments/methods',
    method: 'get'
});

export const setPaymentMethod = (data) => ({
    url: 'payments/methods',
    method: 'post',
    data
});

export const deletePaymentMethod = (methodID) => ({
    url: `payments/methods/${methodID}`,
    method: 'delete'
});

export const createBitcoinPayment = (Amount, Currency) => ({
    url: 'payments/bcinfo',
    method: 'post',
    data: { Amount, Currency }
});

export const createPayPalPayment = (Amount, Currency) => ({
    url: 'payments/paypal',
    method: 'post',
    data: { Amount, Currency }
});

export const payInvoice = (invoiceID, data) => ({
    url: `payments/invoices/${invoiceID}`,
    method: 'post',
    data
});

export const getPaymentMethodStatus = () => ({
    url: 'payments/status',
    method: 'get'
});

export const donate = (data) => ({
    url: 'payments/donate',
    method: 'post',
    data
});

export const buyCredit = (data) => ({
    url: 'payments/credit',
    method: 'post',
    data
});
<|endoftext|>


<commit_before>var fs = require('fs');
var opn = require('opn');
const format = require('pretty-format')  // https://github.com/facebook/jest/tree/master/packages/pretty-format
const path = require('path')

const OUT_FILENAME = "out.html"
const site_dot = '[shape=box,color=grey,fontcolor=dimgrey]'
const python_dot = '[shape=component,style="bold",color=green,fillcolor=lightgreen,fontsize=18]'
const pip_dot = '[shape=box,color=blue]'
const pip_dot_warn = '[shape=invhouse,color=blue,fillcolor=red,style=filled]'
const default_python_dot = '[style=dashed,color=green]'
const default_pip_dot = '[style=dashed,color=blue]'
const aka_python_dot = '[shape=component,color=green,fontsize=10,width=0.5]'

function visualise_digraphs(brain) {
  // returns multiple digraphs in a list of dicts
  let results = []
  Object.keys(brain.sites).forEach( key => {
    let result = ''

    // Add site
    let site = brain.sites[key]
    result += `  "${r(site.path)}" ${site_dot};\n`

    // Pythons
    for (let python of site.pythons) {
      // Add python
      result += `  "${r(python.path)}" ${python_dot}\n`
      // Add python -> site
      result += `  "${r(python.path)}" -> "${r(site.path)}" [style=dotted]\n`

      if (python.pips.length == 0) {
        // Add ?? pip
        result += `  "${'?? no pip in path'}" ${pip_dot}\n`
        result += `  "${'?? no pip in path'}" -> "${r(python.path)}" [style=dotted,color=red]\n`
      }
      if (python.pip_module_version == undefined) {
        // Add !! pip if not installed for this python
        result += `  "${'!! pip not installed'}" ${pip_dot_warn}\n`
        result += `  "${'!! pip not installed'}" -> "${r(python.path)}" [style=dotted,color=red]\n`
      }

      // Digram the default python invocations
      if (python.report_obj) {
        if (python.report_obj.is_default_for.length == 0) {
          // Add ?? no default
          result += `  "${'?? no python in path will invoke'}" ${default_python_dot}\n`
          result += `  "${'?? no python in path will invoke'}" -> "${r(python.path)}" [style=dashed,color=green]\n`
        }
        else
          for (let default_python_name of python.report_obj.is_default_for) {
            result += `  "${default_python_name}" ${default_python_dot}\n`
            result += `  "${default_python_name}" -> "${r(python.path)}" [style=solid,color=green]\n`
          }

        // Diagram the extra pythons which are really the same python
        if (python.report_obj.paths_all.length > 1) {
          let aka_paths_msg = ''
          for (let aka_python_path of python.report_obj.paths_all) {
            if (aka_python_path == python.path) {
              msg_paths = aka_python_path
              continue
            }
            // Add another aka python into the same box
            aka_paths_msg += '\n' + aka_python_path
          }
          // Add aka pythons
          result += `  "${aka_paths_msg}" ${aka_python_dot}\n`
          // Add aka pythons -> python
          result += `  "${python.path}" -> "${aka_paths_msg}" [style=solid,color=green,dir=none]\n`
          // Add aka python -> site
          result += `  "${aka_paths_msg}" -> "${r(site.path)}" [style=dotted]\n`
        }
      }

    }

    // Pips
    for (let pip of site.pips) {
      // Add pip
      result += `  "${r(pip.path)}" ${pip_dot}\n`
      // Add pip -> site
      result += `  "${r(pip.path)}" -> "${r(site.path)}" [style=dotted]\n`
      // Add pip -> python (could have looped through python.pips instead)
      for (let python of pip.pythons)
        result += `  "${r(pip.path)}" -> "${r(python.path)}" [color=blue]\n`

      // Digram the default pip invocations
      if (pip.report_obj) {
        if (pip.report_obj.is_default_for.length == 0) {
          // Add ?? no default
          result += `  "${'?? no pip in path will invoke'}" ${default_pip_dot}\n`
          result += `  "${'?? no pip in path will invoke'}" -> "${r(pip.path)}" [style=dashed,color=blue]\n`
        }
        else
          for (let default_pip_name of pip.report_obj.is_default_for) {
            result += `  "${default_pip_name}" ${default_pip_dot}\n`
            result += `  "${default_pip_name}" -> "${r(pip.path)}" [style=solid,color=blue]\n`
          }
      }

    }

    // Push result
    let final_obj = {}
    final_obj.digraph = `digraph G {\n${result}\n}`
    final_obj.pythons = [...site.pythons]
    final_obj.pips = [...site.pips]
    results.push( final_obj )
  })
  return results
}

function r(s) {
  // return s.replace(/\//g, ' / ')
  // return s.replace(/\/usr/g, '/usr\n')
  return s
}

function viz3_multiple(brain, digraph_objs) {
  let template = `
  <!doctype html>

    <title>Pipfix Visualisation</title>

    <link href="out.css" rel="stylesheet" type="text/css" />

      Pipfix Report

    `
  return template
}

function write_to_file(html_text, logger) {
  fs.writeFile(OUT_FILENAME, html_text, function(err) {
      if(err) {
          return console.log(err);
      }
      logger.info(`The file '${OUT_FILENAME}' was saved!`);

      // opens the url in the default browser
      opn(OUT_FILENAME);
      logger.debug('done opening file')
      process.exit()
  });
}

function visualise(brain, logger) {
  let digraph_objs = visualise_digraphs(brain)
  for (let digraph_obj of digraph_objs) {
    logger.debug(digraph_objs.digraph)  // pipfix --verbose sets logger to debug level, thus we would see this
  }
  let html = viz3_multiple(brain, digraph_objs)
  write_to_file(html, logger)
}

exports.visualise = visualise
<commit_msg>aka pythons sorted in box<commit_after>var fs = require('fs');
var opn = require('opn');
const format = require('pretty-format')  // https://github.com/facebook/jest/tree/master/packages/pretty-format
const path = require('path')

const OUT_FILENAME = "out.html"
const site_dot = '[shape=box,color=grey,fontcolor=dimgrey]'
const python_dot = '[shape=component,style="bold",color=green,fillcolor=lightgreen,fontsize=18]'
const pip_dot = '[shape=box,color=blue]'
const pip_dot_warn = '[shape=invhouse,color=blue,fillcolor=red,style=filled]'
const default_python_dot = '[style=dashed,color=green]'
const default_pip_dot = '[style=dashed,color=blue]'
const aka_python_dot = '[shape=component,color=green,fontsize=10,width=0.5]'

function sort_by_length(arr) {
  arr.sort(function(a, b){
    // ASC  -> a.length - b.length
    // DESC -> b.length - a.length
    return b.length - a.length;
  }).reverse()
  return arr
}

function visualise_digraphs(brain) {
  // returns multiple digraphs in a list of dicts
  let results = []
  Object.keys(brain.sites).forEach( key => {
    let result = ''

    // Add site
    let site = brain.sites[key]
    result += `  "${r(site.path)}" ${site_dot};\n`

    // Pythons
    for (let python of site.pythons) {
      // Add python
      result += `  "${r(python.path)}" ${python_dot}\n`
      // Add python -> site
      result += `  "${r(python.path)}" -> "${r(site.path)}" [style=dotted]\n`

      if (python.pips.length == 0) {
        // Add ?? pip
        result += `  "${'?? no pip in path'}" ${pip_dot}\n`
        result += `  "${'?? no pip in path'}" -> "${r(python.path)}" [style=dotted,color=red]\n`
      }
      if (python.pip_module_version == undefined) {
        // Add !! pip if not installed for this python
        result += `  "${'!! pip not installed'}" ${pip_dot_warn}\n`
        result += `  "${'!! pip not installed'}" -> "${r(python.path)}" [style=dotted,color=red]\n`
      }

      // Digram the default python invocations
      if (python.report_obj) {
        if (python.report_obj.is_default_for.length == 0) {
          // Add ?? no default
          result += `  "${'?? no python in path will invoke'}" ${default_python_dot}\n`
          result += `  "${'?? no python in path will invoke'}" -> "${r(python.path)}" [style=dashed,color=green]\n`
        }
        else
          for (let default_python_name of python.report_obj.is_default_for) {
            result += `  "${default_python_name}" ${default_python_dot}\n`
            result += `  "${default_python_name}" -> "${r(python.path)}" [style=solid,color=green]\n`
          }

        // Diagram the extra pythons which are really the same python
        if (python.report_obj.paths_all.length > 1) {
          let aka_paths_arr = []
          for (let aka_python_path of python.report_obj.paths_all) {
            if (aka_python_path == python.path) {
              msg_paths = aka_python_path
              continue
            }
            // Add another aka python into the same box
            aka_paths_arr.push(aka_python_path)
          }
          let aka_paths = sort_by_length(aka_paths_arr).join('\n')
          // Add aka pythons
          result += `  "${aka_paths}" ${aka_python_dot}\n`
          // Add aka pythons -> python
          result += `  "${python.path}" -> "${aka_paths}" [style=solid,color=green,dir=none]\n`
          // Add aka python -> site
          result += `  "${aka_paths}" -> "${r(site.path)}" [style=dotted]\n`
        }
      }

    }

    // Pips
    for (let pip of site.pips) {
      // Add pip
      result += `  "${r(pip.path)}" ${pip_dot}\n`
      // Add pip -> site
      result += `  "${r(pip.path)}" -> "${r(site.path)}" [style=dotted]\n`
      // Add pip -> python (could have looped through python.pips instead)
      for (let python of pip.pythons)
        result += `  "${r(pip.path)}" -> "${r(python.path)}" [color=blue]\n`

      // Digram the default pip invocations
      if (pip.report_obj) {
        if (pip.report_obj.is_default_for.length == 0) {
          // Add ?? no default
          result += `  "${'?? no pip in path will invoke'}" ${default_pip_dot}\n`
          result += `  "${'?? no pip in path will invoke'}" -> "${r(pip.path)}" [style=dashed,color=blue]\n`
        }
        else
          for (let default_pip_name of pip.report_obj.is_default_for) {
            result += `  "${default_pip_name}" ${default_pip_dot}\n`
            result += `  "${default_pip_name}" -> "${r(pip.path)}" [style=solid,color=blue]\n`
          }
      }

    }

    // Push result
    let final_obj = {}
    final_obj.digraph = `digraph G {\n${result}\n}`
    final_obj.pythons = [...site.pythons]
    final_obj.pips = [...site.pips]
    results.push( final_obj )
  })
  return results
}

function r(s) {
  // return s.replace(/\//g, ' / ')
  // return s.replace(/\/usr/g, '/usr\n')
  return s
}

function viz3_multiple(brain, digraph_objs) {
  let template = `
  <!doctype html>

    <title>Pipfix Visualisation</title>

    <link href="out.css" rel="stylesheet" type="text/css" />

      Pipfix Report

    `
  return template
}

function write_to_file(html_text, logger) {
  fs.writeFile(OUT_FILENAME, html_text, function(err) {
      if(err) {
          return console.log(err);
      }
      logger.info(`The file '${OUT_FILENAME}' was saved!`);

      // opens the url in the default browser
      opn(OUT_FILENAME);
      logger.debug('done opening file')
      process.exit()
  });
}

function visualise(brain, logger) {
  let digraph_objs = visualise_digraphs(brain)
  for (let digraph_obj of digraph_objs) {
    logger.debug(digraph_objs.digraph)  // pipfix --verbose sets logger to debug level, thus we would see this
  }
  let html = viz3_multiple(brain, digraph_objs)
  write_to_file(html, logger)
}

exports.visualise = visualise
<|endoftext|>


<commit_before>/**
 * @namespace GameRooms
 * @summary Namespace for all rooms related methods.
 */
GameRooms = {};

/**
 * @summary A [Meteor.Collection] containing room documents.
 * @locus Anywhere
 * @type {Meteor.Collection}
 */
GameRooms.rooms = new Meteor.Collection("game_rooms");

/**
 * @summary ID of player's current room
 * @locus Anywhere
 */
GameRooms.currentRoomId = function () {
    var playerId = GamePlayers.playerId();
    if (!playerId) {
        return null;
    }
    var room =  GameRooms.rooms.findOne({
        players: {
            $elemMatch: {
                id: playerId
            }
        }
    });
    if (!room) {
        return null;
    }
    return room._id;
};

/**
 * @summary Player's current room
 * @locus Anywhere
 */
GameRooms.currentRoom = function () {
    var currentRoomId = this.currentRoomId();
    if (!currentRoomId) {
        return null;
    }
    return GameRooms.rooms.findOne(currentRoomId);
};

if (Meteor.isServer) {

    Meteor.publish(null, function() {
        //We publish all rooms
        return GameRooms.rooms.find();
    });

    var createRoom = function(name) {
        return GameRooms.rooms.insert({
            name: name,
            players: [],
            owner: null
        });
    };

    var addPlayerToRoom = function(playerId, roomId, isOwner){
        var player = GamePlayers.players.findOne(playerId);
        var addOptions = {
            $push: {
                players: {
                    id: player._id,
                    name: player.name
                }
            }
        };
        if (isOwner) {
            addOptions.$set = {
                owner: playerId
            };
        }
        GameRooms.rooms.update(roomId, addOptions);
    };

    var removePlayerFromRoom = function(playerId, roomId) {
        var room = GameRooms.rooms.findOne(roomId);
        if (!room) {
            throw new Meteor.Error('Room does not exist');
        }
        var players = _.reject(room.players, function(elem){
            return elem.id == playerId;
        });
        GameRooms.rooms.update(roomId, {$set: {players: players}});
        //TODO decide what to do if player is owner of the room, probably assign another user.
    };

    var setCurrentRoom = function(roomId) {
        var room = GameRooms.rooms.findOne(roomId);
        if (!room) {
            throw new Meteor.Error('Room does not exist');
        }
        var currentRoom = GameRooms.currentRoom();
        if (currentRoom) {
            removePlayerFromRoom(GamePlayers.playerId(), currentRoom._id);
        }
        addPlayerToRoom(GamePlayers.playerId(), room._id);
    };

    /**
     * @summary Override this to define a function which will start a new game instance
     * @locus Server
     * @param {String} roomId Identifier of the room
     */
    GameRooms.startGameCallback = function (roomId) {};

    Meteor.methods({
        setCurrentRoom: setCurrentRoom,
        leaveRoom: function () {
            var player = GamePlayers.player();
            if (!player) {
                throw new Meteor.Error('User has no player profile');
            }
            var room = GameRooms.currentRoom();
            if (!room) {
                throw new Meteor.Error('Player is not in a room');
            }
            removePlayerFromRoom(player._id, room._id);
        },
        createRoom: function (name) {
            var roomId = createRoom(name);
            addPlayerToRoom(GamePlayers.playerId(), roomId, true);
        },
        startGame: function() {
            var player = GamePlayers.player();
            if (!player) {
                throw new Meteor.Error('User has no player profile');
            }
            var room = GameRooms.currentRoom();
            if (!room) {
                throw new Meteor.Error('Player is not in a room');
            }
            if (room.owner != player._id) {
                throw new Meteor.Error('Only the room owner can start the game');
            }
            var gameId =  GameRooms.startGameCallback(room._id);
            if (!gameId) {
                throw new Meteor.Error('Game creation callback does not return any game identifier');
            }
            GameRooms.rooms.update(room._id, {
                $set: {
                    game: gameId
                }
            });
        }
    });
}

if (Meteor.isClient) {
    /**
     * @summary Creates a room for current player
     * @param {string} name - Room's name
     * @locus Client
     */
    GameRooms.createRoom = function (name) {
        return Meteor.call('createRoom', name);
    };
    /**
     * @summary Makes current player join a room
     * @param {string} id - Room's ID
     * @locus Client
     */
    GameRooms.joinRoom = function (id) {
        return Meteor.call('setCurrentRoom', id);
    };
    /**
     * @summary Makes current player leave current room
     * @locus Client
     */
    GameRooms.leaveRoom = function () {
        return Meteor.call('leaveRoom');
    };
}<commit_msg>Enable callback when player leaves room, a new owner is chosen when owner leaves, room is deleted if there is no player left. Closes #8.<commit_after>/**
 * @namespace GameRooms
 * @summary Namespace for all rooms related methods.
 */
GameRooms = {};

/**
 * @summary A [Meteor.Collection] containing room documents.
 * @locus Anywhere
 * @type {Meteor.Collection}
 */
GameRooms.rooms = new Meteor.Collection("game_rooms");

/**
 * @summary ID of player's current room
 * @locus Anywhere
 */
GameRooms.currentRoomId = function () {
    var playerId = GamePlayers.playerId();
    if (!playerId) {
        return null;
    }
    var room =  GameRooms.rooms.findOne({
        players: {
            $elemMatch: {
                id: playerId
            }
        }
    });
    if (!room) {
        return null;
    }
    return room._id;
};

/**
 * @summary Player's current room
 * @locus Anywhere
 */
GameRooms.currentRoom = function () {
    var currentRoomId = this.currentRoomId();
    if (!currentRoomId) {
        return null;
    }
    return GameRooms.rooms.findOne(currentRoomId);
};

if (Meteor.isServer) {

    /**
     * @summary Override this to define a function which will start a new game instance
     * @locus Server
     * @param {String} roomId Identifier of the room
     */
    GameRooms.startGameCallback = function (roomId) {};

    /**
     * @summary Override this to define a function which will be triggered when a player leaves a room
     * @locus Server
     * @param {String} playerId Identifier of the player
     * @param {String} roomId Identifier of the room
     */
    GameRooms.playerLeavesRoomCallback = function (playerId, roomId) {};

    Meteor.publish(null, function() {
        //We publish all rooms
        return GameRooms.rooms.find();
    });

    var createRoom = function(name) {
        return GameRooms.rooms.insert({
            name: name,
            players: [],
            owner: null
        });
    };

    var addPlayerToRoom = function(playerId, roomId, isOwner){
        var player = GamePlayers.players.findOne(playerId);
        var addOptions = {
            $push: {
                players: {
                    id: player._id,
                    name: player.name
                }
            }
        };
        if (isOwner) {
            addOptions.$set = {
                owner: playerId
            };
        }
        GameRooms.rooms.update(roomId, addOptions);
    };

    var removePlayerFromRoom = function(playerId, roomId) {
        var room = GameRooms.rooms.findOne(roomId);
        if (!room) {
            throw new Meteor.Error('Room does not exist');
        }
        var players = _.reject(room.players, function(elem){
            return elem.id == playerId;
        });
        var updateFields = {players: players};
        var deleteRoom = false;
        if (playerId == room.owner) {
            if (players.length) {
                updateFields.owner = _.sample(players).id;
            } else {
                deleteRoom = true;
            }
        }
        GameRooms.rooms.update(roomId, {$set: updateFields});
        GameRooms.playerLeavesRoomCallback(playerId, roomId);
        if (deleteRoom) {
            GameRooms.rooms.remove(roomId);
        }
    };

    var setCurrentRoom = function(roomId) {
        var room = GameRooms.rooms.findOne(roomId);
        if (!room) {
            throw new Meteor.Error('Room does not exist');
        }
        var currentRoom = GameRooms.currentRoom();
        if (currentRoom) {
            removePlayerFromRoom(GamePlayers.playerId(), currentRoom._id);
        }
        addPlayerToRoom(GamePlayers.playerId(), room._id);
    };

    Meteor.methods({
        setCurrentRoom: setCurrentRoom,
        leaveRoom: function () {
            var player = GamePlayers.player();
            if (!player) {
                throw new Meteor.Error('User has no player profile');
            }
            var room = GameRooms.currentRoom();
            if (!room) {
                throw new Meteor.Error('Player is not in a room');
            }
            removePlayerFromRoom(player._id, room._id);
        },
        createRoom: function (name) {
            var roomId = createRoom(name);
            addPlayerToRoom(GamePlayers.playerId(), roomId, true);
        },
        startGame: function() {
            var player = GamePlayers.player();
            if (!player) {
                throw new Meteor.Error('User has no player profile');
            }
            var room = GameRooms.currentRoom();
            if (!room) {
                throw new Meteor.Error('Player is not in a room');
            }
            if (room.owner != player._id) {
                throw new Meteor.Error('Only the room owner can start the game');
            }
            var gameId =  GameRooms.startGameCallback(room._id);
            if (!gameId) {
                throw new Meteor.Error('Game creation callback does not return any game identifier');
            }
            GameRooms.rooms.update(room._id, {
                $set: {
                    game: gameId
                }
            });
        }
    });
}

if (Meteor.isClient) {
    /**
     * @summary Creates a room for current player
     * @param {string} name - Room's name
     * @locus Client
     */
    GameRooms.createRoom = function (name) {
        return Meteor.call('createRoom', name);
    };
    /**
     * @summary Makes current player join a room
     * @param {string} id - Room's ID
     * @locus Client
     */
    GameRooms.joinRoom = function (id) {
        return Meteor.call('setCurrentRoom', id);
    };
    /**
     * @summary Makes current player leave current room
     * @locus Client
     */
    GameRooms.leaveRoom = function () {
        return Meteor.call('leaveRoom');
    };
}<|endoftext|>


<commit_before>
var gatherer = require('../lib/gatherer')
var db = require('mongo-promise')
var _ = require('lodash')
var rsvp = require('rsvp')

module.exports = {

  warmMany: function(arr) {
    var obj = arr[0]
    if (!obj) return
    this.warm(obj).then(setTimeout(this.warmMany.bind(this, arr.slice(1)), 200))
  },

  warm: function(obj) {
    return new rsvp.Promise(function(res, rej) {
      if (!obj.refs.length) return res()

      gatherer.gather({
        refs: obj.refs,
        adapters: this.adapters
      }).then(function(data) {
        data._entityId = obj._id.toString()
        db[this.collection].findAndModify({ _entityId: obj._id }, null, data, { upsert: true, 'new':true }).then(function(doc) {
          res(doc)
        })
      }.bind(this))
    }.bind(this))
  },

  isOutdated: function(obj) {
    if (!obj._meta || !obj._meta.fields) return true

    var now = Date.now() / 1000
    var expiries = _.pluck(obj._meta.fields, 'expires')
    return _.any(expiries, function(exp) { return exp < now })
  },

  search: function(params) {

    var fields = params.fields
    var query = this.buildQuery(params.q || {})
    var opts = { skip: parseInt(params.skip || 0), limit: parseInt(params.limit || 500) }

    return db[this.collection].find(query, fields, opts).then(function(results) {
      _.filter(results, this.isOutdated).forEach(this.warm.bind(this))
      return results
    }.bind(this))
  },

  validateRefs: function(refs) {
    return refs.map(function(ref) {
      if (!this.adapters[ref.adapter].canUse(ref.id)) {
        ref.status = 'broken'
      }
      return ref
    }, this)
  }

}
<commit_msg>update time out on warm<commit_after>
var gatherer = require('../lib/gatherer')
var db = require('mongo-promise')
var _ = require('lodash')
var rsvp = require('rsvp')

module.exports = {

  warmMany: function(arr) {
    var obj = arr[0]
    if (!obj) return
    this.warm(obj).then(setTimeout(this.warmMany.bind(this, arr.slice(1)), 2000))
  },

  warm: function(obj) {
    return new rsvp.Promise(function(res, rej) {
      if (!obj.refs.length) return res()

      gatherer.gather({
        refs: obj.refs,
        adapters: this.adapters
      }).then(function(data) {
        data._entityId = obj._id.toString()
        db[this.collection].findAndModify({ _entityId: obj._id }, null, data, { upsert: true, 'new':true }).then(function(doc) {
          res(doc)
        })
      }.bind(this))
    }.bind(this))
  },

  isOutdated: function(obj) {
    if (!obj._meta || !obj._meta.fields) return true

    var now = Date.now() / 1000
    var expiries = _.pluck(obj._meta.fields, 'expires')
    return _.any(expiries, function(exp) { return exp < now })
  },

  search: function(params) {

    var fields = params.fields
    var query = this.buildQuery(params.q || {})
    var opts = { skip: parseInt(params.skip || 0), limit: parseInt(params.limit || 500) }

    return db[this.collection].find(query, fields, opts).then(function(results) {
      _.filter(results, this.isOutdated).forEach(this.warm.bind(this))
      return results
    }.bind(this))
  },

  validateRefs: function(refs) {
    return refs.map(function(ref) {
      if (!this.adapters[ref.adapter].canUse(ref.id)) {
        ref.status = 'broken'
      }
      return ref
    }, this)
  }

}
<|endoftext|>


<commit_before>const admin = require('firebase-admin');
const fetch = require('node-fetch');
const DigestFetch = require('digest-fetch');

const serviceAccount = require(process.env.FIREBASEKEY);

admin.initializeApp({
  credential: admin.credential.cert(serviceAccount),
  databaseURL: `https://${process.env.FIREBASENAME}.firebaseio.com`
});
const db = admin.database();

const occupancyEstimators = [{
  userId: process.env.AXISUSER,
  pass: process.env.AXISPASS,
  domain: "axis-sel-main-c120.lib.virginia.edu",
  fbpath: "locations-schemaorg/location/science/estimatedOccupancy",
  fblogpath: "locationsLogs/science/estimatedOccupancylog"
}]

var promises = [];

occupancyEstimators.forEach(oe=>{
  const client = new DigestFetch(oe.userId, oe.pass, { algorithm: 'MD5' })
  promises.push(client.fetch(`http://${oe.domain}/local/occupancy-estimator/.api?live-occupancy.json`)
    .then(res => res.json())
    .then((data)=>{
      const ref = db.ref(oe.fbpath);
      return ref.once("value").then(snapshot=>{
        var promises = [];
        var val = snapshot.val();
        var loggit = false;
        if (!val) val = {timestamp:null, value:null, totalIn:null, totalOut:null};
        var newval = {};
        if (data.occupancy !== val.value) {
          newval.value = data.occupancy;
          loggit = true;
        }
        if (data['total in'] != val.totalIn) {
          newval.totalIn = data['total in'];
          loggit = true;
        }
        if (data['total out'] != val.totalOut) {
          newval.totalOut = data['total out'];
          loggit = true;
        }
        var newtimestamp = data.unixtime*1000;
        // log if occupancy changed
        if (loggit) {
          promises.push( db.ref(oe.fblogpath+'/'+newtimestamp).set(newval) );
        }
        // update main
        newval.timestamp = newtimestamp;
        promises.push( ref.update(newval) );
        console.log(data);
        return Promise.all(promises);
      });
    }));
});

Promise.all(promises).then(process.exit);<commit_msg>added clemons axis cameras to count polling<commit_after>const admin = require('firebase-admin');
const fetch = require('node-fetch');
const DigestFetch = require('digest-fetch');

const serviceAccount = require(process.env.FIREBASEKEY);

admin.initializeApp({
  credential: admin.credential.cert(serviceAccount),
  databaseURL: `https://${process.env.FIREBASENAME}.firebaseio.com`
});
const db = admin.database();

const occupancyEstimators = [
  {
  userId: process.env.AXISUSER,
  pass: process.env.AXISPASS,
  domain: "axis-sel-main-c120.lib.virginia.edu",
  fbpath: "locations-schemaorg/location/science/estimatedOccupancy",
  fblogpath: "locationsLogs/science/estimatedOccupancylog"
  },
  {
    userId: process.env.AXISUSER,
    pass: process.env.AXISPASS,
    domain: "axis-clm-m3065v-c410a.lib.virginia.edu",
    fbpath: "locations-schemaorg/location/clemons/estimatedOccupancy",
    fblogpath: "locationsLogs/clemons/estimatedOccupancylog"
  }
]

var promises = [];

occupancyEstimators.forEach(oe=>{
  const client = new DigestFetch(oe.userId, oe.pass, { algorithm: 'MD5' })
  promises.push(client.fetch(`http://${oe.domain}/local/occupancy-estimator/.api?live-occupancy.json`)
    .then(res => res.json())
    .then((data)=>{
      const ref = db.ref(oe.fbpath);
      return ref.once("value").then(snapshot=>{
        var promises = [];
        var val = snapshot.val();
        var loggit = false;
        if (!val) val = {timestamp:null, value:null, totalIn:null, totalOut:null};
        var newval = {};
        if (data.occupancy !== val.value) {
          newval.value = data.occupancy;
          loggit = true;
        }
        if (data['total in'] != val.totalIn) {
          newval.totalIn = data['total in'];
          loggit = true;
        }
        if (data['total out'] != val.totalOut) {
          newval.totalOut = data['total out'];
          loggit = true;
        }
        var newtimestamp = data.unixtime*1000;
        // log if occupancy changed
        if (loggit) {
          promises.push( db.ref(oe.fblogpath+'/'+newtimestamp).set(newval) );
        }
        // update main
        newval.timestamp = newtimestamp;
        promises.push( ref.update(newval) );
        console.log(data);
        return Promise.all(promises);
      });
    }));
});

Promise.all(promises).then(process.exit);<|endoftext|>


<commit_before>/*Filter Circle
* Get the current Circle name
* if it starts with a hash tag
* filter all messages that do not contain that hash tag */
var tagtext="";

/*descend takes a starting DOM node and a list of indices
* and the returns the node at the end of the tree path*/
function descend(start,childlist){
	var curchild = start;
	//console.log(start);
	for(index in childlist) {
		var i = childlist[index];
		curchild = curchild.childNodes[i];
	}
	return curchild;
}

function tryToGetPostText(post){
	try{
		var domchild = post.get(0);
		var magic_path = [0,1,0,0,0];//This will probably break.
		var postText = descend(domchild,magic_path).innerHTML;
	}catch(err){
		postText = "";
//		console.log(post.get(0))
//		console.log("caught err:"+err);//Doesn't work on all?
	}
	//console.log("Text:"+postText);
	return postText;
}

function hideTaggedPost(post,tag,hiddenlist){
	var postText = tryToGetPostText(post);
	try{
	if(postText.match(""+tag)){
		//console.log("tag:"+tag+"//text:"+postText+
			//           post.get(0));
		hidePost(post,hiddenlist);
	}
	}catch(err){
		console.log("hideTaggedPost:");
		console.log(post);
		console.log(err);
	}

}

function hidePost(post,hiddenlist){
	hiddenlist[post.get(0)] = true;
	post.css("display","none");
}

/*takes a boolean function(post,text), and hides those posts*/
function hidePosts(func){
	//Shouldn't hiddenlist get recreated each time this
	//function gets called?
	var hiddenlist = {};
	var selection = $("div[id*=update]");
	selection.each(function (){
			var $post = $(this);
			var text = tryToGetPostText($post);
			if(func($post,text)){
				hidePost($post,hiddenlist);
			}else{
				//For some reason, the next
				//each doesn't work...
				$post.css("display","block");
			}
		});

	/*Explicitly show all non-hidden posts*/
	/*NOTE:...and this doesn't seem to work.*/
	selection.each( function(){
		   var $post = $(this);
		   if(hiddenlist[$post.get(0)] == undefined){
			   $post.css("display","block");
		   }
		});
}

function getCircleHashTag(){
	var contentpane=$("div[id=contentPane]").get(0);
	try{
	var circlename = descend(contentPane,[0,0,0]).innerHTML;
	if(circlename.match("<span class")){
		circlename = descend(contentPane,[0,0,0,0]).innerHTML;
	}
	//console.log(circlename);
	if(circlename[0] == "#"){
		return circlename;
	}
	}catch(err){
		console.log("getCircleHashTag:");
		console.log(contentPane);
		console.log(err);
	}
	return "";
}

function filter_circles(e){
	var circle_hashtag=getCircleHashTag();
	console.log(circle_hashtag);
	var nofollow= "[^a-zA-Z0-9]";
	var hashtag_regex = circle_hashtag+nofollow;
	//console.log(circle_hashtag);
	if(circle_hashtag != ""){
		hidePosts(function(post,text) {
			//console.log(text);
			try{
				//undefined needs to be expanded
				//for larger use cases
				if(text==undefined){
					//If we can't parse it
					//hide it.
					console.log(post);
					return true;
				}
				if(text.match(hashtag_regex)==null){
					return true;
				}
				return false;
			}catch(err){
				console.log("filter_circles:");
				console.log(post);
				console.log(err);
			}
		});
	}else{
		//Show all
		var selection = $("div[id*=update]");
		selection.css("display","block");
	}
}

/*The following needs a lot more work to be general
* For starters, clicking more breaks things. A fast way to
* deal with all posts might be a very good idea.*/
var lastGroup = "";
function checkForChange(force){
	if(force == undefined){
		force = false;
	}
	try{
		var contentpane=$("div[id=contentPane]").get(0);
		var curGroup = descend(contentPane,[0,0,0]).innerHTML;
		if(curGroup != lastGroup || force){
			lastGroup = curGroup;
			filter_circles();
		}
	} catch(err){
		console.log("Error:"+err);
	}
}

console.log($("div[id=contentPane]").get(0));
/*addEventListener("mousedown",
	function(){console.log("hey");
		setTimeout(function(){checkForChange(true)},1000)});*/
setInterval(function(){checkForChange(true)},120)//Hack!Hack!Hack!
<commit_msg>Removed console.log.<commit_after>/*Filter Circle
* Get the current Circle name
* if it starts with a hash tag
* filter all messages that do not contain that hash tag */
var tagtext="";

/*descend takes a starting DOM node and a list of indices
* and the returns the node at the end of the tree path*/
function descend(start,childlist){
	var curchild = start;
	//console.log(start);
	for(index in childlist) {
		var i = childlist[index];
		curchild = curchild.childNodes[i];
	}
	return curchild;
}

function tryToGetPostText(post){
	try{
		var domchild = post.get(0);
		var magic_path = [0,1,0,0,0];//This will probably break.
		var postText = descend(domchild,magic_path).innerHTML;
	}catch(err){
		postText = "";
//		console.log(post.get(0))
//		console.log("caught err:"+err);//Doesn't work on all?
	}
	//console.log("Text:"+postText);
	return postText;
}

function hideTaggedPost(post,tag,hiddenlist){
	var postText = tryToGetPostText(post);
	try{
	if(postText.match(""+tag)){
		//console.log("tag:"+tag+"//text:"+postText+
			//           post.get(0));
		hidePost(post,hiddenlist);
	}
	}catch(err){
		console.log("hideTaggedPost:");
		console.log(post);
		console.log(err);
	}

}

function hidePost(post,hiddenlist){
	hiddenlist[post.get(0)] = true;
	post.css("display","none");
}

/*takes a boolean function(post,text), and hides those posts*/
function hidePosts(func){
	//Shouldn't hiddenlist get recreated each time this
	//function gets called?
	var hiddenlist = {};
	var selection = $("div[id*=update]");
	selection.each(function (){
			var $post = $(this);
			var text = tryToGetPostText($post);
			if(func($post,text)){
				hidePost($post,hiddenlist);
			}else{
				//For some reason, the next
				//each doesn't work...
				$post.css("display","block");
			}
		});

	/*Explicitly show all non-hidden posts*/
	/*NOTE:...and this doesn't seem to work.*/
	selection.each( function(){
		   var $post = $(this);
		   if(hiddenlist[$post.get(0)] == undefined){
			   $post.css("display","block");
		   }
		});
}

function getCircleHashTag(){
	var contentpane=$("div[id=contentPane]").get(0);
	try{
	var circlename = descend(contentPane,[0,0,0]).innerHTML;
	if(circlename.match("<span class")){
		circlename = descend(contentPane,[0,0,0,0]).innerHTML;
	}
	//console.log(circlename);
	if(circlename[0] == "#"){
		return circlename;
	}
	}catch(err){
		console.log("getCircleHashTag:");
		console.log(contentPane);
		console.log(err);
	}
	return "";
}

function filter_circles(e){
	var circle_hashtag=getCircleHashTag();
	//console.log(circle_hashtag);
	var nofollow= "[^a-zA-Z0-9]";
	var hashtag_regex = circle_hashtag+nofollow;
	//console.log(circle_hashtag);
	if(circle_hashtag != ""){
		hidePosts(function(post,text) {
			//console.log(text);
			try{
				//undefined needs to be expanded
				//for larger use cases
				if(text==undefined){
					//If we can't parse it
					//hide it.
					console.log(post);
					return true;
				}
				if(text.match(hashtag_regex)==null){
					return true;
				}
				return false;
			}catch(err){
				console.log("filter_circles:");
				console.log(post);
				console.log(err);
			}
		});
	}else{
		//Show all
		var selection = $("div[id*=update]");
		selection.css("display","block");
	}
}

/*The following needs a lot more work to be general
* For starters, clicking more breaks things. A fast way to
* deal with all posts might be a very good idea.*/
var lastGroup = "";
function checkForChange(force){
	if(force == undefined){
		force = false;
	}
	try{
		var contentpane=$("div[id=contentPane]").get(0);
		var curGroup = descend(contentPane,[0,0,0]).innerHTML;
		if(curGroup != lastGroup || force){
			lastGroup = curGroup;
			filter_circles();
		}
	} catch(err){
		console.log("Error:"+err);
	}
}

console.log($("div[id=contentPane]").get(0));
/*addEventListener("mousedown",
	function(){console.log("hey");
		setTimeout(function(){checkForChange(true)},1000)});*/
setInterval(function(){checkForChange(true)},120)//Hack!Hack!Hack!
<|endoftext|>


<commit_before>$(document).ready(function(){
	// initialize tab
	$("#tabs").tabs();

	/** binding */
	// select url when focus on #url [text input]
	$("#url").bind('click', function(){
		this.select();
	});

	// select lyric all
	$("#select").bind("click", function(e){
		$("#lyric_div > textarea").focus();
		$("#lyric_div > textarea").select();
	});

	// copy lyric

	if (window.clipboardData){
		$("#copy").bind("click", function(e){
			var text = $("#lyric_div > textarea").val();
			window.clipboardData.clearData();
			window.clipboardData.setData("Text", text);
			window.alert("Lyric has copied to Clipboard.");
		});
	} else {
		$("#copy").attr("disabled", "disabled");
	}

	// binding examples URL
	$("#examples a").click(function(e){
		e.preventDefault();

		var url = e.target.href;
		$("#url").val(url);
		$("#btn_submit").submit();
	});

	// submit url to get episode list
	$("#query_form").bind("submit", function(e){
		// no form submit action
		e.preventDefault();

		var url = jQuery.trim($("#url").val());

		// check input
		if (url == "" || url == $("#url").attr("title")) {
			return false;
		}

		// show waiting dialog
		$("#btn_submit").attr("disabled", "disabled");
		$("#lyric_div").hide();
		$("#lyric_div > textarea").empty();
		$("#loading_div").html("Loading...");
		$("#loading_div").show();

		// JSON query
		$.getJSON(
			"https://lyric-get-node-test1.azurewebsites.net/app",
			{'url': url},
			function(data){
				var lyric = data["lyric"];
				if (!lyric) {
					// failed to get lyric
					$("#loading_div").html('Failed to get lyric. Please contact franklai.');
					$("#btn_submit").removeAttr("disabled");
					return;
				}
				var count = lyric.split("\n");
				//alert(tmp.length);
				//lyric = tmp.join("
");

				//$("#lyric_div > div").html(lyric);
				$("#lyric_div > textarea").val(lyric);
				$("#lyric_div > textarea").css("height", (14*count.length)+"pt");

				$("#loading_div").hide();
				$("#lyric_div").show();
				$("#btn_submit").removeAttr("disabled");
			}
		);
	});

	$("#loading_div").ajaxError(function(event, request, settings){
		$(this).html('Error.');
		$("#btn_submit").removeAttr("disabled");
	});

});
<commit_msg>set script.js to unix format, and use 2 spaces instead of tab<commit_after>const engine = require('lyric-get-engine');

$(document).ready(function(){
  // initialize tab
  $("#tabs").tabs();

  /** binding */
  // select url when focus on #url [text input]
  $("#url").bind('click', function(){
    this.select();
  });

  // select lyric all
  $("#select").bind("click", function(e){
    $("#lyric_div > textarea").focus();
    $("#lyric_div > textarea").select();
  });

  // copy lyric

  if (window.clipboardData){
    $("#copy").bind("click", function(e){
      var text = $("#lyric_div > textarea").val();
      window.clipboardData.clearData();
      window.clipboardData.setData("Text", text);
      window.alert("Lyric has copied to Clipboard.");
    });
  } else {
    $("#copy").attr("disabled", "disabled");
  }

  // binding examples URL
  $("#examples a").click(function(e){
    e.preventDefault();

    var url = e.target.href;
    $("#url").val(url);
    $("#btn_submit").submit();
  });

  // submit url to get episode list
  $("#query_form").bind("submit", function(e){
    // no form submit action
    e.preventDefault();

    var url = jQuery.trim($("#url").val());

    // check input
    if (url == "" || url == $("#url").attr("title")) {
      return false;
    }

    // show waiting dialog
    $("#btn_submit").attr("disabled", "disabled");
    $("#lyric_div").hide();
    $("#lyric_div > textarea").empty();
    $("#loading_div").html("Loading...");
    $("#loading_div").show();

    // JSON query
    $.getJSON(
      "https://lyric-get-node-test1.azurewebsites.net/app",
      {'url': url},
      function(data){
        var lyric = data["lyric"];
        if (!lyric) {
          // failed to get lyric
          $("#loading_div").html('Failed to get lyric. Please contact franklai.');
          $("#btn_submit").removeAttr("disabled");
          return;
        }
        var count = lyric.split("\n");
        //alert(tmp.length);
        //lyric = tmp.join("
");

        //$("#lyric_div > div").html(lyric);
        $("#lyric_div > textarea").val(lyric);
        $("#lyric_div > textarea").css("height", (14*count.length)+"pt");

        $("#loading_div").hide();
        $("#lyric_div").show();
        $("#btn_submit").removeAttr("disabled");
      }
    );
  });

  $("#loading_div").ajaxError(function(event, request, settings){
    $(this).html('Error.');
    $("#btn_submit").removeAttr("disabled");
  });
});

// vim: tabstop=2 shiftwidth=2 expandtab
<|endoftext|>


<commit_before>module.exports = {
  'usd': {
    code: 'usd',
    minAmount: '2',
    symbol: '$',
    paypalFixedFee: {
      macro: 0.30,
      micro: 0.05
    },
    presets: {
      single: ['20', '10', '5', '3'],
      monthly: ['10', '5', '3', '2']
    }
  },
  'aed': {
    code: 'aed',
    minAmount: '8',
    symbol: 'د.إ.',
    disabled: "paypal",
    presets: {
      single: ['55', '37', '18', '11'],
      monthly: ['37', '18', '11', '8']
    }
  },
  'aud': {
    code: 'aud',
    minAmount: '2',
    symbol: '$',
    paypalFixedFee: {
      macro: 0.30,
      micro: 0.05
    },
    presets: {
      single: ['20', '10', '5', '3'],
      monthly: ['10', '5', '3', '2']
    }
  },
  'ars': {
    code: 'ars',
    minAmount: '30',
    symbol: '$',
    amexDisabled: true,
    disabled: "paypal",
    presets: {
      single: ['300', '150', '75', '45'],
      monthly: ['150', '75', '45', '30']
    }
  },
  'brl': {
    code: 'brl',
    minAmount: '5',
    symbol: 'R$',
    amexDisabled: true,
    paypalFixedFee: {
      macro: 0.60,
      micro: 0.10
    },
    presets: {
      single: ['40', '24', '12', '8'],
      monthly: ['20', '15', '10', '6']
    }
  },
  'cad': {
    code: 'cad',
    minAmount: '2',
    symbol: '$',
    paypalFixedFee: {
      macro: 0.30,
      micro: 0.05
    },
    presets: {
      single: ['20', '10', '5', '3'],
      monthly: ['10', '5', '3', '2']
    }
  },
  'chf': {
    code: 'chf',
    minAmount: '2',
    symbol: 'CHF',
    paypalFixedFee: {
      macro: 0.55,
      micro: 0.09
    },
    presets: {
      single: ['20', '10', '5', '3'],
      monthly: ['10', '5', '3', '2']
    }
  },
  'clp': {
    code: 'clp',
    minAmount: '1300',
    symbol: '$',
    disabled: "paypal",
    amexDisabled: true,
    zeroDecimal: "stripe",
    presets: {
      single: ['13000', '6500', '3250', '2000'],
      monthly: ['6500', '3250', '2000', '1300']
    }
  },
  'cny': {
    code: 'cny',
    minAmount: '12',
    symbol: '¥',
    disabled: "paypal",
    presets: {
      single: ['120','60','30','15'],
      monthly: ['60','30','20','12']
    }
  },
  'czk': {
    code: 'czk',
    minAmount: '45',
    amexDisabled: true,
    symbol: 'Kč',
    paypalFixedFee: {
      macro: 10.00,
      micro: 1.67
    },
    presets: {
      single: ['400', '200', '100', '55'],
      monthly: ['300', '150', '80', '45']
    }
  },
  'dkk': {
    code: 'dkk',
    minAmount: '12',
    symbol: 'kr',
    paypalFixedFee: {
      macro: 2.60,
      micro: 0.43
    },
    presets: {
      single: ['160', '80', '40', '20'],
      monthly: ['100', '60', '30', '15']
    }
  },
  'dzd': {
    code: 'dzd',
    minAmount: '220',
    symbol: 'د.ج.',
    disabled: "paypal",
    presets: {
      single: ['1653', '1102', '551', '330'],
      monthly: ['1102', '551', '330', '220']
    }
  },
  'egp': {
    code: 'egp',
    minAmount: '34',
    symbol: 'ج.م.',
    disabled: "paypal",
    presets: {
      single: ['257', '171', '85', '51'],
      monthly: ['171', '85', '51', '34']
    }
  },
  'eur': {
    code: 'eur',
    minAmount: '2',
    symbol: '€',
    paypalFixedFee: {
      macro: 0.35,
      micro: 0.05
    },
    presets: {
      single: ['20', '10', '5', '3'],
      monthly: ['10', '5', '3', '2']
    }
  },
  'gbp': {
    code: 'gbp',
    minAmount: '1',
    symbol: '£',
    paypalFixedFee: {
      macro: 0.20,
      micro: 0.05
    },
    presets: {
      single: ['20', '10', '5', '3'],
      monthly: ['10', '5', '3', '2']
    }
  },
  'hkd': {
    code: 'hkd',
    minAmount: '15',
    symbol: '$',
    paypalFixedFee: {
      macro: 2.35,
      micro: 0.39
    },
    presets: {
      single: ['100', '50', '25', '18'],
      monthly: ['70', '30', '20', '15']
    }
  },
  'huf': {
    code: 'huf',
    minAmount: '490',
    amexDisabled: true,
    symbol: 'Ft',
    paypalFixedFee: {
      macro: 90,
      micro: 15
    },
    zeroDecimal: "paypal",
    presets: {
      single: ['4000', '2000', '1000', '600'],
      monthly: ['1500', '1000', '800', '500']
    }
  },
  'idr': {
    code: 'idr',
    minAmount: '27000',
    symbol: 'Rp',
    disabled: "paypal",
    presets: {
      single: ['270000', '140000', '70000', '40000'],
      monthly: ['140000', '70000', '40000', '27000']
    }
  },
  'ils': {
    code: 'ils',
    minAmount: '8',
    symbol: '₪',
    paypalFixedFee: {
      macro: 1.20,
      micro: 0.20
    },
    presets: {
      single: ['60', '30', '15', '9'],
      monthly: ['50', '20', '10', '8']
    }
  },
  'inr': {
    code: 'inr',
    minAmount: '130',
    symbol: '₹',
    disabled: "paypal",
    amexDisabled: true,
    presets: {
      single: ['1000', '500', '250', '150'],
      monthly: ['650', '330', '200', '130']
    }
  },
  'jpy': {
    code: 'jpy',
    minAmount: '240',
    symbol: '¥',
    paypalFixedFee: {
      macro: 40,
      micro: 7
    },
    zeroDecimal: "stripe paypal",
    presets: {
      single: ['1600', '800', '400', '250'],
      monthly: ['1000', '600', '300', '240']
    }
  },
  'lbp': {
    code: 'lbp',
    minAmount: '3016',
    symbol: 'ل.ل.',
    disabled: "paypal",
    presets: {
      single: ['22623', '15082', '7541', '4525'],
      monthly: ['15082', '7541', '4525', '3016']
    }
  },
  'mad': {
    code: 'mad',
    minAmount: '20',
    symbol: 'MAD',
    disabled: "paypal",
    presets: {
      single: ['150', '100', '50', '30'],
      monthly: ['100', '50', '30', '20']
    }
  },
  'mxn': {
    code: 'mxn',
    minAmount: '30',
    symbol: '$',
    amexDisabled: true,
    paypalFixedFee: {
      macro: 4.00,
      micro: 0.55
    },
    presets: {
      single: ['240', '120', '60', '35'],
      monthly: ['200', '100', '40', '30']
    }
  },
  'nok': {
    code: 'nok',
    minAmount: '15',
    symbol: 'kr',
    paypalFixedFee: {
      macro: 2.80,
      micro: 0.47
    },
    presets: {
      single: ['160', '80', '40', '20'],
      monthly: ['100', '60', '30', '15']
    }
  },
  'nzd': {
    code: 'nzd',
    minAmount: '3',
    symbol: '$',
    paypalFixedFee: {
      macro: 0.45,
      micro: 0.08
    },
    presets: {
      single: ['40', '20', '10', '4'],
      monthly: ['20', '10', '8', '3']
    }
  },
  'php': {
    code: 'php',
    minAmount: '90',
    symbol: '₱',
    paypalFixedFee: {
      macro: 15.00,
      micro: 2.50
    },
    presets: {
      single: ['600', '300', '150', '100'],
      monthly: ['300', '200', '120', '90']
    }
  },
  'pln': {
    code: 'pln',
    minAmount: '7',
    symbol: 'zł',
    paypalFixedFee: {
      macro: 1.35,
      micro: 0.23
    },
    presets: {
      single: ['80', '40', '20', '10'],
      monthly: ['40', '20', '10', '7']
    }
  },
  'qad': {
    code: 'qad',
    minAmount: '8',
    symbol: 'QAD',
    disabled: "paypal",
    presets: {
      single: ['55', '36', '18', '11'],
      monthly: ['36', '18', '11', '8']
    }
  },
  'rub': {
    code: 'rub',
    minAmount: '100',
    symbol: '₽',
    paypalFixedFee: {
      macro: 10,
      micro: 2
    },
    presets: {
      single: ['1000', '500', '250', '140'],
      monthly: ['250', '180', '120', '100']
    }
  },
  'sar': {
    code: 'sar',
    minAmount: '8',
    symbol: 'ر.س.',
    disabled: "paypal",
    presets: {
      single: ['56', '37', '18', '11'],
      monthly: ['37', '18', '11', '8']
    }
  },
  'sek': {
    code: 'sek',
    minAmount: '15',
    symbol: 'kr',
    paypalFixedFee: {
      macro: 3.25,
      micro: 0.54
    },
    presets: {
      single: ['160', '80', '40', '20'],
      monthly: ['100', '40', '20', '15']
    }
  },
  'thb': {
    code: 'thb',
    minAmount: '70',
    symbol: '฿',
    paypalFixedFee: {
      macro: 11.00,
      micro: 1.80
    },
    presets: {
      single: ['500', '250', '125', '75'],
      monthly: ['300', '200', '100', '70']
    }
  },
  'twd': {
    code: 'twd',
    minAmount: '62',
    symbol: 'NT$',
    paypalFixedFee: {
      macro: 10.00,
      micro: 2.00
    },
    zeroDecimal: "paypal",
    presets: {
      single: ['480', '240', '150', '70'],
      monthly: ['250', '150', '100', '62']
    }
  },
  'uah': {
    code: 'uah',
    minAmount: '53',
    symbol: '₴',
    disabled: "paypal",
    presets: {
      single: ['530', '260', '130', '80'],
      monthly: ['260', '130', '80', '53']
    }
  },
  'yer': {
    code: 'yer',
    minAmount: '500',
    symbol: 'ر.ي.',
    disabled: "paypal",
    presets: {
      single: ['3752', '2500', '1250', '750'],
      monthly: ['2500', '1250', '750', '500']
    }
  },
  'zar': {
    code: 'zar',
    minAmount: '28',
    symbol: 'R',
    disabled: "paypal",
    presets: {
      single: ['275', '130', '70', '40'],
      monthly: ['130', '70', '40', '28']
    }
  }
};
<commit_msg>Fix QAR currency<commit_after>module.exports = {
  'usd': {
    code: 'usd',
    minAmount: '2',
    symbol: '$',
    paypalFixedFee: {
      macro: 0.30,
      micro: 0.05
    },
    presets: {
      single: ['20', '10', '5', '3'],
      monthly: ['10', '5', '3', '2']
    }
  },
  'aed': {
    code: 'aed',
    minAmount: '8',
    symbol: 'د.إ.',
    disabled: "paypal",
    presets: {
      single: ['55', '37', '18', '11'],
      monthly: ['37', '18', '11', '8']
    }
  },
  'aud': {
    code: 'aud',
    minAmount: '2',
    symbol: '$',
    paypalFixedFee: {
      macro: 0.30,
      micro: 0.05
    },
    presets: {
      single: ['20', '10', '5', '3'],
      monthly: ['10', '5', '3', '2']
    }
  },
  'ars': {
    code: 'ars',
    minAmount: '30',
    symbol: '$',
    amexDisabled: true,
    disabled: "paypal",
    presets: {
      single: ['300', '150', '75', '45'],
      monthly: ['150', '75', '45', '30']
    }
  },
  'brl': {
    code: 'brl',
    minAmount: '5',
    symbol: 'R$',
    amexDisabled: true,
    paypalFixedFee: {
      macro: 0.60,
      micro: 0.10
    },
    presets: {
      single: ['40', '24', '12', '8'],
      monthly: ['20', '15', '10', '6']
    }
  },
  'cad': {
    code: 'cad',
    minAmount: '2',
    symbol: '$',
    paypalFixedFee: {
      macro: 0.30,
      micro: 0.05
    },
    presets: {
      single: ['20', '10', '5', '3'],
      monthly: ['10', '5', '3', '2']
    }
  },
  'chf': {
    code: 'chf',
    minAmount: '2',
    symbol: 'CHF',
    paypalFixedFee: {
      macro: 0.55,
      micro: 0.09
    },
    presets: {
      single: ['20', '10', '5', '3'],
      monthly: ['10', '5', '3', '2']
    }
  },
  'clp': {
    code: 'clp',
    minAmount: '1300',
    symbol: '$',
    disabled: "paypal",
    amexDisabled: true,
    zeroDecimal: "stripe",
    presets: {
      single: ['13000', '6500', '3250', '2000'],
      monthly: ['6500', '3250', '2000', '1300']
    }
  },
  'cny': {
    code: 'cny',
    minAmount: '12',
    symbol: '¥',
    disabled: "paypal",
    presets: {
      single: ['120','60','30','15'],
      monthly: ['60','30','20','12']
    }
  },
  'czk': {
    code: 'czk',
    minAmount: '45',
    amexDisabled: true,
    symbol: 'Kč',
    paypalFixedFee: {
      macro: 10.00,
      micro: 1.67
    },
    presets: {
      single: ['400', '200', '100', '55'],
      monthly: ['300', '150', '80', '45']
    }
  },
  'dkk': {
    code: 'dkk',
    minAmount: '12',
    symbol: 'kr',
    paypalFixedFee: {
      macro: 2.60,
      micro: 0.43
    },
    presets: {
      single: ['160', '80', '40', '20'],
      monthly: ['100', '60', '30', '15']
    }
  },
  'dzd': {
    code: 'dzd',
    minAmount: '220',
    symbol: 'د.ج.',
    disabled: "paypal",
    presets: {
      single: ['1653', '1102', '551', '330'],
      monthly: ['1102', '551', '330', '220']
    }
  },
  'egp': {
    code: 'egp',
    minAmount: '34',
    symbol: 'ج.م.',
    disabled: "paypal",
    presets: {
      single: ['257', '171', '85', '51'],
      monthly: ['171', '85', '51', '34']
    }
  },
  'eur': {
    code: 'eur',
    minAmount: '2',
    symbol: '€',
    paypalFixedFee: {
      macro: 0.35,
      micro: 0.05
    },
    presets: {
      single: ['20', '10', '5', '3'],
      monthly: ['10', '5', '3', '2']
    }
  },
  'gbp': {
    code: 'gbp',
    minAmount: '1',
    symbol: '£',
    paypalFixedFee: {
      macro: 0.20,
      micro: 0.05
    },
    presets: {
      single: ['20', '10', '5', '3'],
      monthly: ['10', '5', '3', '2']
    }
  },
  'hkd': {
    code: 'hkd',
    minAmount: '15',
    symbol: '$',
    paypalFixedFee: {
      macro: 2.35,
      micro: 0.39
    },
    presets: {
      single: ['100', '50', '25', '18'],
      monthly: ['70', '30', '20', '15']
    }
  },
  'huf': {
    code: 'huf',
    minAmount: '490',
    amexDisabled: true,
    symbol: 'Ft',
    paypalFixedFee: {
      macro: 90,
      micro: 15
    },
    zeroDecimal: "paypal",
    presets: {
      single: ['4000', '2000', '1000', '600'],
      monthly: ['1500', '1000', '800', '500']
    }
  },
  'idr': {
    code: 'idr',
    minAmount: '27000',
    symbol: 'Rp',
    disabled: "paypal",
    presets: {
      single: ['270000', '140000', '70000', '40000'],
      monthly: ['140000', '70000', '40000', '27000']
    }
  },
  'ils': {
    code: 'ils',
    minAmount: '8',
    symbol: '₪',
    paypalFixedFee: {
      macro: 1.20,
      micro: 0.20
    },
    presets: {
      single: ['60', '30', '15', '9'],
      monthly: ['50', '20', '10', '8']
    }
  },
  'inr': {
    code: 'inr',
    minAmount: '130',
    symbol: '₹',
    disabled: "paypal",
    amexDisabled: true,
    presets: {
      single: ['1000', '500', '250', '150'],
      monthly: ['650', '330', '200', '130']
    }
  },
  'jpy': {
    code: 'jpy',
    minAmount: '240',
    symbol: '¥',
    paypalFixedFee: {
      macro: 40,
      micro: 7
    },
    zeroDecimal: "stripe paypal",
    presets: {
      single: ['1600', '800', '400', '250'],
      monthly: ['1000', '600', '300', '240']
    }
  },
  'lbp': {
    code: 'lbp',
    minAmount: '3016',
    symbol: 'ل.ل.',
    disabled: "paypal",
    presets: {
      single: ['22623', '15082', '7541', '4525'],
      monthly: ['15082', '7541', '4525', '3016']
    }
  },
  'mad': {
    code: 'mad',
    minAmount: '20',
    symbol: 'MAD',
    disabled: "paypal",
    presets: {
      single: ['150', '100', '50', '30'],
      monthly: ['100', '50', '30', '20']
    }
  },
  'mxn': {
    code: 'mxn',
    minAmount: '30',
    symbol: '$',
    amexDisabled: true,
    paypalFixedFee: {
      macro: 4.00,
      micro: 0.55
    },
    presets: {
      single: ['240', '120', '60', '35'],
      monthly: ['200', '100', '40', '30']
    }
  },
  'nok': {
    code: 'nok',
    minAmount: '15',
    symbol: 'kr',
    paypalFixedFee: {
      macro: 2.80,
      micro: 0.47
    },
    presets: {
      single: ['160', '80', '40', '20'],
      monthly: ['100', '60', '30', '15']
    }
  },
  'nzd': {
    code: 'nzd',
    minAmount: '3',
    symbol: '$',
    paypalFixedFee: {
      macro: 0.45,
      micro: 0.08
    },
    presets: {
      single: ['40', '20', '10', '4'],
      monthly: ['20', '10', '8', '3']
    }
  },
  'php': {
    code: 'php',
    minAmount: '90',
    symbol: '₱',
    paypalFixedFee: {
      macro: 15.00,
      micro: 2.50
    },
    presets: {
      single: ['600', '300', '150', '100'],
      monthly: ['300', '200', '120', '90']
    }
  },
  'pln': {
    code: 'pln',
    minAmount: '7',
    symbol: 'zł',
    paypalFixedFee: {
      macro: 1.35,
      micro: 0.23
    },
    presets: {
      single: ['80', '40', '20', '10'],
      monthly: ['40', '20', '10', '7']
    }
  },
  'qar': {
    code: 'qar',
    minAmount: '8',
    symbol: 'ر.ق.',
    disabled: "paypal",
    presets: {
      single: ['55', '36', '18', '11'],
      monthly: ['36', '18', '11', '8']
    }
  },
  'rub': {
    code: 'rub',
    minAmount: '100',
    symbol: '₽',
    paypalFixedFee: {
      macro: 10,
      micro: 2
    },
    presets: {
      single: ['1000', '500', '250', '140'],
      monthly: ['250', '180', '120', '100']
    }
  },
  'sar': {
    code: 'sar',
    minAmount: '8',
    symbol: 'ر.س.',
    disabled: "paypal",
    presets: {
      single: ['56', '37', '18', '11'],
      monthly: ['37', '18', '11', '8']
    }
  },
  'sek': {
    code: 'sek',
    minAmount: '15',
    symbol: 'kr',
    paypalFixedFee: {
      macro: 3.25,
      micro: 0.54
    },
    presets: {
      single: ['160', '80', '40', '20'],
      monthly: ['100', '40', '20', '15']
    }
  },
  'thb': {
    code: 'thb',
    minAmount: '70',
    symbol: '฿',
    paypalFixedFee: {
      macro: 11.00,
      micro: 1.80
    },
    presets: {
      single: ['500', '250', '125', '75'],
      monthly: ['300', '200', '100', '70']
    }
  },
  'twd': {
    code: 'twd',
    minAmount: '62',
    symbol: 'NT$',
    paypalFixedFee: {
      macro: 10.00,
      micro: 2.00
    },
    zeroDecimal: "paypal",
    presets: {
      single: ['480', '240', '150', '70'],
      monthly: ['250', '150', '100', '62']
    }
  },
  'uah': {
    code: 'uah',
    minAmount: '53',
    symbol: '₴',
    disabled: "paypal",
    presets: {
      single: ['530', '260', '130', '80'],
      monthly: ['260', '130', '80', '53']
    }
  },
  'yer': {
    code: 'yer',
    minAmount: '500',
    symbol: 'ر.ي.',
    disabled: "paypal",
    presets: {
      single: ['3752', '2500', '1250', '750'],
      monthly: ['2500', '1250', '750', '500']
    }
  },
  'zar': {
    code: 'zar',
    minAmount: '28',
    symbol: 'R',
    disabled: "paypal",
    presets: {
      single: ['275', '130', '70', '40'],
      monthly: ['130', '70', '40', '28']
    }
  }
};
<|endoftext|>


<commit_before>import {ModelError} from "./error"

// ;; Fragment is the type used to represent a node's collection of
// child nodes.
//
// Fragments are persistent data structures. That means you should
// _not_ mutate them or their content, but create new instances
// whenever needed. The API tries to make this easy.
export class Fragment {
  constructor(content, size) {
    this.content = content
    this.size = size || 0
    if (size == null) for (let i = 0; i < content.length; i++)
      this.size += content[i].nodeSize
  }

  // :: string
  // Concatenate all the text nodes found in this fragment and its
  // children.
  get textContent() {
    let text = ""
    this.content.forEach(n => text += n.textContent)
    return text
  }

  // :: () → string
  // Return a debugging string that describes this fragment.
  toString() { return "<" + this.toStringInner() + ">" }

  toStringInner() { return this.content.join(", ") }

  nodesBetween(from, to, f, nodeStart, parent) {
    for (let i = 0, pos = 0; pos < to; i++) {
      let child = this.content[i], end = pos + child.nodeSize
      if (end > from && f(child, nodeStart + pos, parent) !== false && child.content.size) {
        let start = pos + 1
        child.nodesBetween(Math.max(0, from - start),
                           Math.min(child.content.size, to - start),
                           f, nodeStart + start)
      }
      pos = end
    }
  }

  // :: (number, ?number) → Fragment
  // Cut out the sub-fragment between the two given positions.
  cut(from, to) {
    if (to == null) to = this.size
    if (from == 0 && to == this.size) return this
    let result = [], size = 0
    if (to > from) for (let i = 0, pos = 0; pos < to; i++) {
      let child = this.content[i], end = pos + child.nodeSize
      if (end > from) {
        if (pos < from || end > to) {
          if (child.isText)
            child = child.cut(Math.max(0, from - pos), Math.min(child.text.length, to - pos))
          else
            child = child.cut(Math.max(0, from - pos - 1), Math.min(child.content.size, to - pos - 1))
        }
        result.push(child)
        size += child.nodeSize
      }
      pos = end
    }
    return new Fragment(result, size)
  }

  addToStart(node) {
    return new Fragment([node].concat(this.content), this.size + node.nodeSize)
  }

  addToEnd(node) {
    return new Fragment(this.content.concat(node), this.size + node.nodeSize)
  }

  replace(index, node) {
    let copy = this.content.slice()
    let size = this.size + node.nodeSize - copy[index].nodeSize
    copy[index] = node
    return new Fragment(copy, size)
  }

  // :: () → Object
  // Create a JSON-serializeable representation of this fragment.
  toJSON() {
    return this.content.length ? this.content.map(n => n.toJSON()) : null
  }

  // :: (Schema, Object) → Fragment
  // Deserialize a fragment from its JSON representation.
  static fromJSON(schema, value) {
    return value ? new Fragment(value.map(schema.nodeFromJSON)) : Fragment.empty
  }

  // :: ([Node]) → Fragment
  // Build a fragment from an array of nodes. Ensures that adjacent
  // text nodes with the same style are joined together.
  static fromArray(array) {
    if (!array.length) return Fragment.empty
    let joined, size = 0
    for (let i = 0; i < array.length; i++) {
      let node = array[i]
      size += node.nodeSize
      if (i && node.isText && array[i - 1].sameMarkup(node)) {
        if (!joined) joined = array.slice(0, i)
        joined[joined.length - 1] = node.copy(joined[joined.length - 1].text + node.text)
      } else if (joined) {
        joined.push(node)
      }
    }
    return new Fragment(joined || array, size)
  }

  eq(other) {
    if (this.content.length != other.content.length) return false
    for (let i = 0; i < this.content.length; i++)
      if (!this.content[i].eq(other.content[i])) return false
    return true
  }

  // :: (?union<Fragment, Node, [Node]>) → Fragment
  // Create a fragment from something that can be interpreted as a set
  // of nodes. For `null`, it returns the empty fragment. For a
  // fragment, the fragment itself. For a node or array of nodes, a
  // fragment containing those nodes.
  static from(nodes) {
    if (!nodes) return Fragment.empty
    if (nodes instanceof Fragment) return nodes
    if (Array.isArray(nodes)) return this.fromArray(nodes)
    return new Fragment([nodes], nodes.nodeSize)
  }

  // :: ?Node
  // The first child of the fragment, or `null` if it is empty.
  get firstChild() { return this.content.length ? this.content[0] : null }

  // :: ?Node
  // The last child of the fragment, or `null` if it is empty.
  get lastChild() { return this.content.length ? this.content[this.content.length - 1] : null }

  get childCount() { return this.content.length }

  child(index) {
    let found = this.content[index]
    if (!found) throw new ModelError("Index " + index + " out of range for " + this)
    return found
  }

  maybeChild(index) {
    return this.content[index]
  }

  forEach(f) {
    for (let i = 0, p = 0; i < this.content.length; i++) {
      let child = this.content[i]
      f(child, i, p)
      p += child.nodeSize
    }
  }
}

// :: Fragment
// An empty fragment. Intended to be reused whenever a node doesn't
// contain anything (rather than allocating a new empty fragment for
// each leaf node).
Fragment.empty = new Fragment([], 0)
<commit_msg>Port edit/domchange.js<commit_after>import {ModelError} from "./error"

// ;; Fragment is the type used to represent a node's collection of
// child nodes.
//
// Fragments are persistent data structures. That means you should
// _not_ mutate them or their content, but create new instances
// whenever needed. The API tries to make this easy.
export class Fragment {
  constructor(content, size) {
    this.content = content
    this.size = size || 0
    if (size == null) for (let i = 0; i < content.length; i++)
      this.size += content[i].nodeSize
  }

  // :: string
  // Concatenate all the text nodes found in this fragment and its
  // children.
  get textContent() {
    let text = ""
    this.content.forEach(n => text += n.textContent)
    return text
  }

  // :: () → string
  // Return a debugging string that describes this fragment.
  toString() { return "<" + this.toStringInner() + ">" }

  toStringInner() { return this.content.join(", ") }

  nodesBetween(from, to, f, nodeStart, parent) {
    for (let i = 0, pos = 0; pos < to; i++) {
      let child = this.content[i], end = pos + child.nodeSize
      if (end > from && f(child, nodeStart + pos, parent) !== false && child.content.size) {
        let start = pos + 1
        child.nodesBetween(Math.max(0, from - start),
                           Math.min(child.content.size, to - start),
                           f, nodeStart + start)
      }
      pos = end
    }
  }

  // :: (number, ?number) → Fragment
  // Cut out the sub-fragment between the two given positions.
  cut(from, to) {
    if (to == null) to = this.size
    if (from == 0 && to == this.size) return this
    let result = [], size = 0
    if (to > from) for (let i = 0, pos = 0; pos < to; i++) {
      let child = this.content[i], end = pos + child.nodeSize
      if (end > from) {
        if (pos < from || end > to) {
          if (child.isText)
            child = child.cut(Math.max(0, from - pos), Math.min(child.text.length, to - pos))
          else
            child = child.cut(Math.max(0, from - pos - 1), Math.min(child.content.size, to - pos - 1))
        }
        result.push(child)
        size += child.nodeSize
      }
      pos = end
    }
    return new Fragment(result, size)
  }

  addToStart(node) {
    return new Fragment([node].concat(this.content), this.size + node.nodeSize)
  }

  addToEnd(node) {
    return new Fragment(this.content.concat(node), this.size + node.nodeSize)
  }

  append(other) {
    if (!other.size) return this
    if (!this.size) return other
    let last = this.lastChild, first = other.firstChild, content = this.content.slice(), i = 0
    if (last.isText && last.sameMarkup(first)) {
      content[content.length - 1] = last.copy(last.text + first.text)
      i = 1
    }
    for (; i < other.content.length; i++) content.push(other.content[i])
    return new Fragment(content, this.size + other.size)
  }

  replace(index, node) { // FIXME change name to avoid confusion with Node.replace
    let copy = this.content.slice()
    let size = this.size + node.nodeSize - copy[index].nodeSize
    copy[index] = node
    return new Fragment(copy, size)
  }

  // :: () → Object
  // Create a JSON-serializeable representation of this fragment.
  toJSON() {
    return this.content.length ? this.content.map(n => n.toJSON()) : null
  }

  // :: (Schema, Object) → Fragment
  // Deserialize a fragment from its JSON representation.
  static fromJSON(schema, value) {
    return value ? new Fragment(value.map(schema.nodeFromJSON)) : Fragment.empty
  }

  // :: ([Node]) → Fragment
  // Build a fragment from an array of nodes. Ensures that adjacent
  // text nodes with the same style are joined together.
  static fromArray(array) {
    if (!array.length) return Fragment.empty
    let joined, size = 0
    for (let i = 0; i < array.length; i++) {
      let node = array[i]
      size += node.nodeSize
      if (i && node.isText && array[i - 1].sameMarkup(node)) {
        if (!joined) joined = array.slice(0, i)
        joined[joined.length - 1] = node.copy(joined[joined.length - 1].text + node.text)
      } else if (joined) {
        joined.push(node)
      }
    }
    return new Fragment(joined || array, size)
  }

  eq(other) {
    if (this.content.length != other.content.length) return false
    for (let i = 0; i < this.content.length; i++)
      if (!this.content[i].eq(other.content[i])) return false
    return true
  }

  // :: (?union<Fragment, Node, [Node]>) → Fragment
  // Create a fragment from something that can be interpreted as a set
  // of nodes. For `null`, it returns the empty fragment. For a
  // fragment, the fragment itself. For a node or array of nodes, a
  // fragment containing those nodes.
  static from(nodes) {
    if (!nodes) return Fragment.empty
    if (nodes instanceof Fragment) return nodes
    if (Array.isArray(nodes)) return this.fromArray(nodes)
    return new Fragment([nodes], nodes.nodeSize)
  }

  // :: ?Node
  // The first child of the fragment, or `null` if it is empty.
  get firstChild() { return this.content.length ? this.content[0] : null }

  // :: ?Node
  // The last child of the fragment, or `null` if it is empty.
  get lastChild() { return this.content.length ? this.content[this.content.length - 1] : null }

  get childCount() { return this.content.length }

  child(index) {
    let found = this.content[index]
    if (!found) throw new ModelError("Index " + index + " out of range for " + this)
    return found
  }

  maybeChild(index) {
    return this.content[index]
  }

  forEach(f) {
    for (let i = 0, p = 0; i < this.content.length; i++) {
      let child = this.content[i]
      f(child, i, p)
      p += child.nodeSize
    }
  }
}

// :: Fragment
// An empty fragment. Intended to be reused whenever a node doesn't
// contain anything (rather than allocating a new empty fragment for
// each leaf node).
Fragment.empty = new Fragment([], 0)
<|endoftext|>