<commit_before>(function(){
	"use strict";
	if (typeof(module) != "undefined")
	{
		var ideal = module.parent.exports;
	}

	ideal.Observable = ideal.Proto.clone().newSlots({
		type: "ideal.Observable",
		observations: [],
		observedSlots: []
	}).setSlots({
		init: function()
		{
			this.setObservations([]);
			//this.initObservedSlots();
		},

		initObservedSlots: function()
		{
			var self = this;
			this.observedSlots().forEach(function(slotName){
				self.initObservedSlot(slotName);
			});
		},

		initObservedSlot: function(slotName)
		{
			var self = this;
			var v = self.perform(slotName);
			this.perform("set" + slotName.capitalized(), ideal.Object_perform(v, "clone"));
			this.mySlotChanged(slotName, v, v);
		},

		observedSlots: function()
		{
			if (!this.ownsSlot("_observedSlots"))
			{
				this.setObservedSlots(this._observedSlots.copy());
			}
			return this._observedSlots;
		},

		mySlotChanged: function(slotName, oldValue, newValue)
		{
			ideal.Proto.mySlotChanged.apply(this, arguments);

			if (this.observedSlots().contains(slotName))
			{
				this.sendNotification("slotChanged", ideal.Proto.clone().newSlots({
					slotName: slotName,
					oldValue: oldValue,
					newValue: newValue
				}));

				var prefix = "child";
				ideal.Object_perform(oldValue, "removeObserverWithPrefix", this, prefix);

				var observation = ideal.Object_perform(newValue, "addObserver", this);
				ideal.Object_perform(observation, "newSlot", "parentSlotName", slotName);
				ideal.Object_perform(observation, "setPrefix", prefix);
			}
		},

		childSlotChanged: function(msg)
		{
			var slotName = msg.observation().parentSlotName();
			var value = this.perform(slotName);

			this.mySlotChanged(slotName, value, value);
		},

		addObserver: function(observer) //returns an observation not self
		{
			var observation = ideal.Observation.clone().setObserved(this).setObserver(observer).setPrefix(this.type().split(".").last().uncapitalized());
			this.observations().append(observation);
			return observation;
		},

		removeObserver: function(observer)
		{
			this.setObservations(this.observations().filter(function(observation){
				return observation.observer() != observer;
			}));
			return this;
		},

		removeObserverWithPrefix: function(observer, prefix)
		{
			this.setObservations(this.observations().filter(function(observation){
				return((observation.observer() != observer) || (observation.prefix() != prefix));
			}));
			return this;
		},

		removeAllObservers: function()
		{
			this.observations().empty();
			return this;
		},

		newNotification: function(name)
		{
			return ideal.Notification.clone().setName(name).setSender(this);
		},

		sendNotification: function(name, data)
		{

			this.newNotification(name).setData(data || null).send();
			return this;
		},

		on: function(notificationName, callback)
		{
			this.addObserver(ideal.Proto.clone().setSlot(notificationName, function(msg){
				msg.sender().removeObserver(this);
				callback();
			})).setPrefix(null);

			return this;
		},

		cancel: function()
		{
			this.removeAllObservers();
			return this;
		}
	});
})();<commit_msg>Fix for Observable.on<commit_after>(function(){
	"use strict";
	if (typeof(module) != "undefined")
	{
		var ideal = module.parent.exports;
	}

	ideal.Observable = ideal.Proto.clone().newSlots({
		type: "ideal.Observable",
		observations: [],
		observedSlots: []
	}).setSlots({
		init: function()
		{
			this.setObservations([]);
			//this.initObservedSlots();
		},

		initObservedSlots: function()
		{
			var self = this;
			this.observedSlots().forEach(function(slotName){
				self.initObservedSlot(slotName);
			});
		},

		initObservedSlot: function(slotName)
		{
			var self = this;
			var v = self.perform(slotName);
			this.perform("set" + slotName.capitalized(), ideal.Object_perform(v, "clone"));
			this.mySlotChanged(slotName, v, v);
		},

		observedSlots: function()
		{
			if (!this.ownsSlot("_observedSlots"))
			{
				this.setObservedSlots(this._observedSlots.copy());
			}
			return this._observedSlots;
		},

		mySlotChanged: function(slotName, oldValue, newValue)
		{
			ideal.Proto.mySlotChanged.apply(this, arguments);

			if (this.observedSlots().contains(slotName))
			{
				this.sendNotification("slotChanged", ideal.Proto.clone().newSlots({
					slotName: slotName,
					oldValue: oldValue,
					newValue: newValue
				}));

				var prefix = "child";
				ideal.Object_perform(oldValue, "removeObserverWithPrefix", this, prefix);

				var observation = ideal.Object_perform(newValue, "addObserver", this);
				ideal.Object_perform(observation, "newSlot", "parentSlotName", slotName);
				ideal.Object_perform(observation, "setPrefix", prefix);
			}
		},

		childSlotChanged: function(msg)
		{
			var slotName = msg.observation().parentSlotName();
			var value = this.perform(slotName);

			this.mySlotChanged(slotName, value, value);
		},

		addObserver: function(observer) //returns an observation not self
		{
			var observation = ideal.Observation.clone().setObserved(this).setObserver(observer).setPrefix(this.type().split(".").last().uncapitalized());
			this.observations().append(observation);
			return observation;
		},

		removeObserver: function(observer)
		{
			this.setObservations(this.observations().filter(function(observation){
				return observation.observer() != observer;
			}));
			return this;
		},

		removeObserverWithPrefix: function(observer, prefix)
		{
			this.setObservations(this.observations().filter(function(observation){
				return((observation.observer() != observer) || (observation.prefix() != prefix));
			}));
			return this;
		},

		removeAllObservers: function()
		{
			this.observations().empty();
			return this;
		},

		newNotification: function(name)
		{
			return ideal.Notification.clone().setName(name).setSender(this);
		},

		sendNotification: function(name, data)
		{

			this.newNotification(name).setData(data || null).send();
			return this;
		},

		on: function(notificationName, callback)
		{
			this.addObserver(ideal.Proto.clone().setSlot(notificationName, function(msg){
				msg.sender().removeObserver(this);
				callback(msg);
			})).setPrefix(null);

			return this;
		},

		cancel: function()
		{
			this.removeAllObservers();
			return this;
		}
	});
})();<|endoftext|>


<commit_before>/*jslint devel:true*/
/*global module, require*/

(function () {

    'use strict';

    var exec = require('child_process').exec,
        defaults = require('lodash.defaults');

    module.exports = function (params) {

        var options = defaults(params || {}, {
            source: 'apple-touch-icon.png',
            sizes: [16, 32, 48, 64],
            out: 'favicon.ico',
            upscale: false
        }),
            command,
            i,
            size,
            origin;

        command = 'convert ' + options.source + ' -bordercolor white -border 0 ';

        exec('identify -format "%[fx:w]" ' + options.source, function (err, stdout, stderr) {

            origin = parseInt(stdout, 10);

            for (i = 0; i < options.sizes.length; i += 1) {
                size = options.sizes[i];
                if (options.upscale || (!options.upscale && origin >= size)) {
                    command += '\\( -clone 0 -resize ' + size + 'x' + size + ' \\) ';
                }
            }

            command += '-delete 0 -alpha off -colors 256 ' + options.out;

            exec(command, function () {
                console.log('Generated favicon.ico');
            });

        });

    };

}());
<commit_msg>Added callback option, resolves #2<commit_after>/*jslint devel:true*/
/*global module, require*/

(function () {

    'use strict';

    var exec = require('child_process').exec,
        defaults = require('lodash.defaults');

    module.exports = function (params) {

        var options = defaults(params || {}, {
            source: 'apple-touch-icon.png',
            sizes: [16, 32, 48, 64],
            out: 'favicon.ico',
            upscale: false,
            callback: null
        }),
            command,
            i,
            size,
            origin;

        command = 'convert ' + options.source + ' -bordercolor white -border 0 ';

        exec('identify -format "%[fx:w]" ' + options.source, function (err, stdout, stderr) {

            origin = parseInt(stdout, 10);

            for (i = 0; i < options.sizes.length; i += 1) {
                size = options.sizes[i];
                if (options.upscale || (!options.upscale && origin >= size)) {
                    command += '\\( -clone 0 -resize ' + size + 'x' + size + ' \\) ';
                }
            }

            command += '-delete 0 -alpha off -colors 256 ' + options.out;

            exec(command, function () {
                console.log('Generated favicon.ico');
                if (options.callback) {
                    options.callback();
                }
            });

        });

    };

}());
<|endoftext|>


<commit_before>#!/usr/bin/env node

var async = require('async');
var cli = require('cli');

var fs = require('fs');

var re = require('./lib/regex');
var base = require('./lib/base');

var getRegExp = re.getRegExp;
var getDiff = base.getDiff;
var iterateLines = base.iterateLines;
var log = base.log;

var updateNotifier = require('update-notifier');

var notifier = updateNotifier();

if (notifier.update) {
	notifier.notify(true);
}

var argv = base.argv;

var args = base.args;

var VARS = base.VARS;
var QUIET = base.QUIET;
var INLINE_REPLACE = base.INLINE_REPLACE;

var INDENT = log.INDENT;

var PREFIX_LINE_NUM = base.PREFIX_LINE_NUM;

var convertCss = require('./lib/css');
var convertHtml = require('./lib/html');
var convertJs = require('./lib/js');
var convertVars = require('./lib/vars');

var trackedFiles = {};

var series = args.map(
	function(file) {
		return function(cb) {
			fs.readFile(
				file,
				'utf-8',
				function(err, data) {
					if (err) {
						return cb(err);
					}

					var formatter;

					if (re.REGEX_EXT_CSS.test(file)) {
						formatter = function(content, file, lineOffset) {
							content = convertCss(content, file, lineOffset);

							if (VARS) {
								content = convertVars(content, file, lineOffset);
							}

							return content;
						};
					}
					else if (re.REGEX_EXT_JS.test(file)) {
						formatter = convertJs;
					}
					else if (re.REGEX_EXT_HTML.test(file)) {
						formatter = convertHtml;
					}

					var content = formatter(data, file, 0);

					var changed = (content != data);

					var logSize = log.size();

					var includeHeaderFooter = (logSize || !QUIET);

					if (includeHeaderFooter) {
						console.log('File:'.blackBG + ' ' + file.underline);
					}

					if (logSize) {
						log.flush(true);

						trackedFiles[file] = true;
					}
					else if (includeHeaderFooter) {
						console.log(INDENT + 'clear');
					}

					if (includeHeaderFooter) {
						console.log('----'.subtle);
					}

					if (INLINE_REPLACE && changed) {
						fs.writeFile(
							file,
							content,
							function(err, result) {
								if (err) {
									return cb(err);
								}

								cb(null, content);
							}
						);
					}
					else {
						cb(null, content);
					}
				}
			);
		};
	}
);

var callback = function() {};

if (base.OPEN_FILES) {
	callback = function(err, result) {
		var filesToOpen = Object.keys(trackedFiles);

		if (filesToOpen.length) {
			cli.exec(
				'git config --get user.editor',
				function(res) {
					cli.exec(
						'open -a "' + res[0] + '" "' + filesToOpen.join('" "') + '"'
					);
				}
			);
		}
	};
}

async.series(series, callback);<commit_msg>Remove old index.js<commit_after><|endoftext|>


<commit_before>(function () {
    'use strict';

    var ButtonDropdownComponent = require('../lib/button-dropdown-component.jsx');

    describe('Button Dropdown', function () {
        it('should fail', function () {

        });
    });
}());
<commit_msg>red - force it to be a react component<commit_after>(function () {
    'use strict';

    var ButtonDropdownComponent = require('../lib/button-dropdown-component.jsx'),

        React = require('react');

    describe('Button Dropdown', function () {
        it('should be a react component', function () {
            React.createElement(ButtonDropdownComponent);
        });
    });
}());
<|endoftext|>


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

// Run this to compress all the things!
gulp.task('production', ['images', 'minifyCss', 'uglifyJs']);
<commit_msg>Adds markup task to production.<commit_after>var gulp = require('gulp');

// Run this to compress all the things!
gulp.task('production', ['markup', 'images', 'minifyCss', 'uglifyJs']);
<|endoftext|>


<commit_before>'use strict';

var SkyRemote = require('sky-remote');
var SkyQCheck = require('sky-q');
var Accessory, Service, Characteristic;

module.exports = function(homebridge) {

	Accessory = homebridge.platformAccessory;
	Service = homebridge.hap.Service;
	Characteristic = homebridge.hap.Characteristic;
	homebridge.registerAccessory("homebridge-sky-q", "SkyQ", SkyQAccessory);
};

function SkyQAccessory(log, config, api) {

	this.log = log;
	this.config = config;
	this.name = config.name || 'Sky Q';
	this.stateful = false;

	if (this.config.cmd === 'power' || !this.config.cmd) {

		this.stateful = true;
	}

	var remoteControl = new SkyRemote(config.ipAddress);
	var boxCheck = new SkyQCheck({ip:config.ipAddress})
	this.skyQ = remoteControl;
	this.box = boxCheck;
}

SkyQAccessory.prototype = {

	setPowerState: function(powerOn, callback, context) {

		let funcContext = 'fromSetPowerState';
		var switchService = this.service;
		var log = this.log;
		var name = this.name;
		var stateful = this.stateful;
		var state = powerOn ? 'on' : 'off';
		var delayed = this.config.delayed;
		var skyQ = this.skyQ;
		var box = this.box;

		function sendCmd() {
			log('Sending "' + cmd + '" command to ' + name + '...');

			skyQ.press(cmd, function(error) {

				if (error) {

					log('Failed to send cmd ' + name + '. ' + error);
				}

				if (stateful === true) {

					callback(); // Do this early or Siri moans it takes too long
					if (state === 'on' && delayed === true) {
						setTimeout(function() {

							skyQ.press('sky', function(error) {

								log('Sending "sky" command to ' + name + '...');

			                	       		if (error) {

                        				        	log('Failed to send cmd ' + name + '. ' + error);
	                       					}

							});

						}, 20000);

					}

				} else {
					if (!delayed === true) {
						callback();
					}
					setTimeout(function() {
						switchService.getCharacteristic(Characteristic.On).getValue(null, funcContext);
					}, 1000);
				}
			});
		}
		if (this.config.cmd) {

			var cmd = this.config.cmd.split(',');
		} else {

			var cmd = 'power';
		}

		if (stateful === false && this.config.autoOn === true) {

			box.getPowerState().then(isOn=>{
				if (isOn) {

					log(name + " is on :-)")
					sendCmd();
				} else {

					log(name + " is in standby :-(")
					skyQ.press(['power','backup'], function(error) {

						log('Sending "power,backup" command to ' + name + '...');

						if (error) {

							log('Failed to send cmd ' + name + '. ' + error);
						}
					});
					if (delayed === true) {
						log("Delayed 'sky' press enabled");
						callback(); // Do this early or Siri moans that it takes too long
						setTimeout(function() {

							skyQ.press(['sky','backup'], function(error) {

								log('Sending "sky,backup" command to ' + name + '...');
								if (error) {

									log('Failed to send cmd ' + name + '. ' + error);
								}
							});
							setTimeout(function() {

								sendCmd();

							}, 1000); //Give the box a chance to get back to a channel before sending the cmd
						}, 20000);
					} else {

						setTimeout(function() {

							sendCmd();

						}, 3000); //Give the box a chance to start up before we send the cmd
					}
				}
			}).catch(err=>{
				log("Unable to determine power state")
				log("Perhaps looking at this error will help you figure out why" + err)
			})

		} else {

			box.getPowerState().then(isOn=>{
				if ((isOn && state === 'on') || (!isOn && state === 'off')) {
					callback();
					setTimeout(function() {
						switchService.getCharacteristic(Characteristic.On).getValue(null, funcContext);
					}, 1000);

				} else {
					sendCmd();
				}
			}).catch(err=>{
				log("Unable to determine power state")
				log("Perhaps looking at this error will help you figure out why" + err)
			})
		}

	},

	identify: function(callback) {

		this.log("Identify...");

		callback();
	},

	getState: function(callback) {

		if (this.stateful) {

			this.box.getPowerState().then(isOn=>{
	  		if (isOn) {

			    this.log(this.name + " is on :-)")
			  } else {

			    this.log(this.name + " is in standby :-(")
			  }
			  callback(null, isOn);

			}).catch(err=>{

			  this.log("Unable to determine power state")
			  this.log("Perhaps looking at this error will help you figure out why" + err)
			  callback(err || new Error('Error getting state of ' + this.name));
			})
		} else {

		  callback(null, 0);
		}
	},

	getServices: function() {

		var switchService = new Service.Switch(this.name);

		var characteristic = switchService.getCharacteristic(Characteristic.On).on('set', this.setPowerState.bind(this));

		characteristic.on('get', this.getState.bind(this));

		this.service = switchService;

		return [switchService];
	}
};
<commit_msg>Tied up various callback() code to avoid Siri timeouts<commit_after>'use strict';

var SkyRemote = require('sky-remote');
var SkyQCheck = require('sky-q');
var Accessory, Service, Characteristic;

module.exports = function(homebridge) {

	Accessory = homebridge.platformAccessory;
	Service = homebridge.hap.Service;
	Characteristic = homebridge.hap.Characteristic;
	homebridge.registerAccessory("homebridge-sky-q", "SkyQ", SkyQAccessory);
};

function SkyQAccessory(log, config, api) {

	this.log = log;
	this.config = config;
	this.name = config.name || 'Sky Q';
	this.stateful = false;

	if (this.config.cmd === 'power' || !this.config.cmd) {

		this.stateful = true;
	}

	var remoteControl = new SkyRemote(config.ipAddress);
	var boxCheck = new SkyQCheck({ip:config.ipAddress})
	this.skyQ = remoteControl;
	this.box = boxCheck;
}

SkyQAccessory.prototype = {

	setPowerState: function(powerOn, callback, context) {

		let funcContext = 'fromSetPowerState';
		var switchService = this.service;
		var log = this.log;
		var name = this.name;
		var stateful = this.stateful;
		var state = powerOn ? 'on' : 'off';
		var delayed = this.config.delayed;
		var skyQ = this.skyQ;
		var box = this.box;

		function sendCmd(callBacked) {
			log('Sending "' + cmd + '" command to ' + name + '...');

			if (cmd.length > 6 && callBacked === false) {
				// If it's a long command string that will take a while, immedately callback() to avoid Siri timeout
				callBacked = true;
				callback();
			}

			skyQ.press(cmd, function(error) {

				if (error) {

					log('Failed to send cmd ' + name + '. ' + error);
				}

				if (stateful === true) {

					callback(); // Do this early or Siri moans it takes too long
					if (state === 'on' && delayed === true) {
						setTimeout(function() {

							skyQ.press('sky', function(error) {

								log('Sending "sky" command to ' + name + '...');

			                	       		if (error) {

                        				        	log('Failed to send cmd ' + name + '. ' + error);
	                       					}

							});

						}, 20000);

					}

				} else {
					if (callBacked === false) {
						callback();
					}
					setTimeout(function() {
						switchService.getCharacteristic(Characteristic.On).getValue(null, funcContext);
					}, 1000);
				}
			});
		}
		if (this.config.cmd) {

			var cmd = this.config.cmd.split(',');
		} else {

			var cmd = 'power';
		}

		if (stateful === false && this.config.autoOn === true) {

			box.getPowerState().then(isOn=>{
				if (isOn) {

					log(name + " is on :-)")
					sendCmd(false);
				} else {

					log(name + " is in standby :-(")
					skyQ.press(['power','backup'], function(error) {

						log('Sending "power,backup" command to ' + name + '...');

						if (error) {

							log('Failed to send cmd ' + name + '. ' + error);
						}
					});
					if (delayed === true) {
						log("Delayed 'sky' press enabled");
						callback(); // Do this early or Siri moans that it takes too long
						setTimeout(function() {

							skyQ.press(['sky','backup'], function(error) {

								log('Sending "sky,backup" command to ' + name + '...');
								if (error) {

									log('Failed to send cmd ' + name + '. ' + error);
								}
							});
							setTimeout(function() {

								sendCmd(true);

							}, 1000); //Give the box a chance to get back to a channel before sending the cmd
						}, 20000);
					} else {

						setTimeout(function() {

							sendCmd(false);

						}, 3000); //Give the box a chance to start up before we send the cmd
					}
				}
			}).catch(err=>{
				log("Unable to determine power state 1")
				log("Perhaps looking at this error will help you figure out why" + err)
			  	callback(err || new Error('Error getting state of ' + this.name));
			})

		} else {

			box.getPowerState().then(isOn=>{
				if ((isOn && state === 'on') || (!isOn && state === 'off')) {
					callback();
					setTimeout(function() {
						switchService.getCharacteristic(Characteristic.On).getValue(null, funcContext);
					}, 1000);

				} else {
					sendCmd(false);
				}
			}).catch(err=>{
				log("Unable to determine power state 2")
				log("Perhaps looking at this error will help you figure out why" + err)
			  	callback(err || new Error('Error getting state of ' + this.name));
			})
		}

	},

	identify: function(callback) {

		this.log("Identify...");

		callback();
	},

	getState: function(callback) {

		if (this.stateful) {

			this.box.getPowerState().then(isOn=>{
	  		if (isOn) {

			    this.log(this.name + " is on :-)")
			  } else {

			    this.log(this.name + " is in standby :-(")
			  }
			  callback(null, isOn);

			}).catch(err=>{

			  this.log("Unable to determine power state 3")
			  this.log("Perhaps looking at this error will help you figure out why" + err)
			  callback(err || new Error('Error getting state of ' + this.name));
			})
		} else {

		  callback(null, 0);
		}
	},

	getServices: function() {

		var switchService = new Service.Switch(this.name);

		var characteristic = switchService.getCharacteristic(Characteristic.On).on('set', this.setPowerState.bind(this));

		characteristic.on('get', this.getState.bind(this));

		this.service = switchService;

		return [switchService];
	}
};
<|endoftext|>


<commit_before>var loader = require('./loader.js');
var request = require('request');
var jsdom = require('jsdom');
var jsonfile = require('jsonfile');
var paramCase = require('param-case');

var walk = require('walk');
var files = [];

var st = {};

// Walker options
var walker  = walk.walk('./webidl/webidl', { followLinks: false });

walker.on('file', function(root, stat, next) {
  st = loader.file(root + '/' + stat.name, st);
  next();
});

walker.on('end', function() {
  "use strict";

  var interfaces = st.interfaces;
  var keys = [];

  for (let name in interfaces) {
    let inter = interfaces[name];
    let platform = 'API';
    if (name === 'CSS2Properties') {
      platform = 'CSS';
    }
    keys.push([`${name}`, `${platform}/${name}`]);
    if (inter.members) {
      for (let i in inter.members) {
        let member = inter.members[i];
        if (name === 'CSS2Properties') {
          keys.push([`${name}/${member.name}`, `${platform}/${paramCase(member.name)}`]);
        } else {
          keys.push([`${name}/${member.name}`, `${platform}/${name}/${member.name}`]);
        }
      }
    }
  }

  // var def = jsonfile.readFileSync('webidl.json');
  var def = {};
  var walk = function (i) {
    if (i === keys.length) {
      output();
      return;
    }
    let key = keys[i][0];
    if (def[key]) {
      walk(i+1);
      return;
    }
    var name = keys[i][1];
    var url = `http://developer.mozilla.org/en-US/docs/Web/${name}`;
    request({
      method: 'GET',
      uri: url
    }, function (error, response, body) {
      if (!error && response.statusCode === 200) {
        var doc = null;
        jsdom.env({
          url: url,
          scripts: ["http://code.jquery.com/jquery.js"],
          done: function (errors, window) {
            var $ = window.$;
            var nodes = $('p');
            nodes.each(function () {
              var text = $.trim($(this).text());
              if (text !== '') {
                doc = text;
                console.log(i, key, doc);
                def[key] = {
                  "!url": url,
                  "!doc": doc
                }
                return false;
              }
            });
            walk(i+1);
          }
        });
        // request({
          // method: 'GET',
          // uri: response.headers['location']
        // }, function (error, response, body) {
          // let p = cheerio.load(body)('p');
          // console.log(p);
        // });
      } else {
        walk(i+1);
      }
    });
  };

  var output = function () {
    console.log(JSON.stringify(def, null, 2));
  };

  walk(0);
});

<commit_msg>Skip 'need tech review'<commit_after>var loader = require('./loader.js');
var request = require('request');
var jsdom = require('jsdom');
var jsonfile = require('jsonfile');
var paramCase = require('param-case');

var walk = require('walk');
var files = [];

var st = {};

// Walker options
var walker  = walk.walk('./webidl/webidl', { followLinks: false });

walker.on('file', function(root, stat, next) {
  st = loader.file(root + '/' + stat.name, st);
  next();
});

walker.on('end', function() {
  "use strict";

  var interfaces = st.interfaces;
  var keys = [];

  for (let name in interfaces) {
    let inter = interfaces[name];
    let platform = 'API';
    if (name === 'CSS2Properties') {
      platform = 'CSS';
    }
    keys.push([`${name}`, `${platform}/${name}`]);
    if (inter.members) {
      for (let i in inter.members) {
        let member = inter.members[i];
        if (name === 'CSS2Properties') {
          keys.push([`${name}/${member.name}`, `${platform}/${paramCase(member.name)}`]);
        } else {
          keys.push([`${name}/${member.name}`, `${platform}/${name}/${member.name}`]);
        }
      }
    }
  }

  // var def = jsonfile.readFileSync('webidl.json');
  var def = {};
  var walk = function (i) {
    if (i === keys.length) {
      output();
      return;
    }
    let key = keys[i][0];
    if (def[key]) {
      walk(i+1);
      return;
    }
    var name = keys[i][1];
    var url = `http://developer.mozilla.org/en-US/docs/Web/${name}`;
    request({
      method: 'GET',
      uri: url
    }, function (error, response, body) {
      if (!error && response.statusCode === 200) {
        var doc = null;
        jsdom.env({
          url: url,
          scripts: ["http://code.jquery.com/jquery.js"],
          done: function (errors, window) {
            var $ = window.$;
            var nodes = $('p');
            nodes.each(function () {
              var text = $.trim($(this).text());
              if (text !== '' && text !== 'This article is in need of a technical review.') {
                doc = text;
                console.log(i, key, doc);
                def[key] = {
                  "!url": url,
                  "!doc": doc
                }
                return false;
              }
            });
            walk(i+1);
          }
        });
        // request({
          // method: 'GET',
          // uri: response.headers['location']
        // }, function (error, response, body) {
          // let p = cheerio.load(body)('p');
          // console.log(p);
        // });
      } else {
        walk(i+1);
      }
    });
  };

  var output = function () {
    console.log(JSON.stringify(def, null, 2));
  };

  walk(0);
});

<|endoftext|>


<commit_before>
//only exports browser api. use chloride module
//to get automatic fallbacks!
module.exports = require('./browser')
<commit_msg>use tweetnacl by default, then switch to wasm<commit_after>
//only exports browser api. use chloride module
//to get automatic fallbacks!

//load tweetnacl first, so that it works sync, and everything is there.
module.exports = require('sodium-browserify-tweetnacl')

//now load wasm which has to be async, ugh.
var libsodium = require('libsodium-wrappers')
libsodium.ready.then(function (value, what) {
  require('./browser') (libsodium, module.exports)
}).catch(function (err) {
  //escape from promise land, ugh
  setTimeout(function () {
    console.log(err.stack)
    process.exit(1)
  })
})

<|endoftext|>


<commit_before>var express = require('express');
var restAdaptor = require('./lib/rest-adaptor');
var socketAdaptor = require('./lib/socket-adaptor');

express.application.kotoumi = function(params) {
  params = params || {};

  params.connection = params.connection || new Connection(params);

  params.prefix = params.prefix || '';
  params.prefix = params.prefix.replace(/\/$/, '');

  restAdaptor.registerHandlers(this, params);

  if (params.server)
    socketAdaptor.registerHandlers(this, params.server, params);
}
<commit_msg>Load backend-adaptor correctly<commit_after>var express = require('express');
var Connection = require('./lib/backend-adaptor').Connection;
var restAdaptor = require('./lib/rest-adaptor');
var socketAdaptor = require('./lib/socket-adaptor');

express.application.kotoumi = function(params) {
  params = params || {};

  params.connection = params.connection || new Connection(params);

  params.prefix = params.prefix || '';
  params.prefix = params.prefix.replace(/\/$/, '');

  restAdaptor.registerHandlers(this, params);

  if (params.server)
    socketAdaptor.registerHandlers(this, params.server, params);
}
<|endoftext|>


<commit_before>'use strict';
var gutil = require('gulp-util'),
    through = require('through2'),
    useref = require('node-useref');

module.exports = function () {
    return through.obj(function (file, enc, cb) {
        if (file.isStream()) {
            this.emit('error', new gutil.PluginError('gulp-useref', 'Streaming not supported'));
            return cb();
        }

        var output = useref(file.contents.toString());
        var html = output[0];

        try {
            file.contents = new Buffer(html);
        } catch (err) {
            this.emit('error', new gutil.PluginError('gulp-useref', err));
        }

        this.push(file);

        cb();
    });
};

module.exports.assets = function (options) {
    var path = require('path'),
        fs = require('fs'),
        braceExpandJoin = require('brace-expand-join'),
        glob = require('glob'),
        stripBom = require('strip-bom'),
        isAbsoluteUrl = require('is-absolute-url'),
        opts = options || {},
        types = opts.types || ['css', 'js'],
        restoreStream = through.obj();

    var assets = through.obj(function (file, enc, cb) {
        var output = useref(file.contents.toString());
        var assets = output[1];

        types.forEach(function (type) {
            var files = assets[type];
            if (files) {
                Object.keys(files).forEach(function (name) {
                    var buffer = [];
                    var filepaths = files[name].assets;

                    if (filepaths.length) {
                        var searchPaths,
                            joinedFile;

                        if (files[name].searchPaths) {
                            searchPaths = braceExpandJoin(file.cwd, files[name].searchPaths);
                        } else if (opts.searchPath) {
                            if (Array.isArray(opts.searchPath)) {
                                if (opts.searchPath.length > 1) {
                                    searchPaths = '{' + opts.searchPath.join(',') + '}';
                                } else if (opts.searchPath.length === 1) {
                                    searchPaths = opts.searchPath[0];
                                }
                            } else {
                                searchPaths = opts.searchPath;
                            }

                            searchPaths = braceExpandJoin(file.cwd, searchPaths);
                        }

                        filepaths.forEach(function (filepath) {
                            var pattern,
                                filenames;

                            if (!isAbsoluteUrl(filepath)) {
                                pattern = braceExpandJoin((searchPaths || file.base), filepath);
                                filenames = glob.sync(pattern);
                                if (!filenames.length) {
                                    filenames.push(pattern);
                                }
                                try {
                                    buffer.push(stripBom(fs.readFileSync(filenames[0])));
                                } catch (err) {
                                    this.emit('error', new gutil.PluginError('gulp-useref', err));
                                }
                            }
                        }, this);

                        if (buffer.length) {
                            joinedFile = new gutil.File({
                                cwd: file.cwd,
                                base: file.base,
                                path: path.join(file.base, name),
                                contents: new Buffer(buffer.join(gutil.linefeed))
                            });

                            this.push(joinedFile);
                        }
                    }

                }, this);
            }
        }, this);

        restoreStream.write(file, cb);
    });

    assets.restore = function () {
        return restoreStream.pipe(through.obj(), { end: false });
    };

    return assets;
};
<commit_msg>don't sort results to make sure the first result is always the expected one<commit_after>'use strict';
var gutil = require('gulp-util'),
    through = require('through2'),
    useref = require('node-useref');

module.exports = function () {
    return through.obj(function (file, enc, cb) {
        if (file.isStream()) {
            this.emit('error', new gutil.PluginError('gulp-useref', 'Streaming not supported'));
            return cb();
        }

        var output = useref(file.contents.toString());
        var html = output[0];

        try {
            file.contents = new Buffer(html);
        } catch (err) {
            this.emit('error', new gutil.PluginError('gulp-useref', err));
        }

        this.push(file);

        cb();
    });
};

module.exports.assets = function (options) {
    var path = require('path'),
        fs = require('fs'),
        braceExpandJoin = require('brace-expand-join'),
        glob = require('glob'),
        stripBom = require('strip-bom'),
        isAbsoluteUrl = require('is-absolute-url'),
        opts = options || {},
        types = opts.types || ['css', 'js'],
        restoreStream = through.obj();

    var assets = through.obj(function (file, enc, cb) {
        var output = useref(file.contents.toString());
        var assets = output[1];

        types.forEach(function (type) {
            var files = assets[type];
            if (files) {
                Object.keys(files).forEach(function (name) {
                    var buffer = [];
                    var filepaths = files[name].assets;

                    if (filepaths.length) {
                        var searchPaths,
                            joinedFile;

                        if (files[name].searchPaths) {
                            searchPaths = braceExpandJoin(file.cwd, files[name].searchPaths);
                        } else if (opts.searchPath) {
                            if (Array.isArray(opts.searchPath)) {
                                if (opts.searchPath.length > 1) {
                                    searchPaths = '{' + opts.searchPath.join(',') + '}';
                                } else if (opts.searchPath.length === 1) {
                                    searchPaths = opts.searchPath[0];
                                }
                            } else {
                                searchPaths = opts.searchPath;
                            }

                            searchPaths = braceExpandJoin(file.cwd, searchPaths);
                        }

                        filepaths.forEach(function (filepath) {
                            var pattern,
                                filenames;

                            if (!isAbsoluteUrl(filepath)) {
                                pattern = braceExpandJoin((searchPaths || file.base), filepath);
                                filenames = glob.sync(pattern, { nosort: true });
                                if (!filenames.length) {
                                    filenames.push(pattern);
                                }
                                try {
                                    buffer.push(stripBom(fs.readFileSync(filenames[0])));
                                } catch (err) {
                                    this.emit('error', new gutil.PluginError('gulp-useref', err));
                                }
                            }
                        }, this);

                        if (buffer.length) {
                            joinedFile = new gutil.File({
                                cwd: file.cwd,
                                base: file.base,
                                path: path.join(file.base, name),
                                contents: new Buffer(buffer.join(gutil.linefeed))
                            });

                            this.push(joinedFile);
                        }
                    }

                }, this);
            }
        }, this);

        restoreStream.write(file, cb);
    });

    assets.restore = function () {
        return restoreStream.pipe(through.obj(), { end: false });
    };

    return assets;
};
<|endoftext|>


<commit_before>import Dispatcher from './Dispatcher';

function createDispatchable(type) {
  return {
    dispatch(payload) {
      // TODO ActionCreator displayName to make funcName belongs to ActionCreator
      Dispatcher.dispatch({type, payload});
    }
  };
}

function createAction(funcName, func, spec) {
  var action, scope = Object.assign(createDispatchable(funcName), spec);
  action = func.bind(scope);
  action.actionType = funcName;
  return action;
}

var ActionCreator = function (spec) {
  var func, funcName;
  for (var propName in spec) {
    if (!spec.hasOwnProperty(propName)) {
      continue;
    }

    switch (typeof spec[propName]) {
      case 'function':
        funcName = propName;
        func = spec[funcName];

        this[funcName] = createAction(funcName, func, spec);

        // HACK
        spec[funcName] = this[funcName];

        break;
      default:
        this[propName] = spec[propName];
        break;
    }
  }
};

export default ActionCreator;<commit_msg>Added _ to private methods<commit_after>import Dispatcher from './Dispatcher';

function _createDispatchable(type) {
  return {
    dispatch(payload) {
      // TODO ActionCreator displayName to make funcName belongs to ActionCreator
      Dispatcher.dispatch({type, payload});
    }
  };
}

function _createAction(funcName, func, spec) {
  var action, scope = Object.assign(_createDispatchable(funcName), spec);
  action = func.bind(scope);
  action.actionType = funcName;
  return action;
}

var ActionCreator = function (spec) {
  var func, funcName;
  for (var propName in spec) {
    if (!spec.hasOwnProperty(propName)) {
      continue;
    }

    switch (typeof spec[propName]) {
      case 'function':
        funcName = propName;
        func = spec[funcName];

        this[funcName] = _createAction(funcName, func, spec);

        // HACK
        spec[funcName] = this[funcName];

        break;
      default:
        this[propName] = spec[propName];
        break;
    }
  }
};

export default ActionCreator;<|endoftext|>


<commit_before>var React = require('react-native');
var TwoSideMenus = require('react-native-2-side-menus');
var Scene = require('scene-router');

var {
  Component,
  AppRegistry,
  StyleSheet,
  Text,
  View,
} = React;

async function wait(delay) {
  return new Promise((resolve) => {
    setTimeout(resolve, delay);
  });
}

class Content extends Component {
  constructor(props) {
    super(props);
  }

  render() {
    return (
      <View style={{ flex: 1, backgroundColor: this.props.color, justifyContent: 'center', alignItems: 'center' }}/>
    );
  }
}

class Menu extends Component {
  constructor(props) {
    super(props);
  }

  menuMightOpen() {
    console.log('menu might open');
  }

  menuDidOpen() {
    console.log('menu did open');
  }

  menuDidClose() {
    console.log('menu did close');
  }

  render() {
    return (
      <Content {...this.props}/>
    );
  }
}

class Login extends Component {
  constructor(props) {
    super(props);
  }

  render() {
    return <Content color="blue"/>
  }
}

class App extends Component {
  constructor(props) {
    super(props);
  }

  componentDidMount() {
    const { menu, leftMenu, rightMenu } = this.refs;
    menu.moreLifeCycles(leftMenu, rightMenu);
  }

  render() {
    return (
      <TwoSideMenus
        ref="menu"
        leftMenu={<Menu ref="leftMenu" color="yellow"/>}
        rightMenu={<Menu ref="rightMenu" color="red"/>}>
        {this.props.children}
      </TwoSideMenus>
    );
  }
}

class Intro extends Component {
  constructor(props) {
    super(props);
  }

  render() {
    return (
      <Content color="black"/>
    );
  }
}

class Faq extends Component {
  constructor(props) {
    super(props);
  }

  render() {
    return (
      <Content color="brown"/>
    );
  }
}

class Main extends Component {
  constructor(props) {
    super(props);
  }

  async componentDidMount() {
    const { scene } = this.refs;

    await wait(2000);
    scene.goto('/home/info', { side:'right', withAnimation: true });

    await wait(2000);
    scene.goto('/home/faq', { side:'right', withAnimation: true });
  }

  render() {
    return (
      <Scene ref="scene" initialPath="/login">
        <Scene path="login" component={Login}/>
        <Scene path="home" component={App} fresh={true}>
          <Scene path="info" component={Intro}/>
          <Scene path="faq" component={Faq}/>
        </Scene>
      </Scene>
    );
  }
}

AppRegistry.registerComponent('ExampleWith2SideMenus', () => Main);
<commit_msg>fixed #5 - incorporated 2 side menus example<commit_after>var React = require('react-native');
var TwoSideMenus = require('react-native-2-side-menus');
var Scene = require('scene-router');

var {
  Component,
  AppRegistry,
  StyleSheet,
  Text,
  View,
} = React;

async function wait(delay) {
  return new Promise((resolve) => {
    setTimeout(resolve, delay);
  });
}

class Content extends Component {
  constructor(props) {
    super(props);
  }

  render() {
    return (
      <View style={{ flex: 1, opacity:this.props.opacity, backgroundColor: this.props.color, justifyContent: 'center', alignItems: 'center' }}/>
    );
  }
}

Content.defaultProps = {
  opacity: 1
};

class Menu extends Component {
  constructor(props) {
    super(props);
  }

  menuMightOpen() {
    console.log('menu might open');
  }

  menuDidOpen() {
    console.log('menu did open');
  }

  menuDidClose() {
    console.log('menu did close');
  }

  render() {
    return (
      <Content {...this.props}/>
    );
  }
}

class Login extends Component {
  constructor(props) {
    super(props);
  }

  render() {
    return <Content color="blue" opacity={1}/>
  }
}

class Intro extends Component {
  constructor(props) {
    super(props);
  }

  render() {
    return (
      <Content color="black"/>
    );
  }
}

class Faq extends Component {
  constructor(props) {
    super(props);
  }

  render() {
    return (
      <Content color="brown"/>
    );
  }
}

class App extends Component {
  constructor(props) {
    super(props);
  }

  async componentDidMount() {
    const { menu, leftMenu, rightMenu, scene } = this.refs;

    menu.moreLifeCycles(leftMenu, rightMenu);

    await wait(2000);
    scene.goto('/home/info', { side:'right', withAnimation: true });

    await wait(2000);
    scene.goto('/home/faq', { side:'right', withAnimation: true });
  }

  render() {
    return (
      <TwoSideMenus
        ref="menu"
        leftMenu={<Menu ref="leftMenu" color="yellow"/>}
        rightMenu={<Menu ref="rightMenu" color="red"/>}>
        <Scene ref="scene" initialPath="/login">
          <Scene path="login" component={Login}/>
          <Scene path="home" component={App} flatten={true}>
            <Scene path="info" component={Intro}/>
            <Scene path="faq" component={Faq}/>
          </Scene>
        </Scene>
      </TwoSideMenus>
    );
  }
}

AppRegistry.registerComponent('ExampleWith2SideMenus', () => App);
<|endoftext|>


<commit_before>var re_hex = /&#[xX][\da-fA-F]+;?/g,
	re_strictHex = /&#x[\da-f]+;/gi,
	re_charCode = /&#\d+;?/g,
	re_strictCharCode = /&#\d+;/g,
	re_notUTF8 = /[\u00c0-\u00d6\u00d8-\u00f6\u00f8-\u02ff\u0370-\u037d\u037f-\u1fff\u200c\u200d\u2070-\u218f\u2c00-\u2fef\u3001-\ud7ff\uf900-\ufdcf\ufdf0-\ufffd]/g,
	fromCharCode = String.fromCharCode,
	num_func = function(num){return fromCharCode(parseInt(num.substr(2), 10));},
	hex_func = function(hex){return fromCharCode(parseInt(hex.substr(3), 16));},
	strictNum_func = function(num){return fromCharCode(num.slice(2, -1));},
	strictHex_func = function(num){return fromCharCode(parseInt(num.slice(3, -1), 16));},
	charCode_func = function(c){ return "&#" +c.charCodeAt(0) +";";};

var fetch = function(filename, inherits){
	var obj = require("./entities/" +filename +".json");

	if(inherits) for(var name in inherits) obj[name] = inherits[name];

	var re = Object.keys(obj).sort().join("|").replace(/(\w+)\|\1;/g, "$1;?");
	// add regex for hex and char codes
	re += '|' + re_hex.source.substr(1) + '|' + re_charCode.source.substr(1);

	return {
		func: function(name){
			if (name.charAt(1) === '#') {
				if (name.charAt(2).toLowerCase() === 'x') {
					return hex_func(name);
				}
				return num_func(name);
			}
			return obj[name.substr(1)];
		},
		re: new RegExp("&(?:" +re +")", "g"),
		obj: obj
	};
};

var getReverse = function(obj){
	var reverse = Object.keys(obj).reduce(function(reverse, name){
		reverse[obj[name]] = name;
		return reverse;
	}, {});

	return {
		func: function(name){ return "&" +reverse[name]; },
		re: new RegExp("\\" +Object.keys(reverse).sort().join("|\\"), "g")
	};
};

var modes = ["XML", "HTML4", "HTML5"];

module.exports = {
	decode: function(data, level){
		if(!modes[level]) level = 0;
		return module.exports["decode" +modes[level]](data);
	},
	encode: function(data, level){
		if(!modes[level]) level = 0;
		return module.exports["encode" +modes[level]](data);
	}
};

var tmp;

modes.forEach(function(name){
	var obj = fetch(name.toLowerCase(), tmp),
		regex = obj.re,
		func = obj.func;

	tmp = obj.obj;

	module.exports["decode" +name] = function(data){
		return data
			.replace(regex, func);
	};

	var reverse = getReverse(obj.obj),
		reverse_re = reverse.re,
		reverse_func = reverse.func;

	module.exports["encode" +name] = function(data){
		return data
			.replace(reverse_re, reverse_func)
			.replace(re_notUTF8, charCode_func);
	};
});
<commit_msg>simplified the code, removed unused stuff<commit_after>var re_notUTF8 = /[\u00c0-\u00d6\u00d8-\u00f6\u00f8-\u02ff\u0370-\u037d\u037f-\u1fff\u200c\u200d\u2070-\u218f\u2c00-\u2fef\u3001-\ud7ff\uf900-\ufdcf\ufdf0-\ufffd]/g,
	charCode_func = function(c){ return "&#" + c.charCodeAt(0) + ";";};

var fetch = function(filename, inherits){
	var obj = require("./entities/" + filename + ".json");

	if(inherits) for(var name in inherits) obj[name] = inherits[name];

	var re = Object.keys(obj).sort().join("|").replace(/(\w+)\|\1;/g, "$1;?");

	// also match hex and char codes
	re += "|#[xX][0-9a-fA-F]+;?|#\\d+;?";

	return {
		func: function(name){
			if (name.charAt(1) === "#") {
				if (name.charAt(2).toLowerCase() === "x") {
					return String.fromCharCode(parseInt(name.substr(3), 16));
				}
				return String.fromCharCode(parseInt(name.substr(2), 10));
			}
			return obj[name.substr(1)];
		},
		re: new RegExp("&(?:" + re + ")", "g"),
		obj: obj
	};
};

var getReverse = function(obj){
	var reverse = Object.keys(obj).reduce(function(reverse, name){
		reverse[obj[name]] = name;
		return reverse;
	}, {});

	return {
		func: function(name){ return "&" + reverse[name]; },
		re: new RegExp("\\" + Object.keys(reverse).sort().join("|\\"), "g")
	};
};

var modes = ["XML", "HTML4", "HTML5"];

module.exports = {
	decode: function(data, level){
		if(!modes[level]) level = 0;
		return module.exports["decode" + modes[level]](data);
	},
	encode: function(data, level){
		if(!modes[level]) level = 0;
		return module.exports["encode" + modes[level]](data);
	}
};

var tmp;

modes.forEach(function(name){
	var obj = fetch(name.toLowerCase(), tmp),
		regex = obj.re,
		func = obj.func;

	tmp = obj.obj;

	module.exports["decode" + name] = function(data){
		return data
			.replace(regex, func);
	};

	var reverse = getReverse(obj.obj),
		reverse_re = reverse.re,
		reverse_func = reverse.func;

	module.exports["encode" + name] = function(data){
		return data
			.replace(reverse_re, reverse_func)
			.replace(re_notUTF8, charCode_func);
	};
});
<|endoftext|>


<commit_before>var cluster = require('cluster')

if (cluster.isMaster) {
  var async = require('async')
  var config = require('./config')()
  var fs = require('fs')
  var path = require('path')
  var sharp = require('sharp')
  var io = require('socket.io')(config.stats_port)
  var vnstat = require('vnstat-dumpdb')
  var metadata = require(config.metadata_path)
  var moment = require('moment')
  console.log('Config:')
  console.log(config)

  try {
    var stats = require(config.stats_path)
  } catch (error) {
    var stats = { count: 0 }
  }

  try {
    var images = require(config.image_store_path)
  } catch (e) {
    var images = []
  }

  try {
    var cache = require(config.cache_metadata_path)
  } catch (e) {
    var cache = {}
  }

  var publicStats = {}
  var bandWidth = 0

  io.on('connection', function (socket) {
    socket.emit('stats', publicStats)
  })

  var fetchStats = function () {
    publicStats = {
      count: stats.count,
      bandWidth: bandWidth,
      images: images.length
    }

    io.emit('stats', publicStats)
  }

  var fetchBandwidth = function () {
    vnstat.dumpdb(function (error, data) {
      if (error) {
        console.log('Couldn\'t fetch bandwidth: ' + error)
      } else {
        bandWidth = data.traffic.total.tx
      }
    })
  }

  setInterval(fetchBandwidth, 1000 * 30)
  setInterval(fetchStats, 1000)
  fetchBandwidth()
  fetchStats()

  var saveToFileAndExit = function () {
    saveToFile(function () {
      process.exit(0)
    })
  }

  var saveToFile = function (callback) {
    fs.writeFile(config.stats_path, JSON.stringify(stats), 'utf8', function (error) {
      fs.writeFile(config.cache_metadata_path, JSON.stringify(cache), 'utf8', function (error) {
        setImmediate(callback)
      })
    })
  }

  process.on('exit', saveToFileAndExit)
  process.on('SIGINT', saveToFileAndExit)
  process.on('SIGTERM', saveToFileAndExit)
  /*process.on('uncaughtException', function (error) {
    console.log('Uncaught exception: ')
    console.trace(error)
    saveToFileAndExit()
  })*/

  var loadImages = function () {
    var newImages = []

    async.each(metadata, function (image, next) {
      if (image.deleted) {
        return setImmediate(next)
      }

      var existingImage = imageExists(image)

      if (existingImage) {
        existingImage.post_url = image.post_url
        existingImage.author = image.author
        existingImage.author_url = image.author_url
        newImages.push(existingImage)

        return setImmediate(next)
      }

      var filename = path.resolve(config.folder_path, image.filename)

      console.log('Getting info for new image %s', filename)

      sharp(filename).metadata(function (error, result) {
        if (error) {
          console.trace('imageScan error: %s filename: %s', error, filename)
          return setImmediate(next)
        }

        result.filename = filename
        result.id = image.id
        result.post_url = image.post_url
        result.author = image.author
        result.author_url = image.author_url
        newImages.push(result)

        next()
      })
    }, function (error) {
      writeImagesToFile(newImages)
    })
  }

  var imageExists = function (image) {
    for (var i in images) {
      if (images[i].id === image.id) {
        return images[i]
      }
    }

    return false
  }

  var writeImagesToFile = function (newImages) {
    newImages.sort(function (a, b) {
      return a.id - b.id
    })

    images = newImages

    fs.writeFile(config.image_store_path, JSON.stringify(newImages), 'utf8', function (error) {
      findMissingCacheFiles(function () {
        startWebServers()
      })
    })
  }

  var findMissingCacheFiles = function (callback) {
    fs.readdir(config.cache_folder_path, function (error, list) {
      if (error) {
        console.log('Error reading cache directory!')
        return callback()
      }

      async.each(list, function (filename, next) {
        filename = path.resolve(config.cache_folder_path, filename)
        if (cache[filename] === undefined) {
          fs.unlink(filename, function (error) {
            setImmediate(next)
          })
        } else {
          setImmediate(next)
        }
      }, function (error) {
        callback()
      })
    })
  }

  var startWebServers = function () {
    var cpuCount = require('os').cpus().length - 1

    if (cpuCount < 2) {
      cpuCount = 2
    }

    for (var i = 0, il=cpuCount; i < il; i++) {
      startWorker()
    }

    cluster.on('exit', function (worker) {
      console.log('Worker ' + worker.id + ' died')
      startWorker()
    })

    var triggerSaveToFile = function () {
      saveToFile(function () {
        setImmediate(setTimeout, triggerSaveToFile, 1000 * 5)
      })
    }

    setTimeout(triggerSaveToFile, 1000 * 5)

    var triggerCacheCleanup = function () {
      cleanupCache(function () {
        setImmediate(setTimeout, triggerCacheCleanup, 1000 * 60 * 5)
      })
    }

    setTimeout(triggerCacheCleanup, 1000 * 60 * 5)
  }

  var cleanupCache = function (callback) {
    async.eachLimit(Object.keys(cache), 100, function (filename, next) {
      if (moment().diff(cache[filename], 'days') >= 14) {
        fs.unlink(filename, function (error) {
          delete cache[filename]
          setImmediate(next)
        })
      } else {
        setImmediate(next)
      }
    }, function (error) {
      callback()
    })
  }

  var startWorker = function () {
    var worker = cluster.fork()
    worker.on('message', handleWorkerMessage)
    console.log('Worker ' + worker.id + ' started')
  }

  var handleWorkerMessage = function (msg) {
    stats.count++
    cache[msg] = new Date()
  }

  fs.mkdir(config.cache_folder_path, function (error) {
   loadImages()
  })
} else {
  var config = require('./config')()
  require('./server')(function (callback) {
    callback.listen(process.env.PORT || config.port, 'localhost')
  })
}<commit_msg>Sync methods only on exit<commit_after>var cluster = require('cluster')

if (cluster.isMaster) {
  var async = require('async')
  var config = require('./config')()
  var fs = require('fs')
  var path = require('path')
  var sharp = require('sharp')
  var io = require('socket.io')(config.stats_port)
  var vnstat = require('vnstat-dumpdb')
  var metadata = require(config.metadata_path)
  var moment = require('moment')
  console.log('Config:')
  console.log(config)

  try {
    var stats = require(config.stats_path)
  } catch (error) {
    var stats = { count: 0 }
  }

  try {
    var images = require(config.image_store_path)
  } catch (e) {
    var images = []
  }

  try {
    var cache = require(config.cache_metadata_path)
  } catch (e) {
    var cache = {}
  }

  var publicStats = {}
  var bandWidth = 0

  io.on('connection', function (socket) {
    socket.emit('stats', publicStats)
  })

  var fetchStats = function () {
    publicStats = {
      count: stats.count,
      bandWidth: bandWidth,
      images: images.length
    }

    io.emit('stats', publicStats)
  }

  var fetchBandwidth = function () {
    vnstat.dumpdb(function (error, data) {
      if (error) {
        console.log('Couldn\'t fetch bandwidth: ' + error)
      } else {
        bandWidth = data.traffic.total.tx
      }
    })
  }

  setInterval(fetchBandwidth, 1000 * 30)
  setInterval(fetchStats, 1000)
  fetchBandwidth()
  fetchStats()

  var exited = false

  var saveToFileAndExit = function () {
    if (exited) {
      return
    } else {
      exited = true
    }

    fs.writeFileSync(config.stats_path, JSON.stringify(stats), 'utf8')
    fs.writeFileSync(config.cache_metadata_path, JSON.stringify(cache), 'utf8')
    process.exit(0)
  }

  var saveToFile = function (callback) {
    fs.writeFile(config.stats_path, JSON.stringify(stats), 'utf8', function (error) {
      fs.writeFile(config.cache_metadata_path, JSON.stringify(cache), 'utf8', function (error) {
        callback()
      })
    })
  }

  process.on('exit', saveToFileAndExit)
  process.on('SIGINT', saveToFileAndExit)
  process.on('SIGTERM', saveToFileAndExit)
  process.on('uncaughtException', function (error) {
    console.log('Uncaught exception: ')
    console.trace(error)
    saveToFileAndExit()
  })

  var loadImages = function () {
    var newImages = []

    async.each(metadata, function (image, next) {
      if (image.deleted) {
        return setImmediate(next)
      }

      var existingImage = imageExists(image)

      if (existingImage) {
        existingImage.post_url = image.post_url
        existingImage.author = image.author
        existingImage.author_url = image.author_url
        newImages.push(existingImage)

        return setImmediate(next)
      }

      var filename = path.resolve(config.folder_path, image.filename)

      console.log('Getting info for new image %s', filename)

      sharp(filename).metadata(function (error, result) {
        if (error) {
          console.trace('imageScan error: %s filename: %s', error, filename)
          return setImmediate(next)
        }

        result.filename = filename
        result.id = image.id
        result.post_url = image.post_url
        result.author = image.author
        result.author_url = image.author_url
        newImages.push(result)

        next()
      })
    }, function (error) {
      writeImagesToFile(newImages)
    })
  }

  var imageExists = function (image) {
    for (var i in images) {
      if (images[i].id === image.id) {
        return images[i]
      }
    }

    return false
  }

  var writeImagesToFile = function (newImages) {
    newImages.sort(function (a, b) {
      return a.id - b.id
    })

    images = newImages

    fs.writeFile(config.image_store_path, JSON.stringify(newImages), 'utf8', function (error) {
      findMissingCacheFiles(function () {
        startWebServers()
      })
    })
  }

  var findMissingCacheFiles = function (callback) {
    fs.readdir(config.cache_folder_path, function (error, list) {
      if (error) {
        console.log('Error reading cache directory!')
        return callback()
      }

      async.each(list, function (filename, next) {
        filename = path.resolve(config.cache_folder_path, filename)
        if (cache[filename] === undefined) {
          fs.unlink(filename, function (error) {
            setImmediate(next)
          })
        } else {
          setImmediate(next)
        }
      }, function (error) {
        callback()
      })
    })
  }

  var startWebServers = function () {
    var cpuCount = require('os').cpus().length - 1

    if (cpuCount < 2) {
      cpuCount = 2
    }

    for (var i = 0, il=cpuCount; i < il; i++) {
      startWorker()
    }

    cluster.on('exit', function (worker) {
      console.log('Worker ' + worker.id + ' died')
      startWorker()
    })

    var triggerSaveToFile = function () {
      saveToFile(function () {
        setImmediate(setTimeout, triggerSaveToFile, 1000 * 5)
      })
    }

    setTimeout(triggerSaveToFile, 1000 * 5)

    var triggerCacheCleanup = function () {
      cleanupCache(function () {
        setImmediate(setTimeout, triggerCacheCleanup, 1000 * 60 * 5)
      })
    }

    setTimeout(triggerCacheCleanup, 1000 * 60 * 5)
  }

  var cleanupCache = function (callback) {
    async.eachLimit(Object.keys(cache), 100, function (filename, next) {
      if (moment().diff(cache[filename], 'days') >= 14) {
        fs.unlink(filename, function (error) {
          delete cache[filename]
          setImmediate(next)
        })
      } else {
        setImmediate(next)
      }
    }, function (error) {
      callback()
    })
  }

  var startWorker = function () {
    var worker = cluster.fork()
    worker.on('message', handleWorkerMessage)
    console.log('Worker ' + worker.id + ' started')
  }

  var handleWorkerMessage = function (msg) {
    stats.count++
    cache[msg] = new Date()
  }

  fs.mkdir(config.cache_folder_path, function (error) {
   loadImages()
  })
} else {
  var config = require('./config')()
  require('./server')(function (callback) {
    callback.listen(process.env.PORT || config.port, 'localhost')
  })
}<|endoftext|>


<commit_before>/*
 * Copyright (C) 2016 Glyptodon LLC
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

/**
 * Overrides $templateRequest such that HTML patches defined within Guacamole
 * extensions are automatically applied to template contents.
 */
angular.module('index').config(['$provide', function($provide) {
    $provide.decorator('$templateRequest', ['$delegate', '$injector',
            function decorateTemplateRequest($delegate, $injector) {

        // Required services
        var $q = $injector.get('$q');

        /**
         * Array of the raw HTML of all patches which should be applied to the
         * HTML of retrieved templates.
         *
         * @type String[]
         */
        var patches = [
            '<meta name="before" content="a">
HELLO BEFORE
',
            '<meta name="after" content="a">
HELLO AFTER
',
            '<meta name="replace" content="div.protocol">
:-)
'
        ];

        /**
         * Represents a single HTML patching operation which will be applied
         * to the raw HTML of a template. The name of the patching operation
         * MUST be one of the valid names defined within
         * PatchOperation.Operations.
         *
         * @constructor
         * @param {String} name
         *     The name of the patching operation that will be applied. Valid
         *     names are defined within PatchOperation.Operations.
         *
         * @param {String} selector
         *     The CSS selector which determines which elements within a
         *     template will be affected by the patch operation.
         */
        var PatchOperation = function PatchOperation(name, selector) {

            /**
             * Applies this patch operation to the template defined by the
             * given root element, which must be a single element wrapped by
             * JQuery.
             *
             * @param {Element[]} root
             *     The JQuery-wrapped root element of the template to which
             *     this patch operation should be applied.
             *
             * @param {Element[]} elements
             *     The elements which should be applied by the patch
             *     operation. For example, if the patch operation is inserting
             *     elements, these are the elements that will be inserted.
             */
            this.apply = function apply(root, elements) {
                PatchOperation.Operations[name](root, selector, elements);
            };

        };

        /**
         * Mapping of all valid patch operation names to their corresponding
         * implementations. Each implementation accepts the same three
         * parameters: the root element of the template being patched, the CSS
         * selector determining which elements within the template are patched,
         * and an array of elements which make up the body of the patch.
         *
         * @type Object.<String, Function>
         */
        PatchOperation.Operations = {

            /**
             * Inserts the given elements before the elements matched by the
             * provided CSS selector.
             *
             * @param {Element[]} root
             *     The JQuery-wrapped root element of the template being
             *     patched.
             *
             * @param {String} selector
             *     The CSS selector which determines where this patch operation
             *     should be applied within the template defined by root.
             *
             * @param {Element[]} elements
             *     The contents of the patch which should be applied to the
             *     template defined by root at the locations selected by the
             *     given CSS selector.
             */
            'before' : function before(root, selector, elements) {
                root.find(selector).before(elements);
            },

            /**
             * Inserts the given elements after the elements matched by the
             * provided CSS selector.
             *
             * @param {Element[]} root
             *     The JQuery-wrapped root element of the template being
             *     patched.
             *
             * @param {String} selector
             *     The CSS selector which determines where this patch operation
             *     should be applied within the template defined by root.
             *
             * @param {Element[]} elements
             *     The contents of the patch which should be applied to the
             *     template defined by root at the locations selected by the
             *     given CSS selector.
             */
            'after' : function after(root, selector, elements) {
                root.find(selector).after(elements);
            },

            /**
             * Replaces the elements matched by the provided CSS selector with
             * the given elements.
             *
             * @param {Element[]} root
             *     The JQuery-wrapped root element of the template being
             *     patched.
             *
             * @param {String} selector
             *     The CSS selector which determines where this patch operation
             *     should be applied within the template defined by root.
             *
             * @param {Element[]} elements
             *     The contents of the patch which should be applied to the
             *     template defined by root at the locations selected by the
             *     given CSS selector.
             */
            'replace' : function replace(root, selector, elements) {
                root.find(selector).replaceWith(elements);
            },

            /**
             * Inserts the given elements within the elements matched by the
             * provided CSS selector, before any existing children.
             *
             * @param {Element[]} root
             *     The JQuery-wrapped root element of the template being
             *     patched.
             *
             * @param {String} selector
             *     The CSS selector which determines where this patch operation
             *     should be applied within the template defined by root.
             *
             * @param {Element[]} elements
             *     The contents of the patch which should be applied to the
             *     template defined by root at the locations selected by the
             *     given CSS selector.
             */
            'before-children' : function beforeChildren(root, selector, elements) {
                root.find(selector).prepend(elements);
            },

            /**
             * Inserts the given elements within the elements matched by the
             * provided CSS selector, after any existing children.
             *
             * @param {Element[]} root
             *     The JQuery-wrapped root element of the template being
             *     patched.
             *
             * @param {String} selector
             *     The CSS selector which determines where this patch operation
             *     should be applied within the template defined by root.
             *
             * @param {Element[]} elements
             *     The contents of the patch which should be applied to the
             *     template defined by root at the locations selected by the
             *     given CSS selector.
             */
            'after-children' : function afterChildren(root, selector, elements) {
                root.find(selector).append(elements);
            },

            /**
             * Inserts the given elements within the elements matched by the
             * provided CSS selector, replacing any existing children.
             *
             * @param {Element[]} root
             *     The JQuery-wrapped root element of the template being
             *     patched.
             *
             * @param {String} selector
             *     The CSS selector which determines where this patch operation
             *     should be applied within the template defined by root.
             *
             * @param {Element[]} elements
             *     The contents of the patch which should be applied to the
             *     template defined by root at the locations selected by the
             *     given CSS selector.
             */
            'replace-children' : function replaceChildren(root, selector, elements) {
                root.find(selector).empty().append(elements);
            }

        };

        /**
         * Invokes $templateRequest() with all arguments exactly as provided,
         * applying all HTML patches from any installed Guacamole extensions
         * to the HTML of the requested template.
         *
         * @returns {Promise.<String>}
         *     A Promise which resolves with the patched HTML contents of the
         *     requested template if retrieval of the template is successful.
         */
        var decoratedTemplateRequest = function decoratedTemplateRequest() {

            var deferred = $q.defer();

            // Resolve promise with patched template HTML
            $delegate.apply(this, arguments).then(function patchTemplate(data) {

                // Parse HTML into DOM tree
                var root = $('

').html(data);

                // Apply all defined patches
                angular.forEach(patches, function applyPatch(patch) {

                    var elements = $(patch);

                    // Filter out and parse all applicable meta tags
                    var operations = [];
                    elements = elements.filter(function filterMetaTags(index, element) {

                        // Leave non-meta tags untouched
                        if (element.tagName !== 'META')
                            return true;

                        // Only meta tags having a valid "name" attribute need
                        // to be filtered
                        var name = element.getAttribute('name');
                        if (!name || !(name in PatchOperation.Operations))
                            return true;

                        // The "content" attribute must be present for any
                        // valid "name" meta tag
                        var content = element.getAttribute('content');
                        if (!content)
                            return true;

                        // Filter out and parse meta tag
                        operations.push(new PatchOperation(name, content));
                        return false;

                    });

                    // Apply each operation implied by the meta tags
                    angular.forEach(operations, function applyOperation(operation) {
                        operation.apply(root, elements);
                    });

                });

                // Transform back into HTML
                deferred.resolve.call(this, root.html());

            }, deferred.reject);

            return deferred.promise;

        };

        return decoratedTemplateRequest;

    }]);
}]);<commit_msg>GUAC-1378: Cache previous calls to $templateRequest() to avoid duplicating patch processing work.<commit_after>/*
 * Copyright (C) 2016 Glyptodon LLC
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

/**
 * Overrides $templateRequest such that HTML patches defined within Guacamole
 * extensions are automatically applied to template contents.
 */
angular.module('index').config(['$provide', function($provide) {
    $provide.decorator('$templateRequest', ['$delegate', '$injector',
            function decorateTemplateRequest($delegate, $injector) {

        // Required services
        var $q = $injector.get('$q');

        /**
         * A map of previously-returned promises from past calls to
         * $templateRequest(). Future calls to $templateRequest() will return
         * new promises chained to the first promise returned for a given URL,
         * rather than redo patch processing for every request.
         *
         * @type Object.<String, Promise.<String>>
         */
        var promiseCache = {};

        /**
         * Array of the raw HTML of all patches which should be applied to the
         * HTML of retrieved templates.
         *
         * @type String[]
         */
        var patches = [
            '<meta name="before" content="a">
HELLO BEFORE
',
            '<meta name="after" content="a">
HELLO AFTER
',
            '<meta name="replace" content="div.protocol">
:-)
'
        ];

        /**
         * Represents a single HTML patching operation which will be applied
         * to the raw HTML of a template. The name of the patching operation
         * MUST be one of the valid names defined within
         * PatchOperation.Operations.
         *
         * @constructor
         * @param {String} name
         *     The name of the patching operation that will be applied. Valid
         *     names are defined within PatchOperation.Operations.
         *
         * @param {String} selector
         *     The CSS selector which determines which elements within a
         *     template will be affected by the patch operation.
         */
        var PatchOperation = function PatchOperation(name, selector) {

            /**
             * Applies this patch operation to the template defined by the
             * given root element, which must be a single element wrapped by
             * JQuery.
             *
             * @param {Element[]} root
             *     The JQuery-wrapped root element of the template to which
             *     this patch operation should be applied.
             *
             * @param {Element[]} elements
             *     The elements which should be applied by the patch
             *     operation. For example, if the patch operation is inserting
             *     elements, these are the elements that will be inserted.
             */
            this.apply = function apply(root, elements) {
                PatchOperation.Operations[name](root, selector, elements);
            };

        };

        /**
         * Mapping of all valid patch operation names to their corresponding
         * implementations. Each implementation accepts the same three
         * parameters: the root element of the template being patched, the CSS
         * selector determining which elements within the template are patched,
         * and an array of elements which make up the body of the patch.
         *
         * @type Object.<String, Function>
         */
        PatchOperation.Operations = {

            /**
             * Inserts the given elements before the elements matched by the
             * provided CSS selector.
             *
             * @param {Element[]} root
             *     The JQuery-wrapped root element of the template being
             *     patched.
             *
             * @param {String} selector
             *     The CSS selector which determines where this patch operation
             *     should be applied within the template defined by root.
             *
             * @param {Element[]} elements
             *     The contents of the patch which should be applied to the
             *     template defined by root at the locations selected by the
             *     given CSS selector.
             */
            'before' : function before(root, selector, elements) {
                root.find(selector).before(elements);
            },

            /**
             * Inserts the given elements after the elements matched by the
             * provided CSS selector.
             *
             * @param {Element[]} root
             *     The JQuery-wrapped root element of the template being
             *     patched.
             *
             * @param {String} selector
             *     The CSS selector which determines where this patch operation
             *     should be applied within the template defined by root.
             *
             * @param {Element[]} elements
             *     The contents of the patch which should be applied to the
             *     template defined by root at the locations selected by the
             *     given CSS selector.
             */
            'after' : function after(root, selector, elements) {
                root.find(selector).after(elements);
            },

            /**
             * Replaces the elements matched by the provided CSS selector with
             * the given elements.
             *
             * @param {Element[]} root
             *     The JQuery-wrapped root element of the template being
             *     patched.
             *
             * @param {String} selector
             *     The CSS selector which determines where this patch operation
             *     should be applied within the template defined by root.
             *
             * @param {Element[]} elements
             *     The contents of the patch which should be applied to the
             *     template defined by root at the locations selected by the
             *     given CSS selector.
             */
            'replace' : function replace(root, selector, elements) {
                root.find(selector).replaceWith(elements);
            },

            /**
             * Inserts the given elements within the elements matched by the
             * provided CSS selector, before any existing children.
             *
             * @param {Element[]} root
             *     The JQuery-wrapped root element of the template being
             *     patched.
             *
             * @param {String} selector
             *     The CSS selector which determines where this patch operation
             *     should be applied within the template defined by root.
             *
             * @param {Element[]} elements
             *     The contents of the patch which should be applied to the
             *     template defined by root at the locations selected by the
             *     given CSS selector.
             */
            'before-children' : function beforeChildren(root, selector, elements) {
                root.find(selector).prepend(elements);
            },

            /**
             * Inserts the given elements within the elements matched by the
             * provided CSS selector, after any existing children.
             *
             * @param {Element[]} root
             *     The JQuery-wrapped root element of the template being
             *     patched.
             *
             * @param {String} selector
             *     The CSS selector which determines where this patch operation
             *     should be applied within the template defined by root.
             *
             * @param {Element[]} elements
             *     The contents of the patch which should be applied to the
             *     template defined by root at the locations selected by the
             *     given CSS selector.
             */
            'after-children' : function afterChildren(root, selector, elements) {
                root.find(selector).append(elements);
            },

            /**
             * Inserts the given elements within the elements matched by the
             * provided CSS selector, replacing any existing children.
             *
             * @param {Element[]} root
             *     The JQuery-wrapped root element of the template being
             *     patched.
             *
             * @param {String} selector
             *     The CSS selector which determines where this patch operation
             *     should be applied within the template defined by root.
             *
             * @param {Element[]} elements
             *     The contents of the patch which should be applied to the
             *     template defined by root at the locations selected by the
             *     given CSS selector.
             */
            'replace-children' : function replaceChildren(root, selector, elements) {
                root.find(selector).empty().append(elements);
            }

        };

        /**
         * Invokes $templateRequest() with all arguments exactly as provided,
         * applying all HTML patches from any installed Guacamole extensions
         * to the HTML of the requested template.
         *
         * @param {String} url
         *     The URL of the template being requested.
         *
         * @returns {Promise.<String>}
         *     A Promise which resolves with the patched HTML contents of the
         *     requested template if retrieval of the template is successful.
         */
        var decoratedTemplateRequest = function decoratedTemplateRequest(url) {

            var deferred = $q.defer();

            // Chain to cached promise if it already exists
            var cachedPromise = promiseCache[url];
            if (cachedPromise) {
                cachedPromise.then(deferred.resolve, deferred.reject);
                return deferred.promise;
            }

            // Resolve promise with patched template HTML
            $delegate.apply(this, arguments).then(function patchTemplate(data) {

                // Parse HTML into DOM tree
                var root = $('

').html(data);

                // Apply all defined patches
                angular.forEach(patches, function applyPatch(patch) {

                    var elements = $(patch);

                    // Filter out and parse all applicable meta tags
                    var operations = [];
                    elements = elements.filter(function filterMetaTags(index, element) {

                        // Leave non-meta tags untouched
                        if (element.tagName !== 'META')
                            return true;

                        // Only meta tags having a valid "name" attribute need
                        // to be filtered
                        var name = element.getAttribute('name');
                        if (!name || !(name in PatchOperation.Operations))
                            return true;

                        // The "content" attribute must be present for any
                        // valid "name" meta tag
                        var content = element.getAttribute('content');
                        if (!content)
                            return true;

                        // Filter out and parse meta tag
                        operations.push(new PatchOperation(name, content));
                        return false;

                    });

                    // Apply each operation implied by the meta tags
                    angular.forEach(operations, function applyOperation(operation) {
                        operation.apply(root, elements);
                    });

                });

                // Transform back into HTML
                deferred.resolve.call(this, root.html());

            }, deferred.reject);

            // Cache this promise for future results
            promiseCache[url] = deferred.promise;
            return deferred.promise;

        };

        return decoratedTemplateRequest;

    }]);
}]);<|endoftext|>


<commit_before>/*global define*/
define([
        '../Core/BoundingSphere',
        '../Core/Cartesian3',
        '../Core/DeveloperError',
        './TerrainProvider',
        './TerrainState',
        '../ThirdParty/when'
    ], function(
        BoundingSphere,
        Cartesian3,
        DeveloperError,
        TerrainProvider,
        TerrainState,
        when) {
   "use strict";

   var TileTerrain = function TileTerrain(upsampleDetails) {
       /**
        * The current state of the terrain in the terrain processing pipeline.
        * @type TerrainState
        */
       this.state = TerrainState.UNLOADED;
       this.data = undefined;
       this.mesh = undefined;
       this.vertexArray = undefined;
       this.upsampleDetails = upsampleDetails;
   };

   TileTerrain.prototype.freeResources = function() {
       this.state = TerrainState.UNLOADED;
       this.data = undefined;
       this.mesh = undefined;

       if (typeof this.vertexArray !== 'undefined') {
           var indexBuffer = this.vertexArray.getIndexBuffer();

           this.vertexArray.destroy();
           this.vertexArray = undefined;

           if (!indexBuffer.isDestroyed() && typeof indexBuffer.referenceCount !== 'undefined') {
               --indexBuffer.referenceCount;
               if (indexBuffer.referenceCount === 0) {
                   indexBuffer.destroy();
               }
           }
       }
   };

   TileTerrain.prototype.publishToTile = function(tile) {
       var mesh = this.mesh;
       Cartesian3.clone(mesh.center, tile.center);
       tile.minHeight = mesh.minHeight;
       tile.maxHeight = mesh.maxHeight;
       BoundingSphere.clone(mesh.boundingSphere3D, tile.boundingSphere3D);

       if (typeof mesh.occludeePointInScaledSpace !== 'undefined') {
           Cartesian3.clone(mesh.occludeePointInScaledSpace, tile.occludeePointInScaledSpace);
       } else {
           tile.occludeePointInScaledSpace = undefined;
       }

       // Free the existing vertex array, if any.
       tile.freeVertexArray();

       // Transfer ownership of the vertex array to the tile itself.
       tile.vertexArray = this.vertexArray;
       this.vertexArray = undefined;
   };

   TileTerrain.prototype.processLoadStateMachine = function(context, terrainProvider, x, y, level) {
       if (this.state === TerrainState.UNLOADED) {
           // Request the terrain from the terrain provider.
           this.data = terrainProvider.requestTileGeometry(x, y, level);

           // If the request method returns undefined (instead of a promise), the request
           // has been deferred.
           if (typeof this.data !== 'undefined') {
               this.state = TerrainState.RECEIVING;

               var that = this;
               when(this.data, function(terrainData) {
                   that.data = terrainData;
                   that.state = TerrainState.RECEIVED;
               }, function() {
                   // TODO: add error reporting and retry logic similar to imagery providers.
                   that.state = TerrainState.FAILED;
               });
           }
       }

       if (this.state === TerrainState.RECEIVED) {
           transform(this, context, terrainProvider, x, y, level);
       }

       if (this.state === TerrainState.TRANSFORMED) {
           createResources(this, context, terrainProvider, x, y, level);
       }
   };

   TileTerrain.prototype.processUpsampleStateMachine = function(context, terrainProvider, x, y, level) {
       if (this.state === TerrainState.UNLOADED) {
           var upsampleDetails = this.upsampleDetails;
           if (typeof upsampleDetails === 'undefined') {
               throw new DeveloperError('TileTerrain cannot upsample unless provided upsampleDetails.');
           }

           var sourceData = upsampleDetails.data;
           var sourceX = upsampleDetails.x;
           var sourceY = upsampleDetails.y;
           var sourceLevel = upsampleDetails.level;

           this.data = sourceData.upsample(terrainProvider.tilingScheme, sourceX, sourceY, sourceLevel, x, y, level);
           if (typeof this.data === 'undefined') {
               // The upsample request has been deferred - try again later.
               return;
           }

           this.state = TerrainState.RECEIVING;

           var that = this;
           when(this.data, function(terrainData) {
               that.data = terrainData;
               that.state = TerrainState.RECEIVED;
           }, function() {
               that.state = TerrainState.FAILED;
           });
       }

       if (this.state === TerrainState.RECEIVED) {
           transform(this, context, terrainProvider, x, y, level);
       }

       if (this.state === TerrainState.TRANSFORMED) {
           createResources(this, context, terrainProvider, x, y, level);
       }
   };

   function transform(tileTerrain, context, terrainProvider, x, y, level) {
       var tilingScheme = terrainProvider.tilingScheme;
       var ellipsoid = tilingScheme.getEllipsoid();

       var terrainData = tileTerrain.data;
       var meshPromise = terrainData.createMesh(ellipsoid, tilingScheme, x, y, level);

       if (typeof meshPromise === 'undefined') {
           // Postponed.
           return;
       }

       tileTerrain.state = TerrainState.TRANSFORMING;

       when(meshPromise, function(mesh) {
           tileTerrain.mesh = mesh;
           tileTerrain.state = TerrainState.TRANSFORMED;
       }, function() {
           tileTerrain.state = TerrainState.FAILED;
       });
   }

   function createResources(tileTerrain, context, terrainProvider, x, y, level) {
       TerrainProvider.createTileEllipsoidGeometryFromBuffers(context, tileTerrain.mesh, tileTerrain, true);
       tileTerrain.state = TerrainState.READY;
   }

   return TileTerrain;
});
<commit_msg>Refactor processLoadStateMachine in preparation for error handling.<commit_after>/*global define*/
define([
        '../Core/BoundingSphere',
        '../Core/Cartesian3',
        '../Core/DeveloperError',
        './TerrainProvider',
        './TerrainState',
        '../ThirdParty/when'
    ], function(
        BoundingSphere,
        Cartesian3,
        DeveloperError,
        TerrainProvider,
        TerrainState,
        when) {
   "use strict";

   var TileTerrain = function TileTerrain(upsampleDetails) {
       /**
        * The current state of the terrain in the terrain processing pipeline.
        * @type TerrainState
        */
       this.state = TerrainState.UNLOADED;
       this.data = undefined;
       this.mesh = undefined;
       this.vertexArray = undefined;
       this.upsampleDetails = upsampleDetails;
   };

   TileTerrain.prototype.freeResources = function() {
       this.state = TerrainState.UNLOADED;
       this.data = undefined;
       this.mesh = undefined;

       if (typeof this.vertexArray !== 'undefined') {
           var indexBuffer = this.vertexArray.getIndexBuffer();

           this.vertexArray.destroy();
           this.vertexArray = undefined;

           if (!indexBuffer.isDestroyed() && typeof indexBuffer.referenceCount !== 'undefined') {
               --indexBuffer.referenceCount;
               if (indexBuffer.referenceCount === 0) {
                   indexBuffer.destroy();
               }
           }
       }
   };

   TileTerrain.prototype.publishToTile = function(tile) {
       var mesh = this.mesh;
       Cartesian3.clone(mesh.center, tile.center);
       tile.minHeight = mesh.minHeight;
       tile.maxHeight = mesh.maxHeight;
       BoundingSphere.clone(mesh.boundingSphere3D, tile.boundingSphere3D);

       if (typeof mesh.occludeePointInScaledSpace !== 'undefined') {
           Cartesian3.clone(mesh.occludeePointInScaledSpace, tile.occludeePointInScaledSpace);
       } else {
           tile.occludeePointInScaledSpace = undefined;
       }

       // Free the existing vertex array, if any.
       tile.freeVertexArray();

       // Transfer ownership of the vertex array to the tile itself.
       tile.vertexArray = this.vertexArray;
       this.vertexArray = undefined;
   };

   TileTerrain.prototype.processLoadStateMachine = function(context, terrainProvider, x, y, level) {
       if (this.state === TerrainState.UNLOADED) {
           requestTileGeometry(this, terrainProvider, x, y, level);
       }

       if (this.state === TerrainState.RECEIVED) {
           transform(this, context, terrainProvider, x, y, level);
       }

       if (this.state === TerrainState.TRANSFORMED) {
           createResources(this, context, terrainProvider, x, y, level);
       }
   };

   function requestTileGeometry(tileTerrain, terrainProvider, x, y, level) {
       function success(terrainData) {
           tileTerrain.data = terrainData;
           tileTerrain.state = TerrainState.RECEIVED;
       }

       function failure() {
           // TODO: add error reporting and retry logic similar to imagery providers.
           tileTerrain.state = TerrainState.FAILED;
       }

       // Request the terrain from the terrain provider.
       tileTerrain.data = terrainProvider.requestTileGeometry(x, y, level);

       // If the request method returns undefined (instead of a promise), the request
       // has been deferred.
       if (typeof tileTerrain.data !== 'undefined') {
           tileTerrain.state = TerrainState.RECEIVING;

           when(tileTerrain.data, success, failure);
       } else {
           // Deferred - try again later.
           tileTerrain.state = TerrainState.UNLOADED;
       }
   }

   TileTerrain.prototype.processUpsampleStateMachine = function(context, terrainProvider, x, y, level) {
       if (this.state === TerrainState.UNLOADED) {
           var upsampleDetails = this.upsampleDetails;
           if (typeof upsampleDetails === 'undefined') {
               throw new DeveloperError('TileTerrain cannot upsample unless provided upsampleDetails.');
           }

           var sourceData = upsampleDetails.data;
           var sourceX = upsampleDetails.x;
           var sourceY = upsampleDetails.y;
           var sourceLevel = upsampleDetails.level;

           this.data = sourceData.upsample(terrainProvider.tilingScheme, sourceX, sourceY, sourceLevel, x, y, level);
           if (typeof this.data === 'undefined') {
               // The upsample request has been deferred - try again later.
               return;
           }

           this.state = TerrainState.RECEIVING;

           var that = this;
           when(this.data, function(terrainData) {
               that.data = terrainData;
               that.state = TerrainState.RECEIVED;
           }, function() {
               that.state = TerrainState.FAILED;
           });
       }

       if (this.state === TerrainState.RECEIVED) {
           transform(this, context, terrainProvider, x, y, level);
       }

       if (this.state === TerrainState.TRANSFORMED) {
           createResources(this, context, terrainProvider, x, y, level);
       }
   };

   function transform(tileTerrain, context, terrainProvider, x, y, level) {
       var tilingScheme = terrainProvider.tilingScheme;
       var ellipsoid = tilingScheme.getEllipsoid();

       var terrainData = tileTerrain.data;
       var meshPromise = terrainData.createMesh(ellipsoid, tilingScheme, x, y, level);

       if (typeof meshPromise === 'undefined') {
           // Postponed.
           return;
       }

       tileTerrain.state = TerrainState.TRANSFORMING;

       when(meshPromise, function(mesh) {
           tileTerrain.mesh = mesh;
           tileTerrain.state = TerrainState.TRANSFORMED;
       }, function() {
           tileTerrain.state = TerrainState.FAILED;
       });
   }

   function createResources(tileTerrain, context, terrainProvider, x, y, level) {
       TerrainProvider.createTileEllipsoidGeometryFromBuffers(context, tileTerrain.mesh, tileTerrain, true);
       tileTerrain.state = TerrainState.READY;
   }

   return TileTerrain;
});
<|endoftext|>