<commit_before>const qu = require('async/queue');
const moment = require('moment');
const _ = require('lodash');

const constants = require('../common/constants.js');
const ga = require('../common/ga.js');
const cache = require('../common/data-cache.js')();
const serviceUrl = `https://${constants.hostname}`;

const alarmPeriodMinutes = 12 * 60;
const alarmKey = 'macheteSync';
const entityIdKey = 'spEntityIds';
const sellerDomainKey = 'sellerDomains';
const lastVersionKey = 'lastVersion';

chrome.runtime.onInstalled.addListener(details => {
    const manifest = chrome.runtime.getManifest();
    if (details.reason == 'install') {
        chrome.tabs.create({ url: `${serviceUrl}/setup/postinstall` });
    }
    localStorage.setItem(lastVersionKey, manifest.version);
    setAlarm();
});

chrome.pageAction.onClicked.addListener(ga.mcatch(() => {
    chrome.tabs.create({ url: `${serviceUrl}/dashboard` });
}));

function messageListener(handler) {
    chrome.runtime.onMessage.addListener(messageHandler(handler));
    chrome.runtime.onMessageExternal.addListener(messageHandler(handler));
}

function messageHandler(handler) {
    return ga.mcatch((req, sender, sendResponse) => {
        console.log('Handling message:', req);
        if (sender.tab.incognito) {
            sendResponse({
                error: {
                    handled: true,
                    authError: 'incognito',
                    message: 'Machete cannot be used in incognito mode',
                }
            });
            return true;
        }

        async function f() {
            chrome.pageAction.show(sender.tab.id);
            ga.mga('event', 'background-message', req.action);
            const begin = performance.now();

            try {
                const data = await handler(req, sender);
                const response = { data };
                console.log('Success handling message:', req, "response", response);
                sendResponse(response);
            }
            catch (error) {
                if (handlePortDisconnected(error, req.action))
                    return;
                if (handleMessageTooLong(error, req.action))
                    return;

                const response = { status: error.message, error: ga.errorToObject(error) };
                const authError = handleServerErrors(error, req.action);
                if (authError) {
                    response.error.handled = true;
                    response.error.authError = authError;
                    console.warn(error);
                }
                else {
                    ga.merror(req, error);
                }

                try {
                    sendResponse(response);
                }
                catch (ex) {
                    handlePortDisconnected(ex, req.action);
                }
            }

            const end = performance.now();
            ga.mga('timing', 'Background Task', req.action, Math.round(end - begin));
        }
        f();

        return true;
    });
}

function getUser() {
    return ajax(`${serviceUrl}/api/user`, {
        method: 'GET',
        responseType: 'json'
    });
}

function startSession(req) {
    return dataGather(req);
}

function sayHello() {
    return { 'ok': true };
}

const lastSync = JSON.parse(localStorage.getItem('lastSync')) || {};
function hasSyncedToday(module) {
    if (lastSync[module]) {
        const moduleSync = moment(lastSync[module]);
        console.log('Last data sync for', module, 'at', moduleSync.format());
        return moment().isSame(moduleSync, 'day');
    }

    console.log('No recorded sync for', module);
    return false;
}

function setSyncTime(module, time) {
    lastSync[module] = time;
    localStorage.setItem('lastSync', JSON.stringify(lastSync));
}

const dataGather = cache.coMemo(async function(req) {
    console.log('Data sync start at', moment().format());

    // Store entityIds and domains for further use
    if (req.entityId) {
        setEntityId(req.entityId, { domain: req.domain });
    }
    else if (req.domain) {
        addSellerDomain(req.domain);
    }

    /* These requires MUST go here to avoid a circular require */
    const kdp = require('./kdp.js'); // eslint-disable-line global-require
    const sp = require('./sp.js'); // eslint-disable-line global-require

    const oldSync = Math.max(..._.values(lastSync));
    let newSync = 0;
    for (const mod of [sp, kdp]) {
        if (!mod.name) {
            console.error('looking at nameless module', mod);
            throw new Error('module has no name');
        }

        if (hasSyncedToday(mod.name))
            continue;

        try {
            console.log('Data sync', mod.name, 'start at', moment().format());
            await mod.dataGather(req);
            newSync = Date.now();
            setSyncTime(mod.name, newSync);
        }
        catch (ex) {
            if (!handleServerErrors(ex, 'dataGather:'+mod.name))
                ga.merror(ex);
        }
        console.log('Data sync', mod.name, 'finish at', moment().format());
    }

    cache.clear();

    console.log('Data sync finish at', moment().format());
    return Math.max(newSync, oldSync);
}, { maxAge: 6 * constants.timespan.hour });

function setEntityId(entityId, fields) {
    if (isUnset(entityId)) {
        throw new Error('Invalid arguments to setEntityId:' + JSON.stringify({ entityId, fields }));
    }

    const ids = JSON.parse(localStorage.getItem(entityIdKey)) || [];
    let existing = ids.find(x => x.entityId == entityId);
    if (existing) {
        Object.assign(existing, fields);
    }
    else {
        existing = Object.assign({ entityId }, fields);
        ids.push(existing);
    }
    localStorage.setItem(entityIdKey, JSON.stringify(ids));
    return existing;
}

function isUnset(str) {
    return !str || str == 'undefined' || str == 'null';
}

function getEntityIds() {
    const entityIds = JSON.parse(localStorage.getItem(entityIdKey)) || [];

    // Fix up entityIds to ensure that every one has a stored domain
    let ids = entityIds.map(item => {
        if (typeof item == 'string') {
            return { domain: 'advertising.amazon.com', entityId: item };
        }
        else if (!item.domain) {
            item.domain = 'advertising.amazon.com';
        }
        return item;
    });

    ids = _.uniqBy(ids, 'entityId').filter(x => !isUnset(x.domain) && !isUnset(x.entityId));
    ids.forEach(x => x.domain = x.domain.replace(/^ams\./, 'advertising.'));
    localStorage.setItem(entityIdKey, JSON.stringify(ids));

    return ids;
}

function addSellerDomain(domain) {
    if (!domain) {
        ga.merror("bad arguments to addSellerDomain:", JSON.stringify(domain));
        return;
    }

    const ids = JSON.parse(localStorage.getItem(sellerDomainKey)) || [];
    if (!ids.includes(domain)) {
        ids.push(domain);
        localStorage.setItem(sellerDomainKey, JSON.stringify(ids));
    }
}

function getSellerDomains() {
    return JSON.parse(localStorage.getItem(sellerDomainKey)) || [];
}

function setAlarm() {
    chrome.alarms.onAlarm.addListener(ga.mcatch(alarm => {
        if (alarm.name == alarmKey) {
            dataGather({}).catch(ga.merror);
        }
    }));
    return ga.mpromise(resolve => {
        chrome.alarms.get(alarmKey, alarm => {
            if (!alarm) {
                const when = Date.now() + 1000;
                chrome.alarms.create(alarmKey, {
                    when,
                    periodInMinutes: alarmPeriodMinutes,
                });
                console.log('set alarm ', alarmKey, 'for', moment(when).format());
                resolve(true);
            }
            resolve(false);
        });
    });
}

function handleServerErrors(ex, desc) {
    if (ex.url && ex.url.match(/machete-app.com/)) {
        if (ex.message.match(/^401/)) {
            ga.mga('event', 'error-handled', 'auth-error-401', desc);
            return 'notLoggedIn';
        }
        if (ex.message.match(/^402/)) {
            ga.mga('event', 'error-handled', 'auth-error-402', desc);
            return 'notAllowed';
        }
        if (ex.message.match(/^403/)) {
            ga.mga('event', 'error-handled', 'auth-error-403', desc);
            return 'notOwned';
        }
    }
    if (ex.message.match(/^401/)) {
        ga.mga('event', 'error-handled', 'network-error-401', desc);
        return 'amazonNotLoggedIn';
    }
    if (ex.message.match(/^404/)) {
        ga.mga('event', 'error-handled', 'network-error-404', desc);
        return 'notFound';
    }
    if (ex.message.match(/^50/)) {
        ga.mga('event', 'error-handled', 'server-error', desc);
        return 'serverError';
    }
    if (ex.message.match(/0 error/) || ex.message.match(/Failed to fetch/)) {
        ga.mga('event', 'error-handled', 'network-error-unknown', desc);
        return 'networkError';
    }
    return null;
}

function handlePortDisconnected(ex, desc) {
    if (ex.message.match(/disconnected port object/)) {
        ga.mga('event', 'error-handled', 'port-disconnected', desc);
        return true;
    }
    return false;
}

function handleMessageTooLong(ex, req) {
    if (ex.message.match(/exceeded maximum allowed length/)) {
        ga.merror(ex.message, req);
        return true;
    }
    return false;
}

async function ajax(url, opts) {
    const init = {
        method: opts.method,
        headers: new Headers(),
        mode: 'cors',
        credentials: 'include',
    };

    if (opts.queryData) {
        const q = new URLSearchParams();
        for (const key of Object.keys(opts.queryData)) {
            q.append(key, opts.queryData[key]);
        }
        url += '?' + q.toString();
    }

    if (opts.formData && opts.jsonData)
        throw new Error('Cannot set both formData and jsonData on ajax request');

    if (opts.formData) {
        init.body = new URLSearchParams();
        for (const key of Object.keys(opts.formData)) {
            init.body.append(key, opts.formData[key]);
        }
        init.headers.set('Content-Type', 'application/x-www-form-urlencoded');
    }
    else if (opts.jsonData) {
        init.body = JSON.stringify(opts.jsonData);
        init.headers.set('Content-Type', 'application/json');
    }

    const origStack = new Error().stack;
    try {
        const response = await window.fetch(url, init);
        if (!response.ok) {
            throw new Error(`${response.status} ${response.statusText}`);
        }
        if (response.redirected) {
            // this is USUALLY because we got redirected to a login page. In
            // this case we fake out a 401 so that calling code handles it
            // correctly.
            url += ` (redirected to ${response.url})`;
            throw new Error('401 Redirect');
        }

        if (response.status == 204)
            return null;

        const body = await response.text();
        if (opts.responseType == 'json') {
            if (!body.length)
                return {};
            return JSON.parse(body);
        }
        return body;
    }
    catch (ex) {
        ex.method = opts.method;
        ex.url = url;
        ex.origStack = origStack;
        throw ex;
    }
}

function parallelQueue(items, fn) {
    return new Promise((resolve, reject) => {
        const results = [];
        let error = null;
        const queue = qu((item, callback) => {
            fn(item).then(value => {
                results.push(value);
                callback(null, value);
            })
            .catch(ex => {
                ga.merror(ex);
                error = ex;
                callback();
            });
        }, 3);

        queue.drain = () => {
            if (error)
                reject(error);
            else
                resolve(results);
        };
        queue.error = reject; // shouldn't happen since we're swallowing errors until drain
        queue.push(Array.from(items));
    });
}

module.exports = {
    serviceUrl,
    messageListener,
    getUser: cache.coMemo(getUser, { maxAge: 2 * constants.timespan.minute }),
    sayHello,
    handleServerErrors,
    ajax,
    parallelQueue,
    cache,
    startSession,
    isUnset,
    setEntityId,
    getEntityIds,
    addSellerDomain,
    getSellerDomains,
    hasSyncedToday,
    setSyncTime,
};
<commit_msg>handle 403 errors as a variety of 401 error when coming from amazon<commit_after>const qu = require('async/queue');
const moment = require('moment');
const _ = require('lodash');

const constants = require('../common/constants.js');
const ga = require('../common/ga.js');
const cache = require('../common/data-cache.js')();
const serviceUrl = `https://${constants.hostname}`;

const alarmPeriodMinutes = 12 * 60;
const alarmKey = 'macheteSync';
const entityIdKey = 'spEntityIds';
const sellerDomainKey = 'sellerDomains';
const lastVersionKey = 'lastVersion';

chrome.runtime.onInstalled.addListener(details => {
    const manifest = chrome.runtime.getManifest();
    if (details.reason == 'install') {
        chrome.tabs.create({ url: `${serviceUrl}/setup/postinstall` });
    }
    localStorage.setItem(lastVersionKey, manifest.version);
    setAlarm();
});

chrome.pageAction.onClicked.addListener(ga.mcatch(() => {
    chrome.tabs.create({ url: `${serviceUrl}/dashboard` });
}));

function messageListener(handler) {
    chrome.runtime.onMessage.addListener(messageHandler(handler));
    chrome.runtime.onMessageExternal.addListener(messageHandler(handler));
}

function messageHandler(handler) {
    return ga.mcatch((req, sender, sendResponse) => {
        console.log('Handling message:', req);
        if (sender.tab.incognito) {
            sendResponse({
                error: {
                    handled: true,
                    authError: 'incognito',
                    message: 'Machete cannot be used in incognito mode',
                }
            });
            return true;
        }

        async function f() {
            chrome.pageAction.show(sender.tab.id);
            ga.mga('event', 'background-message', req.action);
            const begin = performance.now();

            try {
                const data = await handler(req, sender);
                const response = { data };
                console.log('Success handling message:', req, "response", response);
                sendResponse(response);
            }
            catch (error) {
                if (handlePortDisconnected(error, req.action))
                    return;
                if (handleMessageTooLong(error, req.action))
                    return;

                const response = { status: error.message, error: ga.errorToObject(error) };
                const authError = handleServerErrors(error, req.action);
                if (authError) {
                    response.error.handled = true;
                    response.error.authError = authError;
                    console.warn(error);
                }
                else {
                    ga.merror(req, error);
                }

                try {
                    sendResponse(response);
                }
                catch (ex) {
                    handlePortDisconnected(ex, req.action);
                }
            }

            const end = performance.now();
            ga.mga('timing', 'Background Task', req.action, Math.round(end - begin));
        }
        f();

        return true;
    });
}

function getUser() {
    return ajax(`${serviceUrl}/api/user`, {
        method: 'GET',
        responseType: 'json'
    });
}

function startSession(req) {
    return dataGather(req);
}

function sayHello() {
    return { 'ok': true };
}

const lastSync = JSON.parse(localStorage.getItem('lastSync')) || {};
function hasSyncedToday(module) {
    if (lastSync[module]) {
        const moduleSync = moment(lastSync[module]);
        console.log('Last data sync for', module, 'at', moduleSync.format());
        return moment().isSame(moduleSync, 'day');
    }

    console.log('No recorded sync for', module);
    return false;
}

function setSyncTime(module, time) {
    lastSync[module] = time;
    localStorage.setItem('lastSync', JSON.stringify(lastSync));
}

const dataGather = cache.coMemo(async function(req) {
    console.log('Data sync start at', moment().format());

    // Store entityIds and domains for further use
    if (req.entityId) {
        setEntityId(req.entityId, { domain: req.domain });
    }
    else if (req.domain) {
        addSellerDomain(req.domain);
    }

    /* These requires MUST go here to avoid a circular require */
    const kdp = require('./kdp.js'); // eslint-disable-line global-require
    const sp = require('./sp.js'); // eslint-disable-line global-require

    const oldSync = Math.max(..._.values(lastSync));
    let newSync = 0;
    for (const mod of [sp, kdp]) {
        if (!mod.name) {
            console.error('looking at nameless module', mod);
            throw new Error('module has no name');
        }

        if (hasSyncedToday(mod.name))
            continue;

        try {
            console.log('Data sync', mod.name, 'start at', moment().format());
            await mod.dataGather(req);
            newSync = Date.now();
            setSyncTime(mod.name, newSync);
        }
        catch (ex) {
            if (!handleServerErrors(ex, 'dataGather:'+mod.name))
                ga.merror(ex);
        }
        console.log('Data sync', mod.name, 'finish at', moment().format());
    }

    cache.clear();

    console.log('Data sync finish at', moment().format());
    return Math.max(newSync, oldSync);
}, { maxAge: 6 * constants.timespan.hour });

function setEntityId(entityId, fields) {
    if (isUnset(entityId)) {
        throw new Error('Invalid arguments to setEntityId:' + JSON.stringify({ entityId, fields }));
    }

    const ids = JSON.parse(localStorage.getItem(entityIdKey)) || [];
    let existing = ids.find(x => x.entityId == entityId);
    if (existing) {
        Object.assign(existing, fields);
    }
    else {
        existing = Object.assign({ entityId }, fields);
        ids.push(existing);
    }
    localStorage.setItem(entityIdKey, JSON.stringify(ids));
    return existing;
}

function isUnset(str) {
    return !str || str == 'undefined' || str == 'null';
}

function getEntityIds() {
    const entityIds = JSON.parse(localStorage.getItem(entityIdKey)) || [];

    // Fix up entityIds to ensure that every one has a stored domain
    let ids = entityIds.map(item => {
        if (typeof item == 'string') {
            return { domain: 'advertising.amazon.com', entityId: item };
        }
        else if (!item.domain) {
            item.domain = 'advertising.amazon.com';
        }
        return item;
    });

    ids = _.uniqBy(ids, 'entityId').filter(x => !isUnset(x.domain) && !isUnset(x.entityId));
    ids.forEach(x => x.domain = x.domain.replace(/^ams\./, 'advertising.'));
    localStorage.setItem(entityIdKey, JSON.stringify(ids));

    return ids;
}

function addSellerDomain(domain) {
    if (!domain) {
        ga.merror("bad arguments to addSellerDomain:", JSON.stringify(domain));
        return;
    }

    const ids = JSON.parse(localStorage.getItem(sellerDomainKey)) || [];
    if (!ids.includes(domain)) {
        ids.push(domain);
        localStorage.setItem(sellerDomainKey, JSON.stringify(ids));
    }
}

function getSellerDomains() {
    return JSON.parse(localStorage.getItem(sellerDomainKey)) || [];
}

function setAlarm() {
    chrome.alarms.onAlarm.addListener(ga.mcatch(alarm => {
        if (alarm.name == alarmKey) {
            dataGather({}).catch(ga.merror);
        }
    }));
    return ga.mpromise(resolve => {
        chrome.alarms.get(alarmKey, alarm => {
            if (!alarm) {
                const when = Date.now() + 1000;
                chrome.alarms.create(alarmKey, {
                    when,
                    periodInMinutes: alarmPeriodMinutes,
                });
                console.log('set alarm ', alarmKey, 'for', moment(when).format());
                resolve(true);
            }
            resolve(false);
        });
    });
}

function handleServerErrors(ex, desc) {
    if (ex.url && ex.url.match(/machete-app.com/)) {
        if (ex.message.match(/^401/)) {
            ga.mga('event', 'error-handled', 'auth-error-401', desc);
            return 'notLoggedIn';
        }
        if (ex.message.match(/^402/)) {
            ga.mga('event', 'error-handled', 'auth-error-402', desc);
            return 'notAllowed';
        }
        if (ex.message.match(/^403/)) {
            ga.mga('event', 'error-handled', 'auth-error-403', desc);
            return 'notOwned';
        }
    }
    if (ex.message.match(/^401/)) {
        ga.mga('event', 'error-handled', 'network-error-401', desc);
        return 'amazonNotLoggedIn';
    }
    if (ex.message.match(/^403/)) {
        ga.mga('event', 'error-handled', 'network-error-403', desc);
        return 'amazonNotLoggedIn';
    }
    if (ex.message.match(/^404/)) {
        ga.mga('event', 'error-handled', 'network-error-404', desc);
        return 'notFound';
    }
    if (ex.message.match(/^50/)) {
        ga.mga('event', 'error-handled', 'server-error', desc);
        return 'serverError';
    }
    if (ex.message.match(/0 error/) || ex.message.match(/Failed to fetch/)) {
        ga.mga('event', 'error-handled', 'network-error-unknown', desc);
        return 'networkError';
    }
    return null;
}

function handlePortDisconnected(ex, desc) {
    if (ex.message.match(/disconnected port object/)) {
        ga.mga('event', 'error-handled', 'port-disconnected', desc);
        return true;
    }
    return false;
}

function handleMessageTooLong(ex, req) {
    if (ex.message.match(/exceeded maximum allowed length/)) {
        ga.merror(ex.message, req);
        return true;
    }
    return false;
}

async function ajax(url, opts) {
    const init = {
        method: opts.method,
        headers: new Headers(),
        mode: 'cors',
        credentials: 'include',
    };

    if (opts.queryData) {
        const q = new URLSearchParams();
        for (const key of Object.keys(opts.queryData)) {
            q.append(key, opts.queryData[key]);
        }
        url += '?' + q.toString();
    }

    if (opts.formData && opts.jsonData)
        throw new Error('Cannot set both formData and jsonData on ajax request');

    if (opts.formData) {
        init.body = new URLSearchParams();
        for (const key of Object.keys(opts.formData)) {
            init.body.append(key, opts.formData[key]);
        }
        init.headers.set('Content-Type', 'application/x-www-form-urlencoded');
    }
    else if (opts.jsonData) {
        init.body = JSON.stringify(opts.jsonData);
        init.headers.set('Content-Type', 'application/json');
    }

    const origStack = new Error().stack;
    try {
        const response = await window.fetch(url, init);
        if (!response.ok) {
            throw new Error(`${response.status} ${response.statusText}`);
        }
        if (response.redirected) {
            // this is USUALLY because we got redirected to a login page. In
            // this case we fake out a 401 so that calling code handles it
            // correctly.
            url += ` (redirected to ${response.url})`;
            throw new Error('401 Redirect');
        }

        if (response.status == 204)
            return null;

        const body = await response.text();
        if (opts.responseType == 'json') {
            if (!body.length)
                return {};
            return JSON.parse(body);
        }
        return body;
    }
    catch (ex) {
        ex.method = opts.method;
        ex.url = url;
        ex.origStack = origStack;
        throw ex;
    }
}

function parallelQueue(items, fn) {
    return new Promise((resolve, reject) => {
        const results = [];
        let error = null;
        const queue = qu((item, callback) => {
            fn(item).then(value => {
                results.push(value);
                callback(null, value);
            })
            .catch(ex => {
                ga.merror(ex);
                error = ex;
                callback();
            });
        }, 3);

        queue.drain = () => {
            if (error)
                reject(error);
            else
                resolve(results);
        };
        queue.error = reject; // shouldn't happen since we're swallowing errors until drain
        queue.push(Array.from(items));
    });
}

module.exports = {
    serviceUrl,
    messageListener,
    getUser: cache.coMemo(getUser, { maxAge: 2 * constants.timespan.minute }),
    sayHello,
    handleServerErrors,
    ajax,
    parallelQueue,
    cache,
    startSession,
    isUnset,
    setEntityId,
    getEntityIds,
    addSellerDomain,
    getSellerDomains,
    hasSyncedToday,
    setSyncTime,
};
<|endoftext|>


<commit_before>adjectiveArray = [{name: "happy"},{name:"sad"},{name:"angry"},{name:"afraid"}];

if (Meteor.isClient) {
    Template.hello.greeting = function() {
        return "Welcome to johari.";
    };

    Template.hello.events({
        'click input': function() {
            // template data, if any, is available in 'this'
            if (typeof console !== 'undefined')
                console.log("You pressed the button");
        }
    });

    Template.adjectives.adjective = function() {
        return adjectiveArray;
    };

    Template.adjectives.events({
        'click li.adjective': function() {
            var prevAdjective = Session.get('selectedAdjective');
            var curAdjective = (prevAdjective == this.name) ? "" : this.name;
            Session.set('selectedAdjective', curAdjective);
        },
    });

    Template.adjectives.isSelected = function() {
        var selectedAdjective = Session.get('selectedAdjective');
        var curAdjective = this.name;
        if (selectedAdjective == curAdjective) {
            return 'selected';
        }
    };
}

if (Meteor.isServer) {
    Meteor.startup(function() {
        // code to run on server at startup
    });
}
<commit_msg>Switching our list from single-select to multi-select.  w00t!<commit_after>adjectiveArray = [{name: "happy"},{name:"sad"},{name:"angry"},{name:"afraid"}];

if (Meteor.isClient) {
    Template.hello.greeting = function() {
        return "Welcome to johari.";
    };

    Template.hello.events({
        'click input': function() {
            // template data, if any, is available in 'this'
            if (typeof console !== 'undefined')
                console.log("You pressed the button");
        }
    });

    Template.adjectives.adjective = function() {
        return adjectiveArray;
    };

    Template.adjectives.events({
        'click li.adjective': function() {
            var selectedAdjectives = Session.get('selectedAdjectives') || [];
            var newSelection = [];

            if (_.contains(selectedAdjectives, this.name)) {
                newSelection = _.without(selectedAdjectives, this.name);
            }
            else {
                newSelection = selectedAdjectives;
                newSelection.push(this.name);
            }

            Session.set('selectedAdjectives', newSelection);
        },
    });

    Template.adjectives.isSelected = function() {
        var selectedAdjectives = Session.get('selectedAdjectives');
        var curAdjective = this.name;
        if (_.contains(selectedAdjectives, this.name)) {
            return 'selected';
        }
    };
}

if (Meteor.isServer) {
    Meteor.startup(function() {
        // code to run on server at startup
    });
}
<|endoftext|>


<commit_before>adjectiveArray = [{name: "happy"},{name:"sad"},{name:"angry"},{name:"afraid"}];

Names = new Meteor.Collection("names");
Adjectives = new Meteor.Collection("adjectives");

if (Meteor.isClient) {
    Router.map(function () {
        this.route('create', {path: '/'});
        this.route('view', {path: 'my-johari/:_id'});
        this.route('submit', {path: '/:_id'});
        this.route('submitted');
    });

    Session.set("adjectiveButtonMonitor", 0);
    Session.set("username", "");

    Template.adjectives.adjective = function() {
        return adjectiveArray;
    };

    Template.adjectives.events({
        'click li.adjective': function() {
            var selectedAdjectives = Session.get('selectedAdjectives') || [];
            var newSelection = [];

            if (_.contains(selectedAdjectives, this.name)) {
                newSelection = _.without(selectedAdjectives, this.name);
            }
            else {
                newSelection = selectedAdjectives;
                newSelection.push(this.name);
            }

            Session.set('selectedAdjectives', newSelection);
        },
        'submit form': function(theEvent) {
            theEvent.preventDefault();
            Session.set("adjectiveButtonMonitor", 1); // toggle value
        }
    });

    Template.adjectives.isSelected = function() {
        var selectedAdjectives = Session.get('selectedAdjectives');
        var curAdjective = this.name;
        if (_.contains(selectedAdjectives, this.name)) {
            return 'selected';
        }
    };

    Template.adjectives.numSelected = function () {
        var selectedAdjectives = Session.get('selectedAdjectives') || [];
        return selectedAdjectives.length;
    };

    Template.adjectives.validSelection = function () {
        var selectedAdjectives = Session.get('selectedAdjectives') || [];
        return selectedAdjectives.length == 3;
    };

    Template.create.events({
        'blur .name': function(theEvent, theTemplate) {
            Session.set("username", theTemplate.find('.name').value);
        }
    })
    Template.create.respondToAdjectiveButton = function () {
        if (Session.get("adjectiveButtonMonitor") == 1) {
            Session.set("adjectiveButtonMonitor", 0);
            var username = Session.get("username");
            var adjectives = Session.get('selectedAdjectives') || [];
            Meteor.call("createUser", username, adjectives, function(error, result) {
                Router.go('view', {_id: result.guid});
            });
        }
        return null;
    };

    Template.makeGuids.events({
        'click input.generate-guid': function () {
            var newGUID = GPW.pronounceable(6);
            Session.set('guid', newGUID);
        }
    });

    Template.makeGuids.guid = function () {
        var curGUID = Session.get('guid') || "";
        return curGUID;
    };

    Template.view.curID = function () {
        return Router.current().params._id;
    };

    Template.submit.curID = function () {
        return Router.current().params._id;
    };
}

if (Meteor.isServer) {
    Meteor.startup(function() {
        // code to run on server at startup
    });

    Meteor.methods({
        'createUser': function(username, adjectives) {
            var newGUID = GPW.pronounceable(6);
            Names.insert({name: username, guid: newGUID});
            _(adjectives).forEach(function(adjective) {
                Adjectives.insert({guid: newGUID, self: true, adjective: adjective});
            });
            return {guid: newGUID};
        }
    });
}
<commit_msg>Remove unused code.<commit_after>adjectiveArray = [{name: "happy"},{name:"sad"},{name:"angry"},{name:"afraid"}];

Names = new Meteor.Collection("names");
Adjectives = new Meteor.Collection("adjectives");

if (Meteor.isClient) {
    Router.map(function () {
        this.route('create', {path: '/'});
        this.route('view', {path: 'my-johari/:_id'});
        this.route('submit', {path: '/:_id'});
        this.route('submitted');
    });

    Session.set("adjectiveButtonMonitor", 0);
    Session.set("username", "");

    Template.adjectives.adjective = function() {
        return adjectiveArray;
    };

    Template.adjectives.events({
        'click li.adjective': function() {
            var selectedAdjectives = Session.get('selectedAdjectives') || [];
            var newSelection = [];

            if (_.contains(selectedAdjectives, this.name)) {
                newSelection = _.without(selectedAdjectives, this.name);
            }
            else {
                newSelection = selectedAdjectives;
                newSelection.push(this.name);
            }

            Session.set('selectedAdjectives', newSelection);
        },
        'submit form': function(theEvent) {
            theEvent.preventDefault();
            Session.set("adjectiveButtonMonitor", 1); // toggle value
        }
    });

    Template.adjectives.isSelected = function() {
        var selectedAdjectives = Session.get('selectedAdjectives');
        var curAdjective = this.name;
        if (_.contains(selectedAdjectives, this.name)) {
            return 'selected';
        }
    };

    Template.adjectives.numSelected = function () {
        var selectedAdjectives = Session.get('selectedAdjectives') || [];
        return selectedAdjectives.length;
    };

    Template.adjectives.validSelection = function () {
        var selectedAdjectives = Session.get('selectedAdjectives') || [];
        return selectedAdjectives.length == 3;
    };

    Template.create.events({
        'blur .name': function(theEvent, theTemplate) {
            Session.set("username", theTemplate.find('.name').value);
        }
    });

    Template.create.respondToAdjectiveButton = function () {
        if (Session.get("adjectiveButtonMonitor") == 1) {
            Session.set("adjectiveButtonMonitor", 0);
            var username = Session.get("username");
            var adjectives = Session.get('selectedAdjectives') || [];
            Meteor.call("createUser", username, adjectives, function(error, result) {
                Router.go('view', {_id: result.guid});
            });
        }
        return null;
    };

    Template.view.curID = function () {
        return Router.current().params._id;
    };

    Template.submit.curID = function () {
        return Router.current().params._id;
    };
}

if (Meteor.isServer) {
    Meteor.startup(function() {
        // code to run on server at startup
    });

    Meteor.methods({
        'createUser': function(username, adjectives) {
            var newGUID = GPW.pronounceable(6);
            Names.insert({name: username, guid: newGUID});
            _(adjectives).forEach(function(adjective) {
                Adjectives.insert({guid: newGUID, self: true, adjective: adjective});
            });
            return {guid: newGUID};
        }
    });
}
<|endoftext|>


<commit_before>
(function (root) {

  function _(parent, selector) {
    if( typeof parent === 'string' ) return document.querySelector(parent);
    return parent.querySelector(selector);
  }

  function $$(parent, selector) {
    if( typeof parent === 'string' ) return document.querySelectorAll(parent);
    return parent.querySelectorAll(selector);
  }

  _.$ = $$;

  // events

  var on = function (el, eventName, handler, useCapture) {
    if( typeof el === 'string' ) {
      return document.documentElement.addEventListener(el, eventName, handler);
    }
    return el.addEventListener(eventName, handler, useCapture);
  };
  var off = function (el, eventName, handler, useCapture) {
    if( typeof el === 'string' ) {
      return document.documentElement.removeEventListener(el, eventName, handler);
    }
    return el.removeEventListener(eventName, handler, useCapture);
  };
  var trigger = document.createEvent ? function (element, eventName, data) {
    var event = document.createEvent('HTMLEvents');
    event.data = data;
    event.initEvent(eventName, true, true);
    element.dispatchEvent(event);
    return event;
  } : function (element, eventName, data) {
    var event = document.createEventObject();
    event.data = data;
    element.fireEvent('on' + eventName, event);
    return event;
  };

  _.on = on;
  _.off = off;
  _.trigger = trigger;

  // ready

  var readyListeners = [],
      initReady = function () {
        var listeners = readyListeners;
        readyListeners = undefined;
        [].forEach.call(listeners, function (cb) { cb(); });
        document.removeEventListener('DOMContentLoaded', initReady);
        window.removeEventListener('load', initReady);
      };

  document.addEventListener('DOMContentLoaded', initReady);
  window.addEventListener('load', initReady);

  function ready (callback) {
    if( callback instanceof Function ) {
      if( readyListeners ) {
        readyListeners.push(callback);
      } else {
        callback();
      }
    }
  }

  _.ready = ready;

  // classList manipulation

  var classListEnabled = 'classList' in document.documentElement;

  var classListHas = classListEnabled ? function (el, className) {
        return el.classList.contains(className);
      } : function (el, className) {
        return new RegExp('\\b' + (className || '') + '\\b','').test(el.className);
      },
      classListAdd = classListEnabled ? function (el, className) {
        el.classList.add(className);
      } : function (el, className) {
        if( !classListHas(el, className) ) el.className += ' ' + className;
      },
      classListRemove = classListEnabled ? function (el, className) {
        el.classList.remove(className);
      } : function (el, className) {
        el.className = el.className.replace(new RegExp('\\s*' + className + '\\s*','g'), ' ');
      },
      classListToggle = classListEnabled ? (function () {
        var aux = document.createElement('span');
        aux.classList.toggle('test', true);
        aux.classList.toggle('test', true);

        // IE does not support second parameter toggle
        return aux.classList.contains('test') ? function (el, className, toggle) {
          el.classList.toggle(className, toggle);
        } : function (el, className, toggle) {
          toggle = toggle === undefined ? !el.classList.contains(className) : toggle;
          if( toggle ) el.classList.add(className);
          else el.classList.remove(className);
        };
      })() : function (el, className) {
        el.className = el.className.replace(new RegExp('\\s*' + className + '\\s*','g'), ' ');
      };

  _.classList = { has: classListHas, add: classListAdd, rm: classListRemove, toggle: classListToggle };

  _.hasClass = classListHas;
  _.addClass = classListAdd;
  _.removeClass = classListRemove;
  _.toggleClass = classListToggle;

  _.tmpClass = function (el, className, duration, cb) {
    var isCollection = !(el instanceof Element ) && el.length;

    if( isCollection ) {
      [].forEach.call(el, function (_el) {
        classListAdd(_el, className);
      });
    } else {
      classListAdd(el, className);
    }
    setTimeout(function () {
      if( isCollection ) {
        [].forEach.call(el, function (_el) {
          classListRemove(_el, className);
        });
      } else {
        classListRemove(el, className);
      }
      if( cb instanceof Function ) {
        cb();
      }
    }, duration instanceof Function ? duration() : duration );
  };

  // utils

  _.first = function (list, iteratee, thisArg) {
    for( var i = 0, n = list.length ; i < n ; i++ ) {
      if( iteratee.call(thisArg, list[i], i) ) return list[i];
    }
  };

  _.last = function (list, iteratee, thisArg) {
    for( var i = list.length - 1 ; i >= 0 ; i-- ) {
      if( iteratee.call(thisArg, list[i], i) ) return list[i];
    }
  };

  _.each = function (o, iteratee, thisArg) {
    if( o instanceof Array ) return o.forEach(iteratee, thisArg);
    for( var key in o ) {
      iteratee.call(thisArg, o[key], key);
    }
  };

  _.noop = function () {};
  _.noopValue = function (value) { return value; };

  _.once = function (fn) {
    var result;
    return function () {
      if( fn ) result = fn.apply(this, arguments);
      fn = null;
      return result;
    };
  };
  _.now = Date.now ? function () {
    return Date.now();
  } : function () {
    return new Date().getTime();
  };

  // ponyfills

  var matchmedia = root.matchMedia || root.webkitMatchMedia || root.mozMatchMedia || root.msMatchMedia;
  _.matchMedia = function (query) {
    return matchmedia(query);
  };

  _.matchesSelector = Element.prototype.matchesSelector ? function (el, selector) {
    return el.matchesSelector(selector);
  } : (function (matchesSelector) {
    return function (el, selector) {
      return el[matchesSelector](selector);
    };
  })( _.first([
    'matchesSelector',
    'webkitMatchesSelector',
    'mozMatchesSelector',
    'msMatchesSelector',
    'oMatchesSelector',
  ], function (matchesSelector) {
    return matchesSelector in Element.prototype;
  }) );

  function _getCurrentScript () {
    var scripts = document.getElementsByTagName('script');
    return scripts[scripts.length - 1];
  }

  Object.defineProperty(_, 'currentScript', {
    get: function () {
      return document.currentScript || _getCurrentScript();
    },
  });

  // dom nodes

  _.closest = Element.prototype.closest ? function (el, selector) {
    return el.closest(selector);
  } : function (el, selector) {
    while( el ) {
      if( _.matchesSelector(el, selector) ) {
        break;
      }
      el = el.parentElement;
    }
    return el;
  };

  function _createComplexEl (tag_name, attrs, children) {
    var classNames = [], id = null;

    tag_name = tag_name.replace(/\.([^#.]+)/g, function (_matched, _className) {
      classNames.push(_className);
      return '';
    }).replace(/\#([^#.]+)/g, function (_matched, _id) {
      id = _id;
      return '';
    });

    attrs = attrs || {};
    if( id ) attrs.id = id;
    if( classNames.length ) {
      attrs.className = (attrs.className ? attrs.className + ' ' : '') + classNames.join(' ');
    }

    return _.create(tag_name, attrs, children);
  }

  _.create = function (tag_name, attrs, children) {
    if( /[#.]/.test(tag_name) ) return _createComplexEl(tag_name, attrs, children);

    var el = document.createElement(tag_name);

    if( attrs ) {
      if( attrs.length ) children = attrs;
      else {
        for( var attr in attrs ) el[attr] = attrs[attr];
      }
    }

    if( typeof children === 'string' ) el.innerHTML = children;
    else if( children ) children.length ? _.each(children, function (child) {
      el.appendChild(child);
    }) : el.appendChild(children);

    return el;
  };

  _.append = function (el, node) {
    if( node === undefined ) return function (_el) { _el.appendChild(el); };
    el.appendChild(node);
    return _;
  };

  _.prepend = function (el, node) {
    if( node === undefined ) return function (_el) { _.prepend(_el, el); };
    if( !el.children.length ) el.appendChild(node);
    else el.insertBefore(node, el.firstElementChild || el.firstChild);
    return _;
  };

  _.remove = function (el) {
    var parent = el.parentElement || el.parentNode;
    if( parent ) parent.removeChild(el);
    return _;
  };

  _.formParams = function (form) {
    if( !(form instanceof Element) && form.length ) form = form[0];

    var data = {};
    [].forEach.call(form.elements, function (el) {
      if( el.name && !el.disabled ) {
        if( el.type === 'radio' ) {
          if( el.checked ) data[el.name] = el.value;
        } else {
          data[el.name] = el.value;
        }
      }
    });
    return data;
  };

  // scroll ponyfill

  function getScrollRoot () {
    var html = document.documentElement, body = document.body;

    if( html.scrollTop ) return html;
    if( body.scrollTop ) return body;

    var cacheTop = ((typeof window.pageYOffset !== 'undefined') ? window.pageYOffset : null) || body.scrollTop || html.scrollTop, // cache the window's current scroll position
        root;

    document.body.style.height = '200vh';
    document.documentElement.style.height = '200vh';

    html.scrollTop = body.scrollTop = cacheTop + (cacheTop > 0) ? -1 : 1;

    document.body.style.height = null;
    document.documentElement.style.height = null;

    // find root by checking which scrollTop has a value different than the cache.
    root = (html.scrollTop !== cacheTop) ? html : body;

    root.scrollTop = cacheTop; // restore the window's scroll position to cached value

    return root; // return the scrolling root element
  }

  var scrollRoot;

  Object.defineProperty(_, 'scrollTop', {
    get: function () {
      return scrollRoot.scrollTop;
    },
    set: function (value) {
      scrollRoot.scrollTop = value;
    }
  });

  ready(function () {
    scrollRoot = getScrollRoot();
  });

  if( typeof exports === 'object' && typeof module !== 'undefined' ) module.exports = _;
  else if( typeof root.define === 'function' && root.define.amd ) define([], function () { return _; });
  else { root._ = _; root.$$ = root.$$ || $$; }

})(this);
<commit_msg>closure lint tweaks<commit_after>
(function (root) {

  function _(parent, selector) {
    if( typeof parent === 'string' ) return document.querySelector(parent);
    return parent.querySelector(selector);
  }

  function $$(parent, selector) {
    if( typeof parent === 'string' ) return document.querySelectorAll(parent);
    return parent.querySelectorAll(selector);
  }

  _.$ = $$;

  // events

  var on = function (el, eventName, handler, useCapture) {
    if( typeof el === 'string' ) {
      return document.documentElement.addEventListener(el, eventName, handler);
    }
    return el.addEventListener(eventName, handler, useCapture);
  };
  var off = function (el, eventName, handler, useCapture) {
    if( typeof el === 'string' ) {
      return document.documentElement.removeEventListener(el, eventName, handler);
    }
    return el.removeEventListener(eventName, handler, useCapture);
  };
  var trigger = document.createEvent ? function (element, eventName, data) {
    var event = document.createEvent('HTMLEvents');
    event.data = data;
    event.initEvent(eventName, true, true);
    element.dispatchEvent(event);
    return event;
  } : function (element, eventName, data) {
    var event = document.createEventObject();
    event.data = data;
    element.fireEvent('on' + eventName, event);
    return event;
  };

  _.on = on;
  _.off = off;
  _.trigger = trigger;

  // ready

  var readyListeners = [],
      initReady = function () {
        var listeners = readyListeners;
        readyListeners = undefined;
        [].forEach.call(listeners, function (cb) { cb(); });
        document.removeEventListener('DOMContentLoaded', initReady);
        window.removeEventListener('load', initReady);
      };

  document.addEventListener('DOMContentLoaded', initReady);
  window.addEventListener('load', initReady);

  function ready (callback) {
    if( callback instanceof Function ) {
      if( readyListeners ) {
        readyListeners.push(callback);
      } else {
        callback();
      }
    }
  }

  _.ready = ready;

  // classList manipulation

  var classListEnabled = 'classList' in document.documentElement;

  var classListHas = classListEnabled ? function (el, className) {
        return el.classList.contains(className);
      } : function (el, className) {
        return new RegExp('\\b' + (className || '') + '\\b','').test(el.className);
      },
      classListAdd = classListEnabled ? function (el, className) {
        el.classList.add(className);
      } : function (el, className) {
        if( !classListHas(el, className) ) el.className += ' ' + className;
      },
      classListRemove = classListEnabled ? function (el, className) {
        el.classList.remove(className);
      } : function (el, className) {
        el.className = el.className.replace(new RegExp('\\s*' + className + '\\s*','g'), ' ');
      },
      classListToggle = classListEnabled ? (function () {
        var aux = document.createElement('span');
        aux.classList.toggle('test', true);
        aux.classList.toggle('test', true);

        // IE does not support second parameter toggle
        return aux.classList.contains('test') ? function (el, className, toggle) {
          el.classList.toggle(className, toggle);
        } : function (el, className, toggle) {
          toggle = toggle === undefined ? !el.classList.contains(className) : toggle;
          if( toggle ) el.classList.add(className);
          else el.classList.remove(className);
        };
      })() : function (el, className) {
        el.className = el.className.replace(new RegExp('\\s*' + className + '\\s*','g'), ' ');
      };

  _.classList = { has: classListHas, add: classListAdd, rm: classListRemove, toggle: classListToggle };

  _.hasClass = classListHas;
  _.addClass = classListAdd;
  _.removeClass = classListRemove;
  _.toggleClass = classListToggle;

  _.tmpClass = function (el, className, duration, cb) {
    var isCollection = !(el instanceof Element ) && el.length;

    if( isCollection ) {
      [].forEach.call(el, function (_el) {
        classListAdd(_el, className);
      });
    } else {
      classListAdd(el, className);
    }
    setTimeout(function () {
      if( isCollection ) {
        [].forEach.call(el, function (_el) {
          classListRemove(_el, className);
        });
      } else {
        classListRemove(el, className);
      }
      if( cb instanceof Function ) {
        cb();
      }
    }, duration instanceof Function ? duration() : duration );
  };

  // utils

  _.first = function (list, iteratee, thisArg) {
    for( var i = 0, n = list.length ; i < n ; i++ ) {
      if( iteratee.call(thisArg, list[i], i) ) return list[i];
    }
  };

  _.last = function (list, iteratee, thisArg) {
    for( var i = list.length - 1 ; i >= 0 ; i-- ) {
      if( iteratee.call(thisArg, list[i], i) ) return list[i];
    }
  };

  _.each = function (o, iteratee, thisArg) {
    if( o instanceof Array ) return o.forEach(iteratee, thisArg);
    for( var key in o ) {
      iteratee.call(thisArg, o[key], key);
    }
  };

  _.noop = function () {};
  _.noopValue = function (value) { return value; };

  _.once = function (fn) {
    var result;
    return function () {
      if( fn ) result = fn.apply(this, arguments);
      fn = null;
      return result;
    };
  };
  _.now = Date.now ? function () {
    return Date.now();
  } : function () {
    return new Date().getTime();
  };

  // ponyfills

  var matchmedia = root.matchMedia || root.webkitMatchMedia || root.mozMatchMedia || root.msMatchMedia;
  _.matchMedia = function (query) {
    return matchmedia(query);
  };

  _.matchesSelector = Element.prototype.matchesSelector ? function (el, selector) {
    return el.matchesSelector(selector);
  } : (function (matchesSelector) {
    return function (el, selector) {
      return el[matchesSelector](selector);
    };
  })( _.first([
    'matchesSelector',
    'webkitMatchesSelector',
    'mozMatchesSelector',
    'msMatchesSelector',
    'oMatchesSelector',
  ], function (matchesSelector) {
    return matchesSelector in Element.prototype;
  }) );

  function _getCurrentScript () {
    var scripts = document.getElementsByTagName('script');
    return scripts[scripts.length - 1];
  }

  Object.defineProperty(_, 'currentScript', {
    get: function () {
      return document.currentScript || _getCurrentScript();
    },
  });

  // dom nodes

  _.closest = Element.prototype.closest ? function (el, selector) {
    return el.closest(selector);
  } : function (el, selector) {
    while( el ) {
      if( _.matchesSelector(el, selector) ) {
        break;
      }
      el = el.parentElement;
    }
    return el;
  };

  function _createComplexEl (tag_name, attrs, children) {
    var classNames = [], id = null;

    tag_name = tag_name.replace(/\.([^#.]+)/g, function (_matched, _className) {
      classNames.push(_className);
      return '';
    }).replace(/\#([^#.]+)/g, function (_matched, _id) {
      id = _id;
      return '';
    });

    attrs = attrs || {};
    if( id ) attrs.id = id;
    if( classNames.length ) {
      attrs.className = (attrs.className ? attrs.className + ' ' : '') + classNames.join(' ');
    }

    return _.create(tag_name, attrs, children);
  }

  _.create = function (tag_name, attrs, children) {
    if( /[#.]/.test(tag_name) ) return _createComplexEl(tag_name, attrs, children);

    var el = document.createElement(tag_name);

    if( attrs ) {
      if( attrs.length ) children = attrs;
      else {
        for( var attr in attrs ) el[attr] = attrs[attr];
      }
    }

    if( typeof children === 'string' ) el.innerHTML = children;
    else if( children ) children.length ? _.each(children, function (child) {
      el.appendChild(child);
    }) : el.appendChild(children);

    return el;
  };

  _.append = function (el, node) {
    if( node === undefined ) return function (_el) { _el.appendChild(el); };
    el.appendChild(node);
    return _;
  };

  _.prepend = function (el, node) {
    if( node === undefined ) return function (_el) { _.prepend(_el, el); };
    if( !el.children.length ) el.appendChild(node);
    else el.insertBefore(node, el.firstElementChild || el.firstChild);
    return _;
  };

  _.remove = function (el) {
    var parent = el.parentElement || el.parentNode;
    if( parent ) parent.removeChild(el);
    return _;
  };

  _.formParams = function (form) {
    if( !(form instanceof Element) && form.length ) form = form[0];

    var data = {};
    [].forEach.call(form.elements, function (el) {
      if( el.name && !el.disabled ) {
        if( el.type === 'radio' ) {
          if( el.checked ) data[el.name] = el.value;
        } else {
          data[el.name] = el.value;
        }
      }
    });
    return data;
  };

  // scroll ponyfill

  function getScrollRoot () {
    var html = document.documentElement, body = document.body;

    if( html.scrollTop ) return html;
    if( body.scrollTop ) return body;

    var cacheTop = ((typeof window.pageYOffset !== 'undefined') ? window.pageYOffset : null) || body.scrollTop || html.scrollTop, // cache the window's current scroll position
        root;

    document.body.style.height = '200vh';
    document.documentElement.style.height = '200vh';

    html.scrollTop = body.scrollTop = cacheTop + (cacheTop > 0) ? -1 : 1;

    document.body.style.height = null;
    document.documentElement.style.height = null;

    // find root by checking which scrollTop has a value different than the cache.
    root = (html.scrollTop !== cacheTop) ? html : body;

    root.scrollTop = cacheTop; // restore the window's scroll position to cached value

    return root; // return the scrolling root element
  }

  var scrollRoot;

  Object.defineProperty(_, 'scrollTop', {
    get: function () {
      return scrollRoot.scrollTop;
    },
    set: function (value) {
      scrollRoot.scrollTop = value;
    }
  });

  ready(function () {
    scrollRoot = getScrollRoot();
  });

  if( typeof exports === 'object' && typeof module !== 'undefined' ) module.exports = _;
  else if( typeof root.define === 'function' && root.define.amd ) root.define([], function () { return _; });
  else { root._ = _; root.$$ = root.$$ || $$; }

})(this);
<|endoftext|>


<commit_before>import repromise from 'repromise';
import toStream from '../convert/to-stream';
import clone from 'safe-clone-deep';
import zlib from 'zlib';

export default function writeBuffer(...params){
  return repromise(()=>writeBufferPromise(...params));
}

function writeBufferPromise(svc,containerName,path,options,data) {
  //options are optional
  if (typeof data === 'undefined') {
    data = options;
    options = {};
  }

  //must have a value
  if (typeof data === 'undefined' || data === null) return Promise.reject(new Error('No data specified'));

  try {
    if (typeof data === 'string') return safeText()
    if (!(data instanceof Buffer)) return saveJson();
    return saveBinary();
  } catch(err) {
    return Promise.reject(err);
  }

  function saveText() {
    data = new Buffer(data);
    options.contentType = options.contentType || 'text/plain, charset=UTF-8';
    return saveBinary();
  }

  function saveJson() {
    data = new Buffer(JSON.stringify(clone(data)));
    options.contentType = options.contentType || 'application/json';
    return saveBinary();
  }

  function saveBinary() {
    return new Promise((resolve,reject)=>{
      svc.createBlockBlobFromStream(containerName,path,toStream(data),data.length,options,(err,result,response)=>{
        if (err) {
          err.detail = {response};
          return reject(err);
        }
        return resolve(result);
      });
    });
  }
}
<commit_msg>fix typo-bug, closes #1<commit_after>import repromise from 'repromise';
import toStream from '../convert/to-stream';
import clone from 'safe-clone-deep';
import zlib from 'zlib';

export default function writeBuffer(...params){
  return repromise(()=>writeBufferPromise(...params));
}

function writeBufferPromise(svc,containerName,path,options,data) {
  //options are optional
  if (typeof data === 'undefined') {
    data = options;
    options = {};
  }

  //must have a value
  if (typeof data === 'undefined' || data === null) return Promise.reject(new Error('No data specified'));

  try {
    if (typeof data === 'string') return saveText()
    if (!(data instanceof Buffer)) return saveJson();
    return saveBinary();
  } catch(err) {
    return Promise.reject(err);
  }

  function saveText() {
    data = new Buffer(data);
    options.contentType = options.contentType || 'text/plain, charset=UTF-8';
    return saveBinary();
  }

  function saveJson() {
    data = new Buffer(JSON.stringify(clone(data)));
    options.contentType = options.contentType || 'application/json';
    return saveBinary();
  }

  function saveBinary() {
    return new Promise((resolve,reject)=>{
      svc.createBlockBlobFromStream(containerName,path,toStream(data),data.length,options,(err,result,response)=>{
        if (err) {
          err.detail = {response};
          return reject(err);
        }
        return resolve(result);
      });
    });
  }
}
<|endoftext|>


<commit_before>function Npc(Character) {
    this.character = Character;
    this.vector = new Vector;
    this.arrowKeys = [38, 39, 40, 37];

    this.speed = 150; // == in milliseconds
    this.score = document.getElementById("npc-score");
    this.playing = null;
}

Npc.prototype.play = function() {
    var npc = this;

    npc.playing = setInterval(function() {
        npc.move();
        npc.character.painter.npcPaint();
        npc.updateScore();
    }, npc.speed);
};

Npc.prototype.move = function() {
    var direction = this.look(this.character.element);

    if (direction === false) {
        return this.teleport();
    }

    this.character.move.direction(direction);
};

Npc.prototype.look = function(element) {
    var numOfDirections = this.arrowKeys.length;
    var arrowKeys = Util.shuffleArray(this.arrowKeys);

    for(var i=0; i < numOfDirections; i++) {
        if (this.isPaintable(element, arrowKeys[i])) {
            return arrowKeys[i];
        }
    }

    return false;
};

Npc.prototype.isPaintable = function(currentLocationElement, direction) {
    var currentVector = new Vector(currentLocationElement);
    var newVector = this.getVector(currentVector, direction);

    if (newVector) {
        return this.character.painter.isPaintable(newVector, this);
    }

    return false;

};

Npc.prototype.getVector = function(currentVector, direction) {
    switch(direction) {
        case 38:
            return currentVector.north();
        case 39:
            return currentVector.east();
        case 40:
            return currentVector.south();
        case 37:
            return currentVector.west();
        default:
            return false;
    }
};

Npc.prototype.teleport = function() {
    var teleport = 4;
    var randomDirection = null;
    var npc = this;

    for(var i=0; i < teleport; i++) {
        randomDirection = Util.randomItem(npc.arrowKeys);
        npc.character.move.direction(randomDirection);
    }

    return true;
};

Npc.prototype.currentScore = function() {
    return document.getElementsByClassName("npc-painted").length;
};

Npc.prototype.updateScore = function() {
    this.score.innerHTML = this.currentScore();
};

Npc.prototype.stop = function() {
    clearInterval(this.playing);
};<commit_msg>Changed teleport to single random square move.<commit_after>function Npc(Character) {
    this.character = Character;
    this.vector = new Vector;
    this.arrowKeys = [38, 39, 40, 37];

    this.speed = 150; // == in milliseconds
    this.score = document.getElementById("npc-score");
    this.playing = null;
}

Npc.prototype.play = function() {
    var npc = this;

    npc.playing = setInterval(function() {
        npc.move();
        npc.character.painter.npcPaint();
        npc.updateScore();
    }, npc.speed);
};

Npc.prototype.move = function() {
    var direction = this.look(this.character.element);

    if (direction === false) {
        return this.moveRandom();
    }

    this.character.move.direction(direction);
};

Npc.prototype.look = function(element) {
    var numOfDirections = this.arrowKeys.length;
    var arrowKeys = Util.shuffleArray(this.arrowKeys);

    for(var i=0; i < numOfDirections; i++) {
        if (this.isPaintable(element, arrowKeys[i])) {
            return arrowKeys[i];
        }
    }

    return false;
};

Npc.prototype.isPaintable = function(currentLocationElement, direction) {
    var currentVector = new Vector(currentLocationElement);
    var newVector = this.getVector(currentVector, direction);

    if (newVector) {
        return this.character.painter.isPaintable(newVector, this);
    }

    return false;

};

Npc.prototype.getVector = function(currentVector, direction) {
    switch(direction) {
        case 38:
            return currentVector.north();
        case 39:
            return currentVector.east();
        case 40:
            return currentVector.south();
        case 37:
            return currentVector.west();
        default:
            return false;
    }
};

Npc.prototype.moveRandom = function() {
    var randomDirection = null;
    var npc = this;

    randomDirection = Util.randomItem(npc.arrowKeys);
    npc.character.move.direction(randomDirection);

    return true;
};

Npc.prototype.currentScore = function() {
    return document.getElementsByClassName("npc-painted").length;
};

Npc.prototype.updateScore = function() {
    this.score.innerHTML = this.currentScore();
};

Npc.prototype.stop = function() {
    clearInterval(this.playing);
};<|endoftext|>


<commit_before>"use strict";

var Freya = Freya || {};

Freya.get_popup = function (url) {

    // Ability to load popup via ajax url
    $.get(url).done(function (data, textStatus, jqXHR) {
        if (data) {
            var $popup = $(data.data_html);
            $('body').append($popup);
            window.rebind($popup);
            $popup.modal('show');
            $popup.on('hidden.bs.modal', function (event) {
                $popup.remove();
            });
            if (data.flash_html) {
                $alerts.append(data.flash_html);
            } else if (data.flash_html === '') {
                $alerts.html('');
            }
        }
    });
};

$(function () {

    var $alerts = $alerts || $('#alerts');

    var done_handler = function (data, textStatus, jqXHR, $initiator) {

        // Ability to replace any block on the page with any block from returned html
        var wrapper = null;
        if ($initiator) {
            if ($initiator.data('wrapper')) {
                wrapper = $initiator.data('wrapper');
            } else if ($initiator.is('form')) {
                wrapper = 'form';
            } else if ($initiator.is('button')) {
                wrapper = '.model-item';
            }
        } else if (data.settings && data.settings['wrapper']) {
            wrapper = data.settings['wrapper'];
        }
        else {
            wrapper = 'body';
        }

        if (data) {
            if (data.redirect_url) {
                if (data.redirect_url == document.URL) {
                    location.reload();
                } else {
                    window.location.href = data.redirect_url;
                }
            }
            if ((data.data_html || data.data_html === '') && wrapper) {
                var newData = $(data.data_html).find(wrapper).andSelf();
                if ($initiator) {
                    $initiator.closest(wrapper).replaceWith(newData);
                    window.rebind($initiator.closest(wrapper));
                } else {
                    $(wrapper).replaceWith(newData);
                    window.rebind($(wrapper));
                }
            }
            if (data.flash_html) {
                $alerts.html(data.flash_html);
            }
            if (data.settings) {
                window.rebind(wrapper, data.settings);
            }
        } else {
            console.log('Data from ajax request is empty')
        }
    };

    // API for BUTTON that updates content on page (using GET method)
    $(document.body).on('click', 'button[data-api="ajax.get"]', function (event) {
        event.preventDefault();
        var $button = $(this);
        var url = $button.attr('action');
        var confirm = $button.attr('data-confirm');

        function handle() {
            $.ajax({
                type: 'get',
                url: url,
                data: {'value': $button.val(), 'next': document.URL}
            })
            .done(function (data, textStatus, jqXHR) {
                done_handler(data, textStatus, jqXHR, $button);
            });
        }

        if (confirm) {
            bootbox.confirm(confirm, function (result) {
                if (result) {
                    handle();
                }
            });
        } else {
            handle();
        }
    });

    // API for BUTTON that updates model on page (card usual)
    $(document.body).on('click', 'button[data-api="ajax.update"]', function (event) {
        event.preventDefault();
        var $button = $(this);
        var url = $button.attr('action');
        var confirm = $button.attr('data-confirm');

        function handle() {
            if (csrftoken) {
                var setting = { beforeSend: function (xhr) {
                    xhr.setRequestHeader("X-CSRFToken", csrftoken)
                }}
            }
            $.ajax($.extend(setting, {
                type: 'post',
                url: url,
                data: {'value': $button.val(), 'next': document.URL}
            }))
            .done(function (data, textStatus, jqXHR) {
                done_handler(data, textStatus, jqXHR, $button);
            });
        }

        if (confirm) {
            bootbox.confirm(confirm, function (result) {
                if (result) {
                    handle();
                }
            });
        } else {
            handle();
        }
    });

    // API for FORM that works by ajax
    $(document.body).on('click', 'form[data-api="ajax.update"] input[type="submit"]', function (event) {
        event.preventDefault();
        var $form = $(this).closest('form[data-api="ajax.update"]');
        var formData = $form.serializeArray();

        formData.push({ name: this.name, value: this.value });
        formData.push({ name: 'next', value: document.URL });
        $.ajax({
            type: 'post',
            url: $form.attr('action'),
            data: formData
        })
        .done(function (data, textStatus, jqXHR) {
            done_handler(data, textStatus, jqXHR, $form);
        });
    });

    // POPUP - GET
    $(document.body).on('click', 'button[data-api="ajax.popup"]', function (event) {
        event.preventDefault();
        var $button = $(this);
        var url = $button.attr('action');
        Freya.get_popup(url);
    });

    // POPUP - FORM
    $(document.body).on('click', '.modal[data-api="ajax.popup"] form [type="submit"]', function (event) {
        event.preventDefault();

        var $button = $(this);
        var $form = $button.closest('form');
        var $popup = $form.closest('.modal[data-api="ajax.popup"]');
        var confirm = Boolean(Number($button.attr('confirm')));

        var url = $form.attr('action');
        var formData = $form.serializeArray();
        formData.push({ name: this.name, value: this.value });
        formData.push({ name: 'next', value: document.URL });
        $.post(url, formData).done(function (data, textStatus, jqXHR) {
            if (data) {
                if (data.redirect_url) {
                    if (data.redirect_url == document.URL) {
                        location.reload();
                    } else {
                        window.location.href = data.redirect_url;
                    }
                }
                if (data.settings && data.settings['closePopup']) {
                    $popup.modal('hide');
                    done_handler(data, textStatus, jqXHR, null);
                } else {
                    if (data.data_html) {
                        // To make update quicker and to not reinit popup
                        $popup.find('.modal-body').replaceWith($(data.data_html).find('.modal-body'));
                        window.rebind($popup);
                    }
                    if (data.flash_html) {
                        $alerts.append(data.flash_html);
                    } else if (data.flash_html === '') {
                        $alerts.html('');
                    }
                }
            }
        });
    });
});
<commit_msg>Update api.js sanitize_html<commit_after>"use strict";

var Freya = Freya || {};

// Get real width and height even for hidden element
Freya.getRealDimensions = function ($el, outer) {
  if ($el.length == 0) {
    return false;
  }
  var $clone = $el.clone()
    .show()
    .css("visibility","hidden")
    .appendTo("body");
  var result = {
    width:      (outer) ? $clone.outerWidth() : $clone.innerWidth(),
    height:     (outer) ? $clone.outerHeight() : $clone.innerHeight(),
    offsetTop:  $clone.offset().top,
    offsetLeft: $clone.offset().left
  };
  $clone.remove();
  return result;
};

// Clean MSWord tags
Freya.cleanWordHtml = function(input) {
    // 1. remove line breaks / Mso classes
    var stringStripper = /(\n|\r| class=(")?Mso[a-zA-Z]+(")?)/g;
    var output = input.replace(stringStripper, ' ');

    // 2. strip Word generated HTML comments
    var commentSripper = new RegExp('', 'g');
    var output = output.replace(commentSripper, '');

    // 3. remove
    var output = output.replace(/ /gi, '');
    return output;
};

Freya.removeAttributes = function (value) {
    var content = $('
').html(value);
    $(content).find('*').each(function(){
        $(this).removeAttributes();
    });
    return $(content)[0].outerHTML;
};

jQuery.fn.removeAttributes = function() {
    return this.each(function() {
        var attributes = $.map(this.attributes, function(item) {
            return item.name;
        });
        var tag = $(this);
        $.each(attributes, function(i, item) {
            if (item !== 'href'){
                tag.removeAttr(item);
            }
        });
    });
};

// Left only valid tags in the string
Freya.sanitize_html = function(value, allowedTags) {
    value = Freya.cleanWordHtml(value);
    value = Freya.removeAttributes(value);
    if (allowedTags.indexOf("br")) {
      allowedTags.push("br /");
      allowedTags.push("br/");
    }
    var tags = /<\/?([a-z][a-z0-9]*)\b[^>]*>/gi;
    return value.replace(tags, function($0, $1) {
        return allowedTags.indexOf($1.toLowerCase()) > -1 ? $0 : '';
    });
};

// Tests for sanitize_html
//var str, newstr;
//var allowedTags = ['em', 'p', 'ul', 'ol', 'li', 'br', 'a', 'span', 'div', 'strong'];
//
//str = 'Valid tags: em,
p
,

 ' +
//      'span
div
 strong ';
//newstr = Freya.sanitize_html(str, allowedTags);
//console.log('str:', str);
//console.log('new:', newstr);
//if (newstr == str) console.log('pass');
//else console.log('error');
//
//str = '

';
//newstr = Freya.sanitize_html(str, allowedTags);
//console.log('str:', str);
//console.log('new:', newstr);
//if (newstr == '

') console.log('pass');
//else console.log('error');
//
//str = 'Test links: Here is the link';
//newstr = Freya.sanitize_html(str, allowedTags);
//console.log('str:', str);
//console.log('new:', newstr);
//if (newstr == str) console.log('pass');
//else console.log('error');
//
//str = 'Test links with attr: Here is the link';
//newstr = Freya.sanitize_html(str, allowedTags);
//console.log('str:', str);
//console.log('new:', newstr);
//if (newstr != str) console.log('pass');
//else console.log('error');
//
//str = 'Images are not valid: ';
//newstr = Freya.sanitize_html(str, allowedTags);
//console.log('str:', str);
//console.log('new:', newstr);
//if (newstr != str) console.log('pass');
//else console.log('error');
//
//str = 'As well as js scripts and frames:  iframe';
//newstr = Freya.sanitize_html(str, allowedTags);
//console.log('str:', str);
//console.log('newstr:', newstr);
//newstr = Freya.sanitize_html(str, allowedTags);
//if (newstr != str) console.log('pass');
//else console.log('error');
<|endoftext|>


<commit_before>var deps = [
    'ui.router',
    'ngAnimate',
    'ngMaterial',
    'mdl',
    'ngIntercom',
    'ngStorage',
    'MinecraftlyAppControllers',
    'MinecraftlyAppServices'
];
angular.module("MinecraftlyAppControllers", []);
angular.module("MinecraftlyAppServices", []);
angular.module('MinecraftlyApp', deps)
        .run(function ($window) {
        })
        .config(function ($stateProvider, $locationProvider, $urlRouterProvider, IntercomProvider) {// $mdThemingProvider, $mdIconProvider,
            IntercomProvider.init('t02jhyr0');
//            $mdThemingProvider.theme('MinecraftlyTheme')
//                    .primaryPalette('blue')
//                    .accentPalette('purple')
//                    .warnPalette('deep-purple');
//            $mdThemingProvider.setDefaultTheme('MinecraftlyTheme');
//            $mdIconProvider
//                    .defaultIconSet('/img/mdi.svg');
//            $locationProvider.html5Mode(true);
            $stateProvider
                    .state('app', {
                        url: "",
                        abstract: true,
                        templateUrl: "templates/app.html",
                        controller: 'AppCtrl'
                    })
            .state('app.home', {
                        cache: false,
                        url: "",
                        views: {
                            'appContent': {
                                templateUrl: "templates/home.html",
                                controller: 'HomeCtrl'
                            }
                        }
                    })
			.state('app.play', {
                        cache: false,
                        url: "/play",
                        views: {
                            'appContent': {
                                templateUrl: "templates/play.html",
                                controller: 'HomeCtrl'
                            }
                        }
                    })
		    .state('app.features', {
                        cache: false,
                        url: "/features",
                        views: {
                            'appContent': {
                                templateUrl: "templates/features.html",
                                controller: 'HomeCtrl'
                            }
                        }
                    });
            $urlRouterProvider.otherwise('');
        });

<commit_msg>Yes, it works! Adding more pages now!<commit_after>var deps = [
    'ui.router',
    'ngAnimate',
    'ngMaterial',
    'mdl',
    'ngIntercom',
    'ngStorage',
    'MinecraftlyAppControllers',
    'MinecraftlyAppServices'
];
angular.module("MinecraftlyAppControllers", []);
angular.module("MinecraftlyAppServices", []);
angular.module('MinecraftlyApp', deps)
        .run(function ($window) {
        })
        .config(function ($stateProvider, $locationProvider, $urlRouterProvider, IntercomProvider) {// $mdThemingProvider, $mdIconProvider,
            IntercomProvider.init('t02jhyr0');
//            $mdThemingProvider.theme('MinecraftlyTheme')
//                    .primaryPalette('blue')
//                    .accentPalette('purple')
//                    .warnPalette('deep-purple');
//            $mdThemingProvider.setDefaultTheme('MinecraftlyTheme');
//            $mdIconProvider
//                    .defaultIconSet('/img/mdi.svg');
//            $locationProvider.html5Mode(true);
            $stateProvider
                    .state('app', {
                        url: "",
                        abstract: true,
                        templateUrl: "templates/app.html",
                        controller: 'AppCtrl'
                    })
            .state('app.home', {
                        cache: false,
                        url: "/",
                        views: {
                            'appContent': {
                                templateUrl: "templates/home.html",
                                controller: 'HomeCtrl'
                            }
                        }
                    })
			.state('app.play', {
                        cache: false,
                        url: "/play",
                        views: {
                            'appContent': {
                                templateUrl: "templates/play.html",
                                controller: 'HomeCtrl'
                            }
                        }
                    })
			.state('app.vote', {
                        cache: false,
                        url: "/vote",
                        views: {
                            'appContent': {
                                templateUrl: "templates/vote.html",
                                controller: 'HomeCtrl'
                            }
                        }
                    })
			.state('app.team', {
                        cache: false,
                        url: "/team",
                        views: {
                            'appContent': {
                                templateUrl: "templates/team.html",
                                controller: 'HomeCtrl'
                            }
                        }
                    })
			.state('app.about', {
                        cache: false,
                        url: "/about",
                        views: {
                            'appContent': {
                                templateUrl: "templates/about.html",
                                controller: 'HomeCtrl'
                            }
                        }
                    })
		    .state('app.features', {
                        cache: false,
                        url: "/features",
                        views: {
                            'appContent': {
                                templateUrl: "templates/features.html",
                                controller: 'HomeCtrl'
                            }
                        }
                    });
            $urlRouterProvider.otherwise('/');
        });

<|endoftext|>


<commit_before>var _ = require('../utility');
var urlparser = require('./url');

var defaults = {
  network: true,
  console: true,
  dom: true,
  location: true
};

function replace(obj, name, replacement, replacements) {
  var orig = obj[name];
  obj[name] = replacement(orig);
  if (replacements) {
    replacements.push([obj, name, orig]);
  }
}

function restore(replacements) {
  var b;
  while (replacements.length) {
    b = replacements.shift();
    b[0][b[1]] = b[2];
  }
}

function Instrumenter(options, telemeter, rollbar, _window, _document) {
  var autoInstrument = options.autoInstrument;
  if (autoInstrument === false) {
    return;
  }
  if (!_.isType(autoInstrument, 'object')) {
    autoInstrument = defaults;
  }
  this.autoInstrument = _.extend(true, {}, defaults, autoInstrument);
  this.telemeter = telemeter;
  this.rollbar = rollbar;
  this._window = _window || {};
  this._document = _document || {};

  this._location = this._window.location;
  this._lastHref = this._location && this._location.href;
}

Instrumenter.prototype.instrument = function() {
  if (this.autoInstrument.network) {
    this.instrumentNetwork();
  }

  if (this.autoInstrument.console) {
    this.instrumentConsole();
  }

  if (this.autoInstrument.dom) {
    this.instrumentDom();
  }

  if (this.autoInstrument.location) {
    this.instrumentLocation();
  }
};

Instrumenter.prototype.instrumentNetwork = function() {
  var self = this;

  function wrapProp(prop, xhr) {
    if (prop in xhr && _.isFunction(xhr[prop])) {
      replace(xhr, prop, function(orig) {
        return self.rollbar.wrap(orig);
      });
    }
  }

  if ('XMLHttpRequest' in this._window) {
    var xhrp = this._window.XMLHttpRequest.prototype;
    replace(xhrp, 'open', function(orig) {
      return function(method, url) {
        if (_.isType(url, 'string')) {
          this.__rollbar_xhr = {
            method: method,
            url: url,
            status_code: null
          };
        }
        return orig.apply(this, arguments);
      };
    });

    replace(xhrp, 'send', function(orig) {
      return function(data) {
        var xhr = this;

        function onreadystatechangeHandler() {
          if (xhr.__rollbar_xhr && (xhr.readyState === 1 || xhr.readyState === 4)) {
            try {
              xhr.__rollbar_xhr.status_code = xhr.status;
            } catch (e) { /* ignore possible exception from xhr.status */ }
            self.telemeter.captureNetwork(xhr.__rollbar_xhr, 'xhr');
          }
        }

        wrapProp('onload', xhr);
        wrapProp('onerror', xhr);
        wrapProp('onprogress', xhr);

        if ('onreadystatechange' in xhr && _.isFunction(xhr.onreadystatechange)) {
          replace(xhr, 'onreadystatechange', function(orig) {
            self.rollbar.wrap(orig, undefined, onreadystatechangeHandler);
          });
        } else {
          xhr.onreadystatechange = onreadystatechangeHandler;
        }
        return orig.apply(this, arguments);
      }
    });
  }

  if ('fetch' in this._window) {
    replace(this._window, 'fetch', function(orig) {
      return function(fn, t) {
        var args = new Array(arguments.length);
        for (var i=0, len=args.length; i < len; i++) {
          args[i] = arguments[i];
        }
        var input = args[0];
        var method = 'GET';
        var url;
        if (_.isType(input, 'string')) {
          url = input;
        } else {
          url = input.url;
          if (input.method) {
            method = input.method;
          }
        }
        if (args[1] && args[1].method) {
          method = args[1].method;
        }
        var metadata = {
          method: method,
          url: url,
          status_code: null
        };
        self.telemeter.captureNetwork(metadata, 'fetch');
        return orig.apply(this, args).then(function (resp) {
          metadata.status_code = resp.status;
          return resp;
        });
      };
    });
  }
};

Instrumenter.prototype.instrumentConsole = function() {
  if (!('console' in this._window && this._window.console.log)) {
    return;
  }

  var self = this;
  var c = this._window.console;

  function wrapConsole(method) {
    var orig = c[method];
    var origConsole = c;
    var level = method === 'warn' ? 'warning' : method;
    c[method] = function() {
      var args = Array.prototype.slice.call(arguments);
      var message = _.formatArgsAsString(args);
      self.telemeter.captureLog(message, level);
      if (orig) {
        Function.prototype.apply.call(orig, origConsole, args);
      }
    };
  }
  var methods = ['debug','info','warn','error','log'];
  for (var i=0, len=methods.length; i < len; i++) {
    wrapConsole(methods[i]);
  }
};

Instrumenter.prototype.instrumentDom = function() {
};

Instrumenter.prototype.instrumentLocation = function() {
  var chrome = this._window.chrome;
  var chromePackagedApp = chrome && chrome.app && chrome.app.runtime;
  // See https://github.com/angular/angular.js/pull/13945/files
  var hasPushState = !chromePackagedApp && this._window.history && this._window.history.pushState;
  if (!hasPushState) {
    return;
  }
  var self = this;
  var oldOnPopState = this._window.onpopstate;
  this._window.onpopstate = function() {
    var current = self._location.href;
    self.handleUrlChange(self._lastHref, current);
    if (oldOnPopState) {
      oldOnPopState.apply(this, arguments);
    }
  };

  replace(this._window.history, 'pushState', function(orig) {
    return function() {
      var url = arguments.length > 2 ? arguments[2] : undefined;
      if (url) {
        self.handleUrlChange(self._lastHref, url + '');
      }
      return orig.apply(this, arguments);
    };
  });
};

Instrumenter.prototype.handleUrlChange = function(from, to) {
  var parsedHref = urlparser.parse(this._location.href);
  var parsedTo = urlparser.parse(to);
  var parsedFrom = urlparser.parse(from);
  this._lastHref = to;
  if (parsedHref.protocol === parsedTo.protocol && parsedHref.host === parsedTo.host) {
    to = parsedTo.path + (parsedTo.hash || '');
  }
  if (parsedHref.protocol === parsedFrom.protocol && parsedHref.host === parsedFrom.host) {
    from = parsedFrom.path + (parsedFrom.hash || '');
  }
  this.telemeter.captureNavigation(from, to);
};

module.exports = Instrumenter;
<commit_msg>change console to log and location to navigation<commit_after>var _ = require('../utility');
var urlparser = require('./url');

var defaults = {
  network: true,
  log: true,
  dom: true,
  navigation: true
};

function replace(obj, name, replacement, replacements) {
  var orig = obj[name];
  obj[name] = replacement(orig);
  if (replacements) {
    replacements.push([obj, name, orig]);
  }
}

function restore(replacements) {
  var b;
  while (replacements.length) {
    b = replacements.shift();
    b[0][b[1]] = b[2];
  }
}

function Instrumenter(options, telemeter, rollbar, _window, _document) {
  var autoInstrument = options.autoInstrument;
  if (autoInstrument === false) {
    this.autoInstrument = {};
    return;
  }
  if (!_.isType(autoInstrument, 'object')) {
    autoInstrument = defaults;
  }
  this.autoInstrument = _.extend(true, {}, defaults, autoInstrument);
  this.telemeter = telemeter;
  this.rollbar = rollbar;
  this._window = _window || {};
  this._document = _document || {};

  this._location = this._window.location;
  this._lastHref = this._location && this._location.href;
}

Instrumenter.prototype.instrument = function() {
  if (this.autoInstrument.network) {
    this.instrumentNetwork();
  }

  if (this.autoInstrument.log) {
    this.instrumentConsole();
  }

  if (this.autoInstrument.dom) {
    this.instrumentDom();
  }

  if (this.autoInstrument.navigation) {
    this.instrumentNavigation();
  }
};

Instrumenter.prototype.instrumentNetwork = function() {
  var self = this;

  function wrapProp(prop, xhr) {
    if (prop in xhr && _.isFunction(xhr[prop])) {
      replace(xhr, prop, function(orig) {
        return self.rollbar.wrap(orig);
      });
    }
  }

  if ('XMLHttpRequest' in this._window) {
    var xhrp = this._window.XMLHttpRequest.prototype;
    replace(xhrp, 'open', function(orig) {
      return function(method, url) {
        if (_.isType(url, 'string')) {
          this.__rollbar_xhr = {
            method: method,
            url: url,
            status_code: null
          };
        }
        return orig.apply(this, arguments);
      };
    });

    replace(xhrp, 'send', function(orig) {
      return function(data) {
        var xhr = this;

        function onreadystatechangeHandler() {
          if (xhr.__rollbar_xhr && (xhr.readyState === 1 || xhr.readyState === 4)) {
            try {
              xhr.__rollbar_xhr.status_code = xhr.status;
            } catch (e) { /* ignore possible exception from xhr.status */ }
            self.telemeter.captureNetwork(xhr.__rollbar_xhr, 'xhr');
          }
        }

        wrapProp('onload', xhr);
        wrapProp('onerror', xhr);
        wrapProp('onprogress', xhr);

        if ('onreadystatechange' in xhr && _.isFunction(xhr.onreadystatechange)) {
          replace(xhr, 'onreadystatechange', function(orig) {
            self.rollbar.wrap(orig, undefined, onreadystatechangeHandler);
          });
        } else {
          xhr.onreadystatechange = onreadystatechangeHandler;
        }
        return orig.apply(this, arguments);
      }
    });
  }

  if ('fetch' in this._window) {
    replace(this._window, 'fetch', function(orig) {
      return function(fn, t) {
        var args = new Array(arguments.length);
        for (var i=0, len=args.length; i < len; i++) {
          args[i] = arguments[i];
        }
        var input = args[0];
        var method = 'GET';
        var url;
        if (_.isType(input, 'string')) {
          url = input;
        } else {
          url = input.url;
          if (input.method) {
            method = input.method;
          }
        }
        if (args[1] && args[1].method) {
          method = args[1].method;
        }
        var metadata = {
          method: method,
          url: url,
          status_code: null
        };
        self.telemeter.captureNetwork(metadata, 'fetch');
        return orig.apply(this, args).then(function (resp) {
          metadata.status_code = resp.status;
          return resp;
        });
      };
    });
  }
};

Instrumenter.prototype.instrumentConsole = function() {
  if (!('console' in this._window && this._window.console.log)) {
    return;
  }

  var self = this;
  var c = this._window.console;

  function wrapConsole(method) {
    var orig = c[method];
    var origConsole = c;
    var level = method === 'warn' ? 'warning' : method;
    c[method] = function() {
      var args = Array.prototype.slice.call(arguments);
      var message = _.formatArgsAsString(args);
      self.telemeter.captureLog(message, level);
      if (orig) {
        Function.prototype.apply.call(orig, origConsole, args);
      }
    };
  }
  var methods = ['debug','info','warn','error','log'];
  for (var i=0, len=methods.length; i < len; i++) {
    wrapConsole(methods[i]);
  }
};

Instrumenter.prototype.instrumentDom = function() {
};

Instrumenter.prototype.instrumentNavigation = function() {
  var chrome = this._window.chrome;
  var chromePackagedApp = chrome && chrome.app && chrome.app.runtime;
  // See https://github.com/angular/angular.js/pull/13945/files
  var hasPushState = !chromePackagedApp && this._window.history && this._window.history.pushState;
  if (!hasPushState) {
    return;
  }
  var self = this;
  var oldOnPopState = this._window.onpopstate;
  this._window.onpopstate = function() {
    var current = self._location.href;
    self.handleUrlChange(self._lastHref, current);
    if (oldOnPopState) {
      oldOnPopState.apply(this, arguments);
    }
  };

  replace(this._window.history, 'pushState', function(orig) {
    return function() {
      var url = arguments.length > 2 ? arguments[2] : undefined;
      if (url) {
        self.handleUrlChange(self._lastHref, url + '');
      }
      return orig.apply(this, arguments);
    };
  });
};

Instrumenter.prototype.handleUrlChange = function(from, to) {
  var parsedHref = urlparser.parse(this._location.href);
  var parsedTo = urlparser.parse(to);
  var parsedFrom = urlparser.parse(from);
  this._lastHref = to;
  if (parsedHref.protocol === parsedTo.protocol && parsedHref.host === parsedTo.host) {
    to = parsedTo.path + (parsedTo.hash || '');
  }
  if (parsedHref.protocol === parsedFrom.protocol && parsedHref.host === parsedFrom.host) {
    from = parsedFrom.path + (parsedFrom.hash || '');
  }
  this.telemeter.captureNavigation(from, to);
};

module.exports = Instrumenter;
<|endoftext|>