<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,
  continue: true*/

var libpath = require('path'),
    utils = require(libpath.join(__dirname, '../../management/utils')),
    Mojito = require(libpath.join(__dirname, '../../mojito')),
    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': {
                fullpath: libpath.join(__dirname, '../../app/autoload/mojito.common.js')
            },
            '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', '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(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(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 = Mojito.createServer(options);

    app.listen(null, null, 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>Fix remaining resource store and add-on references.<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,
  continue: true*/

var libpath = require('path'),
    utils = require(libpath.join(__dirname, '../../management/utils')),
    Mojito = require(libpath.join(__dirname, '../../mojito')),
    Store = require(libpath.join(__dirname, '../../store')),
    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 = {};

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

    store = Store.createStore({
        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(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(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 = Mojito.createServer(options);

    app.listen(null, null, 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>var React = require('react-native');
var deviceScreen = require('Dimensions').get('window');

var {
  StyleSheet,
} = React;

module.exports = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
  menu: {
    flex: 1,
    backgroundColor: 'transparent',
    position: 'absolute',
    top: 0,
    left: 0,
  },
  frontView: {
    flex: 1,
    position: 'absolute',
    left: 0,
    top: 0,
    backgroundColor: '#ffffff',
    width: deviceScreen.width,
    height: deviceScreen.height,
  }
});<commit_msg>Change background color to transparent<commit_after>var React = require('react-native');
var deviceScreen = require('Dimensions').get('window');

var {
  StyleSheet,
} = React;

module.exports = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
  menu: {
    flex: 1,
    backgroundColor: 'transparent',
    position: 'absolute',
    top: 0,
    left: 0,
  },
  frontView: {
    flex: 1,
    position: 'absolute',
    left: 0,
    top: 0,
    backgroundColor: 'transparent',
    width: deviceScreen.width,
    height: deviceScreen.height,
  }
});<|endoftext|>


<commit_before>/**
 * @author 田尘殇Sean(sean.snow@live.com)
 * @date 16/7/20
 */

export const Colors = {
  separator: '#ebebeb',
  underlay: '#f5f5f9',
  white: '#FFF',
  primary: '#337ab7',
  success: '#5cb85c',
  info: '#5bc0de',
  warning: '#f0ad4e',
  danger: '#d9534f'
};

export default {
  fullScreenAbsolute: {
    position: 'absolute',
    top: 0,
    bottom: 0,
    left: 0,
    right: 0
  },
  center: {
    justifyContent: 'center',
    alignItems: 'center'
  },
  flexRow: {
    flex: 1,
    flexDirection: 'row'
  },
  flexColumn: {
    flex: 1,
    flexDirection: 'column'
  }
};
<commit_msg>separator separatorHeight<commit_after>import { StyleSheet } from 'react-native';
/**
 * @author 田尘殇Sean(sean.snow@live.com)
 * @date 16/7/20
 */

export const Colors = {
  separator: '#bbbbbb',
  underlay: '#f5f5f9',
  white: '#FFF',
  primary: '#337ab7',
  success: '#5cb85c',
  info: '#5bc0de',
  warning: '#f0ad4e',
  danger: '#d9534f'
};

// noinspection JSSuspiciousNameCombination
export const separatorHeight = StyleSheet.hairlineWidth;

export default {
  fullScreenAbsolute: {
    position: 'absolute',
    top: 0,
    bottom: 0,
    left: 0,
    right: 0
  },
  center: {
    justifyContent: 'center',
    alignItems: 'center'
  },
  flexRow: {
    flex: 1,
    flexDirection: 'row'
  },
  flexColumn: {
    flex: 1,
    flexDirection: 'column'
  }
};
<|endoftext|>


<commit_before>module.exports = {
    exec: async function (msg, args) {
        async function makeCfg() {
            await db.table("configs").insert({
                id: msg.guild.id,
                modRole: "tt.bot mod",
                prefix: config.prefix
            });
            return await db.table("configs").get(msg.guild.id).run();
        }
        if (args) {
            let c = args.split(" ");
            let setting = c[0];
            let value = c.slice(1).join(" ");
            let server = await db.table("configs").get(msg.guild.id).run();
            if (!server) server = await makeCfg();
            if (setting && value && server[setting]) {
                server[setting] = value;
                await db.table("configs").get(msg.guild.id).update(server).run();
                return await msg.channel.createMessage(`Updated ${setting} to ${value}`);
            } else {
                return await msg.channel.createMessage(`Unknown setting ${setting}`);
            }
        }
        else {
            let server = await db.table("configs").get(msg.guild.id).run();
            if (!server) server = await makeCfg();
            let items = [];
            Object.keys(server).forEach(item => {
                if (item != "id") items.push(`${item} - ${server[item]}`);
            });
            return await bot.createMessage(msg.channel.id, `\`\`\`\nServer configuration for ${msg.guild.name}\n${items.join("\n")}\`\`\`\nEven though the config names are selfexplanatory, it is possible that your settings might bork the configuration.\n`);
        }
    },
    isCmd: true,
    name: "config",
    display: true,
    category: 4,
    description: "This lets you configure your server.",
    args: "[<item> <value>]"
};<commit_msg>AAAAAA forgot one string there<commit_after>module.exports = {
    exec: async function (msg, args) {
        async function makeCfg() {
            await db.table("configs").insert({
                id: msg.guild.id,
                modRole: "tt.bot mod",
                prefix: config.prefix
            });
            return await db.table("configs").get(msg.guild.id).run();
        }
        if (args) {
            let c = args.split(" ");
            let setting = c[0];
            let value = c.slice(1).join(" ");
            let server = await db.table("configs").get(msg.guild.id).run();
            if (!server) server = await makeCfg();
            if (setting && value && server[setting]) {
                server[setting] = value;
                await db.table("configs").get(msg.guild.id).update(server).run();
                return await msg.channel.createMessage(`Updated ${setting} to ${value}`);
            } else {
                return await msg.channel.createMessage(`Unknown setting ${setting}`);
            }
        }
        else {
            let server = await db.table("configs").get(msg.guild.id).run();
            if (!server) server = await makeCfg();
            let items = [];
            Object.keys(server).forEach(item => {
                if (item != "id") items.push(`${item} - ${server[item]}`);
            });
            return await bot.createMessage(msg.channel.id, `\`\`\`\nServer configuration for ${msg.guild.name}\n${items.join("\n")}\`\`\`\nEven though the config names are selfexplanatory, it is possible that your settings might bork the configuration.\nIf you want to use the web version instead, go to ${config.webserverDisplayUrl("/")}`);
        }
    },
    isCmd: true,
    name: "config",
    display: true,
    category: 4,
    description: "This lets you configure your server.",
    args: "[<item> <value>]"
};<|endoftext|>


<commit_before>const Command = require('../base/Command');

class Guilds extends Command {
    constructor(client) {
        super(client, {
            name: 'guilds',
            category: "SWGoH",
            aliases: ['guild'],
            permissions: ['EMBED_LINKS'],
            flags: {
                'min': {
                    aliases: ['minimal', 'minimize', 'm']
                }
            }
        });
    }

    async run(client, message, [userID, ...args], options) { // eslint-disable-line no-unused-vars
        // Basic, with no args, shows the top ## guilds (Based on how many have registered)
        // <allyCode | mention | guildName >

        // Shows your guild's total GP, average GP, and a list of your members
        // Not trying to get any specific guild, show em the top ones
        if (!userID) {
            message.channel.send('I cannot currently list the top guilds, that should be coming soon**™**.\nPlease specify an Ally Code, discord ID, or guild name.');
            // const guilds = [];
            // await connection.query('CALL getAllGuilds();', function(err, results) {
            //     results[0].forEach((row, ix) => {
            //         if (ix < 20) {
            //             guilds.push(`\`[${row.count > 9 ? row.count : '0' + row.count}] ${' '.repeat(10 - row.gp.toString().length) + row.gp.toLocaleString()} GP\` - **${row.guildName}**`);
            //         }
            //     });
            //
            //     const desc = guilds.join('\n');
            //     message.channel.send({embed: {
            //         author: {
            //             name: `Top ${Object.keys(guilds).length}/${results[0].length} Guilds`
            //         },
            //         description: desc,
            //         fields: [
            //             {
            //                 name: message.language.get('COMMAND_GUILDS_MORE_INFO'),
            //                 value: '```;guilds <mention|allyCode|guildName>```'
            //             }
            //         ]
            //     }});
            // });
        } else {    // Else they want a specific guild
            let acType = true;

            // Get the user's ally code from the message or psql db
            if (userID === "me" || client.isUserID(userID) || client.isAllyCode(userID)) {
                userID = await client.getAllyCode(message, userID);
                if (!userID.length) {
                    return message.channel.send('I cannot find a guild for that user.');
                }
                userID = userID[0];
            } else {
                // Or, if they don't have one of those, try getting the guild by name
                userID += args.length ? ' ' + args.join(' ') : '';
                acType = false;
            }

            if (acType) {
                try {
                    const player = await client.swgohAPI.getPlayer(userID, 'ENG_US', 6);
                    userID = player.guildName;
                } catch (e) {
                    console.error(e);
                }
            }

            let guild = null;
            try {
                guild = await client.swgohAPI.report('getGuildRoster', {guildName: userID});
            } catch (e) {
                console.log('ERROR: ' + e);
            }

            if (!guild || !guild.length) {
                return message.channel.send('I cannot find any users for that guild. \nPlease make sure you have spelled the name correctly, and that the capitalization is correct.');
            }
            const sortedGuild = guild.sort((p, c) => p.gpFull > c.gpFull ? 1 : -1);

            let totalGP = 0;
            const users = [];
            sortedGuild.forEach(p => {
                totalGP += parseInt(p.gpFull);
                users.push(`\`[${' '.repeat(9 - p.gpFull.toLocaleString().length) + p.gpFull.toLocaleString()} GP]\` - **${p.name}**`);
            });
            const averageGP = Math.floor(totalGP/users.length);
            message.channel.send({embed: {
                author: {
                    name: `${users.length} Players in ${userID}`
                },
                description: options.flags.min ? '' : users.join('\n'),
                fields: [
                    {
                        name: 'Registered Guild GP',
                        value: '```Total GP: ' + totalGP.toLocaleString() + '\nAverage : ' + averageGP.toLocaleString() + '```'
                    }
                ]
            }});
        }
    }
}

module.exports = Guilds;

<commit_msg>Order by Highest GP first.<commit_after>const Command = require('../base/Command');

class Guilds extends Command {
    constructor(client) {
        super(client, {
            name: 'guilds',
            category: "SWGoH",
            aliases: ['guild'],
            permissions: ['EMBED_LINKS'],
            flags: {
                'min': {
                    aliases: ['minimal', 'minimize', 'm']
                }
            }
        });
    }

    async run(client, message, [userID, ...args], options) { // eslint-disable-line no-unused-vars
        // Basic, with no args, shows the top ## guilds (Based on how many have registered)
        // <allyCode | mention | guildName >

        // Shows your guild's total GP, average GP, and a list of your members
        // Not trying to get any specific guild, show em the top ones
        if (!userID) {
            message.channel.send('I cannot currently list the top guilds, that should be coming soon**™**.\nPlease specify an Ally Code, discord ID, or guild name.');
            // const guilds = [];
            // await connection.query('CALL getAllGuilds();', function(err, results) {
            //     results[0].forEach((row, ix) => {
            //         if (ix < 20) {
            //             guilds.push(`\`[${row.count > 9 ? row.count : '0' + row.count}] ${' '.repeat(10 - row.gp.toString().length) + row.gp.toLocaleString()} GP\` - **${row.guildName}**`);
            //         }
            //     });
            //
            //     const desc = guilds.join('\n');
            //     message.channel.send({embed: {
            //         author: {
            //             name: `Top ${Object.keys(guilds).length}/${results[0].length} Guilds`
            //         },
            //         description: desc,
            //         fields: [
            //             {
            //                 name: message.language.get('COMMAND_GUILDS_MORE_INFO'),
            //                 value: '```;guilds <mention|allyCode|guildName>```'
            //             }
            //         ]
            //     }});
            // });
        } else {    // Else they want a specific guild
            let acType = true;

            // Get the user's ally code from the message or psql db
            if (userID === "me" || client.isUserID(userID) || client.isAllyCode(userID)) {
                userID = await client.getAllyCode(message, userID);
                if (!userID.length) {
                    return message.channel.send('I cannot find a guild for that user.');
                }
                userID = userID[0];
            } else {
                // Or, if they don't have one of those, try getting the guild by name
                userID += args.length ? ' ' + args.join(' ') : '';
                acType = false;
            }

            if (acType) {
                try {
                    const player = await client.swgohAPI.getPlayer(userID, 'ENG_US', 6);
                    userID = player.guildName;
                } catch (e) {
                    console.error(e);
                }
            }

            let guild = null;
            try {
                guild = await client.swgohAPI.report('getGuildRoster', {guildName: userID});
            } catch (e) {
                console.log('ERROR: ' + e);
            }

            if (!guild || !guild.length) {
                return message.channel.send('I cannot find any users for that guild. \nPlease make sure you have spelled the name correctly, and that the capitalization is correct.');
            }
            const sortedGuild = guild.sort((p, c) => c.gpFull - p.gpFull);

            let totalGP = 0;
            const users = [];
            sortedGuild.forEach(p => {
                totalGP += parseInt(p.gpFull);
                users.push(`\`[${' '.repeat(9 - p.gpFull.toLocaleString().length) + p.gpFull.toLocaleString()} GP]\` - **${p.name}**`);
            });
            const averageGP = Math.floor(totalGP/users.length);
            message.channel.send({embed: {
                author: {
                    name: `${users.length} Players in ${userID}`
                },
                description: options.flags.min ? '' : users.join('\n'),
                fields: [
                    {
                        name: 'Registered Guild GP',
                        value: '```Total GP: ' + totalGP.toLocaleString() + '\nAverage : ' + averageGP.toLocaleString() + '```'
                    }
                ]
            }});
        }
    }
}

module.exports = Guilds;

<|endoftext|>


<commit_before>if( !AutomaticDictionary ) AutomaticDictionary = {
    Lib:{}
};
/*
 *  Class to send visits to Google Analytics
 *
 * Builder expects the config:
 *      code: ga urchin code UA-XXXXXX
 *      storage: a object that accepts set(key,value) and get(key) => value
 *          Values stored here are expeted to be persistent.
 *      domain: the domain expected to be the visits.
 *
 **/
//TODO: extract this code as a standalone code.
AutomaticDictionary.Lib.GoogleAnalytics = (function(config){

    var domain = config.domain,
        code = config.code,
        storage = config.storage,
        target = config.url || "https://ssl.google-analytics.com/__utm.gif",
        domain_hash,
        visitor_id,
        first_visit,
        last_session,
        current_session,
        session_number;

    // Generate an int based on the string. A simple hash.
    function hash( string ){
        var out=1;
        for(var i =0; i < string.length; i++){
            out += string.charCodeAt(i) * (10^i);
        }
        return out;
    }

    function rand(min, max) {
        return min + Math.floor(Math.random() * (max - min));
    }

    //Init
    domain_hash = hash(domain);

    //Inc session number on each init.
    session_number = 1 + ( parseInt(storage.get("session_number")) || 0);
    storage.set("session_number", session_number);

    visitor_id = storage.get("visitor_id") || rand(10000000,99999999);
    storage.set("visitor_id", visitor_id)

    first_visit = storage.get("first_visit") || (new Date()).getTime();
    storage.set("first_visit", first_visit);

    current_session = (new Date()).getTime();
    last_session = storage.get("last_session") || current_session;
    storage.set("last_session", current_session);

    function doRequest(visit_url,params,options){
        options = options || {};
        var img = new Image(),
            defaults, i,
            queryString ="",
            win = options.window || window.location,
            cookie = options.cookie || visitor_id;

        defaults={
            utmn: rand(1000000000,9999999999), //random request number
            cookie:visitor_id,
            today:current_session,
            win:win,
            utmwv:"5.1.7",
            utmsr:"-",
            utmsc:"-",
            utmul: window.navigator.language,
            utmje:0,
            utmfl:"-",
            utmdt:"-",
            utmhn:domain,
            utmr:win,
            utmp:visit_url,
            utmac:code,
            utmcc:'__utma='
                +domain_hash+'.'
                +visitor_id+'.'
                +first_visit+'.'
                +last_session+'.'
                +current_session+'.'
                +session_number+';+__utmb='
                +cookie+';+__utmc='
                +cookie+';+__utmz='
                +cookie+'.'+current_session
                +'.2.2.utmccn=(referral)|utmcsr=' + win.host + '|utmcct='
                + win.pathname + '|utmcmd=referral;+__utmv='
            +cookie+'.-;'
            };

        //Proces options.customVars
        if( options && options.customVars ){
            //We supose basic settings like that this settigs are visitor
            //settings and not from this action.
            var eight=[], nine = [];

            for(i = 0; i < options.customVars.length; i++ ){
                eight.push(options.customVars[i].name);
                nine.push(options.customVars[i].value);
            }

            params["utme"] = (params["utme"]||"") +
                "8("+eight.join("*")+")"+
                "9("+nine.join("*")+")"+
                "11(1)";
        }

        //Set default values
        for(i in defaults){
            if((typeof params[i]) == "undefined"){
                params[i] = defaults[i];
            }
        }

        for(i in params){
            //FIXME: escape params value
            queryString+= i+"="+encodeURIComponent(params[i])+"&";
        }

        img.src = target + queryString;
    }
    //options.customVars can be an array as order matters
    function visit(url, options){
        doRequest(url,{},options);
    }

    /*
     * @event_data is a hash with:
     *      "cat": string category like "Image"
     *      "action": string action like "click"
     *      "label": (optional) String labels the action. Recommend using something to
     *          describe the location or situation where event ocurred.
     *      "value": (optional) integer when the action has a numeric "impact" or "meaning"
     *      "non_interaction": (optional) boolean meaning that this is not an interaction
     *          and so the visit could still be considered a bounce.
     *
     **/
    function event(url,event_data,options){
        var glue = "*",
            val = event_data.cat + glue + event_data.action,
            params = {
                utmt:"event"
            };

        if(event_data.label){
            val += glue + event_data.label;
        }
        params["utme"]="5("+val+")";

        if(event_data.value){
            params["utme"] +="("+event_data.value+")";
        }

        if(event_data.non_interaction){
            params["utmni"]="1";
        }

        doRequest(url,params, options);
    }

    return {
        visit:visit,
        event:event
    };
});<commit_msg>Fix GA image url generation<commit_after>if( !AutomaticDictionary ) AutomaticDictionary = {
    Lib:{}
};
/*
 *  Class to send visits to Google Analytics
 *
 * Builder expects the config:
 *      code: ga urchin code UA-XXXXXX
 *      storage: a object that accepts set(key,value) and get(key) => value
 *          Values stored here are expeted to be persistent.
 *      domain: the domain expected to be the visits.
 *
 **/
//TODO: extract this code as a standalone code.
AutomaticDictionary.Lib.GoogleAnalytics = (function(config){

    var domain = config.domain,
        code = config.code,
        storage = config.storage,
        target = config.url || "https://ssl.google-analytics.com/__utm.gif",
        domain_hash,
        visitor_id,
        first_visit,
        last_session,
        current_session,
        session_number;

    // Generate an int based on the string. A simple hash.
    function hash( string ){
        var out=1;
        for(var i =0; i < string.length; i++){
            out += string.charCodeAt(i) * (10^i);
        }
        return out;
    }

    function rand(min, max) {
        return min + Math.floor(Math.random() * (max - min));
    }

    //Init
    domain_hash = hash(domain);

    //Inc session number on each init.
    session_number = 1 + ( parseInt(storage.get("session_number")) || 0);
    storage.set("session_number", session_number);

    visitor_id = storage.get("visitor_id") || rand(10000000,99999999);
    storage.set("visitor_id", visitor_id)

    first_visit = storage.get("first_visit") || (new Date()).getTime();
    storage.set("first_visit", first_visit);

    current_session = (new Date()).getTime();
    last_session = storage.get("last_session") || current_session;
    storage.set("last_session", current_session);

    function doRequest(visit_url,params,options){
        options = options || {};
        var img = new Image(),
            defaults, i,
            queryString ="",
            win = options.window || window.location,
            cookie = options.cookie || visitor_id;

        defaults={
            utmn: rand(1000000000,9999999999), //random request number
            cookie:visitor_id,
            today:current_session,
            win:win,
            utmwv:"5.1.7",
            utmsr:"-",
            utmsc:"-",
            utmul: window.navigator.language,
            utmje:0,
            utmfl:"-",
            utmdt:"-",
            utmhn:domain,
            utmr:win,
            utmp:visit_url,
            utmac:code,
            utmcc:'__utma='
                +domain_hash+'.'
                +visitor_id+'.'
                +first_visit+'.'
                +last_session+'.'
                +current_session+'.'
                +session_number+';+__utmb='
                +cookie+';+__utmc='
                +cookie+';+__utmz='
                +cookie+'.'+current_session
                +'.2.2.utmccn=(referral)|utmcsr=' + win.host + '|utmcct='
                + win.pathname + '|utmcmd=referral;+__utmv='
            +cookie+'.-;'
            };

        //Proces options.customVars
        if( options && options.customVars ){
            //We supose basic settings like that this settigs are visitor
            //settings and not from this action.
            var eight=[], nine = [];

            for(i = 0; i < options.customVars.length; i++ ){
                eight.push(options.customVars[i].name);
                nine.push(options.customVars[i].value);
            }

            params["utme"] = (params["utme"]||"") +
                "8("+eight.join("*")+")"+
                "9("+nine.join("*")+")"+
                "11(1)";
        }

        //Set default values
        for(i in defaults){
            if((typeof params[i]) == "undefined"){
                params[i] = defaults[i];
            }
        }

        for(i in params){
            //FIXME: escape params value
            queryString+= i+"="+encodeURIComponent(params[i])+"&";
        }
        AutomaticDictionary.dump("GA URL is "+target+"?"+queryString);
        img.src = target +"?"+ queryString;
    }
    //options.customVars can be an array as order matters
    function visit(url, options){
        doRequest(url,{},options);
    }

    /*
     * @event_data is a hash with:
     *      "cat": string category like "Image"
     *      "action": string action like "click"
     *      "label": (optional) String labels the action. Recommend using something to
     *          describe the location or situation where event ocurred.
     *      "value": (optional) integer when the action has a numeric "impact" or "meaning"
     *      "non_interaction": (optional) boolean meaning that this is not an interaction
     *          and so the visit could still be considered a bounce.
     *
     **/
    function event(url,event_data,options){
        var glue = "*",
            val = event_data.cat + glue + event_data.action,
            params = {
                utmt:"event"
            };

        if(event_data.label){
            val += glue + event_data.label;
        }
        params["utme"]="5("+val+")";

        if(event_data.value){
            params["utme"] +="("+event_data.value+")";
        }

        if(event_data.non_interaction){
            params["utmni"]="1";
        }

        doRequest(url,params, options);
    }

    return {
        visit:visit,
        event:event
    };
});<|endoftext|>


<commit_before>/*******************************************************************************
Open Source Initiative OSI - The MIT License (MIT):Licensing
[OSI Approved License]
The MIT License (MIT)

Copyright (c) Sean McGregor

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.

*******************************************************************************/

var privly = {

  //Matches:
  //              http://
  //              https://
  //                        priv.ly/textAndNumbers/any/number/of/times
  //
  //also matches localhost:3000
  privlyReferencesRegex: /\b(https?:\/\/){0,1}(priv\.ly|localhost:3000)(\/\w*){2,}\b/gi,

  // Takes a domain with an optional http(s) in front and returns a fully formed domain name
  makeHref: function(domain)
  {
    var hasHTTPRegex = /^((https?)\:\/\/)/i
    if(!hasHTTPRegex.test(domain))
        domain = "http://" + domain;
    return domain;
  },

  //Make plain text links into anchor elements
  createLinks: function()
  {
      /*************************************************************************
      Inspired by Linkify script:
        http://downloads.mozdev.org/greasemonkey/linkify.user.js

      Originally written by Anthony Lieuallen of http://arantius.com/
      Licensed for unlimited modification and redistribution as long as
      this notice is kept intact.
      **************************************************************************/

      var excludeParents = ["a", "applet", "button", "code", "form",
                             "input", "option", "script", "select", "meta",
                             "style", "textarea", "title", "div","span"];
      var excludedParentsString = excludeParents.join(" or parent::");
      var xpathExpression = ".//text()[not(parent:: " + excludedParentsString +")]";

      textNodes = document.evaluate(xpathExpression, document.body, null,
                                    XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);

      for(var i=0; i < textNodes.snapshotLength; i++){
          item = textNodes.snapshotItem(i);

          var itemText = item.nodeValue;

          privly.privlyReferencesRegex.lastIndex = 0;
          if(privly.privlyReferencesRegex.test(itemText)){
              var span = document.createElement("span");
              var lastLastIndex = 0;
              privly.privlyReferencesRegex.lastIndex = 0;
              for(var results = null; results = privly.privlyReferencesRegex.exec(itemText); ){
                  var href = results[0];
                  span.appendChild(document.createTextNode(itemText.substring(lastLastIndex, results.index)));

                  var text = (href.indexOf(" ")==0)?href.substring(1):href;

                  var href = privly.makeHref(text);

                  var a = document.createElement("a");
                  a.setAttribute("href", href);
                  a.appendChild(document.createTextNode(text.substring(0,4).toLowerCase()+text.substring(4)));
                  if(href.indexOf(" ")==0)
                      span.appendChild(document.createTextNode(" "));
                  span.appendChild(a);
                  lastLastIndex = privly.privlyReferencesRegex.lastIndex;
              }
              span.appendChild(document.createTextNode(itemText.substring(lastLastIndex)));
              item.parentNode.replaceChild(span, item);
          }
      }
  },

  //Checks link attributes and text for privly links without the proper href attribute.
  //Twitter and other hosts change links so they can collect click events.
  correctIndirection: function()
  {
    var anchors = document.links;
    var i = anchors.length;
    while (i--){
      var a = anchors[i];

      if(a.href && (a.href.indexOf("priv.ly/posts/") == -1 || a.href.indexOf("priv.ly/posts/") > 9))
      {
        if (privly.privlyReferencesRegex.test(a.innerHTML)) {
          // If the href is not present or is on a different domain
          privly.privlyReferencesRegex.lastIndex = 0;
          var results = privly.privlyReferencesRegex.exec(a.innerHTML);
          var newHref = privly.makeHref(results[0]);
          a.setAttribute("href", newHref);
          //Preventing the default link behavior
          a.addEventListener("mousedown", function(e){
              e.cancelBubble = true;
              e.stopPropagation();
              e.preventDefault();
              linkClicked(a);
            }, true);
        }
      }
      else if(a.href)
      {
        //Preventing the default link behavior
        a.addEventListener("mousedown", function(e){
            e.cancelBubble = true;
            e.stopPropagation();
            e.preventDefault();
            replaceLink(a);
          },
          true);
      }
    }
  },

  nextAvailableFrameID: 0,

  // Replace an anchor element with its referenced content.
  replaceLink: function(object)
  {
    var iFrame = document.createElement('iframe');
    iFrame.setAttribute("frameborder","0");
    iFrame.setAttribute("vspace","0");
    iFrame.setAttribute("hspace","0");
    iFrame.setAttribute("name","privlyiframe");
    iFrame.setAttribute("width","100%");
    iFrame.setAttribute("marginwidth","0");
    iFrame.setAttribute("marginheight","0");
    iFrame.setAttribute("height","1px");
    iFrame.setAttribute("src",object.href + ".iframe?frame_id=" + privly.nextAvailableFrameID);
    iFrame.setAttribute("id","ifrm"+privly.nextAvailableFrameID);
    iFrame.setAttribute("frameborder","0");
    privly.nextAvailableFrameID++;
    iFrame.setAttribute("style","width: 100%; height: 32px; overflow: hidden;");
    iFrame.setAttribute("scrolling","no");
    iFrame.setAttribute("overflow","hidden");

    object.parentNode.replaceChild(iFrame, object);
  },

  //Replace all Privly links with their iframe
  replaceLinks: function(){
    var anchors = document.links;
    var i = anchors.length;
    while (i--){
      var a = anchors[i];
      privly.privlyReferencesRegex.lastIndex = 0;
      if(a.href && privly.privlyReferencesRegex.test(a.href))
      {
        var exclude = a.getAttribute("privly");
        if(exclude != "exclude")
        {
          privly.replaceLink(a);
        }
      }
    }
  },

  //do nothing. Actual implementation is in extension-host-interface.js
  resizeIframe: function(evt){},

  //prevents DOMNodeInserted from sending hundreds of extension runs
  runPending: false,

  //prep the page and replace the links if it is in active mode
  run: function(){

    //create and correct the links pointing
    //to Privly content
    privly.createLinks();
    privly.correctIndirection();

    //replace all available links on load, if in active mode
    if(privly.active)
      privly.replaceLinks();
  },

  //runs privly once then registers the update listener
  //for dynamic pages
  listeners: function(){

    //don't recursively replace links
    if(document.URL.indexOf('priv.ly') != -1 || document.URL.indexOf('localhost:3000') != -1)
      return;

    privly.runPending=true;
      setTimeout(
        function(){
          privly.runPending=false;
          privly.run();
        },
        100);

    //Everytime the page is updated via javascript, we have to check
    //for new Privly content. This might not be supported on other platforms
    document.addEventListener("DOMNodeInserted", function(event) {

      //we check the page a maximum of two times a second
      if(privly.runPending )
        return;
      privly.runPending=true;

      setTimeout(
        function(){
          privly.runPending=false;
          privly.run();
        },
        500);
    });

    //The content's iframe will fire a resize event when it has loaded, resizeIframe
    //sets the height of the iframe to the height of the content contained within.
    window.addEventListener("IframeResizeEvent", function(e) { privly.resizeIframe(e); }, false, true);
  },

  //indicates whether the extension shoud immediatly replace all Privly
  //links it encounters
  active: true,

  // cross platform onload event
  // won't attach anything on IE
  // on macintosh systems.
  addEvent: function(obj, evType, fn){
   if (obj.addEventListener){
     obj.addEventListener(evType, fn, false);
     return true;
   } else if (obj.attachEvent){
     var r = obj.attachEvent("on"+evType, fn);
     return r;
   } else {
     return false;
   }
  }
};

privly.addEvent(window, 'load', privly.listeners);
<commit_msg>narrowed regexp to only match the posts controller<commit_after>/*******************************************************************************
Open Source Initiative OSI - The MIT License (MIT):Licensing
[OSI Approved License]
The MIT License (MIT)

Copyright (c) Sean McGregor

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.

*******************************************************************************/

var privly = {

  //Matches:
  //              http://
  //              https://
  //                        priv.ly/textAndNumbers/any/number/of/times
  //
  //also matches localhost:3000
  privlyReferencesRegex: /\b(https?:\/\/){0,1}(priv\.ly|localhost:3000)(\/posts)(\/\w*){1,}\b/gi,

  // Takes a domain with an optional http(s) in front and returns a fully formed domain name
  makeHref: function(domain)
  {
    var hasHTTPRegex = /^((https?)\:\/\/)/i
    if(!hasHTTPRegex.test(domain))
        domain = "http://" + domain;
    return domain;
  },

  //Make plain text links into anchor elements
  createLinks: function()
  {
      /*************************************************************************
      Inspired by Linkify script:
        http://downloads.mozdev.org/greasemonkey/linkify.user.js

      Originally written by Anthony Lieuallen of http://arantius.com/
      Licensed for unlimited modification and redistribution as long as
      this notice is kept intact.
      **************************************************************************/

      var excludeParents = ["a", "applet", "button", "code", "form",
                             "input", "option", "script", "select", "meta",
                             "style", "textarea", "title", "div","span"];
      var excludedParentsString = excludeParents.join(" or parent::");
      var xpathExpression = ".//text()[not(parent:: " + excludedParentsString +")]";

      textNodes = document.evaluate(xpathExpression, document.body, null,
                                    XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);

      for(var i=0; i < textNodes.snapshotLength; i++){
          item = textNodes.snapshotItem(i);

          var itemText = item.nodeValue;

          privly.privlyReferencesRegex.lastIndex = 0;
          if(privly.privlyReferencesRegex.test(itemText)){
              var span = document.createElement("span");
              var lastLastIndex = 0;
              privly.privlyReferencesRegex.lastIndex = 0;
              for(var results = null; results = privly.privlyReferencesRegex.exec(itemText); ){
                  var href = results[0];
                  span.appendChild(document.createTextNode(itemText.substring(lastLastIndex, results.index)));

                  var text = (href.indexOf(" ")==0)?href.substring(1):href;

                  var href = privly.makeHref(text);

                  var a = document.createElement("a");
                  a.setAttribute("href", href);
                  a.appendChild(document.createTextNode(text.substring(0,4).toLowerCase()+text.substring(4)));
                  if(href.indexOf(" ")==0)
                      span.appendChild(document.createTextNode(" "));
                  span.appendChild(a);
                  lastLastIndex = privly.privlyReferencesRegex.lastIndex;
              }
              span.appendChild(document.createTextNode(itemText.substring(lastLastIndex)));
              item.parentNode.replaceChild(span, item);
          }
      }
  },

  //Checks link attributes and text for privly links without the proper href attribute.
  //Twitter and other hosts change links so they can collect click events.
  correctIndirection: function()
  {
    var anchors = document.links;
    var i = anchors.length;
    while (i--){
      var a = anchors[i];

      if(a.href && (a.href.indexOf("priv.ly/posts/") == -1 || a.href.indexOf("priv.ly/posts/") > 9))
      {
        if (privly.privlyReferencesRegex.test(a.innerHTML)) {
          // If the href is not present or is on a different domain
          privly.privlyReferencesRegex.lastIndex = 0;
          var results = privly.privlyReferencesRegex.exec(a.innerHTML);
          var newHref = privly.makeHref(results[0]);
          a.setAttribute("href", newHref);
          //Preventing the default link behavior
          a.addEventListener("mousedown", function(e){
              e.cancelBubble = true;
              e.stopPropagation();
              e.preventDefault();
              linkClicked(a);
            }, true);
        }
      }
      else if(a.href)
      {
        //Preventing the default link behavior
        a.addEventListener("mousedown", function(e){
            e.cancelBubble = true;
            e.stopPropagation();
            e.preventDefault();
            replaceLink(a);
          },
          true);
      }
    }
  },

  nextAvailableFrameID: 0,

  // Replace an anchor element with its referenced content.
  replaceLink: function(object)
  {
    var iFrame = document.createElement('iframe');
    iFrame.setAttribute("frameborder","0");
    iFrame.setAttribute("vspace","0");
    iFrame.setAttribute("hspace","0");
    iFrame.setAttribute("name","privlyiframe");
    iFrame.setAttribute("width","100%");
    iFrame.setAttribute("marginwidth","0");
    iFrame.setAttribute("marginheight","0");
    iFrame.setAttribute("height","1px");
    iFrame.setAttribute("src",object.href + ".iframe?frame_id=" + privly.nextAvailableFrameID);
    iFrame.setAttribute("id","ifrm"+privly.nextAvailableFrameID);
    iFrame.setAttribute("frameborder","0");
    privly.nextAvailableFrameID++;
    iFrame.setAttribute("style","width: 100%; height: 32px; overflow: hidden;");
    iFrame.setAttribute("scrolling","no");
    iFrame.setAttribute("overflow","hidden");

    object.parentNode.replaceChild(iFrame, object);
  },

  //Replace all Privly links with their iframe
  replaceLinks: function(){
    var anchors = document.links;
    var i = anchors.length;
    while (i--){
      var a = anchors[i];
      privly.privlyReferencesRegex.lastIndex = 0;
      if(a.href && privly.privlyReferencesRegex.test(a.href))
      {
        var exclude = a.getAttribute("privly");
        if(exclude != "exclude")
        {
          privly.replaceLink(a);
        }
      }
    }
  },

  //do nothing. Actual implementation is in extension-host-interface.js
  resizeIframe: function(evt){},

  //prevents DOMNodeInserted from sending hundreds of extension runs
  runPending: false,

  //prep the page and replace the links if it is in active mode
  run: function(){

    //create and correct the links pointing
    //to Privly content
    privly.createLinks();
    privly.correctIndirection();

    //replace all available links on load, if in active mode
    if(privly.active)
      privly.replaceLinks();
  },

  //runs privly once then registers the update listener
  //for dynamic pages
  listeners: function(){

    //don't recursively replace links
    if(document.URL.indexOf('priv.ly') != -1 || document.URL.indexOf('localhost:3000') != -1)
      return;

    privly.runPending=true;
      setTimeout(
        function(){
          privly.runPending=false;
          privly.run();
        },
        100);

    //Everytime the page is updated via javascript, we have to check
    //for new Privly content. This might not be supported on other platforms
    document.addEventListener("DOMNodeInserted", function(event) {

      //we check the page a maximum of two times a second
      if(privly.runPending )
        return;
      privly.runPending=true;

      setTimeout(
        function(){
          privly.runPending=false;
          privly.run();
        },
        500);
    });

    //The content's iframe will fire a resize event when it has loaded, resizeIframe
    //sets the height of the iframe to the height of the content contained within.
    window.addEventListener("IframeResizeEvent", function(e) { privly.resizeIframe(e); }, false, true);
  },

  //indicates whether the extension shoud immediatly replace all Privly
  //links it encounters
  active: true,

  // cross platform onload event
  // won't attach anything on IE
  // on macintosh systems.
  addEvent: function(obj, evType, fn){
   if (obj.addEventListener){
     obj.addEventListener(evType, fn, false);
     return true;
   } else if (obj.attachEvent){
     var r = obj.attachEvent("on"+evType, fn);
     return r;
   } else {
     return false;
   }
  }
};

privly.addEvent(window, 'load', privly.listeners);
<|endoftext|>


<commit_before>exports.names = ['.reward'];
exports.hidden = false;
exports.enabled = true;
exports.matchStart = true;
var tacos = ["a blunt :snoop:", "a leather mask :forsenddk:", "a trimmed mithril armor"];
var cookies = ["a chocolate chip cookie", "a sugar cookie", "an oatmeal raisin cookie", "a 'special' brownie", "an animal cracker", "a scooby snack", "a blueberry muffin", "a cupcake", "Strawberry Sunday", "Chocolate Chip Icecream Cone", "Cookie Dough Triple Scoop ", "Mint Chocolate Chip Icecream Cone", "Chocolate Icecream Sunday", "Banana Split with Whipped Cream", "Vanilla Icecream Cone with Sprinkles ", "Bubblegum Flavored Popcicle", "en bröllopstårta", "kladdkaka"];
exports.cd_all = 15;
exports.cd_user = 30;
exports.cd_manager = 10;
exports.handler = function (data) {
    if (data.from.role > 2 || data.from.username == 'PAJLADA' || data.from.username == 'Jeanny') {
        var params = _.rest(data.message.split(' '), 1);
        var username = '';
        if (params.length < 1) {
            var users = bot.getUsers();
            var randomUserIndex = _.random(1, users.length);
            username = '@' + users[(randomUserIndex - 1)].username;
        } else {
            console.log(params.join(' '));
            username_uf = params.join(' ').trim();
            username = username_uf.replace('@', '');
            console.log(username);
            var user = _.findWhere(bot.getUsers(), {username: username});
            if (user) {
                username = '@' + user.username;
            } else {
                bot.sendChat(username + ' is not here :biblethump:');
                return;
            }
        }

        var random_sentence = _.random(0, 10);
        var random_cookie = _.random(0, cookies.length - 1);
        var random_taco = _.random(0, tacos.length - 1);
        if (random_sentence <= 9) {
            bot.sendChat(username + ', ' + data.from.username + ' has rewarded you with ' + cookies[random_cookie] + '. Enjoy! :minik:');
        } else {
            bot.sendChat(username + ', ' + data.from.username + ' has rewarded you with ' + tacos[random_taco] + '. Enjoy! :minik:');
        }
    }
};
<commit_msg>.reward can now be used by bouncers+<commit_after>exports.names = ['.reward'];
exports.hidden = false;
exports.enabled = true;
exports.matchStart = true;
var tacos = ["a blunt :snoop:", "a leather mask :forsenddk:", "a trimmed mithril armor"];
var cookies = ["a chocolate chip cookie", "a sugar cookie", "an oatmeal raisin cookie", "a 'special' brownie", "an animal cracker", "a scooby snack", "a blueberry muffin", "a cupcake", "Strawberry Sunday", "Chocolate Chip Icecream Cone", "Cookie Dough Triple Scoop ", "Mint Chocolate Chip Icecream Cone", "Chocolate Icecream Sunday", "Banana Split with Whipped Cream", "Vanilla Icecream Cone with Sprinkles ", "Bubblegum Flavored Popcicle", "en bröllopstårta", "kladdkaka"];
exports.cd_all = 15;
exports.cd_user = 30;
exports.cd_manager = 10;
exports.handler = function (data) {
    if (data.from.role > 1) {
        var params = _.rest(data.message.split(' '), 1);
        var username = '';
        if (params.length < 1) {
            var users = bot.getUsers();
            var randomUserIndex = _.random(1, users.length);
            username = '@' + users[(randomUserIndex - 1)].username;
        } else {
            console.log(params.join(' '));
            username_uf = params.join(' ').trim();
            username = username_uf.replace('@', '');
            console.log(username);
            var user = _.findWhere(bot.getUsers(), {username: username});
            if (user) {
                username = '@' + user.username;
            } else {
                bot.sendChat(username + ' is not here :biblethump:');
                return;
            }
        }

        var random_sentence = _.random(0, 10);
        var random_cookie = _.random(0, cookies.length - 1);
        var random_taco = _.random(0, tacos.length - 1);
        if (random_sentence <= 9) {
            bot.sendChat(username + ', ' + data.from.username + ' has rewarded you with ' + cookies[random_cookie] + '. Enjoy! :minik:');
        } else {
            bot.sendChat(username + ', ' + data.from.username + ' has rewarded you with ' + tacos[random_taco] + '. Enjoy! :minik:');
        }
    }
};
<|endoftext|>


<commit_before>var port = chrome.extension.connect({name: "content_script"});
var id = -1;
var nextId = 1;

var editorCallbacks = {}

function iframePath(editorId) {
    return "editor.html?parent_id=" + id + "&editor_id=" + editorId;
}

function hookTextArea(node) {
    var editorId = nextId++;
    node.addEventListener('dblclick', function (ev) {
	if (node.parentNode) {
	    var iframe = document.createElement("iframe");
	    iframe.src = chrome.extension.getURL(iframePath(editorId));
	    iframe.style.setProperty("position", "absolute", "important");
	    function relayout() {
		iframe.style.setProperty("width", node.offsetWidth, "important");
		iframe.style.setProperty("height", node.offsetHeight, "important");
		iframe.style.setProperty("top", node.offsetTop, "important");
		iframe.style.setProperty("left", node.offsetLeft, "important");
	    }
	    relayout();
	    node.parentNode.insertBefore(iframe, node);

	    node.addEventListener("DOMAttrModified", relayout);
	    window.addEventListener("resize", relayout);

	    // FIXME: If another script decides to change this value
	    // again, act accordingly.
	    var oldVisibility = node.style.visibility;
	    node.style.visibility = "hidden";
	    port.postMessage({
		type: "editor_msg",
		id: editorId,
		message: {
		    type: "start_editor",
		    text: node.value
		}
	    });

	    editorCallbacks[editorId] = function (text) {
		node.removeEventListener("DOMAttrModified", relayout);
		window.removeEventListener("resize", relayout);

		node.value = text;
		node.style.visibility = oldVisibility;
		if (iframe.parentNode)
		    iframe.parentNode.removeChild(iframe);
		delete editorCallbacks[editorId];
	    }

	    iframe.focus();
	}
    });
}

port.onMessage.addListener(function (msg) {
    if (msg.type === "init") {
	id = msg.id;

	// Hook the current textareas.
	var textareas = document.getElementsByTagName("textarea");
	for (var i = 0; i < textareas.length; i++) {
	    hookTextArea(textareas[i]);
	}

	// And hook any new ones that get created.
	document.body.addEventListener('DOMNodeInserted', function (ev) {
	    if (ev.target.nodeType != 1)
		return;
	    var textareas = ev.target.getElementsByTagName("textarea");
	    for (var i = 0; i < textareas.length; i++) {
		hookTextArea(textareas[i]);
	    }
	});
    } else if (msg.type === "edit_done") {
	if (editorCallbacks[msg.source])
	    editorCallbacks[msg.source](msg.text);
    } else if (msg.type === "child_detached") {
	delete editorCallbacks[msg.id];
    }
});
<commit_msg>Special-case positon:fixed nodes<commit_after>var port = chrome.extension.connect({name: "content_script"});
var id = -1;
var nextId = 1;

var editorCallbacks = {}

function iframePath(editorId) {
    return "editor.html?parent_id=" + id + "&editor_id=" + editorId;
}

function hookTextArea(node) {
    var editorId = nextId++;
    node.addEventListener('dblclick', function (ev) {
	if (node.parentNode) {
	    var iframe = document.createElement("iframe");
	    iframe.src = chrome.extension.getURL(iframePath(editorId));
	    function relayout() {
		iframe.style.setProperty("width", node.offsetWidth, "important");
		iframe.style.setProperty("height", node.offsetHeight, "important");
		iframe.style.setProperty("top", node.offsetTop, "important");
		iframe.style.setProperty("left", node.offsetLeft, "important");
		if (node.style.position === "fixed") {
		    iframe.style.setProperty("position", "fixed", "important");
		} else {
		    iframe.style.setProperty("position", "absolute", "important");
		}
	    }
	    relayout();
	    node.parentNode.insertBefore(iframe, node);

	    node.addEventListener("DOMAttrModified", relayout);
	    window.addEventListener("resize", relayout);

	    // FIXME: If another script decides to change this value
	    // again, act accordingly.
	    var oldVisibility = node.style.visibility;
	    node.style.visibility = "hidden";
	    port.postMessage({
		type: "editor_msg",
		id: editorId,
		message: {
		    type: "start_editor",
		    text: node.value
		}
	    });

	    editorCallbacks[editorId] = function (text) {
		node.removeEventListener("DOMAttrModified", relayout);
		window.removeEventListener("resize", relayout);

		node.value = text;
		node.style.visibility = oldVisibility;
		if (iframe.parentNode)
		    iframe.parentNode.removeChild(iframe);
		delete editorCallbacks[editorId];
	    }

	    iframe.focus();
	}
    });
}

port.onMessage.addListener(function (msg) {
    if (msg.type === "init") {
	id = msg.id;

	// Hook the current textareas.
	var textareas = document.getElementsByTagName("textarea");
	for (var i = 0; i < textareas.length; i++) {
	    hookTextArea(textareas[i]);
	}

	// And hook any new ones that get created.
	document.body.addEventListener('DOMNodeInserted', function (ev) {
	    if (ev.target.nodeType != 1)
		return;
	    var textareas = ev.target.getElementsByTagName("textarea");
	    for (var i = 0; i < textareas.length; i++) {
		hookTextArea(textareas[i]);
	    }
	});
    } else if (msg.type === "edit_done") {
	if (editorCallbacks[msg.source])
	    editorCallbacks[msg.source](msg.text);
    } else if (msg.type === "child_detached") {
	delete editorCallbacks[msg.id];
    }
});
<|endoftext|>


<commit_before>/**@license
 *  sysend.js - send messages between browser windows/tabs
 *  Copyright (C) 2014 Jakub Jankiewicz <http://jcubic.pl>
 *
 *  Released under the MIT license
 *
 *  The idea for this implementation came from this StackOverflow question:
 *  http://stackoverflow.com/q/24182409/387194
 */
var sysend = (function() {
    // we use prefix so `foo' event don't collide with `foo' locaStorage value
    var uniq_prefix = '___sysend___';
    // we use id because storage event is not executed if message was not
    // changed, and we want it if user send same object twice (before it will
    // be removed)
    var id = 0;
    // we need to clean up localStorage if broadcast on unload
    // because setTimeout will never fire, even setTimeout 0
    var re = new RegExp('^' + uniq_prefix);
    for(var key in localStorage) {
        if (key.match(re)) {
            localStorage.removeItem(key);
        }
    }
	var event = false;
    function get(key) {
        return localStorage.getItem(uniq_prefix + key);
    }
    function set(key, value) {
        localStorage.setItem(uniq_prefix + key, value);
		event = true;
    }
    function remove(key) {
        localStorage.removeItem(uniq_prefix + key);
		event = false;
    }
    function to_json(input) {
        var obj = [id++];
        // undefined in array get stringified as null
        if (typeof input != 'undefined') {
            obj.push(input);
        }
        return JSON.stringify(obj);
    }
    function from_json(json) {
        return JSON.parse(json);
    }
    // object with user events as keys and values arrays of callback functions
    var callbacks = {};
    window.addEventListener('storage', function(e) {
		if (!event) { // Fix issue in IE that storage event is fired on same page where setItem was called
			// get user key
			var key = e.key.replace(new RegExp('^' + uniq_prefix), '');
			if (callbacks[key]) {
				var obj = JSON.parse(get(key));
				if (obj) {
					// don't call on remove
					callbacks[key].forEach(function(fn) {
						fn(obj[1], key);
					});
				}
			}
		}
    }, false);
    return {
        broadcast: function(event, message) {
            set(event, to_json(message));
            // clean up localstorage
            setTimeout(function() {
                remove(event);
            }, 0);
        },
        on: function(event, fn) {
            if (!callbacks[event]) {
                callbacks[event] = [];
            }
            callbacks[event].push(fn);
        },
        off: function(event, fn) {
            if (callbacks[event]) {
                if (fn) {
                    for (var i=callbacks[event].length; i--;) {
                        if (callbacks[event][i] == fn) {
                            callbacks[event].splice(i, 1);
                        }
                    }
                } else {
                    callbacks[event] = [];
                }
            }
        }
    };
})();
<commit_msg>Fix issue in IE and Edge<commit_after>/**@license
 *  sysend.js - send messages between browser windows/tabs
 *  Copyright (C) 2014 Jakub Jankiewicz <http://jcubic.pl>
 *
 *  Released under the MIT license
 *
 *  The idea for this implementation came from this StackOverflow question:
 *  http://stackoverflow.com/q/24182409/387194
 */
var sysend = (function() {
    // we use prefix so `foo' event don't collide with `foo' locaStorage value
    var uniq_prefix = '___sysend___';
    var random_value = Math.random();
    // we use id because storage event is not executed if message was not
    // changed, and we want it if user send same object twice (before it will
    // be removed)
    var id = 0;
    // we need to clean up localStorage if broadcast on unload
    // because setTimeout will never fire, even setTimeout 0
    var re = new RegExp('^' + uniq_prefix);
    for(var key in localStorage) {
        if (key.match(re)) {
            localStorage.removeItem(key);
        }
    }
    function get(key) {
        return localStorage.getItem(uniq_prefix + key);
    }
    function set(key, value) {
        // storage event is not fired when value is set first time
        if (id == 0) {
            localStorage.setItem(uniq_prefix + key, random_value);
        }
        localStorage.setItem(uniq_prefix + key, value);
    }
    function remove(key) {
        localStorage.removeItem(uniq_prefix + key);
    }
    function to_json(input) {
        var obj = [id++];
        // undefined in array get stringified as null
        if (typeof input != 'undefined') {
            obj.push(input);
        }
        return JSON.stringify(obj);
    }
    function from_json(json) {
        return JSON.parse(json);
    }
    // object with user events as keys and values arrays of callback functions
    var callbacks = {};
    window.addEventListener('storage', function(e) {
        // Fix issue in IE that storage event is fired on same page where setItem was called
        if (e.key.match(re) && e.url != location.href) {
            var key = e.key.replace(re, '');
            if (callbacks[key]) {
                var value = e.newValue || get(key);
                if (value != random_value) {
                    var obj = JSON.parse(value);
                    if (obj) {
                        // don't call on remove
                        callbacks[key].forEach(function(fn) {
                            fn(obj[1], key);
                        });
                    }
                }
            }
        }
    }, false);
    return {
        broadcast: function(event, message) {
            set(event, to_json(message));
            // clean up localstorage
            setTimeout(function() {
                remove(event);
            }, 0);
        },
        on: function(event, fn) {
            if (!callbacks[event]) {
                callbacks[event] = [];
            }
            callbacks[event].push(fn);
        },
        off: function(event, fn) {
            if (callbacks[event]) {
                if (fn) {
                    for (var i=callbacks[event].length; i--;) {
                        if (callbacks[event][i] == fn) {
                            callbacks[event].splice(i, 1);
                        }
                    }
                } else {
                    callbacks[event] = [];
                }
            }
        }
    };
})();
<|endoftext|>


<commit_before>
//Parse frome Date object to JSON date
function parseDateToDB (time) {
    return (time.getFullYear().toString()
        + "-" +("0" + (time.getMonth()+1).toString()).slice(-2)
        + "-" +("0" + time.getDate().toString()).slice(-2)
        + "-" +("0" + time.getHours().toString()).slice(-2)
        + ("0"+time.getMinutes().toString()).slice(-2)
        + "-" +("0"+time.getSeconds().toString()).slice(-2));
};

//Reshuffle Array
function shuffleArray(array) {

      var currentIndex = array.length, temporaryValue, randomIndex ;

      // While there remain elements to shuffle...
      while (0 !== currentIndex) {

            // Pick a remaining element...
            randomIndex = Math.floor(Math.random() * currentIndex);
            currentIndex -= 1;

            // And swap it with the current element.
            temporaryValue = array[currentIndex];
            array[currentIndex] = array[randomIndex];
            array[randomIndex] = temporaryValue;
      }

    return array;
}

//find name in array
function findIndex(arr, ID) {
    for (i in arr) {
        var arrLevel2 = arr[i];

        if ($.inArray(ID, arrLevel2) >-1) {

            return arrLevel2[1];
            break;
        };
    }
    return "";
};

//Rolling an array function

function rollArray(array) {
    var tempObject = array[0]; //take first part

    array.splice(0,1); //delete first part
    array.push(tempObject); // add it at the end
    //return array;
}
            <commit_msg>added comment<commit_after>
//Parse frome Date object to JSON date
function parseDateToDB (time) {
    return (time.getFullYear().toString()
        + "-" +("0" + (time.getMonth()+1).toString()).slice(-2)
        + "-" +("0" + time.getDate().toString()).slice(-2)
        + "-" +("0" + time.getHours().toString()).slice(-2)
        + ("0"+time.getMinutes().toString()).slice(-2)
        + "-" +("0"+time.getSeconds().toString()).slice(-2));
};

//Reshuffle Array
// This is important
function shuffleArray(array) {

      var currentIndex = array.length, temporaryValue, randomIndex ;

      // While there remain elements to shuffle...
      while (0 !== currentIndex) {

            // Pick a remaining element...
            randomIndex = Math.floor(Math.random() * currentIndex);
            currentIndex -= 1;

            // And swap it with the current element.
            temporaryValue = array[currentIndex];
            array[currentIndex] = array[randomIndex];
            array[randomIndex] = temporaryValue;
      }

    return array;
}

//find name in array
function findIndex(arr, ID) {
    for (i in arr) {
        var arrLevel2 = arr[i];

        if ($.inArray(ID, arrLevel2) >-1) {

            return arrLevel2[1];
            break;
        };
    }
    return "";
};

//Rolling an array function

function rollArray(array) {
    var tempObject = array[0]; //take first part

    array.splice(0,1); //delete first part
    array.push(tempObject); // add it at the end
    //return array;
}
            <|endoftext|>


<commit_before>// lame music/song.mp3 --tt "One Black Night" --ta "Wonder Girls" --tg "KPop"
// --tl "REBOOT" --ty "2015" --ti "music/img.jpg" music/new_song.mp3
// lame music/song.mp3 --tt "One Black Night" --ta "Wonder Girls" --tg "KPop" --tl "REBOOT" --ty "2015" --ti "music/img.jpg" music/new_song.mp3

var add_quotes = function ( input ) {
    return '"' + input + '"';
};
var execSync = require('child_process').execSync;
var tag = function ( input_path, input_file_name, title, album, artist, genre, date, img_path) {
    var dir_song = 'X:\\Dropbox\\js\\mp3\\music';
    var input = input_file_name;
    // var input = input_path + input_file_name;
    var output = artist + " - " + title + ".mp3";
    var dir_lame = "X:\\Dropbox\\js\\mp3\\";
    var cmd_lame = dir_lame + "lame.exe ";

    var cmd_tag =
        cmd_lame + add_quotes( input    ) +
        " --tt " + add_quotes( title    ) +
        " --ta " + add_quotes( artist   ) +
        " --tg " + add_quotes( genre    ) +
        " --tl " + add_quotes( album    ) +
        " --ta " + add_quotes( artist   ) +
        " --ty " + add_quotes( date     ) +
        " --ti " + add_quotes( img_path ) +
        " "      + add_quotes( output   );

    var cmd_del = "del " + input_file_name;

    execSync( cmd_tag, { cwd : dir_song } );
    execSync( cmd_del, { cwd : dir_song } );
};

tag("music/", "song.mp3", "One Black Night", "REBOOT", "Wonder Girls",
        "KPop", "2015", "img.jpg");
<commit_msg>Made it async<commit_after>// lame music/song.mp3 --tt "One Black Night" --ta "Wonder Girls" --tg "KPop"
// --tl "REBOOT" --ty "2015" --ti "music/img.jpg" music/new_song.mp3
// lame music/song.mp3 --tt "One Black Night" --ta "Wonder Girls" --tg "KPop" --tl "REBOOT" --ty "2015" --ti "music/img.jpg" music/new_song.mp3

var add_quotes = function ( input ) {
    return '"' + input + '"';
};
var exec = require('child_process').exec;
var tag = function ( input_path, input_file_name, title, album, artist, genre, date, img_path) {
    var dir_song = 'X:\\Dropbox\\js\\mp3\\music';
    var input = input_file_name;
    // var input = input_path + input_file_name;
    var output = artist + " - " + title + ".mp3";
    var dir_lame = "X:\\Dropbox\\js\\mp3\\";
    var cmd_lame = dir_lame + "lame.exe ";

    var cmd_tag =
        cmd_lame + add_quotes( input    ) +
        " --tt " + add_quotes( title    ) +
        " --ta " + add_quotes( artist   ) +
        " --tg " + add_quotes( genre    ) +
        " --tl " + add_quotes( album    ) +
        " --ta " + add_quotes( artist   ) +
        " --ty " + add_quotes( date     ) +
        " --ti " + add_quotes( img_path ) +
        " "      + add_quotes( output   );

    var cmd_del = "del " + input_file_name;

    var sink = "";

    exec( cmd_tag, { cwd : dir_song }, function () {
        exec( cmd_del, { cwd : dir_song } );
    });
};

tag("music/", "song.mp3", "One Black Night", "REBOOT", "Wonder Girls",
        "KPop", "2015", "img.jpg");
<|endoftext|>