<commit_before>const fs = require('fs');
const url = require('url');
const path = require('path');
const http = require('http');
const https = require('https');
const os = require('os');
const net = require('net');
const cwd = process.cwd();

const fport = (p = 0) =>
  new Promise((resolve, reject) => {
    const s = net.createServer();
    s.on('error', reject);
    s.listen(p, () => {
      const { port } = s.address();
      s.close(() => resolve(port));
    });
  });

const ips = Object.values(os.networkInterfaces())
  .reduce((every, i) => [...every, ...i], [])
  .filter(i => i.family === 'IPv4' && i.internal === false)
  .map(i => i.address);

const mimes = Object.entries(require('./types.json')).reduce(
  (all, [type, exts]) =>
    Object.assign(all, ...exts.map(ext => ({ [ext]: type }))),
  {}
);

const livereload = `
  <script>
    const source = new EventSource('/livereload');
    source.onmessage = e => location.reload(true);
    console.log('[servor] listening for file changes');
  </script>
`;

module.exports = async ({
  root = '.',
  fallback = 'index.html',
  port,
  reload = true,
  inject,
  credentials
} = {}) => {
  try {
    port = await fport(port || 8080);
  } catch {
    if (port) {
      console.log('[ERR] The port you have specified is already in use!');
      process.exit();
    }
    port = await fport();
  }
  root = root.startsWith('/') ? root : path.join(cwd, root);
  const clients = [];
  const protocol = credentials ? 'https' : 'http';
  const server = credentials
    ? cb => https.createServer(credentials, cb)
    : cb => http.createServer(cb);

  // Server utility functions

  const sendError = (res, resource, status) => {
    res.writeHead(status);
    res.end();
  };

  const sendFile = (res, resource, status, file, ext) => {
    res.writeHead(status, {
      'Content-Type': mimes[ext] || 'application/octet-stream',
      'Access-Control-Allow-Origin': '*'
    });
    res.write(file, 'binary');
    res.end();
  };

  const sendMessage = (res, channel, data) => {
    res.write(`event: ${channel}\nid: 0\ndata: ${data}\n`);
    res.write('\n\n');
  };

  const isRouteRequest = pathname =>
    !~pathname
      .split('/')
      .pop()
      .indexOf('.');

  // Start the server on the desired port

  server((req, res) => {
    const pathname = url.parse(req.url).pathname;
    if (reload && pathname === '/livereload') {
      res.writeHead(200, {
        Connection: 'keep-alive',
        'Content-Type': 'text/event-stream',
        'Cache-Control': 'no-cache',
        'Access-Control-Allow-Origin': '*'
      });
      sendMessage(res, 'connected', 'ready');
      setInterval(sendMessage, 60000, res, 'ping', 'waiting');
      clients.push(res);
    } else {
      const isRoute = isRouteRequest(pathname);
      const status = isRoute && pathname !== '/' ? 301 : 200;
      const resource = isRoute ? `/${fallback}` : decodeURI(pathname);
      const uri = path.join(root, resource);
      const ext = uri.replace(/^.*[\.\/\\]/, '').toLowerCase();
      fs.stat(uri, (err, stat) => {
        if (err) return sendError(res, resource, 404);
        fs.readFile(uri, 'binary', (err, file) => {
          if (err) return sendError(res, resource, 500);
          if (isRoute && inject) file = inject + file;
          if (isRoute && reload) file = livereload + file;
          sendFile(res, resource, status, file, ext);
        });
      });
    }
  }).listen(parseInt(port, 10));

  // Notify livereload clients on file change

  reload &&
    fs.watch(root, { recursive: true }, () => {
      while (clients.length > 0)
        sendMessage(clients.pop(), 'message', 'reload');
    });

  return {
    url: `${protocol}://localhost:${port}`,
    root,
    protocol,
    port,
    ips
  };
};
<commit_msg>Include support for process.env.PORT<commit_after>const fs = require('fs');
const url = require('url');
const path = require('path');
const http = require('http');
const https = require('https');
const os = require('os');
const net = require('net');
const cwd = process.cwd();

const fport = (p = 0) =>
  new Promise((resolve, reject) => {
    const s = net.createServer();
    s.on('error', reject);
    s.listen(p, () => {
      const { port } = s.address();
      s.close(() => resolve(port));
    });
  });

const ips = Object.values(os.networkInterfaces())
  .reduce((every, i) => [...every, ...i], [])
  .filter(i => i.family === 'IPv4' && i.internal === false)
  .map(i => i.address);

const mimes = Object.entries(require('./types.json')).reduce(
  (all, [type, exts]) =>
    Object.assign(all, ...exts.map(ext => ({ [ext]: type }))),
  {}
);

const livereload = `
  <script>
    const source = new EventSource('/livereload');
    source.onmessage = e => location.reload(true);
    console.log('[servor] listening for file changes');
  </script>
`;

module.exports = async ({
  root = '.',
  fallback = 'index.html',
  port,
  reload = true,
  inject,
  credentials
} = {}) => {
  try {
    port = await fport(port || process.env.PORT || 8080);
  } catch {
    if (port || process.env.PORT) {
      console.log('[ERR] The port you have specified is already in use!');
      process.exit();
    }
    port = await fport();
  }
  root = root.startsWith('/') ? root : path.join(cwd, root);
  const clients = [];
  const protocol = credentials ? 'https' : 'http';
  const server = credentials
    ? cb => https.createServer(credentials, cb)
    : cb => http.createServer(cb);

  // Server utility functions

  const sendError = (res, resource, status) => {
    res.writeHead(status);
    res.end();
  };

  const sendFile = (res, resource, status, file, ext) => {
    res.writeHead(status, {
      'Content-Type': mimes[ext] || 'application/octet-stream',
      'Access-Control-Allow-Origin': '*'
    });
    res.write(file, 'binary');
    res.end();
  };

  const sendMessage = (res, channel, data) => {
    res.write(`event: ${channel}\nid: 0\ndata: ${data}\n`);
    res.write('\n\n');
  };

  const isRouteRequest = pathname =>
    !~pathname
      .split('/')
      .pop()
      .indexOf('.');

  // Start the server on the desired port

  server((req, res) => {
    const pathname = url.parse(req.url).pathname;
    if (reload && pathname === '/livereload') {
      res.writeHead(200, {
        Connection: 'keep-alive',
        'Content-Type': 'text/event-stream',
        'Cache-Control': 'no-cache',
        'Access-Control-Allow-Origin': '*'
      });
      sendMessage(res, 'connected', 'ready');
      setInterval(sendMessage, 60000, res, 'ping', 'waiting');
      clients.push(res);
    } else {
      const isRoute = isRouteRequest(pathname);
      const status = isRoute && pathname !== '/' ? 301 : 200;
      const resource = isRoute ? `/${fallback}` : decodeURI(pathname);
      const uri = path.join(root, resource);
      const ext = uri.replace(/^.*[\.\/\\]/, '').toLowerCase();
      fs.stat(uri, (err, stat) => {
        if (err) return sendError(res, resource, 404);
        fs.readFile(uri, 'binary', (err, file) => {
          if (err) return sendError(res, resource, 500);
          if (isRoute && inject) file = inject + file;
          if (isRoute && reload) file = livereload + file;
          sendFile(res, resource, status, file, ext);
        });
      });
    }
  }).listen(parseInt(port, 10));

  // Notify livereload clients on file change

  reload &&
    fs.watch(root, { recursive: true }, () => {
      while (clients.length > 0)
        sendMessage(clients.pop(), 'message', 'reload');
    });

  return {
    url: `${protocol}://localhost:${port}`,
    root,
    protocol,
    port,
    ips
  };
};
<|endoftext|>


<commit_before>'use strict';
var React = require('react/addons');
var cloneWithProps = React.addons.cloneWithProps;

// this should be the entry point to your library
module.exports = React.createClass({
    displayName: 'Ellipsify',

    propTypes: {
        visibleItems: React.PropTypes.number,
        separator: React.PropTypes.string,
        more: React.PropTypes.string,
        moreClass: React.PropTypes.string,
        atFront: React.PropTypes.bool,
    },

    getDefaultProps() {
      return {
        visibleItems: 5,
        separator: ' ',
        more: '…',
        moreClass: 'more',
        atFront: true,
      };
    },

    getInitialState() {
        return {
            visible: false,
        };
    },

    render() {
        var visible = this.state.visible;

        var moreClass = this.props.moreClass;
        var moreContent = this.props.more;

        return (

{visible?
                this.props.children:
                [
                    ellipsify(this.props),
                    {moreContent}
                ]
            }

        );
    },

    onClick() {
        this.setState({
            visible: true,
        });
    },
});

function ellipsify(options) {
    return traverse(options.children, {
        visible: 0,
    });

    function traverse(children, memo) {
        var ret = [];

        React.Children.forEach(children, (child) => {
            var grandChildren = child && child.props && child.props.children;
            var c;

            if(grandChildren) {
                var newChildren = traverse(grandChildren, memo);

                if(newChildren && newChildren.length) {
                    c = cloneWithProps(child);

                    c.props.children = newChildren;

                    ret.push(c);
                }
            }
            else {
                var partsLeft = options.visibleItems - memo.visible;

                if(!partsLeft) {
                    return;
                }

                var parts = child.split(options.separator);
                var len = parts.length;

                // longer section than parts left, go to zero and slice
                if(len > partsLeft) {
                    // slice + combine, memo to max
                    memo.visible = options.visibleItems;

                    var extra = parts[0]? 0: 1;

                    ret.push(parts.slice(0, partsLeft + extra).join(options.separator));
                }
                // excess parts left, add to memo and return whole
                else if(len) {
                    memo.visible += len;

                    ret.push(parts.join(options.separator));
                }
            }
        });

        return ret;
    }
}
<commit_msg>Tidy up<commit_after>'use strict';
var React = require('react/addons');
var cloneWithProps = React.addons.cloneWithProps;

module.exports = React.createClass({
    displayName: 'Ellipsify',

    propTypes: {
        visibleItems: React.PropTypes.number,
        separator: React.PropTypes.string,
        more: React.PropTypes.string,
        moreClass: React.PropTypes.string,
        atFront: React.PropTypes.bool,
    },

    getDefaultProps() {
      return {
        visibleItems: 5,
        separator: ' ',
        more: '…',
        moreClass: 'more',
        atFront: true,
      };
    },

    getInitialState() {
        return {
            visible: false,
        };
    },

    render() {
        var visible = this.state.visible;

        var moreClass = this.props.moreClass;
        var moreContent = this.props.more;

        return (

{visible?
                this.props.children:
                [
                    ellipsify(this.props),
                    {moreContent}
                ]
            }

        );
    },

    onClick() {
        this.setState({
            visible: true,
        });
    },
});

function ellipsify(options) {
    return traverse(options.children, {
        visible: 0,
    });

    function traverse(children, memo) {
        var ret = [];

        React.Children.forEach(children, (child) => {
            var grandChildren = child && child.props && child.props.children;
            var c;

            if(grandChildren) {
                var newChildren = traverse(grandChildren, memo);

                if(newChildren && newChildren.length) {
                    c = cloneWithProps(child);

                    c.props.children = newChildren;

                    ret.push(c);
                }
            }
            else {
                var partsLeft = options.visibleItems - memo.visible;

                if(!partsLeft) {
                    return;
                }

                var parts = child.split(options.separator);
                var len = parts.length;

                // longer section than parts left, go to zero and slice
                if(len > partsLeft) {
                    // slice + combine, memo to max
                    memo.visible = options.visibleItems;

                    var extra = parts[0]? 0: 1;

                    ret.push(parts.slice(0, partsLeft + extra).join(options.separator));
                }
                // excess parts left, add to memo and return whole
                else if(len) {
                    memo.visible += len;

                    ret.push(parts.join(options.separator));
                }
            }
        });

        return ret;
    }
}
<|endoftext|>


<commit_before>import FileMonitor from './FileMonitor';
import {
  BaseFileState,
  CombinedState
} from './states';

export {
  FileMonitor,
  BaseFileState,
  CombinedState
};
<commit_msg>Add export statement for all states<commit_after>import FileMonitor from './FileMonitor';
import {
  BaseFileState,
  ContentHashState,
  LastModifiedState,
  SizeState,
  SmartState,
} from './states';

export {
  FileMonitor,
  BaseFileState,
  ContentHashState,
  LastModifiedState,
  SizeState,
  SmartState
};
<|endoftext|>


<commit_before>var card_catalog = exports;

card_catalog.categorize      = require('./card_catalog/core').categorize;
card_catalog.add_cards       = require('./card_catalog/core').add_cards;
card_catalog.card            = require('./card_catalog/core').card;<commit_msg>expose raw objects<commit_after>var card_catalog = exports;

// Expose raw `classes`
card_catalog.category        = require('./card_catalog/category');
card_catalog.cards           = require('./card_catalog/cards');

// Expose helper methods
card_catalog.categorize      = require('./card_catalog/core').categorize;
card_catalog.add_cards       = require('./card_catalog/core').add_cards;
card_catalog.card            = require('./card_catalog/core').card;<|endoftext|>


<commit_before>'use strict';

var urlUtil = require('url');
var Item = require('./Item');

function unique(array) {
  return array.reduce(function (uniques, item) {
    if (uniques.indexOf(item) < 0) {
      uniques.push(item);
    }
    return uniques;
  }, []);
}

function splitUnique(string) {
  string = string && string.trim();
  if (string) {
    return unique(string.split(/\s+/));
  } else {
    return undefined;
  }
}

function parse($, config) {

  config = config || {};
  var items = [];

  function walkNode(node, currentItem) {
    var prop = splitUnique(node.attr('itemprop'));

    if (prop && currentItem) {
      prop.forEach(function (propName) {
        var value = parseProperty(node);
        currentItem.addProperty(propName, value);
      });
    } else if (node.is('[itemscope]')) {
      var newItem = parseItem(node);
      items.push(newItem);
    } else {
      node.children().each(function (i, child) {
        walkNode($(child), currentItem);
      });
    }
  }

  function parseItem(node) {
    var item = new Item({
      type: splitUnique(node.attr('itemtype')),
      id: node.attr('itemid')
    });

    node.children().each(function (i, child) {
      walkNode($(child), item);
    });

    return item;
  }

  function resolveAttribute(node, attr) {
    return node.attr(attr) || '';
  }

  function resolveUrlAttribute(node, attr) {
    var relative = node.attr(attr);
    if (relative && config.base) {
      return urlUtil.resolve(config.base, relative) || '';
    } else {
      return relative || '';
    }
  }

  function parseProperty(node) {
    if (node.is('[itemscope]')) {
      return parseItem(node);
    } else if (node.is('meta')) {
      return resolveAttribute(node, 'content');
    } else if (node.is('audio,embed,iframe,img,source,track,video')) {
      return resolveUrlAttribute(node, 'src');
    } else if (node.is('a,area,link')) {
      return resolveUrlAttribute(node, 'href');
    } else if (node.is('object')) {
      return resolveUrlAttribute(node, 'data');
    } else if (node.is('data')) {
      return resolveAttribute(node, 'value');
    } else if (node.is('meter')) {
      return resolveAttribute(node, 'value');
    } else if (node.is('time')) {
      return resolveAttribute(node, 'datetime');
    } else {
      return node.text() || '';
    }
  }

  walkNode($.root());

  return {
    items: items.map(function (item) {
      return item.serialize();
    })
  };
}

exports.parse = parse;
<commit_msg>Make clear node is a cheerio object<commit_after>'use strict';

var urlUtil = require('url');
var Item = require('./Item');

function unique(array) {
  return array.reduce(function (uniques, item) {
    if (uniques.indexOf(item) < 0) {
      uniques.push(item);
    }
    return uniques;
  }, []);
}

function splitUnique(string) {
  string = string && string.trim();
  if (string) {
    return unique(string.split(/\s+/));
  } else {
    return undefined;
  }
}

function parse($, config) {

  config = config || {};
  var items = [];

  function walkNode($node, currentItem) {
    var prop = splitUnique($node.attr('itemprop'));

    if (prop && currentItem) {
      prop.forEach(function (propName) {
        var value = parseProperty($node);
        currentItem.addProperty(propName, value);
      });
    } else if ($node.is('[itemscope]')) {
      var newItem = parseItem($node);
      items.push(newItem);
    } else {
      $node.children().each(function (i, child) {
        walkNode($(child), currentItem);
      });
    }
  }

  function parseItem($node) {
    var item = new Item({
      type: splitUnique($node.attr('itemtype')),
      id: $node.attr('itemid')
    });

    $node.children().each(function (i, child) {
      walkNode($(child), item);
    });

    return item;
  }

  function resolveAttribute($node, attr) {
    return $node.attr(attr) || '';
  }

  function resolveUrlAttribute($node, attr) {
    var relative = $node.attr(attr);
    if (relative && config.base) {
      return urlUtil.resolve(config.base, relative) || '';
    } else {
      return relative || '';
    }
  }

  function parseProperty($node) {
    if ($node.is('[itemscope]')) {
      return parseItem($node);
    } else if ($node.is('meta')) {
      return resolveAttribute($node, 'content');
    } else if ($node.is('audio,embed,iframe,img,source,track,video')) {
      return resolveUrlAttribute($node, 'src');
    } else if ($node.is('a,area,link')) {
      return resolveUrlAttribute($node, 'href');
    } else if ($node.is('object')) {
      return resolveUrlAttribute($node, 'data');
    } else if ($node.is('data')) {
      return resolveAttribute($node, 'value');
    } else if ($node.is('meter')) {
      return resolveAttribute($node, 'value');
    } else if ($node.is('time')) {
      return resolveAttribute($node, 'datetime');
    } else {
      return $node.text() || '';
    }
  }

  walkNode($.root());

  return {
    items: items.map(function (item) {
      return item.serialize();
    })
  };
}

exports.parse = parse;
<|endoftext|>


<commit_before>var Ul = require("ul");
var Typpy = require("typpy");
var Deffy = require("deffy");

const TYPES = {
    event: "event",
    dataHandler: "dataHandler",
    streamHandler: "streamHandler",
    load: "load"
};

function Enny() {
    var self = this;
    self.instances = {};
    self.Instance = function (data) {
        return new Enny.Instance(data, {
            enny: self
        });
    };
    self.FlowComponent = function (data) {
        return new Enny.FlowComponent(data, {
            enny: self
        });
    };
}

Enny.prototype.toJSON = function (a, b, c) {
    var self = this;
    var obj = {};
    Object.keys(self.instances).forEach(function (name) {
        obj[name] = self.instances[name]._;
    });
    return obj;
};

Enny.prototype.addInstance = function (ins) {
    ins = this.Instance(ins);
    this.instances[ins._.name] = ins;
    return ins;
};

Enny.Instance = function Instance (data, options) {
    if (Typpy(data) === "instance") {
        return data;
    }
    this._ = Ul.clone(data);
    this.enny = options.enny;
};

Enny.Instance.prototype.connect = function (ins, options, callback) {

    var self = this;
    if (typeof options === "boolean") {
        options = {
            client: options
        };
    } else if (options === "function") {
        callback = options;
        options = {};
    }

    callback = callback || function (err) {
        if (err) { console.error(err); }
    };
    options = Ul.merge(options, {
        client: true
    });
    ins = Enny.Instance(ins, options);

    if (!ins._.name) {
        return callback(new Error("The target instance name is required."));
    }

    if (!self._.name) {
        return callback(new Error("The source instance name is required."));
    }

    var load = null;
    if (options.client) {
        self._.client = Deffy(self._.client, {});
        load = self._.client.load = Deffy(self._.client.load, []);
    } else {
        load = self._.load = Deffy(self._.load, []);
    }
    load.push(ins._.name);
    if (options.save) {
        self.enny.save(callback);
        return self;
    }
    callback();
    return self;
};

Enny.Instance.prototype.addFlow = function (flElm, options, callback) {

    var self = this;
    if (typeof options === "boolean") {
        options = {
            client: options
        };
    } else if (options === "function") {
        callback = options;
        options = {};
    }

    callback = callback || function (err) {
        if (err) { console.error(err); }
    };

    options = Ul.merge(options, {
        client: true
    });

    var flow = null;
    if (options.client) {
        self._.client = Deffy(self._.client, {});
        flow = self._.client.flow = Deffy(self._.client.flow, []);
    } else {
        flow = self._.flow = Deffy(self._.flow, []);
    }

    flow.push(flElm);

    if (options.save) {
        self.enny.save(callback);
        return self;
    }

    callback();
};

Enny.FlowElement = function (data) {
    var self = this;
    this._ = [];
    if (Typpy(data) === "array") {
        data.forEach(self.addComponent.bind(self));
    }
};

Enny.FlowElement.prototype.addComponent = function (data) {
    data = new Enny.FlowCompoent(data);
    this._.push(data.toFlow());
};

Enny.Handler = function Handler(data) {
    if (Typpy(data) === "handler") {
        return data;
    }
    this.to = data.to;
    this.args = Deffy(data.args, []);
    this.isStream = Deffy(data.isStream, true);
    this.handler = data.handler;
};

Enny.Handler.prototype.toFlow = function () {
    var res = [];
    res[0] = (this.isStream ? "" : ":") + (this.to ? this.to + "/" : "") + this.handler;
    res.concat(this.args);
    return res;
};

Enny.FlowComponent = function FlowComponent (data, options) {
    var self = this;
    if (Typpy(data) === "flowcomponent") {
        return data;
    }
    self.enny = options.enny;
    self.data = Ul.clone(data);
};

Enny.FlowComponent.prototype.toFlow = function () {
    var data = this.data;
    var res = null;
    switch (data.type) {
        case TYPES.event:
            if (data.once) {
                return [data.event];
            }
            return data.event;
        case TYPES.dataHandler:
        case TYPES.streamHandler:
            return new Enny.Handler({
                to: data.to,
                isStream: data.type === TYPES.streamHandler,
                args: data.args,
                handler: data.handler
            }).toFlow();
        case TYPES.load:
            return new Enny.Handler({
                args: [[data.instance]],
                handler: TYPES.load
            }).toFlow();
    }
};

module.exports = Enny;
<commit_msg>Little fixes<commit_after>var Ul = require("ul");
var Typpy = require("typpy");
var Deffy = require("deffy");

const TYPES = {
    event: "event",
    dataHandler: "dataHandler",
    streamHandler: "streamHandler",
    load: "load"
};

function Enny() {
    var self = this;
    self.instances = {};
    self.Instance = function (data) {
        return new Enny.Instance(data, {
            enny: self
        });
    };
    self.FlowComponent = function (data) {
        return new Enny.FlowComponent(data, {
            enny: self
        });
    };
}

Enny.prototype.toJSON = function (a, b, c) {
    var self = this;
    var obj = {};
    Object.keys(self.instances).forEach(function (name) {
        obj[name] = Ul.clone(self.instances[name]._);
    });
    return obj;
};

Enny.prototype.addInstance = function (ins) {
    ins = this.Instance(ins);
    this.instances[ins._.name] = ins;
    return ins;
};

Enny.Instance = function Instance (data, options) {
    if (Typpy(data) === "instance") {
        return data;
    }
    this._ = Ul.clone(data);
    this.enny = options.enny;
};

Enny.Instance.prototype.connect = function (ins, options, callback) {

    var self = this;
    if (typeof options === "boolean") {
        options = {
            client: options
        };
    } else if (options === "function") {
        callback = options;
        options = {};
    }

    callback = callback || function (err) {
        if (err) { console.error(err); }
    };
    options = Ul.merge(options, {
        client: true
    });
    ins = Enny.Instance(ins, options);

    if (!ins._.name) {
        return callback(new Error("The target instance name is required."));
    }

    if (!self._.name) {
        return callback(new Error("The source instance name is required."));
    }

    var load = null;
    if (options.client) {
        self._.client = Deffy(self._.client, {});
        load = self._.client.load = Deffy(self._.client.load, []);
    } else {
        load = self._.load = Deffy(self._.load, []);
    }
    load.push(ins._.name);
    if (options.save) {
        self.enny.save(callback);
        return self;
    }
    callback();
    return self;
};

Enny.Instance.prototype.addFlow = function (flElm, options, callback) {

    var self = this;
    if (typeof options === "boolean") {
        options = {
            client: options
        };
    } else if (options === "function") {
        callback = options;
        options = {};
    }

    callback = callback || function (err) {
        if (err) { console.error(err); }
    };

    options = Ul.merge(options, {
        client: true
    });

    var flow = null;
    if (options.client) {
        self._.client = Deffy(self._.client, {});
        flow = self._.client.flow = Deffy(self._.client.flow, []);
    } else {
        flow = self._.flow = Deffy(self._.flow, []);
    }

    flElm = new Enny.FlowElement(flElm);

    flow.push(flElm);

    if (options.save) {
        self.enny.save(callback);
        return self;
    }

    callback();
};

Enny.FlowElement = function FlowElement (data) {
    var self = this;
    if (Typpy(data) === "flowelement") {
        return data;
    }
    this._ = [];
    if (Typpy(data) === "array") {
        data.forEach(self.addComponent.bind(self));
    }
    self.Component = function (data) {

    };
};

Enny.FlowElement.prototype.addComponent = function (data) {
    data = new Enny.FlowComponent(data);
    this._.push(data.toFlow());
};

Enny.Handler = function Handler(data) {
    if (Typpy(data) === "handler") {
        return data;
    }
    this.to = data.to;
    this.args = Deffy(data.args, []);
    this.isStream = Deffy(data.isStream, true);
    this.handler = data.handler;
};

Enny.Handler.prototype.toFlow = function () {
    var res = [];
    res[0] = (this.isStream ? "" : ":") + (this.to ? this.to + "/" : "") + this.handler;
    res.concat(this.args);
    return res;
};

Enny.FlowComponent = function FlowComponent (data) {
    var self = this;
    if (Typpy(data) === "flowcomponent") {
        return data;
    }
    if (data.event) {
        data.type = TYPES.event;
    }
    self.data = Ul.clone(data);
};

Enny.FlowComponent.prototype.toFlow = function () {
    var data = this.data;
    var res = null;
    switch (data.type) {
        case TYPES.event:
            if (data.once) {
                return [data.event];
            }
            return data.event;
        case TYPES.dataHandler:
        case TYPES.streamHandler:
            return new Enny.Handler({
                to: data.to,
                isStream: data.type === TYPES.streamHandler,
                args: data.args,
                handler: data.handler
            }).toFlow();
        case TYPES.load:
            return new Enny.Handler({
                args: [[data.instance]],
                handler: TYPES.load
            }).toFlow();
    }
};

module.exports = Enny;
<|endoftext|>


<commit_before>/*jshint globalstrict:true, devel:true */
/*global require, module, exports, process, __dirname, Buffer */
"use strict";

var fs    = require('fs'),
    path  = require('path'),
    zip   = require('node-zip'),
    etree = require('elementtree'),
    _     = require('lodash');

module.exports = (function() {

    var SHARED_STRINGS = "xl/sharedStrings.xml",
        WORKSHEETS     = "xl/worksheets/";

    /**
     * Create a new workbook. Either pass the raw data of a .xlsx file,
     * or call `loadTemplate()` later.
     */
    var Workbook = function(data) {
        var self = this;

        self.archive = null;
        self.sharedStrings = [];
        self.sharedStringsLookup = {};

        if(data) {
            self.loadTemplate(data);
        }
    };

    /**
     * Load a .xlsx file from a byte array.
     */
    Workbook.prototype.loadTemplate = function(data) {
        var self = this;

        if(Buffer.isBuffer(data)) {
            data = data.toString('binary');
        }

        self.archive = new zip(data, {base64: false, checkCRC32: true});
        self.readSharedStrings();
    };

    /**
     * Interpolate values for the sheet with the given number (1-based)
     * using the given substitutions (an object).
     */
    Workbook.prototype.substitute = function(sheet, substitutions) {
        var self = this;

        function getCurrentRow(row, rowsInserted) {
            return parseInt(row.attrib.r, 10) + rowsInserted;
        }

        function getCurrentCell(cell, currentRow, cellsInserted) {
            var ref = self.joinRef({
                row: currentRow,
                col: self.splitRef(cell.attrib.r).col
            });

            // TODO: optimise
            // TODO: deal with negatives?
            for(var i = 0; i < cellsInserted; ++i) {
                ref = self.nextCol(ref);
            }

            return ref;
        }

        var file = WORKSHEETS + "sheet" + sheet + ".xml",
            tree = etree.parse(self.archive.file(file).asText()),
            root = tree.getroot();

        var sheetData = root.find("sheetData"),
            currentRow = null,
            rowsInserted = 0,
            rows = [];

        sheetData.findall("row").forEach(function(row) {
            var appendRow = true;
            row.attrib.r = currentRow = getCurrentRow(row, rowsInserted);

            var cells = [],
                currentCell = null,
                cellsInserted = 0;

            row.findall("c").forEach(function(cell) {
                var appendCell = true;
                cell.attrib.r = currentCell = getCurrentCell(cell, currentRow, cellsInserted);

                // If c[@t="s"] (string cellumn), look up /c/v@text as integer in
                // `this.sharedStrings`
                if(cell.attrib.t === "s") {
                    var cellValue   = cell.find("v"),
                        stringIndex = parseInt(cellValue.text, 10),
                        string      = self.sharedStrings[stringIndex];

                    // Look for a shared string that may contain placeholders
                    if(string !== undefined) {

                        // Loop over placeholders
                        var placeholders = self.extractPlaceholders(string);
                        placeholders.forEach(function(placeholder) {

                            // Only substitute things for which we have a substition
                            var substitution = substitutions[placeholder.name];
                            if(substitution === undefined) {
                                return;
                            }

                            var substituted = self.substituteScalar(cell, string, placeholder, substitution);
                            if(substituted !== undefined) {
                                string = substituted; // in case we have multiple placeholders
                            } else if(placeholder.full && substitution instanceof Array) {

                                // A table substitution (rows)
                                if(placeholder.type === "table") { // multiple rows

                                    // TODO

                                // A list substitution (columns)
                                } else if(placeholder.type === "normal") {
                                    appendCell = false; // don't double-insert cells
                                    --cellsInserted; // we technically delete one before we start adding back

                                    // add a cell for each element in the list
                                    substitution.forEach(function(substitutionElement) {
                                        ++cellsInserted;
                                        if(cellsInserted > 0) {
                                            currentCell = self.nextCol(currentCell);
                                        }

                                        var newCol = self.cloneElement(cell);
                                        self.insertValue(newCol, substitutionElement);

                                        newCol.attrib.r = currentCell;
                                        cells.push(newCol);
                                    });
                                }
                            }
                        });
                    }
                }

                // if we are inserting rows or columns, we may not want to keep the original cell anymore
                if(appendCell) {
                    cells.push(cell);
                }

            });

            if(appendRow) {
                rows.push(row);

                // We may have inserted columns, so re-build the children of the row
                self.replaceChildren(row, cells);

                // Update row spans attribute
                if(cellsInserted !== 0 && row.attrib.spans) {
                    var rowSpan = row.attrib.spans.split(':').map(function(f) { return parseInt(f, 10); });
                    rowSpan[1] += cellsInserted;
                    row.attrib.spans = rowSpan.join(":");
                }
            }

        });

        // We may have inserted rows, so re-build the children of the sheetData
        self.replaceChildren(sheetData, rows);

        // TODO: Update <mergeCells />

        // Write back the modified XML tree
        self.archive.file(file, etree.tostring(root));
    };

    /**
     * Generate a new binary .xlsx file
     */
    Workbook.prototype.generate = function() {
        var self = this;

        self.writeSharedStrings();
        return self.archive.generate({base64:false,compression:'DEFLATE'});
    };

    // Helpers

    // Read the shared strings from the workbook
    Workbook.prototype.readSharedStrings = function() {
        var self = this;

        var tree = etree.parse(self.archive.file(SHARED_STRINGS).asText());
        self.sharedStrings = [];
        tree.findall('si/t').forEach(function(t) {
            self.sharedStrings.push(t.text);
            self.sharedStringsLookup[t.text] = self.sharedStrings.length - 1;
        });
    };

    // Write back the new shared strings list
    Workbook.prototype.writeSharedStrings = function() {
        var self = this;

        var tree = etree.parse(self.archive.file(SHARED_STRINGS).asText()),
            root = tree.getroot(),
            children = root.getchildren();

        root.delSlice(0, children.length);

        self.sharedStrings.forEach(function(string) {
            var si = new etree.Element("si"),
                t  = new etree.Element("t");

            t.text = string;
            si.append(t);
            root.append(si);
        });

        root.attrib.count = self.sharedStrings.length;
        root.attrib.uniqueCount = self.sharedStrings.length;

        self.archive.file(SHARED_STRINGS, etree.tostring(root));
    };

    // Add a new shared string
    Workbook.prototype.addSharedString = function(s) {
        var self = this;

        var idx = self.sharedStrings.length;
        self.sharedStrings.push(s);
        self.sharedStringsLookup[s] = idx;

        return idx;
    };

    // Get the number of a shared string, adding a new one if necessary.
    Workbook.prototype.stringIndex = function(s) {
        var self = this;

        var idx = self.sharedStringsLookup[s];
        if(idx === undefined) {
            idx = self.addSharedString(s);
        }
        return idx;
    };

    // Replace a shared string with a new one at the same index. Return the
    // index.
    Workbook.prototype.replaceString = function(oldString, newString) {
        var self = this;

        var idx = self.sharedStringsLookup[oldString];
        if(idx === undefined) {
            idx = self.addSharedString(newString);
        } else {
            self.sharedStrings[idx] = newString;
            delete self.sharedStringsLookup[oldString];
            self.sharedStringsLookup[newString] = idx;
        }

        return idx;
    };

    // Return a list of tokens that may exist in the string.
    // Keys are: `placeholder` (the full placeholder, including the `${}`
    // delineators), `name` (the name part of the token), `key` (the object key
    // for `table` tokens), `full` (boolean indicating whether this placeholder
    // is the entirety of the string) and `type` (one of `table` or `cell`)
    Workbook.prototype.extractPlaceholders = function(string) {
        // Yes, that's right. It's a bunch of brackets and question marks and stuff.
        var re = /\${(?:(.+?):)?(.+?)(?:\.(.+?))?}/g;

        var match = null, matches = [];
        while((match = re.exec(string)) !== null) {
            matches.push({
                placeholder: match[0],
                type: match[1] || 'normal',
                name: match[2],
                key: match[3],
                full: match[0].length === string.length
            });
        }

        return matches;
    };

    // Split a reference into an object with keys `row` and `col`.
    Workbook.prototype.splitRef = function(ref) {
        var match = ref.match(/([A-Z]+)([0-9]+)/);
        return {
            col: match[1],
            row: parseInt(match[2], 10)
        };
    };

    // Join an object with keys `row` and `col` into a single reference string
    Workbook.prototype.joinRef = function(ref) {
        return ref.col.toUpperCase() + Number(ref.row).toString();
    };

    // Get the next column's cell reference given a reference like "B2".
    Workbook.prototype.nextCol = function(ref) {
        ref = ref.toUpperCase();
        return ref.replace(/[A-Z]+/, function(match) {
            var chars = match.split('');
            for(var i = chars.length - 1; i >= 0; --i) {

                // Increment char code
                var code = chars[i].charCodeAt(0) + 1;
                if(code > 90) { // Z
                    code = 65;  // A
                }
                chars[i] = String.fromCharCode(code);

                // Unless we rolled over to 'A', we don't need to increment
                // the preceding
                if(code != 65) {
                    return chars.join('');
                }
            }

            // If we got here without returning, then we need to add another
            // character
            return 'A' + chars.join('');
        });
    };

    // Get the next row's cell reference given a reference like "B2".
    Workbook.prototype.nextRow = function(ref) {
        ref = ref.toUpperCase();
        return ref.replace(/[0-9]+/, function(match) {
            return (parseInt(match, 10) + 1).toString();
        });
    };

    // Turn a reference like "AA" into a number like 27
    Workbook.prototype.charToNum = function(str) {
        var num = 0;
        for(var idx = str.length - 1, iteration = 0; idx >= 0; --idx, ++iteration) {
            var thisChar = str.charCodeAt(idx) - 64, // A -> 1; B -> 2; ... Z->26
                multiplier = Math.pow(26, iteration);
            num += multiplier * thisChar;
        }
        return num;
    };

    // Turn a number like 27 into a reference like "AA"
    Workbook.prototype.numToChar = function(num) {
        var str = "";

        for(var i = 0; num > 0; ++i) {
            var remainder = num % 26,
                charCode = remainder + 64;
            num = (num - remainder) / 26;

            // Compensate for the fact that we don't represent zero, e.g. A = 1, Z = 26, but AA = 27
            if(remainder === 0) { // 26 -> Z
                charCode = 90;
                --num;
            }

            str = String.fromCharCode(charCode) + str;
        }

        return str;
    };

    Workbook.prototype.stringify = function (value) {
        var self = this;

        if(value instanceof Date) {
            return value.toISOString();
        } else if(typeof(value) === "number" || typeof(value) === "boolean") {
            return Number(value).toString();
        } else {
            return String(value).toString();
        }
    };

    Workbook.prototype.insertCellValue = function(cell, substitution) {
        var self = this;

        var cellValue = cell.find("v"),
            stringified = self.stringify(substitution);

        if(typeof(substitution) === "number") {
            cell.attrib.t = "n";
            cellValue.text = stringified;
        } else if(typeof(substitution) === "boolean" ) {
            cell.attrib.t = "b";
            cellValue.text = stringified;
        } else if(substitution instanceof Date) {
            cell.attrib.t = "d";
            cellValue.text = stringified;
        } else {
            cell.attrib.t = "s";
            cellValue.text = self.stringIndex(stringified);
        }
    };

    Workbook.prototype.substituteScalar = function(cell, string, placeholder, substitution) {
        var self = this;

        var cellValue = cell.find("v"),
            stringified = self.stringify(substitution),
            newString = stringified;

        if(placeholder.full && typeof(substitution) === "number") {
            cell.attrib.t = "n";
            cellValue.text = stringified;
        } else if(placeholder.full && typeof(substitution) === "boolean" ) {
            cell.attrib.t = "b";
            cellValue.text = stringified;
        } else if(placeholder.full && substitution instanceof Date) {
            cell.attrib.t = "d";
            cellValue.text = stringified;
        } else if(placeholder.full && typeof(substitution) === "string") {
            cell.attrib.t = "s";
            self.replaceString(string, stringified);
        } else if(!placeholder.full) {
            cell.attrib.t = "s";
            newString = string.replace(placeholder.placeholder, stringified);
            self.replaceString(string, newString);
        } else {
            return null;
        }

        return newString;
    };

    Workbook.prototype.cloneElement = function(element) {
        var self = this;

        var newElement = etree.Element(element.tag, element.attrib);
        newElement.text = element.text;
        newElement.tail = element.tail;
        newElement.getchildren().forEach(function(child) {
            newElement.append(self.cloneElement(child));
        });
        return newElement;
    };

    Workbook.prototype.replaceChildren = function(parent, children) {
        parent.delSlice(0, parent.len());
        children.forEach(function(child) {
            parent.append(child);
        });
    };

    return Workbook;
})();<commit_msg>Use our new methods for working with cell references<commit_after>/*jshint globalstrict:true, devel:true */
/*global require, module, exports, process, __dirname, Buffer */
"use strict";

var fs    = require('fs'),
    path  = require('path'),
    zip   = require('node-zip'),
    etree = require('elementtree'),
    _     = require('lodash');

module.exports = (function() {

    var SHARED_STRINGS = "xl/sharedStrings.xml",
        WORKSHEETS     = "xl/worksheets/";

    /**
     * Create a new workbook. Either pass the raw data of a .xlsx file,
     * or call `loadTemplate()` later.
     */
    var Workbook = function(data) {
        var self = this;

        self.archive = null;
        self.sharedStrings = [];
        self.sharedStringsLookup = {};

        if(data) {
            self.loadTemplate(data);
        }
    };

    /**
     * Load a .xlsx file from a byte array.
     */
    Workbook.prototype.loadTemplate = function(data) {
        var self = this;

        if(Buffer.isBuffer(data)) {
            data = data.toString('binary');
        }

        self.archive = new zip(data, {base64: false, checkCRC32: true});
        self.readSharedStrings();
    };

    /**
     * Interpolate values for the sheet with the given number (1-based)
     * using the given substitutions (an object).
     */
    Workbook.prototype.substitute = function(sheet, substitutions) {
        var self = this;

        function getCurrentRow(row, rowsInserted) {
            return parseInt(row.attrib.r, 10) + rowsInserted;
        }

        function getCurrentCell(cell, currentRow, cellsInserted) {
            var ref = self.joinRef({
                row: currentRow,
                col: self.splitRef(cell.attrib.r).col
            });

            // TODO: optimise
            // TODO: deal with negatives?
            for(var i = 0; i < cellsInserted; ++i) {
                ref = self.nextCol(ref);
            }

            return ref;
        }

        var file = WORKSHEETS + "sheet" + sheet + ".xml",
            tree = etree.parse(self.archive.file(file).asText()),
            root = tree.getroot();

        var sheetData = root.find("sheetData"),
            currentRow = null,
            rowsInserted = 0,
            rows = [];

        sheetData.findall("row").forEach(function(row) {
            var appendRow = true;
            row.attrib.r = currentRow = getCurrentRow(row, rowsInserted);

            var cells = [],
                currentCell = null,
                cellsInserted = 0;

            row.findall("c").forEach(function(cell) {
                var appendCell = true;
                cell.attrib.r = currentCell = getCurrentCell(cell, currentRow, cellsInserted);

                // If c[@t="s"] (string cellumn), look up /c/v@text as integer in
                // `this.sharedStrings`
                if(cell.attrib.t === "s") {
                    var cellValue   = cell.find("v"),
                        stringIndex = parseInt(cellValue.text, 10),
                        string      = self.sharedStrings[stringIndex];

                    // Look for a shared string that may contain placeholders
                    if(string !== undefined) {

                        // Loop over placeholders
                        var placeholders = self.extractPlaceholders(string);
                        placeholders.forEach(function(placeholder) {

                            // Only substitute things for which we have a substition
                            var substitution = substitutions[placeholder.name];
                            if(substitution === undefined) {
                                return;
                            }

                            var substituted = self.substituteScalar(cell, string, placeholder, substitution);
                            if(substituted !== undefined) {
                                string = substituted; // in case we have multiple placeholders
                            } else if(placeholder.full && substitution instanceof Array) {

                                // A table substitution (rows)
                                if(placeholder.type === "table") { // multiple rows

                                    // TODO

                                // A list substitution (columns)
                                } else if(placeholder.type === "normal") {
                                    appendCell = false; // don't double-insert cells
                                    --cellsInserted; // we technically delete one before we start adding back

                                    // add a cell for each element in the list
                                    substitution.forEach(function(substitutionElement) {
                                        ++cellsInserted;
                                        if(cellsInserted > 0) {
                                            currentCell = self.nextCol(currentCell);
                                        }

                                        var newCol = self.cloneElement(cell);
                                        self.insertValue(newCol, substitutionElement);

                                        newCol.attrib.r = currentCell;
                                        cells.push(newCol);
                                    });
                                }
                            }
                        });
                    }
                }

                // if we are inserting rows or columns, we may not want to keep the original cell anymore
                if(appendCell) {
                    cells.push(cell);
                }

            });

            if(appendRow) {
                rows.push(row);

                // We may have inserted columns, so re-build the children of the row
                self.replaceChildren(row, cells);

                // Update row spans attribute
                if(cellsInserted !== 0 && row.attrib.spans) {
                    var rowSpan = row.attrib.spans.split(':').map(function(f) { return parseInt(f, 10); });
                    rowSpan[1] += cellsInserted;
                    row.attrib.spans = rowSpan.join(":");
                }
            }

        });

        // We may have inserted rows, so re-build the children of the sheetData
        self.replaceChildren(sheetData, rows);

        // TODO: Update <mergeCells />

        // Write back the modified XML tree
        self.archive.file(file, etree.tostring(root));
    };

    /**
     * Generate a new binary .xlsx file
     */
    Workbook.prototype.generate = function() {
        var self = this;

        self.writeSharedStrings();
        return self.archive.generate({base64:false,compression:'DEFLATE'});
    };

    // Helpers

    // Read the shared strings from the workbook
    Workbook.prototype.readSharedStrings = function() {
        var self = this;

        var tree = etree.parse(self.archive.file(SHARED_STRINGS).asText());
        self.sharedStrings = [];
        tree.findall('si/t').forEach(function(t) {
            self.sharedStrings.push(t.text);
            self.sharedStringsLookup[t.text] = self.sharedStrings.length - 1;
        });
    };

    // Write back the new shared strings list
    Workbook.prototype.writeSharedStrings = function() {
        var self = this;

        var tree = etree.parse(self.archive.file(SHARED_STRINGS).asText()),
            root = tree.getroot(),
            children = root.getchildren();

        root.delSlice(0, children.length);

        self.sharedStrings.forEach(function(string) {
            var si = new etree.Element("si"),
                t  = new etree.Element("t");

            t.text = string;
            si.append(t);
            root.append(si);
        });

        root.attrib.count = self.sharedStrings.length;
        root.attrib.uniqueCount = self.sharedStrings.length;

        self.archive.file(SHARED_STRINGS, etree.tostring(root));
    };

    // Add a new shared string
    Workbook.prototype.addSharedString = function(s) {
        var self = this;

        var idx = self.sharedStrings.length;
        self.sharedStrings.push(s);
        self.sharedStringsLookup[s] = idx;

        return idx;
    };

    // Get the number of a shared string, adding a new one if necessary.
    Workbook.prototype.stringIndex = function(s) {
        var self = this;

        var idx = self.sharedStringsLookup[s];
        if(idx === undefined) {
            idx = self.addSharedString(s);
        }
        return idx;
    };

    // Replace a shared string with a new one at the same index. Return the
    // index.
    Workbook.prototype.replaceString = function(oldString, newString) {
        var self = this;

        var idx = self.sharedStringsLookup[oldString];
        if(idx === undefined) {
            idx = self.addSharedString(newString);
        } else {
            self.sharedStrings[idx] = newString;
            delete self.sharedStringsLookup[oldString];
            self.sharedStringsLookup[newString] = idx;
        }

        return idx;
    };

    // Return a list of tokens that may exist in the string.
    // Keys are: `placeholder` (the full placeholder, including the `${}`
    // delineators), `name` (the name part of the token), `key` (the object key
    // for `table` tokens), `full` (boolean indicating whether this placeholder
    // is the entirety of the string) and `type` (one of `table` or `cell`)
    Workbook.prototype.extractPlaceholders = function(string) {
        // Yes, that's right. It's a bunch of brackets and question marks and stuff.
        var re = /\${(?:(.+?):)?(.+?)(?:\.(.+?))?}/g;

        var match = null, matches = [];
        while((match = re.exec(string)) !== null) {
            matches.push({
                placeholder: match[0],
                type: match[1] || 'normal',
                name: match[2],
                key: match[3],
                full: match[0].length === string.length
            });
        }

        return matches;
    };

    // Split a reference into an object with keys `row` and `col`.
    Workbook.prototype.splitRef = function(ref) {
        var match = ref.match(/([A-Z]+)([0-9]+)/);
        return {
            col: match[1],
            row: parseInt(match[2], 10)
        };
    };

    // Join an object with keys `row` and `col` into a single reference string
    Workbook.prototype.joinRef = function(ref) {
        return ref.col.toUpperCase() + Number(ref.row).toString();
    };

    // Get the next column's cell reference given a reference like "B2".
    Workbook.prototype.nextCol = function(ref) {
        var self = this;
        ref = ref.toUpperCase();
        return ref.replace(/[A-Z]+/, function(match) {
            return self.numToChar(self.charToNum(match) + 1);
        });
    };

    // Get the next row's cell reference given a reference like "B2".
    Workbook.prototype.nextRow = function(ref) {
        ref = ref.toUpperCase();
        return ref.replace(/[0-9]+/, function(match) {
            return (parseInt(match, 10) + 1).toString();
        });
    };

    // Turn a reference like "AA" into a number like 27
    Workbook.prototype.charToNum = function(str) {
        var num = 0;
        for(var idx = str.length - 1, iteration = 0; idx >= 0; --idx, ++iteration) {
            var thisChar = str.charCodeAt(idx) - 64, // A -> 1; B -> 2; ... Z->26
                multiplier = Math.pow(26, iteration);
            num += multiplier * thisChar;
        }
        return num;
    };

    // Turn a number like 27 into a reference like "AA"
    Workbook.prototype.numToChar = function(num) {
        var str = "";

        for(var i = 0; num > 0; ++i) {
            var remainder = num % 26,
                charCode = remainder + 64;
            num = (num - remainder) / 26;

            // Compensate for the fact that we don't represent zero, e.g. A = 1, Z = 26, but AA = 27
            if(remainder === 0) { // 26 -> Z
                charCode = 90;
                --num;
            }

            str = String.fromCharCode(charCode) + str;
        }

        return str;
    };

    Workbook.prototype.stringify = function (value) {
        var self = this;

        if(value instanceof Date) {
            return value.toISOString();
        } else if(typeof(value) === "number" || typeof(value) === "boolean") {
            return Number(value).toString();
        } else {
            return String(value).toString();
        }
    };

    Workbook.prototype.insertCellValue = function(cell, substitution) {
        var self = this;

        var cellValue = cell.find("v"),
            stringified = self.stringify(substitution);

        if(typeof(substitution) === "number") {
            cell.attrib.t = "n";
            cellValue.text = stringified;
        } else if(typeof(substitution) === "boolean" ) {
            cell.attrib.t = "b";
            cellValue.text = stringified;
        } else if(substitution instanceof Date) {
            cell.attrib.t = "d";
            cellValue.text = stringified;
        } else {
            cell.attrib.t = "s";
            cellValue.text = self.stringIndex(stringified);
        }
    };

    Workbook.prototype.substituteScalar = function(cell, string, placeholder, substitution) {
        var self = this;

        var cellValue = cell.find("v"),
            stringified = self.stringify(substitution),
            newString = stringified;

        if(placeholder.full && typeof(substitution) === "number") {
            cell.attrib.t = "n";
            cellValue.text = stringified;
        } else if(placeholder.full && typeof(substitution) === "boolean" ) {
            cell.attrib.t = "b";
            cellValue.text = stringified;
        } else if(placeholder.full && substitution instanceof Date) {
            cell.attrib.t = "d";
            cellValue.text = stringified;
        } else if(placeholder.full && typeof(substitution) === "string") {
            cell.attrib.t = "s";
            self.replaceString(string, stringified);
        } else if(!placeholder.full) {
            cell.attrib.t = "s";
            newString = string.replace(placeholder.placeholder, stringified);
            self.replaceString(string, newString);
        } else {
            return null;
        }

        return newString;
    };

    Workbook.prototype.cloneElement = function(element) {
        var self = this;

        var newElement = etree.Element(element.tag, element.attrib);
        newElement.text = element.text;
        newElement.tail = element.tail;
        newElement.getchildren().forEach(function(child) {
            newElement.append(self.cloneElement(child));
        });
        return newElement;
    };

    Workbook.prototype.replaceChildren = function(parent, children) {
        parent.delSlice(0, parent.len());
        children.forEach(function(child) {
            parent.append(child);
        });
    };

    return Workbook;
})();<|endoftext|>


<commit_before>import React from 'react';
import hoistStatics from 'hoist-non-react-statics';
import invariant from 'invariant';
import shallowEqual from 'shallowequal';

export function DefaultErrorComponent({error}) {
  return (

      {error.message}

      {error.stack}

  );
}

export function DefaultLoadingComponent() {
  return (
Loading...
);
}

export function compose(fn, L1, E1, options = {pure: true}) {
  return (ChildComponent, L2, E2) => {
    invariant(
      Boolean(ChildComponent),
      'Should provide a child component to build the higher order container.'
    );

    const LoadingComponent = L1 || L2 || DefaultLoadingComponent;
    const ErrorComponent = E1 || E2 || DefaultErrorComponent;

    const Container = class extends React.Component {
      constructor(props, context) {
        super(props, context);

        this.state = {};

        // XXX: In the server side environment, we need to
        // stop the subscription right away. Otherwise, it's a starting
        // point to huge subscription leak.
        this._subscribe(props);
      }

      componentDidMount() {
        this._mounted = true;
      }

      componentWillReceiveProps(props) {
        this._subscribe(props);
      }

      componentWillUnmount() {
        this._unsubscribe();
      }

      shouldComponentUpdate(nextProps, nextState) {
        if (!options.pure) {
          return true;
        }

        return (
          !shallowEqual(this.props, nextProps) ||
          this.state.error !== nextState.error ||
          !shallowEqual(this.state.payload, nextState.payload)
        );
      }

      render() {
        const error = this._getError();
        const loading = this._isLoading();

        if (error) {
          return (<ErrorComponent error={error}/>);
        }

        if (loading) {
          return (<LoadingComponent />);
        }

        return (<ChildComponent {...this._getProps()} />);
      }

      _subscribe(props) {
        this._unsubscribe();

        this._stop = fn(props, (error, payload) => {
          if (error) {
            invariant(
              error.message && error.stack,
              'Passed error should be an instance of an Error.'
            );
          }

          const state = {error, payload};

          if (this._mounted) {
            this.setState(state);
          } else {
            this.state = state;
          }
        });
      }

      _unsubscribe() {
        if (this._stop) {
          this._stop();
        }
      }

      _getProps() {
        const {
          payload = {}
        } = this.state;

        const props = {
          ...this.props,
          ...payload
        };

        return props;
      }

      _getError() {
        const {error} = this.state;
        return error;
      }

      _isLoading() {
        const {payload} = this.state;
        return !Boolean(payload);
      }
    };

    const childDisplayName =
      // Get the display name if it's set.
      ChildComponent.displayName ||
      // Get the display name from the function name.
      ChildComponent.name ||
      // If not, just add a default one.
      'ChildComponent';

    Container.displayName = `Container(${childDisplayName})`;
    return hoistStatics(Container, ChildComponent);
  };
}

export function composeWithTracker(reactiveFn, L, E, options) {
  const onPropsChange = (props, onData) => {
    let trackerCleanup;
    const handler = Tracker.autorun(() => {
      trackerCleanup = reactiveFn(props, onData);
    });

    return () => {
      if (typeof (trackerCleanup) === 'function') {
        trackerCleanup();
      }
      return handler.stop();
    };
  };

  return compose(onPropsChange, L, E, options);
}

export function composeWithPromise(fn, L, E, options) {
  const onPropsChange = (props, onData) => {
    const promise = fn(props);
    invariant(
      (typeof promise.then === 'function') &&
      (typeof promise.catch === 'function'),
      'Should return a promise from the callback of `composeWithPromise`'
    );

    onData();
    promise
      .then(data => {
        invariant(
          typeof data === 'object',
          'Should return a plain object from the promise'
        );
        const clonedData = {...data};
        onData(null, clonedData);
      })
      .catch(err => {
        onData(err);
      });
  };

  return compose(onPropsChange, L, E, options);
}

export function composeWithObservable(fn, L, E, options) {
  const onPropsChange = (props, sendData) => {
    const observable = fn(props);
    invariant(
      typeof observable.subscribe === 'function',
      'Should return an observable from the callback of `composeWithObservable`'
    );

    sendData();
    const onData = data => {
      invariant(
        typeof data === 'object',
        'Should return a plain object from the promise'
      );
      const clonedData = {...data};
      sendData(null, clonedData);
    };

    const onError = err => {
      sendData(err);
    };

    const sub = observable.subscribe(onData, onError);
    return sub.completed.bind(sub);
  };

  return compose(onPropsChange, L, E, options);
}

// utility function to compose multiple composers at once.
export function composeAll(...composers) {
  return function (BaseComponent) {
    if (BaseComponent === null || BaseComponent === undefined) {
      throw new Error('Curry function of composeAll needs an input.');
    }

    let finalComponent = BaseComponent;
    composers.forEach(composer => {
      if (typeof composer !== 'function') {
        throw new Error('Composer should be a function.');
      }

      finalComponent = composer(finalComponent);

      if (finalComponent === null || finalComponent === undefined) {
        throw new Error('Composer function should return a value.');
      }
    });

    return finalComponent;
  };
}
<commit_msg>Prevent setState on unmounting/unmounted components<commit_after>import React from 'react';
import hoistStatics from 'hoist-non-react-statics';
import invariant from 'invariant';
import shallowEqual from 'shallowequal';

export function DefaultErrorComponent({error}) {
  return (

      {error.message}

      {error.stack}

  );
}

export function DefaultLoadingComponent() {
  return (
Loading...
);
}

export function compose(fn, L1, E1, options = {pure: true}) {
  return (ChildComponent, L2, E2) => {
    invariant(
      Boolean(ChildComponent),
      'Should provide a child component to build the higher order container.'
    );

    const LoadingComponent = L1 || L2 || DefaultLoadingComponent;
    const ErrorComponent = E1 || E2 || DefaultErrorComponent;

    const Container = class extends React.Component {
      constructor(props, context) {
        super(props, context);

        this.state = {};

        // XXX: In the server side environment, we need to
        // stop the subscription right away. Otherwise, it's a starting
        // point to huge subscription leak.
        this._subscribe(props);
      }

      componentDidMount() {
        this._mounted = true;
      }

      componentWillReceiveProps(props) {
        this._subscribe(props);
      }

      componentWillUnmount() {
        this._mounted = false;
        this._unsubscribe();
      }

      shouldComponentUpdate(nextProps, nextState) {
        if (!options.pure) {
          return true;
        }

        return (
          !shallowEqual(this.props, nextProps) ||
          this.state.error !== nextState.error ||
          !shallowEqual(this.state.payload, nextState.payload)
        );
      }

      render() {
        const error = this._getError();
        const loading = this._isLoading();

        if (error) {
          return (<ErrorComponent error={error}/>);
        }

        if (loading) {
          return (<LoadingComponent />);
        }

        return (<ChildComponent {...this._getProps()} />);
      }

      _subscribe(props) {
        this._unsubscribe();

        this._stop = fn(props, (error, payload) => {
          if (error) {
            invariant(
              error.message && error.stack,
              'Passed error should be an instance of an Error.'
            );
          }

          const state = {error, payload};

          if (this._mounted) {
            this.setState(state);
          } else {
            this.state = state;
          }
        });
      }

      _unsubscribe() {
        if (this._stop) {
          this._stop();
        }
      }

      _getProps() {
        const {
          payload = {}
        } = this.state;

        const props = {
          ...this.props,
          ...payload
        };

        return props;
      }

      _getError() {
        const {error} = this.state;
        return error;
      }

      _isLoading() {
        const {payload} = this.state;
        return !Boolean(payload);
      }
    };

    const childDisplayName =
      // Get the display name if it's set.
      ChildComponent.displayName ||
      // Get the display name from the function name.
      ChildComponent.name ||
      // If not, just add a default one.
      'ChildComponent';

    Container.displayName = `Container(${childDisplayName})`;
    return hoistStatics(Container, ChildComponent);
  };
}

export function composeWithTracker(reactiveFn, L, E, options) {
  const onPropsChange = (props, onData) => {
    let trackerCleanup;
    const handler = Tracker.autorun(() => {
      trackerCleanup = reactiveFn(props, onData);
    });

    return () => {
      if (typeof (trackerCleanup) === 'function') {
        trackerCleanup();
      }
      return handler.stop();
    };
  };

  return compose(onPropsChange, L, E, options);
}

export function composeWithPromise(fn, L, E, options) {
  const onPropsChange = (props, onData) => {
    const promise = fn(props);
    invariant(
      (typeof promise.then === 'function') &&
      (typeof promise.catch === 'function'),
      'Should return a promise from the callback of `composeWithPromise`'
    );

    onData();
    promise
      .then(data => {
        invariant(
          typeof data === 'object',
          'Should return a plain object from the promise'
        );
        const clonedData = {...data};
        onData(null, clonedData);
      })
      .catch(err => {
        onData(err);
      });
  };

  return compose(onPropsChange, L, E, options);
}

export function composeWithObservable(fn, L, E, options) {
  const onPropsChange = (props, sendData) => {
    const observable = fn(props);
    invariant(
      typeof observable.subscribe === 'function',
      'Should return an observable from the callback of `composeWithObservable`'
    );

    sendData();
    const onData = data => {
      invariant(
        typeof data === 'object',
        'Should return a plain object from the promise'
      );
      const clonedData = {...data};
      sendData(null, clonedData);
    };

    const onError = err => {
      sendData(err);
    };

    const sub = observable.subscribe(onData, onError);
    return sub.completed.bind(sub);
  };

  return compose(onPropsChange, L, E, options);
}

// utility function to compose multiple composers at once.
export function composeAll(...composers) {
  return function (BaseComponent) {
    if (BaseComponent === null || BaseComponent === undefined) {
      throw new Error('Curry function of composeAll needs an input.');
    }

    let finalComponent = BaseComponent;
    composers.forEach(composer => {
      if (typeof composer !== 'function') {
        throw new Error('Composer should be a function.');
      }

      finalComponent = composer(finalComponent);

      if (finalComponent === null || finalComponent === undefined) {
        throw new Error('Composer function should return a value.');
      }
    });

    return finalComponent;
  };
}
<|endoftext|>