<commit_before>const crypto = require('crypto');
const fs = require('fs');
const path = require('path');
const zlib = require('zlib');

const babel = require('@babel/core');
const chokidar = require('chokidar');
const mime = require('mime');
const Negotiator = require('negotiator');
const sass = require('sass');
//const sassGraph = require('sass-graph');
const Snockets = require('snockets');
const UglifyJS = require('uglify-js');
const UglifyCss = require('uglifycss');

const gzipContentTypes = require('./gzipContentTypes.js');

exports.static = function(directory, options) {
    // Default to 'public' if the directory is not specified
    directory = directory || 'public';

    // Options are optional
    if (!options) {
        options = {};
    }

    if (!options.babel) {
        options.babel = {};
    }

    // Hashify by default
    if (!Object.prototype.hasOwnProperty.call(options, 'hashify')) {
        options.hashify = true;
    }

    if (!options.sass) {
        options.sass = {};
    }

    if (!options.snockets) {
        options.snockets = {};
    }

    // Snockets must be processed syncronously to produce consistent output
    options.snockets.async = false;

    // UglifyCSS by default
    if (!options.uglifycss) {
        options.uglifycss = {
            enabled: true
        };
    }

    // UglifyJS by default
    if (!options.uglifyjs) {
        options.uglifyjs = {
            enabled: true
        };
    }

    // Don't watch for changes by default
    if (!options.watch) {
        options.watch = {
            enabled: false
        };
    }

    // Create a local cache to hold the files
    const files = {};

    const snockets = new Snockets();

    let watcher;

    if (options.watch.enabled) {
        // Setup the watcher
        watcher = chokidar.watch(directory, { ignoreInitial: true });

        watcher.on('change', function(filePath) {
            removeFile(filePath);
        });
    }

    /**
     * Tries to read a file from local cache.
     * Reads the file from disk if it's not present in the local cache.
     * @param {string} urlPath
     */
    function fetchFile(urlPath) {
        // Try to get the file from local cache
        let file = files[urlPath];

        // Return the file from cache if found
        if (file) {
            return file;
        }

        // Read the file from disk
        file = readFile(urlPath);

        // Put the file in local cache
        files[urlPath] = file;

        return file;
    }

    /**
     * Converts a URL (/robots.txt) to a URL that includes the file's hash (/robots-3f54004ef6fc21b24a9e6069fc114fd9070b77a1.txt)
     * @param {string} url
     * @param {string} hash
     */
    function hashifyUrl(url, hash) {
        if (!url.includes('.')) {
            return url.replace(/([?#].*)?$/, `-${hash}$1`);
        }

        return url.replace(/\.([^.]*)([?#].*)?$/, `-${hash}.$1$2`);
    }

    /**
     * Parses a URL path potentially containing a hash (/robots-3f54004ef6fc21b24a9e6069fc114fd9070b77a1.txt)
     * into an object with a hash and path properties ({ hash: '3f54004ef6fc21b24a9e6069fc114fd9070b77a1', path: '/robots.txt' })
     * @param {object} req
     */
    function parseUrlPath(urlPath) {
        // https://regex101.com/r/j5hvRj/1
        const regex = /\/.+(-([0-9a-f]{40}))/;
        const matches = urlPath.match(regex);

        if (!matches) {
            return {
                path: urlPath
            };
        }

        return {
            hash: matches[2],
            path: urlPath.replace(matches[1], '')
        };
    }

    function readCascadingStyleSheetsFile(filePath) {
        let data;

        // CSS
        try {
            data = fs.readFileSync(filePath).toString();
        } catch(err) {
            // Handle ENOENT (No such file or directory): https://nodejs.org/api/errors.html#common-system-errors
            if (err.code !== 'ENOENT') {
                throw err;
            }

            // SASS
            const basename = path.basename(filePath, path.extname(filePath));
            options.sass.file = path.join(path.dirname(filePath), `${basename}.scss`);
            data = sass.renderSync(options.sass).css.toString();
        }

        // Update URLs in CSS: https://regex101.com/r/FxrppP/1
        data = data.replaceAll(/url\((['"]?(.*?)['"]?)\)/g, function(match, p1, p2) {
            return `url(${urlBuilder(p2)})`;
        });

        // UglifyCSS
        if (options.uglifycss.enabled) {
            data = UglifyCss.processString(data, options.uglifycss);
        }

        return data;
    }

    function readFile(urlPath) {
        let filePath = toFilePath(urlPath);
        let extension = path.extname(filePath);
        let data;

        if (extension === '.css') {
            data = readCascadingStyleSheetsFile(filePath);
        } else if (extension === '.js') {
            data = readJavaScriptFile(filePath);
        } else {
            data = fs.readFileSync(filePath);
        }

        const file = {
            content: data,
            contentLength: data.length,
            contentType: mime.getType(urlPath),
            hash: crypto.createHash('sha1').update(data).digest('hex')
        };

        // Don't gzip any content less that 1500 bytes (the size of a TCP packet). Only gzip specific content types.
        if (file.contentLength > 1500 && gzipContentTypes.includes(file.contentType)) {
            const gzipContent = zlib.gzipSync(file.content);

            file.gzip = {
                content: gzipContent,
                contentLength: gzipContent.length
            };
        }

        return file;
    }

    function readJavaScriptFile(filePath) {
        let data = fs.readFileSync(filePath).toString();

        // Snockets
        try {
            data = snockets.getConcatenation(filePath, options.snockets);
        } catch(err) {
            // Snockets can't parse, so just pass the js file along
            console.warn(`Snockets skipping ${filePath}:\n    ${err}`);
        }

        // Snockets (watcher)
        if (watcher) {
            try {
                // Get all files in the snockets chain
                const compiledChain = snockets.getCompiledChain(filePath, options.snockets);

                // Add each file of the snockets chain to the watcher
                compiledChain.forEach(c => {
                    watcher.add(c.filename);
                });
            } catch(err) {
                // Snockets can't parse, so skip watch
                console.warn(`Snockets skipping watch for ${filePath}:\n    ${err}`);
            }
        }

        // Babel
        try {
            let result = babel.transformSync(data, {
                ...options.babel,
                presets: [require('@babel/preset-react')]
            });

            data = result.code;
        } catch(err) {
            // Babel can't transform, so just pass the file along
            console.warn(`Babel skipping ${filePath}:\n    ${err}`);
        }

        // UglifyJS
        if (options.uglifyjs.enabled) {
            const uglifyjsOptions = JSON.parse(JSON.stringify(options.uglifyjs));
            delete uglifyjsOptions.enabled;

            const result = UglifyJS.minify(data, uglifyjsOptions);

            if (result.error) {
                console.warn(`UglifyJS skipping ${filePath}:\n    ${JSON.stringify(result.error)}`);
            } else {
                data = result.code;
            }
        }

        return data;
    }

    /**
     * Removes a file from the local cache.
     * @param {*} filePath
     */
    function removeFile(filePath) {
        let extension = path.extname(filePath);

        if (extension === '.js') {
            return removeJavaScriptFile(filePath);
        }

        // Remove the changed file from the local cache
        delete files[toUrlPath(filePath)];
    }

    /**
     * Removes a JavaScript file from the local cache.
     * @param {*} filePath
     */
     function removeJavaScriptFile(filePath) {
        // Remove the changed file from the local cache
        delete files[toUrlPath(filePath)];

        // Resolve the absolute file path for the changed file
        const absoluteFilePath = path.resolve(filePath);

        // Find any parents that have a dependency on this file and remove them too
        snockets.depGraph.parentsOf(absoluteFilePath).forEach(removeJavaScriptFile);
    }

    function urlBuilder(urlPath) {
        let url = urlPath;

        if (options.hashify) {
            try {
                const request = parseUrlPath(urlPath);
                const file = fetchFile(request.path);

                url = hashifyUrl(request.path, file.hash);
            } catch(err) {
                // If we don't have a file that matches the specified URL path simply return the original URL path
            }
        }

        if (options.hostname) {
            url = `https://${options.hostname}${url}`;
        }

        return url;
    }

    /**
     * Converts a URL path (/robots.txt) to a file path (/Users/username/site/public/robots.txt).
     * @param {string} urlPath
     */
    function toFilePath(urlPath) {
        const myURL = new URL(urlPath, 'https://example.org/');
        const pathname = myURL.pathname.replace(/^\//, '');
        return path.resolve(directory, pathname);
    }

    /**
     * Converts a file path (/Users/username/site/public/robots.txt) to a URL path (/robots.txt).
     * @param {string} urlPath
     */
    function toUrlPath(filePath) {
        const urlPath = path.posix.relative(directory, path.resolve(filePath));

        return `/${urlPath}`;
    }

    return function staticMiddleware(req, res, next) {
        // Ignore anything that's not a GET or HEAD request
        if (!['GET', 'HEAD'].includes(req.method)) {
            return next();
        }

        // Register function in app.locals to help views build URLs: https://expressjs.com/en/api.html#app.locals
        if (req.app && !req.app.locals.electricity) {
            req.app.locals.electricity = {
                url: urlBuilder
            };
        }

        let file;
        const request = parseUrlPath(req.path);

        try {
            file = fetchFile(request.path);
        } catch(err) {
            // Handle EISDIR (Is a directory): https://nodejs.org/api/errors.html#common-system-errors
            if (err.code === 'EISDIR') {
                return next();
            }

            // Handle ENOENT (No such file or directory): https://nodejs.org/api/errors.html#common-system-errors
            if (err.code === 'ENOENT') {
                return next();
            }

            return next(err);
        }

        // Verify file matches the requested hash, otherwise 302
        if (options.hashify && request.hash !== file.hash) {
            res.set({
                'cache-control': 'no-cache',
                'expires': '0',
                'pragma': 'no-cache'
            });

            const url = hashifyUrl(request.path, file.hash);

            return res.redirect(url);
        }

        // Set a far-future expiration date
        const expires = new Date();
        expires.setFullYear(expires.getFullYear() + 1);

        res.set({
            'cache-control': 'public, max-age=31536000',
            'content-Type': file.contentType,
            etag: file.hash,
            expires: expires.toUTCString()
        });

        // Set any other headers specified in options
        if (options.headers) {
            res.set(options.headers);
        }

        const ifNoneMatch = req.get('if-none-match');

        // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/If-None-Match
        if (ifNoneMatch && ifNoneMatch.includes(file.hash)) {
            return res.sendStatus(304);
        }

        // By default, send the file's content (without gzip)
        let content = file.content;
        let contentLength = file.contentLength;

        // Check to see if the file could be gzipped
        if (file.gzip && file.gzip.content) {
            const negotiator = new Negotiator(req);

            // Ensure the request supports gzip
            if (negotiator.encodings().includes('gzip')) {
                content = file.gzip.content;
                contentLength = file.gzip.contentLength;

                res.set('content-encoding', 'gzip');
            }
        }

        // Set the content-length header
        res.set('content-length', contentLength);

        // Return early without sending content for HEAD requests
        if (req.method === 'HEAD') {
            return res.sendStatus(200);
        }

        res.send(content);
    };
};<commit_msg>forgot replaceAll isn't a thing in Node.js v14<commit_after>const crypto = require('crypto');
const fs = require('fs');
const path = require('path');
const zlib = require('zlib');

const babel = require('@babel/core');
const chokidar = require('chokidar');
const mime = require('mime');
const Negotiator = require('negotiator');
const sass = require('sass');
//const sassGraph = require('sass-graph');
const Snockets = require('snockets');
const UglifyJS = require('uglify-js');
const UglifyCss = require('uglifycss');

const gzipContentTypes = require('./gzipContentTypes.js');

exports.static = function(directory, options) {
    // Default to 'public' if the directory is not specified
    directory = directory || 'public';

    // Options are optional
    if (!options) {
        options = {};
    }

    if (!options.babel) {
        options.babel = {};
    }

    // Hashify by default
    if (!Object.prototype.hasOwnProperty.call(options, 'hashify')) {
        options.hashify = true;
    }

    if (!options.sass) {
        options.sass = {};
    }

    if (!options.snockets) {
        options.snockets = {};
    }

    // Snockets must be processed syncronously to produce consistent output
    options.snockets.async = false;

    // UglifyCSS by default
    if (!options.uglifycss) {
        options.uglifycss = {
            enabled: true
        };
    }

    // UglifyJS by default
    if (!options.uglifyjs) {
        options.uglifyjs = {
            enabled: true
        };
    }

    // Don't watch for changes by default
    if (!options.watch) {
        options.watch = {
            enabled: false
        };
    }

    // Create a local cache to hold the files
    const files = {};

    const snockets = new Snockets();

    let watcher;

    if (options.watch.enabled) {
        // Setup the watcher
        watcher = chokidar.watch(directory, { ignoreInitial: true });

        watcher.on('change', function(filePath) {
            removeFile(filePath);
        });
    }

    /**
     * Tries to read a file from local cache.
     * Reads the file from disk if it's not present in the local cache.
     * @param {string} urlPath
     */
    function fetchFile(urlPath) {
        // Try to get the file from local cache
        let file = files[urlPath];

        // Return the file from cache if found
        if (file) {
            return file;
        }

        // Read the file from disk
        file = readFile(urlPath);

        // Put the file in local cache
        files[urlPath] = file;

        return file;
    }

    /**
     * Converts a URL (/robots.txt) to a URL that includes the file's hash (/robots-3f54004ef6fc21b24a9e6069fc114fd9070b77a1.txt)
     * @param {string} url
     * @param {string} hash
     */
    function hashifyUrl(url, hash) {
        if (!url.includes('.')) {
            return url.replace(/([?#].*)?$/, `-${hash}$1`);
        }

        return url.replace(/\.([^.]*)([?#].*)?$/, `-${hash}.$1$2`);
    }

    /**
     * Parses a URL path potentially containing a hash (/robots-3f54004ef6fc21b24a9e6069fc114fd9070b77a1.txt)
     * into an object with a hash and path properties ({ hash: '3f54004ef6fc21b24a9e6069fc114fd9070b77a1', path: '/robots.txt' })
     * @param {object} req
     */
    function parseUrlPath(urlPath) {
        // https://regex101.com/r/j5hvRj/1
        const regex = /\/.+(-([0-9a-f]{40}))/;
        const matches = urlPath.match(regex);

        if (!matches) {
            return {
                path: urlPath
            };
        }

        return {
            hash: matches[2],
            path: urlPath.replace(matches[1], '')
        };
    }

    function readCascadingStyleSheetsFile(filePath) {
        let data;

        // CSS
        try {
            data = fs.readFileSync(filePath).toString();
        } catch(err) {
            // Handle ENOENT (No such file or directory): https://nodejs.org/api/errors.html#common-system-errors
            if (err.code !== 'ENOENT') {
                throw err;
            }

            // SASS
            const basename = path.basename(filePath, path.extname(filePath));
            options.sass.file = path.join(path.dirname(filePath), `${basename}.scss`);
            data = sass.renderSync(options.sass).css.toString();
        }

        // Update URLs in CSS: https://regex101.com/r/FxrppP/4
        data = data.replace(/url\(['"]?(.*?)['"]?\)/g, function(match, p1) {
            return `url(${urlBuilder(p1)})`;
        });

        // UglifyCSS
        if (options.uglifycss.enabled) {
            data = UglifyCss.processString(data, options.uglifycss);
        }

        return data;
    }

    function readFile(urlPath) {
        let filePath = toFilePath(urlPath);
        let extension = path.extname(filePath);
        let data;

        if (extension === '.css') {
            data = readCascadingStyleSheetsFile(filePath);
        } else if (extension === '.js') {
            data = readJavaScriptFile(filePath);
        } else {
            data = fs.readFileSync(filePath);
        }

        const file = {
            content: data,
            contentLength: data.length,
            contentType: mime.getType(urlPath),
            hash: crypto.createHash('sha1').update(data).digest('hex')
        };

        // Don't gzip any content less that 1500 bytes (the size of a TCP packet). Only gzip specific content types.
        if (file.contentLength > 1500 && gzipContentTypes.includes(file.contentType)) {
            const gzipContent = zlib.gzipSync(file.content);

            file.gzip = {
                content: gzipContent,
                contentLength: gzipContent.length
            };
        }

        return file;
    }

    function readJavaScriptFile(filePath) {
        let data = fs.readFileSync(filePath).toString();

        // Snockets
        try {
            data = snockets.getConcatenation(filePath, options.snockets);
        } catch(err) {
            // Snockets can't parse, so just pass the js file along
            console.warn(`Snockets skipping ${filePath}:\n    ${err}`);
        }

        // Snockets (watcher)
        if (watcher) {
            try {
                // Get all files in the snockets chain
                const compiledChain = snockets.getCompiledChain(filePath, options.snockets);

                // Add each file of the snockets chain to the watcher
                compiledChain.forEach(c => {
                    watcher.add(c.filename);
                });
            } catch(err) {
                // Snockets can't parse, so skip watch
                console.warn(`Snockets skipping watch for ${filePath}:\n    ${err}`);
            }
        }

        // Babel
        try {
            let result = babel.transformSync(data, {
                ...options.babel,
                presets: [require('@babel/preset-react')]
            });

            data = result.code;
        } catch(err) {
            // Babel can't transform, so just pass the file along
            console.warn(`Babel skipping ${filePath}:\n    ${err}`);
        }

        // UglifyJS
        if (options.uglifyjs.enabled) {
            const uglifyjsOptions = JSON.parse(JSON.stringify(options.uglifyjs));
            delete uglifyjsOptions.enabled;

            const result = UglifyJS.minify(data, uglifyjsOptions);

            if (result.error) {
                console.warn(`UglifyJS skipping ${filePath}:\n    ${JSON.stringify(result.error)}`);
            } else {
                data = result.code;
            }
        }

        return data;
    }

    /**
     * Removes a file from the local cache.
     * @param {*} filePath
     */
    function removeFile(filePath) {
        let extension = path.extname(filePath);

        if (extension === '.js') {
            return removeJavaScriptFile(filePath);
        }

        // Remove the changed file from the local cache
        delete files[toUrlPath(filePath)];
    }

    /**
     * Removes a JavaScript file from the local cache.
     * @param {*} filePath
     */
     function removeJavaScriptFile(filePath) {
        // Remove the changed file from the local cache
        delete files[toUrlPath(filePath)];

        // Resolve the absolute file path for the changed file
        const absoluteFilePath = path.resolve(filePath);

        // Find any parents that have a dependency on this file and remove them too
        snockets.depGraph.parentsOf(absoluteFilePath).forEach(removeJavaScriptFile);
    }

    function urlBuilder(urlPath) {
        let url = urlPath;

        if (options.hashify) {
            try {
                const request = parseUrlPath(urlPath);
                const file = fetchFile(request.path);

                url = hashifyUrl(request.path, file.hash);
            } catch(err) {
                // If we don't have a file that matches the specified URL path simply return the original URL path
            }
        }

        if (options.hostname) {
            url = `https://${options.hostname}${url}`;
        }

        return url;
    }

    /**
     * Converts a URL path (/robots.txt) to a file path (/Users/username/site/public/robots.txt).
     * @param {string} urlPath
     */
    function toFilePath(urlPath) {
        const myURL = new URL(urlPath, 'https://example.org/');
        const pathname = myURL.pathname.replace(/^\//, '');
        return path.resolve(directory, pathname);
    }

    /**
     * Converts a file path (/Users/username/site/public/robots.txt) to a URL path (/robots.txt).
     * @param {string} urlPath
     */
    function toUrlPath(filePath) {
        const urlPath = path.posix.relative(directory, path.resolve(filePath));

        return `/${urlPath}`;
    }

    return function staticMiddleware(req, res, next) {
        // Ignore anything that's not a GET or HEAD request
        if (!['GET', 'HEAD'].includes(req.method)) {
            return next();
        }

        // Register function in app.locals to help views build URLs: https://expressjs.com/en/api.html#app.locals
        if (req.app && !req.app.locals.electricity) {
            req.app.locals.electricity = {
                url: urlBuilder
            };
        }

        let file;
        const request = parseUrlPath(req.path);

        try {
            file = fetchFile(request.path);
        } catch(err) {
            // Handle EISDIR (Is a directory): https://nodejs.org/api/errors.html#common-system-errors
            if (err.code === 'EISDIR') {
                return next();
            }

            // Handle ENOENT (No such file or directory): https://nodejs.org/api/errors.html#common-system-errors
            if (err.code === 'ENOENT') {
                return next();
            }

            return next(err);
        }

        // Verify file matches the requested hash, otherwise 302
        if (options.hashify && request.hash !== file.hash) {
            res.set({
                'cache-control': 'no-cache',
                'expires': '0',
                'pragma': 'no-cache'
            });

            const url = hashifyUrl(request.path, file.hash);

            return res.redirect(url);
        }

        // Set a far-future expiration date
        const expires = new Date();
        expires.setFullYear(expires.getFullYear() + 1);

        res.set({
            'cache-control': 'public, max-age=31536000',
            'content-Type': file.contentType,
            etag: file.hash,
            expires: expires.toUTCString()
        });

        // Set any other headers specified in options
        if (options.headers) {
            res.set(options.headers);
        }

        const ifNoneMatch = req.get('if-none-match');

        // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/If-None-Match
        if (ifNoneMatch && ifNoneMatch.includes(file.hash)) {
            return res.sendStatus(304);
        }

        // By default, send the file's content (without gzip)
        let content = file.content;
        let contentLength = file.contentLength;

        // Check to see if the file could be gzipped
        if (file.gzip && file.gzip.content) {
            const negotiator = new Negotiator(req);

            // Ensure the request supports gzip
            if (negotiator.encodings().includes('gzip')) {
                content = file.gzip.content;
                contentLength = file.gzip.contentLength;

                res.set('content-encoding', 'gzip');
            }
        }

        // Set the content-length header
        res.set('content-length', contentLength);

        // Return early without sending content for HEAD requests
        if (req.method === 'HEAD') {
            return res.sendStatus(200);
        }

        res.send(content);
    };
};<|endoftext|>


<commit_before>
var projects = {
  list:[
    {
      name:'Vr Poly Gallery',
      description:'A multi-platform virtual gallery browser for Google\'s Poly 3D Asset Library. Compatible with desktop, mobile web, Cardboard, or Gear VR!',
      img:'img/poly.jpg',
      tags:[ 'React', 'VR', 'google APIs'],
      liveLink:'http://jbr-app.herokuapp.com/VirtualReaction',
      githubLink:'https://github.com/abraxasrex/Virtual_Reaction',
      offLine: false,
       npmPackage: false
    },
    {
      name:'Billseek',
      description:'A social application for tracking and sharing the activity of bills and people in Congress, developed with Angular and typescript.',
      img:'img/Billseek.png',
      tags:[ 'typescript', 'MEAN stack', 'mocha', 'chai'],
      liveLink:'http://jbr-app.herokuapp.com/BillSeek',
      githubLink:'https://github.com/abraxasrex/BillSeek',
      exampleLink:'http://jbr-app.herokuapp.com/BillSeek/interests/togo123',
      offLine: false,
       npmPackage: false
    },
    {
      name:'Grind Log Pro',
      description:'A USDA-compliant web app for grocery stores that scans, logs, and tracks meat grinds.',
      img:'img/glp2.png',
      tags:[ 'consumer-facing', 'MEAN stack', 'bootstrap'],
      liveLink:'http://www.grindlogpro.com',
      githubLink:'https://impgrocery.com/our-services/grind-log-pro/',
      private:true
    },
    {
      name:'Notifry',
      description:'A calendar todo app brought to you by the magic of React.',
      img:'img/notifry.png',
      tags:[ 'React', 'material UI', 'webpack'],
      liveLink:'http://notifry.surge.sh/',
      githubLink:'https://github.com/abraxasrex/Notefry',
      offLine: false
    },
    {
      name:'wav-reverse(npm)',
      description: 'A node package that lets you reverse a .wav file.',
      githubLink:'https://www.npmjs.com/package/reverse-wav',
      liveLink:'https://www.npmjs.com/package/reverse-wav',
      img:"https://www.freesound.org/data/displays/181/181129_321967_spec_L.jpg",
      tags:['node.js', 'audio programming'],
      npmPackage: true
    },
    {
      name:'Virtua Breakfast',
      description:'A game for mobile browsers using Three.js and the DeviceOrientation API. Rotate in place to move the flying donut alongside your field of view. Catch the falling oranges and advance to faster levels. Experience the future of breakfast.',
      img:'img/virtua.png',
      tags:[ 'Three.js', 'VR', 'express.js'],
      githubLink:'https://github.com/abraxasrex/virtual_breakfast',
      liveLink:'http://jbr-app.herokuapp.com/VirtualBreakfast',
      offLine: false
    },
    {
      name:'Cardling',
      description:'Create and keep track of GIF flashcards that help you learn or practice vocabulary.',
      img:'img/cardling.png',
      tags: ['MEAN stack', 'Passport'],
      githubLink: 'https://github.com/abraxasrex/Cardling_2',
      offLine: true
    },
    {
      name:'Placedrop',
      description:'Create customized notes and markers on a local map and plan your daily route. Powered by the Google Maps API, this project grew out of my team\'s entry in Expedia\'s February 2016 hackathon.',
      img:'img/place_drop.png',
      tags:['google APIs', 'hackathon', 'express.js'],
      githubLink:'https://github.com/abraxasrex/placedrop',
      offLine: true
    },
    {
      name:'Hungr',
      description:'Maybe you should cook dinner tonight. Maybe you should eat out. Maybe this app will help you decide? It utilizes the Foursquare and Food2Fork APIs to compare all your delicious options.',
      img:'img/hungr.png',
      tags:['angular.js', 'meteor.js', 'foursquare API'],
      githubLink:'https://github.com/abraxasrex/hungr',
      offLine: true
    },
    {
      name:'Datamap',
      description:'D3.js-powered visualization of climate change in the 20th century. Select a range of years to discover the relative impact of global warming in a given region.',
      githubLink:'https://github.com/abraxasrex/GCC_MAP',
      img:'img/datamap.png',
      tags:['d3.js', 'meteor.js'],
      offLine: true
    },
    {
      name:'Simon Says',
      description:'A variation on the classic memory game. A Zipline project in front end development from FreeCodeCamp.com.',
      tags:['FreeCodeCamp'],
      githubLink:'wip',
      liveLink:"https://codepen.io/jbreasor/full/pjvGGP",
      img:'img/simon.png',
      offLine: false
    },
    {
      name:'Minimal Polls',
      description:'Create customized polls, vote on the polls of others, and share your favorites with your friends. A basejump project for Free Code Camp.',
      tags:['meteor.js', 'FreeCodeCamp'],
      githubLink:"https://github.com/abraxasrex/minimal-voting",
      img:'img/minimal.png',
      offLine: true
    }
  ]
};
var socialMedias = {
  list: [
    {
      name: 'Github',
      link:'https://github.com/abraxasrex'
    },
    {
      name: 'LinkedIn',
      link:'https://www.linkedin.com/in/jonathan-reasor-16966352'
    },
  //  {
    //   name: 'Devpost',
    //   link:'http://devpost.com/jbreasor'
    // },
    {
      name: 'F.C.C.',
      link:'http://www.freecodecamp.com/abraxasrex'
    },
    {
      name:'Codepen',
      link:'http://codepen.io/jbreasor/'
    },
    {
      name:'Codecademy',
      link:'https://www.codecademy.com/davidbowie89'
    },
    {
      name:'Wordpress',
      link:'https://mindbodyscissors.wordpress.com/2015/10/19/meteor-js-through-the-lens-of-a-junior-dev/'
    },
    {
      name:'StackOverFlow',
      link:'http://stackoverflow.com/users/5258815/jonathan-reasor'
    },
    {
      name:'NPM',
      link:'https://www.npmjs.com/~abraxasrex'
    }
  ]};

var tag_colors = {
  'mocha':'PaleGreen',
  'chai':'Peachpuff',
  'hackathon': 'Khaki',
  'google APIs': 'LightSalmon',
  'bootstrap': 'Indigo',
  'typescript':'Orange',
  'material UI': 'Green',
  'express.js':'MediumSlateblue',
  'webpack':'MediumSlateblue',
  'MEAN stack': 'Plum',
  'express.js':'MediumSlateBlue',
  'node.js': 'GreenYellow',
  'meteor.js': 'MediumAquamarine',
  'FreeCodeCamp': 'LightSteelBlue',
  'd3.js': 'Goldenrod',
  'audio programming': 'FloralWhite',
  'angular.js': 'Silver',
  'foursquare API': 'Tomato',
  'Passport': 'LightSeaGreen',
  'React': 'GreenYellow',
  'Three.js' :'DarkOrange',
  'VR':'IndianRed',
  'consumer-facing':'PaleVioletRed'
}
<commit_msg>edit info<commit_after>
var projects = {
  list:[
    {
      name:'Vr Poly Gallery',
      description:'A multi-platform virtual gallery browser for Google\'s Poly 3D Asset Library. For desktop and mobile browsers.',
      img:'img/poly.jpg',
      tags:[ 'React', 'VR', 'google APIs'],
      liveLink:'http://jbr-app.herokuapp.com/VirtualReaction',
      githubLink:'https://github.com/abraxasrex/Virtual_Reaction',
      offLine: false,
       npmPackage: false
    },
    {
      name:'Billseek',
      description:'A social application for tracking and sharing the activity of bills and people in Congress, developed with Angular and typescript.',
      img:'img/Billseek.png',
      tags:[ 'typescript', 'MEAN stack', 'mocha', 'chai'],
      liveLink:'http://jbr-app.herokuapp.com/BillSeek',
      githubLink:'https://github.com/abraxasrex/BillSeek',
      exampleLink:'http://jbr-app.herokuapp.com/BillSeek/interests/togo123',
      offLine: false,
       npmPackage: false
    },
    {
      name:'Grind Log Pro',
      description:'A USDA-compliant web app for grocery stores that scans, logs, and tracks meat grinds.',
      img:'img/glp2.png',
      tags:[ 'consumer-facing', 'MEAN stack', 'bootstrap'],
      liveLink:'http://www.grindlogpro.com',
      githubLink:'https://impgrocery.com/our-services/grind-log-pro/',
      private:true
    },
    {
      name:'Notifry',
      description:'A calendar todo app brought to you by the magic of React.',
      img:'img/notifry.png',
      tags:[ 'React', 'material UI', 'webpack'],
      liveLink:'http://notifry.surge.sh/',
      githubLink:'https://github.com/abraxasrex/Notefry',
      offLine: false
    },
    {
      name:'wav-reverse(npm)',
      description: 'A node package that lets you reverse a .wav file.',
      githubLink:'https://www.npmjs.com/package/reverse-wav',
      liveLink:'https://www.npmjs.com/package/reverse-wav',
      img:"https://www.freesound.org/data/displays/181/181129_321967_spec_L.jpg",
      tags:['node.js', 'audio programming'],
      npmPackage: true
    },
    {
      name:'Virtua Breakfast',
      description:'A game for mobile browsers using Three.js and the DeviceOrientation API. Rotate in place to move the flying donut alongside your field of view. Catch the falling oranges and advance to faster levels. Experience the future of breakfast.',
      img:'img/virtua.png',
      tags:[ 'Three.js', 'VR', 'express.js'],
      githubLink:'https://github.com/abraxasrex/virtual_breakfast',
      liveLink:'http://jbr-app.herokuapp.com/VirtualBreakfast',
      offLine: false
    },
    {
      name:'Cardling',
      description:'Create and keep track of GIF flashcards that help you learn or practice vocabulary.',
      img:'img/cardling.png',
      tags: ['MEAN stack', 'Passport'],
      githubLink: 'https://github.com/abraxasrex/Cardling_2',
      offLine: true
    },
    {
      name:'Placedrop',
      description:'Create customized notes and markers on a local map and plan your daily route. Powered by the Google Maps API, this project grew out of my team\'s entry in Expedia\'s February 2016 hackathon.',
      img:'img/place_drop.png',
      tags:['google APIs', 'hackathon', 'express.js'],
      githubLink:'https://github.com/abraxasrex/placedrop',
      offLine: true
    },
    {
      name:'Hungr',
      description:'Maybe you should cook dinner tonight. Maybe you should eat out. Maybe this app will help you decide? It utilizes the Foursquare and Food2Fork APIs to compare all your delicious options.',
      img:'img/hungr.png',
      tags:['angular.js', 'meteor.js', 'foursquare API'],
      githubLink:'https://github.com/abraxasrex/hungr',
      offLine: true
    },
    {
      name:'Datamap',
      description:'D3.js-powered visualization of climate change in the 20th century. Select a range of years to discover the relative impact of global warming in a given region.',
      githubLink:'https://github.com/abraxasrex/GCC_MAP',
      img:'img/datamap.png',
      tags:['d3.js', 'meteor.js'],
      offLine: true
    },
    {
      name:'Simon Says',
      description:'A variation on the classic memory game. A Zipline project in front end development from FreeCodeCamp.com.',
      tags:['FreeCodeCamp'],
      githubLink:'wip',
      liveLink:"https://codepen.io/jbreasor/full/pjvGGP",
      img:'img/simon.png',
      offLine: false
    },
    {
      name:'Minimal Polls',
      description:'Create customized polls, vote on the polls of others, and share your favorites with your friends. A basejump project for Free Code Camp.',
      tags:['meteor.js', 'FreeCodeCamp'],
      githubLink:"https://github.com/abraxasrex/minimal-voting",
      img:'img/minimal.png',
      offLine: true
    }
  ]
};
var socialMedias = {
  list: [
    {
      name: 'Github',
      link:'https://github.com/abraxasrex'
    },
    {
      name: 'LinkedIn',
      link:'https://www.linkedin.com/in/jonathan-reasor-16966352'
    },
  //  {
    //   name: 'Devpost',
    //   link:'http://devpost.com/jbreasor'
    // },
    {
      name: 'F.C.C.',
      link:'http://www.freecodecamp.com/abraxasrex'
    },
    {
      name:'Codepen',
      link:'http://codepen.io/jbreasor/'
    },
    {
      name:'Codecademy',
      link:'https://www.codecademy.com/davidbowie89'
    },
    {
      name:'Wordpress',
      link:'https://mindbodyscissors.wordpress.com/2015/10/19/meteor-js-through-the-lens-of-a-junior-dev/'
    },
    {
      name:'StackOverFlow',
      link:'http://stackoverflow.com/users/5258815/jonathan-reasor'
    },
    {
      name:'NPM',
      link:'https://www.npmjs.com/~abraxasrex'
    }
  ]};

var tag_colors = {
  'mocha':'PaleGreen',
  'chai':'Peachpuff',
  'hackathon': 'Khaki',
  'google APIs': 'LightSalmon',
  'bootstrap': 'Indigo',
  'typescript':'Orange',
  'material UI': 'Green',
  'express.js':'MediumSlateblue',
  'webpack':'MediumSlateblue',
  'MEAN stack': 'Plum',
  'express.js':'MediumSlateBlue',
  'node.js': 'GreenYellow',
  'meteor.js': 'MediumAquamarine',
  'FreeCodeCamp': 'LightSteelBlue',
  'd3.js': 'Goldenrod',
  'audio programming': 'FloralWhite',
  'angular.js': 'Silver',
  'foursquare API': 'Tomato',
  'Passport': 'LightSeaGreen',
  'React': 'GreenYellow',
  'Three.js' :'DarkOrange',
  'VR':'IndianRed',
  'consumer-facing':'PaleVioletRed'
}
<|endoftext|>


<commit_before>var app = {};

var Image = null;

document.addEventListener("DOMContentLoaded", function(event) {
	app.init();
});

app.init = function(){
	app.Messages.getSettings(function(settings){
		app.settings = settings;
		app.Messages.getNodeByID(new URL(window.location).searchParams.get('id'), function(node){
			app.node = node;
			Title.value = node.title;
			ImagePreview.style.backgroundRepeat = 'no-repeat';
			ImagePreview.style.backgroundSize = '100% 100%';
			switch(node.type){
				case app.GridNodes.GridNodeType.folder:
					Url.parentNode.parentNode.style.display = 'none';
					if(node.image) Image = node.image;
					else Image = app.settings.grid.folderIcon;
					ImagePreview.style.backgroundImage = 'url(' + Image + ')';
					break;
				case app.GridNodes.GridNodeType.bookmark:
					Url.value = node.url;
					Image = 'url(' + node.image + ')';
					ImagePreview.style.backgroundImage = Image;
					break;
			}

			ImageReset.onclick = function(){
				switch(node.type){
					case app.GridNodes.GridNodeType.folder:
						if(node.image){
							Image = node.image;
							ImagePreview.style.backgroundImage = 'url(' + Image + ')';
						} else {
							Image = null;
							ImagePreview.style.backgroundImage = app.settings.grid.folderIcon;
						}
						break;
					case app.GridNodes.GridNodeType.bookmark:
						Image = node.image;
						ImagePreview.style.backgroundImage = 'url(' + Image + ')';
						break;
				}
			};

			ImageFile.onclick = function(){
				this.value = null;
			}
			ImageFile.onchange = function(){
				var fileReader = new FileReader();
				fileReader.onload = function(e){
					Image = e.target.result;
					ImageFile.value = null;
					ImagePreview.style.backgroundImage = 'url(' + Image + ')';
				}
				fileReader.readAsDataURL(ImageFile.files[0]);
			}

		});
	});

	BtnOk.onclick = function(){
		BtnApply.onclick();
		window.frameElement.popup.close();
	}
	BtnApply.onclick = function(){
		switch(app.node.type){
			case app.GridNodes.GridNodeType.folder:
				app.Messages.updateNode(app.node.id, { title: Title.value, image: Image })
				break;
			case app.GridNodes.GridNodeType.bookmark:
				app.Messages.updateNode(app.node.id, { title: Title.value, url: Url.value, image: Image })
				break;
		}
	}
	BtnCancel.onclick = function(){
		window.frameElement.popup.close();
	}

	var tabButtons = Tabs.children[0].children[0].children[0];
	for(var i=0; i<tabButtons.children.length-1; i++){
		tabButtons.children[i].index = i;
		tabButtons.children[i].onclick = function(){
			for(var j=0; j<tabButtons.children.length-1; j++){
				if(j==this.index){
					tabButtons.children[j].className = 'TabButtonActive';
					Tabs.children[1].children[j].className = '';
				} else {
					tabButtons.children[j].className = 'TabButton';
					Tabs.children[1].children[j].className = 'hidden';
				}
			}
		}
	}

};

app.Messages = {};
app.Messages.Commands = {
	getSettings: 0,
	setSettings: 1,
	getNode: 2,
	getNodeByID: 3,
	updateNode: 4,
	setNodeIndex: 5,
	createBookmark: 6,
	createFolder: 7,
	deleteNode: 8,
	refreshNode: 9,
	capturePage: 10,
	settingsChanged: 100,
	gridNodesLoaded: 101
};
app.Messages.getSettings = function(callback){
	browser.runtime.sendMessage({ cmd: app.Messages.Commands.getSettings }).then(callback);
};
app.Messages.getNodeByID = function(id, callback){
	browser.runtime.sendMessage({ cmd: app.Messages.Commands.getNodeByID, id: id }).then(callback);
};
app.Messages.updateNode = function(id, value, callback){
	browser.runtime.sendMessage({ cmd: app.Messages.Commands.updateNode, id: id, value: value }).then(callback);
};

app.GridNodes = {};
app.GridNodes.GridNodeType = { // GridNodeType
	back: -1,
	empty: 0,
	folder: 1,
	bookmark: 2
}
<commit_msg>Bug: Custom image are not displayed in properties window<commit_after>var app = {};

var Image = null;

document.addEventListener("DOMContentLoaded", function(event) {
	app.init();
});

app.init = function(){
	app.Messages.getSettings(function(settings){
		app.settings = settings;
		app.Messages.getNodeByID(new URL(window.location).searchParams.get('id'), function(node){
			app.node = node;
			Title.value = node.title;
			ImagePreview.style.backgroundRepeat = 'no-repeat';
			ImagePreview.style.backgroundSize = '100% 100%';
			switch(node.type){
				case app.GridNodes.GridNodeType.folder:
					Url.parentNode.parentNode.style.display = 'none';
					if(node.image){
						if(node.image.indexOf('url(')>0) Image = node.image;
						else Image = 'url(' + node.image + ')';
					} else Image = app.settings.grid.folderIcon;

					ImagePreview.style.backgroundImage = Image;
					break;
				case app.GridNodes.GridNodeType.bookmark:
					Url.value = node.url;
					Image = 'url(' + node.image + ')';
					ImagePreview.style.backgroundImage = Image;
					break;
			}

			ImageReset.onclick = function(){
				switch(node.type){
					case app.GridNodes.GridNodeType.folder:
						if(node.image){
							Image = node.image;
							ImagePreview.style.backgroundImage = 'url(' + Image + ')';
						} else {
							Image = null;
							ImagePreview.style.backgroundImage = app.settings.grid.folderIcon;
						}
						break;
					case app.GridNodes.GridNodeType.bookmark:
						Image = node.image;
						ImagePreview.style.backgroundImage = 'url(' + Image + ')';
						break;
				}
			};

			ImageFile.onclick = function(){
				this.value = null;
			}
			ImageFile.onchange = function(){
				var fileReader = new FileReader();
				fileReader.onload = function(e){
					Image = e.target.result;
					ImageFile.value = null;
					ImagePreview.style.backgroundImage = 'url(' + Image + ')';
				}
				fileReader.readAsDataURL(ImageFile.files[0]);
			}

		});
	});

	BtnOk.onclick = function(){
		BtnApply.onclick();
		window.frameElement.popup.close();
	}
	BtnApply.onclick = function(){
		switch(app.node.type){
			case app.GridNodes.GridNodeType.folder:
				app.Messages.updateNode(app.node.id, { title: Title.value, image: Image })
				break;
			case app.GridNodes.GridNodeType.bookmark:
				app.Messages.updateNode(app.node.id, { title: Title.value, url: Url.value, image: Image })
				break;
		}
	}
	BtnCancel.onclick = function(){
		window.frameElement.popup.close();
	}

	var tabButtons = Tabs.children[0].children[0].children[0];
	for(var i=0; i<tabButtons.children.length-1; i++){
		tabButtons.children[i].index = i;
		tabButtons.children[i].onclick = function(){
			for(var j=0; j<tabButtons.children.length-1; j++){
				if(j==this.index){
					tabButtons.children[j].className = 'TabButtonActive';
					Tabs.children[1].children[j].className = '';
				} else {
					tabButtons.children[j].className = 'TabButton';
					Tabs.children[1].children[j].className = 'hidden';
				}
			}
		}
	}

};

app.Messages = {};
app.Messages.Commands = {
	getSettings: 0,
	setSettings: 1,
	getNode: 2,
	getNodeByID: 3,
	updateNode: 4,
	setNodeIndex: 5,
	createBookmark: 6,
	createFolder: 7,
	deleteNode: 8,
	refreshNode: 9,
	capturePage: 10,
	settingsChanged: 100,
	gridNodesLoaded: 101
};
app.Messages.getSettings = function(callback){
	browser.runtime.sendMessage({ cmd: app.Messages.Commands.getSettings }).then(callback);
};
app.Messages.getNodeByID = function(id, callback){
	browser.runtime.sendMessage({ cmd: app.Messages.Commands.getNodeByID, id: id }).then(callback);
};
app.Messages.updateNode = function(id, value, callback){
	browser.runtime.sendMessage({ cmd: app.Messages.Commands.updateNode, id: id, value: value }).then(callback);
};

app.GridNodes = {};
app.GridNodes.GridNodeType = { // GridNodeType
	back: -1,
	empty: 0,
	folder: 1,
	bookmark: 2
}
<|endoftext|>


<commit_before>if (!module.parent) {
  console.log("Please don't call me directly. I am just the main app's minion.");
  process.exit(1);
}

// Third-party libraries
var _ = require('underscore')
    ,CONF = require('config');

// Note: if you need to access smth in parent:
// var something = module.parent.exports.something

var mod_hello = module.exports;

mod_hello.root = function(req, res) {

  var name = req.param('name', 'irakli');

  var context = {
    site_title: "Node.js Bootstrap Demo Page"
    ,name: name
  }

  res.render('hello_index', context);

};
<commit_msg>better doc<commit_after>if (!module.parent) {
  console.log("Please don't call me directly. I am just the main app's minion.");
  process.exit(1);
}

// Third-party libraries
var _ = require('underscore')
    ,CONF = require('config');

// Note: if you need to access smth in parent:
// var something = module.parent.exports.something

var mod_hello = module.exports;

mod_hello.root = function(req, res) {

  var name = req.param('name', 'stranger');

  var context = {
    site_title: "Node.js Bootstrap Demo Page"
    ,name: name
  }

  res.render('hello_index', context);

};
<|endoftext|>


<commit_before>#!/usr/bin/env node
(function () {
  "use strict";

  var stdin = process.openStdin()
    , key = process.argv[2].split('.')
    , json = ''
    ;

  stdin.on('data', function (chunk) {
    json += chunk;
  });

  stdin.on('end', function () {
    var data = JSON.parse(json)
      ;

    key.some(function (k) {
      data = data[k];
      if (undefined === data || null === data) {
        return true;
      }
    });

    console.log(JSON.stringify(data));
  });
}());
<commit_msg>remove extra quotes<commit_after>#!/usr/bin/env node
(function () {
  "use strict";

  var stdin = process.openStdin()
    , key = process.argv[2].split('.')
    , json = ''
    ;

  stdin.on('data', function (chunk) {
    json += chunk;
  });

  stdin.on('end', function () {
    var data = JSON.parse(json)
      ;

    key.some(function (k) {
      data = data[k];
      if (undefined === data || null === data) {
        return true;
      }
    });

    console.log(data);
  });
}());
<|endoftext|>


<commit_before>//! MIT License, Topher Winward 2015.
//! https://github.com/Winwardo/js-builder-decorator

"use strict";

(function(){
    /**
     * Decorate any given object or class with builder functions
     */
    var BuilderDecorator = function(decorated_, options) {
        var decorated;
        if (decorated_ instanceof Function) {
            decorated = new decorated_();
        } else {
            decorated = decorated_;
        }

        console.log("decorated", decorated)

        // -----

        if (options == undefined) {
            options = {};
        }

        // -----

        var createSafeCopy = function(e) {
            var copy = Object.create(e);
            if (options.allFieldsMustBeSet === true) {
                for (var field in copy) {
                    copy[field] = null;
                }
            }
            return copy;
        }

        // -----

        function cloneObject(obj) {
            if (obj === null || typeof obj !== 'object') {
                return obj;
            }

            var temp = obj.constructor(); // give temp the original obj's constructor
            for (var key in obj) {
                temp[key] = cloneObject(obj[key]);
            }

            return temp;
        }

        // -----

        var builderObj = {}
        builderObj.__builderData = {}

        for (var x in decorated) {
            // var x = 'name'
            console.log("poo")
            console.log(x)
            console.log(x === 'name')

            builderObj[x] = function(a) {
                // var copy = JSON.parse(JSON.stringify(this));
                var copy = cloneObject(this);
                copy.__builderData[x] = a;
                console.log("this, copy")
                console.log(this);
                console.log(copy);
                // console.log(copy.name)
                return copy;
            }
        }

        // Create setters
        // for (var x in decorated) {
        //     console.log(x)
        //     builderObj[x] = function(a) {
        //         var copy = cloneObject(this);
        //         copy.__builderData[x]=a;
        //         console.log("this, copy")
        //         console.log(this);
        //         console.log(copy);
        //         return copy;
        //     }
        // }

        builderObj.build = function() {
            var that = this;

            var response = {}
            // var x = 'name';
            for (var x in decorated) {
                response[x] = function() { return that.__builderData[x]; }
            }

            return response

            // for (var x in )

        }

        // console.log("builderObj")
        // console.log(builderObj)
        return function() { return builderObj }
    };

    // NPM exports
    if(typeof module !== 'undefined') {
        module.exports = {BuilderDecorator: BuilderDecorator };
    }

    // Standard js exports
    if(typeof window !== 'undefined') {
        window.BuilderDecorator = BuilderDecorator;
    }
})();
<commit_msg>7 / 12<commit_after>//! MIT License, Topher Winward 2015.
//! https://github.com/Winwardo/js-builder-decorator

"use strict";

(function(){
    /**
     * Decorate any given object or class with builder functions
     */
    var BuilderDecorator = function(decorated_, options) {
        var decorated;
        if (decorated_ instanceof Function) {
            decorated = new decorated_();
        } else {
            decorated = decorated_;
        }

        // -----

        if (options == undefined) {
            options = {};
        }

        // -----

        var createSafeCopy = function(e) {
            var copy = Object.create(e);
            if (options.allFieldsMustBeSet === true) {
                for (var field in copy) {
                    copy[field] = null;
                }
            }
            return copy;
        }

        // -----

        function cloneObject(obj) {
            if (obj === null || typeof obj !== 'object') {
                return obj;
            }

            var temp = obj.constructor(); // give temp the original obj's constructor
            for (var key in obj) {
                temp[key] = cloneObject(obj[key]);
            }

            return temp;
        }

        // -----

        var builderObj = {}
        builderObj.__builderData = {}

        var makeSetter = function(fieldName) {
            return function(a) {
                var copy = cloneObject(this);
                copy.__builderData[fieldName] = a;
                console.log("this, copy")
                console.log(this);
                console.log(copy);
                return copy;
            }
        }

        var applySetters = function(builderObj__, decorated__) {
            for (var x in decorated__) {
                builderObj__[x] = makeSetter(x);
            }
        }

        applySetters(builderObj, decorated);

        builderObj.build = function() {
            var that = this;

            var response = {}

            var makeGetter = function(builderData, w) {
                return function() {
                    return builderData[w];
                }
            }

            for (var x in decorated) {
                // response[x] = function() { return that.__builderData[x]; }
                response[x] = makeGetter(that.__builderData, x)
            }

            // console.log("Building:")
            // console.log(response)

            return response
        }

        // console.log("builderObj")
        // console.log(builderObj)
        return function() { return builderObj }
    };

    // NPM exports
    if(typeof module !== 'undefined') {
        module.exports = {BuilderDecorator: BuilderDecorator };
    }

    // Standard js exports
    if(typeof window !== 'undefined') {
        window.BuilderDecorator = BuilderDecorator;
    }
})();
<|endoftext|>


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

var assert = require('assert'),
    vows = require('vows'),
    Step = require('step'),
    _ = require('underscore'),
    querystring = require('querystring'),
    http = require('http'),
    OAuth = require('oauth').OAuth,
    Browser = require('zombie'),
    httputil = require('./lib/http'),
    oauthutil = require('./lib/oauth'),
    setupApp = oauthutil.setupApp,
    newCredentials = oauthutil.newCredentials;

var ignore = function(err) {};

var suite = vows.describe('User stream API test');

// A batch for testing the read access to the API

suite.addBatch({
    'When we set up the app': {
        topic: function() {
            setupApp(this.callback);
        },
        teardown: function(app) {
            if (app && app.close) {
                app.close();
            }
        },
        'it works': function(err, app) {
            assert.ifError(err);
        },
        'and we get new credentials': {
            topic: function() {
                newCredentials("dora", "v4m0nos", this.callback);
            },
            'it works': function(err, cred) {
                assert.ifError(err);
                assert.isObject(cred);
                assert.isString(cred.consumer_key);
                assert.isString(cred.consumer_secret);
                assert.isString(cred.token);
                assert.isString(cred.token_secret);
            },
            'and we check the feed endpoint':
            httputil.endpoint('/api/user/dora/feed', ['GET', 'POST']),
            'and we check the inbox endpoint':
            httputil.endpoint('/api/user/dora/inbox', ['GET', 'POST']),
            'and we get the feed of a new user': {
                topic: function(cred) {
                    var cb = this.callback;
                    httputil.getJSON('http://localhost:4815/api/user/dora/feed', cred, function(err, feed, result) {
                        cb(err, feed);
                    });
                },
                'it works': function(err, feed) {
                    assert.ifError(err);
                },
                'it has the right members': function(err, feed) {
                    assert.include(feed, 'author');
                    assert.include(feed.author, 'id');
                    assert.include(feed.author, 'displayName');
                    assert.include(feed.author, 'objectType');
                    assert.include(feed, 'totalCount');
                    assert.include(feed, 'items');
                    assert.include(feed, 'displayName');
                    assert.include(feed, 'id');
                    assert.include(feed, 'objectTypes');
                    assert.include(feed.objectTypes, 'activity');
                },
                'it is empty': function(err, feed) {
                    assert.equal(feed.totalCount, 0);
                    assert.isEmpty(feed.items);
                },
                'and we get the inbox of a new user': {
                    topic: function(feed, cred) {
                        var cb = this.callback;
                        httputil.getJSON('http://localhost:4815/api/user/dora/inbox', cred, function(err, feed, result) {
                            cb(err, feed);
                        });
                    },
                    'it works': function(err, inbox) {
                        assert.ifError(err);
                    },
                    'it has the right members': function(err, inbox) {
                        assert.include(inbox, 'author');
                        assert.include(inbox.author, 'id');
                        assert.include(inbox.author, 'displayName');
                        assert.include(inbox.author, 'objectType');
                        assert.include(inbox, 'totalCount');
                        assert.include(inbox, 'items');
                        assert.include(inbox, 'displayName');
                        assert.include(inbox, 'id');
                        assert.include(inbox, 'objectTypes');
                        assert.include(inbox.objectTypes, 'activity');
                    },
                    'it is empty': function(err, inbox) {
                        assert.equal(inbox.totalCount, 0);
                        assert.isEmpty(inbox.items);
                    },
                    'and we post a new activity': {
                        topic: function(inbox, feed, cred) {
                            var cb = this.callback,
                                act = {
                                    verb: 'post',
                                    object: {
                                        objectType: 'note',
                                        content: 'Hello, world!'
                                    }
                                };
                            httputil.postJSON('http://localhost:4815/api/user/dora/feed', cred, act, function(err, feed, result) {
                                cb(err, feed);
                            });
                        },
                        'it works': function(err, act) {
                            assert.ifError(err);
                        },
                        'results look right': function(err, act) {
                            assert.isObject(act);
                            assert.include(act, 'id');
                            assert.isString(act.id);
                            assert.include(act, 'actor');
                            assert.isObject(act.actor);
                            assert.include(act.actor, 'id');
                            assert.isString(act.actor.id);
                            assert.include(act, 'verb');
                            assert.isString(act.verb);
                            assert.include(act, 'object');
                            assert.isObject(act.object);
                            assert.include(act.object, 'id');
                            assert.isString(act.object.id);
                            assert.include(act, 'published');
                            assert.isString(act.published);
                            assert.include(act, 'updated');
                            assert.isString(act.updated);
                        },
                        'and we read the feed': {
                            topic: function(act, inbox, feed, cred) {
                                var cb = this.callback;

                                httputil.getJSON('http://localhost:4815/api/user/dora/feed', cred, function(err, newf) {
                                    if (err) {
                                        cb(err);
                                    } else {
                                        cb(null, {act: act, feed: newf});
                                    }
                                });
                            },
                            'it works': function(err, res) {
                                assert.ifError(err);
                            },
                            'it has the right members': function(err, res) {
                                assert.isObject(res);
                                assert.include(res, 'feed');
                                var feed = res.feed;
                                assert.include(feed, 'author');
                                assert.include(feed.author, 'id');
                                assert.include(feed.author, 'displayName');
                                assert.include(feed.author, 'objectType');
                                assert.include(feed, 'totalCount');
                                assert.include(feed, 'items');
                                assert.include(feed, 'displayName');
                                assert.include(feed, 'id');
                                assert.include(feed, 'objectTypes');
                                assert.include(feed.objectTypes, 'activity');
                            },
                            'it has one object': function(err, res) {
                                assert.isObject(res);
                                assert.include(res, 'feed');
                                var feed = res.feed;
                                assert.equal(feed.totalCount, 1);
                                assert.lengthOf(feed.items, 1);
                            },
                            'it has our activity': function(err, res) {
                                assert.isObject(res);
                                assert.include(res, 'feed');
                                assert.include(res, 'act');
                                var feed = res.feed, act = res.act;
                                assert.equal(feed.items[0].id, act.id);
                            }
                        },
                        'and we read the inbox': {
                            topic: function(act, inbox, feed, cred) {
                                var cb = this.callback;
                                httputil.getJSON('http://localhost:4815/api/user/dora/inbox', cred, function(err, newb) {
                                    if (err) {
                                        cb(err);
                                    } else {
                                        cb(null, {act: act, inbox: newb});
                                    }
                                });
                            },
                            'it works': function(err, res) {
                                assert.ifError(err);
                            },
                            'it has the right members': function(err, res) {
                                assert.isObject(res);
                                assert.include(res, 'inbox');
                                var inbox = res.inbox;
                                assert.include(inbox, 'author');
                                assert.include(inbox.author, 'id');
                                assert.include(inbox.author, 'displayName');
                                assert.include(inbox.author, 'objectType');
                                assert.include(inbox, 'totalCount');
                                assert.include(inbox, 'items');
                                assert.include(inbox, 'displayName');
                                assert.include(inbox, 'id');
                                assert.include(inbox, 'objectTypes');
                                assert.include(inbox.objectTypes, 'activity');
                            },
                            'it has one item': function(err, res) {
                                assert.isObject(res);
                                assert.include(res, 'inbox');
                                var inbox = res.inbox;
                                assert.equal(inbox.totalCount, 1);
                                assert.lengthOf(inbox.items, 1);
                            },
                            'it has our activity': function(err, res) {
                                assert.isObject(res);
                                assert.include(res, 'inbox');
                                assert.include(res, 'act');
                                var inbox = res.inbox, act = res.act;
                                assert.equal(inbox.items[0].id, act.id);
                            }
                        }
                    }
                }
            }
        }
    }
});

suite['export'](module);<commit_msg>Some pathological activities<commit_after>// user-stream-api.js
//
// Test user streams
//
// Copyright 2012, StatusNet Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

var assert = require('assert'),
    vows = require('vows'),
    Step = require('step'),
    _ = require('underscore'),
    querystring = require('querystring'),
    http = require('http'),
    OAuth = require('oauth').OAuth,
    Browser = require('zombie'),
    httputil = require('./lib/http'),
    oauthutil = require('./lib/oauth'),
    setupApp = oauthutil.setupApp,
    newCredentials = oauthutil.newCredentials;

var ignore = function(err) {};

var suite = vows.describe('User stream API test');

// A batch for testing the read access to the API

suite.addBatch({
    'When we set up the app': {
        topic: function() {
            setupApp(this.callback);
        },
        teardown: function(app) {
            if (app && app.close) {
                app.close();
            }
        },
        'it works': function(err, app) {
            assert.ifError(err);
        },
        'and we get new credentials': {
            topic: function() {
                newCredentials("dora", "v4m0nos", this.callback);
            },
            'it works': function(err, cred) {
                assert.ifError(err);
                assert.isObject(cred);
                assert.isString(cred.consumer_key);
                assert.isString(cred.consumer_secret);
                assert.isString(cred.token);
                assert.isString(cred.token_secret);
            },
            'and we check the feed endpoint':
            httputil.endpoint('/api/user/dora/feed', ['GET', 'POST']),
            'and we check the inbox endpoint':
            httputil.endpoint('/api/user/dora/inbox', ['GET', 'POST']),
            'and we get the feed of a new user': {
                topic: function(cred) {
                    var cb = this.callback;
                    httputil.getJSON('http://localhost:4815/api/user/dora/feed', cred, function(err, feed, result) {
                        cb(err, feed);
                    });
                },
                'it works': function(err, feed) {
                    assert.ifError(err);
                },
                'it has the right members': function(err, feed) {
                    assert.include(feed, 'author');
                    assert.include(feed.author, 'id');
                    assert.include(feed.author, 'displayName');
                    assert.include(feed.author, 'objectType');
                    assert.include(feed, 'totalCount');
                    assert.include(feed, 'items');
                    assert.include(feed, 'displayName');
                    assert.include(feed, 'id');
                    assert.include(feed, 'objectTypes');
                    assert.include(feed.objectTypes, 'activity');
                },
                'it is empty': function(err, feed) {
                    assert.equal(feed.totalCount, 0);
                    assert.isEmpty(feed.items);
                },
                'and we get the inbox of a new user': {
                    topic: function(feed, cred) {
                        var cb = this.callback;
                        httputil.getJSON('http://localhost:4815/api/user/dora/inbox', cred, function(err, feed, result) {
                            cb(err, feed);
                        });
                    },
                    'it works': function(err, inbox) {
                        assert.ifError(err);
                    },
                    'it has the right members': function(err, inbox) {
                        assert.include(inbox, 'author');
                        assert.include(inbox.author, 'id');
                        assert.include(inbox.author, 'displayName');
                        assert.include(inbox.author, 'objectType');
                        assert.include(inbox, 'totalCount');
                        assert.include(inbox, 'items');
                        assert.include(inbox, 'displayName');
                        assert.include(inbox, 'id');
                        assert.include(inbox, 'objectTypes');
                        assert.include(inbox.objectTypes, 'activity');
                    },
                    'it is empty': function(err, inbox) {
                        assert.equal(inbox.totalCount, 0);
                        assert.isEmpty(inbox.items);
                    },
                    'and we post a new activity': {
                        topic: function(inbox, feed, cred) {
                            var cb = this.callback,
                                act = {
                                    verb: 'post',
                                    object: {
                                        objectType: 'note',
                                        content: 'Hello, world!'
                                    }
                                };
                            httputil.postJSON('http://localhost:4815/api/user/dora/feed', cred, act, function(err, feed, result) {
                                cb(err, feed);
                            });
                        },
                        'it works': function(err, act) {
                            assert.ifError(err);
                        },
                        'results look right': function(err, act) {
                            assert.isObject(act);
                            assert.include(act, 'id');
                            assert.isString(act.id);
                            assert.include(act, 'actor');
                            assert.isObject(act.actor);
                            assert.include(act.actor, 'id');
                            assert.isString(act.actor.id);
                            assert.include(act, 'verb');
                            assert.isString(act.verb);
                            assert.include(act, 'object');
                            assert.isObject(act.object);
                            assert.include(act.object, 'id');
                            assert.isString(act.object.id);
                            assert.include(act, 'published');
                            assert.isString(act.published);
                            assert.include(act, 'updated');
                            assert.isString(act.updated);
                        },
                        'and we read the feed': {
                            topic: function(act, inbox, feed, cred) {
                                var cb = this.callback;

                                httputil.getJSON('http://localhost:4815/api/user/dora/feed', cred, function(err, newf) {
                                    if (err) {
                                        cb(err);
                                    } else {
                                        cb(null, {act: act, feed: newf});
                                    }
                                });
                            },
                            'it works': function(err, res) {
                                assert.ifError(err);
                            },
                            'it has the right members': function(err, res) {
                                assert.isObject(res);
                                assert.include(res, 'feed');
                                var feed = res.feed;
                                assert.include(feed, 'author');
                                assert.include(feed.author, 'id');
                                assert.include(feed.author, 'displayName');
                                assert.include(feed.author, 'objectType');
                                assert.include(feed, 'totalCount');
                                assert.include(feed, 'items');
                                assert.include(feed, 'displayName');
                                assert.include(feed, 'id');
                                assert.include(feed, 'objectTypes');
                                assert.include(feed.objectTypes, 'activity');
                            },
                            'it has one object': function(err, res) {
                                assert.isObject(res);
                                assert.include(res, 'feed');
                                var feed = res.feed;
                                assert.equal(feed.totalCount, 1);
                                assert.lengthOf(feed.items, 1);
                            },
                            'it has our activity': function(err, res) {
                                assert.isObject(res);
                                assert.include(res, 'feed');
                                assert.include(res, 'act');
                                var feed = res.feed, act = res.act;
                                assert.equal(feed.items[0].id, act.id);
                            }
                        },
                        'and we read the inbox': {
                            topic: function(act, inbox, feed, cred) {
                                var cb = this.callback;
                                httputil.getJSON('http://localhost:4815/api/user/dora/inbox', cred, function(err, newb) {
                                    if (err) {
                                        cb(err);
                                    } else {
                                        cb(null, {act: act, inbox: newb});
                                    }
                                });
                            },
                            'it works': function(err, res) {
                                assert.ifError(err);
                            },
                            'it has the right members': function(err, res) {
                                assert.isObject(res);
                                assert.include(res, 'inbox');
                                var inbox = res.inbox;
                                assert.include(inbox, 'author');
                                assert.include(inbox.author, 'id');
                                assert.include(inbox.author, 'displayName');
                                assert.include(inbox.author, 'objectType');
                                assert.include(inbox, 'totalCount');
                                assert.include(inbox, 'items');
                                assert.include(inbox, 'displayName');
                                assert.include(inbox, 'id');
                                assert.include(inbox, 'objectTypes');
                                assert.include(inbox.objectTypes, 'activity');
                            },
                            'it has one item': function(err, res) {
                                assert.isObject(res);
                                assert.include(res, 'inbox');
                                var inbox = res.inbox;
                                assert.equal(inbox.totalCount, 1);
                                assert.lengthOf(inbox.items, 1);
                            },
                            'it has our activity': function(err, res) {
                                assert.isObject(res);
                                assert.include(res, 'inbox');
                                assert.include(res, 'act');
                                var inbox = res.inbox, act = res.act;
                                assert.equal(inbox.items[0].id, act.id);
                            }
                        }
                    }
                }
            }
        }
    }
});

// Test some "bad" kinds of activity

suite.addBatch({
    'When we set up the app': {
        topic: function() {
            setupApp(this.callback);
        },
        teardown: function(app) {
            if (app && app.close) {
                app.close();
            }
        },
        'it works': function(err, app) {
            assert.ifError(err);
        },
        'and we get new credentials': {
            topic: function(app) {
                newCredentials("diego", "rescue", this.callback);
            },
            'it works': function(err, cred) {
                assert.ifError(err);
                assert.isObject(cred);
                assert.isString(cred.consumer_key);
                assert.isString(cred.consumer_secret);
                assert.isString(cred.token);
                assert.isString(cred.token_secret);
            },
            "and we try to post a notice with a different actor": {
                topic: function(cred, app) {
                    var cb = this.callback,
                        act = {
                            actor: {
                                id: "urn:uuid:66822a4d-9f72-4168-8d5a-0b1319afeeb1",
                                displayName: "Not Diego"
                            },
                            verb: 'post',
                            object: {
                                objectType: 'note',
                                content: 'To the rescue!'
                            }
                        };
                    httputil.postJSON('http://localhost:4815/api/user/diego/feed', cred, act, function(err, feed, result) {
                        if (result.statusCode < 400 || result.statusCode >= 500) {
                            cb(new Error("Unexpected result"));
                        } else {
                            cb(null);
                        }
                    });
                },
                'it fails correctly': function(err) {
                    assert.ifError(err);
                }
            },
            "and we try to post a notice with no object": {
                topic: function(cred, app) {
                    var cb = this.callback,
                        act = {
                            verb: 'noop'
                        };
                    httputil.postJSON('http://localhost:4815/api/user/diego/feed', cred, act, function(err, feed, result) {
                        if (result.statusCode < 400 || result.statusCode >= 500) {
                            cb(new Error("Unexpected result"));
                        } else {
                            cb(null);
                        }
                    });
                },
                'it fails correctly': function(err) {
                    assert.ifError(err);
                }
            }
        }
    }
});

suite['export'](module);<|endoftext|>


<commit_before>var elixir = require('laravel-elixir');
require('babel-plugin-syntax-jsx');

elixir.config.js.browserify.transformers
    .find(transformer => transformer.name === 'babelify')
    .options.presets.push(
        'syntax-jsx'
    );
/*
 |--------------------------------------------------------------------------
 | Elixir Asset Management
 |--------------------------------------------------------------------------
 |
 | Elixir provides a clean, fluent API for defining some basic Gulp tasks
 | for your Laravel application. By default, we are compiling the Sass
 | file for our application, as well as publishing vendor resources.
 |
 */

elixir(function(mix) {
    mix.sass('app.scss')
        .babel('student-app.js')
        .version(['public/js/student-app.js', 'public/css/app.css']);
});<commit_msg>fix gulpfile<commit_after>var elixir = require('laravel-elixir');
require('babel-plugin-syntax-jsx');

/*
 |--------------------------------------------------------------------------
 | Elixir Asset Management
 |--------------------------------------------------------------------------
 |
 | Elixir provides a clean, fluent API for defining some basic Gulp tasks
 | for your Laravel application. By default, we are compiling the Sass
 | file for our application, as well as publishing vendor resources.
 |
 */

elixir(function(mix) {
    mix.sass('app.scss')
        .browserify('student-app.js')
        .version(['public/js/student-app.js', 'public/css/app.css']);
});<|endoftext|>


<commit_before>"use strict";

var fhreq = require("./utils/request");
var util = require("util");
var fs = require("fs");
var api = require("./api");
var apps = require("./apps");

var files = module.exports = {

  // Recursive function that converts the FH files data structure into a hash structure
  responseToFiles: function(files, file) {
    if (!file) return;

    if (file instanceof Array) {
      for (var i=0; i<file.length; i++) {
        responseToFiles(files, file[i]);
      }
    }

    if(file && file.type === 'folder') {
      responseToFiles(files, file.children);
    }

    if (file && file.type == 'file') {
      files["." + file.path] = file.guid;
    }
  },

  //Note: the appId provided here is the instance guid.
  //We need the widget id to do file operations.
  list: function(options, appId, cb) {
    var payload = {
        payload: {
          active: "true",
          app: appId
        },
        context:{}
      };

    api.doFileCall(options, "list", payload, "Error listing file: ", cb);
  },

  //Note: you don't need appId/widgId for reading a file, just the fileId
  //itself..
  read: function(options, fileId, cb) {
    var payload = {
      payload: {
        active: "true",
        guid: fileId
      },
      context: {}
    };
    api.doFileCall(options, "read", payload, "Error reading file: ", cb);
  },

  update: function(options, appId, fileId, file, cb) {
    //TODO: tidy this up
    if (typeof file==="string"){
      // If type is string, we're using fs to take contents from a filename
      fs.readFile(file, encoding='utf8', function(err, data) {
        if (err) {
          return cb(err, null);
        } else {
          var payload = {
            files: [{
              guid: fileId,
              contents: data
            }],
            appId: appId
          };

          api.doFileCall(options, "update", payload, "Error updating file: ", cb);
        }
      });
    } else {
      // If not, it's an object and should have a .fileContents
      if (file.fileContents){
        var payload = {
          files: [{
            guid: fileId,
            contents: file.fileContents
          }],
          appId: appId
        };

        api.doFileCall(options, "update", payload, "Error updating file: ", cb);
      } else {
        return cb(new Error("No file contents specified"), null);
      }
    }
  },

  create: function(options, appId, path, name, fileType, cb) {
    apps.read(options, appId, function (err, data) {
      if(err) return cb(err, null);

      var widgId = data.app.guid,
          payload = {
            widget: widgId,
            filePath: path,
            fileName: name,
            type:fileType
          };

      api.doFileCall(options, "create", payload, "Error creating file: ", cb);
    });
  },

  deleteFile: function(options, appId, fileId, path, name, type, cb) {
    apps.read(options, appId, function (err, data) {
      if(err) return cb(err, null);

      var payload = {
            type: type,
            guid: fileId,
            path: path,
            name: name,
            appId: widgId
          };

      api.doFileCall(options, "delete", payload, "Error deleting file: ", cb);
    });
  }

};

<commit_msg>updated files.js so 2 requests no longer have to be made to create or delete a file<commit_after>"use strict";

var fhreq = require("./utils/request");
var util = require("util");
var fs = require("fs");
var api = require("./api");
var apps = require("./apps");

var files = module.exports = {

  // Recursive function that converts the FH files data structure into a hash structure
  responseToFiles: function(files, file) {
    if (!file) return;

    if (file instanceof Array) {
      for (var i=0; i<file.length; i++) {
        responseToFiles(files, file[i]);
      }
    }

    if(file && file.type === 'folder') {
      responseToFiles(files, file.children);
    }

    if (file && file.type == 'file') {
      files["." + file.path] = file.guid;
    }
  },

  //Note: the appId provided here is the instance guid.
  //We need the widget id to do file operations.
  list: function(options, appId, cb) {
    var payload = {
        payload: {
          active: "true",
          app: appId
        },
        context:{}
      };

    api.doFileCall(options, "list", payload, "Error listing file: ", cb);
  },

  //Note: you don't need appId/widgId for reading a file, just the fileId
  //itself..
  read: function(options, fileId, cb) {
    var payload = {
      payload: {
        active: "true",
        guid: fileId
      },
      context: {}
    };
    api.doFileCall(options, "read", payload, "Error reading file: ", cb);
  },

  update: function(options, appId, fileId, file, cb) {
    //TODO: tidy this up
    if (typeof file==="string"){
      // If type is string, we're using fs to take contents from a filename
      fs.readFile(file, encoding='utf8', function(err, data) {
        if (err) {
          return cb(err, null);
        } else {
          var payload = {
            files: [{
              guid: fileId,
              contents: data
            }],
            appId: appId
          };

          api.doFileCall(options, "update", payload, "Error updating file: ", cb);
        }
      });
    } else {
      // If not, it's an object and should have a .fileContents
      if (file.fileContents){
        var payload = {
          files: [{
            guid: fileId,
            contents: file.fileContents
          }],
          appId: appId
        };

        api.doFileCall(options, "update", payload, "Error updating file: ", cb);
      } else {
        return cb(new Error("No file contents specified"), null);
      }
    }
  },

  create: function(options, appId, path, name, fileType, cb) {
    var payload = {
      app: appId,
      filePath: path,
      fileName: name,
      type:fileType
    };

    api.doFileCall(options, "create", payload, "Error creating file: ", cb);
  },

  deleteFile: function(options, appId, fileId, path, name, type, cb) {
    var payload = {
      type: type,
      guid: fileId,
      path: path,
      name: name,
      appId: appId
    };

    api.doFileCall(options, "delete", payload, "Error deleting file: ", cb);
  }

};

<|endoftext|>


<commit_before>'use strict';

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

exports.Cache = require('./cache');
exports.CacheStream = require('./cache_stream');
exports.camelCaseKeys = require('./camel_case_keys');
exports.Color = require('./color');
exports.createSha1Hash = hash.createSha1Hash;
exports.decodeURL = require('./decode_url');
exports.deepMerge = require('./deep_merge');
exports.encodeURL = require('./encode_url');
exports.escapeDiacritic = require('./escape_diacritic');
exports.escapeHTML = require('./escape_html');
exports.escapeRegExp = require('./escape_regexp');
exports.full_url_for = require('./full_url_for');
exports.gravatar = require('./gravatar');
exports.hash = hash.hash;
exports.HashStream = hash.HashStream;
exports.highlight = require('./highlight');
exports.htmlTag = require('./html_tag');
exports.isExternalLink = require('./is_external_link');
exports.Pattern = require('./pattern');
exports.Permalink = require('./permalink');
exports.prettyUrls = require('./pretty_urls');
exports.prismHighlight = require('./prism');
exports.relative_url = require('./relative_url');
exports.slugize = require('./slugize');
exports.spawn = require('./spawn');
exports.stripHTML = require('./strip_html');
exports.stripIndent = require('./strip_indent');
exports.tocObj = require('./toc_obj');
exports.truncate = require('./truncate');
exports.unescapeHTML = require('./unescape_html');
exports.url_for = require('./url_for');
exports.wordWrap = require('./word_wrap');
<commit_msg>refactor(hash): remove the export of HashStream (#285)<commit_after>'use strict';

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

exports.Cache = require('./cache');
exports.CacheStream = require('./cache_stream');
exports.camelCaseKeys = require('./camel_case_keys');
exports.Color = require('./color');
exports.createSha1Hash = hash.createSha1Hash;
exports.decodeURL = require('./decode_url');
exports.deepMerge = require('./deep_merge');
exports.encodeURL = require('./encode_url');
exports.escapeDiacritic = require('./escape_diacritic');
exports.escapeHTML = require('./escape_html');
exports.escapeRegExp = require('./escape_regexp');
exports.full_url_for = require('./full_url_for');
exports.gravatar = require('./gravatar');
exports.hash = hash.hash;
exports.highlight = require('./highlight');
exports.htmlTag = require('./html_tag');
exports.isExternalLink = require('./is_external_link');
exports.Pattern = require('./pattern');
exports.Permalink = require('./permalink');
exports.prettyUrls = require('./pretty_urls');
exports.prismHighlight = require('./prism');
exports.relative_url = require('./relative_url');
exports.slugize = require('./slugize');
exports.spawn = require('./spawn');
exports.stripHTML = require('./strip_html');
exports.stripIndent = require('./strip_indent');
exports.tocObj = require('./toc_obj');
exports.truncate = require('./truncate');
exports.unescapeHTML = require('./unescape_html');
exports.url_for = require('./url_for');
exports.wordWrap = require('./word_wrap');
<|endoftext|>