<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 ctx = {
        ctx: this.ctx,
        output: this.output,
        generator: this.output.name
    };

    return _.bind(func, ctx);
};

// Interpolate a string content to replace shortcuts according to the filetype
TemplateEngine.prototype.interpolate = function(filepath, source) {
    var parser = parsers.get(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>Add book to templating context<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);
}

// Bind a function to a context
// Filters and blocks are binded to this context
TemplateEngine.prototype.bindContext = function(func) {
    var ctx = {
        ctx: this.ctx,
        book: this.book,
        output: this.output
    };
    error.deprecateField(ctx, 'generator', this.output.name, '"generator" property is deprecated, use "output.generator" instead');

    return _.bind(func, ctx);
};

// Interpolate a string content to replace shortcuts according to the filetype
TemplateEngine.prototype.interpolate = function(filepath, source) {
    var parser = parsers.get(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>/*
 * benc2json
 * https://github.com/pwmckenna/benc2json
 *
 * Copyright (c) 2013 Patrick Williams
 * Licensed under the MIT license.
 */

var express = require('express');
var app = express();
var q = require('q');
var URL = require('url');
require('bufferjs');
var _ = require('underscore');
var ntread = require('./nt/read').readURL;

var Firebase = require('./firebase-node');
var FirebaseTokenGenerator = require("./firebase-token-generator-node.js");

if(!process.env.FIREBASE_SECRET) {
    console.error('FIREBASE_SECRET not available in the current environment');
    process.exit(1);
}

var tokenGenerator = new FirebaseTokenGenerator(process.env.FIREBASE_SECRET);
var token = tokenGenerator.createToken({}, {
    admin: true
});
var firebase = new Firebase('https://todium.firebaseio.com/');

var getTorrentReadStream = function(torrent) {
    var ret = new q.defer();
    var torrentStream = torrent.createReadStream();
    var buffers = [];
    torrentStream.addListener('data', function(buffer) {
        buffers.push(buffer);
    });
    torrentStream.addListener('end', function() {
        ret.resolve(Buffer.concat(buffers));
    });
    return ret.promise;
}

var serveEditedTorrentFile = function(res, torrent, tracker) {
    console.log('serving torrent with tracker');
    console.log('torrent', torrent);
    console.log('tracker', tracker);

    ntread(torrent, function(err, torrent) {
        // maybe not a valid torrent file?
        if(err) {
            console.log('unable to read torrent file', err);
            res.writeHead(400);
            res.end();
            return;
        }

        // set the main tracker to our tracker
        if(torrent.metadata.hasOwnProperty('announce-list')) {
            torrent.metadata['announce-list'].push([tracker]);
        } else {
            torrent.metadata['announce-list'] = [[tracker], [torrent.metadata.announce]];
        }

        // now create a read stream and dump it into our response stream
        var torrentReadStreamRequest = getTorrentReadStream(torrent);
        torrentReadStreamRequest.done(function(data) {
            res.writeHead(200, {
                'Content-Type': 'application/x-bittorrent',
                'Content-Disposition': 'inline; filename="' + torrent.metadata.info.name + '.torrent"'
            });
            res.end(data);
        });
        torrentReadStreamRequest.fail(function() {
            console.log('unable to get torrent file stream');
            res.writeHead(400);
            res.end();
            return;
        });
    });
};

var handleParameterRequest = function(req, res) {
    var query = URL.parse(req.url, true).query;
    if(!query.hasOwnProperty('torrent')) {
        res.writeHead(400);
        res.end('no torrent specified');
        return;
    }
    if(!query.hasOwnProperty('tracker')) {
        res.writeHead(400);
        res.end('no tracker specified');
        return;
    }
    serveEditedTorrentFile(res, query['torrent'], query['tracker']);
};

var handleShortenedTorrentLink = function(req, res) {
    var link = req.params.link;
    firebase.child('torrent').child(link).once('value', function(valueSnapshot) {
        var value = valueSnapshot.val();
        var torrent = value.torrent;
        var tracker = value.tracker;
        console.log('torrent', torrent);
        console.log('tracker', tracker);

        serveEditedTorrentFile(res, torrent, tracker);
    });
};

//support the case where someone wants to name their torrent
app.get('/:link/:name.torrent', handleShortenedTorrentLink);
//support the random link name
app.get('/:link.torrent', handleShortenedTorrentLink);
//support the case where someone wants to specify the torrent and tracker themselves
app.get('/', handleParameterRequest);

var port = process.env.PORT || 5000;
var onAuth = function(error, dummy) {
    if(!error) {
        console.log('firebase login success');
        app.listen(port, function() {
            console.log('Listening on ' + port);
        });
    } else {
        console.log('firebase login failure');
        process.exit(1);
    }
};
firebase.auth(token, onAuth);<commit_msg>updating token generator dep<commit_after>/*
 * benc2json
 * https://github.com/pwmckenna/benc2json
 *
 * Copyright (c) 2013 Patrick Williams
 * Licensed under the MIT license.
 */

var express = require('express');
var app = express();
var q = require('q');
var URL = require('url');
require('bufferjs');
var _ = require('underscore');
var ntread = require('./nt/read').readURL;

var Firebase = require('./firebase-node');
var FirebaseTokenGenerator = require('firebase-token-generator');

if(!process.env.FIREBASE_SECRET) {
    console.error('FIREBASE_SECRET not available in the current environment');
    process.exit(1);
}

var tokenGenerator = new FirebaseTokenGenerator(process.env.FIREBASE_SECRET);
var token = tokenGenerator.createToken({}, {
    admin: true
});
var firebase = new Firebase('https://todium.firebaseio.com/');

var getTorrentReadStream = function(torrent) {
    var ret = new q.defer();
    var torrentStream = torrent.createReadStream();
    var buffers = [];
    torrentStream.addListener('data', function(buffer) {
        buffers.push(buffer);
    });
    torrentStream.addListener('end', function() {
        ret.resolve(Buffer.concat(buffers));
    });
    return ret.promise;
}

var serveEditedTorrentFile = function(res, torrent, tracker) {
    console.log('serving torrent with tracker');
    console.log('torrent', torrent);
    console.log('tracker', tracker);

    ntread(torrent, function(err, torrent) {
        // maybe not a valid torrent file?
        if(err) {
            console.log('unable to read torrent file', err);
            res.writeHead(400);
            res.end();
            return;
        }

        // set the main tracker to our tracker
        if(torrent.metadata.hasOwnProperty('announce-list')) {
            torrent.metadata['announce-list'].push([tracker]);
        } else {
            torrent.metadata['announce-list'] = [[tracker], [torrent.metadata.announce]];
        }

        // now create a read stream and dump it into our response stream
        var torrentReadStreamRequest = getTorrentReadStream(torrent);
        torrentReadStreamRequest.done(function(data) {
            res.writeHead(200, {
                'Content-Type': 'application/x-bittorrent',
                'Content-Disposition': 'inline; filename="' + torrent.metadata.info.name + '.torrent"'
            });
            res.end(data);
        });
        torrentReadStreamRequest.fail(function() {
            console.log('unable to get torrent file stream');
            res.writeHead(400);
            res.end();
            return;
        });
    });
};

var handleParameterRequest = function(req, res) {
    var query = URL.parse(req.url, true).query;
    if(!query.hasOwnProperty('torrent')) {
        res.writeHead(400);
        res.end('no torrent specified');
        return;
    }
    if(!query.hasOwnProperty('tracker')) {
        res.writeHead(400);
        res.end('no tracker specified');
        return;
    }
    serveEditedTorrentFile(res, query['torrent'], query['tracker']);
};

var handleShortenedTorrentLink = function(req, res) {
    var link = req.params.link;
    firebase.child('torrent').child(link).once('value', function(valueSnapshot) {
        var value = valueSnapshot.val();
        var torrent = value.torrent;
        var tracker = value.tracker;
        console.log('torrent', torrent);
        console.log('tracker', tracker);

        serveEditedTorrentFile(res, torrent, tracker);
    });
};

//support the case where someone wants to name their torrent
app.get('/:link/:name.torrent', handleShortenedTorrentLink);
//support the random link name
app.get('/:link.torrent', handleShortenedTorrentLink);
//support the case where someone wants to specify the torrent and tracker themselves
app.get('/', handleParameterRequest);

var port = process.env.PORT || 5000;
var onAuth = function(error, dummy) {
    if(!error) {
        console.log('firebase login success');
        app.listen(port, function() {
            console.log('Listening on ' + port);
        });
    } else {
        console.log('firebase login failure');
        process.exit(1);
    }
};
firebase.auth(token, onAuth);<|endoftext|>


<commit_before>/* smooth-scroll.js v1.0 */
(function(){var e=500;var t=15;var n=document.getElementsByTagName("a");var r;for(var i=0;i<n.length;i++){r=n[i].attributes.href===undefined?null:n[i].attributes.href.nodeValue.toString();if(r!==null&&r.length>1&&r.substr(0,1)=="#"){n[i].onclick=function(){var n;var r=this.attributes.href.nodeValue.toString();if(n=document.getElementById(r.substr(1))){var i=e/t;var u=o();var a=(s(n)-u)/i;for(var f=1;f<=i;f++){(function(){var e=a*f;setTimeout(function(){window.scrollTo(0,e+u)},t*f)})()}}return false}}}var s=function(e){var t=0;while(e.offsetParent!=undefined&&e.offsetParent!=null){t+=e.offsetTop+(e.clientTop!=null?e.clientTop:0);e=e.offsetParent}return t};var o=function(){return document.documentElement.scrollTop+document.body.scrollTop}})()
<commit_msg>v1.0.1 | Minified with jscompress.com/<commit_after>/* smooth-scroll.js v1.0.1 */
(function(){var e=500,t=15,n=0,r=document.getElementsByTagName("a"),i;for(var s=0;s<r.length;s++){i=r[s].attributes.href===undefined?null:r[s].attributes.href.nodeValue.toString();if(i!==null&&i.length>1&&i.substr(0,1)=="#"){r[s].onclick=function(){var r;var i=this.attributes.href.nodeValue.toString();if(r=document.getElementById(i.substr(1))){var s=e/t;var a=u();var f=(o(r)-a-n)/s;for(var l=1;l<=s;l++){(function(){var e=f*l;setTimeout(function(){window.scrollTo(0,e+a)},t*l)})()}}return false}}}var o=function(e){var t=0;while(e.offsetParent!=undefined&&e.offsetParent!=null){t+=e.offsetTop+(e.clientTop!=null?e.clientTop:0);e=e.offsetParent}return t};var u=function(){return document.documentElement.scrollTop+document.body.scrollTop}})()
<|endoftext|>


<commit_before>#!/usr/bin/env node

var print = require("sys").print,
	src = require("fs").readFileSync(process.argv[2], "utf8");

// Previously done in sed but reimplemented here due to portability issues
print( src.replace( /^(\s*\*\/)(.+)/m, "$1\n$2" ) + ";" );
<commit_msg>Builds minimal license header block for jquery.min.js<commit_after>#!/usr/bin/env node

var print = require( "sys" ).print,
	fs = require( "fs" ),
	src = fs.readFileSync( process.argv[2], "utf8" ),
	version = fs.readFileSync( "version.txt", "utf8" ),
	// License Template
	license = "/*! jQuery v@VERSION @DATE http://jquery.com/ | http://jquery.org/license */";

license = license.replace( "@VERSION", version )
						.replace( "@DATE", (new Date()).toLocaleString() );

// Previously done in sed but reimplemented here due to portability issues
src = src.replace( /^(\s*\*\/)(.+)/m, "$1\n$2" ) + ";";

// Replace license block with minimal license
src = src.replace( /\/\/.*?\/?\*.+?(?=\n|\r|$)|\/\*[\s\S]*?\/\/[\s\S]*?\*\//, license );

print( src );
<|endoftext|>


<commit_before>/**
 * The MIT License (MIT)
 *
 * Copyright (c) 2016-2017 Mickael Jeanroy
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

const fs = require('fs');
const path = require('path');
const gulp = require('gulp');
const gutil = require('gulp-util');
const Q = require('q');
const gls = require('gulp-live-server');

const rollup = require('rollup');
const alias = require('rollup-plugin-alias');
const commonjs = require('rollup-plugin-commonjs');
const nodeResolve = require('rollup-plugin-node-resolve');

const babel = require('babel-core');
const babelConf = require('../babel.conf');

module.exports = (options) => {
  const bundle = (id) => {
    gutil.log(gutil.colors.gray(`[${id}] Running rollup...`));
    const rollupConf = {
      // Keep the `entry` option for `rollup-plugin-commonjs`
      entry: path.join(options.sample, id, 'app.js'),

      input: path.join(options.sample, id, 'app.js'),
      format: 'iife',
      plugins: [
        alias({
          'backbone-template-manager': path.join(options.dist, 'backbone-template-manager.js'),
        }),

        nodeResolve({
          jsnext: true,
          main: true,
        }),

        commonjs(),
      ],
    };

    return rollup.rollup(rollupConf)
      .then((bundle) => {
        gutil.log(gutil.colors.gray(`[${id}] Generating ES6 bundle`));
        bundle.generate(rollupConf).then((result) => {
          gutil.log(gutil.colors.gray(`[${id}] Generating ES5 bundle`));
          const dest = path.join(options.sample, id, '.tmp', 'bundle.js');
          const es5 = babel.transform(result.code, babelConf);

          gutil.log(gutil.colors.gray(`[${id}] Writing ES5 bundle to: ${dest}`));
          fs.writeFileSync(dest, es5.code, 'utf-8');
        });
      })
      .catch((err) => {
        gutil.log(gutil.colors.red(err));
      });
  };

  const bundleAll = () => {
    const promises = ['dom', 'remote', 'mustache'].map((id) => bundle(id));
    return Q.all(promises);
  };

  gulp.task('serve', ['build'], () => {
    bundleAll().then(() => {
      const main = path.join(options.sample, 'server.js');
      const server = gls.new(main);

      // Start server.
      server.start();

      const srcFiles = path.join(options.src, '**', '*.js');
      const distFiles = path.join(options.dist, '**', '*.js');
      const sampleFiles = path.join(options.sample, '**', '*.js');
      const bundles = path.join(options.sample, '**', '.tmp', '*.js');
      const htmlFiles = path.join(options.sample, '**', '*.html');
      const cssFiles = path.join(options.sample, '**', '*.css');

      // Rebuild dist file when a source file is updated.
      gulp.watch(srcFiles, () => {
        gutil.log(gutil.colors.gray(`Change detected in source files, rebuild`));
        gulp.start('build');
      });

      // Rebuild sample bundle when dist file is updated.
      gulp.watch(distFiles, () => {
        gutil.log(gutil.colors.gray(`Change detected in dist files, bundle app`));
        bundleAll();
      });

      // Rebuild sample when sample source files are updated.
      gulp.watch([sampleFiles, `!${bundles}`], () => {
        gutil.log(gutil.colors.gray(`Change detected in sample, bundle app`));
        bundleAll();
      });

      // Reload when bundle app is updated.
      gulp.watch([bundles, htmlFiles, cssFiles], () => {
        gutil.log(gutil.colors.green(`Change detected, notify server`));
        server.notify();
      });
    });
  });
};
<commit_msg>chore: remove entry hack for rollup-plugin-commonjs<commit_after>/**
 * The MIT License (MIT)
 *
 * Copyright (c) 2016-2017 Mickael Jeanroy
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

const fs = require('fs');
const path = require('path');
const gulp = require('gulp');
const gutil = require('gulp-util');
const Q = require('q');
const gls = require('gulp-live-server');

const rollup = require('rollup');
const alias = require('rollup-plugin-alias');
const commonjs = require('rollup-plugin-commonjs');
const nodeResolve = require('rollup-plugin-node-resolve');

const babel = require('babel-core');
const babelConf = require('../babel.conf');

module.exports = (options) => {
  const bundle = (id) => {
    gutil.log(gutil.colors.gray(`[${id}] Running rollup...`));
    const rollupConf = {
      input: path.join(options.sample, id, 'app.js'),
      format: 'iife',
      plugins: [
        alias({
          'backbone-template-manager': path.join(options.dist, 'backbone-template-manager.js'),
        }),

        nodeResolve({
          jsnext: true,
          main: true,
        }),

        commonjs(),
      ],
    };

    return rollup.rollup(rollupConf)
      .then((bundle) => {
        gutil.log(gutil.colors.gray(`[${id}] Generating ES6 bundle`));
        bundle.generate(rollupConf).then((result) => {
          gutil.log(gutil.colors.gray(`[${id}] Generating ES5 bundle`));
          const dest = path.join(options.sample, id, '.tmp', 'bundle.js');
          const es5 = babel.transform(result.code, babelConf);

          gutil.log(gutil.colors.gray(`[${id}] Writing ES5 bundle to: ${dest}`));
          fs.writeFileSync(dest, es5.code, 'utf-8');
        });
      })
      .catch((err) => {
        gutil.log(gutil.colors.red(err));
      });
  };

  const bundleAll = () => {
    const promises = ['dom', 'remote', 'mustache'].map((id) => bundle(id));
    return Q.all(promises);
  };

  gulp.task('serve', ['build'], () => {
    bundleAll().then(() => {
      const main = path.join(options.sample, 'server.js');
      const server = gls.new(main);

      // Start server.
      server.start();

      const srcFiles = path.join(options.src, '**', '*.js');
      const distFiles = path.join(options.dist, '**', '*.js');
      const sampleFiles = path.join(options.sample, '**', '*.js');
      const bundles = path.join(options.sample, '**', '.tmp', '*.js');
      const htmlFiles = path.join(options.sample, '**', '*.html');
      const cssFiles = path.join(options.sample, '**', '*.css');

      // Rebuild dist file when a source file is updated.
      gulp.watch(srcFiles, () => {
        gutil.log(gutil.colors.gray(`Change detected in source files, rebuild`));
        gulp.start('build');
      });

      // Rebuild sample bundle when dist file is updated.
      gulp.watch(distFiles, () => {
        gutil.log(gutil.colors.gray(`Change detected in dist files, bundle app`));
        bundleAll();
      });

      // Rebuild sample when sample source files are updated.
      gulp.watch([sampleFiles, `!${bundles}`], () => {
        gutil.log(gutil.colors.gray(`Change detected in sample, bundle app`));
        bundleAll();
      });

      // Reload when bundle app is updated.
      gulp.watch([bundles, htmlFiles, cssFiles], () => {
        gutil.log(gutil.colors.green(`Change detected, notify server`));
        server.notify();
      });
    });
  });
};
<|endoftext|>


<commit_before>var gulp = require('gulp');
var webpack = require('webpack');
var paths = require('../paths');
var webpackConfig = require('../../webpack.config.js');

var WebpackDevServer = require("webpack-dev-server");

/**
 * Js task
 * Run using "gulp js"
 * Runs webpack to compile javascript
 */
gulp.task('server', function() {
    webpackConfig.entry.unshift(
        "webpack-dev-server/client?http://localhost:8080",
        "webpack/hot/only-dev-server"
    );
    webpackConfig.plugins = [
        new webpack.HotModuleReplacementPlugin(),
        new webpack.NamedModulesPlugin()
    ];
    var compiler = webpack(webpackConfig);
    server = new WebpackDevServer(compiler, {
        hot: true,
        publicPath: "/static/js/",
        proxy: {
            '/': {
                target: 'http://localhost:8000/',
                secure: false,
                bypass: function(request, response, proxyOptions) {
                    if (request.path.startsWith('/static/js/')) {
                        return request.path;
                    } else if (request.path.indexOf('hot-update') > 0) {
                        // ugly hack, but publicPath is not properly supported :/
                        return '/static/js' + request.path;
                    }
                    return false;
                }
            }
        }
    });
    server.listen(8080);
});
<commit_msg>update docstring<commit_after>var gulp = require('gulp');
var webpack = require('webpack');
var paths = require('../paths');
var webpackConfig = require('../../webpack.config.js');

var WebpackDevServer = require("webpack-dev-server");

/**
 * Server task
 * Run using "gulp server"
 * Starts a webpack dev server on port 8080
 * Proxies request to Django (assumed to be listening on port 8000)
 */
gulp.task('server', function() {
    webpackConfig.entry.unshift(
        "webpack-dev-server/client?http://localhost:8080",
        "webpack/hot/only-dev-server"
    );
    webpackConfig.plugins = [
        new webpack.HotModuleReplacementPlugin(),
        new webpack.NamedModulesPlugin()
    ];
    var compiler = webpack(webpackConfig);
    server = new WebpackDevServer(compiler, {
        hot: true,
        publicPath: "/static/js/",
        proxy: {
            '/': {
                target: 'http://localhost:8000/',
                secure: false,
                bypass: function(request, response, proxyOptions) {
                    if (request.path.startsWith('/static/js/')) {
                        return request.path;
                    } else if (request.path.indexOf('hot-update') > 0) {
                        // ugly hack, but publicPath is not properly supported :/
                        return '/static/js' + request.path;
                    }
                    return false;
                }
            }
        }
    });
    server.listen(8080);
});
<|endoftext|>


<commit_before>(function(root) {

  'use strict';

  var availity = root.availity;

  var blockTemplate =
    '
 0" class="block-ui-overlay" ng-class="{ \'block-ui-visible\': state.blocking }">
'+
    '
'+
    '
'+
    '

'+
    '
'+
    '
';

  availity.ui.constant('AV_BLOCK', {
    TEMPLATES: {
      BLOCK: 'ui/modal/modal-tpl.html'
    }
  });

  var getLoaderController = function(blockId) {
    var el = $('[data-block-ui="'+blockId+'"]') || $('[block-ui="'+blockId+'"]');
    if (el) {
      return el.find('[data-av-loader]').controller('avLoader');
    }
  };

  var triggerLoaderController = function(id, instance, fn) {
    var controller = instance.loaderController;
    if (!controller) {
      controller = getLoaderController(id);
      instance.loaderController = controller;
    }
    if (controller && _.isFunction(controller[fn])) {
      controller[fn]();
    }
  };

  var startInstance = function(id, instance, origStartFn) {
    triggerLoaderController(id, instance, "start");
    origStartFn.apply(instance);
  };

  var stopInstance = function(id, instance, origStopFn) {
    triggerLoaderController(id, instance, "stop");
    origStopFn.apply(instance);
  };

  var modifyBlockInstances = function(id, instance) {
    var origStartFn = instance.start;
    var origStopFn = instance.stop;
    instance.start = function() {
      startInstance(id, instance, origStartFn);
    };
    instance.stop = function() {
      stopInstance(id, instance, origStopFn);
    };
    instance.avModifications = true;
  };

  availity.ui.run(function($injector, $log) {
    try {

      var blockUIConfig = $injector.get('blockUIConfig');
      var blockUI = $injector.get('blockUI');
      blockUIConfig.autoBlock = false;
      blockUIConfig.delay = 0;
      blockUIConfig.template = blockTemplate;

      var origGetFn = blockUI.instances.get;
      blockUI.instances.get = function(id) {
        var instance = origGetFn(id);
        if (!instance.avModifications) {
          modifyBlockInstances(id, instance);
        }
        return instance;
      };

    } catch (e) {
      $log.error("blockUI is required to use av block.");
    }
  });

})(window);
<commit_msg>Change log level from error to warn<commit_after>(function(root) {

  'use strict';

  var availity = root.availity;

  var blockTemplate =
    '
 0" class="block-ui-overlay" ng-class="{ \'block-ui-visible\': state.blocking }">
'+
    '
'+
    '
'+
    '

'+
    '
'+
    '
';

  availity.ui.constant('AV_BLOCK', {
    TEMPLATES: {
      BLOCK: 'ui/modal/modal-tpl.html'
    }
  });

  var getLoaderController = function(blockId) {
    var el = $('[data-block-ui="'+blockId+'"]') || $('[block-ui="'+blockId+'"]');
    if (el) {
      return el.find('[data-av-loader]').controller('avLoader');
    }
  };

  var triggerLoaderController = function(id, instance, fn) {
    var controller = instance.loaderController;
    if (!controller) {
      controller = getLoaderController(id);
      instance.loaderController = controller;
    }
    if (controller && _.isFunction(controller[fn])) {
      controller[fn]();
    }
  };

  var startInstance = function(id, instance, origStartFn) {
    triggerLoaderController(id, instance, "start");
    origStartFn.apply(instance);
  };

  var stopInstance = function(id, instance, origStopFn) {
    triggerLoaderController(id, instance, "stop");
    origStopFn.apply(instance);
  };

  var modifyBlockInstances = function(id, instance) {
    var origStartFn = instance.start;
    var origStopFn = instance.stop;
    instance.start = function() {
      startInstance(id, instance, origStartFn);
    };
    instance.stop = function() {
      stopInstance(id, instance, origStopFn);
    };
    instance.avModifications = true;
  };

  availity.ui.run(function($injector, $log) {
    try {

      var blockUIConfig = $injector.get('blockUIConfig');
      var blockUI = $injector.get('blockUI');
      blockUIConfig.autoBlock = false;
      blockUIConfig.delay = 0;
      blockUIConfig.template = blockTemplate;

      var origGetFn = blockUI.instances.get;
      blockUI.instances.get = function(id) {
        var instance = origGetFn(id);
        if (!instance.avModifications) {
          modifyBlockInstances(id, instance);
        }
        return instance;
      };

    } catch (e) {
      $log.warn("blockUI is required to use av block.");
    }
  });

})(window);
<|endoftext|>


<commit_before>(function () {
    "use strict";

    Mapbender.Digitizer = function () {
        Mapbender.DataManager.apply(this, arguments);
    };

    Mapbender.Digitizer.prototype = Object.create(Mapbender.DataManager.prototype);
    Mapbender.Digitizer.prototype.constructor = Mapbender.DataManager;

    Mapbender.Digitizer.prototype.TYPE = "Digitizer";

    Mapbender.Digitizer.prototype.createScheme_ = function (rawScheme) {
        return new Mapbender.Digitizer.Scheme(rawScheme, this);
    };

    Mapbender.Digitizer.prototype.setup = function () {
        var widget = this;
        Object.getPrototypeOf(Mapbender.Digitizer.prototype).setup.apply(this, arguments);
        widget.contextMenu = new Mapbender.Digitizer.MapContextMenu(widget);

    };

    Mapbender.Digitizer.prototype.isInExtent = function(feature) {
        var widget = this;
        return ol.extent.intersects(widget.map.getView().calculateExtent(), feature.getGeometry().getExtent());
    };

    Mapbender.Digitizer.prototype.refreshConnectedDigitizerFeatures = function(schemaName){
        $(".mb-element-digitizer").not(".mb-element-data-manager").each(function(index,element){
            var foreignDigitizer = $(element).data("mapbenderMbDigitizer");

            try {
                foreignDigitizer.schemes[schemaName].layer.getSource().refresh();
            } catch(e) {
                console.error("No active Digitizer Scheme '"+schemaName+"'",e);
            }
        });

    };

})();
<commit_msg>Absorb inherited parts of DataManager class from feature-branch "ol4" directly into Digitizer class<commit_after>(function () {
    "use strict";

    Mapbender.Digitizer = function () {
        var widget  = this;

        $.extend(widget, options);

        widget.id = $element.attr("id");

        var $spinner = (function() {
            var $parent = $('#' + widget.id).parents('.container-accordion').prev().find('.tablecell');
            var spinner = $("

");
            $parent.prepend(spinner);
            return spinner;
        })();

        var qe = new Mapbender.DataManager.QueryEngine(widget.id,Mapbender.DataManager.createSpinner_($spinner));
        widget.query = qe.query;
        widget.getElementURL = qe.getElementURL;

        Mapbender.elementRegistry.waitReady(widget.target).then( function() {
            widget.setup($element,$title,$selector);
        });
    };

    Mapbender.Digitizer.prototype.TYPE = "Digitizer";

    Mapbender.Digitizer.prototype.setup = function () {
        var widget = this;
        widget.contextMenu = new Mapbender.Digitizer.MapContextMenu(widget);

        var rawSchemes = widget.schemes;
        widget.schemes = {};
        $.each(rawSchemes, function (schemaName,options) {
            options.schemaName = schemaName;
            var schema = widget.schemes[schemaName] = widget.createScheme_(options);
            schema.createMenu($element);
        });
        Object.freeze(widget.schemes);

        if (widget.displayOnInactive) {
            widget.activate(false);
        }
    };

    Mapbender.Digitizer.prototype.isInExtent = function(feature) {
        var widget = this;
        return ol.extent.intersects(widget.map.getView().calculateExtent(), feature.getGeometry().getExtent());
    };

    Mapbender.Digitizer.prototype.refreshConnectedDigitizerFeatures = function(schemaName){
        $(".mb-element-digitizer").not(".mb-element-data-manager").each(function(index,element){
            var foreignDigitizer = $(element).data("mapbenderMbDigitizer");

            try {
                foreignDigitizer.schemes[schemaName].layer.getSource().refresh();
            } catch(e) {
                console.error("No active Digitizer Scheme '"+schemaName+"'",e);
            }
        });

    };

    Mapbender.Digitizer.prototype.getProjectionCode = function() {
        var widget = this;
        return widget.map.getView().getProjection().getCode().split(':').pop();
    };
    Mapbender.Digitizer.prototype.getCurrentSchema = function() {
        var widget = this;
        return widget.selector.getSelectedSchema();
    }

    Mapbender.Digitizer.prototype.createSpinner_ = function ($spinner) {
        var spinner = new function () {
            var spinner = this;

            spinner.openRequests = 0;

            spinner.$element = $spinner;

            spinner.addRequest = function () {
                spinner.openRequests++;
                if (spinner.openRequests >= 1) {
                    spinner.$element.trigger("show");
                }
            };

            spinner.removeRequest = function () {
                spinner.openRequests--;
                if (spinner.openRequests === 0) {
                    spinner.$element.trigger("hide");
                }
            };

        };

        return spinner;
    };

})();
<|endoftext|>


<commit_before>/*
 * @copyright Copyright (c) Sematext Group, Inc. - All Rights Reserved
 *
 * @licence SPM for NodeJS is free-to-use, proprietary software.
 * THIS IS PROPRIETARY SOURCE CODE OF Sematext Group, Inc. (Sematext)
 * This source code may not be copied, reverse engineered, or altered for any purpose.
 * This source code is to be used exclusively by users and customers of Sematext.
 * Please see the full license (found in LICENSE in this distribution) for details on its license and the licenses of its dependencies.
 */

'use strict'
var flatten = require('flat')
var util = require('util')
var spmDefaultConfig = {
  tokens: {
    spm: process.env.SPM_TOKEN
  },
  maxDbSize: 1024*1024*24,
  agentsToLoad: [],
  maxDataPoints: 90,
  recoverInterval: 10000,
  collectionInterval: 20000,
  transmitInterval: 10000,
  maxRetransmitBatchSize: 100,
  spmSenderBulkInsertUrl: 'https://spm-receiver.sematext.com:443/receiver/v1/_bulk',
  dbDir: './spmdb',
  logger: {
    dir: './spmlogs',
    level: 'error',
    console: false,
    maxfiles: '2',
    maxsize: '524288',
    filename: 'spm',
    useLogstashFormat: false,
    silent: false
}
}
var SpmConfig = function () {
  var rc = require('rc')('spmagent', spmDefaultConfig)
  util._extend(this, rc)
  this.rcFlat = flatten(this)
  return this
}

SpmConfig.prototype.get = function (key) {
  return this.rcFlat [key]
}

module.exports = new SpmConfig()

// -e spmagent_retransmitInterval=30000
<commit_msg>spmconfig before merge<commit_after>/*
 * @copyright Copyright (c) Sematext Group, Inc. - All Rights Reserved
 *
 * @licence SPM for NodeJS is free-to-use, proprietary software.
 * THIS IS PROPRIETARY SOURCE CODE OF Sematext Group, Inc. (Sematext)
 * This source code may not be copied, reverse engineered, or altered for any purpose.
 * This source code is to be used exclusively by users and customers of Sematext.
 * Please see the full license (found in LICENSE in this distribution) for details on its license and the licenses of its dependencies.
 */

'use strict'
var flatten = require('flat')
var util = require('util')
var spmDefaultConfig = {
  tokens: {
    spm: process.env.SPM_TOKEN
  },
  maxDbSize: 1024*1024*24,
  agentsToLoad: [],
  maxDataPoints: 90,
  recoverInterval: 10000,
  collectionInterval: 20000,
  transmitInterval: 10000,
  maxRetransmitBatchSize: 100,
  spmSenderBulkInsertUrl: 'https://spm-receiver.sematext.com:443/receiver/v1/_bulk',
  dbDir: './spmdb',
  logger: {
    dir: './spmlogs',
    level: 'error',
    console: false,
    maxfiles: '2',
    maxsize: '524288',
    filename: 'spm',
    useLogstashFormat: false,
    silent: false
}
}
var SpmConfig = function () {
  var rc = require('rc')('spmagent', spmDefaultConfig)
  util._extend(this, rc)
  this.rcFlat = flatten(this)
  return this
}

SpmConfig.prototype.get = function (key) {
  return this.rcFlat [key]
}

module.exports = new SpmConfig()
<|endoftext|>


<commit_before>
// utilities for working with the js-registry site.

exports.publish = publish
exports.tag = tag
exports.adduser = adduser
exports.get = get

var npm = require("../../npm")
  , http = require("http")
  , url = require("url")
  , log = require("./log")
  , uuid = require("./uuid")
  , sha = require("./sha")
  , sys = require("sys")
  , ini = require("./ini")

function get (project, version, cb) {
  if (typeof version === "function") {
    cb = version
    version = null
  }
  GET(project+"/"+(version || ""), cb)
}

function tag (project, version, tag, cb) { PUT(project+"/"+tag, version, cb) }

function publish (data, tarball, cb) {
  // add the dist-url to the data, pointing at the tarball.
  // if the {name} isn't there, then create it.
  // if the {version} is already there, then fail.
  // then:
  // PUT the data to {config.registry}/{data.name}/{data.version}
  try {
    reg()
  } catch (ex) {
    return cb(ex)
  }
  var fullData =
    { "_id" : data.name
    , "name" : data.name
    , "description" : data.description
    , "dist-tags" : {}
    , "versions" : {}
    }
  fullData.versions[ data.version ] = data
  data._id = data.name+"-"+data.version
  data.dist = { "tarball" : tarball }

  // first try to just PUT the whole fullData, and this will fail if it's
  // already there, because it'll be lacking a _rev, so couch'll bounce it.
  PUT(data.name, fullData, function (er) {
    if (!er) return cb()
    // there was an error, so assume the fullData is already there.
    // now try to create just this version.  This time, failure
    // is not ok.
    // Note: the first might've failed for a down host or something,
    // in which case this will likely fail, too.  If the host was down for the
    // first req, but now it's up, then this may fail for not having the
    // project created yet, or because the user doesn't have access to it.
    PUT(data.name+"/"+data.version, data, function (er) {
      if (er) return cb(er)
      cb()
    })
  })
}

function GET (where, cb) {
  reg()
  where = ini.config.registry + where
  var u = url.parse(where)
    , headers = { "host" : u.host
                , "accept" : "application/json"
                }
  if (ini.config.auth) {
    headers.authorization = 'Basic ' + ini.config.auth
  }
  var https = u.protocol === "https:"
    , client = http.createClient(u.port || (https ? 443 : 80), u.hostname, https)
    , request = client.request("GET", u.pathname, headers)

  request.addListener("response", function (response) {
    // if (response.statusCode !== 200) return cb(new Error(
    //   "Status code " + response.statusCode + " from PUT "+where))
    var data = ""
    response.setBodyEncoding("utf8")
    response.addListener("data", function (chunk) { data += chunk })
    response.addListener("end", function () {
      try {
        data = JSON.parse(data)
      } catch (ex) {
        ex.message += "\n" + data
        return cb(ex, data, response)
      }
      if (data.error) return cb(new Error(
        data.error + (" "+data.reason || "")))
      cb(null, data, response)
    })
  })
  request.end()
}

function PUT (where, what, cb) {
  reg()
  what = JSON.stringify(what)
  where = ini.config.registry + where

  var u = url.parse(where)
    , headers = { "content-type" : "application/json"
                , "host" : u.host
                , "content-length" : what.length
                }
  if (ini.config.auth) {
    headers.authorization = 'Basic ' + ini.config.auth
  }

  var https = u.protocol === "https:"
    , client = http.createClient(u.port || (https ? 443 : 80), u.hostname, https)
    , request = client.request("PUT", u.pathname, headers)

  request.addListener("response", function (response) {
    // if (response.statusCode !== 200) return cb(new Error(
    //   "Status code " + response.statusCode + " from PUT "+where))
    var data = ""
    response.setBodyEncoding("utf8")
    response.addListener("data", function (chunk) { data += chunk })
    response.addListener("end", function () {
      try {
        data = JSON.parse(data)
      } catch (ex) {
        ex.message += "\n" + data
        return cb(ex, data, response)
      }
      if (data.error) return cb(new Error(
        data.error + (" "+data.reason || "")))
      cb(null, data, response)
    })
  })
  request.write(what, "utf8")
  request.end()
}

function reg () {
  if (!ini.config.registry) throw new Error(
    "Must define registry before publishing.")
  log(ini.config.registry, "registry")
  if (ini.config.registry.substr(-1) !== "/") {
    ini.config.registry += "/"
  }
}

function adduser (username, password, email, callback) {
  var salt = uuid.generate()
  var userobj =
    { '_id' : 'org.couchdb.user:'+username
    , name : username
    , type : "user"
    , roles : []
    , salt : salt
    , password_sha : sha.hex_sha1(password + salt)
    , email : email
    }
  PUT('/adduser/org.couchdb.user:'+username, userobj, function (error, data, response) {
    // if the error is a 409, then update the rev.
    if (error || response.statusCode !== 201) {
      callback(new Error(
        "Could not create user "+error+'\n'+data))
    } else {
      callback()
    }
  })
}
<commit_msg>Don't throw when the data is null.  Instead, just let the thing respond with the error<commit_after>
// utilities for working with the js-registry site.

exports.publish = publish
exports.tag = tag
exports.adduser = adduser
exports.get = get

var npm = require("../../npm")
  , http = require("http")
  , url = require("url")
  , log = require("./log")
  , uuid = require("./uuid")
  , sha = require("./sha")
  , sys = require("sys")
  , ini = require("./ini")

function get (project, version, cb) {
  if (typeof version === "function") {
    cb = version
    version = null
  }
  GET(project+"/"+(version || ""), cb)
}

function tag (project, version, tag, cb) { PUT(project+"/"+tag, version, cb) }

function publish (data, tarball, cb) {
  // add the dist-url to the data, pointing at the tarball.
  // if the {name} isn't there, then create it.
  // if the {version} is already there, then fail.
  // then:
  // PUT the data to {config.registry}/{data.name}/{data.version}
  try {
    reg()
  } catch (ex) {
    return cb(ex)
  }
  var fullData =
    { "_id" : data.name
    , "name" : data.name
    , "description" : data.description
    , "dist-tags" : {}
    , "versions" : {}
    }
  fullData.versions[ data.version ] = data
  data._id = data.name+"-"+data.version
  data.dist = { "tarball" : tarball }

  // first try to just PUT the whole fullData, and this will fail if it's
  // already there, because it'll be lacking a _rev, so couch'll bounce it.
  PUT(data.name, fullData, function (er) {
    if (!er) return cb()
    // there was an error, so assume the fullData is already there.
    // now try to create just this version.  This time, failure
    // is not ok.
    // Note: the first might've failed for a down host or something,
    // in which case this will likely fail, too.  If the host was down for the
    // first req, but now it's up, then this may fail for not having the
    // project created yet, or because the user doesn't have access to it.
    PUT(data.name+"/"+data.version, data, function (er) {
      if (er) return cb(er)
      cb()
    })
  })
}

function GET (where, cb) {
  reg()
  where = ini.config.registry + where
  var u = url.parse(where)
    , headers = { "host" : u.host
                , "accept" : "application/json"
                }
  if (ini.config.auth) {
    headers.authorization = 'Basic ' + ini.config.auth
  }
  var https = u.protocol === "https:"
    , client = http.createClient(u.port || (https ? 443 : 80), u.hostname, https)
    , request = client.request("GET", u.pathname, headers)

  request.addListener("response", function (response) {
    // if (response.statusCode !== 200) return cb(new Error(
    //   "Status code " + response.statusCode + " from PUT "+where))
    var data = ""
    response.setBodyEncoding("utf8")
    response.addListener("data", function (chunk) { data += chunk })
    response.addListener("end", function () {
      try {
        data = JSON.parse(data)
      } catch (ex) {
        ex.message += "\n" + data
        return cb(ex, data, response)
      }
      if (data && data.error) return cb(new Error(
        data.error + (" "+data.reason || "")))
      cb(null, data, response)
    })
  })
  request.end()
}

function PUT (where, what, cb) {
  reg()
  what = JSON.stringify(what)
  where = ini.config.registry + where

  var u = url.parse(where)
    , headers = { "content-type" : "application/json"
                , "host" : u.host
                , "content-length" : what.length
                }
  if (ini.config.auth) {
    headers.authorization = 'Basic ' + ini.config.auth
  }

  var https = u.protocol === "https:"
    , client = http.createClient(u.port || (https ? 443 : 80), u.hostname, https)
    , request = client.request("PUT", u.pathname, headers)

  request.addListener("response", function (response) {
    // if (response.statusCode !== 200) return cb(new Error(
    //   "Status code " + response.statusCode + " from PUT "+where))
    var data = ""
    response.setBodyEncoding("utf8")
    response.addListener("data", function (chunk) { data += chunk })
    response.addListener("end", function () {
      try {
        data = JSON.parse(data)
      } catch (ex) {
        ex.message += "\n" + data
        return cb(ex, data, response)
      }
      if (data && data.error) return cb(new Error(
        data.error + (" "+data.reason || "")))
      cb(null, data, response)
    })
  })
  request.write(what, "utf8")
  request.end()
}

function reg () {
  if (!ini.config.registry) throw new Error(
    "Must define registry before publishing.")
  log(ini.config.registry, "registry")
  if (ini.config.registry.substr(-1) !== "/") {
    ini.config.registry += "/"
  }
}

function adduser (username, password, email, callback) {
  var salt = uuid.generate()
  var userobj =
    { '_id' : 'org.couchdb.user:'+username
    , name : username
    , type : "user"
    , roles : []
    , salt : salt
    , password_sha : sha.hex_sha1(password + salt)
    , email : email
    }
  PUT('/adduser/org.couchdb.user:'+username, userobj, function (error, data, response) {
    // if the error is a 409, then update the rev.
    if (error || response.statusCode !== 201) {
      callback(new Error(
        "Could not create user "+error+'\n'+data))
    } else {
      callback()
    }
  })
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2012, Joyent, Inc. All rights reserved.
 *
 * A brief overview of this source file: what is its purpose.
 */

var common = require('./job-common');
var VERSION = '7.0.0';

/*
 * Sets up a CNAPI VM action request. Take a look at common.zoneAction. Here you
 * can set parameters such as:
 * - request endpoint (usually the VM endpoint)
 * - jobid (so CNAPI can post status updates back to the job info object)
 * - requestMethod
 * - expects (if you want to check a specific running status of the machine)
 */
function setupRequest(job, cb) {
    job.endpoint = '/servers/' +
                   job.params['server_uuid'] + '/vms/' +
                   job.params['vm_uuid'] + '/stop';
    job.params.jobid = job.uuid;
    job.requestMethod = 'post';
    job.expects = 'stopped';

    return cb(null, 'Request has been setup!');
}

var workflow = module.exports = {
    name: 'stop-' + VERSION,
    version: VERSION,
    chain: [ {
        name: 'common.validate_params',
        timeout: 10,
        retry: 1,
        body: common.validateForZoneAction,
        modules: {}
    }, {
        name: 'common.setup_request',
        timeout: 10,
        retry: 1,
        body: setupRequest,
        modules: {}
    }, {
        name: 'cnapi.stop_vm',
        timeout: 10,
        retry: 1,
        body: common.zoneAction,
        modules: { restify: 'restify' }
    }, {
        name: 'cnapi.poll_task',
        timeout: 120,
        retry: 1,
        body: common.pollTask,
        modules: { sdcClients: 'sdc-clients' }
    }, {
        name: 'vmapi.check_state',
        timeout: 60,
        retry: 1,
        body: common.checkState,
        modules: { sdcClients: 'sdc-clients' }
    }],
    timeout: 210,
    onerror: [ {
        name: 'On error',
        modules: {},
        body: function (job, cb) {
            return cb('Error executing job');
        }
    }]
};
<commit_msg>ZAPI-348: Stop/Shutdown timeout out for jobs should be raised<commit_after>/*
 * Copyright (c) 2012, Joyent, Inc. All rights reserved.
 *
 * A brief overview of this source file: what is its purpose.
 */

var common = require('./job-common');
var VERSION = '7.0.0';

/*
 * Sets up a CNAPI VM action request. Take a look at common.zoneAction. Here you
 * can set parameters such as:
 * - request endpoint (usually the VM endpoint)
 * - jobid (so CNAPI can post status updates back to the job info object)
 * - requestMethod
 * - expects (if you want to check a specific running status of the machine)
 */
function setupRequest(job, cb) {
    job.endpoint = '/servers/' +
                   job.params['server_uuid'] + '/vms/' +
                   job.params['vm_uuid'] + '/stop';
    job.params.jobid = job.uuid;
    job.requestMethod = 'post';
    job.expects = 'stopped';

    return cb(null, 'Request has been setup!');
}

var workflow = module.exports = {
    name: 'stop-' + VERSION,
    version: VERSION,
    chain: [ {
        name: 'common.validate_params',
        timeout: 10,
        retry: 1,
        body: common.validateForZoneAction,
        modules: {}
    }, {
        name: 'common.setup_request',
        timeout: 10,
        retry: 1,
        body: setupRequest,
        modules: {}
    }, {
        name: 'cnapi.stop_vm',
        timeout: 10,
        retry: 1,
        body: common.zoneAction,
        modules: { restify: 'restify' }
    }, {
        name: 'cnapi.poll_task',
        timeout: 300,
        retry: 1,
        body: common.pollTask,
        modules: { sdcClients: 'sdc-clients' }
    }, {
        name: 'vmapi.check_state',
        timeout: 60,
        retry: 1,
        body: common.checkState,
        modules: { sdcClients: 'sdc-clients' }
    }],
    timeout: 390,
    onerror: [ {
        name: 'On error',
        modules: {},
        body: function (job, cb) {
            return cb('Error executing job');
        }
    }]
};
<|endoftext|>


<commit_before>'use strict';

const path = require('path');
const assert = require('assert');

const globStream = require('glob-stream');
const mkdirp = require('mkdirp');

const TarStream = require('./tar-stream');
const FileCopyStream = require('./copy-file-stream');

const cwd = process.cwd();

/**
 * Creates and writes artifact to fs.
 *
 * @param {object}   artifact             The artifact info.
 * @param {string}   artifact.dest        The path to destination file or directory.
 * @param {string[]} [artifact.patterns]  The paths to files which need to be included or excluded.
 * @param {string[]} [artifact.includes]  The paths to files which need to be included.
 * @param {string[]} [artifact.excludes]  The paths to files which need to be excluded.
 * @param {boolean}  [artifact.tar]       If `true`, destination directory will be packed to tarball file.
 *                                        Otherwise files of artifact will be copied to destination directory.
 *                                        If `true`, tarball file will be gzipped.
 * @param {boolean}  [artifact.gzip]      Gzip destination tarball file.
 * @param {object}   [options]            The options.
 * @param {string}   [options.root]       The path to root directory. By default is cwd.
 * @param {boolean}  [options.dotFiles]   Include dotfiles.
 * @param {boolean}  [options.emptyFiles] Include empty files.
 * @returns {Promise}
 */
module.exports = (artifact, options) => {
    options || (options = {});
    artifact || (artifact = {});

    assert(artifact.dest, 'You should specify the dest for artifact.');
    assert(artifact.includes || artifact.patterns,
        'You should specify the includes or patterns parameters for artifact.');

    const root = options.root ? path.resolve(options.root) : cwd;
    const dest = path.resolve(root, artifact.dest);
    const includes = Array.isArray(artifact.includes) ? artifact.includes : [].concat(artifact.includes || []);
    const excludes = Array.isArray(artifact.excludes) ? artifact.excludes : [].concat(artifact.excludes || []);
    const patterns = [].concat(
        Array.isArray(artifact.patterns) ? artifact.patterns : [].concat(artifact.patterns || []),
        includes,
        excludes.map(pattern => isNegativePattern(pattern) ? pattern : `!${pattern}`)
    );

    if (includes.some(isNegativePattern)) {
        throw new Error('The includes parameter of artifact should not contains negative patterns.');
    }

    if (isNegativePattern(patterns[0])) {
        throw new Error('The first pattern of artifact should not be is negative.');
    }

    return new Promise((resolve, reject) => {
        const dir = artifact.tar ? path.dirname(dest) : dest;

        mkdirp(dir, err => {
            if (err) { return reject(err); }

            resolve();
        });
    }).then(() => {
        return new Promise((resolve, reject) => {
            const readStream = globStream.create(patterns, { cwd: root, base: root, dot: options.dotFiles });
            const writeStream = artifact.tar
                ? new TarStream(dest, { gzip: artifact.gzip, emptyFiles: options.emptyFiles })
                : new FileCopyStream(dest, { emptyFiles: options.emptyFiles });

            readStream.on('error', reject);

            writeStream
                .on('error', reject)
                .on(artifact.tar ? 'close' : 'finish', resolve);

            readStream.pipe(writeStream);
        });
    });
};

function isNegativePattern(pattern) {
    return pattern.charAt(0) === '!';
}
<commit_msg>perf(glob): there is no need to sort files<commit_after>'use strict';

const path = require('path');
const assert = require('assert');

const globStream = require('glob-stream');
const mkdirp = require('mkdirp');

const TarStream = require('./tar-stream');
const FileCopyStream = require('./copy-file-stream');

const cwd = process.cwd();

/**
 * Creates and writes artifact to fs.
 *
 * @param {object}   artifact             The artifact info.
 * @param {string}   artifact.dest        The path to destination file or directory.
 * @param {string[]} [artifact.patterns]  The paths to files which need to be included or excluded.
 * @param {string[]} [artifact.includes]  The paths to files which need to be included.
 * @param {string[]} [artifact.excludes]  The paths to files which need to be excluded.
 * @param {boolean}  [artifact.tar]       If `true`, destination directory will be packed to tarball file.
 *                                        Otherwise files of artifact will be copied to destination directory.
 *                                        If `true`, tarball file will be gzipped.
 * @param {boolean}  [artifact.gzip]      Gzip destination tarball file.
 * @param {object}   [options]            The options.
 * @param {string}   [options.root]       The path to root directory. By default is cwd.
 * @param {boolean}  [options.dotFiles]   Include dotfiles.
 * @param {boolean}  [options.emptyFiles] Include empty files.
 * @returns {Promise}
 */
module.exports = (artifact, options) => {
    options || (options = {});
    artifact || (artifact = {});

    assert(artifact.dest, 'You should specify the dest for artifact.');
    assert(artifact.includes || artifact.patterns,
        'You should specify the includes or patterns parameters for artifact.');

    const root = options.root ? path.resolve(options.root) : cwd;
    const dest = path.resolve(root, artifact.dest);
    const includes = Array.isArray(artifact.includes) ? artifact.includes : [].concat(artifact.includes || []);
    const excludes = Array.isArray(artifact.excludes) ? artifact.excludes : [].concat(artifact.excludes || []);
    const patterns = [].concat(
        Array.isArray(artifact.patterns) ? artifact.patterns : [].concat(artifact.patterns || []),
        includes,
        excludes.map(pattern => isNegativePattern(pattern) ? pattern : `!${pattern}`)
    );

    if (includes.some(isNegativePattern)) {
        throw new Error('The includes parameter of artifact should not contains negative patterns.');
    }

    if (isNegativePattern(patterns[0])) {
        throw new Error('The first pattern of artifact should not be is negative.');
    }

    return new Promise((resolve, reject) => {
        const dir = artifact.tar ? path.dirname(dest) : dest;

        mkdirp(dir, err => {
            if (err) { return reject(err); }

            resolve();
        });
    }).then(() => {
        return new Promise((resolve, reject) => {
            const readStream = globStream.create(patterns, {
                cwd: root,
                base: root,
                dot: options.dotFiles,
                nosort: true
            });
            const writeStream = artifact.tar
                ? new TarStream(dest, { gzip: artifact.gzip, emptyFiles: options.emptyFiles })
                : new FileCopyStream(dest, { emptyFiles: options.emptyFiles });

            readStream.on('error', reject);

            writeStream
                .on('error', reject)
                .on(artifact.tar ? 'close' : 'finish', resolve);

            readStream.pipe(writeStream);
        });
    });
};

function isNegativePattern(pattern) {
    return pattern.charAt(0) === '!';
}
<|endoftext|>