<commit_before>'use strict';

var expect = require('chai').expect;
var Promise = require('bluebird');
var mongodb = require('mongodb');
var MongoClient = mongodb.MongoClient;
var entity = require('@back4app/back4app-entity');
var classes = entity.utils.classes;
var objects = entity.utils.objects;
var Adapter = entity.adapters.Adapter;
var Entity = entity.models.Entity;
var AssociationAttribute = entity.models.attributes.types.AssociationAttribute;

var QueryError = require('./errors').QueryError;

module.exports = MongoAdapter;

/**
 * MongoDB adapter for back{4}app's entities.
 * @constructor
 * @memberof module:back4app-entity-mongodb
 * @extends {module:back4app-entity/adapters.Adapter}
 * @param {!string} connectionUrl The connection url for MongoDB as specified in
 * {@link
 * https://mongodb.github.io/node-mongodb-native/api-generated/mongoclient.html
 * }.
 * @param {?Object} [connectionOptions] The optional connection parameter for
 * MongoDB as specified in
 * {@link
 * https://mongodb.github.io/node-mongodb-native/api-generated/mongoclient.html
 * }.
 * @example
 * require('back4app-entity').settings.ADAPTERS = {
 *   default: new MongoAdapter('127.0.0.1', '51764')
 * };
 */
function MongoAdapter(connectionUrl, connectionOptions) {
  Adapter.call(this);

  var _database = null;
  var _databaseIsLocked = false;
  var _databaseRequestQueue = [];

  this.getDatabase = getDatabase;
  this.openConnection = openConnection;
  this.closeConnection = closeConnection;

  expect(arguments).to.have.length.within(
    1,
    2,
    'Invalid arguments length when creating a new MongoAdapter ' +
    '(it has to be passed from 1 to 2 arguments)'
  );

  expect(connectionUrl).to.be.a(
    'string',
    'Invalid argument "connectionUrl" when creating a new MongoAdapter  (it ' +
    'has to be a string)'
  );

  if (connectionOptions) {
    expect(connectionOptions).to.be.a(
      'object',
      'Invalid argument "connectionOptions" when creating a new MongoAdapter ' +
      '(it has to be an object)'
    );
  } else {
    connectionOptions = null;
  }

  function getDatabase() {
    var mongoAdapter = this;

    expect(arguments).to.have.length(
      0,
      'Invalid arguments length when getting a database in a MongoAdapter ' +
      '(it has to be passed no arguments)'
    );

    return new Promise(function (resolve, reject) {
      if (_databaseIsLocked || !_database) {
        mongoAdapter
          .openConnection()
          .then(function () {
            resolve(_database);
          })
          .catch(function (error) {
            reject(error);
          });
      } else {
        resolve(_database);
      }
    });
  }

  /**
   * Connects the adapter with the targeted Mongo database.
   * @name module:back4app-entity-mongodb.MongoAdapter#openConnection
   * @function
   * @returns {Promise.<undefined|Error>} Promise that returns nothing if
   * succeed and the Error if failed.
   * @example
   * mongoAdapter.openConnection()
   *   .then(function () {
 *     console.log('success');
 *   })
   *   .catch(function (error) {
 *     console.log(error);
 *   });
   */
  function openConnection() {
    expect(arguments).to.have.length(
      0,
      'Invalid arguments length when opening a connection in a MongoAdapter ' +
      '(it has to be passed no arguments)'
    );

    return new Promise(function (resolve, reject) {
      if (_databaseIsLocked) {
        _databaseRequestQueue.push(function () {
          openConnection().then(resolve).catch(reject);
        });
      } else if (_database) {
        resolve();
      } else {
        _databaseIsLocked = true;

        MongoClient
          .connect(connectionUrl, connectionOptions)
          .then(function (database) {
            _database = database;
            _databaseIsLocked = false;
            resolve();
            _processDatabaseRequestQueue();
          })
          .catch(function (error) {
            _databaseIsLocked = false;
            reject(error);
            _processDatabaseRequestQueue();
          });
      }
    });
  }

  /**
   * Closes the current adapter' connection with MongoDB.
   * @name module:back4app-entity-mongodb.MongoAdapter#closeConnection
   * @function
   * @returns {Promise.<undefined|Error>} Promise that returns nothing if
   * succeed and the Error if failed.
   * @example
   * mongoAdapter.closeConnection()
   *   .then(function (result) {
   *     console.log(result);
   *   })
   *   .catch(function (error) {
   *     console.log(error);
   *   });
   */
  function closeConnection() {
    expect(arguments).to.have.length(
      0,
      'Invalid arguments length when closing a connection in a MongoAdapter ' +
      '(it has to be passed no arguments)'
    );

    return new Promise(function (resolve, reject) {
      if (_databaseIsLocked) {
        _databaseRequestQueue.push(function () {
          closeConnection()
            .then(resolve)
            .catch(reject);
        });
      } else if (!_database) {
        resolve();
      } else {
        _databaseIsLocked = true;
        _database
          .close()
          .then(function () {
            _database = null;
            _databaseIsLocked = false;
            resolve();
            _processDatabaseRequestQueue();
          })
          .catch(function (error) {
            _databaseIsLocked = false;
            reject(error);
            _processDatabaseRequestQueue();
          });
      }
    });
  }

  function _processDatabaseRequestQueue() {
    while (_databaseRequestQueue.length > 0) {
      _databaseRequestQueue.splice(0,1)[0]();
    }
  }
}

classes.generalize(Adapter, MongoAdapter);

MongoAdapter.prototype.loadAttribute = loadAttribute;
MongoAdapter.prototype.insertObject = insertObject;
//MongoAdapter.prototype.instanceToJSON = instanceToJSON;
MongoAdapter.prototype.getObject = getObject;

function loadAttribute(Entity, attribute) {
  var dataName = attribute.getDataName(Entity.adapterName);

  expect(dataName).to.not.match(
    /^\$/,
    'The dataName of an Attribute cannot start with "$" in a MongoAdapter'
  );

  expect(dataName).to.not.contain(
    '.',
    'The dataName of an Attribute cannot contain "." in a MongoAdapter'
  );
}

function insertObject() {
  return this
    .getDatabase()
    .then(function (database) {
      return database;
    });
}

//function instanceToJSON(instance) {
//  var json = {};
//  for (var key in instance.Entity.attributes) {
//    json[key] = instance[key];
//  }
//
//  if (instance.id) {
//    json._id = instance.id;
//  }
//
//  return json;
//}

function getObject(EntityClass, query) {
  var cursor;
  var document;

  function findDocument(db) {
    // copy query to not mess with user's object
    query = objects.copy(query);

    // rename id field
    if (query.hasOwnProperty('id')) {
      query._id = query.id;
      delete query.id;
    }

    // find collection name
    var GeneralClass = EntityClass;
    while (GeneralClass.General !== Entity) {
      GeneralClass = GeneralClass.General;
    }
    var name = GeneralClass.specification.name;

    // perform query
    cursor = db.collection(name).find(query);
    return cursor.next();
  }

  function checkNotEmpty(doc) {
    // check for no result
    if (doc === null) {
      throw new QueryError('Object does not exist');
    }
    // save document
    document = doc;
  }

  function checkNotMultiple() {
    // check for multiple results
    return cursor.hasNext()
      .then(function (hasNext) {
        if (hasNext) {
          throw new QueryError('Query matches multiple objects');
        }
      });
  }

  function populateEntity() {
    // return populated entity
    return _documentToObject(document);
  }

  return this.getDatabase()
    .then(findDocument)
    .then(checkNotEmpty)
    .then(checkNotMultiple)
    .then(populateEntity);
}

function _documentToObject(document) {
  var obj = objects.copy(document);

  // replace `_id` with `id`
  if (obj.hasOwnProperty('_id')) {
    obj.id = obj._id;
    delete obj._id;
  }

  // get document class and remove `Entity`
  var EntityClass = Entity.getSpecialization(obj.Entity);
  delete obj.Entity;

  // loop through entity's attributes and replace associations with instances
  var attributes = EntityClass.specification.attributes;
  for (var attrName in attributes) {
    if (attributes.hasOwnProperty(attrName) && obj.hasOwnProperty(attrName)) {
      // check for association
      var attr = attributes[attrName];
      if (attr instanceof AssociationAttribute) {
        var multiplicity = attr.multiplicity;
        if (multiplicity === '1' || multiplicity === '0..1') {
          // single related object
          obj[attrName] = _documentToObject(obj[attrName]);
        } else {
          // array of related objects
          var items = obj[attrName];
          for (var i = 0; i < items.length; i++) {
            items[i] = _documentToObject(items[i]);
          }
        }
      }
    }
  }

  return new EntityClass(obj);
}
<commit_msg>Add documentation and argument check for getObject<commit_after>'use strict';

var expect = require('chai').expect;
var Promise = require('bluebird');
var mongodb = require('mongodb');
var MongoClient = mongodb.MongoClient;
var entity = require('@back4app/back4app-entity');
var classes = entity.utils.classes;
var objects = entity.utils.objects;
var Adapter = entity.adapters.Adapter;
var Entity = entity.models.Entity;
var AssociationAttribute = entity.models.attributes.types.AssociationAttribute;

var QueryError = require('./errors').QueryError;

module.exports = MongoAdapter;

/**
 * MongoDB adapter for back{4}app's entities.
 * @constructor
 * @memberof module:back4app-entity-mongodb
 * @extends {module:back4app-entity/adapters.Adapter}
 * @param {!string} connectionUrl The connection url for MongoDB as specified in
 * {@link
 * https://mongodb.github.io/node-mongodb-native/api-generated/mongoclient.html
 * }.
 * @param {?Object} [connectionOptions] The optional connection parameter for
 * MongoDB as specified in
 * {@link
 * https://mongodb.github.io/node-mongodb-native/api-generated/mongoclient.html
 * }.
 * @example
 * require('back4app-entity').settings.ADAPTERS = {
 *   default: new MongoAdapter('127.0.0.1', '51764')
 * };
 */
function MongoAdapter(connectionUrl, connectionOptions) {
  Adapter.call(this);

  var _database = null;
  var _databaseIsLocked = false;
  var _databaseRequestQueue = [];

  this.getDatabase = getDatabase;
  this.openConnection = openConnection;
  this.closeConnection = closeConnection;

  expect(arguments).to.have.length.within(
    1,
    2,
    'Invalid arguments length when creating a new MongoAdapter ' +
    '(it has to be passed from 1 to 2 arguments)'
  );

  expect(connectionUrl).to.be.a(
    'string',
    'Invalid argument "connectionUrl" when creating a new MongoAdapter  (it ' +
    'has to be a string)'
  );

  if (connectionOptions) {
    expect(connectionOptions).to.be.a(
      'object',
      'Invalid argument "connectionOptions" when creating a new MongoAdapter ' +
      '(it has to be an object)'
    );
  } else {
    connectionOptions = null;
  }

  function getDatabase() {
    var mongoAdapter = this;

    expect(arguments).to.have.length(
      0,
      'Invalid arguments length when getting a database in a MongoAdapter ' +
      '(it has to be passed no arguments)'
    );

    return new Promise(function (resolve, reject) {
      if (_databaseIsLocked || !_database) {
        mongoAdapter
          .openConnection()
          .then(function () {
            resolve(_database);
          })
          .catch(function (error) {
            reject(error);
          });
      } else {
        resolve(_database);
      }
    });
  }

  /**
   * Connects the adapter with the targeted Mongo database.
   * @name module:back4app-entity-mongodb.MongoAdapter#openConnection
   * @function
   * @returns {Promise.<undefined|Error>} Promise that returns nothing if
   * succeed and the Error if failed.
   * @example
   * mongoAdapter.openConnection()
   *   .then(function () {
 *     console.log('success');
 *   })
   *   .catch(function (error) {
 *     console.log(error);
 *   });
   */
  function openConnection() {
    expect(arguments).to.have.length(
      0,
      'Invalid arguments length when opening a connection in a MongoAdapter ' +
      '(it has to be passed no arguments)'
    );

    return new Promise(function (resolve, reject) {
      if (_databaseIsLocked) {
        _databaseRequestQueue.push(function () {
          openConnection().then(resolve).catch(reject);
        });
      } else if (_database) {
        resolve();
      } else {
        _databaseIsLocked = true;

        MongoClient
          .connect(connectionUrl, connectionOptions)
          .then(function (database) {
            _database = database;
            _databaseIsLocked = false;
            resolve();
            _processDatabaseRequestQueue();
          })
          .catch(function (error) {
            _databaseIsLocked = false;
            reject(error);
            _processDatabaseRequestQueue();
          });
      }
    });
  }

  /**
   * Closes the current adapter' connection with MongoDB.
   * @name module:back4app-entity-mongodb.MongoAdapter#closeConnection
   * @function
   * @returns {Promise.<undefined|Error>} Promise that returns nothing if
   * succeed and the Error if failed.
   * @example
   * mongoAdapter.closeConnection()
   *   .then(function (result) {
   *     console.log(result);
   *   })
   *   .catch(function (error) {
   *     console.log(error);
   *   });
   */
  function closeConnection() {
    expect(arguments).to.have.length(
      0,
      'Invalid arguments length when closing a connection in a MongoAdapter ' +
      '(it has to be passed no arguments)'
    );

    return new Promise(function (resolve, reject) {
      if (_databaseIsLocked) {
        _databaseRequestQueue.push(function () {
          closeConnection()
            .then(resolve)
            .catch(reject);
        });
      } else if (!_database) {
        resolve();
      } else {
        _databaseIsLocked = true;
        _database
          .close()
          .then(function () {
            _database = null;
            _databaseIsLocked = false;
            resolve();
            _processDatabaseRequestQueue();
          })
          .catch(function (error) {
            _databaseIsLocked = false;
            reject(error);
            _processDatabaseRequestQueue();
          });
      }
    });
  }

  function _processDatabaseRequestQueue() {
    while (_databaseRequestQueue.length > 0) {
      _databaseRequestQueue.splice(0,1)[0]();
    }
  }
}

classes.generalize(Adapter, MongoAdapter);

MongoAdapter.prototype.loadAttribute = loadAttribute;
MongoAdapter.prototype.insertObject = insertObject;
//MongoAdapter.prototype.instanceToJSON = instanceToJSON;
MongoAdapter.prototype.getObject = getObject;

function loadAttribute(Entity, attribute) {
  var dataName = attribute.getDataName(Entity.adapterName);

  expect(dataName).to.not.match(
    /^\$/,
    'The dataName of an Attribute cannot start with "$" in a MongoAdapter'
  );

  expect(dataName).to.not.contain(
    '.',
    'The dataName of an Attribute cannot contain "." in a MongoAdapter'
  );
}

function insertObject() {
  return this
    .getDatabase()
    .then(function (database) {
      return database;
    });
}

//function instanceToJSON(instance) {
//  var json = {};
//  for (var key in instance.Entity.attributes) {
//    json[key] = instance[key];
//  }
//
//  if (instance.id) {
//    json._id = instance.id;
//  }
//
//  return json;
//}

/**
 * Get object from the database matching given query.
 * @name module:back4app-entity-mongodb.MongoAdapter#getObject
 * @function
 * @returns {Promise.<object|Error>} Promise that returns found object if
 * succeed or Error if failed.
 * @example
 * mongoAdapter.getObject(Car, {color: 'red'})
 *   .then(function(car) {
 *     console.log(car);
 *   });
 */
function getObject(EntityClass, query) {
  expect(arguments).to.have.length(
    2,
    'Invalid arguments length when inserting an object in a MongoAdapter ' +
    '(it has to be passed 2 arguments)'
  );

  var cursor;
  var document;

  function findDocument(db) {
    // copy query to not mess with user's object
    query = objects.copy(query);

    // rename id field
    if (query.hasOwnProperty('id')) {
      query._id = query.id;
      delete query.id;
    }

    // find collection name
    var GeneralClass = EntityClass;
    while (GeneralClass.General !== Entity) {
      GeneralClass = GeneralClass.General;
    }
    var name = GeneralClass.specification.name;

    // perform query
    cursor = db.collection(name).find(query);
    return cursor.next();
  }

  function checkNotEmpty(doc) {
    // check for no result
    if (doc === null) {
      throw new QueryError('Object does not exist');
    }
    // save document
    document = doc;
  }

  function checkNotMultiple() {
    // check for multiple results
    return cursor.hasNext()
      .then(function (hasNext) {
        if (hasNext) {
          throw new QueryError('Query matches multiple objects');
        }
      });
  }

  function populateEntity() {
    // return populated entity
    return _documentToObject(document);
  }

  return this.getDatabase()
    .then(findDocument)
    .then(checkNotEmpty)
    .then(checkNotMultiple)
    .then(populateEntity);
}

function _documentToObject(document) {
  var obj = objects.copy(document);

  // replace `_id` with `id`
  if (obj.hasOwnProperty('_id')) {
    obj.id = obj._id;
    delete obj._id;
  }

  // get document class and remove `Entity`
  var EntityClass = Entity.getSpecialization(obj.Entity);
  delete obj.Entity;

  // loop through entity's attributes and replace associations with instances
  var attributes = EntityClass.specification.attributes;
  for (var attrName in attributes) {
    if (attributes.hasOwnProperty(attrName) && obj.hasOwnProperty(attrName)) {
      // check for association
      var attr = attributes[attrName];
      if (attr instanceof AssociationAttribute) {
        var multiplicity = attr.multiplicity;
        if (multiplicity === '1' || multiplicity === '0..1') {
          // single related object
          obj[attrName] = _documentToObject(obj[attrName]);
        } else {
          // array of related objects
          var items = obj[attrName];
          for (var i = 0; i < items.length; i++) {
            items[i] = _documentToObject(items[i]);
          }
        }
      }
    }
  }

  return new EntityClass(obj);
}
<|endoftext|>


<commit_before>this.recline = this.recline || {};
this.recline.Backend = this.recline.Backend || {};
this.recline.Backend.DataProxy = this.recline.Backend.DataProxy || {};

(function($, my) {
  my.__type__ = 'dataproxy';
  // URL for the dataproxy
  my.dataproxy_url = 'http://jsonpdataproxy.appspot.com';

  // ## load
  //
  // Load data from a URL via the [DataProxy](http://github.com/okfn/dataproxy).
  //
  // Returns array of field names and array of arrays for records
  my.fetch = function(dataset) {
    var data = {
      url: dataset.url,
      'max-results':  dataset.size || dataset.rows || 1000,
      type: dataset.format || ''
    };
    var jqxhr = $.ajax({
      url: my.dataproxy_url,
      data: data,
      dataType: 'jsonp'
    });
    var dfd = $.Deferred();
    _wrapInTimeout(jqxhr).done(function(results) {
      if (results.error) {
        dfd.reject(results.error);
      }

      dfd.resolve({
        records: results.data,
        fields: results.fields,
        useMemoryStore: true
      });
    })
    .fail(function(arguments) {
      dfd.reject(arguments);
    });
    return dfd.promise();
  };

  // ## _wrapInTimeout
  //
  // Convenience method providing a crude way to catch backend errors on JSONP calls.
  // Many of backends use JSONP and so will not get error messages and this is
  // a crude way to catch those errors.
  var _wrapInTimeout = function(ourFunction) {
    var dfd = $.Deferred();
    var timeout = 5000;
    var timer = setTimeout(function() {
      dfd.reject({
        message: 'Request Error: Backend did not respond after ' + (timeout / 1000) + ' seconds'
      });
    }, timeout);
    ourFunction.done(function(arguments) {
        clearTimeout(timer);
        dfd.resolve(arguments);
      })
      .fail(function(arguments) {
        clearTimeout(timer);
        dfd.reject(arguments);
      })
      ;
    return dfd.promise();
  }

}(jQuery, this.recline.Backend.DataProxy));
<commit_msg>[be/dataproxy][xs]: dataproxy timeout is now configurable (defaults to 5s).<commit_after>this.recline = this.recline || {};
this.recline.Backend = this.recline.Backend || {};
this.recline.Backend.DataProxy = this.recline.Backend.DataProxy || {};

(function($, my) {
  my.__type__ = 'dataproxy';
  // URL for the dataproxy
  my.dataproxy_url = 'http://jsonpdataproxy.appspot.com';
  // Timeout for dataproxy (after this time if no response we error)
  // Needed because use JSONP so do not receive e.g. 500 errors
  my.timeout = 5000;

  // ## load
  //
  // Load data from a URL via the [DataProxy](http://github.com/okfn/dataproxy).
  //
  // Returns array of field names and array of arrays for records
  my.fetch = function(dataset) {
    var data = {
      url: dataset.url,
      'max-results':  dataset.size || dataset.rows || 1000,
      type: dataset.format || ''
    };
    var jqxhr = $.ajax({
      url: my.dataproxy_url,
      data: data,
      dataType: 'jsonp'
    });
    var dfd = $.Deferred();
    _wrapInTimeout(jqxhr).done(function(results) {
      if (results.error) {
        dfd.reject(results.error);
      }

      dfd.resolve({
        records: results.data,
        fields: results.fields,
        useMemoryStore: true
      });
    })
    .fail(function(arguments) {
      dfd.reject(arguments);
    });
    return dfd.promise();
  };

  // ## _wrapInTimeout
  //
  // Convenience method providing a crude way to catch backend errors on JSONP calls.
  // Many of backends use JSONP and so will not get error messages and this is
  // a crude way to catch those errors.
  var _wrapInTimeout = function(ourFunction) {
    var dfd = $.Deferred();
    var timer = setTimeout(function() {
      dfd.reject({
        message: 'Request Error: Backend did not respond after ' + (my.timeout / 1000) + ' seconds'
      });
    }, my.timeout);
    ourFunction.done(function(arguments) {
        clearTimeout(timer);
        dfd.resolve(arguments);
      })
      .fail(function(arguments) {
        clearTimeout(timer);
        dfd.reject(arguments);
      })
      ;
    return dfd.promise();
  }

}(jQuery, this.recline.Backend.DataProxy));
<|endoftext|>


<commit_before>define(['arches', 'knockout', 'viewmodels/concept-widget'], function (arches, ko, ConceptWidgetViewModel) {
    var name = 'concept-datatype-config';
    ko.components.register(name, {
        viewModel: function(params) {
            this.search = params.search;
            if (this.search) {
                var self = this;
                var filter = params.filterValue();
                params.config = ko.observable({options:[]});
                this.op = ko.observable(filter.op || '');
                this.placeholder = ko.observable('Select a concept');
                this.multiple = ko.observable(false);
                this.searchValue = ko.observable(filter.val || '');
                this.node = params.node;
                this.node.config.rdmCollection = ko.observable(this.node.config.rdmCollection);
                ConceptWidgetViewModel.apply(this, [params]);
                this.filterValue = ko.computed(function () {
                    return {
                        op: self.op(),
                        val: self.searchValue()
                    }
                });
                params.filterValue(this.filterValue());
                this.filterValue.subscribe(function (val) {
                    params.filterValue(val);
                });
            } else {
                this.topConcept = params.config.rdmCollection;
                this.conceptCollections = arches.conceptCollections;
                this.conceptCollections.unshift({
                  'label': null,
                  'id': null
                })
            }
        },
        template: { require: 'text!datatype-config-templates/concept' }
    });
    return name;
});
<commit_msg>Fixed issue with concept values not reloading when a concept facet is removed and re-added, re #2031<commit_after>define(['arches', 'knockout', 'viewmodels/concept-widget'], function (arches, ko, ConceptWidgetViewModel) {
    var name = 'concept-datatype-config';
    ko.components.register(name, {
        viewModel: function(params) {
            this.search = params.search;
            if (this.search) {
                var self = this;
                var filter = params.filterValue();
                params.config = ko.observable({options:[]});
                this.op = ko.observable(filter.op || '');
                this.placeholder = ko.observable('Select a concept');
                this.multiple = ko.observable(false);
                this.searchValue = ko.observable(filter.val || '');
                this.node = params.node;
                if (!ko.isObservable(this.node.config.rdmCollection)) {
                    this.node.config.rdmCollection = ko.observable(this.node.config.rdmCollection);
                }
                ConceptWidgetViewModel.apply(this, [params]);
                this.filterValue = ko.computed(function () {
                    return {
                        op: self.op(),
                        val: self.searchValue()
                    }
                });
                params.filterValue(this.filterValue());
                this.filterValue.subscribe(function (val) {
                    params.filterValue(val);
                });
            } else {
                this.topConcept = params.config.rdmCollection;
                this.conceptCollections = arches.conceptCollections;
                this.conceptCollections.unshift({
                  'label': null,
                  'id': null
                })
            }
        },
        template: { require: 'text!datatype-config-templates/concept' }
    });
    return name;
});
<|endoftext|>


<commit_before>import * as search from 'searchtabular';
import React, { Component } from 'react';
import Item from './Item';
import SearchBar from './Search';
import { compose } from 'redux';
import { multiInfix } from '../../helpers/utils';

class List extends Component {

	render() {
    const { query, rows } = this.props;
    const columns = this.props.fields.map((field) => field={
      property: field.name,
      header: {
        label: field.label,
      },
      filterType:field.filterType,
    });

    const searchExecutor = search.multipleColumns({
      columns,
      query,
      strategy: multiInfix });
    const visibleItems = compose(searchExecutor)(rows);

		return (

 List View

			 <SearchBar
          filter={this.props.filter}
          fields={this.props.fields}
          onFilter={this.props.onFilter}
        />
        {visibleItems.map(item =>
          <Item
            item={item}
            fields={this.props.fields}
            onEdit={this.props.onEdit}
            onDelete={this.props.onDelete}
            key={item.id}
          />
        )}

		);
	}
}

export default List;<commit_msg>Cleaned up formatting<commit_after>import * as search from 'searchtabular';
import React, { Component } from 'react';
import Item from './Item';
import SearchBar from './Search';
import { compose } from 'redux';
import { multiInfix } from '../../helpers/utils';

class List extends Component {

	render() {
    const { query, rows } = this.props;
    const columns = this.props.fields.map((field) => ({
      property: field.name,
      header: {
        label: field.label,
      },
      filterType:field.filterType,
    }));

    const searchExecutor = search.multipleColumns({
      columns,
      query,
      strategy: multiInfix });
    const visibleItems = compose(searchExecutor)(rows);

		return (

 List View

			 <SearchBar
          filter={this.props.filter}
          fields={this.props.fields}
          onFilter={this.props.onFilter}
        />
        {visibleItems.map(item =>
          <Item
            item={item}
            fields={this.props.fields}
            onEdit={this.props.onEdit}
            onDelete={this.props.onDelete}
            key={item.id}
          />
        )}

		);
	}
}

export default List;<|endoftext|>


<commit_before>define(["js/ui/View", "js/core/Bus", "sprd/manager/ProductManager", "sprd/data/ImageService", "designer/manager/FeatureManager", "sprd/entity/ConcreteElement"], function (View, Bus, ProductManager, ImageService, FeatureManager, ConcreteElement) {
    return View.inherit('sprd.view.ProductViewerClass', {

        defaults: {
            view: null,
            product: null,
            width: 300,
            height: 300,
            selectedConfiguration: null,
            editable: true,
            focused: true,

            autoDeselectConfiguration: true,
            showConfigurationInformation: false,

            productViewerSvg: null,

            removeEmptyTextConfiguration: true,
            removeNewConfigurations: false,
            bringSelectedConfigurationToFront: true,

            imageService: null,

            error: "{product.configurationsOnViewError(view)}",
            componentClass: "product-viewer",

            copiedConfiguration: null,
            zoomToPrintArea: 0,
            maxZoom: 1
        },

        inject: {
            bus: Bus,
            productManager: ProductManager,
            imageService: ImageService,
            featureManager: FeatureManager,
            concreteElement: ConcreteElement
        },

        events: ['on:configurationSelect', "on:deselectConfiguration"],

        ctor: function () {
            this.callBase();
            this.bind('productViewerSvg', 'add:configurationViewer', this._onConfigurationViewerAdded, this);
            this.bind('product.configurations', 'reset', this._onConfigurationsReset, this);
            this.bind('product', 'change:configurations', this._onConfigurationsReset, this);
            this.bind('product.configurations', 'remove', this._onConfigurationRemoved , this);
            this.bind('product.configurations', 'add', this._onConfigurationAdded, this);
        },

        _initializationComplete: function () {
            this.callBase();
            var product = this.$.product;

            if (!product) {
                return;
            }

            var configurations = product.$.configurations;

            if (configurations.length === 0) {
                return;
            }

            this.set('selectedConfiguration', configurations.at(0));
        },

        _commitSelectedConfiguration: function (selectedConfiguration, oldSelectedConfiguration) {
            var activeElement = document.activeElement;
            selectedConfiguration && activeElement && activeElement.blur && activeElement.blur();
            if (this.$.product && oldSelectedConfiguration && (oldSelectedConfiguration.type === "text" || oldSelectedConfiguration.type === "specialText")) {
                if (oldSelectedConfiguration.$.isNew && this.$.removeNewConfigurations) {
                    this.$.product.$.configurations.remove(oldSelectedConfiguration);
                }
                if (this.$.removeEmptyTextConfiguration
                    && oldSelectedConfiguration.$.textFlow) {

                    var text = oldSelectedConfiguration.$.textFlow.text(0, -1);
                    if (/^[\s\n\r]*$/.test(text)) {
                        this.$.product.$.configurations.remove(oldSelectedConfiguration);
                    }
                }

            }
        },

        _commitView: function (view) {
            if (view) {
                this.set('selectedConfiguration', null);
            }
        },

        _onConfigurationAdded: function (e) {
            var product = this.$.product,
                configsOnCurrentView = product.getConfigurationsOnView(),
                addedConfig = e.$.item;

            if (addedConfig && _.indexOf(configsOnCurrentView, addedConfig) !== -1) {
                this.set('selectedConfiguration', e.$.item);
            }
        },

        _onConfigurationRemoved: function (e) {
            if (e.$.item === this.$.selectedConfiguration) {
                this.set('selectedConfiguration', null);
            }
        },

        keyUp: function (e) {

        },

        keyPress: function (e) {
            this._keyPressHandler(e.domEvent);
        },

        keyDown: function (e) {
            this._keyDownHandler(e.domEvent);
        },

        _onConfigurationsReset: function () {
            var configurations = this.$.product.$.configurations,
                selectedConfiguration = this.$.selectedConfiguration;

            if (!configurations.contains(selectedConfiguration)) {
                this.set('selectedConfiguration', null);
            }
        },

        _onConfigurationViewerAdded: function (e) {
            var viewer = e.$;
            if (viewer) {
                if (viewer.$.configuration === this.$.selectedConfiguration) {
                    this.set('selectedConfigurationViewer', viewer);
                }
                this.trigger('add:configurationViewer', viewer);
            }
        },

        _clickHandler: function (e) {
            if (this.$.editable && !(e.isDefaultPrevented || e.defaultPrevented)) {

                var previousSelectedConfiguration = this.$.selectedConfiguration;

                if (this.$.autoDeselectConfiguration) {
                    this.$.bus.trigger('ProductViewer.configurationSelected', {configuration: null});
                    this.set('selectedConfiguration', null);
                }

                this.trigger("on:deselectConfiguration", {
                    clickEvent: e,
                    selectedConfiguration: this.$.selectedConfiguration,
                    previousSelectedConfiguration: previousSelectedConfiguration
                });
            }
            e.preventDefault();
            this.set('focused', true);
        },

        _commitChangedAttributes: function ($) {
            this.callBase();
            if ($ && $.hasOwnProperty('selectedConfiguration')) {
                var configuration = $['selectedConfiguration'],
                    viewer = null;

                if (configuration) {
                    viewer = this.getViewerForConfiguration(configuration);
                }

                this.trigger('on:configurationSelect', configuration);
                this.set('selectedConfigurationViewer', viewer);

                if (this.$.bringSelectedConfigurationToFront && viewer && this.$.product.$.configurations.size() > 1) {
                    // rearange configurations in list
                    this.$.product.$.configurations.remove(configuration, {silent: true});
                    this.$.product.$.configurations.add(configuration, {silent: true});
                    // bring viewer to front
                    // timeout is needed here otherwise IE in windows 8
                    // will throw an additional click event
                    // on the underlying element
                    setTimeout(function () {
                        viewer.bringToFront();
                    }, 2)
                }

            }
        },

        getViewerForConfiguration: function (configuration) {
            if (this.$.productViewerSvg) {
                return this.$.productViewerSvg.getViewerForConfiguration(configuration);
            }
            return null;
        },

        getConfigurationsOnActiveView: function (configurations) {
            var self = this,
                printArea = null,
                view = null;

            return configurations.$items.filter(function (configuration) {
                printArea = configuration.$.printArea;
                view = self.$.view;
                return view.containsPrintArea(printArea)
            });
        },

        _keyDownHandler: function (e) {
            var self = this,
                product = self.$.product;

            var viewer = this.$.selectedConfigurationViewer;
            if (viewer) {
                viewer._keyDown(e);
                if (e.defaultPrevented) {
                    return;
                }
            }

            var copiedConfiguration = this.$.copiedConfiguration,
                ctrlKey = e.metaKey || e.ctrlKey;

            var enableCopyPaste = this.$.featureManager.$.enableCopyPaste;

            if (ctrlKey && e.keyCode === 86 && copiedConfiguration && enableCopyPaste) {
                var newConfiguration = copiedConfiguration.clone(),
                    bus = self.$.bus;

                e.preventDefault();
                e.stopPropagation();

                this.$.productManager.moveConfigurationToView(product, newConfiguration, this.$.view, {respectTransform: true}, function (err) {
                    if (err) {
                        bus.trigger("ProductViewer.copyToViewError", err);
                        newConfiguration = null;
                    } else {
                        var configurations = self.$.product.$.configurations,
                            configurationsOnView = self.getConfigurationsOnActiveView(configurations).filter(function (c) {
                                return c !== newConfiguration
                            });

                        var newOffset = newConfiguration.$.offset,
                            newX = Math.round(newOffset.$.x),
                            newY = Math.round(newOffset.$.y);

                        var shift = Math.round((newConfiguration.get("printArea.boundary.size.width") || 500) / 10);

                        for (var i = 0; i < configurationsOnView.length; i++) {

                            var foundConfigurationOnSamePosition = false;

                            for (var j = 0; j < configurationsOnView.length; j++) {
                                var configuration = configurationsOnView[j];

                                var offset = configuration.$.offset,
                                    x = Math.round(offset.$.x),
                                    y = Math.round(offset.$.y);

                                if ((newX == x) && (newY == y)) {
                                    foundConfigurationOnSamePosition = true;
                                    break;
                                }
                            }

                            if (foundConfigurationOnSamePosition) {
                                newX += shift;
                                newY += shift;
                            } else {
                                break;
                            }
                        }

                        newOffset.set({
                            x: newX,
                            y: newY
                        });

                        newConfiguration.$stage = null;
                        bus.setUp(newConfiguration);

                        if (newConfiguration.type == "specialText") {
                            newConfiguration.fetchImage();
                        }
                    }
                });
            }

            var selectedConfiguration = self.$.selectedConfiguration;

            if (selectedConfiguration && product) {

                var deltaX = 0,
                    deltaY = 0;

                switch (e.keyCode) {
                    case 40:
                        deltaY = 1;
                        break;
                    case 38:
                        deltaY = -1;
                        break;
                    case 37:
                        deltaX = -1;
                        break;
                    case 39:
                        deltaX = 1;
                }
                var offset;

                if (deltaX || deltaY) {

                    if (e.shiftKey) {
                        deltaX *= 10;
                        deltaY *= 10;
                    }

                    offset = selectedConfiguration.$.offset.clone();
                    offset.set({
                        x: offset.$.x + deltaX,
                        y: offset.$.y + deltaY
                    });
                    selectedConfiguration.set('offset', offset);

                    this.$configurationMoved = true;
                    e.preventDefault();
                    e.stopPropagation();

                }

                if (e.keyCode === 8 || e.keyCode === 46) {
                    // backspace || delete --> remove selected configuration

                    product.$.configurations.remove(selectedConfiguration);
                    self.set('selectedConfiguration', null);

                    e.preventDefault();
                    e.stopPropagation();
                }

                if (ctrlKey && (e.keyCode === 67 || e.keyCode === 88) && enableCopyPaste) {
                    this.set('copiedConfiguration', selectedConfiguration.clone());

                    if (e.keyCode === 88) {
                        product.$.configurations.remove(selectedConfiguration);
                        self.set('selectedConfiguration', null);
                    }

                    e.preventDefault();
                    e.stopPropagation();
                }
            }

        },

        _keyPressHandler: function (e) {
            var viewer = this.$.selectedConfigurationViewer;
            if (viewer) {
                viewer._keyPress(e);
            }
        },

        _keyUpHandler: function () {
            if (this.$configurationMoved) {
                this.$configurationMoved = false;
                this.$.bus.trigger("Application.productChanged", this.$.product);
            }
        },

        _bindDomEvents: function () {
            if (this.runsInBrowser() && this.$.editable) {
                var self = this;

                this.bind("on:click", this._clickHandler, this);

                this.$stage.bind('on:focus', function () {
                    self.set('focused', true);
                });
                this.callBase();
            }
        },

        deselectConfiguration: function () {
            this.set('selectedConfiguration', null);
        }.bus("ExternalApi.deselectConfiguration"),

        moveConfigurationUp: function () {
            var product = this.$.product;

            if (!product) {
                return;
            }

            var configurations = product.$.configurations,
                configuration = this.$.selectedConfiguration,
                items = configurations.$items;

            var filteredConfigurations = product.getConfigurationsOnView();

            var filteredIndex = filteredConfigurations.indexOf(configuration);

            if (filteredIndex === filteredConfigurations.length - 1) {
                return;
            }

            var successor = filteredConfigurations[filteredIndex + 1];

            var configurationIndex = configurations.indexOf(configuration),
                successorIndex = configurations.indexOf(successor);

            items[configurationIndex] = successor;
            items[successorIndex] = configuration;

            configurations.reset(items);
        }.bus("ExternalApi.layerUp"),

        moveConfigurationDown: function () {
            var product = this.$.product;

            if (!product) {
                return;
            }

            var configurations = product.$.configurations,
                configuration = this.$.selectedConfiguration,
                items = configurations.$items;

            var filteredConfigurations = product.getConfigurationsOnView();

            var filteredIndex = filteredConfigurations.indexOf(configuration);

            if (filteredIndex === 0) {
                return;
            }

            var predecessor = filteredConfigurations[filteredIndex - 1];

            var configurationIndex = configurations.indexOf(configuration),
                predecessorIndex = configurations.indexOf(predecessor);

            items[configurationIndex] = predecessor;
            items[predecessorIndex] = configuration;

            configurations.reset(items);
        }.bus("ExternalApi.layerDown")
    });
});<commit_msg>Moved bus eventhandlers out of productViewer. Would have added an eventhandler for every instance<commit_after>define(["js/ui/View", "js/core/Bus", "sprd/manager/ProductManager", "sprd/data/ImageService", "designer/manager/FeatureManager", "sprd/entity/ConcreteElement"], function (View, Bus, ProductManager, ImageService, FeatureManager, ConcreteElement) {
    return View.inherit('sprd.view.ProductViewerClass', {

        defaults: {
            view: null,
            product: null,
            width: 300,
            height: 300,
            selectedConfiguration: null,
            editable: true,
            focused: true,

            autoDeselectConfiguration: true,
            showConfigurationInformation: false,

            productViewerSvg: null,

            removeEmptyTextConfiguration: true,
            removeNewConfigurations: false,
            bringSelectedConfigurationToFront: true,

            imageService: null,

            error: "{product.configurationsOnViewError(view)}",
            componentClass: "product-viewer",

            copiedConfiguration: null,
            zoomToPrintArea: 0,
            maxZoom: 1
        },

        inject: {
            bus: Bus,
            productManager: ProductManager,
            imageService: ImageService,
            featureManager: FeatureManager,
            concreteElement: ConcreteElement
        },

        events: ['on:configurationSelect', "on:deselectConfiguration"],

        ctor: function () {
            this.callBase();
            this.bind('productViewerSvg', 'add:configurationViewer', this._onConfigurationViewerAdded, this);
            this.bind('product.configurations', 'reset', this._onConfigurationsReset, this);
            this.bind('product', 'change:configurations', this._onConfigurationsReset, this);
            this.bind('product.configurations', 'remove', this._onConfigurationRemoved , this);
            this.bind('product.configurations', 'add', this._onConfigurationAdded, this);
        },

        _initializationComplete: function () {
            this.callBase();
            var product = this.$.product;

            if (!product) {
                return;
            }

            var configurations = product.$.configurations;

            if (configurations.length === 0) {
                return;
            }

            this.set('selectedConfiguration', configurations.at(0));
        },

        _commitSelectedConfiguration: function (selectedConfiguration, oldSelectedConfiguration) {
            var activeElement = document.activeElement;
            selectedConfiguration && activeElement && activeElement.blur && activeElement.blur();
            if (this.$.product && oldSelectedConfiguration && (oldSelectedConfiguration.type === "text" || oldSelectedConfiguration.type === "specialText")) {
                if (oldSelectedConfiguration.$.isNew && this.$.removeNewConfigurations) {
                    this.$.product.$.configurations.remove(oldSelectedConfiguration);
                }
                if (this.$.removeEmptyTextConfiguration
                    && oldSelectedConfiguration.$.textFlow) {

                    var text = oldSelectedConfiguration.$.textFlow.text(0, -1);
                    if (/^[\s\n\r]*$/.test(text)) {
                        this.$.product.$.configurations.remove(oldSelectedConfiguration);
                    }
                }

            }
        },

        _commitView: function (view) {
            if (view) {
                this.set('selectedConfiguration', null);
            }
        },

        _onConfigurationAdded: function (e) {
            var product = this.$.product,
                configsOnCurrentView = product.getConfigurationsOnView(),
                addedConfig = e.$.item;

            if (addedConfig && _.indexOf(configsOnCurrentView, addedConfig) !== -1) {
                this.set('selectedConfiguration', e.$.item);
            }
        },

        _onConfigurationRemoved: function (e) {
            if (e.$.item === this.$.selectedConfiguration) {
                this.set('selectedConfiguration', null);
            }
        },

        keyUp: function (e) {

        },

        keyPress: function (e) {
            this._keyPressHandler(e.domEvent);
        },

        keyDown: function (e) {
            this._keyDownHandler(e.domEvent);
        },

        _onConfigurationsReset: function () {
            var configurations = this.$.product.$.configurations,
                selectedConfiguration = this.$.selectedConfiguration;

            if (!configurations.contains(selectedConfiguration)) {
                this.set('selectedConfiguration', null);
            }
        },

        _onConfigurationViewerAdded: function (e) {
            var viewer = e.$;
            if (viewer) {
                if (viewer.$.configuration === this.$.selectedConfiguration) {
                    this.set('selectedConfigurationViewer', viewer);
                }
                this.trigger('add:configurationViewer', viewer);
            }
        },

        _clickHandler: function (e) {
            if (this.$.editable && !(e.isDefaultPrevented || e.defaultPrevented)) {

                var previousSelectedConfiguration = this.$.selectedConfiguration;

                if (this.$.autoDeselectConfiguration) {
                    this.$.bus.trigger('ProductViewer.configurationSelected', {configuration: null});
                    this.set('selectedConfiguration', null);
                }

                this.trigger("on:deselectConfiguration", {
                    clickEvent: e,
                    selectedConfiguration: this.$.selectedConfiguration,
                    previousSelectedConfiguration: previousSelectedConfiguration
                });
            }
            e.preventDefault();
            this.set('focused', true);
        },

        _commitChangedAttributes: function ($) {
            this.callBase();
            if ($ && $.hasOwnProperty('selectedConfiguration')) {
                var configuration = $['selectedConfiguration'],
                    viewer = null;

                if (configuration) {
                    viewer = this.getViewerForConfiguration(configuration);
                }

                this.trigger('on:configurationSelect', configuration);
                this.set('selectedConfigurationViewer', viewer);

                if (this.$.bringSelectedConfigurationToFront && viewer && this.$.product.$.configurations.size() > 1) {
                    // rearange configurations in list
                    this.$.product.$.configurations.remove(configuration, {silent: true});
                    this.$.product.$.configurations.add(configuration, {silent: true});
                    // bring viewer to front
                    // timeout is needed here otherwise IE in windows 8
                    // will throw an additional click event
                    // on the underlying element
                    setTimeout(function () {
                        viewer.bringToFront();
                    }, 2)
                }

            }
        },

        getViewerForConfiguration: function (configuration) {
            if (this.$.productViewerSvg) {
                return this.$.productViewerSvg.getViewerForConfiguration(configuration);
            }
            return null;
        },

        getConfigurationsOnActiveView: function (configurations) {
            var self = this,
                printArea = null,
                view = null;

            return configurations.$items.filter(function (configuration) {
                printArea = configuration.$.printArea;
                view = self.$.view;
                return view.containsPrintArea(printArea)
            });
        },

        _keyDownHandler: function (e) {
            var self = this,
                product = self.$.product;

            var viewer = this.$.selectedConfigurationViewer;
            if (viewer) {
                viewer._keyDown(e);
                if (e.defaultPrevented) {
                    return;
                }
            }

            var copiedConfiguration = this.$.copiedConfiguration,
                ctrlKey = e.metaKey || e.ctrlKey;

            var enableCopyPaste = this.$.featureManager.$.enableCopyPaste;

            if (ctrlKey && e.keyCode === 86 && copiedConfiguration && enableCopyPaste) {
                var newConfiguration = copiedConfiguration.clone(),
                    bus = self.$.bus;

                e.preventDefault();
                e.stopPropagation();

                this.$.productManager.moveConfigurationToView(product, newConfiguration, this.$.view, {respectTransform: true}, function (err) {
                    if (err) {
                        bus.trigger("ProductViewer.copyToViewError", err);
                        newConfiguration = null;
                    } else {
                        var configurations = self.$.product.$.configurations,
                            configurationsOnView = self.getConfigurationsOnActiveView(configurations).filter(function (c) {
                                return c !== newConfiguration
                            });

                        var newOffset = newConfiguration.$.offset,
                            newX = Math.round(newOffset.$.x),
                            newY = Math.round(newOffset.$.y);

                        var shift = Math.round((newConfiguration.get("printArea.boundary.size.width") || 500) / 10);

                        for (var i = 0; i < configurationsOnView.length; i++) {

                            var foundConfigurationOnSamePosition = false;

                            for (var j = 0; j < configurationsOnView.length; j++) {
                                var configuration = configurationsOnView[j];

                                var offset = configuration.$.offset,
                                    x = Math.round(offset.$.x),
                                    y = Math.round(offset.$.y);

                                if ((newX == x) && (newY == y)) {
                                    foundConfigurationOnSamePosition = true;
                                    break;
                                }
                            }

                            if (foundConfigurationOnSamePosition) {
                                newX += shift;
                                newY += shift;
                            } else {
                                break;
                            }
                        }

                        newOffset.set({
                            x: newX,
                            y: newY
                        });

                        newConfiguration.$stage = null;
                        bus.setUp(newConfiguration);

                        if (newConfiguration.type == "specialText") {
                            newConfiguration.fetchImage();
                        }
                    }
                });
            }

            var selectedConfiguration = self.$.selectedConfiguration;

            if (selectedConfiguration && product) {

                var deltaX = 0,
                    deltaY = 0;

                switch (e.keyCode) {
                    case 40:
                        deltaY = 1;
                        break;
                    case 38:
                        deltaY = -1;
                        break;
                    case 37:
                        deltaX = -1;
                        break;
                    case 39:
                        deltaX = 1;
                }
                var offset;

                if (deltaX || deltaY) {

                    if (e.shiftKey) {
                        deltaX *= 10;
                        deltaY *= 10;
                    }

                    offset = selectedConfiguration.$.offset.clone();
                    offset.set({
                        x: offset.$.x + deltaX,
                        y: offset.$.y + deltaY
                    });
                    selectedConfiguration.set('offset', offset);

                    this.$configurationMoved = true;
                    e.preventDefault();
                    e.stopPropagation();

                }

                if (e.keyCode === 8 || e.keyCode === 46) {
                    // backspace || delete --> remove selected configuration

                    product.$.configurations.remove(selectedConfiguration);
                    self.set('selectedConfiguration', null);

                    e.preventDefault();
                    e.stopPropagation();
                }

                if (ctrlKey && (e.keyCode === 67 || e.keyCode === 88) && enableCopyPaste) {
                    this.set('copiedConfiguration', selectedConfiguration.clone());

                    if (e.keyCode === 88) {
                        product.$.configurations.remove(selectedConfiguration);
                        self.set('selectedConfiguration', null);
                    }

                    e.preventDefault();
                    e.stopPropagation();
                }
            }

        },

        _keyPressHandler: function (e) {
            var viewer = this.$.selectedConfigurationViewer;
            if (viewer) {
                viewer._keyPress(e);
            }
        },

        _keyUpHandler: function () {
            if (this.$configurationMoved) {
                this.$configurationMoved = false;
                this.$.bus.trigger("Application.productChanged", this.$.product);
            }
        },

        _bindDomEvents: function () {
            if (this.runsInBrowser() && this.$.editable) {
                var self = this;

                this.bind("on:click", this._clickHandler, this);

                this.$stage.bind('on:focus', function () {
                    self.set('focused', true);
                });
                this.callBase();
            }
        }
    });
});<|endoftext|>


<commit_before>// Backbone.StateMachine v0.1
//
// Copyright (C)2012 Sébastien Piquemal, Aidbrella
// Distributed Under MIT License
//
// Documentation and Full License Available at:
// https://github.com/sebpiq/backbone.statemachine

Backbone.StateMachine = (function(Backbone, _){

    // Mixin object to create a state machine out of any other object.
    // Note that this requires to be mixed-in with Backbone.Event as well.
    var StateMachine = {

        currentState: undefined,

        // If `silent` is true, the state machine doesn't send events during a transition.
        silent: false,

        // Initializes the state machine : binds states, transitions, ...
        startStateMachine: function(options){
            this._transitions = {};
            this._states = {};
            options || (options = {});
            this._bindStates();
            this._bindTransitions();
            options.currentState && (this.currentState = options.currentState);
            if (options.debugStateMachine === true) DebugView.register(this);
            this.bind('all', this._receive, this);
        },

        // Declares a new transition on the state machine.
        transition: function(leaveState, event, data) {
            data = _.clone(data);
            if (!(this._states.hasOwnProperty(data.enterState)))
                this.state(data.enterState, {});
            if (!(this._transitions.hasOwnProperty(leaveState)))
                this._transitions[leaveState] = {};
            data.callbacks = this._collectMethods((data.callbacks || []));
            this._transitions[leaveState][event] = data;
        },

        // Declares a new state on the state machine
        state: function(name, data) {
            data = _.clone(data);
            data.enterCb = this._collectMethods((data.enterCb || []));
            data.leaveCb = this._collectMethods((data.leaveCb || []));
            this._states[name] = data;
        },

        // Forces the state machine to state 'name'. No transition will occur, but the
        // normal "enter new state" mess will (calling the callbacks, ...).
        toState: function(name) {
            var extraArgs = _.toArray(arguments).slice(1);
            this._callCallbacks(this._states[name].enterCb, extraArgs);
            this.currentState = name;
        },

        // Returns the list of all events that can trigger a transition
        getEvents: function() {
            var events = _.reduce(_.values(this._transitions), function(memo, transitions) {
                return memo.concat(_.keys(transitions));
            }, []);
            return _.uniq(events);
        },

        // Callback bound to all events. Does the actual work when receiving an event.
        _receive: function(event) {
            if (!this._transitions.hasOwnProperty(this.currentState)) return;
            if (!this._transitions[this.currentState].hasOwnProperty(event)) return;
            var data = this._transitions[this.currentState][event];
            var extraArgs = _.toArray(arguments).slice(1);
            this._doTransition.apply(this, [data, event].concat(extraArgs));
        },

        // Executes a transition.
        _doTransition: function(data, event) {
            var extraArgs = _.toArray(arguments).slice(2);
            var leaveState = this.currentState;
            var enterState = data.enterState;
            var triggers = data.triggers;
            if (!this.silent) this.trigger.apply(this, ['leaveState:' + leaveState].concat(extraArgs));
            this._callCallbacks(this._states[leaveState].leaveCb, extraArgs);
            if (!this.silent) {
                this.trigger.apply(this, ['transition', leaveState, enterState].concat(extraArgs));
                if (triggers) this.trigger.apply(this, [triggers].concat(extraArgs));
            }
            this._callCallbacks(data.callbacks, extraArgs);
            if (!this.silent) this.trigger.apply(this, ['enterState:' + enterState].concat(extraArgs));
            this.toState.apply(this, [enterState].concat(extraArgs));
        },

        // Creates transitions from `this.transitions`, which is a hash
        //      {
        //          leaveStateName: {
        //              event: {
        //                  enterState: 'enterStateName',
        //                  triggers: 'eventName',
        //                  callbacks: [callback1, callback2, ...]
        //              }
        //          }
        //      }
        // Transitions are created by calling the `transition` method.
        _bindTransitions: function() {
            if (!this.transitions) return;
            for (var leaveState in this.transitions) {
                for (var event in this.transitions[leaveState]) {
                    this.transition(leaveState, event, this.transitions[leaveState][event]);
                }
            }
        },

        // Creates states from `this.states`, which is a hash
        //      {
        //          stateName: {
        //              className: 'cssClass',
        //              enterCb: [enterCb1, enterCb2, ...], leaveCb: [leaveCb1, leaveCb2, ...]
        //          }
        //      }
        // States are created by calling the `state` method.
        _bindStates: function() {
            if (!this.states) return;
            for (var name in this.states) this.state(name, this.states[name]);
        },

        // Helper for collecting callbacks provided as strings.
        _collectMethods: function(methodNames) {
            methods = [];
            for (var i = 0; i < methodNames.length; i++){
                var method = this[methodNames[i]];
                if (!method) throw new Error('Method "' + methodNames[i] + '" does not exist');
                methods.push(method);
            }
            return methods;
        },

        // Helper for calling a list of callbacks.
        _callCallbacks: function(cbArray, extraArgs) {
            for (var i = 0; i < cbArray.length; i++){
                cbArray[i].apply(this, extraArgs);
            }
        }
    };

    // View for a state machine in the debugger.
    var DebugView = Backbone.View.extend({
        tagName: 'div',
        className: 'backbone-statemachine-debug',
        rendered: false,
        events: {
            'click .log': 'logStateMachine'
        },
        render: function() {
            // This is only called when rendering the first time.
            if (!this.rendered) {
                // sets-up periodic rendering, so the debug view is always up-to-date.
                function periodicRender() {
                    this.render();
                    setTimeout(_.bind(periodicRender, this), 100);
                }
                setTimeout(_.bind(periodicRender, this), 100);
                this.rendered = true;
                // sets-up the debug view's html
                var innerHtml = $('

console.log');
                $(this.el).append(innerHtml);
                // when the debug view is hovered, if the state machine it represents is a view
                // itself, we highlight its element on the page.
                if (this.model.hasOwnProperty('el')) {
                    $(this.el).hover(_.bind(function(){
                        var modelEl = $(this.model.el);
                        this.cssMem = {'background-color': '', 'border': ''}
                        modelEl.css({'background-color': 'blue','border': '3px solid DarkBlue'});
                    }, this));
                    $(this.el).mouseleave(_.bind(function(){
                        var modelEl = $(this.model.el);
                        modelEl.css(this.cssMem);
                    }, this));
                }
            }
            // this does the actual updating of the debug view's html.
            this.$('.state').html(this.model.currentState);
            return this;
        },
        logStateMachine: function(event) {
            event.preventDefault();
            console.log(this.model);
        }
    }, {
        // Registers a state machine in the debugger, so that a debug view will be created for it.
        register: function(instance) {
            // If this is the first state machine registered in the debugger,
            // we create the debugger's html.
            if (this.viewsArray.length == 0) {
                var container = this.el = $('
'+
                    '
backbone.statemachine: DEBUGGER
'+
                    'hide'+
                    '
'
                ).appendTo($('body'));
                $('#backbone-statemachine-debug-hideshow', this.el).click(function(event){
                    event.preventDefault();
                    if (this.collapsed) {
                        $(container).removeClass('collapsed').children().show();
                        $(this).html('hide');
                        this.collapsed = false;
                    } else {
                        $(container).addClass('collapsed').children().hide();
                        $(this).html('show').show();
                        this.collapsed = true;
                    }
                });
            }
            // create the debug view, pick a random color for it, and add it to the debugger.
            var debugView = new DebugView({model: instance});
            var bgColor = this.pickColor();
            $(debugView.el).appendTo(this.el).css({'background-color': bgColor});
            debugView.render();
            if (this.collapsed) $(debugView.el).hide();
            this.viewsArray.push(debugView);
        },
        update: function() {
            _.each(this.viewsArray, function(view){
                view.render();
            });
        },
        pickColor: function() {
            return '#'+Math.floor(Math.random()*16777215).toString(16);
        },
        viewsArray: [],
        el: undefined,
        collapsed: false
    });

    StateMachine.version = '0.2.1';

    return StateMachine;

})(Backbone, _);

// A Backbone view that is also a state machine.
Backbone.StatefulView = (function(Backbone, _){

    var StatefulView = function(options) {
        this.startStateMachine(options);
        Backbone.View.prototype.constructor.apply(this, arguments);
    };

    _.extend(StatefulView.prototype, Backbone.View.prototype, Backbone.StateMachine, {

        startStateMachine: function() {
            // Remembers the events registered using `transition`, so that
            // they are not bound twice.
            this._eventRegistry = [];
            Backbone.StateMachine.startStateMachine.apply(this, arguments);
        },

        toState: function(name) {
            Backbone.StateMachine.toState.apply(this, arguments);
            if (this.el) {
                $(this.el).removeClass((this.stateClassName || ''));
                this.stateClassName = (this._states[name].className || name);
                $(this.el).addClass(this.stateClassName);
            }
        },

        delegateEvents: function(events) {
            // We want all the events in the `transitions` hash to be triggered
            // like events in `View.events`.
            if (!events) {
                events = (this['events'] && _.clone(this['events'])) || {};
                if (events && _.isFunction(events)) events = events();
                _.each(this.getEvents(), function(event) {
                    // If there was already a callback for that event,
                    // we must call it ourselves ... sigh ...
                    var method = events[event];
                    if (method != undefined) {
                        if (!_.isFunction(method)) method = this[events[event]];
                        if (!method) throw new Error('Method "' + events[event] + '" does not exist');
                    }
                    events[event] = (function(method) {
                        return function(DOMEvent) {
                            if (method) method.apply(this, arguments);
                            this._receive(event, DOMEvent);
                        };
                    })(method);
                }, this);
            }
            Backbone.View.prototype.delegateEvents.call(this, events);
        }
    });

    // Set up inheritance for StatefulView.
    StatefulView.extend = Backbone.View.extend;

    return StatefulView;
})(Backbone, _);

<commit_msg>Fix global leak of `methods` in `StateMachine._collectMethods`.<commit_after>// Backbone.StateMachine v0.1
//
// Copyright (C)2012 Sébastien Piquemal, Aidbrella
// Distributed Under MIT License
//
// Documentation and Full License Available at:
// https://github.com/sebpiq/backbone.statemachine

Backbone.StateMachine = (function(Backbone, _){

    // Mixin object to create a state machine out of any other object.
    // Note that this requires to be mixed-in with Backbone.Event as well.
    var StateMachine = {

        currentState: undefined,

        // If `silent` is true, the state machine doesn't send events during a transition.
        silent: false,

        // Initializes the state machine : binds states, transitions, ...
        startStateMachine: function(options){
            this._transitions = {};
            this._states = {};
            options || (options = {});
            this._bindStates();
            this._bindTransitions();
            options.currentState && (this.currentState = options.currentState);
            if (options.debugStateMachine === true) DebugView.register(this);
            this.bind('all', this._receive, this);
        },

        // Declares a new transition on the state machine.
        transition: function(leaveState, event, data) {
            data = _.clone(data);
            if (!(this._states.hasOwnProperty(data.enterState)))
                this.state(data.enterState, {});
            if (!(this._transitions.hasOwnProperty(leaveState)))
                this._transitions[leaveState] = {};
            data.callbacks = this._collectMethods((data.callbacks || []));
            this._transitions[leaveState][event] = data;
        },

        // Declares a new state on the state machine
        state: function(name, data) {
            data = _.clone(data);
            data.enterCb = this._collectMethods((data.enterCb || []));
            data.leaveCb = this._collectMethods((data.leaveCb || []));
            this._states[name] = data;
        },

        // Forces the state machine to state 'name'. No transition will occur, but the
        // normal "enter new state" mess will (calling the callbacks, ...).
        toState: function(name) {
            var extraArgs = _.toArray(arguments).slice(1);
            this._callCallbacks(this._states[name].enterCb, extraArgs);
            this.currentState = name;
        },

        // Returns the list of all events that can trigger a transition
        getEvents: function() {
            var events = _.reduce(_.values(this._transitions), function(memo, transitions) {
                return memo.concat(_.keys(transitions));
            }, []);
            return _.uniq(events);
        },

        // Callback bound to all events. Does the actual work when receiving an event.
        _receive: function(event) {
            if (!this._transitions.hasOwnProperty(this.currentState)) return;
            if (!this._transitions[this.currentState].hasOwnProperty(event)) return;
            var data = this._transitions[this.currentState][event];
            var extraArgs = _.toArray(arguments).slice(1);
            this._doTransition.apply(this, [data, event].concat(extraArgs));
        },

        // Executes a transition.
        _doTransition: function(data, event) {
            var extraArgs = _.toArray(arguments).slice(2);
            var leaveState = this.currentState;
            var enterState = data.enterState;
            var triggers = data.triggers;
            if (!this.silent) this.trigger.apply(this, ['leaveState:' + leaveState].concat(extraArgs));
            this._callCallbacks(this._states[leaveState].leaveCb, extraArgs);
            if (!this.silent) {
                this.trigger.apply(this, ['transition', leaveState, enterState].concat(extraArgs));
                if (triggers) this.trigger.apply(this, [triggers].concat(extraArgs));
            }
            this._callCallbacks(data.callbacks, extraArgs);
            if (!this.silent) this.trigger.apply(this, ['enterState:' + enterState].concat(extraArgs));
            this.toState.apply(this, [enterState].concat(extraArgs));
        },

        // Creates transitions from `this.transitions`, which is a hash
        //      {
        //          leaveStateName: {
        //              event: {
        //                  enterState: 'enterStateName',
        //                  triggers: 'eventName',
        //                  callbacks: [callback1, callback2, ...]
        //              }
        //          }
        //      }
        // Transitions are created by calling the `transition` method.
        _bindTransitions: function() {
            if (!this.transitions) return;
            for (var leaveState in this.transitions) {
                for (var event in this.transitions[leaveState]) {
                    this.transition(leaveState, event, this.transitions[leaveState][event]);
                }
            }
        },

        // Creates states from `this.states`, which is a hash
        //      {
        //          stateName: {
        //              className: 'cssClass',
        //              enterCb: [enterCb1, enterCb2, ...], leaveCb: [leaveCb1, leaveCb2, ...]
        //          }
        //      }
        // States are created by calling the `state` method.
        _bindStates: function() {
            if (!this.states) return;
            for (var name in this.states) this.state(name, this.states[name]);
        },

        // Helper for collecting callbacks provided as strings.
        _collectMethods: function(methodNames) {
            var methods = [];
            for (var i = 0; i < methodNames.length; i++){
                var method = this[methodNames[i]];
                if (!method) throw new Error('Method "' + methodNames[i] + '" does not exist');
                methods.push(method);
            }
            return methods;
        },

        // Helper for calling a list of callbacks.
        _callCallbacks: function(cbArray, extraArgs) {
            for (var i = 0; i < cbArray.length; i++){
                cbArray[i].apply(this, extraArgs);
            }
        }
    };

    // View for a state machine in the debugger.
    var DebugView = Backbone.View.extend({
        tagName: 'div',
        className: 'backbone-statemachine-debug',
        rendered: false,
        events: {
            'click .log': 'logStateMachine'
        },
        render: function() {
            // This is only called when rendering the first time.
            if (!this.rendered) {
                // sets-up periodic rendering, so the debug view is always up-to-date.
                function periodicRender() {
                    this.render();
                    setTimeout(_.bind(periodicRender, this), 100);
                }
                setTimeout(_.bind(periodicRender, this), 100);
                this.rendered = true;
                // sets-up the debug view's html
                var innerHtml = $('

console.log');
                $(this.el).append(innerHtml);
                // when the debug view is hovered, if the state machine it represents is a view
                // itself, we highlight its element on the page.
                if (this.model.hasOwnProperty('el')) {
                    $(this.el).hover(_.bind(function(){
                        var modelEl = $(this.model.el);
                        this.cssMem = {'background-color': '', 'border': ''}
                        modelEl.css({'background-color': 'blue','border': '3px solid DarkBlue'});
                    }, this));
                    $(this.el).mouseleave(_.bind(function(){
                        var modelEl = $(this.model.el);
                        modelEl.css(this.cssMem);
                    }, this));
                }
            }
            // this does the actual updating of the debug view's html.
            this.$('.state').html(this.model.currentState);
            return this;
        },
        logStateMachine: function(event) {
            event.preventDefault();
            console.log(this.model);
        }
    }, {
        // Registers a state machine in the debugger, so that a debug view will be created for it.
        register: function(instance) {
            // If this is the first state machine registered in the debugger,
            // we create the debugger's html.
            if (this.viewsArray.length == 0) {
                var container = this.el = $('
'+
                    '
backbone.statemachine: DEBUGGER
'+
                    'hide'+
                    '
'
                ).appendTo($('body'));
                $('#backbone-statemachine-debug-hideshow', this.el).click(function(event){
                    event.preventDefault();
                    if (this.collapsed) {
                        $(container).removeClass('collapsed').children().show();
                        $(this).html('hide');
                        this.collapsed = false;
                    } else {
                        $(container).addClass('collapsed').children().hide();
                        $(this).html('show').show();
                        this.collapsed = true;
                    }
                });
            }
            // create the debug view, pick a random color for it, and add it to the debugger.
            var debugView = new DebugView({model: instance});
            var bgColor = this.pickColor();
            $(debugView.el).appendTo(this.el).css({'background-color': bgColor});
            debugView.render();
            if (this.collapsed) $(debugView.el).hide();
            this.viewsArray.push(debugView);
        },
        update: function() {
            _.each(this.viewsArray, function(view){
                view.render();
            });
        },
        pickColor: function() {
            return '#'+Math.floor(Math.random()*16777215).toString(16);
        },
        viewsArray: [],
        el: undefined,
        collapsed: false
    });

    StateMachine.version = '0.2.1';

    return StateMachine;

})(Backbone, _);

// A Backbone view that is also a state machine.
Backbone.StatefulView = (function(Backbone, _){

    var StatefulView = function(options) {
        this.startStateMachine(options);
        Backbone.View.prototype.constructor.apply(this, arguments);
    };

    _.extend(StatefulView.prototype, Backbone.View.prototype, Backbone.StateMachine, {

        startStateMachine: function() {
            // Remembers the events registered using `transition`, so that
            // they are not bound twice.
            this._eventRegistry = [];
            Backbone.StateMachine.startStateMachine.apply(this, arguments);
        },

        toState: function(name) {
            Backbone.StateMachine.toState.apply(this, arguments);
            if (this.el) {
                $(this.el).removeClass((this.stateClassName || ''));
                this.stateClassName = (this._states[name].className || name);
                $(this.el).addClass(this.stateClassName);
            }
        },

        delegateEvents: function(events) {
            // We want all the events in the `transitions` hash to be triggered
            // like events in `View.events`.
            if (!events) {
                events = (this['events'] && _.clone(this['events'])) || {};
                if (events && _.isFunction(events)) events = events();
                _.each(this.getEvents(), function(event) {
                    // If there was already a callback for that event,
                    // we must call it ourselves ... sigh ...
                    var method = events[event];
                    if (method != undefined) {
                        if (!_.isFunction(method)) method = this[events[event]];
                        if (!method) throw new Error('Method "' + events[event] + '" does not exist');
                    }
                    events[event] = (function(method) {
                        return function(DOMEvent) {
                            if (method) method.apply(this, arguments);
                            this._receive(event, DOMEvent);
                        };
                    })(method);
                }, this);
            }
            Backbone.View.prototype.delegateEvents.call(this, events);
        }
    });

    // Set up inheritance for StatefulView.
    StatefulView.extend = Backbone.View.extend;

    return StatefulView;
})(Backbone, _);

<|endoftext|>


<commit_before>'use strict';
if (process.argv.length < 4 || process.argv.length > 5) {
  console.log('Usage: node zip_blocks.js path_to_files output_zip [approx_block_size_in_MB]');
  throw new FatalError('Incorrect arguments supplied.');
}

// setup and defaults:
var blockSize = 20; // magic number defaults
var fs = require('fs');
var path = require('path');
var files = {};
var blocks = [];

// parse args:
var pathToFiles = process.argv[2];
var outputZip = process.argv[3];
if (process.argv.length > 4) {
  var inputBlockSize = Number.parseInt(process.argv[4], 10);
  // TODO: test if we get a 'reasonable' number
  blockSize = inputBlockSize;
}
var outputDir = path.dirname(outputZip);
var logFileName = path.join(outputDir, getDateTimeDashesOnly() + '.log');

function writeToLog(text) {
  fs.appendFile(logFileName, text + '\n');
}

// sort files into blocks by size:
fs.readdir(pathToFiles, function (err, listing) {
  for (var i = 0; i < listing.length; ++i) {
    var fullPath = path.join(pathToFiles, listing[i]);
    var stat = fs.statSync(fullPath);
    if (stat.isFile()) {
      files[fullPath] = stat.size;
    }
  }
  testPrint();
  //getBlocks();
  //doZip();
});

function testPrint() {
  for (var key in files) {
    writeToLog(key + ': ' + files[key]);
  }
}

function getBlocks() {}

function doZip() {
  var AdmZip = require('adm-zip');
  var zip = new AdmZip();
    try {
    //zip.addLocalFile
  } catch (err) {
    writeToLog(err);
  }
  zip.writeZip(outputZip);
}

function getDateTimeDashesOnly() {
    var now     = new Date();
    var year    = now.getFullYear();
    var month   = now.getMonth() + 1;
    var day     = now.getDate();
    var hour    = now.getHours();
    var minute  = now.getMinutes();
    var second  = now.getSeconds();
    if (month.toString().length === 1)
        month = '0' + month;
    if (day.toString().length === 1)
        day = '0' + day;
    if (hour.toString().length === 1)
        hour = '0' + hour;
    if (minute.toString().length === 1)
        minute = '0' + minute;
    if (second.toString().length === 1)
        second = '0' + second;
    return year + '-' + month + '-' + day + '_' + hour + '-' + minute + '-' + second;
}

// notes:
//zip.addLocalFile('file_on_disk', 'path_in_archive');
//zip.addLocalFolder('path_on_disk', 'path_in_archive');

    /* async version:
    fs.stat(listing[i], function (err, stat) {
      if (err) {
        writeToLog(err);
        return;
      }
      if (stat.isFile()) {
        files[listing] = stat.size;
      }
    });*/
<commit_msg>Working for first tests.<commit_after>'use strict';
if (process.argv.length < 4 || process.argv.length > 5) {
  console.log('Incorrect arguments supplied.');
  console.log('Usage: node zip_blocks.js path_to_files output_dir [approx_block_size_in_MB]');
  process.exit();
}

// setup and defaults:
var fs = require('fs');
var path = require('path');
var files = {};
var blocks = [];
var blockSizeUnit = 1000000; // million/MB
var compressionRatio = 1; // built for files with very low compression ratio

// parse args:
var pathToFiles = process.argv[2];
var outputDir = process.argv[3];
if (!fs.existsSync(outputDir) || !fs.statSync(outputDir).isDirectory()) {
  console.warn('"' + outputDir + '" is not a directory, using "' + __dirname + '" instead.');
  outputDir = __dirname;
}
var blockSize = 20; // default block size in millions of bytes
if (process.argv.length > 4) {
  var inputBlockSize = parseInt(process.argv[4], 10);
  if (1 <= inputBlockSize  && inputBlockSize <= 100) {
    blockSize = inputBlockSize;
  } else {
    console.warn('Approximate block size must be between 1 and 100 MB inclusive. Using default of 20 MB instead.');
  }
}
var logFileName = path.join(outputDir, getDateTimeDashesOnly() + '.log');
function writeToLog(text) {
  fs.appendFile(logFileName, text + '\n');
}

// sort files into blocks by size:
fs.readdir(pathToFiles, function (err, listing) {
  for (var i = 0; i < listing.length; ++i) {
    var fullPath = path.join(pathToFiles, listing[i]);
    var stat = fs.statSync(fullPath);
    if (stat.isFile()) {
      files[fullPath] = stat.size;
    }
  }
  getBlocks();
  doZip();
});

function getBlocks() {
  var total = 0;
  var max = blockSize * blockSizeUnit * compressionRatio;
  var blockNum = 0;
  blocks[blockNum] = [];
  for (var key in files) {
    if (files[key] > max) {
      writeToLog(key + ' is too big for any block - file skipped.');
      continue;
    }
    total += files[key];
    if (total > max) {
      blockNum += 1;
      blocks[blockNum] = [];
      total = files[key];
    }
    blocks[blockNum].push(key);
  }
}

function doZip() {
  var AdmZip = require('adm-zip');
  for (var zipNum = 0; zipNum < blocks.length; ++zipNum) {
    var zip = new AdmZip();
    for (var i = 0; i < blocks[zipNum].length; ++i) {
      try {
        zip.addLocalFile(blocks[zipNum][i]);
      } catch (err) {
        writeToLog('Error zipping ' + blocks[i]);
        continue;
      }
    }
    zip.writeZip(path.join(outputDir, (zipNum + 1).toString() + '.zip'));
  }
}

function getDateTimeDashesOnly() {
    var now     = new Date();
    var year    = now.getFullYear();
    var month   = now.getMonth() + 1;
    var day     = now.getDate();
    var hour    = now.getHours();
    var minute  = now.getMinutes();
    var second  = now.getSeconds();
    if (month.toString().length === 1)
        month = '0' + month;
    if (day.toString().length === 1)
        day = '0' + day;
    if (hour.toString().length === 1)
        hour = '0' + hour;
    if (minute.toString().length === 1)
        minute = '0' + minute;
    if (second.toString().length === 1)
        second = '0' + second;
    return year + '-' + month + '-' + day + '_' + hour + '-' + minute + '-' + second;
}
<|endoftext|>


<commit_before>/**
 * The CompareFixedHeaderView view.
 */
define([
  'jquery',
  'backbone',
  'underscore',
  'handlebars',
  'mps',
  'compare/presenters/CompareFixedHeaderPresenter',
  'text!compare/templates/compareFixedHeader.handlebars'
], function($, Backbone, _, Handlebars, mps, CompareFixedHeaderPresenter, tpl) {

  'use strict';

  var CompareFixedHeaderView = Backbone.View.extend({

    el: '#compareFixedHeaderView',

    template: Handlebars.compile(tpl),

    events: {},

    initialize: function() {
      this.presenter = new CompareFixedHeaderPresenter(this);
      this.status = this.presenter.status;
      //CACHE
      this.$window = $(window);
      this.$document = $(document);

      this.$offsetTop = $('#offsetTop');
      this.$offsetBottom = $('#offsetBottom');

      // //INITS
      this.calculateOffsets();
      this.scrollDocument();

      this.setListeners();
    },

    setListeners: function(){
      this.$document.on('scroll',_.bind(this.scrollDocument,this));
      this.$window.on('resize',_.bind(this.calculateOffsets,this));
    },

    calculateOffsets: function(){
      this.offsetTop = this.$offsetTop.offset().top;
      this.offsetBottom = this.$offsetBottom.offset().top - this.$el.height();
    },

    scrollDocument: function(e){
      var scrollTop = this.$document.scrollTop();
      this.calculateOffsets();
      if (scrollTop > this.offsetTop) {
        this.$offsetTop.css({'padding-top': this.$el.height()});
        if(scrollTop < this.offsetBottom) {
          this.$el.removeClass('is-bottom').addClass('is-fixed');
        }else{
          this.$el.removeClass('is-fixed').addClass('is-bottom');
        }
      }else{
        this.$offsetTop.css({'padding-top': 0});
        this.$el.removeClass('is-fixed is-bottom');
      }
    },

    render: function() {
      this.$el.html(this.template(this._parseData()));
    },

    _parseData: function() {
      var country1 = this.status.get('country1').toJSON();
      var country2 = this.status.get('country2').toJSON();

      var select1 = {
        tab: '1',
        name: this.setName(country1,1),
      };

      var select2 = {
        tab: '2',
        name: this.setName(country2,2),
      };

      return { selection: [select1, select2] };
    },

    setName: function(country,tab) {
      var jurisdiction = ~~this.status.get('compare'+tab).jurisdiction;
      var area = ~~this.status.get('compare'+tab).area;
      if (!!jurisdiction) {
        return _.findWhere(country.jurisdictions, {id: jurisdiction}).name +' in ' + country.name;
      } else if (!!area) {
        return _.findWhere(country.areas_of_interest, {id: area }).name +' in ' + country.name;
      } else {
        return country.name;
      }
    },

  });

  return CompareFixedHeaderView;

});
<commit_msg>Fixed bar on Country Comparisons<commit_after>/**
 * The CompareFixedHeaderView view.
 */
define([
  'jquery',
  'backbone',
  'underscore',
  'handlebars',
  'mps',
  'compare/presenters/CompareFixedHeaderPresenter',
  'text!compare/templates/compareFixedHeader.handlebars'
], function($, Backbone, _, Handlebars, mps, CompareFixedHeaderPresenter, tpl) {

  'use strict';

  var CompareFixedHeaderView = Backbone.View.extend({

    el: '#compareFixedHeaderView',

    template: Handlebars.compile(tpl),

    events: {},

    initialize: function() {
      this.presenter = new CompareFixedHeaderPresenter(this);
      this.status = this.presenter.status;
      //CACHE
      this.$window = $(window);
      this.$document = $(document);

      this.$offsetTop = $('#offsetTop');
      this.$offsetBottom = $('#offsetBottom');

      // //INITS
      this.calculateOffsets();
      this.scrollDocument();

      this.setListeners();
    },

    setListeners: function(){
      this.$document.on('scroll',_.bind(this.scrollDocument,this));
      this.$window.on('resize',_.bind(this.calculateOffsets,this));
    },

    calculateOffsets: function(){
      this.offsetTop = this.$offsetTop.offset().top;
      this.offsetBottom = this.$offsetBottom.offset().top - this.$el.height();
    },

    scrollDocument: function(e){
      var scrollTop = this.$document.scrollTop();
      this.calculateOffsets();
      if (scrollTop > this.offsetTop) {
        if(scrollTop < this.offsetBottom) {
          this.$el.removeClass('is-bottom').addClass('is-fixed');
        }else{
          this.$el.removeClass('is-fixed').addClass('is-bottom');
        }
      }else{
        this.$el.removeClass('is-fixed is-bottom');
      }
    },

    render: function() {
      this.$el.html(this.template(this._parseData()));
    },

    _parseData: function() {
      var country1 = this.status.get('country1').toJSON();
      var country2 = this.status.get('country2').toJSON();

      var select1 = {
        tab: '1',
        name: this.setName(country1,1),
      };

      var select2 = {
        tab: '2',
        name: this.setName(country2,2),
      };

      return { selection: [select1, select2] };
    },

    setName: function(country,tab) {
      var jurisdiction = ~~this.status.get('compare'+tab).jurisdiction;
      var area = ~~this.status.get('compare'+tab).area;
      if (!!jurisdiction) {
        return _.findWhere(country.jurisdictions, {id: jurisdiction}).name +' in ' + country.name;
      } else if (!!area) {
        return _.findWhere(country.areas_of_interest, {id: area }).name +' in ' + country.name;
      } else {
        return country.name;
      }
    },

  });

  return CompareFixedHeaderView;

});
<|endoftext|>


<commit_before>
//const LOGITECH_LED_SDK_URL = 'https://gaming.logitech.com/sdk/LED_8.87.zip';
const LOGITECH_LED_SDK_URL = 'https://www.logitechg.com/sdk/LED_SDK_9.00.zip';

const fs = require('fs-extra');
const path = require('path');
const EOL = require('os').EOL;
const unzip = require('unzip');
const fstream = require('fstream');
const request = require('request');
const progress = require('request-progress');
const progressBar = require('progress-bar').create(process.stdout, (process.stdout.columns || 70) - 20);
progressBar.format = '$bar; $percentage;% finished.';

const TMP = path.join(__dirname, 'TMP');
const TMP_LED = path.join(TMP, 'LED');
const LED = path.join(__dirname, 'LED');

// only download SDK if not already done
if (!fs.existsSync(LED)) {

    if (fs.existsSync(TMP)) {
        fs.removeSync(TMP);
    }

    fs.mkdirSync(TMP);
    const writeStream = new fstream.Writer(TMP);

    // download and unzip SDK into the LED folder...
    console.log('Download and unzip Logitech LED SDK...');

    // also show a fancy progress bar if stdout is a terminal
    progress(request(LOGITECH_LED_SDK_URL), {
        throttle: 250
    })
    .on('progress', function (state) {
        if (process.stdout.isTTY) {
            progressBar.update(state.percent);
        }
    })
    .on('error', function (err) {
        if (process.stdout.isTTY) {
            progressBar.clear();
        }
        console.log('error downloading Logitech LED SDK:', err.message, EOL);
        process.exit(1);
    })
    .on('end', function (state) {
        fs.moveSync(TMP_LED, LED);
        fs.rmdirSync(TMP);
        if (process.stdout.isTTY) {
            progressBar.clear();
        }
        console.log('finished successfully.' + EOL);
    })
    .pipe(unzip.Parse())
    .pipe(writeStream);
}
<commit_msg>remove temp folder on error<commit_after>
//const LOGITECH_LED_SDK_URL = 'https://gaming.logitech.com/sdk/LED_8.87.zip';
const LOGITECH_LED_SDK_URL = 'https://www.logitechg.com/sdk/LED_SDK_9.00.zip';

const fs = require('fs-extra');
const path = require('path');
const EOL = require('os').EOL;
const unzip = require('unzip');
const fstream = require('fstream');
const request = require('request');
const progress = require('request-progress');
const progressBar = require('progress-bar').create(process.stdout, (process.stdout.columns || 70) - 20);
progressBar.format = '$bar; $percentage;% finished.';

const TMP = path.join(__dirname, 'TMP');
const TMP_LED = path.join(TMP, 'LED');
const LED = path.join(__dirname, 'LED');

// only download SDK if not already done
if (!fs.existsSync(LED)) {

    if (fs.existsSync(TMP)) {
        fs.removeSync(TMP);
    }

    fs.mkdirSync(TMP);
    const writeStream = new fstream.Writer(TMP);

    // download and unzip SDK into the LED folder...
    console.log('Download and unzip Logitech LED SDK...');

    // also show a fancy progress bar if stdout is a terminal
    progress(request(LOGITECH_LED_SDK_URL), {
        throttle: 250
    })
    .on('progress', function (state) {
        if (process.stdout.isTTY) {
            progressBar.update(state.percent);
        }
    })
    .on('error', function (err) {
        if (process.stdout.isTTY) {
            progressBar.clear();
        }
        console.log('error downloading Logitech LED SDK:', err.message, EOL);
        fs.rmdirSync(TMP);
        process.exit(1);
    })
    .on('end', function (state) {
        fs.moveSync(TMP_LED, LED);
        fs.rmdirSync(TMP);
        if (process.stdout.isTTY) {
            progressBar.clear();
        }
        console.log('finished successfully.' + EOL);
    })
    .pipe(unzip.Parse())
    .pipe(writeStream);
}
<|endoftext|>