<commit_before>/* eslint-disable */
module.exports = {
    name: {
        first: 'John',
        last: 'Doe',
    },
    position: 'Software Developer',
    birth: {
      year: 1990,
      location: 'New York'
    },
    experience: [{
            company: 'Company A',
            position: 'Developer',
            timeperiod: 'since January 2016',
            description: 'Programming and watching cute cat videos.'
        },
        {
            company: 'Company B',
            position: 'Frontend Developer',
            timeperiod: 'January 2015 - December 2015',
            description: 'Fulfillment of extremly important tasks.'
        },
        {
            company: 'Company C',
            position: 'Trainee',
            timeperiod: 'March 2014 - December 2014',
            description: 'Making coffee and baking cookies.'
        }
    ],
    education: [{
            degree: 'Master of Arts',
            description: 'Major in Hacking and Computer Penetration, University A, New York, USA.'
        },
        {
            degree: 'Bachelor of Science',
            description: 'Major in Engineering, University B, Los Angeles, USA.'
        }
    ],
    // skill level goes 0 to 100
    skills: [{
            name: 'HTML5',
            level: '99'
        },
        {
            name: 'CSS3',
            level: '95'
        },
        {
            name: 'JavaScript',
            level: '97'
        },
        {
            name: 'Node.js',
            level: '93'
        },
        {
            name: 'Angular 2',
            level: '60'
        },
        {
            name: 'TypeScript',
            level: '80'
        },
        {
            name: 'ES.Next',
            level: '70'
        },
        {
            name: 'Docker',
            level: '99'
        }
    ],
    skillDescription: 'Also proficient in Adobe Photoshop and Illustrator, grew up bilingual (English and Klingon).',
    contact: {
        email: 'john.doe@email.com',
        phone: '0123 456789',
        street: '1234 Broadway',
        city: 'New York',
        website: 'johndoe.com',
        github: 'github.com/JohnDoe'
    }
};
<commit_msg>ADD timeperiod to educations<commit_after>/* eslint-disable */
module.exports = {
    name: {
        first: 'John',
        last: 'Doe',
    },
    position: 'Software Developer',
    birth: {
      year: 1990,
      location: 'New York'
    },
    experience: [{
            company: 'Company A',
            position: 'Developer',
            timeperiod: 'since January 2016',
            description: 'Programming and watching cute cat videos.'
        },
        {
            company: 'Company B',
            position: 'Frontend Developer',
            timeperiod: 'January 2015 - December 2015',
            description: 'Fulfillment of extremly important tasks.'
        },
        {
            company: 'Company C',
            position: 'Trainee',
            timeperiod: 'March 2014 - December 2014',
            description: 'Making coffee and baking cookies.'
        }
    ],
    education: [{
            degree: 'Master of Arts',
            timeperiod: 'March 2012 - December 2013',
            description: 'Major in Hacking and Computer Penetration, University A, New York, USA.'
        },
        {
            degree: 'Bachelor of Science',
            timeperiod: 'March 2009 - December 2011',
            description: 'Major in Engineering, University B, Los Angeles, USA.'
        }
    ],
    // skill level goes 0 to 100
    skills: [{
            name: 'HTML5',
            level: '99'
        },
        {
            name: 'CSS3',
            level: '95'
        },
        {
            name: 'JavaScript',
            level: '97'
        },
        {
            name: 'Node.js',
            level: '93'
        },
        {
            name: 'Angular 2',
            level: '60'
        },
        {
            name: 'TypeScript',
            level: '80'
        },
        {
            name: 'ES.Next',
            level: '70'
        },
        {
            name: 'Docker',
            level: '99'
        }
    ],
    skillDescription: 'Also proficient in Adobe Photoshop and Illustrator, grew up bilingual (English and Klingon).',
    contact: {
        email: 'john.doe@email.com',
        phone: '0123 456789',
        street: '1234 Broadway',
        city: 'New York',
        website: 'johndoe.com',
        github: 'github.com/JohnDoe'
    }
};
<|endoftext|>


<commit_before>var through = require('through2');
var _ = require('lodash');

module.exports = {

  hooks: {

    init: function(format, payload) {

      // make sure we parse $-$ and $$-$$ into katex markup
      payload.md.use(require('markdown-it-katex'));

      // add the katex CSS to all formats. This probably needs to
      // change as we test how katex performs in e-readers.
      var stylesheets = _.get(payload, "config.formats." + format + ".stylesheets.files") || _.get(payload, "config.stylesheets.files");

      // no matter what, all hook functions must return
      // a through2 object, as it's a part of the stream chain.
      return through.obj();
    }
  }

}
<commit_msg>merging into a nice config object<commit_after>var through = require('through2');
var path = require('path');
var _ = require('lodash');

module.exports = {

  hooks: {

    init: function(format, payload) {

      // make sure we parse $-$ and $$-$$ into katex markup
      payload.md.use(require('markdown-it-katex'));

      // add the katex CSS to all formats. This probably needs to
      // change as we test how katex performs in e-readers.
      payload.config.stylesheets = payload.config.stylesheets || {};
      payload.config.stylesheets.files = payload.config.stylesheets.files || [];
      payload.config.stylesheets.files.push(path.join(__dirname, "assets", "katex", "katex.css"));

      // no matter what, all hook functions must return
      // a through2 object, as it's a part of the stream chain.
      return through.obj();
    }
  }

}
<|endoftext|>


<commit_before>import _ from 'lodash'
import async from 'async'
import dbg from 'debug'

const debug = dbg('netiam:plugins:merge')

function extend(document, collection, refField) {
  if (_.isFunction(document.toJSON)) {
    document = document.toJSON()
  }

  return new Promise((resolve, reject) => {
    collection
      .findById(document[refField])
      .lean()
      .exec((err, documentToMerge) => {
        if (err) {
          debug(err)
          return reject(err)
        }

        if (!documentToMerge) {
          return resolve(document)
        }

        const mergedDocument = Object.assign(
          documentToMerge,
          document
        )

        resolve(mergedDocument)
      })
  })
}

function handle(data, collection, refField, expand) {
  return new Promise((resolve, reject) => {
    if (_.isArray(data)) {
      async.map(
        data,
        (document, done) => {
          const subdocs = {}
          let doc

          let p = extend(document, collection, refField)
            .then(function(extendedDocument) {
              doc = extendedDocument
            })

          _.forEach(expand, function(spec, key) {
            p = p.then(() => {
              return handle(document[key], spec.collection, spec.refField)
                .then(function(docs) {
                  subdocs[key] = docs
                })
            })
          })

          p
            .then(() => {
              _.forEach(expand, function(spec, key) {
                doc[key] = subdocs[key]
              })

              done(null, doc)
            })
            .catch((err) => {
              debug(err)
              done(err)
            })
        },
        (err, extendedDocuments) => {
          if (err) {
            debug(err)
            return reject(err)
          }

          resolve(extendedDocuments)
        }
      )
      return
    }

    if (_.isObject(data)) {
      const subdocs = {}
      let doc

      let p = extend(data, collection, refField)
        .then(function(extendedDocument) {
          doc = extendedDocument
        })

      _.forEach(expand, (spec, key) => {
        p = p.then(() => {
          return handle(data[key], spec.collection, spec.refField)
            .then((docs) => {
              subdocs[key] = docs
            })
        })
      })

      p
        .then(() => {
          _.forEach(expand, (spec, key) => {
            doc[key] = subdocs[key]
          })

          resolve(doc)
        })
        .catch((err) => {
          debug(err)
          reject(err)
        })
    }
  })
}

/**
 * This plugin can merge related documents into an existing document
 *
 * @param {Object} spec
 * @returns {Function}
 */
export default function merge(spec) {
  const {collection} = spec
  const {refField} = spec
  let {expand} = spec

  return function(req, res) {
    // property expansion
    if (_.isString(req.query.expand)) {
      var queryExpand = req.query.expand.split(',')
    }
    expand = _.pick(expand, queryExpand)

    return handle(res.body, collection, refField, expand)
      .then(docs => {
        res.body = docs
      })
  }
}
<commit_msg>fix: preserve initial expand spec<commit_after>import _ from 'lodash'
import async from 'async'
import dbg from 'debug'

const debug = dbg('netiam:plugins:merge')

function extend(document, collection, refField) {
  if (_.isFunction(document.toJSON)) {
    document = document.toJSON()
  }

  return new Promise((resolve, reject) => {
    collection
      .findById(document[refField])
      .lean()
      .exec((err, documentToMerge) => {
        if (err) {
          debug(err)
          return reject(err)
        }

        if (!documentToMerge) {
          return resolve(document)
        }

        const mergedDocument = Object.assign(
          documentToMerge,
          document
        )

        resolve(mergedDocument)
      })
  })
}

function handle(data, collection, refField, expand) {
  return new Promise((resolve, reject) => {
    if (_.isArray(data)) {
      async.map(
        data,
        (document, done) => {
          const subdocs = {}
          let doc

          let p = extend(document, collection, refField)
            .then(function(extendedDocument) {
              doc = extendedDocument
            })

          _.forEach(expand, function(spec, key) {
            p = p.then(() => {
              return handle(document[key], spec.collection, spec.refField)
                .then(function(docs) {
                  subdocs[key] = docs
                })
            })
          })

          p
            .then(() => {
              _.forEach(expand, function(spec, key) {
                doc[key] = subdocs[key]
              })

              done(null, doc)
            })
            .catch((err) => {
              debug(err)
              done(err)
            })
        },
        (err, extendedDocuments) => {
          if (err) {
            debug(err)
            return reject(err)
          }

          resolve(extendedDocuments)
        }
      )
      return
    }

    if (_.isObject(data)) {
      const subdocs = {}
      let doc

      let p = extend(data, collection, refField)
        .then(function(extendedDocument) {
          doc = extendedDocument
        })

      _.forEach(expand, (spec, key) => {
        p = p.then(() => {
          return handle(data[key], spec.collection, spec.refField)
            .then((docs) => {
              subdocs[key] = docs
            })
        })
      })

      p
        .then(() => {
          _.forEach(expand, (spec, key) => {
            doc[key] = subdocs[key]
          })

          resolve(doc)
        })
        .catch((err) => {
          debug(err)
          reject(err)
        })
    }
  })
}

/**
 * This plugin can merge related documents into an existing document
 *
 * @param {Object} spec
 * @returns {Function}
 */
export default function merge(spec) {
  const {collection} = spec
  const {refField} = spec
  let {expand} = spec

  return function(req, res) {
    let queryExpand
    // property expansion
    if (_.isString(req.query.expand)) {
      queryExpand = req.query.expand.split(',')
    }
    let expandedPaths = _.pick(expand, queryExpand)

    return handle(res.body, collection, refField, expandedPaths)
      .then(docs => {
        res.body = docs
      })
  }
}
<|endoftext|>


<commit_before>/**
 * @ngdoc filter
 * @name ngSanitize.filter:linky
 * @function
 *
 * @description
 *   Finds links in text input and turns them into html links. Supports http/https/ftp/mailto and
 *   plain email address links.
 *
 * @param {string} text Input text.
 * @returns {string} Html-linkified text.
 *
 * @example
   <doc:example module="ngSanitize">
     <doc:source>

       Snippet: <textarea ng-model="snippet" cols="60" rows="3"></textarea>

           Filter
           Source
           Rendered

           linky filter

<div ng-bind-html="snippet | linky">
</div>

           no filter

<div ng-bind="snippet">
</div>

     </doc:source>
     <doc:scenario>
       it('should linkify the snippet with urls', function() {
         expect(using('#linky-filter').binding('snippet | linky')).
           toBe('Pretty text with some links:
' +
                'http://angularjs.org/,
' +
                'us@somewhere.org,
' +
                'another@somewhere.org,
' +
                'and one more: ftp://127.0.0.1/.');
       });

       it ('should not linkify snippet without the linky filter', function() {
         expect(using('#escaped-html').binding('snippet')).
           toBe("Pretty text with some links:\n" +
                "http://angularjs.org/,\n" +
                "mailto:us@somewhere.org,\n" +
                "another@somewhere.org,\n" +
                "and one more: ftp://127.0.0.1/.");
       });

       it('should update', function() {
         input('snippet').enter('new http://link.');
         expect(using('#linky-filter').binding('snippet | linky')).
           toBe('new http://link.');
         expect(using('#escaped-html').binding('snippet')).toBe('new http://link.');
       });
     </doc:scenario>
   </doc:example>
 */
angular.module('ngSanitize').filter('linky', function() {
  var LINKY_URL_REGEXP = /((ftp|https?):\/\/|(mailto:)?[A-Za-z0-9._%+-]+@)\S*[^\s\.\;\,\(\)\{\}\<\>]/,
      MAILTO_REGEXP = /^mailto:/;

  return function(text) {
    if (!text) return text;
    var match;
    var raw = text;
    var html = [];
    // TODO(vojta): use $sanitize instead
    var writer = htmlSanitizeWriter(html);
    var url;
    var i;
    while ((match = raw.match(LINKY_URL_REGEXP))) {
      // We can not end in these as they are sometimes found at the end of the sentence
      url = match[0];
      // if we did not match ftp/http/mailto then assume mailto
      if (match[2] == match[3]) url = 'mailto:' + url;
      i = match.index;
      writer.chars(raw.substr(0, i));
      writer.start('a', {href:url});
      writer.chars(match[0].replace(MAILTO_REGEXP, ''));
      writer.end('a');
      raw = raw.substring(i + match[0].length);
    }
    writer.chars(raw);
    return html.join('');
  };
});
<commit_msg>fix(docs): fixed documentation for using linky<commit_after>/**
 * @ngdoc filter
 * @name ngSanitize.filter:linky
 * @function
 *
 * @description
 *   Finds links in text input and turns them into html links. Supports http/https/ftp/mailto and
 *   plain email address links.
 *
 * @param {string} text Input text.
 * @returns {string} Html-linkified text.
 *
 * @usage

 *
 * @example
   <doc:example module="ngSanitize">
     <doc:source>

       Snippet: <textarea ng-model="snippet" cols="60" rows="3"></textarea>

           Filter
           Source
           Rendered

           linky filter

<div ng-bind-html="snippet | linky">
</div>

           no filter

<div ng-bind="snippet">
</div>

     </doc:source>
     <doc:scenario>
       it('should linkify the snippet with urls', function() {
         expect(using('#linky-filter').binding('snippet | linky')).
           toBe('Pretty text with some links:
' +
                'http://angularjs.org/,
' +
                'us@somewhere.org,
' +
                'another@somewhere.org,
' +
                'and one more: ftp://127.0.0.1/.');
       });

       it ('should not linkify snippet without the linky filter', function() {
         expect(using('#escaped-html').binding('snippet')).
           toBe("Pretty text with some links:\n" +
                "http://angularjs.org/,\n" +
                "mailto:us@somewhere.org,\n" +
                "another@somewhere.org,\n" +
                "and one more: ftp://127.0.0.1/.");
       });

       it('should update', function() {
         input('snippet').enter('new http://link.');
         expect(using('#linky-filter').binding('snippet | linky')).
           toBe('new http://link.');
         expect(using('#escaped-html').binding('snippet')).toBe('new http://link.');
       });
     </doc:scenario>
   </doc:example>
 */
angular.module('ngSanitize').filter('linky', function() {
  var LINKY_URL_REGEXP = /((ftp|https?):\/\/|(mailto:)?[A-Za-z0-9._%+-]+@)\S*[^\s\.\;\,\(\)\{\}\<\>]/,
      MAILTO_REGEXP = /^mailto:/;

  return function(text) {
    if (!text) return text;
    var match;
    var raw = text;
    var html = [];
    // TODO(vojta): use $sanitize instead
    var writer = htmlSanitizeWriter(html);
    var url;
    var i;
    while ((match = raw.match(LINKY_URL_REGEXP))) {
      // We can not end in these as they are sometimes found at the end of the sentence
      url = match[0];
      // if we did not match ftp/http/mailto then assume mailto
      if (match[2] == match[3]) url = 'mailto:' + url;
      i = match.index;
      writer.chars(raw.substr(0, i));
      writer.start('a', {href:url});
      writer.chars(match[0].replace(MAILTO_REGEXP, ''));
      writer.end('a');
      raw = raw.substring(i + match[0].length);
    }
    writer.chars(raw);
    return html.join('');
  };
});
<|endoftext|>


<commit_before>// noflo-component-factory.js

var _ = require('underscore');
var noflo = require('noflo');
var access = require('./noflo-component-access');

/**
 * Creates a noflo Component factory function from a component definition,
 * registers any event handlers on definition. Triggers ondata events for outPorts.
 * The context of all registered event handlers is of a Component/Port facade and
 * not of the EventEmitter itself. This prevents the caller from gaining access
 * to private areas of noflo internals.
 *
 * Usage:
 *  componentFactory({
 *      description: "text",
 *      icon: 'fontawesome-icon-name',
 *      inPorts: {
 *          portName: {
 *              ondata: function(payload, socketIndex)
 *          }
 *      },
 *      outPorts: {
 *          portName: {
 *              ondata: function(payload)
 *          }
 *      },
 *      onicon: function(icon)
 *   });
 */
module.exports = function(nodeDef, callback){
    if (!nodeDef) throw Error("No parameter");
    return function(metadata) {
        // noflo requires each port and nodeInstance to have its own options object
        var node = new noflo.Component({
            outPorts: _.mapObject(nodeDef.outPorts, _.clone),
            inPorts: _.mapObject(nodeDef.inPorts, _.clone)
        });
        triggerPortDataEvents(node.outPorts);
        var facade = access(node);
        registerPorts(node.outPorts, facade.outPorts, nodeDef.outPorts);
        registerPorts(node.inPorts, facade.inPorts, nodeDef.inPorts);
        registerListeners(node, facade, nodeDef);
        node.description = nodeDef.description;
        node.setIcon(nodeDef.icon);
        if (_.isFunction(callback)) {
            callback.call(node, facade);
        }
        // Used by common-test.js#createComponent to gain access to the facade
        if (metadata && _.isFunction(metadata.facade)) {
            metadata.facade.call(node, facade);
        }
        return node;
    };
};

/**
 * Fires data event when OutPort send function is called on port.
 */
function triggerPortDataEvents(ports) {
    _.each(ports, function(port) {
        if (_.isFunction(port.send)) {
            port.send = _.partial(thenTrigger, port.send, 'data');
        }
    });
}

/**
 * Emit event after function is called
 * @this Port object sending the payload
 * @param fn function to call
 * @param event event to emit
 */
function thenTrigger(fn, event /* arguments to fn and event */) {
    var args = _.toArray(arguments).slice(2);
    var ret = fn.apply(this, args);
    this.emit.apply(this, [].concat(event, args));
    return ret;
}

/**
 * Register listeners of the set of port definitions with this actual noflo Ports set.
 *
 * Usage:
 *  registerPorts({portName: new Port()}, {portName: new PortFacade()}, {
 *      portName: {
 *          ondata: function(payload, socketIndex)
 *      }
 *  });
 */
function registerPorts(ports, facades, portDefs) {
    _.each(portDefs, function(portDef, name) {
        registerListeners(ports[name], facades[name], portDef);
    });
}

/**
 * Registers listers by their event type to this EventEmitter.
 * @param eventEmitter a noflo.Component/Port
 * @param context the facade that the listeners should be bound to
 * @param listeners a hash of event types (prefixed with 'on') to handlers
 * Usage:
 *  registerListeners(new EventEmitter(), facade, {
 *      ondata: function(payload, socketIndex)
 *  });
 */
function registerListeners(eventEmitter, context, listeners) {
    var handlers = _.pick(listeners, isListener);
    var boundHandlers = _.mapObject(handlers, bindThis, context);
    _.each(boundHandlers, register, eventEmitter);
}

/**
 * Checks the given function and that name starts with 'on'.
 * @param fn is a function if result is true
 * @param name starts with 'on' if result is true
 */
function isListener(fn, name) {
    return _.isFunction(fn) && name.indexOf('on') === 0;
}

/**
 * Returns the given function with the context bound to this context.
 * This is needed to ensure that the event handlers are always bound to the facade
 * and not to the underlying noflo Component/Port.
 * @this The component/port facade
 * @param fn the event handler function
 */
function bindThis(fn) {
    return fn.bind(this);
}

/**
 * Registers the function handler with the event type for this EventEmitter.
 * @this EventEmitter (Component or Port) that this fn should be registered with
 * @param fn function handler
 * @param name event type prefixed with 'on'
 */
function register(fn, name) {
    this.on(name.substring(2), fn);
}
<commit_msg>s/listers/listeners/<commit_after>// noflo-component-factory.js

var _ = require('underscore');
var noflo = require('noflo');
var access = require('./noflo-component-access');

/**
 * Creates a noflo Component factory function from a component definition,
 * registers any event handlers on definition. Triggers ondata events for outPorts.
 * The context of all registered event handlers is of a Component/Port facade and
 * not of the EventEmitter itself. This prevents the caller from gaining access
 * to private areas of noflo internals.
 *
 * Usage:
 *  componentFactory({
 *      description: "text",
 *      icon: 'fontawesome-icon-name',
 *      inPorts: {
 *          portName: {
 *              ondata: function(payload, socketIndex)
 *          }
 *      },
 *      outPorts: {
 *          portName: {
 *              ondata: function(payload)
 *          }
 *      },
 *      onicon: function(icon)
 *   });
 */
module.exports = function(nodeDef, callback){
    if (!nodeDef) throw Error("No parameter");
    return function(metadata) {
        // noflo requires each port and nodeInstance to have its own options object
        var node = new noflo.Component({
            outPorts: _.mapObject(nodeDef.outPorts, _.clone),
            inPorts: _.mapObject(nodeDef.inPorts, _.clone)
        });
        triggerPortDataEvents(node.outPorts);
        var facade = access(node);
        registerPorts(node.outPorts, facade.outPorts, nodeDef.outPorts);
        registerPorts(node.inPorts, facade.inPorts, nodeDef.inPorts);
        registerListeners(node, facade, nodeDef);
        node.description = nodeDef.description;
        node.setIcon(nodeDef.icon);
        if (_.isFunction(callback)) {
            callback.call(node, facade);
        }
        // Used by common-test.js#createComponent to gain access to the facade
        if (metadata && _.isFunction(metadata.facade)) {
            metadata.facade.call(node, facade);
        }
        return node;
    };
};

/**
 * Fires data event when OutPort send function is called on port.
 */
function triggerPortDataEvents(ports) {
    _.each(ports, function(port) {
        if (_.isFunction(port.send)) {
            port.send = _.partial(thenTrigger, port.send, 'data');
        }
    });
}

/**
 * Emit event after function is called
 * @this Port object sending the payload
 * @param fn function to call
 * @param event event to emit
 */
function thenTrigger(fn, event /* arguments to fn and event */) {
    var args = _.toArray(arguments).slice(2);
    var ret = fn.apply(this, args);
    this.emit.apply(this, [].concat(event, args));
    return ret;
}

/**
 * Register listeners of the set of port definitions with this actual noflo Ports set.
 *
 * Usage:
 *  registerPorts({portName: new Port()}, {portName: new PortFacade()}, {
 *      portName: {
 *          ondata: function(payload, socketIndex)
 *      }
 *  });
 */
function registerPorts(ports, facades, portDefs) {
    _.each(portDefs, function(portDef, name) {
        registerListeners(ports[name], facades[name], portDef);
    });
}

/**
 * Registers listeners by their event type to this EventEmitter.
 * @param eventEmitter a noflo.Component/Port
 * @param context the facade that the listeners should be bound to
 * @param listeners a hash of event types (prefixed with 'on') to handlers
 * Usage:
 *  registerListeners(new EventEmitter(), facade, {
 *      ondata: function(payload, socketIndex)
 *  });
 */
function registerListeners(eventEmitter, context, listeners) {
    var handlers = _.pick(listeners, isListener);
    var boundHandlers = _.mapObject(handlers, bindThis, context);
    _.each(boundHandlers, register, eventEmitter);
}

/**
 * Checks the given function and that name starts with 'on'.
 * @param fn is a function if result is true
 * @param name starts with 'on' if result is true
 */
function isListener(fn, name) {
    return _.isFunction(fn) && name.indexOf('on') === 0;
}

/**
 * Returns the given function with the context bound to this context.
 * This is needed to ensure that the event handlers are always bound to the facade
 * and not to the underlying noflo Component/Port.
 * @this The component/port facade
 * @param fn the event handler function
 */
function bindThis(fn) {
    return fn.bind(this);
}

/**
 * Registers the function handler with the event type for this EventEmitter.
 * @this EventEmitter (Component or Port) that this fn should be registered with
 * @param fn function handler
 * @param name event type prefixed with 'on'
 */
function register(fn, name) {
    this.on(name.substring(2), fn);
}
<|endoftext|>


<commit_before>const fs = require('fs');
const merge = require('merge');
const path = require('path');

const Promise = require('promise');
const Url = require('url');

class Plugin {
  constructor(config) {
    this.config = config || {};
  }

  /**
   *
   * @param file {String}
   * @param renderResult {StromboliRenderResult}
   * @returns {Promise}
   */
  render(file, renderResult) {
    var that = this;

    const sass = require('node-sass');
    const sassRender = Promise.denodeify(sass.render);

    var replaceUrls = function (filePath) {
      if (!path.extname(filePath)) {
        filePath += '.scss';
      }

      try {
        var data = fs.readFileSync(filePath).toString();
      }
      catch (err) {
        // try with an "_"
        var basename = path.basename(filePath);
        var dirname = path.dirname(filePath);

        basename = '_' + basename;

        filePath = path.join(dirname, basename);

        data = fs.readFileSync(filePath).toString();
      }

      renderResult.addDependency(filePath);

      var basePath = path.dirname(path.relative(path.resolve('.'), filePath));
      var regExp = /\s*url\s*\(\s*(?:'(\S*?)'|"(\S*?)"|((?:\\\s|\\\)|\\"|\\'|\S)*?))\s*\)/gi; // @see https://regex101.com/r/1ot3Ax/3

      var matches = null;

      while (matches = regExp.exec(data)) {
        var match = matches[0];
        var resourceUrl = matches[1] || matches[2];

        data = data.replace(match, ' stromboli-plugin-sass-url("' + resourceUrl + '", "' + basePath + '")');
      }

      return {
        file: filePath,
        contents: data
      };
    };

    var data = replaceUrls(file);

    renderResult.addDependency(file);

    var sassConfig = merge.recursive({
      file: data.file,
      data: data.contents,
      outFile: 'index.css',
      importer: function (url, prev, done) {
        var importPath = path.resolve(path.join(path.dirname(prev), url));

        try {
          var result = replaceUrls(importPath);
        }
        catch (err) {
          renderResult.addDependency(prev);

          return new Error(err.message);
        }

        return result;
      },
      functions: {
        'stromboli-plugin-sass-url($url, $base)': function (url, base) {
          var Url = require('url');
          var rewrotePath = path.join(base.getValue(), url.getValue());
          var resourceUrl = Url.parse(rewrotePath);
          var resolvedPath = path.resolve(resourceUrl.pathname);

          try {
            fs.statSync(resolvedPath);

            renderResult.addDependency(resolvedPath)
          }
          catch (err) {
            // that's OK, don't return the file as a dependency
          }

          return new sass.types.String('url("' + rewrotePath + '")');
        }
      }
    }, that.config);

    // sass render
    return sassRender(sassConfig).then(
      function (sassRenderResult) { // sass render success
        var outFile = sassConfig.outFile || 'index.css';
        var includedFiles = sassRenderResult.stats.includedFiles;

        return Promise.all(includedFiles.map(function (includedFile) {
          renderResult.addDependency(includedFile);

          return includedFile;
        })).then(function () {
          renderResult.addBinary(outFile, sassRenderResult.css.toString());

          if (sassRenderResult.map && !sassConfig.sourceMapEmbed) {
            renderResult.addBinary(outFile + '.map', sassRenderResult.map.toString());
          }

          return renderResult;
        });
      },
      function (err) {
        var error = {
          file: err.file,
          message: err.formatted
        };

        return Promise.reject(error);
      }
    );
  }
}

module.exports = Plugin;<commit_msg>Fix issue #27<commit_after>const fs = require('fs');
const merge = require('merge');
const path = require('path');

const Promise = require('promise');
const Url = require('url');

class Plugin {
  constructor(config) {
    this.config = config || {};
  }

  /**
   *
   * @param file {String}
   * @param renderResult {StromboliRenderResult}
   * @returns {Promise}
   */
  render(file, renderResult) {
    var that = this;

    const sass = require('node-sass');
    const sassRender = Promise.denodeify(sass.render);

    var replaceUrls = function (filePath) {
      if (!path.extname(filePath)) {
        filePath += '.scss';
      }

      try {
        var data = fs.readFileSync(filePath).toString();
      }
      catch (err) {
        // try with an "_"
        var basename = path.basename(filePath);
        var dirname = path.dirname(filePath);

        basename = '_' + basename;

        filePath = path.join(dirname, basename);

        data = fs.readFileSync(filePath).toString();
      }

      renderResult.addDependency(filePath);

      var basePath = path.dirname(path.relative(path.resolve('.'), filePath)).replace(/\\/g, '/');
      var regExp = /\s*url\s*\(\s*(?:'(\S*?)'|"(\S*?)"|((?:\\\s|\\\)|\\"|\\'|\S)*?))\s*\)/gi; // @see https://regex101.com/r/1ot3Ax/3

      var matches = null;

      while (matches = regExp.exec(data)) {
        var match = matches[0];
        var resourceUrl = matches[1] || matches[2];

        data = data.replace(match, ' stromboli-plugin-sass-url("' + resourceUrl + '", "' + basePath + '")');
      }

      return {
        file: filePath,
        contents: data
      };
    };

    var data = replaceUrls(file);

    renderResult.addDependency(file);

    var sassConfig = merge.recursive({
      file: data.file,
      data: data.contents,
      outFile: 'index.css',
      importer: function (url, prev, done) {
        var importPath = path.resolve(path.join(path.dirname(prev), url));

        try {
          var result = replaceUrls(importPath);
        }
        catch (err) {
          renderResult.addDependency(prev);

          return new Error(err.message);
        }

        return result;
      },
      functions: {
        'stromboli-plugin-sass-url($url, $base)': function (url, base) {
          var Url = require('url');
          var rewrotePath = path.join(base.getValue(), url.getValue());
          var resourceUrl = Url.parse(rewrotePath);
          var resolvedPath = path.resolve(resourceUrl.pathname);

          try {
            fs.statSync(resolvedPath);

            renderResult.addDependency(resolvedPath)
          }
          catch (err) {
            // that's OK, don't return the file as a dependency
          }

          rewrotePath = rewrotePath.replace(/\\/g, '/');

          return new sass.types.String('url("' + rewrotePath + '")');
        }
      }
    }, that.config);

    // sass render
    return sassRender(sassConfig).then(
      function (sassRenderResult) { // sass render success
        var outFile = sassConfig.outFile || 'index.css';
        var includedFiles = sassRenderResult.stats.includedFiles;

        return Promise.all(includedFiles.map(function (includedFile) {
          renderResult.addDependency(includedFile);

          return includedFile;
        })).then(function () {
          renderResult.addBinary(outFile, sassRenderResult.css.toString());

          if (sassRenderResult.map && !sassConfig.sourceMapEmbed) {
            renderResult.addBinary(outFile + '.map', sassRenderResult.map.toString());
          }

          return renderResult;
        });
      },
      function (err) {
        var error = {
          file: err.file,
          message: err.formatted
        };

        return Promise.reject(error);
      }
    );
  }
}

module.exports = Plugin;<|endoftext|>


<commit_before>/**
 * Created by marco.gobbi on 07/11/2014.
 */
define(function (require, exports, module) {
	"use strict";
	var signals = require("../../../bower_components/signals/dist/signals.min");
	var _ = require("../../../bower_components/lodash/dist/lodash.min");

	function DisplayList() {
		this.onAdded = new signals.Signal();
		this.onRemoved = new signals.Signal();
		// The node to be monitored
		// Create an observer instance
		var observer = new MutationObserver(this.handleMutations.bind(this));
		// Configuration of the observer:
		// Pass in the target node, as well as the observer options
		observer.observe(document.body, {
			attributes: false,
			childList: true,
			characterData: false
		});
	}

	DisplayList.prototype = {
		handleMutations: function (mutations) {
			var response = _.reduce(mutations, function (result, mutation, index) {
				result.addedNodes = result.addedNodes.concat(Array.prototype.slice.call(mutation.addedNodes));
				result.removedNodes = result.removedNodes.concat(Array.prototype.slice.call(mutation.removedNodes));
				return result;
			}, {addedNodes: [], removedNodes: []});
			//
			response.addedNodes.length && this.onAdded.dispatch(response.addedNodes);
			response.removedNodes.length && this.onRemoved.dispatch(response.removedNodes);
		}
	};
	module.exports = DisplayList;
});<commit_msg>fixed deps path<commit_after>/**
 * Created by marco.gobbi on 07/11/2014.
 */
define(function (require, exports, module) {
	"use strict";
	var signals = require("signals");
	var _ = require("lodash");

	function DisplayList() {
		this.onAdded = new signals.Signal();
		this.onRemoved = new signals.Signal();
		// The node to be monitored
		// Create an observer instance
		var observer = new MutationObserver(this.handleMutations.bind(this));
		// Configuration of the observer:
		// Pass in the target node, as well as the observer options
		observer.observe(document.body, {
			attributes: false,
			childList: true,
			characterData: false
		});
	}

	DisplayList.prototype = {
		handleMutations: function (mutations) {
			var response = _.reduce(mutations, function (result, mutation, index) {
				result.addedNodes = result.addedNodes.concat(Array.prototype.slice.call(mutation.addedNodes));
				result.removedNodes = result.removedNodes.concat(Array.prototype.slice.call(mutation.removedNodes));
				return result;
			}, {addedNodes: [], removedNodes: []});
			//
			response.addedNodes.length && this.onAdded.dispatch(response.addedNodes);
			response.removedNodes.length && this.onRemoved.dispatch(response.removedNodes);
		}
	};
	module.exports = DisplayList;
});<|endoftext|>


<commit_before>import program from 'commander';
import inquirer from 'inquirer';

import CommandError from './CommandError';

export default function prompt(questions, { nonInteractiveHelp } = {}) {
  if (program.nonInteractive) {
    let message = `Input is required, but ${program.name} is in non-interactive mode.\n`;
    if (nonInteractiveHelp) {
      message += nonInteractiveHelp;
    } else {
      let question = Array.isArray(questions) ? questions[0] : questions;
      message += `Required input:\n${question.message.trim().replace(/^/gm, '> ')}`;
    }
    throw new CommandError('NON_INTERACTIVE', message);
  }
  return inquirer.prompt(questions);
}
<commit_msg>Fix prompt error in non-interactive mode<commit_after>import program from 'commander';
import inquirer from 'inquirer';

import CommandError from './CommandError';

export default function prompt(questions, { nonInteractiveHelp } = {}) {
  if (program.nonInteractive && questions.length !== 0) {
    let message = `Input is required, but ${program.name} is in non-interactive mode.\n`;
    if (nonInteractiveHelp) {
      message += nonInteractiveHelp;
    } else {
      let question = Array.isArray(questions) ? questions[0] : questions;
      message += `Required input:\n${question.message.trim().replace(/^/gm, '> ')}`;
    }
    throw new CommandError('NON_INTERACTIVE', message);
  }
  return inquirer.prompt(questions);
}
<|endoftext|>


<commit_before>///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Particle Swarm Optimization Visualization
//
// Author : Marc Gumowski
//
// Description : Function allowing to visualize a simple implementation of the  particle
//               swarm optimization algorithm (PSO).
//
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

function psoViz(id, expr, options) {

  ////////////////////////////////////////////////////////
  // Initial options /////////////////////////////////////
  ////////////////////////////////////////////////////////

  var cfg = {
    width: Math.min(760, window.innerWidth - 10),
    height: Math.min(640, window.innerHeight - 20),
    grid: { xMin: -2, xMax: 2, yMin: -2, yMax: 2 },
    // Vizualization parameters
    radius: 3,
    color: 'ff6600',
    colorBest: "#1b9e77",
    // Algorithm parameters
    iteration: 100,
    number: 50,
    w: 0.72984,
    c1: 2.05 * 0.72984,
    c2: 2.05 * 0.72984,
    animationSpeed: 100
  };

  //Put all of the options into a variable called cfg
	if('undefined' !== typeof options){
	  for(var p in options){
		if('undefined' !== typeof options[p]){ cfg[p] = options[p]; }
	  }
	}

	function randomize(min, max) {
    return Math.random() * (max - min) + min;
  }

  Array.prototype.getMin = function(attrib) {
    return this.reduce(function(prev, curr){
        return prev[attrib] < curr[attrib] ? prev : curr;
    });
  };

  function getgbest(data) {
    best = data.getMin('pbestEval');
    best.color = cfg.colorBest;
    return best;
  }

  ////////////////////////////////////////////////////////
  // SVG /////////////////////////////////////////////////
  ////////////////////////////////////////////////////////

	// Svg
	var svg = d3.select(id).append("svg")
	    .attr('id', 'psoVizSVG')
			.attr("width",  cfg.width)
			.attr("height", cfg.height);

	// Tooltip
	var tip = d3.select(id).append('div')
    .attr('class', 'tooltip')
    .style('opacity', 0);

  // Create a table to display the results
  d3.select("#psoVizResults").append("table");
  var tipBestX = d3.select("#psoVizResults").selectAll("table").append("tr"),
      tipBestY = d3.select("#psoVizResults").selectAll("table").append("tr"),
      tipBestF = d3.select("#psoVizResults").selectAll("table").append("tr"),
      tipBestIt = d3.select("#psoVizResults").selectAll("table").append("tr");

  ////////////////////////////////////////////////////////
  // Scale ///////////////////////////////////////////////
  ////////////////////////////////////////////////////////

	var scaleX = d3.scaleLinear()
	  .domain([cfg.grid.xMin, cfg.grid.xMax])
	  .range([0, cfg.width]);

	var scaleY = d3.scaleLinear()
	  .domain([cfg.grid.yMin, cfg.grid.yMax])
	  .range([0, cfg.height]);

  ////////////////////////////////////////////////////////
  // Contour /////////////////////////////////////////////
  ////////////////////////////////////////////////////////

  // Create a grid of value
 var n = 240, m = Math.round(240 * cfg.height / cfg.width), values = new Array(n * m);
  for (var j = 0.5, k = 0; j < m; ++j) {
    for (var i = 0.5; i < n; ++i, ++k) {
      values[k] = expr(cfg.grid.xMin + (cfg.grid.xMax - cfg.grid.xMin) * i / n,
                       cfg.grid.yMax - (cfg.grid.yMax - cfg.grid.yMin) * j / m);
    }
  }

  // Plot
  var thresholds = d3.range(1, 21)
      .map(function(p) { return Math.pow(2, p); });

  var contours = d3.contours()
      .size([n, m])
      .thresholds(thresholds);

  var color = d3.scaleLog()
      .domain(d3.extent(thresholds))
      .interpolate(function() { return d3.interpolateYlGnBu; });

  svg.append("g").selectAll("path")
    .data(contours(values))
    .enter().append("path")
      .attr("d", d3.geoPath(d3.geoIdentity().scale(cfg.width / n)))
      .attr("fill", function(d) { return color(d.value); })
      .style("stroke", "#fff")
      .style("stroke-width", 0.5);

  ////////////////////////////////////////////////////////
  // Particles ///////////////////////////////////////////
  ////////////////////////////////////////////////////////

  // Initialize data with best known position pbest and velocity
  var data = new Array(1 * cfg.number);
  for (var l = 0; l < cfg.number; ++l) {
    data[l] = {
      "value": cfg.radius,
      "color": cfg.color,
      "position": {
        "x": randomize(scaleX.domain()[0], scaleX.domain()[1]),
        "y": randomize(scaleY.domain()[0], scaleY.domain()[1])
      },
      "velocity": {
        "x": 0,
        "y": 0
      },
      "pbest": {
        "x": [],
        "y": []
      },
      "pbestEval": []
    };
  }

  // Set pbest as initial position
  data.forEach(function(d) {
    d.pbest.x = d.position.x;
    d.pbest.y = d.position.y;
  });

  // Evaluate pbest
  var pbestEval = [];
  data.forEach(function(d) { d.pbestEval = expr(d.pbest.x, d.pbest.y); });

  // Update global best: gbest
  var gbest = getgbest(data);

  // Create particle and initialize position with appropriate scale
  var particles = svg.append('g')
      .style("filter", "url(#gooey)");

  var particle = particles.selectAll('.particle')
      .data(data)
      .enter().append("g")
      .append('circle')
      .attr('class', 'particle')
      .attr('id', function(d,i) { return "particle" + i;})
      .attr('r', function(d) { return d.value; })
      .attr('cx', function(d) { return scaleX(d.position.x); })
      .attr('cy', function(d) { return cfg.height - scaleY(d.position.y); })
      .on("click", function(d) { console.log(d); })
      .style('fill', function(d) { return d.color; })
      .on('mouseover', function(d) {

        d3.select(this).transition("mouse")
          .duration(50)
          .attr('r', 4 * cfg.radius);

        tip.transition("mouse")
          .duration(0)
          .style('opacity', 1);
        tip.html('x = ' + scaleX.invert(d3.select(this).attr("cx")) + ', ' +
                 'y = ' + scaleY.invert(cfg.height - d3.select(this).attr("cy")) + ', ' +
                 'f(x,y) = ' + expr(scaleX.invert(d3.select(this).attr("cx")),
                 scaleY.invert(cfg.height - d3.select(this).attr("cy"))));
      })
      .on('mousemove', function(d) {

        tip.html('x = ' + scaleX.invert(d3.select(this).attr("cx")) + ', ' +
                 'y = ' + scaleY.invert(cfg.height - d3.select(this).attr("cy")) + ', ' +
                 'f(x,y) = ' + expr(scaleX.invert(d3.select(this).attr("cx")),
                 scaleY.invert(cfg.height - d3.select(this).attr("cy"))));
      })
      .on('mouseout', function(d) {

        d3.select(this).transition("mouse")
          .duration(500)
          .attr('r', cfg.radius);

       tip.transition("mouse")
          .duration(500)
          .style('opacity', 0);
      });

  // Add best position text in the results table
  tipBestX.text('x = ' + gbest.pbest.x);
  tipBestY.text('y = ' + gbest.pbest.y);
  tipBestF.text('f(x,y) = ' + gbest.pbestEval);
  tipBestIt.text('Iteration: ' + 0);

  ////////////////////////////////////////////////////////
  // Simulation //////////////////////////////////////////
  ////////////////////////////////////////////////////////

  // Button to start simulation
  d3.select('#start')
    .on('click', function(d) {
      psoVizAlgo();
    });

  function psoVizAlgo() {
    // Criteria: max iteration
    for (var it = 0; it < cfg.iteration; ++it) {

      // Loop
      psoVizLoop(data, cfg);
      // Update viz
      // Duration time for each particle to change is based on the euclidean distance of the particles' velocity.
      particle = particle
            .transition("simulation")
            .duration(function(d) { return distance(d.velocity.x, d.velocity.y) / cfg.animationSpeed; })
            .attr('cx', function(d) { return scaleX(d.pbest.x); })
            .attr('cy', function(d) { return cfg.height - scaleY(d.pbest.y); })
            .style('fill', function(d) { return d.color; });

      // Update results table
      tipBestX = tipBestX.transition("simulation")
        .duration(distance(gbest.velocity.x, gbest.velocity.y) / cfg.animationSpeed)
        .text('x = ' + gbest.pbest.x);
      tipBestY = tipBestY.transition("simulation")
        .duration(distance(gbest.velocity.x, gbest.velocity.y) / cfg.animationSpeed)
        .text('y = ' + gbest.pbest.y);
      tipBestF = tipBestF.transition("simulation")
        .duration(distance(gbest.velocity.x, gbest.velocity.y) / cfg.animationSpeed)
        .text('f(x,y) = ' + gbest.pbestEval);
      tipBestIt = tipBestIt.transition("simulation")
        .duration(distance(gbest.velocity.x, gbest.velocity.y) / cfg.animationSpeed)
        .text('Iteration: ' + (it + 1));
    }
  }

  // Function loop (Code can be improved with vector algebra ?)
  function psoVizLoop(data, cfg) {

        // Update velocity
        data.forEach(function(d) {
          d.velocity.x = cfg.w * d.velocity.x + cfg.c1 * Math.random() * (d.pbest.x - d.position.x) +
                       cfg.c2 * Math.random() * (gbest.position.x - d.position.x);
          d.velocity.y = cfg.w * d.velocity.y + cfg.c1 * Math.random() * (d.pbest.y - d.position.y) +
                       cfg.c2 * Math.random() * (gbest.position.y - d.position.y);
        });

        // Clamp velocity
        data.forEach(function(d) {

          var violation = d.velocity.x < cfg.grid.xMin ? 1 : 0;
          d.velocity.x = (1 - violation) * d.velocity.x + violation * cfg.grid.xMin;
          violation = d.velocity.y < cfg.grid.yMin ? 1 : 0;
          d.velocity.y = (1 - violation) * d.velocity.y + violation * cfg.grid.yMin;

          violation = d.velocity.x > cfg.grid.xMax ? 1 : 0;
          d.velocity.x = (1 - violation) * d.velocity.x + violation * cfg.grid.xMax;
          violation = d.velocity.y < cfg.grid.yMin ? 1 : 0;
          d.velocity.y = (1 - violation) * d.velocity.y + violation * cfg.grid.yMax;

        });

        // Update Position
        data.forEach(function(d) {
          d.position.x = d.position.x + d.velocity.x;
          d.position.y = d.position.y + d.velocity.y;
        });

        // Update pbest
        data.forEach(function(d) {
          d.pbest.x = expr(d.position.x, d.position.y) < d.pbestEval ? d.position.x : d.pbest.x;
          d.pbest.y = expr(d.position.x, d.position.y) < d.pbestEval ? d.position.y : d.pbest.y;
        });

        // Update pbestEval
        data.forEach(function(d) {
          d.pbestEval = expr(d.pbest.x, d.pbest.y);
        });

        // Reinitialize color
        data.forEach(function(d) {
          d.color = cfg.color;
        });

        // Update gbest -> getgbest
        gbest = getgbest(data);
        console.log(gbest.pbestEval);
  }

  function distance(x, y) {

    return Math.sqrt(Math.pow(scaleX(x),2) + Math.pow(scaleY(y), 2));

  }

  ////////////////////////////////////////////////////////
  // Legend and Buttons //////////////////////////////////
  ////////////////////////////////////////////////////////

  //SVG filter for the gooey effect
  //Code taken from http://tympanus.net/codrops/2015/03/10/creative-gooey-effects/
  var defs = particles.append('defs');
  var filter = defs.append('filter').attr('id','gooey');
  filter.append('feGaussianBlur')
  	.attr('in','SourceGraphic')
  	.attr('stdDeviation','1.5')
  	.attr('result','blur');
  filter.append('feColorMatrix')
  	.attr('in','blur')
  	.attr('mode','matrix')
  	.attr('values','1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 18 -7')
  	.attr('result','gooey');
  filter.append('feComposite')
  	.attr('in','SourceGraphic')
  	.attr('in2','goo')
  	.attr('operator','atop');

}

<commit_msg>Changed animation speed<commit_after>///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Particle Swarm Optimization Visualization
//
// Author : Marc Gumowski
//
// Description : Function allowing to visualize a simple implementation of the  particle
//               swarm optimization algorithm (PSO).
//
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

function psoViz(id, expr, options) {

  ////////////////////////////////////////////////////////
  // Initial options /////////////////////////////////////
  ////////////////////////////////////////////////////////

  var cfg = {
    width: Math.min(760, window.innerWidth - 10),
    height: Math.min(640, window.innerHeight - 20),
    grid: { xMin: -2, xMax: 2, yMin: -2, yMax: 2 },
    // Vizualization parameters
    radius: 3,
    color: 'ff6600',
    colorBest: "#1b9e77",
    // Algorithm parameters
    iteration: 100,
    number: 50,
    w: 0.72984,
    c1: 2.05 * 0.72984,
    c2: 2.05 * 0.72984,
    animationSpeed: 10
  };

  //Put all of the options into a variable called cfg
	if('undefined' !== typeof options){
	  for(var p in options){
		if('undefined' !== typeof options[p]){ cfg[p] = options[p]; }
	  }
	}

	function randomize(min, max) {
    return Math.random() * (max - min) + min;
  }

  Array.prototype.getMin = function(attrib) {
    return this.reduce(function(prev, curr){
        return prev[attrib] < curr[attrib] ? prev : curr;
    });
  };

  function getgbest(data) {
    best = data.getMin('pbestEval');
    best.color = cfg.colorBest;
    return best;
  }

  ////////////////////////////////////////////////////////
  // SVG /////////////////////////////////////////////////
  ////////////////////////////////////////////////////////

	// Svg
	var svg = d3.select(id).append("svg")
	    .attr('id', 'psoVizSVG')
			.attr("width",  cfg.width)
			.attr("height", cfg.height);

	// Tooltip
	var tip = d3.select(id).append('div')
    .attr('class', 'tooltip')
    .style('opacity', 0);

  // Create a table to display the results
  d3.select("#psoVizResults").append("table");
  var tipBestX = d3.select("#psoVizResults").selectAll("table").append("tr"),
      tipBestY = d3.select("#psoVizResults").selectAll("table").append("tr"),
      tipBestF = d3.select("#psoVizResults").selectAll("table").append("tr"),
      tipBestIt = d3.select("#psoVizResults").selectAll("table").append("tr");

  ////////////////////////////////////////////////////////
  // Scale ///////////////////////////////////////////////
  ////////////////////////////////////////////////////////

	var scaleX = d3.scaleLinear()
	  .domain([cfg.grid.xMin, cfg.grid.xMax])
	  .range([0, cfg.width]);

	var scaleY = d3.scaleLinear()
	  .domain([cfg.grid.yMin, cfg.grid.yMax])
	  .range([0, cfg.height]);

  ////////////////////////////////////////////////////////
  // Contour /////////////////////////////////////////////
  ////////////////////////////////////////////////////////

  // Create a grid of value
 var n = 240, m = Math.round(240 * cfg.height / cfg.width), values = new Array(n * m);
  for (var j = 0.5, k = 0; j < m; ++j) {
    for (var i = 0.5; i < n; ++i, ++k) {
      values[k] = expr(cfg.grid.xMin + (cfg.grid.xMax - cfg.grid.xMin) * i / n,
                       cfg.grid.yMax - (cfg.grid.yMax - cfg.grid.yMin) * j / m);
    }
  }

  // Plot
  var thresholds = d3.range(1, 21)
      .map(function(p) { return Math.pow(2, p); });

  var contours = d3.contours()
      .size([n, m])
      .thresholds(thresholds);

  var color = d3.scaleLog()
      .domain(d3.extent(thresholds))
      .interpolate(function() { return d3.interpolateYlGnBu; });

  svg.append("g").selectAll("path")
    .data(contours(values))
    .enter().append("path")
      .attr("d", d3.geoPath(d3.geoIdentity().scale(cfg.width / n)))
      .attr("fill", function(d) { return color(d.value); })
      .style("stroke", "#fff")
      .style("stroke-width", 0.5);

  ////////////////////////////////////////////////////////
  // Particles ///////////////////////////////////////////
  ////////////////////////////////////////////////////////

  // Initialize data with best known position pbest and velocity
  var data = new Array(1 * cfg.number);
  for (var l = 0; l < cfg.number; ++l) {
    data[l] = {
      "value": cfg.radius,
      "color": cfg.color,
      "position": {
        "x": randomize(scaleX.domain()[0], scaleX.domain()[1]),
        "y": randomize(scaleY.domain()[0], scaleY.domain()[1])
      },
      "velocity": {
        "x": 0,
        "y": 0
      },
      "pbest": {
        "x": [],
        "y": []
      },
      "pbestEval": []
    };
  }

  // Set pbest as initial position
  data.forEach(function(d) {
    d.pbest.x = d.position.x;
    d.pbest.y = d.position.y;
  });

  // Evaluate pbest
  var pbestEval = [];
  data.forEach(function(d) { d.pbestEval = expr(d.pbest.x, d.pbest.y); });

  // Update global best: gbest
  var gbest = getgbest(data);

  // Create particle and initialize position with appropriate scale
  var particles = svg.append('g')
      .style("filter", "url(#gooey)");

  var particle = particles.selectAll('.particle')
      .data(data)
      .enter().append("g")
      .append('circle')
      .attr('class', 'particle')
      .attr('id', function(d,i) { return "particle" + i;})
      .attr('r', function(d) { return d.value; })
      .attr('cx', function(d) { return scaleX(d.position.x); })
      .attr('cy', function(d) { return cfg.height - scaleY(d.position.y); })
      .on("click", function(d) { console.log(d); })
      .style('fill', function(d) { return d.color; })
      .on('mouseover', function(d) {

        d3.select(this).transition("mouse")
          .duration(50)
          .attr('r', 4 * cfg.radius);

        tip.transition("mouse")
          .duration(0)
          .style('opacity', 1);
        tip.html('x = ' + scaleX.invert(d3.select(this).attr("cx")) + ', ' +
                 'y = ' + scaleY.invert(cfg.height - d3.select(this).attr("cy")) + ', ' +
                 'f(x,y) = ' + expr(scaleX.invert(d3.select(this).attr("cx")),
                 scaleY.invert(cfg.height - d3.select(this).attr("cy"))));
      })
      .on('mousemove', function(d) {

        tip.html('x = ' + scaleX.invert(d3.select(this).attr("cx")) + ', ' +
                 'y = ' + scaleY.invert(cfg.height - d3.select(this).attr("cy")) + ', ' +
                 'f(x,y) = ' + expr(scaleX.invert(d3.select(this).attr("cx")),
                 scaleY.invert(cfg.height - d3.select(this).attr("cy"))));
      })
      .on('mouseout', function(d) {

        d3.select(this).transition("mouse")
          .duration(500)
          .attr('r', cfg.radius);

       tip.transition("mouse")
          .duration(500)
          .style('opacity', 0);
      });

  // Add best position text in the results table
  tipBestX.text('x = ' + gbest.pbest.x);
  tipBestY.text('y = ' + gbest.pbest.y);
  tipBestF.text('f(x,y) = ' + gbest.pbestEval);
  tipBestIt.text('Iteration: ' + 0);

  ////////////////////////////////////////////////////////
  // Simulation //////////////////////////////////////////
  ////////////////////////////////////////////////////////

  // Button to start simulation
  d3.select('#start')
    .on('click', function(d) {
      psoVizAlgo();
    });

  function psoVizAlgo() {
    // Criteria: max iteration
    for (var it = 0; it < cfg.iteration; ++it) {

      // Loop
      psoVizLoop(data, cfg);
      // Update viz
      // Duration time for each particle to change is based on the euclidean distance of the particles' velocity.
      particle = particle
            .transition("simulation")
            .duration(function(d) { return distance(d.velocity.x, d.velocity.y) / cfg.animationSpeed; })
            .attr('cx', function(d) { return scaleX(d.pbest.x); })
            .attr('cy', function(d) { return cfg.height - scaleY(d.pbest.y); })
            .style('fill', function(d) { return d.color; });

      // Update results table
      tipBestX = tipBestX.transition("simulation")
        .duration(distance(gbest.velocity.x, gbest.velocity.y) / cfg.animationSpeed)
        .text('x = ' + gbest.pbest.x);
      tipBestY = tipBestY.transition("simulation")
        .duration(distance(gbest.velocity.x, gbest.velocity.y) / cfg.animationSpeed)
        .text('y = ' + gbest.pbest.y);
      tipBestF = tipBestF.transition("simulation")
        .duration(distance(gbest.velocity.x, gbest.velocity.y) / cfg.animationSpeed)
        .text('f(x,y) = ' + gbest.pbestEval);
      tipBestIt = tipBestIt.transition("simulation")
        .duration(distance(gbest.velocity.x, gbest.velocity.y) / cfg.animationSpeed)
        .text('Iteration: ' + (it + 1));
    }
  }

  // Function loop (Code can be improved with vector algebra ?)
  function psoVizLoop(data, cfg) {

        // Update velocity
        data.forEach(function(d) {
          d.velocity.x = cfg.w * d.velocity.x + cfg.c1 * Math.random() * (d.pbest.x - d.position.x) +
                       cfg.c2 * Math.random() * (gbest.position.x - d.position.x);
          d.velocity.y = cfg.w * d.velocity.y + cfg.c1 * Math.random() * (d.pbest.y - d.position.y) +
                       cfg.c2 * Math.random() * (gbest.position.y - d.position.y);
        });

        // Clamp velocity
        data.forEach(function(d) {

          var violation = d.velocity.x < cfg.grid.xMin ? 1 : 0;
          d.velocity.x = (1 - violation) * d.velocity.x + violation * cfg.grid.xMin;
          violation = d.velocity.y < cfg.grid.yMin ? 1 : 0;
          d.velocity.y = (1 - violation) * d.velocity.y + violation * cfg.grid.yMin;

          violation = d.velocity.x > cfg.grid.xMax ? 1 : 0;
          d.velocity.x = (1 - violation) * d.velocity.x + violation * cfg.grid.xMax;
          violation = d.velocity.y < cfg.grid.yMin ? 1 : 0;
          d.velocity.y = (1 - violation) * d.velocity.y + violation * cfg.grid.yMax;

        });

        // Update Position
        data.forEach(function(d) {
          d.position.x = d.position.x + d.velocity.x;
          d.position.y = d.position.y + d.velocity.y;
        });

        // Update pbest
        data.forEach(function(d) {
          d.pbest.x = expr(d.position.x, d.position.y) < d.pbestEval ? d.position.x : d.pbest.x;
          d.pbest.y = expr(d.position.x, d.position.y) < d.pbestEval ? d.position.y : d.pbest.y;
        });

        // Update pbestEval
        data.forEach(function(d) {
          d.pbestEval = expr(d.pbest.x, d.pbest.y);
        });

        // Reinitialize color
        data.forEach(function(d) {
          d.color = cfg.color;
        });

        // Update gbest -> getgbest
        gbest = getgbest(data);
        console.log(gbest.pbestEval);
  }

  function distance(x, y) {

    return Math.sqrt(Math.pow(scaleX(x),2) + Math.pow(scaleY(y), 2));

  }

  ////////////////////////////////////////////////////////
  // Legend and Buttons //////////////////////////////////
  ////////////////////////////////////////////////////////

  //SVG filter for the gooey effect
  //Code taken from http://tympanus.net/codrops/2015/03/10/creative-gooey-effects/
  var defs = particles.append('defs');
  var filter = defs.append('filter').attr('id','gooey');
  filter.append('feGaussianBlur')
  	.attr('in','SourceGraphic')
  	.attr('stdDeviation','1.5')
  	.attr('result','blur');
  filter.append('feColorMatrix')
  	.attr('in','blur')
  	.attr('mode','matrix')
  	.attr('values','1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 18 -7')
  	.attr('result','gooey');
  filter.append('feComposite')
  	.attr('in','SourceGraphic')
  	.attr('in2','goo')
  	.attr('operator','atop');

}<|endoftext|>


<commit_before>'use strict'

const setImmediate = require('async/setImmediate')
const NOT_STARTED_YET = require('./error-messages').NOT_STARTED_YET
const FloodSub = require('libp2p-floodsub')

module.exports = (node) => {
  const floodSub = new FloodSub(node)

  node._floodSub = floodSub

  return {
    subscribe: (topic, options, handler, callback) => {
      if (!node.isStarted() && !floodSub.started) {
        return setImmediate(() => callback(new Error(NOT_STARTED_YET)))
      }

      if (typeof options === 'function') {
        callback = handler
        handler = options
        options = {}
      }

      function subscribe (cb) {
        if (floodSub.listenerCount(topic) === 0) {
          floodSub.subscribe(topic)
        }

        floodSub.pubsub.on(topic, handler)
        setImmediate(cb)
      }

      subscribe(callback)
    },

    unsubscribe: (topic, handler) => {
      if (!node.isStarted() && !floodSub.started) {
        throw new Error(NOT_STARTED_YET)
      }

      floodSub.removeListener(topic, handler)

      if (floodSub.listenerCount(topic) === 0) {
        floodSub.unsubscribe(topic)
      }
    },

    publish: (topic, data, callback) => {
      if (!node.isStarted() && !floodSub.started) {
        return setImmediate(() => callback(new Error(NOT_STARTED_YET)))
      }

      if (!Buffer.isBuffer(data)) {
        return setImmediate(() => callback(new Error('data must be a Buffer')))
      }

      floodSub.publish(topic, data)

      setImmediate(() => callback())
    },

    ls: (callback) => {
      if (!node.isStarted() && !floodSub.started) {
        return setImmediate(() => callback(new Error(NOT_STARTED_YET)))
      }

      const subscriptions = Array.from(floodSub.subscriptions)

      setImmediate(() => callback(null, subscriptions))
    },

    peers: (topic, callback) => {
      if (!node.isStarted() && !floodSub.started) {
        return setImmediate(() => callback(new Error(NOT_STARTED_YET)))
      }

      if (typeof topic === 'function') {
        callback = topic
        topic = null
      }

      const peers = Array.from(floodSub.peers.values())
        .filter((peer) => topic ? peer.topics.has(topic) : true)
        .map((peer) => peer.info.id.toB58String())

      setImmediate(() => callback(null, peers))
    },

    setMaxListeners (n) {
      return floodSub.setMaxListeners(n)
    }
  }
}
<commit_msg>fix: use correct reference to floodSub<commit_after>'use strict'

const setImmediate = require('async/setImmediate')
const NOT_STARTED_YET = require('./error-messages').NOT_STARTED_YET
const FloodSub = require('libp2p-floodsub')

module.exports = (node) => {
  const floodSub = new FloodSub(node)

  node._floodSub = floodSub

  return {
    subscribe: (topic, options, handler, callback) => {
      if (!node.isStarted() && !floodSub.started) {
        return setImmediate(() => callback(new Error(NOT_STARTED_YET)))
      }

      if (typeof options === 'function') {
        callback = handler
        handler = options
        options = {}
      }

      function subscribe (cb) {
        if (floodSub.listenerCount(topic) === 0) {
          floodSub.subscribe(topic)
        }

        floodSub.on(topic, handler)
        setImmediate(cb)
      }

      subscribe(callback)
    },

    unsubscribe: (topic, handler) => {
      if (!node.isStarted() && !floodSub.started) {
        throw new Error(NOT_STARTED_YET)
      }

      floodSub.removeListener(topic, handler)

      if (floodSub.listenerCount(topic) === 0) {
        floodSub.unsubscribe(topic)
      }
    },

    publish: (topic, data, callback) => {
      if (!node.isStarted() && !floodSub.started) {
        return setImmediate(() => callback(new Error(NOT_STARTED_YET)))
      }

      if (!Buffer.isBuffer(data)) {
        return setImmediate(() => callback(new Error('data must be a Buffer')))
      }

      floodSub.publish(topic, data)

      setImmediate(() => callback())
    },

    ls: (callback) => {
      if (!node.isStarted() && !floodSub.started) {
        return setImmediate(() => callback(new Error(NOT_STARTED_YET)))
      }

      const subscriptions = Array.from(floodSub.subscriptions)

      setImmediate(() => callback(null, subscriptions))
    },

    peers: (topic, callback) => {
      if (!node.isStarted() && !floodSub.started) {
        return setImmediate(() => callback(new Error(NOT_STARTED_YET)))
      }

      if (typeof topic === 'function') {
        callback = topic
        topic = null
      }

      const peers = Array.from(floodSub.peers.values())
        .filter((peer) => topic ? peer.topics.has(topic) : true)
        .map((peer) => peer.info.id.toB58String())

      setImmediate(() => callback(null, peers))
    },

    setMaxListeners (n) {
      return floodSub.setMaxListeners(n)
    }
  }
}
<|endoftext|>


<commit_before>import _ from 'lodash'

const initialState = {
      selectedBoard: 1,
      boardsPanelOpen: false,
      boards: [
        {
          boardId: 1,
          boardIndex: 1,
          boardTitle: 'my board',
          lists: [
            {
              listId: 1,
              listIndex: 1,
              listTitle: 'To Do',
              items: [
                {
                  itemId: 1,
                  itemIndex: 1,
                  itemText: 'test'
                }
              ]
            }
          ]
        },
        {
          boardId: 2,
          boardIndex: 3,
          boardTitle: 'my board 2',
          lists: [
            {
              listId: 1,
              listIndex: 1,
              listTitle: 'To Do 2',
              items: [
                {
                  itemId: 1,
                  itemIndex: 1,
                  itemText: 'test 2'
                }
              ]
            }
          ]
        }
      ]
    }

export default function reducer(state =initialState, action){

	switch(action.type){
    case 'TOGGLE_BOARDS_PANEL': {
      console.log(state.boardsPanelOpen)
      console.log(!state.boardsPanelOpen)

      return {...state, boardsPanelOpen:!state.boardsPanelOpen}
      break
    }
    case 'CREATE_ITEM':{
      let {boardId, listId, itemText} = action.payload
      let newState = _.cloneDeep(state)
      let items = newState.boards.find(board => {return board.boardId === boardId}).lists.find(list => {return list.listId === listId}).items
      items.push({itemText,itemId: _.random(10000), itemIndex: items.length+1})
      return newState
      break
    }
    case 'DELETE_ITEM': {
      let {boardId, listId, itemId} = action.payload
      let newState = _.cloneDeep(state)
      let items = newState.boards.find(board => {return board.boardId === boardId}).lists.find(list => {return list.listId === listId}).items
      let index = items.findIndex(item => item.itemId === itemId)
      items.splice(index,1)
      return newState
      break

    }
    case 'CREATE_LIST':{
      let {boardId, listTitle} = action.payload
      let newState = _.cloneDeep(state)
      const lists = newState.boards.find(board => {return board.boardId === boardId}).lists
      lists.push({listId: _.random(100000), listIndex:lists.length+1,listTitle, items:[]})
      return newState
      break
    }
    case 'DELETE_LIST': {
      let {boardId, listId} = action.payload
      let newState = _.cloneDeep(state)
      const lists = newState.boards.find(board => {return board.boardId === boardId}).lists
      let index = lists.findIndex(list => list.listId === listId)
      lists.splice(index,1)
      return newState
      break

    }
    case 'SELECT_BOARD': {
      return {...state, selectedBoard: action.payload.boardId, boardsPanelOpen:false}
    }
    case 'CREATE_BOARD': {
      let {boardTitle} = action.payload
      let newState = _.cloneDeep(state)
      const boardId = _.random(1000)
      newState.boards.push({boardId:boardId , boardIndex:newState.boards.length+1, boardTitle, lists:[]})
      newState.selectedBoard = boardId
      newState.boardsPanelOpen = false
      return newState
    }
    case 'DELETE_BOARD': {
      let {boardId} = action.payload
      let newState = _.cloneDeep(state)
      let index = newState.boards.findIndex(board => board.boardId === boardId)
      newState.boards.splice(index,1)
      return newState
    }
    case 'SWAP_LISTS': {
      let {boardId, dragListId, hoverListId} = action.payload
      let newState = _.cloneDeep(state)
      let board = _.find(newState.boards, (o) => o.boardId === boardId)
      let dragList = _.find(board.lists, (o) => o.listId === dragListId)
      let hoverList = _.find(board.lists, (o) => o.listId === hoverListId)
      let dragIndex = dragList.listIndex
      let hoverIndex = hoverList.listIndex
      dragList.listIndex = hoverIndex
      hoverList.listIndex = dragIndex
      return newState
    }
    case 'SWAP_ITEMS': {
      let {boardId, dragListId, dragItemId, hoverItemId} = action.payload
      let newState = _.cloneDeep(state)
      let board = _.find(newState.boards, (o) => o.boardId === boardId)
      let dragList = _.find(board.lists, (o) => o.listId === dragListId)
      let dragItem = _.find(dragList.items, (o) => o.itemId === dragItemId)
      let hoverItem = _.find(dragList.items, (o) => o.itemId === hoverItemId)
      let dragIndex = dragItem.itemIndex
      let hoverIndex = hoverItem.itemIndex
      dragItem.itemIndex = hoverIndex
      hoverItem.itemIndex = dragIndex
      return newState
    }

    case 'MOVE_ITEM_TO_LIST': {
      let {boardId, dragListId, hoverListId, dragItemId} = action.payload
      let newState = _.cloneDeep(state)
      let board = _.find(newState.boards, (o) => o.boardId === boardId)
      let dragList = _.find(board.lists, (o) => o.listId === dragListId)
      let hoverList = _.find(board.lists, (o) => o.listId === hoverListId)
      let dragItem = _.find(dragList.items, (o) => o.itemId === dragItemId)
      dragItem.itemIndex = hoverList.items.length+1
      hoverList.items.push(dragItem)
      dragList.items = dragList.items.filter((o) => o.itemId !== dragItemId)

      return newState
    }

		default:
			return state;
	}
}
<commit_msg>fixed IE compatibility with find and findIndex<commit_after>import _ from 'lodash'

const initialState = {
      selectedBoard: 1,
      boardsPanelOpen: false,
      boards: [
        {
          boardId: 1,
          boardIndex: 1,
          boardTitle: 'my board',
          lists: [
            {
              listId: 1,
              listIndex: 1,
              listTitle: 'To Do',
              items: [
                {
                  itemId: 1,
                  itemIndex: 1,
                  itemText: 'test'
                }
              ]
            }
          ]
        },
        {
          boardId: 2,
          boardIndex: 3,
          boardTitle: 'my board 2',
          lists: [
            {
              listId: 1,
              listIndex: 1,
              listTitle: 'To Do 2',
              items: [
                {
                  itemId: 1,
                  itemIndex: 1,
                  itemText: 'test 2'
                }
              ]
            }
          ]
        }
      ]
    }

export default function reducer(state =initialState, action){
//   if (!Array.prototype.find) {
//   Array.prototype.find = function(predicate) {
//     'use strict';
//     if (this == null) {
//       throw new TypeError('Array.prototype.find called on null or undefined');
//     }
//     if (typeof predicate !== 'function') {
//       throw new TypeError('predicate must be a function');
//     }
//     var list = Object(this);
//     var length = list.length >>> 0;
//     var thisArg = arguments[1];
//     var value;

//     for (var i = 0; i < length; i++) {
//       value = list[i];
//       if (predicate.call(thisArg, value, i, list)) {
//         return value;
//       }
//     }
//     return undefined;
//   };
// }

	switch(action.type){
    case 'TOGGLE_BOARDS_PANEL': {

      return {...state, boardsPanelOpen:!state.boardsPanelOpen}
      break
    }
    case 'CREATE_ITEM':{
      let {boardId, listId, itemText} = action.payload
      let newState = _.cloneDeep(state)
      let board = _.find(newState.boards, (board) => board.boardId === boardId)
      let items = _.find(board.lists, (list) => list.listId === listId).items
      items.push({itemText,itemId: _.random(10000), itemIndex: items.length+1})
      return newState
      break
    }
    case 'DELETE_ITEM': {
      let {boardId, listId, itemId} = action.payload
      let newState = _.cloneDeep(state)
      let board = _.find(newState.boards, (board) => board.boardId === boardId)
      let items = _.find(board.lists, (list) => list.listId === listId).items
      let index = _.findIndex(items, (item) => item.itemId === itemId)
      items.splice(index,1)
      return newState
      break

    }
    case 'CREATE_LIST':{
      let {boardId, listTitle} = action.payload
      let newState = _.cloneDeep(state)
      const lists = _.find(newState.boards, (board) => board.boardId === boardId).lists
      lists.push({listId: _.random(100000), listIndex:lists.length+1,listTitle, items:[]})
      return newState
      break
    }
    case 'DELETE_LIST': {
      let {boardId, listId} = action.payload
      let newState = _.cloneDeep(state)
      const lists = _.find(newState.boards, (board) => board.boardId === boardId).lists
      let index = _.findIndex(lists, (list) => list.listId === listId)
      lists.splice(index,1)
      return newState
      break

    }
    case 'SELECT_BOARD': {
      return {...state, selectedBoard: action.payload.boardId, boardsPanelOpen:false}
    }
    case 'CREATE_BOARD': {
      let {boardTitle} = action.payload
      let newState = _.cloneDeep(state)
      const boardId = _.random(1000)
      newState.boards.push({boardId:boardId , boardIndex:newState.boards.length+1, boardTitle, lists:[]})
      newState.selectedBoard = boardId
      newState.boardsPanelOpen = false
      return newState
    }
    case 'DELETE_BOARD': {
      let {boardId} = action.payload
      let newState = _.cloneDeep(state)
      let index = _.findIndex(newState.boards, (board) => board.boardId === boardId)
      newState.boards.splice(index,1)
      return newState
    }
    case 'SWAP_LISTS': {
      let {boardId, dragListId, hoverListId} = action.payload
      let newState = _.cloneDeep(state)
      let board = _.find(newState.boards, (o) => o.boardId === boardId)
      let dragList = _.find(board.lists, (o) => o.listId === dragListId)
      let hoverList = _.find(board.lists, (o) => o.listId === hoverListId)
      let dragIndex = dragList.listIndex
      let hoverIndex = hoverList.listIndex
      dragList.listIndex = hoverIndex
      hoverList.listIndex = dragIndex
      return newState
    }
    case 'SWAP_ITEMS': {
      let {boardId, dragListId, dragItemId, hoverItemId} = action.payload
      let newState = _.cloneDeep(state)
      let board = _.find(newState.boards, (o) => o.boardId === boardId)
      let dragList = _.find(board.lists, (o) => o.listId === dragListId)
      let dragItem = _.find(dragList.items, (o) => o.itemId === dragItemId)
      let hoverItem = _.find(dragList.items, (o) => o.itemId === hoverItemId)
      let dragIndex = dragItem.itemIndex
      let hoverIndex = hoverItem.itemIndex
      dragItem.itemIndex = hoverIndex
      hoverItem.itemIndex = dragIndex
      return newState
    }

    case 'MOVE_ITEM_TO_LIST': {
      let {boardId, dragListId, hoverListId, dragItemId} = action.payload
      let newState = _.cloneDeep(state)
      let board = _.find(newState.boards, (o) => o.boardId === boardId)
      let dragList = _.find(board.lists, (o) => o.listId === dragListId)
      let hoverList = _.find(board.lists, (o) => o.listId === hoverListId)
      let dragItem = _.find(dragList.items, (o) => o.itemId === dragItemId)
      dragItem.itemIndex = hoverList.items.length+1
      hoverList.items.push(dragItem)
      dragList.items = dragList.items.filter((o) => o.itemId !== dragItemId)

      return newState
    }

		default:
			return state;
	}
}
<|endoftext|>


<commit_before>(function() {

  var SyncedGetPutDelete = {
    get: function(path) {
      if(this.caching.cachePath(path)) {
        return this.local.get(path);
      } else {
        return this.remote.get(path);
      }
    },

    put: function(path, body, contentType) {
      if(this.caching.cachePath(path)) {
        return this.local.put(path, body, contentType);
      } else {
        return this.remote.put(path, body, contentType);
      }
    },

    'delete': function(path) {
      if(this.caching.cachePath(path)) {
        return this.local.delete(path);
      } else {
        return this.remote.delete(path);
      }
    }
  }

  /**
   * Class: RemoteStorage
   *
   * Constructor for global <remoteStorage> object.
   *
   * This class primarily contains feature detection code and a global convenience API.
   *
   * Depending on which features are built in, it contains different attributes and
   * functions. See the individual features for more information.
   *
   */
  var RemoteStorage = function() {
    RemoteStorage.eventHandling(
      this, 'ready', 'disconnected', 'disconnect', 'conflict', 'error',
      'features-loaded', 'connecting', 'authing', 'sync-busy', 'sync-done'
    );
    // pending get/put/delete calls.
    this._pending = [];
    this._setGPD({
      get: this._pendingGPD('get'),
      put: this._pendingGPD('put'),
      delete: this._pendingGPD('delete')
    });
    this._cleanups = [];
    this._pathHandlers = {};

    this.__defineGetter__('connected', function() {
      return this.remote.connected;
    });

    this._init();
  };

  RemoteStorage.prototype = {

    /**
     ** PUBLIC INTERFACE
     **/

    /**
     * Method: connect
     *
     * Connect to a remotestorage server.
     *
     * Parameters:
     *   userAddress - The user address (user@host) to connect to.
     *
     * Discovers the webfinger profile of the given user address and
     * initiates the OAuth dance.
     *
     * This method must be called *after* all required access has been claimed.
     *
     */
    connect: function(userAddress) {
      this._emit('connecting');
      RemoteStorage.Discover(userAddress,function(href, storageApi, authURL){
        this._emit('authing');
        this.remote.configure(href, storageApi);
        this.authorize(authURL);
      }.bind(this));
    },

    /**
     * Method: disconnect
     *
     * "Disconnect" from remotestorage server to terminate current session.
     * This method clears all stored settings and deletes the entire local cache.
     *
     * Once the disconnect is complete, the "disconnected" event will be fired.
     * From that point on you can connect again (using <connect>).
     */
    disconnect: function() {
      var n = this._cleanups.length, i = 0;
      var oneDone = function() {
        i++;
        if(i == n) {
          this._init();
          this._emit('disconnected');
          this._emit('disconnect');// DEPRECATED?
        }
      }.bind(this);
      this._cleanups.forEach(function(cleanup) {
        var cleanupResult = cleanup(this);
        if(typeof(cleanup) == 'object' && typeof(cleanup.then) == 'function') {
          cleanupResult.then(oneDone);
        } else {
          oneDone();
        }
      }.bind(this));
    },

    /**
     * Method: onChange
     *
     * Adds a 'change' event handler to the given path.
     * Whenever a 'change' happens (as determined by the backend, such
     * as <RemoteStorage.IndexedDB>) and the affected path is equal to
     * or below the given 'path', the given handler is called.
     *
     * Parameters:
     *   path    - Absolute path to attach handler to.
     *   handler - Handler function.
     */
    onChange: function(path, handler) {
      if(! this._pathHandlers[path]) {
        this._pathHandlers[path] = [];
      }
      this._pathHandlers[path].push(handler);
    },

    /**
     ** INITIALIZATION
     **/

    _init: function() {
      this._loadFeatures(function(features) {
        console.log('all features loaded');
        this.local = features.local && new features.local();
        this.remote = new features.remote();

        if(this.local && this.remote) {
          this._setGPD(SyncedGetPutDelete, this);
          this._bindChange(this.local);
        } else if(this.remote) {
          this._setGPD(this.remote, this.remote);
        }

        if(this.remote) {
          this.remote.on('connected', function() {
            this._emit('ready');
          }.bind(this));
        }

        var fl = features.length;
        for(var i=0;i<fl;i++) {
          var cleanup = features[i].cleanup;
          if(cleanup) {
            this._cleanups.push(cleanup);
          }
        }

        try {
          this._emit('features-loaded');
          this._processPending();
        } catch(exc) {
          console.error("remoteStorage#ready block failed: ");
          if(typeof(exc) == 'string') {
            console.error(exc);
          } else {
            console.error(exc.message, exc.stack);
          }
        }
      });
    },

    /**
     ** FEATURE DETECTION
     **/

    _detectFeatures: function() {
      // determine availability
      var features = [
        'WireClient',
        'Access',
        'Caching',
        'Discover',
        'Authorize',
        'IndexedDB',
        'LocalStorage',
        'Sync',
        'BaseClient',
	      'Widget'
      ].map(function(featureName) {
        var impl = RemoteStorage[featureName];
        return {
          name: featureName,
          init: (impl && impl._rs_init),
          supported: impl && (impl._rs_supported ? impl._rs_supported() : true),
          cleanup: ( impl && impl._rs_cleanup )
        };
      }).filter(function(feature) {
        var supported = !! (feature.init && feature.supported);
        console.log("[FEATURE " + feature.name + "] " + (supported ? '' : 'not ') + 'supported.');
        return supported;
      });

      features.local = RemoteStorage.IndexedDB || RemoteStorage.LocalStorage;
      features.remote = RemoteStorage.WireClient;
      features.caching = !!RemoteStorage.Caching;
      features.sync = !!RemoteStorage.Sync;

      this.features = features;

      return features;
    },

    _loadFeatures: function(callback) {
      var features = this._detectFeatures();
      var n = features.length, i = 0;
      var self = this;
      function featureDoneCb(name) {
        return function() {
          i++;
          console.log("[FEATURE " + name + "] initialized. (" + i + "/" + n + ")");
          if(i == n)
            setTimeout(function() {
              callback.apply(self, [features]);
            }, 0);
        }
      }
      features.forEach(function(feature) {
        console.log("[FEATURE " + feature.name + "] initializing...");
        var initResult = feature.init(self);
        var cb = featureDoneCb(feature.name);
        if(typeof(initResult) == 'object' && typeof(initResult.then) == 'function') {
          initResult.then(cb);
        } else {
          cb();
        }
      });
    },

    /**
     ** GET/PUT/DELETE INTERFACE HELPERS
     **/

    _setGPD: function(impl, context) {
      this.get = impl.get.bind(context);
      this.put = impl.put.bind(context);
      this.delete = impl.delete.bind(context);
    },

    _pendingGPD: function(methodName) {
      return function() {
        var promise = promising();
        this._pending.push({
          method: methodName,
          args: Array.prototype.slice.call(arguments),
          promise: promise
        });
        return promise;
      }.bind(this);
    },

    _processPending: function() {
      this._pending.forEach(function(pending) {
        this[pending.method].apply(this, pending.args).then(pending.promise.fulfill, pending.promise.reject);
      }.bind(this));
    },

    _notReady: function() {
      throw "remotestorage not ready!";
    },

    /**
     ** CHANGE EVENT HANDLING
     **/

    _bindChange: function(object) {
      object.on('change', this._dispatchChange.bind(this));
    },

    _dispatchChange: function(event) {
      for(var path in this._pathHandlers) {
        var pl = path.length;
        this._pathHandlers[path].forEach(function(handler) {
          if(event.path.substr(0, pl) == path) {
            var ev = {};
            for(var key in event) { ev[key] = event[key]; }
            ev.relativePath = event.path.replace(new RegExp('^' + path), '');
            handler(ev);
          }
        });
      }
    }
  };

  window.RemoteStorage = RemoteStorage;

})();
<commit_msg>also emit 'sync-busy' / 'sync-done' when pushing changes directly<commit_after>(function() {

  var SyncedGetPutDelete = {
    get: function(path) {
      if(this.caching.cachePath(path)) {
        return this.local.get(path);
      } else {
        return this.remote.get(path);
      }
    },

    put: function(path, body, contentType) {
      if(this.caching.cachePath(path)) {
        return this.local.put(path, body, contentType);
      } else {
        return this._wrapBusyDone(this.remote.put(path, body, contentType));
      }
    },

    'delete': function(path) {
      if(this.caching.cachePath(path)) {
        return this.local.delete(path);
      } else {
        return this._wrapBusyDone(this.remote.delete(path));
      }
    },

    _wrapBusyDone: function(result) {
      this._emit('sync-busy');
      return result.then(function() {
        var promise = promising();
        this._emit('sync-done');
        return promise.fulfill.apply(promise, arguments);
      }, function(err) {
        throw err;
      });
    }
  }

  /**
   * Class: RemoteStorage
   *
   * Constructor for global <remoteStorage> object.
   *
   * This class primarily contains feature detection code and a global convenience API.
   *
   * Depending on which features are built in, it contains different attributes and
   * functions. See the individual features for more information.
   *
   */
  var RemoteStorage = function() {
    RemoteStorage.eventHandling(
      this, 'ready', 'disconnected', 'disconnect', 'conflict', 'error',
      'features-loaded', 'connecting', 'authing', 'sync-busy', 'sync-done'
    );
    // pending get/put/delete calls.
    this._pending = [];
    this._setGPD({
      get: this._pendingGPD('get'),
      put: this._pendingGPD('put'),
      delete: this._pendingGPD('delete')
    });
    this._cleanups = [];
    this._pathHandlers = {};

    this.__defineGetter__('connected', function() {
      return this.remote.connected;
    });

    this._init();
  };

  RemoteStorage.prototype = {

    /**
     ** PUBLIC INTERFACE
     **/

    /**
     * Method: connect
     *
     * Connect to a remotestorage server.
     *
     * Parameters:
     *   userAddress - The user address (user@host) to connect to.
     *
     * Discovers the webfinger profile of the given user address and
     * initiates the OAuth dance.
     *
     * This method must be called *after* all required access has been claimed.
     *
     */
    connect: function(userAddress) {
      this._emit('connecting');
      RemoteStorage.Discover(userAddress,function(href, storageApi, authURL){
        this._emit('authing');
        this.remote.configure(href, storageApi);
        this.authorize(authURL);
      }.bind(this));
    },

    /**
     * Method: disconnect
     *
     * "Disconnect" from remotestorage server to terminate current session.
     * This method clears all stored settings and deletes the entire local cache.
     *
     * Once the disconnect is complete, the "disconnected" event will be fired.
     * From that point on you can connect again (using <connect>).
     */
    disconnect: function() {
      var n = this._cleanups.length, i = 0;
      var oneDone = function() {
        i++;
        if(i == n) {
          this._init();
          this._emit('disconnected');
          this._emit('disconnect');// DEPRECATED?
        }
      }.bind(this);
      this._cleanups.forEach(function(cleanup) {
        var cleanupResult = cleanup(this);
        if(typeof(cleanup) == 'object' && typeof(cleanup.then) == 'function') {
          cleanupResult.then(oneDone);
        } else {
          oneDone();
        }
      }.bind(this));
    },

    /**
     * Method: onChange
     *
     * Adds a 'change' event handler to the given path.
     * Whenever a 'change' happens (as determined by the backend, such
     * as <RemoteStorage.IndexedDB>) and the affected path is equal to
     * or below the given 'path', the given handler is called.
     *
     * Parameters:
     *   path    - Absolute path to attach handler to.
     *   handler - Handler function.
     */
    onChange: function(path, handler) {
      if(! this._pathHandlers[path]) {
        this._pathHandlers[path] = [];
      }
      this._pathHandlers[path].push(handler);
    },

    /**
     ** INITIALIZATION
     **/

    _init: function() {
      this._loadFeatures(function(features) {
        console.log('all features loaded');
        this.local = features.local && new features.local();
        this.remote = new features.remote();

        if(this.local && this.remote) {
          this._setGPD(SyncedGetPutDelete, this);
          this._bindChange(this.local);
        } else if(this.remote) {
          this._setGPD(this.remote, this.remote);
        }

        if(this.remote) {
          this.remote.on('connected', function() {
            this._emit('ready');
          }.bind(this));
        }

        var fl = features.length;
        for(var i=0;i<fl;i++) {
          var cleanup = features[i].cleanup;
          if(cleanup) {
            this._cleanups.push(cleanup);
          }
        }

        try {
          this._emit('features-loaded');
          this._processPending();
        } catch(exc) {
          console.error("remoteStorage#ready block failed: ");
          if(typeof(exc) == 'string') {
            console.error(exc);
          } else {
            console.error(exc.message, exc.stack);
          }
        }
      });
    },

    /**
     ** FEATURE DETECTION
     **/

    _detectFeatures: function() {
      // determine availability
      var features = [
        'WireClient',
        'Access',
        'Caching',
        'Discover',
        'Authorize',
        'IndexedDB',
        'LocalStorage',
        'Sync',
        'BaseClient',
	      'Widget'
      ].map(function(featureName) {
        var impl = RemoteStorage[featureName];
        return {
          name: featureName,
          init: (impl && impl._rs_init),
          supported: impl && (impl._rs_supported ? impl._rs_supported() : true),
          cleanup: ( impl && impl._rs_cleanup )
        };
      }).filter(function(feature) {
        var supported = !! (feature.init && feature.supported);
        console.log("[FEATURE " + feature.name + "] " + (supported ? '' : 'not ') + 'supported.');
        return supported;
      });

      features.local = RemoteStorage.IndexedDB || RemoteStorage.LocalStorage;
      features.remote = RemoteStorage.WireClient;
      features.caching = !!RemoteStorage.Caching;
      features.sync = !!RemoteStorage.Sync;

      this.features = features;

      return features;
    },

    _loadFeatures: function(callback) {
      var features = this._detectFeatures();
      var n = features.length, i = 0;
      var self = this;
      function featureDoneCb(name) {
        return function() {
          i++;
          console.log("[FEATURE " + name + "] initialized. (" + i + "/" + n + ")");
          if(i == n)
            setTimeout(function() {
              callback.apply(self, [features]);
            }, 0);
        }
      }
      features.forEach(function(feature) {
        console.log("[FEATURE " + feature.name + "] initializing...");
        var initResult = feature.init(self);
        var cb = featureDoneCb(feature.name);
        if(typeof(initResult) == 'object' && typeof(initResult.then) == 'function') {
          initResult.then(cb);
        } else {
          cb();
        }
      });
    },

    /**
     ** GET/PUT/DELETE INTERFACE HELPERS
     **/

    _setGPD: function(impl, context) {
      this.get = impl.get.bind(context);
      this.put = impl.put.bind(context);
      this.delete = impl.delete.bind(context);
    },

    _pendingGPD: function(methodName) {
      return function() {
        var promise = promising();
        this._pending.push({
          method: methodName,
          args: Array.prototype.slice.call(arguments),
          promise: promise
        });
        return promise;
      }.bind(this);
    },

    _processPending: function() {
      this._pending.forEach(function(pending) {
        this[pending.method].apply(this, pending.args).then(pending.promise.fulfill, pending.promise.reject);
      }.bind(this));
    },

    _notReady: function() {
      throw "remotestorage not ready!";
    },

    /**
     ** CHANGE EVENT HANDLING
     **/

    _bindChange: function(object) {
      object.on('change', this._dispatchChange.bind(this));
    },

    _dispatchChange: function(event) {
      for(var path in this._pathHandlers) {
        var pl = path.length;
        this._pathHandlers[path].forEach(function(handler) {
          if(event.path.substr(0, pl) == path) {
            var ev = {};
            for(var key in event) { ev[key] = event[key]; }
            ev.relativePath = event.path.replace(new RegExp('^' + path), '');
            handler(ev);
          }
        });
      }
    }
  };

  window.RemoteStorage = RemoteStorage;

})();
<|endoftext|>