<commit_before>"use strict";

var rework = require('rework');
var reworkSelectors = require('rework-mutate-selectors');
var pureGrids = require('rework-pure-grids');
var mkdirp = require('mkdirp');
var fs = require('fs');
var upath = require('upath');

module.exports = function(config) {
    return function(cb) {
        if (config) {
            var destPath = upath.resolve(config.files.dest, 'purecss');
            createPureCSS({
                originPrefix: config.prefix,
                src: upath.resolve('node_modules', 'purecss', 'build'),
                dest: destPath,
                files: [].concat(config.files.src || [])
            }, function() {
                var prefix = [];
                if (config.columnHasPrefix) {
                    prefix.push(config.prefix);
                }
                if (config.columnPrefix) {
                    prefix.push(config.columnPrefix);
                }
                createGrid(upath.resolve(destPath, 'custom-grid.css'), config.breakpoints, prefix.join('-'), function() {
                    createGridOffset(upath.resolve(destPath, 'custom-grid-offset.css'), config.breakpoints, config.columns, prefix.join('-'), function() {
                        createGridWrapper(upath.resolve(destPath, 'custom-wrapper.css'), config, function() {
                            createCustomMediaVariables(upath.resolve(destPath, 'custom-media-variables.pcss'), config.breakpoints, function() {
                                cb();
                            });
                        });
                    });
                });
            });
        }
    };
};

function createPureCSS(options, cb) {
    if (options.files) {
        var prefixFiles = function(cb) {
            if (options.files.length) {
                var file = options.files.pop();
                fs.readFile(upath.resolve(options.src, file + '.css'), 'utf8', function(err, data) {
                    var css = rework(data);
                    if (options.prefix) {
                        css.use(reworkSelectors.prefix(options.prefix));
                    }
                    if (options.originPrefix) {
                        css.use(reworkSelectors.replace(/^\.pure/g, '.' + options.originPrefix));
                    }
                    writeFile(upath.resolve(options.dest, file + '.css'), css.toString(), function() {
                        prefixFiles(cb);
                    });
                });
            } else {
                cb();
            }
        };
        prefixFiles(function() {
            cb();
        });
    } else {
        cb();
    }
}

function createGrid(dest, breakpoints, prefix, cb) {
    var mediaMap = {};
    for (var key in breakpoints) {
        if (breakpoints.hasOwnProperty(key)) {
            mediaMap[key] = 'screen and (min-width: ' + breakpoints[key] + ')';
        }
    }
    var css = rework('').use(pureGrids.units(12, {
        decimals: 4,
        includeOldIEWidths: false,
        includeReducedFractions: false,
        includeWholeNumbers: false,
        selectorPrefix: '.' + prefix + '-',
        mediaQueries: mediaMap
    })).toString();
    writeFile(dest, css, cb);
}

function createGridWrapper(dest, options, cb) {
    if (options.breakpoints) {
        var css = '';
        css += '.' + options.prefix + '-wrapper {\n';
        css += '   margin: 0 auto;\n';
        css += '}\n';
        for (var key in options.breakpoints) {
            if (options.breakpoints.hasOwnProperty(key)) {
                css += '@media screen and (min-width: ' + options.breakpoints[key] + ') {\n';
                css += '    .' + options.prefix + '-wrapper {\n';
                if (options.wrapperBreakpoints.indexOf(key) > -1) {
                    css += '       max-width: ' + options.breakpoints[key] + ';\n';
                }
                css += '    }\n';
                css += '} \n';
            }
        }
        writeFile(dest, css, cb);
    } else {
        cb();
    }
}

function createGridOffset(dest, breakpoints, columns, prefix, cb) {
    if (breakpoints) {
        var css = '', nextBreakpoint = {};
        var key, last;
        for (key in breakpoints) {
            if (breakpoints.hasOwnProperty(key)) {
                if (last) {
                    nextBreakpoint[last] = breakpoints[key];
                }
                last = key;
            }
        }
        for (key in breakpoints) {
            if (breakpoints.hasOwnProperty(key)) {
                css += '@media screen and (min-width: ' + breakpoints[key] + ')' + (nextBreakpoint[key] ? ' and (max-width: ' + nextBreakpoint[key] + ')' : '') + ' {\n';
                for (var i = 1; i <= columns; i++) {
                    css += '   .' + prefix + '-' + key + '-offset-' + (i) + '-' + columns + ' {\n';
                    css += '       margin-left: ' + ((i / columns) * 100) + '\%;\n';
                    css += '   } \n';
                }
                css += '}\n';
            }
        }
        writeFile(dest, css, cb);
    } else {
        cb();
    }
}

function createCustomMediaVariables(dest, breakpoints, cb) {
    if (breakpoints) {
        var vars = '';
        for (var key in breakpoints) {
            if (breakpoints.hasOwnProperty(key)) {
                vars += '$screen-' + key + ': ' + breakpoints[key] + ';\n';
                vars += '@custom-media --screen-' + key + ' screen and (min-width: ' + breakpoints[key] + ');\n';
                // substract one pixel for max width
                vars += '@custom-media --screen-' + key + '-max screen and (max-width: ' + (parseInt(breakpoints[key]) - (1 / 16)) + 'em);\n';
            }
        }
        writeFile(dest, vars, cb);
    } else {
        cb();
    }
}

var getDirName = require("upath").dirname;

function writeFile(path, content, cb) {
    mkdirp(getDirName(path), function(err) {
        if (err) {
            return cb(err);
        }
        fs.writeFile(path, content, cb);
    });
}
<commit_msg>added visible hidden classes<commit_after>"use strict";

var rework = require('rework');
var reworkSelectors = require('rework-mutate-selectors');
var pureGrids = require('rework-pure-grids');
var mkdirp = require('mkdirp');
var fs = require('fs');
var upath = require('upath');

module.exports = function(config) {
    return function(cb) {
        if (config) {
            var destPath = upath.resolve(config.files.dest, 'purecss');
            createPureCSS({
                originPrefix: config.prefix,
                src: upath.resolve('node_modules', 'purecss', 'build'),
                dest: destPath,
                files: [].concat(config.files.src || [])
            }, function() {
                var prefix = [];
                if (config.columnHasPrefix) {
                    prefix.push(config.prefix);
                }
                if (config.columnPrefix) {
                    prefix.push(config.columnPrefix);
                }
                createGrid(upath.resolve(destPath, 'custom-grid.css'), config.breakpoints, prefix.join('-'), function() {
                    createGridOffset(upath.resolve(destPath, 'custom-grid-offset.css'), config.breakpoints, config.columns, prefix.join('-'), function() {
                        createGridWrapper(upath.resolve(destPath, 'custom-wrapper.css'), config, function() {
                            createVisibleHidden(upath.resolve(destPath, 'custom-visible-hidden.css'), config.breakpoints, prefix.join('-'), function() {
                                createCustomMediaVariables(upath.resolve(destPath, 'custom-media-variables.pcss'), config.breakpoints, function() {
                                    cb();
                                });
                            });
                        });
                    });
                });
            });
        }
    };
};

function createPureCSS(options, cb) {
    if (options.files) {
        var prefixFiles = function(cb) {
            if (options.files.length) {
                var file = options.files.pop();
                fs.readFile(upath.resolve(options.src, file + '.css'), 'utf8', function(err, data) {
                    var css = rework(data);
                    if (options.prefix) {
                        css.use(reworkSelectors.prefix(options.prefix));
                    }
                    if (options.originPrefix) {
                        css.use(reworkSelectors.replace(/^\.pure/g, '.' + options.originPrefix));
                    }
                    writeFile(upath.resolve(options.dest, file + '.css'), css.toString(), function() {
                        prefixFiles(cb);
                    });
                });
            } else {
                cb();
            }
        };
        prefixFiles(function() {
            cb();
        });
    } else {
        cb();
    }
}

function createGrid(dest, breakpoints, prefix, cb) {
    var mediaMap = {};
    for (var key in breakpoints) {
        if (breakpoints.hasOwnProperty(key)) {
            mediaMap[key] = 'screen and (min-width: ' + breakpoints[key] + ')';
        }
    }
    var css = rework('').use(pureGrids.units(12, {
        decimals: 4,
        includeOldIEWidths: false,
        includeReducedFractions: false,
        includeWholeNumbers: false,
        selectorPrefix: '.' + prefix + '-',
        mediaQueries: mediaMap
    })).toString();
    writeFile(dest, css, cb);
}

function createVisibleHidden(dest, breakpoints, prefix, cb) {
    var css = '';
    for (var key in breakpoints) {
        if (breakpoints.hasOwnProperty(key)) {
            css += '@media screen and (min-width: ' + breakpoints[key] + ') {\n';
            css += '  .visible-' + key + ' {\n';
            css += '    display: block;\n';
            css += '  }\n';
            css += '  .hidden-' + key + ' {\n';
            css += '    display: none;\n';
            css += '  }\n';
            css += '}\n';
        }
    }

    writeFile(dest, css, cb);
}

function createGridWrapper(dest, options, cb) {
    if (options.breakpoints) {
        var css = '';
        css += '.' + options.prefix + '-wrapper {\n';
        css += '  margin-left: auto;\n';
        css += '  margin-right: auto;\n';
        css += '}\n';
        for (var key in options.breakpoints) {
            if (options.breakpoints.hasOwnProperty(key)) {
                css += '\n/* ' + key + ' */\n';
                css += '@media screen and (min-width: ' + options.breakpoints[key] + ') {\n';
                css += '  .' + options.prefix + '-wrapper {\n';
                if (options.wrapperBreakpoints.indexOf(key) > -1) {
                    css += '  max-width: ' + options.breakpoints[key] + ';\n';
                }
                css += '  }\n';
                css += '} \n';
            }
        }
        writeFile(dest, css, cb);
    } else {
        cb();
    }
}

function createGridOffset(dest, breakpoints, columns, prefix, cb) {
    if (breakpoints) {
        var css = '',
            nextBreakpoint = {};
        var key, last;
        for (key in breakpoints) {
            if (breakpoints.hasOwnProperty(key)) {
                if (last) {
                    nextBreakpoint[last] = breakpoints[key];
                }
                last = key;
            }
        }
        var createClass = function(key, spacer) {
            spacer = spacer || '';
            for (var i = 0; i <= columns; i++) {
                css += spacer + '.' + prefix + (key ? '-' + key : '') + '-offset-' + i + '-' + columns + ' {\n';
                css += spacer + '  margin-left: ' + ((i / columns) * 100) + '\%;\n';
                css += spacer + '} \n';
            }
        };
        createClass();
        for (key in breakpoints) {
            if (breakpoints.hasOwnProperty(key)) {
                css += '@media screen and (min-width: ' + breakpoints[key] + ') {\n';
                createClass(key, '  ');
                css += '}\n';
            }
        }
        writeFile(dest, css, cb);
    } else {
        cb();
    }
}

function createCustomMediaVariables(dest, breakpoints, cb) {
    if (breakpoints) {
        var vars = '';
        for (var key in breakpoints) {
            if (breakpoints.hasOwnProperty(key)) {
                vars += '$screen-' + key + ': ' + breakpoints[key] + ';\n';
                vars += '@custom-media --screen-' + key + ' screen and (min-width: ' + breakpoints[key] + ');\n';
                // substract one pixel for max width
                vars += '@custom-media --screen-' + key + '-max screen and (max-width: ' + (parseInt(breakpoints[key]) - (1 / 16)) + 'em);\n';
            }
        }
        writeFile(dest, vars, cb);
    } else {
        cb();
    }
}

function writeFile(path, content, cb) {
    mkdirp(upath.dirname(path), function(err) {
        if (err) {
            return cb(err);
        }
        fs.writeFile(path, content, cb);
    });
}
<|endoftext|>


<commit_before>"use strict";

var rework = require('rework');
var reworkSelectors = require('rework-mutate-selectors');
var pureGrids = require('rework-pure-grids');
var mkdirp = require('mkdirp');
var fs = require('fs');
var upath = require('upath');

module.exports = function(config) {
    return function(cb) {
        if (config) {
            var destPath = upath.resolve(config.files.dest, 'purecss');
            createPureCSS({
                originPrefix: config.prefix,
                src: upath.resolve('node_modules', 'purecss', 'build'),
                dest: destPath,
                files: [].concat(config.files.src || [])
            }, function() {
                var prefix = [];
                if (config.columnHasPrefix) {
                    prefix.push(config.prefix);
                }
                if (config.columnPrefix) {
                    prefix.push(config.columnPrefix);
                }
                createGrid(upath.resolve(destPath, 'custom-grid.css'), config.breakpoints, prefix.join('-'), function() {
                    createGridGutter(upath.resolve(destPath, 'custom-grid-gutter.css'), prefix.join('-'), config, function() {
                        createGridOffset(upath.resolve(destPath, 'custom-grid-offset.css'), config.breakpoints, config.columns, prefix.join('-'), function() {
                            createGridWrapper(upath.resolve(destPath, 'custom-wrapper.css'), config, function() {
                                createVisibleHidden(upath.resolve(destPath, 'custom-visible-hidden.css'), config.breakpoints, config.prefix, function() {
                                    createCustomMediaVariables(upath.resolve(destPath, 'custom-media-variables.pcss'), config.breakpoints, function() {
                                        cb();
                                    });
                                });
                            });
                        });
                    });
                });
            });
        } else {
            cb();
        }
    };
};

function createPureCSS(options, cb) {
    if (options.files) {
        var prefixFiles = function(cb) {
            if (options.files.length) {
                var file = options.files.pop();
                fs.readFile(upath.resolve(options.src, file + '.css'), 'utf8', function(err, data) {
                    var css = rework(data);
                    if (options.prefix) {
                        css.use(reworkSelectors.prefix(options.prefix));
                    }
                    if (options.originPrefix) {
                        css.use(reworkSelectors.replace(/^\.pure/g, '.' + options.originPrefix));
                    }
                    writeFile(upath.resolve(options.dest, file + '.css'), css.toString(), function() {
                        prefixFiles(cb);
                    });
                });
            } else {
                cb();
            }
        };
        prefixFiles(function() {
            cb();
        });
    } else {
        cb();
    }
}

function createGrid(dest, breakpoints, prefix, cb) {
    var mediaMap = {};
    for (var key in breakpoints) {
        if (breakpoints.hasOwnProperty(key) && key !== 'default') {
            mediaMap[key] = 'screen and (min-width: ' + breakpoints[key].width + ')';
        }
    }
    var css = rework('').use(pureGrids.units(12, {
        decimals: 4,
        includeOldIEWidths: false,
        includeReducedFractions: false,
        includeWholeNumbers: false,
        selectorPrefix: '.' + prefix + '-',
        mediaQueries: mediaMap
    })).toString();
    writeFile(dest, css, cb);
}

function createVisibleHidden(dest, breakpoints, prefix, cb) {
    prefix = prefix ? prefix + '-' : '';
    var createClass = function(key, spacer) {
        key = key || '';
        spacer = spacer || '';
        css += spacer + '.' + prefix + 'visible' + key + ' {\n';
        css += spacer + '  display: inline-block;\n';
        css += spacer + '}\n';
        css += spacer + '.' + prefix + 'hidden' + key + ' {\n';
        css += spacer + '  display: none;\n';
        css += spacer + '}\n';
    };
    var css = '';
    for (var key in breakpoints) {
        if (breakpoints.hasOwnProperty(key)) {
            css += '\n/* ' + key + ' */\n';
            if (key === 'default') {
                createClass();
            } else {
                css += '@media screen and (min-width: ' + breakpoints[key].width + ') {\n';
                createClass('-' + key, '  ');
                css += '}\n';
            }
        }
    }
    writeFile(dest, css, cb);
}

function createGridWrapper(dest, options, cb) {
    if (options.breakpoints) {
        var css = '';
        for (var key in options.breakpoints) {
            if (options.breakpoints.hasOwnProperty(key)) {
                var breakpoint = options.breakpoints[key];
                css += '\n/* ' + key + ' */\n';
                if (breakpoint.wrapper) {
                    var wrapper = breakpoint.wrapper;
                    if (key === 'default') {
                        // Normal Wrapper
                        css += '.' + options.prefix + '-wrapper {\n';
                        if (wrapper.margin) {
                            css += '  margin-left: ' + wrapper.margin + ';\n';
                            css += '  margin-right: ' + wrapper.margin + ';\n';
                        }
                        if (wrapper["max-width"]) {
                            css += '  max-width: ' + wrapper["max-width"] + ';\n';
                        }
                        if (wrapper.overflow) {
                            css += '  overflow: ' + wrapper.overflow + ';\n';
                        }
                        css += '}\n';
                        // Fullscreen Wrapper
                        if (wrapper.margin && /^([0-9]|px|pt|em|rem|%|vw|vh)+$/.test(wrapper.margin)) {
                            css += '.' + options.prefix + '-wrapper-fullscreen {\n';
                            css += '  margin-left: -' + wrapper.margin + ';\n';
                            css += '  margin-right: -' + wrapper.margin + ';\n';
                            css += '}\n';
                        }
                    } else {
                        css += '@media screen and (min-width: ' + breakpoint.width + ') {\n';
                        // Normal Wrapper
                        css += '  .' + options.prefix + '-wrapper {\n';
                        if (wrapper.margin) {
                            css += '    margin-left: ' + wrapper.margin + ';\n';
                            css += '    margin-right: ' + wrapper.margin + ';\n';
                        }
                        if (wrapper["max-width"]) {
                            css += '    max-width: ' + wrapper["max-width"] + ';\n';
                        }
                        if (wrapper.overflow) {
                            css += '    overflow: ' + wrapper.overflow + ';\n';
                        }
                        css += '  }\n';
                        // Fullscreen Wrapper
                        if (wrapper.margin && /^([0-9]|px|pt|em|rem|%|vw|vh)+$/.test(wrapper.margin)) {
                            css += '  .' + options.prefix + '-wrapper-fullscreen {\n';
                            css += '    margin-left: -' + wrapper.margin + ';\n';
                            css += '    margin-right: -' + wrapper.margin + ';\n';
                            css += '  }\n';
                        }
                        css += '} \n';
                    }
                }
            }
        }
        writeFile(dest, css, cb);
    } else {
        cb();
    }
}

function createGridGutter(dest, prefix, options, cb) {
    if (options.breakpoints && prefix) {
        prefix = prefix ? prefix + '-' : '';
        var css = '';
        for (var key in options.breakpoints) {
            if (options.breakpoints.hasOwnProperty(key)) {
                var breakpoint = options.breakpoints[key];
                if (breakpoint.gutterWidth) {
                    css += '\n/* ' + key + ' */\n';
                    if (key === 'default') {
                        css += '[class*="' + prefix + '"] {\n';
                        css += '  box-sizing: border-box;\n';
                        css += '  padding-left: ' + breakpoint.gutterWidth + ';\n';
                        css += '  padding-right: ' + breakpoint.gutterWidth + ';\n';
                        css += '}\n';
                        css += '.grid-g {\n';
                        css += '  margin: 0 -' + breakpoint.gutterWidth + ';\n';
                        css += '}\n';
                    } else {
                        css += '@media screen and (min-width: ' + breakpoint.width + ') {\n';
                        css += '  [class*="' + prefix + '"] {\n';
                        css += '    padding-left: ' + breakpoint.gutterWidth + ';\n';
                        css += '    padding-right: ' + breakpoint.gutterWidth + ';\n';
                        css += '  }\n';
                        css += '  .grid-g {\n';
                        css += '    margin: 0 -' + breakpoint.gutterWidth + ';\n';
                        css += '  }\n';
                        css += '}\n';
                    }
                }
            }
        }
        writeFile(dest, css, cb);
    } else {
        cb();
    }
}

function createGridOffset(dest, breakpoints, columns, prefix, cb) {
    if (breakpoints) {
        var css = '';
        var createClass = function(key, spacer) {
            key = key || '';
            spacer = spacer || '';
            for (var i = 0; i <= columns; i++) {
                css += spacer + '.' + prefix + key + '-offset-' + i + '-' + columns + ' {\n';
                css += spacer + '  margin-left: ' + ((i / columns) * 100) + '\%;\n';
                css += spacer + '} \n';
            }
        };
        createClass();
        for (var key in breakpoints) {
            if (breakpoints.hasOwnProperty(key) && key !== 'default') {
                css += '\n/* ' + key + ' */\n';
                css += '@media screen and (min-width: ' + breakpoints[key].width + ') {\n';
                createClass('-' + key, '  ');
                css += '}\n';
            }
        }
        writeFile(dest, css, cb);
    } else {
        cb();
    }
}

function createCustomMediaVariables(dest, breakpoints, cb) {
    if (breakpoints) {
        var vars = '',
            nextBreakpoint = {},
            key, last;
        for (key in breakpoints) {
            if (breakpoints.hasOwnProperty(key)) {
                if (last) {
                    nextBreakpoint[last] = breakpoints[key];
                }
                last = key;
            }
        }
        for (key in breakpoints) {
            if (breakpoints.hasOwnProperty(key)) {
                if (key !== 'default') {
                    if ('gutterWidth' in breakpoints[key]) {
                        vars += '$gutter-' + key + '-width: ' + breakpoints[key].gutterWidth + ';\n';
                    }
                    vars += '$screen-' + key + ': ' + breakpoints[key].width + ';\n';
                    vars += '@custom-media --screen-' + key + ' screen and (min-width: ' + breakpoints[key].width + ');\n';
                    if (nextBreakpoint[key]) {
                        // substract one pixel for max width
                        vars += '@custom-media --screen-' + key + '-max screen and (max-width: ' + (parseInt(nextBreakpoint[key].width) - (1 / 16)) + 'rem);\n';
                    }
                    vars += '\n';
                } else {
                    if ('gutterWidth' in breakpoints[key]) {
                        vars += '$gutter-width: ' + breakpoints[key].gutterWidth + ';\n';
                    }
                    if ('width' in breakpoints[key]) {
                        vars += '$screen: ' + breakpoints[key].width + ';\n\n';
                    }
                }
            }
        }
        writeFile(dest, vars, cb);
    } else {
        cb();
    }
}

function writeFile(path, content, cb) {
    mkdirp(upath.dirname(path), function(err) {
        if (err) {
            return cb(err);
        }
        fs.writeFile(path, content, cb);
    });
}
<commit_msg>added purecss screen var only number<commit_after>"use strict";

var rework = require('rework');
var reworkSelectors = require('rework-mutate-selectors');
var pureGrids = require('rework-pure-grids');
var mkdirp = require('mkdirp');
var fs = require('fs');
var upath = require('upath');

module.exports = function(config) {
    return function(cb) {
        if (config) {
            var destPath = upath.resolve(config.files.dest, 'purecss');
            createPureCSS({
                originPrefix: config.prefix,
                src: upath.resolve('node_modules', 'purecss', 'build'),
                dest: destPath,
                files: [].concat(config.files.src || [])
            }, function() {
                var prefix = [];
                if (config.columnHasPrefix) {
                    prefix.push(config.prefix);
                }
                if (config.columnPrefix) {
                    prefix.push(config.columnPrefix);
                }
                createGrid(upath.resolve(destPath, 'custom-grid.css'), config.breakpoints, prefix.join('-'), function() {
                    createGridGutter(upath.resolve(destPath, 'custom-grid-gutter.css'), prefix.join('-'), config, function() {
                        createGridOffset(upath.resolve(destPath, 'custom-grid-offset.css'), config.breakpoints, config.columns, prefix.join('-'), function() {
                            createGridWrapper(upath.resolve(destPath, 'custom-wrapper.css'), config, function() {
                                createVisibleHidden(upath.resolve(destPath, 'custom-visible-hidden.css'), config.breakpoints, config.prefix, function() {
                                    createCustomMediaVariables(upath.resolve(destPath, 'custom-media-variables.pcss'), config.breakpoints, function() {
                                        cb();
                                    });
                                });
                            });
                        });
                    });
                });
            });
        } else {
            cb();
        }
    };
};

function createPureCSS(options, cb) {
    if (options.files) {
        var prefixFiles = function(cb) {
            if (options.files.length) {
                var file = options.files.pop();
                fs.readFile(upath.resolve(options.src, file + '.css'), 'utf8', function(err, data) {
                    var css = rework(data);
                    if (options.prefix) {
                        css.use(reworkSelectors.prefix(options.prefix));
                    }
                    if (options.originPrefix) {
                        css.use(reworkSelectors.replace(/^\.pure/g, '.' + options.originPrefix));
                    }
                    writeFile(upath.resolve(options.dest, file + '.css'), css.toString(), function() {
                        prefixFiles(cb);
                    });
                });
            } else {
                cb();
            }
        };
        prefixFiles(function() {
            cb();
        });
    } else {
        cb();
    }
}

function createGrid(dest, breakpoints, prefix, cb) {
    var mediaMap = {};
    for (var key in breakpoints) {
        if (breakpoints.hasOwnProperty(key) && key !== 'default') {
            mediaMap[key] = 'screen and (min-width: ' + breakpoints[key].width + ')';
        }
    }
    var css = rework('').use(pureGrids.units(12, {
        decimals: 4,
        includeOldIEWidths: false,
        includeReducedFractions: false,
        includeWholeNumbers: false,
        selectorPrefix: '.' + prefix + '-',
        mediaQueries: mediaMap
    })).toString();
    writeFile(dest, css, cb);
}

function createVisibleHidden(dest, breakpoints, prefix, cb) {
    prefix = prefix ? prefix + '-' : '';
    var createClass = function(key, spacer) {
        key = key || '';
        spacer = spacer || '';
        css += spacer + '.' + prefix + 'visible' + key + ' {\n';
        css += spacer + '  display: inline-block;\n';
        css += spacer + '}\n';
        css += spacer + '.' + prefix + 'hidden' + key + ' {\n';
        css += spacer + '  display: none;\n';
        css += spacer + '}\n';
    };
    var css = '';
    for (var key in breakpoints) {
        if (breakpoints.hasOwnProperty(key)) {
            css += '\n/* ' + key + ' */\n';
            if (key === 'default') {
                createClass();
            } else {
                css += '@media screen and (min-width: ' + breakpoints[key].width + ') {\n';
                createClass('-' + key, '  ');
                css += '}\n';
            }
        }
    }
    writeFile(dest, css, cb);
}

function createGridWrapper(dest, options, cb) {
    if (options.breakpoints) {
        var css = '';
        for (var key in options.breakpoints) {
            if (options.breakpoints.hasOwnProperty(key)) {
                var breakpoint = options.breakpoints[key];
                css += '\n/* ' + key + ' */\n';
                if (breakpoint.wrapper) {
                    var wrapper = breakpoint.wrapper;
                    if (key === 'default') {
                        // Normal Wrapper
                        css += '.' + options.prefix + '-wrapper {\n';
                        if (wrapper.margin) {
                            css += '  margin-left: ' + wrapper.margin + ';\n';
                            css += '  margin-right: ' + wrapper.margin + ';\n';
                        }
                        if (wrapper["max-width"]) {
                            css += '  max-width: ' + wrapper["max-width"] + ';\n';
                        }
                        if (wrapper.overflow) {
                            css += '  overflow: ' + wrapper.overflow + ';\n';
                        }
                        css += '}\n';
                        // Fullscreen Wrapper
                        if (wrapper.margin && /^([0-9]|px|pt|em|rem|%|vw|vh)+$/.test(wrapper.margin)) {
                            css += '.' + options.prefix + '-wrapper-fullscreen {\n';
                            css += '  margin-left: -' + wrapper.margin + ';\n';
                            css += '  margin-right: -' + wrapper.margin + ';\n';
                            css += '}\n';
                        }
                    } else {
                        css += '@media screen and (min-width: ' + breakpoint.width + ') {\n';
                        // Normal Wrapper
                        css += '  .' + options.prefix + '-wrapper {\n';
                        if (wrapper.margin) {
                            css += '    margin-left: ' + wrapper.margin + ';\n';
                            css += '    margin-right: ' + wrapper.margin + ';\n';
                        }
                        if (wrapper["max-width"]) {
                            css += '    max-width: ' + wrapper["max-width"] + ';\n';
                        }
                        if (wrapper.overflow) {
                            css += '    overflow: ' + wrapper.overflow + ';\n';
                        }
                        css += '  }\n';
                        // Fullscreen Wrapper
                        if (wrapper.margin && /^([0-9]|px|pt|em|rem|%|vw|vh)+$/.test(wrapper.margin)) {
                            css += '  .' + options.prefix + '-wrapper-fullscreen {\n';
                            css += '    margin-left: -' + wrapper.margin + ';\n';
                            css += '    margin-right: -' + wrapper.margin + ';\n';
                            css += '  }\n';
                        }
                        css += '} \n';
                    }
                }
            }
        }
        writeFile(dest, css, cb);
    } else {
        cb();
    }
}

function createGridGutter(dest, prefix, options, cb) {
    if (options.breakpoints && prefix) {
        prefix = prefix ? prefix + '-' : '';
        var css = '';
        for (var key in options.breakpoints) {
            if (options.breakpoints.hasOwnProperty(key)) {
                var breakpoint = options.breakpoints[key];
                if (breakpoint.gutterWidth) {
                    css += '\n/* ' + key + ' */\n';
                    if (key === 'default') {
                        css += '[class*="' + prefix + '"] {\n';
                        css += '  box-sizing: border-box;\n';
                        css += '  padding-left: ' + breakpoint.gutterWidth + ';\n';
                        css += '  padding-right: ' + breakpoint.gutterWidth + ';\n';
                        css += '}\n';
                        css += '.grid-g {\n';
                        css += '  margin: 0 -' + breakpoint.gutterWidth + ';\n';
                        css += '}\n';
                    } else {
                        css += '@media screen and (min-width: ' + breakpoint.width + ') {\n';
                        css += '  [class*="' + prefix + '"] {\n';
                        css += '    padding-left: ' + breakpoint.gutterWidth + ';\n';
                        css += '    padding-right: ' + breakpoint.gutterWidth + ';\n';
                        css += '  }\n';
                        css += '  .grid-g {\n';
                        css += '    margin: 0 -' + breakpoint.gutterWidth + ';\n';
                        css += '  }\n';
                        css += '}\n';
                    }
                }
            }
        }
        writeFile(dest, css, cb);
    } else {
        cb();
    }
}

function createGridOffset(dest, breakpoints, columns, prefix, cb) {
    if (breakpoints) {
        var css = '';
        var createClass = function(key, spacer) {
            key = key || '';
            spacer = spacer || '';
            for (var i = 0; i <= columns; i++) {
                css += spacer + '.' + prefix + key + '-offset-' + i + '-' + columns + ' {\n';
                css += spacer + '  margin-left: ' + ((i / columns) * 100) + '\%;\n';
                css += spacer + '} \n';
            }
        };
        createClass();
        for (var key in breakpoints) {
            if (breakpoints.hasOwnProperty(key) && key !== 'default') {
                css += '\n/* ' + key + ' */\n';
                css += '@media screen and (min-width: ' + breakpoints[key].width + ') {\n';
                createClass('-' + key, '  ');
                css += '}\n';
            }
        }
        writeFile(dest, css, cb);
    } else {
        cb();
    }
}

function createCustomMediaVariables(dest, breakpoints, cb) {
    if (breakpoints) {
        var vars = '',
            nextBreakpoint = {},
            key, last;
        for (key in breakpoints) {
            if (breakpoints.hasOwnProperty(key)) {
                if (last) {
                    nextBreakpoint[last] = breakpoints[key];
                }
                last = key;
            }
        }
        for (key in breakpoints) {
            if (breakpoints.hasOwnProperty(key)) {
                if (key !== 'default') {
                    if ('gutterWidth' in breakpoints[key]) {
                        vars += '$gutter-' + key + '-width: ' + breakpoints[key].gutterWidth + ';\n';
                    }
                    vars += '$screen-' + key + '-value: ' + breakpoints[key].width.replace(/^([0-9]+).*$/, '$1') + ';\n';
                    vars += '$screen-' + key + ': ' + breakpoints[key].width + ';\n';
                    vars += '@custom-media --screen-' + key + ' screen and (min-width: ' + breakpoints[key].width + ');\n';
                    if (nextBreakpoint[key]) {
                        // substract one pixel for max width
                        vars += '@custom-media --screen-' + key + '-max screen and (max-width: ' + (parseInt(nextBreakpoint[key].width) - (1 / 16)) + 'rem);\n';
                    }
                    vars += '\n';
                } else {
                    if ('gutterWidth' in breakpoints[key]) {
                        vars += '$gutter-width: ' + breakpoints[key].gutterWidth + ';\n';
                    }
                    if ('width' in breakpoints[key]) {
                        vars += '$screen: ' + breakpoints[key].width + ';\n\n';
                    }
                }
            }
        }
        writeFile(dest, vars, cb);
    } else {
        cb();
    }
}

function writeFile(path, content, cb) {
    mkdirp(upath.dirname(path), function(err) {
        if (err) {
            return cb(err);
        }
        fs.writeFile(path, content, cb);
    });
}
<|endoftext|>


<commit_before>var crypto      = require('crypto')
  , util        = require('util')
  , _           = require('underscore');

var TaskScheduler           = {}
  , handlers                = {}
  , taskPlugin
  , errBrokenTaskPluginMsg  = "Task plugin is not properly initialized. Aborting. "
  , brokenTaskPlugin        = true;

/**
 * @type {number} Number of milliseconds between reads from the queue service
 */
var jobInterval = 0;

/**
* @taskPlugin - a task management plugin to put tasks on a queeu.
*               @See: https://github.com/publicmediaplatform/sqstask
*/
TaskScheduler = function(taskPluginParam) {
  var brokenPlugin = isBrokenTaskPlugin(taskPluginParam);
  if (brokenPlugin) {
    throw new Error("Error: " + brokenPlugin);
  } else {
    taskPlugin = taskPluginParam;
  }

  return exports;
};

/**
* Adds a handler callback to a topic.
*
* @param topic
*   Topic name. Any unique string
* @param jobFunction
*   A javascript function that will be called every @interval (see below) milliseconds.
*
* @param cleanupCallback
*   A javascript function that jobFunction will continue to passing along the "err" object. This function's purpose is to do cleanup.
*   Often single cleanup function is relevant for many task types, that is why this is separate. This functionality is heavily used
*   by SQS Task plugin, for instance, which uses cleanup to remove initial message from the message queue.
*
* @interval
*   Time interval (in milliseconds) that callback will be called for the topic.
*
* @return A unique identifier of the callback that can be used in the future to de-register the handler function.
*/
TaskScheduler.addTopicHandler = function(topic, jobFunction, interval) {

  if (!taskPlugin) {
    throw new Error(errBrokenTaskPluginMsg);
    return;
  }

  if(interval && _.isNumber(interval)) {
    jobInterval = interval;
  }

  var funcSalt  = jobFunction.toString() + topic + new Date().getTime()
    , handlerID = crypto.createHash('md5').update(funcSalt).digest("hex");

  // Make sure this handler was not already attached and attach:
  // TODO: Fix how jobs are stopped since we are no longer using setInterval
  if ('undefined' === typeof handlers[handlerID]) {
    queueNextJob(jobFunction, topic);
    handlers[handlerID] = { "jobFunction"     : jobFunction
                          , "topic"           : topic
                          , "interval"        : jobInterval
                          , "timerID"         : 0};

  }

  return handlerID;
};

/**
* De-register a topic handler callback by the unique ID that was generated
* when the handler was attached to the topic.
*
* Returns true if de-registering was successful, false otherwise.
*/
TaskScheduler.removeTopicHandler = function(handlerID) {

  if (!taskPlugin) {
    throw new Error(errBrokenTaskPluginMsg);
    return;
  }

  // Does the handler exist?
  if ('undefined' === typeof handlers[handlerID]) {
    return false
  }

  var timerID = handlers[handlerID].timerID;
  clearInterval(timerID);
  delete handlers[handlerID];
  return true;
}

/**
* Check if a topic exists, create if it doesn't
*/
TaskScheduler.topicEnsureExists = function(topic, callback) {
  taskPlugin.topicEnsureExists(topic, function(err) {
    callback(err);
  });
}

/**
* Send a message to the queue
*/
TaskScheduler.message = function(topic, message, callback) {
  taskPlugin.put(topic, message, function(err) {
    callback(err);
  });
}

/**
* Message class. Every plugin MUST extend this properly, with:
* Message.prototype.__proto__ = scheduler.Message.prototype;
*/
TaskScheduler.Message = function(body, id) {
  this.body = body || "";
  this.id   = id || null;
}
TaskScheduler.Message.prototype.del     = function(callback) {};
TaskScheduler.Message.prototype.release = function(callback) {};

exports = module.exports = TaskScheduler;

//---- Private functions.
//---- These are defined as regular functions so that they don't need to be declared before they are used!

/**
* A callback that wraps custom job functions to provide centralized post-job cleanup: delete message
* from a queue if a job was successful and/or re-post a job on the queue, so it can be retried, if
* the job was unsuccessful.
*
* @TODO: add max_number_or_retries to reposting a job to the queue.
*/
function jobFunctionWrapper(jobFunction, topic) {

  taskPlugin.get(topic, function(err, message) {
    if (('undefined' != typeof message) && ('undefined' !== typeof message.body) && message.body) {
      jobFunction(topic, message.body, function cleanupCallback(err) {
        if (!err) {
          message.del(function(err) {
            if (err) util.log("Error deleting a message: " + util.inspect(err));
            //util.log("DELETED: " + message.body);
          });
          // Queue next job before delete
          queueNextJob(jobFunction, topic);
          return;
        } else { // release message back to the queue
          util.log("Job processing error. Releasing message: " + message.body);
          message.release(function(err2) {
            if (err2) util.log(util.inspect(err2));
            queueNextJob(jobFunction, topic);
            return;
          });
        }
      });
    } else {
      queueNextJob(jobFunction, topic);
    }
  });
}

/**
 * Start the next read from the queue, waiting 'jobInterval' milliseconds
 * TODO: setup a way to stop the next job from executing
 *
 * @param jobFunction
 * @param topic
 */
function queueNextJob(jobFunction, topic) {
  setTimeout(jobFunctionWrapper, jobInterval, jobFunction, topic);
}

function isBrokenTaskPlugin(taskPlugin) {
  var err = false;

  if (typeof taskPlugin  !== 'function') {
    err = "Task plugin is empty or not a proper function/object.";
  }

  if (typeof taskPlugin.get  !== 'function') {
    err = "Task plugin doesn't export a get() function.";
  }

  if (typeof taskPlugin.put  !== 'function') {
    err = "Task plugin doesn't export a put() function.";
  }

  if (typeof taskPlugin.topicEnsureExists  !== 'function') {
    err = "Task plugin doesn't export a topicEnsureExists() function.";
  }

  if (typeof taskPlugin.Message.prototype.del  !== 'function') {
    err = "Task plugin doesn't export a del() function on a message class.";
  }

  if (typeof taskPlugin.Message.prototype.release  !== 'function') {
    err = "Task plugin doesn't export a del() function on a message class.";
  }

  return err;
}
<commit_msg>Added worker suicide functionality<commit_after>var crypto      = require('crypto')
  , util        = require('util')
  , _           = require('underscore');

var TaskScheduler           = {}
  , handlers                = {}
  , taskPlugin
  , errBrokenTaskPluginMsg  = "Task plugin is not properly initialized. Aborting. "
  , brokenTaskPlugin        = true;

/**
 * @type {number} Number of milliseconds between reads from the queue service
 */
var jobInterval = 0;

/**
 * @type {number} Number of poll failures before workers kill themselves. Set to 0 for non-suicidal workers.
 * Useful if managing worker lifecycle dynamically.
 */
var workerSuicide = 0;

/**
* @taskPlugin - a task management plugin to put tasks on a queeu.
*               @See: https://github.com/publicmediaplatform/sqstask
*/
TaskScheduler = function(taskPluginParam, maxAttempts) {
  var brokenPlugin = isBrokenTaskPlugin(taskPluginParam);
  if (brokenPlugin) {
    throw new Error("Error: " + brokenPlugin);
  } else {
    taskPlugin = taskPluginParam;
  }
  if(maxAttempts)
  {
    workerSuicide = parseInt(maxAttempts);
  }

  return exports;
};

/**
* Adds a handler callback to a topic.
*
* @param topic
*   Topic name. Any unique string
* @param jobFunction
*   A javascript function that will be called every @interval (see below) milliseconds.
*
* @param cleanupCallback
*   A javascript function that jobFunction will continue to passing along the "err" object. This function's purpose is to do cleanup.
*   Often single cleanup function is relevant for many task types, that is why this is separate. This functionality is heavily used
*   by SQS Task plugin, for instance, which uses cleanup to remove initial message from the message queue.
*
* @interval
*   Time interval (in milliseconds) that callback will be called for the topic.
*
* @return A unique identifier of the callback that can be used in the future to de-register the handler function.
*/
TaskScheduler.addTopicHandler = function(topic, jobFunction, interval) {

  if (!taskPlugin) {
    throw new Error(errBrokenTaskPluginMsg);
    return;
  }

  if(interval && _.isNumber(interval)) {
    jobInterval = interval;
  }

  var funcSalt  = jobFunction.toString() + topic + new Date().getTime()
    , handlerID = crypto.createHash('md5').update(funcSalt).digest("hex");

  // Make sure this handler was not already attached and attach:
  // TODO: Fix how jobs are stopped since we are no longer using setInterval
  if ('undefined' === typeof handlers[handlerID]) {
    queueNextJob(jobFunction, topic, handlerID);
    handlers[handlerID] = { "jobFunction"     : jobFunction
                          , "topic"           : topic
                          , "interval"        : jobInterval
                          , "timerID"         : 0
                          , "pollFailures"    : 0};

  }

  return handlerID;
};

/**
* De-register a topic handler callback by the unique ID that was generated
* when the handler was attached to the topic.
*
* Returns true if de-registering was successful, false otherwise.
*/
TaskScheduler.removeTopicHandler = function(handlerID) {

  if (!taskPlugin) {
    throw new Error(errBrokenTaskPluginMsg);
    return;
  }

  // Does the handler exist?
  if ('undefined' === typeof handlers[handlerID]) {
    return false
  }

  var timerID = handlers[handlerID].timerID;
  clearInterval(timerID);
  delete handlers[handlerID];
  return true;
}

/**
* Check if a topic exists, create if it doesn't
*/
TaskScheduler.topicEnsureExists = function(topic, callback) {
  taskPlugin.topicEnsureExists(topic, function(err) {
    callback(err);
  });
}

/**
* Send a message to the queue
*/
TaskScheduler.message = function(topic, message, callback) {
  taskPlugin.put(topic, message, function(err) {
    callback(err);
  });
}

/**
* Message class. Every plugin MUST extend this properly, with:
* Message.prototype.__proto__ = scheduler.Message.prototype;
*/
TaskScheduler.Message = function(body, id) {
  this.body = body || "";
  this.id   = id || null;
}
TaskScheduler.Message.prototype.del     = function(callback) {};
TaskScheduler.Message.prototype.release = function(callback) {};

exports = module.exports = TaskScheduler;

//---- Private functions.
//---- These are defined as regular functions so that they don't need to be declared before they are used!

/**
* A callback that wraps custom job functions to provide centralized post-job cleanup: delete message
* from a queue if a job was successful and/or re-post a job on the queue, so it can be retried, if
* the job was unsuccessful.
*
* @TODO: add max_number_or_retries to reposting a job to the queue.
*/
function jobFunctionWrapper(jobFunction, topic, handlerID) {

  taskPlugin.get(topic, function(err, message) {
    if (('undefined' != typeof message) && ('undefined' !== typeof message.body) && message.body) {
      jobFunction(topic, message.body, function cleanupCallback(err) {
        if (!err) {
          // reset failure attempts
          handlers[handlerID].pollFailures = 0;
          message.del(function(err) {
            if (err) util.log("Error deleting a message: " + util.inspect(err));
            //util.log("DELETED: " + message.body);
          });
          // Queue next job before delete
          queueNextJob(jobFunction, topic, handlerID);
          return;
        } else { // release message back to the queue
          util.log("Job processing error. Releasing message: " + message.body);
          message.release(function(err2) {
            if (err2) util.log(util.inspect(err2));
            handlers[handlerID].pollFailures++;
            queueNextJob(jobFunction, topic, handlerID);
            return;
          });
        }
      });
    } else {
      handlers[handlerID].pollFailures++;
      queueNextJob(jobFunction, topic, handlerID);
    }
  });
}

/**
 * Start the next read from the queue, waiting 'jobInterval' milliseconds
 * TODO: setup a way to stop the next job from executing
 *
 * @param jobFunction
 * @param topic
 */
function queueNextJob(jobFunction, topic, handlerID) {
  if(workerSuicide !== 0 && handlers[handlerID].pollFailures >= workerSuicide)
  {
    // stop the cycle of madness
    return;
  }
  setTimeout(jobFunctionWrapper, jobInterval, jobFunction, topic, handlerID);
}

function isBrokenTaskPlugin(taskPlugin) {
  var err = false;

  if (typeof taskPlugin  !== 'function') {
    err = "Task plugin is empty or not a proper function/object.";
  }

  if (typeof taskPlugin.get  !== 'function') {
    err = "Task plugin doesn't export a get() function.";
  }

  if (typeof taskPlugin.put  !== 'function') {
    err = "Task plugin doesn't export a put() function.";
  }

  if (typeof taskPlugin.topicEnsureExists  !== 'function') {
    err = "Task plugin doesn't export a topicEnsureExists() function.";
  }

  if (typeof taskPlugin.Message.prototype.del  !== 'function') {
    err = "Task plugin doesn't export a del() function on a message class.";
  }

  if (typeof taskPlugin.Message.prototype.release  !== 'function') {
    err = "Task plugin doesn't export a del() function on a message class.";
  }

  return err;
}
<|endoftext|>


<commit_before>//       telegram.link
//
//       Copyright 2014 Enrico Stara 'enrico.stara@gmail.com'
//       Released under the MIT license
//       http://telegram.link

//      TelegramLink class
//
// This is the entry-point of Telegram.link library, and it lists high level methods to communicate
// with `TELEGRAM MESSANGER`

// Print library version
require('colors');
console.log(require('./static').signature.blue);
console.log(('v.%s', require('../package.json').version).blue);

// Export the class
module.exports = exports = TelegramLink;

// Export modules
exports.mtproto = require('./mtproto');
exports.net = require('./net');
exports.type_language = require('./type_language');
exports.util = require('./util');
exports.crypto = require('./crypto');

// Import dependencies
var crypto = exports.crypto;
var TcpConnection = exports.net.TcpConnection;
var AbstractObject = exports.type_language.AbstractObject;
var mtproto = exports.mtproto;
var util = exports.util;

// The constructor requires a primary telegram DataCenter address as argument
function TelegramLink(primaryDC) {
    this._connection = new TcpConnection(primaryDC);
}

// The method creates a connection to the DataCenter,
// you provide callback functions to know when is done or to catch an error
TelegramLink.prototype.connect = function (callback, errorback) {
    this._connection.connect(callback, errorback);
};

// The method gets a first authorization from the DataCenter,
// you provide callback functions to know when is done or to catch an error
TelegramLink.prototype.authorization = function (callback, errorback) {
    var logger = exports.util.Logger('TelegramLink.authorization');

    // Create a nonce for the client
    var clientNonce = crypto.createNonce(16);

    // Request a PQ pair number
    mtproto.req_pq({
        props: {
            nonce: clientNonce
        },
        conn: this._connection,
        callback: function (resPQ) {
            logger.debug('\'nonce\' check: %s == %s ? %s', clientNonce, resPQ.nonce, clientNonce == resPQ.nonce);

            // Find P and Q from PQ pair
            var pqFinder = new crypto.PQFinder(resPQ.pq);
            logger.debug('Start finding P and Q, with PQ = %s', pqFinder.getPQPairNumber());
            var pq = pqFinder.findPQ();
            logger.debug('Found P = %s and Q = %s', pq[0], pq[1]);

            // Find the correct Public Key using fingerprint from server response
            var publicKey;
            var fingerprints = resPQ.server_public_key_fingerprints.getList();
            var fingerprint;
            logger.debug('Public keys fingerprints from server: %s', fingerprints);
            for (var i = 0; i < fingerprints.length; i++) {
                fingerprint = fingerprints[i];
                logger.debug('Searching fingerprint %s in store', fingerprint);
                publicKey = crypto.PublicKey.retrieveKey(fingerprint);
                if (publicKey) {
                    logger.debug("Fingerprint %s found in keyStore.", fingerprint);
                    break;
                } else {
                    logger.warn("Fingerprint %s from server not found in keyStore.", fingerprint);
                    errorback();
                }
            }

            // Create the pq_inner_data buffer
            var pqAsBuffer = pqFinder.getPQAsBuffer();
            var newNonce32 = crypto.createNonce(32);
            var serverNonce = resPQ.server_nonce;
            var pqInnerData = new mtproto.P_Q_inner_data({props: {
                pq: resPQ.pq,
                p: pqAsBuffer[0],
                q: pqAsBuffer[1],
                nonce: clientNonce,
                server_nonce: serverNonce,
                new_nonce: newNonce32
            }}).serialize();

            // Create the data with hash to be encrypt
            var hash = crypto.createSHA1Hash(pqInnerData);
            var dataWithHash = Buffer.concat([hash, pqInnerData]);
            logger.debug('Data to be encrypt contain: hash(%s), pqInnerData(%s), total length %s',
                hash.length, pqInnerData.length, dataWithHash.length);

            // Encrypt data with RSA
            var encryptedData = crypto.rsaEncrypt({message: dataWithHash, key: publicKey});

            // Request server DH parameters
            mtproto.req_DH_params({
                props: {
                    nonce: clientNonce,
                    server_nonce: serverNonce,
                    p: pqAsBuffer[0],
                    q: pqAsBuffer[1],
                    public_key_fingerprint: fingerprint,
                    encrypted_data: encryptedData
                },
                conn: this._connection,
                callback: function (serverDHParams) {

                    callback(serverDHParams);

                }.bind(this),
                errorback: function (e) {
                    logger.error('Received exception %s', e);
                    errorback(e);
                }
            });

        }.bind(this),
        errorback: function (e) {
            logger.error('Received exception %s', e);
            errorback(e);
        }
    });

};

// The method closes the communication with the DataCenter,
// you can provide a callback function to know when is done or to catch an error
TelegramLink.prototype.end = function (callback, errorback) {
    this._connection.close(callback, errorback);
};
<commit_msg>Update log message in telegram.link main class<commit_after>//       telegram.link
//
//       Copyright 2014 Enrico Stara 'enrico.stara@gmail.com'
//       Released under the MIT license
//       http://telegram.link

//      TelegramLink class
//
// This is the entry-point of Telegram.link library, and it lists high level methods to communicate
// with `TELEGRAM MESSANGER`

// Print library version
require('colors');
console.log(require('./static').signature.blue);
console.log(('v.%s', require('../package.json').version).blue);

// Export the class
module.exports = exports = TelegramLink;

// Export modules
exports.mtproto = require('./mtproto');
exports.net = require('./net');
exports.type_language = require('./type_language');
exports.util = require('./util');
exports.crypto = require('./crypto');

// Import dependencies
var crypto = exports.crypto;
var TcpConnection = exports.net.TcpConnection;
var HttpConnection = exports.net.HttpConnection;
var AbstractObject = exports.type_language.AbstractObject;
var mtproto = exports.mtproto;
var util = exports.util;

// The constructor requires a primary telegram DataCenter address as argument
function TelegramLink(primaryDC) {
    this._connection = new TcpConnection(primaryDC);
/*
    this._connection = new HttpConnection({
        proxyHost: process.env.PROXY_HOST,
        proxyPort: process.env.PROXY_PORT,
        host: primaryDC.host,
        port: primaryDC.port
    });
*/
}

// The method creates a connection to the DataCenter,
// you provide callback functions to know when is done or to catch an error
TelegramLink.prototype.connect = function (callback, errorback) {
    this._connection.connect(callback, errorback);
};

// The method gets a first authorization from the DataCenter,
// you provide callback functions to know when is done or to catch an error
TelegramLink.prototype.authorization = function (callback, errorback) {
    var logger = exports.util.Logger('TelegramLink.authorization');

    // Create a nonce for the client
    var clientNonce = crypto.createNonce(16);

    // Request a PQ pair number
    mtproto.req_pq({
        props: {
            nonce: clientNonce
        },
        conn: this._connection,
        callback: function (resPQ) {
            logger.debug('\'nonce\' check: %s == %s ? %s', clientNonce, resPQ.nonce, clientNonce == resPQ.nonce);

            // Find P and Q from PQ pair
            var pqFinder = new crypto.PQFinder(resPQ.pq);
            logger.debug('Start finding P and Q, with PQ = %s', pqFinder.getPQPairNumber());
            var pq = pqFinder.findPQ();
            logger.debug('Found P = %s and Q = %s', pq[0], pq[1]);

            // Find the correct Public Key using fingerprint from server response
            var publicKey;
            var fingerprints = resPQ.server_public_key_fingerprints.getList();
            var fingerprint;
            logger.debug('Public keys fingerprints from server: %s', fingerprints);
            for (var i = 0; i < fingerprints.length; i++) {
                fingerprint = fingerprints[i];
                logger.debug('Searching fingerprint %s in store', fingerprint);
                publicKey = crypto.PublicKey.retrieveKey(fingerprint);
                if (publicKey) {
                    logger.debug("Fingerprint %s found in keyStore.", fingerprint);
                    break;
                } else {
                    logger.warn("Fingerprint %s from server not found in keyStore.", fingerprint);
                    errorback();
                }
            }

            // Create the pq_inner_data buffer
            var pqAsBuffer = pqFinder.getPQAsBuffer();
            var newNonce32 = crypto.createNonce(32);
            var serverNonce = resPQ.server_nonce;
            var pqInnerData = new mtproto.P_Q_inner_data({props: {
                pq: resPQ.pq,
                p: pqAsBuffer[0],
                q: pqAsBuffer[1],
                nonce: clientNonce,
                server_nonce: serverNonce,
                new_nonce: newNonce32
            }}).serialize();

            // Create the data with hash to be encrypt
            var hash = crypto.createSHA1Hash(pqInnerData);
            var dataWithHash = Buffer.concat([hash, pqInnerData]);
            logger.debug('Data to be encrypt contain: hash(%s), pqInnerData(%s), total length %s',
                hash.toString('hex'), pqInnerData.toString('hex'), dataWithHash.length);

            // Encrypt data with RSA
            var encryptedData = crypto.rsaEncrypt({message: dataWithHash, key: publicKey});

            // Request server DH parameters
            mtproto.req_DH_params({
                props: {
                    nonce: clientNonce,
                    server_nonce: serverNonce,
                    p: pqAsBuffer[0],
                    q: pqAsBuffer[1],
                    public_key_fingerprint: fingerprint,
                    encrypted_data: encryptedData
                },
                conn: this._connection,
                callback: function (serverDHParams) {

                    callback(serverDHParams);

                }.bind(this),
                errorback: function (e) {
                    logger.error('Received exception %s', e);
                    errorback(e);
                }
            });

        }.bind(this),
        errorback: function (e) {
            logger.error('Received exception %s', e);
            errorback(e);
        }
    });

};

// The method closes the communication with the DataCenter,
// you can provide a callback function to know when is done or to catch an error
TelegramLink.prototype.end = function (callback, errorback) {
    this._connection.close(callback, errorback);
};
<|endoftext|>


<commit_before>const path = require('path');
const _ = require('lodash');
const promisify = require('promisify-node');
const fs = promisify('fs-extra');
const pathExists = require('path-exists');
const sass = require('node-sass');
const less = require('less');
const stylus = require('stylus');
const postcss = require('postcss');
const cssnext = require('postcss-cssnext');
const coffee = require('coffee-script');
const csso = require('csso');
const uglifyjs = require('uglify-js');

module.exports = function(mappings, optimize) {

  if (optimize) {
    return Promise.all(mappings.reduce(processMapping, []))
      .then(result => result.reduce(concatMapping, {}))
      .then(result => {
        const promises = _.map(result, (file, key) => {
          return fs.outputFile(path.join('dest', key + file.ext), file.value);
        });
        return Promise.all(promises)
      });
  }
  return Promise.all(mappings.reduce(processMapping, []));

  function processMapping(accumulator, mapping) {
    const {dest, src, key} = mapping;
    let promise;

    // Files that have minified versions don't need their sources compiled/processed. Do they?
    const noOptHasMin = !(optimize && src.pathMinExists);
    const shouldCompile = shouldCompileType(src.type) && noOptHasMin;
    const shouldPostProcess = shouldPostProcessType(src.type) && !src.isMinified && noOptHasMin;
    const shouldMinify = optimize && shouldMinifyType(dest.type) && !src.pathMinExists;
    const shouldConcat = optimize && shouldConcatType(dest.type);

    if (src.isDirectory || (!shouldCompile && !shouldPostProcess && !shouldMinify && !shouldConcat)) {
      promise = fs.copy(src.pathMinExists ? src.pathMin : src.path, dest.path, {dereference: true});
    }

    else {
      promise = fs.readFile(src.path, 'utf8')
        .then(result => {
          if (shouldCompile) {
            return compile(
              result, src.path, src.dirname, dest.dirname, src.basename, src.basenameStripped,
                dest.basename, src.type
            );
          }
          return result;
        })
        .then(result => shouldPostProcess ? postProcess(result, dest.type) : result)
        .then(result => shouldMinify ? minify(result, dest.type) : result)
        .then(result => shouldConcat ?
              {str: result, ext: dest.extnameMin, key} : fs.outputFile(dest.path, result))
    }

    accumulator.push(promise);

    return accumulator;
  }

  function concatMapping(accumulator, file) {
    if (file) accumulator[file.key] = concat(file.str, file.ext, accumulator[file.key]);
    return accumulator;
  }

  function concat(file, ext, obj) {
    return {ext: _.get(obj, 'ext', ext), value: _.get(obj, 'value', '') + '\n' + file};
  }

  function shouldCompileType(type) {
    return ['sass', 'scss', 'less', 'styl', 'coffee'].includes(type);
  }

  function shouldPostProcessType(type) {
    return ['css'].includes(type);
  }

  function shouldMinifyType(type) {
    return ['css', 'js'].includes(type);
  }

  function shouldConcatType(type) {
    return shouldMinifyType(type);
  }

  function compile(src, srcPath, srcDirname, destDirname, srcBasename, srcBasenameStripped,
      destBasename, type) {
    const sourcemapDirname = path.join('dest', destDirname, type);
    const sourceOnDestPath = path.join(sourcemapDirname, srcBasename);
    fs.outputFileSync(sourceOnDestPath, src);

    if (['sass', 'scss'].includes(type)) {
      return promisify(sass.render)({
        data: src,
        includePaths: [srcDirname],
        outFile: srcBasenameStripped + '.css',
        sourceMap: true,
        importer: function(url, prev, done) {
          const file = path.join(sourcemapDirname, url);
          const importPathBase = path.join(srcDirname, url);
          const importPathBaseAlt = path.join(srcDirname, path.dirname(url), '_' + path.basename(url));
          const importPath = [
            importPathBase + '.scss',
            importPathBaseAlt + '.scss',
            importPathBase,
            importPathBaseAlt,
            importPathBase + '.sass',
            importPathBaseAlt + '.sass'
          ].find(pathExists.sync);

          if (importPath) {
            const file = path.join(type, path.relative(srcDirname, importPath));
            const contents = fs.readFileSync(importPath, 'utf8');
            return {file, contents};
          }
          return {};
        }
      })
      .then(result => {
        result.stats.includedFiles.forEach(dep => {
          fs.copySync(path.join(srcDirname, path.relative(type, dep)), path.join('dest', dep));
        });
        fs.outputFileSync(path.join('dest', destBasename + '.map'), result.map.toString());
        return result.css.toString();
      })
    }
    if (type === 'less') {
      return less.render(src, {
        paths: [srcDirname],
        sourceMap: {
          sourceMapBasepath: srcDirname,
          sourceMapRootpath: type,
          sourceMapURL: 'less.css.map'
        }
      })
      .then(result => {
        result.imports.forEach(dep => {
          fs.copySync(dep, path.join(sourcemapDirname, path.relative(srcDirname, dep)));
        });
        fs.outputFileSync(path.join('dest', destBasename + '.map'), result.map);
        return result.css;
      });
    }
    if (type === 'styl') {
      let result;
      const style = stylus(src)
        .set('filename', srcPath)
        .set('sourcemap', {});

      style.deps().forEach(dep => {
        fs.copySync(dep, path.join(sourcemapDirname, path.relative(srcDirname, dep)));
      });

      style
        .set('filename', sourceOnDestPath)
        .set('dest', 'dest')
        .set('sourcemap', {})
        .define('url', stylus.resolver());

      style.render((err, css) => {
        result = css;
        fs.writeJsonSync(path.join('dest', destBasename + '.map'), style.sourcemap);
      });

      return result;
    }
    if (type === 'coffee') {
      return coffee.compile(src, {sourceMap: true}).js;
    }
  }

  function postProcess(src, type) {
    if (type === 'css') {
      return postcss([cssnext({add: false, browsers: []})]).process(src)
        .then(result => postcss([cssnext]).process(result.css))
        .then(result => result.css);
    }
  }

  function minify(src, type) {
    if (type === 'css') return csso.minify(src).css;
    if (type === 'js') return uglifyjs.minify(src, {fromString: true}).code;
  }
}
<commit_msg>attempted coffeescript sourcemaps<commit_after>const path = require('path');
const _ = require('lodash');
const promisify = require('promisify-node');
const fs = promisify('fs-extra');
const pathExists = require('path-exists');
const sass = require('node-sass');
const less = require('less');
const stylus = require('stylus');
const postcss = require('postcss');
const cssnext = require('postcss-cssnext');
const coffee = require('coffee-script');
const csso = require('csso');
const uglifyjs = require('uglify-js');

module.exports = function(mappings, optimize) {

  if (optimize) {
    return Promise.all(mappings.reduce(processMapping, []))
      .then(result => result.reduce(concatMapping, {}))
      .then(result => {
        const promises = _.map(result, (file, key) => {
          return fs.outputFile(path.join('dest', key + file.ext), file.value);
        });
        return Promise.all(promises)
      });
  }
  return Promise.all(mappings.reduce(processMapping, []));

  function processMapping(accumulator, mapping) {
    const {dest, src, key} = mapping;
    let promise;

    // Files that have minified versions don't need their sources compiled/processed. Do they?
    const noOptHasMin = !(optimize && src.pathMinExists);
    const shouldCompile = shouldCompileType(src.type) && noOptHasMin;
    const shouldPostProcess = shouldPostProcessType(src.type) && !src.isMinified && noOptHasMin;
    const shouldMinify = optimize && shouldMinifyType(dest.type) && !src.pathMinExists;
    const shouldConcat = optimize && shouldConcatType(dest.type);

    if (src.isDirectory || (!shouldCompile && !shouldPostProcess && !shouldMinify && !shouldConcat)) {
      promise = fs.copy(src.pathMinExists ? src.pathMin : src.path, dest.path, {dereference: true});
    }

    else {
      promise = fs.readFile(src.path, 'utf8')
        .then(result => {
          if (shouldCompile) {
            return compile(
              result, src.path, src.dirname, dest.dirname, src.basename, src.basenameStripped,
                dest.basename, src.type
            );
          }
          return result;
        })
        .then(result => shouldPostProcess ? postProcess(result, dest.type) : result)
        .then(result => shouldMinify ? minify(result, dest.type) : result)
        .then(result => shouldConcat ?
              {str: result, ext: dest.extnameMin, key} : fs.outputFile(dest.path, result))
    }

    accumulator.push(promise);

    return accumulator;
  }

  function concatMapping(accumulator, file) {
    if (file) accumulator[file.key] = concat(file.str, file.ext, accumulator[file.key]);
    return accumulator;
  }

  function concat(file, ext, obj) {
    return {ext: _.get(obj, 'ext', ext), value: _.get(obj, 'value', '') + '\n' + file};
  }

  function shouldCompileType(type) {
    return ['sass', 'scss', 'less', 'styl', 'coffee'].includes(type);
  }

  function shouldPostProcessType(type) {
    return ['css'].includes(type);
  }

  function shouldMinifyType(type) {
    return ['css', 'js'].includes(type);
  }

  function shouldConcatType(type) {
    return shouldMinifyType(type);
  }

  function compile(src, srcPath, srcDirname, destDirname, srcBasename, srcBasenameStripped,
      destBasename, type) {
    const sourcemapDirname = path.join('dest', destDirname, type);
    const sourceOnDestPath = path.join(sourcemapDirname, srcBasename);
    fs.outputFileSync(sourceOnDestPath, src);

    if (['sass', 'scss'].includes(type)) {
      return promisify(sass.render)({
        data: src,
        includePaths: [srcDirname],
        outFile: srcBasenameStripped + '.css',
        sourceMap: true,
        importer: function(url, prev, done) {
          const file = path.join(sourcemapDirname, url);
          const importPathBase = path.join(srcDirname, url);
          const importPathBaseAlt = path.join(srcDirname, path.dirname(url), '_' + path.basename(url));
          const importPath = [
            importPathBase + '.scss',
            importPathBaseAlt + '.scss',
            importPathBase,
            importPathBaseAlt,
            importPathBase + '.sass',
            importPathBaseAlt + '.sass'
          ].find(pathExists.sync);

          if (importPath) {
            const file = path.join(type, path.relative(srcDirname, importPath));
            const contents = fs.readFileSync(importPath, 'utf8');
            return {file, contents};
          }
          return {};
        }
      })
      .then(result => {
        result.stats.includedFiles.forEach(dep => {
          fs.copySync(path.join(srcDirname, path.relative(type, dep)), path.join('dest', dep));
        });
        fs.outputFileSync(path.join('dest', destBasename + '.map'), result.map.toString());
        return result.css.toString();
      })
    }
    if (type === 'less') {
      return less.render(src, {
        paths: [srcDirname],
        sourceMap: {
          sourceMapBasepath: srcDirname,
          sourceMapRootpath: type,
          sourceMapURL: 'less.css.map'
        }
      })
      .then(result => {
        result.imports.forEach(dep => {
          fs.copySync(dep, path.join(sourcemapDirname, path.relative(srcDirname, dep)));
        });
        fs.outputFileSync(path.join('dest', destBasename + '.map'), result.map);
        return result.css;
      });
    }
    if (type === 'styl') {
      let result;
      const style = stylus(src)
        .set('filename', srcPath)
        .set('sourcemap', {});

      style.deps().forEach(dep => {
        fs.copySync(dep, path.join(sourcemapDirname, path.relative(srcDirname, dep)));
      });

      style
        .set('filename', sourceOnDestPath)
        .set('dest', 'dest')
        .set('sourcemap', {})
        .define('url', stylus.resolver());

      style.render((err, css) => {
        result = css;
        fs.writeJsonSync(path.join('dest', destBasename + '.map'), style.sourcemap);
      });

      return result;
    }
    if (type === 'coffee') {
      /*
      const filename = path.join(destDirname, type, srcBasename);
      const result = coffee.compile(src, {sourceMap: true, filename});
      fs.outputFileSync(path.join('dest', destBasename + '.map'), result.v3SourceMap);
      return result.js + '\n//# sourceMappingURL=' +
        path.relative(path.join(type), destBasename + '.map');
      */
     return coffee.compile(src);
    }
  }

  function postProcess(src, type) {
    if (type === 'css') {
      return postcss([cssnext({add: false, browsers: []})]).process(src)
        .then(result => postcss([cssnext]).process(result.css))
        .then(result => result.css);
    }
  }

  function minify(src, type) {
    if (type === 'css') return csso.minify(src).css;
    if (type === 'js') return uglifyjs.minify(src, {fromString: true}).code;
  }
}
<|endoftext|>


<commit_before>/*
 *  Copyright 2011 Rackspace
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 */

var url = require('url');
var querystring = require('querystring');

var logmagic = require('logmagic');
var request = require('request');

var sprintf = require('./sprintf');

/**
 * BuildBot Client.
 * @constructor
 * @param {Object} options The options.
 */
function BuildBot(options, log) {
  var parsed = url.parse(options.url);

  // Inject auth into the URL
  delete parsed.host;
  parsed['auth'] = sprintf('%s:%s', options.username, options.password);

  this._url = url.format(parsed);
  this._options = options;
  this.log = log || logmagic.local('buildbot');
}

/**
 * Initiate build on buildbot
 * @param {String} builder The builder to force the build on.
 * @param {String} revision The revision to build.
 * @param {Function} callback The completion callback(err).
 */
BuildBot.prototype.build = function(builder, revision, callback) {
  var self = this,
      reqOpts = {
        method: 'POST',
        uri: sprintf('%s/builders/%s/force', this._url, builder),
        headers: {
          'Content-Type': 'application/x-www-form-urlencoded'
        },
        body: querystring.stringify({
          username: this._options.username,
          revision: revision
        })
      };

  this.log.infof('forcing build of ${revision} on ${builder}', {
    builder: builder,
    revision: revision
  });

  request(reqOpts, function(err, response, body) {
    if (err) {
      callback(err);
    } else if (response.statusCode !== 302) {
      callback(new Error(sprintf('Received %s from %s', response.statusCode, self._options.url)));
    } else {
      callback(null, body);
    }
  });
};

/**
 * Find the oldest build with a given revision.
 */
BuildBot.prototype._findOldestBuild = function(builds, revision) {
  var i, j, number, numbers, build, properties, retrybuild;

  // Get numbers of builds from oldest to newest
  numbers = Object.keys(builds).map(function(numstr) {
    return parseInt(numstr, 10);
  }).sort(function(a, b) {
    return a - b;
  });

  for (i = 0; i < numbers.length; i++) {
    number = numbers[i].toString();

    if (builds.hasOwnProperty(number)) {
      build = builds[number];
      properties = build.properties;

      if (!properties) {
        this.log.warnf('invalid build at ${index}: ${text}', {
          index: number,
          text: build.error
        });
        continue;
      }

      for (j = 0; j < properties.length; j++) {
        if (properties[j][0] === 'got_revision' && properties[j][1] === revision) {
          // If a build failed due to an exception, see if a subsequent one
          // can be used instead. (Also, "5" is apparently undocumented, but
          // seems to be the result code for "retry").
          if (build.results === 4 || build.results === 5) {
            retrybuild = build;
            continue;
          }

          return build;
        }
      }
    }
  }

  return retrybuild;
};

/**
 * Get a build for a specified revision.
 * @param {String} revision The revision to search for.
 * @param {Function} callback A callback fired with (err, build).
 */
BuildBot.prototype.getRevision = function(builder, revision, callback) {
  var self = this,
      selects = [],
      search, i;

  for (i = 1; i <= this._options.num_builds; i++) {
    selects.push(sprintf('-%s', i));
  }

  search = querystring.stringify({select: selects});

  request.get(sprintf('%s/json/builders/%s/builds?%s', this._url, builder, search), function(err, response, body) {
    if (err) {
      callback(err);
    } else {
      try {
        body = JSON.parse(body);
      } catch (e) {
        callback(e);
        return;
      }

      callback(null, self._findOldestBuild(body, revision));
    }
  });
};

BuildBot.prototype.ensureRevisionBuilt = function(builder, revision, callback) {
  var self = this,
      attempts = 0;

  this.log.infof('ensuring revision ${revision} on ${builder}', {
    revision: revision,
    builder: builder
  });

  function attempt(force) {
    attempts++;

    if (attempts > self._options.retries) {
      callback(new Error(sprintf('No build found after %s attempts', self._options.retries)));
      return;
    }

    self.getRevision(builder, revision, function(err, build) {
      if (err) {
        callback(err);
      } else if (!build) {
        if (force) {
          self.build(builder, revision, function(err) {
            if (err) {
              callback(err);
            } else {
              setTimeout(attempt, self._options.delay);
            }
          });
        } else {
          // The build was already forced, but isn't showing up - it is
          // *probably* pending. Alternatively, maybe num_builds happened
          // and we missed it. Oops.
          self.log.infof('build of ${revision} on ${builder} is queued', {
            revision: revision,
            builder: builder
          });
          setTimeout(attempt, self._options.delay);
        }
      } else if (build.times[1] !== null) {
        self.log.infof('build ${number} on ${builder} finished: ${text}', {
          number: build.number,
          result_code: build.results || 0,
          builder: builder,
          text: build.text.join(' ')
        });
        // There is a Buildbot bug where build.results isn't included when it
        // is 0
        if ((build.results || 0) === 0) {
          callback(null, build);
        } else {
          callback(new Error(sprintf('Build %s of %s: %s', build.number, builder, build.text.join(' '))));
        }
      } else {
        self.log.infof('build ${number} on ${builder} ETA is ${eta}s', {
          number: build.number,
          builder: builder,
          eta: build.eta
        });
        // Try again in the greater of half of the ETA or the configured delay
        setTimeout(attempt, Math.max(build.eta * 500, self._options.delay));
      }
    });
  }

  attempt(true);
};

/** BuildBot Class */
exports.BuildBot = BuildBot;
<commit_msg>change buildbot to use documented config format<commit_after>/*
 *  Copyright 2011 Rackspace
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 */

var url = require('url');
var querystring = require('querystring');

var logmagic = require('logmagic');
var request = require('request');

var sprintf = require('./sprintf');

/**
 * BuildBot Client.
 * @constructor
 * @param {Object} options The options.
 */
function BuildBot(options, log) {
  var parsed = url.parse(options.url);

  // Inject auth into the URL
  delete parsed.host;
  parsed['auth'] = sprintf('%s:%s', options.username, options.password);

  this._url = url.format(parsed);
  this._options = options;
  this.log = log || logmagic.local('buildbot');
}

/**
 * Initiate build on buildbot
 * @param {String} builder The builder to force the build on.
 * @param {String} revision The revision to build.
 * @param {Function} callback The completion callback(err).
 */
BuildBot.prototype.build = function(builder, revision, callback) {
  var self = this,
      reqOpts = {
        method: 'POST',
        uri: sprintf('%s/builders/%s/force', this._url, builder),
        headers: {
          'Content-Type': 'application/x-www-form-urlencoded'
        },
        body: querystring.stringify({
          username: this._options.username,
          revision: revision
        })
      };

  this.log.infof('forcing build of ${revision} on ${builder}', {
    builder: builder,
    revision: revision
  });

  request(reqOpts, function(err, response, body) {
    if (err) {
      callback(err);
    } else if (response.statusCode !== 302) {
      callback(new Error(sprintf('Received %s from %s', response.statusCode, self._options.url)));
    } else {
      callback(null, body);
    }
  });
};

/**
 * Find the oldest build with a given revision.
 */
BuildBot.prototype._findOldestBuild = function(builds, revision) {
  var i, j, number, numbers, build, properties, retrybuild;

  // Get numbers of builds from oldest to newest
  numbers = Object.keys(builds).map(function(numstr) {
    return parseInt(numstr, 10);
  }).sort(function(a, b) {
    return a - b;
  });

  for (i = 0; i < numbers.length; i++) {
    number = numbers[i].toString();

    if (builds.hasOwnProperty(number)) {
      build = builds[number];
      properties = build.properties;

      if (!properties) {
        this.log.warnf('invalid build at ${index}: ${text}', {
          index: number,
          text: build.error
        });
        continue;
      }

      for (j = 0; j < properties.length; j++) {
        if (properties[j][0] === 'got_revision' && properties[j][1] === revision) {
          // If a build failed due to an exception, see if a subsequent one
          // can be used instead. (Also, "5" is apparently undocumented, but
          // seems to be the result code for "retry").
          if (build.results === 4 || build.results === 5) {
            retrybuild = build;
            continue;
          }

          return build;
        }
      }
    }
  }

  return retrybuild;
};

/**
 * Get a build for a specified revision.
 * @param {String} revision The revision to search for.
 * @param {Function} callback A callback fired with (err, build).
 */
BuildBot.prototype.getRevision = function(builder, revision, callback) {
  var self = this,
      selects = [],
      search, i;

  for (i = 1; i <= this._options.num_builds; i++) {
    selects.push(sprintf('-%s', i));
  }

  search = querystring.stringify({select: selects});

  request.get(sprintf('%s/json/builders/%s/builds?%s', this._url, builder, search), function(err, response, body) {
    if (err) {
      callback(err);
    } else {
      try {
        body = JSON.parse(body);
      } catch (e) {
        callback(e);
        return;
      }

      callback(null, self._findOldestBuild(body, revision));
    }
  });
};

BuildBot.prototype.ensureRevisionBuilt = function(builder, revision, callback) {
  var self = this,
      attempts = 0;

  this.log.infof('ensuring revision ${revision} on ${builder}', {
    revision: revision,
    builder: builder
  });

  function attempt(force) {
    attempts++;

    if (attempts > self._options.attempts) {
      callback(new Error(sprintf('No build found after %s attempts', self._options.attempts)));
      return;
    }

    self.getRevision(builder, revision, function(err, build) {
      if (err) {
        callback(err);
      } else if (!build) {
        if (force) {
          self.build(builder, revision, function(err) {
            if (err) {
              callback(err);
            } else {
              setTimeout(attempt, self._options.delay);
            }
          });
        } else {
          // The build was already forced, but isn't showing up - it is
          // *probably* pending. Alternatively, maybe num_builds happened
          // and we missed it. Oops.
          self.log.infof('build of ${revision} on ${builder} is queued', {
            revision: revision,
            builder: builder
          });
          setTimeout(attempt, self._options.delay);
        }
      } else if (build.times[1] !== null) {
        self.log.infof('build ${number} on ${builder} finished: ${text}', {
          number: build.number,
          result_code: build.results || 0,
          builder: builder,
          text: build.text.join(' ')
        });
        // There is a Buildbot bug where build.results isn't included when it
        // is 0
        if ((build.results || 0) === 0) {
          callback(null, build);
        } else {
          callback(new Error(sprintf('Build %s of %s: %s', build.number, builder, build.text.join(' '))));
        }
      } else {
        self.log.infof('build ${number} on ${builder} ETA is ${eta}s', {
          number: build.number,
          builder: builder,
          eta: build.eta
        });
        // Try again in the greater of half of the ETA or the configured delay
        setTimeout(attempt, Math.max(build.eta * 500, self._options.delay));
      }
    });
  }

  attempt(true);
};

/** BuildBot Class */
exports.BuildBot = BuildBot;
<|endoftext|>


<commit_before>var os = require('os');
var path = require('path');
var paths = require('./paths');

// Guess proxy defined in the env
/*jshint camelcase: false*/
var proxy = process.env.HTTP_PROXY
    || process.env.http_proxy
    || null;

var httpsProxy = process.env.HTTPS_PROXY
    || process.env.https_proxy
    || proxy;
/*jshint camelcase: true*/

// Use a well known user agent (in this case, curl) when using a proxy,
// to avoid potential filtering on many corporate proxies with blank or unknown agents
var userAgent = !proxy && !httpsProxy
    ? 'node/' + process.version + ' ' + process.platform + ' ' + process.arch
    : 'curl/7.21.4 (universal-apple-darwin11.0) libcurl/7.21.4 OpenSSL/0.9.8r zlib/1.2.5';

var defaults = {
    'cwd': process.cwd(),
    'directory': 'bower_components',
    'registry': 'https://bower.herokuapp.com',
    'shorthand-resolver': 'git://github.com/{{owner}}/{{package}}.git',
    'tmp': os.tmpdir ? os.tmpdir() : os.tmpDir(),
    'proxy': proxy,
    'https-proxy': httpsProxy,
    'timeout': 30000,
    'ca': { search: [] },
    'strict-ssl': true,
    'user-agent': userAgent,
    'color': true,
    'interactive': false,
    'storage': {
        packages: path.join(paths.cache, 'packages'),
        links: path.join(paths.data, 'links'),
        completion: path.join(paths.data, 'completion'),
        registry: path.join(paths.cache, 'registry'),
        git: path.join(paths.data, 'git')
    }
};

module.exports = defaults;
<commit_msg>Change git folder to empty (was not being used anyway).<commit_after>var os = require('os');
var path = require('path');
var paths = require('./paths');

// Guess proxy defined in the env
/*jshint camelcase: false*/
var proxy = process.env.HTTP_PROXY
    || process.env.http_proxy
    || null;

var httpsProxy = process.env.HTTPS_PROXY
    || process.env.https_proxy
    || proxy;
/*jshint camelcase: true*/

// Use a well known user agent (in this case, curl) when using a proxy,
// to avoid potential filtering on many corporate proxies with blank or unknown agents
var userAgent = !proxy && !httpsProxy
    ? 'node/' + process.version + ' ' + process.platform + ' ' + process.arch
    : 'curl/7.21.4 (universal-apple-darwin11.0) libcurl/7.21.4 OpenSSL/0.9.8r zlib/1.2.5';

var defaults = {
    'cwd': process.cwd(),
    'directory': 'bower_components',
    'registry': 'https://bower.herokuapp.com',
    'shorthand-resolver': 'git://github.com/{{owner}}/{{package}}.git',
    'tmp': os.tmpdir ? os.tmpdir() : os.tmpDir(),
    'proxy': proxy,
    'https-proxy': httpsProxy,
    'timeout': 30000,
    'ca': { search: [] },
    'strict-ssl': true,
    'user-agent': userAgent,
    'color': true,
    'interactive': false,
    'storage': {
        packages: path.join(paths.cache, 'packages'),
        links: path.join(paths.data, 'links'),
        completion: path.join(paths.data, 'completion'),
        registry: path.join(paths.cache, 'registry'),
        empty: path.join(paths.data, 'empty')  // Empty dir, used in GIT_TEMPLATE_DIR among others
    }
};

module.exports = defaults;
<|endoftext|>


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

 /* definition of named properties expected by the native side,
    all arrays are stored in order of how they are received from common js code.
    When other platforms evolve to using named args this will be removed.
 */

/**
 * Execute a cordova command.  It is up to the native side whether this action
 * is synchronous or asynchronous.  The native side can return:
 *      Synchronous: PluginResult object as a JSON string
 *      Asynchrounous: Empty string ""
 * If async, the native side will cordova.callbackSuccess or cordova.callbackError,
 * depending upon the result of the action.
 *
 * @param {Function} success    The success callback
 * @param {Function} fail       The fail callback
 * @param {String} service      The name of the service to use
 * @param {String} action       Action to be run in cordova
 * @param {String[]} [args]     Zero or more arguments to pass to the method
 */

var CommandProxy  = {

    "Accelerometer": require('cordova/plugin/windows8/AccelerometerProxy'),
    "Camera":require('cordova/plugin/windows8/CameraProxy'),
    "Capture":require('cordova/plugin/windows8/CaptureProxy'),
    "Compass":require('cordova/plugin/windows8/CompassProxy'),
    "Device":require('cordova/plugin/windows8/DeviceProxy'),
    "File":require('cordova/plugin/windows8/FileProxy'),
    "FileTransfer":require('cordova/plugin/windows8/FileTransferProxy'),
    "Media":require('cordova/plugin/windows8/MediaProxy'),
    "NetworkStatus":require('cordova/plugin/windows8/NetworkStatusProxy'),
    "Notification":require('cordova/plugin/windows8/NotificationProxy')

};

module.exports = function(success, fail, service, action, args) {

    if(CommandProxy[service] && CommandProxy[service][action]) {

        var callbackId = service + cordova.callbackId++;
        console.log("EXEC:" + service + " : " + action);

        if (typeof success == "function" || typeof fail == "function") {
            cordova.callbacks[callbackId] = {success:success, fail:fail};
        }
        // pass it on to Notify
        try {
            CommandProxy [service][action](success, fail, args);
        }
        catch(e) {
            console.log("Exception calling native with command :: " + service + " :: " + action  + " ::exception=" + e);
        }
    }
    else
    {
        if(fail) { fail("Missing Command Error"); }
    }

};

// cordova.exec.addCommandProxy("Accelerometer",{getCurrentAcceleration: function(successCallback, errorCallback, options) {...},...);
module.exports.addCommandProxy = function(id,proxyObj) {

    CommandProxy[id] = proxyObj;
};

// cordova.exec.removeCommandProxy("Accelerometer");
module.exports.removeCommandProxy = function(id) {

    var proxy = CommandProxy[id];
    delete CommandProxy[id];
    CommandProxy[id] = null;
    return proxy;
};

<commit_msg>Change the init time<commit_after>var cordova = require('cordova');

 /* definition of named properties expected by the native side,
    all arrays are stored in order of how they are received from common js code.
    When other platforms evolve to using named args this will be removed.
 */

/**
 * Execute a cordova command.  It is up to the native side whether this action
 * is synchronous or asynchronous.  The native side can return:
 *      Synchronous: PluginResult object as a JSON string
 *      Asynchrounous: Empty string ""
 * If async, the native side will cordova.callbackSuccess or cordova.callbackError,
 * depending upon the result of the action.
 *
 * @param {Function} success    The success callback
 * @param {Function} fail       The fail callback
 * @param {String} service      The name of the service to use
 * @param {String} action       Action to be run in cordova
 * @param {String[]} [args]     Zero or more arguments to pass to the method
 */

var CommandProxy;

function getCP() {
    if (!CommandProxy) {
        CommandProxy = {
          "Accelerometer": require('cordova/plugin/windows8/AccelerometerProxy'),
          "Camera":require('cordova/plugin/windows8/CameraProxy'),
          "Capture":require('cordova/plugin/windows8/CaptureProxy'),
          "Compass":require('cordova/plugin/windows8/CompassProxy'),
          "Device":require('cordova/plugin/windows8/DeviceProxy'),
          "File":require('cordova/plugin/windows8/FileProxy'),
          "FileTransfer":require('cordova/plugin/windows8/FileTransferProxy'),
          "Media":require('cordova/plugin/windows8/MediaProxy'),
          "NetworkStatus":require('cordova/plugin/windows8/NetworkStatusProxy'),
          "Notification":require('cordova/plugin/windows8/NotificationProxy')
        };
    }
    return CommandProxy;
};

module.exports = function(success, fail, service, action, args) {
    var CommandProxy = getCP();
    if(CommandProxy[service] && CommandProxy[service][action]) {

        var callbackId = service + cordova.callbackId++;
        console.log("EXEC:" + service + " : " + action);

        if (typeof success == "function" || typeof fail == "function") {
            cordova.callbacks[callbackId] = {success:success, fail:fail};
        }
        // pass it on to Notify
        try {
            CommandProxy [service][action](success, fail, args);
        }
        catch(e) {
            console.log("Exception calling native with command :: " + service + " :: " + action  + " ::exception=" + e);
        }
    }
    else
    {
        if(fail) { fail("Missing Command Error"); }
    }

};

// cordova.exec.addCommandProxy("Accelerometer",{getCurrentAcceleration: function(successCallback, errorCallback, options) {...},...);
module.exports.addCommandProxy = function(id,proxyObj) {
    var CommandProxy = getCP();
    CommandProxy[id] = proxyObj;
};

// cordova.exec.removeCommandProxy("Accelerometer");
module.exports.removeCommandProxy = function(id) {
    var CommandProxy = getCP();
    var proxy = CommandProxy[id];
    delete CommandProxy[id];
    CommandProxy[id] = null;
    return proxy;
};

<|endoftext|>