<commit_before>
/* Dasca, an idle game by @CylonicRaider (github.com/CylonicRaider/dasca)
 * Abstract engine for JS-based idle games */

'use strict';

/* *** Clock ***
 * An object allowing to sample "time" (as defined by an external source)
 * with a linear transform in place. */

/* Construct a new clock
 * source is a function that, when called, returns the current time; scale
 * and offset modify source's output in a linear fashion: the reading of
 * source is multiplied by scale and offset is added to that to obtain the
 * current time. If scale is undefined or null, it defaults to 1; if offset
 * is null, it is computed such that the clock starts counting from zero. */
function Clock(source, scale, offset) {
  if (scale == null) scale = 1.0;
  if (offset == null) offset = -source() * scale;
  this.source = source;
  this.scale = scale;
  this.offset = offset;
}

Clock.prototype = {
  /* Sample the current time */
  now: function() {
    return this.source() * this.scale + this.offset;
  },

  /* Construct a new clock from this one, applying the given transformation
   * The new clock derives its time from the same (!) source as this one,
   * but its scale and offset are modified to simulate a clock constructed
   * like
   *     new Clock(this, scale, offset);
   */
  derive: function(scale, offset) {
    if (scale == null) scale = 1.0;
    if (offset != null) offset = this.offset * scale + offset;
    var ret = new Clock(this.source, this.scale * scale, offset);
    if (this._realTime) ret._realTime = true;
    return ret;
  },

  /* Change the scale of the clock, ensuring that readings continue to be
   * continuous */
  setScale: function(scale) {
    var samp = this.source();
    this.offset = (this.scale - scale) * samp + this.offset;
    this.scale = scale;
  },

  /* Change the scale of the clock relatively to the current one */
  changeScale: function(factor) {
    this.setScale(this.scale * factor);
  },

  /* Serialization boilerplate */
  constructor: Clock
};

/* Construct a clock that returns (optionally scaled) real time
 * The clock counts from zero */
Clock.realTime = function(scale, start) {
  if (scale == null) scale = 1.0;
  var offset = (start == null) ? null : start - performance.now() * scale;
  var ret = new Clock(function() {
    return performance.now() / 1000.0;
  }, scale, offset);
  ret._realTime = true;
  return ret;
};

/* Seralize a Clock */
Clock.__save__ = function(clock) {
  if (! clock._realTime) throw new Error("Clock not serializable!");
  return {scale: clock.scale, time: clock.now()};
};

/* Deserialize a Clock */
Clock.__restore__ = function(data) {
  return Clock.realTime(data.scale, data.time);
};

/* *** Scheduler ***
 * Schedules callbacks to happen at certain times as defined by a Clock
 * instance. */

/* Construct a new scheduler
 * requeue is a funtion that somehow ("magically") ensures the function
 * to it is asynchronously called again some short time later; tasks is an
 * ordered array of objects whose "time" property is used to determine when
 * they are to run; contTasks is an array of tasks to be run continuously,
 * i.e. at every call of run() (the same semantics as for tasks apply); clock
 * is a Clock instance determining the time this instance works with. The
 * "running" property is set to true; it can be used to stop the Scheduler.
 * To start it, ensure the "running" property is true and call the run()
 * method. */
function Scheduler(requeue, tasks, contTasks, clock) {
  if (tasks == null) tasks = [];
  if (contTasks == null) contTasks = [];
  if (clock == null) clock = Clock.realTime();
  this.requeue = requeue;
  this.tasks = tasks;
  this.contTasks = contTasks;
  this.clock = clock;
  this.running = true;
}

Scheduler.prototype = {
  /* Queue the next run of the scheduler, and perform any tasks whose time
   * has come
   * After obtaining a timestamp from the clock, all tasks whose time
   * property is not less than the timestamp are removed from the queue and
   * run using runTask(); after that, if the "running" property is true,
   * requeue is called with a bound version of this.run as only argument to
   * trigger another execution. */
  run: function() {
    /* Abort if not running */
    if (! this.running) return;
    /* Obtain current timestamp */
    var now = this.clock.now();
    /* For each task that is (over)due */
    while (this.tasks[0] && this.tasks[0].time <= now) {
      /* Run it */
      this.runTask(this.tasks.shift(), now);
    }
    /* Run the continuous tasks */
    for (var i = 0; i < this.contTasks.length; i++) {
      this.runTask(this.contTasks[i], now);
    }
    /* Schedule next iteration */
    this.requeue(this.run.bind(this));
  },

  /* Run a singular task, providing the given timestamp
   * The default implementation calls the task's "cb" (which is assumed to be
   * a function) with the value of now and the Scheduler instance as
   * arguments, and consumes exceptions by logging them to the console. */
  runTask: function(task, now) {
    try {
      task.cb(now, this);
    } catch (e) {
      console.error(e);
    }
  },

  /* Schedule a task to be run
   * If time is not null, it is inserted into task as the "time" property;
   * after that, the task is inserted at an appropriate position. */
  addTask: function(task, time) {
    if (time != null) task.time = time;
    time = task.time;
    var i;
    for (i = 0; i < this.tasks.length; i++) {
      if (this.tasks[i].time > time) break;
    }
    this.tasks.splice(0, i, task);
  },

  /* Cancel all tasks */
  clear: function() {
    this.tasks.splice(0, this.tasks.length);
  },

  /* OOP boilerplate */
  constructor: Scheduler
};

/* Create a Scheduler for animations */
Scheduler.makeAnimated = function(clock) {
  var ret = new Scheduler(requestAnimationFrame.bind(window), null, null,
                          clock);
  ret._type = "animated";
  return ret;
};

/* Create a Scheduler that polls tasks at regular intervals */
Scheduler.makeStrobe = function(fps, clock) {
  var delay = 1000.0 / fps;
  var ret = new Scheduler(function(cb) {
    setTimeout(cb, delay);
  }, null, null, clock);
  ret._type = "strobe";
  ret._fps = fps;
  return ret;
};

/* Prepare for serializing a Scheduler */
Scheduler.__save__ = function(sched) {
  var ret = {type: sched._type, tasks: sched.tasks,
             contTasks: sched.contTasks, clock: sched.clock,
             running: sched.running};
  if (sched._type == "strobe") {
    ret.fps = sched._fps;
  } else if (sched._type != "animated") {
    throw new Error("Scheduler not serializable!");
  }
  return ret;
};

/* Deserialize a Scheduler */
Scheduler.__restore__ = function(data) {
  var ret;
  if (data.type == "animated") {
    ret = Scheduler.makeAnimated(data.clock);
  } else if (data.type == "strobe") {
    ret = Scheduler.makeStrobe(data.fps, data.clock);
  }
  ret.tasks = data.tasks;
  ret.contTasks = data.contTasks;
  ret.running = data.running;
  return ret;
};

/* *** Serialization ***
 * Serializes object trees (!) into JSON strings, allowing reified objects to
 * be of the correct type, to hook their (de)serialization process.
 * Input containing enumerable function properties is rejected (since those
 * are silently swallowed by JSON); use hooks to meaningfully handle them. */

/* Serialize an object tree to JSON, storing type information */
function serialize(obj) {
  return JSON.stringify(obj, function(name, value) {
    /* Fail verbosely */
    if (typeof value == "function")
      throw new Error("Cannot serialize function");
    /* Only transform object values */
    if (typeof value != "object" || Array.isArray(value)) return value;
    /* Get a meaningful constructor name */
    var cons = value.constructor.__sername__;
    if (! cons) cons = value.constructor.name;
    if (! cons) cons = Object.prototype.toString(value).slice(8, -1);
    if (cons == "Object") cons = undefined;
    /* Copy properties into new object, or let object serialize itself */
    var ret;
    if (value.constructor.__save__) {
      ret = value.constructor.__save__(value);
    } else {
      ret = {};
      for (var prop in value) ret[prop] = value[prop];
    }
    /* Add __type__ */
    ret.__type__ = cons;
    /* Done */
    return ret;
  });
}

/* Deserialize a JSON string into an object structure */
function deserialize(obj, env) {
  if (env == null) env = window;
  return JSON.parse(obj, function(name, value) {
    /* Ignore non-objects */
    if (typeof value != "object" || Array.isArray(value)) return value;
    /* Check for a __type__ */
    if (value.__type__) {
      /* Obtain type object */
      var type = env[value.__type__];
      if (type && type.__restore__) {
        /* Use restorer function */
        value = type.__restore__(value, env);
      } else if (type) {
        /* Assume an object is deserializable as-is */
        var newVal = Object.create(type.prototype);
        for (var k in value) if (! /^__.+__$/.test(k)) newVal[k] = value[k];
        value = newVal;
      } else {
        /* Nope */
        throw new Error("Object not deserializable (cannot find type): " +
                        JSON.stringify(value));
      }
    }
    return value;
  });
}
<commit_msg>Automatically start and stop Scheduler as necessary<commit_after>
/* Dasca, an idle game by @CylonicRaider (github.com/CylonicRaider/dasca)
 * Abstract engine for JS-based idle games */

'use strict';

/* *** Clock ***
 * An object allowing to sample "time" (as defined by an external source)
 * with a linear transform in place. */

/* Construct a new clock
 * source is a function that, when called, returns the current time; scale
 * and offset modify source's output in a linear fashion: the reading of
 * source is multiplied by scale and offset is added to that to obtain the
 * current time. If scale is undefined or null, it defaults to 1; if offset
 * is null, it is computed such that the clock starts counting from zero. */
function Clock(source, scale, offset) {
  if (scale == null) scale = 1.0;
  if (offset == null) offset = -source() * scale;
  this.source = source;
  this.scale = scale;
  this.offset = offset;
}

Clock.prototype = {
  /* Sample the current time */
  now: function() {
    return this.source() * this.scale + this.offset;
  },

  /* Construct a new clock from this one, applying the given transformation
   * The new clock derives its time from the same (!) source as this one,
   * but its scale and offset are modified to simulate a clock constructed
   * like
   *     new Clock(this, scale, offset);
   */
  derive: function(scale, offset) {
    if (scale == null) scale = 1.0;
    if (offset != null) offset = this.offset * scale + offset;
    var ret = new Clock(this.source, this.scale * scale, offset);
    if (this._realTime) ret._realTime = true;
    return ret;
  },

  /* Change the scale of the clock, ensuring that readings continue to be
   * continuous */
  setScale: function(scale) {
    var samp = this.source();
    this.offset = (this.scale - scale) * samp + this.offset;
    this.scale = scale;
  },

  /* Change the scale of the clock relatively to the current one */
  changeScale: function(factor) {
    this.setScale(this.scale * factor);
  },

  /* Serialization boilerplate */
  constructor: Clock
};

/* Construct a clock that returns (optionally scaled) real time
 * The clock counts from zero */
Clock.realTime = function(scale, start) {
  if (scale == null) scale = 1.0;
  var offset = (start == null) ? null : start - performance.now() * scale;
  var ret = new Clock(function() {
    return performance.now() / 1000.0;
  }, scale, offset);
  ret._realTime = true;
  return ret;
};

/* Seralize a Clock */
Clock.__save__ = function(clock) {
  if (! clock._realTime) throw new Error("Clock not serializable!");
  return {scale: clock.scale, time: clock.now()};
};

/* Deserialize a Clock */
Clock.__restore__ = function(data) {
  return Clock.realTime(data.scale, data.time);
};

/* *** Scheduler ***
 * Schedules callbacks to happen at certain times as defined by a Clock
 * instance. */

/* Construct a new scheduler
 * requeue is a funtion that somehow ("magically") ensures the function
 * to it is asynchronously called again some short time later; tasks is an
 * ordered array of objects whose "time" property is used to determine when
 * they are to run; contTasks is an array of tasks to be run continuously,
 * i.e. at every call of run() (the same semantics as for tasks apply); clock
 * is a Clock instance determining the time this instance works with. The
 * "running" property is set to true; it can be used to stop the Scheduler.
 * To start it, ensure the "running" property is true and call the run()
 * method. */
function Scheduler(requeue, tasks, contTasks, clock) {
  if (tasks == null) tasks = [];
  if (contTasks == null) contTasks = [];
  if (clock == null) clock = Clock.realTime();
  this.requeue = requeue;
  this.tasks = tasks;
  this.contTasks = contTasks;
  this.clock = clock;
  this.running = true;
  this._idle = true;
}

Scheduler.prototype = {
  /* Queue the next run of the scheduler, and perform any tasks whose time
   * has come
   * After obtaining a timestamp from the clock, all tasks whose time
   * property is not less than the timestamp are removed from the queue and
   * run using runTask(); after that, if the "running" property is true,
   * requeue is called with a bound version of this.run as only argument to
   * trigger another execution. */
  run: function() {
    /* Abort if not running */
    if (! this.running) return;
    /* Obtain current timestamp */
    var now = this.clock.now();
    /* For each task that is (over)due */
    while (this.tasks[0] && this.tasks[0].time <= now) {
      /* Run it */
      this.runTask(this.tasks.shift(), now);
    }
    /* Run the continuous tasks */
    for (var i = 0; i < this.contTasks.length; i++) {
      this.runTask(this.contTasks[i], now);
    }
    /* Schedule next iteration */
    if (this.tasks.length || this.contTasks.length) {
      this.requeue(this.run.bind(this));
    } else {
      this._idle = true;
    }
  },

  /* Run a singular task, providing the given timestamp
   * The default implementation calls the task's "cb" (which is assumed to be
   * a function) with the value of now and the Scheduler instance as
   * arguments, and consumes exceptions by logging them to the console. */
  runTask: function(task, now) {
    try {
      task.cb(now, this);
    } catch (e) {
      console.error(e);
    }
  },

  /* Schedule a task to be run
   * If time is not null, it is inserted into task as the "time" property;
   * after that, the task is inserted at an appropriate position. */
  addTask: function(task, time) {
    if (time != null) task.time = time;
    time = task.time;
    var i;
    for (i = 0; i < this.tasks.length; i++) {
      if (this.tasks[i].time > time) break;
    }
    this.tasks.splice(0, i, task);
    if (this.running && this._idle) {
      this._idle = false;
      this.requeue(this.run.bind(this));
    }
  },

  /* Cancel all tasks */
  clear: function() {
    this.tasks.splice(0, this.tasks.length);
  },

  /* OOP boilerplate */
  constructor: Scheduler
};

/* Create a Scheduler for animations */
Scheduler.makeAnimated = function(clock) {
  var ret = new Scheduler(requestAnimationFrame.bind(window), null, null,
                          clock);
  ret._type = "animated";
  return ret;
};

/* Create a Scheduler that polls tasks at regular intervals */
Scheduler.makeStrobe = function(fps, clock) {
  var delay = 1000.0 / fps;
  var ret = new Scheduler(function(cb) {
    setTimeout(cb, delay);
  }, null, null, clock);
  ret._type = "strobe";
  ret._fps = fps;
  return ret;
};

/* Prepare for serializing a Scheduler */
Scheduler.__save__ = function(sched) {
  var ret = {type: sched._type, tasks: sched.tasks,
             contTasks: sched.contTasks, clock: sched.clock,
             running: sched.running};
  if (sched._type == "strobe") {
    ret.fps = sched._fps;
  } else if (sched._type != "animated") {
    throw new Error("Scheduler not serializable!");
  }
  return ret;
};

/* Deserialize a Scheduler */
Scheduler.__restore__ = function(data) {
  var ret;
  if (data.type == "animated") {
    ret = Scheduler.makeAnimated(data.clock);
  } else if (data.type == "strobe") {
    ret = Scheduler.makeStrobe(data.fps, data.clock);
  }
  ret.tasks = data.tasks;
  ret.contTasks = data.contTasks;
  ret.running = data.running;
  return ret;
};

/* *** Serialization ***
 * Serializes object trees (!) into JSON strings, allowing reified objects to
 * be of the correct type, to hook their (de)serialization process.
 * Input containing enumerable function properties is rejected (since those
 * are silently swallowed by JSON); use hooks to meaningfully handle them. */

/* Serialize an object tree to JSON, storing type information */
function serialize(obj) {
  return JSON.stringify(obj, function(name, value) {
    /* Fail verbosely */
    if (typeof value == "function")
      throw new Error("Cannot serialize function");
    /* Only transform object values */
    if (typeof value != "object" || Array.isArray(value)) return value;
    /* Get a meaningful constructor name */
    var cons = value.constructor.__sername__;
    if (! cons) cons = value.constructor.name;
    if (! cons) cons = Object.prototype.toString(value).slice(8, -1);
    if (cons == "Object") cons = undefined;
    /* Copy properties into new object, or let object serialize itself */
    var ret;
    if (value.constructor.__save__) {
      ret = value.constructor.__save__(value);
    } else {
      ret = {};
      for (var prop in value) ret[prop] = value[prop];
    }
    /* Add __type__ */
    ret.__type__ = cons;
    /* Done */
    return ret;
  });
}

/* Deserialize a JSON string into an object structure */
function deserialize(obj, env) {
  if (env == null) env = window;
  return JSON.parse(obj, function(name, value) {
    /* Ignore non-objects */
    if (typeof value != "object" || Array.isArray(value)) return value;
    /* Check for a __type__ */
    if (value.__type__) {
      /* Obtain type object */
      var type = env[value.__type__];
      if (type && type.__restore__) {
        /* Use restorer function */
        value = type.__restore__(value, env);
      } else if (type) {
        /* Assume an object is deserializable as-is */
        var newVal = Object.create(type.prototype);
        for (var k in value) if (! /^__.+__$/.test(k)) newVal[k] = value[k];
        value = newVal;
      } else {
        /* Nope */
        throw new Error("Object not deserializable (cannot find type): " +
                        JSON.stringify(value));
      }
    }
    return value;
  });
}
<|endoftext|>


<commit_before>// namespace
var MPLAY = MPLAY || {};

(function() {
	"use_strict";

	/**
	 *
	 * @class Page1
	 * @augments MPLAY.MPlayPage
	 */
	var Page1 = function() {
		MPLAY.MPlayPage.call(this);
	};

	Page1.prototype = Object.create(MPLAY.MPlayPage.prototype);
	Page1.prototype.constructor = Page1;

	/**
	 * @override
	 */
	Page1.prototype._onLoad = function() {
		MPLAY.MPlayPage.prototype._onLoad.call(this);

		this.setBackground("/static/gnovel/res/textures/backgrounds/uc final layers png.png");

		//create images
		this._professorImg = this.createImage("/static/gnovel/res/textures/char/sweeney-neutral.png", new THREE.Vector3(75, -180, 80), 600, 1030);
		this._priyaImg = this.createImage("/static/gnovel/res/textures/char/thoughtful-julia.png", new THREE.Vector3(-300, -140, 120), 600, 825);
		this._ryanImg = this.createImage("/static/gnovel/res/textures/char/ryan-happy.png", new THREE.Vector3(0, -110, 140), 600, 923);
		this._catImg = this.createImage("/static/gnovel/res/textures/char/cat-neutral.png", new THREE.Vector3(450, -130, 100), 600, 799);

		this._talked = 0;

		var pageObj = this;
		var io1 = this.createInteractableObject(
			"/static/gnovel/res/textures/Perspective-Button-Stop-icon.png",
			{x: -100, y: 200, width : 64, height : 64, onClick: function() {
				pageObj._talked = 1;
				pageObj._runFlow();
			}});

		var io2 = this.createInteractableObject(
			"/static/gnovel/res/textures/Perspective-Button-Stop-icon.png",
			{x: 100, y: 200, width : 64, height : 64, onClick: function() {
				pageObj._talked = 2;
				pageObj._runFlow();
			}});

		this._professorImg.material.opacity = 0;
		this._priyaImg.material.opacity = 0;
		this._ryanImg.material.opacity = 0;
		this._catImg.material.opacity = 0;

		this._professor = "professor";
		this._priya = "priya";
		this._ryan = "ryan";
		this._cat = "cat";

		// add object tags
		this._setObjectTag(this._professor, this._professorImg);
		this._setObjectTag(this._priya, this._priyaImg);
		this._setObjectTag(this._ryan, this._ryanImg);
		this._setObjectTag(this._cat, this._catImg);

	};

	Page1.prototype._createFlowElements = function() {
		var professor = "%professor";
		var priya = "%priya";
		var ryan = "%ryan";
		var cat = "%cat";
		var o = null;
		var isPhonePickedUp = 1;
		var isPhoneWithYou = 0;
		var player = "Lindsey";
		// this._talked = 1;

		if(this._talked == 0) {
			o = [
				{type: "show", img: professor, position: "center", waitUntilShown: false},
				{type: "dialog", speaker: "professor", text: "My aim in Programming and Society is to help you become a better programmer. Technology impacts how society operates. I will challenge you to look deeper into the programs, apps, and technologies that you use."},
				{type: "dialog", speaker: "professor", text: "The second half of each lesson will break into your assigned study groups. Please use this time wisely, you’ll have a group project later in the semester."},
				{type: "hide", img: professor, waitUntilHidden: false},
				{type: "show", img: ryan, position: "center", waitUntilShown: false},
				{type: "dialog", speaker: "ryan", text: "Awesome! Both you and Priya are in my group. This is Priya. She’s super smart, speaks like a bajillion languages. Too cool for me."},
				{type: "hide", img: ryan, waitUntilHidden: false},
				{type: "show", img: priya, position: "left", waitUntilShown: false},
				{type: "dialog", speaker: "priya", text: "RYAN here helped me with some of my writing last semester. Always willing to be my study partner. I think I annoyed him most of the time. Anyway, nice to meet you"},
				{type: "hide", img: priya, waitUntilHidden: false},
				{type: "show", img: cat, position: "right", waitUntilShown: false},
				{type: "dialog", speaker: "cat", text: "Hey I’m Cat. I’m in Tepper. I think I’m going to be in over my head a little here in a CS class It’s been an adjustment coming back to school."},
				{type: "hide", img: cat, waitUntilHidden: false},
				{type: "show", img: ryan, position: "center", waitUntilShown: false},
				{type: "dialog", speaker: "ryan", text: "Oh, don’t sweat it, Cat. We’ll help you out if you get stuck."},
				{type: "hide", img: ryan, waitUntilHidden: false},
				{type: "show", img: cat, waitUntilShown: false},
				{type: "dialog", speaker: "cat", text: "Sorry - I’m a little all over the place. I lost my phone yesterday."},
				{type: "hide", img: cat, waitUntilHidden: false},
				{type: "compare", leftop: isPhonePickedUp, operator: "equal", rightop: 1, goTrue: "#phone_picked", goFalse: "#phone_notpicked"},
				{type: "show", img: ryan, label: "phone_picked", waitUntilShown: false},
				{type: "dialog", speaker: "ryan", text: "Were you at Scottie’s Bar yesterday? " + player +" found a phone there."},
				{type: "hide", img: ryan, waitUntilHidden: false},
				{type: "show", img: cat, waitUntilShown: false},
				{type: "dialog", speaker: "cat", text: "Oh my God, do you guys have it with you?"},
				{type: "hide", img: cat, waitUntilHidden: false},
				{type: "show", img: ryan, waitUntilShown: false},
				{type: "compare", leftop: isPhoneWithYou, operator: "equal", rightop: 1, goTrue: "#phone_withyou", goFalse: "#phone_notwithyou"},
				{type: "dialog", speaker: "ryan", text: "Yeah, " + player + " has it, right?", label: "phone_withyou"},
				{type: "hide", img: ryan, waitUntilHidden: false},
				{type: "show", img: cat, waitUntilShown: false},
				{type: "dialog", speaker: "cat", text: "Oh my God - you charged it too? You’ve totally restored my faith in humanity."},
				{type: "jump", condition: true, goTrue: "#choices", goFalse: 1000},
				{type: "dialog", speaker: "ryan", text: "We left it with the bartender.", label: "phone_notwithyou"},
				{type: "hide", img: ryan, waitUntilHidden: false},
				{type: "show", img: cat, waitUntilShown: false},
				{type: "dialog", speaker: "cat", text: "Thank you! I’ll run over there after this. Lifesaver!"},
				{type: "choices", choices : [{text: "No Problem.", go: "#hidecat", relationship: {name:"cat", score:0}}, {text : "Happy to help.", go : "#hidecat", integrityScore: 0, relationship: {name:"cat", score:0}}], label: "choices"},
				{type: "hide", img: cat, label: "hidecat", waitUntilHidden: false},
				{type: "jump", condition: true, goTrue: 1000, goFalse: 1000},
				{type: "dialog", speaker: "ryan", text: "I think we saw a phone on the bar at Scotties, right? Maybe it’s yours.", label: "phone_notpicked"},
				{type: "dialog", speaker: "cat", text: "Oh, uh thanks. I’ll call them."},
				{type: "hide", img: cat, waitUntilHidden: false},
			];
		}
		else if(this._talked == 1) {
			o = [
				{type: "show", img: ryan, waitUntilShown: false},
				{type: "dialog", speaker: "ryan", text: "What did I tell you, that karma!"},
			];
		}
		else if(this._talked == 2) {
			o = [
				{type: "show", img: priya, waitUntilShown: false},
				{type: "dialog", speaker: "priya", text: "What are the chances!"},
			];
		}
		return o;
	}

	MPLAY.Page1 = Page1;
}());
<commit_msg>commented transitions of flows which not work<commit_after>// namespace
var MPLAY = MPLAY || {};

(function() {
	"use_strict";

	/**
	 *
	 * @class Page1
	 * @augments MPLAY.MPlayPage
	 */
	var Page1 = function() {
		MPLAY.MPlayPage.call(this);
	};

	Page1.prototype = Object.create(MPLAY.MPlayPage.prototype);
	Page1.prototype.constructor = Page1;

	/**
	 * @override
	 */
	Page1.prototype._onLoad = function() {
		MPLAY.MPlayPage.prototype._onLoad.call(this);

		this.setBackground("/static/gnovel/res/textures/backgrounds/uc final layers png.png");

		//create images
		this._professorImg = this.createImage("/static/gnovel/res/textures/char/sweeney-neutral.png", new THREE.Vector3(75, -180, 80), 600, 1030);
		this._priyaImg = this.createImage("/static/gnovel/res/textures/char/thoughtful-julia.png", new THREE.Vector3(-300, -140, 120), 600, 825);
		this._ryanImg = this.createImage("/static/gnovel/res/textures/char/ryan-happy.png", new THREE.Vector3(0, -110, 140), 600, 923);
		this._catImg = this.createImage("/static/gnovel/res/textures/char/cat-neutral.png", new THREE.Vector3(450, -130, 100), 600, 799);

		this._talked = 0;

		var pageObj = this;
		var io1 = this.createInteractableObject(
			"/static/gnovel/res/textures/Perspective-Button-Stop-icon.png",
			{x: -100, y: 200, width : 64, height : 64, onClick: function() {
				pageObj._talked = 1;
				pageObj._runFlow();
			}});

		var io2 = this.createInteractableObject(
			"/static/gnovel/res/textures/Perspective-Button-Stop-icon.png",
			{x: 100, y: 200, width : 64, height : 64, onClick: function() {
				pageObj._talked = 2;
				pageObj._runFlow();
			}});

		this._professorImg.material.opacity = 0;
		this._priyaImg.material.opacity = 0;
		this._ryanImg.material.opacity = 0;
		this._catImg.material.opacity = 0;

		this._professor = "professor";
		this._priya = "priya";
		this._ryan = "ryan";
		this._cat = "cat";

		// add object tags
		this._setObjectTag(this._professor, this._professorImg);
		this._setObjectTag(this._priya, this._priyaImg);
		this._setObjectTag(this._ryan, this._ryanImg);
		this._setObjectTag(this._cat, this._catImg);

	};

	Page1.prototype._createFlowElements = function() {
		var professor = "%professor";
		var priya = "%priya";
		var ryan = "%ryan";
		var cat = "%cat";
		var o = null;
		var isPhonePickedUp = 1;
		var isPhoneWithYou = 0;
		var player = "Lindsey";
		// this._talked = 1;

		if(this._talked == 0) {
			o = [
				// transition of this flow doesn't work
				{type: "show", img: professor, position: "center", waitUntilShown: false},
				{type: "dialog", speaker: "professor", text: "My aim in Programming and Society is to help you become a better programmer. Technology impacts how society operates. I will challenge you to look deeper into the programs, apps, and technologies that you use."},
				{type: "dialog", speaker: "professor", text: "The second half of each lesson will break into your assigned study groups. Please use this time wisely, you’ll have a group project later in the semester."},
				{type: "hide", img: professor, waitUntilHidden: false},
				{type: "show", img: ryan, position: "center", waitUntilShown: false},
				{type: "dialog", speaker: "ryan", text: "Awesome! Both you and Priya are in my group. This is Priya. She’s super smart, speaks like a bajillion languages. Too cool for me."},
				// transition of this flow doesn't work
				{type: "hide", img: ryan, waitUntilHidden: false},
				// transition of this flow doesn't work
				{type: "show", img: priya, position: "left", waitUntilShown: false},
				{type: "dialog", speaker: "priya", text: "RYAN here helped me with some of my writing last semester. Always willing to be my study partner. I think I annoyed him most of the time. Anyway, nice to meet you"},
				// transition of this flow doesn't work
				{type: "hide", img: priya, waitUntilHidden: false},
				// transition of this flow doesn't work
				{type: "show", img: cat, position: "right", waitUntilShown: false},
				{type: "dialog", speaker: "cat", text: "Hey I’m Cat. I’m in Tepper. I think I’m going to be in over my head a little here in a CS class It’s been an adjustment coming back to school."},
				{type: "hide", img: cat, waitUntilHidden: false},
				{type: "show", img: ryan, position: "center", waitUntilShown: false},
				{type: "dialog", speaker: "ryan", text: "Oh, don’t sweat it, Cat. We’ll help you out if you get stuck."},
				{type: "hide", img: ryan, waitUntilHidden: false},
				{type: "show", img: cat, waitUntilShown: false},
				{type: "dialog", speaker: "cat", text: "Sorry - I’m a little all over the place. I lost my phone yesterday."},
				{type: "hide", img: cat, waitUntilHidden: false},
				{type: "compare", leftop: isPhonePickedUp, operator: "equal", rightop: 1, goTrue: "#phone_picked", goFalse: "#phone_notpicked"},
				{type: "show", img: ryan, label: "phone_picked", waitUntilShown: false},
				{type: "dialog", speaker: "ryan", text: "Were you at Scottie’s Bar yesterday? " + player +" found a phone there."},
				{type: "hide", img: ryan, waitUntilHidden: false},
				{type: "show", img: cat, waitUntilShown: false},
				{type: "dialog", speaker: "cat", text: "Oh my God, do you guys have it with you?"},
				{type: "hide", img: cat, waitUntilHidden: false},
				{type: "show", img: ryan, waitUntilShown: false},
				{type: "compare", leftop: isPhoneWithYou, operator: "equal", rightop: 1, goTrue: "#phone_withyou", goFalse: "#phone_notwithyou"},
				{type: "dialog", speaker: "ryan", text: "Yeah, " + player + " has it, right?", label: "phone_withyou"},
				{type: "hide", img: ryan, waitUntilHidden: false},
				{type: "show", img: cat, waitUntilShown: false},
				{type: "dialog", speaker: "cat", text: "Oh my God - you charged it too? You’ve totally restored my faith in humanity."},
				{type: "jump", condition: true, goTrue: "#choices", goFalse: 1000},
				{type: "dialog", speaker: "ryan", text: "We left it with the bartender.", label: "phone_notwithyou"},
				{type: "hide", img: ryan, waitUntilHidden: false},
				{type: "show", img: cat, waitUntilShown: false},
				{type: "dialog", speaker: "cat", text: "Thank you! I’ll run over there after this. Lifesaver!"},
				{type: "choices", choices : [{text: "No Problem.", go: "#hidecat", relationship: {name:"cat", score:0}}, {text : "Happy to help.", go : "#hidecat", integrityScore: 0, relationship: {name:"cat", score:0}}], label: "choices"},
				{type: "hide", img: cat, label: "hidecat", waitUntilHidden: false},
				{type: "jump", condition: true, goTrue: 1000, goFalse: 1000},
				{type: "dialog", speaker: "ryan", text: "I think we saw a phone on the bar at Scotties, right? Maybe it’s yours.", label: "phone_notpicked"},
				{type: "dialog", speaker: "cat", text: "Oh, uh thanks. I’ll call them."},
				{type: "hide", img: cat, waitUntilHidden: false},
			];
		}
		else if(this._talked == 1) {
			o = [
				{type: "show", img: ryan, waitUntilShown: false},
				{type: "dialog", speaker: "ryan", text: "What did I tell you, that karma!"},
			];
		}
		else if(this._talked == 2) {
			o = [
				{type: "show", img: priya, waitUntilShown: false},
				{type: "dialog", speaker: "priya", text: "What are the chances!"},
			];
		}
		return o;
	}

	MPLAY.Page1 = Page1;
}());
<|endoftext|>


<commit_before>// import moment from 'moment'
import React, { Component } from 'react'
import { Link } from 'react-router-dom'
import PropTypes from 'prop-types'
import TweetEmbed from 'react-tweet-embed'
import FindMe from './FindMe'

import Grid from '@material-ui/core/Grid'
import Typography from '@material-ui/core/Typography'
import Card from '@material-ui/core/Card'
import CardContent from '@material-ui/core/CardContent'
import Checkbox from '@material-ui/core/Checkbox'
import FormGroup from '@material-ui/core/FormGroup'
import FormControlLabel from '@material-ui/core/FormControlLabel'
import FormControl from '@material-ui/core/FormControl'
import Button from '@material-ui/core/Button'
import TextField from '@material-ui/core/TextField'
import Paper from '@material-ui/core/Paper'
import IconButton from '@material-ui/core/IconButton'

import listStyle from './CollectionList.css'
import style from './Collection.css'
import card from '../Card.css'

export default class CollectionList extends Component {
  constructor(props) {
    super(props)
    this.state = {
      checkedTweets: [],
      findUser: '',
      findingUser: false
    }
    this.randomTweet = Math.floor(Math.random() * (98))
  }

  componentDidMount() {
    this.tick()
    this.props.getTweets(this.props.searchId)
    this.props.getUsers(this.props.searchId)
    this.timerId = setInterval(() => {
      this.tick()
    }, 3000)
  }

  componentWillUnmount() {
    clearInterval(this.timerId)
  }

  tick() {
    this.props.getSearch(this.props.searchId)
    this.props.getFoundInSearches()

    const foundTweets = this.props.user.foundInSearches[this.props.searchId] || []
    if (this.state.checkedTweets.length === 0 && foundTweets.length > 0) {
      this.setState({
        checkedTweets: foundTweets.map(() => false)
      })
    }
  }

  handleFindUserInput(user) {
    const findingUser = user === '' ? false : this.state.findingUser
    this.setState({
      findUser: user,
      findingUser
    })
  }

  findUser() {
    if (this.state.findUser !== '') {
      this.setState({
        findingUser: true
      })
      this.props.getTweetsForUser(this.props.searchId, this.state.findUser)
    }
  }

  setAllTweets(checked) {
    this.setState({
      checkedTweets: this.state.checkedTweets.map(() => checked)
    })
  }

  toggleOneTweet(i) {
    this.setState({
      checkedTweets: this.state.checkedTweets.map((v, tIdx) => {return (i === tIdx ? !v : v)})
    })
  }

  render() {
    // don't render until we at least know the title of the collection
    if (!this.props.search.title) {
      return

    }

    const tweetCount = this.props.search.tweetCount.toLocaleString()

    const contact = this.props.search.creator.email
      ? <a href={`mailto:${this.props.search.creator.email}`}>{this.props.search.creator.email}
      : 'No contact provided.'
    let tweets = 'Loading tweets...'
    if (this.props.search.tweets.length > 0) {
      tweets = this.props.search.tweets.slice(this.randomTweet, this.randomTweet + 2).map((t, i) => {
        return <TweetEmbed key={`t${i}`} id={t.id} />
      })
    }

    let userTweets = (

      <Typography variant="body1">Authenticate to Twitter to find out if any of your tweets are
      in this collection.</Typography>
      <Typography variant="body1">When you authenticate, you can specify consent, request removal,
      or start a conversation with the collector about your content.</Typography>

)

    if (this.props.user) {
      const foundTweets = this.props.user.foundInSearches[this.props.searchId] || []
      if (foundTweets.length > 0) {
        userTweets = (<>
          <FormControl component="fieldset" className={style.CardInnerContent}>
            <FormGroup row>
              <FormControlLabel
                value="all"
                control={<Checkbox color="primary"
                  onChange={t => this.setAllTweets(t.target.checked)}
                  checked={this.state.checkedTweets.indexOf(false) === -1} />}
                label={`Select all ${foundTweets.length} tweets`}
              />
            </FormGroup>
          </FormControl>
          <Button size="small">Specify/Adjust Consent</Button>

          {foundTweets.map((tweetId, i) => {
            return (
              <Grid container spacing={0} key={`ut${i}`}>
                <Grid item xs={2}><Checkbox color="primary" checked={this.state.checkedTweets[i] || false} onChange={() => this.toggleOneTweet(i)} /></Grid>
                <Grid item xs={10}><TweetEmbed id={tweetId} /></Grid>
              </Grid>
            )
          })}
        </>)
      } else {
        userTweets = <Typography variant="body1">There are no tweets by you in this collection.</Typography>
      }
    }

    let usersInfo = (

      <Typography variant="body2">Showing {this.props.search.users.length} of {this.props.search.userCount} users.</Typography>
      {this.props.search.users.map((u, i) => {
        return <img className={style.UserImg}
          src={u.avatarUrl}
          alt={u.screenName}
          title={u.screenName} key={`u${i}`} />
      })}

)

    if (this.state.findingUser) {
      if (this.props.foundUserTweets > 0) {
        usersInfo = (

{this.props.search.users.filter(u => u.screenName === this.state.findUser).map((u, i) => {
            return <img className={style.UserImg}
              src={u.avatarUrl}
              alt={u.screenName}
              title={u.screenName} key={`u${i}`} />
          })}

 <a href={`https://twitter.com/${this.state.findUser}`}>@{this.state.findUser}

          <Typography variant="body2">
            Found {this.props.foundUserTweets} tweet{this.props.foundUserTweets > 1 ? 's' : ''} by this user.
          </Typography>

)
      } else {
        usersInfo = <Typography variant="body2">Could not find user "{this.state.findUser}".</Typography>
      }
    }

    return (
      <>
        <Grid container spacing={3} className={listStyle.Header}>
          <Grid item xs={12} className={listStyle.Title}>
            <Typography variant="h2">
              <Link to="/collections">ALL COLLECTIONS</Link> ➔ {this.props.search.title.toUpperCase()}
            </Typography>
          </Grid>
          <Grid item xs={12}>
            <Typography variant="body1">
              { this.props.search.description || 'No description provided for this collection.' }
            </Typography>
          </Grid>
          <Grid item xs={2}>
            <Typography variant="body1">
              Collected by: <a href={`https://twitter.com/${this.props.search.creator.twitterScreenName}`}>
                @{this.props.search.creator.twitterScreenName}
            </Typography>
          </Grid>
          <Grid item xs={2}>
            <Typography variant="body1">
              Contact: {contact}
            </Typography>
          </Grid>
        </Grid>

        <div className={`${card.CardHolder} ${style.CardHolder}`}>
          <Card raised className={`${card.Card} ${style.Card}`} >
            <CardContent>

                <FindMe user={this.props.user} dest={`/collection/${this.props.searchId}`}/>

              {userTweets}
            </CardContent>
          </Card>
          <Card raised className={`${card.Card} ${style.Card}`} >
            <CardContent>

                <Paper id="box" elevation={4} className={style.Search}>
                  <TextField name="usersearch" className={style.SearchInput}
                    onChange={(e) => this.handleFindUserInput(e.target.value)} />
                  <IconButton color="primary" onClick={() => this.findUser()}>
                    <ion-icon name="search"></ion-icon>
                  </IconButton>
                </Paper>

              {usersInfo}
            </CardContent>
          </Card>
          <Card raised className={`${card.Card} ${style.Card}`} >
            <CardContent>
              <Typography variant="h2" className={style.CardTitle}>
                {tweetCount} tweets (all users)
              </Typography>
              <Typography variant="body2">Showing 2 random tweets from the collection.</Typography>
              {tweets}
            </CardContent>
          </Card>

      </>
    )
  }
}

CollectionList.propTypes = {
  user: PropTypes.object,
  searchId: PropTypes.string,
  search: PropTypes.object,
  getSearch: PropTypes.func,
  getTweets: PropTypes.func,
  getUsers: PropTypes.func,
  getFoundInSearches: PropTypes.func,
  getTweetsForUser: PropTypes.func,
  foundUserTweets: PropTypes.bool
}
<commit_msg>simplified user lookup display becuase not all user info may be available<commit_after>// import moment from 'moment'
import React, { Component } from 'react'
import { Link } from 'react-router-dom'
import PropTypes from 'prop-types'
import TweetEmbed from 'react-tweet-embed'
import FindMe from './FindMe'

import Grid from '@material-ui/core/Grid'
import Typography from '@material-ui/core/Typography'
import Card from '@material-ui/core/Card'
import CardContent from '@material-ui/core/CardContent'
import Checkbox from '@material-ui/core/Checkbox'
import FormGroup from '@material-ui/core/FormGroup'
import FormControlLabel from '@material-ui/core/FormControlLabel'
import FormControl from '@material-ui/core/FormControl'
import Button from '@material-ui/core/Button'
import TextField from '@material-ui/core/TextField'
import Paper from '@material-ui/core/Paper'
import IconButton from '@material-ui/core/IconButton'

import listStyle from './CollectionList.css'
import style from './Collection.css'
import card from '../Card.css'

export default class CollectionList extends Component {
  constructor(props) {
    super(props)
    this.state = {
      checkedTweets: [],
      findUser: '',
      findingUser: false,
      lastUserLookup: ''
    }
    this.randomTweet = Math.floor(Math.random() * (98))
  }

  componentDidMount() {
    this.tick()
    this.props.getTweets(this.props.searchId)
    this.props.getUsers(this.props.searchId)
    this.timerId = setInterval(() => {
      this.tick()
    }, 3000)
  }

  componentWillUnmount() {
    clearInterval(this.timerId)
  }

  tick() {
    this.props.getSearch(this.props.searchId)
    this.props.getFoundInSearches()

    const foundTweets = this.props.user.foundInSearches[this.props.searchId] || []
    if (this.state.checkedTweets.length === 0 && foundTweets.length > 0) {
      this.setState({
        checkedTweets: foundTweets.map(() => false)
      })
    }
  }

  handleFindUserInput(user) {
    const findingUser = user === '' ? false : this.state.findingUser
    this.setState({
      findUser: user,
      findingUser
    })
  }

  findUser() {
    if (this.state.findUser !== '') {
      this.setState({
        findingUser: true,
        lastUserLookup: this.state.findUser
      })
      this.props.getTweetsForUser(this.props.searchId, this.state.findUser)
    }
  }

  setAllTweets(checked) {
    this.setState({
      checkedTweets: this.state.checkedTweets.map(() => checked)
    })
  }

  toggleOneTweet(i) {
    this.setState({
      checkedTweets: this.state.checkedTweets.map((v, tIdx) => {return (i === tIdx ? !v : v)})
    })
  }

  render() {
    // don't render until we at least know the title of the collection
    if (!this.props.search.title) {
      return

    }

    const tweetCount = this.props.search.tweetCount.toLocaleString()

    const contact = this.props.search.creator.email
      ? <a href={`mailto:${this.props.search.creator.email}`}>{this.props.search.creator.email}
      : 'No contact provided.'
    let tweets = 'Loading tweets...'
    if (this.props.search.tweets.length > 0) {
      tweets = this.props.search.tweets.slice(this.randomTweet, this.randomTweet + 2).map((t, i) => {
        return <TweetEmbed key={`t${i}`} id={t.id} />
      })
    }

    let userTweets = (

      <Typography variant="body1">Authenticate to Twitter to find out if any of your tweets are
      in this collection.</Typography>
      <Typography variant="body1">When you authenticate, you can specify consent, request removal,
      or start a conversation with the collector about your content.</Typography>

)

    if (this.props.user) {
      const foundTweets = this.props.user.foundInSearches[this.props.searchId] || []
      if (foundTweets.length > 0) {
        userTweets = (<>
          <FormControl component="fieldset" className={style.CardInnerContent}>
            <FormGroup row>
              <FormControlLabel
                value="all"
                control={<Checkbox color="primary"
                  onChange={t => this.setAllTweets(t.target.checked)}
                  checked={this.state.checkedTweets.indexOf(false) === -1} />}
                label={`Select all ${foundTweets.length} tweets`}
              />
            </FormGroup>
          </FormControl>
          <Button size="small">Specify/Adjust Consent</Button>

          {foundTweets.map((tweetId, i) => {
            return (
              <Grid container spacing={0} key={`ut${i}`}>
                <Grid item xs={2}><Checkbox color="primary" checked={this.state.checkedTweets[i] || false} onChange={() => this.toggleOneTweet(i)} /></Grid>
                <Grid item xs={10}><TweetEmbed id={tweetId} /></Grid>
              </Grid>
            )
          })}
        </>)
      } else {
        userTweets = <Typography variant="body1">There are no tweets by you in this collection.</Typography>
      }
    }

    let usersInfo = (

      <Typography variant="body2">Showing {this.props.search.users.length} of {this.props.search.userCount} users.</Typography>
      {this.props.search.users.map((u, i) => {
        return <img className={style.UserImg}
          src={u.avatarUrl}
          alt={u.screenName}
          title={u.screenName} key={`u${i}`} />
      })}

)

    if (this.state.findingUser) {
      if (this.props.foundUserTweets > 0) {
        usersInfo = (
          <Typography variant="body2">
            Found {this.props.foundUserTweets} tweet{this.props.foundUserTweets > 1 ? 's' : ''} by
            <a href={`https://twitter.com/${this.state.lastUserLookup}`}>@{this.state.lastUserLookup}.
          </Typography>)
      } else {
        usersInfo = <Typography variant="body2">Could not find user "{this.state.lastUserLookup}".</Typography>
      }
    }

    return (
      <>
        <Grid container spacing={3} className={listStyle.Header}>
          <Grid item xs={12} className={listStyle.Title}>
            <Typography variant="h2">
              <Link to="/collections">ALL COLLECTIONS</Link> ➔ {this.props.search.title.toUpperCase()}
            </Typography>
          </Grid>
          <Grid item xs={12}>
            <Typography variant="body1">
              { this.props.search.description || 'No description provided for this collection.' }
            </Typography>
          </Grid>
          <Grid item xs={2}>
            <Typography variant="body1">
              Collected by: <a href={`https://twitter.com/${this.props.search.creator.twitterScreenName}`}>
                @{this.props.search.creator.twitterScreenName}
            </Typography>
          </Grid>
          <Grid item xs={2}>
            <Typography variant="body1">
              Contact: {contact}
            </Typography>
          </Grid>
        </Grid>

        <div className={`${card.CardHolder} ${style.CardHolder}`}>
          <Card raised className={`${card.Card} ${style.Card}`} >
            <CardContent>

                <FindMe user={this.props.user} dest={`/collection/${this.props.searchId}`}/>

              {userTweets}
            </CardContent>
          </Card>
          <Card raised className={`${card.Card} ${style.Card}`} >
            <CardContent>

                <Paper id="box" elevation={4} className={style.Search}>
                  <TextField name="usersearch" className={style.SearchInput}
                    onChange={(e) => this.handleFindUserInput(e.target.value)} />
                  <IconButton color="primary" onClick={() => this.findUser()}>
                    <ion-icon name="search"></ion-icon>
                  </IconButton>
                </Paper>

              {usersInfo}
            </CardContent>
          </Card>
          <Card raised className={`${card.Card} ${style.Card}`} >
            <CardContent>
              <Typography variant="h2" className={style.CardTitle}>
                {tweetCount} tweets (all users)
              </Typography>
              <Typography variant="body2">Showing 2 random tweets from the collection.</Typography>
              {tweets}
            </CardContent>
          </Card>

      </>
    )
  }
}

CollectionList.propTypes = {
  user: PropTypes.object,
  searchId: PropTypes.string,
  search: PropTypes.object,
  getSearch: PropTypes.func,
  getTweets: PropTypes.func,
  getUsers: PropTypes.func,
  getFoundInSearches: PropTypes.func,
  getTweetsForUser: PropTypes.func,
  foundUserTweets: PropTypes.bool
}
<|endoftext|>


<commit_before>define([
    "jquery",
    "../core/logger",
    "../utils",
    "../registry",
    "jquery_fullcalendar"
], function($, logger, utils, registry) {
    var log = logger.getLogger("pat.fullcalendar");

    var fullcalendar = {
        name: "fullcalendar",
        trigger: ".pat-fullcalendar",

        init: function($calroot) {
            // XXX: should be within the calendar
            var $filter = $(".calendar-filters");
            var initMonths = function($root) {
                if ($root.hasClass("month")) {
                    fullcalendar.initMonth($root, $filter);
                } else {
                    $root.find(".month").each(function() {
                        fullcalendar.initMonth($(this), $filter);
                    });
                }
            };

            // hide all group checkboxes, will be shown if mentioned
            $filter.find(".check-list .groups label").hide();

            // initialize existing months
            initMonths($calroot);

            // wait for additional months
            $calroot.on("patterns-injected.pat-fullcalendar", function(ev) {
                initMonths($(ev.target));
            });
        },

        initMonth: function($month, $filter) {
            var $events = $(".events", $month);
            if ($events.length === 0) { return; }
            var ym = $("time", $month).attr("datetime").split("-"),
                year = ym[0],
                month = Number(ym[1]) - 1,
                $calendar = $("
\n
")
                    .insertAfter($events);
            var refetch = function() {
                $calendar.fullCalendar("refetchEvents");
                // XXX: replace with mutator event listener
                registry.scan($calendar);
            };
            var refetch_deb = utils.debounce(refetch, 400);
            if ($filter && $filter.length > 0) {
                $(".searchText", $filter).on("keyup", refetch_deb);
                $(".searchText[type=search]", $filter).on("click", refetch_deb);
                $("select[name=state]", $filter).on("change", refetch);
                $(".check-list", $filter).on("change", refetch);
            }
            $events.css("display", "None");
            $calendar.fullCalendar({
                disableDragging: "true",
                dayDblClick: function(/* date, allDay, jsEvent, view */) {
                    // XXX: add event
                },
                events: function(start, end, callback) {
                    var events = fullcalendar.parseEvents($events, $filter);
                    callback(events);
                },
                eventDrop: function(event, dayDelta, minuteDelta, allDay, revertFunc /*, jsEvent, ui, view */) {
                    // XXX: change event
                    revertFunc();
                },
                eventResize: function(event, dayDelta, minuteDelta, revertFunc /*, jsEvent, ui, view */) {
                    // XXX: change event
                    revertFunc();
                },
                header: { left: "", right: "" },
                month: month,
                year: year
            });
            registry.scan($calendar);
        },

        parseEvents: function($events, $filter) {
            // show groups that are mentioned
            $filter.find(
                ".check-list .groups label:hidden"
            ).each(function() {
                var $label = $(this),
                    id = $label.find("input").attr("name"),
                    groupsel = ".group-" + id;
                if ($events.find(groupsel).length > 0) $label.show();
            });

            // OPTINAL: go through other filters and gray out groups that would
            // result in zero matches

            var noattendees = true;

            // parse filters
            if ($filter && $filter.length > 0) {
                var searchText = $(".searchText", $filter).val(),
                    state = $("select[name=state]").val(),
                    $attendees = $(".attendees", $filter),
                    onlyusers = $attendees.is(":has([name=\"only-users\"])"),
                    // XXX: only take visible groups into account
                    groupsel = $(".groups input:checked", $attendees).map(function() {
                        var id = $(this).attr("name");
                        return ".attendees .group-" + id;
                    }).toArray().join(",");

                noattendees = $attendees.is(":has([name=\"no-attendees\"]:checked)");
            }

            var events = $events.find(".event").filter(function() {
                var $event = $(this);
                // workflow state
                if (state && state !== "all") {
                    if (!$event.hasClass(".state-" + state)) {
                        log.debug("filter denied state", $event);
                        return false;
                    }
                }

                if ($event.find(".attendees *").length > 0) {
                    if ($event.find(".attendees .group").length > 0) {
                        if ($event.find(groupsel).length === 0) {
                            log.debug("filter denied groups", $event);
                            return false;
                        }
                    } else if (!onlyusers) {
                        log.debug("filter denied onlyusers", $event);
                        return false;
                    }
                } else if (!noattendees) {
                    log.debug("filter denied noattendees", $event);
                    return false;
                }

                // full text search
                if (searchText && !$event.is(":Contains(" + searchText + ")")) {
                    log.debug("filter denied fulltext", $event);
                    return false;
                }

                return true;
            }).map(function(idx, event) {
                var classNames = $(event).attr("class").split(/\s+/).filter(function(cls) {
                    return (cls !== "event");
                }).concat($("a", event).attr("class").split(/\s+/));
                var allattrs = $("a", event)[0].attributes,
                    attrs = {};
                for (var attr, i=0; i<allattrs.length; i++){
                    attr = allattrs.item(i);
                    if (attr.nodeName.slice(0,5) === "data-") {
                        attrs[attr.nodeName] = attr.nodeValue;
                    }
                }
                var location = ($(".location", event).html() || "").trim();
                var ev = {
                    title: $(".title", event).html().trim() +
                        (location ? (" (" + location + ")") : ""),
                    start: $(".start", event).attr("datetime"),
                    end: $(".end", event).attr("datetime"),
                    allDay: $(event).hasClass("all-day"),
                    url: $("a", event).attr("href"),
                    className: classNames,
                    attrs: attrs,
                    editable: $(event).hasClass("editable")
                };
                if (!ev.title) log.error("No event title for:", event);
                if (!ev.start) log.error("No event start for:", event);
                if (!ev.url) log.error("No event url for:", event);
                return ev;
            }).toArray();
            return events;
        }
    };

    registry.register(fullcalendar);
});
// jshint indent: 4, browser: true, jquery: true, quotmark: double
// vim: sw=4 expandtab
<commit_msg>Fix jshint errors in fullcalendar.js<commit_after>define([
    "jquery",
    "../core/logger",
    "../utils",
    "../registry",
    "jquery_fullcalendar"
], function($, logger, utils, registry) {
    "use strict";

    var log = logger.getLogger("pat.fullcalendar");

    var fullcalendar = {
        name: "fullcalendar",
        trigger: ".pat-fullcalendar",

        init: function($calroot) {
            // XXX: should be within the calendar
            var $filter = $(".calendar-filters");
            var initMonths = function($root) {
                if ($root.hasClass("month")) {
                    fullcalendar.initMonth($root, $filter);
                } else {
                    $root.find(".month").each(function() {
                        fullcalendar.initMonth($(this), $filter);
                    });
                }
            };

            // hide all group checkboxes, will be shown if mentioned
            $filter.find(".check-list .groups label").hide();

            // initialize existing months
            initMonths($calroot);

            // wait for additional months
            $calroot.on("patterns-injected.pat-fullcalendar", function(ev) {
                initMonths($(ev.target));
            });
        },

        initMonth: function($month, $filter) {
            var $events = $(".events", $month);
            if ($events.length === 0) { return; }
            var ym = $("time", $month).attr("datetime").split("-"),
                year = ym[0],
                month = Number(ym[1]) - 1,
                $calendar = $("
\n
")
                    .insertAfter($events);
            var refetch = function() {
                $calendar.fullCalendar("refetchEvents");
                // XXX: replace with mutator event listener
                registry.scan($calendar);
            };
            var refetch_deb = utils.debounce(refetch, 400);
            if ($filter && $filter.length > 0) {
                $(".searchText", $filter).on("keyup", refetch_deb);
                $(".searchText[type=search]", $filter).on("click", refetch_deb);
                $("select[name=state]", $filter).on("change", refetch);
                $(".check-list", $filter).on("change", refetch);
            }
            $events.css("display", "None");
            $calendar.fullCalendar({
                disableDragging: "true",
                dayDblClick: function(/* date, allDay, jsEvent, view */) {
                    // XXX: add event
                },
                events: function(start, end, callback) {
                    var events = fullcalendar.parseEvents($events, $filter);
                    callback(events);
                },
                eventDrop: function(event, dayDelta, minuteDelta, allDay, revertFunc /*, jsEvent, ui, view */) {
                    // XXX: change event
                    revertFunc();
                },
                eventResize: function(event, dayDelta, minuteDelta, revertFunc /*, jsEvent, ui, view */) {
                    // XXX: change event
                    revertFunc();
                },
                header: { left: "", right: "" },
                month: month,
                year: year
            });
            registry.scan($calendar);
        },

        parseEvents: function($events, $filter) {
            // show groups that are mentioned
            $filter.find(
                ".check-list .groups label:hidden"
            ).each(function() {
                var $label = $(this),
                    id = $label.find("input").attr("name"),
                    groupsel = ".group-" + id;
                if ($events.find(groupsel).length > 0) $label.show();
            });

            // OPTINAL: go through other filters and gray out groups that would
            // result in zero matches

            var groupsel,
                noattendees = true,
                onlyusers,
                searchText,
                state,
                $attendees;

            // parse filters
            if ($filter && $filter.length > 0) {
                searchText = $(".searchText", $filter).val();
                state = $("select[name=state]").val();
                $attendees = $(".attendees", $filter);
                onlyusers = $attendees.is(":has([name=\"only-users\"])");
                // XXX: only take visible groups into account
                groupsel = $(".groups input:checked", $attendees).map(function() {
                    var id = $(this).attr("name");
                    return ".attendees .group-" + id;
                }).toArray().join(",");

                noattendees = $attendees.is(":has([name=\"no-attendees\"]:checked)");
            }

            var events = $events.find(".event").filter(function() {
                var $event = $(this);
                // workflow state
                if (state && state !== "all") {
                    if (!$event.hasClass(".state-" + state)) {
                        log.debug("filter denied state", $event);
                        return false;
                    }
                }

                if ($event.find(".attendees *").length > 0) {
                    if ($event.find(".attendees .group").length > 0) {
                        if ($event.find(groupsel).length === 0) {
                            log.debug("filter denied groups", $event);
                            return false;
                        }
                    } else if (!onlyusers) {
                        log.debug("filter denied onlyusers", $event);
                        return false;
                    }
                } else if (!noattendees) {
                    log.debug("filter denied noattendees", $event);
                    return false;
                }

                // full text search
                if (searchText && !$event.is(":Contains(" + searchText + ")")) {
                    log.debug("filter denied fulltext", $event);
                    return false;
                }

                return true;
            }).map(function(idx, event) {
                var classNames = $(event).attr("class").split(/\s+/).filter(function(cls) {
                    return (cls !== "event");
                }).concat($("a", event).attr("class").split(/\s+/));
                var allattrs = $("a", event)[0].attributes,
                    attrs = {};
                for (var attr, i=0; i<allattrs.length; i++){
                    attr = allattrs.item(i);
                    if (attr.nodeName.slice(0,5) === "data-") {
                        attrs[attr.nodeName] = attr.nodeValue;
                    }
                }
                var location = ($(".location", event).html() || "").trim();
                var ev = {
                    title: $(".title", event).html().trim() +
                        (location ? (" (" + location + ")") : ""),
                    start: $(".start", event).attr("datetime"),
                    end: $(".end", event).attr("datetime"),
                    allDay: $(event).hasClass("all-day"),
                    url: $("a", event).attr("href"),
                    className: classNames,
                    attrs: attrs,
                    editable: $(event).hasClass("editable")
                };
                if (!ev.title) log.error("No event title for:", event);
                if (!ev.start) log.error("No event start for:", event);
                if (!ev.url) log.error("No event url for:", event);
                return ev;
            }).toArray();
            return events;
        }
    };

    registry.register(fullcalendar);
});
// jshint indent: 4, browser: true, jquery: true, quotmark: double
// vim: sw=4 expandtab
<|endoftext|>


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

function exec(cmd) {

    return co(function* () {
        var bot = cmd.bot;
        var msg = cmd.msg;
        var args = cmd.args;
        var config = cmd.config;

        if(args.length === 0) {
            return bot.sendMessage(msg,
                "```ruby\n"+
                "Channel: "+config.welcome.channel+"\n"+
                "Enabled: "+config.welcome.enabled+"\n"+
                "Message:\n"+config.welcome.msg+"```"
            );
        }

        switch (args.shift().toLowerCase()) {
            case 'enable':
                config.welcome.enabled = true;
                yield config.storage.setItem('welcome', config.welcome);
                return bot.sendMessage(msg, "welcome message enabled");
            case 'disable':
                config.welcome.enabled = false;
                yield config.storage.setItem('welcome', config.welcome);
                return bot.sendMessage(msg, "welcome message disabled");
            case 'channel':

                if (args.length === 0) {
                    return bot.sendMessage(msg, "no channel specified");
                }
                var channel = args[0];

                // check if the channel exists
                if (!msg.channel.server.channels.get("name", channelName)) {
                    return bot.sendMessage(msg, "channel `" + channel + "` not found on the server");
                }

                // update the channel
                config.welcome.channel = channel;

                // save the settings
                yield config.storage.setItem('welcome', config.welcome);
                return bot.sendMessage(msg, "changed welcome channel to `"+channel+"`");
            case 'msg':
                if (args.length === 0) {
                    // send a list of roles:
                    return bot.sendMessage(msg, "no msg specified");
                }

                // return the message back to original
                config.welcome.msg = args.join(" ");
                yield config.storage.setItem('welcome', config.welcome);
                return bot.sendMessage(msg, "changed welcome message to:\n```\n"+config.welcome.msg+"```");

        }

    });

}

module.exports = {
    desc: 'Administor welcome message',
    name: 'welcome',
    usage: `
\t\t\`welcome\` - lists the current welcome message and settings
\t\t\`welcome enable\` - enables the welcome message
\t\t\`welcome disable\` - disables the welcome message
\t\t\`welcome channel\` - sets the channel the welcome message will be sent to
\t\t\`welcome msg\` - sets the msg to send

\t\tuse \`:USER:\` in the msg to mention the new recruit`,
    alias: [],
    exec: exec,
    admin: true
};<commit_msg>Fixed error in welcome command<commit_after>'use strict';
var co = require('co');

function exec(cmd) {

    return co(function* () {
        var bot = cmd.bot;
        var msg = cmd.msg;
        var args = cmd.args;
        var config = cmd.config;

        if(args.length === 0) {
            return bot.sendMessage(msg,
                "```ruby\n"+
                "Channel: "+config.welcome.channel+"\n"+
                "Enabled: "+config.welcome.enabled+"\n"+
                "Message:\n"+config.welcome.msg+"```"
            );
        }

        switch (args.shift().toLowerCase()) {
            case 'enable':
                config.welcome.enabled = true;
                yield config.storage.setItem('welcome', config.welcome);
                return bot.sendMessage(msg, "welcome message enabled");
            case 'disable':
                config.welcome.enabled = false;
                yield config.storage.setItem('welcome', config.welcome);
                return bot.sendMessage(msg, "welcome message disabled");
            case 'channel':

                if (args.length === 0) {
                    return bot.sendMessage(msg, "no channel specified");
                }
                var channel = args[0];

                // check if the channel exists
                if (!msg.channel.server.channels.get("name", channel)) {
                    return bot.sendMessage(msg, "channel `" + channel + "` not found on the server");
                }

                // update the channel
                config.welcome.channel = channel;

                // save the settings
                yield config.storage.setItem('welcome', config.welcome);
                return bot.sendMessage(msg, "changed welcome channel to `"+channel+"`");
            case 'msg':
                if (args.length === 0) {
                    // send a list of roles:
                    return bot.sendMessage(msg, "no msg specified");
                }

                // return the message back to original
                config.welcome.msg = args.join(" ");
                yield config.storage.setItem('welcome', config.welcome);
                return bot.sendMessage(msg, "changed welcome message to:\n```\n"+config.welcome.msg+"```");

        }

    });

}

module.exports = {
    desc: 'Administor welcome message',
    name: 'welcome',
    usage: `
\t\t\`welcome\` - lists the current welcome message and settings
\t\t\`welcome enable\` - enables the welcome message
\t\t\`welcome disable\` - disables the welcome message
\t\t\`welcome channel\` - sets the channel the welcome message will be sent to
\t\t\`welcome msg\` - sets the msg to send

\t\tuse \`:USER:\` in the msg to mention the new recruit`,
    alias: [],
    exec: exec,
    admin: true
};<|endoftext|>


<commit_before>/* global Vue, gl */
/* eslint-disable no-param-reassign */

((gl) => {
  gl.VueStatusScope = Vue.extend({
    props: [
      'pipeline',
    ],
    computed: {
      cssClasses() {
        const cssObject = {};
        cssObject['ci-status'] = true;
        cssObject[`ci-${this.pipeline.details.status}`] = true;
        return cssObject;
      },
      svg() {
        return document
          .querySelector(
            `.${this.pipeline.details.status}-icon-svg.hidden`,
          ).innerHTML;
      },
    },
    template: `

             {{pipeline.details.status}}

    `,
  });
})(window.gl || (window.gl = {}));
<commit_msg>fix status for svg's on status column<commit_after>/* global Vue, gl */
/* eslint-disable no-param-reassign */

((gl) => {
  gl.VueStatusScope = Vue.extend({
    props: [
      'pipeline',
    ],
    computed: {
      cssClasses() {
        const cssObject = {};
        cssObject['ci-status'] = true;
        cssObject[`ci-${this.pipeline.details.status.text}`] = true;
        return cssObject;
      },
      svg() {
        return document
          .querySelector(
            `.${this.pipeline.details.status.text}-icon-svg.hidden`,
          ).innerHTML;
      },
    },
    template: `

             {{pipeline.details.status.text}}

    `,
  });
})(window.gl || (window.gl = {}));
<|endoftext|>


<commit_before>/*globals L*/
'use strict';

exports.__esModule = true;

var _pluginsFeatureLayer = require('./plugins/FeatureLayer');

exports['default'] = function (_ref) {
  var c = _ref.config;
  var o = _ref.options;

  return {
    create: function create(_ref2) {
      var ow = _ref2.owner;
      var geojson = c.geojson;

      var e = _pluginsFeatureLayer.featureLayer(geojson, o);
      ow.addLayer(e);
      return e;
    },
    update: function update(_ref3) {
      var e = _ref3.element;
      var data = c.data;

      if (data) {
        e.setGeoJSON(data.geojson);
        e.bringToBack();
      }
    },
    remove: function remove(_ref4) {
      var e = _ref4.element;
      var ow = _ref4.owner;

      ow.removeLayer(e);
    }
  };
};

module.exports = exports['default'];<commit_msg>Compile changes<commit_after>/*globals L*/
'use strict';

exports.__esModule = true;

var _pluginsFeatureLayer = require('./plugins/FeatureLayer');

exports['default'] = function (_ref) {
  var c = _ref.config;
  var o = _ref.options;

  return {
    create: function create(_ref2) {
      var ow = _ref2.owner;
      var geojson = c.geojson;

      var e = _pluginsFeatureLayer.featureLayer(geojson, o);
      ow.addLayer(e);
      return e;
    },
    update: function update(_ref3) {
      var e = _ref3.element;
      var geojson = c.geojson;

      if (geojson) {
        e.setGeoJSON(geojson);
        e.bringToBack();
      }
    },
    remove: function remove(_ref4) {
      var e = _ref4.element;
      var ow = _ref4.owner;

      ow.removeLayer(e);
    }
  };
};

module.exports = exports['default'];<|endoftext|>


<commit_before>TileMill = {page:0, uniq: (new Date().getTime())};

$.fn.reverse = [].reverse;

/**
 * Generate the URL of the current project .mml file.
 *
 * @param bool timestamp
 *   Optionally append a timestamp parameter to the URL to avoid
 *   TileLive caching.
 */
TileMill.mmlURL = function(timestamp) {
  var url = window.server + 'projects/mml?id=' + window.project_id;
  //if (timestamp != undefined && !!timestamp) {
    url += '&c=' + TileMill.uniq;
  //}
  url = Base64.encode(url);
  return url;
};

TileMill.addLayer = function(options) {
  var layerName = '';
  if (options.id) {
    layerName = '#' + options.id + ' ';
  }
  if (options.classes.length) {
    layerName += '.' + options.classes.join(', .');
  }
  var checkbox = $('<input class="checkbox" type="checkbox" />');
  var li = $('
')
    .append($('

'))
    .append(checkbox)
    .append($('Delete').click(function() {
      if (confirm('Are you sure you want to delete this layer?')) {
        $(this).parents('li').hide('fast', function() {
          $(this).remove();
        });
      }
      return false;
    }))
    .append($('Inspect').click(function() {
      if (!$(this).parents('li').data('tilemill')['id']) {
        alert('You need to add an id to a field and save to inspect it.');
        return;
      }
      $('#inspector .sidebar-header h2').html('Layers » ' + $(this).parents('li').find('label').text());
      TileMill.inspect($(this).parents('li').data('tilemill').id);
      TileMill.page = 0;
      return false;
    }))
    .append($('Edit').click(function() {
      var options = $(this).parents('li').data('tilemill');
      $('#popup, #popup-layer, #popup-backdrop, #popup-header').show().removeClass('new');
      var layer = $('#popup-layer').find('input.submit').val('Save').data('li', $(this).parents('li')).end();

      options.classes = options.classes.join(' ');
      for (option in options) {
        layer.find('#' + option).val(options[option]).end();
      }

      $('#popup-header h2').text('Edit layer');
      $('#popup-info').hide();
      return false;
    }))
    .append($('' + layerName + ''));
  if (options.status == 'true') {
    checkbox[0].checked = true;
  }
  $('#layers ul.sidebar-content').prepend(li.data('tilemill', options));
};

TileMill.initMap = function() {
  if (!$('#map-preview').is('.inited')) {
    $('#map-preview').addClass('inited');
    var options = {
      projection: new OpenLayers.Projection("EPSG:900913"),
      displayProjection: new OpenLayers.Projection("EPSG:4326"),
      units: "m",
      numZoomLevels: 12,
      maxResolution: 156543.0339,
      maxExtent: new OpenLayers.Bounds(
        -20037500,
        -20037500,
        20037500,
        20037500
      ),
      controls: []
    };
    TileMill.map = new OpenLayers.Map('map-preview', options);
    TileMill.layer = new OpenLayers.Layer.XYZ("Preview", window.tilelive + 'tile/' + TileMill.mmlURL() + '/${z}/${x}/${y}.png');
    TileMill.map.addLayers([ TileMill.layer ]);

    // Set the map's initial center point
    TileMill.map.setCenter(new OpenLayers.LonLat(0, 0), 2);

    // Add control
    var control = new OpenLayers.Control.Navigation({ 'zoomWheelEnabled': true });
    TileMill.map.addControl(control);
    control.activate();

    // Fullscreen toggle
    var fullscreen = $('a.map-fullscreen').click(function() {
      $('#map-preview').toggleClass('fullscreen');
      TileMill.map.updateSize();
      return false;
    });
  }
  // Update map.
  else {
    TileMill.map.removeLayer(TileMill.layer);
    TileMill.layer = new OpenLayers.Layer.XYZ("Preview", window.tilelive + 'tile/' + TileMill.mmlURL() + '/${z}/${x}/${y}.png');
    TileMill.map.addLayers([TileMill.layer]);
  }
};

TileMill.initColors = function() {
  TileMill.farbtastic = $.farbtastic($('#farbtastic'), {callback:'input#color', width:200, height:200});
  $('#color-picker a.color-picker').click(function() {
    $('#farbtastic').toggle('fast');
  });
};

TileMill.initCodeEditor = function(file) {
  $.get('/projects/mss', {'id': project_id, 'filename': file}, function(data) {
    $('textarea#code').val(data);
    TileMill.reloadColors(data);
    TileMill.mirror = CodeMirror.fromTextArea('code', {
      height: "auto",
      parserfile: "parsecss.js",
      stylesheet: static_path + "css/code.css",
      path: static_path + "js/codemirror/js/"
    });
    TileMill.mirror.setCode(data);
    setInterval(function() {
      TileMill.reloadColors(TileMill.mirror.getCode());
    }, 5000);
  });
};

TileMill.save = function(map) {
  var mml = TileMill.mml();
  $.post('/projects/mml', {
    'id': window.project_id,
    'data': mml,
  });
  TileMill.mssSave(project_id);
  TileMill.loadInspection();
  TileMill.uniq = (new Date().getTime());
  TileMill.initMap();
}

TileMill.mml = function() {
  var output = ['<' + '?xml version="1.0" encoding="utf-8"?>',
  '<!DOCTYPE Map[',
  '  <!ENTITY srs900913 "+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs">',
  '  <!ENTITY srsWGS84 "+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs">',
  ']>',
  '<Map srs="&srs900913;">'];
  output.push('