<commit_before>var _ = require('lodash');
var path = require('path');
var nunjucks = require('nunjucks');
var escapeStringRegexp = require('escape-string-regexp');

var Promise = require('../utils/promise');
var error = require('../utils/error');
var parsers = require('../parsers');
var defaultBlocks = require('./blocks');
var defaultFilters = require('./filters');
var Loader = require('./loader');

// Return extension name for a specific block
function blockExtName(name) {
    return 'Block'+name+'Extension';
}

// Normalize the result of block process function
function normBlockResult(blk) {
    if (_.isString(blk)) blk = { body: blk };
    return blk;
}

function TemplateEngine(output) {
    this.output = output;
    this.book = output.book;
    this.log = this.book.log;

    // Create file loader
    this.loader = new Loader(this);

    // Create nunjucks instance
    this.env = new nunjucks.Environment(
        this.loader,
        {
            // Escaping is done after by the asciidoc/markdown parser
            autoescape: false,

            // Syntax
            tags: {
                blockStart: '{%',
                blockEnd: '%}',
                variableStart: '{{',
                variableEnd: '}}',
                commentStart: '{###',
                commentEnd: '###}'
            }
        }
    );

    // List of tags shortcuts
    this.shortcuts = [];

    // Map of blocks bodies (that requires post-processing)
    this.blockBodies = {};

    // Map of added blocks
    this.blocks = {};

    // Bind methods
    _.bindAll(this);

    // Add default blocks and filters
    this.addBlocks(defaultBlocks);
    this.addFilters(defaultFilters);
}

// Bind a function to a context
// Filters and blocks are binded to this context
TemplateEngine.prototype.bindContext = function(func) {
    var that = this;

    return function() {
        var ctx = {
            ctx: this.ctx,
            book: that.book,
            output: that.output
        };
        error.deprecateField(ctx, 'generator', that.output.name, '"generator" property is deprecated, use "output.generator" instead');

        return func.apply(ctx, arguments);
    };
};

// Interpolate a string content to replace shortcuts according to the filetype
TemplateEngine.prototype.interpolate = function(filepath, source) {
    var parser = parsers.getByExt(path.extname(filepath));
    var type = parser? parser.name : null;

    return this.applyShortcuts(type, source);
};

// Add a new custom filter
TemplateEngine.prototype.addFilter = function(filterName, func) {
    try {
        this.env.getFilter(filterName);
        this.log.error.ln('conflict in filters, "'+filterName+'" is already set');
        return false;
    } catch(e) {
        // Filter doesn't exist
    }

    this.log.debug.ln('add filter "'+filterName+'"');
    this.env.addFilter(filterName, this.bindContext(function() {
        var ctx = this;
        var args = Array.prototype.slice.apply(arguments);
        var callback = _.last(args);

        Promise()
        .then(function() {
            return func.apply(ctx, args.slice(0, -1));
        })
        .nodeify(callback);
    }), true);
    return true;
};

// Add multiple filters at once
TemplateEngine.prototype.addFilters = function(filters) {
    _.each(filters, function(filter, name) {
        this.addFilter(name, filter);
    }, this);
};

// Return true if a block is defined
TemplateEngine.prototype.hasBlock = function(name) {
    return this.env.hasExtension(blockExtName(name));
};

// Remove/Disable a block
TemplateEngine.prototype.removeBlock = function(name) {
    if (!this.hasBlock(name)) return;

    // Remove nunjucks extension
    this.env.removeExtension(blockExtName(name));

    // Cleanup shortcuts
    this.shortcuts = _.reject(this.shortcuts, {
        block: name
    });
};

// Add a block
// Using the extensions of nunjucks: https://mozilla.github.io/nunjucks/api.html#addextension
TemplateEngine.prototype.addBlock = function(name, block) {
    var that = this, Ext, extName;

    // Block can be a simple function
    if (_.isFunction(block)) block = { process: block };

    block = _.defaults(block || {}, {
        shortcuts: [],
        end: 'end'+name,
        blocks: []
    });

    extName = blockExtName(name);

    if (!block.process) {
        throw new Error('Invalid block "' + name + '", it should have a "process" method');
    }

    if (this.hasBlock(name) && !defaultBlocks[name]) {
        this.log.warn.ln('conflict in blocks, "'+name+'" is already defined');
    }

    // Cleanup previous block
    this.removeBlock(name);

    this.log.debug.ln('add block \''+name+'\'');
    this.blocks[name] = block;

    Ext = function () {
        this.tags = [name];

        this.parse = function(parser, nodes) {
            var body = null;
            var lastBlockName = null;
            var lastBlockArgs = null;
            var allBlocks = block.blocks.concat([block.end]);
            var subbodies = {};

            var tok = parser.nextToken();
            var args = parser.parseSignature(null, true);
            parser.advanceAfterBlockEnd(tok.value);

            do {
                // Read body
                var currentBody = parser.parseUntilBlocks.apply(parser, allBlocks);

                // Handle body with previous block name and args
                if (lastBlockName) {
                    subbodies[lastBlockName] = subbodies[lastBlockName] || [];
                    subbodies[lastBlockName].push({
                        body: currentBody,
                        args: lastBlockArgs
                    });
                } else {
                    body = currentBody;
                }

                // Read new block
                lastBlockName = parser.peekToken().value;

                // Parse signature and move to the end of the block
                if (lastBlockName != block.end) {
                    lastBlockArgs = parser.parseSignature(null, true);
                    parser.advanceAfterBlockEnd(lastBlockName);
                }
            } while (lastBlockName != block.end);

            parser.advanceAfterBlockEnd();

            var bodies = [body];
            _.each(block.blocks, function(blockName) {
                subbodies[blockName] = subbodies[blockName] || [];
                if (subbodies[blockName].length === 0) {
                    subbodies[blockName].push({
                        args: new nodes.NodeList(),
                        body: new nodes.NodeList()
                    });
                }

                bodies.push(subbodies[blockName][0].body);
            });

            return new nodes.CallExtensionAsync(this, 'run', args, bodies);
        };

        this.run = function(context) {
            var args = Array.prototype.slice.call(arguments, 1);
            var callback = args.pop();

            // Extract blocks
            var blocks = args
                .concat([])
                .slice(-block.blocks.length);

            // Eliminate blocks from list
            if (block.blocks.length > 0) args = args.slice(0, -block.blocks.length);

            // Extract main body and kwargs
            var body = args.pop();
            var kwargs = _.isObject(_.last(args))? args.pop() : {};

            // Extract blocks body
            var _blocks =  _.map(block.blocks, function(blockName, i){
                return {
                    name: blockName,
                    body: blocks[i]()
                };
            });

            Promise()
            .then(function() {
                return that.applyBlock(name, {
                    body: body(),
                    args: args,
                    kwargs: kwargs,
                    blocks: _blocks
                }, context);
            })

            // Process the block returned
            .then(that.processBlock)
            .nodeify(callback);
        };
    };

    // Add the Extension
    this.env.addExtension(extName, new Ext());

    // Add shortcuts if any
    if (!_.isArray(block.shortcuts)) {
        block.shortcuts = [block.shortcuts];
    }

    _.each(block.shortcuts, function(shortcut) {
        this.log.debug.ln('add template shortcut from "'+shortcut.start+'" to block "'+name+'" for parsers ', shortcut.parsers);
        this.shortcuts.push({
            block: name,
            parsers: shortcut.parsers,
            start: shortcut.start,
            end: shortcut.end,
            tag: {
                start: name,
                end: block.end
            }
        });
    }, this);
};

// Add multiple blocks at once
TemplateEngine.prototype.addBlocks = function(blocks) {
    _.each(blocks, function(block, name) {
        this.addBlock(name, block);
    }, this);
};

// Apply a block to some content
// This method result depends on the type of block (async or sync)
TemplateEngine.prototype.applyBlock = function(name, blk, ctx) {
    var func, block, r;

    block = this.blocks[name];
    if (!block) throw new Error('Block not found "'+name+'"');
    if (_.isString(blk)) {
        blk = {
            body: blk
        };
    }

    blk = _.defaults(blk, {
        args: [],
        kwargs: {},
        blocks: []
    });

    // Bind and call block processor
    func = this.bindContext(block.process);
    r = func.call(ctx || {}, blk);

    if (Promise.isPromise(r)) return r.then(normBlockResult);
    else return normBlockResult(r);
};

// Process the result of block in a context
TemplateEngine.prototype.processBlock = function(blk) {
    blk = _.defaults(blk, {
        parse: false,
        post: undefined
    });
    blk.id = _.uniqueId('blk');

    var toAdd = (!blk.parse) || (blk.post !== undefined);

    // Add to global map
    if (toAdd) this.blockBodies[blk.id] = blk;

    // Parsable block, just return it
    if (blk.parse) {
        return blk.body;
    }

    // Return it as a position marker
    return '{{-%'+blk.id+'%-}}';
};

// Render a string (without post processing)
TemplateEngine.prototype.render = function(content, context, options) {
    options = _.defaults(options || {}, {
        path: null
    });
    var filename = options.path;

    // Setup path and type
    if (options.path) {
        options.path = this.book.resolve(options.path);
    }

    // Replace shortcuts
    content = this.applyShortcuts(options.type, content);

    return Promise.nfcall(this.env.renderString.bind(this.env), content, context, options)
    .fail(function(err) {
        throw error.TemplateError(err, {
            filename: filename || '<inline>'
        });
    });
};

// Render a string with post-processing
TemplateEngine.prototype.renderString = function(content, context, options) {
    return this.render(content, context, options)
    .then(this.postProcess);
};

// Apply a shortcut to a string
TemplateEngine.prototype.applyShortcut = function(content, shortcut) {
    var regex = new RegExp(
        escapeStringRegexp(shortcut.start) + '([\\s\\S]*?[^\\$])' + escapeStringRegexp(shortcut.end),
       'g'
    );
    return content.replace(regex, function(all, match) {
        return '{% '+shortcut.tag.start+' %}'+ match + '{% '+shortcut.tag.end+' %}';
    });
};

// Replace position markers of blocks by body after processing
// This is done to avoid that markdown/asciidoc processer parse the block content
TemplateEngine.prototype.replaceBlocks = function(content) {
    var that = this;

    return content.replace(/\{\{\-\%([\s\S]+?)\%\-\}\}/g, function(match, key) {
        var blk = that.blockBodies[key];
        if (!blk) return match;

        var body = blk.body;

        return body;
    });
};

// Apply all shortcuts to a template
TemplateEngine.prototype.applyShortcuts = function(type, content) {
    return _.chain(this.shortcuts)
        .filter(function(shortcut) {
            return _.contains(shortcut.parsers, type);
        })
        .reduce(this.applyShortcut, content)
        .value();
};

// Post process content
TemplateEngine.prototype.postProcess = function(content) {
    var that = this;

    return Promise(content)
    .then(that.replaceBlocks)
    .then(function(_content) {
        return Promise.serie(that.blockBodies, function(blk, blkId) {
            return Promise()
            .then(function() {
                if (!blk.post) return;
                return blk.post();
            })
            .then(function() {
                delete that.blockBodies[blkId];
            });
        })
        .thenResolve(_content);
    });
};

module.exports = TemplateEngine;
<commit_msg>Fix generator deprecation warning being shown for each call<commit_after>var _ = require('lodash');
var path = require('path');
var nunjucks = require('nunjucks');
var escapeStringRegexp = require('escape-string-regexp');

var Promise = require('../utils/promise');
var error = require('../utils/error');
var parsers = require('../parsers');
var defaultBlocks = require('./blocks');
var defaultFilters = require('./filters');
var Loader = require('./loader');

// Return extension name for a specific block
function blockExtName(name) {
    return 'Block'+name+'Extension';
}

// Normalize the result of block process function
function normBlockResult(blk) {
    if (_.isString(blk)) blk = { body: blk };
    return blk;
}

function TemplateEngine(output) {
    this.output = output;
    this.book = output.book;
    this.log = this.book.log;

    // Create file loader
    this.loader = new Loader(this);

    // Create nunjucks instance
    this.env = new nunjucks.Environment(
        this.loader,
        {
            // Escaping is done after by the asciidoc/markdown parser
            autoescape: false,

            // Syntax
            tags: {
                blockStart: '{%',
                blockEnd: '%}',
                variableStart: '{{',
                variableEnd: '}}',
                commentStart: '{###',
                commentEnd: '###}'
            }
        }
    );

    // List of tags shortcuts
    this.shortcuts = [];

    // Map of blocks bodies (that requires post-processing)
    this.blockBodies = {};

    // Map of added blocks
    this.blocks = {};

    // Bind methods
    _.bindAll(this);

    // Add default blocks and filters
    this.addBlocks(defaultBlocks);
    this.addFilters(defaultFilters);

    // Build context for this book with depreacted fields
    this.ctx = {
        book: this.book,
        output: this.output
    };
    error.deprecateField(this.ctx, 'generator', this.output.name, '"generator" property is deprecated, use "output.generator" instead');
}

// Bind a function to a context
// Filters and blocks are binded to this context
TemplateEngine.prototype.bindContext = function(func) {
    var that = this;

    return function() {
        var ctx = _.extend({
            ctx: this.ctx
        }, that.ctx);

        return func.apply(ctx, arguments);
    };
};

// Interpolate a string content to replace shortcuts according to the filetype
TemplateEngine.prototype.interpolate = function(filepath, source) {
    var parser = parsers.getByExt(path.extname(filepath));
    var type = parser? parser.name : null;

    return this.applyShortcuts(type, source);
};

// Add a new custom filter
TemplateEngine.prototype.addFilter = function(filterName, func) {
    try {
        this.env.getFilter(filterName);
        this.log.error.ln('conflict in filters, "'+filterName+'" is already set');
        return false;
    } catch(e) {
        // Filter doesn't exist
    }

    this.log.debug.ln('add filter "'+filterName+'"');
    this.env.addFilter(filterName, this.bindContext(function() {
        var ctx = this;
        var args = Array.prototype.slice.apply(arguments);
        var callback = _.last(args);

        Promise()
        .then(function() {
            return func.apply(ctx, args.slice(0, -1));
        })
        .nodeify(callback);
    }), true);
    return true;
};

// Add multiple filters at once
TemplateEngine.prototype.addFilters = function(filters) {
    _.each(filters, function(filter, name) {
        this.addFilter(name, filter);
    }, this);
};

// Return true if a block is defined
TemplateEngine.prototype.hasBlock = function(name) {
    return this.env.hasExtension(blockExtName(name));
};

// Remove/Disable a block
TemplateEngine.prototype.removeBlock = function(name) {
    if (!this.hasBlock(name)) return;

    // Remove nunjucks extension
    this.env.removeExtension(blockExtName(name));

    // Cleanup shortcuts
    this.shortcuts = _.reject(this.shortcuts, {
        block: name
    });
};

// Add a block
// Using the extensions of nunjucks: https://mozilla.github.io/nunjucks/api.html#addextension
TemplateEngine.prototype.addBlock = function(name, block) {
    var that = this, Ext, extName;

    // Block can be a simple function
    if (_.isFunction(block)) block = { process: block };

    block = _.defaults(block || {}, {
        shortcuts: [],
        end: 'end'+name,
        blocks: []
    });

    extName = blockExtName(name);

    if (!block.process) {
        throw new Error('Invalid block "' + name + '", it should have a "process" method');
    }

    if (this.hasBlock(name) && !defaultBlocks[name]) {
        this.log.warn.ln('conflict in blocks, "'+name+'" is already defined');
    }

    // Cleanup previous block
    this.removeBlock(name);

    this.log.debug.ln('add block \''+name+'\'');
    this.blocks[name] = block;

    Ext = function () {
        this.tags = [name];

        this.parse = function(parser, nodes) {
            var body = null;
            var lastBlockName = null;
            var lastBlockArgs = null;
            var allBlocks = block.blocks.concat([block.end]);
            var subbodies = {};

            var tok = parser.nextToken();
            var args = parser.parseSignature(null, true);
            parser.advanceAfterBlockEnd(tok.value);

            do {
                // Read body
                var currentBody = parser.parseUntilBlocks.apply(parser, allBlocks);

                // Handle body with previous block name and args
                if (lastBlockName) {
                    subbodies[lastBlockName] = subbodies[lastBlockName] || [];
                    subbodies[lastBlockName].push({
                        body: currentBody,
                        args: lastBlockArgs
                    });
                } else {
                    body = currentBody;
                }

                // Read new block
                lastBlockName = parser.peekToken().value;

                // Parse signature and move to the end of the block
                if (lastBlockName != block.end) {
                    lastBlockArgs = parser.parseSignature(null, true);
                    parser.advanceAfterBlockEnd(lastBlockName);
                }
            } while (lastBlockName != block.end);

            parser.advanceAfterBlockEnd();

            var bodies = [body];
            _.each(block.blocks, function(blockName) {
                subbodies[blockName] = subbodies[blockName] || [];
                if (subbodies[blockName].length === 0) {
                    subbodies[blockName].push({
                        args: new nodes.NodeList(),
                        body: new nodes.NodeList()
                    });
                }

                bodies.push(subbodies[blockName][0].body);
            });

            return new nodes.CallExtensionAsync(this, 'run', args, bodies);
        };

        this.run = function(context) {
            var args = Array.prototype.slice.call(arguments, 1);
            var callback = args.pop();

            // Extract blocks
            var blocks = args
                .concat([])
                .slice(-block.blocks.length);

            // Eliminate blocks from list
            if (block.blocks.length > 0) args = args.slice(0, -block.blocks.length);

            // Extract main body and kwargs
            var body = args.pop();
            var kwargs = _.isObject(_.last(args))? args.pop() : {};

            // Extract blocks body
            var _blocks =  _.map(block.blocks, function(blockName, i){
                return {
                    name: blockName,
                    body: blocks[i]()
                };
            });

            Promise()
            .then(function() {
                return that.applyBlock(name, {
                    body: body(),
                    args: args,
                    kwargs: kwargs,
                    blocks: _blocks
                }, context);
            })

            // Process the block returned
            .then(that.processBlock)
            .nodeify(callback);
        };
    };

    // Add the Extension
    this.env.addExtension(extName, new Ext());

    // Add shortcuts if any
    if (!_.isArray(block.shortcuts)) {
        block.shortcuts = [block.shortcuts];
    }

    _.each(block.shortcuts, function(shortcut) {
        this.log.debug.ln('add template shortcut from "'+shortcut.start+'" to block "'+name+'" for parsers ', shortcut.parsers);
        this.shortcuts.push({
            block: name,
            parsers: shortcut.parsers,
            start: shortcut.start,
            end: shortcut.end,
            tag: {
                start: name,
                end: block.end
            }
        });
    }, this);
};

// Add multiple blocks at once
TemplateEngine.prototype.addBlocks = function(blocks) {
    _.each(blocks, function(block, name) {
        this.addBlock(name, block);
    }, this);
};

// Apply a block to some content
// This method result depends on the type of block (async or sync)
TemplateEngine.prototype.applyBlock = function(name, blk, ctx) {
    var func, block, r;

    block = this.blocks[name];
    if (!block) throw new Error('Block not found "'+name+'"');
    if (_.isString(blk)) {
        blk = {
            body: blk
        };
    }

    blk = _.defaults(blk, {
        args: [],
        kwargs: {},
        blocks: []
    });

    // Bind and call block processor
    func = this.bindContext(block.process);
    r = func.call(ctx || {}, blk);

    if (Promise.isPromise(r)) return r.then(normBlockResult);
    else return normBlockResult(r);
};

// Process the result of block in a context
TemplateEngine.prototype.processBlock = function(blk) {
    blk = _.defaults(blk, {
        parse: false,
        post: undefined
    });
    blk.id = _.uniqueId('blk');

    var toAdd = (!blk.parse) || (blk.post !== undefined);

    // Add to global map
    if (toAdd) this.blockBodies[blk.id] = blk;

    // Parsable block, just return it
    if (blk.parse) {
        return blk.body;
    }

    // Return it as a position marker
    return '{{-%'+blk.id+'%-}}';
};

// Render a string (without post processing)
TemplateEngine.prototype.render = function(content, context, options) {
    options = _.defaults(options || {}, {
        path: null
    });
    var filename = options.path;

    // Setup path and type
    if (options.path) {
        options.path = this.book.resolve(options.path);
    }

    // Replace shortcuts
    content = this.applyShortcuts(options.type, content);

    return Promise.nfcall(this.env.renderString.bind(this.env), content, context, options)
    .fail(function(err) {
        throw error.TemplateError(err, {
            filename: filename || '<inline>'
        });
    });
};

// Render a string with post-processing
TemplateEngine.prototype.renderString = function(content, context, options) {
    return this.render(content, context, options)
    .then(this.postProcess);
};

// Apply a shortcut to a string
TemplateEngine.prototype.applyShortcut = function(content, shortcut) {
    var regex = new RegExp(
        escapeStringRegexp(shortcut.start) + '([\\s\\S]*?[^\\$])' + escapeStringRegexp(shortcut.end),
       'g'
    );
    return content.replace(regex, function(all, match) {
        return '{% '+shortcut.tag.start+' %}'+ match + '{% '+shortcut.tag.end+' %}';
    });
};

// Replace position markers of blocks by body after processing
// This is done to avoid that markdown/asciidoc processer parse the block content
TemplateEngine.prototype.replaceBlocks = function(content) {
    var that = this;

    return content.replace(/\{\{\-\%([\s\S]+?)\%\-\}\}/g, function(match, key) {
        var blk = that.blockBodies[key];
        if (!blk) return match;

        var body = blk.body;

        return body;
    });
};

// Apply all shortcuts to a template
TemplateEngine.prototype.applyShortcuts = function(type, content) {
    return _.chain(this.shortcuts)
        .filter(function(shortcut) {
            return _.contains(shortcut.parsers, type);
        })
        .reduce(this.applyShortcut, content)
        .value();
};

// Post process content
TemplateEngine.prototype.postProcess = function(content) {
    var that = this;

    return Promise(content)
    .then(that.replaceBlocks)
    .then(function(_content) {
        return Promise.serie(that.blockBodies, function(blk, blkId) {
            return Promise()
            .then(function() {
                if (!blk.post) return;
                return blk.post();
            })
            .then(function() {
                delete that.blockBodies[blkId];
            });
        })
        .thenResolve(_content);
    });
};

module.exports = TemplateEngine;
<|endoftext|>


<commit_before>'use strict';

const ms = require('pretty-ms');

module.exports = (data) => `

passes: ${data.passes}

failures: ${data.failures}

duration: ${ms(data.duration)}

${data.report}

`;
<commit_msg>fix(body): fix closing ul tag<commit_after>'use strict';

const ms = require('pretty-ms');

module.exports = (data) => `

passes: ${data.passes}

failures: ${data.failures}

duration: ${ms(data.duration)}

${data.report}

`;
<|endoftext|>


<commit_before>"use strict";
const express = require("express"),
    logger = require("morgan"),
    cookieParser = require("cookie-parser"),
    bodyParser = require("body-parser"),
    methodOverride = require("method-override"),
    session = require("express-session"),
    mongojs = require("mongojs");

const MongoStore = require("connect-mongo")(session);

let app = express();

let config = {
    db: process.env.DBURL
};

// Integrate Middleware
app.use(logger("dev"));
app.use(methodOverride("_method"));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(session({
    secret: "keyboard cat",
    store: new MongoStore({ url: config.db })
}));

app.use((req, res, next) => {
    // MONGOJS - See GH for Docs
    req.db = mongojs(config.db);
    next();
});

app.get("/dynamic", (req, res) => {
	res.send("Hello, world");
});

app.use(express.static("Build/Client"));

require("./routes/test.js")(app);

let server = app.listen(process.env.PORT || 3000, () => {
	let {address: host, port} = server.address();

	console.log(`Listening on http://${host}:${port}/`);
});
<commit_msg>Update main.js<commit_after>"use strict";
const express = require("express"),
    logger = require("morgan"),
    cookieParser = require("cookie-parser"),
    bodyParser = require("body-parser"),
    methodOverride = require("method-override"),
    session = require("express-session"),
    mongojs = require("mongojs");

const MongoStore = require("connect-mongo")(session);

let app = express();

let config = {
    db: process.env.DBURL
};

// Integrate Middleware
app.use(logger("dev"));
app.use(methodOverride("_method"));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(session({
    secret: "keyboard cat",
    store: new MongoStore({ url: config.db })
}));

app.use((req, res, next) => {
    // MONGOJS - See GH for Docs
    req.db = mongojs(config.db);
    next();
});

app.get("/dynamic", (req, res) => {
	res.send("Hello, world");
});

app.use(express.static("Build/Client"));

// require("./routes/test.js")(app);

let server = app.listen(process.env.PORT || 3000, () => {
	let {address: host, port} = server.address();

	console.log(`Listening on http://${host}:${port}/`);
});
<|endoftext|>


<commit_before>var dgram = require('dgram')

var DELAY = 800
var FREQ = 100
var lastSend = 0

module.exports = {
  init: init,
  send: send,
  getVersion: getVersion,
  getSerial: getSerial,
  getEnergy: getEnergy
}

var sequenceNumber = 100;
var callbacks = [];
var version = "Unknown"
var serial = "Unknown"
var energy = "Unknown"

var server = dgram.createSocket("udp4");

var queue = [];

function getVersion() {
  return version
}

function getSerial() {
  return serial
}

function getEnergy() {
  return energy
}

server.on("error", function (err) {
  console.warn("server error:\n" + err.stack);
  server.close();
});

server.on("message", function (msg, rinfo) {
  var str = String(msg)

  if (str.charAt(0) == '*') {
    var obj = JSON.parse(str.substring(2))

    if (obj.type == 'hub') {
      version = obj.fw
      serial = '74:0A:BC:' + obj.mac
    } else if (obj.type == 'energy') {
      energy = obj.cUse
    }
  } else {
    var recvSequenceNumber = 'S' + String(msg).substring(0, 3)

    var callback = false

    if (callbacks[recvSequenceNumber]) {
      callbacks[recvSequenceNumber](msg, rinfo)
      delete callbacks[recvSequenceNumber]
      callback = true
    }
  }

  console.log("recv: " + String(msg).replace('\n', '') + " (callback=" + callback + ")")
});

server.on("listening", function () {
  server.setBroadcast(true);
});

server.bind(9761);

function init(callback) {
  send("@H", "", "", "", "Retrieving", "Version", null)
}

function send(command, room, device, func, line1, line2, callback) {
  for (i = 0; i < queue.length; i++) {
    if (queue[i].room == room && queue[i].device == device && queue[i].func.substring(0,1) == func.substring(0,1)) {
      removedCallback = queue[i].callback

      console.log('Duplicate message dropped ', JSON.stringify(queue[i]))

      queue.splice(i, 1);

      removedCallback("100,OK", null)
    }
  }

  queue.push({command: command, room: room, device: device, func: func, line1: line1, line2: line2, callback: callback});
}

function sendFromQueue() {
  var now = new Date().getTime()

  if (now > lastSend + DELAY) {
    var command = queue.shift();

    if (command) {
      var buffer = new Buffer(sequenceNumber + "," +
        (command.command? command.command : "!") +
        (command.room? "R" + command.room : "") +
        (command.device? "D" + command.device : "") +
        (command.func? "F" + command.func : "") +
        "|" + (command.line1? command.line1 : "") +
        "|" + (command.line2? command.line2 : "") +
        "\n");

      if (command.callback) {
        callbacks[String('S' + sequenceNumber)] = command.callback;
      }

      if( sequenceNumber++ == 1000) {
        sequenceNumber = 100;
      }

      console.log("send: " + buffer.toString().replace('\n', ''));

      server.send(buffer, 0, buffer.length, 9760, "255.255.255.255", function(err, bytes) {
        if (err) {
          console.error(err);
        }
      });
    }

    lastSend = now
  }
}

setInterval(sendFromQueue, FREQ);
<commit_msg>Call callbacks immediately.<commit_after>var dgram = require('dgram')

var DELAY = 800
var FREQ = 100
var lastSend = 0

module.exports = {
  init: init,
  send: send,
  getVersion: getVersion,
  getSerial: getSerial,
  getEnergy: getEnergy
}

var sequenceNumber = 100;
var callbacks = [];
var version = "Unknown"
var serial = "Unknown"
var energy = "Unknown"

var server = dgram.createSocket("udp4");

var queue = [];

function getVersion() {
  return version
}

function getSerial() {
  return serial
}

function getEnergy() {
  return energy
}

server.on("error", function (err) {
  console.warn("server error:\n" + err.stack);
  server.close();
});

server.on("message", function (msg, rinfo) {
  var str = String(msg)

  if (str.charAt(0) == '*') {
    var obj = JSON.parse(str.substring(2))

    if (obj.type == 'hub') {
      version = obj.fw
      serial = '74:0A:BC:' + obj.mac
    } else if (obj.type == 'energy') {
      energy = obj.cUse
    }
  } else {
    var recvSequenceNumber = 'S' + String(msg).substring(0, 3)

    var callback = false

    if (callbacks[recvSequenceNumber]) {
      callbacks[recvSequenceNumber](msg, rinfo)
      delete callbacks[recvSequenceNumber]
      callback = true
    }
  }

  console.log("recv: " + String(msg).replace('\n', '') + " (callback=" + callback + ")")
});

server.on("listening", function () {
  server.setBroadcast(true);
});

server.bind(9761);

function init(callback) {
  send("@H", "", "", "", "Retrieving", "Version", null)
}

function send(command, room, device, func, line1, line2, callback) {
  for (i = 0; i < queue.length; i++) {
    if (queue[i].room == room && queue[i].device == device && queue[i].func.substring(0,1) == func.substring(0,1)) {
      // removedCallback = queue[i].callback

      console.log('Duplicate message dropped ', JSON.stringify(queue[i]))

      queue.splice(i, 1);

      removedCallback("100,OK", null)
    }
  }

  if (callback) {
    callback("100,OK", null)
  }

  queue.push({command: command, room: room, device: device, func: func, line1: line1, line2: line2, callback: callback});
}

function sendFromQueue() {
  var now = new Date().getTime()

  if (now > lastSend + DELAY) {
    var command = queue.shift();

    if (command) {
      var buffer = new Buffer(sequenceNumber + "," +
        (command.command? command.command : "!") +
        (command.room? "R" + command.room : "") +
        (command.device? "D" + command.device : "") +
        (command.func? "F" + command.func : "") +
        "|" + (command.line1? command.line1 : "") +
        "|" + (command.line2? command.line2 : "") +
        "\n");

      // if (command.callback) {
      //   callbacks[String('S' + sequenceNumber)] = command.callback;
      // }

      if( sequenceNumber++ == 1000) {
        sequenceNumber = 100;
      }

      console.log("send: " + buffer.toString().replace('\n', ''));

      server.send(buffer, 0, buffer.length, 9760, "255.255.255.255", function(err, bytes) {
        if (err) {
          console.error(err);
        }
      });
    }

    lastSend = now
  }
}

setInterval(sendFromQueue, FREQ);
<|endoftext|>


<commit_before>// XXX Todo:
// On windows, create a .cmd file.
// Read the #! in the file to see what it uses.  The vast majority
// of the time, this will be either:
// "#!/usr/bin/env <prog> <args...>"
// or:
// "#!<prog> <args...>"
//
// Write a binroot/pkg.bin + ".cmd" file that has this line in it:
// @<prog> <args...> %~dp0<target> %*

module.exports = cmdShim
cmdShim.ifExists = cmdShimIfExists

var fs = require("graceful-fs")
  , chain = require("slide").chain
  , mkdir = require("mkdirp")
  , rm = require("rimraf")
  , log = require("npmlog")
  , path = require("path")
  , npm = require("../npm.js")
  , shebangExpr = /^#\!\s*(?:\/usr\/bin\/env)?\s*([^ \t]+)(.*)$/

function cmdShimIfExists (from, to, cb) {
  fs.stat(from, function (er) {
    if (er) return cb()
    cmdShim(from, to, cb)
  })
}

function cmdShim (from, to, cb) {
  if (process.platform !== "win32") {
    return cb(new Error(".cmd shims only should be used on windows"))
  }

  chain
    ( [ [fs, "stat", from]
      , [rm, to + ".cmd"]
      , [rm, to]
      , [mkdir, path.dirname(to)]
      , [writeShim, from, to] ]
    , cb )
}

function writeShim (from, to, cb) {
  // make a cmd file and a sh script
  // First, check if the bin is a #! of some sort.
  // If not, then assume it's something that'll be compiled, or some other
  // sort of script, and just call it directly.
  fs.readFile(from, "utf8", function (er, data) {
    if (er) return writeShim_(from, to, null, null, cb)
    var firstLine = data.trim().split(/\r*\n/)[0]
      , shebang = firstLine.match(shebangExpr)
    if (!shebang) return writeShim_(from, to, null, null, cb)
    var prog = shebang[1]
      , args = shebang[2] || ""
    return writeShim_(from, to, prog, args, cb)
  })
}

function writeShim_ (from, to, prog, args, cb) {
  var shTarget = path.relative(path.dirname(to), from)
    , target = shTarget.split("/").join("\\")
    , longProg
    , shProg = prog && prog.split("\\").join("/")
    , shLongProg
  shTarget = shTarget.split("\\").join("/")
  args = args || ""
  if (!prog) {
    prog = "\"%~dp0\\" + target + "\""
    shProg = "\"$basedir/" + shTarget + "\""
    args = ""
    target = ""
    shTarget = ""
  } else {
    longProg = "\"%~dp0\\" + prog + ".exe\""
    shLongProg = "\"$basedir/" + prog + "\""
    target = "\"%~dp0\\" + target + "\""
    shTarget = "\"$basedir/" + shTarget + "\""
  }

  // @IF EXIST "%~dp0\node.exe" (
  //   "%~dp0\node.exe" "%~dp0\.\node_modules\npm\bin\npm-cli.js" %*
  // ) ELSE (
  //   node "%~dp0\.\node_modules\npm\bin\npm-cli.js" %*
  // )
  var cmd
  if (longProg) {
    cmd = "@IF EXIST " + longProg + " (\r\n"
        + "  " + longProg + " " + args + " " + target + " %*\r\n"
        + ") ELSE (\r\n"
        + "  " + prog + " " + args + " " + target + " %*\r\n"
        + ")"
  } else {
    cmd = prog + " " + args + " " + target + " %*\r\n"
  }

  cmd = ":: Created by npm, please don't edit manually.\r\n" + cmd

  // #!/bin/sh
  // basedir=`dirname "$0"`
  //
  // case `uname` in
  //     *CYGWIN*) basedir=`cygpath -w "$basedir"`;;
  // esac
  //
  // if [ -x "$basedir/node.exe" ]; then
  //   "$basedir/node.exe" "$basedir/node_modules/npm/bin/npm-cli.js" "$@"
  //   ret=$?
  // else
  //   node "$basedir/node_modules/npm/bin/npm-cli.js" "$@"
  //   ret=$?
  // fi
  // exit $ret

  var sh = "#!/bin/sh\n"

  if (shLongProg) {
    sh = sh
        + "basedir=`dirname \"$0\"`\n"
        + "\n"
        + "case `uname` in\n"
        + "    *CYGWIN*) basedir=`cygpath -w \"$basedir\"`;;\n"
        + "esac\n"
        + "\n"

    sh = sh
       + "if [ -x "+shLongProg+" ]; then\n"
       + "  " + shLongProg + " " + args + " " + shTarget + " \"$@\"\n"
       + "  ret=$?\n"
       + "else \n"
       + "  " + shProg + " " + args + " " + shTarget + " \"$@\"\n"
       + "  ret=$?\n"
       + "fi\n"
       + "exit $ret\n"
  } else {
    sh = shProg + " " + args + " " + shTarget + " \"$@\"\n"
       + "exit $?\n"
  }

  fs.writeFile(to + ".cmd", cmd, "utf8", function (er) {
    if (er) {
      log.warn("cmdShim", "Could not write "+to+".cmd")
      return cb(er)
    }
    fs.writeFile(to, sh, "utf8", function (er) {
      if (er) {
        log.warn("shShim", "Could not write "+to)
        return cb(er)
      }
      fs.chmod(to, 0755, cb)
    })
  })
}
<commit_msg>remove cmd-shim util<commit_after><|endoftext|>


<commit_before>var should = require('should');

function fnNotStrict() {
    return this.b;
}

function fnStrict() {
    'use strict';
    return this.b;
}

function d(succ){
    if(!succ){
        throw new TypeError();
    }
    return 'a';
}

describe('various this scenarios', function () {
    it('>> strict - throws exception', function () {
        should(fnStrict).throw(TypeError);
    });

    it('>> not strict', function () {
        should(fnNotStrict()).be.undefined();
    });
    it('simple thingy', function () {
        should(d(true)).equal('a');
    });

    it('simple thingy throws exception', function () {
        should(d.bind(null, false)).throw(Error);
    });

});
<commit_msg>renamed test file. improved test.<commit_after><|endoftext|>


<commit_before>(function() {

  var root = (typeof exports == 'undefined' ? window : exports);

  function RetinaImagePath(path) {
    this.path = path;
    this.at_2x_path = path.replace(/\.\w+$/, function(match) { return "@2x" + match; });
  }

  root.RetinaImagePath = RetinaImagePath;

  RetinaImagePath.confirmed_paths = [];

  RetinaImagePath.prototype.is_external = function() {
    return !!(this.path.match(/^https?\:/i) && !this.path.match('//' + document.domain) )
  }

  RetinaImagePath.prototype.check_2x_variant = function(callback) {
    var http, that = this;
    if (this.is_external()) {
      return callback(false);
    } else if (this.at_2x_path in RetinaImagePath.confirmed_paths) {
      return callback(true);
    } else {
      http = new XMLHttpRequest;
      http.open('HEAD', this.at_2x_path);
      http.onreadystatechange = function() {
        if (http.readyState != 4) {
          return callback(false);
        }

        if (http.status >= 200 && http.status <= 399) {
          RetinaImagePath.confirmed_paths.push(that.at_2x_path);
          return callback(true);
        } else {
          return callback(false);
        }
      }
      http.send();
    }
  }

  function RetinaImage(el) {
    this.el = el;
    this.path = new RetinaImagePath(this.el.getAttribute('src'));
    var that = this;
    this.path.check_2x_variant(function(hasVariant) {
      if (hasVariant) that.swap();
    });
  }

  root.RetinaImage = RetinaImage;

  RetinaImage.prototype.swap = function(path) {
    if (typeof path == 'undefined') path = this.path.at_2x_path;

    var that = this;
    function load() {
      if (! that.el.complete) {
        setTimeout(load, 5);
      } else {
        that.el.setAttribute('width', that.el.offsetWidth);
        that.el.setAttribute('height', that.el.offsetHeight);
        that.el.setAttribute('src', path);
      }
    }
    load();
  }

  if (root.devicePixelRatio > 1) {
    window.onload = function() {
      var images = document.getElementsByTagName("img"), retinaImages = [], i, image;
      for (i = 0; i < images.length; i++) {
        image = images[i];
        retinaImages.push(new RetinaImage(image));
      }
    }
  }

})();
<commit_msg>Save and call any existing window.onload handler<commit_after>(function() {

  var root = (typeof exports == 'undefined' ? window : exports);

  function RetinaImagePath(path) {
    this.path = path;
    this.at_2x_path = path.replace(/\.\w+$/, function(match) { return "@2x" + match; });
  }

  root.RetinaImagePath = RetinaImagePath;

  RetinaImagePath.confirmed_paths = [];

  RetinaImagePath.prototype.is_external = function() {
    return !!(this.path.match(/^https?\:/i) && !this.path.match('//' + document.domain) )
  }

  RetinaImagePath.prototype.check_2x_variant = function(callback) {
    var http, that = this;
    if (this.is_external()) {
      return callback(false);
    } else if (this.at_2x_path in RetinaImagePath.confirmed_paths) {
      return callback(true);
    } else {
      http = new XMLHttpRequest;
      http.open('HEAD', this.at_2x_path);
      http.onreadystatechange = function() {
        if (http.readyState != 4) {
          return callback(false);
        }

        if (http.status >= 200 && http.status <= 399) {
          RetinaImagePath.confirmed_paths.push(that.at_2x_path);
          return callback(true);
        } else {
          return callback(false);
        }
      }
      http.send();
    }
  }

  function RetinaImage(el) {
    this.el = el;
    this.path = new RetinaImagePath(this.el.getAttribute('src'));
    var that = this;
    this.path.check_2x_variant(function(hasVariant) {
      if (hasVariant) that.swap();
    });
  }

  root.RetinaImage = RetinaImage;

  RetinaImage.prototype.swap = function(path) {
    if (typeof path == 'undefined') path = this.path.at_2x_path;

    var that = this;
    function load() {
      if (! that.el.complete) {
        setTimeout(load, 5);
      } else {
        that.el.setAttribute('width', that.el.offsetWidth);
        that.el.setAttribute('height', that.el.offsetHeight);
        that.el.setAttribute('src', path);
      }
    }
    load();
  }

  if (root.devicePixelRatio > 1) {
    var existing_onload = window.onload || new Function;
    window.onload = function() {
      var images = document.getElementsByTagName("img"), retinaImages = [], i, image;
      for (i = 0; i < images.length; i++) {
        image = images[i];
        retinaImages.push(new RetinaImage(image));
      }
      existing_onload();
    }
  }

})();
<|endoftext|>


<commit_before>'use strict';
var angularMeteorCollections = angular.module('angular-meteor.collections', ['angular-meteor.subscribe']);

angularMeteorCollections.factory('$collection', ['$q', 'HashKeyCopier', '$subscribe',
  function ($q, HashKeyCopier, $subscribe) {
    return function (collection, selector, options) {
      if (!selector) selector = {};
      if (!(collection instanceof Meteor.Collection)) {
        throw new TypeError("The first argument of $collection must be a Meteor.Collection object.");
      }
      return {

        bindOne: function(scope, model, id, auto, publisher) {
          Tracker.autorun(function(self) {
            scope[model] = collection.findOne(id);
            if (!scope.$$phase) scope.$apply(); // Update bindings in scope.
            scope.$on('$destroy', function () {
              self.stop(); // Stop computation if scope is destroyed.
            });
          });

          if (auto) { // Deep watches the model and performs autobind.
            scope.$watch(model, function (newItem, oldItem) {
              if (newItem)
                if (newItem._id)
                  collection.update({_id: newItem._id}, { $set: _.omit(newItem, '_id') });
            }, true);
          }

          var deferred = $q.defer();

          if (publisher) {  // Subscribe to a publish method
            var publishName = null;
            if (publisher === true)
              publishName = collection._name;
            else
              publishName = publisher;

            $subscribe.subscribe(publishName).then(function(){
              deferred.resolve(scope[model]);
            });

          } else { // If no subscription, resolve immediately
            deferred.resolve(scope[model]);
          }

          return deferred.promise;
        },

        bind: function (scope, model, auto, publisher, paginate) {
          auto = auto || false; // Sets default binding type.
          if (!(typeof auto === 'boolean')) { // Checks if auto is a boolean.
            throw new TypeError("The third argument of bind must be a boolean.");
          }

          var unregisterWatch = null;

          var rebind = function(){
            Tracker.autorun(function (self) {

              if (paginate){
                options = {
                  limit: parseInt(scope.perPage),
                  skip: (parseInt(scope.page) - 1) * parseInt(scope.perPage)
                };
                if (scope.sort) { options.sort = [scope.sort]; }
              }

              var ngCollection = new AngularMeteorCollection(collection, $q, selector, options);

              // Bind collection to model in scope. Transfer $$hashKey based on _id.
              var newArray = HashKeyCopier.copyHashKeys(scope[model], ngCollection, ["_id"]);
              scope[model] = updateAngularCollection(newArray, scope[model]);

              if (!scope.$$phase) scope.$apply(); // Update bindings in scope.
              scope.$on('$destroy', function () {
                self.stop(); // Stop computation if scope is destroyed.
              });
            });

            if (auto) { // Deep watches the model and performs autobind.
              unregisterWatch = scope.$watch(model, function (newItems, oldItems) {
                // Remove items that don't exist in the collection anymore.
                angular.forEach(oldItems, function (oldItem) {
                  var index = newItems.map(function (item) {
                    return item._id;
                  }).indexOf(oldItem._id);
                  if (index == -1) { // To here get all objects that pushed or spliced
                    if (oldItem._id) { // This is a check to get only the spliced objects
                      newItems.remove(oldItem._id);
                    }
                  }
                });
                newItems.save(); // Saves all items.
              }, auto);
            }
          };
          rebind();

          if (paginate){
            scope.$watch("page", function(newValue, oldValue){
              if (!newValue)
                return;

              if (newValue == oldValue)
                return;

              if (unregisterWatch)
                unregisterWatch();

              rebind();
            });
          }

          var deferred = $q.defer();

          if (publisher) {  // Subscribe to a publish method
            var publishName = null;
            if (publisher === true)
              publishName = collection._name;
            else
              publishName = publisher;

            $subscribe.subscribe(publishName).then(function(){
              deferred.resolve(scope[model]);
            });

          } else { // If no subscription, resolve immediately
            deferred.resolve(scope[model]);
          }

          return deferred.promise;
        }
      };
    }
  }
]);

var AngularMeteorCollection = function (collection, $q, selector, options) {
  var self = collection.find(selector, options).fetch();

  self.__proto__ = AngularMeteorCollection.prototype;
  self.__proto__.$q = $q;
  self.$$collection = collection;

  return self;
};

AngularMeteorCollection.prototype = []; // Allows inheritance of native Array methods.

AngularMeteorCollection.prototype.save = function save(docs) {
  var self = this,
    collection = self.$$collection,
    $q = self.$q,
    promises = []; // To store all promises.

  /*
   * The upsertObject function will either update an object if the _id exists
   * or insert an object if the _id is not set in the collection.
   * Returns a promise.
   */
  function upsertObject(item, $q) {
    var deferred = $q.defer();

    item = angular.copy(item);
    delete item.$$hashKey;
    for (var property in item) {
      delete property.$$hashKey;
    }

    if (item._id) { // Performs an update if the _id property is set.
      var item_id = item._id; // Store the _id in temporary variable
      delete item._id; // Remove the _id property so that it can be $set using update.
      var objectId = (item_id._str) ? new Meteor.Collection.ObjectID(item_id._str) : item_id;
      collection.update(objectId, {$set: item}, function (error) {
        if (error) {
          deferred.reject(error);
        } else {
          deferred.resolve({_id: objectId, action: "updated"});
        }
      });
    } else { // Performs an insert if the _id property isn't set.
      collection.insert(item, function (error, result) {
        if (error) {
          deferred.reject(error);
        } else {
          deferred.resolve({_id: result, action: "inserted"});
        }
      });
    }

    return deferred.promise;
  }

  /*
   * How to update the collection depending on the 'docs' argument passed.
   */
  if (docs) { // Checks if a 'docs' argument was passed.
    if (angular.isArray(docs)) { // If an array of objects were passed.
      angular.forEach(docs, function (doc) {
        this.push(upsertObject(doc, $q));
      }, promises);
    } else { // If a single object was passed.
      promises.push(upsertObject(docs, $q));
    }
  } else { // If no 'docs' argument was passed, save the entire collection.
    angular.forEach(self, function (doc) {
      this.push(upsertObject(doc, $q));
    }, promises);
  }

  return $q.all(promises); // Returns all promises when they're resolved.
};

AngularMeteorCollection.prototype.remove = function remove(keys) {
  var self = this,
    collection = self.$$collection,
    $q = self.$q,
    promises = []; // To store all promises.

  /*
   * The removeObject function will delete an object with the _id property
   * equal to the specified key.
   * Returns a promise.
   */
  function removeObject(key, $q) {
    var deferred = $q.defer();

    if (key) { // Checks if 'key' argument is set.
      if(key._id) {
        key = key._id;
      }
      var objectId = (key._str) ? new Meteor.Collection.ObjectID(key._str) : key;
      collection.remove(objectId, function (error) {
        if (error) {
          deferred.reject(error);
        } else {
          deferred.resolve({_id: objectId, action: "removed"});
        }
      });
    } else {
      deferred.reject("key cannot be null");
    }

    return deferred.promise;
  }

  /*
   * What to remove from collection depending on the 'keys' argument passed.
   */
  if (keys) { // Checks if a 'keys' argument was passed.
    if (angular.isArray(keys)) { // If an array of keys were passed.
      angular.forEach(keys, function (key) {
        this.push(removeObject(key, $q));
      }, promises);
    } else { // If a single key was passed.
      promises.push(removeObject(keys, $q));
    }
  } else { // If no 'keys' argument was passed, save the entire collection.
    angular.forEach(self, function (doc) {
      this.push(removeObject(doc._id, $q));
    }, promises);
  }

  return $q.all(promises); // Returns all promises when they're resolved.
};

var updateAngularCollection = function (newArray, oldArray) {
  if (!newArray || !oldArray) return newArray;

  for (var i = 0; i < newArray.length; i++) {
    for (var j = 0; j < oldArray.length; j++) {
      if (angular.equals(newArray[i], oldArray[j])) {
        newArray[i] = oldArray[j];
        break;
      }
    }
  }

  return newArray;
};<commit_msg>fix phase check in isolated scopes<commit_after>'use strict';
var angularMeteorCollections = angular.module('angular-meteor.collections', ['angular-meteor.subscribe']);

angularMeteorCollections.factory('$collection', ['$q', 'HashKeyCopier', '$subscribe',
  function ($q, HashKeyCopier, $subscribe) {
    return function (collection, selector, options) {
      if (!selector) selector = {};
      if (!(collection instanceof Meteor.Collection)) {
        throw new TypeError("The first argument of $collection must be a Meteor.Collection object.");
      }
      return {

        bindOne: function(scope, model, id, auto, publisher) {
          Tracker.autorun(function(self) {
            scope[model] = collection.findOne(id);
            if (!scope.$root.$$phase) scope.$apply(); // Update bindings in scope.
            scope.$on('$destroy', function () {
              self.stop(); // Stop computation if scope is destroyed.
            });
          });

          if (auto) { // Deep watches the model and performs autobind.
            scope.$watch(model, function (newItem, oldItem) {
              if (newItem)
                if (newItem._id)
                  collection.update({_id: newItem._id}, { $set: _.omit(newItem, '_id') });
            }, true);
          }

          var deferred = $q.defer();

          if (publisher) {  // Subscribe to a publish method
            var publishName = null;
            if (publisher === true)
              publishName = collection._name;
            else
              publishName = publisher;

            $subscribe.subscribe(publishName).then(function(){
              deferred.resolve(scope[model]);
            });

          } else { // If no subscription, resolve immediately
            deferred.resolve(scope[model]);
          }

          return deferred.promise;
        },

        bind: function (scope, model, auto, publisher, paginate) {
          auto = auto || false; // Sets default binding type.
          if (!(typeof auto === 'boolean')) { // Checks if auto is a boolean.
            throw new TypeError("The third argument of bind must be a boolean.");
          }

          var unregisterWatch = null;

          var rebind = function(){
            Tracker.autorun(function (self) {

              if (paginate){
                options = {
                  limit: parseInt(scope.perPage),
                  skip: (parseInt(scope.page) - 1) * parseInt(scope.perPage)
                };
                if (scope.sort) { options.sort = [scope.sort]; }
              }

              var ngCollection = new AngularMeteorCollection(collection, $q, selector, options);

              // Bind collection to model in scope. Transfer $$hashKey based on _id.
              var newArray = HashKeyCopier.copyHashKeys(scope[model], ngCollection, ["_id"]);
              scope[model] = updateAngularCollection(newArray, scope[model]);

              if (!scope.$root.$$phase) scope.$apply(); // Update bindings in scope.
              scope.$on('$destroy', function () {
                self.stop(); // Stop computation if scope is destroyed.
              });
            });

            if (auto) { // Deep watches the model and performs autobind.
              unregisterWatch = scope.$watch(model, function (newItems, oldItems) {
                // Remove items that don't exist in the collection anymore.
                angular.forEach(oldItems, function (oldItem) {
                  var index = newItems.map(function (item) {
                    return item._id;
                  }).indexOf(oldItem._id);
                  if (index == -1) { // To here get all objects that pushed or spliced
                    if (oldItem._id) { // This is a check to get only the spliced objects
                      newItems.remove(oldItem._id);
                    }
                  }
                });
                newItems.save(); // Saves all items.
              }, auto);
            }
          };
          rebind();

          if (paginate){
            scope.$watch("page", function(newValue, oldValue){
              if (!newValue)
                return;

              if (newValue == oldValue)
                return;

              if (unregisterWatch)
                unregisterWatch();

              rebind();
            });
          }

          var deferred = $q.defer();

          if (publisher) {  // Subscribe to a publish method
            var publishName = null;
            if (publisher === true)
              publishName = collection._name;
            else
              publishName = publisher;

            $subscribe.subscribe(publishName).then(function(){
              deferred.resolve(scope[model]);
            });

          } else { // If no subscription, resolve immediately
            deferred.resolve(scope[model]);
          }

          return deferred.promise;
        }
      };
    }
  }
]);

var AngularMeteorCollection = function (collection, $q, selector, options) {
  var self = collection.find(selector, options).fetch();

  self.__proto__ = AngularMeteorCollection.prototype;
  self.__proto__.$q = $q;
  self.$$collection = collection;

  return self;
};

AngularMeteorCollection.prototype = []; // Allows inheritance of native Array methods.

AngularMeteorCollection.prototype.save = function save(docs) {
  var self = this,
    collection = self.$$collection,
    $q = self.$q,
    promises = []; // To store all promises.

  /*
   * The upsertObject function will either update an object if the _id exists
   * or insert an object if the _id is not set in the collection.
   * Returns a promise.
   */
  function upsertObject(item, $q) {
    var deferred = $q.defer();

    item = angular.copy(item);
    delete item.$$hashKey;
    for (var property in item) {
      delete property.$$hashKey;
    }

    if (item._id) { // Performs an update if the _id property is set.
      var item_id = item._id; // Store the _id in temporary variable
      delete item._id; // Remove the _id property so that it can be $set using update.
      var objectId = (item_id._str) ? new Meteor.Collection.ObjectID(item_id._str) : item_id;
      collection.update(objectId, {$set: item}, function (error) {
        if (error) {
          deferred.reject(error);
        } else {
          deferred.resolve({_id: objectId, action: "updated"});
        }
      });
    } else { // Performs an insert if the _id property isn't set.
      collection.insert(item, function (error, result) {
        if (error) {
          deferred.reject(error);
        } else {
          deferred.resolve({_id: result, action: "inserted"});
        }
      });
    }

    return deferred.promise;
  }

  /*
   * How to update the collection depending on the 'docs' argument passed.
   */
  if (docs) { // Checks if a 'docs' argument was passed.
    if (angular.isArray(docs)) { // If an array of objects were passed.
      angular.forEach(docs, function (doc) {
        this.push(upsertObject(doc, $q));
      }, promises);
    } else { // If a single object was passed.
      promises.push(upsertObject(docs, $q));
    }
  } else { // If no 'docs' argument was passed, save the entire collection.
    angular.forEach(self, function (doc) {
      this.push(upsertObject(doc, $q));
    }, promises);
  }

  return $q.all(promises); // Returns all promises when they're resolved.
};

AngularMeteorCollection.prototype.remove = function remove(keys) {
  var self = this,
    collection = self.$$collection,
    $q = self.$q,
    promises = []; // To store all promises.

  /*
   * The removeObject function will delete an object with the _id property
   * equal to the specified key.
   * Returns a promise.
   */
  function removeObject(key, $q) {
    var deferred = $q.defer();

    if (key) { // Checks if 'key' argument is set.
      if(key._id) {
        key = key._id;
      }
      var objectId = (key._str) ? new Meteor.Collection.ObjectID(key._str) : key;
      collection.remove(objectId, function (error) {
        if (error) {
          deferred.reject(error);
        } else {
          deferred.resolve({_id: objectId, action: "removed"});
        }
      });
    } else {
      deferred.reject("key cannot be null");
    }

    return deferred.promise;
  }

  /*
   * What to remove from collection depending on the 'keys' argument passed.
   */
  if (keys) { // Checks if a 'keys' argument was passed.
    if (angular.isArray(keys)) { // If an array of keys were passed.
      angular.forEach(keys, function (key) {
        this.push(removeObject(key, $q));
      }, promises);
    } else { // If a single key was passed.
      promises.push(removeObject(keys, $q));
    }
  } else { // If no 'keys' argument was passed, save the entire collection.
    angular.forEach(self, function (doc) {
      this.push(removeObject(doc._id, $q));
    }, promises);
  }

  return $q.all(promises); // Returns all promises when they're resolved.
};

var updateAngularCollection = function (newArray, oldArray) {
  if (!newArray || !oldArray) return newArray;

  for (var i = 0; i < newArray.length; i++) {
    for (var j = 0; j < oldArray.length; j++) {
      if (angular.equals(newArray[i], oldArray[j])) {
        newArray[i] = oldArray[j];
        break;
      }
    }
  }

  return newArray;
};<|endoftext|>


<commit_before>const React = require('react');
const Radium = require('radium');

const Spin = require('./Spin');

const StyleConstants = require('../constants/Style');

const Icon = require('../components/Icon');

const { buttonTypes } = require('../constants/App');

const Button = React.createClass({
  propTypes: {
    actionText: React.PropTypes.string,
    ariaLabel: React.PropTypes.string,
    icon: React.PropTypes.string,
    isActive: React.PropTypes.bool,
    onClick: React.PropTypes.func,
    primaryColor: React.PropTypes.string,
    style: React.PropTypes.object,
    type: React.PropTypes.oneOf(buttonTypes)
  },

  getDefaultProps () {
    return {
      onClick () {},
      isActive: false,
      primaryColor: StyleConstants.Colors.PRIMARY,
      type: 'primary'
    };
  },

  _isLargeOrMediumWindowSize () {
    const windowSize = StyleConstants.getWindowSize();

    return windowSize === 'medium' || windowSize === 'large';
  },

  render () {
    const styles = this.styles();

    return (

          {(this.props.icon && !this.props.isActive) ? <Icon size={20} style={styles.icon} type={this.props.icon} /> : null}
          {this.props.isActive ? (
            <Spin direction='counterclockwise'>
              <Icon size={20} type='spinner' />
            </Spin>
          ) : null }

            {this.props.isActive ? this.props.actionText : this.props.children}

    );
  },

  styles () {
    return {
      component: Object.assign({
        borderRadius: 2,
        borderStyle: 'solid',
        borderWidth: 1,
        borderColor: 'transparent',
        boxSizing: 'border-box',
        display: 'inline-block',
        padding: '4px 14px',
        fontSize: StyleConstants.FontSizes.MEDIUM,
        fontFamily: StyleConstants.Fonts.SEMIBOLD,
        cursor: this.props.type === 'disabled' ? 'default' : 'pointer',
        transition: 'all .2s ease-in',
        minWidth: 16,
        position: 'relative'
      }, this.props.style),
      children: {
        justifyContent: 'center',
        display: 'flex',
        alignItems: 'center',
        lineHeight: '20px'
      },
      primary: {
        backgroundColor: this.props.primaryColor,
        borderColor: this.props.primaryColor,
        color: StyleConstants.Colors.WHITE,
        fill: StyleConstants.Colors.WHITE,
        transition: 'all .2s ease-in',

        ':hover': !this._isLargeOrMediumWindowSize() ? null : {
          backgroundColor: StyleConstants.adjustColor(this.props.primaryColor, -15),
          borderColor: StyleConstants.adjustColor(this.props.primaryColor, -15),
          transition: 'all .2s ease-in'
        },
        ':active': {
          backgroundColor: StyleConstants.adjustColor(this.props.primaryColor, -30),
          borderColor: StyleConstants.adjustColor(this.props.primaryColor, -30),
          transition: 'all .2s ease-in'
        }
      },
      primaryOutline: {
        backgroundColor: 'transparent',
        borderColor: this.props.primaryColor,
        color: this.props.primaryColor,
        fill: this.props.primaryColor,
        transition: 'all .2s ease-in',

        ':hover': !this._isLargeOrMediumWindowSize() ? null : {
          backgroundColor: this.props.primaryColor,
          color: StyleConstants.Colors.WHITE,
          fill: StyleConstants.Colors.WHITE,
          transition: 'all .2s ease-in'
        },
        ':active': {
          backgroundColor: StyleConstants.adjustColor(this.props.primaryColor, -30),
          borderColor: StyleConstants.adjustColor(this.props.primaryColor, -30),
          color: StyleConstants.Colors.WHITE,
          fill: StyleConstants.Colors.WHITE,
          transition: 'all .2s ease-in'
        }
      },
      primaryInverse: {
        backgroundColor: StyleConstants.Colors.WHITE,
        borderColor: StyleConstants.Colors.WHITE,
        color: this.props.primaryColor,
        fill: this.props.primaryColor,
        transition: 'all .2s ease-in',

        ':hover': !this._isLargeOrMediumWindowSize() ? null : {
          backgroundColor: StyleConstants.adjustColor(StyleConstants.Colors.WHITE, -15),
          borderColor: StyleConstants.adjustColor(StyleConstants.Colors.WHITE, -15),
          transition: 'all .2s ease-in'
        },
        ':active': {
          backgroundColor: StyleConstants.adjustColor(StyleConstants.Colors.WHITE, -30),
          borderColor: StyleConstants.adjustColor(StyleConstants.Colors.WHITE, -30),
          transition: 'all .2s ease-in'
        }
      },
      secondary: {
        backgroundColor: 'transparent',
        borderColor: StyleConstants.Colors.ASH,
        color: StyleConstants.Colors.ASH,
        fill: StyleConstants.Colors.ASH,
        transition: 'all .2s ease-in',
        ':hover': !this._isLargeOrMediumWindowSize() ? null : {
          backgroundColor: StyleConstants.Colors.ASH,
          borderColor: StyleConstants.Colors.ASH,
          color: StyleConstants.Colors.WHITE,
          fill: StyleConstants.Colors.WHITE,
          transition: 'all .2s ease-in'
        },
        ':active': {
          backgroundColor: StyleConstants.adjustColor(StyleConstants.Colors.ASH, -30),
          borderColor: StyleConstants.adjustColor(StyleConstants.Colors.ASH, -30),
          color: StyleConstants.Colors.WHITE,
          fill: StyleConstants.Colors.WHITE,
          transition: 'all .2s ease-in'
        }
      },
      base: {
        backgroundColor: 'transparent',
        color: this.props.primaryColor,
        fill: this.props.primaryColor,
        transition: 'all .2s ease-in',
        borderColor: 'transparent',
        borderRadius: 2,
        borderWidth: 1,
        ':hover': !this._isLargeOrMediumWindowSize() ? null : {
          color: StyleConstants.adjustColor(this.props.primaryColor, -8),
          fill: StyleConstants.adjustColor(this.props.primaryColor, -8),
          transition: 'all .2s ease-in',
          borderColor: StyleConstants.Colors.FOG
        },
        ':active': {
          color: StyleConstants.adjustColor(this.props.primaryColor, -16),
          fill: StyleConstants.adjustColor(this.props.primaryColor, -16),
          transition: 'all .2s ease-in',
          backgroundColor: StyleConstants.Colors.PORCELAIN
        }
      },
      neutral: {
        backgroundColor: 'transparent',
        borderColor: StyleConstants.Colors.FOG,
        borderRadius: 2,
        borderWidth: 1,
        color: this.props.primaryColor,
        fill: this.props.primaryColor,
        ':hover': !this._isLargeOrMediumWindowSize() ? null : {
          backgroundColor: StyleConstants.Colors.PORCELAIN
        },
        ':active': {
          backgroundColor: StyleConstants.adjustColor(StyleConstants.Colors.PORCELAIN, -15)
        }
      },
      disabled: {
        backgroundColor: 'transparent',
        borderColor: StyleConstants.Colors.FOG,
        color: StyleConstants.Colors.FOG,
        fill: StyleConstants.Colors.FOG
      },
      icon: {
        marginLeft: this.props.children ? -4 : 0,
        marginRight: this.props.children ? 5 : 0
      },
      buttonText: {
        marginLeft: (this.props.isActive && this.props.actionText) ? 10 : 0
      }
    };
  }
});

module.exports = Radium(Button);
<commit_msg>Turns div into native html button element<commit_after>const React = require('react');
const Radium = require('radium');

const Spin = require('./Spin');

const StyleConstants = require('../constants/Style');

const Icon = require('../components/Icon');

const { buttonTypes } = require('../constants/App');

const Button = React.createClass({
  propTypes: {
    actionText: React.PropTypes.string,
    ariaLabel: React.PropTypes.string,
    icon: React.PropTypes.string,
    isActive: React.PropTypes.bool,
    onClick: React.PropTypes.func,
    primaryColor: React.PropTypes.string,
    style: React.PropTypes.object,
    type: React.PropTypes.oneOf(buttonTypes)
  },

  getDefaultProps () {
    return {
      onClick () {},
      isActive: false,
      primaryColor: StyleConstants.Colors.PRIMARY,
      type: 'primary'
    };
  },

  _isLargeOrMediumWindowSize () {
    const windowSize = StyleConstants.getWindowSize();

    return windowSize === 'medium' || windowSize === 'large';
  },

  render () {
    const styles = this.styles();

    return (
      <button
        aria-label={this.props.ariaLabel}
        onClick={this.props.type === 'disabled' ? null : this.props.onClick}
        role='button'
        style={Object.assign({}, styles.component, styles[this.props.type], this.props.style)}
      >

          {(this.props.icon && !this.props.isActive) ? <Icon size={20} style={styles.icon} type={this.props.icon} /> : null}
          {this.props.isActive ? (
            <Spin direction='counterclockwise'>
              <Icon size={20} type='spinner' />
            </Spin>
          ) : null }

            {this.props.isActive ? this.props.actionText : this.props.children}

      </button>
    );
  },

  styles () {
    return {
      component: Object.assign({
        borderRadius: 2,
        borderStyle: 'solid',
        borderWidth: 1,
        borderColor: 'transparent',
        boxSizing: 'border-box',
        display: 'inline-block',
        padding: '4px 14px',
        fontSize: StyleConstants.FontSizes.MEDIUM,
        fontFamily: StyleConstants.Fonts.SEMIBOLD,
        cursor: this.props.type === 'disabled' ? 'default' : 'pointer',
        transition: 'all .2s ease-in',
        minWidth: 16,
        position: 'relative'
      }, this.props.style),
      children: {
        justifyContent: 'center',
        display: 'flex',
        alignItems: 'center',
        lineHeight: '20px'
      },
      primary: {
        backgroundColor: this.props.primaryColor,
        borderColor: this.props.primaryColor,
        color: StyleConstants.Colors.WHITE,
        fill: StyleConstants.Colors.WHITE,
        transition: 'all .2s ease-in',

        ':hover': !this._isLargeOrMediumWindowSize() ? null : {
          backgroundColor: StyleConstants.adjustColor(this.props.primaryColor, -15),
          borderColor: StyleConstants.adjustColor(this.props.primaryColor, -15),
          transition: 'all .2s ease-in'
        },
        ':active': {
          backgroundColor: StyleConstants.adjustColor(this.props.primaryColor, -30),
          borderColor: StyleConstants.adjustColor(this.props.primaryColor, -30),
          transition: 'all .2s ease-in'
        }
      },
      primaryOutline: {
        backgroundColor: 'transparent',
        borderColor: this.props.primaryColor,
        color: this.props.primaryColor,
        fill: this.props.primaryColor,
        transition: 'all .2s ease-in',

        ':hover': !this._isLargeOrMediumWindowSize() ? null : {
          backgroundColor: this.props.primaryColor,
          color: StyleConstants.Colors.WHITE,
          fill: StyleConstants.Colors.WHITE,
          transition: 'all .2s ease-in'
        },
        ':active': {
          backgroundColor: StyleConstants.adjustColor(this.props.primaryColor, -30),
          borderColor: StyleConstants.adjustColor(this.props.primaryColor, -30),
          color: StyleConstants.Colors.WHITE,
          fill: StyleConstants.Colors.WHITE,
          transition: 'all .2s ease-in'
        }
      },
      primaryInverse: {
        backgroundColor: StyleConstants.Colors.WHITE,
        borderColor: StyleConstants.Colors.WHITE,
        color: this.props.primaryColor,
        fill: this.props.primaryColor,
        transition: 'all .2s ease-in',

        ':hover': !this._isLargeOrMediumWindowSize() ? null : {
          backgroundColor: StyleConstants.adjustColor(StyleConstants.Colors.WHITE, -15),
          borderColor: StyleConstants.adjustColor(StyleConstants.Colors.WHITE, -15),
          transition: 'all .2s ease-in'
        },
        ':active': {
          backgroundColor: StyleConstants.adjustColor(StyleConstants.Colors.WHITE, -30),
          borderColor: StyleConstants.adjustColor(StyleConstants.Colors.WHITE, -30),
          transition: 'all .2s ease-in'
        }
      },
      secondary: {
        backgroundColor: 'transparent',
        borderColor: StyleConstants.Colors.ASH,
        color: StyleConstants.Colors.ASH,
        fill: StyleConstants.Colors.ASH,
        transition: 'all .2s ease-in',
        ':hover': !this._isLargeOrMediumWindowSize() ? null : {
          backgroundColor: StyleConstants.Colors.ASH,
          borderColor: StyleConstants.Colors.ASH,
          color: StyleConstants.Colors.WHITE,
          fill: StyleConstants.Colors.WHITE,
          transition: 'all .2s ease-in'
        },
        ':active': {
          backgroundColor: StyleConstants.adjustColor(StyleConstants.Colors.ASH, -30),
          borderColor: StyleConstants.adjustColor(StyleConstants.Colors.ASH, -30),
          color: StyleConstants.Colors.WHITE,
          fill: StyleConstants.Colors.WHITE,
          transition: 'all .2s ease-in'
        }
      },
      base: {
        backgroundColor: 'transparent',
        color: this.props.primaryColor,
        fill: this.props.primaryColor,
        transition: 'all .2s ease-in',
        borderColor: 'transparent',
        borderRadius: 2,
        borderWidth: 1,
        ':hover': !this._isLargeOrMediumWindowSize() ? null : {
          color: StyleConstants.adjustColor(this.props.primaryColor, -8),
          fill: StyleConstants.adjustColor(this.props.primaryColor, -8),
          transition: 'all .2s ease-in',
          borderColor: StyleConstants.Colors.FOG
        },
        ':active': {
          color: StyleConstants.adjustColor(this.props.primaryColor, -16),
          fill: StyleConstants.adjustColor(this.props.primaryColor, -16),
          transition: 'all .2s ease-in',
          backgroundColor: StyleConstants.Colors.PORCELAIN
        }
      },
      neutral: {
        backgroundColor: 'transparent',
        borderColor: StyleConstants.Colors.FOG,
        borderRadius: 2,
        borderWidth: 1,
        color: this.props.primaryColor,
        fill: this.props.primaryColor,
        ':hover': !this._isLargeOrMediumWindowSize() ? null : {
          backgroundColor: StyleConstants.Colors.PORCELAIN
        },
        ':active': {
          backgroundColor: StyleConstants.adjustColor(StyleConstants.Colors.PORCELAIN, -15)
        }
      },
      disabled: {
        backgroundColor: 'transparent',
        borderColor: StyleConstants.Colors.FOG,
        color: StyleConstants.Colors.FOG,
        fill: StyleConstants.Colors.FOG
      },
      icon: {
        marginLeft: this.props.children ? -4 : 0,
        marginRight: this.props.children ? 5 : 0
      },
      buttonText: {
        marginLeft: (this.props.isActive && this.props.actionText) ? 10 : 0
      }
    };
  }
});

module.exports = Radium(Button);
<|endoftext|>


<commit_before>/* eslint-env jest */
/* global device */

import { init, cleanup } from 'detox'
import { getEnv } from 'jest-jasmine2'
import { detox as config } from '../package.json'
import adapter, { beforeEach as _beforeEach, afterAll as _afterAll } from 'detox/runners/jest/adapter'

jest.setTimeout(120000)

beforeAll(async () => {
	await init(config, {launchApp: false})
	getEnv().addReporter(adapter)
})

beforeEach(async () => {
	await _beforeEach()
	await device.relaunchApp({delete: true})
})

afterAll(async () => {
	await _afterAll()
	await cleanup()
})
<commit_msg>rename beforeEach/afterEach imported symbols<commit_after>/* eslint-env jest */
/* global device */

import { init, cleanup } from 'detox'
import { getEnv } from 'jest-jasmine2'
import { detox as config } from '../package.json'
import adapter, { beforeEach as beforeEachDetox, afterAll as afterAllDetox } from 'detox/runners/jest/adapter'

jest.setTimeout(120000)

beforeAll(async () => {
	await init(config, {launchApp: false})
	getEnv().addReporter(adapter)
})

beforeEach(async () => {
	await beforeEachDetox()
	await device.relaunchApp({delete: true})
})

afterAll(async () => {
	await afterAllDetox()
	await cleanup()
})
<|endoftext|>


<commit_before>var {computed, when, h, throttle} = require('mutant')
var nest = require('depnest')

exports.gives = nest('app.html.progressNotifier')

exports.needs = nest({
  'progress.html.render': 'first',
  'progress.obs.global': 'first',
  'progress.obs.query': 'first'
})

exports.create = function (api) {
  return nest('app.html.progressNotifier', function (id) {
    var progress = api.progress.obs.global()
    var queryProgress = api.progress.obs.query()

    var maxQueryPending = 0

    var indexProgress = computed([queryProgress.pending], (pending) => {
      if (pending === 0 || pending > maxQueryPending) {
        maxQueryPending = pending
      }
      if (pending === 0) {
        return 1
      } else {
        return (maxQueryPending - pending) / maxQueryPending
      }
    })

    var downloadProgress = computed([progress.feeds, progress.incomplete], (feeds, incomplete) => {
      if (feeds) {
        return clamp((incomplete - feeds) / feeds)
      } else {
        return 1
      }
    })

    var hidden = computed([progress.incomplete, progress.feeds, queryProgress.pending], (incomplete, feeds, indexing) => {
      return incomplete <= 5 && !indexing && feeds
    })

    var hasDownloadProgress = computed([progress.feeds, progress.incomplete], (feeds, incomplete) => {
      if (feeds) {
        return incomplete > 5
      }
    })

    return h('div.info', { hidden: throttle(hidden, 5000) }, [
      h('div.status', [
        h('Loading -small', [
          when(hasDownloadProgress,
            ['Downloading new messages', h('progress', { style: {'margin-left': '10px'}, min: 0, max: 1, value: downloadProgress })],
            when(queryProgress.pending, [
              ['Indexing database', h('progress', { style: {'margin-left': '10px'}, min: 0, max: 1, value: indexProgress })]
            ], 'Checking for changes...')
          )
        ])
      ])
    ])
  })
}

function clamp (value) {
  return Math.min(1, Math.max(0, value)) || 0
}
<commit_msg>increase threshold for loading message to appear<commit_after>var {computed, when, h, throttle} = require('mutant')
var nest = require('depnest')

exports.gives = nest('app.html.progressNotifier')

exports.needs = nest({
  'progress.html.render': 'first',
  'progress.obs.global': 'first',
  'progress.obs.query': 'first'
})

exports.create = function (api) {
  return nest('app.html.progressNotifier', function (id) {
    var progress = api.progress.obs.global()
    var queryProgress = api.progress.obs.query()

    var maxQueryPending = 0

    var indexProgress = computed([queryProgress.pending], (pending) => {
      if (pending === 0 || pending > maxQueryPending) {
        maxQueryPending = pending
      }
      if (pending === 0) {
        return 1
      } else {
        return (maxQueryPending - pending) / maxQueryPending
      }
    })

    var downloadProgress = computed([progress.feeds, progress.incomplete], (feeds, incomplete) => {
      if (feeds) {
        return clamp((incomplete - feeds) / feeds)
      } else {
        return 1
      }
    })

    var hidden = computed([progress.incomplete, progress.feeds, queryProgress.pending], (incomplete, feeds, indexing) => {
      return incomplete <= 10 && indexing <= 10 && feeds
    })

    var hasDownloadProgress = computed([progress.feeds, progress.incomplete], (feeds, incomplete) => {
      if (feeds) {
        return incomplete > 10
      }
    })

    return h('div.info', { hidden: throttle(hidden, 5000) }, [
      h('div.status', [
        h('Loading -small', [
          when(hasDownloadProgress,
            ['Downloading new messages', h('progress', { style: {'margin-left': '10px'}, min: 0, max: 1, value: downloadProgress })],
            when(queryProgress.pending, [
              ['Indexing database', h('progress', { style: {'margin-left': '10px'}, min: 0, max: 1, value: indexProgress })]
            ], 'Checking for changes...')
          )
        ])
      ])
    ])
  })
}

function clamp (value) {
  return Math.min(1, Math.max(0, value)) || 0
}
<|endoftext|>


<commit_before>import React from 'react';

export default function Cursor(props) {
  return (

  );
}
<commit_msg>add blinking cursor<commit_after>import React from 'react';

const styles = {
  root: {
    position: 'absolute',
    display: 'inline-block',
  },
  verticalLine: {
    position: 'absolute',
    width: '0',
    borderLeft: '2px solid red',
    marginLeft: '1px'
  },
  marker: {
    width: '4px',
    height: '4px',
    background: 'red'
  }
}

class Cursor extends React.Component {
  state = {
    visible: true,
  };

  constructor(props) {
    super(props);
    this._startBlinking();
  }

  componentWillUnmount() {
    this._stopBlinking();
  }

  _startBlinking() {
    this.blinkInterval = setInterval(::this._toggle, 750);
  }

  _stopBlinking() {
    clearInterval(this.blinkInterval);
  }

  _toggle() {
    this.setState(state => {
      const { visible, ...rest } = state;
      return {
        visible: !visible,
        ...rest,
      }
    })
  }

  render() {
    const { visible } = this.state;
    return (

    );
  }
}

export default Cursor;
<|endoftext|>


<commit_before>const React = require('react');
const Velocity = require('velocity-animate');

const StyleConstants = require('../constants/Style');

const Icon = require('../components/Icon');

const Drawer = React.createClass({
  propTypes: {
    duration: React.PropTypes.number,
    easing: React.PropTypes.array,
    isOpen: React.PropTypes.bool,
    onClose: React.PropTypes.func.isRequired,
    siblingContent: React.PropTypes.shape({
      currentSiblingIndex: React.PropTypes.number.isRequired,
      nextSibling: React.PropTypes.func.isRequired,
      previousSibling: React.PropTypes.func.isRequired,
      totalSiblings: React.PropTypes.number.isRequired
    })
  },

  getDefaultProps () {
    return {
      duration: 500,
      isOpen: false,
      easing: [0.28, 0.14, 0.34, 1.04]
    };
  },

  componentDidMount () {
    this._renderTransition(this.props.isOpen);
  },

  componentWillReceiveProps (newProps) {
    if (newProps.isOpen !== this.props.isOpen) {
      this._renderTransition(newProps.isOpen);
    }
  },

  _renderSiblingContent () {
    const styles = this.styles();

    return (

 (this._siblingContent = ref)} style={styles.siblingContent}>
        <Icon onClick={this.props.siblingContent.previousSibling} size={25} style={styles.icon} type='caret-left'/>
        {this.props.siblingContent.currentSiblingIndex} of {this.props.siblingContent.totalSiblings}
        <Icon onClick={this.props.siblingContent.nextSibling} size={25} style={styles.icon} type='caret-right'/>

    );
  },

  _renderTransition (isOpen) {
    const el = this._component;
    const transition = isOpen ? { right: -800 } : { right: 0 };
    const options = {
      complete: this._slideArrowAndSiblingContent.bind(this, isOpen),
      duration: this.props.duration,
      easing: this.props.easing
    };

    Velocity(el, transition, options);
  },

  _slideArrowAndSiblingContent (isOpen) {
    this._slideArrow(isOpen);
    this._slideSiblingContent(isOpen);
  },

  _slideArrow (isOpen) {
    const el = this._arrow;
    const transition = isOpen ? { left: -25 } : { left: 25 };
    const options = {
      duration: 200,
      easing: this.props.easing
    };

    Velocity(el, transition, options);
  },

  _slideSiblingContent (isOpen) {
    const el = this._siblingContent;
    const transition = isOpen ? { top: -25 } : { top: 12 };
    const options = {
      duration: 200,
      easing: this.props.easing
    };

    Velocity(el, transition, options);
  },

  render () {
    const styles = this.styles();

    return (

 (this._component = ref)} style={styles.component}>

           (this._arrow = ref)} style={styles.iconContainer}>
            <Icon onClick={this.props.onClose} size={25} style={styles.icon}type='arrow-left'/>

          {this.props.siblingContent ? this._renderSiblingContent() : null}

          {this.props.children}

    );
  },

  styles () {
    return {
      component: {
        top: 0,
        bottom: 0,
        right: -800,
        position: 'absolute',
        width: 800,
        overflow: 'hidden',
        backgroundColor: StyleConstants.Colors.PORCELAIN
      },
      icon: {
        color: StyleConstants.Colors.ASH
      },
      iconContainer: {
        position: 'absolute',
        left: -25,
        top: 12
      },
      nav: {
        backgroundColor: StyleConstants.Colors.PORCELAIN,
        borderBottom: 'solid 1px ' + StyleConstants.Colors.ASH,
        height: 15,
        padding: '15px 25px'
      },
      siblingContent: {
        fontFamily: StyleConstants.Fonts.THIN,
        color: StyleConstants.Colors.ASH,
        position: 'absolute',
        right: 25,
        top: -25
      }
    };
  }

});

module.exports = Drawer;
<commit_msg>Reshaping siblingContent to navContent<commit_after>const React = require('react');
const Velocity = require('velocity-animate');

const StyleConstants = require('../constants/Style');

const Icon = require('../components/Icon');

const Drawer = React.createClass({
  propTypes: {
    duration: React.PropTypes.number,
    easing: React.PropTypes.array,
    isOpen: React.PropTypes.bool,
    navContent: React.PropTypes.shape({
      label: React.PropTypes.string.isRequired,
      onNextClick: React.PropTypes.func.isRequired,
      onPreviousClick: React.PropTypes.func.isRequired
    }),
    onClose: React.PropTypes.func.isRequired
  },

  getDefaultProps () {
    return {
      duration: 500,
      isOpen: false,
      easing: [0.28, 0.14, 0.34, 1.04]
    };
  },

  componentDidMount () {
    this._renderTransition(this.props.isOpen);
  },

  componentWillReceiveProps (newProps) {
    if (newProps.isOpen !== this.props.isOpen) {
      this._renderTransition(newProps.isOpen);
    }
  },

  _renderNavContent () {
    const styles = this.styles();

    return (

 (this._navContent = ref)} style={styles.navContent}>
        <Icon onClick={this.props.navContent.onPreviousClick} size={25} style={styles.icon} type='caret-left'/>
        {this.props.navContent.label}
        <Icon onClick={this.props.navContent.onNextClick} size={25} style={styles.icon} type='caret-right'/>

    );
  },

  _renderTransition (isOpen) {
    const el = this._component;
    const transition = isOpen ? { right: -800 } : { right: 0 };
    const options = {
      complete: this._doNavAnimation.bind(this, isOpen),
      duration: this.props.duration,
      easing: this.props.easing
    };

    Velocity(el, transition, options);
  },

  _doNavAnimation (isOpen) {
    this._slideArrow(isOpen);
    this._slideNavContent(isOpen);
  },

  _slideArrow (isOpen) {
    const el = this._arrow;
    const transition = isOpen ? { left: -25 } : { left: 25 };
    const options = {
      duration: 200,
      easing: this.props.easing
    };

    Velocity(el, transition, options);
  },

  _slideNavContent (isOpen) {
    const el = this._navContent;
    const transition = isOpen ? { top: -25 } : { top: 12 };
    const options = {
      duration: 200,
      easing: this.props.easing
    };

    Velocity(el, transition, options);
  },

  render () {
    const styles = this.styles();

    return (

 (this._component = ref)} style={styles.component}>

           (this._arrow = ref)} style={styles.iconContainer}>
            <Icon onClick={this.props.onClose} size={25} style={styles.icon}type='arrow-left'/>

          {this.props.navContent ? this._renderNavContent() : null}

          {this.props.children}

    );
  },

  styles () {
    return {
      component: {
        top: 0,
        bottom: 0,
        right: -800,
        position: 'absolute',
        width: 800,
        overflow: 'hidden',
        backgroundColor: StyleConstants.Colors.PORCELAIN
      },
      icon: {
        color: StyleConstants.Colors.ASH
      },
      iconContainer: {
        position: 'absolute',
        left: -25,
        top: 12
      },
      nav: {
        backgroundColor: StyleConstants.Colors.PORCELAIN,
        borderBottom: 'solid 1px ' + StyleConstants.Colors.ASH,
        height: 15,
        padding: '15px 25px'
      },
      navContent: {
        fontFamily: StyleConstants.Fonts.THIN,
        color: StyleConstants.Colors.ASH,
        position: 'absolute',
        right: 25,
        top: -25
      }
    };
  }

});

module.exports = Drawer;
<|endoftext|>


<commit_before><commit_msg>give context to extenstions<commit_after><|endoftext|>


<commit_before>import React from 'react'
import propTypes from 'prop-types'

import AccountMerge from './operations/AccountMerge'
import AllowTrust from './operations/AllowTrust'
import ChangeTrust from './operations/ChangeTrust'
import CreateAccount from './operations/CreateAccount'
import Inflation from './operations/Inflation'
import ManageData from './operations/ManageData'
import Offer from './operations/Offer'
import PathPayment from './operations/PathPayment'
import Payment from './operations/Payment'
import SetOptions from './operations/SetOptions'

import AccountLink from './shared/AccountLink'
import Asset from './shared/Asset'
import JSONButton from './shared/JSONButton'
import TimeSynchronisedFormattedRelative from './shared/TimeSynchronizedFormattedRelative'
import TransactionHash from './shared/TransactionHash'

// operations
// account_merge: AccountMerge,
// allow_trust: AllowTrust,
// change_trust: ChangeTrust,
// create_account: CreateAccount,
// create_passive_offer: Offer,
// inflation: Inflation,
// manage_data: ManageData,
// manage_offer: Offer,
// path_payment: PathPayment,
// payment: Payment,
// set_options: SetOptions,

const Amount = ({amount, assetType, assetCode, assetIssuer}) => (

    {amount} <Asset code={assetCode} type={assetType} issuer={assetIssuer} />

)

const effectTypeComponentMap = {
  account_created: Amount,
  account_removed: Amount,
  account_credited: Amount,
  account_debited: Amount,
  // account_thresholds_updated: Something,
  // account_home_domain_updated: Something,
  // account_flags_updated: Something,
  // signer_created: Something,
  // signer_removed: Something,
  // signer_updated: Something,
  // trustline_created: Something,
  // trustline_removed: Something,
  // trustline_updated: Something,
  // trustline_authorized: Something,
  // trustline_deauthorized: Something,
  offer_created: Offer,
  offer_removed: Offer,
  offer_updated: Offer,
  // trade: Something,
  // data_created: Something,
  // data_removed: Something,
  // data_updated: Something,
}

const EffectDetails = ({effect}) => {
  const SubEffectComponent = effectTypeComponentMap[effect.type]
  if (!SubEffectComponent) return {effect.type}
  return <SubEffectComponent {...effect} />
}

class Effect extends React.Component {
  state = {tx: null}

  componentDidMount() {
    this.props.effect
      .operation()
      .then(eff => eff.transaction())
      .then(tx => this.setState({tx: tx}))
  }

  render() {
    const {effect, effectURLFn, showAccount = true} = this.props

    const opLink = effect.links.operation.href
    const opId = opLink.substring(opLink.lastIndexOf('/') + 1)

    return (

        {showAccount && (

            <AccountLink account={effect.account} />

        )}
        {effect.type}

          <EffectDetails effect={effect} />

          {this.state.tx != null && (
            <TransactionHash hash={this.state.tx.hash} compact={true} />
          )}

          {this.state.tx != null && (
            <TimeSynchronisedFormattedRelative
              initialNow={this.props.parentRenderTimestamp}
              value={this.state.tx.created_at}
            />
          )}

          <JSONButton url={effectURLFn(opId)} />

    )
  }
}

Effect.propTypes = {
  effect: propTypes.shape({
    id: propTypes.string.isRequired,
    links: propTypes.object.isRequired,
    account: propTypes.string.isRequired,
    type: propTypes.string.isRequired,
  }).isRequired,
  effectURLFn: propTypes.func.isRequired,
  parentRenderTimestamp: propTypes.number,
}

export default Effect
<commit_msg>#50 further optimisation - only one call required to get the tx details for each effect<commit_after>import React from 'react'
import propTypes from 'prop-types'

import AccountMerge from './operations/AccountMerge'
import AllowTrust from './operations/AllowTrust'
import ChangeTrust from './operations/ChangeTrust'
import CreateAccount from './operations/CreateAccount'
import Inflation from './operations/Inflation'
import ManageData from './operations/ManageData'
import Offer from './operations/Offer'
import PathPayment from './operations/PathPayment'
import Payment from './operations/Payment'
import SetOptions from './operations/SetOptions'

import AccountLink from './shared/AccountLink'
import Asset from './shared/Asset'
import JSONButton from './shared/JSONButton'
import TimeSynchronisedFormattedRelative from './shared/TimeSynchronizedFormattedRelative'
import TransactionHash from './shared/TransactionHash'

// operations
// account_merge: AccountMerge,
// allow_trust: AllowTrust,
// change_trust: ChangeTrust,
// create_account: CreateAccount,
// create_passive_offer: Offer,
// inflation: Inflation,
// manage_data: ManageData,
// manage_offer: Offer,
// path_payment: PathPayment,
// payment: Payment,
// set_options: SetOptions,

const Amount = ({amount, assetType, assetCode, assetIssuer}) => (

    {amount} <Asset code={assetCode} type={assetType} issuer={assetIssuer} />

)

const effectTypeComponentMap = {
  account_created: Amount,
  account_removed: Amount,
  account_credited: Amount,
  account_debited: Amount,
  // account_thresholds_updated: Something,
  // account_home_domain_updated: Something,
  // account_flags_updated: Something,
  // signer_created: Something,
  // signer_removed: Something,
  // signer_updated: Something,
  // trustline_created: Something,
  // trustline_removed: Something,
  // trustline_updated: Something,
  // trustline_authorized: Something,
  // trustline_deauthorized: Something,
  offer_created: Offer,
  offer_removed: Offer,
  offer_updated: Offer,
  // trade: Something,
  // data_created: Something,
  // data_removed: Something,
  // data_updated: Something,
}

const EffectDetails = ({effect}) => {
  const SubEffectComponent = effectTypeComponentMap[effect.type]
  if (!SubEffectComponent) return {effect.type}
  return <SubEffectComponent {...effect} />
}

class Effect extends React.Component {
  state = {tx: null}

  componentDidMount() {
    this.props.effect
      .operation()
      .then(op => this.setState({tx: op.transaction_hash, time: op.created_at}))
  }

  render() {
    const {effect, effectURLFn, showAccount = true} = this.props

    const opLink = effect.links.operation.href
    const opId = opLink.substring(opLink.lastIndexOf('/') + 1)

    return (

        {showAccount && (

            <AccountLink account={effect.account} />

        )}
        {effect.type}

          <EffectDetails effect={effect} />

          {this.state.tx != null && (
            <TransactionHash hash={this.state.tx} compact={true} />
          )}

          {this.state.tx != null && (
            <TimeSynchronisedFormattedRelative
              initialNow={this.props.parentRenderTimestamp}
              value={this.state.time}
            />
          )}

          <JSONButton url={effectURLFn(opId)} />

    )
  }
}

Effect.propTypes = {
  effect: propTypes.shape({
    id: propTypes.string.isRequired,
    links: propTypes.object.isRequired,
    account: propTypes.string.isRequired,
    type: propTypes.string.isRequired,
  }).isRequired,
  effectURLFn: propTypes.func.isRequired,
  parentRenderTimestamp: propTypes.number,
}

export default Effect
<|endoftext|>