<commit_before>var http = require('http');
var root = require('root');
var flat = require('flat-file-db');
var path = require('path');
var tar = require('tar-fs');
var zlib = require('zlib');
var os = require('os');
var xtend = require('xtend');
var rimraf = require('rimraf');
var once = require('once');
var pump = require('pump');
var select = require('select-keys');
var shell = require('shell-quote');
var respawns = require('respawn-group');
var protocol = require('../lib/protocol');
var parse = require('../lib/parse-remote');
var subscriptions = require('../lib/subscriptions');
var pkg = require('../package.json');

var noop = function() {};

var HANDSHAKE =
	'HTTP/1.1 101 Swiching Protocols\r\n'+
	'Upgrade: hms-protocol\r\n'+
	'Connection: Upgrade\r\n\r\n';

var log = function(tag) {
	tag = tag ? '[dock] ['+tag+']' : '[dock]';
	console.log.apply(null, arguments);
};

module.exports = function(opts) {
	var server = root();
	var db = typeof opts.db == 'object' && opts.db || flat.sync('db');
	var mons = respawns();
	var subs = subscriptions();
	var origin = opts.id || os.hostname();

	subs.on('subscribe', function(id, protocol, count) {
		if (count > 1) return;
		log(id, 'forwarding events and output');
	});

	subs.on('unsubscribe', function(id, protocol, count) {
		if (count) return;
		log(id, 'unforwarding event and output');
	});

	mons.on('finalize', function(mon) {
		rimraf(mon.cwd, noop);
	});

	mons.on('stdout', function(mon, data) {
		subs.publish('stdout', mon.id, origin, data);
	});

	mons.on('stderr', function(mon, data) {
		subs.publish('stderr', mon.id, origin, data);
	});

	mons.on('spawn', function(mon, child) {
		log(mon.id, 'spawned '+child.pid);
		subs.publish('spawn', mon.id, origin, child.pid);
	});

	mons.on('exit', function(mon, code) {
		log(mon.id, 'exited ('+code+')');
		subs.publish('exit', mon.id, origin, code);
	});

	var remote = parse(opts.remote);
	var info = {};

	var onmon = function(id, service) {
		if (!service.start || !service.cwd) return false;

		var env = xtend(service.env);
		var stale = mons.get(id) || {};
		var cmd = shell.parse(service.start, service.env);
		var fresh = {command:cmd, cwd:service.cwd, env:env};

		if (JSON.stringify({command:stale.command, cwd:stale.cwd, env:stale.env}) === JSON.stringify(fresh)) return false;

		info[id] = {revision:service.revision, deployed:service.deployed};
		mons.add(id, fresh);
		return true;
	};

	var onstatuschange = function(id, status, cb) {
		if (!db.has(id)) return onnotfound(cb);
		onmon(id, db.get(id));

		var ondone = function() {
			if (!db.has(id)) return cb();
			var s = db.get(id);
			s.stopped = status === 'stop';
			db.put(id, s, cb);
		};

		switch (status) {
			case 'start':
			log(id, 'starting process');
			mons.start(id);
			return ondone();

			case 'restart':
			log(id, 'restarting process');
			mons.restart(id);
			return ondone();

			case 'stop':
			log(id, 'stopping process');
			return mons.stop(id, ondone);
		}
	};

	var onprotocol = function(protocol, docking) {
		var onnotfound = function(cb) {
			return docking ? cb() : cb(new Error('Service not found'));
		};

		protocol.on('get', function(id, cb) {
			if (!db.has(id)) return onnotfound(cb);
			cb(null, db.get(id));
		});

		protocol.on('distribute', function(id, service, cb) {
			if (!docking) return cb(new Error('Cannot distribute on a dock'));
			if (!service) return cb(new Error('Service must be passed'));

			var cwd = path.join('builds', id+'@'+service.deployed);

			var done = once(function(err) {
				if (err) return onerror(err);
				log(id, 'distribute succeded');
				cb();
			});

			var upsert = function() {
				service.cwd = cwd;
				db.put(id, service, cb);
			};

			var onerror = function(err) {
				log(id, 'distribute failed ('+err.message+')');
				rimraf(cwd, function() {
					cb(err);
				});
			};

			var req = http.get(xtend(remote, {
				path:'/'+id,
				headers:{origin:origin}
			}));

			log(id, 'fetching build from remote');
			req.on('error', done);
			req.on('response', function(response) {
				if (response.statusCode !== 200) return done(new Error('Could not fetch build'));
				pump(response, zlib.createGunzip(), tar.extract(cwd), function(err) {
					if (err) return done(err);
					upsert();
				});
			});
		});

		protocol.on('list', function(cb) {
			var list = db.keys().map(function(key) {
				return db.get(key);
			});

			cb(null, list);
		});

		protocol.on('remove', function(id, cb) {
			if (!docking) return cb(new Error('Cannot remove on a dock'));
			log(id, 'stopping and removing process');
			mons.remove(id, function() {
				db.del(id, cb);
			});
		});

		protocol.on('update', function(id, opts, cb) {
			if (!docking) return cb(new Error('Cannot update on a dock'));
			if (!db.has(id)) return onnotfound(cb);
			log(id, 'updating process');
			db.put(id, xtend(db.get(id), select(opts, ['start', 'build', 'env', 'docks'])), cb);
		});

		protocol.on('restart', function(id, cb) {
			onstatuschange(id, 'restart', cb);
		});

		protocol.on('start', function(id, cb) {
			onstatuschange(id, 'start', cb);
		});

		protocol.on('stop', function(id, cb) {
			onstatuschange(id, 'stop', cb);
		});

		protocol.on('ps', function(cb) {
			var list = mons.list().map(function(mon) {
				return xtend(mon.toJSON(), info[mon.id]);
			});

			cb(null, [{id:origin, list:list}]);
		});

		protocol.on('subscribe', function(id, cb) {
			if (!docking && id !== '*' && !db.has(id)) return onnotfound(cb);
			subs.subscribe(id, protocol);
			cb();
		});

		protocol.once('subscribe', function() {
			protocol.on('close', function() {
				subs.clear(protocol);
			});
		});

		protocol.on('unsubscribe', function(id, cb) {
			subs.unsubscribe(id, protocol);
			cb();
		});
	};

	var dropped = true;
	var connect = function() {
		var req = http.request(xtend(remote, {
			method:'CONNECT',
			path:'/dock',
			headers:{origin:origin}
		}));

		var reconnect = once(function() {
			if (dropped) return setTimeout(connect, 5000);
			dropped = true;
			log(null, 'connection to remote dropped');
			setTimeout(connect, 2500);
		});

		req.on('error', reconnect);
		req.on('connect', function(res, socket, data) {
			dropped = false;
			log(null, 'connection to remote established');
			var p = protocol(socket, data);
			p.ping();
			p.on('close', reconnect);
			onprotocol(p, true);
		});

		req.end();
	};

	server.get('/', function(req, res) {
		res.end('hms-dock '+pkg.version+'\n');
	});

	server.error(function(req, res) {
		res.end('Cannot deploy to a dock');
	});

	server.on('connect', function(req, socket, data) {
		socket.write(HANDSHAKE);
		onprotocol(protocol(socket, data), false);
	});

	var port = opts.port || 10002;
	server.listen(port, function(addr) {
		log(null, origin, 'listening on', port);

		db.keys().forEach(function(key) {
			var service = db.get(key);
			if (!service.stopped) onstatuschange(key, 'start', noop);
		});

		connect();
	});

	var shutdown = function() {
		log(null, 'shutting down');
		mons.shutdown(function() {
			process.exit(0);
		});
	};

	process.on('SIGTERM', shutdown);
	process.on('SIGINT', shutdown);
};<commit_msg>will never clean latest cwd<commit_after>var http = require('http');
var root = require('root');
var flat = require('flat-file-db');
var path = require('path');
var tar = require('tar-fs');
var zlib = require('zlib');
var os = require('os');
var xtend = require('xtend');
var rimraf = require('rimraf');
var once = require('once');
var pump = require('pump');
var select = require('select-keys');
var shell = require('shell-quote');
var respawns = require('respawn-group');
var protocol = require('../lib/protocol');
var parse = require('../lib/parse-remote');
var subscriptions = require('../lib/subscriptions');
var pkg = require('../package.json');

var noop = function() {};

var HANDSHAKE =
	'HTTP/1.1 101 Swiching Protocols\r\n'+
	'Upgrade: hms-protocol\r\n'+
	'Connection: Upgrade\r\n\r\n';

var log = function(tag) {
	tag = tag ? '[dock] ['+tag+']' : '[dock]';
	console.log.apply(null, arguments);
};

module.exports = function(opts) {
	var server = root();
	var db = typeof opts.db == 'object' && opts.db || flat.sync('db');
	var mons = respawns();
	var subs = subscriptions();
	var origin = opts.id || os.hostname();

	subs.on('subscribe', function(id, protocol, count) {
		if (count > 1) return;
		log(id, 'forwarding events and output');
	});

	subs.on('unsubscribe', function(id, protocol, count) {
		if (count) return;
		log(id, 'unforwarding event and output');
	});

	mons.on('finalize', function(mon) {
		var cwd = db.has(mon.id) && db.get(mon.id).cwd;
		if (mon.cwd !== cwd) rimraf(mon.cwd, noop);
	});

	mons.on('stdout', function(mon, data) {
		subs.publish('stdout', mon.id, origin, data);
	});

	mons.on('stderr', function(mon, data) {
		subs.publish('stderr', mon.id, origin, data);
	});

	mons.on('spawn', function(mon, child) {
		log(mon.id, 'spawned '+child.pid);
		subs.publish('spawn', mon.id, origin, child.pid);
	});

	mons.on('exit', function(mon, code) {
		log(mon.id, 'exited ('+code+')');
		subs.publish('exit', mon.id, origin, code);
	});

	var remote = parse(opts.remote);
	var info = {};

	var onmon = function(id, service) {
		if (!service.start || !service.cwd) return false;

		var env = xtend(service.env);
		var stale = mons.get(id) || {};
		var cmd = shell.parse(service.start, service.env);
		var fresh = {command:cmd, cwd:service.cwd, env:env};

		if (JSON.stringify({command:stale.command, cwd:stale.cwd, env:stale.env}) === JSON.stringify(fresh)) return false;

		info[id] = {revision:service.revision, deployed:service.deployed};
		mons.add(id, fresh);
		return true;
	};

	var onstatuschange = function(id, status, cb) {
		if (!db.has(id)) return onnotfound(cb);
		onmon(id, db.get(id));

		var ondone = function() {
			if (!db.has(id)) return cb();
			var s = db.get(id);
			s.stopped = status === 'stop';
			db.put(id, s, cb);
		};

		switch (status) {
			case 'start':
			log(id, 'starting process');
			mons.start(id);
			return ondone();

			case 'restart':
			log(id, 'restarting process');
			mons.restart(id);
			return ondone();

			case 'stop':
			log(id, 'stopping process');
			return mons.stop(id, ondone);
		}
	};

	var onprotocol = function(protocol, docking) {
		var onnotfound = function(cb) {
			return docking ? cb() : cb(new Error('Service not found'));
		};

		protocol.on('get', function(id, cb) {
			if (!db.has(id)) return onnotfound(cb);
			cb(null, db.get(id));
		});

		protocol.on('distribute', function(id, service, cb) {
			if (!docking) return cb(new Error('Cannot distribute on a dock'));
			if (!service) return cb(new Error('Service must be passed'));

			var cwd = path.join('builds', id+'@'+service.deployed);

			var done = once(function(err) {
				if (err) return onerror(err);
				log(id, 'distribute succeded');
				cb();
			});

			var upsert = function() {
				service.cwd = cwd;
				db.put(id, service, cb);
			};

			var onerror = function(err) {
				log(id, 'distribute failed ('+err.message+')');
				rimraf(cwd, function() {
					cb(err);
				});
			};

			var req = http.get(xtend(remote, {
				path:'/'+id,
				headers:{origin:origin}
			}));

			log(id, 'fetching build from remote');
			req.on('error', done);
			req.on('response', function(response) {
				if (response.statusCode !== 200) return done(new Error('Could not fetch build'));
				pump(response, zlib.createGunzip(), tar.extract(cwd), function(err) {
					if (err) return done(err);
					upsert();
				});
			});
		});

		protocol.on('list', function(cb) {
			var list = db.keys().map(function(key) {
				return db.get(key);
			});

			cb(null, list);
		});

		protocol.on('remove', function(id, cb) {
			if (!docking) return cb(new Error('Cannot remove on a dock'));
			log(id, 'stopping and removing process');
			mons.remove(id, function() {
				db.del(id, cb);
			});
		});

		protocol.on('update', function(id, opts, cb) {
			if (!docking) return cb(new Error('Cannot update on a dock'));
			if (!db.has(id)) return onnotfound(cb);
			log(id, 'updating process');
			db.put(id, xtend(db.get(id), select(opts, ['start', 'build', 'env', 'docks'])), cb);
		});

		protocol.on('restart', function(id, cb) {
			onstatuschange(id, 'restart', cb);
		});

		protocol.on('start', function(id, cb) {
			onstatuschange(id, 'start', cb);
		});

		protocol.on('stop', function(id, cb) {
			onstatuschange(id, 'stop', cb);
		});

		protocol.on('ps', function(cb) {
			var list = mons.list().map(function(mon) {
				return xtend(mon.toJSON(), info[mon.id]);
			});

			cb(null, [{id:origin, list:list}]);
		});

		protocol.on('subscribe', function(id, cb) {
			if (!docking && id !== '*' && !db.has(id)) return onnotfound(cb);
			subs.subscribe(id, protocol);
			cb();
		});

		protocol.once('subscribe', function() {
			protocol.on('close', function() {
				subs.clear(protocol);
			});
		});

		protocol.on('unsubscribe', function(id, cb) {
			subs.unsubscribe(id, protocol);
			cb();
		});
	};

	var dropped = true;
	var connect = function() {
		var req = http.request(xtend(remote, {
			method:'CONNECT',
			path:'/dock',
			headers:{origin:origin}
		}));

		var reconnect = once(function() {
			if (dropped) return setTimeout(connect, 5000);
			dropped = true;
			log(null, 'connection to remote dropped');
			setTimeout(connect, 2500);
		});

		req.on('error', reconnect);
		req.on('connect', function(res, socket, data) {
			dropped = false;
			log(null, 'connection to remote established');
			var p = protocol(socket, data);
			p.ping();
			p.on('close', reconnect);
			onprotocol(p, true);
		});

		req.end();
	};

	server.get('/', function(req, res) {
		res.end('hms-dock '+pkg.version+'\n');
	});

	server.error(function(req, res) {
		res.end('Cannot deploy to a dock');
	});

	server.on('connect', function(req, socket, data) {
		socket.write(HANDSHAKE);
		onprotocol(protocol(socket, data), false);
	});

	var port = opts.port || 10002;
	server.listen(port, function(addr) {
		log(null, origin, 'listening on', port);

		db.keys().forEach(function(key) {
			var service = db.get(key);
			if (!service.stopped) onstatuschange(key, 'start', noop);
		});

		connect();
	});

	var shutdown = function() {
		log(null, 'shutting down');
		mons.shutdown(function() {
			process.exit(0);
		});
	};

	process.on('SIGTERM', shutdown);
	process.on('SIGINT', shutdown);
};<|endoftext|>


<commit_before>'use strict';

var Alexa = require('alexa-sdk');
var constants = require('./constants');
var stateHandlers = require('./stateHandlers');
var audioEventHandlers = require('./audioEventHandlers');

exports.handler = function(event, context, callback){
    var alexa = Alexa.handler(event, context);
    alexa.appId = constants.appId;
    alexa.dynamoDBTableName = constants.dynamoDBTableName;
    alexa.registerHandlers(
        stateHandlers.startModeIntentHandlers,
        stateHandlers.playModeIntentHandlers,
        stateHandlers.remoteControllerHandlers,
        stateHandlers.resumeDecisionModeIntentHandlers,
        audioEventHandlers
    );

    if (event.context.System.device.supportedInterfaces.AudioPlayer === undefined) {
        alexa.emit(':tell', 'Sorry, this skill is not supported on this device');
    }
    else alexa.execute();
};
<commit_msg>small fix about code format<commit_after>'use strict';

var Alexa = require('alexa-sdk');
var constants = require('./constants');
var stateHandlers = require('./stateHandlers');
var audioEventHandlers = require('./audioEventHandlers');

exports.handler = function(event, context, callback){
    var alexa = Alexa.handler(event, context);
    alexa.appId = constants.appId;
    alexa.dynamoDBTableName = constants.dynamoDBTableName;
    alexa.registerHandlers(
        stateHandlers.startModeIntentHandlers,
        stateHandlers.playModeIntentHandlers,
        stateHandlers.remoteControllerHandlers,
        stateHandlers.resumeDecisionModeIntentHandlers,
        audioEventHandlers
    );

    if (event.context.System.device.supportedInterfaces.AudioPlayer === undefined) {
        alexa.emit(':tell', 'Sorry, this skill is not supported on this device');
    }
    else {
        alexa.execute();
    }
};
<|endoftext|>


<commit_before>var __slice = Array.prototype.slice;
(function($) {
  var Sketch;
  $.fn.sketch = function() {
    var args, key, sketch;
    key = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
    if (this.length > 1) {
      $.error('Sketch.js can only be called on one element at a time.');
    }
    sketch = this.data('sketch');
    if (typeof key === 'string' && sketch) {
      if (sketch[key]) {
        if (typeof sketch[key] === 'function') {
          return sketch[key].apply(sketch, args);
        } else if (args.length === 0) {
          return sketch[key];
        } else if (args.length === 1) {
          return sketch[key] = args[0];
        }
      } else {
        return $.error('Sketch.js did not recognize the given command.');
      }
    } else if (sketch) {
      return sketch;
    } else {
      this.data('sketch', new Sketch(this.get(0), key));
      return this;
    }
  };
  Sketch = (function() {
    function Sketch(el, opts) {
      this.el = el;
      this.canvas = $(el);
      this.context = el.getContext('2d');
      this.options = $.extend({
        toolLinks: true,
        defaultTool: 'marker',
        defaultColor: '#000000',
        defaultSize: 5
      }, opts);
      this.painting = false;
      this.color = this.options.defaultColor;
      this.size = this.options.defaultSize;
      this.tool = this.options.defaultTool;
      this.actions = [];
      this.action = [];
      this.canvas.bind('click mousedown mouseup mousemove mouseleave mouseout touchstart touchmove touchend touchcancel', this.onEvent);
      if (this.options.toolLinks) {
        $('body').delegate("a[href=\"#" + (this.canvas.attr('id')) + "\"]", 'click', function(e) {
          var $canvas, $this, key, sketch, _i, _len, _ref;
          $this = $(this);
          $canvas = $($this.attr('href'));
          sketch = $canvas.data('sketch');
          _ref = ['color', 'size', 'tool'];
          for (_i = 0, _len = _ref.length; _i < _len; _i++) {
            key = _ref[_i];
            if ($this.attr("data-" + key)) {
              sketch.set(key, $(this).attr("data-" + key));
            }
          }
          if ($(this).attr('data-download')) {
            sketch.download($(this).attr('data-download'));
          }
          return false;
        });
      }
    }
    Sketch.prototype.download = function(format) {
      var mime;
      format || (format = "png");
      if (format === "jpg") {
        format = "jpeg";
      }
      mime = "image/" + format;
      return window.open(this.el.toDataURL(mime).replace('image/png','image/octet-stream'));

    };
    Sketch.prototype.set = function(key, value) {
      this[key] = value;
      return this.canvas.trigger("sketch.change" + key, value);
    };
    Sketch.prototype.startPainting = function() {
      this.painting = true;
      return this.action = {
        tool: this.tool,
        color: this.color,
        size: parseFloat(this.size),
        events: []
      };
    };
    Sketch.prototype.stopPainting = function() {
      if (this.action) {
        this.actions.push(this.action);
      }
      this.painting = false;
      this.action = null;
      return this.redraw();
    };
    Sketch.prototype.onEvent = function(e) {
      if (e.originalEvent && e.originalEvent.targetTouches) {
        e.pageX = e.originalEvent.targetTouches[0].pageX;
        e.pageY = e.originalEvent.targetTouches[0].pageY;
      }
      $.sketch.tools[$(this).data('sketch').tool].onEvent.call($(this).data('sketch'), e);
      e.preventDefault();
      return false;
    };
    Sketch.prototype.redraw = function() {
      var sketch;
      this.el.width = this.canvas.width();
      this.context = this.el.getContext('2d');
      sketch = this;
      $.each(this.actions, function() {
        if (this.tool) {
          return $.sketch.tools[this.tool].draw.call(sketch, this);
        }
      });
      if (this.painting && this.action) {
        return $.sketch.tools[this.action.tool].draw.call(sketch, this.action);
      }
    };
    return Sketch;
  })();
  $.sketch = {
    tools: {}
  };
  $.sketch.tools.marker = {
    onEvent: function(e) {
      switch (e.type) {
        case 'mousedown':
        case 'touchstart':
          this.startPainting();
          break;
        case 'mouseup':
        case 'mouseout':
        case 'mouseleave':
        case 'touchend':
        case 'touchcancel':
          this.stopPainting();
      }
      if (this.painting) {
        this.action.events.push({
          x: e.pageX - this.canvas.offset().left,
          y: e.pageY - this.canvas.offset().top,
          event: e.type
        });
        return this.redraw();
      }
    },
    draw: function(action) {
      var event, previous, _i, _len, _ref;
      this.context.lineJoin = "round";
      this.context.lineCap = "round";
      this.context.beginPath();
      this.context.moveTo(action.events[0].x, action.events[0].y);
      _ref = action.events;
      for (_i = 0, _len = _ref.length; _i < _len; _i++) {
        event = _ref[_i];
        this.context.lineTo(event.x, event.y);
        previous = event;
      }
      this.context.strokeStyle = action.color;
      this.context.lineWidth = action.size;
      return this.context.stroke();
    }
  };
  return $.sketch.tools.eraser = {
    onEvent: function(e) {
      return $.sketch.tools.marker.onEvent.call(this, e);
    },
    draw: function(action) {
      var oldcomposite;
      oldcomposite = this.context.globalCompositeOperation;
      this.context.globalCompositeOperation = "copy";
      action.color = "rgba(0,0,0,0)";
      $.sketch.tools.marker.draw.call(this, action);
      return this.context.globalCompositeOperation = oldcomposite;
    }
  };
})(jQuery);

<commit_msg>java programming<commit_after>var __slice = Array.prototype.slice;
(function($) {
  var Sketch;
  $.fn.sketch = function() {
    var args, key, sketch;
    key = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
    if (this.length > 1) {
      $.error('Sketch.js can only be called on one element at a time.');
    }
    sketch = this.data('sketch');
    if (typeof key === 'string' && sketch) {
      if (sketch[key]) {
        if (typeof sketch[key] === 'function') {
          return sketch[key].apply(sketch, args);
        } else if (args.length === 0) {
          return sketch[key];
        } else if (args.length === 1) {
          return sketch[key] = args[0];
        }
      } else {
        return $.error('Sketch.js did not recognize the given command.');
      }
    } else if (sketch) {
      return sketch;
    } else {
      this.data('sketch', new Sketch(this.get(0), key));
      return this;
    }
  };
  Sketch = (function() {
    function Sketch(el, opts) {
      this.el = el;
      this.canvas = $(el);
      this.context = el.getContext('2d');
      this.options = $.extend({
        toolLinks: true,
        defaultTool: 'marker',
        defaultColor: '#000000',
        defaultSize: 5
      }, opts);
      this.painting = false;
      this.color = this.options.defaultColor;
      this.size = this.options.defaultSize;
      this.tool = this.options.defaultTool;
      this.actions = [];
      this.action = [];
      this.canvas.bind('click mousedown mouseup mousemove mouseleave mouseout touchstart touchmove touchend touchcancel', this.onEvent);
      if (this.options.toolLinks) {
        $('body').delegate("a[href=\"#" + (this.canvas.attr('id')) + "\"]", 'click', function(e) {
          var $canvas, $this, key, sketch, _i, _len, _ref;
          $this = $(this);
          $canvas = $($this.attr('href'));
          sketch = $canvas.data('sketch');
          _ref = ['color', 'size', 'tool'];
          for (_i = 0, _len = _ref.length; _i < _len; _i++) {
            key = _ref[_i];
            if ($this.attr("data-" + key)) {
              sketch.set(key, $(this).attr("data-" + key));
            }
          }
          if ($(this).attr('data-download')) {
            sketch.download($(this).attr('data-download'));
          }
          return false;
        });
      }
    }
    Sketch.prototype.download = function(format) {
      var mime;
      format || (format = "png");
      if (format === "jpg") {
        format = "jpeg";
      }
      mime = "image/" + format;

      return window.open(this.el.toDataURL(mime).replace('image/png','image/octet-stream'));

    };
    Sketch.prototype.set = function(key, value) {
      this[key] = value;
      return this.canvas.trigger("sketch.change" + key, value);
    };
    Sketch.prototype.startPainting = function() {
      this.painting = true;
      return this.action = {
        tool: this.tool,
        color: this.color,
        size: parseFloat(this.size),
        events: []
      };
    };
    Sketch.prototype.stopPainting = function() {
      if (this.action) {
        this.actions.push(this.action);
      }
      this.painting = false;
      this.action = null;
      return this.redraw();
    };
    Sketch.prototype.onEvent = function(e) {
      if (e.originalEvent && e.originalEvent.targetTouches) {
        e.pageX = e.originalEvent.targetTouches[0].pageX;
        e.pageY = e.originalEvent.targetTouches[0].pageY;
      }
      $.sketch.tools[$(this).data('sketch').tool].onEvent.call($(this).data('sketch'), e);
      e.preventDefault();
      return false;
    };
    Sketch.prototype.redraw = function() {
      var sketch;
      this.el.width = this.canvas.width();
      this.context = this.el.getContext('2d');
      sketch = this;
      $.each(this.actions, function() {
        if (this.tool) {
          return $.sketch.tools[this.tool].draw.call(sketch, this);
        }
      });
      if (this.painting && this.action) {
        return $.sketch.tools[this.action.tool].draw.call(sketch, this.action);
      }
    };
    return Sketch;
  })();
  $.sketch = {
    tools: {}
  };
  $.sketch.tools.marker = {
    onEvent: function(e) {
      switch (e.type) {
        case 'mousedown':
        case 'touchstart':
          this.startPainting();
          break;
        case 'mouseup':
        case 'mouseout':
        case 'mouseleave':
        case 'touchend':
        case 'touchcancel':
          this.stopPainting();
      }
      if (this.painting) {
        this.action.events.push({
          x: e.pageX - this.canvas.offset().left,
          y: e.pageY - this.canvas.offset().top,
          event: e.type
        });
        return this.redraw();
      }
    },
    draw: function(action) {
      var event, previous, _i, _len, _ref;
      this.context.lineJoin = "round";
      this.context.lineCap = "round";
      this.context.beginPath();
      this.context.moveTo(action.events[0].x, action.events[0].y);
      _ref = action.events;
      for (_i = 0, _len = _ref.length; _i < _len; _i++) {
        event = _ref[_i];
        this.context.lineTo(event.x, event.y);
        previous = event;
      }
      this.context.strokeStyle = action.color;
      this.context.lineWidth = action.size;
      return this.context.stroke();
    }
  };
  return $.sketch.tools.eraser = {
    onEvent: function(e) {
      return $.sketch.tools.marker.onEvent.call(this, e);
    },
    draw: function(action) {
      var oldcomposite;
      oldcomposite = this.context.globalCompositeOperation;
      this.context.globalCompositeOperation = "copy";
      action.color = "rgba(0,0,0,0)";
      $.sketch.tools.marker.draw.call(this, action);
      return this.context.globalCompositeOperation = oldcomposite;
    }
  };
})(jQuery);

<|endoftext|>


<commit_before>/* exported loadFromKinto */
/* exported saveToKinto */
/* exported BrowserStorageCredentials */

let syncDebounce = null;

const cryptographer = new Jose.WebCryptographer();
cryptographer.setKeyEncryptionAlgorithm('A256KW');
cryptographer.setContentEncryptionAlgorithm('A256GCM');

function shared_key(key) {
  return crypto.subtle.importKey(
    'jwk',
    { kty: key.kty, k: key.k.replace(/=/, '') },
    'AES-KW',
    true,
    ['wrapKey', 'unwrapKey']
  );
}

function encrypt(key, content) {
  const encrypter = new JoseJWE.Encrypter(cryptographer, shared_key(key));
  return encrypter.encrypt(JSON.stringify(content));
}

function decrypt(key, encrypted) {
  const decrypter = new JoseJWE.Decrypter(cryptographer, shared_key(key));
  return decrypter.decrypt(encrypted).then(result => {
    return JSON.parse(result);
  });
}

// An "id schema" used to validate Kinto IDs and generate new ones.
const notesIdSchema = {
  // FIXME: Maybe this should generate IDs?
  generate() {
    throw new Error('cannot generate IDs');
  },

  validate() {
    // FIXME: verify that at least this matches Kinto server ID format
    return true;
  },
};

class ServerKeyNewerError extends Error {
  constructor() {
    super('key used to encrypt the record appears to be newer than our key');
  }
}

class ServerKeyOlderError extends Error {
  constructor() {
    super('key used to encrypt the record appears to be older than our key');
  }
}

class JWETransformer {
  constructor(key) {
    this.key = key;
  }

  async encode(record) {
    // FIXME: should we try to obfuscate the record ID?
    const ciphertext = await encrypt(this.key, record);
    // Copy over the _status field, so that we handle concurrency
    // headers (If-Match, If-None-Match) correctly.
    // DON'T copy over "deleted" status, because then we'd leak
    // plaintext deletes.
    const status = record._status && (record._status === 'deleted' ? 'updated' : record._status);
    const encryptedResult = {
      content: ciphertext,
      id: record.id,
      _status: status,
      kid: this.key.kid,
    };
    if (record.hasOwnProperty('last_modified')) {
      encryptedResult.last_modified = record.last_modified;
    }

    return encryptedResult;
  }

  async decode(record) {
    if (!record.content) {
      // This can happen for tombstones if a record is deleted.
      if (record.deleted) {
        return record;
      }
      throw new Error('No ciphertext: nothing to decrypt?');
    }

    if (record.kid !== this.key.kid) {
      if (this.key.kid < record.kid) {
        throw new ServerKeyNewerError();
      } else {
        throw new ServerKeyOlderError();
      }
    }

    let decoded = await decrypt(this.key, record.content);
    if (!decoded.hasOwnProperty('id')) {
      // Old-style encrypted notes aren't true Kinto records --
      // they're just the content field.
      decoded = {
        content: decoded,
        id: 'singleNote',
      };
    }
    if (record.hasOwnProperty('last_modified')) {
      decoded.last_modified = record.last_modified;
    }

    // _status: deleted records were deleted on a client, but
    // uploaded as an encrypted blob so we don't leak deletions.
    // If we get such a record, flag it as deleted.
    if (decoded._status === 'deleted') {
      decoded.deleted = true;
    }
    return decoded;
  }
}

/**
 * Interface describing a mechanism to fetch credentials.
 */
class Credentials {
  async get() {
    return Promise.reject('Implement me');
  }

  /**
   * Call this if, for example, credentials were invalid.
   */
  async clear() {
    return Promise.reject('Implement me');
  }
}

class BrowserStorageCredentials extends Credentials {
  constructor(storage) {
    super();
    this.storage = storage;
  }

  async get() {
    const data = await this.storage.get(['credentials']);
    return data.credentials;
  }

  async clear() {
    return this.storage.remove('credentials');
  }
}

/**
 * Try to sync our data against the Kinto server.
 *
 * Returns a promise. The promise can reject in case of sync failure
 * or any other reason. This is so that programming errors can be
 * caught more easily in testing. Since this application is
 * offline-first, sync failure should not be a failure for callers.
 */
function syncKinto(client, credentials) {
  // Get credentials and lastmodified
  let collection, credential;
  return credentials.get()
    .then(received => {
      credential = received;
      // XXX: Ask for an refresh token
      // Query Kinto with the Bearer Token
      if (!received) return;
      collection = client
        .collection('notes', {
          idSchema: notesIdSchema,
          remoteTransformers: [new JWETransformer(credential.key)],
        });
      return collection
        .sync({
          headers: { Authorization: `Bearer ${credential.access_token}` },
          strategy: 'manual',
        });
    })
    .then(syncResult => {
      // FIXME: Do we need to do anything with errors, published,
      // updated, etc.?
      return Promise.all(syncResult.conflicts.map(conflict => {
        console.log(conflict);
        let totalOps = conflict.remote.content.ops.slice();
        totalOps.push({ insert: '\n====== On this computer: ======\n\n' });
        totalOps = totalOps.concat(conflict.local.content.ops);
        const resolution = {
          id: conflict.remote.id,
          content: {ops: totalOps},
        };
        return collection.resolve(conflict, resolution);
      }))
        .then(() => syncKinto(client, credentials));
    })
    .catch(error => {
      if (error.response && error.response.status === 401) {
        // In case of 401 log the user out.
        // FIXME: Fetch a new token and retry?
        return credentials.clear();
      } else if (error instanceof ServerKeyNewerError) {
        // If the key date is greater than current one, log the user out.
        console.error(error);
        return credentials.clear();
      } else if (error instanceof ServerKeyOlderError) {
        // If the key date is older than the current one, we can't help
        // because there is no way we get the previous key.
        // Flush the server because whatever was there is wrong.
        console.error(error);
        const kintoHttp = client.api;
        return kintoHttp.bucket('default').deleteCollection('notes', {
          headers: { Authorization: `Bearer ${credential.access_token}` }
        }).then(() => collection.resetSyncStatus())
          .then(() => syncKinto(client, credentials));
      } else if (error.message.includes('flushed')) {
        return collection.resetSyncStatus()
          .then(() => {
            return syncKinto(client, credentials);
          });
      } else {
        console.error(error);
        return Promise.reject(error);
      }
    });
}

function retrieveNote(client) {
  return client.collection('notes', {
    idSchema: notesIdSchema,
  }).getAny('singleNote');
}

/**
 * Try to sync against the Kinto server, and retrieve the current note
 * contents.
 *
 * On completion, a 'kinto-loaded' event will be fired with the
 * following structure:
 *
 * {
 *   action: 'kinto-loaded',
 *   data: the "content" that was previously saved to Kinto, or null
 *     if nothing was previously saved to Kinto (for example, a new
 *     FxA account, or if syncing failed on a fresh profile)
 *   last_modified: the timestamp of the sync, or null
 * }
 */
function loadFromKinto(client, credentials) {
  return syncKinto(client, credentials)
  // Ignore failure of syncKinto by retrieving note even when promise rejected
    .then(() => retrieveNote(client), () => retrieveNote(client))
    .then(result => {
      console.log('Collection had record', result);
      browser.runtime.sendMessage({
        action: 'kinto-loaded',
        data: result ? result.data.content : null,
        last_modified: result ? result.data.last_modified : null,
      });
    });
}

function saveToKinto(client, credentials, content) {
  let resolve;
  const promise = new Promise(thisResolve => {
    resolve = thisResolve;
  });

  // XXX: Debounce the call and set the status to Editing
  browser.runtime.sendMessage('notes@mozilla.com', {
    action: 'text-editing'
  });

  const later = function() {
    syncDebounce = null;
    const notes = client.collection('notes', {
      idSchema: notesIdSchema,
    });
    return notes.upsert({ id: 'singleNote', content })
      .then(() => {
        browser.runtime.sendMessage('notes@mozilla.com', {
          action: 'text-saved'
        });
        return syncKinto(client, credentials);
      })
      .then(() => retrieveNote(client), () => retrieveNote(client))
      .then(result => {
        // Set the status to synced
        return browser.runtime.sendMessage('notes@mozilla.com', {
          action: 'text-synced',
          last_modified: result.data.last_modified,
        });
      })
      .then(() => {
        resolve();
      });
  };

  clearTimeout(syncDebounce);
  syncDebounce = setTimeout(later, 1000);
  return promise;
}
<commit_msg>Only recur to handle conflicts when there were conflicts<commit_after>/* exported loadFromKinto */
/* exported saveToKinto */
/* exported BrowserStorageCredentials */

let syncDebounce = null;

const cryptographer = new Jose.WebCryptographer();
cryptographer.setKeyEncryptionAlgorithm('A256KW');
cryptographer.setContentEncryptionAlgorithm('A256GCM');

function shared_key(key) {
  return crypto.subtle.importKey(
    'jwk',
    { kty: key.kty, k: key.k.replace(/=/, '') },
    'AES-KW',
    true,
    ['wrapKey', 'unwrapKey']
  );
}

function encrypt(key, content) {
  const encrypter = new JoseJWE.Encrypter(cryptographer, shared_key(key));
  return encrypter.encrypt(JSON.stringify(content));
}

function decrypt(key, encrypted) {
  const decrypter = new JoseJWE.Decrypter(cryptographer, shared_key(key));
  return decrypter.decrypt(encrypted).then(result => {
    return JSON.parse(result);
  });
}

// An "id schema" used to validate Kinto IDs and generate new ones.
const notesIdSchema = {
  // FIXME: Maybe this should generate IDs?
  generate() {
    throw new Error('cannot generate IDs');
  },

  validate() {
    // FIXME: verify that at least this matches Kinto server ID format
    return true;
  },
};

class ServerKeyNewerError extends Error {
  constructor() {
    super('key used to encrypt the record appears to be newer than our key');
  }
}

class ServerKeyOlderError extends Error {
  constructor() {
    super('key used to encrypt the record appears to be older than our key');
  }
}

class JWETransformer {
  constructor(key) {
    this.key = key;
  }

  async encode(record) {
    // FIXME: should we try to obfuscate the record ID?
    const ciphertext = await encrypt(this.key, record);
    // Copy over the _status field, so that we handle concurrency
    // headers (If-Match, If-None-Match) correctly.
    // DON'T copy over "deleted" status, because then we'd leak
    // plaintext deletes.
    const status = record._status && (record._status === 'deleted' ? 'updated' : record._status);
    const encryptedResult = {
      content: ciphertext,
      id: record.id,
      _status: status,
      kid: this.key.kid,
    };
    if (record.hasOwnProperty('last_modified')) {
      encryptedResult.last_modified = record.last_modified;
    }

    return encryptedResult;
  }

  async decode(record) {
    if (!record.content) {
      // This can happen for tombstones if a record is deleted.
      if (record.deleted) {
        return record;
      }
      throw new Error('No ciphertext: nothing to decrypt?');
    }

    if (record.kid !== this.key.kid) {
      if (this.key.kid < record.kid) {
        throw new ServerKeyNewerError();
      } else {
        throw new ServerKeyOlderError();
      }
    }

    let decoded = await decrypt(this.key, record.content);
    if (!decoded.hasOwnProperty('id')) {
      // Old-style encrypted notes aren't true Kinto records --
      // they're just the content field.
      decoded = {
        content: decoded,
        id: 'singleNote',
      };
    }
    if (record.hasOwnProperty('last_modified')) {
      decoded.last_modified = record.last_modified;
    }

    // _status: deleted records were deleted on a client, but
    // uploaded as an encrypted blob so we don't leak deletions.
    // If we get such a record, flag it as deleted.
    if (decoded._status === 'deleted') {
      decoded.deleted = true;
    }
    return decoded;
  }
}

/**
 * Interface describing a mechanism to fetch credentials.
 */
class Credentials {
  async get() {
    return Promise.reject('Implement me');
  }

  /**
   * Call this if, for example, credentials were invalid.
   */
  async clear() {
    return Promise.reject('Implement me');
  }
}

class BrowserStorageCredentials extends Credentials {
  constructor(storage) {
    super();
    this.storage = storage;
  }

  async get() {
    const data = await this.storage.get(['credentials']);
    return data.credentials;
  }

  async clear() {
    return this.storage.remove('credentials');
  }
}

/**
 * Try to sync our data against the Kinto server.
 *
 * Returns a promise. The promise can reject in case of sync failure
 * or any other reason. This is so that programming errors can be
 * caught more easily in testing. Since this application is
 * offline-first, sync failure should not be a failure for callers.
 */
function syncKinto(client, credentials) {
  // Get credentials and lastmodified
  let collection, credential;
  return credentials.get()
    .then(received => {
      credential = received;
      // XXX: Ask for an refresh token
      // Query Kinto with the Bearer Token
      if (!received) return;
      collection = client
        .collection('notes', {
          idSchema: notesIdSchema,
          remoteTransformers: [new JWETransformer(credential.key)],
        });
      return collection
        .sync({
          headers: { Authorization: `Bearer ${credential.access_token}` },
          strategy: 'manual',
        });
    })
    .then(syncResult => {
      // FIXME: Do we need to do anything with errors, published,
      // updated, etc.?
      if (syncResult.conflicts.length > 0) {
        return Promise.all(syncResult.conflicts.map(conflict => {
          console.log("Handling conflict", conflict);
          let totalOps = conflict.remote.content.ops.slice();
          totalOps.push({ insert: '\n====== On this computer: ======\n\n' });
          totalOps = totalOps.concat(conflict.local.content.ops);
          const resolution = {
            id: conflict.remote.id,
            content: {ops: totalOps},
          };
          return collection.resolve(conflict, resolution);
        }))
          .then(() => syncKinto(client, credentials));
      }
    })
    .catch(error => {
      if (error.response && error.response.status === 401) {
        // In case of 401 log the user out.
        // FIXME: Fetch a new token and retry?
        return credentials.clear();
      } else if (error instanceof ServerKeyNewerError) {
        // If the key date is greater than current one, log the user out.
        console.error(error);
        return credentials.clear();
      } else if (error instanceof ServerKeyOlderError) {
        // If the key date is older than the current one, we can't help
        // because there is no way we get the previous key.
        // Flush the server because whatever was there is wrong.
        console.error(error);
        const kintoHttp = client.api;
        return kintoHttp.bucket('default').deleteCollection('notes', {
          headers: { Authorization: `Bearer ${credential.access_token}` }
        }).then(() => collection.resetSyncStatus())
          .then(() => syncKinto(client, credentials));
      } else if (error.message.includes('flushed')) {
        return collection.resetSyncStatus()
          .then(() => {
            return syncKinto(client, credentials);
          });
      } else {
        console.error(error);
        return Promise.reject(error);
      }
    });
}

function retrieveNote(client) {
  return client.collection('notes', {
    idSchema: notesIdSchema,
  }).getAny('singleNote');
}

/**
 * Try to sync against the Kinto server, and retrieve the current note
 * contents.
 *
 * On completion, a 'kinto-loaded' event will be fired with the
 * following structure:
 *
 * {
 *   action: 'kinto-loaded',
 *   data: the "content" that was previously saved to Kinto, or null
 *     if nothing was previously saved to Kinto (for example, a new
 *     FxA account, or if syncing failed on a fresh profile)
 *   last_modified: the timestamp of the sync, or null
 * }
 */
function loadFromKinto(client, credentials) {
  return syncKinto(client, credentials)
  // Ignore failure of syncKinto by retrieving note even when promise rejected
    .then(() => retrieveNote(client), () => retrieveNote(client))
    .then(result => {
      console.log('Collection had record', result);
      browser.runtime.sendMessage({
        action: 'kinto-loaded',
        data: result ? result.data.content : null,
        last_modified: result ? result.data.last_modified : null,
      });
    });
}

function saveToKinto(client, credentials, content) {
  let resolve;
  const promise = new Promise(thisResolve => {
    resolve = thisResolve;
  });

  // XXX: Debounce the call and set the status to Editing
  browser.runtime.sendMessage('notes@mozilla.com', {
    action: 'text-editing'
  });

  const later = function() {
    syncDebounce = null;
    const notes = client.collection('notes', {
      idSchema: notesIdSchema,
    });
    return notes.upsert({ id: 'singleNote', content })
      .then(() => {
        browser.runtime.sendMessage('notes@mozilla.com', {
          action: 'text-saved'
        });
        return syncKinto(client, credentials);
      })
      .then(() => retrieveNote(client), () => retrieveNote(client))
      .then(result => {
        // Set the status to synced
        return browser.runtime.sendMessage('notes@mozilla.com', {
          action: 'text-synced',
          last_modified: result.data.last_modified,
        });
      })
      .then(() => {
        resolve();
      });
  };

  clearTimeout(syncDebounce);
  syncDebounce = setTimeout(later, 1000);
  return promise;
}
<|endoftext|>


<commit_before>'use strict';

var autoprefixer = require('gulp-autoprefixer');
var browserSync = require('browser-sync').create();
var concat = require('gulp-concat');
var gulp = require('gulp');
var runSequence = require('run-sequence');
var sass = require('gulp-sass');
var sourcemaps = require('gulp-sourcemaps');
var uglify = require('gulp-uglify');
var wait = require('gulp-wait');

var appName = 'cms_lab_publications';
var paths = {
    css: appName + '/static/' + appName + '/css',
    js: appName + '/static/' + appName + '/js',
    sass: appName + '/sass/app.scss',
    templates: '**/templates/**/*.html',
};

gulp.task('js_app', function() {
    return gulp.src(paths.js + '/app/**/*.js')
        .pipe(sourcemaps.init())
            .pipe(concat('app.js'))
            .pipe(uglify())
        .pipe(sourcemaps.write('../maps'))
        .pipe(gulp.dest(paths.js))
        .pipe(browserSync.stream());
});

gulp.task('js_vendor', function() {
    return gulp.src(paths.js + '/vendor/**/*.js')
        .pipe(sourcemaps.init())
            .pipe(concat('vendor.js'))
            .pipe(uglify())
        .pipe(sourcemaps.write('../maps'))
        .pipe(gulp.dest(paths.js))
        .pipe(browserSync.stream());
});

gulp.task('reloadBrowsers', function() {
    browserSync.reload();
});

gulp.task('sass', function() {
    return gulp.src(paths.sass)
        .pipe(sourcemaps.init())
            .pipe(sass({ outputStyle: 'compressed' }))
            .pipe(autoprefixer())
        .pipe(sourcemaps.write('../maps'))
        .pipe(gulp.dest(paths.css))
        .pipe(browserSync.stream());
});

gulp.task('touchPy', function() {
    // Touch a .py file in order to trigger runserver to restart
    // and then wait a moment while it restarts.
    return gulp.src(appName + '/__init__.py')
        .pipe(gulp.dest(appName))
        .pipe(wait(2000));
});

gulp.task('watch', function() {
    browserSync.init({
        proxy: '127.0.0.1:8000',
    });
    gulp.watch(paths.sass, ['sass']);
    gulp.watch(paths.js + '/app/**/*.js', ['js_app']);
    gulp.watch(paths.js + '/vendor/**/*.js', ['js_vendor']);
    gulp.watch(paths.templates).on('change', function(){
        runSequence('touchPy', 'reloadBrowsers');
    });
});

gulp.task('default', ['js_app', 'js_vendor', 'sass', 'watch']);
<commit_msg>Add Browsersync notifications<commit_after>'use strict';

var autoprefixer = require('gulp-autoprefixer');
var browserSync = require('browser-sync').create();
var concat = require('gulp-concat');
var gulp = require('gulp');
var runSequence = require('run-sequence');
var sass = require('gulp-sass');
var sourcemaps = require('gulp-sourcemaps');
var uglify = require('gulp-uglify');
var wait = require('gulp-wait');

var appName = 'cms_lab_publications';
var paths = {
    css: appName + '/static/' + appName + '/css',
    js: appName + '/static/' + appName + '/js',
    sass: appName + '/sass/app.scss',
    templates: '**/templates/**/*.html',
};

gulp.task('js_app', function() {
    browserSync.notify('Compiling App JavaScript');
    return gulp.src(paths.js + '/app/**/*.js')
        .pipe(sourcemaps.init())
            .pipe(concat('app.js'))
            .pipe(uglify())
        .pipe(sourcemaps.write('../maps'))
        .pipe(gulp.dest(paths.js))
        .pipe(browserSync.stream());
});

gulp.task('js_vendor', function() {
    browserSync.notify('Compiling Vendor JavaScript');
    return gulp.src(paths.js + '/vendor/**/*.js')
        .pipe(sourcemaps.init())
            .pipe(concat('vendor.js'))
            .pipe(uglify())
        .pipe(sourcemaps.write('../maps'))
        .pipe(gulp.dest(paths.js))
        .pipe(browserSync.stream());
});

gulp.task('reloadBrowsers', function() {
    browserSync.notify('Reloading Browsers');
    browserSync.reload();
});

gulp.task('sass', function() {
    browserSync.notify('Compiling Sass');
    return gulp.src(paths.sass)
        .pipe(sourcemaps.init())
            .pipe(sass({ outputStyle: 'compressed' }))
            .pipe(autoprefixer())
        .pipe(sourcemaps.write('../maps'))
        .pipe(gulp.dest(paths.css))
        .pipe(browserSync.stream());
});

gulp.task('touchPy', function() {
    // Touch a .py file in order to trigger runserver to restart
    // and then wait a moment while it restarts.
    browserSync.notify('Restarting Runserver');
    return gulp.src(appName + '/__init__.py')
        .pipe(gulp.dest(appName))
        .pipe(wait(2000));
});

gulp.task('watch', function() {
    browserSync.init({
        proxy: '127.0.0.1:8000',
    });
    gulp.watch(paths.sass, ['sass']);
    gulp.watch(paths.js + '/app/**/*.js', ['js_app']);
    gulp.watch(paths.js + '/vendor/**/*.js', ['js_vendor']);
    gulp.watch(paths.templates).on('change', function(){
        runSequence('touchPy', 'reloadBrowsers');
    });
});

gulp.task('default', ['js_app', 'js_vendor', 'sass', 'watch']);
<|endoftext|>


<commit_before>/*
    viewer.js
    =========
    This file contains all procedures related to the rendering of textbook files within a page.

    If you have a textbook object already, use renderTextbook(), otherwise loadJsonTextbook() will
    generate one for you from a JSON source file.

    This is contains much code from https://github.com/mozilla/pdf.js/tree/master/examples/helloworld
    within the function renderPdfClip.

    Requirements
    ------------
    This file requires the jQuery library and pdf.js to be included in the page to function correctly.
*/

/*Note the 'container' variable refers to an actual DOM element, not its ID*/
function renderTextbook(container, textbook) {
    container.className += " textbook_container";

    var header = document.createElement('header');
    container.appendChild(header);

    var title = document.createElement('h1');
    title.textContent = textbook.title;
    header.appendChild(title);

    var author = document.createElement('span');
    author.textContent = 'By '+textbook.author;
    author.className += "author";
    header.appendChild(author);

    $.each(textbook.elements, function( index, element ) { renderTextbookElement(container, element); });
}

function renderTextbookElement(container, element) {
        //Create element container
        var element_container = document.createElement('div');
        element_container.className += "wrapper";
        container.appendChild(element_container);
        //Render if we know how
        switch (element.type) {
            case 'pdfHorizontal':
                element_container.className += " pdfHorizontal";
                renderPdfHorizontal(element_container, element.source, element.startY, element.endY);
                break;
            case 'pdfRectangle':
                element_container.className += " pdfRectangle";
                renderPdfRectangle(element_container, element);
                break;
            case 'youtube':
                element_container.className += " youtube";
                renderYoutubeElement(element_container, element);
                break;
            case 'wikipedia':
                element_container.className += " wikipedia";
                renderWikipediaElement(element_container, element);
                break;
            case 'image':
                element_container.className += " image";
                renderImageElement(element_container, element);
                break;
            default:
                break;
        }
}

function renderYoutubeElement(container, element) {
    var tag = "";
    if ((typeof element.start === 'undefined')|(typeof element.end === 'undefined')) {
        tag = "";
    } else {
        tag = "";
    }
    container.innerHTML = tag;
}

function renderImageElement(container, element) {
    var image = document.createElement('img');
    image.src = element.source;
    container.appendChild(image);
}

function renderWikipediaElement(container, element) {
    var source = "http://en.wikipedia.org/w/api.php?action=parse&page="+element.page+"&format=json";
    $.getJSON( source, function(page) {
        container.innerHTML = page.parse.text['*'];
    });
}

function renderPdfHorizontal(container, pdf_url, start, end) {
    //Unpack start and end variables
    var start_page = Math.floor(start);
    var start_y = start-start_page;
    var end_page = Math.floor(end);
    var end_y = end-end_page;
    //If is just a single page
    if (start_page==end_page) {
        var canvas = document.createElement('canvas');
        container.appendChild(canvas);
        renderPdfClip(canvas, pdf_url, start_page, start_y, end_y);
    } else {
        //Else loop through, creating a new canvas for each page
        for (var i = start_page; i <= end_page; i++) {
            var canvas = document.createElement('canvas');
            container.appendChild(canvas);
            switch(i) {
                case start_page:
                    renderPdfClip(canvas, pdf_url, i, start_y, 1);
                    break;
                case end_page:
                    renderPdfClip(canvas, pdf_url, i, 0, end_y);
                    break;
                default:
                    renderPdfClip(canvas, pdf_url, i, 0, 1);
            }
        }
    }
}

/*
renderPdfClip
-------------
Aim of this is to render a snippet of a PDF on a page. Seems to work mostly....
This is done based on a start_y, and end_y of a page, on a page by page basis.
These are used as fractions of the whole page (.

This is done by modifying the height and width of the canvas element that pdf.js renders to. It
then using canvas.translate to move to the correct section of the page.
*/
function renderPdfClip(canvas, pdf_url, page_no, y1, y2) {
    // NOTE:
    // Using a PDF from another server will likely *NOT* work. Because of browser
    // security restrictions, we have to use a file server with special headers
    // (CORS) - most servers don't support cross-origin browser requests.
    // ----> why we're making a locally run web application.

    // Disable workers to avoid yet another cross-origin issue (workers need the URL of
    // the script to be loaded, and dynamically loading a cross-origin script does
    // not work)
    PDFJS.disableWorker = true;

    // Asynchronous download PDF as an ArrayBuffer
    PDFJS.getDocument(pdf_url).then(function getClipViewer(pdf) {
      // Fetch the first page
      pdf.getPage(page_no).then(function getPageClipViewer(page) {
        var scale = 1.5;
        var viewport = page.getViewport(scale);

        // Prepare canvas using PDF page dimensions
        var context = canvas.getContext('2d');

        // Displacement and clipping of pages
        canvas.height = viewport.height*(y2-y1);
        canvas.width = viewport.width;
        context.translate(0,-(viewport.height*y1));

        // Render PDF page into canvas context
        page.render({canvasContext: context, viewport: viewport});
      });
    });

}

function renderPdfRectangle(container, pdfRect) {
    // Check for valid inputs
    if ((pdfRect.startX>1)|(pdfRect.endX>1)|(pdfRect.startY>1)|(pdfRect.endY>1)|
        (pdfRect.startX<0)|(pdfRect.endX<0)|(pdfRect.startY<0)|(pdfRect.endY<0)) {
        console.log("Could not render pdfRectangle ('"+pdfRect.source+'). These can not extend outside of page boundaries. So startX, startY, endX, and endY parameters must to between 0 and 1.');
        return;
    }

    // NOTE:
    // Using a PDF from another server will likely *NOT* work. Because of browser
    // security restrictions, we have to use a file server with special headers
    // (CORS) - most servers don't support cross-origin browser requests.
    // ----> why we're making a locally run web application.

    // Disable workers to avoid yet another cross-origin issue (workers need the URL of
    // the script to be loaded, and dynamically loading a cross-origin script does
    // not work)
    PDFJS.disableWorker = true;

    // Asynchronous download PDF as an ArrayBuffer
    PDFJS.getDocument(pdfRect.source).then(function getClipViewer(pdf) {
      // Fetch the first page
      pdf.getPage(pdfRect.page).then(function getPageClipViewer(page) {
        var scale = 1.5;
        var viewport = page.getViewport(scale);

        // Prepare canvas using PDF page dimensions
        var canvas = document.createElement('canvas');
        canvas.id = container.id + "_page_"+pdfRect.page;
        container.appendChild(canvas);
        var context = canvas.getContext('2d');

        // Displacement and clipping of pages
        canvas.height = viewport.height*(pdfRect.endY-pdfRect.startY);
        canvas.width = viewport.width*(pdfRect.endX-pdfRect.startX);
        context.translate(-(viewport.width*pdfRect.startX),-(viewport.height*pdfRect.startY));

        // Render PDF page into canvas context
        page.render({canvasContext: context, viewport: viewport});
      });
    });

}<commit_msg>changed renderTextbookElement to renderElement<commit_after>/*
    viewer.js
    =========
    This file contains all procedures related to the rendering of textbook files within a page.

    If you have a textbook object already, use renderTextbook(), otherwise loadJsonTextbook() will
    generate one for you from a JSON source file.

    This is contains much code from https://github.com/mozilla/pdf.js/tree/master/examples/helloworld
    within the function renderPdfClip.

    Requirements
    ------------
    This file requires the jQuery library and pdf.js to be included in the page to function correctly.
*/

/*Note the 'container' variable refers to an actual DOM element, not its ID*/
function renderTextbook(container, textbook) {
    container.className += " textbook_container";

    var header = document.createElement('header');
    container.appendChild(header);

    var title = document.createElement('h1');
    title.textContent = textbook.title;
    header.appendChild(title);

    var author = document.createElement('span');
    author.textContent = 'By '+textbook.author;
    author.className += "author";
    header.appendChild(author);

    $.each(textbook.elements, function( index, element ) { renderElement(container, element); });
}

function renderElement(container, element) {
        //Create element container
        var element_container = document.createElement('div');
        element_container.className += "wrapper";
        container.appendChild(element_container);
        //Render if we know how
        switch (element.type) {
            case 'pdfHorizontal':
                element_container.className += " pdfHorizontal";
                renderPdfHorizontal(element_container, element.source, element.startY, element.endY);
                break;
            case 'pdfRectangle':
                element_container.className += " pdfRectangle";
                renderPdfRectangle(element_container, element);
                break;
            case 'youtube':
                element_container.className += " youtube";
                renderYoutubeElement(element_container, element);
                break;
            case 'wikipedia':
                element_container.className += " wikipedia";
                renderWikipediaElement(element_container, element);
                break;
            case 'image':
                element_container.className += " image";
                renderImageElement(element_container, element);
                break;
            default:
                break;
        }
}

function renderYoutubeElement(container, element) {
    var tag = "";
    if ((typeof element.start === 'undefined')|(typeof element.end === 'undefined')) {
        tag = "";
    } else {
        tag = "";
    }
    container.innerHTML = tag;
}

function renderImageElement(container, element) {
    var image = document.createElement('img');
    image.src = element.source;
    container.appendChild(image);
}

function renderWikipediaElement(container, element) {
    var source = "http://en.wikipedia.org/w/api.php?action=parse&page="+element.page+"&format=json";
    $.getJSON( source, function(page) {
        container.innerHTML = page.parse.text['*'];
    });
}

function renderPdfHorizontal(container, pdf_url, start, end) {
    //Unpack start and end variables
    var start_page = Math.floor(start);
    var start_y = start-start_page;
    var end_page = Math.floor(end);
    var end_y = end-end_page;
    //If is just a single page
    if (start_page==end_page) {
        var canvas = document.createElement('canvas');
        container.appendChild(canvas);
        renderPdfClip(canvas, pdf_url, start_page, start_y, end_y);
    } else {
        //Else loop through, creating a new canvas for each page
        for (var i = start_page; i <= end_page; i++) {
            var canvas = document.createElement('canvas');
            container.appendChild(canvas);
            switch(i) {
                case start_page:
                    renderPdfClip(canvas, pdf_url, i, start_y, 1);
                    break;
                case end_page:
                    renderPdfClip(canvas, pdf_url, i, 0, end_y);
                    break;
                default:
                    renderPdfClip(canvas, pdf_url, i, 0, 1);
            }
        }
    }
}

/*
renderPdfClip
-------------
Aim of this is to render a snippet of a PDF on a page. Seems to work mostly....
This is done based on a start_y, and end_y of a page, on a page by page basis.
These are used as fractions of the whole page (.

This is done by modifying the height and width of the canvas element that pdf.js renders to. It
then using canvas.translate to move to the correct section of the page.
*/
function renderPdfClip(canvas, pdf_url, page_no, y1, y2) {
    // NOTE:
    // Using a PDF from another server will likely *NOT* work. Because of browser
    // security restrictions, we have to use a file server with special headers
    // (CORS) - most servers don't support cross-origin browser requests.
    // ----> why we're making a locally run web application.

    // Disable workers to avoid yet another cross-origin issue (workers need the URL of
    // the script to be loaded, and dynamically loading a cross-origin script does
    // not work)
    PDFJS.disableWorker = true;

    // Asynchronous download PDF as an ArrayBuffer
    PDFJS.getDocument(pdf_url).then(function getClipViewer(pdf) {
      // Fetch the first page
      pdf.getPage(page_no).then(function getPageClipViewer(page) {
        var scale = 1.5;
        var viewport = page.getViewport(scale);

        // Prepare canvas using PDF page dimensions
        var context = canvas.getContext('2d');

        // Displacement and clipping of pages
        canvas.height = viewport.height*(y2-y1);
        canvas.width = viewport.width;
        context.translate(0,-(viewport.height*y1));

        // Render PDF page into canvas context
        page.render({canvasContext: context, viewport: viewport});
      });
    });

}

function renderPdfRectangle(container, pdfRect) {
    // Check for valid inputs
    if ((pdfRect.startX>1)|(pdfRect.endX>1)|(pdfRect.startY>1)|(pdfRect.endY>1)|
        (pdfRect.startX<0)|(pdfRect.endX<0)|(pdfRect.startY<0)|(pdfRect.endY<0)) {
        console.log("Could not render pdfRectangle ('"+pdfRect.source+'). These can not extend outside of page boundaries. So startX, startY, endX, and endY parameters must to between 0 and 1.');
        return;
    }

    // NOTE:
    // Using a PDF from another server will likely *NOT* work. Because of browser
    // security restrictions, we have to use a file server with special headers
    // (CORS) - most servers don't support cross-origin browser requests.
    // ----> why we're making a locally run web application.

    // Disable workers to avoid yet another cross-origin issue (workers need the URL of
    // the script to be loaded, and dynamically loading a cross-origin script does
    // not work)
    PDFJS.disableWorker = true;

    // Asynchronous download PDF as an ArrayBuffer
    PDFJS.getDocument(pdfRect.source).then(function getClipViewer(pdf) {
      // Fetch the first page
      pdf.getPage(pdfRect.page).then(function getPageClipViewer(page) {
        var scale = 1.5;
        var viewport = page.getViewport(scale);

        // Prepare canvas using PDF page dimensions
        var canvas = document.createElement('canvas');
        canvas.id = container.id + "_page_"+pdfRect.page;
        container.appendChild(canvas);
        var context = canvas.getContext('2d');

        // Displacement and clipping of pages
        canvas.height = viewport.height*(pdfRect.endY-pdfRect.startY);
        canvas.width = viewport.width*(pdfRect.endX-pdfRect.startX);
        context.translate(-(viewport.width*pdfRect.startX),-(viewport.height*pdfRect.startY));

        // Render PDF page into canvas context
        page.render({canvasContext: context, viewport: viewport});
      });
    });

}<|endoftext|>


<commit_before>$(".title-rename-form1").on("submit", function(evt) {
	evt.preventDefault()

	var newTitle = $(".title-rename-1").val()
	$(".title-1").text(newTitle)
	//alert(newTitle)

})
$(".title-rename-form2").on("submit", function(evt) {
	evt.preventDefault()

	var newTitle = $(".title-rename-2").val()
	$(".title-2").text(newTitle)
	//alert(newTitle)

})
$(".title-rename-form3").on("submit", function(evt) {
	evt.preventDefault()

	var newTitle = $(".title-rename-3").val()
	$(".title-3").text(newTitle)
	//alert(newTitle)

})
$(".search-button").onClick( function(evt){
	console.log("hi");

	evt.preventDefault()

}

<commit_msg>Update script.js<commit_after>$(".title-rename-form1").on("submit", function(evt) {
	evt.preventDefault()

	var newTitle = $(".title-rename-1").val()
	$(".title-1").text(newTitle)
	//alert(newTitle)

})
$(".title-rename-form2").on("submit", function(evt) {
	evt.preventDefault()

	var newTitle = $(".title-rename-2").val()
	$(".title-2").text(newTitle)
	//alert(newTitle)

})
$(".title-rename-form3").on("submit", function(evt) {
	evt.preventDefault()

	var newTitle = $(".title-rename-3").val()
	$(".title-3").text(newTitle)
	//alert(newTitle)

})

<|endoftext|>


<commit_before>const useragent = require('useragent');
const memoizeSync = require('memoizesync');
const downgradeCsp3ToCsp2 = require('./downgradeCsp3ToCsp2');
const downgradeCsp2ToCsp1 = require('./downgradeCsp2ToCsp1');
require('useragent/features');
const parseCsp = require('./parseCsp');

const cspStatsByLevel = {
    1: require('caniuse-db/features-json/contentsecuritypolicy.json').stats,
    2: require('caniuse-db/features-json/contentsecuritypolicy2.json').stats
};

try {
    cspStatsByLevel[3] = require('caniuse-db/features-json/contentsecuritypolicy3.json').stats;
} catch (e) {}

const maxCspLevel = Math.max(...Object.keys(cspStatsByLevel).map(levelStr => parseInt(levelStr, 10)));

const caniuseIdByAgentFamily = {
    IE: 'ie',
    'Mobile Safari UI/WKWebView': 'mobile_safari',
    Safari: 'safari',
    Chrome: 'chrome',
    Opera: 'opera',
    Firefox: 'firefox',
    'Opera Mini': 'op_mini',
    'BlackBerry WebKit': 'bb',
    'Opera Mobile': 'op_mob',
    'Chrome Mobile': 'and_chr',
    // : 'android',
    // : 'and_ff',
    // : 'ie_mob',
    // : 'and_uc',
    // : 'samsung',
    // : 'and_qq',
    // : 'ios_saf'
};

function fromCamelCase(str) {
    return str.replace(/[A-Z]/g, $0 => `-${$0.toLowerCase()}`);
}

function serializeCsp(parsedCsp) {
    return Object.keys(parsedCsp)
        .reduce((text, directiveName) => {
            text += (text ? '; ' : '') + fromCamelCase(directiveName);
            if (parsedCsp[directiveName].length > 0) {
                text += ' ' + parsedCsp[directiveName].join(' ');
            }

            return text;
        }, '');
}

let lookupTargetCspLevelInCanIUseDb = memoizeSync((family, major, minor) => {
    let targetCspLevel;
    let caniuseId = caniuseIdByAgentFamily[family];
    if (caniuseId === 'ie' && parseInt(major, 10) >= 12) {
        caniuseId = 'edge';
    }
    if (caniuseId) {
        let seenNo = false;
        for (let cspLevel = maxCspLevel ; cspLevel > 0 ; cspLevel -= 1) {
            const cspIsSupportedByVersion = cspStatsByLevel[cspLevel][caniuseId];
            const majorMinorVersion = major + '.' + minor;
            const cspIsSupportedInMinorVersion = cspIsSupportedByVersion[majorMinorVersion];
            if (cspIsSupportedInMinorVersion) {
                if (/^y/.test(cspIsSupportedInMinorVersion)) {
                    targetCspLevel = cspLevel;
                    break;
                } else {
                    seenNo = true;
                }
            } else {
                const cspIsSupportedInMajorVersion = cspIsSupportedByVersion[major];
                if (cspIsSupportedInMajorVersion) {
                    if (/^y/.test(cspIsSupportedInMajorVersion)) {
                        targetCspLevel = cspLevel;
                        break;
                    } else {
                        seenNo = true;
                    }
                }
            }
        }
        if (!targetCspLevel && seenNo) {
            return 0;
        }
    }
    return targetCspLevel;
});

module.exports = (config = {}) => {
    return (req, res, next) => {
        const agent = useragent.lookup(req.headers['user-agent']);
        const oldWriteHead = res.writeHead;
        res.writeHead = (...args) => {
            const existingCspHeaderValue = res.getHeader('Content-Security-Policy');

            if (existingCspHeaderValue) {

                const parsedCsp = parseCsp(existingCspHeaderValue);
                let targetCspLevel;
                let newHeaderName;

                if (agent.family === 'IE' && agent.satisfies('11 || 10')) {
                    newHeaderName = 'X-Content-Security-Policy';
                    targetCspLevel = 1;
                } else if (agent.family === 'Safari' && agent.satisfies('6.1 || 6')) {
                    targetCspLevel = 1;
                    newHeaderName = 'X-Webkit-CSP';
                } else {
                    targetCspLevel = lookupTargetCspLevelInCanIUseDb(agent.family, agent.major, agent.minor);
                }

                if (targetCspLevel === 0) {
                    res.removeHeader('Content-Security-Policy');
                } else if (targetCspLevel > 0) {
                    let downgradedCsp = parsedCsp;
                    if (targetCspLevel < 3) {
                        downgradedCsp = downgradeCsp3ToCsp2(downgradedCsp);
                    }
                    if (targetCspLevel < 2) {
                        downgradedCsp = downgradeCsp2ToCsp1(downgradedCsp);
                    }
                    const serializedCsp = serializeCsp(downgradedCsp);
                    if (newHeaderName) {
                        res.removeHeader('Content-Security-Policy');
                        res.setHeader(newHeaderName, serializedCsp);
                    } else {
                        res.setHeader('Content-Security-Policy', serializedCsp);
                    }
                }
            }
            return oldWriteHead.call(res, ...args);
        };
        next();
    };
};
<commit_msg>Memoize the code that parses, downgrades, and reserializes the CSP.<commit_after>const useragent = require('useragent');
const memoizeSync = require('memoizesync');
const downgradeCsp3ToCsp2 = require('./downgradeCsp3ToCsp2');
const downgradeCsp2ToCsp1 = require('./downgradeCsp2ToCsp1');
require('useragent/features');
const parseCsp = require('./parseCsp');

const cspStatsByLevel = {
    1: require('caniuse-db/features-json/contentsecuritypolicy.json').stats,
    2: require('caniuse-db/features-json/contentsecuritypolicy2.json').stats
};

try {
    cspStatsByLevel[3] = require('caniuse-db/features-json/contentsecuritypolicy3.json').stats;
} catch (e) {}

const maxCspLevel = Math.max(...Object.keys(cspStatsByLevel).map(levelStr => parseInt(levelStr, 10)));

const caniuseIdByAgentFamily = {
    IE: 'ie',
    'Mobile Safari UI/WKWebView': 'mobile_safari',
    Safari: 'safari',
    Chrome: 'chrome',
    Opera: 'opera',
    Firefox: 'firefox',
    'Opera Mini': 'op_mini',
    'BlackBerry WebKit': 'bb',
    'Opera Mobile': 'op_mob',
    'Chrome Mobile': 'and_chr',
    // : 'android',
    // : 'and_ff',
    // : 'ie_mob',
    // : 'and_uc',
    // : 'samsung',
    // : 'and_qq',
    // : 'ios_saf'
};

function fromCamelCase(str) {
    return str.replace(/[A-Z]/g, $0 => `-${$0.toLowerCase()}`);
}

function serializeCsp(parsedCsp) {
    return Object.keys(parsedCsp)
        .reduce((text, directiveName) => {
            text += (text ? '; ' : '') + fromCamelCase(directiveName);
            if (parsedCsp[directiveName].length > 0) {
                text += ' ' + parsedCsp[directiveName].join(' ');
            }

            return text;
        }, '');
}

const lookupTargetCspLevelInCanIUseDb = memoizeSync((family, major, minor) => {
    let targetCspLevel;
    let caniuseId = caniuseIdByAgentFamily[family];
    if (caniuseId === 'ie' && parseInt(major, 10) >= 12) {
        caniuseId = 'edge';
    }
    if (caniuseId) {
        let seenNo = false;
        for (let cspLevel = maxCspLevel ; cspLevel > 0 ; cspLevel -= 1) {
            const cspIsSupportedByVersion = cspStatsByLevel[cspLevel][caniuseId];
            const majorMinorVersion = major + '.' + minor;
            const cspIsSupportedInMinorVersion = cspIsSupportedByVersion[majorMinorVersion];
            if (cspIsSupportedInMinorVersion) {
                if (/^y/.test(cspIsSupportedInMinorVersion)) {
                    targetCspLevel = cspLevel;
                    break;
                } else {
                    seenNo = true;
                }
            } else {
                const cspIsSupportedInMajorVersion = cspIsSupportedByVersion[major];
                if (cspIsSupportedInMajorVersion) {
                    if (/^y/.test(cspIsSupportedInMajorVersion)) {
                        targetCspLevel = cspLevel;
                        break;
                    } else {
                        seenNo = true;
                    }
                }
            }
        }
        if (!targetCspLevel && seenNo) {
            return 0;
        }
    }
    return targetCspLevel;
});

const downgradeAndSerializeCsp = memoizeSync((cspStr, targetCspLevel) => {
    const parsedCsp = parseCsp(cspStr);
    let downgradedCsp = parsedCsp;
    if (targetCspLevel < 3) {
        downgradedCsp = downgradeCsp3ToCsp2(downgradedCsp);
    }
    if (targetCspLevel < 2) {
        downgradedCsp = downgradeCsp2ToCsp1(downgradedCsp);
    }
    return serializeCsp(downgradedCsp);
});

module.exports = (config = {}) => {
    return (req, res, next) => {
        const agent = useragent.lookup(req.headers['user-agent']);
        const oldWriteHead = res.writeHead;
        res.writeHead = (...args) => {
            const existingCspHeaderValue = res.getHeader('Content-Security-Policy');

            if (existingCspHeaderValue) {
                let targetCspLevel;
                let newHeaderName;

                if (agent.family === 'IE' && agent.satisfies('11 || 10')) {
                    newHeaderName = 'X-Content-Security-Policy';
                    targetCspLevel = 1;
                } else if (agent.family === 'Safari' && agent.satisfies('6.1 || 6')) {
                    targetCspLevel = 1;
                    newHeaderName = 'X-Webkit-CSP';
                } else {
                    targetCspLevel = lookupTargetCspLevelInCanIUseDb(agent.family, agent.major, agent.minor);
                }

                if (targetCspLevel === 0) {
                    res.removeHeader('Content-Security-Policy');
                } else if (targetCspLevel > 0) {
                    let serializedCsp = downgradeAndSerializeCsp(existingCspHeaderValue, targetCspLevel);
                    if (newHeaderName) {
                        res.removeHeader('Content-Security-Policy');
                        res.setHeader(newHeaderName, serializedCsp);
                    } else {
                        res.setHeader('Content-Security-Policy', serializedCsp);
                    }
                }
            }
            return oldWriteHead.call(res, ...args);
        };
        next();
    };
};
<|endoftext|>


<commit_before>'use strict';

var express = require('express');
var routes = require('./app/routes/index.js');
var mongoose = require('mongoose');
var passport = require('passport');
var session = require('express-session');

var app = express();
require('dotenv').load();
require('./app/config/passport')(passport);

mongoose.connect(process.env.MONGO_URI);

app.use('/controllers', express.static(process.cwd() + '/app/controllers'));
app.use('/public', express.static(process.cwd() + '/public'));
app.use('/common', express.static(process.cwd() + '/app/common'));

app.use(session({
	secret: 'secretClementine',
	resave: false,
	saveUninitialized: true
}));

app.use(passport.initialize());
app.use(passport.session());

routes(app, passport);

var port = process.env.PORT || 8080;
app.listen(port,  function () {
	console.log('Node.js listening on port ' + port + '...');
});<commit_msg>Remove unused file<commit_after><|endoftext|>


<commit_before>var THREE = require("three");

var PlayerControls = require('./playercontrols');

function PlayerControlsTouch(player, domElement)
{
  PlayerControls.apply(this, arguments);

  var self = this;

  var currentTouches = {};

  var velocityTouches = {};
  this._targetVelocity = new THREE.Vector3;

  domElement.addEventListener('contextmenu', function(event) {
    event.preventDefault();
  }, false);

  domElement.addEventListener('touchstart', touchStart, false);
  domElement.addEventListener('touchmove', touchMove, false);
  domElement.addEventListener('touchend', touchEnd, false);
  domElement.addEventListener('touchcancel', touchEnd, false);

  function touchStart(event) {
    // A touch is a sign that touch controls can be used.
    self.active = true;

    for (var touch, i = 0; i < event.changedTouches.length; i++) {
      touch = event.changedTouches[i];

      currentTouches[touch.identifier] = {
        start: {
          x: touch.clientX,
          y: touch.clientY
        },
        previous: {
          x: touch.clientX,
          y: touch.clientY
        },
        current: {
          x: touch.clientX,
          y: touch.clientY
        }
      };
    }
  }

  function addRotationSpeed(touch) {
    var touchInfo = currentTouches[touch.identifier];

    self.rotationSpeedX -= 4 * (touchInfo.current.x - touchInfo.previous.x) / domElement.clientHeight;
  }

  function addVelocityTouch(touch) {
    var touchInfo = currentTouches[touch.identifier];

    var speed = -4 * (touchInfo.current.y - touchInfo.start.y) / domElement.clientHeight;

    self._targetVelocity.set(0, 0, speed);

    velocityTouches[touch.identifier] = true;
  }

  function removeVelocityTouch(touch) {
    delete velocityTouches[touch.identifier];

    if (Object.keys(velocityTouches).length === 0) {
      self._targetVelocity.set(0, 0, 0);
    }
  }

  function touchMove(event) {
    for (var touch, touchInfo, i = 0; i < event.changedTouches.length; i++) {
      touch = event.changedTouches[i];
      touchInfo = currentTouches[touch.identifier];

      touchInfo.previous = touchInfo.current;
      touchInfo.current = {
        x: touch.clientX,
        y: touch.clientY
      };

      var dxTotal = touchInfo.current.x - touchInfo.start.x;
      var dyTotal = touchInfo.current.y - touchInfo.start.y;

      if (Math.abs(dxTotal) > Math.abs(dyTotal)) {
        addRotationSpeed(touch);

        // This touch is no longer moving the player forward
        removeVelocityTouch(touch);
      }
      else {
        addVelocityTouch(touch);
      }
    }
  }

  function touchEnd(event) {
    for (var touch, i = 0; i < event.changedTouches.length; i++) {
      touch = event.changedTouches[i];

      delete currentTouches[touch.identifier];
      removeVelocityTouch(touch);
    }
  }
}

PlayerControlsTouch.prototype = Object.create(PlayerControls.prototype);

PlayerControlsTouch.prototype._updateOrientation = function(delta) {
  var player = this.player;

  // Update camera roll/pitch etc
  this.rotationSpeedX -= 4 * this.rotationSpeedX * delta;
  this.rotationSpeedY -= 4 * this.rotationSpeedY * delta;

  var movementVector = new THREE.Vector3(this.rotationSpeedX * delta, -this.rotationSpeedY * delta, 1.0);
  movementVector.normalize();

  var rotation = new THREE.Quaternion;

  rotation.setFromUnitVectors(new THREE.Vector3(0, 0, 1), movementVector);

  player.quaternion.multiply(rotation);
};

PlayerControlsTouch.prototype._updateVelocity = function(delta) {
  this.velocity.copy(this._targetVelocity);
};

module.exports = PlayerControlsTouch;
<commit_msg>Increase angular acceleration on mobile<commit_after>var THREE = require("three");

var PlayerControls = require('./playercontrols');

function PlayerControlsTouch(player, domElement)
{
  PlayerControls.apply(this, arguments);

  var self = this;

  var currentTouches = {};

  var velocityTouches = {};
  this._targetVelocity = new THREE.Vector3;

  domElement.addEventListener('contextmenu', function(event) {
    event.preventDefault();
  }, false);

  domElement.addEventListener('touchstart', touchStart, false);
  domElement.addEventListener('touchmove', touchMove, false);
  domElement.addEventListener('touchend', touchEnd, false);
  domElement.addEventListener('touchcancel', touchEnd, false);

  function touchStart(event) {
    // A touch is a sign that touch controls can be used.
    self.active = true;

    for (var touch, i = 0; i < event.changedTouches.length; i++) {
      touch = event.changedTouches[i];

      currentTouches[touch.identifier] = {
        start: {
          x: touch.clientX,
          y: touch.clientY
        },
        previous: {
          x: touch.clientX,
          y: touch.clientY
        },
        current: {
          x: touch.clientX,
          y: touch.clientY
        }
      };
    }
  }

  function addRotationSpeed(touch) {
    var touchInfo = currentTouches[touch.identifier];

    self.rotationSpeedX -= 6 * (touchInfo.current.x - touchInfo.previous.x) / domElement.clientHeight;
  }

  function addVelocityTouch(touch) {
    var touchInfo = currentTouches[touch.identifier];

    var speed = -4 * (touchInfo.current.y - touchInfo.start.y) / domElement.clientHeight;

    self._targetVelocity.set(0, 0, speed);

    velocityTouches[touch.identifier] = true;
  }

  function removeVelocityTouch(touch) {
    delete velocityTouches[touch.identifier];

    if (Object.keys(velocityTouches).length === 0) {
      self._targetVelocity.set(0, 0, 0);
    }
  }

  function touchMove(event) {
    for (var touch, touchInfo, i = 0; i < event.changedTouches.length; i++) {
      touch = event.changedTouches[i];
      touchInfo = currentTouches[touch.identifier];

      touchInfo.previous = touchInfo.current;
      touchInfo.current = {
        x: touch.clientX,
        y: touch.clientY
      };

      var dxTotal = touchInfo.current.x - touchInfo.start.x;
      var dyTotal = touchInfo.current.y - touchInfo.start.y;

      if (Math.abs(dxTotal) > Math.abs(dyTotal)) {
        addRotationSpeed(touch);

        // This touch is no longer moving the player forward
        removeVelocityTouch(touch);
      }
      else {
        addVelocityTouch(touch);
      }
    }
  }

  function touchEnd(event) {
    for (var touch, i = 0; i < event.changedTouches.length; i++) {
      touch = event.changedTouches[i];

      delete currentTouches[touch.identifier];
      removeVelocityTouch(touch);
    }
  }
}

PlayerControlsTouch.prototype = Object.create(PlayerControls.prototype);

PlayerControlsTouch.prototype._updateOrientation = function(delta) {
  var player = this.player;

  // Update camera roll/pitch etc
  this.rotationSpeedX -= 4 * this.rotationSpeedX * delta;
  this.rotationSpeedY -= 4 * this.rotationSpeedY * delta;

  var movementVector = new THREE.Vector3(this.rotationSpeedX * delta, -this.rotationSpeedY * delta, 1.0);
  movementVector.normalize();

  var rotation = new THREE.Quaternion;

  rotation.setFromUnitVectors(new THREE.Vector3(0, 0, 1), movementVector);

  player.quaternion.multiply(rotation);
};

PlayerControlsTouch.prototype._updateVelocity = function(delta) {
  this.velocity.copy(this._targetVelocity);
};

module.exports = PlayerControlsTouch;
<|endoftext|>


<commit_before>var fs = require('fs');
var child_process = require('child_process')
var max_sleep = 300
//Added a comment that achieves no real goal.

var commit_messages = [
  "Fixing an important issue with the universe.",
  "Someone poisoned the waterhole!",
  "You feeling lucky punk?",
  "Five bullets or six?",
  "Fixed memory parsing error #1337",
  "Cleaned out the intertubes",
  "AAAAAAAAAAARGH!",
  "Fixed a typo",
  "Updated the readme",
  "Fixing a typo added in the last readme update",
  "GET A HAIRCUT!",
  "Updated the readme again",
  "Found an issue with the letter 'a', so I fixed it.",
  "Incompatible dimensions found, Cthuhlu Error 666",
  "Who you calling a fool?",
  "How many more of these can I make?",
  "Fixing an error introduced in the last commit",
  "Re-updating the readme.",
  "Work in Progress",
  "WIP",
  "Quick fix",
  "Grammar fix",
  "Fixing punctuation",
  "Correcting style",
  "Logic error"
]

if ( process.argv[ 2 ] && process.argv[ 3 ] ) {
  var inFile = process.argv[ 2 ]
  var outFile = process.argv[ 3 ]
  if (process.argv [ 4 ]) max_sleep = process.argv [ 4 ]
  console.info("Writing from %s to %s, with up to %s seconds between commits", inFile, outFile, max_sleep)
  var outFD = fs.openSync(outFile, 'w')
  fs.readFile(inFile, function(err,data) {
    var length = data.length
    console.info("Bytes: %s", length)
    try {
      child_process.execFileSync('/usr/bin/git', ['add', outFile])
    } catch (e) {
      console.error("Couldn't add %s to git: %s", outFile, e)
    }
    var message = commit_messages[randomIntFromInterval(0, commit_messages.length - 1)]
    var args = ['commit', outFile, '-m', message]
    for (var counter = 0; counter < length; counter++)
    {
      var message = comm<commit_msg>Correcting style<commit_after>var fs = require('fs');
var child_process = require('child_process')
var max_sleep = 300
//Added a comment that achieves no real goal.

var commit_messages = [
  "Fixing an important issue with the universe.",
  "Someone poisoned the waterhole!",
  "You feeling lucky punk?",
  "Five bullets or six?",
  "Fixed memory parsing error #1337",
  "Cleaned out the intertubes",
  "AAAAAAAAAAARGH!",
  "Fixed a typo",
  "Updated the readme",
  "Fixing a typo added in the last readme update",
  "GET A HAIRCUT!",
  "Updated the readme again",
  "Found an issue with the letter 'a', so I fixed it.",
  "Incompatible dimensions found, Cthuhlu Error 666",
  "Who you calling a fool?",
  "How many more of these can I make?",
  "Fixing an error introduced in the last commit",
  "Re-updating the readme.",
  "Work in Progress",
  "WIP",
  "Quick fix",
  "Grammar fix",
  "Fixing punctuation",
  "Correcting style",
  "Logic error"
]

if ( process.argv[ 2 ] && process.argv[ 3 ] ) {
  var inFile = process.argv[ 2 ]
  var outFile = process.argv[ 3 ]
  if (process.argv [ 4 ]) max_sleep = process.argv [ 4 ]
  console.info("Writing from %s to %s, with up to %s seconds between commits", inFile, outFile, max_sleep)
  var outFD = fs.openSync(outFile, 'w')
  fs.readFile(inFile, function(err,data) {
    var length = data.length
    console.info("Bytes: %s", length)
    try {
      child_process.execFileSync('/usr/bin/git', ['add', outFile])
    } catch (e) {
      console.error("Couldn't add %s to git: %s", outFile, e)
    }
    var message = commit_messages[randomIntFromInterval(0, commit_messages.length - 1)]
    var args = ['commit', outFile, '-m', message]
    for (var counter = 0; counter < length; counter++)
    {
      var message = commi<|endoftext|>