<commit_before>var http       = require('http');
var https      = require('https');
var merge      = require('./utils/merge');
var query      = require('./utils/queryparams');
var serializer = require('./serializer');
var errors     = require('./Errors');
var Thenable   = require('./vendor/Thenable');

var Client = function(config, resources) {
  this.host      = config.host;
  this.port      = config.port;
  this.base      = config.base    || '';
  this.headers   = config.headers || {};
  this.scheme    = config.scheme  || 'http';
  this.resources = resources      || {};
};

merge(Client.prototype, {
  get: function(path, params) {
    var fullPath = this._fullPath(path, params);
    var options  = this._buildOptions(fullPath, 'GET');

    return this._makeRequest(options);
  },

  delete: function(path) {
    var options = this._buildOptions(path, 'DELETE');

    return this._makeRequest(options);
  },

  post: function(path, data) {
    var options = this._buildOptions(path, 'POST');

    return this._makeRequest(options, data);
  },

  put: function(path, data) {
    var options = this._buildOptions(path, 'PUT');

    return this._makeRequest(options, data);
  },

  _makeRequest: function(options, data) {
    var client    = (this.scheme === 'https' ? https : http);
    var resources = this.resources;

    this._insertContentLength(options.headers, data);

    return new Thenable(function(resolve, reject) {
      var buffer = '';
      var request = client.request(options, function(response) {
        response.setEncoding('utf8');

        response.on('data', function(chunk) {
          buffer += chunk;
        });

        response.on('end', function() {
          var wrapper = {
            status: response.statusCode,
            body: serializer.load(buffer, resources)
          };

          if (wrapper.status >= 200 && wrapper.status <= 399) {
            resolve(wrapper);
          } else {
            reject(errors(wrapper.status));
          }
        });
      });

      request.on('error', function(error) {
        reject(error);
      });

      if (data) {
        request.write(serializer.dump(data));
      }

      request.end();
    });
  },

  _fullPath: function(path, params) {
    return params ? path + '?' + query.stringify(params) : path;
  },

  _buildOptions: function(path, method) {
    return {
      hostname: this.host,
      port:     this.port,
      headers:  this.headers,
      path:     this.base + path,
      method:   method
    };
  },

  _insertContentLength: function(headers, data) {
    if (data) {
      var jsonContent = JSON.stringify(data)
      headers['Content-Length'] = Buffer.byteLength(jsonContent, 'utf8');
    }
  }
});

module.exports = Client;
<commit_msg>Use serializer.dump instead of hard coding JSON<commit_after>var http       = require('http');
var https      = require('https');
var merge      = require('./utils/merge');
var query      = require('./utils/queryparams');
var serializer = require('./serializer');
var errors     = require('./Errors');
var Thenable   = require('./vendor/Thenable');

var Client = function(config, resources) {
  this.host      = config.host;
  this.port      = config.port;
  this.base      = config.base    || '';
  this.headers   = config.headers || {};
  this.scheme    = config.scheme  || 'http';
  this.resources = resources      || {};
};

merge(Client.prototype, {
  get: function(path, params) {
    var fullPath = this._fullPath(path, params);
    var options  = this._buildOptions(fullPath, 'GET');

    return this._makeRequest(options);
  },

  delete: function(path) {
    var options = this._buildOptions(path, 'DELETE');

    return this._makeRequest(options);
  },

  post: function(path, data) {
    var options = this._buildOptions(path, 'POST');

    return this._makeRequest(options, data);
  },

  put: function(path, data) {
    var options = this._buildOptions(path, 'PUT');

    return this._makeRequest(options, data);
  },

  _makeRequest: function(options, data) {
    var client    = (this.scheme === 'https' ? https : http);
    var resources = this.resources;

    this._insertContentLength(options.headers, data);

    return new Thenable(function(resolve, reject) {
      var buffer = '';
      var request = client.request(options, function(response) {
        response.setEncoding('utf8');

        response.on('data', function(chunk) {
          buffer += chunk;
        });

        response.on('end', function() {
          var wrapper = {
            status: response.statusCode,
            body: serializer.load(buffer, resources)
          };

          if (wrapper.status >= 200 && wrapper.status <= 399) {
            resolve(wrapper);
          } else {
            reject(errors(wrapper.status));
          }
        });
      });

      request.on('error', function(error) {
        reject(error);
      });

      if (data) {
        request.write(serializer.dump(data));
      }

      request.end();
    });
  },

  _fullPath: function(path, params) {
    return params ? path + '?' + query.stringify(params) : path;
  },

  _buildOptions: function(path, method) {
    return {
      hostname: this.host,
      port:     this.port,
      headers:  this.headers,
      path:     this.base + path,
      method:   method
    };
  },

  _insertContentLength: function(headers, data) {
    if (data) {
      var body = serializer.dump(data);
      headers['Content-Length'] = Buffer.byteLength(body, 'utf8');
    }
  }
});

module.exports = Client;
<|endoftext|>


<commit_before>var persistence = require('../');
var mem = require('persistence-memory');
var JaySchema = require('jayschema');

persistence.validator = new JaySchema();
mem.connect({
  name : 'persistence_test'
}, function(err, db) {
  if (err)
    throw err;

  persistence.engine = db;

  var Author = persistence.define('author', {
    "name" : {
      "type" : "string"
    }
  });

  Author.create({
    _id : 'pvorb',
    name : 'Paul'
  }, function(err, pvorb) {
    Author.all(function(err, result) {
      console.log(err, result);
    });
  });
});
<commit_msg>Formatted<commit_after>var persistence = require('../');
var mem = require('persistence-memory');
var JaySchema = require('jayschema');

persistence.validator = new JaySchema();
mem.connect({
    name: 'persistence_test'
}, function(err, db) {
    if (err) throw err;

    persistence.engine = db;

    var Author = persistence.define('author', {
        "name": {
            "type": "string"
        }
    });

    Author.create({
        _id: 'pvorb',
        name: 'Paul'
    }, function(err, pvorb) {
        Author.all(function(err, result) {
            console.log(err, result);
        });
    });
});<|endoftext|>


<commit_before>var MetadataView = require('../../../app/views/metadata');
var mockFile = require('../../mocks/models/file');
var mockFileView = require('../../mocks/views/file');

var templates = require('../../../dist/templates');
var $ = require('jquery-browserify');
var _ = require('underscore');
var jsyaml = require('js-yaml');

'use strict';

describe('Metadata editor view', function() {

  var metadataEditor;

  var model;
  beforeEach(function() {
    $('<div />', {
      id: 'meta',
      html: _.template(templates.metadata)
    }).appendTo($('body'));

    model = mockFile();
    var fileView = mockFileView();
    metadataEditor = new MetadataView({
      model: model,
      titleAsHeading: fileView.titleAsHeading(),
      view: fileView,
      el: $('#meta')
    });
  });

  afterEach(function() {
    $('#meta').remove();
    if (metadataEditor.remove) {
      metadataEditor.remove();
    }
  });

  describe('creating editor elements', function() {

    // Without any defaults, we should only see the raw meta element
    it('shows a raw editor', function() {
      metadataEditor.render();
      expect($('#meta').find('.form-item').length).to.equal(1);
    });

    it('creates a text input element with default value, label and data-type', function() {
      model.set('defaults', [{
        name: 'text',
        field: {
          element: 'text',
          value: 'hello world',
          label: 'text label'
        }
      }]);
      metadataEditor.render();
      var $meta = $('#meta').find('input[type="text"]');
      expect($meta.length).to.equal(1);
      expect($meta.val()).to.equal('hello world');
      expect($meta.data('type')).to.equal('text');
      expect($('#meta').find('label[for="text"]').text()).to.equal('text label');
    });

    it('creates a textarea element with default value and label', function() {
      model.set('defaults', [{
        name: 'foo',
        field: {
          element: 'textarea',
          label: 'bar',
          value: '123'
        }
      }]);
      metadataEditor.render();
      expect($('#meta').find('label[for="foo"]').text()).to.equal('bar');
      expect(metadataEditor.codeMirrorInstances.foo.getValue()).to.equal('123');
    });

    it('creates a select element with correct label and options', function() {
      model.set('defaults', [{
        name: 'select',
        field: {
          element: 'select',
          label: 'select label',
          options: [
            {name: 'Dan', value: 'dan'},
            {name: 'Jon', value: 'jon'},
            {name: 'Sre', value: 'sre'}
          ]
        }
      }]);
      metadataEditor.render();
      expect($('#meta').find('label[for="select"]').text()).to.equal('select label');
      expect($('#meta').find('ul.chzn-results').find('li').length).to.equal(3);
    });

    it('creates a multiselect element with correct label and options', function() {
      model.set('defaults', [{
        name: 'multiselect',
        field: {
          element: 'multiselect',
          label: 'multiselect label',
          options: [
            {name: 'Dan', value: 'dan'},
            {name: 'Jon', value: 'jon'}
          ]
        }
      }]);
      metadataEditor.render();
      expect($('#meta').find('label[for="multiselect"]').text()).to.equal('multiselect label');
      expect($('#meta').find('ul.chzn-results').find('li').length).to.equal(2);
    });

    it('creates a checkbox element with default value and label', function() {
      model.set('defaults', [{
        name: 'checkbox',
        field: {
          element: 'checkbox',
          label: 'checkbox label',
          value: false
        }
      }]);
      metadataEditor.render();
      expect($('#meta').find('input[type="checkbox"]').length).to.equal(1);
      expect($('#meta').find('input[type="checkbox"]:checked').length).to.equal(0);
      expect($('#meta').find('label[for="checkbox"]').text()).to.equal('checkbox label');
    });

    it('creates a number element with default value, label, and data-type', function() {
      model.set('defaults', [{
        name: 'number',
        field: {
          element: 'number',
          label: 'number label',
          value: 4
        }
      }]);
      metadataEditor.render();
      var $meta = $('#meta').find('input[type="text"]');
      expect($meta.length).to.equal(1);
      expect($meta.val()).to.equal('4');
      expect($meta.data('type')).to.equal('number');
      expect($('#meta').find('label[for="number"]').text()).to.equal('number label');
    });

    it('creates a button element that defaults to on (true)', function() {
      model.set('defaults', [{
        name: 'button',
        field: {
          element: 'button',
          on: 'on',
          off: 'off'
        }
      }]);
      metadataEditor.render();
      var $button = $('#meta').find('[name="button"]');
      expect($button.length).to.equal(1);
      expect($button.val()).to.equal('on');
      expect($button.text()).to.equal('on');
    });

    it('creates a text element if no field object exists', function() {
      model.set('defaults', [{
        name: 'shouldBeText'
      }]);
      metadataEditor.render();
      expect($('#meta').find('input[type="text"]').length).to.equal(1);
    });

    it('does not append hidden meta elements', function() {
      model.set('defaults', [{
        name: 'layout',
        field: {
          element: 'hidden',
          value: 'fixed'
        }
      }]);
      metadataEditor.render();
      expect($('#meta').find('.form-item').length).to.equal(1);
    });

    it('saves defaults that are hidden to metadata', function() {
      model.set('defaults', [{
        name: 'layout',
        field: {
          element: 'hidden',
          value: 'fixed'
        }
      }]);
      metadataEditor.render();
      expect(metadataEditor.model.get('metadata').layout).to.equal('fixed');
    });

    it('saves multiple hidden elements to metadata', function() {
      model.set('defaults', [{
        name: 'layout',
        field: {
          element: 'hidden',
          value: 'fixed'
        }
      },
      {
        name: 'published',
        field: {
          element: 'hidden',
          value: true
        }
      }]);
      metadataEditor.render();
      expect(metadataEditor.model.get('metadata').layout).to.equal('fixed');
      expect(metadataEditor.model.get('metadata').published).to.equal(true);
    });

    it('does not crap out on hidden metadata with no defaults', function() {
      model.set('defaults', [{
        name: 'layout',
        field: {
          element: 'hidden'
        }
      }]);
      metadataEditor.render();
      var values = metadataEditor.getValue();
      expect(values.hasOwnProperty('layout')).to.ok;
      expect(metadataEditor.model.get('metadata').layout).to.equal('');
    });

    it('textarea names do not collide with view methods', function() {
      var view = metadataEditor.view;
      model.set('defaults', [{
        name: 'view',
        field: {
          element: 'textarea',
        }
      }]);
      metadataEditor.render();
      expect(metadataEditor.view).to.deep.equal(view);
    });
  });

  describe('testing user input from form elements', function() {
    // Although there are separate tests for getting values from each meta element individually,
    // this one is more about the ability of this one to save values to a metadata object.

    it('saves changes to model on change to a text input', function() {
      model.set('defaults', [{
        name: 'foo',
        field: {
          element: 'text',
          value: 'foo'
        }
      }]);
      metadataEditor.render();

      var newValue = 'bar';
      $('#meta').find('[name="foo"]').val(newValue);
      $('.metafield').trigger('change');
      expect(model.get('metadata').foo).to.equal(newValue);
    });

    it('saves changes to model on textarea blur', function() {
      model.set('defaults', [{
        name: 'textarea',
        field: {
          element: 'textarea',
          value: 'foo',
        }
      }]);
      metadataEditor.render();
      metadataEditor.codeMirrorInstances.textarea.setValue('bar');
      $('.metafield').trigger('change');
      expect(model.get('metadata').textarea).to.equal('bar');
    });

    it('saves changes to model on checkboxes', function() {
      model.set('defaults', [{
        name: 'checkbox',
        field: {
          element: 'checkbox',
          label: 'checkbox label',
          value: false
        }
      }]);
      metadataEditor.render();
      var $input = $('#meta').find('input[name="checkbox"]');
      $input[0].checked = true;
      $input.trigger('change');
      expect(model.get('metadata').checkbox).to.equal(true);
    });

    it('saves changes to model on selects', function() {
      model.set('defaults', [{
        name: 'select',
        field: {
          element: 'select',
          label: 'select label',
          options: [
            {name: 'Dan', value: 'dan'},
            {name: 'Jon', value: 'jon'},
            {name: 'Sre', value: 'sre'}
          ]
        }
      }]);
      metadataEditor.render();
      var $select = $('#meta').find('select');
      $select[0].selectedIndex=1;
      $select.trigger('liszt:updated').trigger('change');
      expect(model.get('metadata').select).to.equal('jon');
    });

    it('saves changes to model on multiselects', function() {
      model.set('defaults', [{
        name: 'select',
        field: {
          element: 'multiselect',
          label: 'multiselect label',
          options: [
            {name: 'Dan', value: 'dan'},
            {name: 'Jon', value: 'jon'},
            {name: 'Sre', value: 'sre'}
          ]
        }
      }]);
      metadataEditor.render();
      var $select = $('#meta').find('select');
      $select[0].selectedIndex=2;
      $select.trigger('liszt:updated').trigger('change');
      expect(model.get('metadata').select[0]).to.equal('sre');
    });

    it('saves number fields as numbers', function() {
      model.set('defaults', [{
        name: 'number',
        field: {
          element: 'number',
          label: 'number label',
          value: 4
        }
      }]);
      metadataEditor.render();
      var $input = $('#meta').find('input[name="number"]')
      $input.val(6);
      $input.trigger('change');
      expect(model.get('metadata').number).to.equal(6);
    });

    it('saves button values as boolean, defaulting to true', function() {
      model.set('defaults', [{
        name: 'button',
        field: {
          element: 'button',
          on: 'on',
          off: 'off'
        }
      }]);
      metadataEditor.render();
      var $button = $('#meta').find('[name="button"]');
      expect(model.get('metadata').button).to.equal(true);
      $button.trigger('click');
      expect(model.get('metadata').button).to.equal(false);
    });

    it('does not error when titleAsHeading is true and no title is defined on metadata', function() {
      model.set('metadata', {
        title: null
      });
      metadataEditor.titleAsHeading = true;
      metadataEditor.render();
      expect(metadataEditor).to.be.ok;
    });
  });

  describe('setting defaults on load', function() {
    it('sets values on text elements', function() {
      model.set('defaults', [{
        name: 'text',
        field: {
          element: 'text'
        }
      }]);
      model.set('metadata', {
        text: 'abc'
      });
      metadataEditor.render();
      expect($('#meta').find('input[name="text"]').val()).to.equal('abc');
    });

    it('sets values on textarea elements', function() {
      model.set('defaults', [{
        name: 'textarea',
        field: {
          element: 'textarea'
        }
      }]);
      model.set('metadata', {
        textarea: 'abc'
      });
      metadataEditor.render();
      expect(metadataEditor.codeMirrorInstances.textarea.getValue()).to.equal('abc');
    });

    it('sets values on select elements', function() {
      model.set('defaults', [{
        name: 'select',
        field: {
          element: 'select',
          options: [
            {name: 'Dan', value: 'dan'},
            {name: 'Jon', value: 'jon'},
            {name: 'Sre', value: 'sre'}
          ]
        }
      }]);
      model.set('metadata', {
        select: 'jon'
      });
      metadataEditor.render();
      expect($('#meta').find('select').val()).to.equal('jon');
    });

    it('sets values on multiselect elements', function() {
      model.set('defaults', [{
        name: 'multiselect',
        field: {
          element: 'multiselect',
          options: [
            {name: 'Dan', value: 'dan'},
            {name: 'Jon', value: 'jon'},
            {name: 'Sre', value: 'sre'}
          ]
        }
      }]);
      model.set('metadata', {
        multiselect: ['jon','sre']
      });
      metadataEditor.render();
      expect($('#meta').find('select').val()).to.deep.equal(['jon','sre']);
    });

    it('sets values on checkbox elements', function() {
      model.set('defaults', [{
        name: 'checkbox',
        field: {
          element: 'checkbox',
          value: false
        }
      }]);
      model.set('metadata', {
        checkbox: true
      });
      metadataEditor.render();
      expect($('#meta').find('input[name="checkbox"]')[0].checked).to.equal(true);
    });

    it('puts metadata without defaults into the raw editor', function() {
      model.set('defaults', []);
      model.set('metadata', {
        text: 'hello world'
      });
      metadataEditor.render();
      expect(jsyaml.safeLoad(metadataEditor.codeMirrorInstances.rawEditor.getValue()))
        .to.deep.equal({text: 'hello world'});
    });

    it('does not put title, publish, or hidden elements into the raw editor', function() {
      model.set('defaults', [{
        name: 'layout',
        field: {
          element: 'hidden',
          value: 'page'
        }
      }]);
      model.set('metadata', {
        published: true,
        title: 'hello world'
      });
      metadataEditor.render();
      expect(metadataEditor.codeMirrorInstances.rawEditor.getValue()).to.equal('');
    });

    it('handles text elements with duplicate names', function() {
      model.set('defaults', [{
        name: 'text',
        field: {
          element: 'text',
        }
      },{
        name: 'text',
        field: {
          element: 'text',
        }
      }]);
      model.set('metadata', {
        text: ['hello', 'world']
      });
      metadataEditor.render();
      expect(model.get('metadata').text).to.deep.equal(['hello', 'world']);
    });

    it('adds options to selects from metadata when none exists in defaults', function() {
      model.set('defaults', [{
        name: 'select',
        field: {
          element: 'select',
          options: []
        }
      }]);
      model.set('metadata', {
        select: 'foo'
      });
      metadataEditor.render();
      expect($('#meta').find('select').find('option').length).to.equal(1);
      expect(model.get('metadata').select).to.equal('foo');
    });

    it('adds options to multiselects from metadata when none exists in defaults', function() {
      model.set('defaults', [{
        name: 'multiselect',
        field: {
          element: 'multiselect',
          options: []
        }
      }]);
      model.set('metadata', {
        multiselect: ['foo', 'bar']
      });
      metadataEditor.render();
      expect($('#meta').find('select').find('option').length).to.equal(2);
      expect(model.get('metadata').multiselect).to.deep.equal(['foo', 'bar']);
    });
  });
});
<commit_msg>Metadata should remove elements that are non-existant<commit_after>var MetadataView = require('../../../app/views/metadata');
var mockFile = require('../../mocks/models/file');
var mockFileView = require('../../mocks/views/file');

var templates = require('../../../dist/templates');
var $ = require('jquery-browserify');
var _ = require('underscore');
var jsyaml = require('js-yaml');

'use strict';

describe('Metadata editor view', function() {

  var metadataEditor;

  var model;
  beforeEach(function() {
    $('<div />', {
      id: 'meta',
      html: _.template(templates.metadata)
    }).appendTo($('body'));

    model = mockFile();
    var fileView = mockFileView();
    metadataEditor = new MetadataView({
      model: model,
      titleAsHeading: fileView.titleAsHeading(),
      view: fileView,
      el: $('#meta')
    });
  });

  afterEach(function() {
    $('#meta').remove();
    if (metadataEditor.remove) {
      metadataEditor.remove();
    }
  });

  describe('creating editor elements', function() {

    // Without any defaults, we should only see the raw meta element
    it('shows a raw editor', function() {
      metadataEditor.render();
      expect($('#meta').find('.form-item').length).to.equal(1);
    });

    it('creates a text input element with default value, label and data-type', function() {
      model.set('defaults', [{
        name: 'text',
        field: {
          element: 'text',
          value: 'hello world',
          label: 'text label'
        }
      }]);
      metadataEditor.render();
      var $meta = $('#meta').find('input[type="text"]');
      expect($meta.length).to.equal(1);
      expect($meta.val()).to.equal('hello world');
      expect($meta.data('type')).to.equal('text');
      expect($('#meta').find('label[for="text"]').text()).to.equal('text label');
    });

    it('creates a textarea element with default value and label', function() {
      model.set('defaults', [{
        name: 'foo',
        field: {
          element: 'textarea',
          label: 'bar',
          value: '123'
        }
      }]);
      metadataEditor.render();
      expect($('#meta').find('label[for="foo"]').text()).to.equal('bar');
      expect(metadataEditor.codeMirrorInstances.foo.getValue()).to.equal('123');
    });

    it('creates a select element with correct label and options', function() {
      model.set('defaults', [{
        name: 'select',
        field: {
          element: 'select',
          label: 'select label',
          options: [
            {name: 'Dan', value: 'dan'},
            {name: 'Jon', value: 'jon'},
            {name: 'Sre', value: 'sre'}
          ]
        }
      }]);
      metadataEditor.render();
      expect($('#meta').find('label[for="select"]').text()).to.equal('select label');
      expect($('#meta').find('ul.chzn-results').find('li').length).to.equal(3);
    });

    it('creates a multiselect element with correct label and options', function() {
      model.set('defaults', [{
        name: 'multiselect',
        field: {
          element: 'multiselect',
          label: 'multiselect label',
          options: [
            {name: 'Dan', value: 'dan'},
            {name: 'Jon', value: 'jon'}
          ]
        }
      }]);
      metadataEditor.render();
      expect($('#meta').find('label[for="multiselect"]').text()).to.equal('multiselect label');
      expect($('#meta').find('ul.chzn-results').find('li').length).to.equal(2);
    });

    it('creates a checkbox element with default value and label', function() {
      model.set('defaults', [{
        name: 'checkbox',
        field: {
          element: 'checkbox',
          label: 'checkbox label',
          value: false
        }
      }]);
      metadataEditor.render();
      expect($('#meta').find('input[type="checkbox"]').length).to.equal(1);
      expect($('#meta').find('input[type="checkbox"]:checked').length).to.equal(0);
      expect($('#meta').find('label[for="checkbox"]').text()).to.equal('checkbox label');
    });

    it('creates a number element with default value, label, and data-type', function() {
      model.set('defaults', [{
        name: 'number',
        field: {
          element: 'number',
          label: 'number label',
          value: 4
        }
      }]);
      metadataEditor.render();
      var $meta = $('#meta').find('input[type="text"]');
      expect($meta.length).to.equal(1);
      expect($meta.val()).to.equal('4');
      expect($meta.data('type')).to.equal('number');
      expect($('#meta').find('label[for="number"]').text()).to.equal('number label');
    });

    it('creates a button element that defaults to on (true)', function() {
      model.set('defaults', [{
        name: 'button',
        field: {
          element: 'button',
          on: 'on',
          off: 'off'
        }
      }]);
      metadataEditor.render();
      var $button = $('#meta').find('[name="button"]');
      expect($button.length).to.equal(1);
      expect($button.val()).to.equal('on');
      expect($button.text()).to.equal('on');
    });

    it('creates a text element if no field object exists', function() {
      model.set('defaults', [{
        name: 'shouldBeText'
      }]);
      metadataEditor.render();
      expect($('#meta').find('input[type="text"]').length).to.equal(1);
    });

    it('does not append hidden meta elements', function() {
      model.set('defaults', [{
        name: 'layout',
        field: {
          element: 'hidden',
          value: 'fixed'
        }
      }]);
      metadataEditor.render();
      expect($('#meta').find('.form-item').length).to.equal(1);
    });

    it('saves defaults that are hidden to metadata', function() {
      model.set('defaults', [{
        name: 'layout',
        field: {
          element: 'hidden',
          value: 'fixed'
        }
      }]);
      metadataEditor.render();
      expect(metadataEditor.model.get('metadata').layout).to.equal('fixed');
    });

    it('saves multiple hidden elements to metadata', function() {
      model.set('defaults', [{
        name: 'layout',
        field: {
          element: 'hidden',
          value: 'fixed'
        }
      },
      {
        name: 'published',
        field: {
          element: 'hidden',
          value: true
        }
      }]);
      metadataEditor.render();
      expect(metadataEditor.model.get('metadata').layout).to.equal('fixed');
      expect(metadataEditor.model.get('metadata').published).to.equal(true);
    });

    it('does not crap out on hidden metadata with no defaults', function() {
      model.set('defaults', [{
        name: 'layout',
        field: {
          element: 'hidden'
        }
      }]);
      metadataEditor.render();
      var values = metadataEditor.getValue();
      expect(values.hasOwnProperty('layout')).to.notOk;
    });

    it('textarea names do not collide with view methods', function() {
      var view = metadataEditor.view;
      model.set('defaults', [{
        name: 'view',
        field: {
          element: 'textarea',
        }
      }]);
      metadataEditor.render();
      expect(metadataEditor.view).to.deep.equal(view);
    });
  });

  describe('testing user input from form elements', function() {
    // Although there are separate tests for getting values from each meta element individually,
    // this one is more about the ability of this one to save values to a metadata object.

    it('saves changes to model on change to a text input', function() {
      model.set('defaults', [{
        name: 'foo',
        field: {
          element: 'text',
          value: 'foo'
        }
      }]);
      metadataEditor.render();

      var newValue = 'bar';
      $('#meta').find('[name="foo"]').val(newValue);
      $('.metafield').trigger('change');
      expect(model.get('metadata').foo).to.equal(newValue);
    });

    it('saves changes to model on textarea blur', function() {
      model.set('defaults', [{
        name: 'textarea',
        field: {
          element: 'textarea',
          value: 'foo',
        }
      }]);
      metadataEditor.render();
      metadataEditor.codeMirrorInstances.textarea.setValue('bar');
      $('.metafield').trigger('change');
      expect(model.get('metadata').textarea).to.equal('bar');
    });

    it('saves changes to model on checkboxes', function() {
      model.set('defaults', [{
        name: 'checkbox',
        field: {
          element: 'checkbox',
          label: 'checkbox label',
          value: false
        }
      }]);
      metadataEditor.render();
      var $input = $('#meta').find('input[name="checkbox"]');
      $input[0].checked = true;
      $input.trigger('change');
      expect(model.get('metadata').checkbox).to.equal(true);
    });

    it('saves changes to model on selects', function() {
      model.set('defaults', [{
        name: 'select',
        field: {
          element: 'select',
          label: 'select label',
          options: [
            {name: 'Dan', value: 'dan'},
            {name: 'Jon', value: 'jon'},
            {name: 'Sre', value: 'sre'}
          ]
        }
      }]);
      metadataEditor.render();
      var $select = $('#meta').find('select');
      $select[0].selectedIndex=1;
      $select.trigger('liszt:updated').trigger('change');
      expect(model.get('metadata').select).to.equal('jon');
    });

    it('saves changes to model on multiselects', function() {
      model.set('defaults', [{
        name: 'select',
        field: {
          element: 'multiselect',
          label: 'multiselect label',
          options: [
            {name: 'Dan', value: 'dan'},
            {name: 'Jon', value: 'jon'},
            {name: 'Sre', value: 'sre'}
          ]
        }
      }]);
      metadataEditor.render();
      var $select = $('#meta').find('select');
      $select[0].selectedIndex=2;
      $select.trigger('liszt:updated').trigger('change');
      expect(model.get('metadata').select[0]).to.equal('sre');
    });

    it('saves number fields as numbers', function() {
      model.set('defaults', [{
        name: 'number',
        field: {
          element: 'number',
          label: 'number label',
          value: 4
        }
      }]);
      metadataEditor.render();
      var $input = $('#meta').find('input[name="number"]')
      $input.val(6);
      $input.trigger('change');
      expect(model.get('metadata').number).to.equal(6);
    });

    it('saves button values as boolean, defaulting to true', function() {
      model.set('defaults', [{
        name: 'button',
        field: {
          element: 'button',
          on: 'on',
          off: 'off'
        }
      }]);
      metadataEditor.render();
      var $button = $('#meta').find('[name="button"]');
      expect(model.get('metadata').button).to.equal(true);
      $button.trigger('click');
      expect(model.get('metadata').button).to.equal(false);
    });

    it('does not error when titleAsHeading is true and no title is defined on metadata', function() {
      model.set('metadata', {
        title: null
      });
      metadataEditor.titleAsHeading = true;
      metadataEditor.render();
      expect(metadataEditor).to.be.ok;
    });
  });

  describe('setting defaults on load', function() {
    it('sets values on text elements', function() {
      model.set('defaults', [{
        name: 'text',
        field: {
          element: 'text'
        }
      }]);
      model.set('metadata', {
        text: 'abc'
      });
      metadataEditor.render();
      expect($('#meta').find('input[name="text"]').val()).to.equal('abc');
    });

    it('sets values on textarea elements', function() {
      model.set('defaults', [{
        name: 'textarea',
        field: {
          element: 'textarea'
        }
      }]);
      model.set('metadata', {
        textarea: 'abc'
      });
      metadataEditor.render();
      expect(metadataEditor.codeMirrorInstances.textarea.getValue()).to.equal('abc');
    });

    it('sets values on select elements', function() {
      model.set('defaults', [{
        name: 'select',
        field: {
          element: 'select',
          options: [
            {name: 'Dan', value: 'dan'},
            {name: 'Jon', value: 'jon'},
            {name: 'Sre', value: 'sre'}
          ]
        }
      }]);
      model.set('metadata', {
        select: 'jon'
      });
      metadataEditor.render();
      expect($('#meta').find('select').val()).to.equal('jon');
    });

    it('sets values on multiselect elements', function() {
      model.set('defaults', [{
        name: 'multiselect',
        field: {
          element: 'multiselect',
          options: [
            {name: 'Dan', value: 'dan'},
            {name: 'Jon', value: 'jon'},
            {name: 'Sre', value: 'sre'}
          ]
        }
      }]);
      model.set('metadata', {
        multiselect: ['jon','sre']
      });
      metadataEditor.render();
      expect($('#meta').find('select').val()).to.deep.equal(['jon','sre']);
    });

    it('sets values on checkbox elements', function() {
      model.set('defaults', [{
        name: 'checkbox',
        field: {
          element: 'checkbox',
          value: false
        }
      }]);
      model.set('metadata', {
        checkbox: true
      });
      metadataEditor.render();
      expect($('#meta').find('input[name="checkbox"]')[0].checked).to.equal(true);
    });

    it('puts metadata without defaults into the raw editor', function() {
      model.set('defaults', []);
      model.set('metadata', {
        text: 'hello world'
      });
      metadataEditor.render();
      expect(jsyaml.safeLoad(metadataEditor.codeMirrorInstances.rawEditor.getValue()))
        .to.deep.equal({text: 'hello world'});
    });

    it('does not put title, publish, or hidden elements into the raw editor', function() {
      model.set('defaults', [{
        name: 'layout',
        field: {
          element: 'hidden',
          value: 'page'
        }
      }]);
      model.set('metadata', {
        published: true,
        title: 'hello world'
      });
      metadataEditor.render();
      expect(metadataEditor.codeMirrorInstances.rawEditor.getValue()).to.equal('');
    });

    it('handles text elements with duplicate names', function() {
      model.set('defaults', [{
        name: 'text',
        field: {
          element: 'text',
        }
      },{
        name: 'text',
        field: {
          element: 'text',
        }
      }]);
      model.set('metadata', {
        text: ['hello', 'world']
      });
      metadataEditor.render();
      expect(model.get('metadata').text).to.deep.equal(['hello', 'world']);
    });

    it('adds options to selects from metadata when none exists in defaults', function() {
      model.set('defaults', [{
        name: 'select',
        field: {
          element: 'select',
          options: []
        }
      }]);
      model.set('metadata', {
        select: 'foo'
      });
      metadataEditor.render();
      expect($('#meta').find('select').find('option').length).to.equal(1);
      expect(model.get('metadata').select).to.equal('foo');
    });

    it('adds options to multiselects from metadata when none exists in defaults', function() {
      model.set('defaults', [{
        name: 'multiselect',
        field: {
          element: 'multiselect',
          options: []
        }
      }]);
      model.set('metadata', {
        multiselect: ['foo', 'bar']
      });
      metadataEditor.render();
      expect($('#meta').find('select').find('option').length).to.equal(2);
      expect(model.get('metadata').multiselect).to.deep.equal(['foo', 'bar']);
    });

    it('removes meta values that are empty strings from text fields', function () {
      model.set('defaults', [{
        name: 'false',
        field: {
          element: 'text',
          value: 'false'
        }
      }, {
        name: 'null',
        field: {
          element: 'text',
          value: 'null'
        }
      }, {
        name: 'numerical zero',
        field: {
          element: 'text',
          value: 0
        }
      }, {
        name: 'empty string',
        field: {
          element: 'text',
          value: ''
        }
      }]);
      metadataEditor.render();
      expect(model.get('metadata').hasOwnProperty('false')).ok;
      expect(model.get('metadata').hasOwnProperty('null')).ok;
      expect(model.get('metadata').hasOwnProperty('numerical zero')).ok;
      expect(model.get('metadata').hasOwnProperty('empty string')).not.ok;
    });

    it('removes meta values that are empty strings from textarea fields', function () {
      model.set('defaults', [{
        name: 'false',
        field: {
          element: 'textarea',
          value: 'false'
        }
      }, {
        name: 'null',
        field: {
          element: 'textarea',
          value: 'null'
        }
      }, {
        name: 'numerical zero',
        field: {
          element: 'textarea',
          value: 0
        }
      }, {
        name: 'empty string',
        field: {
          element: 'textarea',
          value: ''
        }
      }]);
      metadataEditor.render();
      // textareas behave differently, parsing is done by codemirror
      // and jsyaml, so we have less control over the outcome.
      expect(model.get('metadata').hasOwnProperty('false')).not.ok;
      expect(model.get('metadata').hasOwnProperty('null')).not.ok;
      expect(model.get('metadata').hasOwnProperty('numerical zero')).ok;
      expect(model.get('metadata').hasOwnProperty('empty string')).not.ok;
    });

    it('removes empty string values that are not defaults', function () {
      model.set('metadata', {
        notExist: '',
        shouldExist: false
      });
      metadataEditor.render();
      expect(model.get('metadata').hasOwnProperty('shouldExist')).ok;
      expect(model.get('metadata').hasOwnProperty('notExist')).not.ok;
    });
  });
});
<|endoftext|>


<commit_before>import React from 'react';

// ROUTER
import {
  History
}
from 'react-router';
import reactMixin from 'react-mixin';

// COMPONENTS
import NavBar from './NavBar.js';
import Loading from './Loading.js'
import StreamLiveView from './StreamLiveView.js';

// UTILITIES
import Sound from '../../node_modules/react-sound';
import $ from '../../public/js/jquery-1.11.1.min';

var BASE_URL = window.protocol + document.location.host;

class StreamLive extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      status: "STOPPED",
      disabled: false,
      desc: "",
      name: "",
      broadcaster: "",
      broadcasterImage: "",
      streamImage: "",
      listenerLiveCount: "",
      listenerTotalCount: "",
      listenerMaxCount: "",
      heartCount: 0,
      creator: "",
      isLoading: true,
      image: "",
      soundcloud: "",
      website: "",
      websiteTitle: "",
      streamId: this.props.params.streamId || window.location.pathname.substr(8)
    }
  }

  componentDidMount() {
    this.fetchStreamData();

    //add bclient on handler here
    window.bClient.on('stream', function(data, meta) {
      if (meta.type === 'event') {
        if (meta.action === 'enterStream' || meta.action === 'leaveStream' || meta.action === 'upHeart') {
          console.log('onEnterStream-' + meta.streamId);
          if (meta.streamId === this.state.streamId) {

            $.ajax({
              url: BASE_URL + '/api/stream/' + this.state.streamId
            })
            .done((streamData) => {
              $.ajax({
                url: BASE_URL + '/api/user/' + streamData.creator
              })
              .done((userData) => {
                this.setState({
                  listenerLiveCount: streamData.listenerLiveCount,
                  listenerMaxCount: streamData.listenerMaxCount,
                  listenerTotalCount: streamData.listenerTotalCount,
                  heartCount: streamData.heartCountNum
                });
              });
            });
          }
        }
      }
    }.bind(this));

  }

  componentWillUnmount(){
    var PUT_NOLISTENER = BASE_URL + '/api/nolistener/' + this.state.streamId;
     $.ajax({
      url: PUT_NOLISTENER,
      method: 'PUT',
      contentType: "application/x-www-form-urlencoded",
      data: ''
    }).done((responseData) => {
      leaveStream(this.state.streamId);
    });
  }

  playSong() {
    this.setState({
      status: "PLAYING",
      disabled: true
    });
  }

  stopSong() {
    this.setState({
      status: "STOPPED",
      disabled: false
    });
  }

  addHeart() {
    var PUT_HEART = BASE_URL + '/api/stream/' + this.state.streamId;

    // As of iOS 9.3 and OSX 10.11, Safari does not support fetch
    $.ajax({
      url: PUT_HEART,
      method: 'PUT',
      contentType: "application/x-www-form-urlencoded",
      data: ''
    })
    .done((responseData) => {
      upHeart(this.props.params.streamId);
      this.setState({
        heartCount: responseData.heartCountNum.length > 5 ? '> 9,999' : responseData.heartCountNum
      });
    });
  }

  fetchStreamData() {
    $.ajax({
      url: BASE_URL + '/api/stream/' + this.state.streamId
    })
    .done((streamData) => {
      $.ajax({
        url: BASE_URL + '/api/user/' + streamData.creator
      })
      .done((userData) => {
        this.setState({
          name: streamData.name,
          broadcaster: streamData.broadcaster,
          desc: streamData.description,
          listenerLiveCount: streamData.listenerLiveCount,
          creator: streamData.creator,
          heartCount: streamData.heartCountNum,
          listenerMaxCount: streamData.listenerMaxCount,
          listenerTotalCount: streamData.listenerTotalCount,
          isLoading: false,
          broadcasterImage: userData.user.scAvatarUri,
          streamImage: streamData.streamImage,
          soundcloud: userData.user.scPermalink,
          website: userData.user.website,
          websiteTitle: userData.user.websiteTitle
        });
      });
    });
  }

  render() {
    var partial = <Loading />;

    if (!this.state.isLoading) {
      partial = <StreamLiveView
        state={this.state}
        playSong={this.playSong.bind(this)}
        stopSong={this.stopSong.bind(this)}
        addHeart={this.addHeart.bind(this)}
      />
    }
    return (

          <NavBar title={'Now Playing'} history={this.history} />
          {partial}

        <Sound
          url={'/stream/' + this.state.streamId}
          playStatus={this.state.status}
          onLoading={this.handleSongLoading}
          onPlaying={this.handleSongPlaying}
          onFinishedPlaying={this.handleSongFinishedPlaying} />

    )
  }
}

var styles = {
  container: {
    'display': 'flex',
    'flexDirection': 'column',
  }
}

reactMixin.onClass(StreamLive, History);

export default StreamLive;<commit_msg>Material Design and code styling.<commit_after>import React from 'react';

// ROUTER
import {
  History
}
from 'react-router';
import reactMixin from 'react-mixin';

// COMPONENTS
import NavBar from './NavBar.js';
import Loading from './Loading.js'
import StreamLiveView from './StreamLiveView.js';

// UTILITIES
import Sound from '../../node_modules/react-sound';
import $ from '../../public/js/jquery-1.11.1.min';

// MATERIAL UI
import Card from 'material-ui/lib/card/card';

var BASE_URL = window.protocol + document.location.host;

class StreamLive extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      status: "STOPPED",
      disabled: false,
      desc: "",
      name: "",
      broadcaster: "",
      broadcasterImage: "",
      streamImage: "",
      listenerLiveCount: "",
      listenerTotalCount: "",
      listenerMaxCount: "",
      heartCount: 0,
      creator: "",
      isLoading: true,
      image: "",
      soundcloud: "",
      website: "",
      websiteTitle: "",
      streamId: this.props.params.streamId || window.location.pathname.substr(8)
    }
  }

  componentDidMount() {
    this.fetchStreamData();

    window.bClient.on('stream', function(data, meta) {
      if (meta.type === 'event'
      && (meta.action === 'enterStream' || meta.action === 'leaveStream' || meta.action === 'upHeart')
      && meta.streamId === this.state.streamId) {
        $.ajax({
          url: BASE_URL + '/api/stream/' + this.state.streamId
        })
        .done((streamData) => {
          $.ajax({
            url: BASE_URL + '/api/user/' + streamData.creator
          })
          .done((userData) => {
            this.setState({
              listenerLiveCount: streamData.listenerLiveCount,
              listenerMaxCount: streamData.listenerMaxCount,
              listenerTotalCount: streamData.listenerTotalCount,
              heartCount: streamData.heartCountNum
            });
          });
        });
      }
    }.bind(this));

  }

  componentWillUnmount(){
    var PUT_NOLISTENER = BASE_URL + '/api/nolistener/' + this.state.streamId;
     $.ajax({
      url: PUT_NOLISTENER,
      method: 'PUT',
      contentType: "application/x-www-form-urlencoded",
      data: ''
    }).done((responseData) => {
      leaveStream(this.state.streamId);
    });
  }

  playSong() {
    this.setState({
      status: "PLAYING",
      disabled: true
    });
  }

  stopSong() {
    this.setState({
      status: "STOPPED",
      disabled: false
    });
  }

  addHeart() {
    var PUT_HEART = BASE_URL + '/api/stream/' + this.state.streamId;

    // As of iOS 9.3 and OSX 10.11, Safari does not support fetch
    $.ajax({
      url: PUT_HEART,
      method: 'PUT',
      contentType: "application/x-www-form-urlencoded",
      data: ''
    })
    .done((responseData) => {
      upHeart(this.props.params.streamId);
      this.setState({
        heartCount: responseData.heartCountNum.length > 5 ? '> 9,999' : responseData.heartCountNum
      });
    });
  }

  fetchStreamData() {
    $.ajax({
      url: BASE_URL + '/api/stream/' + this.state.streamId
    })
    .done((streamData) => {
      $.ajax({
        url: BASE_URL + '/api/user/' + streamData.creator
      })
      .done((userData) => {
        this.setState({
          name: streamData.name,
          broadcaster: streamData.broadcaster,
          desc: streamData.description,
          listenerLiveCount: streamData.listenerLiveCount,
          creator: streamData.creator,
          heartCount: streamData.heartCountNum,
          listenerMaxCount: streamData.listenerMaxCount,
          listenerTotalCount: streamData.listenerTotalCount,
          isLoading: false,
          broadcasterImage: userData.user.scAvatarUri,
          streamImage: streamData.streamImage,
          soundcloud: userData.user.scPermalink,
          website: userData.user.website,
          websiteTitle: userData.user.websiteTitle
        });
      });
    });
  }

  render() {
    var partial = <Loading />;

    if (!this.state.isLoading) {
      partial = <StreamLiveView
        state={this.state}
        playSong={this.playSong.bind(this)}
        stopSong={this.stopSong.bind(this)}
        addHeart={this.addHeart.bind(this)}
      />
    }
    return (

        <Card style={styles.container}>
          <NavBar title={'Now Playing'} history={this.history} />
          {partial}
        </Card>

        <Sound
          url={'/stream/' + this.state.streamId}
          playStatus={this.state.status}
          onLoading={this.handleSongLoading}
          onPlaying={this.handleSongPlaying}
          onFinishedPlaying={this.handleSongFinishedPlaying} />

    )
  }
}

var styles = {
  container: {
    'display': 'flex',
    'flexDirection': 'column',
  }
}

reactMixin.onClass(StreamLive, History);

export default StreamLive;
<|endoftext|>


<commit_before>'use strict';
/*global process*/

import config from "./config";
import ndVisualization from "./lib/ndVisualization";
import ndConnector from "./lib/ndConnector";
import ndMidi from "./lib/ndMidi";
import ndSelector from "./lib/ndSelector";

// MIDI Controllers
import ndKorgNanoPad2 from "./lib/ndKorgNanoPad2";

 // Container for the NERD DISCO, you might say it's a party.
const container = document.getElementById('nerddisco');

/*
 * Select areas on the canvas
 */
let selectors = [];

[1, 2, 3, 4, 5, 6, 7, 8].forEach(name => {
  selectors.push(new ndSelector({
    parent_element : container,
    selector_element_name : name,
    selector_element_width : config.pixel_per_led_x * config.led_row_amount,
    selector_element_height : config.pixel_per_led_y * config.led_column_amount
  }));
});

/**
 * Handle all visualzations on canvas
 */
const visualization = new ndVisualization({
  parent_element : container,
  drawing_activated : true,
  drawing_permanent : false,
  drawing_square_size_x : 400,
  drawing_square_size_y : 100,
  led_row_amount : config.led_row_amount,
  led_column_amount : config.led_column_amount,
  pixel_per_led_x : config.pixel_per_led_x,
  pixel_per_led_y : config.pixel_per_led_y,
  selectors : selectors
});

/**
 * Connect the client to the server over socket.io
 */
const websocket = new ndConnector({
  url : 'localhost:1337'
});

/**
 * Control MIDI devices.
 */
const midi = new ndMidi({
  debug : false
});
const nanopad2 = new ndKorgNanoPad2();

/*
 * Observable all the things \0_0/
 */
nanopad2.listen();

/**
 * Update everything:
 * - canvas
 * - LED
 * - audio data
 */
let fps = 60;
let data;

function update() {
  visualization.draw();
  data = visualization.getLEDs();
  websocket.sendLEDs(data);

  // console.log(data.length, data);

  setTimeout(function() {
    window.requestAnimationFrame(update);
  }, 1000 / fps);
}

update();
<commit_msg>Added a lot of ndParticleGroups for every part of the edrum to ndVisualization.<commit_after>'use strict';
/*global process*/

import config from "./config";
import ndVisualization from "./lib/ndVisualization";
import ndParticleGroup from "./lib/ndParticleGroup";
import ndConnector from "./lib/ndConnector";
import ndMidi from "./lib/ndMidi";
import ndSelector from "./lib/ndSelector";

// MIDI Controllers
import ndKorgNanoPad2 from "./lib/ndKorgNanoPad2";
import ndXDrumDD530 from "./lib/ndXDrumDD530";

 // Container for the NERD DISCO, you might say it's a party.
const container = document.getElementById('nerddisco');

/*
 * Select areas on the canvas
 */
let selectors = [];

[1, 2, 3, 4, 5, 6, 7, 8].forEach(name => {
  selectors.push(new ndSelector({
    parent_element : container,
    selector_element_name : name,
    selector_element_width : config.pixel_per_led_x * config.led_row_amount,
    selector_element_height : config.pixel_per_led_y * config.led_column_amount
  }));
});

/**
 * Handle all visualzations on canvas
 */
const visualization = new ndVisualization({
  parent_element : container,
  drawing_activated : false,
  drawing_permanent : false,
  drawing_square_size_x : 400,
  drawing_square_size_y : 100,
  led_row_amount : config.led_row_amount,
  led_column_amount : config.led_column_amount,
  pixel_per_led_x : config.pixel_per_led_x,
  pixel_per_led_y : config.pixel_per_led_y,
  selectors : selectors
});

/**
 * Connect the client to the server over socket.io
 */
const websocket = new ndConnector({
  url : 'localhost:1337'
});

/**
 * Control MIDI devices.
 */
const midi = new ndMidi({
  debug : false
});

const nanopad2 = new ndKorgNanoPad2();
const edrum = new ndXDrumDD530();

/*
 * Observable all the things \0_0/
 */
//nanopad2.listen();
edrum.listen();

let w = 35 / 2;

visualization.addElement(new ndParticleGroup({ name : 'snare', x : 0, color : 'red' }));
visualization.addElement(new ndParticleGroup({ name : 'tom1', x : -w, color : 'green' }));
visualization.addElement(new ndParticleGroup({ name : 'tom2', x : -w * 1.5, color : 'blue' }));
visualization.addElement(new ndParticleGroup({ name : 'tom3', x : -w * 2, color : 'orange' }));
visualization.addElement(new ndParticleGroup({ name : 'crash', x : -w * 2.5, color : 'yellow' }));
visualization.addElement(new ndParticleGroup({ name : 'ride', x : w, color : 'purple' }));
visualization.addElement(new ndParticleGroup({ name : 'hihat_open', x : w * 1.5, color : 'khaki' }));
visualization.addElement(new ndParticleGroup({ name : 'kick', x : w * 2, color : 'greenyellow' }));

/**
 * Update everything:
 * - canvas
 * - LED
 * - audio data
 */
let fps = 60;
let data;

function update() {
  visualization.draw();
  data = visualization.getLEDs();
  websocket.sendLEDs(data);

  // console.log(data.length, data);

  setTimeout(function() {
    window.requestAnimationFrame(update);
  }, 1000 / fps);
}

update();
<|endoftext|>


<commit_before>$(document).on('rex:ready', function() {
    var root = $("#rex-quicknavigation-structure");
    if (root) {
        $.post(root.data('url')).done(function(quickNav) {
            root.html(quickNav);
        });
    }
});

$(document).on("shown.bs.dropdown", function() {
    quicknavi_filter_init();
    var ctype = getUrlVars()["ctype"];
    if (ctype) {
        $(".quicknavi a").attr('href', function(i, h) {
            return h + (h.indexOf('?') != -1 ? "&ctype=" + ctype : "?ctype=" + ctype);
        });
    }

    $('.quicknavi').hover(function() {

    });

    $(this).find(".dropdown-menu li.bg-primary a").focus();

    $('#qsearch').delay(200).fadeIn(function() {
        $('.dropdown-menu.quicknavi li:first-child input').focus();
    });

});

function quicknavi_filter_init() {
    $('#qsearch').keyup(function() {
        var current_query = $('#qsearch').val();
        if (current_query !== "") {
            $(".quicknavi.list-group li.quickitem").hide();
            $(".quicknavi.list-group li.quickitem").each(function() {
                var current_keyword = $(this).text();
                var current_keyword_uppercase = current_keyword.toUpperCase();
                var uppercase = current_query.toUpperCase();

                if ((current_keyword.indexOf(current_query) >= 0) || (current_keyword_uppercase.indexOf(uppercase) >= 0)) {
                    $(this).show();
                }

            });
        } else {
            $(".quicknavi.list-group li.quickitem").show();
        }
    });
}

function getUrlVars() {
    var vars = {};
    var parts = window.location.href.replace(/[?&]+([^=&]+)=([^&]*)/gi, function(m, key, value) {
        vars[key] = value;
    });
    return vars;
}
<commit_msg>unnötigen code entfernt<commit_after>$(document).on('rex:ready', function() {
    var root = $("#rex-quicknavigation-structure");
    if (root) {
        $.post(root.data('url')).done(function(quickNav) {
            root.html(quickNav);
        });
    }
});

$(document).on("shown.bs.dropdown", function() {
    quicknavi_filter_init();
    var ctype = getUrlVars()["ctype"];
    if (ctype) {
        $(".quicknavi a").attr('href', function(i, h) {
            return h + (h.indexOf('?') != -1 ? "&ctype=" + ctype : "?ctype=" + ctype);
        });
    }

    $(this).find(".dropdown-menu li.bg-primary a").focus();

    $('#qsearch').delay(200).fadeIn(function() {
        $('.dropdown-menu.quicknavi li:first-child input').focus();
    });

});

function quicknavi_filter_init() {
    $('#qsearch').keyup(function() {
        var current_query = $('#qsearch').val();
        if (current_query !== "") {
            $(".quicknavi.list-group li.quickitem").hide();
            $(".quicknavi.list-group li.quickitem").each(function() {
                var current_keyword = $(this).text();
                var current_keyword_uppercase = current_keyword.toUpperCase();
                var uppercase = current_query.toUpperCase();

                if ((current_keyword.indexOf(current_query) >= 0) || (current_keyword_uppercase.indexOf(uppercase) >= 0)) {
                    $(this).show();
                }

            });
        } else {
            $(".quicknavi.list-group li.quickitem").show();
        }
    });
}

function getUrlVars() {
    var vars = {};
    var parts = window.location.href.replace(/[?&]+([^=&]+)=([^&]*)/gi, function(m, key, value) {
        vars[key] = value;
    });
    return vars;
}
<|endoftext|>


<commit_before>// Public object
SockJS = (function(){
              var _document = document;
              var _window = window;
              var utils = {};

<!-- include lib/reventtarget.js -->
<!-- include lib/simpleevent.js -->
<!-- include lib/eventemitter.js -->
<!-- include lib/utils.js -->
<!-- include lib/dom.js -->
<!-- include lib/dom2.js -->
<!-- include lib/sockjs.js -->
<!-- include lib/trans-websocket.js -->
<!-- include lib/trans-sender.js -->
<!-- include lib/trans-jsonp-receiver.js -->
<!-- include lib/trans-jsonp-polling.js -->
<!-- include lib/trans-xhr.js -->
<!-- include lib/trans-iframe.js -->
<!-- include lib/trans-iframe-within.js -->
<!-- include lib/info.js -->
<!-- include lib/trans-iframe-eventsource.js -->
<!-- include lib/trans-iframe-xhr-polling.js -->
<!-- include lib/trans-iframe-htmlfile.js -->
<!-- include lib/trans-polling.js -->
<!-- include lib/trans-receiver-eventsource.js -->
<!-- include lib/trans-receiver-htmlfile.js -->
<!-- include lib/trans-receiver-xhr.js -->
<!-- include lib/test-hooks.js -->
                  return SockJS;
          })();
if ('_sockjs_onload' in window) setTimeout(_sockjs_onload, 1);
<commit_msg>Fix #53 - AMD compliance<commit_after>// Public object
SockJS = (function(){
              var _document = document;
              var _window = window;
              var utils = {};

<!-- include lib/reventtarget.js -->
<!-- include lib/simpleevent.js -->
<!-- include lib/eventemitter.js -->
<!-- include lib/utils.js -->
<!-- include lib/dom.js -->
<!-- include lib/dom2.js -->
<!-- include lib/sockjs.js -->
<!-- include lib/trans-websocket.js -->
<!-- include lib/trans-sender.js -->
<!-- include lib/trans-jsonp-receiver.js -->
<!-- include lib/trans-jsonp-polling.js -->
<!-- include lib/trans-xhr.js -->
<!-- include lib/trans-iframe.js -->
<!-- include lib/trans-iframe-within.js -->
<!-- include lib/info.js -->
<!-- include lib/trans-iframe-eventsource.js -->
<!-- include lib/trans-iframe-xhr-polling.js -->
<!-- include lib/trans-iframe-htmlfile.js -->
<!-- include lib/trans-polling.js -->
<!-- include lib/trans-receiver-eventsource.js -->
<!-- include lib/trans-receiver-htmlfile.js -->
<!-- include lib/trans-receiver-xhr.js -->
<!-- include lib/test-hooks.js -->
                  return SockJS;
          })();
if ('_sockjs_onload' in window) setTimeout(_sockjs_onload, 1);

// AMD compliance
if (typeof define === 'function' && define.amd) {
    define('sockjs', [], function(){return SockJS;});
}
<|endoftext|>


<commit_before>/*global require */
var $ = require('jquery');
var api = require('../js/api');
var test = require('tape');
var response = require('./fixtures/article/1.json');
var utils = require('./utils');

test("test component api", function(t) {
  t.plan(2);
  var slug = 'test';
  var server = utils.mock_component(slug, response);
  var callback = function(data) {
    t.ok(data, 'data is returned');
    t.equal(data['slug'], slug, 'slug is returned');
    server.restore();
    t.end();
  };
  var promise = api.component(slug, callback);
  $.when(promise).done(function() {
    //maybe a test here?
  });
});

test("test component api's use of localstorage", function(t) {
  t.plan(2);
  var localSlug = 'localtest';
  var localResponse = 'test local data';
  localStorage.setItem(localSlug, localResponse);
  var promise = api.component(localSlug, function(response) {
    t.equal(response, localResponse, 'component pulls from localstorage');
    t.end();
  });//pulls from local are sync, thank goodness
  t.equal( promise.state(), 'resolved', 'promise is resolved as expected');
  setTimeout(function() {
    t.end()
  }, 100);
});

<commit_msg>stash changes breaking<commit_after>/*global require */
var $ = require('jquery');
var api = require('../js/api');
var test = require('tape');
var response = require('./fixtures/article/1.json');
var utils = require('./utils');

module.exports = {
  "beforeEach": function() {

  },
  "component api": {
    "get" : function() {
      var slug = 'test';
      var server = utils.mock_component(slug, response);
      var callback = function(data) {
        should.exist.ok(data, 'data is returned');
        t.equal(data['slug'], slug, 'slug is returned');
        server.restore();
        t.end();
      };
      var promise = api.component(slug, callback);
      $.when(promise).done(function() {
        //maybe a test here?
      });
    }
  }
}

test("test component api's use of localstorage", function(t) {
  t.plan(2);
  var localSlug = 'localtest';
  var localResponse = 'test local data';
  localStorage.setItem(localSlug, localResponse);
  var promise = api.component(localSlug, function(response) {
    t.equal(response, localResponse, 'component pulls from localstorage');
    t.end();
  });//pulls from local are sync, thank goodness
  t.equal( promise.state(), 'resolved', 'promise is resolved as expected');
  setTimeout(function() {
    t.end()
  }, 100);
});

<|endoftext|>


<commit_before><commit_msg>calculate times and sine wave<commit_after><|endoftext|>


<commit_before>const { readFileSync, writeFileSync, existsSync } = require('fs')
const elementTree = require('elementtree')
const { relative } = require('path')
const { red, green } = require('kolorist')

const { resolveDir } = require('../utils/app-paths')
const { log, warn } = require('../utils/logger')
const spawnSync = require('../utils/spawn-sync')

const cordovaConfigXml = resolveDir('src-cordova/config.xml')
const srcCordovaDir = resolveDir('src-cordova')

const platformList = [ 'cordova-android', 'cordova-ios' ]
const generatorList = [ 'png', 'splashscreen' ]

function getNode (root, tag, selector) {
  return (
    root.find(`${tag}${selector}`) ||
    elementTree.SubElement(root, tag)
  )
}

function hasNode (root, tag, selector) {
  return root.find(`${tag}${selector}`)
}

function isCordovaFile (file) {
  return platformList.includes(file.platform) &&
    generatorList.includes(file.generator)
}

function getCordovaFiles (files) {
  const cordovaFiles = []

  files.forEach(file => {
    if (isCordovaFile(file)) {
      cordovaFiles.push(file)
    }
  })

  return cordovaFiles
}

function updateConfigXml (cordovaFiles, hasSplashscreen) {
  const doc = elementTree.parse(readFileSync(cordovaConfigXml, 'utf-8'))
  const rootNode = doc.getroot()

  if (hasSplashscreen && !rootNode.find('preference[@name="SplashMaintainAspectRatio"]')) {
    const prefNode = elementTree.SubElement(rootNode, 'preference')
    prefNode.set('name', 'SplashMaintainAspectRatio')
    prefNode.set('value', 'true')
  }

  const androidNode = getNode(rootNode, 'platform', '[@name="android"]')
  const iosNode = getNode(rootNode, 'platform', '[@name="ios"]')

  cordovaFiles.forEach(file => {
    const isAndroid = file.platform === 'cordova-android'
    const node = isAndroid ? androidNode : iosNode
    const src = relative(srcCordovaDir, file.absoluteName)
      .replace(/\\/g, '/') // Windows support

    if (file.generator === 'splashscreen') {
      // <splash src="res/screen/android/splash-land-hdpi.png" density="land-hdpi"/>
      // <splash src="res/screen/ios/Default@2x~ipad~comany.png" />

      const entry = getNode(
        node,
        'splash',
        isAndroid ? `[@density="${file.density}"]` : `[@src="${src}"]`
      )

      entry.set('src', src)

      if (isAndroid) {
        entry.set('density', file.density)
      }
    }
    else if (file.generator === 'png') {
      // <icon src="res/android/ldpi.png" density="ldpi" />
      // <icon src="res/ios/icon-60@3x.png" width="180" height="180" />

      const entry = getNode(
        node,
        'icon',
        isAndroid
          ? `[@density="${file.density}"]`
          : `[@width="${file.width}"][@height="${file.height}"]`
      )

      entry.set('src', src)

      if (isAndroid) {
        entry.set('density', file.density)
      }
      else {
        entry.set('width', file.width)
        entry.set('height', file.height)
      }
    }
  })

  writeFileSync(cordovaConfigXml, doc.write({ indent: 4 }), 'utf-8')
  log(`Updated src-cordova/config.xml`)
}

function hasDeepProp (target /* , param1, param2, ... */) {
  let obj = target

  for (let i = 1; i < arguments.length; i++) {
    const prop = arguments[i]
    obj = obj[prop]

    if (obj === void 0) {
      return false
    }
  }

  return true
}

function installSplashscreenPlugin () {
  const pkgPath = resolveDir('src-cordova/package.json')

  if (!existsSync(pkgPath)) {
    // malformed /src-cordova...
    return
  }

  const pkg = require(pkgPath)

  if (
    hasDeepProp(pkg, 'dependencies', 'cordova-plugin-splashscreen') ||
    hasDeepProp(pkg, 'cordova', 'plugins', 'cordova-plugin-splashscreen')
  ) {
    // it's already installed, so nothing to do
    return
  }

  log(`Installing cordova-plugin-splashscreen...`)

  spawnSync('cordova', [ 'plugin', 'add', 'cordova-plugin-splashscreen' ], {
    cwd: srcCordovaDir
  }, () => {
    warn()
    warn('Failed to install cordova-plugin-splashscreen. Please do it manually.')
    console.log(' -> /src-cordova: $ cordova plugin add cordova-plugin-splashscreen\n')
  })

  console.log()
}

module.exports.mountCordova = function mountCordova (files) {
  if (existsSync(cordovaConfigXml)) {
    const cordovaFiles = getCordovaFiles(files)

    if (cordovaFiles.length > 0) {
      const hasSplashscreen = cordovaFiles.some(file => file.generator === 'splashscreen')

      if (hasSplashscreen) {
        installSplashscreenPlugin()
      }

      updateConfigXml(cordovaFiles, hasSplashscreen)
    }
  }
}

module.exports.isCordovaFile = isCordovaFile

module.exports.verifyCordova = function verifyCordova (file) {
  if (isCordovaFile(file) && existsSync(cordovaConfigXml)) {
    const doc = elementTree.parse(readFileSync(cordovaConfigXml, 'utf-8'))
    const isAndroid = file.platform === 'cordova-android'

    const node = doc.getroot()
      .find(`platform[@name="${isAndroid ? 'android' : 'ios'}"]`)

    // verify that the platform is installed
    if (!node) {
      return red('ERROR: platform not installed!')
    }

    const src = relative(srcCordovaDir, file.absoluteName)

    if (file.generator === 'splashscreen') {
      const selector = isAndroid
        ? `[@density="${file.density}"]`
        : `[@src="${src}"]`

      if (!hasNode(node, 'splash', selector)) {
        return red('ERROR: no entry for it in src-cordova/config.xml')
      }
    }
    else {
      const selector = isAndroid
        ? `[@density="${file.density}"]`
        : `[@width="${file.width}"][@height="${file.height}"]`

      if (!hasNode(node, 'icon', selector)) {
        return red('ERROR: no entry for it in src-cordova/config.xml')
      }
    }

    return green('mounted')
  }
}
<commit_msg>fix(icongenie): Icongenie does not add name="android" and name="iOS" to platform tags #12948<commit_after>const { readFileSync, writeFileSync, existsSync } = require('fs')
const elementTree = require('elementtree')
const { relative } = require('path')
const { red, green } = require('kolorist')

const { resolveDir } = require('../utils/app-paths')
const { log, warn } = require('../utils/logger')
const spawnSync = require('../utils/spawn-sync')

const cordovaConfigXml = resolveDir('src-cordova/config.xml')
const srcCordovaDir = resolveDir('src-cordova')

const platformList = [ 'cordova-android', 'cordova-ios' ]
const generatorList = [ 'png', 'splashscreen' ]

function getNode (root, tag, selector) {
  return (
    root.find(`${tag}${selector}`) ||
    elementTree.SubElement(root, tag)
  )
}

function hasNode (root, tag, selector) {
  return root.find(`${tag}${selector}`)
}

function isCordovaFile (file) {
  return platformList.includes(file.platform) &&
    generatorList.includes(file.generator)
}

function getCordovaFiles (files) {
  const cordovaFiles = []

  files.forEach(file => {
    if (isCordovaFile(file)) {
      cordovaFiles.push(file)
    }
  })

  return cordovaFiles
}

function updateConfigXml (cordovaFiles, hasSplashscreen) {
  const doc = elementTree.parse(readFileSync(cordovaConfigXml, 'utf-8'))
  const rootNode = doc.getroot()

  if (hasSplashscreen && !rootNode.find('preference[@name="SplashMaintainAspectRatio"]')) {
    const prefNode = elementTree.SubElement(rootNode, 'preference')
    prefNode.set('name', 'SplashMaintainAspectRatio')
    prefNode.set('value', 'true')
  }

  const androidNode = getNode(rootNode, 'platform', '[@name="android"]')
  if (androidNode.get('name') === void 0) {
    androidNode.set('name', 'android')
  }

  const iosNode = getNode(rootNode, 'platform', '[@name="ios"]')
  if (iosNode.get('name') === void 0) {
    iosNode.set('name', 'ios')
  }

  cordovaFiles.forEach(file => {
    const isAndroid = file.platform === 'cordova-android'
    const node = isAndroid ? androidNode : iosNode
    const src = relative(srcCordovaDir, file.absoluteName)
      .replace(/\\/g, '/') // Windows support

    if (file.generator === 'splashscreen') {
      // <splash src="res/screen/android/splash-land-hdpi.png" density="land-hdpi"/>
      // <splash src="res/screen/ios/Default@2x~ipad~comany.png" />

      const entry = getNode(
        node,
        'splash',
        isAndroid ? `[@density="${file.density}"]` : `[@src="${src}"]`
      )

      entry.set('src', src)

      if (isAndroid) {
        entry.set('density', file.density)
      }
    }
    else if (file.generator === 'png') {
      // <icon src="res/android/ldpi.png" density="ldpi" />
      // <icon src="res/ios/icon-60@3x.png" width="180" height="180" />

      const entry = getNode(
        node,
        'icon',
        isAndroid
          ? `[@density="${file.density}"]`
          : `[@width="${file.width}"][@height="${file.height}"]`
      )

      entry.set('src', src)

      if (isAndroid) {
        entry.set('density', file.density)
      }
      else {
        entry.set('width', file.width)
        entry.set('height', file.height)
      }
    }
  })

  writeFileSync(cordovaConfigXml, doc.write({ indent: 4 }), 'utf-8')
  log(`Updated src-cordova/config.xml`)
}

function hasDeepProp (target /* , param1, param2, ... */) {
  let obj = target

  for (let i = 1; i < arguments.length; i++) {
    const prop = arguments[i]
    obj = obj[prop]

    if (obj === void 0) {
      return false
    }
  }

  return true
}

function installSplashscreenPlugin () {
  const pkgPath = resolveDir('src-cordova/package.json')

  if (!existsSync(pkgPath)) {
    // malformed /src-cordova...
    return
  }

  const pkg = require(pkgPath)

  if (
    hasDeepProp(pkg, 'dependencies', 'cordova-plugin-splashscreen') ||
    hasDeepProp(pkg, 'cordova', 'plugins', 'cordova-plugin-splashscreen')
  ) {
    // it's already installed, so nothing to do
    return
  }

  log(`Installing cordova-plugin-splashscreen...`)

  spawnSync('cordova', [ 'plugin', 'add', 'cordova-plugin-splashscreen' ], {
    cwd: srcCordovaDir
  }, () => {
    warn()
    warn('Failed to install cordova-plugin-splashscreen. Please do it manually.')
    console.log(' -> /src-cordova: $ cordova plugin add cordova-plugin-splashscreen\n')
  })

  console.log()
}

module.exports.mountCordova = function mountCordova (files) {
  if (existsSync(cordovaConfigXml)) {
    const cordovaFiles = getCordovaFiles(files)

    if (cordovaFiles.length > 0) {
      const hasSplashscreen = cordovaFiles.some(file => file.generator === 'splashscreen')

      if (hasSplashscreen) {
        installSplashscreenPlugin()
      }

      updateConfigXml(cordovaFiles, hasSplashscreen)
    }
  }
}

module.exports.isCordovaFile = isCordovaFile

module.exports.verifyCordova = function verifyCordova (file) {
  if (isCordovaFile(file) && existsSync(cordovaConfigXml)) {
    const doc = elementTree.parse(readFileSync(cordovaConfigXml, 'utf-8'))
    const isAndroid = file.platform === 'cordova-android'

    const node = doc.getroot()
      .find(`platform[@name="${isAndroid ? 'android' : 'ios'}"]`)

    // verify that the platform is installed
    if (!node) {
      return red('ERROR: platform not installed!')
    }

    const src = relative(srcCordovaDir, file.absoluteName)

    if (file.generator === 'splashscreen') {
      const selector = isAndroid
        ? `[@density="${file.density}"]`
        : `[@src="${src}"]`

      if (!hasNode(node, 'splash', selector)) {
        return red('ERROR: no entry for it in src-cordova/config.xml')
      }
    }
    else {
      const selector = isAndroid
        ? `[@density="${file.density}"]`
        : `[@width="${file.width}"][@height="${file.height}"]`

      if (!hasNode(node, 'icon', selector)) {
        return red('ERROR: no entry for it in src-cordova/config.xml')
      }
    }

    return green('mounted')
  }
}
<|endoftext|>


<commit_before>import React, {Component, PropTypes} from 'react';

import injectF from './../../helpers/injectF';
import Heading from './../Heading/Heading';

const styles = require('./PageAbout.scss');

@injectF
export default class PageAbout extends Component {

  static propTypes = {
    f: PropTypes.func.isRequired
  };

  render() {
    const {f} = this.props;
    return (

        <Heading>{f('about')}</Heading>

    );
  }
}
<commit_msg>display appVersion in container PageAbout<commit_after>import React, {Component, PropTypes} from 'react';
import {connect} from 'react-redux';

import injectF from './../../helpers/injectF';
import Heading from './../Heading/Heading';

const styles = require('./PageAbout.scss');

@connect(({main}) => ({
  appVersion: main.get('appVersion')
}))
@injectF
export default class PageAbout extends Component {

  static propTypes = {
    f: PropTypes.func.isRequired,
    appVersion: PropTypes.string.isRequired
  };

  render() {
    const {f, appVersion} = this.props;
    return (

        <Heading>{f('about-version', {appVersion})}</Heading>

    );
  }
}
<|endoftext|>


<commit_before>"use strict";

const fs        = require("fs");
const merge     = require("merge");
const minimatch = require("minimatch");

/**
 * Configurações
 *
 * @constructor
 * @param {string[]} pattern Padrão de Captura
 * @param {fs}       fs      Manipulador de Sistema de Arquivos
 */
function Config (pattern, fs)
{
    this.setPattern(pattern);
    this.setFs(fs);
};

/**
 * Configura o Padrão de Captura
 *
 * @param  {string[]} pattern Valores para Configuração
 * @return undefined
 */
Config.prototype.setPattern = function (pattern)
{
    this._pattern = pattern;
};

/**
 * Apresenta o Padrão de Captura
 *
 * @return {string[]} Valores Configurados
 */
Config.prototype.getPattern = function ()
{
    return this._pattern;
};

/**
 * Configura o Manipulador de Sistema de Arquivos
 *
 * @param  {fs}      aFs Elemento para Configuração
 * @return undefined
 */
Config.prototype.setFs = function (aFs)
{
    this._fs = aFs || fs;
};

/**
 * Apresenta o Manipulador de Sistema de Arquivos
 *
 * @return {fs} Elemento Configurado
 */
Config.prototype.getFs = function ()
{
    return this._fs;
};

/**
 * Busca Nomes de Arquivos
 *
 * @return {string[]} Lista de Arquivos Encontrados
 */
Config.prototype._fetchFilenames = function ()
{
    // Inicialização
    var fs        = this.getFs();
    var pattern   = this.getPattern();
    var filenames = [];
    // Função: Captura Recursiva
    var fn = function (directory) {
        // Leitura de Diretório
        fs.readdirSync(directory).forEach(function (filename) {
            // Caminho Completo
            filename = directory + "/" + filename;
            // Diretório?
            if (fs.statSync(filename).isDirectory()) {
                // Recursão
                fn(filename);
                return;
            }
            // Captura
            filenames.push(filename.substr(2));
        });
    };
    // Execução
    fn(".");
    // Apresentação
    return filenames.filter(function (filename) {
        return pattern.filter(function (pattern) {
            return minimatch(filename, pattern);
        }).length > 0;
    });
};

/**
 * Mescla Elementos de Configuração
 *
 * Recebe como parâmetro um conjunto de objetos que possuem dois parâmetros: `filename` e `content`. Apresenta como
 * resultado os parâmetros `content` mesclados em ordem alfabética de `filename`.
 *
 * @param  {object[]} elements Informações para Mesclagem
 * @return object     Elemento Resultante
 */
Config.prototype._merge = function (elements)
{
    // Ordenação
    elements.sort(function (a, b) {
        return a.filename.localeCompare(b.filename);
    });

    // Apresentação
    return elements.reduce(function (elements, item) {
        return merge(elements, item.content);
    }, {});
};

/**
 * Busca Configurações
 *
 * @return {Promise} Execução Assíncrona
 */
Config.prototype.fetch = function ()
{
    // Inicialização
    var pattern = this.getPattern();
    var fs      = this.getFs();

    // Capturar Arquivos
    var filenames = this._fetchFilenames();

    // Execuções Assíncronas
    var promises = [];

    // Consulta
    filenames.forEach(function (filename) {
        // Execução Assíncrona
        promises.push(new Promise(function (resolve, reject) {
            // Tratamento
            try {
                // Carregar Arquivo
                var content = fs.readFileSync(filename);
                // Sucesso!
                var element = {"filename": filename, "content": JSON.parse(content)};
                // Apresentação
                resolve(element);
            } catch (error) {
                // Impossível Continuar
                reject(error);
            }
        }));
    });

    // Execução
    return Promise.all(promises).then(this._merge);
};

// Configuração
module.exports = Config;
<commit_msg>Encapsula leitura de arquivo único<commit_after>"use strict";

const fs        = require("fs");
const merge     = require("merge");
const minimatch = require("minimatch");

/**
 * Configurações
 *
 * @constructor
 * @param {string[]} pattern Padrão de Captura
 * @param {fs}       fs      Manipulador de Sistema de Arquivos
 */
function Config (pattern, fs)
{
    this.setPattern(pattern);
    this.setFs(fs);
};

/**
 * Configura o Padrão de Captura
 *
 * @param  {string[]} pattern Valores para Configuração
 * @return undefined
 */
Config.prototype.setPattern = function (pattern)
{
    this._pattern = pattern;
};

/**
 * Apresenta o Padrão de Captura
 *
 * @return {string[]} Valores Configurados
 */
Config.prototype.getPattern = function ()
{
    return this._pattern;
};

/**
 * Configura o Manipulador de Sistema de Arquivos
 *
 * @param  {fs}      aFs Elemento para Configuração
 * @return undefined
 */
Config.prototype.setFs = function (aFs)
{
    this._fs = aFs || fs;
};

/**
 * Apresenta o Manipulador de Sistema de Arquivos
 *
 * @return {fs} Elemento Configurado
 */
Config.prototype.getFs = function ()
{
    return this._fs;
};

/**
 * Busca Nomes de Arquivos
 *
 * @return {string[]} Lista de Arquivos Encontrados
 */
Config.prototype._fetchFilenames = function ()
{
    // Inicialização
    var fs        = this.getFs();
    var pattern   = this.getPattern();
    var filenames = [];
    // Função: Captura Recursiva
    var fn = function (directory) {
        // Leitura de Diretório
        fs.readdirSync(directory).forEach(function (filename) {
            // Caminho Completo
            filename = directory + "/" + filename;
            // Diretório?
            if (fs.statSync(filename).isDirectory()) {
                // Recursão
                fn(filename);
                return;
            }
            // Captura
            filenames.push(filename.substr(2));
        });
    };
    // Execução
    fn(".");
    // Apresentação
    return filenames.filter(function (filename) {
        return pattern.filter(function (pattern) {
            return minimatch(filename, pattern);
        }).length > 0;
    });
};

/**
 * Mescla Elementos de Configuração
 *
 * Recebe como parâmetro um conjunto de objetos que possuem dois parâmetros: `filename` e `content`. Apresenta como
 * resultado os parâmetros `content` mesclados em ordem alfabética de `filename`.
 *
 * @param  {object[]} elements Informações para Mesclagem
 * @return object     Elemento Resultante
 */
Config.prototype._merge = function (elements)
{
    // Ordenação
    elements.sort(function (a, b) {
        return a.filename.localeCompare(b.filename);
    });

    // Apresentação
    return elements.reduce(function (elements, item) {
        return merge(elements, item.content);
    }, {});
};

/**
 * Lê Arquivo de Forma Síncrona
 *
 * Executa a leitura do arquivo informado como parâmetro, apresentando um objeto que representa o seu conteúdo. Caso
 * algum problema seja encontrado, atira um objeto de erro.
 *
 * @param  {string} filename Nome do Arquivo
 * @throws {Error}  Erro Encontrado durante Processamento
 * @return {object} Objeto que Representa o Conteúdo do Arquivo
 */
Config.prototype._readSync = function (filename)
{
    return JSON.parse(this.getFs().readFileSync(filename));
};

/**
 * Busca Configurações
 *
 * @return {Promise} Execução Assíncrona
 */
Config.prototype.fetch = function ()
{
    // Inicialização
    var self    = this;
    var pattern = this.getPattern();
    var fs      = this.getFs();

    // Capturar Arquivos
    var filenames = this._fetchFilenames();

    // Execuções Assíncronas
    var promises = [];

    // Consulta
    filenames.forEach(function (filename) {
        // Execução Assíncrona
        promises.push(new Promise(function (resolve, reject) {
            // Tratamento
            try {
                // Sucesso!
                var element = {"filename": filename, "content": self._readSync(filename)};
                // Apresentação
                resolve(element);
            } catch (error) {
                // Impossível Continuar
                reject(error);
            }
        }));
    });

    // Execução
    return Promise.all(promises).then(this._merge);
};

// Configuração
module.exports = Config;
<|endoftext|>