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

(function(mod) {
  if (typeof exports == "object" && typeof module == "object") // CommonJS
    mod(require("../../lib/codemirror"));
  else if (typeof define == "function" && define.amd) // AMD
    define(["../../lib/codemirror"], mod);
  else // Plain browser env
    mod(CodeMirror);
})(function(CodeMirror) {
"use strict";

CodeMirror.defineMode("commonlisp", function (config) {
  var specialForm = /^(block|let*|return-from|catch|load-time-value|setq|eval-when|locally|symbol-macrolet|flet|macrolet|tagbody|function|multiple-value-call|the|go|multiple-value-prog1|throw|if|progn|unwind-protect|labels|progv|let|quote)$/;
  var assumeBody = /^with|^def|^do|^prog|case$|^cond$|bind$|when$|unless$/;
  var numLiteral = /^(?:[+\-]?(?:\d+|\d*\.\d+)(?:[efd][+\-]?\d+)?|[+\-]?\d+(?:\/[+\-]?\d+)?|#b[+\-]?[01]+|#o[+\-]?[0-7]+|#x[+\-]?[\da-f]+)/;
  var symbol = /[^\s'`,@()\[\]";]/;
  var type;

  function readSym(stream) {
    var ch;
    while (ch = stream.next()) {
      if (ch == "\\") stream.next();
      else if (!symbol.test(ch)) { stream.backUp(1); break; }
    }
    return stream.current();
  }

  function base(stream, state) {
    if (stream.eatSpace()) {type = "ws"; return null;}
    if (stream.match(numLiteral)) return "number";
    var ch = stream.next();
    if (ch == "\\") ch = stream.next();

    if (ch == '"') return (state.tokenize = inString)(stream, state);
    else if (ch == "(") { type = "open"; return "bracket"; }
    else if (ch == ")" || ch == "]") { type = "close"; return "bracket"; }
    else if (ch == ";") { stream.skipToEnd(); type = "ws"; return "comment"; }
    else if (/['`,@]/.test(ch)) return null;
    else if (ch == "|") {
      if (stream.skipTo("|")) { stream.next(); return "symbol"; }
      else { stream.skipToEnd(); return "error"; }
    } else if (ch == "#") {
      var ch = stream.next();
      if (ch == "[") { type = "open"; return "bracket"; }
      else if (/[+\-=\.']/.test(ch)) return null;
      else if (/\d/.test(ch) && stream.match(/^\d*#/)) return null;
      else if (ch == "|") return (state.tokenize = inComment)(stream, state);
      else if (ch == ":") { readSym(stream); return "meta"; }
      else if (ch == "\\") { stream.next(); readSym(stream); return "string-2" }
      else return "error";
    } else {
      var name = readSym(stream);
      if (name == ".") return null;
      type = "symbol";
      if (name == "nil" || name == "t" || name.charAt(0) == ":") return "atom";
      if (state.lastType == "open" && (specialForm.test(name) || assumeBody.test(name))) return "keyword";
      if (name.charAt(0) == "&") return "variable-2";
      return "variable";
    }
  }

  function inString(stream, state) {
    var escaped = false, next;
    while (next = stream.next()) {
      if (next == '"' && !escaped) { state.tokenize = base; break; }
      escaped = !escaped && next == "\\";
    }
    return "string";
  }

  function inComment(stream, state) {
    var next, last;
    while (next = stream.next()) {
      if (next == "#" && last == "|") { state.tokenize = base; break; }
      last = next;
    }
    type = "ws";
    return "comment";
  }

  return {
    startState: function () {
      return {ctx: {prev: null, start: 0, indentTo: 0}, lastType: null, tokenize: base};
    },

    token: function (stream, state) {
      if (stream.sol() && typeof state.ctx.indentTo != "number")
        state.ctx.indentTo = state.ctx.start + 1;

      type = null;
      var style = state.tokenize(stream, state);
      if (type != "ws") {
        if (state.ctx.indentTo == null) {
          if (type == "symbol" && assumeBody.test(stream.current()))
            state.ctx.indentTo = state.ctx.start + config.indentUnit;
          else
            state.ctx.indentTo = "next";
        } else if (state.ctx.indentTo == "next") {
          state.ctx.indentTo = stream.column();
        }
        state.lastType = type;
      }
      if (type == "open") state.ctx = {prev: state.ctx, start: stream.column(), indentTo: null};
      else if (type == "close") state.ctx = state.ctx.prev || state.ctx;
      return style;
    },

    indent: function (state, _textAfter) {
      var i = state.ctx.indentTo;
      return typeof i == "number" ? i : state.ctx.start + 1;
    },

    closeBrackets: {pairs: "()[]{}\"\""},
    lineComment: ";;",
    blockCommentStart: "#|",
    blockCommentEnd: "|#"
  };
});

CodeMirror.defineMIME("text/x-common-lisp", "commonlisp");

});
<commit_msg>[commonlisp mode] Fix wrong bracket<commit_after>// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE

(function(mod) {
  if (typeof exports == "object" && typeof module == "object") // CommonJS
    mod(require("../../lib/codemirror"));
  else if (typeof define == "function" && define.amd) // AMD
    define(["../../lib/codemirror"], mod);
  else // Plain browser env
    mod(CodeMirror);
})(function(CodeMirror) {
"use strict";

CodeMirror.defineMode("commonlisp", function (config) {
  var specialForm = /^(block|let*|return-from|catch|load-time-value|setq|eval-when|locally|symbol-macrolet|flet|macrolet|tagbody|function|multiple-value-call|the|go|multiple-value-prog1|throw|if|progn|unwind-protect|labels|progv|let|quote)$/;
  var assumeBody = /^with|^def|^do|^prog|case$|^cond$|bind$|when$|unless$/;
  var numLiteral = /^(?:[+\-]?(?:\d+|\d*\.\d+)(?:[efd][+\-]?\d+)?|[+\-]?\d+(?:\/[+\-]?\d+)?|#b[+\-]?[01]+|#o[+\-]?[0-7]+|#x[+\-]?[\da-f]+)/;
  var symbol = /[^\s'`,@()\[\]";]/;
  var type;

  function readSym(stream) {
    var ch;
    while (ch = stream.next()) {
      if (ch == "\\") stream.next();
      else if (!symbol.test(ch)) { stream.backUp(1); break; }
    }
    return stream.current();
  }

  function base(stream, state) {
    if (stream.eatSpace()) {type = "ws"; return null;}
    if (stream.match(numLiteral)) return "number";
    var ch = stream.next();
    if (ch == "\\") ch = stream.next();

    if (ch == '"') return (state.tokenize = inString)(stream, state);
    else if (ch == "(") { type = "open"; return "bracket"; }
    else if (ch == ")" || ch == "]") { type = "close"; return "bracket"; }
    else if (ch == ";") { stream.skipToEnd(); type = "ws"; return "comment"; }
    else if (/['`,@]/.test(ch)) return null;
    else if (ch == "|") {
      if (stream.skipTo("|")) { stream.next(); return "symbol"; }
      else { stream.skipToEnd(); return "error"; }
    } else if (ch == "#") {
      var ch = stream.next();
      if (ch == "(") { type = "open"; return "bracket"; }
      else if (/[+\-=\.']/.test(ch)) return null;
      else if (/\d/.test(ch) && stream.match(/^\d*#/)) return null;
      else if (ch == "|") return (state.tokenize = inComment)(stream, state);
      else if (ch == ":") { readSym(stream); return "meta"; }
      else if (ch == "\\") { stream.next(); readSym(stream); return "string-2" }
      else return "error";
    } else {
      var name = readSym(stream);
      if (name == ".") return null;
      type = "symbol";
      if (name == "nil" || name == "t" || name.charAt(0) == ":") return "atom";
      if (state.lastType == "open" && (specialForm.test(name) || assumeBody.test(name))) return "keyword";
      if (name.charAt(0) == "&") return "variable-2";
      return "variable";
    }
  }

  function inString(stream, state) {
    var escaped = false, next;
    while (next = stream.next()) {
      if (next == '"' && !escaped) { state.tokenize = base; break; }
      escaped = !escaped && next == "\\";
    }
    return "string";
  }

  function inComment(stream, state) {
    var next, last;
    while (next = stream.next()) {
      if (next == "#" && last == "|") { state.tokenize = base; break; }
      last = next;
    }
    type = "ws";
    return "comment";
  }

  return {
    startState: function () {
      return {ctx: {prev: null, start: 0, indentTo: 0}, lastType: null, tokenize: base};
    },

    token: function (stream, state) {
      if (stream.sol() && typeof state.ctx.indentTo != "number")
        state.ctx.indentTo = state.ctx.start + 1;

      type = null;
      var style = state.tokenize(stream, state);
      if (type != "ws") {
        if (state.ctx.indentTo == null) {
          if (type == "symbol" && assumeBody.test(stream.current()))
            state.ctx.indentTo = state.ctx.start + config.indentUnit;
          else
            state.ctx.indentTo = "next";
        } else if (state.ctx.indentTo == "next") {
          state.ctx.indentTo = stream.column();
        }
        state.lastType = type;
      }
      if (type == "open") state.ctx = {prev: state.ctx, start: stream.column(), indentTo: null};
      else if (type == "close") state.ctx = state.ctx.prev || state.ctx;
      return style;
    },

    indent: function (state, _textAfter) {
      var i = state.ctx.indentTo;
      return typeof i == "number" ? i : state.ctx.start + 1;
    },

    closeBrackets: {pairs: "()[]{}\"\""},
    lineComment: ";;",
    blockCommentStart: "#|",
    blockCommentEnd: "|#"
  };
});

CodeMirror.defineMIME("text/x-common-lisp", "commonlisp");

});
<|endoftext|>


<commit_before>/**
 * A Backbone.View for Spytext fields.
 *
 * @module spytext/field
 */

var Snapback = require('./snapback');

var selectron = require('./selectron');
var commands = require('./commands');

var app = require('ridge');

/**
 * @readonly
 */
var blockTags = [ 'P', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'LI' ];

module.exports = require('ridge/view').extend({
	/**
	 * @lends SpytextField.prototype
	 */
	events: _.extend({
		focus: 'activate',

		blur: 'deactivate',
	}, require('./events')),

	/**
	 * @constructs
	 * @augments Backbone.View
	 */
	initialize: function() {
		var _view = this;
		this.$el.addClass('spytext-field').attr('contentEditable', 'true');

		commands.deleteEmptyTextNodes(this.el);
		commands.deleteEmptyElements(this.el);
		if($(this.el).is(':empty')) {
			$(this.el).append('
');
		}
		commands.setBR(_.toArray(this.el.children));

		this.originalValue = this.el.innerHTML;

		if(!app.spytextToolbar) {
			app.spytextToolbar = new app.views.SpytextToolbar();
			$(document.body).append(app.spytextToolbar.el);
		}

		this.toolbar = app.spytextToolbar;

		this.snapback = new Snapback(this.el);
	},

	/**
	 * Activates the current field.
	 */
	activate: function() {
		var _field = this;

		// enable snapback, ie. tell the snapback instance's
		// mutationObserver to observer
		_field.snapback.enable();

		// toggle the toolbar, passing the current field to it
		_field.toolbar.toggle(_field);

		selectron.setElement(_field.el);

		// i think the timeout is because of the range not being initialized
		// so snapback.storePositions/selectron produces an error
		setTimeout(function() {
			_field.snapback.storePositions();

			// this is to capture events when mousedown on
			// fields element but mouseup outside
			$(document).on('mousedown', function(e) {
				clearTimeout(this.timeout);
				_field.snapback.register();
			});
			$(document).on('mouseup', function(e) {
				setTimeout(function() {
					selectron.normalize();
					selectron.update();
					_field.toolbar.setActiveStyles();
					_field.snapback.storePositions();
				});
			});
		});
	},

	/**
	 * Deactivates the current field.
	 */
	deactivate: function() {
		// register mutations (if any) as an undo before deactivating
		this.snapback.register();

		// disable snapback, ie. disconnect the mutationObserver
		this.snapback.disable();

		// deactivate toolbar
		this.toolbar.toggle();

		// stop listening to mouseup and mousedown on document
		$(document).off('mouseup');
		$(document).off('mousedown');
	},

	render: function() {
		if(!this.el.firstChild) {
			this.$el.append('

');
		}
	},

	/**
	 * Calls a command from module:spytext/commands
	 *
	 * @see module:spytext/commands
	 */
	command: function(command) {
		var field = this;

		// register mutations (if any) as undo before calling command
		// so that the command becomes it's own undo without merging
		// it with any previous mutations in the mutation array in snapback
		field.snapback.register();

		if(commands[command]) {
			// call the command
			commands[command].apply(null,  [ field.el ].concat(_.rest(arguments)));

			// normalize any text nodes in the field's element
			field.el.normalize();

			$(field.el).trigger('change');
			// unfortunately, we need to wrap the registation of a new Undo
			// in a timeout
			setTimeout(function(){
				// register the called command as an undo
				field.snapback.register();
				field.toolbar.setActiveStyles();
			});
		}
	},
});
<commit_msg>Removed app depencency (no global toolbar).<commit_after>/**
 * A Backbone.View for Spytext fields.
 *
 * @module spytext/field
 */

var Snapback = require('./snapback');
var SpytextToolbar = require('./toolbar');

var selectron = require('./selectron');
var commands = require('./commands');

/**
 * @readonly
 */
var blockTags = [ 'P', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'LI' ];

module.exports = require('ridge/view').extend({
	/**
	 * @lends SpytextField.prototype
	 */
	events: _.extend({
		focus: 'activate',

		blur: 'deactivate',
	}, require('./events')),

	/**
	 * @constructs
	 * @augments Backbone.View
	 */
	initialize: function() {
		var _view = this;
		this.$el.addClass('spytext-field').attr('contentEditable', 'true');

		commands.deleteEmptyTextNodes(this.el);
		commands.deleteEmptyElements(this.el);
		if($(this.el).is(':empty')) {
			$(this.el).append('
');
		}
		commands.setBR(_.toArray(this.el.children));

		this.originalValue = this.el.innerHTML;

		this.toolbar = new SpytextToolbar();

		$(document.body).append(this.toolbar.el);

		this.snapback = new Snapback(this.el);
	},

	/**
	 * Activates the current field.
	 */
	activate: function() {
		var _field = this;

		// enable snapback, ie. tell the snapback instance's
		// mutationObserver to observer
		_field.snapback.enable();

		// toggle the toolbar, passing the current field to it
		_field.toolbar.toggle(_field);

		selectron.setElement(_field.el);

		// i think the timeout is because of the range not being initialized
		// so snapback.storePositions/selectron produces an error
		setTimeout(function() {
			_field.snapback.storePositions();

			// this is to capture events when mousedown on
			// fields element but mouseup outside
			$(document).on('mousedown', function(e) {
				clearTimeout(this.timeout);
				_field.snapback.register();
			});
			$(document).on('mouseup', function(e) {
				setTimeout(function() {
					selectron.normalize();
					selectron.update();
					_field.toolbar.setActiveStyles();
					_field.snapback.storePositions();
				});
			});
		});
	},

	/**
	 * Deactivates the current field.
	 */
	deactivate: function() {
		// register mutations (if any) as an undo before deactivating
		this.snapback.register();

		// disable snapback, ie. disconnect the mutationObserver
		this.snapback.disable();

		// deactivate toolbar
		this.toolbar.toggle();

		// stop listening to mouseup and mousedown on document
		$(document).off('mouseup');
		$(document).off('mousedown');
	},

	render: function() {
		if(!this.el.firstChild) {
			this.$el.append('

');
		}
	},

	/**
	 * Calls a command from module:spytext/commands
	 *
	 * @see module:spytext/commands
	 */
	command: function(command) {
		var field = this;

		// register mutations (if any) as undo before calling command
		// so that the command becomes it's own undo without merging
		// it with any previous mutations in the mutation array in snapback
		field.snapback.register();

		if(commands[command]) {
			// call the command
			commands[command].apply(null,  [ field.el ].concat(_.rest(arguments)));

			// normalize any text nodes in the field's element
			field.el.normalize();

			$(field.el).trigger('change');
			// unfortunately, we need to wrap the registation of a new Undo
			// in a timeout
			setTimeout(function(){
				// register the called command as an undo
				field.snapback.register();
				field.toolbar.setActiveStyles();
			});
		}
	},
});
<|endoftext|>


<commit_before>CodeMirror.defineMode("commonlisp", function (config) {
  var assumeBody = /^with|^def|^do|^prog|case$|^cond$|bind$|when$|unless$/;
  var numLiteral = /^(?:[+\-]?(?:\d+|\d*\.\d+)(?:[efd][+\-]?\d+)?|[+\-]?\d+(?:\/[+\-]?\d+)?|#b[+\-]?[01]+|#o[+\-]?[0-7]+|#x[+\-]?[\da-f]+)/;
  var symbol = /[^\s'`,@()\[\]";]/;
  var type;

  function readSym(stream) {
    var ch;
    while (ch = stream.next()) {
      if (ch == "\\") stream.next();
      else if (!symbol.test(ch)) { stream.backUp(1); break; }
    }
    return stream.current();
  }

  function base(stream, state) {
    if (stream.eatSpace()) {type = "ws"; return null;}
    if (stream.match(numLiteral)) return "number";
    var ch = stream.next();
    if (ch == "\\") ch = stream.next();

    if (ch == '"') return (state.tokenize = inString)(stream, state);
    else if (ch == "(") { type = "open"; return "bracket"; }
    else if (ch == ")" || ch == "]") { type = "close"; return "bracket"; }
    else if (ch == ";") { stream.skipToEnd(); type = "ws"; return "comment"; }
    else if (/['`,@]/.test(ch)) return null;
    else if (ch == "|") {
      if (stream.skipTo("|")) { stream.next(); return "symbol"; }
      else { stream.skipToEnd(); return "error"; }
    } else if (ch == "#") {
      if (stream.eat("[")) { type = "open"; return "bracket"; }
      else if (stream.eat(/[+\-=\.]/)) return null;
      else if (stream.match(/^\d+#/)) return null;
      else if (stream.eat("|")) return (state.tokenize = inComment)(stream, state);
      else if (stream.eat(":")) { readSym(stream); return "meta"; }
      else { stream.next(); return "error"; }
    } else {
      var name = readSym(stream);
      if (name == ".") return null;
      type = "symbol";
      if (name == "nil" || name == "t") return "atom";
      if (name.charAt(0) == ":") return "keyword";
      return "variable";
    }
  }

  function inString(stream, state) {
    var escaped = false, next;
    while (next = stream.next()) {
      if (next == '"' && !escaped) { state.tokenize = base; break; }
      escaped = !escaped && next == "\\";
    }
    return "string";
  }

  function inComment(stream, state) {
    var next, last;
    while (next = stream.next()) {
      if (next == "#" && last == "|") { state.tokenize = base; break; }
      last = next;
    }
    type = "ws";
    return "comment";
  }

  return {
    startState: function () {
      return {ctx: {prev: null, start: 0, indentTo: 0}, tokenize: base};
    },

    token: function (stream, state) {
      if (stream.sol() && typeof state.ctx.indentTo != "number")
        state.ctx.indentTo = state.ctx.start + 1;

      type = null;
      var style = state.tokenize(stream, state);
      if (type != "ws") {
        if (state.ctx.indentTo == null) {
          if (type == "symbol" && assumeBody.test(stream.current()))
            state.ctx.indentTo = state.ctx.start + config.indentUnit;
          else
            state.ctx.indentTo = "next";
        } else if (state.ctx.indentTo == "next") {
          state.ctx.indentTo = stream.column();
        }
      }
      if (type == "open") state.ctx = {prev: state.ctx, start: stream.column(), indentTo: null};
      else if (type == "close") state.ctx = state.ctx.prev;
      return style;
    },

    indent: function (state, textAfter) {
      var i = state.ctx.indentTo;
      return typeof i == "number" ? i : state.ctx.start + 1;
    }
  };
});

CodeMirror.defineMIME("text/x-common-lisp", "commonlisp");
<commit_msg>[commonlisp mode] Various small fixes<commit_after>CodeMirror.defineMode("commonlisp", function (config) {
  var assumeBody = /^with|^def|^do|^prog|case$|^cond$|bind$|when$|unless$/;
  var numLiteral = /^(?:[+\-]?(?:\d+|\d*\.\d+)(?:[efd][+\-]?\d+)?|[+\-]?\d+(?:\/[+\-]?\d+)?|#b[+\-]?[01]+|#o[+\-]?[0-7]+|#x[+\-]?[\da-f]+)/;
  var symbol = /[^\s'`,@()\[\]";]/;
  var type;

  function readSym(stream) {
    var ch;
    while (ch = stream.next()) {
      if (ch == "\\") stream.next();
      else if (!symbol.test(ch)) { stream.backUp(1); break; }
    }
    return stream.current();
  }

  function base(stream, state) {
    if (stream.eatSpace()) {type = "ws"; return null;}
    if (stream.match(numLiteral)) return "number";
    var ch = stream.next();
    if (ch == "\\") ch = stream.next();

    if (ch == '"') return (state.tokenize = inString)(stream, state);
    else if (ch == "(") { type = "open"; return "bracket"; }
    else if (ch == ")" || ch == "]") { type = "close"; return "bracket"; }
    else if (ch == ";") { stream.skipToEnd(); type = "ws"; return "comment"; }
    else if (/['`,@]/.test(ch)) return null;
    else if (ch == "|") {
      if (stream.skipTo("|")) { stream.next(); return "symbol"; }
      else { stream.skipToEnd(); return "error"; }
    } else if (ch == "#") {
      var ch = stream.next();
      if (ch == "[") { type = "open"; return "bracket"; }
      else if (/[+\-=\.']/.test(ch)) return null;
      else if (/\d/.test(ch) && stream.match(/^\d*#/)) return null;
      else if (ch == "|") return (state.tokenize = inComment)(stream, state);
      else if (ch == ":") { readSym(stream); return "meta"; }
      else return "error";
    } else {
      var name = readSym(stream);
      if (name == ".") return null;
      type = "symbol";
      if (name == "nil" || name == "t") return "atom";
      if (name.charAt(0) == ":") return "keyword";
      if (name.charAt(0) == "&") return "variable-2";
      return "variable";
    }
  }

  function inString(stream, state) {
    var escaped = false, next;
    while (next = stream.next()) {
      if (next == '"' && !escaped) { state.tokenize = base; break; }
      escaped = !escaped && next == "\\";
    }
    return "string";
  }

  function inComment(stream, state) {
    var next, last;
    while (next = stream.next()) {
      if (next == "#" && last == "|") { state.tokenize = base; break; }
      last = next;
    }
    type = "ws";
    return "comment";
  }

  return {
    startState: function () {
      return {ctx: {prev: null, start: 0, indentTo: 0}, tokenize: base};
    },

    token: function (stream, state) {
      if (stream.sol() && typeof state.ctx.indentTo != "number")
        state.ctx.indentTo = state.ctx.start + 1;

      type = null;
      var style = state.tokenize(stream, state);
      if (type != "ws") {
        if (state.ctx.indentTo == null) {
          if (type == "symbol" && assumeBody.test(stream.current()))
            state.ctx.indentTo = state.ctx.start + config.indentUnit;
          else
            state.ctx.indentTo = "next";
        } else if (state.ctx.indentTo == "next") {
          state.ctx.indentTo = stream.column();
        }
      }
      if (type == "open") state.ctx = {prev: state.ctx, start: stream.column(), indentTo: null};
      else if (type == "close") state.ctx = state.ctx.prev;
      return style;
    },

    indent: function (state, textAfter) {
      var i = state.ctx.indentTo;
      return typeof i == "number" ? i : state.ctx.start + 1;
    }
  };
});

CodeMirror.defineMIME("text/x-common-lisp", "commonlisp");
<|endoftext|>


<commit_before>'use strict';

var linspace = require( 'compute-linspace' );
var zeta = require( './../lib' );

var s;
var v;
var i;

s = linspace( -50.0, 50.0, 200 );
for ( i = 0; i < s.length; i++ ) {
	v = zeta( s[ i ] );
	console.log( 's: %d, ζ(s): %d', s[ i ], v );
}
<commit_msg>Fix require statement for linspace<commit_after>'use strict';

var linspace = require( '@stdlib/math/generics/utils/linspace' );
var zeta = require( './../lib' );

var s;
var v;
var i;

s = linspace( -50.0, 50.0, 200 );
for ( i = 0; i < s.length; i++ ) {
	v = zeta( s[ i ] );
	console.log( 's: %d, ζ(s): %d', s[ i ], v );
}
<|endoftext|>


<commit_before>import React from 'react'

const PATH_STYLE = {
  fill: 'none',
  fillOpacity: '1',
  stroke: '#ff0000',
  strokeWidth: '1',
  strokeLinecap: 'butt',
  strokeLinejoin: 'round',
  strokeMiterlimit: '4',
  strokeDasharray: 'none',
  strokeDashoffset: '0',
  strokeOpacity: '1',
}

const map = (value, istart, istop, ostart, ostop) => (
  ostart + (ostop - ostart) * ((value - istart) / (istop - istart))
)

const pathD = values => {
  let variationValue = 0
  const variations = values.map(val => (
    variationValue = variationValue + val
  ))
  const max = Math.max(...variations)
  const min = Math.min(...variations)
  return variations.reduce((d, val, i) => {
    const y = map(val, min, max, 125, 500 - 125)
    if (i === 0) {
      return `M ${500 - 10 * i} ${y}`
    }
    return `${d} L ${500 - 10 * i} ${y}`
  }, '')
}

const Graph = props => (

    <svg
      width='100%'
      height='100%'
      preserveAspectRatio='none'
      viewBox='0 0 500 500'
    >
      <path
        style={PATH_STYLE}
        d={pathD(props.betHistory)}
      />
    </svg>

)

export default Graph
<commit_msg>Graph tweaks<commit_after>import React from 'react'

const PATH_STYLE = {
  fill: 'none',
  fillOpacity: '1',
  stroke: '#ff0000',
  strokeWidth: '1',
  strokeLinecap: 'butt',
  strokeLinejoin: 'round',
  strokeMiterlimit: '4',
  strokeDasharray: 'none',
  strokeDashoffset: '0',
  strokeOpacity: '1',
}

const map = (value, istart, istop, ostart, ostop) => (
  ostart + (ostop - ostart) * ((value - istart) / (istop - istart))
)

const pathD = values => {
  let variationValue = 0
  const variations = values.map(val => (
    variationValue = variationValue + val
  ))
  const max = Math.max(...variations)
  const min = Math.min(...variations)
  return variations.reduce((d, val, i) => {
    const y = map(val, min, max, 125, 500 - 125)
    if (i === 0) {
      return `M ${500} ${y}`
    }
    return `${d} L ${500 - 20 * i} ${y}`
  }, '')
}

const Graph = props => (

    <svg
      width='100%'
      height='100%'
      preserveAspectRatio='none'
      viewBox='0 0 500 500'
    >
      <path
        style={PATH_STYLE}
        d={pathD(props.betHistory)}
      />
    </svg>

)

export default Graph
<|endoftext|>


<commit_before>import { FMRS_MA_2018 } from '../../../data/state/massachusetts/2018/FMRS_MA_2018';

/** Get maximum benefit/subsidy amount for client from Section 8 Project-Based
* Voucher program. Please allow the client to put in their own subsidy amount
* if needed since custom amounts are totally a thing that happen (like the PHA
* requesting a standard that is higher than 110%). An accurate amount is important
* when calculating eligibility/amounts from other benefit programs.
* Once you're enrolled in the program, which our interface is
* currently assuming to be the case, you stay in it. There are
* reasons that you leave it, but we have to discuss with the
* case managers what they want to do about those. They're weird.
* There will be extra info if subsidy amount is $0, though.
*
* @function
* @since 09/2017
*
* @see trello: https://trello.com/c/EIt2BCMQ/53-housing-choice-voucher-section-8-pseudocode-doc
* @see docs: https://docs.google.com/spreadsheets/d/14FFcrEwZVTJDc00X7V4XkicE3NYVVF0lijV1jMLe--Y/edit#gid=1209051854
* @see docs: https://docs.google.com/spreadsheets/d/14FFcrEwZVTJDc00X7V4XkicE3NYVVF0lijV1jMLe--Y/edit#gid=1209051854 (recommended by Kristin, Project Hope staff)
* @see gathered info: https://docs.google.com/spreadsheets/d/14FFcrEwZVTJDc00X7V4XkicE3NYVVF0lijV1jMLe--Y/edit#gid=1209051854
* @see codepen test: https://codepen.io/knod/pen/oeOpRz?editors=0010
*
* @todo Find out how close to 0 the benefit amount needs
* to be in order for the client to be warned.
*/
var getHousingEligibility = function ( client ) {
	/** @todo Maybe allow client to put in a custom rent amount, but
	* should be warned that this amount may not be accurate either
	* because in some cases calculations and estimates have to be made
	* for essential utilitie allowances if utilities aren't included in
	* the rent amount. Maybe a custom subsidy amount would be better?
	*/

    if ( typeof client.customRentSubsidyAmount === 'number' ) {
    	return subsidyResult( client.customRentSubsidyAmount );
    }

    // (24 CFR 5.611 https://www.ecfr.gov/cgi-bin/text-idx?SID=51891282d9b5314112b0b2462cb22681&mc=true&node=se24.1.5_1611&rgn=div8, https://www.hudexchange.info/resources/documents/incomeresidentrentcalc.pdf)
    var adjusted 	= (30/100) * client.householdMonthlyAdjustedIncome,
    // (24CFR5.609 (linked from http://www.tacinc.org/media/58886/S8MS%20Full%20Book.pdf) https://www.hudexchange.info/resources/documents/incomeresidentrentcalc.pdf)
    	gross 		= 0.1 * client.householdMonthlyGrossIncome,
	// welfare rent (Does MA have welfare rent? If so, how is it calculated?
	// Does the client know the amount?)
    	welfareRent = client.welfareRent || 0,
	// Possibly also the public housing agency's own minimum rent, which doesn't
	// always exist, can be different amounts, and can sometimes we waived (pg 63 of "Book")
		PHAMinRent 	= client.PHAMinRent || 0;

	// TTP = total tenant payment
    var minTTP = Math.max( adjusted, gross, welfareRent, PHAMinRent ),
    	estimatedRent = FMRS_MA_2018[ client.areaOfResidence ][ client.housing.numBedrooms ],
	// The maximum amount a PHA (public housing agency) can give to client has a range
	// of 90% to 110% depending on how it choose to do things.
	// We're currently going to assume the minimum of that range. That is, we're going
	// to assume a PHA with a standard that sets their maximum subsidy at 90%. In this
	// way if we mislead the client, it'll at least be in a cautious direction. Maybe
	// allow the client to override that value if they want.
		maxSubsidyAllowedMin = estimatedRent * 0.9,
	// Actual subsidy takes into account what the client can pay
		subsidy = maxSubsidyAllowedMin - minTTP;

	var result = subsidyResult( subsidy );

	return result;
}

var subsidyResult = function ( subsidyAmount ) {
	/** @todo Include a warning somewhere about items
	* that are uncertain. Also, maybe provide option to
	* give even more detailed info, like that particular
	* PHA's min rent amount, the PHA's percent for their
	* standard, or just the PHA's flat subsidy amount for
	* that apartment (before other things like minTTP are
	* factored in). (This for all programs ideally. Of
	* course this whole todo is a dream goal...)
	*/
	var result = { result: 'good', details: 'All good!', benefitValue: Math.max( 0, Math.round( subsidyAmount ) ) };

	if ( subsidyAmount <= 0 ) {
		result.result 	= 'information';
		/** @todo Check accuracy of language used. */
		result.details 	= 'Your PHA must allow you the option of continuing in the HCV program for six more months. Without selecting to continue, you will be unenrolled.';
	} else if ( subsidyAmount <= 50 ) {
		result.result 	= 'information';
		/** @todo Give more specific message about which limit is getting hit. Not sure how to judge which limit is the one that's getting close, though. */
		result.details 	= 'Your income amount means your subsidy is close to $0. When it gets to $0 you might be unenrolled from the HCV program, but you should be able to choose an option to extend your enrollment.';
  }

	return result;
};  // End subsidyResult()

export { getHousingEligibility };
<commit_msg>Adds provision if input fields are not filled in<commit_after>import { FMRS_MA_2018 } from '../../../data/state/massachusetts/2018/FMRS_MA_2018';

/** Get maximum benefit/subsidy amount for client from Section 8 Project-Based
* Voucher program. Please allow the client to put in their own subsidy amount
* if needed since custom amounts are totally a thing that happen (like the PHA
* requesting a standard that is higher than 110%). An accurate amount is important
* when calculating eligibility/amounts from other benefit programs.
* Once you're enrolled in the program, which our interface is
* currently assuming to be the case, you stay in it. There are
* reasons that you leave it, but we have to discuss with the
* case managers what they want to do about those. They're weird.
* There will be extra info if subsidy amount is $0, though.
*
* @function
* @since 09/2017
*
* @see trello: https://trello.com/c/EIt2BCMQ/53-housing-choice-voucher-section-8-pseudocode-doc
* @see docs: https://docs.google.com/spreadsheets/d/14FFcrEwZVTJDc00X7V4XkicE3NYVVF0lijV1jMLe--Y/edit#gid=1209051854
* @see docs: https://docs.google.com/spreadsheets/d/14FFcrEwZVTJDc00X7V4XkicE3NYVVF0lijV1jMLe--Y/edit#gid=1209051854 (recommended by Kristin, Project Hope staff)
* @see gathered info: https://docs.google.com/spreadsheets/d/14FFcrEwZVTJDc00X7V4XkicE3NYVVF0lijV1jMLe--Y/edit#gid=1209051854
* @see codepen test: https://codepen.io/knod/pen/oeOpRz?editors=0010
*
* @todo Find out how close to 0 the benefit amount needs
* to be in order for the client to be warned.
*/
var getHousingEligibility = function ( client ) {
	/** @todo Maybe allow client to put in a custom rent amount, but
	* should be warned that this amount may not be accurate either
	* because in some cases calculations and estimates have to be made
	* for essential utilitie allowances if utilities aren't included in
	* the rent amount. Maybe a custom subsidy amount would be better?
	*/

	// Send it right back if it's missing input values
	var props = propsNeeded( client )
	if ( props.length ) {
		var details = "Not enough information. These fields need to be filled in: ";
		for (let propi = 0; propi < props.length; propi++) {
			let prop = props[ propi ];
			details += prop;
			if ( propi < props.length - 1 ) { details += ", "; }
			else { details += "."; }
		};
		return { result: "information", details: details }
	}

	// Not sure about this part
    if ( typeof client.customRentSubsidyAmount === 'number' ) {
    	return subsidyResult( client.customRentSubsidyAmount );
    }

    // (24 CFR 5.611 https://www.ecfr.gov/cgi-bin/text-idx?SID=51891282d9b5314112b0b2462cb22681&mc=true&node=se24.1.5_1611&rgn=div8, https://www.hudexchange.info/resources/documents/incomeresidentrentcalc.pdf)
    var adjusted 	= (30/100) * client.householdMonthlyAdjustedIncome,
    // (24CFR5.609 (linked from http://www.tacinc.org/media/58886/S8MS%20Full%20Book.pdf) https://www.hudexchange.info/resources/documents/incomeresidentrentcalc.pdf)
    	gross 		= 0.1 * client.householdMonthlyGrossIncome,
	// welfare rent (Does MA have welfare rent? If so, how is it calculated?
	// Does the client know the amount?)
    	welfareRent = client.welfareRent || 0,
	// Possibly also the public housing agency's own minimum rent, which doesn't
	// always exist, can be different amounts, and can sometimes we waived (pg 63 of "Book")
		PHAMinRent 	= client.PHAMinRent || 0;

	// TTP = total tenant payment
    var minTTP = Math.max( adjusted, gross, welfareRent, PHAMinRent ),
    	estimatedRent = FMRS_MA_2018[ client.areaOfResidence ][ client.numberOfBedrooms ],
	// The maximum amount a PHA (public housing agency) can give to client has a range
	// of 90% to 110% depending on how it choose to do things.
	// We're currently going to assume the minimum of that range. That is, we're going
	// to assume a PHA with a standard that sets their maximum subsidy at 90%. In this
	// way if we mislead the client, it'll at least be in a cautious direction. Maybe
	// allow the client to override that value if they want.
		maxSubsidyAllowedMin = estimatedRent * 0.9,
	// Actual subsidy takes into account what the client can pay
		subsidy = maxSubsidyAllowedMin - minTTP;

	var result = subsidyResult( subsidy );

	return result;
}

var subsidyResult = function ( subsidyAmount ) {
	/** @todo Include a warning somewhere about items
	* that are uncertain. Also, maybe provide option to
	* give even more detailed info, like that particular
	* PHA's min rent amount, the PHA's percent for their
	* standard, or just the PHA's flat subsidy amount for
	* that apartment (before other things like minTTP are
	* factored in). (This for all programs ideally. Of
	* course this whole todo is a dream goal...)
	*/
	var result = { result: 'good', details: 'All good!', benefitValue: Math.max( 0, Math.round( subsidyAmount ) ) };

	if ( subsidyAmount <= 0 ) {
		result.result 	= 'information';
		/** @todo Check accuracy of language used. */
		result.details 	= 'Your PHA must allow you the option of continuing in the HCV program for six more months. Without selecting to continue, you will be unenrolled.';
	} else if ( subsidyAmount <= 50 ) {
		result.result 	= 'information';
		/** @todo Give more specific message about which limit is getting hit. Not sure how to judge which limit is the one that's getting close, though. */
		result.details 	= 'Your income amount means your subsidy is close to $0. When it gets to $0 you might be unenrolled from the HCV program, but you should be able to choose an option to extend your enrollment.';
  }

	return result;
};  // End subsidyResult()

var requiredProps = [
	"householdMonthlyAdjustedIncome"
	"householdMonthlyGrossIncome"
	"areaOfResidence"
	"numberOfBedrooms"
];

var propsNeeded = function ( client ) {

	var missingProps = [];

	for ( let propi = 0; propi < requiredProps.length; propi++ ) {
		let key = requiredProps[ propi ];
		if ( client[ key ] === undefined ) { missingProps.push( key ); }
	}

	return missingProps;
};  // End propsNeeded()

export { getHousingEligibility };
<|endoftext|>


<commit_before>// Copyright 2018-2021, University of Colorado Boulder

/**
 * QUnit tests for GrabDragInteraction
 *
 * @author Michael Kauzmann (PhET Interactive Simulations)
 */

import Display from '../../../scenery/js/display/Display.js';
import KeyboardDragListener from '../../../scenery/js/listeners/KeyboardDragListener.js';
import Node from '../../../scenery/js/nodes/Node.js';
import Rectangle from '../../../scenery/js/nodes/Rectangle.js';
import Tandem from '../../../tandem/js/Tandem.js';
import GrabDragInteraction from './GrabDragInteraction.js';

// constants
const thingString = 'thing';
const movableString = 'movable';

QUnit.module( 'GrabDragInteraction' );

QUnit.test( 'GrabDragInteraction defaults', assert => {

  assert.ok( true, 'first test' );

  const rootNode = new Node( { tagName: 'div' } );
  const display = new Display( rootNode ); // eslint-disable-line
  display.initializeEvents();
  document.body.appendChild( display.domElement );

  phet = phet || {}; // eslint-disable-line no-global-assign
  phet.joist = phet.joist || {};
  phet.joist.sim = phet.joist.sim || { utteranceQueue: display.utteranceQueue }; // stub utteranceQueue global

  // GrabDragInteraction requires a sim
  phet.joist.sim.supportsGestureDescription = phet.joist.sim.supportsGestureDescription || false;

  const a = new Rectangle( 0, 0, 5, 5 );

  rootNode.addChild( a );

  const keyboardDragListener = new KeyboardDragListener();
  const interaction = new GrabDragInteraction( a, keyboardDragListener, {
    tandem: Tandem.ROOT_TEST.createTandem( 'myGrabDragInteraction' ),
    objectToGrabString: thingString
  } );

  const testDefaultGrabbable = () => {

    assert.ok( interaction.grabbable, 'default to grabbable' );
    assert.ok( a.tagName.toUpperCase() === 'BUTTON', 'grabbable defaults to button' );
    assert.ok( a.ariaRole === null, 'no role for grabbable' );
    assert.ok( a.ariaLabel.indexOf( thingString ) >= 0, 'ariaLabel should include thing string for grabbable' );

    const aElement = a.pdomInstances[ 0 ].peer.primarySibling;
    assert.ok( aElement.tagName === 'BUTTON', 'grabbable defaults to button html element.' );
  };

  testDefaultGrabbable();

  a.pdomInstances[ 0 ].peer.primarySibling.click();

  const testDefaultDraggable = () => {

    assert.ok( !interaction.grabbable, 'should be draggable after click draggable' );
    assert.ok( a.tagName.toUpperCase() === 'DIV', 'draggable defaults to div' );
    assert.ok( a.ariaRole === 'application', 'draggable gets application role' );
    assert.ok( a.ariaLabel.indexOf( thingString ) >= 0, 'ariaLabel should include thing string' );
    assert.ok( a.ariaLabel === a.innerContent, 'ariaLabel should include thing string' );

    const aElement = a.pdomInstances[ 0 ].peer.primarySibling;
    assert.ok( aElement.tagName === 'DIV', 'draggable defaults to div html element.' );
    assert.ok( aElement.getAttribute( 'aria-roledescription' ) === movableString, 'aria role description should describe that it is movable by default' );
    assert.ok( aElement.innerHTML === a.ariaLabel, 'element innerHTML should be same as model label' );
    assert.ok( aElement.getAttribute( 'aria-label' ) === a.ariaLabel, 'element innerHTML should be same as model label' );
  };

  testDefaultDraggable();

  a.pdomInstances[ 0 ].peer.primarySibling.blur();

  testDefaultGrabbable();

  display.dispose();
} );<commit_msg>remove unneeded global stub, https://github.com/phetsims/utterance-queue/issues/13<commit_after>// Copyright 2018-2021, University of Colorado Boulder

/**
 * QUnit tests for GrabDragInteraction
 *
 * @author Michael Kauzmann (PhET Interactive Simulations)
 */

import Display from '../../../scenery/js/display/Display.js';
import KeyboardDragListener from '../../../scenery/js/listeners/KeyboardDragListener.js';
import Node from '../../../scenery/js/nodes/Node.js';
import Rectangle from '../../../scenery/js/nodes/Rectangle.js';
import Tandem from '../../../tandem/js/Tandem.js';
import GrabDragInteraction from './GrabDragInteraction.js';

// constants
const thingString = 'thing';
const movableString = 'movable';

QUnit.module( 'GrabDragInteraction' );

QUnit.test( 'GrabDragInteraction defaults', assert => {

  assert.ok( true, 'first test' );

  const rootNode = new Node( { tagName: 'div' } );
  const display = new Display( rootNode ); // eslint-disable-line
  display.initializeEvents();
  document.body.appendChild( display.domElement );

  phet = phet || {}; // eslint-disable-line no-global-assign
  phet.joist = phet.joist || {};
  phet.joist.sim = phet.joist.sim || {};

  // GrabDragInteraction requires a sim
  phet.joist.sim.supportsGestureDescription = phet.joist.sim.supportsGestureDescription || false;

  const a = new Rectangle( 0, 0, 5, 5 );

  rootNode.addChild( a );

  const keyboardDragListener = new KeyboardDragListener();
  const interaction = new GrabDragInteraction( a, keyboardDragListener, {
    tandem: Tandem.ROOT_TEST.createTandem( 'myGrabDragInteraction' ),
    objectToGrabString: thingString
  } );

  const testDefaultGrabbable = () => {

    assert.ok( interaction.grabbable, 'default to grabbable' );
    assert.ok( a.tagName.toUpperCase() === 'BUTTON', 'grabbable defaults to button' );
    assert.ok( a.ariaRole === null, 'no role for grabbable' );
    assert.ok( a.ariaLabel.indexOf( thingString ) >= 0, 'ariaLabel should include thing string for grabbable' );

    const aElement = a.pdomInstances[ 0 ].peer.primarySibling;
    assert.ok( aElement.tagName === 'BUTTON', 'grabbable defaults to button html element.' );
  };

  testDefaultGrabbable();

  a.pdomInstances[ 0 ].peer.primarySibling.click();

  const testDefaultDraggable = () => {

    assert.ok( !interaction.grabbable, 'should be draggable after click draggable' );
    assert.ok( a.tagName.toUpperCase() === 'DIV', 'draggable defaults to div' );
    assert.ok( a.ariaRole === 'application', 'draggable gets application role' );
    assert.ok( a.ariaLabel.indexOf( thingString ) >= 0, 'ariaLabel should include thing string' );
    assert.ok( a.ariaLabel === a.innerContent, 'ariaLabel should include thing string' );

    const aElement = a.pdomInstances[ 0 ].peer.primarySibling;
    assert.ok( aElement.tagName === 'DIV', 'draggable defaults to div html element.' );
    assert.ok( aElement.getAttribute( 'aria-roledescription' ) === movableString, 'aria role description should describe that it is movable by default' );
    assert.ok( aElement.innerHTML === a.ariaLabel, 'element innerHTML should be same as model label' );
    assert.ok( aElement.getAttribute( 'aria-label' ) === a.ariaLabel, 'element innerHTML should be same as model label' );
  };

  testDefaultDraggable();

  a.pdomInstances[ 0 ].peer.primarySibling.blur();

  testDefaultGrabbable();

  display.dispose();
} );<|endoftext|>


<commit_before>import React from 'react';
import autoBind from 'react-autobind';
import alertify from 'alertifyjs';
import Dropzone from 'react-dropzone';
import TextBox from 'js/components/common/textBox';
import {actions} from '../../actions';
import {bem} from 'js/bem';
import {ASSET_FILE_TYPES} from '../../constants';
import {renderLoading} from 'js/components/modalForms/modalHelpers';

/**
 * @prop {object} asset
 *
 * Modal for uploading form media
 */
class FormMedia extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      uploadedAssets: [],
      fieldsErrors: {},
      inputURL: '',
      // to show loading icon instead of nothing on first load
      isInitialised: false,
      // to show loading icon while uploading any file
      isUploadFilePending: false,
      isUploadURLPending: false
    };

    autoBind(this);
  }

  /*
   * setup
   */

  componentDidMount() {
    actions.media.loadMedia(this.props.asset.uid);

    actions.media.loadMedia.completed.listen(this.onGetMediaCompleted);
    actions.media.uploadMedia.failed.listen(this.onUploadFailed);
  }

  /*
   * action listeners
   */

  onGetMediaCompleted(uploadedAssets) {
    this.setState({
      uploadedAssets: uploadedAssets.results,
      isUploadFilePending: false,
      isUploadURLPending: false,
      isInitialised: true,
    });
  }

  onUploadFailed(response) {
    this.setState({
      fieldsErrors: response.responseJSON,
      isUploadFilePending: false,
      isUploadURLPending: false
    });
  }

  /*
   * Utilities
   */

  toBase64(file) {
    return new Promise(function(resolve, reject) {
      var reader = new FileReader();
      reader.readAsDataURL(file);
      reader.onload = function() {
          return resolve(reader.result);
      };
      reader.onerror = function(error) {
          return reject(error);
      };
    });
  }

  uploadMedia(formMediaJSON) {
    // Reset error message before uploading again
    this.setState({fieldsErrors: {}});
    actions.media.uploadMedia(this.props.asset.uid, formMediaJSON);
  }

  /*
   * DOM listeners
   */

  onFileDrop(files) {
    if (files.length >= 1) {
      this.setState({isUploadFilePending: true});

      files.forEach(async (file) => {
        var base64File = await this.toBase64(file);

        this.uploadMedia({
	      description: 'default',
          file_type: ASSET_FILE_TYPES.form_media.id,
          metadata: JSON.stringify({filename: file.name}),
	      base64Encoded: base64File
	    });
      });
    }
  }

  onInputURLChange(inputURL) {
    this.setState({inputURL: inputURL});
  }

  onSubmitURL() {
    var url = this.state.inputURL;

    if (url === '') {
      alertify.warning(t('URL is empty!'));
    } else {
      this.setState({
        isUploadURLPending: true,
        inputURL: ''
      });

      this.uploadMedia({
        description: 'default',
        file_type: ASSET_FILE_TYPES.form_media.id,
        metadata: JSON.stringify({redirect_url: url}),
      });
    }
  }

  onDeleteMedia(url) {
    actions.media.deleteMedia(this.props.asset.uid, url);
  }

  /*
   * rendering
   */

  renderButton() {
    const buttonClassNames = ['formBuilder-header__button', 'formBuilder-header__button--save'];
    if (this.state.isUploadURLPending) {
      buttonClassNames.push('formBuilder-header__button--savepending');
    }
    return (
      <button
        className={buttonClassNames.join(' ')}
        onClick={this.onSubmitURL}
      >

        {t('ADD')}
      </button>
    );
  }

  renderFileName(item){
    // Check if current item is uploaded via URL. `redirect_url` is the indicator
    var fileName = item.metadata.filename;
    if (item.metadata.redirect_url) {
      var url = item.metadata.redirect_url;
      if (url.length > 50) {
        // Shorten URL to exactly 50 chars
        var urlBack = url.slice(url.length - 24);
        var urlFront = url.replace('https://', '').replace('http://', '').substr(0, 25);
        fileName = urlFront + '…' + urlBack;
      } else {
        fileName = url;
      }
    }

    return (
      {fileName}
    );
  }

  renderIcon(item) {
    const iconClassNames = ['form-media__file-type', 'fa'];
    // Check if current item is uploaded via URL. `redirect_url` is the indicator
    if (item.metadata.redirect_url) {
      iconClassNames.push('fa-link');
    } else {
      iconClassNames.push('fa-file');
    }

    return (

    );
  }

  render() {
    return (
      <bem.FormView m='form-media' className='form-media'>

          {!this.state.isUploadFilePending &&
            <Dropzone
                onDrop={this.onFileDrop.bind(this)}
                className='dropzone-settings'
            >
              {this.state.fieldsErrors.base64Encoded &&
                <bem.FormView__cell m='error'>

{this.state.fieldsErrors.base64Encoded}

                </bem.FormView__cell>
              }

              {t(' Drag and drop files here')}

                {t('or')} {t('click here to browse')}

            </Dropzone>
          }

          {this.state.isUploadFilePending &&

              {renderLoading(t('Uploading file…'))}

          }

              {t('You can also add files using a URL')}

              <TextBox
                type='url'
                placeholder={t('Paste URL here')}
                errors={this.state.fieldsErrors.metadata}
                value={this.state.inputURL}
                onChange={this.onInputURLChange}
              />
              {this.renderButton()}

            {t('File(s) uploaded to this project')}

            {
              (!this.state.isInitialised ||
                this.state.isUploadFilePending ||
                this.state.isUploadURLPending) &&

                  {renderLoading(t('loading media'))}

            }

            {this.state.uploadedAssets.map((item, n) => {
                return (

                    {this.renderIcon(item)}
                    {this.renderFileName(item)}
                     this.onDeleteMedia(item.url)}
                    />

                );
            })}

            {this.state.isInitialised &&
              this.state.uploadedAssets.length == 0 &&

                    {t('No files uploaded yet')}

            }

      </bem.FormView>
    );
  }
}

export default FormMedia;
<commit_msg>PR Changes: remove unecessary white space<commit_after>import React from 'react';
import autoBind from 'react-autobind';
import alertify from 'alertifyjs';
import Dropzone from 'react-dropzone';
import TextBox from 'js/components/common/textBox';
import {actions} from '../../actions';
import {bem} from 'js/bem';
import {ASSET_FILE_TYPES} from '../../constants';
import {renderLoading} from 'js/components/modalForms/modalHelpers';

/**
 * @prop {object} asset
 *
 * Modal for uploading form media
 */
class FormMedia extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      uploadedAssets: [],
      fieldsErrors: {},
      inputURL: '',
      // to show loading icon instead of nothing on first load
      isInitialised: false,
      // to show loading icon while uploading any file
      isUploadFilePending: false,
      isUploadURLPending: false
    };

    autoBind(this);
  }

  /*
   * setup
   */

  componentDidMount() {
    actions.media.loadMedia(this.props.asset.uid);

    actions.media.loadMedia.completed.listen(this.onGetMediaCompleted);
    actions.media.uploadMedia.failed.listen(this.onUploadFailed);
  }

  /*
   * action listeners
   */

  onGetMediaCompleted(uploadedAssets) {
    this.setState({
      uploadedAssets: uploadedAssets.results,
      isUploadFilePending: false,
      isUploadURLPending: false,
      isInitialised: true,
    });
  }

  onUploadFailed(response) {
    this.setState({
      fieldsErrors: response.responseJSON,
      isUploadFilePending: false,
      isUploadURLPending: false
    });
  }

  /*
   * Utilities
   */

  toBase64(file) {
    return new Promise(function(resolve, reject) {
      var reader = new FileReader();
      reader.readAsDataURL(file);
      reader.onload = function() {
          return resolve(reader.result);
      };
      reader.onerror = function(error) {
          return reject(error);
      };
    });
  }

  uploadMedia(formMediaJSON) {
    // Reset error message before uploading again
    this.setState({fieldsErrors: {}});
    actions.media.uploadMedia(this.props.asset.uid, formMediaJSON);
  }

  /*
   * DOM listeners
   */

  onFileDrop(files) {
    if (files.length >= 1) {
      this.setState({isUploadFilePending: true});

      files.forEach(async (file) => {
        var base64File = await this.toBase64(file);

        this.uploadMedia({
	      description: 'default',
          file_type: ASSET_FILE_TYPES.form_media.id,
          metadata: JSON.stringify({filename: file.name}),
	      base64Encoded: base64File
	    });
      });
    }
  }

  onInputURLChange(inputURL) {
    this.setState({inputURL: inputURL});
  }

  onSubmitURL() {
    var url = this.state.inputURL;

    if (url === '') {
      alertify.warning(t('URL is empty!'));
    } else {
      this.setState({
        isUploadURLPending: true,
        inputURL: ''
      });

      this.uploadMedia({
        description: 'default',
        file_type: ASSET_FILE_TYPES.form_media.id,
        metadata: JSON.stringify({redirect_url: url}),
      });
    }
  }

  onDeleteMedia(url) {
    actions.media.deleteMedia(this.props.asset.uid, url);
  }

  /*
   * rendering
   */

  renderButton() {
    const buttonClassNames = ['formBuilder-header__button', 'formBuilder-header__button--save'];
    if (this.state.isUploadURLPending) {
      buttonClassNames.push('formBuilder-header__button--savepending');
    }
    return (
      <button
        className={buttonClassNames.join(' ')}
        onClick={this.onSubmitURL}
      >

        {t('ADD')}
      </button>
    );
  }

  renderFileName(item){
    // Check if current item is uploaded via URL. `redirect_url` is the indicator
    var fileName = item.metadata.filename;
    if (item.metadata.redirect_url) {
      var url = item.metadata.redirect_url;
      if (url.length > 50) {
        // Shorten URL to exactly 50 chars
        var urlBack = url.slice(url.length - 24);
        var urlFront = url.replace('https://', '').replace('http://', '').substr(0, 25);
        fileName = urlFront + '…' + urlBack;
      } else {
        fileName = url;
      }
    }

    return (
      {fileName}
    );
  }

  renderIcon(item) {
    const iconClassNames = ['form-media__file-type', 'fa'];
    // Check if current item is uploaded via URL. `redirect_url` is the indicator
    if (item.metadata.redirect_url) {
      iconClassNames.push('fa-link');
    } else {
      iconClassNames.push('fa-file');
    }

    return (

    );
  }

  render() {
    return (
      <bem.FormView m='form-media' className='form-media'>

          {!this.state.isUploadFilePending &&
            <Dropzone
                onDrop={this.onFileDrop.bind(this)}
                className='dropzone-settings'
            >
              {this.state.fieldsErrors.base64Encoded &&
                <bem.FormView__cell m='error'>

{this.state.fieldsErrors.base64Encoded}

                </bem.FormView__cell>
              }

              {t('Drag and drop files here')}

                {t('or')} {t('click here to browse')}

            </Dropzone>
          }

          {this.state.isUploadFilePending &&

              {renderLoading(t('Uploading file…'))}

          }

              {t('You can also add files using a URL')}

              <TextBox
                type='url'
                placeholder={t('Paste URL here')}
                errors={this.state.fieldsErrors.metadata}
                value={this.state.inputURL}
                onChange={this.onInputURLChange}
              />
              {this.renderButton()}

            {t('File(s) uploaded to this project')}

            {
              (!this.state.isInitialised ||
                this.state.isUploadFilePending ||
                this.state.isUploadURLPending) &&

                  {renderLoading(t('loading media'))}

            }

            {this.state.uploadedAssets.map((item, n) => {
                return (

                    {this.renderIcon(item)}
                    {this.renderFileName(item)}
                     this.onDeleteMedia(item.url)}
                    />

                );
            })}

            {this.state.isInitialised &&
              this.state.uploadedAssets.length == 0 &&

                    {t('No files uploaded yet')}

            }

      </bem.FormView>
    );
  }
}

export default FormMedia;
<|endoftext|>


<commit_before>import Vue from 'vue';
import App from './App.vue';

new Vue({
    el: '#app',
    render: h => h(App)
});
<commit_msg>FIX(vue) rxjs-import<commit_after>import Vue from 'vue';
import App from './App.vue';
import 'rxjs';
new Vue({
    el: '#app',
    render: h => h(App)
});
<|endoftext|>


<commit_before>var addressPoints = [
  [
    "Valencia, Spain. November 2016. Congress of online political communication. Mediaflows.",
    39.4699014,
    -0.3759513
  ],
  [
    "Budapest, Hungary. December 2012. The EU and the Politicization of Europe. Euroacademia.",
    47.4983815,
    19.0404707
  ],
  [
    "Lisbon, Portugal. June 2014. European Dialogue on Internet Governance. EuroDIG.",
    38.7077926,
    -9.1365061
  ],
  [
    "Tampere, Finland. August 2017. NordMedia 2017 bi-annual Conference. Nordicom.",
    61.4980214,
    23.7603118
  ],
  [
    "Berlin, Germany. September 2012. Europe’s common future. Böll Foundation.",
    52.5170365,
    13.3888599
  ],
  [
    "Milan, Italy. June 2017. 7th Conference European Political Sciences. EPSA.",
    45.4667971,
    9.1904984
  ],
  [
    "Vilnius, Lithuania. December 2013. Closing Conference of the Lithuanian Presidency. Council of the EU.",
    54.6870458,
    25.2829111
  ],
  [
    "Loughborough, UK. September 2013. 14th Annual UACES Forum Conference. UACES.",
    52.7723859,
    -1.2077985
  ],
  [
    "Cologne, Germany. July 2017. 3rd Computational Social Science Conference. IC2S2.",
    50.938361,
    6.959974
  ],
  [
    "Copenhagen, Denmark. June 2012. Conference United We Stand. Copenhagen Business School CBS.",
    55.6867243,
    12.5700724
  ],
  [
    "Istanbul, Turkey. May 2011. Accession of Turkey to the EU: Expectations and Realities. Bogazici University.",
    41.0096334,
    28.9651646
  ],
  [
    "Malm\u00f6, Sweden. April 2012. International Seminar Our Europe 2021. Europaforum.",
    55.6052931,
    13.0001566
  ],
  [
    "London, UK. June 2016. PhD Symposium Media and Communications. London Shool of Economics.",
    51.5073219,
    -0.1276474
  ],
  [
    "Milan, Italy. November 2016. Workshop at Public Opinion and Media Lab. University of Milan.",
    45.465428,
    9.199076
  ],
  [
    "Berlin, Germany. June 2013. European Dialogue on Internet Governance. EuroDIG.",
    52.526614,
    13.385468
  ],
  [
    "Oslo, Norway. September 2017. ECPR General Conference.",
    59.5139,
    10.7522
  ],
    [
    "Stockholm, Sweden. June 2012. European Dialogue on Internet Governance. EuroDIG.",
    59.329323,
    18.068581
  ],
];<commit_msg>conferes update<commit_after>var addressPoints = [
  [
    "Valencia, Spain. November 2016. Congress of online political communication. Mediaflows.",
    39.4699014,
    -0.3759513
  ],
  [
    "Budapest, Hungary. December 2012. The EU and the Politicization of Europe. Euroacademia.",
    47.4983815,
    19.0404707
  ],
  [
    "Lisbon, Portugal. June 2014. European Dialogue on Internet Governance. EuroDIG.",
    38.7077926,
    -9.1365061
  ],
  [
    "Tampere, Finland. August 2017. NordMedia 2017 bi-annual Conference. Nordicom.",
    61.4980214,
    23.7603118
  ],
  [
    "Berlin, Germany. September 2012. Europe’s common future. Böll Foundation.",
    52.5170365,
    13.3888599
  ],
  [
    "Milan, Italy. June 2017. 7th Conference European Political Sciences. EPSA.",
    45.4667971,
    9.1904984
  ],
  [
    "Vilnius, Lithuania. December 2013. Closing Conference of the Lithuanian Presidency. Council of the EU.",
    54.6870458,
    25.2829111
  ],
  [
    "Loughborough, UK. September 2013. 14th Annual UACES Forum Conference. UACES.",
    52.7723859,
    -1.2077985
  ],
  [
    "Cologne, Germany. July 2017. 3rd Computational Social Science Conference. IC2S2.",
    50.938361,
    6.959974
  ],
  [
    "Copenhagen, Denmark. June 2012. Conference United We Stand. Copenhagen Business School CBS.",
    55.6867243,
    12.5700724
  ],
  [
    "Istanbul, Turkey. May 2011. Accession of Turkey to the EU: Expectations and Realities. Bogazici University.",
    41.0096334,
    28.9651646
  ],
  [
    "Malm\u00f6, Sweden. April 2012. International Seminar Our Europe 2021. Europaforum.",
    55.6052931,
    13.0001566
  ],
  [
    "London, UK. June 2016. PhD Symposium Media and Communications. London Shool of Economics.",
    51.5073219,
    -0.1276474
  ],
  [
    "Milan, Italy. November 2016. Workshop at Public Opinion and Media Lab. University of Milan.",
    45.465428,
    9.199076
  ],
  [
    "Berlin, Germany. June 2013. European Dialogue on Internet Governance. EuroDIG.",
    52.526614,
    13.385468
  ],
  [
    "Oslo, Norway. September 2017. ECPR General Conference.",
    59.5139,
    10.7522
  ],
    [
    "Stockholm, Sweden. June 2012. European Dialogue on Internet Governance. EuroDIG.",
    59.329323,
    18.068581
  ],
    [
    "Tartu, Estonia. October 2017. Association of Internet Researchers. AOIR.",
    58.377,
    26.72900
  ],
    [
    "Stockholm, Sweden. November 2017. ECREA Symposium Digital Democracy in the age of Big Data. Södertorns Högskola",
    59.220452,
    17.943596
  ],
];<|endoftext|>


<commit_before>var Immutable = require('Immutable');

function shallowEqualImmutable(objA, objB) {
  if (Immutable.is(objA, objB)) {
    return true;
  }
  var key;
  // Test for A's keys different from B.
  for (key in objA) {
    if (objA.hasOwnProperty(key) &&
        (!objB.hasOwnProperty(key) || !Immutable.is(objA[key], objB[key]))) {
      return false;
    }
  }
  // Test for B's keys missing from A.
  for (key in objB) {
    if (objB.hasOwnProperty(key) && !objA.hasOwnProperty(key)) {
      return false;
    }
  }
  return true;
}

module.exports = shallowEqualImmutable;
<commit_msg>Use a lowercase 'immutable' module name<commit_after>var Immutable = require('immutable');

function shallowEqualImmutable(objA, objB) {
  if (Immutable.is(objA, objB)) {
    return true;
  }
  var key;
  // Test for A's keys different from B.
  for (key in objA) {
    if (objA.hasOwnProperty(key) &&
        (!objB.hasOwnProperty(key) || !Immutable.is(objA[key], objB[key]))) {
      return false;
    }
  }
  // Test for B's keys missing from A.
  for (key in objB) {
    if (objB.hasOwnProperty(key) && !objA.hasOwnProperty(key)) {
      return false;
    }
  }
  return true;
}

module.exports = shallowEqualImmutable;
<|endoftext|>


<commit_before>(function(env) {
    "use strict";
    env.ddg_spice_time = function(api_result) {

        if (!api_result || !api_result.locations.length) {
            return Spice.failed('time');
        }

        var dateObj = DDG.getDateFromString(api_result.locations[0].time.iso),
            months = new Array('January', 'February', 'March', 'April', 'May', 'June', 'Jully', 'August', 'September', 'October', 'November', 'December'),
            days = new Array('Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday');

        //Convert 24 hour time to 12 hour time
        function toPrettyTime(date) {
          var hours = date.getHours(),
              minutes = date.getMinutes()
          return {
            hours: (hours % 12) || 12,
            minutes: minutes<10 ? '0'+minutes : minutes,
            amPM: hours >= 12 ? "PM" : "AM"
        }
        }

        var dateTime = {
            time: toPrettyTime(dateObj),
            dayName: days[dateObj.getDay()],
            day: dateObj.getDate(),
            monthName: months[dateObj.getMonth()],
            year: dateObj.getFullYear(),
            placeName: api_result.locations[0].geo.name,
            offset: api_result.locations[0].time.timezone.offset.replace(/0|:/g, ""),
            zone: api_result.locations[0].time.timezone.zonename,
            country: api_result.locations[0].geo.country.name
        }

        Spice.add({
            id: "time",
            name: "Time",
            data: dateTime,
            meta: {
                sourceName: "timeanddate.com",
                sourceUrl: 'http://www.timeanddate.com/worldclock/city.html?n=' + api_result.locations[0].id
            },
            templates: {
                group: 'base',
                options: {
                    content: Spice.time.content,
                    moreAt: true
                }
            }
        });
    };
}(this));<commit_msg>Update API error checking<commit_after>(function(env) {
    "use strict";
    env.ddg_spice_time = function(api_result) {

        if (!api_result || api_result.info == "No matches") {
            return Spice.failed('time');
        }

        var dateObj = DDG.getDateFromString(api_result.locations[0].time.iso),
            months = new Array('January', 'February', 'March', 'April', 'May', 'June', 'Jully', 'August', 'September', 'October', 'November', 'December'),
            days = new Array('Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday');

        //Convert 24 hour time to 12 hour time
        function toPrettyTime(date) {
          var hours = date.getHours(),
              minutes = date.getMinutes()
          return {
            hours: (hours % 12) || 12,
            minutes: minutes<10 ? '0'+minutes : minutes,
            amPM: hours >= 12 ? "PM" : "AM"
        }
        }

        var dateTime = {
            time: toPrettyTime(dateObj),
            dayName: days[dateObj.getDay()],
            day: dateObj.getDate(),
            monthName: months[dateObj.getMonth()],
            year: dateObj.getFullYear(),
            placeName: api_result.locations[0].geo.name,
            offset: api_result.locations[0].time.timezone.offset.replace(/0|:/g, ""),
            zone: api_result.locations[0].time.timezone.zonename,
            country: api_result.locations[0].geo.country.name
        }

        Spice.add({
            id: "time",
            name: "Time",
            data: dateTime,
            meta: {
                sourceName: "timeanddate.com",
                sourceUrl: 'http://www.timeanddate.com/worldclock/city.html?n=' + api_result.locations[0].id
            },
            templates: {
                group: 'base',
                options: {
                    content: Spice.time.content,
                    moreAt: true
                }
            }
        });
    };
}(this));<|endoftext|>


<commit_before>import angular from 'angular'
import 'angular-aria'
import 'angular-i18n/nl-nl'
import 'angular-sanitize'

const moduleDependencies = [
  // Main modules
  'dpDetail',
  'dpDataSelection',

  // Shared module
  'dpShared',
  'ngAria',
]

// eslint-disable-next-line angular/di
angular.module('atlas', moduleDependencies).config(['$provide', urlChangeProvider])

urlChangeProvider.$inject = ['$provide']
/* istanbul ignore next */
function urlChangeProvider($provide) {
  $provide.decorator('$browser', [
    '$delegate',
    function ($delegate) {
      $delegate.onUrlChange = function () {}
      $delegate.url = function () {
        return ''
      }
      return $delegate
    },
  ])
}
<commit_msg>Fix a breaking change due to the angular dependency update<commit_after>import angular from 'angular'
import 'angular-aria'
import 'angular-i18n/nl-nl'
import 'angular-sanitize'

const moduleDependencies = [
  // Main modules
  'dpDetail',
  'dpDataSelection',

  // Shared module
  'dpShared',
  'ngAria',
]

// eslint-disable-next-line angular/di
angular.module('atlas', moduleDependencies).config(['$provide', urlChangeProvider])

// Allow https://github.com/angular/angular.js/blob/master/CHANGELOG.md#breaking-changes
angular.UNSAFE_restoreLegacyJqLiteXHTMLReplacement()

urlChangeProvider.$inject = ['$provide']
/* istanbul ignore next */
function urlChangeProvider($provide) {
  $provide.decorator('$browser', [
    '$delegate',
    function ($delegate) {
      $delegate.onUrlChange = function () {}
      $delegate.url = function () {
        return ''
      }
      return $delegate
    },
  ])
}
<|endoftext|>


<commit_before>// @flow
import * as PeopleGen from './people-gen'
import * as Saga from '../util/saga'
import * as I from 'immutable'
import * as Constants from '../constants/people'
import * as Types from '../constants/types/people'
import * as RouteTypes from '../constants/types/route-tree'
import * as RouteConstants from '../constants/route-tree'
import * as RPCTypes from '../constants/types/rpc-gen'
import engine from '../engine'
import {peopleTab} from '../constants/tabs'
import {type TypedState} from '../constants/reducer'
import {createDecrementWaiting, createIncrementWaiting} from '../actions/waiting-gen'
import {getPath} from '../route-tree'

const _getPeopleData = function(action: PeopleGen.GetPeopleDataPayload, state: TypedState) {
  return Saga.sequentially([
    Saga.put(createIncrementWaiting({key: Constants.getPeopleDataWaitingKey})),
    Saga.call(RPCTypes.homeHomeGetScreenRpcPromise, {
      markViewed: action.payload.markViewed,
      numFollowSuggestionsWanted: action.payload.numFollowSuggestionsWanted,
    }),
    Saga.identity(state.config.following),
    Saga.identity(state.config.followers),
    Saga.put(createDecrementWaiting({key: Constants.getPeopleDataWaitingKey})),
  ])
}

const _processPeopleData = function(fromGetPeopleData: any[]) {
  const data: RPCTypes.HomeScreen = fromGetPeopleData[1]
  const following: I.Set<string> = fromGetPeopleData[2]
  const followers: I.Set<string> = fromGetPeopleData[3]

  const oldItems: I.List<Types.PeopleScreenItem> =
    (data.items &&
      data.items
        .filter(item => !item.badged && item.data.t !== RPCTypes.homeHomeScreenItemType.todo)
        .reduce(Constants.reduceRPCItemToPeopleItem, I.List())) ||
    I.List()
  const newItems: I.List<Types.PeopleScreenItem> =
    (data.items &&
      data.items
        .filter(item => item.badged || item.data.t === RPCTypes.homeHomeScreenItemType.todo)
        .reduce(Constants.reduceRPCItemToPeopleItem, I.List())) ||
    I.List()

  const followSuggestions: I.List<Types.FollowSuggestion> =
    (data.followSuggestions &&
      data.followSuggestions.reduce((list, suggestion) => {
        const followsMe = followers.has(suggestion.username)
        const iFollow = following.has(suggestion.username)
        return list.push(
          Constants.makeFollowSuggestion({
            username: suggestion.username,
            followsMe,
            iFollow,
            fullName: suggestion.fullName,
          })
        )
      }, I.List())) ||
    I.List()

  return Saga.put(
    PeopleGen.createPeopleDataProcessed({
      oldItems,
      newItems,
      lastViewed: new Date(data.lastViewed),
      followSuggestions,
      version: data.version,
    })
  )
}

const _markViewed = (action: PeopleGen.MarkViewedPayload) =>
  Saga.call(RPCTypes.homeHomeMarkViewedRpcPromise, {})

const _skipTodo = (action: PeopleGen.SkipTodoPayload) => {
  return Saga.sequentially([
    Saga.call(RPCTypes.homeHomeSkipTodoTypeRpcPromise, {
      t: RPCTypes.homeHomeScreenTodoType[action.payload.type],
    }),
    // TODO get rid of this load and have core send us a homeUIRefresh
    Saga.put(
      PeopleGen.createGetPeopleData({
        markViewed: false,
        numFollowSuggestionsWanted: Constants.defaultNumFollowSuggestions,
      })
    ),
  ])
}

let _wasOnPeopleTab = true
const _setupPeopleHandlers = () => {
  return Saga.put((dispatch: Dispatch) => {
    engine().listenOnConnect('registerHomeUI', () => {
      RPCTypes.delegateUiCtlRegisterHomeUIRpcPromise()
        .then(() => console.log('Registered home UI'))
        .catch(error => console.warn('Error in registering home UI:', error))
    })

    engine().setIncomingHandler('keybase.1.homeUI.homeUIRefresh', (args: {||}) => {
      if (_wasOnPeopleTab) {
        dispatch(
          PeopleGen.createGetPeopleData({
            markViewed: false,
            numFollowSuggestionsWanted: Constants.defaultNumFollowSuggestions,
          })
        )
      }
    })
  })
}
const _onTabChange = (action: RouteTypes.SwitchTo, state: TypedState) => {
  // TODO replace this with notification based refreshing
  const list = I.List(action.payload.path)
  const root = list.first()
  const peoplePath = getPath(state.routeTree.routeState, [peopleTab])

  if (root !== peopleTab && _wasOnPeopleTab && peoplePath.size === 1) {
    _wasOnPeopleTab = false
    return Saga.put(PeopleGen.createMarkViewed())
  } else if (root === peopleTab && !_wasOnPeopleTab) {
    _wasOnPeopleTab = true
    return Saga.put(
      PeopleGen.createGetPeopleData({
        markViewed: false,
        numFollowSuggestionsWanted: Constants.defaultNumFollowSuggestions,
      })
    )
  }
}

const peopleSaga = function*(): Saga.SagaGenerator<any, any> {
  yield Saga.safeTakeEveryPure(PeopleGen.getPeopleData, _getPeopleData, _processPeopleData, () =>
    // TODO replace this with engine handling once that lands
    Saga.put(createDecrementWaiting({key: Constants.getPeopleDataWaitingKey}))
  )
  yield Saga.safeTakeEveryPure(PeopleGen.markViewed, _markViewed)
  yield Saga.safeTakeEveryPure(PeopleGen.skipTodo, _skipTodo)
  yield Saga.safeTakeEveryPure(PeopleGen.setupPeopleHandlers, _setupPeopleHandlers)
  yield Saga.safeTakeEveryPure(RouteConstants.switchTo, _onTabChange)
}

export default peopleSaga
<commit_msg>Ignore api network errors in homeMarkViewed (#10990)<commit_after>// @flow
import * as PeopleGen from './people-gen'
import * as Saga from '../util/saga'
import * as I from 'immutable'
import * as Constants from '../constants/people'
import * as Types from '../constants/types/people'
import * as RouteTypes from '../constants/types/route-tree'
import * as RouteConstants from '../constants/route-tree'
import * as RPCTypes from '../constants/types/rpc-gen'
import logger from '../logger'
import engine from '../engine'
import {peopleTab} from '../constants/tabs'
import {type TypedState} from '../constants/reducer'
import {createDecrementWaiting, createIncrementWaiting} from '../actions/waiting-gen'
import {getPath} from '../route-tree'

const _getPeopleData = function(action: PeopleGen.GetPeopleDataPayload, state: TypedState) {
  return Saga.sequentially([
    Saga.put(createIncrementWaiting({key: Constants.getPeopleDataWaitingKey})),
    Saga.call(RPCTypes.homeHomeGetScreenRpcPromise, {
      markViewed: action.payload.markViewed,
      numFollowSuggestionsWanted: action.payload.numFollowSuggestionsWanted,
    }),
    Saga.identity(state.config.following),
    Saga.identity(state.config.followers),
    Saga.put(createDecrementWaiting({key: Constants.getPeopleDataWaitingKey})),
  ])
}

const _processPeopleData = function(fromGetPeopleData: any[]) {
  const data: RPCTypes.HomeScreen = fromGetPeopleData[1]
  const following: I.Set<string> = fromGetPeopleData[2]
  const followers: I.Set<string> = fromGetPeopleData[3]

  const oldItems: I.List<Types.PeopleScreenItem> =
    (data.items &&
      data.items
        .filter(item => !item.badged && item.data.t !== RPCTypes.homeHomeScreenItemType.todo)
        .reduce(Constants.reduceRPCItemToPeopleItem, I.List())) ||
    I.List()
  const newItems: I.List<Types.PeopleScreenItem> =
    (data.items &&
      data.items
        .filter(item => item.badged || item.data.t === RPCTypes.homeHomeScreenItemType.todo)
        .reduce(Constants.reduceRPCItemToPeopleItem, I.List())) ||
    I.List()

  const followSuggestions: I.List<Types.FollowSuggestion> =
    (data.followSuggestions &&
      data.followSuggestions.reduce((list, suggestion) => {
        const followsMe = followers.has(suggestion.username)
        const iFollow = following.has(suggestion.username)
        return list.push(
          Constants.makeFollowSuggestion({
            username: suggestion.username,
            followsMe,
            iFollow,
            fullName: suggestion.fullName,
          })
        )
      }, I.List())) ||
    I.List()

  return Saga.put(
    PeopleGen.createPeopleDataProcessed({
      oldItems,
      newItems,
      lastViewed: new Date(data.lastViewed),
      followSuggestions,
      version: data.version,
    })
  )
}

const _markViewed = (action: PeopleGen.MarkViewedPayload) =>
  Saga.call(RPCTypes.homeHomeMarkViewedRpcPromise, {})

const _skipTodo = (action: PeopleGen.SkipTodoPayload) => {
  return Saga.sequentially([
    Saga.call(RPCTypes.homeHomeSkipTodoTypeRpcPromise, {
      t: RPCTypes.homeHomeScreenTodoType[action.payload.type],
    }),
    // TODO get rid of this load and have core send us a homeUIRefresh
    Saga.put(
      PeopleGen.createGetPeopleData({
        markViewed: false,
        numFollowSuggestionsWanted: Constants.defaultNumFollowSuggestions,
      })
    ),
  ])
}

let _wasOnPeopleTab = true
const _setupPeopleHandlers = () => {
  return Saga.put((dispatch: Dispatch) => {
    engine().listenOnConnect('registerHomeUI', () => {
      RPCTypes.delegateUiCtlRegisterHomeUIRpcPromise()
        .then(() => console.log('Registered home UI'))
        .catch(error => console.warn('Error in registering home UI:', error))
    })

    engine().setIncomingHandler('keybase.1.homeUI.homeUIRefresh', (args: {||}) => {
      if (_wasOnPeopleTab) {
        dispatch(
          PeopleGen.createGetPeopleData({
            markViewed: false,
            numFollowSuggestionsWanted: Constants.defaultNumFollowSuggestions,
          })
        )
      }
    })
  })
}
const _onTabChange = (action: RouteTypes.SwitchTo, state: TypedState) => {
  // TODO replace this with notification based refreshing
  const list = I.List(action.payload.path)
  const root = list.first()
  const peoplePath = getPath(state.routeTree.routeState, [peopleTab])

  if (root !== peopleTab && _wasOnPeopleTab && peoplePath.size === 1) {
    _wasOnPeopleTab = false
    return Saga.put(PeopleGen.createMarkViewed())
  } else if (root === peopleTab && !_wasOnPeopleTab) {
    _wasOnPeopleTab = true
    return Saga.put(
      PeopleGen.createGetPeopleData({
        markViewed: false,
        numFollowSuggestionsWanted: Constants.defaultNumFollowSuggestions,
      })
    )
  }
}

const networkErrors = [
  RPCTypes.constantsStatusCode.scgenericapierror,
  RPCTypes.constantsStatusCode.scapinetworkerror,
  RPCTypes.constantsStatusCode.sctimeout,
]

const peopleSaga = function*(): Saga.SagaGenerator<any, any> {
  yield Saga.safeTakeEveryPure(PeopleGen.getPeopleData, _getPeopleData, _processPeopleData, () =>
    // TODO replace this with engine handling once that lands
    Saga.put(createDecrementWaiting({key: Constants.getPeopleDataWaitingKey}))
  )
  yield Saga.safeTakeEveryPure(PeopleGen.markViewed, _markViewed, null, err => {
    if (networkErrors.includes(err.code)) {
      logger.warn('Network error calling homeMarkViewed')
    } else {
      throw err
    }
  })
  yield Saga.safeTakeEveryPure(PeopleGen.skipTodo, _skipTodo)
  yield Saga.safeTakeEveryPure(PeopleGen.setupPeopleHandlers, _setupPeopleHandlers)
  yield Saga.safeTakeEveryPure(RouteConstants.switchTo, _onTabChange)
}

export default peopleSaga
<|endoftext|>


<commit_before>/* jshint expr: true */
var chai = require('chai');
var spies = require('chai-spies');
var request = require('supertest');
var app = require('../src/app');
var Deployment = require('../src/Deployment');
var ghPushFixture = require('./fixtures/github-push.json');
var ghStatusSuccessFixture = require('./fixtures/github-status-success.json');
var ghStatusFailureFixture = require('./fixtures/github-status-failure.json');
var ghWrongBranchFixture = require('./fixtures/github-wrong-branch.json');

var expect = chai.expect;
chai.use(spies);

describe('API', function() {
  describe('/github', function() {
    var hash = {
      empty: 'sha1=7876c938d38e99b954b3d839c7bafb343d29e776',
      payload: 'sha1=afc5f9b9343a32bdb7c3c5357a9b5aeebe69ebd8',
      wrongStatus: 'sha1=99eb999cad90ad98c78b1affb516b5018954eaa7',
      correctStatus: 'sha1=d167d37201caf04118a96982080827898c969163',
      wrongBranch: 'sha1=a8a62aa8e11029cef4fe0473b7158458f6a84622'
    };

    var deploySpy;
    beforeEach(function() {
      deploySpy = chai.spy(Deployment);
    });

    it('should deploy with a correct payload', function(done) {
      request(app)
        .post('/api/github')
        .set('x-hub-signature', hash.correctStatus)
        .set('x-github-event', 'status')
        .send(ghStatusSuccessFixture)
        .expect(200)
        .expect('Content-Type', /json/)
        .end(function(err, res) {
          if (err) return done(err);
          expect(res.body.status).to.equal(200);
          expect(res.body.output).to.equal('deploying all the things');
          expect(deploySpy).to.have.been.called;
          done();
        });
    });

    it('should return 200 when auth succeeds', function(done) {
      request(app)
        .post('/api/github')
        .set('x-hub-signature', hash.empty)
        .expect(200, done);
    });

    it('should not deploy when given incorrect hash', function(done) {
      request(app)
        .post('/api/github')
        .set('x-hub-signature', 'wrong')
        .expect(403)
        .expect('Content-Type', /json/)
        .end(function(err, res) {
          if (err) return done(err);
          var error = res.body;
          expect(error.statusCode).to.equal(403);
          expect(error.message).to.equal('Invalid hook signature');
          expect(deploySpy).not.to.have.been.called;
          done();
        });
    });

    it('should not deploy if status is failure', function(done) {
      request(app)
        .post('/api/github')
        .set('x-hub-signature', hash.wrongStatus)
        .set('x-github-event', 'status')
        .send(ghStatusFailureFixture)
        .expect(200)
        .expect('Content-Type', /json/)
        .end(function(err, res) {
          if (err) return done(err);
          var error = res.body;
          expect(error.statusCode).to.equal(200);
          expect(error.message).to.equal('State is not success, nothing will be done');
          expect(deploySpy).not.to.have.been.called;
          done();
        });
    });

    it('should not deploy if event is not status', function(done) {
      request(app)
        .post('/api/github')
        .set('x-hub-signature', hash.payload)
        .set('x-github-event', 'push')
        .send(ghPushFixture)
        .expect(200)
        .expect('Content-Type', /json/)
        .end(function(err, res) {
          if (err) return done(err);
          var error = res.body;
          expect(error.statusCode).to.equal(200);
          expect(error.message).to.equal('Not a status event, nothing will be done');
          expect(deploySpy).not.to.have.been.called;
          done();
        });
    });

    it('should not deploy if branch is not master', function(done) {
      request(app)
        .post('/api/github')
        .set('x-hub-signature', hash.wrongBranch)
        .set('x-github-event', 'status')
        .send(ghWrongBranchFixture)
        .expect(200)
        .expect('Content-Type', /json/)
        .end(function(err, res) {
          if (err) return done(err);
          var error = res.body;
          expect(error.statusCode).to.equal(200);
          expect(error.message).to.equal('Received hook from a different branch than master, nothing will be done');
          expect(deploySpy).not.to.have.been.called;
          done();
        });
    });
  });
});
<commit_msg>Fix api deployment test<commit_after>/* jshint expr: true */
var chai = require('chai');
var spies = require('chai-spies');
var request = require('supertest');
var Bluebird = require('bluebird');
var app = require('../src/app');
var Deployment = require('../src/Deployment');
var ghPushFixture = require('./fixtures/github-push.json');
var ghStatusSuccessFixture = require('./fixtures/github-status-success.json');
var ghStatusFailureFixture = require('./fixtures/github-status-failure.json');
var ghWrongBranchFixture = require('./fixtures/github-wrong-branch.json');

var expect = chai.expect;
chai.use(spies);

describe('API', function() {
  describe('/github', function() {
    var hash = {
      empty: 'sha1=7876c938d38e99b954b3d839c7bafb343d29e776',
      payload: 'sha1=afc5f9b9343a32bdb7c3c5357a9b5aeebe69ebd8',
      wrongStatus: 'sha1=99eb999cad90ad98c78b1affb516b5018954eaa7',
      correctStatus: 'sha1=d167d37201caf04118a96982080827898c969163',
      wrongBranch: 'sha1=a8a62aa8e11029cef4fe0473b7158458f6a84622'
    };

    var deploySpy;
    beforeEach(function() {
      Deployment.prototype.run = Bluebird.method(function () { return true; });
      deploySpy = chai.spy(Deployment.prototype.run);
    });

    it('should deploy with a correct payload', function(done) {
      request(app)
        .post('/api/github')
        .set('x-hub-signature', hash.correctStatus)
        .set('x-github-event', 'status')
        .send(ghStatusSuccessFixture)
        .expect(200)
        .expect('Content-Type', /json/)
        .end(function(err, res) {
          if (err) return done(err);
          expect(res.body.status).to.equal(200);
          expect(deploySpy).to.have.been.called;
          done();
        });
    });

    it('should return 200 when auth succeeds', function(done) {
      request(app)
        .post('/api/github')
        .set('x-hub-signature', hash.empty)
        .expect(200, done);
    });

    it('should not deploy when given incorrect hash', function(done) {
      request(app)
        .post('/api/github')
        .set('x-hub-signature', 'wrong')
        .expect(403)
        .expect('Content-Type', /json/)
        .end(function(err, res) {
          if (err) return done(err);
          var error = res.body;
          expect(error.statusCode).to.equal(403);
          expect(error.message).to.equal('Invalid hook signature');
          expect(deploySpy).not.to.have.been.called;
          done();
        });
    });

    it('should not deploy if status is failure', function(done) {
      request(app)
        .post('/api/github')
        .set('x-hub-signature', hash.wrongStatus)
        .set('x-github-event', 'status')
        .send(ghStatusFailureFixture)
        .expect(200)
        .expect('Content-Type', /json/)
        .end(function(err, res) {
          if (err) return done(err);
          var error = res.body;
          expect(error.statusCode).to.equal(200);
          expect(error.message).to.equal('State is not success, nothing will be done');
          expect(deploySpy).not.to.have.been.called;
          done();
        });
    });

    it('should not deploy if event is not status', function(done) {
      request(app)
        .post('/api/github')
        .set('x-hub-signature', hash.payload)
        .set('x-github-event', 'push')
        .send(ghPushFixture)
        .expect(200)
        .expect('Content-Type', /json/)
        .end(function(err, res) {
          if (err) return done(err);
          var error = res.body;
          expect(error.statusCode).to.equal(200);
          expect(error.message).to.equal('Not a status event, nothing will be done');
          expect(deploySpy).not.to.have.been.called;
          done();
        });
    });

    it('should not deploy if branch is not master', function(done) {
      request(app)
        .post('/api/github')
        .set('x-hub-signature', hash.wrongBranch)
        .set('x-github-event', 'status')
        .send(ghWrongBranchFixture)
        .expect(200)
        .expect('Content-Type', /json/)
        .end(function(err, res) {
          if (err) return done(err);
          var error = res.body;
          expect(error.statusCode).to.equal(200);
          expect(error.message).to.equal('Received hook from a different branch than master, nothing will be done');
          expect(deploySpy).not.to.have.been.called;
          done();
        });
    });
  });
});
<|endoftext|>