<commit_before>const HIGHEST_POSSIBLE_Z_INDEX = 2147483647;

var library = [];
var counter = 0;

function checkSupported() {
  // Check for the various File API support.
  if (!(window.File && window.FileReader && window.FileList && window.Blob)) {
    throw ('The File APIs are not fully supported in this browser.');
  }
}

function createFilesElement() {
  var filesElement = document.createElement('input');
  filesElement.type = 'file';
  filesElement.name = 'files[]';
  filesElement.multiple = true;
  filesElement.style.zIndex = HIGHEST_POSSIBLE_Z_INDEX;
  filesElement.style.position = 'relative';
  filesElement.className = 'cordova-photo-library-select';
  document.body.appendChild(filesElement);
  return filesElement;
}

function removeFilesElement(filesElement) {
  filesElement.parentNode.removeChild(filesElement);
}

function getFiles(filesElement) {
  //convert from array-like to real array
  let files = Array.from(filesElement.files); // FileList object
  return files.filter(f => f.type.match('image.*'));
}

function readFileAsDataURL(file) {
  return new Promise((resolve, reject) => {
    let reader = new FileReader();
    reader.onload = (e) => {
      resolve(e.target.result);
    };
    reader.readAsDataURL(file);
  });
}

function readDataUrlAsImage(dataURL) {
  return new Promise((resolve, reject) => {
    var imageObj = new Image();
    imageObj.onload = () => {
      resolve(imageObj);
    };
    imageObj.src = dataURL;
  });
}

function files2Library(files) {
  return new Promise((resolve, reject) => {

    let filesWithDataPromises = files.map(f => {
      return new Promise((resolve, reject) => {
        readFileAsDataURL(f)
          .then(dataURL => {
            return readDataUrlAsImage(dataURL).then(image => {
              return { dataURL, image };
            });
          })
          .then(dataURLwithImage => {
            let {image} = dataURLwithImage;
            resolve({
              file: f,
              dataURL: dataURLwithImage.dataURL,
              width: image.width,
              height: image.height
            });
          });
      });
    });

    Promise.all(filesWithDataPromises)
      .then(filesWithData => {
        let result = filesWithData.map(fileWithData => {

          let {file} = fileWithData;
          let {dataURL} = fileWithData;

          let libraryItem = {
            id: `${counter}#${file.name}`,
            filename: file.name,
            nativeURL: dataURL,
            width: fileWithData.width,
            height: fileWithData.height,
            creationDate: file.lastModifiedDate, // file contains only lastModifiedDate
          };
          counter += 1;
          return libraryItem;

        });

        resolve(result);

      });

  });
}

// From here: https://gist.github.com/davoclavo/4424731
function dataURLToBlob(dataURL) {
  // convert base64 to raw binary data held in a string
  var byteString = atob(dataURL.split(',')[1]);

  // separate out the mime component
  var mimeString = dataURL.split(',')[0].split(':')[1].split(';')[0];

  // write the bytes of the string to an ArrayBuffer
  var arrayBuffer = new ArrayBuffer(byteString.length);
  var _ia = new Uint8Array(arrayBuffer);
  for (var i = 0; i < byteString.length; i++) {
    _ia[i] = byteString.charCodeAt(i);
  }

  var dataView = new DataView(arrayBuffer);
  var blob = new Blob([dataView], { type: mimeString });
  return blob;
}

module.exports = {

  getLibrary: function (success, error, [options]) {

    checkSupported();

    let filesElement = createFilesElement();

    filesElement.addEventListener('change', (evt) => {

      let files = getFiles(evt.target);
      files2Library(files).then(lib => {
        library = lib;
        removeFilesElement(filesElement);
        success(library);
      });

    }, false);

  },

  getThumbnail: function (success, error, [photoId, options]) {

    let libraryItem = library.find(li => li.id === photoId);
    if (!libraryItem) {
      error(`Photo with id ${photoId} not found in the library`);
      return;
    }

    success(dataURLToBlob(libraryItem.nativeURL));

  },

  getPhoto: function (success, error, [photoId, options]) {

    let libraryItem = library.find(li => li.id === photoId);
    if (!libraryItem) {
      error(`Photo with id ${photoId} not found in the library`);
      return;
    }

    success(dataURLToBlob(libraryItem.nativeURL));

  },

  stopCaching: function (success, error) {
    // Nothing to do
  },

  //TODO: remove this
  echo: function (success, error) {

  },

};

require('cordova/exec/proxy').add('PhotoLibrary', module.exports);
<commit_msg>some code rafactoring<commit_after>module.exports = {

  getLibrary: function (success, error, [options]) {

    checkSupported();

    let filesElement = createFilesElement();

    filesElement.addEventListener('change', (evt) => {

      let files = getFiles(evt.target);
      files2Library(files).then(lib => {
        library = lib;
        removeFilesElement(filesElement);
        success(library);
      });

    }, false);

  },

  getThumbnail: function (success, error, [photoId, options]) {

    let libraryItem = library.find(li => li.id === photoId);
    if (!libraryItem) {
      error(`Photo with id ${photoId} not found in the library`);
      return;
    }

    let {thumbnailWidth, thumbnailHeight, quality} = options;

    //TODO: resize
    success(dataURLToBlob(libraryItem.nativeURL));

  },

  getPhoto: function (success, error, [photoId, options]) {

    let libraryItem = library.find(li => li.id === photoId);
    if (!libraryItem) {
      error(`Photo with id ${photoId} not found in the library`);
      return;
    }

    success(dataURLToBlob(libraryItem.nativeURL));

  },

  stopCaching: function (success, error) {
    // Nothing to do
  },

  //TODO: remove this
  echo: function (success, error) {

  },

};

require('cordova/exec/proxy').add('PhotoLibrary', module.exports);

const HIGHEST_POSSIBLE_Z_INDEX = 2147483647;

var library = [];
var counter = 0;

function checkSupported() {
  // Check for the various File API support.
  if (!(window.File && window.FileReader && window.FileList && window.Blob)) {
    throw ('The File APIs are not fully supported in this browser.');
  }
}

function createFilesElement() {
  var filesElement = document.createElement('input');
  filesElement.type = 'file';
  filesElement.name = 'files[]';
  filesElement.multiple = true;
  filesElement.style.zIndex = HIGHEST_POSSIBLE_Z_INDEX;
  filesElement.style.position = 'relative';
  filesElement.className = 'cordova-photo-library-select';
  document.body.appendChild(filesElement);
  return filesElement;
}

function removeFilesElement(filesElement) {
  filesElement.parentNode.removeChild(filesElement);
}

function getFiles(filesElement) {
  //convert from array-like to real array
  let files = Array.from(filesElement.files); // FileList object
  return files.filter(f => f.type.match('image.*'));
}

function readFileAsDataURL(file) {
  return new Promise((resolve, reject) => {
    let reader = new FileReader();
    reader.onload = (e) => {
      resolve(e.target.result);
    };
    reader.readAsDataURL(file);
  });
}

function readDataUrlAsImage(dataURL) {
  return new Promise((resolve, reject) => {
    var imageObj = new Image();
    imageObj.onload = () => {
      resolve(imageObj);
    };
    imageObj.src = dataURL;
  });
}

function files2Library(files) {
  return new Promise((resolve, reject) => {

    let filesWithDataPromises = files.map(f => {
      return new Promise((resolve, reject) => {
        readFileAsDataURL(f)
          .then(dataURL => {
            return readDataUrlAsImage(dataURL).then(image => {
              return { dataURL, image };
            });
          })
          .then(dataURLwithImage => {
            let {image} = dataURLwithImage;
            resolve({
              file: f,
              dataURL: dataURLwithImage.dataURL,
              width: image.width,
              height: image.height
            });
          });
      });
    });

    Promise.all(filesWithDataPromises)
      .then(filesWithData => {
        let result = filesWithData.map(fileWithData => {

          let {file, dataURL} = fileWithData;

          let libraryItem = {
            id: `${counter}#${file.name}`,
            filename: file.name,
            nativeURL: dataURL,
            width: fileWithData.width,
            height: fileWithData.height,
            creationDate: file.lastModifiedDate, // file contains only lastModifiedDate
          };
          counter += 1;
          return libraryItem;

        });

        resolve(result);

      });

  });
}

// From here: https://gist.github.com/davoclavo/4424731
function dataURLToBlob(dataURL) {
  // convert base64 to raw binary data held in a string
  var byteString = atob(dataURL.split(',')[1]);

  // separate out the mime component
  var mimeString = dataURL.split(',')[0].split(':')[1].split(';')[0];

  // write the bytes of the string to an ArrayBuffer
  var arrayBuffer = new ArrayBuffer(byteString.length);
  var _ia = new Uint8Array(arrayBuffer);
  for (var i = 0; i < byteString.length; i++) {
    _ia[i] = byteString.charCodeAt(i);
  }

  var dataView = new DataView(arrayBuffer);
  var blob = new Blob([dataView], { type: mimeString });
  return blob;
}
<|endoftext|>


<commit_before>import IJ from '../ij';

export default function gaussian_filter(n, sigma){
	var cols = this.width;
	var new_img = this.clone();
	var kernel = get_gaussian_kernel(n, sigma);
	var temp = cols*n; //variable for checking the image border
	for(var p = cols*n+n; p < this.data.length - cols*n; p++){
		if(p == temp+cols-n){
			p += 2*n - 1;
		}else{
			new_img.data[p] = convolution(p, this.data, kernel);
		}
	}
}

function get_gaussian_kernel(n, sigma){
	var kernel = [];
	var sigma2 = 2*(sigma*sigma);//2*sigma^2
	var sum = 0;
	for(var y = -n; y <= n; y++){
		for(var x = -n; x <= n; x++){
			var value = -((x*x) + (y*y))/sigma2;
			value = Math.pow(Math.E, value);
			sum += value;
			kernel.push(value);
		}
	}
	for(var i = 0; i < kernel.length; i++){
		kernel[i] /= sum;
	}
	return kernel;
}

function convolution(p, data, kernel){
	var result = 0;
	var n = (int)(Math.sqrt(kernel.length) - 1)/2;
	var neighbors = get_neighbors(data, this.width, p, n);

	var j = -(kernel.length-1);
	for(var i = 0; i < kernel.length; i++){
		result = kernel[i]*neighbors[j];
		j--;
	}
	return result;
}

function get_neighbors(data, cols, p, n){
	var neighbors = [];

	for(var i = -n; i <= n; i++){
		for(var k = -n; k <= n; k++){
			neighbors.push(data[p+(i*cols)+k]);
		}
	}
	return neighbors;
}
<commit_msg>add new line<commit_after>import IJ from '../ij';

export default function gaussian_filter(n, sigma){
	var cols = this.width;
	var new_img = this.clone();
	var kernel = get_gaussian_kernel(n, sigma);
	var temp = cols*n; //variable for checking the image border
	for(var p = cols*n+n; p < this.data.length - cols*n; p++){
		if(p == temp+cols-n){
			p += 2*n - 1;
		}else{
			new_img.data[p] = convolution(p, this.data, kernel);
		}
	}
}

function get_gaussian_kernel(n, sigma){
	var kernel = [];
	var sigma2 = 2*(sigma*sigma);//2*sigma^2
	var sum = 0;
	for(var y = -n; y <= n; y++){
		for(var x = -n; x <= n; x++){
			var value = -((x*x) + (y*y))/sigma2;
			value = Math.pow(Math.E, value);
			sum += value;
			kernel.push(value);
		}
	}

	for(var i = 0; i < kernel.length; i++){
		kernel[i] /= sum;
	}
	return kernel;
}

function convolution(p, data, kernel){
	var result = 0;
	var n = (int)(Math.sqrt(kernel.length) - 1)/2;
	var neighbors = get_neighbors(data, this.width, p, n);

	var j = -(kernel.length-1);
	for(var i = 0; i < kernel.length; i++){
		result = kernel[i]*neighbors[j];
		j--;
	}
	return result;
}

function get_neighbors(data, cols, p, n){
	var neighbors = [];

	for(var i = -n; i <= n; i++){
		for(var k = -n; k <= n; k++){
			neighbors.push(data[p+(i*cols)+k]);
		}
	}
	return neighbors;
}
<|endoftext|>


<commit_before>var debug = require('debug')('mdns-packet:lib:dns:bufferconsumer');
var util = require('util');

var LABEL_POINTER = 0xc0;

var BufferConsumer = module.exports = function BufferConsumer(arg) {
  if (!(arg instanceof Buffer)) {
    debug('arg', arg);
    throw new Error('Expected instance of Buffer');
  }
  this.buffer = arg;
  this.length = this.buffer.length;
  debug('new consumer of %d bytes', this.length);
  this._offset = 0;
};

BufferConsumer.prototype.tell = function () {
  return this._offset;
};

BufferConsumer.prototype.seek = function (pos) {
  debug('seek(%d)', pos);
  if (pos < 0) {
    throw new Error('Negative pos not allowed');
  }
  if (pos > this.length) {
    debug('bad packet', this.buffer.toString('hex'));
    throw new Error(util.format('Cannot seek after EOF. %d > %d',
      pos, this.length));
  }
  this._offset = pos;
  return this;
};

BufferConsumer.prototype.slice = function (length) {
  var v;
  if (typeof length === 'undefined') {
    v = this.buffer.slice(this._offset);
    this._offset = this.length - 1;
    return v;
  }
  else {
    if ((this._offset + length) > this.length) {
      debug('Buffer owerflow. Slice beyond buffer.', {
        offset:this._offset,
        length:length,
        bufferLength: this.length
      });
      debug('so far', this);
      throw new Error('Buffer overflow');
    }
    v = this.buffer.slice(this._offset, this._offset + length);
    this._offset += length;
    return v;
  }
};

BufferConsumer.prototype.isEOF = function () {
  return this._offset >= this.length;
};

BufferConsumer.prototype.byte = function () {
  this._offset += 1;
  return this.buffer.readUInt8(this._offset - 1);
};

BufferConsumer.prototype.short = function () {
  this._offset += 2;
  return this.buffer.readUInt16BE(this._offset - 2);
};

BufferConsumer.prototype.long = function () {
  this._offset += 4;
  return this.buffer.readUInt32BE(this._offset - 4);
};

BufferConsumer.prototype.string = function (encoding, length) {
  var end;
  var ret;

  if (length === undefined) {
    end = this.buffer.length;
  }
  else {
    end = this.tell() + length;
  }

  if (!encoding) {
    encoding = 'utf8';
  }
  ret = this.buffer.toString(encoding, this._offset, end);
  debug('got a %s character string:', length, ret);
  this.seek(end);
  return ret;
};

/**
 * Consumes a DNS name, which will either finish with a NULL byte or a suffix
 * reference (i.e., 0xc0 <ref>).
 */
BufferConsumer.prototype.name = function (join, endAt) {
  debug('.name(join:%s, endAt:%s)', join, endAt);
  if (typeof join === 'undefined') { join = true; }
  var parts = [];
  var ret;
  var len;
  var pos;
  var end;
  var comp = false;
  len = this.byte();
  debug('name initial len', len);
  if (len === 0) {
    parts.push('');
  }
  while (len !== 0) {
    if ((len & LABEL_POINTER) === LABEL_POINTER) {
      debug('has label');
      len -= LABEL_POINTER;
      len = len << 8;
      pos = len + this.byte();
      if (!comp) {
        end = this.tell();
      }
      this.seek(pos);
      len = this.byte();
      comp = true;
      continue;
    }
    debug('no label');

    // Otherwise, consume a string!
    var v = this.string('ascii', len);
    if (v.length > 0) {
      parts.push(v);
    }

    if (endAt && this.tell() >= endAt) {
      debug('leaving at', endAt);
      break;
    }
    len = this.byte();
    debug('got len', len);
  }
  if (!comp) {
    end = this.tell();
  }
  debug('ended');
  this.seek(end);
  if (join) {
    ret = parts.join('.');
  } else {
    ret = parts;
  }
  debug('ret', ret);
  return ret;
};

<commit_msg>Use utf8 instead of ascii for string encoding.<commit_after>var debug = require('debug')('mdns-packet:lib:dns:bufferconsumer');
var util = require('util');

var LABEL_POINTER = 0xc0;

var BufferConsumer = module.exports = function BufferConsumer(arg) {
  if (!(arg instanceof Buffer)) {
    debug('arg', arg);
    throw new Error('Expected instance of Buffer');
  }
  this.buffer = arg;
  this.length = this.buffer.length;
  debug('new consumer of %d bytes', this.length);
  this._offset = 0;
};

BufferConsumer.prototype.tell = function () {
  return this._offset;
};

BufferConsumer.prototype.seek = function (pos) {
  debug('seek(%d)', pos);
  if (pos < 0) {
    throw new Error('Negative pos not allowed');
  }
  if (pos > this.length) {
    debug('bad packet', this.buffer.toString('hex'));
    throw new Error(util.format('Cannot seek after EOF. %d > %d',
      pos, this.length));
  }
  this._offset = pos;
  return this;
};

BufferConsumer.prototype.slice = function (length) {
  var v;
  if (typeof length === 'undefined') {
    v = this.buffer.slice(this._offset);
    this._offset = this.length - 1;
    return v;
  }
  else {
    if ((this._offset + length) > this.length) {
      debug('Buffer owerflow. Slice beyond buffer.', {
        offset:this._offset,
        length:length,
        bufferLength: this.length
      });
      debug('so far', this);
      throw new Error('Buffer overflow');
    }
    v = this.buffer.slice(this._offset, this._offset + length);
    this._offset += length;
    return v;
  }
};

BufferConsumer.prototype.isEOF = function () {
  return this._offset >= this.length;
};

BufferConsumer.prototype.byte = function () {
  this._offset += 1;
  return this.buffer.readUInt8(this._offset - 1);
};

BufferConsumer.prototype.short = function () {
  this._offset += 2;
  return this.buffer.readUInt16BE(this._offset - 2);
};

BufferConsumer.prototype.long = function () {
  this._offset += 4;
  return this.buffer.readUInt32BE(this._offset - 4);
};

BufferConsumer.prototype.string = function (encoding, length) {
  var end;
  var ret;

  if (length === undefined) {
    end = this.buffer.length;
  }
  else {
    end = this.tell() + length;
  }

  if (!encoding) {
    encoding = 'utf8';
  }
  ret = this.buffer.toString(encoding, this._offset, end);
  debug('got a %s character string:', length, ret);
  this.seek(end);
  return ret;
};

/**
 * Consumes a DNS name, which will either finish with a NULL byte or a suffix
 * reference (i.e., 0xc0 <ref>).
 */
BufferConsumer.prototype.name = function (join, endAt) {
  debug('.name(join:%s, endAt:%s)', join, endAt);
  if (typeof join === 'undefined') { join = true; }
  var parts = [];
  var ret;
  var len;
  var pos;
  var end;
  var comp = false;
  len = this.byte();
  debug('name initial len', len);
  if (len === 0) {
    parts.push('');
  }
  while (len !== 0) {
    if ((len & LABEL_POINTER) === LABEL_POINTER) {
      debug('has label');
      len -= LABEL_POINTER;
      len = len << 8;
      pos = len + this.byte();
      if (!comp) {
        end = this.tell();
      }
      this.seek(pos);
      len = this.byte();
      comp = true;
      continue;
    }
    debug('no label');

    // Otherwise, consume a string!
    var v = this.string('utf8', len);
    if (v.length > 0) {
      parts.push(v);
    }

    if (endAt && this.tell() >= endAt) {
      debug('leaving at', endAt);
      break;
    }
    len = this.byte();
    debug('got len', len);
  }
  if (!comp) {
    end = this.tell();
  }
  debug('ended');
  this.seek(end);
  if (join) {
    ret = parts.join('.');
  } else {
    ret = parts;
  }
  debug('ret', ret);
  return ret;
};

<|endoftext|>


<commit_before>import Component from 'react-pure-render/component';
import React, { PropTypes } from 'react';
import Todo from './Todo.react';
import todosMessages from '../../common/todos/todosMessages';
import { FormattedMessage } from 'react-intl';
import { connect } from 'react-redux';
import { deleteTodo, toggleTodoCompleted } from '../../common/todos/actions';

// Container component.
export class Todos extends Component {

  static propTypes = {
    deleteTodo: PropTypes.func.isRequired,
    todos: PropTypes.object.isRequired,
    filter: PropTypes.object.isRequired
  };

  render() {
    const { deleteTodo, todos, toggleTodoCompleted, filter } = this.props;

    if (!todos.size) {
      return
<FormattedMessage {...todosMessages.empty} />
;
    }

    var selectedFilter = filter.get('selectedFilter');

    const list = todos.toList().sortBy(item => item.createdAt).reverse().filter(item => selectedFilter === null? item : item.status === selectedFilter);

    return (

        {
          list.map(todo =>
          {
            if (todo.status !== 'delete' || selectedFilter === 'delete')
            {
              return (
                <Todo
                  deleteTodo={deleteTodo}
                  todo={todo}
                  toggleTodoCompleted={toggleTodoCompleted}
                  key={todo.id}
                  selectedFilter={selectedFilter}
                />
              );
            }
          }
        )
      }

    );
  }

}

export default connect(state => ({
  todos: state.todos.map,
  filter: state.filter.map
}), { deleteTodo, toggleTodoCompleted })(Todos);
<commit_msg>fixed the issue for showing the deleted items when we select all<commit_after>import Component from 'react-pure-render/component';
import React, { PropTypes } from 'react';
import Todo from './Todo.react';
import todosMessages from '../../common/todos/todosMessages';
import { FormattedMessage } from 'react-intl';
import { connect } from 'react-redux';
import { deleteTodo, toggleTodoCompleted } from '../../common/todos/actions';

// Container component.
export class Todos extends Component {

  static propTypes = {
    deleteTodo: PropTypes.func.isRequired,
    todos: PropTypes.object.isRequired,
    filter: PropTypes.object.isRequired
  };

  render() {
    const { deleteTodo, todos, toggleTodoCompleted, filter } = this.props;

    if (!todos.size) {
      return
<FormattedMessage {...todosMessages.empty} />
;
    }

    var selectedFilter = filter.get('selectedFilter');

    const list = todos.toList().sortBy(item => item.createdAt).reverse().filter(item => selectedFilter === null? item : item.status === selectedFilter);

    return (

        {
          list.map(todo =>
          {
            if (todo.status !== 'delete' || selectedFilter === 'delete'  || selectedFilter === null)
            {
              return (
                <Todo
                  deleteTodo={deleteTodo}
                  todo={todo}
                  toggleTodoCompleted={toggleTodoCompleted}
                  key={todo.id}
                  selectedFilter={selectedFilter}
                />
              );
            }
          }
        )
      }

    );
  }

}

export default connect(state => ({
  todos: state.todos.map,
  filter: state.filter.map
}), { deleteTodo, toggleTodoCompleted })(Todos);
<|endoftext|>


<commit_before>var srcFolder = "../../../src/node_modules/";
var wd = require(srcFolder + "wd");
var async = require(srcFolder + "async");

var config = {
	  host: "ondemand.saucelabs.com"
  , port: 80
  , username: process.env.SAUCE_USER
  , accessKey: process.env.SAUCE_KEY
}

var allTestsPassed = true;

var sauceTestWorker = async.queue(function (testSettings, callback) {
  var browser = wd.remote(config.host, config.port, config.username, config.accessKey);
  var browserChain = browser.chain();
  var name = process.env.GIT_HASH + " - " + testSettings.browserName + " " + testSettings.version + ", " + testSettings.platform;
  testSettings.name = name;
  console.log("Remote sauce test '" + name + "' started!");

  browserChain.init(testSettings).get("http://localhost:9001/tests/frontend/", function(){
    //tear down the test excecution
    var stopSauce = function(success){
      getStatusInterval && clearInterval(getStatusInterval);
      clearTimeout(timeout);

      browserChain.quit();

      if(!success){
        allTestsPassed = false;
      }

      var testResult = knownConsoleText.replace(/\[red\]/g,'\x1B[31m').replace(/\[yellow\]/g,'\x1B[33m')
                       .replace(/\[green\]/g,'\x1B[32m').replace(/\[clear\]/g, '\x1B[39m');
      testResult = testResult.split("\n").map(function(line){
        var newLine = "[" + testSettings.browserName + (testSettings.version === "" ? '' : (" " + testSettings.version)) + "] ";
      }).join("\n");

      console.log(testResult);
      console.log("Remote sauce test '" + name + "' finished!");

      callback();
    }

    //timeout for the case the test hangs
    var timeout = setTimeout(function(){
      stopSauce(false);
    }, 60000 * 10);

    var knownConsoleText = "";
    var getStatusInterval = setInterval(function(){
      browserChain.eval("$('#console').text()", function(err, consoleText){
        if(!consoleText || err){
          return;
        }
        knownConsoleText = consoleText;

        if(knownConsoleText.indexOf("FINISHED") > 0){
          var success = knownConsoleText.indexOf("FAILED") === -1;
          stopSauce(success);
        }
      });
    }, 5000);
  });
}, 5); //run 2 tests in parrallel

// Firefox
sauceTestWorker.push({
    'platform'       : 'Linux'
  , 'browserName'    : 'firefox'
  , 'version'        : ''
});

// Chrome
sauceTestWorker.push({
    'platform'       : 'Linux'
  , 'browserName'    : 'googlechrome'
  , 'version'        : ''
});

// IE 8
sauceTestWorker.push({
    'platform'       : 'Windows 2003'
  , 'browserName'    : 'iexplore'
  , 'version'        : '8'
});

// IE 9
sauceTestWorker.push({
    'platform'       : 'Windows 2008'
  , 'browserName'    : 'iexplore'
  , 'version'        : '9'
});

// IE 10
sauceTestWorker.push({
    'platform'       : 'Windows 2012'
  , 'browserName'    : 'iexplore'
  , 'version'        : '10'
});

sauceTestWorker.drain = function() {
  setTimeout(function(){
    process.exit(allTestsPassed ? 0 : 1);
  }, 3000);
}<commit_msg>I'm so stupid...<commit_after>var srcFolder = "../../../src/node_modules/";
var wd = require(srcFolder + "wd");
var async = require(srcFolder + "async");

var config = {
	  host: "ondemand.saucelabs.com"
  , port: 80
  , username: process.env.SAUCE_USER
  , accessKey: process.env.SAUCE_KEY
}

var allTestsPassed = true;

var sauceTestWorker = async.queue(function (testSettings, callback) {
  var browser = wd.remote(config.host, config.port, config.username, config.accessKey);
  var browserChain = browser.chain();
  var name = process.env.GIT_HASH + " - " + testSettings.browserName + " " + testSettings.version + ", " + testSettings.platform;
  testSettings.name = name;
  console.log("Remote sauce test '" + name + "' started!");

  browserChain.init(testSettings).get("http://localhost:9001/tests/frontend/", function(){
    //tear down the test excecution
    var stopSauce = function(success){
      getStatusInterval && clearInterval(getStatusInterval);
      clearTimeout(timeout);

      browserChain.quit();

      if(!success){
        allTestsPassed = false;
      }

      var testResult = knownConsoleText.replace(/\[red\]/g,'\x1B[31m').replace(/\[yellow\]/g,'\x1B[33m')
                       .replace(/\[green\]/g,'\x1B[32m').replace(/\[clear\]/g, '\x1B[39m');
      testResult = testResult.split("\n").map(function(line){
        return "[" + testSettings.browserName + (testSettings.version === "" ? '' : (" " + testSettings.version)) + "] " + line;
      }).join("\n");

      console.log(testResult);
      console.log("Remote sauce test '" + name + "' finished!");

      callback();
    }

    //timeout for the case the test hangs
    var timeout = setTimeout(function(){
      stopSauce(false);
    }, 60000 * 10);

    var knownConsoleText = "";
    var getStatusInterval = setInterval(function(){
      browserChain.eval("$('#console').text()", function(err, consoleText){
        if(!consoleText || err){
          return;
        }
        knownConsoleText = consoleText;

        if(knownConsoleText.indexOf("FINISHED") > 0){
          var success = knownConsoleText.indexOf("FAILED") === -1;
          stopSauce(success);
        }
      });
    }, 5000);
  });
}, 5); //run 2 tests in parrallel

// Firefox
sauceTestWorker.push({
    'platform'       : 'Linux'
  , 'browserName'    : 'firefox'
  , 'version'        : ''
});

// Chrome
sauceTestWorker.push({
    'platform'       : 'Linux'
  , 'browserName'    : 'googlechrome'
  , 'version'        : ''
});

// IE 8
sauceTestWorker.push({
    'platform'       : 'Windows 2003'
  , 'browserName'    : 'iexplore'
  , 'version'        : '8'
});

// IE 9
sauceTestWorker.push({
    'platform'       : 'Windows 2008'
  , 'browserName'    : 'iexplore'
  , 'version'        : '9'
});

// IE 10
sauceTestWorker.push({
    'platform'       : 'Windows 2012'
  , 'browserName'    : 'iexplore'
  , 'version'        : '10'
});

sauceTestWorker.drain = function() {
  setTimeout(function(){
    process.exit(allTestsPassed ? 0 : 1);
  }, 3000);
}<|endoftext|>


<commit_before>"use strict";

var env = require('../lib/env');
var Spec = require('../lib/Spec');
var Op = require('../lib/Op');
var Host = require('../lib/Host');
var Model = require('../lib/Model');
var SyncSet = require('../lib/Set');
var Storage = require('../lib/Storage');
var levelup = require('levelup');
var memdown = require('memdown');

env.multihost = true;
env.debug = console.log;
env.logs.op = true;

MetricLengthField.metricRe = /(\d+)(mm|cm|m|km)?/g;  // "1m and 10cm"
MetricLengthField.scale = { m:1, cm:0.01, mm:0.001, km:1000 };
MetricLengthField.scaleArray = ['km','m','cm','mm'];

function MetricLengthField (value) {
    // convert mm cm m km
    if (typeof(value)==='number') {
        this.meters = value;
    } else {
        value = value.toString();
        this.meters=0;
        var m=[], scale=MetricLengthField.scale;
        MetricLengthField.metricRe.lastIndex = 0;
        while (m=MetricLengthField.metricRe.exec(value)) {
            var unit = m[2] ? scale[m[2]] : 1;
            this.meters += parseInt(m[1]) * unit;
        }
    }
}
MetricLengthField.prototype.add = function () {

};
// .pojo() invokes (entry.toJSON&&entry.toJSON()) || entry.toString()
MetricLengthField.prototype.toString = function () {
    var m = this.meters, ret='', scar = MetricLengthField.scaleArray;
    for(var i=0; i<scar.length; i++) {
        var unit = scar[i],
            scale= MetricLengthField.scale[unit];
        var wholeUnits = Math.floor(m/scale);
        if (wholeUnits>=1) {
            ret += wholeUnits + unit;
        }
        m -= wholeUnits*scale;
    }
    return ret;
};
MetricLengthField.prototype.toPojo = MetricLengthField.prototype.toString;

// Duck is our core testing class :)
var Duck = Model.extend('Duck',{
    defaults: {
        age: 0,
        height: {type:MetricLengthField,value:'3cm'},
        mood: 'neutral'
    },
    // Simply a regular convenience method
    canDrink: function () {
        return this.age >= 18; // Russia
    },
    validate: function (spec,val) {
        return ''; // :|
        //return spec.op()!=='set' || !('height' in val);
        //throw new Error("can't set height, may only grow");
    }
    /*$$grow: function (spec,by,src) {
        this.height = this.height.add(by);
    }*/
});

var Nest = SyncSet.extend('Nest',{
    entryType: Duck
});

var db2 = levelup('222', { db: memdown });
var storage2 = new Storage(db2);
var host2 = env.localhost= new Host('gritzko',0,storage2);
host2.availableUplinks = function () {return [storage2]; };

/*test('2._ empty Syncable', function () {
    ok(true); // TODO
    // var syn = new Syncable(host2);
    // equal(syn._version,'!0')
    // deepEqual(syn.toPojo(),{});
    // deepEqual(syn.toPojo(true),{
    //    _version,'!0', _id: syn._id, _host: host2
    //});
});*/

asyncTest('2.a basic listener func', function (test) {
    console.warn(QUnit.config.current.testName);
    env.localhost= host2;
    env.logs.op = true;
    expect(7);
    // global objects must be pre-created
    host2.deliver(new Op('/Duck#hueyA!0time.state', '{}', host2.id));
    // construct an object with an id provided; it will try to fetch
    // previously saved state for the id (which is none)
    var huey = host2.get('/Duck#hueyA');
    //ok(!huey._version); //storage is a?sync
    // listen to a field
    huey.on4('set:age',function lsfn2a (ev){
        equal(ev.value.age,1); // 1
        equal(ev.spec.op(),'set'); // 2
        equal(ev.spec.toString(),'/Duck#hueyA!'+ev.spec.version()+'.set'); // 3
        var version = ev.spec.token('!');
        equal(version.ext,'gritzko'); // 4
        huey.off4('set:age',lsfn2a);
        //equal(huey._lstn.length,2); // only the uplink remains (and the comma)
    });
    huey.on4('set', function (ev) {
        deepEqual(ev.value, {age: 1}); // 5
        deepEqual(ev.old_value, {age: 0}); // 6
    });
    huey.on4('set:age', function (ev) {
        equal(ev.value.age, 1); // 7
        env.logs.op = false;
        start();
    });
    huey.on4('set:height', function (ev) {
        ok(false);
    });
    huey.onInit4(function init2a () {
        huey.set({age:1});
    });
});

test('2.b create-by-id', function (test) {
    console.warn(QUnit.config.current.testName);
    env.localhost= host2;
    // there is 1:1 spec-to-object correspondence;
    // an attempt of creating a second copy of a model object
    // will throw an exception
    var dewey1 = new Duck('dewey');
    // that's we resort to descendant() doing find-or-create
    var dewey2 = host2.get('/Duck#dewey');
    // must be the same object
    strictEqual(dewey1,dewey2);
    equal(dewey1.spec().type(),'Duck');
});

asyncTest('2.c version ids', function (test) {
    console.warn(QUnit.config.current.testName);
    env.localhost= host2;
    host2.deliver(new Op('/Duck#louie!0time.state', '{}', host2.id));
    var louie = new Duck('louie');
    louie.onInit4(function(){
        var ts1 = host2.time();
        louie.set({age:3});
        var ts2 = host2.time();
        ok(ts2>ts1);
        var vv = new Spec.Map(louie._version);
        ok(vv.covers(ts1));
        ok(!vv.covers(ts2));
        console.log(ts1,vv.toString(),ts2);
        start();
    });
});

test('2.d pojos',function (test) {
    console.warn(QUnit.config.current.testName);
    env.localhost= host2;
    var dewey = new Duck({age:0});
    var json = dewey.toPojo();
    var duckJSON = {
        mood: "neutral",
        age: 0,
        height: '3cm'
    };
    deepEqual(json,duckJSON);
});

asyncTest('2.e reactions',function (test) {
    console.warn(QUnit.config.current.testName);
    env.localhost= host2;
    var huey = new Duck();
    expect(2);
    var handle = Duck.addReaction('set', function reactionFn(spec,val) {
        console.log('yupee im growing');
        equal(val,'{"age":1}');
        start();
    });
    //var version = host2.time(), sp = '!'+version+'.set';
    host2.deliver(new Op(huey.newEventSpec('set'), '{"age":1}', host2.id));
    Duck.removeReaction(handle);
    equal(Duck.prototype._reactions['set'].length,0); // no house cleaning :)
});

// TODO $$event listener/reaction (Model.on: 'key' > .set && key check)

test('2.f once',function (test) {
    console.warn(QUnit.config.current.testName);
    env.localhost= host2;
    var huey = new Duck();
    expect(1);
    huey.once4('set:age',function onceAgeCb(ev){
        equal(ev.value.age,4);
    });
    huey.set({age:4});
    huey.set({age:5});
});

asyncTest('2.g custom field type',function (test) {
    console.warn(QUnit.config.current.testName);
    env.localhost= host2;
    host2.deliver(new Op('/Duck#huey!0time.state', '{}', host2.id));
    var huey = host2.get('/Duck#huey');
    huey.onInit4(function(){ // FIXME onLoad
        huey.set({height:'32cm'});
        ok(Math.abs(huey.height.meters-0.32)<0.0001);
        var vid = host2.time();
        host2.deliver(new Op('/Duck#huey!'+vid+'.set','{"height":"35cm"}', host2.id));
        huey.on4('set', function(){
            ok(Math.abs(huey.height.meters-0.35)<0.0001);
            start();
        });
    });
});

test('2.h state init',function (test) {
    console.warn(QUnit.config.current.testName);
    env.localhost= host2;
    var factoryBorn = new Duck({age:0,height:'4cm'});
    ok(Math.abs(factoryBorn.height.meters-0.04)<0.0001);
    equal(factoryBorn.age,0);
});

test('2.i batched set',function (test) {
    console.warn(QUnit.config.current.testName);
    env.localhost= host2;
    var nameless = new Duck();
    nameless.set({
        age:1,
        height: '60cm'
    });
    ok(Math.abs(nameless.height.meters-0.6)<0.0001);
    equal(nameless.age,1);
    ok(!nameless.canDrink());

});

/* FIXME:  spec - to - (order)
test('2.j basic Set functions (string index)',function (test) {
    console.warn(QUnit.config.current.testName);
    env.localhost= host2;
    var hueyClone = new Duck({age:2});
    var deweyClone = new Duck({age:1});
    var louieClone = new Duck({age:3});
    var clones = new Nest();
    clones.addObject(louieClone);
    clones.addObject(hueyClone);
    clones.addObject(deweyClone);
    var sibs = clones.list(function(a,b){return a.age - b.age;});
    strictEqual(sibs[0],deweyClone);
    strictEqual(sibs[1],hueyClone);
    strictEqual(sibs[2],louieClone);
    var change = {};
    change[hueyClone.spec()] = 0;
    clones.change(change);
    var sibs2 = clones.list(function(a,b){return a.age - b.age;});
    equal(sibs2.length,2);
    strictEqual(sibs2[0],deweyClone);
    strictEqual(sibs2[1],louieClone);
});*/

test('2.l partial order', function (test) {
    env.localhost= host2;
    var duckling = new Duck();
    duckling.deliver(new Spec(duckling.spec()+'!1time+user2.set'),'{"height":"2cm"}');
    duckling.deliver(new Spec(duckling.spec()+'!0time+user1.set'),'{"height":"3cm"}');
    equal(duckling.height.toString(), '2cm');
});

/*asyncTest('2.m init push', function (test) {
    env.localhost= host2;
    var scrooge = new Duck({age:105});
    scrooge.onInit4(function check() {
        equal(scrooge._version.substr(1), scrooge._id);
        var json = storage2.states[scrooge.spec()];
        ok(json);
        var state = JSON.parse(json);
        equal(state.age,105);
        start();
    });
});*/

/*test('2.n local listeners for on/off', function () {
    console.warn(QUnit.config.current.testName);
    expect(4);
    env.localhost= host2;
    var duck = new Duck();
    duck.on('.on', function (spec, val) {
        console.log('triggered by itself, on(init) and host2.on below');
        equal(spec.op(), 'on');
    });
    duck.onInit4(function gotit(){
        console.log('inevitable');
        ok(duck._version);
    });
    duck.on('.reon', function (spec, val) {
        console.log("must NOT get triggered if the storage is sync");
        equal(spec.op(), 'reon');
    });
    host2.on('/Host#gritzko.on', function (spec, val) {
        console.log('this listener is triggered by itself');
        equal(spec.op(), 'on');
    });
});*/

/*test('2.o event relay', function () {
    console.warn(QUnit.config.current.testName);
    var hueyClone = new Duck({age:2}, host2);
    var deweyClone = new Duck({age:1}, host2);
    var louieClone = new Duck({age:3}, host2);
    var clones = new Nest('',host2);
    clones.addObject(louieClone);
    clones.addObject(hueyClone);
    clones.onObjectEvent(function(spec,val){
        ok('age' in val);
    });
    expect(3);
    hueyClone.set({age:3});
    louieClone.set({age:4});
    clones.addObject(deweyClone);
    deweyClone.set({age:2});
});*/

/*  TODO
 * test('2.m on/off sub', function (test) {
    env.localhost= host2
    var duckling = new Duck();

    expect(2);
    duckling.on('on',function(spec){
        ok(spec.op(),'on');
    });
    duckling.on('set',function(spec){
        equal(spec.op(),'set');
    });
    duckling.set({age:1});

});*/
<commit_msg>refactor(0.4): 02 tests OK<commit_after>"use strict";

var env = require('../lib/env');
var Spec = require('../lib/Spec');
var Op = require('../lib/Op');
var Host = require('../lib/Host');
var Model = require('../lib/Model');
var SyncSet = require('../lib/Set');
var Storage = require('../lib/Storage');
var levelup = require('levelup');
var memdown = require('memdown');

env.multihost = true;
env.debug = console.log;
env.logs.op = true;

MetricLengthField.metricRe = /(\d+)(mm|cm|m|km)?/g;  // "1m and 10cm"
MetricLengthField.scale = { m:1, cm:0.01, mm:0.001, km:1000 };
MetricLengthField.scaleArray = ['km','m','cm','mm'];

function MetricLengthField (value) {
    // convert mm cm m km
    if (typeof(value)==='number') {
        this.meters = value;
    } else {
        value = value.toString();
        this.meters=0;
        var m=[], scale=MetricLengthField.scale;
        MetricLengthField.metricRe.lastIndex = 0;
        while (m=MetricLengthField.metricRe.exec(value)) {
            var unit = m[2] ? scale[m[2]] : 1;
            this.meters += parseInt(m[1]) * unit;
        }
    }
}
MetricLengthField.prototype.add = function () {

};
// .pojo() invokes (entry.toJSON&&entry.toJSON()) || entry.toString()
MetricLengthField.prototype.toString = function () {
    var m = this.meters, ret='', scar = MetricLengthField.scaleArray;
    for(var i=0; i<scar.length; i++) {
        var unit = scar[i],
            scale= MetricLengthField.scale[unit];
        var wholeUnits = Math.floor(m/scale);
        if (wholeUnits>=1) {
            ret += wholeUnits + unit;
        }
        m -= wholeUnits*scale;
    }
    return ret;
};
MetricLengthField.prototype.toPojo = MetricLengthField.prototype.toString;

// Duck is our core testing class :)
var Duck = Model.extend('Duck',{
    defaults: {
        age: 0,
        height: {type:MetricLengthField,value:'3cm'},
        mood: 'neutral'
    },
    // Simply a regular convenience method
    canDrink: function () {
        return this.age >= 18; // Russia
    },
    validate: function (spec,val) {
        return ''; // :|
        //return spec.op()!=='set' || !('height' in val);
        //throw new Error("can't set height, may only grow");
    }
    /*$$grow: function (spec,by,src) {
        this.height = this.height.add(by);
    }*/
});

var Nest = SyncSet.extend('Nest',{
    entryType: Duck
});

var db2 = levelup('222', { db: memdown });
var storage2 = new Storage(db2);
var host2 = env.localhost= new Host('gritzko',0,storage2);
host2.availableUplinks = function () {return [storage2]; };

/*test('2._ empty Syncable', function () {
    ok(true); // TODO
    // var syn = new Syncable(host2);
    // equal(syn._version,'!0')
    // deepEqual(syn.toPojo(),{});
    // deepEqual(syn.toPojo(true),{
    //    _version,'!0', _id: syn._id, _host: host2
    //});
});*/

asyncTest('2.a basic listener func', function (test) {
    console.warn(QUnit.config.current.testName);
    env.localhost= host2;
    env.logs.op = true;
    expect(7);
    // global objects must be pre-created
    host2.deliver(new Op('/Duck#hueyA!0time.state', '{}', host2.id));
    // construct an object with an id provided; it will try to fetch
    // previously saved state for the id (which is none)
    var huey = host2.get('/Duck#hueyA');
    //ok(!huey._version); //storage is a?sync
    // listen to a field
    huey.on4('set:age',function lsfn2a (ev){
        equal(ev.value.age,1); // 1
        equal(ev.spec.op(),'set'); // 2
        equal(ev.spec.toString(),'/Duck#hueyA!'+ev.spec.version()+'.set'); // 3
        var version = ev.spec.token('!');
        equal(version.ext,'gritzko'); // 4
        huey.off4('set:age',lsfn2a);
        //equal(huey._lstn.length,2); // only the uplink remains (and the comma)
    });
    huey.on4('set', function (ev) {
        deepEqual(ev.value, {age: 1}); // 5
        deepEqual(ev.old_value, {age: 0}); // 6
    });
    huey.on4('set:age', function (ev) {
        equal(ev.value.age, 1); // 7
        env.logs.op = false;
        start();
    });
    huey.on4('set:height', function (ev) {
        ok(false);
    });
    huey.onInit4(function init2a () {
        huey.set({age:1});
    });
});

test('2.b create-by-id', function (test) {
    console.warn(QUnit.config.current.testName);
    env.localhost= host2;
    // there is 1:1 spec-to-object correspondence;
    // an attempt of creating a second copy of a model object
    // will throw an exception
    var dewey1 = new Duck('dewey');
    // that's we resort to descendant() doing find-or-create
    var dewey2 = host2.get('/Duck#dewey');
    // must be the same object
    strictEqual(dewey1,dewey2);
    equal(dewey1.spec().type(),'Duck');
});

asyncTest('2.c version ids', function (test) {
    console.warn(QUnit.config.current.testName);
    env.localhost= host2;
    host2.deliver(new Op('/Duck#louie!0time.state', '{}', host2.id));
    var louie = new Duck('louie');
    louie.onInit4(function(){
        var ts1 = host2.time();
        louie.set({age:3});
        var ts2 = host2.time();
        ok(ts2>ts1);
        var vv = new Spec.Map(louie._version);
        ok(vv.covers(ts1));
        ok(!vv.covers(ts2));
        console.log(ts1,vv.toString(),ts2);
        start();
    });
});

test('2.d pojos',function (test) {
    console.warn(QUnit.config.current.testName);
    env.localhost= host2;
    var dewey = new Duck({age:0});
    var json = dewey.toPojo();
    var duckJSON = {
        mood: "neutral",
        age: 0,
        height: '3cm'
    };
    deepEqual(json,duckJSON);
});

asyncTest('2.e reactions',function (test) {
    console.warn(QUnit.config.current.testName);
    env.localhost= host2;
    host2.deliver( new Op('/Duck#huey2!0time.state', '{}', host2.id) );
    var huey = new Duck("huey2");
    expect(2);
    var handle = Duck.addReaction('set', function reactionFn(spec,val) {
        console.log('yupee im growing');
        equal(val,'{"age":1}');
        start();
    });
    //var version = host2.time(), sp = '!'+version+'.set';
    //host2.deliver(new Op(huey.newEventSpec('set'), '{"age":1}', host2.id));

    huey.onInit4(function(){
        huey.set({age: 1});
        Duck.removeReaction(handle);
        equal(Duck.prototype._reactions['set'].length,0); // no house cleaning :)
    });
});

// TODO $$event listener/reaction (Model.on: 'key' > .set && key check)

test('2.f once',function (test) {
    console.warn(QUnit.config.current.testName);
    env.localhost= host2;
    var huey = new Duck();
    expect(1);
    huey.once4('set:age',function onceAgeCb(ev){
        equal(ev.value.age,4);
    });
    huey.set({age:4});
    huey.set({age:5});
});

asyncTest('2.g custom field type',function (test) {
    console.warn(QUnit.config.current.testName);
    env.localhost= host2;
    host2.deliver(new Op('/Duck#huey!0time.state', '{}', host2.id));
    var huey = host2.get('/Duck#huey');
    huey.onInit4(function(){ // FIXME onLoad
        huey.set({height:'32cm'});
        ok(Math.abs(huey.height.meters-0.32)<0.0001);
        var vid = host2.time();
        host2.deliver(new Op('/Duck#huey!'+vid+'.set','{"height":"35cm"}', host2.id));
        huey.on4('set', function(){
            ok(Math.abs(huey.height.meters-0.35)<0.0001);
            start();
        });
    });
});

test('2.h state init',function (test) {
    console.warn(QUnit.config.current.testName);
    env.localhost= host2;
    var factoryBorn = new Duck({age:0,height:'4cm'});
    ok(Math.abs(factoryBorn.height.meters-0.04)<0.0001);
    equal(factoryBorn.age,0);
});

test('2.i batched set',function (test) {
    console.warn(QUnit.config.current.testName);
    env.localhost= host2;
    var nameless = new Duck();
    nameless.set({
        age:1,
        height: '60cm'
    });
    ok(Math.abs(nameless.height.meters-0.6)<0.0001);
    equal(nameless.age,1);
    ok(!nameless.canDrink());

});

/* FIXME:  spec - to - (order)
test('2.j basic Set functions (string index)',function (test) {
    console.warn(QUnit.config.current.testName);
    env.localhost= host2;
    var hueyClone = new Duck({age:2});
    var deweyClone = new Duck({age:1});
    var louieClone = new Duck({age:3});
    var clones = new Nest();
    clones.addObject(louieClone);
    clones.addObject(hueyClone);
    clones.addObject(deweyClone);
    var sibs = clones.list(function(a,b){return a.age - b.age;});
    strictEqual(sibs[0],deweyClone);
    strictEqual(sibs[1],hueyClone);
    strictEqual(sibs[2],louieClone);
    var change = {};
    change[hueyClone.spec()] = 0;
    clones.change(change);
    var sibs2 = clones.list(function(a,b){return a.age - b.age;});
    equal(sibs2.length,2);
    strictEqual(sibs2[0],deweyClone);
    strictEqual(sibs2[1],louieClone);
});*/

test('2.l partial order', function (test) {
    env.localhost= host2;
    var duckling = new Duck();
    duckling.deliver( new Op(
            duckling.spec()+'!1time+user2.set',
            '{"height":"2cm"}',
            host2.id ));
    duckling.deliver( new Op(
            duckling.spec()+'!0time+user1.set',
            '{"height":"3cm"}',
            host2.id ));
    equal(duckling.height.toString(), '2cm');
});

/*asyncTest('2.m init push', function (test) {
    env.localhost= host2;
    var scrooge = new Duck({age:105});
    scrooge.onInit4(function check() {
        equal(scrooge._version.substr(1), scrooge._id);
        var json = storage2.states[scrooge.spec()];
        ok(json);
        var state = JSON.parse(json);
        equal(state.age,105);
        start();
    });
});*/

/*test('2.n local listeners for on/off', function () {
    console.warn(QUnit.config.current.testName);
    expect(4);
    env.localhost= host2;
    var duck = new Duck();
    duck.on('.on', function (spec, val) {
        console.log('triggered by itself, on(init) and host2.on below');
        equal(spec.op(), 'on');
    });
    duck.onInit4(function gotit(){
        console.log('inevitable');
        ok(duck._version);
    });
    duck.on('.reon', function (spec, val) {
        console.log("must NOT get triggered if the storage is sync");
        equal(spec.op(), 'reon');
    });
    host2.on('/Host#gritzko.on', function (spec, val) {
        console.log('this listener is triggered by itself');
        equal(spec.op(), 'on');
    });
});*/

/*test('2.o event relay', function () {
    console.warn(QUnit.config.current.testName);
    var hueyClone = new Duck({age:2}, host2);
    var deweyClone = new Duck({age:1}, host2);
    var louieClone = new Duck({age:3}, host2);
    var clones = new Nest('',host2);
    clones.addObject(louieClone);
    clones.addObject(hueyClone);
    clones.onObjectEvent(function(spec,val){
        ok('age' in val);
    });
    expect(3);
    hueyClone.set({age:3});
    louieClone.set({age:4});
    clones.addObject(deweyClone);
    deweyClone.set({age:2});
});*/

/*  TODO
 * test('2.m on/off sub', function (test) {
    env.localhost= host2
    var duckling = new Duck();

    expect(2);
    duckling.on('on',function(spec){
        ok(spec.op(),'on');
    });
    duckling.on('set',function(spec){
        equal(spec.op(),'set');
    });
    duckling.set({age:1});

});*/
<|endoftext|>


<commit_before>'use babel';
'use strict';

import fs from 'fs';
import path from 'path';
import EventEmitter from 'events';
import { CompositeDisposable } from 'atom';
import { GAMES, GAME_UNKNOWN, GAME_SKYRIM, ERROR_MATCH, loadConfigFile, validateGameCompiler } from './util';

export default class PapyrusBuildProvider extends EventEmitter {
	constructor(cwd) {
		super();

		// Initialise all the things
		this.cwd = cwd;
		this.game = GAME_UNKNOWN;
		this.configFile = null;
		this.projectFile = null;
		this.disposables = new CompositeDisposable();
		this.fileWatchers = [];

		// Add listeners for game compiler settings to refresh the build targets
		GAMES.forEach((game, index, array) => {
			if(index === 0) return;
			this.disposables.add(atom.config.onDidChange('build-papyrus.' + game.slug + 'CompilerPath', (newValue) => {
				if(this.game === index && this.validateGameCompiler(false)) this.emit('refresh');
			}));
		});

		// Listen for the default game changing for projects
		this.disposables.add(atom.config.onDidChange('build-papyrus.defaultGame', (newValue) => {
			if(this.projectFile) this.emit('refresh');
		}));
	}

	destructor() {
		this.disposables.dispose();
		this.closeFileWatchers();
	}

	getNiceName() {
		return 'Papyrus';
	}

	isEligible() {
		this.configFile = null;
		this.projectFile = null;
		this.closeFileWatchers();

		// Search for .papyrus.json and Papyrus project files
		const files = fs.readdirSync(this.cwd);
		for(const fileName of files) {
			const filePath = path.join(this.cwd, fileName);
			if(fs.statSync(filePath).isFile()) {
				const baseName = path.basename(fileName);
				if(!this.configFile && (baseName === '.build-papyrus.json' || baseName === '.build-papyrus.cson' || baseName === '.build-papyrus.yml')) {
					this.configFile = filePath;
					this.fileWatchers.push(fs.watch(this.configFile, () => this.emit('refresh')));
				} else if(!this.projectFile && path.extname(fileName).toLowerCase() === '.ppj') {
					this.projectFile = filePath;
				}
			}
		}

		this.game = GAME_UNKNOWN;
		if(this.projectFile || this.configFile) return true;
		return false;
	}

	settings() {
		return new Promise((resolve, reject) => {
			if(this.configFile) this.config = loadConfigFile(this.configFile);
			if(this.config) {
				if(!this.projectFile && !this.config.game && !this.config.compiler) return reject(new Error('Either "game" or "compiler" must be specified in the Papyrus config file.'));

				// Get the game from the config
				if(this.config.game) {
					this.config.game = this.config.game.toLowerCase();
					this.game = GAMES.findIndex(game => game.slug === this.config.game);
					if(this.game === -1) {
						this.game = GAME_UNKNOWN;
						return reject(new Error('Invalid "game" specified in the Papyrus config file. Must be one of "skyrim" or "fallout4".'));
					}
				}

				// Get the default game for projects
				if(this.game === GAME_UNKNOWN && this.projectFile) {
					if(!this.setGameFromDefault()) return reject(new Error('Invalid default game in build-papyrus settings'));
				}

				// If the game is still unknown or the compiler setting is set, validate the custom compiler
				if(this.game === GAME_UNKNOWN || this.config.compiler) {
					try {
						if(!this.config.compiler || !fs.statSync(this.config.compiler).isFile()) {
							return reject(new Error('"compiler" must be specified and a valid path to a file in the Papyrus config file since "game" isn\'t specified.'));
						}
					} catch(e) {
						return reject(new Error('"compiler" must be a valid path to a file in the Papyrus config file.'));
					}
				}
			} else {
				this.config = {};
				if(this.projectFile && !this.setGameFromDefault()) return reject(new Error('Invalid default game in build-papyrus settings.'));
			}

			if(this.game === GAME_UNKNOWN || this.validateGameCompiler()) {
				const buildConfigs = [];

				// Add the project file build configurations
				if(this.projectFile && this.game !== GAME_SKYRIM) {
					buildConfigs.push(this.makeBuildConfig('Papyrus default (Project file)', [ this.projectFile ]));
					buildConfigs.push(this.makeBuildConfig('Papyrus release (Project file)', [ this.projectFile, '-release' ]));
					buildConfigs.push(this.makeBuildConfig('Papyrus final release (Project file)', [ this.projectFile, '-release', '-final' ]));
				}

				// Add the config file build configuration
				try {
					if(this.isConfigBuildable()) {
						const args = [
							'{FILE_ACTIVE}',
							'-import=' + this.config.imports.join(';'),
							'-output=' + (this.config.output ? this.config.output : '.'),
							'-flags=' + (this.game === GAME_UNKNOWN || this.config.flags ? this.config.flags : GAMES[this.game].flags)
						];
						if(typeof this.config.optimize === 'undefined' || this.config.optimize) args.push('-optimize');
						if(this.config.release) args.push('-release');
						if(this.config.final) args.push('-final');

						buildConfigs.push(this.makeBuildConfig('Papyrus default (Configuration file)', args));
						if(this.game !== GAME_SKYRIM) {
							buildConfigs.push(this.makeBuildConfig('Papyrus release (Configuration file)', args.concat(['-release'])));
							buildConfigs.push(this.makeBuildConfig('Papyrus final release (Configuration file)', args.concat(['-release', '-final'])));
						}
					}
				} catch(e) {
					if(buildConfigs.length === 0) return reject(e);
				}

				return resolve(buildConfigs);
			} else {
				return reject(new Error('Invalid ' + GAMES[this.game].title + ' compiler path.'));
			}
		});
	}

	makeBuildConfig(name, args) {
		return {
			name: name,
			exec: this.game === GAME_UNKNOWN || this.config.compiler ? this.config.compiler : atom.config.get('build-papyrus.' + GAMES[this.game].slug + 'CompilerPath'),
			args: args,
			cwd: this.cwd,
			sh: false,
			errorMatch: ERROR_MATCH
		};
	}

	isConfigBuildable() {
		if(!this.config.game && !this.config.compiler) throw new Error('Either "game" or "compiler" must be specified in the Papyrus config file.');
		if(!Array.isArray(this.config.imports)) throw new Error('"imports" must be specified as an array in the Papyrus config file.');
		if(this.config.output && !fs.statSync(this.config.output).isDirectory()) throw new Error('"output" must be a valid directory in the Papyrus config file.');
		if(this.game === GAME_UNKNOWN && !this.config.flags) throw new Error('"flags" must be specified in the Papyrus config file since "game" isn\'t specified.');
		return true;
	}

	validateGameCompiler(showNotification = true) {
		return validateGameCompiler(this.game, showNotification);
	}

	setGameFromDefault() {
		const defaultGame = atom.config.get('build-papyrus.defaultGame');
		this.game = GAMES.findIndex(obj => obj.slug === defaultGame);
		if(this.game === -1) {
			this.game = GAME_UNKNOWN;
			return false;
		}
		return true;
	}

	closeFileWatchers() {
		this.fileWatchers.forEach((watcher, index, array) => {
			watcher.close();
			delete array[index];
		});
	}
}
<commit_msg>Added colons to the build target names<commit_after>'use babel';
'use strict';

import fs from 'fs';
import path from 'path';
import EventEmitter from 'events';
import { CompositeDisposable } from 'atom';
import { GAMES, GAME_UNKNOWN, GAME_SKYRIM, ERROR_MATCH, loadConfigFile, validateGameCompiler } from './util';

export default class PapyrusBuildProvider extends EventEmitter {
	constructor(cwd) {
		super();

		// Initialise all the things
		this.cwd = cwd;
		this.game = GAME_UNKNOWN;
		this.configFile = null;
		this.projectFile = null;
		this.disposables = new CompositeDisposable();
		this.fileWatchers = [];

		// Add listeners for game compiler settings to refresh the build targets
		GAMES.forEach((game, index, array) => {
			if(index === 0) return;
			this.disposables.add(atom.config.onDidChange('build-papyrus.' + game.slug + 'CompilerPath', (newValue) => {
				if(this.game === index && this.validateGameCompiler(false)) this.emit('refresh');
			}));
		});

		// Listen for the default game changing for projects
		this.disposables.add(atom.config.onDidChange('build-papyrus.defaultGame', (newValue) => {
			if(this.projectFile) this.emit('refresh');
		}));
	}

	destructor() {
		this.disposables.dispose();
		this.closeFileWatchers();
	}

	getNiceName() {
		return 'Papyrus';
	}

	isEligible() {
		this.configFile = null;
		this.projectFile = null;
		this.closeFileWatchers();

		// Search for .papyrus.json and Papyrus project files
		const files = fs.readdirSync(this.cwd);
		for(const fileName of files) {
			const filePath = path.join(this.cwd, fileName);
			if(fs.statSync(filePath).isFile()) {
				const baseName = path.basename(fileName);
				if(!this.configFile && (baseName === '.build-papyrus.json' || baseName === '.build-papyrus.cson' || baseName === '.build-papyrus.yml')) {
					this.configFile = filePath;
					this.fileWatchers.push(fs.watch(this.configFile, () => this.emit('refresh')));
				} else if(!this.projectFile && path.extname(fileName).toLowerCase() === '.ppj') {
					this.projectFile = filePath;
				}
			}
		}

		this.game = GAME_UNKNOWN;
		if(this.projectFile || this.configFile) return true;
		return false;
	}

	settings() {
		return new Promise((resolve, reject) => {
			if(this.configFile) this.config = loadConfigFile(this.configFile);
			if(this.config) {
				if(!this.projectFile && !this.config.game && !this.config.compiler) return reject(new Error('Either "game" or "compiler" must be specified in the Papyrus config file.'));

				// Get the game from the config
				if(this.config.game) {
					this.config.game = this.config.game.toLowerCase();
					this.game = GAMES.findIndex(game => game.slug === this.config.game);
					if(this.game === -1) {
						this.game = GAME_UNKNOWN;
						return reject(new Error('Invalid "game" specified in the Papyrus config file. Must be one of "skyrim" or "fallout4".'));
					}
				}

				// Get the default game for projects
				if(this.game === GAME_UNKNOWN && this.projectFile) {
					if(!this.setGameFromDefault()) return reject(new Error('Invalid default game in build-papyrus settings'));
				}

				// If the game is still unknown or the compiler setting is set, validate the custom compiler
				if(this.game === GAME_UNKNOWN || this.config.compiler) {
					try {
						if(!this.config.compiler || !fs.statSync(this.config.compiler).isFile()) {
							return reject(new Error('"compiler" must be specified and a valid path to a file in the Papyrus config file since "game" isn\'t specified.'));
						}
					} catch(e) {
						return reject(new Error('"compiler" must be a valid path to a file in the Papyrus config file.'));
					}
				}
			} else {
				this.config = {};
				if(this.projectFile && !this.setGameFromDefault()) return reject(new Error('Invalid default game in build-papyrus settings.'));
			}

			if(this.game === GAME_UNKNOWN || this.validateGameCompiler()) {
				const buildConfigs = [];

				// Add the project file build configurations
				if(this.projectFile && this.game !== GAME_SKYRIM) {
					buildConfigs.push(this.makeBuildConfig('Papyrus: default (Project file)', [ this.projectFile ]));
					buildConfigs.push(this.makeBuildConfig('Papyrus: release (Project file)', [ this.projectFile, '-release' ]));
					buildConfigs.push(this.makeBuildConfig('Papyrus: final release (Project file)', [ this.projectFile, '-release', '-final' ]));
				}

				// Add the config file build configuration
				try {
					if(this.isConfigBuildable()) {
						const args = [
							'{FILE_ACTIVE}',
							'-import=' + this.config.imports.join(';'),
							'-output=' + (this.config.output ? this.config.output : '.'),
							'-flags=' + (this.game === GAME_UNKNOWN || this.config.flags ? this.config.flags : GAMES[this.game].flags)
						];
						if(typeof this.config.optimize === 'undefined' || this.config.optimize) args.push('-optimize');
						if(this.config.release) args.push('-release');
						if(this.config.final) args.push('-final');

						buildConfigs.push(this.makeBuildConfig('Papyrus: default (Configuration file)', args));
						if(this.game !== GAME_SKYRIM) {
							buildConfigs.push(this.makeBuildConfig('Papyrus: release (Configuration file)', args.concat(['-release'])));
							buildConfigs.push(this.makeBuildConfig('Papyrus: final release (Configuration file)', args.concat(['-release', '-final'])));
						}
					}
				} catch(e) {
					if(buildConfigs.length === 0) return reject(e);
				}

				return resolve(buildConfigs);
			} else {
				return reject(new Error('Invalid ' + GAMES[this.game].title + ' compiler path.'));
			}
		});
	}

	makeBuildConfig(name, args) {
		return {
			name: name,
			exec: this.game === GAME_UNKNOWN || this.config.compiler ? this.config.compiler : atom.config.get('build-papyrus.' + GAMES[this.game].slug + 'CompilerPath'),
			args: args,
			cwd: this.cwd,
			sh: false,
			errorMatch: ERROR_MATCH
		};
	}

	isConfigBuildable() {
		if(!this.config.game && !this.config.compiler) throw new Error('Either "game" or "compiler" must be specified in the Papyrus config file.');
		if(!Array.isArray(this.config.imports)) throw new Error('"imports" must be specified as an array in the Papyrus config file.');
		if(this.config.output && !fs.statSync(this.config.output).isDirectory()) throw new Error('"output" must be a valid directory in the Papyrus config file.');
		if(this.game === GAME_UNKNOWN && !this.config.flags) throw new Error('"flags" must be specified in the Papyrus config file since "game" isn\'t specified.');
		return true;
	}

	validateGameCompiler(showNotification = true) {
		return validateGameCompiler(this.game, showNotification);
	}

	setGameFromDefault() {
		const defaultGame = atom.config.get('build-papyrus.defaultGame');
		this.game = GAMES.findIndex(obj => obj.slug === defaultGame);
		if(this.game === -1) {
			this.game = GAME_UNKNOWN;
			return false;
		}
		return true;
	}

	closeFileWatchers() {
		this.fileWatchers.forEach((watcher, index, array) => {
			watcher.close();
			delete array[index];
		});
	}
}
<|endoftext|>


<commit_before>/* eslint-disable max-len */
exports.extensions = {
  supported: [
    { icon: 'actionscript', extensions: ['as'] },
    { icon: 'angular', extensions: [] },
    { icon: 'apache', extensions: ['htaccess', 'htpasswd'] },
    { icon: 'applescript', extensions: ['app'] },
    { icon: 'asp', extensions: ['asp'] },
    { icon: 'autohotkey', extensions: ['ahk'] },
    { icon: 'babel', extensions: ['babelrc'] },
    { icon: 'binary', extensions: ['bin', 'o', 'a', 'exe', 'obj', 'lib', 'dll', 'pyc'] }, // http://www.file-extensions.org/filetype/extension/name/binary-files
    { icon: 'blade', extensions: ['.blade.php'], special: 'php' },
    { icon: 'bower', extensions: ['bowerrc'] },
    { icon: 'bower', extensions: ['bower'], special: 'json' },
    { icon: 'c', extensions: ['c'] },
    { icon: 'cheader', extensions: ['h'] },
    { icon: 'c++', extensions: ['cpp', 'hpp', 'cc', 'cxx'] },
    { icon: 'cake', extensions: ['cake'] },
    { icon: 'cfm', extensions: ['cfm', 'cfc', 'lucee'] },
    { icon: 'clojure', extensions: ['clojure', 'cjm', 'clj', 'cljs', 'cljc', 'edn'] },
    { icon: 'coffeescript', extensions: ['coffee'] },
    { icon: 'config', extensions: ['env', 'ini', 'makefile'] },
    { icon: 'compass', extensions: [] },
    { icon: 'cs', extensions: ['cs'] },
    { icon: 'cshtml', extensions: ['cshtml'] },
    { icon: 'css', extensions: ['css'] },
    { icon: 'csslint', extensions: ['csslintrc'] },
    { icon: 'cucumber', extensions: ['feature'] },
    { icon: 'dlang', extensions: ['d'] },
    { icon: 'docker', extensions: ['dockerfile'] },
    { icon: 'editorconfig', extensions: ['editorconfig'] },
    { icon: 'elixir', extensions: ['ex', 'exs', 'eex'] },
    { icon: 'elm', extensions: ['elm'] },
    { icon: 'erb', extensions: ['rhtml', 'erb'] },
    { icon: 'erlang', extensions: ['erl', 'hrl', 'emakefile', 'emakerfile'] },
    { icon: 'eslint', extensions: ['eslintrc', 'eslintignore'] },
    { icon: 'eslint', extensions: ['.eslintrc.js'], special: 'js' },
    { icon: 'eslint', extensions: ['.eslintrc.json'], special: 'json' },
    { icon: 'eslint', extensions: ['.eslintrc.yaml'], special: 'yaml' },
    { icon: 'eslint', extensions: ['.eslintrc.yml'], special: 'yml' },
    { icon: 'favicon', extensions: ['favicon'], special: 'ico' },
    { icon: 'font', extensions: ['woff', 'woff2', 'ttf', 'otf', 'eot', 'pfa', 'pfb', 'sfd'] },
    { icon: 'fsharp', extensions: ['fs', 'fsx', 'fsi'] },
    { icon: 'git', extensions: ['gitattributes', 'gitignore', 'gitmodules'] },
    { icon: 'go', extensions: ['go'] },
    { icon: 'gradle', extensions: ['gradle'] },
    { icon: 'graphviz', extensions: [] },
    { icon: 'groovy', extensions: [] },
    { icon: 'gruntfile', extensions: ['gruntfile'], special: 'js' },
    { icon: 'gulpfile', extensions: ['gulpfile'], special: 'js' },
    { icon: 'haml', extensions: ['haml'] },
    { icon: 'handlebars', extensions: ['hbs', 'handlebars'] },
    { icon: 'haskell', extensions: ['has', 'hs', 'lhs', 'lit', 'gf'] },
    { icon: 'haxe', extensions: ['hxml'] },
    { icon: 'html', extensions: ['htm', 'html'] },
    { icon: 'image', extensions: ['jpeg', 'jpg', 'gif', 'png', 'bmp'] },
    { icon: 'ionic', extensions: ['ionic'], special: 'project' },
    { icon: 'jade', extensions: ['jade', 'pug'] },
    { icon: 'java', extensions: ['java'] },
    { icon: 'js', extensions: ['js'] },
    { icon: 'jsp', extensions: ['jsp'] },
    { icon: 'julia', extensions: ['jl'] },
    { icon: 'log', extensions: ['log'] },
    { icon: 'less', extensions: ['less'] },
    { icon: 'license', extensions: ['license'] },
    { icon: 'lisp', extensions: ['bil'] },
    { icon: 'lsl', extensions: ['lsl'] },
    { icon: 'lua', extensions: ['lua'] },
    { icon: 'markdown', extensions: ['md'] },
    { icon: 'marko', extensions: ['marko'] },
    { icon: 'markojs', extensions: ['.marko.js'], special: 'js' },
    { icon: 'markup', extensions: [] },
    { icon: 'matlab', extensions: ['m', 'fig', 'mat', 'mex', 'mexn', 'mexrs6', 'mn', 'mum', 'mx', 'mx3', 'rwd', 'slx', 'slddc', 'smv', 'tikz', 'xvc', 'xvc'] },
    { icon: 'mustache', extensions: ['mustache', 'mst'] },
    { icon: 'nim', extensions: ['nim', 'nims', 'cfg'] },
    { icon: 'node', extensions: ['json'] },
    { icon: 'node2', extensions: ['nvmrc'] },
    { icon: 'npm', extensions: ['npmignore'] },
    { icon: 'npm', extensions: ['package'], special: 'json' },
    { icon: 'nunjucks', extensions: ['njk', 'nunjucks', 'nunjs', 'nunj', 'njs', 'nj'] },
    { icon: 'ocaml', extensions: ['cma', 'cmi', 'ml', 'mly', 'ocamlmakefile'] },
    { icon: 'perl', extensions: ['perl'] },
    { icon: 'php', extensions: ['php', 'php1', 'php2', 'php3', 'php4', 'php5', 'php6', 'phps', 'phpsa', 'phpt'] },
    { icon: 'procfile', extensions: ['procfile'] },
    { icon: 'powershell', extensions: ['ps1', 'psm1', 'psd1'] },
    { icon: 'puppet', extensions: ['epp'] },
    { icon: 'python', extensions: ['py'] },
    { icon: 'r', extensions: ['r'] },
    { icon: 'rails', extensions: [] },
    { icon: 'reactjs', extensions: ['jsx'] },
    { icon: 'reactts', extensions: ['tsx'] },
    { icon: 'riot', extensions: ['tag'] },
    { icon: 'robotframework', extensions: ['robot'] },
    { icon: 'ruby', extensions: ['rb', 'gemfile'] },
    { icon: 'ruby', extensions: ['gemfile'], special: 'lock' },
    { icon: 'rust', extensions: ['rs'] },
    { icon: 'sass', extensions: ['sass'] },
    { icon: 'scala', extensions: ['scala'] },
    { icon: 'scss', extensions: ['scss'] },
    { icon: 'settings', extensions: [] },
    { icon: 'shell', extensions: ['bat', 'sh', 'cmd', 'bash', 'zsh', 'fish'] },
    { icon: 'slim', extensions: [] },
    { icon: 'source', extensions: [] },
    { icon: 'sql', extensions: ['sql'] },
    { icon: 'smarty', extensions: ['tpl', 'swig'] },
    { icon: 'stylelint', extensions: ['stylelintrc'] },
    { icon: 'stylelint', extensions: ['stylelint.config'], special: 'js' },
    { icon: 'stylus', extensions: ['styl'] },
    { icon: 'svg', extensions: ['svg'] },
    { icon: 'swift', extensions: ['swift'] },
    { icon: 'tcl', extensions: ['tcl'] },
    { icon: 'tex', extensions: ['texi'] },
    { icon: 'text', extensions: ['txt'] },
    { icon: 'textile', extensions: ['textile'] },
    { icon: 'todo', extensions: ['todo'] },
    { icon: 'twig', extensions: ['twig'] },
    { icon: 'typescript', extensions: ['ts'] },
    { icon: 'typescriptdef', extensions: ['.d.ts'], special: 'ts' },
    { icon: 'vbhtml', extensions: ['vbhtml'] },
    { icon: 'vue', extensions: ['vue'] },
    { icon: 'vscode', extensions: ['vscodeignore', 'launch', 'jsconfig', 'tsconfig'], special: 'json' },
    { icon: 'xml', extensions: ['xml', 'axml', 'xaml'] },
    { icon: 'yaml', extensions: ['yml', 'yaml'] },
    { icon: 'zip', extensions: ['zip', 'rar', '7z', 'tar', 'gz', 'bzip2', 'xz', 'bz2'] }
  ],
  parse: function () {
    var s = this.replace(/\./g, '_');
    if ((/^\d/).test(s)) return 'n' + s;
    return s;
  }
};
<commit_msg>Update supportedExtensions.js<commit_after>/* eslint-disable max-len */
exports.extensions = {
  supported: [
    { icon: 'actionscript', extensions: ['as'] },
    { icon: 'angular', extensions: [] },
    { icon: 'apache', extensions: ['htaccess', 'htpasswd'] },
    { icon: 'applescript', extensions: ['app'] },
    { icon: 'asp', extensions: ['asp'] },
    { icon: 'autohotkey', extensions: ['ahk'] },
    { icon: 'babel', extensions: ['babelrc'] },
    { icon: 'binary', extensions: ['bin', 'o', 'a', 'exe', 'obj', 'lib', 'dll', 'pyc'] }, // http://www.file-extensions.org/filetype/extension/name/binary-files
    { icon: 'blade', extensions: ['.blade.php'], special: 'php' },
    { icon: 'bower', extensions: ['bowerrc'] },
    { icon: 'bower', extensions: ['bower'], special: 'json' },
    { icon: 'c', extensions: ['c'] },
    { icon: 'cheader', extensions: ['h'] },
    { icon: 'c++', extensions: ['cpp', 'hpp', 'cc', 'cxx'] },
    { icon: 'cake', extensions: ['cake'] },
    { icon: 'cfm', extensions: ['cfm', 'cfc', 'lucee'] },
    { icon: 'clojure', extensions: ['clojure', 'cjm', 'clj', 'cljs', 'cljc', 'edn'] },
    { icon: 'coffeescript', extensions: ['coffee'] },
    { icon: 'config', extensions: ['env', 'ini', 'makefile'] },
    { icon: 'compass', extensions: [] },
    { icon: 'cs', extensions: ['cs'] },
    { icon: 'cshtml', extensions: ['cshtml'] },
    { icon: 'css', extensions: ['css'] },
    { icon: 'csslint', extensions: ['csslintrc'] },
    { icon: 'cucumber', extensions: ['feature'] },
    { icon: 'dlang', extensions: ['d'] },
    { icon: 'docker', extensions: ['dockerfile'] },
    { icon: 'editorconfig', extensions: ['editorconfig'] },
    { icon: 'elixir', extensions: ['ex', 'exs', 'eex'] },
    { icon: 'elm', extensions: ['elm'] },
    { icon: 'erb', extensions: ['rhtml', 'erb'] },
    { icon: 'erlang', extensions: ['erl', 'hrl', 'emakefile', 'emakerfile'] },
    { icon: 'eslint', extensions: ['eslintrc', 'eslintignore'] },
    { icon: 'eslint', extensions: ['.eslintrc.js'], special: 'js' },
    { icon: 'eslint', extensions: ['.eslintrc.json'], special: 'json' },
    { icon: 'eslint', extensions: ['.eslintrc.yaml'], special: 'yaml' },
    { icon: 'eslint', extensions: ['.eslintrc.yml'], special: 'yml' },
    { icon: 'favicon', extensions: ['favicon'], special: 'ico' },
    { icon: 'font', extensions: ['woff', 'woff2', 'ttf', 'otf', 'eot', 'pfa', 'pfb', 'sfd'] },
    { icon: 'fsharp', extensions: ['fs', 'fsx', 'fsi'] },
    { icon: 'git', extensions: ['gitattributes', 'gitignore', 'gitmodules'] },
    { icon: 'go', extensions: ['go'] },
    { icon: 'gradle', extensions: ['gradle'] },
    { icon: 'graphviz', extensions: [] },
    { icon: 'groovy', extensions: [] },
    { icon: 'gruntfile', extensions: ['gruntfile'], special: 'js' },
    { icon: 'gulpfile', extensions: ['gulpfile'], special: 'js' },
    { icon: 'haml', extensions: ['haml'] },
    { icon: 'handlebars', extensions: ['hbs', 'handlebars'] },
    { icon: 'haskell', extensions: ['has', 'hs', 'lhs', 'lit', 'gf'] },
    { icon: 'haxe', extensions: ['hxml'] },
    { icon: 'html', extensions: ['htm', 'html'] },
    { icon: 'image', extensions: ['jpeg', 'jpg', 'gif', 'png', 'bmp'] },
    { icon: 'ionic', extensions: ['ionic'], special: 'project' },
    { icon: 'jade', extensions: ['jade', 'pug'] },
    { icon: 'java', extensions: ['java'] },
    { icon: 'js', extensions: ['js'] },
    { icon: 'jsp', extensions: ['jsp'] },
    { icon: 'julia', extensions: ['jl'] },
    { icon: 'log', extensions: ['log'] },
    { icon: 'less', extensions: ['less'] },
    { icon: 'license', extensions: ['license'] },
    { icon: 'lisp', extensions: ['bil'] },
    { icon: 'lsl', extensions: ['lsl'] },
    { icon: 'lua', extensions: ['lua'] },
    { icon: 'markdown', extensions: ['md'] },
    { icon: 'marko', extensions: ['marko'] },
    { icon: 'markojs', extensions: ['.marko.js'], special: 'js' },
    { icon: 'markup', extensions: [] },
    { icon: 'matlab', extensions: ['m', 'fig', 'mat', 'mex', 'mexn', 'mexrs6', 'mn', 'mum', 'mx', 'mx3', 'rwd', 'slx', 'slddc', 'smv', 'tikz', 'xvc', 'xvc'] },
    { icon: 'mustache', extensions: ['mustache', 'mst'] },
    { icon: 'nim', extensions: ['nim', 'nims', 'cfg'] },
    { icon: 'node', extensions: ['json'] },
    { icon: 'node2', extensions: ['nvmrc'] },
    { icon: 'npm', extensions: ['npmignore'] },
    { icon: 'npm', extensions: ['package'], special: 'json' },
    { icon: 'nunjucks', extensions: ['njk', 'nunjucks', 'nunjs', 'nunj', 'njs', 'nj'] },
    { icon: 'ocaml', extensions: ['cma', 'cmi', 'ml', 'mly', 'ocamlmakefile'] },
    { icon: 'perl', extensions: ['perl'] },
    { icon: 'php', extensions: ['php', 'php1', 'php2', 'php3', 'php4', 'php5', 'php6', 'phps', 'phpsa', 'phpt'] },
    { icon: 'procfile', extensions: ['procfile'] },
    { icon: 'powershell', extensions: ['ps1', 'psm1', 'psd1'] },
    { icon: 'puppet', extensions: ['epp'] },
    { icon: 'python', extensions: ['py'] },
    { icon: 'r', extensions: ['r'] },
    { icon: 'rails', extensions: [] },
    { icon: 'reactjs', extensions: ['jsx'] },
    { icon: 'reactts', extensions: ['tsx'] },
    { icon: 'riot', extensions: ['tag'] },
    { icon: 'robotframework', extensions: ['robot'] },
    { icon: 'ruby', extensions: ['rb', 'gemfile'] },
    { icon: 'ruby', extensions: ['gemfile'], special: 'lock' },
    { icon: 'rust', extensions: ['rs'] },
    { icon: 'sass', extensions: ['sass'] },
    { icon: 'scala', extensions: ['scala'] },
    { icon: 'scss', extensions: ['scss'] },
    { icon: 'settings', extensions: [] },
    { icon: 'shell', extensions: ['bat', 'sh', 'cmd', 'bash', 'zsh', 'fish'] },
    { icon: 'slim', extensions: [] },
    { icon: 'source', extensions: [] },
    { icon: 'sql', extensions: ['sql'] },
    { icon: 'smarty', extensions: ['tpl', 'swig'] },
    { icon: 'stylelint', extensions: ['stylelintrc'] },
    { icon: 'stylelint', extensions: ['stylelint.config'], special: 'js' },
    { icon: 'stylus', extensions: ['styl'] },
    { icon: 'svg', extensions: ['svg'] },
    { icon: 'swift', extensions: ['swift'] },
    { icon: 'tcl', extensions: ['tcl'] },
    { icon: 'tex', extensions: ['texi', 'tex'] },
    { icon: 'text', extensions: ['txt'] },
    { icon: 'textile', extensions: ['textile'] },
    { icon: 'todo', extensions: ['todo'] },
    { icon: 'twig', extensions: ['twig'] },
    { icon: 'typescript', extensions: ['ts'] },
    { icon: 'typescriptdef', extensions: ['.d.ts'], special: 'ts' },
    { icon: 'vbhtml', extensions: ['vbhtml'] },
    { icon: 'vue', extensions: ['vue'] },
    { icon: 'vscode', extensions: ['vscodeignore', 'launch', 'jsconfig', 'tsconfig'], special: 'json' },
    { icon: 'xml', extensions: ['xml', 'axml', 'xaml'] },
    { icon: 'yaml', extensions: ['yml', 'yaml'] },
    { icon: 'zip', extensions: ['zip', 'rar', '7z', 'tar', 'gz', 'bzip2', 'xz', 'bz2'] }
  ],
  parse: function () {
    var s = this.replace(/\./g, '_');
    if ((/^\d/).test(s)) return 'n' + s;
    return s;
  }
};
<|endoftext|>


<commit_before>'use strict';

var fs = require('fs');
var configHelper = require('../config');
var config = configHelper.getConfig();
var semver = require('semver');
var path = require('path');
var log = require('../logger')('nodecg/lib/bundles/parser');
var jade = require('jade');
var util = require('util');
var Q = require('q');
var exec = require('child_process').exec;
var bower = require('bower');

var pjson = require('../../package.json');

module.exports = function parse(bundleName) {
    // resolve the path to the bundle and its nodecg.json
    var dir = path.resolve(__dirname, '../../bundles/', bundleName);
    var manifestPath = path.join(dir, 'nodecg.json');

    // Return null if nodecg.json doesn't exist
    if (!fs.existsSync(manifestPath)) {
        return null;
    }

    log.trace('Discovered bundle in folder bundles/%s', bundleName);

    // Read metadata from the nodecg.json manifest file
    var bundle = readManifest(manifestPath);
    bundle.dir = dir;

    // Don't load the bundle if it depends on a different version of NodeCG
    if (!isCompatible(bundle.nodecgDependency)) {
        log.warn('Did not load %s as it requires NodeCG %s. Current version is %s',
            bundle.name, bundle.nodecgDependency, pjson.version);
        return null;
    }

    // If there is a config file for this bundle, parse it
    var cfgPath = path.resolve(__dirname, '../../cfg/', bundle.name + '.json');
    bundle.config = readConfig(cfgPath);

    // Read all HTML/CSS/JS files in the package's "dashboard" dir into memory
    // They will then get passed to dashboard.jade at the time of 'GET' and be templated into the final rendered page
    bundle.dashboard = {};
    bundle.dashboard.dir = path.join(bundle.dir, 'dashboard');

    readDashboardResources(bundle);
    readDashboardPanels(bundle);

    // The following operation(s) are async, so we make a collective promise for them
    return Q.all([
        installNpmPackages(bundle),
        installBowerPackages(bundle)
    ])
        .then(function() {
            return bundle;
        })
        .catch(function(err) {
            log.error(err.stack);
        });
};

function readManifest(path) {
    // Parse the JSON from nodecg.json
    var manifest = JSON.parse(fs.readFileSync(path, 'utf8'));

    // Copy the JSON we use into the beginnings of our bundle object
    return {
        name: manifest.name,
        version: manifest.version,
        description: manifest.description,
        homepage: manifest.homepage,
        authors: manifest.authors,
        license: manifest.license,
        nodecgDependency: manifest.nodecgDependency,
        dependencies: manifest.dependencies,
        extension: manifest.extension,
        bundleDependencies: manifest.bundleDependencies
    };
}

function installNpmPackages(bundle) {
    var deferred = Q.defer();

    if (bundle.dependencies) {
        log.warn('Bundle "%s" has the "dependencies" property in its nodecg.json', bundle.name);
        log.warn('Per-bundle npm dependencies have been moved into package.json');
        log.warn('Please remove the "dependencies" field from this bundle\'s nodecg.json and ' +
            'move it into a package.json');
    }

    // Do nothing if package.json does not exist
    var packagejsonPath = path.join(bundle.dir, 'package.json');
    if (!fs.existsSync(packagejsonPath)) {
        log.trace('Nothing to install for bundle', bundle.name);
        deferred.resolve();
        return deferred.promise;
    }

    exec('npm install', { cwd: bundle.dir }, function(err) {
        if (err) {
            deferred.reject(new Error(
                util.format('[%s] Failed to install npm dependencies:', bundle.name, err.message)
            ));
            return;
        }
        log.trace('Successfully installed dependencies for bundle', bundle.name);
        deferred.resolve();
    });

    return deferred.promise;
}

function installBowerPackages(bundle) {
    var deferred = Q.defer();

    // Do nothing if bower.json does not exist
    var packagejsonPath = path.join(bundle.dir, 'bower.json');
    if (!fs.existsSync(packagejsonPath)) {
        log.trace('Nothing to install for bundle', bundle.name);
        deferred.resolve();
        return deferred.promise;
    }

    bower.commands.install(undefined, undefined, { cwd: bundle.dir })
        .on('end', function(installed) { deferred.resolve(installed); })
        .on('error', function(error) { deferred.reject(error); });

    return deferred.promise;
}

function readDashboardPanels(bundle) {
    bundle.dashboard.panels = [];
    var manifestPath = path.join(bundle.dashboard.dir, 'panels.json');

    var manifest;
    try {
        manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
    } catch(e) {
        log.warn('[%s] dashboard/panels.json not found or not valid, this bundle will not have any dashboard panels',
            bundle.name);
        return;
    }

    manifest.forEach(function(panel, index) {
        try {
            var missingProps = [];
            if (typeof(panel.name) === 'undefined') missingProps.push('name');
            if (typeof(panel.title) === 'undefined') missingProps.push('title');
            if (typeof(panel.file) === 'undefined') missingProps.push('file');
            if (missingProps.length) {
                log.error('[%s] Panel #%d could not be parsed as it is missing the following properties:',
                    bundle.name, index, missingProps.join(', '));
                return;
            }

            panel.file = path.join(bundle.dashboard.dir, panel.file);
            panel.width = panel.width || 2;
            panel.faIcon = panel.faIcon || 'fa-question-circle';
            panel.viewUrl = panel.viewUrl || '/view/' + bundle.name;

            switch (path.extname(panel.file)) {
                case '.jade':
                    // Render the panel as Jade, giving it access to both
                    // this specific bundle's config and NodeCG's config
                    panel.body = jade.renderFile(panel.file, {
                        bundleConfig: bundle.config,
                        ncgConfig: config
                    });
                    break;
                case '.html':
                    // Copy the HTML verbatim with no further processing
                    panel.body = fs.readFileSync(panel.file, {encoding: 'utf8'});
                    break;
            }

            bundle.dashboard.panels.push(panel);
        } catch (e) {
            log.error('Error parsing panel \'%s\' for bundle %s:\n', panel.name, bundle.name, e.message);
        }
    });
}

function readDashboardResources(bundle) {
    // Arrays with the JS, CSS, and HTML
    bundle.dashboard.js = [];
    bundle.dashboard.css = [];

    var dashboardDir;
    try {
        // returns just the filenames of each file in the folder, not full path
        dashboardDir = fs.readdirSync(bundle.dashboard.dir);
    } catch(e) {
        // This used to log a message, but the message in readDashboardPanels() makes it redundant.
        return;
    }

    dashboardDir.forEach(function(file) {
        var filepath = path.join(bundle.dashboard.dir, file);
        if (!fs.statSync(filepath).isFile()) {
            // Skip directories
            return;
        }

        switch (path.extname(filepath)) {
            case '.js':
                bundle.dashboard.js.push(fs.readFileSync(filepath, {encoding: 'utf8'}));
                break;
            case '.css':
                bundle.dashboard.css.push(fs.readFileSync(filepath, {encoding: 'utf8'}));
                break;
        }
    });
}

function readConfig(cfgPath) {
    if (!fs.existsSync(cfgPath)) {
        // Skip if config does not exist
        return {};
    }

    return JSON.parse(fs.readFileSync(cfgPath, 'utf8'));
}

function isCompatible(nodecgDependency) {
    return !!semver.satisfies(pjson.version, nodecgDependency);
}
<commit_msg>Make messages more specific.<commit_after>'use strict';

var fs = require('fs');
var configHelper = require('../config');
var config = configHelper.getConfig();
var semver = require('semver');
var path = require('path');
var log = require('../logger')('nodecg/lib/bundles/parser');
var jade = require('jade');
var util = require('util');
var Q = require('q');
var exec = require('child_process').exec;
var bower = require('bower');

var pjson = require('../../package.json');

module.exports = function parse(bundleName) {
    // resolve the path to the bundle and its nodecg.json
    var dir = path.resolve(__dirname, '../../bundles/', bundleName);
    var manifestPath = path.join(dir, 'nodecg.json');

    // Return null if nodecg.json doesn't exist
    if (!fs.existsSync(manifestPath)) {
        return null;
    }

    log.trace('Discovered bundle in folder bundles/%s', bundleName);

    // Read metadata from the nodecg.json manifest file
    var bundle = readManifest(manifestPath);
    bundle.dir = dir;

    // Don't load the bundle if it depends on a different version of NodeCG
    if (!isCompatible(bundle.nodecgDependency)) {
        log.warn('Did not load %s as it requires NodeCG %s. Current version is %s',
            bundle.name, bundle.nodecgDependency, pjson.version);
        return null;
    }

    // If there is a config file for this bundle, parse it
    var cfgPath = path.resolve(__dirname, '../../cfg/', bundle.name + '.json');
    bundle.config = readConfig(cfgPath);

    // Read all HTML/CSS/JS files in the package's "dashboard" dir into memory
    // They will then get passed to dashboard.jade at the time of 'GET' and be templated into the final rendered page
    bundle.dashboard = {};
    bundle.dashboard.dir = path.join(bundle.dir, 'dashboard');

    readDashboardResources(bundle);
    readDashboardPanels(bundle);

    // The following operation(s) are async, so we make a collective promise for them
    return Q.all([
        installNpmPackages(bundle),
        installBowerPackages(bundle)
    ])
        .then(function() {
            return bundle;
        })
        .catch(function(err) {
            log.error(err.stack);
        });
};

function readManifest(path) {
    // Parse the JSON from nodecg.json
    var manifest = JSON.parse(fs.readFileSync(path, 'utf8'));

    // Copy the JSON we use into the beginnings of our bundle object
    return {
        name: manifest.name,
        version: manifest.version,
        description: manifest.description,
        homepage: manifest.homepage,
        authors: manifest.authors,
        license: manifest.license,
        nodecgDependency: manifest.nodecgDependency,
        dependencies: manifest.dependencies,
        extension: manifest.extension,
        bundleDependencies: manifest.bundleDependencies
    };
}

function installNpmPackages(bundle) {
    var deferred = Q.defer();

    if (bundle.dependencies) {
        log.warn('Bundle "%s" has the "dependencies" property in its nodecg.json', bundle.name);
        log.warn('Per-bundle npm dependencies have been moved into package.json');
        log.warn('Please remove the "dependencies" field from this bundle\'s nodecg.json and ' +
            'move it into a package.json');
    }

    // Do nothing if package.json does not exist
    var packagejsonPath = path.join(bundle.dir, 'package.json');
    if (!fs.existsSync(packagejsonPath)) {
        log.trace('No npm dependencies to install for bundle', bundle.name);
        deferred.resolve();
        return deferred.promise;
    }

    exec('npm install', { cwd: bundle.dir }, function(err) {
        if (err) {
            deferred.reject(new Error(
                util.format('[%s] Failed to install npm dependencies:', bundle.name, err.message)
            ));
            return;
        }
        log.trace('Successfully installed npm dependencies for bundle', bundle.name);
        deferred.resolve();
    });

    return deferred.promise;
}

function installBowerPackages(bundle) {
    var deferred = Q.defer();

    // Do nothing if bower.json does not exist
    var packagejsonPath = path.join(bundle.dir, 'bower.json');
    if (!fs.existsSync(packagejsonPath)) {
        log.trace('No Bower dependencies to install for bundle', bundle.name);
        deferred.resolve();
        return deferred.promise;
    }

    bower.commands.install(undefined, undefined, { cwd: bundle.dir })
        .on('end', function(installed) {
            log.trace('Successfully installed Bower dependencies for bundle', bundle.name);
            deferred.resolve();
        })
        .on('error', function(error) {
            deferred.reject(new Error(
                util.format('[%s] Failed to install Bower dependencies:', bundle.name, error.message)
            ));
        });

    return deferred.promise;
}

function readDashboardPanels(bundle) {
    bundle.dashboard.panels = [];
    var manifestPath = path.join(bundle.dashboard.dir, 'panels.json');

    var manifest;
    try {
        manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
    } catch(e) {
        log.warn('[%s] dashboard/panels.json not found or not valid, this bundle will not have any dashboard panels',
            bundle.name);
        return;
    }

    manifest.forEach(function(panel, index) {
        try {
            var missingProps = [];
            if (typeof(panel.name) === 'undefined') missingProps.push('name');
            if (typeof(panel.title) === 'undefined') missingProps.push('title');
            if (typeof(panel.file) === 'undefined') missingProps.push('file');
            if (missingProps.length) {
                log.error('[%s] Panel #%d could not be parsed as it is missing the following properties:',
                    bundle.name, index, missingProps.join(', '));
                return;
            }

            panel.file = path.join(bundle.dashboard.dir, panel.file);
            panel.width = panel.width || 2;
            panel.faIcon = panel.faIcon || 'fa-question-circle';
            panel.viewUrl = panel.viewUrl || '/view/' + bundle.name;

            switch (path.extname(panel.file)) {
                case '.jade':
                    // Render the panel as Jade, giving it access to both
                    // this specific bundle's config and NodeCG's config
                    panel.body = jade.renderFile(panel.file, {
                        bundleConfig: bundle.config,
                        ncgConfig: config
                    });
                    break;
                case '.html':
                    // Copy the HTML verbatim with no further processing
                    panel.body = fs.readFileSync(panel.file, {encoding: 'utf8'});
                    break;
            }

            bundle.dashboard.panels.push(panel);
        } catch (e) {
            log.error('Error parsing panel \'%s\' for bundle %s:\n', panel.name, bundle.name, e.message);
        }
    });
}

function readDashboardResources(bundle) {
    // Arrays with the JS, CSS, and HTML
    bundle.dashboard.js = [];
    bundle.dashboard.css = [];

    var dashboardDir;
    try {
        // returns just the filenames of each file in the folder, not full path
        dashboardDir = fs.readdirSync(bundle.dashboard.dir);
    } catch(e) {
        // This used to log a message, but the message in readDashboardPanels() makes it redundant.
        return;
    }

    dashboardDir.forEach(function(file) {
        var filepath = path.join(bundle.dashboard.dir, file);
        if (!fs.statSync(filepath).isFile()) {
            // Skip directories
            return;
        }

        switch (path.extname(filepath)) {
            case '.js':
                bundle.dashboard.js.push(fs.readFileSync(filepath, {encoding: 'utf8'}));
                break;
            case '.css':
                bundle.dashboard.css.push(fs.readFileSync(filepath, {encoding: 'utf8'}));
                break;
        }
    });
}

function readConfig(cfgPath) {
    if (!fs.existsSync(cfgPath)) {
        // Skip if config does not exist
        return {};
    }

    return JSON.parse(fs.readFileSync(cfgPath, 'utf8'));
}

function isCompatible(nodecgDependency) {
    return !!semver.satisfies(pjson.version, nodecgDependency);
}
<|endoftext|>