<commit_before>/* eslint-disable no-unused-vars */
const $ = require('jquery');
const _ = require('lodash');
const moment = require('frozen-moment');
const ga = require('./ga.js');
const common = require('./common.js');
const constants = require('./constants.js');

function getEntityId(href = window.location.toString()) {
    let entityId = getQueryArgs(href).entityId;
    if (entityId) {
        return entityId;
    }

    let navLink = $('.topNavLogo')[0];
    if (navLink) {
        let navHref = navLink.href;
        let query = navHref.substring(navHref.indexOf('?') + 1);
        entityId = getQueryArgs(query).entityId;
        if (entityId) {
            return entityId;
        }
    }

    throw new Error('could not discover entityId');
}

function stripPrefix(id) {
    if (!id)
        return id;
    if (!id.replace)
        return id;
    return id.replace(/^AX?/, '');
}

function getCampaignId(href = window.location.toString()) {
    let campaignId = getQueryArgs(href).campaignId;
    if (campaignId) {
        return stripPrefix(campaignId);
    }

    if (href) {
        const rawId = getUriPathChunk(href, 'campaigns');
        return stripPrefix(rawId);
    }

    campaignId = $('input[name=campaignId]').val();
    if (campaignId)
        return stripPrefix(campaignId);

    throw new Error('could not discover campaignId');
}

// take a uri like host.com/foo/1/ and extract the "1" given "foo"
function getUriPathChunk(href, chunk) {
    let path = href.split('?')[0];
    let parts = path.split('/');
    let nameIndex = parts.indexOf(chunk);
    if (nameIndex >= 0) {
        return parts[nameIndex + 1];
    }
    return null;
}

function getQueryArgs(str = window.location.toString()) {
    let qstring = str || window.location.toString();
    qstring = qstring.split('?').pop();
    if (qstring.includes('#')) {
        qstring = qstring.substring(0, qstring.lastIndexOf('#'));
    }

    let qs = qstring.split('&');
    let args = {};
    for (let q of qs) {
        let parts = q.split('=');
        args[parts[0]] = parts[1];
    }
    return args;
}

function getAdGroupIdFromDOM(dom) {
    const adGroupIdInput = dom.querySelector('input[name=adGroupId]');
    if (adGroupIdInput)
        return stripPrefix(adGroupIdInput.value);

    const sspaLink = dom.querySelector('.page-container nav li a');
    if (!sspaLink)
        return null;

    return stripPrefix(getUriPathChunk(sspaLink.href, 'ad-groups'));
}

function getCurrentCampaignSnapshot(entityId = getEntityId(), campaignId = getCampaignId()) {
    return getCampaignSummaries(entityId).then(summaries => {
        const summary = summaries.find(x => x.campaignId == campaignId);
        return summary.lifetimeData;
    });
}

function getCampaignHistory(entityId = getEntityId(), campaignId = getCampaignId()) {
    return common.bgMessage({
        action: 'sp.getDataHistory',
        entityId: entityId,
        campaignId: campaignId,
    });
}

function getAggregateCampaignHistory(entityId = getEntityId(), campaignIds) {
    return common.bgMessage({
        action: 'sp.getAggregateCampaignHistory',
        entityId,
        campaignIds,
    });
}

function getKeywordData(entityId = getEntityId(), campaignId = getCampaignId(), adGroupId) {
    return common.bgMessage({
        action: 'sp.getKeywordData',
        entityId,
        campaignId,
        adGroupId,
    });
}

function getAggregateKeywordData(entityId = getEntityId(), adGroupIds) {
    return common.bgMessage({
        action: 'sp.getAggregateKeywordData',
        entityId,
        adGroupIds
    });
}

let allowedPromise = null;
function getAllCampaignsAllowed(entityId = getEntityId()) {
    if (!allowedPromise) {
        allowedPromise = common.bgMessage({
            action: 'sp.getAllowedCampaigns',
            entityId
        });
    }
    return allowedPromise;
}

async function getCampaignAllowed(entityId = getEntityId(), campaignId = getCampaignId()) {
    try {
        const allowed = await getAllCampaignsAllowed(entityId);
        if (!allowed) {
            return false;
        }
        if (allowed[0] == '*') {
            return true;
        }
        return allowed.includes(campaignId);
    }
    catch (ex) {
        return false;
    }
}

let summaryPromise = null;
function getCampaignSummaries(entityId = getEntityId()) {
    if (!summaryPromise) {
        summaryPromise = common.bgMessage({
            action: 'sp.getCampaignSummaries',
            entityId: entityId,
        });
    }
    return summaryPromise;
}

async function getAllowedCampaignSummaries(entityId = getEntityId()) {
    const summaries = await getCampaignSummaries(entityId);
    const rv = [];
    for (const summary of summaries) {
        if (await getCampaignAllowed(entityId, summary.campaignId)) {
            rv.push(summary);
        }
    }
    return summaries;
}

async function getCampaignSummary(entityId = getEntityId(), campaignId = getCampaignId()) {
    const summaries = await getCampaignSummaries(entityId);
    return summaries.find(x => x.campaignId == campaignId);
}

function getKdpSalesHistory(asin) {
    return common.bgMessage({
        action: 'kdp.getSalesHistory',
        asin,
    });
}

function storeAdGroupMetadata(entityId, campaignId, adGroupId) {
    return common.bgMessage({
        action: 'sp.storeAdGroupMetadata',
        entityId,
        campaignId,
        adGroupId,
    });
}

function updateKeyword(keywords, operation, dataValues) {
    return common.bgMessage({
        action: 'sp.updateKeyword',
        entityId: getEntityId(),
        keywords,
        operation,
        dataValues,
    });
}

function updateKeywordStatus(enable, keywords) {
    let operation = enable ? "ENABLE" : "PAUSE";
    return updateKeyword(keywords, operation, {});
}

function updateKeywordBid(bid, keywords) {
    bid = parseFloat(bid).toFixed(2).toString();
    return updateKeyword(keywords, 'UPDATE', {bid});
}

function addKeywords(adGroupId, keywords, bid) {
    return common.bgMessage({
        action: 'sp.addKeywords',
        entityId: getEntityId(),
        adGroupId,
        keywords,
        bid,
    });
}

async function copyKeywordsToCampaigns(campaigns, keywords) {
    const rv = {
        ok: [],
        fail: []
    };
    for (const campaign of campaigns) {
        const result = await common.bgMessage({
            action: 'sp.addKeywords',
            entityId: getEntityId(),
            campaignId: campaign.campaignId,
            adGroupId: campaign.adGroupId,
            keywords: keywords,
        });
        rv.ok.push(...result.ok);
        rv.fail.push(...result.fail);
    }

    return rv;
}

function isRunning(campaignSummary) {
    return campaignSummary && ['RUNNING', 'OUT_OF_BUDGET', 'ENABLED', null].includes(campaignSummary.status || null);
}

function calculateKnpIncome(amsSales, kdpSales) {
    if (!kdpSales)
        return amsSales;

    return amsSales.map(item => {
        const itemDate = moment(item.timestamp).startOf('day').freeze();
        const salesWindow = salesWindowFilter(itemDate.subtract(15, 'days'), itemDate);
        const kdpWindow = kdpSales.filter(salesWindow);
        const amsWindow = amsSales.filter(salesWindow);
        const kdpSalesCount = kdpWindow.reduce((sum, item) => sum + item.paidEbook + item.paidPaperback, 0);
        const amsSalesCount = amsWindow.reduce((sum, item) => sum + (item.salesCount || 0), 0);
        const ratio = kdpSalesCount ? amsSalesCount / kdpSalesCount : 0;

        const rv = Object.assign({}, item);
        const kdpOnDate = kdpSales.find(x => moment(x.date).isSame(itemDate, 'day'));
        if (kdpOnDate) {
            const sales = item.salesValue || item.sales || 0; // salesValue for campaigns, sales for keywords
            rv.knpeCount = kdpOnDate.knp * ratio;
            rv.knpeValue = rv.knpeCount * 0.005;
            rv.knpeTotalValue = sales + rv.knpeValue;
            rv.knpeAcos = rv.knpeTotalSales ? 100 * (rv.spend / rv.knpeTotalSales) : null;
        }
        else {
            rv.knpeCount = null;
            rv.knpeValue = null;
            rv.knpeTotalValue = null;
            rv.knpeAcos = null;
        }

        return rv;
    });
}

function salesWindowFilter(startDate, endDate) {
    return item => {
        const date = moment(item.date || item.timestamp);
        return date.isSameOrBefore(endDate) && date.isAfter(startDate);
    };
}

let startSessionPromise = null;
function startSession() {
    if (!startSessionPromise) {
        startSessionPromise = common.bgMessage({
            action: 'startSession',
            entityId: getEntityId(),
        });
    }
    return startSessionPromise;
}

function amsPageInit() {
    common.getUser().then(ga.mcatch(user => {
        const desc = user.activeSubscription.name;
        let email = user.email;
        let profileText = "Your Profile";
        let label = 'view-profile';
        if (user.isAnon) {
            email = '';
            profileText = 'Login/Register';
            label = 'login';
        }
        let links = $('.userBarLinksRight');
        if (links[0]) {
            let chunks = links[0].innerHTML.split(' | ');
            chunks.splice(-1, 0, `${desc} (<a data-mclick="machete-status ${label}" title="${email}" href="https://${constants.hostname}/profile" target="_blank">${profileText}</a>)`);
            links[0].innerHTML = chunks.join(' | ');
        }
        let logout = links.find('a');
        if (logout[1]) {
            $(logout[1]).click(ga.mcatch(() => {
                const result = confirm(
                    `Logging out of AMS will prevent Machete from monitoring your campaigns. Instead, you may close this tab without logging out.

                    Continue logging out?`);
                return result;
            }));
        }

        let brandName = null;
        const brandNameDiv = $('#currentBrandName');
        if (brandNameDiv.length)
            brandName = brandNameDiv[0].innerText;
        if (!brandName) {
            const accountLink = $('.kdpUserBarLinksRight').find('a').first();
            if (accountLink.length)
                brandName = accountLink[0].innerText.replace('Hello ', '');
        }
        if (brandName) {
            common.bgMessage({
                action: 'sp.setBrandName',
                entityId: getEntityId(),
                brandName,
            }).catch(ga.mcatch);
        }
    }));
}

function requestKdpIntegration() {
    return common.bgMessage({ action: 'kdp.requestPermission' });
}

function hasKdpIntegration() {
    return common.bgMessage({ action: 'kdp.hasPermission' });
}

function campaignSelectOptions(campaigns) {
    let options = [
        { value: campaigns, label: 'All Campaigns' },
        { value: campaigns.filter(c => isRunning(c)), label: 'All Active Campaigns' }
    ];
    for (const asinGroup of Object.values(_.groupBy(campaigns, 'asin'))) {
        if (!asinGroup[0].asin)
            continue;
        options.push({ value: asinGroup, label: `All Campaigns For "${asinGroup[0].productTitle || '[unknown title]'}" (ASIN ${asinGroup[0].asin})`});
    }
    options = options.concat(...campaigns.filter(c => c.name).map(c => ({ value: [c], label: c.name })));

    return options;
}

module.exports = {
    amsPageInit,
    stripPrefix,
    getEntityId,
    getCampaignId,
    getQueryArgs,
    getAdGroupIdFromDOM,
    getCurrentCampaignSnapshot,
    getCampaignHistory,
    getAggregateCampaignHistory,
    getKeywordData,
    getAggregateKeywordData,
    getAllCampaignsAllowed,
    getCampaignAllowed,
    getCampaignSummaries,
    getAllowedCampaignSummaries,
    getCampaignSummary,
    getKdpSalesHistory,
    storeAdGroupMetadata,
    updateKeywordStatus,
    updateKeywordBid,
    addKeywords,
    copyKeywordsToCampaigns,
    isRunning,
    startSession,
    calculateKnpIncome,
    requestKdpIntegration,
    hasKdpIntegration,
    campaignSelectOptions,
};
<commit_msg>updated getAdGroupIdFromDOM in order to work on new pages<commit_after>/* eslint-disable no-unused-vars */
const $ = require('jquery');
const _ = require('lodash');
const moment = require('frozen-moment');
const ga = require('./ga.js');
const common = require('./common.js');
const constants = require('./constants.js');

function getEntityId(href = window.location.toString()) {
    let entityId = getQueryArgs(href).entityId;
    if (entityId) {
        return entityId;
    }

    let navLink = $('.topNavLogo')[0];
    if (navLink) {
        let navHref = navLink.href;
        let query = navHref.substring(navHref.indexOf('?') + 1);
        entityId = getQueryArgs(query).entityId;
        if (entityId) {
            return entityId;
        }
    }

    throw new Error('could not discover entityId');
}

function stripPrefix(id) {
    if (!id)
        return id;
    if (!id.replace)
        return id;
    return id.replace(/^AX?/, '');
}

function getCampaignId(href = window.location.toString()) {
    let campaignId = getQueryArgs(href).campaignId;
    if (campaignId) {
        return stripPrefix(campaignId);
    }

    if (href) {
        const rawId = getUriPathChunk(href, 'campaigns');
        return stripPrefix(rawId);
    }

    campaignId = $('input[name=campaignId]').val();
    if (campaignId)
        return stripPrefix(campaignId);

    throw new Error('could not discover campaignId');
}

// take a uri like host.com/foo/1/ and extract the "1" given "foo"
function getUriPathChunk(href, chunk) {
    let path = href.split('?')[0];
    let parts = path.split('/');
    let nameIndex = parts.indexOf(chunk);
    if (nameIndex >= 0) {
        return parts[nameIndex + 1];
    }
    return null;
}

function getQueryArgs(str = window.location.toString()) {
    let qstring = str || window.location.toString();
    qstring = qstring.split('?').pop();
    if (qstring.includes('#')) {
        qstring = qstring.substring(0, qstring.lastIndexOf('#'));
    }

    let qs = qstring.split('&');
    let args = {};
    for (let q of qs) {
        let parts = q.split('=');
        args[parts[0]] = parts[1];
    }
    return args;
}

function getAdGroupIdFromDOM(dom) {
    const adGroupIdInput = dom.querySelector('input[name=adGroupId]');
    if (adGroupIdInput)
        return stripPrefix(adGroupIdInput.value);

    const sspaLink = dom.querySelector('.page-container nav li a');
    if (sspaLink)
        return stripPrefix(getUriPathChunk(sspaLink.href, 'ad-groups'));

    const scripts = dom.querySelectorAll('script');
    for (const script of scripts) {
        const match = script.innerText.match(/adGroupId: *"(.*)"/);
        if (match) {
            return match[1];
        }
    }

    return null;
}

function getCurrentCampaignSnapshot(entityId = getEntityId(), campaignId = getCampaignId()) {
    return getCampaignSummaries(entityId).then(summaries => {
        const summary = summaries.find(x => x.campaignId == campaignId);
        return summary.lifetimeData;
    });
}

function getCampaignHistory(entityId = getEntityId(), campaignId = getCampaignId()) {
    return common.bgMessage({
        action: 'sp.getDataHistory',
        entityId: entityId,
        campaignId: campaignId,
    });
}

function getAggregateCampaignHistory(entityId = getEntityId(), campaignIds) {
    return common.bgMessage({
        action: 'sp.getAggregateCampaignHistory',
        entityId,
        campaignIds,
    });
}

function getKeywordData(entityId = getEntityId(), campaignId = getCampaignId(), adGroupId) {
    return common.bgMessage({
        action: 'sp.getKeywordData',
        entityId,
        campaignId,
        adGroupId,
    });
}

function getAggregateKeywordData(entityId = getEntityId(), adGroupIds) {
    return common.bgMessage({
        action: 'sp.getAggregateKeywordData',
        entityId,
        adGroupIds
    });
}

let allowedPromise = null;
function getAllCampaignsAllowed(entityId = getEntityId()) {
    if (!allowedPromise) {
        allowedPromise = common.bgMessage({
            action: 'sp.getAllowedCampaigns',
            entityId
        });
    }
    return allowedPromise;
}

async function getCampaignAllowed(entityId = getEntityId(), campaignId = getCampaignId()) {
    try {
        const allowed = await getAllCampaignsAllowed(entityId);
        if (!allowed) {
            return false;
        }
        if (allowed[0] == '*') {
            return true;
        }
        return allowed.includes(campaignId);
    }
    catch (ex) {
        return false;
    }
}

let summaryPromise = null;
function getCampaignSummaries(entityId = getEntityId()) {
    if (!summaryPromise) {
        summaryPromise = common.bgMessage({
            action: 'sp.getCampaignSummaries',
            entityId: entityId,
        });
    }
    return summaryPromise;
}

async function getAllowedCampaignSummaries(entityId = getEntityId()) {
    const summaries = await getCampaignSummaries(entityId);
    const rv = [];
    for (const summary of summaries) {
        if (await getCampaignAllowed(entityId, summary.campaignId)) {
            rv.push(summary);
        }
    }
    return summaries;
}

async function getCampaignSummary(entityId = getEntityId(), campaignId = getCampaignId()) {
    const summaries = await getCampaignSummaries(entityId);
    return summaries.find(x => x.campaignId == campaignId);
}

function getKdpSalesHistory(asin) {
    return common.bgMessage({
        action: 'kdp.getSalesHistory',
        asin,
    });
}

function storeAdGroupMetadata(entityId, campaignId, adGroupId) {
    return common.bgMessage({
        action: 'sp.storeAdGroupMetadata',
        entityId,
        campaignId,
        adGroupId,
    });
}

function updateKeyword(keywords, operation, dataValues) {
    return common.bgMessage({
        action: 'sp.updateKeyword',
        entityId: getEntityId(),
        keywords,
        operation,
        dataValues,
    });
}

function updateKeywordStatus(enable, keywords) {
    let operation = enable ? "ENABLE" : "PAUSE";
    return updateKeyword(keywords, operation, {});
}

function updateKeywordBid(bid, keywords) {
    bid = parseFloat(bid).toFixed(2).toString();
    return updateKeyword(keywords, 'UPDATE', {bid});
}

function addKeywords(adGroupId, keywords, bid) {
    return common.bgMessage({
        action: 'sp.addKeywords',
        entityId: getEntityId(),
        adGroupId,
        keywords,
        bid,
    });
}

async function copyKeywordsToCampaigns(campaigns, keywords) {
    const rv = {
        ok: [],
        fail: []
    };
    for (const campaign of campaigns) {
        const result = await common.bgMessage({
            action: 'sp.addKeywords',
            entityId: getEntityId(),
            campaignId: campaign.campaignId,
            adGroupId: campaign.adGroupId,
            keywords: keywords,
        });
        rv.ok.push(...result.ok);
        rv.fail.push(...result.fail);
    }

    return rv;
}

function isRunning(campaignSummary) {
    return campaignSummary && ['RUNNING', 'OUT_OF_BUDGET', 'ENABLED', null].includes(campaignSummary.status || null);
}

function calculateKnpIncome(amsSales, kdpSales) {
    if (!kdpSales)
        return amsSales;

    return amsSales.map(item => {
        const itemDate = moment(item.timestamp).startOf('day').freeze();
        const salesWindow = salesWindowFilter(itemDate.subtract(15, 'days'), itemDate);
        const kdpWindow = kdpSales.filter(salesWindow);
        const amsWindow = amsSales.filter(salesWindow);
        const kdpSalesCount = kdpWindow.reduce((sum, item) => sum + item.paidEbook + item.paidPaperback, 0);
        const amsSalesCount = amsWindow.reduce((sum, item) => sum + (item.salesCount || 0), 0);
        const ratio = kdpSalesCount ? amsSalesCount / kdpSalesCount : 0;

        const rv = Object.assign({}, item);
        const kdpOnDate = kdpSales.find(x => moment(x.date).isSame(itemDate, 'day'));
        if (kdpOnDate) {
            const sales = item.salesValue || item.sales || 0; // salesValue for campaigns, sales for keywords
            rv.knpeCount = kdpOnDate.knp * ratio;
            rv.knpeValue = rv.knpeCount * 0.005;
            rv.knpeTotalValue = sales + rv.knpeValue;
            rv.knpeAcos = rv.knpeTotalSales ? 100 * (rv.spend / rv.knpeTotalSales) : null;
        }
        else {
            rv.knpeCount = null;
            rv.knpeValue = null;
            rv.knpeTotalValue = null;
            rv.knpeAcos = null;
        }

        return rv;
    });
}

function salesWindowFilter(startDate, endDate) {
    return item => {
        const date = moment(item.date || item.timestamp);
        return date.isSameOrBefore(endDate) && date.isAfter(startDate);
    };
}

let startSessionPromise = null;
function startSession() {
    if (!startSessionPromise) {
        startSessionPromise = common.bgMessage({
            action: 'startSession',
            entityId: getEntityId(),
        });
    }
    return startSessionPromise;
}

function amsPageInit() {
    common.getUser().then(ga.mcatch(user => {
        const desc = user.activeSubscription.name;
        let email = user.email;
        let profileText = "Your Profile";
        let label = 'view-profile';
        if (user.isAnon) {
            email = '';
            profileText = 'Login/Register';
            label = 'login';
        }
        let links = $('.userBarLinksRight');
        if (links[0]) {
            let chunks = links[0].innerHTML.split(' | ');
            chunks.splice(-1, 0, `${desc} (<a data-mclick="machete-status ${label}" title="${email}" href="https://${constants.hostname}/profile" target="_blank">${profileText}</a>)`);
            links[0].innerHTML = chunks.join(' | ');
        }
        let logout = links.find('a');
        if (logout[1]) {
            $(logout[1]).click(ga.mcatch(() => {
                const result = confirm(
                    `Logging out of AMS will prevent Machete from monitoring your campaigns. Instead, you may close this tab without logging out.

                    Continue logging out?`);
                return result;
            }));
        }

        let brandName = null;
        const brandNameDiv = $('#currentBrandName');
        if (brandNameDiv.length)
            brandName = brandNameDiv[0].innerText;
        if (!brandName) {
            const accountLink = $('.kdpUserBarLinksRight').find('a').first();
            if (accountLink.length)
                brandName = accountLink[0].innerText.replace('Hello ', '');
        }
        if (brandName) {
            common.bgMessage({
                action: 'sp.setBrandName',
                entityId: getEntityId(),
                brandName,
            }).catch(ga.mcatch);
        }
    }));
}

function requestKdpIntegration() {
    return common.bgMessage({ action: 'kdp.requestPermission' });
}

function hasKdpIntegration() {
    return common.bgMessage({ action: 'kdp.hasPermission' });
}

function campaignSelectOptions(campaigns) {
    let options = [
        { value: campaigns, label: 'All Campaigns' },
        { value: campaigns.filter(c => isRunning(c)), label: 'All Active Campaigns' }
    ];
    for (const asinGroup of Object.values(_.groupBy(campaigns, 'asin'))) {
        if (!asinGroup[0].asin)
            continue;
        options.push({ value: asinGroup, label: `All Campaigns For "${asinGroup[0].productTitle || '[unknown title]'}" (ASIN ${asinGroup[0].asin})`});
    }
    options = options.concat(...campaigns.filter(c => c.name).map(c => ({ value: [c], label: c.name })));

    return options;
}

module.exports = {
    amsPageInit,
    stripPrefix,
    getEntityId,
    getCampaignId,
    getQueryArgs,
    getAdGroupIdFromDOM,
    getCurrentCampaignSnapshot,
    getCampaignHistory,
    getAggregateCampaignHistory,
    getKeywordData,
    getAggregateKeywordData,
    getAllCampaignsAllowed,
    getCampaignAllowed,
    getCampaignSummaries,
    getAllowedCampaignSummaries,
    getCampaignSummary,
    getKdpSalesHistory,
    storeAdGroupMetadata,
    updateKeywordStatus,
    updateKeywordBid,
    addKeywords,
    copyKeywordsToCampaigns,
    isRunning,
    startSession,
    calculateKnpIncome,
    requestKdpIntegration,
    hasKdpIntegration,
    campaignSelectOptions,
};
<|endoftext|>


<commit_before>adapterManagerRegisterAdapter((function(){

	win.bidDetailsMap = win.bidDetailsMap || {};
	win.progKeyValueMap = win.progKeyValueMap || {};

	var adapterID = 'pubmatic',

		constConfigPubID = 'pub_id',
		constPubId = 'pubId',
		constPubMaticResponseCreative = 'creative_tag',
		constPubMaticResponseTrackingURL = 'tracking_url',
		adapterConfigMandatoryParams = [constConfigPubID, constConfigKeyGeneratigPattern, constConfigServerSideKey],
		slotConfigMandatoryParams = [],

		dealKey = constDealKeyFirstPart + adapterID,
		dealChannelValues = {
			1: constDealChannelPMP,
			5: constDealChannelPreffered,
			6: constDealChannelPMPG
		},

		pubID = 0,
		wrapperImpressionID = '',
		conf = {},
		pmSlotToDivIDMap = {},

		isPixelingDone = false,

		ortbEnabledPublishers = {5890:''},

		setTimeStampAndZone = function(conf) {
			var currTime = new Date();
			conf.kltstamp  = currTime.getFullYear()
								+ "-" + (currTime.getMonth() + 1)
								+ "-" + currTime.getDate()
								+ " " + currTime.getHours()
								+ ":" + currTime.getMinutes()
								+ ":" + currTime.getSeconds();
			conf.timezone = currTime.getTimezoneOffset()/60  * -1;
		},

		initiateUserSyncup = function(){
			if( ! isPixelingDone ){
				setTimeout(function(){
					var element = doc.createElement('iframe');
					element.src = utilMetaInfo.protocol + 'ads.pubmatic.com/AdServer/js/showad.js#PIX&kdntuid=1&p=' + pubID + '&s=&a=';
					element.style.height ="0px";
					element.style.width ="0px";
					doc.getElementsByTagName("script")[0].parentNode.appendChild(element);
					isPixelingDone = true;
				}, 2000);
			}
		},

		initConf = function(){
			conf[constPubId] = pubID;
			conf['wiid'] = wrapperImpressionID;
			//conf.pm_cb = 'DM.callBack';
			conf.pm_cb = 'window.PWT.PubmaticAdapterCallback';
			conf.grs = 3; // Grouped Response parameter, 0: default, 1: variables are split, 2: 1+rid passed to cback func, 3: 1+ md5 of bidid
			conf.a = 1;// async == true
			conf.pageURL  = utilMetaInfo.u;
			conf.refurl   = utilMetaInfo.r;
			conf.inIframe = win != top ? '1' : '0';
			conf.screenResolution =  win.screen.width + 'x' + win.screen.height;
			conf.ranreq = Math.random();

			conf.profileid = bidManagerGetProfileID();
			if(utilUsingDifferentProfileVersionID){
				conf.versionid = bidManagerGetProfileDisplayVersionID();
			}

			if(navigator.cookieEnabled === false ){
				conf.fpcd = '1';
			}
			setTimeStampAndZone( conf );
		},

		createOrtbJson = function(conf, slots, keyGenerationPattern){
			var json = null,
				loc = win.location,
				nav = win.navigator,
				passTheseConfParamsIntoDmExtension = ['a', 'pm_cb', 'pubId', 'ctype', 'kval_param', 'lmk', 'profileid', 'versionid'],
				copyFromConfAndDeleteFromConf = function(conf, key, dmExtension){
					if(conf[key]){
						dmExtension[key] = decodeURIComponent(conf[key]);
						delete conf[key];
					}
				},
				convertAllValuesToString = function(obj){
					var newObj = {};
					for(var key in obj){
						if(obj.hasOwnProperty(key)){
							newObj[key] = String(obj[key]);
						}
					}
					return newObj;
				}
			;

			delete conf.grs; // as it is not required in ORTB call

			// setting up the schema
			json = {
				id : ''+utilGetCurrentTimestampInMs(),
				at: 2,
				cur: ["USD"],
				imp: [],
				site: {
					domain: loc.hostname,
					page: loc.href,
					publisher: {
						id: ''+pubID
					}
				},
				device: {
					ua: nav.userAgent
				},
				ext: {
					extension: {}
				}
			};

			// adding slots info
			for(var i= 0, l = slots.length; i < l; i++){
				var slot = slots[i];

				var format = [];
				for(var k=0, kl = slot[constAdSlotSizes].length; k<kl; k++){
					var width = slot[constAdSlotSizes][k][0];
					var height = slot[constAdSlotSizes][k][1];
					format.push({
						w: parseInt(width),
						h: parseInt(height)
					});
				}

				var anImp = {
					id: slot[constCommonDivID],
					banner: {
						pos: 0,
						format: format
					},
					ext: {
						extension: {
							div: slot[constCommonDivID],
							adunit: slot[constAdUnitID],
							slotIndex: slot[constAdUnitIndex]/*,
							"keyValue": slot[constCommonSlotKeyValue]*/ // do not pass kval_param for now
						}
					}
				};

				json.imp.push(anImp);
			}

			//if there are no json.imp then return null
			if(json.imp.length == 0){
				return null;
			}

			// DM specific params
			var dmExtension = {
				rs: 1//todo confirm
			};

			for(var i=0, l = passTheseConfParamsIntoDmExtension.length; i < l; i++){
				copyFromConfAndDeleteFromConf(conf, passTheseConfParamsIntoDmExtension[i], dmExtension);
			}
			json.ext.extension['dm'] = dmExtension;

			// AdServer specific params to be passed, as it is
			json.ext.extension['as'] = convertAllValuesToString(conf);

			return json;
		},

		makeOrtbCall = function(slots, keyGenerationPattern){
			var request_url = utilMetaInfo.protocol + 'hb.pubmatic.com/openrtb/24/',
				json = createOrtbJson(conf, slots, keyGenerationPattern)
			;
			if(json == null){
				utilLog(adapterID+': Error in generating ORTB json.')
				return;
			}

			utilAjaxCall(
				request_url,
				function(response){
					try{
						response = JSON.parse(response);
					}catch(e){
						utilLog(adapterID+constCommonMessage21);
						utilLog(e);
						return;
					}

					if(response.seatbid && response.seatbid[0]){
						var seatbid = response.seatbid[0];
						if(seatbid.bid && seatbid.bid.length > 0){
							var bids = seatbid.bid;
							for(var i=0, l=bids.length; i<l; i++){

								var responseBid = bids[i];

								if(responseBid.impid && responseBid.h && responseBid.w
									&& responseBid.ext && responseBid.ext.extension
									&& responseBid.ext.extension.slotname){

									var keyValuePairs = {},
										bidID = utilGetUniqueIdentifierStr(),
										dealID = responseBid.dealid || "",
										dealChannel = utilGetDealChannelValue(dealChannelValues, responseBid.ext.extension.dealchannel)
									;

									if(dealID){
										keyValuePairs[dealKey] = dealChannel+constDealKeyValueSeparator+dealID+constDealKeyValueSeparator+bidID;
									}

									bidManagerSetBidFromBidder(
										responseBid.impid,
										adapterID,
										bidManagerCreateBidObject(
											responseBid.price,
											bidManagerCreateDealObject(dealID, dealChannel),
											"",
											generateCreative(
												responseBid.adm,
												responseBid.ext.extension.trackingUrl,
												pubID
											),
											"",
											responseBid.w,
											responseBid.h,
											responseBid.ext.extension.slotname,
											keyValuePairs
										),
										bidID
									);
								}else{
									utilLog(adapterID+constCommonMessage21);
								}
							}
						}else{
							utilLog(adapterID+constCommonMessage21);
						}
					}else{
						utilLog(adapterID+constCommonMessage21);
					}
				},
				JSON.stringify(json),
				{} // todo later
			);
		},

		createLegacyCall = function(activeSlots, keyGenerationPattern){

			var request_url = "",
				tempURL,
				protocol = utilMetaInfo.protocol,
				adserver_url = 'haso.pubmatic.com/ads/',
				slots = [],
				dmPremiumPubList = {46076:'', 60530:'', 9999:'', 7777:''}
			;

			utilForEachGeneratedKey(
				adapterID,
				slotConfigMandatoryParams,
				activeSlots,
				keyGenerationPattern,
				null,
				function(generatedKey, kgpConsistsWidthAndHeight, currentSlot, keyConfig, currentWidth, currentHeight){
					slots.push( generatedKey );
					pmSlotToDivIDMap[ generatedKey ] = currentSlot[constCommonDivID];
					//todo: do pass kval_param_slots
				}
			);

			if(slots.length > 0){
				tempURL = (win.pm_dm_enabled != true && ! utilHasOwnProperty(dmPremiumPubList, conf[constPubId])) ? 'gads.pubmatic.com/AdServer/AdCallAggregator' : (adserver_url +  conf[constPubId] + '/GRPBID/index.html');
				request_url = protocol + tempURL + '?' + utilToUrlParams(conf);
				request_url += '&adslots=' + encodeURIComponent('[' + slots.join(',') +']');
			}

			return request_url;
		},

		fetchBids = function(configObject, activeSlots){
			utilLog(adapterID+constCommonMessage01);

			var adapterConfig = utilLoadGlobalConfigForAdapter(configObject, adapterID, adapterConfigMandatoryParams);
			if(!adapterConfig){
				return;
			}

			var isServerSideKey = adapterConfig[constConfigServerSideKey];
			if(isServerSideKey !== 'true'){
				utilLog(adapterID+': '+constConfigServerSideKey+' should be set to true, setting it to true.')
				isServerSideKey = true;
			}

			pubID = adapterConfig[constConfigPubID] || 0;
			wrapperImpressionID = configObject.global.pwt.wiid;

			if(pubID == 0){
				utilLog(adapterID+': '+constConfigPubID+' should be non-zero.'+constCommonMessage07);
				return;
			}

			initConf();
			// do not pass kval_param for now
			//conf['kval_param'] = JSON.stringify(configObject[constConfigGlobalKeyValue]);

			if(utilHasOwnProperty(ortbEnabledPublishers, pubID)){
				makeOrtbCall(activeSlots, adapterConfig[constConfigKeyGeneratigPattern]);
			}else{
				utilLoadScript(createLegacyCall(activeSlots, adapterConfig[constConfigKeyGeneratigPattern]));
			}

			initiateUserSyncup();
		},

		generateCreative = function(creative, tracker, pubID){
			var isTrackerFirstEnabled = function(pubId){
					var config = {37576: ''}; // this is a whitelist
					return utilHasOwnProperty(config, pubId);
				}
			;
			tracker = '',
				output = (isTrackerFirstEnabled(pubID) ? tracker : '') + decodeURIComponent(creative) + (isTrackerFirstEnabled(pubID) ? '' : tracker)
			;

			if(win.PubMaticAI!=null){
				output = "" + output + "";
			}

			return output;
		}
	;

	win.PWT.PubmaticAdapterCallback = function(){
		var localProgKeyValueMap = win.progKeyValueMap,
			bidDetailsMap = win.bidDetailsMap
		;

		win.progKeyValueMap = {};
		for( var key in localProgKeyValueMap){

			if( utilHasOwnProperty(localProgKeyValueMap, key) ){

				var progKeyValueMapDetails = localProgKeyValueMap[key].split(';');
				var progKeyValueMapDetailsLength = progKeyValueMapDetails.length;
				if(progKeyValueMapDetailsLength == 8){

					var bid = bidDetailsMap[ progKeyValueMapDetails[5] ],
						bidID = utilGetUniqueIdentifierStr(),
						dealID = progKeyValueMapDetails[7] || "",
						keyValuePairs = {},
						dealChannel = utilGetDealChannelValue(dealChannelValues, bid.deal_channel)
					;

					if(dealID){
						keyValuePairs[dealKey] = dealChannel+constDealKeyValueSeparator+dealID+constDealKeyValueSeparator+bidID;
					}

					bidManagerSetBidFromBidder(
						pmSlotToDivIDMap[key],
						adapterID,
						bidManagerCreateBidObject(
							progKeyValueMapDetails[3],
							bidManagerCreateDealObject(dealID, dealChannel),
							"",
							generateCreative(bid[constPubMaticResponseCreative], bid[constPubMaticResponseTrackingURL], pubID),
							"",
							bid[constCommonWidth],
							bid[constCommonHeight],
							key,
							keyValuePairs
						),
						bidID
					);
				}
			}
		}
	};

	return {
		fB: fetchBids,
		dC: utilDisplayCreative,
		ID: function(){
			return adapterID;
		}
	};

})());<commit_msg>Trim dealID and dealChannel<commit_after>adapterManagerRegisterAdapter((function(){

	win.bidDetailsMap = win.bidDetailsMap || {};
	win.progKeyValueMap = win.progKeyValueMap || {};

	var adapterID = 'pubmatic',

		constConfigPubID = 'pub_id',
		constPubId = 'pubId',
		constPubMaticResponseCreative = 'creative_tag',
		constPubMaticResponseTrackingURL = 'tracking_url',
		adapterConfigMandatoryParams = [constConfigPubID, constConfigKeyGeneratigPattern, constConfigServerSideKey],
		slotConfigMandatoryParams = [],

		dealKey = constDealKeyFirstPart + adapterID,
		dealChannelValues = {
			1: constDealChannelPMP,
			5: constDealChannelPreffered,
			6: constDealChannelPMPG
		},

		pubID = 0,
		wrapperImpressionID = '',
		conf = {},
		pmSlotToDivIDMap = {},

		isPixelingDone = false,

		ortbEnabledPublishers = {5890:''},

		setTimeStampAndZone = function(conf) {
			var currTime = new Date();
			conf.kltstamp  = currTime.getFullYear()
								+ "-" + (currTime.getMonth() + 1)
								+ "-" + currTime.getDate()
								+ " " + currTime.getHours()
								+ ":" + currTime.getMinutes()
								+ ":" + currTime.getSeconds();
			conf.timezone = currTime.getTimezoneOffset()/60  * -1;
		},

		initiateUserSyncup = function(){
			if( ! isPixelingDone ){
				setTimeout(function(){
					var element = doc.createElement('iframe');
					element.src = utilMetaInfo.protocol + 'ads.pubmatic.com/AdServer/js/showad.js#PIX&kdntuid=1&p=' + pubID + '&s=&a=';
					element.style.height ="0px";
					element.style.width ="0px";
					doc.getElementsByTagName("script")[0].parentNode.appendChild(element);
					isPixelingDone = true;
				}, 2000);
			}
		},

		initConf = function(){
			conf[constPubId] = pubID;
			conf['wiid'] = wrapperImpressionID;
			//conf.pm_cb = 'DM.callBack';
			conf.pm_cb = 'window.PWT.PubmaticAdapterCallback';
			conf.grs = 3; // Grouped Response parameter, 0: default, 1: variables are split, 2: 1+rid passed to cback func, 3: 1+ md5 of bidid
			conf.a = 1;// async == true
			conf.pageURL  = utilMetaInfo.u;
			conf.refurl   = utilMetaInfo.r;
			conf.inIframe = win != top ? '1' : '0';
			conf.screenResolution =  win.screen.width + 'x' + win.screen.height;
			conf.ranreq = Math.random();

			conf.profileid = bidManagerGetProfileID();
			if(utilUsingDifferentProfileVersionID){
				conf.versionid = bidManagerGetProfileDisplayVersionID();
			}

			if(navigator.cookieEnabled === false ){
				conf.fpcd = '1';
			}
			setTimeStampAndZone( conf );
		},

		createOrtbJson = function(conf, slots, keyGenerationPattern){
			var json = null,
				loc = win.location,
				nav = win.navigator,
				passTheseConfParamsIntoDmExtension = ['a', 'pm_cb', 'pubId', 'ctype', 'kval_param', 'lmk', 'profileid', 'versionid'],
				copyFromConfAndDeleteFromConf = function(conf, key, dmExtension){
					if(conf[key]){
						dmExtension[key] = decodeURIComponent(conf[key]);
						delete conf[key];
					}
				},
				convertAllValuesToString = function(obj){
					var newObj = {};
					for(var key in obj){
						if(obj.hasOwnProperty(key)){
							newObj[key] = String(obj[key]);
						}
					}
					return newObj;
				}
			;

			delete conf.grs; // as it is not required in ORTB call

			// setting up the schema
			json = {
				id : ''+utilGetCurrentTimestampInMs(),
				at: 2,
				cur: ["USD"],
				imp: [],
				site: {
					domain: loc.hostname,
					page: loc.href,
					publisher: {
						id: ''+pubID
					}
				},
				device: {
					ua: nav.userAgent
				},
				ext: {
					extension: {}
				}
			};

			// adding slots info
			for(var i= 0, l = slots.length; i < l; i++){
				var slot = slots[i];

				var format = [];
				for(var k=0, kl = slot[constAdSlotSizes].length; k<kl; k++){
					var width = slot[constAdSlotSizes][k][0];
					var height = slot[constAdSlotSizes][k][1];
					format.push({
						w: parseInt(width),
						h: parseInt(height)
					});
				}

				var anImp = {
					id: slot[constCommonDivID],
					banner: {
						pos: 0,
						format: format
					},
					ext: {
						extension: {
							div: slot[constCommonDivID],
							adunit: slot[constAdUnitID],
							slotIndex: slot[constAdUnitIndex]/*,
							"keyValue": slot[constCommonSlotKeyValue]*/ // do not pass kval_param for now
						}
					}
				};

				json.imp.push(anImp);
			}

			//if there are no json.imp then return null
			if(json.imp.length == 0){
				return null;
			}

			// DM specific params
			var dmExtension = {
				rs: 1//todo confirm
			};

			for(var i=0, l = passTheseConfParamsIntoDmExtension.length; i < l; i++){
				copyFromConfAndDeleteFromConf(conf, passTheseConfParamsIntoDmExtension[i], dmExtension);
			}
			json.ext.extension['dm'] = dmExtension;

			// AdServer specific params to be passed, as it is
			json.ext.extension['as'] = convertAllValuesToString(conf);

			return json;
		},

		makeOrtbCall = function(slots, keyGenerationPattern){
			var request_url = utilMetaInfo.protocol + 'hb.pubmatic.com/openrtb/24/',
				json = createOrtbJson(conf, slots, keyGenerationPattern)
			;
			if(json == null){
				utilLog(adapterID+': Error in generating ORTB json.')
				return;
			}

			utilAjaxCall(
				request_url,
				function(response){
					try{
						response = JSON.parse(response);
					}catch(e){
						utilLog(adapterID+constCommonMessage21);
						utilLog(e);
						return;
					}

					if(response.seatbid && response.seatbid[0]){
						var seatbid = response.seatbid[0];
						if(seatbid.bid && seatbid.bid.length > 0){
							var bids = seatbid.bid;
							for(var i=0, l=bids.length; i<l; i++){

								var responseBid = bids[i];

								if(responseBid.impid && responseBid.h && responseBid.w
									&& responseBid.ext && responseBid.ext.extension
									&& responseBid.ext.extension.slotname){

									var keyValuePairs = {},
										bidID = utilGetUniqueIdentifierStr(),
										dealID = utilTrim(responseBid.dealid),
										dealChannel = utilGetDealChannelValue(dealChannelValues, utilTrim(responseBid.ext.extension.dealchannel))
									;

									if(dealID){
										keyValuePairs[dealKey] = dealChannel+constDealKeyValueSeparator+dealID+constDealKeyValueSeparator+bidID;
									}

									bidManagerSetBidFromBidder(
										responseBid.impid,
										adapterID,
										bidManagerCreateBidObject(
											responseBid.price,
											bidManagerCreateDealObject(dealID, dealChannel),
											"",
											generateCreative(
												responseBid.adm,
												responseBid.ext.extension.trackingUrl,
												pubID
											),
											"",
											responseBid.w,
											responseBid.h,
											responseBid.ext.extension.slotname,
											keyValuePairs
										),
										bidID
									);
								}else{
									utilLog(adapterID+constCommonMessage21);
								}
							}
						}else{
							utilLog(adapterID+constCommonMessage21);
						}
					}else{
						utilLog(adapterID+constCommonMessage21);
					}
				},
				JSON.stringify(json),
				{} // todo later
			);
		},

		createLegacyCall = function(activeSlots, keyGenerationPattern){

			var request_url = "",
				tempURL,
				protocol = utilMetaInfo.protocol,
				adserver_url = 'haso.pubmatic.com/ads/',
				slots = [],
				dmPremiumPubList = {46076:'', 60530:'', 9999:'', 7777:''}
			;

			utilForEachGeneratedKey(
				adapterID,
				slotConfigMandatoryParams,
				activeSlots,
				keyGenerationPattern,
				null,
				function(generatedKey, kgpConsistsWidthAndHeight, currentSlot, keyConfig, currentWidth, currentHeight){
					slots.push( generatedKey );
					pmSlotToDivIDMap[ generatedKey ] = currentSlot[constCommonDivID];
					//todo: do pass kval_param_slots
				}
			);

			if(slots.length > 0){
				tempURL = (win.pm_dm_enabled != true && ! utilHasOwnProperty(dmPremiumPubList, conf[constPubId])) ? 'gads.pubmatic.com/AdServer/AdCallAggregator' : (adserver_url +  conf[constPubId] + '/GRPBID/index.html');
				request_url = protocol + tempURL + '?' + utilToUrlParams(conf);
				request_url += '&adslots=' + encodeURIComponent('[' + slots.join(',') +']');
			}

			return request_url;
		},

		fetchBids = function(configObject, activeSlots){
			utilLog(adapterID+constCommonMessage01);

			var adapterConfig = utilLoadGlobalConfigForAdapter(configObject, adapterID, adapterConfigMandatoryParams);
			if(!adapterConfig){
				return;
			}

			var isServerSideKey = adapterConfig[constConfigServerSideKey];
			if(isServerSideKey !== 'true'){
				utilLog(adapterID+': '+constConfigServerSideKey+' should be set to true, setting it to true.')
				isServerSideKey = true;
			}

			pubID = adapterConfig[constConfigPubID] || 0;
			wrapperImpressionID = configObject.global.pwt.wiid;

			if(pubID == 0){
				utilLog(adapterID+': '+constConfigPubID+' should be non-zero.'+constCommonMessage07);
				return;
			}

			initConf();
			// do not pass kval_param for now
			//conf['kval_param'] = JSON.stringify(configObject[constConfigGlobalKeyValue]);

			if(utilHasOwnProperty(ortbEnabledPublishers, pubID)){
				makeOrtbCall(activeSlots, adapterConfig[constConfigKeyGeneratigPattern]);
			}else{
				utilLoadScript(createLegacyCall(activeSlots, adapterConfig[constConfigKeyGeneratigPattern]));
			}

			initiateUserSyncup();
		},

		generateCreative = function(creative, tracker, pubID){
			var isTrackerFirstEnabled = function(pubId){
					var config = {37576: ''}; // this is a whitelist
					return utilHasOwnProperty(config, pubId);
				}
			;
			tracker = '',
				output = (isTrackerFirstEnabled(pubID) ? tracker : '') + decodeURIComponent(creative) + (isTrackerFirstEnabled(pubID) ? '' : tracker)
			;

			if(win.PubMaticAI!=null){
				output = "" + output + "";
			}

			return output;
		}
	;

	win.PWT.PubmaticAdapterCallback = function(){
		var localProgKeyValueMap = win.progKeyValueMap,
			bidDetailsMap = win.bidDetailsMap
		;

		win.progKeyValueMap = {};
		for( var key in localProgKeyValueMap){

			if( utilHasOwnProperty(localProgKeyValueMap, key) ){

				var progKeyValueMapDetails = localProgKeyValueMap[key].split(';');
				var progKeyValueMapDetailsLength = progKeyValueMapDetails.length;
				if(progKeyValueMapDetailsLength == 8){

					var bid = bidDetailsMap[ progKeyValueMapDetails[5] ],
						bidID = utilGetUniqueIdentifierStr(),
						dealID = utilTrim(progKeyValueMapDetails[7]),
						keyValuePairs = {},
						dealChannel = utilGetDealChannelValue(dealChannelValues, utilTrim(bid.deal_channel))
					;

					if(dealID){
						keyValuePairs[dealKey] = dealChannel+constDealKeyValueSeparator+dealID+constDealKeyValueSeparator+bidID;
					}

					bidManagerSetBidFromBidder(
						pmSlotToDivIDMap[key],
						adapterID,
						bidManagerCreateBidObject(
							progKeyValueMapDetails[3],
							bidManagerCreateDealObject(dealID, dealChannel),
							"",
							generateCreative(bid[constPubMaticResponseCreative], bid[constPubMaticResponseTrackingURL], pubID),
							"",
							bid[constCommonWidth],
							bid[constCommonHeight],
							key,
							keyValuePairs
						),
						bidID
					);
				}
			}
		}
	};

	return {
		fB: fetchBids,
		dC: utilDisplayCreative,
		ID: function(){
			return adapterID;
		}
	};

})());<|endoftext|>


<commit_before>'use strict';

var startsWith = require('lodash/startsWith');
var clone = require('lodash/clone');
var Component = require('../ui/Component');
// var DefaultDOMElement = require('../ui/DefaultDOMElement');
var TestItem = require('./TestItem');
var Router = require('../ui/Router');

function TestSuite() {
  TestSuite.super.apply(this, arguments);

  var moduleNames = {};
  this.props.harness.getTests().forEach(function(t) {
    if (t.moduleName) {
      moduleNames[t.moduleName] = true;
    }
  });
  this.moduleNames = Object.keys(moduleNames);
}

TestSuite.Prototype = function() {

  this.didMount = function() {
    this.router.on('route:changed', this.onRouteChange, this);
    this.router.start();

    this.runTests();
  };

  this.dispose = function() {
    this.router.off(this);
  };

  this.getInitialState = function() {
    this.router = new Router();
    return this.router.readRoute();
  };

  this.render = function($$) {
    var el = $$('div').addClass('sc-test-suite');

    var state = this.state;
    var filter = this.state.filter || '';

    var toolbar = $$('div').addClass('se-toolbar');
    var moduleSelect = $$('select').ref('moduleNames');
    moduleSelect.append($$('option').attr('value', '').append('---   All   --'));
    this.moduleNames.forEach(function(moduleName) {
      var option = $$('option').attr('value', moduleName).append(moduleName);
      if (moduleName === state.filter) option.attr('selected', true);
      moduleSelect.append(option);
    });
    moduleSelect.on('change', this.onModuleSelect);
    toolbar.append($$('div').addClass('logo').append('Substance TestSuite'))
    toolbar.append(moduleSelect);
    toolbar.append(
      $$('div').append(
        $$('input').attr({ type: 'checkbox' })
          .on('change', this.onToggleHideSuccessful).ref('hideCheckbox'),
        $$('label').append('Only show failed tests only')
      )
    );

    el.append(toolbar);

    var tests = $$('div').addClass('se-tests').ref('tests');
    this.props.harness.getTests().forEach(function(test) {
      var testItem = $$(TestItem, { test: test });
      if (!_filter(test.moduleName, filter)) {
        testItem.addClass('sm-hidden');
      }
      tests.append(testItem);
    });

    el.append(tests);

    if (this.state.hideSuccessful) {
      el.addClass('sm-hide-successful');
    }

    return el;
  };

  this.didUpdate = function() {
    this.runTests();
  };

  this.runTests = function() {
    var testItems = this.refs.tests.getChildren();
    var tests = [];
    var filter = this.state.filter || '';
    testItems.forEach(function(testItem) {
      var t = testItem.props.test;
      if(_filter(t.moduleName, filter)) {
        testItem.removeClass('sm-hidden');
        tests.push(t);
      } else {
        testItem.addClass('sm-hidden');
      }
    });
    this.props.harness.runTests(tests);
  };

  function _filter(name, f) {
    return startsWith(name, f);
  }

  this.onModuleSelect = function() {
    var filter = this.refs.moduleNames.htmlProp('value');
    this.extendState({
      filter: filter
    });
    this.updateRoute();
  };

  this.updateRoute = function() {
    this.router.writeRoute(this.state);
  };

  this.onRouteChange = function(newState) {
    this.setState(newState);
  };

  this.onToggleHideSuccessful = function() {
    var checked = this.refs.hideCheckbox.htmlProp('checked');
    if (checked) {
      this.extendState({
        hideSuccessful: checked
      });
    } else {
      var newState = clone(this.state);
      delete newState.hideSuccessful;
      this.setState(newState);
    }
    this.updateRoute();
  };

};

Component.extend(TestSuite);

module.exports = TestSuite;<commit_msg>Fix linter.<commit_after>'use strict';

var startsWith = require('lodash/startsWith');
var clone = require('lodash/clone');
var Component = require('../ui/Component');
// var DefaultDOMElement = require('../ui/DefaultDOMElement');
var TestItem = require('./TestItem');
var Router = require('../ui/Router');

function TestSuite() {
  TestSuite.super.apply(this, arguments);

  var moduleNames = {};
  this.props.harness.getTests().forEach(function(t) {
    if (t.moduleName) {
      moduleNames[t.moduleName] = true;
    }
  });
  this.moduleNames = Object.keys(moduleNames);
}

TestSuite.Prototype = function() {

  this.didMount = function() {
    this.router.on('route:changed', this.onRouteChange, this);
    this.router.start();

    this.runTests();
  };

  this.dispose = function() {
    this.router.off(this);
  };

  this.getInitialState = function() {
    this.router = new Router();
    return this.router.readRoute();
  };

  this.render = function($$) {
    var el = $$('div').addClass('sc-test-suite');

    var state = this.state;
    var filter = this.state.filter || '';

    var toolbar = $$('div').addClass('se-toolbar');
    var moduleSelect = $$('select').ref('moduleNames');
    moduleSelect.append($$('option').attr('value', '').append('---   All   --'));
    this.moduleNames.forEach(function(moduleName) {
      var option = $$('option').attr('value', moduleName).append(moduleName);
      if (moduleName === state.filter) option.attr('selected', true);
      moduleSelect.append(option);
    });
    moduleSelect.on('change', this.onModuleSelect);
    toolbar.append($$('div').addClass('logo').append('Substance TestSuite'));
    toolbar.append(moduleSelect);
    toolbar.append(
      $$('div').append(
        $$('input').attr({ type: 'checkbox' })
          .on('change', this.onToggleHideSuccessful).ref('hideCheckbox'),
        $$('label').append('Only show failed tests only')
      )
    );

    el.append(toolbar);

    var tests = $$('div').addClass('se-tests').ref('tests');
    this.props.harness.getTests().forEach(function(test) {
      var testItem = $$(TestItem, { test: test });
      if (!_filter(test.moduleName, filter)) {
        testItem.addClass('sm-hidden');
      }
      tests.append(testItem);
    });

    el.append(tests);

    if (this.state.hideSuccessful) {
      el.addClass('sm-hide-successful');
    }

    return el;
  };

  this.didUpdate = function() {
    this.runTests();
  };

  this.runTests = function() {
    var testItems = this.refs.tests.getChildren();
    var tests = [];
    var filter = this.state.filter || '';
    testItems.forEach(function(testItem) {
      var t = testItem.props.test;
      if(_filter(t.moduleName, filter)) {
        testItem.removeClass('sm-hidden');
        tests.push(t);
      } else {
        testItem.addClass('sm-hidden');
      }
    });
    this.props.harness.runTests(tests);
  };

  function _filter(name, f) {
    return startsWith(name, f);
  }

  this.onModuleSelect = function() {
    var filter = this.refs.moduleNames.htmlProp('value');
    this.extendState({
      filter: filter
    });
    this.updateRoute();
  };

  this.updateRoute = function() {
    this.router.writeRoute(this.state);
  };

  this.onRouteChange = function(newState) {
    this.setState(newState);
  };

  this.onToggleHideSuccessful = function() {
    var checked = this.refs.hideCheckbox.htmlProp('checked');
    if (checked) {
      this.extendState({
        hideSuccessful: checked
      });
    } else {
      var newState = clone(this.state);
      delete newState.hideSuccessful;
      this.setState(newState);
    }
    this.updateRoute();
  };

};

Component.extend(TestSuite);

module.exports = TestSuite;<|endoftext|>


<commit_before>module.exports = () => {
    const Mock = {};

    Mock.config = {
        vars:  'object',
        moduleName:  'string',
        baseDir:  'string',
        destDir:  'string',
        srcDir:  'string',
        tempDir: 'string',
        EXPRESS_PORT:  'number',
        EXPRESS_ROOT:  'string',
        eslintConfig:  'string',
        stylelintConfig:  'string',
        packageJson:  'string',
        srcFiles: 'array',
        electronPackagingOptions: 'object',
        buildFiles: 'array',
        js_main_file_name:  'string',
        js_main_entry_path:  'string',
        js_output_path:  'string',
        js_external_scripts: 'array',
        js_runtime_configs: 'array',
        styles_main_file_name:  'string',
        styles_external_stylesheets: 'array',
        template_main_file_name:  'string',
        template_stats_file_name:  'string',
        template_src_path:  'string',
        template_engine:  'string',
        gaEnable: 'boolean',
        gaTrackingId: 'string',
        gaPageViewOnLoad: 'boolean',
        media_audio_output_path:  'string',
        media_files_output_path:  'string',
        media_fonts_output_path:  'string',
        media_images_output_path:  'string',
        media_video_output_path:  'string',
        media_favicon_path: 'string',
        imageminConfig:  'object',
        externalModules:  'object',
        sourcemapDev: 'boolean',
        sourcemapProd: 'boolean',
        sourcemapType: 'string',
        autoprefixerOptions:  'object',
        hotReloadingOptions:  'object',
        BrowserSyncReloadOnChange: 'boolean',
        enableRemoteDebugging: 'boolean',
        onBuildStartShellCommands:  'array',
        onBuildEndShellCommands:  'array',
        onBuildExitShellCommands:  'array',
        failOnProdBuildJsError:  'boolean',
        failOnProdBuildStyleError:  'boolean',
        eslintQuietMode: 'boolean',
        devtool:  'string',
        entry:  'array',
        output:  'object',
        resolve:  'object',
        module:  'object',
        postcss:  'array',
        eslint:  'object',
        bail:  'boolean',
        plugins:  'array'
    };
    Mock.packageJson = {};
    Mock.packageJson.devDependencies = {
        "autoprefixer": "^6.4.0",
        "babel-cli": "^6.11.4",
        "babel-core": "^6.13.2",
        "babel-eslint": "^7.0.0",
        "babel-jest": "^17.0.0",
        "babel-loader": "^6.2.4",
        "babel-plugin-add-module-exports": "^0.2.1",
        "babel-plugin-istanbul": "^3.0.0",
        "babel-plugin-react-html-attrs": "^2.0.0",
        "babel-plugin-react-transform": "^2.0.2",
        "babel-plugin-syntax-object-rest-spread": "^6.13.0",
        "babel-plugin-transform-class-properties": "^6.11.5",
        "babel-plugin-transform-decorators-legacy": "^1.3.4",
        "babel-plugin-transform-runtime": "^6.12.0",
        "babel-polyfill": "^6.13.0",
        "babel-preset-es2015": "^6.14.0",
        "babel-preset-react": "^6.11.1",
        "babel-preset-react-hmre": "^1.1.1",
        "babel-preset-stage-0": "^6.5.0",
        "babel-register": "^6.11.6",
        "babel-runtime": "^6.11.6",
        "browser-sync": "^2.14.0",
        "browser-sync-webpack-plugin": "^1.1.2",
        "chai": "^3.5.0",
        "chalk": "^1.1.3",
        "clean-webpack-plugin": "^0.1.10",
        "connect-history-api-fallback": "^1.3.0",
        "copy-webpack-plugin": "^4.0.0",
        "cross-env": "^3.1.3",
        "css-loader": "^0.25.0",
        "electron": "^1.4.5",
        "electron-packager": "^8.2.0",
        "eslint": "^3.3.0",
        "eslint-loader": "1.5.0",
        "expose-loader": "^0.7.1",
        "express": "^4.14.0",
        "express-history-api-fallback": "^2.0.0",
        "extract-text-webpack-plugin": "^1.0.1",
        "file-loader": "^0.9.0",
        "fs-extra": "^1.0.0",
        "gulp": "^3.9.1",
        "gulp-debug": "^3.0.0",
        "gulp-eslint": "^3.0.1",
        "gulp-load-plugins": "^1.2.4",
        "gulp-plumber": "^1.1.0",
        "gulp-util": "^3.0.7",
        "html-webpack-plugin": "^2.22.0",
        "imagemin-webpack-plugin": "^1.1.0",
        "ip": "^1.1.3",
        "istanbul": "^0.4.5",
        "jasmine-core": "^2.4.1",
        "jest": "^17.0.0",
        "jest-cli": "^17.0.0",
        "json-loader": "^0.5.4",
        "less": "^2.7.1",
        "less-loader": "^2.2.3",
        "lodash": "^4.15.0",
        "mocha": "^3.0.2",
        "mocha-lcov-reporter": "^1.2.0",
        "morgan": "^1.7.0",
        "node-sass": "^3.8.0",
        "postcss-loader": "^1.0.0",
        "progress-bar-webpack-plugin": "^1.9.0",
        "pug": "^2.0.0-beta5",
        "pug-loader": "^2.2.1",
        "q": "^1.4.1",
        "q-io": "^1.13.2",
        "react-addons-test-utils": "^15.3.0",
        "react-hot-loader": "^3.0.0-beta.6",
        "react-test-renderer": "^15.3.1",
        "react-tools": "^0.13.3",
        "react-transform-hmr": "^1.0.4",
        "redux-devtools": "^3.3.1",
        "sass-loader": "^4.0.0",
        "style-loader": "^0.13.1",
        "stylelint-config-standard": "^14.0.0",
        "stylelint-webpack-plugin": "^0.4.0",
        "template-html-loader": "0.0.3",
        "url-loader": "^0.5.7",
        "vorlon": "^0.4.0",
        "webpack": "^1.13.1",
        "webpack-dev-middleware": "^1.6.1",
        "webpack-dev-server": "^1.14.1",
        "webpack-hot-middleware": "^2.12.2",
        "webpack-notifier": "^1.4.1",
        "webpack-shell-plugin": "^0.4.3",
        "webpack-visualizer-plugin": "^0.1.5",
        "worker-loader": "^0.7.1"
    };

    return Mock;
};<commit_msg>fix build<commit_after>module.exports = () => {
    const Mock = {};

    Mock.config = {
        vars:  'object',
        moduleName:  'string',
        baseDir:  'string',
        destDir:  'string',
        srcDir:  'string',
        tempDir: 'string',
        EXPRESS_PORT:  'number',
        EXPRESS_ROOT:  'string',
        eslintConfig:  'string',
        stylelintConfig:  'string',
        packageJson:  'string',
        srcFiles: 'array',
        electronPackagingOptions: 'object',
        buildFiles: 'array',
        js_main_file_name:  'string',
        js_main_entry_path:  'string',
        js_output_path:  'string',
        js_external_scripts: 'array',
        js_runtime_configs: 'array',
        styles_main_file_name:  'string',
        styles_external_stylesheets: 'array',
        template_main_file_name:  'string',
        template_stats_file_name:  'string',
        template_src_path:  'string',
        template_engine:  'string',
        gaEnable: 'boolean',
        gaTrackingId: 'string',
        gaPageViewOnLoad: 'boolean',
        media_audio_output_path:  'string',
        media_files_output_path:  'string',
        media_fonts_output_path:  'string',
        media_images_output_path:  'string',
        media_video_output_path:  'string',
        media_favicon_path: 'string',
        imageminConfig:  'object',
        externalModulePaths: 'object',
        externalModules:  'object',
        sourcemapDev: 'boolean',
        sourcemapProd: 'boolean',
        sourcemapType: 'string',
        autoprefixerOptions:  'object',
        hotReloadingOptions:  'object',
        BrowserSyncReloadOnChange: 'boolean',
        enableRemoteDebugging: 'boolean',
        onBuildStartShellCommands:  'array',
        onBuildEndShellCommands:  'array',
        onBuildExitShellCommands:  'array',
        failOnProdBuildJsError:  'boolean',
        failOnProdBuildStyleError:  'boolean',
        eslintQuietMode: 'boolean',
        devtool:  'string',
        entry:  'array',
        output:  'object',
        resolve:  'object',
        module:  'object',
        postcss:  'array',
        eslint:  'object',
        bail:  'boolean',
        plugins:  'array'
    };
    Mock.packageJson = {};
    Mock.packageJson.devDependencies = {
        "autoprefixer": "^6.4.0",
        "babel-cli": "^6.11.4",
        "babel-core": "^6.13.2",
        "babel-eslint": "^7.0.0",
        "babel-jest": "^17.0.0",
        "babel-loader": "^6.2.4",
        "babel-plugin-add-module-exports": "^0.2.1",
        "babel-plugin-istanbul": "^3.0.0",
        "babel-plugin-react-html-attrs": "^2.0.0",
        "babel-plugin-react-transform": "^2.0.2",
        "babel-plugin-syntax-object-rest-spread": "^6.13.0",
        "babel-plugin-transform-class-properties": "^6.11.5",
        "babel-plugin-transform-decorators-legacy": "^1.3.4",
        "babel-plugin-transform-runtime": "^6.12.0",
        "babel-polyfill": "^6.13.0",
        "babel-preset-es2015": "^6.14.0",
        "babel-preset-react": "^6.11.1",
        "babel-preset-react-hmre": "^1.1.1",
        "babel-preset-stage-0": "^6.5.0",
        "babel-register": "^6.11.6",
        "babel-runtime": "^6.11.6",
        "browser-sync": "^2.14.0",
        "browser-sync-webpack-plugin": "^1.1.2",
        "chai": "^3.5.0",
        "chalk": "^1.1.3",
        "clean-webpack-plugin": "^0.1.10",
        "connect-history-api-fallback": "^1.3.0",
        "copy-webpack-plugin": "^4.0.0",
        "cross-env": "^3.1.3",
        "css-loader": "^0.25.0",
        "electron": "^1.4.5",
        "electron-packager": "^8.2.0",
        "eslint": "^3.3.0",
        "eslint-loader": "1.5.0",
        "expose-loader": "^0.7.1",
        "express": "^4.14.0",
        "express-history-api-fallback": "^2.0.0",
        "extract-text-webpack-plugin": "^1.0.1",
        "file-loader": "^0.9.0",
        "fs-extra": "^1.0.0",
        "gulp": "^3.9.1",
        "gulp-debug": "^3.0.0",
        "gulp-eslint": "^3.0.1",
        "gulp-load-plugins": "^1.2.4",
        "gulp-plumber": "^1.1.0",
        "gulp-util": "^3.0.7",
        "html-webpack-plugin": "^2.22.0",
        "imagemin-webpack-plugin": "^1.1.0",
        "ip": "^1.1.3",
        "istanbul": "^0.4.5",
        "jasmine-core": "^2.4.1",
        "jest": "^17.0.0",
        "jest-cli": "^17.0.0",
        "json-loader": "^0.5.4",
        "less": "^2.7.1",
        "less-loader": "^2.2.3",
        "lodash": "^4.15.0",
        "mocha": "^3.0.2",
        "mocha-lcov-reporter": "^1.2.0",
        "morgan": "^1.7.0",
        "node-sass": "^3.8.0",
        "postcss-loader": "^1.0.0",
        "progress-bar-webpack-plugin": "^1.9.0",
        "pug": "^2.0.0-beta5",
        "pug-loader": "^2.2.1",
        "q": "^1.4.1",
        "q-io": "^1.13.2",
        "react-addons-test-utils": "^15.3.0",
        "react-hot-loader": "^3.0.0-beta.6",
        "react-test-renderer": "^15.3.1",
        "react-tools": "^0.13.3",
        "react-transform-hmr": "^1.0.4",
        "redux-devtools": "^3.3.1",
        "sass-loader": "^4.0.0",
        "style-loader": "^0.13.1",
        "stylelint-config-standard": "^14.0.0",
        "stylelint-webpack-plugin": "^0.4.0",
        "template-html-loader": "0.0.3",
        "url-loader": "^0.5.7",
        "vorlon": "^0.4.0",
        "webpack": "^1.13.1",
        "webpack-dev-middleware": "^1.6.1",
        "webpack-dev-server": "^1.14.1",
        "webpack-hot-middleware": "^2.12.2",
        "webpack-notifier": "^1.4.1",
        "webpack-shell-plugin": "^0.4.3",
        "webpack-visualizer-plugin": "^0.1.5",
        "worker-loader": "^0.7.1"
    };

    return Mock;
};<|endoftext|>


<commit_before>import React, { Component } from 'react';
import styled from 'styled-components';

import { base } from '../base';
import Sidebar from './Header';
import Router from './Router';
import { colors } from '../theme/variables';

const Wrapper = styled.div`
  display: flex;
  height: 100%;
  border-top: 2px solid ${colors.darkblack};
`;

class App extends Component {
  constructor() {
    super();
    this.addTodo = this.addTodo.bind(this);
    this.updateTodo = this.updateTodo.bind(this);
    this.removeTodo = this.removeTodo.bind(this);
    this.addProject = this.addProject.bind(this);
    this.updateProject = this.updateProject.bind(this);
    this.removeProject = this.removeProject.bind(this);
    this.addSkill = this.addSkill.bind(this);
    this.removeSkill = this.removeSkill.bind(this);

    this.state = {
      todos: {},
      projects: {},
      skills: {},
    };
  }

  componentWillMount() {
    this.ref = [
      base.syncState('todos', {
        context: this,
        state: 'todos',
      }),
      base.syncState('projects', {
        context: this,
        state: 'projects',
      }),
      base.syncState('skills', {
        context: this,
        state: 'skills',
      }),
    ];

    const localStorageTodoRef = localStorage.getItem('todos');
    if (localStorageTodoRef) {
      this.setState({
        todos: JSON.parse(localStorageTodoRef),
      });
    }

    const localStorageProjectRef = localStorage.getItem('projects');
    if (localStorageProjectRef) {
      this.setState({
        projects: JSON.parse(localStorageProjectRef),
      });
    }

    const localStorageSkillRef = localStorage.getItem('skills');
    if (localStorageSkillRef) {
      this.setState({
        skills: JSON.parse(localStorageSkillRef),
      });
    }
  }

  componentWillUpdate(nextProps, nextState) {
    localStorage.setItem('todos', JSON.stringify(nextState.todos));
    localStorage.setItem('projects', JSON.stringify(nextState.projects));
    localStorage.setItem('skills', JSON.stringify(nextState.skills));
  }

  componentWillUnmount() {
    base.removeBinding(this.ref);
  }

  // update our state
  addTodo(todo) {
    const todos = { ...this.state.todos };
    const timestamp = Date.now();
    todos[`todo-${timestamp}`] = { ...todo };
    this.setState({ todos }); // same as this.setState({ todos: todos })
  }

  updateTodo(key, updatedProp) {
    const todos = { ...this.state.todos };
    const todo = todos[key];
    const updatedTodo = {
      ...todo,
      ...updatedProp,
    };
    todos[key] = updatedTodo;
    this.setState({
      todos,
    });
  }

  removeTodo(key) {
    const todos = { ...this.state.todos };
    console.log('Deleting todo');
    // delete todos[key];
    todos[key] = null;
    this.setState({ todos });
  }

  addProject(project) {
    // update our state
    // copy our state
    const projects = { ...this.state.projects };
    // add in our new project
    const timestamp = Date.now();
    projects[`project-${timestamp}`] = project;
    // set state
    this.setState({ projects }); // same as this.setState({ projects: projects })
  }

  updateProject(key, updatedProject) {
    const projects = { ...this.state.projects };
    projects[key] = updatedProject;
    this.setState({
      projects,
    });
  }

  removeProject(key) {
    const projects = { ...this.state.projects };
    projects[key] = null;
    this.setState({ projects });
  }

  addSkill(skill) {
    // update our state
    // copy our state
    const skills = { ...this.state.skills };
    // add in our new skill
    const timestamp = Date.now();
    skills[`skill-${timestamp}`] = skill;
    // set state
    this.setState({ skills }); // same as this.setState({ skills: skills })
  }

  updateSkill(key, updatedSkill) {
    const skills = { ...this.state.skills };
    skills[key] = updatedSkill;
    this.setState({
      skills,
    });
  }

  removeSkill(key) {
    const skills = { ...this.state.skills };
    skills[key] = null;
    this.setState({ skills });
  }

  render() {
    return (
      <Wrapper className="App wrapper">
        <Sidebar className="Sidebar" />
        <Router
          {...this.state}
          addTodo={this.addTodo}
          updateTodo={this.updateTodo}
          removeTodo={this.removeTodo}
          addProject={this.addProject}
          updateProject={this.updateProject}
          removeProject={this.removeProject}
          addSkill={this.addSkill}
          updateSkill={this.updateSkill}
          removeSkill={this.removeSkill}
        />
      </Wrapper>
    );
  }
}

export default App;
<commit_msg>Simplify local storage<commit_after>import React, { Component } from 'react';
import styled from 'styled-components';

import { base } from '../base';
import Sidebar from './Header';
import Router from './Router';
import { colors } from '../theme/variables';

const Wrapper = styled.div`
  display: flex;
  height: 100%;
  border-top: 2px solid ${colors.darkblack};
`;

class App extends Component {
  constructor() {
    super();
    this.addTodo = this.addTodo.bind(this);
    this.updateTodo = this.updateTodo.bind(this);
    this.removeTodo = this.removeTodo.bind(this);
    this.addProject = this.addProject.bind(this);
    this.updateProject = this.updateProject.bind(this);
    this.removeProject = this.removeProject.bind(this);
    this.addSkill = this.addSkill.bind(this);
    this.removeSkill = this.removeSkill.bind(this);

    this.state = {
      todos: {},
      projects: {},
      skills: {},
    };
  }

  componentWillMount() {
    this.ref = [
      base.syncState('todos', {
        context: this,
        state: 'todos',
      }),
      base.syncState('projects', {
        context: this,
        state: 'projects',
      }),
      base.syncState('skills', {
        context: this,
        state: 'skills',
      }),
    ];

    const localStorageRef = {
      todos: localStorage.getItem('todos'),
      projects: localStorage.getItem('projects'),
      skills: localStorage.getItem('skills'),
    };
    if (localStorageRef) {
      this.setState({
        todos: JSON.parse(localStorageRef.todos),
        projects: JSON.parse(localStorageRef.projects),
        skills: JSON.parse(localStorageRef.skills),
      });
    }
  }

  componentWillUpdate(nextProps, nextState) {
    localStorage.setItem('todos', JSON.stringify(nextState.todos));
    localStorage.setItem('projects', JSON.stringify(nextState.projects));
    localStorage.setItem('skills', JSON.stringify(nextState.skills));
  }

  componentWillUnmount() {
    base.removeBinding(this.ref);
  }

  // update our state
  addTodo(todo) {
    const todos = { ...this.state.todos };
    const timestamp = Date.now();
    todos[`todo-${timestamp}`] = { ...todo };
    this.setState({ todos }); // same as this.setState({ todos: todos })
  }

  updateTodo(key, updatedProp) {
    const todos = { ...this.state.todos };
    const todo = todos[key];
    const updatedTodo = {
      ...todo,
      ...updatedProp,
    };
    todos[key] = updatedTodo;
    this.setState({
      todos,
    });
  }

  removeTodo(key) {
    const todos = { ...this.state.todos };
    console.log('Deleting todo');
    // delete todos[key];
    todos[key] = null;
    this.setState({ todos });
  }

  addProject(project) {
    // update our state
    // copy our state
    const projects = { ...this.state.projects };
    // add in our new project
    const timestamp = Date.now();
    projects[`project-${timestamp}`] = project;
    // set state
    this.setState({ projects }); // same as this.setState({ projects: projects })
  }

  updateProject(key, updatedProject) {
    const projects = { ...this.state.projects };
    projects[key] = updatedProject;
    this.setState({
      projects,
    });
  }

  removeProject(key) {
    const projects = { ...this.state.projects };
    projects[key] = null;
    this.setState({ projects });
  }

  addSkill(skill) {
    // update our state
    // copy our state
    const skills = { ...this.state.skills };
    // add in our new skill
    const timestamp = Date.now();
    skills[`skill-${timestamp}`] = skill;
    // set state
    this.setState({ skills }); // same as this.setState({ skills: skills })
  }

  updateSkill(key, updatedSkill) {
    const skills = { ...this.state.skills };
    skills[key] = updatedSkill;
    this.setState({
      skills,
    });
  }

  removeSkill(key) {
    const skills = { ...this.state.skills };
    skills[key] = null;
    this.setState({ skills });
  }

  render() {
    return (
      <Wrapper className="App wrapper">
        <Sidebar className="Sidebar" />
        <Router
          {...this.state}
          addTodo={this.addTodo}
          updateTodo={this.updateTodo}
          removeTodo={this.removeTodo}
          addProject={this.addProject}
          updateProject={this.updateProject}
          removeProject={this.removeProject}
          addSkill={this.addSkill}
          updateSkill={this.updateSkill}
          removeSkill={this.removeSkill}
        />
      </Wrapper>
    );
  }
}

export default App;
<|endoftext|>


<commit_before>import React from 'react';
import PropTypes from 'prop-types';
import { styled } from '@storybook/theming';

import { ScrollArea } from '@storybook/components';

import NotificationList, { NotificationListSpacer } from './NotificationList';
import SidebarHeading from './SidebarHeading';
import SidebarStories from './SidebarStories';

const Heading = styled(SidebarHeading)({
  padding: '20px 20px 12px',
});

const Stories = styled(SidebarStories)(({ loading }) => (loading ? { marginTop: 8 } : {}));

const Container = styled.nav({
  position: 'absolute',
  zIndex: 1,
  left: 0,
  top: 0,
  bottom: 0,
  right: 0,
  width: '100%',
  height: '100%',
  overflowY: 'auto',
  overflowX: 'hidden',
});

const Foot = styled.div({});

export const Notifications = styled.div({
  position: 'fixed',
  display: 'block',
  bottom: 20,
  left: 20,
  margin: 0,
  padding: 0,
  width: '20%',
  minWidth: 200,
  maxWidth: 280,
  zIndex: 2,
});

const CustomScrollArea = styled(ScrollArea)({
  '.simplebar-track.simplebar-vertical': {
    right: '4px',
  },
});

const Sidebar = ({ storyId, notifications = [], stories, menu, menuHighlighted, loading }) => (
  <Container className="container">
    <CustomScrollArea vertical>
      <Heading menuHighlighted={menuHighlighted} menu={menu} />
      <Stories stories={stories} storyId={storyId} loading={loading} />

      <Foot>
        <NotificationListSpacer notifications={notifications} />
      </Foot>
    </CustomScrollArea>

    <Notifications>
      <NotificationList notifications={notifications} />
    </Notifications>
  </Container>
);

Sidebar.propTypes = {
  stories: PropTypes.shape({}).isRequired,
  storyId: PropTypes.string,
  notifications: PropTypes.arrayOf(PropTypes.shape({})).isRequired,
  menu: PropTypes.arrayOf(PropTypes.shape({})).isRequired,
  menuHighlighted: PropTypes.bool,
  loading: PropTypes.bool,
};
Sidebar.defaultProps = {
  storyId: undefined,
  menuHighlighted: false,
  loading: false,
};
Sidebar.displayName = 'Sidebar';

export default Sidebar;
<commit_msg>CLEANUP no double scrolling in Sidebar<commit_after>import React from 'react';
import PropTypes from 'prop-types';
import { styled } from '@storybook/theming';

import { ScrollArea } from '@storybook/components';

import NotificationList, { NotificationListSpacer } from './NotificationList';
import SidebarHeading from './SidebarHeading';
import SidebarStories from './SidebarStories';

const Heading = styled(SidebarHeading)({
  padding: '20px 20px 12px',
});

const Stories = styled(SidebarStories)(({ loading }) => (loading ? { marginTop: 8 } : {}));

const Container = styled.nav({
  position: 'absolute',
  zIndex: 1,
  left: 0,
  top: 0,
  bottom: 0,
  right: 0,
  width: '100%',
  height: '100%',
});

const Foot = styled.div({});

export const Notifications = styled.div({
  position: 'fixed',
  display: 'block',
  bottom: 20,
  left: 20,
  margin: 0,
  padding: 0,
  width: '20%',
  minWidth: 200,
  maxWidth: 280,
  zIndex: 2,
});

const CustomScrollArea = styled(ScrollArea)({
  '.simplebar-track.simplebar-vertical': {
    right: '4px',
  },
});

const Sidebar = ({ storyId, notifications = [], stories, menu, menuHighlighted, loading }) => (
  <Container className="container">
    <CustomScrollArea vertical>
      <Heading menuHighlighted={menuHighlighted} menu={menu} />
      <Stories stories={stories} storyId={storyId} loading={loading} />

      <Foot>
        <NotificationListSpacer notifications={notifications} />
      </Foot>
    </CustomScrollArea>

    <Notifications>
      <NotificationList notifications={notifications} />
    </Notifications>
  </Container>
);

Sidebar.propTypes = {
  stories: PropTypes.shape({}).isRequired,
  storyId: PropTypes.string,
  notifications: PropTypes.arrayOf(PropTypes.shape({})).isRequired,
  menu: PropTypes.arrayOf(PropTypes.shape({})).isRequired,
  menuHighlighted: PropTypes.bool,
  loading: PropTypes.bool,
};
Sidebar.defaultProps = {
  storyId: undefined,
  menuHighlighted: false,
  loading: false,
};
Sidebar.displayName = 'Sidebar';

export default Sidebar;
<|endoftext|>


<commit_before>var express = require('express');
var bodyParser = require('body-parser');
var Twitter = require('twitter');
var FB = require('fb');
var async = require('async');

//Database Mongodb connect with Mongoose
var mongoose = require('mongoose');

var mongoAddress = process.env.MONGO_ADDRESS; // e.g. 127.0.0.1
var mongoAddressPort = process.env.MONGO_ADDRESS_PORT || 27017; // e.g. 27017
var mongoColletion = process.env.MONGO_COLLECTION; // e.g. msgGlobal/msgs
var mongoAddressScheme = "mongodb://"
var mongoURI = mongoAddressScheme + mongoAddress + ":" + mongoAddressPort + "/" + mongoColletion;

console.log("Connecting to MongoDB at the uri: ", mongoURI);
mongoose.connect(mongoURI);

var db = mongoose.connection;
db.on('error',console.error.bind(console,'connection error: '));
db.once('connected',function(){
	console.log('Connected to the database');
});

// Example Schema
var msgSchema = mongoose.Schema({
	user_id: String,
	message: String,
	tweet_id:String,
	fb_id:String
});

var MSG = mongoose.model('MSG',msgSchema);
//NOTE: with process.env.USER_ID register my id
var userTweet = process.env.USER_TW_ID;
console.log('USER_TW_ID',userTweet);
var userfb =process.env.USER_FB_ID;
console.log('USER_FB_ID',userfb);

var app = express();

//Twitter
var client = new Twitter({
	consumer_key:process.env.TWITTER_CONSUMER_KEY,
	consumer_secret:process.env.TWITTER_CONSUMER_SECRET,
	access_token_key:process.env.TWITTER_ACCESS_TOKEN_KEY,
	access_token_secret:process.env.TWITTER_ACCESS_TOKEN_SECRET
});

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(express.static(__dirname + '/public'));

app.post('/message',function(req,res){
	var msg = req.body.message;
	console.log('message',msg);

	console.log('PROGRAM START');

	async.waterfall([
		function(callback){
			client.post('statuses/update',{status:msg},function(err,tweet,response){
				if(err) {
					callback(true,'Error posting Twitter');
					return;
				}
				console.log(tweet);
				callback(null,tweet);
			});
		},
		function(callback){

			FB.setAccessToken(process.env.ACCEESS_TOKEN);
			FB.api('me/feed', 'post', { message: msg}, function (res) {
				if(!res || res.error) {
    				console.log(!res ? 'error occurred' : res.error);
    				return;
  				}
  			console.log('Post Id: ' + res.id);
  			callback(null,fb)
			});
		},
		function(fb, callback){
			var msgSocial = new MSG({user_id: userTweet, message: msg, tweet_id: tweet.id_str, fb_id: userfb});
			console.log(msgSocial.user_id,msgSocial.message,msgSocial.tweet_id,msgSocial.fb_id);
			msgTweet.save(function(err,file){
				if(err) {
					callback(true,'Error saving the user in MongoDB');
					return;
				}
				console.log('User saved successfully!')
				callback(null,file);
			});

		}
	], function(err,result){
			 if(err){
			 	res.json({'error':result});
			 }else{
			 	console.log('Main callback: '+ result);
			 	res.json(result);
			 }
			}
	);
	console.log('END PROGRAM');
});

app.get('/message/:message_id',

	function(req,res){

		var msg_id = mongoose.Types.ObjectId(req.params.message_id);
		console.log('PROGRAM START');

		async.waterfall([
			function(callback){
				db.collection('msgs').findOne({'_id':msg_id},function(err,file){
					if(err) return callback(err);
					console.log(file.message);
					callback(null,file);
				});
			},
			function(msg1,callback){
				client.get('statuses/show',{id:msg1.tweet_id},function(err,tweets,response){
					if(err) return callback(err);
					console.log(tweets.text);
					callback(null,tweets);

				});
			}
		], function(err,result){
			if(err) return err;
			console.log('Main callback: '+ result);
			res.json(result);
			}
		);
		console.log('END PROGRAM');
});

var server = app.listen(3000, function () {
  var host = server.address().address;
  var port = server.address().port;

  console.log('Example app listening at http://%s:%s', host, port);
});
<commit_msg>insert parameter id<commit_after>var express = require('express');
var bodyParser = require('body-parser');
var Twitter = require('twitter');
var FB = require('fb');
var async = require('async');

//Database Mongodb connect with Mongoose
var mongoose = require('mongoose');

var mongoAddress = process.env.MONGO_ADDRESS; // e.g. 127.0.0.1
var mongoAddressPort = process.env.MONGO_ADDRESS_PORT || 27017; // e.g. 27017
var mongoColletion = process.env.MONGO_COLLECTION; // e.g. msgGlobal/msgs
var mongoAddressScheme = "mongodb://"
var mongoURI = mongoAddressScheme + mongoAddress + ":" + mongoAddressPort + "/" + mongoColletion;

console.log("Connecting to MongoDB at the uri: ", mongoURI);
mongoose.connect(mongoURI);

var db = mongoose.connection;
db.on('error',console.error.bind(console,'connection error: '));
db.once('connected',function(){
	console.log('Connected to the database');
});

// Example Schema
var msgSchema = mongoose.Schema({
	user_id: String,
	user_fb_id: String,
	message: String,
	tweet_id: String,
	fb_id: String
});

var MSG = mongoose.model('MSG',msgSchema);
//NOTE: with process.env.USER_ID register my id
var userTweet = process.env.USER_TW_ID;
console.log('USER_TW_ID',userTweet);
var userfb =process.env.USER_FB_ID;
console.log('USER_FB_ID',userfb);

var app = express();

//Twitter
var client = new Twitter({
	consumer_key:process.env.TWITTER_CONSUMER_KEY,
	consumer_secret:process.env.TWITTER_CONSUMER_SECRET,
	access_token_key:process.env.TWITTER_ACCESS_TOKEN_KEY,
	access_token_secret:process.env.TWITTER_ACCESS_TOKEN_SECRET
});

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(express.static(__dirname + '/public'));

app.post('/message',function(req,res){
	var msg = req.body.message;
	console.log('message',msg);

	console.log('PROGRAM START');

	async.waterfall([
		function(callback){
			client.post('statuses/update',{status:msg},function(err,tweet,response){
				if(err) {
					callback(true,'Error posting Twitter');
					return;
				}
				console.log(tweet);
				callback(null,tweet);
			});
		},
		function(tweet,callback){

			FB.setAccessToken(process.env.ACCEESS_TOKEN);
			FB.api('/me/feed', 'post', {message:tweet.msg}, function (err,res) {
				if(err) {
    				console.log('Error posting Facebook');
    				return;
  				}
  			console.log('Post Id: ' + res.id);
  			callback(null,fb)
			});
		},
		function(fb,callback){
			var msgSocial = new MSG({
				user_tw_id: userTweet,
				user_fb_id: userfb,
				message: msg,
				tweet_id: tweet.id_str,
				fb_id: fb.id_str
			});
			console.log(msgSocial.user_tw_id, msgSocial.user_fb_id, msgSocial.message, msgSocial.tweet_id, msgSocial.fb_id);
			msgTweet.save(function(err,file){
				if(err) {
					callback(true,'Error saving the user in MongoDB');
					return;
				}
				console.log('User saved successfully!')
				callback(null,file);
			});

		}
	], function(err,result){
			 if(err){
			 	res.json({'error':result});
			 }else{
			 	console.log('Main callback: '+ result);
			 	res.json(result);
			 }
			}
	);
	console.log('END PROGRAM');
});

app.get('/message/:message_id',

	function(req,res){

		var msg_id = mongoose.Types.ObjectId(req.params.message_id);
		console.log('PROGRAM START');

		async.waterfall([
			function(callback){
				db.collection('msgs').findOne({'_id':msg_id},function(err,file){
					if(err) return callback(err);
					console.log(file.message);
					callback(null,file);
				});
			},
			function(msg1,callback){
				client.get('statuses/show',{id:msg1.tweet_id},function(err,tweets,response){
					if(err) return callback(err);
					console.log(tweets.text);
					callback(null,tweets);

				});
			}
		], function(err,result){
			if(err) return err;
			console.log('Main callback: '+ result);
			res.json(result);
			}
		);
		console.log('END PROGRAM');
});

var server = app.listen(3000, function () {
  var host = server.address().address;
  var port = server.address().port;

  console.log('Example app listening at http://%s:%s', host, port);
});
<|endoftext|>