<commit_before>goog.provide('utilities.Topping');

var toppingData = {
  //PEPPERONI//
  pepperoni: {
    image: 'assets/toppings_pepperoni.png',
    chaining: function(levelData, wedge, row, column,resultsObject){
      //nothing happens here!
    },
    powerUp: function(levelData, wedge, row, column, strength){
      //nuttin here either
    }
  },

  //MUSHROOM//
  mushroom: {
    image: 'assets/toppings_mushroom.png',
    chaining: function(levelData, wedge, row, column, resultsObject){
        //turn into a pepperoni and ATTACK!!
        levelData.get(wedge, row, column).toppingType = 'pepperoni';
        levelData.get(wedge, row, column).sprite.setFill(toppingData.pepperoni.image);
        resultsObject.mushroom++;
        attackNeighbors(levelData, wedge, row, column, resultsObject);
    },

    //STACKING power-up
    powerUp: function(levelData, wedge, row, column, strength){
      if(strength >= 4){

        if(strength <6) {
          levelData.get(wedge, row, column).toppingType = 'doublePepperoni';
          levelData.get(wedge, row, column).sprite.setFill(toppingData.doublePepperoni.image);
        }
        else if (strength >=6) {
          levelData.get(wedge, row, column).toppingType = 'triplePepperoni';
          levelData.get(wedge, row, column).sprite.setFill(toppingData.triplePepperoni.image);
        }
        console.log(levelData.get(wedge, row, column).toppingType);
        return true;
      }

      levelData.get(wedge,row,column).toppingType.stack = 1;
      return false;
    }
  },

  //OLIVES//
  olive: {
    image: 'assets/toppings_olive.png',
    chaining: function(levelData, wedge, row, column, resultsObject){
      var neighborTypes = checkNeighbors(levelData,wedge,row,column);
      var pprCount = 0;

      for (var i = neighborTypes.length - 1; i >= 0; i--) {
        if(neighborTypes[i] == 'pepperoni')
          pprCount++;
        else if(neighborTypes[i] == 'doublePepperoni' || neighborTypes[i] == 'triplePepperoni'){
          pprCount +=2; //don't need 3 anywho
        }
      }

      if(pprCount >= 2){
        //turn into a pepperoni and ATTACK!!
        levelData.get(wedge, row, column).toppingType = 'pepperoni';
        levelData.get(wedge, row, column).sprite.setFill(toppingData.pepperoni.image);
        resultsObject.olive++;
        return attackNeighbors(levelData, wedge, row, column, resultsObject);
      }
    },

    //AOE power-up
    powerUp: function(levelData, wedge, row, column, strength){
      if(strength >= 2){
        var neighborList = levelData.neighbors(wedge,row,column);
        console.log('AOE ENABLED');

        for (var i = neighborList.length - 1; i >= 0; i--) {
          var neighborData = levelData.get(neighborList[i].wedge, neighborList[i].row, neighborList[i].column);

          if(!neighborData.isOccupied){
            neighborData.toppingType = 'littlePepperoni';
            neighborData.sprite.setFill(utilities.Topping('pepperoni').image)
            neighborData.isOccupied = true;
          }
        }
        return true;
      }
      return false;
    }
  },

  //ANCHOVY//
  anchovy: {
    image: 'assets/toppings_anchovy.png',
    chaining: function(levelData, wedge, row, column, resultsObject){
      var neighborTypes = checkNeighbors(levelData,wedge,row,column);
      var pprCount = 0;

      for (var i = neighborTypes.length - 1; i >= 0; i--) {
        if(neighborTypes[i] == 'pepperoni')
          pprCount ++;
        else if(neighborTypes[i] == 'doublePepperoni')
          pprCount +=2; //don't need 3 anywho
        else if(neighborTypes[i] == 'triplePepperoni')
          pprCount +=3;
      }

      if(pprCount >= 3){
        //turn into a pepperoni and ATTACK!!
        levelData.get(wedge, row, column).toppingType = 'pepperoni';
        levelData.get(wedge, row, column).sprite.setFill(toppingData.pepperoni.image);
        resultsObject.anchovy++;
        return attackNeighbors(levelData, wedge, row, column, resultsObject);
      }
    },
    powerUp: function(levelData, wedge, row, column, strength){
      if(strength >= 1){
        return true;
      }
      return false;
    }
  },

  // bacon: 4,
  // buffaloChicken: 5,

  doublePepperoni: {
    image: 'assets/toppings_pepperoni_double.png',
    chaining: function(levelData, wedge, row, column,resultsObject){
      //nothing happens here!
    },
    powerUp: function(levelData, wedge, row, column, strength){
      //nuttin here either
    }
  },

  triplePepperoni: {
    image: 'assets/toppings_pepperoni_triple.png',
    chaining: function(levelData, wedge, row, column,resultsObject){
      //nothing happens here!
    },
    powerUp: function(levelData, wedge, row, column, strength){
      //nuttin here either
    }
  },

  littlePepperoni: {
    image: 'assets/toppings_pepperoni.png',
    chaining: function(levelData, wedge, row, column,resultsObject){
      //turn into a pepperoni and ATTACK!!
      levelData.get(wedge, row, column).toppingType = 'pepperoni';
      levelData.get(wedge, row, column).sprite.setFill(toppingData.pepperoni.image);
      resultsObject.mushroom++;
      attackNeighbors(levelData, wedge, row, column, resultsObject);
    },
    powerUp: function(levelData, wedge, row, column, strength){
      //nuttin here either
    }
  }

};

utilities.Topping = function(type)
{
    return toppingData[type];
};

//dat local neighbor check
function attackNeighbors(levelData, wedge,row,column, resultsObject)
{
  //TALLYING
  levelData.get(wedge,row,column).toppingType;

  var neighborList = levelData.neighbors(wedge,row,column);

  for (var i = neighborList.length - 1; i >= 0; i--) {
    var target = levelData.get(neighborList[i].wedge, neighborList[i].row, neighborList[i].column);

    if(target.isOccupied && target.toppingType != 'pepperoni')
      toppingData[target.toppingType].chaining(levelData,neighborList[i].wedge, neighborList[i].row, neighborList[i].column, resultsObject);
  }
}

function checkNeighbors(levelData, wedge,row,column)
{
  var neighborList = levelData.neighbors(wedge,row,column);
  var neighborTypes = [];

  for (var i = neighborList.length - 1; i >= 0; i--) {
    var target = levelData.get(neighborList[i].wedge, neighborList[i].row, neighborList[i].column);

    if(target.isOccupied)
      neighborTypes.push(target.toppingType);
  }

  return neighborTypes;
}

goog.exportSymbol('utilities.Topping',utilities.Topping);

/*
var attackNeighbors = function(wedge,row,column)
            {
                var neighborList = levelData.neighbors(wedge,row,column);

                for(i=0; i<neighborList.length; i++){
                  console.log(neighborList);
                  var target= levelData.get(neighborList[i].wedge,, neighborList[i].row, neighborList[i].column);

                  if(!target.isOccupied)
                    return;

                  if(target.toppingType == 'mushroom'){
                    target.toppingType = 'pepperoni';
                    target.sprite.setFill(utilities.Topping('pepperoni').image);
                    attackNeighbors(neighborList[i].wedge,, neighborList[i].row, neighborList[i].column);
                  }
                }
            }

attackNeighbors(wedge,row,column);
*/<commit_msg>parameter for TIMER<commit_after>goog.provide('utilities.Topping');

var toppingData = {
  //PEPPERONI//
  pepperoni: {
    image: 'assets/toppings_pepperoni.png',
    chaining: function(levelData, wedge, row, column,resultsObject){
      //nothing happens here!
    },
    powerUp: function(levelData, wedge, row, column, strength){
      //nuttin here either
    }
  },

  //MUSHROOM//
  mushroom: {
    image: 'assets/toppings_mushroom.png',
    chaining: function(levelData, wedge, row, column, resultsObject){
        //turn into a pepperoni and ATTACK!!
        levelData.get(wedge, row, column).toppingType = 'pepperoni';
        levelData.get(wedge, row, column).sprite.setFill(toppingData.pepperoni.image);
        resultsObject.mushroom++;
        attackNeighbors(levelData, wedge, row, column, resultsObject);
    },

    //STACKING power-up
    powerUp: function(levelData, wedge, row, column, strength){
      if(strength >= 4){

        if(strength <6) {
          levelData.get(wedge, row, column).toppingType = 'doublePepperoni';
          levelData.get(wedge, row, column).sprite.setFill(toppingData.doublePepperoni.image);
        }
        else if (strength >=6) {
          levelData.get(wedge, row, column).toppingType = 'triplePepperoni';
          levelData.get(wedge, row, column).sprite.setFill(toppingData.triplePepperoni.image);
        }
        console.log(levelData.get(wedge, row, column).toppingType);
        return true;
      }

      levelData.get(wedge,row,column).toppingType.stack = 1;
      return false;
    }
  },

  //OLIVES//
  olive: {
    image: 'assets/toppings_olive.png',
    chaining: function(levelData, wedge, row, column, resultsObject){
      var neighborTypes = checkNeighbors(levelData,wedge,row,column);
      var pprCount = 0;

      for (var i = neighborTypes.length - 1; i >= 0; i--) {
        if(neighborTypes[i] == 'pepperoni')
          pprCount++;
        else if(neighborTypes[i] == 'doublePepperoni' || neighborTypes[i] == 'triplePepperoni'){
          pprCount +=2; //don't need 3 anywho
        }
      }

      if(pprCount >= 2){
        //turn into a pepperoni and ATTACK!!
        levelData.get(wedge, row, column).toppingType = 'pepperoni';
        levelData.get(wedge, row, column).sprite.setFill(toppingData.pepperoni.image);
        resultsObject.olive++;
        return attackNeighbors(levelData, wedge, row, column, resultsObject);
      }
    },

    //AOE power-up
    powerUp: function(levelData, wedge, row, column, strength){
      if(strength >= 2){
        var neighborList = levelData.neighbors(wedge,row,column);
        console.log('AOE ENABLED');

        for (var i = neighborList.length - 1; i >= 0; i--) {
          var neighborData = levelData.get(neighborList[i].wedge, neighborList[i].row, neighborList[i].column);

          if(!neighborData.isOccupied){
            neighborData.toppingType = 'littlePepperoni';
            neighborData.sprite.setFill(utilities.Topping('pepperoni').image)
            neighborData.isOccupied = true;
          }
        }
        return true;
      }
      return false;
    }
  },

  //ANCHOVY//
  anchovy: {
    image: 'assets/toppings_anchovy.png',
    chaining: function(levelData, wedge, row, column, resultsObject, levelTimer){
      var neighborTypes = checkNeighbors(levelData,wedge,row,column);
      var pprCount = 0;

      for (var i = neighborTypes.length - 1; i >= 0; i--) {
        if(neighborTypes[i] == 'pepperoni')
          pprCount ++;
        else if(neighborTypes[i] == 'doublePepperoni')
          pprCount +=2; //don't need 3 anywho
        else if(neighborTypes[i] == 'triplePepperoni')
          pprCount +=3;
      }

      if(pprCount >= 3){
        //turn into a pepperoni and ATTACK!!
        levelData.get(wedge, row, column).toppingType = 'pepperoni';
        levelData.get(wedge, row, column).sprite.setFill(toppingData.pepperoni.image);
        resultsObject.anchovy++;
        return attackNeighbors(levelData, wedge, row, column, resultsObject);
      }
    },
    powerUp: function(levelData, wedge, row, column, strength){
      if(strength >= 1){
        return true;
      }
      return false;
    }
  },

  // bacon: 4,
  // buffaloChicken: 5,

  doublePepperoni: {
    image: 'assets/toppings_pepperoni_double.png',
    chaining: function(levelData, wedge, row, column,resultsObject){
      //nothing happens here!
    },
    powerUp: function(levelData, wedge, row, column, strength){
      //nuttin here either
    }
  },

  triplePepperoni: {
    image: 'assets/toppings_pepperoni_triple.png',
    chaining: function(levelData, wedge, row, column,resultsObject){
      //nothing happens here!
    },
    powerUp: function(levelData, wedge, row, column, strength){
      //nuttin here either
    }
  },

  littlePepperoni: {
    image: 'assets/toppings_pepperoni.png',
    chaining: function(levelData, wedge, row, column,resultsObject){
      //turn into a pepperoni and ATTACK!!
      levelData.get(wedge, row, column).toppingType = 'pepperoni';
      levelData.get(wedge, row, column).sprite.setFill(toppingData.pepperoni.image);
      resultsObject.mushroom++;
      attackNeighbors(levelData, wedge, row, column, resultsObject);
    },
    powerUp: function(levelData, wedge, row, column, strength){
      //nuttin here either
    }
  }

};

utilities.Topping = function(type)
{
    return toppingData[type];
};

//dat local neighbor check
function attackNeighbors(levelData, wedge,row,column, resultsObject)
{
  //TALLYING
  levelData.get(wedge,row,column).toppingType;

  var neighborList = levelData.neighbors(wedge,row,column);

  for (var i = neighborList.length - 1; i >= 0; i--) {
    var target = levelData.get(neighborList[i].wedge, neighborList[i].row, neighborList[i].column);

    if(target.isOccupied && target.toppingType != 'pepperoni')
      toppingData[target.toppingType].chaining(levelData,neighborList[i].wedge, neighborList[i].row, neighborList[i].column, resultsObject);
  }
}

function checkNeighbors(levelData, wedge,row,column)
{
  var neighborList = levelData.neighbors(wedge,row,column);
  var neighborTypes = [];

  for (var i = neighborList.length - 1; i >= 0; i--) {
    var target = levelData.get(neighborList[i].wedge, neighborList[i].row, neighborList[i].column);

    if(target.isOccupied)
      neighborTypes.push(target.toppingType);
  }

  return neighborTypes;
}

goog.exportSymbol('utilities.Topping',utilities.Topping);

/*
var attackNeighbors = function(wedge,row,column)
            {
                var neighborList = levelData.neighbors(wedge,row,column);

                for(i=0; i<neighborList.length; i++){
                  console.log(neighborList);
                  var target= levelData.get(neighborList[i].wedge,, neighborList[i].row, neighborList[i].column);

                  if(!target.isOccupied)
                    return;

                  if(target.toppingType == 'mushroom'){
                    target.toppingType = 'pepperoni';
                    target.sprite.setFill(utilities.Topping('pepperoni').image);
                    attackNeighbors(neighborList[i].wedge,, neighborList[i].row, neighborList[i].column);
                  }
                }
            }

attackNeighbors(wedge,row,column);
*/<|endoftext|>


<commit_before>'use strict';

const path = require('path');
const Promise = require('bluebird');
const debug = require('../src/util/debug')('bin:schedule');
const connection = require('../src/mongo/connection');

// Config
const config = require('../src/config/config').globalConfig;
const sources = Object.keys(config.source);
const aggregations = Object.keys(config.aggregation);

const schedulerLog = require('../src/mongo/models/schedulerLog');

const ProcessScheduler = require('process-scheduler');

Promise.coroutine(function* () {
    yield connection();
    const schedulerConfig = {
        threads: {
            source: config.schedulerThreadsSource,
            aggregation: config.schedulerThreadsAggregation
        }
    };

    const schedule = [];
    // Create configuration
    for (const collection of sources) {
        schedule.push({
            id: 'source_copy_' + collection,
            worker: path.join(__dirname, '../src/source/copyWorker.js'),
            immediate: false,
            cronRule: config.source[collection].copyCronRule,
            deps: [],
            noConcurrency: ['source_remove_' + collection, 'source_copy_missing_ids' + collection],
            arg: config.source[collection],
            type: 'source'
        });
        // copy missing ids
        schedule.push({
            id: 'source_copy_missing_ids' + collection,
            worker: path.join(__dirname, '../src/source/copyMissingIdsWorker.js'),
            immediate: false,
            cronRule: config.source[collection].copyMissingIdsCronRule,
            deps: [],
            noConcurrency: [],
            arg: config.source[collection],
            type: 'source'
        });
        schedule.push({
            id: 'source_remove_' + collection,
            worker: path.join(__dirname, '../src/source/removeWorker.js'),
            immediate: false,
            cronRule: config.source[collection].removeCronRule,
            deps: [],
            noConcurrency: [],
            arg: config.source[collection],
            type: 'source'
        });
    }

    for (const collection of aggregations) {
        let aggId = 'aggregation_' + collection;
        schedule.push({
            id: aggId,
            worker: path.join(__dirname, '../src/aggregation/worker.js'),
            immediate: false,
            arg: collection,
            type: 'aggregation'
        });

        let sources = Object.keys(config.aggregation[collection].sources);
        for (const source of sources) {
            setDeps('source_copy_' + source, aggId);
            setDeps('source_remove_' + source, aggId);
            setDeps('source_copy_missing_ids_' + source, aggId);
        }
    }

    function setDeps(name, aggId) {
        let s = schedule.find(s => s.id === name);
        if (s) {
            s.deps.push(aggId);
            s.noConcurrency.push(aggId);
        }
    }

    debug.trace('scheduler config' + schedulerConfig);
    var scheduler = new ProcessScheduler(schedulerConfig);

    scheduler.on('change', function (data) {
        schedulerLog.save(data);
    });
    scheduler.schedule(schedule);

    process.on('message', function (packet) {
        // When sending trigger requests form the web...
        switch (packet.type) {
            case 'scheduler:trigger':
                debug.trace('scheduler:trigger message received' + packet);
                if (packet.data.taskId) {
                    scheduler.trigger(packet.data.taskId);
                }
                break;
            default:
                debug.trace('unknown packet type sent to scheduler');
                break;
        }
    });

})();
<commit_msg>fix process ids in scheduler<commit_after>'use strict';

const path = require('path');
const Promise = require('bluebird');
const debug = require('../src/util/debug')('bin:schedule');
const connection = require('../src/mongo/connection');

// Config
const config = require('../src/config/config').globalConfig;
const sources = Object.keys(config.source);
const aggregations = Object.keys(config.aggregation);

const schedulerLog = require('../src/mongo/models/schedulerLog');

const ProcessScheduler = require('process-scheduler');

const REMOVE_ID = 'source_remove_';
const COPY_ID = 'source_copy_';
const COPY_MISSING_ID = 'source_copy_missing_ids_';

Promise.coroutine(function* () {
    yield connection();
    const schedulerConfig = {
        threads: {
            source: config.schedulerThreadsSource,
            aggregation: config.schedulerThreadsAggregation
        }
    };

    const schedule = [];
    // Create configuration
    for (const collection of sources) {
        schedule.push({
            id: COPY_ID + collection,
            worker: path.join(__dirname, '../src/source/copyWorker.js'),
            immediate: false,
            cronRule: config.source[collection].copyCronRule,
            deps: [],
            noConcurrency: [REMOVE_ID + collection, COPY_MISSING_ID + collection],
            arg: config.source[collection],
            type: 'source'
        });
        // copy missing ids
        schedule.push({
            id: COPY_MISSING_ID + collection,
            worker: path.join(__dirname, '../src/source/copyMissingIdsWorker.js'),
            immediate: false,
            cronRule: config.source[collection].copyMissingIdsCronRule,
            deps: [],
            noConcurrency: [],
            arg: config.source[collection],
            type: 'source'
        });
        schedule.push({
            id: REMOVE_ID + collection,
            worker: path.join(__dirname, '../src/source/removeWorker.js'),
            immediate: false,
            cronRule: config.source[collection].removeCronRule,
            deps: [],
            noConcurrency: [],
            arg: config.source[collection],
            type: 'source'
        });
    }

    for (const collection of aggregations) {
        let aggId = 'aggregation_' + collection;
        schedule.push({
            id: aggId,
            worker: path.join(__dirname, '../src/aggregation/worker.js'),
            immediate: false,
            arg: collection,
            type: 'aggregation'
        });

        let sources = Object.keys(config.aggregation[collection].sources);
        for (const source of sources) {
            setDeps(COPY_ID + source, aggId);
            setDeps(REMOVE_ID + source, aggId);
            setDeps(COPY_MISSING_ID + source, aggId);
        }
    }

    function setDeps(name, aggId) {
        let s = schedule.find(s => s.id === name);
        if (s) {
            s.deps.push(aggId);
            s.noConcurrency.push(aggId);
        }
    }

    debug.trace('scheduler config' + schedulerConfig);
    var scheduler = new ProcessScheduler(schedulerConfig);

    scheduler.on('change', function (data) {
        schedulerLog.save(data);
    });
    scheduler.schedule(schedule);

    process.on('message', function (packet) {
        // When sending trigger requests form the web...
        switch (packet.type) {
            case 'scheduler:trigger':
                debug.trace('scheduler:trigger message received' + packet);
                if (packet.data.taskId) {
                    scheduler.trigger(packet.data.taskId);
                }
                break;
            default:
                debug.trace('unknown packet type sent to scheduler');
                break;
        }
    });

})();
<|endoftext|>


<commit_before>import _ from "underscore";
import BaseView from "./BaseView";

let callbackIdGenerator = 0;
let emptyImage = 'empty.gif';
let cache = [];
let timeout;

export default class ImageView extends BaseView {

	tagName() {
		return 'figure';
	}

	constructor(options) {
		super(options);

		this._loaded = false;
		this._loadDebounce = null;
		this._appended = false;

		this.src     = '';

		this.setDefaultsOptions({
			src: null,
			autoload: true,
			placeholder: null,
			size: 'auto', // auto, normal, contain, cover. Scale the image to its container
			worker: false,
			viewport: null,
			className: 'ui-image',
			position: 'center', // top-left, top, top-right, center-left, center, center-right, bottom-left, bottom, bottom-right
			orientation: 0
		});

		this.$el.addClass(_.result(this.options, 'className') || '');

		if (this.options.size !== 'normal')
			this.$el.addClass(' ' + _.result(this.options, 'position') || '');

		this.image = new Image();
		this.image.style.opacity = 0;
		if (this.options.placeholder) {
			this.image.src = this.options.placeholder;
		}

		this.bufferImage = new Image();

		// Normal
		this.bufferImage.onerror = (err) => {
			this._loaded = false;
			this.requestAnimationFrame(() => {
				this.image.src = this.options.placeholder || emptyImage;
			});
		};
		this.bufferImage.onload = () => {
			this._loaded = true;
			this.requestAnimationFrame(() => {
				this.image.src = this.src;
				this.requestAnimationFrame(() => {
					if ( this.rendered )
						this.render();
					this.trigger('loaded');
				});
			});
		};

		this.setSource(this.options.src);
	}

	load() {
		if (this.src == this.bufferImage.src)
			return;
		this._loaded = false;
		if (this._loadDebounce)
			this.cancelAnimationFrame(this._loadDebounce);
		this._loadDebounce = this.requestAnimationFrame(() => {
			this.bufferImage.src = this.src;
		});
	}

	setSource(src, orientation) {
		if (this.src == src) return;
		if (typeof orientation !== 'undefined') {
			this.options.orientation = orientation;
		}
		if (this._loadDebounce)
			this.cancelAnimationFrame(this._loadDebounce);
		this.src = src;
		if (this.options.autoload) {
			this.load();
			return;
		}
		// this.image.style.visiblity = 'hidden';
		this.image.style.opacity = 0;
		this.image.src = emptyImage;
	}

	onRender(rendered) {
		if (!this._loaded && !this.options.placeholder) return;

		let bufferImage = this.bufferImage;
		let orientation = this.options.orientation;

		if (!this._loaded && this.options.placeholder) {
			bufferImage = this.image;
			orientation = 0;
		}

		let width       = bufferImage.width;
		let height      = bufferImage.height;

		var viewport = this.options.viewport ? this.options.viewport : this.viewport;
		if (!viewport) {
			// CAUTION: Always specify viewport dimensions to improve the performance!
			viewport = this.viewport = { width: this.$el.width(), height: this.$el.height() };
		}

		if (Math.abs(orientation) === 90) {
			viewport = {
				width:  viewport.height,
				height: viewport.width
			};
		}

		var cssText = '';

		var size = this.options.size;
		if (size !== 'normal') {
			var resized = {};
			var cover   = size === 'cover';

			if (size === 'auto')
				cover = width < height;

			var viewportRatio = viewport.width / viewport.height;
			var imageRatio    = width / height;
			var position      = this.options.position;

			var top;
			var left;
			var displayWidth;
			var displayHeight;
			var marginTop;
			var marginLeft;

			if ((cover === true && imageRatio >= viewportRatio) || (cover === false && imageRatio <= viewportRatio)) {
				resized.width = width * viewport.height / height;
				displayWidth  = resized.width;
				displayHeight = viewport.height;
			} else if ((cover === true && imageRatio < viewportRatio) || (cover === false && imageRatio > viewportRatio)) {
				resized.height = height * viewport.width / width;
				displayWidth  = viewport.width;
				displayHeight = resized.height;
			}

			switch (position) {
				case 'top':
					top        = 0;
					left       = 50;
					marginTop  = 0;
					marginLeft = displayWidth/-2;
					break;
				case 'center':
				default:
					top        = 50;
					left       = 50;
					marginTop  = displayHeight/-2;
					marginLeft = displayWidth/-2;
					break;
			}

			cssText =
				'position: absolute;' +
				'top: ' + top + '%;' +
				'left: ' + left + '%;' +
				'height: ' + displayHeight + 'px;' +
				'width: ' + displayWidth + 'px;' +
				'margin-top: ' + marginTop + 'px;' +
				'margin-left: ' + marginLeft + 'px;';
		}

		if (orientation !== 0) {
			cssText += '-webkit-transform: rotate(' + orientation + 'deg);';
			cssText += 'transform: rotate(' + orientation + 'deg);';
		}

		this.requestAnimationFrame(() => {
			cssText += 'opacity: 1;';
			this.image.style.cssText = cssText;
			if (!this._appended) {
				this.$el.append(this.image);
				this._appended = true;
			}
		});
	}

	refresh() {
		this.viewport = null;
		this.render();
	}

	width(val) {
		if (typeof val !== "undefined")
			return this.image.width = val;
		return this.image.width || 0;
	}

	height(val) {
		if (typeof val !== "undefined")
			return this.image.height = val;
		return this.image.height || 0;
	}

	destroy() {
		cache.push(this.image);
		this.image.src = emptyImage;
		if (timeout) clearTimeout(timeout);
		timeout = setTimeout(function(){ cache = [] }, 60000);
		super.destroy();
	}

}
<commit_msg>Added support to remote placeholders on ImageView<commit_after>import _ from "underscore";
import BaseView from "./BaseView";

let callbackIdGenerator = 0;
let emptyImage = 'empty.gif';
let cache = [];
let timeout;

export default class ImageView extends BaseView {

	tagName() {
		return 'figure';
	}

	constructor(options) {
		super(options);

		this._loaded = false;
		this._loadDebounce = null;
		this._appended = false;

		this.src     = '';

		this.setDefaultsOptions({
			src: null,
			autoload: true,
			placeholder: null,
			size: 'auto', // auto, normal, contain, cover. Scale the image to its container
			worker: false,
			viewport: null,
			className: 'ui-image',
			position: 'center', // top-left, top, top-right, center-left, center, center-right, bottom-left, bottom, bottom-right
			orientation: 0
		});

		this.$el.addClass(_.result(this.options, 'className') || '');

		if (this.options.size !== 'normal')
			this.$el.addClass(' ' + _.result(this.options, 'position') || '');

		this.image = new Image();
		this.image.style.opacity = 0;

		// Placeholder
		this.placeholderImage = new Image();
		this.placeholderImage.onload = () => {
			this._placeholderLoaded = true;
			if (!this._loaded) {
				this.requestAnimationFrame(() => {
					this.image.src = this.placeholderImage.src;
					this.requestAnimationFrame(() => {
						if ( this.rendered )
							this.render();
					});
				});
			}
		};

		if (this.options.placeholder) {
			this.placeholderImage.src = this.options.placeholder;
		}

		this.bufferImage = new Image();

		// Normal
		this.bufferImage.onerror = (err) => {
			this._loaded = false;
			this.requestAnimationFrame(() => {
				this.image.src = this.options.placeholder || emptyImage;
			});
		};
		this.bufferImage.onload = () => {
			this._loaded = true;
			this.requestAnimationFrame(() => {
				this.image.src = this.src;
				this.requestAnimationFrame(() => {
					if ( this.rendered )
						this.render();
					this.trigger('loaded');
				});
			});
		};

		this.setSource(this.options.src);
	}

	load() {
		if (this.src == this.bufferImage.src)
			return;
		this._loaded = false;
		if (this._loadDebounce)
			this.cancelAnimationFrame(this._loadDebounce);
		this._loadDebounce = this.requestAnimationFrame(() => {
			this.bufferImage.src = this.src;
		});
	}

	setSource(src, orientation) {
		if (this.src == src) return;
		if (typeof orientation !== 'undefined') {
			this.options.orientation = orientation;
		}
		if (this._loadDebounce)
			this.cancelAnimationFrame(this._loadDebounce);
		this.src = src;
		if (this.options.autoload) {
			this.load();
			return;
		}
		// this.image.style.visiblity = 'hidden';
		this.image.style.opacity = 0;
		this.image.src = emptyImage;
	}

	setPlaceholder(src, orientation) {
		if (this.placeholderImage.src == src) return;
		if (typeof orientation !== 'undefined') {
			this.options.orientation = orientation;
		}
		if (this._loadDebounce)
			this.cancelAnimationFrame(this._loadDebounce);
		this.placeholderImage.src = src;
		this.image.style.opacity = 0;
		this.image.src = emptyImage;
	}

	onRender(rendered) {
		if (!this._loaded && !this._placeholderLoaded)
			return;

		let bufferImage = this.bufferImage;
		let orientation = this.options.orientation;

		if (!this._loaded && this._placeholderLoaded) {
			bufferImage = this.placeholderImage;
			orientation = 0;
		}

		let width       = bufferImage.width;
		let height      = bufferImage.height;

		var viewport = this.options.viewport ? this.options.viewport : this.viewport;
		if (!viewport) {
			// CAUTION: Always specify viewport dimensions to improve the performance!
			viewport = this.viewport = { width: this.$el.width(), height: this.$el.height() };
		}

		if (Math.abs(orientation) === 90) {
			viewport = {
				width:  viewport.height,
				height: viewport.width
			};
		}

		var cssText = '';

		var size = this.options.size;
		if (size !== 'normal') {
			var resized = {};
			var cover   = size === 'cover';

			if (size === 'auto')
				cover = width < height;

			var viewportRatio = viewport.width / viewport.height;
			var imageRatio    = width / height;
			var position      = this.options.position;

			var top;
			var left;
			var displayWidth;
			var displayHeight;
			var marginTop;
			var marginLeft;

			if ((cover === true && imageRatio >= viewportRatio) || (cover === false && imageRatio <= viewportRatio)) {
				resized.width = width * viewport.height / height;
				displayWidth  = resized.width;
				displayHeight = viewport.height;
			} else if ((cover === true && imageRatio < viewportRatio) || (cover === false && imageRatio > viewportRatio)) {
				resized.height = height * viewport.width / width;
				displayWidth  = viewport.width;
				displayHeight = resized.height;
			}

			switch (position) {
				case 'top':
					top        = 0;
					left       = 50;
					marginTop  = 0;
					marginLeft = displayWidth/-2;
					break;
				case 'center':
				default:
					top        = 50;
					left       = 50;
					marginTop  = displayHeight/-2;
					marginLeft = displayWidth/-2;
					break;
			}

			cssText =
				'position: absolute;' +
				'top: ' + top + '%;' +
				'left: ' + left + '%;' +
				'height: ' + displayHeight + 'px;' +
				'width: ' + displayWidth + 'px;' +
				'margin-top: ' + marginTop + 'px;' +
				'margin-left: ' + marginLeft + 'px;';
		}

		if (orientation !== 0) {
			cssText += '-webkit-transform: rotate(' + orientation + 'deg);';
			cssText += 'transform: rotate(' + orientation + 'deg);';
		}

		this.requestAnimationFrame(() => {
			cssText += 'opacity: 1;';
			this.image.style.cssText = cssText;
			if (!this._appended) {
				this.$el.append(this.image);
				this._appended = true;
			}
		});
	}

	refresh() {
		this.viewport = null;
		this.render();
	}

	width(val) {
		if (typeof val !== "undefined")
			return this.image.width = val;
		return this.image.width || 0;
	}

	height(val) {
		if (typeof val !== "undefined")
			return this.image.height = val;
		return this.image.height || 0;
	}

	destroy() {
		cache.push(this.image);
		this.image.src = emptyImage;
		if (this.placeholderImage.src) {
			cache.push(this.placeholderImage);
			this.placeholderImage.src = emptyImage;
		}
		if (timeout) clearTimeout(timeout);
		timeout = setTimeout(function(){ cache = [] }, 60000);
		this.image = null;
		this.bufferImage = null;
		this.placeholderImage = null;
		super.destroy();
	}

}
<|endoftext|>


<commit_before>var iotivity = require( "bindings" )( "iotivity" ),
	OicResource = require( "./OicResource" ).OicResource,
	_ = require( "underscore" ),
	OicServer = function() {
		if ( !this._isOicServer ) {
			return new OicServer();
		}
	},
	OicRequestEvent = function() {
		if ( !this._isOicRequestEvent ) {
			return new OicRequestEvent();
		}
	};

_.extend( OicRequestEvent.prototype, {
	_isOicRequestEvent: true,

	sendResponse: function( resource ) {

		var oicResponse = [];
		oicResponse.requestHandle = this.requestId;
		oicResponse.resourceHandle = this.target;
		oicResponse.payload = resource;
		oicResponse.numRcvdVendorSpecificHeaderOptions = this.headerOptions.length;
		oicResponse.sendVendorSpecificHeaderOptions = new Array( this.headerOptions.length );
		for ( i = 0; i < this.headerOptions.length; i++ ) {
			oicResponse.sendVendorSpecificHeaderOptions[ i ] = [];
			oicResponse.sendVendorSpecificHeaderOptions[ i ].name = this.headerOptions[ i ].name;
			oicResponse.sendVendorSpecificHeaderOptions[ i ].value = this.headerOptions[ i ].value;
		}

		//FIXME: This url should be a FQDN or COAP URL ?
		oicResponse.resourceUri = iotivity.OCGetResourceUri( this.target );
		oicResponse.ehResult = iotivity.OCEntityHandlerResult.OC_EH_OK;

		var ret = iotivity.OCDoResponse( oicResponse );
		if ( ret != iotivity.OCStackResult.OC_STACK_OK ) {
			console.log( "DoResponse Error" );
		}
	},
	sendError: function( error ) {
		oicResponse.requestHandle = this.requestId;
		oicResponse.resourceHandle = this.target;
		oicResponse.ehResult = error.message;
		var ret = iotivity.OCDoResponse( oicResponse );
		if ( ret != iotivity.OCStackResult.OC_STACK_OK ) {
			console.log( "DoResponse Error" );
		}
	}
} );

_.extend( OicServer.prototype, {
	_isOicServer: true,
	onrequest: null,
	_resources: [],
	listeners: {},
	_interestedObservers: [],

	addEventListener: function( event, callback ) {
		if ( !( event in this.listeners ) ) {
			this.listeners[ event ] = [];
		}

		// Currently allows duplicate callbacks. Should it?
		this.listeners[ event ].push( callback );
	},

	removeEventListener: function( event, callback ) {
		if ( event in this.listeners ) {
			this.listeners[ event ] = this.listeners[ event ].filter( function( ev ) {
				return ev !== callback;
			} );
		}
	},

	dispatchEvent: function( event, request ) {
		if ( typeof this[ "on" + event ] === "function" ) {
			this[ "on" + event ]( request );
		}
		if ( event in this.listeners ) {
			for ( var i = 0, len = this.listeners[ event ].length; i < len; i++ ) {
				this.listeners[ event ][ i ].call( this, request );
			}
		}
	},

	registerResource: function( init ) {
		return new Promise( _.bind( function( fulfill, reject ) {
			var result = 0;
			var flag = 0;
			var handle = {};
			var resource = new OicResource( init );

			if ( init.discoverable ) {
				flag |= iotivity.OCResourceProperty.OC_DISCOVERABLE;
			}

			if ( init.observable ) {
				flag |= iotivity.OCResourceProperty.OC_OBSERVABLE;
			}

			result = iotivity.OCCreateResource(
				handle,

				// FIXME: API SPEC mentions an array.Vaguely remember that the first type is
				// default from the Oic Spec. Check it up.
				init.resourceTypes[ 0 ],

				// FIXME: API SPEC mentions an array.Vaguely remember that the first type is
				// default from the Oic Spec. Check it up.
				init.interfaces[ 0 ],
				init.url,
				function( flag, request ) {

					// Handle the request and raise events accordingly
					var oicReq = new OicRequestEvent();

					oicReq.requestId = request.requestHandle;
					oicReq.target = request.resource;
					oicReq.source = resource;

					if ( flag & iotivity.OCEntityHandlerFlag.OC_REQUEST_FLAG ) {

						// As per the C++ Code: The query format is q1=v1&;q1=v2;
						var obj;
						var seperator = "&;";
						var qparams = request.query.split( seperator );
						oicReq.queryOptions = new Array( qparams.length );

						for ( i = 0; request.query !== "" && i < qparams.length; i++ ) {
							var param = qparams[ i ].split( "=" );
							oicReq.queryOptions[ i ] = [];
							oicReq.queryOptions[ i ].key = param[ 0 ];
							oicReq.queryOptions[ i ].value = param[ 1 ];
						}

						var len = request.rcvdVendorSpecificHeaderOptions.length;
						oicReq.headerOptions = new Array( len );
						if ( len > 0 ) {
							for ( i = 0; i < len; i++ ) {
								var headerOption = {};

								headerOption.name =
									request.rcvdVendorSpecificHeaderOptions[ i ].optionID;
								headerOption.value =
									request.rcvdVendorSpecificHeaderOptions[ i ].optionData;
								oicReq.headerOptions[ i ] = headerOption;
							}
						}

						if ( request.method == iotivity.OCMethod.OC_REST_GET ) {
							oicReq.type = "retrieve";
						} else if ( request.method == iotivity.OCMethod.OC_REST_PUT ) {
							oicReq.type = "create";

							obj = request.payload;
							_.extend( oicReq.res, obj );

						} else if ( request.method == iotivity.OCMethod.OC_REST_POST ) {
							oicReq.type = "update";

							//FIXME: Check if this is the right way of doing it.
							obj = request.payload;
							_.extend( oicReq.res, obj );
							oicReq.updatedPropertyNames = _.difference( resource, obj );
						} else if ( request.method == iotivity.OCMethod.OC_REST_DELETE ) {
							oicReq.type = "delete";
						} else if ( request.method == iotivity.OCMethod.OC_REST_OBSERVE ) {
							oicReq.type = "observe";
						}

					}

					if ( flag & iotivity.OCEntityHandlerFlag.OC_OBSERVE_FLAG ) {
						if ( request.obsInfo.action ==
								iotivity.OCObserveAction.OC_OBSERVE_REGISTER ) {
							resource._server._interestedObservers.push( request.obsInfo.obsId );
						} else if ( request.obsInfo.action ==
								iotivity.OCObserveAction.OC_OBSERVE_DEREGISTER ) {
							var index = resource._server._interestedObservers
								.indexOf( request.obsInfo.obsId );

							// FIXME: Should we loop and remove?
							while ( index != -1 ) {
								resource._server._interestedObservers.splice( index, 1 );
								index = resource._server._interestedObservers
									.indexOf( request.obsInfo.obsId );
							}
						}

						// FIXME: Check how this should be done.
						oicReq.type = "observe";
					}

					resource._server.dispatchEvent( "request", oicReq );

					return iotivity.OCEntityHandlerResult.OC_EH_OK;
				},
				flag );

			if ( result !== iotivity.OCStackResult.OC_STACK_OK ) {
				reject( _.extend( new Error( "registerResource: OCCreateResource() failed" ), {
					result: result
				} ) );
				return;
			}

			// FIXME: What whould be the id? Something unique or the handle?
			resource.id = handle;

			//FIXME: Check if we can do this.
			resource._server = this;
			this._resources[ handle ] = resource;
			fulfill( resource );
		}, this ) );

	},

	unregisterResource: function( resourceId ) {
		return new Promise( _.bind( function( fulfill, reject ) {
			var result;

			result = iotivity.OCDeleteResource( resourceId.handle );
			if ( result !== iotivity.OCStackResult.OC_STACK_OK ) {
				reject( _.extend( new Error( "unregisterResource: OCDeleteResource() failed" ), {
					result: result
				} ) );
				return;
			}

			fulfill();
		}, this ) );
	},

	enablePresence: function( ttl ) {
		return new Promise( _.bind( function( fulfill, reject ) {
			var result;

			result = iotivity.OCStartPresence( ttl ? ttl : 0 );

			if ( result !== iotivity.OCStackResult.OC_STACK_OK ) {
				reject( _.extend( new Error( "enablePresence: OCStartPresence() failed" ), {
					result: result
				} ) );
				return;
			}

			fulfill();
		}, this ) );
	},

	disablePresence: function() {
		return new Promise( _.bind( function( fulfill, reject ) {
			var result;

			result = iotivity.OCStopPresence();

			if ( result !== iotivity.OCStackResult.OC_STACK_OK ) {
				reject( _.extend( new Error( "enablePresence: OCStopPresence() failed" ), {
					result: result
				} ) );
				return;
			}

			fulfill();
		}, this ) );
	},

	notify: function( resourceId, method, updatedPropertyNames ) {
		return new Promise( _.bind( function( fulfill, reject ) {
			var result;

			var resource = this._resources[ resourceId ];

			var payload = [];
			payload.type = iotivity.OCPayloadType.PAYLOAD_TYPE_REPRESENTATION;
			payload.uri = resource.url;
			payload.values = resource.properties;

			//FIXME: Find how we define QoS
			result = iotivity.OCNotifyListOfObservers( resourceId.handle,
				this._interestedObservers,
				payload,
				iotivity.OCQualityOfService.OC_NA_QOS
			);

			if ( result !== iotivity.OCStackResult.OC_STACK_OK ) {
				reject( _.extend( new Error( "notify: OCNotifyListOfObservers() failed" ), {
					result: result
				} ) );
				return;
			}

			fulfill();
		}, this ) );
	}
} );

module.exports = {
	OicServer: OicServer,
	OicRequestEvent: OicRequestEvent
};
<commit_msg>OicServer: Use node's own event infrastructure<commit_after>var iotivity = require( "bindings" )( "iotivity" ),
	OicResource = require( "./OicResource" ).OicResource,
	_ = require( "underscore" ),
	OicServer = function() {
		if ( !this._isOicServer ) {
			return new OicServer();
		}
	},
	OicRequestEvent = function() {
		if ( !this._isOicRequestEvent ) {
			return new OicRequestEvent();
		}
	};

_.extend( OicRequestEvent.prototype, {
	_isOicRequestEvent: true,

	sendResponse: function( resource ) {

		var oicResponse = [];
		oicResponse.requestHandle = this.requestId;
		oicResponse.resourceHandle = this.target;
		oicResponse.payload = resource;
		oicResponse.numRcvdVendorSpecificHeaderOptions = this.headerOptions.length;
		oicResponse.sendVendorSpecificHeaderOptions = new Array( this.headerOptions.length );
		for ( i = 0; i < this.headerOptions.length; i++ ) {
			oicResponse.sendVendorSpecificHeaderOptions[ i ] = [];
			oicResponse.sendVendorSpecificHeaderOptions[ i ].name = this.headerOptions[ i ].name;
			oicResponse.sendVendorSpecificHeaderOptions[ i ].value = this.headerOptions[ i ].value;
		}

		//FIXME: This url should be a FQDN or COAP URL ?
		oicResponse.resourceUri = iotivity.OCGetResourceUri( this.target );
		oicResponse.ehResult = iotivity.OCEntityHandlerResult.OC_EH_OK;

		var ret = iotivity.OCDoResponse( oicResponse );
		if ( ret != iotivity.OCStackResult.OC_STACK_OK ) {
			console.log( "DoResponse Error" );
		}
	},
	sendError: function( error ) {
		oicResponse.requestHandle = this.requestId;
		oicResponse.resourceHandle = this.target;
		oicResponse.ehResult = error.message;
		var ret = iotivity.OCDoResponse( oicResponse );
		if ( ret != iotivity.OCStackResult.OC_STACK_OK ) {
			console.log( "DoResponse Error" );
		}
	}
} );

require( "util" ).inherits( OicServer, require( "events" ).EventEmitter );

_.extend( OicServer.prototype, {
	_isOicServer: true,
	onrequest: null,
	_resources: [],
	_interestedObservers: [],

	addEventListener: function( event, callback ) {
		this.addListener( event, callback );
	},

	removeEventListener: function( event, callback ) {
		this.removeListener( event, callback );
	},

	dispatchEvent: function( event, request ) {
		this.emit( event, request );
		if ( typeof this[ "on" + event ] === "function" ) {
			this[ "on" + event ]( request );
		}
	},

	registerResource: function( init ) {
		return new Promise( _.bind( function( fulfill, reject ) {
			var result = 0;
			var flag = 0;
			var handle = {};
			var resource = new OicResource( init );

			if ( init.discoverable ) {
				flag |= iotivity.OCResourceProperty.OC_DISCOVERABLE;
			}

			if ( init.observable ) {
				flag |= iotivity.OCResourceProperty.OC_OBSERVABLE;
			}

			result = iotivity.OCCreateResource(
				handle,

				// FIXME: API SPEC mentions an array.Vaguely remember that the first type is
				// default from the Oic Spec. Check it up.
				init.resourceTypes[ 0 ],

				// FIXME: API SPEC mentions an array.Vaguely remember that the first type is
				// default from the Oic Spec. Check it up.
				init.interfaces[ 0 ],
				init.url,
				function( flag, request ) {

					// Handle the request and raise events accordingly
					var oicReq = new OicRequestEvent();

					oicReq.requestId = request.requestHandle;
					oicReq.target = request.resource;
					oicReq.source = resource;

					if ( flag & iotivity.OCEntityHandlerFlag.OC_REQUEST_FLAG ) {

						// As per the C++ Code: The query format is q1=v1&;q1=v2;
						var obj;
						var seperator = "&;";
						var qparams = request.query.split( seperator );
						oicReq.queryOptions = new Array( qparams.length );

						for ( i = 0; request.query !== "" && i < qparams.length; i++ ) {
							var param = qparams[ i ].split( "=" );
							oicReq.queryOptions[ i ] = [];
							oicReq.queryOptions[ i ].key = param[ 0 ];
							oicReq.queryOptions[ i ].value = param[ 1 ];
						}

						var len = request.rcvdVendorSpecificHeaderOptions.length;
						oicReq.headerOptions = new Array( len );
						if ( len > 0 ) {
							for ( i = 0; i < len; i++ ) {
								var headerOption = {};

								headerOption.name =
									request.rcvdVendorSpecificHeaderOptions[ i ].optionID;
								headerOption.value =
									request.rcvdVendorSpecificHeaderOptions[ i ].optionData;
								oicReq.headerOptions[ i ] = headerOption;
							}
						}

						if ( request.method == iotivity.OCMethod.OC_REST_GET ) {
							oicReq.type = "retrieve";
						} else if ( request.method == iotivity.OCMethod.OC_REST_PUT ) {
							oicReq.type = "create";

							obj = request.payload;
							_.extend( oicReq.res, obj );

						} else if ( request.method == iotivity.OCMethod.OC_REST_POST ) {
							oicReq.type = "update";

							//FIXME: Check if this is the right way of doing it.
							obj = request.payload;
							_.extend( oicReq.res, obj );
							oicReq.updatedPropertyNames = _.difference( resource, obj );
						} else if ( request.method == iotivity.OCMethod.OC_REST_DELETE ) {
							oicReq.type = "delete";
						} else if ( request.method == iotivity.OCMethod.OC_REST_OBSERVE ) {
							oicReq.type = "observe";
						}

					}

					if ( flag & iotivity.OCEntityHandlerFlag.OC_OBSERVE_FLAG ) {
						if ( request.obsInfo.action ==
								iotivity.OCObserveAction.OC_OBSERVE_REGISTER ) {
							resource._server._interestedObservers.push( request.obsInfo.obsId );
						} else if ( request.obsInfo.action ==
								iotivity.OCObserveAction.OC_OBSERVE_DEREGISTER ) {
							var index = resource._server._interestedObservers
								.indexOf( request.obsInfo.obsId );

							// FIXME: Should we loop and remove?
							while ( index != -1 ) {
								resource._server._interestedObservers.splice( index, 1 );
								index = resource._server._interestedObservers
									.indexOf( request.obsInfo.obsId );
							}
						}

						// FIXME: Check how this should be done.
						oicReq.type = "observe";
					}

					resource._server.dispatchEvent( "request", oicReq );

					return iotivity.OCEntityHandlerResult.OC_EH_OK;
				},
				flag );

			if ( result !== iotivity.OCStackResult.OC_STACK_OK ) {
				reject( _.extend( new Error( "registerResource: OCCreateResource() failed" ), {
					result: result
				} ) );
				return;
			}

			// FIXME: What whould be the id? Something unique or the handle?
			resource.id = handle;

			//FIXME: Check if we can do this.
			resource._server = this;
			this._resources[ handle ] = resource;
			fulfill( resource );
		}, this ) );

	},

	unregisterResource: function( resourceId ) {
		return new Promise( _.bind( function( fulfill, reject ) {
			var result;

			result = iotivity.OCDeleteResource( resourceId.handle );
			if ( result !== iotivity.OCStackResult.OC_STACK_OK ) {
				reject( _.extend( new Error( "unregisterResource: OCDeleteResource() failed" ), {
					result: result
				} ) );
				return;
			}

			fulfill();
		}, this ) );
	},

	enablePresence: function( ttl ) {
		return new Promise( _.bind( function( fulfill, reject ) {
			var result;

			result = iotivity.OCStartPresence( ttl ? ttl : 0 );

			if ( result !== iotivity.OCStackResult.OC_STACK_OK ) {
				reject( _.extend( new Error( "enablePresence: OCStartPresence() failed" ), {
					result: result
				} ) );
				return;
			}

			fulfill();
		}, this ) );
	},

	disablePresence: function() {
		return new Promise( _.bind( function( fulfill, reject ) {
			var result;

			result = iotivity.OCStopPresence();

			if ( result !== iotivity.OCStackResult.OC_STACK_OK ) {
				reject( _.extend( new Error( "enablePresence: OCStopPresence() failed" ), {
					result: result
				} ) );
				return;
			}

			fulfill();
		}, this ) );
	},

	notify: function( resourceId, method, updatedPropertyNames ) {
		return new Promise( _.bind( function( fulfill, reject ) {
			var result;

			var resource = this._resources[ resourceId ];

			var payload = [];
			payload.type = iotivity.OCPayloadType.PAYLOAD_TYPE_REPRESENTATION;
			payload.uri = resource.url;
			payload.values = resource.properties;

			//FIXME: Find how we define QoS
			result = iotivity.OCNotifyListOfObservers( resourceId.handle,
				this._interestedObservers,
				payload,
				iotivity.OCQualityOfService.OC_NA_QOS
			);

			if ( result !== iotivity.OCStackResult.OC_STACK_OK ) {
				reject( _.extend( new Error( "notify: OCNotifyListOfObservers() failed" ), {
					result: result
				} ) );
				return;
			}

			fulfill();
		}, this ) );
	}
} );

module.exports = {
	OicServer: OicServer,
	OicRequestEvent: OicRequestEvent
};
<|endoftext|>


<commit_before>'use strict'

const config = require(__dirname + '/../config')
const GitHub = require('./GitHub')
const markdownTable = require('markdown-table')
const md5 = require('md5')
const Mailgun = require('mailgun-js')
const NodeRSA = require('node-rsa')
const objectPath = require('object-path')
const SiteConfig = require(__dirname + '/../siteConfig')
const slugify = require('slug')
const SubscriptionsManager = require('./SubscriptionsManager')
const uuid = require('node-uuid')
const yaml = require('js-yaml')

const Staticman = function (parameters) {
  this.parameters = parameters

  // Initialise GitHub API
  this.github = new GitHub({
    username: this.parameters.username,
    repository: this.parameters.repository,
    branch: this.parameters.branch
  })

  // Generate unique id
  this.uid = uuid.v1()

  // Initialise RSA
  this.rsa = new NodeRSA()
  this.rsa.importKey(config.get('rsaPrivateKey'))
}

Staticman.prototype._applyInternalFields = function (data) {
  let internalFields = {
    _id: this.uid
  }

  // Inject parent, if present
  if (this.options.parent) {
    internalFields._parent = this.options.parent
  }

  return Object.assign(internalFields, data)
}

Staticman.prototype._applyGeneratedFields = function (data) {
  const generatedFields = this.siteConfig.get('generatedFields')

  if (!generatedFields) return data

  Object.keys(generatedFields).forEach(field => {
    const generatedField = generatedFields[field]

    if ((typeof generatedField === 'object') && (!(generatedField instanceof Array))) {
      const options = generatedField.options || {}

      switch (generatedField.type) {
        case 'date':
          data[field] = this._createDate(options)

          break

        case 'slugify':
          if (typeof options.field === 'string') {
            data[field] = slugify(data[options.field]).toLowerCase()
          }

          break
      }
    } else {
      data[field] = generatedField
    }
  })

  return data
}

Staticman.prototype._applyTransforms = function (fields) {
  const transforms = this.siteConfig.get('transforms')

  if (!transforms) return Promise.resolve(fields)

  // This doesn't serve any purpose for now, but we might want to have
  // asynchronous transforms in the future.
  let queue = []

  Object.keys(transforms).forEach(field => {
    if (!fields[field]) return

    if (transforms[field] === 'md5') {
      fields[field] = md5(fields[field])
    }
  })

  return Promise.all(queue).then((results) => {
    return fields
  })
}

Staticman.prototype._checkForSpam = function (fields) {
  if (!this.siteConfig.get('akismet.enabled')) return Promise.resolve(fields)

  return new Promise((resolve, reject) => {
    const akismet = require('akismet').client({
      blog: config.get('akismet.site'),
      apiKey: config.get('akismet.apiKey')
    })

    akismet.checkSpam({
      user_ip: this.ip,
      user_agent: this.userAgent,
      comment_type: this.siteConfig.get('akismet.type'),
      comment_author: fields[this.siteConfig.get('akismet.author')],
      comment_author_email: fields[this.siteConfig.get('akismet.authorEmail')],
      comment_author_url: fields[this.siteConfig.get('akismet.authorUrl')],
      comment_content: fields[this.siteConfig.get('akismet.content')]
    }, (err, isSpam) => {
      if (err) return reject(err)

      if (isSpam) return reject('IS_SPAM')

      return resolve(fields)
    })
  })
}

Staticman.prototype._createDate = function (options) {
  const date = new Date()

  switch (options.format) {
    case 'timestamp':
      return date.getTime()

    case 'timestamp-seconds':
      return Math.floor(date.getTime() / 1000)

    case 'iso8601':
    default:
      return date.toISOString()
  }
}

Staticman.prototype._createFile = function (fields) {
  return new Promise((resolve, reject) => {
    switch (this.siteConfig.get('format').toLowerCase()) {
      case 'json':
        return resolve(JSON.stringify(fields))

      case 'yaml':
      case 'yml':
        try {
          const output = yaml.safeDump(fields)

          return resolve(output)
        } catch (err) {
          return reject(err)
        }

        break

      case 'frontmatter':
        const transforms = this.siteConfig.get('transforms')

        const contentField = transforms && Object.keys(transforms).find(field => {
          return transforms[field] === 'frontmatterContent'
        })

        if (!contentField) {
          return reject('NO_FRONTMATTER_CONTENT_TRANSFORM')
        }

        const content = fields[contentField]

        delete fields[contentField]

        try {
          const output = `---\n${yaml.safeDump(fields)}---\n${content}\n`

          return resolve(output)
        } catch (err) {
          return reject(err)
        }

        break

      default:
        return reject('INVALID_FORMAT')
    }
  })
}

Staticman.prototype._generatePRBody = function (fields) {
  let table = [
    ['Field', 'Content']
  ]

  Object.keys(fields).forEach(field => {
    table.push([field, fields[field]])
  })

  let message = this.siteConfig.get('pullRequestBody') + markdownTable(table)

  if (this.siteConfig.get('notifications.enabled')) {
    const notificationsPayload = {
      configPath: this.configPath,
      fields,
      options: this.options,
      parameters: this.parameters
    }

    message += `\n\n<!--staticman_notification:${JSON.stringify(notificationsPayload)}-->`
  }

  return message
}

Staticman.prototype._getConfig = function (force) {
  if (this.siteConfig && !force) return Promise.resolve(this.siteConfig)

  if (!this.configPath) return Promise.reject('NO_CONFIG_PATH')

  return this.github.readFile(this.configPath.file).then(data => {
    const config = objectPath.get(data, this.configPath.path)
    const validationErrors = this._validateConfig(config)

    if (validationErrors) {
      return Promise.reject(validationErrors)
    }

    if (config.branch !== this.parameters.branch) {
      return Promise.reject('BRANCH_MISMATCH')
    }

    return this.siteConfig
  })
}

Staticman.prototype._getNewFilePath = function (data) {
  const configFilename = this.siteConfig.get('filename')
  const filename = configFilename ? this._resolvePlaceholders(configFilename, {
    fields: data,
    options: this.options
  }) : this.uid

  const path = this._resolvePlaceholders(this.siteConfig.get('path'), {
    fields: data,
    options: this.options
  })

  const extension = this._getExtensionForFormat(this.siteConfig.get('format'))

  return `${path}/${filename}.${extension}`
}

Staticman.prototype._getExtensionForFormat = function (format) {
  switch (format.toLowerCase()) {
    case 'json':
      return 'json'

    case 'yaml':
    case 'yml':
      return 'yml'

    case 'frontmatter':
      return 'md'
  }
}

Staticman.prototype._initialiseSubscriptions = function () {
  if (!this.siteConfig.get('notifications.enabled')) return null

  // Initialise Mailgun
  const mailgun = Mailgun({
    apiKey: this.siteConfig.get('notifications.apiKey') || config.get('email.apiKey'),
    domain: this.siteConfig.get('notifications.domain') || config.get('email.domain')
  })

  // Initialise SubscriptionsManager
  const subscriptions = new SubscriptionsManager(this.parameters, this.github, mailgun)

  return subscriptions
}

Staticman.prototype._resolvePlaceholders = function (subject, baseObject) {
  const matches = subject.match(/{(.*?)}/g)

  if (!matches) return subject

  matches.forEach((match) => {
    const escapedMatch = match.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
    const property = match.slice(1, -1)

    let newText

    switch (property) {
      case '@timestamp':
        newText = new Date().getTime()

        break

      case '@id':
        newText = this.uid

        break

      default:
        newText = objectPath.get(baseObject, property) || ''
    }

    subject = subject.replace(new RegExp(escapedMatch, 'g'), newText)
  })

  return subject
}

Staticman.prototype._validateConfig = function (config) {
  if (!config) {
    return {
      code: 'MISSING_CONFIG_BLOCK'
    }
  }

  const requiredFields = [
    'allowedFields',
    'branch',
    'format',
    'path'
  ]

  let missingFields = []

  // Checking for missing required fields
  requiredFields.forEach(requiredField => {
    if (objectPath.get(config, requiredField) === undefined) {
      missingFields.push(requiredField)
    }
  })

  if (missingFields.length) {
    return {
      code: 'MISSING_CONFIG_FIELDS',
      data: missingFields
    }
  }

  // Check origin
  if (config.allowedOrigins && config.allowedOrigins.length) {
    if (this.options.origin) {
      const url = require('url').parse(this.options.origin)

      const validOrigin = config.allowedOrigins.some(origin => {
        return origin === url.hostname
      })

      if (!validOrigin) {
        return {
          code: 'INVALID_ORIGIN',
          data: null
        }
      }
    } else {
      return {
        code: 'MISSING_ORIGIN',
        data: null
      }
    }
  }

  this.siteConfig = SiteConfig(config, this.rsa)

  return null
}

Staticman.prototype._validateFields = function (fields) {
  let errors = []
  let missingRequiredFields = []
  let invalidFields = []

  Object.keys(fields).forEach(field => {
    // Check for any invalid fields
    if ((this.siteConfig.get('allowedFields').indexOf(field) === -1) && (fields[field] !== '')) {
      invalidFields.push(field)
    }

    // Trim fields
    if (typeof fields[field] === 'string') {
      fields[field] = fields[field].trim()
    }
  })

  // Check for missing required fields
  this.siteConfig.get('requiredFields').forEach(field => {
    if ((fields[field] === undefined) || (fields[field] === '')) {
      missingRequiredFields.push(field)
    }
  })

  if (missingRequiredFields.length) {
    errors.push({
      code: 'MISSING_REQUIRED_FIELDS',
      data: missingRequiredFields
    })
  }

  if (invalidFields.length) {
    errors.push({
      code: 'INVALID_FIELDS',
      data: invalidFields
    })
  }

  if (errors.length) return errors

  return null
}

Staticman.prototype.processEntry = function (fields, options) {
  this.fields = Object.assign({}, fields)
  this.options = Object.assign({}, options)

  return this._getConfig().then(config => {
    return this._checkForSpam(fields)
  }).then(fields => {
    // Validate fields
    const fieldErrors = this._validateFields(fields)

    if (fieldErrors) return Promise.reject(fieldErrors)

    // Add generated fields
    fields = this._applyGeneratedFields(fields)

    // Apply transforms
    return this._applyTransforms(fields)
  }).then(transformedFields => {
    return this._applyInternalFields(transformedFields)
  }).then(extendedFields => {
    // Create file
    return this._createFile(extendedFields)
  }).then(data => {
    const filePath = this._getNewFilePath(fields)
    const subscriptions = this._initialiseSubscriptions()

    // Subscribe user, if applicable
    if (subscriptions && options.parent && options.subscribe && this.fields[options.subscribe]) {
      subscriptions.set(options.parent, this.fields[options.subscribe]).catch(err => {
        console.log(err.stack || err)
      })
    }

    if (this.siteConfig.get('moderation')) {
      const newBranch = 'staticman_' + this.uid

      return this.github.writeFileAndSendPR(filePath, data, newBranch, this.siteConfig.get('commitMessage'), this._generatePRBody(fields))
    } else if (subscriptions && options.parent) {
      subscriptions.send(options.parent, fields, options)
    }

    return this.github.writeFile(filePath, data, this.parameters.branch, this.siteConfig.get('commitMessage'))
  }).then(result => {
    return {
      fields: fields,
      redirect: options.redirect ? options.redirect : false
    }
  })
}

Staticman.prototype.processMerge = function (fields, options) {
  this.fields = Object.assign({}, fields)
  this.options = Object.assign({}, options)

  return this._getConfig().then(config => {
    const subscriptions = this._initialiseSubscriptions()

    return subscriptions.send(options.parent, fields, options, this.siteConfig)
  })
}

Staticman.prototype.setConfigPath = function (configPath) {
  this.configPath = configPath
}

Staticman.prototype.setIp = function (ip) {
  this.ip = ip
}

Staticman.prototype.setUserAgent = function (userAgent) {
  this.userAgent = userAgent
}

module.exports = Staticman
<commit_msg>Let commit message use placeholders<commit_after>'use strict'

const config = require(__dirname + '/../config')
const GitHub = require('./GitHub')
const markdownTable = require('markdown-table')
const md5 = require('md5')
const Mailgun = require('mailgun-js')
const NodeRSA = require('node-rsa')
const objectPath = require('object-path')
const SiteConfig = require(__dirname + '/../siteConfig')
const slugify = require('slug')
const SubscriptionsManager = require('./SubscriptionsManager')
const uuid = require('node-uuid')
const yaml = require('js-yaml')

const Staticman = function (parameters) {
  this.parameters = parameters

  // Initialise GitHub API
  this.github = new GitHub({
    username: this.parameters.username,
    repository: this.parameters.repository,
    branch: this.parameters.branch
  })

  // Generate unique id
  this.uid = uuid.v1()

  // Initialise RSA
  this.rsa = new NodeRSA()
  this.rsa.importKey(config.get('rsaPrivateKey'))
}

Staticman.prototype._applyInternalFields = function (data) {
  let internalFields = {
    _id: this.uid
  }

  // Inject parent, if present
  if (this.options.parent) {
    internalFields._parent = this.options.parent
  }

  return Object.assign(internalFields, data)
}

Staticman.prototype._applyGeneratedFields = function (data) {
  const generatedFields = this.siteConfig.get('generatedFields')

  if (!generatedFields) return data

  Object.keys(generatedFields).forEach(field => {
    const generatedField = generatedFields[field]

    if ((typeof generatedField === 'object') && (!(generatedField instanceof Array))) {
      const options = generatedField.options || {}

      switch (generatedField.type) {
        case 'date':
          data[field] = this._createDate(options)

          break

        case 'slugify':
          if (typeof options.field === 'string') {
            data[field] = slugify(data[options.field]).toLowerCase()
          }

          break
      }
    } else {
      data[field] = generatedField
    }
  })

  return data
}

Staticman.prototype._applyTransforms = function (fields) {
  const transforms = this.siteConfig.get('transforms')

  if (!transforms) return Promise.resolve(fields)

  // This doesn't serve any purpose for now, but we might want to have
  // asynchronous transforms in the future.
  let queue = []

  Object.keys(transforms).forEach(field => {
    if (!fields[field]) return

    if (transforms[field] === 'md5') {
      fields[field] = md5(fields[field])
    }
  })

  return Promise.all(queue).then((results) => {
    return fields
  })
}

Staticman.prototype._checkForSpam = function (fields) {
  if (!this.siteConfig.get('akismet.enabled')) return Promise.resolve(fields)

  return new Promise((resolve, reject) => {
    const akismet = require('akismet').client({
      blog: config.get('akismet.site'),
      apiKey: config.get('akismet.apiKey')
    })

    akismet.checkSpam({
      user_ip: this.ip,
      user_agent: this.userAgent,
      comment_type: this.siteConfig.get('akismet.type'),
      comment_author: fields[this.siteConfig.get('akismet.author')],
      comment_author_email: fields[this.siteConfig.get('akismet.authorEmail')],
      comment_author_url: fields[this.siteConfig.get('akismet.authorUrl')],
      comment_content: fields[this.siteConfig.get('akismet.content')]
    }, (err, isSpam) => {
      if (err) return reject(err)

      if (isSpam) return reject('IS_SPAM')

      return resolve(fields)
    })
  })
}

Staticman.prototype._createDate = function (options) {
  const date = new Date()

  switch (options.format) {
    case 'timestamp':
      return date.getTime()

    case 'timestamp-seconds':
      return Math.floor(date.getTime() / 1000)

    case 'iso8601':
    default:
      return date.toISOString()
  }
}

Staticman.prototype._createFile = function (fields) {
  return new Promise((resolve, reject) => {
    switch (this.siteConfig.get('format').toLowerCase()) {
      case 'json':
        return resolve(JSON.stringify(fields))

      case 'yaml':
      case 'yml':
        try {
          const output = yaml.safeDump(fields)

          return resolve(output)
        } catch (err) {
          return reject(err)
        }

        break

      case 'frontmatter':
        const transforms = this.siteConfig.get('transforms')

        const contentField = transforms && Object.keys(transforms).find(field => {
          return transforms[field] === 'frontmatterContent'
        })

        if (!contentField) {
          return reject('NO_FRONTMATTER_CONTENT_TRANSFORM')
        }

        const content = fields[contentField]

        delete fields[contentField]

        try {
          const output = `---\n${yaml.safeDump(fields)}---\n${content}\n`

          return resolve(output)
        } catch (err) {
          return reject(err)
        }

        break

      default:
        return reject('INVALID_FORMAT')
    }
  })
}

Staticman.prototype._generatePRBody = function (fields) {
  let table = [
    ['Field', 'Content']
  ]

  Object.keys(fields).forEach(field => {
    table.push([field, fields[field]])
  })

  let message = this.siteConfig.get('pullRequestBody') + markdownTable(table)

  if (this.siteConfig.get('notifications.enabled')) {
    const notificationsPayload = {
      configPath: this.configPath,
      fields,
      options: this.options,
      parameters: this.parameters
    }

    message += `\n\n<!--staticman_notification:${JSON.stringify(notificationsPayload)}-->`
  }

  return message
}

Staticman.prototype._getConfig = function (force) {
  if (this.siteConfig && !force) return Promise.resolve(this.siteConfig)

  if (!this.configPath) return Promise.reject('NO_CONFIG_PATH')

  return this.github.readFile(this.configPath.file).then(data => {
    const config = objectPath.get(data, this.configPath.path)
    const validationErrors = this._validateConfig(config)

    if (validationErrors) {
      return Promise.reject(validationErrors)
    }

    if (config.branch !== this.parameters.branch) {
      return Promise.reject('BRANCH_MISMATCH')
    }

    return this.siteConfig
  })
}

Staticman.prototype._getNewFilePath = function (data) {
  const configFilename = this.siteConfig.get('filename')
  const filename = configFilename ? this._resolvePlaceholders(configFilename, {
    fields: data,
    options: this.options
  }) : this.uid

  const path = this._resolvePlaceholders(this.siteConfig.get('path'), {
    fields: data,
    options: this.options
  })

  const extension = this._getExtensionForFormat(this.siteConfig.get('format'))

  return `${path}/${filename}.${extension}`
}

Staticman.prototype._getExtensionForFormat = function (format) {
  switch (format.toLowerCase()) {
    case 'json':
      return 'json'

    case 'yaml':
    case 'yml':
      return 'yml'

    case 'frontmatter':
      return 'md'
  }
}

Staticman.prototype._initialiseSubscriptions = function () {
  if (!this.siteConfig.get('notifications.enabled')) return null

  // Initialise Mailgun
  const mailgun = Mailgun({
    apiKey: this.siteConfig.get('notifications.apiKey') || config.get('email.apiKey'),
    domain: this.siteConfig.get('notifications.domain') || config.get('email.domain')
  })

  // Initialise SubscriptionsManager
  const subscriptions = new SubscriptionsManager(this.parameters, this.github, mailgun)

  return subscriptions
}

Staticman.prototype._resolvePlaceholders = function (subject, baseObject) {
  const matches = subject.match(/{(.*?)}/g)

  if (!matches) return subject

  matches.forEach((match) => {
    const escapedMatch = match.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
    const property = match.slice(1, -1)

    let newText

    switch (property) {
      case '@timestamp':
        newText = new Date().getTime()

        break

      case '@id':
        newText = this.uid

        break

      default:
        newText = objectPath.get(baseObject, property) || ''
    }

    subject = subject.replace(new RegExp(escapedMatch, 'g'), newText)
  })

  return subject
}

Staticman.prototype._validateConfig = function (config) {
  if (!config) {
    return {
      code: 'MISSING_CONFIG_BLOCK'
    }
  }

  const requiredFields = [
    'allowedFields',
    'branch',
    'format',
    'path'
  ]

  let missingFields = []

  // Checking for missing required fields
  requiredFields.forEach(requiredField => {
    if (objectPath.get(config, requiredField) === undefined) {
      missingFields.push(requiredField)
    }
  })

  if (missingFields.length) {
    return {
      code: 'MISSING_CONFIG_FIELDS',
      data: missingFields
    }
  }

  // Check origin
  if (config.allowedOrigins && config.allowedOrigins.length) {
    if (this.options.origin) {
      const url = require('url').parse(this.options.origin)

      const validOrigin = config.allowedOrigins.some(origin => {
        return origin === url.hostname
      })

      if (!validOrigin) {
        return {
          code: 'INVALID_ORIGIN',
          data: null
        }
      }
    } else {
      return {
        code: 'MISSING_ORIGIN',
        data: null
      }
    }
  }

  this.siteConfig = SiteConfig(config, this.rsa)

  return null
}

Staticman.prototype._validateFields = function (fields) {
  let errors = []
  let missingRequiredFields = []
  let invalidFields = []

  Object.keys(fields).forEach(field => {
    // Check for any invalid fields
    if ((this.siteConfig.get('allowedFields').indexOf(field) === -1) && (fields[field] !== '')) {
      invalidFields.push(field)
    }

    // Trim fields
    if (typeof fields[field] === 'string') {
      fields[field] = fields[field].trim()
    }
  })

  // Check for missing required fields
  this.siteConfig.get('requiredFields').forEach(field => {
    if ((fields[field] === undefined) || (fields[field] === '')) {
      missingRequiredFields.push(field)
    }
  })

  if (missingRequiredFields.length) {
    errors.push({
      code: 'MISSING_REQUIRED_FIELDS',
      data: missingRequiredFields
    })
  }

  if (invalidFields.length) {
    errors.push({
      code: 'INVALID_FIELDS',
      data: invalidFields
    })
  }

  if (errors.length) return errors

  return null
}

Staticman.prototype.processEntry = function (fields, options) {
  this.fields = Object.assign({}, fields)
  this.options = Object.assign({}, options)

  return this._getConfig().then(config => {
    return this._checkForSpam(fields)
  }).then(fields => {
    // Validate fields
    const fieldErrors = this._validateFields(fields)

    if (fieldErrors) return Promise.reject(fieldErrors)

    // Add generated fields
    fields = this._applyGeneratedFields(fields)

    // Apply transforms
    return this._applyTransforms(fields)
  }).then(transformedFields => {
    return this._applyInternalFields(transformedFields)
  }).then(extendedFields => {
    // Create file
    return this._createFile(extendedFields)
  }).then(data => {
    const filePath = this._getNewFilePath(fields)
    const subscriptions = this._initialiseSubscriptions()
    const commitMessage = this._resolvePlaceholders(this.siteConfig.get('commitMessage'), {
      fields,
      options
    })

    // Subscribe user, if applicable
    if (subscriptions && options.parent && options.subscribe && this.fields[options.subscribe]) {
      subscriptions.set(options.parent, this.fields[options.subscribe]).catch(err => {
        console.log(err.stack || err)
      })
    }

    if (this.siteConfig.get('moderation')) {
      const newBranch = 'staticman_' + this.uid

      return this.github.writeFileAndSendPR(filePath, data, newBranch, commitMessage, this._generatePRBody(fields))
    } else if (subscriptions && options.parent) {
      subscriptions.send(options.parent, fields, options)
    }

    return this.github.writeFile(filePath, data, this.parameters.branch, commitMessage)
  }).then(result => {
    return {
      fields: fields,
      redirect: options.redirect ? options.redirect : false
    }
  })
}

Staticman.prototype.processMerge = function (fields, options) {
  this.fields = Object.assign({}, fields)
  this.options = Object.assign({}, options)

  return this._getConfig().then(config => {
    const subscriptions = this._initialiseSubscriptions()

    return subscriptions.send(options.parent, fields, options, this.siteConfig)
  })
}

Staticman.prototype.setConfigPath = function (configPath) {
  this.configPath = configPath
}

Staticman.prototype.setIp = function (ip) {
  this.ip = ip
}

Staticman.prototype.setUserAgent = function (userAgent) {
  this.userAgent = userAgent
}

module.exports = Staticman
<|endoftext|>


<commit_before>/* A bunch of time-related util functions. */

var INTERVAL = process.env.INTERVAL == "true";

function TimeUtils() {
  if (!(this instanceof TimeUtils))
    return new TimeUtils();
}

/**
 * Get the minimum update time.
 * updateAt can be undefined.
 */
TimeUtils.prototype.replaceUpdateTime = function(updateAt, newUpdateAt) {
  return (updateAt && updateAt < newUpdateAt) ? updateAt : newUpdateAt;
};

/**
 * Get the minimum update time for given variables.
 * The variables must be time variables.
 */
TimeUtils.prototype.getMinimumUpdateTime = function(variables, taCounter) {
  var minimumUpdateTime = -1;
  for(var i = 0; i < taCounter; i++) {
    var updateTime = this._getUpdateTime(variables, i);
    if(updateTime < minimumUpdateTime || minimumUpdateTime == -1) {
      minimumUpdateTime = updateTime;
    }
  }
  return minimumUpdateTime;
};

/**
 * Get the update time for given variable.
 * The variable must be a time variable.
 */
TimeUtils.prototype._getUpdateTime = function(variables, variableCount) {
  return this._parseTimeVariable(variables["?final" + variableCount]);
};

/**
 * Check if all given time variables are 'now'.
 */
TimeUtils.prototype.areAllCurrent = function(variables, current, taCounter) {
  for(var i = 0; i < taCounter; i++) {
    if(!this._isCurrent(variables, current, i)) return false;
  }
  return true;
};

/**
 * Check if given time variables (initial and final) encapsulate the current time.
 */
TimeUtils.prototype._isCurrent = function(variables, current, variableCount) {
  var initial;
  if(INTERVAL) initial = this._parseTimeVariable(variables["?initial" + variableCount]);
  var final = this._parseTimeVariable(variables["?final" + variableCount]);
  if(INTERVAL && !interval) {
    throw new Error('Could not find a valid initial time ' + "?initial" + variableCount);
  }
  if(!final) {
    throw new Error('Could not find a valid final time ' + "?final" + variableCount);
  }
  current = current || this.getTime();
  return (!INTERVAL || initial < current) && current <= final;
};

/**
 * Parse the given time variable to a timestamp.
 */
TimeUtils.prototype._parseTimeVariable = function(timeVariable) {
  var timeString = timeVariable.replace(/\^\^.*/g, "").replace(/"/g, "");
  return Date.parse(timeString);
};

/**
 * Get the current numerical time.
 */
TimeUtils.prototype.getTime = function() {
  return new Date().getTime();
};

module.exports = new TimeUtils();<commit_msg>Fix crash when using interval annotation<commit_after>/* A bunch of time-related util functions. */

var INTERVAL = process.env.INTERVAL == "true";

function TimeUtils() {
  if (!(this instanceof TimeUtils))
    return new TimeUtils();
}

/**
 * Get the minimum update time.
 * updateAt can be undefined.
 */
TimeUtils.prototype.replaceUpdateTime = function(updateAt, newUpdateAt) {
  return (updateAt && updateAt < newUpdateAt) ? updateAt : newUpdateAt;
};

/**
 * Get the minimum update time for given variables.
 * The variables must be time variables.
 */
TimeUtils.prototype.getMinimumUpdateTime = function(variables, taCounter) {
  var minimumUpdateTime = -1;
  for(var i = 0; i < taCounter; i++) {
    var updateTime = this._getUpdateTime(variables, i);
    if(updateTime < minimumUpdateTime || minimumUpdateTime == -1) {
      minimumUpdateTime = updateTime;
    }
  }
  return minimumUpdateTime;
};

/**
 * Get the update time for given variable.
 * The variable must be a time variable.
 */
TimeUtils.prototype._getUpdateTime = function(variables, variableCount) {
  return this._parseTimeVariable(variables["?final" + variableCount]);
};

/**
 * Check if all given time variables are 'now'.
 */
TimeUtils.prototype.areAllCurrent = function(variables, current, taCounter) {
  for(var i = 0; i < taCounter; i++) {
    if(!this._isCurrent(variables, current, i)) return false;
  }
  return true;
};

/**
 * Check if given time variables (initial and final) encapsulate the current time.
 */
TimeUtils.prototype._isCurrent = function(variables, current, variableCount) {
  var initial;
  if(INTERVAL) initial = this._parseTimeVariable(variables["?initial" + variableCount]);
  var final = this._parseTimeVariable(variables["?final" + variableCount]);
  if(INTERVAL && !initial) {
    throw new Error('Could not find a valid initial time ' + "?initial" + variableCount);
  }
  if(!final) {
    throw new Error('Could not find a valid final time ' + "?final" + variableCount);
  }
  current = current || this.getTime();
  return (!INTERVAL || initial < current) && current <= final;
};

/**
 * Parse the given time variable to a timestamp.
 */
TimeUtils.prototype._parseTimeVariable = function(timeVariable) {
  var timeString = timeVariable.replace(/\^\^.*/g, "").replace(/"/g, "");
  return Date.parse(timeString);
};

/**
 * Get the current numerical time.
 */
TimeUtils.prototype.getTime = function() {
  return new Date().getTime();
};

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


<commit_before>module.exports = Transport;

var C = {
  // Transport status codes
  STATUS_READY:        0,
  STATUS_DISCONNECTED: 1,
  STATUS_ERROR:        2
};

/**
 * Expose C object.
 */
Transport.C = C;

/**
 * Dependencies.
 */
var debug = require('debug')('JsSIP:Transport');
var JsSIP_C = require('./Constants');
var Parser = require('./Parser');
var UA = require('./UA');
var SIPMessage = require('./SIPMessage');
var sanityCheck = require('./sanityCheck');
// 'websocket' module uses the native WebSocket interface when bundled to run in a browser.
var W3CWebSocket = require('websocket').w3cwebsocket;

function Transport(ua, server) {
  this.ua = ua;
  this.ws = null;
  this.server = server;
  this.reconnection_attempts = 0;
  this.closed = false;
  this.connected = false;
  this.reconnectTimer = null;
  this.lastTransportError = {};

  /**
   * Options for the Node "websocket" library.
   */

  this.node_websocket_options = this.ua.configuration.node_websocket_options || {};

  // Add our User-Agent header.
  this.node_websocket_options.headers = this.node_websocket_options.headers || {};
  this.node_websocket_options.headers['User-Agent'] = JsSIP_C.USER_AGENT;
}

Transport.prototype = {

  /**
  * Connect socket.
  */
  connect: function() {
    var transport = this;

    if(this.ws && (this.ws.readyState === this.ws.OPEN || this.ws.readyState === this.ws.CONNECTING)) {
      debug('WebSocket ' + this.server.ws_uri + ' is already connected');
      return false;
    }

    if(this.ws) {
      this.ws.close();
    }

    debug('connecting to WebSocket ' + this.server.ws_uri);
    this.ua.onTransportConnecting(this,
      (this.reconnection_attempts === 0)?1:this.reconnection_attempts);

    try {
      this.ws = new W3CWebSocket(this.server.ws_uri, 'sip', this.node_websocket_options.origin, this.node_websocket_options.headers, this.node_websocket_options.requestOptions, this.node_websocket_options.clientConfig);
      this.ws.binaryType = 'arraybuffer';

      this.ws.onopen = function() {
        transport.onOpen();
      };

      this.ws.onclose = function(e) {
        transport.onClose(e);
      };

      this.ws.onmessage = function(e) {
        transport.onMessage(e);
      };

      this.ws.onerror = function(e) {
        transport.onError(e);
      };
    } catch(e) {
      debug('error connecting to WebSocket ' + this.server.ws_uri + ': ' + e);
      this.lastTransportError.code = null;
      this.lastTransportError.reason = e.message;
      this.ua.onTransportError(this);
    }
  },

  /**
  * Disconnect socket.
  */
  disconnect: function() {
    if(this.ws) {
      // Clear reconnectTimer
      clearTimeout(this.reconnectTimer);
      // TODO: should make this.reconnectTimer = null here?

      this.closed = true;
      debug('closing WebSocket ' + this.server.ws_uri);
      this.ws.close();
    }

    // TODO: Why this??
    if (this.reconnectTimer !== null) {
      clearTimeout(this.reconnectTimer);
      this.reconnectTimer = null;
      this.ua.onTransportDisconnected({
        transport: this,
        code: this.lastTransportError.code,
        reason: this.lastTransportError.reason
      });
    }
  },

  /**
   * Send a message.
   */
  send: function(msg) {
    var message = msg.toString();

    if(this.ws && this.ws.readyState === this.ws.OPEN) {
      debug('sending WebSocket message:\n\n' + message + '\n');
      this.ws.send(message);
      return true;
    } else {
      debug('unable to send message, WebSocket is not open');
      return false;
    }
  },

  // Transport Event Handlers

  onOpen: function() {
    this.connected = true;

    debug('WebSocket ' + this.server.ws_uri + ' connected');
    // Clear reconnectTimer since we are not disconnected
    if (this.reconnectTimer !== null) {
      clearTimeout(this.reconnectTimer);
      this.reconnectTimer = null;
    }
    // Reset reconnection_attempts
    this.reconnection_attempts = 0;
    // Disable closed
    this.closed = false;
    // Trigger onTransportConnected callback
    this.ua.onTransportConnected(this);
  },

  onClose: function(e) {
    var connected_before = this.connected;

    this.connected = false;
    this.lastTransportError.code = e.code;
    this.lastTransportError.reason = e.reason;
    debug('WebSocket disconnected (code: ' + e.code + (e.reason? '| reason: ' + e.reason : '') +')');

    if(e.wasClean === false) {
      debug('WebSocket abrupt disconnection');
    }
    // Transport was connected
    if (connected_before === true) {
      this.ua.onTransportClosed(this);

      // Check whether the user requested to close.
      if(!this.closed) {
        this.reConnect();
      }
    } else {
      // This is the first connection attempt
      // May be a network error (or may be UA.stop() was called)
      this.ua.onTransportError(this);
    }
  },

  onMessage: function(e) {
    var message, transaction,
      data = e.data;

    // CRLF Keep Alive response from server. Ignore it.
    if(data === '\r\n') {
      debug('received WebSocket message with CRLF Keep Alive response');
      return;
    }

    // WebSocket binary message.
    else if (typeof data !== 'string') {
      try {
        data = String.fromCharCode.apply(null, new Uint8Array(data));
      } catch(evt) {
        debug('received WebSocket binary message failed to be converted into string, message discarded');
        return;
      }

      debug('received WebSocket binary message:\n\n' + data + '\n');
    }

    // WebSocket text message.
    else {
      debug('received WebSocket text message:\n\n' + data + '\n');
    }

    message = Parser.parseMessage(data, this.ua);

    if (! message) {
      return;
    }

    if(this.ua.status === UA.C.STATUS_USER_CLOSED && message instanceof SIPMessage.IncomingRequest) {
      return;
    }

    // Do some sanity check
    if(! sanityCheck(message, this.ua, this)) {
      return;
    }

    if(message instanceof SIPMessage.IncomingRequest) {
      message.transport = this;
      this.ua.receiveRequest(message);
    } else if(message instanceof SIPMessage.IncomingResponse) {
      /* Unike stated in 18.1.2, if a response does not match
      * any transaction, it is discarded here and no passed to the core
      * in order to be discarded there.
      */
      switch(message.method) {
        case JsSIP_C.INVITE:
          transaction = this.ua.transactions.ict[message.via_branch];
          if(transaction) {
            transaction.receiveResponse(message);
          }
          break;
        case JsSIP_C.ACK:
          // Just in case ;-)
          break;
        default:
          transaction = this.ua.transactions.nict[message.via_branch];
          if(transaction) {
            transaction.receiveResponse(message);
          }
          break;
      }
    }
  },

  onError: function(e) {
    debug('WebSocket connection error: %o', e);
  },

  /**
  * Reconnection attempt logic.
  */
  reConnect: function() {
    var transport = this;

    this.reconnection_attempts += 1;

    if(this.reconnection_attempts > this.ua.configuration.ws_server_max_reconnection) {
      debug('maximum reconnection attempts for WebSocket ' + this.server.ws_uri);
      this.ua.onTransportError(this);
    } else {
      debug('trying to reconnect to WebSocket ' + this.server.ws_uri + ' (reconnection attempt ' + this.reconnection_attempts + ')');

      this.reconnectTimer = setTimeout(function() {
        transport.connect();
        transport.reconnectTimer = null;
      }, this.ua.configuration.ws_server_reconnection_timeout * 1000);
    }
  }
};
<commit_msg>Be ready for a mangled version non including Node-WebSocket.<commit_after>module.exports = Transport;

var C = {
  // Transport status codes
  STATUS_READY:        0,
  STATUS_DISCONNECTED: 1,
  STATUS_ERROR:        2
};

/**
 * Expose C object.
 */
Transport.C = C;

/**
 * Dependencies.
 */
var debug = require('debug')('JsSIP:Transport');
var JsSIP_C = require('./Constants');
var Parser = require('./Parser');
var UA = require('./UA');
var SIPMessage = require('./SIPMessage');
var sanityCheck = require('./sanityCheck');
// 'websocket' module uses the native WebSocket interface when bundled to run in a browser.
var W3CWebSocket = require('websocket').w3cwebsocket;

function Transport(ua, server) {
  this.ua = ua;
  this.ws = null;
  this.server = server;
  this.reconnection_attempts = 0;
  this.closed = false;
  this.connected = false;
  this.reconnectTimer = null;
  this.lastTransportError = {};

  /**
   * Options for the Node "websocket" library.
   */

  this.node_websocket_options = this.ua.configuration.node_websocket_options || {};

  // Add our User-Agent header.
  this.node_websocket_options.headers = this.node_websocket_options.headers || {};
  this.node_websocket_options.headers['User-Agent'] = JsSIP_C.USER_AGENT;
}

Transport.prototype = {

  /**
  * Connect socket.
  */
  connect: function() {
    var transport = this;

    if(this.ws && (this.ws.readyState === this.ws.OPEN || this.ws.readyState === this.ws.CONNECTING)) {
      debug('WebSocket ' + this.server.ws_uri + ' is already connected');
      return false;
    }

    if(this.ws) {
      this.ws.close();
    }

    debug('connecting to WebSocket ' + this.server.ws_uri);
    this.ua.onTransportConnecting(this,
      (this.reconnection_attempts === 0)?1:this.reconnection_attempts);

    try {
      // Hack in case W3CWebSocket is not the class exported by Node-WebSocket
      // (may just happen if the above `var W3CWebSocket` line is overriden by
      // `var W3CWebSocket = global.W3CWebSocket`).
      if (W3CWebSocket.length > 3) {
        this.ws = new W3CWebSocket(this.server.ws_uri, 'sip', this.node_websocket_options.origin, this.node_websocket_options.headers, this.node_websocket_options.requestOptions, this.node_websocket_options.clientConfig);
      } else {
        this.ws = new W3CWebSocket(this.server.ws_uri, 'sip');
      }

      this.ws.binaryType = 'arraybuffer';

      this.ws.onopen = function() {
        transport.onOpen();
      };

      this.ws.onclose = function(e) {
        transport.onClose(e);
      };

      this.ws.onmessage = function(e) {
        transport.onMessage(e);
      };

      this.ws.onerror = function(e) {
        transport.onError(e);
      };
    } catch(e) {
      debug('error connecting to WebSocket ' + this.server.ws_uri + ': ' + e);
      this.lastTransportError.code = null;
      this.lastTransportError.reason = e.message;
      this.ua.onTransportError(this);
    }
  },

  /**
  * Disconnect socket.
  */
  disconnect: function() {
    if(this.ws) {
      // Clear reconnectTimer
      clearTimeout(this.reconnectTimer);
      // TODO: should make this.reconnectTimer = null here?

      this.closed = true;
      debug('closing WebSocket ' + this.server.ws_uri);
      this.ws.close();
    }

    // TODO: Why this??
    if (this.reconnectTimer !== null) {
      clearTimeout(this.reconnectTimer);
      this.reconnectTimer = null;
      this.ua.onTransportDisconnected({
        transport: this,
        code: this.lastTransportError.code,
        reason: this.lastTransportError.reason
      });
    }
  },

  /**
   * Send a message.
   */
  send: function(msg) {
    var message = msg.toString();

    if(this.ws && this.ws.readyState === this.ws.OPEN) {
      debug('sending WebSocket message:\n\n' + message + '\n');
      this.ws.send(message);
      return true;
    } else {
      debug('unable to send message, WebSocket is not open');
      return false;
    }
  },

  // Transport Event Handlers

  onOpen: function() {
    this.connected = true;

    debug('WebSocket ' + this.server.ws_uri + ' connected');
    // Clear reconnectTimer since we are not disconnected
    if (this.reconnectTimer !== null) {
      clearTimeout(this.reconnectTimer);
      this.reconnectTimer = null;
    }
    // Reset reconnection_attempts
    this.reconnection_attempts = 0;
    // Disable closed
    this.closed = false;
    // Trigger onTransportConnected callback
    this.ua.onTransportConnected(this);
  },

  onClose: function(e) {
    var connected_before = this.connected;

    this.connected = false;
    this.lastTransportError.code = e.code;
    this.lastTransportError.reason = e.reason;
    debug('WebSocket disconnected (code: ' + e.code + (e.reason? '| reason: ' + e.reason : '') +')');

    if(e.wasClean === false) {
      debug('WebSocket abrupt disconnection');
    }
    // Transport was connected
    if (connected_before === true) {
      this.ua.onTransportClosed(this);

      // Check whether the user requested to close.
      if(!this.closed) {
        this.reConnect();
      }
    } else {
      // This is the first connection attempt
      // May be a network error (or may be UA.stop() was called)
      this.ua.onTransportError(this);
    }
  },

  onMessage: function(e) {
    var message, transaction,
      data = e.data;

    // CRLF Keep Alive response from server. Ignore it.
    if(data === '\r\n') {
      debug('received WebSocket message with CRLF Keep Alive response');
      return;
    }

    // WebSocket binary message.
    else if (typeof data !== 'string') {
      try {
        data = String.fromCharCode.apply(null, new Uint8Array(data));
      } catch(evt) {
        debug('received WebSocket binary message failed to be converted into string, message discarded');
        return;
      }

      debug('received WebSocket binary message:\n\n' + data + '\n');
    }

    // WebSocket text message.
    else {
      debug('received WebSocket text message:\n\n' + data + '\n');
    }

    message = Parser.parseMessage(data, this.ua);

    if (! message) {
      return;
    }

    if(this.ua.status === UA.C.STATUS_USER_CLOSED && message instanceof SIPMessage.IncomingRequest) {
      return;
    }

    // Do some sanity check
    if(! sanityCheck(message, this.ua, this)) {
      return;
    }

    if(message instanceof SIPMessage.IncomingRequest) {
      message.transport = this;
      this.ua.receiveRequest(message);
    } else if(message instanceof SIPMessage.IncomingResponse) {
      /* Unike stated in 18.1.2, if a response does not match
      * any transaction, it is discarded here and no passed to the core
      * in order to be discarded there.
      */
      switch(message.method) {
        case JsSIP_C.INVITE:
          transaction = this.ua.transactions.ict[message.via_branch];
          if(transaction) {
            transaction.receiveResponse(message);
          }
          break;
        case JsSIP_C.ACK:
          // Just in case ;-)
          break;
        default:
          transaction = this.ua.transactions.nict[message.via_branch];
          if(transaction) {
            transaction.receiveResponse(message);
          }
          break;
      }
    }
  },

  onError: function(e) {
    debug('WebSocket connection error: %o', e);
  },

  /**
  * Reconnection attempt logic.
  */
  reConnect: function() {
    var transport = this;

    this.reconnection_attempts += 1;

    if(this.reconnection_attempts > this.ua.configuration.ws_server_max_reconnection) {
      debug('maximum reconnection attempts for WebSocket ' + this.server.ws_uri);
      this.ua.onTransportError(this);
    } else {
      debug('trying to reconnect to WebSocket ' + this.server.ws_uri + ' (reconnection attempt ' + this.reconnection_attempts + ')');

      this.reconnectTimer = setTimeout(function() {
        transport.connect();
        transport.reconnectTimer = null;
      }, this.ua.configuration.ws_server_reconnection_timeout * 1000);
    }
  }
};
<|endoftext|>