<commit_before>/**
 * @preserve EventEmitter v3.0.0
 *
 * Copyright 2011, Oliver Caldwell (olivercaldwell.co.uk)
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * https://github.com/Wolfy87/EventEmitter
 */

(function(exports) {
	'use strict';

	/**
	 * EventEmitter class
	 * Creates an object with event registering and firing methods
	 */
	function EventEmitter() {
		// Initialise required storage variables
		this._listeners = {};
		this._maxListeners = 10;
	}

	/**
	 * Event class
	 * Contains Event methods and property storage
	 *
	 * @param {String} type Event type name
	 * @param {Function} listener Function to be called when the event is fired
	 * @param {Object} scope Object that this should be set to when the listener is called
	 * @param {Boolean} once If true then the listener will be removed after the first call
	 * @param {Object} instance The parent EventEmitter instance
	 */
	function Event(type, listener, scope, once, instance) {
		// Store arguments
		this.type = type;
		this.listener = listener;
		this.scope = scope;
		this.once = once;
		this.instance = instance;
	}

	/**
	 * Executes the listener
	 *
	 * @param {Array} args List of arguments to pass to the listener
	 * @return {Boolean} If false then it was a once event
	 */
	Event.prototype.fire = function(args) {
		this.listener.apply(this.scope || this, args || []);

		// Remove the listener if this is a once only listener
		if(this.once) {
			this.instance.removeListener(this.type, this.listener);
			return false;
		}
	};

	/**
	 * Passes every listener for a specified event to a function one at a time
	 *
	 * @param {String} type Event type name
	 * @param {Function} callback Function to pass each listener to
	 * @return {Object} The current EventEmitter instance to allow chaining
	 */
	EventEmitter.prototype.eachListener = function(type, callback) {
		// Initialise variables
		var i = null,
			possibleListeners = null,
			result = null;

		// Only loop if the type exists
		if(this._listeners.hasOwnProperty(type)) {
			possibleListeners = this._listeners[type];

			for(i = 0; i < possibleListeners.length; i += 1) {
				result = callback.call(this, possibleListeners[i], i);

				if(result === false) {
					i -= 1;
				}
				else if(result === true) {
					break;
				}
			}
		}

		// Return the instance to allow chaining
		return this;
	};

	/**
	 * Adds an event listener for the specified event
	 *
	 * @param {String} type Event type name
	 * @param {Function} listener Function to be called when the event is fired
	 * @param {Object} scope Object that this should be set to when the listener is called
	 * @param {Boolean} once If true then the listener will be removed after the first call
	 * @return {Object} The current EventEmitter instance to allow chaining
	 */
	EventEmitter.prototype.addListener = function(type, listener, scope, once) {
		// Create the listener array if it does not exist yet
		if(!this._listeners.hasOwnProperty(type)) {
			this._listeners[type] = [];
		}

		// Push the new event to the array
		this._listeners[type].push(new Event(type, listener, scope, once, this));

		// Emit the new listener event
		this.emit('newListener', type, listener, scope, once);

		// Check if we have exceeded the maxListener count
		// Ignore this check if the count is 0
		// Also don't check if we have already fired a warning
		if(this._maxListeners && !this._listeners[type].warned && this._listeners[type].length > this._maxListeners) {
			// The max listener count has been exceeded!
			// My god, we have a mother flipping memory leak on our hands!
			// Beter let the big developer in the sky know
			console.warn('Possible EventEmitter memory leak detected. ' + this._listeners[type].length + ' listeners added. Use emitter.setMaxListeners() to increase limit.');

			// Set the flag so it doesn't fire again
			this._listeners[type].warned = true;
		}

		// Return the instance to allow chaining
		return this;
	};

	/**
	 * Alias of the addListener method
	 *
	 * @param {String} type Event type name
	 * @param {Function} listener Function to be called when the event is fired
	 * @param {Object} scope Object that this should be set to when the listener is called
	 * @param {Boolean} once If true then the listener will be removed after the first call
	 */
	EventEmitter.prototype.on = EventEmitter.prototype.addListener;

	/**
	 * Alias of the addListener method but will remove the event after the first use
	 *
	 * @param {String} type Event type name
	 * @param {Function} listener Function to be called when the event is fired
	 * @param {Object} scope Object that this should be set to when the listener is called
	 * @return {Object} The current EventEmitter instance to allow chaining
	 */
	EventEmitter.prototype.once = function(type, listener, scope) {
		return this.addListener(type, listener, scope, true);
	};

	/**
	 * Removes the a listener for the specified event
	 *
	 * @param {String} type Event type name the listener must have for the event to be removed
	 * @param {Function} listener Listener the event must have to be removed
	 * @return {Object} The current EventEmitter instance to allow chaining
	 */
	EventEmitter.prototype.removeListener = function(type, listener) {
		this.eachListener(type, function(currentListener, index) {
			// If this is the listener remove it from the array
			if(currentListener.listener === listener) {
				this._listeners[type].splice(index, 1);
			}
		});

		// Remove the property if there are no more listeners
		if(this._listeners[type] && this._listeners[type].length === 0) {
			delete this._listeners[type];
		}

		// Return the instance to allow chaining
		return this;
	};

	/**
	 * Removes all listeners for a specified event
	 *
	 * @param {String} type Event type name to remove all listeners from
	 * @return {Object} The current EventEmitter instance to allow chaining
	 */
	EventEmitter.prototype.removeAllListeners = function(type) {
		// Check for a type, if there is none remove all listeners
		// If there is a type however, just remove the listeners for that type
		if(type && this._listeners.hasOwnProperty(type)) {
			delete this._listeners[type];
		}
		else if(!type) {
			this._listeners = {};
		}

		// Return the instance to allow chaining
		return this;
	};

	/**
	 * Retrieves the array of listeners for a specified event
	 *
	 * @param {String} type Event type name to return all listeners from
	 * @return {Array | Boolean} Will return either an array of listeners or false if there are none
	 */
	EventEmitter.prototype.listeners = function(type) {
		// Return the array of listeners of false if it does not exist
		if(this._listeners.hasOwnProperty(type)) {
			return this._listeners[type];
		}

		return false;
	};

	/**
	 * Emits an event executing all appropriate listeners
	 *
	 * @param {String} type Event type name to run all listeners from
	 * @param {Array} args List of arguments to pass to the listener
	 * @return {Object} The current EventEmitter instance to allow chaining
	 */
	EventEmitter.prototype.emit = function(type, args) {
		this.eachListener(type, function(currentListener) {
			return currentListener.fire(args);
		});

		// Return the instance to allow chaining
		return this;
	};

	/**
	 * Sets the max listener count for the EventEmitter
	 * When the count of listeners for an event exceeds this limit a warning will be printed
	 * Set to 0 for no limit
	 *
	 * @param {Number} maxListeners The new max listener limit
	 * @return {Object} The current EventEmitter instance to allow chaining
	 */
	EventEmitter.prototype.setMaxListeners = function(maxListeners) {
		this._maxListeners = maxListeners;

		// Return the instance to allow chaining
		return this;
	};

	// Export the class
	exports.EventEmitter = EventEmitter;
}(this));<commit_msg>Did a find and replace for ._listeners -> ._events. Now the actual object matches the layout of the node EventEmitter. Apart from ._maxListeners. But that can't be helped. #10<commit_after>/**
 * @preserve EventEmitter v3.0.0
 *
 * Copyright 2011, Oliver Caldwell (olivercaldwell.co.uk)
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * https://github.com/Wolfy87/EventEmitter
 */

(function(exports) {
	'use strict';

	/**
	 * EventEmitter class
	 * Creates an object with event registering and firing methods
	 */
	function EventEmitter() {
		// Initialise required storage variables
		this._events = {};
		this._maxListeners = 10;
	}

	/**
	 * Event class
	 * Contains Event methods and property storage
	 *
	 * @param {String} type Event type name
	 * @param {Function} listener Function to be called when the event is fired
	 * @param {Object} scope Object that this should be set to when the listener is called
	 * @param {Boolean} once If true then the listener will be removed after the first call
	 * @param {Object} instance The parent EventEmitter instance
	 */
	function Event(type, listener, scope, once, instance) {
		// Store arguments
		this.type = type;
		this.listener = listener;
		this.scope = scope;
		this.once = once;
		this.instance = instance;
	}

	/**
	 * Executes the listener
	 *
	 * @param {Array} args List of arguments to pass to the listener
	 * @return {Boolean} If false then it was a once event
	 */
	Event.prototype.fire = function(args) {
		this.listener.apply(this.scope || this, args || []);

		// Remove the listener if this is a once only listener
		if(this.once) {
			this.instance.removeListener(this.type, this.listener);
			return false;
		}
	};

	/**
	 * Passes every listener for a specified event to a function one at a time
	 *
	 * @param {String} type Event type name
	 * @param {Function} callback Function to pass each listener to
	 * @return {Object} The current EventEmitter instance to allow chaining
	 */
	EventEmitter.prototype.eachListener = function(type, callback) {
		// Initialise variables
		var i = null,
			possibleListeners = null,
			result = null;

		// Only loop if the type exists
		if(this._events.hasOwnProperty(type)) {
			possibleListeners = this._events[type];

			for(i = 0; i < possibleListeners.length; i += 1) {
				result = callback.call(this, possibleListeners[i], i);

				if(result === false) {
					i -= 1;
				}
				else if(result === true) {
					break;
				}
			}
		}

		// Return the instance to allow chaining
		return this;
	};

	/**
	 * Adds an event listener for the specified event
	 *
	 * @param {String} type Event type name
	 * @param {Function} listener Function to be called when the event is fired
	 * @param {Object} scope Object that this should be set to when the listener is called
	 * @param {Boolean} once If true then the listener will be removed after the first call
	 * @return {Object} The current EventEmitter instance to allow chaining
	 */
	EventEmitter.prototype.addListener = function(type, listener, scope, once) {
		// Create the listener array if it does not exist yet
		if(!this._events.hasOwnProperty(type)) {
			this._events[type] = [];
		}

		// Push the new event to the array
		this._events[type].push(new Event(type, listener, scope, once, this));

		// Emit the new listener event
		this.emit('newListener', type, listener, scope, once);

		// Check if we have exceeded the maxListener count
		// Ignore this check if the count is 0
		// Also don't check if we have already fired a warning
		if(this._maxListeners && !this._events[type].warned && this._events[type].length > this._maxListeners) {
			// The max listener count has been exceeded!
			// My god, we have a mother flipping memory leak on our hands!
			// Beter let the big developer in the sky know
			console.warn('Possible EventEmitter memory leak detected. ' + this._events[type].length + ' listeners added. Use emitter.setMaxListeners() to increase limit.');

			// Set the flag so it doesn't fire again
			this._events[type].warned = true;
		}

		// Return the instance to allow chaining
		return this;
	};

	/**
	 * Alias of the addListener method
	 *
	 * @param {String} type Event type name
	 * @param {Function} listener Function to be called when the event is fired
	 * @param {Object} scope Object that this should be set to when the listener is called
	 * @param {Boolean} once If true then the listener will be removed after the first call
	 */
	EventEmitter.prototype.on = EventEmitter.prototype.addListener;

	/**
	 * Alias of the addListener method but will remove the event after the first use
	 *
	 * @param {String} type Event type name
	 * @param {Function} listener Function to be called when the event is fired
	 * @param {Object} scope Object that this should be set to when the listener is called
	 * @return {Object} The current EventEmitter instance to allow chaining
	 */
	EventEmitter.prototype.once = function(type, listener, scope) {
		return this.addListener(type, listener, scope, true);
	};

	/**
	 * Removes the a listener for the specified event
	 *
	 * @param {String} type Event type name the listener must have for the event to be removed
	 * @param {Function} listener Listener the event must have to be removed
	 * @return {Object} The current EventEmitter instance to allow chaining
	 */
	EventEmitter.prototype.removeListener = function(type, listener) {
		this.eachListener(type, function(currentListener, index) {
			// If this is the listener remove it from the array
			if(currentListener.listener === listener) {
				this._events[type].splice(index, 1);
			}
		});

		// Remove the property if there are no more listeners
		if(this._events[type] && this._events[type].length === 0) {
			delete this._events[type];
		}

		// Return the instance to allow chaining
		return this;
	};

	/**
	 * Removes all listeners for a specified event
	 *
	 * @param {String} type Event type name to remove all listeners from
	 * @return {Object} The current EventEmitter instance to allow chaining
	 */
	EventEmitter.prototype.removeAllListeners = function(type) {
		// Check for a type, if there is none remove all listeners
		// If there is a type however, just remove the listeners for that type
		if(type && this._events.hasOwnProperty(type)) {
			delete this._events[type];
		}
		else if(!type) {
			this._events = {};
		}

		// Return the instance to allow chaining
		return this;
	};

	/**
	 * Retrieves the array of listeners for a specified event
	 *
	 * @param {String} type Event type name to return all listeners from
	 * @return {Array | Boolean} Will return either an array of listeners or false if there are none
	 */
	EventEmitter.prototype.listeners = function(type) {
		// Return the array of listeners of false if it does not exist
		if(this._events.hasOwnProperty(type)) {
			return this._events[type];
		}

		return false;
	};

	/**
	 * Emits an event executing all appropriate listeners
	 *
	 * @param {String} type Event type name to run all listeners from
	 * @param {Array} args List of arguments to pass to the listener
	 * @return {Object} The current EventEmitter instance to allow chaining
	 */
	EventEmitter.prototype.emit = function(type, args) {
		this.eachListener(type, function(currentListener) {
			return currentListener.fire(args);
		});

		// Return the instance to allow chaining
		return this;
	};

	/**
	 * Sets the max listener count for the EventEmitter
	 * When the count of listeners for an event exceeds this limit a warning will be printed
	 * Set to 0 for no limit
	 *
	 * @param {Number} maxListeners The new max listener limit
	 * @return {Object} The current EventEmitter instance to allow chaining
	 */
	EventEmitter.prototype.setMaxListeners = function(maxListeners) {
		this._maxListeners = maxListeners;

		// Return the instance to allow chaining
		return this;
	};

	// Export the class
	exports.EventEmitter = EventEmitter;
}(this));<|endoftext|>


<commit_before>// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE

// Define search commands. Depends on dialog.js or another
// implementation of the openDialog method.

// Replace works a little oddly -- it will do the replace on the next
// Ctrl-G (or whatever is bound to findNext) press. You prevent a
// replace by making sure the match is no longer selected when hitting
// Ctrl-G.

"use strict";

function searchOverlay(query, caseInsensitive) {
  if (typeof query == "string")
    query = new RegExp(query.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"), caseInsensitive ? "gi" : "g");
  else if (!query.global)
    query = new RegExp(query.source, query.ignoreCase ? "gi" : "g");

  return {token: function(stream) {
    query.lastIndex = stream.pos;
    var match = query.exec(stream.string);
    if (match && match.index == stream.pos) {
      stream.pos += match[0].length || 1;
      return "searching";
    } else if (match) {
      stream.pos = match.index;
    } else {
      stream.skipToEnd();
    }
  }};
}

function SearchState() {
  this.posFrom = this.posTo = this.lastQuery = this.query = null;
  this.overlay = null;
}

function getSearchState(cm) {
  return cm.state.search || (cm.state.search = new SearchState());
}

function queryCaseInsensitive(query) {
  return typeof query == "string" && query == query.toLowerCase();
}

function getSearchCursor(cm, query, pos) {
  // Heuristic: if the query string is all lowercase, do a case insensitive search.
  return cm.getSearchCursor(query, pos, queryCaseInsensitive(query));
}

function persistentDialog(cm, text, deflt, onEnter, onKeyDown) {
  cm.openDialog(text, onEnter, {
    value: deflt,
    selectValueOnOpen: true,
    closeOnEnter: false,
    onClose: function() { clearSearch(cm); },
    onKeyDown: onKeyDown
  });
}

function dialog(cm, text, shortText, deflt, f) {
  if (cm.openDialog) cm.openDialog(text, f, {value: deflt, selectValueOnOpen: true});
  else f(prompt(shortText, deflt));
}

function confirmDialog(cm, text, shortText, fs) {
  if (cm.openConfirm) cm.openConfirm(text, fs);
  else if (confirm(shortText)) fs[0]();
}

function parseString(string) {
  return string.replace(/\\(.)/g, function(_, ch) {
    if (ch == "n") return "\n"
    if (ch == "r") return "\r"
    return ch
  })
}

function parseQuery(query) {
  var isRE = query.match(/^\/(.*)\/([a-z]*)$/);
  if (isRE) {
    try { query = new RegExp(isRE[1], isRE[2].indexOf("i") == -1 ? "" : "i"); }
    catch(e) {} // Not a regular expression after all, do a string search
  } else {
    query = parseString(query)
  }
  if (typeof query == "string" ? query == "" : query.test(""))
    query = /x^/;
  return query;
}

if(navigator.platform == "MacIntel") {
    var queryDialog =
      'Search: <input type="text" style="width: 10em" class="CodeMirror-search-field"/> Hit enter, then Next (⌘-G) and Prev (Shift-⌘-G). Use /re/ for regular expression.';
} else {
    var queryDialog =
      'Search: <input type="text" style="width: 10em" class="CodeMirror-search-field"/> Hit enter, then Next (Ctrl-G) and Prev (Shift-Ctrl-G). Use /re/ for regular expression.';
}

function startSearch(cm, state, query) {
  state.queryText = query;
  state.query = parseQuery(query);
  cm.removeOverlay(state.overlay, queryCaseInsensitive(state.query));
  state.overlay = searchOverlay(state.query, queryCaseInsensitive(state.query));
  cm.addOverlay(state.overlay);
  if (cm.showMatchesOnScrollbar) {
    if (state.annotate) { state.annotate.clear(); state.annotate = null; }
    state.annotate = cm.showMatchesOnScrollbar(state.query, queryCaseInsensitive(state.query));
  }
}

function doSearch(cm, rev, persistent, immediate) {
  var state = getSearchState(cm);
  if (state.query) return findNext(cm, rev);
  var q = cm.getSelection() || state.lastQuery;
  if (persistent && cm.openDialog) {
    var hiding = null
    var searchNext = function(query, event) {
      CodeMirror.e_stop(event);
      if (!query) return;
      if (query != state.queryText) {
        startSearch(cm, state, query);
        state.posFrom = state.posTo = cm.getCursor();
      }
      if (hiding) hiding.style.opacity = 1
      findNext(cm, event.shiftKey, function(_, to) {
        var dialog
        if (to.line < 3 && document.querySelector &&
            (dialog = cm.display.wrapper.querySelector(".CodeMirror-dialog")) &&
            dialog.getBoundingClientRect().bottom - 4 > cm.cursorCoords(to, "window").top)
          (hiding = dialog).style.opacity = .4
      })
    };
    persistentDialog(cm, queryDialog, q, searchNext, function(event, query) {
      var keyName = CodeMirror.keyName(event)
      var cmd = CodeMirror.keyMap[cm.getOption("keyMap")][keyName]
      if (!cmd) cmd = cm.getOption('extraKeys')[keyName]
      if (cmd == "findNext" || cmd == "findPrev" ||
        cmd == "findPersistentNext" || cmd == "findPersistentPrev") {
        CodeMirror.e_stop(event);
        startSearch(cm, getSearchState(cm), query);
        cm.execCommand(cmd);
      } else if (cmd == "find" || cmd == "findPersistent") {
        CodeMirror.e_stop(event);
        searchNext(query, event);
      }
    });
    if (immediate && q) {
      startSearch(cm, state, q);
      findNext(cm, rev);
    }
  } else {
    dialog(cm, queryDialog, "Search for:", q, function(query) {
      if (query && !state.query) cm.operation(function() {
        startSearch(cm, state, query);
        state.posFrom = state.posTo = cm.getCursor();
        findNext(cm, rev);
      });
    });
  }
}

function findNext(cm, rev, callback) {cm.operation(function() {
  var state = getSearchState(cm);
  var cursor = getSearchCursor(cm, state.query, rev ? state.posFrom : state.posTo);
  if (!cursor.find(rev)) {
    cursor = getSearchCursor(cm, state.query, rev ? CodeMirror.Pos(cm.lastLine()) : CodeMirror.Pos(cm.firstLine(), 0));
    if (!cursor.find(rev)) return;
  }
  cm.setSelection(cursor.from(), cursor.to());
  cm.scrollIntoView({from: cursor.from(), to: cursor.to()}, 20);
  state.posFrom = cursor.from(); state.posTo = cursor.to();
  if (callback) callback(cursor.from(), cursor.to())
});}

function clearSearch(cm) {cm.operation(function() {
  var state = getSearchState(cm);
  state.lastQuery = state.query;
  if (!state.query) return;
  state.query = state.queryText = null;
  cm.removeOverlay(state.overlay);
  if (state.annotate) { state.annotate.clear(); state.annotate = null; }
});}

var replaceQueryDialog =
  ' <input type="text" style="width: 10em" class="CodeMirror-search-field"/> Hit enter (use /re/ syntax for regular expression search)';
var replacementQueryDialog = 'With: <input type="text" style="width: 10em" class="CodeMirror-search-field"/>';
var doReplaceConfirm = "Replace? <button>Yes</button> <button>No</button> <button>All</button> <button>Stop</button>";

function replaceAll(cm, query, text) {
  cm.operation(function() {
    for (var cursor = getSearchCursor(cm, query); cursor.findNext();) {
      if (typeof query != "string") {
        var match = cm.getRange(cursor.from(), cursor.to()).match(query);
        cursor.replace(text.replace(/\$(\d)/g, function(_, i) {return match[i];}));
      } else cursor.replace(text);
    }
  });
}

function replace(cm, all) {
  if (cm.getOption("readOnly")) return;
  var query = cm.getSelection() || getSearchState(cm).lastQuery;
  var dialogText = all ? "Replace all:" : "Replace:"
  dialog(cm, dialogText + replaceQueryDialog, dialogText, query, function(query) {
    if (!query) return;
    query = parseQuery(query);
    dialog(cm, replacementQueryDialog, "Replace with:", "", function(text) {
      text = parseString(text)
      if (all) {
        replaceAll(cm, query, text)
      } else {
        clearSearch(cm);
        var cursor = getSearchCursor(cm, query, cm.getCursor("from"));
        var advance = function() {
          var start = cursor.from(), match;
          if (!(match = cursor.findNext())) {
            cursor = getSearchCursor(cm, query);
            if (!(match = cursor.findNext()) ||
                (start && cursor.from().line == start.line && cursor.from().ch == start.ch)) return;
          }
          cm.setSelection(cursor.from(), cursor.to());
          cm.scrollIntoView({from: cursor.from(), to: cursor.to()});
          confirmDialog(cm, doReplaceConfirm, "Replace?",
                        [function() {doReplace(match);}, advance,
                         function() {replaceAll(cm, query, text)}]);
        };
        var doReplace = function(match) {
          cursor.replace(typeof query == "string" ? text :
                         text.replace(/\$(\d)/g, function(_, i) {return match[i];}));
          advance();
        };
        advance();
      }
    });
  });
}

CodeMirror.commands.find = function(cm) {clearSearch(cm); doSearch(cm);};
CodeMirror.commands.findNext = doSearch;
CodeMirror.commands.findPrev = function(cm) {doSearch(cm, true);};

CodeMirror.commands.findPersistent = function(cm) {clearSearch(cm); doSearch(cm, false, true);};
CodeMirror.commands.findPersistentNext = function(cm) {doSearch(cm, false, true, true);};
CodeMirror.commands.findPersistentPrev = function(cm) {doSearch(cm, true, true, true);};

CodeMirror.commands.findPersistent = function(cm) {clearSearch(cm); doSearch(cm, false, true);};
CodeMirror.commands.findPersistentNext = function(cm) {doSearch(cm, false, true, true);};
CodeMirror.commands.findPersistentPrev = function(cm) {doSearch(cm, true, true, true);};

CodeMirror.commands.clearSearch = clearSearch;
CodeMirror.commands.replace = replace;
CodeMirror.commands.replaceAll = function(cm) {replace(cm, true);};

<commit_msg>fix https://github.com/sagemathinc/smc/issues/522 -- "change sagews search to be aware of hidden control codes"<commit_after>// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE

// Define search commands. Depends on dialog.js or another
// implementation of the openDialog method.

// Replace works a little oddly -- it will do the replace on the next
// Ctrl-G (or whatever is bound to findNext) press. You prevent a
// replace by making sure the match is no longer selected when hitting
// Ctrl-G.

"use strict";

function searchOverlay(query, caseInsensitive) {
  if (typeof query == "string")
    query = new RegExp(query.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"), caseInsensitive ? "gi" : "g");
  else if (!query.global)
    query = new RegExp(query.source, query.ignoreCase ? "gi" : "g");

  return {token: function(stream) {
    query.lastIndex = stream.pos;
    var match = query.exec(stream.string);
    if (match && match.index == stream.pos) {
      stream.pos += match[0].length || 1;
      return "searching";
    } else if (match) {
      stream.pos = match.index;
    } else {
      stream.skipToEnd();
    }
  }};
}

function SearchState() {
  this.posFrom = this.posTo = this.lastQuery = this.query = null;
  this.overlay = null;
}

function getSearchState(cm) {
  return cm.state.search || (cm.state.search = new SearchState());
}

function queryCaseInsensitive(query) {
  return typeof query == "string" && query == query.toLowerCase();
}

function getSearchCursor(cm, query, pos) {
  // Heuristic: if the query string is all lowercase, do a case insensitive search.
  return cm.getSearchCursor(query, pos, queryCaseInsensitive(query));
}

function persistentDialog(cm, text, deflt, onEnter, onKeyDown) {
  cm.openDialog(text, onEnter, {
    value: deflt,
    selectValueOnOpen: true,
    closeOnEnter: false,
    onClose: function() { clearSearch(cm); },
    onKeyDown: onKeyDown
  });
}

function dialog(cm, text, shortText, deflt, f) {
  if (cm.openDialog) cm.openDialog(text, f, {value: deflt, selectValueOnOpen: true});
  else f(prompt(shortText, deflt));
}

function confirmDialog(cm, text, shortText, fs) {
  if (cm.openConfirm) cm.openConfirm(text, fs);
  else if (confirm(shortText)) fs[0]();
}

function parseString(string) {
  return string.replace(/\\(.)/g, function(_, ch) {
    if (ch == "n") return "\n"
    if (ch == "r") return "\r"
    return ch
  })
}

function parseQuery(query) {
  var isRE = query.match(/^\/(.*)\/([a-z]*)$/);
  if (isRE) {
    try { query = new RegExp(isRE[1], isRE[2].indexOf("i") == -1 ? "" : "i"); }
    catch(e) {} // Not a regular expression after all, do a string search
  } else {
    query = parseString(query)
  }
  if (typeof query == "string" ? query == "" : query.test(""))
    query = /x^/;
  return query;
}

if(navigator.platform == "MacIntel") {
    var queryDialog =
      'Search: <input type="text" style="width: 10em" class="CodeMirror-search-field"/> Hit enter, then Next (⌘-G) and Prev (Shift-⌘-G). Use /re/ for regular expression.';
} else {
    var queryDialog =
      'Search: <input type="text" style="width: 10em" class="CodeMirror-search-field"/> Hit enter, then Next (Ctrl-G) and Prev (Shift-Ctrl-G). Use /re/ for regular expression.';
}

function startSearch(cm, state, query) {
  state.queryText = query;
  state.query = parseQuery(query);
  cm.removeOverlay(state.overlay, queryCaseInsensitive(state.query));
  state.overlay = searchOverlay(state.query, queryCaseInsensitive(state.query));
  cm.addOverlay(state.overlay);
  if (cm.showMatchesOnScrollbar) {
    if (state.annotate) { state.annotate.clear(); state.annotate = null; }
    state.annotate = cm.showMatchesOnScrollbar(state.query, queryCaseInsensitive(state.query));
  }
}

function doSearch(cm, rev, persistent, immediate) {
  var state = getSearchState(cm);
  if (state.query) return findNext(cm, rev);
  var q = cm.getSelection() || state.lastQuery;
  if (persistent && cm.openDialog) {
    var hiding = null
    var searchNext = function(query, event) {
      CodeMirror.e_stop(event);
      if (!query) return;
      if (query != state.queryText) {
        startSearch(cm, state, query);
        state.posFrom = state.posTo = cm.getCursor();
      }
      if (hiding) hiding.style.opacity = 1
      findNext(cm, event.shiftKey, function(_, to) {
        var dialog
        if (to.line < 3 && document.querySelector &&
            (dialog = cm.display.wrapper.querySelector(".CodeMirror-dialog")) &&
            dialog.getBoundingClientRect().bottom - 4 > cm.cursorCoords(to, "window").top)
          (hiding = dialog).style.opacity = .4
      })
    };
    persistentDialog(cm, queryDialog, q, searchNext, function(event, query) {
      var keyName = CodeMirror.keyName(event)
      var cmd = CodeMirror.keyMap[cm.getOption("keyMap")][keyName]
      if (!cmd) cmd = cm.getOption('extraKeys')[keyName]
      if (cmd == "findNext" || cmd == "findPrev" ||
        cmd == "findPersistentNext" || cmd == "findPersistentPrev") {
        CodeMirror.e_stop(event);
        startSearch(cm, getSearchState(cm), query);
        cm.execCommand(cmd);
      } else if (cmd == "find" || cmd == "findPersistent") {
        CodeMirror.e_stop(event);
        searchNext(query, event);
      }
    });
    if (immediate && q) {
      startSearch(cm, state, q);
      findNext(cm, rev);
    }
  } else {
    dialog(cm, queryDialog, "Search for:", q, function(query) {
      if (query && !state.query) cm.operation(function() {
        startSearch(cm, state, query);
        state.posFrom = state.posTo = cm.getCursor();
        findNext(cm, rev);
      });
    });
  }
}

/* Return true if the given position is part of a collapsed mark.
   See https://github.com/sagemathinc/smc/issues/522
   We need this since codemirror's own search doesn't ignore
   collapsed ranges, e.g., the output in sage worksheets.
*/
function isCollapsedPos(cm, pos) {
  var marks = cm.findMarksAt(pos);
  for(var i=0; i<marks.length; i++) {
    if(marks[i].collapsed) {
      return true;
    }
  }
  return false;
}

function findNext(cm, rev, callback) {cm.operation(function() {
  var state = getSearchState(cm);
  var cursor = getSearchCursor(cm, state.query, rev ? state.posFrom : state.posTo);
  if (!cursor.find(rev)) {
    cursor = getSearchCursor(cm, state.query, rev ? CodeMirror.Pos(cm.lastLine()) : CodeMirror.Pos(cm.firstLine(), 0));
    if (!cursor.find(rev)) return;
  }
  cm.setSelection(cursor.from(), cursor.to());
  cm.scrollIntoView({from: cursor.from(), to: cursor.to()}, 20);
  state.posFrom = cursor.from(); state.posTo = cursor.to();
  if (isCollapsedPos(cm, state.posFrom)) {
      /* In a collapsed range -- just try again.  This won't lead to an infinite loop in case
         of no patches, since that's handled by the "if (!cursor.find(rev))" above. */
      findNext(cm, rev, callback);
      return
  }
  if (callback) callback(cursor.from(), cursor.to())
});}

function clearSearch(cm) {cm.operation(function() {
  var state = getSearchState(cm);
  state.lastQuery = state.query;
  if (!state.query) return;
  state.query = state.queryText = null;
  cm.removeOverlay(state.overlay);
  if (state.annotate) { state.annotate.clear(); state.annotate = null; }
});}

var replaceQueryDialog =
  ' <input type="text" style="width: 10em" class="CodeMirror-search-field"/> Hit enter (use /re/ syntax for regular expression search)';
var replacementQueryDialog = 'With: <input type="text" style="width: 10em" class="CodeMirror-search-field"/>';
var doReplaceConfirm = "Replace? <button>Yes</button> <button>No</button> <button>All</button> <button>Stop</button>";

function replaceAll(cm, query, text) {
  cm.operation(function() {
    for (var cursor = getSearchCursor(cm, query); cursor.findNext();) {
      if (typeof query != "string") {
        var match = cm.getRange(cursor.from(), cursor.to()).match(query);
        cursor.replace(text.replace(/\$(\d)/g, function(_, i) {return match[i];}));
      } else cursor.replace(text);
    }
  });
}

function replace(cm, all) {
  if (cm.getOption("readOnly")) return;
  var query = cm.getSelection() || getSearchState(cm).lastQuery;
  var dialogText = all ? "Replace all:" : "Replace:"
  dialog(cm, dialogText + replaceQueryDialog, dialogText, query, function(query) {
    if (!query) return;
    query = parseQuery(query);
    dialog(cm, replacementQueryDialog, "Replace with:", "", function(text) {
      text = parseString(text)
      if (all) {
        replaceAll(cm, query, text)
      } else {
        clearSearch(cm);
        var cursor = getSearchCursor(cm, query, cm.getCursor("from"));
        var advance = function() {
          var start = cursor.from(), match;
          if (!(match = cursor.findNext())) {
            cursor = getSearchCursor(cm, query);
            if (!(match = cursor.findNext()) ||
                (start && cursor.from().line == start.line && cursor.from().ch == start.ch)) return;
          }
          cm.setSelection(cursor.from(), cursor.to());
          cm.scrollIntoView({from: cursor.from(), to: cursor.to()});
          confirmDialog(cm, doReplaceConfirm, "Replace?",
                        [function() {doReplace(match);}, advance,
                         function() {replaceAll(cm, query, text)}]);
        };
        var doReplace = function(match) {
          cursor.replace(typeof query == "string" ? text :
                         text.replace(/\$(\d)/g, function(_, i) {return match[i];}));
          advance();
        };
        advance();
      }
    });
  });
}

CodeMirror.commands.find = function(cm) {clearSearch(cm); doSearch(cm);};
CodeMirror.commands.findNext = doSearch;
CodeMirror.commands.findPrev = function(cm) {doSearch(cm, true);};

CodeMirror.commands.findPersistent = function(cm) {clearSearch(cm); doSearch(cm, false, true);};
CodeMirror.commands.findPersistentNext = function(cm) {doSearch(cm, false, true, true);};
CodeMirror.commands.findPersistentPrev = function(cm) {doSearch(cm, true, true, true);};

CodeMirror.commands.findPersistent = function(cm) {clearSearch(cm); doSearch(cm, false, true);};
CodeMirror.commands.findPersistentNext = function(cm) {doSearch(cm, false, true, true);};
CodeMirror.commands.findPersistentPrev = function(cm) {doSearch(cm, true, true, true);};

CodeMirror.commands.clearSearch = clearSearch;
CodeMirror.commands.replace = replace;
CodeMirror.commands.replaceAll = function(cm) {replace(cm, true);};

<|endoftext|>


<commit_before>/*
 * Copyright 2020 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * External dependencies
 */
import { render } from '@testing-library/react';

/**
 * Internal dependencies
 */
import { TestDisplayElement } from '../../../components/canvas/test/_utils';
import { OverlayType } from '../../../utils/backgroundOverlay';

describe('MediaDisplay', () => {
  let imageElement;
  let videoElement;
  let storyContext;
  let refs;

  beforeEach(() => {
    imageElement = {
      id: '1',
      type: 'image',
      x: 0,
      y: 0,
      width: 80,
      height: 100,
      rotationAngle: 0,
      scale: 100,
      focalX: 50,
      focalY: 50,
      resource: {
        type: 'image',
        mimeType: 'image/png',
        src: 'https://example.com/image1',
        width: 1000,
        height: 800,
        sizes: {
          medium: {
            source_url: 'https://example.com/image1-mid',
            width: 500,
            height: 400,
          },
          full: {
            source_url: 'https://example.com/image1',
            width: 1000,
            height: 800,
          },
        },
      },
    };
    videoElement = {
      id: 'baz',
      type: 'video',
      mimeType: 'video/mp4',
      scale: 1,
      origRatio: 9 / 16,
      x: 0,
      y: 0,
      height: 1920,
      width: 1080,
      rotationAngle: 0,
      isBackground: false,
      loop: true,
      flip: {
        vertical: false,
        horizontal: false,
      },
      resource: {
        type: 'video',
        mimeType: 'video/mp4',
        id: 123,
        src: 'https://example.com/video.mp4',
        poster: 'https://example.com/poster.png',
        height: 1920,
        width: 1080,
        length: 99,
      },
    };

    storyContext = {};
    refs = {};
  });

  it('should render img with srcset', () => {
    const { container } = render(
      <TestDisplayElement storyContext={storyContext} element={imageElement} />
    );

    const img = container.querySelector('img');

    expect(img.srcset).toBe(
      'https://example.com/image1 1000w,https://example.com/image1-mid 500w'
    );
    // Take optimized image loading into account, will use medium size at start
    expect(img.src).toBe(imageElement.resource.sizes.medium.source_url);
  });

  it('should render img with scale and focal point', () => {
    const { container } = render(
      <TestDisplayElement storyContext={storyContext} element={imageElement} />
    );

    const img = container.querySelector('img');
    // The offset is setup to fit 1000:800 image inside 80:100 box.
    expect(window.getComputedStyle(img)).toMatchObject({
      width: '125px',
      height: '100px',
      left: '-22.5px',
      top: '0px',
    });
  });

  it('should apply and reset transformations', () => {
    const { container } = render(
      <TestDisplayElement
        refs={refs}
        storyContext={storyContext}
        element={imageElement}
      />
    );

    const {
      actions: { pushTransform },
    } = refs.transformContext;

    const img = container.querySelector('img');

    // Start with empty style.
    expect(img.style.cssText).toBe('');

    // Resize to 100:80 (or 1:1 with the original size).
    pushTransform(imageElement.id, { resize: [100, 80] });
    expect(img.style.cssText).not.toBe('');
    expect(img.style).toMatchObject({
      width: '100px',
      height: '80px',
      left: '0px',
      top: '0px',
    });

    // Reset.
    pushTransform(imageElement.id, null);
    expect(img.style.cssText).toBe('');
  });

  it('should render flipped background video with overlay', () => {
    const overlayCases = [
      OverlayType.NONE,
      OverlayType.SOLID,
      OverlayType.LINEAR,
      OverlayType.RADIAL,
    ];
    const flipCases = [
      {
        flip: { vertical: true, horizontal: false },
        transform: 'scale3d(1, -1, 1)',
      },
      {
        flip: { vertical: false, horizontal: true },
        transform: 'scale3d(-1, 1, 1)',
      },
      {
        flip: { vertical: true, horizontal: true },
        transform: 'scale3d(-1, -1, 1)',
      },
    ];

    overlayCases.forEach((backgroundOverlay) => {
      flipCases.forEach(({ flip, transform }) => {
        const flippedBackgroundVideo = {
          ...videoElement,
          isBackground: true,
          flip,
        };
        const { container } = render(
          <TestDisplayElement
            storyContext={{
              ...storyContext,
              page: {
                backgroundOverlay,
              },
            }}
            element={flippedBackgroundVideo}
          />
        );

        const element = container.querySelector('[data-element-id="baz"]')
          .firstChild;
        expect(window.getComputedStyle(element)).toMatchObject({
          transform,
        });
      });
    });
  });
});
<commit_msg>Fix tests<commit_after>/*
 * Copyright 2020 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * External dependencies
 */
import { render } from '@testing-library/react';

/**
 * Internal dependencies
 */
import { TestDisplayElement } from '../../../components/canvas/test/_utils';
import { OverlayType } from '../../../utils/backgroundOverlay';
import resourceList from '../../../utils/resourceList';

describe('MediaDisplay', () => {
  let imageElement;
  let videoElement;
  let storyContext;
  let refs;

  beforeEach(() => {
    imageElement = {
      id: '1',
      type: 'image',
      x: 0,
      y: 0,
      width: 80,
      height: 100,
      rotationAngle: 0,
      scale: 100,
      focalX: 50,
      focalY: 50,
      resource: {
        type: 'image',
        mimeType: 'image/png',
        src: 'https://example.com/image1',
        width: 1000,
        height: 800,
        sizes: {
          medium: {
            source_url: 'https://example.com/image1-mid',
            width: 500,
            height: 400,
          },
          full: {
            source_url: 'https://example.com/image1',
            width: 1000,
            height: 800,
          },
        },
      },
    };
    videoElement = {
      id: 'baz',
      type: 'video',
      mimeType: 'video/mp4',
      scale: 1,
      origRatio: 9 / 16,
      x: 0,
      y: 0,
      height: 1920,
      width: 1080,
      rotationAngle: 0,
      isBackground: false,
      loop: true,
      flip: {
        vertical: false,
        horizontal: false,
      },
      resource: {
        type: 'video',
        mimeType: 'video/mp4',
        id: 123,
        src: 'https://example.com/video.mp4',
        poster: 'https://example.com/poster.png',
        height: 1920,
        width: 1080,
        length: 99,
      },
    };

    storyContext = {};
    refs = {};
  });

  it('should render img with srcset, when fullsize resource is loaded', () => {
    resourceList[imageElement.resource.id] = { type: 'fullsize' };
    const { container } = render(
      <TestDisplayElement storyContext={storyContext} element={imageElement} />
    );

    const img = container.querySelector('img');

    expect(img.srcset).toBe(
      'https://example.com/image1 1000w,https://example.com/image1-mid 500w'
    );
    // Take optimized image loading into account, will use medium size at start
    expect(img.src).toBe(imageElement.resource.sizes.medium.source_url);
  });

  it('should render img with scale and focal point', () => {
    const { container } = render(
      <TestDisplayElement storyContext={storyContext} element={imageElement} />
    );

    const img = container.querySelector('img');
    // The offset is setup to fit 1000:800 image inside 80:100 box.
    expect(window.getComputedStyle(img)).toMatchObject({
      width: '125px',
      height: '100px',
      left: '-22.5px',
      top: '0px',
    });
  });

  it('should apply and reset transformations', () => {
    const { container } = render(
      <TestDisplayElement
        refs={refs}
        storyContext={storyContext}
        element={imageElement}
      />
    );

    const {
      actions: { pushTransform },
    } = refs.transformContext;

    const img = container.querySelector('img');

    // Start with empty style.
    expect(img.style.cssText).toBe('');

    // Resize to 100:80 (or 1:1 with the original size).
    pushTransform(imageElement.id, { resize: [100, 80] });
    expect(img.style.cssText).not.toBe('');
    expect(img.style).toMatchObject({
      width: '100px',
      height: '80px',
      left: '0px',
      top: '0px',
    });

    // Reset.
    pushTransform(imageElement.id, null);
    expect(img.style.cssText).toBe('');
  });

  it('should render flipped background video with overlay', () => {
    const overlayCases = [
      OverlayType.NONE,
      OverlayType.SOLID,
      OverlayType.LINEAR,
      OverlayType.RADIAL,
    ];
    const flipCases = [
      {
        flip: { vertical: true, horizontal: false },
        transform: 'scale3d(1, -1, 1)',
      },
      {
        flip: { vertical: false, horizontal: true },
        transform: 'scale3d(-1, 1, 1)',
      },
      {
        flip: { vertical: true, horizontal: true },
        transform: 'scale3d(-1, -1, 1)',
      },
    ];

    overlayCases.forEach((backgroundOverlay) => {
      flipCases.forEach(({ flip, transform }) => {
        const flippedBackgroundVideo = {
          ...videoElement,
          isBackground: true,
          flip,
        };
        const { container } = render(
          <TestDisplayElement
            storyContext={{
              ...storyContext,
              page: {
                backgroundOverlay,
              },
            }}
            element={flippedBackgroundVideo}
          />
        );

        const element = container.querySelector('[data-element-id="baz"]')
          .firstChild;
        expect(window.getComputedStyle(element)).toMatchObject({
          transform,
        });
      });
    });
  });
});
<|endoftext|>


<commit_before>'use strict';

var Attributes = GURPS.Attributes;

describe('Attributes module creation', function () {
  it('without arguments', function () {
    var obj = new Attributes();
    expect(obj).toEqual(jasmine.any(Object));
  });

  it("with empty object", function () {
    var obj = new Attributes({});
    expect(obj).toEqual(jasmine.any(Object));
  });
});
<commit_msg>attributes tests<commit_after>'use strict';

var Attributes = GURPS.Attributes;

describe('Attributes module creation', function () {
  it('without arguments', function () {
    var module = new Attributes();
    expect(module).toEqual(jasmine.any(Object));
  });

  it("with empty object", function () {
    var module = new Attributes({});
    expect(module).toEqual(jasmine.any(Object));
  });
});

describe('Attributes module get', function () {
  it("undefined attribute should be zero", function () {
    var module, value;
    module = new Attributes({});
    value = module.get('attr');

    expect(value).toEqual(jasmine.any(Number));
    expect(value).toEqual(0);
  });

  it("simple attribute should be it's value", function () {
    var module, value;
    module = new Attributes({
      attr: 11
    });
    value = module.get('attr');

    expect(value).toEqual(jasmine.any(Number));
    expect(value).toEqual(11);
  });

  it("string attribute should be the zero if referenced attribute's is undefined", function () {
    var module, value;
    module = new Attributes({
      attr: 'referenced'
    });
    value = module.get('attr');

    expect(value).toEqual(jasmine.any(Number));
    expect(value).toEqual(0);
  });

  it("string attribute should be the referenced attribute's value", function () {
    var module, value;
    module = new Attributes({
      referenced: 11,
      attr: 'referenced'
    });
    value = module.get('attr');

    expect(value).toEqual(jasmine.any(Number));
    expect(value).toEqual(11);
  });

  it("array of keys should be the sum of it's values", function () {
    var module, value;
    module = new Attributes({
      key1: 11,
      key2: 22,
      key3: 33,
      attr: ['key1', 'key2', 'key3']
    });
    value = module.get('attr');

    expect(value).toEqual(jasmine.any(Number));
    expect(value).toEqual(11 + 22 + 33);
  });

  //TODO
  /*it("array of formulas should be the sum of it's values", function () {
    var module, value;
    module = new Attributes({
        key1: 11,
        key2: 22,
        key3: 33,
        attr: [{floor: 11,2}, {}, 'key3']
    });
    value = module.get('attr');

    expect(value).toEqual(jasmine.any(Number));
    expect(value).toEqual(11 + 22 + 33);
  });
    */

});
<|endoftext|>


<commit_before>'use strict';

module.exports = function (client) {

	function enabled(msg) {
		return msg.markable && client.config.chatMarkers !== false;
	}

	client.disco.addFeature('urn:xmpp:chat-markers:0');

	client.on('message', function(msg) {
		if (enabled(msg)) {
			client.sendMessage({
				to: msg.from,
				received: msg.id
			});
			return ;
		}

		if (msg.received) {
			return client.emit('marker:received', msg.received);
		}

		if (msg.displayed) {
			return client.emit('marker:displayed', msg.displayed);
		}

		if (msg.acknowledged) {
			return client.emit('marker:acknowledged', msg.acknowledged);
		}
	});

	client.markDisplayed = function(msg) {
		if (enabled(msg)) {
			client.sendMessage({
				to: msg.from,
				displayed: msg.id
			});
		}
	};

	client.markAcknowledged = function(msg) {
		if (enabled(msg)) {
			client.sendMessage({
				to: msg.from,
				acknowledged: msg.id
			});
		}
	};
};
<commit_msg>Use spaces<commit_after>'use strict';

module.exports = function (client) {

    function enabled(msg) {
        return msg.markable && client.config.chatMarkers !== false;
    }

    client.disco.addFeature('urn:xmpp:chat-markers:0');

    client.on('message', function(msg) {
        if (enabled(msg)) {
            client.sendMessage({
                to: msg.from,
                received: msg.id
            });
            return ;
        }

        if (msg.received) {
            return client.emit('marker:received', msg.received);
        }

        if (msg.displayed) {
            return client.emit('marker:displayed', msg.displayed);
        }

        if (msg.acknowledged) {
            return client.emit('marker:acknowledged', msg.acknowledged);
        }
    });

    client.markDisplayed = function(msg) {
        if (enabled(msg)) {
            client.sendMessage({
                to: msg.from,
                displayed: msg.id
            });
        }
    };

    client.markAcknowledged = function(msg) {
        if (enabled(msg)) {
            client.sendMessage({
                to: msg.from,
                acknowledged: msg.id
            });
        }
    };
};
<|endoftext|>


<commit_before>/**
 * NodeBot
 *
 * @author  Kevin "Loki" Kragenbrink <kevin@writh.net>
 * @updated 12 November 2011
 * @version 0.4.0
 */

// Update this configuration section with your information.
var config = {
    // The list of plugins you want to use.
    plugins                 : ['Finger'],

    // Output decorators.
    output : {
        header              : '[center( < %s >, 78, = )]\n',
        prefix              : '<%s>',
        tail                : '[repeat( =, 78 )]'
    },

    // Connection information.
    mud : {
        host                : 'writh.net',  // The hostname of your MUSH; best if localhost
        port                : 2016,         // The port of your MUSH
        user                : 'NodeBot',    // The username of your bot.
        pass                : '!'           // The password of your bot.
    },

    // The level of details you want to see in your logs. (debug, log, warn, or error)
    logLevel                : 'debug'
};
// *** STOP ***
// Do not edit below this line.
// *** STOP ***

/**
 * NodeBot Bootstrap Script
 *
 * Bootstraps the NodeBot and initializes its plugins for run.
 * @param config
 */
var NodeBot = function( config ) {
    var self                = this;
    var libraries = {
        Controller          : false,
        Connection          : false,
        Log                 : false,
        Mud                 : false,
        Process             : false,
        ProcessManager      : false
    };
    var plugins             = {};
    var version             = '0.4.0';
    self.config             = config;
    self.prelog             = [];

    /**
     * Creates a log store until the Log class is initialized.
     * @param type
     */
    function Prelog( type ) {
        return function() {
            var args = Array.prototype.slice.call( arguments, 0 );
            args.unshift( type );
            self.prelog.push( args );
        }
    }
    self.debug = new Prelog( 'debug' );
    self.error = new Prelog( 'error' );
    self.log = new Prelog( 'log' );
    self.warn = new Prelog( 'warn' );

    /**
     * Initializes NodeBot and instantiates all libraries and plugins.
     * @private
     */
    function init() {

        self.log( 'NodeBot', "NodeBot %s starting up.", version );
        loadLibraries();
        loadPlugins();
        self.Connection.connect();
    }

    /**
     * Iterates through the libraries and initializes them.
     * @private
     */
    function loadLibraries() {
        for ( var i in libraries ) {
            loadLibrary( i );
        }

    }

    /**
     * Iterates through the requested plugins and initializes them.
     * @private
     */
    function loadPlugins() {
        for ( var i in self.config.plugins ) {
            loadPlugin( self.config.plugins[i] );
        }
    }

    /**
     * Registers a Library.
     * @param Library
     * @private
     */
    function loadLibrary( Library ) {

        if ( !libraries[Library] ) {
            self[Library]                   = require( './lib/' + Library );

            if ( typeof self[Library].init === 'function' ) {
                self[Library].init( self );
            }

            libraries[Library]              = true;
        }
    }

    /**
     * Registers a Plugin.
     * @param Plugin
     * @private
     */
    function loadPlugin( Plugin ) {

        var pluginName                  = Plugin.toLowerCase();
        plugins[pluginName]             = require( './plugins/' + Plugin + '.js' );
        plugins[pluginName].init( self );
    }

    // Go!
    init();
    return self;
};

module.exports              = new NodeBot( config );<commit_msg>* Default connection info should be default!<commit_after>/**
 * NodeBot
 *
 * @author  Kevin "Loki" Kragenbrink <kevin@writh.net>
 * @updated 12 November 2011
 * @version 0.4.0
 */

// Update this configuration section with your information.
var config = {
    // The list of plugins you want to use.
    plugins                 : ['Finger'],

    // Output decorators.
    output : {
        header              : '[center( < %s >, 78, = )]\n',
        prefix              : '<%s>',
        tail                : '[repeat( =, 78 )]'
    },

    // Connection information.
    mud : {
        host                : 'localhost',  // The hostname of your MUSH; best if localhost
        port                : 2067,         // The port of your MUSH
        user                : 'NodeBot',    // The username of your bot.
        pass                : '!'           // The password of your bot.
    },

    // The level of details you want to see in your logs. (debug, log, warn, or error)
    logLevel                : 'debug'
};
// *** STOP ***
// Do not edit below this line.
// *** STOP ***

/**
 * NodeBot Bootstrap Script
 *
 * Bootstraps the NodeBot and initializes its plugins for run.
 * @param config
 */
var NodeBot = function( config ) {
    var self                = this;
    var libraries = {
        Controller          : false,
        Connection          : false,
        Log                 : false,
        Mud                 : false,
        Process             : false,
        ProcessManager      : false
    };
    var plugins             = {};
    var version             = '0.4.0';
    self.config             = config;
    self.prelog             = [];

    /**
     * Creates a log store until the Log class is initialized.
     * @param type
     */
    function Prelog( type ) {
        return function() {
            var args = Array.prototype.slice.call( arguments, 0 );
            args.unshift( type );
            self.prelog.push( args );
        }
    }
    self.debug = new Prelog( 'debug' );
    self.error = new Prelog( 'error' );
    self.log = new Prelog( 'log' );
    self.warn = new Prelog( 'warn' );

    /**
     * Initializes NodeBot and instantiates all libraries and plugins.
     * @private
     */
    function init() {

        self.log( 'NodeBot', "NodeBot %s starting up.", version );
        loadLibraries();
        loadPlugins();
        self.Connection.connect();
    }

    /**
     * Iterates through the libraries and initializes them.
     * @private
     */
    function loadLibraries() {
        for ( var i in libraries ) {
            loadLibrary( i );
        }

    }

    /**
     * Iterates through the requested plugins and initializes them.
     * @private
     */
    function loadPlugins() {
        for ( var i in self.config.plugins ) {
            loadPlugin( self.config.plugins[i] );
        }
    }

    /**
     * Registers a Library.
     * @param Library
     * @private
     */
    function loadLibrary( Library ) {

        if ( !libraries[Library] ) {
            self[Library]                   = require( './lib/' + Library );

            if ( typeof self[Library].init === 'function' ) {
                self[Library].init( self );
            }

            libraries[Library]              = true;
        }
    }

    /**
     * Registers a Plugin.
     * @param Plugin
     * @private
     */
    function loadPlugin( Plugin ) {

        var pluginName                  = Plugin.toLowerCase();
        plugins[pluginName]             = require( './plugins/' + Plugin + '.js' );
        plugins[pluginName].init( self );
    }

    // Go!
    init();
    return self;
};

module.exports              = new NodeBot( config );<|endoftext|>


<commit_before>'use strict';

var analytics = require('./lib/analytics');
var DropinError = require('./lib/dropin-error');
var EventEmitter = require('@braintree/event-emitter');
var constants = require('./constants');
var paymentMethodTypes = constants.paymentMethodTypes;
var paymentOptionIDs = constants.paymentOptionIDs;
var dependencySetupStates = constants.dependencySetupStates;
var isGuestCheckout = require('./lib/is-guest-checkout');
var Promise = require('./lib/promise');
var paymentSheetViews = require('./views/payment-sheet-views');
var vaultManager = require('braintree-web/vault-manager');

var VAULTED_PAYMENT_METHOD_TYPES_THAT_SHOULD_BE_HIDDEN = [
  paymentMethodTypes.applePay,
  paymentMethodTypes.googlePay,
  paymentMethodTypes.venmo
];
var DEFAULT_PAYMENT_OPTION_PRIORITY = [
  paymentOptionIDs.card,
  paymentOptionIDs.paypal,
  paymentOptionIDs.paypalCredit,
  paymentOptionIDs.venmo,
  paymentOptionIDs.applePay,
  paymentOptionIDs.googlePay
];
var ASYNC_DEPENDENCIES = DEFAULT_PAYMENT_OPTION_PRIORITY.concat(['threeDSecure', 'dataCollector']);
var DEPENDENCY_READY_CHECK_INTERVAL = 200;

function DropinModel(options) {
  this.rootNode = options.container;
  this.componentID = options.componentID;
  this.merchantConfiguration = options.merchantConfiguration;
  this.isGuestCheckout = isGuestCheckout(options.client);

  this.dependencyStates = ASYNC_DEPENDENCIES.reduce(function (total, dependencyKey) {
    if (dependencyKey in options.merchantConfiguration) {
      total[dependencyKey] = dependencySetupStates.INITIALIZING;
    }

    return total;
  }, {});
  // card is on by default, so we need to set it's state to INITIALIZING
  // unless the merchant has specifically opted out of using the card form
  if (options.merchantConfiguration.card !== false) {
    this.dependencyStates.card = dependencySetupStates.INITIALIZING;
  }

  this.failedDependencies = {};
  this._options = options;
  this._setupComplete = false;

  while (this.rootNode.parentNode) {
    this.rootNode = this.rootNode.parentNode;
  }
  this.isInShadowDom = this.rootNode.toString() === '[object ShadowRoot]';

  EventEmitter.call(this);
}

EventEmitter.createChild(DropinModel);

DropinModel.prototype.initialize = function () {
  var self = this;
  var dependencyReadyInterval = setInterval(function () {
    var ready = true;

    Object.keys(self.dependencyStates).forEach(function (dep) {
      if (self.dependencyStates[dep] === dependencySetupStates.INITIALIZING) {
        ready = false;
      }
    });

    if (!ready) {
      return;
    }

    clearInterval(dependencyReadyInterval);

    self._emit('asyncDependenciesReady');
  }, DEPENDENCY_READY_CHECK_INTERVAL);

  return vaultManager.create({
    client: self._options.client
  }).then(function (vaultManagerInstance) {
    self._vaultManager = vaultManagerInstance;

    return self._getSupportedPaymentOptions(self._options);
  }).then(function (paymentOptions) {
    self.supportedPaymentOptions = paymentOptions;

    return self.getVaultedPaymentMethods();
  }).then(function (paymentMethods) {
    self._paymentMethods = paymentMethods;
    self._paymentMethodIsRequestable = self._paymentMethods.length > 0;
  });
};

DropinModel.prototype.confirmDropinReady = function () {
  this._setupComplete = true;
};

DropinModel.prototype.isPaymentMethodRequestable = function () {
  return Boolean(this._paymentMethodIsRequestable);
};

DropinModel.prototype.addPaymentMethod = function (paymentMethod) {
  this._paymentMethods.push(paymentMethod);
  this._emit('addPaymentMethod', paymentMethod);
  this.changeActivePaymentMethod(paymentMethod);
};

DropinModel.prototype.removePaymentMethod = function (paymentMethod) {
  var paymentMethodLocation = this._paymentMethods.indexOf(paymentMethod);

  if (paymentMethodLocation === -1) {
    return;
  }

  this._paymentMethods.splice(paymentMethodLocation, 1);
  this._emit('removePaymentMethod', paymentMethod);
};

DropinModel.prototype.refreshPaymentMethods = function () {
  var self = this;

  return self.getVaultedPaymentMethods().then(function (paymentMethods) {
    self._paymentMethods = paymentMethods;

    self._emit('refreshPaymentMethods');
  });
};

DropinModel.prototype.changeActivePaymentMethod = function (paymentMethod) {
  this._activePaymentMethod = paymentMethod;
  this._emit('changeActivePaymentMethod', paymentMethod);
};

DropinModel.prototype.changeActivePaymentView = function (paymentViewID) {
  this._activePaymentView = paymentViewID;
  this._emit('changeActivePaymentView', paymentViewID);
};

DropinModel.prototype.removeActivePaymentMethod = function () {
  this._activePaymentMethod = null;
  this._emit('removeActivePaymentMethod');
  this.setPaymentMethodRequestable({
    isRequestable: false
  });
};

DropinModel.prototype.selectPaymentOption = function (paymentViewID) {
  this._emit('paymentOptionSelected', {
    paymentOption: paymentViewID
  });
};

DropinModel.prototype.enableEditMode = function () {
  analytics.sendEvent(this._options.client, 'manager.appeared');
  this._isInEditMode = true;
  this._emit('enableEditMode');
};

DropinModel.prototype.disableEditMode = function () {
  this._isInEditMode = false;
  this._emit('disableEditMode');
};

DropinModel.prototype.isInEditMode = function () {
  return Boolean(this._isInEditMode);
};

DropinModel.prototype.confirmPaymentMethodDeletion = function (paymentMethod) {
  this._paymentMethodWaitingToBeDeleted = paymentMethod;
  this._emit('confirmPaymentMethodDeletion', paymentMethod);
};

DropinModel.prototype._shouldEmitRequestableEvent = function (options) {
  var requestableStateHasNotChanged = this.isPaymentMethodRequestable() === options.isRequestable;
  var nonce = options.selectedPaymentMethod && options.selectedPaymentMethod.nonce;
  var nonceHasNotChanged = nonce === this._paymentMethodRequestableNonce;

  if (!this._setupComplete) {
    // don't emit event until after Drop-in is fully set up
    // fixes issues with lazy loading of imports where event
    // should not be emitted
    // https://github.com/braintree/braintree-web-drop-in/issues/511
    return false;
  }

  if (requestableStateHasNotChanged && (!options.isRequestable || nonceHasNotChanged)) {
    return false;
  }

  return true;
};

DropinModel.prototype.setPaymentMethodRequestable = function (options) {
  var shouldEmitEvent = this._shouldEmitRequestableEvent(options);
  var paymentMethodRequestableResponse = {
    paymentMethodIsSelected: Boolean(options.selectedPaymentMethod),
    type: options.type
  };

  this._paymentMethodIsRequestable = options.isRequestable;

  if (options.isRequestable) {
    this._paymentMethodRequestableNonce = options.selectedPaymentMethod && options.selectedPaymentMethod.nonce;
  } else {
    delete this._paymentMethodRequestableNonce;
  }

  if (!shouldEmitEvent) {
    return;
  }

  if (options.isRequestable) {
    this._emit('paymentMethodRequestable', paymentMethodRequestableResponse);
  } else {
    this._emit('noPaymentMethodRequestable');
  }
};

DropinModel.prototype.getPaymentMethods = function () {
  // we want to return a copy of the Array
  // so we can loop through it in dropin.updateConfiguration
  // while calling model.removePaymentMethod
  // which updates the original array
  return this._paymentMethods.slice();
};

DropinModel.prototype.getActivePaymentMethod = function () {
  return this._activePaymentMethod;
};

DropinModel.prototype.getActivePaymentView = function () {
  return this._activePaymentView;
};

DropinModel.prototype.reportAppSwitchPayload = function (payload) {
  this.appSwitchPayload = payload;
};

DropinModel.prototype.reportAppSwitchError = function (sheetId, error) {
  this.appSwitchError = {
    id: sheetId,
    error: error
  };
};

DropinModel.prototype.hasAtLeastOneAvailablePaymentOption = function () {
  var self = this;
  var i;

  for (i = 0; i < this.supportedPaymentOptions.length; i++) {
    if (self.dependencyStates[this.supportedPaymentOptions[i]] === dependencySetupStates.DONE) {
      return true;
    }
  }

  return false;
};

DropinModel.prototype.asyncDependencyReady = function (key) {
  this.dependencyStates[key] = dependencySetupStates.DONE;
};

DropinModel.prototype.asyncDependencyFailed = function (options) {
  if (this.failedDependencies.hasOwnProperty(options.view)) {
    return;
  }
  this.failedDependencies[options.view] = options.error;
  this.dependencyStates[options.view] = dependencySetupStates.FAILED;
};

DropinModel.prototype.cancelInitialization = function (error) {
  this._emit('cancelInitialization', error);
};

DropinModel.prototype.reportError = function (error) {
  this._emit('errorOccurred', error);
};

DropinModel.prototype.clearError = function () {
  this._emit('errorCleared');
};

DropinModel.prototype.preventUserAction = function () {
  this._emit('preventUserAction');
};

DropinModel.prototype.allowUserAction = function () {
  this._emit('allowUserAction');
};

DropinModel.prototype.deleteVaultedPaymentMethod = function () {
  var self = this;
  var promise = Promise.resolve();
  var error;

  this._emit('startVaultedPaymentMethodDeletion');

  if (!self.isGuestCheckout) {
    promise = this._vaultManager.deletePaymentMethod(this._paymentMethodWaitingToBeDeleted.nonce).catch(function (err) {
      error = err;
    });
  }

  return promise.then(function () {
    delete self._paymentMethodWaitingToBeDeleted;

    return self.refreshPaymentMethods();
  }).then(function () {
    self.disableEditMode();
    self._emit('finishVaultedPaymentMethodDeletion', error);
  });
};

DropinModel.prototype.cancelDeleteVaultedPaymentMethod = function () {
  this._emit('cancelVaultedPaymentMethodDeletion');

  delete this._paymentMethodWaitingToBeDeleted;
};

DropinModel.prototype.getVaultedPaymentMethods = function () {
  var self = this;

  if (self.isGuestCheckout) {
    return Promise.resolve([]);
  }

  return self._vaultManager.fetchPaymentMethods({
    defaultFirst: this.merchantConfiguration.showDefaultPaymentMethodFirst !== false
  }).then(function (paymentMethods) {
    return self._getSupportedPaymentMethods(paymentMethods).map(function (paymentMethod) {
      paymentMethod.vaulted = true;

      return paymentMethod;
    });
  }).catch(function () {
    return Promise.resolve([]);
  });
};

DropinModel.prototype._getSupportedPaymentMethods = function (paymentMethods) {
  var supportedPaymentMethods = this.supportedPaymentOptions.reduce(function (array, key) {
    var paymentMethodType = paymentMethodTypes[key];

    if (canShowVaultedPaymentMethodType(paymentMethodType)) {
      array.push(paymentMethodType);
    }

    return array;
  }, []);

  return paymentMethods.filter(function (paymentMethod) {
    return supportedPaymentMethods.indexOf(paymentMethod.type) > -1;
  });
};

DropinModel.prototype._getSupportedPaymentOptions = function (options) {
  var self = this;
  var paymentOptionPriority = options.merchantConfiguration.paymentOptionPriority || DEFAULT_PAYMENT_OPTION_PRIORITY;
  var promises;

  if (!(paymentOptionPriority instanceof Array)) {
    throw new DropinError('paymentOptionPriority must be an array.');
  }

  // Remove duplicates
  paymentOptionPriority = paymentOptionPriority.filter(function (item, pos) { return paymentOptionPriority.indexOf(item) === pos; });

  promises = paymentOptionPriority.map(function (paymentOption) {
    return getPaymentOption(paymentOption, options).then(function (result) {
      if (!result.success) {
        self.dependencyStates[result.id] = dependencySetupStates.NOT_ENABLED;
      }

      return result;
    });
  });

  return Promise.all(promises).then(function (result) {
    result = result.filter(function (item) {
      return item.success;
    });

    if (result.length === 0) {
      return Promise.reject(new DropinError('No valid payment options available.'));
    }

    return result.map(function (item) { return item.id; });
  });
};

function getPaymentOption(paymentOption, options) {
  return isPaymentOptionEnabled(paymentOption, options).then(function (success) {
    return {
      success: success,
      id: paymentOptionIDs[paymentOption]
    };
  });
}

function isPaymentOptionEnabled(paymentOption, options) {
  var SheetView = paymentSheetViews[paymentOptionIDs[paymentOption]];

  if (!SheetView) {
    return Promise.reject(new DropinError('paymentOptionPriority: Invalid payment option specified.'));
  }

  return SheetView.isEnabled({
    client: options.client,
    merchantConfiguration: options.merchantConfiguration
  }).catch(function (error) {
    console.error(SheetView.ID + ' view errored when checking if it was supported.'); // eslint-disable-line no-console
    console.error(error); // eslint-disable-line no-console

    return Promise.resolve(false);
  });
}

function canShowVaultedPaymentMethodType(paymentMethodType) {
  return paymentMethodType && VAULTED_PAYMENT_METHOD_TYPES_THAT_SHOULD_BE_HIDDEN.indexOf(paymentMethodType) === -1;
}

module.exports = DropinModel;
<commit_msg>Update dropin-model.js<commit_after>'use strict';

var analytics = require('./lib/analytics');
var DropinError = require('./lib/dropin-error');
var EventEmitter = require('@braintree/event-emitter');
var constants = require('./constants');
var paymentMethodTypes = constants.paymentMethodTypes;
var paymentOptionIDs = constants.paymentOptionIDs;
var dependencySetupStates = constants.dependencySetupStates;
var isGuestCheckout = require('./lib/is-guest-checkout');
var Promise = require('./lib/promise');
var paymentSheetViews = require('./views/payment-sheet-views');
var vaultManager = require('braintree-web/vault-manager');

var VAULTED_PAYMENT_METHOD_TYPES_THAT_SHOULD_BE_HIDDEN = [
  paymentMethodTypes.applePay,
  paymentMethodTypes.googlePay,
  paymentMethodTypes.venmo
];
var DEFAULT_PAYMENT_OPTION_PRIORITY = [
  paymentOptionIDs.card,
  paymentOptionIDs.paypal,
  paymentOptionIDs.paypalCredit,
  paymentOptionIDs.venmo,
  paymentOptionIDs.applePay,
  paymentOptionIDs.googlePay
];
var ASYNC_DEPENDENCIES = DEFAULT_PAYMENT_OPTION_PRIORITY.concat(['threeDSecure', 'dataCollector']);
var DEPENDENCY_READY_CHECK_INTERVAL = 200;

function DropinModel(options) {
  this.rootNode = options.container;
  this.componentID = options.componentID;
  this.merchantConfiguration = options.merchantConfiguration;
  this.isGuestCheckout = isGuestCheckout(options.client);

  this.dependencyStates = ASYNC_DEPENDENCIES.reduce(function (total, dependencyKey) {
    if (dependencyKey in options.merchantConfiguration) {
      total[dependencyKey] = dependencySetupStates.INITIALIZING;
    }

    return total;
  }, {});
  // card is on by default, so we need to set it's state to INITIALIZING
  // unless the merchant has specifically opted out of using the card form
  if (options.merchantConfiguration.card !== false) {
    this.dependencyStates.card = dependencySetupStates.INITIALIZING;
  }

  this.failedDependencies = {};
  this._options = options;
  this._setupComplete = false;

  while (this.rootNode.parentNode) {
    this.rootNode = this.rootNode.parentNode;
  }
  this.isInShadowDom = this.rootNode.toString() === '[object ShadowRoot]';

  EventEmitter.call(this);
}

EventEmitter.createChild(DropinModel);

DropinModel.prototype.initialize = function () {
  var dep;
  var self = this;
  var dependencyReadyInterval = setInterval(function () {
    for (dep in self.dependencyStates) {
      if (self.dependencyStates[dep] === dependencySetupStates.INITIALIZING) {
        return;
      }
    }

    clearInterval(dependencyReadyInterval);

    self._emit('asyncDependenciesReady');
  }, DEPENDENCY_READY_CHECK_INTERVAL);

  return vaultManager.create({
    client: self._options.client
  }).then(function (vaultManagerInstance) {
    self._vaultManager = vaultManagerInstance;

    return self._getSupportedPaymentOptions(self._options);
  }).then(function (paymentOptions) {
    self.supportedPaymentOptions = paymentOptions;

    return self.getVaultedPaymentMethods();
  }).then(function (paymentMethods) {
    self._paymentMethods = paymentMethods;
    self._paymentMethodIsRequestable = self._paymentMethods.length > 0;
  });
};

DropinModel.prototype.confirmDropinReady = function () {
  this._setupComplete = true;
};

DropinModel.prototype.isPaymentMethodRequestable = function () {
  return Boolean(this._paymentMethodIsRequestable);
};

DropinModel.prototype.addPaymentMethod = function (paymentMethod) {
  this._paymentMethods.push(paymentMethod);
  this._emit('addPaymentMethod', paymentMethod);
  this.changeActivePaymentMethod(paymentMethod);
};

DropinModel.prototype.removePaymentMethod = function (paymentMethod) {
  var paymentMethodLocation = this._paymentMethods.indexOf(paymentMethod);

  if (paymentMethodLocation === -1) {
    return;
  }

  this._paymentMethods.splice(paymentMethodLocation, 1);
  this._emit('removePaymentMethod', paymentMethod);
};

DropinModel.prototype.refreshPaymentMethods = function () {
  var self = this;

  return self.getVaultedPaymentMethods().then(function (paymentMethods) {
    self._paymentMethods = paymentMethods;

    self._emit('refreshPaymentMethods');
  });
};

DropinModel.prototype.changeActivePaymentMethod = function (paymentMethod) {
  this._activePaymentMethod = paymentMethod;
  this._emit('changeActivePaymentMethod', paymentMethod);
};

DropinModel.prototype.changeActivePaymentView = function (paymentViewID) {
  this._activePaymentView = paymentViewID;
  this._emit('changeActivePaymentView', paymentViewID);
};

DropinModel.prototype.removeActivePaymentMethod = function () {
  this._activePaymentMethod = null;
  this._emit('removeActivePaymentMethod');
  this.setPaymentMethodRequestable({
    isRequestable: false
  });
};

DropinModel.prototype.selectPaymentOption = function (paymentViewID) {
  this._emit('paymentOptionSelected', {
    paymentOption: paymentViewID
  });
};

DropinModel.prototype.enableEditMode = function () {
  analytics.sendEvent(this._options.client, 'manager.appeared');
  this._isInEditMode = true;
  this._emit('enableEditMode');
};

DropinModel.prototype.disableEditMode = function () {
  this._isInEditMode = false;
  this._emit('disableEditMode');
};

DropinModel.prototype.isInEditMode = function () {
  return Boolean(this._isInEditMode);
};

DropinModel.prototype.confirmPaymentMethodDeletion = function (paymentMethod) {
  this._paymentMethodWaitingToBeDeleted = paymentMethod;
  this._emit('confirmPaymentMethodDeletion', paymentMethod);
};

DropinModel.prototype._shouldEmitRequestableEvent = function (options) {
  var requestableStateHasNotChanged = this.isPaymentMethodRequestable() === options.isRequestable;
  var nonce = options.selectedPaymentMethod && options.selectedPaymentMethod.nonce;
  var nonceHasNotChanged = nonce === this._paymentMethodRequestableNonce;

  if (!this._setupComplete) {
    // don't emit event until after Drop-in is fully set up
    // fixes issues with lazy loading of imports where event
    // should not be emitted
    // https://github.com/braintree/braintree-web-drop-in/issues/511
    return false;
  }

  if (requestableStateHasNotChanged && (!options.isRequestable || nonceHasNotChanged)) {
    return false;
  }

  return true;
};

DropinModel.prototype.setPaymentMethodRequestable = function (options) {
  var shouldEmitEvent = this._shouldEmitRequestableEvent(options);
  var paymentMethodRequestableResponse = {
    paymentMethodIsSelected: Boolean(options.selectedPaymentMethod),
    type: options.type
  };

  this._paymentMethodIsRequestable = options.isRequestable;

  if (options.isRequestable) {
    this._paymentMethodRequestableNonce = options.selectedPaymentMethod && options.selectedPaymentMethod.nonce;
  } else {
    delete this._paymentMethodRequestableNonce;
  }

  if (!shouldEmitEvent) {
    return;
  }

  if (options.isRequestable) {
    this._emit('paymentMethodRequestable', paymentMethodRequestableResponse);
  } else {
    this._emit('noPaymentMethodRequestable');
  }
};

DropinModel.prototype.getPaymentMethods = function () {
  // we want to return a copy of the Array
  // so we can loop through it in dropin.updateConfiguration
  // while calling model.removePaymentMethod
  // which updates the original array
  return this._paymentMethods.slice();
};

DropinModel.prototype.getActivePaymentMethod = function () {
  return this._activePaymentMethod;
};

DropinModel.prototype.getActivePaymentView = function () {
  return this._activePaymentView;
};

DropinModel.prototype.reportAppSwitchPayload = function (payload) {
  this.appSwitchPayload = payload;
};

DropinModel.prototype.reportAppSwitchError = function (sheetId, error) {
  this.appSwitchError = {
    id: sheetId,
    error: error
  };
};

DropinModel.prototype.hasAtLeastOneAvailablePaymentOption = function () {
  var self = this;
  var i;

  for (i = 0; i < this.supportedPaymentOptions.length; i++) {
    if (self.dependencyStates[this.supportedPaymentOptions[i]] === dependencySetupStates.DONE) {
      return true;
    }
  }

  return false;
};

DropinModel.prototype.asyncDependencyReady = function (key) {
  this.dependencyStates[key] = dependencySetupStates.DONE;
};

DropinModel.prototype.asyncDependencyFailed = function (options) {
  if (this.failedDependencies.hasOwnProperty(options.view)) {
    return;
  }
  this.failedDependencies[options.view] = options.error;
  this.dependencyStates[options.view] = dependencySetupStates.FAILED;
};

DropinModel.prototype.cancelInitialization = function (error) {
  this._emit('cancelInitialization', error);
};

DropinModel.prototype.reportError = function (error) {
  this._emit('errorOccurred', error);
};

DropinModel.prototype.clearError = function () {
  this._emit('errorCleared');
};

DropinModel.prototype.preventUserAction = function () {
  this._emit('preventUserAction');
};

DropinModel.prototype.allowUserAction = function () {
  this._emit('allowUserAction');
};

DropinModel.prototype.deleteVaultedPaymentMethod = function () {
  var self = this;
  var promise = Promise.resolve();
  var error;

  this._emit('startVaultedPaymentMethodDeletion');

  if (!self.isGuestCheckout) {
    promise = this._vaultManager.deletePaymentMethod(this._paymentMethodWaitingToBeDeleted.nonce).catch(function (err) {
      error = err;
    });
  }

  return promise.then(function () {
    delete self._paymentMethodWaitingToBeDeleted;

    return self.refreshPaymentMethods();
  }).then(function () {
    self.disableEditMode();
    self._emit('finishVaultedPaymentMethodDeletion', error);
  });
};

DropinModel.prototype.cancelDeleteVaultedPaymentMethod = function () {
  this._emit('cancelVaultedPaymentMethodDeletion');

  delete this._paymentMethodWaitingToBeDeleted;
};

DropinModel.prototype.getVaultedPaymentMethods = function () {
  var self = this;

  if (self.isGuestCheckout) {
    return Promise.resolve([]);
  }

  return self._vaultManager.fetchPaymentMethods({
    defaultFirst: this.merchantConfiguration.showDefaultPaymentMethodFirst !== false
  }).then(function (paymentMethods) {
    return self._getSupportedPaymentMethods(paymentMethods).map(function (paymentMethod) {
      paymentMethod.vaulted = true;

      return paymentMethod;
    });
  }).catch(function () {
    return Promise.resolve([]);
  });
};

DropinModel.prototype._getSupportedPaymentMethods = function (paymentMethods) {
  var supportedPaymentMethods = this.supportedPaymentOptions.reduce(function (array, key) {
    var paymentMethodType = paymentMethodTypes[key];

    if (canShowVaultedPaymentMethodType(paymentMethodType)) {
      array.push(paymentMethodType);
    }

    return array;
  }, []);

  return paymentMethods.filter(function (paymentMethod) {
    return supportedPaymentMethods.indexOf(paymentMethod.type) > -1;
  });
};

DropinModel.prototype._getSupportedPaymentOptions = function (options) {
  var self = this;
  var paymentOptionPriority = options.merchantConfiguration.paymentOptionPriority || DEFAULT_PAYMENT_OPTION_PRIORITY;
  var promises;

  if (!(paymentOptionPriority instanceof Array)) {
    throw new DropinError('paymentOptionPriority must be an array.');
  }

  // Remove duplicates
  paymentOptionPriority = paymentOptionPriority.filter(function (item, pos) { return paymentOptionPriority.indexOf(item) === pos; });

  promises = paymentOptionPriority.map(function (paymentOption) {
    return getPaymentOption(paymentOption, options).then(function (result) {
      if (!result.success) {
        self.dependencyStates[result.id] = dependencySetupStates.NOT_ENABLED;
      }

      return result;
    });
  });

  return Promise.all(promises).then(function (result) {
    result = result.filter(function (item) {
      return item.success;
    });

    if (result.length === 0) {
      return Promise.reject(new DropinError('No valid payment options available.'));
    }

    return result.map(function (item) { return item.id; });
  });
};

function getPaymentOption(paymentOption, options) {
  return isPaymentOptionEnabled(paymentOption, options).then(function (success) {
    return {
      success: success,
      id: paymentOptionIDs[paymentOption]
    };
  });
}

function isPaymentOptionEnabled(paymentOption, options) {
  var SheetView = paymentSheetViews[paymentOptionIDs[paymentOption]];

  if (!SheetView) {
    return Promise.reject(new DropinError('paymentOptionPriority: Invalid payment option specified.'));
  }

  return SheetView.isEnabled({
    client: options.client,
    merchantConfiguration: options.merchantConfiguration
  }).catch(function (error) {
    console.error(SheetView.ID + ' view errored when checking if it was supported.'); // eslint-disable-line no-console
    console.error(error); // eslint-disable-line no-console

    return Promise.resolve(false);
  });
}

function canShowVaultedPaymentMethodType(paymentMethodType) {
  return paymentMethodType && VAULTED_PAYMENT_METHOD_TYPES_THAT_SHOULD_BE_HIDDEN.indexOf(paymentMethodType) === -1;
}

module.exports = DropinModel;
<|endoftext|>


<commit_before>var Q     = require('q'),
    utils = require('./utils');

module.exports.create = function (id, client) {
  var instance = {},
      logger   = utils.logger(__filename),
      pendingMessages = {};

  /*

  */
  instance.id = 'radio.' + id;

  instance.volume = function (params) {
    console.log('volume should return promise');
    return sendCommandForAction('volume', params);
  };

  instance.playRandom = function (params) {
    return sendCommandForAction('random', params);
  };

  instance.play = function (params) {
    return sendCommandForAction('play', params);
  };

  client.on('message', handleClientMessage);

  function handleClientMessage(data) {
    var deferred,
        content = data.content;

    logger.debug('Incoming message', data.content);

    if (content && content.correlationId) {
      deferred = pendingMessages[content.correlationId];

      if (content.error) {
        deferred.reject(content.error);
      } else {
        deferred.resolve(content);
      }

      delete pendingMessages[content.correlationId];
    }
  }

  function sendCommandForAction(action, params) {
    var deferred = Q.defer(),
        sendPromise;

    params.action = action;
    sendPromise = client.createExchange({ exchangeName: 'radiodan' })
                        .then(function () {
                           return sendCommandToExchange(params);
                          })
                        .then(null, utils.failedPromiseHandler());

    sendPromise.then(function (command) {
      pendingMessages[command.correlationId] = deferred;
    });

    return deferred.promise;
  }

  function sendCommandToExchange(params) {
    return client.sendCommand({
      exchangeName : 'radiodan',
      topicKey     : instance.id + '.command',
      command      : params
    });
  }

  return instance;
};
<commit_msg>remove extra logger<commit_after>var Q     = require('q'),
    utils = require('./utils');

module.exports.create = function (id, client) {
  var instance = {},
      logger   = utils.logger(__filename),
      pendingMessages = {};

  /*

  */
  instance.id = 'radio.' + id;

  instance.volume = function (params) {
    return sendCommandForAction('volume', params);
  };

  instance.playRandom = function (params) {
    return sendCommandForAction('random', params);
  };

  instance.play = function (params) {
    return sendCommandForAction('play', params);
  };

  client.on('message', handleClientMessage);

  function handleClientMessage(data) {
    var deferred,
        content = data.content;

    logger.debug('Incoming message', data.content);

    if (content && content.correlationId) {
      deferred = pendingMessages[content.correlationId];

      if (content.error) {
        deferred.reject(content.error);
      } else {
        deferred.resolve(content);
      }

      delete pendingMessages[content.correlationId];
    }
  }

  function sendCommandForAction(action, params) {
    var deferred = Q.defer(),
        sendPromise;

    params.action = action;
    sendPromise = client.createExchange({ exchangeName: 'radiodan' })
                        .then(function () {
                           return sendCommandToExchange(params);
                          })
                        .then(null, utils.failedPromiseHandler());

    sendPromise.then(function (command) {
      pendingMessages[command.correlationId] = deferred;
    });

    return deferred.promise;
  }

  function sendCommandToExchange(params) {
    return client.sendCommand({
      exchangeName : 'radiodan',
      topicKey     : instance.id + '.command',
      command      : params
    });
  }

  return instance;
};
<|endoftext|>