<commit_before>const fse = require('fs-extra');
const os = require('os');
const fs = require('fs');
const inquirer = require('inquirer');
const crypto = require('crypto')
const zlib = require('zlib');
const shell = require('shelljs');
const figlet = require('figlet');
const path = require("path");
const replace = require("replace");
const Datauri = require('datauri').sync;
const absolutePath = path.resolve(".");
const algorithm = 'sha1';

function startBuild() {
    console.log(' Preparing for building Jste Framework ');
    shell.rm('-rf', 'tmp');
    shell.mkdir('tmp');
    shell.ln('-sf', absolutePath + '/src', 'tmp/src');
    shell.cd('build');
    shell.rm('-rf', '*');
    shell.mkdir('minified', 'compressed');
    fse.copySync(absolutePath + '/src/JS/Core/analyzeCommand-CompilationTemplate.js', absolutePath + '/tmp/analyzeCommand-Compiled.js');
    fse.copySync(absolutePath + '/src/JS/Core/wordsTranslationsInit-CompilationTemplate.js', absolutePath + '/tmp/wordsTranslationsInit-Compiled.js');
    fse.copySync(absolutePath + '/src/Res.html', absolutePath + '/tmp/Res.html');
    fse.copySync(absolutePath + '/src/Res-LiveVersion.html', absolutePath + '/tmp/Res-LiveVersion.html');
    var langCodes = ['en', 'fr', 'ar', 'arz'];
    for (var i = 0; i < langCodes.length; i++) {
        replace({
            regex: langCodes[i].toUpperCase() + "_RIVESCRIPT",
            replacement: Datauri(absolutePath + '/src/JS/Translations/RiveScript/' + langCodes[i] + '.rive'),
            paths: [absolutePath + '/tmp/analyzeCommand-Compiled.js'],
            recursive: true,
            silent: true,
        });
    }
    replace({
        regex: "DICTIONARY_URL",
        replacement: Datauri(absolutePath + '/src/JS/Translations/words.json'),
        paths: [absolutePath + '/tmp/wordsTranslationsInit-Compiled.js'],
        recursive: true,
        silent: true
    });
    replace({
        regex: 'src="(?!http)',
        replacement: 'src="src/',
        paths: [absolutePath + '/tmp/Res.html', absolutePath + '/tmp/Res-LiveVersion.html'],
        recursive: true,
        silent: true
    });
    replace({
        regex: 'href="(?!http)',
        replacement: 'href="src/',
        paths: [absolutePath + '/tmp/Res.html', absolutePath + '/tmp/Res-LiveVersion.html'],
        recursive: true,
        silent: true
    });
    replace({
        regex: 'src/JS/Core/wordsTranslationsInit\.js',
        replacement: 'wordsTranslationsInit-Compiled.js',
        paths: [absolutePath + '/tmp/Res.html', absolutePath + '/tmp/Res-LiveVersion.html'],
        recursive: true,
        silent: true
    });
    replace({
        regex: 'src/JS/Core/analyzeCommand\.js',
        replacement: 'analyzeCommand-Compiled.js',
        paths: [absolutePath + '/tmp/Res.html', absolutePath + '/tmp/Res-LiveVersion.html'],
        recursive: true,
        silent: true
    });
    console.log(' ');
    console.log(' Starting building Jste Framework ');
    var frameworkMinifiedFileInfo = {};
    var frameworkCompressedFileInfo = {};
    console.log(' Bundling the framework files into one HTML file ');
    shell.exec('polymer-bundler -r ' + absolutePath + '/tmp Res.html  --strip-comments --inline-scripts --inline-css --rewrite-urls-in-templates > framework.html');
    console.log(' Minifying the framework bundled file ');
    shell.exec('html-minifier framework.html --remove-comments --minify-css --minify-js --remove-comments --use-short-doctype > minified/framework.min.html');
    frameworkMinifiedFileInfo.size = fse.statSync('minified/framework.min.html').size;
    frameworkCompressedFileInfo.size = frameworkMinifiedFileInfo.size;
    console.log(' Hashing the framework minified file ');
    var shasum = crypto.createHash(algorithm);
    shasum.update(fse.readFileSync('minified/framework.min.html', 'utf8'));
    frameworkMinifiedFileInfo.sha1 = shasum.digest('hex');
    fse.writeFileSync('minified/framework.info.json', JSON.stringify(frameworkMinifiedFileInfo));
    shell.rm('-rf', 'framework.html');
    console.log(' Compresssing the framework minified file ');
    var gzip = zlib.createGzip();
    var inp = fse.createReadStream('minified/framework.min.html');
    var out = fse.createWriteStream('compressed/framework.min.html.gz');
    inp.pipe(gzip).pipe(out);
    console.log(' Hashing the framework compressed file ');
    var shasum = crypto.createHash(algorithm);
    shasum.update(fse.readFileSync('compressed/framework.min.html.gz', 'utf8'));
    frameworkCompressedFileInfo.sha1 = shasum.digest('hex');
    fse.writeFileSync('compressed/framework.info.json', JSON.stringify(frameworkCompressedFileInfo));
    console.log(' Jste Framework has been built properly ;) ');
    console.log(' ');
    console.log(' Starting building Jste Framework Live Version ');
    var frameworkLiveVersionMinifiedFileInfo = {};
    var frameworkLiveVersionCompressedFileInfo = {};
    console.log(' Bundling the framework files into one HTML file ');
    shell.exec('polymer-bundler -r ' + absolutePath + '/tmp Res-LiveVersion.html  --strip-comments --inline-scripts --inline-css --rewrite-urls-in-templates > framework-LiveVersion.html');
    console.log(' Minifying the framework bundled file ');
    shell.exec('html-minifier framework-LiveVersion.html --remove-comments --minify-css --minify-js --remove-comments --use-short-doctype > minified/framework-LiveVersion.min.html');
    frameworkLiveVersionMinifiedFileInfo.size = fse.statSync('minified/framework-LiveVersion.min.html').size;
    frameworkLiveVersionCompressedFileInfo.size = frameworkLiveVersionMinifiedFileInfo.size;
    console.log(' Hashing the framework minified file ');
    var shasum = crypto.createHash(algorithm);
    shasum.update(fse.readFileSync('minified/framework-LiveVersion.min.html', 'utf8'));
    frameworkLiveVersionMinifiedFileInfo.sha1 = shasum.digest('hex');
    fse.writeFileSync('minified/framework-LiveVersion.info.json', JSON.stringify(frameworkLiveVersionMinifiedFileInfo));
    shell.rm('-rf', 'framework-LiveVersion.html');
    console.log(' Compresssing the framework minified file ');
    var gzip = zlib.createGzip();
    var inp = fse.createReadStream('minified/framework-LiveVersion.min.html');
    var out = fse.createWriteStream('compressed/framework-LiveVersion.min.html.gz');
    inp.pipe(gzip).pipe(out);
    console.log(' Hashing the framework compressed file ');
    var shasum = crypto.createHash(algorithm);
    shasum.update(fse.readFileSync('compressed/framework-LiveVersion.min.html.gz', 'utf8'));
    frameworkLiveVersionCompressedFileInfo.sha1 = shasum.digest('hex');
    fse.writeFileSync('compressed/framework-LiveVersion.info.json', JSON.stringify(frameworkLiveVersionCompressedFileInfo));
    console.log(' Jste Framework Live Version has been built properly ;) ');
    console.log(' ');
    console.log(' Starting building the BLOB DB Manager for Jste Framework Live Version ');
    var dbManagerMinifiedFileInfo = {};
    var dbManagerCompressedFileInfo = {};
    console.log(' Minifying the BLOB DB Manager file ');
    shell.exec('html-minifier ../utils/db-manager.html --remove-comments --minify-css --minify-js --remove-comments --use-short-doctype > minified/db-manager.min.html');
    dbManagerMinifiedFileInfo.size = fse.statSync('minified/db-manager.min.html').size;
    dbManagerCompressedFileInfo.size = dbManagerMinifiedFileInfo.size;
    console.log(' Hashing the BLOB DB Manager minified file ');
    var shasum = crypto.createHash(algorithm);
    shasum.update(fse.readFileSync('minified/db-manager.min.html', 'utf8'));
    dbManagerMinifiedFileInfo.sha1 = shasum.digest('hex');
    fse.writeFileSync('minified/db-manager.info.json', JSON.stringify(dbManagerMinifiedFileInfo));
    shell.rm('-rf', 'db-manager.html');
    console.log(' Compresssing the BLOB DB Manager minified file ');
    var gzip = zlib.createGzip();
    var inp = fse.createReadStream('minified/db-manager.min.html');
    var out = fse.createWriteStream('compressed/db-manager.min.html.gz');
    inp.pipe(gzip).pipe(out);
    console.log(' Hashing the BLOB DB Manager compressed file ');
    var shasum = crypto.createHash(algorithm);
    shasum.update(fse.readFileSync('compressed/db-manager.min.html.gz', 'utf8'));
    dbManagerCompressedFileInfo.sha1 = shasum.digest('hex');
    fse.writeFileSync('compressed/db-manager.info.json', JSON.stringify(dbManagerCompressedFileInfo));
    console.log(' The BLOB DB Manager for Jste Framework Live Version has been built properly ;) ');
    shell.cd('../');
    shell.rm('-rf', 'tmp');
    if (global.gitURLPrefix) {
        console.log(' ');
        console.log(' Updating the index ');
        shell.exec('git add .');
        console.log(' ');
        console.log(' Recording the change to the local repo ');
        shell.exec('git commit -m "' + global.commitMessage + '"');
        console.log(' ');
        console.log(' Pushing the updates to GitHub ');
        shell.exec('git push ' + gitURLPrefix + 'framework.git master');
    }
    if (shell.test('-d', '../manager')) {
        console.log(' ');
        console.log(' Preparing for building Jste Manager ');
        shell.cd('../manager');
        console.log(' ');
        console.log(' Updating framework file ');
        fs.copyFileSync(path.resolve('..') + '/framework/build/compressed/framework.min.html.gz', path.resolve('.') + '/src/assets/framework.min.html.gz');
        console.log(' ');
        console.log(' Starting building Jste Manager ');
        shell.exec('node build');
        if (global.gitURLPrefix) {
            console.log(' ');
            console.log(' Updating the index ');
            shell.exec('git add .');
            console.log(' ');
            console.log(' Recording the change to the local repo ');
            shell.exec('git commit -m "Updating Framework Files"');
            console.log(' ');
            console.log(' Pushing the updates to GitHub ');
            shell.exec('git push ' + gitURLPrefix + 'manager.git master');
        }
    }
    if (shell.test('-d', '../manager-heroku')) {
        console.log(' ');
        console.log(' Preparing for building Jste Manager Heroku version ');
        shell.cd('../manager-heroku');
        console.log(' ');
        console.log(' Updating framework file ');
        fs.copyFileSync(path.resolve('..') + '/framework/build/compressed/framework-LiveVersion.min.html.gz', path.resolve('.') + '/assets/framework-LiveVersion.min.html.gz');
        fs.copyFileSync(path.resolve('..') + '/framework/build/compressed/db-manager.min.html.gz', path.resolve('.') + '/assets/db-manager.min.html.gz');
        if (global.gitURLPrefix) {
            console.log(' ');
            console.log(' Updating the index ');
            shell.exec('git add .');
            console.log(' ');
            console.log(' Recording the change to the local repo ');
            shell.exec('git commit -m "Updating Framework Files"');
            console.log(' ');
            console.log(' Pushing the updates to GitHub ');
            shell.exec('git push ' + gitURLPrefix + 'manager-heroku.git master');
            console.log(' ');
            console.log(' Pushing the updates to Heroku ');
            shell.exec('git push heroku master');
        }
    }
    if (shell.test('-d', '../manager-phone')) {
        console.log(' ');
        console.log(' Preparing for building Jste Manager phone version ');
        shell.cd('../manager-phone/src');
        console.log(' ');
        console.log(' Updating framework file ');
        fs.copyFileSync(path.resolve('../..') + '/framework/build/minified/framework.min.html', path.resolve('.') + '/www/jxcore/assets/framework.min.html');
        console.log(' ');
        console.log(' Starting building Jste Manager phone version ');
        shell.exec('cordova build');
        shell.cd('../');
        shell.cp('src/platforms/android/build/outputs/apk/debug/android-debug.apk', 'build');
        if (global.gitURLPrefix) {
            console.log(' ');
            console.log(' Updating the index ');
            shell.exec('git add .');
            console.log(' ');
            console.log(' Recording the change to the local repo ');
            shell.exec('git commit -m "Updating Framework Files"');
            console.log(' ');
            console.log(' Pushing the updates to GitHub ');
            shell.exec('git push ' + gitURLPrefix + 'manager-phone.git master');
        }
    }
}

figlet('JSTE FRAMEWORK', function (err, data) {
    console.log(data);
    console.log('');
    console.log(' Welcome to Jste Framework builder :) ')
    inquirer
        .prompt([{
            type: 'confirm',
            name: 'deploy',
            message: 'Do you want to deploy this build ?'
        }])
        .then(options => {
            if (options.deploy == true) {
                inquirer
                    .prompt([{
                            type: 'input',
                            name: 'commit_message',
                            message: 'Please enter the commit message '
                        }, {
                            type: 'input',
                            name: 'git_username',
                            message: 'Please enter your GitHub username '
                        },
                        {
                            type: 'password',
                            name: 'git_password',
                            mask: '*',
                            message: 'Please enter your GitHub password '
                        }
                    ]).then(git_info => {
                        global.gitURLPrefix = 'https://' + git_info.git_username + ':' + git_info.git_password + '@github.com/project-jste/';
                        global.commitMessage = git_info.commit_message;
                        startBuild();
                    })
            } else {
                startBuild();
            }
        });
});<commit_msg>Bug Fixes<commit_after>const fse = require('fs-extra');
const os = require('os');
const fs = require('fs');
const inquirer = require('inquirer');
const crypto = require('crypto')
const zlib = require('zlib');
const shell = require('shelljs');
const figlet = require('figlet');
const path = require("path");
const replace = require("replace");
const Datauri = require('datauri').sync;
const absolutePath = path.resolve(".");
const algorithm = 'sha1';

function startBuild() {
    console.log(' Preparing for building Jste Framework ');
    shell.rm('-rf', 'tmp');
    shell.mkdir('tmp');
    shell.ln('-sf', absolutePath + '/src', 'tmp/src');
    shell.cd('build');
    shell.rm('-rf', '*');
    shell.mkdir('minified', 'compressed');
    fse.copySync(absolutePath + '/src/JS/Core/analyzeCommand-CompilationTemplate.js', absolutePath + '/tmp/analyzeCommand-Compiled.js');
    fse.copySync(absolutePath + '/src/JS/Core/wordsTranslationsInit-CompilationTemplate.js', absolutePath + '/tmp/wordsTranslationsInit-Compiled.js');
    fse.copySync(absolutePath + '/src/Res.html', absolutePath + '/tmp/Res.html');
    fse.copySync(absolutePath + '/src/Res-LiveVersion.html', absolutePath + '/tmp/Res-LiveVersion.html');
    var langCodes = ['en', 'fr', 'ar', 'arz'];
    for (var i = 0; i < langCodes.length; i++) {
        replace({
            regex: langCodes[i].toUpperCase() + "_RIVESCRIPT",
            replacement: Datauri(absolutePath + '/src/JS/Translations/RiveScript/' + langCodes[i] + '.rive'),
            paths: [absolutePath + '/tmp/analyzeCommand-Compiled.js'],
            recursive: true,
            silent: true,
        });
    }
    replace({
        regex: "DICTIONARY_URL",
        replacement: Datauri(absolutePath + '/src/JS/Translations/words.json'),
        paths: [absolutePath + '/tmp/wordsTranslationsInit-Compiled.js'],
        recursive: true,
        silent: true
    });
    replace({
        regex: 'src="(?!http)',
        replacement: 'src="src/',
        paths: [absolutePath + '/tmp/Res.html', absolutePath + '/tmp/Res-LiveVersion.html'],
        recursive: true,
        silent: true
    });
    replace({
        regex: 'href="(?!http)',
        replacement: 'href="src/',
        paths: [absolutePath + '/tmp/Res.html', absolutePath + '/tmp/Res-LiveVersion.html'],
        recursive: true,
        silent: true
    });
    replace({
        regex: 'src/JS/Core/wordsTranslationsInit\.js',
        replacement: 'wordsTranslationsInit-Compiled.js',
        paths: [absolutePath + '/tmp/Res.html', absolutePath + '/tmp/Res-LiveVersion.html'],
        recursive: true,
        silent: true
    });
    replace({
        regex: 'src/JS/Core/analyzeCommand\.js',
        replacement: 'analyzeCommand-Compiled.js',
        paths: [absolutePath + '/tmp/Res.html', absolutePath + '/tmp/Res-LiveVersion.html'],
        recursive: true,
        silent: true
    });
    console.log(' ');
    console.log(' Starting building Jste Framework ');
    var frameworkMinifiedFileInfo = {};
    var frameworkCompressedFileInfo = {};
    console.log(' Bundling the framework files into one HTML file ');
    shell.exec('polymer-bundler -r ' + absolutePath + '/tmp Res.html  --strip-comments --inline-scripts --inline-css --rewrite-urls-in-templates > framework.html');
    console.log(' Minifying the framework bundled file ');
    shell.exec('html-minifier framework.html --remove-comments --minify-css --minify-js --remove-comments --use-short-doctype > minified/framework.min.html');
    frameworkMinifiedFileInfo.size = fse.statSync('minified/framework.min.html').size;
    frameworkCompressedFileInfo.size = frameworkMinifiedFileInfo.size;
    console.log(' Hashing the framework minified file ');
    var shasum = crypto.createHash(algorithm);
    shasum.update(fse.readFileSync('minified/framework.min.html', 'utf8'));
    frameworkMinifiedFileInfo.sha1 = shasum.digest('hex');
    fse.writeFileSync('minified/framework.info.json', JSON.stringify(frameworkMinifiedFileInfo));
    shell.rm('-rf', 'framework.html');
    console.log(' Compresssing the framework minified file ');
    var gzip = zlib.createGzip();
    var inp = fse.createReadStream('minified/framework.min.html');
    var out = fse.createWriteStream('compressed/framework.min.html.gz');
    inp.pipe(gzip).pipe(out);
    console.log(' Hashing the framework compressed file ');
    var shasum = crypto.createHash(algorithm);
    shasum.update(fse.readFileSync('compressed/framework.min.html.gz', 'utf8'));
    frameworkCompressedFileInfo.sha1 = shasum.digest('hex');
    fse.writeFileSync('compressed/framework.info.json', JSON.stringify(frameworkCompressedFileInfo));
    console.log(' Jste Framework has been built properly ;) ');
    console.log(' ');
    console.log(' Starting building Jste Framework Live Version ');
    var frameworkLiveVersionMinifiedFileInfo = {};
    var frameworkLiveVersionCompressedFileInfo = {};
    console.log(' Bundling the framework files into one HTML file ');
    shell.exec('polymer-bundler -r ' + absolutePath + '/tmp Res-LiveVersion.html  --strip-comments --inline-scripts --inline-css --rewrite-urls-in-templates > framework-LiveVersion.html');
    console.log(' Minifying the framework bundled file ');
    shell.exec('html-minifier framework-LiveVersion.html --remove-comments --minify-css --minify-js --remove-comments --use-short-doctype > minified/framework-LiveVersion.min.html');
    frameworkLiveVersionMinifiedFileInfo.size = fse.statSync('minified/framework-LiveVersion.min.html').size;
    frameworkLiveVersionCompressedFileInfo.size = frameworkLiveVersionMinifiedFileInfo.size;
    console.log(' Hashing the framework minified file ');
    var shasum = crypto.createHash(algorithm);
    shasum.update(fse.readFileSync('minified/framework-LiveVersion.min.html', 'utf8'));
    frameworkLiveVersionMinifiedFileInfo.sha1 = shasum.digest('hex');
    fse.writeFileSync('minified/framework-LiveVersion.info.json', JSON.stringify(frameworkLiveVersionMinifiedFileInfo));
    shell.rm('-rf', 'framework-LiveVersion.html');
    console.log(' Compresssing the framework minified file ');
    var gzip = zlib.createGzip();
    var inp = fse.createReadStream('minified/framework-LiveVersion.min.html');
    var out = fse.createWriteStream('compressed/framework-LiveVersion.min.html.gz');
    inp.pipe(gzip).pipe(out);
    console.log(' Hashing the framework compressed file ');
    var shasum = crypto.createHash(algorithm);
    shasum.update(fse.readFileSync('compressed/framework-LiveVersion.min.html.gz', 'utf8'));
    frameworkLiveVersionCompressedFileInfo.sha1 = shasum.digest('hex');
    fse.writeFileSync('compressed/framework-LiveVersion.info.json', JSON.stringify(frameworkLiveVersionCompressedFileInfo));
    console.log(' Jste Framework Live Version has been built properly ;) ');
    console.log(' ');
    console.log(' Starting building the BLOB DB Manager for Jste Framework Live Version ');
    var dbManagerMinifiedFileInfo = {};
    var dbManagerCompressedFileInfo = {};
    console.log(' Minifying the BLOB DB Manager file ');
    shell.exec('html-minifier ../utils/db-manager.html --remove-comments --minify-css --minify-js --remove-comments --use-short-doctype > minified/db-manager.min.html');
    dbManagerMinifiedFileInfo.size = fse.statSync('minified/db-manager.min.html').size;
    dbManagerCompressedFileInfo.size = dbManagerMinifiedFileInfo.size;
    console.log(' Hashing the BLOB DB Manager minified file ');
    var shasum = crypto.createHash(algorithm);
    shasum.update(fse.readFileSync('minified/db-manager.min.html', 'utf8'));
    dbManagerMinifiedFileInfo.sha1 = shasum.digest('hex');
    fse.writeFileSync('minified/db-manager.info.json', JSON.stringify(dbManagerMinifiedFileInfo));
    shell.rm('-rf', 'db-manager.html');
    console.log(' Compresssing the BLOB DB Manager minified file ');
    var gzip = zlib.createGzip();
    var inp = fse.createReadStream('minified/db-manager.min.html');
    var out = fse.createWriteStream('compressed/db-manager.min.html.gz');
    inp.pipe(gzip).pipe(out);
    console.log(' Hashing the BLOB DB Manager compressed file ');
    var shasum = crypto.createHash(algorithm);
    shasum.update(fse.readFileSync('compressed/db-manager.min.html.gz', 'utf8'));
    dbManagerCompressedFileInfo.sha1 = shasum.digest('hex');
    fse.writeFileSync('compressed/db-manager.info.json', JSON.stringify(dbManagerCompressedFileInfo));
    console.log(' The BLOB DB Manager for Jste Framework Live Version has been built properly ;) ');
    shell.cd('../');
    shell.rm('-rf', 'tmp');
    if (global.gitURLPrefix) {
        console.log(' ');
        console.log(' Updating the index ');
        shell.exec('git add .');
        console.log(' ');
        console.log(' Recording the change to the local repo ');
        shell.exec('git commit -m "' + global.commitMessage + '"');
        console.log(' ');
        console.log(' Pushing the updates to GitHub ');
        shell.exec('git push ' + gitURLPrefix + 'framework.git master');
    }
    if (shell.test('-d', '../manager')) {
        console.log(' ');
        console.log(' Preparing for building Jste Manager ');
        shell.cd('../manager');
        console.log(' ');
        console.log(' Updating framework file ');
        fs.createReadStream(path.resolve('..') + '/framework/build/compressed/framework.min.html.gz').pipe(fs.createWriteStream(path.resolve('.') + '/src/assets/framework.min.html.gz'));
        console.log(' ');
        console.log(' Starting building Jste Manager ');
        shell.exec('node build');
        if (global.gitURLPrefix) {
            console.log(' ');
            console.log(' Updating the index ');
            shell.exec('git add .');
            console.log(' ');
            console.log(' Recording the change to the local repo ');
            shell.exec('git commit -m "Updating Framework Files"');
            console.log(' ');
            console.log(' Pushing the updates to GitHub ');
            shell.exec('git push ' + gitURLPrefix + 'manager.git master');
        }
    }
    if (shell.test('-d', '../manager-heroku')) {
        console.log(' ');
        console.log(' Preparing for building Jste Manager Heroku version ');
        shell.cd('../manager-heroku');
        console.log(' ');
        console.log(' Updating framework file ');
        fs.createReadStream(path.resolve('..') + '/framework/build/compressed/framework-LiveVersion.min.html.gz').pipe(fs.createWriteStream(path.resolve('.') + '/assets/framework-LiveVersion.min.html.gz'));
        fs.createReadStream(path.resolve('..') + '/framework/build/compressed/db-manager.min.html.gz').pipe(fs.createWriteStream(path.resolve('.') + '/assets/db-manager.min.html.gz'));
        if (global.gitURLPrefix) {
            console.log(' ');
            console.log(' Updating the index ');
            shell.exec('git add .');
            console.log(' ');
            console.log(' Recording the change to the local repo ');
            shell.exec('git commit -m "Updating Framework Files"');
            console.log(' ');
            console.log(' Pushing the updates to GitHub ');
            shell.exec('git push ' + gitURLPrefix + 'manager-heroku.git master');
            console.log(' ');
            console.log(' Pushing the updates to Heroku ');
            shell.exec('git push heroku master');
        }
    }
    if (shell.test('-d', '../manager-phone')) {
        console.log(' ');
        console.log(' Preparing for building Jste Manager phone version ');
        shell.cd('../manager-phone/src');
        console.log(' ');
        console.log(' Updating framework file ');
        fs.createReadStream(path.resolve('../..') + '/framework/build/minified/framework.min.html').pipe(fs.createWriteStream(path.resolve('.') + '/www/jxcore/assets/framework.min.html'));
        console.log(' ');
        console.log(' Starting building Jste Manager phone version ');
        shell.exec('cordova build');
        shell.cd('../');
        shell.cp('src/platforms/android/build/outputs/apk/debug/android-debug.apk', 'build');
        if (global.gitURLPrefix) {
            console.log(' ');
            console.log(' Updating the index ');
            shell.exec('git add .');
            console.log(' ');
            console.log(' Recording the change to the local repo ');
            shell.exec('git commit -m "Updating Framework Files"');
            console.log(' ');
            console.log(' Pushing the updates to GitHub ');
            shell.exec('git push ' + gitURLPrefix + 'manager-phone.git master');
        }
    }
}

figlet('JSTE FRAMEWORK', function (err, data) {
    console.log(data);
    console.log('');
    console.log(' Welcome to Jste Framework builder :) ')
    inquirer
        .prompt([{
            type: 'confirm',
            name: 'deploy',
            message: 'Do you want to deploy this build ?'
        }])
        .then(options => {
            if (options.deploy == true) {
                inquirer
                    .prompt([{
                            type: 'input',
                            name: 'commit_message',
                            message: 'Please enter the commit message '
                        }, {
                            type: 'input',
                            name: 'git_username',
                            message: 'Please enter your GitHub username '
                        },
                        {
                            type: 'password',
                            name: 'git_password',
                            mask: '*',
                            message: 'Please enter your GitHub password '
                        }
                    ]).then(git_info => {
                        global.gitURLPrefix = 'https://' + git_info.git_username + ':' + git_info.git_password + '@github.com/project-jste/';
                        global.commitMessage = git_info.commit_message;
                        startBuild();
                    })
            } else {
                startBuild();
            }
        });
});<|endoftext|>


<commit_before>/*
 * Copyright (c) 2011-2012, Yahoo! Inc.  All rights reserved.
 * Copyrights licensed under the New BSD License.
 * See the accompanying LICENSE file for terms.
 */

/*jslint anon:true, sloppy:true, nomen:true, regexp:true, stupid:true*/

var libpath = require('path'),
    utils = require(libpath.join(__dirname, '../../management/utils')),
    fs = require('fs'),
    libqs = require('querystring'),
    MODE_755 = parseInt('755', 8),
    getSpecURL,
    mkdirP,
    rmdirR,
    writeWebPagesToFiles,
    YUI = require('yui').YUI,
    Y = YUI({useSync: true}).use('json-parse', 'json-stringify', 'escape');

Y.applyConfig({useSync: false});

/**
 * The usage string for this command.
 */
exports.usage = 'mojito build {type} [destination]\n' +
    "\t- type: 'html5app'\n" +
    '\t- destination: (optional) the directory where the build output goes.\n' +
    "\t  By default this is the type i.e. './artifacts/builds/<type>'\n" +
    '\nOPTIONS: \n' +
    '\t --replace: Tells the build system to delete the destination' +
    ' directory and replace it.\n' +
    '\t        -r: Short for --replace\n' +
    '\t --context: Tells the build system what context to build with' +
    ' i.e. device=iphone&lang=en-GB.\n' +
    '\t        -c: Short for --context\n';

/**
 * The options list for this command.
 */
exports.options = [
    {
        shortName: 'r',
        longName: 'replace',
        hasValue: false
    },
    {
        shortName: 'm',
        longName: 'mojit',
        hasValue: true
    },
    {
        shortName: 'c',
        longName: 'context',
        hasValue: true
    }
];

/**
 * The run() method which handles processing for this command.
 * @param {Array} params Optional parameters to the command.
 * @param {Object} options Optional options for the command.
 * @param {Function} callback Function to invoke on commmand completion.
 */
exports.run = function(params, options, callback) {
    var store,
        type = 'html5app',
        cwd = process.cwd(),
        destination,
        appConfig,
        config = {};

    Y.applyConfig({
        useSync: true,
        modules: {
            'mojito-util': {
                fullpath: libpath.join(__dirname, '../../app/autoload/util.common.js')
            },
            'mojito-resource-store': {
                fullpath: libpath.join(__dirname, '../../store.server.js')
            }
        }
    });
    Y.use('mojito-util', 'mojito-resource-store');
    Y.applyConfig({useSync: false});
    store = new Y.mojito.ResourceStore({
        root: cwd,
        context: {}
    });

    if (!params[0]) {
        params[0] = '';
    }

    switch (params[0].toUpperCase()) {
    case 'HTML5APP':
        type = 'html5app';
        break;
    default:
        utils.error("Can only build type '" + type + "'", exports.usage);
        return;
    }

    // Set the destination for the generated files
    if (params[1] && params[1][0] === '/') {
        destination = libpath.join(params[1]);
    } else if (params[1]) {
        destination = libpath.join(cwd, params[1]);
    } else {
        destination = libpath.join(cwd, 'artifacts/builds', type);
    }

    // Are we in a Mojito App?
    utils.isMojitoApp(cwd, exports.usage, true);

    appConfig = store.getStaticAppConfig();
    // Is there a "builds" section for this "type" in the appConfig
    if (appConfig.builds && appConfig.builds[type]) {
        config = appConfig.builds[type];
    }

    if (options.replace) {
        try {
            rmdirR(destination);
            console.log('Removing all files in folder "' + destination + '"');
        } catch (err2) {    // err2 to get past JSLint
            // Dirty way to check dir
        }
    }

    exports['build' + type](options, store, config, destination, callback);
};

/**
 * The build command itself.
 * @param {Object} cmdOptions Options for the command.
 * @param {Object} store The relevant resource store reference.
 * @param {Object} config Configuration data for the context.
 * @param {string} destination A path to target with build output.
 * @param {Function} callback A function to invoke on completion.
 */
exports.buildhtml5app = function(cmdOptions, store, config, destination,
    callback) {

    var type = 'HTML5 Application',
        i,
        from,
        to,
        // files to fetch through the server
        serverFiles = { css: true, js: true, json: true },
        extension,
        manifest = 'CACHE MANIFEST\n',
        indexJs = "module.exports = require('express')." +
            "createServer(require('express')['static'](__dirname));",
        url,
        storeURLs,
        urls = {}, // from: to
        app,
        context = '',
        contextObj = libqs.parse(cmdOptions.context),
        appConfig,
        tunnelPrefix,
        dynamicURLs = {},
        mr,
        mojitRes,
        mojitRess,
        sr,
        specRes,
        specRess,
        id;

    if (typeof cmdOptions.context === 'string') {
        // Parse the context into an object
        config.context = utils.contextCsvToObject(cmdOptions.context);
        // Stringify the context object into query string
        context = '?' + libqs.stringify(config.context);
    }

    urls['/' + context] = '/index.html';

    if (config.urls && config.urls.length) {
        for (i = 0; i < config.urls.length; i += 1) {
            urls[config.urls[i] + context] = config.urls[i];
        }
    }

    store.preload();

    appConfig = store.getAppConfig(contextObj);
    tunnelPrefix = appConfig.tunnelPrefix || '/tunnel';

    console.log('Building a "' + type + '" of the Mojito application at "' +
        store._config.root + '"');

    console.log('...');

    // Set the cachable files in the manifest
    manifest += 'CACHE:\n';

    // Copy all the files into the destination directory
    storeURLs = store.getAllURLs();
    for (url in storeURLs) {
        if (storeURLs.hasOwnProperty(url)) {
            from = storeURLs[url];  // filesystem path
            to = libpath.join(destination, url);
            extension = from.split('.').pop();

            mkdirP(libpath.dirname(to), MODE_755);

            manifest += url + '\n';

            if (serverFiles[extension]) {
                urls[url + context] = url;
                mkdirP(libpath.dirname(libpath.join(destination, url)),
                    MODE_755);
            } else {
                fs.writeFileSync(to, fs.readFileSync(from), 'utf8');
            }
        }
    }

    mojitRess = store.getResources('client', contextObj, {type: 'mojit'});
    for (mr = 0; mr < mojitRess.length; mr += 1) {
        mojitRes = mojitRess[mr];
        if (!mojitRes.url) {
            continue;
        }
        url = mojitRes.url + '/definition.json';
        dynamicURLs[url] = true;

        specRess = store.getResources('client', contextObj, {type: 'spec', mojit: mojitRes.name});
        for (sr = 0; sr < specRess.length; sr += 1) {
            specRes = specRess[sr];
            dynamicURLs[specRes.url] = true;
        }
    }

    for (id in appConfig.specs) {
        if (appConfig.specs.hasOwnProperty(id)) {
            url = getSpecURL(appConfig, id);
            dynamicURLs[url] = true;
        }
    }

    // Get all the dynamic URLs we have to call via the "tunnel"
    for (url in dynamicURLs) {
        if (dynamicURLs.hasOwnProperty(url)) {
            urls[tunnelPrefix + url + context] = url;
            mkdirP(libpath.dirname(libpath.join(destination, url)), MODE_755);
        }
    }

    for (url in urls) {
        if (urls.hasOwnProperty(url)) {
            manifest += (urls[url] === '/' ? '/index.html' : urls[url]) + '\n';
        }
    }

    // Write the "cache.manifest" file
    fs.writeFileSync(libpath.join(destination, 'cache.manifest'), manifest,
        'utf8');

    // Write a "quick test" index.js file
    fs.writeFileSync(libpath.join(destination, 'index.js'), indexJs, 'utf8');

    // Now use the server to generate some of the files
    writeWebPagesToFiles(type, store, destination, urls, config, callback);
};

getSpecURL = function(appConfig, id) {
    var prefix = '/static',
        parts = id.split(':'),
        typeName = parts[0],
        specName = parts[1] || 'default',
        ns = typeName.replace(/\./g, '_'),
        url;

    if (appConfig && appConfig.staticHandling &&
            appConfig.staticHandling.hasOwnProperty('prefix')) {
        prefix = (appConfig.staticHandling.prefix ? '/' +
            appConfig.staticHandling.prefix : '');
    }
    url = prefix + '/' + typeName + '/specs/' + specName + '.json';
    return url;
};

mkdirP = function(p, mode) {
    var ps = libpath.normalize(p).split('/'),
        i;

    for (i = 0; i <= ps.length; i += 1) {
        try {
            fs.mkdirSync(ps.slice(0, i).join('/'), mode);
        } catch (err) {
            // Dirty way to check dir
        }
    }
};

rmdirR = function(path) {
    var files = fs.readdirSync(path),
        currDir = path,
        i,
        currFile;

    /* Loop through and delete everything in the sub-tree after checking it */
    for (i = 0; i < files.length; i += 1) {
        currFile = fs.statSync(currDir + '/' + files[i]);

        if (currFile.isDirectory()) {
            // Recursive function back to the beginning
            rmdirR(currDir + '/' + files[i]);
        } else if (currFile.isSymbolicLink()) {
            // Unlink symlinks
            fs.unlinkSync(currDir + '/' + files[i]);
        } else {
            // Assume it's a file - perhaps a try/catch belongs here?
            fs.unlinkSync(currDir + '/' + files[i]);
        }
    }

    /*
     * Now that we know everything in the sub-tree has been deleted,
     * we can delete the main directory.
     */
    return fs.rmdirSync(path);
};

/**
 * Calculates the filesystem path to get from source to destination.
 *
 * @private
 * @param {string} dst The destination directory.
 * @param {string} src The source directory.
 * @return {string} The path from source to destination.
 */
function pathTo(dst, src) {
    var dstParts,
        srcParts,
        i,
        j,
        path = [];

    // trimming leading and trailing slashes removes nasty corner cases from the
    // algorithm
    if ('/' === dst.charAt(0)) {
        dst = dst.substring(1);
    }
    if ('/' === dst.charAt(dst.length - 1)) {
        dst = dst.substring(0, dst.length - 1);
    }
    if ('/' === src.charAt(0)) {
        src = src.substring(1);
    }
    if ('/' === src.charAt(src.length - 1)) {
        src = src.substring(0, src.length - 1);
    }

    dstParts = dst ? dst.split('/') : [];
    srcParts = src ? src.split('/') : [];
    path = [];
    for (i = 0; i < dstParts.length && i < srcParts.length; i += 1) {
        if (dstParts[i] !== srcParts[i]) {
            break;
        }
    }
    for (j = i; j < srcParts.length; j += 1) {
        path.push('..');
    }
    for (j = i; j < dstParts.length; j += 1) {
        path.push(dstParts[j]);
    }
    return libpath.join.apply(libpath, path) || '.';
}

/**
 * Adds the HTML5 cache manifest to the <html>
 *
 * @private
 * @param {string} root The directory where html5app is being built into.
 * @param {string} relativePath The file path, relative to root.
 * @param {string} content The body of the file.
 * @param {Boolean} force Whether to fixup the content, even though the path
 *     might not end in .html.
 * @return {string} The fixed up content.
 */
function attachManifest(root, relativePath, content, force) {
    var extname = libpath.extname(relativePath),
        dirname,
        pathToRoot;

    if (force || '.html' === extname) {
        dirname = libpath.dirname(relativePath);
        pathToRoot = pathTo('/', dirname);

        content = content.replace(/<html>/, '<html manifest="' + pathToRoot +
            '/cache.manifest">');
    }

    return content;
}

/**
 * Changes server-relative paths to file-relative paths.
 *
 * @private
 * @param {string} root The directory where html5app is being built into.
 * @param {string} relativePath The file path, relative to root.
 * @param {string} content The body of the file.
 * @param {Boolean} force Whether to fixup the content, even though the path
 *     might not end in .html.
 * @return {string} The fixed up content.
 */
function forceRelativePaths(root, relativePath, content, force) {
    var extname = libpath.extname(relativePath),
        dirname;

    if (force || '.html' === extname) {
        dirname = libpath.dirname(relativePath);

        content = content.replace(/(src|href)="([^"]+)"/g,
            function(all, name, val) {
                // FUTURE:  once the "/" aren't escaped, we can do this easier
                var fixed = utils.decodeHTMLEntities(val);
                if ('/' === fixed.charAt(0)) {
                    fixed = libpath.join(pathTo(libpath.dirname(fixed), dirname),
                        libpath.basename(fixed));
                }
                fixed = Y.Escape.html(fixed);
                return name + '="' + fixed + '"';
            });
    }

    return content;
}

writeWebPagesToFiles = function(type, store, destination, urls, config,
        callback) {
    var options,
        userPages = {},
        i,
        app;

    if (config.urls) {
        // If the user is using builds.html5app.attachManifest or
        // .forceRelativePaths, we explicitly want to fix those URLs which are
        // pages (the ones they've specified).
        for (i = 0; i < config.urls.length; i += 1) {
            userPages[config.urls[i]] = true;
        }
    }

    options = {
        port: 11111,
        context: config.context
    };

    app = new utils.App(options);

    app.start(function(err) {
        var got = 0,
            need;

        if (err) {
            utils.error(err);
            return;
        }
        need = Object.keys(urls).length;

        Object.keys(urls).forEach(function(u) {
            var opts = {
                    headers: {
                        'x-mojito-build': 'html5app',
                        'x-mojito-build-path-to-root': pathTo('/',
                            libpath.dirname(urls[u]))
                    }
                };
            app.getWebPage(u, opts, function(err, url, content) {
                var dest;

                got += 1;

                if (err) {
                    utils.error('FAILED to get ' + url + ' with error:\n' +
                                err, null, true);
                } else {
                    if (config.attachManifest) {
                        content = attachManifest(destination, urls[url],
                            content,
                            userPages[url]);
                    }
                    if (config.forceRelativePaths) {
                        content = forceRelativePaths(destination, urls[url],
                            content,
                            userPages[url]
                            );
                    }
                    dest = libpath.join(destination, urls[url]);
                    mkdirP(libpath.dirname(dest), MODE_755);
                    fs.writeFileSync(dest, content, 'utf8');
                }

                if (got === need) {
                    app.close();
                    callback();
                }
            });
        });
    });
};
<commit_msg>Bug fix for accessing app.json builds with correct context.<commit_after>/*
 * Copyright (c) 2011-2012, Yahoo! Inc.  All rights reserved.
 * Copyrights licensed under the New BSD License.
 * See the accompanying LICENSE file for terms.
 */

/*jslint anon:true, sloppy:true, nomen:true, regexp:true, stupid:true*/

var libpath = require('path'),
    utils = require(libpath.join(__dirname, '../../management/utils')),
    fs = require('fs'),
    libqs = require('querystring'),
    MODE_755 = parseInt('755', 8),
    getSpecURL,
    mkdirP,
    rmdirR,
    writeWebPagesToFiles,
    YUI = require('yui').YUI,
    Y = YUI({useSync: true}).use('json-parse', 'json-stringify', 'escape');

Y.applyConfig({useSync: false});

/**
 * The usage string for this command.
 */
exports.usage = 'mojito build {type} [destination]\n' +
    "\t- type: 'html5app'\n" +
    '\t- destination: (optional) the directory where the build output goes.\n' +
    "\t  By default this is the type i.e. './artifacts/builds/<type>'\n" +
    '\nOPTIONS: \n' +
    '\t --replace: Tells the build system to delete the destination' +
    ' directory and replace it.\n' +
    '\t        -r: Short for --replace\n' +
    '\t --context: Tells the build system what context to build with' +
    ' i.e. device=iphone&lang=en-GB.\n' +
    '\t        -c: Short for --context\n';

/**
 * The options list for this command.
 */
exports.options = [
    {
        shortName: 'r',
        longName: 'replace',
        hasValue: false
    },
    {
        shortName: 'm',
        longName: 'mojit',
        hasValue: true
    },
    {
        shortName: 'c',
        longName: 'context',
        hasValue: true
    }
];

/**
 * The run() method which handles processing for this command.
 * @param {Array} params Optional parameters to the command.
 * @param {Object} options Optional options for the command.
 * @param {Function} callback Function to invoke on commmand completion.
 */
exports.run = function(params, options, callback) {
    var store,
        type = 'html5app',
        cwd = process.cwd(),
        destination,
        appConfig,
        config = {},
        context = {};

    Y.applyConfig({
        useSync: true,
        modules: {
            'mojito-util': {
                fullpath: libpath.join(__dirname, '../../app/autoload/util.common.js')
            },
            'mojito-resource-store': {
                fullpath: libpath.join(__dirname, '../../store.server.js')
            }
        }
    });

    if (typeof options.context === 'string') {
        // Parse the context into an object
        context = utils.contextCsvToObject(options.context);
    }

    Y.use('mojito-util', 'mojito-resource-store');
    Y.applyConfig({useSync: false});
    store = new Y.mojito.ResourceStore({
        root: cwd,
        context: context
    });

    if (!params[0]) {
        params[0] = '';
    }

    switch (params[0].toUpperCase()) {
    case 'HTML5APP':
        type = 'html5app';
        break;
    default:
        utils.error("Can only build type '" + type + "'", exports.usage);
        return;
    }

    // Set the destination for the generated files
    if (params[1] && params[1][0] === '/') {
        destination = libpath.join(params[1]);
    } else if (params[1]) {
        destination = libpath.join(cwd, params[1]);
    } else {
        destination = libpath.join(cwd, 'artifacts/builds', type);
    }

    // Are we in a Mojito App?
    utils.isMojitoApp(cwd, exports.usage, true);

    appConfig = store.getStaticAppConfig();
    // Is there a "builds" section for this "type" in the appConfig
    if (appConfig.builds && appConfig.builds[type]) {
        config = appConfig.builds[type];
    }

    if (options.replace) {
        try {
            rmdirR(destination);
            console.log('Removing all files in folder "' + destination + '"');
        } catch (err2) {    // err2 to get past JSLint
            // Dirty way to check dir
        }
    }

    exports['build' + type](options, store, config, destination, callback);
};

/**
 * The build command itself.
 * @param {Object} cmdOptions Options for the command.
 * @param {Object} store The relevant resource store reference.
 * @param {Object} config Configuration data for the context.
 * @param {string} destination A path to target with build output.
 * @param {Function} callback A function to invoke on completion.
 */
exports.buildhtml5app = function(cmdOptions, store, config, destination,
    callback) {

    var type = 'HTML5 Application',
        i,
        from,
        to,
        // files to fetch through the server
        serverFiles = { css: true, js: true, json: true },
        extension,
        manifest = 'CACHE MANIFEST\n',
        indexJs = "module.exports = require('express')." +
            "createServer(require('express')['static'](__dirname));",
        url,
        storeURLs,
        urls = {}, // from: to
        app,
        context = '',
        contextObj = libqs.parse(cmdOptions.context),
        appConfig,
        tunnelPrefix,
        dynamicURLs = {},
        mr,
        mojitRes,
        mojitRess,
        sr,
        specRes,
        specRess,
        id;

    if (typeof cmdOptions.context === 'string') {
        // Parse the context into an object
        config.context = utils.contextCsvToObject(cmdOptions.context);
        // Stringify the context object into query string
        context = '?' + libqs.stringify(config.context);
    }

    urls['/' + context] = '/index.html';

    if (config.urls && config.urls.length) {
        for (i = 0; i < config.urls.length; i += 1) {
            urls[config.urls[i] + context] = config.urls[i];
        }
    }

    store.preload();

    appConfig = store.getAppConfig(contextObj);
    tunnelPrefix = appConfig.tunnelPrefix || '/tunnel';

    console.log('Building a "' + type + '" of the Mojito application at "' +
        store._config.root + '"');

    console.log('...');

    // Set the cachable files in the manifest
    manifest += 'CACHE:\n';

    // Copy all the files into the destination directory
    storeURLs = store.getAllURLs();
    for (url in storeURLs) {
        if (storeURLs.hasOwnProperty(url)) {
            from = storeURLs[url];  // filesystem path
            to = libpath.join(destination, url);
            extension = from.split('.').pop();

            mkdirP(libpath.dirname(to), MODE_755);

            manifest += url + '\n';

            if (serverFiles[extension]) {
                urls[url + context] = url;
                mkdirP(libpath.dirname(libpath.join(destination, url)),
                    MODE_755);
            } else {
                fs.writeFileSync(to, fs.readFileSync(from), 'utf8');
            }
        }
    }

    mojitRess = store.getResources('client', contextObj, {type: 'mojit'});
    for (mr = 0; mr < mojitRess.length; mr += 1) {
        mojitRes = mojitRess[mr];
        if (!mojitRes.url) {
            continue;
        }
        url = mojitRes.url + '/definition.json';
        dynamicURLs[url] = true;

        specRess = store.getResources('client', contextObj, {type: 'spec', mojit: mojitRes.name});
        for (sr = 0; sr < specRess.length; sr += 1) {
            specRes = specRess[sr];
            dynamicURLs[specRes.url] = true;
        }
    }

    for (id in appConfig.specs) {
        if (appConfig.specs.hasOwnProperty(id)) {
            url = getSpecURL(appConfig, id);
            dynamicURLs[url] = true;
        }
    }

    // Get all the dynamic URLs we have to call via the "tunnel"
    for (url in dynamicURLs) {
        if (dynamicURLs.hasOwnProperty(url)) {
            urls[tunnelPrefix + url + context] = url;
            mkdirP(libpath.dirname(libpath.join(destination, url)), MODE_755);
        }
    }

    for (url in urls) {
        if (urls.hasOwnProperty(url)) {
            manifest += (urls[url] === '/' ? '/index.html' : urls[url]) + '\n';
        }
    }

    // Write the "cache.manifest" file
    fs.writeFileSync(libpath.join(destination, 'cache.manifest'), manifest,
        'utf8');

    // Write a "quick test" index.js file
    fs.writeFileSync(libpath.join(destination, 'index.js'), indexJs, 'utf8');

    // Now use the server to generate some of the files
    writeWebPagesToFiles(type, store, destination, urls, config, callback);
};

getSpecURL = function(appConfig, id) {
    var prefix = '/static',
        parts = id.split(':'),
        typeName = parts[0],
        specName = parts[1] || 'default',
        ns = typeName.replace(/\./g, '_'),
        url;

    if (appConfig && appConfig.staticHandling &&
            appConfig.staticHandling.hasOwnProperty('prefix')) {
        prefix = (appConfig.staticHandling.prefix ? '/' +
            appConfig.staticHandling.prefix : '');
    }
    url = prefix + '/' + typeName + '/specs/' + specName + '.json';
    return url;
};

mkdirP = function(p, mode) {
    var ps = libpath.normalize(p).split('/'),
        i;

    for (i = 0; i <= ps.length; i += 1) {
        try {
            fs.mkdirSync(ps.slice(0, i).join('/'), mode);
        } catch (err) {
            // Dirty way to check dir
        }
    }
};

rmdirR = function(path) {
    var files = fs.readdirSync(path),
        currDir = path,
        i,
        currFile;

    /* Loop through and delete everything in the sub-tree after checking it */
    for (i = 0; i < files.length; i += 1) {
        currFile = fs.statSync(currDir + '/' + files[i]);

        if (currFile.isDirectory()) {
            // Recursive function back to the beginning
            rmdirR(currDir + '/' + files[i]);
        } else if (currFile.isSymbolicLink()) {
            // Unlink symlinks
            fs.unlinkSync(currDir + '/' + files[i]);
        } else {
            // Assume it's a file - perhaps a try/catch belongs here?
            fs.unlinkSync(currDir + '/' + files[i]);
        }
    }

    /*
     * Now that we know everything in the sub-tree has been deleted,
     * we can delete the main directory.
     */
    return fs.rmdirSync(path);
};

/**
 * Calculates the filesystem path to get from source to destination.
 *
 * @private
 * @param {string} dst The destination directory.
 * @param {string} src The source directory.
 * @return {string} The path from source to destination.
 */
function pathTo(dst, src) {
    var dstParts,
        srcParts,
        i,
        j,
        path = [];

    // trimming leading and trailing slashes removes nasty corner cases from the
    // algorithm
    if ('/' === dst.charAt(0)) {
        dst = dst.substring(1);
    }
    if ('/' === dst.charAt(dst.length - 1)) {
        dst = dst.substring(0, dst.length - 1);
    }
    if ('/' === src.charAt(0)) {
        src = src.substring(1);
    }
    if ('/' === src.charAt(src.length - 1)) {
        src = src.substring(0, src.length - 1);
    }

    dstParts = dst ? dst.split('/') : [];
    srcParts = src ? src.split('/') : [];
    path = [];
    for (i = 0; i < dstParts.length && i < srcParts.length; i += 1) {
        if (dstParts[i] !== srcParts[i]) {
            break;
        }
    }
    for (j = i; j < srcParts.length; j += 1) {
        path.push('..');
    }
    for (j = i; j < dstParts.length; j += 1) {
        path.push(dstParts[j]);
    }
    return libpath.join.apply(libpath, path) || '.';
}

/**
 * Adds the HTML5 cache manifest to the <html>
 *
 * @private
 * @param {string} root The directory where html5app is being built into.
 * @param {string} relativePath The file path, relative to root.
 * @param {string} content The body of the file.
 * @param {Boolean} force Whether to fixup the content, even though the path
 *     might not end in .html.
 * @return {string} The fixed up content.
 */
function attachManifest(root, relativePath, content, force) {
    var extname = libpath.extname(relativePath),
        dirname,
        pathToRoot;

    if (force || '.html' === extname) {
        dirname = libpath.dirname(relativePath);
        pathToRoot = pathTo('/', dirname);

        content = content.replace(/<html>/, '<html manifest="' + pathToRoot +
            '/cache.manifest">');
    }

    return content;
}

/**
 * Changes server-relative paths to file-relative paths.
 *
 * @private
 * @param {string} root The directory where html5app is being built into.
 * @param {string} relativePath The file path, relative to root.
 * @param {string} content The body of the file.
 * @param {Boolean} force Whether to fixup the content, even though the path
 *     might not end in .html.
 * @return {string} The fixed up content.
 */
function forceRelativePaths(root, relativePath, content, force) {
    var extname = libpath.extname(relativePath),
        dirname;

    if (force || '.html' === extname) {
        dirname = libpath.dirname(relativePath);

        content = content.replace(/(src|href)="([^"]+)"/g,
            function(all, name, val) {
                // FUTURE:  once the "/" aren't escaped, we can do this easier
                var fixed = utils.decodeHTMLEntities(val);
                if ('/' === fixed.charAt(0)) {
                    fixed = libpath.join(pathTo(libpath.dirname(fixed), dirname),
                        libpath.basename(fixed));
                }
                fixed = Y.Escape.html(fixed);
                return name + '="' + fixed + '"';
            });
    }

    return content;
}

writeWebPagesToFiles = function(type, store, destination, urls, config,
        callback) {
    var options,
        userPages = {},
        i,
        app;

    if (config.urls) {
        // If the user is using builds.html5app.attachManifest or
        // .forceRelativePaths, we explicitly want to fix those URLs which are
        // pages (the ones they've specified).
        for (i = 0; i < config.urls.length; i += 1) {
            userPages[config.urls[i]] = true;
        }
    }

    options = {
        port: 11111,
        context: config.context
    };

    app = new utils.App(options);

    app.start(function(err) {
        var got = 0,
            need;

        if (err) {
            utils.error(err);
            return;
        }
        need = Object.keys(urls).length;

        Object.keys(urls).forEach(function(u) {
            var opts = {
                    headers: {
                        'x-mojito-build': 'html5app',
                        'x-mojito-build-path-to-root': pathTo('/',
                            libpath.dirname(urls[u]))
                    }
                };
            app.getWebPage(u, opts, function(err, url, content) {
                var dest;

                got += 1;

                if (err) {
                    utils.error('FAILED to get ' + url + ' with error:\n' +
                                err, null, true);
                } else {
                    if (config.attachManifest) {
                        content = attachManifest(destination, urls[url],
                            content,
                            userPages[url]);
                    }
                    if (config.forceRelativePaths) {
                        content = forceRelativePaths(destination, urls[url],
                            content,
                            userPages[url]
                            );
                    }
                    dest = libpath.join(destination, urls[url]);
                    mkdirP(libpath.dirname(dest), MODE_755);
                    fs.writeFileSync(dest, content, 'utf8');
                }

                if (got === need) {
                    app.close();
                    callback();
                }
            });
        });
    });
};
<|endoftext|>


<commit_before>'use strict';
var beautify = require('js-beautify').html;
var branch = require('metalsmith-branch');
var collections = require('metalsmith-collections');
var config = require('./config.json');
var drafts = require('metalsmith-drafts');
var excerpts = require('metalsmith-excerpts');
var layouts = require('metalsmith-layouts');
var markdown = require('metalsmith-markdown');
var metalsmith = require('metalsmith');
var minify = require('html-minifier').minify;
var moment = require('moment');
var nunjucks = require('nunjucks');
var permalinks = require('metalsmith-permalinks');
var sourcelink = require('metalsmith-source-link');
var typography = require('metalsmith-typography');

nunjucks.configure('./templates', {watch: false});

module.exports = function(callback) {
  return metalsmith(__dirname)
  .metadata({
    site: config
  })
  .clean(false) // leave for gulp
  .source('./src')
  .destination('./build')
  .ignore(['.*.swp'])
  .use(sourcelink('https://github.com/earnubs/field-notes/tree/master/'))
  .use(drafts())
  .use(markdown({
    langPrefix: 'hl',
    highlight: function (code) {
      return require('highlight.js').highlightAuto(code).value;
    }
  }))
  .use(typography())
  .use(excerpts())
  .use(
    collections({
      posts: {
        pattern: 'posts/**.html',
        sortBy: 'publishedDate',
        reverse: true
      }
    })
  )
  .use(
    branch('posts/**.html')
    .use(permalinks({
      pattern: 'posts/:title',
      relative: false
    }))
  )
  .use(
    branch(['!posts/**.html', '!index.html'])
    .use(permalinks({
      relative: false
    }))
  )
  .use(
    layouts({
      engine: 'nunjucks',
      default: 'base.html',
      directory: 'templates',
      pattern: '**/*.html',
      moment: moment
    })
  )
  .use(function(files, metalsmith, done) {
    Object.keys(files).forEach(function(file) {
      var content = files[file].contents.toString();
      var min = minify(content, {
        removeAttributeQuotes: true,
        removeComments: true,
        collapseBooleanAttributes: true,
        removeRedundantAttributes: true,
        removeEmptyAttributes: true,
        removeScriptTypeAttributes: true,
        removeStyleLinkTypeAttributes: true,
        removeOptionalTags: true
      });
      var beaut = beautify(min, {
        'indent_size': 2,
        'indent_char': ' ',
        'eol': '\n',
        'indent_level': 0,
        'indent_with_tabs': false,
        'preserve_newlines': true,
        'max_preserve_newlines': 0,
        'brace_style': 'collapse',
        'wrap_line_length': 0,
        'wrap_attributes': 'auto',
        'wrap_attributes_indent_size': 4,
        'end_with_newline': true,
        'extra_liners': 'head,body,pre,/html]'
      });

      files[file].contents = new Buffer(beaut);
    });
    done();
  })
  .build(function(err) {
    if (err) {
      throw new Error(err);
    } else {
      return callback(); // let gulp run async
    }
  });
};
<commit_msg>21st century js<commit_after>'use strict';
const beautify = require('js-beautify').html;
const branch = require('metalsmith-branch');
const collections = require('metalsmith-collections');
const drafts = require('metalsmith-drafts');
const excerpts = require('metalsmith-excerpts');
const layouts = require('metalsmith-layouts');
const markdown = require('metalsmith-markdown');
const metalsmith = require('metalsmith');
const minify = require('html-minifier').minify;
const moment = require('moment');
const nunjucks = require('nunjucks');
const permalinks = require('metalsmith-permalinks');
const sourcelink = require('metalsmith-source-link');
const typography = require('metalsmith-typography');

const config = require('./config.json');

nunjucks.configure('./templates', {watch: false});

module.exports = function(callback) {
  return metalsmith(__dirname)
  .metadata({
    site: config
  })
  .clean(false) // leave for gulp
  .source('./src')
  .destination('./build')
  .ignore(['.*.swp'])
  .use(sourcelink('https://github.com/earnubs/field-notes/tree/master/'))
  .use(drafts())
  .use(markdown({
    langPrefix: 'hl',
    highlight: (code) => {
      return require('highlight.js').highlightAuto(code).value;
    }
  }))
  .use(typography())
  .use(excerpts())
  .use(
    collections({
      posts: {
        pattern: 'posts/**.html',
        sortBy: 'publishedDate',
        reverse: true
      }
    })
  )
  .use(
    branch('posts/**.html')
    .use(permalinks({
      pattern: 'posts/:title',
      relative: false
    }))
  )
  .use(
    branch(['!posts/**.html', '!index.html'])
    .use(permalinks({
      relative: false
    }))
  )
  .use(
    layouts({
      engine: 'nunjucks',
      default: 'base.html',
      directory: 'templates',
      pattern: '**/*.html',
      moment: moment
    })
  )
  .use((files, metalsmith, done) => {
    Object.keys(files).forEach((file) => {
      const content = files[file].contents.toString();
      const min = minify(content, {
        removeAttributeQuotes: true,
        removeComments: true,
        collapseBooleanAttributes: true,
        removeRedundantAttributes: true,
        removeEmptyAttributes: true,
        removeScriptTypeAttributes: true,
        removeStyleLinkTypeAttributes: true,
        removeOptionalTags: true
      });
      const beaut = beautify(min, {
        'indent_size': 2,
        'indent_char': ' ',
        'eol': '\n',
        'indent_level': 0,
        'indent_with_tabs': false,
        'preserve_newlines': true,
        'max_preserve_newlines': 0,
        'brace_style': 'collapse',
        'wrap_line_length': 0,
        'wrap_attributes': 'auto',
        'wrap_attributes_indent_size': 4,
        'end_with_newline': true,
        'extra_liners': 'head,body,pre,/html]'
      });

      files[file].contents = new Buffer(beaut);
    });
    done();
  })
  .build((err) => {
    if (err) {
      throw new Error(err);
    } else {
      return callback(); // let gulp run async
    }
  });
};
<|endoftext|>


<commit_before>var Observable = function() {
  this.subscribers = {};
}

Observable.prototype.on = function(ev, f) {
  if (this.subscribers[ev] == void 0) {
    this.subscribers[ev] = [];
  }
  this.subscribers[ev].push(f);
  return this;
}

Observable.prototype.fire = function(ev, data) {
  var found = this.subscribers[ev];
  if (found != void 0) {
    for (var i = 0; i < found.length; i++) {
      found[i](data);
    }
  }
  return this;
}

function getUrlVars() {
  var vars = [];
  var pairs = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&');

  for (var i = 0; i < pairs.length; i++) {
    var pair = pairs[i].split('=');
    vars.push(decodeURIComponent(pair[0]));
    vars[pair[0]] = pair[1];
  }

  return vars;
}

var JobView = function() {
  var li, bar, timeText;

  return {
    init: function(parent, job, values) {
      li = document.createElement("li");
      li.className = job.status();

      var h1 = document.createElement("h1");
      h1.appendChild(document.createTextNode(values.name));

      var time = document.createElement("time");
      timeText = document.createTextNode(job.verb() + " " + job.time());
      time.appendChild(timeText);

      li.appendChild(h1);
      li.appendChild(time);

      bar = document.createElement("div");
      bar.classList.add("bar");
      bar.setAttribute("style", "width: " + job.percentage() + "%;");

      li.appendChild(bar);
      parent.append(li);
    },
    refresh: function(job) {
      li.className = job.status();
      timeText.textContent = job.verb() + " " + job.time();
      bar.setAttribute("style", "width: " + job.percentage() + "%;");
    }
  }
}

var Job = function(values, observable) {
  var _values = values, _observable = observable, view = new JobView();

  return {
    init: function(parent) {
      view.init(parent, this, _values);
    },
    status: function() {
      switch (_values.colour) {
      case "blue":          return "not-building";
      case "red":           return "failed";
      case "red_anime":     return "was-failed in-progress";
      case "blue_anime":    return "was-built in-progress";
      case "aborted_anime": return "was-aborted in-progress";
      default:              return "no-change";
      }
    },
    percentage: function() {
      var duration = Date.now() - _values.startedAt;
      var percentage = Math.round((duration / _values.estimatedDuration) * 100);

      return percentage > 100 ? 100 : percentage;
    },
    time: function() {
      return moment.unix(_values.startedAt / 1000).fromNow();
    },
    verb: function() {
      if (this.status().indexOf("in-progress") != -1)
        return "started";

      if (this.status() == "failed")
        return "failed";

      return "finished";
    },
    update: function(values) {
      view.refresh(this);

      var transitionFor = function(oldColour, newColour) {
        if (oldColour === undefined)
          return "new";
        if (newColour=="blue" && oldColour=="blue_anime")
          return "successful";
        if (newColour=="blue" && oldColour=="red_anime")
          return "fixed";
        if (newColour=="red" && oldColour=="blue_anime")
          return "failed";
        if (newColour=="red" && oldColour=="red_anime")
          return "repeatedlyFailing";
        if (newColour.match(/_anime$/) && !oldColour.match(/_anime$/))
          return "started";
        return "noChange";
      }

      var transition = transitionFor(_values.color, values.color);

      _values = values;
      observable.fire('job_' + transition);
    }
  };
};

var Jobs = function(el, baseUrl, ignore) {
  var ul = $(el).html("");
  var _jobs = {};
  var lastColor = null;
  var _baseUrl = baseUrl;
  var _ignore = ignore;
  var observable = new Observable();

  observable.on('update', function(data) {
    for (var i = 0; i < data.jobs.length; i++) {
      var job = data.jobs[i];

      if (_ignore(job.name)) { continue; }
      if (job.lastBuild == null) { continue; }

      var values = {
        name: job.name,
        colour: job.color,
        startedAt: job.lastBuild.timestamp,
        estimatedDuration: job.lastBuild.estimatedDuration
      };

      if (_jobs[values.name] === void 0) {
        _jobs[values.name] = new Job(values, observable);
        _jobs[values.name].init(ul);
      } else {
        _jobs[values.name].update(values);
      }
    }

    var c = this.color();
    if (c != lastColor) {
      lastColor = c;
      observable.fire(c);
    }
  }.bind(this));

  // Events: (update(data), disconnected, red, anime, green)
  this.on = observable.on.bind(observable);

  this.poll = function() {
    var url = _baseUrl + "/api/json?depth=2&tree=jobs[name,color,lastBuild[number,builtOn,duration,estimatedDuration,timestamp,result]]";
    $.ajax({
      url: url,
      timeout: 5000
    }).done(function(data) {
      observable.fire('connected');
      observable.fire('update', data);
    }).fail(function(err) {
      observable.fire('disconnected', err);
    });
  };

  this.color = function() {
    var verbs = {};
    for (var job in _jobs) {
      var v = _jobs[job].verb();
      if (!verbs[v]) { verbs[v] = 0; }
      verbs[v] += 1;
    }

    if (verbs['failed'] > 0) return 'red';
    if (verbs['started'] > 0) return 'anime';
    return 'green';
  };

  this.reset = function () {
    lastColor = null;
  }

  this.observable = observable;
};

var bonusRound = {
  cat: function(jobs) {
    var box = $('#box').hide();

    jobs.on('green', function() {
      imageShow("http://thecatapi.com/api/images/get.php?format=src&type=gif&t=" + new Date().getTime());
    }).on('anime', function() {
      imageHide();
    }).on('red', function() {
      imageHide();
    });
  },
  porkour: function(jobs) {
    var box = $('#box').hide();

    jobs.on('green', function() {
      imageShow("http://i.imgur.com/pIxorOD.gif")
    }).on('anime', function() {
      imageHide();
    }).on('red', function() {
      imageHide();
    });
  },
  green: function(jobs) {
    jobs.on('green', function() {
      $('body').css({background: 'green'});
    }).on('anime', function() {
      $('body').css({background: 'black'});
    }).on('red', function() {
      $('body').css({background: 'black'});
    });
  },
  guid: function(jobs) {
    jobs.on('green', function() {
      $('#box').show();
      $('#box').html("
" + Math.uuid() + "
");
    }).on('anime', function() {
      $('#box').hide();
    }).on('red', function() {
      $('#box').hide();
    });
  }
}

var audioList = {
  classic: function(jobs) {
    var play = function(path) {
      var _audio;
      return function() {
        if (_audio === void 0) {
          _audio = new Audio(path);
        }
        _audio.play();
      }
    }

    jobs.on('job_fixed', play('audioz/classic/fixed.mp3'))
        .on('job_failed', play('audioz/classic/failed.mp3'))
        .on('job_repeatedlyFailing', play('audioz/classic/repeatedlyFailing.mp3'));
  }
}

function imageShow(url) {
  $('body').css({
      "background-image": 'url("' + url + '")',
  });
}

function imageHide() {
  $('body').css({"background-image": ""});
}

$(function() {
  var vars = getUrlVars(),
      baseUrl = vars["server"],
      theme = vars["theme"],
      filters = (vars["filters"] || "").toLowerCase().split(','),
      scope = vars["scope"] || "contains",
      showInactive = vars["showInactive"],
      bonusName = vars["bonusRound"],
      audioName = vars['audio'];

  var nameMatcher = (scope == "contains")
    ? function (name, filter) { return name.indexOf(filter) !== -1; }
    : function (name, filter) { return name.indexOf(filter) === 0; };

  var ignore = function(name) {
    return filters.length > 0 && !filters.some(function (filter) { return nameMatcher(name.toLowerCase(), filter); })
  };

  var jobs = new Jobs('ul', baseUrl, ignore);

  if (theme == "neon") { $('body').addClass('neon'); }
  if (showInactive)  { $('body').addClass('show-inactive'); }

  if (bonusName != void 0 && bonusRound[bonusName] != void 0) {
    bonusRound[bonusName](jobs);
  }

  if (audioName != void 0 && audioList[audioName] != void 0) {
    audioList[audioName](jobs);
  }

  $(document).on('click', function() {
    jobs.reset();
    jobs.poll();
  });

  jobs.on('disconnected', function(err) {
    console.log("Error contacting the build server", err);
    imageShow("http://i.stack.imgur.com/jiFfM.jpg");
  }).on('connected', function() {
    imageHide();
  });

  window.setInterval(function() { jobs.poll(); }, 5000);
  jobs.poll();
});
<commit_msg>Allow debugging<commit_after>var Observable = function() {
  this.subscribers = {};
}

Observable.prototype.on = function(ev, f) {
  if (this.subscribers[ev] == void 0) {
    this.subscribers[ev] = [];
  }
  this.subscribers[ev].push(f);
  return this;
}

Observable.prototype.fire = function(ev, data) {
  var found = this.subscribers[ev];
  if (found != void 0) {
    for (var i = 0; i < found.length; i++) {
      found[i](data);
    }
  }
  return this;
}

function getUrlVars() {
  var vars = [];
  var pairs = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&');

  for (var i = 0; i < pairs.length; i++) {
    var pair = pairs[i].split('=');
    vars.push(decodeURIComponent(pair[0]));
    vars[pair[0]] = pair[1];
  }

  return vars;
}

var JobView = function() {
  var li, bar, timeText;

  return {
    init: function(parent, job, values) {
      li = document.createElement("li");
      li.className = job.status();

      var h1 = document.createElement("h1");
      h1.appendChild(document.createTextNode(values.name));

      var time = document.createElement("time");
      timeText = document.createTextNode(job.verb() + " " + job.time());
      time.appendChild(timeText);

      li.appendChild(h1);
      li.appendChild(time);

      bar = document.createElement("div");
      bar.classList.add("bar");
      bar.setAttribute("style", "width: " + job.percentage() + "%;");

      li.appendChild(bar);
      parent.append(li);
    },
    refresh: function(job) {
      li.className = job.status();
      timeText.textContent = job.verb() + " " + job.time();
      bar.setAttribute("style", "width: " + job.percentage() + "%;");
    }
  }
}

var Job = function(values, observable) {
  var _values = values, _observable = observable, view = new JobView();

  return {
    init: function(parent) {
      view.init(parent, this, _values);
    },
    status: function() {
      switch (_values.colour) {
      case "blue":          return "not-building";
      case "red":           return "failed";
      case "red_anime":     return "was-failed in-progress";
      case "blue_anime":    return "was-built in-progress";
      case "aborted_anime": return "was-aborted in-progress";
      default:              return "no-change";
      }
    },
    percentage: function() {
      var duration = Date.now() - _values.startedAt;
      var percentage = Math.round((duration / _values.estimatedDuration) * 100);

      return percentage > 100 ? 100 : percentage;
    },
    time: function() {
      return moment.unix(_values.startedAt / 1000).fromNow();
    },
    verb: function() {
      if (this.status().indexOf("in-progress") != -1)
        return "started";

      if (this.status() == "failed")
        return "failed";

      return "finished";
    },
    update: function(values) {
      view.refresh(this);

      var transitionFor = function(oldColour, newColour) {
        if (oldColour === undefined)
          return "new";
        if (newColour=="blue" && oldColour=="blue_anime")
          return "successful";
        if (newColour=="blue" && oldColour=="red_anime")
          return "fixed";
        if (newColour=="red" && oldColour=="blue_anime")
          return "failed";
        if (newColour=="red" && oldColour=="red_anime")
          return "repeatedlyFailing";
        if (newColour.match(/_anime$/) && !oldColour.match(/_anime$/))
          return "started";
        return "noChange";
      }

      var transition = transitionFor(_values.color, values.color);

      _values = values;
      observable.fire('job_' + transition);
    }
  };
};

var Jobs = function(el, baseUrl, ignore) {
  var ul = $(el).html("");
  var _jobs = {};
  var lastColor = null;
  var _baseUrl = baseUrl;
  var _ignore = ignore;
  var observable = new Observable();

  observable.on('update', function(data) {
    for (var i = 0; i < data.jobs.length; i++) {
      var job = data.jobs[i];

      if (_ignore(job.name)) { continue; }
      if (job.lastBuild == null) { continue; }

      var values = {
        name: job.name,
        colour: job.color,
        startedAt: job.lastBuild.timestamp,
        estimatedDuration: job.lastBuild.estimatedDuration
      };

      if (_jobs[values.name] === void 0) {
        _jobs[values.name] = new Job(values, observable);
        _jobs[values.name].init(ul);
      } else {
        _jobs[values.name].update(values);
      }
    }

    var c = this.color();
    if (c != lastColor) {
      lastColor = c;
      observable.fire(c);
    }
  }.bind(this));

  // Events: (update(data), disconnected, red, anime, green)
  this.on = observable.on.bind(observable);

  this.poll = function() {
    var url = _baseUrl + "/api/json?depth=2&tree=jobs[name,color,lastBuild[number,builtOn,duration,estimatedDuration,timestamp,result]]";
    $.ajax({
      url: url,
      timeout: 5000
    }).done(function(data) {
      observable.fire('connected');
      observable.fire('update', data);
    }).fail(function(err) {
      observable.fire('disconnected', err);
    });
  };

  this.color = function() {
    var verbs = {};
    for (var job in _jobs) {
      var v = _jobs[job].verb();
      if (!verbs[v]) { verbs[v] = 0; }
      verbs[v] += 1;
    }

    if (verbs['failed'] > 0) return 'red';
    if (verbs['started'] > 0) return 'anime';
    return 'green';
  };

  this.reset = function () {
    lastColor = null;
  }

  this.observable = observable;
};

var bonusRound = {
  cat: function(jobs) {
    var box = $('#box').hide();

    jobs.on('green', function() {
      imageShow("http://thecatapi.com/api/images/get.php?format=src&type=gif&t=" + new Date().getTime());
    }).on('anime', function() {
      imageHide();
    }).on('red', function() {
      imageHide();
    });
  },
  porkour: function(jobs) {
    var box = $('#box').hide();

    jobs.on('green', function() {
      imageShow("http://i.imgur.com/pIxorOD.gif")
    }).on('anime', function() {
      imageHide();
    }).on('red', function() {
      imageHide();
    });
  },
  green: function(jobs) {
    jobs.on('green', function() {
      $('body').css({background: 'green'});
    }).on('anime', function() {
      $('body').css({background: 'black'});
    }).on('red', function() {
      $('body').css({background: 'black'});
    });
  },
  guid: function(jobs) {
    jobs.on('green', function() {
      $('#box').show();
      $('#box').html("
" + Math.uuid() + "
");
    }).on('anime', function() {
      $('#box').hide();
    }).on('red', function() {
      $('#box').hide();
    });
  }
}

var audioList = {
  classic: function(jobs) {
    var play = function(path) {
      var _audio;
      return function() {
        if (_audio === void 0) {
          _audio = new Audio(path);
        }
        _audio.play();
      }
    }

    jobs.on('job_fixed', play('audioz/classic/fixed.mp3'))
        .on('job_failed', play('audioz/classic/failed.mp3'))
        .on('job_repeatedlyFailing', play('audioz/classic/repeatedlyFailing.mp3'));
  }
}

function imageShow(url) {
  $('body').css({
      "background-image": 'url("' + url + '")',
  });
}

function imageHide() {
  $('body').css({"background-image": ""});
}

var start = (function() {
  var vars = getUrlVars(),
      baseUrl = vars["server"],
      theme = vars["theme"],
      filters = (vars["filters"] || "").toLowerCase().split(','),
      scope = vars["scope"] || "contains",
      showInactive = vars["showInactive"],
      bonusName = vars["bonusRound"],
      audioName = vars['audio'];

  var nameMatcher = (scope == "contains")
    ? function (name, filter) { return name.indexOf(filter) !== -1; }
    : function (name, filter) { return name.indexOf(filter) === 0; };

  var ignore = function(name) {
    return filters.length > 0 && !filters.some(function (filter) { return nameMatcher(name.toLowerCase(), filter); })
  };

  var jobs = new Jobs('ul', baseUrl, ignore);

  if (theme == "neon") { $('body').addClass('neon'); }
  if (showInactive)  { $('body').addClass('show-inactive'); }

  if (bonusName != void 0 && bonusRound[bonusName] != void 0) {
    bonusRound[bonusName](jobs);
  }

  if (audioName != void 0 && audioList[audioName] != void 0) {
    audioList[audioName](jobs);
  }

  $(document).on('click', function() {
    jobs.reset();
    jobs.poll();
  });

  jobs.on('disconnected', function(err) {
    console.log("Error contacting the build server", err);
    imageShow("http://i.stack.imgur.com/jiFfM.jpg");
  }).on('connected', function() {
    imageHide();
  });

  window.setInterval(function() { jobs.poll(); }, 5000);
  jobs.poll();

  return jobs;
});

$(start);
<|endoftext|>